IAP GITLAB

Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • AirShowerPhysics/corsika
  • rulrich/corsika
  • AAAlvesJr/corsika
  • Andre/corsika
  • arrabito/corsika
  • Nikos/corsika
  • olheiser73/corsika
  • AirShowerPhysics/papers/corsika
  • pranav/corsika
9 results
Show changes
Showing
with 3030 additions and 23 deletions
#ifndef _Physics_NullModel_NullModel_h_
#define _Physics_NullModel_NullModel_h_
namespace physics {
namespace processes {
class NullModel {
public:
NullModel();
~NullModel();
void init();
void run();
double GetStepLength();
};
}
}
#endif
# CORSIKA 8 Framework for Particle Cascades in Astroparticle Physics
The purpose of CORSIKA 8 is to simulate any particle cascades in
astroparticle physics or astrophysical context. A lot of emphasis has been
put on modularity, flexibility, completeness, validation and
correctness. To boost computational efficiency, different techniques
are provided, like thinning or cascade equations. The aim is that
CORSIKA 8 remains the most comprehensive framework for simulating
particle cascades with stochastic and continuous processes.
The software makes extensive use of static design patterns and
compiler optimization. Thus, the most fundamental configuration
decisions of the user must be performed at compile time. At run time,
model parameters can still be changed.
CORSIKA 8 is by default released under the BSD 3-Clause License. See [license
file](https://gitlab.iap.kit.edu/AirShowerPhysics/corsika/blob/master/LICENSE)
which is part of every release and the source code.
If you use, or want to refer to, CORSIKA 8 please cite ["Towards a Next
Generation of CORSIKA: A Framework for the Simulation of Particle
Cascades in Astroparticle Physics", Comput. Softw. Big Sci. 3 (2019)
2](https://doi.org/10.1007/s41781-018-0013-0) as well as
["Simulating radio emission from particle cascades with CORSIKA 8", Astropart. Phys. 166 (2025)
103072](https://doi.org/10.1016/j.astropartphys.2024.103072).
We kindly ask (and require) any relevant improvement or addition to be offered or
contributed to the main CORSIKA 8 repository for the benefit of the
whole community.
CORSIKA 8 makes use of various third-party code, in particular interaction
models. Please check the [using and collaborating
agreement](https://gitlab.iap.kit.edu/AirShowerPhysics/corsika/blob/master/USING_COLLABORATING.md)
for further information on this topic.
If you plan to contribute to CORSIKA 8, please check the guidelines outlined here:
[coding
guidelines](https://gitlab.iap.kit.edu/AirShowerPhysics/corsika/blob/master/CONTRIBUTING.md). Code
that fails the review by the CORSIKA 8 author group must be improved
before it can be merged in the official code base. After your code has
been accepted and merged, you become a contributor of the CORSIKA 8
project (code author).
IMPORTANT: Before you contribute, you need to read and agree to the conditions set out in the
[using and collaborating
agreement](https://gitlab.iap.kit.edu/AirShowerPhysics/corsika/blob/master/USING_COLLABORATING.md).
The agreement can be discussed, and eventually improved if necessary.
## Get in contact
* Join our chat threads using Mattermost via this [invite link](https://mattermost.hzdr.de/signup_user_complete/?id=xtdd8jyt6trbiezt71gaz3z4ge&md=link&sbr=su). Click the `GitLab` button, then `Sign in with Helmholtz ID`. You will be able to make an account by either finding your institution, or using your e.g. ORCID, GitHub, or Google account.
* Connect to https://gitlab.iap.kit.edu, register yourself and join the "Air Shower Physics" group. Write to us on Mattermost (in the User Questions channel), or directly contact one of the [steering comittee members](https://gitlab.iap.kit.edu/AirShowerPhysics/corsika/-/wikis/Steering-Committee) in case there are problems with that.
* Connect to corsika-devel@lists.kit.edu (self-register at
https://www.lists.kit.edu/sympa/subscribe/corsika-devel) to get in
touch with the project.
## Installation
CORSIKA 8 is tested regularly at least on `gcc11.0.0` and `clang-14.0.0`.
### Prerequisites
You will also need:
- Python 3 (supported versions are Python >= 3.6), with pip
- cmake > 3.4
- git
- g++, gfortran, binutils, make
- optional: FLUKA (see below)
On a bare Ubuntu machine, just add:
``` shell
sudo apt-get install python3 python3-pip cmake g++ gfortran git doxygen graphviz
```
### Creating a virtual environment and Conan
It is recommended that you install CORSIKA 8 and its dependencies within a python3 virtual environment.
To do so, you can run the following.
``` shell
# Create the environment using your native python3 binary
python3 -m venv /path/to/new/virtual/environment/corsika-8
# Load the environment (should be run each time you open a new terminal)
source /path/to/new/virtual/environment/corsika-8/bin/activate
```
You will need to load the environment each time that you open a new terminal.
CORSIKA 8 uses the [conan](https://conan.io/) package manager to
manage our dependencies. Currently, version 2.50.0 or higher is required.
**Note**: if you are NOT using a virtual environment, you may want to use the `pip install --user` flag.
``` shell
pip install conan particle==0.25.1 numpy
```
### Enabling FLUKA support
For legal reasons we do not distribute/bundle FLUKA together with CORSIKA 8.
As FLUKA is the standard low-energy hadronic interaction model for CORSIKA 8, you have to download
it separately from (http://www.fluka.org/), which requires registering there as FLUKA user.
The following should be done *before* compiling CORSIKA 8:
1. Note your system's version of gfortran (`gfortran --version`) and glibc (`ldd --version`)
2. Download the FLUKA __binary__, ensuring that it matches the versions you found above
3. Download the FLUKA __data file__ (will be named something similar to __fluka20xy.z-data.tar.gz__).
4. Un-tar the files that you downloaded using `tar -xf <filename>`
5. Set environmental variables `export FLUFOR=gfortran` and `export FLUPRO=<path to where you unzipped the files>`. Note that the `FLUPRO` directory should contain __libflukahp.a__. Both of these variables will have to be set every time you open a new terminal.
6. Go to the `FLUPRO` directory and run `make`. This will compile an exe, __flukahp__, in your current directory.
7. Follow the normal steps to compile CORSIKA 8 (see below).
When you later install CORSIKA 8, you should see a message during the __cmake__ step indicating the FLUKA was correctly found.
``` shell
libflukahp.a found in directory <some location here> via FLUPRO environment variable
FLUKA support is enabled.
```
### Compiling CORSIKA 8
Once Conan is installed and FLUKA provided, follow these steps to download and install CORSIKA 8:
``` shell
cd ./top/directory/for/corsika/installation
git clone --recursive git@gitlab.iap.kit.edu:AirShowerPhysics/corsika.git
# Or for https: git clone --recursive https://gitlab.iap.kit.edu/AirShowerPhysics/corsika.git
mkdir corsika-build
cd corsika-build
../corsika/conan-install.sh --source-directory ../corsika --release-with-debug
# conan-install.sh takes required options from command line to install dependencies for 'Debug', 'Release' and 'RelWithDebInfo' builds.
../corsika/corsika-cmake.sh -c "-DCMAKE_BUILD_TYPE="RelWithDebInfo" -DWITH_FLUKA=ON -DCMAKE_INSTALL_PREFIX=../corsika-install"
make -j4 #The number should match the number of available cores on your machine
make install
```
## Alternate installation using docker containers
There are docker containers prepared that bring all the environment and packages you need to run CORSIKA. See [docker hub](https://hub.docker.com/repository/docker/corsika/devel) for a complete overview.
### Prerequisites
You only need docker, e.g. on Ubuntu: `sudo apt-get install docker` and of course root access.
### Compiling
Follow these steps to download and install CORSIKA 8, master development version
```shell
cd ./top/directory/for/corsika/installation
git clone --recursive git@gitlab.iap.kit.edu:AirShowerPhysics/corsika.git
sudo docker run -v $PWD:/corsika -it corsika/devel:clang-8 /bin/bash
mkdir corsika-build
cd corsika-build
../corsika/conan-install.sh --source-directory ../corsika --release-with-debug
# conan-install.sh takes required options from command line to install dependencies for 'Debug', 'Release' and 'RelWithDebInfo' builds.
../corsika/corsika-cmake.sh -c "-DCMAKE_BUILD_TYPE="RelWithDebInfo" -DWITH_FLUKA=ON -DCMAKE_INSTALL_PREFIX=../corsika-install"
make -j4 #The number should match the number of available cores on your machine
make install
```
## Running Unit Tests
To run the unit tests, do the following.
```shell
cd ./corsika-build
ctest -j4 #The number should match the number of available cores on your machine
```
## Running applications and examples
### Standard applications
Applications for standard use-cases are located in the `applications` directory.
These are example scripts that can be used directly or slightly modified for your use case.
See [applications/README.md] for more.
The applications are compiled automatically after running `make` and will appear your `corsika-build/bin` directory.
After running `make install` the binaries will also be copied into your `corsika-install/bin` directory as well.
For example, from inside your `corsika-install/bin` directory, run
```shell
c8_air_shower --pdg 2212 -E 1e5 -f my_shower
```
This will run a vertical 100 TeV proton shower and will create and put the output into `./my_shower`.
### Building the examples
Unlike the applications, the examples must be compiled as a second step.
From your top corsika directory, (the one that includes `corsika-build` and `corsika-install`) run
```shell
export CONAN_DEPENDENCIES=$PWD/corsika-install/lib/cmake/dependencies
cmake -DCMAKE_TOOLCHAIN_FILE=${CONAN_DEPENDENCIES}/conan_toolchain.cmake -DCMAKE_PREFIX_PATH=${CONAN_DEPENDENCIES} -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_BUILD_TYPE=RelWithDebInfo -Dcorsika_DIR=$PWD/corsika-build -DWITH_FLUKA=ON -S $PWD/corsika/examples -B $PWD/corsika-build-examples
cd corsika-build-examples
make -j4 #The number should match the number of available cores on your machine
```
You can run the examples by using the binaries in `corsika-build-examples/bin/`.
For example:
```shell
corsika-build-examples/bin/known_particles
```
This will print out all of the particles that are known by CORSIKA.
### Generating doxygen documentation
To generate the documentation, you need doxygen and graphviz. If you work with
the docker corsika/devel containers this is already included.
Otherwise, e.g. on Ubuntu machines, do:
```shell
sudo apt-get install doxygen graphviz
```
Switch to the `corsika-build` directory and do
```shell
make docs
make install
```
open with firefox:
```shell
firefox ../corsika-install/share/corsika/doc/html/index.html
```
# Usage and collaboration agreement
The CORSIKA 8 project very much welcomes all collaboration and
contributions. The aim of the project is to create a
scientific software framework as a fundamental tool for research.
The project consists of the contributions from the scientific
community and individuals in a best effort to deliver the best
possible performance and physics output.
## The software license of the CORSIKA project
CORSIKA 8 is by default released under the BSD 3-Clause License, as copied in full in the file
[LICENSE](LICENSE). Each source file of the CORSIKA project contains a
short statement of the copyright and this license. Each binary or
source code release of CORSIKA contains the file LICENSE.
The code, documentation and content in the folder [./externals](./externals)
is not integral part of the CORSIKA project and can be based on, or
include, other licenses, which must be compatible with the CORSIKA 8 license.
The folder [./modules](./modules) contains the code of several
external physics models for your convenience. They each come with
their own license which we ask you to honor. Please also make sure to cite the
adequate reference papers when using their models in scientific work
and publications.
Of course, we have the authors' consent to
distribute their code together with CORSIKA 8.
Check the content of these folders carefully for details and additional
license information. It depends on the configuration of
the build system to what extent this code is used to build CORSIKA.
## Contributing
If you want to contribute, you need to read
[the contributing GUIDELINES](CONTRIBUTING.md) and comply with these rules, or help to
improve them.
## General guidelines
We reproduce below some guidelines copied from http://www.montecarlonet.org/ that we also ask you to follow in the spirit of academic collaboration.
1) The integrity of the program should be respected.
-------------------------------------------------
1.1) Suspected bugs and proposed fixes should be reported back to the
original authors to be considered for inclusion in the standard
distribution. No independently developed and maintained forks
should be created as long as the original authors actively work on
the program.
1.2) The program should normally be redistributed in its entirety.
When there are special reasons, an agreement should be sought with
the original authors to redistribute only specific parts. This
should be arranged such that the redistributed parts remain
updated in step with the standard distribution.
1.3) Any changes in the code must be clearly marked in the source
(reason, author, date) and documented. If any modified version is
redistributed it should be stated at the point of distribution
(download link) that it has been modified and why.
1.4) If a significant part of the code is used by another program,
this should be clearly specified in that program's documentation and
stated at its point of distribution.
1.5) Copyright information and references may not be removed.
Copyright-related program messages may not be altered and must be
printed even if only a part of the program is used. Adding further
messages specifying any modifications is encouraged.
2) The program and its physics should be properly cited when used for
academic publications
------------------------------------------------------------------
2.1) The main software reference as designated by the program authors
should always be cited.
2.2) In addition, the original literature on which the program is based
should be cited to the extent that it is of relevance for a study,
applying the same threshold criteria as for other literature.
2.3) When several programs are combined, they should all be mentioned,
commensurate with their importance for the physics study at hand.
2.4) To make published results reproducible, the exact versions of the
codes that were used and any relevant program and parameter
modifications should be spelled out.
(These guidelines were originally edited by Nils Lavesson and David Grellscheid
for the MCnet collaboration, which has approved and agreed to respect
them. MCnet is a Marie Curie Research Training Network funded under
Framework Programme 6 contract MRTN-CT-2006-035606.)
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
add_executable (c8_air_shower c8_air_shower.cpp)
target_link_libraries (c8_air_shower CORSIKA8)
if(WITH_FLUKA)
message("compiling c8_air_shower.cpp with FLUKA")
target_compile_definitions(c8_air_shower PRIVATE WITH_FLUKA)
else()
message("compiling c8_air_shower.cpp with UrQMD")
endif()
install (
TARGETS c8_air_shower DESTINATION bin
)
# CORSIKA 8 Applications
This directory contains standard applications which are typical for astroparticle physics solutions.
They are "physics-complete" and are suitable for generating simulations that can be used in publications.
For example, `c8_air_shower.cpp` would be a similar binary to what would be built by CORSIKA 7 and will simulate
air showers in a curved atmosphere.
/*
* (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
*
* This software is distributed under the terms of the 3-clause BSD license.
* See file LICENSE for a full version of the license.
*/
/* clang-format off */
// InteractionCounter used boost/histogram, which
// fails if boost/type_traits have been included before. Thus, we have
// to include it first...
#include <corsika/framework/process/InteractionCounter.hpp>
/* clang-format on */
#include <corsika/framework/core/Cascade.hpp>
#include <corsika/framework/core/EnergyMomentumOperations.hpp>
#include <corsika/framework/core/Logging.hpp>
#include <corsika/framework/core/PhysicalUnits.hpp>
#include <corsika/framework/geometry/PhysicalGeometry.hpp>
#include <corsika/framework/geometry/Plane.hpp>
#include <corsika/framework/geometry/Sphere.hpp>
#include <corsika/framework/process/DynamicInteractionProcess.hpp>
#include <corsika/framework/process/ProcessSequence.hpp>
#include <corsika/framework/process/SwitchProcessSequence.hpp>
#include <corsika/framework/random/RNGManager.hpp>
#include <corsika/framework/random/PowerLawDistribution.hpp>
#include <corsika/framework/utility/CorsikaFenv.hpp>
#include <corsika/framework/utility/SaveBoostHistogram.hpp>
#include <corsika/modules/writers/EnergyLossWriter.hpp>
#include <corsika/modules/writers/InteractionWriter.hpp>
#include <corsika/modules/writers/LongitudinalWriter.hpp>
#include <corsika/modules/writers/PrimaryWriter.hpp>
#include <corsika/modules/writers/SubWriter.hpp>
#include <corsika/output/OutputManager.hpp>
#include <corsika/media/CORSIKA7Atmospheres.hpp>
#include <corsika/media/Environment.hpp>
#include <corsika/media/GeomagneticModel.hpp>
#include <corsika/media/GladstoneDaleRefractiveIndex.hpp>
#include <corsika/media/HomogeneousMedium.hpp>
#include <corsika/media/IMagneticFieldModel.hpp>
#include <corsika/media/LayeredSphericalAtmosphereBuilder.hpp>
#include <corsika/media/MediumPropertyModel.hpp>
#include <corsika/media/NuclearComposition.hpp>
#include <corsika/media/ShowerAxis.hpp>
#include <corsika/media/UniformMagneticField.hpp>
#include <corsika/modules/BetheBlochPDG.hpp>
#include <corsika/modules/Epos.hpp>
#include <corsika/modules/LongitudinalProfile.hpp>
#include <corsika/modules/ObservationPlane.hpp>
#include <corsika/modules/PROPOSAL.hpp>
#include <corsika/modules/ParticleCut.hpp>
#include <corsika/modules/Pythia8.hpp>
#include <corsika/modules/QGSJetII.hpp>
#include <corsika/modules/Sibyll.hpp>
#include <corsika/modules/Sophia.hpp>
#include <corsika/modules/StackInspector.hpp>
#include <corsika/modules/thinning/EMThinning.hpp>
// for ICRC2023
#ifdef WITH_FLUKA
#include <corsika/modules/FLUKA.hpp>
#else
#include <corsika/modules/UrQMD.hpp>
#endif
#include <corsika/modules/TAUOLA.hpp>
#include <corsika/modules/radio/CoREAS.hpp>
#include <corsika/modules/radio/RadioProcess.hpp>
#include <corsika/modules/radio/ZHS.hpp>
#include <corsika/modules/radio/observers/Observer.hpp>
#include <corsika/modules/radio/observers/TimeDomainObserver.hpp>
#include <corsika/modules/radio/detectors/ObserverCollection.hpp>
#include <corsika/modules/radio/propagators/TabulatedFlatAtmospherePropagator.hpp>
#include <corsika/setup/SetupStack.hpp>
#include <corsika/setup/SetupTrajectory.hpp>
#include <corsika/setup/SetupC7trackedParticles.hpp>
#include <boost/filesystem.hpp>
#include <CLI/App.hpp>
#include <CLI/Config.hpp>
#include <CLI/Formatter.hpp>
#include <cstdlib>
#include <iomanip>
#include <limits>
#include <string>
using namespace corsika;
using namespace std;
using EnvironmentInterface =
IRefractiveIndexModel<IMediumPropertyModel<IMagneticFieldModel<IMediumModel>>>;
using EnvType = Environment<EnvironmentInterface>;
using StackType = setup::Stack<EnvType>;
using TrackingType = setup::Tracking;
using Particle = StackType::particle_type;
//
// This is the main example script which runs EAS with fairly standard settings
// w.r.t. what was implemented in CORSIKA 7. Users may want to change some of the
// specifics (observation altitude, magnetic field, energy cuts, etc.), but this
// example is the most physics-complete one and should be used for full simulations
// of particle cascades in air
//
long registerRandomStreams(long seed) {
RNGManager<>::getInstance().registerRandomStream("cascade");
RNGManager<>::getInstance().registerRandomStream("qgsjet");
RNGManager<>::getInstance().registerRandomStream("sibyll");
RNGManager<>::getInstance().registerRandomStream("sophia");
RNGManager<>::getInstance().registerRandomStream("epos");
RNGManager<>::getInstance().registerRandomStream("pythia");
RNGManager<>::getInstance().registerRandomStream("urqmd");
RNGManager<>::getInstance().registerRandomStream("fluka");
RNGManager<>::getInstance().registerRandomStream("proposal");
RNGManager<>::getInstance().registerRandomStream("thinning");
RNGManager<>::getInstance().registerRandomStream("primary_particle");
if (seed == 0) {
std::random_device rd;
seed = rd();
CORSIKA_LOG_INFO("random seed (auto) {}", seed);
} else {
CORSIKA_LOG_INFO("random seed {}", seed);
}
RNGManager<>::getInstance().setSeed(seed);
return seed;
}
template <typename T>
using MyExtraEnv =
GladstoneDaleRefractiveIndex<MediumPropertyModel<UniformMagneticField<T>>>;
int main(int argc, char** argv) {
// the main command line description
CLI::App app{"Simulate standard (downgoing) showers with CORSIKA 8."};
CORSIKA_LOG_INFO(
"Please cite the following papers when using CORSIKA 8:\n"
" - \"Towards a Next Generation of CORSIKA: A Framework for the Simulation of "
"Particle Cascades in Astroparticle Physics\", Comput. Softw. Big Sci. 3 (2019) "
"2, https://doi.org/10.1007/s41781-018-0013-0\n"
" - \"Simulating radio emission from particle cascades with CORSIKA 8\", "
"Astropart. Phys. 166 (2025) 103072, "
"https://doi.org/10.1016/j.astropartphys.2024.103072");
//////// Primary options ////////
// some options that we want to fill in
int A, Z, nevent = 0;
std::vector<double> cli_energy_range;
// the following section adds the options to the parser
// we start by definining a sub-group for the primary ID
auto opt_Z = app.add_option("-Z", Z, "Atomic number for primary")
->check(CLI::Range(0, 26))
->group("Primary");
auto opt_A = app.add_option("-A", A, "Atomic mass number for primary")
->needs(opt_Z)
->check(CLI::Range(1, 58))
->group("Primary");
app.add_option("-p,--pdg",
"PDG code for primary (p=2212, gamma=22, e-=11, nu_e=12, mu-=13, "
"nu_mu=14, tau=15, nu_tau=16).")
->excludes(opt_A)
->excludes(opt_Z)
->group("Primary");
app.add_option("-E,--energy", "Primary energy in GeV")->default_val(0);
app.add_option("--energy_range", cli_energy_range,
"Low and high values that define the range of the primary energy in GeV")
->expected(2)
->check(CLI::PositiveNumber)
->group("Primary");
app.add_option("--eslope", "Spectral index for sampling energies, dN/dE = E^eSlope")
->default_val(-1.0)
->group("Primary");
app.add_option("-z,--zenith", "Primary zenith angle (deg)")
->default_val(0.)
->check(CLI::Range(0., 90.))
->group("Primary");
app.add_option("-a,--azimuth", "Primary azimuth angle (deg)")
->default_val(0.)
->check(CLI::Range(0., 360.))
->group("Primary");
//////// Config options ////////
app.add_option("--emcut",
"Min. kin. energy of photons, electrons and "
"positrons in tracking (GeV)")
->default_val(0.5e-3)
->check(CLI::Range(0.000001, 1.e13))
->group("Config");
app.add_option("--hadcut", "Min. kin. energy of hadrons in tracking (GeV)")
->default_val(0.3)
->check(CLI::Range(0.02, 1.e13))
->group("Config");
app.add_option("--mucut", "Min. kin. energy of muons in tracking (GeV)")
->default_val(0.3)
->check(CLI::Range(0.000001, 1.e13))
->group("Config");
app.add_option("--taucut", "Min. kin. energy of tau leptons in tracking (GeV)")
->default_val(0.3)
->check(CLI::Range(0.000001, 1.e13))
->group("Config");
app.add_option("--max-deflection-angle",
"maximal deflection angle in tracking in radians")
->default_val(0.2)
->check(CLI::Range(1.e-8, 1.))
->group("Config");
bool track_neutrinos = false;
app.add_flag("--track-neutrinos", track_neutrinos, "switch on tracking of neutrinos")
->group("Config");
//////// Misc options ////////
app.add_option("--neutrino-interaction-type",
"charged (CC) or neutral current (NC) or both")
->default_val("both")
->check(CLI::IsMember({"neutral", "NC", "charged", "CC", "both"}))
->group("Misc.");
app.add_option("--observation-level",
"Height above earth radius of the observation level (in m)")
->default_val(0.)
->check(CLI::Range(-1.e3, 1.e5))
->group("Config");
app.add_option("--injection-height",
"Height above earth radius of the injection point (in m)")
->default_val(112.75e3)
->check(CLI::Range(-1.e3, 1.e6))
->group("Config");
app.add_option("-N,--nevent", nevent, "The number of events/showers to run.")
->default_val(1)
->check(CLI::PositiveNumber)
->group("Library/Output");
app.add_option("-f,--filename", "Filename for output library.")
->required()
->default_val("corsika_library")
->check(CLI::NonexistentPath)
->group("Library/Output");
bool compressOutput = false;
app.add_flag("--compress", compressOutput, "Compress the output directory to a tarball")
->group("Library/Output");
app.add_option("-s,--seed", "The random number seed.")
->default_val(0)
->check(CLI::NonNegativeNumber)
->group("Misc.");
bool force_interaction = false;
app.add_flag("--force-interaction", force_interaction,
"Force the location of the first interaction.")
->group("Misc.");
bool force_decay = false;
app.add_flag("--force-decay", force_decay, "Force the primary to immediately decay")
->group("Misc.");
bool disable_interaction_hists = false;
app.add_flag("--disable-interaction-histograms", disable_interaction_hists,
"Store interaction histograms")
->group("Misc.");
app.add_option("-v,--verbosity", "Verbosity level: warn, info, debug, trace.")
->default_val("info")
->check(CLI::IsMember({"warn", "info", "debug", "trace"}))
->group("Misc.");
app.add_option("-M,--hadronModel", "High-energy hadronic interaction model")
->default_val("SIBYLL-2.3d")
->check(CLI::IsMember({"SIBYLL-2.3d", "QGSJet-II.04", "EPOS-LHC", "Pythia8"}))
->group("Misc.");
app.add_option("-T,--hadronModelTransitionEnergy",
"Transition between high-/low-energy hadronic interaction "
"model in GeV")
->default_val(std::pow(10, 1.9)) // 79.4 GeV
->check(CLI::NonNegativeNumber)
->group("Misc.");
//////// Thinning options ////////
app.add_option("--emthin",
"fraction of primary energy at which thinning of EM particles starts")
->default_val(1.e-6)
->check(CLI::Range(0., 1.))
->group("Thinning");
app.add_option("--max-weight",
"maximum weight for thinning of EM particles (0 to select Kobal's "
"optimum times 0.5)")
->default_val(0)
->check(CLI::NonNegativeNumber)
->group("Thinning");
bool multithin = false;
app.add_flag("--multithin", multithin, "keep thinned particles (with weight=0)")
->group("Thinning");
app.add_option("--ring", "concentric ring of star shape pattern of observers")
->default_val(0)
->check(CLI::Range(0, 20))
->group("Radio");
// parse the command line options into the variables
CLI11_PARSE(app, argc, argv);
if (app.count("--verbosity")) {
auto const loglevel = app["--verbosity"]->as<std::string>();
if (loglevel == "warn") {
logging::set_level(logging::level::warn);
} else if (loglevel == "info") {
logging::set_level(logging::level::info);
} else if (loglevel == "debug") {
logging::set_level(logging::level::debug);
} else if (loglevel == "trace") {
#ifndef _C8_DEBUG_
CORSIKA_LOG_ERROR("trace log level requires a Debug build.");
return 1;
#endif
logging::set_level(logging::level::trace);
}
}
// check that we got either PDG or A/Z
// this can be done with option_groups but the ordering
// gets all messed up
if (app.count("--pdg") == 0) {
if ((app.count("-A") == 0) || (app.count("-Z") == 0)) {
CORSIKA_LOG_ERROR("If --pdg is not provided, then both -A and -Z are required.");
return 1;
}
}
// initialize random number sequence(s)
auto seed = registerRandomStreams(app["--seed"]->as<long>());
/* === START: SETUP ENVIRONMENT AND ROOT COORDINATE SYSTEM === */
EnvType env;
CoordinateSystemPtr const& rootCS = env.getCoordinateSystem();
Point const center{rootCS, 0_m, 0_m, 0_m};
Point const surface_{rootCS, 0_m, 0_m, constants::EarthRadius::Mean};
GeomagneticModel wmm(center, corsika_data("GeoMag/WMM.COF"));
// build an atmosphere with Keilhauer's parametrization of the
// US standard atmosphere into `env`
create_5layer_atmosphere<EnvironmentInterface, MyExtraEnv>(
env, AtmosphereId::USStdBK, center, 1.000327, surface_, Medium::AirDry1Atm,
MagneticFieldVector{rootCS, 50_uT, 0_T, 0_T});
/* === END: SETUP ENVIRONMENT AND ROOT COORDINATE SYSTEM === */
/* === START: CONSTRUCT PRIMARY PARTICLE === */
// parse the primary ID as a PDG or A/Z code
Code beamCode;
// check if we want to use a PDG code instead
if (app.count("--pdg") > 0) {
beamCode = convert_from_PDG(PDGCode(app["--pdg"]->as<int>()));
} else {
// check manually for proton and neutrons
if ((A == 1) && (Z == 1))
beamCode = Code::Proton;
else if ((A == 1) && (Z == 0))
beamCode = Code::Neutron;
else
beamCode = get_nucleus_code(A, Z);
}
HEPEnergyType eMin = 0_GeV;
HEPEnergyType eMax = 0_GeV;
// check the particle energy parameters
if (app["--energy"]->as<double>() > 0.0) {
eMin = app["--energy"]->as<double>() * 1_GeV;
eMax = app["--energy"]->as<double>() * 1_GeV;
} else if (cli_energy_range.size()) {
if (cli_energy_range[0] > cli_energy_range[1]) {
CORSIKA_LOG_WARN(
"Energy range lower bound is greater than upper bound. swapping...");
eMin = cli_energy_range[1] * 1_GeV;
eMax = cli_energy_range[0] * 1_GeV;
} else {
eMin = cli_energy_range[0] * 1_GeV;
eMax = cli_energy_range[1] * 1_GeV;
}
} else {
CORSIKA_LOG_CRITICAL(
"Must set either the (--energy) flag or the (--energy_range) flag to "
"positive value(s)");
return 0;
}
// direction of the shower in (theta, phi) space
auto const thetaRad = app["--zenith"]->as<double>() / 180. * M_PI;
auto const phiRad = app["--azimuth"]->as<double>() / 180. * M_PI;
auto const [nx, ny, nz] = std::make_tuple(sin(thetaRad) * cos(phiRad),
sin(thetaRad) * sin(phiRad), -cos(thetaRad));
auto propDir = DirectionVector(rootCS, {nx, ny, nz});
/* === END: CONSTRUCT PRIMARY PARTICLE === */
/* === START: CONSTRUCT GEOMETRY === */
auto const observationHeight =
app["--observation-level"]->as<double>() * 1_m + constants::EarthRadius::Mean;
auto const injectionHeight =
app["--injection-height"]->as<double>() * 1_m + constants::EarthRadius::Mean;
auto const t = -observationHeight * cos(thetaRad) +
sqrt(-static_pow<2>(sin(thetaRad) * observationHeight) +
static_pow<2>(injectionHeight));
Point const showerCore{rootCS, 0_m, 0_m, observationHeight};
Point const injectionPos =
showerCore + DirectionVector{rootCS,
{-sin(thetaRad) * cos(phiRad),
-sin(thetaRad) * sin(phiRad), cos(thetaRad)}} *
t;
// we make the axis much longer than the inj-core distance since the
// profile will go beyond the core, depending on zenith angle
ShowerAxis const showerAxis{injectionPos, (showerCore - injectionPos) * 1.2, env};
auto const dX = 10_g / square(1_cm); // Binning of the writers along the shower axis
/* === END: CONSTRUCT GEOMETRY === */
std::stringstream args;
for (int i = 0; i < argc; ++i) { args << argv[i] << " "; }
// create the output manager that we then register outputs with
OutputManager output(app["--filename"]->as<std::string>(), seed, args.str(),
compressOutput);
// register energy losses as output
EnergyLossWriter dEdX{showerAxis, dX};
output.add("energyloss", dEdX);
DynamicInteractionProcess<StackType> heModel;
auto const all_elements = corsika::get_all_elements_in_universe(env);
// have SIBYLL always for PROPOSAL photo-hadronic interactions
auto sibyll = std::make_shared<corsika::sibyll::Interaction>(
all_elements, corsika::setup::C7trackedParticles);
if (auto const modelStr = app["--hadronModel"]->as<std::string>();
modelStr == "SIBYLL-2.3d") {
heModel = DynamicInteractionProcess<StackType>{sibyll};
} else if (modelStr == "QGSJet-II.04") {
heModel = DynamicInteractionProcess<StackType>{
std::make_shared<corsika::qgsjetII::Interaction>()};
} else if (modelStr == "EPOS-LHC") {
heModel = DynamicInteractionProcess<StackType>{
std::make_shared<corsika::epos::Interaction>(corsika::setup::C7trackedParticles)};
} else if (modelStr == "Pythia8") {
heModel = DynamicInteractionProcess<StackType>{
std::make_shared<corsika::pythia8::Interaction>(
corsika::setup::C7trackedParticles)};
} else {
CORSIKA_LOG_CRITICAL("invalid choice \"{}\"; also check argument parser", modelStr);
return EXIT_FAILURE;
}
InteractionCounter heCounted{heModel};
corsika::pythia8::Decay decayPythia;
// tau decay via TAUOLA (hard coded to left handed)
corsika::tauola::Decay decayTauola(corsika::tauola::Helicity::LeftHanded);
struct IsTauSwitch {
bool operator()(const Particle& p) const {
return (p.getPID() == Code::TauMinus || p.getPID() == Code::TauPlus);
}
};
auto decaySequence = make_select(IsTauSwitch(), decayTauola, decayPythia);
// neutrino interactions with pythia (options are: NC, CC)
bool NC = false;
bool CC = false;
if (auto const nuIntStr = app["--neutrino-interaction-type"]->as<std::string>();
nuIntStr == "neutral" || nuIntStr == "NC") {
NC = true;
CC = false;
} else if (nuIntStr == "charged" || nuIntStr == "CC") {
NC = false;
CC = true;
} else if (nuIntStr == "both") {
NC = true;
CC = true;
}
corsika::pythia8::NeutrinoInteraction neutrinoPrimaryPythia(
corsika::setup::C7trackedParticles, NC, CC);
// hadronic photon interactions in resonance region
corsika::sophia::InteractionModel sophia;
HEPEnergyType const emcut = 1_GeV * app["--emcut"]->as<double>();
HEPEnergyType const hadcut = 1_GeV * app["--hadcut"]->as<double>();
HEPEnergyType const mucut = 1_GeV * app["--mucut"]->as<double>();
HEPEnergyType const taucut = 1_GeV * app["--taucut"]->as<double>();
ParticleCut<SubWriter<decltype(dEdX)>> cut(emcut, emcut, hadcut, mucut, taucut,
!track_neutrinos, dEdX);
// tell proposal that we are interested in all energy losses above the particle cut
auto const prod_threshold = std::min({emcut, hadcut, mucut, taucut});
set_energy_production_threshold(Code::Electron, prod_threshold);
set_energy_production_threshold(Code::Positron, prod_threshold);
set_energy_production_threshold(Code::Photon, prod_threshold);
set_energy_production_threshold(Code::MuMinus, prod_threshold);
set_energy_production_threshold(Code::MuPlus, prod_threshold);
set_energy_production_threshold(Code::TauMinus, prod_threshold);
set_energy_production_threshold(Code::TauPlus, prod_threshold);
// energy threshold for high energy hadronic model. Affects LE/HE switch for
// hadron interactions and the hadronic photon model in proposal
HEPEnergyType const heHadronModelThreshold =
1_GeV * app["--hadronModelTransitionEnergy"]->as<double>();
corsika::proposal::Interaction emCascade(
env, sophia, sibyll->getHadronInteractionModel(), heHadronModelThreshold);
// use BetheBlochPDG for hadronic continuous losses, and proposal otherwise
corsika::proposal::ContinuousProcess<SubWriter<decltype(dEdX)>> emContinuousProposal(
env, dEdX);
BetheBlochPDG<SubWriter<decltype(dEdX)>> emContinuousBethe{dEdX};
struct EMHadronSwitch {
EMHadronSwitch() = default;
bool operator()(const Particle& p) const { return is_hadron(p.getPID()); }
};
auto emContinuous =
make_select(EMHadronSwitch(), emContinuousBethe, emContinuousProposal);
LongitudinalWriter profile{showerAxis, dX};
output.add("profile", profile);
LongitudinalProfile<SubWriter<decltype(profile)>> longprof{profile};
// for ICRC2023
#ifdef WITH_FLUKA
corsika::fluka::Interaction leIntModel{all_elements};
#else
corsika::urqmd::UrQMD leIntModel{};
#endif
InteractionCounter leIntCounted{leIntModel};
// assemble all processes into an ordered process list
struct EnergySwitch {
HEPEnergyType cutE_;
EnergySwitch(HEPEnergyType cutE)
: cutE_(cutE) {}
bool operator()(const Particle& p) const { return (p.getKineticEnergy() < cutE_); }
};
auto hadronSequence =
make_select(EnergySwitch(heHadronModelThreshold), leIntCounted, heCounted);
// observation plane
Plane const obsPlane(showerCore, DirectionVector(rootCS, {0., 0., 1.}));
ObservationPlane<TrackingType, ParticleWriterParquet> observationLevel{
obsPlane, DirectionVector(rootCS, {1., 0., 0.}),
true, // plane should "absorb" particles
false}; // do not print z-coordinate
// register ground particle output
output.add("particles", observationLevel);
PrimaryWriter<TrackingType, ParticleWriterParquet> primaryWriter(observationLevel);
output.add("primary", primaryWriter);
int ring_number{app["--ring"]->as<int>()};
auto const radius_{ring_number * 25_m};
const int rr_ = static_cast<int>(radius_ / 1_m);
// Radio observers and relevant information
// the observer time variables
const TimeType duration_{4e-7_s};
const InverseTimeType sampleRate_{1e+9_Hz};
// the observer collection for CoREAS and ZHS
ObserverCollection<TimeDomainObserver> detectorCoREAS;
ObserverCollection<TimeDomainObserver> detectorZHS;
auto const showerCoreX_{showerCore.getCoordinates().getX()};
auto const showerCoreY_{showerCore.getCoordinates().getY()};
auto const injectionPosX_{injectionPos.getCoordinates().getX()};
auto const injectionPosY_{injectionPos.getCoordinates().getY()};
auto const injectionPosZ_{injectionPos.getCoordinates().getZ()};
auto const triggerpoint_{Point(rootCS, injectionPosX_, injectionPosY_, injectionPosZ_)};
if (ring_number != 0) {
// setup CoREAS observers - use the for loop for star shape pattern
for (auto phi_1 = 0; phi_1 <= 315; phi_1 += 45) {
auto phiRad_1 = phi_1 / 180. * M_PI;
auto const point_1{Point(rootCS, showerCoreX_ + radius_ * cos(phiRad_1),
showerCoreY_ + radius_ * sin(phiRad_1),
constants::EarthRadius::Mean)};
std::cout << "Observer point CoREAS: " << point_1 << std::endl;
auto triggertime_1{(triggerpoint_ - point_1).getNorm() / constants::c};
std::string name_1 = "CoREAS_R=" + std::to_string(rr_) +
"_m--Phi=" + std::to_string(phi_1) + "degrees";
TimeDomainObserver observer_1(name_1, point_1, rootCS, triggertime_1, duration_,
sampleRate_, triggertime_1);
detectorCoREAS.addObserver(observer_1);
}
// setup ZHS observers - use the for loop for star shape pattern
for (auto phi_ = 0; phi_ <= 315; phi_ += 45) {
auto phiRad_ = phi_ / 180. * M_PI;
auto const point_{Point(rootCS, showerCoreX_ + radius_ * cos(phiRad_),
showerCoreY_ + radius_ * sin(phiRad_),
constants::EarthRadius::Mean)};
std::cout << "Observer point ZHS: " << point_ << std::endl;
auto triggertime_{(triggerpoint_ - point_).getNorm() / constants::c};
std::string name_ =
"ZHS_R=" + std::to_string(rr_) + "_m--Phi=" + std::to_string(phi_) + "degrees";
TimeDomainObserver observer_2(name_, point_, rootCS, triggertime_, duration_,
sampleRate_, triggertime_);
detectorZHS.addObserver(observer_2);
}
}
LengthType const step = 1_m;
auto TP =
make_tabulated_flat_atmosphere_radio_propagator(env, injectionPos, surface_, step);
// initiate CoREAS
RadioProcess<decltype(detectorCoREAS), CoREAS<decltype(detectorCoREAS), decltype(TP)>,
decltype(TP)>
coreas(detectorCoREAS, TP);
// register CoREAS with the output manager
output.add("CoREAS", coreas);
// initiate ZHS
RadioProcess<decltype(detectorZHS), ZHS<decltype(detectorZHS), decltype(TP)>,
decltype(TP)>
zhs(detectorZHS, TP);
// register ZHS with the output manager
output.add("ZHS", zhs);
// make and register the first interaction writer
InteractionWriter<setup::Tracking, ParticleWriterParquet> inter_writer(
showerAxis, observationLevel);
output.add("interactions", inter_writer);
/* === END: SETUP PROCESS LIST === */
// trigger the output manager to open the library for writing
output.startOfLibrary();
// loop over each shower
for (int i_shower = 1; i_shower < nevent + 1; i_shower++) {
CORSIKA_LOG_INFO("Shower {} / {} ", i_shower, nevent);
// randomize the primary energy
double const eSlope = app["--eslope"]->as<double>();
PowerLawDistribution<HEPEnergyType> powerLawRng(eSlope, eMin, eMax);
HEPEnergyType const primaryTotalEnergy =
(eMax == eMin) ? eMin
: powerLawRng(RNGManager<>::getInstance().getRandomStream(
"primary_particle"));
auto const eKin = primaryTotalEnergy - get_mass(beamCode);
// set up thinning based on primary parameters
double const emthinfrac = app["--emthin"]->as<double>();
double const maxWeight = std::invoke([&]() {
if (auto const wm = app["--max-weight"]->as<double>(); wm > 0)
return wm;
else
return 0.5 * emthinfrac * primaryTotalEnergy / 1_GeV;
});
EMThinning thinning{emthinfrac * primaryTotalEnergy, maxWeight, !multithin};
// set up the stack inspector
StackInspector<StackType> stackInspect(10000, false, primaryTotalEnergy);
// assemble the final process sequence
auto sequence =
make_sequence(stackInspect, neutrinoPrimaryPythia, hadronSequence, decaySequence,
emCascade, emContinuous, coreas, zhs, longprof, observationLevel,
inter_writer, thinning, cut);
// create the cascade object using the default stack and tracking
// implementation
TrackingType tracking(app["--max-deflection-angle"]->as<double>());
StackType stack;
Cascade EAS(env, tracking, sequence, output, stack);
// setup particle stack, and add primary particle
stack.clear();
// print our primary parameters all in one place
CORSIKA_LOG_INFO("Primary name: {}", beamCode);
if (app["--pdg"]->count() > 0) {
CORSIKA_LOG_INFO("Primary PDG ID: {}", app["--pdg"]->as<int>());
} else {
CORSIKA_LOG_INFO("Primary Z/A: {}/{}", Z, A);
}
CORSIKA_LOG_INFO("Primary Total Energy: {}", primaryTotalEnergy);
CORSIKA_LOG_INFO("Primary Momentum: {}",
calculate_momentum(primaryTotalEnergy, get_mass(beamCode)));
CORSIKA_LOG_INFO("Primary Direction: {}", propDir.getNorm());
CORSIKA_LOG_INFO("Point of Injection: {}", injectionPos.getCoordinates());
CORSIKA_LOG_INFO("Shower Axis Length: {}",
(showerCore - injectionPos).getNorm() * 1.2);
// add the desired particle to the stack
auto const primaryProperties =
std::make_tuple(beamCode, eKin, propDir.normalized(), injectionPos, 0_ns);
stack.addParticle(primaryProperties);
// if we want to fix the first location of the shower
if (force_interaction) {
CORSIKA_LOG_INFO("Fixing first interaction at injection point.");
EAS.forceInteraction();
}
if (force_decay) {
CORSIKA_LOG_INFO("Forcing the primary to decay");
EAS.forceDecay();
}
primaryWriter.recordPrimary(primaryProperties);
// run the shower
EAS.run();
HEPEnergyType const Efinal =
dEdX.getEnergyLost() + observationLevel.getEnergyGround();
CORSIKA_LOG_INFO(
"total energy budget (GeV): {} (dEdX={} ground={}), "
"relative difference (%): {}",
Efinal / 1_GeV, dEdX.getEnergyLost() / 1_GeV,
observationLevel.getEnergyGround() / 1_GeV,
(Efinal / primaryTotalEnergy - 1) * 100);
if (!disable_interaction_hists) {
CORSIKA_LOG_INFO("Saving interaction histograms");
auto const hists = heCounted.getHistogram() + leIntCounted.getHistogram();
// directory for output of interaction histograms
string const outdir(app["--filename"]->as<std::string>() + "/interaction_hist");
boost::filesystem::create_directories(outdir);
string const labHist_file = outdir + "/inthist_lab_" + to_string(i_shower) + ".npz";
string const cMSHist_file = outdir + "/inthist_cms_" + to_string(i_shower) + ".npz";
save_hist(hists.labHist(), labHist_file, true);
save_hist(hists.CMSHist(), cMSHist_file, true);
}
}
// and finalize the output on disk
output.endOfLibrary();
return EXIT_SUCCESS;
}
# Copyright (c) 2012 - 2017, Lars Bilke
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors
# may be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# CHANGES:
#
# 2012-01-31, Lars Bilke
# - Enable Code Coverage
#
# 2013-09-17, Joakim Söderberg
# - Added support for Clang.
# - Some additional usage instructions.
#
# 2016-02-03, Lars Bilke
# - Refactored functions to use named parameters
#
# 2017-06-02, Lars Bilke
# - Merged with modified version from github.com/ufz/ogs
#
#
# USAGE:
#
# 1. Copy this file into your cmake modules path.
#
# 2. Add the following line to your CMakeLists.txt:
# include(CodeCoverage)
#
# 3. Append necessary compiler flags:
# APPEND_COVERAGE_COMPILER_FLAGS()
#
# 4. If you need to exclude additional directories from the report, specify them
# using the COVERAGE_LCOV_EXCLUDES variable before calling SETUP_TARGET_FOR_COVERAGE_LCOV.
# Example:
# set(COVERAGE_LCOV_EXCLUDES 'dir1/*' 'dir2/*')
#
# 5. Use the functions described below to create a custom make target which
# runs your test executable and produces a code coverage report.
#
# 6. Build a Debug build:
# cmake -DCMAKE_BUILD_TYPE=Debug ..
# make
# make my_coverage_target
#
include(CMakeParseArguments)
# Check prereqs
find_program( GCOV_PATH gcov )
find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
find_program( SIMPLE_PYTHON_EXECUTABLE python )
if(NOT GCOV_PATH)
message(FATAL_ERROR "gcov not found! Aborting...")
endif() # NOT GCOV_PATH
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3)
message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
endif()
elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
endif()
set(COVERAGE_COMPILER_FLAGS "-g -O0 --coverage -fprofile-arcs -ftest-coverage"
CACHE INTERNAL "")
set(CMAKE_CXX_FLAGS_COVERAGE
${COVERAGE_COMPILER_FLAGS}
CACHE STRING "Flags used by the C++ compiler during coverage builds."
FORCE )
set(CMAKE_C_FLAGS_COVERAGE
${COVERAGE_COMPILER_FLAGS}
CACHE STRING "Flags used by the C compiler during coverage builds."
FORCE )
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
""
CACHE STRING "Flags used for linking binaries during coverage builds."
FORCE )
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
""
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
FORCE )
mark_as_advanced(
CMAKE_CXX_FLAGS_COVERAGE
CMAKE_C_FLAGS_COVERAGE
CMAKE_EXE_LINKER_FLAGS_COVERAGE
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
link_libraries(gcov)
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
endif()
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# SETUP_TARGET_FOR_COVERAGE_LCOV(
# NAME testrunner_coverage # New target name
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES testrunner # Dependencies to build first
# )
function(SETUP_TARGET_FOR_COVERAGE_LCOV)
set(options NONE)
set(oneValueArgs NAME)
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT LCOV_PATH)
message(FATAL_ERROR "lcov not found! Aborting...")
endif() # NOT LCOV_PATH
if(NOT GENHTML_PATH)
message(FATAL_ERROR "genhtml not found! Aborting...")
endif() # NOT GENHTML_PATH
# Setup target
add_custom_target(${Coverage_NAME}
# Cleanup lcov
COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} -directory . --zerocounters
# Create baseline to make sure untouched files show up in the report
COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} -c -i -d . -o ${Coverage_NAME}.base
# Run tests
COMMAND ${Coverage_EXECUTABLE}
# Capturing lcov counters and generating report
COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} --directory . --capture --output-file ${Coverage_NAME}.info
# add baseline counters
COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base -a ${Coverage_NAME}.info --output-file ${Coverage_NAME}.total
COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} --remove ${Coverage_NAME}.total ${COVERAGE_LCOV_EXCLUDES} --output-file ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
COMMAND ${GENHTML_PATH} -o ${Coverage_NAME} ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
COMMAND ${CMAKE_COMMAND} -E remove ${Coverage_NAME}.base ${Coverage_NAME}.total ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
)
# Show where to find the lcov info report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info."
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
)
endfunction() # SETUP_TARGET_FOR_COVERAGE_LCOV
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# SETUP_TARGET_FOR_COVERAGE_GCOVR_XML(
# NAME ctest_coverage # New target name
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES executable_target # Dependencies to build first
# )
function(SETUP_TARGET_FOR_COVERAGE_GCOVR_XML)
set(options NONE)
set(oneValueArgs NAME)
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT SIMPLE_PYTHON_EXECUTABLE)
message(FATAL_ERROR "python not found! Aborting...")
endif() # NOT SIMPLE_PYTHON_EXECUTABLE
if(NOT GCOVR_PATH)
message(FATAL_ERROR "gcovr not found! Aborting...")
endif() # NOT GCOVR_PATH
# Combine excludes to several -e arguments
set(GCOVR_EXCLUDES "")
foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDES})
list(APPEND GCOVR_EXCLUDES "-e")
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
endforeach()
add_custom_target(${Coverage_NAME}
# Run tests
${Coverage_EXECUTABLE}
# Running gcovr
COMMAND ${GCOVR_PATH} --xml
-r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES}
--object-directory=${PROJECT_BINARY_DIR}
-o ${Coverage_NAME}.xml
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
COMMENT "Running gcovr to produce Cobertura code coverage report."
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
)
endfunction() # SETUP_TARGET_FOR_COVERAGE_GCOVR_XML
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML(
# NAME ctest_coverage # New target name
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES executable_target # Dependencies to build first
# )
function(SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML)
set(options NONE)
set(oneValueArgs NAME)
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT SIMPLE_PYTHON_EXECUTABLE)
message(FATAL_ERROR "python not found! Aborting...")
endif() # NOT SIMPLE_PYTHON_EXECUTABLE
if(NOT GCOVR_PATH)
message(FATAL_ERROR "gcovr not found! Aborting...")
endif() # NOT GCOVR_PATH
# Combine excludes to several -e arguments
set(GCOVR_EXCLUDES "")
foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDES})
list(APPEND GCOVR_EXCLUDES "-e")
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
endforeach()
add_custom_target(${Coverage_NAME}
# Run tests
${Coverage_EXECUTABLE}
# Create folder
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
# Running gcovr
COMMAND ${GCOVR_PATH} --html --html-details
-r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES}
--object-directory=${PROJECT_BINARY_DIR}
-o ${Coverage_NAME}/index.html
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
COMMENT "Running gcovr to produce HTML code coverage report."
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
)
endfunction() # SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML
function(APPEND_COVERAGE_COMPILER_FLAGS)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
endfunction() # APPEND_COVERAGE_COMPILER_FLAGS
# Copyright (c) 2012 - 2017, Lars Bilke
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors
# may be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# CHANGES:
#
# 2012-01-31, Lars Bilke
# - Enable Code Coverage
#
# 2013-09-17, Joakim Söderberg
# - Added support for Clang.
# - Some additional usage instructions.
#
# 2016-02-03, Lars Bilke
# - Refactored functions to use named parameters
#
# 2017-06-02, Lars Bilke
# - Merged with modified version from github.com/ufz/ogs
#
#
# USAGE:
#
# 1. Copy this file into your cmake modules path.
#
# 2. Add the following line to your CMakeLists.txt:
# include(CodeCoverage)
#
# 3. Append necessary compiler flags:
# APPEND_COVERAGE_COMPILER_FLAGS()
#
# 4. If you need to exclude additional directories from the report, specify them
# using the COVERAGE_LCOV_EXCLUDES variable before calling SETUP_TARGET_FOR_COVERAGE_LCOV.
# Example:
# set(COVERAGE_LCOV_EXCLUDES 'dir1/*' 'dir2/*')
#
# 5. Use the functions described below to create a custom make target which
# runs your test executable and produces a code coverage report.
#
# 6. Build a Debug build:
# cmake -DCMAKE_BUILD_TYPE=Debug ..
# make
# make my_coverage_target
#
include(CMakeParseArguments)
# Check prereqs
find_program( GCOV_PATH gcov )
find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
find_program( SIMPLE_PYTHON_EXECUTABLE python )
if(NOT GCOV_PATH)
message(FATAL_ERROR "gcov not found! Aborting...")
endif() # NOT GCOV_PATH
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3)
message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
endif()
elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
endif()
set(COVERAGE_COMPILER_FLAGS "-g -O0 --coverage -fprofile-arcs -ftest-coverage"
CACHE INTERNAL "")
set(CMAKE_CXX_FLAGS_COVERAGE
${COVERAGE_COMPILER_FLAGS}
CACHE STRING "Flags used by the C++ compiler during coverage builds."
FORCE )
set(CMAKE_C_FLAGS_COVERAGE
${COVERAGE_COMPILER_FLAGS}
CACHE STRING "Flags used by the C compiler during coverage builds."
FORCE )
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
""
CACHE STRING "Flags used for linking binaries during coverage builds."
FORCE )
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
""
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
FORCE )
mark_as_advanced(
CMAKE_CXX_FLAGS_COVERAGE
CMAKE_C_FLAGS_COVERAGE
CMAKE_EXE_LINKER_FLAGS_COVERAGE
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
link_libraries(gcov)
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
endif()
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# SETUP_TARGET_FOR_COVERAGE_LCOV(
# NAME testrunner_coverage # New target name
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES testrunner # Dependencies to build first
# )
function(SETUP_TARGET_FOR_COVERAGE_LCOV)
set(options NONE)
set(oneValueArgs NAME)
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT LCOV_PATH)
message(FATAL_ERROR "lcov not found! Aborting...")
endif() # NOT LCOV_PATH
if(NOT GENHTML_PATH)
message(FATAL_ERROR "genhtml not found! Aborting...")
endif() # NOT GENHTML_PATH
# Setup target
add_custom_target(${Coverage_NAME}
# Cleanup lcov
COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} -directory . --zerocounters
# Create baseline to make sure untouched files show up in the report
COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} -c -i -d . -o ${Coverage_NAME}.base
# Run tests
COMMAND ${Coverage_EXECUTABLE}
# Capturing lcov counters and generating report
COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} --directory . --capture --output-file ${Coverage_NAME}.info
# add baseline counters
COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base -a ${Coverage_NAME}.info --output-file ${Coverage_NAME}.total
COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} --remove ${Coverage_NAME}.total ${COVERAGE_LCOV_EXCLUDES} --output-file ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
COMMAND ${GENHTML_PATH} -o ${Coverage_NAME} ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
COMMAND ${CMAKE_COMMAND} -E remove ${Coverage_NAME}.base ${Coverage_NAME}.total ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
)
# Show where to find the lcov info report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info."
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
)
endfunction() # SETUP_TARGET_FOR_COVERAGE_LCOV
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# SETUP_TARGET_FOR_COVERAGE_GCOVR_XML(
# NAME ctest_coverage # New target name
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES executable_target # Dependencies to build first
# )
function(SETUP_TARGET_FOR_COVERAGE_GCOVR_XML)
set(options NONE)
set(oneValueArgs NAME)
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT SIMPLE_PYTHON_EXECUTABLE)
message(FATAL_ERROR "python not found! Aborting...")
endif() # NOT SIMPLE_PYTHON_EXECUTABLE
if(NOT GCOVR_PATH)
message(FATAL_ERROR "gcovr not found! Aborting...")
endif() # NOT GCOVR_PATH
# Combine excludes to several -e arguments
set(GCOVR_EXCLUDES "")
foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDES})
list(APPEND GCOVR_EXCLUDES "-e")
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
endforeach()
add_custom_target(${Coverage_NAME}
# Run tests
${Coverage_EXECUTABLE}
# Running gcovr
COMMAND ${GCOVR_PATH} --xml
-r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES}
--object-directory=${PROJECT_BINARY_DIR}
-o ${Coverage_NAME}.xml
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
COMMENT "Running gcovr to produce Cobertura code coverage report."
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
)
endfunction() # SETUP_TARGET_FOR_COVERAGE_GCOVR_XML
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML(
# NAME ctest_coverage # New target name
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES executable_target # Dependencies to build first
# )
function(SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML)
set(options NONE)
set(oneValueArgs NAME)
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT SIMPLE_PYTHON_EXECUTABLE)
message(FATAL_ERROR "python not found! Aborting...")
endif() # NOT SIMPLE_PYTHON_EXECUTABLE
if(NOT GCOVR_PATH)
message(FATAL_ERROR "gcovr not found! Aborting...")
endif() # NOT GCOVR_PATH
# Combine excludes to several -e arguments
set(GCOVR_EXCLUDES "")
foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDES})
list(APPEND GCOVR_EXCLUDES "-e")
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
endforeach()
add_custom_target(${Coverage_NAME}
# Run tests
${Coverage_EXECUTABLE}
# Create folder
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
# Running gcovr
COMMAND ${GCOVR_PATH} --html --html-details
-r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES}
--object-directory=${PROJECT_BINARY_DIR}
-o ${Coverage_NAME}/index.html
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
COMMENT "Running gcovr to produce HTML code coverage report."
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ;
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
)
endfunction() # SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML
function(APPEND_COVERAGE_COMPILER_FLAGS)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
endfunction() # APPEND_COVERAGE_COMPILER_FLAGS
#
# (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
#
# See file AUTHORS for a list of contributors.
#
# This software is distributed under the terms of the 3-clause BSD license.
# See file LICENSE for a full version of the license.
#
# - find Conex
#
# This module defines
# CONEX_PREFIX
# CONEX_INCLUDE_DIR
# CONEX_LIBRARY
set (SEARCH_conex_
${WITH_CONEX}
${CONEXROOT}
${CONEX_ROOT}
$ENV{CONEXROOT}
$ENV{CONEX_ROOT}
)
find_path (CONEX_PREFIX
NAMES lib/${CMAKE_SYSTEM_NAME}
PATHS ${SEARCH_conex_}
DOC "The CONEX root directory"
NO_DEFAULT_PATH
)
find_path (CONEX_INCLUDE_DIR
NAMES ConexDynamicInterface.h
PATHS ${CONEX_PREFIX}
PATH_SUFFIXES src
DOC "The CONEX include directory"
)
find_library (CONEX_LIBRARY
NAMES libCONEXdynamic.a
PATHS ${CONEX_PREFIX}
PATH_SUFFIXES lib/${CMAKE_SYSTEM_NAME}
DOC "The CONEX library"
)
# standard cmake infrastructure:
include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (CONEX
"Did not find system-level CONEX."
CONEX_INCLUDE_DIR CONEX_LIBRARY CONEX_PREFIX)
mark_as_advanced (CONEX_INCLUDE_DIR CONEX_LIBRARY CONEX_PREFIX)
#
# (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
#
# See file AUTHORS for a list of contributors.
#
# This software is distributed under the terms of the 3-clause BSD license.
# See file LICENSE for a full version of the license.
#
add_library (PhysUnits INTERFACE)
target_compile_options (PhysUnits
INTERFACE
-I${CMAKE_SOURCE_DIR}/externals/phys_units
)
set (PhysUnits_FOUND True)
#
# (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
#
# See file AUTHORS for a list of contributors.
#
# This software is distributed under the terms of the 3-clause BSD license.
# See file LICENSE for a full version of the license.
#
#################################################
#
# run pythia8-config and interpret result
#
function (_Pythia8_CONFIG_ option variable type doc)
execute_process (COMMAND ${Pythia8_CONFIG} ${option}
OUTPUT_VARIABLE _local_out_
RESULT_VARIABLE _local_res_)
string (REGEX REPLACE "\n$" "" _local_out_ "${_local_out_}")
if (NOT ${_local_res_} EQUAL 0)
message ("Error in running ${Pythia8_CONFIG} ${option}")
else ()
set (${variable} "${_local_out_}" CACHE ${type} ${doc})
endif ()
endfunction (_Pythia8_CONFIG_)
#################################################
#
# take directory and assume standard install layout
#
function (_Pythia8_LAYOUT_ dir variable type doc)
set (${variable} "${dir}" CACHE ${type} ${doc})
endfunction (_Pythia8_LAYOUT_)
#################################################
#
# Searched Pythia8 on system. Expect pythia8-config in PATH, or typical installation location
#
# This module defines
# HAVE_Pythia8
# Pythia8_INCLUDE_DIR where to locate Pythia.h file
# Pythia8_LIBRARY where to find the libpythia8 library
# Pythia8_LIBRARIES (not cached) the libraries to link against to use Pythia8
# Pythia8_VERSION version of Pythia8 if found
#
set (_SEARCH_Pythia8_
${PROJECT_BINARY_DIR}/ThirdParty/pythia8-install
${PYTHIA8}
$ENV{PYTHIA8}
${PYTHIA8DIR}
$ENV{PYTHIA8DIR}
${PYTHIA8_ROOT}
$ENV{PYTHIA8_ROOT}
${PYTHIA8_DIR}
$ENV{PYTHIA8_DIR}
${Pythia8_DIR}
$ENV{Pythia8_DIR}
/opt/pythia8
)
find_file (Pythia8_Pythia_h_LOC
NAME Pythia.h
PATHS ${_SEARCH_Pythia8_}
PATH_SUFFIXES include/Pythia8
DOC "The location of the Pythia8/Pythia.h script"
REQUIRED)
if ("${Pythia8_Pythia_h_LOC}" STREQUAL "Pythia8_Pythia_h_LOC-NOTFOUND")
message (FATAL_ERROR "Did not find SYSTEM-level Pythia8 in: \"${_SEARCH_Pythia8_}\"")
endif ()
string (REPLACE "/include/Pythia8/Pythia.h" "" Pythia8_DIR ${Pythia8_Pythia_h_LOC})
set (Pythia8_CONFIG ${Pythia8_DIR}/bin/pythia-config)
if (Pythia8_CONFIG)
set (HAVE_Pythia8 1 CACHE BOOL "presence of pythia8, found via pythia8-config")
# pythia-config is not relocatable
#_Pythia8_CONFIG_ ("--prefix" Pythia8_PREFIX PATH "location of pythia8 installation")
#_Pythia8_CONFIG_ ("--includedir" Pythia8_INCLUDE_DIR PATH "pythia8 include directory")
#_Pythia8_CONFIG_ ("--libdir" Pythia8_LIBRARY STRING "the pythia8 libs")
#_Pythia8_CONFIG_ ("--datadir" Pythia8_DATA_DIR PATH "the pythia8 data dir")
_Pythia8_LAYOUT_ ("${Pythia8_DIR}" Pythia8_PREFIX PATH "location of pythia8 installation")
_Pythia8_LAYOUT_ ("${Pythia8_DIR}/include" Pythia8_INCLUDE_DIR PATH "pythia8 include directory")
_Pythia8_LAYOUT_ ("${Pythia8_DIR}/lib" Pythia8_LIBRARY STRING "the pythia8 libs")
_Pythia8_LAYOUT_ ("${Pythia8_DIR}/share/Pythia8/xmldoc" Pythia8_DATA_DIR PATH "the pythia8 data dir")
# read the config string
file (READ "${Pythia8_INCLUDE_DIR}/Pythia8/Pythia.h" Pythia8_TMP_PYTHIA_H)
string (REGEX MATCH "#define PYTHIA_VERSION_INTEGER ([0-9]*)" _ ${Pythia8_TMP_PYTHIA_H})
set (Pythia8_VERSION ${CMAKE_MATCH_1})
message (STATUS "Found Pythia8 version: ${Pythia8_VERSION}")
endif ()
# standard cmake infrastructure:
include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (Pythia8 REQUIRED_VARS Pythia8_PREFIX Pythia8_INCLUDE_DIR Pythia8_LIBRARY VERSION_VAR Pythia8_VERSION)
mark_as_advanced (Pythia8_DATA_DIR Pythia8_INCLUDE_DIR Pythia8_LIBRARY)
#
# (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
#
# See file AUTHORS for a list of contributors.
#
# This software is distributed under the terms of the 3-clause BSD license.
# See file LICENSE for a full version of the license.
#
# Look for an executable called sphinx-build
find_program (SPHINX_EXECUTABLE
NAMES sphinx-build
DOC "Path to sphinx-build executable")
include (FindPackageHandleStandardArgs)
#Handle standard arguments to find_package like REQUIRED and QUIET
find_package_handle_standard_args (Sphinx
"Failed to find sphinx-build executable"
SPHINX_EXECUTABLE)
#
# (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
#
# See file AUTHORS for a list of contributors.
#
# This software is distributed under the terms of the 3-clause BSD license.
# See file LICENSE for a full version of the license.
#
set (CORSIKA8_VERSION @c8_version@)
@PACKAGE_INIT@
#+++++++++++++++++++++++++++++
# Setup hardware and infrastructure dependent defines and other setting
#
include (${CMAKE_CURRENT_LIST_DIR}/corsikaDefines.cmake)
#+++++++++++++++++++++++++++
# Options
#
option (WITH_HISTORY "Flag to switch on/off HISTORY" ON)
#++++++++++++++++++++++++++++
# General config and flags
#
set (CMAKE_CXX_STANDARD @CMAKE_CXX_STANDARD@)
set (CMAKE_CXX_EXTENSIONS @CMAKE_CXX_EXTENSIONS@)
set (COMPILE_OPTIONS @COMPILE_OPTIONS@)
set (CMAKE_VERBOSE_MAKEFILE @CMAKE_VERBOSE_MAKEFILE@)
#+++++++++++++++++++++++++++++
# external dependencies
# same list as top-level CML.txt, except for Catch2 (not needed here)
#
find_package(Boost COMPONENTS filesystem REQUIRED)
find_package(CLI11 REQUIRED)
find_package(Eigen3 REQUIRED)
find_package(spdlog REQUIRED)
find_package(yaml-cpp REQUIRED)
find_package(Arrow REQUIRED)
find_package(PROPOSAL REQUIRED)
#+++++++++++++++++++++++++++++
# Import Pythia8
# since we always import pythia (ExternalProject_Add) we have to
# import here, too.
#
add_library (C8::ext::pythia8 STATIC IMPORTED GLOBAL)
set_target_properties (
C8::ext::pythia8 PROPERTIES
IMPORTED_LOCATION @Pythia8_LIBDIR@/libpythia8.a
IMPORTED_LINK_INTERFACE_LIBRARIES dl
INTERFACE_INCLUDE_DIRECTORIES @Pythia8_INCDIR@
)
set (Pythia8_FOUND @Pythia8_FOUND@)
message (STATUS "Pythia8 at: @Pythia8_PREFIX@")
#+++++++++++++++++++++++++++++
# Import TAUOLA
# since we always import TAUOLA (ExternalProject_Add) we have to
# import here, too.
#
add_library (C8::ext::tauola::CxxInterface STATIC IMPORTED GLOBAL)
add_library (C8::ext::tauola::Fortran STATIC IMPORTED GLOBAL)
add_library(C8::ext::tauola INTERFACE IMPORTED)
set_property(TARGET C8::ext::tauola
PROPERTY
INTERFACE_LINK_LIBRARIES
C8::ext::tauola::CxxInterface
C8::ext::tauola::Fortran)
set_target_properties (
C8::ext::tauola::CxxInterface PROPERTIES
IMPORTED_LOCATION @TAUOLA_LIBDIR@/libTauolaCxxInterface.a
IMPORTED_LINK_INTERFACE_LIBRARIES dl
INTERFACE_INCLUDE_DIRECTORIES @TAUOLA_INCDIR@
)
set_target_properties (
C8::ext::tauola::Fortran PROPERTIES
IMPORTED_LOCATION @TAUOLA_LIBDIR@/libTauolaFortran.a
IMPORTED_LINK_INTERFACE_LIBRARIES dl
INTERFACE_INCLUDE_DIRECTORIES @TAUOLA_INCDIR@
)
set (TAUOLA_FOUND @TAUOLA_FOUND@)
message (STATUS "TAUOLA at: @TAUOLA_PREFIX@")
#++++++++++++++++++++++++++++++
# import CORSIKA8
#
include ("${CMAKE_CURRENT_LIST_DIR}/corsikaTargets.cmake")
check_required_components (corsika)
#+++++++++++++++++++++++++++++++
# add further definitions / options
#
if (WITH_HISTORY)
set_property (
TARGET CORSIKA8::CORSIKA8
APPEND PROPERTY
INTERFACE_COMPILE_DEFINITIONS "WITH_HISTORY"
)
endif (WITH_HISTORY)
#+++++++++++++++++++++++++++++++
#
# final summary output
#
include (FeatureSummary)
add_feature_info (HISTORY WITH_HISTORY "Full information on cascade history for particles.")
feature_summary (WHAT ALL)
#
# (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
#
# See file AUTHORS for a list of contributors.
#
# This software is distributed under the terms of the 3-clause BSD license.
# See file LICENSE for a full version of the license.
#
#+++++++++++++++++++++++++++++
# as long as there still are modules using it:
#
enable_language (Fortran)
set (CMAKE_Fortran_FLAGS "-std=legacy -Wfunction-elimination")
#+++++++++++++++++++++++++++++
# Build types settings
#
# setup coverage build type
set (CMAKE_CXX_FLAGS_COVERAGE "-g --coverage")
set (CMAKE_EXE_LINKER_FLAGS_COVERAGE "--coverage")
set (CMAKE_SHARED_LINKER_FLAGS_COVERAGE "--coverage")
# set a flag to inform code that we are in debug mode
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_C8_DEBUG_")
#+++++++++++++++++++++++++++++
# Build type selection
#
# Set the possible values of build type for cmake-gui and command line check
set (ALLOWED_BUILD_TYPES Debug Release MinSizeRel RelWithDebInfo Coverage)
set_property (CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${ALLOWED_BUILD_TYPES})
set (DEFAULT_BUILD_TYPE "Release")
if (EXISTS "${CMAKE_SOURCE_DIR}/.git")
set (DEFAULT_BUILD_TYPE "Debug")
endif ()
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message (STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as no other was specified.")
set (CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE
STRING "Choose the type of build." FORCE)
else (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
# Ignore capitalization when build type is selected manually and check for valid setting
string (TOLOWER ${CMAKE_BUILD_TYPE} SELECTED_LOWER)
string (TOLOWER "${ALLOWED_BUILD_TYPES}" BUILD_TYPES_LOWER)
if (NOT SELECTED_LOWER IN_LIST BUILD_TYPES_LOWER)
message (FATAL_ERROR "Unknown build type: ${CMAKE_BUILD_TYPE} [allowed: ${ALLOWED_BUILD_TYPES}]")
endif ()
message (STATUS "Build type is: ${CMAKE_BUILD_TYPE}")
endif (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
#
# Floating point exception support - select implementation to use
#
include (CheckIncludeFileCXX)
CHECK_INCLUDE_FILE_CXX ("fenv.h" HAS_FEENABLEEXCEPT)
if (HAS_FEENABLEEXCEPT) # FLOATING_POINT_ENVIRONMENT
set (CORSIKA_HAS_FEENABLEEXCEPT 1)
set_property (DIRECTORY ${CMAKE_HOME_DIRECTORY} APPEND PROPERTY COMPILE_DEFINITIONS "CORSIKA_HAS_FEENABLEEXCEPT")
endif ()
#
# General OS Detection
#
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set (CORSIKA_OS_WINDOWS TRUE)
set (CORSIKA_OS "Windows")
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set (CORSIKA_OS_LINUX TRUE)
set (CORSIKA_OS "Linux")
# check for RedHat/CentOS compiler from the software collections (scl)
string (FIND ${CMAKE_CXX_COMPILER} "/opt/rh/devtoolset-" index)
if (${index} EQUAL 0)
set (CORSIKA_SCL_CXX TRUE)
endif ()
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set (CORSIKA_OS_MAC TRUE)
set (CORSIKA_OS "Mac")
endif ()
#
# (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
#
# See file AUTHORS for a list of contributors.
#
# This software is distributed under the terms of the 3-clause BSD license.
# See file LICENSE for a full version of the license.
#
#################################################
#
# central macro to register unit tests in cmake
#
# 1) Simple use:
# Pass the name of the test.cc file as the first
# argument, without the ".cc" extention.
#
# Example: CORSIKA_ADD_TEST (testSomething)
#
# This generates target testSomething from file testSomething.cc.
#
# 2) Customize sources:
# If 1) doesn't work, use the SOURCES keyword to explicitly
# specify the sources.
#
# Example: CORSIKA_ADD_TEST (testSomething
# SOURCES source1.cc source2.cc someheader.h)
#
# 3) Customize sanitizers:
# You can override which sanitizers are compiled into the
# test, but only do this if the defaults do not work.
#
# Example: CORSIKA_ADD_TEST (testSomething SANITIZE undefined)
#
# Only uses the sanitizer for undefined behavior.
#
# In all cases, you can further customize the target with
# target_link_libraries(testSomething ...) and so on.
#
# TEMPORARY: All sanitizers are currently globally disabled by default, to enable them,
# set CORSIKA_SANITIZERS_ENABLED to TRUE.
function (CORSIKA_ADD_TEST)
cmake_parse_arguments (PARSE_ARGV 1 C8_ADD_TEST "" "SANITIZE" "SOURCES")
set (name ${ARGV0})
if (NOT C8_ADD_TEST_SOURCES)
set (sources ${name}.cc)
else ()
set (sources ${C8_ADD_TEST_SOURCES})
endif ()
if (NOT C8_ADD_TEST_SANITIZE)
set(sanitize "address,undefined")
else ()
set(sanitize ${C8_ADD_TEST_SANITIZE})
endif ()
find_package(Catch2 REQUIRED)
add_executable (${name} ${sources})
target_link_libraries (${name} CORSIKA8 Catch2::Catch2WithMain CorsikaTestingCommon)
target_compile_options (${name} PRIVATE -g) # do not skip asserts
target_include_directories (${name} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
file (MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/test_outputs/)
if (CORSIKA_SANITIZERS_ENABLED)
# -O1 is suggested in clang docs to get reasonable performance
target_compile_options (${name} PRIVATE -O1 -fno-omit-frame-pointer -fsanitize=${sanitize} -fno-sanitize-recover=all)
set_target_properties (${name} PROPERTIES LINK_FLAGS "-fsanitize=${sanitize}")
endif ()
add_test (NAME ${name} COMMAND ${name} -o ${PROJECT_BINARY_DIR}/test_outputs/junit-${name}.xml -s -r junit)
endfunction (CORSIKA_ADD_TEST)
#!/bin/bash
function show_usage(){
printf "\n\nUsage:"
printf "$0 options [parameters]\n"
printf "\n"
printf "Options:\n"
printf "\n -s or --source-directory:\n Corsika 8 download directory, which contains the 'conanfile.py' recipe. Default is the current directory."
printf "\n -d or --debug:\n Specify 'Debug' as build type for the installed dependences. This should be matched when building CORSIKA 8."
printf "\n -r or --release:\n Specify 'Release' as build type for the installed dependences. This should be matched when building CORSIKA 8."
printf "\n -rd or --release-with-debug:\n Specify 'RelWithDebInfo' as build type for the installed dependences. This should be matched when building CORSIKA 8."
printf "\n\nExample: ./conan-install.sh --source-directory /some_path/corsika --debug"
printf "\n -h or --help:\n Prints this message.\n"
exit 0
}
echo "|---------------------------------------------------|"
echo "|-----------------[ CORSIKA 8 ]---------------------|"
echo "|-----[ CONAN2 DEPENDENCIES INSTALL SCRIPT ]------- |"
echo "|---------------------------------------------------|"
echo "|-------------------- BEGIN ------------------------| "
echo " "
SOURCE=${BASH_SOURCE[0]}
while [ -L "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR=$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )
SOURCE=$(readlink "$SOURCE")
[[ $SOURCE != /* ]] && SOURCE=$DIR/$SOURCE # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
SCRIPT_DIR=$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )
BUILD_TYPE="RelWithDebInfo"
CORSIKA_DIR=${CURRENT_DIR}
CORSIKA_DIR_INFORMED=${CURRENT_DIR}
CONAN2_OUTPUT_FOLDER_NAME="conan_cmake"
printf "[ conan-install | info > This script is located at the directory: ${SCRIPT_DIR}\n"
if [[ "$1" == "--help" ]] || [[ "$1" == "-h" ]];then
show_usage
fi
while [ ! -z "$1" ]; do
case "$1" in
--source-directory|-s)
shift
CORSIKA_DIR=$(readlink -e ${1})
CORSIKA_DIR_INFORMED=${1}
;;
--debug|-d)
#shift
BUILD_TYPE="Debug"
;;
--release|-r)
#shift
BUILD_TYPE="Release"
;;
--release-with-debug|-rd)
#shift
BUILD_TYPE="RelWithDebInfo"
;;
--help|-h)
#shift
show_usage
;;
*)
show_usage
;;
esac
if [ $# -gt 0 ]; then
shift
fi
done
if [[ ${#CORSIKA_DIR} -eq 0 ]]; then
printf "[ conan-install | warning > Output folder for cmake scripts generated by conan2 not found.\n"
printf "[ conan-install | warning > Directory '${CORSIKA_DIR_INFORMED}' does not exist.\n"
exit 1
fi
if [ -d "${CORSIKA_DIR}/${CONAN2_OUTPUT_FOLDER_NAME}" ]; then
printf "[ conan-install | info > Output folder for cmake scripts generated by conan2 is: ${CORSIKA_DIR}/${CONAN2_OUTPUT_FOLDER_NAME}\n"
else
printf "[ conan-install | warning > Output folder for cmake scripts generated by conan2 not found.\n"
printf "[ conan-install | warning > Creating directory ${CORSIKA_DIR}/${CONAN2_OUTPUT_FOLDER_NAME}.\n"
mkdir -p "${CORSIKA_DIR}/${CONAN2_OUTPUT_FOLDER_NAME}"
fi
if [ -f "${CORSIKA_DIR}/conanfile.py" ]; then
printf "[ conan-install | info > conan2 recipe: ${CORSIKA_DIR}/conanfile.py\n"
else
printf "[ conan-install | warning > conan2 recipe not found.\n"
printf "[ conan-install | warning > File '${CORSIKA_DIR}/conanfile.py' does not exist.\n"
exit 1
fi
# Conan2 variabes
CONAN2_HOME=$(readlink -e `conan config home`)
CONAN2_PROFILE_NAME="corsika8"
printf "[ conan-install | info > conan2 home: ${CONAN2_HOME}\n"
# Conan2 commands
CONAN2_DEFAULT_PROFILE_COMMAND="conan profile detect --force"
CONAN2_PROFILE_COMMAND="conan profile detect --name ${CONAN2_PROFILE_NAME} --force"
CONAN2_INSTALL_COMMAND="conan install ${CORSIKA_DIR} --output-folder=${CORSIKA_DIR}/${CONAN2_OUTPUT_FOLDER_NAME} --build=missing --settings=build_type=${BUILD_TYPE} --profile=${CONAN2_PROFILE_NAME}"
CONAN2_SHOW_PROFLE_COMMAND="conan profile show -pr ${CONAN2_PROFILE_NAME}"
printf "[ conan-install | info > Creating default profile...\n\n"
eval $CONAN2_DEFAULT_PROFILE_COMMAND
if [ ! $? -eq 0 ]; then
printf "[ conan-install | error > Exit code 126 (Command invoked cannot execute):\n ${CONAN2_DEFAULT_PROFILE_COMMAND}.\n"
exit 126
fi
printf "[ conan-install | info > Creating '${CONAN2_PROFILE_NAME}' profile...\n\n"
eval $CONAN2_PROFILE_COMMAND
if [ ! $? -eq 0 ]; then
printf "[ conan-install | error > Exit code 126 (Command invoked cannot execute):\n ${CONAN2_PROFILE_COMMAND}.\n"
exit 126
fi
printf "\n\n[ conan-install | info > Editing '${CONAN2_PROFILE_NAME}' profile\n"
#========== cppstd setting ============
STD_NUMBER=`grep -n -m 1 "compiler.cppstd=" ${CONAN2_HOME}/profiles/${CONAN2_PROFILE_NAME} | cut -d: -f1`
SED_STD_COMMAND="sed -i '${STD_NUMBER}s/.*/compiler.cppstd=gnu17/' ${CONAN2_HOME}/profiles/${CONAN2_PROFILE_NAME}"
eval $SED_STD_COMMAND
if [ ! $? -eq 0 ]; then
printf "[ conan-install | error > Exit code 126 (Command invoked cannot execute):\n ${SED_STD_COMMAND}\n"
exit 126
fi
#========== libcxx setting ============
CXX_NUMBER=`grep -n -m 1 "compiler.libcxx=" ${CONAN2_HOME}/profiles/${CONAN2_PROFILE_NAME} | cut -d: -f1`
SED_CXX_COMMAND="sed -i '${CXX_NUMBER}s/.*/compiler.libcxx=libstdc++11/' ${CONAN2_HOME}/profiles/${CONAN2_PROFILE_NAME}"
eval $SED_CXX_COMMAND
if [ ! $? -eq 0 ]; then
printf "[ conan-install | error > Exit code 126 (Command invoked cannot execute):\n ${SED_CXX_COMMAND}\n"
exit 126
fi
eval $CONAN2_SHOW_PROFLE_COMMAND
if [ ! $? -eq 0 ]; then
printf "[ conan-install | error > Exit code 126 (Command invoked cannot execute):\n ${CONAN2_SHOW_PROFLE_COMMAND}\n"
exit 126
fi
printf "[ conan-install | info > ${CONAN2_INSTALL_COMMAND}\n"
eval ${CONAN2_INSTALL_COMMAND}
if [ ! $? -eq 0 ]; then
printf "[ conan-install | error > Exit code 126 (Command invoked cannot execute):\n ${CONAN2_INSTALL_COMMAND}\n"
exit 126
fi
CORSIKA_CMAKE_SCRIPT="#!/bin/bash
function show_usage(){
printf \"\n\nUsage:\"
printf \"\$0 options [parameters]\n\"
printf \"\n\"
printf \"Options:\n\"
printf \"\n -c or --cmake-flags:\n Additional flags and settings to cmake base command. Default is empty string.\"
printf \"\n\nExample: ./corsika-cmake.sh --cmake-flags '-DUSE_Pythia8_C8=C8' \"
printf \"\n\nNote: the source directory (the one containing CMakeLists.txt), CMAKE_BUILD_TYPE, CMAKE_POLICY_DEFAULT_CMP0091 and CMAKE_TOOLCHAIN_FILE are already set. Do not repeat them.\"
printf \"\n -h or --help:\n Prints this message.\n\"
exit 0
}
echo \"|---------------------------------------------------|\"
echo \"|-----------------[ CORSIKA 8 ]---------------------|\"
echo \"|----------[ CMAKE CONFIGURATION SCRIPT ]---------- |\"
echo \"|---------------------------------------------------|\"
echo \"|-------------------- BEGIN ------------------------|\"
CMAKE_BASE_SETTINGS=\"cmake -S ${CORSIKA_DIR} -D CONAN_CMAKE_DIR=${CORSIKA_DIR}/${CONAN2_OUTPUT_FOLDER_NAME} -D CMAKE_TOOLCHAIN_FILE=${CORSIKA_DIR}/${CONAN2_OUTPUT_FOLDER_NAME}/conan_toolchain.cmake -D CMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_BUILD_TYPE=${BUILD_TYPE}\"
CMAKE_ADDITIONAL_SETTINGS=\"\"
if [[ \"\$1\" == \"--help\" ]] || [[ \"\$1\" == \"-h\" ]];then
show_usage
fi
while [ ! -z \"\$1\" ]; do
case \"\$1\" in
--cmake-flags|-c)
shift
CMAKE_ADDITIONAL_SETTINGS=\${1}
;;
--help|-h)
#shift
show_usage
;;
*)
show_usage
;;
esac
if [ \$# -gt 0 ]; then
shift
fi
done
printf \"[corsika-cmake | info > Issuing CMake command :\n\"
printf '[corsika-cmake | info > \e[1;36m%s\e[0m\n\n\n' \"\${CMAKE_BASE_SETTINGS} \${CMAKE_ADDITIONAL_SETTINGS}\"
eval \"\${CMAKE_BASE_SETTINGS} \${CMAKE_ADDITIONAL_SETTINGS}\"
if [ ! \$? -eq 0 ]; then
printf \"[ corsika | error > Project configuration (CMake) failed. \n\"
exit 1
fi
echo \"|---------------------------------------------------|\"
echo \"|-----------------[ CORSIKA 8 ]---------------------|\"
echo \"|----------[ CMAKE CONFIGURATION SCRIPT ]---------- |\"
echo \"|---------------------------------------------------|\"
echo \"|-------------------- END --------------------------|\"
"
printf "%s" "${CORSIKA_CMAKE_SCRIPT}" > ${SCRIPT_DIR}/corsika-cmake.sh
chmod +x ${SCRIPT_DIR}/corsika-cmake.sh
printf "\n\n[ conan-install | info > Copy and paste the commands below in the corsika-build directory:\n\n"
printf '\e[1;36m%s\e[0m\n' "> ${SCRIPT_DIR}/corsika-cmake.sh "
printf '\e[1;36m%s\e[0m\n' "> make -j8"
echo " "
echo "|---------------------------------------------------|"
echo "|-----------------[ CORSIKA 8 ]---------------------|"
echo "|-----[ CONAN2 DEPENDENCIES INSTALL SCRIPT ]------- |"
echo "|---------------------------------------------------|"
echo "|-------------------- END --------------------------| "
echo " "
exit 0
from conan import ConanFile
from conan.tools.cmake import cmake_layout,CMakeToolchain, CMakeDeps
class Pkg(ConanFile):
generators = "CMakeDeps", #"CMakeToolchain",
settings = "os", "arch", "compiler", "build_type"
default_options = {
'readline*:shared': 'True',
'arrow*:shared': 'False',
'arrow*:parquet': 'True',
'arrow*:fPIC': 'False',
'arrow*:with_re2': 'True',
'arrow*:with_protobuf': 'False',
'arrow*:with_openssl': 'False',
'arrow*:with_gflags': 'False',
'arrow*:with_glog': 'False',
'arrow*:with_grpc': 'False',
'arrow*:with_utf8proc': 'False',
'arrow*:with_zstd': 'False',
'arrow*:with_bz2': 'False',
'arrow*:with_lz4': 'True',
'arrow*:with_thrift': 'True',
'arrow*:with_boost': 'True',
'boost*:without_container': 'True',
'boost*:without_context': 'True',
'boost*:without_contract': 'True',
'boost*:without_coroutine': 'True',
'boost*:without_date_time': 'True',
'boost*:without_fiber': 'True',
'boost*:without_filesystem': 'False',
'boost*:without_graph': 'True',
'boost*:without_graph_parallel': 'True',
'boost*:without_iostreams': 'False',
'boost*:without_json': 'True',
'boost*:without_locale': 'True',
'boost*:without_log': 'True',
'boost*:without_math': 'False',
'boost*:without_mpi': 'True',
'boost*:without_nowide': 'True',
'boost*:without_program_options': 'True',
'boost*:without_python': 'True',
'boost*:without_serialization': 'False',
'boost*:without_stacktrace': 'True',
'boost*:without_system': 'False',
'boost*:without_test': 'True',
'boost*:without_thread': 'True',
'boost*:without_timer': 'True',
'boost*:without_type_erasure': 'True',
'boost*:without_wave': 'True'
}
def configure(self):
self.options['arrow'].with_boost = True
self.options['arrow'].parquet = True
self.options['arrow'].with_thrift = True
def requirements(self):
self.requires("spdlog/1.14.1", force=True)
self.requires("catch2/3.6.0")
self.requires("bzip2/1.0.8")
self.requires("boost/1.85.0", force=True)
self.requires("eigen/3.4.0")
self.requires("zlib/1.3.1")
self.requires("yaml-cpp/0.8.0")
self.requires("cli11/1.9.1")
self.requires("arrow/16.1.0")
self.requires("proposal/7.6.2")
def build_requirements(self):
self.tool_requires("readline/8.0")
self.tool_requires("bison/[>1.0]")
def generate(self):
tc = CMakeToolchain(self)
tc.absolute_paths = True
tc.generate()
/*
* (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
*
* This software is distributed under the terms of the 3-clause BSD license.
* See file LICENSE for a full version of the license.
*/
// Another possibility:
// https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Execute-Around_Pointer
// for a more global approach
//
// In this case here only a single function is measured via member function pointer.
#pragma once
#include <chrono>
#include <utility>
namespace corsika {
// Common
template <typename TClass, typename TRet, typename... TArgs,
TRet (TClass::*TFuncPtr)(TArgs...), typename TTimer>
inline ClassTimer<TRet (TClass::*)(TArgs...), TFuncPtr, TTimer>::ClassTimer(TClass& obj)
: ClassTimerImpl<TClass, TTimer>(obj) {}
template <typename TClass, typename TRet, typename... TArgs,
TRet (TClass::*TFuncPtr)(TArgs...), typename TTimer>
inline TRet ClassTimer<TRet (TClass::*)(TArgs...), TFuncPtr, TTimer>::call(
TArgs... args) {
this->start_ = ClassTimerImpl<TClass, TTimer>::clock_type::now();
auto tmp = (this->obj_.*TFuncPtr)(std::forward<TArgs>(args)...);
this->timeDiff_ = std::chrono::duration_cast<
typename ClassTimerImpl<TClass, TTimer>::duration_type>(
ClassTimerImpl<TClass, TTimer>::clock_type::now() - this->start_);
return tmp;
}
// Specialisation 1
template <typename TClass, typename... TArgs, void (TClass::*TFuncPtr)(TArgs...),
typename TTimer>
inline ClassTimer<void (TClass::*)(TArgs...), TFuncPtr, TTimer>::ClassTimer(TClass& obj)
: ClassTimerImpl<TClass, TTimer>(obj) {}
template <typename TClass, typename... TArgs, void (TClass::*TFuncPtr)(TArgs...),
typename TTimer>
inline void ClassTimer<void (TClass::*)(TArgs...), TFuncPtr, TTimer>::call(
TArgs... args) {
this->start_ = ClassTimerImpl<TClass, TTimer>::clock_type::now();
(this->obj_.*TFuncPtr)(std::forward<TArgs>(args)...);
this->timeDiff_ = std::chrono::duration_cast<
typename ClassTimerImpl<TClass, TTimer>::duration_type>(
ClassTimerImpl<TClass, TTimer>::clock_type::now() - this->start_);
return;
}
/// Specialisation 2
template <typename TClass, typename TRet, typename... TArgs,
TRet (TClass::*TFuncPtr)(TArgs...) const, typename TTimer>
inline ClassTimer<TRet (TClass::*)(TArgs...) const, TFuncPtr, TTimer>::ClassTimer(
TClass& obj)
: ClassTimerImpl<TClass, TTimer>(obj) {}
template <typename TClass, typename TRet, typename... TArgs,
TRet (TClass::*TFuncPtr)(TArgs...) const, typename TTimer>
inline TRet ClassTimer<TRet (TClass::*)(TArgs...) const, TFuncPtr, TTimer>::call(
TArgs... args) {
this->start_ = ClassTimerImpl<TClass, TTimer>::clock_type::now();
auto tmp = (this->obj_.*TFuncPtr)(std::forward<TArgs>(args)...);
this->timeDiff_ = std::chrono::duration_cast<
typename ClassTimerImpl<TClass, TTimer>::duration_type>(
ClassTimerImpl<TClass, TTimer>::clock_type::now() - this->start_);
return tmp;
}
/// Specialisation 3
template <typename TClass, typename... TArgs, void (TClass::*TFuncPtr)(TArgs...) const,
typename TTimer>
inline ClassTimer<void (TClass::*)(TArgs...) const, TFuncPtr, TTimer>::ClassTimer(
TClass& obj)
: ClassTimerImpl<TClass, TTimer>(obj) {}
template <typename TClass, typename... TArgs, void (TClass::*TFuncPtr)(TArgs...) const,
typename TTimer>
inline void ClassTimer<void (TClass::*)(TArgs...) const, TFuncPtr, TTimer>::call(
TArgs... args) {
this->start_ = ClassTimerImpl<TClass, TTimer>::clock_type::now();
(this->obj_.*TFuncPtr)(std::forward<TArgs>(args)...);
this->timeDiff_ = std::chrono::duration_cast<
typename ClassTimerImpl<TClass, TTimer>::duration_type>(
ClassTimerImpl<TClass, TTimer>::clock_type::now() - this->start_);
return;
}
} // namespace corsika
/*
* (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
*
* This software is distributed under the terms of the 3-clause BSD license.
* See file LICENSE for a full version of the license.
*/
#pragma once
#include <chrono>
#include <utility>
namespace corsika {
template <typename TFunc, typename TTime>
inline FunctionTimer<TFunc, TTime>::FunctionTimer(TFunc f)
: function_(f) {}
template <typename TFunc, typename TTime>
template <typename... TArgs>
inline auto FunctionTimer<TFunc, TTime>::operator()(TArgs&&... args)
-> std::invoke_result_t<TFunc, TArgs...> {
this->startTimer();
auto tmp = function_(std::forward<TArgs>(args)...);
this->stopTimer();
return tmp;
}
} // namespace corsika
/*
* (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
*
* This software is distributed under the terms of the 3-clause BSD license.
* See file LICENSE for a full version of the license.
*/
#pragma once
#include <corsika/framework/core/PhysicalUnits.hpp>
#include <corsika/framework/core/Step.hpp>
#include <corsika/framework/process/ProcessReturn.hpp>
#include <corsika/framework/process/ContinuousProcessStepLength.hpp>
#include <corsika/framework/process/ContinuousProcessIndex.hpp>
#include <corsika/framework/random/ExponentialDistribution.hpp>
#include <corsika/framework/random/RNGManager.hpp>
#include <corsika/framework/random/UniformRealDistribution.hpp>
#include <corsika/framework/stack/SecondaryView.hpp>
#include <corsika/framework/utility/COMBoost.hpp>
#include <corsika/media/Environment.hpp>
#include <corsika/media/NuclearComposition.hpp>
#include <cassert>
#include <cmath>
#include <iostream>
#include <limits>
#include <type_traits>
namespace corsika {
template <typename TTracking, typename TProcessList, typename TOutput, typename TStack>
inline Cascade<TTracking, TProcessList, TOutput, TStack>::Cascade(
Environment<medium_interface_type> const& env, TTracking& tr, TProcessList& pl,
TOutput& out, TStack& stack)
: environment_(env)
, tracking_(tr)
, sequence_(pl)
, output_(out)
, stack_(stack)
, forceInteraction_(false)
, forceDecay_(false) {
CORSIKA_LOG_INFO(c8_ascii_);
CORSIKA_LOG_INFO("This is CORSIKA {}.{}.{}.{}", CORSIKA_RELEASE_NUMBER,
CORSIKA_MAJOR_NUMBER, CORSIKA_MINOR_NUMBER, CORSIKA_PATCH_NUMBER);
CORSIKA_LOG_INFO(
"The C8 author list can be found at: "
"https://gitlab.iap.kit.edu/AirShowerPhysics/corsika/-/wikis/"
"Current-CORSIKA-8-author-list");
CORSIKA_LOG_INFO("Tracking algorithm: {} (version {})", TTracking::getName(),
TTracking::getVersion());
if constexpr (stack_view_type::has_event) {
CORSIKA_LOG_INFO("Stack - with full cascade HISTORY.");
}
}
template <typename TTracking, typename TProcessList, typename TOutput, typename TStack>
inline void Cascade<TTracking, TProcessList, TOutput, TStack>::run() {
// trigger the start of the outputs for this shower
output_.startOfShower();
setNodes(); // put each particle on stack in correct environment volume
while (!stack_.isEmpty()) {
sequence_.initCascadeEquations();
while (!stack_.isEmpty()) {
CORSIKA_LOG_TRACE("Stack: {}", stack_.asString());
count_++;
auto pNext = stack_.getNextParticle();
CORSIKA_LOG_TRACE(
"============== next particle : count={}, pid={}"
", stack entries={}"
", stack deleted={}",
count_, pNext.getPID(), stack_.getEntries(), stack_.getErased());
step(pNext);
sequence_.doStack(stack_);
}
// do cascade equations, which can put new particles on Stack,
// thus, the double loop
sequence_.doCascadeEquations(stack_);
}
// indicate end of shower
output_.endOfShower();
}
template <typename TTracking, typename TProcessList, typename TOutput, typename TStack>
inline void Cascade<TTracking, TProcessList, TOutput, TStack>::forceInteraction() {
forceInteraction_ = true;
if (forceDecay_) {
CORSIKA_LOG_ERROR("Cannot set forceInteraction when forceDecay is already set");
throw std::runtime_error(
"Cannot set forceInteraction when forceDecay is already set");
}
}
template <typename TTracking, typename TProcessList, typename TOutput, typename TStack>
inline void Cascade<TTracking, TProcessList, TOutput, TStack>::forceDecay() {
forceDecay_ = true;
if (forceInteraction_) {
CORSIKA_LOG_ERROR("Cannot set forceDecay when forceInteraction is already set");
throw std::runtime_error(
"Cannot set forceDecay when forceInteraction is already set");
}
}
template <typename TTracking, typename TProcessList, typename TOutput, typename TStack>
inline void Cascade<TTracking, TProcessList, TOutput, TStack>::step(
particle_type& particle) {
// determine the volume where the particle is (last) known to be
auto const* currentLogicalNode = particle.getNode();
// assert that particle stays outside void Universe if it has no
// model properties set
assert((currentLogicalNode != &*environment_.getUniverse() ||
environment_.getUniverse()->hasModelProperties()) &&
"FATAL: The environment model has no valid properties set!");
NuclearComposition const& composition =
currentLogicalNode->getModelProperties().getNuclearComposition();
// determine projectile
HEPEnergyType const Elab = particle.getEnergy();
FourMomentum const projectileP4{Elab, particle.getMomentum()};
// determine combined full inelastic cross section of the particles in the material
auto const targetMomentum = MomentumVector{
particle.getMomentum().getCoordinateSystem(), {0_GeV, 0_GeV, 0_GeV}};
auto const xs_function = [&](Code const targetId) -> CrossSectionType {
FourMomentum const targetP4{get_mass(targetId), targetMomentum};
return sequence_.getCrossSection(particle, targetId, targetP4);
};
CrossSectionType const total_cx_pre = composition.getWeightedSum(xs_function);
if (forceInteraction_) {
CORSIKA_LOG_TRACE("forced interaction!");
forceInteraction_ = false; // just one (first) interaction
stack_view_type secondaries(particle);
interaction(secondaries, projectileP4, composition, total_cx_pre);
sequence_.doSecondaries(secondaries);
particle.erase(); // primary particle is done
return;
}
if (forceDecay_) {
CORSIKA_LOG_TRACE("forced decay!");
forceDecay_ = false; // just one decay
stack_view_type secondaries(particle);
decay(secondaries, sequence_.getInverseLifetime(particle));
if (secondaries.getSize() == 1 && secondaries.getProjectile().getPID() ==
secondaries.getNextParticle().getPID()) {
throw std::runtime_error(
fmt::format("Particle {} decays into itself!",
get_name(secondaries.getProjectile().getPID())));
}
sequence_.doSecondaries(secondaries);
particle.erase(); // primary particle is done
return;
}
// calculate interaction length in medium
GrammageType const total_lambda =
(composition.getAverageMassNumber() * constants::u) / total_cx_pre;
// sample random exponential step length in grammage
ExponentialDistribution expDist{total_lambda};
GrammageType const next_interact = expDist(rng_);
CORSIKA_LOG_DEBUG("total_lambda={} g/cm2, next_interact={} g/cm2",
double(total_lambda / 1_g * 1_cm * 1_cm),
double(next_interact / 1_g * 1_cm * 1_cm));
// determine combined total inverse decay time
InverseTimeType const total_inv_lifetime_pre = sequence_.getInverseLifetime(particle);
// sample random exponential decay time
ExponentialDistribution expDistDecay(1 / total_inv_lifetime_pre);
TimeType const next_decay = expDistDecay(rng_);
CORSIKA_LOG_DEBUG("total_lifetime={} ns, next_decay={} ns",
(1 / total_inv_lifetime_pre) / 1_ns, next_decay / 1_ns);
// convert next_decay from time to length [m]
LengthType const distance_decay = next_decay * particle.getMomentum().getNorm() /
particle.getEnergy() * constants::c;
// determine geometric tracking
auto [track, nextVol] = tracking_.getTrack(particle);
auto geomMaxLength = track.getLength(1);
// convert next_step from grammage to length
LengthType const distance_interact =
currentLogicalNode->getModelProperties().getArclengthFromGrammage(track,
next_interact);
// determine the maximum geometric step length
ContinuousProcessStepLength const continuousMaxStep =
sequence_.getMaxStepLength(particle, track);
LengthType const continuous_max_dist = continuousMaxStep;
// take minimum of geometry, interaction, decay for next step
LengthType const min_discrete = std::min(distance_interact, distance_decay);
LengthType const min_non_continuous = std::min(min_discrete, geomMaxLength);
LengthType const min_distance = std::min(min_non_continuous, continuous_max_dist);
bool const isContinuous = continuous_max_dist < min_non_continuous;
// inform ContinuousProcesses (if applicable) that it is responsible for step-limit
// this would become simpler if we follow the idea of Max to enumerate ALL types of
// processes. Then non-continuous are included and no further logic is needed to
// distinguish between continuous and non-continuous limit.
auto const limitingId = isContinuous ? continuousMaxStep : ContinuousProcessIndex{};
// // the current step IS limited by a known continuous process
CORSIKA_LOG_DEBUG(
"transport particle by : {} m "
"Medium transition after: {} m "
"Decay after: {} m "
"Interaction after: {} m "
"Continuous limit: {} m ",
min_distance / 1_m, geomMaxLength / 1_m, distance_decay / 1_m,
distance_interact / 1_m, continuous_max_dist / 1_m);
// move particle along the trajectory to new position
// also update momentum/direction/time
track.setLength(min_distance);
Step step{particle, track};
// apply all continuous processes on particle + track
if (sequence_.doContinuous(step, limitingId) == ProcessReturn::ParticleAbsorbed) {
CORSIKA_LOG_DEBUG("Cascade: delete absorbed particle PID={} E={} GeV",
particle.getPID(), particle.getEnergy() / 1_GeV);
if (particle.isErased()) {
CORSIKA_LOG_WARN(
"Particle marked as Absorbed in doContinuous, but prematurely erased. This "
"may be bug. Check.");
} else {
particle.erase();
}
return; // particle is gone -> return
}
particle.setTime(step.getTimePost());
particle.setPosition(step.getPositionPost());
particle.setDirection(step.getDirectionPost());
particle.setKineticEnergy(step.getEkinPost());
if (isContinuous) {
return; // there is nothing further, step is finished
}
CORSIKA_LOG_DEBUG("discrete process before geometric limit ? {}",
((min_distance < geomMaxLength) ? "yes" : "no"));
if (geomMaxLength < min_discrete) {
// geometric / tracking limit
if (nextVol != currentLogicalNode) {
// boundary crossing, step is limited by volume boundary
CORSIKA_LOG_DEBUG("volume boundary crossing to {}", fmt::ptr(nextVol));
if (nextVol == environment_.getUniverse().get()) {
CORSIKA_LOG_DEBUG(
"particle left physics world, is now in unknown space -> delete");
particle.erase();
}
particle.setNode(nextVol);
/*
doBoundary may delete the particle (or not)
caveat: any changes to particle, or even the production
of new secondaries is currently not passed to ParticleCut,
thus, particles outside the desired phase space may be produced.
\todo: this must be fixed.
*/
sequence_.doBoundaryCrossing(particle, *currentLogicalNode, *nextVol);
return; // step finished
}
CORSIKA_LOG_DEBUG("step limit reached (e.g. deflection). nothing further happens.");
// final sanity check, no actions
{
auto const* numericalNodeAfterStep =
environment_.getUniverse()->getContainingNode(particle.getPosition());
CORSIKA_LOG_TRACE(
"Geometry check: numericalNodeAfterStep={} currentLogicalNode={}",
fmt::ptr(numericalNodeAfterStep), fmt::ptr(currentLogicalNode));
if (numericalNodeAfterStep != currentLogicalNode) {
CORSIKA_LOG_DEBUG(
"expect to be in node currentLogicalNode={} but are in "
"numericalNodeAfterStep={}. Continue, but without guarantee.",
fmt::ptr(currentLogicalNode), fmt::ptr(numericalNodeAfterStep));
}
}
// we did not cross any volume boundary
// step length limit
return;
}
// interaction or decay to happen in this step
// the outcome of decay or interaction MAY be a) new particles in
// secondaries, b) the projectile particle deleted (or
// changed)
stack_view_type secondaries{particle};
/*
Create SecondaryView object on Stack. The data container
remains untouched and identical, and 'projectile' is identical
to 'particle' above this line. However,
projectile.addSecondaries populate the SecondaryView, which can
then be used afterwards for further processing. Thus: it is
important to use projectile/view (and not particle) for Interaction,
and Decay!
*/
FourMomentum const projectileP4Post{particle.getEnergy(), particle.getMomentum()};
bool eraseParticle =
false; // only erase original particle if it decayed or interacted
if (distance_interact < distance_decay) {
eraseParticle = isInteracted(
interaction(secondaries, projectileP4Post, composition, total_cx_pre));
} else {
[[maybe_unused]] auto projectile = secondaries.getProjectile();
if (decay(secondaries, total_inv_lifetime_pre) == ProcessReturn::Decayed) {
eraseParticle = true;
if (secondaries.getSize() == 1 &&
projectile.getPID() == secondaries.getNextParticle().getPID()) {
throw std::runtime_error(fmt::format("Particle {} decays into itself!",
get_name(projectile.getPID())));
}
}
}
if (eraseParticle) {
// doSecondaries() makes sense only if there was an actual event
sequence_.doSecondaries(secondaries);
particle.erase();
}
}
template <typename TTracking, typename TProcessList, typename TOutput, typename TStack>
inline ProcessReturn Cascade<TTracking, TProcessList, TOutput, TStack>::decay(
stack_view_type& view, InverseTimeType initial_inv_decay_time) {
CORSIKA_LOG_DEBUG("decay");
// one option is that decay_time is now larger (less
// probability for decay) than it was before the step, thus,
// no decay might actually occur and is allowed
UniformRealDistribution<InverseTimeType> uniDist(initial_inv_decay_time);
const auto sample_process = uniDist(rng_);
auto const returnCode = sequence_.selectDecay(view, sample_process);
if (returnCode != ProcessReturn::Decayed) {
CORSIKA_LOG_ERROR("Particle {} did not decay!",
get_name(view.getProjectile().getPID()));
}
setEventType(view, history::EventType::Decay);
return returnCode;
}
template <typename TTracking, typename TProcessList, typename TOutput, typename TStack>
inline ProcessReturn Cascade<TTracking, TProcessList, TOutput, TStack>::interaction(
stack_view_type& view, FourMomentum const& projectileP4,
NuclearComposition const& composition,
CrossSectionType const initial_cross_section) {
CORSIKA_LOG_DEBUG("collide");
// one option is that cross section is now smaller (less
// probability for collision) than it was before the step, thus,
// no interaction might actually occur and is allowed
UniformRealDistribution<CrossSectionType> uniDist(initial_cross_section);
CrossSectionType const sample_process_by_cx = uniDist(rng_);
auto const returnCode = sequence_.selectInteraction(view, projectileP4, composition,
rng_, sample_process_by_cx);
if (returnCode != ProcessReturn::Interacted) {
CORSIKA_LOG_DEBUG("Particle did not interact!");
}
setEventType(view, history::EventType::Interaction);
return returnCode;
}
template <typename TTracking, typename TProcessList, typename TOutput, typename TStack>
inline void Cascade<TTracking, TProcessList, TOutput, TStack>::setNodes() {
std::for_each(stack_.begin(), stack_.end(), [&](auto& p) {
auto const* numericalNode =
environment_.getUniverse()->getContainingNode(p.getPosition());
p.setNode(numericalNode);
});
}
template <typename TTracking, typename TProcessList, typename TOutput, typename TStack>
inline void Cascade<TTracking, TProcessList, TOutput, TStack>::setEventType(
stack_view_type& view, [[maybe_unused]] history::EventType eventType) {
if constexpr (stack_view_type::has_event) {
for (auto&& sec : view) { sec.getEvent()->setEventType(eventType); }
}
}
} // namespace corsika