A modular C++20 library for electromagnetic field calculations and signal processing in QTNM (Quantum Technologies for Neutrino Mass) experiments.
The project is organized into two main categories:
Reusable mathematical and computational libraries:
- BasicCore - Header-only constants and basic math (no dependencies)
- SignalUtils - FFTW/Boost dependent signal processing utilities
- ROOTUtils - ROOT framework dependent analysis utilities
- BasicFunctions - Legacy consolidated utility functions
Domain-specific physics implementations:
- FieldClasses - EM field calculations at spatial points
- ElectronDynamics - Particle trajectory generation (Boris solver)
- Antennas - Antenna implementations (dipoles, patches, etc.)
- SignalProcessing - Voltage signals, noise, local oscillators
- Waveguides - Waveguide and cavity mode calculations
- Scattering - Electron scattering models
The core code requires C++20, built with CMake (3.18+) with the following external dependencies:
| BOOST (1.73+) | ROOT (6.14+) | FFTW3 | |
|---|---|---|---|
| BasicCore | |||
| SignalUtils | x | x | |
| ROOTUtils | x | ||
| BasicFunctions | x |
| BOOST (1.73+) | ROOT (6.14+) | FFTW3 | |
|---|---|---|---|
| FieldClasses | x | ||
| ElectronDynamics | x | x | |
| Antennas | x | ||
| SignalProcessing | x | ||
| Waveguides | x | ||
| Scattering |
HDF5 libraries are also required for some executables purely for I/O.
Utility Dependencies:
BasicCore→ No dependencies (header-only)SignalUtils→ FFTW3 + BoostROOTUtils→ BasicCore + SignalUtils + ROOTBasicFunctions→ BasicCore + ROOT
Physics Dependencies:
FieldClasses→ BasicCore + ROOTUtils + ROOTAntennas→ BasicFunctions + ROOTWaveguides→ BasicCore + ROOT + BoostElectronDynamics→ BasicCore + Waveguides + ROOT + BoostScattering→ BasicCore + BasicFunctions + BoostSignalProcessing→ SignalUtils + FieldClasses + Antennas + Waveguides + ROOT
There are also 47+ example programs (executables/) demonstrating various physics calculations and signal processing workflows. We recommend installing all packages to access the full functionality.
A docker image containing the required external libraries is available at: https://hub.docker.com/repository/docker/sebj101/qtnm_deps.
A minimal set of instructions to install the required dependencies using Ubuntu 20.04 are:
$ sudo apt-get update -y
$ sudo apt-get upgrade -y
$ sudo apt-get install -y git mpich make wget python3-pip build-essential libssl-dev libfftw3-dev libgsl27
$ wget https://github.com/Kitware/CMake/releases/download/v3.20.0/cmake-3.20.0.tar.gz
$ tar -zxvf cmake-3.20.0.tar.gz
$ cd cmake-3.20.0
$ ./bootstrap
$ make
$ make install
$ wget https://root.cern/download/root_v6.26.04.Linux-ubuntu22-x86_64-gcc11.2.tar.gz
$ tar -xzvf root_v6.26.04.Linux-ubuntu22-x86_64-gcc11.2.tar.gz
$ echo "source /path/to/root/bin/thisroot.sh" >> ~/.bashrc
$ source ~/.bashrc
$ wget https://boostorg.jfrog.io/artifactory/main/release/1.73.0/source/boost_1_73_0.tar.bz2
$ tar --bzip2 -xf boost_1_73_0.tar.bz2
$ cd "boost_1_73_0/"
$ ./bootstrap.sh --prefix=/usr/local --with-libraries=program_options
$ ./b2 install
$ sudo apt-get install -y libhdf5-serial-dev
The package uses a hierarchical CMake build system.
$ mkdir build
$ cd build
$ cmake ..
$ cmake --build . -jNwhere N is the number of cores used in the build
- Modular Design: Each
utilities/andphysics/directory manages its own subdirectories - Clean Dependencies: Clear separation between utility libraries and physics modules
- Selective Building: Can build individual libraries as needed
- Professional Structure: Follows modern C++ project organization patterns
- Maintainable: Easy to add new libraries or modify existing ones
All the code required to create magnetic fields and electron trajectories is contained within the physics/ElectronDynamics/ module.
It is possible to use the contained classes to generate your own electron trajectories (this is demonstrated in the writeTrajectory executable).
However, a helper class (ElectronTrajectoryGen contained within physics/ElectronDynamics/TrajectoryGen.h) exists which will create ROOT files containing the trajectories in a format that can be read by other package components.
The required arguments are:
- The output file path
- A pointer to the magnetic field map (more on this later)
- A ROOT TVector3 of the initial electron position
- A ROOT TVector3 of the initial electron velocity
- The simulation step size to use in seconds (for reference an endpoint electron in a 1T field will have a cyclotron period of about
$3.7 \times 10^{-11}$ seconds so 20 steps per orbit would be$1.85 \times 10^{-12}$ . - The total time to simulate in seconds
The optional arguments are:
- The time (in seconds) at which to start the simulation
- The energy loss (which by default is zero). For realistic energy loss this should be set to
$2 r_{e} / (3 c)$
Upon successfuly creation of the ElectronTrajectoryGen object, call the GenerateTraj member function to produce the file.
The solver used to propagate the particles is the Boris solver which is energy conserving (except for any specified energy losses). An explanation of the solver (named as the Boris C solver) is given in Ref. 1.
Classes representing several types of magnetic fields and trapping configurations are found in physics/ElectronDynamics/QTNMFields.h.
The most familiar ones are BathtubField and HarmonicField.
Different types of antenna are implemented as derived classes of the abstract base class IAntenna in physics/Antennas/.
Typically the one used for analyses is the HalfWaveDipole.
Implementations exist for other antennas including HertzianDipole, PatchAntenna, and IsotropicAntenna.
The HalfWaveDipole requires a spatial position, the directions of two (perpendicular) cartesian axes and a central frequency.
Additionally a time delay (in seconds) may be specified for the antenna.
If you want to view the EM fields at a given point in space the best class to use is FieldPoint located in physics/FieldClasses/FieldClasses.h which takes as its inputs a ROOT file containing an electron trajectory and a pointer to an antenna.
Calling the function GenerateFields is required to generate the fields between two specified times.
The InducedVoltage class (in physics/SignalProcessing/) provides a lighter weight implementation of just the voltage induced on the specific antenna (or array of antennas).
The required inputs are an electron trajectory file and either a pointer to an antenna or (in the case of simulating an array of antennas wired together) a vector of antennas.
Additionally, a boolean can be specified over whether or not to include the signal propagation time when generating the signal.
If one just wants to view this signal without any downmixing, downsampling or noise added then simply call the function GenerateVoltage.
A TGraph of the time series signal can then be produced using GetVoltageGraph.
Full signal processing is done using the Signal class (in physics/SignalProcessing/) which takes as an input the path to the electron trajectory file, a pointer to the IAntenna, a LocalOscillator used to define the down-mixing and the sampling rate (in Hertz).
Additionally a vector of GaussianNoise terms can be supplied as well as a maximum acquisition time.
The organized utility libraries provide:
- BasicCore: Constants (
utilities/BasicCore/Constants.h), math utilities, neutrino oscillation parameters - SignalUtils: FFTW wrappers, digital filters (
ButterworthFilter), Fourier transforms - ROOTUtils: TGraph utilities, power spectra, correlation analysis, signal analysis functions
- BasicFunctions: Consolidated legacy functions for backward compatibility