Running AM³ with the native C++

AM³ is natively written in C++, and can be compiled and run without using the Python interface. The Python interface does not compromise on performance or flexibility, because it simply maps into Python the underlying C++ functions. To users who do not intend to customize AM³, we therefore recommend utilizing the Python interface, which is more flexible, easier to use, and does not require compilation on a project-by-project basis.

When working with C++ it is necessary to first compile the AM³ C++ library, and then your project, by using a Makefile or CMake script. You then write a C++ script with your source simulation, accompanied by a Makefile or CMake script with instructions to link the AM³ library and compile your code. We provide an example in docs/examples/cplusplus.

C++ script example

In your C++ script, make sure to first include all AM³ header files. The class subjects should be declared according to C++ syntax. You can then set up the solver, define the physical parameters, run the simulation, and print the results to an output file:

#include "AM3/AM3Arrays.h"
#include "AM3/HadronicSynchrotron.h"
#include "AM3/PairProduction.h"    
#include "AM3/Acceleration.h"
#include "AM3/AM3.h"
#include "AM3/PhysicsHandler.h"
#include "AM3/Synchrotron.h"
#include "AM3/BetheHeitler.h"        
#include "AM3/Injection.h"
#include "AM3/PionDecay.h"
#include "AM3/consts.h"
#include "AM3/Escape.h"
#include "AM3/InverseCompton.h"
#include "AM3/RunParams.h"
#include "AM3/global_defs.h"
#include "AM3/Expansion.h"
#include "AM3/MuonDecay.h"
#include "AM3/SimulationManager.h"
#include "AM3/math.h"
#include "AM3/HadronicInverseCompton.h"
#include "AM3/PhotoPion.h"
#include "AM3/ProtonProton.h"
#include "AM3/Solver.h"
#include <iostream>

using namespace std;

int main()
{
    // refer to https://am3.readthedocs.io/en/latest/examples/blazar_detailed_example.html# for a detailed description of the functions

    AM3 am3;
    am3.set_estimate_max_energies(0);

    am3.set_process_parse_sed(1);
    am3.set_process_hadronic(1);
    am3.set_process_merge_positrons_into_electrons(0);
    am3.set_process_escape(1);
    am3.set_process_expansion(0);
    am3.set_process_adiabatic_cooling(1);
    am3.set_process_electron_syn(1);
    am3.set_process_ssa(1);
    am3.set_process_proton_syn(1);
    am3.set_process_quantum_syn(0);
    am3.set_process_electron_compton(1);
    am3.set_process_proton_compton(1);
    am3.set_process_compton_photon_energy_loss(0);
    am3.set_process_muon_syn(0);
    am3.set_process_pion_syn(0);
    am3.set_process_muon_compton(0);
    am3.set_process_pion_compton(0);
    
    am3.set_process_pion_decay(1);
    am3.set_process_muon_decay(1);
    
    am3.set_process_annihilation(1);
    am3.set_optimize_annihilation_pair_emission(1);
    
    am3.set_process_bethe_heitler(1);
    am3.set_optimize_bethe_heitler_outgoing_pairs_grid(1);
    am3.set_optimize_bethe_heitler_incoming_protons_min(1e12);
    am3.set_optimize_bethe_heitler_target_photon_max(1e6);
    
    am3.set_process_photopion(1);
    am3.set_optimize_photopion_target_photon_grid(1);
    am3.set_optimize_photopion_target_photon_max(1e6);
    
    am3.init_kernels();
    
    am3.set_mag_field(1.0);
    am3.set_escape_timescale(1e17 / 3e10);
    am3.set_solver_time_step(1e-1 * am3.get_escape_timescale());

    double volume = 4 * 3.14 / 3 * pow(1e17,3);
    
    double elec_emin =  1e8;
    double elec_emax =  1e11;
    double eindex =     2.02;
    double elum =       1.84e+41;

    double proton_emin =  1e10;
    double proton_emax =  1e17;
    double pindex =     1.0;
    double plum =       6.29e+43;

    cout<<"Set particle injections"<<endl;

    am3.clear_particle_densities();
    am3.set_powerlaw_injection_parameters_electrons(volume, elum, elec_emin, elec_emin, elec_emax, eindex, eindex, 1.0);
    am3.set_powerlaw_injection_parameters_protons(volume, plum, proton_emin, proton_emin, proton_emax, pindex, pindex, 1.0);
    double time = 0;
    am3.evolve_step();
    time += am3.get_solver_time_step();




    return 0;
}

Compiling the AM³ C++ library

To compile your AM³ C++ library, you can use a CMake script like the one we provide in the AM³ root directory.

Make sure to install cmake, as well as the required Eigen and GSL libraries:

$ apt update && apt install -y g++ cmake libeigen3-dev libgsl-dev

Then navigate to your AM³ root directory and run

$ cmake -S . -B build -DPYTHON=OFF -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=~/.local/am3
$ cmake --build build -- -j 2
$ cmake --install build

The AM³ C++ library should now be installed.

Compiling your C++ project

Finally, to compile and run your C++ simulation, you need a script like the one above, and a Cmake script to link it to the pre-compiled AM³ library. Place both in the same directory (we provide an example of a CMake script in docs/examples/cplusplus), navigate to that directory, and run

$ CMAKE_PREFIX_PATH=~/.local/am3 cmake -S . -B build
$ cmake --build build

The first command writes a build/Makefile, and the second command runs the makefile and compiles your executable, in this case build/TestAM3withCpp. You can then run your project with

$ ./build/TestAM3withCpp