diff --git a/Documentation/Examples/CMakeLists.txt b/Documentation/Examples/CMakeLists.txt index 3cce0678741508b8de9453dd482e7626cd1cd7f9..13848d99808f1e9ec83f7727674e76ae82b4c2f6 100644 --- a/Documentation/Examples/CMakeLists.txt +++ b/Documentation/Examples/CMakeLists.txt @@ -87,7 +87,8 @@ if (Pythia8_FOUND) install (TARGETS cascade_proton_example DESTINATION share/examples) endif() -CORSIKA_ADD_TEST(vertical_EAS) +#CORSIKA_ADD_TEST(vertical_EAS) +add_executable(vertical_EAS vertical_EAS.cc) target_link_libraries (vertical_EAS SuperStupidStack CORSIKAunits @@ -104,6 +105,7 @@ target_link_libraries (vertical_EAS ProcessTrackingLine ProcessParticleCut ProcessStackInspector + ProcessInteractionCounter CORSIKAprocesses CORSIKAcascade CORSIKAparticles diff --git a/Documentation/Examples/vertical_EAS.cc b/Documentation/Examples/vertical_EAS.cc index 8dd6f827df46e28c98c2354c2e122734250d87e1..ae48ca770681eeba48e7f6626e0e4a7dd7afbfa5 100644 --- a/Documentation/Examples/vertical_EAS.cc +++ b/Documentation/Examples/vertical_EAS.cc @@ -12,6 +12,7 @@ #include <corsika/process/ProcessSequence.h> #include <corsika/process/StackProcess.h> #include <corsika/process/energy_loss/EnergyLoss.h> +#include <corsika/process/interaction_counter/InteractionCounter.h> #include <corsika/process/observation_plane/ObservationPlane.h> #include <corsika/process/particle_cut/ParticleCut.h> #include <corsika/process/switch_process/SwitchProcess.h> @@ -48,6 +49,7 @@ #include <iomanip> #include <iostream> #include <limits> +#include <string> #include <typeinfo> using namespace corsika; @@ -64,6 +66,7 @@ using namespace corsika::units::si; void registerRandomStreams() { random::RNGManager::GetInstance().RegisterRandomStream("cascade"); + random::RNGManager::GetInstance().RegisterRandomStream("qgran"); random::RNGManager::GetInstance().RegisterRandomStream("s_rndm"); random::RNGManager::GetInstance().RegisterRandomStream("pythia"); random::RNGManager::GetInstance().RegisterRandomStream("UrQMD"); @@ -71,7 +74,11 @@ void registerRandomStreams() { random::RNGManager::GetInstance().SeedAll(); } -int main() { +int main(int argc, char** argv) { + if (argc != 4) { + std::cerr << "must provide A, Z, energy" << std::endl; + return 1; + } feenableexcept(FE_INVALID); // initialize random number sequence(s) registerRandomStreams(); @@ -97,15 +104,17 @@ int main() { // setup particle stack, and add primary particle setup::Stack stack; stack.Clear(); - const Code beamCode = Code::Proton; - auto const mass = particles::GetMass(beamCode); - const HEPEnergyType E0 = 0.1_PeV; + const Code beamCode = Code::Nucleus; + unsigned short const A = std::stoi(std::string(argv[1])); + unsigned short Z = std::stoi(std::string(argv[2])); + auto const mass = particles::GetNucleusMass(A, Z); + const HEPEnergyType E0 = 1_GeV * std::stof(std::string(argv[3])); double theta = 0.; double phi = 0.; Point const injectionPos( rootCS, 0_m, 0_m, - 112.8_km * 0.999 + + 112.7_km + builder.earthRadius); // this is the CORSIKA 7 start of atmosphere/universe // { @@ -124,23 +133,33 @@ int main() { cout << "input angles: theta=" << theta << " phi=" << phi << endl; cout << "input momentum: " << plab.GetComponents() / 1_GeV << endl; - stack.AddParticle( - std::tuple<particles::Code, units::si::HEPEnergyType, - corsika::stack::MomentumVector, geometry::Point, units::si::TimeType>{ - beamCode, E0, plab, injectionPos, 0_ns}); - // } + 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}); + + } 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}); + } Line const line(injectionPos, plab.normalized() * 1_m * 1_Hz); auto const velocity = line.GetV0().norm(); - auto const observationHeight = 1.425_km + builder.earthRadius; + auto const observationHeight = 1.4_km + builder.earthRadius; - setup::Trajectory const showerAxis(line, (112.8_km - observationHeight) / velocity); + setup::Trajectory const showerAxis(line, (112.7_km - observationHeight) / velocity); // setup processes, decays and interactions process::sibyll::Interaction sibyll; + process::interaction_counter::InteractionCounter sibyllCounted(sibyll); + process::sibyll::NuclearInteraction sibyllNuc(sibyll, env); + process::interaction_counter::InteractionCounter sibyllNucCounted(sibyllNuc); process::pythia::Decay decayPythia; @@ -166,30 +185,31 @@ int main() { }); decaySibyll.PrintDecayConfig(); - process::particle_cut::ParticleCut cut(5_GeV); + process::particle_cut::ParticleCut cut(100_GeV); - process::track_writer::TrackWriter trackWriter("tracks.dat"); + // process::track_writer::TrackWriter trackWriter("tracks.dat"); process::energy_loss::EnergyLoss eLoss(showerAxis); Plane const obsPlane(Point(rootCS, 0_m, 0_m, observationHeight), Vector<dimensionless_d>(rootCS, {0., 0., 1.})); - process::observation_plane::ObservationPlane observationLevel(obsPlane, - "particles.dat"); + process::observation_plane::ObservationPlane observationLevel(obsPlane, "/dev/null"); // assemble all processes into an ordered process list process::UrQMD::UrQMD urqmd; - auto sibyllSequence = sibyll << sibyllNuc; + auto sibyllSequence = sibyllNucCounted << sibyllCounted; process::switch_process::SwitchProcess switchProcess(urqmd, sibyllSequence, 55_GeV); auto decaySequence = decayPythia << decaySibyll; - auto sequence = switchProcess << decaySequence << eLoss << cut << observationLevel - << trackWriter; + auto sequence = switchProcess << decaySequence << eLoss << cut << observationLevel; + // << trackWriter; // define air shower object, run simulation tracking_line::TrackingLine tracking; cascade::Cascade EAS(env, tracking, sequence, stack); EAS.Init(); +// EAS.SetNodes(); +// EAS.forceInteraction(); EAS.Run(); eLoss.PrintProfile(); // print longitudinal profile @@ -201,6 +221,13 @@ int main() { << "relative difference (%): " << (Efinal / E0 - 1) * 100 << endl; cout << "total dEdX energy (GeV): " << eLoss.GetTotal() / 1_GeV << endl << "relative difference (%): " << eLoss.GetTotal() / E0 * 100 << endl; + + auto const cms_hists = *std::get<0>(sibyllCounted.CMSHists()) + *std::get<0>(sibyllNucCounted.CMSHists()); + auto const lab_hists = *std::get<0>(sibyllCounted.labHists()) + *std::get<0>(sibyllNucCounted.labHists()); + + process::interaction_counter::saveHist(cms_hists, *std::get<1>(sibyllNucCounted.CMSHists()), "intcount_hist_cms.txt", "center-of-mass system"); + process::interaction_counter::saveHist(lab_hists, *std::get<1>(sibyllNucCounted.labHists()), "intcount_hist_lab.txt", "lab system"); + std::ofstream finish("finished"); finish << "run completed without error" << std::endl; diff --git a/Processes/CMakeLists.txt b/Processes/CMakeLists.txt index 9ca109dee4bbef7442de84944047730ffa0ba98c..6e93793eceed7a20cdaf7363dd585cc93b1afbac 100644 --- a/Processes/CMakeLists.txt +++ b/Processes/CMakeLists.txt @@ -10,7 +10,6 @@ if (PYTHIA8_FOUND) endif (PYTHIA8_FOUND) add_subdirectory (HadronicElasticModel) add_subdirectory (UrQMD) -add_subdirectory (SwitchProcess) # continuous physics add_subdirectory (EnergyLoss) @@ -22,6 +21,10 @@ add_subdirectory (StackInspector) # cuts, thinning, etc. add_subdirectory (ParticleCut) +# meta-processes +add_subdirectory (InteractionCounter) +add_subdirectory (SwitchProcess) + ########################################## # add_custom_target(CORSIKAprocesses) add_library (CORSIKAprocesses INTERFACE) diff --git a/Processes/InteractionCounter/CMakeLists.txt b/Processes/InteractionCounter/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..4ce877826cc206270220754cad4bcb206bd3fe97 --- /dev/null +++ b/Processes/InteractionCounter/CMakeLists.txt @@ -0,0 +1,43 @@ +set ( + MODEL_HEADERS + InteractionCounter.h + ) + +set ( + MODEL_NAMESPACE + corsika/process/interaction_counter + ) + +FIND_PACKAGE( Boost 1.70 REQUIRED ) + +add_library (ProcessInteractionCounter INTERFACE) +CORSIKA_COPY_HEADERS_TO_NAMESPACE (ProcessInteractionCounter ${MODEL_NAMESPACE} ${MODEL_HEADERS}) + +# target dependencies on other libraries (also the header onlys) +target_link_libraries ( + ProcessInteractionCounter + INTERFACE + CORSIKAunits + CORSIKAprocesssequence + ) + +target_include_directories ( + ProcessInteractionCounter + INTERFACE + $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include> + $<INSTALL_INTERFACE:include/include> + ${Boost_INCLUDE_DIR} + ) + +install (FILES ${MODEL_HEADERS} DESTINATION include/${MODEL_NAMESPACE}) + +# -------------------- +# code unit testing +#~ CORSIKA_ADD_TEST(testLuminosityCounter) +#~ target_link_libraries ( + #~ testLuminosityCounter + #~ ProcessLuminosityCounter + #~ CORSIKAstackinterface + #~ CORSIKAtesting +#~ ) + diff --git a/Processes/InteractionCounter/InteractionCounter.h b/Processes/InteractionCounter/InteractionCounter.h new file mode 100644 index 0000000000000000000000000000000000000000..7c5de97a8944ea0ec28292471d30a8509048824f --- /dev/null +++ b/Processes/InteractionCounter/InteractionCounter.h @@ -0,0 +1,172 @@ +/* + * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu + * + * See file AUTHORS for a list of contributors. + * + * This software is distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3). See file LICENSE for a full version of + * the license. + */ + +#ifndef _corsika_InteractionCounter_h +#define _corsika_InteractionCounter_h + +#include <corsika/process/InteractionProcess.h> +#include <corsika/process/ProcessSequence.h> +#include <corsika/setup/SetupStack.h> +#include <corsika/units/PhysicalUnits.h> + +#include <boost/histogram.hpp> +#include <boost/histogram/ostream.hpp> +#include <fstream> +#include <functional> +#include <map> +#include <utility> + +namespace corsika::process::interaction_counter { + + template <class TCountedProcess> + class InteractionCounter + : public InteractionProcess<InteractionCounter<TCountedProcess>> { + static auto constexpr lower_edge_cms = 1., upper_edge_cms = 1e8; // GeV sqrt s + static auto constexpr lower_edge_lab = 1., upper_edge_lab = 1e12; // GeV lab + static auto constexpr num_bins_lab = 120, num_bins_cms = 80; + + static auto constexpr numIds = + static_cast<particles::CodeIntType>(particles::Code::LastParticle); + + using hist_type_count_cms = decltype(boost::histogram::make_histogram( + boost::histogram::axis::integer<particles::CodeIntType>(0, numIds), + boost::histogram::axis::regular<double, boost::histogram::axis::transform::log>( + num_bins_cms, lower_edge_cms, upper_edge_cms))); + + using hist_type_count_lab = decltype(boost::histogram::make_histogram( + boost::histogram::axis::integer<particles::CodeIntType>(0, numIds), + boost::histogram::axis::regular<double, boost::histogram::axis::transform::log>( + num_bins_lab, lower_edge_lab, upper_edge_lab))); + + static_assert(std::is_same_v<hist_type_count_cms, hist_type_count_lab>); + + using nucl_hist_type = decltype(boost::histogram::make_histogram( + boost::histogram::axis::regular<double, boost::histogram::axis::transform::log>( + num_bins_lab, lower_edge_lab, upper_edge_lab))); + + TCountedProcess& process_; + hist_type_count_cms interaction_histogram_cms_; + hist_type_count_lab interaction_histogram_lab_; + + std::map<int32_t, nucl_hist_type> nuclIntHistLab, nuclIntHistCMS; + + public: + InteractionCounter(TCountedProcess& process) + : process_(process) + , interaction_histogram_cms_{boost::histogram::make_histogram( + boost::histogram::axis::integer<short>(0, numIds), + boost::histogram::axis::regular<double, + boost::histogram::axis::transform::log>( + num_bins_cms, lower_edge_cms, upper_edge_cms))} + , interaction_histogram_lab_{boost::histogram::make_histogram( + boost::histogram::axis::integer<short>(0, numIds), + boost::histogram::axis::regular<double, + boost::histogram::axis::transform::log>( + num_bins_lab, lower_edge_lab, upper_edge_lab))} {} + + template <typename TProjectile> + auto DoInteraction(TProjectile& projectile) { + using namespace units::si; + auto constexpr massAir = 15.994_GeV * (1.f - 0.7847) + 14.003_GeV * .7847; + auto const sqrtS = sqrt(projectile.GetMass() * projectile.GetMass() + + massAir * massAir + 2 * projectile.GetEnergy() * massAir); + + if (projectile.GetPID() == corsika::particles::Code::Nucleus) { + std::cerr << "NUCLEUS " << projectile.GetEnergy() << " " + << projectile.GetNuclearA() << " " << projectile.GetNuclearZ() + << std::endl; + int const A = projectile.GetNuclearA(); + int const Z = projectile.GetNuclearZ(); + int32_t pdg = 1'000'000'000l + Z * 10'000l + A * 10l; + + if (nuclIntHistCMS.count(pdg) == 0) { + + nuclIntHistLab.emplace( + pdg, + boost::histogram::make_histogram( + boost::histogram::axis::regular<double, + boost::histogram::axis::transform::log>( + num_bins_lab, lower_edge_lab, upper_edge_lab))); + + nuclIntHistCMS.emplace( + pdg, + boost::histogram::make_histogram( + boost::histogram::axis::regular<double, + boost::histogram::axis::transform::log>( + num_bins_cms, lower_edge_cms, upper_edge_cms))); + } + + nuclIntHistLab[pdg](projectile.GetEnergy() / 1_GeV); + nuclIntHistCMS[pdg](sqrtS / 1_GeV); + } else { + interaction_histogram_cms_( + static_cast<corsika::particles::CodeIntType>(projectile.GetPID()), + sqrtS / 1_GeV); + + interaction_histogram_lab_( + static_cast<corsika::particles::CodeIntType>(projectile.GetPID()), + projectile.GetEnergy() / 1_GeV); + } + + return process_.DoInteraction(projectile); + } + + void Init() { process_.Init(); } + + template <typename TParticle> + auto GetInteractionLength(TParticle const& particle) const { + return process_.GetInteractionLength(particle); + } + + auto CMSHists() const { + return std::make_pair(&interaction_histogram_cms_, &nuclIntHistCMS); + } + + auto labHists() const { + return std::make_pair(&interaction_histogram_lab_, &nuclIntHistLab); + } + }; + + template <typename T1, typename T2> + static void saveHist(T1 const& hist, T2 const& histMap, std::string const& filename, + std::string const& comment = "") { + auto const& energy_axis = hist.axis(1); + std::ofstream myfile; + myfile.open(filename); + myfile << "# interaction count histogram (" << comment << ")" << std::endl + << "# " << energy_axis.size() << " bins between " << energy_axis.bin(0).lower() + << " and " << energy_axis.bin(energy_axis.size() - 1).upper() << " GeV" + << std::endl; + + for (particles::CodeIntType p = 0; + p < static_cast<particles::CodeIntType>(particles::Code::LastParticle); ++p) { + + if (auto pdg = static_cast<particles::PDGCodeType>( + particles::GetPDG(static_cast<particles::Code>(p))); + pdg < 1'000'000'000l) { + myfile << "# " << static_cast<particles::Code>(p) << std::endl; + myfile << pdg; + for (int i = 0; i < energy_axis.size(); ++i) { myfile << ' ' << hist.at(p, i); } + myfile << std::endl; + } + } + + myfile << "# nuclei" << std::endl; + for (auto const& [pdg, hist] : histMap) { + auto const num_ebins_nucl = hist.axis(0).size(); + assert(energy_axis.size() == num_ebins_nucl); + + myfile << pdg << " "; + for (int i = 0; i < num_ebins_nucl; ++i) { myfile << ' ' << hist.at(i); } + myfile << std::endl; + } + } +} // namespace corsika::process::interaction_counter +#endif diff --git a/Processes/Sibyll/NuclearInteraction.cc b/Processes/Sibyll/NuclearInteraction.cc index a79fd80c2a5bc751bf247b4a01cc725986f9501f..d557f28662be5ea754074d2ebf3f25828146ca6b 100644 --- a/Processes/Sibyll/NuclearInteraction.cc +++ b/Processes/Sibyll/NuclearInteraction.cc @@ -177,7 +177,7 @@ namespace corsika::process::sibyll { template <> template <> tuple<units::si::CrossSectionType, units::si::CrossSectionType> - NuclearInteraction<SetupEnvironment>::GetCrossSection(Particle& vP, + NuclearInteraction<SetupEnvironment>::GetCrossSection(Particle const& vP, const particles::Code TargetId) { using namespace units::si; if (vP.GetPID() != particles::Code::Nucleus) @@ -216,7 +216,7 @@ namespace corsika::process::sibyll { template <> template <> units::si::GrammageType NuclearInteraction<SetupEnvironment>::GetInteractionLength( - Particle& vP) { + Particle const& vP) { using namespace units; using namespace units::si; diff --git a/Processes/Sibyll/NuclearInteraction.h b/Processes/Sibyll/NuclearInteraction.h index 199901cb8cd3b1061b6b2c2a30ea1f37e77d0e03..1be24afccb741d5f4c4d96dc59c1be9105c87507 100644 --- a/Processes/Sibyll/NuclearInteraction.h +++ b/Processes/Sibyll/NuclearInteraction.h @@ -50,10 +50,10 @@ namespace corsika::process::sibyll { template <typename Particle> std::tuple<corsika::units::si::CrossSectionType, corsika::units::si::CrossSectionType> - GetCrossSection(Particle& p, const corsika::particles::Code TargetId); + GetCrossSection(Particle const& p, const corsika::particles::Code TargetId); template <typename Particle> - corsika::units::si::GrammageType GetInteractionLength(Particle&); + corsika::units::si::GrammageType GetInteractionLength(Particle const&); template <typename Projectile> corsika::process::EProcessReturn DoInteraction(Projectile&);