diff --git a/Framework/Particles/NuclearData.xml b/Framework/Particles/NuclearData.xml index 0fff50c33839093fc8bfacb9a7632f36110a2492..73eda0ef2350aa6849df60c61a34231dd9fff869 100644 --- a/Framework/Particles/NuclearData.xml +++ b/Framework/Particles/NuclearData.xml @@ -18,19 +18,19 @@ <particle id="1000020030" name="helium3" A="3" Z="2" > </particle> -<particle id="1000020030" name="lithium" A="6" Z="3" > +<particle id="1000030070" name="lithium7" A="7" Z="3" > </particle> -<particle id="1000020030" name="beryllium" A="9" Z="4" > +<particle id="1000040090" name="beryllium9" A="9" Z="4" > </particle> -<particle id="1000020030" name="boron" A="10" Z="5" > +<particle id="1000110050" name="boron11" A="11" Z="5" > </particle> <particle id="1000060120" name="carbon" A="12" Z="6" > </particle> -<particle id="1000060120" name="carbon13" A="13" Z="6" > +<particle id="1000060130" name="carbon13" A="13" Z="6" > </particle> <particle id="1000070140" name="nitrogen" A="14" Z="7" > @@ -39,10 +39,10 @@ <particle id="1000080160" name="oxygen" A="16" Z="8" > </particle> -<particle id="1000080160" name="fluor" A="18" Z="9" > +<particle id="1000080180" name="fluor" A="18" Z="9" > </particle> -<particle id="1000100220" name="neon21" A="21" Z="10" > +<particle id="1000100210" name="neon21" A="21" Z="10" > </particle> <particle id="1000100220" name="neon" A="22" Z="10" > diff --git a/Framework/Particles/ParticleProperties.cc b/Framework/Particles/ParticleProperties.cc index 4932492ddf33028b456670e9ca2da0a5b8d0efe2..b90a744bd38f5dc2755a2f10753af2e7c7386081 100644 --- a/Framework/Particles/ParticleProperties.cc +++ b/Framework/Particles/ParticleProperties.cc @@ -27,5 +27,16 @@ namespace corsika::particles { std::ostream& operator<<(std::ostream& stream, corsika::particles::Code const p) { return stream << corsika::particles::GetName(p); } + + Code ConvertFromPDG(PDGCode p) { + static_assert(detail::conversionArray.size() % 2 == 1); + auto constexpr maxPDG{(detail::conversionArray.size() - 1) >> 1}; + auto k = static_cast<PDGCodeType>(p); + if (abs(k) <= maxPDG) { + return detail::conversionArray[k + maxPDG]; + } else { + return detail::conversionMap.at(p); + } + } } // namespace corsika::particles diff --git a/Framework/Particles/ParticleProperties.h b/Framework/Particles/ParticleProperties.h index ad1a14e620899089e94093722c630e218b8db4c2..2f5365eb0525183b2810da96e3c7b85fe9766570 100644 --- a/Framework/Particles/ParticleProperties.h +++ b/Framework/Particles/ParticleProperties.h @@ -40,14 +40,15 @@ namespace corsika::particles { * The Code enum is the actual place to define CORSIKA 8 particle codes. */ enum class Code : int16_t; + enum class PDGCode : int32_t; using CodeIntType = std::underlying_type<Code>::type; - using PDGCodeType = int32_t; + using PDGCodeType = std::underlying_type<PDGCode>::type; // forward declarations to be used in GeneratedParticleProperties int16_t constexpr GetElectricChargeNumber(Code const); corsika::units::si::ElectricChargeType constexpr GetElectricCharge(Code const); corsika::units::si::HEPMassType constexpr GetMass(Code const); - PDGCodeType constexpr GetPDG(Code const); + PDGCode constexpr GetPDG(Code const); constexpr std::string const& GetName(Code const); corsika::units::si::TimeType constexpr GetLifetime(Code const); @@ -58,46 +59,52 @@ namespace corsika::particles { #include <corsika/particles/GeneratedParticleProperties.inc> /*! - * returns mass of particle + * returns mass of particle in natural units */ corsika::units::si::HEPMassType constexpr GetMass(Code const p) { - return detail::masses[static_cast<CodeIntType const>(p)]; + return detail::masses[static_cast<CodeIntType>(p)]; } - PDGCodeType constexpr GetPDG(Code const p) { - return detail::pdg_codes[static_cast<CodeIntType const>(p)]; + /*! + * returns PDG id + */ + PDGCode constexpr GetPDG(Code const p) { + return detail::pdg_codes[static_cast<CodeIntType>(p)]; } /*! - * returns electric charge of particle / (e/3). + * returns electric charge of particle / (e/3), e.g. return 3 for a proton. */ int16_t constexpr GetElectricChargeNumber(Code const p) { - return detail::electric_charges[static_cast<CodeIntType const>(p)]; + return detail::electric_charges[static_cast<CodeIntType>(p)]; } + /*! + * returns electric charge of particle, e.g. return 1.602e-19_C for a proton. + */ corsika::units::si::ElectricChargeType constexpr GetElectricCharge(Code const p) { - return GetElectricChargeNumber(p) * (corsika::units::constants::e / 3.); + return GetElectricChargeNumber(p) * (corsika::units::constants::e * (1. / 3.)); } constexpr std::string const& GetName(Code const p) { - return detail::names[static_cast<CodeIntType const>(p)]; + return detail::names[static_cast<CodeIntType>(p)]; } corsika::units::si::TimeType constexpr GetLifetime(Code const p) { - return detail::lifetime[static_cast<CodeIntType const>(p)] * + return detail::lifetime[static_cast<CodeIntType>(p)] * corsika::units::si::second; } bool constexpr IsNucleus(Code const p) { - return detail::isNucleus[static_cast<CodeIntType const>(p)]; + return detail::isNucleus[static_cast<CodeIntType>(p)]; } int constexpr GetNucleusA(Code const p) { - return detail::nucleusA[static_cast<CodeIntType const>(p)]; + return detail::nucleusA[static_cast<CodeIntType>(p)]; } int constexpr GetNucleusZ(Code const p) { - return detail::nucleusZ[static_cast<CodeIntType const>(p)]; + return detail::nucleusZ[static_cast<CodeIntType>(p)]; } /** @@ -105,7 +112,8 @@ namespace corsika::particles { **/ std::ostream& operator<<(std::ostream& stream, corsika::particles::Code const p); - + + Code ConvertFromPDG(PDGCode); } // namespace corsika::particles #endif diff --git a/Framework/Particles/pdxml_reader.py b/Framework/Particles/pdxml_reader.py index 99544cf5029c933ef9a43478dae73d28c2efbb56..946940f7dcf54551e2888e438c6eeeae0e1659e1 100755 --- a/Framework/Particles/pdxml_reader.py +++ b/Framework/Particles/pdxml_reader.py @@ -4,6 +4,7 @@ import sys, math, itertools, re, csv, pprint import xml.etree.ElementTree as ET from collections import OrderedDict import pickle +import io GeVfm = 0.19732696312541853 c_speed_of_light = 29.9792458e10 # mm / s @@ -39,7 +40,7 @@ def parsePythia(filename): ctau = 0. else: print ("missing lifetime: " + str(pdg_id) + " " + str(name)) - sys.exit(0) + sys.exit(1) yield (pdg_id, name, mass, electric_charge, antiName, ctau/c_speed_of_light) @@ -93,42 +94,7 @@ def class_names(filename): pdg_id = int(particle.attrib["pdgID"]) map[pdg_id] = name - return map - - - -############################################################## -# -# Automatically produce a string qualifying as C++ class name -# -# This function produces names of type "DELTA_PLUS_PLUS" -# -def c_identifier(name): - orig = name - name = name.upper() - for c in "() /": - name = name.replace(c, "_") - - name = name.replace("BAR", "_BAR") - name = name.replace("0", "_0") - name = name.replace("*", "_STAR") - name = name.replace("'", "_PRIME") - name = name.replace("+", "_PLUS") - name = name.replace("-", "_MINUS") - - while True: - tmp = name.replace("__", "_") - if tmp == name: - break - else: - name = tmp - - pattern = re.compile(r'^[A-Z_][A-Z_0-9]*$') - if pattern.match(name): - return name.strip("_") - else: - raise Exception("could not generate C identifier for '{:s}'".format(orig)) - + return map ############################################################## # @@ -163,7 +129,7 @@ def c_identifier_camel(name): name = tmp name.strip("_") - # remove all "_", if this does not by accident concatenate two number + # remove all "_", if this does not by accident concatenate two numbers istart = 0 while True: i = name.find('_', istart) @@ -253,6 +219,47 @@ def read_nuclei_db(filename, particle_db, classnames): return particle_db +############################################################### +# +# build conversion table PDG -> ngc +# +def gen_conversion_PDG_ngc(particle_db): + # todo: find a optimum value, think about cache miss with array vs lookup time with map + P_MAX = 500 # the maximum PDG code that is still filled into the table + + conversionDict = dict() + conversionTable = [None] * (2*P_MAX + 1) + for cId, p in particle_db.items(): + pdg = p['pdg'] + + if abs(pdg) < P_MAX: + if conversionTable[pdg + P_MAX]: + raise Exception("table entry already occupied") + else: + conversionTable[pdg + P_MAX] = cId + else: + if pdg in conversionDict.keys(): + raise Exception(f"map entry {pdg} already occupied") + else: + conversionDict[pdg] = cId + + output = io.StringIO() + def oprint(*args, **kwargs): + print(*args, **kwargs, file=output) + + oprint(f"static std::array<Code, {len(conversionTable)}> constexpr conversionArray {{") + for ngc in conversionTable: + oprint(" Code::{0},".format(ngc if ngc else "Unknown")) + oprint("};") + oprint() + + oprint("static std::map<PDGCode, Code> const conversionMap {") + for ngc in conversionDict.values(): + oprint(f" {{PDGCode::{ngc}, Code::{ngc}}},") + oprint("};") + oprint() + + return output.getvalue() ############################################################### @@ -260,7 +267,7 @@ def read_nuclei_db(filename, particle_db, classnames): # return string with enum of all internal particle codes # def gen_internal_enum(particle_db): - string = ("enum class Code : int16_t {\n" + string = ("enum class Code : CodeIntType {\n" " FirstParticle = 1, // if you want to loop over particles, you want to start with \"1\" \n") # identifier for eventual loops... @@ -277,6 +284,20 @@ def gen_internal_enum(particle_db): return string +############################################################### +# +# return string with enum of all PDG particle codes +# +def gen_pdg_enum(particle_db): + string = "enum class PDGCode : PDGCodeType {\n" + + for cId in particle_db: + pdgCode = particle_db[cId]['pdg'] + string += " {key:s} = {code:d},\n".format(key = cId, code = pdgCode) + + string += " };\n" + + return string ############################################################### @@ -296,9 +317,9 @@ def gen_properties(particle_db): string += "};\n\n" # PDG code table - string += "static constexpr std::array<PDGCodeType const, size> pdg_codes = {\n" - for p in particle_db.values(): - string += " {pdg:d}, // {name:s}\n".format(pdg = p['pdg'], name = p['name']) + string += "static constexpr std::array<PDGCode, size> pdg_codes = {\n" + for p in particle_db.keys(): + string += f" PDGCode::{p},\n" string += "};\n" # name string table @@ -473,8 +494,10 @@ if __name__ == "__main__": with open("GeneratedParticleProperties.inc", "w") as f: print(inc_start(), file=f) print(gen_internal_enum(particle_db), file=f) + print(gen_pdg_enum(particle_db), file=f) print(detail_start(), file=f) print(gen_properties(particle_db), file=f) + print(gen_conversion_PDG_ngc(particle_db), file=f) print(detail_end(), file=f) print(gen_classes(particle_db), file=f) print(inc_end(), file=f) diff --git a/Framework/Particles/testParticles.cc b/Framework/Particles/testParticles.cc index 1ca8b2188b5004c22c3168b5ad90290aa10a8ffb..0603ea03575cb7668bed8e3e276b5c81f60e27c3 100644 --- a/Framework/Particles/testParticles.cc +++ b/Framework/Particles/testParticles.cc @@ -50,11 +50,23 @@ TEST_CASE("ParticleProperties", "[Particles]") { } SECTION("PDG") { - REQUIRE(GetPDG(Code::PiPlus) == 211); - REQUIRE(GetPDG(Code::DPlus) == 411); - REQUIRE(GetPDG(Code::NuMu) == 14); - REQUIRE(GetPDG(Code::NuE) == 12); - REQUIRE(GetPDG(Code::MuMinus) == 13); + REQUIRE(GetPDG(Code::PiPlus) == PDGCode::PiPlus); + REQUIRE(GetPDG(Code::DPlus) == PDGCode::DPlus); + REQUIRE(GetPDG(Code::NuMu) == PDGCode::NuMu); + REQUIRE(GetPDG(Code::NuE) == PDGCode::NuE); + REQUIRE(GetPDG(Code::MuMinus) == PDGCode::MuMinus); + + REQUIRE(static_cast<int>(GetPDG(Code::PiPlus)) == 211); + REQUIRE(static_cast<int>(GetPDG(Code::DPlus)) == 411); + REQUIRE(static_cast<int>(GetPDG(Code::NuMu)) == 14); + REQUIRE(static_cast<int>(GetPDG(Code::NuEBar)) == -12); + REQUIRE(static_cast<int>(GetPDG(Code::MuMinus)) == 13); + } + + SECTION("Conversion PDG -> internal") { + REQUIRE(ConvertFromPDG(PDGCode::KStarMinus) == Code::KStarMinus); + REQUIRE(ConvertFromPDG(PDGCode::MuPlus) == Code::MuPlus); + REQUIRE(ConvertFromPDG(PDGCode::SigmaStarCMinusBar) == Code::SigmaStarCMinusBar); } SECTION("Lifetimes") { @@ -70,12 +82,12 @@ TEST_CASE("ParticleProperties", "[Particles]") { } SECTION("Nuclei") { - REQUIRE(IsNucleus(Code::Gamma) == false); - REQUIRE(IsNucleus(Code::Argon) == true); - REQUIRE(IsNucleus(Code::Proton) == false); - REQUIRE(IsNucleus(Code::Hydrogen) == true); - REQUIRE(Argon::IsNucleus() == true); - REQUIRE(EtaC::IsNucleus() == false); + REQUIRE_FALSE(IsNucleus(Code::Gamma)); + REQUIRE(IsNucleus(Code::Argon)); + REQUIRE_FALSE(IsNucleus(Code::Proton)); + REQUIRE(IsNucleus(Code::Hydrogen)); + REQUIRE(Argon::IsNucleus()); + REQUIRE_FALSE(EtaC::IsNucleus()); REQUIRE(GetNucleusA(Code::Hydrogen) == 1); REQUIRE(GetNucleusA(Code::Tritium) == 3);