Changelog¶
All notable changes to PyBurgers will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[2.1.0] - 2026-04-13¶
Added¶
- Pluggable spatial discretization (
SpatialOperator): New abstract base class withget_operator(scheme_id, nx)factory method decouples spatial differentiation from the solvers. The scheme is selected vianumerics.spatialin the namelist (1=FD2,2=FD4,3=Spectral). Both DNS and LES use the same pluggable interface. - 2nd-order central finite differences (
FD2): New spatial scheme (numerics.spatial = 1) using 2nd-order central stencils for all derivative orders (1st, 2nd, 3rd, 4th, and squared). Periodic boundary conditions applied via circular padding. - 4th-order central finite differences (
FD4): New spatial scheme (numerics.spatial = 2) using 4th-order central stencils for 1st and 2nd derivatives (3rd and 4th derivatives fall back to 2nd-order wide stencils). Higher accuracy than FD2 with slightly larger stencil footprint. - Pluggable time integration (
TemporalIntegrator): New abstract base class withget_integrator(scheme_id, nx)factory method decouples time advancement from the step loop. The scheme is selected vianumerics.temporalin the namelist (1=AB2,2=AM2,3=RK3). - Adams-Bashforth 2nd order (
AB2): New time integration scheme (numerics.temporal = 1). Variable-step 2nd-order multistep method bootstrapped with forward Euler on the first step; 1 RHS evaluation per step. - Adams-Moulton 2nd-order predictor-corrector (
AM2): New time integration scheme (numerics.temporal = 2) pairing the variable-step AB2 predictor with the A-stable AM2 (trapezoidal) corrector in a PECE scheme. Reduces local truncation error compared to AB2 at the cost of one additional RHS evaluation per step. - jsonschema validation:
Inputnow uses thejsonschemalibrary for schema-driven namelist validation, replacing the previous manual validation logic. Provides clearer error messages and schema-first extensibility. cflandmax_stepmoved tonumericssection: These time-stepping controls are now undernumerics.cflandnumerics.max_stepin the namelist, co-located with the scheme selection keys they govern.
Fixed¶
- Energy conservation bug: Corrected an error in RHS assembly for LES/FD operators that produced non-physical energy growth
- Enstrophy computation bug: Fixed incorrect enstrophy diagnostic that accumulated error over long runs
- Aliasing bug in Deardorff SGS: Corrected nonlinear term handling in the TKE equation that introduced aliasing artifacts
- TKE computation bug: Fixed an error in the subgrid TKE prognostic equation that caused incorrect TKE levels
- Deardorff SGS advancing TKE every substep: The TKE equation is now advanced once per full timestep rather than once per RK3 substep, matching the correct PECE/RK3 integration semantics
- Sign error in Dynamic Smagorinsky: Corrected a coefficient sign in
SmagDynamicthat could produce negative eddy-viscosity artifacts under certain flow conditions - NaN protection in RK3: Added guards against NaN propagation in the RK3 substep loop when velocity magnitudes approach machine limits
- AB2 stability for DNS: Lowered
dissipative_stability_limitto 0.2 and added Nyquist-mode zeroing after each FD operator call to maintain stability at DNS resolution - Energy budget violations in LES/FD mode: Fixed operator ordering issue that produced spurious energy injection in LES runs with FD2/FD4 spatial schemes
- Divide-by-zero in CFL stability computation: Added protection for the case where maximum velocity or wavenumber is zero at startup
- Buffer mutation in
Derivatives.compute(): External inputs (SGS stress, TKE) no longer corrupt the velocity buffer; auto-save/restore eliminates error-prone manual copies in LES and Deardorff SGS - Float equality in dynamic SGS models: Replaced exact
== 0comparison with tolerance (< 1e-30) inSmagDynamicandWongLillycoefficient computation to avoid division-by-zero edge cases - Default noise exponent sign: Changed default from
0.75to-0.75inInputto match namelist convention and prevent silent sign error when the exponent is omitted SmagConstanttau buffer allocation:compute()now writes in-place vianp.multiply(..., out=self.result["tau"])instead of reassigning the dict entry with a fresh array each call, matching all other SGS models- DNS/LES filter ratio validation:
Inputnow raisesNamelistErrorifgrid.dns.pointsis not divisible bygrid.les.points; previously the filter width was silently wrong for non-divisible configurations Derivativesdealiasing rule: FixedDerivativesto use the 3/2-rule (correct zero-padding factor) instead of 2× padding for the nonlinear squared term- FBM buffer protection: Added guard against out-of-bounds write in the fractional Brownian motion noise generator for edge-case grid sizes
- Delayed mode validation:
Inputnow validatesnumerics.temporalandnumerics.spatialscheme IDs immediately on parse rather than at first use
Changed¶
- Namelist keys renamed:
numerics.integration→numerics.temporal;numerics.advection→numerics.spatial. Names now match theTemporalIntegratorandSpatialOperatorclass hierarchy. - Scheme IDs reordered (simpler → more capable): Temporal:
1=AB2,2=AM2,3=RK3 (was1=RK3,2=AB2). Spatial:1=FD2,2=FD4,3=Spectral (was1=Spectral,2=FD2,3=FD4). - Hyperviscosity is now always active and scheme-normalized: Previously a user-configurable namelist option, hyperviscosity is now applied automatically to all spatial schemes. The coefficient is normalized as
ν₄ = π⁴·dx⁴/λ_hypervisc, whereλ_hyperviscis the scheme's maximum modified wavenumber magnitude. This ensures equal Nyquist damping rate and a scheme-independent hyperviscous timestep limit (C/π⁴) across FD2, FD4, and Spectral. Thephysics.hyperviscositynamelist key andHyperviscosityConfigdataclass have been removed. Derivatives.compute()parameter: Renamedordertoordersfor clarity (it accepts a list)- RK3 coefficient variables: Renamed
A/Btork3_a/rk3_bincore.pyfor PEP 8 compliance - Schema enforces even grid point counts:
grid.dns.pointsandgrid.les.pointsnow require"multipleOf": 2; odd sizes produce incorrect rfft output - Schema rejects unknown namelist keys:
"additionalProperties": falseadded to all object sections; typos in optional keys (e.g."amplitde") now raise a validation error instead of silently falling back to defaults Derivatives.zero_nyquistsimplified: Always restores physical space; therestore_physical=Falsepath and_fu_validoptimization flag have been removed as they were never exercised in productionDealiasnot instantiated in DNS mode:SpectralWorkspaceno longer allocates aDealiasobject when running DNS, saving memory and FFTW plan overhead
Improved¶
FD2/FD4buffer allocation: Spatial operators now pre-allocate the padded buffer and all output arrays in__init__, eliminating onenp.padallocation and five result-array allocations percompute()call- Shared padded FFT plans in LES mode:
Dealiasnow reuses the padded FFT buffers and plans fromDerivativeswhen constructed viaSpectralWorkspace, halving the number of padded FFTW plans created - LES efficiency: Eliminated unnecessary intermediate array copies throughout the LES RHS evaluation path
- Spectral performance: Replaced
up**2withnp.square(self.up, out=self.up)for in-place squaring; eliminated unnecessary.copy()inDealias.compute()return Derivatives.compute()dispatch: Changedif/if/ifchain toeliffor mutually exclusive derivative keys, avoiding redundant comparisons- Google style guide compliance: Added
Raises:sections to all factory-method docstrings (get_operator,get_integrator,get_model); added docstrings to private logging filter/handler methods; fixed imperative mood andis not Nonechecks inSpectralWorkspace; explicitint()cast fornoise.seedinInput
Removed¶
- Dead
TYPE_CHECKINGblock inspectral_workspace.py - Dead
self.mpattribute fromBurgersbase class (core.py) - Dead
_fu_validflag andrestore_physical=Falsebranch fromDerivatives.zero_nyquist physics.hyperviscositynamelist key andHyperviscosityConfigdataclass (hyperviscosity now always active and auto-configured)
[2.0.1] - 2026-03-27¶
Added¶
-i/--inputflag: Specify a custom namelist path without renaming files, enabling multiple configuration files for different experiments
Fixed¶
- Array overwrite bug: Corrected in-place overwrite in
Derivatives.computesq branch that corrupted spectral data - Output timing check: Fixed floating-point precision failure that could skip saving output frames
- FFTW wisdom accumulation: Plans now accumulate across config changes rather than being invalidated, improving cold-start performance on subsequent runs
- Cross-platform file locking: Replaced
fcntl(Unix-only) withfilelockfor portable wisdom file access
Changed¶
- Random seed API: Replaced hardcoded random seed with NumPy's configurable
GeneratorAPI for improved reproducibility control - Simulation timing: Switched to
time.perf_counter()for higher-resolution elapsed time measurement
Improved¶
- DNS performance: Runtime reduced from ~40 sec to ~34 sec via pre-allocated RHS buffer, precomputed noise scale constant, and eliminated redundant FFT pairs in RK3 Nyquist zeroing
[2.0.0] - 2026-02-02¶
Version 2.0 represents a complete rewrite of PyBurgers with modern Python practices, significant performance improvements, and enhanced usability.
Added¶
- Schema-validated namelist: JSON configuration with comprehensive validation via
schema_namelist.json - FFTW wisdom caching: Intelligent caching system stores optimized FFT plans in
~/.pyburgers_fftw_wisdomfor instant startup on subsequent runs - File locking: Thread-safe wisdom file access prevents corruption when running multiple instances
- Comprehensive logging: Configurable logging levels (DEBUG, INFO, WARNING, ERROR, CRITICAL) with file and console output
- Data models: Pydantic-style dataclasses for type-safe configuration (
data_models.py) - MkDocs documentation: Professional documentation site with Material theme
- Namelist documentation generator: Script to auto-generate documentation from JSON schema
- Comprehensive test suite: Pytest-based tests for derivatives, FBM, filtering, SGS models, and integration
- FFTW planning levels: Support for ESTIMATE, MEASURE, PATIENT, and EXHAUSTIVE planning strategies
- Multithreading: Configurable thread count for FFT operations
- Custom exceptions:
PyBurgersError,NamelistError,InvalidModefor better error handling - NetCDF metadata: Enhanced output with comprehensive simulation metadata
- pyproject.toml: Modern Python packaging with optional dependencies for dev and docs
- Hyperviscosity: Optional fourth-order hyperviscosity term (
-ν₄∂⁴u/∂x⁴) to address spectral blocking at high-frequency wavenumbers; coefficient auto-computed asΔx⁴
Changed¶
- Python requirement: Now requires Python ≥ 3.10 (up from Python 2/3 compatibility)
- FFT backend: Switched to real FFTs (rfft/irfft) for ~2× speedup and 50% memory reduction
- Project structure: Complete reorganization into logical modules:
pyburgers/core.py: Abstract base classpyburgers/dns.py: DNS solverpyburgers/les.py: LES solverpyburgers/utils/: Utilities (spectral, IO, logging, FFTW)pyburgers/physics/sgs/: Subgrid-scale models- Spectral workspace: Unified workspace object manages all FFT operations and buffers
- Initialization: Streamlined startup with warmup phase for FFTW planning
- Time stepping: Replaced Adams-Bashforth with Williamson (1980) low-storage RK3 and CFL-based adaptive time stepping
- Output organization: NetCDF output with improved structure and metadata
- Logging: Moved from print statements to proper Python logging framework
- Constants: Centralized physical and numerical constants in
utils/constants.py
Improved¶
- Performance: Dramatic speedup (~50× faster) through real FFTs, optimized FFTW planning, and efficient buffer management. Benchmark on M3 Max MacBook Pro with default namelist: DNS dropped from ~43 min to ~40 sec; LES dropped from ~23 min to ~7 sec
- Code organization: Clear separation of concerns with abstract base class and mode-specific implementations
- Documentation: Comprehensive docs covering theory, usage, API reference, and contribution guidelines
- Error messages: Descriptive error messages with context and suggestions
- Type hints: Full type annotations throughout the codebase
- Reproducibility: Fixed random seed for consistent results across runs
- Memory efficiency: Reduced memory footprint through real FFT usage and efficient buffer management
Fixed¶
- Deardorff model bugs: Corrected implementation issues in the TKE-based SGS model
- Nyquist mode handling: Proper zeroing of Nyquist mode to prevent aliasing
- Edge cases: Improved handling of boundary conditions and special cases
Developer Experience¶
- Linting: Configured Ruff for code quality (pycodestyle, pyflakes, isort, pyupgrade, flake8-bugbear)
- Formatting: Automated code formatting with Ruff
- Testing: Easy test execution with
pytestand coverage reports - CI/CD: GitHub Actions workflow for automated documentation deployment
- Development install: Simple
pip install -e ".[dev]"for development dependencies
Migration from v1.x¶
Version 2.0 is not backward compatible with v1.x. Key migration steps:
- Configuration: Convert old configuration to JSON namelist format
- Python version: Upgrade to Python 3.10 or newer
- Dependencies: Update to numpy ≥ 2.1, pyfftw ≥ 0.15, netCDF4 ≥ 1.7
- Import paths: Update imports to use new module structure
- Output files: NetCDF structure has changed; update analysis scripts accordingly
Notes¶
- First run with new grid sizes will take extra time for FFTW planning; subsequent runs will be fast
- FFTW wisdom file is stored at
~/.pyburgers_fftw_wisdomand can be deleted to force re-planning - Recommended FFTW planning level is
FFTW_PATIENTfor production runs
[1.0.0] - 2019-11-03¶
Initial release of PyBurgers.
Features¶
- Direct Numerical Simulation (DNS) mode
- Large-Eddy Simulation (LES) mode
- Four subgrid-scale models (Smagorinsky, Dynamic Smagorinsky, Wong-Lilly, Deardorff)
- Fourier collocation spatial methods
- Adams-Bashforth time integration
- Fractional Brownian motion forcing
- NetCDF output