Architecture¶
This page provides visual diagrams showing how PyBurgers is structured and how the simulation flows from start to finish.
High-Level Architecture¶
flowchart TB
subgraph entry[Entry Point]
CLI[burgers.py<br/>CLI Interface]
end
subgraph config[Configuration]
NL[namelist.json<br/>User Config]
Schema[schema_namelist.json<br/>Validation Rules]
Input[Input Class<br/>Parser & Validator]
end
subgraph core[Core Simulation]
Base[Burgers<br/>Abstract Base Class]
DNS[DNS Class<br/>Direct Simulation]
LES[LES Class<br/>Large-Eddy Simulation]
end
subgraph physics[Physics Models]
SGS[SGS Base Class]
Smag[Smagorinsky Models]
Wong[Wong-Lilly Model]
Dear[Deardorff TKE Model]
end
subgraph utils[Utilities]
Spectral[SpectralWorkspace<br/>FFT Operations]
Deriv[Derivatives]
Filter[Filter]
Dealias[Dealias]
FBM[FBM Noise]
FFTW[FFTW Wisdom Cache]
end
subgraph output[Output]
Output[Output Class<br/>NetCDF Writer]
NC[pyburgers_*.nc<br/>Results]
end
CLI --> NL
NL --> Input
Schema --> Input
Input --> DNS
Input --> LES
DNS --> Base
LES --> Base
LES --> SGS
SGS --> Smag
SGS --> Wong
SGS --> Dear
Base --> Spectral
Spectral --> Deriv
Spectral --> Filter
Spectral --> Dealias
Spectral --> FBM
Spectral --> FFTW
Base --> Output
Output --> NC
style CLI fill:#e1f5ff
style Base fill:#fff4e1
style DNS fill:#e8f5e9
style LES fill:#e8f5e9
style Spectral fill:#f3e5f5
style Output fill:#ffe0b2
Simulation Execution Flow¶
flowchart TD
Start([Start]) --> Parse[Parse CLI Arguments<br/>dns or les mode]
Parse --> Load[Load namelist.json]
Load --> Validate[Validate Configuration<br/>against schema]
Validate --> Setup[Setup Logging]
Setup --> LoadWisdom{Load FFTW<br/>Wisdom?}
LoadWisdom -->|Cached| Reuse[Reuse Cached Plans]
LoadWisdom -->|None/Mismatch| Warmup[Warmup FFTW Plans]
Reuse --> InitSolver
Warmup --> SaveWisdom[Save Wisdom Cache]
SaveWisdom --> InitSolver
InitSolver[Initialize Solver<br/>DNS or LES] --> CreateWorkspace[Create SpectralWorkspace<br/>FFT buffers & plans]
CreateWorkspace --> InitSGS{LES Mode?}
InitSGS -->|Yes| LoadSGS[Load SGS Model<br/>0-4]
InitSGS -->|No| InitIC
LoadSGS --> InitIC
InitIC[Initialize Velocity Field<br/>Random + low-k energy] --> CreateOutput[Create NetCDF Output]
CreateOutput --> TimeLoop{t < duration?}
TimeLoop -->|Yes| RK3Step[RK3 Time Step]
RK3Step --> Stage1[Stage 1:<br/>Compute RHS, Update u]
Stage1 --> Stage2[Stage 2:<br/>Compute RHS, Update u]
Stage2 --> Stage3[Stage 3:<br/>Compute RHS, Update u]
Stage3 --> ComputeCFL[Compute CFL<br/>Adaptive Δt]
ComputeCFL --> CheckSave{Time to<br/>save?}
CheckSave -->|Yes| WriteNC[Write to NetCDF]
CheckSave -->|No| CheckPrint
WriteNC --> CheckPrint{Time to<br/>print?}
CheckPrint -->|Yes| LogProgress[Log Progress]
CheckPrint -->|No| TimeLoop
LogProgress --> TimeLoop
TimeLoop -->|No| CloseOutput[Close NetCDF File]
CloseOutput --> End([End])
style Start fill:#e1f5ff
style End fill:#e1f5ff
style RK3Step fill:#fff4e1
style WriteNC fill:#e8f5e9
style InitSolver fill:#f3e5f5
RK3 Stage Details¶
Each Runge-Kutta stage computes the right-hand side (RHS) of the Burgers equation:
flowchart TD
Start([Stage k]) --> Noise[Generate FBM Noise<br/>Stochastic forcing]
Noise --> FFT1[FFT: u → û]
FFT1 --> Deriv[Compute Derivatives<br/>∂u/∂x, ∂²u/∂x²]
Deriv --> Dealias[Compute u²<br/>with dealiasing]
Dealias --> NonLin[Compute ∂u²/∂x]
NonLin --> SGSCheck{LES Mode?}
SGSCheck -->|Yes| ComputeSGS[Compute SGS Stress<br/>τ = -2ν_t ∂u/∂x]
SGSCheck -->|No| BuildRHS
ComputeSGS --> BuildRHS[Build RHS:<br/>F = -∂u²/∂x + ν∂²u/∂x² + ∂τ/∂x + noise]
BuildRHS --> UpdateU[Update u<br/>using RK3 coefficients]
UpdateU --> ZeroNyquist[Zero Nyquist Mode]
ZeroNyquist --> IFFT[IFFT: û → u]
IFFT --> End([Next Stage])
style Start fill:#e1f5ff
style End fill:#e1f5ff
style ComputeSGS fill:#fff4e1
style Dealias fill:#ffe0b2
Class Hierarchy¶
classDiagram
class Burgers {
<<abstract>>
+SpectralWorkspace workspace
+Input input_obj
+Output output
+run()
+_compute_rhs()*
+_initialize_velocity()
+_compute_cfl()
}
class DNS {
+_compute_rhs()
Override: No SGS model
}
class LES {
+SGS sgs_model
+_compute_rhs()
Override: Includes SGS stress
}
class SGS {
<<abstract>>
+compute()*
+get_model()$
}
class SmagConstant {
+Cs: float
+compute()
Constant coefficient
}
class SmagDynamic {
+compute()
Dynamic coefficient
}
class WongLilly {
+compute()
Dynamic with scale-similarity
}
class Deardorff {
+tke_sgs: array
+compute()
1.5-order TKE equation
}
class SpectralWorkspace {
+Derivatives deriv
+Dealias dealias
+Filter filter
+FBM noise
}
Burgers <|-- DNS
Burgers <|-- LES
Burgers *-- SpectralWorkspace
LES *-- SGS
SGS <|-- SmagConstant
SGS <|-- SmagDynamic
SGS <|-- WongLilly
SGS <|-- Deardorff
Data Flow in SpectralWorkspace¶
flowchart TB
subgraph "Physical Space"
U[u: velocity field<br/>Real array nx]
end
subgraph "Spectral Operations"
FFT[FFT: rfft<br/>pyfftw]
UHat[û: velocity spectrum<br/>Complex array nx/2+1]
D1[∂u/∂x<br/>Multiply by ik]
D2[∂²u/∂x²<br/>Multiply by -k²]
D3[∂³u/∂x³<br/>Multiply by -ik³]
Filt[Filter<br/>Spectral cutoff]
Deal[Dealiasing<br/>3/2 padding]
end
subgraph "Back to Physical"
IFFT[IFFT: irfft<br/>pyfftw]
Result[Derivatives in x-space]
end
U -->|Forward| FFT
FFT --> UHat
UHat --> D1
UHat --> D2
UHat --> D3
UHat --> Filt
UHat --> Deal
D1 --> IFFT
D2 --> IFFT
D3 --> IFFT
Filt --> IFFT
Deal --> IFFT
IFFT --> Result
style U fill:#e1f5ff
style UHat fill:#fff4e1
style Result fill:#e8f5e9
FFTW Wisdom Caching Strategy¶
flowchart TD
Start([Initialization]) --> CheckFile{Wisdom file<br/>exists?}
CheckFile -->|No| Warmup[Run Warmup:<br/>Create all plans]
CheckFile -->|Yes| Lock[Acquire Read Lock]
Lock --> Load[Load Wisdom File]
Load --> CheckMeta{Metadata<br/>matches?}
CheckMeta -->|nx_dns matches?| CheckLES
CheckMeta -->|No| Invalid1[Mark Invalid]
CheckLES -->|nx_les matches?| CheckBeta
CheckLES -->|No| Invalid2[Mark Invalid]
CheckBeta -->|noise_beta matches?| CheckPlan
CheckBeta -->|No| Invalid3[Mark Invalid]
CheckPlan -->|FFTW planning matches?| CheckThreads
CheckPlan -->|No| Invalid4[Mark Invalid]
CheckThreads -->|Threads match?| Import
CheckThreads -->|No| Invalid5[Mark Invalid]
Invalid1 --> Warmup
Invalid2 --> Warmup
Invalid3 --> Warmup
Invalid4 --> Warmup
Invalid5 --> Warmup
Import[Import Wisdom<br/>Fast startup] --> Continue([Continue])
Warmup --> Save[Save Wisdom<br/>with metadata]
Save --> Continue
style CheckFile fill:#e1f5ff
style Import fill:#e8f5e9
style Warmup fill:#fff4e1
style Continue fill:#e1f5ff
SGS Model Selection¶
flowchart TD
Start([LES Mode]) --> ReadConfig[Read subgrid_model<br/>from namelist]
ReadConfig --> Factory{Model ID}
Factory -->|0| NoModel[No SGS Model<br/>τ = 0]
Factory -->|1| SmagC[Constant Smagorinsky<br/>C_s = 0.18]
Factory -->|2| SmagD[Dynamic Smagorinsky<br/>C_s computed]
Factory -->|3| WongL[Wong-Lilly<br/>Dynamic + similarity]
Factory -->|4| Dear[Deardorff TKE<br/>1.5-order closure]
NoModel --> Compute[compute method]
SmagC --> Compute
SmagD --> Compute
WongL --> Compute
Dear --> Compute
Compute --> Return[Return τ, C_s<br/>Optional: TKE]
Return --> RHS[Add ∂τ/∂x to RHS]
style Start fill:#e1f5ff
style Factory fill:#fff4e1
style Return fill:#e8f5e9
Key Design Patterns¶
Abstract Base Class Pattern¶
Burgersdefines common interface and time-stepping logicDNSandLESimplement mode-specific RHS computation- Eliminates code duplication while allowing specialization
Factory Pattern¶
SGS.get_model()creates appropriate SGS model instance- Centralizes model selection logic
- Easy to add new SGS models
Workspace Pattern¶
SpectralWorkspacebundles all spectral operations- Pre-allocates FFTW buffers for efficiency
- Provides clean interface to complex FFT operations
Caching Pattern¶
- FFTW wisdom stored with metadata validation
- First run: slow planning, subsequent runs: instant
- Automatic invalidation on parameter changes