From d7ac9f8a97065295e7a1e95c57c52feddf789813 Mon Sep 17 00:00:00 2001 From: ralfulrich <ralf.ulrich@kit.edu> Date: Mon, 25 Oct 2021 13:30:01 +0200 Subject: [PATCH] qgsjetII new interface --- .../detail/modules/qgsjetII/Interaction.inl | 397 ------------------ .../modules/qgsjetII/InteractionModel.inl | 308 ++++++++++++++ .../modules/sibyll/InteractionModel.inl | 35 +- corsika/framework/utility/COMBoost.hpp | 32 +- corsika/modules/LongitudinalProfile.hpp | 3 +- corsika/modules/QGSJetII.hpp | 21 +- corsika/modules/Sibyll.hpp | 4 +- corsika/modules/qgsjetII/Interaction.hpp | 65 --- corsika/modules/qgsjetII/InteractionModel.hpp | 77 ++++ .../modules/qgsjetII/ParticleConversion.hpp | 8 +- corsika/modules/sibyll/InteractionModel.hpp | 4 +- tests/modules/CMakeLists.txt | 2 +- tests/modules/testQGSJetII.cpp | 103 +++-- tests/modules/testSibyll.cpp | 7 +- 14 files changed, 514 insertions(+), 552 deletions(-) delete mode 100644 corsika/detail/modules/qgsjetII/Interaction.inl create mode 100644 corsika/detail/modules/qgsjetII/InteractionModel.inl delete mode 100644 corsika/modules/qgsjetII/Interaction.hpp create mode 100644 corsika/modules/qgsjetII/InteractionModel.hpp diff --git a/corsika/detail/modules/qgsjetII/Interaction.inl b/corsika/detail/modules/qgsjetII/Interaction.inl deleted file mode 100644 index c3147dbb8..000000000 --- a/corsika/detail/modules/qgsjetII/Interaction.inl +++ /dev/null @@ -1,397 +0,0 @@ -/* - * (c) Copyright 2020 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/modules/qgsjetII/Interaction.hpp> - -#include <corsika/media/Environment.hpp> -#include <corsika/media/NuclearComposition.hpp> -#include <corsika/framework/geometry/QuantityVector.hpp> -#include <corsika/framework/geometry/FourVector.hpp> -#include <corsika/modules/qgsjetII/ParticleConversion.hpp> -#include <corsika/modules/qgsjetII/QGSJetIIFragmentsStack.hpp> -#include <corsika/modules/qgsjetII/QGSJetIIStack.hpp> -#include <corsika/framework/utility/COMBoost.hpp> - -#include <sstream> -#include <string> -#include <tuple> - -#include <qgsjet-II-04.hpp> - -namespace corsika::qgsjetII { - - inline Interaction::Interaction(boost::filesystem::path dataPath) { - CORSIKA_LOG_DEBUG("Reading QGSJetII data tables from {}", dataPath); - - // initialize QgsjetII - static bool initialized = false; - if (!initialized) { - qgset_(); - datadir DIR(dataPath.string() + "/"); - qgaini_(DIR.data); - initialized = true; - } - } - - inline Interaction::~Interaction() { - CORSIKA_LOG_DEBUG("QgsjetII::Interaction n= {}", count_); - } - - inline CrossSectionType Interaction::getCrossSection(const Code beamId, - const Code targetId, - const HEPEnergyType Elab, - const unsigned int Abeam, - const unsigned int targetA) const { - double sigProd = std::numeric_limits<double>::infinity(); - - if (corsika::qgsjetII::canInteract(beamId)) { - - int const iBeam = static_cast<QgsjetIIXSClassIntType>( - corsika::qgsjetII::getQgsjetIIXSCode(beamId)); - int iTarget = 1; - if (is_nucleus(targetId)) { - iTarget = targetA; - if (iTarget > int(maxMassNumber_) || iTarget <= 0) { - std::ostringstream txt; - txt << "QgsjetII target outside range. Atarget=" << iTarget; - throw std::runtime_error(txt.str().c_str()); - } - } - int iProjectile = 1; - if (is_nucleus(beamId)) { - iProjectile = Abeam; - if (iProjectile > int(maxMassNumber_) || iProjectile <= 0) { - std::ostringstream txt; - txt << "QgsjetII projectile outside range. Aprojectile=" << iProjectile; - throw std::runtime_error(txt.str().c_str()); - } - } - - CORSIKA_LOG_DEBUG( - "QgsjetII::getCrossSection Elab= {} GeV iBeam= {}" - " iProjectile= {} iTarget= {}", - Elab / 1_GeV, iBeam, iProjectile, iTarget); - sigProd = qgsect_(Elab / 1_GeV, iBeam, iProjectile, iTarget); - CORSIKA_LOG_DEBUG("QgsjetII::getCrossSection sigProd= {} mb", sigProd); - } - - return sigProd * 1_mb; - } - - template <typename TParticle> - inline GrammageType Interaction::getInteractionLength(const TParticle& particle) const { - - // coordinate system, get global frame of reference - CoordinateSystemPtr const& rootCS = get_root_CoordinateSystem(); - - const Code corsikaBeamId = particle.getPID(); - - // beam particles for qgsjetII : 1, 2, 3 for p, pi, k - // read from cross section code table - const bool kInteraction = corsika::qgsjetII::canInteract(corsikaBeamId); - - // FOR NOW: assume target is at rest - MomentumVector pTarget(rootCS, {0_GeV, 0_GeV, 0_GeV}); - - // total momentum and energy - HEPEnergyType const Elab = particle.getEnergy(); - - CORSIKA_LOG_DEBUG( - "Interaction: LambdaInt: \n" - " input energy: {} GeV" - " beam can interact: {}" - " beam pid: {}", - particle.getEnergy() / 1_GeV, kInteraction, corsikaBeamId); - - if (kInteraction) { - - int Abeam = 0; - if (is_nucleus(corsikaBeamId)) Abeam = get_nucleus_A(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.. - */ - - auto const* currentNode = particle.getNode(); - const auto& mediumComposition = - currentNode->getModelProperties().getNuclearComposition(); - - CrossSectionType weightedProdCrossSection = - mediumComposition.getWeightedSum([=](Code targetID) -> CrossSectionType { - int targetA = 0; - if (is_nucleus(targetID)) targetA = get_nucleus_A(targetID); - return getCrossSection(corsikaBeamId, targetID, Elab, Abeam, targetA); - }); - - CORSIKA_LOG_DEBUG( - "Interaction: " - "IntLength: weighted CrossSection (mb): {}", - weightedProdCrossSection / 1_mb); - - // calculate interaction length in medium - GrammageType const int_length = mediumComposition.getAverageMassNumber() * - constants::u / weightedProdCrossSection; - CORSIKA_LOG_DEBUG( - "Interaction: " - "interaction length (g/cm2): {}", - int_length / (0.001_kg) * 1_cm * 1_cm); - - return int_length; - } - - return std::numeric_limits<double>::infinity() * 1_g / (1_cm * 1_cm); - } - - /** - In this function QGSJETII is called to produce one event. The - event is copied (and boosted) into the shower lab frame. - */ - - template <typename TView> - inline void Interaction::doInteraction(TView& view) { - - auto const projectile = view.getProjectile(); - auto const corsikaBeamId = projectile.getPID(); - CORSIKA_LOG_DEBUG( - "ProcessQgsjetII: " - "doInteraction: {} interaction possible? {}", - corsikaBeamId, corsika::qgsjetII::canInteract(corsikaBeamId)); - - if (!corsika::qgsjetII::canInteract(corsikaBeamId)) return; - - CoordinateSystemPtr const& rootCS = get_root_CoordinateSystem(); - - // position and time of interaction, not used in QgsjetII - Point const pOrig = projectile.getPosition(); - TimeType const tOrig = projectile.getTime(); - - // define target - // for QgsjetII is always a single nucleon - // FOR NOW: target is always at rest - auto const targetEnergyLab = 0_GeV + constants::nucleonMass; - auto const targetMomentumLab = MomentumVector(rootCS, 0_GeV, 0_GeV, 0_GeV); - FourVector const PtargLab(targetEnergyLab, targetMomentumLab); - - // define projectile - HEPEnergyType const projectileEnergyLab = projectile.getEnergy(); - auto const projectileMomentumLab = projectile.getMomentum(); - - int beamA = 0; - if (is_nucleus(corsikaBeamId)) beamA = get_nucleus_A(corsikaBeamId); - - HEPEnergyType const projectileEnergyLabPerNucleon = projectileEnergyLab / beamA; - - CORSIKA_LOG_DEBUG( - "ebeam lab: {} GeV " - "pbeam lab: {} GeV ", - projectileEnergyLab / 1_GeV, projectileMomentumLab.getComponents() / 1_GeV); - CORSIKA_LOG_DEBUG( - "etarget lab: {} GeV " - "ptarget lab: {} GeV ", - targetEnergyLab / 1_GeV, targetMomentumLab.getComponents() / 1_GeV); - CORSIKA_LOG_DEBUG("position of interaction: {}", pOrig.getCoordinates()); - CORSIKA_LOG_DEBUG("time: {} ", tOrig); - - // 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 - */ - 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]; - int targetA = 0; - if (is_nucleus(targetId)) targetA = get_nucleus_A(targetId); - const auto sigProd = - getCrossSection(corsikaBeamId, targetId, projectileEnergyLab, beamA, targetA); - cross_section_of_components[i] = sigProd; - } - - const auto targetCode = - mediumComposition.sampleTarget(cross_section_of_components, rng_); - - int targetMassNumber = 1; // proton - if (is_nucleus(targetCode)) { // nucleus - targetMassNumber = get_nucleus_A(targetCode); - if (targetMassNumber > int(maxMassNumber_)) - throw std::runtime_error( - "QgsjetII target mass outside range."); // LCOV_EXCL_LINE there is no - // allowed path here - } else { - if (targetCode != Proton::code) // LCOV_EXCL_LINE there is no allowed path here - throw std::runtime_error( - "QgsjetII Taget not possible."); // LCOV_EXCL_LINE there is no allowed path - // here - } - CORSIKA_LOG_DEBUG("target: {}, qgsjetII code/A: {}", targetCode, targetMassNumber); - - int projectileMassNumber = 1; // "1" means "hadron" - QgsjetIIHadronType qgsjet_hadron_type = - qgsjetII::getQgsjetIIHadronType(corsikaBeamId); - if (qgsjet_hadron_type == QgsjetIIHadronType::NucleusType) { - projectileMassNumber = get_nucleus_A(corsikaBeamId); - if (projectileMassNumber > int(maxMassNumber_)) - throw std::runtime_error( - "QgsjetII projectile mass outside range."); // LCOV_EXCL_LINE there is no - // allowed path here - std::array<QgsjetIIHadronType, 2> constexpr nucleons = { - QgsjetIIHadronType::ProtonType, QgsjetIIHadronType::NeutronType}; - std::uniform_int_distribution select(0, 1); - qgsjet_hadron_type = nucleons[select(rng_)]; - } else { - // from conex: replace pi0 or rho0 with pi+/pi- in alternating sequence - if (qgsjet_hadron_type == QgsjetIIHadronType::NeutralLightMesonType) { - qgsjet_hadron_type = alternate_; - alternate_ = (alternate_ == QgsjetIIHadronType::PiPlusType - ? QgsjetIIHadronType::PiMinusType - : QgsjetIIHadronType::PiPlusType); - } - } - - // beam id for qgsjetII - int kBeam = 2; // default: proton Shouldn't we randomize neutron/proton for nuclei? - if (!is_nucleus(corsikaBeamId)) { - kBeam = corsika::qgsjetII::convertToQgsjetIIRaw(corsikaBeamId); - // from conex - if (kBeam == 0) { // replace pi0 or rho0 with pi+/pi- - static int select = 1; - kBeam = select; - select *= -1; - } - // replace lambda by neutron - if (kBeam == 6) - kBeam = 3; - else if (kBeam == -6) - kBeam = -3; - // else if (abs(kBeam)>6) -> throw - } - - count_++; - int qgsjet_hadron_type_int = static_cast<QgsjetIICodeIntType>(qgsjet_hadron_type); - CORSIKA_LOG_DEBUG( - "qgsjet_hadron_type_int={} projectileMassNumber={} targetMassNumber={}", - qgsjet_hadron_type_int, projectileMassNumber, targetMassNumber); - qgini_(projectileEnergyLab / 1_GeV, qgsjet_hadron_type_int, projectileMassNumber, - targetMassNumber); - qgconf_(); - - // bookkeeping - MomentumVector Plab_final(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV}); - HEPEnergyType Elab_final = 0_GeV; - - // to read the secondaries - // define rotation to and from CoM frame - // CoM frame definition in QgsjetII projectile: +z - auto const& originalCS = projectileMomentumLab.getCoordinateSystem(); - CoordinateSystemPtr const zAxisFrame = - make_rotationToZ(originalCS, projectileMomentumLab); - - // fragments - QGSJetIIFragmentsStack qfs; - for (auto& fragm : qfs) { - int const A = fragm.getFragmentSize(); - if (A == 1) { // nucleon - std::uniform_real_distribution<double> select; - Code idFragm = Code::Proton; - if (select(rng_) > 0.5) { idFragm = Code::Neutron; } - - const HEPMassType nucleonMass = get_mass(idFragm); - // no pT, frgments just go forward - auto momentum = - Vector(zAxisFrame, corsika::QuantityVector<hepmomentum_d>{ - 0.0_GeV, 0.0_GeV, - sqrt((projectileEnergyLabPerNucleon + nucleonMass) * - (projectileEnergyLabPerNucleon - nucleonMass))}); - - momentum.rebase(originalCS); // transform back into standard lab frame - CORSIKA_LOG_DEBUG( - "secondary fragment> id= {}" - " p={}", - idFragm, momentum.getComponents()); - auto pnew = view.addSecondary(std::make_tuple(idFragm, momentum, pOrig, tOrig)); - Plab_final += pnew.getMomentum(); - Elab_final += pnew.getEnergy(); - - } else { // nucleus, A>1 - - int Z = 0; - switch (A) { - case 2: // deuterium - Z = 1; - break; - case 3: // tritium - Z = 1; - break; - case 4: // helium - Z = 2; - break; - default: // nucleus - { - Z = int(A / 2.15 + 0.7); - } - } - - HEPMassType const nucleusMass = Proton::mass * Z + Neutron::mass * (A - Z); - // no pT, frgments just go forward - auto momentum = Vector( - zAxisFrame, QuantityVector<hepmomentum_d>{ - 0.0_GeV, 0.0_GeV, - sqrt((projectileEnergyLabPerNucleon * A + nucleusMass) * - (projectileEnergyLabPerNucleon * A - nucleusMass))}); - - momentum.rebase(originalCS); // transform back into standard lab frame - CORSIKA_LOG_DEBUG( - "secondary fragment> id={}" - " p={}" - " A={}" - " Z={}", - get_nucleus_code(A, Z), momentum.getComponents(), A, Z); - - auto pnew = view.addSecondary( - std::make_tuple(get_nucleus_code(A, Z), momentum, pOrig, tOrig)); - Plab_final += pnew.getMomentum(); - Elab_final += pnew.getEnergy(); - } - } - - // secondaries - QGSJetIIStack qs; - for (auto& psec : qs) { - - auto momentum = psec.getMomentum(zAxisFrame); - - momentum.rebase(originalCS); // transform back into standard lab frame - CORSIKA_LOG_DEBUG("secondary> id= {}, p= {}", - corsika::qgsjetII::convertFromQgsjetII(psec.getPID()), - momentum.getComponents()); - auto pnew = view.addSecondary(std::make_tuple( - corsika::qgsjetII::convertFromQgsjetII(psec.getPID()), momentum, pOrig, tOrig)); - Plab_final += pnew.getMomentum(); - Elab_final += pnew.getEnergy(); - } - CORSIKA_LOG_DEBUG( - "conservation (all GeV): Ecm_final= n/a " /* << Ecm_final / 1_GeV*/ - ", Elab_final={} " - ", Plab_final={}" - ", N_wounded,targ={}" - ", N_wounded,proj={}" - ", N_fragm,proj={}", - Elab_final / 1_GeV, (Plab_final / 1_GeV).getComponents(), - QGSJetIIFragmentsStackData::getWoundedNucleonsTarget(), - QGSJetIIFragmentsStackData::getWoundedNucleonsProjectile(), qfs.getSize()); - } -} // namespace corsika::qgsjetII diff --git a/corsika/detail/modules/qgsjetII/InteractionModel.inl b/corsika/detail/modules/qgsjetII/InteractionModel.inl new file mode 100644 index 000000000..3d5209d8e --- /dev/null +++ b/corsika/detail/modules/qgsjetII/InteractionModel.inl @@ -0,0 +1,308 @@ +/* + * (c) Copyright 2020 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/modules/qgsjetII/InteractionModel.hpp> + +#include <corsika/framework/geometry/QuantityVector.hpp> +#include <corsika/framework/geometry/FourVector.hpp> +#include <corsika/modules/qgsjetII/ParticleConversion.hpp> +#include <corsika/modules/qgsjetII/QGSJetIIFragmentsStack.hpp> +#include <corsika/modules/qgsjetII/QGSJetIIStack.hpp> +#include <corsika/framework/utility/COMBoost.hpp> + +#include <sstream> +#include <tuple> + +#include <qgsjet-II-04.hpp> + +namespace corsika::qgsjetII { + + inline InteractionModel::InteractionModel(boost::filesystem::path const dataPath) { + CORSIKA_LOG_DEBUG("Reading QGSJetII data tables from {}", dataPath); + + // initialize QgsjetII + static bool initialized = false; + if (!initialized) { + qgset_(); + datadir DIR(dataPath.string() + "/"); + qgaini_(DIR.data); + initialized = true; + } + } + + inline InteractionModel::~InteractionModel() { + CORSIKA_LOG_DEBUG("QgsjetII::InteractionModel n= {}", count_); + } + + inline void InteractionModel::isValid(Code const projectileId, + Code const targetId) const { + if (is_nucleus(targetId)) { + size_t iTarget = get_nucleus_A(targetId); + if (iTarget > int(maxMassNumber_) || iTarget <= 0) { + std::ostringstream txt; + txt << "QgsjetII target outside range. Atarget=" << iTarget; + throw std::runtime_error(txt.str().c_str()); + } + } else if (targetId != Proton::code) { + std::ostringstream txt; + txt << "QgsjetII not valid target=" << targetId; + throw std::runtime_error(txt.str().c_str()); + } + + if (is_nucleus(projectileId)) { + size_t iProjectile = get_nucleus_A(projectileId); + if (iProjectile > int(maxMassNumber_) || iProjectile <= 0) { + std::ostringstream txt; + txt << "QgsjetII projectile outside range. Aprojectile=" << iProjectile; + throw std::runtime_error(txt.str().c_str()); + } + } else if (!is_hadron(projectileId)) { + std::ostringstream txt; + txt << "QgsjetII projectile can only be hadrons. Is=" << projectileId; + throw std::runtime_error(txt.str().c_str()); + } + } + + inline CrossSectionType InteractionModel::getCrossSection( + Code const projectileId, Code const targetId, FourMomentum const& projectileP4, + FourMomentum const& targetP4) const { + + double sigProd = std::numeric_limits<double>::infinity(); + + if (!corsika::qgsjetII::canInteract(projectileId)) { return sigProd * 1_mb; } + + isValid(projectileId, targetId); // throws + + // define projectile, in lab frame + auto const sqrtS2 = (projectileP4 + targetP4).getNormSqr(); + HEPEnergyType const Elab = (sqrtS2 - static_pow<2>(get_mass(projectileId)) - + static_pow<2>(get_mass(targetId))) / + (2 * get_mass(targetId)); + + int const iBeam = static_cast<QgsjetIIXSClassIntType>( + corsika::qgsjetII::getQgsjetIIXSCode(projectileId)); + int iTarget = 1; + if (is_nucleus(targetId)) { iTarget = get_nucleus_A(targetId); } + int iProjectile = 1; + if (is_nucleus(projectileId)) { iProjectile = get_nucleus_A(projectileId); } + + CORSIKA_LOG_DEBUG( + "QgsjetII::getCrossSection Elab= {} GeV iBeam= {}" + " iProjectile= {} iTarget= {}", + Elab / 1_GeV, iBeam, iProjectile, iTarget); + sigProd = qgsect_(Elab / 1_GeV, iBeam, iProjectile, iTarget); + CORSIKA_LOG_DEBUG("QgsjetII::getCrossSection sigProd= {} mb", sigProd); + + return sigProd * 1_mb; + } + + template <typename TSecondaries> + inline void InteractionModel::doInteraction(TSecondaries& view, Code const projectileId, + Code const targetId, + FourMomentum const& projectileP4, + FourMomentum const& targetP4) { + + CORSIKA_LOG_DEBUG( + "ProcessQgsjetII: " + "doInteraction: {} interaction possible? {}", + projectileId, corsika::qgsjetII::canInteract(projectileId)); + + if (!corsika::qgsjetII::canInteract(projectileId)) return; + + isValid(projectileId, targetId); // throws + + CoordinateSystemPtr const& rootCS = get_root_CoordinateSystem(); + + // define projectile, in lab frame + auto const sqrtS2 = (projectileP4 + targetP4).getNormSqr(); + HEPEnergyType const Elab = (sqrtS2 - static_pow<2>(get_mass(projectileId)) - + static_pow<2>(get_mass(targetId))) / + (2 * get_mass(targetId)); + + int beamA = 0; + if (is_nucleus(projectileId)) { beamA = get_nucleus_A(projectileId); } + + CORSIKA_LOG_DEBUG("ebeam lab: {} GeV ", Elab / 1_GeV); + + int targetMassNumber = 1; // proton + if (is_nucleus(targetId)) { // nucleus + targetMassNumber = get_nucleus_A(targetId); + } + CORSIKA_LOG_DEBUG("target: {}, qgsjetII code/A: {}", targetId, targetMassNumber); + + // select QGSJetII internal projectile type + int projectileMassNumber = 1; // "1" means "hadron" + QgsjetIIHadronType qgsjet_hadron_type = qgsjetII::getQgsjetIIHadronType(projectileId); + if (qgsjet_hadron_type == QgsjetIIHadronType::NucleusType) { + projectileMassNumber = get_nucleus_A(projectileId); + std::array<QgsjetIIHadronType, 2> constexpr nucleons = { + QgsjetIIHadronType::ProtonType, QgsjetIIHadronType::NeutronType}; + std::uniform_int_distribution select(0, 1); + qgsjet_hadron_type = nucleons[select(rng_)]; + } else if (qgsjet_hadron_type == QgsjetIIHadronType::NeutralLightMesonType) { + // from conex: replace pi0 or rho0 with pi+/pi- in alternating sequence + qgsjet_hadron_type = alternate_; + alternate_ = + (alternate_ == QgsjetIIHadronType::PiPlusType ? QgsjetIIHadronType::PiMinusType + : QgsjetIIHadronType::PiPlusType); + } + + count_++; + int qgsjet_hadron_type_int = static_cast<QgsjetIICodeIntType>(qgsjet_hadron_type); + CORSIKA_LOG_DEBUG( + "qgsjet_hadron_type_int={} projectileMassNumber={} targetMassNumber={}", + qgsjet_hadron_type_int, projectileMassNumber, targetMassNumber); + qgini_(Elab / 1_GeV, qgsjet_hadron_type_int, projectileMassNumber, targetMassNumber); + qgconf_(); + + // bookkeeping + MomentumVector Plab_final(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV}); + HEPEnergyType Elab_final = 0_GeV; + + // to read the secondaries + // define rotation to and from CoM frame + // CoM frame definition in QgsjetII projectile: +z + + // QGSJetII, both, in input and output only considers the lab frame with a target at + // rest. + + // system of initial-state + COMBoost boost(projectileP4, targetP4); + + auto const& originalCS = boost.getOriginalCS(); + auto const& csPrime = + boost.getRotatedCS(); // z is along the CM motion (projectile, in Cascade) + + MomentumVector const projectileMomentum = projectileP4.getSpaceLikeComponents(); + HEPMomentumType const pLabMag = + sqrt((Elab - get_mass(projectileId)) * (Elab + get_mass(projectileId))); + MomentumVector pLab(csPrime, {0_eV, 0_eV, pLabMag}); + + // internal QGSJetII system + COMBoost boostInternal({Elab, pLab}, get_mass(targetId)); + + // position and time of interaction, not used in QgsjetII + auto const projectile = view.getProjectile(); + Point const pOrig = projectile.getPosition(); + TimeType const tOrig = projectile.getTime(); + + // fragments + QGSJetIIFragmentsStack qfs; + for (auto& fragm : qfs) { + int const A = fragm.getFragmentSize(); + if (A == 1) { // nucleon + std::uniform_real_distribution<double> select; + Code idFragm = Code::Proton; + if (select(rng_) > 0.5) { idFragm = Code::Neutron; } + + const HEPMassType nucleonMass = get_mass(idFragm); + // no pT, fragments just go forward + HEPEnergyType const projectileEnergyLabPerNucleon = Elab / beamA; + MomentumVector momentum{csPrime, + {0.0_GeV, 0.0_GeV, + sqrt((projectileEnergyLabPerNucleon + nucleonMass) * + (projectileEnergyLabPerNucleon - nucleonMass))}}; + + // this is not "CoM" here, but rather the system defined by projectile+target, + // which in Cascade-mode is already lab + auto const P4com = + boostInternal.toCoM(FourVector{projectileEnergyLabPerNucleon, momentum}); + auto const P4output = boost.fromCoM(P4com); + auto p3output = P4output.getSpaceLikeComponents(); + p3output.rebase(originalCS); // transform back into standard lab frame + + CORSIKA_LOG_DEBUG( + "secondary fragment> id= {}" + " p={}", + idFragm, p3output.getComponents()); + auto pnew = view.addSecondary(std::make_tuple(idFragm, p3output, pOrig, tOrig)); + Plab_final += pnew.getMomentum(); + Elab_final += pnew.getEnergy(); + + } else { // nucleus, A>1 + + int Z = 0; + switch (A) { + case 2: // deuterium + Z = 1; + break; + case 3: // tritium + Z = 1; + break; + case 4: // helium + Z = 2; + break; + default: // nucleus + { + Z = int(A / 2.15 + 0.7); + } + } + + HEPMassType const nucleusMass = Proton::mass * Z + Neutron::mass * (A - Z); + // no pT, frgments just go forward + HEPEnergyType const projectileEnergyLabPerNucleon = Elab / beamA; + MomentumVector momentum{ + csPrime, + {0.0_GeV, 0.0_GeV, + sqrt((projectileEnergyLabPerNucleon * A + nucleusMass) * + (projectileEnergyLabPerNucleon * A - nucleusMass))}}; + + // this is not "CoM" here, but rather the system defined by projectile+target, + // which in Cascade-mode is already lab + auto const P4com = + boostInternal.toCoM(FourVector{projectileEnergyLabPerNucleon * A, momentum}); + auto const P4output = boost.fromCoM(P4com); + auto p3output = P4output.getSpaceLikeComponents(); + p3output.rebase(originalCS); // transform back into standard lab frame + + CORSIKA_LOG_DEBUG( + "secondary fragment> id={}" + " p={}" + " A={}" + " Z={}", + get_nucleus_code(A, Z), p3output.getComponents(), A, Z); + + auto pnew = view.addSecondary( + std::make_tuple(get_nucleus_code(A, Z), p3output, pOrig, tOrig)); + Plab_final += pnew.getMomentum(); + Elab_final += pnew.getEnergy(); + } + } + + // secondaries + QGSJetIIStack qs; + for (auto& psec : qs) { + + auto momentum = psec.getMomentum(csPrime); + // this is not "CoM" here, but rather the system defined by projectile+target, + // which in Cascade-mode is already lab + auto const P4com = boostInternal.toCoM(FourVector{psec.getEnergy(), momentum}); + auto const P4output = boost.fromCoM(P4com); + auto p3output = P4output.getSpaceLikeComponents(); + p3output.rebase(originalCS); // transform back into standard lab frame + + CORSIKA_LOG_DEBUG("secondary> id= {}, p= {}", + corsika::qgsjetII::convertFromQgsjetII(psec.getPID()), + p3output.getComponents()); + auto pnew = view.addSecondary(std::make_tuple( + corsika::qgsjetII::convertFromQgsjetII(psec.getPID()), p3output, pOrig, tOrig)); + Plab_final += pnew.getMomentum(); + Elab_final += pnew.getEnergy(); + } + CORSIKA_LOG_DEBUG( + "conservation (all GeV): Ecm_final= n/a " /* << Ecm_final / 1_GeV*/ + ", Elab_final={} " + ", Plab_final={}" + ", N_wounded,targ={}" + ", N_wounded,proj={}" + ", N_fragm,proj={}", + Elab_final / 1_GeV, (Plab_final / 1_GeV).getComponents(), + QGSJetIIFragmentsStackData::getWoundedNucleonsTarget(), + QGSJetIIFragmentsStackData::getWoundedNucleonsProjectile(), qfs.getSize()); + } +} // namespace corsika::qgsjetII diff --git a/corsika/detail/modules/sibyll/InteractionModel.inl b/corsika/detail/modules/sibyll/InteractionModel.inl index c0716be3a..af1a01133 100644 --- a/corsika/detail/modules/sibyll/InteractionModel.inl +++ b/corsika/detail/modules/sibyll/InteractionModel.inl @@ -156,8 +156,8 @@ namespace corsika::sibyll { auto const tmp = psib.getMomentum().getComponents(); auto const pCoM = MomentumVector(csPrime, tmp); HEPEnergyType const eCoM = psib.getEnergy(); - auto const Plab = boost.fromCoM(FourVector{eCoM, pCoM}); - auto const p3lab = Plab.getSpaceLikeComponents(); + auto const P4lab = boost.fromCoM(FourVector{eCoM, pCoM}); + auto const p3lab = P4lab.getSpaceLikeComponents(); // add to corsika stack auto pnew = secondaries.addSecondary(std::make_tuple( @@ -167,19 +167,20 @@ namespace corsika::sibyll { Elab_final += pnew.getEnergy(); Ecm_final += psib.getEnergy(); } - HEPEnergyType const Elab_initial = - static_pow<2>(sqrtSnn) / (2 * constants::nucleonMass); - CORSIKA_LOG_DEBUG( - "conservation (all GeV): " - "sqrtSnn={}, sqrtSnn_final={}, " - "Elab_initial={}, Elab_final={}, " - "diff(%)={}, " - "E in nucleons={}, " - "Plab_final={} ", - sqrtSnn / 1_GeV, Ecm_final * 2. / (get_nwounded() + 1) / 1_GeV, Elab_initial, - Elab_final / 1_GeV, (Elab_final - Elab_initial) / Elab_initial * 100, - constants::nucleonMass * get_nwounded() / 1_GeV, - (Plab_final / 1_GeV).getComponents()); - } // namespace corsika::sibyll - + { // just output + HEPEnergyType const Elab_initial = + static_pow<2>(sqrtSnn) / (2 * constants::nucleonMass); + CORSIKA_LOG_DEBUG( + "conservation (all GeV): " + "sqrtSnn={}, sqrtSnn_final={}, " + "Elab_initial={}, Elab_final={}, " + "diff(%)={}, " + "E in nucleons={}, " + "Plab_final={} ", + sqrtSnn / 1_GeV, Ecm_final * 2. / (get_nwounded() + 1) / 1_GeV, Elab_initial, + Elab_final / 1_GeV, (Elab_final - Elab_initial) / Elab_initial * 100, + constants::nucleonMass * get_nwounded() / 1_GeV, + (Plab_final / 1_GeV).getComponents()); + } + } } // namespace corsika::sibyll diff --git a/corsika/framework/utility/COMBoost.hpp b/corsika/framework/utility/COMBoost.hpp index 8bba6b43d..98be9fc07 100644 --- a/corsika/framework/utility/COMBoost.hpp +++ b/corsika/framework/utility/COMBoost.hpp @@ -25,11 +25,11 @@ namespace corsika { */ /** - * @class COMBoost + * @class COMBoost * @ingroup Utilities * - * This utility class handles Lorentz boost between different - * referenence frames, using FourVector. + * This utility class handles Lorentz boost (in one spatial direction) + * between different referenence frames, using FourVector. * * The class is initialized with projectile and optionally target * energy/momentum data. During initialization, a rotation matrix is @@ -47,16 +47,26 @@ namespace corsika { class COMBoost { public: - //! construct a COMBoost given four-vector of projectile and mass of target (target at - //! rest) + /** + * Construct a COMBoost given four-vector of projectile and mass of target (target at + * rest). + * + * The FourMomentum and mass define the lab system. + */ COMBoost(FourMomentum const& P4projectile, HEPEnergyType const massTarget); - //! construct a COMBoost given two four-vectors of projectile target - COMBoost(FourMomentum const& P4projectile, FourMomentum const& P4target); - - //! construct a COMBoost to boost into the rest frame given a 3-momentum and mass + /** + * Construct a COMBoost to boost into the rest frame given a 3-momentum and mass. + */ COMBoost(MomentumVector const& momentum, HEPEnergyType const mass); + /** + * Construct a COMBoost given two four-vectors of projectile target. + * + * The tow FourMomentum can define an arbitrary system. + */ + COMBoost(FourMomentum const& P4projectile, FourMomentum const& P4target); + //! transforms a 4-momentum from lab frame to the center-of-mass frame template <typename FourVector> FourVector toCoM(FourVector const& p4) const; @@ -65,10 +75,10 @@ namespace corsika { template <typename FourVector> FourVector fromCoM(FourVector const& p4) const; - //! returns the rotated coordinate system + //! returns the rotated coordinate system: +z is projectile direction CoordinateSystemPtr getRotatedCS() const; - //! returns the original coordinate system + //! returns the original coordinate system of the projectile (lab) CoordinateSystemPtr getOriginalCS() const; protected: diff --git a/corsika/modules/LongitudinalProfile.hpp b/corsika/modules/LongitudinalProfile.hpp index 1d84462b0..b5d199fb8 100644 --- a/corsika/modules/LongitudinalProfile.hpp +++ b/corsika/modules/LongitudinalProfile.hpp @@ -31,8 +31,7 @@ namespace corsika { * simulation into a projected grammage range and counts for * different particle species when they cross dX (default: 10g/cm2) * boundaries. - * - **/ + */ class LongitudinalProfile : public ContinuousProcess<LongitudinalProfile> { diff --git a/corsika/modules/QGSJetII.hpp b/corsika/modules/QGSJetII.hpp index 9540c4ad1..dd7422442 100644 --- a/corsika/modules/QGSJetII.hpp +++ b/corsika/modules/QGSJetII.hpp @@ -8,4 +8,23 @@ #pragma once -#include <corsika/modules/qgsjetII/Interaction.hpp> +#include <corsika/modules/qgsjetII/InteractionModel.hpp> + +#include <corsika/framework/process/InteractionProcess.hpp> + +/** + * @file QGSJetII.hpp + * + * Includes all the parts of the QGSJetII model. Defines the InteractionProcess<TModel> + * classes needed for the ProcessSequence. + */ + +namespace corsika::qgsjetII { + /** + * @brief qgsjetII::Interaction is the process for ProcessSequence. + * + * The qgsjetII::InteractionModel is wrapped as an InteractionProcess here in order + * to provide all the functions for ProcessSequence. + */ + class Interaction : public InteractionModel, public InteractionProcess<Interaction> {}; +} // namespace corsika::qgsjetII diff --git a/corsika/modules/Sibyll.hpp b/corsika/modules/Sibyll.hpp index 401766122..9737e260d 100644 --- a/corsika/modules/Sibyll.hpp +++ b/corsika/modules/Sibyll.hpp @@ -18,7 +18,7 @@ /** * @file Sibyll.hpp * - * Includes all the parts of the Sibyll model. Defines the InteractoinProcess<TModel> + * Includes all the parts of the Sibyll model. Defines the InteractionProcess<TModel> * classes needed for the ProcessSequence. */ @@ -26,7 +26,7 @@ namespace corsika::sibyll { /** * @brief sibyll::Interaction is the process for ProcessSequence. * - * The sibyll::Model is wrapped as an InteractionProcess here in order + * The sibyll::InteractionModel is wrapped as an InteractionProcess here in order * to provide all the functions for ProcessSequence. */ class Interaction : public InteractionModel, public InteractionProcess<Interaction> {}; diff --git a/corsika/modules/qgsjetII/Interaction.hpp b/corsika/modules/qgsjetII/Interaction.hpp deleted file mode 100644 index 0030de2fc..000000000 --- a/corsika/modules/qgsjetII/Interaction.hpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * (c) Copyright 2020 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/framework/core/ParticleProperties.hpp> -#include <corsika/framework/core/PhysicalUnits.hpp> -#include <corsika/framework/random/RNGManager.hpp> -#include <corsika/framework/process/InteractionProcess.hpp> -#include <corsika/modules/qgsjetII/ParticleConversion.hpp> -#include <corsika/framework/utility/CorsikaData.hpp> - -#include <boost/filesystem/path.hpp> - -#include <qgsjet-II-04.hpp> -#include <string> - -namespace corsika::qgsjetII { - - class Interaction : public corsika::InteractionProcess<Interaction> { - - public: - Interaction(boost::filesystem::path dataPath = corsika_data("QGSJetII")); - ~Interaction(); - - bool wasInitialized() { return initialized_; } - unsigned int getMaxTargetMassNumber() const { return maxMassNumber_; } - bool isValidTarget(corsika::Code TargetId) const { - return is_nucleus(TargetId) && (get_nucleus_A(TargetId) < maxMassNumber_); - } - - CrossSectionType getCrossSection(const Code, const Code, const HEPEnergyType, - const unsigned int Abeam = 0, - const unsigned int Atarget = 0) const; - - template <typename TParticle> - GrammageType getInteractionLength(TParticle const&) const; - - /** - In this function QGSJETII is called to produce one event. The - event is copied (and boosted) into the shower lab frame. - */ - - template <typename TSecondaryView> - void doInteraction(TSecondaryView&); - - private: - int count_ = 0; - bool initialized_ = false; - QgsjetIIHadronType alternate_ = - QgsjetIIHadronType::PiPlusType; // for pi0, rho0 projectiles - - corsika::default_prng_type& rng_ = - corsika::RNGManager<>::getInstance().getRandomStream("qgsjet"); - static unsigned int constexpr maxMassNumber_ = 208; - }; - -} // namespace corsika::qgsjetII - -#include <corsika/detail/modules/qgsjetII/Interaction.inl> diff --git a/corsika/modules/qgsjetII/InteractionModel.hpp b/corsika/modules/qgsjetII/InteractionModel.hpp new file mode 100644 index 000000000..4ec1bf6a2 --- /dev/null +++ b/corsika/modules/qgsjetII/InteractionModel.hpp @@ -0,0 +1,77 @@ +/* + * (c) Copyright 2020 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/modules/qgsjetII/ParticleConversion.hpp> +#include <qgsjet-II-04.hpp> + +#include <corsika/framework/core/ParticleProperties.hpp> +#include <corsika/framework/core/PhysicalUnits.hpp> +#include <corsika/framework/random/RNGManager.hpp> +#include <corsika/framework/utility/COMBoost.hpp> +#include <corsika/framework/utility/CorsikaData.hpp> + +#include <boost/filesystem/path.hpp> + +namespace corsika::qgsjetII { + + class InteractionModel { + + public: + InteractionModel(boost::filesystem::path dataPath = corsika_data("QGSJetII")); + ~InteractionModel(); + + /** + * Throws exception if invalid system is passed. + * + * @param beamId + * @param targetId + */ + void isValid(Code const beamId, Code const targetId) const; + + /** + * Return the QGSJETII inelastic/production cross section. + * + * This cross section must correspond to the process described in doInteraction. + * Allowed targets are: nuclei or single nucleons (p,n,hydrogen). + * + * @param projectile is the Code of the projectile + * @param target is the Code of the target + * @param sqrtSnn is the center-of-mass energy (per nucleon pair) + * @param Aprojectile is the mass number of the projectils, if it is a nucleus + * @param Atarget is the mass number of the target, if it is a nucleus + * + * @return inelastic cross section. + */ + CrossSectionType getCrossSection(Code const projectile, Code const target, + FourMomentum const& projectileP4, + FourMomentum const& targetP4) const; + + /** + * In this function QGSJETII is called to produce one event. + * + * The event is copied (and boosted) into the shower lab frame. + */ + template <typename TSecondaries> + void doInteraction(TSecondaries&, Code const projectile, Code const target, + FourMomentum const& projectileP4, FourMomentum const& targetP4); + + private: + int count_ = 0; + QgsjetIIHadronType alternate_ = + QgsjetIIHadronType::PiPlusType; // for pi0, rho0 projectiles + + corsika::default_prng_type& rng_ = + corsika::RNGManager<>::getInstance().getRandomStream("qgsjet"); + static size_t constexpr maxMassNumber_ = 208; + }; + +} // namespace corsika::qgsjetII + +#include <corsika/detail/modules/qgsjetII/InteractionModel.inl> diff --git a/corsika/modules/qgsjetII/ParticleConversion.hpp b/corsika/modules/qgsjetII/ParticleConversion.hpp index 3b4f689b8..0a3ff8c08 100644 --- a/corsika/modules/qgsjetII/ParticleConversion.hpp +++ b/corsika/modules/qgsjetII/ParticleConversion.hpp @@ -15,13 +15,13 @@ namespace corsika::qgsjetII { /** - These are the possible secondaries produced by QGSJetII + * These are the possible secondaries produced by QGSJetII. */ enum class QgsjetIICode : int8_t; using QgsjetIICodeIntType = std::underlying_type<QgsjetIICode>::type; /** - These are the possible projectile for which QGSJetII knwos cross section + * These are the possible projectile for which QGSJetII knwos cross section. */ enum class QgsjetIIXSClass : int8_t { CannotInteract = 0, @@ -32,7 +32,7 @@ namespace corsika::qgsjetII { using QgsjetIIXSClassIntType = std::underlying_type<QgsjetIIXSClass>::type; /** - These are the only possible projectile types in QGSJetII + * These are the only possible projectile types in QGSJetII. */ enum class QgsjetIIHadronType : int8_t { UndefinedType = 0, @@ -58,7 +58,7 @@ namespace corsika::qgsjetII { namespace corsika::qgsjetII { - QgsjetIICode constexpr convertToQgsjetII(Code pCode) { + QgsjetIICode constexpr convertToQgsjetII(Code const pCode) { return corsika2qgsjetII[static_cast<CodeIntType>(pCode)]; } diff --git a/corsika/modules/sibyll/InteractionModel.hpp b/corsika/modules/sibyll/InteractionModel.hpp index 2b4191368..91b4c98a9 100644 --- a/corsika/modules/sibyll/InteractionModel.hpp +++ b/corsika/modules/sibyll/InteractionModel.hpp @@ -48,7 +48,7 @@ namespace corsika::sibyll { HEPEnergyType const sqrtSnn) const; /** - * @brief returns inelastic AND elastic cross sections. + * Returns inelastic AND elastic cross sections. * * These cross sections must correspond to the process described in doInteraction * AND elastic scattering (sigma_tot = sigma_inel + sigma_el). Allowed targets are: @@ -68,7 +68,7 @@ namespace corsika::sibyll { FourMomentum const& targetP4) const; /** - * @brief returns inelastic (production) cross section. + * Returns inelastic (production) cross section. * * This cross section must correspond to the process described in doInteraction. * Allowed targets are: nuclei or single nucleons (p,n,hydrogen). diff --git a/tests/modules/CMakeLists.txt b/tests/modules/CMakeLists.txt index 496deb3eb..5d6ec770f 100644 --- a/tests/modules/CMakeLists.txt +++ b/tests/modules/CMakeLists.txt @@ -4,7 +4,7 @@ set (test_modules_sources testTracking.cpp ## testExecTime.cpp --> needs to be fixed, see #326 testObservationPlane.cpp - #testQGSJetII.cpp + testQGSJetII.cpp #testPythia8.cpp #testUrQMD.cpp #testCONEX.cpp diff --git a/tests/modules/testQGSJetII.cpp b/tests/modules/testQGSJetII.cpp index 84f1b4ebe..2a8cd57a8 100644 --- a/tests/modules/testQGSJetII.cpp +++ b/tests/modules/testQGSJetII.cpp @@ -6,8 +6,7 @@ * the license. */ -#include <corsika/modules/qgsjetII/Interaction.hpp> -#include <corsika/modules/qgsjetII/ParticleConversion.hpp> +#include <corsika/modules/QGSJetII.hpp> #include <corsika/framework/core/ParticleProperties.hpp> #include <corsika/framework/core/PhysicalUnits.hpp> @@ -49,6 +48,7 @@ auto sumMomentum(TStackView const& view, CoordinateSystemPtr const& vCS) { TEST_CASE("QgsjetII", "[processes]") { logging::set_level(logging::level::info); + RNGManager<>::getInstance().registerRandomStream("qgsjet"); SECTION("Corsika -> QgsjetII") { CHECK(corsika::qgsjetII::convertToQgsjetII(PiMinus::code) == @@ -91,6 +91,14 @@ TEST_CASE("QgsjetII", "[processes]") { CHECK(corsika::qgsjetII::getQgsjetIIXSCode(Code::PiMinus) == corsika::qgsjetII::QgsjetIIXSClass::LightMesons); } + + SECTION("valid") { + + corsika::qgsjetII::InteractionModel model; + + CHECK_THROWS(model.isValid(Code::Electron, Code::Proton)); + CHECK_THROWS(model.isValid(Code::Proton, Code::Electron)); + } } #include <corsika/framework/geometry/Point.hpp> @@ -115,25 +123,23 @@ TEST_CASE("QgsjetIIInterface", "interaction,processes") { logging::set_level(logging::level::info); auto [env, csPtr, nodePtr] = setup::testing::setup_environment(Code::Oxygen); + auto const& cs = *csPtr; [[maybe_unused]] auto const& env_dummy = env; [[maybe_unused]] auto const& node_dummy = nodePtr; - RNGManager<>::getInstance().registerRandomStream("qgsjet"); - SECTION("InteractionInterface") { auto [stackPtr, secViewPtr] = setup::testing::setup_stack( Code::Proton, 110_GeV, (setup::Environment::BaseNodeType* const)nodePtr, *csPtr); setup::StackView& view = *(secViewPtr.get()); - auto particle = stackPtr->first(); auto projectile = secViewPtr->getProjectile(); auto const projectileMomentum = projectile.getMomentum(); - corsika::qgsjetII::Interaction model; - model.doInteraction(view); - [[maybe_unused]] const GrammageType length = model.getInteractionLength(particle); - - CHECK(length / (1_g / square(1_cm)) == Approx(93.04).margin(0.1)); + corsika::qgsjetII::InteractionModel model; + model.doInteraction(view, Code::Proton, Code::Oxygen, + {sqrt(static_pow<2>(110_GeV) + static_pow<2>(Proton::mass)), + MomentumVector{cs, 110_GeV, 0_GeV, 0_GeV}}, + {Oxygen::mass, MomentumVector{cs, {0_eV, 0_eV, 0_eV}}}); /* ********************************** As it turned out already two times (#291 and #307) that the detailed output of @@ -152,24 +158,25 @@ TEST_CASE("QgsjetIIInterface", "interaction,processes") { SECTION("InteractionInterface Nuclei") { + HEPEnergyType const P0 = 20100_GeV; + MomentumVector const plab = MomentumVector(cs, {P0, 0_eV, 0_eV}); + Code const pid = get_nucleus_code(60, 30); auto [stackPtr, secViewPtr] = setup::testing::setup_stack( - get_nucleus_code(60, 30), 20100_GeV, - (setup::Environment::BaseNodeType* const)nodePtr, *csPtr); + pid, P0, (setup::Environment::BaseNodeType* const)nodePtr, *csPtr); setup::StackView& view = *(secViewPtr.get()); - auto particle = stackPtr->first(); - auto projectile = secViewPtr->getProjectile(); - auto const projectileMomentum = projectile.getMomentum(); - corsika::qgsjetII::Interaction model; - model.doInteraction(view); // this also should produce some fragments + HEPEnergyType const Elab = sqrt(static_pow<2>(P0) + static_pow<2>(get_mass(pid))); + FourMomentum const projectileP4(Elab, plab); + FourMomentum const targetP4(Oxygen::mass, MomentumVector(cs, {0_eV, 0_eV, 0_eV})); + view.clear(); + + corsika::qgsjetII::InteractionModel model; + model.doInteraction(view, pid, Code::Oxygen, projectileP4, + targetP4); // this also should produce some fragments CHECK(view.getSize() == Approx(300).margin(150)); // this is not physics validation int countFragments = 0; for (auto const& sec : view) { countFragments += (is_nucleus(sec.getPID())); } CHECK(countFragments == Approx(4).margin(2)); // this is not physics validation - [[maybe_unused]] const GrammageType length = model.getInteractionLength(particle); - - CHECK(length / (1_g / square(1_cm)) == - Approx(12).margin(2)); // this is not physics validation } SECTION("Heavy nuclei") { @@ -178,38 +185,33 @@ TEST_CASE("QgsjetIIInterface", "interaction,processes") { get_nucleus_code(1000, 1000), 1100_GeV, (setup::Environment::BaseNodeType* const)nodePtr, *csPtr); setup::StackView& view = *(secViewPtr.get()); - auto particle = stackPtr->first(); auto projectile = secViewPtr->getProjectile(); auto const projectileMomentum = projectile.getMomentum(); - corsika::qgsjetII::Interaction model; + corsika::qgsjetII::InteractionModel model; + FourMomentum const aP4(100_GeV, {cs, 99_GeV, 0_GeV, 0_GeV}); + FourMomentum const bP4(1_TeV, {cs, 0.9_TeV, 0_GeV, 0_GeV}); + + CHECK_THROWS(model.getCrossSection(get_nucleus_code(10, 5), + get_nucleus_code(1000, 500), aP4, bP4)); + CHECK_THROWS(model.getCrossSection(Code::Nucleus, Code::Nucleus, aP4, bP4)); CHECK_THROWS( - model.getCrossSection(Code::Nucleus, Code::Nucleus, 100_GeV, 10., 1000.)); - CHECK_THROWS( - model.getCrossSection(Code::Nucleus, Code::Nucleus, 100_GeV, 1000., 10.)); - CHECK_THROWS(model.doInteraction(view)); - CHECK_THROWS(model.getInteractionLength(particle)); + model.doInteraction(view, get_nucleus_code(1000, 500), Code::Oxygen, aP4, bP4)); } SECTION("Allowed Particles") { - { // electron - auto [stackPtr, secViewPtr] = setup::testing::setup_stack( - Code::Electron, 100_GeV, (setup::Environment::BaseNodeType* const)nodePtr, - *csPtr); - [[maybe_unused]] setup::StackView& view = *(secViewPtr.get()); - auto particle = stackPtr->first(); - corsika::qgsjetII::Interaction model; - GrammageType const length = model.getInteractionLength(particle); - CHECK(length / (1_g / square(1_cm)) == std::numeric_limits<double>::infinity()); - } + { // pi0 is internally converted into pi+/pi- auto [stackPtr, secViewPtr] = setup::testing::setup_stack( Code::Pi0, 1000_GeV, (setup::Environment::BaseNodeType* const)nodePtr, *csPtr); [[maybe_unused]] setup::StackView& view = *(secViewPtr.get()); [[maybe_unused]] auto particle = stackPtr->first(); - corsika::qgsjetII::Interaction model; - model.doInteraction(view); + corsika::qgsjetII::InteractionModel model; + model.doInteraction(view, Code::Pi0, Code::Oxygen, + {sqrt(static_pow<2>(1_TeV) + static_pow<2>(Pi0::mass)), + MomentumVector{cs, 1_TeV, 0_GeV, 0_GeV}}, + {Oxygen::mass, MomentumVector{cs, 0_eV, 0_eV, 0_eV}}); CHECK(view.getSize() == Approx(10).margin(8)); // this is not physics validation } { // rho0 is internally converted into pi-/pi+ @@ -217,8 +219,11 @@ TEST_CASE("QgsjetIIInterface", "interaction,processes") { Code::Rho0, 1000_GeV, (setup::Environment::BaseNodeType* const)nodePtr, *csPtr); [[maybe_unused]] setup::StackView& view = *(secViewPtr.get()); [[maybe_unused]] auto particle = stackPtr->first(); - corsika::qgsjetII::Interaction model; - model.doInteraction(view); + corsika::qgsjetII::InteractionModel model; + model.doInteraction(view, Code::Rho0, Code::Oxygen, + {sqrt(static_pow<2>(1_TeV) + static_pow<2>(Rho0::mass)), + MomentumVector{cs, 1_TeV, 0_GeV, 0_GeV}}, + {Oxygen::mass, MomentumVector{cs, 0_eV, 0_eV, 0_eV}}); CHECK(view.getSize() == Approx(25).margin(20)); // this is not physics validation } { // Lambda is internally converted into neutron @@ -227,8 +232,11 @@ TEST_CASE("QgsjetIIInterface", "interaction,processes") { *csPtr); [[maybe_unused]] setup::StackView& view = *(secViewPtr.get()); [[maybe_unused]] auto particle = stackPtr->first(); - corsika::qgsjetII::Interaction model; - model.doInteraction(view); + corsika::qgsjetII::InteractionModel model; + model.doInteraction(view, Code::Lambda0, Code::Oxygen, + {sqrt(static_pow<2>(100_GeV) + static_pow<2>(Lambda0::mass)), + MomentumVector{cs, 100_GeV, 0_GeV, 0_GeV}}, + {Oxygen::mass, MomentumVector{cs, 0_eV, 0_eV, 0_eV}}); CHECK(view.getSize() == Approx(25).margin(20)); // this is not physics validation } { // AntiLambda is internally converted into anti neutron @@ -237,8 +245,11 @@ TEST_CASE("QgsjetIIInterface", "interaction,processes") { *csPtr); [[maybe_unused]] setup::StackView& view = *(secViewPtr.get()); [[maybe_unused]] auto particle = stackPtr->first(); - corsika::qgsjetII::Interaction model; - model.doInteraction(view); + corsika::qgsjetII::InteractionModel model; + model.doInteraction(view, Code::Lambda0Bar, Code::Oxygen, + {sqrt(static_pow<2>(1_TeV) + static_pow<2>(Lambda0Bar::mass)), + MomentumVector{cs, 1_TeV, 0_GeV, 0_GeV}}, + {Oxygen::mass, MomentumVector{cs, 0_eV, 0_eV, 0_eV}}); CHECK(view.getSize() == Approx(70).margin(67)); // this is not physics validation } } diff --git a/tests/modules/testSibyll.cpp b/tests/modules/testSibyll.cpp index a08e33d8c..718a43601 100644 --- a/tests/modules/testSibyll.cpp +++ b/tests/modules/testSibyll.cpp @@ -88,7 +88,6 @@ TEST_CASE("Sibyll", "modules") { #include <corsika/framework/geometry/Vector.hpp> #include <corsika/framework/core/PhysicalUnits.hpp> - #include <corsika/framework/core/ParticleProperties.hpp> #include <SetupTestEnvironment.hpp> @@ -186,9 +185,9 @@ TEST_CASE("SibyllInterface", "modules") { model.setVerbose(true); HEPEnergyType const Elab = sqrt(static_pow<2>(P0) + static_pow<2>(Proton::mass)); FourMomentum const projectileP4(Elab, plab); - FourMomentum const nucleonP4(Oxygen::mass, MomentumVector(cs, {0_eV, 0_eV, 0_eV})); + FourMomentum const nucleusP4(Oxygen::mass, MomentumVector(cs, {0_eV, 0_eV, 0_eV})); view.clear(); - model.doInteraction(view, Code::Proton, Code::Oxygen, projectileP4, nucleonP4); + model.doInteraction(view, Code::Proton, Code::Oxygen, projectileP4, nucleusP4); auto const pSum = sumMomentum(view, cs); /* @@ -255,7 +254,7 @@ TEST_CASE("SibyllInterface", "modules") { Approx(0).margin(plab.getNorm() * 0.05 / 1_GeV)); CHECK(pSum.getNorm() / P0 == Approx(1).margin(0.05)); [[maybe_unused]] CrossSectionType const cx = - model.getCrossSection(Code::Proton, Code::Oxygen, projectileP4, nucleonP4); + model.getCrossSection(Code::Proton, Code::Oxygen, projectileP4, nucleusP4); CHECK(cx / 1_mb == Approx(300).margin(1)); // CHECK(view.getEntries() == 9); //! \todo: this was 20 before refactory-2020: check // "also sibyll not stable wrt. to compiler -- GitLab