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 172 additions and 1670 deletions
"""
(c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
This software is distributed under the terms of the GNU General Public
Licence version 3 (GPL Version 3). See file LICENSE for a full version of
the license.
"""
__version__: str = "8.0.0-alpha"
"""
(c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
This software is distributed under the terms of the GNU General Public
Licence version 3 (GPL Version 3). See file LICENSE for a full version of
the license.
"""
import corsika
def test_corsika_version() -> None:
"""
Check the current CORSIKA version.
"""
assert corsika.__version__ == "8.0.0-alpha"
# CORSIKA 8 Framework for Particle Cascades in Astroparticle Physics
# CORSIKA 8 Framework for Particle Cascades in Astroparticle Physics
The purpose of CORSIKA is to simulate any particle cascades in
astroparticle physics or astrophysical context. A lot of emphasis is
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
correctness. To boost computational efficiency, different techniques
are provided, like thinning or cascade equations. The aim is that
CORSIKA remains the most comprehensive framework for simulating
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
decision of the user must be performed at compile time. At run time
only specific model parameters can still be changed.
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 GPLv3 license. See [license
file](https://gitlab.ikp.kit.edu/AirShowerPhysics/corsika/blob/master/LICENSE)
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). We kindly ask (and
require) any relevant improvement or addition to be offered or
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.
When you plan to contribute to CORSIKA 8 check the guidelines outlined here:
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.ikp.kit.edu/AirShowerPhysics/corsika/blob/master/CONTRIBUTING.md). Code
that fails the review by the CORSIKA author group must be improved
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
[collaboration
agreement](https://gitlab.ikp.kit.edu/AirShowerPhysics/corsika/blob/master/COLLABORATION_AGREEMENT.md). The
agreement can be discussed, and eventually improved.
been accepted and merged, you become a contributor of the CORSIKA 8
project (code author).
We also want to point you to the [MCnet
guidelines](https://gitlab.ikp.kit.edu/AirShowerPhysics/corsika/blob/master/MCNET_GUIDELINES),
which are very useful also for us.
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
* Connect to https://gitlab.ikp.kit.edu register yourself and join the "Air Shower Physics" group
* 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
touch with the project.
## Prerequisites
## Installation
CORSIKA 8 is tested regularly via gitlab-CI using recent gcc and clang
versions. Additional software prerequisites: cmake, g++, git.
Furthermore, eigen3, boost, catch2, spdlog are shipped in the
ThirdParty directory, so an installation on the system is optional.
Also Pythia 8, CONEX and PROPOSAL are distributed in the ThirdParty
folder. You may also install those packages on your system and use
those; we test with Pythia version 8.235.
CORSIKA 8 is tested regularly at least on `gcc11.0.0` and `clang-14.0.0`.
On a bare Ubuntu 18.04, just add:
```
sudo apt install cmake g++ git
### 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
```
add ```libeigen3-dev``` if you want to use system version of eigen3.
If you work with FreeBSD, run:
### 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
```
pkg install git cmake python3 flang
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
```
or add ```boost-libs``` and ```eigen``` if you want to use the system versions.
## Installation
### 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).
Follow these steps to download and install CORSIKA 8 milestone2
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.
```
git clone --recursive https://gitlab.ikp.kit.edu/AirShowerPhysics/corsika.git
cd corsika
mkdir ../corsika-build
cd ../corsika-build
cmake ../corsika -DCMAKE_INSTALL_PREFIX=../corsika-install
make -j8
### 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
make test
```
and if you want to see how the first simple hadron cascade develops,
see `Documentation/Examples/cascade_example.cc` for a starting point.
Run the cascade_example with:
## 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
```
cd ../corsika-install
share/examples/cascade_example
## 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
```
Visualize output (needs gnuplot installed):
## 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
```
bash share/tools/plot_tracks.sh tracks.dat
firefox tracks.dat.gif
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
```
Or also consider the `vertical_eas` example in the same directory, which can
be configured with command line options.
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. On Ubuntu 18.04, do:
```
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
```
make doxygen
Switch to the `corsika-build` directory and do
```shell
make docs
make install
```
browse with firefox:
open with firefox:
```shell
firefox ../corsika-install/share/corsika/doc/html/index.html
```
firefox ../corsika-install/share/doc/html/index.html
```
This is currently derived from
https://gitlab.ikp.kit.edu/AirShowerPhysics/corsika/wikis/ICRC2019
and will be revised whenever needed:
- Luisa Arrabito (1)
- Dominik Baack (2)
- Johan Bregeon (1)
- Hans Dembinski (3)
- Ralph Engel (4)
- Dieter Heck (4)
- Tim Huege (4,5)
- Lukas Nellen (6)
- Tanguy Pierog (4)
- Maximilian Reininghaus (4,7)
- Felix Riehn (8)
- Ralf Ulrich (4)
- Darko Veberic (4)
Affiliations:
- University of Montpellier, France
- TU Dortmund University, Germany
- Max Planck Institute for Nuclear Physics, Heidelberg, Germany
- Karlsruhe Institute of Technology (KIT), Germany
- Vrije Universiteit Brussel, Belgium
- National Autonomous University of Mexico (UNAM)
- Instituto de Tecnologías en Detección y Astropartículas (CNEA, CONICET, UNSAM), Buenos Aires, Argentina
- Laboratory of Instrumentation and Experimental Particles (LIP), Portugal
set (
SETUP_HEADERS
SetupStack.h
SetupEnvironment.h
SetupTrajectory.h
)
set (
SETUP_NAMESPACE
corsika/setup
)
add_library (CORSIKAsetup INTERFACE)
CORSIKA_COPY_HEADERS_TO_NAMESPACE (CORSIKAsetup ${SETUP_NAMESPACE} ${SETUP_HEADERS})
target_link_libraries (
CORSIKAsetup
INTERFACE
CORSIKAgeometry
SuperStupidStack
NuclearStackExtension
)
target_include_directories (
CORSIKAsetup
INTERFACE
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>
$<INSTALL_INTERFACE:include/include>
)
install (
FILES ${SETUP_HEADERS}
DESTINATION include/${SETUP_NAMESPACE}
)
/*
* (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
*
* This software is distributed under the terms of the GNU General Public
* Licence version 3 (GPL Version 3). See file LICENSE for a full version of
* the license.
*/
#pragma once
#include <corsika/environment/Environment.h>
#include <corsika/environment/IMediumModel.h>
#include <corsika/environment/NameModel.h>
namespace corsika::setup {
using IEnvironmentModel = environment::IMediumModel;
using SetupEnvironment = environment::Environment<IEnvironmentModel>;
} // namespace corsika::setup
/*
* (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
*
* This software is distributed under the terms of the GNU General Public
* Licence version 3 (GPL Version 3). See file LICENSE for a full version of
* the license.
*/
#pragma once
// the basic particle data stack:
#include <corsika/stack/super_stupid/SuperStupidStack.h>
// extension with nuclear data for Code::Nucleus
#include <corsika/stack/nuclear_extension/NuclearStackExtension.h>
// extension with geometry information for tracking
#include <corsika/environment/Environment.h>
#include <corsika/setup/SetupEnvironment.h>
#include <corsika/stack/CombinedStack.h>
#include <tuple>
#include <utility>
#include <vector>
// definition of stack-data object to store geometry information
template <typename TEnvType>
/**
* @class GeometryData
*
* definition of stack-data object to store geometry information
*/
class GeometryData {
public:
using BaseNodeType = typename TEnvType::BaseNodeType;
// these functions are needed for the Stack interface
void Clear() { fNode.clear(); }
unsigned int GetSize() const { return fNode.size(); }
unsigned int GetCapacity() const { return fNode.size(); }
void Copy(const int i1, const int i2) { fNode[i2] = fNode[i1]; }
void Swap(const int i1, const int i2) { std::swap(fNode[i1], fNode[i2]); }
// custom data access function
void SetNode(const int i, BaseNodeType const* v) { fNode[i] = v; }
auto const* GetNode(const int i) const { return fNode[i]; }
// these functions are also needed by the Stack interface
void IncrementSize() { fNode.push_back(nullptr); }
void DecrementSize() {
if (fNode.size() > 0) { fNode.pop_back(); }
}
// custom private data section
private:
std::vector<const BaseNodeType*> fNode;
};
/**
* @class GeometryDataInterface
*
* corresponding defintion of a stack-readout object, the iteractor
* dereference operator will deliver access to these function
// defintion of a stack-readout object, the iteractor dereference
// operator will deliver access to these function
*/
template <typename T, typename TEnvType>
class GeometryDataInterface : public T {
public:
using T::GetIndex;
using T::GetStackData;
using T::SetParticleData;
using BaseNodeType = typename TEnvType::BaseNodeType;
// default version for particle-creation from input data
void SetParticleData(const std::tuple<BaseNodeType const*> v) {
SetNode(std::get<0>(v));
}
void SetParticleData(GeometryDataInterface& parent,
const std::tuple<BaseNodeType const*>) {
SetNode(parent.GetNode()); // copy Node from parent particle!
}
void SetParticleData() { SetNode(nullptr); }
void SetParticleData(GeometryDataInterface& parent) {
SetNode(parent.GetNode()); // copy Node from parent particle!
}
void SetNode(BaseNodeType const* v) { GetStackData().SetNode(GetIndex(), v); }
auto const* GetNode() const { return GetStackData().GetNode(GetIndex()); }
};
namespace corsika::setup {
namespace detail {
//
// this is an auxiliary help typedef, which I don't know how to put
// into NuclearStackExtension.h where it belongs...
template <typename StackIter>
using ExtendedParticleInterfaceType =
corsika::stack::nuclear_extension::NuclearParticleInterface<
corsika::stack::super_stupid::SuperStupidStack::PIType, StackIter>;
//
// the particle data stack with extra nuclear information:
using ParticleDataStack = corsika::stack::nuclear_extension::NuclearStackExtension<
corsika::stack::super_stupid::SuperStupidStack, ExtendedParticleInterfaceType>;
template <typename T>
using SetupGeometryDataInterface = GeometryDataInterface<T, setup::SetupEnvironment>;
// combine particle data stack with geometry information for tracking
template <typename StackIter>
using StackWithGeometryInterface =
corsika::stack::CombinedParticleInterface<ParticleDataStack::PIType,
SetupGeometryDataInterface, StackIter>;
using StackWithGeometry =
corsika::stack::CombinedStack<typename ParticleDataStack::StackImpl,
GeometryData<setup::SetupEnvironment>,
StackWithGeometryInterface>;
} // namespace detail
// this is the REAL stack we use:
using Stack = detail::StackWithGeometry;
/*
See Issue 161
unfortunately clang does not support this in the same way (yet) as
gcc, so we have to distinguish here. If clang cataches up, we
could remove the clang branch here and also in
corsika::Cascade. The gcc code is much more generic and
universal. If we could do the gcc version, we won't had to define
StackView globally, we could do it with MakeView whereever it is
actually needed. Keep an eye on this!
*/
#if defined(__clang__)
using StackView =
corsika::stack::SecondaryView<typename corsika::setup::Stack::StackImpl,
corsika::setup::detail::StackWithGeometryInterface>;
#elif defined(__GNUC__) || defined(__GNUG__)
using StackView = corsika::stack::MakeView<corsika::setup::Stack>::type;
#endif
} // namespace corsika::setup
/*
* (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
*
* This software is distributed under the terms of the GNU General Public
* Licence version 3 (GPL Version 3). See file LICENSE for a full version of
* the license.
*/
#pragma once
#include <corsika/geometry/Helix.h>
#include <corsika/geometry/Line.h>
#include <corsika/geometry/Trajectory.h>
#include <corsika/units/PhysicalUnits.h>
// #include <variant>
namespace corsika::setup {
/// definition of Trajectory base class, to be used in tracking and cascades
typedef corsika::geometry::Trajectory<corsika::geometry::Line> Trajectory;
/*
typedef std::variant<std::monostate, corsika::geometry::Trajectory<Line>,
corsika::geometry::Trajectory<Helix>>
Trajectory;
/// helper visitor to modify Particle by moving along Trajectory
template <typename Particle>
class ParticleUpdate {
Particle& fP;
public:
ParticleUpdate(Particle& p)
: fP(p) {}
void operator()(std::monostate const&) {}
template <typename T>
void operator()(T const& trajectory) {
fP.SetPosition(trajectory.GetPosition(1));
}
};
/// helper visitor to modify Particle by moving along Trajectory
class GetDuration {
public:
corsika::units::si::TimeType operator()(std::monostate const&) {
return 0 * corsika::units::si::second;
}
template <typename T>
corsika::units::si::TimeType operator()(T const& trajectory) {
return trajectory.GetDuration();
}
};
*/
} // namespace corsika::setup
add_subdirectory (DummyStack)
add_subdirectory (SuperStupidStack)
add_subdirectory (NuclearStackExtension)
set (DummyStack_HEADERS DummyStack.h)
set (DummyStack_NAMESPACE corsika/stack/dummy)
add_library (DummyStack INTERFACE)
CORSIKA_COPY_HEADERS_TO_NAMESPACE (DummyStack ${DummyStack_NAMESPACE} ${DummyStack_HEADERS})
target_link_libraries (
DummyStack
INTERFACE
CORSIKAstackinterface
CORSIKAunits
CORSIKAparticles
)
target_include_directories (
DummyStack
INTERFACE
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>
$<INSTALL_INTERFACE:include>
)
install (
FILES
${DummyStack_HEADERS}
DESTINATION
include/${DummyStack_NAMESPACE}
)
/*
* (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
*
* This software is distributed under the terms of the GNU General Public
* Licence version 3 (GPL Version 3). See file LICENSE for a full version of
* the license.
*/
#pragma once
#include <corsika/particles/ParticleProperties.h>
#include <corsika/stack/Stack.h>
#include <corsika/units/PhysicalUnits.h>
#include <string>
#include <vector>
namespace corsika::stack {
namespace dummy {
/**
* Example of a particle object on the stack.
*/
template <typename _Stack>
class ParticleRead : public StackIteratorInfo<_Stack, ParticleRead<_Stack> > {
using StackIteratorInfo<_Stack, ParticleRead>::GetIndex;
using StackIteratorInfo<_Stack, ParticleRead>::GetStack;
public:
};
/**
*
* Memory implementation of the most simple (stupid) particle stack object.
*/
class DummyStackImpl {
public:
void Init() {}
void Clear() {}
int GetSize() const { return 0; }
int GetCapacity() const { return 0; }
/**
* Function to copy particle at location i2 in stack to i1
*/
void Copy(const int i1, const int i2) {}
protected:
void IncrementSize() {}
void DecrementSize() {}
}; // end class DummyStackImpl
typedef StackIterator<DummyStackImpl, ParticleRead<DummyStackImpl> > Particle;
typedef Stack<DummyStackImpl, Particle> DummyStack;
} // namespace dummy
} // namespace corsika::stack
/*
* (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
*
* This software is distributed under the terms of the GNU General Public
* Licence version 3 (GPL Version 3). See file LICENSE for a full version of
* the license.
*/
#pragma once
#include <corsika/logging/Logging.h>
#include <corsika/stack/Stack.h>
#include <tuple>
#include <utility>
#include <vector>
namespace corsika::stack::node {
/**
* @class GeometryDataInterface
*
* corresponding defintion of a stack-readout object, the iteractor
* dereference operator will deliver access to these function
// defintion of a stack-readout object, the iteractor dereference
// operator will deliver access to these function
*/
template <typename T, typename TEnvType>
class GeometryDataInterface : public T {
protected:
using T::GetStack;
using T::GetStackData;
public:
using T::GetIndex;
using BaseNodeType = typename TEnvType::BaseNodeType;
public:
// default version for particle-creation from input data
void SetParticleData(const std::tuple<BaseNodeType const*> v) {
SetNode(std::get<0>(v));
}
void SetParticleData(GeometryDataInterface& parent,
const std::tuple<BaseNodeType const*>) {
SetNode(parent.GetNode()); // copy Node from parent particle!
}
void SetParticleData() { SetNode(nullptr); }
void SetParticleData(GeometryDataInterface& parent) {
SetNode(parent.GetNode()); // copy Node from parent particle!
}
std::string as_string() const { return fmt::format("node={}", fmt::ptr(GetNode())); }
void SetNode(BaseNodeType const* v) { GetStackData().SetNode(GetIndex(), v); }
BaseNodeType const* GetNode() const { return GetStackData().GetNode(GetIndex()); }
};
// definition of stack-data object to store geometry information
template <typename TEnvType>
/**
* @class GeometryData
*
* definition of stack-data object to store geometry information
*/
class GeometryData {
public:
using BaseNodeType = typename TEnvType::BaseNodeType;
// these functions are needed for the Stack interface
void Clear() { fNode.clear(); }
unsigned int GetSize() const { return fNode.size(); }
unsigned int GetCapacity() const { return fNode.size(); }
void Copy(const int i1, const int i2) { fNode[i2] = fNode[i1]; }
void Swap(const int i1, const int i2) { std::swap(fNode[i1], fNode[i2]); }
// custom data access function
void SetNode(const int i, BaseNodeType const* v) { fNode[i] = v; }
BaseNodeType const* GetNode(const int i) const { return fNode[i]; }
// these functions are also needed by the Stack interface
void IncrementSize() { fNode.push_back(nullptr); }
void DecrementSize() {
if (fNode.size() > 0) { fNode.pop_back(); }
}
// custom private data section
private:
std::vector<const BaseNodeType*> fNode;
};
template <typename T, typename TEnv>
struct MakeGeometryDataInterface {
typedef GeometryDataInterface<T, TEnv> type;
};
} // namespace corsika::stack::node
/*
* (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
*
* This software is distributed under the terms of the GNU General Public
* Licence version 3 (GPL Version 3). See file LICENSE for a full version of
* the license.
*/
#include <corsika/logging/Logging.h>
#include <corsika/history/HistoryObservationPlane.hpp>
#include <boost/histogram/ostream.hpp>
#include <fstream>
#include <iostream>
using namespace corsika::units::si;
using namespace corsika::history;
using namespace corsika;
HistoryObservationPlane::HistoryObservationPlane(setup::Stack const& stack,
geometry::Plane const& obsPlane,
bool deleteOnHit)
: stack_{stack}
, plane_{obsPlane}
, deleteOnHit_{deleteOnHit} {}
corsika::process::EProcessReturn HistoryObservationPlane::DoContinuous(
setup::Stack::ParticleType const& particle, setup::Trajectory const& trajectory) {
TimeType const timeOfIntersection =
(plane_.GetCenter() - trajectory.GetR0()).dot(plane_.GetNormal()) /
trajectory.GetV0().dot(plane_.GetNormal());
if (timeOfIntersection < TimeType::zero()) { return process::EProcessReturn::eOk; }
if (plane_.IsAbove(trajectory.GetR0()) == plane_.IsAbove(trajectory.GetPosition(1))) {
return process::EProcessReturn::eOk;
}
C8LOG_DEBUG(fmt::format("HistoryObservationPlane: Particle detected: pid={}",
particle.GetPID()));
auto const pid = particle.GetPID();
if (particles::IsMuon(pid)) { fillHistoryHistogram(particle); }
if (deleteOnHit_) {
return process::EProcessReturn::eParticleAbsorbed;
} else {
return process::EProcessReturn::eOk;
}
}
LengthType HistoryObservationPlane::MaxStepLength(setup::Stack::ParticleType const&,
setup::Trajectory const& trajectory) {
TimeType const timeOfIntersection =
(plane_.GetCenter() - trajectory.GetR0()).dot(plane_.GetNormal()) /
trajectory.GetV0().dot(plane_.GetNormal());
if (timeOfIntersection < TimeType::zero()) {
return std::numeric_limits<double>::infinity() * 1_m;
}
auto const pointOfIntersection = trajectory.GetPosition(timeOfIntersection);
return (trajectory.GetR0() - pointOfIntersection).norm() * 1.0001;
}
void HistoryObservationPlane::fillHistoryHistogram(
setup::Stack::ParticleType const& muon) {
// double const muonEnergy = muon.GetEnergy() / 1_eV;
// auto parent = stack_.begin() + muon.GetEvent()->projectileIndex();
Event* event = muon.GetEvent().get();
int intCounter = 0;
while (event) {
event = event->parentEvent().get();
intCounter++;
}
histogram_(intCounter);
}
void HistoryObservationPlane::print() { std::cout << histogram_ << std::endl; }
set (NuclearStackExtension_HEADERS NuclearStackExtension.h)
set (NuclearStackExtension_NAMESPACE corsika/stack/nuclear_extension)
add_library (NuclearStackExtension INTERFACE)
CORSIKA_COPY_HEADERS_TO_NAMESPACE (NuclearStackExtension ${NuclearStackExtension_NAMESPACE} ${NuclearStackExtension_HEADERS})
target_link_libraries (
NuclearStackExtension
INTERFACE
CORSIKAstackinterface
CORSIKAunits
CORSIKAparticles
CORSIKAgeometry
)
target_include_directories (
NuclearStackExtension
INTERFACE
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>
$<INSTALL_INTERFACE:include>
)
install (
FILES
${NuclearStackExtension_HEADERS}
DESTINATION
include/${NuclearStackExtension_NAMESPACE}
)
# ----------------
# code unit testing
CORSIKA_ADD_TEST(testNuclearStackExtension)
target_link_libraries (
testNuclearStackExtension
SuperStupidStack
NuclearStackExtension
CORSIKAparticles
CORSIKAgeometry
CORSIKAunits
CORSIKAtesting
)
/*
* (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
*
* This software is distributed under the terms of the GNU General Public
* Licence version 3 (GPL Version 3). See file LICENSE for a full version of
* the license.
*/
#pragma once
#include <corsika/particles/ParticleProperties.h>
#include <corsika/stack/Stack.h>
#include <corsika/units/PhysicalUnits.h>
#include <corsika/geometry/Point.h>
#include <corsika/geometry/Vector.h>
#include <algorithm>
#include <tuple>
#include <vector>
namespace corsika::stack {
/**
* @namespace nuclear_extension
*
* Add A and Z data to existing stack of particle properties.
*
* Only for Code::Nucleus particles A and Z are stored, not for all
* normal elementary particles.
*
* Thus in your code, make sure to always check <code>
* particle.GetPID()==Code::Nucleus </code> before attempting to
* read any nuclear information.
*
*
*/
typedef corsika::geometry::Vector<corsika::units::si::hepmomentum_d> MomentumVector;
namespace nuclear_extension {
/**
* @class NuclearParticleInterface
*
* Define ParticleInterface for NuclearStackExtension Stack derived from
* ParticleInterface of Inner stack class
*/
template <template <typename> typename InnerParticleInterface,
typename StackIteratorInterface>
class NuclearParticleInterface
: public InnerParticleInterface<StackIteratorInterface> {
protected:
using InnerParticleInterface<StackIteratorInterface>::GetStackData;
using InnerParticleInterface<StackIteratorInterface>::GetIndex;
public:
void SetParticleData(
const std::tuple<corsika::particles::Code, corsika::units::si::HEPEnergyType,
corsika::stack::MomentumVector, corsika::geometry::Point,
corsika::units::si::TimeType>& v) {
if (std::get<0>(v) == corsika::particles::Code::Nucleus) {
std::ostringstream err;
err << "NuclearStackExtension: no A and Z specified for new Nucleus!";
throw std::runtime_error(err.str());
}
InnerParticleInterface<StackIteratorInterface>::SetParticleData(v);
SetNucleusRef(-1); // this is not a nucleus
}
void SetParticleData(
const std::tuple<corsika::particles::Code, corsika::units::si::HEPEnergyType,
corsika::stack::MomentumVector, corsika::geometry::Point,
corsika::units::si::TimeType, unsigned short, unsigned short>&
v) {
const unsigned short A = std::get<5>(v);
const unsigned short Z = std::get<6>(v);
if (std::get<0>(v) != corsika::particles::Code::Nucleus || A == 0 || Z == 0) {
std::ostringstream err;
err << "NuclearStackExtension: no A and Z specified for new Nucleus!";
throw std::runtime_error(err.str());
}
SetNucleusRef(GetStackData().GetNucleusNextRef()); // store this nucleus data ref
SetNuclearA(A);
SetNuclearZ(Z);
InnerParticleInterface<StackIteratorInterface>::SetParticleData(
std::tuple<corsika::particles::Code, corsika::units::si::HEPEnergyType,
corsika::stack::MomentumVector, corsika::geometry::Point,
corsika::units::si::TimeType>{std::get<0>(v), std::get<1>(v),
std::get<2>(v), std::get<3>(v),
std::get<4>(v)});
}
void SetParticleData(
InnerParticleInterface<StackIteratorInterface>& p,
const std::tuple<corsika::particles::Code, corsika::units::si::HEPEnergyType,
corsika::stack::MomentumVector, corsika::geometry::Point,
corsika::units::si::TimeType>& v) {
if (std::get<0>(v) == corsika::particles::Code::Nucleus) {
std::ostringstream err;
err << "NuclearStackExtension: no A and Z specified for new Nucleus!";
throw std::runtime_error(err.str());
}
InnerParticleInterface<StackIteratorInterface>::SetParticleData(
p, std::tuple<corsika::particles::Code, corsika::units::si::HEPEnergyType,
corsika::stack::MomentumVector, corsika::geometry::Point,
corsika::units::si::TimeType>{std::get<0>(v), std::get<1>(v),
std::get<2>(v), std::get<3>(v),
std::get<4>(v)});
SetNucleusRef(-1); // this is not a nucleus
}
void SetParticleData(
InnerParticleInterface<StackIteratorInterface>& p,
const std::tuple<corsika::particles::Code, corsika::units::si::HEPEnergyType,
corsika::stack::MomentumVector, corsika::geometry::Point,
corsika::units::si::TimeType, unsigned short, unsigned short>&
v) {
const unsigned short A = std::get<5>(v);
const unsigned short Z = std::get<6>(v);
if (std::get<0>(v) != corsika::particles::Code::Nucleus || A == 0 || Z == 0) {
std::ostringstream err;
err << "NuclearStackExtension: no A and Z specified for new Nucleus!";
throw std::runtime_error(err.str());
}
SetNucleusRef(GetStackData().GetNucleusNextRef()); // store this nucleus data ref
SetNuclearA(A);
SetNuclearZ(Z);
InnerParticleInterface<StackIteratorInterface>::SetParticleData(
p, std::tuple<corsika::particles::Code, corsika::units::si::HEPEnergyType,
corsika::stack::MomentumVector, corsika::geometry::Point,
corsika::units::si::TimeType>{std::get<0>(v), std::get<1>(v),
std::get<2>(v), std::get<3>(v),
std::get<4>(v)});
}
/**
* @name individual setters
* @{
*/
void SetNuclearA(const unsigned short vA) {
GetStackData().SetNuclearA(GetIndex(), vA);
}
void SetNuclearZ(const unsigned short vZ) {
GetStackData().SetNuclearZ(GetIndex(), vZ);
}
/// @}
/**
* @name individual getters
* @{
*/
int GetNuclearA() const { return GetStackData().GetNuclearA(GetIndex()); }
int GetNuclearZ() const { return GetStackData().GetNuclearZ(GetIndex()); }
/// @}
/**
* Overwrite normal GetParticleMass function with nuclear version
*/
corsika::units::si::HEPMassType GetMass() const {
if (InnerParticleInterface<StackIteratorInterface>::GetPID() ==
corsika::particles::Code::Nucleus)
return corsika::particles::GetNucleusMass(GetNuclearA(), GetNuclearZ());
return InnerParticleInterface<StackIteratorInterface>::GetMass();
}
/**
* Overwirte normal GetChargeNumber function with nuclear version
**/
int16_t GetChargeNumber() const {
if (InnerParticleInterface<StackIteratorInterface>::GetPID() ==
corsika::particles::Code::Nucleus)
return GetNuclearZ();
return InnerParticleInterface<StackIteratorInterface>::GetChargeNumber();
}
int GetNucleusRef() const { return GetStackData().GetNucleusRef(GetIndex()); }
protected:
void SetNucleusRef(const int vR) { GetStackData().SetNucleusRef(GetIndex(), vR); }
};
/**
* @class NuclearStackExtension
*
* Memory implementation of adding nuclear inforamtion to the
* existing particle stack defined in class InnerStackImpl.
*
* Inside the NuclearStackExtension class there is a dedicated
* fNucleusRef index, where fNucleusRef[i] is referring to the
* correct A and Z for a specific particle index i. fNucleusRef[i]
* == -1 means that this is not a nucleus, and a subsequent call to
* GetNucleusA would produce an exception.
*/
template <typename InnerStackImpl>
class NuclearStackExtensionImpl : public InnerStackImpl {
public:
void Init() { InnerStackImpl::Init(); }
void Dump() { InnerStackImpl::Dump(); }
void Clear() {
InnerStackImpl::Clear();
fNucleusRef.clear();
fNuclearA.clear();
fNuclearZ.clear();
}
unsigned int GetSize() const { return fNucleusRef.size(); }
unsigned int GetCapacity() const { return fNucleusRef.capacity(); }
void SetNuclearA(const unsigned int i, const unsigned short vA) {
fNuclearA[GetNucleusRef(i)] = vA;
}
void SetNuclearZ(const unsigned int i, const unsigned short vZ) {
fNuclearZ[GetNucleusRef(i)] = vZ;
}
void SetNucleusRef(const unsigned int i, const int v) { fNucleusRef[i] = v; }
int GetNuclearA(const unsigned int i) const { return fNuclearA[GetNucleusRef(i)]; }
int GetNuclearZ(const unsigned int i) const { return fNuclearZ[GetNucleusRef(i)]; }
// this function will create new storage for Nuclear Properties, and return the
// reference to it
int GetNucleusNextRef() {
fNuclearA.push_back(0);
fNuclearZ.push_back(0);
return fNuclearA.size() - 1;
}
int GetNucleusRef(const unsigned int i) const {
if (fNucleusRef[i] >= 0) return fNucleusRef[i];
std::ostringstream err;
err << "NuclearStackExtension: no nucleus at ref=" << i;
throw std::runtime_error(err.str());
}
/**
* Function to copy particle at location i1 in stack to i2
*/
void Copy(const unsigned int i1, const unsigned int i2) {
// index range check
if (i1 >= GetSize() || i2 >= GetSize()) {
std::ostringstream err;
err << "NuclearStackExtension: trying to access data beyond size of stack!";
throw std::runtime_error(err.str());
}
// copy internal particle data p[i2] = p[i1]
InnerStackImpl::Copy(i1, i2);
// check if any of p[i1] or p[i2] was a Code::Nucleus
const int ref1 = fNucleusRef[i1];
const int ref2 = fNucleusRef[i2];
if (ref2 < 0) {
if (ref1 >= 0) {
// i1 is nucleus, i2 is not
fNucleusRef[i2] = GetNucleusNextRef();
fNuclearA[fNucleusRef[i2]] = fNuclearA[ref1];
fNuclearZ[fNucleusRef[i2]] = fNuclearZ[ref1];
} else {
// neither i1 nor i2 are nuclei
}
} else {
if (ref1 >= 0) {
// both are nuclei, i2 is overwritten with nucleus i1
// fNucleusRef stays the same, but A and Z data is overwritten
fNuclearA[ref2] = fNuclearA[ref1];
fNuclearZ[ref2] = fNuclearZ[ref1];
} else {
// i2 is overwritten with non-nucleus i1
fNucleusRef[i2] = -1; // flag as non-nucleus
fNuclearA.erase(fNuclearA.cbegin() + ref2); // remove data for i2
fNuclearZ.erase(fNuclearZ.cbegin() + ref2); // remove data for i2
const int n = fNucleusRef.size(); // update fNucleusRef: indices above ref2
// must be decremented by 1
for (int i = 0; i < n; ++i) {
if (fNucleusRef[i] > ref2) { fNucleusRef[i] -= 1; }
}
}
}
}
/**
* Function to copy particle at location i2 in stack to i1
*/
void Swap(const unsigned int i1, const unsigned int i2) {
// index range check
if (i1 >= GetSize() || i2 >= GetSize()) {
std::ostringstream err;
err << "NuclearStackExtension: trying to access data beyond size of stack!";
throw std::runtime_error(err.str());
}
// swap original particle data
InnerStackImpl::Swap(i1, i2);
// swap corresponding nuclear reference data
std::swap(fNucleusRef[i2], fNucleusRef[i1]);
}
void IncrementSize() {
InnerStackImpl::IncrementSize();
fNucleusRef.push_back(-1);
}
void DecrementSize() {
InnerStackImpl::DecrementSize();
if (fNucleusRef.size() > 0) {
const int ref = fNucleusRef.back();
fNucleusRef.pop_back();
if (ref >= 0) {
fNuclearA.erase(fNuclearA.begin() + ref);
fNuclearZ.erase(fNuclearZ.begin() + ref);
const int n = fNucleusRef.size();
for (int i = 0; i < n; ++i) {
if (fNucleusRef[i] >= ref) { fNucleusRef[i] -= 1; }
}
}
}
}
private:
/// the actual memory to store particle data
std::vector<int> fNucleusRef;
std::vector<unsigned short> fNuclearA;
std::vector<unsigned short> fNuclearZ;
}; // end class NuclearStackExtensionImpl
// template<typename StackIteratorInterface>
// using NuclearParticleInterfaceType<StackIteratorInterface> =
// NuclearParticleInterface< ,StackIteratorInterface>
// works, but requires stupd _PI class
// template<typename SS> using TEST =
// NuclearParticleInterface<corsika::stack::super_stupid::SuperStupidStack::PIType,
// SS>;
template <typename InnerStack, template <typename> typename _PI>
using NuclearStackExtension =
Stack<NuclearStackExtensionImpl<typename InnerStack::StackImpl>, _PI>;
// ----
// I'm dont't manage to do this properly.......
/*
template<typename TT, typename SS> using TESTi = typename
NuclearParticleInterface<TT::template PIType, SS>::ExtendedParticleInterface;
template<typename TT, typename SS> using TEST1 = TESTi<TT, SS>;
template<typename SS> using TEST2 = TEST1<typename
corsika::stack::super_stupid::SuperStupidStack, SS>;
using NuclearStackExtension = Stack<NuclearStackExtensionImpl<typename
InnerStack::StackImpl>, TEST2>;
*/
/*
// .... this should be fixed ....
template <typename InnerStack, typename SS=StackIteratorInterface>
//using NuclearStackExtension = Stack<NuclearStackExtensionImpl<typename
InnerStack::StackImpl>, NuclearParticleInterface<typename InnerStack::template PIType,
StackIteratorInterface>::ExtendedParticleInterface>; using NuclearStackExtension =
Stack<NuclearStackExtensionImpl<typename InnerStack::StackImpl>, TEST1<typename
corsika::stack::super_stupid::SuperStupidStack, SS> >;
//template <typename InnerStack>
// using NuclearStackExtension = Stack<NuclearStackExtensionImpl<typename
InnerStack::StackImpl>, TEST<typename
corsika::stack::super_stupid::SuperStupidStack::PIType>>;
//using NuclearStackExtension = Stack<NuclearStackExtensionImpl<typename
InnerStack::StackImpl>, TEST>;
*/
} // namespace nuclear_extension
} // namespace corsika::stack
/*
* (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
*
* This software is distributed under the terms of the GNU General Public
* Licence version 3 (GPL Version 3). See file LICENSE for a full version of
* the license.
*/
#include <corsika/geometry/RootCoordinateSystem.h>
#include <corsika/stack/nuclear_extension/NuclearStackExtension.h>
#include <corsika/stack/super_stupid/SuperStupidStack.h>
#include <corsika/units/PhysicalUnits.h>
using namespace corsika;
using namespace corsika::stack::nuclear_extension;
using namespace corsika::geometry;
using namespace corsika::units::si;
#include <catch2/catch.hpp>
// this is an auxiliary help typedef, which I don't know how to put
// into NuclearStackExtension.h where it belongs...
template <typename StackIter>
using ExtendedParticleInterfaceType =
corsika::stack::nuclear_extension::NuclearParticleInterface<
corsika::stack::super_stupid::SuperStupidStack::template PIType, StackIter>;
using ExtStack = NuclearStackExtension<corsika::stack::super_stupid::SuperStupidStack,
ExtendedParticleInterfaceType>;
#include <iostream>
using namespace std;
TEST_CASE("NuclearStackExtension", "[stack]") {
geometry::CoordinateSystem& dummyCS =
geometry::RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
SECTION("write non nucleus") {
NuclearStackExtension<corsika::stack::super_stupid::SuperStupidStack,
ExtendedParticleInterfaceType>
s;
s.AddParticle(
std::tuple<particles::Code, units::si::HEPEnergyType,
corsika::stack::MomentumVector, geometry::Point, units::si::TimeType>{
particles::Code::Electron, 1.5_GeV,
corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s});
REQUIRE(s.GetSize() == 1);
}
SECTION("write nucleus") {
NuclearStackExtension<corsika::stack::super_stupid::SuperStupidStack,
ExtendedParticleInterfaceType>
s;
s.AddParticle(std::tuple<particles::Code, units::si::HEPEnergyType,
corsika::stack::MomentumVector, geometry::Point,
units::si::TimeType, unsigned short, unsigned short>{
particles::Code::Nucleus, 1.5_GeV,
corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, 10, 10});
REQUIRE(s.GetSize() == 1);
}
SECTION("write invalid nucleus") {
ExtStack s;
REQUIRE_THROWS(
s.AddParticle(std::tuple<particles::Code, units::si::HEPEnergyType,
corsika::stack::MomentumVector, geometry::Point,
units::si::TimeType, unsigned short, unsigned short>{
particles::Code::Nucleus, 1.5_GeV,
corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, 0, 0}));
}
SECTION("read non nucleus") {
ExtStack s;
s.AddParticle(
std::tuple<particles::Code, units::si::HEPEnergyType,
corsika::stack::MomentumVector, geometry::Point, units::si::TimeType>{
particles::Code::Electron, 1.5_GeV,
corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s});
const auto pout = s.GetNextParticle();
REQUIRE(pout.GetPID() == particles::Code::Electron);
REQUIRE(pout.GetEnergy() == 1.5_GeV);
REQUIRE(pout.GetTime() == 100_s);
}
SECTION("read nucleus") {
ExtStack s;
s.AddParticle(std::tuple<particles::Code, units::si::HEPEnergyType,
corsika::stack::MomentumVector, geometry::Point,
units::si::TimeType, unsigned short, unsigned short>{
particles::Code::Nucleus, 1.5_GeV,
corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, 10, 9});
const auto pout = s.GetNextParticle();
REQUIRE(pout.GetPID() == particles::Code::Nucleus);
REQUIRE(pout.GetEnergy() == 1.5_GeV);
REQUIRE(pout.GetTime() == 100_s);
REQUIRE(pout.GetNuclearA() == 10);
REQUIRE(pout.GetNuclearZ() == 9);
}
SECTION("read invalid nucleus") {
ExtStack s;
s.AddParticle(
std::tuple<particles::Code, units::si::HEPEnergyType,
corsika::stack::MomentumVector, geometry::Point, units::si::TimeType>{
particles::Code::Electron, 1.5_GeV,
corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s});
const auto pout = s.GetNextParticle();
REQUIRE_THROWS(pout.GetNuclearA());
REQUIRE_THROWS(pout.GetNuclearZ());
}
SECTION("stack fill and cleanup") {
ExtStack s;
// add 99 particles, each 10th particle is a nucleus with A=i and Z=A/2!
for (int i = 0; i < 99; ++i) {
if ((i + 1) % 10 == 0) {
s.AddParticle(std::tuple<particles::Code, units::si::HEPEnergyType,
corsika::stack::MomentumVector, geometry::Point,
units::si::TimeType, unsigned short, unsigned short>{
particles::Code::Nucleus, 1.5_GeV,
corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, i, i / 2});
} else {
s.AddParticle(std::tuple<particles::Code, units::si::HEPEnergyType,
corsika::stack::MomentumVector, geometry::Point,
units::si::TimeType>{
particles::Code::Electron, 1.5_GeV,
corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s});
}
}
REQUIRE(s.GetSize() == 99);
for (int i = 0; i < 99; ++i) s.GetNextParticle().Delete();
REQUIRE(s.GetSize() == 0);
}
SECTION("stack operations") {
ExtStack s;
// add 99 particles, each 10th particle is a nucleus with A=i and Z=A/2!
for (int i = 0; i < 99; ++i) {
if ((i + 1) % 10 == 0) {
s.AddParticle(std::tuple<particles::Code, units::si::HEPEnergyType,
corsika::stack::MomentumVector, geometry::Point,
units::si::TimeType, unsigned short, unsigned short>{
particles::Code::Nucleus, i * 15_GeV,
corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, i, i / 2});
} else {
s.AddParticle(std::tuple<particles::Code, units::si::HEPEnergyType,
corsika::stack::MomentumVector, geometry::Point,
units::si::TimeType>{
particles::Code::Electron, i * 1.5_GeV,
corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s});
}
}
// copy
{
s.Copy(s.begin() + 9, s.begin() + 10); // nuclei to non-nuclei
const auto& p9 = s.cbegin() + 9;
const auto& p10 = s.cbegin() + 10;
REQUIRE(p9.GetPID() == particles::Code::Nucleus);
REQUIRE(p9.GetEnergy() == 9 * 15_GeV);
REQUIRE(p9.GetTime() == 100_s);
REQUIRE(p9.GetNuclearA() == 9);
REQUIRE(p9.GetNuclearZ() == 9 / 2);
REQUIRE(p10.GetPID() == particles::Code::Nucleus);
REQUIRE(p10.GetEnergy() == 9 * 15_GeV);
REQUIRE(p10.GetTime() == 100_s);
REQUIRE(p10.GetNuclearA() == 9);
REQUIRE(p10.GetNuclearZ() == 9 / 2);
}
// copy
{
s.Copy(s.begin() + 93, s.begin() + 9); // non-nuclei to nuclei
const auto& p93 = s.cbegin() + 93;
const auto& p9 = s.cbegin() + 9;
REQUIRE(p9.GetPID() == particles::Code::Electron);
REQUIRE(p9.GetEnergy() == 93 * 1.5_GeV);
REQUIRE(p9.GetTime() == 100_s);
REQUIRE(p93.GetPID() == particles::Code::Electron);
REQUIRE(p93.GetEnergy() == 93 * 1.5_GeV);
REQUIRE(p93.GetTime() == 100_s);
}
// swap
{
s.Swap(s.begin() + 11, s.begin() + 10);
const auto& p11 = s.cbegin() + 11; // now: nucleus
const auto& p10 = s.cbegin() + 10; // now: electron
REQUIRE(p11.GetPID() == particles::Code::Nucleus);
REQUIRE(p11.GetEnergy() == 9 * 15_GeV);
REQUIRE(p11.GetTime() == 100_s);
REQUIRE(p11.GetNuclearA() == 9);
REQUIRE(p11.GetNuclearZ() == 9 / 2);
REQUIRE(p10.GetPID() == particles::Code::Electron);
REQUIRE(p10.GetEnergy() == 11 * 1.5_GeV);
REQUIRE(p10.GetTime() == 100_s);
}
// swap two nuclei
{
s.Swap(s.begin() + 29, s.begin() + 59);
const auto& p29 = s.cbegin() + 29;
const auto& p59 = s.cbegin() + 59;
REQUIRE(p29.GetPID() == particles::Code::Nucleus);
REQUIRE(p29.GetEnergy() == 59 * 15_GeV);
REQUIRE(p29.GetTime() == 100_s);
REQUIRE(p29.GetNuclearA() == 59);
REQUIRE(p29.GetNuclearZ() == 59 / 2);
REQUIRE(p59.GetPID() == particles::Code::Nucleus);
REQUIRE(p59.GetEnergy() == 29 * 15_GeV);
REQUIRE(p59.GetTime() == 100_s);
REQUIRE(p59.GetNuclearA() == 29);
REQUIRE(p59.GetNuclearZ() == 29 / 2);
}
for (int i = 0; i < 99; ++i) s.DeleteLast();
REQUIRE(s.GetSize() == 0);
}
}
set (SuperStupidStack_HEADERS SuperStupidStack.h)
set (SuperStupidStack_NAMESPACE corsika/stack/super_stupid)
add_library (SuperStupidStack INTERFACE)
CORSIKA_COPY_HEADERS_TO_NAMESPACE (SuperStupidStack ${SuperStupidStack_NAMESPACE} ${SuperStupidStack_HEADERS})
target_link_libraries (
SuperStupidStack
INTERFACE
CORSIKAstackinterface
CORSIKAunits
CORSIKAparticles
CORSIKAgeometry
)
target_include_directories (
SuperStupidStack
INTERFACE
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>
$<INSTALL_INTERFACE:include>
)
install (
FILES
${SuperStupidStack_HEADERS}
DESTINATION
include/${SuperStupidStack_NAMESPACE}
)
# ----------------
# code unit testing
CORSIKA_ADD_TEST(testSuperStupidStack)
target_link_libraries (
testSuperStupidStack
CORSIKAgeometry
CORSIKAparticles
CORSIKAunits
CORSIKAtesting
)
/*
* (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
*
* This software is distributed under the terms of the GNU General Public
* Licence version 3 (GPL Version 3). See file LICENSE for a full version of
* the license.
*/
#pragma once
#include <corsika/particles/ParticleProperties.h>
#include <corsika/stack/Stack.h>
#include <corsika/units/PhysicalUnits.h>
#include <corsika/geometry/Point.h>
#include <corsika/geometry/RootCoordinateSystem.h> // remove
#include <corsika/geometry/Vector.h>
#include <algorithm>
#include <vector>
namespace corsika::stack {
typedef corsika::geometry::Vector<corsika::units::si::hepmomentum_d> MomentumVector;
namespace super_stupid {
/**
* Example of a particle object on the stack.
*/
template <typename StackIteratorInterface>
class ParticleInterface : public ParticleBase<StackIteratorInterface> {
protected:
using corsika::stack::ParticleBase<StackIteratorInterface>::GetStack;
using corsika::stack::ParticleBase<StackIteratorInterface>::GetStackData;
public:
using corsika::stack::ParticleBase<StackIteratorInterface>::GetIndex;
public:
void SetParticleData(
const std::tuple<corsika::particles::Code, corsika::units::si::HEPEnergyType,
MomentumVector, corsika::geometry::Point,
corsika::units::si::TimeType>& v) {
SetPID(std::get<0>(v));
SetEnergy(std::get<1>(v));
SetMomentum(std::get<2>(v));
SetPosition(std::get<3>(v));
SetTime(std::get<4>(v));
}
/*
void SetParticleData(const corsika::particles::Code vDataPID,
const corsika::units::si::HEPEnergyType vDataE,
const MomentumVector& vMomentum,
const corsika::geometry::Point& vPosition,
const corsika::units::si::TimeType vTime) {
}*/
void SetParticleData(
ParticleInterface<StackIteratorInterface>&,
const std::tuple<corsika::particles::Code, corsika::units::si::HEPEnergyType,
MomentumVector, corsika::geometry::Point,
corsika::units::si::TimeType>& v) {
SetPID(std::get<0>(v));
SetEnergy(std::get<1>(v));
SetMomentum(std::get<2>(v));
SetPosition(std::get<3>(v));
SetTime(std::get<4>(v));
}
/* void SetParticleData(ParticleInterface<StackIteratorInterface>&,
const corsika::particles::Code vDataPID,
const corsika::units::si::HEPEnergyType vDataE,
const MomentumVector& vMomentum,
const corsika::geometry::Point& vPosition,
const corsika::units::si::TimeType vTime) {
SetPID(vDataPID);
SetEnergy(vDataE);
SetMomentum(vMomentum);
SetPosition(vPosition);
SetTime(vTime);
}*/
/// individual setters
void SetPID(const corsika::particles::Code id) {
GetStackData().SetPID(GetIndex(), id);
}
void SetEnergy(const corsika::units::si::HEPEnergyType& e) {
GetStackData().SetEnergy(GetIndex(), e);
}
void SetMomentum(const MomentumVector& v) {
GetStackData().SetMomentum(GetIndex(), v);
}
void SetPosition(const corsika::geometry::Point& v) {
GetStackData().SetPosition(GetIndex(), v);
}
void SetTime(const corsika::units::si::TimeType& v) {
GetStackData().SetTime(GetIndex(), v);
}
/// individual getters
corsika::particles::Code GetPID() const {
return GetStackData().GetPID(GetIndex());
}
corsika::units::si::HEPEnergyType GetEnergy() const {
return GetStackData().GetEnergy(GetIndex());
}
MomentumVector GetMomentum() const {
return GetStackData().GetMomentum(GetIndex());
}
corsika::geometry::Point GetPosition() const {
return GetStackData().GetPosition(GetIndex());
}
corsika::units::si::TimeType GetTime() const {
return GetStackData().GetTime(GetIndex());
}
/**
* @name derived quantities
*
* @{
*/
corsika::geometry::Vector<corsika::units::si::dimensionless_d> GetDirection()
const {
return GetMomentum() / GetEnergy();
}
corsika::units::si::HEPMassType GetMass() const {
return corsika::particles::GetMass(GetPID());
}
int16_t GetChargeNumber() const {
return corsika::particles::GetChargeNumber(GetPID());
}
///@}
};
/**
* Memory implementation of the most simple (stupid) particle stack object.
*/
class SuperStupidStackImpl {
public:
void Init() {}
void Dump() const {}
void Clear() {
fDataPID.clear();
fDataE.clear();
fMomentum.clear();
fPosition.clear();
fTime.clear();
}
unsigned int GetSize() const { return fDataPID.size(); }
unsigned int GetCapacity() const { return fDataPID.size(); }
void SetPID(const unsigned int i, const corsika::particles::Code id) {
fDataPID[i] = id;
}
void SetEnergy(const unsigned int i, const corsika::units::si::HEPEnergyType e) {
fDataE[i] = e;
}
void SetMomentum(const unsigned int i, const MomentumVector& v) {
fMomentum[i] = v;
}
void SetPosition(const unsigned int i, const corsika::geometry::Point& v) {
fPosition[i] = v;
}
void SetTime(const unsigned int i, const corsika::units::si::TimeType& v) {
fTime[i] = v;
}
corsika::particles::Code GetPID(const unsigned int i) const { return fDataPID[i]; }
corsika::units::si::HEPEnergyType GetEnergy(const unsigned int i) const {
return fDataE[i];
}
MomentumVector GetMomentum(const unsigned int i) const { return fMomentum[i]; }
corsika::geometry::Point GetPosition(const unsigned int i) const {
return fPosition[i];
}
corsika::units::si::TimeType GetTime(const unsigned int i) const {
return fTime[i];
}
/**
* Function to copy particle at location i2 in stack to i1
*/
void Copy(const unsigned int i1, const unsigned int i2) {
fDataPID[i2] = fDataPID[i1];
fDataE[i2] = fDataE[i1];
fMomentum[i2] = fMomentum[i1];
fPosition[i2] = fPosition[i1];
fTime[i2] = fTime[i1];
}
/**
* Function to copy particle at location i2 in stack to i1
*/
void Swap(const unsigned int i1, const unsigned int i2) {
std::swap(fDataPID[i2], fDataPID[i1]);
std::swap(fDataE[i2], fDataE[i1]);
std::swap(fMomentum[i2], fMomentum[i1]);
std::swap(fPosition[i2], fPosition[i1]);
std::swap(fTime[i2], fTime[i1]);
}
void IncrementSize() {
using corsika::geometry::Point;
using corsika::particles::Code;
fDataPID.push_back(Code::Unknown);
fDataE.push_back(0 * corsika::units::si::electronvolt);
geometry::CoordinateSystem& dummyCS =
geometry::RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
fMomentum.push_back(MomentumVector(
dummyCS,
{0 * corsika::units::si::electronvolt, 0 * corsika::units::si::electronvolt,
0 * corsika::units::si::electronvolt}));
fPosition.push_back(
Point(dummyCS, {0 * corsika::units::si::meter, 0 * corsika::units::si::meter,
0 * corsika::units::si::meter}));
fTime.push_back(0 * corsika::units::si::second);
}
void DecrementSize() {
if (fDataE.size() > 0) {
fDataPID.pop_back();
fDataE.pop_back();
fMomentum.pop_back();
fPosition.pop_back();
fTime.pop_back();
}
}
private:
/// the actual memory to store particle data
std::vector<corsika::particles::Code> fDataPID;
std::vector<corsika::units::si::HEPEnergyType> fDataE;
std::vector<MomentumVector> fMomentum;
std::vector<corsika::geometry::Point> fPosition;
std::vector<corsika::units::si::TimeType> fTime;
}; // end class SuperStupidStackImpl
typedef Stack<SuperStupidStackImpl, ParticleInterface> SuperStupidStack;
} // namespace super_stupid
} // namespace corsika::stack
/*
* (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
*
* This software is distributed under the terms of the GNU General Public
* Licence version 3 (GPL Version 3). See file LICENSE for a full version of
* the license.
*/
#include <corsika/geometry/RootCoordinateSystem.h>
#include <corsika/stack/super_stupid/SuperStupidStack.h>
#include <corsika/units/PhysicalUnits.h>
using namespace corsika::geometry;
using namespace corsika::units::si;
#include <catch2/catch.hpp>
using namespace corsika;
using namespace corsika::stack::super_stupid;
#include <iostream>
using namespace std;
TEST_CASE("SuperStupidStack", "[stack]") {
geometry::CoordinateSystem& dummyCS =
geometry::RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
SECTION("read+write") {
SuperStupidStack s;
s.AddParticle(std::tuple<corsika::particles::Code, corsika::units::si::HEPEnergyType,
corsika::stack::MomentumVector, corsika::geometry::Point,
corsika::units::si::TimeType>{
particles::Code::Electron, 1.5_GeV,
corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s});
// read
REQUIRE(s.GetSize() == 1);
auto pout = s.GetNextParticle();
REQUIRE(pout.GetPID() == particles::Code::Electron);
REQUIRE(pout.GetEnergy() == 1.5_GeV);
// REQUIRE(pout.GetMomentum() == stack::MomentumVector(dummyCS, {1_GeV,
// 1_GeV, 1_GeV})); REQUIRE(pout.GetPosition() == Point(dummyCS, {1 * meter, 1 *
// meter, 1 * meter}));
REQUIRE(pout.GetTime() == 100_s);
}
SECTION("write+delete") {
SuperStupidStack s;
for (int i = 0; i < 99; ++i)
s.AddParticle(
std::tuple<corsika::particles::Code, corsika::units::si::HEPEnergyType,
corsika::stack::MomentumVector, corsika::geometry::Point,
corsika::units::si::TimeType>{
particles::Code::Electron, 1.5_GeV,
corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}),
Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s});
REQUIRE(s.GetSize() == 99);
for (int i = 0; i < 99; ++i) s.GetNextParticle().Delete();
REQUIRE(s.GetSize() == 0);
}
}