NMR Random Walk Simulation
Simulate solid-state NMR spectra and stimulated echo (STE) decays using random walk models.
Build
Requires CMake 3.18+, a C++17 compiler, and OpenMP.
cmake -B build
cmake --build build
The executable is build/src/rwsim.
Running
./build/src/rwsim /path/to/config.txt MotionModel DistributionModel --ste --spectrum -ARG1 1 -ARG2 2
Three positional arguments are required: the path to a configuration file, the motion model name, and the distribution model name.
Set --ste and/or --spectrum to run stimulated echo or spectrum simulations.
Any parameter from the configuration file can be overridden on the command line, e.g. -tau 1e-3.
Use -seed 42 for reproducible results. Without a seed, a random one is used.
Output files are overwritten if a simulation with the same parameters is run again.
Configuration file
Change delta, eta, mixing times, echo times, etc. in this file. If a parameter appears multiple times, only the last value is used.
General parameters
| Parameter | Description |
|---|---|
| num_walker | Number of trajectories |
| delta | Anisotropy parameter in Hz |
| eta | Asymmetry parameter |
Distribution of correlation times
| Model | CLI name | Parameters |
|---|---|---|
| Delta distribution (same tau for all walkers) | Delta |
tau (jump time in s) |
| Log-normal distribution | LogNormal |
tau (peak time in s), sigma (width) |
Motion models
| Model | CLI name | Parameters |
|---|---|---|
| Isotropic random jump | RandomJump |
— |
| Isotropic jump by fixed angle | IsotropicAngle |
angle (degrees) |
| Bimodal angle distribution | BimodalAngle |
angle1, angle2 (degrees), probability1 (0–1) |
| Tetrahedral 4-site jump | FourSiteTetrahedral |
— |
| Octahedral 6-site jump (C3) | SixSiteOctahedralC3 |
— |
| N-site jump on cone | NSiteConeJump |
num_sites, chi (cone angle, degrees) |
| Random jump on cone | RandomJumpOnCone |
angle (cone angle) |
| Wobbling in cone | ConeWobble |
angle (cone angle) |
Spectrum parameters
| Parameter | Description |
|---|---|
| dwell_time | Acquisition dwell time in s |
| num_acq | Number of acquisition points |
| techo_start | First echo time in s |
| techo_stop | Last echo time in s |
| techo_steps | Number of echo times |
STE parameters
| Parameter | Description |
|---|---|
| tevo_start | First evolution time in s |
| tevo_stop | Last evolution time in s |
| tevo_steps | Number of evolution times |
| tmix_start | First mixing time in s |
| tmix_stop | Last mixing time in s |
| tmix_steps | Number of mixing times (log-spaced) |
| tpulse4 | Delay of 4th pulse in s |
Architecture
The simulation is built around three abstractions:
Dynamics
Dynamics (src/dynamics/base.h) produces trajectory steps — pairs of {dt, omega} representing a waiting time and the NMR frequency after a jump. This is the core interface for defining physical models.
DecoupledDynamics wraps a separate motion model and time distribution, calling them independently. This covers all existing models.
To implement a coupled model where motion and time are interdependent (e.g. jump angle affects waiting time, or position-dependent dynamics), implement the Dynamics interface directly:
class MyModel : public Dynamics {
void initialize(std::mt19937_64& rng) override { /* set initial state */ }
Step next(std::mt19937_64& rng) override {
// draw angle, compute rate from angle, draw wait time from rate
return {dt, omega};
}
// ... clone(), setParameters(), etc.
};
Experiment
Experiment (src/experiments/base.h) defines how trajectory data is turned into observables:
setup(params)— configure time axes, allocate accumulatorsaccumulate(trajectory)— process one walker's trajectorysave(directory)— write results to filesclone()/merge()— for thread-parallel accumulation
Existing experiments: SpectrumExperiment, STEExperiment.
Simulation runner
run_simulation() (src/sims.h) connects a Dynamics and an Experiment:
- Sets parameters on both
- Generates trajectories in parallel (OpenMP, one clone per thread)
- Each thread accumulates into its own experiment clone
- Merges thread-local results
- Saves output
The walker loop is parallelized with OpenMP using static scheduling for deterministic reproducibility with a given seed and thread count.