This document describes the technical architecture of Atoms_Rust, including module structure, data flow, and design decisions.
Atoms_Rust is organized as a Rust library with multiple binary front-ends, following the principle of separation of concerns between physics, rendering, and user interaction.
graph TB
subgraph "Application Layer"
RT[realtime.rs<br/>3D Realtime]
RAY[raytracer.rs<br/>GPU Rendering]
A2D[atom_2d.rs<br/>2D Simulation]
W2D[wave_2d.rs<br/>Wave Viz]
end
subgraph "Library Layer"
LIB[lib.rs<br/>Public API]
end
subgraph "Core Modules"
PHYS[physics/<br/>Quantum Mechanics]
REND[render/<br/>GPU Utilities]
CAM[camera/<br/>Navigation]
end
RT --> LIB
RAY --> LIB
A2D --> LIB
W2D --> LIB
LIB --> PHYS
LIB --> REND
LIB --> CAM
style LIB fill:#e1f5fe
style PHYS fill:#fff3e0
style REND fill:#e8f5e9
style CAM fill:#fce4ec
src/
├── lib.rs # Library entry point, re-exports
├── constants.rs # Physical constants (a₀, ħ, mₑ)
│
├── physics/ # Core physics calculations
│ ├── mod.rs # Module exports
│ ├── polynomials.rs # Laguerre & Legendre polynomials
│ ├── sampling.rs # CDF-based probability sampling
│ └── color.rs # Inferno colormap implementation
│
├── render/ # Rendering utilities
│ ├── mod.rs # Module exports
│ ├── instanced.rs # Instanced particle rendering
│ └── shaders.rs # GLSL shader code
│
├── camera/ # Camera controllers
│ ├── mod.rs # Module exports
│ └── orbit.rs # Orbit camera implementation
│
└── bin/ # Executable binaries
├── realtime.rs # 3D realtime visualizer
├── raytracer.rs # GPU raytracing mode
├── atom_2d.rs # 2D atom simulation
└── wave_2d.rs # 2D wave visualization
The physics module contains all quantum mechanical calculations.
classDiagram
class Sampler {
-Vec~f64~ r_cdf
-Vec~f64~ theta_cdf
-f64 r_max
-i32 last_n
-i32 last_l
-i32 last_m
+new() Sampler
+prepare(n, l, m) void
+sample_r(n, l, rng) f32
+sample_theta(l, m, rng) f32
-build_r_cdf(n, l) void
-build_theta_cdf(l, m) void
}
class Polynomials {
+laguerre(n, l, rho) f64
+legendre(l, m, x) f64
+factorial(n) f64
+tgamma_int(n) f64
}
class ColorMaps {
+inferno(r, theta, phi, n, l, m) Color
+inferno_scaled(r, theta, phi, n, l, m) Color
+inferno_log(r, theta, phi, n, l, m) Color
+heatmap_fire(value) Color
+calculate_probability_flow(pos, n, l, m) Vec3
}
Sampler --> Polynomials : uses
ColorMaps --> Polynomials : uses
Mathematical functions for quantum mechanics:
| Function | Description | Complexity |
|---|---|---|
laguerre(n, l, rho) |
Associated Laguerre polynomial |
O(k) where k = n-l-1 |
legendre(l, m, x) |
Associated Legendre polynomial |
O(l) |
factorial(n) |
Integer factorial | O(n) |
tgamma_int(n) |
Gamma function for integers | O(n) |
Probability sampling implementation:
| Struct/Function | Description |
|---|---|
Sampler |
Caches CDF tables for efficient sampling |
sample_r() |
Sample radial distance from $r^2 |
sample_theta() |
Sample polar angle from $\sin\theta |
sample_phi() |
Uniform azimuthal sampling |
spherical_to_cartesian() |
Coordinate conversion |
Color mapping for visualization:
| Function | Description |
|---|---|
inferno() |
Standard probability density to color |
inferno_scaled() |
Scaled version for realtime (matches C++) |
inferno_log() |
Log-compressed for raytracer |
heatmap_fire() |
Fire color gradient implementation |
calculate_probability_flow() |
Probability current velocity |
GPU rendering utilities.
classDiagram
class ParticleInstance {
+[f32;3] position
+f32 _padding
+[f32;4] color
+f32 scale
+[f32;3] _padding2
+new(pos, color, scale) ParticleInstance
}
class ParticleBatch {
-Vec~ParticleInstance~ instances
-f32 sphere_radius
+new(capacity, radius) ParticleBatch
+add(pos, color) void
+clear() void
+len() usize
+is_empty() bool
}
class Shaders {
<<constant>>
INSTANCED_VERTEX_SHADER
INSTANCED_FRAGMENT_SHADER
POINT_VERTEX_SHADER
POINT_FRAGMENT_SHADER
RAYTRACER_VERTEX_SHADER
RAYTRACER_FRAGMENT_SHADER
}
ParticleBatch --> ParticleInstance : contains
| Shader | Purpose |
|---|---|
INSTANCED_* |
Instanced sphere rendering with lighting |
POINT_* |
Point sprites with fake sphere shading |
RAYTRACER_* |
SSBO-based GPU raytracing |
Camera controllers for 3D navigation.
classDiagram
class OrbitCamera {
+Vec3 target
+f32 radius
+f32 azimuth
+f32 elevation
+f32 orbit_speed
+f32 pan_speed
+f32 zoom_speed
+bool dragging
+Vec2 last_mouse_pos
+new() OrbitCamera
+with_radius(r) OrbitCamera
+with_target(t) OrbitCamera
+position() Vec3
+forward() Vec3
+right() Vec3
+up() Vec3
+update() void
+reset() void
}
flowchart TD
START[User Input: n, l, m] --> PREPARE[Sampler::prepare]
PREPARE --> BUILD_R[Build radial CDF<br/>4096 points]
BUILD_R --> BUILD_THETA[Build angular CDF<br/>2048 points]
BUILD_THETA --> LOOP[Particle Loop]
subgraph LOOP [Per Particle]
SAMPLE_R[Sample r from CDF] --> SAMPLE_THETA[Sample θ from CDF]
SAMPLE_THETA --> SAMPLE_PHI[Sample φ uniformly]
SAMPLE_PHI --> CART[spherical_to_cartesian]
CART --> COLOR[inferno color]
end
LOOP --> STORE[Store Particle]
STORE --> LOOP
STORE --> RENDER[Render Loop]
sequenceDiagram
participant Main as Main Loop
participant Input as Input Handler
participant Camera as OrbitCamera
participant Sampler as Sampler
participant Physics as Physics Engine
participant GPU as GPU Renderer
Main->>Input: Poll events
Input->>Camera: Update camera
alt Quantum numbers changed
Main->>Sampler: prepare(n, l, m)
loop N particles
Main->>Sampler: sample_r/theta/phi()
Main->>Physics: spherical_to_cartesian()
Main->>Physics: inferno() color
end
end
Main->>Physics: calculate_probability_flow()
loop All particles
Main->>GPU: draw_sphere(pos, color)
end
Main->>Main: next_frame().await
Decision: Separate library from executables
Rationale:
- Code reuse between visualization modes
- Allows external crates to use the physics engine
- Clear separation of concerns
Decision: Cache CDF tables in Sampler struct
Rationale:
- Building CDF tables is O(N) where N ≈ 4000
- Sampling from cached CDF is O(log N)
- Same (n, l, m) often used for many frames
Decision: Use rayon for parallel iteration
particles.par_iter_mut().for_each(|p| {
p.vel = calculate_probability_flow(p.pos, n, l, m);
// Update position...
});Rationale:
- Particle updates are independent
- Linear speedup with core count
- Minimal synchronization overhead
Decision: Use Vec::with_capacity() everywhere
let mut particles: Vec<Particle> = Vec::with_capacity(num_particles);Rationale:
- Eliminates reallocation during runtime
- Improves cache locality
- Reduces memory fragmentation
Particle struct:
┌─────────────────────────────────────────────┐
│ pos: Vec3 (12 bytes) │ vel: Vec3 (12 bytes) │
├──────────────────────┴──────────────────────┤
│ color: Color (16 bytes) │
├─────────────────────────────────────────────┤
│ r: f32 (4 bytes) │ theta: f32 (4 bytes) │
└─────────────────────────────────────────────┘
Total: 48 bytes per particle
| Operation | Complexity | Notes |
|---|---|---|
| Build CDF | O(N) | N = 4096 for r, 2048 for θ |
| Sample from CDF | O(log N) | Binary search |
| Particle update | O(1) | Per particle |
| Total frame update | O(P × log N) | P = particle count |
| Render | O(P) | Per particle draw call |
pie title Frame Time Distribution
"GPU Draw Calls" : 60
"Particle Updates" : 25
"CDF Sampling" : 10
"Color Calculation" : 5
- Create new binary in
src/bin/ - Import library functions:
use atoms_rust::{ inferno, sample_phi, spherical_to_cartesian, OrbitCamera, Sampler, };
- Implement custom rendering logic
- Add to
Cargo.toml:[[bin]] name = "your_visualizer" path = "src/bin/your_visualizer.rs"
- Add to appropriate module in
src/physics/ - Export from
mod.rs - Add to
lib.rsre-exports - Document with rustdoc and LaTeX
graph LR
subgraph "Direct Dependencies"
MQ[macroquad 0.4<br/>Game framework]
RAND[rand 0.8<br/>Random numbers]
RAYON[rayon 1.10<br/>Parallelism]
ERR[thiserror 1.0<br/>Error types]
end
subgraph "Dev Dependencies"
CRIT[criterion 0.5<br/>Benchmarking]
end
ATOMS[Atoms_Rust] --> MQ
ATOMS --> RAND
ATOMS --> RAYON
ATOMS --> ERR
ATOMS -.-> CRIT
| Crate | Purpose |
|---|---|
macroquad |
Cross-platform rendering, input handling |
rand |
Random number generation for sampling |
rayon |
Parallel iterator for particle updates |
thiserror |
Derive error types |
# Cargo.toml release profile
[profile.release]
opt-level = 3 # Maximum optimization
lto = true # Link-time optimizationThis configuration ensures:
- Maximum runtime performance
- Smaller binary size
- Dead code elimination