129 lines
4.7 KiB
Markdown
129 lines
4.7 KiB
Markdown
# 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.
|
||
|
||
```bash
|
||
cmake -B build
|
||
cmake --build build
|
||
```
|
||
|
||
The executable is `build/src/rwsim`.
|
||
|
||
# Running
|
||
|
||
```bash
|
||
./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:
|
||
|
||
```cpp
|
||
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 accumulators
|
||
- `accumulate(trajectory)` — process one walker's trajectory
|
||
- `save(directory)` — write results to files
|
||
- `clone()` / `merge()` — for thread-parallel accumulation
|
||
|
||
Existing experiments: `SpectrumExperiment`, `STEExperiment`.
|
||
|
||
## Simulation runner
|
||
|
||
`run_simulation()` (`src/sims.h`) connects a `Dynamics` and an `Experiment`:
|
||
|
||
1. Sets parameters on both
|
||
2. Generates trajectories in parallel (OpenMP, one clone per thread)
|
||
3. Each thread accumulates into its own experiment clone
|
||
4. Merges thread-local results
|
||
5. Saves output
|
||
|
||
The walker loop is parallelized with OpenMP using static scheduling for deterministic reproducibility with a given seed and thread count.
|