diff --git a/Documentation/Examples/cascade_example.cc b/Documentation/Examples/cascade_example.cc index f1e437ef1a4c84ba42ead78f7b5b509aa2b401c8..fef09923e475538032c86fbac341119799dcd3a9 100644 --- a/Documentation/Examples/cascade_example.cc +++ b/Documentation/Examples/cascade_example.cc @@ -208,13 +208,15 @@ int main() { Point{env.GetCoordinateSystem(), 0_m, 0_m, 0_m}, 1_km * std::numeric_limits<double>::infinity()); + // fraction of oxygen + const float fox = 0.20946; using MyHomogeneousModel = corsika::environment::HomogeneousMedium<corsika::environment::IMediumModel>; theMedium->SetModelProperties<MyHomogeneousModel>( 1_kg / (1_m * 1_m * 1_m), corsika::environment::NuclearComposition( - std::vector<corsika::particles::Code>{corsika::particles::Code::Nitrogen,corsika::particles::Code::Oxygen,corsika::particles::Code::Proton}, - std::vector<float>{0.5,0.3,0.2})); + std::vector<corsika::particles::Code>{corsika::particles::Code::Nitrogen,corsika::particles::Code::Oxygen}, + std::vector<float>{(float)1.-fox, fox})); universe.AddChild(std::move(theMedium)); @@ -237,7 +239,7 @@ int main() { // setup particle stack, and add primary particle setup::Stack stack; stack.Clear(); - const hep::EnergyType E0 = 100_GeV; + const hep::EnergyType E0 = 100_TeV; double theta = 0.; double phi = 0.; { diff --git a/Processes/Sibyll/Interaction.h b/Processes/Sibyll/Interaction.h index ff5477f75d5eb5ba9906944059160c352e100098..8ed9ca78d2a8d64f590a6dbcf2918da459487605 100644 --- a/Processes/Sibyll/Interaction.h +++ b/Processes/Sibyll/Interaction.h @@ -30,7 +30,6 @@ namespace corsika::process::sibyll { int fCount = 0; int fNucCount = 0; - int kTarget = 0; public: Interaction(corsika::environment::Environment const& env) : fEnvironment(env) { } ~Interaction() { @@ -71,54 +70,6 @@ namespace corsika::process::sibyll { // read from cross section code table const int kBeam = process::sibyll::GetSibyllXSCode(corsikaBeamId); const bool kInteraction = process::sibyll::CanInteract(corsikaBeamId); - - // get target from environment - /* - the target should be defined by the Environment, - ideally as full particle object so that the four momenta - and the boosts can be defined.. - */ - const auto currentNode = fEnvironment.GetUniverse()->GetContainingNode(p.GetPosition()); - const auto sample_target = [](const corsika::environment::NuclearComposition& comp) - { - double prev =0.; - std::vector<float> cumFrac; - for (auto f: comp.GetFractions()){ - cumFrac.push_back(prev+f); - prev = cumFrac.back(); - } - int a = 1; - const double r = s_rndm_(a); - int i = -1; - //cout << "rndm: " << r << endl; - for (auto cf: cumFrac){ - ++i; - //cout << "cf: " << cf << " " << comp.GetComponents()[i] << endl; - if(r<cf) break; - } - return comp.GetComponents()[i]; - }; - - const auto compo = currentNode->GetModelProperties().GetNuclearComposition(); - for (auto tid: compo.GetComponents()){ - cout << "Interaction: possible targets: " << tid << endl; - } - const auto tg = sample_target( compo ); - cout << "Interaction: target selected: " << tg << endl; - // test if valid in sibyll - // FOR NOW: throw error if not, may need workaround for atmosphere, contains small argon fraction - if(IsNucleus(tg)) - kTarget = GetNucleusA(tg); - else - if(tg==corsika::particles::Proton::GetCode()) - kTarget = 1; - else - throw std::runtime_error("Sibyll target particle unknown. Only nuclei with A<18 or protons are allowed."); - - cout << "Interaction: kTarget: " << kTarget << endl; - // redundant check - if(kTarget>18||kTarget==0) - throw std::runtime_error("Sibyll target outside range. Only nuclei with A<18 are allowed."); const hep::MassType nucleon_mass = 0.5 * (corsika::particles::Proton::GetMass() + corsika::particles::Neutron::GetMass()); @@ -139,33 +90,70 @@ namespace corsika::process::sibyll { << " input energy: " << p.GetEnergy() / 1_GeV << endl << " beam can interact:" << kBeam << endl << " beam XS code:" << kBeam << endl - << " beam pid:" << p.GetPID() << endl - << " target mass number:" << kTarget << std::endl; + << " beam pid:" << p.GetPID() << endl; if (kInteraction) { - double prodCrossSection, dummy, dum1, dum2, dum3, dum4; - double dumdif[3]; - - if (kTarget == 1) - sib_sigma_hp_(kBeam, Ecm, dum1, dum2, prodCrossSection, dumdif, dum3, dum4); - else - sib_sigma_hnuc_(kBeam, kTarget, Ecm, prodCrossSection, dummy); - - std::cout << "Interaction: " - << "MinStep: sibyll return: " << prodCrossSection << std::endl; - si::CrossSectionType sig = prodCrossSection * 1_mbarn; - std::cout << "Interaction: " - << "MinStep: CrossSection (mb): " << sig / 1_mbarn << std::endl; - - const si::MassType nucleon_mass = - 0.93827_GeV / corsika::units::constants::cSquared; - std::cout << "Interaction: " - << "nucleon mass " << nucleon_mass << std::endl; - // calculate interaction length in medium - GrammageType int_length = kTarget * nucleon_mass / sig; - std::cout << "Interaction: " - << "interaction length (g/cm2): " << int_length << std::endl; + // get target from environment + /* + the target should be defined by the Environment, + ideally as full particle object so that the four momenta + and the boosts can be defined.. + */ + const auto currentNode = fEnvironment.GetUniverse()->GetContainingNode(p.GetPosition()); + const auto mediumComposition = currentNode->GetModelProperties().GetNuclearComposition(); + // determine average interaction length + // FOR NOW: weighted sum + int i =-1; + double avgTargetMassNumber = 0.; + si::CrossSectionType weightedProdCrossSection = 0_mbarn; + int kTarget = 0; + // get weights of components from environment/medium + const auto w = mediumComposition.GetFractions(); + // loop over components in medium + for (auto targetId: mediumComposition.GetComponents() ){ + i++; + cout << "Interaction: get interaction lenght for target: " << targetId << endl; + if(IsNucleus(targetId)) + kTarget = GetNucleusA(targetId); + else + if(targetId==corsika::particles::Proton::GetCode()) + kTarget = 1; + else + throw std::runtime_error("GetInteractionLength: Sibyll target particle unknown. Only nuclei or protons are allowed."); + + cout << "Interaction: kTarget: " << kTarget << endl; + // check if nuclei in range + if(kTarget>18||kTarget==0) + throw std::runtime_error("Sibyll target outside range. Only nuclei with A<18 are allowed."); + + // get cross section from sibyll + double sigProd, dummy, dum1, dum2, dum3, dum4; + double dumdif[3]; + + if (kTarget == 1) + sib_sigma_hp_(kBeam, Ecm, dum1, dum2, sigProd, dumdif, dum3, dum4); + else + sib_sigma_hnuc_(kBeam, kTarget, Ecm, sigProd, dummy); + + std::cout << "Interaction: " + << " IntLength: sibyll return: " << sigProd << std::endl; + weightedProdCrossSection += w[i] * sigProd * 1_mbarn; + avgTargetMassNumber += w[i] * kTarget; + } + cout << "Interaction: " + << "IntLength: weighted CrossSection (mb): " << weightedProdCrossSection / 1_mbarn + << endl; + + const si::MassType nucleon_mass = + 0.93827_GeV / corsika::units::constants::cSquared; + std::cout << "Interaction: " + << "nucleon mass " << nucleon_mass << std::endl; + // calculate interaction length in medium +#warning check interaction length units + GrammageType int_length = avgTargetMassNumber * nucleon_mass / weightedProdCrossSection; + std::cout << "Interaction: " + << "interaction length (g/cm2): " << int_length / ( 0.001_kg ) * 1_cm * 1_cm << std::endl; return int_length; } @@ -219,10 +207,41 @@ namespace corsika::process::sibyll { const CoordinateSystem tempCS = rootCS.rotate(zAxis, phi); const CoordinateSystem sibyllCS = tempCS.rotate(yAxis, theta); - - // redundant check if target code is valid - if(kTarget>18||kTarget==0) - throw std::runtime_error("Interaction: Sibyll target outside range. Only nuclei with A<18 are allowed."); + const auto sample_target = [](const corsika::environment::NuclearComposition& comp) + { + double prev =0.; + std::vector<float> cumFrac; + for (auto f: comp.GetFractions()){ + cumFrac.push_back(prev+f); + prev = cumFrac.back(); + } + int a = 1; + const double r = s_rndm_(a); + int i = -1; + //cout << "rndm: " << r << endl; + for (auto cf: cumFrac){ + ++i; + //cout << "cf: " << cf << " " << comp.GetComponents()[i] << endl; + if(r<cf) break; + } + return comp.GetComponents()[i]; + }; + const auto currentNode = fEnvironment.GetUniverse()->GetContainingNode(p.GetPosition()); + const auto mediumComposition = currentNode->GetModelProperties().GetNuclearComposition(); + + const auto tg = sample_target( mediumComposition ); + cout << "Interaction: target selected: " << tg << endl; + // test if valid in sibyll + // FOR NOW: throw error if not, may need workaround for atmosphere, contains small argon fraction + int kTarget = 0; + if(IsNucleus(tg)) + kTarget = GetNucleusA(tg); + else + if(tg==corsika::particles::Proton::GetCode()) + kTarget = 1; + else + throw std::runtime_error("Sibyll target particle unknown. Only nuclei with A<18 or protons are allowed."); + // FOR NOW: target is always at rest const hep::MassType nucleon_mass = 0.5 * (corsika::particles::Proton::GetMass() +