diff --git a/Processes/QGSJetII/Interaction.cc b/Processes/QGSJetII/Interaction.cc index 17329a2fea426ee61381013e31f98410e22c88be..98dd4b1948eb3555d0ba315e198fdfe44f5fe4be 100644 --- a/Processes/QGSJetII/Interaction.cc +++ b/Processes/QGSJetII/Interaction.cc @@ -21,9 +21,7 @@ #include <corsika/setup/SetupTrajectory.h> #include <corsika/utl/COMBoost.h> -#include <corsika/random/RNGManager.h> -#include <corsika/random/UniformRealDistribution.h> - +#include <random> #include <sstream> #include <string> #include <tuple> @@ -55,9 +53,6 @@ namespace corsika::process::qgsjetII { Interaction::~Interaction() { cout << "QgsjetII::Interaction n=" << count_ << endl; } void Interaction::Init() { - - using random::RNGManager; - // initialize QgsjetII if (!initialized_) { qgset_(); @@ -76,7 +71,7 @@ namespace corsika::process::qgsjetII { if (process::qgsjetII::CanInteract(beamId)) { - const int iBeam = process::qgsjetII::GetQgsjetIIXSCode(beamId); + const int iBeam = process::qgsjetII::GetQgsjetIIXSCodeRaw(beamId); int iTarget = 1; if (particles::IsNucleus(targetId)) { iTarget = targetA; @@ -253,56 +248,47 @@ namespace corsika::process::qgsjetII { mediumComposition.SampleTarget(cross_section_of_components, rng_); cout << "Interaction: target selected: " << targetCode << endl; - int targetQgsCode = -1; - if (particles::IsNucleus(targetCode)) - targetQgsCode = particles::GetNucleusA(targetCode); - if (targetCode == particles::Proton::GetCode()) targetQgsCode = 1; - cout << "Interaction: target qgsjetII code/A: " << targetQgsCode << endl; - if (targetQgsCode > maxMassNumber_ || targetQgsCode < 1) - throw std::runtime_error("QgsjetII target outside range."); - - int projQgsCode = 1; - if (particles::IsNucleus(corsikaBeamId)) projQgsCode = vP.GetNuclearA(); - cout << "Interaction: projectile qgsjetII code/A: " << projQgsCode << " " - << corsikaBeamId << endl; - if (projQgsCode > maxMassNumber_ || projQgsCode < 1) - throw std::runtime_error("QgsjetII target outside range."); - - // beam id for qgsjetII - QgsjetIICode qgsjet_beam_code; - if (corsikaBeamId == particles::Code::Nucleus) { - std::array<QgsjetIICode, 2> constexpr nucleons = {QgsjetIICode::Proton, - QgsjetIICode::Neutron}; + int targetMassNumber = 1; // proton + if (particles::IsNucleus(targetCode)) { // nucleus + targetMassNumber = particles::GetNucleusA(targetCode); + if (targetMassNumber > maxMassNumber_) + throw std::runtime_error("QgsjetII target mass outside range."); + } else { + if (targetCode != particles::Proton::GetCode()) + throw std::runtime_error("QgsjetII Taget not possible."); + } + cout << "Interaction: target qgsjetII code/A: " << targetMassNumber << endl; + + int projectileMassNumber = 1; // "1" means "hadron" + QgsjetIIHadronType qgsjet_hadron_type = + process::qgsjetII::GetQgsjetIIHadronType(corsikaBeamId); + if (qgsjet_hadron_type == QgsjetIIHadronType::NucleusType) { + projectileMassNumber = vP.GetNuclearA(); + if (projectileMassNumber > maxMassNumber_) + throw std::runtime_error("QgsjetII projectile mass outside range."); + std::array<QgsjetIIHadronType, 2> constexpr nucleons = { + QgsjetIIHadronType::ProtonType, QgsjetIIHadronType::NeutronType}; std::uniform_int_distribution select(0, 1); - qgsjet_beam_code = nucleons[select(rng_)]; - } else { // it is an "elementary" particle - qgsjet_beam_code = process::qgsjetII::ConvertToQgsjetII(corsikaBeamId); - // from conex - if (qgsjet_beam_code == QgsjetIICode::Pi0 or - qgsjet_beam_code == QgsjetIICode::Rho0) { // replace pi0 or rho0 with pi+/pi- - // in alternating sequence - qgsjet_beam_code = alternate_; - alternate_ = (alternate_ == QgsjetIICode::PiPlus ? QgsjetIICode::PiMinus - : QgsjetIICode::PiPlus); + 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); } - // replace lambda by neutron - if (qgsjet_beam_code == QgsjetIICode::Lambda0) - qgsjet_beam_code = QgsjetIICode::Neutron; - else if (qgsjet_beam_code == QgsjetIICode::Lambda0Bar) - qgsjet_beam_code = QgsjetIICode::AntiNeutron; - // else if (abs(qgsjet_beam_code)>6) -> throw } + cout << "Interaction: projectile qgsjetII code/A: " << projectileMassNumber << " " + << corsikaBeamId << endl; - int qgsjet_beam_code_int = static_cast<QgsjetIICodeIntType>(qgsjet_beam_code); + int qgsjet_hadron_type_int = static_cast<QgsjetIICodeIntType>(qgsjet_hadron_type); cout << "Interaction: " << " DoInteraction: E(GeV):" << projectileEnergyLab / 1_GeV << endl; count_++; - qgini_(projectileEnergyLab / 1_GeV, qgsjet_beam_code_int, projQgsCode, - targetQgsCode); - // this is from CRMC, is this REALLY needed ??? - qgini_(projectileEnergyLab / 1_GeV, qgsjet_beam_code_int, projQgsCode, - targetQgsCode); + qgini_(projectileEnergyLab / 1_GeV, qgsjet_hadron_type_int, projectileMassNumber, + targetMassNumber); qgconf_(); // bookkeeping diff --git a/Processes/QGSJetII/Interaction.h b/Processes/QGSJetII/Interaction.h index d06a078430590390070de5969b2425bb44a87d68..7df95c1517a75722c2f2e7c19cd21baa50694678 100644 --- a/Processes/QGSJetII/Interaction.h +++ b/Processes/QGSJetII/Interaction.h @@ -26,7 +26,8 @@ namespace corsika::process::qgsjetII { std::string data_path_; int count_ = 0; bool initialized_ = false; - QgsjetIICode alternate_ = QgsjetIICode::PiPlus; // for pi0, rho0 projectiles + QgsjetIIHadronType alternate_ = + QgsjetIIHadronType::PiPlusType; // for pi0, rho0 projectiles public: Interaction(const std::string& dataPath = ""); diff --git a/Processes/QGSJetII/ParticleConversion.h b/Processes/QGSJetII/ParticleConversion.h index 1a89658666deda150d5131c6bc0c01e06951174a..5828e82f583e24d2680fd9d0da9ade929b2aa455 100644 --- a/Processes/QGSJetII/ParticleConversion.h +++ b/Processes/QGSJetII/ParticleConversion.h @@ -17,9 +17,44 @@ namespace corsika::process::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 + */ + enum class QgsjetIIXSClass : int8_t { + CannotInteract = 0, + LightMesons = 1, + Baryons = 2, + Kaons = 3, + }; + using QgsjetIIXSClassIntType = std::underlying_type<QgsjetIIXSClass>::type; + + /** + These are the only possible projectile types in QGSJetII + */ + enum class QgsjetIIHadronType : int8_t { + UndefinedType = 0, + PiPlusType = +1, + PiMinusType = -1, + ProtonType = +2, + AntiProtonType = -2, + NeutronType = +3, + AntiNeutronType = -3, + KaonPlusType = +4, + KaonMinusType = -4, + Kaon0LType = +5, + Kaon0SType = -5, + // special codes, not in QGSJetII + NucleusType, + NeutralLightMesonType + }; + using QgsjetIIHadronTypeIntType = std::underlying_type<QgsjetIIHadronType>::type; + #include <corsika/process/qgsjetII/Generated.inc> QgsjetIICode constexpr ConvertToQgsjetII(corsika::particles::Code pCode) { @@ -38,17 +73,27 @@ namespace corsika::process::qgsjetII { return corsikaCode; } - int constexpr ConvertToQgsjetIIRaw(corsika::particles::Code pCode) { - return static_cast<int>(ConvertToQgsjetII(pCode)); + QgsjetIICodeIntType constexpr ConvertToQgsjetIIRaw(corsika::particles::Code pCode) { + return static_cast<QgsjetIICodeIntType>(ConvertToQgsjetII(pCode)); } - int constexpr GetQgsjetIIXSCode(corsika::particles::Code pCode) { - if (pCode == corsika::particles::Code::Nucleus) return 2; + QgsjetIIXSClass constexpr GetQgsjetIIXSCode(corsika::particles::Code pCode) { + // if (pCode == corsika::particles::Code::Nucleus) + // static_cast(QgsjetIIXSClassIntType>(); return corsika2qgsjetIIXStype[static_cast<corsika::particles::CodeIntType>(pCode)]; } + QgsjetIIXSClassIntType constexpr GetQgsjetIIXSCodeRaw(corsika::particles::Code pCode) { + return static_cast<QgsjetIIXSClassIntType>(GetQgsjetIIXSCode(pCode)); + } + bool constexpr CanInteract(corsika::particles::Code pCode) { - return (GetQgsjetIIXSCode(pCode) > 0) && (ConvertToQgsjetIIRaw(pCode) <= 5); + return GetQgsjetIIXSCode(pCode) != QgsjetIIXSClass::CannotInteract; + } + + QgsjetIIHadronType constexpr GetQgsjetIIHadronType(corsika::particles::Code pCode) { + return corsika2qgsjetIIHadronType[static_cast<corsika::particles::CodeIntType>( + pCode)]; } } // namespace corsika::process::qgsjetII diff --git a/Processes/QGSJetII/code_generator.py b/Processes/QGSJetII/code_generator.py index 3b7113ec513e28fcb823fb1693cf83f6a6b6d545..d8f9a46937c01cd2576731bd7fad002da9eb77bb 100755 --- a/Processes/QGSJetII/code_generator.py +++ b/Processes/QGSJetII/code_generator.py @@ -14,14 +14,67 @@ import pickle, sys, itertools # loads the pickled particle_db (which is an OrderedDict) +# definition of particle_db dict is: "name", "antiName", "pdg", "mass", "electric_charge", "lifetime", "ngc_code", "isNucleus", "isHadron" def load_particledb(filename): with open(filename, "rb") as f: particle_db = pickle.load(f) return particle_db +def set_default_qgsjetII_definition(particle_db): + for identifier, pData in particle_db.items(): + # the cross-section types + xsType = "CannotInteract" + hadronType = "UndefinedType" + if (pData['isNucleus']): + xsType = "Baryons" + hadronType = "NucleusType" + elif (pData['isHadron']): + pdg = abs(pData['pdg']) + anti = pData['pdg'] < 0 + isBaryon = (1000 <= pdg < 4000) + charge = pData['electric_charge'] + if (pdg>=100 and pdg<300 and pdg!=130): # light mesons + xsType = "LightMesons" + if (charge==0): + hadronType = "NeutralLightMesonType" + else: + if (charge>0): + hadronType = "PiPlusType" + else: + hadronType = "PiMinusType" + elif ((pdg>=300 and pdg<400) or pdg in [130, 10313, 10323]): # kanos + xsType = "Kaons" + if (charge>0): + hadronType = "KaonPlusType" + else: + hadronType = "KaonMinusType" + if (charge==0): + hadronType = "Kaon0SType" + if (pdg == 130): + hadronType = "Kaon0LType" + elif (pdg == 310): + hadronType = "Kaon0SType" + elif (isBaryon or pData['isNucleus']): # baryons + xsType = "Baryons" + if (charge==0): + if (anti): + hadronType = "AntiNeutronType" + else: + hadronType = "NeutronType" + else: + if (charge>0): + hadronType = "ProtonType" + else: + hadronType = "AntiProtonType" + # all othe not-captured cased are hopefully irrelevant + -# + pData['qgsjetII_xsType'] = xsType + pData['qgsjetII_hadronType'] = hadronType + + +# read the qgsjet-codes data file def read_qgsjetII_codes(filename, particle_db): with open(filename) as f: for line in f: @@ -33,13 +86,11 @@ def read_qgsjetII_codes(filename, particle_db): identifier, model_code, xsType = line.split() try: particle_db[identifier]["qgsjetII_code"] = int(model_code) - particle_db[identifier]["qgsjetII_xsType"] = int(xsType) + particle_db[identifier]["qgsjetII_xsType"] = xsType except KeyError as e: raise Exception("Identifier '{:s}' not found in particle_db".format(identifier)) - - # generates the enum to access qgsjetII particles by readable names def generate_qgsjetII_enum(particle_db): output = "enum class QgsjetIICode : int8_t {\n" @@ -50,7 +101,6 @@ def generate_qgsjetII_enum(particle_db): return output - # generates the look-up table to convert corsika codes to qgsjetII codes def generate_corsika2qgsjetII(particle_db): string = "std::array<QgsjetIICodeIntType, {:d}> constexpr corsika2qgsjetII = {{\n".format(len(particle_db)) @@ -61,13 +111,22 @@ def generate_corsika2qgsjetII(particle_db): return string - # generates the look-up table to convert corsika codes to qgsjetII codes def generate_corsika2qgsjetII_xsType(particle_db): - string = "std::array<int, {:d}> constexpr corsika2qgsjetIIXStype = {{\n".format(len(particle_db)) + string = "std::array<QgsjetIIXSClass, {:d}> constexpr corsika2qgsjetIIXStype = {{\n".format(len(particle_db)) for identifier, pData in particle_db.items(): - modelCodeXS = pData.get("qgsjetII_xsType", -1) - string += " {:d}, // {:s}\n".format(modelCodeXS, identifier if modelCodeXS else identifier + " (not implemented in QGSJETII)") + modelCodeXS = pData.get("qgsjetII_xsType", "CannotInteract") + string += " QgsjetIIXSClass::{:s}, // {:s}\n".format(modelCodeXS, identifier if modelCodeXS else identifier + " (not implemented in QGSJETII)") + string += "};\n" + return string + + +# generates the look-up table to convert corsika codes to qgsjetII codes +def generate_corsika2qgsjetII_hadronType(particle_db): + string = "std::array<QgsjetIIHadronType, {:d}> constexpr corsika2qgsjetIIHadronType = {{\n".format(len(particle_db)) + for identifier, pData in particle_db.items(): + modelCode = pData.get("qgsjetII_hadronType", "UndefinedType") + string += " QgsjetIIHadronType::{:s}, // {:s}\n".format(modelCode, identifier if modelCode else identifier + " (not implemented in QGSJETII)") string += "};\n" return string @@ -98,6 +157,7 @@ def generate_qgsjetII2corsika(particle_db) : string += "};\n" return string + if __name__ == "__main__": if len(sys.argv) != 3: print("usage: {:s} <particle_db.pkl> <qgsjetII_codes.dat>".format(sys.argv[0]), file=sys.stderr) @@ -107,6 +167,7 @@ if __name__ == "__main__": particle_db = load_particledb(sys.argv[1]) read_qgsjetII_codes(sys.argv[2], particle_db) + set_default_qgsjetII_definition(particle_db) with open("Generated.inc", "w") as f: print("// this file is automatically generated\n// edit at your own risk!\n", file=f) @@ -114,3 +175,4 @@ if __name__ == "__main__": print(generate_corsika2qgsjetII(particle_db), file=f) print(generate_qgsjetII2corsika(particle_db), file=f) print(generate_corsika2qgsjetII_xsType(particle_db), file=f) + print(generate_corsika2qgsjetII_hadronType(particle_db), file=f) diff --git a/Processes/QGSJetII/qgsjet-II-04-codes.dat b/Processes/QGSJetII/qgsjet-II-04-codes.dat index 3550eed83ce3f847153b8e79f85646af0816a7e4..ff0595bf1173d91cb1b732c2f99c0b9c8264d233 100644 --- a/Processes/QGSJetII/qgsjet-II-04-codes.dat +++ b/Processes/QGSJetII/qgsjet-II-04-codes.dat @@ -1,52 +1,37 @@ # input file for particle conversion to/from QGSJet -# the format of this file is: "corsika-identifier" "qgsjet-id" - -# class 0 (cannot interact) -Electron 11 0 -Positron -11 0 - -# class 1 -Pi0 0 1 -PiPlus 1 1 -PiMinus -1 1 -# in crmc: all particles from 100 to 999 ??? -Eta 10 1 -Rho0 -10 1 - -# class 2 -#Nucleus 40 2 -Neutron 3 2 -AntiNeutron -3 2 -Proton 2 2 -AntiProton -2 2 -# in crmc: 1000 to 9999 ??? -Lambda0 6 2 -Lambda0Bar -6 2 -LambdaCPlus 9 2 -LambdaCMinusBar -9 2 - -# class 3 -K0Long -5 3 -K0 5 3 -K0Bar -5 3 -K0Short 5 3 -# ambiguity between the K0/b and K0s/l -KPlus 4 3 -KMinus -4 3 - -# class 4 -D0 8 4 -D0Bar 8 4 -DPlus 7 4 -DMinus -7 4 -#DS+/- (340) -#etac (440) -#j/psi (441) -#h_1c0 -#psi' -#Xi_0c0 -#Xi_1c0 -#Xi_2c0 - - +# the format of this file is: "corsika-identifier" "qgsjet-id" "xs-class" + +# Note, we list here only the particles, which are produced by +# QGSJetII as secondaries. There is additional mapping of corsika +# particles on QGSJetII "xs-class"es and "hadron-type"s, which are +# programmed in code_generator.py + +# class 1 (-> as pions) +Pi0 0 LightMesons +PiPlus 1 LightMesons +PiMinus -1 LightMesons +Eta 10 LightMesons +Rho0 -10 LightMesons + +# class 2 (-> as proton) +Neutron 3 Baryons +AntiNeutron -3 Baryons +Proton 2 Baryons +AntiProton -2 Baryons +Lambda0 6 Baryons +Lambda0Bar -6 Baryons +LambdaCPlus 9 Baryons +LambdaCMinusBar -9 Baryons + +# class 3 (-> as kaon) +K0Short 5 Kaons +K0Long -5 Kaons +KPlus 4 Kaons +KMinus -4 Kaons + +# class 4 (-> charmed mesons, not in qgsjetII) +D0 8 Charmed +D0Bar -8 Charmed +DPlus 7 Charmed +DMinus -7 Charmed diff --git a/Processes/QGSJetII/qgsjet-II-04.f b/Processes/QGSJetII/qgsjet-II-04.f index 40b2a4ccbc8da8506f5a6bafec36f190bec9b7bb..a3efe5977f9037e6e80eb3ec44864c71e29a6e2a 100644 --- a/Processes/QGSJetII/qgsjet-II-04.f +++ b/Processes/QGSJetII/qgsjet-II-04.f @@ -2051,7 +2051,7 @@ c216 format(2x,'qgaini: integrated cut Pomeron eikonals') c============================================================================= subroutine qgini(e0n,icp0,iap,iat) -c----------------------------------------------------------------------------- +c---------------------s-------------------------------------------------------- c additional initialization procedure c e0n - interaction energy (per hadron/nucleon), c icp0 - hadron type (+-1 - pi+-, +-2 - p(p~), +-3 - n(n~), diff --git a/Processes/QGSJetII/testQGSJetII.cc b/Processes/QGSJetII/testQGSJetII.cc index 4f284e056992a9987ae4cd70b4a5f471f5caca6a..8258b3c5eae4c52ab94633adae74f48a673a3d4b 100644 --- a/Processes/QGSJetII/testQGSJetII.cc +++ b/Processes/QGSJetII/testQGSJetII.cc @@ -49,10 +49,14 @@ TEST_CASE("QgsjetII", "[processes]") { SECTION("cross-section type") { - REQUIRE(process::qgsjetII::GetQgsjetIIXSCode(particles::Code::Neutron) == 2); - REQUIRE(process::qgsjetII::GetQgsjetIIXSCode(particles::Code::K0Long) == 3); - REQUIRE(process::qgsjetII::GetQgsjetIIXSCode(particles::Code::Proton) == 2); - REQUIRE(process::qgsjetII::GetQgsjetIIXSCode(particles::Code::PiMinus) == 1); + REQUIRE(process::qgsjetII::GetQgsjetIIXSCode(particles::Code::Neutron) == + process::qgsjetII::QgsjetIIXSClass::Baryons); + REQUIRE(process::qgsjetII::GetQgsjetIIXSCode(particles::Code::K0Long) == + process::qgsjetII::QgsjetIIXSClass::Kaons); + REQUIRE(process::qgsjetII::GetQgsjetIIXSCode(particles::Code::Proton) == + process::qgsjetII::QgsjetIIXSClass::Baryons); + REQUIRE(process::qgsjetII::GetQgsjetIIXSCode(particles::Code::PiMinus) == + process::qgsjetII::QgsjetIIXSClass::LightMesons); } }