diff --git a/.clang-format b/.clang-format index 0ac489959f851bf8930e40fc9eec547d23c4909b..afc401b287b98713c3647a8a4b1752b3c9c7c080 100644 --- a/.clang-format +++ b/.clang-format @@ -57,6 +57,7 @@ IncludeCategories: Priority: 2 - Regex: '.*' Priority: 3 +SortIncludes: false IndentCaseLabels: true IndentWidth: 2 IndentWrappedFunctionNames: false @@ -76,7 +77,6 @@ PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left ReflowComments: true -SortIncludes: true SpaceAfterCStyleCast: false SpaceBeforeAssignmentOperators: true SpaceBeforeParens: ControlStatements diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1bc50e665c00b23c53ef16812db92fba158991c2..464ce2402377ddacbf94a9147aa958ebbd9bdf3d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -276,6 +276,8 @@ build_test-clang-8: # normal pipeline for each commit .example: stage: example + before_script: + - apt-get -qq update && apt-get -qq install -y gdb tags: - corsika script: @@ -330,6 +332,8 @@ example-clang-8: stage: build_test_example tags: - corsika + before_script: + - apt-get -qq update && apt-get -qq install -y gdb script: - cd build - cmake --build . -- -j4 @@ -439,6 +443,8 @@ install-clang-8: stage: optional tags: - corsika + before_script: + - apt-get -qq update && apt-get -qq install -y gdb script: - cd build - cmake .. -DCMAKE_BUILD_TYPE=Release diff --git a/.gitlab/merge_request_templates/Code Approval.md b/.gitlab/merge_request_templates/Code Approval.md index fed15a38efcfdb1a0a4ded8050733598ec2856ca..ed076c02e7be42adb5da776b21546e985d2d60c5 100644 --- a/.gitlab/merge_request_templates/Code Approval.md +++ b/.gitlab/merge_request_templates/Code Approval.md @@ -1,15 +1,18 @@ -The code approval procedure is described in the [code approval procedure wiki](https://gitlab.ikp.kit.edu/AirShowerPhysics/corsika/-/wikis/Code-Approval-Procedure) +Issues: Closes #.... -- [ ] The MR is without WIP (work in progress) status -- [ ] Make sure the most recent CI jobs (config, quality, build, tests) all run fine with no failures +The code approval procedure is described in the wiki: [Code approval procedure wiki](https://gitlab.ikp.kit.edu/AirShowerPhysics/corsika/-/wikis/Code-Approval-Procedure) + +- [ ] The MR is without `WIP/Draft` status +- [ ] Make sure the most recent CI jobs (config, quality, build_test_example) all run fine with no failures - if "check clang-format" failed: the code contributor has to run `./do-clang-format.py --apply` eventually with the `--all` option - if "check copyright" failed the code contributor has to run`./do-copyright.py --add=20xy` -- [ ] Also run all the extra optional jobs "coverage", "release-clang-8", "release-u-18.04" and make sure no problems occur -- [ ] Check in the "coverage" job output that the coverage did not decreases (!). It should always stay, or increase. If it decreased --> ask contributor to add further unit tests, and check coverage report. +- [ ] Make sure also the jobs with MR-label `ready for code review` succeed. This includes the optional jobs, in particular 'coverage', 'release-clang-8", "release-u-18.04" and make sure no problems occur. You may have to trigger a pipeline manually to check this. +- [ ] Check in the "coverage" job output that the coverage did not decrease. It should always stay, or increase. If it decreased --> ask contributor to add further needed unit tests, and check coverage report. - On the MR page, open the "Open in Web IDE" tool - [ ] Check if the provided solution solves the Issue, discuss on gitlab - [ ] Check that all changes are actually related to the issue - [ ] There are no debug statements left, not even commented out - [ ] Check all changes for coding rules and guidelines -- When all above is done - - [ ] **Add label "Code Review Finished"** +- When all above is done: + - **Add MR label "Code Review Finished"** + diff --git a/CMakeModules/CorsikaUtilities.cmake b/CMakeModules/CorsikaUtilities.cmake index d80269b3a24e549a7655b769099bd6579a79a112..96d29eeb614391ae0f4fd05a4892e7d02eeeef2d 100644 --- a/CMakeModules/CorsikaUtilities.cmake +++ b/CMakeModules/CorsikaUtilities.cmake @@ -174,13 +174,15 @@ endfunction (CORSIKA_ADD_TEST) # specify the sources. # # Example: CORSIKA_ADD_EXAMPLE (testSomething -# SOURCES source1.cc source2.cc someheader.h) +# SOURCES source1.cc source2.cc someheader.h +# RUN_OPTION "extra command line options" +# RUN_IN_GDB) # # In all cases, you can further customize the target with # target_link_libraries(testSomething ...) and so on. # function (CORSIKA_ADD_EXAMPLE) - cmake_parse_arguments (PARSE_ARGV 1 C8_ADD_EXAMPLE "" "" "SOURCES;RUN_OPTIONS") + cmake_parse_arguments (PARSE_ARGV 1 C8_ADD_EXAMPLE "RUN_IN_GDB" "" "SOURCES;RUN_OPTIONS") set (name ${ARGV0}) if (NOT C8_ADD_EXAMPLE_SOURCES) @@ -204,12 +206,21 @@ function (CORSIKA_ADD_EXAMPLE) add_custom_target (run_examples) endif () add_dependencies (run_examples ${name}) + if (C8_ADD_EXAMPLE_RUN_IN_GDB) + # convert cmake list into real string: + string (REPLACE ";" " " run_options_str "${run_options}") + # run the command in gdb and study backtrace a bit + set (CMD gdb -q --batch -ex "run ${run_options_str}" -ex bt -ex "info locals" -ex "up" -ex "info locals" -ex "up" -ex "info locals" -ex "up" -ex "info locals" -ex quit "${CMAKE_CURRENT_BINARY_DIR}/${name}") + else (C8_ADD_EXAMPLE_RUN_IN_GDB) + # just run the command as-is + set (CMD ${CMAKE_CURRENT_BINARY_DIR}/${name} ${run_options}) + endif (C8_ADD_EXAMPLE_RUN_IN_GDB) add_custom_command (TARGET run_examples POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "" COMMAND ${CMAKE_COMMAND} -E echo "**************************************" COMMAND ${CMAKE_COMMAND} -E echo "***** running example: ${name} " ${run_options} VERBATIM - COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${name} ${run_options} VERBATIM + COMMAND ${CMD} VERBATIM WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/example_outputs) install (TARGETS ${name} DESTINATION share/examples) endfunction (CORSIKA_ADD_EXAMPLE) diff --git a/Documentation/Doxygen/Doxyfile.in b/Documentation/Doxygen/Doxyfile.in index 77031e96dc0e9d9f1b17cb4fed4f0e2201deb284..b733d09258adfa7e7200033acda18823a8c8ca9d 100644 --- a/Documentation/Doxygen/Doxyfile.in +++ b/Documentation/Doxygen/Doxyfile.in @@ -7,11 +7,11 @@ GENERATE_XML = YES OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/ INPUT = @PROJECT_SOURCE_DIR@ @PROJECT_BINARY_DIR@/Framework -EXCLUDE_PATTERNS = */ThirdParty/*/* +EXCLUDE_PATTERNS = */ThirdParty/*/* */build*/corsika/* FULL_PATH_NAMES = YES STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@ -FILE_PATTERNS = *.cc *.cpp *.cxx *.h *.dox *.inc *.md +FILE_PATTERNS = *.cc *.cpp *.cxx *.h *.hpp *.dox *.inc *.md EXTENSION_MAPPING = inc=C++ RECURSIVE = YES diff --git a/Documentation/Examples/CMakeLists.txt b/Documentation/Examples/CMakeLists.txt index 17c711669f514a311dbaa9297139ca6d26959f8b..62c9d6bd3b9b05e28cf7985a4c9766a7ed4570c4 100644 --- a/Documentation/Examples/CMakeLists.txt +++ b/Documentation/Examples/CMakeLists.txt @@ -24,12 +24,12 @@ target_link_libraries (boundary_example ProcessParticleCut ProcessTrackingLine ProcessPythia8 - ProcessProposal CORSIKAprocesses CORSIKAparticles CORSIKAgeometry CORSIKAenvironment CORSIKAprocesssequence + C8::ext::boost # boost::histogram ) CORSIKA_ADD_EXAMPLE (cascade_example) @@ -66,7 +66,6 @@ if (Pythia8_FOUND) ProcessSibyll ProcessPythia8 ProcessUrQMD - ProcessSwitch CORSIKAcascade ProcessCONEXSourceCut ProcessEnergyLoss @@ -95,7 +94,6 @@ if (Pythia8_FOUND) ProcessSibyll ProcessPythia8 ProcessUrQMD - ProcessSwitch CORSIKAcascade ProcessProposal ProcessPythia8 @@ -123,6 +121,7 @@ CORSIKA_ADD_EXAMPLE (stopping_power stopping_power) target_link_libraries (stopping_power CORSIKAsetup CORSIKAunits + CORSIKAlogging ProcessEnergyLoss CORSIKAparticles CORSIKAgeometry @@ -137,7 +136,7 @@ target_link_libraries (staticsequence_example CORSIKAlogging) -CORSIKA_ADD_EXAMPLE (em_shower RUN_OPTIONS 100.) +CORSIKA_ADD_EXAMPLE (em_shower RUN_OPTIONS "100.") target_link_libraries (em_shower SuperStupidStack CORSIKAunits @@ -146,7 +145,6 @@ target_link_libraries (em_shower ProcessSibyll ProcessPythia8 ProcessUrQMD - ProcessSwitch CORSIKAcascade ProcessCONEXSourceCut ProcessEnergyLoss diff --git a/Documentation/Examples/boundary_example.cc b/Documentation/Examples/boundary_example.cc index 40c60ebed365e24d8e4aed8595968581fa7252e7..9bf4e188ae18a1e668e86c9e8294d52a1c9642b1 100644 --- a/Documentation/Examples/boundary_example.cc +++ b/Documentation/Examples/boundary_example.cc @@ -34,6 +34,8 @@ #include <corsika/utl/CorsikaFenv.h> +#include <corsika/logging/Logging.h> + #include <iostream> #include <limits> #include <typeinfo> @@ -60,7 +62,9 @@ struct MyBoundaryCrossingProcess EProcessReturn DoBoundaryCrossing(Particle& p, typename Particle::BaseNodeType const& from, typename Particle::BaseNodeType const& to) { - std::cout << "boundary crossing! from: " << &from << "; to: " << &to << std::endl; + + C8LOG_INFO("MyBoundaryCrossingProcess: crossing! from: {} to: {} ", fmt::ptr(&from), + fmt::ptr(&to)); auto const& name = particles::GetName(p.GetPID()); auto const start = p.GetPosition().GetCoordinates(); @@ -82,7 +86,9 @@ private: // int main() { - std::cout << "boundary_example" << std::endl; + logging::SetLevel(logging::level::info); + + C8LOG_INFO("boundary_example"); feenableexcept(FE_INVALID); // initialize random number sequence(s) @@ -95,24 +101,23 @@ int main() { const CoordinateSystem& rootCS = env.GetCoordinateSystem(); - auto outerMedium = EnvType::CreateNode<Sphere>( + // create "world" as infinite sphere filled with protons + auto world = EnvType::CreateNode<Sphere>( Point{rootCS, 0_m, 0_m, 0_m}, 1_km * std::numeric_limits<double>::infinity()); auto const props = - outerMedium - ->SetModelProperties<environment::HomogeneousMedium<setup::IEnvironmentModel>>( - 1_kg / (1_m * 1_m * 1_m), - environment::NuclearComposition( - std::vector<particles::Code>{particles::Code::Proton}, - std::vector<float>{1.f})); - - auto innerMedium = EnvType::CreateNode<Sphere>(Point{rootCS, 0_m, 0_m, 0_m}, 5_km); - - innerMedium->SetModelProperties(props); + world->SetModelProperties<environment::HomogeneousMedium<setup::IEnvironmentModel>>( + 1_kg / (1_m * 1_m * 1_m), + environment::NuclearComposition( + std::vector<particles::Code>{particles::Code::Proton}, + std::vector<float>{1.f})); - outerMedium->AddChild(std::move(innerMedium)); + // add a "target" sphere with 5km readius at 0,0,0 + auto target = EnvType::CreateNode<Sphere>(Point{rootCS, 0_m, 0_m, 0_m}, 5_km); + target->SetModelProperties(props); - universe.AddChild(std::move(outerMedium)); + world->AddChild(std::move(target)); + universe.AddChild(std::move(world)); // setup processes, decays and interactions tracking_line::TrackingLine tracking; @@ -121,28 +126,28 @@ int main() { process::sibyll::Interaction sibyll; process::sibyll::Decay decay; - process::particle_cut::ParticleCut cut(20_GeV, true, true); + process::particle_cut::ParticleCut cut(50_GeV, true, true); - process::track_writer::TrackWriter trackWriter("tracks.dat"); + process::track_writer::TrackWriter trackWriter("boundary_tracks.dat"); MyBoundaryCrossingProcess<true> boundaryCrossing("crossings.dat"); // assemble all processes into an ordered process list - auto sequence = sibyll << decay << cut << boundaryCrossing << trackWriter; + auto sequence = process::sequence(sibyll, decay, cut, boundaryCrossing, trackWriter); // setup particle stack, and add primary particles setup::Stack stack; stack.Clear(); - const Code beamCode = Code::Proton; - const HEPMassType mass = particles::GetMass(Code::Proton); - const HEPEnergyType E0 = 50_TeV; + const Code beamCode = Code::MuPlus; + const HEPMassType mass = particles::GetMass(beamCode); + const HEPEnergyType E0 = 100_GeV; std::uniform_real_distribution distTheta(0., 180.); std::uniform_real_distribution distPhi(0., 360.); std::mt19937 rng; for (int i = 0; i < 100; ++i) { - auto const theta = distTheta(rng); - auto const phi = distPhi(rng); + double const theta = distTheta(rng); + double const phi = distPhi(rng); auto elab2plab = [](HEPEnergyType Elab, HEPMassType m) { return sqrt((Elab - m) * (Elab + m)); @@ -155,9 +160,12 @@ int main() { auto const [px, py, pz] = momentumComponents(theta / 180. * M_PI, phi / 180. * M_PI, P0); auto plab = corsika::stack::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; + C8LOG_INFO( + "input particle: {} " + "input angles: theta={} phi={}" + "input momentum: {} GeV", + beamCode, theta, phi, plab.GetComponents() / 1_GeV); + // shoot particles from inside target out Point pos(rootCS, 0_m, 0_m, 0_m); stack.AddParticle( std::tuple<particles::Code, units::si::HEPEnergyType, @@ -170,10 +178,10 @@ int main() { EAS.Run(); - cout << "Result: E0=" << E0 / 1_GeV << endl; + C8LOG_INFO("Result: E0={}GeV", E0 / 1_GeV); cut.ShowResults(); - const HEPEnergyType Efinal = - cut.GetCutEnergy() + cut.GetInvEnergy() + cut.GetEmEnergy(); - cout << "total energy (GeV): " << Efinal / 1_GeV << endl - << "relative difference (%): " << (Efinal / E0 - 1.) * 100 << endl; + [[maybe_unused]] const HEPEnergyType Efinal = + (cut.GetCutEnergy() + cut.GetInvEnergy() + cut.GetEmEnergy()); + C8LOG_INFO("Total energy (GeV): {} relative difference (%): {}", Efinal / 1_GeV, + (Efinal / E0 - 1.) * 100); } diff --git a/Documentation/Examples/cascade_example.cc b/Documentation/Examples/cascade_example.cc index fe8e05d87460d23d3517f4028a686198205dff30..64ed627e03c8c7687a2b75330dd50d46e1168627 100644 --- a/Documentation/Examples/cascade_example.cc +++ b/Documentation/Examples/cascade_example.cc @@ -35,6 +35,7 @@ #include <corsika/random/RNGManager.h> #include <corsika/utl/CorsikaFenv.h> +#include <corsika/logging/Logging.h> #include <iostream> #include <limits> @@ -56,6 +57,8 @@ using namespace corsika::units::si; // int main() { + logging::SetLevel(logging::level::debug); + std::cout << "cascade_example" << std::endl; const LengthType height_atmosphere = 112.8_km; @@ -147,8 +150,8 @@ int main() { process::energy_loss::EnergyLoss eLoss{showerAxis, cut.GetECut()}; // assemble all processes into an ordered process list - auto sequence = stackInspect << sibyll << sibyllNuc << decay << eLoss << cut - << trackWriter; + auto sequence = + process::sequence(stackInspect, sibyll, sibyllNuc, decay, eLoss, cut, trackWriter); // define air shower object, run simulation cascade::Cascade EAS(env, tracking, sequence, stack); diff --git a/Documentation/Examples/cascade_proton_example.cc b/Documentation/Examples/cascade_proton_example.cc index 6050f7fcfae52c7a5f77e76928abbf44113c276d..4ca053f377d67d2aa597b8e377575c4f960cd305 100644 --- a/Documentation/Examples/cascade_proton_example.cc +++ b/Documentation/Examples/cascade_proton_example.cc @@ -38,6 +38,8 @@ #include <corsika/utl/CorsikaFenv.h> +#include <corsika/logging/Logging.h> + #include <iostream> #include <limits> #include <typeinfo> @@ -59,6 +61,8 @@ using namespace corsika::units::si; // int main() { + logging::SetLevel(logging::level::info); + std::cout << "cascade_proton_example" << std::endl; feenableexcept(FE_INVALID); @@ -136,7 +140,7 @@ int main() { // assemble all processes into an ordered process list // auto sequence = sibyll << decay << hadronicElastic << cut << trackWriter; - auto sequence = pythia << decay << cut << trackWriter << stackInspect; + auto sequence = process::sequence(pythia, decay, cut, trackWriter, stackInspect); // cout << "decltype(sequence)=" << type_id_with_cvr<decltype(sequence)>().pretty_name() // << "\n"; diff --git a/Documentation/Examples/em_shower.cc b/Documentation/Examples/em_shower.cc index 1c5c07cd483242cceed18aa356f4167a0253abb5..c41d4574755db08489665f1bfde06fcded43d4c0 100644 --- a/Documentation/Examples/em_shower.cc +++ b/Documentation/Examples/em_shower.cc @@ -29,6 +29,8 @@ #include <corsika/utl/CorsikaFenv.h> #include <corsika/process/interaction_counter/InteractionCounter.hpp> +#include <corsika/logging/Logging.h> + #include <iomanip> #include <iostream> #include <limits> @@ -54,6 +56,9 @@ void registerRandomStreams() { } int main(int argc, char** argv) { + + logging::SetLevel(logging::level::info); + if (argc != 2) { std::cerr << "usage: em_shower <energy/GeV>" << std::endl; return 1; @@ -144,8 +149,8 @@ int main(int argc, char** argv) { process::observation_plane::ObservationPlane observationLevel(obsPlane, "particles.dat"); - auto sequence = proposalCounted << em_continuous << longprof << cut << observationLevel - << trackWriter; + auto sequence = process::sequence(proposalCounted, em_continuous, longprof, cut, + observationLevel, trackWriter); // define air shower object, run simulation tracking_line::TrackingLine tracking; cascade::Cascade EAS(env, tracking, sequence, stack); @@ -169,11 +174,7 @@ int main(int argc, char** argv) { em_continuous.Reset(); auto const hists = proposalCounted.GetHistogram(); - hists.saveLab("inthist_lab.txt"); - hists.saveCMS("inthist_cms.txt"); - - longprof.save("longprof.txt"); - - std::ofstream finish("finished"); - finish << "run completed without error" << std::endl; + hists.saveLab("inthist_lab_emShower.npz"); + hists.saveCMS("inthist_cms_emShower.npz"); + longprof.save("longprof_emShower.txt"); } diff --git a/Documentation/Examples/staticsequence_example.cc b/Documentation/Examples/staticsequence_example.cc index ca75fe4b22172488675fddca7601748acf8e3214..659a3d6c2d13e9f3840f80d162cb8dff3feadfac 100644 --- a/Documentation/Examples/staticsequence_example.cc +++ b/Documentation/Examples/staticsequence_example.cc @@ -23,43 +23,43 @@ using namespace std; const int nData = 10; -class Process1 : public BaseProcess<Process1> { +class Process1 : public ContinuousProcess<Process1> { public: Process1() {} - template <typename D, typename T, typename S> - EProcessReturn DoContinuous(D& d, T&, S&) const { + template <typename D, typename T> + EProcessReturn DoContinuous(D& d, T&) const { for (int i = 0; i < nData; ++i) d.p[i] += 1; return EProcessReturn::eOk; } }; -class Process2 : public BaseProcess<Process2> { +class Process2 : public ContinuousProcess<Process2> { public: Process2() {} - template <typename D, typename T, typename S> - inline EProcessReturn DoContinuous(D& d, T&, S&) const { + template <typename D, typename T> + inline EProcessReturn DoContinuous(D& d, T&) const { for (int i = 0; i < nData; ++i) d.p[i] -= 0.1 * i; return EProcessReturn::eOk; } }; -class Process3 : public BaseProcess<Process3> { +class Process3 : public ContinuousProcess<Process3> { public: Process3() {} - template <typename D, typename T, typename S> - inline EProcessReturn DoContinuous(D&, T&, S&) const { + template <typename D, typename T> + inline EProcessReturn DoContinuous(D&, T&) const { return EProcessReturn::eOk; } }; -class Process4 : public BaseProcess<Process4> { +class Process4 : public ContinuousProcess<Process4> { public: Process4(const double v) : fV(v) {} - template <typename D, typename T, typename S> - inline EProcessReturn DoContinuous(D& d, T&, S&) const { + template <typename D, typename T> + inline EProcessReturn DoContinuous(D& d, T&) const { for (int i = 0; i < nData; ++i) d.p[i] *= fV; return EProcessReturn::eOk; } @@ -78,25 +78,31 @@ struct DummyTrajectory {}; void modular() { - Process1 m1; - Process2 m2; - Process3 m3; - Process4 m4(0.9); + // = 0 + Process1 m1; // + 1.0 + Process2 m2; // - (0.1*i) + Process3 m3; // * 1.0 + Process4 m4(1.5); // * 1.5 - auto sequence = m1 << m2 << m3 << m4; + auto sequence = process::sequence(m1, m2, m3, m4); DummyData particle; DummyTrajectory track; - const int n = 1000; - for (int i = 0; i < n; ++i) { sequence.DoContinuous(particle, track); } + double check[nData] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - for (int i = 0; i < nData; ++i) { - // cout << p.p[i] << endl; - // assert(p.p[i] == n-i*100); + const int nEv = 10; + for (int iEv = 0; iEv < nEv; ++iEv) { + sequence.DoContinuous(particle, track); + for (int i = 0; i < nData; ++i) { + check[i] += 1. - 0.1 * i; + check[i] *= 1.5; + } } - cout << " done (nothing...) " << endl; + for (int i = 0; i < nData; ++i) { assert(particle.p[i] == check[i]); } + + cout << " done (checking...) " << endl; } int main() { diff --git a/Documentation/Examples/vertical_EAS.cc b/Documentation/Examples/vertical_EAS.cc index 042e64bc29f468afa32c45b654b9082adedc33dd..14eeea8b94560f4f7233c8d385606702fd5e6294 100644 --- a/Documentation/Examples/vertical_EAS.cc +++ b/Documentation/Examples/vertical_EAS.cc @@ -22,6 +22,7 @@ #include <corsika/geometry/Sphere.h> #include <corsika/logging/Logging.h> #include <corsika/process/ProcessSequence.h> +#include <corsika/process/SwitchProcessSequence.h> #include <corsika/process/StackProcess.h> #include <corsika/process/energy_loss/EnergyLoss.h> #include <corsika/process/longitudinal_profile/LongitudinalProfile.h> @@ -34,7 +35,6 @@ #include <corsika/process/sibyll/Decay.h> #include <corsika/process/sibyll/Interaction.h> #include <corsika/process/sibyll/NuclearInteraction.h> -#include <corsika/process/switch_process/SwitchProcess.h> #include <corsika/process/tracking_line/TrackingLine.h> #include <corsika/process/urqmd/UrQMD.h> #include <corsika/random/RNGManager.h> @@ -60,6 +60,8 @@ using namespace corsika::environment; using namespace std; using namespace corsika::units::si; +using Particle = setup::Stack::StackIterator; + void registerRandomStreams(const int seed) { random::RNGManager::GetInstance().RegisterRandomStream("cascade"); random::RNGManager::GetInstance().RegisterRandomStream("qgsjet"); @@ -149,23 +151,20 @@ int main(int argc, char** argv) { std::cout << "point of injection: " << injectionPos.GetCoordinates() << std::endl; if (A != 1) { - stack.AddParticle(std::tuple<particles::Code, units::si::HEPEnergyType, - corsika::stack::MomentumVector, geometry::Point, - units::si::TimeType, unsigned short, unsigned short>{ - beamCode, E0, plab, injectionPos, 0_ns, A, Z}); + stack.AddParticle(std::make_tuple(beamCode, E0, plab, injectionPos, 0_ns, A, Z)); } else { stack.AddParticle( - std::tuple<particles::Code, units::si::HEPEnergyType, - corsika::stack::MomentumVector, geometry::Point, units::si::TimeType>{ - particles::Code::Proton, E0, plab, injectionPos, 0_ns}); + std::make_tuple(particles::Code::Proton, E0, plab, injectionPos, 0_ns)); } - std::cout << "shower axis length: " << (showerCore - injectionPos).norm() * 1.02 + // 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).norm() * 1.5 << std::endl; environment::ShowerAxis const showerAxis{injectionPos, - (showerCore - injectionPos) * 1.02, env}; + (showerCore - injectionPos) * 1.5, env}; // setup processes, decays and interactions @@ -200,7 +199,6 @@ int main(int argc, char** argv) { decaySibyll.PrintDecayConfig(); - // PROPOSAL processs proposal{...}; process::particle_cut::ParticleCut cut{60_GeV, false, true}; process::proposal::Interaction proposal(env, cut.GetECut()); process::proposal::ContinuousProcess em_continuous(env, cut.GetECut()); @@ -218,21 +216,30 @@ int main(int argc, char** argv) { process::interaction_counter::InteractionCounter urqmdCounted{urqmd}; // assemble all processes into an ordered process list - - auto sibyllSequence = sibyllNucCounted << sibyllCounted; - process::switch_process::SwitchProcess switchProcess(urqmdCounted, sibyllSequence, - 55_GeV); - auto decaySequence = decayPythia << decaySibyll; - - auto sequence = switchProcess << reset_particle_mass << decaySequence << proposalCounted - << em_continuous << cut << longprof << observationLevel; + struct EnergySwitch { + HEPEnergyType cutE_; + EnergySwitch(HEPEnergyType cutE) + : cutE_(cutE) {} + process::SwitchResult operator()(const Particle& p) { + if (p.GetEnergy() < cutE_) + return process::SwitchResult::First; + else + return process::SwitchResult::Second; + } + }; + auto hadronSequence = + process::select(urqmdCounted, process::sequence(sibyllNucCounted, sibyllCounted), + EnergySwitch(55_GeV)); + auto decaySequence = process::sequence(decayPythia, decaySibyll); + auto sequence = + process::sequence(hadronSequence, reset_particle_mass, decaySequence, + proposalCounted, em_continuous, cut, observationLevel, longprof); // define air shower object, run simulation tracking_line::TrackingLine tracking; cascade::Cascade EAS(env, tracking, sequence, stack); // to fix the point of first interaction, uncomment the following two lines: - // EAS.SetNodes(); // EAS.forceInteraction(); EAS.Run(); @@ -252,11 +259,7 @@ int main(int argc, char** argv) { auto const hists = sibyllCounted.GetHistogram() + sibyllNucCounted.GetHistogram() + urqmdCounted.GetHistogram() + proposalCounted.GetHistogram(); - hists.saveLab("inthist_lab.npz"); - hists.saveCMS("inthist_cms.npz"); - - longprof.save("longprof.txt"); - - std::ofstream finish("finished"); - finish << "run completed without error" << std::endl; + hists.saveLab("inthist_lab_verticalEAS.npz"); + hists.saveCMS("inthist_cms_verticalEAS.npz"); + longprof.save("longprof_verticalEAS.txt"); } diff --git a/Environment/CMakeLists.txt b/Environment/CMakeLists.txt index 5536d2ea3e9aee1c2f3df00ed4b3b7db81d6e138..f0adcf74a8fcbd55abf8eaec6b75a42700630f6d 100644 --- a/Environment/CMakeLists.txt +++ b/Environment/CMakeLists.txt @@ -49,7 +49,7 @@ target_link_libraries ( CORSIKAgeometry CORSIKAparticles CORSIKAunits - CORSIKArandom + CORSIKAlogging ) target_include_directories ( diff --git a/Environment/ShowerAxis.cc b/Environment/ShowerAxis.cc index fadc86ab352b5285021b4c6dfe4006e34ddab3a9..3cc5779e08a6c411a39a7d5aeec0831f5c1e4f2b 100644 --- a/Environment/ShowerAxis.cc +++ b/Environment/ShowerAxis.cc @@ -7,7 +7,9 @@ */ #include <corsika/environment/ShowerAxis.h> -#include <sstream> +#include <corsika/logging/Logging.h> + +#include <string> using namespace corsika::environment; using namespace corsika::units::si; @@ -20,19 +22,22 @@ GrammageType ShowerAxis::X(LengthType l) const { decltype(X_.size()) const upper = lower + 1; if (lower < 0) { + C8LOG_ERROR("cannot extrapolate to points behind point of injection l={} m", l / 1_m); throw std::runtime_error("cannot extrapolate to points behind point of injection"); } if (upper >= X_.size()) { - std::stringstream errormsg; - errormsg << "shower axis too short, cannot extrapolate (l / max_length_ = " - << l / max_length_ << ")"; - throw std::runtime_error(errormsg.str().c_str()); + const std::string err = + fmt::format("shower axis too short, cannot extrapolate (l / max_length_ = {} )", + l / max_length_); + C8LOG_ERROR(err); + throw std::runtime_error(err.c_str()); } assert(0 <= lambda && lambda <= 1.); - std::cout << l << ": " << lower << " " << lambda << " " << upper << std::endl; + C8LOG_TRACE("ShowerAxis::X l={} m, lower={}, lambda={}, upper={}", l / 1_m, lower, + lambda, upper); // linear interpolation between X[lower] and X[upper] return X_[upper] * lambda + X_[lower] * (1 - lambda); diff --git a/Framework/Analytics/testClassTimer.cc b/Framework/Analytics/testClassTimer.cc index 290eabc0e3e8362c126ca2b6a13ee3b47e1b19b8..95f82b4b2caa93394634e5c39ee542dacda94f2f 100644 --- a/Framework/Analytics/testClassTimer.cc +++ b/Framework/Analytics/testClassTimer.cc @@ -110,7 +110,7 @@ TEST_CASE("Analytics", "[Timer]") { tc.call(); - REQUIRE(tc.getTime().count() == Approx(100000).margin(1000)); + CHECK(tc.getTime().count() == Approx(100000).margin(10000)); } SECTION("Measure runtime of a function with arguments") { @@ -120,7 +120,7 @@ TEST_CASE("Analytics", "[Timer]") { tc.call(1); - REQUIRE(tc.getTime().count() == Approx(100000).margin(1000)); + CHECK(tc.getTime().count() == Approx(100000).margin(10000)); } SECTION("Measure runtime of a const function without arguments") { @@ -131,17 +131,17 @@ TEST_CASE("Analytics", "[Timer]") { tc.call(); - REQUIRE(tc.getTime().count() == Approx(100000).margin(1000)); + CHECK(tc.getTime().count() == Approx(100000).margin(10000)); } SECTION("Measure runtime of function inside class") { auto test = foo(); - REQUIRE(test.inside() == 123); + CHECK(test.inside() == 123); } SECTION("Measure runtime of function inside class") { auto test = fooT3<fooT1>(); - REQUIRE(test.inside_t(1, 'a', 'b') == 123); + CHECK(test.inside_t(1, 'a', 'b') == 123); } } diff --git a/Framework/Cascade/CMakeLists.txt b/Framework/Cascade/CMakeLists.txt index 9bb6019340dc8578c4f9016091e0cc2c1de0162f..2a12099736e967a7bbcfc9db3395f46fc94590cd 100644 --- a/Framework/Cascade/CMakeLists.txt +++ b/Framework/Cascade/CMakeLists.txt @@ -51,6 +51,5 @@ target_link_libraries ( CORSIKAcascade ProcessStackInspector ProcessTrackingLine - ProcessNullModel CORSIKAtesting ) diff --git a/Framework/Cascade/Cascade.h b/Framework/Cascade/Cascade.h index b520acddde752d6e4b0db7d3cdf711f154b1689c..43a5275435480e45aaa3bb06ac824f2ba5636f40 100644 --- a/Framework/Cascade/Cascade.h +++ b/Framework/Cascade/Cascade.h @@ -74,11 +74,11 @@ namespace corsika::cascade { private: // Data members - corsika::environment::Environment<MediumInterface> const& fEnvironment; - TTracking& fTracking; - TProcessList& fProcessSequence; - TStack& fStack; - corsika::random::RNG& fRNG = + corsika::environment::Environment<MediumInterface> const& environment_; + TTracking& tracking_; + TProcessList& process_sequence_; + TStack& stack_; + corsika::random::RNG& rng_ = corsika::random::RNGManager::GetInstance().GetRandomStream("cascade"); unsigned int count_ = 0; @@ -93,27 +93,15 @@ namespace corsika::cascade { */ Cascade(corsika::environment::Environment<MediumInterface> const& env, TTracking& tr, TProcessList& pl, TStack& stack) - : fEnvironment(env) - , fTracking(tr) - , fProcessSequence(pl) - , fStack(stack) + : environment_(env) + , tracking_(tr) + , process_sequence_(pl) + , stack_(stack) , count_(0) { C8LOG_INFO(c8_ascii_); -#ifdef WITH_HISTORY - C8LOG_INFO(" - With full cascade HISTORY."); -#endif - } - - /** - * set the nodes for all particles on the stack according to their numerical - * position - */ - void SetNodes() { - std::for_each(fStack.begin(), fStack.end(), [&](auto& p) { - auto const* numericalNode = - fEnvironment.GetUniverse()->GetContainingNode(p.GetPosition()); - p.SetNode(numericalNode); - }); + if constexpr (TStackView::has_event) { + C8LOG_INFO(" - With full cascade HISTORY."); + } } /** @@ -121,20 +109,20 @@ namespace corsika::cascade { * particles from the Stack until the Stack is empty. */ void Run() { - SetNodes(); + setNodes(); - while (!fStack.IsEmpty()) { - while (!fStack.IsEmpty()) { - C8LOG_TRACE(fmt::format("Stack: {}", fStack.as_string())); + while (!stack_.IsEmpty()) { + while (!stack_.IsEmpty()) { + C8LOG_TRACE("Stack: {}", stack_.as_string()); count_++; - auto pNext = fStack.GetNextParticle(); - C8LOG_DEBUG(fmt::format( + auto pNext = stack_.GetNextParticle(); + C8LOG_DEBUG( "============== next particle : count={}, pid={}, " ", stack entries={}" ", stack deleted={}", - count_, pNext.GetPID(), fStack.getEntries(), fStack.getDeleted())); + count_, pNext.GetPID(), stack_.getEntries(), stack_.getDeleted()); Step(pNext); - fProcessSequence.DoStack(fStack); + process_sequence_.DoStack(stack_); } // do cascade equations, which can put new particles on Stack, // thus, the double loop @@ -149,11 +137,12 @@ namespace corsika::cascade { */ void forceInteraction() { C8LOG_DEBUG("forced interaction!"); - auto vParticle = fStack.GetNextParticle(); + setNodes(); + auto vParticle = stack_.GetNextParticle(); TStackView secondaries(vParticle); - interaction(vParticle, secondaries); - fProcessSequence.DoSecondaries(secondaries); - vParticle.Delete(); // todo: this should be reviewed, see below + interaction(secondaries); + process_sequence_.DoSecondaries(secondaries); + vParticle.Delete(); // primary particle has interacted and is gone } private: @@ -172,16 +161,16 @@ namespace corsika::cascade { using namespace corsika::units::si; // determine geometric tracking - auto [step, geomMaxLength, nextVol] = fTracking.GetTrack(vParticle); + auto [step, geomMaxLength, nextVol] = tracking_.GetTrack(vParticle); [[maybe_unused]] auto const& dummy_nextVol = nextVol; // determine combined total interaction length (inverse) InverseGrammageType const total_inv_lambda = - fProcessSequence.GetTotalInverseInteractionLength(vParticle); + process_sequence_.GetInverseInteractionLength(vParticle); // sample random exponential step length in grammage corsika::random::ExponentialDistribution expDist(1 / total_inv_lambda); - GrammageType const next_interact = expDist(fRNG); + GrammageType const next_interact = expDist(rng_); C8LOG_DEBUG( "total_lambda={} g/cm2, " @@ -193,8 +182,8 @@ namespace corsika::cascade { // assert that particle stays outside void Universe if it has no // model properties set - assert(currentLogicalNode != &*fEnvironment.GetUniverse() || - fEnvironment.GetUniverse()->HasModelProperties()); + assert(currentLogicalNode != &*environment_.GetUniverse() || + environment_.GetUniverse()->HasModelProperties()); // convert next_step from grammage to length LengthType const distance_interact = @@ -202,16 +191,16 @@ namespace corsika::cascade { next_interact); // determine the maximum geometric step length from continuous processes - LengthType const distance_max = fProcessSequence.MaxStepLength(vParticle, step); + LengthType const distance_max = process_sequence_.MaxStepLength(vParticle, step); C8LOG_DEBUG("distance_max={} m", distance_max / 1_m); // determine combined total inverse decay time InverseTimeType const total_inv_lifetime = - fProcessSequence.GetTotalInverseLifetime(vParticle); + process_sequence_.GetInverseLifetime(vParticle); // sample random exponential decay time corsika::random::ExponentialDistribution expDistDecay(1 / total_inv_lifetime); - TimeType const next_decay = expDistDecay(fRNG); + TimeType const next_decay = expDistDecay(rng_); C8LOG_DEBUG( "total_lifetime={} s" ", next_decay={} s", @@ -236,12 +225,11 @@ namespace corsika::cascade { step.LimitEndTo(min_distance); // apply all continuous processes on particle + track - process::EProcessReturn status = fProcessSequence.DoContinuous(vParticle, step); - - if (status == process::EProcessReturn::eParticleAbsorbed) { + if (process_sequence_.DoContinuous(vParticle, step) == + process::EProcessReturn::eParticleAbsorbed) { C8LOG_DEBUG("Cascade: delete absorbed particle PID={} E={} GeV", vParticle.GetPID(), vParticle.GetEnergy() / 1_GeV); - vParticle.Delete(); + if (!vParticle.isDeleted()) vParticle.Delete(); return; } @@ -271,10 +259,10 @@ namespace corsika::cascade { [[maybe_unused]] auto projectile = secondaries.GetProjectile(); if (min_distance == distance_interact) { - interaction(vParticle, secondaries); + interaction(secondaries); } else { assert(min_distance == distance_decay); - decay(vParticle, secondaries); + decay(secondaries); // make sure particle actually did decay if it should have done so if (secondaries.getSize() == 1 && projectile.GetPID() == secondaries.GetNextParticle().GetPID()) @@ -283,7 +271,7 @@ namespace corsika::cascade { particles::GetName(projectile.GetPID()))); } - fProcessSequence.DoSecondaries(secondaries); + process_sequence_.DoSecondaries(secondaries); vParticle.Delete(); } else { // step-length limitation within volume @@ -293,10 +281,9 @@ namespace corsika::cascade { [[maybe_unused]] auto const assertion = [&] { auto const* numericalNodeAfterStep = - fEnvironment.GetUniverse()->GetContainingNode(vParticle.GetPosition()); - C8LOG_TRACE(fmt::format( - "Geometry check: numericalNodeAfterStep={} currentLogicalNode={}", - fmt::ptr(numericalNodeAfterStep), fmt::ptr(currentLogicalNode))); + environment_.GetUniverse()->GetContainingNode(vParticle.GetPosition()); + C8LOG_TRACE("Geometry check: numericalNodeAfterStep={} currentLogicalNode={}", + fmt::ptr(numericalNodeAfterStep), fmt::ptr(currentLogicalNode)); return numericalNodeAfterStep == currentLogicalNode; }; @@ -306,45 +293,61 @@ namespace corsika::cascade { /* DoBoundary may delete the particle (or not) - small caveat: any changes to vParticle, or even the production + caveat: any changes to vParticle, or even the production of new secondaries is currently not passed to ParticleCut, thus, particles outside the desired phase space may be produced. + + todo: this must be fixed. */ - fProcessSequence.DoBoundaryCrossing(vParticle, *currentLogicalNode, *nextVol); + process_sequence_.DoBoundaryCrossing(vParticle, *currentLogicalNode, *nextVol); } } - auto decay(Particle& particle, TStackView& view) { + process::EProcessReturn decay(TStackView& view) { C8LOG_DEBUG("decay"); units::si::InverseTimeType const actual_decay_time = - fProcessSequence.GetTotalInverseLifetime(particle); + process_sequence_.GetInverseLifetime(view.parent()); random::UniformRealDistribution<units::si::InverseTimeType> uniDist( actual_decay_time); - const auto sample_process = uniDist(fRNG); - units::si::InverseTimeType inv_decay_count = units::si::InverseTimeType::zero(); - auto const returnCode = - fProcessSequence.SelectDecay(particle, view, sample_process, inv_decay_count); + const auto sample_process = uniDist(rng_); + auto const returnCode = process_sequence_.SelectDecay(view, sample_process); + if (returnCode != process::EProcessReturn::eDecayed) { + C8LOG_WARN("Particle did not decay!"); + } SetEventType(view, history::EventType::Decay); return returnCode; } - auto interaction(Particle& particle, TStackView& view) { + process::EProcessReturn interaction(TStackView& view) { C8LOG_DEBUG("collide"); units::si::InverseGrammageType const current_inv_length = - fProcessSequence.GetTotalInverseInteractionLength(particle); + process_sequence_.GetInverseInteractionLength(view.parent()); random::UniformRealDistribution<units::si::InverseGrammageType> uniDist( current_inv_length); - const auto sample_process = uniDist(fRNG); - auto inv_lambda_count = units::si::InverseGrammageType::zero(); - auto const returnCode = fProcessSequence.SelectInteraction( - particle, view, sample_process, inv_lambda_count); + const auto sample_process = uniDist(rng_); + auto const returnCode = process_sequence_.SelectInteraction(view, sample_process); + if (returnCode != process::EProcessReturn::eInteracted) { + C8LOG_WARN("Particle did not interace!"); + } SetEventType(view, history::EventType::Interaction); return returnCode; } + /** + * set the nodes for all particles on the stack according to their numerical + * position + */ + void setNodes() { + std::for_each(stack_.begin(), stack_.end(), [&](auto& p) { + auto const* numericalNode = + environment_.GetUniverse()->GetContainingNode(p.GetPosition()); + p.SetNode(numericalNode); + }); + } + void SetEventType(TStackView& view, [[maybe_unused]] history::EventType eventType) { if constexpr (TStackView::has_event) { for (auto&& sec : view) { sec.GetEvent()->setEventType(eventType); } diff --git a/Framework/Cascade/testCascade.cc b/Framework/Cascade/testCascade.cc index 02f974f5245f487c29bd49d00f14216b36312f7d..7cf7b9224327fe3422a86b32e3515f1a44f4af48 100644 --- a/Framework/Cascade/testCascade.cc +++ b/Framework/Cascade/testCascade.cc @@ -11,7 +11,7 @@ #include <corsika/cascade/Cascade.h> #include <corsika/process/ProcessSequence.h> -#include <corsika/process/null_model/NullModel.h> +#include <corsika/process/NullModel.h> #include <corsika/process/stack_inspector/StackInspector.h> #include <corsika/process/tracking_line/TrackingLine.h> @@ -132,13 +132,13 @@ TEST_CASE("Cascade", "[Cascade]") { tracking_line::TrackingLine tracking; stack_inspector::StackInspector<TestCascadeStack> stackInspect(1, true, E0); - null_model::NullModel nullModel; + process::NullModel nullModel; const GrammageType X0 = 20_g / square(1_cm); const HEPEnergyType Ecrit = 85_MeV; ProcessSplit split(X0); ProcessCut cut(Ecrit); - auto sequence = nullModel << stackInspect << split << cut; + auto sequence = process::sequence(nullModel, stackInspect, split, cut); TestCascadeStack stack; stack.Clear(); stack.AddParticle( @@ -161,7 +161,6 @@ TEST_CASE("Cascade", "[Cascade]") { } SECTION("forced interaction") { - EAS.SetNodes(); EAS.forceInteraction(); CHECK(stack.getEntries() == 2); CHECK(split.GetCalls() == 1); diff --git a/Framework/Particles/ParticleProperties.h b/Framework/Particles/ParticleProperties.h index d217aa50ba2299136cd8358293be1eb35964e5dd..7abcc768b5444e15414f6880c6a56aa54b288087 100644 --- a/Framework/Particles/ParticleProperties.h +++ b/Framework/Particles/ParticleProperties.h @@ -54,8 +54,13 @@ namespace corsika::particles { int constexpr GetNucleusA(Code const); int constexpr GetNucleusZ(Code const); +} // namespace corsika::particles + +// here we read the implementation of all those objects and function #include <corsika/particles/GeneratedParticleProperties.inc> +namespace corsika::particles { + /*! * returns mass of particle in natural units */ diff --git a/Framework/Particles/pdxml_reader.py b/Framework/Particles/pdxml_reader.py index 8c80bec9021cc2f798443c806f7bdd794d0752d5..16978d643142950a52993baab35d69987899a79e 100755 --- a/Framework/Particles/pdxml_reader.py +++ b/Framework/Particles/pdxml_reader.py @@ -447,7 +447,8 @@ def gen_classes(particle_db): # def inc_start(): string = ('// generated by pdxml_reader.py\n' - '// MANUAL EDITS ON OWN RISK. THEY WILL BE OVERWRITTEN. \n') + '// MANUAL EDITS ON OWN RISK. THEY WILL BE OVERWRITTEN. \n' + 'namespace corsika::particles {\n') return string @@ -463,14 +464,14 @@ def detail_start(): # # def detail_end(): - string = "\n}//end namespace detail\n" + string = "\n} // end namespace detail\n" return string ############################################################### # # def inc_end(): - string = "" + string = "\n} // end namespace corsika::particles\n" return string diff --git a/Framework/Particles/testParticles.cc b/Framework/Particles/testParticles.cc index e01f0b1fb8f93ab0db33c4cf4b270eab19720fbb..8b3f7184c6b31d5b447dbdb173847cdfc0d080ae 100644 --- a/Framework/Particles/testParticles.cc +++ b/Framework/Particles/testParticles.cc @@ -18,123 +18,126 @@ using namespace corsika::particles; TEST_CASE("ParticleProperties", "[Particles]") { SECTION("Types") { - REQUIRE(Electron::GetCode() == Code::Electron); - REQUIRE(Positron::GetCode() == Code::Positron); - REQUIRE(Proton::GetCode() == Code::Proton); - REQUIRE(Neutron::GetCode() == Code::Neutron); - REQUIRE(Gamma::GetCode() == Code::Gamma); - REQUIRE(PiPlus::GetCode() == Code::PiPlus); + CHECK(Electron::GetCode() == Code::Electron); + CHECK(Positron::GetCode() == Code::Positron); + CHECK(Proton::GetCode() == Code::Proton); + CHECK(Neutron::GetCode() == Code::Neutron); + CHECK(Gamma::GetCode() == Code::Gamma); + CHECK(PiPlus::GetCode() == Code::PiPlus); } SECTION("Masses") { - REQUIRE(Electron::GetMass() / (511_keV) == Approx(1)); - REQUIRE(Electron::GetMass() / GetMass(Code::Electron) == Approx(1)); + CHECK(Electron::GetMass() / (511_keV) == Approx(1)); + CHECK(Electron::GetMass() / GetMass(Code::Electron) == Approx(1)); - REQUIRE((Proton::GetMass() + Neutron::GetMass()) / - corsika::units::constants::nucleonMass == - Approx(2)); + CHECK((Proton::GetMass() + Neutron::GetMass()) / + corsika::units::constants::nucleonMass == + Approx(2)); } SECTION("Charges") { - REQUIRE(Electron::GetCharge() / constants::e == Approx(-1)); - REQUIRE(Positron::GetCharge() / constants::e == Approx(+1)); - REQUIRE(GetCharge(Positron::GetAntiParticle()) / constants::e == Approx(-1)); + CHECK(Electron::GetCharge() / constants::e == Approx(-1)); + CHECK(Positron::GetCharge() / constants::e == Approx(+1)); + CHECK(GetCharge(Positron::GetAntiParticle()) / constants::e == Approx(-1)); } SECTION("Names") { - REQUIRE(Electron::GetName() == "e-"); - REQUIRE(PiMinus::GetName() == "pi-"); - REQUIRE(Nucleus::GetName() == "nucleus"); - REQUIRE(Iron::GetName() == "iron"); + CHECK(Electron::GetName() == "e-"); + CHECK(PiMinus::GetName() == "pi-"); + CHECK(Nucleus::GetName() == "nucleus"); + CHECK(Iron::GetName() == "iron"); } SECTION("PDG") { - REQUIRE(GetPDG(Code::PiPlus) == PDGCode::PiPlus); - REQUIRE(GetPDG(Code::DPlus) == PDGCode::DPlus); - REQUIRE(GetPDG(Code::NuMu) == PDGCode::NuMu); - REQUIRE(GetPDG(Code::NuE) == PDGCode::NuE); - REQUIRE(GetPDG(Code::MuMinus) == PDGCode::MuMinus); - - REQUIRE(static_cast<int>(GetPDG(Code::PiPlus)) == 211); - REQUIRE(static_cast<int>(GetPDG(Code::DPlus)) == 411); - REQUIRE(static_cast<int>(GetPDG(Code::NuMu)) == 14); - REQUIRE(static_cast<int>(GetPDG(Code::NuEBar)) == -12); - REQUIRE(static_cast<int>(GetPDG(Code::MuMinus)) == 13); + CHECK(GetPDG(Code::PiPlus) == PDGCode::PiPlus); + CHECK(GetPDG(Code::DPlus) == PDGCode::DPlus); + CHECK(GetPDG(Code::NuMu) == PDGCode::NuMu); + CHECK(GetPDG(Code::NuE) == PDGCode::NuE); + CHECK(GetPDG(Code::MuMinus) == PDGCode::MuMinus); + + CHECK(static_cast<int>(GetPDG(Code::PiPlus)) == 211); + CHECK(static_cast<int>(GetPDG(Code::DPlus)) == 411); + CHECK(static_cast<int>(GetPDG(Code::NuMu)) == 14); + CHECK(static_cast<int>(GetPDG(Code::NuEBar)) == -12); + CHECK(static_cast<int>(GetPDG(Code::MuMinus)) == 13); } SECTION("Conversion PDG -> internal") { - REQUIRE(ConvertFromPDG(PDGCode::KStarMinus) == Code::KStarMinus); - REQUIRE(ConvertFromPDG(PDGCode::MuPlus) == Code::MuPlus); - REQUIRE(ConvertFromPDG(PDGCode::SigmaStarCMinusBar) == Code::SigmaStarCMinusBar); + CHECK(ConvertFromPDG(PDGCode::KStarMinus) == Code::KStarMinus); + CHECK(ConvertFromPDG(PDGCode::MuPlus) == Code::MuPlus); + CHECK(ConvertFromPDG(PDGCode::SigmaStarCMinusBar) == Code::SigmaStarCMinusBar); } SECTION("Lifetimes") { - REQUIRE(GetLifetime(Code::Electron) == - std::numeric_limits<double>::infinity() * corsika::units::si::second); - REQUIRE(GetLifetime(Code::DPlus) < GetLifetime(Code::Gamma)); - REQUIRE(GetLifetime(Code::RhoPlus) / corsika::units::si::second == - (Approx(4.414566727909413e-24).epsilon(1e-3))); - REQUIRE(GetLifetime(Code::SigmaMinusBar) / corsika::units::si::second == - (Approx(8.018880848563575e-11).epsilon(1e-5))); - REQUIRE(GetLifetime(Code::MuPlus) / corsika::units::si::second == - (Approx(2.1970332555864364e-06).epsilon(1e-5))); + CHECK(GetLifetime(Code::Electron) == + std::numeric_limits<double>::infinity() * corsika::units::si::second); + CHECK(GetLifetime(Code::DPlus) < GetLifetime(Code::Gamma)); + CHECK(GetLifetime(Code::RhoPlus) / corsika::units::si::second == + (Approx(4.414566727909413e-24).epsilon(1e-3))); + CHECK(GetLifetime(Code::SigmaMinusBar) / corsika::units::si::second == + (Approx(8.018880848563575e-11).epsilon(1e-5))); + CHECK(GetLifetime(Code::MuPlus) / corsika::units::si::second == + (Approx(2.1970332555864364e-06).epsilon(1e-5))); } SECTION("Particle groups: electromagnetic") { - REQUIRE(IsEM(Code::Gamma)); - REQUIRE(IsEM(Code::Electron)); - REQUIRE_FALSE(IsEM(Code::MuPlus)); - REQUIRE_FALSE(IsEM(Code::NuE)); - REQUIRE_FALSE(IsEM(Code::Proton)); - REQUIRE_FALSE(IsEM(Code::PiPlus)); - REQUIRE_FALSE(IsEM(Code::Oxygen)); + CHECK(IsEM(Code::Gamma)); + CHECK(IsEM(Code::Electron)); + CHECK_FALSE(IsEM(Code::MuPlus)); + CHECK_FALSE(IsEM(Code::NuE)); + CHECK_FALSE(IsEM(Code::Proton)); + CHECK_FALSE(IsEM(Code::PiPlus)); + CHECK_FALSE(IsEM(Code::Oxygen)); } SECTION("Particle groups: hadrons") { - REQUIRE_FALSE(IsHadron(Code::Gamma)); - REQUIRE_FALSE(IsHadron(Code::Electron)); - REQUIRE_FALSE(IsHadron(Code::MuPlus)); - REQUIRE_FALSE(IsHadron(Code::NuE)); - REQUIRE(IsHadron(Code::Proton)); - REQUIRE(IsHadron(Code::PiPlus)); - REQUIRE(IsHadron(Code::Oxygen)); - REQUIRE(IsHadron(Code::Nucleus)); + CHECK_FALSE(IsHadron(Code::Gamma)); + CHECK_FALSE(IsHadron(Code::Electron)); + CHECK_FALSE(IsHadron(Code::MuPlus)); + CHECK_FALSE(IsHadron(Code::NuE)); + CHECK(IsHadron(Code::Proton)); + CHECK(IsHadron(Code::PiPlus)); + CHECK(IsHadron(Code::Oxygen)); + CHECK(IsHadron(Code::Nucleus)); } SECTION("Particle groups: muons") { - REQUIRE_FALSE(IsMuon(Code::Gamma)); - REQUIRE_FALSE(IsMuon(Code::Electron)); - REQUIRE(IsMuon(Code::MuPlus)); - REQUIRE_FALSE(IsMuon(Code::NuE)); - REQUIRE_FALSE(IsMuon(Code::Proton)); - REQUIRE_FALSE(IsMuon(Code::PiPlus)); - REQUIRE_FALSE(IsMuon(Code::Oxygen)); + CHECK_FALSE(IsMuon(Code::Gamma)); + CHECK_FALSE(IsMuon(Code::Electron)); + CHECK(IsMuon(Code::MuPlus)); + CHECK_FALSE(IsMuon(Code::NuE)); + CHECK_FALSE(IsMuon(Code::Proton)); + CHECK_FALSE(IsMuon(Code::PiPlus)); + CHECK_FALSE(IsMuon(Code::Oxygen)); } SECTION("Particle groups: neutrinos") { - REQUIRE_FALSE(IsNeutrino(Code::Gamma)); - REQUIRE_FALSE(IsNeutrino(Code::Electron)); - REQUIRE_FALSE(IsNeutrino(Code::MuPlus)); - REQUIRE(IsNeutrino(Code::NuE)); - REQUIRE_FALSE(IsNeutrino(Code::Proton)); - REQUIRE_FALSE(IsNeutrino(Code::PiPlus)); - REQUIRE_FALSE(IsNeutrino(Code::Oxygen)); + CHECK_FALSE(IsNeutrino(Code::Gamma)); + CHECK_FALSE(IsNeutrino(Code::Electron)); + CHECK_FALSE(IsNeutrino(Code::MuPlus)); + CHECK(IsNeutrino(Code::NuE)); + CHECK_FALSE(IsNeutrino(Code::Proton)); + CHECK_FALSE(IsNeutrino(Code::PiPlus)); + CHECK_FALSE(IsNeutrino(Code::Oxygen)); } SECTION("Nuclei") { - REQUIRE_FALSE(IsNucleus(Code::Gamma)); - REQUIRE(IsNucleus(Code::Argon)); - REQUIRE_FALSE(IsNucleus(Code::Proton)); - REQUIRE(IsNucleus(Code::Hydrogen)); - REQUIRE(Argon::IsNucleus()); - REQUIRE_FALSE(EtaC::IsNucleus()); - - REQUIRE(GetNucleusA(Code::Hydrogen) == 1); - REQUIRE(GetNucleusA(Code::Tritium) == 3); - REQUIRE(Hydrogen::GetNucleusZ() == 1); - REQUIRE(Tritium::GetNucleusA() == 3); - - REQUIRE_THROWS(GetNucleusA(Code::Nucleus)); - REQUIRE_THROWS(GetNucleusZ(Code::Nucleus)); + CHECK_FALSE(IsNucleus(Code::Gamma)); + CHECK(IsNucleus(Code::Argon)); + CHECK_FALSE(IsNucleus(Code::Proton)); + CHECK(IsNucleus(Code::Hydrogen)); + CHECK(Argon::IsNucleus()); + CHECK_FALSE(EtaC::IsNucleus()); + + CHECK(GetNucleusA(Code::Hydrogen) == 1); + CHECK(GetNucleusA(Code::Tritium) == 3); + CHECK(Hydrogen::GetNucleusZ() == 1); + CHECK(Tritium::GetNucleusA() == 3); + + // Nucleus is a generic object, it has no specific properties + CHECK_THROWS(GetNucleusA(Code::Nucleus)); + CHECK_THROWS(GetNucleusZ(Code::Nucleus)); + CHECK_THROWS(GetMass(Code::Nucleus)); + CHECK_THROWS(GetCharge(Code::Nucleus)); } } diff --git a/Framework/ProcessSequence/BaseProcess.h b/Framework/ProcessSequence/BaseProcess.h index 42934bbe9f6309ab437f16843ccddd696e1a3e46..c1a4e232e0e0689b67aaca62af99b0abcfb47c8f 100644 --- a/Framework/ProcessSequence/BaseProcess.h +++ b/Framework/ProcessSequence/BaseProcess.h @@ -21,6 +21,7 @@ namespace corsika::process { ProcessSequence. Both, the ProcessSequence and all its elements are of type BaseProcess<T> + \todo rename BaseProcess into just Process */ class _BaseProcess {}; diff --git a/Framework/ProcessSequence/CMakeLists.txt b/Framework/ProcessSequence/CMakeLists.txt index 811e2c3864c4d617043586842c03bcc74db3bb6f..7a75548932875f31f19f4fdd0aab3fbf19cbf867 100644 --- a/Framework/ProcessSequence/CMakeLists.txt +++ b/Framework/ProcessSequence/CMakeLists.txt @@ -17,7 +17,10 @@ set ( StackProcess.h DecayProcess.h ProcessSequence.h + SwitchProcessSequence.h ProcessReturn.h + ProcessTraits.h + NullModel.h ) CORSIKA_COPY_HEADERS_TO_NAMESPACE (CORSIKAprocesssequence ${CORSIKAprocesssequence_NAMESPACE} ${CORSIKAprocesssequence_HEADERS}) @@ -27,6 +30,7 @@ target_link_libraries ( CORSIKAprocesssequence INTERFACE CORSIKAsetup + CORSIKAlogging ) target_include_directories ( @@ -53,8 +57,26 @@ target_link_libraries ( CORSIKA_ADD_TEST (testProcessSequence) target_link_libraries ( testProcessSequence - ProcessSwitch CORSIKAgeometry CORSIKAprocesssequence CORSIKAtesting ) + +# -------------------- +# code unit testing +CORSIKA_ADD_TEST (testNullModel) +target_link_libraries ( + testNullModel + CORSIKAsetup + CORSIKAgeometry + CORSIKAunits + CORSIKAtesting + ) + +# # CORSIKA_ADD_TEST (testSwitchProcessSequence) +# # target_link_libraries ( +# # testSwitchProcessSequence +# # CORSIKAgeometry +# # CORSIKAprocesssequence +# # CORSIKAtesting +# # ) diff --git a/Framework/ProcessSequence/ContinuousProcess.h b/Framework/ProcessSequence/ContinuousProcess.h index 2c9e7bbc854b6000ec2e41f93c75a8aa509b771f..c4138a755264be14c3551ddbb310dceb2495231a 100644 --- a/Framework/ProcessSequence/ContinuousProcess.h +++ b/Framework/ProcessSequence/ContinuousProcess.h @@ -9,7 +9,6 @@ #pragma once #include <corsika/process/BaseProcess.h> -#include <corsika/process/ProcessReturn.h> // for convenience #include <corsika/units/PhysicalUnits.h> namespace corsika::process { diff --git a/Framework/ProcessSequence/DecayProcess.h b/Framework/ProcessSequence/DecayProcess.h index eb0cf982f08a166948becba132ab6346baa60365..09ba807434de88dbbe1952ebf1c86de7e260d0ed 100644 --- a/Framework/ProcessSequence/DecayProcess.h +++ b/Framework/ProcessSequence/DecayProcess.h @@ -9,8 +9,6 @@ #pragma once #include <corsika/process/BaseProcess.h> -#include <corsika/process/ProcessReturn.h> // for convenience -#include <corsika/setup/SetupTrajectory.h> #include <corsika/units/PhysicalUnits.h> namespace corsika::process { @@ -35,12 +33,17 @@ namespace corsika::process { EProcessReturn DoDecay(TParticle&); template <typename TParticle> - corsika::units::si::TimeType GetLifetime(TParticle& p); + corsika::units::si::TimeType GetLifetime(const TParticle&); template <typename TParticle> - corsika::units::si::InverseTimeType GetInverseLifetime(TParticle& vP) { - return 1. / GetRef().GetLifetime(vP); + corsika::units::si::InverseTimeType GetInverseLifetime(const TParticle& particle) { + return 1. / GetRef().GetLifetime(particle); } + + /* template <typename TParticle> + corsika::units::si::InverseTimeType GetInverseInteractionLength(TParticle&& particle) + { auto p = std::move(particle); return 1. / GetRef().GetLifetime(p); + }*/ }; } // namespace corsika::process diff --git a/Framework/ProcessSequence/InteractionProcess.h b/Framework/ProcessSequence/InteractionProcess.h index cfecccc8156d3b4519209ba5efe9c965f1f89b93..e70729db8d2ae7ba3149b1f42ade39d78aaf29b5 100644 --- a/Framework/ProcessSequence/InteractionProcess.h +++ b/Framework/ProcessSequence/InteractionProcess.h @@ -9,8 +9,6 @@ #pragma once #include <corsika/process/BaseProcess.h> -#include <corsika/process/ProcessReturn.h> // for convenience -#include <corsika/setup/SetupTrajectory.h> #include <corsika/units/PhysicalUnits.h> namespace corsika::process { @@ -35,11 +33,12 @@ namespace corsika::process { EProcessReturn DoInteraction(TParticle&); template <typename TParticle> - corsika::units::si::GrammageType GetInteractionLength(TParticle& p); + corsika::units::si::GrammageType GetInteractionLength(const TParticle&); template <typename TParticle> - corsika::units::si::InverseGrammageType GetInverseInteractionLength(TParticle& p) { - return 1. / GetRef().GetInteractionLength(p); + corsika::units::si::InverseGrammageType GetInverseInteractionLength( + const TParticle& particle) { + return 1. / GetRef().GetInteractionLength(particle); } }; diff --git a/Framework/ProcessSequence/NullModel.h b/Framework/ProcessSequence/NullModel.h new file mode 100644 index 0000000000000000000000000000000000000000..feb0debd90b9063cab60c48ae96e7c16ffbc5207 --- /dev/null +++ b/Framework/ProcessSequence/NullModel.h @@ -0,0 +1,22 @@ +/* + * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu + * + * This software is distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3). See file LICENSE for a full version of + * the license. + */ + +#pragma once + +#include <corsika/process/BaseProcess.h> + +namespace corsika::process { + + class NullModel : public corsika::process::BaseProcess<NullModel> { + + public: + NullModel() = default; + ~NullModel() = default; + }; + +} // namespace corsika::process diff --git a/Framework/ProcessSequence/ProcessReturn.h b/Framework/ProcessSequence/ProcessReturn.h index ae1e45b951d7a2ff144c6d683bc7b88ff93eb831..c4e7d5890411e461b8d50c4b31d44e6803b6c8d2 100644 --- a/Framework/ProcessSequence/ProcessReturn.h +++ b/Framework/ProcessSequence/ProcessReturn.h @@ -39,8 +39,20 @@ namespace corsika::process { return (static_cast<int>(a) & static_cast<int>(b)) != 0; } + inline bool isOk(const EProcessReturn a) { + return static_cast<int>(a & EProcessReturn::eOk); + } + inline bool isAbsorbed(const EProcessReturn a) { return static_cast<int>(a & EProcessReturn::eParticleAbsorbed); } + inline bool isDecayed(const EProcessReturn a) { + return static_cast<int>(a & EProcessReturn::eDecayed); + } + + inline bool isInteracted(const EProcessReturn a) { + return static_cast<int>(a & EProcessReturn::eInteracted); + } + } // namespace corsika::process diff --git a/Framework/ProcessSequence/ProcessSequence.h b/Framework/ProcessSequence/ProcessSequence.h index ea125461368ae712407070ac56b6d993dff62ea4..adffdd9ebfe443cbcc590c472b18c2ed1f4ecdcd 100644 --- a/Framework/ProcessSequence/ProcessSequence.h +++ b/Framework/ProcessSequence/ProcessSequence.h @@ -9,6 +9,7 @@ #pragma once #include <corsika/process/BaseProcess.h> +#include <corsika/process/ProcessTraits.h> #include <corsika/process/BoundaryCrossingProcess.h> #include <corsika/process/ContinuousProcess.h> #include <corsika/process/DecayProcess.h> @@ -16,7 +17,9 @@ #include <corsika/process/ProcessReturn.h> #include <corsika/process/SecondariesProcess.h> #include <corsika/process/StackProcess.h> +#include <corsika/process/NullModel.h> #include <corsika/units/PhysicalUnits.h> +#include <corsika/logging/Logging.h> #include <cmath> #include <limits> @@ -28,101 +31,80 @@ namespace corsika::process { A compile time static list of processes. The compiler will generate a new type based on template logic containing all the - elements. + elements provided by the user. + + TProcess1 and TProcess2 must both be derived from BaseProcess, + and are both references if possible (lvalue), otherwise (rvalue) + they are just classes. This allows us to handle both, rvalue as + well as lvalue Processes in the ProcessSequence. \comment Using CRTP pattern, https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ + template <typename TProcess1, typename TProcess2 = NullModel> + class ProcessSequence : public BaseProcess<ProcessSequence<TProcess1, TProcess2>> { - // this is a marker to track which BaseProcess is also a ProcessSequence - template <typename TClass> - struct is_process_sequence : std::false_type {}; - - template <typename TClass> - bool constexpr is_process_sequence_v = is_process_sequence<TClass>::value; - - // we also need a marker to identify SwitchProcess - namespace switch_process { - template <typename TProcess1, typename TProcess2> - class SwitchProcess; // fwd-decl. - } - - // to detect SwitchProcesses inside the ProcessSequence - template <typename TClass> - struct is_switch_process : std::false_type {}; - - template <typename TClass> - bool constexpr is_switch_process_v = is_switch_process<TClass>::value; - - template <typename Process1, typename Process2> - struct is_switch_process<switch_process::SwitchProcess<Process1, Process2>> - : std::true_type {}; - - /** - T1 and T2 are both references if possible (lvalue), otherwise - (rvalue) they are just classes. This allows us to handle both, - rvalue as well as lvalue Processes in the ProcessSequence. - */ - template <typename T1, typename T2> - class ProcessSequence : public BaseProcess<ProcessSequence<T1, T2>> { + using TProcess1type = typename std::decay_t<TProcess1>; + using TProcess2type = typename std::decay_t<TProcess2>; - using T1type = typename std::decay<T1>::type; - using T2type = typename std::decay<T2>::type; + static bool constexpr t1ProcSeq = is_process_sequence_v<TProcess1type>; + static bool constexpr t2ProcSeq = is_process_sequence_v<TProcess2type>; - static bool constexpr t1ProcSeq = is_process_sequence_v<T1type>; - static bool constexpr t2ProcSeq = is_process_sequence_v<T2type>; + static bool constexpr t1SwitchProcSeq = is_switch_process_sequence_v<TProcess1type>; + static bool constexpr t2SwitchProcSeq = is_switch_process_sequence_v<TProcess2type>; - static bool constexpr t1SwitchProc = is_switch_process_v<T1type>; - static bool constexpr t2SwitchProc = is_switch_process_v<T2type>; + TProcess1 A_; // this is a reference, if possible + TProcess2 B_; // this is a reference, if possible public: - T1 A; // this is a reference, if possible - T2 B; // this is a reference, if possible + ProcessSequence(TProcess1 in_A, TProcess2 in_B) + : A_(in_A) + , B_(in_B) {} - ProcessSequence(T1 in_A, T2 in_B) - : A(in_A) - , B(in_B) {} - - template <typename Particle, typename VTNType> - EProcessReturn DoBoundaryCrossing(Particle& p, VTNType const& from, - VTNType const& to) { + template <typename TParticle, typename TVTNType> + EProcessReturn DoBoundaryCrossing(TParticle& particle, TVTNType const& from, + TVTNType const& to) { EProcessReturn ret = EProcessReturn::eOk; - if constexpr (std::is_base_of_v<BoundaryCrossingProcess<T1type>, T1type> || + if constexpr (std::is_base_of_v<BoundaryCrossingProcess<TProcess1type>, + TProcess1type> || t1ProcSeq) { - ret |= A.DoBoundaryCrossing(p, from, to); + ret |= A_.DoBoundaryCrossing(particle, from, to); } - if constexpr (std::is_base_of_v<BoundaryCrossingProcess<T2type>, T2type> || + if constexpr (std::is_base_of_v<BoundaryCrossingProcess<TProcess2type>, + TProcess2type> || t2ProcSeq) { - ret |= B.DoBoundaryCrossing(p, from, to); + ret |= B_.DoBoundaryCrossing(particle, from, to); } return ret; } template <typename TParticle, typename TTrack> - EProcessReturn DoContinuous(TParticle& vP, TTrack& vT) { + inline EProcessReturn DoContinuous(TParticle& particle, TTrack& vT) { EProcessReturn ret = EProcessReturn::eOk; - if constexpr (std::is_base_of_v<ContinuousProcess<T1type>, T1type> || t1ProcSeq) { - if (!isAbsorbed(ret)) { ret |= A.DoContinuous(vP, vT); } + if constexpr (std::is_base_of_v<ContinuousProcess<TProcess1type>, TProcess1type> || + t1ProcSeq) { + ret |= A_.DoContinuous(particle, vT); } - if constexpr (std::is_base_of_v<ContinuousProcess<T2type>, T2type> || t2ProcSeq) { - if (!isAbsorbed(ret)) { ret |= B.DoContinuous(vP, vT); } + if constexpr (std::is_base_of_v<ContinuousProcess<TProcess2type>, TProcess2type> || + t2ProcSeq) { + if (!isAbsorbed(ret)) { ret |= B_.DoContinuous(particle, vT); } } return ret; } template <typename TSecondaries> - EProcessReturn DoSecondaries(TSecondaries& vS) { - EProcessReturn ret = EProcessReturn::eOk; - if constexpr (std::is_base_of_v<SecondariesProcess<T1type>, T1type> || t1ProcSeq) { - ret |= A.DoSecondaries(vS); + inline void DoSecondaries(TSecondaries& vS) { + if constexpr (std::is_base_of_v<SecondariesProcess<TProcess1type>, TProcess1type> || + t1ProcSeq) { + A_.DoSecondaries(vS); } - if constexpr (std::is_base_of_v<SecondariesProcess<T2type>, T2type> || t2ProcSeq) { - ret |= B.DoSecondaries(vS); + if constexpr (std::is_base_of_v<SecondariesProcess<TProcess2type>, TProcess2type> || + t2ProcSeq) { + B_.DoSecondaries(vS); } - return ret; } /** @@ -130,16 +112,18 @@ namespace corsika::process { so they can be exectuted only each N steps. Often these are "maintenacne processes" that do not need to run after each single step of the simulations. In the CheckStep function it is - tested if either A or B are StackProcess and if they are due + tested if either A_ or B_ are StackProcess and if they are due for execution. */ - bool CheckStep() { + inline bool CheckStep() { bool ret = false; - if constexpr (std::is_base_of_v<StackProcess<T1type>, T1type> || t1ProcSeq) { - ret |= A.CheckStep(); + if constexpr (std::is_base_of_v<StackProcess<TProcess1type>, TProcess1type> || + (t1ProcSeq && !t1SwitchProcSeq)) { + ret |= A_.CheckStep(); } - if constexpr (std::is_base_of_v<StackProcess<T2type>, T2type> || t2ProcSeq) { - ret |= B.CheckStep(); + if constexpr (std::is_base_of_v<StackProcess<TProcess2type>, TProcess2type> || + (t2ProcSeq && !t2SwitchProcSeq)) { + ret |= B_.CheckStep(); } return ret; } @@ -148,189 +132,257 @@ namespace corsika::process { Execute the StackProcess-es in the ProcessSequence */ template <typename TStack> - EProcessReturn DoStack(TStack& vS) { - EProcessReturn ret = EProcessReturn::eOk; - if constexpr (std::is_base_of_v<StackProcess<T1type>, T1type> || t1ProcSeq) { - if (A.CheckStep()) { ret |= A.DoStack(vS); } + inline void DoStack(TStack& stack) { + if constexpr (std::is_base_of_v<StackProcess<TProcess1type>, TProcess1type> || + (t1ProcSeq && !t1SwitchProcSeq)) { + if (A_.CheckStep()) { A_.DoStack(stack); } } - if constexpr (std::is_base_of_v<StackProcess<T2type>, T2type> || t2ProcSeq) { - if (B.CheckStep()) { ret |= B.DoStack(vS); } + if constexpr (std::is_base_of_v<StackProcess<TProcess2type>, TProcess2type> || + (t2ProcSeq && !t2SwitchProcSeq)) { + if (B_.CheckStep()) { B_.DoStack(stack); } } - return ret; } template <typename TParticle, typename TTrack> - corsika::units::si::LengthType MaxStepLength(TParticle& vP, TTrack& vTrack) { + inline corsika::units::si::LengthType MaxStepLength(TParticle& particle, + TTrack& vTrack) { corsika::units::si::LengthType max_length = // if no other process in the sequence implements it std::numeric_limits<double>::infinity() * corsika::units::si::meter; - if constexpr (std::is_base_of_v<ContinuousProcess<T1type>, T1type> || t1ProcSeq) { - corsika::units::si::LengthType const len = A.MaxStepLength(vP, vTrack); + if constexpr (std::is_base_of_v<ContinuousProcess<TProcess1type>, TProcess1type> || + t1ProcSeq) { + corsika::units::si::LengthType const len = A_.MaxStepLength(particle, vTrack); max_length = std::min(max_length, len); } - if constexpr (std::is_base_of_v<ContinuousProcess<T2type>, T2type> || t2ProcSeq) { - corsika::units::si::LengthType const len = B.MaxStepLength(vP, vTrack); + if constexpr (std::is_base_of_v<ContinuousProcess<TProcess2type>, TProcess2type> || + t2ProcSeq) { + corsika::units::si::LengthType const len = B_.MaxStepLength(particle, vTrack); max_length = std::min(max_length, len); } return max_length; } template <typename TParticle> - corsika::units::si::GrammageType GetTotalInteractionLength(TParticle& vP) { - return 1. / GetInverseInteractionLength(vP); - } - - template <typename TParticle> - corsika::units::si::InverseGrammageType GetTotalInverseInteractionLength( - TParticle& vP) { - return GetInverseInteractionLength(vP); + inline corsika::units::si::GrammageType GetInteractionLength(TParticle&& particle) { + return 1. / GetInverseInteractionLength(particle); } template <typename TParticle> - corsika::units::si::InverseGrammageType GetInverseInteractionLength(TParticle& vP) { + inline corsika::units::si::InverseGrammageType GetInverseInteractionLength( + TParticle&& particle) { using namespace corsika::units::si; - InverseGrammageType tot = 0 * meter * meter / gram; + InverseGrammageType tot = 0 * meter * meter / gram; // default value - if constexpr (std::is_base_of_v<InteractionProcess<T1type>, T1type> || t1ProcSeq || - t1SwitchProc) { - tot += A.GetInverseInteractionLength(vP); + if constexpr (std::is_base_of_v<InteractionProcess<TProcess1type>, TProcess1type> || + t1ProcSeq) { + tot += A_.GetInverseInteractionLength(particle); } - if constexpr (std::is_base_of_v<InteractionProcess<T2type>, T2type> || t2ProcSeq || - t2SwitchProc) { - tot += B.GetInverseInteractionLength(vP); + if constexpr (std::is_base_of_v<InteractionProcess<TProcess2type>, TProcess2type> || + t2ProcSeq) { + tot += B_.GetInverseInteractionLength(particle); } return tot; } - template <typename TParticle, typename TSecondaries> - EProcessReturn SelectInteraction( - TParticle& vP, TSecondaries& vS, - [[maybe_unused]] corsika::units::si::InverseGrammageType lambda_select, - corsika::units::si::InverseGrammageType& lambda_inv_count) { + template <typename TSecondaryView> + inline EProcessReturn SelectInteraction( + TSecondaryView& view, + [[maybe_unused]] corsika::units::si::InverseGrammageType lambda_inv_select, + [[maybe_unused]] corsika::units::si::InverseGrammageType lambda_inv_sum = + corsika::units::si::InverseGrammageType::zero()) { + + // TODO: add check for lambda_inv_select>lambda_inv_tot - if constexpr (t1ProcSeq || t1SwitchProc) { + if constexpr (t1ProcSeq) { // if A is a process sequence --> check inside const EProcessReturn ret = - A.SelectInteraction(vP, vS, lambda_select, lambda_inv_count); - // if A did succeed, stop routine + A_.SelectInteraction(view, lambda_inv_select, lambda_inv_sum); + // if A_ did succeed, stop routine. Not checking other static branch B_. if (ret != EProcessReturn::eOk) { return ret; } - } else if constexpr (std::is_base_of_v<InteractionProcess<T1type>, T1type>) { + } else if constexpr (std::is_base_of_v<InteractionProcess<TProcess1type>, + TProcess1type>) { // if this is not a ContinuousProcess --> evaluate probability - lambda_inv_count += A.GetInverseInteractionLength(vP); + const auto particle = view.parent(); + lambda_inv_sum += A_.GetInverseInteractionLength(particle); // check if we should execute THIS process and then EXIT - if (lambda_select < lambda_inv_count) { - A.DoInteraction(vS); + if (lambda_inv_select < lambda_inv_sum) { + A_.DoInteraction(view); return EProcessReturn::eInteracted; } - } // end branch A + } // end branch A_ - if constexpr (t2ProcSeq || t2SwitchProc) { - // if A is a process sequence --> check inside - const EProcessReturn ret = - B.SelectInteraction(vP, vS, lambda_select, lambda_inv_count); - // if A did succeed, stop routine - if (ret != EProcessReturn::eOk) { return ret; } - } else if constexpr (std::is_base_of_v<InteractionProcess<T2type>, T2type>) { + if constexpr (t2ProcSeq) { + // if B_ is a process sequence --> check inside + return B_.SelectInteraction(view, lambda_inv_select, lambda_inv_sum); + } else if constexpr (std::is_base_of_v<InteractionProcess<TProcess2type>, + TProcess2type>) { // if this is not a ContinuousProcess --> evaluate probability - lambda_inv_count += B.GetInverseInteractionLength(vP); + lambda_inv_sum += B_.GetInverseInteractionLength(view.parent()); // check if we should execute THIS process and then EXIT - if (lambda_select < lambda_inv_count) { - B.DoInteraction(vS); + if (lambda_inv_select < lambda_inv_sum) { + B_.DoInteraction(view); return EProcessReturn::eInteracted; } - } // end branch A + } // end branch B_ return EProcessReturn::eOk; } template <typename TParticle> - corsika::units::si::TimeType GetTotalLifetime(TParticle& p) { - return 1. / GetInverseLifetime(p); - } - - template <typename TParticle> - corsika::units::si::InverseTimeType GetTotalInverseLifetime(TParticle& p) { - return GetInverseLifetime(p); + inline corsika::units::si::TimeType GetLifetime(TParticle& particle) { + return 1. / GetInverseLifetime(particle); } template <typename TParticle> - corsika::units::si::InverseTimeType GetInverseLifetime(TParticle& p) { + inline corsika::units::si::InverseTimeType GetInverseLifetime(TParticle&& particle) { using namespace corsika::units::si; - corsika::units::si::InverseTimeType tot = 0 / second; + corsika::units::si::InverseTimeType tot = 0 / second; // default value - if constexpr (std::is_base_of_v<DecayProcess<T1type>, T1type> || t1ProcSeq) { - tot += A.GetInverseLifetime(p); + if constexpr (std::is_base_of_v<DecayProcess<TProcess1type>, TProcess1type> || + t1ProcSeq) { + tot += A_.GetInverseLifetime(particle); } - if constexpr (std::is_base_of_v<DecayProcess<T2type>, T2type> || t2ProcSeq) { - tot += B.GetInverseLifetime(p); + if constexpr (std::is_base_of_v<DecayProcess<TProcess2type>, TProcess2type> || + t2ProcSeq) { + tot += B_.GetInverseLifetime(particle); } return tot; } // select decay process - template <typename TParticle, typename TSecondaries> - EProcessReturn SelectDecay( - TParticle& vP, TSecondaries& vS, - [[maybe_unused]] corsika::units::si::InverseTimeType decay_select, - corsika::units::si::InverseTimeType& decay_inv_count) { + template <typename TSecondaryView> + inline EProcessReturn SelectDecay( + TSecondaryView& view, + [[maybe_unused]] corsika::units::si::InverseTimeType decay_inv_select, + [[maybe_unused]] corsika::units::si::InverseTimeType decay_inv_sum = + corsika::units::si::InverseTimeType::zero()) { + + // TODO: add check for decay_inv_select>decay_inv_tot + if constexpr (t1ProcSeq) { - // if A is a process sequence --> check inside - const EProcessReturn ret = A.SelectDecay(vP, vS, decay_select, decay_inv_count); - // if A did succeed, stop routine + // if A_ is a process sequence --> check inside + const EProcessReturn ret = A_.SelectDecay(view, decay_inv_select, decay_inv_sum); + // if A_ did succeed, stop routine here (not checking other static branch B_) if (ret != EProcessReturn::eOk) { return ret; } - } else if constexpr (std::is_base_of_v<DecayProcess<T1type>, T1type>) { + } else if constexpr (std::is_base_of_v<DecayProcess<TProcess1type>, + TProcess1type>) { // if this is not a ContinuousProcess --> evaluate probability - decay_inv_count += A.GetInverseLifetime(vP); + decay_inv_sum += A_.GetInverseLifetime(view.parent()); // check if we should execute THIS process and then EXIT - if (decay_select < decay_inv_count) { // more pedagogical: rndm_select < - // decay_inv_count / decay_inv_tot - A.DoDecay(vS); + if (decay_inv_select < decay_inv_sum) { // more pedagogical: rndm_select < + // decay_inv_sum / decay_inv_tot + A_.DoDecay(view); return EProcessReturn::eDecayed; } - } // end branch A + } // end branch A_ if constexpr (t2ProcSeq) { - // if A is a process sequence --> check inside - const EProcessReturn ret = B.SelectDecay(vP, vS, decay_select, decay_inv_count); - // if A did succeed, stop routine - if (ret != EProcessReturn::eOk) { return ret; } - } else if constexpr (std::is_base_of_v<DecayProcess<T2type>, T2type>) { + // if B_ is a process sequence --> check inside + return B_.SelectDecay(view, decay_inv_select, decay_inv_sum); + } else if constexpr (std::is_base_of_v<DecayProcess<TProcess2type>, + TProcess2type>) { // if this is not a ContinuousProcess --> evaluate probability - decay_inv_count += B.GetInverseLifetime(vP); + decay_inv_sum += B_.GetInverseLifetime(view.parent()); // check if we should execute THIS process and then EXIT - if (decay_select < decay_inv_count) { - B.DoDecay(vS); + if (decay_inv_select < decay_inv_sum) { + B_.DoDecay(view); return EProcessReturn::eDecayed; } - } // end branch B + } // end branch B_ return EProcessReturn::eOk; } }; - // the << operator assembles many BaseProcess, ContinuousProcess, and - // Interaction/DecayProcess objects into a ProcessSequence, all combinatorics - // must be allowed, this is why we define a macro to define all - // combinations here: - - // enable the << operator to construct ProcessSequence from two - // Processes, only if poth Processes derive from BaseProcesses + /** + * \function sequence + * + * to construct ProcessSequences in a flexible and dynamic way the + * `sequence` factory functions are provided + * + * Any objects of type + * - BaseProcess, + * - ContinuousProcess, and + * - Interaction/DecayProcess, + * - StackProcess, + * - SecondariesProcess + * can be assembled into a ProcessSequence, all + * combinatorics are allowed. + + * The sequence function checks that all its arguments are all of + * types derived from BaseProcess. Also the ProcessSequence itself + * is derived from type BaseProcess + **/ + + template <typename... TProcesses, typename TProcess1> + inline typename std::enable_if_t< + std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess1>>, + typename std::decay_t<TProcess1>>, + ProcessSequence<TProcess1, decltype(sequence(std::declval<TProcesses>()...))>> + sequence(TProcess1&& vA, TProcesses&&... vBs) { + return ProcessSequence<TProcess1, decltype(sequence(std::declval<TProcesses>()...))>( + vA, sequence(std::forward<TProcesses>(vBs)...)); + } template <typename TProcess1, typename TProcess2> - inline typename std::enable_if< - std::is_base_of<BaseProcess<typename std::decay<TProcess1>::type>, - typename std::decay<TProcess1>::type>::value && - std::is_base_of<BaseProcess<typename std::decay<TProcess2>::type>, - typename std::decay<TProcess2>::type>::value, - ProcessSequence<TProcess1, TProcess2>>::type - operator<<(TProcess1&& vA, TProcess2&& vB) { + inline typename std::enable_if_t< + std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess1>>, + typename std::decay_t<TProcess1>> && + std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess2>>, + typename std::decay_t<TProcess2>>, + ProcessSequence<TProcess1, TProcess2>> + sequence(TProcess1&& vA, TProcess2&& vB) { return ProcessSequence<TProcess1, TProcess2>(vA, vB); } - /// marker to identify objectas ProcessSequence + /** + * also allow a single Process in ProcessSequence, accompany by + * `NullModel` + **/ + template <typename TProcess> + inline typename std::enable_if_t< + std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess>>, + typename std::decay_t<TProcess>>, + ProcessSequence<TProcess, NullModel>> + sequence(TProcess&& vA) { + return ProcessSequence<TProcess, NullModel>(vA, NullModel()); + } + + /** + * traits marker to identify objectas ProcessSequence + **/ + template <typename TProcess1, typename TProcess2> + struct is_process_sequence<ProcessSequence<TProcess1, TProcess2>> : std::true_type { + // only switch on for BaseProcesses + template <typename std::enable_if_t< + std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess1>>, + typename std::decay_t<TProcess1>> && + std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess2>>, + typename std::decay_t<TProcess2>>, + int>> + is_process_sequence() {} + }; + + /** + * traits marker to identify objects containing any StackProcesses + **/ + namespace detail { + // need helper alias to achieve this: + template <typename TProcess1, typename TProcess2, + typename = typename std::enable_if_t< + contains_stack_process_v<TProcess1> || + std::is_base_of_v<StackProcess<typename std::decay_t<TProcess1>>, + typename std::decay_t<TProcess1>> || + contains_stack_process_v<TProcess2> || + std::is_base_of_v<StackProcess<typename std::decay_t<TProcess2>>, + typename std::decay_t<TProcess2>>, + int>> + using enable_if_stack = ProcessSequence<TProcess1, TProcess2>; + } // namespace detail + template <typename TProcess1, typename TProcess2> - struct is_process_sequence<corsika::process::ProcessSequence<TProcess1, TProcess2>> + struct contains_stack_process<detail::enable_if_stack<TProcess1, TProcess2>> : std::true_type {}; } // namespace corsika::process diff --git a/Framework/ProcessSequence/ProcessTraits.h b/Framework/ProcessSequence/ProcessTraits.h new file mode 100644 index 0000000000000000000000000000000000000000..e0cb00ebfde8827bbb098dc34d13df1c94a72eb2 --- /dev/null +++ b/Framework/ProcessSequence/ProcessTraits.h @@ -0,0 +1,41 @@ +/* + * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu + * + * This software is distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3). See file LICENSE for a full version of + * the license. + */ + +#pragma once + +namespace corsika::process { + + /** + * A traits marker to track which BaseProcess is also a ProcessSequence + **/ + template <typename TClass> + struct is_process_sequence : std::false_type {}; + + template <typename TClass> + bool constexpr is_process_sequence_v = is_process_sequence<TClass>::value; + + /** + * A traits marker to identiy a BaseProcess that is also SwitchProcessesSequence + **/ + + template <typename TClass> + struct is_switch_process_sequence : std::false_type {}; + + template <typename TClass> + bool constexpr is_switch_process_sequence_v = is_switch_process_sequence<TClass>::value; + + /** + * A traits marker to identify ProcessSequence that contain a StackProcess + **/ + template <typename TClass> + struct contains_stack_process : std::false_type {}; + + template <typename TClass> + bool constexpr contains_stack_process_v = contains_stack_process<TClass>::value; + +} // namespace corsika::process diff --git a/Framework/ProcessSequence/SecondariesProcess.h b/Framework/ProcessSequence/SecondariesProcess.h index 355a465c78bbdf4008b63f18e091a58321b4a949..a9bc3832a2e8a82949a6d03c3b9c1c5d44a49828 100644 --- a/Framework/ProcessSequence/SecondariesProcess.h +++ b/Framework/ProcessSequence/SecondariesProcess.h @@ -9,8 +9,6 @@ #pragma once #include <corsika/process/BaseProcess.h> -#include <corsika/process/ProcessReturn.h> // for convenience -#include <corsika/setup/SetupTrajectory.h> #include <corsika/units/PhysicalUnits.h> namespace corsika::process { @@ -30,7 +28,7 @@ namespace corsika::process { /// here starts the interface-definition part // -> enforce TDerived to implement DoSecondaries... template <typename TSecondaries> - inline EProcessReturn DoSecondaries(TSecondaries&); + inline void DoSecondaries(TSecondaries&); }; } // namespace corsika::process diff --git a/Framework/ProcessSequence/StackProcess.h b/Framework/ProcessSequence/StackProcess.h index 64a5dff97b6d2df4df5837b3bcc0e2b3052938e6..ce5c0998df246ed5ceb20bed618b40814a79077f 100644 --- a/Framework/ProcessSequence/StackProcess.h +++ b/Framework/ProcessSequence/StackProcess.h @@ -9,8 +9,6 @@ #pragma once #include <corsika/process/BaseProcess.h> -#include <corsika/process/ProcessReturn.h> // for convenience -#include <corsika/setup/SetupTrajectory.h> #include <corsika/units/PhysicalUnits.h> namespace corsika::process { @@ -36,7 +34,7 @@ namespace corsika::process { /// here starts the interface-definition part // -> enforce TDerived to implement DoStack... template <typename TStack> - inline EProcessReturn DoStack(TStack&); + inline void DoStack(TStack&); int GetStep() const { return fIStep; } bool CheckStep() { return !((++fIStep) % fNStep); } diff --git a/Framework/ProcessSequence/SwitchProcessSequence.h b/Framework/ProcessSequence/SwitchProcessSequence.h new file mode 100644 index 0000000000000000000000000000000000000000..f1b1dfcf5eee747f2007d207788ad2f686285766 --- /dev/null +++ b/Framework/ProcessSequence/SwitchProcessSequence.h @@ -0,0 +1,393 @@ +/* + * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu + * + * This software is distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3). See file LICENSE for a full version of + * the license. + */ + +#pragma once + +#include <corsika/process/BaseProcess.h> +#include <corsika/process/ProcessTraits.h> +#include <corsika/process/BoundaryCrossingProcess.h> +#include <corsika/process/ContinuousProcess.h> +#include <corsika/process/DecayProcess.h> +#include <corsika/process/InteractionProcess.h> +#include <corsika/process/ProcessReturn.h> +#include <corsika/process/SecondariesProcess.h> +#include <corsika/process/StackProcess.h> +#include <corsika/units/PhysicalUnits.h> + +#include <cmath> +#include <limits> +#include <type_traits> + +namespace corsika::process { + + // enum for the process switch selection: identify if First or + // Second process branch should be used. + enum class SwitchResult { First, Second }; + + /** + \class SwitchProcessSequence + + A compile time static list of processes that uses an internal + TSelect class to switch between different versions of processes + (or process sequence). + + TProcess1 and TProcess2 must be derived from BaseProcess and are + both references if possible (lvalue), otherwise (rvalue) they are + just classes. This allows us to handle both, rvalue as well as + lvalue Processes in the SwitchProcessSequence. + + TSelect has to implement a `operator()(const Particle&)` and has to + return either SwitchResult::First or SwitchResult::Second. Note: + TSelect may absolutely also use random numbers to sample between + its results. This can be used to achieve arbitrarily smooth + transition or mixtures of processes. + + Warning: do not put StackProcess into a SwitchProcessSequence + since this makes no sense. The StackProcess acts on an entire + particle stack and not on indiviidual particles. + + \comment See also class ProcessSequence + **/ + + template <typename TProcess1, typename TProcess2, typename TSelect> + class SwitchProcessSequence + : public BaseProcess<SwitchProcessSequence<TProcess1, TProcess2, TSelect>> { + + using TProcess1type = typename std::decay_t<TProcess1>; + using TProcess2type = typename std::decay_t<TProcess2>; + + static bool constexpr t1ProcSeq = is_process_sequence_v<TProcess1type>; + static bool constexpr t2ProcSeq = is_process_sequence_v<TProcess2type>; + + // make sure only BaseProcess types TProcess1/2 are passed + static_assert(std::is_base_of_v<BaseProcess<TProcess1type>, TProcess1type>, + "can only use process derived from BaseProcess in " + "SwitchProcessSequence, for Process 1"); + static_assert(std::is_base_of_v<BaseProcess<TProcess2type>, TProcess2type>, + "can only use process derived from BaseProcess in " + "SwitchProcessSequence, for Process 2"); + + // make sure TSelect is a function + static_assert(!std::is_function_v<TSelect>, "TSelect must be a function type"); + + // make sure none of TProcess1/2 is a StackProcess + static_assert(!std::is_base_of_v<StackProcess<TProcess1type>, TProcess1type>, + "cannot use StackProcess in SwitchProcessSequence, for Process 1"); + static_assert(!std::is_base_of_v<StackProcess<TProcess2type>, TProcess2type>, + "cannot use StackProcess in SwitchProcessSequence, for Process 2"); + + // if TProcess1/2 are already ProcessSequences, make sure they do not contain + // StackProcess + // if constexpr (t1ProcSeq) { + static_assert(!contains_stack_process_v<TProcess1type>, + "cannot use StackProcess in SwitchProcessSequence, remove from " + "ProcessSequence 1"); + //} + + // if constexpr (t2ProcSeq) + static_assert(!contains_stack_process_v<TProcess2type>, + "cannot use StackProcess in SwitchProcessSequence, remove from " + "ProcessSequence 2"); + + TSelect select_; // this is a reference, if possible + + TProcess1 A_; // this is a reference, if possible + TProcess2 B_; // this is a reference, if possible + + public: + SwitchProcessSequence(TProcess1 in_A, TProcess2 in_B, TSelect sel) + : select_(sel) + , A_(in_A) + , B_(in_B) {} + + template <typename TParticle, typename TVTNType> + EProcessReturn DoBoundaryCrossing(TParticle& particle, TVTNType const& from, + TVTNType const& to) { + switch (select_(particle)) { + case SwitchResult::First: { + if constexpr (std::is_base_of_v<BoundaryCrossingProcess<TProcess1type>, + TProcess1type> || + t1ProcSeq) { + return A_.DoBoundaryCrossing(particle, from, to); + } + break; + } + case SwitchResult::Second: { + if constexpr (std::is_base_of_v<BoundaryCrossingProcess<TProcess2type>, + TProcess2type> || + t2ProcSeq) { + return B_.DoBoundaryCrossing(particle, from, to); + } + break; + } + } + return EProcessReturn::eOk; + } + + template <typename TParticle, typename TTrack> + inline EProcessReturn DoContinuous(TParticle& particle, TTrack& vT) { + switch (select_(particle)) { + case SwitchResult::First: { + if constexpr (std::is_base_of_v<ContinuousProcess<TProcess1type>, + TProcess1type> || + t1ProcSeq) { + return A_.DoContinuous(particle, vT); + } + break; + } + case SwitchResult::Second: { + if constexpr (std::is_base_of_v<ContinuousProcess<TProcess2type>, + TProcess2type> || + t2ProcSeq) { + return B_.DoContinuous(particle, vT); + } + break; + } + } + return EProcessReturn::eOk; + } + + template <typename TSecondaries> + inline void DoSecondaries(TSecondaries& vS) { + const auto& particle = vS.parent(); + switch (select_(particle)) { + case SwitchResult::First: { + if constexpr (std::is_base_of_v<SecondariesProcess<TProcess1type>, + TProcess1type> || + t1ProcSeq) { + A_.DoSecondaries(vS); + } + break; + } + case SwitchResult::Second: { + if constexpr (std::is_base_of_v<SecondariesProcess<TProcess2type>, + TProcess2type> || + t2ProcSeq) { + B_.DoSecondaries(vS); + } + break; + } + } + } + + template <typename TParticle, typename TTrack> + inline corsika::units::si::LengthType MaxStepLength(TParticle& particle, + TTrack& vTrack) { + switch (select_(particle)) { + case SwitchResult::First: { + if constexpr (std::is_base_of_v<ContinuousProcess<TProcess1type>, + TProcess1type> || + t1ProcSeq) { + return A_.MaxStepLength(particle, vTrack); + } + break; + } + case SwitchResult::Second: { + if constexpr (std::is_base_of_v<ContinuousProcess<TProcess2type>, + TProcess2type> || + t2ProcSeq) { + return B_.MaxStepLength(particle, vTrack); + } + break; + } + } + + // if no other process in the sequence implements it + return std::numeric_limits<double>::infinity() * corsika::units::si::meter; + } + + template <typename TParticle> + inline corsika::units::si::GrammageType GetInteractionLength(TParticle&& particle) { + return 1. / GetInverseInteractionLength(particle); + } + + template <typename TParticle> + inline corsika::units::si::InverseGrammageType GetInverseInteractionLength( + TParticle&& particle) { + using namespace corsika::units::si; + + switch (select_(particle)) { + case SwitchResult::First: { + if constexpr (std::is_base_of_v<InteractionProcess<TProcess1type>, + TProcess1type> || + t1ProcSeq) { + return A_.GetInverseInteractionLength(particle); + } + break; + } + case SwitchResult::Second: { + if constexpr (std::is_base_of_v<InteractionProcess<TProcess2type>, + TProcess2type> || + t2ProcSeq) { + return B_.GetInverseInteractionLength(particle); + } + break; + } + } + return 0 * meter * meter / gram; // default value + } + + template <typename TSecondaryView> + inline EProcessReturn SelectInteraction( + TSecondaryView& view, + [[maybe_unused]] corsika::units::si::InverseGrammageType lambda_inv_select, + [[maybe_unused]] corsika::units::si::InverseGrammageType lambda_inv_sum = + corsika::units::si::InverseGrammageType::zero()) { + switch (select_(view.parent())) { + case SwitchResult::First: { + if constexpr (t1ProcSeq) { + // if A_ is a process sequence --> check inside + const EProcessReturn ret = + A_.SelectInteraction(view, lambda_inv_select, lambda_inv_sum); + // if A_ did succeed, stop routine. Not checking other static branch B_. + if (ret != EProcessReturn::eOk) { return ret; } + } else if constexpr (std::is_base_of_v<InteractionProcess<TProcess1type>, + TProcess1type>) { + // if this is not a ContinuousProcess --> evaluate probability + lambda_inv_sum += A_.GetInverseInteractionLength(view.parent()); + // check if we should execute THIS process and then EXIT + if (lambda_inv_select < lambda_inv_sum) { + A_.DoInteraction(view); + return EProcessReturn::eInteracted; + } + } // end branch A_ + break; + } + + case SwitchResult::Second: { + + if constexpr (t2ProcSeq) { + // if B_ is a process sequence --> check inside + return B_.SelectInteraction(view, lambda_inv_select, lambda_inv_sum); + } else if constexpr (std::is_base_of_v<InteractionProcess<TProcess2type>, + TProcess2type>) { + // if this is not a ContinuousProcess --> evaluate probability + lambda_inv_sum += B_.GetInverseInteractionLength(view.parent()); + // check if we should execute THIS process and then EXIT + if (lambda_inv_select < lambda_inv_sum) { + B_.DoInteraction(view); + return EProcessReturn::eInteracted; + } + } // end branch B_ + break; + } + } + return EProcessReturn::eOk; + } + + template <typename TParticle> + inline corsika::units::si::TimeType GetLifetime(TParticle&& particle) { + return 1. / GetInverseLifetime(particle); + } + + template <typename TParticle> + inline corsika::units::si::InverseTimeType GetInverseLifetime(TParticle&& particle) { + using namespace corsika::units::si; + + switch (select_(particle)) { + case SwitchResult::First: { + if constexpr (std::is_base_of_v<DecayProcess<TProcess1type>, TProcess1type> || + t1ProcSeq) { + return A_.GetInverseLifetime(particle); + } + break; + } + + case SwitchResult::Second: { + if constexpr (std::is_base_of_v<DecayProcess<TProcess2type>, TProcess2type> || + t2ProcSeq) { + return B_.GetInverseLifetime(particle); + } + break; + } + } + return 0 / second; // default value + } + + // select decay process + template <typename TSecondaryView> + inline EProcessReturn SelectDecay( + TSecondaryView& view, + [[maybe_unused]] corsika::units::si::InverseTimeType decay_inv_select, + [[maybe_unused]] corsika::units::si::InverseTimeType decay_inv_sum = + corsika::units::si::InverseTimeType::zero()) { + switch (select_(view.parent())) { + case SwitchResult::First: { + if constexpr (t1ProcSeq) { + // if A_ is a process sequence --> check inside + const EProcessReturn ret = + A_.SelectDecay(view, decay_inv_select, decay_inv_sum); + // if A_ did succeed, stop routine here (not checking other static branch B_) + if (ret != EProcessReturn::eOk) { return ret; } + } else if constexpr (std::is_base_of_v<DecayProcess<TProcess1type>, + TProcess1type>) { + // if this is not a ContinuousProcess --> evaluate probability + decay_inv_sum += A_.GetInverseLifetime(view.parent()); + // check if we should execute THIS process and then EXIT + if (decay_inv_select < decay_inv_sum) { + // more pedagogical: rndm_select < decay_inv_sum / decay_inv_tot + A_.DoDecay(view); + return EProcessReturn::eDecayed; + } + } // end branch A_ + break; + } + + case SwitchResult::Second: { + + if constexpr (t2ProcSeq) { + // if B_ is a process sequence --> check inside + return B_.SelectDecay(view, decay_inv_select, decay_inv_sum); + } else if constexpr (std::is_base_of_v<DecayProcess<TProcess2type>, + TProcess2type>) { + // if this is not a ContinuousProcess --> evaluate probability + decay_inv_sum += B_.GetInverseLifetime(view.parent()); + // check if we should execute THIS process and then EXIT + if (decay_inv_select < decay_inv_sum) { + B_.DoDecay(view); + return EProcessReturn::eDecayed; + } + } // end branch B_ + break; + } + } + return EProcessReturn::eOk; + } + }; + + // the method `select(proc1,proc1,selector)` assembles many + // BaseProcesses, and ProcessSequences into a SwitchProcessSequence, + // all combinatorics must be allowed, this is why we define a macro + // to define all combinations here: + + // Both, Processes1 and Processes2, must derive from BaseProcesses + + template <typename TProcess1, typename TProcess2, typename TSelect> + inline typename std::enable_if_t< + std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess1>>, + typename std::decay_t<TProcess1>> && + std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess2>>, + typename std::decay_t<TProcess2>>, + SwitchProcessSequence<TProcess1, TProcess2, TSelect>> + select(TProcess1&& vA, TProcess2&& vB, TSelect selector) { + return SwitchProcessSequence<TProcess1, TProcess2, TSelect>(vA, vB, selector); + } + + /// traits marker to identify objectas ProcessSequence + template <typename TProcess1, typename TProcess2, typename TSelect> + struct is_process_sequence< + corsika::process::SwitchProcessSequence<TProcess1, TProcess2, TSelect>> + : std::true_type {}; + + /// traits marker to identify objectas SwitchProcessSequence + template <typename TProcess1, typename TProcess2, typename TSelect> + struct is_switch_process_sequence< + corsika::process::SwitchProcessSequence<TProcess1, TProcess2, TSelect>> + : std::true_type {}; + +} // namespace corsika::process diff --git a/Framework/ProcessSequence/testNullModel.cc b/Framework/ProcessSequence/testNullModel.cc new file mode 100644 index 0000000000000000000000000000000000000000..33bfda3d01cda939f6205271cb2d00d3e6d8cb7e --- /dev/null +++ b/Framework/ProcessSequence/testNullModel.cc @@ -0,0 +1,29 @@ +/* + * (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 <catch2/catch.hpp> + +#include <corsika/process/NullModel.h> + +#include <corsika/geometry/Point.h> +#include <corsika/geometry/RootCoordinateSystem.h> +#include <corsika/geometry/Vector.h> + +#include <corsika/units/PhysicalUnits.h> + +#include <corsika/setup/SetupStack.h> +#include <corsika/setup/SetupTrajectory.h> + +using namespace corsika::units::si; +using namespace corsika::process; +using namespace corsika; + +TEST_CASE("NullModel", "[processes]") { + + SECTION("interface") { [[maybe_unused]] NullModel model; } +} diff --git a/Framework/ProcessSequence/testProcessSequence.cc b/Framework/ProcessSequence/testProcessSequence.cc index b51876886acbd22a80dd20aca4abe5d50c23e216..875cbc5821fe5e67da0ece3977f13446f2a0659a 100644 --- a/Framework/ProcessSequence/testProcessSequence.cc +++ b/Framework/ProcessSequence/testProcessSequence.cc @@ -11,9 +11,11 @@ #include <array> #include <iomanip> #include <iostream> +#include <typeinfo> #include <corsika/process/ProcessSequence.h> -#include <corsika/process/switch_process/SwitchProcess.h> +#include <corsika/process/SwitchProcessSequence.h> +#include <corsika/units/PhysicalUnits.h> using namespace corsika; using namespace corsika::units::si; @@ -22,7 +24,12 @@ using namespace std; static const int nData = 10; -int globalCount = 0; +int globalCount = 0; // simple counter + +int checkDecay = 0; // use this as a bit field +int checkInteract = 0; // use this as a bit field +int checkSec = 0; // use this as a bit field +int checkCont = 0; // use this as a bit field class ContinuousProcess1 : public ContinuousProcess<ContinuousProcess1> { int fV = 0; @@ -38,7 +45,8 @@ public: template <typename D, typename T> inline EProcessReturn DoContinuous(D& d, T&) const { cout << "ContinuousProcess1::DoContinuous" << endl; - for (int i = 0; i < nData; ++i) d.p[i] += 0.933; + checkCont |= 1; + for (int i = 0; i < nData; ++i) d.data_[i] += 0.933; return EProcessReturn::eOk; } }; @@ -56,7 +64,27 @@ public: template <typename D, typename T> inline EProcessReturn DoContinuous(D& d, T&) const { cout << "ContinuousProcess2::DoContinuous" << endl; - for (int i = 0; i < nData; ++i) d.p[i] += 0.933; + checkCont |= 2; + for (int i = 0; i < nData; ++i) d.data_[i] += 0.111; + return EProcessReturn::eOk; + } +}; + +class ContinuousProcess3 : public ContinuousProcess<ContinuousProcess3> { + int fV = 0; + +public: + ContinuousProcess3(const int v) + : fV(v) { + cout << "globalCount: " << globalCount << ", fV: " << fV << std::endl; + globalCount++; + } + + template <typename D, typename T> + inline EProcessReturn DoContinuous(D& d, T&) const { + cout << "ContinuousProcess3::DoContinuous" << endl; + checkCont |= 4; + for (int i = 0; i < nData; ++i) d.data_[i] += 0.333; return EProcessReturn::eOk; } }; @@ -69,12 +97,18 @@ public: globalCount++; } - template <typename D, typename S> - inline EProcessReturn DoInteraction(D& d, S&) const { - for (int i = 0; i < nData; ++i) d.p[i] += 1 + i; + template <typename TView> + inline EProcessReturn DoInteraction(TView& v) const { + checkInteract |= 1; + for (int i = 0; i < nData; ++i) v.parent().data_[i] += 1 + i; return EProcessReturn::eOk; } + template <typename TParticle> + corsika::units::si::GrammageType GetInteractionLength(TParticle&) const { + return 10_g / square(1_cm); + } + private: int fV; }; @@ -89,15 +123,17 @@ public: globalCount++; } - template <typename Particle> - inline EProcessReturn DoInteraction(Particle&) const { + template <typename TView> + inline EProcessReturn DoInteraction(TView& v) const { + checkInteract |= 2; + for (int i = 0; i < nData; ++i) v.parent().data_[i] /= 1.1; cout << "Process2::DoInteraction" << endl; return EProcessReturn::eOk; } template <typename Particle> GrammageType GetInteractionLength(Particle&) const { cout << "Process2::GetInteractionLength" << endl; - return 3_g / (1_cm * 1_cm); + return 20_g / (1_cm * 1_cm); } }; @@ -111,15 +147,17 @@ public: globalCount++; } - template <typename Particle> - inline EProcessReturn DoInteraction(Particle&) const { + template <typename TView> + inline EProcessReturn DoInteraction(TView& v) const { + checkInteract |= 4; + for (int i = 0; i < nData; ++i) v.parent().data_[i] *= 1.01; cout << "Process3::DoInteraction" << endl; return EProcessReturn::eOk; } template <typename Particle> GrammageType GetInteractionLength(Particle&) const { cout << "Process3::GetInteractionLength" << endl; - return 1_g / (1_cm * 1_cm); + return 30_g / (1_cm * 1_cm); } }; @@ -135,11 +173,14 @@ public: template <typename D, typename T> inline EProcessReturn DoContinuous(D& d, T&) const { - for (int i = 0; i < nData; ++i) { d.p[i] /= 1.2; } + std::cout << "Base::DoContinuous" << std::endl; + checkCont |= 8; + for (int i = 0; i < nData; ++i) { d.data_[i] /= 1.2; } return EProcessReturn::eOk; } - template <typename Particle> - EProcessReturn DoInteraction(Particle&) const { + template <typename TView> + EProcessReturn DoInteraction(TView&) const { + checkInteract |= 8; return EProcessReturn::eOk; } }; @@ -156,8 +197,28 @@ public: TimeType GetLifetime(Particle&) const { return 1_s; } + template <typename TView> + EProcessReturn DoDecay(TView&) const { + checkDecay |= 1; + return EProcessReturn::eOk; + } +}; + +class Decay2 : public DecayProcess<Decay2> { + +public: + Decay2(const int) { + cout << "Decay2()" << endl; + globalCount++; + } + template <typename Particle> - EProcessReturn DoDecay(Particle&) const { + TimeType GetLifetime(Particle&) const { + return 2_s; + } + template <typename TView> + EProcessReturn DoDecay(TView&) const { + checkDecay |= 2; return EProcessReturn::eOk; } }; @@ -178,10 +239,17 @@ public: struct DummyStack {}; struct DummyData { - double p[nData] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + double data_[nData] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; }; struct DummyTrajectory {}; +struct DummyView { + DummyView(DummyData& p) + : p_(p) {} + DummyData& p_; + DummyData& parent() { return p_; } +}; + TEST_CASE("Process Sequence", "[Process Sequence]") { SECTION("Check construction") { @@ -195,7 +263,17 @@ TEST_CASE("Process Sequence", "[Process Sequence]") { Process4 m4(3); CHECK(globalCount == 4); - [[maybe_unused]] auto sequence = m1 << m2 << m3 << m4; + auto sequence1 = process::sequence(m1, m2, m3, m4); + CHECK(is_process_sequence_v<decltype(sequence1)> == true); + CHECK(is_process_sequence_v<decltype(m2)> == false); + CHECK(is_switch_process_sequence_v<decltype(sequence1)> == false); + CHECK(is_switch_process_sequence_v<decltype(m2)> == false); + + auto sequence2 = process::sequence(m1, m2, m3); + CHECK(is_process_sequence_v<decltype(sequence2)> == true); + + auto sequence3 = process::sequence(m4); + CHECK(is_process_sequence_v<decltype(sequence3)> == true); } SECTION("interaction length") { @@ -206,11 +284,13 @@ TEST_CASE("Process Sequence", "[Process Sequence]") { DummyData particle; - auto sequence2 = cp1 << m2 << m3; - GrammageType const tot = sequence2.GetTotalInteractionLength(particle); - InverseGrammageType const tot_inv = - sequence2.GetTotalInverseInteractionLength(particle); + auto sequence2 = sequence(cp1, m2, m3); + GrammageType const tot = sequence2.GetInteractionLength(particle); + InverseGrammageType const tot_inv = sequence2.GetInverseInteractionLength(particle); cout << "lambda_tot=" << tot << "; lambda_tot_inv=" << tot_inv << endl; + + CHECK(tot / 1_g * square(1_cm) == 12); + CHECK(tot_inv * 1_g / square(1_cm) == 1. / 12); globalCount = 0; } @@ -223,22 +303,24 @@ TEST_CASE("Process Sequence", "[Process Sequence]") { DummyData particle; - auto sequence2 = cp1 << m2 << m3 << d3; - TimeType const tot = sequence2.GetTotalLifetime(particle); - InverseTimeType const tot_inv = sequence2.GetTotalInverseLifetime(particle); + auto sequence2 = sequence(cp1, m2, m3, d3); + TimeType const tot = sequence2.GetLifetime(particle); + InverseTimeType const tot_inv = sequence2.GetInverseLifetime(particle); cout << "lambda_tot=" << tot << "; lambda_tot_inv=" << tot_inv << endl; + CHECK(tot / 1_s == 1); + CHECK(tot_inv * 1_s == 1.); globalCount = 0; } SECTION("sectionTwo") { globalCount = 0; - ContinuousProcess1 cp1(0); - ContinuousProcess2 cp2(1); - Process2 m2(2); - Process3 m3(3); + ContinuousProcess1 cp1(0); // += 0.933 + ContinuousProcess2 cp2(1); // += 0.111 + Process2 m2(2); // /= 1.1 + Process3 m3(3); // *= 1.01 - auto sequence2 = cp1 << m2 << m3 << cp2; + auto sequence2 = sequence(cp1, m2, m3, cp2); DummyData particle; DummyTrajectory track; @@ -247,15 +329,18 @@ TEST_CASE("Process Sequence", "[Process Sequence]") { globalCount = 0; cout << "-->docont" << endl; - sequence2.DoContinuous(particle, track); - cout << "-->dodisc" << endl; - cout << "-->done" << endl; + // validation data + double test_data[nData] = {0}; const int nLoop = 5; cout << "Running loop with n=" << nLoop << endl; - for (int i = 0; i < nLoop; ++i) { sequence2.DoContinuous(particle, track); } + for (int iLoop = 0; iLoop < nLoop; ++iLoop) { + for (int i = 0; i < nData; ++i) { test_data[i] += 0.933 + 0.111; } + sequence2.DoContinuous(particle, track); + } for (int i = 0; i < nData; i++) { - cout << "data[" << i << "]=" << particle.p[i] << endl; + cout << "data_[" << i << "]=" << particle.data_[i] << endl; + CHECK(particle.data_[i] == Approx(test_data[i]).margin(1e-9)); } cout << "done" << endl; } @@ -266,7 +351,7 @@ TEST_CASE("Process Sequence", "[Process Sequence]") { Stack1 s1(1); Stack1 s2(2); - auto sequence = s1 << s2; + auto sequence = process::sequence(s1, s2); DummyStack stack; @@ -275,17 +360,120 @@ TEST_CASE("Process Sequence", "[Process Sequence]") { CHECK(s1.GetCount() == 20); CHECK(s2.GetCount() == 10); + + ContinuousProcess2 cp2(1); // += 0.111 + Process2 m2(2); // /= 1.1 + auto sequence2 = process::sequence(cp2, m2); + auto sequence3 = process::sequence(cp2, m2, s1); + + CHECK(is_process_sequence_v<decltype(sequence2)> == true); + CHECK(is_process_sequence_v<decltype(sequence3)> == true); + CHECK(contains_stack_process_v<decltype(sequence2)> == false); + CHECK(contains_stack_process_v<decltype(sequence3)> == true); } } -/* - Note: there is a fine-grained dedicated test-suite for SwitchProcess - in Processes/SwitchProcess/testSwtichProcess - */ -TEST_CASE("SwitchProcess") { - globalCount = 0; - Process1 p1(0); - Process2 p2(1); - switch_process::SwitchProcess s(p1, p2, 10_GeV); - CHECK(is_switch_process_v<decltype(s)>); +TEST_CASE("Switch Process Sequence", "[Process Sequence]") { + + SECTION("Check construction") { + + struct TestSelect { + corsika::process::SwitchResult operator()(const DummyData& p) const { + std::cout << "TestSelect data=" << p.data_[0] << std::endl; + if (p.data_[0] > 0) return corsika::process::SwitchResult::First; + return corsika::process::SwitchResult::Second; + } + }; + TestSelect select; + + auto sequence1 = process::sequence(Process1(0), ContinuousProcess2(0), Decay1(0)); + auto sequence2 = process::sequence(ContinuousProcess3(0), Process2(0), Decay2(0)); + + auto sequence = + process::sequence(ContinuousProcess1(0), Process3(0), + SwitchProcessSequence(sequence1, sequence2, select)); + + auto sequence_alt = process::sequence( + ContinuousProcess1(0), Process3(0), + process::select(process::sequence(Process1(0), ContinuousProcess2(0), Decay1(0)), + process::sequence(ContinuousProcess3(0), Process2(0), Decay2(0)), + select)); + + // check that same process sequence can be build in different ways + CHECK(typeid(sequence) == typeid(sequence_alt)); + CHECK(is_process_sequence_v<decltype(sequence)> == true); + CHECK(is_process_sequence_v<decltype( + SwitchProcessSequence(sequence1, sequence2, select))> == true); + + DummyData particle; + DummyTrajectory track; + DummyView view(particle); + + checkDecay = 0; + checkInteract = 0; + checkSec = 0; + checkCont = 0; + particle.data_[0] = 100; // data positive + sequence.DoContinuous(particle, track); + CHECK(checkInteract == 0); + CHECK(checkDecay == 0); + CHECK(checkCont == 0b011); + CHECK(checkSec == 0); + + checkDecay = 0; + checkInteract = 0; + checkSec = 0; + checkCont = 0; + particle.data_[0] = -100; // data negative + sequence_alt.DoContinuous(particle, track); + CHECK(checkInteract == 0); + CHECK(checkDecay == 0); + CHECK(checkCont == 0b101); + CHECK(checkSec == 0); + + // 1/(30g/cm2) is Process3 + corsika::units::si::InverseGrammageType lambda_select = .9 / 30. * square(1_cm) / 1_g; + corsika::units::si::InverseTimeType time_select = 0.1 / second; + + checkDecay = 0; + checkInteract = 0; + checkSec = 0; + checkCont = 0; + particle.data_[0] = 100; // data positive + sequence.SelectInteraction(view, lambda_select); + sequence.SelectDecay(view, time_select); + CHECK(checkInteract == 0b100); // this is Process3 + CHECK(checkDecay == 0b001); // this is Decay1 + CHECK(checkCont == 0); + CHECK(checkSec == 0); + lambda_select = 1.01 / 30. * square(1_cm) / 1_g; + checkInteract = 0; + sequence.SelectInteraction(view, lambda_select); + CHECK(checkInteract == 0b001); // this is Process1 + + checkDecay = 0; + checkInteract = 0; + checkSec = 0; + checkCont = 0; + particle.data_[0] = -100; // data negative + sequence.SelectInteraction(view, lambda_select); + sequence.SelectDecay(view, time_select); + CHECK(checkInteract == 0b010); // this is Process2 + CHECK(checkDecay == 0b010); // this is Decay2 + CHECK(checkCont == 0); + CHECK(checkSec == 0); + + checkDecay = 0; + checkInteract = 0; + checkSec = 0; + checkCont = 0; + particle.data_[0] = -100; // data negative + sequence.DoSecondaries(view); + Stack1 stack(0); + sequence.DoStack(stack); + CHECK(checkInteract == 0); + CHECK(checkDecay == 0); + CHECK(checkCont == 0); + CHECK(checkSec == 0); + } } diff --git a/Framework/ProcessSequence/testSwitchProcessSequence.cc b/Framework/ProcessSequence/testSwitchProcessSequence.cc new file mode 100644 index 0000000000000000000000000000000000000000..a778f2efb5dd587b3fc2341dbb7cb5e205c671ab --- /dev/null +++ b/Framework/ProcessSequence/testSwitchProcessSequence.cc @@ -0,0 +1,247 @@ +/* + * (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/process/switch_process/SwitchProcess.h> +#include <corsika/stack/SecondaryView.h> +#include <corsika/stack/Stack.h> +#include <corsika/units/PhysicalUnits.h> + +#include <catch2/catch.hpp> + +#include <algorithm> +#include <random> + +using namespace corsika; +using namespace corsika::process; +using namespace corsika::units::si; + +class TestStackData { + +public: + // these functions are needed for the Stack interface + void Clear() { fData.clear(); } + unsigned int GetSize() const { return fData.size(); } + unsigned int GetCapacity() const { return fData.size(); } + void Copy(int i1, int i2) { fData[i2] = fData[i1]; } + void Swap(int i1, int i2) { std::swap(fData[i1], fData[i2]); } + + // custom data access function + void SetData(unsigned int i, HEPEnergyType v) { fData[i] = v; } + HEPEnergyType GetData(const unsigned int i) const { return fData[i]; } + + // these functions are also needed by the Stack interface + void IncrementSize() { fData.resize(fData.size() + 1); } + void DecrementSize() { + if (fData.size() > 0) { fData.pop_back(); } + } + + // custom private data section +private: + std::vector<HEPEnergyType> fData; +}; + +/** + * From static_cast of a StackIterator over entries in the + * TestStackData class you get and object of type + * TestParticleInterface defined here + * + * It provides Get/Set methods to read and write data to the "Data" + * storage of TestStackData obtained via + * "StackIteratorInterface::GetStackData()", given the index of the + * iterator "StackIteratorInterface::GetIndex()" + * + */ +template <typename StackIteratorInterface> +class TestParticleInterface + : public corsika::stack::ParticleBase<StackIteratorInterface> { + +public: + using corsika::stack::ParticleBase<StackIteratorInterface>::GetStackData; + using corsika::stack::ParticleBase<StackIteratorInterface>::GetIndex; + + /* + The SetParticleData methods are called for creating new entries + on the stack. You can specifiy various parametric versions to + perform this task: + */ + + // default version for particle-creation from input data + void SetParticleData(const std::tuple<HEPEnergyType> v) { SetEnergy(std::get<0>(v)); } + void SetParticleData(TestParticleInterface<StackIteratorInterface>& /*parent*/, + std::tuple<HEPEnergyType> v) { + SetEnergy(std::get<0>(v)); + } + + // here are the fundamental methods for access to TestStackData data + void SetEnergy(HEPEnergyType v) { GetStackData().SetData(GetIndex(), v); } + HEPEnergyType GetEnergy() const { return GetStackData().GetData(GetIndex()); } +}; + +using SimpleStack = corsika::stack::Stack<TestStackData, TestParticleInterface>; + +// see issue 161 +#if defined(__clang__) +using StackTestView = corsika::stack::SecondaryView<TestStackData, TestParticleInterface>; +#elif defined(__GNUC__) || defined(__GNUG__) +using StackTestView = corsika::stack::MakeView<SimpleStack>::type; +#endif + +auto constexpr kgMSq = 1_kg / (1_m * 1_m); + +template <int N> +struct DummyProcess : InteractionProcess<DummyProcess<N>> { + + template <typename TParticle> + corsika::units::si::GrammageType GetInteractionLength(TParticle const&) const { + return N * kgMSq; + } + + template <typename TSecondaries> + corsika::process::EProcessReturn DoInteraction(TSecondaries& vSec) { + // to figure out which process was selected in the end, we produce N + // secondaries for DummyProcess<N> + + for (int i = 0; i < N; ++i) { + vSec.AddSecondary(std::tuple<HEPEnergyType>{vSec.GetEnergy() / N}); + } + + return EProcessReturn::eOk; + } +}; + +using DummyLowEnergyProcess = DummyProcess<1>; +using DummyHighEnergyProcess = DummyProcess<2>; +using DummyAdditionalProcess = DummyProcess<3>; + +TEST_CASE("SwitchProcess from InteractionProcess") { + DummyLowEnergyProcess low; + DummyHighEnergyProcess high; + DummyAdditionalProcess proc; + + switch_process::SwitchProcess switchProcess(low, high, 1_TeV); + auto seq = switchProcess << proc; + + SimpleStack stack; + + SECTION("low energy") { + stack.AddParticle(std::tuple<HEPEnergyType>{0.5_TeV}); + auto p = stack.GetNextParticle(); + + // low energy process returns 1 kg/m² + SECTION("interaction length") { + CHECK(switchProcess.GetInteractionLength(p) / kgMSq == Approx(1)); + CHECK(seq.GetInteractionLength(p) / kgMSq == Approx(3. / 4)); + } + } + + SECTION("high energy") { + stack.AddParticle(std::tuple<HEPEnergyType>{4_TeV}); + auto p = stack.GetNextParticle(); + + // high energy process returns 2 kg/m² + SECTION("interaction length") { + CHECK(switchProcess.GetInteractionLength(p) / kgMSq == Approx(2)); + CHECK(seq.GetInteractionLength(p) / kgMSq == Approx(6. / 5)); + } + + // high energy process creates 2 secondaries + SECTION("SelectInteraction") { + typename SimpleStack::ParticleType theParticle = + stack.GetNextParticle(); // as in corsika::Cascade + StackTestView view(theParticle); + auto projectile = view.GetProjectile(); + + InverseGrammageType invLambda = 0 / kgMSq; + switchProcess.SelectInteraction(p, projectile, 0.01 / kgMSq, invLambda); + + CHECK(view.getSize() == 2); + } + } +} + +TEST_CASE("SwitchProcess from ProcessSequence") { + DummyProcess<1> innerA; + DummyProcess<2> innerB; + DummyProcess<3> outer; + DummyProcess<4> additional; + + auto seq = innerA << innerB; + + switch_process::SwitchProcess switchProcess(seq, outer, 1_TeV); + auto completeSeq = switchProcess << additional; + + SimpleStack stack; + + SECTION("low energy") { + stack.AddParticle(std::tuple<HEPEnergyType>{0.5_TeV}); + auto p = stack.GetNextParticle(); + + SECTION("interaction length") { + CHECK(switchProcess.GetInteractionLength(p) / kgMSq == Approx(2. / 3)); + CHECK(completeSeq.GetInteractionLength(p) / kgMSq == Approx(4. / 7)); + } + + SECTION("SelectInteraction") { + std::vector<int> numberOfSecondaries; + + for (int i = 0; i < 1000; ++i) { + typename SimpleStack::ParticleType theParticle = + stack.GetNextParticle(); // as in corsika::Cascade + StackTestView view(theParticle); + auto projectile = view.GetProjectile(); + + double r = i / 1000.; + InverseGrammageType invLambda = r * 7. / 4 / kgMSq; + + InverseGrammageType accumulator = 0 / kgMSq; + completeSeq.SelectInteraction(p, projectile, invLambda, accumulator); + + numberOfSecondaries.push_back(view.getSize()); + } + + auto const mean = + std::accumulate(numberOfSecondaries.cbegin(), numberOfSecondaries.cend(), 0.) / + numberOfSecondaries.size(); + CHECK(mean == Approx(12. / 7.).margin(0.01)); + } + } + + SECTION("high energy") { + stack.AddParticle(std::tuple<HEPEnergyType>{3.0_TeV}); + auto p = stack.GetNextParticle(); + + SECTION("interaction length") { + CHECK(switchProcess.GetInteractionLength(p) / kgMSq == Approx(3)); + CHECK(completeSeq.GetInteractionLength(p) / kgMSq == Approx(12. / 7.)); + } + + SECTION("SelectInteraction") { + std::vector<int> numberOfSecondaries; + + for (int i = 0; i < 1000; ++i) { + typename SimpleStack::ParticleType theParticle = + stack.GetNextParticle(); // as in corsika::Cascade + StackTestView view(theParticle); + auto projectile = view.GetProjectile(); + + double r = i / 1000.; + InverseGrammageType invLambda = r * 7. / 12. / kgMSq; + + InverseGrammageType accumulator = 0 / kgMSq; + completeSeq.SelectInteraction(p, projectile, invLambda, accumulator); + + numberOfSecondaries.push_back(view.getSize()); + } + + auto const mean = + std::accumulate(numberOfSecondaries.cbegin(), numberOfSecondaries.cend(), 0.) / + numberOfSecondaries.size(); + CHECK(mean == Approx(24. / 7.).margin(0.01)); + } + } +} diff --git a/Processes/SwitchProcess/testSwitchProcess.cc b/Framework/ProcessSequence/testSwitchProcessSequence.h similarity index 94% rename from Processes/SwitchProcess/testSwitchProcess.cc rename to Framework/ProcessSequence/testSwitchProcessSequence.h index 9ee148e1855edc2b45c81594425e8786e2434d09..709dc8510684c9e7c4dc8ebbb91fa20611ac17ad 100644 --- a/Processes/SwitchProcess/testSwitchProcess.cc +++ b/Framework/ProcessSequence/testSwitchProcessSequence.h @@ -137,19 +137,6 @@ TEST_CASE("SwitchProcess from InteractionProcess") { REQUIRE(switchProcess.GetInteractionLength(p) / kgMSq == Approx(1)); REQUIRE(seq.GetTotalInteractionLength(p) / kgMSq == Approx(3. / 4)); } - - // low energy process creates 1 secondary - //~ SECTION("SelectInteraction") { - //~ typename SimpleStack::ParticleType theParticle = - //~ stack.GetNextParticle(); // as in corsika::Cascade - //~ StackTestView view(theParticle); - //~ auto projectile = view.GetProjectile(); - - //~ InverseGrammageType invLambda = 0 / kgMSq; - //~ switchProcess.SelectInteraction(p, projectile, 0.01 / kgMSq, invLambda); - - //~ REQUIRE(view.GetSize() == 1); - //~ } } SECTION("high energy") { diff --git a/Framework/Random/CMakeLists.txt b/Framework/Random/CMakeLists.txt index f9c72763ca232ed24db5ff5dea1a407eb24b6a7c..f909f77f1f32c88f77a52482839af3cf43e2949a 100644 --- a/Framework/Random/CMakeLists.txt +++ b/Framework/Random/CMakeLists.txt @@ -20,9 +20,8 @@ CORSIKA_COPY_HEADERS_TO_NAMESPACE (CORSIKArandom ${CORSIKArandom_NAMESPACE} ${CO target_link_libraries ( CORSIKArandom - INTERFACE CORSIKAutilities - CORSIKAunits + CORSIKAlogging ) target_include_directories ( @@ -50,4 +49,5 @@ target_link_libraries ( testRandom CORSIKArandom CORSIKAtesting + CORSIKAunits ) diff --git a/Framework/Random/RNGManager.cc b/Framework/Random/RNGManager.cc index 238b38636e4ef5ec6ab9a3e219ba044d7a503845..8bbcf15dd391a744d69e017f7570e5163a0308a2 100644 --- a/Framework/Random/RNGManager.cc +++ b/Framework/Random/RNGManager.cc @@ -7,6 +7,8 @@ */ #include <corsika/random/RNGManager.h> +#include <corsika/logging/Logging.h> + #include <sstream> void corsika::random::RNGManager::RegisterRandomStream(std::string const& pStreamName) { @@ -42,14 +44,21 @@ std::stringstream corsika::random::RNGManager::dumpState() const { } void corsika::random::RNGManager::SeedAll(uint64_t vSeed) { - for (auto& entry : rngs) { entry.second.seed(vSeed++); } + for (auto& entry : rngs) { + auto seed = vSeed++; + C8LOG_TRACE("Random seed stream {} seed {}", entry.first, seed); + entry.second.seed(seed); + } } void corsika::random::RNGManager::SeedAll() { std::random_device rd; - + std::seed_seq sseq{rd(), rd(), rd(), rd(), rd(), rd()}; for (auto& entry : rngs) { - std::seed_seq sseq{rd(), rd(), rd(), rd(), rd(), rd()}; - entry.second.seed(sseq); + std::vector<std::uint32_t> seeds(1); + sseq.generate(seeds.begin(), seeds.end()); + std::uint32_t seed = seeds[0]; + C8LOG_TRACE("Random seed stream {} seed {}", entry.first, seed); + entry.second.seed(seed); } } diff --git a/Framework/Random/UniformRealDistribution.h b/Framework/Random/UniformRealDistribution.h index 7e092076da1ea7d179df5313a9d767f9e38faf9f..0c63e85428a1e2556a81995b386ba46493546866 100644 --- a/Framework/Random/UniformRealDistribution.h +++ b/Framework/Random/UniformRealDistribution.h @@ -8,7 +8,6 @@ #pragma once -#include <corsika/units/PhysicalUnits.h> #include <random> namespace corsika::random { diff --git a/Framework/StackInterface/SecondaryView.h b/Framework/StackInterface/SecondaryView.h index dcdcab8127e6217bfc4f75d68787ae92b80a9178..709a8c4feb658659f9369f938490b7101e91b1da 100644 --- a/Framework/StackInterface/SecondaryView.h +++ b/Framework/StackInterface/SecondaryView.h @@ -168,8 +168,9 @@ namespace corsika::stack { * SecondaryView is derived from. This projectile should not be * used to modify the Stack! */ - ConstStackIteratorValue parent() const { - return ConstStackIteratorValue(inner_stack_, projectile_index_); + StackIteratorValue parent() + const { // todo: check if this can't be ConstStackIteratorValue + return StackIteratorValue(inner_stack_, projectile_index_); } /** diff --git a/Framework/StackInterface/Stack.h b/Framework/StackInterface/Stack.h index e166fccba8a8acdb957222b08b42bdcf63a87193..85ec6418fe0898573b3db16d9d52e867404d3b76 100644 --- a/Framework/StackInterface/Stack.h +++ b/Framework/StackInterface/Stack.h @@ -301,9 +301,11 @@ namespace corsika::stack { /** * check if this particle was already deleted */ - bool isDeleted(const StackIterator& p) { return isDeleted(p.GetIndex()); } + bool isDeleted(const StackIterator& p) const { return isDeleted(p.GetIndex()); } bool isDeleted(const ConstStackIterator& p) const { return isDeleted(p.GetIndex()); } - bool isDeleted(const ParticleInterfaceType& p) { return isDeleted(p.GetIterator()); } + bool isDeleted(const ParticleInterfaceType& p) const { + return isDeleted(p.GetIterator()); + } /** * Function to ultimatively remove the last entry from the stack, diff --git a/Framework/StackInterface/StackIteratorInterface.h b/Framework/StackInterface/StackIteratorInterface.h index 2229c17bc395a2f12b83aae0ae5c89162c95fdd3..6c4901084843c568016450205435884d3e6bb972 100644 --- a/Framework/StackInterface/StackIteratorInterface.h +++ b/Framework/StackInterface/StackIteratorInterface.h @@ -64,7 +64,7 @@ namespace corsika::stack { For two examples see stack_example.cc, or the corsika::processes::sibyll::SibStack class - */ + **/ template <typename TStackData, template <typename> typename TParticleInterface, typename StackType = Stack<TStackData, TParticleInterface>> @@ -105,6 +105,10 @@ namespace corsika::stack { StackIteratorInterface() = delete; public: + StackIteratorInterface(StackIteratorInterface&& rhs) + : index_(std::move(rhs.index_)) + , data_(std::move(rhs.data_)) {} + StackIteratorInterface(StackIteratorInterface const& vR) : index_(vR.index_) , data_(vR.data_) {} @@ -118,7 +122,7 @@ namespace corsika::stack { /** iterator must always point to data, with an index: @param data reference to the stack [rw] @param index index on stack - */ + **/ StackIteratorInterface(StackType& data, const unsigned int index) : index_(index) , data_(&data) {} @@ -129,7 +133,7 @@ namespace corsika::stack { @param args variadic list of data to initialize stack entry, this must be consistent with the definition of the user-provided ParticleInterfaceType::SetParticleData(...) function - */ + **/ template <typename... Args> StackIteratorInterface(StackType& data, const unsigned int index, const Args... args) : index_(index) @@ -146,7 +150,7 @@ namespace corsika::stack { @param args variadic list of data to initialize stack entry, this must be consistent with the definition of the user-provided ParticleInterfaceType::SetParticleData(...) function - */ + **/ template <typename... Args> StackIteratorInterface(StackType& data, const unsigned int index, StackIteratorInterface& parent, const Args... args) @@ -160,7 +164,7 @@ namespace corsika::stack { public: /** @name Iterator interface @{ - */ + **/ StackIteratorInterface& operator++() { do { ++index_; @@ -195,14 +199,15 @@ namespace corsika::stack { /** * Convert iterator to value type, where value type is the user-provided particle * readout class - */ + **/ ParticleInterfaceType& operator*() { return static_cast<ParticleInterfaceType&>(*this); } + /** * Convert iterator to const value type, where value type is the user-provided * particle readout class - */ + **/ const ParticleInterfaceType& operator*() const { return static_cast<const ParticleInterfaceType&>(*this); } @@ -212,7 +217,7 @@ namespace corsika::stack { /** * @name Stack data access * @{ - */ + **/ /// Get current particle index inline unsigned int GetIndex() const { return index_; } /// Get current particle Stack object @@ -234,7 +239,7 @@ namespace corsika::stack { @class ConstStackIteratorInterface This is the iterator class for const-access to stack data - */ + **/ template <typename TStackData, template <typename> typename TParticleInterface, typename StackType = Stack<TStackData, TParticleInterface>> @@ -275,6 +280,10 @@ namespace corsika::stack { ConstStackIteratorInterface() = delete; public: + ConstStackIteratorInterface(ConstStackIteratorInterface&& rhs) + : index_(std::move(rhs.index_)) + , data_(std::move(rhs.data_)) {} + ConstStackIteratorInterface(const StackType& data, const unsigned int index) : index_(index) , data_(&data) {} @@ -290,13 +299,13 @@ namespace corsika::stack { \endverbatim See documentation of StackIteratorInterface for more details. - */ + **/ bool isDeleted() const { return GetStack().isDeleted(*this); } public: /** @name Iterator interface - */ + **/ ///@{ ConstStackIteratorInterface& operator++() { do { @@ -339,7 +348,7 @@ namespace corsika::stack { protected: /** @name Stack data access Only the const versions for read-only access - */ + **/ ///@{ inline unsigned int GetIndex() const { return index_; } inline const StackType& GetStack() const { return *data_; } diff --git a/Framework/Utilities/CMakeLists.txt b/Framework/Utilities/CMakeLists.txt index 5618ab4a8cf35be1e36630eac8d3f8d0ab627e95..95170d4a35b01b6f44eaf6aff11f47ebf0881e00 100644 --- a/Framework/Utilities/CMakeLists.txt +++ b/Framework/Utilities/CMakeLists.txt @@ -37,6 +37,7 @@ set ( UTILITIES_DEPENDS CORSIKAgeometry CORSIKAunits + CORSIKAlogging C8::ext::boost # so far only for MetaProgramming C8::ext::eigen3 # for COMboost ) diff --git a/Framework/Utilities/COMBoost.cc b/Framework/Utilities/COMBoost.cc index c6688199ab5d543cfd1670b93e7416cbd8a961f7..5bb4be9da2a2784dc70efa0a7b6b5b1233d3b3f4 100644 --- a/Framework/Utilities/COMBoost.cc +++ b/Framework/Utilities/COMBoost.cc @@ -12,6 +12,7 @@ #include <corsika/units/PhysicalUnits.h> #include <corsika/utl/COMBoost.h> #include <corsika/utl/sgn.h> +#include <corsika/logging/Logging.h> #include <cmath> @@ -38,9 +39,8 @@ COMBoost::COMBoost(FourVector<HEPEnergyType, Vector<hepmomentum_d>> const& Pproj setBoost(coshEta, sinhEta); - std::cout << "COMBoost (1-beta)=" << 1 - sinhEta / coshEta << " gamma=" << coshEta - << std::endl; - std::cout << " det = " << boost_.determinant() - 1 << std::endl; + C8LOG_TRACE("COMBoost (1-beta)={}, gamma={}, det={}", 1 - sinhEta / coshEta, coshEta, + boost_.determinant() - 1); } COMBoost::COMBoost(geometry::Vector<units::si::hepmomentum_d> const& momentum, diff --git a/Framework/Utilities/COMBoost.h b/Framework/Utilities/COMBoost.h index 0c78d49acb6ef06dd41c1e64c7f5048172c1e34a..73b7c93001321dff22902477dc701aee043e9040 100644 --- a/Framework/Utilities/COMBoost.h +++ b/Framework/Utilities/COMBoost.h @@ -11,6 +11,7 @@ #include <corsika/geometry/CoordinateSystem.h> #include <corsika/geometry/FourVector.h> #include <corsika/units/PhysicalUnits.h> +#include <corsika/logging/Logging.h> #include <Eigen/Dense> @@ -69,10 +70,10 @@ namespace corsika::utl { Eigen::Vector2d com; com << (Ecm * (1 / 1_GeV)), (pCM.eVector(2) * (1 / 1_GeV).magnitude()); - std::cout << "COMBoost::fromCoM Ecm=" << Ecm / 1_GeV << " GeV, " - << " pcm = " << pCM / 1_GeV << " (norm = " << pCM.norm() / 1_GeV - << " GeV), invariant mass = " << p.GetNorm() / 1_GeV << " GeV" - << std::endl; + C8LOG_TRACE( + "COMBoost::fromCoM Ecm={} GeV" + " pcm={} GeV (norm = {} GeV), invariant mass={} GeV", + Ecm / 1_GeV, pCM / 1_GeV, pCM.norm() / 1_GeV, p.GetNorm() / 1_GeV); auto const boostedZ = inverseBoost_ * com; auto const E_lab = boostedZ(0) * 1_GeV; @@ -84,10 +85,11 @@ namespace corsika::utl { FourVector f(E_lab, pLab); - std::cout << "COMBoost::fromCoM --> Elab=" << E_lab / 1_GeV << "GeV, " - << " plab = " << pLab.GetComponents() << " (norm =" << pLab.norm() / 1_GeV - << " GeV), invariant mass = " << f.GetNorm() / 1_GeV << " GeV" - << std::endl; + C8LOG_TRACE("COMBoost::fromCoM --> Elab={} GeV", + " plab={} GeV (norm={} GeV) " + " GeV), invariant mass = {}", + E_lab / 1_GeV, f.GetNorm() / 1_GeV, pLab.GetComponents(), + pLab.norm() / 1_GeV); return f; } diff --git a/Processes/AnalyticProcessors/testExecTime.cc b/Processes/AnalyticProcessors/testExecTime.cc index dbda248c889279e58a0feb4be6650e02eb02bb7a..e2fc710e7a201096184edac399befe01a8d04356 100644 --- a/Processes/AnalyticProcessors/testExecTime.cc +++ b/Processes/AnalyticProcessors/testExecTime.cc @@ -33,86 +33,86 @@ TEST_CASE("Timing process", "[proccesses][analytic_processors ExecTime]") { SECTION("BoundaryCrossing") { ExecTime<DummyBoundaryCrossingProcess<10>> execTime; auto start = std::chrono::steady_clock::now(); - REQUIRE(execTime.DoBoundaryCrossing(tmp, 0, 0) == EProcessReturn::eOk); + CHECK(execTime.DoBoundaryCrossing(tmp, 0, 0) == EProcessReturn::eOk); auto end = std::chrono::steady_clock::now(); - REQUIRE(std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() == - Approx(10).margin(5)); + CHECK(std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() == + Approx(10).margin(5)); for (int i = 0; i < 100; i++) execTime.DoBoundaryCrossing(tmp, 0, 0); - REQUIRE(execTime.mean() == Approx(10 * 1000).margin(2 * 1000)); + CHECK(execTime.mean() == Approx(10 * 1000).margin(2 * 1000)); - REQUIRE(execTime.sumTime() == Approx(10 * 100 * 1000).margin((10 * 100) * 1000)); + CHECK(execTime.sumTime() == Approx(10 * 100 * 1000).margin((10 * 100) * 1000)); - REQUIRE(fabs(execTime.var()) < 20000); + CHECK(fabs(execTime.var()) < 100000); } SECTION("Continuous") { ExecTime<DummyContinuousProcess<50>> execTime; auto start = std::chrono::steady_clock::now(); - REQUIRE(execTime.DoContinuous(tmp, tmp) == EProcessReturn::eOk); + CHECK(execTime.DoContinuous(tmp, tmp) == EProcessReturn::eOk); auto end = std::chrono::steady_clock::now(); - REQUIRE(std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() == - Approx(50).margin(5)); + CHECK(std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() == + Approx(50).margin(5)); for (int i = 0; i < 100; i++) execTime.DoContinuous(tmp, tmp); - REQUIRE(execTime.mean() == Approx(50 * 1000).margin(2 * 1000)); + CHECK(execTime.mean() == Approx(50 * 1000).margin(2 * 1000)); - REQUIRE(execTime.sumTime() == Approx(50 * 100 * 1000).margin((10 * 100) * 1000)); + CHECK(execTime.sumTime() == Approx(50 * 100 * 1000).margin((10 * 100) * 1000)); - REQUIRE(fabs(execTime.var()) < 20000); + CHECK(fabs(execTime.var()) < 100000); } SECTION("Decay") { ExecTime<DummyDecayProcess<10>> execTime; auto start = std::chrono::steady_clock::now(); - REQUIRE(execTime.DoDecay(tmp) == EProcessReturn::eOk); + CHECK(execTime.DoDecay(tmp) == EProcessReturn::eOk); auto end = std::chrono::steady_clock::now(); - REQUIRE(std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() == - Approx(10).margin(5)); + CHECK(std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() == + Approx(10).margin(5)); for (int i = 0; i < 100; i++) execTime.DoDecay(tmp); - REQUIRE(execTime.mean() == Approx(10 * 1000).margin(2 * 1000)); + CHECK(execTime.mean() == Approx(10 * 1000).margin(2 * 1000)); - REQUIRE(execTime.sumTime() == Approx(10 * 100 * 100).margin((10 * 100) * 1000)); + CHECK(execTime.sumTime() == Approx(10 * 100 * 100).margin((10 * 100) * 1000)); - REQUIRE(fabs(execTime.var()) < 20000); + CHECK(fabs(execTime.var()) < 100000); } SECTION("Interaction") { ExecTime<DummyInteractionProcess<10>> execTime; auto start = std::chrono::steady_clock::now(); - REQUIRE(execTime.DoInteraction(tmp) == EProcessReturn::eOk); + CHECK(execTime.DoInteraction(tmp) == EProcessReturn::eOk); auto end = std::chrono::steady_clock::now(); - REQUIRE(std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() == - Approx(10).margin(5)); + CHECK(std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() == + Approx(10).margin(5)); for (int i = 0; i < 100; i++) execTime.DoInteraction(tmp); - REQUIRE(execTime.mean() == Approx(10 * 1000).margin(2 * 1000)); + CHECK(execTime.mean() == Approx(10 * 1000).margin(2 * 1000)); - REQUIRE(execTime.sumTime() == Approx(10 * 100 * 1000).margin((10 * 100) * 1000)); + CHECK(execTime.sumTime() == Approx(10 * 100 * 1000).margin((10 * 100) * 1000)); - REQUIRE(fabs(execTime.var()) < 20000); + CHECK(fabs(execTime.var()) < 100000); } SECTION("Secondaries") { ExecTime<DummySecondariesProcess<10>> execTime; auto start = std::chrono::steady_clock::now(); - REQUIRE(execTime.DoSecondaries(tmp) == EProcessReturn::eOk); + CHECK(execTime.DoSecondaries(tmp) == EProcessReturn::eOk); auto end = std::chrono::steady_clock::now(); - REQUIRE(std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() == - Approx(10).margin(5)); + CHECK(std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() == + Approx(10).margin(5)); for (int i = 0; i < 100; i++) execTime.DoSecondaries(tmp); - REQUIRE(execTime.mean() == Approx(10 * 1000).margin(2 * 1000)); + CHECK(execTime.mean() == Approx(10 * 1000).margin(2 * 1000)); - REQUIRE(execTime.sumTime() == Approx(10 * 100 * 1000).margin((10 * 100) * 1000)); + CHECK(execTime.sumTime() == Approx(10 * 100 * 1000).margin((10 * 100) * 1000)); - REQUIRE(fabs(execTime.var()) < 20000); + CHECK(fabs(execTime.var()) < 100000); } SECTION("TestMeanAlgo") { @@ -128,7 +128,7 @@ TEST_CASE("Timing process", "[proccesses][analytic_processors ExecTime]") { std::vector<double> elems; - for (int i = 0; i < 1000000; i++) { + for (int i = 0; i < 1000; i++) { double timeDiv = distribution(generator); elems.push_back(timeDiv); @@ -148,7 +148,7 @@ TEST_CASE("Timing process", "[proccesses][analytic_processors ExecTime]") { fMean2 += delta * delta2; } - REQUIRE(fN == 1000000); + CHECK(fN == 1000); double mean = 0; std::for_each(elems.begin(), elems.end(), [&](double i) { mean += i; }); @@ -159,10 +159,10 @@ TEST_CASE("Timing process", "[proccesses][analytic_processors ExecTime]") { [&](double i) { var += (mean - i) * (mean - i); }); var = var / fN; - REQUIRE(mean == Approx(10000.0).margin(10)); - REQUIRE(var == Approx(200.0 * 200).margin(200)); + CHECK(mean == Approx(10000.0).margin(10)); + CHECK(var == Approx(200.0 * 200).margin(2000)); - REQUIRE(fMean2 / fN == Approx(200 * 200).margin(200)); // Varianz - REQUIRE(fMean == Approx(10000).margin(10)); + CHECK(fMean2 / fN == Approx(200 * 200).margin(2000)); // Varianz + CHECK(fMean == Approx(10000).margin(10)); } } diff --git a/Processes/CMakeLists.txt b/Processes/CMakeLists.txt index 5deaf153c5944aa5fe0800db28809ff5131f512b..4e9f59df367346d51a9072e6a7bfe95ec87fb4c1 100644 --- a/Processes/CMakeLists.txt +++ b/Processes/CMakeLists.txt @@ -2,7 +2,6 @@ add_subdirectory (AnalyticProcessors) add_subdirectory (ExampleProcessors) -add_subdirectory (NullModel) # tracking add_subdirectory (TrackingLine) # hadron interaction models @@ -31,13 +30,11 @@ add_subdirectory (ParticleCut) add_subdirectory (OnShellCheck) # meta-processes add_subdirectory (InteractionCounter) -add_subdirectory (SwitchProcess) ########################################## # add_custom_target(CORSIKAprocesses) add_library (CORSIKAprocesses INTERFACE) -add_dependencies (CORSIKAprocesses ProcessNullModel) add_dependencies (CORSIKAprocesses ProcessSibyll) add_dependencies (CORSIKAprocesses ProcessProposal) if (Pythia8_FOUND) diff --git a/Processes/EnergyLoss/CMakeLists.txt b/Processes/EnergyLoss/CMakeLists.txt index 62fca1ca017b3dbea3a4a331381596b87931ac01..3df3978d5fdb4a23b3548e5c68b8a55f6c11f4d8 100644 --- a/Processes/EnergyLoss/CMakeLists.txt +++ b/Processes/EnergyLoss/CMakeLists.txt @@ -32,6 +32,7 @@ target_link_libraries ( CORSIKAgeometry CORSIKAenvironment CORSIKAsetup + CORSIKAlogging ) target_include_directories ( diff --git a/Processes/EnergyLoss/EnergyLoss.cc b/Processes/EnergyLoss/EnergyLoss.cc index 69dcd7877e49b760980b15056c657a0468bf546f..336294d8e97ee9be5fdc3c82b46b30365849e826 100644 --- a/Processes/EnergyLoss/EnergyLoss.cc +++ b/Processes/EnergyLoss/EnergyLoss.cc @@ -13,6 +13,8 @@ #include <corsika/setup/SetupStack.h> #include <corsika/setup/SetupTrajectory.h> +#include <corsika/logging/Logging.h> + #include <corsika/geometry/Line.h> #include <cmath> @@ -85,19 +87,18 @@ HEPEnergyType EnergyLoss::BetheBloch(SetupParticle const& p, GrammageType const double const beta2 = (gamma2 - 1) / gamma2; // 1-1/gamma2 (1-1/gamma)*(1+1/gamma); // (gamma_2-1)/gamma_2 = (1-1/gamma2); double constexpr c2 = 1; // HEP convention here c=c2=1 - cout << "BetheBloch beta2=" << beta2 << " gamma2=" << gamma2 << endl; + C8LOG_DEBUG("BetheBloch beta2={}, gamma2={}", beta2, gamma2); [[maybe_unused]] double const eta2 = beta2 / (1 - beta2); HEPMassType const Wmax = 2 * me * c2 * beta2 * gamma2 / (1 + 2 * gamma * me / m + me2 / m2); // approx, but <<1% HEPMassType const Wmax = 2*me*c2*beta2*gamma2; for HEAVY // PARTICLES Wmax ~ 2me v2 for non-relativistic particles - cout << "BetheBloch Wmax=" << Wmax << endl; + C8LOG_DEBUG("BetheBloch Wmax={}", Wmax); // Sternheimer parameterization, density corrections towards high energies // NOTE/TODO: when Cbar is 0 it needs to be approximated from parameterization -> // MISSING - cout << "BetheBloch p.GetMomentum().GetNorm()/m=" << p.GetMomentum().GetNorm() / m - << endl; + C8LOG_DEBUG("BetheBloch p.GetMomentum().GetNorm()/m{}=", p.GetMomentum().GetNorm() / m); double const x = log10(p.GetMomentum().GetNorm() / m); double delta = 0; if (x >= x1) { @@ -107,7 +108,7 @@ HEPEnergyType EnergyLoss::BetheBloch(SetupParticle const& p, GrammageType const } else if (x < x0) { // and IF conductor (otherwise, this is 0) delta = delta0 * pow(100, 2 * (x - x0)); } - cout << "BetheBloch delta=" << delta << endl; + C8LOG_DEBUG("BetheBloch delta={}", delta); // with further low energies correction, accurary ~1% down to beta~0.05 (1MeV for p) @@ -141,9 +142,6 @@ HEPEnergyType EnergyLoss::BetheBloch(SetupParticle const& p, GrammageType const double const y2 = Z * Z * alpha * alpha / beta2; double const bloch = -y2 * (1.202 - y2 * (1.042 - 0.855 * y2 + 0.343 * y2 * y2)); - // cout << "BetheBloch Erel=" << Erel << " barkas=" << barkas << " bloch=" << bloch << - // endl; - double const aux = 2 * me * c2 * beta2 * gamma2 * Wmax / (Ieff * Ieff); return -K * Z2 * ZoverA / beta2 * (0.5 * log(aux) - beta2 - Cadj / Z - delta / 2 + barkas + bloch) * dX; @@ -168,24 +166,18 @@ process::EProcessReturn EnergyLoss::DoContinuous(SetupParticle& p, SetupTrack co GrammageType const dX = p.GetNode()->GetModelProperties().IntegratedGrammage(t, t.GetLength()); - cout << "EnergyLoss " << p.GetPID() << ", z=" << p.GetChargeNumber() - << ", dX=" << dX / 1_g * square(1_cm) << "g/cm2" << endl; + C8LOG_DEBUG("EnergyLoss pid={}, z={}, dX={} g/cm2", p.GetPID(), p.GetChargeNumber(), + dX / 1_g * square(1_cm)); HEPEnergyType dE = TotalEnergyLoss(p, dX); auto E = p.GetEnergy(); - const auto Ekin = E - p.GetMass(); + [[maybe_unused]] const auto Ekin = E - p.GetMass(); auto Enew = E + dE; - cout << "EnergyLoss dE=" << dE / 1_MeV << "MeV, " - << " E=" << E / 1_GeV << "GeV, Ekin=" << Ekin / 1_GeV << ", Enew=" << Enew / 1_GeV - << "GeV" << endl; - auto status = process::EProcessReturn::eOk; - if (E < emCut_) { - Enew = emCut_; - status = process::EProcessReturn::eParticleAbsorbed; - } + C8LOG_DEBUG("EnergyLoss dE={} MeV, E={} GeV, Ekin={} GeV, Enew={} GeV", dE / 1_MeV, + E / 1_GeV, Ekin / 1_GeV, Enew / 1_GeV); p.SetEnergy(Enew); MomentumUpdate(p, Enew); FillProfile(t, dE); - return status; + return process::EProcessReturn::eOk; } LengthType EnergyLoss::MaxStepLength(SetupParticle const& vParticle, @@ -228,34 +220,35 @@ void EnergyLoss::FillProfile(SetupTrack const& vTrack, const HEPEnergyType dE) { GrammageType const grammageEnd = shower_axis_.projectedX(vTrack.GetPosition(1)); const auto deltaX = grammageEnd - grammageStart; - const int binStart = grammageStart / dX_; - const int binEnd = grammageEnd / dX_; + int binStart = grammageStart / dX_; + if (binStart < 0) return; + int binEnd = grammageEnd / dX_; + if (binEnd > int(profile_.size() - 1)) return; + if (deltaX < dX_threshold_) return; - std::cout << "energy deposit of " << -dE << " between " << grammageStart << " and " - << grammageEnd << std::endl; + C8LOG_DEBUG("energy deposit of -dE={} between {} and {}", -dE, grammageStart, + grammageEnd); auto energyCount = HEPEnergyType::zero(); - auto fill = [&](int bin, GrammageType weight) { - if (deltaX > dX_threshold_) { - auto const increment = -dE * weight / deltaX; - profile_[bin] += increment; - energyCount += increment; + auto fill = [&](const int bin, const double weight) { + auto const increment = -dE * weight; + profile_[bin] += increment; + energyCount += increment; - std::cout << "filling bin " << bin << " with weight " << weight << ": " << increment - << std::endl; - } + C8LOG_DEBUG("filling bin {} with weight {} : {} ", bin, weight, increment); }; // fill longitudinal profile - fill(binStart, (1 + binStart) * dX_ - grammageStart); - fill(binEnd, grammageEnd - binEnd * dX_); - - if (binStart == binEnd) { fill(binStart, -dX_); } - - for (int bin = binStart + 1; bin < binEnd; ++bin) { fill(bin, dX_); } + if (binStart == binEnd) { + fill(binStart, 1); + } else { + fill(binStart, ((1 + binStart) * dX_ - grammageStart) / deltaX); + fill(binEnd, (grammageEnd - binEnd * dX_) / deltaX); + for (int bin = binStart + 1; bin < binEnd; ++bin) { fill(bin, 1); } + } - std::cout << "total energy added to histogram: " << energyCount << std::endl; + C8LOG_DEBUG("total energy added to histogram: {} ", energyCount); } void EnergyLoss::PrintProfile() const { diff --git a/Processes/LongitudinalProfile/LongitudinalProfile.cc b/Processes/LongitudinalProfile/LongitudinalProfile.cc index 0e174ee7338dfe2f5fb47bbbf6facfe811fe2ced..f9fd05c1baf2e450fc22e791a60e788a51ceda57 100644 --- a/Processes/LongitudinalProfile/LongitudinalProfile.cc +++ b/Processes/LongitudinalProfile/LongitudinalProfile.cc @@ -11,6 +11,8 @@ #include <corsika/particles/ParticleProperties.h> +#include <corsika/logging/Logging.h> + #include <corsika/setup/SetupStack.h> #include <corsika/setup/SetupTrajectory.h> @@ -39,6 +41,10 @@ corsika::process::EProcessReturn LongitudinalProfile::DoContinuous(Particle cons GrammageType const grammageStart = shower_axis_.projectedX(vTrack.GetPosition(0)); GrammageType const grammageEnd = shower_axis_.projectedX(vTrack.GetPosition(1)); + C8LOG_INFO( + "pos1={} m, pos2={}, X={} g/cm2", vTrack.GetPosition(0).GetCoordinates() / 1_m, + vTrack.GetPosition(1).GetCoordinates() / 1_m, grammageStart / 1_g * square(1_cm)); + const int binStart = std::ceil(grammageStart / dX_); const int binEnd = std::floor(grammageEnd / dX_); diff --git a/Processes/NullModel/NullModel.cc b/Processes/NullModel/NullModel.cc deleted file mode 100644 index 1a3afc793fd60c8cd5085c03cb444d3d1a399221..0000000000000000000000000000000000000000 --- a/Processes/NullModel/NullModel.cc +++ /dev/null @@ -1,31 +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/process/null_model/NullModel.h> -#include <corsika/setup/SetupStack.h> -#include <corsika/setup/SetupTrajectory.h> - -using namespace corsika; -namespace corsika::process::null_model { - - NullModel::NullModel(units::si::LengthType maxStepLength) - : fMaxStepLength(maxStepLength) {} - - template <> - process::EProcessReturn NullModel::DoContinuous(setup::Stack::ParticleType&, - setup::Trajectory&) const { - return process::EProcessReturn::eOk; - } - - template <> - units::si::LengthType NullModel::MaxStepLength(setup::Stack::ParticleType&, - setup::Trajectory&) const { - return fMaxStepLength; - } - -} // namespace corsika::process::null_model diff --git a/Processes/NullModel/NullModel.h b/Processes/NullModel/NullModel.h deleted file mode 100644 index ba80599f3e67cc9104b28b0ef35921b101841bb3..0000000000000000000000000000000000000000 --- a/Processes/NullModel/NullModel.h +++ /dev/null @@ -1,30 +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. - */ - -#pragma once - -#include <corsika/process/BaseProcess.h> -#include <corsika/units/PhysicalUnits.h> - -namespace corsika::process::null_model { - - class NullModel : public corsika::process::BaseProcess<NullModel> { - corsika::units::si::LengthType const fMaxStepLength; - - public: - NullModel(corsika::units::si::LengthType maxStepLength = - corsika::units::si::meter * std::numeric_limits<double>::infinity()); - - template <typename Particle, typename Track> - process::EProcessReturn DoContinuous(Particle&, Track&) const; - - template <typename Particle, typename Track> - corsika::units::si::LengthType MaxStepLength(Particle&, Track&) const; - }; - -} // namespace corsika::process::null_model diff --git a/Processes/NullModel/testNullModel.cc b/Processes/NullModel/testNullModel.cc deleted file mode 100644 index 653393e11e38e380424e53d618befe7fab4b2ace..0000000000000000000000000000000000000000 --- a/Processes/NullModel/testNullModel.cc +++ /dev/null @@ -1,53 +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 <catch2/catch.hpp> - -#include <corsika/process/null_model/NullModel.h> - -#include <corsika/geometry/Point.h> -#include <corsika/geometry/RootCoordinateSystem.h> -#include <corsika/geometry/Vector.h> - -#include <corsika/units/PhysicalUnits.h> - -#include <corsika/setup/SetupStack.h> -#include <corsika/setup/SetupTrajectory.h> - -using namespace corsika::units::si; -using namespace corsika::process::null_model; -using namespace corsika; - -TEST_CASE("NullModel", "[processes]") { - - auto const& dummyCS = - geometry::RootCoordinateSystem::GetInstance().GetRootCoordinateSystem(); - geometry::Point const origin(dummyCS, {0_m, 0_m, 0_m}); - geometry::Vector<units::si::SpeedType::dimension_type> v(dummyCS, 0_m / second, - 0_m / second, 1_m / second); - geometry::Line line(origin, v); - geometry::Trajectory<geometry::Line> track(line, 10_s); - - setup::Stack stack; - setup::Stack::ParticleType particle = stack.AddParticle( - std::tuple<particles::Code, units::si::HEPEnergyType, - corsika::stack::MomentumVector, geometry::Point, units::si::TimeType>{ - particles::Code::Electron, 100_GeV, - corsika::stack::MomentumVector(dummyCS, {0_GeV, 0_GeV, -1_GeV}), - geometry::Point(dummyCS, {0_m, 0_m, 10_km}), 0_ns}); - SECTION("interface") { - - NullModel model(10_m); - - [[maybe_unused]] const process::EProcessReturn ret = - model.DoContinuous(particle, track); - LengthType const length = model.MaxStepLength(particle, track); - - CHECK((length / 10_m) == Approx(1)); - } -} diff --git a/Processes/ObservationPlane/ObservationPlane.cc b/Processes/ObservationPlane/ObservationPlane.cc index cb7ee95bd6241c942189417da34107a6e19efbd0..ab3a8023215528084dd242b656597f74e9989d23 100644 --- a/Processes/ObservationPlane/ObservationPlane.cc +++ b/Processes/ObservationPlane/ObservationPlane.cc @@ -7,9 +7,9 @@ */ #include <corsika/process/observation_plane/ObservationPlane.h> +#include <corsika/logging/Logging.h> #include <fstream> -#include <iostream> using namespace corsika::process::observation_plane; using namespace corsika::units::si; @@ -25,7 +25,7 @@ ObservationPlane::ObservationPlane(geometry::Plane const& obsPlane, } corsika::process::EProcessReturn ObservationPlane::DoContinuous( - setup::Stack::ParticleType const& particle, setup::Trajectory const& trajectory) { + setup::Stack::ParticleType& particle, setup::Trajectory const& trajectory) { TimeType const timeOfIntersection = (plane_.GetCenter() - trajectory.GetR0()).dot(plane_.GetNormal()) / trajectory.GetV0().dot(plane_.GetNormal()); @@ -45,6 +45,7 @@ corsika::process::EProcessReturn ObservationPlane::DoContinuous( if (deleteOnHit_) { count_ground_++; energy_ground_ += energy; + particle.Delete(); return process::EProcessReturn::eParticleAbsorbed; } else { return process::EProcessReturn::eOk; @@ -62,15 +63,19 @@ LengthType ObservationPlane::MaxStepLength(setup::Stack::ParticleType const&, } auto const pointOfIntersection = trajectory.GetPosition(timeOfIntersection); - return (trajectory.GetR0() - pointOfIntersection).norm() * 1.0001; + auto dist = (trajectory.GetR0() - pointOfIntersection).norm() * 1.0001; + C8LOG_TRACE("ObservationPlane::MaxStepLength l={} m", dist / 1_m); + return dist; } void ObservationPlane::ShowResults() const { - std::cout << " ******************************" << std::endl - << " ObservationPlane: " << std::endl; - std::cout << " energy in ground (GeV) : " << energy_ground_ / 1_GeV << std::endl - << " no. of particles in ground : " << count_ground_ << std::endl - << " ******************************" << std::endl; + C8LOG_INFO( + " ******************************\n" + " ObservationPlane: \n" + " energy in ground (GeV) : {}\n" + " no. of particles in ground : {}\n" + " ******************************", + energy_ground_ / 1_GeV, count_ground_); } void ObservationPlane::Reset() { diff --git a/Processes/ObservationPlane/ObservationPlane.h b/Processes/ObservationPlane/ObservationPlane.h index 7223defb1748b5c67a04969316725fd09c65b8d9..86c5ba0f2100043f5a7c4b9c2ba250b1e3a57a20 100644 --- a/Processes/ObservationPlane/ObservationPlane.h +++ b/Processes/ObservationPlane/ObservationPlane.h @@ -29,7 +29,7 @@ namespace corsika::process::observation_plane { ObservationPlane(geometry::Plane const&, std::string const&, bool = true); corsika::process::EProcessReturn DoContinuous( - corsika::setup::Stack::ParticleType const& vParticle, + corsika::setup::Stack::ParticleType& vParticle, corsika::setup::Trajectory const& vTrajectory); corsika::units::si::LengthType MaxStepLength( diff --git a/Processes/ParticleCut/ParticleCut.cc b/Processes/ParticleCut/ParticleCut.cc index 72a97ee065d654799c7ae72cb4742a0d8d0a1452..728c7d25bb149ea20fb492628c9326f489426e62 100644 --- a/Processes/ParticleCut/ParticleCut.cc +++ b/Processes/ParticleCut/ParticleCut.cc @@ -27,9 +27,9 @@ namespace corsika::process { if (vP.GetPID() == particles::Code::Nucleus) { // calculate energy per nucleon auto const ElabNuc = energyLab / vP.GetNuclearA(); - return (ElabNuc <= fECut); + return (ElabNuc <= energy_cut_); } else { - return (energyLab <= fECut); + return (energyLab <= energy_cut_); } } @@ -87,13 +87,12 @@ namespace corsika::process { return false; // this particle will not be removed/cut } - EProcessReturn ParticleCut::DoSecondaries(corsika::setup::StackView& vS) { + void ParticleCut::DoSecondaries(corsika::setup::StackView& vS) { auto particle = vS.begin(); while (particle != vS.end()) { if (checkCutParticle(particle)) { particle.Delete(); } ++particle; // next entry in SecondaryView } - return EProcessReturn::eOk; } process::EProcessReturn ParticleCut::DoContinuous( @@ -102,13 +101,15 @@ namespace corsika::process { C8LOG_TRACE("ParticleCut::DoContinuous"); if (checkCutParticle(particle)) { C8LOG_TRACE("removing during continuous"); + particle.Delete(); + // signal to upstream code that this particle was deleted return process::EProcessReturn::eParticleAbsorbed; } return process::EProcessReturn::eOk; } ParticleCut::ParticleCut(const units::si::HEPEnergyType eCut, bool em, bool inv) - : fECut(eCut) + : energy_cut_(eCut) , bCutEm(em) , bCutInv(inv) { fEmEnergy = 0_GeV; diff --git a/Processes/ParticleCut/ParticleCut.h b/Processes/ParticleCut/ParticleCut.h index 4705051d4261028c49caca1af39066563fd1bff6..b0e8977530a8fd7a800908bd6eb48519a411d9f0 100644 --- a/Processes/ParticleCut/ParticleCut.h +++ b/Processes/ParticleCut/ParticleCut.h @@ -12,6 +12,7 @@ #include <corsika/process/ContinuousProcess.h> #include <corsika/process/SecondariesProcess.h> #include <corsika/setup/SetupStack.h> +#include <corsika/setup/SetupTrajectory.h> #include <corsika/units/PhysicalUnits.h> namespace corsika::process { @@ -19,7 +20,7 @@ namespace corsika::process { class ParticleCut : public process::SecondariesProcess<ParticleCut>, public corsika::process::ContinuousProcess<ParticleCut> { - units::si::HEPEnergyType const fECut; + units::si::HEPEnergyType const energy_cut_; bool bCutEm; bool bCutInv; @@ -32,7 +33,7 @@ namespace corsika::process { public: ParticleCut(const units::si::HEPEnergyType eCut, bool em, bool inv); - EProcessReturn DoSecondaries(corsika::setup::StackView&); + void DoSecondaries(corsika::setup::StackView&); EProcessReturn DoContinuous(corsika::setup::Stack::ParticleType& vParticle, corsika::setup::Trajectory const& vTrajectory); @@ -42,7 +43,7 @@ namespace corsika::process { return units::si::meter * std::numeric_limits<double>::infinity(); } - units::si::HEPEnergyType GetECut() const { return fECut; } + units::si::HEPEnergyType GetECut() const { return energy_cut_; } units::si::HEPEnergyType GetInvEnergy() const { return fInvEnergy; } units::si::HEPEnergyType GetCutEnergy() const { return fEnergy; } units::si::HEPEnergyType GetEmEnergy() const { return fEmEnergy; } diff --git a/Processes/ParticleCut/testParticleCut.cc b/Processes/ParticleCut/testParticleCut.cc index 2092636fa372628080769d22c52679289d9d045b..921eecc3ea2e59095f276bb03d7faec4ab43174a 100644 --- a/Processes/ParticleCut/testParticleCut.cc +++ b/Processes/ParticleCut/testParticleCut.cc @@ -37,15 +37,16 @@ TEST_CASE("ParticleCut", "[processes]") { const HEPEnergyType Eabove = 1_TeV; const HEPEnergyType Ebelow = 10_GeV; // list of arbitrary particles - std::vector<particles::Code> particleList = { + const std::vector<particles::Code> particleList = { particles::Code::PiPlus, particles::Code::PiMinus, particles::Code::KPlus, particles::Code::KMinus, particles::Code::K0Long, particles::Code::K0Short, particles::Code::Electron, particles::Code::MuPlus, particles::Code::NuE, - particles::Code::Neutron}; + particles::Code::Neutron, particles::Code::NuMu}; SECTION("cut on particle type: inv") { ParticleCut cut(20_GeV, false, true); + CHECK(cut.GetECut() == 20_GeV); // add primary particle to stack auto particle = stack.AddParticle( @@ -62,15 +63,15 @@ TEST_CASE("ParticleCut", "[processes]") { // add secondaries, all with energies above the threshold // only cut is by species for (auto proType : particleList) - projectile.AddSecondary(std::tuple<particles::Code, units::si::HEPEnergyType, - corsika::stack::MomentumVector, geometry::Point, - units::si::TimeType>{ + projectile.AddSecondary(std::make_tuple( proType, Eabove, corsika::stack::MomentumVector(rootCS, {0_GeV, 0_GeV, 0_GeV}), - geometry::Point(rootCS, 0_m, 0_m, 0_m), 0_ns}); + geometry::Point(rootCS, 0_m, 0_m, 0_m), 0_ns)); cut.DoSecondaries(view); CHECK(view.getEntries() == 9); + CHECK(cut.GetNumberInvParticles() == 2); + CHECK(cut.GetInvEnergy() / 1_GeV == 2000); } SECTION("cut on particle type: em") { @@ -79,11 +80,9 @@ TEST_CASE("ParticleCut", "[processes]") { // add primary particle to stack auto particle = stack.AddParticle( - std::tuple<particles::Code, units::si::HEPEnergyType, - corsika::stack::MomentumVector, geometry::Point, units::si::TimeType>{ - particles::Code::Proton, Eabove, - corsika::stack::MomentumVector(rootCS, {0_GeV, 0_GeV, 0_GeV}), - geometry::Point(rootCS, 0_m, 0_m, 0_m), 0_ns}); + std::make_tuple(particles::Code::Proton, Eabove, + corsika::stack::MomentumVector(rootCS, {0_GeV, 0_GeV, 0_GeV}), + geometry::Point(rootCS, 0_m, 0_m, 0_m), 0_ns)); // view on secondary particles corsika::setup::StackView view(particle); // ref. to primary particle through the secondary view. @@ -91,16 +90,16 @@ TEST_CASE("ParticleCut", "[processes]") { auto projectile = view.GetProjectile(); // add secondaries, all with energies above the threshold // only cut is by species - for (auto proType : particleList) - projectile.AddSecondary(std::tuple<particles::Code, units::si::HEPEnergyType, - corsika::stack::MomentumVector, geometry::Point, - units::si::TimeType>{ + for (auto proType : particleList) { + projectile.AddSecondary(std::make_tuple( proType, Eabove, corsika::stack::MomentumVector(rootCS, {0_GeV, 0_GeV, 0_GeV}), - geometry::Point(rootCS, 0_m, 0_m, 0_m), 0_ns}); - + geometry::Point(rootCS, 0_m, 0_m, 0_m), 0_ns)); + } cut.DoSecondaries(view); - CHECK(view.getEntries() == 9); + CHECK(view.getEntries() == 10); + CHECK(cut.GetNumberEmParticles() == 1); + CHECK(cut.GetEmEnergy() / 1_GeV == 1000); } SECTION("cut low energy") { @@ -108,11 +107,9 @@ TEST_CASE("ParticleCut", "[processes]") { // add primary particle to stack auto particle = stack.AddParticle( - std::tuple<particles::Code, units::si::HEPEnergyType, - corsika::stack::MomentumVector, geometry::Point, units::si::TimeType>{ - particles::Code::Proton, Eabove, - corsika::stack::MomentumVector(rootCS, {0_GeV, 0_GeV, 0_GeV}), - geometry::Point(rootCS, 0_m, 0_m, 0_m), 0_ns}); + std::make_tuple(particles::Code::Proton, Eabove, + corsika::stack::MomentumVector(rootCS, {0_GeV, 0_GeV, 0_GeV}), + geometry::Point(rootCS, 0_m, 0_m, 0_m), 0_ns)); // view on secondary particles setup::StackView view{particle}; // ref. to primary particle through the secondary view. @@ -121,15 +118,52 @@ TEST_CASE("ParticleCut", "[processes]") { // add secondaries, all with energies below the threshold // only cut is by species for (auto proType : particleList) - projectile.AddSecondary(std::tuple<particles::Code, units::si::HEPEnergyType, - corsika::stack::MomentumVector, geometry::Point, - units::si::TimeType>{ + projectile.AddSecondary(std::make_tuple( proType, Ebelow, corsika::stack::MomentumVector(rootCS, {0_GeV, 0_GeV, 0_GeV}), - geometry::Point(rootCS, 0_m, 0_m, 0_m), 0_ns}); + geometry::Point(rootCS, 0_m, 0_m, 0_m), 0_ns)); + unsigned short A = 18; + unsigned short Z = 8; + projectile.AddSecondary( + std::make_tuple(particles::Code::Nucleus, Eabove * A, + corsika::stack::MomentumVector(rootCS, {0_GeV, 0_GeV, 0_GeV}), + geometry::Point(rootCS, 0_m, 0_m, 0_m), 0_ns, A, Z)); + projectile.AddSecondary( + std::make_tuple(particles::Code::Nucleus, Ebelow * A, + corsika::stack::MomentumVector(rootCS, {0_GeV, 0_GeV, 0_GeV}), + geometry::Point(rootCS, 0_m, 0_m, 0_m), 0_ns, A, Z)); + + cut.DoSecondaries(view); + + CHECK(view.getEntries() == 1); + CHECK(view.getSize() == 13); + } + + SECTION("cut on time") { + ParticleCut cut(20_GeV, false, false); + const TimeType too_late = 1_s; + // add primary particle to stack + auto particle = stack.AddParticle( + std::make_tuple(particles::Code::Proton, Eabove, + corsika::stack::MomentumVector(rootCS, {0_GeV, 0_GeV, 0_GeV}), + geometry::Point(rootCS, 0_m, 0_m, 0_m), 1_ns)); + // view on secondary particles + corsika::setup::StackView view(particle); + // ref. to primary particle through the secondary view. + // only this way the secondary view is populated + auto projectile = view.GetProjectile(); + // add secondaries, all with energies above the threshold + // only cut is by species + for (auto proType : particleList) { + projectile.AddSecondary(std::make_tuple( + proType, Eabove, corsika::stack::MomentumVector(rootCS, {0_GeV, 0_GeV, 0_GeV}), + geometry::Point(rootCS, 0_m, 0_m, 0_m), too_late)); + } cut.DoSecondaries(view); - REQUIRE(view.getEntries() == 0); - REQUIRE(view.getSize() == 10); + CHECK(view.getEntries() == 0); + CHECK(cut.GetCutEnergy() / 1_GeV == 11000); + cut.Reset(); + CHECK(cut.GetCutEnergy() == 0_GeV); } } diff --git a/Processes/Proposal/CMakeLists.txt b/Processes/Proposal/CMakeLists.txt index cc0be5438fc75bb48f32b0501957d41cf1ce38a2..08a37a68b441536a1fba53314165b00991d64d19 100644 --- a/Processes/Proposal/CMakeLists.txt +++ b/Processes/Proposal/CMakeLists.txt @@ -22,6 +22,7 @@ TARGET_LINK_LIBRARIES ( CORSIKAunits CORSIKAthirdparty CORSIKAgeometry + CORSIKAlogging CORSIKAenvironment ProcessParticleCut PROPOSAL::PROPOSAL diff --git a/Processes/Proposal/ContinuousProcess.cc b/Processes/Proposal/ContinuousProcess.cc index 59ec7e87f56d92cc4433abf090d838ccd24fc6c7..371f28262bd3b7a5e5f67fc2d2415c221cd43ffc 100644 --- a/Processes/Proposal/ContinuousProcess.cc +++ b/Processes/Proposal/ContinuousProcess.cc @@ -15,6 +15,7 @@ #include <corsika/setup/SetupTrajectory.h> #include <corsika/units/PhysicalUnits.h> #include <corsika/utl/COMBoost.h> +#include <corsika/logging/Logging.h> #include <iostream> @@ -106,19 +107,6 @@ namespace corsika::process::proposal { // if the particle has a charge take multiple scattering into account if (vP.GetChargeNumber() != 0) Scatter(vP, dE, dX); - - // Update the energy and absorbe the particle if it's below the energy - // threshold, because it will no longer propagated. - if (final_energy <= emCut_) { - vP.SetEnergy(emCut_); - vP.SetMomentum(vP.GetMomentum() * vP.GetEnergy() / vP.GetMomentum().GetNorm()); - return process::EProcessReturn::eParticleAbsorbed; - } - if (final_energy <= emCut_) { - vP.SetEnergy(emCut_); - vP.SetMomentum(vP.GetMomentum() * vP.GetEnergy() / vP.GetMomentum().GetNorm()); - return process::EProcessReturn::eParticleAbsorbed; - } vP.SetEnergy(final_energy); vP.SetMomentum(vP.GetMomentum() * vP.GetEnergy() / vP.GetMomentum().GetNorm()); return process::EProcessReturn::eOk; @@ -132,7 +120,7 @@ namespace corsika::process::proposal { if (!CanInteract(vP.GetPID())) return units::si::meter * std::numeric_limits<double>::infinity(); - // Limit the step size of a conitnous loss. The maximal continuous loss seems to be a + // Limit the step size of a conitnuous loss. The maximal continuous loss seems to be a // hyper parameter which must be adjusted. // // in any case: never go below 0.99*emCut_ This needs to be @@ -152,7 +140,10 @@ namespace corsika::process::proposal { 1_g / square(1_cm); // return it in distance aequivalent - return vP.GetNode()->GetModelProperties().ArclengthFromGrammage(vT, grammage); + auto dist = vP.GetNode()->GetModelProperties().ArclengthFromGrammage(vT, grammage); + C8LOG_TRACE("PROPOSAL::MaxStepLength X={} g/cm2, l={} m ", + grammage / 1_g * square(1_cm), dist / 1_m); + return dist; } void ContinuousProcess::ShowResults() const { diff --git a/Processes/Pythia/Decay.cc b/Processes/Pythia/Decay.cc index 4caf02487afa2d7a89d600a33a2c46eefb00c294..92920dfbacdcaa809df665db59ae57bc70d8b46c 100644 --- a/Processes/Pythia/Decay.cc +++ b/Processes/Pythia/Decay.cc @@ -28,7 +28,8 @@ using Track = Trajectory; namespace corsika::process::pythia { - Decay::Decay() { + Decay::Decay(const bool print_listing) + : print_listing_(print_listing) { // set random number generator in pythia Pythia8::RndmEngine* rndm = new corsika::process::pythia::Random(); @@ -231,8 +232,10 @@ namespace corsika::process::pythia { else cout << "Pythia::Decay: particles after decay: " << event.size() << endl; - // list final state - event.list(); + if (print_listing_) { + // list final state + event.list(); + } // loop over final state for (int i = 0; i < event.size(); ++i) diff --git a/Processes/Pythia/Decay.h b/Processes/Pythia/Decay.h index fb4708df15e3c7948a0d352d2ebcd326af68aa53..51a43b7e3824ec399eefa4bf96893144cb2db8f4 100644 --- a/Processes/Pythia/Decay.h +++ b/Processes/Pythia/Decay.h @@ -11,6 +11,8 @@ #include <Pythia8/Pythia.h> #include <corsika/particles/ParticleProperties.h> #include <corsika/process/DecayProcess.h> +#include <corsika/units/PhysicalUnits.h> +#include <corsika/geometry/FourVector.h> namespace corsika::process { @@ -21,9 +23,10 @@ namespace corsika::process { class Decay : public corsika::process::DecayProcess<Decay> { int fCount = 0; bool handleAllDecays_ = true; + bool print_listing_ = false; public: - Decay(); + Decay(const bool print_listing = false); Decay(std::set<particles::Code>); ~Decay(); diff --git a/Processes/Pythia/Interaction.cc b/Processes/Pythia/Interaction.cc index fe641a62629a5bfc2b75f4ce9d0ada6c984322ce..7a0dbfa64878c77d3fbed0b6fd58798219dc0b38 100644 --- a/Processes/Pythia/Interaction.cc +++ b/Processes/Pythia/Interaction.cc @@ -29,9 +29,9 @@ namespace corsika::process::pythia { typedef corsika::geometry::Vector<corsika::units::si::hepmomentum_d> MomentumVector; - Interaction::~Interaction() {} + Interaction::Interaction(const bool print_listing) + : print_listing_(print_listing) { - Interaction::Interaction() { cout << "Pythia::Interaction n=" << fCount << endl; using random::RNGManager; @@ -164,7 +164,7 @@ namespace corsika::process::pythia { } template <> - units::si::GrammageType Interaction::GetInteractionLength(Particle& p) { + units::si::GrammageType Interaction::GetInteractionLength(const Particle& p) { using namespace units; using namespace units::si; @@ -365,8 +365,11 @@ namespace corsika::process::pythia { // link to pythia stack Pythia8::Event& event = fPythia.event; - // print final state - event.list(); + + if (print_listing_) { + // list final state + event.list(); + } MomentumVector Plab_final(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV}); HEPEnergyType Elab_final = 0_GeV; diff --git a/Processes/Pythia/Interaction.h b/Processes/Pythia/Interaction.h index 4b06aeb6d58f6bf034b49b054376e540fa279628..ef2bdfbcc5566951434c73df86ec621e561f48b9 100644 --- a/Processes/Pythia/Interaction.h +++ b/Processes/Pythia/Interaction.h @@ -22,10 +22,11 @@ namespace corsika::process::pythia { int fCount = 0; bool fInitialized = false; + bool print_listing_ = false; public: - Interaction(); - ~Interaction(); + Interaction(const bool print_listing = false); + ~Interaction() = default; void SetParticleListStable(std::vector<particles::Code> const&); void SetUnstable(const corsika::particles::Code); @@ -47,7 +48,7 @@ namespace corsika::process::pythia { const corsika::units::si::HEPEnergyType CoMenergy); template <typename TParticle> - corsika::units::si::GrammageType GetInteractionLength(TParticle&); + corsika::units::si::GrammageType GetInteractionLength(const TParticle&); /** In this function PYTHIA is called to produce one event. The diff --git a/Processes/Sibyll/Decay.cc b/Processes/Sibyll/Decay.cc index 62d0b45819be56c8fcbec7b67360a17c96650b73..8297739b793e33d7b4fe9b65bfd66def992f372e 100644 --- a/Processes/Sibyll/Decay.cc +++ b/Processes/Sibyll/Decay.cc @@ -23,11 +23,12 @@ using namespace corsika::setup; using SetupView = corsika::setup::StackView; using SetupProjectile = corsika::setup::StackView::ParticleType; -using SetupParticle = corsika::setup::Stack::ParticleType; +using Particle = corsika::setup::Stack::ParticleType; namespace corsika::process::sibyll { - Decay::Decay() { + Decay::Decay(const bool sibyll_printout_on) + : sibyll_listing_(sibyll_printout_on) { // switch off decays to avoid internal decay chains SetAllStable(); // handle all decays by default @@ -40,7 +41,7 @@ namespace corsika::process::sibyll { SetAllStable(); } - Decay::~Decay() { C8LOG_DEBUG(fmt::format("Sibyll::Decay n={}", fCount)); } + Decay::~Decay() { C8LOG_DEBUG("Sibyll::Decay n={}", count_); } bool Decay::CanHandleDecay(const particles::Code vParticleCode) { using namespace corsika::particles; @@ -60,7 +61,7 @@ namespace corsika::process::sibyll { void Decay::SetHandleDecay(const particles::Code vParticleCode) { handleAllDecays_ = false; - C8LOG_DEBUG(fmt::format("Sibyll::Decay: set to handle decay of {}", vParticleCode)); + C8LOG_DEBUG("Sibyll::Decay: set to handle decay of {}", vParticleCode); if (Decay::CanHandleDecay(vParticleCode)) handledDecays_.insert(vParticleCode); else @@ -102,13 +103,13 @@ namespace corsika::process::sibyll { } void Decay::SetUnstable(const particles::Code vCode) { - C8LOG_DEBUG(fmt::format("Sibyll::Decay: setting {} unstable. ", vCode)); + C8LOG_DEBUG("Sibyll::Decay: setting {} unstable. ", vCode); const int s_id = abs(process::sibyll::ConvertToSibyllRaw(vCode)); s_csydec_.idb[s_id - 1] = abs(s_csydec_.idb[s_id - 1]); } void Decay::SetStable(const particles::Code vCode) { - C8LOG_DEBUG(fmt::format("Sibyll::Decay: setting {} stable. ", vCode)); + C8LOG_DEBUG("Sibyll::Decay: setting {} stable. ", vCode); const int s_id = abs(process::sibyll::ConvertToSibyllRaw(vCode)); s_csydec_.idb[s_id - 1] = (-1) * abs(s_csydec_.idb[s_id - 1]); } @@ -121,28 +122,26 @@ namespace corsika::process::sibyll { for (int i = 0; i < 99; ++i) s_csydec_.idb[i] = abs(s_csydec_.idb[i]); } - void Decay::PrintDecayConfig(const particles::Code vCode) { - const int sibCode = process::sibyll::ConvertToSibyllRaw(vCode); - const int absSibCode = abs(sibCode); - C8LOG_DEBUG( - fmt::format("Decay: Sibyll decay configuration: {} is {}", vCode, - (s_csydec_.idb[absSibCode - 1] <= 0) ? "stable" : "unstable")); + void Decay::PrintDecayConfig([[maybe_unused]] const particles::Code vCode) { + [[maybe_unused]] const int sibCode = process::sibyll::ConvertToSibyllRaw(vCode); + [[maybe_unused]] const int absSibCode = abs(sibCode); + C8LOG_DEBUG("Decay: Sibyll decay configuration: {} is {}", vCode, + (s_csydec_.idb[absSibCode - 1] <= 0) ? "stable" : "unstable"); } void Decay::PrintDecayConfig() { - C8LOG_DEBUG(fmt::format("Sibyll::Decay: decay configuration:")); + C8LOG_DEBUG("Sibyll::Decay: decay configuration:"); if (handleAllDecays_) { - C8LOG_DEBUG(fmt::format( - " all particles known to Sibyll are handled by Sibyll::Decay!")); + C8LOG_DEBUG(" all particles known to Sibyll are handled by Sibyll::Decay!"); } else { - for (auto& pCode : handledDecays_) { - C8LOG_DEBUG(fmt::format(" Decay of {} is handled by Sibyll!", pCode)); + for ([[maybe_unused]] auto& pCode : handledDecays_) { + C8LOG_DEBUG(" Decay of {} is handled by Sibyll!", pCode); } } } template <> - units::si::TimeType Decay::GetLifetime(SetupParticle const& vP) { + units::si::TimeType Decay::GetLifetime(Particle const& vP) { using namespace units::si; const particles::Code pid = vP.GetPID(); @@ -155,19 +154,19 @@ namespace corsika::process::sibyll { const TimeType t0 = particles::GetLifetime(vP.GetPID()); auto const lifetime = gamma * t0; - const auto mkin = + [[maybe_unused]] const auto mkin = (E * E - vP.GetMomentum().squaredNorm()); // delta_mass(vP.GetMomentum(), E, m); - C8LOG_DEBUG(fmt::format("Sibyll::Decay: code: {} ", vP.GetPID())); - C8LOG_DEBUG(fmt::format("Sibyll::Decay: MinStep: t0: {} ", t0)); - C8LOG_DEBUG(fmt::format("Sibyll::Decay: MinStep: energy: {} GeV ", E / 1_GeV)); - C8LOG_DEBUG(fmt::format("Sibyll::Decay: momentum: {} GeV ", - vP.GetMomentum().GetComponents() / 1_GeV)); - C8LOG_DEBUG(fmt::format("Sibyll::Decay: momentum: shell mass-kin. inv. mass {} {}", - mkin / 1_GeV / 1_GeV, m / 1_GeV * m / 1_GeV)); - auto sib_id = process::sibyll::ConvertToSibyllRaw(vP.GetPID()); - C8LOG_DEBUG(fmt::format("Sibyll::Decay: sib mass: {}", get_sibyll_mass2(sib_id))); - C8LOG_DEBUG(fmt::format("Sibyll::Decay: MinStep: gamma: {}", gamma)); - C8LOG_DEBUG(fmt::format("Sibyll::Decay: MinStep: tau {} s: ", lifetime / 1_s)); + C8LOG_DEBUG("Sibyll::Decay: code: {} ", vP.GetPID()); + C8LOG_DEBUG("Sibyll::Decay: MinStep: t0: {} ", t0); + C8LOG_DEBUG("Sibyll::Decay: MinStep: energy: {} GeV ", E / 1_GeV); + C8LOG_DEBUG("Sibyll::Decay: momentum: {} GeV ", + vP.GetMomentum().GetComponents() / 1_GeV); + C8LOG_DEBUG("Sibyll::Decay: momentum: shell mass-kin. inv. mass {} {}", + mkin / 1_GeV / 1_GeV, m / 1_GeV * m / 1_GeV); + [[maybe_unused]] auto sib_id = process::sibyll::ConvertToSibyllRaw(vP.GetPID()); + C8LOG_DEBUG("Sibyll::Decay: sib mass: {}", get_sibyll_mass2(sib_id)); + C8LOG_DEBUG("Sibyll::Decay: MinStep: gamma: {}", gamma); + C8LOG_DEBUG("Sibyll::Decay: MinStep: tau {} s: ", lifetime / 1_s); return lifetime; } else @@ -186,7 +185,7 @@ namespace corsika::process::sibyll { if (!IsDecayHandled(pCode)) throw std::runtime_error("STOP! Sibyll not configured to execute this decay!"); - fCount++; + count_++; SibStack ss; ss.Clear(); @@ -206,12 +205,14 @@ namespace corsika::process::sibyll { PrintDecayConfig(pCode); // call sibyll decay - C8LOG_DEBUG(fmt::format("Decay: calling Sibyll decay routine..")); + C8LOG_DEBUG("Decay: calling Sibyll decay routine.."); decsib_(); - // print output - int print_unit = 6; - sib_list_(print_unit); + if (sibyll_listing_) { + // print output + int print_unit = 6; + sib_list_(print_unit); + } // reset to stable SetStable(pCode); diff --git a/Processes/Sibyll/Decay.h b/Processes/Sibyll/Decay.h index 42867ed2b560487901489c0df1bb153380948147..e5862344e86c13d6dbc11ee78246987fe3fcf198 100644 --- a/Processes/Sibyll/Decay.h +++ b/Processes/Sibyll/Decay.h @@ -20,11 +20,12 @@ namespace corsika::process { namespace sibyll { class Decay : public corsika::process::DecayProcess<Decay> { - int fCount = 0; + int count_ = 0; bool handleAllDecays_ = true; + bool sibyll_listing_ = false; public: - Decay(); + Decay(const bool sibyll_listing = false); Decay(std::set<particles::Code>); ~Decay(); diff --git a/Processes/Sibyll/Interaction.cc b/Processes/Sibyll/Interaction.cc index b028ca8769e3761c8adf6453b6162478271a756e..aa222b7f65ced91a80b5e6402a0ae5a45926c6dc 100644 --- a/Processes/Sibyll/Interaction.cc +++ b/Processes/Sibyll/Interaction.cc @@ -25,7 +25,7 @@ using std::tuple; using namespace corsika; using namespace corsika::setup; -using SetupParticle = setup::Stack::StackIterator; +using Particle = setup::Stack::StackIterator; using SetupView = setup::StackView; using Track = Trajectory; @@ -33,7 +33,8 @@ namespace corsika::process::sibyll { bool Interaction::initialized_ = false; - Interaction::Interaction() { + Interaction::Interaction(const bool sibyll_printout_on) + : sibyll_listing_(sibyll_printout_on) { using random::RNGManager; // initialize Sibyll @@ -81,8 +82,7 @@ namespace corsika::process::sibyll { } template <> - units::si::GrammageType Interaction::GetInteractionLength( - SetupParticle const& vP) const { + units::si::GrammageType Interaction::GetInteractionLength(Particle const& vP) const { using namespace units; using namespace units::si; @@ -172,187 +172,186 @@ namespace corsika::process::sibyll { auto const projectile = view.GetProjectile(); const auto corsikaBeamId = projectile.GetPID(); - C8LOG_DEBUG( - fmt::format("ProcessSibyll: " - "DoInteraction: {} interaction? ", - corsikaBeamId, process::sibyll::CanInteract(corsikaBeamId))); if (particles::IsNucleus(corsikaBeamId)) { // nuclei handled by different process, this should not happen throw std::runtime_error("Nuclear projectile are not handled by SIBYLL!"); } - if (process::sibyll::CanInteract(corsikaBeamId)) { - // position and time of interaction, not used in Sibyll - Point const pOrig = projectile.GetPosition(); - TimeType const tOrig = projectile.GetTime(); + // position and time of interaction, not used in Sibyll + Point const pOrig = projectile.GetPosition(); + TimeType const tOrig = projectile.GetTime(); - // define projectile - HEPEnergyType const eProjectileLab = projectile.GetEnergy(); - auto const pProjectileLab = projectile.GetMomentum(); - const CoordinateSystem& originalCS = pProjectileLab.GetCoordinateSystem(); + // define projectile + HEPEnergyType const eProjectileLab = projectile.GetEnergy(); + auto const pProjectileLab = projectile.GetMomentum(); + const CoordinateSystem& originalCS = pProjectileLab.GetCoordinateSystem(); - // define target - // for Sibyll is always a single nucleon - // FOR NOW: target is always at rest - const auto eTargetLab = 0_GeV + constants::nucleonMass; - const auto pTargetLab = MomentumVector(originalCS, 0_GeV, 0_GeV, 0_GeV); - const FourVector PtargLab(eTargetLab, pTargetLab); + C8LOG_DEBUG( + "ProcessSibyll: " + "DoInteraction: pid {} interaction ", + corsikaBeamId); - C8LOG_DEBUG( - fmt::format("Interaction: ebeam lab: {} GeV" - "Interaction: pbeam lab: {} GeV", - eProjectileLab / 1_GeV, pProjectileLab.GetComponents())); - C8LOG_DEBUG( - fmt::format("Interaction: etarget lab: {} GeV " - "Interaction: ptarget lab: {} GeV", - eTargetLab / 1_GeV, pTargetLab.GetComponents() / 1_GeV)); + // define target + // for Sibyll is always a single nucleon + // FOR NOW: target is always at rest + const auto eTargetLab = 0_GeV + constants::nucleonMass; + const auto pTargetLab = MomentumVector(originalCS, 0_GeV, 0_GeV, 0_GeV); + const FourVector PtargLab(eTargetLab, pTargetLab); - const FourVector PprojLab(eProjectileLab, pProjectileLab); + C8LOG_DEBUG( + "Interaction: ebeam lab: {} GeV" + "Interaction: pbeam lab: {} GeV", + eProjectileLab / 1_GeV, pProjectileLab.GetComponents()); + C8LOG_DEBUG( + "Interaction: etarget lab: {} GeV " + "Interaction: ptarget lab: {} GeV", + eTargetLab / 1_GeV, pTargetLab.GetComponents() / 1_GeV); - // define target kinematics in lab frame - // define boost to and from CoM frame - // CoM frame definition in Sibyll projectile: +z - COMBoost const boost(PprojLab, constants::nucleonMass); - auto const& csPrime = boost.GetRotatedCS(); + const FourVector PprojLab(eProjectileLab, pProjectileLab); - // just for show: - // boost projecticle - auto const PprojCoM = boost.toCoM(PprojLab); + // define target kinematics in lab frame + // define boost to and from CoM frame + // CoM frame definition in Sibyll projectile: +z + COMBoost const boost(PprojLab, constants::nucleonMass); + auto const& csPrime = boost.GetRotatedCS(); - // boost target - auto const PtargCoM = boost.toCoM(PtargLab); + // just for show: + // boost projecticle + [[maybe_unused]] auto const PprojCoM = boost.toCoM(PprojLab); - C8LOG_DEBUG( - fmt::format("Interaction: ebeam CoM: {} GeV " - "Interaction: pbeam CoM: {} GeV ", - PprojCoM.GetTimeLikeComponent() / 1_GeV, - PprojCoM.GetSpaceLikeComponents().GetComponents(csPrime) / 1_GeV)); - C8LOG_DEBUG( - fmt::format("Interaction: etarget CoM: {} GeV " - "Interaction: ptarget CoM: {} GeV ", - PtargCoM.GetTimeLikeComponent() / 1_GeV, - PtargCoM.GetSpaceLikeComponents().GetComponents(csPrime) / 1_GeV)); - - C8LOG_DEBUG(fmt::format("Interaction: position of interaction: {} ", - pOrig.GetCoordinates())); - C8LOG_DEBUG(fmt::format("Interaction: time: {} ", tOrig)); - - HEPEnergyType Etot = eProjectileLab + eTargetLab; - MomentumVector Ptot = projectile.GetMomentum(); - // invariant mass, i.e. cm. energy - HEPEnergyType Ecm = sqrt(Etot * Etot - Ptot.squaredNorm()); - - // sample target mass number - auto const* currentNode = projectile.GetNode(); - auto const& mediumComposition = - currentNode->GetModelProperties().GetNuclearComposition(); - // get cross sections for target materials - /* - Here we read the cross section from the interaction model again, - should be passed from GetInteractionLength if possible - */ - //#warning reading interaction cross section again, should not be necessary - auto const& compVec = mediumComposition.GetComponents(); - std::vector<CrossSectionType> cross_section_of_components(compVec.size()); - - for (size_t i = 0; i < compVec.size(); ++i) { - auto const targetId = compVec[i]; - const auto [sigProd, sigEla] = GetCrossSection(corsikaBeamId, targetId, Ecm); - [[maybe_unused]] const auto& dummy_sigEla = sigEla; - cross_section_of_components[i] = sigProd; - } + // boost target + [[maybe_unused]] auto const PtargCoM = boost.toCoM(PtargLab); - const auto targetCode = - mediumComposition.SampleTarget(cross_section_of_components, RNG_); - C8LOG_DEBUG(fmt::format("Interaction: target selected: {} ", targetCode)); - /* - FOR NOW: allow nuclei with A<18 or protons only. - when medium composition becomes more complex, approximations will have to be - allowed air in atmosphere also contains some Argon. - */ - int targetSibCode = -1; - if (IsNucleus(targetCode)) targetSibCode = GetNucleusA(targetCode); - if (targetCode == particles::Proton::GetCode()) targetSibCode = 1; - C8LOG_DEBUG(fmt::format("Interaction: sibyll code: {}", targetSibCode)); - if (targetSibCode > maxTargetMassNumber_ || targetSibCode < 1) - throw std::runtime_error( - "Sibyll target outside range. Only nuclei with A<18 or protons are " - "allowed."); + C8LOG_DEBUG( + "Interaction: ebeam CoM: {} GeV " + "Interaction: pbeam CoM: {} GeV ", + PprojCoM.GetTimeLikeComponent() / 1_GeV, + PprojCoM.GetSpaceLikeComponents().GetComponents(csPrime) / 1_GeV); + C8LOG_DEBUG( + "Interaction: etarget CoM: {} GeV " + "Interaction: ptarget CoM: {} GeV ", + PtargCoM.GetTimeLikeComponent() / 1_GeV, + PtargCoM.GetSpaceLikeComponents().GetComponents(csPrime) / 1_GeV); + + C8LOG_DEBUG("Interaction: position of interaction: {} ", pOrig.GetCoordinates()); + C8LOG_DEBUG("Interaction: time: {} ", tOrig); + + HEPEnergyType Etot = eProjectileLab + eTargetLab; + MomentumVector Ptot = projectile.GetMomentum(); + // invariant mass, i.e. cm. energy + HEPEnergyType Ecm = sqrt(Etot * Etot - Ptot.squaredNorm()); + + // sample target mass number + auto const* currentNode = projectile.GetNode(); + auto const& mediumComposition = + currentNode->GetModelProperties().GetNuclearComposition(); + // get cross sections for target materials + /* + Here we read the cross section from the interaction model again, + should be passed from GetInteractionLength if possible + */ + //#warning reading interaction cross section again, should not be necessary + auto const& compVec = mediumComposition.GetComponents(); + std::vector<CrossSectionType> cross_section_of_components(compVec.size()); + + for (size_t i = 0; i < compVec.size(); ++i) { + auto const targetId = compVec[i]; + const auto [sigProd, sigEla] = GetCrossSection(corsikaBeamId, targetId, Ecm); + [[maybe_unused]] const auto& dummy_sigEla = sigEla; + cross_section_of_components[i] = sigProd; + } + + const auto targetCode = + mediumComposition.SampleTarget(cross_section_of_components, RNG_); + C8LOG_DEBUG("Interaction: target selected: {} ", targetCode); + /* + FOR NOW: allow nuclei with A<18 or protons only. + when medium composition becomes more complex, approximations will have to be + allowed air in atmosphere also contains some Argon. + */ + int targetSibCode = -1; + if (IsNucleus(targetCode)) targetSibCode = GetNucleusA(targetCode); + if (targetCode == particles::Proton::GetCode()) targetSibCode = 1; + C8LOG_DEBUG("Interaction: sibyll code: {}", targetSibCode); + if (targetSibCode > maxTargetMassNumber_ || targetSibCode < 1) + throw std::runtime_error( + "Sibyll target outside range. Only nuclei with A<18 or protons are " + "allowed."); - // beam id for sibyll - const int kBeam = process::sibyll::ConvertToSibyllRaw(corsikaBeamId); + // beam id for sibyll + const int kBeam = process::sibyll::ConvertToSibyllRaw(corsikaBeamId); + C8LOG_DEBUG( + "Interaction: " + " DoInteraction: E(GeV): {} " + " Ecm(GeV): {} ", + eProjectileLab / 1_GeV, Ecm / 1_GeV); + if (Ecm > GetMaxEnergyCoM()) + throw std::runtime_error("Interaction::DoInteraction: CoM energy too high!"); + // FR: removed eProjectileLab < 8.5_GeV || + if (Ecm < GetMinEnergyCoM()) { C8LOG_DEBUG( - fmt::format("Interaction: " - " DoInteraction: E(GeV): {} " - " Ecm(GeV): {} ", - eProjectileLab / 1_GeV, Ecm / 1_GeV)); - if (Ecm > GetMaxEnergyCoM()) - throw std::runtime_error("Interaction::DoInteraction: CoM energy too high!"); - // FR: removed eProjectileLab < 8.5_GeV || - if (Ecm < GetMinEnergyCoM()) { - C8LOG_DEBUG( - fmt::format("Interaction: " - " DoInteraction: should have dropped particle.. " - "THIS IS AN ERROR")); - throw std::runtime_error("energy too low for SIBYLL"); - } else { - count_++; - // Sibyll does not know about units.. - const double sqs = Ecm / 1_GeV; - // running sibyll, filling stack - sibyll_(kBeam, targetSibCode, sqs); + "Interaction: " + " DoInteraction: should have dropped particle.. " + "THIS IS AN ERROR"); + throw std::runtime_error("energy too low for SIBYLL"); + } else { + count_++; + // Sibyll does not know about units.. + const double sqs = Ecm / 1_GeV; + // running sibyll, filling stack + sibyll_(kBeam, targetSibCode, sqs); + if (sibyll_listing_) { // print final state int print_unit = 6; sib_list_(print_unit); nucCount_ += get_nwounded() - 1; + } - // add particles from sibyll to stack - // link to sibyll stack - SibStack ss; - - MomentumVector Plab_final(originalCS, {0.0_GeV, 0.0_GeV, 0.0_GeV}); - HEPEnergyType Elab_final = 0_GeV, Ecm_final = 0_GeV; - for (auto& psib : ss) { - - // abort on particles that have decayed in Sibyll. Should not happen! - if (psib.HasDecayed()) - throw std::runtime_error("found particle that decayed in SIBYLL!"); - - // transform 4-momentum to lab. frame - // note that the momentum needs to be rotated back - auto const tmp = psib.GetMomentum().GetComponents(); - auto const pCoM = Vector<hepmomentum_d>(csPrime, tmp); - HEPEnergyType const eCoM = psib.GetEnergy(); - auto const Plab = boost.fromCoM(FourVector(eCoM, pCoM)); - auto const p3lab = Plab.GetSpaceLikeComponents(); - assert(p3lab.GetCoordinateSystem() == originalCS); // just to be sure! - - // add to corsika stack - auto pnew = view.AddSecondary( - make_tuple(process::sibyll::ConvertFromSibyll(psib.GetPID()), - Plab.GetTimeLikeComponent(), p3lab, pOrig, tOrig)); - - Plab_final += pnew.GetMomentum(); - Elab_final += pnew.GetEnergy(); - Ecm_final += psib.GetEnergy(); - } - C8LOG_DEBUG(fmt::format( - "conservation (all GeV):" - "Ecm_initial(per nucleon)={}, Ecm_final(per nucleon)={}, " - "Elab_initial={}, Elab_final={}, " - "diff (%)={}, " - "E in nucleons={}, " - "Plab_initial={}, " - "Plab_final={} ", - Ecm / 1_GeV, Ecm_final * 2. / (get_nwounded() + 1) / 1_GeV, Etot / 1_GeV, - Elab_final / 1_GeV, (Elab_final / Etot / get_nwounded() - 1) * 100, - constants::nucleonMass * get_nwounded() / 1_GeV, - (pProjectileLab / 1_GeV).GetComponents(), - (Plab_final / 1_GeV).GetComponents())); + // add particles from sibyll to stack + // link to sibyll stack + SibStack ss; + + MomentumVector Plab_final(originalCS, {0.0_GeV, 0.0_GeV, 0.0_GeV}); + HEPEnergyType Elab_final = 0_GeV, Ecm_final = 0_GeV; + for (auto& psib : ss) { + + // abort on particles that have decayed in Sibyll. Should not happen! + if (psib.HasDecayed()) + throw std::runtime_error("found particle that decayed in SIBYLL!"); + + // transform 4-momentum to lab. frame + // note that the momentum needs to be rotated back + auto const tmp = psib.GetMomentum().GetComponents(); + auto const pCoM = Vector<hepmomentum_d>(csPrime, tmp); + HEPEnergyType const eCoM = psib.GetEnergy(); + auto const Plab = boost.fromCoM(FourVector(eCoM, pCoM)); + auto const p3lab = Plab.GetSpaceLikeComponents(); + assert(p3lab.GetCoordinateSystem() == originalCS); // just to be sure! + + // add to corsika stack + auto pnew = view.AddSecondary( + make_tuple(process::sibyll::ConvertFromSibyll(psib.GetPID()), + Plab.GetTimeLikeComponent(), p3lab, pOrig, tOrig)); + + Plab_final += pnew.GetMomentum(); + Elab_final += pnew.GetEnergy(); + Ecm_final += psib.GetEnergy(); } + C8LOG_DEBUG( + "conservation (all GeV):" + "Ecm_initial(per nucleon)={}, Ecm_final(per nucleon)={}, " + "Elab_initial={}, Elab_final={}, " + "diff (%)={}, " + "E in nucleons={}, " + "Plab_initial={}, " + "Plab_final={} ", + Ecm / 1_GeV, Ecm_final * 2. / (get_nwounded() + 1) / 1_GeV, Etot / 1_GeV, + Elab_final / 1_GeV, (Elab_final / Etot / get_nwounded() - 1) * 100, + constants::nucleonMass * get_nwounded() / 1_GeV, + (pProjectileLab / 1_GeV).GetComponents(), (Plab_final / 1_GeV).GetComponents()); } return process::EProcessReturn::eOk; } diff --git a/Processes/Sibyll/Interaction.h b/Processes/Sibyll/Interaction.h index cccc971bd36517f955f23da88d6b7a588fd4341d..52a43309d06efe3f0fbc622b84dc29a82c9d7328 100644 --- a/Processes/Sibyll/Interaction.h +++ b/Processes/Sibyll/Interaction.h @@ -21,9 +21,10 @@ namespace corsika::process::sibyll { int count_ = 0; int nucCount_ = 0; static bool initialized_; ///! flag to assure init is done only once + bool sibyll_listing_; public: - Interaction(); + Interaction(const bool sibyll_printout_on = false); ~Interaction(); void SetAllStable(); @@ -45,7 +46,7 @@ namespace corsika::process::sibyll { const corsika::units::si::HEPEnergyType) const; template <typename TParticle> - corsika::units::si::GrammageType GetInteractionLength(TParticle const&) const; + corsika::units::si::GrammageType GetInteractionLength(const TParticle&) const; /** In this function SIBYLL is called to produce one event. The diff --git a/Processes/Sibyll/NuclearInteraction.cc b/Processes/Sibyll/NuclearInteraction.cc index c53beeae7a6934dd090af9ea5302deacf342b681..de77d5d33a32b1cb4461abb88552ee14bea415a0 100644 --- a/Processes/Sibyll/NuclearInteraction.cc +++ b/Processes/Sibyll/NuclearInteraction.cc @@ -235,7 +235,7 @@ namespace corsika::process::sibyll { pTotLab += pTarget; auto const pTotLabNorm = pTotLab.norm(); // calculate cm. energy - const HEPEnergyType ECoM = sqrt( + [[maybe_unused]] const HEPEnergyType ECoM = sqrt( (Elab + pTotLabNorm) * (Elab - pTotLabNorm)); // binomial for numerical accuracy auto const ECoMNN = sqrt(2. * ElabNuc * constants::nucleonMass); C8LOG_DEBUG( @@ -406,10 +406,10 @@ namespace corsika::process::sibyll { // define boost to NUCLEON-NUCLEON frame COMBoost const boost(PprojNucLab, constants::nucleonMass); // boost projecticle - auto const PprojNucCoM = boost.toCoM(PprojNucLab); + [[maybe_unused]] auto const PprojNucCoM = boost.toCoM(PprojNucLab); // boost target - auto const PtargNucCoM = boost.toCoM(PtargNucLab); + [[maybe_unused]] auto const PtargNucCoM = boost.toCoM(PtargNucLab); C8LOG_DEBUG( fmt::format("Interaction: ebeam CoM: {} " diff --git a/Processes/StackInspector/StackInspector.cc b/Processes/StackInspector/StackInspector.cc index da4a91baafaf6253137956d57297cf198ba238c4..6bd1bceb3c912abbaf971ba18039504a6422c0b0 100644 --- a/Processes/StackInspector/StackInspector.cc +++ b/Processes/StackInspector/StackInspector.cc @@ -40,7 +40,7 @@ template <typename TStack> StackInspector<TStack>::~StackInspector() {} template <typename TStack> -process::EProcessReturn StackInspector<TStack>::DoStack(const TStack& vS) { +void StackInspector<TStack>::DoStack(const TStack& vS) { [[maybe_unused]] int i = 0; HEPEnergyType Etot = 0_GeV; @@ -63,7 +63,7 @@ process::EProcessReturn StackInspector<TStack>::DoStack(const TStack& vS) { const std::chrono::duration<double> elapsed_seconds = now - StartTime_; std::time_t const now_time = std::chrono::system_clock::to_time_t(now); auto const dE = E0_ - Etot; - if (dE < dE_threshold_) return process::EProcessReturn::eOk; + if (dE < dE_threshold_) return; double const progress = dE / E0_; double const eta_seconds = elapsed_seconds.count() / progress; @@ -77,7 +77,7 @@ process::EProcessReturn StackInspector<TStack>::DoStack(const TStack& vS) { << ", nStep=" << GetStep() << ", stackEntries=" << vS.getEntries() << ", Estack=" << Etot / 1_GeV << " GeV" << ", ETA=" << std::put_time(std::localtime(&eta_time), "%T") << endl; - return process::EProcessReturn::eOk; + return; } #include <corsika/cascade/testCascade.h> diff --git a/Processes/StackInspector/StackInspector.h b/Processes/StackInspector/StackInspector.h index 280ff15e6b97117d9936996a1953490063d688d2..6d99a4164844c4fae10fb0e29b15afc15a67d8aa 100644 --- a/Processes/StackInspector/StackInspector.h +++ b/Processes/StackInspector/StackInspector.h @@ -30,7 +30,7 @@ namespace corsika::process { const corsika::units::si::HEPEnergyType vE0); ~StackInspector(); - EProcessReturn DoStack(const TStack&); + void DoStack(const TStack&); /** * To set a new E0, for example when a new shower event is started diff --git a/Processes/StackInspector/testStackInspector.cc b/Processes/StackInspector/testStackInspector.cc index 89edc2a44e8f56f2d9022f2d0ecb688a7e41881f..d76d9fd09b0bd57b37f81daa3f57106eea151910 100644 --- a/Processes/StackInspector/testStackInspector.cc +++ b/Processes/StackInspector/testStackInspector.cc @@ -46,7 +46,6 @@ TEST_CASE("StackInspector", "[processes]") { SECTION("interface") { StackInspector<TestCascadeStack> model(1, true, E0); - - [[maybe_unused]] const process::EProcessReturn ret = model.DoStack(stack); + model.DoStack(stack); } } diff --git a/Processes/TrackingLine/CMakeLists.txt b/Processes/TrackingLine/CMakeLists.txt index 8411487ff9df4088ea26b7754f1fcd0c5fd0867f..dd626f8778c5a4139fe042fc651bb5e20eb315fe 100644 --- a/Processes/TrackingLine/CMakeLists.txt +++ b/Processes/TrackingLine/CMakeLists.txt @@ -21,7 +21,6 @@ set_target_properties ( PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION 1 -# PUBLIC_HEADER "${MODEL_HEADERS}" ) # target dependencies on other libraries (also the header onlys) @@ -33,6 +32,7 @@ target_link_libraries ( CORSIKAunits CORSIKAenvironment CORSIKAgeometry + CORSIKAlogging ) target_include_directories ( diff --git a/Processes/TrackingLine/TrackingLine.cc b/Processes/TrackingLine/TrackingLine.cc index ee76db62c7db07a0988a462367808530f6c636df..23efd27760e873d6cfd9ba564008bd78a95012af 100644 --- a/Processes/TrackingLine/TrackingLine.cc +++ b/Processes/TrackingLine/TrackingLine.cc @@ -12,6 +12,7 @@ #include <corsika/geometry/Sphere.h> #include <corsika/geometry/Vector.h> #include <corsika/process/tracking_line/TrackingLine.h> +#include <corsika/logging/Logging.h> #include <limits> #include <stdexcept> diff --git a/Processes/TrackingLine/TrackingLine.h b/Processes/TrackingLine/TrackingLine.h index 48bdc3a45da5d1fafcbc3ae144b7916ebd601797..5e20d920c7e0f875618b06943c244ec0e23d329f 100644 --- a/Processes/TrackingLine/TrackingLine.h +++ b/Processes/TrackingLine/TrackingLine.h @@ -14,6 +14,8 @@ #include <corsika/geometry/Trajectory.h> #include <corsika/geometry/Vector.h> #include <corsika/units/PhysicalUnits.h> +#include <corsika/logging/Logging.h> + #include <optional> #include <type_traits> #include <utility> @@ -38,7 +40,7 @@ namespace corsika::process { class TrackingLine { public: - TrackingLine(){}; + TrackingLine() = default; template <typename Particle> // was Stack previously, and argument was // Stack::StackIterator @@ -49,27 +51,22 @@ namespace corsika::process { p.GetMomentum() / p.GetEnergy() * corsika::units::constants::c; auto const currentPosition = p.GetPosition(); - std::cout << "TrackingLine pid: " << p.GetPID() - << " , E = " << p.GetEnergy() / 1_GeV << " GeV" << std::endl; - std::cout << "TrackingLine pos: " - << currentPosition.GetCoordinates() - // << " [" << p.GetNode()->GetModelProperties().GetName() << "]" - << std::endl; - std::cout << "TrackingLine E: " << p.GetEnergy() / 1_GeV << " GeV" << std::endl; - std::cout << "TrackingLine p: " << p.GetMomentum().GetComponents() / 1_GeV - << " GeV " << std::endl; - std::cout << "TrackingLine v: " << velocity.GetComponents() << std::endl; + C8LOG_DEBUG( + "TrackingLine pid: {}" + " , E = {} GeV", + p.GetPID(), p.GetEnergy() / 1_GeV); + C8LOG_DEBUG("TrackingLine pos: {}", currentPosition.GetCoordinates()); + C8LOG_DEBUG("TrackingLine E: {} GeV", p.GetEnergy() / 1_GeV); + C8LOG_DEBUG("TrackingLine p: {} GeV", p.GetMomentum().GetComponents() / 1_GeV); + C8LOG_DEBUG("TrackingLine v: {} ", velocity.GetComponents()); // to do: include effect of magnetic field geometry::Line line(currentPosition, velocity); auto const* currentLogicalVolumeNode = p.GetNode(); - //~ auto const* currentNumericalVolumeNode = - //~ fEnvironment.GetUniverse()->GetContainingNode(currentPosition); - auto const numericallyInside = - currentLogicalVolumeNode->GetVolume().Contains(currentPosition); - std::cout << "numericallyInside = " << (numericallyInside ? "true" : "false"); + C8LOG_DEBUG("numericallyInside = {} ", + currentLogicalVolumeNode->GetVolume().Contains(currentPosition)); auto const& children = currentLogicalVolumeNode->GetChildNodes(); auto const& excluded = currentLogicalVolumeNode->GetExcludedNodes(); @@ -85,14 +82,11 @@ namespace corsika::process { if (auto opt = TimeOfIntersection(line, sphere); opt.has_value()) { auto const [t1, t2] = *opt; - std::cout << "intersection times: " << t1 / 1_s << "; " - << t2 / 1_s - // << " " << vtn.GetModelProperties().GetName() - << std::endl; + C8LOG_DEBUG("intersection times: {} s; {} s", t1 / 1_s, t2 / 1_s); if (t1.magnitude() > 0) intersections.emplace_back(t1, &vtn); else if (t2.magnitude() > 0) - std::cout << "inside other volume" << std::endl; + C8LOG_DEBUG("inside other volume"); } }; @@ -123,10 +117,7 @@ namespace corsika::process { min = minIter->first; } - std::cout << " t-intersect: " - << min - // << " " << minIter->second->GetModelProperties().GetName() - << std::endl; + C8LOG_DEBUG(" t-intersect: {} ", min); return std::make_tuple(geometry::Trajectory<geometry::Line>(line, min), velocity.norm() * min, minIter->second); diff --git a/Processes/UrQMD/UrQMD.cc b/Processes/UrQMD/UrQMD.cc index 26814293241bfb877794687e7b6cf27790c947bb..9d78d20ae7f209cdc62d0c368ee336a70dabd49a 100644 --- a/Processes/UrQMD/UrQMD.cc +++ b/Processes/UrQMD/UrQMD.cc @@ -19,7 +19,6 @@ #include <cmath> #include <fstream> #include <functional> -#include <iostream> #include <random> #include <sstream> @@ -40,10 +39,6 @@ CrossSectionType UrQMD::GetTabulatedCrossSection(particles::Code projectileCode, HEPEnergyType labEnergy) const { // translated to C++ from CORSIKA 7 subroutine cxtot_u - C8LOG_DEBUG("UrQMD::GetTabulatedCrossSection proj={}, targ={}, E={}GeV", - particles::GetName(projectileCode), particles::GetName(targetCode), - labEnergy / 1_GeV); - auto const kinEnergy = labEnergy - particles::GetMass(projectileCode); assert(kinEnergy >= HEPEnergyType::zero()); @@ -91,10 +86,10 @@ CrossSectionType UrQMD::GetTabulatedCrossSection(particles::Code projectileCode, case particles::Code::K0Bar: projectileIndex = 8; break; - default: - std::cout << "WARNING: UrQMD cross-section not tabulated for " << projectileCode - << std::endl; + default: { + C8LOG_WARN("WARNING: UrQMD cross-section not tabulated for {}", projectileCode); return CrossSectionType::zero(); + } } int targetIndex; @@ -120,6 +115,10 @@ CrossSectionType UrQMD::GetTabulatedCrossSection(particles::Code projectileCode, xs_interp_support_table_[projectileIndex][targetIndex][je + i - 1 - 1] * w[i]; } + C8LOG_DEBUG("UrQMD::GetTabulatedCrossSection proj={}, targ={}, E={}GeV, sigma={}", + particles::GetName(projectileCode), particles::GetName(targetCode), + labEnergy / 1_GeV, result); + return result; } @@ -256,6 +255,9 @@ corsika::process::EProcessReturn UrQMD::DoInteraction(SetupView& view) { auto const& projectilePosition = projectile.GetPosition(); auto const projectileTime = projectile.GetTime(); + C8LOG_DEBUG("UrQMD::DoInteraction pid={} E={} GeV", projectileCode, + projectileEnergyLab / 1_GeV); + // sample target particle auto const& mediumComposition = projectile.GetNode()->GetModelProperties().GetNuclearComposition(); @@ -348,14 +350,14 @@ corsika::process::EProcessReturn UrQMD::DoInteraction(SetupView& view) { auto const energy = sqrt(momentum.squaredNorm() + square(particles::GetMass(code))); momentum.rebase(originalCS); // transform back into standard lab frame - std::cout << i << " " << code << " " << momentum.GetComponents() << std::endl; + C8LOG_DEBUG(" Secondary {} code {} p={} GeV", i, code, + momentum.GetComponents() / 1_GeV); view.AddSecondary( - std::tuple<particles::Code, HEPEnergyType, stack::MomentumVector, geometry::Point, - TimeType>{code, energy, momentum, projectilePosition, projectileTime}); + std::make_tuple(code, energy, momentum, projectilePosition, projectileTime)); } - std::cout << "UrQMD generated " << sys_.npart << " secondaries!" << std::endl; + C8LOG_DEBUG("UrQMD generated {} secondaries!", sys_.npart); return process::EProcessReturn::eOk; } diff --git a/Stack/NuclearStackExtension/NuclearStackExtension.h b/Stack/NuclearStackExtension/NuclearStackExtension.h index 4409a215eed0c331e922b311235f37e10ded24d8..c2ac33e2e0f25079dbd535ed52360bbb0c1e6244 100644 --- a/Stack/NuclearStackExtension/NuclearStackExtension.h +++ b/Stack/NuclearStackExtension/NuclearStackExtension.h @@ -190,7 +190,9 @@ namespace corsika::stack { return InnerParticleInterface<StackIteratorInterface>::GetChargeNumber(); } - int GetNucleusRef() const { return GetStackData().GetNucleusRef(GetIndex()); } + int GetNucleusRef() const { + return GetStackData().GetNucleusRef(GetIndex()); + } // LCOV_EXCL_LINE protected: void SetNucleusRef(const int vR) { GetStackData().SetNucleusRef(GetIndex(), vR); } diff --git a/Stack/NuclearStackExtension/testNuclearStackExtension.cc b/Stack/NuclearStackExtension/testNuclearStackExtension.cc index 6896953a6079ba0c66b4ba630cf96a2c78a3bd48..72017c91a05c70d9c062fd72c20f0ff31cc4e246 100644 --- a/Stack/NuclearStackExtension/testNuclearStackExtension.cc +++ b/Stack/NuclearStackExtension/testNuclearStackExtension.cc @@ -119,6 +119,7 @@ TEST_CASE("NuclearStackExtension", "[stack]") { ParticleDataStack s; // add 99 particles, each 10th particle is a nucleus with A=i and Z=A/2! + // i=9, 19, 29, etc. are nuclei for (int i = 0; i < 99; ++i) { if ((i + 1) % 10 == 0) { s.AddParticle(std::make_tuple( @@ -167,6 +168,21 @@ TEST_CASE("NuclearStackExtension", "[stack]") { CHECK(p93.GetTime() == 100_s); } + // copy + { + s.Copy(s.begin() + 89, s.begin() + 79); // nuclei to nuclei + const auto& p89 = s.cbegin() + 89; + const auto& p79 = s.cbegin() + 79; + + CHECK(p89.GetPID() == particles::Code::Nucleus); + CHECK(p89.GetEnergy() == 89 * 15_GeV); + CHECK(p89.GetTime() == 100_s); + + CHECK(p79.GetPID() == particles::Code::Nucleus); + CHECK(p79.GetEnergy() == 89 * 15_GeV); + CHECK(p79.GetTime() == 100_s); + } + // swap { s.Swap(s.begin() + 11, s.begin() + 10); @@ -206,4 +222,37 @@ TEST_CASE("NuclearStackExtension", "[stack]") { for (int i = 0; i < 99; ++i) s.last().Delete(); CHECK(s.getEntries() == 0); } + + SECTION("not allowed") { + NuclearStackExtension<corsika::stack::super_stupid::SuperStupidStack, + ExtendedParticleInterfaceType> + s; + + // not valid: + CHECK_THROWS(s.AddParticle(std::make_tuple( + particles::Code::Oxygen, 1.5_GeV, + corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), + Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, 16, 8))); + + // valid + auto particle = s.AddParticle( + std::make_tuple(particles::Code::Nucleus, 1.5_GeV, + corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), + Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, 10, 9)); + + // not valid + CHECK_THROWS(particle.AddSecondary(std::make_tuple( + particles::Code::Oxygen, 1.5_GeV, + corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), + Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, 16, 8))); + + // add a another nucleus, so there are two now + s.AddParticle( + std::make_tuple(particles::Code::Nucleus, 1.5_GeV, + corsika::stack::MomentumVector(dummyCS, {1_GeV, 1_GeV, 1_GeV}), + Point(dummyCS, {1 * meter, 1 * meter, 1 * meter}), 100_s, 10, 9)); + + // not valid, since end() is not a valid entry + CHECK_THROWS(s.Swap(s.begin(), s.end())); + } }