diff --git a/Documentation/Examples/CMakeLists.txt b/Documentation/Examples/CMakeLists.txt index 03eacd0a0206365680151f67d1131d7362e3d31c..8294036d1f03876fbf462c22f1286d190771ae22 100644 --- a/Documentation/Examples/CMakeLists.txt +++ b/Documentation/Examples/CMakeLists.txt @@ -43,6 +43,27 @@ target_link_libraries (cascade_example SuperStupidStack CORSIKAunits install (TARGETS cascade_example DESTINATION share/examples) CORSIKA_ADD_TEST (cascade_example) +add_executable (cascade_proton_example cascade_proton_example.cc) +target_compile_options(cascade_proton_example PRIVATE -g) # do not skip asserts +target_link_libraries (cascade_proton_example SuperStupidStack CORSIKAunits + CORSIKAlogging + CORSIKArandom + ProcessSibyll + ProcessPythia + CORSIKAcascade + ProcessStackInspector + ProcessTrackWriter + ProcessTrackingLine + ProcessHadronicElasticModel + CORSIKAprocesses + CORSIKAparticles + CORSIKAgeometry + CORSIKAenvironment + CORSIKAprocesssequence + ) +install (TARGETS cascade_proton_example DESTINATION share/examples) +CORSIKA_ADD_TEST (cascade_proton_example) + add_executable (staticsequence_example staticsequence_example.cc) target_compile_options(staticsequence_example PRIVATE -g) # do not skip asserts target_link_libraries (staticsequence_example diff --git a/Documentation/Examples/cascade_example.cc b/Documentation/Examples/cascade_example.cc index 62e2347f4f3f096f7314cd9087ffcef6ff0fdf40..97929b681d68c54e82f920a02e001c088d932ffa 100644 --- a/Documentation/Examples/cascade_example.cc +++ b/Documentation/Examples/cascade_example.cc @@ -241,9 +241,8 @@ int main() { theMedium->SetModelProperties<MyHomogeneousModel>( 1_kg / (1_m * 1_m * 1_m), environment::NuclearComposition( - std::vector<particles::Code>{particles::Code::Nitrogen, - particles::Code::Oxygen}, - std::vector<float>{(float)1. - fox, fox})); + std::vector<particles::Code>{particles::Code::Nitrogen, particles::Code::Oxygen}, + std::vector<float>{(float)1.-fox, fox})); universe.AddChild(std::move(theMedium)); @@ -259,11 +258,11 @@ int main() { random::RNGManager::GetInstance().RegisterRandomStream("s_rndm"); + random::RNGManager::GetInstance().RegisterRandomStream("pythia"); process::sibyll::Interaction sibyll(env); process::sibyll::NuclearInteraction sibyllNuc(env, sibyll); - process::sibyll::Decay decay(trackedHadrons); - //random::RNGManager::GetInstance().RegisterRandomStream("pythia"); - //process::pythia::Decay decay(trackedHadrons); + // process::sibyll::Decay decay(trackedHadrons); + process::pythia::Decay decay(trackedHadrons); ProcessCut cut(20_GeV); // random::RNGManager::GetInstance().RegisterRandomStream("HadronicElasticModel"); @@ -274,7 +273,7 @@ int main() { // assemble all processes into an ordered process list // auto sequence = p0 << sibyll << decay << hadronicElastic << cut << trackWriter; - auto sequence = p0 << sibyll << sibyllNuc << decay << cut << trackWriter; + auto sequence = p0 << sibyll << sibyllNuc << decay << cut << trackWriter; // cout << "decltype(sequence)=" << type_id_with_cvr<decltype(sequence)>().pretty_name() // << "\n"; diff --git a/Documentation/Examples/cascade_proton_example.cc b/Documentation/Examples/cascade_proton_example.cc new file mode 100644 index 0000000000000000000000000000000000000000..b8851ffe622e1583a2ce55e60e7dd4a112065959 --- /dev/null +++ b/Documentation/Examples/cascade_proton_example.cc @@ -0,0 +1,325 @@ + +/* + * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu + * + * See file AUTHORS for a list of contributors. + * + * This software is distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3). See file LICENSE for a full version of + * the license. + */ + +#include <corsika/cascade/Cascade.h> +#include <corsika/process/ProcessSequence.h> +#include <corsika/process/hadronic_elastic_model/HadronicElasticModel.h> +#include <corsika/process/stack_inspector/StackInspector.h> +#include <corsika/process/tracking_line/TrackingLine.h> + +#include <corsika/setup/SetupStack.h> +#include <corsika/setup/SetupTrajectory.h> + +#include <corsika/environment/Environment.h> +#include <corsika/environment/HomogeneousMedium.h> +#include <corsika/environment/NuclearComposition.h> + +#include <corsika/geometry/Sphere.h> + +#include <corsika/process/sibyll/Decay.h> +#include <corsika/process/sibyll/Interaction.h> +#include <corsika/process/sibyll/NuclearInteraction.h> + +#include <corsika/process/pythia/Decay.h> +#include <corsika/process/pythia/Interaction.h> + +#include <corsika/process/track_writer/TrackWriter.h> + +#include <corsika/units/PhysicalUnits.h> + +#include <corsika/random/RNGManager.h> + +#include <corsika/utl/CorsikaFenv.h> + +#include <boost/type_index.hpp> +using boost::typeindex::type_id_with_cvr; + +#include <iostream> +#include <limits> +#include <typeinfo> + +using namespace corsika; +using namespace corsika::process; +using namespace corsika::units; +using namespace corsika::particles; +using namespace corsika::random; +using namespace corsika::setup; +using namespace corsika::geometry; +using namespace corsika::environment; + +using namespace std; +using namespace corsika::units::si; + +class ProcessCut : public process::ContinuousProcess<ProcessCut> { + + HEPEnergyType fECut; + + HEPEnergyType fEnergy = 0_GeV; + HEPEnergyType fEmEnergy = 0_GeV; + int fEmCount = 0; + HEPEnergyType fInvEnergy = 0_GeV; + int fInvCount = 0; + +public: + ProcessCut(const HEPEnergyType cut) + : fECut(cut) {} + + template <typename Particle> + bool isBelowEnergyCut(Particle& p) const { + // nuclei + if (p.GetPID() == particles::Code::Nucleus) { + auto const ElabNuc = p.GetEnergy() / p.GetNuclearA(); + auto const EcmNN = sqrt(2. * ElabNuc * 0.93827_GeV); + if (ElabNuc < fECut || EcmNN < 10_GeV) + return true; + else + return false; + } else { + // TODO: center-of-mass energy hard coded + const HEPEnergyType Ecm = sqrt(2. * p.GetEnergy() * 0.93827_GeV); + if (p.GetEnergy() < fECut || Ecm < 10_GeV) + return true; + else + return false; + } + } + + bool isEmParticle(Code pCode) const { + bool is_em = false; + // FOR NOW: switch + switch (pCode) { + case Code::Electron: + is_em = true; + break; + case Code::Positron: + is_em = true; + break; + case Code::Gamma: + is_em = true; + break; + default: + break; + } + return is_em; + } + + void defineEmParticles() const { + // create bool array identifying em particles + } + + bool isInvisible(Code pCode) const { + bool is_inv = false; + // FOR NOW: switch + switch (pCode) { + case Code::NuE: + is_inv = true; + break; + case Code::NuEBar: + is_inv = true; + break; + case Code::NuMu: + is_inv = true; + break; + case Code::NuMuBar: + is_inv = true; + break; + case Code::MuPlus: + is_inv = true; + break; + case Code::MuMinus: + is_inv = true; + break; + + case Code::Neutron: + is_inv = true; + break; + + case Code::AntiNeutron: + is_inv = true; + break; + + default: + break; + } + return is_inv; + } + + template <typename Particle> + LengthType MaxStepLength(Particle& p, setup::Trajectory&) const { + cout << "ProcessCut: MinStep: pid: " << p.GetPID() << endl; + cout << "ProcessCut: MinStep: energy (GeV): " << p.GetEnergy() / 1_GeV << endl; + const Code pid = p.GetPID(); + if (isEmParticle(pid) || isInvisible(pid) || isBelowEnergyCut(p)) { + cout << "ProcessCut: MinStep: next cut: " << 0. << endl; + return 0_m; + } else { + LengthType next_step = 1_m * std::numeric_limits<double>::infinity(); + cout << "ProcessCut: MinStep: next cut: " << next_step << endl; + return next_step; + } + } + + template <typename Particle, typename Stack> + EProcessReturn DoContinuous(Particle& p, setup::Trajectory&, Stack&) { + const Code pid = p.GetPID(); + HEPEnergyType energy = p.GetEnergy(); + cout << "ProcessCut: DoContinuous: " << pid << " E= " << energy + << ", EcutTot=" << (fEmEnergy + fInvEnergy + fEnergy) / 1_GeV << " GeV" << endl; + EProcessReturn ret = EProcessReturn::eOk; + if (isEmParticle(pid)) { + cout << "removing em. particle..." << endl; + fEmEnergy += energy; + fEmCount += 1; + // p.Delete(); + ret = EProcessReturn::eParticleAbsorbed; + } else if (isInvisible(pid)) { + cout << "removing inv. particle..." << endl; + fInvEnergy += energy; + fInvCount += 1; + // p.Delete(); + ret = EProcessReturn::eParticleAbsorbed; + } else if (isBelowEnergyCut(p)) { + cout << "removing low en. particle..." << endl; + fEnergy += energy; + // p.Delete(); + ret = EProcessReturn::eParticleAbsorbed; + } + return ret; + } + + void Init() { + fEmEnergy = 0. * 1_GeV; + fEmCount = 0; + fInvEnergy = 0. * 1_GeV; + fInvCount = 0; + fEnergy = 0. * 1_GeV; + // defineEmParticles(); + } + + void ShowResults() { + cout << " ******************************" << endl + << " ParticleCut: " << endl + << " energy in em. component (GeV): " << fEmEnergy / 1_GeV << endl + << " no. of em. particles injected: " << fEmCount << endl + << " energy in inv. component (GeV): " << fInvEnergy / 1_GeV << endl + << " no. of inv. particles injected: " << fInvCount << endl + << " energy below particle cut (GeV): " << fEnergy / 1_GeV << endl + << " ******************************" << endl; + } + + HEPEnergyType GetInvEnergy() const { return fInvEnergy; } + HEPEnergyType GetCutEnergy() const { return fEnergy; } + HEPEnergyType GetEmEnergy() const { return fEmEnergy; } +}; + +// +// The example main program for a particle cascade +// +int main() { + feenableexcept(FE_INVALID); + // initialize random number sequence(s) + random::RNGManager::GetInstance().RegisterRandomStream("cascade"); + + // setup environment, geometry + environment::Environment env; + auto& universe = *(env.GetUniverse()); + + auto theMedium = environment::Environment::CreateNode<Sphere>( + Point{env.GetCoordinateSystem(), 0_m, 0_m, 0_m}, + 1_km * std::numeric_limits<double>::infinity()); + + using MyHomogeneousModel = environment::HomogeneousMedium<environment::IMediumModel>; + theMedium->SetModelProperties<MyHomogeneousModel>( + 1_kg / (1_m * 1_m * 1_m), + environment::NuclearComposition( + std::vector<particles::Code>{particles::Code::Hydrogen}, + std::vector<float>{(float)1.})); + + universe.AddChild(std::move(theMedium)); + + const CoordinateSystem& rootCS = env.GetCoordinateSystem(); + + // setup processes, decays and interactions + tracking_line::TrackingLine<setup::Stack, setup::Trajectory> tracking(env); + stack_inspector::StackInspector<setup::Stack> p0(true); + + const std::vector<particles::Code> trackedHadrons = { + particles::Code::PiPlus, particles::Code::PiMinus, particles::Code::KPlus, + particles::Code::KMinus, particles::Code::K0Long, particles::Code::K0Short}; + + + random::RNGManager::GetInstance().RegisterRandomStream("s_rndm"); + random::RNGManager::GetInstance().RegisterRandomStream("pythia"); + // process::sibyll::Interaction sibyll(env); + process::pythia::Interaction pythia(env); + // process::sibyll::NuclearInteraction sibyllNuc(env, sibyll); + // process::sibyll::Decay decay(trackedHadrons); + process::pythia::Decay decay(trackedHadrons); + ProcessCut cut(20_GeV); + + // random::RNGManager::GetInstance().RegisterRandomStream("HadronicElasticModel"); + // process::HadronicElasticModel::HadronicElasticInteraction + // hadronicElastic(env); + + process::TrackWriter::TrackWriter trackWriter("tracks.dat"); + + // assemble all processes into an ordered process list + // auto sequence = p0 << sibyll << decay << hadronicElastic << cut << trackWriter; + // auto sequence = p0 << sibyll << sibyllNuc << decay << cut << trackWriter; + + auto sequence = p0 << pythia << decay << cut << trackWriter; + + // cout << "decltype(sequence)=" << type_id_with_cvr<decltype(sequence)>().pretty_name() + // << "\n"; + + // setup particle stack, and add primary particle + setup::Stack stack; + stack.Clear(); + const Code beamCode = Code::Proton; + const HEPMassType mass = particles::Proton::GetMass(); + const HEPEnergyType E0 = 100_GeV; + double theta = 0.; + double phi = 0.; + + { + auto elab2plab = [](HEPEnergyType Elab, HEPMassType m) { + return sqrt(Elab * Elab - m * m); + }; + HEPMomentumType P0 = elab2plab(E0, mass); + auto momentumComponents = [](double theta, double phi, HEPMomentumType ptot) { + return std::make_tuple(ptot * sin(theta) * cos(phi), ptot * sin(theta) * sin(phi), + -ptot * cos(theta)); + }; + auto const [px, py, pz] = + momentumComponents(theta / 180. * M_PI, phi / 180. * M_PI, P0); + auto plab = 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; + Point pos(rootCS, 0_m, 0_m, 0_m); + stack.AddParticle(std::tuple<particles::Code, units::si::HEPEnergyType, + corsika::stack::MomentumVector, geometry::Point, + units::si::TimeType>{ + beamCode, E0, plab, pos, 0_ns}); + } + + // define air shower object, run simulation + cascade::Cascade EAS(env, tracking, sequence, stack); + EAS.Init(); + EAS.Run(); + + cout << "Result: E0=" << E0 / 1_GeV << endl; + 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; +}