From 2cf22feb36ab17adf65ccdb567e787187ba5b80a Mon Sep 17 00:00:00 2001 From: Amanda Lund Date: Fri, 12 Sep 2025 19:55:45 +0000 Subject: [PATCH 1/7] Import decay tables --- src/celeritas/Types.hh | 14 ++++++ src/celeritas/ext/GeantImporter.cc | 76 ++++++++++++++++++++++++++++++ src/celeritas/inp/Physics.hh | 24 ++++++++++ src/celeritas/io/ImportData.hh | 2 +- 4 files changed, 115 insertions(+), 1 deletion(-) diff --git a/src/celeritas/Types.hh b/src/celeritas/Types.hh index 9232c0a776..244f602639 100644 --- a/src/celeritas/Types.hh +++ b/src/celeritas/Types.hh @@ -191,6 +191,20 @@ enum class MscStepLimitAlgorithm size_, }; +//---------------------------------------------------------------------------// +//! Decay channel type +enum class DecayChannelType +{ + dalitz, + kl3, + muon, + neutron_beta, + phase_space, + pion_radiative, + tau_leptonic, + size_ +}; + //---------------------------------------------------------------------------// //! Nuclear form factor model for Coulomb scattering enum class NuclearFormFactorType diff --git a/src/celeritas/ext/GeantImporter.cc b/src/celeritas/ext/GeantImporter.cc index c06fcb9c6a..56fb9bf5ff 100644 --- a/src/celeritas/ext/GeantImporter.cc +++ b/src/celeritas/ext/GeantImporter.cc @@ -18,18 +18,24 @@ #include #include #include +#include +#include +#include #include #include #include #include #include +#include #include #include #include #include #include #include +#include #include +#include #include #include #include @@ -37,6 +43,8 @@ #include #include #include +#include +#include #include #include #include @@ -51,9 +59,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -171,6 +181,8 @@ struct ProcessFilter return (which & DataSelection::em); case G4ProcessType::fOptical: return (which & DataSelection::optical); + case G4ProcessType::fDecay: + return (which & (DataSelection::em | DataSelection::hadron)); case G4ProcessType::fHadronic: return (which & DataSelection::hadron); default: @@ -388,6 +400,29 @@ to_form_factor_type(G4NuclearFormfactorType const& form_factor_type) CELER_ASSERT_UNREACHABLE(); } +//---------------------------------------------------------------------------// +/*! + * Get a \c DecayChannelType from a \c G4VDecayChannel subclass. + */ +DecayChannelType to_decay_channel_type(G4VDecayChannel const* channel) +{ + if (dynamic_cast(channel)) + return DecayChannelType::dalitz; + if (dynamic_cast(channel)) + return DecayChannelType::kl3; + if (dynamic_cast(channel)) + return DecayChannelType::muon; + if (dynamic_cast(channel)) + return DecayChannelType::neutron_beta; + if (dynamic_cast(channel)) + return DecayChannelType::phase_space; + if (dynamic_cast(channel)) + return DecayChannelType::pion_radiative; + if (dynamic_cast(channel)) + return DecayChannelType::tau_leptonic; + CELER_ASSERT_UNREACHABLE(); +} + //---------------------------------------------------------------------------// /*! * Return a populated \c inp::Particle vector. @@ -929,6 +964,38 @@ std::vector import_regions() return result; } +//---------------------------------------------------------------------------// +/*! + * Import a decay table from a Geant4 particle definition. + */ +inp::DecayPhysics::DecayTable import_decay_table(G4ParticleDefinition const& p) +{ + inp::DecayPhysics::DecayTable result; + + auto* g4_table = p.GetDecayTable(); + CELER_ASSERT(g4_table); + + for (auto channel_idx : range(g4_table->entries())) + { + auto* g4_channel = (*g4_table)[channel_idx]; + CELER_ASSERT(g4_channel); + + inp::DecayChannel channel; + channel.type = to_decay_channel_type(g4_channel); + channel.branching_ratio = g4_channel->GetBR(); + for (auto daughter_idx : range(g4_channel->GetNumberOfDaughters())) + { + auto const* daughter = g4_channel->GetDaughter(daughter_idx); + channel.daughters.push_back(PDGNumber(daughter->GetPDGEncoding())); + } + result.push_back(std::move(channel)); + } + + CELER_LOG(debug) << "Imported decay table for particle " + << p.GetParticleName(); + return result; +} + //---------------------------------------------------------------------------// /*! * Return a populated \c ImportProcess vector. @@ -947,6 +1014,7 @@ auto import_processes(GeantImporter::DataSelection selected, auto& processes = imported.processes; auto& msc_models = imported.msc_models; auto& optical_models = imported.optical_models; + auto& decay = imported.decay; static celeritas::TypeDemangler const demangle_process; std::unordered_map visited; @@ -956,6 +1024,14 @@ auto import_processes(GeantImporter::DataSelection selected, auto append_process = [&](G4ParticleDefinition const& particle, G4VProcess const& process) -> void { + if (dynamic_cast(&process)) + { + // Store decay table if decay process is enabled for this particle + decay.tables.insert({PDGNumber(particle.GetPDGEncoding()), + import_decay_table(particle)}); + return; + } + // Check for duplicate processes auto [prev, inserted] = visited.insert({&process, &particle}); diff --git a/src/celeritas/inp/Physics.hh b/src/celeritas/inp/Physics.hh index 89659979ec..b6503f0852 100644 --- a/src/celeritas/inp/Physics.hh +++ b/src/celeritas/inp/Physics.hh @@ -14,6 +14,7 @@ #include "corecel/io/Label.hh" #include "celeritas/Types.hh" #include "celeritas/phys/AtomicNumber.hh" +#include "celeritas/phys/PDGNumber.hh" #include "PhysicsProcess.hh" #include "ProcessBuilder.hh" @@ -95,6 +96,29 @@ struct OpticalPhysics } }; +//---------------------------------------------------------------------------// +/*! + * Branching ratio and daughters for a decay channel. + */ +struct DecayChannel +{ + DecayChannelType type{DecayChannelType::size_}; + double branching_ratio{}; + std::vector daughters; +}; + +//---------------------------------------------------------------------------// +/*! + * Decay processes and options. + */ +struct DecayPhysics +{ + using DecayTable = std::vector; + + //! Decay channels for particles for which decay is enabled + std::unordered_map tables; +}; + //---------------------------------------------------------------------------// /*! * Set up physics options. diff --git a/src/celeritas/io/ImportData.hh b/src/celeritas/io/ImportData.hh index 93bba504dd..f3d1de0136 100644 --- a/src/celeritas/io/ImportData.hh +++ b/src/celeritas/io/ImportData.hh @@ -113,7 +113,7 @@ struct ImportData // Physics groups inp::OpticalPhysics optical_physics; - + inp::DecayPhysics decay; //!@} }; From 8f9a3285ed08c6bb9812d1fe2c5520c6acd40475 Mon Sep 17 00:00:00 2001 From: Amanda Lund Date: Wed, 17 Sep 2025 13:29:40 +0000 Subject: [PATCH 2/7] Refactor to store decay channels in particle input --- src/celeritas/ext/GeantImporter.cc | 26 ++++++++++++++----- src/celeritas/ext/RootInterfaceLinkDef.h | 1 + src/celeritas/inp/Particle.hh | 14 ++++++++++ src/celeritas/inp/Physics.hh | 18 +++---------- test/celeritas/MockTestBase.cc | 15 +++++++---- test/celeritas/SimpleTestBase.cc | 6 +++-- test/celeritas/em/CoulombScattering.test.cc | 9 ++++--- test/celeritas/em/Rayleigh.test.cc | 2 +- .../em/distribution/EnergyLossHelper.test.cc | 6 +++-- test/celeritas/field/FieldPropagator.test.cc | 9 ++++--- test/celeritas/io/EventIOTestBase.cc | 14 ++++++---- test/celeritas/neutron/NeutronTestBase.cc | 4 +-- test/celeritas/optical/OpticalTestBase.cc | 6 +++-- test/celeritas/phys/CutoffParams.test.cc | 11 +++++--- test/celeritas/phys/InteractorHostTestBase.cc | 14 ++++++---- test/celeritas/phys/Particle.test.cc | 11 +++++--- test/celeritas/phys/Physics.test.cc | 5 ++-- test/celeritas/phys/PrimaryGenerator.test.cc | 5 ++-- test/celeritas/phys/ProcessBuilder.test.cc | 3 ++- 19 files changed, 114 insertions(+), 65 deletions(-) diff --git a/src/celeritas/ext/GeantImporter.cc b/src/celeritas/ext/GeantImporter.cc index 56fb9bf5ff..17e9da428b 100644 --- a/src/celeritas/ext/GeantImporter.cc +++ b/src/celeritas/ext/GeantImporter.cc @@ -453,6 +453,8 @@ import_particles(GeantImporter::DataSelection::Flags particle_flags) result.mass = particle_view.mass(); result.charge = particle_view.charge(); result.decay_constant = particle_view.decay_constant(); + result.decay_table + = import_decay_table(*(particle_iterator.value())); if (G4VERSION_NUMBER < 1070 && particle_view.is_optical_photon()) { @@ -968,13 +970,15 @@ std::vector import_regions() /*! * Import a decay table from a Geant4 particle definition. */ -inp::DecayPhysics::DecayTable import_decay_table(G4ParticleDefinition const& p) +std::vector import_decay_table(G4ParticleDefinition const& p) { - inp::DecayPhysics::DecayTable result; - auto* g4_table = p.GetDecayTable(); - CELER_ASSERT(g4_table); + if (!g4_table) + { + return {}; + } + std::vector result; for (auto channel_idx : range(g4_table->entries())) { auto* g4_channel = (*g4_table)[channel_idx]; @@ -986,6 +990,15 @@ inp::DecayPhysics::DecayTable import_decay_table(G4ParticleDefinition const& p) for (auto daughter_idx : range(g4_channel->GetNumberOfDaughters())) { auto const* daughter = g4_channel->GetDaughter(daughter_idx); + if (!daughter) + { + CELER_LOG(warning) + << "Ignoring decay table for particle " + << p.GetParticleName() << " since daughter '" + << g4_channel->GetDaughterName(daughter_idx) + << "' is not defined"; + return {}; + } channel.daughters.push_back(PDGNumber(daughter->GetPDGEncoding())); } result.push_back(std::move(channel)); @@ -1026,9 +1039,8 @@ auto import_processes(GeantImporter::DataSelection selected, G4VProcess const& process) -> void { if (dynamic_cast(&process)) { - // Store decay table if decay process is enabled for this particle - decay.tables.insert({PDGNumber(particle.GetPDGEncoding()), - import_decay_table(particle)}); + // Add decay process if enabled for this particle + decay.particles.insert({PDGNumber(particle.GetPDGEncoding())}); return; } diff --git a/src/celeritas/ext/RootInterfaceLinkDef.h b/src/celeritas/ext/RootInterfaceLinkDef.h index f3b24b7cea..8f0a74403d 100644 --- a/src/celeritas/ext/RootInterfaceLinkDef.h +++ b/src/celeritas/ext/RootInterfaceLinkDef.h @@ -45,6 +45,7 @@ // Input data +#pragma link C++ class celeritas::inp::DecayPhysics+; #pragma link C++ class celeritas::inp::FresnelReflection+; #pragma link C++ class celeritas::inp::GaussianRoughness+; #pragma link C++ class celeritas::inp::Grid+; diff --git a/src/celeritas/inp/Particle.hh b/src/celeritas/inp/Particle.hh index 36ec6714ae..7c9e6cc0d8 100644 --- a/src/celeritas/inp/Particle.hh +++ b/src/celeritas/inp/Particle.hh @@ -18,6 +18,17 @@ namespace celeritas { namespace inp { +//---------------------------------------------------------------------------// +/*! + * Branching ratio and daughters for a decay channel. + */ +struct DecayChannel +{ + DecayChannelType type{DecayChannelType::size_}; + double branching_ratio{}; + std::vector daughters; +}; + //---------------------------------------------------------------------------// /*! * Particle data. @@ -26,6 +37,7 @@ struct Particle { using Charge = Quantity; using MevMass = Quantity; + using DecayTable = std::vector; //! Particle name std::string name; @@ -37,6 +49,8 @@ struct Particle Charge charge; //! Decay constant [1/time] double decay_constant{constants::stable_decay_constant}; + //! Decay channels + DecayTable decay_channels; }; //---------------------------------------------------------------------------// diff --git a/src/celeritas/inp/Physics.hh b/src/celeritas/inp/Physics.hh index b6503f0852..d3eb9e02c4 100644 --- a/src/celeritas/inp/Physics.hh +++ b/src/celeritas/inp/Physics.hh @@ -8,6 +8,7 @@ #include #include +#include #include #include "corecel/Types.hh" @@ -96,27 +97,14 @@ struct OpticalPhysics } }; -//---------------------------------------------------------------------------// -/*! - * Branching ratio and daughters for a decay channel. - */ -struct DecayChannel -{ - DecayChannelType type{DecayChannelType::size_}; - double branching_ratio{}; - std::vector daughters; -}; - //---------------------------------------------------------------------------// /*! * Decay processes and options. */ struct DecayPhysics { - using DecayTable = std::vector; - - //! Decay channels for particles for which decay is enabled - std::unordered_map tables; + //! Particles for which decay is enabled + std::unordered_set particles; }; //---------------------------------------------------------------------------// diff --git a/test/celeritas/MockTestBase.cc b/test/celeritas/MockTestBase.cc index 4c597908e1..25ecc3f187 100644 --- a/test/celeritas/MockTestBase.cc +++ b/test/celeritas/MockTestBase.cc @@ -113,27 +113,32 @@ auto MockTestBase::build_particle() -> SPConstParticle constexpr auto zero = zero_quantity(); ParticleParams::Input inp; - inp.push_back({"gamma", pdg::gamma(), zero, zero, stable_decay_constant}); + inp.push_back( + {"gamma", pdg::gamma(), zero, zero, stable_decay_constant, {}}); inp.push_back({"celeriton", PDGNumber{1337}, MevMass{1}, ElementaryCharge{1}, - stable_decay_constant}); + stable_decay_constant, + {}}); inp.push_back({"anti-celeriton", PDGNumber{-1337}, MevMass{1}, ElementaryCharge{-1}, - stable_decay_constant}); + stable_decay_constant, + {}}); inp.push_back({"electron", pdg::electron(), MevMass{0.5109989461}, ElementaryCharge{-1}, - stable_decay_constant}); + stable_decay_constant, + {}}); inp.push_back({"celerino", PDGNumber{81}, MevMass{0}, ElementaryCharge{0}, - stable_decay_constant}); + stable_decay_constant, + {}}); return std::make_shared(std::move(inp)); } diff --git a/test/celeritas/SimpleTestBase.cc b/test/celeritas/SimpleTestBase.cc index 592ad909e4..755a48487b 100644 --- a/test/celeritas/SimpleTestBase.cc +++ b/test/celeritas/SimpleTestBase.cc @@ -68,12 +68,14 @@ auto SimpleTestBase::build_particle() -> SPConstParticle pdg::gamma(), zero_quantity(), zero_quantity(), - stable_decay_constant}); + stable_decay_constant, + {}}); defs.push_back({"electron", pdg::electron(), MevMass{0.5}, ElementaryCharge{-1}, - stable_decay_constant}); + stable_decay_constant, + {}}); return std::make_shared(std::move(defs)); } diff --git a/test/celeritas/em/CoulombScattering.test.cc b/test/celeritas/em/CoulombScattering.test.cc index afc03d3684..6a387c5963 100644 --- a/test/celeritas/em/CoulombScattering.test.cc +++ b/test/celeritas/em/CoulombScattering.test.cc @@ -42,17 +42,20 @@ class CoulombScatteringTest : public InteractorHostTestBase pdg::electron(), emass, ElementaryCharge{-1}, - stable_decay_constant}, + stable_decay_constant, + {}}, {"positron", pdg::positron(), emass, ElementaryCharge{1}, - stable_decay_constant}, + stable_decay_constant, + {}}, {"proton", pdg::proton(), units::MevMass{938.28}, ElementaryCharge{1}, - stable_decay_constant}, + stable_decay_constant, + {}}, }; this->set_particle_params(std::move(par_inp)); diff --git a/test/celeritas/em/Rayleigh.test.cc b/test/celeritas/em/Rayleigh.test.cc index 8eab1067ab..242327598e 100644 --- a/test/celeritas/em/Rayleigh.test.cc +++ b/test/celeritas/em/Rayleigh.test.cc @@ -38,7 +38,7 @@ class RayleighInteractorTest : public InteractorHostTestBase // Set up shared particle data for RayleighModel Base::set_particle_params( - {{"gamma", pdg::gamma(), zero, zero, stable_decay_constant}}); + {{"gamma", pdg::gamma(), zero, zero, stable_decay_constant, {}}}); auto const& particles = *this->particle_params(); model_ref_.gamma = particles.find(pdg::gamma()); diff --git a/test/celeritas/em/distribution/EnergyLossHelper.test.cc b/test/celeritas/em/distribution/EnergyLossHelper.test.cc index bb5c831e27..79fc6cd9de 100644 --- a/test/celeritas/em/distribution/EnergyLossHelper.test.cc +++ b/test/celeritas/em/distribution/EnergyLossHelper.test.cc @@ -86,12 +86,14 @@ class EnergyLossDistributionTest : public Test pdg::electron(), MevMass{0.5109989461}, ElementaryCharge{-1}, - stable_decay_constant}, + stable_decay_constant, + {}}, {"mu_minus", pdg::mu_minus(), MevMass{105.6583745}, ElementaryCharge{-1}, - stable_decay_constant}}; + stable_decay_constant, + {}}}; particles = std::make_shared(std::move(par_inp)); // Construct shared cutoff params diff --git a/test/celeritas/field/FieldPropagator.test.cc b/test/celeritas/field/FieldPropagator.test.cc index 3c0cae16db..cb893e934b 100644 --- a/test/celeritas/field/FieldPropagator.test.cc +++ b/test/celeritas/field/FieldPropagator.test.cc @@ -107,17 +107,20 @@ auto FieldPropagatorTestBase::build_particle() const -> SPConstParticle pdg::electron(), MevMass{0.5109989461}, ElementaryCharge{-1}, - stable_decay_constant}, + stable_decay_constant, + {}}, {"positron", pdg::positron(), MevMass{0.5109989461}, ElementaryCharge{1}, - stable_decay_constant}, + stable_decay_constant, + {}}, {"gamma", pdg::gamma(), zero_quantity(), zero_quantity(), - stable_decay_constant}}; + stable_decay_constant, + {}}}; return std::make_shared(std::move(defs)); } diff --git a/test/celeritas/io/EventIOTestBase.cc b/test/celeritas/io/EventIOTestBase.cc index c8ece564a2..07801e824e 100644 --- a/test/celeritas/io/EventIOTestBase.cc +++ b/test/celeritas/io/EventIOTestBase.cc @@ -70,23 +70,27 @@ void EventIOTestBase::SetUp() pdg::proton(), MevMass{938.27208816}, ElementaryCharge{1}, - stable_decay_constant}, + stable_decay_constant, + {}}, {"d_quark", PDGNumber(1), MevMass{4.7}, ElementaryCharge{-1.0 / 3}, - stable_decay_constant}, + stable_decay_constant, + {}}, {"anti_u_quark", PDGNumber(-2), MevMass{2.2}, ElementaryCharge{-2.0 / 3}, - stable_decay_constant}, + stable_decay_constant, + {}}, {"w_minus", PDGNumber(-24), MevMass{8.0379e4}, zero, - 1.0 / (3.157e-25 * second)}, - {"gamma", pdg::gamma(), zero, zero, stable_decay_constant}, + 1.0 / (3.157e-25 * second), + {}}, + {"gamma", pdg::gamma(), zero, zero, stable_decay_constant, {}}, }); } diff --git a/test/celeritas/neutron/NeutronTestBase.cc b/test/celeritas/neutron/NeutronTestBase.cc index 11e33013c7..46c859076e 100644 --- a/test/celeritas/neutron/NeutronTestBase.cc +++ b/test/celeritas/neutron/NeutronTestBase.cc @@ -31,8 +31,8 @@ NeutronTestBase::NeutronTestBase() // Setup default particle params ParticleParams::Input par_inp = { - {"neutron", pdg::neutron(), neutron_mass, zero, stable_decay_constant}, - {"proton", pdg::proton(), proton_mass, zero, stable_decay_constant}}; + {"neutron", pdg::neutron(), neutron_mass, zero, stable_decay_constant, {}}, + {"proton", pdg::proton(), proton_mass, zero, stable_decay_constant, {}}}; this->set_particle_params(std::move(par_inp)); // Setup default material params diff --git a/test/celeritas/optical/OpticalTestBase.cc b/test/celeritas/optical/OpticalTestBase.cc index 51ec235bc2..05370195f6 100644 --- a/test/celeritas/optical/OpticalTestBase.cc +++ b/test/celeritas/optical/OpticalTestBase.cc @@ -29,12 +29,14 @@ OpticalTestBase::OpticalTestBase() pdg::electron(), e_mass, units::ElementaryCharge{-1}, - constants::stable_decay_constant}); + constants::stable_decay_constant, + {}}); inp.push_back({"positron", pdg::positron(), e_mass, units::ElementaryCharge{1}, - constants::stable_decay_constant}); + constants::stable_decay_constant, + {}}); particle_params_ = std::make_shared(std::move(inp)); particle_state_ diff --git a/test/celeritas/phys/CutoffParams.test.cc b/test/celeritas/phys/CutoffParams.test.cc index 3827ed3544..cc89f1d320 100644 --- a/test/celeritas/phys/CutoffParams.test.cc +++ b/test/celeritas/phys/CutoffParams.test.cc @@ -72,19 +72,22 @@ class CutoffParamsTest : public Test pdg::electron(), MevMass{0.5109989461}, ElementaryCharge{-1}, - stable_decay_constant}); + stable_decay_constant, + {}}); p_input.push_back( - {"gamma", pdg::gamma(), zero, zero, stable_decay_constant}); + {"gamma", pdg::gamma(), zero, zero, stable_decay_constant, {}}); p_input.push_back({"positron", pdg::positron(), MevMass{0.5109989461}, ElementaryCharge{1}, - stable_decay_constant}); + stable_decay_constant, + {}}); p_input.push_back({"proton", pdg::proton(), MevMass{938.27208816}, ElementaryCharge{1}, - stable_decay_constant}); + stable_decay_constant, + {}}); particles = std::make_shared(std::move(p_input)); } diff --git a/test/celeritas/phys/InteractorHostTestBase.cc b/test/celeritas/phys/InteractorHostTestBase.cc index 50e38bea10..b487cd3b83 100644 --- a/test/celeritas/phys/InteractorHostTestBase.cc +++ b/test/celeritas/phys/InteractorHostTestBase.cc @@ -40,23 +40,27 @@ InteractorHostBase::InteractorHostBase() pdg::electron(), emass, ElementaryCharge{-1}, - stable_decay_constant}, + stable_decay_constant, + {}}, {"positron", pdg::positron(), emass, ElementaryCharge{1}, - stable_decay_constant}, - {"gamma", pdg::gamma(), zero, zero, stable_decay_constant}, + stable_decay_constant, + {}}, + {"gamma", pdg::gamma(), zero, zero, stable_decay_constant, {}}, {"mu_minus", pdg::mu_minus(), mumass, ElementaryCharge{-1}, - native_value_from(mu_decay_constant)}, + native_value_from(mu_decay_constant), + {}}, {"mu_plus", pdg::mu_plus(), mumass, ElementaryCharge{1}, - native_value_from(mu_decay_constant)}, + native_value_from(mu_decay_constant), + {}}, }; this->set_particle_params(std::move(par_inp)); diff --git a/test/celeritas/phys/Particle.test.cc b/test/celeritas/phys/Particle.test.cc index 49ec9c06de..306f9a05e9 100644 --- a/test/celeritas/phys/Particle.test.cc +++ b/test/celeritas/phys/Particle.test.cc @@ -48,19 +48,22 @@ class ParticleTest : public Test pdg::electron(), MevMass{0.5109989461}, ElementaryCharge{-1}, - stable_decay_constant}); + stable_decay_constant, + {}}); defs.push_back( - {"gamma", pdg::gamma(), zero, zero, stable_decay_constant}); + {"gamma", pdg::gamma(), zero, zero, stable_decay_constant, {}}); defs.push_back({"neutron", PDGNumber{2112}, MevMass{939.565413}, zero, - 1.0 / (879.4 * second)}); + 1.0 / (879.4 * second), + {}}); defs.push_back({"positron", pdg::positron(), MevMass{0.5109989461}, ElementaryCharge{1}, - stable_decay_constant}); + stable_decay_constant, + {}}); particle_params = std::make_shared(std::move(defs)); } diff --git a/test/celeritas/phys/Physics.test.cc b/test/celeritas/phys/Physics.test.cc index 9e19179128..cf2f973b6f 100644 --- a/test/celeritas/phys/Physics.test.cc +++ b/test/celeritas/phys/Physics.test.cc @@ -872,8 +872,9 @@ auto EPlusAnnihilationTest::build_particle() -> SPConstParticle pdg::positron(), MevMass{0.5109989461}, ElementaryCharge{1}, - stable_decay_constant}, - {"gamma", pdg::gamma(), zero, zero, stable_decay_constant}}); + stable_decay_constant, + {}}, + {"gamma", pdg::gamma(), zero, zero, stable_decay_constant, {}}}); } //---------------------------------------------------------------------------// diff --git a/test/celeritas/phys/PrimaryGenerator.test.cc b/test/celeritas/phys/PrimaryGenerator.test.cc index 5e7ad74119..7952ac82e7 100644 --- a/test/celeritas/phys/PrimaryGenerator.test.cc +++ b/test/celeritas/phys/PrimaryGenerator.test.cc @@ -37,12 +37,13 @@ class PrimaryGeneratorTest : public Test // Create particle defs ParticleParams::Input defs{ - {"gamma", pdg::gamma(), zero, zero, stable_decay_constant}, + {"gamma", pdg::gamma(), zero, zero, stable_decay_constant, {}}, {"electron", pdg::electron(), units::MevMass{0.5109989461}, units::ElementaryCharge{-1}, - stable_decay_constant}}; + stable_decay_constant, + {}}}; particles_ = std::make_shared(std::move(defs)); } diff --git a/test/celeritas/phys/ProcessBuilder.test.cc b/test/celeritas/phys/ProcessBuilder.test.cc index 110f8b5807..6e28d8c84e 100644 --- a/test/celeritas/phys/ProcessBuilder.test.cc +++ b/test/celeritas/phys/ProcessBuilder.test.cc @@ -463,7 +463,8 @@ TEST_F(ProcessBuilderTest, neutron_elastic) pdg::neutron(), units::MevMass{939.5654133}, zero_quantity(), - constants::stable_decay_constant}, + constants::stable_decay_constant, + {}}, }; SPConstParticle particle_params = std::make_shared(std::move(particle_inp)); From ffa73cc52f4f77c12ba6dbefd6ad53e4e2204df5 Mon Sep 17 00:00:00 2001 From: Amanda Lund Date: Mon, 22 Sep 2025 21:00:11 +0000 Subject: [PATCH 3/7] Revert "Refactor to store decay channels in particle input" This reverts commit 757e9a1541c1efa4a118f62eca7cc22f8305781c. --- src/celeritas/ext/GeantImporter.cc | 24 ++++++------------- src/celeritas/inp/Particle.hh | 14 ----------- src/celeritas/inp/Physics.hh | 18 +++++++++++--- test/celeritas/MockTestBase.cc | 15 ++++-------- test/celeritas/SimpleTestBase.cc | 6 ++--- test/celeritas/em/CoulombScattering.test.cc | 9 +++---- test/celeritas/em/Rayleigh.test.cc | 2 +- .../em/distribution/EnergyLossHelper.test.cc | 6 ++--- test/celeritas/field/FieldPropagator.test.cc | 9 +++---- test/celeritas/io/EventIOTestBase.cc | 14 ++++------- test/celeritas/neutron/NeutronTestBase.cc | 4 ++-- test/celeritas/optical/OpticalTestBase.cc | 6 ++--- test/celeritas/phys/CutoffParams.test.cc | 11 ++++----- test/celeritas/phys/InteractorHostTestBase.cc | 14 ++++------- test/celeritas/phys/Particle.test.cc | 11 ++++----- test/celeritas/phys/Physics.test.cc | 5 ++-- test/celeritas/phys/PrimaryGenerator.test.cc | 5 ++-- test/celeritas/phys/ProcessBuilder.test.cc | 3 +-- 18 files changed, 65 insertions(+), 111 deletions(-) diff --git a/src/celeritas/ext/GeantImporter.cc b/src/celeritas/ext/GeantImporter.cc index 17e9da428b..b748817417 100644 --- a/src/celeritas/ext/GeantImporter.cc +++ b/src/celeritas/ext/GeantImporter.cc @@ -970,15 +970,13 @@ std::vector import_regions() /*! * Import a decay table from a Geant4 particle definition. */ -std::vector import_decay_table(G4ParticleDefinition const& p) +inp::DecayPhysics::DecayTable import_decay_table(G4ParticleDefinition const& p) { + inp::DecayPhysics::DecayTable result; + auto* g4_table = p.GetDecayTable(); - if (!g4_table) - { - return {}; - } + CELER_ASSERT(g4_table); - std::vector result; for (auto channel_idx : range(g4_table->entries())) { auto* g4_channel = (*g4_table)[channel_idx]; @@ -990,15 +988,6 @@ std::vector import_decay_table(G4ParticleDefinition const& p) for (auto daughter_idx : range(g4_channel->GetNumberOfDaughters())) { auto const* daughter = g4_channel->GetDaughter(daughter_idx); - if (!daughter) - { - CELER_LOG(warning) - << "Ignoring decay table for particle " - << p.GetParticleName() << " since daughter '" - << g4_channel->GetDaughterName(daughter_idx) - << "' is not defined"; - return {}; - } channel.daughters.push_back(PDGNumber(daughter->GetPDGEncoding())); } result.push_back(std::move(channel)); @@ -1039,8 +1028,9 @@ auto import_processes(GeantImporter::DataSelection selected, G4VProcess const& process) -> void { if (dynamic_cast(&process)) { - // Add decay process if enabled for this particle - decay.particles.insert({PDGNumber(particle.GetPDGEncoding())}); + // Store decay table if decay process is enabled for this particle + decay.tables.insert({PDGNumber(particle.GetPDGEncoding()), + import_decay_table(particle)}); return; } diff --git a/src/celeritas/inp/Particle.hh b/src/celeritas/inp/Particle.hh index 7c9e6cc0d8..36ec6714ae 100644 --- a/src/celeritas/inp/Particle.hh +++ b/src/celeritas/inp/Particle.hh @@ -18,17 +18,6 @@ namespace celeritas { namespace inp { -//---------------------------------------------------------------------------// -/*! - * Branching ratio and daughters for a decay channel. - */ -struct DecayChannel -{ - DecayChannelType type{DecayChannelType::size_}; - double branching_ratio{}; - std::vector daughters; -}; - //---------------------------------------------------------------------------// /*! * Particle data. @@ -37,7 +26,6 @@ struct Particle { using Charge = Quantity; using MevMass = Quantity; - using DecayTable = std::vector; //! Particle name std::string name; @@ -49,8 +37,6 @@ struct Particle Charge charge; //! Decay constant [1/time] double decay_constant{constants::stable_decay_constant}; - //! Decay channels - DecayTable decay_channels; }; //---------------------------------------------------------------------------// diff --git a/src/celeritas/inp/Physics.hh b/src/celeritas/inp/Physics.hh index d3eb9e02c4..b6503f0852 100644 --- a/src/celeritas/inp/Physics.hh +++ b/src/celeritas/inp/Physics.hh @@ -8,7 +8,6 @@ #include #include -#include #include #include "corecel/Types.hh" @@ -97,14 +96,27 @@ struct OpticalPhysics } }; +//---------------------------------------------------------------------------// +/*! + * Branching ratio and daughters for a decay channel. + */ +struct DecayChannel +{ + DecayChannelType type{DecayChannelType::size_}; + double branching_ratio{}; + std::vector daughters; +}; + //---------------------------------------------------------------------------// /*! * Decay processes and options. */ struct DecayPhysics { - //! Particles for which decay is enabled - std::unordered_set particles; + using DecayTable = std::vector; + + //! Decay channels for particles for which decay is enabled + std::unordered_map tables; }; //---------------------------------------------------------------------------// diff --git a/test/celeritas/MockTestBase.cc b/test/celeritas/MockTestBase.cc index 25ecc3f187..4c597908e1 100644 --- a/test/celeritas/MockTestBase.cc +++ b/test/celeritas/MockTestBase.cc @@ -113,32 +113,27 @@ auto MockTestBase::build_particle() -> SPConstParticle constexpr auto zero = zero_quantity(); ParticleParams::Input inp; - inp.push_back( - {"gamma", pdg::gamma(), zero, zero, stable_decay_constant, {}}); + inp.push_back({"gamma", pdg::gamma(), zero, zero, stable_decay_constant}); inp.push_back({"celeriton", PDGNumber{1337}, MevMass{1}, ElementaryCharge{1}, - stable_decay_constant, - {}}); + stable_decay_constant}); inp.push_back({"anti-celeriton", PDGNumber{-1337}, MevMass{1}, ElementaryCharge{-1}, - stable_decay_constant, - {}}); + stable_decay_constant}); inp.push_back({"electron", pdg::electron(), MevMass{0.5109989461}, ElementaryCharge{-1}, - stable_decay_constant, - {}}); + stable_decay_constant}); inp.push_back({"celerino", PDGNumber{81}, MevMass{0}, ElementaryCharge{0}, - stable_decay_constant, - {}}); + stable_decay_constant}); return std::make_shared(std::move(inp)); } diff --git a/test/celeritas/SimpleTestBase.cc b/test/celeritas/SimpleTestBase.cc index 755a48487b..592ad909e4 100644 --- a/test/celeritas/SimpleTestBase.cc +++ b/test/celeritas/SimpleTestBase.cc @@ -68,14 +68,12 @@ auto SimpleTestBase::build_particle() -> SPConstParticle pdg::gamma(), zero_quantity(), zero_quantity(), - stable_decay_constant, - {}}); + stable_decay_constant}); defs.push_back({"electron", pdg::electron(), MevMass{0.5}, ElementaryCharge{-1}, - stable_decay_constant, - {}}); + stable_decay_constant}); return std::make_shared(std::move(defs)); } diff --git a/test/celeritas/em/CoulombScattering.test.cc b/test/celeritas/em/CoulombScattering.test.cc index 6a387c5963..afc03d3684 100644 --- a/test/celeritas/em/CoulombScattering.test.cc +++ b/test/celeritas/em/CoulombScattering.test.cc @@ -42,20 +42,17 @@ class CoulombScatteringTest : public InteractorHostTestBase pdg::electron(), emass, ElementaryCharge{-1}, - stable_decay_constant, - {}}, + stable_decay_constant}, {"positron", pdg::positron(), emass, ElementaryCharge{1}, - stable_decay_constant, - {}}, + stable_decay_constant}, {"proton", pdg::proton(), units::MevMass{938.28}, ElementaryCharge{1}, - stable_decay_constant, - {}}, + stable_decay_constant}, }; this->set_particle_params(std::move(par_inp)); diff --git a/test/celeritas/em/Rayleigh.test.cc b/test/celeritas/em/Rayleigh.test.cc index 242327598e..8eab1067ab 100644 --- a/test/celeritas/em/Rayleigh.test.cc +++ b/test/celeritas/em/Rayleigh.test.cc @@ -38,7 +38,7 @@ class RayleighInteractorTest : public InteractorHostTestBase // Set up shared particle data for RayleighModel Base::set_particle_params( - {{"gamma", pdg::gamma(), zero, zero, stable_decay_constant, {}}}); + {{"gamma", pdg::gamma(), zero, zero, stable_decay_constant}}); auto const& particles = *this->particle_params(); model_ref_.gamma = particles.find(pdg::gamma()); diff --git a/test/celeritas/em/distribution/EnergyLossHelper.test.cc b/test/celeritas/em/distribution/EnergyLossHelper.test.cc index 79fc6cd9de..bb5c831e27 100644 --- a/test/celeritas/em/distribution/EnergyLossHelper.test.cc +++ b/test/celeritas/em/distribution/EnergyLossHelper.test.cc @@ -86,14 +86,12 @@ class EnergyLossDistributionTest : public Test pdg::electron(), MevMass{0.5109989461}, ElementaryCharge{-1}, - stable_decay_constant, - {}}, + stable_decay_constant}, {"mu_minus", pdg::mu_minus(), MevMass{105.6583745}, ElementaryCharge{-1}, - stable_decay_constant, - {}}}; + stable_decay_constant}}; particles = std::make_shared(std::move(par_inp)); // Construct shared cutoff params diff --git a/test/celeritas/field/FieldPropagator.test.cc b/test/celeritas/field/FieldPropagator.test.cc index cb893e934b..3c0cae16db 100644 --- a/test/celeritas/field/FieldPropagator.test.cc +++ b/test/celeritas/field/FieldPropagator.test.cc @@ -107,20 +107,17 @@ auto FieldPropagatorTestBase::build_particle() const -> SPConstParticle pdg::electron(), MevMass{0.5109989461}, ElementaryCharge{-1}, - stable_decay_constant, - {}}, + stable_decay_constant}, {"positron", pdg::positron(), MevMass{0.5109989461}, ElementaryCharge{1}, - stable_decay_constant, - {}}, + stable_decay_constant}, {"gamma", pdg::gamma(), zero_quantity(), zero_quantity(), - stable_decay_constant, - {}}}; + stable_decay_constant}}; return std::make_shared(std::move(defs)); } diff --git a/test/celeritas/io/EventIOTestBase.cc b/test/celeritas/io/EventIOTestBase.cc index 07801e824e..c8ece564a2 100644 --- a/test/celeritas/io/EventIOTestBase.cc +++ b/test/celeritas/io/EventIOTestBase.cc @@ -70,27 +70,23 @@ void EventIOTestBase::SetUp() pdg::proton(), MevMass{938.27208816}, ElementaryCharge{1}, - stable_decay_constant, - {}}, + stable_decay_constant}, {"d_quark", PDGNumber(1), MevMass{4.7}, ElementaryCharge{-1.0 / 3}, - stable_decay_constant, - {}}, + stable_decay_constant}, {"anti_u_quark", PDGNumber(-2), MevMass{2.2}, ElementaryCharge{-2.0 / 3}, - stable_decay_constant, - {}}, + stable_decay_constant}, {"w_minus", PDGNumber(-24), MevMass{8.0379e4}, zero, - 1.0 / (3.157e-25 * second), - {}}, - {"gamma", pdg::gamma(), zero, zero, stable_decay_constant, {}}, + 1.0 / (3.157e-25 * second)}, + {"gamma", pdg::gamma(), zero, zero, stable_decay_constant}, }); } diff --git a/test/celeritas/neutron/NeutronTestBase.cc b/test/celeritas/neutron/NeutronTestBase.cc index 46c859076e..11e33013c7 100644 --- a/test/celeritas/neutron/NeutronTestBase.cc +++ b/test/celeritas/neutron/NeutronTestBase.cc @@ -31,8 +31,8 @@ NeutronTestBase::NeutronTestBase() // Setup default particle params ParticleParams::Input par_inp = { - {"neutron", pdg::neutron(), neutron_mass, zero, stable_decay_constant, {}}, - {"proton", pdg::proton(), proton_mass, zero, stable_decay_constant, {}}}; + {"neutron", pdg::neutron(), neutron_mass, zero, stable_decay_constant}, + {"proton", pdg::proton(), proton_mass, zero, stable_decay_constant}}; this->set_particle_params(std::move(par_inp)); // Setup default material params diff --git a/test/celeritas/optical/OpticalTestBase.cc b/test/celeritas/optical/OpticalTestBase.cc index 05370195f6..51ec235bc2 100644 --- a/test/celeritas/optical/OpticalTestBase.cc +++ b/test/celeritas/optical/OpticalTestBase.cc @@ -29,14 +29,12 @@ OpticalTestBase::OpticalTestBase() pdg::electron(), e_mass, units::ElementaryCharge{-1}, - constants::stable_decay_constant, - {}}); + constants::stable_decay_constant}); inp.push_back({"positron", pdg::positron(), e_mass, units::ElementaryCharge{1}, - constants::stable_decay_constant, - {}}); + constants::stable_decay_constant}); particle_params_ = std::make_shared(std::move(inp)); particle_state_ diff --git a/test/celeritas/phys/CutoffParams.test.cc b/test/celeritas/phys/CutoffParams.test.cc index cc89f1d320..3827ed3544 100644 --- a/test/celeritas/phys/CutoffParams.test.cc +++ b/test/celeritas/phys/CutoffParams.test.cc @@ -72,22 +72,19 @@ class CutoffParamsTest : public Test pdg::electron(), MevMass{0.5109989461}, ElementaryCharge{-1}, - stable_decay_constant, - {}}); + stable_decay_constant}); p_input.push_back( - {"gamma", pdg::gamma(), zero, zero, stable_decay_constant, {}}); + {"gamma", pdg::gamma(), zero, zero, stable_decay_constant}); p_input.push_back({"positron", pdg::positron(), MevMass{0.5109989461}, ElementaryCharge{1}, - stable_decay_constant, - {}}); + stable_decay_constant}); p_input.push_back({"proton", pdg::proton(), MevMass{938.27208816}, ElementaryCharge{1}, - stable_decay_constant, - {}}); + stable_decay_constant}); particles = std::make_shared(std::move(p_input)); } diff --git a/test/celeritas/phys/InteractorHostTestBase.cc b/test/celeritas/phys/InteractorHostTestBase.cc index b487cd3b83..50e38bea10 100644 --- a/test/celeritas/phys/InteractorHostTestBase.cc +++ b/test/celeritas/phys/InteractorHostTestBase.cc @@ -40,27 +40,23 @@ InteractorHostBase::InteractorHostBase() pdg::electron(), emass, ElementaryCharge{-1}, - stable_decay_constant, - {}}, + stable_decay_constant}, {"positron", pdg::positron(), emass, ElementaryCharge{1}, - stable_decay_constant, - {}}, - {"gamma", pdg::gamma(), zero, zero, stable_decay_constant, {}}, + stable_decay_constant}, + {"gamma", pdg::gamma(), zero, zero, stable_decay_constant}, {"mu_minus", pdg::mu_minus(), mumass, ElementaryCharge{-1}, - native_value_from(mu_decay_constant), - {}}, + native_value_from(mu_decay_constant)}, {"mu_plus", pdg::mu_plus(), mumass, ElementaryCharge{1}, - native_value_from(mu_decay_constant), - {}}, + native_value_from(mu_decay_constant)}, }; this->set_particle_params(std::move(par_inp)); diff --git a/test/celeritas/phys/Particle.test.cc b/test/celeritas/phys/Particle.test.cc index 306f9a05e9..49ec9c06de 100644 --- a/test/celeritas/phys/Particle.test.cc +++ b/test/celeritas/phys/Particle.test.cc @@ -48,22 +48,19 @@ class ParticleTest : public Test pdg::electron(), MevMass{0.5109989461}, ElementaryCharge{-1}, - stable_decay_constant, - {}}); + stable_decay_constant}); defs.push_back( - {"gamma", pdg::gamma(), zero, zero, stable_decay_constant, {}}); + {"gamma", pdg::gamma(), zero, zero, stable_decay_constant}); defs.push_back({"neutron", PDGNumber{2112}, MevMass{939.565413}, zero, - 1.0 / (879.4 * second), - {}}); + 1.0 / (879.4 * second)}); defs.push_back({"positron", pdg::positron(), MevMass{0.5109989461}, ElementaryCharge{1}, - stable_decay_constant, - {}}); + stable_decay_constant}); particle_params = std::make_shared(std::move(defs)); } diff --git a/test/celeritas/phys/Physics.test.cc b/test/celeritas/phys/Physics.test.cc index cf2f973b6f..9e19179128 100644 --- a/test/celeritas/phys/Physics.test.cc +++ b/test/celeritas/phys/Physics.test.cc @@ -872,9 +872,8 @@ auto EPlusAnnihilationTest::build_particle() -> SPConstParticle pdg::positron(), MevMass{0.5109989461}, ElementaryCharge{1}, - stable_decay_constant, - {}}, - {"gamma", pdg::gamma(), zero, zero, stable_decay_constant, {}}}); + stable_decay_constant}, + {"gamma", pdg::gamma(), zero, zero, stable_decay_constant}}); } //---------------------------------------------------------------------------// diff --git a/test/celeritas/phys/PrimaryGenerator.test.cc b/test/celeritas/phys/PrimaryGenerator.test.cc index 7952ac82e7..5e7ad74119 100644 --- a/test/celeritas/phys/PrimaryGenerator.test.cc +++ b/test/celeritas/phys/PrimaryGenerator.test.cc @@ -37,13 +37,12 @@ class PrimaryGeneratorTest : public Test // Create particle defs ParticleParams::Input defs{ - {"gamma", pdg::gamma(), zero, zero, stable_decay_constant, {}}, + {"gamma", pdg::gamma(), zero, zero, stable_decay_constant}, {"electron", pdg::electron(), units::MevMass{0.5109989461}, units::ElementaryCharge{-1}, - stable_decay_constant, - {}}}; + stable_decay_constant}}; particles_ = std::make_shared(std::move(defs)); } diff --git a/test/celeritas/phys/ProcessBuilder.test.cc b/test/celeritas/phys/ProcessBuilder.test.cc index 6e28d8c84e..110f8b5807 100644 --- a/test/celeritas/phys/ProcessBuilder.test.cc +++ b/test/celeritas/phys/ProcessBuilder.test.cc @@ -463,8 +463,7 @@ TEST_F(ProcessBuilderTest, neutron_elastic) pdg::neutron(), units::MevMass{939.5654133}, zero_quantity(), - constants::stable_decay_constant, - {}}, + constants::stable_decay_constant}, }; SPConstParticle particle_params = std::make_shared(std::move(particle_inp)); From 888d0bfe7e462b9681d06e657567823ad1aab8ea Mon Sep 17 00:00:00 2001 From: Amanda Lund Date: Tue, 23 Sep 2025 21:54:25 +0000 Subject: [PATCH 4/7] Add initial decay implementation - Rename Process to InteractionProcess and add DecayProcess - Add DecayChannel abstract base class - Add MuDecayChannel and executor - Add decay tables and channel - to - action mapping to physics data - Add DecayTableInserter helper class to build decay tables in physics data - Add decay to particle - processes in physics if present - Add decay_length method to ParticleTrackView - Add decay limiter in calc_physics_step_limit - Store decay process xs and sample from among other interaction processes - Sample decay channel using branching ratios if decay process is chosen - Cache sampled channel for accessing decay daughters in interactor - Refactor muon decay data and interactor to use generic decay data --- src/accel/SharedParams.cc | 1 - src/celeritas/CMakeLists.txt | 3 + src/celeritas/Types.cc | 18 ++ src/celeritas/Types.hh | 28 +- src/celeritas/decay/DecayData.hh | 54 ++++ src/celeritas/decay/DecayProcess.cc | 90 +++++++ src/celeritas/decay/DecayProcess.hh | 64 +++++ src/celeritas/decay/channel/DecayChannel.hh | 30 +++ src/celeritas/decay/channel/MuDecayChannel.cc | 78 ++++++ src/celeritas/decay/channel/MuDecayChannel.cu | 34 +++ src/celeritas/decay/channel/MuDecayChannel.hh | 36 +++ src/celeritas/decay/data/MuDecayData.hh | 49 ---- .../decay/executor/MuDecayExecutor.hh | 7 +- .../decay/interactor/MuDecayInteractor.hh | 42 ++- .../em/process/BremsstrahlungProcess.hh | 2 +- src/celeritas/em/process/ComptonProcess.hh | 2 +- .../em/process/CoulombScatteringProcess.hh | 2 +- .../em/process/EIonizationProcess.hh | 2 +- .../em/process/EPlusAnnihilationProcess.hh | 2 +- .../em/process/GammaConversionProcess.hh | 2 +- .../em/process/MuBremsstrahlungProcess.hh | 2 +- .../em/process/MuIonizationProcess.hh | 2 +- .../em/process/MuPairProductionProcess.hh | 2 +- .../em/process/PhotoelectricProcess.hh | 2 +- src/celeritas/em/process/RayleighProcess.hh | 2 +- src/celeritas/ext/GeantImporter.cc | 19 +- src/celeritas/ext/RootInterfaceLinkDef.h | 1 + src/celeritas/inp/Physics.hh | 3 + src/celeritas/inp/ProcessBuilder.hh | 5 +- .../neutron/process/NeutronElasticProcess.hh | 2 +- .../process/NeutronInelasticProcess.hh | 2 +- src/celeritas/phys/ImportedProcessAdapter.hh | 4 +- src/celeritas/phys/ParticleTrackView.hh | 30 +++ src/celeritas/phys/PhysicsData.hh | 27 +- src/celeritas/phys/PhysicsParams.cc | 241 ++++++++++++------ src/celeritas/phys/PhysicsParams.hh | 17 +- src/celeritas/phys/PhysicsParamsOutput.cc | 15 ++ src/celeritas/phys/PhysicsStepUtils.hh | 18 +- src/celeritas/phys/PhysicsStepView.hh | 26 ++ src/celeritas/phys/PhysicsTrackView.hh | 58 +++++ src/celeritas/phys/Process.hh | 49 ++-- src/celeritas/phys/ProcessBuilder.hh | 2 +- .../phys/detail/DecayTableInserter.cc | 130 ++++++++++ .../phys/detail/DecayTableInserter.hh | 63 +++++ .../phys/detail/EnergyMaxXsCalculator.cc | 2 +- .../phys/detail/EnergyMaxXsCalculator.hh | 2 +- src/celeritas/setup/Problem.cc | 8 +- test/celeritas/data/four-steel-slabs.root | Bin 57241 -> 57659 bytes .../data/four-steel-slabs.root-dump.json | 8 +- test/celeritas/data/simple-cms.root | Bin 24627 -> 25046 bytes test/celeritas/decay/MuDecay.test.cc | 24 +- test/celeritas/phys/MockProcess.hh | 2 +- test/celeritas/phys/Physics.test.cc | 2 +- 53 files changed, 1084 insertions(+), 232 deletions(-) create mode 100644 src/celeritas/decay/DecayData.hh create mode 100644 src/celeritas/decay/DecayProcess.cc create mode 100644 src/celeritas/decay/DecayProcess.hh create mode 100644 src/celeritas/decay/channel/DecayChannel.hh create mode 100644 src/celeritas/decay/channel/MuDecayChannel.cc create mode 100644 src/celeritas/decay/channel/MuDecayChannel.cu create mode 100644 src/celeritas/decay/channel/MuDecayChannel.hh delete mode 100644 src/celeritas/decay/data/MuDecayData.hh create mode 100644 src/celeritas/phys/detail/DecayTableInserter.cc create mode 100644 src/celeritas/phys/detail/DecayTableInserter.hh diff --git a/src/accel/SharedParams.cc b/src/accel/SharedParams.cc index 101ed459c3..e8d9214508 100644 --- a/src/accel/SharedParams.cc +++ b/src/accel/SharedParams.cc @@ -68,7 +68,6 @@ #include "celeritas/phys/ParticleParams.hh" #include "celeritas/phys/PhysicsParams.hh" #include "celeritas/phys/Process.hh" -#include "celeritas/phys/ProcessBuilder.hh" #include "celeritas/setup/FrameworkInput.hh" #include "celeritas/track/SimParams.hh" #include "celeritas/track/TrackInitParams.hh" diff --git a/src/celeritas/CMakeLists.txt b/src/celeritas/CMakeLists.txt index da32d79623..11eeadfb54 100644 --- a/src/celeritas/CMakeLists.txt +++ b/src/celeritas/CMakeLists.txt @@ -36,6 +36,7 @@ list(APPEND PUBLIC_DEPS ${_core_geo_deps}) list(APPEND SOURCES Types.cc TypesIO.json.cc + decay/DecayProcess.cc em/detail/Utils.cc em/params/AtomicRelaxationParams.cc em/params/FluctuationParams.cc @@ -118,6 +119,7 @@ list(APPEND SOURCES optical/surface/SurfacePhysicsParams.cc optical/surface/SurfaceSteppingAction.cc phys/CutoffParams.cc + phys/detail/DecayTableInserter.cc phys/detail/EnergyMaxXsCalculator.cc phys/GeneratorInterface.cc phys/GeneratorRegistry.cc @@ -328,6 +330,7 @@ celeritas_polysource(alongstep/AlongStepNeutralAction) celeritas_polysource(alongstep/AlongStepUniformMscAction) celeritas_polysource(alongstep/AlongStepRZMapFieldMscAction) celeritas_polysource(alongstep/AlongStepCylMapFieldMscAction) +celeritas_polysource(decay/channel/MuDecayChannel) celeritas_polysource(em/model/BetheHeitlerModel) celeritas_polysource(em/model/BetheBlochModel) celeritas_polysource(em/model/BraggModel) diff --git a/src/celeritas/Types.cc b/src/celeritas/Types.cc index 42419553b8..219d482207 100644 --- a/src/celeritas/Types.cc +++ b/src/celeritas/Types.cc @@ -90,6 +90,24 @@ char const* to_cstring(NuclearFormFactorType value) return to_cstring_impl(value); } +//---------------------------------------------------------------------------// +/*! + * Get a string corresponding to the decay channel. + */ +char const* to_cstring(DecayChannelType value) +{ + static EnumStringMapper const to_cstring_impl{ + "dalitz", + "kl3", + "muon", + "neutron_beta", + "phase_space", + "pion_radiative", + "tau_leptonic", + }; + return to_cstring_impl(value); +} + //---------------------------------------------------------------------------// /*! * Get a string corresponding to the wavelength shifting time model selection. diff --git a/src/celeritas/Types.hh b/src/celeritas/Types.hh index 244f602639..1fc1832d0b 100644 --- a/src/celeritas/Types.hh +++ b/src/celeritas/Types.hh @@ -68,6 +68,9 @@ using TrackId = OpaqueId; //! Opaque index of particle-nucleon cascade channel using ChannelId = OpaqueId; +//! Opaque index of decay channel +using DecayChannelId = OpaqueId; + //! Opaque index to one elemental component datum in a particular material using ElementComponentId = OpaqueId; @@ -191,6 +194,17 @@ enum class MscStepLimitAlgorithm size_, }; +//---------------------------------------------------------------------------// +//! Nuclear form factor model for Coulomb scattering +enum class NuclearFormFactorType +{ + none, + flat, + exponential, + gaussian, + size_ +}; + //---------------------------------------------------------------------------// //! Decay channel type enum class DecayChannelType @@ -205,17 +219,6 @@ enum class DecayChannelType size_ }; -//---------------------------------------------------------------------------// -//! Nuclear form factor model for Coulomb scattering -enum class NuclearFormFactorType -{ - none, - flat, - exponential, - gaussian, - size_ -}; - //---------------------------------------------------------------------------// //! Optical photon wavelength shifting time model enum class WlsTimeProfile @@ -291,6 +294,9 @@ char const* to_cstring(MscStepLimitAlgorithm value); // Get a string corresponding to the nuclear form factor model char const* to_cstring(NuclearFormFactorType value); +// Get a string corresponding to the decay channel +char const* to_cstring(DecayChannelType value); + // Get a string corresponding to the interpolation method char const* to_cstring(InterpolationType value); diff --git a/src/celeritas/decay/DecayData.hh b/src/celeritas/decay/DecayData.hh new file mode 100644 index 0000000000..6910074275 --- /dev/null +++ b/src/celeritas/decay/DecayData.hh @@ -0,0 +1,54 @@ +//------------------------------- -*- C++ -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file celeritas/decay/data/DecayData.hh +//---------------------------------------------------------------------------// +#pragma once + +#include "corecel/Macros.hh" +#include "corecel/Types.hh" +#include "corecel/data/Collection.hh" +#include "celeritas/Types.hh" + +namespace celeritas +{ +//---------------------------------------------------------------------------// +/*! + * Data for a decay interactor. + * + * This stores the particle IDs of the daughters for a specific decay channel. + */ +struct DecayChannelData +{ + //! Daughter particle IDs + ItemRange daughters; + + //! Whether the data is assigned + explicit CELER_FUNCTION operator bool() const + { + return !daughters.empty(); + } +}; + +//---------------------------------------------------------------------------// +/*! + * Decay channels for a particle type. + */ +struct DecayTableData +{ + //! Decay channels + ItemRange channel_ids; + //! Branching ratio of each decay channel + ItemRange branching_ratios; + + //! Whether the data is assigned + explicit CELER_FUNCTION operator bool() const + { + return !channel_ids.empty() + && branching_ratios.size() == channel_ids.size(); + } +}; + +//---------------------------------------------------------------------------// +} // namespace celeritas diff --git a/src/celeritas/decay/DecayProcess.cc b/src/celeritas/decay/DecayProcess.cc new file mode 100644 index 0000000000..6114c712fa --- /dev/null +++ b/src/celeritas/decay/DecayProcess.cc @@ -0,0 +1,90 @@ +//------------------------------- -*- C++ -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file celeritas/decay/DecayProcess.cc +//---------------------------------------------------------------------------// +#include "DecayProcess.hh" + +#include + +#include "corecel/Assert.hh" +#include "celeritas/decay/DecayData.hh" +#include "celeritas/decay/channel/MuDecayChannel.hh" +#include "celeritas/phys/PDGNumber.hh" +#include "celeritas/phys/ParticleParams.hh" + +namespace celeritas +{ +//---------------------------------------------------------------------------// +/*! + * Construct from particles and input data. + */ +DecayProcess::DecayProcess(SPConstParticles particles, + inp::DecayPhysics const& input) + : particles_(std::move(particles)), input_(input) +{ + CELER_EXPECT(particles_); + CELER_VALIDATE(input_, << "no decay tables are present"); +} + +//---------------------------------------------------------------------------// +/*! + * Construct the decay channels. + */ +auto DecayProcess::build_channels(ActionIdIter start_id) const -> VecChannel +{ + VecChannel result; + std::set types; + for (auto const& [pdg, table] : input_.tables) + { + for (auto const& channel : table) + { + // Identify the unique channel types + auto [iter, inserted] = types.insert(channel.type); + if (inserted) + { + // Construct an action for each channel + switch (*iter) + { + case DecayChannelType::muon: + result.push_back(std::make_shared( + *start_id++, input_)); + break; + default: + CELER_NOT_IMPLEMENTED("Decay channel type"); + } + } + } + } + CELER_VALIDATE(!result.empty(), + << "no supported channels for decay process"); + return result; +} + +//---------------------------------------------------------------------------// +/*! + * Get the decay table for a particle. + */ +auto DecayProcess::decay_table(ParticleId pid) const -> DecayTable +{ + auto iter = input_.tables.find(particles_->id_to_pdg(pid)); + if (iter == input_.tables.end()) + { + return {}; + } + return iter->second; +} + +//---------------------------------------------------------------------------// +/*! + * Whether the decay process applies to the particle. + */ +bool DecayProcess::is_applicable(ParticleId pid) const +{ + return input_.tables.find(particles_->id_to_pdg(pid)) + != input_.tables.end(); +} + +//---------------------------------------------------------------------------// +} // namespace celeritas diff --git a/src/celeritas/decay/DecayProcess.hh b/src/celeritas/decay/DecayProcess.hh new file mode 100644 index 0000000000..5259c29360 --- /dev/null +++ b/src/celeritas/decay/DecayProcess.hh @@ -0,0 +1,64 @@ +//------------------------------- -*- C++ -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file celeritas/decay/DecayProcess.hh +//---------------------------------------------------------------------------// +#pragma once + +#include + +#include "celeritas/Types.hh" +#include "celeritas/decay/channel/DecayChannel.hh" +#include "celeritas/inp/Physics.hh" +#include "celeritas/phys/ImportedProcessAdapter.hh" +#include "celeritas/phys/Process.hh" + +namespace celeritas +{ +class ParticleParams; + +//---------------------------------------------------------------------------// +/*! + * Process for decay. + */ +class DecayProcess final : public Process +{ + public: + //!@{ + //! \name Type aliases + using SPConstChannel = std::shared_ptr; + using SPConstParticles = std::shared_ptr; + using VecChannel = std::vector; + using DecayTable = inp::DecayPhysics::DecayTable; + //!@} + + public: + // Construct from particles and input data + DecayProcess(SPConstParticles, inp::DecayPhysics const&); + + // Construct the decay channels + VecChannel build_channels(ActionIdIter start_id) const; + + // Get the decay table for a particle + DecayTable decay_table(ParticleId) const; + + // Whether the decay process applies to the particle + bool is_applicable(ParticleId) const; + + //!@{ + //! \name Process interface + + //! Whether the process applies when the particle is stopped + bool applies_at_rest() const final { return true; } + //! Name of the process + std::string_view label() const final { return "Decay"; } + //!@} + + private: + SPConstParticles particles_; + inp::DecayPhysics const& input_; +}; + +//---------------------------------------------------------------------------// +} // namespace celeritas diff --git a/src/celeritas/decay/channel/DecayChannel.hh b/src/celeritas/decay/channel/DecayChannel.hh new file mode 100644 index 0000000000..9135406b7b --- /dev/null +++ b/src/celeritas/decay/channel/DecayChannel.hh @@ -0,0 +1,30 @@ +//------------------------------- -*- C++ -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file celeritas/decay/channel/DecayChannel.hh +//---------------------------------------------------------------------------// +#pragma once + +#include "corecel/Types.hh" +#include "celeritas/Types.hh" +#include "celeritas/global/ActionInterface.hh" + +namespace celeritas +{ +//---------------------------------------------------------------------------// +/*! + * Abstract base class representing a decay channel. + * + * This class is responsible for validating the input decay table data and + * launching a kernel for the decay interactor. + */ +class DecayChannel : public CoreStepActionInterface +{ + public: + //! Dependency ordering of the action + StepActionOrder order() const final { return StepActionOrder::post; } +}; + +//---------------------------------------------------------------------------// +} // namespace celeritas diff --git a/src/celeritas/decay/channel/MuDecayChannel.cc b/src/celeritas/decay/channel/MuDecayChannel.cc new file mode 100644 index 0000000000..fafb873718 --- /dev/null +++ b/src/celeritas/decay/channel/MuDecayChannel.cc @@ -0,0 +1,78 @@ +//------------------------------- -*- C++ -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file celeritas/decay/channel/MuDecayChannel.cc +//---------------------------------------------------------------------------// +#include "MuDecayChannel.hh" + +#include "celeritas/Quantities.hh" +#include "celeritas/decay/executor/MuDecayExecutor.hh" +#include "celeritas/em/interactor/detail/PhysicsConstants.hh" +#include "celeritas/global/ActionLauncher.hh" +#include "celeritas/global/CoreParams.hh" +#include "celeritas/global/CoreState.hh" +#include "celeritas/global/TrackExecutor.hh" +#include "celeritas/phys/InteractionApplier.hh" +#include "celeritas/phys/PDGNumber.hh" + +namespace celeritas +{ +//---------------------------------------------------------------------------// +/*! + * Construct from action ID and input decay table data. + */ +MuDecayChannel::MuDecayChannel(ActionId id, inp::DecayPhysics const& input) + : StaticConcreteAction(id, "muon-decay-channel", "muon decay") +{ + CELER_EXPECT(id); + CELER_EXPECT(input); + + // Validate the input data + for (auto const& [pdg, table] : input.tables) + { + for (auto const& channel : table) + { + // Loop over decay tables and find all channels of this type + if (channel.type == DecayChannelType::muon) + { + // Check that the input data matches the data expected by the + // muon decay interactor + auto const& daughters = channel.daughters; + CELER_VALIDATE(daughters.size() == 1, + << "muon decay only supports one daughter: " + "neutrinos are currently neglected"); + CELER_VALIDATE( + (pdg == pdg::mu_minus() && daughters[0] == pdg::electron()) + || (pdg == pdg::mu_plus() + && daughters[0] == pdg::positron()), + << "expected decay channel mu- -> e- or mu+ -> e+"); + } + } + } +} + +//---------------------------------------------------------------------------// +/*! + * Interact with host data. + */ +void MuDecayChannel::step(CoreParams const& params, CoreStateHost& state) const +{ + auto execute + = make_action_track_executor(params.ptr(), + state.ptr(), + this->action_id(), + InteractionApplier{MuDecayExecutor{}}); + return launch_action(*this, params, state, execute); +} + +//---------------------------------------------------------------------------// +#if !CELER_USE_DEVICE +void MuDecayChannel::step(CoreParams const&, CoreStateDevice&) const +{ + CELER_NOT_CONFIGURED("CUDA OR HIP"); +} +#endif + +//---------------------------------------------------------------------------// +} // namespace celeritas diff --git a/src/celeritas/decay/channel/MuDecayChannel.cu b/src/celeritas/decay/channel/MuDecayChannel.cu new file mode 100644 index 0000000000..ac85d12f97 --- /dev/null +++ b/src/celeritas/decay/channel/MuDecayChannel.cu @@ -0,0 +1,34 @@ +//------------------------------ -*- cuda -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file celeritas/decay/channel/MuDecayChannel.cu +//---------------------------------------------------------------------------// +#include "MuDecayChannel.hh" + +#include "celeritas/decay/executor/MuDecayExecutor.hh" +#include "celeritas/global/ActionLauncher.device.hh" +#include "celeritas/global/CoreParams.hh" +#include "celeritas/global/CoreState.hh" +#include "celeritas/global/TrackExecutor.hh" +#include "celeritas/phys/InteractionApplier.hh" + +namespace celeritas +{ +//---------------------------------------------------------------------------// +/*! + * Interact with device data. + */ +void MuDecayChannel::step(CoreParams const& params, CoreStateDevice& state) const +{ + auto execute + = make_action_track_executor(params.ptr(), + state.ptr(), + this->action_id(), + InteractionApplier{MuDecayExecutor{}}); + static ActionLauncher const launch_kernel(*this); + launch_kernel(*this, params, state, execute); +} + +//---------------------------------------------------------------------------// +} // namespace celeritas diff --git a/src/celeritas/decay/channel/MuDecayChannel.hh b/src/celeritas/decay/channel/MuDecayChannel.hh new file mode 100644 index 0000000000..e8508b8ca8 --- /dev/null +++ b/src/celeritas/decay/channel/MuDecayChannel.hh @@ -0,0 +1,36 @@ +//------------------------------- -*- C++ -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file celeritas/decay/channel/MuDecayChannel.hh +//---------------------------------------------------------------------------// +#pragma once + +#include "celeritas/inp/Physics.hh" + +#include "DecayChannel.hh" + +namespace celeritas +{ +//---------------------------------------------------------------------------// +/*! + * Set up and launch an action to model muon decay kinematics. + */ +class MuDecayChannel : public DecayChannel, public StaticConcreteAction +{ + public: + // Construct from action ID and imported data + MuDecayChannel(ActionId, inp::DecayPhysics const&); + + //!@{ + //! \name StepAction interface + + // Apply the interaction kernel on host + void step(CoreParams const&, CoreStateHost&) const final; + // Apply the interaction kernel on device + void step(CoreParams const&, CoreStateDevice&) const final; + //!@} +}; + +//---------------------------------------------------------------------------// +} // namespace celeritas diff --git a/src/celeritas/decay/data/MuDecayData.hh b/src/celeritas/decay/data/MuDecayData.hh deleted file mode 100644 index 3495e37caf..0000000000 --- a/src/celeritas/decay/data/MuDecayData.hh +++ /dev/null @@ -1,49 +0,0 @@ -//------------------------------- -*- C++ -*- -------------------------------// -// Copyright Celeritas contributors: see top-level COPYRIGHT file for details -// SPDX-License-Identifier: (Apache-2.0 OR MIT) -//---------------------------------------------------------------------------// -//! \file celeritas/decay/data/MuDecayData.hh -//---------------------------------------------------------------------------// -#pragma once - -#include "corecel/Macros.hh" -#include "corecel/Types.hh" -#include "celeritas/Quantities.hh" -#include "celeritas/Types.hh" - -namespace celeritas -{ -//---------------------------------------------------------------------------// -/*! - * Device data for creating a muon decay interactor. - */ -struct MuDecayData -{ - //!@{ - //! \name Type aliases - using Mass = units::MevMass; - //!@} - - //! Particle identifiers - ParticleId mu_minus_id; - ParticleId mu_plus_id; - ParticleId electron_id; - ParticleId positron_id; - - //! Muon/anti-muon mass [MeV] - Mass muon_mass; - - //! Electron/positron mass [MeV] - Mass electron_mass; - - //! Check whether the data is assigned - explicit CELER_FUNCTION operator bool() const - { - return mu_minus_id && mu_plus_id && electron_id && positron_id - && muon_mass > zero_quantity() - && electron_mass > zero_quantity(); - } -}; - -//---------------------------------------------------------------------------// -} // namespace celeritas diff --git a/src/celeritas/decay/executor/MuDecayExecutor.hh b/src/celeritas/decay/executor/MuDecayExecutor.hh index c7c188c938..1eec125b52 100644 --- a/src/celeritas/decay/executor/MuDecayExecutor.hh +++ b/src/celeritas/decay/executor/MuDecayExecutor.hh @@ -6,7 +6,6 @@ //---------------------------------------------------------------------------// #pragma once -#include "celeritas/decay/data/MuDecayData.hh" #include "celeritas/decay/interactor/MuDecayInteractor.hh" #include "celeritas/global/CoreTrackView.hh" #include "celeritas/phys/Interaction.hh" @@ -18,8 +17,6 @@ struct MuDecayExecutor { inline CELER_FUNCTION Interaction operator()(celeritas::CoreTrackView const& track); - - MuDecayData data; }; //---------------------------------------------------------------------------// @@ -31,8 +28,10 @@ CELER_FUNCTION Interaction MuDecayExecutor::operator()(CoreTrackView const& trac auto allocate_secondaries = track.physics_step().make_secondary_allocator(); auto particle = track.particle(); auto const& dir = track.geometry().dir(); + auto daughters + = track.physics().daughters(track.physics_step().decay_channel()); - MuDecayInteractor interact(data, particle, dir, allocate_secondaries); + MuDecayInteractor interact(daughters, particle, dir, allocate_secondaries); auto rng = track.rng(); return interact(rng); } diff --git a/src/celeritas/decay/interactor/MuDecayInteractor.hh b/src/celeritas/decay/interactor/MuDecayInteractor.hh index a51b000acd..e13f635159 100644 --- a/src/celeritas/decay/interactor/MuDecayInteractor.hh +++ b/src/celeritas/decay/interactor/MuDecayInteractor.hh @@ -14,7 +14,6 @@ #include "corecel/random/distribution/RejectionSampler.hh" #include "geocel/random/IsotropicDistribution.hh" #include "celeritas/Quantities.hh" -#include "celeritas/decay/data/MuDecayData.hh" #include "celeritas/phys/FourVector.hh" #include "celeritas/phys/Interaction.hh" #include "celeritas/phys/ParticleTrackView.hh" @@ -64,7 +63,7 @@ class MuDecayInteractor public: // Construct with shared and state data inline CELER_FUNCTION - MuDecayInteractor(MuDecayData const& shared, + MuDecayInteractor(Span daughters, ParticleTrackView const& particle, Real3 const& inc_direction, StackAllocator& allocate); @@ -82,14 +81,12 @@ class MuDecayInteractor //// DATA //// - // Constant data - MuDecayData const& shared_; + // Daughter particle properties + ParticleView daughter_; // Incident muon energy Energy const inc_energy_; // Allocate space for secondary particles (electron only) StackAllocator& allocate_; - // Define decay channel based on muon or anti-muon primary - ParticleId sec_id_; // Incident muon four vector FourVector inc_fourvec_; // Maximum electron energy [MeV] @@ -121,23 +118,18 @@ class MuDecayInteractor * using the physics manual definition. */ CELER_FUNCTION -MuDecayInteractor::MuDecayInteractor(MuDecayData const& shared, +MuDecayInteractor::MuDecayInteractor(Span daughters, ParticleTrackView const& particle, Real3 const& inc_direction, StackAllocator& allocate) - : shared_(shared) + : daughter_(particle.particle_view(daughters.front())) , inc_energy_(particle.energy()) , allocate_(allocate) - , sec_id_((particle.particle_id() == shared_.mu_minus_id) - ? shared_.electron_id - : shared_.positron_id) , inc_fourvec_{FourVector::from_particle(particle, inc_direction)} - , max_energy_(real_type{0.5} * shared_.muon_mass.value() - - shared_.electron_mass.value()) + , max_energy_(real_type{0.5} * value_as(particle.mass()) + - value_as(daughter_.mass())) { - CELER_EXPECT(shared_); - CELER_EXPECT(particle.particle_id() == shared_.mu_minus_id - || particle.particle_id() == shared_.mu_plus_id); + CELER_EXPECT(daughters.size() == 1); } //---------------------------------------------------------------------------// @@ -163,26 +155,26 @@ CELER_FUNCTION Interaction MuDecayInteractor::operator()(Engine& rng) { electron_nu_energy_frac = generate_canonical(rng); } while (RejectionSampler( - electron_nu_energy_frac * (real_type{1} - electron_nu_energy_frac), + electron_nu_energy_frac * (1 - electron_nu_energy_frac), real_type{0.25})(rng)); electron_energy_frac = generate_canonical(rng); - } while (electron_nu_energy_frac + electron_energy_frac < real_type{1}); + } while (electron_nu_energy_frac + electron_energy_frac < 1); // Decay isotropically in rest frame and boost secondaries to the lab frame auto charged_lep_fv = this->to_lab_frame( IsotropicDistribution{}(rng), - this->calc_momentum(electron_energy_frac, shared_.electron_mass), - shared_.electron_mass); + this->calc_momentum(electron_energy_frac, daughter_.mass()), + daughter_.mass()); // Return charged lepton only Interaction result = Interaction::from_absorption(); - result.secondaries = {secondaries, 1}; - result.secondaries[0].particle_id = sec_id_; + secondaries[0].particle_id = daughter_.particle_id(); // Interaction stores kinetic energy; FourVector stores total energy - result.secondaries[0].energy - = Energy{charged_lep_fv.energy - shared_.electron_mass.value()}; - result.secondaries[0].direction = make_unit_vector(charged_lep_fv.mom); + secondaries[0].energy + = Energy{charged_lep_fv.energy - value_as(daughter_.mass())}; + secondaries[0].direction = make_unit_vector(charged_lep_fv.mom); + result.secondaries = {secondaries, 1}; return result; } diff --git a/src/celeritas/em/process/BremsstrahlungProcess.hh b/src/celeritas/em/process/BremsstrahlungProcess.hh index bfbc39b503..b0c396b6f9 100644 --- a/src/celeritas/em/process/BremsstrahlungProcess.hh +++ b/src/celeritas/em/process/BremsstrahlungProcess.hh @@ -21,7 +21,7 @@ namespace celeritas /*! * Bremsstrahlung process for electrons and positrons. */ -class BremsstrahlungProcess : public Process +class BremsstrahlungProcess : public InteractionProcess { public: //!@{ diff --git a/src/celeritas/em/process/ComptonProcess.hh b/src/celeritas/em/process/ComptonProcess.hh index dacf7fd361..77344d1c0f 100644 --- a/src/celeritas/em/process/ComptonProcess.hh +++ b/src/celeritas/em/process/ComptonProcess.hh @@ -19,7 +19,7 @@ namespace celeritas /*! * Compton scattering process for gammas. */ -class ComptonProcess : public Process +class ComptonProcess : public InteractionProcess { public: //!@{ diff --git a/src/celeritas/em/process/CoulombScatteringProcess.hh b/src/celeritas/em/process/CoulombScatteringProcess.hh index 0705fbce65..fb6d758cbf 100644 --- a/src/celeritas/em/process/CoulombScatteringProcess.hh +++ b/src/celeritas/em/process/CoulombScatteringProcess.hh @@ -22,7 +22,7 @@ namespace celeritas /*! * Coulomb scattering process for electrons off of atoms. */ -class CoulombScatteringProcess : public Process +class CoulombScatteringProcess : public InteractionProcess { public: //!@{ diff --git a/src/celeritas/em/process/EIonizationProcess.hh b/src/celeritas/em/process/EIonizationProcess.hh index 8233292d4c..4f438d054e 100644 --- a/src/celeritas/em/process/EIonizationProcess.hh +++ b/src/celeritas/em/process/EIonizationProcess.hh @@ -19,7 +19,7 @@ namespace celeritas /*! * Ionization process for electrons and positrons. */ -class EIonizationProcess : public Process +class EIonizationProcess : public InteractionProcess { public: //!@{ diff --git a/src/celeritas/em/process/EPlusAnnihilationProcess.hh b/src/celeritas/em/process/EPlusAnnihilationProcess.hh index 53f1f3d1df..fabc0e38c3 100644 --- a/src/celeritas/em/process/EPlusAnnihilationProcess.hh +++ b/src/celeritas/em/process/EPlusAnnihilationProcess.hh @@ -19,7 +19,7 @@ namespace celeritas /*! * Annihiliation process for positrons. */ -class EPlusAnnihilationProcess final : public Process +class EPlusAnnihilationProcess final : public InteractionProcess { public: //!@{ diff --git a/src/celeritas/em/process/GammaConversionProcess.hh b/src/celeritas/em/process/GammaConversionProcess.hh index bdef82129c..ccb1012880 100644 --- a/src/celeritas/em/process/GammaConversionProcess.hh +++ b/src/celeritas/em/process/GammaConversionProcess.hh @@ -19,7 +19,7 @@ namespace celeritas /*! * Conversion of gammas to electrons and positrons. */ -class GammaConversionProcess : public Process +class GammaConversionProcess : public InteractionProcess { public: //!@{ diff --git a/src/celeritas/em/process/MuBremsstrahlungProcess.hh b/src/celeritas/em/process/MuBremsstrahlungProcess.hh index 2444b2ab71..4353d9bd83 100644 --- a/src/celeritas/em/process/MuBremsstrahlungProcess.hh +++ b/src/celeritas/em/process/MuBremsstrahlungProcess.hh @@ -20,7 +20,7 @@ namespace celeritas /*! * Bremsstrahlung process for muons. */ -class MuBremsstrahlungProcess : public Process +class MuBremsstrahlungProcess : public InteractionProcess { public: //!@{ diff --git a/src/celeritas/em/process/MuIonizationProcess.hh b/src/celeritas/em/process/MuIonizationProcess.hh index 1e81aa4152..33981bfbe5 100644 --- a/src/celeritas/em/process/MuIonizationProcess.hh +++ b/src/celeritas/em/process/MuIonizationProcess.hh @@ -19,7 +19,7 @@ namespace celeritas /*! * Ionization process for muons. */ -class MuIonizationProcess : public Process +class MuIonizationProcess : public InteractionProcess { public: //!@{ diff --git a/src/celeritas/em/process/MuPairProductionProcess.hh b/src/celeritas/em/process/MuPairProductionProcess.hh index e8cd7e9a10..dbd5e3fec7 100644 --- a/src/celeritas/em/process/MuPairProductionProcess.hh +++ b/src/celeritas/em/process/MuPairProductionProcess.hh @@ -21,7 +21,7 @@ namespace celeritas /*! * Electron-positron pair production process for muons. */ -class MuPairProductionProcess : public Process +class MuPairProductionProcess : public InteractionProcess { public: //!@{ diff --git a/src/celeritas/em/process/PhotoelectricProcess.hh b/src/celeritas/em/process/PhotoelectricProcess.hh index e416cc7106..d5ddff0ff9 100644 --- a/src/celeritas/em/process/PhotoelectricProcess.hh +++ b/src/celeritas/em/process/PhotoelectricProcess.hh @@ -22,7 +22,7 @@ namespace celeritas /*! * Photoelectric effect process for gammas. */ -class PhotoelectricProcess : public Process +class PhotoelectricProcess : public InteractionProcess { public: //!@{ diff --git a/src/celeritas/em/process/RayleighProcess.hh b/src/celeritas/em/process/RayleighProcess.hh index 05df11c087..989615d9a5 100644 --- a/src/celeritas/em/process/RayleighProcess.hh +++ b/src/celeritas/em/process/RayleighProcess.hh @@ -20,7 +20,7 @@ namespace celeritas /*! * Rayleigh scattering process for gammas. */ -class RayleighProcess : public Process +class RayleighProcess : public InteractionProcess { public: //!@{ diff --git a/src/celeritas/ext/GeantImporter.cc b/src/celeritas/ext/GeantImporter.cc index b748817417..30fa5ab967 100644 --- a/src/celeritas/ext/GeantImporter.cc +++ b/src/celeritas/ext/GeantImporter.cc @@ -453,8 +453,6 @@ import_particles(GeantImporter::DataSelection::Flags particle_flags) result.mass = particle_view.mass(); result.charge = particle_view.charge(); result.decay_constant = particle_view.decay_constant(); - result.decay_table - = import_decay_table(*(particle_iterator.value())); if (G4VERSION_NUMBER < 1070 && particle_view.is_optical_photon()) { @@ -985,9 +983,21 @@ inp::DecayPhysics::DecayTable import_decay_table(G4ParticleDefinition const& p) inp::DecayChannel channel; channel.type = to_decay_channel_type(g4_channel); channel.branching_ratio = g4_channel->GetBR(); - for (auto daughter_idx : range(g4_channel->GetNumberOfDaughters())) + + // Exclude the neutrino daughters for muon decay + //! \todo Remove once neutrinos are included in \c MuDecayInteractor + size_type num_daughters = channel.type == DecayChannelType::muon + ? 1 + : g4_channel->GetNumberOfDaughters(); + + for (auto daughter_idx : range(num_daughters)) { auto const* daughter = g4_channel->GetDaughter(daughter_idx); + CELER_VALIDATE(daughter, + << "decay process is enabled for particle " + << p.GetParticleName() << ", but daughter '" + << g4_channel->GetDaughterName(daughter_idx) + << "' is not defined"); channel.daughters.push_back(PDGNumber(daughter->GetPDGEncoding())); } result.push_back(std::move(channel)); @@ -1029,6 +1039,9 @@ auto import_processes(GeantImporter::DataSelection selected, if (dynamic_cast(&process)) { // Store decay table if decay process is enabled for this particle + CELER_LOG(debug) << "Saving process '" << process.GetProcessName() + << "' for particle " << particle.GetParticleName() + << " (" << particle.GetPDGEncoding() << ')'; decay.tables.insert({PDGNumber(particle.GetPDGEncoding()), import_decay_table(particle)}); return; diff --git a/src/celeritas/ext/RootInterfaceLinkDef.h b/src/celeritas/ext/RootInterfaceLinkDef.h index 8f0a74403d..c5b2f9fdc9 100644 --- a/src/celeritas/ext/RootInterfaceLinkDef.h +++ b/src/celeritas/ext/RootInterfaceLinkDef.h @@ -45,6 +45,7 @@ // Input data +#pragma link C++ class celeritas::inp::DecayChannel+; #pragma link C++ class celeritas::inp::DecayPhysics+; #pragma link C++ class celeritas::inp::FresnelReflection+; #pragma link C++ class celeritas::inp::GaussianRoughness+; diff --git a/src/celeritas/inp/Physics.hh b/src/celeritas/inp/Physics.hh index b6503f0852..7b692bf729 100644 --- a/src/celeritas/inp/Physics.hh +++ b/src/celeritas/inp/Physics.hh @@ -117,6 +117,9 @@ struct DecayPhysics //! Decay channels for particles for which decay is enabled std::unordered_map tables; + + //! Whether the data are assigned + explicit operator bool() const { return !tables.empty(); } }; //---------------------------------------------------------------------------// diff --git a/src/celeritas/inp/ProcessBuilder.hh b/src/celeritas/inp/ProcessBuilder.hh index 6a8c73bd57..2656cf4e84 100644 --- a/src/celeritas/inp/ProcessBuilder.hh +++ b/src/celeritas/inp/ProcessBuilder.hh @@ -18,7 +18,7 @@ namespace celeritas class ImportedProcesses; class MaterialParams; class ParticleParams; -class Process; +class InteractionProcess; namespace inp { @@ -38,7 +38,8 @@ struct ProcessBuilderInput //!@{ //! \name User builder type aliases using ProcessBuilderFunction - = std::function(ProcessBuilderInput const&)>; + = std::function( + ProcessBuilderInput const&)>; using ProcessBuilderMap = std::unordered_map; //!@} diff --git a/src/celeritas/neutron/process/NeutronElasticProcess.hh b/src/celeritas/neutron/process/NeutronElasticProcess.hh index 6181244275..1186765e95 100644 --- a/src/celeritas/neutron/process/NeutronElasticProcess.hh +++ b/src/celeritas/neutron/process/NeutronElasticProcess.hh @@ -22,7 +22,7 @@ namespace celeritas /*! * Elastic scattering process for neutrons. */ -class NeutronElasticProcess : public Process +class NeutronElasticProcess : public InteractionProcess { public: //!@{ diff --git a/src/celeritas/neutron/process/NeutronInelasticProcess.hh b/src/celeritas/neutron/process/NeutronInelasticProcess.hh index 01e8e991d9..fa73435895 100644 --- a/src/celeritas/neutron/process/NeutronInelasticProcess.hh +++ b/src/celeritas/neutron/process/NeutronInelasticProcess.hh @@ -22,7 +22,7 @@ namespace celeritas /*! * Inelastic interaction process for neutrons. */ -class NeutronInelasticProcess : public Process +class NeutronInelasticProcess : public InteractionProcess { public: //!@{ diff --git a/src/celeritas/phys/ImportedProcessAdapter.hh b/src/celeritas/phys/ImportedProcessAdapter.hh index b47f582794..6797576cdb 100644 --- a/src/celeritas/phys/ImportedProcessAdapter.hh +++ b/src/celeritas/phys/ImportedProcessAdapter.hh @@ -77,8 +77,8 @@ class ImportedProcessAdapter //! \name Type aliases using SPConstImported = std::shared_ptr; using SPConstParticles = std::shared_ptr; - using XsGrid = Process::XsGrid; - using EnergyLossGrid = Process::EnergyLossGrid; + using XsGrid = InteractionProcess::XsGrid; + using EnergyLossGrid = InteractionProcess::EnergyLossGrid; using SpanConstPDG = Span; //!@} diff --git a/src/celeritas/phys/ParticleTrackView.hh b/src/celeritas/phys/ParticleTrackView.hh index c360562fc0..7a0da1ebf5 100644 --- a/src/celeritas/phys/ParticleTrackView.hh +++ b/src/celeritas/phys/ParticleTrackView.hh @@ -77,8 +77,12 @@ class ParticleTrackView //// STATIC PROPERTIES (requires an indirection) //// + // Get static particle properties for the current state CELER_FORCEINLINE_FUNCTION ParticleView particle_view() const; + // Get static particle properties for another particle type + CELER_FORCEINLINE_FUNCTION ParticleView particle_view(ParticleId) const; + // Rest mass [MeV / c^2] CELER_FORCEINLINE_FUNCTION Mass mass() const; @@ -117,6 +121,9 @@ class ParticleTrackView // Relativistic momentum squared [MeV^2 / c^2] inline CELER_FUNCTION MomentumSq momentum_sq() const; + // Decay length [len] + inline CELER_FUNCTION real_type decay_length() const; + private: ParamsRef const& params_; StateRef const& states_; @@ -219,6 +226,16 @@ CELER_FUNCTION ParticleView ParticleTrackView::particle_view() const return ParticleView(params_, states_.particle_id[track_slot_]); } +//---------------------------------------------------------------------------// +/*! + * Get static particle properties for another particle type. + */ +CELER_FUNCTION ParticleView ParticleTrackView::particle_view(ParticleId id) const +{ + CELER_EXPECT(id < params_.size()); + return ParticleView(params_, id); +} + //---------------------------------------------------------------------------// /*! * Rest mass [MeV / c^2]. @@ -405,5 +422,18 @@ CELER_FUNCTION auto ParticleTrackView::momentum() const -> Momentum return Momentum{std::sqrt(this->momentum_sq().value())}; } +//---------------------------------------------------------------------------// +/*! + * Decay length \f$ d = \beta \gamma c \tau \f$ [len]. + */ +CELER_FUNCTION real_type ParticleTrackView::decay_length() const +{ + CELER_EXPECT(this->mass() > zero_quantity()); + CELER_EXPECT(this->decay_constant() != constants::stable_decay_constant); + + return constants::c_light * value_as(this->momentum()) + / (value_as(this->mass()) * this->decay_constant()); +} + //---------------------------------------------------------------------------// } // namespace celeritas diff --git a/src/celeritas/phys/PhysicsData.hh b/src/celeritas/phys/PhysicsData.hh index c0e27c7fa3..082e760828 100644 --- a/src/celeritas/phys/PhysicsData.hh +++ b/src/celeritas/phys/PhysicsData.hh @@ -12,6 +12,7 @@ #include "corecel/data/StackAllocatorData.hh" #include "celeritas/Quantities.hh" #include "celeritas/Types.hh" +#include "celeritas/decay/DecayData.hh" #include "celeritas/em/data/AtomicRelaxationData.hh" #include "celeritas/em/data/EPlusGGData.hh" #include "celeritas/em/data/LivermorePEData.hh" @@ -132,6 +133,7 @@ struct ProcessGroup UniformTable energy_loss; //!< Process-integrated energy loss UniformTable range; //!< Process-integrated range UniformTable inverse_range; //!< Inverse process-integrated range + DecayTableData decay; //!< Decay channels and branching ratios ParticleProcessId at_rest; //!< ID of the particle's at-rest process //! True if assigned and valid @@ -243,6 +245,10 @@ struct PhysicsParamsScalars ActionId::size_type model_to_action{}; //! Number of physics models ModelId::size_type num_models{}; + //! Number of decay channels + ModelId::size_type num_channels{}; + //! ID of the decay process + ProcessId decay; // User-configurable constants real_type min_eprime_over_e{}; //!< xi [unitless] @@ -300,7 +306,7 @@ struct PhysicsParamsScalars //! Indicate an interaction failed to allocate memory CELER_FORCEINLINE_FUNCTION ActionId failure_action() const { - return ActionId{model_to_action + num_models}; + return ActionId{model_to_action + num_models + num_channels}; } }; @@ -323,6 +329,8 @@ struct PhysicsParamsData using ParticleItems = Collection; template using ParticleModelItems = Collection; + template + using DecayChannelItems = Collection; //// DATA //// @@ -349,6 +357,12 @@ struct PhysicsParamsData Items pmodel_ids; Items process_ids; + // Decay table storage + Items daughters; + Items channel_ids; + DecayChannelItems channels; + DecayChannelItems actions; + // Backend storage Items reals; @@ -385,6 +399,11 @@ struct PhysicsParamsData pmodel_ids = other.pmodel_ids; process_ids = other.process_ids; + daughters = other.daughters; + channel_ids = other.channel_ids; + channels = other.channels; + actions = other.actions; + reals = other.reals; return *this; @@ -454,6 +473,7 @@ struct PhysicsStateData StateItems state; //!< Track state [track] StateItems msc_step; //!< Internal MSC data [track] + StateItems decay_channel; //!< Sampled channel [track] Items per_process_xs; //!< XS [track][particle process] @@ -478,6 +498,7 @@ struct PhysicsStateData CELER_EXPECT(other); state = other.state; msc_step = other.msc_step; + decay_channel = other.decay_channel; per_process_xs = other.per_process_xs; @@ -501,6 +522,10 @@ inline void resize(PhysicsStateData* state, CELER_EXPECT(params.scalars.max_particle_processes > 0); resize(&state->state, size); resize(&state->msc_step, size); + if (params.scalars.decay) + { + resize(&state->decay_channel, size); + } resize(&state->per_process_xs, size * params.scalars.max_particle_processes); resize(&state->relaxation, params.hardwired.relaxation, size); diff --git a/src/celeritas/phys/PhysicsParams.cc b/src/celeritas/phys/PhysicsParams.cc index b498400d18..e384d74ea1 100644 --- a/src/celeritas/phys/PhysicsParams.cc +++ b/src/celeritas/phys/PhysicsParams.cc @@ -52,6 +52,7 @@ #include "PhysicsData.hh" #include "Process.hh" +#include "detail/DecayTableInserter.hh" #include "detail/DiscreteSelectAction.hh" #include "detail/EnergyMaxXsCalculator.hh" #include "detail/PreStepAction.hh" @@ -87,6 +88,7 @@ bool ignore_particle(PDGNumber pdg) */ PhysicsParams::PhysicsParams(Input inp) : processes_(std::move(inp.processes)) + , decay_(std::move(inp.decay)) , relaxation_(std::move(inp.relaxation)) { CELER_EXPECT(!processes_.empty()); @@ -136,6 +138,9 @@ PhysicsParams::PhysicsParams(Input inp) // Emit models for associated processes models_ = this->build_models(inp.action_registry); + // Emit channels for the decay process + channels_ = this->build_channels(inp.action_registry); + // Place "failure" *after* all the model IDs auto failure_action = make_shared( action_reg.next_id(), @@ -149,7 +154,7 @@ PhysicsParams::PhysicsParams(Input inp) HostValue host_data; this->build_options(inp.options, &host_data); this->build_ids(*inp.particles, &host_data); - this->build_tables(inp.options, *inp.materials, &host_data); + this->build_tables(inp, &host_data); this->build_model_tables(*inp.materials, &host_data); // Add step limiter if being used (TODO: remove this hack from physics) @@ -205,6 +210,9 @@ auto PhysicsParams::processes(ParticleId id) const -> SpanConstProcessId //---------------------------------------------------------------------------// // HELPER FUNCTIONS //---------------------------------------------------------------------------// +/*! + * Construct models and add to the action registry. + */ auto PhysicsParams::build_models(ActionRegistry* mgr) const -> VecModel { VecModel models; @@ -231,6 +239,33 @@ auto PhysicsParams::build_models(ActionRegistry* mgr) const -> VecModel return models; } +//---------------------------------------------------------------------------// +/*! + * Construct decay channels and add to the action registry. + */ +auto PhysicsParams::build_channels(ActionRegistry* reg) const -> VecChannel +{ + if (!decay_) + { + // No decay process + return {}; + } + + // Construct channels, assigning each channel ID + auto id_iter = Process::ActionIdIter{reg->next_id()}; + auto result = decay_->build_channels(id_iter); + CELER_ASSERT(!result.empty()); + for (auto const& channel : result) + { + CELER_ASSERT(channel); + CELER_ASSERT(channel->action_id() == *id_iter++); + + // Add channel to action registry + reg->insert(channel); + } + return result; +} + //---------------------------------------------------------------------------// /*! * Construct on-device particle-dependent physics options. @@ -315,7 +350,7 @@ void PhysicsParams::build_ids(ParticleParams const& particles, data->scalars.model_to_action = this->model(ModelId{0})->action_id().get(); // Note: use map to keep ProcessId sorted - std::vector particle_models(particles.size()); + std::vector particle_to_proc(particles.size()); std::vector temp_model_ids; ParticleModelId::size_type pm_idx{0}; @@ -339,13 +374,26 @@ void PhysicsParams::build_ids(ParticleParams const& particles, << " MeV) to be less than upper energy limit (" << value_as(applic.upper) << " MeV) for model " << m.label()); - particle_models[applic.particle.get()][process_id].push_back( + particle_to_proc[applic.particle.get()][process_id].push_back( {value_as(applic.lower), value_as(applic.upper), ParticleModelId{pm_idx++}}); temp_model_ids.push_back(mid); } } + if (decay_) + { + // Store decay process ID + data->scalars.decay = ProcessId(processes_.size()); + for (auto pid : range(ParticleId(particles.size()))) + { + if (decay_->is_applicable(pid)) + { + // Add null models for decay process + particle_to_proc[pid.get()][data->scalars.decay].push_back({}); + } + } + } make_builder(&data->model_ids) .insert_back(temp_model_ids.begin(), temp_model_ids.end()); @@ -355,13 +403,14 @@ void PhysicsParams::build_ids(ParticleParams const& particles, CollectionBuilder pmodel_ids(&data->pmodel_ids); DedupeCollectionBuilder reals(&data->reals); - process_groups.reserve(particle_models.size()); + process_groups.reserve(particle_to_proc.size()); // Loop over particle IDs, set ProcessGroup ProcessId::size_type max_particle_processes = 0; for (auto par_id : range(ParticleId{particles.size()})) { - auto& process_to_models = particle_models[par_id.get()]; + // Get map of process ID to model range for this particle + auto& process_to_models = particle_to_proc[par_id.get()]; if (process_to_models.empty() && !ignore_particle(particles.id_to_pdg(par_id))) { @@ -380,8 +429,15 @@ void PhysicsParams::build_ids(ParticleParams const& particles, // Add process ID temp_processes.push_back(pid_models.first); + if (pid_models.second.empty()) + { + // Skip constructing model data for decay, which has no models + CELER_ASSERT(pid_models.first == data->scalars.decay); + temp_model_groups.push_back({}); + continue; + } + std::vector& models = pid_models.second; - CELER_ASSERT(!models.empty()); // Construct model data std::vector temp_energy_grid; @@ -431,6 +487,7 @@ void PhysicsParams::build_ids(ParticleParams const& particles, } data->scalars.max_particle_processes = max_particle_processes; data->scalars.num_models = this->num_models(); + data->scalars.num_channels = this->channels_.size(); // Assign hardwired models that do on-the-fly xs calculation for (auto model_id : range(ModelId(this->num_models()))) @@ -493,9 +550,7 @@ void PhysicsParams::build_hardwired() /*! * Construct cross section data. */ -void PhysicsParams::build_tables(Options const& opts, - MaterialParams const& mats, - HostValue* data) const +void PhysicsParams::build_tables(Input const& inp, HostValue* data) const { CELER_EXPECT(*data); @@ -510,6 +565,7 @@ void PhysicsParams::build_tables(Options const& opts, XsGridInserter insert_xs(&data->reals, &data->xs_grids); UniformGridInserter insert_uniform(&data->reals, &data->uniform_grids); + detail::DecayTableInserter insert_decay(inp.particles, channels_, *data); Applicability applic; for (auto particle_id : range(ParticleId(data->process_groups.size()))) @@ -531,93 +587,120 @@ void PhysicsParams::build_tables(Options const& opts, // Loop over per-particle processes for (auto pp_idx : range(process_ids.size())) { - // Get energy bounds for this process - auto energy_grid = data->reals[model_groups[pp_idx].energy]; - applic.lower = Energy{energy_grid.front()}; - applic.upper = Energy{energy_grid.back()}; - CELER_ASSERT(applic.lower < applic.upper); - - Process const& proc = *this->process(process_ids[pp_idx]); - // Grid IDs for each grid type, each material - std::vector macro_xs_ids(mats.size()); - std::vector energy_loss_ids(mats.size()); - std::vector range_ids(mats.size()); + std::vector macro_xs_ids(inp.materials->size()); + std::vector energy_loss_ids(inp.materials->size()); + std::vector range_ids(inp.materials->size()); std::vector inverse_range_ids; - - // Energy of maximum cross section for each material - detail::EnergyMaxXsCalculator calc_integral_xs(opts, proc); std::vector energy_max_xs; - if (calc_integral_xs) - { - energy_max_xs.resize(mats.size()); - } - if (proc.applies_at_rest()) + auto set_at_rest = [&](Process const& p) { + if (p.applies_at_rest()) + { + /* \todo For now assume only one process per particle + * applies at rest. If a particle has multiple + * at-rest processes, we will need to select the + * process with the shortest time to interaction in + * \c select_discrete_interaction. + */ + CELER_VALIDATE(!process_group.at_rest, + << "particle " + << inp.particles->id_to_label(particle_id) + << " has multiple at-rest processes"); + + // Discrete interaction can occur at rest + process_group.at_rest = ParticleProcessId(pp_idx); + } + }; + + ProcessId process_id = process_ids[pp_idx]; + if (process_id == data->scalars.decay) { - /* \todo For now assume only one process per particle applies - * at rest. If a particle has multiple at-rest processes, we - * will need to check which process has the shortest time to - * interaction and choose that process in \c - * select_discrete_interaction. - */ - CELER_VALIDATE(!process_group.at_rest, - << "particle ID " << particle_id.get() - << " has multiple at-rest processes"); - - // Discrete interaction can occur at rest - process_group.at_rest = ParticleProcessId(pp_idx); - } + // Check whether discrete interaction can occur at rest + CELER_ASSERT(decay_); + set_at_rest(*decay_); - // Loop over materials - for (auto mat_idx : range(mats.size())) + // Build the decay table for this particle + auto table = decay_->decay_table(particle_id); + process_group.decay = insert_decay(table); + } + else { - applic.material = PhysMatId(mat_idx); + // Build the cross section and energy loss grids + InteractionProcess const& proc = *this->process(process_id); + + // Check whether discrete interaction can occur at rest + set_at_rest(proc); + + // Get energy bounds for this process + auto energy_grid = data->reals[model_groups[pp_idx].energy]; + applic.lower = Energy{energy_grid.front()}; + applic.upper = Energy{energy_grid.back()}; + CELER_ASSERT(applic.lower < applic.upper); - // Construct macroscopic cross section grid - auto macro_xs = proc.macro_xs(applic); - if (macro_xs) + // Energy of maximum cross section for each material + detail::EnergyMaxXsCalculator calc_integral_xs(inp.options, + proc); + if (calc_integral_xs) { - macro_xs_ids[mat_idx] = insert_xs(macro_xs); + energy_max_xs.resize(inp.materials->size()); } - // Construct energy loss grid - auto energy_loss = proc.energy_loss(applic); - if (energy_loss) + // Loop over materials + for (auto mat_idx : range(inp.materials->size())) { - energy_loss_ids[mat_idx] = insert_uniform(energy_loss); + applic.material = PhysMatId(mat_idx); - // Construct range grid from energy loss - auto range = RangeGridCalculator(BC::geant)(energy_loss); - range_ids[mat_idx] = insert_uniform(range); + // Construct macroscopic cross section grid + auto macro_xs = proc.macro_xs(applic); + if (macro_xs) + { + macro_xs_ids[mat_idx] = insert_xs(macro_xs); + } - if (range.interpolation.type - == InterpolationType::cubic_spline) + // Construct energy loss grid + auto energy_loss = proc.energy_loss(applic); + if (energy_loss) { - // Build the inverse range grid if cubic spline - // interpolation is used - inverse_range_ids.resize(mats.size(), UniformGridId{}); - - // The range and energy values are not inverted on the - // grid, but the derivatives are calculated using the - // inverted grid. - auto inverse_range - = data->uniform_grids[range_ids[mat_idx]]; - auto derivative - = SplineDerivCalculator(BC::geant).calc_from_inverse( - inverse_range, make_const_ref(*data).reals); - inverse_range.derivative = reals.insert_back( - derivative.begin(), derivative.end()); - inverse_range_ids[mat_idx] - = uniform_grids.push_back(inverse_range); + energy_loss_ids[mat_idx] = insert_uniform(energy_loss); + + // Construct range grid from energy loss + auto range + = RangeGridCalculator(BC::geant)(energy_loss); + range_ids[mat_idx] = insert_uniform(range); + + if (range.interpolation.type + == InterpolationType::cubic_spline) + { + // Build the inverse range grid if cubic spline + // interpolation is used + inverse_range_ids.resize(inp.materials->size(), + UniformGridId{}); + + // The range and energy values are not inverted on + // the grid, but the derivatives are calculated + // using the inverted grid. + auto inverse_range + = data->uniform_grids[range_ids[mat_idx]]; + auto derivative + = SplineDerivCalculator(BC::geant) + .calc_from_inverse( + inverse_range, + make_const_ref(*data).reals); + inverse_range.derivative = reals.insert_back( + derivative.begin(), derivative.end()); + inverse_range_ids[mat_idx] + = uniform_grids.push_back(inverse_range); + } } - } - if (calc_integral_xs) - { - // Find and store the energy of the largest cross section - // for this material if the integral approach is used - energy_max_xs[mat_idx] = calc_integral_xs(macro_xs); + if (calc_integral_xs) + { + // Find and store the energy of the largest cross + // section for this material if the integral approach + // is used + energy_max_xs[mat_idx] = calc_integral_xs(macro_xs); + } } } diff --git a/src/celeritas/phys/PhysicsParams.hh b/src/celeritas/phys/PhysicsParams.hh index 976d3b48c6..b986187b99 100644 --- a/src/celeritas/phys/PhysicsParams.hh +++ b/src/celeritas/phys/PhysicsParams.hh @@ -20,6 +20,7 @@ #include "celeritas/Quantities.hh" #include "celeritas/Types.hh" #include "celeritas/Units.hh" +#include "celeritas/decay/DecayProcess.hh" #include "celeritas/global/ActionInterface.hh" #include "Model.hh" @@ -62,10 +63,12 @@ class PhysicsParams final : public ParamsDataInterface //! \name Type aliases using SPConstParticles = std::shared_ptr; using SPConstMaterials = std::shared_ptr; - using SPConstProcess = std::shared_ptr; + using SPConstProcess = std::shared_ptr; + using SPConstDecay = std::shared_ptr; using SPConstModel = std::shared_ptr; using SPConstRelaxation = std::shared_ptr; + using VecChannel = DecayProcess::VecChannel; using VecProcess = std::vector; using SpanConstProcessId = Span; using ActionIdRange = Range; @@ -78,6 +81,7 @@ class PhysicsParams final : public ParamsDataInterface SPConstParticles particles; SPConstMaterials materials; VecProcess processes; + SPConstDecay decay; //!< Optional decay process SPConstRelaxation relaxation; //!< Optional atomic relaxation ActionRegistry* action_registry = nullptr; @@ -111,6 +115,12 @@ class PhysicsParams final : public ParamsDataInterface // Get the process for the given model inline ProcessId process_id(ModelId id) const; + //! Get decay process + SPConstDecay decay_process() const { return decay_; } + + //! Get decay channels + VecChannel const& decay_channels() const { return channels_; } + // Get the action IDs for all models inline ActionIdRange model_actions() const; @@ -142,6 +152,8 @@ class PhysicsParams final : public ParamsDataInterface // Host metadata/access VecProcess processes_; VecModel models_; + SPConstDecay decay_; + VecChannel channels_; SPConstRelaxation relaxation_; // Host/device storage and reference @@ -152,10 +164,11 @@ class PhysicsParams final : public ParamsDataInterface private: VecModel build_models(ActionRegistry*) const; + VecChannel build_channels(ActionRegistry*) const; void build_options(Options const&, HostValue*) const; void build_particle_options(ParticleOptions const&, ParticleScalars*) const; void build_ids(ParticleParams const&, HostValue*) const; - void build_tables(Options const&, MaterialParams const&, HostValue*) const; + void build_tables(Input const& inp, HostValue*) const; void build_model_tables(MaterialParams const&, HostValue*) const; void build_hardwired(); }; diff --git a/src/celeritas/phys/PhysicsParamsOutput.cc b/src/celeritas/phys/PhysicsParamsOutput.cc index fb0daf83fb..9b2084a4fe 100644 --- a/src/celeritas/phys/PhysicsParamsOutput.cc +++ b/src/celeritas/phys/PhysicsParamsOutput.cc @@ -69,9 +69,24 @@ void PhysicsParamsOutput::output(JsonPimpl* j) const Process const& p = *physics_->process(id); label.push_back(p.label()); } + if (auto p = physics_->decay_process()) + { + label.push_back(p->label()); + } obj["processes"] = {{"label", std::move(label)}}; } + // Save decay channels + { + auto label = json::array(); + + for (auto const& channel : physics_->decay_channels()) + { + label.push_back(channel->label()); + } + obj["decay_channels"] = {{"label", std::move(label)}}; + } + // Save options { auto const& scalars = physics_->host_ref().scalars; diff --git a/src/celeritas/phys/PhysicsStepUtils.hh b/src/celeritas/phys/PhysicsStepUtils.hh index 916f776236..502d931a2e 100644 --- a/src/celeritas/phys/PhysicsStepUtils.hh +++ b/src/celeritas/phys/PhysicsStepUtils.hh @@ -116,7 +116,13 @@ calc_physics_step_limit(MaterialTrackView const& material, for (auto ppid : range(ParticleProcessId{physics.num_particle_processes()})) { real_type process_xs = 0; - if (auto const& process = physics.integral_xs_process(ppid)) + if (physics.process(ppid) == physics.scalars().decay) + { + // Calculate the macroscopic cross section as the inverse of the + // particle's decay length + process_xs = 1 / particle.decay_length(); + } + else if (auto const& process = physics.integral_xs_process(ppid)) { // If the integral approach is used and this particle has an energy // loss process, estimate the maximum cross section over the step @@ -314,6 +320,16 @@ select_discrete_interaction(MaterialView const& material, return physics.scalars().integral_rejection_action(); } + if (physics.process(ppid) == physics.scalars().decay) + { + // The decay process was selected: sample a decay channel according to + // the branching ratios and return the action corresponding to the + // channel type + auto channel_id = physics.select_decay_channel(rng); + pstep.decay_channel(channel_id); + return physics.channel_to_action(channel_id); + } + // Find the model that applies at the particle energy auto find_model = physics.make_model_finder(ppid); auto pmid = find_model(particle.energy()); diff --git a/src/celeritas/phys/PhysicsStepView.hh b/src/celeritas/phys/PhysicsStepView.hh index c8a05dd502..3e3adff02f 100644 --- a/src/celeritas/phys/PhysicsStepView.hh +++ b/src/celeritas/phys/PhysicsStepView.hh @@ -56,6 +56,9 @@ class PhysicsStepView // Set the sampled element inline CELER_FUNCTION void element(ElementComponentId); + // Set the sampled decay channel + inline CELER_FUNCTION void decay_channel(DecayChannelId); + // Save MSC step data inline CELER_FUNCTION void msc_step(MscStep const&); @@ -77,6 +80,9 @@ class PhysicsStepView // Sampled element for discrete interaction CELER_FORCEINLINE_FUNCTION ElementComponentId element() const; + // Sampled decay channel + CELER_FORCEINLINE_FUNCTION DecayChannelId decay_channel() const; + // Mutable access to MSC step data (TODO: hack) inline CELER_FUNCTION MscStep& msc_step(); @@ -148,6 +154,16 @@ CELER_FUNCTION void PhysicsStepView::element(ElementComponentId elcomp_id) this->state().element = elcomp_id; } +//---------------------------------------------------------------------------// +/*! + * Set the sampled decay channel. + */ +CELER_FUNCTION void PhysicsStepView::decay_channel(DecayChannelId channel_id) +{ + CELER_EXPECT(track_slot_ < states_.decay_channel.size()); + states_.decay_channel[track_slot_] = channel_id; +} + //---------------------------------------------------------------------------// /*! * Save MSC step limit data. @@ -222,6 +238,16 @@ CELER_FUNCTION ElementComponentId PhysicsStepView::element() const return this->state().element; } +//---------------------------------------------------------------------------// +/*! + * Sampled decay channel. + */ +CELER_FUNCTION DecayChannelId PhysicsStepView::decay_channel() const +{ + CELER_EXPECT(track_slot_ < states_.decay_channel.size()); + return states_.decay_channel[track_slot_]; +} + //---------------------------------------------------------------------------// /*! * Mutable access to MSC step data (TODO: hack) diff --git a/src/celeritas/phys/PhysicsTrackView.hh b/src/celeritas/phys/PhysicsTrackView.hh index 49019625f6..62c75b0c40 100644 --- a/src/celeritas/phys/PhysicsTrackView.hh +++ b/src/celeritas/phys/PhysicsTrackView.hh @@ -135,9 +135,17 @@ class PhysicsTrackView TabulatedElementSelector make_element_selector(UniformTableId, Energy) const; + // Sample a decay channel according to the branching ratios + template + inline CELER_FUNCTION DecayChannelId select_decay_channel(Engine&) const; + // ID of the particle's at-rest process inline CELER_FUNCTION ParticleProcessId at_rest_process() const; + // Get the daughters for a decay channel + inline CELER_FUNCTION Span + daughters(DecayChannelId) const; + //// PARAMETER DATA //// // Convert an action to a model ID for diagnostics, empty if not a model @@ -146,6 +154,9 @@ class PhysicsTrackView // Convert a selected model ID into a simulation action ID inline CELER_FUNCTION ActionId model_to_action(ModelId) const; + // Convert a selected decay channel ID into a simulation action ID + inline CELER_FUNCTION ActionId channel_to_action(DecayChannelId) const; + // Get the model ID corresponding to the given ParticleModelId inline CELER_FUNCTION ModelId model_id(ParticleModelId) const; @@ -603,6 +614,23 @@ PhysicsTrackView::make_element_selector(UniformTableId table_id, energy}; } +//---------------------------------------------------------------------------// +/*! + * Sample a decay channel according to the branching ratios. + */ +template +CELER_FUNCTION DecayChannelId +PhysicsTrackView::select_decay_channel(Engine& rng) const +{ + auto const& table = this->process_group().decay; + CELER_ASSERT(table); + auto branching_ratios = params_.reals[table.branching_ratios]; + auto idx = make_selector( + [&branching_ratios](size_type i) { return branching_ratios[i]; }, + branching_ratios.size())(rng); + return params_.channel_ids[table.channel_ids[idx]]; +} + //---------------------------------------------------------------------------// /*! * ID of the particle's at-rest process. @@ -615,6 +643,21 @@ CELER_FUNCTION ParticleProcessId PhysicsTrackView::at_rest_process() const return this->process_group().at_rest; } +//---------------------------------------------------------------------------// +/*! + * Get the daughters for a decay channel. + */ +CELER_FUNCTION Span +PhysicsTrackView::daughters(DecayChannelId channel_id) const +{ + CELER_EXPECT(channel_id < params_.channel_ids.size()); + auto const& table = this->process_group().decay; + CELER_ASSERT(table); + auto const& channel = params_.channels[channel_id]; + CELER_ASSERT(channel); + return params_.daughters[channel.daughters]; +} + //---------------------------------------------------------------------------// /*! * Convert an action to a model ID for diagnostics, false if not a model. @@ -643,6 +686,21 @@ CELER_FUNCTION ActionId PhysicsTrackView::model_to_action(ModelId model) const return ActionId{model.unchecked_get() + params_.scalars.model_to_action}; } +//---------------------------------------------------------------------------// +/*! + * Convert a sampled decay channel ID into a simulation action ID. + * + * Unlike the model-to-action ID conversion, there isn't a one-to-one + * correspondence between the channel ID and the action ID. Multiple channel + * IDs can map to a single channel action. + */ +CELER_FUNCTION ActionId +PhysicsTrackView::channel_to_action(DecayChannelId channel) const +{ + CELER_ASSERT(channel < params_.actions.size()); + return params_.actions[channel]; +} + //---------------------------------------------------------------------------// /*! * Get the model ID corresponding to the given ParticleModelId. diff --git a/src/celeritas/phys/Process.hh b/src/celeritas/phys/Process.hh index 96477854e9..d9962d0d42 100644 --- a/src/celeritas/phys/Process.hh +++ b/src/celeritas/phys/Process.hh @@ -19,6 +19,36 @@ namespace celeritas struct Applicability; class Model; +//---------------------------------------------------------------------------// +/*! + * An interface for physics processes. + */ +class Process +{ + public: + //!@{ + //! \name Type aliases + using ActionIdIter = RangeIter; + //!@} + + public: + // Virtual destructor for polymorphic deletion + virtual ~Process(); + + //! Whether the process applies when the particle is stopped + virtual bool applies_at_rest() const = 0; + + //! Name of the process + virtual std::string_view label() const = 0; + + protected: + //!@{ + //! Allow construction and assignment only through daughter classes + Process() = default; + CELER_DEFAULT_COPY_MOVE(Process); + //!@} +}; + //---------------------------------------------------------------------------// /*! * An interface/factory method for creating models. @@ -33,22 +63,18 @@ class Model; * Each process has an interaction ("post step doit") and may have both energy * loss and range limiters. */ -class Process +class InteractionProcess : virtual public Process { public: //!@{ //! \name Type aliases using SPConstModel = std::shared_ptr; using VecModel = std::vector; - using ActionIdIter = RangeIter; using XsGrid = inp::XsGrid; using EnergyLossGrid = inp::UniformGrid; //!@} public: - // Virtual destructor for polymorphic deletion - virtual ~Process(); - //! Construct the models associated with this process virtual VecModel build_models(ActionIdIter start_id) const = 0; @@ -60,19 +86,6 @@ class Process //! Whether the integral method can be used to sample interaction length virtual bool supports_integral_xs() const = 0; - - //! Whether the process applies when the particle is stopped - virtual bool applies_at_rest() const = 0; - - //! Name of the process - virtual std::string_view label() const = 0; - - protected: - //!@{ - //! Allow construction and assignment only through daughter classes - Process() = default; - CELER_DEFAULT_COPY_MOVE(Process); - //!@} }; //---------------------------------------------------------------------------// diff --git a/src/celeritas/phys/ProcessBuilder.hh b/src/celeritas/phys/ProcessBuilder.hh index cd882b47a6..94b128b327 100644 --- a/src/celeritas/phys/ProcessBuilder.hh +++ b/src/celeritas/phys/ProcessBuilder.hh @@ -58,7 +58,7 @@ class ProcessBuilder //!@{ //! \name Type aliases using IPC = ImportProcessClass; - using SPProcess = std::shared_ptr; + using SPProcess = std::shared_ptr; using SPConstParticle = std::shared_ptr; using SPConstMaterial = std::shared_ptr; using SPConstImported = std::shared_ptr; diff --git a/src/celeritas/phys/detail/DecayTableInserter.cc b/src/celeritas/phys/detail/DecayTableInserter.cc new file mode 100644 index 0000000000..35af77101e --- /dev/null +++ b/src/celeritas/phys/detail/DecayTableInserter.cc @@ -0,0 +1,130 @@ +//------------------------------ -*- C++ -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file celeritas/phys/detail/DecayTableInserter.cc +//---------------------------------------------------------------------------// +#include "DecayTableInserter.hh" + +#include "corecel/io/Logger.hh" +#include "celeritas/decay/channel/MuDecayChannel.hh" +#include "celeritas/phys/ParticleParams.hh" + +namespace celeritas +{ +namespace detail +{ +//---------------------------------------------------------------------------// +/*! + * Construct with particles, decay channels and pointer to host data. + */ +DecayTableInserter::DecayTableInserter(SPConstParticles particles, + VecChannel const& channels, + Data& data) + : particles_(particles) + , reals_{&data.reals} + , daughters_{&data.daughters} + , channel_ids_{&data.channel_ids} + , channels_{&data.channels} + , actions_{&data.actions} +{ + CELER_EXPECT(particles_); + + // Build a mapping of channel type to action ID + for (auto const& channel : channels) + { + if (dynamic_cast(channel.get())) + { + channel_to_action_.insert({DCT::muon, channel->action_id()}); + } + else + { + CELER_NOT_IMPLEMENTED("Decay channels other than muon"); + } + } +} + +//---------------------------------------------------------------------------// +/*! + * Construct decay table for a single particle. + */ +DecayTableData DecayTableInserter::operator()(DecayTable const& inp) +{ + if (inp.empty()) + { + // No decay process for this particle + return {}; + } + + DecayTableData result; + + double accum_br{0}; + std::vector branching_ratios; + std::vector channel_ids; + std::vector channels; + std::vector actions; + + branching_ratios.reserve(inp.size()); + channel_ids.reserve(inp.size()); + channels.reserve(inp.size()); + actions.reserve(inp.size()); + + for (auto ch_inp : inp) + { + CELER_VALIDATE(ch_inp.type != DCT::size_, + << "invalid decay channel type"); + CELER_VALIDATE(ch_inp.branching_ratio > 0, + << "invalid branching_ratio=" << ch_inp.branching_ratio + << " (should be positive)"); + CELER_VALIDATE(!ch_inp.daughters.empty(), + << "decay channel must have daughters"); + + // Get the particle ID from the PDG and store the daughters + DecayChannelData channel; + std::vector daughters; + daughters.reserve(ch_inp.daughters.size()); + for (auto pdg : ch_inp.daughters) + { + daughters.push_back(particles_->find(pdg)); + } + channel.daughters + = daughters_.insert_back(daughters.begin(), daughters.end()); + channel_ids.push_back(channels_.push_back(channel)); + + // Store the branching ratio and find the channel's action ID + branching_ratios.push_back(ch_inp.branching_ratio); + actions.push_back(channel_to_action_[ch_inp.type]); + + // Calculate the sum of the branching ratios + accum_br += ch_inp.branching_ratio; + } + result.channel_ids + = channel_ids_.insert_back(channel_ids.begin(), channel_ids.end()); + + if (!(soft_equal(1, accum_br))) + { + CELER_LOG(warning) + << "branching ratios for decay channels should sum to 1 " + "but instead sum tp " + << accum_br; + } + double norm = 1 / accum_br; + for (auto& br : branching_ratios) + { + // Renormalize the branching ratios + br *= norm; + } + result.branching_ratios + = reals_.insert_back(branching_ratios.begin(), branching_ratios.end()); + + // Append to mapping from channel ID to action ID + actions_.insert_back(actions.begin(), actions.end()); + + CELER_ENSURE(channels_.size() == actions_.size()); + CELER_ENSURE(result); + return result; +} + +//---------------------------------------------------------------------------// +} // namespace detail +} // namespace celeritas diff --git a/src/celeritas/phys/detail/DecayTableInserter.hh b/src/celeritas/phys/detail/DecayTableInserter.hh new file mode 100644 index 0000000000..50950bfd22 --- /dev/null +++ b/src/celeritas/phys/detail/DecayTableInserter.hh @@ -0,0 +1,63 @@ +//------------------------------- -*- C++ -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file celeritas/phys/detail/DecayTableInserter.hh +//---------------------------------------------------------------------------// +#pragma once + +#include +#include + +#include "corecel/data/CollectionBuilder.hh" +#include "celeritas/Types.hh" +#include "celeritas/decay/DecayData.hh" +#include "celeritas/decay/DecayProcess.hh" +#include "celeritas/decay/channel/DecayChannel.hh" +#include "celeritas/inp/Physics.hh" +#include "celeritas/phys/PhysicsData.hh" + +namespace celeritas +{ +class ParticleParams; + +namespace detail +{ +//---------------------------------------------------------------------------// +/*! + * Construct a decay table from input data. + */ +class DecayTableInserter +{ + public: + //!@{ + //! \name Type aliases + using Data = HostVal; + using DecayTable = inp::DecayPhysics::DecayTable; + using SPConstParticles = std::shared_ptr; + using VecChannel = DecayProcess::VecChannel; + //!@} + + public: + // Construct with particles, decay channels and pointer to host data + DecayTableInserter(SPConstParticles, VecChannel const&, Data&); + + // Construct decay table for a single particle + DecayTableData operator()(DecayTable const& inp); + + private: + using DCT = DecayChannelType; + using MapChannelAction = std::unordered_map; + + SPConstParticles particles_; + CollectionBuilder reals_; + CollectionBuilder daughters_; + CollectionBuilder channel_ids_; + CollectionBuilder channels_; + CollectionBuilder actions_; + MapChannelAction channel_to_action_; +}; + +//---------------------------------------------------------------------------// +} // namespace detail +} // namespace celeritas diff --git a/src/celeritas/phys/detail/EnergyMaxXsCalculator.cc b/src/celeritas/phys/detail/EnergyMaxXsCalculator.cc index e43c28d716..f05e148987 100644 --- a/src/celeritas/phys/detail/EnergyMaxXsCalculator.cc +++ b/src/celeritas/phys/detail/EnergyMaxXsCalculator.cc @@ -22,7 +22,7 @@ namespace detail * Construct with physics options and process. */ EnergyMaxXsCalculator::EnergyMaxXsCalculator(PhysicsOptions const& opts, - Process const& proc) + InteractionProcess const& proc) : use_integral_xs_(!opts.disable_integral_xs && proc.supports_integral_xs()) , is_annihilation_(dynamic_cast(&proc)) { diff --git a/src/celeritas/phys/detail/EnergyMaxXsCalculator.hh b/src/celeritas/phys/detail/EnergyMaxXsCalculator.hh index 847e1171fb..fffa0e3d16 100644 --- a/src/celeritas/phys/detail/EnergyMaxXsCalculator.hh +++ b/src/celeritas/phys/detail/EnergyMaxXsCalculator.hh @@ -25,7 +25,7 @@ class EnergyMaxXsCalculator { public: // Construct with physics options and process - EnergyMaxXsCalculator(PhysicsOptions const&, Process const&); + EnergyMaxXsCalculator(PhysicsOptions const&, InteractionProcess const&); // Calculate the energy of the maximum cross section in the grid real_type operator()(inp::XsGrid const&) const; diff --git a/src/celeritas/setup/Problem.cc b/src/celeritas/setup/Problem.cc index 3d319743f1..b107a60654 100644 --- a/src/celeritas/setup/Problem.cc +++ b/src/celeritas/setup/Problem.cc @@ -31,6 +31,7 @@ #include "celeritas/alongstep/AlongStepGeneralLinearAction.hh" #include "celeritas/alongstep/AlongStepRZMapFieldMscAction.hh" #include "celeritas/alongstep/AlongStepUniformMscAction.hh" +#include "celeritas/decay/DecayProcess.hh" #include "celeritas/em/params/UrbanMscParams.hh" #include "celeritas/em/params/WentzelOKVIParams.hh" #include "celeritas/ext/GeantPhysicsOptions.hh" @@ -99,7 +100,7 @@ auto build_physics_processes(inp::EmPhysics const& em, { // TODO: process builder should be deleted; instead it should get // p.physics.em or whatever - std::vector> result; + std::vector> result; ProcessBuilder build_process( imported, params.particle, params.material, em.user_processes); for (auto pc : ProcessBuilder::get_all_process_classes(imported.processes)) @@ -166,6 +167,11 @@ auto build_physics(inp::Problem const& p, // Build processes input.processes = build_physics_processes(p.physics.em, params, imported); + if (imported.decay) + { + input.decay + = std::make_shared(params.particle, imported.decay); + } return std::make_shared(std::move(input)); } diff --git a/test/celeritas/data/four-steel-slabs.root b/test/celeritas/data/four-steel-slabs.root index 239c31a907a6224fc9e071017fc01a4863eafc49..b1c0e2c32ca8ad32164efbf9991abfcc30654724 100644 GIT binary patch delta 53484 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 =4%tol{{Dmx&gWP(O;)Z(hA3;PgF zl(%gAVa}WbuxI@i&|V3rwOO9C+-#aznAy&sJPBV@EF@M;ta}%=sCu|6>inkmEfh$UTPB#p*itV5s;#C&S_i~D%yHyyKU zg^zSGnXZc4EB;Q{FV=;GP|Ng|Z_RrjY7)7-@?`krroS3hd5;P(+0u&c6@ zm{plY$54^xM;qfdf!DHlg=ovo*ZBiwSPKSnxnj?8LLtN^aD@q$zqj7{Bas}jD7bz? zJNP)kKV2~W(NL_|xRdvgqV!ON2p5Z!istf*$SXOq?s)En{Q|pd?6Z7l*2Z_>g=`$F zEjC76vm0{zAM4Lmt>x$@$!wXohsa|}hqIH>6rB?4x+fq^t$GO8U4LE-ujaL{1}bIA zDXyn(S`%GA(PH@nRYrTS@bm}CH#Ogqpo$qsLnFTr^jH-tc;DI#XHgjQC8K@V$gctY zCtg(lBX`FSEkO z!~`aFk*Ms)F|u(>qCtiW?63+xr>m?z+=e?pZfVu_cj{8E383R=I09`->ihluSWn|u zOvN3DVl#JAu^aiUU|Z1LNA&Eo$pNSi3T)dA-9v`Lb`J@kVTN$#<;be`DbZpxt^$d% z352b6Zl*yAL3}Kzsn;1;zjhg*M z^vzWtpp@AQQY&}ymI&Mkl|Tr`btasCNL!2^F4<2FnqDUtZG|yrA%i@PM~PdBG-^xC z)iFz5tr1x$R{8mWd!M*1{Md#+XpGX~jmlEbnxoSsZi3*+ZzQEd;09@x&^xHO=O)kQ zt{vq!lY7>T@lHk%|0xk-W=n)GfR!IK34ssGhqu906V~>TIE~`rWYVS?x^`xQ*x$ce?K{Wy9hwzU|Ix@Aqib>h{la;a18FFv#9%9 z0!U%ycihUuDQgA>bZS;s<0uL+NgDT-Z8`@80de%q4rOXq8R`|l#tY3~9YLWE{{17W z3^g;MZFxrVmAJkuUmWZ`%-v}6l4Blv?fDMD#UeWns* z&VUa!?aN@9FRjZ}28LS+Lu0zGKmRsFUC&7Em7aF58P-#39OaqJtIt53j2UV=7FR8U zbcCz@5DyT|6=HEi@U%O;^}M+HlDIzplsH~H%|TfASKZ=qY8r&;r3oy}IHrX)ln?{p z77W_R48)nGEY7eztOCWBJrcvSQpDF=4CY546(O`7C#FRCL++nP*mm)556UZIfn}wH#{Hl%#>K(e8hVs}Y?d+c8O*R?i3Hx96otZ^dnsOiffI@WWuQF>3u<;Cbnl!6G`}54uy7$Wjh3NH;6>lmj zCT92^GWmigq4E3eZunDMP?Esaaa8!mVa%Oh)bE1wo|vtPZ;hI-jc=;QgHr%7VM@Y= zw>h&vwnqQ7>T4|b@Dde)UNp#r)YNKalfG3yd6=hLaq0{=`qQNN%IqRP+&VepHI ifYtZ&|GR#u|GIuNga51RSM`TG5)1;(dL5$Fg8l{My7mPC delta 53025 zcmZtscT`i~^9Bl|2#5tyq^W=(6;P^zNC&ZjQUwXU_m)tk1~{T3DosH^x>A)8S_q+s zA|N$VLP;PIq(kV05|Z5W{jK$`_m6v7YwwdhGxN-B7_ugNrlE~B9m}fe4}-mAVWG~m zu&_9@u#nTibqjp$3$A0}Dm?*iE-Wm?tSl@_Vl2m=N@slgdg}Z}`Pp;FezY{Nf7TMc z18OX?{7>(7n9p4k7T5nX1j$%f*j_yG@OF75YZ~CGU5O1U;O{@V|vN2j!E)Q zjzENBDeX4x;g%6=Yn?&{Bs4r^K?(#;1ivnEtr4hA}Amr z*ji}K@%#5*GtB|5VeT7x=WqPjc(lPS^+`#NJ>~1EGg+li4|uuQ?T5JaE=4_cf>a>6 zz8%j@R=$NjF4#URpne}}QI>Z7l>cd^<4Wnq=yc;ii(#IC0DvbwKoZiaevU)wJU`ClV8>(;qjh?SAL& zCkJa*Io4(ECvSULhfX)RQkiytS@N~?Zy8xvSWRJP!VwOgFO(uA{5qP3$%4p%@pqF6 zDy<%Yiin6eee+f6z@A*=?J$>Zj?UcQIE@TDSNlG4tb>CR|#Qx!~(>eK-jUOF# zv|cR@C-gn*l0r0dLQRQs;bMcU{u<9pi!^+l+Ei~Zl;^-V0>I8a3oRX;hr5v!LN-|q z-~rZ+U(?W|Dr#1G|1NK9t^A;P3}o8<+f?|~HQvUGIpb;huH%}kW#<=%$v5gb)8D`hfH$WWHX=YrXM3^Oy;nnpA$- z8ZM&-hdrWkHz9QROwHNyNn|{E2}yN4-z9Wu_IFEp<55mgQ_tq_`^GKBh(i3enVC)4UI)=& zf+ONLIskz97f;=IY22$-?GvO|mNMy)>$Jdox^&jyV|b4z|Et>LR>Jo7_V*3szus#f zI&({o_^oVeXN9Qk73qhNK4xVi5m{p4!#VhVyzBOur|$dj%}*dw?}NyD^pE&d?qR{` zVyKl5Cjm1Co%1(Zneu#-K>6vlnd=Im@BC(NWsl!L#A{6t$`dp0ztqCP zIl*^>Rb~^l$b0P1V6kouT%!%~6OmTo0%>?EV<{*0#hRs0uG$ptMpK6;Z8kdM!M&cV zVfgCRUI&`?FCYga02bo#k&goKrBlqF$Q>=ys7nN%HnvCYsbU-*b4 znrqTC$jrt)Ht_wsgF0Jf-^3BZ6ZiG(Bw*vQFTv^|ZF+r8b#!{dY(`~bz*5@>_w~Xd z4?&_ORo5?u1DZala>nwb-0iqg2k>L7;u5DN*I9d^pp7_>$HV6(>;5H+x#|)uJ%mn4 zMXV1v7N%u50QPMvl1&fe8;WY4SS)2XYxq2i{+2@eNwSk$;|wuTp)6M*rwmnLIKavk zoy~mr?x@NPLJZc<FTp;0nHLQi@s+ct@Jszc{oF@+*BiA(Q?{h?~+N=NtP0x12rD_W{>L zDa{FP$PQ3-cRTy9gB*0G2`5lFKCHa_?w&m7b$9qxKG{-5%8(?mcvOv20AwBIsC z=*(#VPG{n;vbDYU`6guQ9H8$Vy;~k8NR~YY(i(y zgyn;#Z6M+eS?xKu%d4KjfT^o>wWQ9EXy-Si&nXCM^HnVGa<*(H5c+&m#mwBTIOJ{Dpkh|Cn4>1M7NI zA#F+hL-W3DJnNG@e3(+KY}3L`*mK6cDHv|lj4v-OL8Tt?A`=!#GRkSDHHLl)BLx-a zHruQ62qnDLEFY|n?Esq0@#CK(%AldesR8wzOXi-%-P@Hirw6s{#$Hm`SR*IEc{g*r(^eJ0XaRntMa#L8q{I6 zN3h?sxsQ7;NB(`$?qT}(WyqVgh2u(7+pFLH#(M>q7G;J3(b1%FcLjOM&bAkiG1Arf zht%Z!f9?wTx4%Qo#Rff}JilK9-?@Phd@LAmC6AltIz4hXu|xFFUBje4`5!CHadGLS z^g<|GAu?KuUx8`VU6cA}!*+kbfMA(~>|T6{`G)?Lm`r&mC^dQk5YsM56RAlJc`-9g z`#5I#l8HA3iioyRu9BsZ0#{0D_2R-$thQq;;iVhdP-*|IcYBqI8KZeqU2mvfKoy@4 zlejA%nTK`{HX^HNMR*M+ZF_GgNLBC=7OppK?7%)*jGk#87E{>JZu9tD-gTH%BV3)T zvH1Mz>^9NTwLF0?p~dEvUg%2ua-+A@1p>LO?imVrOAk+l?5+%=M=#jf3H&Zb%y60d zJFgB7oxV%?pmO{6^vyJ(da+lkq^}<5OxPC$;zwYinZ3;>pNE9KUA9VXuiP#7nfp_HSOtxLy?O3WoNy*SsoXo1KT*7ODLLA$SRQEf z-2DqJn)rfx0uh=2&?#d;^4x{PqWh3**1+UD6^r;}}01ec1AQtz80}SLhWb%5(gU2l}r}^XJ8w)|$@|^Bp$wWksSE=sUup z?I|lKp}B4bUbRXHvB^_U_z~(8!L$1BOgjcE)=iF_Ni+KEs050`A!j4bQGEzFZ+v5Mzl-DdSEj@-CYo{=pjLs0 zWmS!ZE^k%8{QewOC|X@DZ)spV%1A6cAtWs>C~*I}asJ#5OYCS=)J|nc$iYcTS?%8L z|4aFJkX{q9T%Eki}G_s?w za_N*ed*;JP@gvZ;qwZAxcrk4qsoZy;94e3RaU8Xz%H6(gzV}nNp^~KLsqRr|>)g4+ zIm+XuwiP5jgIUwh%u~Aqj}L@@?3?0EI#-&h#1>q(n2IW+A~h>V0*eEmRwnJ9+Wt2h zig&@L-TYut>|@ck4R?GW*me%sbJ<2Tn`=|E{65C*)o{r~QmbxC69|UhTJ|LkmiZX}|+pEktx zaI7QaMHHaT-4JJ=D{27~J!!GXct&)9)vh(_o=Rpvb?0Xqda!8A1YqE5EG|p?q2(YA z_C9ybm=D(SZhGaXm*0CLxK?>DB}d5Ts24ynOD;x32{z$Ds%N288;;Z9oeCv~5)zkh3mZ zfuKPoxX%yL1p$)=(8N~Ba@^C==k9iAE}a$%0wjK%MIQ_VHYaywE`we)Xf+#xu^?I6 z0gd+!2s8&BUZb{yB$*Q)cq+(F9(XZojJlU`AhW+)4!?Q`U97kIAFSHZzriu6zCEO` zwc`*!dz_n2sNH%EGM&3JTs8@u81(lvUb||!x6(Lwl~A>?_<)=83%Pgp5xn;1-B<3p zx~dDW7g^$aQTJc|>67)k|5C?)m6cnlezW2BdoHUQ<71CvvZaYogC@e|NZ8@!rN>w~nWg|1bH9@}HmsNihkwx!E-LkgIbR8#e zB|&msWxN5ee%qq%9bjp-l#9kVPNY=QnQeGj~!l1?v{p(GDPmm)+DCXaF**#V$sXI6JC zDba|zjk0>Squv0`>)YR*K0zu5YiP0Fv|2=`DdJhO1d~k|BY>v-Glv$Swwzd=WL2qYeTCsWoTO6VunyYQ&OZ#H6XG zevB!xyc|-F%qz82#q68BsPJ03^dmSbC)bjS%EAfD-)$hUMSP26JS6XR~E zu&L>LLD%*`2@ak+Jh34U;SnvE-&f1=QJ9!aclusXgddT^EhaQwgA9)e2xrwA;ymY3 zMUom(T#$fAN+V^ymR9{H`4Of9CV-Fv1@aTSHzh zYxF010)9h@Hc`w3D`|!u`syA*4IwJ@JxWNs_CH{3K;J^oV<_NGGKX zqFZd43QNaMcrKN&hE{<9tLu$IbA8&aeQd&9w<&CddA=Ng}K|a~<@e=AHIfwH$5CGx2 z-u%3pl7sg&P%V7RdJBT+9f%~~F~fQ8Cht&~Yp&)<&YAJREx)h$4EjoFntPfB5+DB( z+UHwishTNmG>}R56zUqyYluxWM@s4@XAyTNJ*Rj!RS|bBN=G?zdSpvOoY9d0rEgtC z*usZ9^G<;1b@#eD$y#nFd;1Dt{bb#NI-Ls8t|#)!tk9j&SgX6}Uk9LX}+FYS3 z6M%dFWc6-tEPdhHm# zrf&YT)~I##cEQvgAFksKqJgynFy)h#Qk%_aW0KbR%q*!f&W!8YoukMUgL79NT^7Xt ze%lzpo!Q;sOU0XT&BR_(T)*Ap`|0aN%-`+eD;(YK>veEgU*M;so-kl=$eQC86A{0} zxgu0hg2$;h9*k&}04DCmGdtHfey$m;A9c5J8Qb(^>0TdD(b>&iP*a9|e=|~w3d)Sc z27Su#+gUiU*Wma`b@MXxidE4m49vB;BTd%oF@K^F_p?K5E5327WaBCKW~0)i)@z#fM+v3^$7URLPPOCVm0vYzb-=Fv0YPhr186N>RN;6Y zkyzaiJagRJaR!ESp3n~W@4`XPV+$~}d- zsw{5JxyNm8r+Wp%ViPmyWmQ>D0rO{wuWeGd+Zt@J5rCzOvgUeMspFVg>Nb=7cjhS9 zqwYRB+|s)HdM_Iv?BiNh6WaQ3pL@h+T-n_5bCTo_nTJyRAx$*K;;%=&Y#QIi)dKXS z`1iMDo0bCx{i9%vOr6i-si(vFb28}H#{Hw#*A9kEnyq9u)Vse`jQ4=RL2!=3YL$6-S^ypL9Uqss~^Z7iJZWWonqldL+Lt#AB_T39uu`F|FydeW6Ro)!zN z2Gv=o!R%!GYdp0&kAV^|StsUWLR##kM!sXKGboUKJIz-fQTLnP!Grawk>wBN{#sot z_^3SLLpoa?%#XgrGMIbu@?EVREIFWOwfC`bmDIT9$vou*VG8T;7SmemZX(Sph`ayt z7Zl&4?adpTuXgAJ71a4hc9HwG0QZeD$GbG?_fSrK-xGsswBi^rDzzNv)Y|T5>)EBW zPrb1qCv<03v+m6703CWkm(u%K*?%jw6VxlI*qaRnpI>sGdS?6B$s8U0$=c2Y&+XI3 zp#QuoD^e+?h0~Twt^h9?F5p7e_Q5N!ouvD9JR_(oAh^*@!3tQHd3z@IqLRo#%QDN# zv&vg=c-4T#*jmWfoUb*w`c9pgJCarH^?6~Kb*P8*%7v9=^hC`9^0c08mYy`eYCsCU z64vy*L*+oHz4~m!TBpC1;rJ_Xea#KIhHB9|()<29b(9$C%Z8^-08uN))ND`x=K$=O9XJ2U|xxQ`xYL=Qu)F880RP3A@82=1w` zyUf-tz49$qQ4c1a!D^gQqh~AQ0aoLPw%G^-SbRsy`3=RLKr`39Jz00tG(vo6XV%=_ zr(cwN{j1JQeg8~ebl*-Zol9BOE|lBO%cN2G{XLs+bb&`i1?iI7SB5#ao#ND-0Oqf`KUv<$h8Sr$E*F%GbLj!)k*W-w~?a%aTM+1qNW5rj!sRA ze7p^zdimk_Oep? zM6Qnh(cjIMK8EqxhyGozPBgC}dDEB0r^d+}Qc7sJWDLFkz|dcj!iB<`mdr0LZwxU; z*VUOq&UzFW2T8T2W(>y&T1apI99*{wE4Q*`+J-mNDgT7YsYp#PfOd$<$|g1w0dizk z-@Iu)STdu{>RJd7sTj>HlR?w1N-W)l(wy<>E{#Y={Te0Mf@P@uvcVYpIT{g5oz)?B zO^_K)PAklR?~r1{(|qKBIu2)%8v7&xv3?Y@7RH$^xuh*IX)88vj=y z(`1gxSAiOI#=e9V8UU-;tl@jnQHP?A$6jB+fLzJ4DCNKru*Ov=OE~)-H1!Z_A`O56 z=H|$lIe?Wrz`mV^;dpf@{j?GiaG##)5|OB_Nx6ju(mN69( zpRufYHp%eZSBux|G_G^2dr&Qnm|fm;`jro_GRin(fTa67l}l09R}UL0LcZ7q&xw3v zZsvSUto?4Vf+^wt5zVv;cYo($3SRR5PX0!b^lXaB%ViOLjkZ;v+^RND5=phy&Mg~d zS%8DhHD*1S#L%1D{MYNBh4t%%H(On`}GoH@QgaTgZW;U&($_9{N4t`JWT6$A-@za@tN!{dNOp&~uR5aJ)C?lDV|O zq3K_xhC$Cw<}%$z@?&Z0OM#fKb!8}e*5Exx2X^uYa2M~h@}Cj&2d!X9)rh&c3}nW` z?$h&o;(6BI9BSLfy!og_&$n}c8AKgwLly6ty*kuZUAIx=S{CVV2&J+A0Gtoxu*XKg z>zT6Vv&$k=sO}3ayNNlq`sibOi6u3npc!xDT+Ls`^W{w^aPK4E^kwRx?{H3PhM6a` zu8D~1Tby1KQDzX?*F@%awSg#__6qJjSQ>3UhLwVm#250n(({W-QJ`@*+Q^rAvwQDk zEl?f6Jmt$=WOnNRWeonTf1ty3A9xOKiaZ6th%M`qNH&&ZNd(Ckvy*rw<0?I02BO1U zgk2~AeucdQo27%Ahem-wZ+p2qRnx`J;8wLxB{N{nd0-Uyc!h@LA3!FiH<1}I7jhD% z@Ddf6FUv45M@=#Io+@yxm2*iwMh{Uu)T; zHGZa_0@OL8SaE0bHTwOyXUz9XL>nix#={2m<4ay}d{%PhWFuyC<>^n0=svnq;F`Tn|D8E=RpH;bE%Ed! zmoWv0RI?<3Rqn1pVS3}S-Nd1PxkqffiES3Z9GDbAy9wJuV1>({iL?ci120RZgXzF~ zbRN#OEaEecuRbxN8AiKvsQv?Zv4z=|`vH7WUU_{Ud?>;dIeq{aBMkGoMl_!R6mPX- z%OcX}W4T%O5=kd;te~e7Gd+&IL^1Uywl$H$bv=&VMC01ndtj!VeE@5vUqAg^-k0ef z;lNo7+*NcHt_5~{=dOc^63jRb?g=)hCN-ZO)No8{s%SRwO=@1~-vM(IS|oG5ys;pV z>Aopb$0SnC4Rn4({lB)l|y{JY@Q@Ob;&AeeskfA=il3T)U_N~=CPanm^*IBpj1kfOY?__c$k_xR#^W< zWHXj$q7#icmByYn|0wcM z^hY-_3z-cokMApyI1unW->v|X?jxsFS{R&T5#-Ym**UqRmAX%H7X_dkh?`O84* z_wz@pS^|%@`@4fq3?2_XBDd`1TR-QPu68&O3;p#QV|!%vnA3)BFg!|l?y8D>M7{F+=2X}|+ap@GEH|cnNPoEg{3S4^ zOuzN&bp_DnZ&UJ&i`LrYtZSNsT_KSvy_=a8k+K#xrqrcGlgLg(Xfnq=>kKRq>213J)(QL$)^B4P z`h2mf2LD>K>*IrnLL{F}{A#lMxCi=IX|QR_Q!hl}87>n+h_9t|iXpbs%hmzyoRD`^ zDDnUjTa2@+cZ_VpUt2NHFWR$1@_B2}u(Nd^@oHVGhm>vAQddOjkEOp%dxeJ()JvCf z9>mYXJ58{(@QREt71x15CDeEc_N}Ce>Gla$R@TXKs>iAv=fUIcRb5zVV}+r1OY@xh z;*Jv{lp-FnGc1X|S!wqNYyL7is)@dQ{k4_+klZSU?Qo4epg6(!RyiNBcFBR3Jb~7} zQB1GF{(3n(@L4u?753ta-Z))xl)-4Pi>2y}OlU?FD&m@ZbDx$y z!BEGx!Z$_8t7N?&pFZV@-iai)L2+=Qa%pX_IU ztzm^A>N3d$zkBA$qi}P#A$<-+O8paF7!FxudFQ%2ZF(gg(rc#@d-TV&!jkI$c%r9x z8lpR_AP&RdskYpy*Qoe5-HdOH@WNOd@>FH;k%9akUlhK?Y_7XNu(zc2QiGzbtzd0y z$)kyHWfN(w64EzD*69;-kn?%dj^9nFmZ7Olq189XdV4(IF$bC24W-q^dcNdlxyffm z3DeNF7vhqn{mbD{{B$bw%B3b@NzJP8^2xHs9Xa>xx3zC3QK!8wku(F0CT#GYU(08| z-2ry(N34bUIFP&zd{a^uOW#6Eg8NH2Cb@dFMH8CKbLYQdm#3~2BR+5?M9@wro>ueq zH9l~uxr%FT{oW#T``@RSH@ov~1Ir3iTtyAJp@suIzJE;AUq1J8dGn@(*pDbrwDB`a z)oC{NYy73PJYgA$3xo@upcPu0B%DyKu>@XS z&d1)>j$y4+X#ulIyv1E#te!r@l%8muC^g$!w)#-eNUZr8nv(LX;nXe*%?(nO2$Mj< zEWHYAzhyi9BjO+uXV>#sFY}xKGz^KL-T!4Ni41u6I`5tXB+T`*DGyH7LQqX+*xJ6= z(WM&JH2Rd14-rGC?v3f!y13LhKAcYnnu!oTtAx{&uuW8zN*aAp?jKw-Qz#N%ajz_-Gw~)$T^5GjsJ_=WoXq_IOEWA7)OVY!bOQTv&B{i0=p9L0d>H0?($>` z>3jHSPx;?PV}-}}B$)%s&mONBnzQZu0Eh1Sai%T!UVhiedS_mN(1#(oh8KtyD>Q72 z$v~ev1yhp_*{(AE6WuYj!fJthZIgzSbTdPpBJthT8rvu^eQ!LNci>zia?#BZylPLXI6urs?%W%J8@8FICvsbh{$j%+=e_lp*F20N=i`L2O)ACa z(W>t^1J_0>PX*`9w@(Aq7Kurp?I@xZ$vhek87WtC_vT%rQ{BDh#1X!lOU$;j{gCNn z*8K8har0;n;TQV<6e>=g3sU%SX0`IvxpaAjU)H}Q)OO;`diB{68x@xq8pE3{qGLpo z$&z5g3*Vtz_a0tDZ2Z1Isx7Jjnf`27)TCopeJat@rE&A|F9|>`qY&Er-!a6-qH!va zwuNlVhn*0*Kn6|onM*$#3r$1xki+`X8iH5v65r#5h=ptda~sRxT}`&VLc zR|2RwmFQJJ35eq))XKK;{G?Ejil=%7&_|z2%&dp5C31ll7B<9)Go@|+=55yCm|+Pu z=wRuG*mIx{=?GcWU$kk+-pu z461h)fict!?f3bQ>_+q7{1HvuE16K_ShhyotEpK}vF(k#E#49NtgT~L4KYP=+pgIi zpY@-ReffUtg7?WvyGut!P3z1vv=r5%O55oVRd#7%P}AilQ|e_i=m%r;O$^yFAe{Pu zCJ9i9wl_i*tD=eP)|=l4XPNvob^Mh%PJ|3`J#j$I0(#XGFshSrJe!3)B_#5*fc{51{2ZQ)2Fn>ZPTn%?`#(Vz-kj!EGY< z0F7Q=(=ww4q{mv9|A<6s0v={~5&C_Ab{aKbt9kI;0T^so8V%6Rpm!uLsE-zlps;ss zL~rC33^J+?RG&_n@=?=dv3n-{h$?K-uHRvacrK;s!11T!**;*^2NkFC2_ImWdKvGyg)gV>bRBM4`M^VZSPIS@78$fFA#FyQtjx z1qS=`D{mPpFoE7*azXzMNsX52W>{Hevx&lr+VD4r<|NaRvvX;0G`~)eEmPgcwvN*1 z$S(10L-nU9taSVAh7;u;jmUW7I6QBF#@Z0~r?zVmbjqCn{OA^z0?WOVTxLZjGpLzl zNkrJ#ICR=><9te)&4OiDgp7rVAQY)}Lq;NS}{(E|M!Mf~v zqmnZq4)2ZO75+&LKE*s)Yu1dxnskzjMz6R5#celZtzb#??2o)?g?D7i`WF}-d4Adh zD1I54vHnq<8vGIR4|9JekFs?ckMJ_M*Dtzb~Sz>yL<|Up7M~$R7q>YMBk~41?e6c+s3E)ZjLf zZf;Pn3n1>;5q(*bjk5k|iR0*Z6?lTF&-@{Ue;5XR11FhwwAJ-r!dCR#6|D?|$<(4G z0Vqv%6Y$y1tdRx-vj-AG>)+9{-)e^;MlP+c-{2Euysz^F#5eON3qwIKNf&Ho0#tnf z@uiA|ScV-4h@N}j$5E#kI67S@4;siacg;n683tSJD_78uslmo?nWW_{6gJsWmh^?+ z9S|1{6~rJ?=-FSyQgi0nKn2&rMqpa65}RB#zau`y3nD@O9Cc(cnkrZ^bz2bxs3kX^ zqQ=QjCswyQ-h<>lM{@%u$3VfQkAQ?W&;kI~&fia=mh2`<0g~u8v z(zD&E{+*-jG}ZIAGs~#M)%CZHhXHGN4w~vQVm1mM24;vMB0ebF1?W=f9+r?JF%l?U z2UwczIQdSBwWpN5E1>Nam5P1yl`d2_{)N~ETU|e?qaBl)gTc}PKQwj1lSYIYxRpni zf$2vJvqtr&IMRr4T(je-tp@=2%-R`%o2|mcZ!F20JKF(oQFin8(V@!>Yp=exEvc^zic&Mm z8*t#2hJ{)NPk-m-0L*Ql^2luZ`k)%O|M>PdythbAT*w|l)eODsAOBK4+7cLKwc>N0!_evrf+-l+16l}X{WrIWp@=nGrh}q z^qCg<7iQ)(CS_)U?eaQp!~B-rcoqHoo062}J57&H7xF-s)7Hl?u3Nbj9t3D@U9o#8 zDYPAq>Ig`*T-ps2>0auq0_1+!gh+0@dzUgDg*?Zjce*t0fUJLW3{fT5ozR$(dt61} zyzmpMrP{Rixp(FhnGtXe@%z&aO~W;4Hk&v;s)i~l<5$*F^*Q`R#e70FCgRG%db@17 z%S5rBWkKJ5ewT)71Lna*2-`?QUQ z9qc?kST(bv83f^ktYb}9;WWbhScHbV<{Dsxq}D2@}wKGf6mlNzDnJP3LoXCB{q#L;S+RHMM4v3v!aIGMF*XgwVajT-IswaIA zWs-=nZ5u`_ttgI84JP^NrX5w0l@l$Z$&PjOwXdhyz&YS<-7zV(#ifh`e(KAJR}s3d z)jcDy_n}VXaaF8LGA06@EqGFJUd*>X=yjpj3K|FlZ0jVO(WDXCIm^7}&M+rq&Xwy^ zUZY<6qt#w6Y8YGS3x{2Lz?2Scdlc@3{Y#{qf!toWB-qGdGP6IF8Yoe9uV^@oYSr18gWW5)~SGK=s4UR_lQYj>9l*{8jEwB9eV&!?wB>-$uQTG{X2g#-Jd`BuTUW88(+}8?|UZ;hQ zJ_)#cc-&gU{Bl2a4e|B5v(Md?8Zwe70(PXNKQz@8bQ0Vl!5(8JPNPpy8B(~ZuWmkf z5zps}hhBocD`{I>!BSA5vf$Nd2~MMVz1Ha;y$TA3=L96gEHC$Gm|eL+_5nc25*%d{ z1gegX_SX%9Q)pg@{W`2N2vEHv#Aw4{hwO935t9xA2F!{$*1Xp(PUilMo2geQXuPs~*+x^f*aIa~pxt?PM zcF}Yn1xf>r;IXV2xnigU^q}`{v{2kVkaE{13}|w*xBnAe$VszVjVy%M$f7jEc7g|= zXe!g>*Lkp%(8dnN%&J-Ba(Nr2ya15yB`i1tKKQO!e*a7gY?gO%2Z};r>)gt>(sm4J zR)`P*XX&I>7;WG}{RZVNouZz3IiUnu1z_7h|5a4Y9cCm*<3clePE*!zWGc9MfRkb# zI;!p@F-O4dUG;8ic^fr&^o6N_-~bAXS~n&xtwz#R7sz+Tp2UokL;o&rsP3oHv(F{1 zJhKTNCm&#Sm`!y*={C)IRw{sp3-hG=JR0k^MBujDYGvfaOjZt~Y(JX`{|OR1&bOB;`QQ{L z3m`ewZH;R%E?d;3B1}SsL?_s!$2>IxlPM^aH4e6XdETGs|ByKG^`ZQMv?7(QM6#3% zGkKSWk3G$FGl$wX>`z)x2c}waJ;JJCT|Uo^_IB+EbEsh^0qQLBml}i9Q#1|fa1VWi z#v`7Z;kI<7i{Ec+i}YSkqYIqkqM+1Do(DjmX{F2!W=sv4kn}KWVOmyotA`hRot~AC zSwK%#sX-+E%MAbCzcpUTGd#}huTqowZ}zTyY3o)9AVv${R{dsEOsJ?po5joJVD;;I zY_mg&%7Ll(;PG8sieJzdSJ4{JJlu6|O{|oJys#8@sTq?!+;xm*aKPV~9SIqp78$>M z>$VKFxnhE(^kAD_hsLbxi)~oW!lzJ*>S3;M`OMm;iF5BfOxdled?hxQBFAJ1R)=f# z;almz$0k!oqQ;tm3w%XbBP!cYm_U^BR!h5-<_>H49$C*ib{XD~eMVElt7(-I93jaN zboW~4rpWxbyAapZuHgE8OWu$o6p@>IzUs(jJ;c0ZYNV^3)V&JS;jG_?5OMqb`1Yq+0EC)*g4&Da9_B`d{xa)=hq^{K9&1R&Fj(T)q!u?UMXnW zC!8CyZ8YWbkS!s$N)0{)|P(5pUCX9yBH@H^|G1x>Yq#|oN$i=6Y3-FiTbz4C{e zcMA-fjbK|HQ^St~DN$M!MI-p8Ms?FyP-!i?hTrWzF*f-d<*}GM+>f`qNr1&i*5FkQ zf5RU_Z2upsBNc?Jn|`xQr6_Yt(j0s;2B|Y36oTRBEC+517)Y4E5co8wC5W?+^5 z6@-2LxkcPqKP0p4qK+iVsFKjQw39a8?+>vOy95hw*#ChaJ?db__q;5vIe3~P*m=*= zXDt0v0C6r2&jp=MGPH8Fq=YCRxEfENLu88sk85j29ZxO9M=6CeL_P+Wa%Jf! z=}9*^1^#jUIZ7R{gK(H(eJ2_7QTYEnC|?8YI*?p}bEY;Jw;Gk5fPbY}-BEL)0bsw% zEhQ=eKYe+AZ`&%bG@;f^o(^w!33MiE1RgwGhG^pjn#@#8Erha{jg7=zT?69^BRq?b z+z?J3#X*!&WR(i_>)x?q?0fv?xBH{3g=VD*B3XHX#SzVT&NnN^rq4mmv(2xXhOHPC z;h!?bC%TWiN)1M(l{QERb@*-!keG|Fn>r@#{R%l;2@azm77Ii!Pz|{h$s_6>Ud-^c zzV&Q3+X<{ngdsvMFqKX;6UHs-7Nf-IUuHniFw}6AWstA8>$1#~erv!g)32M4H zX0_tYANnNEl62aYw@oySb-h4eZc?)rV;0N7b*+a#A_+!Q2Hx)gC3@~(*RO7AhfG{h zW#`>*F>%#y}pU2nDC6i=#1O( zHPBcQBBg|(jedR*+YlP4s8rNrHTgrSq&YCQwgX>B*^X&P-zjufR7d_1! z6|=PNb2P3{c69ZdZX-wTB2P=n6s$QMteHFbX>Ivz15bgcvD@Omn&P2TRZ4a~1rhpW z+)QI^PJ)g0`;O4`2t<6Y6h;YWbh}-zyLV>t^3Tlj6alG$DdeqZCUX@^!Ao7!e;@nv zEf~1{$VwOV^jllRw0(>A<6GeJgA2S}FwY{we%=k`!gka(y}L(MJtZ|jA?jG@fdq*PCCql<_{3`kzJ;JpoWyb^N(u9CY~3nQ1q8f3?Ov+1&rBxNFIHsSjSWz} zW-uU!1Wnq5_GlJDpoY70*60t666Rs2f16AwsPT4|SO$O`Z&qACt-FAL`NE^gOb0(G z$3HZ(+zpI~VW+YDEVZMK0-ymt>kOzLl(zn`(J;{h6nWW&E%0#nXNfZ>W+th*3dMK1 zqTH7dMDhO#|6S4*WqohkxcC21blqW1G+*~;#R@i1q`ekI>56m#Q4ysp5<)_e8X{b1p$@bRhqC#C?SL%>77VPAc0V&g%VomAz!|~cIVtXlYO$!bN0^6y=TbB&sdEH zU{62FOR!Pn`4y(5DSxO3Tlrl7ekrPsDEA-jx*S5_6UF#>-;+w5INMdO@>lAN&~!?=n%!NgEvjg8WSMUdO(#A&eS} zjUap$YsB{~4%QwX3JQsHQh@n3kIc6ZbmHH6EY|QYShp1ywT&QS>tqONYC(llRf6tQ zYJ)*C^0&=U<+e=4d56A<)Qme+oLuQ4A5sF?6e9<(5qD#jo)&z4CJD#Uf}eycHOmcA=Zw%)L=d5Tf5T;e*= zB;iJECngzm&|KMa4Jx#*l`0(eUZ@EaT;jnZ$~GC>ek(H^!3}E-W?pr5QOgK8V`e!& z92iuXf$+IFD_p$E2-x$cgB-309}$tC&V7skdBE0a5Xp7f4N;PP$F*!?XEO)~dP1Ai zin%TS(WTbdqdig!)`+*Wch<1Z|EaZ(bv-@fW=jl^`UFY8boTf!afjWDZ(r38vtsYx z4O$TrJJS`nyBS+!PD%%6INb+(00UI(y{g2VBU!_@>YpwBfw*0MOUgV#*S>PJV&xD} z>vCSUVeh2n(jZ(Ew&_B*Ij+!Q#jGWL#}||gr`=kSXPf6wF*5VQni4mlvOOwt!WLzX z-m=Vs>t6G!38o_#37oIz2@8Fio3|x@G?t*4)%l|rKS3$s!vhvt0M3#6FGq6JrnX4h z)8g7jwrzxC;P@JWzx!UoabsDp%4DDw`uLG6yGUav)A1!?0yiu!Cat0IJX=Y?+(Iqc z2EiA(L@4!Mzc<=xYU{jC`|oM=wdUtT+hcQ+rvnn&_1CVIi4vV|o&PZ6)&FHxZ+kV}xF3%hcXhxs8r z%O!(x#OSWNpF?)!#)btpqFP1(Wayz)#XN2Y1s1uz^84QOFTBHArbx}X2e)AA7mG{P z>F7P&aI$4s+J*0qapA~I_h$gC=+8CHA1zmzb3^(3YJhZansO!mgq6#;KV9mJOykFq zo)tW+(Vgbf2O)b_aSK`v^;|Q(%U^ZK5*MZVtECQangp?aJYHqcD zscix&wB7#NVzm@22PV*aMN8|JLDPs|W$R~q?9+{0ZN=3O9ONR)k1WvD7l0_t{r-Kg z{Beu*eiH|s5MZ!j$C(g!j4d2IX^>W4GwAqDV>gUGG~6ISQ%FJE!+sSyZ%(c!A2Qc! zrG->W{F!HKH7-r<&lC#0V&j7PcTtsVa~6Jtjavg^t z_vW|l5O&0yc60CPewBf3`V^heVpGRmFIIs;OnMqqvZl67-S3w<;10i4-V{yTBYo)j zpu9Lp3BI{k`m8?s%ED(@MA)yzP0_`E;oBNRe52g_pZ=hYz73rfrg6qa7gw=v^%ckX zn^}upac;PbB`dq2wwBsWqF32setB0!jhOkMsMC|`*V|hMR%u!d`6S)b#3D`YTZzfS zm!NXCa*4LcncG8QNq5lC#=KSg)inMr#h4*7xYauqJ27GfnDf!<^pUpZLAA%L&zTi( zj?K#hS}VOLkLqI%1?iK_%8?d9GqQWF%x=d;hWoy9*2E_~ySR$S9o}q_>VcQ`fq*zA z%T$#0P5YmCNPp?3&p7}pC3o6`APaSunI8yT%PahjpUtWj^a@DC967gMIHJs7Hl1{t zWzQfBBXhgkh=DnB7VKvuW@=YZAIJmNxd3ByHwmrjN)^7k<-?ueznMsdX}3X)&Ft&l zHKlQZNn~vOxfBG7Aaj-39Q_cYT-Yocz$xit1b!JSd%q+Kf{2TZ@|!o{Rsn@WTb_$% zpj0dt2)J`)n9&}GS72WyW3a>J0!tw)pU7r~N!cOBkr?dAx#}}AG&dARsRNkE{E|gR z(f^`GF*8srz-7pv=pIFm(s2s8S_fj>Z#ZJUd9g|=b4pap7v7eTF&D=RzVwEp-3tRu zUhjKGlGCqFDL`2%@lFD7>xq+BnJIE$4!m}1DT~x`Hh?re^bQa`c$oWPk zSmOi#%Dl=_nMoyw`SY>?r7s^Le24UhA^aJ*z;Z`C>z$_=s5@btGVT7YEbxVl&G5Ew zE;%cxr|<6N5ep5!wA*}w%g>!Ha<8H&d3PBF8 ztp4RaIY=!J#5ix2-lMhG!I(?Audpd~wD{;Kw#Ssa~4J`a6%T8n04%c-GBKKjqTRn8CB+!DkBjG`R0VXO( zyErmCaDk2u=TThKukUp03g4p})id6~Q>n$Wp1}E+8~sH95+cISueCgh8~3m*;{-3b3&qMMN<>8NgSOyBA(JHPX%`R-=ggMA%dkzEA~ zU%aMj>0W9DY>qeV;pFyX0c=tiFY0P+B?hvq`XX%t(4e%XPnuknlJs1h4hlbbB*%jp zXdrTDrgjdx@h|LQ#0vIL=EQN{6`?|Jk*-@xfZVPZNYN}JghO6#un)4j;p-N=vn+cbW zx~kd${nr^kygrP7dRG$`MjJPZH!Ri?e$jD5&Fo~Tmx-#-y4{MfJ5T)63XXA$p|^=M zZLV^vlaD9fQ7-6xjh6cFdo>~cWy{BT%tEG3HB+{E3;40WTu~9c1wrpkFO7bnac&BCkJNGjnIK@{hhLE{ z^UxYU*AknTq*$)@TO@5IV0ub`3;4KyIw|69qOJloeQY)3_POYOApt(~!_Tw$ai4-H z*F(RPr5~cbE;m0_&ow8OErxPVKO%;r?6SgWb&fZ5k>~IG<~BW6I78o*nm_%?I%nTW z^3zBa8+!DUX2|2h3&10rki@H}e=%Vc!^1r>l2$I->k8r7{QvDV#kiWCVKdzRT|dLV zu`b&Rbc{Sc8rBsgQBSyZecv52E+x-~y)(}iE z3mSy^b_C7O&m6=YxtBqsTRS>-Jqv17S*rS|Xu3F#tERvp!1czc{e2{EhnBHcc)hBH z(QsqRa&8y60x8_9-q&BhR~%Sy$G>u8UID^~^A?Ys;=t%`@U@pS8X91#IWzKj_t)Y| zQ3V;NhUr5PbJA0JoAFU+)D-*C^q$Np25SHT<}KS?QI73G$BC695Oenu!3Ft!1d0s) zjI*V=fgr(`;?Ys-jKY)|-LFIsGAi98SoIRX4ah)d;A|;gA5Mol%&0A{-UU;i9+7o2 z(}oaUl(lRM-L#+wo)sU2vYHqhDY`YpQwo@+3&ocO^^A)vk(##eB36XKDj+rnCXaZ- zh@hHUJHYA8w6TyMo40;rkL^4kI8-22&$h|t8g&pxfnkh@uWWc;7~{l1L$}y{0Hrh2 zv31PE>Y10GB+m=;&S1_hkr(C$Gg9V9$^4HugqGeiP6VCJ4K=a4?Z5xgZLD%)vQlHL z@>kW;y>e{Q-;(o|<}ZA$4wL!)F9_G%M>Pdm@E`HC8h<@|u^j8E>Uat(b(vcF2i3GP ztK?~ATjj0Bg?Ax`u~HHD#NNzD0M$i_KPs<&w^iaR$8K#RdCRfOkWp^0ZXW#yj0jWY zAJhl1@9Gn)+iT~tv0IS;6)cL0`@B}pKLKe0 zEw9+*zHcj_=P4VW(sGL}W%X&Ro@O8Zza_!$4 zwsfSQ`| zgGcL=`ftrz$^Nd?i658O7f#Hli1L^<^i^Gd@Id&*WT*yT;k1_tT?MyNzIl{~Tv7l1 zsNp_uL23-PE!BTWn>BrBCTsiwuS+MrurpfL%cSqDf!#OG)DHm@pme&PBFux|`?!rv zl=U&0e=U;gAK9ku*1c^Q?xe-#LXGh4(5T2T8ijDm+$~F_f8#F6(hT^kz4&Hsj?LKT zvW|y}FlB|yQVw=fo_4Wev?~Hx3vV3%TZz)X^`mm^$EBIDyIiJ%=c;~|_A*f~kG?i? z>cvNF3IYOjXakF55klQ_d;d>f#DHeW1HU3`Uoa2$H0RBzy?teSJ45nJS9Ya?-0v@J zK@Rr#BcNjSpaZGI*vxeL?Uq=&K=q*>F@Y1FZ=FZ4i_2pgPmlYMe)Fu1ayUPaEE%|_2f>u4Be5rUy9+E5 zSAsrR8t?+eSSSIbbHkB{Qk;AjU}QanLEbo=wEm&12&>9|P!WWvLE%R+AM%_Qa9H{8 zQ7iqVQrTz!c1vb0-k|nLRAmM1Ius$S^-@@5w@1z5<;Dj`moCa}S%F{0Rw3VA~_>?yx2OKY$cVwFj9O6-h--Bf%jSt!CmN zQCS(QB9UavS{!b~@qQaZYs$WgxKQCwWw6@+@+}^z!ercfz3!)y0@L{JVRd^>Kbu?w zY{Ux1agyP5#<5dV_hj8s?A5B>tFSdR_Gv^xNY6Q3r6hHnZlgqJw14Ldz@$o|u?Ag| zdIjY!s43TmT0n?tVWn7=*bK>hiDLcuoK2G91(BcYalBos?x=L;mfc32G&rwIPhJT0 zhtgktk-YPHo=`crJY?!Oa2A9c0LI@zjR6a~+O&nQ|Ikrz$Vy7pM!17eIZ4#kr`psp zu)mw*H-DL8mPP`_#Lkt{86)ooHd7x(qL=d4KI^%TII-@#Iy(hT-v)W&5qL*~O_)ac zT2LS}Tmr%;vL0P(8Cx7!uA=DLwB`ee8JzwQqAx=Tj0-UB-$~_$wK(8ceb-V1BkxX7(_W6NR!$_K$-IB>V%`fLlx_>-i`V^ou61opTy({2+wMu<@6CelGPD ztG>WXfQUF;4w2FW2DGFx)onk0?NgpJCSHZNKUGUHPxlsKyzpMID7>M5S9E`@r**C8 z=TyU{<1;)jugH8u6Ef?eNT7Jdg68UoSJHAa;Z+n92ycs38oUJHypkxlAFk9M4QuGc z#ePY0OcI{1q)7J$Yqr^H4@P`)OXd+45UtD`SfzH^J_~;a&_!j$!gZF^y<`0gQP5>Z z%lkr5LwH&?g5P({5S4UGB1aSPAid!Qw(WU_moV>n337Mv3}@iyz`M1qcfM5*!;{=Q zKpjioF8mZmJ?WeygTn(BIMR#1GNA0I6iY1J(CbNUp13SH<$7C zG&m-A52rFvx3fKp#&&7)I!Wje@{QZPieC4d$rmBGVtNsNy7a%ECsX%;wFCVyiwE!QUOeu%f-}s+0E-bNCr^{j zyhZwH*BtC~0e_R!D&#?8Dj|#(=v1b7wT9QFijUM+j^Re34*B!V=XFK;jhb#-bjx|0 z0P0n0TSbqf!e{|Rpc~O7(l5Jw`M6<`w@H=!L%5tj*Pt_HLeCfGb-6fzxp!@?OMCHq z{NH&kf^fgAh?`p?&da1qc)7){7tVw4@Yh@Q&sYC#^%Uq>S83B;Y@g{b2@K-FgDC%t z(pr;0{Gy~v1E;ll@JLhAs!i4W4?iQT9&!CQB<;nW6ndX*iOO$!kvweqUbFUM^LYGu z>LuZR_Z_K!?*hLodl(X^H>ZC1NkzpxTYMiz!^Ft!W-E&HyASNirq3&T;x9+dpNM^A zISAmC0?C0z`lf$ix?wu#XD^fS?S#QtWPhPW$IzBhYIbEeY}mYUB|iTr{w3u^nHW(J zUEy$OIA=i=rcih1O)x?-w@8Z|rhrwzxPz5hTgQCa^ z<1<4Q37Uk!>m_bxGqu~0O+87%RPu2PfG#-{SFYezMrJiw6&#^OqOo2Z%$r(mj;MGf z_Hv?iG&$Z`6(6m+3NfcCF4m+{(bxsjsm$F40@*Bz=K~_-1qSQx$I>q%I-q2r{^}%s zF>wAANz-q^`XwqP$f=)x&|%^K{JbcWIRK@{+$HVKGM@FO zD%S7|LSmww(HqN3MS%c1nMN#jO(0KZG=10ex&?_D)rz}&R?CBR9jfWkOA`hqh9)l6 zxJ$q_;?sQYPhCzW_oWQ2ZPcLgfjjqIB7Wv%lNDxKE$ZhdFc~tb#XE5xZ^%B~^DWS= zRdmKoghr%&wJmG!!6m{2WEA=2WPbBrLQEY>r&X0rE8>WW09R@CW*4Qc7tgHO%_p`! ztL6Qi=AY4jN!I(xS*yPqd9PC*?xe&r>o5DMTtIGu8fpR5pGuAQ8(v~-9pC+%OmMwO@<3kNfHiXj|R3 zA6w!ss>Qw*aRO8nudC&xsu;*=_&Bwpj)v!pnNH*wyZI&U(WKFnyPDyjeMZ-rBYVw1 z3u*eBIhkJ{&ah3GM_OvtO1o_fcVvtH{(RaxNxm@T7f$oZQx4ou^!xocskG6|Wbmho z$)n)5e16^lna5`*v>plf+E9iq(*jzr%)#t*i6ghd2R{OwSQK4M<-LLr{Vy|h=FFBm z!maheGae>UCsTRJ!^bn^UR&4Vj2}IE|;IjHf46F0r8( z7y&CuVQ+ElI9$&=*RUNdgx#Hgme<8FunXUdNEs=hpdq|G%2&8`n%Q+@JaYN zs%_Y>L;WWm8I}^|m9{m0j0ZoMWj2%7qVn4eYf&GP+^6k!kXYBn%gddgj|)Y!W4%q_ z664!7#Vy)yLnOZMcuQWFASFzRvbmqh5Ql?^1Jr-d;9id}>B#W9grAeMvD5Q3QD2{4 zU++h9fexZU<(1hVe($N*0H?Sx+PB)MQ%x*h7u}q=sBU3y6kF*#y{^jzT239wGmhp0 zWqFbLKus9Ui!b*{0E7oWnFy{13vns5F{I=>-p@pRMRLvaXGs{XtvCD^qC*(yH@f|J z@ZM8ytV{M8nX^a;qd6Z}KJ-kJ2j3UD=}k}O(%$3It)suA)o@7if+Tkuk8_V0*FPcL z-))^%r%ZmMggP>NQ+m)vRh}yeK7S}hNtKdWnamZ!p5kygHrh$tJE4eV?Tg+D^73z- zd5)I4*}C$cD(7APXk7S577(?6BQw|#_f}-g&FuPxlGVX)W)Shjhe8`7YlMQaPfs(? zc@Gw-y;>rR*=WMaaLb|p)Dbym_Pdr{?GDGm>G%$)`i3tI?|xS5AMn$OY#q>R+bt&p zc2kDuXzF({m2S#+rI>R#27jwz3P?wg{a?EyyQ@f$^THcwEf^N?P<-Ya-@9uefxb~o zyMwAtj3Q@C2~9W6<-!a#=l2a-_3K>PeVV7Gs#uuZwr~%w)N8v-U}jJxk?9R4*SR0a z>9E5%5r%Cm2hTexlIGvKd-%nW-}#I4@u@OPV6M>Fy`YLT@|}bjPB%XY#Yp3r(Vwjm zct1!@z#H{gfc%(6)gL;nk5($Ixx%by>2iVpOMJ|h^#RjQMdZ$Sh!AKs|3=c>bnVd_ z`DH%&F9u;Ep55)dJ5mm)Ps#JbEzu@mgG?8)AurNGq)pEAUzGu)d0+HNE> z@9~X6#Nepj>F3+N?nHJLZPD}vd1ApPeUPiFIG)DNTl&->`+awTSonE3T~eL&_6mq8 zM3RGe5^kvrA~cnJ#wyQN{?L5dq5ZNX)+v={&hw308wgxZP=8X|+`7CZ@AI{`b5FkN zNh6?L7r{=ltjZ4ij-E6e<>};=JT5z=%30*j?kL_<#50T^E2&I^EbuvOBb&M+wOcQ| z&PZOc#`OBiU+92VFTHyc<~4iXZE@L!N1@9i{4gOx6}prpS{xPJD?*RaXe zS%Gh%+B}I?1xG0`3E_L?c^b0kDBQ{?L7*!`)Bal+F_kOxTRFq~c1r6#M8weVSlOqO z)9O;=XI2voLu&P+9aMttN4B;|D5*6DZDxAkNf|#wWEHe^ z9y!gsqJ^;eJ)Mi*{;B#+!JQtM&=eZg!z0iMV0)2YArn;4A~Cub_Y3&7H$xAv77 z#u4PtinbFZu}2o^(8SlXjDP^}{5+wtBH=JJeNevX0o{Q}{v1V1;}~bd(g#)A#+OF( zAreX>_on|<4Ko^VEJgNe4`Ga4f!>SCb1)~AU2OQ4mjVEuPrWKuMbxlG*_qPTfBikh z1y%=+aLy9cit{^{>nIZ3LCokU%kI78dZat1=Y*3#8=j8D3UP|L9=F`R*afeqDS#CVZ1Aec_4{n^{H0Liu{@a;NEYRf+k546j8Rh$Ry7$rd`@YRI z4+-t<)+yz0TXV~^);Y0L9%1%t~H{N2snfC}^P_0pt^fb6? zsPPI!hx2<;Q#>3RpS&b>T~xKP;9dY*ay#iEx}enAvi1}A8e81o70+ADowcaW$f`6J z2s9auAePR6G*79Uos=sO{7{tk_1-HGRPQtV(>Z|asc_e(>$}el&I zv5a_#X1q(SuCnG1A-n2yyu|yHnU!$L2xayRSo!D$t$_ED+~C*VNp367YIF6-ob>eP#rCPHGg2 zN=h4uOtiEkCx^_`$8NZQSb8B|0%)Frp@>y*o66GRf&oW*qhg@}dM8(k2J9r*kvRc= zTXQC6;Bl}pZP>LDp;){{&+IpyLEoUBkmQ`}Do&B!TMpb8;RSC=PXy77u|+A8)y&|* zf;*sdZ6Z;!^BW;0bPLGng7JaL=WERnPhP{jH2Dz&mV)+*9*}9y9#BO@3+TP(7h|M5 z;8m0=P<-L<$ajJWI;1-!t^nWqY7XVwJrFNfCIg!b>~gVxl3&(tX9{-ljl9<1m%-DN zD$2dW`{clM-aW=>-Yj%6bfVh3Yk<39@q7UaF@F6L_1{WZV_Emz2u7CAhf#VcJ=qah zL_M(@Jf+ALGkFbc7zgAbI4+MrxU#-U?~-EC+ug|7L5>Sdss^a~dT5e*zgDy60#8}= z7`CM5GOuN!rVwjzPW71Yv3^0)s_&UHtJiDyr$Tv(RTEMLsuWb8j1<7^Usnxlmjy*> zI~bIOJ;+3uQ^sw0^)4sc$dx~z`SI&Viev1V@gFU^D+$Zl;}?R< z9OZ$tOZ(?y?1hDoC>v?)tmTBAjHPgztc`_-&s+X0tVy33>)K$OwT# z=a>QMp49{g=)0n_P}bT)cIEx~k$KO>H%quawA&zd2cZHJi=yaev3g9vm`gWq%inyo zvFGUEQ0kE%I9qF!P1F3ZZL_x}9(Z}TeCEhf1QqxnZu~v_+;84l4cbObRNbG@8G|!P zQ-AWe)Ejlo-yO(3`}i96Z?m=jole`A(B~2g)VExLAFH>qZ{Mni2A%nBv&oHDNKe=r z)<=&X{af#N<>=AA>A~yVhHQ8+Ptlt2rAx1_wsX(7sOLsBnQyQ3bI$D**&gLN+8Xs! zdP-wnd!u3N1d*8ZaNG4%T4&o_)7R*1%FAz1 zdZ#crImx+bl)D|T_A)E0Fh0PTS@1rD2h+JL%h>`}a^eFx+Z8__tU{*G-$l5UZn-*Y zYU_80ZwhsaK)#H(T#`suhvln_^T(mcu-NNv|DA(FLStrfM`iERnVm;in_;GMuupmT&v`tz@ss3`M%}qkII*%e_Oaa#{P0co-+g+ z?^lRM1%a4zho+>0A(#Hdin$9qy)kncIM+8ptc0k-@rdxL2n+sTB$mp0U1Rnv=v^*R zhG14q9LP#H7so^--YZJ;v8^y$=|L$_AY4xyU+eGtnL`Cz1%K&L5=1D!jSp0?ESg-f zMYG&4KP3oGAcOpDsygjsGu#CoYs{K?Yx@LGxkJSDKKqN@kSQ+c{+FpV#e#qz{X)YO zMX3DL#LvUMozXRXUS*&p%Fq1hx0xL8axv zMeb_FeO+y=XLu5u`}1o^=x9li+70G}0+>Z4+MHvr_b{M;7=+#Ia!hp2JO?Uk;enD4 zs^7g;*$rv&Mi&6mlQ^}6$vlEDVETnzEDU^HgAvEZzY(#Mt^M&jkn>H3C!O}tWw5lk zpn2yX81hGP9wIV0*bRT}t{#E1pGDrE$wQ3Xi+4Z`BB)G%#|}(%Xz}c0Kh2zWLEZ6e3hmC4KpP$97vZXLDD^NLOe7GP zOD8{t;&PV7hebZyf7EC%RhuL{tgBkr92RL3(TKOW*oe;6 zTaXW|ZfJGc?oi{G3UC5tqI?oVm7m~fyE{5hboX?@hVx+s7d)UAA~ua9zGE@Pn((0(M$%6B>TBss(u)pI3bV82A+Q^q~~%=y8y zKUTAXKMD^J?2R!_lu=ampKKTW^ip<&NI@Uk&vmDMUveysTvs@pXqur16ES{jbBDdA z2P(j3&L!S?WMTC(*e>hu)+oa+ci*5+K?)-q08HO%6svVaIpbBu^N4KXn5H!g{9%dV}zzI%&7-R~d z2`jlD{Q{ZF$gDJ0ykHR@F0)ay?p9(JupXSC>XwRbw->qtKo{|nF$$%c>+@gC0xa#& zZ<23+`56AWLE)^_WK%uFnOQDH4@t*J_T`CT%GkDCxs_VSJW-rk-Zr+Z2(b#$2(rmj zR8obrWZ=L2_t&m~`}{3AXjWJP6LLQLpy2+B zGtBU7bYMBGV9@2=`bPc()AN`cPi!(m?0Sz}I_DZrSsiGJMCK}iy+bvipGA_!}ELFkdx@wf%?_^Fc}qcsOgASFW_=TcVF0A zLlOLNLV|Jn;vxa|yP`@0$;ZP2C8s8~;Lu%vW%@Gh9(9I1))NrfBE$G{Zx+{4LN>v-lZ;4?7HnIW&ShMj8= zq~z&SmlT*#OyZJCW%`skmV8tpD(X(vKa5iUhuYuRZ5O<)fY0RQ4;zS(fEYOB-Js**wN6zUpOz{mP=X7`OkiCa13TFr%jvP* z0k?o0GB%`cAaixyV)5DX%-Nf@_IShqZSJad2qdU>b$>_3)eWCGxz+*Bzrbv)B30Bp zT}x8@7#W9mZ!HHCTi64B9% zLD}o`Yk{Est|+*p{!Uj@+r7AeKVXDC-FpSx78KmH9Oxp@22p78N0pp zhtc{%dDk50i!s73n($RWb3rLxt=#5h9EZ#Z;WRGAmSbd9z#}O|-MC7VRj_zr<1%;> z(;UsY9tyXb4R)w2`O?RDK!D<31ap~VDM|n1(J08pN*{{>x7R0s8D|1-X4UVCNOEhi zdq$6(Wwtwnp_uTYDf zHso%0A{XF~nB4;dIN`ZTD4eV^F;}Rcm=M$PuM{d#w9-jT^*2v-|A+ zP78&RasPeA``utLsFx$SM15~Tj~xOEVp$PnjR4|>T3&N7Xf?UXKPD4bDUpe?Zw@ty zdsA#?48$lu)Q&GDS6U4VI9e`1c)}939PH3IHMm2?_yp+`2;P`Kt(K{Qt6cn5(Cb&z z%6JRi>AEJO2jSzZRZ}xpCoy_1Q)77r5;3A{yPGK(jw=hw`D=!#5Q49`A|>4trP6@=3ziFnbOq9enG(!)Sh`=k(>R80;P=IffFVv?kLiX z+vwb42S&8;iOKY=F+R{ba163&Ee4u9B@PT9J5C4;S+o6A;vY^iDOegP2&2_tgLf>rnw1T$LqS(!va*SacgUVrP(72WRHA@#bqkmcL z+&#ZJ^t*Q)jOGjfN1gF2Wjo8r`hK1cA}r(uXb0wb4G(t?p>8Vg`OlNR+Ru>-1b}UsP7_TWV0n(tadsaQQ<=a z<7-a0K#8aMg;)LA_&~DbPY3)$26-2G`|MDM8CtUzR#lho1(Ff$PmI0okC05ckA^Br zWHRHV@dgmlttk%5-7!e+LXj}Ft?*iCs7faza!)&I=Cn1$=AWF1x|?Ss7nrJDOmyV_ zAllZn*b*qnlAxCKqY=D~s&U zhVI@Gum+h&4f@FcWGzCJ&+O*9WZ1Fj_xB?93?6M4|FzH6H?piH|C}lzOZX^3t>XE= z$W|sHSf9)%jp&_ukV5oAf3~}zMaTtL>Q~mE28MnJKF^hL5oEfEF>P8)@H;CMf53Z` zLxO0DC4?jguP2h_bPuEs`^aHJb=+#3s+Wq$gI0?XHA&ZKx8+L&v-*;=w*> z&6D$;@VcN*#!%m4pyj-W1v?nnVqI%7GzCXJ96Uq}6L32n%BbhWfukT%2DzQHUJGSg zc?XR!8fXx}e66y1kzBe{wG%`K1uvrav1ie?8}fvms>i?QiURKpi|9*K6<=?YfQf9z zV-u~UY*A8naBSI%Du^I=gjwC6Bdr-%F*sMjLP<D#5M-=&S zWBK!5+A!tR;@J`yQ=)-hyjT3UQtl%HZInT;&9L#wB3t46PI#HCqpdAt=$&?S1ZyQV zXZ}lxAY{~P0+6uz7E!bl;^Anyh>nDCQY8+{r_T|b{)J}d!e71YdaY?rDtP%$F}48n zEOspfd1HvZ7n-q0F)$kG07P3$oxB4bb8k5#y8f-Nt;sb%LEgx-S&Vo5k(2i_4~kjk zaE45*>lp^_!%r{XwgP!9Pih{gx)ud4vPy^DQX+eyl<0L)<6pQ?e^g@ zDHQ32(cBSfNxake%Td>og(}69JmI80zen(ZE=-iO`et{TT45i2a{@{rH#}XfsfyXd z2L=JG%0KUU4{(zyoRmjHt!-IBtO2Tk=?F}r6tb|*qL5RZ@%#PGu?QFrs!(oDD!1)& zc`mS!71W-BGNXz+*FB`5XAWw_Q%NwKb;UISTg8?X7DMfZtSBFn0`kxb{f@$M)*8P9 z#|kg#!Bu|`X1mjRL5K`jMT4yDMo0mE{@h?pzb%ABQZM2Kl4Xiuwq%vf1k+qHV8*KLvW|_Gbn6-3)lGN>Va^-V>-H+jpka?KJjezQNC9nbfW@Dj^ z7i2!rY0vPih7%rZ-U9SAOM<8xcO4{Q>0Qs*rvv2MIZ}|>7e~5_Q-YqGh`P1B<3NON z7zB}%LP;(&bu<2j?_1#_zp2u)bZ<)R`!J^yn`mBNgT4*A?`Z6LSioIZRCDQK{!D%g zWMDca1GAm$fili=7U|=@-*9sk{uJKovOr6b<=_o9D^OzJHE{&{7a#lcy%unU{^hV= z1i4=3bEhB3fr+?V4T@6(hZ&5xgMFvl3eloQ#@pp9Qvu*i=4Dt4Vu1U_Ad+{#?>mEh zog`YxC>pop*>G(>$D)#~YuYyBjn9RMT@zMP`=?d1lVle^=0g}|*zf434<2Da#1um3 z>4Ug_hJ7ym`R|jo!>qr+v zX|61AA!t6zO&=4=N;`w@wsvPBON@g^0sNqisVX16d&r4}1YB0K)jSSyksx=m39r%} zMZCXZPQ<}s5h054s3m(Yoh;sF@hhmr4V^LAS@FkzE1MiHarMjX$TW1V$EK}oHL-!= zk@>yMXFwhKaaZ~El1I(UuItxUJO&I5k-1Sp>h2PI1gAjE;#b5gWY_wp##-rSA38ZX ztGj$Nw8#l?qNbjy9&AcUj?W9COx;I1L8wFL<51{ii>bh%1m^oHd*tjKz3_Dm)av55 z+HSgf8)FJ*PKWOwwFuD&4cWDuvI7C*O?a&$+pf#9BjH~WB1I7n*X`>`wLz=i(GZy& z%7gnnrqH~QkDxwFf2SkmGab7E7QGfC`Kr*W08?25nsv#(YumG~IvwM|tw}nr!Ol_| zN?H3hy?>}?fsz(e8eRFwfcv>M-`0pfba5TMWIzfTn^qiRgbi{J{wc7+gbES&+Q!el z?6Q=H^r8>rm3!x1JJd5I1dNqP5gA`S$~Mf!~x{nkDV8oOwHX9*jUq{w$FSO=p)usEg#oYp(m?pOk${4HvSKYBc}OgZ~--f-n1Tfm4m0e z)~M*7xC2Xmx%6M!QzTlGz+vM#Z=)3(vgH%>4M`X(iEvB)CJnxZU-Yom^6P^w3-!HM zIc#rrf*DCMp}QNkv?J9Eg%O-75gY*;(gf}S#8fJAMx zn_;0{H42Mw+bOF^L@i}w-%*C>2X-8GKZ@MO55W{az{keDR;|3x^<@S?3OQP+-x*1E zEFi$wXlYLri5+G5YpUIbomAE;?oexYmYFNh+n@Ttp?E(J24o^dd0_pnY(G7IMorD^P*d3H`N0Zue6>=BDohqXswl;9FhPsC+ZhK zd{qFIa^ogp{8x5nDH=CK(3mx#IkDbKJi+~bLQi>`Lw!AxO{D}ggQYz*Zs7#<|Av<5 z70Uu5SSaS}YHnMc+*qL`9qWhd-#8*+i+zGAg0%MG)vwjrV(xKPeJRl_ip#xc z{D@4J1;{;jqT7{p3K{h-9+9La0YxqV1;mQ!_xNVBant!N7)H_k2HZ=GOrVsD|LP5x z{eo|n=^98=`#`x&D3uMzU7@wd7Ds#l8YT&62uE3$E?*z>NMU;Sw^Dix16eo&WOnA!R4(=!l~f2L{Y5Uv3tq z|98y4g{62=NVXqavZKoSm_#iIq1;n;wf>OqRh00%Qli$+un<2XoN$ZM;)o$Dxu>12 z=2And7NwG3tIVhz90r1;>-R86;D{qCBD9w>>NC+v*4Ekhg0~T!wMA?St@0yZ zkVh#@=#{TVbh|lT>CQ0criwU~_BvpKY@=KTP4%@(pv_t$-B#yj`wq@aBTefPZZX$h zV+@<3^gDsvy&@%kPTX~~L=QK~I=j~aRmz`ge`p-KJpuqfvC}>x?#Rc_x*}a%$&`9E z|GR5`jxecLxgj!ufFq{cd{2JK0grd5!z{8G4U~_D-!=usM#_{%E)#zjsdE*rNO}H! zYUhy(qXLFUus#&0mK0HZVvrB%l4$+M51dRMLR(;bFx}Q#YwIoyBzV#o zA)MNh?0{M^9cM_*cc5kYmFapXjfyHurw1DQ^F$$u(Zjbx4M z#tkc0tu(TjOAs)TI8sxt)h)jVlZ8o!Y$~DhH0D#2sgp8{us0ol^hq_fH{2!mM8i)K$v&vB%SYp?l@a3cGBOQ9HhSZTB1&7Sf-v6ND@1 zW%!fwdCs4=KqsFQ82q?&tJH~JleJ)iD^lEj%QwxJS%aTe+0#d_{DB~i?5mpfPZBJA znl-2P_7^`ZBD#V2TXKmDWz*7WGR^WKDT;_5Qs#HLPK;{g!@j&NRk)7;qHyYX5Z^E5 z5u7giscOL;)p<{yNNzfGE+Syh7#+I*H3^_i|5OB*YNXDGRH6g0cMPa^xiV`n?P3d` z*jM6LHlTSiDX5~Bvv zCDJ8hqeC3sG8%*-HChQlIs}}AC?F*uBA}qCJp2Bhf1ZDyb9VMQpPijg-1~mteBFC9 z)ql@cS-^|jB+g|fq-}X7p}WU5yFcL0EqbqJ#6iFLf+Ws0E;bI@KH+#j`R_{%^%3cQ z3i^u_)|uzB^>z(b#vLWz9-A-spI}P5un))5-as$f=RWow^mJn<4HwuO+;5@AiX6pk z`;MLxou-4AwmRKdr@yD);s`x)=l@bz)dyBEd+>w!S={>NCNw@Z19LthhdaNyYf87l z<0}DAGu*cLX6FA(N8z3M9ON>KrqC-8elk9QJY-3q`cJ}J0e zdOpV;V_xyuE$Vl#Z^>kjS^vmU#0ez<_Q(g-rzum>IYJ8jRO^M7yD*761>)UN?jGSW&r2|o{SvQ=c zL$UOEyn&R|=(_UP<7R59KFpJ=45@?buy^a%UM#Wf1NGSNI^!u?YyAG7_3yrDg)=@3 z{G%NAyuPp%`~7p)*u?x4?#)v<&zB`y2l>sF9QRo80TXC-YvokyvGO}=$hL*hP)i&eZk-r zIQ3(@7Ygv%U?1aLIP$oiR~v)P(f(`R*eZC24O2MY#;V(4-s$xG>3vq^9T<#+zu$tV z3}AgLheg?=rTk~Ae>I#i%Ro08A5u3C3HSsKOgY3f%@X<#jE&RRhgGz9mx*EVb5a_y zo6w3cCwl{!uZrc@hw;@@>p>4_z3myFVmIG#1&(8ba1rdWuRF6wf&jF(FRIy&Z=EpR z`@V1KT|?kaSftJ8<+IIrf6Wxnm+LOVlSRxdVQ*j$A(Z$Ux$cAfcbQ(L2TzFyTi>-FH%b2ZiUg z2P+O$VAq~7n~-)oVFHaaXTujX+9Fz%{`}m#4fj7Nbk;V*-C~@nK#Jn&=h%oRHh!p} zD{RD9^CR2XR=2OJS9>|^MaC`8%pqKwsGFtr@NJL1TklScGqdDl4jD#Wsg0A6Hzd0x zG~K`L|NWSI(rW8p3$j(U0dW&N76@-gwb?`V+|^br~M?Le(zO0 zDTc5qYn^4w2j8J(CdEI4k6#<(x;q!9$cx`OsAaAMzg+y_{3Ab7W*<23*8Q_-t@35Zn>Xv;)9+$jInDelOH%zm7lqm1%pN%^h&}Gc zF0||!&&NhWZ)TzG@OwTAaZ1VWddR*FT)iTJ8XuZ;S{^ZU;v%|4G^$Vh0wvY{cJU~^ zz`k}$K8XAo)E!}3I@V!QwYuK9nC1P-yB%vDsSUdjV)q|f%QKG^@_^nv{3hyDath<* z9`tXGcoTOFs4G%?{pnj5mBrt~jaTB!s#+4EzXQ|ra0GsP#_&I_1@@$k_lvuTOAy`C?AlKV#OFu?G2C_2bC4_lP%H$TI-fcbkrEP_Ps97>7{AySo^Yp3d8 zy`B(pZwNoL*${ij7Kj^>qKnI_+jk(ny&Dkrc_=ZQ44zr=#TMv&Oj9_JIWMW<&N+G> zWarqB5l%L9bDfne1_=VVHN%C<#i^W)I&JOa5U)K;+Oco@fBn-;f#7~(pS|$!=4y`+ zQ~Ns<72S(nc*atf?K#u}>@)SO{5s&l*>dhZ?F$q-MiH|vXHqI)bl542O1@fjQaz@_ zD$0$H!&S4kHyFM0e&O5#+=N1!%UWKqCeKtFId@Y%u%mBPt_M_K4Fw|?UfavX;V!Sm zn;u{o4q5h2ePDr0t;?0ahd0*WZcmCx51fVaI27ICwkr;DZ*vC>L2f@>gxyG})pRyiEa| zJnl}aU;Em^lhSTJd=22j(eiTri?p33OeQ9Clr#OSU>p^hkIiV?HybbU$IN9=k5@eY z_i_CT^7#JCn-iQ%GxJS*s#zP=byfHN{s{D#hG#jxbxsfGR$HNEe4>{fiPHuqe zGr>Db8#sL0vj04C_;)xshqE*)P)a21an$$qtxVIrolrG$^qg;cuZXi;w@p_n3TVq- z>Mlfmg45Pv2A9IT^GTK=%>&jKnF?2%9lvV_cR#P_ytIX9!+&5N-+3^XZ*#_vjYlfX zgv)$+autnPvk{E-dzsVbrRH?jpzipov;zM5q(Ldq&atyu_oHp7Z@1U`mwt~=|H1tu z5{1PIIrCc9D1&}~{EX}HQtEvvbYxDUN(rK-=~i8653qJUm2ZByUnywV{<3G^!#>9+ zTwxK~OJVcA5o(&KqLaiZ;T zH4NqDsuD&jHXtw<{mKjXGr&Lb_Q(z{+4ZeMk>Me3^_Ahmx&`Ec@AAb0F2!i!bf}Q7 zN72Tm5UUZ9hpjrV!+J8lXrU~4=up48oAQ=hDWUCMY70*4lrpa+IlkhlK}qN)bnjtm zKwotlcI2-?eUI5y%iMZR;qF7G&Tc3V{cD%@g>~EToq;xG8UKM5hZi$5=Jp%#myy3h ze0CiCWA~^h@;O&9U*~3zZiZaDx_jckM2iZKtbgow`ulq@#6Nb!KR{x77WcDTig<&* z#ZCTyDs6dgHDHfb&%eax^JwPa4Ccp;J(WtUSzEXIr9g@QZM6Tye4h~Oav#R|zF9s? zuxnR@6gF?5Q-5Op0Vf>i{Sj{AZ+?;D{`6oT_iU|<|F3r?<6ezeR<&1r8+mj@fg9iI7I)xkK+y3$3nE$}$)sH!HoT21` zd}e01qflRI3s|$-zhd|3WD;6MQcWF@iG14WNP&rZ_EYBkIo9xlV)9uYb<3t^k<;!B zT^CjMIW66BXLt5#c|F{!_o5)&-3{9F_xBx~NRV5p(qmW02E)3*D~Izr)e88>A1{$X zxG!}azRmux92(3WyY}r3TEc(-xm#^&7>QYCW)(TL$BwH$ev90YYf;7j5V);KA5BNSJB=I0*Ce+ z>kr%e#PWPO7lWrC5Pi{vdC@uT#u7h zUG;UCA7jm=%C1xV;|s#MzJ0patY+Lo5&6YS>S=$F^I+|JEIRpp|L)<3H^V{FBBTg5*rUaNk=_GK2=RD^dsRe!-{mSHI9oAj|i?^yH|!0b7}AS5ZC18+%zJHj@yjxJiH*s?cE>!_9^X`qn$4~DfY$V zAm_)&dZlX@={SWlvAYF*ryZ@H&m8fiiYVD)>3E-#8an>{`^GxM8 ztYk~iQ@6uE51b3@k5G>L{?6~hPM6;Ry)pjY=dU{d@_RYot(lU-D9-ispl)9G#aiMh z=j@`QZh9P*Ov+V{x9Jp)Q$*Gjo;Y6FE15*Mb-=4}@A}=QW3!hx$+=^m6~5#6Po6^k zBV%uRT+3P>v&Ki+h@{#JUHd41=+~T39dMr_?iN|Xjmw>{?YEk@weD&@bZY3D>yLQL zR%IBf1XVJjsf4$h&G$c=SpODjPi3#9m-O|Z+{%4Z{;`owZEJJ*az^Z@dDlVr%`QRh zK)7*HLHKg1K3BKQ8=R@X=6J^C22=_2Yxb-c{Hl8%dNr5IFqHTRM^Gq8oqV9tVJ53M z9g-FARiV_3o{IWzbi7oP$~k`3>|l3iS?o*BOV3S|hGob2<@qXMKdql={ z@ffsc_uj+7rnb?3&-WECzFjh693}aU4B@}-LwlS``u1~&nU4#bZF?U2MmY31{V2JJ ze;9jFOo*U)sm3SOG-LCxo4;L-8ESM*ZQqz3BO|YRKkl2ix56|! zgMQnXANNn?ybuF2+bezl``Ku2HZ4+-w$Jq(!t~{|9pT=9_hFAWJ8=~RA9B)v{DkRCOH13AT|4La8b$W6gR%uAKM?$s(hy?{A$pu^KE&S>a)7_6E#@qP9wP$MIEW295i7LC5m%)#YTQ(0W%io5#Ny-^?#eZgUbABOH z7Fux@d%TbJTyp$f(6aIF!KP&L9K8E9u3g-FbRzipl=+`1?`$O|Rw1doec&8=#Wk6o zC2rY%`q)+V_{q!s@Nd+ar7d$km{@pgBn`V{ZDdEG$8*v8`{a zbJ3LWPfex~Fj&|F7@4K1EB*$Ji3_G#abWNlCxN&4>+yiWUmxFkCB9Cl59217e8=r{ zdp3K3doRSq?E#x$8un?E2e;P14WyYp*k!qBLZeZm6uT^o*+VomKmf0LfH(j^FaRI| z0DzBU0_Cj%$^ZfYpte5mXFV?w)PyW1@3__&9?1pKWzvWE5c%E`jNrSAp_0yuUA25t znC%Kd3B}TEV_w(z3Xa>zkapPb$`Z;k#dsn7`{O?mBqUAAzX`!qV3R)ZtTd@|f&%jK z{_rpZp)Ai>ldz1G%4-E71to| z^&k7--09LqvNIPmXG`2Aw)cJ`kwG+E27% z4sM6t{Z%Vi&l5McMG%q52&B(=s&zVi#Al+902906pU@$!tVGKU>2{BVWOg#ykarn& z#Y>L9$f-?xpiK$8n1w;{q z!j!vG5Cw=F0`f6sY3bAdF$T4jTfH*&VTE^LuqzJFmp6Lgay+qk!C4lRSzvGgPkee` zlL+{#Cw2|L8BU8XfFzAR^l zwV0EIMVr+gjz3x1DwL6yZcDuu@~jgqB2yJ$@)i^$`gM~kyql=U!opIn<;DA%e2FwH z=a;xy_DCy@l59TOp2Nv1zodw&Lp234g+TCt1F)cucP+l$aFBL@^`wd6oY<7fjERIh z3>NHxUwK;HWEFE%pvl?6FjA6~BodN){`eyqyiEfFi)BE4bu*@z5}z{MLqKf^cTn!6 z!o3=7EG*TWT8{`aBrSWtXQk12B#=-Ezv5?SVX0S>mIhT%(9uuw;ot15FoKxs1~p9> zY_pf}H;3eBs^$k?d=b)o*W%#p=#q^&GkK$((Ma41`m-kt1|wKQQe5QkGkVt_)YZd< zJ@yOm^xjpJmiELSYmr}{kZv?10;K#)t-TD}eXP9FwV_^qW*OR#4BZWV+qI+PEkXD} zs&@^UkXBn++BYgB6pL8>OTlLdfS~_y=XA z1cOuY1P2Wpa?l0s2g|Xtz*(-fk=7Iy7oj0mdB(CA7qyAj6voyUxz_Y~Ay$mJ+dH6a zv-#E06Z7mJG9HiYOT7Wnd+IA<6C*A;2*;T;HwoY@$MfrSHKJ`E6(VaMnWo-aVVOQ% z9+7tC`#dT_?Y%5(U!^0iKQD*E0%#~N=;eel3n|y>k7QTPb0_1q;oXGpIvu`rsyz$AE_DNsy=;3I_n_z6@uk{^Bq5^Qb+BL< zY%#pwQ|*qo`61ffGwXyCRO=G^VWHPtlulC6@CvTdB~;(afA-lDrMRZvCVTv4;!YuL$do$*<_QA;&1jd ztQy5aMp_eADAT5?SK@??Oc!Ps_$0x*j~wn0DH5&SBuPllEQrhr$Zl?TDT4#xWF6y- z7I$>~^7w;$Gx;VoydmzEhF&35IkpcB&r70-ZEXoGtPQ#bgzu_gdyC@+c#^dNV=Nv6 z&FFuUgcD())lYPj|MsUP%(55e%nb!(N5pnA0zU0{xT0hxyOq!kswk$W2V9L+nfRRP zleCo&*T}KzF(-?i2Y`}pfK3v7d$fZkIom%7U=ZtP=x5oEm%xvJz{o!QQL$IpoH#Xs zA%yHKpFv=sv1Y9)VMY_xOPEr@!_8;WB9RI$qwZFu50LP?w;&}vWnwl9=`1GoAdqZH za%;akM#IodUL+&kY?u~V?g?HYW_k39z%-h2E8mWY3J|>;%$zhps0=kj@|FjC)*!?P zMmY!-DDy+K0u3$dtg~|Q4K3p`wl`VquaNkW1Krn*D~-Z)GvYk+Zh6@)VsPP) zkkdCC`d0Uhh_+-WNWBaIli*<8tu_v9_l(37DdA~z5n`oEH(T}umfkke{&%nH2+~XR z2!gF)h4f~B$D33H?lLtIn0fy-Jt&vk<>lS670#$<-7$IydQMY)RSDT=tKvmuV942QI2yoDXV;;IR5`$FI z4VzTJ;G_$AFPveb;_&C;pLz*_OWO0QgNyb_UBkb4atQpN>eFtVlDwm^D9asD97hIf zf2pK^1WucZOJ+~_ar)RNHhR6n^PF;}pRO%D8g?9zqw%H)FW_@ainuCEi=g=~O^0@+ z<$0y{wE#xj1Trxn39r@P-`8gEq;^%8f`y5yc>8@5w z5I=UT!o5dgq(~jVr37f0bMX&;hP=hlJC#x#eL#$#Uu3*v)Ph%o)(>+ae(HFEA}ylT zA)ZGhdG?KOt6(*MNAAt=43x3^$qV1Jub~e$ zHk>7+K!43+-GV24A#_a0rA>xC-ny1wT%>4JZXi%W(4Caq+JZA0;F~_E3;TQYWbGvjSHX~;e63#vMhexN~-~OZEI;fkMK&b zduL_$kNTnyACNRhk45-cUQ0Wl~%Y{kf~I!bK--qKHaxlZ8;T z*rM#di>W)5SP7PZGO1O? zd@gc$q@iCB#Lp717cE6YyOh#@iE#SGsjprew0#%;JQs)3=GGKYc%j@`n=7<#aaTw| z>Lowle6enG8|5yV$~8wmrIvgykHv68sh!B?O!eS^Y4@ORzX0tq$8EstaY-not(*DZ zQ|F)!!Mt|2liF6id_w#Jva;0;y7o+%M0iR7tFi~hFpodE6bP?ideI-BESOkc&KetH z0Ph?uWEP|N`85&-b4y95r}(`+0x&YVZbYTx32!7?>~}Lrew2k+Wo8!${=~l+dIi!t4kVP5&wg6hyTY7mR|k4u2(# zCW{u9)|As@qiZdR22Ik9gH+JIlzGAJ4B!R;`_rrilN@4&KNoqZb|tv`bG08I#t6%1 z2kAJoI1q<&szpdSrp7gQ3L}E-MFtqT8G+ZCmYWxB5%4~GtayTRNP{ewg+)^_LFg-s zOSKS*{l8IL;%bJhmMu}#vOq2jSuRmV`abfrj5G6+^tgV4P|ky3UhkozJWI_@2DQCFEJ)YC z%A_C`QWC+#av}ORa@HQO`}x{Neo#T56wM|&nc(e(EgysVQT2IC_9jl}6$9g)D`~dud4VFc|DSl|kF&^e~x5 zynTtMYX_b9%x!BC2?l|98_4&O`C%4@z~{K(WWKaS%1my?0RqX>_^qjMyvZ!sNO>Q| zZZzCP6%Gc6$p{;LavNadIXgE8#>B*~LappLfhURFdYjTnAcF zpnO#bi~kW3xpt}_1fkbAB)vqPn7#JtFYrW)iPZq~fR>;^y1b67b^}zg;^p%mW{OlU z|3$@LAma*oN@HdLK-vmuTeF576Nb+-D{kDOmMBXLT%hOro&@$4V7i~{C*Q3A*Z0Xz znf*3Vlu*b(CpV5zVI!e5U98r{6II(s*%KN1Kvr3)y88|V+IF<4oE9uB{xU3$bsl}+ zA4ML020{k}zXX*8LnQPKiwg^1t3)KeV&b8I#_>^iS3%42ip%nI$&9qoJM7;;0P$zD zjpFkrl2im3%_MPd;0skP7cF?o`m5wsCRdC65@Sv=IW(6EK;Mf&S=Q2jDt{#(bhMg` z@lRP-F%TD?oHCKfHWyEqGD^<6L;oo$l`2*alJb(aIg^!@Weg=6Y(PNp?Amit*o71d z1wrd5L=_>;Vdgc=)LU;zv+LR$bAV=u?_)wSz9+3nfnTbJ(#EXHQ*a%&lg3P!kg8@T zt(U^17j=G7)*3AX1V-cN80IcQgBF`)p1g&y%Jx1uc=)AFCgh}I(y z5u@?+vzO+R(?|?p*V18Yq_8Ik`zBZui}SOL){l=vM5*6c80?K4W6GWNih4#!xBv3YjRREsw~Myi}b%kHiq!;64LW9vHk;@|d7yn}l&i&q%Q~x~^|4 z5HLAsDTG=x2pnQvOp+%kN0kmoe;`^5j3VI7` zr6#Ad4qCr4@!ZNb@Nw~i##^?=T6%%h(-Ea&jhXeB?RmJn2aJ2J27FS4z16ACtOC(F zgY^#I5*w{?JMvYLOVMyRf864RG$}e*<9(0MYl+6^nRFwVP*%KJwdhLV9E8RwHE`zvEkYU~dzOf0rlknUMMQv0?F3Eh7 z7}iD&zuvAQl_hrZODv~+#K)A|rIoVl5NygpVrGhhu-IfmUehOK@@e{LBh1{8PTP<$Wt zt_VFJVGr!6VkL_v$O43%KQJ;P`9dOK7fcD-fxVtQ?nF|A$X-~DjN7?e)`iBq7zswz z72t2)1)n1O;<}T?X|P9Cx{Xk1W@))YngMx0s%n%P>#Yr1v76k;w~u|+7To!(IC$%&ttgT_7Vt8yt5Lg)b@)Cc44Vc8wwic6xfNO#k-P8&fw>< zOPO?`JMsONFAevXYos5oms|1Yth5ji|mbhv!(*^&rJv@v8Q|9>u z7i&dC^Q!9LT~c?IUwcjC0^ge!Ewz0v*gV81K{O=o?e0kmZ7mMIuWmV9DCeZ^uXU{#u zlLO%sf*pUVp#meyQMnFIsJ!BGP^l4bOd4wkmU&QtF%k(Zq596<7eRA+hCBh7b5Aq~ zAiG~6=s1NZ5~S0fF!F^^ZqJf;0CvbhEj&)s2`wUKCdLx*CjJG!v1Ep@-i&g0up=Z( z)t=~F+wh*BA+LiDb=BhR5rw4S=E!~0BVA4(>F2qZhJK?w*5yw5rKO}$jHxYKMruDt zw=T2Ic{P(9-Y!vTLRs)gMP#CFJrF?B4gxUtFYsuFuf)`fmc+UIw9qyGm}Fjek;<5- zi&pnjd?j42R$$DBGKl=kNV7CPZnzu5yhNwH(J|guYvv_eD>HV+zQp2wo%NB0@F@e{ zqkuUkq^ead#|O2@#W}}| zh9i{ei-hrlnXD+eWNQv@rU`g-(Li{JpLuD!Vk%uF?eSAM zxawaKOw6xppoB#xLJl#lXyHw=u?47hoEaYGb|^0|vCAz1vKD5TKPURSMD&oF1Pe+F zDrM55_yi8#rdSKlViVX?8UHR&($|Epi1IB_!Pnn#+aW_#CPiE9>6(@~pILL{mXxts z*}Z7a%M;-apx_Xi9QoxE4-xY<+o1( zK3b^|;5xMi8e&MD57|L~9M_Nqv*p%%coer$>V%w>_)_shi|Z3=lC{{03Te@KaPa?{ z6ji5@tNxiylKBI6Tua8JC$Aq#2v18HNQh1m-4O$D*|_rTY0?2*!7R2ZRJVyHbXAXnp_cBRW`16( zQD-C`tRGeA%AbLer8~pJ34wKhBMTdq>o%fb)V-~9CIgP;?z6EDo5_&9t*lx3MHSPv zMQ%N=c>RidfP(kj%UaKBW>qb4uLup%U~dBhbQ{Ak%+vBNBRp4&HHO=hOot+dm9W$b z=#Vt`ps~Q!(vL05+u6ZSJxT{Sn-`TQa?U2NyNwU_*OGl_$>U#rkcQF6`wdaKEQ!VL zQ+#PfEcjt^V^N%&#%=D82<2N|t(D+DUuh*6fs*lJDDfY5yghqKZj-CPy2 zObFy?%2kjQaD0R_!w8ZJ7DqC@>l{|FrdBqtHnHO~Q_M+`;2A#>9g%1|v2vRqFd7H&GixbHLqiE*pdVpn zE~){QORnnAL*Bxs`blrLk+QLhj?7RX>)DnKay2B6XNVhKA2O|`TV|5G3^Hsw+Tnx z(s^_cc0FY;WjB-x#qYs3EQprfP)qG1*DaPbGkPQ%h^ynS7ipw=q`x(q z6g)cwy9!9-A5&y8f`@~O^d2sb%v>NmH_ln=RFq|gYfvL61&`S$-SCMTU)0zFL+Z0@ zH_E$6p*)RYHh8W@(vH1Gs?UL}v~;k}L`JAJ{e|vh{1?OYHinCM(M!TA!f(5n`cVR@ z6h44Ty)wEpd-*{Zi+A-0^T(z~<$5LKOV#pa#oRwL@y_`DeiEDDJ#+<+=UqA%=e%Qbk)dLVtZ z!uORFlsaqq6^L!+^S103fAuVSxoGqvz-#6wh!a8=i^7D5rf-QUokePE_xWu_`RfYv z8|wEF*{X9=q5v$Ak?z8Zfm>2kavmS_or8-wFDh!&uZk#aMaWG5;wnem6Ms9lqaciB z4@lRB#1n*-NnJ;AauP3!@~oOg;G4c*77{ip5pBMo2dur%K9rZ1m8J18(+xw?7gl}5t{ykKqE;kXLz5?@rODO0*AF)T#w}k&uW5&y=aN(*y?J^YR(~bB~(EUL`3okgCd% z1a(J?)4H4`x>Gu260ZdrAj{n6yX<>kLuQ>h4IorT{)>9eV3b~S8i@!#R3bScTMk+x z;CwJn#tI?%7Fm5PC|S>p+8wzBz{}OiIF67f+ZP)Wn%W^G%X9{Wu+qe509atdJ)a~S zBt^1&@VwTgt=7Tc`wSBYyJEk0i(XT$6E19u7N06&HyEZ+AZEfvGvgCw5pGD0h-Stgz~1CTN@n45O}-jBtlb`Jc=1G9bIO){JE zoKhgyHlLHc-}X_>h_z3!FWsuTMF;`oB3dr5{k6DTP0L%Va{8;;g_#y)S6S6d583%3 zpCpnH0c8}AzH4=s(W8Wgs3!|kMUZKK#&HnZfY=zZ@KB(>EDJvhvOCeja*!%q_g=kt zh)Yd}SX%{Q#_Hhc@bIvWr8qsIlxuFzRi5S;3zhFPu**Iz+S1!%4xkFn^B5C==Mv^i zoIO+V%UTf!JiV%}Q~|A}0A1#D3ZX)lZu0)QH(d;RV@1$eGEsP|6#~dnTqf!exLZ7quq=4D~naI{3sZP!eMerk`sWy zsBQAb)CW(w+S&-BMmtjy;V!b|Y-*NUs|XJNL^idp%^fs1PqA=t{$q5@HIR-Od}sI( zqBDbFf_NX&4@R&H#Aun}6H5S2Ns8$oGm8(1^FM0Yy0Meg)egBC!9C!>lL&iNLQjB2 z1?h8F)(1S#yurk=Tr#{K_IY3%o4$#tocVeGLc(OuI$Xcka%y`UU-=U!Ppu#IHy2Cm95OHGtrb1#K^N%o0J(g-H->n2}HDfz!(}zn~<9KF{+ot zq;&({sPegB>he>vmWJ2T34fuRzCNR66y*0)nhvW##!(83Np^&0Q7DSE$y1@Na*G6I zT1O!SZRt1*k3-gQ65(?d@ITPM44S8OT#93gyIJ-l#HHg#a6@8ei30mvSAKA46QOoi zah@=GV%rp%;>)aT!jl*xT(i-#706u;Nf$v^-E`OxpY4ISUMA{FRE|a$3h~DcV|3em z(OKXOUyE3BN7}?CZExal+&Pys3(FGKl`~ooCR9A^O)j+vYowZFljB;yXII zYM%oycd4GkWxx4%+gg*JB$3ve6kWk8XclK!dz+J&x@;6zx1Y@ z15hsA%DJ92w7L4WTARCtu8t)APvH_LzFZdqU0;j=%-`YEU0r2-}Uw_&WoHs ziE1>S$}rAcqRXQ_-lIyGok-4k`j&{)TUu91T$z)lSZl&f51(@Jq@!i^>F)_v7(y~^ znXJQ6lQ64$Pr>#$XDW&N2Z_e-((QSH-QwxJ-{awjXr_Gaql6n~eq@lS3B)B2V5;|O zQ7`Me>KWyJNwh!&$Uvy{v;BPPda2m7l~`LTmP9@tvieQtFaXUV zA$P!p7&_aKp{^dGXyH}pS(w07fqegCn-iX=#Z{BIn&CnC!975Ux~kQdBv32aY%$S_ zb+RYwtKP>DKsR&TC4~2ykU0&D&gJOJqFj+5qB0Brc;h(zzAlL??M+RyxfH?vZAPL(Xy2?|Kj zKf#LnHQCY(2lawTNe_XO9s8qxWfl(^Tm6TrDVH(922x{mOJCCK#>Y$2(b2HcQ!{ky zz-Cp%1659&FUU7~kbyhg`tx3+p>Pg4ppJZuKC09*d&STOVMCWCdssl!lDA5V`MW-> zpjdmy^!tYf0mL~`Bs67K&Ygow=T{@~n|5`B5+WPbk16>a;Gz+MR5kTheAapLit_cE z{TiV`iT1~IJsUAr$dzDXtGrhl;D-7(U2hVSCve6dW+&VjKw7~`#db!o2RAoHkKPHp zE4j`psdA>};RQ>p2|?;h$)J`7RpsYqY6e2j>Z6fLNjX?X+D?%St65~OM&m81AHxR{ zA&NhL30JtiSMR>;pepT7XO$=Trm5qSp4ERu^6^!o7 z1G&&Y?KzZ1c3ymgOH*Fom{CU9lW)KI?QihhJI*BOelgI9=lK^jMK7dgG?V+j*k|#} zB7--4IGaa_LtuU#u#MLO&ouJVU zJ|SOu+)P$9aZq2#zYpfUTJCevrq-)HhjqCi3rSgi(D|YBY-U9XuJYisd~gKqS(G_# z6p<)tc{>eX4>}XIg*(_4vfPLWxI)&oe1Jz^X-}hg?G4yCM$+2t z@evCg3RS&glTw{e`U4+2;-vy3KXHE-zNXUPg2??w_t(5aAhuC>OWuQ6ZkNh)%*<<% zeDD8agrGdEO(4T`_;?9wd5WG<%Z{;5c=vyJA7P(_C{>U^iGWHIdd_Bk@eh_JC5CkZs6GV` zYsiVnN$WFiwiGu-8OZ4YNvtBP6Nk^!5a9#RUcUGIs@MZ3h-8IwThy1Zn<-?=`IspsI zItwZN(yvLdXmtpI~qZ)G3{d5+O@R{A5&La zR3SV{81?Rsb#EV zDy-iZutWB2C4iER7JVP_+pAENz86GXuMYB{0g^F(HM8 zY5I;+{SneQN4Z920JBj64I>(kvBWR4jw&Ln4UdLGVg7>px;myDx;vp&t!1DH=exc9 z2D%ZPuBDZsX1jhfoVlHDxmGeGw;ERVf`QJOyJ0TzUM?hidcj!lRgC3kdl&zm z@{$!uxIm-V>p}~d`y!D}TjP$|g=q_b*xAdkz3HL5o>!2s zos(Kfe2%4kUPSq22-Z##6T2FT>s)x{PbO?2Glv$ZdK6S7jP7);Qr*Kxa5?%l+o;c zK&1p&RL%f2{P;f@=p8ydq_4EN47!_dUtYq2qHg8ZGTkHIf+fp~(@=Cl3PRbsRul3C zqeXtdZ6r2nL7KZiB3CvLgOn&(@~~R{(VAvmlusb8+GiGO`Bg{kw_Z~KL!}JiaSW{_ zDPMZ<%0Us1*i>aLC)&x$15nRm(0@K>Y@5xV&COZ^Tz>*XWe$U?b(1e=J66=655yC6 zS*rj~ejCExr}7LuQ=41Jh>J^{Jx7`$svmfm0z6` zo(r0nZ{RiHvl|xb>?LBjl_tQad=@_%59+T!O2NY-5mKSZfUAmMcUJxqJCgLhWY{~S z$U`kVzf@ARR3x9|%=3!Bcwf7t6Y=LR*Fx{{a!mfSU|ZagK6Vo7~cB z6giz0;DrdVfCrs~ykg_|NfS)ex21eWU6(mU(ry6`kPwz(&^h5>Q#8kCCEt*wtf8|d z&bh+!6{YOh8cQgc(6s=+sf0vE@ftWfr=%WLY)9@FOb>Q^MdL#Z#(_YeLmK(c zN7Cs!$kz!KK5k~nT3=XY6riVQcau1LTnvE5Bd2sgVkL-B+el5%9Y2MTN-4maA092a z^M8S+#{2{HjIi#+Ad*xncLu&qZ^{su;XSW*Lg7mmtr;7Z;UYS85lyh>s3Ba!LWrkQ zC?!{~54{Jm@GB*$<+c!(ln|bjB2>DC$k5Z}my&#pHL@BDPSrA@Ffv^xq$IM{ev{5Z zG4feAEja}r$>KmiB3-lx0mHhI@Ho=9^s+W%hiRHNL`NhDBjtd|Snl}@VoL8?#BA97 z!j#kwVLL-E#ALD6L-_ynb*67g;9DGLUj#%^QxJ``6mw0{aZPXw(F~UiEz5-xQ%fDS z%>s9GySQYzcVr0;nSR^^|XucFO5SbE4DqlOqjut0Dw$ZH>aIRwq zZTXoa9}z=VyWlAUkFv9YFEBHlM0@wI7wrS6P*3m=oK;}Wfv&M4)B^R-W(Q}x8)x!* z8$NECoGbEeRhK_Y4jTI}%ANPRk4sc8x!AyAzx<{ZfAfgnF(<4nT>THzmGWfw8`3h?@0|dt zr-Wq&HM4|=;9rGCZ-P#i^|Y{9*zOy|_s_gi;_wHnv$<{~F6N%L-3ILQgd#u$q6ev{ zz-H5P4EM@1Of7=MnP&|j_0UEs3#E$L_tWG1Xa?X#gj|XfZZkHXRUdFr`(B!hJMfVC zeCbivVQnSbK9yWXnF6nRet3#yH-Y=pai2&W=`DbqdZ6w~3327G@cdX=*OGkG=VAAJ z3X_|QY$@g+5Y9wEu9rmb1V_!^$BbCYZ(Gq0I=x&%9(I)^pYBh%VdEy-piSRH6B;}( z+d~?2O&ZYNFH2@<%E`JMpHYa@I>fMqw^9}yl5nQNDX@W|})w#QiO7XqkxYuPJkhQ^Y- zK_^Y1GI4uAHyX0$e@K7VS0KsGK4spbSa^xB`KbL7saA(NqYv?F`ua7|Q&Idkjkl3^ zdf^vck?r4L5-X0A=%H|8YI9F>!!X~p+5wZ^V%56C1{=qoU$B^Mskt=ID-7ZCZ97bz zeB4&xdFQ3I|u1QD1slL8~Z_XjPztG)2r|+K{5t*iNjrL@HSoz zRX?y^FJE$Zwn^b5mt!_(6%TEEHIV6U`v{wi?)PX#@IC^Cts#)4~4K&=Y2y$!#|c zf@3PHFMJVPqrNmOwBO5P5n>9C;X&+_8V!``NukYQXkmay@5(aG=Bx8WG|DvaY^wHy z$0qHD2IA&Pt}JnoiQ674+voo*2uP_x6`Rw&0_I zedI75^dmn@O?FNWL{(h@+%hXw=RE3}eFK%Xd$^#wo;SWWW6>B#b(^@vJU;@xjjr_4 zJ~bj~cG4>3U6xv6f}>z~i;-R4PX?wVEQ{js1_t!{0|RsNK4zg;_y+2=#WcTBhH5q7 z@Zp{f?QTY)A=IlD^w0Ud9R`#KK#b2j=M~(ldeKJN~W-P^F6YoFU{NEf0F}7@x>-+7^+w8(x!2ipPiats*qMIOqi#4rDKVd z#UBjEPsTT(kK8fMbWm&Ts=PII)P&|{j7F`y2?8eYG_bv3X8p}ry-IM|ycKx>lkDj| z>Ys;h76j(s$SDhl*B*s#yasekuv?zc#p#jqQENd)tU~P*V%YHLxkNO`K>$h8g;UPd zW31V46*CVrdyugzRQj4-6@JPd$;{c;2iTwP!mA3NB5 zDuy?2WvRy{hM-&q)KB9(h~<}uvO<=rrUnc|A@A8Y3tnB{Gy$7Fr{h27KYYuXl^d@2 zT%aDKsK)WR)*nU!LuF6E*B7_^GWbon{V&bc4?9xwe?;`zy`e8#!LHY`nq&5cgw<(m ze$okpVnDMQ@5rYv^i8;zaJ`qQJDM(CZY6mEoeGNHo`S*N?4s6TjJj*l z<-GkV5GiQ~K%dh`B^+OqK@(0IR1fNjfrw)5wKcu>&r6rW@~gA*``2;#>*~9Kcu~^7 zDc2z(I$92=>gy1VO>9-RE(L8fodZiYfZH=h#A22SlJG_C&64^(h5)goW-e@!D#CA} zYj3QsdnjnQ@yV9cu5OgCH@2+Bt`+RhlFa``)x&Z!T#XKaiUni&SyInOt=92`q(dxF z0uK{rCb?327XNA{rvtWA*MWAd)Q*-}N(y4CS)=K^4z}`bDJ*JE`d%y+5pahBOU4G! zlo?2S$ytPh>^`2RB5*CCa#us8mAe`<(P@1{eW=rdR~%8q zavZtmZre?V;dBI@=q_W?J7CRlk^fF2DKWGvfLarK+ZvL5!C64wC~{JGC?+nkJam0> z?wdolzJD9i$<&DaQdN5efbrd>-xQQMo7-pyyES5KYb0XBDNy8giGKR87*2o!meR(n z5yy0N7;wW!1EAfD-=!m3{H|O={YNE|7`B{^I}R0fMF1L&^AvOBug-V*(+aPJb)qUF z`qPPV319D7+w=(@ySF!|S?6Imo@xKBDh}gHB1$1~tYY}DWyv5^Dja?M!hrcb_iovD zO^LQ}4(mlO#5Pp8oN{iyegz7b!`XM=Q8 op?jgNGX{XoX#E~_`YYw1Oqj<1GGVVQ{(mOS1@@};m}52IZy%j^@c;k- diff --git a/test/celeritas/data/four-steel-slabs.root-dump.json b/test/celeritas/data/four-steel-slabs.root-dump.json index 9fb7735d2f..958b5e8082 100644 --- a/test/celeritas/data/four-steel-slabs.root-dump.json +++ b/test/celeritas/data/four-steel-slabs.root-dump.json @@ -53,7 +53,7 @@ "name" : "G4_STAINLESS-STEEL", "state" : 1, "temperature" : 293.15, - "number_density" : 86993489258991547580416, + "number_density" : 86993489258991530803200, "elements" : [{ "_typename" : "celeritas::ImportMatElemComponent", "element_id" : 0, @@ -356,7 +356,7 @@ "_typename" : "celeritas::EnumArray", "data_" : [-9.21034037197618, 4.60517018598809] }, - "y" : [0.0919755519795959, 128.588033594672], + "y" : [0.0919755519795958, 128.588033594672], "interpolation" : { "_typename" : "celeritas::inp::Interpolation", "type" : 0, @@ -574,5 +574,9 @@ "dielectric_metal" : [] } } + }, + "decay" : { + "_typename" : "celeritas::inp::DecayPhysics", + "tables" : [] } } diff --git a/test/celeritas/data/simple-cms.root b/test/celeritas/data/simple-cms.root index 92a67975e2463bd840deec48fa69c8317662900e..95fcc6e68a04d349a96de2c4def2ea14f44c6638 100644 GIT binary patch delta 22247 zcma&MbyQT}7dH$H%n-xS4Fb~ADJcvkE#2K99TFm!VQ3KPMurrmQ%V@ROKC(xLTN!! zq@MZy)_T|T$NR_o-nGu$JLleW&OUqZv(MT4vzyV_iv!s5e%{^zSXh_ev9Pclv9RnG zF~tV+9E2&@n9_-h`EkO+;_AS{lB&SM=GU80_^;4eEhuKog4zv|JevW z`2YMw$O!Mh&i^+67FHFe?@mnl-yj&;NdMn-{Wtvoz1VI*M_5>o!~fUb@c*gDHcvOl zeoXXu7|UD>zlaSh{Bd&u_8SmAqnPQTCsi+{RD18W(Cu+SFYK##Km|j#k7Tn7-V<#4 zVW;ZXt9JwSCS5f`%SF^L>ZY8&d8>9wcbTLYg7b-S4dQn$>zVK6nnY>`(p4Zv#7sFF z?4NrlO%llNmypfxAP(4oHSX0rE2KEV4s%LATp+ql9zH|`MSjA^6d1n0l#mb;){iA_ z>kka(GX8!2+#cqPmCm>eyY^7%QFiP707XzQXc?Z8B#agzWckyK_e>aDhJXlhazM8C z>~8Bp5e&-54}~ti0m0=2bgPE9(P;gsj7KT@XV?`-ue(0Pq{kCH!0{JKuOeU~$BlwE zQ-CU|c-)V#zgS(R*B7TR6Bq!p&r5TM%d6#?n$JA+%kb4-{rOnJ;Tc9=PNiup%tj6UPVbOGUPskp?v=svS7fz99J zwrccAO@(KUCe%(EF<#2hzpK&-Xl#&|EZ!MTCH1^^2odF{X{TN*0#@1X7i=7pZ#!_0 zgUrTX9tqZnB*Uy{+<~9lvFmp-8OMU2O*UZ)w@tUZ_(M0U`?}W?G~LV`r)zeA%J0V9 z(uCaGOm^qYx20T1^#ROV9mkoDfRoDWEZe-8+f2EKy9Yc=w6wH;`(SpqwhbFUrxP`| zrsb~L?!6rAj*i>pf%Fca1LYC#OBxfM)gD`wp4-f3L^aKOwPhRcI|MIKu~YCWW;9|AuBez6Xao^A9@30v4@wA z2(fEkOU*|WGbwGoc|9JliatwRKfmfie$~8d?e)sY84R8La`&%?fqpy2;>erZ2(ldd zeQjfO_NvT~@;Tt3>ao;quyO2tlw@G#;G95CW5G)zeF3a7HOV_pUCP+?RNlsaldbP& zuUIbXN`Fp1dp&WNc2dtoNRfM7ACP&o_Mc3aDn7b`L(dgLv-+aZ~lzp`;D_$hCK+z#k+@-k2RtmOlw7oXLW)lg$) zg0y~7I|1>1+_Bwi{IN$LYK?OJwC5T0ovRu_$4azPJshxzb$V=WV8+q}AMkIlvZ{9P}RUxX3A45!w4>);u9*`PYS z0W9v}Y(43`@Tk?c_L2T&<=QCmwRP}!sCj#9V-XmRS1caYrO5-_-P5(Og}dQ$ygx*-e(wWl&P`7pH<`D$rE^6hI_u57_tvxf)s;oJpglQ}tK$AklJ*sA-|nCm0BsZ6 z&T@vh1+gMS8gweC;yz#f$HrfDAWcX zLoc(Vt(n#Sb+6s^N6y$d?UWwPL|Nt5q@Q>K-Ah{A;6vl<0ZZa5vN_b9@RtYIZzh9^ z{`8)<0YOtbs!x<=?-nlb4#~@xkBj(Sc;_4cIp1^FODw-CpZM#h(4h58R;-x_cYB%sVFTPB;hN$i8Mi_U05^ ze)mdj=AbmmNn;z&^A+J;|j5U62m52m}Jcb1N(v;Uauitx(No#zbrCGoNb9 ztKddcTKmLDWL8=qD@&r5^O?Gp#BBm{;TO`Yx^{l3X3zEVcAq%Zxs^qtZo=v)d!b~? zKmEbNr8z&9^sV;(p=kB)E+k4Il*ghrEG5g*wrRxubx>$c{{&!SeAp)6mCu&#*lPDF zPk|xx*qGs&SGQ2mXOikE=uFU}YJjO{V}tNx!`kM^bFL&Q} z%SBSh!(Er^dABNkHlZ^?I!(P{o->2D0OzWW#Vb{Z;#%bG)QN<})yJ1dr<6R;ihzT- z+gnrqy85~BOA^57aOQ-j)9v21ZX=g1KkB$Bu8xT3-oW9$MewtD)=T8A|K)O#HdOXf zkbYdeBILdmxbhFV`SclOr-yC&wGo)Ubol8!qIp>loE>UOJ9ymNC8!((c9~z#=-3;) z^%iWr|0n2nIc9KsDW9w+TGR7uzO=Zk@L)XPwnOPKuW_At#-6x_@1O4psQ^4&meLYMZP8FN?6TJJrS} zx52HTOW;FKmUUoVmlyD1+}FuWbMv<)|>i|O7pSzlf1u4F5xk^A72yn!s6DO zf#Bcfi;2MVqayaj$NZ;V_V-6?es6neOxAh}{sMRTInQ3-GAJ$F9vLJZZ&-D%(|Wa! z-3@qc6`IfpG~EwAr^={*xpwD&!@2Jg`*;Odp_F-7KQ?p6Q0;t~*t&7l`_$)z{7V=1 z5!ltt?%s9Acus6z`P$`rx9wTzsPp~72o<6uKk8`XsaEjsKf0N>BQ#5;EC2Y8dcS+M znLYajqh7wJ))ox+_F1{}UXASc|3rRyA9O@W=(oIs9_^f~ z@$_y1rT3)%yx9|i?8RMB6iwf4qdyr29d;OxY;u>HzS2EVz{Z(EFSo>x%?=~y{`pMs2*LGcZ!;>2UITQeQO;(FdrRA0#yr| zS%uUu|Lwl$UC5lCAt}1$YwYwp8n~UAG^nksX!?D;WZc;4Tz=u1unnm`?5wjdDJiP) zqHX^eF5{cLpnd2`ml}&#>lIR;+`R1J6eyz;`gG@8x^WPp{KD#2fu_ziiEnqS60mCE zWpmJ#;M#kqK%kU9f7bn3HDv7P=V#?7&7o)0eKevr5n7 zxWh6@aej)wPYJ>PDlVum!RNEtQ83WygGd8?XoDF{eKdhtHb0;}>M=b)w|39DBPC)% zOGSc$My**=KJPX>OfB!H5!W?IGm*fb2Qb-$PJh$))Y50{33t0XYA-f_P~>=3iu55| zTAPgh*N7o+*S*7HZ0|rIZ@-mLn~|6?1}AS=)}H-)3z{JiyA`BWK9zMISMW)xKoV zFjHm}`=d1@|I48fnf3ne@RPxmBUI~0R=K=a3CP7}X3zYG3K#1(e|ig> zM&K5AOUD_pk6^2zKdFX4EHkwLQ;GrFZ;`8lB{07^1lQgb5JW2D-8x@$6@lFRQ($Ev z@<94bn37wk-Xw4{Pr|#8(FO!b9#G6Ixy*tc0sciyA%%PB@E*jgYornQB=(6Y4uzs?I_T4KuZu^XSl2VCm zYn}PrTjv3LbkSMpaatdss}?%G*~U5#58bWkSXtbLk&~PTS*EJ_krt(83_27s(eo=f_d5Y(?8{#MqQMa(`xKfj$i`7j*;JoheT_7xmzxiE`wUgg0&~v4H^0SH;b`W^w*);P+ zvT{7Hqo=U353bUmI5H#E2ftGNUO;dtA;W#&qVe{sdht@Iz$DylY6ptFo*N5n8>s|DZGRs^DD!qXCd=X?c`7qc}-ow%C7>$ zF1NtlcE7f{B_?AN199g;#>%En=iLIze}76B0@pWHfa^cwX6r)uK3BkQKE`gy{d{&J z(9pU2(b~XQBmy)Ww@R6udup>^|o9Sn{(%g@y|=D415Z^ZZX-rzPcfu z$A-g!x*-QsZL4?%Pj;IU-M=mPF%D9MdQc1?8KX`#YEr)P9h9%j(0sVRBq<-D+ zC3$Abd3Cqqu!}Yj3h7cRO90LM`mj%)vC9-JQDL1sfA(fzR+m{u#o<6g=3ftc%5f;tf+vrpUuE?`faeMc^*YE&468t>e#x+>CUe zSEjf@HgL5Wjm)w5;&-YJVZ@y&TxijF7$bu~ zZ7BK34%&A%VqX!6$5;sD=lqF!DW8H4p3Kh04aB#axgR5bWEjgJ-e&ICAnj9NWOg0& z=`kd^d0g@Nn>fsuM&oM}A2H^bUuUZ6nZ78K;a{4j)@PM3bQ`$WE>*e*0raHrUA0ic4! z5A~&AlQ8+G1Rt~R8f1NAsk$7hGU{G|i|oAmJbZQyODiwxeNT5GrS{^~X{{k38M%{m zAl7>l0!zE#Hhlt8*Q{EBy*)&^f=*(Oy#c`eBp7~UDSBZ*Rj&= zL)7`mk;(ABF~msj15WFR5$yd{tbA6_A0J(-KcxZFlOwSA&yGI;UDlzeC{7_IRX&ax z_>^u;?H`{AWZv~FYv&Jykk*DInPDk;rupqh4??YicQJP1UvT2IF{HKZwdV5ujlZtu zYWJI~z~N2qX9T~C;Y`-xIyn^QVdLHW6si@Zmfnd9&f1+_2atd z8p%|Hq%S4ud{ozhaTZPdy{7A8)C#B6Ccc~4v^|&kd>y|7G*~bte>c>TP5r(p;!pR% zd_op7Q(GM=MN%e-TiJQhy*)mb)tR4G@hCU?krwXgn31^-(ihbI&_- zh*TQ3*lSH5A(7fq73{XMTRPBv8?gN1?wMWe`L@`b*3Y<%<0kk8ZzP;waQCKD_#bb$ z#S$*&W{C>kzo^vh3{>e&87uCuvG7iFZ&Hf(w_Jknd%~!`t_Rs)*GU@U*6^pSgsl}n z{JR)Kl?XT~c(vYhZ}oS(2!FWU_wdrmFQ>lT$P)14zj*6(Z?WsoyOHq?2IV#OHn}|U zw>9(2wy@uL44Ga%{KT9Y%=Fg__wD#?=P+FD*m|Kh@ipw>aa(f1jiy zC-XS!D0Hr6Mw<^eG&|n^K(U-u{CgGi8mYLQm+1x&W;0Pr|EtRme&Vm2(-kvi?;eZn zABX+U>6L{MGHg$KT)!HC+i9lVytYt;5w5{%Ki=yz?ifR==*)&*d?>*@S`=C?_bkHI zEB2R>(oB#An)}Y4Ocg2Di9$J}f>)z`n-g~(qF&>YIqw;6wwDh58@j_wV(R}TBi9d} z7y-PQzhTL-7CnWdHm92skDoeR7JPtNQyUMj5Zjzc_mp9Nd?^M#LCqQxJcB#y8dXXR7z) zn`m3a`g^8xo?z98Lgd~2Zu-|@TuIv6*IGcAuYVVErRFu@;^FAmaJQ2GbKkQG>2N%+ z+9(b%S_+Y{JAgJnK9EP@|64L{(d}2) zdAqb);TOGEo#9!?{+e%sAE%<33|q9=yl#bF=*ss_j(_rrMZTygt};%f)t)ezF~8(# zV>)HJIoy%H&-fvOYafu+x>S&;YIs1t@mDYHsa6S z+ip+S>fbKWSO?l>r~#p+Et3eNBA`t;F%py=xtX8_ri0v#4PB~Q6iMQ1OF9&jb&kX5 z{SU3yAlPF3&z!hUHZE3q2jM{K@p0}C3Kb?p$7_!8SA2f6Y984u4lRT5XY!J@W={tC zF!4E=S`%ZL9Iiw+pz`IGZMyizPE$AnIS_xl#nrYZBMJG^nD4`ySg~96^~2}S%#eL4 z+OPTUbVe;-`wX3~y!9@5U|E_-YsmXI;Zi`b*8M>3uI(J7;EBb<4{ zGWO@wNG5>xmqZ!Sk7}a(A}=*j(mIighBF0D_sg_UTTV%zM|Uvaxy*=qs#yLq+}2Fr zMJ_rhRP(@5K~t<$!4r7Sc-R?DORJUd0N3Q{U_9SSWQ?bFvb7E0!m>`IJOBtG-zJrJyU3~GN_bbCT@$&2LF_Zb=&^zV>mw{{^YHswkV6iAr4rm7N=w^4$@Y+u zmUf<&wr%R_1+-$%FeRC-spC_p(I?#=T9DGFYW#!$z_LMFfcAz{KsJ$Q;BP!)>(5IG zEAVW>Hy0?>qCF3;`G=M5^Cqpot?ikEt!@?m*F!WK6-il;ltR_y;^0Jtx@;B}awNC` zAAiP)#Y(&V9wq~hVYqx-ExfL@9MgL`&nY7$WG*ZeRaqhEV{40BPY}Hty~U}@362S< zOLK*QW3a$hF_%3+b6+vc90@UJCi0V1x*ZTLval(Ns3F0fK$FuY4d>3P2~l`Zk;6?y z=LT$&5XDnLAEiS7B1Nb`ASL|KTr8^je;BY4yYoME6!hwU;G^V!=qQJAI)dwAdNju~ zU@x2H;W)q|7TIziVJj*mq^1}=Daax=kjSfvr=UekY%h9qkGW(zOocEZ2CzLtZ#u^B z2Z2B`AmqH_D{L?XTww`z&H*u^>HD5wI6{b>OS)~Ck&|7pm6x8EpJ#%j?>&LuMWY8t z(f_dt_Z;6eofHJhcJYFT>jCka_UaGGDYgQ^;21-2jCqQmK-4=r+SCG2ngdoeX$GPU z`X~~g4FU%1MSU**#4?UR6hp0W4!B}W8;Zj8DL#`vu|LD=>PtWn3_WEDvi(g~QK}FV z*?=LEuX9R^g{x194Fq!D>1R)MYj~N8JA0+3KPX%b7E&d9SAcH>l#EqLRjK51#19!8 z$NAXX3f(&aSqL&pMiwPou{h#>7;2vAnGXwD@VUzk-j+QV_PwW<6b8Vp`XAyf`#+xk z4{^qTz!*UI{}1B)e=%smfON1ed%7zZjOah)`v1y?of3m}V}v%M_P+rX{u3HkM|uYr zKVT(=r8a^UjO}kLdD4#_M~_C}ZZpx+2K^@{K+Q*8&)we3J=Mk9{0T-%-yVW>Fsvg3 zt5$+l!QeL1-oY>Plrh(9A3ZSGBQ2)gb9Cr!dJ|(}0y!`IUlVOku{3H?2>G81>Nn`; zi0i};RY74;=uar-um~-N@&TBeyUzrs@v_oQdXs*-CT<~lqG&o*n>S#MUH^flfo04<^7fKB);YV;Vs3pwXn@Hgmic_eHT3c|6uO9>`Y$Il|G)hVp2~tevuR z1^!3azG{si$}bOyq0l)PsvS!uoBK`-ezUC~Mb|nFHe_Kt!;EeQnIg|p7$d7vattl? zGjc3TQZh^n-lr6#n_4Cvy`Yu3`T0XiNFpxgDxNN5(M9QIP?GM5OWjeP6|k7V5|3Iz zAcR5W>PZCOQ*n7SKNY7c$NF(om_J~T{Om6#Dfhfz4qL-$)9)#tpzvcOR(b7Wc90ZR zioTGfkkF2j=rif%CgldF;mRyL7vu6rJDGc&<!_Wz)!A$!z2G@0$}S?nS?_f7Id zJmnpqScHeDVjmckpaM40=-Ehp5xm&H5osY$B)#F?T;LBW7>TeoOZKw&vQTA=)Ao`+ zYNZ;-DD!!uhmhqD0^uRpjv5#Yw!jGC91MP;JA_zsH&u%iO9i}JdD)+&)OtmjTVY=Y zQcLQWr@orXf1Af#ly915o{^iQRIp^^6S6KRzCq(o-o%iH@~Xt?Vuc)mm4D(qS|Aj8 zl&BsM^+@0;uA?EfgTD&TJXMFSiNXO`c^BgTgtENCWpAI127KOLLxRH)dGxBEI(v6N zV~;%d#K)WwECJxIY!g<#VQp0>m;5r6`t5BqOJgOws8p<4btC)LWH%0PHC81L`>It& zQGvOoR?m8hA}f|Xv}xT)7ob5nNaG!O6F36?yO@Q!zxS?;Ja?1ISEbF{w@Gl6)^UwN zmyk&;?iB{N*RvPk{wW-xm5=qPAMmj=OHv#We~eWo*UH{nxs0*L z?FdBI7X*Tp!7}4rq>=)m6mGCa0{KP4+))eKiCN7OdtjP0g^YVKOR07WVv$eKMlD{t zPm|%u$+d?vn*=ps(HQqPEHm5VCoDuw(B>?#56Vo7fDdqz+D{`Yy1_ok-RJ{damg4Vq3J3^y3abB>OY!SK} zX6!j-p_wWocKlXpU{dG0To{w-18pPZK*ZUrg1NiO&S^tH)Ez9xvw$0Wt* z;;e3w`uW1a-+7am$FO<61c; z$ssP)NbZQuo&1y9OXPc7M?{O_u|4J(VGVJ6Cn5;?U_e$1OM*hl)k5X^jtyOjQnvQ4 zI8IRDLJ-LRL0J_rUJ&!u&Fb*p05BReN54WMlF4AW)8ZRMf!FyLF} z%xJ`7t<>&_9~$~;S_>jBCS54U&{l~sH^FHWAn_>V2bxCyrionWi(GvAW^jRFBQMph zM!LT~MIt4tpODlJkC@9uJKA+)zQI&?2`d4f8co$)zLU+lTSo5Cs|(i)R}Z%i(+T$# zo+ob7siRMpCe+I#>?CBVs4GrZ%&22EyEIX{wSis&0?YRjqjxmZn*97cih&Vgqs9S{ z6sK1J@BBaWhTprkhwCY|`(wzcAX)Ctz(`GhIFovVX}EP`CytsSoIy@R?KK2*y5YoA z%W_I%;ha!>sRK3o{g0Q`EbAvW`-I3>g_)+!WPVph@;s-3K5JrJ7c-ZJ*yt2F=yVf{ zDEwBM+}}-7OzgJLI5?8{Y3&Ru1d`^dpq>sahmjMBOH+EZ$S=D}IR^PFy#^2AKM%0? z;)$oT!*1ah12GC&*%IlBl#tf+G8KX8_pk#$Ii-)R9D zxm7XSp@4!u!2rQ8LmURC*AX%PSds-F(R~r-+T~8vRM`Ut2e~mpcn>|yAAc7esMoBHxOmQAvl@_<* zAw4hf)?z+gZwaVR@vHG`@bU0#I3-_l3d@%(y?z5>U?z}w;N+1{qK`lLu56FWCCl(! znc-l+Y_B}qagZ+Em8uQSHeW1~He4-M970}NypxaVIk@n`pXmHT|3X8z32-K5Cld)p zP_UK^p-0guwOMv>YBk`<%9EN(kw#8OH)rsWFL4pB)COg2!rM$~jiSNBY(|#4r^7B4 z+@X8rWyTQ)e3i7WM-*uf6s*;!K)a4TS~ zlVXlO#tFd>Sr&dGszOg*mm5MjN8$cR;um+_U5kfU4I1JZG zGg_&5fgRAtN%C$`a47b1!QT{jUNQh3h9= z=`oxD7sVg^^`zK{C1DHY2d*v_f=~88;E;qDa}yD(==lKL2WX|#R0JaB1oZMtX0crm z6a9;Qbpn||G3v^M*k2~5>YfiVPLMMELXA}N&EE(LE{(&qR&HTIxlA^C{nshxpDbfy zX5D=7s~*OtNUHipL-R#_RKJ=aaf!cCs?7>rq9DYQX0z|G5&XL)QKW*w)KX6#3k#A- zm$2dbJ>dhG>`Kkj&M*9ZqMjVI6WF5&4HY9swBsb?p!6TYH`{+>jqq!9ZVB+~@F&cS zO-4h13zNEtR0g&)lGkfp#K)VA*5E3gRWt7^V1GlSaSLsn`g3fe#i0boBR8W)%3;n4 z(3%8&HFfO?+*+{Odt4*7jw%k7OsJ#b1E*Q^1PFjwgC)qd~T|u92&{cx}bF1qZq#LJCMM77Dm=L}(g|gt14mql&GY zy|uctI>$MqROO1fhtqDpIdzKpj-@4lf0%`IJ}j=Q#O^AA9udxe_3%@**OPAVQsob7 z?~FA5M7g`q+JUr{PbQIVU@R&qGO~qs6c#w|S$4uGcin~wA zJ?zX`+2uqWOWr-5jRRM1F=6p5$f6P7qc}(>$o(}8;2#4@Ox%PNp8J8-v`>J9BYVGZ z`F8p#iges2N~=C7DrcxvyR1rZ0ceXy_W;+friy|cpXogw9`){BznVN$+8Ovm($H(_ z$ikDPf?LqBpe&x9GgJfX|$GT{>o{2JTlmI zMcL!!+p{<>M>XEY$~42$MxfSP(O=AwA09^Fdi7A)fH9}kZgv)zKO(@^mOCoOfK&1@ zC(@tI{kjp$og*xSp)aEUlV)tr7Sx;-l6wQGmly{xRi_Zp%==|T@%Ts;I6VG-_@D_j z^!VJC;eD%Ae1|$uJc=FnQO{3Uw8KwFRVQC(KVN*;ayG|C`rv5LIbbh7f5|`C_BXO* z((=GG-m{;qHA_ofy9$+TwcP1kS%@5rj4YU(-~Kz8_P4}v^sn$w?cnbXk0~6N85+}a zQxR}z6;3QA>883f`1N)m%BcoL)rYdDXnFWoEc7RqSJ=`k7pmwE2iP2Ij&*Re^RjG)3j9s6+E(K?IV@o z7l7%92*oHqB2l&ZHIK~z%fsg9=8Pax868X^>()lleoFDj1D?%3V&Bc)E2rcw+oeG) zedxDOLtwWgM8L70x5M!QQ`25Qw{{Z4bOkaH8 z>PJ({4&iQthArbrXbt9GVZGOYKjDt%Y`1J6`PBCW*o=*RFiII*rM*5+3DMTJ+nmRx zi-Nb(ipj#;CAX2Bl;0^iM~6@=vT7iZCGobGt>a#188y|;0K~X27knBiv(rh#c=DE8 z72~o^N2spi`jl-ID4|O_FgdDxtC7WXd#`y{8?=Lq7eDN@eolD>@_c8Y`M>b7B(8~fl9ZrcuwYW77E`C*QLedQ+hdgcD%)*76_ zdf6ZlTg%Ha{2$iaNsMaiu)Iw~>wDT7W=I0!6SZ(Yi$1DH@he$$XI|&S2Va&TS5c@X zAqJ*m6h|EDw=V8+Rat`Ea@P0Kiilq&la#==ISG5#VG_y{jv_Xr=vyHWmcuoViZDdL z?V)WuIa{W{fwQZJibAtKR$Wb$rx!~scwEyO2~uJrpA_nPmZ%;?5U-f7_UBD_hKErClfLClu3D#2kTFI+@Ugt z+oUgqD-YBKH74Vq@o{sHKhv7V8p5C3qwqS5Oh6AlREvw?5>ePg=6z;?+B*!*4##4S z?;>JaC4F`{E4m5ai7)|_xLsf;`yF-m;5$VKL2>Q#ltva_1=_*k1hPeTg<3>yC%D{H zWrt9K)?M4nP1T+-6n z#N{glU#v3tbwNb!%Qw;jxPFQn&c1LRd%s7noblhuoJR%h&jd`r5WpOz2a!9g@b+G! zCXg(^Sd@jo$^+2|Krw>)F&j?OsCbkp*C}fIqlCH&ZGdN|MYvua zgCqs~nm2k@mGo8DtLc<1(o*qujxtDnKP???%7m4g43#GkL_3fsojaB?OgiAL<`B0f z8tQ;AtBZ+6M0nn^y6->alJCU|-~a-=M$cG=mFcxs_wB{UoH zV2jh=%U&hS*Nwa~0qZwW+*=)ofY_K)IY~w`UgBIj+7@3ybbkQfC;A$}S(aBwUbV*G zK2@z?qP1awD+4F4M%*+fQFcxVODw#MkXX~q$CTWZBf&1h&EJDuOiyvYn^tJA+cuuu zqVRQ-tu+caD|uVfHoq!flMCaDoRL}s;YW3qHmg%|uzknh1Hb zln(-8_bFo?_bR}YyT}$L)i3DRygMZ{t)<3q4Lp>!HQ}ic`fs=@){i95@dFf#Qy~wE zT>x92Q!^6v?IijX#YjDD6IO)hI)%HF>OuEwLVaDu>`(nV{#Y_35{S=4Ogx@=Z!#3y zh*{IPU5AXk%(2TX1PRO^5Q!7D@X>_%AR_B66ogwu&@y`hASMkJKbqhi@>dOozT_>o zKX76tr;X@+rl7~K?wyrD(op)@@bB2f8bBxtsu*lbEA~)(3@v2G5VJEY`k7I!MMxX_ zDG@>fpN~yp|BjY291xCGCNsciPsjNJUK(MdTR#K%-M2o=fEjq83~q1BOGEuPI{B7gze7bwD>+h|#!d)m{6dV1B02s->}#y&huAXKFsbpfS@Kd&&`%&USFZ~%JF)nu`iY6He8 z_JNe`Vk2vMb0aHy2)d+gN!?JqRtJTTnbfYD_#wya_Jt2zpR{qeO3J^Z6jP_PDJaNE zfByjbFtN|zV2FdK$_XW>y$PZ_r_>jLk4Up4jF6o4#k3jW4ffwFi7SiA@zpt!-fkL3 zF8dBlqHQC(ypaQdT6&f|71dk6aT&=RH`3=q5sIyN^zX$tbyfJ%(eg|Hl<67A_p|O` zH46>uJrBGF?%->3$0nSX*9>_K>Vp25xN<`)A=$N>0>ed`odqN@q%Q=tSk6+xQwj5Z za_&c3_K)nkVo=0Yd54UG%rub_eEa5O?Q9&&GRsI?;uPLje~{C2pOg`rGHUqCX!klQ zR1>c_UVtGIhh3gVsRS1Y*o;tYDSq<9h2ECo4cwE6bsKv}d{*OCcdd^|N^&MCeX}K&kA$fC!21~uKfLcm@GjrT z>Ta2(*`(zljej9C6%(I5g!D8{RX$wpz&OxfW*fJ^%n!=yZOj9MveACQ)lacoOcFC* zn@jE~F>dxvpwVbhYlEby++#idc6MPwjz(@3R*qIaif${CosjVY1)qCf7d>a+N9_ju zq#0%f@39U(^C~0N$mJ3}^$1G%K?klC9D6$vp5(a9I7$^pD18|Mb5msm5s@;ZJ(FPc z3$X36BRFPZNdfR5K>g0rpFKCnHwk&|sY)ac?lXE4Kxs~Fd7<>^ZfB5ub_@vlL6~CP z90{&;AzsC)RyTh?BoPpy?{tPth%1@j-kvO*ESOBw;F;AUp{r8qh?gRC)n{LZu6`T9 zBHm*j#1%D%AhyEChXvHe(D?K$ApYk=9aVH|!(uOYl7NR;<7p^14;C(qT`JzlW-iB5 z3GQsl@`H*!=d6sf3Uq=q`3<48JI(53HRN#$>sq{AiWQn@ocyeirxR7o8=WyGpI5&gny6|G^teX_BTmloit0*BvCKJe*G6IPpVGeSWBrant*z3rtgVt2{s$P@Ps1GAf$s=m zb|xW@NXN%9M&DP67ccVgkI4ffyKon5>r3k-VjdLgW9QMZd^!1m+j^b)UTD-zGiBW@ zhoOs%tEeL~lIRNvD^sFs)`OI28XRZXH;D#p@w`IPT|gzo)1y%0oQ?0;pyx;ji+m;5 zH0&KnO(9_p%el4PPKqzaS&FQH?~FYjU)#;emrjXf%veM{H>P8GZcIk3k0H=9*-4VB z3?x02Kqe9i{d%IjBxk85$TEiffh`$AD)||2WnlkNY66E z5#WGtVY@$x6yme7ot?FA2mOVrs-7|8ouAWZSPd5Fc44~GI|d)KMnn_jW-Tdcj`;cf zz?Z_M3}n{zRdt62N0C^HZ69;HZXJ~N8MykmkuS^Y`e9SeqS(?&l=fS(VCP1}4db<*t6rN;K5tqrefgNlX2ZUZ6}1>nny@?~$Q?zSNz< zk~T~4SLOi7aWeSNVAAw#;za0gAHR>}E56u@$o4P8KskRl5P1w&DgUB`nT~v)249Vj zq7|}I*Y?6dR@ztxr*R7BjBF&KLg-bxh1q!OL4w-$Qo=WB0~w%9Rvynmr-_Mv@AszA(;72nnP^JJ z*FqrLvcT#xIO`@F%Q_h6U~9P)!smhY_N-=WvnX3Da#)8_@&(JgRn#ynxLJ~04WE;c z(TSOx_by@(Zvf(Bxmjb6_CBiWOWYBK>YfewkvIKTa`Pj)C+1@XjFz zRyMG@n6i=;=&%g;5eFv2rg8gpN_}siCaH;t3gwWkEh&gH&CS^UB^kSiZp?vjv+jSa z&!8pvHACbT0n${T%eraz&C-9tf>~$)LTsaB) z9WJIj_S*XJ$1I3BS-xTXF?(E2O5G{DGm|rusNjsV2G%xKmq9{-Sw3SxcO;|hjuxdRHXKUjLO(@#NOm$T3u*6Lb?nkx^-tfZx9)=h88yQdUpAvh*JdCDHFT< z73FlPEbA7?iz8ASEs#6YkPPDjzZ~MYaj&;4(mg9O?j)>|@avUTu7{84A!zmxIy4Tx%3AK(x_W%hYGL#$a_P>^b#k(XUaBCQ<%*E3?-SRHj)pu6}v zA~Z$0et0VSg-)vAhLV+rv88!NRu0rga3lv?gqcS5i3$Z{K_BUQ!zLzRgi{zpb&N)5 zs4F|7ethj;xFOV!5CzI}t$ zh-(`5NC6csxOF;~wo1>eO43j1(RX=kJS!@iWdq>UxkBRE-ps*0R79}7 zgxfTebxnAY5-3Hk@9^Qsu*4~iT|Ve><0 z&&kg%8J1nbuY7tDpJ0`;SgkG%QuKjQ#gdQ3$pZfH+R=>YFAepvBsNNi%7~RMA(cW| zvr=@P@$m~xYvE3TC|(5N1g;;$S{Xk7Kxxp32@tN{0$5VM5)^O0< zln|Ds*=E4&*=-94pST_`f$JJsZ(S4ipYRi8aJ7FHaePbm&4YIQDZh};E_|FF_35WX z*^X^HR6y#>mhTY8NcMQsP7jYq)+N&aO(P3X5&eGY7=zz%f5vPY#VBTm)2qT#{t)#2 zyU%Py5x^a4jze{ast%r;_8CJ!9*TmL7&9qkL*o${dke*G)(_STk&mY+x|5P>YU6UW z^)l?KGmhZ5^17v)5|U<{r!*+A)WF@3%)r?U_#}!T*qJ7TL*(E+L+~}MbCS1~Ti&Ek zq0hLuokhGujH^+tnBAsNx6hcBLzKU^h4%k6a-UyKrQaUF(?dcJ9YYB%2~A3Zh=54| z2|ZMiq5%~HmI*~vWK1J;HB{*a6a)pOsep`v1PoFP8XfG&0HPuyij^7fncrP^-F4sH zKj55oUOeZVXYcQ4Ki#Gr71AZ8+oHJ~Vb-LzAb)m3v^3G9zjQBiuC$UqUz*n#Nb#+S zl1W-fX&C(bJ8J`N+J$UrW03qHG1qqUlY^GdN@_i8;AdBXpZsEW))o)Pj2^+Z;}j?L zB~hy2&!Q3hg61AG^dR;UBc`|k85MHToA%YH)c6WbV{QkVFClGJ)ySGU$?S>y(5qkk zUANwSw`4`HwdX15AgztbOlLAH;D>1Shs+@pKY9Mp0P9x=n?p+S{fs&KRH+;PXl=lJ z#Mup!Bx_sbuyxwtrq9NXRT2EfS25#P{6=lJ2x0n+ z;-lU@0hJpTK=EGdYaD|nFz028|y+R}=eSf$5o&w#T66Wwk{aM+Vy2yeT| z;rBByl#g!LVa+I|Z4IgZkg=Gjrt}jxHP&w6mJw%AeN4vRuirEC7L;>EA?3{&!aZH{ zSujNF`qAI8U#%ygM#P#b%xNc1G5S`8H!}5v!YlCWLP>wW94lQ?U3A{J($|V+g@=Ju zkXw8HeZjD@V(ha z^2{=6(ApXGLo5`(HUww!jp_yP9;ow*jt7+E|p@n?uWpd5v%M%v-!xu)-q|T4ST`E1nR`Q0ik{%^=!c(NRn>;*LiAY&Ost zCYzlnkU3@bgn6nPK-F@gf|*V9EQOmMr`2SuMhuUxn>^kt;K`tSZb0X59+q?<#ZQ%J z>zLHg&~BPTh*mLRu5g?5%q+Q=$$r7opu4^Sw!t#c$23h}2fvgM>XwbQQ_v6pq;K4? z$Npb~HQmS%U$d2>l4m{}K_(C6#`=gqmU7hY6l2bg_lKQOs~1Ivgp^i>ML{Zay`8iq zb+?z_q8j3K6Epzs=iwyp8f8`+A5k;KxQts|AFsix|9eGg6@8%Z*QTo$gRPJ$>7%{W zHa|$T4)}|1yu_e81wCi~Qqr&_H=!zc4LAinUfyIJ&D4E-O=+>J0LHG=f?wk(&&wT7 zk^by2ZWx!xQ>8ClWv3>?aurxs?$V!jsU1^T_wUEvBv^bDhbCH3-qYOQNQ`#I2-1;_ z!nrff;pOMGqqDeQ%RI_E1+D&&JpN^a!12*w?%bd}9;l7F*Binl5m75A0%begj&_-L zR{y9!l!W|wOMQvssRc<74dWz$rvnxwy+r#qv#Yrnd|Wh1*f}BGV&mLlO@=QKd^}st z%FE|;1ZJ88Jg=lB=F=O(z6h%c8=z5OrF<*jqE1`IMWi;u@%V*ao{B-R zH!M9k(a`m|4v?m4b9Kh{E)cnzCGAO=r^C$LT34XzUP`Qo6M?ufMa>u2M!4EeB5&-) z^zTv)BZToer^?L+@9tn21wmeur7g5%>GxgM6Xs-_4$=kKfj&-DRB}>YP*PnPeov8@ zulg3#+8F6swwaIZ;p+r;qP?IB0#EZ@Wv3${$#PB25HlxUW7Ka(J zqXPpJe?BfUEcwEBiwG{?*754Jd{c*s<8_iwnu%{nk~(2r+~`CQ7i$!RQfZ@=UZOYl zp6sHq3@6G^D+HV1HDl-DGt_T~=RL?rAM!4n6J%tKip-x2#Vd%~`Ei4FryKg>9ekZ=X1EHcWm3!EB z?stAbDN?l@7@{aKcx{Z3(yEJ$x}vHJpfh3I;fQ1Ei;G#V!gUjPY*s5`u?8#~#Iz8r zL?$|#nZ!m>>I0vYj|t5M+Xb=xnjCD7m(+Fv60I0`IoKHQk)M&~EtpTfp>Go4weLE$ z_GG`6+WgAKNz$LQ#r`rAFE`IXp)kqkCe1P|0%zLQW484Vg8g=IrrPFaB|H!y{QZ9j zXlOi;2~ym9_#kqb4p*Rczn!wQ01BT>l*L0ss^%IOy#eBH*MWA=8#bRYZiDT89?16f!?Rz1Kl`*nO=*NUVa_;>GKi4fPYDc z&9$}9ob7Z$C$-UWZuJ1Wto%$=U1*Eq*l#|0!;f3chi5*~nC}A^qM?lN>7?}b3a025 zC$}tI;WhwTvwcfRvu9y%e{n;Qs|>JjSGD6ri-LU0-$r|7)Y=w2ywxA{Yz@&?0gle8 zol*K2bQiK~9ieAgfvk$A-F%}ve;)gVbXH!{8xqc$N5(Xncw<>d)qmR=rwHC5hWFl8 zcWut?Z{Dz%QG}mx+-QE)L@DhOyMxU>5$uzcPqU!Y!Tlhuuxu^{{o>}9;|k9F7hOCNyg9m2-C0MA)>Yge?% z3*XN&H3XNgDX3t48XUUbV;yHcb!uh2v{)(EVBXl`V>*|%%TWKvtTWAsbW;K{aD^xb z{E?I8K9u@dhWt4SkT$I+zWMOioox2=+>m?hM&39q$9-!qT<;GPH*{{d0v1l!F49#M z+a(FJgKeBSg=%;QpcG;ALI`{4g)V(X-81t=_!d1`ba7DR*?5FDU45g^^$P)W0B3wnEwpU^eu@ryKSLjEx3a zgZI8~6IC!H6;Gigzk>kMP;t^2(IWgIP9U>59e&EB$K_&tw2V!b&as-2{6WJNI6k@? z9#i*EV5Pa3f0nm_bdqcJi!V9$sye6G5mNwo*vPH4n8_cQr4$KP*%S&j>ZYXqH=m6= zx@?5(YbhS%@eXg2JZ`O?s#UJahiu+r;F7jM)v!fzOx8Qb>Dp^iG-dIAE^HtPdK_S;i0XcUcD8^}khtWp@3p6>!7jNU}kG z$OFoa#bW9~bG8AnF$K9a6;O7Y_nap>0*OA^by!lX{qHtmJESuj=E*%^15zXo z9J*yOd^@9g*Vy0*8`uR7qBIz>OnP0j-Y<_A#U>d;_TZ*17~bwM6V#ytxIa&xcgE>d z85jLs*mxMm>~anx1(M+1qtV*<+?it;gsb}NQ=qb z_C*k3@W$TA2b8XqXR>}s?JV@F)k=8~;{j?JybvHb{Fr(zm(qtu56ceqL-HQQZ8)_; zI~1D2-BwRAO|fWyg`bXuo&T+{*!NR`=3PvI163!((o9>+oS&|SdG|4$6^i-Z<6rvh zHuRvc%j+`>Wz8HDGFvgVSV9$Dt zU|r(0x@t-Ka^qvipj(id}` zM*fy%(F)Omld1X?tyKyJzU9(AWrQq>tw>Yw4aafV_)FevNnDM&mYFI8e?NbB|9La|CoI% zsw==$iC^WpI_Eo2tENTJtD+Nv?f3YGK#K=(9cM0z5XIc4RexFg?gaaW+h#=juhdvx zf06dyYg~<+q}xg#9AMHJYc1_T&&v<*PR<5F}Kg(n?ycdA@9Jl2ny=f+MO z_d$y1Wz*6i58F3%!_8N+qE2RZ+W7u`2i*26U#n;-yF9V<$8r6%L(Qr+D(HbXAal+N z#Rho=9ef%=POWbYvc8|?_KZV5h8Ayu1H7{vRkp>t@|d|e(Q4-$M)?r~Na`ZdhabnZ zj~Np+lkMO~<%n4|S?SS6+{H0t)5hUvx7W?sH4+h?bzqSc z<_SjrPVk8OP*^h9c0}?B599)MYG>sV66=m2j>kc!87Z2wD2TK#`&=_L4CS9;| z_U)ikx2Q4n^oFNYdhXyxS*}ZoZL|Z2$$xgwL1yK@p}t7q8j#(2n`=ISC*RYZGNX^R z(gS$Ui4X$|B4Qpa`>aIpe^@Z+1DB7RSw`X%vj=xOY@VU1q%e)2kSc=!lK}HTy;58G zu@%m6)QS0vx13{2bOF4s!sP-1nH65I{AAn}K9}q?jd=-d8`fP{-tLU&{Jw6azw~m@ z{U3$PY!#f&Hf&kv|K*Rdd! zyr!v1qok%*4x@odlFGe#n_GZIKpZ|FCQD4sL%#)Vyuk2n1{!_nyB9hSJu|LqvwfiJ zZoAe_@y`kB*sV{R4jkalB~-tH6ib}Y$oh70jt3<<@N<29xXhUHLe5W_0UxQ_m&`I; zT$ji-wLA#}BWm`)-y5K;Cnt8*pK~f1RF^59;_A*R%s^~(=ulOoUgH2&!D* z7~SGO?+C5CC@Q`pIKj3e4&hz1YvAZ`t2U)v@%vpO!P$<(Wyf-5L=ck zJK6Z0TuG_Wyja{3ghZIA7}|4nrOjX`wS(JGArfR`lRW`{;2*`RB%t5&4N1JId$V3= zSNpL|jA3Y0ZD39%*MyaZdx_*bB#l)fs`bh#`b=n<&kAvO{K(gynTynp0oe1MBe2Ii zv!{m!IKa_`sO_V&2YSkVUrz$VF^Oce@e1v8IeM%SRG5y2dV)yk$e$rcpv8xsWNk2@ zE(;XrL-m40?jVfqwPc zA_^P!iHC7!ozrh-5I{kyw6`gxC$PKd?4fjS zln9l-MmrGCEkN;nd+TArlGTV4PuOFJb{&6Jva2p?u5?$`853{<028LgY(%3iyTJ_i z$9CE~ySYHCk{>(UnB#Jwnt^m4uO_Bmfv10MXg%Sbg3s^aw?X8|N+5lcg*afC@5p~f d{Lue9;`g6}Y5!j%e!!u!j)=HNN64k1{{ljNXMq3! delta 21775 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 diff --git a/test/celeritas/decay/MuDecay.test.cc b/test/celeritas/decay/MuDecay.test.cc index df8e50d92f..7771ec0210 100644 --- a/test/celeritas/decay/MuDecay.test.cc +++ b/test/celeritas/decay/MuDecay.test.cc @@ -23,18 +23,14 @@ class MuDecayInteractorTest : public InteractorHostTestBase void SetUp() override { auto const& params = *this->particle_params(); - data_.electron_id = params.find(pdg::electron()); - data_.positron_id = params.find(pdg::positron()); - data_.mu_minus_id = params.find(pdg::mu_minus()); - data_.mu_plus_id = params.find(pdg::mu_plus()); - data_.electron_mass = params.get(data_.electron_id).mass(); - data_.muon_mass = params.get(data_.mu_minus_id).mass(); - + mu_minus_daughters_.push_back(params.find(pdg::electron())); + mu_plus_daughters_.push_back(params.find(pdg::positron())); this->set_inc_direction({0, 0, 1}); } protected: - MuDecayData data_; + std::vector mu_minus_daughters_; + std::vector mu_plus_daughters_; struct TestResult { @@ -46,7 +42,7 @@ class MuDecayInteractorTest : public InteractorHostTestBase { this->resize_secondaries(num_samples); this->set_inc_particle(pdg::mu_minus(), energy); - MuDecayInteractor interact(data_, + MuDecayInteractor interact(make_span(mu_minus_daughters_), this->particle_track(), this->direction(), this->secondary_allocator()); @@ -75,13 +71,15 @@ TEST_F(MuDecayInteractorTest, basic) { auto const& params = *this->particle_params(); auto const at_rest = MevEnergy{0}; - auto const max_lepton_energy = real_type{0.5} * data_.muon_mass.value() - - data_.electron_mass.value(); + auto const max_lepton_energy + = real_type{0.5} + * params.get(params.find(pdg::mu_minus())).mass().value() + - params.get(params.find(pdg::electron())).mass().value(); // Anti-muon decay { this->set_inc_particle(pdg::mu_plus(), at_rest); - MuDecayInteractor interact(data_, + MuDecayInteractor interact(make_span(mu_plus_daughters_), this->particle_track(), this->direction(), this->secondary_allocator()); @@ -97,7 +95,7 @@ TEST_F(MuDecayInteractorTest, basic) // Muon decay { this->set_inc_particle(pdg::mu_minus(), at_rest); - MuDecayInteractor interact(data_, + MuDecayInteractor interact(make_span(mu_minus_daughters_), this->particle_track(), this->direction(), this->secondary_allocator()); diff --git a/test/celeritas/phys/MockProcess.hh b/test/celeritas/phys/MockProcess.hh index d5fb821b61..d86678524d 100644 --- a/test/celeritas/phys/MockProcess.hh +++ b/test/celeritas/phys/MockProcess.hh @@ -57,7 +57,7 @@ using MevPerCmLoss = RealQuantity; * The given applicability vector has one element per model that it will * create. Each model can have a different particle type and/or energy range. */ -class MockProcess : public Process +class MockProcess : public InteractionProcess { public: //!@{ diff --git a/test/celeritas/phys/Physics.test.cc b/test/celeritas/phys/Physics.test.cc index 9e19179128..618d8bc17d 100644 --- a/test/celeritas/phys/Physics.test.cc +++ b/test/celeritas/phys/Physics.test.cc @@ -149,7 +149,7 @@ TEST_F(PhysicsParamsTest, output) auto j = nlohmann::json::parse(to_string(out)); j["sizes"].erase("reals"); EXPECT_JSON_EQ( - R"json({"_category":"internal","_label":"physics","models":{"label":["mock-model-1","mock-model-2","mock-model-3","mock-model-4","mock-model-5","mock-model-6","mock-model-7","mock-model-8","mock-model-9","mock-model-10","mock-model-11"],"process_id":[0,0,1,2,2,2,3,3,4,4,5]},"options":{"fixed_step_limiter":0.0,"heavy.lowest_energy":[0.001,"MeV"],"heavy.max_step_over_range":0.2,"heavy.min_range":0.010000000000000002,"light.lowest_energy":[0.001,"MeV"],"light.max_step_over_range":0.2,"light.min_range":0.1,"linear_loss_limit":0.01,"min_eprime_over_e":0.8},"processes":{"label":["scattering","absorption","purrs","hisses","meows","barks"]},"sizes":{"integral_xs":8,"model_groups":8,"model_ids":11,"process_groups":5,"process_ids":8,"uniform_grid_ids":57,"uniform_grids":57,"uniform_tables":44,"xs_grid_ids":32,"xs_grids":32,"xs_tables":8}})json", + R"json({"_category":"internal","_label":"physics","decay_channels":{"label":[]},"models":{"label":["mock-model-1","mock-model-2","mock-model-3","mock-model-4","mock-model-5","mock-model-6","mock-model-7","mock-model-8","mock-model-9","mock-model-10","mock-model-11"],"process_id":[0,0,1,2,2,2,3,3,4,4,5]},"options":{"fixed_step_limiter":0.0,"heavy.lowest_energy":[0.001,"MeV"],"heavy.max_step_over_range":0.2,"heavy.min_range":0.010000000000000002,"light.lowest_energy":[0.001,"MeV"],"light.max_step_over_range":0.2,"light.min_range":0.1,"linear_loss_limit":0.01,"min_eprime_over_e":0.8},"processes":{"label":["scattering","absorption","purrs","hisses","meows","barks"]},"sizes":{"integral_xs":8,"model_groups":8,"model_ids":11,"process_groups":5,"process_ids":8,"uniform_grid_ids":57,"uniform_grids":57,"uniform_tables":44,"xs_grid_ids":32,"xs_grids":32,"xs_tables":8}})json", j.dump()); } From 9a467b17e369fd9f61c71866adcbd74ae22bc66d Mon Sep 17 00:00:00 2001 From: Amanda Lund Date: Sat, 27 Sep 2025 11:43:32 +0000 Subject: [PATCH 5/7] Remove unsupported decay channel types --- src/celeritas/Types.cc | 6 ------ src/celeritas/Types.hh | 6 ------ src/celeritas/ext/GeantImporter.cc | 30 ++++++++++-------------------- 3 files changed, 10 insertions(+), 32 deletions(-) diff --git a/src/celeritas/Types.cc b/src/celeritas/Types.cc index 219d482207..3353e8d50c 100644 --- a/src/celeritas/Types.cc +++ b/src/celeritas/Types.cc @@ -97,13 +97,7 @@ char const* to_cstring(NuclearFormFactorType value) char const* to_cstring(DecayChannelType value) { static EnumStringMapper const to_cstring_impl{ - "dalitz", - "kl3", "muon", - "neutron_beta", - "phase_space", - "pion_radiative", - "tau_leptonic", }; return to_cstring_impl(value); } diff --git a/src/celeritas/Types.hh b/src/celeritas/Types.hh index 1fc1832d0b..345860ad42 100644 --- a/src/celeritas/Types.hh +++ b/src/celeritas/Types.hh @@ -209,13 +209,7 @@ enum class NuclearFormFactorType //! Decay channel type enum class DecayChannelType { - dalitz, - kl3, muon, - neutron_beta, - phase_space, - pion_radiative, - tau_leptonic, size_ }; diff --git a/src/celeritas/ext/GeantImporter.cc b/src/celeritas/ext/GeantImporter.cc index 30fa5ab967..ecd5b0698d 100644 --- a/src/celeritas/ext/GeantImporter.cc +++ b/src/celeritas/ext/GeantImporter.cc @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -26,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -35,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -43,8 +40,6 @@ #include #include #include -#include -#include #include #include #include @@ -59,7 +54,6 @@ #include #include #include -#include #include #include #include @@ -406,21 +400,17 @@ to_form_factor_type(G4NuclearFormfactorType const& form_factor_type) */ DecayChannelType to_decay_channel_type(G4VDecayChannel const* channel) { - if (dynamic_cast(channel)) - return DecayChannelType::dalitz; - if (dynamic_cast(channel)) - return DecayChannelType::kl3; + CELER_EXPECT(channel); + + DecayChannelType result{DecayChannelType::size_}; if (dynamic_cast(channel)) - return DecayChannelType::muon; - if (dynamic_cast(channel)) - return DecayChannelType::neutron_beta; - if (dynamic_cast(channel)) - return DecayChannelType::phase_space; - if (dynamic_cast(channel)) - return DecayChannelType::pion_radiative; - if (dynamic_cast(channel)) - return DecayChannelType::tau_leptonic; - CELER_ASSERT_UNREACHABLE(); + { + result = DecayChannelType::muon; + } + CELER_VALIDATE(result != DecayChannelType::size_, + << "unsupported decay channel type '" + << channel->GetKinematicsName() << "'"); + return result; } //---------------------------------------------------------------------------// From c30626c841c3a05fde56a3f8d0ba69c97ee3fc9a Mon Sep 17 00:00:00 2001 From: Amanda Lund Date: Sat, 27 Sep 2025 19:13:43 +0000 Subject: [PATCH 6/7] Fix docs --- src/celeritas/decay/DecayData.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/celeritas/decay/DecayData.hh b/src/celeritas/decay/DecayData.hh index 6910074275..29b17ba121 100644 --- a/src/celeritas/decay/DecayData.hh +++ b/src/celeritas/decay/DecayData.hh @@ -2,7 +2,7 @@ // Copyright Celeritas contributors: see top-level COPYRIGHT file for details // SPDX-License-Identifier: (Apache-2.0 OR MIT) //---------------------------------------------------------------------------// -//! \file celeritas/decay/data/DecayData.hh +//! \file celeritas/decay/DecayData.hh //---------------------------------------------------------------------------// #pragma once From 08a2f1f0f9ce3c31041c02e9a274e16c8214b8a4 Mon Sep 17 00:00:00 2001 From: Amanda Lund Date: Sun, 28 Sep 2025 09:03:18 +0000 Subject: [PATCH 7/7] clang-tidy --- src/celeritas/phys/detail/DecayTableInserter.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/celeritas/phys/detail/DecayTableInserter.cc b/src/celeritas/phys/detail/DecayTableInserter.cc index 35af77101e..585339e876 100644 --- a/src/celeritas/phys/detail/DecayTableInserter.cc +++ b/src/celeritas/phys/detail/DecayTableInserter.cc @@ -69,7 +69,7 @@ DecayTableData DecayTableInserter::operator()(DecayTable const& inp) channels.reserve(inp.size()); actions.reserve(inp.size()); - for (auto ch_inp : inp) + for (auto const& ch_inp : inp) { CELER_VALIDATE(ch_inp.type != DCT::size_, << "invalid decay channel type");