From f551ac31d3a77cd3ca03b6037d57d2e9d3b49c69 Mon Sep 17 00:00:00 2001 From: Alan Coleman <alanco@umich.edu> Date: Thu, 7 Dec 2023 11:25:29 +0000 Subject: [PATCH] Resolve "synchronize output format between examples" --- CMakeLists.txt | 7 + README.md | 30 +- applications/CMakeLists.txt | 13 + applications/README.md | 7 + .../c8_air_shower.cpp | 68 ++--- .../process/SwitchProcessSequence.inl | 16 +- .../modules/energy_loss/BetheBlochPDG.inl | 4 +- .../modules/proposal/ContinuousProcess.inl | 4 +- .../modules/proposal/InteractionModel.inl | 3 +- .../modules/proposal/ProposalProcessBase.inl | 2 +- corsika/detail/modules/radio/RadioProcess.inl | 5 +- corsika/modules/Random.hpp | 2 +- corsika/modules/writers/EnergyLossWriter.hpp | 2 +- .../modules/writers/LongitudinalWriter.hpp | 4 +- corsika/modules/writers/WriterOff.hpp | 2 +- examples/CMakeLists.txt | 128 ++++---- examples/README.md | 9 + examples/cascade_example.cpp | 158 ---------- examples/{ => cascade_examples}/em_shower.cpp | 96 +++--- examples/{ => cascade_examples}/mars.cpp | 68 +++-- .../mc_conex.cpp} | 150 ++++----- .../radio_em_shower.cpp | 199 ++++++------ examples/{ => cascade_examples}/water.cpp | 142 +++++---- examples/cascade_proton_example.cpp | 147 --------- .../boundary_crossing.cpp} | 10 +- .../{ => framework_examples}/environment.cpp | 0 .../geometry.cpp} | 0 .../helix_trajectory.cpp} | 0 .../known_particles.cpp} | 11 +- .../stack.cpp} | 0 .../static_sequence.cpp} | 2 +- .../{ => physics_examples}/stopping_power.cpp | 9 +- .../synchrotron_clover_leaf.cpp} | 22 +- .../synchrotron_test_C8tracking.cpp | 0 .../synchrotron_test_manual_tracking.cpp | 0 examples/vertical_EAS.cpp | 286 ------------------ 36 files changed, 566 insertions(+), 1040 deletions(-) create mode 100644 applications/CMakeLists.txt create mode 100644 applications/README.md rename examples/corsika.cpp => applications/c8_air_shower.cpp (92%) create mode 100644 examples/README.md delete mode 100644 examples/cascade_example.cpp rename examples/{ => cascade_examples}/em_shower.cpp (74%) rename examples/{ => cascade_examples}/mars.cpp (88%) rename examples/{hybrid_MC.cpp => cascade_examples/mc_conex.cpp} (81%) rename examples/{ => cascade_examples}/radio_em_shower.cpp (58%) rename examples/{ => cascade_examples}/water.cpp (72%) delete mode 100644 examples/cascade_proton_example.cpp rename examples/{boundary_example.cpp => framework_examples/boundary_crossing.cpp} (94%) rename examples/{ => framework_examples}/environment.cpp (100%) rename examples/{geometry_example.cpp => framework_examples/geometry.cpp} (100%) rename examples/{helix_example.cpp => framework_examples/helix_trajectory.cpp} (100%) rename examples/{particle_list_example.cpp => framework_examples/known_particles.cpp} (85%) rename examples/{stack_example.cpp => framework_examples/stack.cpp} (100%) rename examples/{staticsequence_example.cpp => framework_examples/static_sequence.cpp} (99%) rename examples/{ => physics_examples}/stopping_power.cpp (92%) rename examples/{clover_leaf.cpp => physics_examples/synchrotron_clover_leaf.cpp} (90%) rename examples/{ => physics_examples}/synchrotron_test_C8tracking.cpp (100%) rename examples/{ => physics_examples}/synchrotron_test_manual_tracking.cpp (100%) delete mode 100644 examples/vertical_EAS.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 29ebd5356..65b91e2a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -262,6 +262,13 @@ add_subdirectory (modules/conex) add_subdirectory (modules/epos) add_subdirectory (modules/fluka) +# +#+++++++++++++++++++++++++++++++ +# standard applications +# + +add_subdirectory(applications) + #+++++++++++++++++++++++++++++++ # unit testing # diff --git a/README.md b/README.md index 506ac4d93..105f090a6 100644 --- a/README.md +++ b/README.md @@ -102,8 +102,6 @@ make install ### FLUKA support -Warning: may only work when the next version of FLUKA is released (as of 2023.06.15) - For legal reasons we do not distribute/bundle FLUKA together with CORSIKA 8. If you want to use FLUKA as low-energy hadronic interaction model, you have to download it separately from (http://www.fluka.org/), which requires registering there as FLUKA user. @@ -142,22 +140,40 @@ make install To run the Unit Tests, just type `ctest` in your build area. -## Running examples +## 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 -From your top corsika build directory, (the one that includes `corsika-build` and `corsika-install`) type +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 cmake -Dcorsika_DIR=$PWD/corsika-build -S ./corsika/examples -B ./corsika-build-examples cd corsika-build-examples make -j4 #The number should match the number of available cores on your machine ``` -From any directory, run the program `corsika-build-examples/bin/corsika`. As an example, you can run with the following flags: +You can run the examples by using the binaries in `corsika-build-examples/bin/`. +For example: ```shell -corsika-build-examples/bin/corsika --pdg 2212 -E 1e5 -f my_shower +corsika-build-examples/bin/known_particles ``` -This will run a vertical 100 TeV proton shower and will create and put the output into `./my_shower`. +This will print out all of the particles that are known by CORSIKA. ### Generating doxygen documentation diff --git a/applications/CMakeLists.txt b/applications/CMakeLists.txt new file mode 100644 index 000000000..27dac14b5 --- /dev/null +++ b/applications/CMakeLists.txt @@ -0,0 +1,13 @@ +SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") + +if(WITH_FLUKA) + message("compiling c8_air_shower.cpp with FLUKA") +else() + message("compiling c8_air_shower.cpp with UrQMD") +endif() +add_executable (c8_air_shower c8_air_shower.cpp) +target_link_libraries (c8_air_shower CORSIKA8) + +install ( + TARGETS c8_air_shower DESTINATION bin +) diff --git a/applications/README.md b/applications/README.md new file mode 100644 index 000000000..24b892df2 --- /dev/null +++ b/applications/README.md @@ -0,0 +1,7 @@ +# 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. diff --git a/examples/corsika.cpp b/applications/c8_air_shower.cpp similarity index 92% rename from examples/corsika.cpp rename to applications/c8_air_shower.cpp index df5547107..fd7b02538 100644 --- a/examples/corsika.cpp +++ b/applications/c8_air_shower.cpp @@ -20,7 +20,6 @@ #include <corsika/framework/geometry/Plane.hpp> #include <corsika/framework/geometry/Sphere.hpp> #include <corsika/framework/process/DynamicInteractionProcess.hpp> -#include <corsika/framework/process/InteractionCounter.hpp> #include <corsika/framework/process/ProcessSequence.hpp> #include <corsika/framework/process/SwitchProcessSequence.hpp> #include <corsika/framework/random/RNGManager.hpp> @@ -35,7 +34,6 @@ #include <corsika/media/CORSIKA7Atmospheres.hpp> #include <corsika/media/Environment.hpp> -#include <corsika/media/FlatExponential.hpp> #include <corsika/media/GeomagneticModel.hpp> #include <corsika/media/GladstoneDaleRefractiveIndex.hpp> #include <corsika/media/HomogeneousMedium.hpp> @@ -50,7 +48,6 @@ #include <corsika/modules/Epos.hpp> #include <corsika/modules/LongitudinalProfile.hpp> #include <corsika/modules/ObservationPlane.hpp> -#include <corsika/modules/OnShellCheck.hpp> #include <corsika/modules/PROPOSAL.hpp> #include <corsika/modules/ParticleCut.hpp> #include <corsika/modules/Pythia8.hpp> @@ -94,8 +91,17 @@ using namespace std; using EnvironmentInterface = IRefractiveIndexModel<IMediumPropertyModel<IMagneticFieldModel<IMediumModel>>>; using EnvType = Environment<EnvironmentInterface>; - -using Particle = setup::Stack<EnvType>::particle_type; +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"); @@ -111,9 +117,9 @@ long registerRandomStreams(long seed) { if (seed == 0) { std::random_device rd; seed = rd(); - std::cout << "random seed (auto) " << seed << std::endl; + CORSIKA_LOG_INFO("random seed (auto) {}", seed); } else { - std::cout << "random seed " << seed << std::endl; + CORSIKA_LOG_INFO("random seed {}", seed); } RNGManager<>::getInstance().setSeed(seed); return seed; @@ -346,6 +352,8 @@ int main(int argc, char** argv) { // 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 + uint const nAxisBins = showerAxis.getMaximumX() / dX + 1; // Get maximum number of bins /* === END: CONSTRUCT GEOMETRY === */ double const emthinfrac = app["--emthin"]->as<double>(); @@ -364,22 +372,22 @@ int main(int argc, char** argv) { OutputManager output(app["--filename"]->as<std::string>(), seed, args.str(), outputDir); // register energy losses as output - EnergyLossWriter dEdX{showerAxis, 10_g / square(1_cm), 200}; + EnergyLossWriter dEdX{showerAxis, dX, nAxisBins}; output.add("energyloss", dEdX); - DynamicInteractionProcess<setup::Stack<EnvType>> heModel; + DynamicInteractionProcess<StackType> heModel; // have SIBYLL always for PROPOSAL photo-hadronic interactions auto sibyll = std::make_shared<corsika::sibyll::Interaction>(env); if (auto const modelStr = app["--hadronModel"]->as<std::string>(); modelStr == "SIBYLL-2.3d") { - heModel = DynamicInteractionProcess<setup::Stack<EnvType>>{sibyll}; + heModel = DynamicInteractionProcess<StackType>{sibyll}; } else if (modelStr == "QGSJet-II.04") { - heModel = DynamicInteractionProcess<setup::Stack<EnvType>>{ + heModel = DynamicInteractionProcess<StackType>{ std::make_shared<corsika::qgsjetII::Interaction>()}; } else if (modelStr == "EPOS-LHC") { - heModel = DynamicInteractionProcess<setup::Stack<EnvType>>{ + heModel = DynamicInteractionProcess<StackType>{ std::make_shared<corsika::epos::Interaction>()}; } else { CORSIKA_LOG_CRITICAL("invalid choice \"{}\"; also check argument parser", modelStr); @@ -426,7 +434,7 @@ int main(int argc, char** argv) { auto emContinuous = make_select(EMHadronSwitch(), emContinuousBethe, emContinuousProposal); - LongitudinalWriter profile{showerAxis, 200, 10_g / square(1_cm)}; + LongitudinalWriter profile{showerAxis, nAxisBins, dX}; output.add("profile", profile); LongitudinalProfile<SubWriter<decltype(profile)>> longprof{profile}; @@ -438,7 +446,7 @@ int main(int argc, char** argv) { #endif InteractionCounter leIntCounted{leIntModel}; - StackInspector<setup::Stack<EnvType>> stackInspect(10000, false, E0); + StackInspector<StackType> stackInspect(10000, false, E0); // assemble all processes into an ordered process list struct EnergySwitch { @@ -452,30 +460,20 @@ int main(int argc, char** argv) { // observation plane Plane const obsPlane(showerCore, DirectionVector(rootCS, {0., 0., 1.})); - ObservationPlane<setup::Tracking, ParticleWriterParquet> observationLevel{ + 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<setup::Tracking, ParticleWriterParquet> primaryWriter(observationLevel); + PrimaryWriter<TrackingType, ParticleWriterParquet> primaryWriter(observationLevel); output.add("primary", primaryWriter); int ring_number{app["--ring"]->as<int>()}; - std::cout << "Ring number : " << ring_number << std::endl; auto const radius_{ring_number * 25_m}; - // std::cout << "Radius = " << radius_ << std::endl; const int rr_ = static_cast<int>(radius_ / 1_m); - // if (ring_number == 0) { - // // assemble the final process sequence without radio - // auto sequence = make_sequence(stackInspect, hadronSequence, - // decaySequence, emCascade, - // emContinuous, longprof, observationLevel, - // thinning, cut); - // } else { - // Radio antennas and relevant information // the antenna time variables const TimeType duration_{4e-7_s}; @@ -491,14 +489,11 @@ int main(int argc, char** argv) { auto const injectionPosY_{injectionPos.getCoordinates().getY()}; auto const injectionPosZ_{injectionPos.getCoordinates().getZ()}; auto const triggerpoint_{Point(rootCS, injectionPosX_, injectionPosY_, injectionPosZ_)}; - std::cout << "Trigger Point is: " << triggerpoint_ << std::endl; if (ring_number != 0) { // setup CoREAS antennas - 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 phi_1 = 0; - // 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)}; @@ -514,8 +509,6 @@ int main(int argc, char** argv) { // setup ZHS antennas - use the for loop for star shape pattern for (auto phi_ = 0; phi_ <= 315; phi_ += 45) { auto phiRad_ = phi_ / 180. * M_PI; - // auto phi_ = 0; phi_; - // auto phiRad_ = phi_ / 180. * M_PI; auto const point_{Point(rootCS, showerCoreX_ + radius_ * cos(phiRad_), showerCoreY_ + radius_ * sin(phiRad_), constants::EarthRadius::Mean)}; @@ -557,18 +550,19 @@ int main(int argc, char** argv) { // create the cascade object using the default stack and tracking // implementation - setup::Tracking tracking; - setup::Stack<EnvType> stack; + TrackingType tracking; + StackType stack; Cascade EAS(env, tracking, sequence, output, stack); // print our primary parameters all in one place if (app["--pdg"]->count() > 0) { - CORSIKA_LOG_INFO("Primary PDG ID: {}", app["--pdg"]->as<int>()); + CORSIKA_LOG_INFO("Primary PDG ID: {}", app["--pdg"]->as<int>()); } else { - CORSIKA_LOG_INFO("Primary Z/A: {}/{}", Z, A); + CORSIKA_LOG_INFO("Primary Z/A: {}/{}", Z, A); } - CORSIKA_LOG_INFO("Primary Energy: {}", E0); - CORSIKA_LOG_INFO("Primary Momentum: {}", P0); + CORSIKA_LOG_INFO("Primary Energy: {}", E0); + CORSIKA_LOG_INFO("Primary Momentum: {}", P0); + CORSIKA_LOG_INFO("Primary Direction: {}", plab.getNorm()); CORSIKA_LOG_INFO("Point of Injection: {}", injectionPos.getCoordinates()); CORSIKA_LOG_INFO("Shower Axis Length: {}", (showerCore - injectionPos).getNorm() * 1.2); diff --git a/corsika/detail/framework/process/SwitchProcessSequence.inl b/corsika/detail/framework/process/SwitchProcessSequence.inl index 0e4584a76..364e307c4 100644 --- a/corsika/detail/framework/process/SwitchProcessSequence.inl +++ b/corsika/detail/framework/process/SwitchProcessSequence.inl @@ -77,10 +77,10 @@ namespace corsika { template <typename TCondition, typename TSequence, typename USequence, int IndexStart, int IndexProcess1, int IndexProcess2> template <typename TParticle> - inline ProcessReturn SwitchProcessSequence< - TCondition, TSequence, USequence, IndexStart, IndexProcess1, - IndexProcess2>::doContinuous(Step<TParticle>& step, - ContinuousProcessIndex const idLimit) { + inline ProcessReturn SwitchProcessSequence<TCondition, TSequence, USequence, IndexStart, + IndexProcess1, IndexProcess2>:: + doContinuous(Step<TParticle>& step, + [[maybe_unused]] ContinuousProcessIndex const idLimit) { if (select_(step.getParticlePre())) { if constexpr (process1_type::is_process_sequence) { return A_.doContinuous(step, idLimit); @@ -218,10 +218,10 @@ namespace corsika { template <typename TCondition, typename TSequence, typename USequence, int IndexStart, int IndexProcess1, int IndexProcess2> template <typename TParticle> - CrossSectionType SwitchProcessSequence< - TCondition, TSequence, USequence, IndexStart, IndexProcess1, - IndexProcess2>::getCrossSection(TParticle const& projectile, Code const targetId, - FourMomentum const& targetP4) const { + CrossSectionType SwitchProcessSequence<TCondition, TSequence, USequence, IndexStart, + IndexProcess1, IndexProcess2>:: + getCrossSection(TParticle const& projectile, [[maybe_unused]] Code const targetId, + [[maybe_unused]] FourMomentum const& targetP4) const { if (select_(projectile)) { if constexpr (is_interaction_process_v<process1_type>) { diff --git a/corsika/detail/modules/energy_loss/BetheBlochPDG.inl b/corsika/detail/modules/energy_loss/BetheBlochPDG.inl index 6847d90a3..fed757cd4 100644 --- a/corsika/detail/modules/energy_loss/BetheBlochPDG.inl +++ b/corsika/detail/modules/energy_loss/BetheBlochPDG.inl @@ -162,10 +162,8 @@ namespace corsika { HEPEnergyType const dE = getTotalEnergyLoss(step.getParticlePre(), dX); // if (dE > HEPEnergyType::zero()) // dE = -dE; - [[maybe_unused]] const auto Ekin = step.getEkinPre(); - auto EkinNew = Ekin + dE; CORSIKA_LOG_TRACE("EnergyLoss dE={} MeV, Ekin={} GeV, EkinNew={} GeV", dE / 1_MeV, - Ekin / 1_GeV, EkinNew / 1_GeV); + step.getEkinPre() / 1_GeV, (step.getEkinPre() + dE) / 1_GeV); step.add_dEkin(dE); // also send to output diff --git a/corsika/detail/modules/proposal/ContinuousProcess.inl b/corsika/detail/modules/proposal/ContinuousProcess.inl index 36f277270..a49a846ba 100644 --- a/corsika/detail/modules/proposal/ContinuousProcess.inl +++ b/corsika/detail/modules/proposal/ContinuousProcess.inl @@ -48,8 +48,8 @@ namespace corsika::proposal { template <typename TEnvironment, typename... TOutputArgs> inline ContinuousProcess<TOutput>::ContinuousProcess(TEnvironment const& _env, TOutputArgs&&... args) - : TOutput(args...) - , ProposalProcessBase(_env) {} + : ProposalProcessBase(_env) + , TOutput(args...) {} template <typename TOutput> template <typename TParticle> diff --git a/corsika/detail/modules/proposal/InteractionModel.inl b/corsika/detail/modules/proposal/InteractionModel.inl index 05c44ba2f..288b36c51 100644 --- a/corsika/detail/modules/proposal/InteractionModel.inl +++ b/corsika/detail/modules/proposal/InteractionModel.inl @@ -56,7 +56,8 @@ namespace corsika::proposal { template <typename TStackView> inline ProcessReturn InteractionModel<THadronicLEModel, THadronicHEModel>::doInteraction( - TStackView& view, Code const projectileId, FourMomentum const& projectileP4) { + TStackView& view, Code const projectileId, + [[maybe_unused]] FourMomentum const& projectileP4) { auto const projectile = view.getProjectile(); diff --git a/corsika/detail/modules/proposal/ProposalProcessBase.inl b/corsika/detail/modules/proposal/ProposalProcessBase.inl index 0ea18a4bf..2a72811ee 100644 --- a/corsika/detail/modules/proposal/ProposalProcessBase.inl +++ b/corsika/detail/modules/proposal/ProposalProcessBase.inl @@ -46,7 +46,7 @@ namespace corsika::proposal { } return lowest_table_value; - }; + } template <typename TEnvironment> inline ProposalProcessBase::ProposalProcessBase(TEnvironment const& _env) { diff --git a/corsika/detail/modules/radio/RadioProcess.inl b/corsika/detail/modules/radio/RadioProcess.inl index 9211af14b..bad68ac85 100644 --- a/corsika/detail/modules/radio/RadioProcess.inl +++ b/corsika/detail/modules/radio/RadioProcess.inl @@ -57,7 +57,8 @@ namespace corsika { template <typename Particle, typename Track> inline LengthType RadioProcess<TAntennaCollection, TRadioImpl, TPropagator>::getMaxStepLength( - const Particle& vParticle, const Track& vTrack) const { + [[maybe_unused]] const Particle& vParticle, + [[maybe_unused]] const Track& vTrack) const { return meter * std::numeric_limits<double>::infinity(); } @@ -176,4 +177,4 @@ namespace corsika { return config; } -} // namespace corsika \ No newline at end of file +} // namespace corsika diff --git a/corsika/modules/Random.hpp b/corsika/modules/Random.hpp index a254aa229..d31bd35df 100644 --- a/corsika/modules/Random.hpp +++ b/corsika/modules/Random.hpp @@ -23,7 +23,7 @@ namespace corsika { inline void rng_func(corsika::default_prng_type& rng, double* dest, std::size_t N) { std::uniform_real_distribution<double> udist(0.0, 1.0); std::generate(dest, std::next(dest, N), std::bind(udist, std::ref(rng))); - }; + } } // namespace detail inline void connect_random_stream(corsika::default_prng_type& rng, diff --git a/corsika/modules/writers/EnergyLossWriter.hpp b/corsika/modules/writers/EnergyLossWriter.hpp index b516ab626..c247b424e 100644 --- a/corsika/modules/writers/EnergyLossWriter.hpp +++ b/corsika/modules/writers/EnergyLossWriter.hpp @@ -156,7 +156,7 @@ namespace corsika { /** * Return the configuration of this output. */ - YAML::Node getConfig() const; + YAML::Node getConfig() const override; private: ShowerAxis const& showerAxis_; ///< conversion between geometry and grammage diff --git a/corsika/modules/writers/LongitudinalWriter.hpp b/corsika/modules/writers/LongitudinalWriter.hpp index caa49f9af..0d6eb2822 100644 --- a/corsika/modules/writers/LongitudinalWriter.hpp +++ b/corsika/modules/writers/LongitudinalWriter.hpp @@ -122,12 +122,12 @@ namespace corsika { /** * Return a summary. */ - YAML::Node getSummary() const; + YAML::Node getSummary() const override; /** * Return the configuration of this output. */ - YAML::Node getConfig() const; + YAML::Node getConfig() const override; number_profile::ProfileData const& getProfile( number_profile::ProfileIndex index) const { diff --git a/corsika/modules/writers/WriterOff.hpp b/corsika/modules/writers/WriterOff.hpp index 3d752cc9a..da418d54d 100644 --- a/corsika/modules/writers/WriterOff.hpp +++ b/corsika/modules/writers/WriterOff.hpp @@ -43,7 +43,7 @@ namespace corsika { template <typename... TArgs> void write(TArgs&&...) {} - virtual YAML::Node getConfig() const { return YAML::Node(); } + virtual YAML::Node getConfig() const override { return YAML::Node(); } }; // class WriterOff diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index d3aa7ecc2..614bfb9bc 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -9,88 +9,88 @@ find_package (corsika CONFIG REQUIRED) # this is only for CORSIKA_REGISTER_EXAMPLE include ("${CMAKE_CURRENT_SOURCE_DIR}/corsikaExamples.cmake") -add_executable (helix_example helix_example.cpp) -target_link_libraries (helix_example CORSIKA8::CORSIKA8) -CORSIKA_REGISTER_EXAMPLE (helix_example) -add_executable (geometry_example geometry_example.cpp) -target_link_libraries (geometry_example CORSIKA8::CORSIKA8) -CORSIKA_REGISTER_EXAMPLE (geometry_example) +################### +## cascade_examples +################### -add_executable (stack_example stack_example.cpp) -target_link_libraries (stack_example CORSIKA8::CORSIKA8) -CORSIKA_REGISTER_EXAMPLE (stack_example) +add_executable (em_shower cascade_examples/em_shower.cpp) +target_link_libraries (em_shower CORSIKA8::CORSIKA8) +CORSIKA_REGISTER_EXAMPLE (em_shower RUN_OPTIONS 100 8472) -add_executable (cascade_example cascade_example.cpp) -target_link_libraries (cascade_example CORSIKA8::CORSIKA8) -CORSIKA_REGISTER_EXAMPLE (cascade_example) +if (WITH_FLUKA) + add_executable (mars cascade_examples/mars.cpp) + target_link_libraries (mars CORSIKA8::CORSIKA8) + message("FLUKA found, will make 'mars' example") +else() + message("FLUKA not found, will not make 'mars' example") +endif() -add_executable (boundary_example boundary_example.cpp) -target_link_libraries (boundary_example CORSIKA8::CORSIKA8) -CORSIKA_REGISTER_EXAMPLE (boundary_example) +add_executable (mc_conex cascade_examples/mc_conex.cpp) +target_link_libraries (mc_conex CORSIKA8::CORSIKA8) +CORSIKA_REGISTER_EXAMPLE (mc_conex RUN_OPTIONS 4 2 10000.) -add_executable (cascade_proton_example cascade_proton_example.cpp) -target_link_libraries (cascade_proton_example CORSIKA8::CORSIKA8) -CORSIKA_REGISTER_EXAMPLE (cascade_proton_example) +add_executable (radio_em_shower cascade_examples/radio_em_shower.cpp) +target_link_libraries (radio_em_shower CORSIKA8::CORSIKA8) +CORSIKA_REGISTER_EXAMPLE (radio_em_shower RUN_OPTIONS 10 1121673489) -add_executable (vertical_EAS vertical_EAS.cpp) -target_link_libraries (vertical_EAS CORSIKA8::CORSIKA8) -CORSIKA_REGISTER_EXAMPLE (vertical_EAS RUN_OPTIONS 4 2 10000.) +if (WITH_FLUKA) + add_executable (water cascade_examples/water.cpp) + target_link_libraries (water CORSIKA8::CORSIKA8) + message("FLUKA found, will make 'water' example") +else() + message("FLUKA not found, will not make 'water' example") +endif() -add_executable (stopping_power stopping_power.cpp) -target_link_libraries (stopping_power CORSIKA8::CORSIKA8) -CORSIKA_REGISTER_EXAMPLE (stopping_power) -add_executable (staticsequence_example staticsequence_example.cpp) -target_link_libraries (staticsequence_example CORSIKA8::CORSIKA8) -CORSIKA_REGISTER_EXAMPLE (staticsequence_example) +##################### +## framework_examples +##################### -add_executable (particle_list_example particle_list_example.cpp) -target_link_libraries (particle_list_example CORSIKA8::CORSIKA8) -CORSIKA_REGISTER_EXAMPLE (particle_list_example) +add_executable (boundary_crossing framework_examples/boundary_crossing.cpp) +target_link_libraries (boundary_crossing CORSIKA8::CORSIKA8) +CORSIKA_REGISTER_EXAMPLE (boundary_crossing) -add_executable (em_shower em_shower.cpp) -target_link_libraries (em_shower CORSIKA8::CORSIKA8) -CORSIKA_REGISTER_EXAMPLE (em_shower RUN_OPTIONS 100 8472) +add_executable (environment framework_examples/environment.cpp) +target_link_libraries (environment CORSIKA8::CORSIKA8) -add_executable (hybrid_MC hybrid_MC.cpp) -target_link_libraries (hybrid_MC CORSIKA8::CORSIKA8) -CORSIKA_REGISTER_EXAMPLE (hybrid_MC RUN_OPTIONS 4 2 10000.) +add_executable (geometry framework_examples/geometry.cpp) +target_link_libraries (geometry CORSIKA8::CORSIKA8) +CORSIKA_REGISTER_EXAMPLE (geometry) +add_executable (helix_trajectory framework_examples/helix_trajectory.cpp) +target_link_libraries (helix_trajectory CORSIKA8::CORSIKA8) +CORSIKA_REGISTER_EXAMPLE (helix_trajectory) -add_executable (corsika corsika.cpp) -# for ICRC 2023 -option(WITH_FLUKA "use FLUKA instead of UrQMD in corsika.cpp") -if (WITH_FLUKA) - target_compile_definitions(corsika PRIVATE WITH_FLUKA) - message("compiling corsika.cpp with FLUKA") -else() - message("compiling corsika.cpp with UrQMD") -endif() -target_link_libraries (corsika CORSIKA8::CORSIKA8) -CORSIKA_REGISTER_EXAMPLE (corsika RUN_OPTIONS --energy=10 --zenith=10 --nevent=2 --filename=corsika_test --pdg=2212) +add_executable (known_particles framework_examples/known_particles.cpp) +target_link_libraries (known_particles CORSIKA8::CORSIKA8) +CORSIKA_REGISTER_EXAMPLE (known_particles) -add_executable (mars mars.cpp) -target_link_libraries (mars CORSIKA8::CORSIKA8) +add_executable (stack framework_examples/stack.cpp) +target_link_libraries (stack CORSIKA8::CORSIKA8) +CORSIKA_REGISTER_EXAMPLE (stack) -add_executable (water water.cpp) -target_link_libraries (water CORSIKA8::CORSIKA8) +add_executable (static_sequence framework_examples/static_sequence.cpp) +target_link_libraries (static_sequence CORSIKA8::CORSIKA8) +CORSIKA_REGISTER_EXAMPLE (static_sequence) -add_executable (environment environment.cpp) -target_link_libraries (environment CORSIKA8::CORSIKA8) -add_executable (synchrotron_test_manual_tracking synchrotron_test_manual_tracking.cpp) -target_link_libraries (synchrotron_test_manual_tracking CORSIKA8::CORSIKA8) -CORSIKA_REGISTER_EXAMPLE (synchrotron_test_manual_tracking) +################### +## physics_examples +################### -add_executable (synchrotron_test_C8tracking synchrotron_test_C8tracking.cpp) +add_executable (stopping_power physics_examples/stopping_power.cpp) +target_link_libraries (stopping_power CORSIKA8::CORSIKA8) +CORSIKA_REGISTER_EXAMPLE (stopping_power) + +add_executable (synchrotron_clover_leaf physics_examples/synchrotron_clover_leaf.cpp) +target_link_libraries (synchrotron_clover_leaf CORSIKA8::CORSIKA8) +CORSIKA_REGISTER_EXAMPLE (synchrotron_clover_leaf) + +add_executable (synchrotron_test_C8tracking physics_examples/synchrotron_test_C8tracking.cpp) target_link_libraries (synchrotron_test_C8tracking CORSIKA8::CORSIKA8) CORSIKA_REGISTER_EXAMPLE (synchrotron_test_C8tracking) -add_executable (clover_leaf clover_leaf.cpp) -target_link_libraries (clover_leaf CORSIKA8::CORSIKA8) -CORSIKA_REGISTER_EXAMPLE (clover_leaf) - -add_executable (radio_em_shower radio_em_shower.cpp) -target_link_libraries (radio_em_shower CORSIKA8::CORSIKA8) -CORSIKA_REGISTER_EXAMPLE (radio_em_shower RUN_OPTIONS 10 1121673489) +add_executable (synchrotron_test_manual_tracking physics_examples/synchrotron_test_manual_tracking.cpp) +target_link_libraries (synchrotron_test_manual_tracking CORSIKA8::CORSIKA8) +CORSIKA_REGISTER_EXAMPLE (synchrotron_test_manual_tracking) diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 000000000..ba9a661db --- /dev/null +++ b/examples/README.md @@ -0,0 +1,9 @@ +# CORSIKA 8 Examples + +This directory contains several example scripts that can help you get started to simulate your own showers and/or to begin developing your own interfaces within the C8 framework. +The sub-directories contain the several types of examples: + + * **cascade_examples**: scripts to set up running full cascade simulations for various use cases. This is a good starting point if you want to simulate showers for your own experiments. + * **framework_examples**: show how to use and interact with the internal framework of C8 + * **physics_examples**: demonstrate various tests of the particle interactions and/or cascades + \ No newline at end of file diff --git a/examples/cascade_example.cpp b/examples/cascade_example.cpp deleted file mode 100644 index 351809bf7..000000000 --- a/examples/cascade_example.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - * (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/framework/process/ProcessSequence.hpp> -#include <corsika/framework/process/SwitchProcessSequence.hpp> -#include <corsika/framework/core/Cascade.hpp> -#include <corsika/framework/core/PhysicalUnits.hpp> -#include <corsika/framework/core/Logging.hpp> -#include <corsika/framework/core/EnergyMomentumOperations.hpp> -#include <corsika/framework/random/RNGManager.hpp> -#include <corsika/framework/geometry/Sphere.hpp> -#include <corsika/framework/utility/CorsikaFenv.hpp> - -#include <corsika/output/OutputManager.hpp> -#include <corsika/modules/writers/SubWriter.hpp> -#include <corsika/modules/writers/EnergyLossWriter.hpp> - -#include <corsika/media/Environment.hpp> -#include <corsika/media/HomogeneousMedium.hpp> -#include <corsika/media/NuclearComposition.hpp> -#include <corsika/media/ShowerAxis.hpp> -#include <corsika/media/MediumPropertyModel.hpp> -#include <corsika/media/UniformMagneticField.hpp> - -#include <corsika/setup/SetupStack.hpp> -#include <corsika/setup/SetupTrajectory.hpp> - -#include <corsika/modules/BetheBlochPDG.hpp> -#include <corsika/modules/StackInspector.hpp> -#include <corsika/modules/Sibyll.hpp> -#include <corsika/modules/ParticleCut.hpp> -#include <corsika/modules/TrackWriter.hpp> - -#include <iostream> -#include <limits> - -using namespace corsika; -using namespace std; - -// -// The example main program for a particle cascade -// -int main() { - - logging::set_level(logging::level::warn); - - CORSIKA_LOG_INFO("cascade_example"); - - LengthType const height_atmosphere = 112.8_km; - - feenableexcept(FE_INVALID); - // initialize random number sequence(s) - RNGManager<>::getInstance().registerRandomStream("cascade"); - - // setup environment, geometry - using EnvironmentInterface = IMediumPropertyModel<IMagneticFieldModel<IMediumModel>>; - using EnvType = Environment<EnvironmentInterface>; - EnvType env; - auto& universe = *(env.getUniverse()); - - CoordinateSystemPtr const& rootCS = env.getCoordinateSystem(); - - auto world = EnvType::createNode<Sphere>(Point{rootCS, 0_m, 0_m, 0_m}, 150_km); - - using MyHomogeneousModel = - MediumPropertyModel<UniformMagneticField<HomogeneousMedium<EnvironmentInterface>>>; - - // fraction of oxygen - double const fox = 0.20946; - auto const props = world->setModelProperties<MyHomogeneousModel>( - Medium::AirDry1Atm, MagneticFieldVector(rootCS, 0_T, 0_T, 0_T), - 1_kg / (1_m * 1_m * 1_m), - NuclearComposition({Code::Nitrogen, Code::Oxygen}, {1. - fox, fox})); - - auto innerMedium = EnvType::createNode<Sphere>(Point{rootCS, 0_m, 0_m, 0_m}, 5000_m); - - innerMedium->setModelProperties(props); - world->addChild(std::move(innerMedium)); - universe.addChild(std::move(world)); - - // setup particle stack, and add primary particle - setup::Stack<EnvType> stack; - stack.clear(); - const int nuclA = 4; - const int nuclZ = int(nuclA / 2.15 + 0.7); - const Code beamCode = get_nucleus_code(nuclA, nuclZ); - const HEPMassType mass = get_nucleus_mass(beamCode); - const HEPEnergyType E0 = nuclA * 1_TeV; - double theta = 0.; - double phi = 0.; - - Point const injectionPos( - rootCS, 0_m, 0_m, - height_atmosphere); // this is the CORSIKA 7 start of atmosphere/universe - - OutputManager output("cascade_outputs"); - - theta *= M_PI / 180.; - phi *= M_PI / 180.; - DirectionVector const direction( - rootCS, {sin(theta) * cos(phi), sin(theta) * sin(phi), -cos(theta)}); - - ShowerAxis const showerAxis{injectionPos, direction * 100_km, env}; - EnergyLossWriter dEdX{showerAxis}; - output.add("energyloss", dEdX); - - { - HEPMomentumType const P0 = calculate_momentum(E0, mass); - auto plab = direction * P0; - CORSIKA_LOG_INFO("input particle: {}", beamCode); - CORSIKA_LOG_INFO("input angles: theta={} phi={}", theta, phi); - CORSIKA_LOG_INFO("input momentum: {}", plab.getComponents() / 1_GeV); - stack.addParticle(std::make_tuple( - beamCode, calculate_kinetic_energy(plab.getNorm(), get_mass(beamCode)), direction, - injectionPos, 0_ns)); - } - - // setup processes, decays and interactions - setup::Tracking tracking; - StackInspector<setup::Stack<EnvType>> stackInspect(100, true, E0); - - RNGManager<>::getInstance().registerRandomStream("sibyll"); - - corsika::sibyll::Interaction sibyll{env}; - corsika::sibyll::Decay decay; - - // cascade with only HE model ==> HE cut - ParticleCut<SubWriter<decltype(dEdX)>> cut(80_GeV, true, dEdX); - BetheBlochPDG<SubWriter<decltype(dEdX)>> eLoss{dEdX}; - - TrackWriter trackWriter; - output.add("tracks", trackWriter); // register TrackWriter - - // assemble all processes into an ordered process list - auto sequence = make_sequence(stackInspect, sibyll, decay, eLoss, trackWriter, cut); - - // define air shower object, run simulation - Cascade EAS(env, tracking, sequence, output, stack); - - output.startOfLibrary(); - EAS.run(); - output.endOfLibrary(); - - const HEPEnergyType Efinal = dEdX.getEnergyLost(); - CORSIKA_LOG_INFO( - "\n" - "total cut energy (GeV) : {}\n" - "relative difference (%): {}\n" - "total dEdX energy (GeV): {}\n" - "relative difference (%): {}\n", - Efinal / 1_GeV, (Efinal / E0 - 1) * 100, dEdX.getEnergyLost() / 1_GeV, - dEdX.getEnergyLost() / E0 * 100); -} diff --git a/examples/em_shower.cpp b/examples/cascade_examples/em_shower.cpp similarity index 74% rename from examples/em_shower.cpp rename to examples/cascade_examples/em_shower.cpp index cd06faa12..a4d6c3471 100644 --- a/examples/em_shower.cpp +++ b/examples/cascade_examples/em_shower.cpp @@ -18,10 +18,10 @@ #include <corsika/framework/process/SwitchProcessSequence.hpp> #include <corsika/framework/random/RNGManager.hpp> #include <corsika/framework/utility/CorsikaFenv.hpp> -#include <corsika/framework/utility/SaveBoostHistogram.hpp> #include <corsika/modules/writers/EnergyLossWriter.hpp> #include <corsika/modules/writers/LongitudinalWriter.hpp> +#include <corsika/modules/writers/PrimaryWriter.hpp> #include <corsika/modules/writers/SubWriter.hpp> #include <corsika/output/OutputManager.hpp> @@ -29,11 +29,9 @@ #include <corsika/media/Environment.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/LongitudinalProfile.hpp> #include <corsika/modules/ObservationPlane.hpp> #include <corsika/modules/PROPOSAL.hpp> @@ -62,13 +60,19 @@ void registerRandomStreams(int seed) { if (seed == 0) { std::random_device rd; seed = rd(); - cout << "new random seed (auto) " << seed << endl; + CORSIKA_LOG_INFO("random seed (auto) {} ", seed); + } else { + CORSIKA_LOG_INFO("random seed {} ", seed); } RNGManager<>::getInstance().setSeed(seed); } +using EnvironmentInterface = IMediumPropertyModel<IMagneticFieldModel<IMediumModel>>; +using EnvType = Environment<EnvironmentInterface>; template <typename T> using MyExtraEnv = MediumPropertyModel<UniformMagneticField<T>>; +using StackType = setup::Stack<EnvType>; +using TrackingType = setup::Tracking; int main(int argc, char** argv) { @@ -87,29 +91,23 @@ int main(int argc, char** argv) { registerRandomStreams(seed); // setup environment, geometry - using EnvironmentInterface = IMediumPropertyModel<IMagneticFieldModel<IMediumModel>>; - using EnvType = Environment<EnvironmentInterface>; EnvType env; CoordinateSystemPtr const& rootCS = env.getCoordinateSystem(); Point const center{rootCS, 0_m, 0_m, 0_m}; // build a Linsley US Standard atmosphere into `env` + MagneticFieldVector bField{rootCS, 50_uT, 0_T, 0_T}; create_5layer_atmosphere<EnvironmentInterface, MyExtraEnv>( - env, AtmosphereId::LinsleyUSStd, center, Medium::AirDry1Atm, - MagneticFieldVector{rootCS, 20.4_uT, 0_T, -43.23_uT}); + env, AtmosphereId::LinsleyUSStd, center, Medium::AirDry1Atm, bField); std::unordered_map<Code, HEPEnergyType> energy_resolution = { - {Code::Electron, 2_MeV}, - {Code::Positron, 2_MeV}, - {Code::Photon, 2_MeV}, + {Code::Electron, 5_MeV}, + {Code::Positron, 5_MeV}, + {Code::Photon, 5_MeV}, }; for (auto [pcode, energy] : energy_resolution) set_energy_production_threshold(pcode, energy); - // setup particle stack, and add primary particle - setup::Stack<EnvType> stack; - stack.clear(); - const Code beamCode = Code::Electron; auto const mass = get_mass(beamCode); const HEPEnergyType E0 = 1_GeV * std::stof(std::string(argv[1])); @@ -123,10 +121,6 @@ int main(int argc, char** argv) { auto const [px, py, pz] = momentumComponents(thetaRad, P0); auto plab = MomentumVector(rootCS, {px, py, pz}); - cout << "input particle: " << beamCode << endl; - cout << "input angles: theta=" << theta << endl; - cout << "input momentum: " << plab.getComponents() / 1_GeV - << ", norm = " << plab.getNorm() << endl; auto const observationHeight = 0.0_km + constants::EarthRadius::Mean; auto const injectionHeight = 112.75_km + constants::EarthRadius::Mean; @@ -137,54 +131,67 @@ int main(int argc, char** argv) { Point const injectionPos = showerCore + DirectionVector{rootCS, {-sin(thetaRad), 0, cos(thetaRad)}} * t; - std::cout << "point of injection: " << injectionPos.getCoordinates() << std::endl; - - stack.addParticle(std::make_tuple( - beamCode, calculate_kinetic_energy(plab.getNorm(), get_mass(beamCode)), - plab.normalized(), injectionPos, 0_ns)); - - CORSIKA_LOG_INFO("shower axis length: {} ", - (showerCore - injectionPos).getNorm() * 1.02); - ShowerAxis const showerAxis{injectionPos, (showerCore - injectionPos) * 1.02, env, false, 1000}; - - OutputManager output("em_shower_outputs"); - - EnergyLossWriter dEdX{showerAxis, 10_g / square(1_cm), 200}; - // register energy losses as output - output.add("dEdX", dEdX); + auto const dX = 10_g / square(1_cm); // Binning of the writers along the shower axis + uint const nAxisBins = showerAxis.getMaximumX() / dX + 1; // Get maximum number of bins + + CORSIKA_LOG_INFO("Primary particle: {}", beamCode); + CORSIKA_LOG_INFO("Zenith angle: {} (rad)", theta); + CORSIKA_LOG_INFO("Momentum: {} (GeV)", plab.getComponents() / 1_GeV); + CORSIKA_LOG_INFO("Propagation dir: {}", plab.getNorm()); + CORSIKA_LOG_INFO("Injection point: {}", injectionPos.getCoordinates()); + CORSIKA_LOG_INFO("shower axis length: {} ", + (showerCore - injectionPos).getNorm() * 1.02); // setup processes, decays and interactions + EnergyLossWriter energyloss{showerAxis, dX, nAxisBins}; + ParticleCut<SubWriter<decltype(energyloss)>> cut(5_MeV, 5_MeV, 100_GeV, 100_GeV, true, + energyloss); - ParticleCut<SubWriter<decltype(dEdX)>> cut(2_MeV, 2_MeV, 100_GeV, 100_GeV, true, dEdX); corsika::sibyll::Interaction sibyll{env}; corsika::sophia::InteractionModel sophia; - HEPEnergyType heThresholdNN = 60_GeV; + HEPEnergyType heThresholdNN = 80_GeV; corsika::proposal::Interaction emCascade( env, sophia, sibyll.getHadronInteractionModel(), heThresholdNN); - corsika::proposal::ContinuousProcess<SubWriter<decltype(dEdX)>> emContinuous(env, dEdX); - // BetheBlochPDG<SubWriter<decltype(dEdX)>> emContinuous{dEdX}; + corsika::proposal::ContinuousProcess<SubWriter<decltype(energyloss)>> emContinuous( + env, energyloss); // NOT possible right now, due to interface differenc in PROPOSAL // InteractionCounter emCascadeCounted(emCascade); + OutputManager output("em_shower_outputs"); + + output.add("energyloss", energyloss); + TrackWriter tracks; output.add("tracks", tracks); - // long. profile - LongitudinalWriter profile{showerAxis, 10_g / square(1_cm)}; + LongitudinalWriter profile{showerAxis, nAxisBins, dX}; output.add("profile", profile); LongitudinalProfile<SubWriter<decltype(profile)>> longprof{profile}; Plane const obsPlane(showerCore, DirectionVector(rootCS, {0., 0., 1.})); - ObservationPlane<setup::Tracking, ParticleWriterParquet> observationLevel{ + ObservationPlane<TrackingType, ParticleWriterParquet> observationLevel{ obsPlane, DirectionVector(rootCS, {1., 0., 0.})}; output.add("particles", observationLevel); + PrimaryWriter<TrackingType, ParticleWriterParquet> primaryWriter(observationLevel); + output.add("primary", primaryWriter); + auto sequence = make_sequence(emCascade, emContinuous, longprof, observationLevel, cut); // define air shower object, run simulation - setup::Tracking tracking; + TrackingType tracking; + + auto const primaryProperties = std::make_tuple( + beamCode, calculate_kinetic_energy(plab.getNorm(), get_mass(beamCode)), + plab.normalized(), injectionPos, 0_ns); + + // setup particle stack, and add primary particle + StackType stack; + stack.clear(); + stack.addParticle(primaryProperties); + primaryWriter.recordPrimary(primaryProperties); output.startOfLibrary(); Cascade EAS(env, tracking, sequence, output, stack); @@ -194,7 +201,8 @@ int main(int argc, char** argv) { EAS.run(); - HEPEnergyType const Efinal = dEdX.getEnergyLost() + observationLevel.getEnergyGround(); + HEPEnergyType const Efinal = + energyloss.getEnergyLost() + observationLevel.getEnergyGround(); CORSIKA_LOG_INFO( "total energy budget (GeV): {}, " @@ -202,4 +210,6 @@ int main(int argc, char** argv) { Efinal / 1_GeV, (Efinal / E0 - 1) * 100); output.endOfLibrary(); + + return EXIT_SUCCESS; } diff --git a/examples/mars.cpp b/examples/cascade_examples/mars.cpp similarity index 88% rename from examples/mars.cpp rename to examples/cascade_examples/mars.cpp index 6a57b6ec3..55739516b 100644 --- a/examples/mars.cpp +++ b/examples/cascade_examples/mars.cpp @@ -30,6 +30,7 @@ #include <corsika/modules/writers/EnergyLossWriter.hpp> #include <corsika/modules/writers/LongitudinalWriter.hpp> +#include <corsika/modules/writers/PrimaryWriter.hpp> #include <corsika/modules/writers/SubWriter.hpp> #include <corsika/output/OutputManager.hpp> @@ -55,7 +56,7 @@ #include <corsika/modules/Sophia.hpp> #include <corsika/modules/StackInspector.hpp> #include <corsika/modules/TrackWriter.hpp> -#include <corsika/modules/UrQMD.hpp> +#include <corsika/modules/FLUKA.hpp> #include <corsika/setup/SetupStack.hpp> #include <corsika/setup/SetupTrajectory.hpp> @@ -74,8 +75,9 @@ using namespace std; using EnvironmentInterface = IMediumPropertyModel<IMagneticFieldModel<IMediumModel>>; using EnvType = Environment<EnvironmentInterface>; - -using Particle = setup::Stack<EnvType>::particle_type; +using StackType = setup::Stack<EnvType>; +using TrackingType = setup::Tracking; +using Particle = StackType::particle_type; typedef decltype(1 * pascal) PressureType; typedef decltype(1 * degree_celsius) TemperatureType; @@ -111,7 +113,7 @@ void registerRandomStreams(int seed) { RNGManager<>::getInstance().registerRandomStream("sibyll"); RNGManager<>::getInstance().registerRandomStream("sophia"); RNGManager<>::getInstance().registerRandomStream("pythia"); - RNGManager<>::getInstance().registerRandomStream("urqmd"); + RNGManager<>::getInstance().registerRandomStream("fluka"); RNGManager<>::getInstance().registerRandomStream("proposal"); if (seed == 0) { std::random_device rd; @@ -200,8 +202,6 @@ int main(int argc, char** argv) { } // 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."); @@ -224,12 +224,10 @@ int main(int argc, char** argv) { Medium::AirDry1Atm, // Mars, close enough MagneticFieldVector{rootCS, 0_T, 0_uT, 0_T}); // Mars - builder.setNuclearComposition( // Mars - {{Code::Nitrogen, Code::Oxygen}, {1. / 3., 2. / 3.}}); // simplified - //{{Code::Carbon, Code::Oxygen, // 95.97 CO2 - // Code::Nitrogen}, // 1.89 N2 + 1.93 Argon + 0.146 O2 - // {0.9597 / 3, 0.9597 * 2 / 3, - // 1 - 0.9597}}); // values taken from AIRES manual, Ar removed for now + builder.setNuclearComposition( // Mars + {{Code::Carbon, Code::Oxygen, // 95.97 CO2 + Code::Nitrogen}, // 1.89 N2 + 1.93 Argon + 0.146 O2 + {0.9597 / 3, 0.9597 * 2 / 3, 1 - 0.9597}}); // values taken from AIRES manual MarsAtmModel layer1(0.699e3 * pascal, 0.00009 / 1_m, 31.0 * degree_celsius, 0.000998 * 1 * degree_celsius / 1_m); @@ -305,8 +303,10 @@ int main(int argc, char** argv) { OutputManager output(app["--filename"]->as<std::string>()); 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 + uint const nAxisBins = showerAxis.getMaximumX() / dX + 1; // Get maximum number of bins - EnergyLossWriter dEdX{showerAxis}; + EnergyLossWriter dEdX{showerAxis, dX, nAxisBins}; output.add("energyloss", dEdX); HEPEnergyType const emcut = 1_GeV; @@ -338,13 +338,13 @@ int main(int argc, char** argv) { auto emContinuous = make_select(EMHadronSwitch(), emContinuousBethe, emContinuousProposal); - LongitudinalWriter longprof{showerAxis}; + LongitudinalWriter longprof{showerAxis, nAxisBins, dX}; output.add("profile", longprof); LongitudinalProfile<SubWriter<decltype(longprof)>> profile{longprof}; - corsika::urqmd::UrQMD urqmd; - InteractionCounter urqmdCounted{urqmd}; - StackInspector<setup::Stack<EnvType>> stackInspect(5000, false, E0); + corsika::fluka::Interaction leIntModel{env}; + InteractionCounter leIntCounted{leIntModel}; + StackInspector<StackType> stackInspect(5000, false, E0); // assemble all processes into an ordered process list struct EnergySwitch { @@ -354,7 +354,7 @@ int main(int argc, char** argv) { bool operator()(Particle const& p) const { return (p.getKineticEnergy() < cutE_); } }; auto hadronSequence = - make_select(EnergySwitch(heHadronModelThreshold), urqmdCounted, sibyllCounted); + make_select(EnergySwitch(heHadronModelThreshold), leIntCounted, sibyllCounted); // track writer TrackWriter trackWriter; @@ -362,11 +362,14 @@ int main(int argc, char** argv) { // observation plane Plane const obsPlane(showerCore, DirectionVector(rootCS, {0., 0., 1.})); - ObservationPlane<setup::Tracking> observationLevel( - obsPlane, DirectionVector(rootCS, {1., 0., 0.})); + ObservationPlane<TrackingType> observationLevel(obsPlane, + DirectionVector(rootCS, {1., 0., 0.})); // register the observation plane with the output output.add("particles", observationLevel); + PrimaryWriter<TrackingType, ParticleWriterParquet> primaryWriter(observationLevel); + output.add("primary", primaryWriter); + // assemble the final process sequence auto sequence = make_sequence(stackInspect, hadronSequence, decayPythia, emCascade, emContinuous, @@ -375,18 +378,19 @@ int main(int argc, char** argv) { // create the cascade object using the default stack and tracking // implementation - setup::Tracking tracking; - setup::Stack<EnvType> stack; + TrackingType tracking; + StackType stack; Cascade EAS(env, tracking, sequence, output, stack); // print our primary parameters all in one place if (app["--pdg"]->count() > 0) { - CORSIKA_LOG_INFO("Primary PDG ID: {}", app["--pdg"]->as<int>()); + CORSIKA_LOG_INFO("Primary PDG ID: {}", app["--pdg"]->as<int>()); } else { - CORSIKA_LOG_INFO("Primary Z/A: {}/{}", Z, A); + CORSIKA_LOG_INFO("Primary Z/A: {}/{}", Z, A); } - CORSIKA_LOG_INFO("Primary Energy: {}", E0); - CORSIKA_LOG_INFO("Primary Momentum: {}", P0); + CORSIKA_LOG_INFO("Primary Energy: {}", E0); + CORSIKA_LOG_INFO("Primary Momentum: {}", P0); + CORSIKA_LOG_INFO("Primary Direction: {}", plab.getNorm()); CORSIKA_LOG_INFO("Point of Injection: {}", injectionPos.getCoordinates()); CORSIKA_LOG_INFO("Shower Axis Length: {}", (showerCore - injectionPos).getNorm() * 1.2); @@ -409,9 +413,12 @@ int main(int argc, char** argv) { stack.clear(); // add the desired particle to the stack - stack.addParticle(std::make_tuple( + auto const primaryProperties = std::make_tuple( beamCode, calculate_kinetic_energy(plab.getNorm(), get_mass(beamCode)), - plab.normalized(), injectionPos, 0_ns)); + plab.normalized(), injectionPos, 0_ns); + stack.addParticle(primaryProperties); + + primaryWriter.recordPrimary(primaryProperties); // run the shower EAS.run(); @@ -424,11 +431,6 @@ int main(int argc, char** argv) { "relative difference (%): {}", Efinal / 1_GeV, (Efinal / E0 - 1) * 100); - auto const hists = sibyllCounted.getHistogram() + urqmdCounted.getHistogram(); - - save_hist(hists.labHist(), labHist_file, true); - save_hist(hists.CMSHist(), cMSHist_file, true); - // trigger the output manager to save this shower to disk output.endOfShower(); } diff --git a/examples/hybrid_MC.cpp b/examples/cascade_examples/mc_conex.cpp similarity index 81% rename from examples/hybrid_MC.cpp rename to examples/cascade_examples/mc_conex.cpp index cd819bdf1..cdee78eb4 100644 --- a/examples/hybrid_MC.cpp +++ b/examples/cascade_examples/mc_conex.cpp @@ -6,50 +6,43 @@ * 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/process/ProcessSequence.hpp> -#include <corsika/framework/process/SwitchProcessSequence.hpp> -#include <corsika/framework/process/InteractionCounter.hpp> -#include <corsika/framework/geometry/Plane.hpp> -#include <corsika/framework/geometry/Sphere.hpp> -#include <corsika/framework/geometry/PhysicalGeometry.hpp> -#include <corsika/framework/utility/SaveBoostHistogram.hpp> -#include <corsika/framework/utility/CorsikaFenv.hpp> +#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/core/Cascade.hpp> #include <corsika/framework/core/Step.hpp> -#include <corsika/framework/core/EnergyMomentumOperations.hpp> +#include <corsika/framework/geometry/PhysicalGeometry.hpp> +#include <corsika/framework/geometry/Plane.hpp> +#include <corsika/framework/geometry/Sphere.hpp> +#include <corsika/framework/process/InteractionCounter.hpp> +#include <corsika/framework/process/ProcessSequence.hpp> +#include <corsika/framework/process/SwitchProcessSequence.hpp> #include <corsika/framework/random/RNGManager.hpp> +#include <corsika/framework/utility/SaveBoostHistogram.hpp> +// #include <corsika/framework/utility/CorsikaFenv.hpp> -#include <corsika/output/OutputManager.hpp> -#include <corsika/modules/writers/SubWriter.hpp> #include <corsika/modules/writers/EnergyLossWriter.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/FlatExponential.hpp> #include <corsika/media/LayeredSphericalAtmosphereBuilder.hpp> -#include <corsika/media/NuclearComposition.hpp> #include <corsika/media/MediumPropertyModel.hpp> -#include <corsika/media/UniformMagneticField.hpp> #include <corsika/media/ShowerAxis.hpp> -#include <corsika/media/CORSIKA7Atmospheres.hpp> +#include <corsika/media/UniformMagneticField.hpp> #include <corsika/modules/BetheBlochPDG.hpp> #include <corsika/modules/LongitudinalProfile.hpp> #include <corsika/modules/ObservationPlane.hpp> -#include <corsika/modules/TrackWriter.hpp> #include <corsika/modules/ParticleCut.hpp> +#include <corsika/modules/PROPOSAL.hpp> #include <corsika/modules/Pythia8.hpp> #include <corsika/modules/Sibyll.hpp> +#include <corsika/modules/TrackWriter.hpp> #include <corsika/modules/UrQMD.hpp> -#include <corsika/modules/PROPOSAL.hpp> #include <corsika/modules/CONEX.hpp> #include <corsika/setup/SetupStack.hpp> @@ -63,6 +56,12 @@ using namespace corsika; using namespace std; +// +// An example of running an EAS where the hadronic cascade is +// handled by sibyll+URQMD and the EM cascade is treated with +// CONEX + Bethe Bloch (as opposed to PROPOSAL). +// + /** * Random number stream initialization * @@ -70,17 +69,19 @@ using namespace std; */ void registerRandomStreams(uint64_t seed) { RNGManager<>::getInstance().registerRandomStream("cascade"); - RNGManager<>::getInstance().registerRandomStream("qgsjet"); - RNGManager<>::getInstance().registerRandomStream("sibyll"); + RNGManager<>::getInstance().registerRandomStream("conex"); RNGManager<>::getInstance().registerRandomStream("epos"); + RNGManager<>::getInstance().registerRandomStream("proposal"); RNGManager<>::getInstance().registerRandomStream("pythia"); + RNGManager<>::getInstance().registerRandomStream("qgsjet"); + RNGManager<>::getInstance().registerRandomStream("sibyll"); RNGManager<>::getInstance().registerRandomStream("urqmd"); - RNGManager<>::getInstance().registerRandomStream("proposal"); - RNGManager<>::getInstance().registerRandomStream("conex"); if (seed == 0) { std::random_device rd; seed = rd(); - CORSIKA_LOG_INFO("new random seed (auto) {}", seed); + CORSIKA_LOG_INFO("random seed (auto) {} ", seed); + } else { + CORSIKA_LOG_INFO("random seed {} ", seed); } RNGManager<>::getInstance().setSeed(seed); } @@ -141,8 +142,12 @@ private: /** * Selection of environment interface implementation: */ +using EnvironmentInterface = IMediumPropertyModel<IMagneticFieldModel<IMediumModel>>; +using EnvType = Environment<EnvironmentInterface>; template <typename T> using MyExtraEnv = MediumPropertyModel<UniformMagneticField<T>>; +using StackType = setup::Stack<EnvType>; +using TrackingType = setup::Tracking; int main(int argc, char** argv) { @@ -157,7 +162,6 @@ int main(int argc, char** argv) { " if no seed is given, a random seed is chosen"); return 1; } - feenableexcept(FE_INVALID); uint64_t seed = 0; if (argc > 4) seed = std::stol(std::string(argv[4])); @@ -165,20 +169,15 @@ int main(int argc, char** argv) { registerRandomStreams(seed); // setup environment, geometry - using EnvironmentInterface = IMediumPropertyModel<IMagneticFieldModel<IMediumModel>>; - using EnvType = Environment<EnvironmentInterface>; EnvType env; CoordinateSystemPtr const& rootCS = env.getCoordinateSystem(); Point const center{rootCS, 0_m, 0_m, 0_m}; // build a Linsley US Standard atmosphere into `env` + MagneticFieldVector bField{rootCS, 50_uT, 0_T, 0_T}; create_5layer_atmosphere<EnvironmentInterface, MyExtraEnv>( - env, AtmosphereId::LinsleyUSStd, center, Medium::AirDry1Atm, - MagneticFieldVector{rootCS, 0_T, 50_uT, 0_T}); + env, AtmosphereId::LinsleyUSStd, center, Medium::AirDry1Atm, bField); - // setup particle stack, and add primary particle - setup::Stack<EnvType> stack; - stack.clear(); unsigned short const A = std::stoi(std::string(argv[1])); unsigned short const Z = std::stoi(std::string(argv[2])); Code const beamCode = get_nucleus_code(A, Z); @@ -194,12 +193,6 @@ int main(int argc, char** argv) { auto const [px, py, pz] = momentumComponents(thetaRad, P0); auto plab = MomentumVector(rootCS, {px, py, pz}); - CORSIKA_LOG_INFO( - "input particle: {}, " - "input angles: theta={}, " - "input momentum: {} GeV, " - ", norm={}", - beamCode, theta, plab.getComponents() / 1_GeV, plab.getNorm()); auto const observationHeight = 0_km + constants::EarthRadius::Mean; auto const injectionHeight = 112.75_km + constants::EarthRadius::Mean; @@ -211,28 +204,25 @@ int main(int argc, char** argv) { showerCore + Vector<dimensionless_d>{rootCS, {-sin(thetaRad), 0, cos(thetaRad)}} * t; - CORSIKA_LOG_INFO("point of injection: {} ", injectionPos.getCoordinates()); - - stack.addParticle(std::make_tuple( - Code::Proton, calculate_kinetic_energy(plab.getNorm(), get_mass(beamCode)), - plab.normalized(), injectionPos, 0_ns)); - - CORSIKA_LOG_INFO("shower axis length: {} m", - (showerCore - injectionPos).getNorm() * 1.02); - - OutputManager output("hybrid_MC_outputs"); ShowerAxis const showerAxis{injectionPos, (showerCore - injectionPos) * 1.02, env, false, 1000}; + auto const dX = 10_g / square(1_cm); // Binning of the writers along the shower axis + uint const nAxisBins = showerAxis.getMaximumX() / dX + 1; // Get maximum number of bins + + CORSIKA_LOG_INFO("Primary particle: {}", beamCode); + CORSIKA_LOG_INFO("Zenith angle: {} (rad)", theta); + CORSIKA_LOG_INFO("Momentum: {} (GeV)", plab.getComponents() / 1_GeV); + CORSIKA_LOG_INFO("Propagation dir: {}", plab.getNorm()); + CORSIKA_LOG_INFO("Injection point: {}", injectionPos.getCoordinates()); + CORSIKA_LOG_INFO("shower axis length: {} ", + (showerCore - injectionPos).getNorm() * 1.02); - // setup processes, decays and interactions + // SETUP WRITERS - corsika::sibyll::Interaction sibyll{env}; - InteractionCounter sibyllCounted{sibyll}; - - corsika::pythia8::Decay decayPythia; + OutputManager output("hybrid_MC_outputs"); // register energy losses as output - EnergyLossWriter dEdX{showerAxis, 10_g / square(1_cm), 200}; + EnergyLossWriter dEdX{showerAxis, dX, nAxisBins}; output.add("energyloss", dEdX); // create a track writer and register it with the output manager @@ -242,19 +232,29 @@ int main(int argc, char** argv) { ParticleCut<SubWriter<decltype(dEdX)>> cut(3_GeV, false, dEdX); BetheBlochPDG<SubWriter<decltype(dEdX)>> eLoss(dEdX); - LongitudinalWriter profile{showerAxis, 10_g / square(1_cm)}; + LongitudinalWriter profile{showerAxis, nAxisBins, dX}; output.add("profile", profile); LongitudinalProfile<SubWriter<decltype(profile)>> longprof{profile}; + Plane const obsPlane(showerCore, DirectionVector(rootCS, {0., 0., 1.})); + ObservationPlane<TrackingType> observationLevel(obsPlane, + DirectionVector(rootCS, {1., 0., 0.})); + output.add("particles", observationLevel); + + PrimaryWriter<TrackingType, ParticleWriterParquet> primaryWriter(observationLevel); + output.add("primary", primaryWriter); + + // SETUP PROCESSES, DECAYS, INTERACTIONS + + corsika::sibyll::Interaction sibyll{env}; + InteractionCounter sibyllCounted{sibyll}; + + corsika::pythia8::Decay decayPythia; + CONEXhybrid // SubWriter<decltype(dEdX>, SubWriter<decltype(profile)>> conex_model(center, showerAxis, t, injectionHeight, E0, get_PDG(Code::Proton), dEdX, profile); - Plane const obsPlane(showerCore, DirectionVector(rootCS, {0., 0., 1.})); - ObservationPlane<setup::Tracking> observationLevel( - obsPlane, DirectionVector(rootCS, {1., 0., 0.}), "particles.dat"); - output.add("obsplane", observationLevel); - corsika::urqmd::UrQMD urqmd_model; InteractionCounter urqmdCounted{urqmd_model}; @@ -265,7 +265,7 @@ int main(int argc, char** argv) { HEPEnergyType cutE_; EnergySwitch(HEPEnergyType cutE) : cutE_(cutE) {} - bool operator()(const setup::Stack<EnvType>::particle_type& p) const { + bool operator()(const StackType::particle_type& p) const { return (p.getEnergy() < cutE_); } }; @@ -273,17 +273,27 @@ int main(int argc, char** argv) { auto sequence = make_sequence(hadronSequence, decayPythia, eLoss, cut, conex_model, longprof, observationLevel, trackCheck); + StackType stack; + stack.clear(); + // define air shower object, run simulation - setup::Tracking tracking; + TrackingType tracking; Cascade EAS(env, tracking, sequence, output, stack); + output.startOfLibrary(); + + auto const primaryProperties = std::make_tuple( + Code::Proton, calculate_kinetic_energy(plab.getNorm(), get_mass(beamCode)), + plab.normalized(), injectionPos, 0_ns); + + stack.addParticle(primaryProperties); + primaryWriter.recordPrimary(primaryProperties); + // to fix the point of first interaction, uncomment the following two lines: // EAS.SetNodes(); // EAS.forceInteraction(); - output.startOfLibrary(); EAS.run(); - output.endOfLibrary(); const HEPEnergyType Efinal = dEdX.getEnergyLost() + observationLevel.getEnergyGround(); CORSIKA_LOG_INFO( @@ -296,5 +306,7 @@ int main(int argc, char** argv) { save_hist(hists.labHist(), "inthist_lab_hybrid.npz", true); save_hist(hists.CMSHist(), "inthist_cms_hybrid.npz", true); + output.endOfLibrary(); + CORSIKA_LOG_INFO("done"); } diff --git a/examples/radio_em_shower.cpp b/examples/cascade_examples/radio_em_shower.cpp similarity index 58% rename from examples/radio_em_shower.cpp rename to examples/cascade_examples/radio_em_shower.cpp index c574755f7..65a0b1485 100644 --- a/examples/radio_em_shower.cpp +++ b/examples/cascade_examples/radio_em_shower.cpp @@ -21,10 +21,11 @@ #include <corsika/framework/utility/CorsikaFenv.hpp> #include <corsika/framework/utility/SaveBoostHistogram.hpp> -#include <corsika/output/OutputManager.hpp> -#include <corsika/modules/writers/SubWriter.hpp> #include <corsika/modules/writers/EnergyLossWriter.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/Environment.hpp> #include <corsika/media/LayeredSphericalAtmosphereBuilder.hpp> @@ -64,6 +65,13 @@ using namespace corsika; using namespace std; +// +// An example of running an casacde which generates radio input for a +// cascade that has hadronic interactions turned off. Currently, this +// will produce output for only one antenna, but there are lines below, +// which are commented out, to enable a full star-shape pattern of antennas +// + void registerRandomStreams(int seed) { RNGManager<>::getInstance().registerRandomStream("cascade"); RNGManager<>::getInstance().registerRandomStream("proposal"); @@ -72,14 +80,21 @@ void registerRandomStreams(int seed) { if (seed == 0) { std::random_device rd; seed = rd(); - cout << "new random seed (auto) " << seed << endl; + CORSIKA_LOG_INFO("random seed (auto) {} ", seed); + } else { + CORSIKA_LOG_INFO("random seed {} ", seed); } RNGManager<>::getInstance().setSeed(seed); } +using EnvironmentInterface = + IRefractiveIndexModel<IMediumPropertyModel<IMagneticFieldModel<IMediumModel>>>; +using EnvType = Environment<EnvironmentInterface>; template <typename TInterface> using MyExtraEnv = UniformRefractiveIndex<MediumPropertyModel<UniformMagneticField<TInterface>>>; +using StackType = setup::Stack<EnvType>; +using TrackingType = setup::Tracking; int main(int argc, char** argv) { @@ -93,22 +108,21 @@ int main(int argc, char** argv) { } int seed{static_cast<int>(std::stof(std::string(argv[2])))}; - std::cout << "Seed: " << seed << std::endl; + CORSIKA_LOG_INFO("Seed {}", seed); feenableexcept(FE_INVALID); // initialize random number sequence(s) registerRandomStreams(seed); // setup environment, geometry - using EnvironmentInterface = - IRefractiveIndexModel<IMediumPropertyModel<IMagneticFieldModel<IMediumModel>>>; - using EnvType = Environment<EnvironmentInterface>; EnvType env; CoordinateSystemPtr const& rootCS = env.getCoordinateSystem(); Point const center{rootCS, 0_m, 0_m, 0_m}; + double const refractive_index = 1.000327; + MagneticFieldVector const bField{rootCS, 50_uT, 0_T, 0_T}; create_5layer_atmosphere<EnvironmentInterface, MyExtraEnv>( - env, AtmosphereId::LinsleyUSStd, center, 1.000327, Medium::AirDry1Atm, - MagneticFieldVector{rootCS, 50_uT, 0_T, 0_T}); + env, AtmosphereId::LinsleyUSStd, center, refractive_index, Medium::AirDry1Atm, + bField); std::unordered_map<Code, HEPEnergyType> energy_resolution = { {Code::Electron, 5_MeV}, @@ -118,26 +132,19 @@ int main(int argc, char** argv) { for (auto [pcode, energy] : energy_resolution) set_energy_production_threshold(pcode, energy); - // setup particle stack, and add primary particle - setup::Stack<EnvType> stack; - stack.clear(); - const Code beamCode = Code::Electron; + Code const beamCode = Code::Electron; auto const mass = get_mass(beamCode); - const HEPEnergyType E0 = 1_GeV * std::stof(std::string(argv[1])); - double theta = 0.; + HEPEnergyType const E0 = 1_GeV * std::stof(std::string(argv[1])); + double const theta = 0.; auto const thetaRad = theta / 180. * M_PI; - HEPMomentumType P0 = calculate_momentum(E0, mass); + HEPMomentumType const P0 = calculate_momentum(E0, mass); auto momentumComponents = [](double thetaRad, HEPMomentumType ptot) { return std::make_tuple(ptot * sin(thetaRad), 0_eV, -ptot * cos(thetaRad)); }; auto const [px, py, pz] = momentumComponents(thetaRad, P0); - auto plab = MomentumVector(rootCS, {px, py, pz}); - cout << "input particle: " << beamCode << endl; - cout << "input angles: theta=" << theta << endl; - cout << "input momentum: " << plab.getComponents() / 1_GeV - << ", norm = " << plab.getNorm() << endl; + auto const plab = MomentumVector(rootCS, {px, py, pz}); auto const observationHeight = 1.4_km + constants::EarthRadius::Mean; auto const injectionHeight = 112.75_km + constants::EarthRadius::Mean; @@ -148,104 +155,103 @@ int main(int argc, char** argv) { Point const injectionPos = showerCore + DirectionVector{rootCS, {-sin(thetaRad), 0, cos(thetaRad)}} * t; - std::cout << "point of injection: " << injectionPos.getCoordinates() << std::endl; - - stack.addParticle(std::make_tuple( - beamCode, calculate_kinetic_energy(plab.getNorm(), get_mass(beamCode)), - plab.normalized(), injectionPos, 0_ns)); - - CORSIKA_LOG_INFO("shower axis length: {} ", - (showerCore - injectionPos).getNorm() * 1.02); - ShowerAxis const showerAxis{injectionPos, (showerCore - injectionPos) * 1.02, env, false, 1000}; + auto const dX = 10_g / square(1_cm); // Binning of the writers along the shower axis + uint const nAxisBins = showerAxis.getMaximumX() / dX + 1; // Get maximum number of bins + // setup the radio antennas TimeType const groundHitTime{(showerCore - injectionPos).getNorm() / constants::c}; - std::string outname_ = "radio_em_shower_outputs"; // + std::to_string(rr_); - OutputManager output(outname_); - // Radio antennas and relevant information // the antenna time variables - const TimeType duration_{1e-6_s}; - const InverseTimeType sampleRate_{1e+9_Hz}; + TimeType const duration{1e-6_s}; + InverseTimeType const sampleRate{1e+9_Hz}; // the detector (aka antenna collection) for CoREAS and ZHS AntennaCollection<TimeDomainAntenna> detectorCoREAS; AntennaCollection<TimeDomainAntenna> 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_)}; - std::cout << "Trigger Point is: " << triggerpoint_ << std::endl; + 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)}; + + CORSIKA_LOG_INFO("Primary particle: {}", beamCode); + CORSIKA_LOG_INFO("Zenith angle: {} (rad)", theta); + CORSIKA_LOG_INFO("Momentum: {} (GeV)", plab.getComponents() / 1_GeV); + CORSIKA_LOG_INFO("Propagation dir: {}", plab.getNorm()); + CORSIKA_LOG_INFO("Injection point: {}", injectionPos.getCoordinates()); + CORSIKA_LOG_INFO("shower axis length: {} ", + (showerCore - injectionPos).getNorm() * 1.02); + CORSIKA_LOG_INFO("Trigger Point is: {}", triggerpoint); // // setup CoREAS antennas - use the for loop for star shape pattern - // for (auto radius_1 = 25_m; radius_1 <= 500_m; radius_1 += 25_m) { - // for (auto phi_1 = 0; phi_1 <= 315; phi_1 += 45) { - auto radius_1 = 200_m; - auto phi_1 = 45; - auto phiRad_1 = phi_1 / 180. * M_PI; - auto rr_1 = static_cast<int>(radius_1 / 1_m); - auto const point_1{Point(rootCS, showerCoreX_ + radius_1 * cos(phiRad_1), - showerCoreY_ + radius_1 * sin(phiRad_1), - constants::EarthRadius::Mean)}; - std::cout << "Antenna point: " << point_1 << std::endl; - auto triggertime_1{(triggerpoint_ - point_1).getNorm() / constants::c}; - std::string name_1 = - "CoREAS_R=" + std::to_string(rr_1) + "_m--Phi=" + std::to_string(phi_1) + "degrees"; - TimeDomainAntenna antenna_1(name_1, point_1, rootCS, triggertime_1, duration_, - sampleRate_, triggertime_1); - detectorCoREAS.addAntenna(antenna_1); + // for (auto radius_coreas = 25_m; radius_coreas <= 500_m; radius_coreas += 25_m) { + // for (auto phi_coreas = 0; phi_coreas <= 315; phi_coreas += 45) { + auto radius_coreas = 200_m; + auto phi_coreas = 45; + auto phiRad_coreas = phi_coreas / 180. * M_PI; + auto rr_coreas = static_cast<int>(radius_coreas / 1_m); + auto const point_coreas{Point(rootCS, showerCoreX + radius_coreas * cos(phiRad_coreas), + showerCoreY + radius_coreas * sin(phiRad_coreas), + constants::EarthRadius::Mean)}; + std::cout << "Antenna point: " << point_coreas << std::endl; + CORSIKA_LOG_INFO("Antenna point {}", injectionPos.getCoordinates()); + auto triggertime_coreas{(triggerpoint - point_coreas).getNorm() / constants::c}; + std::string name_coreas = "CoREAS_R=" + std::to_string(rr_coreas) + + "_m--Phi=" + std::to_string(phi_coreas) + "degrees"; + TimeDomainAntenna antenna_coreas(name_coreas, point_coreas, rootCS, triggertime_coreas, + duration, sampleRate, triggertime_coreas); + detectorCoREAS.addAntenna(antenna_coreas); // } // } // // setup ZHS antennas - use the for loop for star shape pattern - // for (auto radius_ = 25_m; radius_ <= 500_m; radius_ += 25_m) { - // for (auto phi_ = 0; phi_ <= 315; phi_ += 45) { - auto radius_ = 200_m; - auto phi_ = 45; - auto phiRad_ = phi_ / 180. * M_PI; - auto rr_ = static_cast<int>(radius_ / 1_m); - auto const point_{Point(rootCS, showerCoreX_ + radius_ * cos(phiRad_), - showerCoreY_ + radius_ * sin(phiRad_), - constants::EarthRadius::Mean)}; - auto triggertime_{(triggerpoint_ - point_).getNorm() / constants::c}; - std::string name_ = - "ZHS_R=" + std::to_string(rr_) + "_m--Phi=" + std::to_string(phi_) + "degrees"; - TimeDomainAntenna antenna_(name_, point_, rootCS, triggertime_, duration_, sampleRate_, - triggertime_); - detectorZHS.addAntenna(antenna_); + // for (auto radius_zhs = 25_m; radius_zhs <= 500_m; radius_zhs += 25_m) { + // for (auto phi_zhs = 0; phi_zhs <= 315; phi_zhs += 45) { + auto radius_zhs = 200_m; + auto phi_zhs = 45; + auto phiRad_zhs = phi_zhs / 180. * M_PI; + auto rr_zhs = static_cast<int>(radius_zhs / 1_m); + auto const point_zhs{Point(rootCS, showerCoreX + radius_zhs * cos(phiRad_zhs), + showerCoreY + radius_zhs * sin(phiRad_zhs), + constants::EarthRadius::Mean)}; + auto triggertime_zhs{(triggerpoint - point_zhs).getNorm() / constants::c}; + std::string name_zhs = "ZHS_R=" + std::to_string(rr_zhs) + + "_m--Phi=" + std::to_string(phi_zhs) + "degrees"; + TimeDomainAntenna antenna_zhs(name_zhs, point_zhs, rootCS, triggertime_zhs, duration, + sampleRate, triggertime_zhs); + detectorZHS.addAntenna(antenna_zhs); // } // } // setup processes, decays and interactions - - EnergyLossWriter dEdX{showerAxis, 10_g / square(1_cm), 200}; - // register energy losses as output - output.add("dEdX", dEdX); - - ParticleCut<SubWriter<decltype(dEdX)>> cut(5_MeV, 5_MeV, 100_GeV, 100_GeV, true, dEdX); - - corsika::sophia::InteractionModel sophia; + EnergyLossWriter energyloss{showerAxis, dX, nAxisBins}; + ParticleCut<SubWriter<decltype(energyloss)>> cut(5_MeV, 5_MeV, 100_GeV, 100_GeV, true, + energyloss); corsika::sibyll::Interaction sibyll{env}; + corsika::sophia::InteractionModel sophia; HEPEnergyType heThresholdNN = 80_GeV; corsika::proposal::Interaction emCascade( env, sophia, sibyll.getHadronInteractionModel(), heThresholdNN); - corsika::proposal::ContinuousProcess<SubWriter<decltype(dEdX)>> emContinuous(env, dEdX); - // BetheBlochPDG<SubWriter<decltype(dEdX)>> emContinuous{dEdX}; + corsika::proposal::ContinuousProcess<SubWriter<decltype(energyloss)>> emContinuous( + env, energyloss); // NOT possible right now, due to interface differenc in PROPOSAL // InteractionCounter emCascadeCounted(emCascade); + OutputManager output("radio_em_shower_outputs"); + + output.add("energyloss", energyloss); + TrackWriter tracks; output.add("tracks", tracks); - // long. profile - LongitudinalWriter profile{showerAxis, 10_g / square(1_cm)}; + LongitudinalWriter profile{showerAxis, nAxisBins, dX}; output.add("profile", profile); LongitudinalProfile<SubWriter<decltype(profile)>> longprof{profile}; @@ -269,15 +275,27 @@ int main(int argc, char** argv) { output.add("ZHS", zhs); Plane const obsPlane(showerCore, DirectionVector(rootCS, {0., 0., 1.})); - ObservationPlane<setup::Tracking, ParticleWriterParquet> observationLevel{ + ObservationPlane<TrackingType, ParticleWriterParquet> observationLevel{ obsPlane, DirectionVector(rootCS, {1., 0., 0.})}; output.add("particles", observationLevel); - // auto sequence = make_sequence(emCascade, emContinuous, longprof, cut, coreas, zhs); + PrimaryWriter<TrackingType, ParticleWriterParquet> primaryWriter(observationLevel); + output.add("primary", primaryWriter); + auto sequence = make_sequence(emCascade, emContinuous, longprof, coreas, zhs, tracks, observationLevel, cut); // define air shower object, run simulation - setup::Tracking tracking; + TrackingType tracking; + + auto const primaryProperties = std::make_tuple( + beamCode, calculate_kinetic_energy(plab.getNorm(), get_mass(beamCode)), + plab.normalized(), injectionPos, 0_ns); + + // setup particle stack, and add primary particle + StackType stack; + stack.clear(); + stack.addParticle(primaryProperties); + primaryWriter.recordPrimary(primaryProperties); output.startOfLibrary(); Cascade EAS(env, tracking, sequence, output, stack); @@ -287,7 +305,8 @@ int main(int argc, char** argv) { EAS.run(); - HEPEnergyType const Efinal = dEdX.getEnergyLost() + observationLevel.getEnergyGround(); + HEPEnergyType const Efinal = + energyloss.getEnergyLost() + observationLevel.getEnergyGround(); CORSIKA_LOG_INFO( "total energy budget (GeV): {}, " @@ -295,4 +314,6 @@ int main(int argc, char** argv) { Efinal / 1_GeV, (Efinal / E0 - 1) * 100); output.endOfLibrary(); + + return EXIT_SUCCESS; } diff --git a/examples/water.cpp b/examples/cascade_examples/water.cpp similarity index 72% rename from examples/water.cpp rename to examples/cascade_examples/water.cpp index 577ce4ad8..324e2e732 100644 --- a/examples/water.cpp +++ b/examples/cascade_examples/water.cpp @@ -24,15 +24,16 @@ #include <corsika/media/ShowerAxis.hpp> #include <corsika/modules/ObservationPlane.hpp> #include <corsika/modules/LongitudinalProfile.hpp> -#include <corsika/modules/writers/SubWriter.hpp> -#include <corsika/modules/writers/LongitudinalWriter.hpp> #include <corsika/modules/writers/EnergyLossWriter.hpp> +#include <corsika/modules/writers/LongitudinalWriter.hpp> +#include <corsika/modules/writers/PrimaryWriter.hpp> +#include <corsika/modules/writers/SubWriter.hpp> #include <corsika/modules/PROPOSAL.hpp> #include <corsika/modules/ParticleCut.hpp> #include <corsika/modules/Pythia8.hpp> #include <corsika/modules/Sibyll.hpp> #include <corsika/modules/Sophia.hpp> -#include <corsika/modules/UrQMD.hpp> +#include <corsika/modules/FLUKA.hpp> #include <corsika/modules/tracking/TrackingStraight.hpp> #include <corsika/output/OutputManager.hpp> @@ -41,6 +42,7 @@ #include <corsika/stack/VectorStack.hpp> #include <corsika/setup/SetupStack.hpp> +#include <corsika/setup/SetupTrajectory.hpp> #include <CLI/App.hpp> #include <CLI/Config.hpp> @@ -50,9 +52,9 @@ using namespace corsika; using IMediumType = IMediumPropertyModel<IMediumModel>; using EnvType = Environment<IMediumType>; -using StackActive = setup::Stack<EnvType>; -using StackView = StackActive::stack_view_type; -using Particle = StackActive::particle_type; +using StackType = setup::Stack<EnvType>; +using TrackingType = tracking_line::Tracking; +using Particle = StackType::particle_type; void registerRandomStreams(int seed) { RNGManager<>::getInstance().registerRandomStream("cascade"); @@ -61,7 +63,7 @@ void registerRandomStreams(int seed) { RNGManager<>::getInstance().registerRandomStream("sophia"); RNGManager<>::getInstance().registerRandomStream("epos"); RNGManager<>::getInstance().registerRandomStream("pythia"); - RNGManager<>::getInstance().registerRandomStream("urqmd"); + RNGManager<>::getInstance().registerRandomStream("fluka"); RNGManager<>::getInstance().registerRandomStream("proposal"); if (seed == 0) { std::random_device rd; @@ -75,12 +77,12 @@ void registerRandomStreams(int seed) { int main(int argc, char** argv) { // * process input - Code primaryType; - HEPEnergyType e0, eCut; + Code beamCode; + HEPEnergyType E0, eCut; int A, Z, n_event; int randomSeed; std::string output_dir; - CLI::App app{"Neutrino event generator"}; + CLI::App app{"Cascade in water"}; // 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)) @@ -110,8 +112,25 @@ int main(int argc, char** argv) { app.add_option("-s", randomSeed, "Seed for random number") ->check(CLI::NonNegativeNumber) ->default_val(0); + + // parse the command line options into the variables CLI11_PARSE(app, argc, argv); + std::string_view const loglevel = app["-v"]->as<std::string_view>(); + 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 @@ -121,37 +140,24 @@ int main(int argc, char** argv) { return 1; } } + + // initialize random number sequence(s) + registerRandomStreams(randomSeed); + // check if we want to use a PDG code instead if (app.count("--pdg") > 0) { - primaryType = convert_from_PDG(PDGCode(app["--pdg"]->as<int>())); + beamCode = convert_from_PDG(PDGCode(app["--pdg"]->as<int>())); } else { // check manually for proton and neutrons if ((A == 1) && (Z == 1)) - primaryType = Code::Proton; + beamCode = Code::Proton; else if ((A == 1) && (Z == 0)) - primaryType = Code::Neutron; + beamCode = Code::Neutron; else - primaryType = get_nucleus_code(A, Z); + beamCode = get_nucleus_code(A, Z); } - e0 = app["-E"]->as<double>() * 1_GeV; eCut = app["--eCut"]->as<double>() * 1_GeV; - std::string_view const loglevel = app["-v"]->as<std::string_view>(); - 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); - } - - registerRandomStreams(randomSeed); // * environment and universe EnvType env; @@ -163,27 +169,26 @@ int main(int argc, char** argv) { Point const center{rootCS, 0_m, 0_m, 0_m}; auto sphere = std::make_unique<Sphere>(center, 100_m); auto node = std::make_unique<VolumeTreeNode<IMediumType>>(std::move(sphere)); - // Hydrogen is not supported by UrQMD yet. See #456 - auto comp = NuclearComposition({{Code::Oxygen}, {1.0}}); + NuclearComposition const nuclearComposition{{Code::Hydrogen, Code::Oxygen}, + {2.0 / 3.0, 1.0 / 3.0}}; // density of sea water auto density = 1.02_g / (1_cm * 1_cm * 1_cm); auto water_medium = std::make_shared<MediumPropertyModel<HomogeneousMedium<IMediumType>>>( - Medium::WaterLiquid, density, comp); + Medium::WaterLiquid, density, nuclearComposition); node->setModelProperties(water_medium); universe->addChild(std::move(node)); } - // * detector geometry + // * make downward-going shower axis and a observation plane in x-y-plane auto injectorLength = 50_m; - Point const injectorPos = Point(rootCS, {0_m, 0_m, injectorLength}); - auto const& injectCS = make_translation(rootCS, injectorPos.getCoordinates()); + Point const injectionPos = Point(rootCS, {0_m, 0_m, injectorLength}); + auto const& injectCS = make_translation(rootCS, injectionPos.getCoordinates()); DirectionVector upVec(rootCS, {0., 0., 1.}); DirectionVector leftVec(rootCS, {1., 0., 0.}); DirectionVector downVec(rootCS, {0., 0., -1.}); - // * observation plane - std::vector<ObservationPlane<tracking_line::Tracking>> obsPlanes; + std::vector<ObservationPlane<TrackingType, ParticleWriterParquet>> obsPlanes; const int nPlane = 5; for (int i = 0; i < nPlane - 1; i++) { Point planeCenter{injectCS, {0_m, 0_m, -(i + 1) * 3_m}}; @@ -193,12 +198,14 @@ int main(int argc, char** argv) { Plane{Point{injectCS, {0_m, 0_m, -50_m}}, upVec}, leftVec, true); // * longitutional profile - ShowerAxis const showerAxis{injectorPos, 1.2 * injectorLength * downVec, env}; - LongitudinalWriter longiWriter{showerAxis, 5500, 1_g / square(1_cm)}; + ShowerAxis const showerAxis{injectionPos, 1.2 * injectorLength * downVec, env}; + auto const dX = 1_g / square(1_cm); // Binning of the writers along the shower axis + uint const nAxisBins = showerAxis.getMaximumX() / dX + 1; // Get maximum number of bins + LongitudinalWriter longiWriter{showerAxis, nAxisBins, dX}; LongitudinalProfile<SubWriter<decltype(longiWriter)>> longprof{longiWriter}; // * energy loss profile - EnergyLossWriter dEdX{showerAxis, 1_g / square(1_cm), 5500}; + EnergyLossWriter dEdX{showerAxis, dX, nAxisBins}; // * physical process list // particle production threshold @@ -207,19 +214,19 @@ int main(int argc, char** argv) { ParticleCut<SubWriter<decltype(dEdX)>> cut(emCut, emCut, hadCut, hadCut, true, dEdX); // hadronic interactions - HEPEnergyType heHadronModelThreshold = 63.1_GeV; + HEPEnergyType heHadronModelThreshold = std::pow(10, 1.9) * 1_GeV; corsika::sibyll::Interaction sibyll(env); - corsika::urqmd::UrQMD urqmd; - InteractionCounter urqmdCounted(urqmd); + + corsika::fluka::Interaction leIntModel{env}; + InteractionCounter leIntCounted{leIntModel}; struct EnergySwitch { HEPEnergyType cutE_; EnergySwitch(HEPEnergyType cutE) : cutE_(cutE) {} bool operator()(const Particle& p) const { return (p.getKineticEnergy() < cutE_); } }; - // auto lowModel = make_sequence(urqmd); auto hadronSequence = - make_select(EnergySwitch(heHadronModelThreshold), urqmdCounted, sibyll); + make_select(EnergySwitch(heHadronModelThreshold), leIntCounted, sibyll); // decay process corsika::pythia8::Decay decayPythia; @@ -243,19 +250,41 @@ int main(int argc, char** argv) { // hard coded auto obsPlaneSequence = make_sequence(obsPlanes[0], obsPlanes[1], obsPlanes[2], obsPlanes[3], obsPlanes[4]); - output.add("longi_profile", longiWriter); - output.add("energy_loss", dEdX); + + PrimaryWriter<TrackingType, ParticleWriterParquet> primaryWriter(obsPlanes.back()); + output.add("primary", primaryWriter); + + output.add("profile", longiWriter); + output.add("energyloss", dEdX); // * the final process sequence auto sequence = make_sequence(physics_sequence, longprof, obsPlaneSequence, cut); // * tracking and stack - tracking_line::Tracking tracking; - StackActive stack; + TrackingType tracking; + StackType stack; // * cascade manager Cascade EAS(env, tracking, sequence, output, stack); + E0 = app["-E"]->as<double>() * 1_GeV; + HEPEnergyType mass = get_mass(beamCode); + // convert Elab to Plab + HEPMomentumType P0 = calculate_momentum(E0, mass); + auto plab = MomentumVector(rootCS, P0 * downVec.getNorm()); + + // print our primary parameters all in one place + 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 Energy: {}", E0); + CORSIKA_LOG_INFO("Primary Momentum: {}", P0); + CORSIKA_LOG_INFO("Primary Direction: {}", plab.getNorm()); + CORSIKA_LOG_INFO("Point of Injection: {}", injectionPos.getCoordinates()); + CORSIKA_LOG_INFO("Shower Axis Length: {}", injectorLength); + // * main loop output.startOfLibrary(); for (int i_shower = 0; i_shower < n_event; i_shower++) { @@ -263,8 +292,11 @@ int main(int argc, char** argv) { CORSIKA_LOG_INFO("Event: {} / {}", i_shower, n_event); // * inject primary - auto primary = stack.addParticle(std::make_tuple( - primaryType, e0 - get_mass(primaryType), downVec, injectorPos, 0_ns)); + auto const primaryProperties = std::make_tuple( + beamCode, calculate_kinetic_energy(plab.getNorm(), get_mass(beamCode)), + plab.normalized(), injectionPos, 0_ns); + auto primary = stack.addParticle(primaryProperties); + stack.addParticle(primaryProperties); EAS.run(); @@ -273,8 +305,8 @@ int main(int argc, char** argv) { CORSIKA_LOG_INFO( "total energy budget (TeV): {:.2f} (dEdX={:.2f} ground={:.2f}), " "relative difference (%): {:.3f}", - e0 / 1_TeV, dEdX.getEnergyLost() / 1_TeV, obsPlaneFinal.getEnergyGround() / 1_TeV, - (Efinal / e0 - 1.) * 100.); + E0 / 1_TeV, dEdX.getEnergyLost() / 1_TeV, obsPlaneFinal.getEnergyGround() / 1_TeV, + (Efinal / E0 - 1.) * 100.); } output.endOfLibrary(); diff --git a/examples/cascade_proton_example.cpp b/examples/cascade_proton_example.cpp deleted file mode 100644 index 68c7c72cd..000000000 --- a/examples/cascade_proton_example.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* - * (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/framework/process/ProcessSequence.hpp> -#include <corsika/framework/process/SwitchProcessSequence.hpp> -#include <corsika/framework/core/Cascade.hpp> -#include <corsika/framework/core/PhysicalUnits.hpp> -#include <corsika/framework/core/Logging.hpp> -#include <corsika/framework/core/EnergyMomentumOperations.hpp> -#include <corsika/framework/random/RNGManager.hpp> -#include <corsika/framework/geometry/Sphere.hpp> -#include <corsika/framework/utility/CorsikaFenv.hpp> - -#include <corsika/output/OutputManager.hpp> -#include <corsika/modules/writers/SubWriter.hpp> -#include <corsika/modules/writers/EnergyLossWriter.hpp> - -#include <corsika/media/Environment.hpp> -#include <corsika/media/HomogeneousMedium.hpp> -#include <corsika/media/NuclearComposition.hpp> -#include <corsika/media/ShowerAxis.hpp> -#include <corsika/media/MediumPropertyModel.hpp> -#include <corsika/media/UniformMagneticField.hpp> - -#include <corsika/setup/SetupStack.hpp> -#include <corsika/setup/SetupTrajectory.hpp> - -#include <corsika/modules/BetheBlochPDG.hpp> -#include <corsika/modules/StackInspector.hpp> -#include <corsika/modules/Sibyll.hpp> -#include <corsika/modules/ParticleCut.hpp> -#include <corsika/modules/TrackWriter.hpp> -#include <corsika/modules/HadronicElasticModel.hpp> -#include <corsika/modules/Pythia8.hpp> -#include <corsika/modules/Sibyll.hpp> - -#include <iostream> -#include <limits> -#include <typeinfo> - -using namespace corsika; -using namespace std; - -// -// The example main program for a particle cascade -// -int main() { - - logging::set_level(logging::level::warn); - - std::cout << "cascade_proton_example" << std::endl; - - feenableexcept(FE_INVALID); - // initialize random number sequence(s) - RNGManager<>::getInstance().registerRandomStream("cascade"); - - OutputManager output("cascade_proton_outputs"); - - // setup environment, geometry - using EnvironmentInterface = IMediumPropertyModel<IMagneticFieldModel<IMediumModel>>; - using EnvType = Environment<EnvironmentInterface>; - EnvType env; - auto& universe = *(env.getUniverse()); - CoordinateSystemPtr const& rootCS = env.getCoordinateSystem(); - - auto world = EnvType::createNode<Sphere>(Point{rootCS, 0_m, 0_m, 0_m}, 150_km); - - using MyHomogeneousModel = - MediumPropertyModel<UniformMagneticField<HomogeneousMedium<EnvironmentInterface>>>; - - world->setModelProperties<MyHomogeneousModel>( - Medium::AirDry1Atm, MagneticFieldVector(rootCS, 0_T, 0_T, 1_mT), - 1_kg / (1_m * 1_m * 1_m), NuclearComposition({Code::Proton}, {1.})); - - universe.addChild(std::move(world)); - - // setup particle stack, and add primary particle - setup::Stack<EnvType> stack; - stack.clear(); - const Code beamCode = Code::Proton; - const HEPMassType mass = Proton::mass; - const HEPEnergyType E0 = 200_GeV; - double theta = 0.; - double phi = 0.; - - Point injectionPos(rootCS, 0_m, 0_m, 0_m); - { - auto elab2plab = [](HEPEnergyType Elab, HEPMassType m) { - return sqrt(Elab * Elab - m * m); - }; - HEPMomentumType P0 = elab2plab(E0, mass); - auto momentumComponents = [](double theta, double phi, HEPMomentumType ptot) { - return std::make_tuple(ptot * sin(theta) * cos(phi), ptot * sin(theta) * sin(phi), - -ptot * cos(theta)); - }; - auto const [px, py, pz] = - momentumComponents(theta / 180. * M_PI, phi / 180. * M_PI, P0); - auto plab = MomentumVector(rootCS, {px, py, pz}); - cout << "input particle: " << beamCode << endl; - cout << "input angles: theta=" << theta << " phi=" << phi << endl; - cout << "input momentum: " << plab.getComponents() / 1_GeV << endl; - stack.addParticle(std::make_tuple( - beamCode, calculate_kinetic_energy(plab.getNorm(), get_mass(beamCode)), - plab.normalized(), injectionPos, 0_ns)); - } - - // setup processes, decays and interactions - setup::Tracking tracking; - StackInspector<setup::Stack<EnvType>> stackInspect(1000, true, E0); - - RNGManager<>::getInstance().registerRandomStream("pythia"); - RNGManager<>::getInstance().registerRandomStream("sibyll"); - corsika::sibyll::Interaction sibyll{env}; - // corsika::pythia8::Interaction pythia; - corsika::pythia8::Decay decay; - - ShowerAxis const showerAxis{injectionPos, Vector{rootCS, 0_m, 0_m, -100_km}, env}; - EnergyLossWriter dEdX{showerAxis}; - output.add("energyloss", dEdX); - - BetheBlochPDG<SubWriter<decltype(dEdX)>> eLoss{dEdX}; - ParticleCut<SubWriter<decltype(dEdX)>> cut(60_GeV, true, dEdX); - cut.printThresholds(); - - // RNGManager::getInstance().registerRandomStream("HadronicElasticModel"); - // HadronicElasticModel::HadronicElasticInteraction - // hadronicElastic(env); - - TrackWriter trackWriter; - output.add("tracks", trackWriter); // register TrackWriter - - // assemble all processes into an ordered process list - auto sequence = make_sequence(sibyll, decay, eLoss, trackWriter, stackInspect, cut); - - // define air shower object, run simulation - Cascade EAS(env, tracking, sequence, output, stack); - output.startOfLibrary(); - EAS.run(); - output.endOfLibrary(); - - CORSIKA_LOG_INFO("Done"); -} diff --git a/examples/boundary_example.cpp b/examples/framework_examples/boundary_crossing.cpp similarity index 94% rename from examples/boundary_example.cpp rename to examples/framework_examples/boundary_crossing.cpp index 895b5214e..d470a4c3c 100644 --- a/examples/boundary_example.cpp +++ b/examples/framework_examples/boundary_crossing.cpp @@ -37,6 +37,13 @@ using namespace corsika; using namespace std; +// +// This example shows how to make a custom process which deletes particles that +// cross a particular boundary (a sphere in this case) +// For a plane boundary, this can be implemented by adding an ObservationPlane +// or Observation Volume object instead (the standard "absorbing" geometry objects) +// + template <bool deleteParticle> struct MyBoundaryCrossingProcess : public BoundaryCrossingProcess<MyBoundaryCrossingProcess<deleteParticle>> { @@ -65,9 +72,6 @@ private: std::ofstream file_; }; -// -// The example main program for a particle cascade -// int main() { logging::set_level(logging::level::warn); diff --git a/examples/environment.cpp b/examples/framework_examples/environment.cpp similarity index 100% rename from examples/environment.cpp rename to examples/framework_examples/environment.cpp diff --git a/examples/geometry_example.cpp b/examples/framework_examples/geometry.cpp similarity index 100% rename from examples/geometry_example.cpp rename to examples/framework_examples/geometry.cpp diff --git a/examples/helix_example.cpp b/examples/framework_examples/helix_trajectory.cpp similarity index 100% rename from examples/helix_example.cpp rename to examples/framework_examples/helix_trajectory.cpp diff --git a/examples/particle_list_example.cpp b/examples/framework_examples/known_particles.cpp similarity index 85% rename from examples/particle_list_example.cpp rename to examples/framework_examples/known_particles.cpp index 2c9016f52..4f6cf35ba 100644 --- a/examples/particle_list_example.cpp +++ b/examples/framework_examples/known_particles.cpp @@ -18,11 +18,14 @@ using namespace corsika; using namespace std; // -// The example main program for a particle list +// This example prints out all of the particles that are +// known to CORSIKA 8 and the corresponding IDs in the +// hadronic model codes. // + int main() { - logging::set_level(logging::level::warn); + logging::set_level(logging::level::info); corsika_logger->set_pattern("[%n:%^%-8l%$] %v"); logging::info( @@ -30,7 +33,7 @@ int main() { "------------------------------------------\n" " particles in CORSIKA\n" "------------------------------------------\n"); - int const width = 20 + 10 + 10 + 10 + 15 + 15 + 17; + int const width = 20 + 10 + 10 + 10 + 16 + 16 + 17; logging::info( "Name | " "PDG-id | " @@ -46,7 +49,7 @@ int main() { ? to_string(corsika::sibyll::getSibyllMass(p) / 1_GeV) : ""); auto const qgs_id = corsika::qgsjetII::convertToQgsjetII(p); - logging::info("{:20} | {:10} | {:10} | {:10} | {:>15.5} | {:>15.5} |", p, + logging::info("{:20} | {:10} | {:10} | {:10} | {:>16.5} | {:>16.5} |", p, static_cast<int>(get_PDG(p)), (sib_id != corsika::sibyll::SibyllCode::Unknown ? to_string(static_cast<int>(sib_id)) diff --git a/examples/stack_example.cpp b/examples/framework_examples/stack.cpp similarity index 100% rename from examples/stack_example.cpp rename to examples/framework_examples/stack.cpp diff --git a/examples/staticsequence_example.cpp b/examples/framework_examples/static_sequence.cpp similarity index 99% rename from examples/staticsequence_example.cpp rename to examples/framework_examples/static_sequence.cpp index b9bbba59f..b3242dd5e 100644 --- a/examples/staticsequence_example.cpp +++ b/examples/framework_examples/static_sequence.cpp @@ -131,4 +131,4 @@ int main() { modular(); return 0; -} \ No newline at end of file +} diff --git a/examples/stopping_power.cpp b/examples/physics_examples/stopping_power.cpp similarity index 92% rename from examples/stopping_power.cpp rename to examples/physics_examples/stopping_power.cpp index 8b39786e1..28a9ff7f0 100644 --- a/examples/stopping_power.cpp +++ b/examples/physics_examples/stopping_power.cpp @@ -9,7 +9,6 @@ #include <corsika/media/Environment.hpp> #include <corsika/media/HomogeneousMedium.hpp> #include <corsika/media/IMediumModel.hpp> -#include <corsika/media/ShowerAxis.hpp> #include <corsika/framework/geometry/Sphere.hpp> #include <corsika/modules/BetheBlochPDG.hpp> @@ -30,7 +29,7 @@ using namespace std; // int main() { - logging::set_level(logging::level::warn); + logging::set_level(logging::level::info); CORSIKA_LOG_INFO("stopping_power"); @@ -52,7 +51,9 @@ int main() { setup::Stack<EnvType> stack; - std::ofstream file("dEdX.dat"); + std::string fileName = "dEdX.dat"; + CORSIKA_LOG_INFO("Writing to file {}", fileName); + std::ofstream file(fileName); file << "# beta*gamma, dE/dX / MeV/(g/cm²)" << std::endl; for (HEPEnergyType E0 = 200_MeV; E0 < 1_PeV; E0 *= 1.05) { @@ -79,5 +80,5 @@ int main() { HEPEnergyType dE = eLoss.getTotalEnergyLoss(p, 1_g / square(1_cm)); file << P0 / mass << "\t" << -dE / 1_MeV << std::endl; } - CORSIKA_LOG_INFO("finished writing dEdX.dat"); + CORSIKA_LOG_INFO("finished writing {}", fileName); } diff --git a/examples/clover_leaf.cpp b/examples/physics_examples/synchrotron_clover_leaf.cpp similarity index 90% rename from examples/clover_leaf.cpp rename to examples/physics_examples/synchrotron_clover_leaf.cpp index f1044b9b3..a200ea101 100644 --- a/examples/clover_leaf.cpp +++ b/examples/physics_examples/synchrotron_clover_leaf.cpp @@ -24,7 +24,6 @@ #include <corsika/media/MediumPropertyModel.hpp> #include <corsika/media/UniformMagneticField.hpp> #include <corsika/media/UniformRefractiveIndex.hpp> -#include <corsika/media/ShowerAxis.hpp> #include <corsika/setup/SetupStack.hpp> #include <corsika/setup/SetupTrajectory.hpp> @@ -35,14 +34,10 @@ #include <corsika/modules/radio/antennas/Antenna.hpp> #include <corsika/modules/radio/antennas/TimeDomainAntenna.hpp> #include <corsika/modules/radio/detectors/AntennaCollection.hpp> -#include <corsika/modules/radio/propagators/NumericalIntegratingPropagator.hpp> #include <corsika/modules/radio/propagators/DummyTestPropagator.hpp> -#include <corsika/modules/TrackWriter.hpp> +#include <corsika/modules/writers/PrimaryWriter.hpp> -#include <corsika/modules/StackInspector.hpp> -#include <corsika/modules/ParticleCut.hpp> #include <corsika/modules/TimeCut.hpp> -// #include <corsika/modules/TrackWriter.hpp> #include <iomanip> #include <iostream> @@ -57,6 +52,7 @@ using namespace std; // A simple shower to get the electric field trace of an electron (& a positron) // in order to reveal the "clover leaf" pattern of energy fluence to the ground. // + int main() { logging::set_level(logging::level::info); @@ -70,7 +66,7 @@ int main() { auto seed = rd(); RNGManager<>::getInstance().setSeed(seed); - OutputManager output("1 electron - 1 positron"); + OutputManager output("clover_leaf_outputs"); // create a suitable environment using IModelInterface = @@ -105,7 +101,6 @@ int main() { auto const injectionPosY_{injectionPos.getCoordinates().getY()}; auto const injectionPosZ_{injectionPos.getCoordinates().getZ()}; auto const triggerpoint_{Point(rootCS, injectionPosX_, injectionPosY_, injectionPosZ_)}; - std::cout << "Trigger Point is: " << triggerpoint_ << std::endl; // the antenna characteristics const TimeType duration_{2e-6_s}; // 0.8e-4_s @@ -113,7 +108,6 @@ int main() { // the detectors AntennaCollection<TimeDomainAntenna> detectorCoREAS; - // AntennaCollection<TimeDomainAntenna> detectorZHS; std::string name_center = "CoREAS_R=0_m--Phi=0degrees"; auto triggertime_center{((triggerpoint_ - center).getNorm() / constants::c) - 500_ns}; @@ -127,7 +121,7 @@ int main() { auto rr_1 = static_cast<int>(radius_1 / 1_m); auto const point_1{Point(rootCS, centerX + radius_1 * cos(phiRad_1), centerY + radius_1 * sin(phiRad_1), centerZ)}; - std::cout << "Antenna point: " << point_1 << std::endl; + CORSIKA_LOG_INFO("Antenna point: {}", point_1); auto triggertime_1{((triggerpoint_ - point_1).getNorm() / constants::c) - 500_ns}; std::string name_1 = "CoREAS_R=" + std::to_string(rr_1) + "_m--Phi=" + std::to_string(phi_1) + "degrees"; @@ -186,16 +180,8 @@ int main() { coreas(detectorCoREAS, SP); output.add("CoREAS", coreas); - // RadioProcess<decltype(detectorZHS), ZHS<decltype(detectorZHS), - // decltype(SP)>, decltype(SP)> - // zhs(detectorZHS, SP); - // output.add("ZHS", zhs); - TimeCut cut(period / 4); - // TrackWriter trackWriter; - // output.add("tracks", trackWriter); // register TrackWriter - // assemble all processes into an ordered process list auto sequence = make_sequence(coreas, cut); diff --git a/examples/synchrotron_test_C8tracking.cpp b/examples/physics_examples/synchrotron_test_C8tracking.cpp similarity index 100% rename from examples/synchrotron_test_C8tracking.cpp rename to examples/physics_examples/synchrotron_test_C8tracking.cpp diff --git a/examples/synchrotron_test_manual_tracking.cpp b/examples/physics_examples/synchrotron_test_manual_tracking.cpp similarity index 100% rename from examples/synchrotron_test_manual_tracking.cpp rename to examples/physics_examples/synchrotron_test_manual_tracking.cpp diff --git a/examples/vertical_EAS.cpp b/examples/vertical_EAS.cpp deleted file mode 100644 index 4a64fc19b..000000000 --- a/examples/vertical_EAS.cpp +++ /dev/null @@ -1,286 +0,0 @@ -/* - * (c) Copyright 2022 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. - */ - -#define TRACE - -/* 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/InteractionCounter.hpp> -#include <corsika/framework/process/ProcessSequence.hpp> -#include <corsika/framework/process/SwitchProcessSequence.hpp> -#include <corsika/framework/random/RNGManager.hpp> -#include <corsika/framework/utility/CorsikaFenv.hpp> -#include <corsika/framework/utility/SaveBoostHistogram.hpp> - -#include <corsika/modules/writers/EnergyLossWriter.hpp> -#include <corsika/modules/writers/LongitudinalWriter.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/FlatExponential.hpp> -#include <corsika/media/GeomagneticModel.hpp> -#include <corsika/media/HomogeneousMedium.hpp> -#include <corsika/media/IMagneticFieldModel.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/Sibyll.hpp> -#include <corsika/modules/Sophia.hpp> -#include <corsika/modules/StackInspector.hpp> -#include <corsika/modules/TrackWriter.hpp> -#include <corsika/modules/UrQMD.hpp> - -#include <corsika/setup/SetupStack.hpp> -#include <corsika/setup/SetupTrajectory.hpp> - -#include <iomanip> -#include <iostream> -#include <limits> -#include <string> - -using namespace corsika; -using namespace std; - -using EnvironmentInterface = IMediumPropertyModel<IMagneticFieldModel<IMediumModel>>; -using EnvType = Environment<EnvironmentInterface>; - -using Particle = setup::Stack<EnvType>::particle_type; - -void registerRandomStreams(int seed) { - RNGManager<>::getInstance().registerRandomStream("cascade"); - RNGManager<>::getInstance().registerRandomStream("sibyll"); - // RNGManager<>::getInstance().registerRandomStream("sophia"); - RNGManager<>::getInstance().registerRandomStream("pythia"); - RNGManager<>::getInstance().registerRandomStream("urqmd"); - RNGManager<>::getInstance().registerRandomStream("proposal"); - if (seed == 0) { - std::random_device rd; - seed = rd(); - cout << "new random seed (auto) " << seed << endl; - } - RNGManager<>::getInstance().setSeed(seed); -} - -template <typename T> -using MyExtraEnv = MediumPropertyModel<UniformMagneticField<T>>; - -// argv : 1.number of nucleons, 2.number of protons, -// 3.total energy in GeV, 4.number of showers, -// 5.seed (0 by default to generate random values for all) - -int main(int argc, char** argv) { - - logging::set_level(logging::level::warn); - - CORSIKA_LOG_INFO("vertical_EAS"); - - if (argc < 4) { - std::cerr << "usage: vertical_EAS <A> <Z> <energy/GeV> [seed] \n" - " if A=0, Z is interpreted as PDG code \n" - " if no seed is given, a random seed is chosen \n" - << std::endl; - return 1; - } - feenableexcept(FE_INVALID); - - int seed = 0; - - if (argc > 4) { seed = std::stoi(std::string(argv[4])); } - - // initialize random number sequence(s) - registerRandomStreams(seed); - - // setup environment, geometry - EnvType env; - CoordinateSystemPtr const& rootCS = env.getCoordinateSystem(); - Point const center{rootCS, 0_m, 0_m, 0_m}; - - // build a Linsley US Standard atmosphere into `env` - create_5layer_atmosphere<EnvironmentInterface, MyExtraEnv>( - env, AtmosphereId::LinsleyUSStd, center, Medium::AirDry1Atm, - MagneticFieldVector{rootCS, 20.4_uT, 0_T, -43.23_uT}); - - // Uncomment if you want to use PROPOSAL - // std::unordered_map<Code, HEPEnergyType> energy_resolution = { - // {Code::Electron, 2_MeV}, - // {Code::Positron, 2_MeV}, - // {Code::Photon, 2_MeV}, - // }; - // for (auto [pcode, energy] : energy_resolution) - // set_energy_production_threshold(pcode, energy); - - // pre-setup particle stack - unsigned short const A = std::stoi(std::string(argv[1])); - Code beamCode; - unsigned short Z = 0; - if (A > 0) { - Z = std::stoi(std::string(argv[2])); - if (A == 1 && Z == 0) - beamCode = Code::Neutron; - else if (A == 1 && Z == 1) - beamCode = Code::Proton; - else - beamCode = get_nucleus_code(A, Z); - } else { - int pdg = std::stoi(std::string(argv[2])); - beamCode = convert_from_PDG(PDGCode(pdg)); - } - HEPEnergyType mass = get_mass(beamCode); - HEPEnergyType const E0 = 1_GeV * std::stof(std::string(argv[3])); - double theta = 0.; - double phi = 180.; - auto const thetaRad = theta / 180. * constants::pi; - auto const phiRad = phi / 180. * constants::pi; - - HEPMomentumType P0 = calculate_momentum(E0, mass); - auto momentumComponents = [](double theta, double phi, HEPMomentumType ptot) { - return std::make_tuple(ptot * sin(theta) * cos(phi), ptot * sin(theta) * sin(phi), - -ptot * cos(theta)); - }; - - auto const [px, py, pz] = momentumComponents(thetaRad, phiRad, P0); - auto plab = MomentumVector(rootCS, {px, py, pz}); - cout << "input particle: " << beamCode << endl; - cout << "input angles: theta=" << theta << ",phi=" << phi << endl; - cout << "input momentum: " << plab.getComponents() / 1_GeV - << ", norm = " << plab.getNorm() << endl; - - auto const observationHeight = 0.0_km + constants::EarthRadius::Mean; - auto const injectionHeight = 111.75_km + 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; - - std::cout << "point of injection: " << injectionPos.getCoordinates() << std::endl; - - // we make the axis much longer than the inj-core distance since the - // profile will go beyond the core, depending on zenith angle - std::cout << "shower axis length: " << (showerCore - injectionPos).getNorm() * 1.5 - << std::endl; - - ShowerAxis const showerAxis{injectionPos, (showerCore - injectionPos) * 1.5, env, false, - 1000}; - - // create the output manager that we then register outputs with - OutputManager output("vertical_EAS_outputs"); - - // EnergyLossWriterParquet dEdX_output{showerAxis, 10_g / square(1_cm), 200}; - // register energy losses as output - // output.add("dEdX", dEdX_output); - // register profile output - - // construct the overall energy loss writer and register it - EnergyLossWriter dEdX{showerAxis}; - output.add("energyloss", dEdX); - - // construct the continuous energy loss model - BetheBlochPDG<SubWriter<decltype(dEdX)>> emContinuous{dEdX}; - - // construct a particle cut - cuts are set to values close to reality, put - // higher values for faster runs - ParticleCut<SubWriter<decltype(dEdX)>> cut{2_MeV, 2_MeV, 2_GeV, 300_MeV, true, dEdX}; - - // setup longitudinal profile - LongitudinalWriter longProf{showerAxis}; - output.add("profile", longProf); - - LongitudinalProfile<SubWriter<decltype(longProf)>> profile{longProf}; - - // create a track writer and register it with the output manager - TrackWriter<TrackWriterParquet> trackWriter; - output.add("tracks", trackWriter); - - // setup processes, decays and interactions - - corsika::sibyll::Interaction sibyll{env}; - InteractionCounter sibyllCounted{sibyll}; - - HEPEnergyType heThresholdNN = 60_GeV; - // PROPOSAL is disabled for this example - // corsika::sophia::InteractionModel sophia; - // corsika::proposal::Interaction emCascade(env, sophia, - // sibyll.getHadronInteractionModel(), heThresholdNN); - // corsika::proposal::ContinuousProcess<SubWriter<decltype(dEdX)>> - // emContinuous(env, dEdX); - - corsika::pythia8::Decay decayPythia; - - corsika::urqmd::UrQMD urqmd; - InteractionCounter urqmdCounted{urqmd}; - StackInspector<setup::Stack<EnvType>> stackInspect(50000, false, E0); - - // 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.getEnergy() < cutE_); } - }; - auto hadronSequence = make_select(EnergySwitch(55_GeV), urqmdCounted, sibyllCounted); - - // directory for outputs - string const labHist_file = "inthist_lab_verticalEAS.npz"; - string const cMSHist_file = "inthist_cms_verticalEAS.npz"; - - // setup particle stack, and add primary particle - setup::Stack<EnvType> stack; - stack.clear(); - - stack.addParticle(std::make_tuple( - beamCode, calculate_kinetic_energy(plab.getNorm(), get_mass(beamCode)), - plab.normalized(), injectionPos, 0_ns)); - - Plane const obsPlane(showerCore, DirectionVector(rootCS, {0., 0., 1.})); - ObservationPlane<setup::Tracking, ParticleWriterParquet> observationLevel{ - obsPlane, DirectionVector(rootCS, {1., 0., 0.})}; - output.add("particles", observationLevel); - - auto sequence = make_sequence(stackInspect, hadronSequence, decayPythia, emContinuous, - profile, observationLevel, cut); - - // define air shower object, run simulation - setup::Tracking tracking; - output.startOfLibrary(); - Cascade EAS(env, tracking, sequence, output, stack); - EAS.run(); - - auto const hists = sibyllCounted.getHistogram() + urqmdCounted.getHistogram(); - - save_hist(hists.labHist(), labHist_file, true); - save_hist(hists.CMSHist(), cMSHist_file, true); - - output.endOfLibrary(); -} -- GitLab