Solves the 2D wave equation on a square domain with zero boundary conditions. Uses implicit time stepping with a Gauss-Seidel iterative solver, parallelized via MPI 2D Cartesian domain decomposition.
# Install MPI and NetCDF (Ubuntu/Debian)
sudo apt install libopenmpi-dev libnetcdf-dev
# Install MPI and NetCDF (Arch)
sudo pacman -S openmpi netcdf
# Build and run
mpicc -O3 -march=native waveEq.c -o wave.x -lnetcdf -lm
mpirun -np 4 ./wave.x
# View results
ncview grid.ncwaveEq.c Main solver (MPI topology, Gauss-Seidel, time loop)
config.h Simulation parameters and output toggles
io_netcdf.h NetCDF output (included when write_netcdf=1)
io_tensogram.h Tensogram benchmark (included when write_tensogram=1)
tensogram.h Tensogram C API header (from tensogram FFI build)
visualize_tgm.py Animate a single .tgm file (PIL-optimized GIFs)
plot_bench.py Benchmark report: comparison PNGs + per-codec GIFs
benchmark.md Compression benchmark results and analysis
Controlled by flags in config.h. Set to 1 to enable, 0 to disable.
| Flag | Default | Output file | Requires |
|---|---|---|---|
write_posix |
0 | t_NNNN.txt |
nothing |
write_netcdf |
0 | grid.nc |
libnetcdf |
write_tensogram |
1 | bench_*.tgm |
libtensogram_ffi |
Tensogram is a binary format for N-dimensional tensors with built-in compression. To enable it:
- Set
write_tensogramto1inconfig.h - Build the Tensogram FFI library and copy its header:
cd /path/to/tensogram
cargo build --release -p tensogram-ffi
cp crates/tensogram-ffi/tensogram.h /path/to/2d_wave_mpi/- Compile with the Tensogram library:
TGM=/path/to/tensogram/target/release
mpicc -O3 -march=native -I. waveEq.c -o wave.x \
-L$TGM -ltensogram_ffi -lm -lpthread -ldl- Run with the library path:
LD_LIBRARY_PATH=$TGM mpirun -np 16 ./wave.xSet write_netcdf to 1 and write_tensogram to 0 in config.h:
mpicc -O3 -march=native waveEq.c -o wave.x -lnetcdf -lmSet both write_netcdf and write_tensogram to 0 in config.h:
mpicc -O3 -march=native waveEq.c -o wave.x -lmWhen write_tensogram is enabled, the solver captures simulation frames and then benchmarks all 21 compression codecs automatically. Each codec writes a separate bench_<name>.tgm file and the results are printed as a table and saved to results.md.
The codecs tested include:
- Lossless: raw, lz4, zstd (levels 1/3/9), blosc2
- Lossless + shuffle: byte shuffle with zstd, lz4, blosc2
- Lossy quantization: simple_packing at 24/16/12 bits per value, combined with zstd, lz4, or szip
- Floating-point lossy: ZFP (fixed rate, fixed accuracy), SZ3 (absolute and relative error bounds)
See benchmark.md for the full benchmark table with analysis and recommendations.
ncview grid.nc# Interactive window
python3 visualize_tgm.py grid.tgm
# Save as GIF (every 10th frame)
python3 visualize_tgm.py grid.tgm 10 --save
# Zoom into a sub-region using range decode
python3 visualize_tgm.py grid.tgm 10 --zoom 100:400,100:400 --save# Static comparison PNGs (all codecs side by side + error maps)
python3 plot_bench.py 150 --save
# Generate animated GIFs for every codec
python3 plot_bench.py 150 --save --gifs --skip 3Both Python scripts require the tensogram Python bindings:
cd /path/to/tensogram
python3 -m venv .venv && source .venv/bin/activate
pip install numpy matplotlib Pillow maturin
cd crates/tensogram-python && maturin develop --releaseThe number of MPI ranks must be a perfect square (1, 4, 9, 16, ...) and the grid size (528 by default) must be divisible by sqrt(ranks).
mpirun -np 1 ./wave.x # single process
mpirun -np 4 ./wave.x # 2x2 decomposition
mpirun -np 16 ./wave.x # 4x4 decomposition (recommended)All parameters are in config.h.
| Parameter | Default | Description |
|---|---|---|
dx |
0.00594998 | Grid spacing (gives 528x528 grid) |
dt |
0.001 | Time step |
f_to_go |
3.14159 (pi) | Domain size |
t_to_go |
3.0 | Total simulation time |
gerr_max |
1e-6 | Gauss-Seidel convergence tolerance |
| Parameter | Default | Description |
|---|---|---|
write_posix |
0 | Enable POSIX text file output |
write_netcdf |
0 | Enable NetCDF output |
write_tensogram |
1 | Enable Tensogram compression benchmark |
write_interval |
10 | Write every Nth solver step (reduces output size) |
tgm_bench_steps |
0 | Max frames to capture (0 = all) |
The solver runs 3001 steps for t=3.0. write_interval controls how many are captured:
| write_interval | Frames | Raw size | Covers |
|---|---|---|---|
| 1 | 3001 | 6.69 GB | every step |
| 10 | 301 | 671 MB | every 10th step |
| 20 | 151 | 337 MB | every 20th step |
