From cc044defbbaf33b69866b67569aa58092f447b77 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Tue, 4 Jun 2024 08:43:31 -0500 Subject: [PATCH 01/94] Move table loading responsibility to individual fluxes --- python/SIREN_Controller.py | 9 ++-- python/__init__.py | 7 +-- python/_util.py | 33 +++++++------ resources/Examples/Example1/DIS_ATLAS.py | 7 +-- .../Examples/Example2/DipolePortal_MINERvA.py | 7 +-- .../Example2/DipolePortal_MiniBooNE.py | 7 +-- .../Fluxes/BNB/BNB-v1.0/FluxCalculator.py | 29 ----------- resources/Fluxes/BNB/BNB-v1.0/flux.py | 47 ++++++++++++++++++ .../Fluxes/HE_SN/HE_SN-v1.0/FluxCalculator.py | 22 --------- resources/Fluxes/HE_SN/HE_SN-v1.0/flux.py | 33 +++++++++++++ .../Fluxes/NUMI/NUMI-v1.0/FluxCalculator.py | 31 ------------ resources/Fluxes/NUMI/NUMI-v1.0/flux.py | 48 +++++++++++++++++++ 12 files changed, 164 insertions(+), 116 deletions(-) delete mode 100644 resources/Fluxes/BNB/BNB-v1.0/FluxCalculator.py create mode 100644 resources/Fluxes/BNB/BNB-v1.0/flux.py delete mode 100644 resources/Fluxes/HE_SN/HE_SN-v1.0/FluxCalculator.py create mode 100644 resources/Fluxes/HE_SN/HE_SN-v1.0/flux.py delete mode 100644 resources/Fluxes/NUMI/NUMI-v1.0/FluxCalculator.py create mode 100644 resources/Fluxes/NUMI/NUMI-v1.0/flux.py diff --git a/python/SIREN_Controller.py b/python/SIREN_Controller.py index 7f714b115..7990dab0d 100644 --- a/python/SIREN_Controller.py +++ b/python/SIREN_Controller.py @@ -1,3 +1,4 @@ +import os import h5py import numpy as np import awkward as ak @@ -413,10 +414,12 @@ def SetInjectorStoppingCondition(self, stopping_condition): self.injector.SetStoppingCondition(stopping_condition) # Initialize the injector, either from an existing .siren_injector file or from controller injection objects - def InitializeInjector(self,filenames=None): - if type(filenames)==str: - filenames = [filenames] + def InitializeInjector(self, filenames=None): + if type(filenames) == str: + if os.path.isfile(filenames): + filenames = [filenames] self.injectors=[] + filenames = None if filenames is None: assert(self.primary_injection_process.primary_type is not None) # Use controller injection objects diff --git a/python/__init__.py b/python/__init__.py index 2429378ba..7f0f00e2d 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -14,8 +14,8 @@ utilities.get_detector_model_path = _util.get_detector_model_path utilities.get_material_model_path = _util.get_material_model_path utilities.get_cross_section_model_path = _util.get_cross_section_model_path -utilities.get_tabulated_flux_model_path = _util.get_tabulated_flux_model_path -utilities.get_tabulated_flux_file = _util.get_tabulated_flux_file +utilities.get_flux_model_path = _util.get_flux_model_path +utilities.load_flux = _util.load_flux def darknews_version(): try: @@ -24,4 +24,5 @@ def darknews_version(): except: print("WARNING: DarkNews is not installed in the local environment") return None -utilities.darknews_version = darknews_version \ No newline at end of file +utilities.darknews_version = darknews_version + diff --git a/python/_util.py b/python/_util.py index 5fa66fef5..2e3b087f7 100644 --- a/python/_util.py +++ b/python/_util.py @@ -1,6 +1,7 @@ import os import re import sys +import uuid import importlib THIS_DIR = os.path.abspath(os.path.dirname(__file__)) @@ -537,19 +538,21 @@ def get_cross_section_model_path(model_name, must_exist=True): return _get_model_path(model_name, prefix="CrossSections", is_file=False, must_exist=must_exist) -def get_tabulated_flux_model_path(model_name, must_exist=True): +def get_flux_model_path(model_name, must_exist=True): return _get_model_path(model_name,prefix="Fluxes", is_file=False, must_exist=must_exist) - - -def get_tabulated_flux_file(model_name, tag, must_exist=True): - abs_flux_dir = get_tabulated_flux_model_path(model_name,must_exist=must_exist) - # require existence of FluxCalculator.py - FluxCalculatorFile = os.path.join(abs_flux_dir,"FluxCalculator.py") - assert(os.path.isfile(FluxCalculatorFile)) - spec = importlib.util.spec_from_file_location("FluxCalculator", FluxCalculatorFile) - FluxCalculator = importlib.util.module_from_spec(spec) - sys.modules["FluxCalculator"] = FluxCalculator - spec.loader.exec_module(FluxCalculator) - flux_file = FluxCalculator.MakeFluxFile(tag,abs_flux_dir) - del sys.modules["FluxCalculator"] # remove flux directory from the system - return flux_file \ No newline at end of file + + +def load_flux(model_name, *args, **kwargs): + abs_flux_dir = get_flux_model_path(model_name, must_exist=True) + + # require existence of flux.py + flux_file = os.path.join(abs_flux_dir, "flux.py") + assert(os.path.isfile(flux_file)) + spec = importlib.util.spec_from_file_location("flux", flux_file) + flux = importlib.util.module_from_spec(spec) + module_name = f"siren-flux-{model_name}-{str(uuid.uuid4())}" + sys.modules[module_name] = flux + spec.loader.exec_module(flux) + flux_file = flux.load_flux(*args, **kwargs) + del sys.modules[module_name] # remove flux directory from the system + return flux_file diff --git a/resources/Examples/Example1/DIS_ATLAS.py b/resources/Examples/Example1/DIS_ATLAS.py index fcbe7a7b3..a64e06791 100644 --- a/resources/Examples/Example1/DIS_ATLAS.py +++ b/resources/Examples/Example1/DIS_ATLAS.py @@ -38,9 +38,10 @@ # energy distribution # HE SN flux from ATLAS paper -flux_file = siren.utilities.get_tabulated_flux_file("HE_SN","numu") -edist = siren.distributions.TabulatedFluxDistribution(100, 1e6, flux_file, True) #bool is whether flux is physical -primary_injection_distributions["energy"] = edist +edist = siren.utilities.load_flux("HE_SN", tag="numu", min_energy=100, max_energy=1e6, physically_normalized=True) +edist_gen = siren.utilities.load_flux("HE_SN", tag="numu", min_energy=100, max_energy=1e6, physically_normalized=False) + +primary_injection_distributions["energy"] = edist_gen primary_physical_distributions["energy"] = edist # direction distribution diff --git a/resources/Examples/Example2/DipolePortal_MINERvA.py b/resources/Examples/Example2/DipolePortal_MINERvA.py index 536508af8..6a33862a7 100644 --- a/resources/Examples/Example2/DipolePortal_MINERvA.py +++ b/resources/Examples/Example2/DipolePortal_MINERvA.py @@ -41,11 +41,8 @@ primary_physical_distributions = {} # energy distribution -flux_file = siren.utilities.get_tabulated_flux_file("NUMI","FHC_ME_numu") -edist = siren.distributions.TabulatedFluxDistribution(flux_file, True) -edist_gen = siren.distributions.TabulatedFluxDistribution( - model_kwargs["m4"], 20, flux_file, False -) +edist = siren.utilities.load_flux("NUMI", tag="FHC_ME_numu", physically_normalized=True) +edist_gen = siren.utilities.load_flux("NUMI", tag="FHC_ME_numu", min_energy=model_kwargs["m4"], max_energy=20, physically_normalized=False) primary_injection_distributions["energy"] = edist_gen primary_physical_distributions["energy"] = edist diff --git a/resources/Examples/Example2/DipolePortal_MiniBooNE.py b/resources/Examples/Example2/DipolePortal_MiniBooNE.py index 7fd7c62cd..05d022530 100644 --- a/resources/Examples/Example2/DipolePortal_MiniBooNE.py +++ b/resources/Examples/Example2/DipolePortal_MiniBooNE.py @@ -41,11 +41,8 @@ primary_physical_distributions = {} # energy distribution -flux_file = siren.utilities.get_tabulated_flux_file("BNB","FHC_numu") -edist = siren.distributions.TabulatedFluxDistribution(flux_file, True) -edist_gen = siren.distributions.TabulatedFluxDistribution( - model_kwargs["m4"], 10, flux_file, False -) +edist = siren.utilities.load_flux("BNB", tag="FHC_numu", physically_normalized=True) +edist_gen = siren.utilities.load_flux("BNB", tag="FHC_numu", min_energy=model_kwargs["m4"], max_energy=10, physically_normalized=False) primary_injection_distributions["energy"] = edist_gen primary_physical_distributions["energy"] = edist diff --git a/resources/Fluxes/BNB/BNB-v1.0/FluxCalculator.py b/resources/Fluxes/BNB/BNB-v1.0/FluxCalculator.py deleted file mode 100644 index d93221ad0..000000000 --- a/resources/Fluxes/BNB/BNB-v1.0/FluxCalculator.py +++ /dev/null @@ -1,29 +0,0 @@ -import os -def MakeFluxFile(tag, abs_flux_dir): - ''' - Accepts the following tags: - {FHC,RHC}_{nue,nuebar,numu,numubar} - ''' - mode,particle = tag.split("_") - if mode not in ["FHC","RHC"]: - print("%s beam mode specified in tag %s is not valid"%(mode,tag)) - exit(0) - if particle not in ["nue","numu","nuebar","numubar"]: - print("%s particle specified in tag %s is not valid"%(particle,tag)) - exit(0) - input_flux_file = os.path.join(abs_flux_dir, - "BNB_%s.dat"%mode) - output_flux_file = os.path.join(abs_flux_dir, - "BNB_%s_%s_flux.txt"%(mode,particle)) - with open(input_flux_file,"r") as fin: - all_lines = fin.readlines() - headers = all_lines[0].strip().split() - data = [line.strip().split() for line in all_lines[1:]] - pid = headers.index(particle) - with open(output_flux_file,"w") as fout: - for row in data: - Elow,Ehigh,bin_flux = float(row[0]),float(row[1]),float(row[pid]) - Emid = (Elow+Ehigh)/2. - flux = bin_flux/50*1000*1e4 # put flux in units of nu/m^2/GeV/POT - print(Emid,flux,file=fout) - return output_flux_file \ No newline at end of file diff --git a/resources/Fluxes/BNB/BNB-v1.0/flux.py b/resources/Fluxes/BNB/BNB-v1.0/flux.py new file mode 100644 index 000000000..0d6be7571 --- /dev/null +++ b/resources/Fluxes/BNB/BNB-v1.0/flux.py @@ -0,0 +1,47 @@ +import os +import siren + + +def load_flux(tag=None, min_energy=None, max_energy=None, physically_normalized=True): + """ + Accepts the following tags: + {FHC,RHC}_{nue,nuebar,numu,numubar} + """ + + if tag is None: + raise TypeError("\"tag\" is a required argument") + try: + tag = str(tag) + except: + raise RuntimeError("\"tag\" must convert to a str") + if min_energy is None != max_energy is None: + raise RuntimeError("Neither or both \"min_energy\" and \"max_energy\" must be provided") + has_energy_range = min_energy is not None + + mode, particle = tag.split("_") + if mode not in ["FHC", "RHC"]: + raise ValueError("%s beam mode specified in tag %s is not valid" % (mode, tag)) + if particle not in ["nue", "numu", "nuebar", "numubar"]: + raise ValueError("%s particle specified in tag %s is not valid" % (particle, tag)) + + abs_flux_dir = os.path.dirname(__file__) + input_flux_file = os.path.join(abs_flux_dir, "BNB_%s.dat" % mode) + + all_lines = open(input_flux_file, "r").readlines() + headers = all_lines[0].strip().split() + data = [line.strip().split() for line in all_lines[1:]] + pid = headers.index(particle) + e_low_idx = 0 + e_high_idx = 1 + + energies = [(float(row[e_low_idx]) + float(row[e_high_idx]))/2.0 for row in data] + flux = [float(row[pid]) / 50 * 1000 * 1e4 for row in data] # put flux in units of nu/m^2/GeV/POT + + table = None + if has_energy_range: + table = siren.distributions.TabulatedFluxDistribution(min_energy, max_energy, energies, flux, physically_normalized) + else: + table = siren.distributions.TabulatedFluxDistribution(energies, flux, physically_normalized) + + return table + diff --git a/resources/Fluxes/HE_SN/HE_SN-v1.0/FluxCalculator.py b/resources/Fluxes/HE_SN/HE_SN-v1.0/FluxCalculator.py deleted file mode 100644 index 80fbc49de..000000000 --- a/resources/Fluxes/HE_SN/HE_SN-v1.0/FluxCalculator.py +++ /dev/null @@ -1,22 +0,0 @@ -import os - -def MakeFluxFile(tag, abs_flux_dir): - ''' - only supported tag is "numu" - ''' - if tag!="numu": - print("Tag %s not supported for HE SN"%tag) - exit(0) - input_flux_file = os.path.join(abs_flux_dir, - "dN_dE_SNe_2n_D1_0_s20_t100d_NuMu_d10kpc.txt") - output_flux_file = os.path.join(abs_flux_dir, - "HE_SN_numu.txt") - with open(input_flux_file,"r") as fin: - all_lines = fin.readlines() - data = [line.strip().split() for line in all_lines] - with open(output_flux_file,"w") as fout: - for row in data: - E,flux = float(row[0]),float(row[1]) - flux*=1e4 # put flux in units of nu/m^2/GeV/100d - print(E,flux,file=fout) - return output_flux_file \ No newline at end of file diff --git a/resources/Fluxes/HE_SN/HE_SN-v1.0/flux.py b/resources/Fluxes/HE_SN/HE_SN-v1.0/flux.py new file mode 100644 index 000000000..0440f99f6 --- /dev/null +++ b/resources/Fluxes/HE_SN/HE_SN-v1.0/flux.py @@ -0,0 +1,33 @@ +import os +import siren + +def load_flux(tag=None, min_energy=None, max_energy=None, physically_normalized=True): + ''' + only supported tag is "numu" + ''' + if tag!="numu": + raise ValueError("Tag %s not supported for HE SN" % tag) + + has_energy_range = min_energy is not None + + abs_flux_dir = os.path.dirname(__file__) + input_flux_file = os.path.join(abs_flux_dir, + "dN_dE_SNe_2n_D1_0_s20_t100d_NuMu_d10kpc.txt") + + all_lines = open(input_flux_file, "r").readlines() + headers = all_lines[0].strip().split() + data = [line.strip().split() for line in all_lines[1:]] + e_idx = 0 + flux_idx = 1 + + energies = [float(row[e_idx]) for row in data] + flux = [float(row[flux_idx]) * 1e4 for row in data] # put flux in units of nu/m^2/GeV/100d + + table = None + if has_energy_range: + table = siren.distributions.TabulatedFluxDistribution(min_energy, max_energy, energies, flux, physically_normalized) + else: + table = siren.distributions.TabulatedFluxDistribution(energies, flux, physically_normalized) + + return table + diff --git a/resources/Fluxes/NUMI/NUMI-v1.0/FluxCalculator.py b/resources/Fluxes/NUMI/NUMI-v1.0/FluxCalculator.py deleted file mode 100644 index de7b13b0f..000000000 --- a/resources/Fluxes/NUMI/NUMI-v1.0/FluxCalculator.py +++ /dev/null @@ -1,31 +0,0 @@ -import os -def MakeFluxFile(tag, abs_flux_dir): - ''' - Accepts the following tags: - {FHC,RHC}_{LE,ME}_{nue,nuebar,numu,numubar} - ''' - mode,energy,particle = tag.split("_") - if mode not in ["FHC","RHC"]: - print("%s beam mode specified in tag %s is not valid"%(mode,tag)) - exit(0) - if energy not in ["LE","ME"]: - print("%s energy mode specified in tag %s is not valid"%(energy,tag)) - exit(0) - if particle not in ["nue","numu","nuebar","numubar"]: - print("%s particle specified in tag %s is not valid"%(particle,tag)) - exit(0) - input_flux_file = os.path.join(abs_flux_dir, - "NUMI_%s_%s.dat"%(mode,energy)) - output_flux_file = os.path.join(abs_flux_dir, - "NUMI_%s_%s_%s_flux.txt"%(mode,energy,particle)) - with open(input_flux_file,"r") as fin: - all_lines = fin.readlines() - headers = all_lines[0].strip().split() - data = [line.strip().split() for line in all_lines[1:]] - pid = headers.index(particle) - with open(output_flux_file,"w") as fout: - for row in data: - E,flux = float(row[0]),float(row[pid]) - flux*=1e4 # put flux in units of nu/m^2/GeV/POT - print(E,flux,file=fout) - return output_flux_file \ No newline at end of file diff --git a/resources/Fluxes/NUMI/NUMI-v1.0/flux.py b/resources/Fluxes/NUMI/NUMI-v1.0/flux.py new file mode 100644 index 000000000..ca54fc77f --- /dev/null +++ b/resources/Fluxes/NUMI/NUMI-v1.0/flux.py @@ -0,0 +1,48 @@ +import os +import siren + + +def load_flux(tag=None, min_energy=None, max_energy=None, physically_normalized=True): + ''' + Accepts the following tags: + {FHC,RHC}_{LE,ME}_{nue,nuebar,numu,numubar} + ''' + + if tag is None: + raise TypeError("\"tag\" is a required argument") + try: + tag = str(tag) + except: + raise RuntimeError("\"tag\" must convert to a str") + if min_energy is None != max_energy is None: + raise RuntimeError("Neither or both \"min_energy\" and \"max_energy\" must be provided") + has_energy_range = min_energy is not None + + mode, energy, particle = tag.split("_") + if mode not in ["FHC","RHC"]: + raise ValueError("%s beam mode specified in tag %s is not valid"%(mode,tag)) + if energy not in ["LE","ME"]: + raise ValueError("%s energy mode specified in tag %s is not valid"%(energy,tag)) + if particle not in ["nue","numu","nuebar","numubar"]: + raise ValueError("%s particle specified in tag %s is not valid"%(particle,tag)) + + abs_flux_dir = os.path.dirname(__file__) + input_flux_file = os.path.join(abs_flux_dir, + "NUMI_%s_%s.dat" % (mode, energy)) + + all_lines = open(input_flux_file, "r").readlines() + headers = all_lines[0].strip().split() + data = [line.strip().split() for line in all_lines[1:]] + pid = headers.index(particle) + e_idx = 0 + + energies = [float(row[e_idx]) for row in data] + flux = [float(row[pid]) * 1e4 for row in data] # put flux in units of nu/m^2/GeV/POT + + table = None + if has_energy_range: + table = siren.distributions.TabulatedFluxDistribution(min_energy, max_energy, energies, flux, physically_normalized) + else: + table = siren.distributions.TabulatedFluxDistribution(energies, flux, physically_normalized) + + return table From fa04cb273e6a214a20231040d899a41f6ce8d72e Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 5 Jun 2024 04:01:37 -0500 Subject: [PATCH 02/94] __repr__ and __str__ for InteractionSignature --- .../private/pybindings/dataclasses.cxx | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/projects/dataclasses/private/pybindings/dataclasses.cxx b/projects/dataclasses/private/pybindings/dataclasses.cxx index a3a74f06f..e328b280f 100644 --- a/projects/dataclasses/private/pybindings/dataclasses.cxx +++ b/projects/dataclasses/private/pybindings/dataclasses.cxx @@ -33,17 +33,32 @@ PYBIND11_MODULE(dataclasses,m) { .def_readwrite("helicity",&Particle::helicity) .def("GenerateID",&Particle::GenerateID); - enum_(particle, "ParticleType", arithmetic()) + enum_(particle, "ParticleType", arithmetic()) #define X(a, b) .value( #a , ParticleType:: a ) #include "../../public/SIREN/dataclasses/ParticleTypes.def" #undef X - .export_values(); - - class_>(m, "InteractionSignature") - .def(init<>()) - .def_readwrite("primary_type",&InteractionSignature::primary_type) - .def_readwrite("target_type",&InteractionSignature::target_type) - .def_readwrite("secondary_types",&InteractionSignature::secondary_types); + .export_values(); + + class_>(m, "InteractionSignature") + .def(init<>()) + .def("__str__", [](InteractionSignature const & p) { std::stringstream ss; ss << p; return ss.str(); }) + .def("__repr__", [](InteractionSignature const & s) { + std::stringstream ss; + ss << "InteractionSignature( "; + ss << s.primary_type << " "; + if(s.primary_type == ParticleType::unknown or s.target_type != ParticleType::unknown) { + ss << s.target_type << " "; + } + ss << "-> "; + for(auto const & secondary : s.secondary_types) { + ss << secondary << " "; + } + ss << ")"; + return ss.str(); + }) + .def_readwrite("primary_type",&InteractionSignature::primary_type) + .def_readwrite("target_type",&InteractionSignature::target_type) + .def_readwrite("secondary_types",&InteractionSignature::secondary_types); class_>(m, "PrimaryDistributionRecord") .def(init()) From 322d98798ffa0a48a86be33b625091157a3ff102 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 5 Jun 2024 04:02:03 -0500 Subject: [PATCH 03/94] Whitespace --- python/SIREN_DarkNews.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/python/SIREN_DarkNews.py b/python/SIREN_DarkNews.py index 212366c53..b5c4fb2f5 100644 --- a/python/SIREN_DarkNews.py +++ b/python/SIREN_DarkNews.py @@ -100,9 +100,6 @@ def __init__( self.GenerateCrossSections(use_pickles=use_pickles,**xs_kwargs) self.GenerateDecays(use_pickles=use_pickles) - - - def GenerateCrossSections(self, use_pickles, **kwargs): # Save all unique scattering processes self.cross_sections = [] From 8b5bbcd6d651ceea257a1490939c6c3ac9273b56 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 5 Jun 2024 04:02:43 -0500 Subject: [PATCH 04/94] load_module function --- python/_util.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/python/_util.py b/python/_util.py index 2e3b087f7..5d4dff1ac 100644 --- a/python/_util.py +++ b/python/_util.py @@ -2,6 +2,7 @@ import re import sys import uuid +import pathlib import importlib THIS_DIR = os.path.abspath(os.path.dirname(__file__)) @@ -169,6 +170,22 @@ def has_module(module_name): return True +def load_module(name, path, persist=True): + """Load a module with a specific name and path""" + url = pathlib.Path(os.path.abspath(path)).as_uri() + module_name = f"{name}-{str(uuid.uuid5(uuid.NAMESPACE_URL, url))}" + if module_name in sys.modules: + return module + spec = importlib.util.spec_from_file_location(name, path) + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module + spec.loader.exec_module(module_name) + module = sys.modules[module_name] + if not persist: + del sys.modules[module_name] + return module + + _VERSION_PATTERN = r""" v? (?: @@ -556,3 +573,4 @@ def load_flux(model_name, *args, **kwargs): flux_file = flux.load_flux(*args, **kwargs) del sys.modules[module_name] # remove flux directory from the system return flux_file + From ad97eef0f672e9f50c3030c4688cfdfa12cc7618 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 5 Jun 2024 10:19:48 -0500 Subject: [PATCH 05/94] Sketch loading logic for DarkNews --- .../DarkNewsTables/DarkNewsCrossSection.py | 503 ++++++++++++++++++ .../DarkNewsTables/DarkNewsDecay.py | 320 +++++++++++ .../CrossSections/DarkNewsTables/logger.py | 11 + .../CrossSections/DarkNewsTables/processes.py | 342 ++++++++++++ 4 files changed, 1176 insertions(+) create mode 100644 resources/CrossSections/DarkNewsTables/DarkNewsCrossSection.py create mode 100644 resources/CrossSections/DarkNewsTables/DarkNewsDecay.py create mode 100644 resources/CrossSections/DarkNewsTables/logger.py create mode 100644 resources/CrossSections/DarkNewsTables/processes.py diff --git a/resources/CrossSections/DarkNewsTables/DarkNewsCrossSection.py b/resources/CrossSections/DarkNewsTables/DarkNewsCrossSection.py new file mode 100644 index 000000000..688da76ad --- /dev/null +++ b/resources/CrossSections/DarkNewsTables/DarkNewsCrossSection.py @@ -0,0 +1,503 @@ +import os +import numpy as np +import functools +from scipy.interpolate import LinearNDInterpolator, PchipInterpolator + +base_path = os.path.dirname(os.path.abspath(__file__)) +loader_file = os.path.join(base_path, "loader.py") +siren._util.load_module("loader", loader_file) + +# SIREN methods +from siren.interactions import DarkNewsCrossSection +from siren import dataclasses +from siren.dataclasses import Particle + +# DarkNews methods +from DarkNews import phase_space + +# A class representing a single ups_case DarkNews class +# Only handles methods concerning the upscattering part +class PyDarkNewsCrossSection(DarkNewsCrossSection): + def __init__( + self, + ups_case, # DarkNews UpscatteringProcess instance + tolerance=1e-6, # supposed to represent machine epsilon + interp_tolerance=5e-2, # relative interpolation tolerance + always_interpolate=True, # bool whether to always interpolate the total/differential cross section + ): + DarkNewsCrossSection.__init__(self) # C++ constructor + + self.ups_case = ups_case + self.tolerance = tolerance + self.interp_tolerance = interp_tolerance + self.always_interpolate = always_interpolate + + # 2D table in E, sigma + self.total_cross_section_table = np.empty((0, 2), dtype=float) + # 3D table in E, z, dsigma/dQ2 where z = (Q2 - Q2min) / (Q2max - Q2min) + self.differential_cross_section_table = np.empty((0, 3), dtype=float) + + def load_from_table(self, table_dir): + # Make the table directory where will we store cross section tables + table_dir_exists = False + if os.path.exists(table_dir): + # print("Directory '%s' already exists"%table_dir) + table_dir_exists = True + else: + try: + os.makedirs(table_dir, exist_ok=False) + # print("Directory '%s' created successfully" % table_dir) + except OSError as error: + raise RuntimeError("Directory '%s' cannot be created" % table_dir) + + # Look in table dir and check whether total/differential xsec tables exist + if table_dir_exists: + total_xsec_file = os.path.join(table_dir, "total_cross_sections.npy") + if os.path.exists(total_xsec_file): + self.total_cross_section_table = np.load(total_xsec_file) + diff_xsec_file = os.path.join( + table_dir, "differential_cross_sections.npy" + ) + if os.path.exists(diff_xsec_file): + self.differential_cross_section_table = np.load(diff_xsec_file) + + self.configure() + + + # serialization method + def get_representation(self): + return { + "total_cross_section_table": self.total_cross_section_table, + "differential_cross_section_table": self.differential_cross_section_table, + "ups_case": self.ups_case, + "tolerance": self.tolerance, + "interp_tolerance": self.interp_tolerance, + "always_interpolate": self.always_interpolate, + "is_configured": False, + } + + # Configure function to set up member variables + # assumes we have defined the following: + # ups_case, total_cross_section_table, differential_cross_section_table, + # tolerance, interp_tolerance, always_interpolate + # kwargs argument can be used to set any of these + def configure(self, **kwargs): + + for k, v in kwargs.items(): + self.__setattr__(k, v) + + # Define the target particle + # make sure protons are stored as H nuclei + self.target_type = Particle.ParticleType(self.ups_case.nuclear_target.pdgid) + if self.target_type == Particle.ParticleType.PPlus: + self.target_type = Particle.ParticleType.HNucleus + + # Initialize interpolation objects + self.total_cross_section_interpolator = None + self.differential_cross_section_interpolator = None + self._redefine_interpolation_objects(total=True, diff=True) + self.is_configured = True + + # Sorts and redefines scipy interpolation objects + def _redefine_interpolation_objects(self, total=False, diff=False): + if total: + if len(self.total_cross_section_table) <= 1: + return + idxs = np.argsort(self.total_cross_section_table[:, 0]) + self.total_cross_section_table = self.total_cross_section_table[idxs] + self.total_cross_section_interpolator = PchipInterpolator( + self.total_cross_section_table[:, 0], + self.total_cross_section_table[:, 1], + ) + if diff: + if len(self.differential_cross_section_table) <= 1: + return + idxs = np.lexsort( + ( + self.differential_cross_section_table[:, 1], + self.differential_cross_section_table[:, 0], + ) + ) + self.differential_cross_section_table = ( + self.differential_cross_section_table[idxs] + ) + # If we only have two energy points, don't try to construct interpolator + if len(np.unique(self.differential_cross_section_table[:, 0])) <= 2: + return + self.differential_cross_section_interpolator = LinearNDInterpolator( + self.differential_cross_section_table[:, :2], + self.differential_cross_section_table[:, 2], + rescale=True, + ) + + # Check whether we have close-enough entries in the intrepolation tables + def _interpolation_flags(self, inputs, mode): + # + # returns UseSinglePoint,Interpolate,closest_idx + # UseSinglePoint: whether to use a single point in table + # Interpolate: whether to interpolate bewteen different points + # closest_idx: index of closest point in table (for UseSinglePoint) + + # Determine which table we are using + if mode == "total": + interp_table = self.total_cross_section_table + elif mode == "differential": + interp_table = self.differential_cross_section_table + else: + print("Invalid interpolation table mode %s" % mode) + exit(0) + + # first check if we have saved table points already + if len(interp_table) == 0: + return False, False, -1 + + # bools to keep track of whether to use a single point or interpolate + UseSinglePoint = False + Interpolate = True + # order events by the relative difference + rel_diff = np.abs((interp_table[:, :-1] - inputs) / inputs) + rel_diff_length = np.sqrt(np.sum(rel_diff**2, axis=-1)) + closest_idx_abs = np.argmin(rel_diff_length, axis=-1) + # First check whether we have a close-enough single point + if np.all(np.abs(rel_diff[closest_idx_abs]) < self.tolerance): + UseSinglePoint = True + # Ensure we have enough points to interpolate + if len(interp_table) < len(inputs) + 1: + Interpolate = False + # Require that we have at least len(inputs)+1 close points to interpolate + else: + close = np.all(rel_diff < self.interp_tolerance, axis=-1) + if sum(close) < len(inputs) + 1: + Interpolate = False + return UseSinglePoint, Interpolate, closest_idx_abs + + # return entries in interpolation table if we have inputs + def _query_interpolation_table(self, inputs, mode): + # + # returns: + # 0 if we are not close enough to any points in the interpolation table + # otherwise, returns the desired interpolated value + + # First make sure we are configured + self._ensure_configured() + + # Determine which table we are using + if mode == "total": + interp_table = self.total_cross_section_table + interpolator = self.total_cross_section_interpolator + elif mode == "differential": + interp_table = self.differential_cross_section_table + interpolator = self.differential_cross_section_interpolator + else: + print("Invalid interpolation table mode %s" % mode) + exit(0) + + if self.always_interpolate: + # check if energy is within table range + + if interpolator is None or inputs[0] > interp_table[-1, 0]: + print( + "Requested interpolation at %2.2f GeV. Either this is above the table boundary or the interpolator doesn't yet exist. Filling %s table" + % (inputs[0], mode) + ) + n = self.FillInterpolationTables( + total=(mode == "total"), + diff=(mode == "differential"), + Emax=(1 + self.interp_tolerance) * inputs[0], + ) + print("Added %d points" % n) + if mode == "total": + interpolator = self.total_cross_section_interpolator + elif mode == "differential": + interpolator = self.differential_cross_section_interpolator + elif inputs[0] < interp_table[0, 0]: + print( + "Requested interpolation at %2.2f GeV below table boundary. Requring calculation" + % inputs[0] + ) + return 0 + val = max(0, interpolator(inputs)) + if val < 0: + print( + "WARNING: negative interpolated value for %s-%s %s cross section at," + % ( + self.ups_case.nuclear_target.name, + self.ups_case.scattering_regime, + mode, + ), + inputs, + ) + return val + + UseSinglePoint, Interpolate, closest_idx = self._interpolation_flags( + inputs, mode + ) + + if UseSinglePoint: + if closest_idx < 0: + print( + "Trying to use a single table point, but no closest idx found. Exiting..." + ) + exit(0) + return interp_table[closest_idx, -1] + elif Interpolate: + return interpolator(inputs) + else: + return -1 + + def FillTableAtEnergy(self, E, total=True, diff=True, factor=0.8): + num_added_points = 0 + if total: + xsec = self.ups_case.total_xsec(E) + self.total_cross_section_table = np.append( + self.total_cross_section_table, [[E, xsec]], axis=0 + ) + num_added_points += 1 + if diff: + interaction = dataclasses.InteractionRecord() + interaction.signature.primary_type = self.GetPossiblePrimaries()[ + 0 + ] # only one primary + interaction.signature.target_type = self.GetPossibleTargets()[ + 0 + ] # only one target + interaction.target_mass = self.ups_case.MA + interaction.primary_momentum = [E, 0, 0, 0] + zmin, zmax = self.tolerance, 1 + Q2min = self.Q2Min(interaction) + Q2max = self.Q2Max(interaction) + z = zmin + while z < zmax: + Q2 = Q2min + z * (Q2max - Q2min) + dxsec = self.ups_case.diff_xsec_Q2(E, Q2).item() + self.differential_cross_section_table = np.append( + self.differential_cross_section_table, + [[E, z, dxsec]], + axis=0, + ) + num_added_points += 1 + z *= 1 + factor * self.interp_tolerance + self._redefine_interpolation_objects(total=total, diff=diff) + return num_added_points + + # Fills the total and differential cross section tables within interp_tolerance + def FillInterpolationTables(self, total=True, diff=True, factor=0.8, Emax=None): + increment_factor = 0.5 * factor * self.interp_tolerance + Emin = (1.0 + self.tolerance) * self.ups_case.Ethreshold + if Emax is None: + if ( + len(self.total_cross_section_table) + + len(self.differential_cross_section_table) + ) <= 0: + return 0 + Emax = max( + np.max([0] + list(self.total_cross_section_table[:, 0])), + np.max([0] + list(self.differential_cross_section_table[:, 0])), + ) + num_added_points = 0 + E = Emin + E_existing_total = np.unique(self.total_cross_section_table[:, 0]) + E_existing_diff = np.unique(self.differential_cross_section_table[:, 0]) + while E < Emax: + # sample more coarsely past 1.5*threshold + if E > 1.5 * self.ups_case.Ethreshold: + increment_factor = factor * self.interp_tolerance + n = self.FillTableAtEnergy( + E, + total=(total and (E not in E_existing_total)), + diff=(diff and (E not in E_existing_diff)), + factor=factor, + ) + num_added_points += n + E *= 1 + increment_factor + self._redefine_interpolation_objects(total=total, diff=diff) + return num_added_points + + # Saves the tables for the scipy interpolation objects + def SaveInterpolationTables(self, table_dir, total=True, diff=True): + if total: + self._redefine_interpolation_objects(total=True) + with open( + os.path.join(table_dir, "total_cross_sections.npy"), "wb" + ) as f: + np.save(f, self.total_cross_section_table) + if diff: + self._redefine_interpolation_objects(diff=True) + with open( + os.path.join(table_dir, "differential_cross_sections.npy"), "wb" + ) as f: + np.save(f, self.differential_cross_section_table) + + def GetPossiblePrimaries(self): + return [Particle.ParticleType(self.ups_case.nu_projectile.pdgid)] + + def _ensure_configured(self): + if not self.is_configured: + self.configure() + + def GetPossibleTargetsFromPrimary(self, primary_type): + self._ensure_configured() + if Particle.ParticleType(self.ups_case.nu_projectile.pdgid) == primary_type: + return [self.target_type] + return [] + + def GetPossibleTargets(self): + self._ensure_configured() + return [self.target_type] + + def GetPossibleSignatures(self): + self._ensure_configured() + signature = dataclasses.InteractionSignature() + signature.primary_type = Particle.ParticleType( + self.ups_case.nu_projectile.pdgid + ) + signature.target_type = self.target_type + signature.secondary_types = [] + signature.secondary_types.append( + Particle.ParticleType(self.ups_case.nu_upscattered.pdgid) + ) + signature.secondary_types.append(self.target_type) + return [signature] + + def GetPossibleSignaturesFromParents(self, primary_type, target_type): + if ( + Particle.ParticleType(self.ups_case.nu_projectile.pdgid) == primary_type + ) and ((self.target_type == target_type)): + signature = dataclasses.InteractionSignature() + signature.primary_type = Particle.ParticleType( + self.ups_case.nu_projectile.pdgid + ) + signature.target_type = self.target_type + secondary_types = [] + secondary_types.append( + Particle.ParticleType(self.ups_case.nu_upscattered.pdgid) + ) + secondary_types.append( + Particle.ParticleType(self.ups_case.nuclear_target.pdgid) + ) + signature.secondary_types = secondary_types + return [signature] + return [] + + def DifferentialCrossSection(self, arg1, target=None, energy=None, Q2=None): + if type(arg1) == dataclasses.InteractionRecord: + interaction = arg1 + # Calculate Q2 assuming we are in the target rest frame + m1sq = interaction.primary_momentum[0] ** 2 - np.sum( + [p**2 for p in interaction.primary_momentum[1:]] + ) + m3sq = interaction.secondary_momenta[0][0] ** 2 - np.sum( + [p**2 for p in interaction.secondary_momenta[0][1:]] + ) + p1p3 = interaction.primary_momentum[0] * interaction.secondary_momenta[0][ + 0 + ] - np.sum( + p1 * p3 + for p1, p3 in zip( + interaction.primary_momentum[1:], + interaction.secondary_momenta[0][1:], + ) + ) + Q2 = -(m1sq + m3sq - 2 * p1p3) + energy = interaction.primary_momentum[0] + else: + primary = arg1 + interaction = dataclasses.InteractionRecord() + interaction.signature.primary_type = primary + interaction.signature.target_type = target + interaction.primary_momentum = [energy, 0, 0, 0] + interaction.target_mass = self.ups_case.MA + if interaction.signature.primary_type != Particle.ParticleType( + self.ups_case.nu_projectile.pdgid + ): + return 0 + if interaction.primary_momentum[0] < self.InteractionThreshold(interaction): + return 0 + Q2min = self.Q2Min(interaction) + Q2max = self.Q2Max(interaction) + if Q2 < Q2min or Q2 > Q2max: + return 0 + z = (Q2 - Q2min) / (Q2max - Q2min) + + if self.always_interpolate: + # Check if we can interpolate + val = self._query_interpolation_table([energy, z], mode="differential") + if val >= 0: + # we have recovered the differential cross section from the interpolation table + return val + + # If we have reached this block, we must compute the differential cross section using DarkNews + dxsec = self.ups_case.diff_xsec_Q2(energy, Q2).item() + return dxsec + + def TargetMass(self, target_type): + target_mass = self.ups_case.MA + return target_mass + + def SecondaryMasses(self, secondary_types): + secondary_masses = [] + secondary_masses.append(self.ups_case.m_ups) + secondary_masses.append(self.ups_case.MA) + return secondary_masses + + def SecondaryHelicities(self, record): + secondary_helicities = [] + secondary_helicities.append( + self.ups_case.h_upscattered * record.primary_helicity + ) + secondary_helicities.append(record.target_helicity) + self.h_ups = self.ups_case.m_ups + self.h_target = self.ups_case.MA + return secondary_helicities + + def TotalCrossSection(self, arg1, energy=None, target=None): + # Handle overloaded arguments + if type(arg1) == dataclasses.InteractionRecord: + primary = arg1.signature.primary_type + energy = arg1.primary_momentum[0] + target = arg1.signature.target_type + elif energy is not None and target is not None: + primary = arg1 + else: + print("Incorrect function call to TotalCrossSection!") + exit(0) + if int(primary) != self.ups_case.nu_projectile: + return 0 + interaction = dataclasses.InteractionRecord() + interaction.signature.primary_type = primary + interaction.signature.target_type = target + interaction.primary_momentum[0] = energy + if energy < self.InteractionThreshold(interaction): + # print("Python: energy %2.2f < self.InteractionThreshold(interaction) %2.2f"%(energy,self.InteractionThreshold(interaction))) + return 0 + + # Check if we can interpolate + val = self._query_interpolation_table([energy], mode="total") + if val >= 0: + # we have recovered the cross section from the interpolation table + return val + + # If we have reached this block, we must compute the cross section using DarkNews + xsec = self.ups_case.total_xsec(energy) + self.total_cross_section_table = np.append( + self.total_cross_section_table, [[energy, xsec]], axis=0 + ) + self._redefine_interpolation_objects(total=True) + return xsec + + def InteractionThreshold(self, interaction): + return self.ups_case.Ethreshold + + def Q2Min(self, interaction): + return phase_space.upscattering_Q2min( + interaction.primary_momentum[0], + self.ups_case.m_ups, + self.ups_case.MA, + ) + + def Q2Max(self, interaction): + return phase_space.upscattering_Q2max( + interaction.primary_momentum[0], + self.ups_case.m_ups, + self.ups_case.MA, + ) diff --git a/resources/CrossSections/DarkNewsTables/DarkNewsDecay.py b/resources/CrossSections/DarkNewsTables/DarkNewsDecay.py new file mode 100644 index 000000000..5a3b37125 --- /dev/null +++ b/resources/CrossSections/DarkNewsTables/DarkNewsDecay.py @@ -0,0 +1,320 @@ +import os +import numpy as np +import functools + +base_path = os.path.dirname(os.path.abspath(__file__)) +loader_file = os.path.join(base_path, "loader.py") +siren._util.load_module("loader", loader_file) + +# SIREN methods +from siren.interactions import DarkNewsDecay +from siren import dataclasses +from siren.dataclasses import Particle + +# A class representing a single decay_case DarkNews class +# Only handles methods concerning the decay part +class PyDarkNewsDecay(DarkNewsDecay): + def __init__(self, dec_case): + DarkNewsDecay.__init__(self) # C++ constructor + self.dec_case = dec_case + + # Some variables for storing the decay phase space integrator + self.decay_integrator = None + self.decay_norm = None + self.PS_samples = None + self.PS_weights = None + self.PS_weights_CDF = None + self.total_width = None + + def load_from_table(self, table_dir): + if table_dir is None: + print( + "No table_dir specified; will sample from new VEGAS integrator for each decay" + ) + print("WARNING: this will siginficantly slow down event generation") + return + + # Make the table directory where will we store cross section integrators + table_dir_exists = False + if os.path.exists(table_dir): + # print("Directory '%s' already exists"%table_dir) + table_dir_exists = True + else: + try: + os.makedirs(table_dir, exist_ok=False) + print("Directory '%s' created successfully" % table_dir) + except OSError as error: + print("Directory '%s' cannot be created" % table_dir) + exit(0) + + # Try to find the decay integrator + int_file = os.path.join(table_dir, "decay_integrator.pkl") + if os.path.isfile(int_file): + with open(int_file, "rb") as ifile: + self.decay_integrator = pickle.load(ifile) + # Try to find the normalization information + norm_file = os.path.join(table_dir, "decay_norm.json") + if os.path.isfile(norm_file): + with open( + norm_file, + ) as nfile: + self.decay_norm = json.load(nfile) + + + # serialization method + def get_representation(self): + return {"decay_integrator":self.decay_integrator, + "decay_norm":self.decay_norm, + "dec_case":self.dec_case, + "PS_samples":self.PS_samples, + "PS_weights":self.PS_weights, + "PS_weights_CDF":self.PS_weights_CDF, + "total_width":self.total_width, + } + + def SetIntegratorAndNorm(self, decay_norm, decay_integrator): + self.decay_norm = decay_norm + self.decay_integrator = decay_integrator + + def GetPossibleSignatures(self): + signature = dataclasses.InteractionSignature() + signature.primary_type = Particle.ParticleType(self.dec_case.nu_parent.pdgid) + signature.target_type = Particle.ParticleType.Decay + secondary_types = [] + secondary_types.append(Particle.ParticleType(self.dec_case.nu_daughter.pdgid)) + for secondary in self.dec_case.secondaries: + secondary_types.append(Particle.ParticleType(secondary.pdgid)) + signature.secondary_types = secondary_types + return [signature] + + def GetPossibleSignaturesFromParent(self, primary_type): + if Particle.ParticleType(self.dec_case.nu_parent.pdgid) == primary_type: + signature = dataclasses.InteractionSignature() + signature.primary_type = Particle.ParticleType( + self.dec_case.nu_parent.pdgid + ) + signature.target_type = Particle.ParticleType.Decay + secondary_types = [] + secondary_types.append( + Particle.ParticleType(self.dec_case.nu_daughter.pdgid) + ) + for secondary in self.dec_case.secondaries: + secondary_types.append(Particle.ParticleType(secondary.pdgid)) + signature.secondary_types = secondary_types + return [signature] + return [] + + def DifferentialDecayWidth(self, record): + # Momentum variables of HNL necessary for calculating decay phase space + PN = np.array(record.primary_momentum) + + if type(self.dec_case) == FermionSinglePhotonDecay: + gamma_idx = 0 + for secondary in record.signature.secondary_types: + if secondary == dataclasses.Particle.ParticleType.Gamma: + break + gamma_idx += 1 + if gamma_idx >= len(record.signature.secondary_types): + print("No gamma found in the list of secondaries!") + exit(0) + + Pgamma = np.array(record.secondary_momenta[gamma_idx]) + momenta = np.expand_dims(PN, 0), np.expand_dims(Pgamma, 0) + + elif type(self.dec_case) == FermionDileptonDecay: + lepminus_idx = -1 + lepplus_idx = -1 + nu_idx = -1 + for idx, secondary in enumerate(record.signature.secondary_types): + if secondary in [ + dataclasses.Particle.ParticleType.EMinus, + dataclasses.Particle.ParticleType.MuMinus, + dataclasses.Particle.ParticleType.TauMinus, + ]: + lepminus_idx = idx + elif secondary in [ + dataclasses.Particle.ParticleType.EPlus, + dataclasses.Particle.ParticleType.MuPlus, + dataclasses.Particle.ParticleType.TauPlus, + ]: + lepplus_idx = idx + else: + nu_idx = idx + if -1 in [lepminus_idx, lepplus_idx, nu_idx]: + print("Couldn't find two leptons and a neutrino in the final state!") + exit(0) + Pnu = np.array(record.secondary_momenta[nu_idx]) + Plepminus = np.array(record.secondary_momenta[lepminus_idx]) + Plepplus = np.array(record.secondary_momenta[lepplus_idx]) + momenta = ( + np.expand_dims(PN, 0), + np.expand_dims(Plepminus, 0), + np.expand_dims(Plepplus, 0), + np.expand_dims(Pnu, 0), + ) + else: + print("%s is not a valid decay class type!" % type(self.dec_case)) + exit(0) + return self.dec_case.differential_width(momenta) + + def TotalDecayWidth(self, arg1): + if type(arg1) == dataclasses.InteractionRecord: + primary = arg1.signature.primary_type + elif type(arg1) == dataclasses.Particle.ParticleType: + primary = arg1 + else: + print("Incorrect function call to TotalDecayWidth!") + exit(0) + if int(primary) != self.dec_case.nu_parent: + return 0 + if self.total_width is None: + # Need to set the total width + if type(self.dec_case) == FermionDileptonDecay and ( + self.dec_case.vector_off_shell and self.dec_case.scalar_off_shell + ): + # total width calculation requires evaluating an integral + if self.decay_integrator is None or self.decay_norm is None: + # We need to initialize a new VEGAS integrator in DarkNews + self.total_width, dec_norm, dec_integrator = self.dec_case.total_width( + return_norm=True, return_dec=True + ) + self.SetIntegratorAndNorm(dec_norm, dec_integrator) + else: + self.total_width = ( + self.decay_integrator["diff_decay_rate_0"].mean + * self.decay_norm["diff_decay_rate_0"] + ) + else: + self.total_width = self.dec_case.total_width() + return self.total_width + + def TotalDecayWidthForFinalState(self, record): + sig = self.GetPossibleSignatures()[0] + if ( + (record.signature.primary_type != sig.primary_type) + or (record.signature.target_type != sig.target_type) + or (len(record.signature.secondary_types) != len(sig.secondary_types)) + or ( + np.any( + [ + record.signature.secondary_types[i] != sig.secondary_types[i] + for i in range(len(sig.secondary_types)) + ] + ) + ) + ): + return 0 + ret = self.dec_case.total_width() + return ret + + def DensityVariables(self): + if type(self.dec_case) == FermionSinglePhotonDecay: + return "cost" + elif type(self.dec_case) == FermionDileptonDecay: + if self.dec_case.vector_on_shell and self.dec_case.scalar_on_shell: + print("Can't have both the scalar and vector on shell") + exit(0) + elif (self.dec_case.vector_on_shell and self.dec_case.scalar_off_shell) or ( + self.dec_case.vector_off_shell and self.dec_case.scalar_on_shell + ): + return "cost" + elif self.dec_case.vector_off_shell and self.dec_case.scalar_off_shell: + return "t,u,c3,phi34" + else: + print("%s is not a valid decay class type!" % type(self.dec_case)) + exit(0) + return "" + + def GetPSSample(self, random): + # Make the PS weight CDF if that hasn't been done + if self.PS_weights_CDF is None: + self.PS_weights_CDF = np.cumsum(self.PS_weights) + + # Random number to determine + x = random.Uniform(0, self.PS_weights_CDF[-1]) + + # find first instance of a CDF entry greater than x + PSidx = np.argmax(x - self.PS_weights_CDF <= 0) + return self.PS_samples[:, PSidx] + + def SampleRecordFromDarkNews(self, record, random): + # First, make sure we have PS samples and weights + if self.PS_samples is None or self.PS_weights is None: + # We need to generate new PS samples + if self.decay_integrator is None or self.decay_norm is None: + # We need to initialize a new VEGAS integrator in DarkNews + (self.PS_samples, PS_weights_dict), dec_norm, dec_integrator = self.dec_case.SamplePS( + return_norm=True, return_dec=True + ) + self.PS_weights = PS_weights_dict["diff_decay_rate_0"] + self.SetIntegratorAndNorm(dec_norm, dec_integrator) + else: + # We already have an integrator, we just need new PS samples + self.PS_samples, PS_weights_dict = self.dec_case.SamplePS( + existing_integrator=self.decay_integrator + ) + self.PS_weights = PS_weights_dict["diff_decay_rate_0"] + + # Now we must sample an PS point on the hypercube + PS = self.GetPSSample(random) + + # Find the four-momenta associated with this point + # Expand dims required to call DarkNews function on signle sample + four_momenta = get_decay_momenta_from_vegas_samples( + np.expand_dims(PS, 0), + self.dec_case, + np.expand_dims(np.array(record.primary_momentum), 0), + ) + + secondaries = record.GetSecondaryParticleRecords() + + if type(self.dec_case) == FermionSinglePhotonDecay: + gamma_idx = 0 + for secondary in record.signature.secondary_types: + if secondary == dataclasses.Particle.ParticleType.Gamma: + break + gamma_idx += 1 + if gamma_idx >= len(record.signature.secondary_types): + print("No gamma found in the list of secondaries!") + exit(0) + nu_idx = 1 - gamma_idx + secondaries[gamma_idx].four_momentum = np.squeeze(four_momenta["P_decay_photon"]) + secondaries[gamma_idx].mass = 0 + secondaries[nu_idx].four_momentum = np.squeeze(four_momenta["P_decay_N_daughter"]) + secondaries[nu_idx].mass = 0 + + elif type(self.dec_case) == FermionDileptonDecay: + lepminus_idx = -1 + lepplus_idx = -1 + nu_idx = -1 + for idx, secondary in enumerate(record.signature.secondary_types): + if secondary in [ + dataclasses.Particle.ParticleType.EMinus, + dataclasses.Particle.ParticleType.MuMinus, + dataclasses.Particle.ParticleType.TauMinus, + ]: + lepminus_idx = idx + elif secondary in [ + dataclasses.Particle.ParticleType.EPlus, + dataclasses.Particle.ParticleType.MuPlus, + dataclasses.Particle.ParticleType.TauPlus, + ]: + lepplus_idx = idx + else: + nu_idx = idx + if -1 in [lepminus_idx, lepplus_idx, nu_idx]: + print([lepminus_idx, lepplus_idx, nu_idx]) + print(record.signature.secondary_types) + print("Couldn't find two leptons and a neutrino in the final state!") + exit(0) + secondaries[lepminus_idx].four_momentum = ( + np.squeeze(four_momenta["P_decay_ell_minus"]) + ) + secondaries[lepplus_idx].four_momentum = ( + np.squeeze(four_momenta["P_decay_ell_plus"]) + ) + secondaries[nu_idx].four_momentum = ( + np.squeeze(four_momenta["P_decay_N_daughter"]) + ) + return record + diff --git a/resources/CrossSections/DarkNewsTables/logger.py b/resources/CrossSections/DarkNewsTables/logger.py new file mode 100644 index 000000000..e8ebef6f6 --- /dev/null +++ b/resources/CrossSections/DarkNewsTables/logger.py @@ -0,0 +1,11 @@ +# Monkey patch DarkNews logger to hide printouts + +from DarkNews.ModelContainer import ModelContainer +ModelContainer_configure_logger = ModelContainer.configure_logger + +@functools.wraps(ModelContainer.configure_logger) +def suppress_info(self, logger, loglevel="INFO", prettyprinter=None, logfile=None, verbose=False): + return ModelContainer_configure_logger(self, logger, loglevel="WARNING", prettyprinter=prettyprinter, logfile=logfile, verbose=verbose) + +ModelContainer.configure_logger = suppress_info + diff --git a/resources/CrossSections/DarkNewsTables/processes.py b/resources/CrossSections/DarkNewsTables/processes.py new file mode 100644 index 000000000..c26e0aad7 --- /dev/null +++ b/resources/CrossSections/DarkNewsTables/processes.py @@ -0,0 +1,342 @@ +import os +import siren + +base_path = os.path.dirname(os.path.abspath(__file__)) +loader_file = os.path.join(base_path, "loader.py") +siren._util.load_module("loader", loader_file) + +from DarkNews.ModelContainer import ModelContainer + +xs_path = siren.utilities.get_cross_section_model_path( + f"DarkNewsTables-v{siren.utilities.darknews_version()}", must_exist=False +) + +def GetDetectorModelTargets(detector_model): + """ + Determines the targets that exist inside the detector model + :return: lists of targets and strings + :rtype: (list, list) + """ + count = 0 + targets = [] + target_strs = [] + while detector_model.Materials.HasMaterial(count): + for target in detector_model.Materials.GetMaterialTargets(count): + if target not in targets: + targets.append(target) + if str(target).find("Nucleus") == -1: + continue + else: + target_str = str(target)[ + str(target).find("Type") + 5 : str(target).find("Nucleus") + ] + if target_str == "H": + target_str = "H1" + if target_str not in target_strs: + target_strs.append(target_str) + count += 1 + return targets, target_strs + + +def load_cross_section( + model_container, + upscattering_key, + tolerance=1e-6, + interp_tolerance=5e-2, + always_interpolate=True, +): + if upscattering_key not in model_container.ups_cases: + raise KeyError( + f'Upscattering key "{upscattering_key}" not present in model_container.ups_cases' + ) + upscattering_model = model_container.ups_cases[upscattering_key] + return PyDarkNewsCrossSection( + upscattering_model, + tolerance=tolerance, + interp_tolerance=interp_tolerance, + always_interpolate=always_interpolate, + ) + + +def load_cross_section_from_table( + model_container, + upscattering_key, + table_dir, + tolerance=1e-6, + interp_tolerance=5e-2, + always_interpolate=True, +): + subdir = "_".join(["CrossSection"] + [str(x) for x in upscattering_key]) + table_subdir = os.path.join(table_dir, subdir) + + cross_section = load_cross_section( + model_container, + upscattering_key, + tolerance=tolerance, + interp_tolerance=interp_tolerance, + always_interpolate=always_interpolate, + ) + cross_section.load_from_table(table_subdir) + return cross_section + + +def load_cross_section_from_pickle( + upscattering_key, + table_dir, + tolerance=1e-6, + interp_tolerance=5e-2, + always_interpolate=True, +): + subdir = "_".join(["CrossSection"] + [str(x) for x in upscattering_key]) + table_subdir = os.path.join(table_dir, subdir) + fname = os.path.join(table_dir, "xs_object.pkl") + with open(fname, "rb") as f: + xs_obj = pickle.load(f) + xs_obj.configure( + tolerance=tolerance, + interp_tolerance=interp_tolerance, + always_interpolate=always_interpolate, + ) + return xs_obj + + +def attempt_to_load_cross_section( + models, + ups_key, + tabel_dir, + preferences, +): + if len(preferences) == 0: + raise ValueError("preferences must have at least one entry") + + subdir = "_".join(["CrossSection"] + [str(x) for x in ups_key]) + loaded = False + cross_section = None + for p in preferences: + if p == "table": + table_subdir = os.path.join(table_dir, subdir) + if os.path.isdir(table_subdir): + try: + cross_section = append( + load_cross_section_from_table( + models, + ups_key, + table_subdir, + tolerance=tolerance, + interp_tolerance=interp_tolerance, + always_interpolate=always_interpolate, + ) + ) + loaded = True + except Exception as e: + print( + "Encountered exception while loading DN cross section from table" + ) + raise e from None + break + elif p == "pickle": + table_subdir = os.path.join(table_dir, subdir) + if os.path.isdir(table_subdir): + try: + cross_section = append( + load_cross_section_from_pickle( + ups_key, + table_subdir, + tolerance=tolerance, + interp_tolerance=interp_tolerance, + always_interpolate=always_interpolate, + ) + ) + loaded = True + except Exception as e: + print( + "Encountered exception while loading DN cross section from pickle" + ) + raise e from None + break + elif p == "normal": + try: + cross_sections = append( + load_cross_section( + models, + ups_key, + tolerance=tolerance, + interp_tolerance=interp_tolerance, + always_interpolate=always_interpolate, + ) + ) + loaded = True + except Exception as e: + print("Encountered exception while loading DN cross section normally") + raise e from None + break + + if not loaded: + raise RuntimeError("Not able to load DN cross section with any strategy") + return cross_section + + +def load_cross_sections( + model_kwargs, + table_dir=None, + tolerance=1e-6, + interp_tolerance=5e-2, + always_interpolate=True, + preferences=None, +): + if preferences is None: + preferences = ["table", "pickle", "normal"] + + models = ModelContainer(**model_kwargs) + + if table_dir is None: + table_dir = "" + + cross_sections = [] + for ups_key, ups_case in models.ups_cases.items(): + cross_sections.append( + attempt_to_load_cross_section(models, ups_key, table_dir, preferences) + ) + + return cross_sections + + +def load_processes( + primary_type=None, + target_types=None, + fill_tables_at_start=False, + Emax=None, + m4=None, + mu_tr_mu4=None, # GeV^-1 + UD4=0, + Umu4=0, + epsilon=0.0, + gD=0.0, + decay_product="photon", + noHC=True, + HNLtype="dirac", + nuclear_targets=None, + detector_model=None, + tolerance=1e-6, # supposed to represent machine epsilon + interp_tolerance=5e-2, # relative interpolation tolerance + always_interpolate=True, # bool whether to always interpolate the total/differential cross section +): + + if nuclear_targets is None and detector_model is None: + raise ValueError( + 'Either "nuclear_targets" or "detector_model" must be provided' + ) + + if nuclear_targets is None: + nuclear_targets = GetDetectorModelTargets(detector_model)[1] + + base_path = os.path.dirname(os.path.abspath(__file__)) + table_dir = os.path.join(base_path, "Dipole_M%2.2e_mu%2.2e" % (m4, mu_tr_mu4)) + + model_kwargs = { + "m4": m4, + "mu_tr_mu4": mu_tr_mu4, + "UD4": UD4, + "Umu4": Umu4, + "epsilon": epsilon, + "gD": gD, + "decay_product": decay_product, + "noHC": noHC, + } + + cross_sections = load_cross_sections( + model_kwargs, + table_dir=None, + tolerance=tolerance, + interp_tolerance=interp_tolerance, + always_interpolate=always_interpolate, + ) + + if fill_tables_at_start: + if Emax is None: + print( + "WARNING: Cannot fill cross section tables without specifying a maximum energy" + ) + else: + for cross_section in cross_sections: + cross_section.FillInterpolationTables(Emax=Emax) + + # Initialize primary InteractionCollection + # Loop over available cross sections and save those which match primary type + primary_cross_sections = [] + for cross_section in self.DN_processes.cross_sections: + if primary_type == _dataclasses.Particle.ParticleType( + cross_section.ups_case.nu_projectile.pdgid + ): + primary_cross_sections.append(cross_section) + primary_interaction_collection = _interactions.InteractionCollection( + primary_type, primary_cross_sections + ) + + # Initialize secondary processes and define secondary InteractionCollection objects + secondary_decays = {} + # Also keep track of the minimum decay width for defining the position distribution later + self.DN_min_decay_width = np.inf + # Loop over available decays, group by parent type + for decay in self.DN_processes.decays: + secondary_type = _dataclasses.Particle.ParticleType( + decay.dec_case.nu_parent.pdgid + ) + if secondary_type not in secondary_decays.keys(): + secondary_decays[secondary_type] = [] + secondary_decays[secondary_type].append(decay) + total_decay_width = decay.TotalDecayWidth(secondary_type) + if total_decay_width < self.DN_min_decay_width: + self.DN_min_decay_width = total_decay_width + # Now make the list of secondary cross section collections + # Add new secondary injection and physical processes at the same time + secondary_interaction_collections = [] + for secondary_type, decay_list in secondary_decays.items(): + # Define a sedcondary injection distribution + secondary_injection_process = _injection.SecondaryInjectionProcess() + secondary_physical_process = _injection.PhysicalProcess() + secondary_injection_process.primary_type = secondary_type + secondary_physical_process.primary_type = secondary_type + + # Add the secondary position distribution + if self.fid_vol is not None: + secondary_injection_process.AddSecondaryInjectionDistribution( + _distributions.SecondaryBoundedVertexDistribution(self.fid_vol) + ) + else: + secondary_injection_process.AddSecondaryInjectionDistribution( + _distributions.SecondaryPhysicalVertexDistribution() + ) + + self.secondary_injection_processes.append(secondary_injection_process) + self.secondary_physical_processes.append(secondary_physical_process) + + secondary_interaction_collections.append( + _interactions.InteractionCollection(secondary_type, decay_list) + ) + + self.SetInteractions( + primary_interaction_collection, secondary_interaction_collections + ) + + +def GetFiducialVolume(self): + """ + :return: identified fiducial volume for the experiment, None if not found + """ + detector_model_file = _util.get_detector_model_path(self.experiment) + with open(detector_model_file) as file: + fiducial_line = None + detector_line = None + for line in file: + data = line.split() + if len(data) <= 0: + continue + elif data[0] == "fiducial": + fiducial_line = line + elif data[0] == "detector": + detector_line = line + if fiducial_line is None or detector_line is None: + return None + return _detector.DetectorModel.ParseFiducialVolume(fiducial_line, detector_line) + return None From 226746d4506d1ebb1a5d2465dd4cde487cce82d6 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Thu, 6 Jun 2024 08:35:43 -0500 Subject: [PATCH 06/94] Sketch DN decay logic and fix some obvious issues in the DN xs logic --- .../DarkNewsTables/DarkNewsCrossSection.py | 52 +++-- .../DarkNewsTables/DarkNewsDecay.py | 52 ++--- .../CrossSections/DarkNewsTables/processes.py | 182 +++++++++++++++--- 3 files changed, 193 insertions(+), 93 deletions(-) diff --git a/resources/CrossSections/DarkNewsTables/DarkNewsCrossSection.py b/resources/CrossSections/DarkNewsTables/DarkNewsCrossSection.py index 688da76ad..6843972f7 100644 --- a/resources/CrossSections/DarkNewsTables/DarkNewsCrossSection.py +++ b/resources/CrossSections/DarkNewsTables/DarkNewsCrossSection.py @@ -39,30 +39,37 @@ def __init__( def load_from_table(self, table_dir): # Make the table directory where will we store cross section tables - table_dir_exists = False - if os.path.exists(table_dir): - # print("Directory '%s' already exists"%table_dir) - table_dir_exists = True - else: + if not os.path.exists(table_dir): try: os.makedirs(table_dir, exist_ok=False) - # print("Directory '%s' created successfully" % table_dir) except OSError as error: raise RuntimeError("Directory '%s' cannot be created" % table_dir) # Look in table dir and check whether total/differential xsec tables exist - if table_dir_exists: - total_xsec_file = os.path.join(table_dir, "total_cross_sections.npy") - if os.path.exists(total_xsec_file): - self.total_cross_section_table = np.load(total_xsec_file) - diff_xsec_file = os.path.join( - table_dir, "differential_cross_sections.npy" - ) - if os.path.exists(diff_xsec_file): - self.differential_cross_section_table = np.load(diff_xsec_file) + total_xsec_file = os.path.join(table_dir, "total_cross_sections.npy") + if os.path.exists(total_xsec_file): + self.total_cross_section_table = np.load(total_xsec_file) + diff_xsec_file = os.path.join( + table_dir, "differential_cross_sections.npy" + ) + if os.path.exists(diff_xsec_file): + self.differential_cross_section_table = np.load(diff_xsec_file) self.configure() + def save_to_table(self, table_dir, total=True, diff=True): + if total: + self._redefine_interpolation_objects(total=True) + with open( + os.path.join(table_dir, "total_cross_sections.npy"), "wb" + ) as f: + np.save(f, self.total_cross_section_table) + if diff: + self._redefine_interpolation_objects(diff=True) + with open( + os.path.join(table_dir, "differential_cross_sections.npy"), "wb" + ) as f: + np.save(f, self.differential_cross_section_table) # serialization method def get_representation(self): @@ -313,21 +320,6 @@ def FillInterpolationTables(self, total=True, diff=True, factor=0.8, Emax=None): self._redefine_interpolation_objects(total=total, diff=diff) return num_added_points - # Saves the tables for the scipy interpolation objects - def SaveInterpolationTables(self, table_dir, total=True, diff=True): - if total: - self._redefine_interpolation_objects(total=True) - with open( - os.path.join(table_dir, "total_cross_sections.npy"), "wb" - ) as f: - np.save(f, self.total_cross_section_table) - if diff: - self._redefine_interpolation_objects(diff=True) - with open( - os.path.join(table_dir, "differential_cross_sections.npy"), "wb" - ) as f: - np.save(f, self.differential_cross_section_table) - def GetPossiblePrimaries(self): return [Particle.ParticleType(self.ups_case.nu_projectile.pdgid)] diff --git a/resources/CrossSections/DarkNewsTables/DarkNewsDecay.py b/resources/CrossSections/DarkNewsTables/DarkNewsDecay.py index 5a3b37125..c21d947a3 100644 --- a/resources/CrossSections/DarkNewsTables/DarkNewsDecay.py +++ b/resources/CrossSections/DarkNewsTables/DarkNewsDecay.py @@ -27,49 +27,35 @@ def __init__(self, dec_case): self.total_width = None def load_from_table(self, table_dir): - if table_dir is None: - print( - "No table_dir specified; will sample from new VEGAS integrator for each decay" - ) - print("WARNING: this will siginficantly slow down event generation") - return - # Make the table directory where will we store cross section integrators - table_dir_exists = False - if os.path.exists(table_dir): - # print("Directory '%s' already exists"%table_dir) - table_dir_exists = True - else: + if not os.path.exists(table_dir): try: os.makedirs(table_dir, exist_ok=False) - print("Directory '%s' created successfully" % table_dir) except OSError as error: - print("Directory '%s' cannot be created" % table_dir) - exit(0) + raise RuntimeError("Directory '%s' cannot be created" % table_dir) # Try to find the decay integrator - int_file = os.path.join(table_dir, "decay_integrator.pkl") - if os.path.isfile(int_file): - with open(int_file, "rb") as ifile: - self.decay_integrator = pickle.load(ifile) - # Try to find the normalization information - norm_file = os.path.join(table_dir, "decay_norm.json") - if os.path.isfile(norm_file): - with open( - norm_file, - ) as nfile: - self.decay_norm = json.load(nfile) + decay_file = os.path.join(table_dir, "decay.pkl") + if os.path.isfile(decay_file): + with open(decay_file, "rb") as f: + self.decay_norm, self.decay_integrator = pickle.load(f) + def save_to_table(self, table_dir): + with open(os.path.join(table_dir, "decay.pkl") as f: + pickle.dump(f, { + "decay_integrator": self.decay_integrator, + "decay_norm": self.decay_norm + }) # serialization method def get_representation(self): - return {"decay_integrator":self.decay_integrator, - "decay_norm":self.decay_norm, - "dec_case":self.dec_case, - "PS_samples":self.PS_samples, - "PS_weights":self.PS_weights, - "PS_weights_CDF":self.PS_weights_CDF, - "total_width":self.total_width, + return {"decay_integrator": self.decay_integrator, + "decay_norm": self.decay_norm, + "dec_case": self.dec_case, + "PS_samples": self.PS_samples, + "PS_weights": self.PS_weights, + "PS_weights_CDF": self.PS_weights_CDF, + "total_width": self.total_width, } def SetIntegratorAndNorm(self, decay_norm, decay_integrator): diff --git a/resources/CrossSections/DarkNewsTables/processes.py b/resources/CrossSections/DarkNewsTables/processes.py index c26e0aad7..1fbfaf7bb 100644 --- a/resources/CrossSections/DarkNewsTables/processes.py +++ b/resources/CrossSections/DarkNewsTables/processes.py @@ -11,6 +11,7 @@ f"DarkNewsTables-v{siren.utilities.darknews_version()}", must_exist=False ) + def GetDetectorModelTargets(detector_model): """ Determines the targets that exist inside the detector model @@ -117,15 +118,13 @@ def attempt_to_load_cross_section( table_subdir = os.path.join(table_dir, subdir) if os.path.isdir(table_subdir): try: - cross_section = append( - load_cross_section_from_table( - models, - ups_key, - table_subdir, - tolerance=tolerance, - interp_tolerance=interp_tolerance, - always_interpolate=always_interpolate, - ) + cross_section = load_cross_section_from_table( + models, + ups_key, + table_subdir, + tolerance=tolerance, + interp_tolerance=interp_tolerance, + always_interpolate=always_interpolate, ) loaded = True except Exception as e: @@ -138,14 +137,12 @@ def attempt_to_load_cross_section( table_subdir = os.path.join(table_dir, subdir) if os.path.isdir(table_subdir): try: - cross_section = append( - load_cross_section_from_pickle( - ups_key, - table_subdir, - tolerance=tolerance, - interp_tolerance=interp_tolerance, - always_interpolate=always_interpolate, - ) + cross_section = load_cross_section_from_pickle( + ups_key, + table_subdir, + tolerance=tolerance, + interp_tolerance=interp_tolerance, + always_interpolate=always_interpolate, ) loaded = True except Exception as e: @@ -156,14 +153,12 @@ def attempt_to_load_cross_section( break elif p == "normal": try: - cross_sections = append( - load_cross_section( - models, - ups_key, - tolerance=tolerance, - interp_tolerance=interp_tolerance, - always_interpolate=always_interpolate, - ) + cross_sections = load_cross_section( + models, + ups_key, + tolerance=tolerance, + interp_tolerance=interp_tolerance, + always_interpolate=always_interpolate, ) loaded = True except Exception as e: @@ -201,6 +196,125 @@ def load_cross_sections( return cross_sections +def load_decay( + model_container, + decay_key, +): + if decay_key not in model_container.dec_cases: + raise KeyError( + f'Decay key "{decay_key}" not present in model_container.dec_cases' + ) + decay_model = model_container.dec_cases[decay_key] + return PyDarkNewsDecay( + decay_model, + ) + + +def load_decay_from_table( + model_container, + decay_key, + table_dir, +): + subdir = "_".join(["Decay"] + [str(x) for x in decay_key]) + table_subdir = os.path.join(table_dir, subdir) + + decay = load_decay( + model_container, + decay_key, + ) + decay.load_from_table(table_subdir) + return decay + + +def load_decay_from_pickle( + decay_key, + table_dir, +): + subdir = "_".join(["Decay"] + [str(x) for x in decay_key]) + table_subdir = os.path.join(table_dir, subdir) + fname = os.path.join(table_dir, "dec_object.pkl") + with open(fname, "rb") as f: + dec_obj = pickle.load(f) + return dec_obj + + +def attempt_to_load_decay( + models, + dec_key, + tabel_dir, + preferences, +): + if len(preferences) == 0: + raise ValueError("preferences must have at least one entry") + + subdir = "_".join(["Decay"] + [str(x) for x in dec_key]) + loaded = False + decay = None + for p in preferences: + if p == "table": + table_subdir = os.path.join(table_dir, subdir) + if os.path.isdir(table_subdir): + try: + decay = load_decay_from_table( + models, + dec_key, + table_subdir, + ) + loaded = True + except Exception as e: + print("Encountered exception while loading DN decay from table") + raise e from None + break + elif p == "pickle": + table_subdir = os.path.join(table_dir, subdir) + if os.path.isdir(table_subdir): + try: + decay = load_decay_from_pickle( + ups_key, + table_dir, + ) + loaded = True + except Exception as e: + print("Encountered exception while loading DN decay from pickle") + raise e from None + break + elif p == "normal": + try: + decay = load_decay( + models, + dec_key, + ) + loaded = True + except Exception as e: + print("Encountered exception while loading DN decay normally") + raise e from None + break + + if not loaded: + raise RuntimeError("Not able to load DN decay with any strategy") + return decay + + +def load_decays( + model_kwargs, + table_dir=None, + preferences=None, +): + if preferences is None: + preferences = ["table", "pickle", "normal"] + + models = ModelContainer(**model_kwargs) + + if table_dir is None: + table_dir = "" + + decays = [] + for dec_key, dec_case in models.dec_cases.items(): + decays.append(attempt_to_load_decy(models, dec_key, table_dir, preferences)) + + return decays + + def load_processes( primary_type=None, target_types=None, @@ -245,11 +359,19 @@ def load_processes( } cross_sections = load_cross_sections( - model_kwargs, - table_dir=None, - tolerance=tolerance, - interp_tolerance=interp_tolerance, - always_interpolate=always_interpolate, + model_kwargs, + table_dir=None, + tolerance=tolerance, + interp_tolerance=interp_tolerance, + always_interpolate=always_interpolate, + ) + + decays = load_decays( + model_kwargs, + table_dir=None, + tolerance=tolerance, + interp_tolerance=interp_tolerance, + always_interpolate=always_interpolate, ) if fill_tables_at_start: From e88fee6964b2226db043258cdc4e740d547313ee Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Thu, 6 Jun 2024 09:28:58 -0500 Subject: [PATCH 07/94] Return cross sections and decays --- .../CrossSections/DarkNewsTables/processes.py | 120 +++--------------- 1 file changed, 19 insertions(+), 101 deletions(-) diff --git a/resources/CrossSections/DarkNewsTables/processes.py b/resources/CrossSections/DarkNewsTables/processes.py index 1fbfaf7bb..cb4d95edc 100644 --- a/resources/CrossSections/DarkNewsTables/processes.py +++ b/resources/CrossSections/DarkNewsTables/processes.py @@ -172,7 +172,7 @@ def attempt_to_load_cross_section( def load_cross_sections( - model_kwargs, + models, table_dir=None, tolerance=1e-6, interp_tolerance=5e-2, @@ -182,8 +182,6 @@ def load_cross_sections( if preferences is None: preferences = ["table", "pickle", "normal"] - models = ModelContainer(**model_kwargs) - if table_dir is None: table_dir = "" @@ -296,15 +294,13 @@ def attempt_to_load_decay( def load_decays( - model_kwargs, + models, table_dir=None, preferences=None, ): if preferences is None: preferences = ["table", "pickle", "normal"] - models = ModelContainer(**model_kwargs) - if table_dir is None: table_dir = "" @@ -347,33 +343,32 @@ def load_processes( base_path = os.path.dirname(os.path.abspath(__file__)) table_dir = os.path.join(base_path, "Dipole_M%2.2e_mu%2.2e" % (m4, mu_tr_mu4)) - model_kwargs = { - "m4": m4, - "mu_tr_mu4": mu_tr_mu4, - "UD4": UD4, - "Umu4": Umu4, - "epsilon": epsilon, - "gD": gD, - "decay_product": decay_product, - "noHC": noHC, - } + models = ModelContainer( + m4=m4, + mu_tr_mu4=mu_tr_mu4, + UD4=UD4, + Umu4=Umu4, + epsilon=epsilon, + gD=gD, + decay_product=decay_product, + noHC=noHC, + ) cross_sections = load_cross_sections( - model_kwargs, - table_dir=None, + models, + table_dir=table_dir, tolerance=tolerance, interp_tolerance=interp_tolerance, always_interpolate=always_interpolate, ) decays = load_decays( - model_kwargs, - table_dir=None, - tolerance=tolerance, - interp_tolerance=interp_tolerance, - always_interpolate=always_interpolate, + models, + table_dir=table_dir, ) + cross_sections = [xs for xs in cross_sections if len([s for s in xs.GetPossibleSignatures() if s.primary_type == primary_type])>0] + if fill_tables_at_start: if Emax is None: print( @@ -383,82 +378,5 @@ def load_processes( for cross_section in cross_sections: cross_section.FillInterpolationTables(Emax=Emax) - # Initialize primary InteractionCollection - # Loop over available cross sections and save those which match primary type - primary_cross_sections = [] - for cross_section in self.DN_processes.cross_sections: - if primary_type == _dataclasses.Particle.ParticleType( - cross_section.ups_case.nu_projectile.pdgid - ): - primary_cross_sections.append(cross_section) - primary_interaction_collection = _interactions.InteractionCollection( - primary_type, primary_cross_sections - ) - - # Initialize secondary processes and define secondary InteractionCollection objects - secondary_decays = {} - # Also keep track of the minimum decay width for defining the position distribution later - self.DN_min_decay_width = np.inf - # Loop over available decays, group by parent type - for decay in self.DN_processes.decays: - secondary_type = _dataclasses.Particle.ParticleType( - decay.dec_case.nu_parent.pdgid - ) - if secondary_type not in secondary_decays.keys(): - secondary_decays[secondary_type] = [] - secondary_decays[secondary_type].append(decay) - total_decay_width = decay.TotalDecayWidth(secondary_type) - if total_decay_width < self.DN_min_decay_width: - self.DN_min_decay_width = total_decay_width - # Now make the list of secondary cross section collections - # Add new secondary injection and physical processes at the same time - secondary_interaction_collections = [] - for secondary_type, decay_list in secondary_decays.items(): - # Define a sedcondary injection distribution - secondary_injection_process = _injection.SecondaryInjectionProcess() - secondary_physical_process = _injection.PhysicalProcess() - secondary_injection_process.primary_type = secondary_type - secondary_physical_process.primary_type = secondary_type - - # Add the secondary position distribution - if self.fid_vol is not None: - secondary_injection_process.AddSecondaryInjectionDistribution( - _distributions.SecondaryBoundedVertexDistribution(self.fid_vol) - ) - else: - secondary_injection_process.AddSecondaryInjectionDistribution( - _distributions.SecondaryPhysicalVertexDistribution() - ) - - self.secondary_injection_processes.append(secondary_injection_process) - self.secondary_physical_processes.append(secondary_physical_process) - - secondary_interaction_collections.append( - _interactions.InteractionCollection(secondary_type, decay_list) - ) - - self.SetInteractions( - primary_interaction_collection, secondary_interaction_collections - ) - + return cross_sections + decays -def GetFiducialVolume(self): - """ - :return: identified fiducial volume for the experiment, None if not found - """ - detector_model_file = _util.get_detector_model_path(self.experiment) - with open(detector_model_file) as file: - fiducial_line = None - detector_line = None - for line in file: - data = line.split() - if len(data) <= 0: - continue - elif data[0] == "fiducial": - fiducial_line = line - elif data[0] == "detector": - detector_line = line - if fiducial_line is None or detector_line is None: - return None - return _detector.DetectorModel.ParseFiducialVolume(fiducial_line, detector_line) - return None From c19596f7c57ad851129605a6c1a0a198a7db556e Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Thu, 6 Jun 2024 09:47:15 -0500 Subject: [PATCH 08/94] Introspect package version in __init__.py --- python/__init__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/python/__init__.py b/python/__init__.py index 7f0f00e2d..aec0b49c8 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -9,6 +9,16 @@ from . import _util +# Intropspect package version +import sys +if sys.version_info >= (3, 8): + from importlib import metadata +else: + import importlib_metadata as metadata +__version__ = metadata.version(__package__) +del sys +del metadata + # set up some public-facing utilities functions utilities.get_resource_package_dir = _util.resource_package_dir utilities.get_detector_model_path = _util.get_detector_model_path From 79f1b345c9542f937f96ef4d7b111adf293e740d Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Thu, 6 Jun 2024 10:05:50 -0500 Subject: [PATCH 09/94] Start writing logic to generically load resources --- python/SIREN_DarkNews.py | 2 +- python/_util.py | 55 +++++++++++++++++++++++++++------------- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/python/SIREN_DarkNews.py b/python/SIREN_DarkNews.py index b5c4fb2f5..bedbd7137 100644 --- a/python/SIREN_DarkNews.py +++ b/python/SIREN_DarkNews.py @@ -57,7 +57,7 @@ def __init__( if self.table_dir is None: self.table_dir = os.path.join( resources_dir, - "CrossSections", + "Processes", "DarkNewsTables", datetime.datetime.now().strftime("%Y_%m_%d__%H:%M"), ) diff --git a/python/_util.py b/python/_util.py index 5d4dff1ac..780faee1a 100644 --- a/python/_util.py +++ b/python/_util.py @@ -543,34 +543,53 @@ def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exi return os.path.join(base_dir, model_name, model_file_name) -def get_detector_model_path(model_name, must_exist=True): +def get_detector_model_file_path(model_name, must_exist=True): return _get_model_path(model_name, prefix="Detectors/densities", suffix=".dat", is_file=True, must_exist=must_exist) -def get_material_model_path(model_name, must_exist=True): +def get_material_model_file_path(model_name, must_exist=True): return _get_model_path(model_name, prefix="Detectors/materials", suffix=".dat", is_file=True, must_exist=must_exist) -def get_cross_section_model_path(model_name, must_exist=True): - return _get_model_path(model_name, prefix="CrossSections", is_file=False, must_exist=must_exist) +_resource_folder_by_name = { + "flux": "Fluxes", + "detector": "Detectors", + "processes": "Processes", +} def get_flux_model_path(model_name, must_exist=True): - return _get_model_path(model_name,prefix="Fluxes", is_file=False, must_exist=must_exist) + return _get_model_path(model_name, prefix=_resource_folder_by_name["flux"], is_file=False, must_exist=must_exist) + + +def get_detector_model_path(model_name, must_exist=True): + return _get_model_path(model_name, prefix=_resource_folder_by_name["detector"], is_file=False, must_exist=must_exist) + + +def get_processes_model_path(model_name, must_exist=True): + return _get_model_path(model_name, prefix=_resource_folder_by_name["processes"], is_file=False, must_exist=must_exist) + + +def load_resource(resource_name, resource_type, *args, **kwargs): + folder = _resource_folder_by_name[resource_type] + + abs_dir = _get_model_path(model_name, prefix=folder, is_file=False, must_exist=True) + + fname = os.path.join(abs_flux_dir, f"{resource_name}.py") + assert(os.path.isfile(fname)) + resource_module = load_module(f"siren-{resource_type}-{model_name}", fname, persist=False) + loader = getattr(resource_module, f"load_{resource_name}") + resource = loader(*args, **kwargs) + return resource def load_flux(model_name, *args, **kwargs): - abs_flux_dir = get_flux_model_path(model_name, must_exist=True) - - # require existence of flux.py - flux_file = os.path.join(abs_flux_dir, "flux.py") - assert(os.path.isfile(flux_file)) - spec = importlib.util.spec_from_file_location("flux", flux_file) - flux = importlib.util.module_from_spec(spec) - module_name = f"siren-flux-{model_name}-{str(uuid.uuid4())}" - sys.modules[module_name] = flux - spec.loader.exec_module(flux) - flux_file = flux.load_flux(*args, **kwargs) - del sys.modules[module_name] # remove flux directory from the system - return flux_file + return load_resource("flux", model_name, *args, **kwargs) + + +def load_detector(model_name, *args, **kwargs): + return load_resource("detector", model_name, *args, **kwargs) + +def load_processes(model_name, *args, **kwargs): + return load_resource("processes", model_name, *args, **kwargs) From d5bbec454b2d3e8a95af1932ccabc768f6108cf5 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Tue, 27 Aug 2024 14:05:29 -0600 Subject: [PATCH 10/94] Remove material model path method --- python/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python/__init__.py b/python/__init__.py index aec0b49c8..b83d12fbe 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -22,7 +22,6 @@ # set up some public-facing utilities functions utilities.get_resource_package_dir = _util.resource_package_dir utilities.get_detector_model_path = _util.get_detector_model_path -utilities.get_material_model_path = _util.get_material_model_path utilities.get_cross_section_model_path = _util.get_cross_section_model_path utilities.get_flux_model_path = _util.get_flux_model_path utilities.load_flux = _util.load_flux From c9a09d1f32cfd6538e699348c00cce1408703afb Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 28 Aug 2024 15:48:34 -0600 Subject: [PATCH 11/94] Needs functools --- resources/CrossSections/DarkNewsTables/logger.py | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/CrossSections/DarkNewsTables/logger.py b/resources/CrossSections/DarkNewsTables/logger.py index e8ebef6f6..bdd03c096 100644 --- a/resources/CrossSections/DarkNewsTables/logger.py +++ b/resources/CrossSections/DarkNewsTables/logger.py @@ -1,4 +1,5 @@ # Monkey patch DarkNews logger to hide printouts +import functools from DarkNews.ModelContainer import ModelContainer ModelContainer_configure_logger = ModelContainer.configure_logger From 844e0cde467ba0bfcedc390cdefe09dc804500d7 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 28 Aug 2024 16:01:22 -0600 Subject: [PATCH 12/94] import struct. Properly return the module from sys.modules. Call exec_module with the actual module. Swap the argument order in load_resource. Fix variable names in load_resource. --- python/_util.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/python/_util.py b/python/_util.py index 780faee1a..4a50c531f 100644 --- a/python/_util.py +++ b/python/_util.py @@ -133,6 +133,7 @@ def get_platform(): sys.platform does. The result can be: linux32, linux64, win32, win64, osx32, osx64. Other platforms may be added in the future. """ + import struct # Get platform if sys.platform.startswith("linux"): plat = "linux%i" @@ -175,11 +176,11 @@ def load_module(name, path, persist=True): url = pathlib.Path(os.path.abspath(path)).as_uri() module_name = f"{name}-{str(uuid.uuid5(uuid.NAMESPACE_URL, url))}" if module_name in sys.modules: - return module + return sys.modules[module_name] spec = importlib.util.spec_from_file_location(name, path) module = importlib.util.module_from_spec(spec) sys.modules[module_name] = module - spec.loader.exec_module(module_name) + spec.loader.exec_module(module) module = sys.modules[module_name] if not persist: del sys.modules[module_name] @@ -570,14 +571,14 @@ def get_processes_model_path(model_name, must_exist=True): return _get_model_path(model_name, prefix=_resource_folder_by_name["processes"], is_file=False, must_exist=must_exist) -def load_resource(resource_name, resource_type, *args, **kwargs): +def load_resource(resource_type, resource_name, *args, **kwargs): folder = _resource_folder_by_name[resource_type] - abs_dir = _get_model_path(model_name, prefix=folder, is_file=False, must_exist=True) + abs_dir = _get_model_path(resource_name, prefix=folder, is_file=False, must_exist=True) - fname = os.path.join(abs_flux_dir, f"{resource_name}.py") + fname = os.path.join(abs_dir, f"{resource_name}.py") assert(os.path.isfile(fname)) - resource_module = load_module(f"siren-{resource_type}-{model_name}", fname, persist=False) + resource_module = load_module(f"siren-{resource_type}-{resource_name}", fname, persist=False) loader = getattr(resource_module, f"load_{resource_name}") resource = loader(*args, **kwargs) return resource From 5940daeddb00df8127c3dcc4d338de58983f23b9 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 28 Aug 2024 16:01:52 -0600 Subject: [PATCH 13/94] docstrings, type hints, and variable names --- .../CrossSections/DarkNewsTables/processes.py | 177 +++++++++++++----- 1 file changed, 133 insertions(+), 44 deletions(-) diff --git a/resources/CrossSections/DarkNewsTables/processes.py b/resources/CrossSections/DarkNewsTables/processes.py index cb4d95edc..1d0832fcb 100644 --- a/resources/CrossSections/DarkNewsTables/processes.py +++ b/resources/CrossSections/DarkNewsTables/processes.py @@ -1,4 +1,5 @@ import os +from typing import Tuple, List, Any, Optional import siren base_path = os.path.dirname(os.path.abspath(__file__)) @@ -7,16 +8,30 @@ from DarkNews.ModelContainer import ModelContainer +# Import PyDarkNewsDecay and PyDarkNewsCrossSection +decay_file = os.path.join(base_path, "DarkNewsDecay.py") +cross_section_file = os.path.join(base_path, "DarkNewsCrossSection.py") +siren._util.load_module("DarkNewsDecay", decay_file) +siren._util.load_module("DarkNewsCrossSection", cross_section_file) + +from DarkNewsDecay import PyDarkNewsDecay +from DarkNewsCrossSection import PyDarkNewsCrossSection + xs_path = siren.utilities.get_cross_section_model_path( f"DarkNewsTables-v{siren.utilities.darknews_version()}", must_exist=False ) - -def GetDetectorModelTargets(detector_model): +def GetDetectorModelTargets(detector_model: siren.detector.DetectorModel) -> Tuple[List[siren.dataclasses.Particle.ParticleType], List[str]]: """ - Determines the targets that exist inside the detector model - :return: lists of targets and strings - :rtype: (list, list) + Determines the targets that exist inside the detector model. + + Args: + detector_model (siren.detector.DetectorModel): The detector model object. + + Returns: + Tuple[List[siren.dataclasses.Particle.ParticleType], List[str]]: A tuple containing two lists: + - List of target objects (ParticleType) + - List of target strings """ count = 0 targets = [] @@ -40,12 +55,28 @@ def GetDetectorModelTargets(detector_model): def load_cross_section( - model_container, - upscattering_key, - tolerance=1e-6, - interp_tolerance=5e-2, - always_interpolate=True, -): + model_container: ModelContainer, + upscattering_key: Any, + tolerance: float = 1e-6, + interp_tolerance: float = 5e-2, + always_interpolate: bool = True, +) -> PyDarkNewsCrossSection: + """ + Loads a cross-section object based on the given parameters. + + Args: + model_container (ModelContainer): The model container object. + upscattering_key (Any): The key for the upscattering model. + tolerance (float, optional): Tolerance for calculations. Defaults to 1e-6. + interp_tolerance (float, optional): Interpolation tolerance. Defaults to 5e-2. + always_interpolate (bool, optional): Whether to always interpolate. Defaults to True. + + Returns: + PyDarkNewsCrossSection: The loaded cross-section object. + + Raises: + KeyError: If the upscattering key is not present in model_container.ups_cases. + """ if upscattering_key not in model_container.ups_cases: raise KeyError( f'Upscattering key "{upscattering_key}" not present in model_container.ups_cases' @@ -88,6 +119,7 @@ def load_cross_section_from_pickle( interp_tolerance=5e-2, always_interpolate=True, ): + import pickle subdir = "_".join(["CrossSection"] + [str(x) for x in upscattering_key]) table_subdir = os.path.join(table_dir, subdir) fname = os.path.join(table_dir, "xs_object.pkl") @@ -102,11 +134,33 @@ def load_cross_section_from_pickle( def attempt_to_load_cross_section( - models, - ups_key, - tabel_dir, - preferences, -): + models: ModelContainer, + ups_key: Any, + table_dir: str, + preferences: List[str], + tolerance: float = 1e-6, + interp_tolerance: float = 5e-2, + always_interpolate: bool = True, +) -> PyDarkNewsCrossSection: + """ + Attempts to load a cross-section object using different strategies based on preferences. + + Args: + models (ModelContainer): The model container object. + ups_key (Any): The key for the upscattering model. + table_dir (str): Directory path for the tables. + preferences (List[str]): List of loading preferences (e.g., ["table", "pickle", "normal"]). + tolerance (float, optional): Tolerance for calculations. Defaults to 1e-6. + interp_tolerance (float, optional): Interpolation tolerance. Defaults to 5e-2. + always_interpolate (bool, optional): Whether to always interpolate. Defaults to True. + + Returns: + PyDarkNewsCrossSection: The loaded cross-section object. + + Raises: + ValueError: If preferences list is empty. + RuntimeError: If unable to load the cross-section with any strategy. + """ if len(preferences) == 0: raise ValueError("preferences must have at least one entry") @@ -188,7 +242,12 @@ def load_cross_sections( cross_sections = [] for ups_key, ups_case in models.ups_cases.items(): cross_sections.append( - attempt_to_load_cross_section(models, ups_key, table_dir, preferences) + attempt_to_load_cross_section(models, ups_key, + table_dir, + preferences, + tolerance, + interp_tolerance, + always_interpolate) ) return cross_sections @@ -228,6 +287,7 @@ def load_decay_from_pickle( decay_key, table_dir, ): + import pickle subdir = "_".join(["Decay"] + [str(x) for x in decay_key]) table_subdir = os.path.join(table_dir, subdir) fname = os.path.join(table_dir, "dec_object.pkl") @@ -238,14 +298,14 @@ def load_decay_from_pickle( def attempt_to_load_decay( models, - dec_key, - tabel_dir, + decay_key, + table_dir, preferences, ): if len(preferences) == 0: raise ValueError("preferences must have at least one entry") - subdir = "_".join(["Decay"] + [str(x) for x in dec_key]) + subdir = "_".join(["Decay"] + [str(x) for x in decay_key]) loaded = False decay = None for p in preferences: @@ -255,7 +315,7 @@ def attempt_to_load_decay( try: decay = load_decay_from_table( models, - dec_key, + decay_key, table_subdir, ) loaded = True @@ -268,7 +328,7 @@ def attempt_to_load_decay( if os.path.isdir(table_subdir): try: decay = load_decay_from_pickle( - ups_key, + decay_key, table_dir, ) loaded = True @@ -280,7 +340,7 @@ def attempt_to_load_decay( try: decay = load_decay( models, - dec_key, + decay_key, ) loaded = True except Exception as e: @@ -305,32 +365,61 @@ def load_decays( table_dir = "" decays = [] - for dec_key, dec_case in models.dec_cases.items(): - decays.append(attempt_to_load_decy(models, dec_key, table_dir, preferences)) + for decay_key, dec_case in models.dec_cases.items(): + decays.append(attempt_to_load_decay(models, decay_key, table_dir, preferences)) return decays def load_processes( - primary_type=None, - target_types=None, - fill_tables_at_start=False, - Emax=None, - m4=None, - mu_tr_mu4=None, # GeV^-1 - UD4=0, - Umu4=0, - epsilon=0.0, - gD=0.0, - decay_product="photon", - noHC=True, - HNLtype="dirac", - nuclear_targets=None, - detector_model=None, - tolerance=1e-6, # supposed to represent machine epsilon - interp_tolerance=5e-2, # relative interpolation tolerance - always_interpolate=True, # bool whether to always interpolate the total/differential cross section -): + primary_type: Optional[Any] = None, + target_types: Optional[List[Any]] = None, + fill_tables_at_start: bool = False, + Emax: Optional[float] = None, + m4: Optional[float] = None, + mu_tr_mu4: Optional[float] = None, + UD4: float = 0, + Umu4: float = 0, + epsilon: float = 0.0, + gD: float = 0.0, + decay_product: str = "photon", + noHC: bool = True, + HNLtype: str = "dirac", + nuclear_targets: Optional[List[str]] = None, + detector_model: Optional[Any] = None, + tolerance: float = 1e-6, + interp_tolerance: float = 5e-2, + always_interpolate: bool = True, +) -> List[Any]: + """ + Loads and returns a list of cross-section and decay objects based on the given parameters. + + Args: + primary_type (Optional[Any]): The primary particle type. + target_types (Optional[List[Any]]): List of target particle types. + fill_tables_at_start (bool): Whether to fill interpolation tables at start. + Emax (Optional[float]): Maximum energy for table filling. + m4 (Optional[float]): Mass parameter. + mu_tr_mu4 (Optional[float]): Transition magnetic moment parameter. + UD4 (float): UD4 parameter. + Umu4 (float): Umu4 parameter. + epsilon (float): Epsilon parameter. + gD (float): gD parameter. + decay_product (str): Type of decay product. + noHC (bool): noHC parameter. + HNLtype (str): Type of HNL (e.g., "dirac"). + nuclear_targets (Optional[List[str]]): List of nuclear targets. + detector_model (Optional[Any]): Detector model object. + tolerance (float): Tolerance for calculations. + interp_tolerance (float): Interpolation tolerance. + always_interpolate (bool): Whether to always interpolate. + + Returns: + List[Any]: A list of loaded cross-section and decay objects. + + Raises: + ValueError: If neither nuclear_targets nor detector_model is provided. + """ if nuclear_targets is None and detector_model is None: raise ValueError( From e33c191da13579f60cbbf5fa24c2597653ff5696 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 28 Aug 2024 21:21:01 -0600 Subject: [PATCH 14/94] Move cross sections. Fix string formatting --- python/_util.py | 2 +- .../CSMSDISSplines-v1.0/dsdxdy_nu_CC_iso.fits | Bin .../CSMSDISSplines-v1.0/dsdxdy_nu_NC_iso.fits | Bin .../CSMSDISSplines-v1.0/dsdxdy_nubar_CC_iso.fits | Bin .../CSMSDISSplines-v1.0/dsdxdy_nubar_NC_iso.fits | Bin .../CSMSDISSplines-v1.0/sigma_nu_CC_iso.fits | Bin .../CSMSDISSplines-v1.0/sigma_nu_NC_iso.fits | Bin .../CSMSDISSplines-v1.0/sigma_nubar_CC_iso.fits | Bin .../CSMSDISSplines-v1.0/sigma_nubar_NC_iso.fits | Bin .../DarkNewsTables/DarkNewsCrossSection.py | 0 .../DarkNewsTables/DarkNewsDecay.py | 0 .../DarkNewsTables/README.md | 0 .../DarkNewsTables/logger.py | 0 .../DarkNewsTables/processes.py | 0 14 files changed, 1 insertion(+), 1 deletion(-) rename resources/{CrossSections => Processes}/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_CC_iso.fits (100%) rename resources/{CrossSections => Processes}/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_NC_iso.fits (100%) rename resources/{CrossSections => Processes}/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_CC_iso.fits (100%) rename resources/{CrossSections => Processes}/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_NC_iso.fits (100%) rename resources/{CrossSections => Processes}/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_CC_iso.fits (100%) rename resources/{CrossSections => Processes}/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_NC_iso.fits (100%) rename resources/{CrossSections => Processes}/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_CC_iso.fits (100%) rename resources/{CrossSections => Processes}/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_NC_iso.fits (100%) rename resources/{CrossSections => Processes}/DarkNewsTables/DarkNewsCrossSection.py (100%) rename resources/{CrossSections => Processes}/DarkNewsTables/DarkNewsDecay.py (100%) rename resources/{CrossSections => Processes}/DarkNewsTables/README.md (100%) rename resources/{CrossSections => Processes}/DarkNewsTables/logger.py (100%) rename resources/{CrossSections => Processes}/DarkNewsTables/processes.py (100%) diff --git a/python/_util.py b/python/_util.py index 4a50c531f..f03a565dc 100644 --- a/python/_util.py +++ b/python/_util.py @@ -503,7 +503,7 @@ def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exi # Raise an error if no model file is found and we require it to exist if len(model_versions) == 0 and must_exist: raise ValueError( - "No model found for {}\nSearched in ".format( + "No model found for {}\nSearched in {}".format( model_name, os.path.join(base_dir, model_name) ) ) diff --git a/resources/CrossSections/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_CC_iso.fits b/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_CC_iso.fits similarity index 100% rename from resources/CrossSections/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_CC_iso.fits rename to resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_CC_iso.fits diff --git a/resources/CrossSections/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_NC_iso.fits b/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_NC_iso.fits similarity index 100% rename from resources/CrossSections/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_NC_iso.fits rename to resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_NC_iso.fits diff --git a/resources/CrossSections/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_CC_iso.fits b/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_CC_iso.fits similarity index 100% rename from resources/CrossSections/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_CC_iso.fits rename to resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_CC_iso.fits diff --git a/resources/CrossSections/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_NC_iso.fits b/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_NC_iso.fits similarity index 100% rename from resources/CrossSections/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_NC_iso.fits rename to resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_NC_iso.fits diff --git a/resources/CrossSections/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_CC_iso.fits b/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_CC_iso.fits similarity index 100% rename from resources/CrossSections/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_CC_iso.fits rename to resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_CC_iso.fits diff --git a/resources/CrossSections/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_NC_iso.fits b/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_NC_iso.fits similarity index 100% rename from resources/CrossSections/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_NC_iso.fits rename to resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_NC_iso.fits diff --git a/resources/CrossSections/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_CC_iso.fits b/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_CC_iso.fits similarity index 100% rename from resources/CrossSections/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_CC_iso.fits rename to resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_CC_iso.fits diff --git a/resources/CrossSections/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_NC_iso.fits b/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_NC_iso.fits similarity index 100% rename from resources/CrossSections/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_NC_iso.fits rename to resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_NC_iso.fits diff --git a/resources/CrossSections/DarkNewsTables/DarkNewsCrossSection.py b/resources/Processes/DarkNewsTables/DarkNewsCrossSection.py similarity index 100% rename from resources/CrossSections/DarkNewsTables/DarkNewsCrossSection.py rename to resources/Processes/DarkNewsTables/DarkNewsCrossSection.py diff --git a/resources/CrossSections/DarkNewsTables/DarkNewsDecay.py b/resources/Processes/DarkNewsTables/DarkNewsDecay.py similarity index 100% rename from resources/CrossSections/DarkNewsTables/DarkNewsDecay.py rename to resources/Processes/DarkNewsTables/DarkNewsDecay.py diff --git a/resources/CrossSections/DarkNewsTables/README.md b/resources/Processes/DarkNewsTables/README.md similarity index 100% rename from resources/CrossSections/DarkNewsTables/README.md rename to resources/Processes/DarkNewsTables/README.md diff --git a/resources/CrossSections/DarkNewsTables/logger.py b/resources/Processes/DarkNewsTables/logger.py similarity index 100% rename from resources/CrossSections/DarkNewsTables/logger.py rename to resources/Processes/DarkNewsTables/logger.py diff --git a/resources/CrossSections/DarkNewsTables/processes.py b/resources/Processes/DarkNewsTables/processes.py similarity index 100% rename from resources/CrossSections/DarkNewsTables/processes.py rename to resources/Processes/DarkNewsTables/processes.py From 1642d85d620616ede69f008be6ca5635ecc14b41 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 28 Aug 2024 22:48:48 -0600 Subject: [PATCH 15/94] cross_Section -> processes --- python/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/__init__.py b/python/__init__.py index b83d12fbe..14689b726 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -22,7 +22,7 @@ # set up some public-facing utilities functions utilities.get_resource_package_dir = _util.resource_package_dir utilities.get_detector_model_path = _util.get_detector_model_path -utilities.get_cross_section_model_path = _util.get_cross_section_model_path +utilities.get_processes_model_path = _util.get_processes_model_path utilities.get_flux_model_path = _util.get_flux_model_path utilities.load_flux = _util.load_flux From 34976e92dc88320a2175853653a8b96cd33a1de3 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 28 Aug 2024 22:50:34 -0600 Subject: [PATCH 16/94] Refactor _get_model_path. Add support for top-level loaders --- python/_util.py | 195 ++++++++++++++++++++++++++---------------------- 1 file changed, 105 insertions(+), 90 deletions(-) diff --git a/python/_util.py b/python/_util.py index f03a565dc..40d4db571 100644 --- a/python/_util.py +++ b/python/_util.py @@ -223,6 +223,24 @@ def load_module(name, path, persist=True): re.VERBOSE | re.IGNORECASE, ) +_UNVERSIONED_MODEL_PATTERN = ( + r""" + (?P + (?: + [a-zA-Z0-9]+ + ) + | + (?: + (?:[a-zA-Z0-9]+(?:[-_\.][a-zA-Z0-9]+)*(?:[-_\.][a-zA-Z]+[a-zA-Z0-9]*))? + ) + ) + (?: + - + (?P""" + + _VERSION_PATTERN + + r"))?" +) + _MODEL_PATTERN = ( r""" (?P @@ -418,128 +436,123 @@ def tokenize_version(version): return tuple(token_list) -def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exist=True): - # Get the path to the model file - _model_regex = re.compile( - r"^\s*" + _MODEL_PATTERN + ("" if suffix is None else r"(?:" + suffix + r")?") + r"\s*$", - re.VERBOSE | re.IGNORECASE, - ) - if suffix is None: - suffix = "" - # Get the path to the resources directory - resources_dir = resource_package_dir() +def _get_base_directory(resources_dir, prefix): base_dir = resources_dir - - # Add prefix if present if prefix is not None: base_dir = os.path.join(base_dir, prefix) + return base_dir - # Get the model name and version - d = _model_regex.match(model_name) - if d is None: - raise ValueError("Invalid model name: {}".format(model_name)) - d = d.groupdict() - model_name = d["model_name"] - version = d["version"] - - # Search for the model folder in the resources directory +def _find_model_folder_and_file(base_dir, model_name, must_exist, specific_file=None): model_names = [ f for f in os.listdir(base_dir) if not os.path.isfile(os.path.join(base_dir, f)) ] - model_names = [f for f in model_names if f.lower().startswith(model_name.lower())] - folder_exists = False + exact_model_names = [f for f in model_names if f.lower() == model_name.lower()] + + if len(exact_model_names) == 0: + model_names = [f for f in model_names if f.lower().startswith(model_name.lower())] + else: + model_names = exact_model_names if len(model_names) == 0 and must_exist: - # Whoops, we didn't find the model folder! - raise ValueError( - "No model folders found for {}\nSearched in ".format(model_name, base_dir) - ) + raise ValueError(f"No model folders found for {model_name}\nSearched in {base_dir}") elif len(model_names) == 0 and not must_exist: - # Let's use the provided model name as the folder name - model_name = model_name + return model_name, False, None elif len(model_names) == 1: - # We found the model folder! - folder_exists = True - model_name = model_names[0] + name = model_names[0] + if specific_file is not None: + specific_file_path = os.path.join(base_dir, name, specific_file) + if os.path.isfile(specific_file_path): + return name, True, specific_file_path + else: + return name, True, None else: - # Multiple model folders found, we cannot decide which one to use - raise ValueError( - "Multiple directories found for {}\nSearched in ".format( - model_name, base_dir - ) - ) + raise ValueError(f"Multiple directories found for {model_name}\nSearched in {base_dir}") +def _get_model_files(base_dir, model_name, is_file, folder_exists, version=None): if folder_exists: - # Search for the model file in the model folder - model_files = [ - f - for f in os.listdir(os.path.join(base_dir, model_name)) + if version: + version_dir = os.path.join(base_dir, model_name, f"v{version}") + if os.path.isdir(version_dir): + return [ + f for f in os.listdir(version_dir) + if is_file == os.path.isfile(os.path.join(version_dir, f)) + ] + return [ + f for f in os.listdir(os.path.join(base_dir, model_name)) if is_file == os.path.isfile(os.path.join(base_dir, model_name, f)) ] - else: - model_files = [] + return [] - # From the found model files, extract the model versions +def _extract_model_versions(model_files, model_regex, model_name): model_versions = [] for f in model_files: - d = _model_regex.match(f) + d = model_regex.match(f) if d is not None: if d.groupdict()["version"] is not None: model_versions.append(normalize_version(d.groupdict()["version"])) else: - print(ValueError( - "Input model file has no version: {}\nSearched in ".format( - f, os.path.join(base_dir, model_name) - ) - )) + print(f"Warning: Input model file has no version: {f}") elif f.lower().startswith(model_name.lower()): - print(ValueError( - "Unable to parse version from {}\nFound in ".format( - f, os.path.join(base_dir, model_name) - ) - )) - - # Raise an error if no model file is found and we require it to exist - if len(model_versions) == 0 and must_exist: - raise ValueError( - "No model found for {}\nSearched in {}".format( - model_name, os.path.join(base_dir, model_name) - ) - ) + print(f"Warning: Unable to parse version from {f}") + return model_versions +def _get_model_file_name(version, model_versions, model_files, model_name, suffix, must_exist): if version is None and must_exist: - # If no version is provided, use the latest version - version_idx, version = max( - enumerate(model_versions), key=lambda x: tokenize_version(x[1]) - ) - model_file_name = model_files[version_idx] + version_idx, version = max(enumerate(model_versions), key=lambda x: tokenize_version(x[1])) + return model_files[version_idx] elif version is None and not must_exist: - # If no version is provided and we don't require it to exist, default to v1 version = "v1" - model_file_name = "{}-v{}{}".format(model_name, version, suffix) + return f"{model_name}-v{version}{suffix}" else: - # A version is provided version = normalize_version(version) if must_exist: - # If the version must exist, raise an error if it doesn't if version not in model_versions: - raise ValueError( - "No model found for {}-{}\nSearched in ".format( - model_name, version, os.path.join(base_dir, model_name) - ) - ) + raise ValueError(f"No model found for {model_name}-{version}") version_idx = model_versions.index(version) - model_file_name = model_files[version_idx] + return model_files[version_idx] else: - # The version doesn't have to exist if version in model_versions: - # If the version exists, use it version_idx = model_versions.index(version) - model_file_name = model_files[version_idx] + return model_files[version_idx] else: - # Otherwise use the provided version - model_file_name = "{}-v{}{}".format(model_name, version, suffix) + return f"{model_name}-v{version}{suffix}" + +def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exist=True, specific_file=None): + _model_regex = re.compile( + r"^\s*" + _MODEL_PATTERN + ("" if suffix is None else r"(?:" + suffix + r")?") + r"\s*$", + re.VERBOSE | re.IGNORECASE, + ) + suffix = "" if suffix is None else suffix + + resources_dir = resource_package_dir() + base_dir = _get_base_directory(resources_dir, prefix) + + d = _model_regex.match(model_name) + if d is None: + raise ValueError(f"Invalid model name: {model_name}") + d = d.groupdict() + model_name, version = d["model_name"], d["version"] + + model_name, folder_exists, specific_file_path = _find_model_folder_and_file(base_dir, model_name, must_exist, specific_file) + + if specific_file_path and not version: + return os.path.dirname(specific_file_path) + + model_files = _get_model_files(base_dir, model_name, is_file, folder_exists, version) + model_versions = _extract_model_versions(model_files, _model_regex, model_name) + + if len(model_versions) == 0 and must_exist: + if specific_file_path: + return os.path.dirname(specific_file_path) + raise ValueError(f"No model found for {model_name}\nSearched in {os.path.join(base_dir, model_name)}") + + model_file_name = _get_model_file_name(version, model_versions, model_files, model_name, suffix, must_exist) + + if version: + version_dir = os.path.join(base_dir, model_name, f"v{version}") + if os.path.isdir(version_dir): + return os.path.join(version_dir, model_file_name) return os.path.join(base_dir, model_name, model_file_name) @@ -560,26 +573,28 @@ def get_material_model_file_path(model_name, must_exist=True): def get_flux_model_path(model_name, must_exist=True): - return _get_model_path(model_name, prefix=_resource_folder_by_name["flux"], is_file=False, must_exist=must_exist) + return _get_model_path(model_name, prefix=_resource_folder_by_name["flux"], is_file=False, must_exist=must_exist, specific_file=f"flux.py") def get_detector_model_path(model_name, must_exist=True): - return _get_model_path(model_name, prefix=_resource_folder_by_name["detector"], is_file=False, must_exist=must_exist) + return _get_model_path(model_name, prefix=_resource_folder_by_name["detector"], is_file=False, must_exist=must_exist, specific_file=f"detector.py") def get_processes_model_path(model_name, must_exist=True): - return _get_model_path(model_name, prefix=_resource_folder_by_name["processes"], is_file=False, must_exist=must_exist) + return _get_model_path(model_name, prefix=_resource_folder_by_name["processes"], is_file=False, must_exist=must_exist, specific_file="processes.py") def load_resource(resource_type, resource_name, *args, **kwargs): folder = _resource_folder_by_name[resource_type] + specific_file = f"{resource_type}.py" - abs_dir = _get_model_path(resource_name, prefix=folder, is_file=False, must_exist=True) + abs_dir = _get_model_path(resource_name, prefix=folder, is_file=False, must_exist=True, specific_file=specific_file) - fname = os.path.join(abs_dir, f"{resource_name}.py") + fname = os.path.join(abs_dir, f"{resource_type}.py") + print(fname) assert(os.path.isfile(fname)) resource_module = load_module(f"siren-{resource_type}-{resource_name}", fname, persist=False) - loader = getattr(resource_module, f"load_{resource_name}") + loader = getattr(resource_module, f"load_{resource_type}") resource = loader(*args, **kwargs) return resource From 16a7b61bc0952c5c3713d71083bd4a14e4ece56d Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 28 Aug 2024 22:51:20 -0600 Subject: [PATCH 17/94] Fix imports. loader -> logger --- resources/Processes/DarkNewsTables/processes.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/resources/Processes/DarkNewsTables/processes.py b/resources/Processes/DarkNewsTables/processes.py index 1d0832fcb..ff0ce8d66 100644 --- a/resources/Processes/DarkNewsTables/processes.py +++ b/resources/Processes/DarkNewsTables/processes.py @@ -3,21 +3,21 @@ import siren base_path = os.path.dirname(os.path.abspath(__file__)) -loader_file = os.path.join(base_path, "loader.py") -siren._util.load_module("loader", loader_file) +logger_file = os.path.join(base_path, "logger.py") +siren._util.load_module("logger", logger_file) -from DarkNews.ModelContainer import ModelContainer +from siren.DNModelContainer import ModelContainer # Import PyDarkNewsDecay and PyDarkNewsCrossSection decay_file = os.path.join(base_path, "DarkNewsDecay.py") cross_section_file = os.path.join(base_path, "DarkNewsCrossSection.py") -siren._util.load_module("DarkNewsDecay", decay_file) -siren._util.load_module("DarkNewsCrossSection", cross_section_file) +DarkNewsDecay = siren._util.load_module("DarkNewsDecay", decay_file) +DarkNewsCrossSection = siren._util.load_module("DarkNewsCrossSection", cross_section_file) -from DarkNewsDecay import PyDarkNewsDecay -from DarkNewsCrossSection import PyDarkNewsCrossSection +PyDarkNewsCrossSection = DarkNewsCrossSection.PyDarkNewsCrossSection +PyDarkNewsDecay = DarkNewsDecay.PyDarkNewsDecay -xs_path = siren.utilities.get_cross_section_model_path( +xs_path = siren.utilities.get_processes_model_path( f"DarkNewsTables-v{siren.utilities.darknews_version()}", must_exist=False ) From b81b555a58ff15c8355c5ab60b0073b26d4ca896 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 28 Aug 2024 22:51:46 -0600 Subject: [PATCH 18/94] Fix imports --- resources/Processes/DarkNewsTables/DarkNewsCrossSection.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/resources/Processes/DarkNewsTables/DarkNewsCrossSection.py b/resources/Processes/DarkNewsTables/DarkNewsCrossSection.py index 6843972f7..694ccb099 100644 --- a/resources/Processes/DarkNewsTables/DarkNewsCrossSection.py +++ b/resources/Processes/DarkNewsTables/DarkNewsCrossSection.py @@ -3,9 +3,11 @@ import functools from scipy.interpolate import LinearNDInterpolator, PchipInterpolator +from siren import _util + base_path = os.path.dirname(os.path.abspath(__file__)) -loader_file = os.path.join(base_path, "loader.py") -siren._util.load_module("loader", loader_file) +logger_file = os.path.join(base_path, "logger.py") +_util.load_module("logger", logger_file) # SIREN methods from siren.interactions import DarkNewsCrossSection From c9dc192798fc0479434899b643e8b250601d979c Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 28 Aug 2024 22:52:45 -0600 Subject: [PATCH 19/94] Fix imports. loader -> logger. Instance checking instead of type checking. non-zero CDF check. --- .../Processes/DarkNewsTables/DarkNewsDecay.py | 45 +++++++++++++------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/resources/Processes/DarkNewsTables/DarkNewsDecay.py b/resources/Processes/DarkNewsTables/DarkNewsDecay.py index c21d947a3..9c076b3d4 100644 --- a/resources/Processes/DarkNewsTables/DarkNewsDecay.py +++ b/resources/Processes/DarkNewsTables/DarkNewsDecay.py @@ -1,10 +1,12 @@ import os import numpy as np -import functools +import pickle + +from siren import _util base_path = os.path.dirname(os.path.abspath(__file__)) -loader_file = os.path.join(base_path, "loader.py") -siren._util.load_module("loader", loader_file) +logger_file = os.path.join(base_path, "logger.py") +_util.load_module("logger", logger_file) # SIREN methods from siren.interactions import DarkNewsDecay @@ -41,7 +43,7 @@ def load_from_table(self, table_dir): self.decay_norm, self.decay_integrator = pickle.load(f) def save_to_table(self, table_dir): - with open(os.path.join(table_dir, "decay.pkl") as f: + with open(os.path.join(table_dir, "decay.pkl")) as f: pickle.dump(f, { "decay_integrator": self.decay_integrator, "decay_norm": self.decay_norm @@ -94,7 +96,7 @@ def DifferentialDecayWidth(self, record): # Momentum variables of HNL necessary for calculating decay phase space PN = np.array(record.primary_momentum) - if type(self.dec_case) == FermionSinglePhotonDecay: + if isinstance(self.dec_case, FermionSinglePhotonDecay): gamma_idx = 0 for secondary in record.signature.secondary_types: if secondary == dataclasses.Particle.ParticleType.Gamma: @@ -107,7 +109,7 @@ def DifferentialDecayWidth(self, record): Pgamma = np.array(record.secondary_momenta[gamma_idx]) momenta = np.expand_dims(PN, 0), np.expand_dims(Pgamma, 0) - elif type(self.dec_case) == FermionDileptonDecay: + elif isinstance(self.dec_case, FermionDileptonDecay): lepminus_idx = -1 lepplus_idx = -1 nu_idx = -1 @@ -144,9 +146,9 @@ def DifferentialDecayWidth(self, record): return self.dec_case.differential_width(momenta) def TotalDecayWidth(self, arg1): - if type(arg1) == dataclasses.InteractionRecord: + if isinstance(arg1, dataclasses.InteractionRecord): primary = arg1.signature.primary_type - elif type(arg1) == dataclasses.Particle.ParticleType: + elif isinstance(arg1, dataclasses.Particle.ParticleType): primary = arg1 else: print("Incorrect function call to TotalDecayWidth!") @@ -155,7 +157,7 @@ def TotalDecayWidth(self, arg1): return 0 if self.total_width is None: # Need to set the total width - if type(self.dec_case) == FermionDileptonDecay and ( + if isinstance(self.dec_case, FermionDileptonDecay) and ( self.dec_case.vector_off_shell and self.dec_case.scalar_off_shell ): # total width calculation requires evaluating an integral @@ -194,9 +196,9 @@ def TotalDecayWidthForFinalState(self, record): return ret def DensityVariables(self): - if type(self.dec_case) == FermionSinglePhotonDecay: + if isinstance(self.dec_case, FermionSinglePhotonDecay): return "cost" - elif type(self.dec_case) == FermionDileptonDecay: + elif isinstance(self.dec_case, FermionDileptonDecay): if self.dec_case.vector_on_shell and self.dec_case.scalar_on_shell: print("Can't have both the scalar and vector on shell") exit(0) @@ -223,6 +225,23 @@ def GetPSSample(self, random): PSidx = np.argmax(x - self.PS_weights_CDF <= 0) return self.PS_samples[:, PSidx] + def GetPSSample(self, random): + # Make the PS weight CDF if that hasn't been done + if self.PS_weights_CDF is None: + self.PS_weights_CDF = np.cumsum(self.PS_weights) + + # Check that the CDF makes sense + total_weight = self.PS_weights_CDF[-1] + if total_weight == 0: + raise ValueError("Total weight is zero, cannot sample") + + # Random number to determine + x = random.Uniform(0, total_weight) + + # find first instance of a CDF entry greater than x + PSidx = np.argmax(x - self.PS_weights_CDF <= 0) + return self.PS_samples[:, PSidx] + def SampleRecordFromDarkNews(self, record, random): # First, make sure we have PS samples and weights if self.PS_samples is None or self.PS_weights is None: @@ -254,7 +273,7 @@ def SampleRecordFromDarkNews(self, record, random): secondaries = record.GetSecondaryParticleRecords() - if type(self.dec_case) == FermionSinglePhotonDecay: + if isinstance(self.dec_case, FermionSinglePhotonDecay): gamma_idx = 0 for secondary in record.signature.secondary_types: if secondary == dataclasses.Particle.ParticleType.Gamma: @@ -269,7 +288,7 @@ def SampleRecordFromDarkNews(self, record, random): secondaries[nu_idx].four_momentum = np.squeeze(four_momenta["P_decay_N_daughter"]) secondaries[nu_idx].mass = 0 - elif type(self.dec_case) == FermionDileptonDecay: + elif isinstance(self.dec_case, FermionDileptonDecay): lepminus_idx = -1 lepplus_idx = -1 nu_idx = -1 From fa099a43f53eee2b4db9e84d20eee17632714302 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 28 Aug 2024 23:02:36 -0600 Subject: [PATCH 20/94] Avoid repeated use of np.append --- .../DarkNewsTables/DarkNewsCrossSection.py | 51 ++++++++++--------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/resources/Processes/DarkNewsTables/DarkNewsCrossSection.py b/resources/Processes/DarkNewsTables/DarkNewsCrossSection.py index 694ccb099..dfb5dc482 100644 --- a/resources/Processes/DarkNewsTables/DarkNewsCrossSection.py +++ b/resources/Processes/DarkNewsTables/DarkNewsCrossSection.py @@ -2,6 +2,7 @@ import numpy as np import functools from scipy.interpolate import LinearNDInterpolator, PchipInterpolator +from typing import List, Tuple from siren import _util @@ -17,6 +18,7 @@ # DarkNews methods from DarkNews import phase_space + # A class representing a single ups_case DarkNews class # Only handles methods concerning the upscattering part class PyDarkNewsCrossSection(DarkNewsCrossSection): @@ -51,9 +53,7 @@ def load_from_table(self, table_dir): total_xsec_file = os.path.join(table_dir, "total_cross_sections.npy") if os.path.exists(total_xsec_file): self.total_cross_section_table = np.load(total_xsec_file) - diff_xsec_file = os.path.join( - table_dir, "differential_cross_sections.npy" - ) + diff_xsec_file = os.path.join(table_dir, "differential_cross_sections.npy") if os.path.exists(diff_xsec_file): self.differential_cross_section_table = np.load(diff_xsec_file) @@ -62,9 +62,7 @@ def load_from_table(self, table_dir): def save_to_table(self, table_dir, total=True, diff=True): if total: self._redefine_interpolation_objects(total=True) - with open( - os.path.join(table_dir, "total_cross_sections.npy"), "wb" - ) as f: + with open(os.path.join(table_dir, "total_cross_sections.npy"), "wb") as f: np.save(f, self.total_cross_section_table) if diff: self._redefine_interpolation_objects(diff=True) @@ -91,7 +89,6 @@ def get_representation(self): # tolerance, interp_tolerance, always_interpolate # kwargs argument can be used to set any of these def configure(self, **kwargs): - for k, v in kwargs.items(): self.__setattr__(k, v) @@ -254,22 +251,22 @@ def _query_interpolation_table(self, inputs, mode): else: return -1 - def FillTableAtEnergy(self, E, total=True, diff=True, factor=0.8): + def FillTableAtEnergy( + self, E: float, total: bool = True, diff: bool = True, factor: float = 0.8 + ) -> int: num_added_points = 0 + new_total_points: List[Tuple[float, float]] = [] + new_diff_points: List[Tuple[float, float, float]] = [] + if total: xsec = self.ups_case.total_xsec(E) - self.total_cross_section_table = np.append( - self.total_cross_section_table, [[E, xsec]], axis=0 - ) + new_total_points.append((E, xsec)) num_added_points += 1 + if diff: interaction = dataclasses.InteractionRecord() - interaction.signature.primary_type = self.GetPossiblePrimaries()[ - 0 - ] # only one primary - interaction.signature.target_type = self.GetPossibleTargets()[ - 0 - ] # only one target + interaction.signature.primary_type = self.GetPossiblePrimaries()[0] + interaction.signature.target_type = self.GetPossibleTargets()[0] interaction.target_mass = self.ups_case.MA interaction.primary_momentum = [E, 0, 0, 0] zmin, zmax = self.tolerance, 1 @@ -279,13 +276,19 @@ def FillTableAtEnergy(self, E, total=True, diff=True, factor=0.8): while z < zmax: Q2 = Q2min + z * (Q2max - Q2min) dxsec = self.ups_case.diff_xsec_Q2(E, Q2).item() - self.differential_cross_section_table = np.append( - self.differential_cross_section_table, - [[E, z, dxsec]], - axis=0, - ) + new_diff_points.append((E, z, dxsec)) num_added_points += 1 z *= 1 + factor * self.interp_tolerance + + if new_total_points: + self.total_cross_section_table = np.vstack( + (self.total_cross_section_table, new_total_points) + ) + if new_diff_points: + self.differential_cross_section_table = np.vstack( + (self.differential_cross_section_table, new_diff_points) + ) + self._redefine_interpolation_objects(total=total, diff=diff) return num_added_points @@ -473,8 +476,8 @@ def TotalCrossSection(self, arg1, energy=None, target=None): # If we have reached this block, we must compute the cross section using DarkNews xsec = self.ups_case.total_xsec(energy) - self.total_cross_section_table = np.append( - self.total_cross_section_table, [[energy, xsec]], axis=0 + self.total_cross_section_table = np.vstack( + (self.total_cross_section_table, [[energy, xsec]]) ) self._redefine_interpolation_objects(total=True) return xsec From 5fbf8e4d43bcf8f7b4b93ef822894c6fe2823cfb Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 28 Aug 2024 23:09:11 -0600 Subject: [PATCH 21/94] Override logging in our own copy of ModelContainer --- python/DNModelContainer.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/python/DNModelContainer.py b/python/DNModelContainer.py index 73f6f779c..49482b060 100644 --- a/python/DNModelContainer.py +++ b/python/DNModelContainer.py @@ -552,8 +552,15 @@ def configure_logger( ValueError: _description_ """ - loglevel = loglevel.upper() - _numeric_level = getattr(logging, loglevel, None) + # override default loglevel + loglevel = logging.WARNING + + if isinstance(loglevel, int): + _numeric_level = loglevel + elif isinstance(loglevel, str): + loglevel = loglevel.upper() + _numeric_level = getattr(logging, loglevel, None) + if not isinstance(_numeric_level, int): raise ValueError("Invalid log level: %s" % self.loglevel) logger.setLevel(_numeric_level) From 811780d2f66188e0dc1188e38dfea8340c6b43bd Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 28 Aug 2024 23:12:12 -0600 Subject: [PATCH 22/94] Check for DarkNews.ModelContainer.configure_logger in case it is removed in the future. --- resources/Processes/DarkNewsTables/logger.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/resources/Processes/DarkNewsTables/logger.py b/resources/Processes/DarkNewsTables/logger.py index bdd03c096..5f9ee80ba 100644 --- a/resources/Processes/DarkNewsTables/logger.py +++ b/resources/Processes/DarkNewsTables/logger.py @@ -1,12 +1,18 @@ # Monkey patch DarkNews logger to hide printouts import functools -from DarkNews.ModelContainer import ModelContainer -ModelContainer_configure_logger = ModelContainer.configure_logger +dn_has_modelcontainer_logger = False +try: + from DarkNews.ModelContainer import ModelContainer + ModelContainer_configure_logger = ModelContainer.configure_logger + dn_has_modelcontainer_logger = True +except: + pass -@functools.wraps(ModelContainer.configure_logger) -def suppress_info(self, logger, loglevel="INFO", prettyprinter=None, logfile=None, verbose=False): - return ModelContainer_configure_logger(self, logger, loglevel="WARNING", prettyprinter=prettyprinter, logfile=logfile, verbose=verbose) +if dn_has_modelcontainer_logger: + @functools.wraps(ModelContainer.configure_logger) + def suppress_info(self, logger, loglevel="INFO", prettyprinter=None, logfile=None, verbose=False): + return ModelContainer_configure_logger(self, logger, loglevel="WARNING", prettyprinter=prettyprinter, logfile=logfile, verbose=verbose) -ModelContainer.configure_logger = suppress_info + ModelContainer.configure_logger = suppress_info From 0b6f53dcfe845bc4060e9306e4ec52a0432696f3 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Thu, 29 Aug 2024 21:27:44 -0600 Subject: [PATCH 23/94] Move detector files --- .../densities_ATLAS-v1.dat} | 0 .../materials_ATLAS-v1.dat} | 0 .../CCM-v1.dat => CCM/densities_CCM-v1.dat} | 0 .../CCM-v2.dat => CCM/densities_CCM-v2.dat} | 0 .../CCM-v1.dat => CCM/materials_CCM-v1.dat} | 0 resources/Detectors/CCM/materials_CCM-v2.dat | 54 +++++++++++++++++++ .../densities_DUNEFD-v1.dat} | 0 .../materials_DUNEFD-v1.dat} | 0 .../densities_HyperK-v1.dat} | 0 .../materials_HyperK-v1.dat} | 0 .../densities_IceCube-v1.dat} | 0 .../materials_IceCube-v1.dat} | 0 .../densities_MINERvA-v1.dat} | 0 .../materials_MINERvA-v1.dat} | 0 .../densities_MiniBooNE-v1.dat} | 0 .../materials_MiniBooNE-v1.dat} | 0 .../{densities/README => README_densities} | 0 .../{materials/README => README_materials} | 0 18 files changed, 54 insertions(+) rename resources/Detectors/{densities/ATLAS/ATLAS-v1.dat => ATLAS/densities_ATLAS-v1.dat} (100%) rename resources/Detectors/{materials/ATLAS/ATLAS-v1.dat => ATLAS/materials_ATLAS-v1.dat} (100%) rename resources/Detectors/{densities/CCM/CCM-v1.dat => CCM/densities_CCM-v1.dat} (100%) rename resources/Detectors/{densities/CCM/CCM-v2.dat => CCM/densities_CCM-v2.dat} (100%) rename resources/Detectors/{materials/CCM/CCM-v1.dat => CCM/materials_CCM-v1.dat} (100%) create mode 100644 resources/Detectors/CCM/materials_CCM-v2.dat rename resources/Detectors/{densities/DUNEFD/DUNEFD-v1.dat => DUNEFD/densities_DUNEFD-v1.dat} (100%) rename resources/Detectors/{materials/DUNEFD/DUNEFD-v1.dat => DUNEFD/materials_DUNEFD-v1.dat} (100%) rename resources/Detectors/{densities/HyperK/HyperK-v1.dat => HyperK/densities_HyperK-v1.dat} (100%) rename resources/Detectors/{materials/HyperK/HyperK-v1.dat => HyperK/materials_HyperK-v1.dat} (100%) rename resources/Detectors/{densities/IceCube/IceCube-v1.dat => IceCube/densities_IceCube-v1.dat} (100%) rename resources/Detectors/{materials/IceCube/IceCube-v1.dat => IceCube/materials_IceCube-v1.dat} (100%) rename resources/Detectors/{densities/MINERvA/MINERvA-v1.dat => MINERvA/densities_MINERvA-v1.dat} (100%) rename resources/Detectors/{materials/MINERvA/MINERvA-v1.dat => MINERvA/materials_MINERvA-v1.dat} (100%) rename resources/Detectors/{densities/MiniBooNE/MiniBooNE-v1.dat => MiniBooNE/densities_MiniBooNE-v1.dat} (100%) rename resources/Detectors/{materials/MiniBooNE/MiniBooNE-v1.dat => MiniBooNE/materials_MiniBooNE-v1.dat} (100%) rename resources/Detectors/{densities/README => README_densities} (100%) rename resources/Detectors/{materials/README => README_materials} (100%) diff --git a/resources/Detectors/densities/ATLAS/ATLAS-v1.dat b/resources/Detectors/ATLAS/densities_ATLAS-v1.dat similarity index 100% rename from resources/Detectors/densities/ATLAS/ATLAS-v1.dat rename to resources/Detectors/ATLAS/densities_ATLAS-v1.dat diff --git a/resources/Detectors/materials/ATLAS/ATLAS-v1.dat b/resources/Detectors/ATLAS/materials_ATLAS-v1.dat similarity index 100% rename from resources/Detectors/materials/ATLAS/ATLAS-v1.dat rename to resources/Detectors/ATLAS/materials_ATLAS-v1.dat diff --git a/resources/Detectors/densities/CCM/CCM-v1.dat b/resources/Detectors/CCM/densities_CCM-v1.dat similarity index 100% rename from resources/Detectors/densities/CCM/CCM-v1.dat rename to resources/Detectors/CCM/densities_CCM-v1.dat diff --git a/resources/Detectors/densities/CCM/CCM-v2.dat b/resources/Detectors/CCM/densities_CCM-v2.dat similarity index 100% rename from resources/Detectors/densities/CCM/CCM-v2.dat rename to resources/Detectors/CCM/densities_CCM-v2.dat diff --git a/resources/Detectors/materials/CCM/CCM-v1.dat b/resources/Detectors/CCM/materials_CCM-v1.dat similarity index 100% rename from resources/Detectors/materials/CCM/CCM-v1.dat rename to resources/Detectors/CCM/materials_CCM-v1.dat diff --git a/resources/Detectors/CCM/materials_CCM-v2.dat b/resources/Detectors/CCM/materials_CCM-v2.dat new file mode 100644 index 000000000..a1c3649e2 --- /dev/null +++ b/resources/Detectors/CCM/materials_CCM-v2.dat @@ -0,0 +1,54 @@ +# Material model file +# Detector: CCM +# Version: v2 +# Date: 2023-03-18 +# Authors: Nicholas Kamp +# Notes: +# Uses PREM model of the Earth, assumes a single far detector with the liquid argon embedded directly in the roc + +ARGON 1 # CCM Argon +1000180400 1.0000000 # Ar40 100.0%% + +STEEL 4 # Mostly Fe +1000060120 0.0013000 # C12 0.13% +1000140280 0.0020000 # Si28 0.2% +1000250550 0.0100000 # Mn55 1.0% +1000260560 0.9870000 # Fe56 98.7% + +LEAD 2 # Mostly Pb +1000822080 0.9995000 # Pb208 99.95% +1000290630 0.0005000 # Cu63 0.05% + +GRAPHITE 1 # Essentially Carbon +1000060120 1.0000000 # C12 100% + +WATER 2 # H20 +1000010010 0.1150000 # H1 11.5% +1000080160 0.8850000 # 016 88.5% + +AIR 2 # N2 + O2 +1000070140 0.7562326 # N2 78% in volume +1000080160 0.2437674 # O2 22% in volume + +# Guess based on https://mcnp.lanl.gov/pdf_files/la-ur-07-5898.pdf +CONCRETE 7 # mostly SiO2 +1000010010 0.0045300 # H1 0.453% +1000080160 0.5126000 # 016 51.26% +1000110230 0.0152700 # Na23 1.527% +1000130270 0.0355500 # Al27 3.555% +1000140280 0.3603600 # Si28 36.036% +1000200400 0.0579100 # Ca40 5.791% +1000260560 0.0137800 # Fe56 1.378% + +ALUMINUM 1 # pure Al +1000130270 1.0000000 # Al27 100% + +BERYLLIUM 1 # pure Be +1000040090 1.0000000 # Be9 100% + +TUNGSTEN 1 # pure W +1000741830 1.0000000 # W183 100% + +POLY 2 # C2H4 +1000060120 0.8571400 # C12 85.714% +1000010010 0.1428600 # H1 14.286% diff --git a/resources/Detectors/densities/DUNEFD/DUNEFD-v1.dat b/resources/Detectors/DUNEFD/densities_DUNEFD-v1.dat similarity index 100% rename from resources/Detectors/densities/DUNEFD/DUNEFD-v1.dat rename to resources/Detectors/DUNEFD/densities_DUNEFD-v1.dat diff --git a/resources/Detectors/materials/DUNEFD/DUNEFD-v1.dat b/resources/Detectors/DUNEFD/materials_DUNEFD-v1.dat similarity index 100% rename from resources/Detectors/materials/DUNEFD/DUNEFD-v1.dat rename to resources/Detectors/DUNEFD/materials_DUNEFD-v1.dat diff --git a/resources/Detectors/densities/HyperK/HyperK-v1.dat b/resources/Detectors/HyperK/densities_HyperK-v1.dat similarity index 100% rename from resources/Detectors/densities/HyperK/HyperK-v1.dat rename to resources/Detectors/HyperK/densities_HyperK-v1.dat diff --git a/resources/Detectors/materials/HyperK/HyperK-v1.dat b/resources/Detectors/HyperK/materials_HyperK-v1.dat similarity index 100% rename from resources/Detectors/materials/HyperK/HyperK-v1.dat rename to resources/Detectors/HyperK/materials_HyperK-v1.dat diff --git a/resources/Detectors/densities/IceCube/IceCube-v1.dat b/resources/Detectors/IceCube/densities_IceCube-v1.dat similarity index 100% rename from resources/Detectors/densities/IceCube/IceCube-v1.dat rename to resources/Detectors/IceCube/densities_IceCube-v1.dat diff --git a/resources/Detectors/materials/IceCube/IceCube-v1.dat b/resources/Detectors/IceCube/materials_IceCube-v1.dat similarity index 100% rename from resources/Detectors/materials/IceCube/IceCube-v1.dat rename to resources/Detectors/IceCube/materials_IceCube-v1.dat diff --git a/resources/Detectors/densities/MINERvA/MINERvA-v1.dat b/resources/Detectors/MINERvA/densities_MINERvA-v1.dat similarity index 100% rename from resources/Detectors/densities/MINERvA/MINERvA-v1.dat rename to resources/Detectors/MINERvA/densities_MINERvA-v1.dat diff --git a/resources/Detectors/materials/MINERvA/MINERvA-v1.dat b/resources/Detectors/MINERvA/materials_MINERvA-v1.dat similarity index 100% rename from resources/Detectors/materials/MINERvA/MINERvA-v1.dat rename to resources/Detectors/MINERvA/materials_MINERvA-v1.dat diff --git a/resources/Detectors/densities/MiniBooNE/MiniBooNE-v1.dat b/resources/Detectors/MiniBooNE/densities_MiniBooNE-v1.dat similarity index 100% rename from resources/Detectors/densities/MiniBooNE/MiniBooNE-v1.dat rename to resources/Detectors/MiniBooNE/densities_MiniBooNE-v1.dat diff --git a/resources/Detectors/materials/MiniBooNE/MiniBooNE-v1.dat b/resources/Detectors/MiniBooNE/materials_MiniBooNE-v1.dat similarity index 100% rename from resources/Detectors/materials/MiniBooNE/MiniBooNE-v1.dat rename to resources/Detectors/MiniBooNE/materials_MiniBooNE-v1.dat diff --git a/resources/Detectors/densities/README b/resources/Detectors/README_densities similarity index 100% rename from resources/Detectors/densities/README rename to resources/Detectors/README_densities diff --git a/resources/Detectors/materials/README b/resources/Detectors/README_materials similarity index 100% rename from resources/Detectors/materials/README rename to resources/Detectors/README_materials From 8a39ee4946c8f89953a2cf522fab8a3c8ed94172 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Thu, 29 Aug 2024 21:36:53 -0600 Subject: [PATCH 24/94] Move detector files into subfolders --- .../ATLAS/{densities_ATLAS-v1.dat => ATLAS-v1/densities.dat} | 0 .../ATLAS/{materials_ATLAS-v1.dat => ATLAS-v1/materials.dat} | 0 .../Detectors/CCM/{densities_CCM-v1.dat => CCM-v1/densities.dat} | 0 .../Detectors/CCM/{materials_CCM-v1.dat => CCM-v1/materials.dat} | 0 .../DUNEFD/{densities_DUNEFD-v1.dat => DUNEFD-v1/densities.dat} | 0 .../DUNEFD/{materials_DUNEFD-v1.dat => DUNEFD-v1/materials.dat} | 0 .../HyperK/{densities_HyperK-v1.dat => HyperK-v1/densities.dat} | 0 .../HyperK/{materials_HyperK-v1.dat => HyperK-v1/materials.dat} | 0 .../{densities_IceCube-v1.dat => IceCube-v1/densities.dat} | 0 .../{materials_IceCube-v1.dat => IceCube-v1/materials.dat} | 0 .../{densities_MINERvA-v1.dat => MINERvA-v1/densities.dat} | 0 .../{materials_MINERvA-v1.dat => MINERvA-v1/materials.dat} | 0 .../{densities_MiniBooNE-v1.dat => MiniBooNE-v1/densities.dat} | 0 .../{materials_MiniBooNE-v1.dat => MiniBooNE-v1/materials.dat} | 0 14 files changed, 0 insertions(+), 0 deletions(-) rename resources/Detectors/ATLAS/{densities_ATLAS-v1.dat => ATLAS-v1/densities.dat} (100%) rename resources/Detectors/ATLAS/{materials_ATLAS-v1.dat => ATLAS-v1/materials.dat} (100%) rename resources/Detectors/CCM/{densities_CCM-v1.dat => CCM-v1/densities.dat} (100%) rename resources/Detectors/CCM/{materials_CCM-v1.dat => CCM-v1/materials.dat} (100%) rename resources/Detectors/DUNEFD/{densities_DUNEFD-v1.dat => DUNEFD-v1/densities.dat} (100%) rename resources/Detectors/DUNEFD/{materials_DUNEFD-v1.dat => DUNEFD-v1/materials.dat} (100%) rename resources/Detectors/HyperK/{densities_HyperK-v1.dat => HyperK-v1/densities.dat} (100%) rename resources/Detectors/HyperK/{materials_HyperK-v1.dat => HyperK-v1/materials.dat} (100%) rename resources/Detectors/IceCube/{densities_IceCube-v1.dat => IceCube-v1/densities.dat} (100%) rename resources/Detectors/IceCube/{materials_IceCube-v1.dat => IceCube-v1/materials.dat} (100%) rename resources/Detectors/MINERvA/{densities_MINERvA-v1.dat => MINERvA-v1/densities.dat} (100%) rename resources/Detectors/MINERvA/{materials_MINERvA-v1.dat => MINERvA-v1/materials.dat} (100%) rename resources/Detectors/MiniBooNE/{densities_MiniBooNE-v1.dat => MiniBooNE-v1/densities.dat} (100%) rename resources/Detectors/MiniBooNE/{materials_MiniBooNE-v1.dat => MiniBooNE-v1/materials.dat} (100%) diff --git a/resources/Detectors/ATLAS/densities_ATLAS-v1.dat b/resources/Detectors/ATLAS/ATLAS-v1/densities.dat similarity index 100% rename from resources/Detectors/ATLAS/densities_ATLAS-v1.dat rename to resources/Detectors/ATLAS/ATLAS-v1/densities.dat diff --git a/resources/Detectors/ATLAS/materials_ATLAS-v1.dat b/resources/Detectors/ATLAS/ATLAS-v1/materials.dat similarity index 100% rename from resources/Detectors/ATLAS/materials_ATLAS-v1.dat rename to resources/Detectors/ATLAS/ATLAS-v1/materials.dat diff --git a/resources/Detectors/CCM/densities_CCM-v1.dat b/resources/Detectors/CCM/CCM-v1/densities.dat similarity index 100% rename from resources/Detectors/CCM/densities_CCM-v1.dat rename to resources/Detectors/CCM/CCM-v1/densities.dat diff --git a/resources/Detectors/CCM/materials_CCM-v1.dat b/resources/Detectors/CCM/CCM-v1/materials.dat similarity index 100% rename from resources/Detectors/CCM/materials_CCM-v1.dat rename to resources/Detectors/CCM/CCM-v1/materials.dat diff --git a/resources/Detectors/DUNEFD/densities_DUNEFD-v1.dat b/resources/Detectors/DUNEFD/DUNEFD-v1/densities.dat similarity index 100% rename from resources/Detectors/DUNEFD/densities_DUNEFD-v1.dat rename to resources/Detectors/DUNEFD/DUNEFD-v1/densities.dat diff --git a/resources/Detectors/DUNEFD/materials_DUNEFD-v1.dat b/resources/Detectors/DUNEFD/DUNEFD-v1/materials.dat similarity index 100% rename from resources/Detectors/DUNEFD/materials_DUNEFD-v1.dat rename to resources/Detectors/DUNEFD/DUNEFD-v1/materials.dat diff --git a/resources/Detectors/HyperK/densities_HyperK-v1.dat b/resources/Detectors/HyperK/HyperK-v1/densities.dat similarity index 100% rename from resources/Detectors/HyperK/densities_HyperK-v1.dat rename to resources/Detectors/HyperK/HyperK-v1/densities.dat diff --git a/resources/Detectors/HyperK/materials_HyperK-v1.dat b/resources/Detectors/HyperK/HyperK-v1/materials.dat similarity index 100% rename from resources/Detectors/HyperK/materials_HyperK-v1.dat rename to resources/Detectors/HyperK/HyperK-v1/materials.dat diff --git a/resources/Detectors/IceCube/densities_IceCube-v1.dat b/resources/Detectors/IceCube/IceCube-v1/densities.dat similarity index 100% rename from resources/Detectors/IceCube/densities_IceCube-v1.dat rename to resources/Detectors/IceCube/IceCube-v1/densities.dat diff --git a/resources/Detectors/IceCube/materials_IceCube-v1.dat b/resources/Detectors/IceCube/IceCube-v1/materials.dat similarity index 100% rename from resources/Detectors/IceCube/materials_IceCube-v1.dat rename to resources/Detectors/IceCube/IceCube-v1/materials.dat diff --git a/resources/Detectors/MINERvA/densities_MINERvA-v1.dat b/resources/Detectors/MINERvA/MINERvA-v1/densities.dat similarity index 100% rename from resources/Detectors/MINERvA/densities_MINERvA-v1.dat rename to resources/Detectors/MINERvA/MINERvA-v1/densities.dat diff --git a/resources/Detectors/MINERvA/materials_MINERvA-v1.dat b/resources/Detectors/MINERvA/MINERvA-v1/materials.dat similarity index 100% rename from resources/Detectors/MINERvA/materials_MINERvA-v1.dat rename to resources/Detectors/MINERvA/MINERvA-v1/materials.dat diff --git a/resources/Detectors/MiniBooNE/densities_MiniBooNE-v1.dat b/resources/Detectors/MiniBooNE/MiniBooNE-v1/densities.dat similarity index 100% rename from resources/Detectors/MiniBooNE/densities_MiniBooNE-v1.dat rename to resources/Detectors/MiniBooNE/MiniBooNE-v1/densities.dat diff --git a/resources/Detectors/MiniBooNE/materials_MiniBooNE-v1.dat b/resources/Detectors/MiniBooNE/MiniBooNE-v1/materials.dat similarity index 100% rename from resources/Detectors/MiniBooNE/materials_MiniBooNE-v1.dat rename to resources/Detectors/MiniBooNE/MiniBooNE-v1/materials.dat From 6c7d3465011d8d81dde10fb5df42e696a2e8e47c Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Fri, 30 Aug 2024 13:52:46 -0600 Subject: [PATCH 25/94] Add load_* methods to siren.utilities --- python/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/__init__.py b/python/__init__.py index 14689b726..411d6aa37 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -25,6 +25,8 @@ utilities.get_processes_model_path = _util.get_processes_model_path utilities.get_flux_model_path = _util.get_flux_model_path utilities.load_flux = _util.load_flux +utilities.load_detector = _util.load_detector +utilities.load_processes = _util.load_processes def darknews_version(): try: From 049325538a3d709bce3aea48947393bbf9905144 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Fri, 30 Aug 2024 13:53:55 -0600 Subject: [PATCH 26/94] Refactor model path search to just handle folders. Add special load_ function for the detector models --- python/_util.py | 130 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 1 deletion(-) diff --git a/python/_util.py b/python/_util.py index 40d4db571..131ef679f 100644 --- a/python/_util.py +++ b/python/_util.py @@ -464,6 +464,8 @@ def _find_model_folder_and_file(base_dir, model_name, must_exist, specific_file= specific_file_path = os.path.join(base_dir, name, specific_file) if os.path.isfile(specific_file_path): return name, True, specific_file_path + else: + return name, True, None else: return name, True, None else: @@ -557,6 +559,108 @@ def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exi return os.path.join(base_dir, model_name, model_file_name) +def _get_model_folder(base_dir, model_name, must_exist): + model_names = [ + f for f in os.listdir(base_dir) if os.path.isdir(os.path.join(base_dir, f)) + ] + + exact_model_names = [f for f in model_names if f.lower() == model_name.lower()] + + if len(exact_model_names) == 0: + model_names = [f for f in model_names if f.lower().startswith(model_name.lower())] + else: + model_names = exact_model_names + + if len(model_names) == 0 and must_exist: + raise ValueError(f"No model folders found for {model_name}\nSearched in {base_dir}") + elif len(model_names) == 0 and not must_exist: + return model_name, False + elif len(model_names) == 1: + return model_names[0], True + else: + raise ValueError(f"Multiple directories found for {model_name}\nSearched in {base_dir}") + +def _get_model_subfolders(base_dir, model_regex): + model_subfolders = [ + f for f in os.listdir(base_dir) if os.path.isdir(os.path.join(base_dir, f)) + ] + model_subfolders = [ + f for f in model_subfolders if model_regex.match(f) is not None + ] + return model_subfolders + + +def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exist=True, specific_file=None): + _model_regex = re.compile( + r"^\s*" + _MODEL_PATTERN + ("" if suffix is None else r"(?:" + suffix + r")?") + r"\s*$", + re.VERBOSE | re.IGNORECASE, + ) + suffix = "" if suffix is None else suffix + + resources_dir = resource_package_dir() + base_dir = _get_base_directory(resources_dir, prefix) + + d = _model_regex.match(model_name) + if d is None: + raise ValueError(f"Invalid model name: {model_name}") + d = d.groupdict() + model_search_name, version = d["model_name"], d["version"] + + if version is not None: + version = normalize_version(version) + + found_model_name, folder_exists = _get_model_folder(base_dir, model_search_name, must_exist) + + model_dir = os.path.join(base_dir, found_model_name) + + if not must_exist and not folder_exists: + if version is None: + version = "v1" + + model_dir = os.path.join(model_dir, f"{found_model_name}-v{version}") + return model_dir + + + model_subfolders = _get_model_subfolders(model_dir, _model_regex) + + if len(model_subfolders) == 0: + if must_exist: + raise ValueError(f"No model folders found for {model_search_name}\nSearched in {model_dir}") + else: + if version is None: + version = "v1" + + model_dir = os.path.join(model_dir, f"{found_model_name}-v{version}") + return model_dir + + models_and_versions = [] + for f in model_subfolders: + d = _model_regex.match(f).groupdict() + if d["version"] is not None: + models_and_versions.append((f, normalize_version(d["version"]))) + + matching_models = [(m, v) for m, v in models_and_versions if v == version] + + if len(matching_models) == 1: + model_dir = os.path.join(model_dir, matching_models[0][0]) + return model_dir + elif len(matching_models) > 1: + raise ValueError(f"Multiple directories found for {model_search_name} with version {version}\nSearched in {model_dir}") + + top_level_has_specific_file = specific_file is not None and os.path.isfile(os.path.join(model_dir, specific_file)) + + if top_level_has_specific_file: + return model_dir + + if len(matching_models) == 0: + if must_exist and version is not None: + raise ValueError(f"No model folders found for {model_search_name} with version {version}\nSearched in {model_dir}") + + found_model_subfolder, subfolder_version = max(models_and_versions, key=lambda x: tokenize_version(x[1])) + + return os.path.join(model_dir, found_model_subfolder) + + def get_detector_model_file_path(model_name, must_exist=True): return _get_model_path(model_name, prefix="Detectors/densities", suffix=".dat", is_file=True, must_exist=must_exist) @@ -604,7 +708,31 @@ def load_flux(model_name, *args, **kwargs): def load_detector(model_name, *args, **kwargs): - return load_resource("detector", model_name, *args, **kwargs) + resource_type = "detector" + resource_name = model_name + folder = _resource_folder_by_name[resource_type] + specific_file = f"{resource_type}.py" + + abs_dir = _get_model_path(resource_name, prefix=folder, is_file=False, must_exist=True, specific_file=specific_file) + + script_fname = os.path.join(abs_dir, f"{resource_type}.py") + if os.path.isfile(script_fname): + resource_module = load_module(f"siren-{resource_type}-{resource_name}", script_fname, persist=False) + loader = getattr(resource_module, f"load_{resource_type}") + resource = loader(*args, **kwargs) + return resource + + densities_fname = os.path.join(abs_dir, "densities.dat") + materials_fname = os.path.join(abs_dir, "materials.dat") + + if os.path.isfile(densities_fname) and os.path.isfile(materials_fname): + from . import detector as _detector + detector_model = _detector.DetectorModel() + detector_model.LoadMaterialModel(materials_fname) + detector_model.LoadDetectorModel(densities_fname) + return detector_model + + raise ValueError("Could not find detector loading script \"{script_fname}\" or densities and materials files \"{densities_fname}\", \"materials_fname\"") def load_processes(model_name, *args, **kwargs): From b59d9d6270aeda31436c54830d58383f37988dee Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Fri, 30 Aug 2024 15:48:48 -0600 Subject: [PATCH 27/94] Need to defined is_configured ahead of time --- resources/Processes/DarkNewsTables/DarkNewsCrossSection.py | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/Processes/DarkNewsTables/DarkNewsCrossSection.py b/resources/Processes/DarkNewsTables/DarkNewsCrossSection.py index dfb5dc482..fbc4476c1 100644 --- a/resources/Processes/DarkNewsTables/DarkNewsCrossSection.py +++ b/resources/Processes/DarkNewsTables/DarkNewsCrossSection.py @@ -31,6 +31,7 @@ def __init__( ): DarkNewsCrossSection.__init__(self) # C++ constructor + self.is_configured = False self.ups_case = ups_case self.tolerance = tolerance self.interp_tolerance = interp_tolerance From 8cb75a59258b44db3d77d8173025aa3114649634 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Fri, 30 Aug 2024 15:51:37 -0600 Subject: [PATCH 28/94] Pass nuclear targets to ModelContainer. Typo "s" --- resources/Processes/DarkNewsTables/processes.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/Processes/DarkNewsTables/processes.py b/resources/Processes/DarkNewsTables/processes.py index ff0ce8d66..d5bcce35b 100644 --- a/resources/Processes/DarkNewsTables/processes.py +++ b/resources/Processes/DarkNewsTables/processes.py @@ -207,7 +207,7 @@ def attempt_to_load_cross_section( break elif p == "normal": try: - cross_sections = load_cross_section( + cross_section = load_cross_section( models, ups_key, tolerance=tolerance, @@ -433,6 +433,7 @@ def load_processes( table_dir = os.path.join(base_path, "Dipole_M%2.2e_mu%2.2e" % (m4, mu_tr_mu4)) models = ModelContainer( + nuclear_targets=nuclear_targets, m4=m4, mu_tr_mu4=mu_tr_mu4, UD4=UD4, From a271cff4e4f01af91f75dfa0c7ca85756d98f7ae Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Fri, 30 Aug 2024 16:47:33 -0600 Subject: [PATCH 29/94] Inherit from a common Interaction class to enable a more concise constructor --- .../interactions/private/CrossSection.cxx | 2 +- .../private/InteractionCollection.cxx | 18 ++++++++++++++ .../public/SIREN/interactions/CrossSection.h | 5 +++- .../public/SIREN/interactions/Decay.h | 5 +++- .../public/SIREN/interactions/Interaction.h | 24 +++++++++++++++++++ .../interactions/InteractionCollection.h | 1 + 6 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 projects/interactions/public/SIREN/interactions/Interaction.h diff --git a/projects/interactions/private/CrossSection.cxx b/projects/interactions/private/CrossSection.cxx index dfcbf49f6..2d0a3fdac 100644 --- a/projects/interactions/private/CrossSection.cxx +++ b/projects/interactions/private/CrossSection.cxx @@ -31,4 +31,4 @@ bool CrossSection::operator==(CrossSection const & other) const { } } // namespace interactions -} // namespace siren \ No newline at end of file +} // namespace siren diff --git a/projects/interactions/private/InteractionCollection.cxx b/projects/interactions/private/InteractionCollection.cxx index 0f68772ba..9a3464a73 100644 --- a/projects/interactions/private/InteractionCollection.cxx +++ b/projects/interactions/private/InteractionCollection.cxx @@ -7,6 +7,7 @@ #include // for vector #include // for pair +#include "SIREN/interactions/Interaction.h" // for Interaction #include "SIREN/interactions/CrossSection.h" // for CrossSe... #include "SIREN/interactions/Decay.h" // for Decay #include "SIREN/dataclasses/InteractionRecord.h" // for Interac... @@ -60,6 +61,23 @@ InteractionCollection::InteractionCollection(siren::dataclasses::ParticleType pr InitializeTargetTypes(); } +InteractionCollection::InteractionCollection(siren::dataclasses::ParticleType primary_type, std::vector> interactions) : primary_type(primary_type) { + for(auto interaction : interactions) { + std::shared_ptr xs = std::dynamic_pointer_cast(interaction); + if(xs) { + cross_sections.push_back(xs); + } else { + std::shared_ptr dec = std::dynamic_pointer_cast(interaction); + if(dec) { + decays.push_back(dec); + } else { + throw std::runtime_error("InteractionCollection: Interaction is neither a CrossSection nor a Decay"); + } + } + } + InitializeTargetTypes(); +} + bool InteractionCollection::operator==(InteractionCollection const & other) const { return std::tie(primary_type, target_types, cross_sections, decays) diff --git a/projects/interactions/public/SIREN/interactions/CrossSection.h b/projects/interactions/public/SIREN/interactions/CrossSection.h index 57ef742ea..0512218c9 100644 --- a/projects/interactions/public/SIREN/interactions/CrossSection.h +++ b/projects/interactions/public/SIREN/interactions/CrossSection.h @@ -17,6 +17,7 @@ #include "SIREN/dataclasses/Particle.h" // for Particle #include "SIREN/dataclasses/InteractionSignature.h" // for InteractionSignature #include "SIREN/utilities/Random.h" // for SIREN_random +#include "SIREN/interactions/Interaction.h" // for Interaction namespace siren { namespace dataclasses { class InteractionRecord; } } namespace siren { namespace dataclasses { class CrossSectionDistributionRecord; } } @@ -26,7 +27,7 @@ namespace siren { namespace utilities { class SIREN_random; } } namespace siren { namespace interactions { -class CrossSection { +class CrossSection : public Interaction { friend cereal::access; private: void SampleFinalState(dataclasses::InteractionRecord &, std::shared_ptr) const; @@ -59,6 +60,8 @@ friend cereal::access; } // namespace siren CEREAL_CLASS_VERSION(siren::interactions::CrossSection, 0); +CEREAL_REGISTER_TYPE(siren::interactions::CrossSection); +CEREAL_REGISTER_POLYMORPHIC_RELATION(siren::interactions::Interaction, siren::interactions::CrossSection); #endif // SIREN_CrossSection_H diff --git a/projects/interactions/public/SIREN/interactions/Decay.h b/projects/interactions/public/SIREN/interactions/Decay.h index 3c3512664..e547a4051 100644 --- a/projects/interactions/public/SIREN/interactions/Decay.h +++ b/projects/interactions/public/SIREN/interactions/Decay.h @@ -17,6 +17,7 @@ #include "SIREN/dataclasses/Particle.h" // for Particle #include "SIREN/dataclasses/InteractionSignature.h" // for InteractionSignature #include "SIREN/utilities/Random.h" // for SIREN_random +#include "SIREN/interactions/Interaction.h" // for Interaction namespace siren { namespace dataclasses { class InteractionRecord; } } namespace siren { namespace dataclasses { class CrossSectionDistributionRecord; } } @@ -26,7 +27,7 @@ namespace siren { namespace utilities { class SIREN_random; } } namespace siren { namespace interactions { -class Decay { +class Decay : public Interaction { friend cereal::access; private: public: @@ -56,5 +57,7 @@ friend cereal::access; } // namespace siren CEREAL_CLASS_VERSION(siren::interactions::Decay, 0); +CEREAL_REGISTER_TYPE(siren::interactions::Decay); +CEREAL_REGISTER_POLYMORPHIC_RELATION(siren::interactions::Interaction, siren::interactions::Decay); #endif // SIREN_Decay_H diff --git a/projects/interactions/public/SIREN/interactions/Interaction.h b/projects/interactions/public/SIREN/interactions/Interaction.h new file mode 100644 index 000000000..042a6d0a8 --- /dev/null +++ b/projects/interactions/public/SIREN/interactions/Interaction.h @@ -0,0 +1,24 @@ +#pragma once +#ifndef SIREN_Interaction_H +#define SIREN_Interaction_H + +#include +#include +#include +#include +#include + +namespace siren { +namespace interactions { + +class Interaction { +public: + virtual ~Interaction() = default; +}; + +}; +}; + +CEREAL_CLASS_VERSION(siren::interactions::Interaction, 0); + +#endif // SIREN_Interaction_H diff --git a/projects/interactions/public/SIREN/interactions/InteractionCollection.h b/projects/interactions/public/SIREN/interactions/InteractionCollection.h index 3a8e8f80b..243b41142 100644 --- a/projects/interactions/public/SIREN/interactions/InteractionCollection.h +++ b/projects/interactions/public/SIREN/interactions/InteractionCollection.h @@ -48,6 +48,7 @@ class InteractionCollection { InteractionCollection(siren::dataclasses::ParticleType primary_type, std::vector> cross_sections); InteractionCollection(siren::dataclasses::ParticleType primary_type, std::vector> decays); InteractionCollection(siren::dataclasses::ParticleType primary_type, std::vector> cross_sections, std::vector> decays); + InteractionCollection(siren::dataclasses::ParticleType primary_type, std::vector> interactions); bool operator==(InteractionCollection const & other) const; std::vector> const & GetCrossSections() const {return cross_sections;} std::vector> const & GetDecays() const {return decays;} From a2a3dbb21b4e682a3a7f28d820ffcd7ea6be6773 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sat, 31 Aug 2024 19:02:20 -0600 Subject: [PATCH 30/94] load_process returns maps from particle type to interactions --- .../Processes/DarkNewsTables/processes.py | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/resources/Processes/DarkNewsTables/processes.py b/resources/Processes/DarkNewsTables/processes.py index d5bcce35b..1a57ca933 100644 --- a/resources/Processes/DarkNewsTables/processes.py +++ b/resources/Processes/DarkNewsTables/processes.py @@ -1,6 +1,7 @@ import os from typing import Tuple, List, Any, Optional import siren +import collections base_path = os.path.dirname(os.path.abspath(__file__)) logger_file = os.path.join(base_path, "logger.py") @@ -370,6 +371,17 @@ def load_decays( return decays +# This class is a hacky workaround for an issue with the python reference counting of classes derived +# from a pybind11 trampoline class i.e. python cross-section classes and python decay classes that +# inherit from siren.interactions.CrossSection or siren.interactions.Decay. If these python classes +# are passed to the InteractionCollection constructor, but a python-side reference to them is not +# maintained, then their python side state/memory will be destroyed/deallocated. This class maintains +# a python-side reference to all PyDarkNewsCrossSection and PyDarkNewsDecay instances created by +# load_processes(...) to avoid this issue +class Holder: + holders = [] + def __init__(self): + Holder.holders.append(self) def load_processes( primary_type: Optional[Any] = None, @@ -468,5 +480,26 @@ def load_processes( for cross_section in cross_sections: cross_section.FillInterpolationTables(Emax=Emax) - return cross_sections + decays + primary_processes = collections.defaultdict(list) + # Loop over available cross sections and save those which match primary type + for cross_section in cross_sections: + if primary_type == siren.dataclasses.Particle.ParticleType( + cross_section.ups_case.nu_projectile.pdgid + ): + primary_processes[primary_type].append(cross_section) + + secondary_processes = collections.defaultdict(list) + # Loop over available decays, group by parent type + for decay in decays: + secondary_type = siren.dataclasses.Particle.ParticleType( + decay.dec_case.nu_parent.pdgid + ) + secondary_processes[secondary_type].append(decay) + + + holder = Holder() + holder.primary_processes = primary_processes + holder.secondary_processes = secondary_processes + + return dict(primary_processes), dict(secondary_processes) From 5492b695706f47c0a9edfe1726b645689ec1f533 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sat, 31 Aug 2024 19:41:57 -0600 Subject: [PATCH 31/94] Loader for CSMS splines --- .../CSMSDISSplines-v1.0/processes.py | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/processes.py diff --git a/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/processes.py b/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/processes.py new file mode 100644 index 000000000..394153550 --- /dev/null +++ b/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/processes.py @@ -0,0 +1,109 @@ +import os +from typing import Tuple, List, Any, Optional +import siren +import collections + +base_path = os.path.dirname(os.path.abspath(__file__)) + +neutrinos = [ + siren.dataclasses.Particle.ParticleType.NuE, + siren.dataclasses.Particle.ParticleType.NuMu, + siren.dataclasses.Particle.ParticleType.NuTau, +] +antineutrinos = [ + siren.dataclasses.Particle.ParticleType.NuEBar, + siren.dataclasses.Particle.ParticleType.NuMuBar, + siren.dataclasses.Particle.ParticleType.NuTauBar, +] +processes = ["CC", "NC"] + + +def _get_primary_types(primary_types): + if primary_types is None: + primary_types = [ + siren.dataclasses.Particle.ParticleType.NuE, + siren.dataclasses.Particle.ParticleType.NuMu, + siren.dataclasses.Particle.ParticleType.NuTau, + siren.dataclasses.Particle.ParticleType.NuEBar, + siren.dataclasses.Particle.ParticleType.NuMuBar, + siren.dataclasses.Particle.ParticleType.NuTauBar, + ] + + supported_primaries = neutrinos + antineutrinos + for i, p in enumerate(primary_types): + if p not in supported_primaries: + raise ValueError(f"primary_types[{i}] \"{p}\" not supported") + + if len(primary_types) == 0: + print("Warning: len(primary_types) == 0") + + return primary_types + +def _get_isoscalar(isoscalar): + if isoscalar is None: + isoscalar = True + + if not isoscalar: + raise ValueError("Non-isoscalar splines are not supported for CSMSDISSplines-v1.0") + + return isoscalar + + +def _get_target_types(isoscalar, target_types): + if target_types is None: + if isoscalar: + target_types = [siren.dataclasses.Particle.ParticleType.Nucleon] + else: + target_types = [siren.dataclasses.Particle.ParticleType.PPlus, siren.dataclasses.Particle.ParticleType.Neutron] + + if len(target_types) == 0: + print("Warning: len(target_types) == 0") + + return target_types + +def _get_process_types(process_types): + if process_types is None: + process_types = ["CC", "NC"] + + for i, p in enumerate(process_types): + if p not in processes: + raise ValueError(f"process_types[{i}] \"{p}\" not supported") + + if len(process_types) == 0: + print("Warning: len(process_types) == 0") + + return process_types + + +def load_processes( + primary_types: Optional[List[siren.dataclasses.Particle.ParticleType]] = None, + target_types: Optional[List[siren.dataclasses.Particle.ParticleType]] = None, + isoscalar: Optional[bool] = None, + process_types: Optional[List[str]] = None, + ): + + primary_types = _get_primary_types(primary_types) + isoscalar = _get_isoscalar(isoscalar) + target_types = _get_target_types(isoscalar, target_types) + process_types = _get_process_types(process_types) + + neutrino_types = [t for t in primary_types if t in neutrinos] + antineutrino_types = [t for t in primary_types if t in antineutrinos] + + primary_processes = [] + primary_processes_dict = collections.defaultdict(list) + + for process_type in process_types: + for primaries, nunubar in [[neutrinos, "nu"], [antineutrinos, "nubar"]]: + if isoscalar: + dxs_file = os.path.join(base_path, f"dsdxdy_{nunubar}_{process_type}_iso.fits") + xs_file = os.path.join(base_path, f"sigma_{nunubar}_{process_type}_iso.fits") + xs = siren.interactions.DISFromSpline(dxs_file, xs_file, primaries, target_types, "m") + primary_processes.append(xs) + for primary_type in primaries: + primary_processes_dict[primary_type].append(xs) + else: + pass + + return dict(primary_processes_dict), {} + From ea69003813403ccb2268620996bb14d44c250d92 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sun, 1 Sep 2024 18:00:25 -0600 Subject: [PATCH 32/94] Move resources --- .../ATLAS/ATLAS-v1/densities.dat | 0 .../ATLAS/ATLAS-v1/materials.dat | 0 .../CCM/CCM-v1/densities.dat | 0 .../CCM/CCM-v1/materials.dat | 0 .../CCM/densities_CCM-v2.dat | 0 .../CCM/materials_CCM-v2.dat | 0 .../DUNEFD/DUNEFD-v1/densities.dat | 0 .../DUNEFD/DUNEFD-v1/materials.dat | 0 .../HyperK/HyperK-v1/densities.dat | 0 .../HyperK/HyperK-v1/materials.dat | 0 .../IceCube/IceCube-v1/densities.dat | 0 .../IceCube/IceCube-v1/materials.dat | 0 .../MINERvA/MINERvA-v1/densities.dat | 0 .../MINERvA/MINERvA-v1/materials.dat | 0 .../MiniBooNE/MiniBooNE-v1/densities.dat | 0 .../MiniBooNE/MiniBooNE-v1/materials.dat | 0 resources/{Detectors => detectors}/README_densities | 0 resources/{Detectors => detectors}/README_materials | 0 .../AdditionalPaperPlots/PaperPlots.ipynb | 0 .../{Examples => examples}/Example1/DIS_ATLAS.py | 0 .../{Examples => examples}/Example1/DIS_DUNE.py | 0 .../{Examples => examples}/Example1/DIS_IceCube.py | 0 .../Example1/PaperPlots.ipynb | 0 .../Example2/DipolePortal_CCM.py | 0 .../Example2/DipolePortal_MINERvA.py | 0 .../Example2/DipolePortal_MiniBooNE.py | 0 .../Example2/DipolePortal_ND280UPGRD.py | 0 .../Example2/PaperPlots.ipynb | 0 resources/{Examples => examples}/figures.mplstyle | 0 .../legacy_examples/compiling_c_example.md | 0 .../legacy_examples/convert_to_i3.py | 0 .../legacy_examples/inject_muons.cpp | 0 .../legacy_examples/inject_muons.py | 0 .../{Fluxes => fluxes}/BNB/BNB-v1.0/BNB_FHC.dat | 0 .../{Fluxes => fluxes}/BNB/BNB-v1.0/BNB_RHC.dat | 0 resources/{Fluxes => fluxes}/BNB/BNB-v1.0/flux.py | 0 .../dN_dE_SNe_2n_D1_0_s20_t100d_NuMu_d10kpc.txt | 0 .../{Fluxes => fluxes}/HE_SN/HE_SN-v1.0/flux.py | 0 .../NUMI/NUMI-v1.0/NUMI_FHC_LE.dat | 0 .../NUMI/NUMI-v1.0/NUMI_FHC_ME.dat | 0 .../NUMI/NUMI-v1.0/NUMI_FHC_ME_unofficial.dat | 0 .../NUMI/NUMI-v1.0/NUMI_RHC_LE.dat | 0 .../NUMI/NUMI-v1.0/NUMI_RHC_ME.dat | 0 .../NUMI/NUMI-v1.0/NUMI_RHC_ME_unofficial.dat | 0 resources/{Fluxes => fluxes}/NUMI/NUMI-v1.0/flux.py | 0 .../CSMSDISSplines-v1.0/dsdxdy_nu_CC_iso.fits | Bin .../CSMSDISSplines-v1.0/dsdxdy_nu_NC_iso.fits | Bin .../CSMSDISSplines-v1.0/dsdxdy_nubar_CC_iso.fits | Bin .../CSMSDISSplines-v1.0/dsdxdy_nubar_NC_iso.fits | Bin .../CSMSDISSplines/CSMSDISSplines-v1.0/processes.py | 0 .../CSMSDISSplines-v1.0/sigma_nu_CC_iso.fits | Bin .../CSMSDISSplines-v1.0/sigma_nu_NC_iso.fits | Bin .../CSMSDISSplines-v1.0/sigma_nubar_CC_iso.fits | Bin .../CSMSDISSplines-v1.0/sigma_nubar_NC_iso.fits | Bin .../DarkNewsTables/DarkNewsCrossSection.py | 0 .../DarkNewsTables/DarkNewsDecay.py | 0 .../DarkNewsTables/README.md | 0 .../DarkNewsTables/logger.py | 0 .../DarkNewsTables/processes.py | 0 59 files changed, 0 insertions(+), 0 deletions(-) rename resources/{Detectors => detectors}/ATLAS/ATLAS-v1/densities.dat (100%) rename resources/{Detectors => detectors}/ATLAS/ATLAS-v1/materials.dat (100%) rename resources/{Detectors => detectors}/CCM/CCM-v1/densities.dat (100%) rename resources/{Detectors => detectors}/CCM/CCM-v1/materials.dat (100%) rename resources/{Detectors => detectors}/CCM/densities_CCM-v2.dat (100%) rename resources/{Detectors => detectors}/CCM/materials_CCM-v2.dat (100%) rename resources/{Detectors => detectors}/DUNEFD/DUNEFD-v1/densities.dat (100%) rename resources/{Detectors => detectors}/DUNEFD/DUNEFD-v1/materials.dat (100%) rename resources/{Detectors => detectors}/HyperK/HyperK-v1/densities.dat (100%) rename resources/{Detectors => detectors}/HyperK/HyperK-v1/materials.dat (100%) rename resources/{Detectors => detectors}/IceCube/IceCube-v1/densities.dat (100%) rename resources/{Detectors => detectors}/IceCube/IceCube-v1/materials.dat (100%) rename resources/{Detectors => detectors}/MINERvA/MINERvA-v1/densities.dat (100%) rename resources/{Detectors => detectors}/MINERvA/MINERvA-v1/materials.dat (100%) rename resources/{Detectors => detectors}/MiniBooNE/MiniBooNE-v1/densities.dat (100%) rename resources/{Detectors => detectors}/MiniBooNE/MiniBooNE-v1/materials.dat (100%) rename resources/{Detectors => detectors}/README_densities (100%) rename resources/{Detectors => detectors}/README_materials (100%) rename resources/{Examples => examples}/AdditionalPaperPlots/PaperPlots.ipynb (100%) rename resources/{Examples => examples}/Example1/DIS_ATLAS.py (100%) rename resources/{Examples => examples}/Example1/DIS_DUNE.py (100%) rename resources/{Examples => examples}/Example1/DIS_IceCube.py (100%) rename resources/{Examples => examples}/Example1/PaperPlots.ipynb (100%) rename resources/{Examples => examples}/Example2/DipolePortal_CCM.py (100%) rename resources/{Examples => examples}/Example2/DipolePortal_MINERvA.py (100%) rename resources/{Examples => examples}/Example2/DipolePortal_MiniBooNE.py (100%) rename resources/{Examples => examples}/Example2/DipolePortal_ND280UPGRD.py (100%) rename resources/{Examples => examples}/Example2/PaperPlots.ipynb (100%) rename resources/{Examples => examples}/figures.mplstyle (100%) rename resources/{Examples => examples}/legacy_examples/compiling_c_example.md (100%) rename resources/{Examples => examples}/legacy_examples/convert_to_i3.py (100%) rename resources/{Examples => examples}/legacy_examples/inject_muons.cpp (100%) rename resources/{Examples => examples}/legacy_examples/inject_muons.py (100%) rename resources/{Fluxes => fluxes}/BNB/BNB-v1.0/BNB_FHC.dat (100%) rename resources/{Fluxes => fluxes}/BNB/BNB-v1.0/BNB_RHC.dat (100%) rename resources/{Fluxes => fluxes}/BNB/BNB-v1.0/flux.py (100%) rename resources/{Fluxes => fluxes}/HE_SN/HE_SN-v1.0/dN_dE_SNe_2n_D1_0_s20_t100d_NuMu_d10kpc.txt (100%) rename resources/{Fluxes => fluxes}/HE_SN/HE_SN-v1.0/flux.py (100%) rename resources/{Fluxes => fluxes}/NUMI/NUMI-v1.0/NUMI_FHC_LE.dat (100%) rename resources/{Fluxes => fluxes}/NUMI/NUMI-v1.0/NUMI_FHC_ME.dat (100%) rename resources/{Fluxes => fluxes}/NUMI/NUMI-v1.0/NUMI_FHC_ME_unofficial.dat (100%) rename resources/{Fluxes => fluxes}/NUMI/NUMI-v1.0/NUMI_RHC_LE.dat (100%) rename resources/{Fluxes => fluxes}/NUMI/NUMI-v1.0/NUMI_RHC_ME.dat (100%) rename resources/{Fluxes => fluxes}/NUMI/NUMI-v1.0/NUMI_RHC_ME_unofficial.dat (100%) rename resources/{Fluxes => fluxes}/NUMI/NUMI-v1.0/flux.py (100%) rename resources/{Processes => processes}/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_CC_iso.fits (100%) rename resources/{Processes => processes}/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_NC_iso.fits (100%) rename resources/{Processes => processes}/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_CC_iso.fits (100%) rename resources/{Processes => processes}/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_NC_iso.fits (100%) rename resources/{Processes => processes}/CSMSDISSplines/CSMSDISSplines-v1.0/processes.py (100%) rename resources/{Processes => processes}/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_CC_iso.fits (100%) rename resources/{Processes => processes}/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_NC_iso.fits (100%) rename resources/{Processes => processes}/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_CC_iso.fits (100%) rename resources/{Processes => processes}/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_NC_iso.fits (100%) rename resources/{Processes => processes}/DarkNewsTables/DarkNewsCrossSection.py (100%) rename resources/{Processes => processes}/DarkNewsTables/DarkNewsDecay.py (100%) rename resources/{Processes => processes}/DarkNewsTables/README.md (100%) rename resources/{Processes => processes}/DarkNewsTables/logger.py (100%) rename resources/{Processes => processes}/DarkNewsTables/processes.py (100%) diff --git a/resources/Detectors/ATLAS/ATLAS-v1/densities.dat b/resources/detectors/ATLAS/ATLAS-v1/densities.dat similarity index 100% rename from resources/Detectors/ATLAS/ATLAS-v1/densities.dat rename to resources/detectors/ATLAS/ATLAS-v1/densities.dat diff --git a/resources/Detectors/ATLAS/ATLAS-v1/materials.dat b/resources/detectors/ATLAS/ATLAS-v1/materials.dat similarity index 100% rename from resources/Detectors/ATLAS/ATLAS-v1/materials.dat rename to resources/detectors/ATLAS/ATLAS-v1/materials.dat diff --git a/resources/Detectors/CCM/CCM-v1/densities.dat b/resources/detectors/CCM/CCM-v1/densities.dat similarity index 100% rename from resources/Detectors/CCM/CCM-v1/densities.dat rename to resources/detectors/CCM/CCM-v1/densities.dat diff --git a/resources/Detectors/CCM/CCM-v1/materials.dat b/resources/detectors/CCM/CCM-v1/materials.dat similarity index 100% rename from resources/Detectors/CCM/CCM-v1/materials.dat rename to resources/detectors/CCM/CCM-v1/materials.dat diff --git a/resources/Detectors/CCM/densities_CCM-v2.dat b/resources/detectors/CCM/densities_CCM-v2.dat similarity index 100% rename from resources/Detectors/CCM/densities_CCM-v2.dat rename to resources/detectors/CCM/densities_CCM-v2.dat diff --git a/resources/Detectors/CCM/materials_CCM-v2.dat b/resources/detectors/CCM/materials_CCM-v2.dat similarity index 100% rename from resources/Detectors/CCM/materials_CCM-v2.dat rename to resources/detectors/CCM/materials_CCM-v2.dat diff --git a/resources/Detectors/DUNEFD/DUNEFD-v1/densities.dat b/resources/detectors/DUNEFD/DUNEFD-v1/densities.dat similarity index 100% rename from resources/Detectors/DUNEFD/DUNEFD-v1/densities.dat rename to resources/detectors/DUNEFD/DUNEFD-v1/densities.dat diff --git a/resources/Detectors/DUNEFD/DUNEFD-v1/materials.dat b/resources/detectors/DUNEFD/DUNEFD-v1/materials.dat similarity index 100% rename from resources/Detectors/DUNEFD/DUNEFD-v1/materials.dat rename to resources/detectors/DUNEFD/DUNEFD-v1/materials.dat diff --git a/resources/Detectors/HyperK/HyperK-v1/densities.dat b/resources/detectors/HyperK/HyperK-v1/densities.dat similarity index 100% rename from resources/Detectors/HyperK/HyperK-v1/densities.dat rename to resources/detectors/HyperK/HyperK-v1/densities.dat diff --git a/resources/Detectors/HyperK/HyperK-v1/materials.dat b/resources/detectors/HyperK/HyperK-v1/materials.dat similarity index 100% rename from resources/Detectors/HyperK/HyperK-v1/materials.dat rename to resources/detectors/HyperK/HyperK-v1/materials.dat diff --git a/resources/Detectors/IceCube/IceCube-v1/densities.dat b/resources/detectors/IceCube/IceCube-v1/densities.dat similarity index 100% rename from resources/Detectors/IceCube/IceCube-v1/densities.dat rename to resources/detectors/IceCube/IceCube-v1/densities.dat diff --git a/resources/Detectors/IceCube/IceCube-v1/materials.dat b/resources/detectors/IceCube/IceCube-v1/materials.dat similarity index 100% rename from resources/Detectors/IceCube/IceCube-v1/materials.dat rename to resources/detectors/IceCube/IceCube-v1/materials.dat diff --git a/resources/Detectors/MINERvA/MINERvA-v1/densities.dat b/resources/detectors/MINERvA/MINERvA-v1/densities.dat similarity index 100% rename from resources/Detectors/MINERvA/MINERvA-v1/densities.dat rename to resources/detectors/MINERvA/MINERvA-v1/densities.dat diff --git a/resources/Detectors/MINERvA/MINERvA-v1/materials.dat b/resources/detectors/MINERvA/MINERvA-v1/materials.dat similarity index 100% rename from resources/Detectors/MINERvA/MINERvA-v1/materials.dat rename to resources/detectors/MINERvA/MINERvA-v1/materials.dat diff --git a/resources/Detectors/MiniBooNE/MiniBooNE-v1/densities.dat b/resources/detectors/MiniBooNE/MiniBooNE-v1/densities.dat similarity index 100% rename from resources/Detectors/MiniBooNE/MiniBooNE-v1/densities.dat rename to resources/detectors/MiniBooNE/MiniBooNE-v1/densities.dat diff --git a/resources/Detectors/MiniBooNE/MiniBooNE-v1/materials.dat b/resources/detectors/MiniBooNE/MiniBooNE-v1/materials.dat similarity index 100% rename from resources/Detectors/MiniBooNE/MiniBooNE-v1/materials.dat rename to resources/detectors/MiniBooNE/MiniBooNE-v1/materials.dat diff --git a/resources/Detectors/README_densities b/resources/detectors/README_densities similarity index 100% rename from resources/Detectors/README_densities rename to resources/detectors/README_densities diff --git a/resources/Detectors/README_materials b/resources/detectors/README_materials similarity index 100% rename from resources/Detectors/README_materials rename to resources/detectors/README_materials diff --git a/resources/Examples/AdditionalPaperPlots/PaperPlots.ipynb b/resources/examples/AdditionalPaperPlots/PaperPlots.ipynb similarity index 100% rename from resources/Examples/AdditionalPaperPlots/PaperPlots.ipynb rename to resources/examples/AdditionalPaperPlots/PaperPlots.ipynb diff --git a/resources/Examples/Example1/DIS_ATLAS.py b/resources/examples/Example1/DIS_ATLAS.py similarity index 100% rename from resources/Examples/Example1/DIS_ATLAS.py rename to resources/examples/Example1/DIS_ATLAS.py diff --git a/resources/Examples/Example1/DIS_DUNE.py b/resources/examples/Example1/DIS_DUNE.py similarity index 100% rename from resources/Examples/Example1/DIS_DUNE.py rename to resources/examples/Example1/DIS_DUNE.py diff --git a/resources/Examples/Example1/DIS_IceCube.py b/resources/examples/Example1/DIS_IceCube.py similarity index 100% rename from resources/Examples/Example1/DIS_IceCube.py rename to resources/examples/Example1/DIS_IceCube.py diff --git a/resources/Examples/Example1/PaperPlots.ipynb b/resources/examples/Example1/PaperPlots.ipynb similarity index 100% rename from resources/Examples/Example1/PaperPlots.ipynb rename to resources/examples/Example1/PaperPlots.ipynb diff --git a/resources/Examples/Example2/DipolePortal_CCM.py b/resources/examples/Example2/DipolePortal_CCM.py similarity index 100% rename from resources/Examples/Example2/DipolePortal_CCM.py rename to resources/examples/Example2/DipolePortal_CCM.py diff --git a/resources/Examples/Example2/DipolePortal_MINERvA.py b/resources/examples/Example2/DipolePortal_MINERvA.py similarity index 100% rename from resources/Examples/Example2/DipolePortal_MINERvA.py rename to resources/examples/Example2/DipolePortal_MINERvA.py diff --git a/resources/Examples/Example2/DipolePortal_MiniBooNE.py b/resources/examples/Example2/DipolePortal_MiniBooNE.py similarity index 100% rename from resources/Examples/Example2/DipolePortal_MiniBooNE.py rename to resources/examples/Example2/DipolePortal_MiniBooNE.py diff --git a/resources/Examples/Example2/DipolePortal_ND280UPGRD.py b/resources/examples/Example2/DipolePortal_ND280UPGRD.py similarity index 100% rename from resources/Examples/Example2/DipolePortal_ND280UPGRD.py rename to resources/examples/Example2/DipolePortal_ND280UPGRD.py diff --git a/resources/Examples/Example2/PaperPlots.ipynb b/resources/examples/Example2/PaperPlots.ipynb similarity index 100% rename from resources/Examples/Example2/PaperPlots.ipynb rename to resources/examples/Example2/PaperPlots.ipynb diff --git a/resources/Examples/figures.mplstyle b/resources/examples/figures.mplstyle similarity index 100% rename from resources/Examples/figures.mplstyle rename to resources/examples/figures.mplstyle diff --git a/resources/Examples/legacy_examples/compiling_c_example.md b/resources/examples/legacy_examples/compiling_c_example.md similarity index 100% rename from resources/Examples/legacy_examples/compiling_c_example.md rename to resources/examples/legacy_examples/compiling_c_example.md diff --git a/resources/Examples/legacy_examples/convert_to_i3.py b/resources/examples/legacy_examples/convert_to_i3.py similarity index 100% rename from resources/Examples/legacy_examples/convert_to_i3.py rename to resources/examples/legacy_examples/convert_to_i3.py diff --git a/resources/Examples/legacy_examples/inject_muons.cpp b/resources/examples/legacy_examples/inject_muons.cpp similarity index 100% rename from resources/Examples/legacy_examples/inject_muons.cpp rename to resources/examples/legacy_examples/inject_muons.cpp diff --git a/resources/Examples/legacy_examples/inject_muons.py b/resources/examples/legacy_examples/inject_muons.py similarity index 100% rename from resources/Examples/legacy_examples/inject_muons.py rename to resources/examples/legacy_examples/inject_muons.py diff --git a/resources/Fluxes/BNB/BNB-v1.0/BNB_FHC.dat b/resources/fluxes/BNB/BNB-v1.0/BNB_FHC.dat similarity index 100% rename from resources/Fluxes/BNB/BNB-v1.0/BNB_FHC.dat rename to resources/fluxes/BNB/BNB-v1.0/BNB_FHC.dat diff --git a/resources/Fluxes/BNB/BNB-v1.0/BNB_RHC.dat b/resources/fluxes/BNB/BNB-v1.0/BNB_RHC.dat similarity index 100% rename from resources/Fluxes/BNB/BNB-v1.0/BNB_RHC.dat rename to resources/fluxes/BNB/BNB-v1.0/BNB_RHC.dat diff --git a/resources/Fluxes/BNB/BNB-v1.0/flux.py b/resources/fluxes/BNB/BNB-v1.0/flux.py similarity index 100% rename from resources/Fluxes/BNB/BNB-v1.0/flux.py rename to resources/fluxes/BNB/BNB-v1.0/flux.py diff --git a/resources/Fluxes/HE_SN/HE_SN-v1.0/dN_dE_SNe_2n_D1_0_s20_t100d_NuMu_d10kpc.txt b/resources/fluxes/HE_SN/HE_SN-v1.0/dN_dE_SNe_2n_D1_0_s20_t100d_NuMu_d10kpc.txt similarity index 100% rename from resources/Fluxes/HE_SN/HE_SN-v1.0/dN_dE_SNe_2n_D1_0_s20_t100d_NuMu_d10kpc.txt rename to resources/fluxes/HE_SN/HE_SN-v1.0/dN_dE_SNe_2n_D1_0_s20_t100d_NuMu_d10kpc.txt diff --git a/resources/Fluxes/HE_SN/HE_SN-v1.0/flux.py b/resources/fluxes/HE_SN/HE_SN-v1.0/flux.py similarity index 100% rename from resources/Fluxes/HE_SN/HE_SN-v1.0/flux.py rename to resources/fluxes/HE_SN/HE_SN-v1.0/flux.py diff --git a/resources/Fluxes/NUMI/NUMI-v1.0/NUMI_FHC_LE.dat b/resources/fluxes/NUMI/NUMI-v1.0/NUMI_FHC_LE.dat similarity index 100% rename from resources/Fluxes/NUMI/NUMI-v1.0/NUMI_FHC_LE.dat rename to resources/fluxes/NUMI/NUMI-v1.0/NUMI_FHC_LE.dat diff --git a/resources/Fluxes/NUMI/NUMI-v1.0/NUMI_FHC_ME.dat b/resources/fluxes/NUMI/NUMI-v1.0/NUMI_FHC_ME.dat similarity index 100% rename from resources/Fluxes/NUMI/NUMI-v1.0/NUMI_FHC_ME.dat rename to resources/fluxes/NUMI/NUMI-v1.0/NUMI_FHC_ME.dat diff --git a/resources/Fluxes/NUMI/NUMI-v1.0/NUMI_FHC_ME_unofficial.dat b/resources/fluxes/NUMI/NUMI-v1.0/NUMI_FHC_ME_unofficial.dat similarity index 100% rename from resources/Fluxes/NUMI/NUMI-v1.0/NUMI_FHC_ME_unofficial.dat rename to resources/fluxes/NUMI/NUMI-v1.0/NUMI_FHC_ME_unofficial.dat diff --git a/resources/Fluxes/NUMI/NUMI-v1.0/NUMI_RHC_LE.dat b/resources/fluxes/NUMI/NUMI-v1.0/NUMI_RHC_LE.dat similarity index 100% rename from resources/Fluxes/NUMI/NUMI-v1.0/NUMI_RHC_LE.dat rename to resources/fluxes/NUMI/NUMI-v1.0/NUMI_RHC_LE.dat diff --git a/resources/Fluxes/NUMI/NUMI-v1.0/NUMI_RHC_ME.dat b/resources/fluxes/NUMI/NUMI-v1.0/NUMI_RHC_ME.dat similarity index 100% rename from resources/Fluxes/NUMI/NUMI-v1.0/NUMI_RHC_ME.dat rename to resources/fluxes/NUMI/NUMI-v1.0/NUMI_RHC_ME.dat diff --git a/resources/Fluxes/NUMI/NUMI-v1.0/NUMI_RHC_ME_unofficial.dat b/resources/fluxes/NUMI/NUMI-v1.0/NUMI_RHC_ME_unofficial.dat similarity index 100% rename from resources/Fluxes/NUMI/NUMI-v1.0/NUMI_RHC_ME_unofficial.dat rename to resources/fluxes/NUMI/NUMI-v1.0/NUMI_RHC_ME_unofficial.dat diff --git a/resources/Fluxes/NUMI/NUMI-v1.0/flux.py b/resources/fluxes/NUMI/NUMI-v1.0/flux.py similarity index 100% rename from resources/Fluxes/NUMI/NUMI-v1.0/flux.py rename to resources/fluxes/NUMI/NUMI-v1.0/flux.py diff --git a/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_CC_iso.fits b/resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_CC_iso.fits similarity index 100% rename from resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_CC_iso.fits rename to resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_CC_iso.fits diff --git a/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_NC_iso.fits b/resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_NC_iso.fits similarity index 100% rename from resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_NC_iso.fits rename to resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nu_NC_iso.fits diff --git a/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_CC_iso.fits b/resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_CC_iso.fits similarity index 100% rename from resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_CC_iso.fits rename to resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_CC_iso.fits diff --git a/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_NC_iso.fits b/resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_NC_iso.fits similarity index 100% rename from resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_NC_iso.fits rename to resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/dsdxdy_nubar_NC_iso.fits diff --git a/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/processes.py b/resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/processes.py similarity index 100% rename from resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/processes.py rename to resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/processes.py diff --git a/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_CC_iso.fits b/resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_CC_iso.fits similarity index 100% rename from resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_CC_iso.fits rename to resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_CC_iso.fits diff --git a/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_NC_iso.fits b/resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_NC_iso.fits similarity index 100% rename from resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_NC_iso.fits rename to resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nu_NC_iso.fits diff --git a/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_CC_iso.fits b/resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_CC_iso.fits similarity index 100% rename from resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_CC_iso.fits rename to resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_CC_iso.fits diff --git a/resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_NC_iso.fits b/resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_NC_iso.fits similarity index 100% rename from resources/Processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_NC_iso.fits rename to resources/processes/CSMSDISSplines/CSMSDISSplines-v1.0/sigma_nubar_NC_iso.fits diff --git a/resources/Processes/DarkNewsTables/DarkNewsCrossSection.py b/resources/processes/DarkNewsTables/DarkNewsCrossSection.py similarity index 100% rename from resources/Processes/DarkNewsTables/DarkNewsCrossSection.py rename to resources/processes/DarkNewsTables/DarkNewsCrossSection.py diff --git a/resources/Processes/DarkNewsTables/DarkNewsDecay.py b/resources/processes/DarkNewsTables/DarkNewsDecay.py similarity index 100% rename from resources/Processes/DarkNewsTables/DarkNewsDecay.py rename to resources/processes/DarkNewsTables/DarkNewsDecay.py diff --git a/resources/Processes/DarkNewsTables/README.md b/resources/processes/DarkNewsTables/README.md similarity index 100% rename from resources/Processes/DarkNewsTables/README.md rename to resources/processes/DarkNewsTables/README.md diff --git a/resources/Processes/DarkNewsTables/logger.py b/resources/processes/DarkNewsTables/logger.py similarity index 100% rename from resources/Processes/DarkNewsTables/logger.py rename to resources/processes/DarkNewsTables/logger.py diff --git a/resources/Processes/DarkNewsTables/processes.py b/resources/processes/DarkNewsTables/processes.py similarity index 100% rename from resources/Processes/DarkNewsTables/processes.py rename to resources/processes/DarkNewsTables/processes.py From 7e5e5f179d20420317e313128b8a8b760d5c3473 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sun, 1 Sep 2024 18:01:31 -0600 Subject: [PATCH 33/94] un-capitalize folders --- python/_util.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/python/_util.py b/python/_util.py index 131ef679f..7ab1cca90 100644 --- a/python/_util.py +++ b/python/_util.py @@ -662,17 +662,17 @@ def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exi def get_detector_model_file_path(model_name, must_exist=True): - return _get_model_path(model_name, prefix="Detectors/densities", suffix=".dat", is_file=True, must_exist=must_exist) + return _get_model_path(model_name, prefix="detectors/densities", suffix=".dat", is_file=True, must_exist=must_exist) def get_material_model_file_path(model_name, must_exist=True): - return _get_model_path(model_name, prefix="Detectors/materials", suffix=".dat", is_file=True, must_exist=must_exist) + return _get_model_path(model_name, prefix="detectors/materials", suffix=".dat", is_file=True, must_exist=must_exist) _resource_folder_by_name = { - "flux": "Fluxes", - "detector": "Detectors", - "processes": "Processes", + "flux": "fluxes", + "detector": "detectors", + "processes": "processes", } From 55d8dc66a8d055f7d70ac973230ce5a1246c5d42 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 11 Sep 2024 20:09:40 -0600 Subject: [PATCH 34/94] First pass at Injector wrapper --- python/Injector.py | 203 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 python/Injector.py diff --git a/python/Injector.py b/python/Injector.py new file mode 100644 index 000000000..6b0bc233d --- /dev/null +++ b/python/Injector.py @@ -0,0 +1,203 @@ +from . import utilities as _utilities +from . import math as _math +from . import dataclasses as _dataclasses +from . import geometry as _geometry +from . import detector as _detector +from . import interactions as _interactions +from . import distributions as _distributions +from . import injection as _injection + +import collections +from functools import wraps + +from typing import Tuple, List, Dict, Optional, Union +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import siren + +_Injector = _injection.Injector + +ParticleType = _dataclasses.Particle.ParticleType +CrossSection = _interactions.CrossSection +Decay = _interactions.Decay +Interaction = _interactions.Interaction +DetectorModel = _detector.DetectorModel +SIREN_random = _utilities.SIREN_random +PrimaryInjectionDistribution = _distributions.PrimaryInjectionDistribution +SecondaryInjectionDistribution = _distributions.SecondaryInjectionDistribution +SecondaryInjectionProcess = _injection.SecondaryInjectionProcess + +class Injector: + def __init__( + self, + number_of_events: int, + detector_model: "DetectorModel", + random: "SIREN_random", + primary_interactions: Dict["ParticleType", List[Union["CrossSection", "Decay", "Interaction"]]], + primary_injection_distributions: List["PrimaryInjectionDistribution"], + secondary_interactions: Optional[Dict["ParticleType", List[Union["CrossSection", "Decay", "Interaction"]]]] = None, + secondary_injection_distributions: Optional[Dict["ParticleType", List["SecondaryInjectionDistribution"]]] = None, + ): + self.number_of_events = number_of_events + + self.detector_model = detector_model + + if len(primary_interactions) != 1: + raise ValueError(f"len(primary_interactions) != 1") + + if (secondary_interactions is None) != (secondary_injection_distributions is None): + raise ValueError("Neither or both of secondary_interactions and secondary_injection_distributions must be provided") + + if secondary_interactions is None: + secondary_interactions = dict() + secondary_injection_distributions = dict() + + self.primary_interactions = primary_interactions + self.primary_injection_distributions = primary_injection_distributions + + primary_type, primary_interactions = list(primary_interactions.items())[0] + + self.primary_interaction_collection = _interactions.InteractionCollection( + primary_type, primary_interactions + ) + self.primary_process = _injection.PrimaryInjectionProcess( + primary_type, self.primary_interaction_collection + ) + for dist in primary_injection_distributions: + self.primary_process.AddPrimaryInjectionDistribution(dist) + + + self.secondary_interactions = secondary_interactions + self.secondary_injection_distributions = secondary_injection_distributions + + self.secondary_interaction_collections = [] + self.secondary_processes = [] + for secondary_type, secondary_interactions in secondary_interactions.items(): + secondary_distributions = self.secondary_injection_distributions[secondary_type] + secondary_process = SecondaryInjectionProcess(secondary_type, secondary_interactions) + for dist in secondary_distributions: + secondary_process.AddSecondaryInjectionDistribution(dist) + self.secondary_processes.append(secondary_process) + + self.injector = _injection.Injector( + self.number_of_events, + self.detector_model, + self.primary_process, + self.secondary_processes, + self.random, + ) + + # TODO define wrapper functions that modify the internal state of the python object + @wraps(_Injector.SetPrimaryProcess) + def SetPrimaryProcess(self, primary_process): + # Get the internals first + primary_injection_distributions = primary_process.GetPrimaryInjectionDistributions() + primary_interaction_collection = primary_process.GetInteractionCollection() + primary_interactions = list(primary_interaction_collection.GetCrossSections()) + list(primary_interaction_collection.GetDecays()) + + # Now we can overwite things + self.injector.SetPrimaryProcess(primary_process) + self.primary_process = primary_process + self.primary_injection_distributions = primary_injection_distributions + self.primary_interaction_collection = primary_interaction_collection + self.primary_interactions = {primary_process.primary_type: primary_interactions} + + @wraps(_Injector.SetStoppingCondition) + def SetStoppingCondition(self, stopping_condition): + self.stopping_condition = stopping_condition + self.injector.SetStoppingCondition(stopping_condition) + + @wraps(_Injector.AddSecondaryProcess) + def AddSecondaryProcess(self, secondary_process): + # Update internal state + secondary_type = secondary_process.secondary_type + secondary_distributions = secondary_process.GetSecondaryInjectionDistributions() + secondary_interaction_collection = secondary_process.GetInteractionCollection() + secondary_interactions = list(secondary_interaction_collection.GetCrossSections()) + list(secondary_interaction_collection.GetDecays()) + + # Update class attributes + self.secondary_processes.append(secondary_process) + if secondary_type not in self.secondary_interactions: + self.secondary_interactions[secondary_type] = [] + self.secondary_interactions[secondary_type].extend(secondary_interactions) + if secondary_type not in self.secondary_injection_distributions: + self.secondary_injection_distributions[secondary_type] = [] + self.secondary_injection_distributions[secondary_type].extend(secondary_distributions) + + # Update the underlying C++ object + self.injector.AddSecondaryProcess(secondary_process) + + @wraps(_Injector.GetPrimaryProcess) + def GetPrimaryProcess(self): + return self.primary_process + + @wraps(_Injector.GetSecondaryProcessMap) + def GetSecondaryProcesses(self): + return self.secondary_processes + + @wraps(_Injector.NewRecord) + def NewRecord(self): + return self.injector.NewRecord() + + @wraps(_Injector.SetRandom) + def SetRandom(self, random): + self.injector.SetRandom(random) + + @wraps(_Injector.GenerateEvent) + def GenerateEvent(self): + return self.injector.GenerateEvent() + + @wraps(_Injector.DensityVariables) + def DensityVariables(self): + return self.injector.DensityVariables() + + @wraps(_Injector.Name) + def Name(self): + return self.injector.Name() + + @wraps(_Injector.GetPrimaryInjectionDistributions) + def GetPrimaryInjectionDistributions(self): + return self.primary_injection_distributions + + @wraps(_Injector.GetDetectorModel) + def GetDetectorModel(self): + return self.detector_model + + @wraps(_Injector.GetInteractions) + def GetInteractions(self): + return self.injector.GetInteractions() + + @wraps(_Injector.InjectedEvents) + def InjectedEvents(self): + return self.injector.InjectedEvents() + + @wraps(_Injector.EventsToInject) + def EventsToInject(self): + return self.injector.EventsToInject() + + @wraps(_Injector.ResetInjectedEvents) + def ResetInjectedEvents(self): + self.injector.ResetInjectedEvents() + + @wraps(_Injector.SaveInjector) + def SaveInjector(self, filename): + self.injector.SaveInjector(filename) + + @wraps(_Injector.LoadInjector) + def LoadInjector(self, filename): + self.injector.LoadInjector(filename) + # Update Python object state after loading + self.primary_process = self.injector.GetPrimaryProcess() + self.secondary_processes = self.injector.GetSecondaryProcesses() + self.primary_injection_distributions = self.primary_process.GetPrimaryInjectionDistributions() + self.primary_interaction_collection = self.primary_process.GetInteractionCollection() + self.primary_interactions = {self.primary_process.primary_type: list(self.primary_interaction_collection.GetCrossSections()) + list(self.primary_interaction_collection.GetDecays())} + # Update secondary interactions and distributions + self.secondary_interactions = {} + self.secondary_injection_distributions = {} + for process in self.secondary_processes: + secondary_type = process.secondary_type + self.secondary_interactions[secondary_type] = list(process.GetInteractionCollection().GetCrossSections()) + list(process.GetInteractionCollection().GetDecays()) + self.secondary_injection_distributions[secondary_type] = process.GetSecondaryInjectionDistributions() + From e9443fb9ae40e3ea2b66cc1afeabc506895a27dd Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 11 Sep 2024 20:09:59 -0600 Subject: [PATCH 35/94] Remvoe the holder --- resources/processes/DarkNewsTables/processes.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/processes/DarkNewsTables/processes.py b/resources/processes/DarkNewsTables/processes.py index 1a57ca933..d9e4b802e 100644 --- a/resources/processes/DarkNewsTables/processes.py +++ b/resources/processes/DarkNewsTables/processes.py @@ -497,9 +497,9 @@ def load_processes( secondary_processes[secondary_type].append(decay) - holder = Holder() - holder.primary_processes = primary_processes - holder.secondary_processes = secondary_processes + #holder = Holder() + #holder.primary_processes = primary_processes + #holder.secondary_processes = secondary_processes return dict(primary_processes), dict(secondary_processes) From e01cdca854e3c0510ba3e9f20171aaa91422046a Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 11 Sep 2024 20:10:24 -0600 Subject: [PATCH 36/94] particle type properties for the processes --- projects/injection/private/pybindings/injection.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/projects/injection/private/pybindings/injection.cxx b/projects/injection/private/pybindings/injection.cxx index 044ccd06d..2dfc7bdf4 100644 --- a/projects/injection/private/pybindings/injection.cxx +++ b/projects/injection/private/pybindings/injection.cxx @@ -43,16 +43,19 @@ PYBIND11_MODULE(injection,m) { class_, Process>(m, "PhysicalProcess") .def(init<>()) + .def_property("primary_type", &Process::GetPrimaryType, &Process::SetPrimaryType) .def("AddPhysicalDistribution",&PhysicalProcess::AddPhysicalDistribution) .def("GetPhysicalDistributions",&PhysicalProcess::GetPhysicalDistributions); class_, Process>(m, "PrimaryInjectionProcess") .def(init<>()) + .def_property("primary_type", &Process::GetPrimaryType, &Process::SetPrimaryType) .def("AddPrimaryInjectionDistribution",&PrimaryInjectionProcess::AddPrimaryInjectionDistribution) .def("GetPrimaryInjectionDistributions",&PrimaryInjectionProcess::GetPrimaryInjectionDistributions); class_, Process>(m, "SecondaryInjectionProcess") .def(init<>()) + .def_property("secondary_type", &Process::GetSecondaryType, &Process::SetSecondaryType) .def("AddSecondaryInjectionDistribution",&SecondaryInjectionProcess::AddSecondaryInjectionDistribution) .def("GetSecondaryInjectionDistributions",&SecondaryInjectionProcess::GetSecondaryInjectionDistributions); From 6e8a5b1c5206953f9e7c6a02ee892dcba770cefd Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 11 Sep 2024 20:10:56 -0600 Subject: [PATCH 37/94] New access methods for process subclasses --- projects/injection/private/Process.cxx | 18 ++++++++++++++++++ .../injection/public/SIREN/injection/Process.h | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/projects/injection/private/Process.cxx b/projects/injection/private/Process.cxx index 524161c47..93c9228a7 100644 --- a/projects/injection/private/Process.cxx +++ b/projects/injection/private/Process.cxx @@ -90,6 +90,16 @@ std::vector> const & Phys return physical_distributions; } +void SetPhysicalDistributions(std::vector> const & distributions) { + for(std::vector>::const_iterator it_1 = distributions.begin(); it_1 != distributions.end(); ++it_1) { + for(std::vector>::const_iterator it_2 = it_1 + 1; it_2 != distributions.end(); ++it_2) { + if((*it_1) == (*it_2)) + throw std::runtime_error("Cannot add duplicate WeightableDistributions"); + } + } + physical_distributions = distributions; +} + PrimaryInjectionProcess::PrimaryInjectionProcess(siren::dataclasses::ParticleType _primary_type, std::shared_ptr _interactions) : PhysicalProcess(_primary_type, _interactions) {}; PrimaryInjectionProcess::PrimaryInjectionProcess(PrimaryInjectionProcess const & other) : PhysicalProcess(other), primary_injection_distributions(other.primary_injection_distributions) {}; @@ -144,6 +154,14 @@ SecondaryInjectionProcess & SecondaryInjectionProcess::operator=(SecondaryInject return *this; }; +void SecondaryInjectionProcess::SetSecondaryType(siren::dataclasses::ParticleType _primary_type) { + primary_type = _primary_type; +} + +siren::dataclasses::ParticleType SecondaryInjectionProcess::GetSecondaryType() const { + return primary_type; +} + void SecondaryInjectionProcess::AddPhysicalDistribution(std::shared_ptr dist) { throw std::runtime_error("Cannot add a physical distribution to an SecondaryInjectionProcess"); } diff --git a/projects/injection/public/SIREN/injection/Process.h b/projects/injection/public/SIREN/injection/Process.h index f6c429eaf..5510f0d28 100644 --- a/projects/injection/public/SIREN/injection/Process.h +++ b/projects/injection/public/SIREN/injection/Process.h @@ -68,6 +68,7 @@ class PhysicalProcess : public Process { virtual ~PhysicalProcess() = default; virtual void AddPhysicalDistribution(std::shared_ptr dist); std::vector> const & GetPhysicalDistributions() const; + virtual void SetPhysicalDistributions(std::vector> const & distributions); template void serialize(Archive & archive, std::uint32_t const version) { if(version == 0) { @@ -116,6 +117,9 @@ class SecondaryInjectionProcess : public PhysicalProcess { SecondaryInjectionProcess(SecondaryInjectionProcess && other); SecondaryInjectionProcess & operator=(SecondaryInjectionProcess const & other); SecondaryInjectionProcess & operator=(SecondaryInjectionProcess && other); + void SetSecondaryType(siren::dataclasses::ParticleType _primary_type); + siren::dataclasses::ParticleType GetSecondaryType() const; + virtual ~SecondaryInjectionProcess() = default; virtual void AddPhysicalDistribution(std::shared_ptr dist) override; virtual void AddSecondaryInjectionDistribution(std::shared_ptr dist); From 23c169a6194420ae5a2d87c0a1904a8711cad902 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 11 Sep 2024 20:47:41 -0600 Subject: [PATCH 38/94] Add more accessor method for processes --- projects/injection/private/Injector.cxx | 4 +++ projects/injection/private/Process.cxx | 34 +++++++++++++++++-- .../private/pybindings/injection.cxx | 17 ++++++---- .../public/SIREN/injection/Injector.h | 1 + .../public/SIREN/injection/Process.h | 2 ++ 5 files changed, 48 insertions(+), 10 deletions(-) diff --git a/projects/injection/private/Injector.cxx b/projects/injection/private/Injector.cxx index 877a729e6..e7f15b656 100644 --- a/projects/injection/private/Injector.cxx +++ b/projects/injection/private/Injector.cxx @@ -461,6 +461,10 @@ std::shared_ptr Injector::GetDetectorModel() con return detector_model; } +void Injector::SetDetectorModel(std::shared_ptr detector_model) { + this->detector_model = detector_model; +} + std::shared_ptr Injector::GetInteractions() const { return primary_process->GetInteractions(); } diff --git a/projects/injection/private/Process.cxx b/projects/injection/private/Process.cxx index 93c9228a7..0c467df92 100644 --- a/projects/injection/private/Process.cxx +++ b/projects/injection/private/Process.cxx @@ -90,7 +90,7 @@ std::vector> const & Phys return physical_distributions; } -void SetPhysicalDistributions(std::vector> const & distributions) { +void PhysicalProcess::SetPhysicalDistributions(std::vector> const & distributions) { for(std::vector>::const_iterator it_1 = distributions.begin(); it_1 != distributions.end(); ++it_1) { for(std::vector>::const_iterator it_2 = it_1 + 1; it_2 != distributions.end(); ++it_2) { if((*it_1) == (*it_2)) @@ -130,6 +130,20 @@ void PrimaryInjectionProcess::AddPrimaryInjectionDistribution(std::shared_ptr(dist)); } +void PrimaryInjectionProcess::SetPrimaryInjectionDistributions(std::vector> const & distributions) { + for(std::vector>::const_iterator it_1 = distributions.begin(); it_1 != distributions.end(); ++it_1) { + for(std::vector>::const_iterator it_2 = it_1 + 1; it_2 != distributions.end(); ++it_2) { + if((*it_1) == (*it_2)) + throw std::runtime_error("Cannot add duplicate PrimaryInjectionDistributions"); + } + } + primary_injection_distributions = distributions; + physical_distributions.clear(); + for(auto dist: primary_injection_distributions) { + physical_distributions.push_back(std::static_pointer_cast(dist)); + } +} + std::vector> const & PrimaryInjectionProcess::GetPrimaryInjectionDistributions() const { return primary_injection_distributions; } @@ -155,11 +169,11 @@ SecondaryInjectionProcess & SecondaryInjectionProcess::operator=(SecondaryInject }; void SecondaryInjectionProcess::SetSecondaryType(siren::dataclasses::ParticleType _primary_type) { - primary_type = _primary_type; + SetPrimaryType(_primary_type); } siren::dataclasses::ParticleType SecondaryInjectionProcess::GetSecondaryType() const { - return primary_type; + return GetPrimaryType(); } void SecondaryInjectionProcess::AddPhysicalDistribution(std::shared_ptr dist) { @@ -175,6 +189,20 @@ void SecondaryInjectionProcess::AddSecondaryInjectionDistribution(std::shared_pt secondary_injection_distributions.push_back(dist); } +void SecondaryInjectionProcess::SetSecondaryInjectionDistributions(std::vector> const & distributions) { + for(std::vector>::const_iterator it_1 = distributions.begin(); it_1 != distributions.end(); ++it_1) { + for(std::vector>::const_iterator it_2 = it_1 + 1; it_2 != distributions.end(); ++it_2) { + if((*it_1) == (*it_2)) + throw std::runtime_error("Cannot add duplicate SecondaryInjectionDistributions"); + } + } + secondary_injection_distributions = distributions; + physical_distributions.clear(); + for(auto dist: secondary_injection_distributions) { + physical_distributions.push_back(std::static_pointer_cast(dist)); + } +} + std::vector> const & SecondaryInjectionProcess::GetSecondaryInjectionDistributions() const { return secondary_injection_distributions; } diff --git a/projects/injection/private/pybindings/injection.cxx b/projects/injection/private/pybindings/injection.cxx index 2dfc7bdf4..494f9f884 100644 --- a/projects/injection/private/pybindings/injection.cxx +++ b/projects/injection/private/pybindings/injection.cxx @@ -44,20 +44,23 @@ PYBIND11_MODULE(injection,m) { class_, Process>(m, "PhysicalProcess") .def(init<>()) .def_property("primary_type", &Process::GetPrimaryType, &Process::SetPrimaryType) - .def("AddPhysicalDistribution",&PhysicalProcess::AddPhysicalDistribution) - .def("GetPhysicalDistributions",&PhysicalProcess::GetPhysicalDistributions); + .def_property("interactions", &Process::GetInteractions, &Process::SetInteractions) + .def_property("distributions", &PhysicalProcess::GetPhysicalDistributions, &PhysicalProcess::SetPhysicalDistributions) + .def("AddPhysicalDistribution",&PhysicalProcess::AddPhysicalDistribution); class_, Process>(m, "PrimaryInjectionProcess") .def(init<>()) .def_property("primary_type", &Process::GetPrimaryType, &Process::SetPrimaryType) - .def("AddPrimaryInjectionDistribution",&PrimaryInjectionProcess::AddPrimaryInjectionDistribution) - .def("GetPrimaryInjectionDistributions",&PrimaryInjectionProcess::GetPrimaryInjectionDistributions); + .def_property("interactions", &Process::GetInteractions, &Process::SetInteractions) + .def_property("distributions", &PrimaryInjectionProcess::GetPrimaryInjectionDistributions, &PrimaryInjectionProcess::SetPrimaryInjectionDistributions) + .def("AddPrimaryInjectionDistribution",&PrimaryInjectionProcess::AddPrimaryInjectionDistribution); class_, Process>(m, "SecondaryInjectionProcess") .def(init<>()) - .def_property("secondary_type", &Process::GetSecondaryType, &Process::SetSecondaryType) - .def("AddSecondaryInjectionDistribution",&SecondaryInjectionProcess::AddSecondaryInjectionDistribution) - .def("GetSecondaryInjectionDistributions",&SecondaryInjectionProcess::GetSecondaryInjectionDistributions); + .def_property("secondary_type", &SecondaryInjectionProcess::GetSecondaryType, &SecondaryInjectionProcess::SetSecondaryType) + .def_property("interactions", &Process::GetInteractions, &Process::SetInteractions) + .def_property("distributions", &SecondaryInjectionProcess::GetSecondaryInjectionDistributions, &SecondaryInjectionProcess::SetSecondaryInjectionDistributions) + .def("AddSecondaryInjectionDistribution",&SecondaryInjectionProcess::AddSecondaryInjectionDistribution); // Injection diff --git a/projects/injection/public/SIREN/injection/Injector.h b/projects/injection/public/SIREN/injection/Injector.h index c7249eb9d..c776c9971 100644 --- a/projects/injection/public/SIREN/injection/Injector.h +++ b/projects/injection/public/SIREN/injection/Injector.h @@ -103,6 +103,7 @@ friend cereal::access; virtual std::tuple SecondaryInjectionBounds(siren::dataclasses::InteractionRecord const & interaction) const; virtual std::vector> GetPrimaryInjectionDistributions() const; virtual std::shared_ptr GetDetectorModel() const; + virtual void SetDetectorModel(std::shared_ptr detector_model); virtual std::shared_ptr GetInteractions() const; unsigned int InjectedEvents() const; unsigned int EventsToInject() const; diff --git a/projects/injection/public/SIREN/injection/Process.h b/projects/injection/public/SIREN/injection/Process.h index 5510f0d28..c3d926400 100644 --- a/projects/injection/public/SIREN/injection/Process.h +++ b/projects/injection/public/SIREN/injection/Process.h @@ -94,6 +94,7 @@ class PrimaryInjectionProcess : public PhysicalProcess { virtual ~PrimaryInjectionProcess() = default; virtual void AddPhysicalDistribution(std::shared_ptr dist) override; virtual void AddPrimaryInjectionDistribution(std::shared_ptr dist); + void SetPrimaryInjectionDistributions(std::vector> const & distributions); std::vector> const & GetPrimaryInjectionDistributions() const; template void serialize(Archive & archive, std::uint32_t const version) { @@ -123,6 +124,7 @@ class SecondaryInjectionProcess : public PhysicalProcess { virtual ~SecondaryInjectionProcess() = default; virtual void AddPhysicalDistribution(std::shared_ptr dist) override; virtual void AddSecondaryInjectionDistribution(std::shared_ptr dist); + void SetSecondaryInjectionDistributions(std::vector> const & distributions); std::vector> const & GetSecondaryInjectionDistributions() const; template void serialize(Archive & archive, std::uint32_t const version) { From c97cd103c4ac97ef344b1ff98cf474e831cf7fdb Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 11 Sep 2024 22:21:46 -0600 Subject: [PATCH 39/94] Additional setters and getters --- projects/injection/private/Injector.cxx | 10 ++++++++++ projects/injection/private/pybindings/injection.cxx | 2 ++ projects/injection/public/SIREN/injection/Injector.h | 2 ++ 3 files changed, 14 insertions(+) diff --git a/projects/injection/private/Injector.cxx b/projects/injection/private/Injector.cxx index e7f15b656..d6e8ff059 100644 --- a/projects/injection/private/Injector.cxx +++ b/projects/injection/private/Injector.cxx @@ -135,6 +135,16 @@ void Injector::AddSecondaryProcess(std::shared_ptrGetPrimaryType(), vtx_dist}); } +void Injector::SetSecondaryProcesses(std::vector> secondaries) { + secondary_processes.clear(); + secondary_position_distributions.clear(); + secondary_process_map.clear(); + secondary_position_distribution_map.clear(); + for(auto secondary : secondaries) { + AddSecondaryProcess(secondary); + } +} + siren::dataclasses::InteractionRecord Injector::NewRecord() const { siren::dataclasses::InteractionRecord record; record.signature.primary_type = primary_process->GetPrimaryType(); diff --git a/projects/injection/private/pybindings/injection.cxx b/projects/injection/private/pybindings/injection.cxx index 494f9f884..97c3bc1c8 100644 --- a/projects/injection/private/pybindings/injection.cxx +++ b/projects/injection/private/pybindings/injection.cxx @@ -71,6 +71,7 @@ PYBIND11_MODULE(injection,m) { .def(init, std::shared_ptr, std::shared_ptr>()) .def(init, std::shared_ptr, std::vector>, std::shared_ptr>()) .def("SetStoppingCondition",&Injector::SetStoppingCondition) + .def("GetStoppingCondition",&Injector::GetStoppingCondition) .def("SetPrimaryProcess",&Injector::SetPrimaryProcess) .def("AddSecondaryProcess",&Injector::AddSecondaryProcess) .def("GetPrimaryProcess",&Injector::GetPrimaryProcess) @@ -83,6 +84,7 @@ PYBIND11_MODULE(injection,m) { .def("Name",&Injector::Name) .def("GetPrimaryInjectionDistributions",&Injector::GetPrimaryInjectionDistributions) .def("GetDetectorModel",&Injector::GetDetectorModel) + .def("SetDetectorModel",&Injector::SetDetectorModel) .def("GetInteractions",&Injector::GetInteractions) .def("InjectedEvents",&Injector::InjectedEvents) .def("EventsToInject",&Injector::EventsToInject) diff --git a/projects/injection/public/SIREN/injection/Injector.h b/projects/injection/public/SIREN/injection/Injector.h index c776c9971..bd82e28bf 100644 --- a/projects/injection/public/SIREN/injection/Injector.h +++ b/projects/injection/public/SIREN/injection/Injector.h @@ -78,6 +78,7 @@ friend cereal::access; Injector(unsigned int events_to_inject, std::shared_ptr detector_model, std::shared_ptr primary_process, std::vector> secondary_processes, std::shared_ptr random); void SetStoppingCondition(std::function, size_t)> f_in) {stopping_condition = f_in;} + std::function, size_t)> GetStoppingCondition() {return stopping_condition;} std::shared_ptr FindPrimaryVertexDistribution(std::shared_ptr process); std::shared_ptr FindSecondaryVertexDistribution(std::shared_ptr process); void SetPrimaryProcess(std::shared_ptr primary); @@ -85,6 +86,7 @@ friend cereal::access; std::vector> GetSecondaryProcesses() {return secondary_processes;} std::map> GetSecondaryProcessMap() {return secondary_process_map;} void AddSecondaryProcess(std::shared_ptr secondary); + void SetSecondaryProcesses(std::vector> secondary_processes); virtual siren::dataclasses::InteractionRecord NewRecord() const; // set primary type from primary process; void SetRandom(std::shared_ptr random); virtual void SampleCrossSection(siren::dataclasses::InteractionRecord & record) const; From b4e7f6f5b4b413db5d1eeff9b36da8a2fbd97d17 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 11 Sep 2024 22:22:30 -0600 Subject: [PATCH 40/94] Set primary type when setting interactions --- projects/injection/private/Process.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/projects/injection/private/Process.cxx b/projects/injection/private/Process.cxx index 0c467df92..0543f7aa0 100644 --- a/projects/injection/private/Process.cxx +++ b/projects/injection/private/Process.cxx @@ -25,6 +25,7 @@ Process & Process::operator=(Process && other) { void Process::SetInteractions(std::shared_ptr _interactions) { interactions = _interactions; + primary_type = interactions->GetPrimaryType(); } std::shared_ptr Process::GetInteractions() const { @@ -33,6 +34,8 @@ std::shared_ptr Process::GetInteractions() void Process::SetPrimaryType(siren::dataclasses::ParticleType _primary_type) { primary_type = _primary_type; + if(interactions) + interactions->SetPrimaryType(_primary_type); } siren::dataclasses::ParticleType Process::GetPrimaryType() const { From 488548607e1db100b1f34ae384ac821c892723b9 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 11 Sep 2024 22:22:56 -0600 Subject: [PATCH 41/94] Additional setters and getters --- projects/interactions/private/InteractionCollection.cxx | 8 ++++++++ .../private/pybindings/InteractionCollection.h | 2 ++ .../public/SIREN/interactions/InteractionCollection.h | 2 ++ 3 files changed, 12 insertions(+) diff --git a/projects/interactions/private/InteractionCollection.cxx b/projects/interactions/private/InteractionCollection.cxx index 9a3464a73..af6f0e411 100644 --- a/projects/interactions/private/InteractionCollection.cxx +++ b/projects/interactions/private/InteractionCollection.cxx @@ -116,6 +116,14 @@ bool InteractionCollection::MatchesPrimary(dataclasses::InteractionRecord const return primary_type == record.signature.primary_type; } +siren::dataclasses::ParticleType InteractionCollection::GetPrimaryType() const { + return primary_type; +} + +void InteractionCollection::SetPrimaryType(siren::dataclasses::ParticleType primary_type) { + this->primary_type = primary_type; +} + std::map InteractionCollection::TotalCrossSectionByTarget(siren::dataclasses::InteractionRecord const & record) const { std::map result; for(siren::dataclasses::ParticleType target : target_types) { diff --git a/projects/interactions/private/pybindings/InteractionCollection.h b/projects/interactions/private/pybindings/InteractionCollection.h index 5d8314acc..1df424399 100644 --- a/projects/interactions/private/pybindings/InteractionCollection.h +++ b/projects/interactions/private/pybindings/InteractionCollection.h @@ -35,5 +35,7 @@ void register_InteractionCollection(pybind11::module_ & m) { .def("TotalDecayWidth",&InteractionCollection::TotalDecayWidth) .def("TotalDecayLength",&InteractionCollection::TotalDecayLength) .def("MatchesPrimary",&InteractionCollection::MatchesPrimary) + .def("GetPrimaryType",&InteractionCollection::GetPrimaryType) + .def("SetPrimaryType",&InteractionCollection::SetPrimaryType) ; } diff --git a/projects/interactions/public/SIREN/interactions/InteractionCollection.h b/projects/interactions/public/SIREN/interactions/InteractionCollection.h index 243b41142..ecab54659 100644 --- a/projects/interactions/public/SIREN/interactions/InteractionCollection.h +++ b/projects/interactions/public/SIREN/interactions/InteractionCollection.h @@ -63,6 +63,8 @@ class InteractionCollection { }; double TotalDecayWidth(siren::dataclasses::InteractionRecord const & record) const; double TotalDecayLength(siren::dataclasses::InteractionRecord const & record) const; + siren::dataclasses::ParticleType GetPrimaryType() const; + void SetPrimaryType(siren::dataclasses::ParticleType primary_type); virtual bool MatchesPrimary(dataclasses::InteractionRecord const & record) const; std::map TotalCrossSectionByTarget(siren::dataclasses::InteractionRecord const & record) const; std::map TotalCrossSectionByTargetAllFinalStates(siren::dataclasses::InteractionRecord const & record) const; From 3b62df20b247f6261f91118345052c9619da263d Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 11 Sep 2024 22:24:13 -0600 Subject: [PATCH 42/94] Produce a random seed by default. Getter for seed --- projects/utilities/private/Random.cxx | 31 +++++++-- .../private/pybindings/utilities.cxx | 4 +- .../utilities/public/SIREN/utilities/Random.h | 64 ++++++++++--------- 3 files changed, 64 insertions(+), 35 deletions(-) diff --git a/projects/utilities/private/Random.cxx b/projects/utilities/private/Random.cxx index 78a2e0f2f..214d2d12a 100644 --- a/projects/utilities/private/Random.cxx +++ b/projects/utilities/private/Random.cxx @@ -1,19 +1,27 @@ #include "SIREN/utilities/Random.h" +#include +#include #include +#include // for uint32_t #include +#include + +namespace { + std::mutex global_seed_lock; +} namespace siren { namespace utilities { - SIREN_random::SIREN_random(void){ + SIREN_random::SIREN_random() { // default to boring seed - seed = 1; + seed = generate_seed(); configuration = std::default_random_engine(seed); generator = std::uniform_real_distribution( 0.0, 1.0); } - SIREN_random::SIREN_random( unsigned int _seed ){ + SIREN_random::SIREN_random(uint64_t _seed) { seed = _seed; configuration = std::default_random_engine(seed); generator = std::uniform_real_distribution( 0.0, 1.0); @@ -40,10 +48,25 @@ namespace utilities { } // reconfigures the generator with a new seed - void SIREN_random::set_seed( unsigned int new_seed) { + void SIREN_random::set_seed(uint64_t new_seed) { seed = new_seed; this->configuration = std::default_random_engine(seed); } + uint64_t SIREN_random::get_seed() const { + return seed; + } + + uint64_t SIREN_random::generate_seed() { + std::atomic_thread_fence(std::memory_order_acquire); + std::lock_guard lg(global_seed_lock); + std::hash string_hash; + std::stringstream s; + s << time(0) << getpid() << gethostid(); + std::atomic_thread_fence(std::memory_order_release); + uint64_t seed = string_hash(s.str()); + return seed; + } + } // namespace utilities } // namespace siren diff --git a/projects/utilities/private/pybindings/utilities.cxx b/projects/utilities/private/pybindings/utilities.cxx index 0feafd28f..c2581980c 100644 --- a/projects/utilities/private/pybindings/utilities.cxx +++ b/projects/utilities/private/pybindings/utilities.cxx @@ -16,5 +16,7 @@ PYBIND11_MODULE(utilities,m) { .def(init<>()) .def(init()) .def("Uniform",&SIREN_random::Uniform) - .def("set_seed",&SIREN_random::set_seed); + .def("set_seed",&SIREN_random::set_seed) + .def("get_seed",&SIREN_random::get_seed) + .def_static("generate_seed",&SIREN_random::generate_seed); } diff --git a/projects/utilities/public/SIREN/utilities/Random.h b/projects/utilities/public/SIREN/utilities/Random.h index f6ae1e9db..599e23146 100644 --- a/projects/utilities/public/SIREN/utilities/Random.h +++ b/projects/utilities/public/SIREN/utilities/Random.h @@ -8,6 +8,7 @@ // this implements a class to sample numbers just like in an i3 service #include // default_random_engine, uniform_real_distribution +#include // for uint32_t #include #include @@ -22,43 +23,46 @@ namespace siren { namespace utilities { - class SIREN_random{ - public: - SIREN_random(); - SIREN_random( unsigned int _seed ); +class SIREN_random{ +public: + SIREN_random(); + SIREN_random(uint64_t _seed); - // this naming convention is used to - double Uniform( double from=0.0, double to=1.0); - double PowerLaw(double min, double max, double n); + // this naming convention is used to + double Uniform( double from=0.0, double to=1.0); + double PowerLaw(double min, double max, double n); - // in case this is set up without a seed! - void set_seed(unsigned int new_seed); + // in case this is set up without a seed! + void set_seed(uint64_t new_seed); + uint64_t get_seed() const; - template - void save(Archive & archive, std::uint32_t const version) const { - if(version == 0) { - archive(::cereal::make_nvp("Seed", seed)); - } else { - throw std::runtime_error("SIREN_random only supports version <= 0!"); - } - }; + static uint64_t generate_seed(); - template - void load(Archive & archive, std::uint32_t const version) { - if(version == 0) { - archive(::cereal::make_nvp("Seed", seed)); - set_seed(seed); - } else { - throw std::runtime_error("SIREN_random only supports version <= 0!"); - } - }; + template + void save(Archive & archive, std::uint32_t const version) const { + if(version == 0) { + archive(::cereal::make_nvp("Seed", seed)); + } else { + throw std::runtime_error("SIREN_random only supports version <= 0!"); + } + }; - private: - unsigned int seed; - std::default_random_engine configuration; - std::uniform_real_distribution generator; + template + void load(Archive & archive, std::uint32_t const version) { + if(version == 0) { + archive(::cereal::make_nvp("Seed", seed)); + set_seed(seed); + } else { + throw std::runtime_error("SIREN_random only supports version <= 0!"); + } }; +private: + uint64_t seed; + std::default_random_engine configuration; + std::uniform_real_distribution generator; +}; + } // namespace utilities } // namespace siren From 61dabf328b60532c13efc57816b6893d492cb4f5 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 11 Sep 2024 22:26:14 -0600 Subject: [PATCH 43/94] Rework Injector wrapper with @property --- python/Injector.py | 361 +++++++++++++++++++++++++++++---------------- 1 file changed, 232 insertions(+), 129 deletions(-) diff --git a/python/Injector.py b/python/Injector.py index 6b0bc233d..2b69ccb1a 100644 --- a/python/Injector.py +++ b/python/Injector.py @@ -31,56 +31,40 @@ class Injector: def __init__( self, - number_of_events: int, - detector_model: "DetectorModel", - random: "SIREN_random", + number_of_events: Optional[int] = None, + detector_model: Optional["DetectorModel"] = None, + seed: Optional[int] = None, primary_interactions: Dict["ParticleType", List[Union["CrossSection", "Decay", "Interaction"]]], primary_injection_distributions: List["PrimaryInjectionDistribution"], secondary_interactions: Optional[Dict["ParticleType", List[Union["CrossSection", "Decay", "Interaction"]]]] = None, secondary_injection_distributions: Optional[Dict["ParticleType", List["SecondaryInjectionDistribution"]]] = None, ): - self.number_of_events = number_of_events + self.__seed = None + self.__number_of_events = 0 + self.__detector_model = None - self.detector_model = detector_model + self.__primary_type = None + self.__primary_interactions = [] + self.__primary_injection_distributions = [] + + self.__secondary_interactions = [] + self.__secondary_injection_distributions = [] + self.__stopping_condition = None + + self.__injector = None if len(primary_interactions) != 1: raise ValueError(f"len(primary_interactions) != 1") if (secondary_interactions is None) != (secondary_injection_distributions is None): - raise ValueError("Neither or both of secondary_interactions and secondary_injection_distributions must be provided") + raise ValueError("Both or neither secondary_interactions and secondary_injection_distributions must be provided") if secondary_interactions is None: secondary_interactions = dict() secondary_injection_distributions = dict() - self.primary_interactions = primary_interactions - self.primary_injection_distributions = primary_injection_distributions - - primary_type, primary_interactions = list(primary_interactions.items())[0] - - self.primary_interaction_collection = _interactions.InteractionCollection( - primary_type, primary_interactions - ) - self.primary_process = _injection.PrimaryInjectionProcess( - primary_type, self.primary_interaction_collection - ) - for dist in primary_injection_distributions: - self.primary_process.AddPrimaryInjectionDistribution(dist) - - self.secondary_interactions = secondary_interactions - self.secondary_injection_distributions = secondary_injection_distributions - - self.secondary_interaction_collections = [] - self.secondary_processes = [] - for secondary_type, secondary_interactions in secondary_interactions.items(): - secondary_distributions = self.secondary_injection_distributions[secondary_type] - secondary_process = SecondaryInjectionProcess(secondary_type, secondary_interactions) - for dist in secondary_distributions: - secondary_process.AddSecondaryInjectionDistribution(dist) - self.secondary_processes.append(secondary_process) - - self.injector = _injection.Injector( + self.__injector = _injection.Injector( self.number_of_events, self.detector_model, self.primary_process, @@ -88,116 +72,235 @@ def __init__( self.random, ) - # TODO define wrapper functions that modify the internal state of the python object - @wraps(_Injector.SetPrimaryProcess) - def SetPrimaryProcess(self, primary_process): - # Get the internals first - primary_injection_distributions = primary_process.GetPrimaryInjectionDistributions() - primary_interaction_collection = primary_process.GetInteractionCollection() - primary_interactions = list(primary_interaction_collection.GetCrossSections()) + list(primary_interaction_collection.GetDecays()) - - # Now we can overwite things - self.injector.SetPrimaryProcess(primary_process) - self.primary_process = primary_process - self.primary_injection_distributions = primary_injection_distributions - self.primary_interaction_collection = primary_interaction_collection - self.primary_interactions = {primary_process.primary_type: primary_interactions} - - @wraps(_Injector.SetStoppingCondition) - def SetStoppingCondition(self, stopping_condition): - self.stopping_condition = stopping_condition - self.injector.SetStoppingCondition(stopping_condition) - - @wraps(_Injector.AddSecondaryProcess) - def AddSecondaryProcess(self, secondary_process): - # Update internal state - secondary_type = secondary_process.secondary_type - secondary_distributions = secondary_process.GetSecondaryInjectionDistributions() - secondary_interaction_collection = secondary_process.GetInteractionCollection() - secondary_interactions = list(secondary_interaction_collection.GetCrossSections()) + list(secondary_interaction_collection.GetDecays()) - - # Update class attributes - self.secondary_processes.append(secondary_process) - if secondary_type not in self.secondary_interactions: - self.secondary_interactions[secondary_type] = [] - self.secondary_interactions[secondary_type].extend(secondary_interactions) - if secondary_type not in self.secondary_injection_distributions: - self.secondary_injection_distributions[secondary_type] = [] - self.secondary_injection_distributions[secondary_type].extend(secondary_distributions) - - # Update the underlying C++ object - self.injector.AddSecondaryProcess(secondary_process) - - @wraps(_Injector.GetPrimaryProcess) - def GetPrimaryProcess(self): - return self.primary_process - - @wraps(_Injector.GetSecondaryProcessMap) - def GetSecondaryProcesses(self): - return self.secondary_processes + def __initialize_injector(self): + if self.__seed is None: + random = _utilities.SIREN_random() + self.__seed = random.get_seed() + else: + random = _utilities.SIREN_random(self.__seed) - @wraps(_Injector.NewRecord) - def NewRecord(self): - return self.injector.NewRecord() + if self.__number_of_events is None: + raise ValueError("number_of_events must be provided") + elif self.__number_of_events <= 0: + raise ValueError("number_of_events must be positive") - @wraps(_Injector.SetRandom) - def SetRandom(self, random): - self.injector.SetRandom(random) + if self.__detector_model is None: + raise ValueError("detector_model must be provided") - @wraps(_Injector.GenerateEvent) - def GenerateEvent(self): - return self.injector.GenerateEvent() + if self.__primary_type is None: + raise ValueError("primary_type must be provided") - @wraps(_Injector.DensityVariables) - def DensityVariables(self): - return self.injector.DensityVariables() + if len(self.__primary_interactions) == 0: + raise ValueError("primary_interactions must be provided") - @wraps(_Injector.Name) - def Name(self): - return self.injector.Name() - - @wraps(_Injector.GetPrimaryInjectionDistributions) - def GetPrimaryInjectionDistributions(self): - return self.primary_injection_distributions + if len(self.__primary_injection_distributions) == 0: + raise ValueError("primary_injection_distributions must be provided") - @wraps(_Injector.GetDetectorModel) - def GetDetectorModel(self): - return self.detector_model + if len(self.__secondary_interactions) == 0: + raise ValueError("secondary_interactions must be provided") - @wraps(_Injector.GetInteractions) - def GetInteractions(self): - return self.injector.GetInteractions() + if len(self.__secondary_injection_distributions) == 0: + raise ValueError("secondary_injection_distributions must be provided") - @wraps(_Injector.InjectedEvents) - def InjectedEvents(self): - return self.injector.InjectedEvents() + if list(sorted(self.__secondary_interactions.keys())) != list(sorted(self.__secondary_injection_distributions.keys())): + raise ValueError("secondary_interactions and secondary_injection_distributions must have the same keys") - @wraps(_Injector.EventsToInject) - def EventsToInject(self): - return self.injector.EventsToInject() + primary_type = self.primary_type + primary_interaction_collection = _interactions.InteractionCollection( + primary_type, self.primary_interactions + ) + primary_process = _injection.PrimaryInjectionProcess( + primary_type, primary_interaction_collection + ) + primary_process.distributions = self.primary_injection_distributions + + secondary_interactions = self.secondary_interactions + secondary_injection_distributions = self.secondary_injection_distributions + + secondary_interaction_collections = [] + secondary_processes = [] + for secondary_type, secondary_interactions in secondary_interactions.items(): + secondary_interaction_collection = _interactions.InteractionCollection( + secondary_type, secondary_interactions + ) + secondary_process = SecondaryInjectionProcess( + secondary_type, secondary_interaction_collection + ) + secondary_process.distributions = secondary_injection_distributions[secondary_type] + secondary_processes.append(secondary_process) + + self.__injector = _Injector( + self.number_of_events, + self.detector_model, + primary_process, + secondary_processes, + random, + ) + + if self.__stopping_condition is not None: + self.__injector.SetStoppingCondition(self.__stopping_condition) + + @property + def seed(self): + return self.__seed + + @property.setter + def seed(self, seed): + self.__seed = seed + if self.__injector is not None: + self.__injector.GetRandom().set_seed(seed) + + @property + def number_of_events(self): + if self.__injector is not None: + return self.__injector.EventsToInject() + return self.__number_of_events + + @property + def detector_model(self): + if self.__injector is not None: + return self.__injector.GetDetectorModel() + return self.__detector_model + + @property.setter + def detector_model(self, detector_model): + if self.__injector is not None: + self.__injector.SetDetectorModel(detector_model) + self.__detector_model = detector_model + + @property + def primary_type(self): + return self.__primary_type + + @property.setter + def primary_type(self, primary_type): + if self.__injector is not None: + primary_process = self.__injector.GetPrimaryProcess() + primary_process.primary_type = primary_type + self.__primary_type = primary_type + + @property + def primary_interactions(self): + return self.__primary_interactions + + @property.setter + def primary_interactions(self, primary_interactions): + if self.__injector is not None: + primary_process = self.__injector.GetPrimaryProcess() + primary_interaction_collection = _interactions.InteractionCollection( + self.primary_type, primary_interactions + ) + primary_process.interactions = primary_interaction_collection + self.__primary_interactions = primary_interactions + + @property + def primary_injection_distributions(self): + return self.__primary_injection_distributions + + @property.setter + def primary_injection_distributions(self, primary_injection_distributions): + if self.__injector is not None: + primary_process = self.__injector.GetPrimaryProcess() + primary_process.distributions = primary_injection_distributions + self.__primary_injection_distributions = primary_injection_distributions + + @property + def secondary_interactions(self): + return self.__secondary_interactions + + @property.setter + def secondary_interactions(self, secondary_interactions): + if self.__injector is not None: + secondary_processes = self.__injector.GetSecondaryProcessMap() + current_secondary_types = sorted(list(secondary_processes.keys())) + new_secondary_types = sorted(list(secondary_interactions.keys())) + if current_secondary_types != new_secondary_types: + raise ValueError("Cannot change the secondary types after initialization") + for secondary_type, secondary_process in secondary_processes.items(): + secondary_process.interactions = secondary_interactions[secondary_type] + self.__secondary_interactions = secondary_interactions + + @property + def secondary_injection_distributions(self): + return self.__secondary_injection_distributions + + @property.setter + def secondary_injection_distributions(self, secondary_injection_distributions): + if self.__injector is not None: + secondary_processes = self.__injector.GetSecondaryProcesses() + current_secondary_types = sorted(list(secondary_processes.keys())) + new_secondary_types = sorted(list(secondary_injection_distributions.keys())) + if current_secondary_types != new_secondary_types: + raise ValueError("Cannot change the secondary types after initialization") + for secondary_type, secondary_process in secondary_injection_distributions.items(): + secondary_process.distributions = secondary_distributions[secondary_type] + self.__secondary_injection_distributions = secondary_injection_distributions + + @property + def stopping_condition(self): + return self.__stopping_condition + + @property.setter + def stopping_condition(self, stopping_condition): + if self.__injector is not None: + self.__injector.SetStoppingCondition(stopping_condition) + self.__stopping_condition = stopping_condition + + @wraps(_Injector.NewRecord) + def new_record(self): + return self.__injector.NewRecord() + self.new_record.__name__ = "new_record" + self.new_record.__doc__ = _Injector.NewRecord.__doc__.replace("NewRecord", "new_record") + + @wraps(_Injector.GenerateEvent) + def generate_event(self): + if self.__injector is None: + self.__initialize_injector() + return self.__injector.GenerateEvent() + self.generate_event.__name__ = "generate_event" + self.generate_event.__doc__ = _Injector.GenerateEvent.__doc__.replace("GenerateEvent", "generate_event") + + @property + def density_variables(self): + if self.__injector is not None: + return self.__injector.DensityVariables() + return None + + @property + def injected_events(self): + if self.__injector is not None: + return self.__injector.InjectedEvents() + return 0 @wraps(_Injector.ResetInjectedEvents) - def ResetInjectedEvents(self): - self.injector.ResetInjectedEvents() + def reset_injected_events(self): + if self.__injector is not None: + self.__injector.ResetInjectedEvents() + self.reset_injected_events.__name__ = "reset_injected_events" + self.reset_injected_events.__doc__ = _Injector.ResetInjectedEvents.__doc__.replace("ResetInjectedEvents", "reset_injected_events") @wraps(_Injector.SaveInjector) - def SaveInjector(self, filename): - self.injector.SaveInjector(filename) + def save(self, filename): + self.__injector.SaveInjector(filename) + self.save.__name__ = "save" + self.save.__doc__ = _Injector.SaveInjector.__doc__.replace("SaveInjector", "save") @wraps(_Injector.LoadInjector) - def LoadInjector(self, filename): - self.injector.LoadInjector(filename) + def load(self, filename): + self.__injector.LoadInjector(filename) # Update Python object state after loading - self.primary_process = self.injector.GetPrimaryProcess() - self.secondary_processes = self.injector.GetSecondaryProcesses() - self.primary_injection_distributions = self.primary_process.GetPrimaryInjectionDistributions() - self.primary_interaction_collection = self.primary_process.GetInteractionCollection() - self.primary_interactions = {self.primary_process.primary_type: list(self.primary_interaction_collection.GetCrossSections()) + list(self.primary_interaction_collection.GetDecays())} - # Update secondary interactions and distributions - self.secondary_interactions = {} - self.secondary_injection_distributions = {} - for process in self.secondary_processes: - secondary_type = process.secondary_type - self.secondary_interactions[secondary_type] = list(process.GetInteractionCollection().GetCrossSections()) + list(process.GetInteractionCollection().GetDecays()) - self.secondary_injection_distributions[secondary_type] = process.GetSecondaryInjectionDistributions() + self.__number_of_events = self.__injector.EventsToInject() + self.__detector_model = self.__injector.GetDetectorModel() + primary_process = self.__injector.GetPrimaryProcess() + self.__primary_type = primary_process.primary_type + self.__primary_interactions = list(primary_process.interactions.GetCrossSections()) + list(primary_process.interactions.GetDecays()) + self.__primary_injection_distributions = list(primary_process.distributions) + + self.__secondary_interactions = {} + self.__secondary_injection_distributions = {} + for secondary_type, secondary_process in self.__injector.GetSecondaryProcessMap(): + self.__secondary_interactions[secondary_type] = list(secondary_process.interactions.GetCrossSections()) + list(secondary_process.interactions.GetDecays()) + self.__secondary_injection_distributions[secondary_type] = list(secondary_process.distributions) + + self.__stopping_condition = self.__injector.GetStoppingCondition() From 324699c8c58c16dac42b313ab0a743870aafb51d Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 11 Sep 2024 22:43:07 -0600 Subject: [PATCH 44/94] Fix some obvious runtime issues --- python/Injector.py | 88 +++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/python/Injector.py b/python/Injector.py index 2b69ccb1a..3a02dcaba 100644 --- a/python/Injector.py +++ b/python/Injector.py @@ -10,7 +10,7 @@ import collections from functools import wraps -from typing import Tuple, List, Dict, Optional, Union +from typing import Tuple, List, Dict, Optional, Union, Callable from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -21,23 +21,24 @@ ParticleType = _dataclasses.Particle.ParticleType CrossSection = _interactions.CrossSection Decay = _interactions.Decay -Interaction = _interactions.Interaction DetectorModel = _detector.DetectorModel SIREN_random = _utilities.SIREN_random PrimaryInjectionDistribution = _distributions.PrimaryInjectionDistribution SecondaryInjectionDistribution = _distributions.SecondaryInjectionDistribution SecondaryInjectionProcess = _injection.SecondaryInjectionProcess +InteractionTreeDatum = _dataclasses.InteractionTreeDatum class Injector: def __init__( self, number_of_events: Optional[int] = None, - detector_model: Optional["DetectorModel"] = None, + detector_model: Optional[_detector.DetectorModel] = None, seed: Optional[int] = None, - primary_interactions: Dict["ParticleType", List[Union["CrossSection", "Decay", "Interaction"]]], - primary_injection_distributions: List["PrimaryInjectionDistribution"], - secondary_interactions: Optional[Dict["ParticleType", List[Union["CrossSection", "Decay", "Interaction"]]]] = None, - secondary_injection_distributions: Optional[Dict["ParticleType", List["SecondaryInjectionDistribution"]]] = None, + primary_interactions: Dict[_dataclasses.Particle.ParticleType, List[Union[_interactions.CrossSection, _interactions.Decay]]] = None, + primary_injection_distributions: List[_distributions.PrimaryInjectionDistribution] = None, + secondary_interactions: Optional[Dict[_dataclasses.Particle.ParticleType, List[Union[_interactions.CrossSection, _interactions.Decay]]]] = None, + secondary_injection_distributions: Optional[Dict[_dataclasses.Particle.ParticleType, List[_distributions.SecondaryInjectionDistribution]]] = None, + stopping_condition: Optional[Callable[[_dataclasses.InteractionTreeDatum, int], bool]] = None, ): self.__seed = None self.__number_of_events = 0 @@ -47,31 +48,30 @@ def __init__( self.__primary_interactions = [] self.__primary_injection_distributions = [] - self.__secondary_interactions = [] - self.__secondary_injection_distributions = [] + self.__secondary_interactions = {} + self.__secondary_injection_distributions = {} self.__stopping_condition = None self.__injector = None - if len(primary_interactions) != 1: - raise ValueError(f"len(primary_interactions) != 1") - - if (secondary_interactions is None) != (secondary_injection_distributions is None): - raise ValueError("Both or neither secondary_interactions and secondary_injection_distributions must be provided") - - if secondary_interactions is None: - secondary_interactions = dict() - secondary_injection_distributions = dict() + if seed is not None: + self.__seed = seed + if number_of_events is not None: + self.__number_of_events = number_of_events + if detector_model is not None: + self.__detector_model = detector_model + if primary_interactions is not None: + self.__primary_interactions = primary_interactions + if primary_injection_distributions is not None: + self.__primary_injection_distributions = primary_injection_distributions + if secondary_interactions is not None: + self.__secondary_interactions = secondary_interactions + if secondary_injection_distributions is not None: + self.__secondary_injection_distributions = secondary_injection_distributions + if stopping_condition is not None: + self.__stopping_condition = stopping_condition - self.__injector = _injection.Injector( - self.number_of_events, - self.detector_model, - self.primary_process, - self.secondary_processes, - self.random, - ) - def __initialize_injector(self): if self.__seed is None: random = _utilities.SIREN_random() @@ -90,8 +90,8 @@ def __initialize_injector(self): if self.__primary_type is None: raise ValueError("primary_type must be provided") - if len(self.__primary_interactions) == 0: - raise ValueError("primary_interactions must be provided") + if len(self.__primary_interactions) != 1: + raise ValueError("primary_interactions must have exactly one key") if len(self.__primary_injection_distributions) == 0: raise ValueError("primary_injection_distributions must be provided") @@ -144,7 +144,7 @@ def __initialize_injector(self): def seed(self): return self.__seed - @property.setter + @seed.setter def seed(self, seed): self.__seed = seed if self.__injector is not None: @@ -162,7 +162,7 @@ def detector_model(self): return self.__injector.GetDetectorModel() return self.__detector_model - @property.setter + @detector_model.setter def detector_model(self, detector_model): if self.__injector is not None: self.__injector.SetDetectorModel(detector_model) @@ -172,7 +172,7 @@ def detector_model(self, detector_model): def primary_type(self): return self.__primary_type - @property.setter + @primary_type.setter def primary_type(self, primary_type): if self.__injector is not None: primary_process = self.__injector.GetPrimaryProcess() @@ -183,7 +183,7 @@ def primary_type(self, primary_type): def primary_interactions(self): return self.__primary_interactions - @property.setter + @primary_interactions.setter def primary_interactions(self, primary_interactions): if self.__injector is not None: primary_process = self.__injector.GetPrimaryProcess() @@ -197,7 +197,7 @@ def primary_interactions(self, primary_interactions): def primary_injection_distributions(self): return self.__primary_injection_distributions - @property.setter + @primary_injection_distributions.setter def primary_injection_distributions(self, primary_injection_distributions): if self.__injector is not None: primary_process = self.__injector.GetPrimaryProcess() @@ -208,7 +208,7 @@ def primary_injection_distributions(self, primary_injection_distributions): def secondary_interactions(self): return self.__secondary_interactions - @property.setter + @secondary_interactions.setter def secondary_interactions(self, secondary_interactions): if self.__injector is not None: secondary_processes = self.__injector.GetSecondaryProcessMap() @@ -224,7 +224,7 @@ def secondary_interactions(self, secondary_interactions): def secondary_injection_distributions(self): return self.__secondary_injection_distributions - @property.setter + @secondary_injection_distributions.setter def secondary_injection_distributions(self, secondary_injection_distributions): if self.__injector is not None: secondary_processes = self.__injector.GetSecondaryProcesses() @@ -240,7 +240,7 @@ def secondary_injection_distributions(self, secondary_injection_distributions): def stopping_condition(self): return self.__stopping_condition - @property.setter + @stopping_condition.setter def stopping_condition(self, stopping_condition): if self.__injector is not None: self.__injector.SetStoppingCondition(stopping_condition) @@ -249,16 +249,16 @@ def stopping_condition(self, stopping_condition): @wraps(_Injector.NewRecord) def new_record(self): return self.__injector.NewRecord() - self.new_record.__name__ = "new_record" - self.new_record.__doc__ = _Injector.NewRecord.__doc__.replace("NewRecord", "new_record") + new_record.__name__ = "new_record" + new_record.__doc__ = _Injector.NewRecord.__doc__.replace("NewRecord", "new_record") @wraps(_Injector.GenerateEvent) def generate_event(self): if self.__injector is None: self.__initialize_injector() return self.__injector.GenerateEvent() - self.generate_event.__name__ = "generate_event" - self.generate_event.__doc__ = _Injector.GenerateEvent.__doc__.replace("GenerateEvent", "generate_event") + generate_event.__name__ = "generate_event" + generate_event.__doc__ = _Injector.GenerateEvent.__doc__.replace("GenerateEvent", "generate_event") @property def density_variables(self): @@ -276,14 +276,14 @@ def injected_events(self): def reset_injected_events(self): if self.__injector is not None: self.__injector.ResetInjectedEvents() - self.reset_injected_events.__name__ = "reset_injected_events" - self.reset_injected_events.__doc__ = _Injector.ResetInjectedEvents.__doc__.replace("ResetInjectedEvents", "reset_injected_events") + reset_injected_events.__name__ = "reset_injected_events" + reset_injected_events.__doc__ = _Injector.ResetInjectedEvents.__doc__.replace("ResetInjectedEvents", "reset_injected_events") @wraps(_Injector.SaveInjector) def save(self, filename): self.__injector.SaveInjector(filename) - self.save.__name__ = "save" - self.save.__doc__ = _Injector.SaveInjector.__doc__.replace("SaveInjector", "save") + save.__name__ = "save" + save.__doc__ = _Injector.SaveInjector.__doc__.replace("SaveInjector", "save") @wraps(_Injector.LoadInjector) def load(self, filename): From 9cecedb4382305f7962908b481fa8c6c20c56bca Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 11 Sep 2024 22:43:25 -0600 Subject: [PATCH 45/94] Replace Injector with python wrapper --- python/__init__.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/__init__.py b/python/__init__.py index 411d6aa37..c0a2760b7 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -8,6 +8,7 @@ from . import injection from . import _util +from . import Injector # Intropspect package version import sys @@ -28,6 +29,11 @@ utilities.load_detector = _util.load_detector utilities.load_processes = _util.load_processes +# Override the Injector with the python wrapper +injection._Injector = injection.Injector +injection.Injector = Injector.Injector +del Injector + def darknews_version(): try: import DarkNews From aae1f782ba0d9b5b05bfc845a41ba5cd76252628 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Thu, 12 Sep 2024 12:37:07 -0600 Subject: [PATCH 46/94] Fiducial volume utilities --- python/__init__.py | 1 + python/_util.py | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/python/__init__.py b/python/__init__.py index c0a2760b7..b6b0fb225 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -28,6 +28,7 @@ utilities.load_flux = _util.load_flux utilities.load_detector = _util.load_detector utilities.load_processes = _util.load_processes +utilities.get_fiducial_volume = _util.get_fiducial_volume # Override the Injector with the python wrapper injection._Injector = injection.Injector diff --git a/python/_util.py b/python/_util.py index 7ab1cca90..abbea95ae 100644 --- a/python/_util.py +++ b/python/_util.py @@ -737,3 +737,25 @@ def load_detector(model_name, *args, **kwargs): def load_processes(model_name, *args, **kwargs): return load_resource("processes", model_name, *args, **kwargs) + +def get_fiducial_volume(experiment): + """ + :return: identified fiducial volume for the experiment, None if not found + """ + detector_model_file = get_detector_model_path(experiment) + "/densities.dat" + with open(detector_model_file) as file: + fiducial_line = None + detector_line = None + for line in file: + data = line.split() + if len(data) <= 0: + continue + elif data[0] == "fiducial": + fiducial_line = line + elif data[0] == "detector": + detector_line = line + if fiducial_line is None or detector_line is None: + return None + from . import detector as _detector + return _detector.DetectorModel.ParseFiducialVolume(fiducial_line, detector_line) + return None From d1902ef7e111a91e5e1e55668ea29593625b09d4 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Thu, 12 Sep 2024 12:37:40 -0600 Subject: [PATCH 47/94] Setter for number of events. Fix initialization checks --- python/Injector.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/python/Injector.py b/python/Injector.py index 3a02dcaba..017d7c644 100644 --- a/python/Injector.py +++ b/python/Injector.py @@ -90,18 +90,12 @@ def __initialize_injector(self): if self.__primary_type is None: raise ValueError("primary_type must be provided") - if len(self.__primary_interactions) != 1: - raise ValueError("primary_interactions must have exactly one key") + if len(self.__primary_interactions) == 0: + raise ValueError("primary_interactions must be provided") if len(self.__primary_injection_distributions) == 0: raise ValueError("primary_injection_distributions must be provided") - if len(self.__secondary_interactions) == 0: - raise ValueError("secondary_interactions must be provided") - - if len(self.__secondary_injection_distributions) == 0: - raise ValueError("secondary_injection_distributions must be provided") - if list(sorted(self.__secondary_interactions.keys())) != list(sorted(self.__secondary_injection_distributions.keys())): raise ValueError("secondary_interactions and secondary_injection_distributions must have the same keys") @@ -156,6 +150,12 @@ def number_of_events(self): return self.__injector.EventsToInject() return self.__number_of_events + @number_of_events.setter + def number_of_events(self, number_of_events): + if self.__injector is not None: + raise ValueError("Cannot change the number of events after initialization") + self.__number_of_events = number_of_events + @property def detector_model(self): if self.__injector is not None: From 6fd09b9cfbcd8298d846e09277e9d500f7840dc3 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Thu, 12 Sep 2024 12:51:09 -0600 Subject: [PATCH 48/94] Remove requirement for target_types --- .../primary/vertex/ColumnDepthPositionDistribution.cxx | 8 ++++---- .../primary/vertex/PointSourcePositionDistribution.cxx | 9 ++++----- .../distributions/private/pybindings/distributions.cxx | 4 ++-- .../primary/vertex/ColumnDepthPositionDistribution.h | 7 ++----- .../primary/vertex/PointSourcePositionDistribution.h | 7 ++----- 5 files changed, 14 insertions(+), 21 deletions(-) diff --git a/projects/distributions/private/primary/vertex/ColumnDepthPositionDistribution.cxx b/projects/distributions/private/primary/vertex/ColumnDepthPositionDistribution.cxx index a4eed9b3c..fe901fd85 100644 --- a/projects/distributions/private/primary/vertex/ColumnDepthPositionDistribution.cxx +++ b/projects/distributions/private/primary/vertex/ColumnDepthPositionDistribution.cxx @@ -173,7 +173,7 @@ double ColumnDepthPositionDistribution::GenerationProbability(std::shared_ptr depth_function, std::set target_types) : radius(radius), endcap_length(endcap_length), depth_function(depth_function), target_types(target_types) {} +ColumnDepthPositionDistribution::ColumnDepthPositionDistribution(double radius, double endcap_length, std::shared_ptr depth_function) : radius(radius), endcap_length(endcap_length), depth_function(depth_function) {} std::string ColumnDepthPositionDistribution::Name() const { return "ColumnDepthPositionDistribution"; @@ -215,7 +215,7 @@ bool ColumnDepthPositionDistribution::equal(WeightableDistribution const & other (depth_function and x->depth_function and *depth_function == *x->depth_function) or (!depth_function and !x->depth_function) ) - and target_types == x->target_types); + ); } bool ColumnDepthPositionDistribution::less(WeightableDistribution const & other) const { @@ -226,9 +226,9 @@ bool ColumnDepthPositionDistribution::less(WeightableDistribution const & other) and *depth_function < *x->depth_function); // Less than bool f = false; return - std::tie(radius, endcap_length, f, target_types) + std::tie(radius, endcap_length, f) < - std::tie(radius, x->endcap_length, depth_less, x->target_types); + std::tie(radius, x->endcap_length, depth_less); } } // namespace distributions diff --git a/projects/distributions/private/primary/vertex/PointSourcePositionDistribution.cxx b/projects/distributions/private/primary/vertex/PointSourcePositionDistribution.cxx index 977ae58da..db194e978 100644 --- a/projects/distributions/private/primary/vertex/PointSourcePositionDistribution.cxx +++ b/projects/distributions/private/primary/vertex/PointSourcePositionDistribution.cxx @@ -144,7 +144,7 @@ double PointSourcePositionDistribution::GenerationProbability(std::shared_ptr target_types) : origin(origin), max_distance(max_distance), target_types(target_types) {} +PointSourcePositionDistribution::PointSourcePositionDistribution(siren::math::Vector3D origin, double max_distance) : origin(origin), max_distance(max_distance) {} std::string PointSourcePositionDistribution::Name() const { return "PointSourcePositionDistribution"; @@ -177,16 +177,15 @@ bool PointSourcePositionDistribution::equal(WeightableDistribution const & other return false; else return (origin == x->origin - and max_distance == x->max_distance - and target_types == x->target_types); + and max_distance == x->max_distance); } bool PointSourcePositionDistribution::less(WeightableDistribution const & other) const { const PointSourcePositionDistribution* x = dynamic_cast(&other); return - std::tie(origin, max_distance, target_types) + std::tie(origin, max_distance) < - std::tie(origin, x->max_distance, x->target_types); + std::tie(origin, x->max_distance); } } // namespace distributions diff --git a/projects/distributions/private/pybindings/distributions.cxx b/projects/distributions/private/pybindings/distributions.cxx index e698f5a15..f70348f0f 100644 --- a/projects/distributions/private/pybindings/distributions.cxx +++ b/projects/distributions/private/pybindings/distributions.cxx @@ -187,7 +187,7 @@ PYBIND11_MODULE(distributions,m) { .def("Name",&CylinderVolumePositionDistribution::Name); class_, VertexPositionDistribution>(m, "ColumnDepthPositionDistribution") - .def(init, std::set>()) + .def(init>()) .def("GenerationProbability",&ColumnDepthPositionDistribution::GenerationProbability) .def("InjectionBounds",&ColumnDepthPositionDistribution::InjectionBounds) .def("Name",&ColumnDepthPositionDistribution::Name) @@ -202,7 +202,7 @@ PYBIND11_MODULE(distributions,m) { class_, VertexPositionDistribution>(m, "PointSourcePositionDistribution") .def(init<>()) - .def(init>()) + .def(init()) .def("GenerationProbability",&PointSourcePositionDistribution::GenerationProbability) .def("InjectionBounds",&PointSourcePositionDistribution::InjectionBounds) .def("Name",&PointSourcePositionDistribution::Name); diff --git a/projects/distributions/public/SIREN/distributions/primary/vertex/ColumnDepthPositionDistribution.h b/projects/distributions/public/SIREN/distributions/primary/vertex/ColumnDepthPositionDistribution.h index d0669dafc..ab067713b 100644 --- a/projects/distributions/public/SIREN/distributions/primary/vertex/ColumnDepthPositionDistribution.h +++ b/projects/distributions/public/SIREN/distributions/primary/vertex/ColumnDepthPositionDistribution.h @@ -38,7 +38,6 @@ friend cereal::access; double radius; double endcap_length; std::shared_ptr depth_function; - std::set target_types; siren::math::Vector3D SampleFromDisk(std::shared_ptr rand, siren::math::Vector3D const & dir) const; @@ -46,7 +45,7 @@ friend cereal::access; public: std::tuple GetSamplePosition(std::shared_ptr rand, std::shared_ptr detector_model, std::shared_ptr interactions, siren::dataclasses::PrimaryDistributionRecord & record); virtual double GenerationProbability(std::shared_ptr detector_model, std::shared_ptr interactions, siren::dataclasses::InteractionRecord const & record) const override; - ColumnDepthPositionDistribution(double radius, double endcap_length, std::shared_ptr depth_function, std::set target_types); + ColumnDepthPositionDistribution(double radius, double endcap_length, std::shared_ptr depth_function); std::string Name() const override; virtual std::shared_ptr clone() const override; virtual std::tuple InjectionBounds(std::shared_ptr detector_model, std::shared_ptr interactions, siren::dataclasses::InteractionRecord const & interaction) const override; @@ -56,7 +55,6 @@ friend cereal::access; archive(::cereal::make_nvp("Radius", radius)); archive(::cereal::make_nvp("EndcapLength", endcap_length)); archive(::cereal::make_nvp("DepthFunction", depth_function)); - archive(::cereal::make_nvp("TargetTypes", target_types)); archive(cereal::virtual_base_class(this)); } else { throw std::runtime_error("ColumnDepthPositionDistribution only supports version <= 0!"); @@ -72,8 +70,7 @@ friend cereal::access; archive(::cereal::make_nvp("Radius", r)); archive(::cereal::make_nvp("EndcapLength", l)); archive(::cereal::make_nvp("DepthFunction", f)); - archive(::cereal::make_nvp("TargetTypes", t)); - construct(r, l, f, t); + construct(r, l, f); archive(cereal::virtual_base_class(construct.ptr())); } else { throw std::runtime_error("ColumnDepthPositionDistribution only supports version <= 0!"); diff --git a/projects/distributions/public/SIREN/distributions/primary/vertex/PointSourcePositionDistribution.h b/projects/distributions/public/SIREN/distributions/primary/vertex/PointSourcePositionDistribution.h index d14279ac3..dd05add34 100644 --- a/projects/distributions/public/SIREN/distributions/primary/vertex/PointSourcePositionDistribution.h +++ b/projects/distributions/public/SIREN/distributions/primary/vertex/PointSourcePositionDistribution.h @@ -34,7 +34,6 @@ friend cereal::access; private: siren::math::Vector3D origin; double max_distance; - std::set target_types; siren::math::Vector3D SampleFromDisk(std::shared_ptr rand, siren::math::Vector3D const & dir) const; @@ -43,7 +42,7 @@ friend cereal::access; virtual double GenerationProbability(std::shared_ptr detector_model, std::shared_ptr interactions, siren::dataclasses::InteractionRecord const & record) const override; PointSourcePositionDistribution(); PointSourcePositionDistribution(const PointSourcePositionDistribution &) = default; - PointSourcePositionDistribution(siren::math::Vector3D origin, double max_distance, std::set target_types); + PointSourcePositionDistribution(siren::math::Vector3D origin, double max_distance); std::string Name() const override; virtual std::tuple InjectionBounds(std::shared_ptr detector_model, std::shared_ptr interactions, siren::dataclasses::InteractionRecord const & interaction) const override; virtual std::shared_ptr clone() const override; @@ -52,7 +51,6 @@ friend cereal::access; if(version == 0) { archive(::cereal::make_nvp("Origin", origin)); archive(::cereal::make_nvp("MaxDistance", max_distance)); - archive(::cereal::make_nvp("TargetTypes", target_types)); archive(cereal::virtual_base_class(this)); } else { throw std::runtime_error("PointSourcePositionDistribution only supports version <= 0!"); @@ -66,8 +64,7 @@ friend cereal::access; std::set t; archive(::cereal::make_nvp("Origin", r)); archive(::cereal::make_nvp("MaxDistance", l)); - archive(::cereal::make_nvp("TargetTypes", t)); - construct(r, l, t); + construct(r, l); archive(cereal::virtual_base_class(construct.ptr())); } else { throw std::runtime_error("PointSourcePositionDistribution only supports version <= 0!"); From bf999b822d6f23c6d558a44df8b558435c8a6ad7 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Thu, 12 Sep 2024 12:51:41 -0600 Subject: [PATCH 49/94] Add constructor with contents to pybindings --- projects/injection/private/pybindings/injection.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/projects/injection/private/pybindings/injection.cxx b/projects/injection/private/pybindings/injection.cxx index 97c3bc1c8..74a2ce20b 100644 --- a/projects/injection/private/pybindings/injection.cxx +++ b/projects/injection/private/pybindings/injection.cxx @@ -43,6 +43,7 @@ PYBIND11_MODULE(injection,m) { class_, Process>(m, "PhysicalProcess") .def(init<>()) + .def(init>()) .def_property("primary_type", &Process::GetPrimaryType, &Process::SetPrimaryType) .def_property("interactions", &Process::GetInteractions, &Process::SetInteractions) .def_property("distributions", &PhysicalProcess::GetPhysicalDistributions, &PhysicalProcess::SetPhysicalDistributions) @@ -50,6 +51,7 @@ PYBIND11_MODULE(injection,m) { class_, Process>(m, "PrimaryInjectionProcess") .def(init<>()) + .def(init>()) .def_property("primary_type", &Process::GetPrimaryType, &Process::SetPrimaryType) .def_property("interactions", &Process::GetInteractions, &Process::SetInteractions) .def_property("distributions", &PrimaryInjectionProcess::GetPrimaryInjectionDistributions, &PrimaryInjectionProcess::SetPrimaryInjectionDistributions) @@ -57,6 +59,7 @@ PYBIND11_MODULE(injection,m) { class_, Process>(m, "SecondaryInjectionProcess") .def(init<>()) + .def(init>()) .def_property("secondary_type", &SecondaryInjectionProcess::GetSecondaryType, &SecondaryInjectionProcess::SetSecondaryType) .def_property("interactions", &Process::GetInteractions, &Process::SetInteractions) .def_property("distributions", &SecondaryInjectionProcess::GetSecondaryInjectionDistributions, &SecondaryInjectionProcess::SetSecondaryInjectionDistributions) From 990e474036e623f4471d13627332fd4007cf8413 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Fri, 13 Sep 2024 18:13:03 -0600 Subject: [PATCH 50/94] Move examples --- .../ND280UPGRD-v1.dat => ND280UPGRD/densities_ND280UPGRD-v1.dat} | 0 .../ND280UPGRD-v1.dat => ND280UPGRD/materials_ND280UPGRD-v1.dat} | 0 resources/examples/{Example1 => example1}/DIS_ATLAS.py | 0 resources/examples/{Example1 => example1}/DIS_DUNE.py | 0 resources/examples/{Example1 => example1}/DIS_IceCube.py | 0 resources/examples/{Example1 => example1}/PaperPlots.ipynb | 0 resources/examples/{Example2 => example2}/DipolePortal_CCM.py | 0 resources/examples/{Example2 => example2}/DipolePortal_MINERvA.py | 0 .../examples/{Example2 => example2}/DipolePortal_MiniBooNE.py | 0 .../examples/{Example2 => example2}/DipolePortal_ND280UPGRD.py | 0 resources/examples/{Example2 => example2}/PaperPlots.ipynb | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename resources/Detectors/{densities/ND280UPGRD/ND280UPGRD-v1.dat => ND280UPGRD/densities_ND280UPGRD-v1.dat} (100%) rename resources/Detectors/{materials/ND280UPGRD/ND280UPGRD-v1.dat => ND280UPGRD/materials_ND280UPGRD-v1.dat} (100%) rename resources/examples/{Example1 => example1}/DIS_ATLAS.py (100%) rename resources/examples/{Example1 => example1}/DIS_DUNE.py (100%) rename resources/examples/{Example1 => example1}/DIS_IceCube.py (100%) rename resources/examples/{Example1 => example1}/PaperPlots.ipynb (100%) rename resources/examples/{Example2 => example2}/DipolePortal_CCM.py (100%) rename resources/examples/{Example2 => example2}/DipolePortal_MINERvA.py (100%) rename resources/examples/{Example2 => example2}/DipolePortal_MiniBooNE.py (100%) rename resources/examples/{Example2 => example2}/DipolePortal_ND280UPGRD.py (100%) rename resources/examples/{Example2 => example2}/PaperPlots.ipynb (100%) diff --git a/resources/Detectors/densities/ND280UPGRD/ND280UPGRD-v1.dat b/resources/Detectors/ND280UPGRD/densities_ND280UPGRD-v1.dat similarity index 100% rename from resources/Detectors/densities/ND280UPGRD/ND280UPGRD-v1.dat rename to resources/Detectors/ND280UPGRD/densities_ND280UPGRD-v1.dat diff --git a/resources/Detectors/materials/ND280UPGRD/ND280UPGRD-v1.dat b/resources/Detectors/ND280UPGRD/materials_ND280UPGRD-v1.dat similarity index 100% rename from resources/Detectors/materials/ND280UPGRD/ND280UPGRD-v1.dat rename to resources/Detectors/ND280UPGRD/materials_ND280UPGRD-v1.dat diff --git a/resources/examples/Example1/DIS_ATLAS.py b/resources/examples/example1/DIS_ATLAS.py similarity index 100% rename from resources/examples/Example1/DIS_ATLAS.py rename to resources/examples/example1/DIS_ATLAS.py diff --git a/resources/examples/Example1/DIS_DUNE.py b/resources/examples/example1/DIS_DUNE.py similarity index 100% rename from resources/examples/Example1/DIS_DUNE.py rename to resources/examples/example1/DIS_DUNE.py diff --git a/resources/examples/Example1/DIS_IceCube.py b/resources/examples/example1/DIS_IceCube.py similarity index 100% rename from resources/examples/Example1/DIS_IceCube.py rename to resources/examples/example1/DIS_IceCube.py diff --git a/resources/examples/Example1/PaperPlots.ipynb b/resources/examples/example1/PaperPlots.ipynb similarity index 100% rename from resources/examples/Example1/PaperPlots.ipynb rename to resources/examples/example1/PaperPlots.ipynb diff --git a/resources/examples/Example2/DipolePortal_CCM.py b/resources/examples/example2/DipolePortal_CCM.py similarity index 100% rename from resources/examples/Example2/DipolePortal_CCM.py rename to resources/examples/example2/DipolePortal_CCM.py diff --git a/resources/examples/Example2/DipolePortal_MINERvA.py b/resources/examples/example2/DipolePortal_MINERvA.py similarity index 100% rename from resources/examples/Example2/DipolePortal_MINERvA.py rename to resources/examples/example2/DipolePortal_MINERvA.py diff --git a/resources/examples/Example2/DipolePortal_MiniBooNE.py b/resources/examples/example2/DipolePortal_MiniBooNE.py similarity index 100% rename from resources/examples/Example2/DipolePortal_MiniBooNE.py rename to resources/examples/example2/DipolePortal_MiniBooNE.py diff --git a/resources/examples/Example2/DipolePortal_ND280UPGRD.py b/resources/examples/example2/DipolePortal_ND280UPGRD.py similarity index 100% rename from resources/examples/Example2/DipolePortal_ND280UPGRD.py rename to resources/examples/example2/DipolePortal_ND280UPGRD.py diff --git a/resources/examples/Example2/PaperPlots.ipynb b/resources/examples/example2/PaperPlots.ipynb similarity index 100% rename from resources/examples/Example2/PaperPlots.ipynb rename to resources/examples/example2/PaperPlots.ipynb From 1b347514319b976bce7a0af0dc7f3e65b404613d Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Fri, 13 Sep 2024 19:31:03 -0600 Subject: [PATCH 51/94] Utilities for string manipulation (mainly inserting tabs) --- projects/utilities/CMakeLists.txt | 1 + .../utilities/private/StringManipulation.cxx | 41 +++++++++++++++++++ .../SIREN/utilities/StringManipulation.h | 17 ++++++++ 3 files changed, 59 insertions(+) create mode 100644 projects/utilities/private/StringManipulation.cxx create mode 100644 projects/utilities/public/SIREN/utilities/StringManipulation.h diff --git a/projects/utilities/CMakeLists.txt b/projects/utilities/CMakeLists.txt index f0dec7b97..5ad24dfaa 100644 --- a/projects/utilities/CMakeLists.txt +++ b/projects/utilities/CMakeLists.txt @@ -3,6 +3,7 @@ LIST (APPEND utilities_SOURCES ${PROJECT_SOURCE_DIR}/projects/utilities/private/Interpolator.cxx ${PROJECT_SOURCE_DIR}/projects/utilities/private/Random.cxx + ${PROJECT_SOURCE_DIR}/projects/utilities/private/StringManipulation.cxx ) add_library(SIREN_utilities OBJECT ${utilities_SOURCES}) set_property(TARGET SIREN_utilities PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/projects/utilities/private/StringManipulation.cxx b/projects/utilities/private/StringManipulation.cxx new file mode 100644 index 000000000..96f009f65 --- /dev/null +++ b/projects/utilities/private/StringManipulation.cxx @@ -0,0 +1,41 @@ +#include +#include +#include + +#include "SIREN/utilities/StringManipulation.h" + +namespace siren { +namespace utilities { + +std::string add_prefix(std::string const & input, std::string const & prefix) { + std::istringstream iss(input); + std::vector lines; + std::string line; + ssize_t last_non_empty_line = -1; + size_t line_number = 0; + + // Read each line and track the last non-empty line + while (std::getline(iss, line)) { + lines.push_back(line); + if (!line.empty()) { + last_non_empty_line = line_number; + } + line_number++; + } + + std::ostringstream oss; + + // Add prefix to each line up to the last non-empty line + if (last_non_empty_line >= 0) { + for (size_t i = 0; i <= static_cast(last_non_empty_line); ++i) { + oss << prefix << lines[i] << '\n'; + } + // Ensure the string ends with an empty newline + oss << '\n'; + } + + return oss.str(); +} + +} // namespace utilities +} // namespace siren diff --git a/projects/utilities/public/SIREN/utilities/StringManipulation.h b/projects/utilities/public/SIREN/utilities/StringManipulation.h new file mode 100644 index 000000000..ef3d90a76 --- /dev/null +++ b/projects/utilities/public/SIREN/utilities/StringManipulation.h @@ -0,0 +1,17 @@ +#pragma once +#ifndef SIREN_StringMapulation_H +#define SIREN_StringMapulation_H + +#include + +namespace siren { +namespace utilities { + +constexpr char const * tab = " "; + +std::string add_prefix(std::string const & input, std::string const & prefix); + +} // namespace utilities +} // namespace siren + +#endif // SIREN_StringMapulation_H From bb2776d3619a6ff7eb0d77f34db715df8a9ba3db Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Fri, 13 Sep 2024 19:33:29 -0600 Subject: [PATCH 52/94] A few pythonic changes to dataclasses pybindings. Moving ParticleType into dataclasses. Clean up InteractionSignature __str__ and __repr__ --- .../private/InteractionSignature.cxx | 41 +++++++++++++----- .../private/pybindings/dataclasses.cxx | 42 +++++++------------ .../SIREN/dataclasses/InteractionSignature.h | 9 ++-- python/Injector.py | 8 ++-- python/__init__.py | 2 + 5 files changed, 58 insertions(+), 44 deletions(-) diff --git a/projects/dataclasses/private/InteractionSignature.cxx b/projects/dataclasses/private/InteractionSignature.cxx index 1cf3a381b..b0b54ebc0 100644 --- a/projects/dataclasses/private/InteractionSignature.cxx +++ b/projects/dataclasses/private/InteractionSignature.cxx @@ -1,4 +1,5 @@ #include "SIREN/dataclasses/InteractionSignature.h" +#include "SIREN/utilities/StringManipulation.h" #include // for tie, operator<, operator==, tuple #include // for operator<<, char_traits, basic_ostream, endl, ost... @@ -23,20 +24,38 @@ bool InteractionSignature::operator<(InteractionSignature const & other) const { } // namespace dataclasses } // namespace siren -std::ostream& operator<<(std::ostream& os, siren::dataclasses::InteractionSignature const& signature) { - std::stringstream ss; - ss << "InteractionSignature (" << &signature << ") "; - os << ss.str() << '\n'; - +std::ostream& operator<<(std::ostream& os, siren::dataclasses::InteractionSignature const & signature) { + os << to_repr(signature); + return os; +} - os << "PrimaryType: " << signature.primary_type << "\n"; - os << "TargetType: " << signature.target_type << "\n"; - os << "SecondaryTypes:"; +std::string to_str(siren::dataclasses::InteractionSignature const & signature) { + using siren::utilities::tab; + std::stringstream ss; + ss << "[ InteractionSignature (" << &signature << ") \n"; + ss << tab << "PrimaryType: " << signature.primary_type << '\n'; + ss << tab << "TargetType: " << signature.target_type << '\n'; + ss << tab << "SecondaryTypes:"; for(auto secondary: signature.secondary_types) { - os << " " << secondary; + ss << ' ' << secondary; } - os << std::endl; + ss << "\n]"; - return os; + return ss.str(); } +std::string to_repr(siren::dataclasses::InteractionSignature const & signature) { + using siren::dataclasses::ParticleType; + std::stringstream ss; + ss << "InteractionSignature( "; + ss << signature.primary_type << " "; + if(signature.primary_type == ParticleType::unknown or signature.target_type != ParticleType::unknown) { + ss << signature.target_type << " "; + } + ss << "-> "; + for(auto const & secondary : signature.secondary_types) { + ss << secondary << " "; + } + ss << ")"; + return ss.str(); +} diff --git a/projects/dataclasses/private/pybindings/dataclasses.cxx b/projects/dataclasses/private/pybindings/dataclasses.cxx index e328b280f..3a049edf6 100644 --- a/projects/dataclasses/private/pybindings/dataclasses.cxx +++ b/projects/dataclasses/private/pybindings/dataclasses.cxx @@ -31,9 +31,9 @@ PYBIND11_MODULE(dataclasses,m) { .def_readwrite("position",&Particle::position) .def_readwrite("length",&Particle::length) .def_readwrite("helicity",&Particle::helicity) - .def("GenerateID",&Particle::GenerateID); + .def("generate_id",&Particle::GenerateID); - enum_(particle, "ParticleType", arithmetic()) + enum_(m, "ParticleType", arithmetic()) #define X(a, b) .value( #a , ParticleType:: a ) #include "../../public/SIREN/dataclasses/ParticleTypes.def" #undef X @@ -41,21 +41,8 @@ PYBIND11_MODULE(dataclasses,m) { class_>(m, "InteractionSignature") .def(init<>()) - .def("__str__", [](InteractionSignature const & p) { std::stringstream ss; ss << p; return ss.str(); }) - .def("__repr__", [](InteractionSignature const & s) { - std::stringstream ss; - ss << "InteractionSignature( "; - ss << s.primary_type << " "; - if(s.primary_type == ParticleType::unknown or s.target_type != ParticleType::unknown) { - ss << s.target_type << " "; - } - ss << "-> "; - for(auto const & secondary : s.secondary_types) { - ss << secondary << " "; - } - ss << ")"; - return ss.str(); - }) + .def("__str__", [](InteractionSignature const & s) { return to_str(s); }) + .def("__repr__", [](InteractionSignature const & s) { return to_repr(s); }) .def_readwrite("primary_type",&InteractionSignature::primary_type) .def_readwrite("target_type",&InteractionSignature::target_type) .def_readwrite("secondary_types",&InteractionSignature::secondary_types); @@ -66,8 +53,8 @@ PYBIND11_MODULE(dataclasses,m) { [](siren::dataclasses::PrimaryDistributionRecord const & pdr) {siren::dataclasses::ParticleID id = pdr.id; return id;}) .def_property_readonly("type", [](siren::dataclasses::PrimaryDistributionRecord const & pdr) {siren::dataclasses::ParticleType pt = pdr.type; return pt;}) - .def("GetParticle", &PrimaryDistributionRecord::GetParticle) - .def("SetParticle", &PrimaryDistributionRecord::SetParticle) + //.def("GetParticle", &PrimaryDistributionRecord::GetParticle) + //.def("SetParticle", &PrimaryDistributionRecord::SetParticle) .def_property("mass", ((double const & (PrimaryDistributionRecord::*)())(&PrimaryDistributionRecord::GetMass)), &PrimaryDistributionRecord::SetMass) .def_property("energy", ((double const & (PrimaryDistributionRecord::*)())(&PrimaryDistributionRecord::GetEnergy)), &PrimaryDistributionRecord::SetEnergy) .def_property("kinetic_energy", ((double const & (PrimaryDistributionRecord::*)())(&PrimaryDistributionRecord::GetKineticEnergy)), &PrimaryDistributionRecord::SetKineticEnergy) @@ -78,7 +65,7 @@ PYBIND11_MODULE(dataclasses,m) { .def_property("initial_position", ((std::array const & (PrimaryDistributionRecord::*)())(&PrimaryDistributionRecord::GetInitialPosition)), &PrimaryDistributionRecord::SetInitialPosition) .def_property("interaction_vertex", ((std::array const & (PrimaryDistributionRecord::*)())(&PrimaryDistributionRecord::GetInteractionVertex)), &PrimaryDistributionRecord::SetInteractionVertex) .def_property("helicity", ((double const & (PrimaryDistributionRecord::*)())(&PrimaryDistributionRecord::GetHelicity)), &PrimaryDistributionRecord::SetHelicity) - .def("Finalize", &PrimaryDistributionRecord::Finalize); + .def("finalize", &PrimaryDistributionRecord::Finalize); class_>(m, "SecondaryParticleRecord") .def(init()) @@ -88,8 +75,8 @@ PYBIND11_MODULE(dataclasses,m) { [](siren::dataclasses::SecondaryParticleRecord const & spr) {siren::dataclasses::ParticleType pt = spr.type; return pt;}) .def_property_readonly("initial_position", [](siren::dataclasses::SecondaryParticleRecord const & spr) {std::array ip = spr.initial_position; return ip;}) - .def("GetParticle", &SecondaryParticleRecord::GetParticle) - .def("SetParticle", &SecondaryParticleRecord::SetParticle) + //.def("GetParticle", &SecondaryParticleRecord::GetParticle) + //.def("SetParticle", &SecondaryParticleRecord::SetParticle) .def_property("mass", ((double const & (SecondaryParticleRecord::*)())(&SecondaryParticleRecord::GetMass)), &SecondaryParticleRecord::SetMass) .def_property("energy", ((double const & (SecondaryParticleRecord::*)())(&SecondaryParticleRecord::GetEnergy)), &SecondaryParticleRecord::SetEnergy) .def_property("kinetic_energy", ((double const & (SecondaryParticleRecord::*)())(&SecondaryParticleRecord::GetKineticEnergy)), &SecondaryParticleRecord::SetKineticEnergy) @@ -97,7 +84,7 @@ PYBIND11_MODULE(dataclasses,m) { .def_property("three_momentum", ((std::array const & (SecondaryParticleRecord::*)())(&SecondaryParticleRecord::GetThreeMomentum)), &SecondaryParticleRecord::SetThreeMomentum) .def_property("four_momentum", ((std::array (SecondaryParticleRecord::*)())(&SecondaryParticleRecord::GetFourMomentum)), &SecondaryParticleRecord::SetFourMomentum) .def_property("helicity", ((double const & (SecondaryParticleRecord::*)())(&SecondaryParticleRecord::GetHelicity)), &SecondaryParticleRecord::SetHelicity) - .def("Finalize", &SecondaryParticleRecord::Finalize); + .def("finalize", &SecondaryParticleRecord::Finalize); class_>(m, "CrossSectionDistributionRecord") .def(init()) @@ -126,13 +113,16 @@ PYBIND11_MODULE(dataclasses,m) { .def_property("target_mass", ((double const & (siren::dataclasses::CrossSectionDistributionRecord::*)() const)(&siren::dataclasses::CrossSectionDistributionRecord::GetTargetMass)), &siren::dataclasses::CrossSectionDistributionRecord::SetTargetMass) .def_property("target_helicity", ((double const & (siren::dataclasses::CrossSectionDistributionRecord::*)() const)(&siren::dataclasses::CrossSectionDistributionRecord::GetTargetHelicity)), &siren::dataclasses::CrossSectionDistributionRecord::SetTargetHelicity) .def_property("interaction_parameters", ((std::map const & (siren::dataclasses::CrossSectionDistributionRecord::*)())(&siren::dataclasses::CrossSectionDistributionRecord::GetInteractionParameters)), &siren::dataclasses::CrossSectionDistributionRecord::SetInteractionParameters) - .def("GetSecondaryParticleRecord", + .def_property_readonly("secondary_particle_records", + [](siren::dataclasses::CrossSectionDistributionRecord & cdr) -> std::vector & {return cdr.GetSecondaryParticleRecords();}, + return_value_policy::reference_internal) + .def("get_econdary_particle_record", [](siren::dataclasses::CrossSectionDistributionRecord & cdr, size_t i) -> siren::dataclasses::SecondaryParticleRecord & {return cdr.GetSecondaryParticleRecord(i);}, return_value_policy::reference_internal) - .def("GetSecondaryParticleRecords", + .def("get_econdary_particle_records", [](siren::dataclasses::CrossSectionDistributionRecord & cdr) -> std::vector & {return cdr.GetSecondaryParticleRecords();}, return_value_policy::reference_internal) - .def("Finalize", &CrossSectionDistributionRecord::Finalize); + .def("finalize", &CrossSectionDistributionRecord::Finalize); class_>(m, "InteractionRecord") diff --git a/projects/dataclasses/public/SIREN/dataclasses/InteractionSignature.h b/projects/dataclasses/public/SIREN/dataclasses/InteractionSignature.h index f3325d5b6..52f66b0f1 100644 --- a/projects/dataclasses/public/SIREN/dataclasses/InteractionSignature.h +++ b/projects/dataclasses/public/SIREN/dataclasses/InteractionSignature.h @@ -4,16 +4,18 @@ #include // for ostream #include // for vector +#include // for string #include // for uint32_t #include // for runtime_error #include // for make_nvp, CEREAL_CL... #include "SIREN/dataclasses/Particle.h" // for Particle - // namespace siren { namespace dataclasses { struct InteractionSignature; } } -std::ostream& operator<<(std::ostream& os, siren::dataclasses::InteractionSignature const& signature); +std::ostream& operator<<(std::ostream& os, siren::dataclasses::InteractionSignature const & signature); +std::string to_str(siren::dataclasses::InteractionSignature const & signature); +std::string to_repr(siren::dataclasses::InteractionSignature const & signature); namespace siren { namespace dataclasses { @@ -25,7 +27,8 @@ struct InteractionSignature { bool operator==(InteractionSignature const & other) const; bool operator<(InteractionSignature const & other) const; - friend std::ostream& ::operator<<(std::ostream& os, InteractionSignature const& signature); + friend std::string (::to_str)(siren::dataclasses::InteractionSignature const & signature); + friend std::string (::to_repr)(siren::dataclasses::InteractionSignature const & signature); template void serialize(Archive & archive, std::uint32_t const version) { if(version == 0) { diff --git a/python/Injector.py b/python/Injector.py index 017d7c644..8ca27cbff 100644 --- a/python/Injector.py +++ b/python/Injector.py @@ -18,7 +18,7 @@ _Injector = _injection.Injector -ParticleType = _dataclasses.Particle.ParticleType +ParticleType = _dataclasses.ParticleType CrossSection = _interactions.CrossSection Decay = _interactions.Decay DetectorModel = _detector.DetectorModel @@ -34,10 +34,10 @@ def __init__( number_of_events: Optional[int] = None, detector_model: Optional[_detector.DetectorModel] = None, seed: Optional[int] = None, - primary_interactions: Dict[_dataclasses.Particle.ParticleType, List[Union[_interactions.CrossSection, _interactions.Decay]]] = None, + primary_interactions: Dict[_dataclasses.ParticleType, List[Union[_interactions.CrossSection, _interactions.Decay]]] = None, primary_injection_distributions: List[_distributions.PrimaryInjectionDistribution] = None, - secondary_interactions: Optional[Dict[_dataclasses.Particle.ParticleType, List[Union[_interactions.CrossSection, _interactions.Decay]]]] = None, - secondary_injection_distributions: Optional[Dict[_dataclasses.Particle.ParticleType, List[_distributions.SecondaryInjectionDistribution]]] = None, + secondary_interactions: Optional[Dict[_dataclasses.ParticleType, List[Union[_interactions.CrossSection, _interactions.Decay]]]] = None, + secondary_injection_distributions: Optional[Dict[_dataclasses.ParticleType, List[_distributions.SecondaryInjectionDistribution]]] = None, stopping_condition: Optional[Callable[[_dataclasses.InteractionTreeDatum, int], bool]] = None, ): self.__seed = None diff --git a/python/__init__.py b/python/__init__.py index b6b0fb225..587cce09a 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -35,6 +35,8 @@ injection.Injector = Injector.Injector del Injector +dataclasses.Particle.ParticleType = dataclasses.ParticleType + def darknews_version(): try: import DarkNews From d02b3b73404fae5f81c4a8dd9d467bb04d03c6cf Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Fri, 13 Sep 2024 20:47:16 -0600 Subject: [PATCH 53/94] Add bindings for ParticleID --- .../private/pybindings/dataclasses.cxx | 159 +++++++++++------- 1 file changed, 97 insertions(+), 62 deletions(-) diff --git a/projects/dataclasses/private/pybindings/dataclasses.cxx b/projects/dataclasses/private/pybindings/dataclasses.cxx index 3a049edf6..f2f1166b0 100644 --- a/projects/dataclasses/private/pybindings/dataclasses.cxx +++ b/projects/dataclasses/private/pybindings/dataclasses.cxx @@ -10,45 +10,80 @@ #include "../../public/SIREN/dataclasses/InteractionTree.h" #include +#include #include -using namespace pybind11; -PYBIND11_MODULE(dataclasses,m) { - using namespace siren::dataclasses; - - class_> particle(m, "Particle"); - - particle.def(init<>()) - .def(init()) - .def(init, std::array, double, double>()) - .def(init, std::array, double, double>()) - .def("__str__", [](Particle const & p) { std::stringstream ss; ss << p; return ss.str(); }) - .def_readwrite("id",&Particle::id) - .def_readwrite("type",&Particle::type) - .def_readwrite("mass",&Particle::mass) - .def_readwrite("momentum",&Particle::momentum) - .def_readwrite("position",&Particle::position) - .def_readwrite("length",&Particle::length) - .def_readwrite("helicity",&Particle::helicity) - .def("generate_id",&Particle::GenerateID); - - enum_(m, "ParticleType", arithmetic()) +PYBIND11_MODULE(dataclasses, m) { + namespace py = pybind11; + using namespace siren::dataclasses; + + // Create a Python class binding for siren::dataclasses::ParticleID + py::class_ particle_id(m, "ParticleID"); + + particle_id + .def(py::init<>()) + .def(py::init(), py::arg("major"), py::arg("minor")) + .def(py::init(), py::arg("other")) + .def(py::init(), py::arg("other")) + .def_static("generate_id", &siren::dataclasses::ParticleID::GenerateID) + .def("is_set", &siren::dataclasses::ParticleID::IsSet) + //.def_property("major_id", &siren::dataclasses::ParticleID::GetMajorID, &siren::dataclasses::ParticleID::SetMajorID) + // Getters for major and minor IDs + .def_property_readonly("major_id", &siren::dataclasses::ParticleID::GetMajorID) + .def_property_readonly("minor_id", &siren::dataclasses::ParticleID::GetMinorID) + // Method to set the ID + .def("set", &siren::dataclasses::ParticleID::SetID, py::arg("major"), py::arg("minor")) + // Overload the bool operator + .def("__bool__", &siren::dataclasses::ParticleID::operator bool) + // Comparison operators + .def(py::self == py::self) + .def(py::self != py::self) + .def(py::self < py::self) + // String representation + .def("__repr__", + [](const siren::dataclasses::ParticleID &id) { + std::ostringstream oss; + oss << id; + return oss.str(); + } + ) + // Optional: Serialize method if needed in Python + // .def("serialize", &siren::dataclasses::ParticleID::serialize) + ; + + py::class_> particle(m, "Particle"); + + particle.def(py::init<>()) + .def(py::init()) + .def(py::init, std::array, double, double>()) + .def(py::init, std::array, double, double>()) + .def("__str__", [](Particle const & p) { std::stringstream ss; ss << p; return ss.str(); }) + .def_readwrite("id",&Particle::id) + .def_readwrite("type",&Particle::type) + .def_readwrite("mass",&Particle::mass) + .def_readwrite("momentum",&Particle::momentum) + .def_readwrite("position",&Particle::position) + .def_readwrite("length",&Particle::length) + .def_readwrite("helicity",&Particle::helicity) + .def("generate_id",&Particle::GenerateID); + + py::enum_(m, "ParticleType", py::arithmetic()) #define X(a, b) .value( #a , ParticleType:: a ) #include "../../public/SIREN/dataclasses/ParticleTypes.def" #undef X .export_values(); - class_>(m, "InteractionSignature") - .def(init<>()) + py::class_>(m, "InteractionSignature") + .def(py::init<>()) .def("__str__", [](InteractionSignature const & s) { return to_str(s); }) .def("__repr__", [](InteractionSignature const & s) { return to_repr(s); }) .def_readwrite("primary_type",&InteractionSignature::primary_type) .def_readwrite("target_type",&InteractionSignature::target_type) .def_readwrite("secondary_types",&InteractionSignature::secondary_types); - class_>(m, "PrimaryDistributionRecord") - .def(init()) + py::class_>(m, "PrimaryDistributionRecord") + .def(py::init()) .def_property_readonly("id", [](siren::dataclasses::PrimaryDistributionRecord const & pdr) {siren::dataclasses::ParticleID id = pdr.id; return id;}) .def_property_readonly("type", @@ -67,8 +102,8 @@ PYBIND11_MODULE(dataclasses,m) { .def_property("helicity", ((double const & (PrimaryDistributionRecord::*)())(&PrimaryDistributionRecord::GetHelicity)), &PrimaryDistributionRecord::SetHelicity) .def("finalize", &PrimaryDistributionRecord::Finalize); - class_>(m, "SecondaryParticleRecord") - .def(init()) + py::class_>(m, "SecondaryParticleRecord") + .def(py::init()) .def_property_readonly("id", [](siren::dataclasses::SecondaryParticleRecord const & spr) {siren::dataclasses::ParticleID id = spr.id; return id;}) .def_property_readonly("type", @@ -86,8 +121,8 @@ PYBIND11_MODULE(dataclasses,m) { .def_property("helicity", ((double const & (SecondaryParticleRecord::*)())(&SecondaryParticleRecord::GetHelicity)), &SecondaryParticleRecord::SetHelicity) .def("finalize", &SecondaryParticleRecord::Finalize); - class_>(m, "CrossSectionDistributionRecord") - .def(init()) + py::class_>(m, "CrossSectionDistributionRecord") + .def(py::init()) .def_property_readonly("record", [](siren::dataclasses::CrossSectionDistributionRecord const & cdr) {siren::dataclasses::InteractionRecord ir = cdr.record; return ir;}) .def_property_readonly("signature", @@ -115,45 +150,45 @@ PYBIND11_MODULE(dataclasses,m) { .def_property("interaction_parameters", ((std::map const & (siren::dataclasses::CrossSectionDistributionRecord::*)())(&siren::dataclasses::CrossSectionDistributionRecord::GetInteractionParameters)), &siren::dataclasses::CrossSectionDistributionRecord::SetInteractionParameters) .def_property_readonly("secondary_particle_records", [](siren::dataclasses::CrossSectionDistributionRecord & cdr) -> std::vector & {return cdr.GetSecondaryParticleRecords();}, - return_value_policy::reference_internal) + py::return_value_policy::reference_internal) .def("get_econdary_particle_record", [](siren::dataclasses::CrossSectionDistributionRecord & cdr, size_t i) -> siren::dataclasses::SecondaryParticleRecord & {return cdr.GetSecondaryParticleRecord(i);}, - return_value_policy::reference_internal) + py::return_value_policy::reference_internal) .def("get_econdary_particle_records", [](siren::dataclasses::CrossSectionDistributionRecord & cdr) -> std::vector & {return cdr.GetSecondaryParticleRecords();}, - return_value_policy::reference_internal) + py::return_value_policy::reference_internal) .def("finalize", &CrossSectionDistributionRecord::Finalize); - class_>(m, "InteractionRecord") - .def(init<>()) - .def("__str__", [](InteractionRecord const & r) { std::stringstream ss; ss << r; return ss.str(); }) - .def_readwrite("signature",&InteractionRecord::signature) - .def_readwrite("primary_mass",&InteractionRecord::primary_mass) - .def_readwrite("primary_momentum",&InteractionRecord::primary_momentum) - .def_readwrite("primary_helicity",&InteractionRecord::primary_helicity) - .def_readwrite("target_mass",&InteractionRecord::target_mass) - .def_readwrite("target_helicity",&InteractionRecord::target_helicity) - .def_readwrite("interaction_vertex",&InteractionRecord::interaction_vertex) - .def_readwrite("secondary_masses",&InteractionRecord::secondary_masses) - .def_readwrite("secondary_momenta",&InteractionRecord::secondary_momenta) - .def_readwrite("secondary_helicities",&InteractionRecord::secondary_helicities) - .def_readwrite("interaction_parameters",&InteractionRecord::interaction_parameters); - - class_>(m, "InteractionTreeDatum") - .def(init()) - .def_readwrite("record",&InteractionTreeDatum::record) - .def_readwrite("parent",&InteractionTreeDatum::parent) - .def_readwrite("daughters",&InteractionTreeDatum::daughters) - .def("depth",&InteractionTreeDatum::depth); - - class_>(m, "InteractionTree") - .def(init<>()) - .def_readwrite("tree",&InteractionTree::tree) - .def("add_entry",static_cast (InteractionTree::*)(InteractionTreeDatum&,std::shared_ptr)>(&InteractionTree::add_entry)) - .def("add_entry",static_cast (InteractionTree::*)(InteractionRecord&,std::shared_ptr)>(&InteractionTree::add_entry)); - - m.def("SaveInteractionTrees",&SaveInteractionTrees); - m.def("LoadInteractionTrees",&LoadInteractionTrees,pybind11::return_value_policy::reference); + py::class_>(m, "InteractionRecord") + .def(py::init<>()) + .def("__str__", [](InteractionRecord const & r) { std::stringstream ss; ss << r; return ss.str(); }) + .def_readwrite("signature",&InteractionRecord::signature) + .def_readwrite("primary_mass",&InteractionRecord::primary_mass) + .def_readwrite("primary_momentum",&InteractionRecord::primary_momentum) + .def_readwrite("primary_helicity",&InteractionRecord::primary_helicity) + .def_readwrite("target_mass",&InteractionRecord::target_mass) + .def_readwrite("target_helicity",&InteractionRecord::target_helicity) + .def_readwrite("interaction_vertex",&InteractionRecord::interaction_vertex) + .def_readwrite("secondary_masses",&InteractionRecord::secondary_masses) + .def_readwrite("secondary_momenta",&InteractionRecord::secondary_momenta) + .def_readwrite("secondary_helicities",&InteractionRecord::secondary_helicities) + .def_readwrite("interaction_parameters",&InteractionRecord::interaction_parameters); + + py::class_>(m, "InteractionTreeDatum") + .def(py::init()) + .def_readwrite("record",&InteractionTreeDatum::record) + .def_readwrite("parent",&InteractionTreeDatum::parent) + .def_readwrite("daughters",&InteractionTreeDatum::daughters) + .def("depth",&InteractionTreeDatum::depth); + + py::class_>(m, "InteractionTree") + .def(py::init<>()) + .def_readwrite("tree",&InteractionTree::tree) + .def("add_entry",static_cast (InteractionTree::*)(InteractionTreeDatum&,std::shared_ptr)>(&InteractionTree::add_entry)) + .def("add_entry",static_cast (InteractionTree::*)(InteractionRecord&,std::shared_ptr)>(&InteractionTree::add_entry)); + + m.def("SaveInteractionTrees",&SaveInteractionTrees); + m.def("LoadInteractionTrees",&LoadInteractionTrees, py::return_value_policy::reference); } From 41768b9f1bf4e0281af408efe85196e1478e0900 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Fri, 13 Sep 2024 21:03:07 -0600 Subject: [PATCH 54/94] Clean up ParticleID __str__ and __repr__. Implement != operator --- projects/dataclasses/private/ParticleID.cxx | 34 ++++++++++++++++--- .../private/pybindings/dataclasses.cxx | 23 +++---------- .../public/SIREN/dataclasses/ParticleID.h | 5 +++ 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/projects/dataclasses/private/ParticleID.cxx b/projects/dataclasses/private/ParticleID.cxx index 2074ddae8..666abb78d 100644 --- a/projects/dataclasses/private/ParticleID.cxx +++ b/projects/dataclasses/private/ParticleID.cxx @@ -6,15 +6,35 @@ #include #include -std::ostream& operator<<(std::ostream& os, siren::dataclasses::ParticleID const& record) { - os << "ParticleID (" << &record << ")\n"; - os << "IDSet: " << record.id_set << "\n"; - os << "MajorID: " << record.major_id << "\n"; - os << "MinorID: " << record.minor_id; +#include "SIREN/utilities/StringManipulation.h" +std::ostream& operator<<(std::ostream& os, siren::dataclasses::ParticleID const& id) { + os << to_repr(id); return os; } +std::string to_str(siren::dataclasses::ParticleID const & id) { + using siren::utilities::tab; + std::stringstream ss; + ss << "[ ParticleID (" << &id << ")\n"; + ss << tab << "IDSet: " << id.IsSet() << '\n'; + ss << tab << "MajorID: " << id.GetMajorID() << '\n'; + ss << tab << "MinorID: " << id.GetMinorID() << '\n'; + ss << ']'; + return ss.str(); +} + +std::string to_repr(siren::dataclasses::ParticleID const & id) { + std::stringstream ss; + ss << "ParticleID("; + if(id.IsSet()) + ss << id.GetMajorID() << ", " << id.GetMinorID(); + else + ss << "unset"; + ss << ")"; + return ss.str(); +} + namespace siren { namespace dataclasses { @@ -60,6 +80,10 @@ bool ParticleID::operator==(ParticleID const & other) const { return std::tie(id_set, major_id, minor_id) == std::tie(id_set, other.major_id, other.minor_id); } +bool ParticleID::operator!=(ParticleID const & other) const { + return not (*this == other); +} + // Adapted from https://github.com/icecube/icetray-public/blob/4436c3e10c23f95a8965c98fecccb7775a361fab/dataclasses/private/dataclasses/physics/I3Particle.cxx#L42-L93 ParticleID ParticleID::GenerateID() { int this_pid = getpid(); diff --git a/projects/dataclasses/private/pybindings/dataclasses.cxx b/projects/dataclasses/private/pybindings/dataclasses.cxx index f2f1166b0..b80199ba8 100644 --- a/projects/dataclasses/private/pybindings/dataclasses.cxx +++ b/projects/dataclasses/private/pybindings/dataclasses.cxx @@ -26,30 +26,17 @@ PYBIND11_MODULE(dataclasses, m) { .def(py::init(), py::arg("major"), py::arg("minor")) .def(py::init(), py::arg("other")) .def(py::init(), py::arg("other")) - .def_static("generate_id", &siren::dataclasses::ParticleID::GenerateID) - .def("is_set", &siren::dataclasses::ParticleID::IsSet) - //.def_property("major_id", &siren::dataclasses::ParticleID::GetMajorID, &siren::dataclasses::ParticleID::SetMajorID) - // Getters for major and minor IDs .def_property_readonly("major_id", &siren::dataclasses::ParticleID::GetMajorID) .def_property_readonly("minor_id", &siren::dataclasses::ParticleID::GetMinorID) - // Method to set the ID - .def("set", &siren::dataclasses::ParticleID::SetID, py::arg("major"), py::arg("minor")) - // Overload the bool operator .def("__bool__", &siren::dataclasses::ParticleID::operator bool) - // Comparison operators + .def("__repr__", [](siren::dataclasses::ParticleID const & id) { return to_repr(id); }) + .def("__str__", [](siren::dataclasses::ParticleID const & id) { return to_str(id); }) + .def("is_set", &siren::dataclasses::ParticleID::IsSet) + .def("set", &siren::dataclasses::ParticleID::SetID, py::arg("major"), py::arg("minor")) .def(py::self == py::self) .def(py::self != py::self) .def(py::self < py::self) - // String representation - .def("__repr__", - [](const siren::dataclasses::ParticleID &id) { - std::ostringstream oss; - oss << id; - return oss.str(); - } - ) - // Optional: Serialize method if needed in Python - // .def("serialize", &siren::dataclasses::ParticleID::serialize) + .def_static("generate_id", &siren::dataclasses::ParticleID::GenerateID) ; py::class_> particle(m, "Particle"); diff --git a/projects/dataclasses/public/SIREN/dataclasses/ParticleID.h b/projects/dataclasses/public/SIREN/dataclasses/ParticleID.h index c01b8a841..e2d6d9321 100644 --- a/projects/dataclasses/public/SIREN/dataclasses/ParticleID.h +++ b/projects/dataclasses/public/SIREN/dataclasses/ParticleID.h @@ -16,6 +16,8 @@ namespace siren { namespace dataclasses { class ParticleID; } } std::ostream& operator<<(std::ostream& os, siren::dataclasses::ParticleID const& record); +std::string to_str(siren::dataclasses::ParticleID const & record); +std::string to_repr(siren::dataclasses::ParticleID const & record); namespace siren { namespace dataclasses { @@ -45,7 +47,10 @@ class ParticleID { bool operator<(ParticleID const & other) const; bool operator==(ParticleID const & other) const; + bool operator!=(ParticleID const & other) const; friend std::ostream& ::operator<<(std::ostream& os, ParticleID const& record); + friend std::string (::to_str)(ParticleID const & record); + friend std::string (::to_repr)(ParticleID const & record); template void serialize(Archive & archive, std::uint32_t const version) { if(version == 0) { From ef147b693138df42b163b535960f9d94b549d7bd Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Fri, 13 Sep 2024 21:03:50 -0600 Subject: [PATCH 55/94] Use lambda in favor of separate function pointer --- .../detector/private/pybindings/DetectorSector.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/projects/detector/private/pybindings/DetectorSector.h b/projects/detector/private/pybindings/DetectorSector.h index f54349c9a..9285ee662 100644 --- a/projects/detector/private/pybindings/DetectorSector.h +++ b/projects/detector/private/pybindings/DetectorSector.h @@ -6,19 +6,17 @@ #include "../../public/SIREN/detector/DetectorModel.h" -std::string to_str(siren::detector::DetectorSector const & sector) { - std::stringstream ss; - sector.Print(ss); - return ss.str(); -} - void register_DetectorSector(pybind11::module_ & m) { using namespace pybind11; using namespace siren::detector; class_>(m, "DetectorSector") .def(init<>()) - .def("__str__", &to_str) + .def("__str__", [](const DetectorSector & sector) { + std::stringstream ss; + sector.Print(ss); + return ss.str(); + }) .def_readwrite("name",&DetectorSector::name) .def_readwrite("material_id",&DetectorSector::material_id) .def_readwrite("level", &DetectorSector::level) From 5d8339a95363b65e2a63d9f17e38ca3b10d5f778 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Fri, 13 Sep 2024 22:10:28 -0600 Subject: [PATCH 56/94] __str__ and __repr__ for InteractionRecord --- .../dataclasses/private/InteractionRecord.cxx | 134 ++++++++++++------ projects/dataclasses/private/ParticleID.cxx | 2 +- .../private/pybindings/dataclasses.cxx | 33 +++-- .../SIREN/dataclasses/InteractionRecord.h | 14 ++ .../utilities/private/StringManipulation.cxx | 20 ++- .../SIREN/utilities/StringManipulation.h | 1 + 6 files changed, 136 insertions(+), 68 deletions(-) diff --git a/projects/dataclasses/private/InteractionRecord.cxx b/projects/dataclasses/private/InteractionRecord.cxx index 48c52530b..1a166db10 100644 --- a/projects/dataclasses/private/InteractionRecord.cxx +++ b/projects/dataclasses/private/InteractionRecord.cxx @@ -4,6 +4,8 @@ #include // for tie, operator==, tuple #include #include // for operator<<, basic_ostream, char_traits, endl, ost... + // +#include "SIREN/utilities/StringManipulation.h" // for tab std::ostream& operator<<(std::ostream& os, siren::dataclasses::InteractionRecord const& record); std::ostream& operator<<(std::ostream& os, siren::dataclasses::PrimaryDistributionRecord const& record); @@ -1099,61 +1101,101 @@ std::ostream& operator<<(std::ostream& os, siren::dataclasses::SecondaryDistribu return os; } -std::ostream& operator<<(std::ostream& os, siren::dataclasses::InteractionRecord const& record) { - std::stringstream ss; - ss << "InteractionRecord (" << &record << ") "; - os << ss.str() << '\n'; - os << "Signature(" << &record.signature << "): " << record.signature.primary_type << " + " << record.signature.target_type << " ->"; - for(auto secondary: record.signature.secondary_types) { - os << " " << secondary; - } - os << "\n"; +std::ostream& operator<<(std::ostream& os, siren::dataclasses::InteractionRecord const & record) { + os << to_repr(record); + return os; +} - ss.str(std::string()); - std::string id_str; - ss << record.primary_id; - id_str = ss.str(); - std::string from = "\n"; - std::string to = "\n "; - size_t start_pos = 0; - while((start_pos = id_str.find(from, start_pos)) != std::string::npos) { - id_str.replace(start_pos, from.length(), to); - start_pos += to.length(); // Handles case where 'to' is a substring of 'from' - } - ss << "PrimaryID: " << id_str << "\n"; - os << "PrimaryInitialPosition: " << record.primary_initial_position.at(0) << " " << record.primary_initial_position.at(1) << " " << record.primary_initial_position.at(2) << "\n"; - os << "InteractionVertex: " << record.interaction_vertex.at(0) << " " << record.interaction_vertex.at(1) << " " << record.interaction_vertex.at(2) << "\n"; - os << "PrimaryMass: " << record.primary_mass << "\n"; - os << "PrimaryMomentum: " << record.primary_momentum.at(0) << " " << record.primary_momentum.at(1) << " " << record.primary_momentum.at(2) << " " << record.primary_momentum.at(3) << "\n"; - os << "TargetID: " << record.target_id << "\n"; - os << "TargetMass: " << record.target_mass << "\n"; - os << "SecondaryIDs:\n"; +std::string to_str(siren::dataclasses::InteractionRecord const & record) { + using siren::utilities::tab; + std::stringstream ss; + ss << "[ InteractionRecord (" << &record << "):\n"; + ss << tab << "InteractionSignature: " << record.signature.primary_type << " + " << record.signature.target_type << " ->"; + if(record.signature.secondary_types.size() > 3) { + ss << '\n'; + ss << tab << tab; + } + for(auto secondary: record.signature.secondary_types) + ss << " " << secondary; + ss << '\n'; + + ss << tab << "PrimaryID: " << to_repr(record.primary_id) << '\n'; + ss << tab << "PrimaryInitialPosition: " << record.primary_initial_position.at(0) << " " << record.primary_initial_position.at(1) << " " << record.primary_initial_position.at(2) << '\n'; + ss << tab << "InteractionVertex: " << record.interaction_vertex.at(0) << " " << record.interaction_vertex.at(1) << " " << record.interaction_vertex.at(2) << '\n'; + ss << tab << "PrimaryMass: " << record.primary_mass << '\n'; + ss << tab << "PrimaryMomentum: " << record.primary_momentum.at(0) << " " << record.primary_momentum.at(1) << " " << record.primary_momentum.at(2) << " " << record.primary_momentum.at(3) << '\n'; + ss << tab << "TargetID: " << to_repr(record.target_id) << '\n'; + ss << tab << "TargetMass: " << record.target_mass << '\n'; + ss << tab << "SecondaryIDs:\n"; for(auto const & secondary: record.secondary_ids) { - ss.str(std::string()); - id_str.clear(); - ss << secondary; - id_str = ss.str(); - start_pos = 0; - while((start_pos = id_str.find(from, start_pos)) != std::string::npos) { - id_str.replace(start_pos, from.length(), to); - start_pos += to.length(); // Handles case where 'to' is a substring of 'from' - } - os << "\t" << id_str << "\n"; + ss << tab << tab << to_repr(secondary) << '\n'; } - os << "SecondaryMomenta:\n"; + ss << tab << "SecondaryMomenta:\n"; for(auto const & secondary: record.secondary_momenta) { - os << "\t" << secondary.at(0) << " " << secondary.at(1) << " " << secondary.at(2) << " " << secondary.at(3) << "\n"; + ss << tab << tab << secondary.at(0) << " " << secondary.at(1) << " " << secondary.at(2) << " " << secondary.at(3) << '\n'; } - os << "SecondaryMasses:\n"; + ss << tab << "SecondaryMasses:\n"; for(auto const & secondary: record.secondary_masses) { - os << "\t" << secondary << "\n"; + ss << tab << tab << secondary << '\n'; } - os << "InteractionParameters:\n"; + ss << tab << "InteractionParameters:\n"; for(std::pair const & param : record.interaction_parameters) { - os << "\t\"" << param.first << "\": " << param.second << "\n"; + ss << tab << tab << '\"' << param.first << "\": " << param.second << '\n'; } - os << std::endl; + ss << ']'; - return os; + return ss.str(); +} + +std::string to_repr(siren::dataclasses::InteractionRecord const & record) { + using siren::utilities::tab; + std::stringstream ss; + ss << "InteractionRecord("; + ss << record.signature.primary_type << " + " << record.signature.target_type << " ->"; + for(auto secondary: record.signature.secondary_types) + ss << " " << secondary; + ss << ", "; + ss << "primary_id=" << to_repr(record.primary_id) << ", "; + ss << "primary_initial_position=(" << record.primary_initial_position.at(0) << ", " << record.primary_initial_position.at(1) << ", " << record.primary_initial_position.at(2) << "), "; + ss << "interaction_vertex=(" << record.interaction_vertex.at(0) << ", " << record.interaction_vertex.at(1) << ", " << record.interaction_vertex.at(2) << "), "; + ss << "primary_mass=" << record.primary_mass << ", "; + ss << "primary_momentum=(" << record.primary_momentum.at(0) << ", " << record.primary_momentum.at(1) << ", " << record.primary_momentum.at(2) << ", " << record.primary_momentum.at(3) << "), "; + ss << "target_id=" << to_repr(record.target_id) << ", "; + ss << "target_mass=" << record.target_mass << ", "; + ss << "secondary_ids=["; + if(record.secondary_ids.size() > 0) { + ss << to_repr(record.secondary_ids.at(0)); + for(size_t i=1; i 0) { + ss << "(" << record.secondary_momenta.at(0).at(0) << ", " << record.secondary_momenta.at(0).at(1) << ", " << record.secondary_momenta.at(0).at(2) << ", " << record.secondary_momenta.at(0).at(3) << ")"; + for(size_t i=1; i 0) { + ss << record.secondary_masses.at(0); + for(size_t i=1; i 0) { + auto it = record.interaction_parameters.begin(); + ss << '\"' << it->first << "\": " << it->second; + for(++it; it != record.interaction_parameters.end(); ++it) { + ss << ", \"" << it->first << "\": " << it->second; + } + } + ss << "}"; + ss << ")"; + return ss.str(); } diff --git a/projects/dataclasses/private/ParticleID.cxx b/projects/dataclasses/private/ParticleID.cxx index 666abb78d..e6e3268af 100644 --- a/projects/dataclasses/private/ParticleID.cxx +++ b/projects/dataclasses/private/ParticleID.cxx @@ -8,7 +8,7 @@ #include "SIREN/utilities/StringManipulation.h" -std::ostream& operator<<(std::ostream& os, siren::dataclasses::ParticleID const& id) { +std::ostream& operator<<(std::ostream& os, siren::dataclasses::ParticleID const & id) { os << to_repr(id); return os; } diff --git a/projects/dataclasses/private/pybindings/dataclasses.cxx b/projects/dataclasses/private/pybindings/dataclasses.cxx index b80199ba8..04709bfab 100644 --- a/projects/dataclasses/private/pybindings/dataclasses.cxx +++ b/projects/dataclasses/private/pybindings/dataclasses.cxx @@ -19,9 +19,7 @@ PYBIND11_MODULE(dataclasses, m) { using namespace siren::dataclasses; // Create a Python class binding for siren::dataclasses::ParticleID - py::class_ particle_id(m, "ParticleID"); - - particle_id + py::class_(m, "ParticleID") .def(py::init<>()) .def(py::init(), py::arg("major"), py::arg("minor")) .def(py::init(), py::arg("other")) @@ -39,9 +37,8 @@ PYBIND11_MODULE(dataclasses, m) { .def_static("generate_id", &siren::dataclasses::ParticleID::GenerateID) ; - py::class_> particle(m, "Particle"); - - particle.def(py::init<>()) + py::class_>(m, "Particle") + .def(py::init<>()) .def(py::init()) .def(py::init, std::array, double, double>()) .def(py::init, std::array, double, double>()) @@ -53,7 +50,8 @@ PYBIND11_MODULE(dataclasses, m) { .def_readwrite("position",&Particle::position) .def_readwrite("length",&Particle::length) .def_readwrite("helicity",&Particle::helicity) - .def("generate_id",&Particle::GenerateID); + .def("generate_id",&Particle::GenerateID) + ; py::enum_(m, "ParticleType", py::arithmetic()) #define X(a, b) .value( #a , ParticleType:: a ) @@ -67,7 +65,8 @@ PYBIND11_MODULE(dataclasses, m) { .def("__repr__", [](InteractionSignature const & s) { return to_repr(s); }) .def_readwrite("primary_type",&InteractionSignature::primary_type) .def_readwrite("target_type",&InteractionSignature::target_type) - .def_readwrite("secondary_types",&InteractionSignature::secondary_types); + .def_readwrite("secondary_types",&InteractionSignature::secondary_types) + ; py::class_>(m, "PrimaryDistributionRecord") .def(py::init()) @@ -106,7 +105,8 @@ PYBIND11_MODULE(dataclasses, m) { .def_property("three_momentum", ((std::array const & (SecondaryParticleRecord::*)())(&SecondaryParticleRecord::GetThreeMomentum)), &SecondaryParticleRecord::SetThreeMomentum) .def_property("four_momentum", ((std::array (SecondaryParticleRecord::*)())(&SecondaryParticleRecord::GetFourMomentum)), &SecondaryParticleRecord::SetFourMomentum) .def_property("helicity", ((double const & (SecondaryParticleRecord::*)())(&SecondaryParticleRecord::GetHelicity)), &SecondaryParticleRecord::SetHelicity) - .def("finalize", &SecondaryParticleRecord::Finalize); + .def("finalize", &SecondaryParticleRecord::Finalize) + ; py::class_>(m, "CrossSectionDistributionRecord") .def(py::init()) @@ -144,12 +144,14 @@ PYBIND11_MODULE(dataclasses, m) { .def("get_econdary_particle_records", [](siren::dataclasses::CrossSectionDistributionRecord & cdr) -> std::vector & {return cdr.GetSecondaryParticleRecords();}, py::return_value_policy::reference_internal) - .def("finalize", &CrossSectionDistributionRecord::Finalize); + .def("finalize", &CrossSectionDistributionRecord::Finalize) + ; py::class_>(m, "InteractionRecord") .def(py::init<>()) - .def("__str__", [](InteractionRecord const & r) { std::stringstream ss; ss << r; return ss.str(); }) + .def("__str__", [](InteractionRecord const & r) { return to_str(r); }) + .def("__repr__", [](InteractionRecord const & r) { return to_str(r); }) .def_readwrite("signature",&InteractionRecord::signature) .def_readwrite("primary_mass",&InteractionRecord::primary_mass) .def_readwrite("primary_momentum",&InteractionRecord::primary_momentum) @@ -160,20 +162,23 @@ PYBIND11_MODULE(dataclasses, m) { .def_readwrite("secondary_masses",&InteractionRecord::secondary_masses) .def_readwrite("secondary_momenta",&InteractionRecord::secondary_momenta) .def_readwrite("secondary_helicities",&InteractionRecord::secondary_helicities) - .def_readwrite("interaction_parameters",&InteractionRecord::interaction_parameters); + .def_readwrite("interaction_parameters",&InteractionRecord::interaction_parameters) + ; py::class_>(m, "InteractionTreeDatum") .def(py::init()) .def_readwrite("record",&InteractionTreeDatum::record) .def_readwrite("parent",&InteractionTreeDatum::parent) .def_readwrite("daughters",&InteractionTreeDatum::daughters) - .def("depth",&InteractionTreeDatum::depth); + .def("depth",&InteractionTreeDatum::depth) + ; py::class_>(m, "InteractionTree") .def(py::init<>()) .def_readwrite("tree",&InteractionTree::tree) .def("add_entry",static_cast (InteractionTree::*)(InteractionTreeDatum&,std::shared_ptr)>(&InteractionTree::add_entry)) - .def("add_entry",static_cast (InteractionTree::*)(InteractionRecord&,std::shared_ptr)>(&InteractionTree::add_entry)); + .def("add_entry",static_cast (InteractionTree::*)(InteractionRecord&,std::shared_ptr)>(&InteractionTree::add_entry)) + ; m.def("SaveInteractionTrees",&SaveInteractionTrees); m.def("LoadInteractionTrees",&LoadInteractionTrees, py::return_value_policy::reference); diff --git a/projects/dataclasses/public/SIREN/dataclasses/InteractionRecord.h b/projects/dataclasses/public/SIREN/dataclasses/InteractionRecord.h index 061ee0118..8cf47a89b 100644 --- a/projects/dataclasses/public/SIREN/dataclasses/InteractionRecord.h +++ b/projects/dataclasses/public/SIREN/dataclasses/InteractionRecord.h @@ -37,6 +37,18 @@ std::ostream& operator<<(std::ostream& os, siren::dataclasses::SecondaryParticle std::ostream& operator<<(std::ostream& os, siren::dataclasses::CrossSectionDistributionRecord const & record); std::ostream& operator<<(std::ostream& os, siren::dataclasses::SecondaryDistributionRecord const & record); +std::string to_str(siren::dataclasses::InteractionRecord const & record); +std::string to_str(siren::dataclasses::PrimaryDistributionRecord const & record); +std::string to_str(siren::dataclasses::SecondaryParticleRecord const & record); +std::string to_str(siren::dataclasses::CrossSectionDistributionRecord const & record); +std::string to_str(siren::dataclasses::SecondaryDistributionRecord const & record); + +std::string to_repr(siren::dataclasses::InteractionRecord const & record); +std::string to_repr(siren::dataclasses::PrimaryDistributionRecord const & record); +std::string to_repr(siren::dataclasses::SecondaryParticleRecord const & record); +std::string to_repr(siren::dataclasses::CrossSectionDistributionRecord const & record); +std::string to_repr(siren::dataclasses::SecondaryDistributionRecord const & record); + namespace siren { namespace dataclasses { @@ -265,6 +277,8 @@ class InteractionRecord { bool operator==(InteractionRecord const & other) const; bool operator<(InteractionRecord const & other) const; friend std::ostream& ::operator<<(std::ostream& os, InteractionRecord const& record); + friend std::string (::to_str)(InteractionRecord const & record); + friend std::string (::to_repr)(InteractionRecord const & record); template void save(Archive & archive, std::uint32_t const version) const { diff --git a/projects/utilities/private/StringManipulation.cxx b/projects/utilities/private/StringManipulation.cxx index 96f009f65..8d4e4dd38 100644 --- a/projects/utilities/private/StringManipulation.cxx +++ b/projects/utilities/private/StringManipulation.cxx @@ -15,27 +15,33 @@ std::string add_prefix(std::string const & input, std::string const & prefix) { size_t line_number = 0; // Read each line and track the last non-empty line - while (std::getline(iss, line)) { + while(std::getline(iss, line)) { lines.push_back(line); - if (!line.empty()) { + if (not line.empty()) { last_non_empty_line = line_number; } - line_number++; + ++line_number; } std::ostringstream oss; // Add prefix to each line up to the last non-empty line - if (last_non_empty_line >= 0) { - for (size_t i = 0; i <= static_cast(last_non_empty_line); ++i) { + if(last_non_empty_line >= 0) { + for (size_t i = 0; i < static_cast(last_non_empty_line); ++i) { oss << prefix << lines[i] << '\n'; } - // Ensure the string ends with an empty newline - oss << '\n'; + oss << prefix << lines[last_non_empty_line]; } return oss.str(); } +std::string indent(std::string const & input, size_t n_indent) { + std::stringstream ss; + for(size_t i = 0; i < n_indent; ++i) + ss << tab; + return add_prefix(input, ss.str()); +} + } // namespace utilities } // namespace siren diff --git a/projects/utilities/public/SIREN/utilities/StringManipulation.h b/projects/utilities/public/SIREN/utilities/StringManipulation.h index ef3d90a76..e5902f737 100644 --- a/projects/utilities/public/SIREN/utilities/StringManipulation.h +++ b/projects/utilities/public/SIREN/utilities/StringManipulation.h @@ -10,6 +10,7 @@ namespace utilities { constexpr char const * tab = " "; std::string add_prefix(std::string const & input, std::string const & prefix); +std::string indent(std::string const & input, size_t n_indent = 1); } // namespace utilities } // namespace siren From e7aeb09180a708840cb38e84be13f41fad1954b2 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Fri, 13 Sep 2024 22:15:48 -0600 Subject: [PATCH 57/94] to_str --> to_repr --- projects/dataclasses/private/pybindings/dataclasses.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/dataclasses/private/pybindings/dataclasses.cxx b/projects/dataclasses/private/pybindings/dataclasses.cxx index 04709bfab..fe082afff 100644 --- a/projects/dataclasses/private/pybindings/dataclasses.cxx +++ b/projects/dataclasses/private/pybindings/dataclasses.cxx @@ -151,7 +151,7 @@ PYBIND11_MODULE(dataclasses, m) { py::class_>(m, "InteractionRecord") .def(py::init<>()) .def("__str__", [](InteractionRecord const & r) { return to_str(r); }) - .def("__repr__", [](InteractionRecord const & r) { return to_str(r); }) + .def("__repr__", [](InteractionRecord const & r) { return to_repr(r); }) .def_readwrite("signature",&InteractionRecord::signature) .def_readwrite("primary_mass",&InteractionRecord::primary_mass) .def_readwrite("primary_momentum",&InteractionRecord::primary_momentum) From 83e609b8e1877fcd9fc43583eaa224f9d462805c Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Fri, 13 Sep 2024 23:20:21 -0600 Subject: [PATCH 58/94] __str__ and __repr__ for CrossSectionDistributionRecord and SecondaryParticleRecord --- .../dataclasses/private/InteractionRecord.cxx | 300 +++++++++++------- .../private/pybindings/dataclasses.cxx | 4 + .../SIREN/dataclasses/InteractionRecord.h | 6 + 3 files changed, 200 insertions(+), 110 deletions(-) diff --git a/projects/dataclasses/private/InteractionRecord.cxx b/projects/dataclasses/private/InteractionRecord.cxx index 1a166db10..c8ccef439 100644 --- a/projects/dataclasses/private/InteractionRecord.cxx +++ b/projects/dataclasses/private/InteractionRecord.cxx @@ -929,137 +929,217 @@ std::ostream & operator<<(std::ostream & os, siren::dataclasses::PrimaryDistribu return os; } -std::ostream & operator<<(std::ostream & os, siren::dataclasses::CrossSectionDistributionRecord const & record) { - std::stringstream ss; - ss << "CrossSectionDistributionRecord (" << &record << ") "; - os << ss.str() << '\n'; - - ss.str(std::string()); - std::string id_str; - ss << record.GetPrimaryID(); - id_str = ss.str(); - std::string from = "\n"; - std::string to = "\n "; - size_t start_pos = 0; - while((start_pos = id_str.find(from, start_pos)) != std::string::npos) { - id_str.replace(start_pos, from.length(), to); - start_pos += to.length(); // Handles case where 'to' is a substring of 'from' - } - os << "PrimaryID: " << id_str << "\n"; - - os << "PrimaryType: " << record.primary_type << "\n"; - - os << "PrimaryInitialPosition: " << record.primary_initial_position.at(0) << " " << record.primary_initial_position.at(1) << " " << record.primary_initial_position.at(2) << "\n"; - - os << "PrimaryMass: " << record.primary_mass << "\n"; - - os << "PrimaryMomentum: " << record.primary_momentum.at(0) << " " << record.primary_momentum.at(1) << " " << record.primary_momentum.at(2) << " " << record.primary_momentum.at(3) << "\n"; - - os << "PrimaryHelicity: " << record.primary_helicity << "\n"; - - os << "InteractionVertex: " << record.interaction_vertex.at(0) << " " << record.interaction_vertex.at(1) << " " << record.interaction_vertex.at(2) << "\n"; - - ss.str(std::string()); - ss << record.GetTargetID(); - id_str = ss.str(); - start_pos = 0; - while((start_pos = id_str.find(from, start_pos)) != std::string::npos) { - id_str.replace(start_pos, from.length(), to); - start_pos += to.length(); // Handles case where 'to' is a substring of 'from' - } - os << "TargetID: " << id_str << "\n"; - - os << "TargetType: " << record.target_type << "\n"; +std::ostream& operator<<(std::ostream& os, siren::dataclasses::CrossSectionDistributionRecord const& record) { + os << to_repr(record); + return os; +} - os << "TargetMass: " << record.target_mass << "\n"; +std::string to_str(siren::dataclasses::CrossSectionDistributionRecord const & record) { + using siren::utilities::tab; + using siren::utilities::indent; + std::stringstream ss; - os << "TargetHelicity: " << record.target_helicity << "\n"; + ss << "[ CrossSectionDistributionRecord (" << &record << "):\n"; + ss << tab << "PrimaryID: " << to_repr(record.GetPrimaryID()) << '\n'; + ss << tab << "PrimaryType: " << record.primary_type << '\n'; + ss << tab << "PrimaryInitialPosition: " + << record.primary_initial_position.at(0) << " " + << record.primary_initial_position.at(1) << " " + << record.primary_initial_position.at(2) << '\n'; + ss << tab << "PrimaryMass: " << record.primary_mass << '\n'; + ss << tab << "PrimaryMomentum: " + << record.primary_momentum.at(0) << " " + << record.primary_momentum.at(1) << " " + << record.primary_momentum.at(2) << " " + << record.primary_momentum.at(3) << '\n'; + ss << tab << "PrimaryHelicity: " << record.primary_helicity << '\n'; + ss << tab << "InteractionVertex: " + << record.interaction_vertex.at(0) << " " + << record.interaction_vertex.at(1) << " " + << record.interaction_vertex.at(2) << '\n'; + ss << tab << "TargetID: " << to_repr(record.GetTargetID()) << '\n'; + ss << tab << "TargetType: " << record.target_type << '\n'; + ss << tab << "TargetMass: " << record.target_mass << '\n'; + ss << tab << "TargetHelicity: " << record.target_helicity << '\n'; - if(record.interaction_parameters.size() > 0) { - os << "InteractionParameters:\n"; - for(auto const & parameter: record.interaction_parameters) { - os << "\t" << parameter.first << ": " << parameter.second << "\n"; + ss << tab << "InteractionParameters:\n"; + if (!record.interaction_parameters.empty()) { + for (const auto& parameter : record.interaction_parameters) { + ss << tab << tab << parameter.first << ": " << parameter.second << '\n'; } - } else { - os << "InteractionParameters: " << "None" << "\n"; } - os << "SecondaryParticles:\n"; - std::string secondary_str; - for(size_t i = 0; i < record.signature.secondary_types.size(); ++i) { - ss.str(std::string()); - ss << record.GetSecondaryParticleRecord(i); - secondary_str = ss.str(); - start_pos = 0; - while((start_pos = secondary_str.find(from, start_pos)) != std::string::npos) { - secondary_str.replace(start_pos, from.length(), to); - start_pos += to.length(); // Handles case where 'to' is a substring of 'from' - } - os << secondary_str << "\n"; + ss << tab << "SecondaryParticles:\n"; + for(size_t i=0; ifirst << "\": " << it->second; + for (++it; it != record.interaction_parameters.end(); ++it) { + ss << ", \"" << it->first << "\": " << it->second; + } } + ss << "}, "; + + // Secondary Particles + ss << "secondary_particles=["; + for (size_t i = 0; i < record.signature.secondary_types.size(); ++i) { + siren::dataclasses::SecondaryParticleRecord const & secondary = record.secondary_particles[i]; + if (i > 0) ss << ", "; + ss << "{"; + ss << "index=" << secondary.secondary_index << ", "; + ss << "id=" << to_repr(secondary.id) << ", "; + ss << "type=" << secondary.type << ", "; + ss << "initial_position=(" + << secondary.initial_position.at(0) << ", " + << secondary.initial_position.at(1) << ", " + << secondary.initial_position.at(2) << ")"; + if (secondary.mass_set) + ss << ", mass=" << secondary.mass; + if (secondary.energy_set) + ss << ", energy=" << secondary.energy; + if (secondary.kinetic_energy_set) + ss << ", kinetic_energy=" << secondary.kinetic_energy; + if (secondary.direction_set) + ss << ", direction=(" + << secondary.direction.at(0) << ", " + << secondary.direction.at(1) << ", " + << secondary.direction.at(2) << ")"; + if (secondary.momentum_set) + ss << ", momentum=(" + << secondary.momentum.at(0) << ", " + << secondary.momentum.at(1) << ", " + << secondary.momentum.at(2) << ")"; + if (secondary.helicity_set) + ss << ", helicity=" << secondary.helicity; + ss << "}"; + } + ss << "]"; - if(record.energy_set) { - os << "Energy: " << record.energy << "\n"; - } else { - os << "Energy: " << "None" << "\n"; - } + ss << ")"; - if(record.kinetic_energy_set) { - os << "KineticEnergy: " << record.kinetic_energy << "\n"; - } else { - os << "KineticEnergy: " << "None" << "\n"; - } + return ss.str(); +} - if(record.direction_set) { - os << "Direction: " << record.direction.at(0) << " " << record.direction.at(1) << " " << record.direction.at(2) << "\n"; - } else { - os << "Direction: " << "None" << "\n"; - } - if(record.momentum_set) { - os << "Momentum: " << record.momentum.at(0) << " " << record.momentum.at(1) << " " << record.momentum.at(2) << "\n"; - } else { - os << "Momentum: " << "None" << "\n"; - } +std::ostream & operator<<(std::ostream & os, siren::dataclasses::SecondaryParticleRecord const & record) { + os << to_repr(record); + return os; +} - os << "InitialPosition: " << record.initial_position.at(0) << " " << record.initial_position.at(1) << " " << record.initial_position.at(2) << "\n"; +std::string to_str(siren::dataclasses::SecondaryParticleRecord const& record) { + using siren::utilities::tab; + using siren::utilities::indent; + std::stringstream ss; + ss << "[ SecondaryParticleRecord (" << &record << "):\n"; + ss << tab << "Index: " << record.secondary_index << '\n'; + ss << tab << "ID: " << to_repr(record.id) << '\n'; + ss << tab << "Type: " << record.type << '\n'; + ss << tab << "InitialPosition: " + << record.initial_position.at(0) << " " + << record.initial_position.at(1) << " " + << record.initial_position.at(2) << '\n'; + ss << tab << "Mass: "; + if (record.mass_set) + ss << record.mass << '\n'; + else + ss << "unset\n"; + ss << tab << "Energy: "; + if (record.energy_set) + ss << record.energy << '\n'; + else + ss << "unset\n"; + ss << tab << "KineticEnergy: "; + if (record.kinetic_energy_set) + ss << record.kinetic_energy << '\n'; + else + ss << "unset\n"; + ss << tab << "Direction: "; + if (record.direction_set) + ss << record.direction.at(0) << " " << record.direction.at(1) << " " << record.direction.at(2) << '\n'; + else + ss << "unset\n"; + ss << tab << "Momentum: "; + if (record.momentum_set) + ss << record.momentum.at(0) << " " << record.momentum.at(1) << " " << record.momentum.at(2) << '\n'; + else + ss << "unset\n"; + ss << tab << "Helicity: "; + if (record.helicity_set) + ss << record.helicity << '\n'; + else + ss << "unset\n"; + ss << ']'; - if(record.helicity_set) { - os << "Helicity: " << record.helicity << "\n"; - } else { - os << "Helicity: " << "None" << "\n"; - } + return ss.str(); +} - return os; +std::string to_repr(siren::dataclasses::SecondaryParticleRecord const& record) { + std::stringstream ss; + ss << "SecondaryParticleRecord("; + ss << "index=" << record.secondary_index << ", "; + ss << "id=" << to_repr(record.id) << ", "; + ss << "type=" << record.type << ", "; + ss << "initial_position=(" + << record.initial_position.at(0) << ", " + << record.initial_position.at(1) << ", " + << record.initial_position.at(2) << ")"; + if (record.mass_set) + ss << ", mass=" << record.mass; + if (record.energy_set) + ss << ", energy=" << record.energy; + if (record.kinetic_energy_set) + ss << ", kinetic_energy=" << record.kinetic_energy; + if (record.direction_set) + ss << ", direction=(" + << record.direction.at(0) << ", " + << record.direction.at(1) << ", " + << record.direction.at(2) << ")"; + if (record.momentum_set) + ss << ", momentum=(" + << record.momentum.at(0) << ", " + << record.momentum.at(1) << ", " + << record.momentum.at(2) << ")"; + if (record.helicity_set) + ss << ", helicity=" << record.helicity; + ss << ")"; + return ss.str(); } std::ostream& operator<<(std::ostream& os, siren::dataclasses::SecondaryDistributionRecord const& record) { diff --git a/projects/dataclasses/private/pybindings/dataclasses.cxx b/projects/dataclasses/private/pybindings/dataclasses.cxx index fe082afff..7cf9e2990 100644 --- a/projects/dataclasses/private/pybindings/dataclasses.cxx +++ b/projects/dataclasses/private/pybindings/dataclasses.cxx @@ -90,6 +90,8 @@ PYBIND11_MODULE(dataclasses, m) { py::class_>(m, "SecondaryParticleRecord") .def(py::init()) + .def("__str__", [](SecondaryParticleRecord const & spr) { return to_str(spr); }) + .def("__repr__", [](SecondaryParticleRecord const & spr) { return to_repr(spr); }) .def_property_readonly("id", [](siren::dataclasses::SecondaryParticleRecord const & spr) {siren::dataclasses::ParticleID id = spr.id; return id;}) .def_property_readonly("type", @@ -110,6 +112,8 @@ PYBIND11_MODULE(dataclasses, m) { py::class_>(m, "CrossSectionDistributionRecord") .def(py::init()) + .def("__str__", [](CrossSectionDistributionRecord const & cdr) { return to_str(cdr); }) + .def("__repr__", [](CrossSectionDistributionRecord const & cdr) { return to_repr(cdr); }) .def_property_readonly("record", [](siren::dataclasses::CrossSectionDistributionRecord const & cdr) {siren::dataclasses::InteractionRecord ir = cdr.record; return ir;}) .def_property_readonly("signature", diff --git a/projects/dataclasses/public/SIREN/dataclasses/InteractionRecord.h b/projects/dataclasses/public/SIREN/dataclasses/InteractionRecord.h index 8cf47a89b..9388d25e1 100644 --- a/projects/dataclasses/public/SIREN/dataclasses/InteractionRecord.h +++ b/projects/dataclasses/public/SIREN/dataclasses/InteractionRecord.h @@ -153,6 +153,10 @@ class SecondaryParticleRecord { mutable double helicity = 0; public: friend std::ostream& ::operator<<(std::ostream& os, SecondaryParticleRecord const& record); + friend std::string (::to_str)(SecondaryParticleRecord const & record); + friend std::string (::to_repr)(SecondaryParticleRecord const & record); + friend std::string (::to_str)(CrossSectionDistributionRecord const & record); + friend std::string (::to_repr)(CrossSectionDistributionRecord const & record); SecondaryParticleRecord(SecondaryParticleRecord const & other) = delete; SecondaryParticleRecord(SecondaryParticleRecord && other) = default; @@ -217,6 +221,8 @@ class CrossSectionDistributionRecord { std::vector secondary_particles; public: friend std::ostream& ::operator<<(std::ostream& os, CrossSectionDistributionRecord const& record); + friend std::string (::to_str)(CrossSectionDistributionRecord const & record); + friend std::string (::to_repr)(CrossSectionDistributionRecord const & record); CrossSectionDistributionRecord(CrossSectionDistributionRecord const & other) = delete; CrossSectionDistributionRecord(CrossSectionDistributionRecord && other) = default; From 19778c4c8deeef8a81d492298867449f34019e26 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sat, 14 Sep 2024 11:18:40 -0600 Subject: [PATCH 59/94] Specify namespace for args of forward declared output functions. --- .../public/SIREN/dataclasses/InteractionRecord.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/projects/dataclasses/public/SIREN/dataclasses/InteractionRecord.h b/projects/dataclasses/public/SIREN/dataclasses/InteractionRecord.h index 9388d25e1..c5c7da68f 100644 --- a/projects/dataclasses/public/SIREN/dataclasses/InteractionRecord.h +++ b/projects/dataclasses/public/SIREN/dataclasses/InteractionRecord.h @@ -153,10 +153,10 @@ class SecondaryParticleRecord { mutable double helicity = 0; public: friend std::ostream& ::operator<<(std::ostream& os, SecondaryParticleRecord const& record); - friend std::string (::to_str)(SecondaryParticleRecord const & record); - friend std::string (::to_repr)(SecondaryParticleRecord const & record); - friend std::string (::to_str)(CrossSectionDistributionRecord const & record); - friend std::string (::to_repr)(CrossSectionDistributionRecord const & record); + friend std::string (::to_str)(siren::dataclasses::SecondaryParticleRecord const & record); + friend std::string (::to_repr)(siren::dataclasses::SecondaryParticleRecord const & record); + friend std::string (::to_str)(siren::dataclasses::CrossSectionDistributionRecord const & record); + friend std::string (::to_repr)(siren::dataclasses::CrossSectionDistributionRecord const & record); SecondaryParticleRecord(SecondaryParticleRecord const & other) = delete; SecondaryParticleRecord(SecondaryParticleRecord && other) = default; From 764f63d04542c0a4f64afa45ffe24c76ac577a91 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sat, 14 Sep 2024 11:38:45 -0600 Subject: [PATCH 60/94] Add output functions as friends. More specific namespaces. --- .../SIREN/dataclasses/InteractionRecord.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/projects/dataclasses/public/SIREN/dataclasses/InteractionRecord.h b/projects/dataclasses/public/SIREN/dataclasses/InteractionRecord.h index c5c7da68f..5ee85fd48 100644 --- a/projects/dataclasses/public/SIREN/dataclasses/InteractionRecord.h +++ b/projects/dataclasses/public/SIREN/dataclasses/InteractionRecord.h @@ -80,7 +80,9 @@ class PrimaryDistributionRecord { mutable std::array interaction_vertex; mutable double helicity = 0; public: - friend std::ostream& ::operator<<(std::ostream& os, PrimaryDistributionRecord const& record); + friend std::ostream& ::operator<<(std::ostream& os, siren::dataclasses::PrimaryDistributionRecord const& record); + friend std::string (::to_str)(siren::dataclasses::PrimaryDistributionRecord const & record); + friend std::string (::to_repr)(siren::dataclasses::PrimaryDistributionRecord const & record); PrimaryDistributionRecord(PrimaryDistributionRecord const & other) = delete; PrimaryDistributionRecord(PrimaryDistributionRecord && other) = default; @@ -152,7 +154,7 @@ class SecondaryParticleRecord { mutable std::array momentum = {0, 0, 0}; mutable double helicity = 0; public: - friend std::ostream& ::operator<<(std::ostream& os, SecondaryParticleRecord const& record); + friend std::ostream& ::operator<<(std::ostream& os, siren::dataclasses::SecondaryParticleRecord const& record); friend std::string (::to_str)(siren::dataclasses::SecondaryParticleRecord const & record); friend std::string (::to_repr)(siren::dataclasses::SecondaryParticleRecord const & record); friend std::string (::to_str)(siren::dataclasses::CrossSectionDistributionRecord const & record); @@ -220,9 +222,9 @@ class CrossSectionDistributionRecord { private: std::vector secondary_particles; public: - friend std::ostream& ::operator<<(std::ostream& os, CrossSectionDistributionRecord const& record); - friend std::string (::to_str)(CrossSectionDistributionRecord const & record); - friend std::string (::to_repr)(CrossSectionDistributionRecord const & record); + friend std::ostream& ::operator<<(std::ostream& os, siren::dataclasses::CrossSectionDistributionRecord const& record); + friend std::string (::to_str)(siren::dataclasses::CrossSectionDistributionRecord const & record); + friend std::string (::to_repr)(siren::dataclasses::CrossSectionDistributionRecord const & record); CrossSectionDistributionRecord(CrossSectionDistributionRecord const & other) = delete; CrossSectionDistributionRecord(CrossSectionDistributionRecord && other) = default; @@ -282,9 +284,9 @@ class InteractionRecord { bool operator==(InteractionRecord const & other) const; bool operator<(InteractionRecord const & other) const; - friend std::ostream& ::operator<<(std::ostream& os, InteractionRecord const& record); - friend std::string (::to_str)(InteractionRecord const & record); - friend std::string (::to_repr)(InteractionRecord const & record); + friend std::ostream& ::operator<<(std::ostream& os, siren::dataclasses::InteractionRecord const& record); + friend std::string (::to_str)(siren::dataclasses::InteractionRecord const & record); + friend std::string (::to_repr)(siren::dataclasses::InteractionRecord const & record); template void save(Archive & archive, std::uint32_t const version) const { From 4c298f1abdef660cbc977db4fe89ce312d46d9e6 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sat, 14 Sep 2024 11:42:39 -0600 Subject: [PATCH 61/94] __str__ and __repr__ for PrimaryDistributionRecord --- .../dataclasses/private/InteractionRecord.cxx | 148 ++++++++++-------- .../private/pybindings/dataclasses.cxx | 2 + 2 files changed, 89 insertions(+), 61 deletions(-) diff --git a/projects/dataclasses/private/InteractionRecord.cxx b/projects/dataclasses/private/InteractionRecord.cxx index c8ccef439..bb0b6aab6 100644 --- a/projects/dataclasses/private/InteractionRecord.cxx +++ b/projects/dataclasses/private/InteractionRecord.cxx @@ -853,80 +853,106 @@ bool InteractionRecord::operator<(InteractionRecord const & other) const { } // namespace siren std::ostream & operator<<(std::ostream & os, siren::dataclasses::PrimaryDistributionRecord const & record) { + os << to_repr(record); + return os; +} + +std::string to_str(siren::dataclasses::PrimaryDistributionRecord const & record) { + using siren::utilities::tab; std::stringstream ss; - ss << "PrimaryDistributionRecord (" << &record << ") "; - os << ss.str() << '\n'; + ss << "[ PrimaryDistributionRecord (" << &record << ")\n"; - ss.str(std::string()); - std::string id_str; - ss << record.GetID(); - id_str = ss.str(); - std::string from = "\n"; - std::string to = "\n "; - size_t start_pos = 0; - while((start_pos = id_str.find(from, start_pos)) != std::string::npos) { - id_str.replace(start_pos, from.length(), to); - start_pos += to.length(); // Handles case where 'to' is a substring of 'from' - } - os << "ID: " << id_str << "\n"; + ss << tab << "ID: " << to_repr(record.id) << "\n"; + ss << tab << "Type: " << record.type << "\n"; - os << "Type: " << record.GetType() << "\n"; + ss << tab << "Mass: "; + if(record.mass_set) + ss << record.mass << '\n'; + else + ss << "unset\n"; - if(record.mass_set) { - os << "Mass: " << record.GetMass() << "\n"; - } else { - os << "Mass: " << "None" << "\n"; - } + ss << tab << "Energy: "; + if(record.energy_set) + ss << record.energy << '\n'; + else + ss << "unset\n"; - if(record.energy_set) { - os << "Energy: " << record.GetEnergy() << "\n"; - } else { - os << "Energy: " << "None" << "\n"; - } + ss << tab << "KineticEnergy: "; + if(record.kinetic_energy_set) + ss << record.kinetic_energy << '\n'; + else + ss << "unset\n"; - if(record.kinetic_energy_set) { - os << "KineticEnergy: " << record.GetKineticEnergy() << "\n"; - } else { - os << "KineticEnergy: " << "None" << "\n"; - } + ss << tab << "Direction: "; + if(record.direction_set) + ss << record.direction.at(0) << " " << record.direction.at(1) << " " << record.direction.at(2) << '\n'; + else + ss << "unset\n"; - if(record.direction_set) { - os << "Direction: " << record.GetDirection().at(0) << " " << record.GetDirection().at(1) << " " << record.GetDirection().at(2) << "\n"; - } else { - os << "Direction: " << "None" << "\n"; - } + ss << tab << "Momentum: "; + if(record.momentum_set) + ss << record.momentum.at(0) << " " << record.momentum.at(1) << " " << record.momentum.at(2) << '\n'; + else + ss << "unset\n"; - if(record.momentum_set) { - os << "Momentum: " << record.GetThreeMomentum().at(0) << " " << record.GetThreeMomentum().at(1) << " " << record.GetThreeMomentum().at(2) << "\n"; - } else { - os << "Momentum: " << "None" << "\n"; - } + ss << tab << "Length: "; + if(record.length_set) + ss << record.length << '\n'; + else + ss << "unset\n"; - if(record.length_set) { - os << "Length: " << record.GetLength() << "\n"; - } else { - os << "Length: " << "None" << "\n"; - } + ss << tab << "InitialPosition: "; + if(record.initial_position_set) + ss << record.initial_position.at(0) << " " << record.initial_position.at(1) << " " << record.initial_position.at(2) << '\n'; + else + ss << "unset\n"; - if(record.initial_position_set) { - os << "InitialPosition: " << record.GetInitialPosition().at(0) << " " << record.GetInitialPosition().at(1) << " " << record.GetInitialPosition().at(2) << "\n"; - } else { - os << "InitialPosition: " << "None" << "\n"; - } + ss << tab << "InteractionVertex: "; + if(record.interaction_vertex_set) + ss << record.interaction_vertex.at(0) << " " << record.interaction_vertex.at(1) << " " << record.interaction_vertex.at(2) << '\n'; + else + ss << "unset\n"; - if(record.interaction_vertex_set) { - os << "InteractionVertex: " << record.GetInteractionVertex().at(0) << " " << record.GetInteractionVertex().at(1) << " " << record.GetInteractionVertex().at(2) << "\n"; - } else { - os << "InteractionVertex: " << "None" << "\n"; - } + ss << tab << "Helicity: "; + if(record.helicity_set) + ss << record.helicity << '\n'; + else + ss << "unset\n"; - if(record.helicity_set) { - os << "Helicity: " << record.GetHelicity() << "\n"; - } else { - os << "Helicity: " << "None" << "\n"; - } + ss << "]"; - return os; + return ss.str(); +} + +std::string to_repr(siren::dataclasses::PrimaryDistributionRecord const & record) { + std::stringstream ss; + ss << "PrimaryDistributionRecord("; + + ss << "id=" << to_repr(record.GetID()) << ", "; + ss << "type=" << record.GetType(); + + if(record.mass_set) + ss << ", mass=" << record.mass; + if(record.energy_set) + ss << ", energy=" << record.energy; + if(record.kinetic_energy_set) + ss << ", kinetic_energy=" << record.kinetic_energy; + if(record.direction_set) + ss << ", direction=(" << record.direction.at(0) << ", " << record.direction.at(1) << ", " << record.direction.at(2) << ")"; + if(record.momentum_set) + ss << ", momentum=(" << record.momentum.at(0) << ", " << record.momentum.at(1) << ", " << record.momentum.at(2) << ")"; + if(record.length_set) + ss << ", length=" << record.length; + if(record.initial_position_set) + ss << ", initial_position=(" << record.initial_position.at(0) << ", " << record.initial_position.at(1) << ", " << record.initial_position.at(2) << ")"; + if(record.interaction_vertex_set) + ss << ", interaction_vertex=(" << record.interaction_vertex.at(0) << ", " << record.interaction_vertex.at(1) << ", " << record.interaction_vertex.at(2) << ")"; + if(record.helicity_set) + ss << ", helicity=" << record.helicity; + + ss << ")"; + + return ss.str(); } std::ostream& operator<<(std::ostream& os, siren::dataclasses::CrossSectionDistributionRecord const& record) { diff --git a/projects/dataclasses/private/pybindings/dataclasses.cxx b/projects/dataclasses/private/pybindings/dataclasses.cxx index 7cf9e2990..81c2820b0 100644 --- a/projects/dataclasses/private/pybindings/dataclasses.cxx +++ b/projects/dataclasses/private/pybindings/dataclasses.cxx @@ -70,6 +70,8 @@ PYBIND11_MODULE(dataclasses, m) { py::class_>(m, "PrimaryDistributionRecord") .def(py::init()) + .def("__str__", [](PrimaryDistributionRecord const & pdr) { return to_str(pdr); }) + .def("__repr__", [](PrimaryDistributionRecord const & pdr) { return to_repr(pdr); }) .def_property_readonly("id", [](siren::dataclasses::PrimaryDistributionRecord const & pdr) {siren::dataclasses::ParticleID id = pdr.id; return id;}) .def_property_readonly("type", From aee543146a7f4ea6304a1d33f2336ce9d16642d5 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sat, 14 Sep 2024 11:57:57 -0600 Subject: [PATCH 62/94] __str__ and __repr__ for Particle --- .../dataclasses/private/InteractionRecord.cxx | 2 +- projects/dataclasses/private/Particle.cxx | 51 ++++++++++++------- .../private/pybindings/dataclasses.cxx | 3 +- .../public/SIREN/dataclasses/Particle.h | 4 ++ 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/projects/dataclasses/private/InteractionRecord.cxx b/projects/dataclasses/private/InteractionRecord.cxx index bb0b6aab6..4724e9be7 100644 --- a/projects/dataclasses/private/InteractionRecord.cxx +++ b/projects/dataclasses/private/InteractionRecord.cxx @@ -860,7 +860,7 @@ std::ostream & operator<<(std::ostream & os, siren::dataclasses::PrimaryDistribu std::string to_str(siren::dataclasses::PrimaryDistributionRecord const & record) { using siren::utilities::tab; std::stringstream ss; - ss << "[ PrimaryDistributionRecord (" << &record << ")\n"; + ss << "[ PrimaryDistributionRecord (" << &record << "):\n"; ss << tab << "ID: " << to_repr(record.id) << "\n"; ss << tab << "Type: " << record.type << "\n"; diff --git a/projects/dataclasses/private/Particle.cxx b/projects/dataclasses/private/Particle.cxx index 60154e49d..e970ccb84 100644 --- a/projects/dataclasses/private/Particle.cxx +++ b/projects/dataclasses/private/Particle.cxx @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -11,30 +12,42 @@ #include #include "SIREN/utilities/Constants.h" +#include "SIREN/utilities/StringManipulation.h" std::ostream& operator<<(std::ostream& os, siren::dataclasses::Particle const& p) { - os << "Particle (" << &p << ")\n"; + os << to_repr(p); + return os; +} +std::string to_str(siren::dataclasses::Particle const& p) { + using siren::utilities::tab; std::stringstream ss; - ss << p.id; - std::string id_str = ss.str(); - std::string from = "\n"; - std::string to = "\n "; - size_t start_pos = 0; - while((start_pos = id_str.find(from, start_pos)) != std::string::npos) { - id_str.replace(start_pos, from.length(), to); - start_pos += to.length(); // Handles case where 'to' is a substring of 'from' - } - - os << "ID: " << id_str << "\n"; - os << "Type: " << p.type << "\n"; - os << "Mass: " << p.mass << "\n"; - os << "Momentum: " << p.momentum.at(0) << " " << p.momentum.at(1) << " " << p.momentum.at(2) << " " << p.momentum.at(3) << "\n"; - os << "Position: " << p.position.at(0) << " " << p.position.at(1) << " " << p.position.at(2) << "\n"; - os << "Length: " << p.length << "\n"; - os << "Helicity: " << p.helicity; + ss << "[ Particle (" << &p << "):\n"; + ss << tab << "ID: " << to_repr(p.id) << '\n'; + ss << tab << "Type: " << p.type << '\n'; + ss << tab << "Mass: " << p.mass << '\n'; + ss << tab << "Momentum: " << p.momentum.at(0) << ' ' << p.momentum.at(1) << ' ' << p.momentum.at(2) << ' ' << p.momentum.at(3) << '\n'; + ss << tab << "Position: " << p.position.at(0) << ' ' << p.position.at(1) << ' ' << p.position.at(2) << '\n'; + ss << tab << "Length: " << p.length << '\n'; + ss << tab << "Helicity: " << p.helicity << '\n'; + ss << ']'; + + return ss.str(); +} - return os; +std::string to_repr(siren::dataclasses::Particle const& p) { + std::stringstream ss; + ss << "Particle("; + ss << "id=" << to_repr(p.id) << ", "; + ss << "type=" << p.type << ", "; + ss << "mass=" << p.mass << ", "; + ss << "momentum=(" << p.momentum.at(0) << ", " << p.momentum.at(1) << ", " << p.momentum.at(2) << ", " << p.momentum.at(3) << "), "; + ss << "position=(" << p.position.at(0) << ", " << p.position.at(1) << ", " << p.position.at(2) << "), "; + ss << "length=" << p.length << ", "; + ss << "helicity=" << p.helicity; + ss << ')'; + + return ss.str(); } namespace siren { diff --git a/projects/dataclasses/private/pybindings/dataclasses.cxx b/projects/dataclasses/private/pybindings/dataclasses.cxx index 81c2820b0..ec1196e69 100644 --- a/projects/dataclasses/private/pybindings/dataclasses.cxx +++ b/projects/dataclasses/private/pybindings/dataclasses.cxx @@ -42,7 +42,8 @@ PYBIND11_MODULE(dataclasses, m) { .def(py::init()) .def(py::init, std::array, double, double>()) .def(py::init, std::array, double, double>()) - .def("__str__", [](Particle const & p) { std::stringstream ss; ss << p; return ss.str(); }) + .def("__str__", [](Particle const & p) { return to_str(p); }) + .def("__repr__", [](Particle const & p) { return to_repr(p); }) .def_readwrite("id",&Particle::id) .def_readwrite("type",&Particle::type) .def_readwrite("mass",&Particle::mass) diff --git a/projects/dataclasses/public/SIREN/dataclasses/Particle.h b/projects/dataclasses/public/SIREN/dataclasses/Particle.h index 94a61693f..6373a730d 100644 --- a/projects/dataclasses/public/SIREN/dataclasses/Particle.h +++ b/projects/dataclasses/public/SIREN/dataclasses/Particle.h @@ -27,6 +27,8 @@ namespace siren { namespace dataclasses { class Particle; } } std::ostream & operator<<(std::ostream & os, siren::dataclasses::Particle const & p); +std::string to_str(siren::dataclasses::Particle const & p); +std::string to_repr(siren::dataclasses::Particle const & p); namespace siren { namespace dataclasses { @@ -52,6 +54,8 @@ class Particle { ParticleID & GenerateID(); friend std::ostream & ::operator<<(std::ostream & os, siren::dataclasses::Particle const & p); + friend std::string (::to_str)(siren::dataclasses::Particle const & p); + friend std::string (::to_repr)(siren::dataclasses::Particle const & p); template void serialize(Archive & archive, std::uint32_t const version) { From a597bcb1280e7718610b499707cca708af8586ce Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sun, 15 Sep 2024 14:53:34 -0600 Subject: [PATCH 63/94] Move detector files --- .../detectors/CCM/{densities_CCM-v2.dat => CCM-v2/densities.dat} | 0 .../detectors/CCM/{materials_CCM-v2.dat => CCM-v2/materials.dat} | 0 .../ND280UPGRD/ND280UPGRD-v1/densities.dat} | 0 .../ND280UPGRD/ND280UPGRD-v1/materials.dat} | 0 resources/{Detectors => detectors}/visuals/Det_Visual_Examples.nb | 0 resources/{Detectors => detectors}/visuals/DetectorVisuals.wl | 0 resources/{Detectors => detectors}/visuals/README.md | 0 .../{Fluxes => fluxes}/T2K_NEAR/T2K_NEAR-v1.0/FluxCalculator.py | 0 .../{Fluxes => fluxes}/T2K_NEAR/T2K_NEAR-v1.0/T2KOUT_PLUS_nue.dat | 0 .../T2K_NEAR/T2K_NEAR-v1.0/T2KOUT_PLUS_numu.dat | 0 .../{Fluxes => fluxes}/T2K_NEAR/T2K_NEAR-v1.0/T2K_MINUS_250kA.dat | 0 .../{Fluxes => fluxes}/T2K_NEAR/T2K_NEAR-v1.0/T2K_PLUS_250kA.dat | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename resources/detectors/CCM/{densities_CCM-v2.dat => CCM-v2/densities.dat} (100%) rename resources/detectors/CCM/{materials_CCM-v2.dat => CCM-v2/materials.dat} (100%) rename resources/{Detectors/ND280UPGRD/densities_ND280UPGRD-v1.dat => detectors/ND280UPGRD/ND280UPGRD-v1/densities.dat} (100%) rename resources/{Detectors/ND280UPGRD/materials_ND280UPGRD-v1.dat => detectors/ND280UPGRD/ND280UPGRD-v1/materials.dat} (100%) rename resources/{Detectors => detectors}/visuals/Det_Visual_Examples.nb (100%) rename resources/{Detectors => detectors}/visuals/DetectorVisuals.wl (100%) rename resources/{Detectors => detectors}/visuals/README.md (100%) rename resources/{Fluxes => fluxes}/T2K_NEAR/T2K_NEAR-v1.0/FluxCalculator.py (100%) rename resources/{Fluxes => fluxes}/T2K_NEAR/T2K_NEAR-v1.0/T2KOUT_PLUS_nue.dat (100%) rename resources/{Fluxes => fluxes}/T2K_NEAR/T2K_NEAR-v1.0/T2KOUT_PLUS_numu.dat (100%) rename resources/{Fluxes => fluxes}/T2K_NEAR/T2K_NEAR-v1.0/T2K_MINUS_250kA.dat (100%) rename resources/{Fluxes => fluxes}/T2K_NEAR/T2K_NEAR-v1.0/T2K_PLUS_250kA.dat (100%) diff --git a/resources/detectors/CCM/densities_CCM-v2.dat b/resources/detectors/CCM/CCM-v2/densities.dat similarity index 100% rename from resources/detectors/CCM/densities_CCM-v2.dat rename to resources/detectors/CCM/CCM-v2/densities.dat diff --git a/resources/detectors/CCM/materials_CCM-v2.dat b/resources/detectors/CCM/CCM-v2/materials.dat similarity index 100% rename from resources/detectors/CCM/materials_CCM-v2.dat rename to resources/detectors/CCM/CCM-v2/materials.dat diff --git a/resources/Detectors/ND280UPGRD/densities_ND280UPGRD-v1.dat b/resources/detectors/ND280UPGRD/ND280UPGRD-v1/densities.dat similarity index 100% rename from resources/Detectors/ND280UPGRD/densities_ND280UPGRD-v1.dat rename to resources/detectors/ND280UPGRD/ND280UPGRD-v1/densities.dat diff --git a/resources/Detectors/ND280UPGRD/materials_ND280UPGRD-v1.dat b/resources/detectors/ND280UPGRD/ND280UPGRD-v1/materials.dat similarity index 100% rename from resources/Detectors/ND280UPGRD/materials_ND280UPGRD-v1.dat rename to resources/detectors/ND280UPGRD/ND280UPGRD-v1/materials.dat diff --git a/resources/Detectors/visuals/Det_Visual_Examples.nb b/resources/detectors/visuals/Det_Visual_Examples.nb similarity index 100% rename from resources/Detectors/visuals/Det_Visual_Examples.nb rename to resources/detectors/visuals/Det_Visual_Examples.nb diff --git a/resources/Detectors/visuals/DetectorVisuals.wl b/resources/detectors/visuals/DetectorVisuals.wl similarity index 100% rename from resources/Detectors/visuals/DetectorVisuals.wl rename to resources/detectors/visuals/DetectorVisuals.wl diff --git a/resources/Detectors/visuals/README.md b/resources/detectors/visuals/README.md similarity index 100% rename from resources/Detectors/visuals/README.md rename to resources/detectors/visuals/README.md diff --git a/resources/Fluxes/T2K_NEAR/T2K_NEAR-v1.0/FluxCalculator.py b/resources/fluxes/T2K_NEAR/T2K_NEAR-v1.0/FluxCalculator.py similarity index 100% rename from resources/Fluxes/T2K_NEAR/T2K_NEAR-v1.0/FluxCalculator.py rename to resources/fluxes/T2K_NEAR/T2K_NEAR-v1.0/FluxCalculator.py diff --git a/resources/Fluxes/T2K_NEAR/T2K_NEAR-v1.0/T2KOUT_PLUS_nue.dat b/resources/fluxes/T2K_NEAR/T2K_NEAR-v1.0/T2KOUT_PLUS_nue.dat similarity index 100% rename from resources/Fluxes/T2K_NEAR/T2K_NEAR-v1.0/T2KOUT_PLUS_nue.dat rename to resources/fluxes/T2K_NEAR/T2K_NEAR-v1.0/T2KOUT_PLUS_nue.dat diff --git a/resources/Fluxes/T2K_NEAR/T2K_NEAR-v1.0/T2KOUT_PLUS_numu.dat b/resources/fluxes/T2K_NEAR/T2K_NEAR-v1.0/T2KOUT_PLUS_numu.dat similarity index 100% rename from resources/Fluxes/T2K_NEAR/T2K_NEAR-v1.0/T2KOUT_PLUS_numu.dat rename to resources/fluxes/T2K_NEAR/T2K_NEAR-v1.0/T2KOUT_PLUS_numu.dat diff --git a/resources/Fluxes/T2K_NEAR/T2K_NEAR-v1.0/T2K_MINUS_250kA.dat b/resources/fluxes/T2K_NEAR/T2K_NEAR-v1.0/T2K_MINUS_250kA.dat similarity index 100% rename from resources/Fluxes/T2K_NEAR/T2K_NEAR-v1.0/T2K_MINUS_250kA.dat rename to resources/fluxes/T2K_NEAR/T2K_NEAR-v1.0/T2K_MINUS_250kA.dat diff --git a/resources/Fluxes/T2K_NEAR/T2K_NEAR-v1.0/T2K_PLUS_250kA.dat b/resources/fluxes/T2K_NEAR/T2K_NEAR-v1.0/T2K_PLUS_250kA.dat similarity index 100% rename from resources/Fluxes/T2K_NEAR/T2K_NEAR-v1.0/T2K_PLUS_250kA.dat rename to resources/fluxes/T2K_NEAR/T2K_NEAR-v1.0/T2K_PLUS_250kA.dat From 4cc6e93dee1fd44e4dbe5368590c0238eb6a9c84 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sun, 15 Sep 2024 15:19:22 -0600 Subject: [PATCH 64/94] Fix paths in visualization to match updated directory structure --- .../detectors/visuals/Det_Visual_Examples.nb | 575 +++++++----------- .../detectors/visuals/DetectorVisuals.wl | 6 +- resources/detectors/visuals/README.md | 8 +- 3 files changed, 224 insertions(+), 365 deletions(-) diff --git a/resources/detectors/visuals/Det_Visual_Examples.nb b/resources/detectors/visuals/Det_Visual_Examples.nb index 6710d4051..f4b823f38 100644 --- a/resources/detectors/visuals/Det_Visual_Examples.nb +++ b/resources/detectors/visuals/Det_Visual_Examples.nb @@ -10,10 +10,10 @@ NotebookFileLineBreakTest NotebookFileLineBreakTest NotebookDataPosition[ 158, 7] -NotebookDataLength[ 41346, 848] -NotebookOptionsPosition[ 38267, 784] -NotebookOutlinePosition[ 38662, 800] -CellTagsIndexPosition[ 38619, 797] +NotebookDataLength[ 32117, 707] +NotebookOptionsPosition[ 29036, 643] +NotebookOutlinePosition[ 29434, 659] +CellTagsIndexPosition[ 29391, 656] WindowFrame->Normal*) (* Beginning of Notebook Content *) @@ -58,14 +58,14 @@ Cell[BoxData[ CellChangeTimes->{{3.930845768512031*^9, 3.930845780337503*^9}, { 3.93084581693408*^9, 3.930845853905582*^9}, {3.93091362763332*^9, 3.9309136464460287`*^9}}, - CellLabel->"In[2]:=",ExpressionUUID->"01061750-99ce-4ee2-ba52-6ccdbfbf6f3b"], + CellLabel->"In[1]:=",ExpressionUUID->"01061750-99ce-4ee2-ba52-6ccdbfbf6f3b"], Cell[BoxData[ RowBox[{"<<", "DetectorVisuals`"}]], "Input", CellChangeTimes->{{3.930845856938705*^9, 3.930845892210829*^9}, { 3.9308460624868727`*^9, 3.930846074171977*^9}, {3.9309136516632137`*^9, 3.930913666071559*^9}}, - CellLabel->"In[35]:=",ExpressionUUID->"a6dc3d65-b39c-4f5d-8e40-9ac1c63e10c6"] + CellLabel->"In[2]:=",ExpressionUUID->"a6dc3d65-b39c-4f5d-8e40-9ac1c63e10c6"] }, Open ]], Cell[CellGroupData[{ @@ -87,104 +87,72 @@ Cell[CellGroupData[{ Cell[BoxData[ RowBox[{"Visuals", "[", - RowBox[{"\"\\"", ",", + RowBox[{"\"\\"", ",", "\"\\"", ",", RowBox[{"{", RowBox[{"\"\\"", ",", "\"\\""}], "}"}]}], "]"}]], "Input", CellChangeTimes->{{3.9308461111501207`*^9, 3.930846132819652*^9}, { 3.9308462468135443`*^9, 3.930846247147883*^9}, {3.930846995520549*^9, - 3.9308470458198357`*^9}}, - CellLabel->"In[4]:=",ExpressionUUID->"758f5770-9701-4c2e-9c28-f1655b0a6965"], + 3.9308470458198357`*^9}, {3.935423845589867*^9, 3.935423846508115*^9}}, + CellLabel->"In[3]:=",ExpressionUUID->"758f5770-9701-4c2e-9c28-f1655b0a6965"], Cell[BoxData[ Graphics3DBox[{ - {RGBColor[0.35093217511999275`, 0.3525201340616513, 0.8276327252716125], - Opacity[0.1], CuboidBox[{-2.8, -3.05, -3.8}, {2.8, 3.05, 3.8}]}, - {RGBColor[0.8477780541436477, 0.3160906000834609, 0.219018325039134], - Opacity[0.1], CuboidBox[{-1.75, -2., -3.8}, {1.75, 2., 3.8}]}, - {RGBColor[0.22330177948027363`, 0.31121718977849944`, 0.08734595030416648], - Opacity[0.1], CuboidBox[{-1.75, -2., -3.7}, {1.75, 2., 3.7}]}, - {RGBColor[0.8477780541436477, 0.3160906000834609, 0.219018325039134], - Opacity[0.1], CuboidBox[{-1.75, -1.8, -3.5}, {1.75, 1.8, 3.5}]}, - {RGBColor[0.5014698837210463, 0.8279721286735073, 0.25805733064978975`], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{-2.8, -3.05, -3.8}, {2.8, 3.05, 3.8}]}, + {Opacity[0.1], CuboidBox[{-1.75, -2., -3.8}, {1.75, 2., 3.8}]}, + {Opacity[0.1], CuboidBox[{-1.75, -2., -3.7}, {1.75, 2., 3.7}]}, + {Opacity[0.1], CuboidBox[{-1.75, -1.8, -3.5}, {1.75, 1.8, 3.5}]}, + {Opacity[0.1], CuboidBox[{-0.8975, 0.34249999999999997`, -3.205}, {0.8975, 1.1375, -1.205}]}, - {RGBColor[0.6907727880028507, 0.11798104164182699`, 0.5416072831768857], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{-0.85, 0.39, -3.205}, {0.85, 1.0899999999999999`, -1.205}]}, - {RGBColor[0.5014698837210463, 0.8279721286735073, 0.25805733064978975`], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{-0.8975, -1.1375, -3.205}, { 0.8975, -0.34249999999999997`, -1.205}]}, - {RGBColor[0.6907727880028507, 0.11798104164182699`, 0.5416072831768857], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{-0.85, -1.0899999999999999`, -3.205}, { 0.85, -0.39, -1.205}]}, - {RGBColor[0.20715118379631448`, 0.30858200457649687`, 0.3717365440678644], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{-1.009, -0.32, -3.214}, {1.009, 0.32, -1.1960000000000002`}]}, - {RGBColor[0.20715118379631448`, 0.30858200457649687`, 0.3717365440678644], - Opacity[0.1], CuboidBox[{-0.96, -0.28, -3.165}, {0.96, 0.28, -1.245}]}, - {RGBColor[0.25586105262190606`, 0.2633788353773121, 0.2901412060568902], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{-0.96, -0.28, -3.165}, {0.96, 0.28, -1.245}]}, + {Opacity[0.1], CuboidBox[{-1.15, 1.1600000000000001`, -3.355}, {1.15, 1.17, -1.0550000000000002`}]}, - {RGBColor[0.25586105262190606`, 0.2633788353773121, 0.2901412060568902], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{-1.15, -1.17, -3.355}, { 1.15, -1.1600000000000001`, -1.0550000000000002`}]}, - {RGBColor[0.25586105262190606`, 0.2633788353773121, 0.2901412060568902], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{1.1900000000000002`, -1.15, -3.355}, {1.2, 1.15, -1.0550000000000002`}]}, - {RGBColor[0.25586105262190606`, 0.2633788353773121, 0.2901412060568902], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{-1.2, -1.15, -3.355}, {-1.1900000000000002`, 1.15, -1.0550000000000002`}]}, - {RGBColor[0.25586105262190606`, 0.2633788353773121, 0.2901412060568902], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{-1.15, -1.15, -3.2649999999999997`}, {1.15, 1.15, -3.255}]}, - {RGBColor[0.25586105262190606`, 0.2633788353773121, 0.2901412060568902], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{-1.15, -1.15, -1.1749999999999998`}, {1.15, 1.15, -1.165}]}, - {RGBColor[0.7458525322351903, 0.7847146789223423, 0.9181634201906055], - Opacity[0.1], CuboidBox[{-1.25, -1.25, -0.875}, {1.25, 1.25, 0.125}]}, - {RGBColor[0.6907727880028507, 0.11798104164182699`, 0.5416072831768857], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{-1.25, -1.25, -0.875}, {1.25, 1.25, 0.125}]}, + {Opacity[0.1], CuboidBox[{-1.235, -1.235, -0.86}, {1.235, 1.235, 0.10999999999999999`}]}, - {RGBColor[0.7458525322351903, 0.7847146789223423, 0.9181634201906055], - Opacity[0.1], CuboidBox[{-1.25, -1.25, 0.49}, {1.25, 1.25, 1.49}]}, - {RGBColor[0.6907727880028507, 0.11798104164182699`, 0.5416072831768857], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{-1.25, -1.25, 0.49}, {1.25, 1.25, 1.49}]}, + {Opacity[0.1], CuboidBox[{-1.235, -1.235, 0.505}, {1.235, 1.235, 1.475}]}, - {RGBColor[0.7458525322351903, 0.7847146789223423, 0.9181634201906055], - Opacity[0.1], CuboidBox[{-1.25, -1.25, 1.855}, {1.25, 1.25, 2.855}]}, - {RGBColor[0.6907727880028507, 0.11798104164182699`, 0.5416072831768857], - Opacity[0.1], CuboidBox[{-1.235, -1.235, 1.87}, {1.235, 1.235, 2.84}]}, - {RGBColor[0.20715118379631448`, 0.30858200457649687`, 0.3717365440678644], - Opacity[0.1], CuboidBox[{-1.02, -1.02, -3.75}, {1.02, 1.02, -3.25}]}, - {RGBColor[0.20715118379631448`, 0.30858200457649687`, 0.3717365440678644], - Opacity[0.1], CuboidBox[{-1.02, -1.02, 3.}, {1.02, 1.02, 3.5}]}, - {RGBColor[0.20715118379631448`, 0.30858200457649687`, 0.3717365440678644], - Opacity[0.1], CuboidBox[{1.25, -1.18, -0.875}, {1.75, 1.18, 2.965}]}, - {RGBColor[0.20715118379631448`, 0.30858200457649687`, 0.3717365440678644], - Opacity[0.1], CuboidBox[{-1.75, -1.18, -0.875}, {-1.25, 1.18, 2.965}]}, - {RGBColor[0.20715118379631448`, 0.30858200457649687`, 0.3717365440678644], - Opacity[0.1], CuboidBox[{-0.76, 1.25, -0.875}, {0.76, 1.75, 2.965}]}, - {RGBColor[0.20715118379631448`, 0.30858200457649687`, 0.3717365440678644], - Opacity[0.1], CuboidBox[{-0.76, -1.75, -0.875}, {0.76, -1.25, 2.965}]}, - {RGBColor[0.7212050307872955, 0.3081619831157636, 0.9100551807755652], - Opacity[0.1], CuboidBox[{-1.15, -1.2, 0.125}, {1.15, 1.2, 0.49}]}, - {RGBColor[0.20715118379631448`, 0.30858200457649687`, 0.3717365440678644], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{-1.25, -1.25, 1.855}, {1.25, 1.25, 2.855}]}, + {Opacity[0.1], CuboidBox[{-1.235, -1.235, 1.87}, {1.235, 1.235, 2.84}]}, + {Opacity[0.1], CuboidBox[{-1.02, -1.02, -3.75}, {1.02, 1.02, -3.25}]}, + {Opacity[0.1], CuboidBox[{-1.02, -1.02, 3.}, {1.02, 1.02, 3.5}]}, + {Opacity[0.1], CuboidBox[{1.25, -1.18, -0.875}, {1.75, 1.18, 2.965}]}, + {Opacity[0.1], CuboidBox[{-1.75, -1.18, -0.875}, {-1.25, 1.18, 2.965}]}, + {Opacity[0.1], CuboidBox[{-0.76, 1.25, -0.875}, {0.76, 1.75, 2.965}]}, + {Opacity[0.1], CuboidBox[{-0.76, -1.75, -0.875}, {0.76, -1.25, 2.965}]}, + {Opacity[0.1], CuboidBox[{-1.15, -1.2, 0.125}, {1.15, 1.2, 0.49}]}, + {Opacity[0.1], CuboidBox[{-0.9215, -0.9215, 0.1635}, {0.9215, 0.9215, 0.4515}]}, - {RGBColor[0.7212050307872955, 0.3081619831157636, 0.9100551807755652], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{-1.15, -1.2, 1.4900000000000002`}, {1.15, 1.2, 1.855}]}, - {RGBColor[0.20715118379631448`, 0.30858200457649687`, 0.3717365440678644], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{-0.9215, -0.9215, 1.564}, {0.9215, 0.9215, 1.7810000000000001`}]}}, ImageSize->{326.05528778058215`, 276.80632953762915`}, @@ -201,133 +169,109 @@ Cell[BoxData[ 3.930995881446875*^9, 3.930995996055388*^9, 3.930996573196425*^9, 3.9309969008185797`*^9, 3.930997477608238*^9, 3.93100477589196*^9, 3.931005380832015*^9, {3.931005967116878*^9, 3.931005978085596*^9}, - 3.931008220329236*^9, 3.931008284734171*^9}, - CellLabel->"Out[4]=",ExpressionUUID->"8a3d7fe4-05dd-4061-b3db-44a8b527c5fa"] + 3.931008220329236*^9, 3.931008284734171*^9, {3.93542387743606*^9, + 3.93542389950345*^9}}, + CellLabel->"Out[3]=",ExpressionUUID->"5609e820-8728-41eb-804e-82e36e1de646"] }, Open ]], Cell[CellGroupData[{ Cell[BoxData[ RowBox[{"Visuals", "[", - RowBox[{"\"\\"", ",", + RowBox[{"\"\\"", ",", "\"\\"", ",", RowBox[{"{", RowBox[{"\"\\"", ",", "\"\\""}], "}"}]}], "]"}]], "Input", CellChangeTimes->{{3.9308464581373568`*^9, 3.9308464652613783`*^9}, { - 3.930847248876378*^9, 3.9308472858524933`*^9}}, - CellLabel->"In[39]:=",ExpressionUUID->"85f2f25e-059b-47e1-b7b7-1cd9a7fb936b"], + 3.930847248876378*^9, 3.9308472858524933`*^9}, {3.935423851296529*^9, + 3.9354238540901823`*^9}}, + CellLabel->"In[4]:=",ExpressionUUID->"85f2f25e-059b-47e1-b7b7-1cd9a7fb936b"], Cell[BoxData[ Graphics3DBox[{ - {RGBColor[0.41718218051431455`, 0.6517933847257689, 0.5388337863559993], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{5.0001999999999995`, -2.9465, -2.}, {11.1978, 2.9465, -1.3900000000000001`}]}, - {RGBColor[0.41718218051431455`, 0.6517933847257689, 0.5388337863559993], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{5., -0.9144, -1.3900000000000001`}, {5.660399999999999, 0.9144, 0.464}]}, - {RGBColor[0.41718218051431455`, 0.6517933847257689, 0.5388337863559993], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{5.6604, -0.9398, -1.3900000000000001`}, {6.574800000000001, 0.9398, 0.464}]}, - {RGBColor[0.32506606707200136`, 0.23990300858724734`, 0.486881531810764], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{6.5748, -0.9398, -1.3900000000000001`}, {6.7780000000000005`, 0.9398, 0.464}]}, - {RGBColor[0.41718218051431455`, 0.6517933847257689, 0.5388337863559993], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{6.778, -1.2446, -1.3900000000000001`}, {7.2352, 1.2446, 0.464}]}, - {RGBColor[0.521412842051586, 0.4962344456641059, 0.6541153328529785], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{7.2352, -1.8288, -1.3900000000000001`}, {7.3114, 1.8288, 0.464}]}, - {RGBColor[0.41718218051431455`, 0.6517933847257689, 0.5388337863559993], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{8.311399999999999, -1.8288, -1.3900000000000001`}, {8.7686, 1.8288, 0.464}]}, - {RGBColor[0.32506606707200136`, 0.23990300858724734`, 0.486881531810764], - Opacity[0.1], + {Opacity[0.1], CuboidBox[NCache[{18., Rational[-5, 2], -2.}, {18., -2.5, -2.}], NCache[{19., Rational[5, 2], 1.}, {19., 2.5, 1.}]]}, - {RGBColor[0.41718218051431455`, 0.6517933847257689, 0.5388337863559993], - Opacity[0.1], + {Opacity[0.1], CuboidBox[NCache[{19., Rational[-5, 2], -2.}, {19., -2.5, -2.}], NCache[{21., Rational[5, 2], 1.}, {21., 2.5, 1.}]]}, - {RGBColor[0.41718218051431455`, 0.6517933847257689, 0.5388337863559993], - Opacity[0.1], CuboidBox[{21., 4., -2.}, {25., 5., 1.}]}, - {RGBColor[0.41718218051431455`, 0.6517933847257689, 0.5388337863559993], - Opacity[0.1], CuboidBox[{21., -5., -2.}, {25., -4., 1.}]}, - {RGBColor[0.32506606707200136`, 0.23990300858724734`, 0.486881531810764], - Opacity[0.1], CylinderBox[{{0, 0, -2}, {0, 0, 2}}, 5]}, - {RGBColor[0.32506606707200136`, 0.23990300858724734`, 0.486881531810764], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{21., 4., -2.}, {25., 5., 1.}]}, + {Opacity[0.1], CuboidBox[{21., -5., -2.}, {25., -4., 1.}]}, + {Opacity[0.1], CylinderBox[{{0, 0, -2}, {0, 0, 2}}, 5]}, + {Opacity[0.1], CylinderBox[{{0, 0, -0.6299999999999999}, {0, 0, 1.}}, 0.83]}, - {RGBColor[0.0848019125038495, 0.8968379325252431, 0.05613755639699236], - Opacity[0.1], + {Opacity[0.1], CylinderBox[{{0, 0, -0.44999999999999996`}, {0, 0, 0.79}}, 0.55]}, - {RGBColor[0.7911505744190059, 0.18559734430518615`, 0.2453924328324959], - Opacity[0.1], CylinderBox[{{0, 0, -0.391}, {0, 0, -0.241}}, 0.3]}, - {RGBColor[0.7911505744190059, 0.18559734430518615`, 0.2453924328324959], - Opacity[0.1], + {Opacity[0.1], CylinderBox[{{0, 0, -0.391}, {0, 0, -0.241}}, 0.3]}, + {Opacity[0.1], CylinderBox[{{0, 0, -0.241}, {0, 0, -0.09100000000000001}}, 0.3]}, - {RGBColor[0.7911505744190059, 0.18559734430518615`, 0.2453924328324959], - Opacity[0.1], + {Opacity[0.1], CylinderBox[{{0, 0, 0.07999999999999999}, {0, 0, 0.5}}, 0.3]}, - {RGBColor[0.3351807133351079, 0.2763153120327406, 0.7227930518683081], - Opacity[0.1], + {Opacity[0.1], CylinderBox[{{0, 0, 0.09200000000000001}, {0, 0, 0.183}}, 0.05]}, - {RGBColor[0.3351807133351079, 0.2763153120327406, 0.7227930518683081], - Opacity[0.1], CylinderBox[{{0, 0, -0.39}, {0, 0, -0.092}}, 0.05]}, - {RGBColor[0.32506606707200136`, 0.23990300858724734`, 0.486881531810764], - Opacity[0.1], CylinderBox[{{23, 0, -1.96}, {23, 0, 0.66}}, 1.38]}, - {RGBColor[0.009276515470650892, 0.6652402538800535, 0.2557510553491851], - Opacity[0.1], + {Opacity[0.1], CylinderBox[{{0, 0, -0.39}, {0, 0, -0.092}}, 0.05]}, + {Opacity[0.1], CylinderBox[{{23, 0, -1.96}, {23, 0, 0.66}}, 1.38]}, + {Opacity[0.1], CylinderBox[{{23, 0, -1.9100000000000001`}, {23, 0, 0.61}}, 1.35]}, - {RGBColor[0.32506606707200136`, 0.23990300858724734`, 0.486881531810764], - Opacity[0.1], + {Opacity[0.1], CylinderBox[{{23, 0, -1.85}, {23, 0, 0.5499999999999999}}, 1.25]}, - {RGBColor[0.6493869773926908, 0.16552659229722266`, 0.1134446897889001], - Opacity[0.1], + {Opacity[0.1], CylinderBox[{{23, 0, -1.7999999999999998`}, {23, 0, 0.4999999999999999}}, 1.2]}, - {RGBColor[0.3086780992491793, 0.10261299404488455`, 0.5061987340813581], - Opacity[0.1], - CylinderBox[{{23, 0, -1.4}, {23, 0, 0.09999999999999998}}, 1.06]}, - {RGBColor[0.6493869773926908, 0.16552659229722266`, 0.1134446897889001], - Opacity[0.1], - CylinderBox[{{23, 0, -1.266}, {23, 0, -0.03400000000000003}}, - 0.96]}}]], "Output", + {Opacity[0.1], + CylinderBox[{{23, 0, -1.271305}, {23, 0, -0.028695000000000026`}}, + 1.130076]}, + {Opacity[0.1], + CylinderBox[{{23, 0, -1.2698}, {23, 0, -0.030200000000000005`}}, + 1.12776]}}]], "Output", CellChangeTimes->{ 3.930847286401828*^9, 3.9309138898128967`*^9, {3.930995702475547*^9, 3.9309957057441807`*^9}, 3.930996904682377*^9, 3.9309974796076202`*^9, 3.931005982557057*^9, 3.93100621941457*^9, 3.9310087892293873`*^9, 3.9310089841360407`*^9, 3.93100907290653*^9, 3.931009196389038*^9, - 3.9310093752491703`*^9}, - CellLabel->"Out[39]=",ExpressionUUID->"5a905629-0c22-4620-b59c-02655db9bf79"] + 3.9310093752491703`*^9, {3.935423877536092*^9, 3.935423899603882*^9}}, + CellLabel->"Out[4]=",ExpressionUUID->"22bf564d-0ceb-4fae-ab91-6dd16c0c0d80"] }, Open ]], Cell[CellGroupData[{ Cell[BoxData[ RowBox[{"Visuals", "[", - RowBox[{"\"\\"", ",", + RowBox[{"\"\\"", ",", "\"\\"", ",", RowBox[{"{", RowBox[{"\"\\"", ",", "\"\\""}], "}"}]}], "]"}]], "Input", CellChangeTimes->{{3.9309951152387*^9, 3.930995153174532*^9}, 3.930997063585266*^9, 3.931005817453622*^9, {3.9310092389209433`*^9, - 3.9310092757902718`*^9}, {3.9310093189732447`*^9, - 3.931009348185121*^9}},ExpressionUUID->"45186205-4e3c-43da-8cf6-\ -942bd6843b62"], + 3.9310092757902718`*^9}, {3.9310093189732447`*^9, 3.931009348185121*^9}, + 3.9354238524438887`*^9}, + CellLabel->"In[5]:=",ExpressionUUID->"45186205-4e3c-43da-8cf6-942bd6843b62"], Cell[BoxData[ Graphics3DBox[{ - {RGBColor[0.2298911743818579, 0.31209133471148953`, 0.7146612930358287], - Opacity[0.1], CuboidBox[{-1, -1, -1.0375}, {1, 1, -0.9625}]}, - {RGBColor[0.16452635096365742`, 0.23517942424424865`, 0.9345244778129824], - Opacity[0.1], + {Opacity[0.1], CuboidBox[{-1, -1, -1.0375}, {1, 1, -0.9625}]}, + {Opacity[0.1], PolyhedronBox[{{{0., 1.23553, -0.0027999999999996916`}, {1.07, 0.61776, -0.0027999999999996916`}, { 1.07, -0.61776, -0.0027999999999996916`}, { @@ -336,60 +280,51 @@ Cell[BoxData[ 1.23553, 4.1372}, {1.07, 0.61776, 4.1372}, {1.07, -0.61776, 4.1372}, { 0., -1.23553, 4.1372}, {-1.07, -0.61776, 4.1372}, {-1.07, 0.61776, 4.1372}}}]}, - {RGBColor[0.3275193083067711, 0.5033666810361557, 0.1674300296182314], - Opacity[0.1], + {Opacity[0.1], PolyhedronBox[{{{0., 1.06232, 0.}, {0.92, 0.53116, 0.}, {0.92, -0.53116, 0.}, {0., -1.06232, 0.}, {-0.92, -0.53116, 0.}, {-0.92, 0.53116, 0.}}, {{ 0., 1.06232, 4.1344}, {0.92, 0.53116, 4.1344}, {0.92, -0.53116, 4.1344}, {0., -1.06232, 4.1344}, {-0.92, -0.53116, 4.1344}, {-0.92, 0.53116, 4.1344}}}]}, - {RGBColor[0.2298911743818579, 0.31209133471148953`, 0.7146612930358287], - Opacity[0.1], + {Opacity[0.1], PolyhedronBox[{{{-0.2825, 0.8992, 0.136}, {0.6375, -0.6942, 0.136}, { 0., -1.06232, 0.136}, {-0.92, -0.53116, 0.136}, {-0.92, 0.53116, 0.136}}, {{-0.2825, 0.8992, 0.16167}, {0.6375, -0.6942, 0.16167}, { 0., -1.06232, 0.16167}, {-0.92, -0.53116, 0.16167}, {-0.92, 0.53116, 0.16167}}}]}, - {RGBColor[0.8775095682131331, 0.5860897175157826, 0.24202862693045568`], - Opacity[0.1], + {Opacity[0.1], PolyhedronBox[{{{0.6375, -0.6942, 0.136}, {-0.2825, 0.8992, 0.136}, {0., 1.06232, 0.136}, {0.92, 0.53116, 0.136}, {0.92, -0.53116, 0.136}}, {{ 0.6375, -0.6942, 0.16178}, {-0.2825, 0.8992, 0.16178}, {0., 1.06232, 0.16178}, {0.92, 0.53116, 0.16178}, {0.92, -0.53116, 0.16178}}}]}, - {RGBColor[0.2298911743818579, 0.31209133471148953`, 0.7146612930358287], - Opacity[0.1], + {Opacity[0.1], PolyhedronBox[{{{-0.6375, -0.6942, 0.313}, {0.2825, 0.8992, 0.313}, {0.92, 0.53116, 0.313}, {0.92, -0.53116, 0.313}, {0., -1.06232, 0.313}}, {{-0.6375, -0.6942, 0.33863}, {0.2825, 0.8992, 0.33863}, {0.92, 0.53116, 0.33863}, {0.92, -0.53116, 0.33863}, {0., -1.06232, 0.33863}}}]}, - {RGBColor[0.8775095682131331, 0.5860897175157826, 0.24202862693045568`], - Opacity[0.1], + {Opacity[0.1], PolyhedronBox[{{{0.2825, 0.8992, 0.313}, {-0.6375, -0.6942, 0.313}, {-0.92, -0.53116, 0.313}, {-0.92, 0.53116, 0.313}, {0., 1.06232, 0.313}}, {{0.2825, 0.8992, 0.33881}, {-0.6375, -0.6942, 0.33881}, {-0.92, -0.53116, 0.33881}, {-0.92, 0.53116, 0.33881}, {0., 1.06232, 0.33881}}}]}, - {RGBColor[0.2654164649210198, 0.39657426393543016`, 0.2847295993909016], - Opacity[0.1], + {Opacity[0.1], PolyhedronBox[{{{0., 1.06232, 0.534}, {0.92, 0.53116, 0.534}, {-0.92, -0.53116, 0.534}, {-0.92, 0.53116, 0.534}}, {{0., 1.06232, 0.6102000000000001}, {0.92, 0.53116, 0.6102000000000001}, {-0.92, -0.53116, 0.6102000000000001}, {-0.92, 0.53116, 0.6102000000000001}}}]}, - {RGBColor[0.2298911743818579, 0.31209133471148953`, 0.7146612930358287], - Opacity[0.1], + {Opacity[0.1], PolyhedronBox[{{{0., 0., 0.534}, {0.92, 0.53116, 0.534}, {0.92, -0.53116, 0.534}, {0., -1.06232, 0.534}}, {{0., 0., 0.5597300000000001}, {0.92, 0.53116, 0.5597300000000001}, {0.92, -0.53116, 0.5597300000000001}, { 0., -1.06232, 0.5597300000000001}}}]}, - {RGBColor[0.8775095682131331, 0.5860897175157826, 0.24202862693045568`], - Opacity[0.1], + {Opacity[0.1], PolyhedronBox[{{{0., 0., 0.534}, {0., -1.06232, 0.534}, {-0.92, -0.53116, 0.534}}, {{0., 0., 0.5596300000000001}, {0., -1.06232, 0.5596300000000001}, {-0.92, -0.53116, 0.5596300000000001}}}]}, - {RGBColor[0.8332620257988352, 0.5659513355920436, 0.30336281249235686`], - Opacity[0.1], + {Opacity[0.1], PolyhedronBox[{{{0., 1.06232, 0.895}, {0.92, 0.53116, 0.895}, { 0.92, -0.53116, 0.895}, {0., -1.06232, 0.895}, {-0.92, -0.53116, 0.895}, {-0.92, 0.53116, 0.895}}, {{0., 1.06232, 1.0756000000000001`}, { @@ -397,22 +332,19 @@ Cell[BoxData[ 1.0756000000000001`}, {0., -1.06232, 1.0756000000000001`}, {-0.92, -0.53116, 1.0756000000000001`}, {-0.92, 0.53116, 1.0756000000000001`}}}]}, - {RGBColor[0.8775095682131331, 0.5860897175157826, 0.24202862693045568`], - Opacity[0.1], + {Opacity[0.1], PolyhedronBox[{{{0., 1.06232, 1.256}, {0.92, 0.53116, 1.256}, { 0.92, -0.53116, 1.256}, {0., -1.06232, 1.256}, {-0.92, -0.53116, 1.256}, {-0.92, 0.53116, 1.256}}, {{0., 1.06232, 1.26395}, {0.92, 0.53116, 1.26395}, {0.92, -0.53116, 1.26395}, {0., -1.06232, 1.26395}, {-0.92, -0.53116, 1.26395}, {-0.92, 0.53116, 1.26395}}}]}, - {RGBColor[0.2298911743818579, 0.31209133471148953`, 0.7146612930358287], - Opacity[0.1], + {Opacity[0.1], PolyhedronBox[{{{-0.2825, 0.8992, 1.389}, {0.6375, -0.6942, 1.389}, { 0., -1.06232, 1.389}, {-0.92, -0.53116, 1.389}, {-0.92, 0.53116, 1.389}}, {{-0.2825, 0.8992, 1.40189}, {0.6375, -0.6942, 1.40189}, { 0., -1.06232, 1.40189}, {-0.92, -0.53116, 1.40189}, {-0.92, 0.53116, 1.40189}}}]}, - {RGBColor[0.8775095682131331, 0.5860897175157826, 0.24202862693045568`], - Opacity[0.1], + {Opacity[0.1], PolyhedronBox[{{{0.6375, -0.6942, 1.389}, {-0.2825, 0.8992, 1.389}, {0., 1.06232, 1.389}, {0.92, 0.53116, 1.389}, {0.92, -0.53116, 1.389}}, {{ 0.6375, -0.6942, 1.40217}, {-0.2825, 0.8992, 1.40217}, {0., 1.06232, @@ -434,33 +366,33 @@ Cell[BoxData[ 3.931008289070985*^9, {3.931008607676939*^9, 3.931008627241765*^9}, 3.931008698778192*^9, 3.93100874878646*^9, 3.931008989014098*^9, 3.93100908020753*^9, 3.9310091171045313`*^9, 3.931009199983571*^9, { - 3.931009253670957*^9, 3.931009276283464*^9}}, - CellLabel->"Out[38]=",ExpressionUUID->"7aa043b8-c09a-4a90-8f3b-914c780b39b6"] + 3.931009253670957*^9, 3.931009276283464*^9}, {3.935423877628962*^9, + 3.935423899702532*^9}}, + CellLabel->"Out[5]=",ExpressionUUID->"e0160564-d0ed-4637-bf6a-db4a523dd2d7"] }, Open ]], Cell[CellGroupData[{ Cell[BoxData[ RowBox[{"Visuals", "[", - RowBox[{"\"\\"", ",", + RowBox[{"\"\\"", ",", "\"\\"", ",", RowBox[{"{", "\"\\"", "}"}]}], "]"}]], "Input", - CellChangeTimes->{{3.9309213638291893`*^9, 3.930921408318699*^9}}, - CellLabel->"In[40]:=",ExpressionUUID->"623517c9-0b0a-43b7-941c-607589cb47ec"], + CellChangeTimes->{{3.9309213638291893`*^9, 3.930921408318699*^9}, + 3.9354238562198133`*^9}, + CellLabel->"In[6]:=",ExpressionUUID->"623517c9-0b0a-43b7-941c-607589cb47ec"], Cell[BoxData[ Graphics3DBox[{ - {RGBColor[0.9999669336121517, 0.957806585512984, 0.28830420784733946`], - Opacity[0.1], SphereBox[{0, 0, 0}, 9.1]}, - {RGBColor[0.3248443069364404, 0.6150261091426228, 0.006485477421444896], - Opacity[0.1], SphereBox[{0, 0, 0}, 6.1]}}]], "Output", + {Opacity[0.1], SphereBox[{0, 0, 0}, 9.1]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6.1]}}]], "Output", CellChangeTimes->{ 3.93092140928104*^9, 3.930995708508224*^9, 3.930995999878187*^9, 3.930996576802916*^9, 3.930996907051785*^9, 3.930997612674156*^9, 3.931005382662628*^9, {3.931008610552994*^9, 3.931008629581517*^9}, 3.9310086961250677`*^9, 3.931008747296633*^9, 3.931008986563098*^9, 3.9310090761618843`*^9, 3.931009114241016*^9, 3.93100919847633*^9, - 3.931009377767623*^9}, - CellLabel->"Out[40]=",ExpressionUUID->"928e908c-d246-44d0-8e3f-99106d65c374"] + 3.931009377767623*^9, {3.935423877714003*^9, 3.935423899792832*^9}}, + CellLabel->"Out[6]=",ExpressionUUID->"457c7840-21be-418e-b2d7-20c799d31837"] }, Open ]] }, Open ]], @@ -478,10 +410,10 @@ Cell[BoxData[ RowBox[{"{", RowBox[{ RowBox[{"Visuals", "[", - RowBox[{"\"\\"", ",", + RowBox[{"\"\\"", ",", "\"\\"", ",", RowBox[{"{", "}"}]}], "]"}], ",", "\[IndentingNewLine]", RowBox[{"Visuals", "[", - RowBox[{"\"\\"", ",", + RowBox[{"\"\\"", ",", "\"\\"", ",", RowBox[{"{", RowBox[{ "\"\\"", ",", "\"\\"", ",", @@ -492,56 +424,32 @@ Cell[BoxData[ "}"}]}], "]"}]}], "}"}], "]"}]], "Input", CellChangeTimes->{{3.9308473708407297`*^9, 3.9308473846505938`*^9}, { 3.9308474813020153`*^9, 3.930847490639382*^9}, {3.930847780142088*^9, - 3.93084785043423*^9}, {3.9308478814387417`*^9, 3.9308479120262003`*^9}}, + 3.93084785043423*^9}, {3.9308478814387417`*^9, 3.9308479120262003`*^9}, { + 3.935423858727695*^9, 3.935423860187827*^9}}, CellLabel->"In[7]:=",ExpressionUUID->"d7a1ae22-5013-434c-9f40-0ccdc86a3ce7"], Cell[BoxData[ GraphicsBox[{{}, {InsetBox[ Graphics3DBox[{ - {RGBColor[ - 0.33604086192392857`, 0.9653758014770579, 0.8082011998173695], - Opacity[0.1], SphereBox[{0, 0, 0}, 6478000]}, - {RGBColor[ - 0.7454100290394681, 0.7665909595605325, 0.16392086034407471`], - Opacity[0.1], SphereBox[{0, 0, 0}, 6371324]}, - {RGBColor[ - 0.7454100290394681, 0.7665909595605325, 0.16392086034407471`], - Opacity[0.1], SphereBox[{0, 0, 0}, 6356000]}, - {RGBColor[ - 0.17011058031535153`, 0.08842194355669797, 0.22208792588679205`], - Opacity[0.1], SphereBox[{0, 0, 0}, 6346600]}, - {RGBColor[ - 0.17011058031535153`, 0.08842194355669797, 0.22208792588679205`], - Opacity[0.1], SphereBox[{0, 0, 0}, 6151000]}, - {RGBColor[ - 0.17011058031535153`, 0.08842194355669797, 0.22208792588679205`], - Opacity[0.1], SphereBox[{0, 0, 0}, 5971000]}, - {RGBColor[ - 0.17011058031535153`, 0.08842194355669797, 0.22208792588679205`], - Opacity[0.1], SphereBox[{0, 0, 0}, 5771000]}, - {RGBColor[ - 0.17011058031535153`, 0.08842194355669797, 0.22208792588679205`], - Opacity[0.1], SphereBox[{0, 0, 0}, 5701000]}, - {RGBColor[0.7125743490533816, 0.6497192986538929, 0.3566876197914912], - Opacity[0.1], SphereBox[{0, 0, 0}, 3480000]}, - {RGBColor[0.805721607371412, 0.9209617322598633, 0.8867540239707707], - Opacity[0.1], SphereBox[{0, 0, 0}, 1221500]}, - {RGBColor[ - 0.33604086192392857`, 0.9653758014770579, 0.8082011998173695], - Opacity[0.1], CylinderBox[{{0, 0, 6371223}, {0, 0, 6371245}}, 11]}, - {RGBColor[ - 0.3987342262275555, 0.45800648525877863`, 0.0818749710267983], - Opacity[0.1], + {Opacity[0.1], SphereBox[{0, 0, 0}, 6478000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6371324]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6356000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6346600]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6151000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 5971000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 5771000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 5701000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 3480000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 1221500]}, + {Opacity[0.1], CylinderBox[{{0, 0, 6371223}, {0, 0, 6371245}}, 11]}, + {Opacity[0.1], CylinderBox[{{0, 0, 6.37122785*^6}, {0, 0, 6.37124015*^6}}, 3.82]}}], {192., -205.275}, ImageScaled[{0.5, 0.5}], {360, 391}, BaseStyle->{Graphics3DBoxOptions -> {SphericalRegion -> False}}, ContentSelectable->True], InsetBox[ Graphics3DBox[{ - {RGBColor[0.5589070573347059, 0.5978054217068245, 0.7989344230742892], - Opacity[0.1], CylinderBox[{{0, 0, 6371223}, {0, 0, 6371245}}, 11]}, - {RGBColor[ - 0.48018618880404773`, 0.0759986548288627, 0.5876392247182236], - Opacity[0.1], + {Opacity[0.1], CylinderBox[{{0, 0, 6371223}, {0, 0, 6371245}}, 11]}, + {Opacity[0.1], CylinderBox[{{0, 0, 6.37122785*^6}, {0, 0, 6.37124015*^6}}, 3.82]}}], {576., -205.275}, ImageScaled[{0.5, 0.5}], {360, 391}, BaseStyle->{Graphics3DBoxOptions -> {SphericalRegion -> False}}, @@ -552,8 +460,9 @@ Cell[BoxData[ PlotRangePadding->{6, 5}]], "Output", CellChangeTimes->{{3.930847372845573*^9, 3.930847385329747*^9}, 3.9308474913439817`*^9, 3.93084785162274*^9, {3.930847888148061*^9, - 3.9308479131871243`*^9}, 3.930913893848425*^9}, - CellLabel->"Out[7]=",ExpressionUUID->"eb22797f-f400-4d3d-8fbd-b073c6b6fe6c"] + 3.9308479131871243`*^9}, 3.930913893848425*^9, {3.935423878748316*^9, + 3.9354239008174686`*^9}}, + CellLabel->"Out[7]=",ExpressionUUID->"2dbd9e98-8740-42be-9dc3-422765729334"] }, Open ]], Cell[CellGroupData[{ @@ -563,10 +472,10 @@ Cell[BoxData[ RowBox[{"{", RowBox[{ RowBox[{"Visuals", "[", - RowBox[{"\"\\"", ",", + RowBox[{"\"\\"", ",", "\"\\"", ",", RowBox[{"{", "}"}]}], "]"}], ",", "\[IndentingNewLine]", RowBox[{"Visuals", "[", - RowBox[{"\"\\"", ",", + RowBox[{"\"\\"", ",", "\"\\"", ",", RowBox[{"{", RowBox[{ "\"\\"", ",", "\"\\"", ",", @@ -575,43 +484,29 @@ Cell[BoxData[ "\"\\"", ",", "\"\\"", ",", "\"\\"", ",", "\"\\""}], "}"}]}], "]"}]}], "}"}], "]"}]], "Input", - CellChangeTimes->{{3.93084793508619*^9, 3.9308479993874903`*^9}}, + CellChangeTimes->{{3.93084793508619*^9, 3.9308479993874903`*^9}, { + 3.935423862154442*^9, 3.935423863098934*^9}}, CellLabel->"In[8]:=",ExpressionUUID->"c2600694-ff87-45e8-aa45-7e0762877b49"], Cell[BoxData[ GraphicsBox[{{}, {InsetBox[ Graphics3DBox[{ - {RGBColor[0.3854333319682095, 0.2892742647377069, 0.8094932070709475], - Opacity[0.1], CuboidBox[{-7, -29.1, 6369838}, {7, 29.1, 6369850}]}, - {RGBColor[0.4929121197143007, 0.8219087232339506, 0.05781061434027657], - Opacity[0.1], SphereBox[{0, 0, 0}, 6478000]}, - {RGBColor[ - 0.7307987869233605, 0.8513437211581723, 0.31005230536151496`], - Opacity[0.1], SphereBox[{0, 0, 0}, 6371324]}, - {RGBColor[ - 0.7307987869233605, 0.8513437211581723, 0.31005230536151496`], - Opacity[0.1], SphereBox[{0, 0, 0}, 6356000]}, - {RGBColor[0.1964479760083393, 0.8963638500949567, 0.5827067954797789], - Opacity[0.1], SphereBox[{0, 0, 0}, 6346600]}, - {RGBColor[0.1964479760083393, 0.8963638500949567, 0.5827067954797789], - Opacity[0.1], SphereBox[{0, 0, 0}, 6151000]}, - {RGBColor[0.1964479760083393, 0.8963638500949567, 0.5827067954797789], - Opacity[0.1], SphereBox[{0, 0, 0}, 5971000]}, - {RGBColor[0.1964479760083393, 0.8963638500949567, 0.5827067954797789], - Opacity[0.1], SphereBox[{0, 0, 0}, 5771000]}, - {RGBColor[0.1964479760083393, 0.8963638500949567, 0.5827067954797789], - Opacity[0.1], SphereBox[{0, 0, 0}, 5701000]}, - {RGBColor[ - 0.7506626862180743, 0.5253325729662548, 0.44264896991070013`], - Opacity[0.1], SphereBox[{0, 0, 0}, 3480000]}, - {RGBColor[0.786628620543359, 0.6894960380159745, 0.5808208645108668], - Opacity[0.1], SphereBox[{0, 0, 0}, 1221500]}}], {192., -205.275}, + {Opacity[0.1], CuboidBox[{-7, -29.1, 6369838}, {7, 29.1, 6369850}]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6478000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6371324]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6356000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6346600]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6151000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 5971000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 5771000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 5701000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 3480000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 1221500]}}], {192., -205.275}, ImageScaled[{0.5, 0.5}], {360, 391}, BaseStyle->{Graphics3DBoxOptions -> {SphericalRegion -> False}}, ContentSelectable->True], InsetBox[ Graphics3DBox[ - {RGBColor[0.7680744425973096, 0.829550618397942, 0.35629067827826955`], - Opacity[0.1], CuboidBox[{-7, -29.1, 6369838}, {7, 29.1, 6369850}]}], {576., -205.275}, + {Opacity[0.1], CuboidBox[{-7, -29.1, 6369838}, {7, 29.1, 6369850}]}], {576., -205.275}, ImageScaled[{0.5, 0.5}], {360, 391}, BaseStyle->{Graphics3DBoxOptions -> {SphericalRegion -> False}}, ContentSelectable->True]}, {}}, @@ -620,8 +515,9 @@ Cell[BoxData[ PlotRange->{{0, 768.}, {-410.55, 0}}, PlotRangePadding->{6, 5}]], "Output", CellChangeTimes->{{3.930847943143111*^9, 3.930847949745967*^9}, { - 3.930847986070044*^9, 3.930848000974144*^9}, 3.930913896769115*^9}, - CellLabel->"Out[8]=",ExpressionUUID->"f81cbe95-f330-439e-bb2a-5afd2a6189ed"] + 3.930847986070044*^9, 3.930848000974144*^9}, 3.930913896769115*^9, { + 3.935423879951643*^9, 3.935423902016954*^9}}, + CellLabel->"Out[8]=",ExpressionUUID->"2cf3f729-3dc6-4032-b2a2-e3db2c56bfd4"] }, Open ]], Cell[CellGroupData[{ @@ -631,10 +527,10 @@ Cell[BoxData[ RowBox[{"{", RowBox[{ RowBox[{"Visuals", "[", - RowBox[{"\"\\"", ",", + RowBox[{"\"\\"", ",", "\"\\"", ",", RowBox[{"{", "}"}]}], "]"}], ",", "\[IndentingNewLine]", RowBox[{"Visuals", "[", - RowBox[{"\"\\"", ",", + RowBox[{"\"\\"", ",", "\"\\"", ",", RowBox[{"{", RowBox[{ "\"\\"", ",", "\"\\"", ",", @@ -643,48 +539,30 @@ Cell[BoxData[ "\"\\"", ",", "\"\\"", ",", "\"\\"", ",", "\"\\""}], "}"}]}], "]"}]}], "}"}], "]"}]], "Input", - CellChangeTimes->{{3.930848012050405*^9, 3.930848018088457*^9}}, + CellChangeTimes->{{3.930848012050405*^9, 3.930848018088457*^9}, { + 3.935423864989311*^9, 3.935423865685445*^9}}, CellLabel->"In[9]:=",ExpressionUUID->"bed39234-fab0-4316-b468-3b5240c92626"], Cell[BoxData[ GraphicsBox[{{}, {InsetBox[ Graphics3DBox[{ - {RGBColor[ - 0.7265281738369762, 0.23654605801110473`, 0.4513669482600129], - Opacity[0.1], SphereBox[{0, 0, 0}, 6478000]}, - {RGBColor[0.8285668626756055, 0.6123076208047464, 0.3756755558784768], - Opacity[0.1], SphereBox[{0, 0, 0}, 6371324]}, - {RGBColor[0.8285668626756055, 0.6123076208047464, 0.3756755558784768], - Opacity[0.1], SphereBox[{0, 0, 0}, 6356000]}, - {RGBColor[ - 0.9161148893717073, 0.27921300626842793`, 0.6143387394926221], - Opacity[0.1], SphereBox[{0, 0, 0}, 6346600]}, - {RGBColor[ - 0.9161148893717073, 0.27921300626842793`, 0.6143387394926221], - Opacity[0.1], SphereBox[{0, 0, 0}, 6151000]}, - {RGBColor[ - 0.9161148893717073, 0.27921300626842793`, 0.6143387394926221], - Opacity[0.1], SphereBox[{0, 0, 0}, 5971000]}, - {RGBColor[ - 0.9161148893717073, 0.27921300626842793`, 0.6143387394926221], - Opacity[0.1], SphereBox[{0, 0, 0}, 5771000]}, - {RGBColor[ - 0.9161148893717073, 0.27921300626842793`, 0.6143387394926221], - Opacity[0.1], SphereBox[{0, 0, 0}, 5701000]}, - {RGBColor[0.05484206767198696, 0.5458487029750789, 0.4295754281321804], - Opacity[0.1], SphereBox[{0, 0, 0}, 3480000]}, - {RGBColor[ - 0.5357009384874412, 0.9447267464809403, 0.19597814354442122`], - Opacity[0.1], SphereBox[{0, 0, 0}, 1221500]}, - {RGBColor[0.2516965757577794, 0.619361342638632, 0.9908314833376688], - Opacity[0.1], + {Opacity[0.1], SphereBox[{0, 0, 0}, 6478000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6371324]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6356000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6346600]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6151000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 5971000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 5771000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 5701000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 3480000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 1221500]}, + {Opacity[0.1], CylinderBox[{{0, 0, 6370644}, {0, 0, 6370704}}, 37]}}], {192., -205.275}, ImageScaled[{0.5, 0.5}], {360, 391}, BaseStyle->{Graphics3DBoxOptions -> {SphericalRegion -> False}}, ContentSelectable->True], InsetBox[ Graphics3DBox[ - {RGBColor[0.3817965102765275, 0.560240567502444, 0.9641154785852963], - Opacity[0.1], CylinderBox[{{0, 0, 6370644}, {0, 0, 6370704}}, 37]}], {576., -205.275}, + {Opacity[0.1], CylinderBox[{{0, 0, 6370644}, {0, 0, 6370704}}, 37]}], {576., -205.275}, ImageScaled[{0.5, 0.5}], {360, 391}, BaseStyle->{Graphics3DBoxOptions -> {SphericalRegion -> False}}, ContentSelectable->True]}, {}}, @@ -692,8 +570,10 @@ Cell[BoxData[ UpTo[600], Automatic}, PlotRange->{{0, 768.}, {-410.55, 0}}, PlotRangePadding->{6, 5}]], "Output", - CellChangeTimes->{3.930848021055759*^9, 3.930913899366457*^9}, - CellLabel->"Out[9]=",ExpressionUUID->"b92d23cd-00b8-4bec-934c-3505cc26fb17"] + CellChangeTimes->{ + 3.930848021055759*^9, 3.930913899366457*^9, {3.935423881025281*^9, + 3.935423903319018*^9}}, + CellLabel->"Out[9]=",ExpressionUUID->"cc5e32c9-e802-4f29-bdca-7e0da8312b3d"] }, Open ]], Cell[CellGroupData[{ @@ -703,10 +583,10 @@ Cell[BoxData[ RowBox[{"{", RowBox[{ RowBox[{"Visuals", "[", - RowBox[{"\"\\"", ",", + RowBox[{"\"\\"", ",", "\"\\"", ",", RowBox[{"{", "}"}]}], "]"}], ",", "\[IndentingNewLine]", RowBox[{"Visuals", "[", - RowBox[{"\"\\"", ",", + RowBox[{"\"\\"", ",", "\"\\"", ",", RowBox[{"{", RowBox[{ "\"\\"", ",", "\"\\"", ",", @@ -717,66 +597,45 @@ Cell[BoxData[ "\"\\"", ",", "\"\\""}], "}"}]}], "]"}]}], "}"}], "]"}]], "Input", CellChangeTimes->{{3.930848034137143*^9, 3.930848038040841*^9}, { - 3.930848069237928*^9, 3.930848095894021*^9}}, + 3.930848069237928*^9, 3.930848095894021*^9}, {3.935423867541347*^9, + 3.935423870895969*^9}}, CellLabel->"In[10]:=",ExpressionUUID->"8d947ccf-7f8c-4f79-90f3-3e4c0822da4d"], Cell[BoxData[ GraphicsBox[{{}, {InsetBox[ Graphics3DBox[{ - {RGBColor[0.1452511204960758, 0.1857823034997803, 0.8210871966901028], - Opacity[0.1], SphereBox[{0, 0, 0}, 6478000]}, - {RGBColor[ - 0.009264329959300932, 0.6010366846363033, 0.9777323081774445], - Opacity[0.1], SphereBox[{0, 0, 0}, 6374134]}, - {RGBColor[ - 0.009264329959300932, 0.6010366846363033, 0.9777323081774445], - Opacity[0.1], SphereBox[{0, 0, 0}, 6373934]}, - {RGBColor[0.8885868418790182, 0.0606888172852702, 0.1352350531160138], - Opacity[0.1], SphereBox[{0, 0, 0}, 6371324]}, - {RGBColor[0.8885868418790182, 0.0606888172852702, 0.1352350531160138], - Opacity[0.1], SphereBox[{0, 0, 0}, 6356000]}, - {RGBColor[ - 0.24378268391346758`, 0.9872974256150269, 0.9000805642525402], - Opacity[0.1], SphereBox[{0, 0, 0}, 6346600]}, - {RGBColor[ - 0.24378268391346758`, 0.9872974256150269, 0.9000805642525402], - Opacity[0.1], SphereBox[{0, 0, 0}, 6151000]}, - {RGBColor[ - 0.24378268391346758`, 0.9872974256150269, 0.9000805642525402], - Opacity[0.1], SphereBox[{0, 0, 0}, 5971000]}, - {RGBColor[ - 0.24378268391346758`, 0.9872974256150269, 0.9000805642525402], - Opacity[0.1], SphereBox[{0, 0, 0}, 5771000]}, - {RGBColor[ - 0.24378268391346758`, 0.9872974256150269, 0.9000805642525402], - Opacity[0.1], SphereBox[{0, 0, 0}, 5701000]}, - {RGBColor[ - 0.14910337100201443`, 0.12436833265249714`, 0.4709167434095338], - Opacity[0.1], SphereBox[{0, 0, 0}, 3480000]}, - {RGBColor[ - 0.14682213790113297`, 0.8224387401991233, 0.15218462186818482`], - Opacity[0.1], SphereBox[{0, 0, 0}, 1221500]}, - {RGBColor[ - 0.009264329959300932, 0.6010366846363033, 0.9777323081774445], - Opacity[0.1], CylinderBox[{{0, 0, 6371684}, {0, 0, 6372684}}, 564.19], - {Opacity[0.1], CylinderBox[{{0, 0, -500}, {0, 0, 500}}, 564.19]}}}], {186.03333333333333, -226.8}, - ImageScaled[{0.5, 0.5}], {360, 432}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6478000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6374134]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6373934]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6371324]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6356000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6346600]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 6151000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 5971000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 5771000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 5701000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 3480000]}, + {Opacity[0.1], SphereBox[{0, 0, 0}, 1221500]}, + {Opacity[0.1], + CylinderBox[{{0, 0, 6371684}, {0, 0, 6372684}}, 564.19]}}], {192., -205.275}, + ImageScaled[{0.5, 0.5}], {360, 391}, BaseStyle->{Graphics3DBoxOptions -> {SphericalRegion -> False}}, ContentSelectable->True], InsetBox[ Graphics3DBox[ - {RGBColor[0.3678945716866675, 0.40177799905618894`, 0.4900159272427156], - Opacity[0.1], CylinderBox[{{0, 0, 6371684}, {0, 0, 6372684}}, 564.19], - {Opacity[0.1], CylinderBox[{{0, 0, -500}, {0, 0, 500}}, 564.19]}}], {379.1, -226.8}, - ImageScaled[{0.5, 0.5}], {2, 432}, + {Opacity[0.1], + CylinderBox[{{0, 0, 6371684}, {0, 0, 6372684}}, 564.19]}], {576., -205.275}, + ImageScaled[{0.5, 0.5}], {360, 391}, BaseStyle->{Graphics3DBoxOptions -> {SphericalRegion -> False}}, ContentSelectable->True]}, {}}, ImageSize->{ UpTo[600], Automatic}, - PlotRange->{{0, 386.1333333333333}, {-453.6, 0}}, + PlotRange->{{0, 768.}, {-410.55, 0}}, PlotRangePadding->{6, 5}]], "Output", - CellChangeTimes->{3.9308480391473513`*^9, 3.930848097045261*^9, - 3.930848147809525*^9, 3.9308483503991203`*^9, 3.930913901638027*^9}, - CellLabel->"Out[10]=",ExpressionUUID->"83fa702f-558a-482f-8040-ab82e433ee6c"] + CellChangeTimes->{ + 3.9308480391473513`*^9, 3.930848097045261*^9, 3.930848147809525*^9, + 3.9308483503991203`*^9, 3.930913901638027*^9, {3.9354238821424294`*^9, + 3.935423904408852*^9}}, + CellLabel->"Out[10]=",ExpressionUUID->"f8fb5630-ccc4-485a-9544-6a2b09e4f261"] }, Open ]] }, Open ]] }, Open ]] @@ -784,7 +643,7 @@ Cell[BoxData[ }, WindowSize->{849, 1027}, WindowMargins->{{0, Automatic}, {Automatic, -124}}, -FrontEndVersion->"13.3 for Mac OS X ARM (64-bit) (July 24, 2023)", +FrontEndVersion->"13.2 for Mac OS X ARM (64-bit) (January 30, 2023)", StyleDefinitions->"Default.nb", ExpressionUUID->"180ddf86-c472-42f5-b29b-4c869749c105" ] @@ -806,46 +665,46 @@ Cell[CellGroupData[{ Cell[1136, 40, 255, 4, 45, "Subsubsection",ExpressionUUID->"1828e000-2b55-4658-a39d-d3ec0e65319c"], Cell[1394, 46, 237, 4, 35, "Text",ExpressionUUID->"b85c7e71-3fe5-4770-92d2-3b8310f025c5"], Cell[1634, 52, 390, 8, 30, "Input",ExpressionUUID->"01061750-99ce-4ee2-ba52-6ccdbfbf6f3b"], -Cell[2027, 62, 307, 5, 30, "Input",ExpressionUUID->"a6dc3d65-b39c-4f5d-8e40-9ac1c63e10c6"] +Cell[2027, 62, 306, 5, 30, "Input",ExpressionUUID->"a6dc3d65-b39c-4f5d-8e40-9ac1c63e10c6"] }, Open ]], Cell[CellGroupData[{ -Cell[2371, 72, 266, 4, 53, "Subsection",ExpressionUUID->"5b67d770-d2b6-44d9-871c-110d0d66dc83"], +Cell[2370, 72, 266, 4, 53, "Subsection",ExpressionUUID->"5b67d770-d2b6-44d9-871c-110d0d66dc83"], Cell[CellGroupData[{ -Cell[2662, 80, 169, 3, 45, "Subsubsection",ExpressionUUID->"b4bb631f-eef9-40d0-aa86-e66af2411a5f"], +Cell[2661, 80, 169, 3, 45, "Subsubsection",ExpressionUUID->"b4bb631f-eef9-40d0-aa86-e66af2411a5f"], Cell[CellGroupData[{ -Cell[2856, 87, 432, 9, 30, "Input",ExpressionUUID->"758f5770-9701-4c2e-9c28-f1655b0a6965"], -Cell[3291, 98, 6350, 106, 294, "Output",ExpressionUUID->"8a3d7fe4-05dd-4061-b3db-44a8b527c5fa"] +Cell[2855, 87, 497, 9, 30, "Input",ExpressionUUID->"758f5770-9701-4c2e-9c28-f1655b0a6965"], +Cell[3355, 98, 3927, 75, 294, "Output",ExpressionUUID->"5609e820-8728-41eb-804e-82e36e1de646"] }, Open ]], Cell[CellGroupData[{ -Cell[9678, 209, 372, 8, 30, "Input",ExpressionUUID->"85f2f25e-059b-47e1-b7b7-1cd9a7fb936b"], -Cell[10053, 219, 4820, 88, 212, "Output",ExpressionUUID->"5a905629-0c22-4620-b59c-02655db9bf79"] +Cell[7319, 178, 441, 9, 30, "Input",ExpressionUUID->"85f2f25e-059b-47e1-b7b7-1cd9a7fb936b"], +Cell[7763, 189, 2966, 64, 211, "Output",ExpressionUUID->"22bf564d-0ceb-4fae-ab91-6dd16c0c0d80"] }, Open ]], Cell[CellGroupData[{ -Cell[14910, 312, 456, 10, 30, "Input",ExpressionUUID->"45186205-4e3c-43da-8cf6-942bd6843b62"], -Cell[15369, 324, 6834, 113, 226, "Output",ExpressionUUID->"7aa043b8-c09a-4a90-8f3b-914c780b39b6"] +Cell[10766, 258, 520, 10, 30, "Input",ExpressionUUID->"45186205-4e3c-43da-8cf6-942bd6843b62"], +Cell[11289, 270, 5805, 100, 226, "Output",ExpressionUUID->"e0160564-d0ed-4637-bf6a-db4a523dd2d7"] }, Open ]], Cell[CellGroupData[{ -Cell[22240, 442, 287, 5, 30, "Input",ExpressionUUID->"623517c9-0b0a-43b7-941c-607589cb47ec"], -Cell[22530, 449, 767, 13, 408, "Output",ExpressionUUID->"928e908c-d246-44d0-8e3f-99106d65c374"] +Cell[17131, 375, 333, 6, 30, "Input",ExpressionUUID->"623517c9-0b0a-43b7-941c-607589cb47ec"], +Cell[17467, 383, 659, 11, 408, "Output",ExpressionUUID->"457c7840-21be-418e-b2d7-20c799d31837"] }, Open ]] }, Open ]], Cell[CellGroupData[{ -Cell[23346, 468, 175, 3, 45, "Subsubsection",ExpressionUUID->"7e1653cb-c490-4521-8bec-792810d94dea"], +Cell[18175, 400, 175, 3, 45, "Subsubsection",ExpressionUUID->"7e1653cb-c490-4521-8bec-792810d94dea"], Cell[CellGroupData[{ -Cell[23546, 475, 1015, 20, 94, "Input",ExpressionUUID->"d7a1ae22-5013-434c-9f40-0ccdc86a3ce7"], -Cell[24564, 497, 2968, 58, 341, "Output",ExpressionUUID->"eb22797f-f400-4d3d-8fbd-b073c6b6fe6c"] +Cell[18375, 407, 1102, 21, 94, "Input",ExpressionUUID->"d7a1ae22-5013-434c-9f40-0ccdc86a3ce7"], +Cell[19480, 430, 1779, 34, 341, "Output",ExpressionUUID->"2dbd9e98-8740-42be-9dc3-422765729334"] }, Open ]], Cell[CellGroupData[{ -Cell[27569, 560, 865, 18, 94, "Input",ExpressionUUID->"c2600694-ff87-45e8-aa45-7e0762877b49"], -Cell[28437, 580, 2446, 43, 341, "Output",ExpressionUUID->"f81cbe95-f330-439e-bb2a-5afd2a6189ed"] +Cell[21296, 469, 952, 19, 94, "Input",ExpressionUUID->"c2600694-ff87-45e8-aa45-7e0762877b49"], +Cell[22251, 490, 1515, 29, 341, "Output",ExpressionUUID->"2cf3f729-3dc6-4032-b2a2-e3db2c56bfd4"] }, Open ]], Cell[CellGroupData[{ -Cell[30920, 628, 864, 18, 94, "Input",ExpressionUUID->"bed39234-fab0-4316-b468-3b5240c92626"], -Cell[31787, 648, 2423, 47, 341, "Output",ExpressionUUID->"b92d23cd-00b8-4bec-934c-3505cc26fb17"] +Cell[23803, 524, 951, 19, 94, "Input",ExpressionUUID->"bed39234-fab0-4316-b468-3b5240c92626"], +Cell[24757, 545, 1453, 30, 341, "Output",ExpressionUUID->"cc5e32c9-e802-4f29-bdca-7e0da8312b3d"] }, Open ]], Cell[CellGroupData[{ -Cell[34247, 700, 991, 20, 115, "Input",ExpressionUUID->"8d947ccf-7f8c-4f79-90f3-3e4c0822da4d"], -Cell[35241, 722, 2974, 56, 449, "Output",ExpressionUUID->"83fa702f-558a-482f-8040-ab82e433ee6c"] +Cell[26247, 580, 1078, 21, 115, "Input",ExpressionUUID->"8d947ccf-7f8c-4f79-90f3-3e4c0822da4d"], +Cell[27328, 603, 1656, 34, 341, "Output",ExpressionUUID->"f8fb5630-ccc4-485a-9544-6a2b09e4f261"] }, Open ]] }, Open ]] }, Open ]] diff --git a/resources/detectors/visuals/DetectorVisuals.wl b/resources/detectors/visuals/DetectorVisuals.wl index e27833df8..f0f1b006e 100644 --- a/resources/detectors/visuals/DetectorVisuals.wl +++ b/resources/detectors/visuals/DetectorVisuals.wl @@ -6,10 +6,10 @@ Visuals::usage = "Visuals[Experiment, Modules] displays the experiment as a 3D m Begin["`Private`"]; -Visuals[Experiment_, Modules_] := +Visuals[Experiment_, Version_, Modules_] := Module[{exp = Experiment, mods = Modules, dimensionFile, materialFile, keysDim, materials, color, boxes, polygons, cylinders, spheres,numd,visual}, - dimensionFile = Import[FileNames[All, FileNameJoin[{NotebookDirectory[], "/../densities", exp}]][[-1]]]; - materialFile = Import[FileNames[All, FileNameJoin[{NotebookDirectory[], "/../materials", exp}]][[-1]]]; + dimensionFile = Import[FileNames[FileNameJoin[{NotebookDirectory[], "../", exp, StringJoin[exp,"-",Version], StringJoin["/*densities*.dat"]}]][[-1]]]; + materialFile = Import[FileNames[FileNameJoin[{NotebookDirectory[], "../", exp, StringJoin[exp,"-",Version], StringJoin["/*materials_*.dat"]}]][[-1]]]; dimensionFile = Delete[dimensionFile, Position[dimensionFile, _?(#[[1]] == "#" &)]]; dimensionFile = Delete[dimensionFile, Position[dimensionFile, {}]]; diff --git a/resources/detectors/visuals/README.md b/resources/detectors/visuals/README.md index 94b38be0d..79e3f8794 100644 --- a/resources/detectors/visuals/README.md +++ b/resources/detectors/visuals/README.md @@ -2,21 +2,21 @@ `DetectorVisuals.wl` is a Wolfram Language package that takes the detector dimension files in `/densities/` and material file in `/materials/` to create a 3D model in `MATHEMATICA`. -To call functions in the package, save the working notebook in `\visuals\` and add `\path\to\visuals` to `$Path` so `MATHEMATICA` can find the package file. +To call functions in the package, save the working notebook in `\visuals\` and add `\path\to\visuals` to `$Path` so `MATHEMATICA` can find the package file. -If the notebook directory is correctly saved in `\visuals\`, run +If the notebook directory is correctly saved in `\visuals\`, run ``` AppendTo[$Path, NotebookDirectory[]]; ``` -to append `\path\to\visuals\` to `MATHEMATICA` so it has access to the package. Next, run +to append `\path\to\visuals\` to `MATHEMATICA` so it has access to the package. Next, run ``` << DetectorVisuals` ``` -to import the package. To create visualisation for an experiment, run +to import the package. To create visualisation for an experiment, run ``` Visuals["YourExperiment", {Excluded Modules}] From 1a35e9deb7f091e49b03bde111238236f716417a Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sun, 15 Sep 2024 15:23:54 -0600 Subject: [PATCH 65/94] Moving paper plots --- .../PaperPlots.ipynb | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename resources/examples/{AdditionalPaperPlots => additional_paper_plots}/PaperPlots.ipynb (100%) diff --git a/resources/examples/AdditionalPaperPlots/PaperPlots.ipynb b/resources/examples/additional_paper_plots/PaperPlots.ipynb similarity index 100% rename from resources/examples/AdditionalPaperPlots/PaperPlots.ipynb rename to resources/examples/additional_paper_plots/PaperPlots.ipynb From fb0bdab9d614ef8c10bede7854524c81bc6e9c6d Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sun, 15 Sep 2024 16:34:35 -0600 Subject: [PATCH 66/94] primary_type should be an argument --- python/Injector.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/Injector.py b/python/Injector.py index 8ca27cbff..d7096b594 100644 --- a/python/Injector.py +++ b/python/Injector.py @@ -34,6 +34,7 @@ def __init__( number_of_events: Optional[int] = None, detector_model: Optional[_detector.DetectorModel] = None, seed: Optional[int] = None, + primary_type: Optional[_dataclasses.ParticleType] = None, primary_interactions: Dict[_dataclasses.ParticleType, List[Union[_interactions.CrossSection, _interactions.Decay]]] = None, primary_injection_distributions: List[_distributions.PrimaryInjectionDistribution] = None, secondary_interactions: Optional[Dict[_dataclasses.ParticleType, List[Union[_interactions.CrossSection, _interactions.Decay]]]] = None, @@ -60,6 +61,8 @@ def __init__( self.__number_of_events = number_of_events if detector_model is not None: self.__detector_model = detector_model + if primary_type is not None: + self.__primary_type = primary_type if primary_interactions is not None: self.__primary_interactions = primary_interactions if primary_injection_distributions is not None: From 253954a1603a3530cfa87a992eb0eae45bc88c79 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sun, 15 Sep 2024 16:35:05 -0600 Subject: [PATCH 67/94] Add wrapper for Weighter --- python/Weighter.py | 310 +++++++++++++++++++++++++++++++++++++++++++++ python/__init__.py | 6 + 2 files changed, 316 insertions(+) create mode 100644 python/Weighter.py diff --git a/python/Weighter.py b/python/Weighter.py new file mode 100644 index 000000000..145080bda --- /dev/null +++ b/python/Weighter.py @@ -0,0 +1,310 @@ +from . import utilities as _utilities +from . import math as _math +from . import dataclasses as _dataclasses +from . import geometry as _geometry +from . import detector as _detector +from . import interactions as _interactions +from . import distributions as _distributions +from . import injection as _injection +from . import Injector as _Injector_module + +from typing import Tuple, List, Dict, Optional, Union, Callable +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import siren + +_Injector = _injection.Injector +_Weighter = _injection.Weighter + +_PyInjector = _Injector_module.Injector + +ParticleType = _dataclasses.ParticleType +CrossSection = _interactions.CrossSection +Decay = _interactions.Decay +DetectorModel = _detector.DetectorModel +InteractionTree = _dataclasses.InteractionTree + +class Weighter: + """ + A wrapper for the C++ Weighter class, handling event weight calculations. + """ + + def __init__(self, + injectors: Optional[List[_Injector]] = None, + detector_model: Optional[DetectorModel] = None, + primary_type: Optional[_dataclasses.ParticleType] = None, + primary_interactions: Optional[Dict[_dataclasses.ParticleType, List[Union[_interactions.CrossSection, _interactions.Decay]]]] = None, + primary_physical_distributions: Optional[List[_distributions.WeightableDistribution]] = None, + secondary_interactions: Optional[Dict[_dataclasses.ParticleType, List[Union[_interactions.CrossSection, _interactions.Decay]]]] = None, + secondary_physical_distributions: Optional[Dict[_dataclasses.ParticleType, List[_distributions.WeightableDistribution]]] = None, + ): + """ + Initialize the Weighter with interactions and physical processes. + + Args: + injectors: List of injector objects. + detector_model: The detector model. + primary_type: The primary particle type. + primary_interactions: Dictionary of primary particle interactions. + primary_physical_distributions: List of primary physical distributions. + secondary_interactions: Dictionary of secondary particle interactions. + secondary_physical_distributions: Dictionary of secondary physical distributions. + + Note: + All parameters are optional and can be set later using property setters. + """ + + self.__injectors = None + self.__detector_model = None + + self.__primary_type = None + self.__primary_interactions = [] + self.__primary_physical_distributions = [] + + self.__secondary_interactions = {} + self.__secondary_physical_distributions = {} + + self.__weighter = None + + if injectors is not None: + self.injectors = injectors + if detector_model is not None: + self.__detector_model = detector_model + if primary_type is not None: + self.__primary_type = primary_type + if primary_interactions is not None: + self.__primary_interactions = primary_interactions + if primary_physical_distributions is not None: + self.__primary_physical_distributions = primary_physical_distributions + if secondary_interactions is not None: + self.__secondary_interactions = secondary_interactions + if secondary_physical_distributions is not None: + self.__secondary_physical_distributions = secondary_physical_distributions + + def __initialize_weighter(self): + """ + Initialize the internal C++ Weighter object. + + This method creates the C++ Weighter object using the configured parameters. + It is called automatically when needed and should not be called directly. + + Raises: + ValueError: If any required attributes are not set. + """ + + if self.__injectors is None: + raise ValueError("Injectors have not been set.") + if self.__detector_model is None: + raise ValueError("Detector model has not been set.") + if self.__primary_type is None: + raise ValueError("Primary type has not been set.") + if len(self.__primary_interactions) == 0: + raise ValueError("Primary interactions have not been set.") + if len(self.__primary_physical_distributions) == 0: + raise ValueError("Primary physical distributions have not been set.") + + injectors = [injector._Injector__injector if isinstance(injector, _PyInjector) else injector for injector in self.__injectors] + + primary_type = self.primary_type + primary_interaction_collection = _interactions.InteractionCollection( + primary_type, self.primary_interactions + ) + primary_process = _injection.PhysicalProcess( + primary_type, primary_interaction_collection + ) + primary_process.distributions = self.primary_physical_distributions + + secondary_interactions = self.secondary_interactions + secondary_physical_distributions = self.secondary_physical_distributions + + secondary_processes = [] + for secondary_type, secondary_interactions in secondary_interactions.items(): + secondary_interaction_collection = _interactions.InteractionCollection( + secondary_type, secondary_interactions + ) + secondary_process = _injection.PhysicalProcess( + secondary_type, secondary_interaction_collection + ) + if secondary_type in secondary_physical_distributions: + secondary_process.distributions = secondary_physical_distributions[secondary_type] + else: + secondary_process.distributions = [] + secondary_processes.append(secondary_process) + + self.__weighter = _Weighter( + injectors, + self.detector_model, + primary_process, + secondary_processes, + ) + + @property + def injectors(self) -> List[_Injector]: + """ + Get the list of injectors. + + Returns: + List[_Injector]: The current list of injector objects. + """ + return self.__injectors + + @injectors.setter + def injectors(self, injectors: List[_Injector]): + """ + Set the list of injectors. + + Args: + injectors: A list of Injector objects. + + Raises: + ValueError: If the weighter has already been initialized. + TypeError: If the input is not a list of Injector objects. + ValueError: If any of the injectors are not initialized. + """ + + if self.__weighter is not None: + raise ValueError("Cannot set injectors after weighter has been initialized.") + if not isinstance(injectors, list): + raise TypeError("Injectors must be a list.") + if not all(isinstance(injector, (_Injector, _PyInjector)) for injector in injectors): + raise TypeError("All injectors must be of type Injector.") + if not all(injector._Injector__injector is not None for injector in injectors if isinstance(injector, _PyInjector)): + raise ValueError("All injectors must be initialized.") + self.__injectors = injectors + + @property + def detector_model(self) -> DetectorModel: + """ + Get the detector model. + + Returns: + DetectorModel: The current detector model. + """ + return self.__detector_model + + @detector_model.setter + def detector_model(self, detector_model: DetectorModel): + """ + Set the detector model. + + Args: + detector_model: The DetectorModel object to set. + + Raises: + ValueError: If the weighter has already been initialized. + TypeError: If the input is not a DetectorModel object. + """ + + if self.__weighter is not None: + raise ValueError("Cannot set detector model after weighter has been initialized.") + if not isinstance(detector_model, DetectorModel): + raise TypeError("Detector model must be of type DetectorModel.") + self.__detector_model = detector_model + + @property + def primary_type(self) -> ParticleType: + return self.__primary_type + + @primary_type.setter + def primary_type(self, primary_type: ParticleType): + if self.__weighter is not None: + raise ValueError("Cannot set primary type after weighter has been initialized.") + if not isinstance(primary_type, ParticleType): + raise TypeError("Primary type must be of type ParticleType.") + self.__primary_type = primary_type + + @property + def primary_interactions(self) -> Dict[ParticleType, List[Union[CrossSection, Decay]]]: + return self.__primary_interactions + + @primary_interactions.setter + def primary_interactions(self, primary_interactions: List[Union[CrossSection, Decay]]): + if self.__weighter is not None: + raise ValueError("Cannot set primary interactions after weighter has been initialized.") + if not isinstance(primary_interactions, list): + raise TypeError("Primary interactions must be a list.") + if not all(isinstance(interaction, (CrossSection, Decay)) for interaction in primary_interactions): + raise TypeError("All interactions in primary interactions must be of type CrossSection or Decay.") + self.__primary_interactions = primary_interactions + + @property + def primary_physical_distributions(self) -> List[_distributions.WeightableDistribution]: + return self.__primary_physical_distributions + + @primary_physical_distributions.setter + def primary_physical_distributions(self, primary_physical_distributions: List[_distributions.WeightableDistribution]): + if self.__weighter is not None: + raise ValueError("Cannot set primary physical distributions after weighter has been initialized.") + if not isinstance(primary_physical_distributions, list): + raise TypeError("Primary physical distributions must be a list.") + if not all(isinstance(distribution, _distributions.WeightableDistribution) for distribution in primary_physical_distributions): + raise TypeError("All distributions in primary physical distributions must be of type WeightableDistribution.") + self.__primary_physical_distributions = primary_physical_distributions + + @property + def secondary_interactions(self) -> Dict[ParticleType, List[Union[CrossSection, Decay]]]: + return self.__secondary_interactions + + @secondary_interactions.setter + def secondary_interactions(self, secondary_interactions: Dict[ParticleType, List[Union[CrossSection, Decay]]]): + if self.__weighter is not None: + raise ValueError("Cannot set secondary interactions after weighter has been initialized.") + if not isinstance(secondary_interactions, dict): + raise TypeError("Secondary interactions must be a dictionary.") + if not all(isinstance(particle_type, ParticleType) for particle_type in secondary_interactions.keys()): + raise TypeError("All keys in secondary interactions must be of type ParticleType.") + if not all(isinstance(interactions, list) for interactions in secondary_interactions.values()): + raise TypeError("All values in secondary interactions must be lists.") + if not all(isinstance(interaction, (CrossSection, Decay)) for interactions in secondary_interactions.values() for interaction in interactions): + raise TypeError("All interactions in secondary interactions must be of type CrossSection or Decay.") + self.__secondary_interactions = secondary_interactions + + @property + def secondary_physical_distributions(self) -> Dict[ParticleType, List[_distributions.WeightableDistribution]]: + return self.__secondary_physical_distributions + + @secondary_physical_distributions.setter + def secondary_physical_distributions(self, secondary_physical_distributions: Dict[ParticleType, List[_distributions.WeightableDistribution]]): + if self.__weighter is not None: + raise ValueError("Cannot set secondary physical distributions after weighter has been initialized.") + if not isinstance(secondary_physical_distributions, dict): + raise TypeError("Secondary physical distributions must be a dictionary.") + if not all(isinstance(particle_type, ParticleType) for particle_type in secondary_physical_distributions.keys()): + raise TypeError("All keys in secondary physical distributions must be of type ParticleType.") + if not all(isinstance(distributions, list) for distributions in secondary_physical_distributions.values()): + raise TypeError("All values in secondary physical distributions must be lists.") + if not all(isinstance(distribution, _distributions.WeightableDistribution) for distributions in secondary_physical_distributions.values() for distribution in distributions): + raise TypeError("All distributions in secondary physical distributions must be of type WeightableDistribution.") + self.__secondary_physical_distributions = secondary_physical_distributions + + def __call__(self, interaction_tree: InteractionTree) -> float: + """ + Calculate the event weight for a given interaction tree. + + This method initializes the weighter if necessary and then calculates the event weight. + + Args: + interaction_tree: The interaction tree to weight. + + Returns: + float: The calculated event weight. + """ + + if self.__weighter is None: + self.__initialize_weighter() + return self.__weighter.EventWeight(interaction_tree) + + def event_weight(self, interaction_tree: InteractionTree) -> float: + """ + Calculate the event weight for a given interaction tree. + + This method is an alias for __call__ and provides the same functionality. + + Args: + interaction_tree: The interaction tree to weight. + + Returns: + float: The calculated event weight. + """ + return self(interaction_tree) diff --git a/python/__init__.py b/python/__init__.py index 587cce09a..0dd24eeac 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -9,6 +9,7 @@ from . import _util from . import Injector +from . import Weighter # Intropspect package version import sys @@ -35,6 +36,11 @@ injection.Injector = Injector.Injector del Injector +# Override the Weighter with the python wrapper +injection._Weighter = injection.Weighter +injection.Weighter = Weighter.Weighter +del Weighter + dataclasses.Particle.ParticleType = dataclasses.ParticleType def darknews_version(): From ceae573db1bc38ac0acc2ee2c6c9948a07269d6e Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sun, 15 Sep 2024 16:58:12 -0600 Subject: [PATCH 68/94] Re-write the DIS_ATLAS example with the new interface. Still need to save events --- resources/examples/example1/DIS_ATLAS.py | 126 +++++++++++++++-------- 1 file changed, 83 insertions(+), 43 deletions(-) diff --git a/resources/examples/example1/DIS_ATLAS.py b/resources/examples/example1/DIS_ATLAS.py index a64e06791..add646ed4 100644 --- a/resources/examples/example1/DIS_ATLAS.py +++ b/resources/examples/example1/DIS_ATLAS.py @@ -1,7 +1,12 @@ import os - import siren -from siren.SIREN_Controller import SIREN_Controller +try: + from tqdm import tqdm as tqdm +except ImportError: + print("Importing tqdm failed, using default range") + tqdm = lambda x: x + +seed = 99 # Number of events to inject events_to_inject = int(1e5) @@ -9,62 +14,97 @@ # Expeirment to run experiment = "ATLAS" -# Define the controller -controller = SIREN_Controller(events_to_inject, experiment, seed=99) +# Load the detector model +detector_model = siren.utilities.load_detector(experiment) # Particle to inject primary_type = siren.dataclasses.Particle.ParticleType.NuMu cross_section_model = "CSMSDISSplines" -xsfiledir = siren.utilities.get_cross_section_model_path(cross_section_model) - # Cross Section Model target_type = siren.dataclasses.Particle.ParticleType.Nucleon -DIS_xs = siren.interactions.DISFromSpline( - os.path.join(xsfiledir, "dsdxdy_nu_CC_iso.fits"), - os.path.join(xsfiledir, "sigma_nu_CC_iso.fits"), - [primary_type], - [target_type], "m" +primary_processes, secondary_processes = siren.utilities.load_processes( + cross_section_model, + primary_types = [primary_type], + target_types = [target_type], + isoscalar = True, + process_types = ["CC"], ) -primary_xs = siren.interactions.InteractionCollection(primary_type, [DIS_xs]) -controller.SetInteractions(primary_xs) - -# Primary distributions -primary_injection_distributions = {} -primary_physical_distributions = {} - -# energy distribution -# HE SN flux from ATLAS paper -edist = siren.utilities.load_flux("HE_SN", tag="numu", min_energy=100, max_energy=1e6, physically_normalized=True) -edist_gen = siren.utilities.load_flux("HE_SN", tag="numu", min_energy=100, max_energy=1e6, physically_normalized=False) - -primary_injection_distributions["energy"] = edist_gen -primary_physical_distributions["energy"] = edist - -# direction distribution +# Choose the direction we will inject from # let's just inject upwards injection_dir = siren.math.Vector3D(0, 0, 1) injection_dir.normalize() -direction_distribution = siren.distributions.FixedDirection(injection_dir) -primary_injection_distributions["direction"] = direction_distribution -primary_physical_distributions["direction"] = direction_distribution - -# position distribution -position_distribution = controller.GetCylinderVolumePositionDistributionFromSector("tilecal") -primary_injection_distributions["position"] = position_distribution - -# SetProcesses -controller.SetProcesses( - primary_type, primary_injection_distributions, primary_physical_distributions -) - -controller.Initialize() -events = controller.GenerateEvents() +# Build the position distribution using properties of the geometry +fiducial_volume_name = "tilecal" +geo = None +for sector in detector_model.Sectors: + if sector.name == fiducial_volume_name: + geo = sector.geo + break + +det_position = detector_model.GeoPositionToDetPosition(siren.detector.GeometryPosition(geo.placement.Position)) +det_rotation = geo.placement.Quaternion +det_placement = siren.geometry.Placement(det_position.get(), det_rotation) +cylinder = siren.geometry.Cylinder(det_placement, geo.Radius, geo.InnerRadius, geo.Z) + +position_distribution = siren.distributions.CylinderVolumePositionDistribution(cylinder) + +primary_injection_distributions = [ + siren.distributions.PrimaryMass(0), + # energy distribution + # HE SN flux from ATLAS paper + siren.utilities.load_flux( + "HE_SN", + tag="numu", + min_energy=100, + max_energy=1e6, + physically_normalized=True), + siren.distributions.FixedDirection(injection_dir), + position_distribution, +] + +primary_physical_distributions = [ + # energy distribution + # HE SN flux from ATLAS paper + siren.utilities.load_flux( + "HE_SN", + tag="numu", + min_energy=100, + max_energy=1e6, + physically_normalized=False), + siren.distributions.FixedDirection(injection_dir), +] + +injector = siren.injection.Injector() +injector.seed = seed +injector.number_of_events = events_to_inject +injector.detector_model = detector_model +injector.primary_type = primary_type +injector.primary_interactions = primary_processes[primary_type] +injector.primary_injection_distributions = primary_injection_distributions +injector.secondary_interactions = {} +injector.secondary_injection_distributions = {} + +print("Generating events") +events = [injector.generate_event() for _ in tqdm(range(events_to_inject))] + +weighter = siren.injection.Weighter() +weighter.injectors = [injector] +weighter.detector_model = detector_model +weighter.primary_type = primary_type +weighter.primary_interactions = primary_processes[primary_type] +weighter.primary_physical_distributions = primary_physical_distributions +weighter.secondary_interactions = {} +weighter.secondary_physical_distributions = {} + +print("Weighting events") +weights = [weighter(event) for event in tqdm(events)] os.makedirs("output", exist_ok=True) -controller.SaveEvents("output/ATLAS_DIS") +#TODO save the events and weights + From 1622a4a583f76baad27361de9edc6352f7079f4c Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sun, 15 Sep 2024 17:41:40 -0600 Subject: [PATCH 69/94] Utilities for exploring and getting docs --- python/_util.py | 138 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 116 insertions(+), 22 deletions(-) diff --git a/python/_util.py b/python/_util.py index abbea95ae..cb49bda22 100644 --- a/python/_util.py +++ b/python/_util.py @@ -2,6 +2,7 @@ import re import sys import uuid +import pydoc import pathlib import importlib @@ -259,6 +260,11 @@ def load_module(name, path, persist=True): + r"))?" ) +_model_regex = re.compile( + r"^\s*" + _MODEL_PATTERN + r"\s*$", + re.VERBOSE | re.IGNORECASE, +) + def decompose_version(version): # Break the version string into its components matches = _version_regex.match(version) @@ -521,7 +527,7 @@ def _get_model_file_name(version, model_versions, model_files, model_name, suffi return f"{model_name}-v{version}{suffix}" def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exist=True, specific_file=None): - _model_regex = re.compile( + model_regex = re.compile( r"^\s*" + _MODEL_PATTERN + ("" if suffix is None else r"(?:" + suffix + r")?") + r"\s*$", re.VERBOSE | re.IGNORECASE, ) @@ -530,7 +536,7 @@ def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exi resources_dir = resource_package_dir() base_dir = _get_base_directory(resources_dir, prefix) - d = _model_regex.match(model_name) + d = model_regex.match(model_name) if d is None: raise ValueError(f"Invalid model name: {model_name}") d = d.groupdict() @@ -542,7 +548,7 @@ def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exi return os.path.dirname(specific_file_path) model_files = _get_model_files(base_dir, model_name, is_file, folder_exists, version) - model_versions = _extract_model_versions(model_files, _model_regex, model_name) + model_versions = _extract_model_versions(model_files, model_regex, model_name) if len(model_versions) == 0 and must_exist: if specific_file_path: @@ -591,7 +597,7 @@ def _get_model_subfolders(base_dir, model_regex): def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exist=True, specific_file=None): - _model_regex = re.compile( + model_regex = re.compile( r"^\s*" + _MODEL_PATTERN + ("" if suffix is None else r"(?:" + suffix + r")?") + r"\s*$", re.VERBOSE | re.IGNORECASE, ) @@ -600,7 +606,7 @@ def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exi resources_dir = resource_package_dir() base_dir = _get_base_directory(resources_dir, prefix) - d = _model_regex.match(model_name) + d = model_regex.match(model_name) if d is None: raise ValueError(f"Invalid model name: {model_name}") d = d.groupdict() @@ -621,7 +627,7 @@ def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exi return model_dir - model_subfolders = _get_model_subfolders(model_dir, _model_regex) + model_subfolders = _get_model_subfolders(model_dir, model_regex) if len(model_subfolders) == 0: if must_exist: @@ -635,7 +641,7 @@ def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exi models_and_versions = [] for f in model_subfolders: - d = _model_regex.match(f).groupdict() + d = model_regex.match(f).groupdict() if d["version"] is not None: models_and_versions.append((f, normalize_version(d["version"]))) @@ -687,18 +693,29 @@ def get_detector_model_path(model_name, must_exist=True): def get_processes_model_path(model_name, must_exist=True): return _get_model_path(model_name, prefix=_resource_folder_by_name["processes"], is_file=False, must_exist=must_exist, specific_file="processes.py") - -def load_resource(resource_type, resource_name, *args, **kwargs): +def import_resource(resource_type, resource_name): folder = _resource_folder_by_name[resource_type] specific_file = f"{resource_type}.py" abs_dir = _get_model_path(resource_name, prefix=folder, is_file=False, must_exist=True, specific_file=specific_file) fname = os.path.join(abs_dir, f"{resource_type}.py") - print(fname) - assert(os.path.isfile(fname)) - resource_module = load_module(f"siren-{resource_type}-{resource_name}", fname, persist=False) - loader = getattr(resource_module, f"load_{resource_type}") + if not os.path.isfile(fname): + return None + return load_module(f"siren-{resource_type}-{resource_name}", fname, persist=False) + + +def get_resource_loader(resource_type, resource_name): + resource_module = import_resource(resource_type, resource_name) + if resource_module is None: + return None + return getattr(resource_module, f"load_{resource_type}") + + +def load_resource(resource_type, resource_name, *args, **kwargs): + loader = get_resource_loader(resource_type, resource_name) + if loader is None: + return None resource = loader(*args, **kwargs) return resource @@ -708,19 +725,15 @@ def load_flux(model_name, *args, **kwargs): def load_detector(model_name, *args, **kwargs): + resource = load_resource("flux", model_name, *args, **kwargs) + if resource is not None: + return resource + resource_type = "detector" resource_name = model_name folder = _resource_folder_by_name[resource_type] - specific_file = f"{resource_type}.py" - abs_dir = _get_model_path(resource_name, prefix=folder, is_file=False, must_exist=True, specific_file=specific_file) - - script_fname = os.path.join(abs_dir, f"{resource_type}.py") - if os.path.isfile(script_fname): - resource_module = load_module(f"siren-{resource_type}-{resource_name}", script_fname, persist=False) - loader = getattr(resource_module, f"load_{resource_type}") - resource = loader(*args, **kwargs) - return resource + abs_dir = _get_model_path(resource_name, prefix=folder, is_file=False, must_exist=True, specific_file=None) densities_fname = os.path.join(abs_dir, "densities.dat") materials_fname = os.path.join(abs_dir, "materials.dat") @@ -759,3 +772,84 @@ def get_fiducial_volume(experiment): from . import detector as _detector return _detector.DetectorModel.ParseFiducialVolume(fiducial_line, detector_line) return None + +def list_fluxes(): + return sorted(_get_model_subfolders(_get_base_directory(resource_package_dir(), "fluxes"), _model_regex)) + +def list_detectors(): + dirs = sorted(_get_model_subfolders(_get_base_directory(resource_package_dir(), "detectors"), _model_regex)) + dirs = [d for d in dirs if d != "visuals"] + return dirs + +def list_processes(): + return sorted(_get_model_subfolders(_get_base_directory(resource_package_dir(), "processes"), _model_regex)) + +def flux_docs(flux_name): + loader = get_resource_loader("flux", flux_name) + if loader is None: + raise ValueError(f"Could not find documentation for flux {flux_name}") + return loader.__doc__ + +def detector_docs(detector_name): + loader = get_resource_loader("detector", detector_name) + if loader is not None: + return loader.__doc__ + + resource_name = detector_name + folder = _resource_folder_by_name["detector"] + + abs_dir = _get_model_path(resource_name, prefix=folder, is_file=False, must_exist=True, specific_file=None) + + densities_fname = os.path.join(abs_dir, "densities.dat") + materials_fname = os.path.join(abs_dir, "materials.dat") + + lines = [] + if os.path.isfile(densities_fname): + with open(densities_fname) as file: + new_lines = [] + for l in file.readlines(): + l = l.strip() + if l.startswith("#"): + new_lines.append(l) + else: + break + lines.extend(new_lines) + + if os.path.isfile(materials_fname): + with open(materials_fname) as file: + new_lines = [] + for l in file.readlines(): + l = l.strip() + if l.startswith("#"): + new_lines.append(l) + else: + break + if len(lines) > 0 and len(new_lines) > 0: + lines.append("") + lines.extend(new_lines) + + doc = "\n".join(lines) + + if len(doc) == 0: + raise ValueError(f"Could not find documentation for detector {detector_name}") + + return doc + + +def process_docs(process_name): + loader = get_resource_loader("processes", process_name) + if loader is None: + raise ValueError(f"Could not find documentation for process {process_name}") + return loader.__doc__ + +def flux_help(flux_name): + doc = flux_docs(flux_name) + pydoc.pager(doc) + +def detector_help(detector_name): + doc = detector_docs(detector_name) + pydoc.pager(doc) + +def process_help(process_name): + doc = process_docs(process_name) + pydoc.pager(doc) From 0d41fb18574a9d3f5ddc887edf075fb5b57d4a1b Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sun, 15 Sep 2024 17:44:58 -0600 Subject: [PATCH 70/94] Rename and fix T2K_NEAR flux script to work with new directory structure. --- .../T2K_NEAR-v1.0/{FluxCalculator.py => flux.py} | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) rename resources/fluxes/T2K_NEAR/T2K_NEAR-v1.0/{FluxCalculator.py => flux.py} (92%) diff --git a/resources/fluxes/T2K_NEAR/T2K_NEAR-v1.0/FluxCalculator.py b/resources/fluxes/T2K_NEAR/T2K_NEAR-v1.0/flux.py similarity index 92% rename from resources/fluxes/T2K_NEAR/T2K_NEAR-v1.0/FluxCalculator.py rename to resources/fluxes/T2K_NEAR/T2K_NEAR-v1.0/flux.py index b9a040c51..4dccc2cc5 100644 --- a/resources/fluxes/T2K_NEAR/T2K_NEAR-v1.0/FluxCalculator.py +++ b/resources/fluxes/T2K_NEAR/T2K_NEAR-v1.0/flux.py @@ -1,24 +1,26 @@ import os -def MakeFluxFile(tag, abs_flux_dir): - +def load_flux(tag): + ''' Accepts the following tags: {PLUS, MINUS}_{nue,nuebar,numu,numubar} ''' enhance, particle = tag.split("_") - + if enhance not in ["MINUS", "PLUS"]: print("%s 250kA enhancement specified in tag %s is not valid"%(enhance)) exit(0) if particle not in ["numu", "numubar", "nue", "nuebar"]: print("%s particle specified in tag %s is not valid"%(particle)) exit(0) - + + abs_flux_dir = os.path.dirname(__file__) + input_flux_file = os.path.join(abs_flux_dir, "T2K_%s_250kA.dat"%(enhance)) - + output_flux_file = os.path.join(abs_flux_dir, "T2KOUT_%s.dat"%(tag)) @@ -32,4 +34,4 @@ def MakeFluxFile(tag, abs_flux_dir): E, flux = (float(row[1])+float(row[3]))/2, float(row[pid+2]) flux*=2e-16 # put flux in units of nu/m^2/GeV/POT print(E, flux, file=fout) - return output_flux_file \ No newline at end of file + return output_flux_file From 87a76bcffe85b8ed5d8ece6b44ac8c0febc2b39e Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sun, 15 Sep 2024 18:22:30 -0600 Subject: [PATCH 71/94] Enable access to resources through the module / tab-complete --- python/__init__.py | 1 + python/_util.py | 34 +++++++++++++++++++++++++++------- python/resources.py | 27 +++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 python/resources.py diff --git a/python/__init__.py b/python/__init__.py index 0dd24eeac..950ddd621 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -10,6 +10,7 @@ from . import _util from . import Injector from . import Weighter +from . import resources # Intropspect package version import sys diff --git a/python/_util.py b/python/_util.py index cb49bda22..74cc7b86b 100644 --- a/python/_util.py +++ b/python/_util.py @@ -724,14 +724,9 @@ def load_flux(model_name, *args, **kwargs): return load_resource("flux", model_name, *args, **kwargs) -def load_detector(model_name, *args, **kwargs): - resource = load_resource("flux", model_name, *args, **kwargs) - if resource is not None: - return resource - - resource_type = "detector" +def _detector_file_loader(model_name): resource_name = model_name - folder = _resource_folder_by_name[resource_type] + folder = _resource_folder_by_name["detector"] abs_dir = _get_model_path(resource_name, prefix=folder, is_file=False, must_exist=True, specific_file=None) @@ -748,6 +743,13 @@ def load_detector(model_name, *args, **kwargs): raise ValueError("Could not find detector loading script \"{script_fname}\" or densities and materials files \"{densities_fname}\", \"materials_fname\"") +def load_detector(model_name, *args, **kwargs): + resource = load_resource("flux", model_name, *args, **kwargs) + if resource is not None: + return resource + return _detector_file_loader + + def load_processes(model_name, *args, **kwargs): return load_resource("processes", model_name, *args, **kwargs) @@ -853,3 +855,21 @@ def detector_help(detector_name): def process_help(process_name): doc = process_docs(process_name) pydoc.pager(doc) + +def _get_process_loader(process_name): + return get_resource_loader("processes", process_name) + +def _get_flux_loader(flux_name): + return get_resource_loader("flux", flux_name) + +def _get_detector_loader(detector_name): + loader = get_resource_loader("detector", detector_name) + if loader is not None: + return loader + + def load_detector(): + return _detector_file_loader(detector_name) + + load_detector.__doc__ = detector_docs(detector_name) + + return load_detector diff --git a/python/resources.py b/python/resources.py new file mode 100644 index 000000000..260e33eaf --- /dev/null +++ b/python/resources.py @@ -0,0 +1,27 @@ +from . import _util + +class ResourceList: + def __init__(self, resource_type, list_method, load_method): + self.__resource_type = resource_type + self.__list_method = list_method + self.__load_method = load_method + + def __getattr__(self, name): + resources = self.__list_method() + if name in resources: + return self.__load_method(name) + else: + # Default behaviour + return object.__getattribute__(self, name) + + def __dir__(self): + dirs = dir(self.__class__) + dirs += list(self.__dict__.keys()) + dirs += self.__list_method() + return sorted(dirs) + +fluxes = ResourceList('fluxes', _util.list_fluxes, _util._get_flux_loader) +detectors = ResourceList('detectors', _util.list_detectors, _util._get_detector_loader) +processes = ResourceList('processes', _util.list_processes, _util._get_process_loader) + +del ResourceList From b2eda5e341a907add9d800f457864a311e3af389 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sun, 15 Sep 2024 18:41:19 -0600 Subject: [PATCH 72/94] Add file paths to detector docs --- python/_util.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/python/_util.py b/python/_util.py index 74cc7b86b..94c658301 100644 --- a/python/_util.py +++ b/python/_util.py @@ -667,14 +667,6 @@ def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exi return os.path.join(model_dir, found_model_subfolder) -def get_detector_model_file_path(model_name, must_exist=True): - return _get_model_path(model_name, prefix="detectors/densities", suffix=".dat", is_file=True, must_exist=must_exist) - - -def get_material_model_file_path(model_name, must_exist=True): - return _get_model_path(model_name, prefix="detectors/materials", suffix=".dat", is_file=True, must_exist=must_exist) - - _resource_folder_by_name = { "flux": "fluxes", "detector": "detectors", @@ -815,6 +807,8 @@ def detector_docs(detector_name): new_lines.append(l) else: break + if len(new_lines) > 0: + lines.append(f"Detector definition: {densities_fname}") lines.extend(new_lines) if os.path.isfile(materials_fname): @@ -828,11 +822,12 @@ def detector_docs(detector_name): break if len(lines) > 0 and len(new_lines) > 0: lines.append("") + lines.append(f"Material definitions: {materials_fname}") lines.extend(new_lines) doc = "\n".join(lines) - if len(doc) == 0: + if len(lines) == 0: raise ValueError(f"Could not find documentation for detector {detector_name}") return doc From 254eb2d8855e5369f617e873dafbf32fa6efa747 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Sun, 15 Sep 2024 18:57:01 -0600 Subject: [PATCH 73/94] Expose resource loader functions in the resources submodule --- python/resources.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/python/resources.py b/python/resources.py index 260e33eaf..d64218c29 100644 --- a/python/resources.py +++ b/python/resources.py @@ -1,5 +1,11 @@ +__all__ = ["load_flux", "load_detector", "load_processes", "fluxes", "detectors", "processes"] + from . import _util +load_flux = _util.load_flux +load_detector = _util.load_detector +load_processes = _util.load_processes + class ResourceList: def __init__(self, resource_type, list_method, load_method): self.__resource_type = resource_type @@ -24,4 +30,5 @@ def __dir__(self): detectors = ResourceList('detectors', _util.list_detectors, _util._get_detector_loader) processes = ResourceList('processes', _util.list_processes, _util._get_process_loader) +del _util del ResourceList From bc0a31c26f03982743a128b6178d33434042f757 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 18 Sep 2024 12:50:50 -0600 Subject: [PATCH 74/94] Don't require a version folder if there is a top level loader --- python/_util.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/python/_util.py b/python/_util.py index 94c658301..1724c2140 100644 --- a/python/_util.py +++ b/python/_util.py @@ -621,15 +621,22 @@ def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exi if not must_exist and not folder_exists: if version is None: - version = "v1" + model_dir = os.path.join(model_dir, f"{found_model_name}-v1") + else: + model_dir = os.path.join(model_dir, f"{found_model_name}-v{version}") - model_dir = os.path.join(model_dir, f"{found_model_name}-v{version}") return model_dir + top_level_has_specific_file = specific_file is not None and os.path.isfile(os.path.join(model_dir, specific_file)) + + if version is None and top_level_has_specific_file: + return model_dir model_subfolders = _get_model_subfolders(model_dir, model_regex) if len(model_subfolders) == 0: + if top_level_has_specific_file: + return model_dir if must_exist: raise ValueError(f"No model folders found for {model_search_name}\nSearched in {model_dir}") else: @@ -653,8 +660,6 @@ def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exi elif len(matching_models) > 1: raise ValueError(f"Multiple directories found for {model_search_name} with version {version}\nSearched in {model_dir}") - top_level_has_specific_file = specific_file is not None and os.path.isfile(os.path.join(model_dir, specific_file)) - if top_level_has_specific_file: return model_dir From 24774394b627ea73525b5151d230aa6aa3aa7c38 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 18 Sep 2024 18:36:46 -0600 Subject: [PATCH 75/94] Update DIS_DUNE --- resources/examples/example1/DIS_DUNE.py | 107 +++++++++++++----------- 1 file changed, 60 insertions(+), 47 deletions(-) diff --git a/resources/examples/example1/DIS_DUNE.py b/resources/examples/example1/DIS_DUNE.py index 7bf411915..de72b9be7 100644 --- a/resources/examples/example1/DIS_DUNE.py +++ b/resources/examples/example1/DIS_DUNE.py @@ -1,67 +1,80 @@ import os - import siren -from siren.SIREN_Controller import SIREN_Controller +from siren import utilities # Number of events to inject events_to_inject = int(1e5) -# Expeirment to run +# Experiment to run experiment = "DUNEFD" - -# Define the controller -controller = SIREN_Controller(events_to_inject, experiment) - -# Particle to inject +detector_model = utilities.load_detector(experiment) primary_type = siren.dataclasses.Particle.ParticleType.NuMu - -cross_section_model = "CSMSDISSplines" - -xsfiledir = siren.utilities.get_cross_section_model_path(cross_section_model) - -# Cross Section Model target_type = siren.dataclasses.Particle.ParticleType.Nucleon -DIS_xs = siren.interactions.DISFromSpline( - os.path.join(xsfiledir, "dsdxdy_nu_CC_iso.fits"), - os.path.join(xsfiledir, "sigma_nu_CC_iso.fits"), - [primary_type], - [target_type], "m" +# Primary interactions and distributions +primary_processes, _ = utilities.load_processes( + "CSMSDISSplines", # model_name + primary_types=[primary_type], + target_types=[target_type], + isoscalar=True, # for isoscalar splines + process_types=["CC"] # specify the process type, e.g., "CC" for charged current ) -primary_xs = siren.interactions.InteractionCollection(primary_type, [DIS_xs]) -controller.SetInteractions(primary_xs) - -# Primary distributions -primary_injection_distributions = {} -primary_physical_distributions = {} - -# energy distribution +# Energy distribution edist = siren.distributions.PowerLaw(1, 1e3, 1e6) -primary_injection_distributions["energy"] = edist -primary_physical_distributions["energy"] = edist -# direction distribution +# Direction distribution direction_distribution = siren.distributions.IsotropicDirection() -primary_injection_distributions["direction"] = direction_distribution -primary_physical_distributions["direction"] = direction_distribution -# position distribution +# Position distribution muon_range_func = siren.distributions.LeptonDepthFunction() position_distribution = siren.distributions.ColumnDepthPositionDistribution( - 60, 60.0, muon_range_func, set(controller.GetDetectorModelTargets()[0]) -) -primary_injection_distributions["position"] = position_distribution - -# SetProcesses -controller.SetProcesses( - primary_type, primary_injection_distributions, primary_physical_distributions -) - -controller.Initialize() - -events = controller.GenerateEvents() - + 60, 60.0, muon_range_func) + + +# Define injection distributions +primary_injection_distributions = { + "energy": edist, + "direction": direction_distribution, + "position": position_distribution +} + +# Set up the Injector +injector = siren.injection.Injector() +injector.number_of_events = events_to_inject +injector.detector_model = detector_model +injector.primary_type = primary_type +injector.primary_interactions = primary_processes[primary_type] +injector.primary_injection_distributions = [ + siren.distributions.PrimaryMass(0), + edist, + direction_distribution, + position_distribution +] + +# Generate events +event = injector.generate_event() + +# Set up the Weighter for event weighting +weighter = siren.injection.Weighter() +weighter.injectors = [injector] +weighter.detector_model = detector_model +weighter.primary_type = primary_type +weighter.primary_interactions = primary_processes[primary_type] +weighter.primary_physical_distributions = [ + edist, + direction_distribution, + position_distribution +] + +# Compute weight +weight = weighter(event) + +# Output events and weights os.makedirs("output", exist_ok=True) +print(str(event)) +print(f"Event weight: {weight}") + +# Save events +# TODO -controller.SaveEvents("output/DUNE_DIS") \ No newline at end of file From a5cb6dfb8128d4c9db3985a38c449be34c6f6981 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 18 Sep 2024 18:46:04 -0600 Subject: [PATCH 76/94] Remove position dist from physical dists --- resources/examples/example1/DIS_DUNE.py | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/examples/example1/DIS_DUNE.py b/resources/examples/example1/DIS_DUNE.py index de72b9be7..4f094479b 100644 --- a/resources/examples/example1/DIS_DUNE.py +++ b/resources/examples/example1/DIS_DUNE.py @@ -64,7 +64,6 @@ weighter.primary_physical_distributions = [ edist, direction_distribution, - position_distribution ] # Compute weight From 35c05c54fd3a25ebec452ca0d0e138eaa21dd9f3 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 18 Sep 2024 18:52:52 -0600 Subject: [PATCH 77/94] DIS_IceCube --- resources/examples/example1/DIS_IceCube.py | 106 ++++++++++----------- 1 file changed, 52 insertions(+), 54 deletions(-) diff --git a/resources/examples/example1/DIS_IceCube.py b/resources/examples/example1/DIS_IceCube.py index db9913512..f4c2bb2d3 100644 --- a/resources/examples/example1/DIS_IceCube.py +++ b/resources/examples/example1/DIS_IceCube.py @@ -1,71 +1,69 @@ import os - import siren -from siren.SIREN_Controller import SIREN_Controller +from siren import utilities # Number of events to inject events_to_inject = int(1e5) -# Expeirment to run +# Experiment to run experiment = "IceCube" - -# Define the controller -controller = SIREN_Controller(events_to_inject, experiment) +detector_model = utilities.load_detector(experiment) # Particle to inject primary_type = siren.dataclasses.Particle.ParticleType.NuMu +# Cross-section model to use cross_section_model = "CSMSDISSplines" -xsfiledir = siren.utilities.get_cross_section_model_path(cross_section_model) - -# Cross Section Model -target_type = siren.dataclasses.Particle.ParticleType.Nucleon - -DIS_xs = siren.interactions.DISFromSpline( - os.path.join(xsfiledir, "dsdxdy_nu_CC_iso.fits"), - os.path.join(xsfiledir, "sigma_nu_CC_iso.fits"), - [primary_type], - [target_type], "m" -) - -primary_xs = siren.interactions.InteractionCollection(primary_type, [DIS_xs]) -controller.SetInteractions(primary_xs) - -# Primary distributions -primary_injection_distributions = {} -primary_physical_distributions = {} - -mass_dist = siren.distributions.PrimaryMass(0) -primary_injection_distributions["mass"] = mass_dist -primary_physical_distributions["mass"] = mass_dist - -# energy distribution -edist = siren.distributions.PowerLaw(2, 1e3, 1e6) -primary_injection_distributions["energy"] = edist -primary_physical_distributions["energy"] = edist - -# direction distribution -direction_distribution = siren.distributions.IsotropicDirection() -primary_injection_distributions["direction"] = direction_distribution -primary_physical_distributions["direction"] = direction_distribution - -# position distribution -muon_range_func = siren.distributions.LeptonDepthFunction() -position_distribution = siren.distributions.ColumnDepthPositionDistribution( - 600, 600.0, muon_range_func, set(controller.GetDetectorModelTargets()[0]) -) -primary_injection_distributions["position"] = position_distribution - -# SetProcesses -controller.SetProcesses( - primary_type, primary_injection_distributions, primary_physical_distributions +# Load the cross-section model +primary_processes, _ = utilities.load_processes( + cross_section_model, + primary_types=[primary_type], + target_types=[siren.dataclasses.Particle.ParticleType.Nucleon], + isoscalar=True, + process_types=["CC"] ) -controller.Initialize() - -events = controller.GenerateEvents() - +# Extract the primary cross-sections for the primary type +primary_cross_sections = primary_processes[primary_type] + +# Set up the Injector +injector = siren.injection.Injector() +injector.number_of_events = events_to_inject +injector.detector_model = detector_model +injector.primary_type = primary_type +injector.primary_interactions = primary_cross_sections + +# Directly set the distributions +injector.primary_injection_distributions = [ + siren.distributions.PrimaryMass(0), # Mass distribution + siren.distributions.PowerLaw(2, 1e3, 1e6), # Energy distribution + siren.distributions.IsotropicDirection(), # Direction distribution + siren.distributions.ColumnDepthPositionDistribution(600, 600.0, siren.distributions.LeptonDepthFunction()) # Position distribution +] + +# Generate events +event = injector.generate_event() + +# Set up the Weighter for event weighting (without position distribution) +weighter = siren.injection.Weighter() +weighter.injectors = [injector] +weighter.detector_model = detector_model +weighter.primary_type = primary_type +weighter.primary_interactions = primary_cross_sections +weighter.primary_physical_distributions = [ + siren.distributions.PowerLaw(2, 1e3, 1e6), # Energy distribution + siren.distributions.IsotropicDirection() # Direction distribution +] + +# Compute weight +weight = weighter(event) + +# Output events and weights os.makedirs("output", exist_ok=True) +print(str(event)) +print(f"Event weight: {weight}") + +# Save events +# injector.SaveEvents("output/IceCube_DIS") -controller.SaveEvents("output/IceCube_DIS") From f48fdb3baf29851194ddcecb766b8c51b86a1358 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 18 Sep 2024 21:28:27 -0600 Subject: [PATCH 78/94] Fix method name --- projects/dataclasses/private/pybindings/dataclasses.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/dataclasses/private/pybindings/dataclasses.cxx b/projects/dataclasses/private/pybindings/dataclasses.cxx index ec1196e69..42b9f071d 100644 --- a/projects/dataclasses/private/pybindings/dataclasses.cxx +++ b/projects/dataclasses/private/pybindings/dataclasses.cxx @@ -145,10 +145,10 @@ PYBIND11_MODULE(dataclasses, m) { .def_property_readonly("secondary_particle_records", [](siren::dataclasses::CrossSectionDistributionRecord & cdr) -> std::vector & {return cdr.GetSecondaryParticleRecords();}, py::return_value_policy::reference_internal) - .def("get_econdary_particle_record", + .def("get_secondary_particle_record", [](siren::dataclasses::CrossSectionDistributionRecord & cdr, size_t i) -> siren::dataclasses::SecondaryParticleRecord & {return cdr.GetSecondaryParticleRecord(i);}, py::return_value_policy::reference_internal) - .def("get_econdary_particle_records", + .def("get_secondary_particle_records", [](siren::dataclasses::CrossSectionDistributionRecord & cdr) -> std::vector & {return cdr.GetSecondaryParticleRecords();}, py::return_value_policy::reference_internal) .def("finalize", &CrossSectionDistributionRecord::Finalize) From 8bf11d75f935de039ec1b32fae65a7c2988210fb Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 18 Sep 2024 21:47:25 -0600 Subject: [PATCH 79/94] Remove old function def. Load detector models correctly. --- python/_util.py | 42 ++---------------------------------------- 1 file changed, 2 insertions(+), 40 deletions(-) diff --git a/python/_util.py b/python/_util.py index 1724c2140..35572ea89 100644 --- a/python/_util.py +++ b/python/_util.py @@ -526,44 +526,6 @@ def _get_model_file_name(version, model_versions, model_files, model_name, suffi else: return f"{model_name}-v{version}{suffix}" -def _get_model_path(model_name, prefix=None, suffix=None, is_file=True, must_exist=True, specific_file=None): - model_regex = re.compile( - r"^\s*" + _MODEL_PATTERN + ("" if suffix is None else r"(?:" + suffix + r")?") + r"\s*$", - re.VERBOSE | re.IGNORECASE, - ) - suffix = "" if suffix is None else suffix - - resources_dir = resource_package_dir() - base_dir = _get_base_directory(resources_dir, prefix) - - d = model_regex.match(model_name) - if d is None: - raise ValueError(f"Invalid model name: {model_name}") - d = d.groupdict() - model_name, version = d["model_name"], d["version"] - - model_name, folder_exists, specific_file_path = _find_model_folder_and_file(base_dir, model_name, must_exist, specific_file) - - if specific_file_path and not version: - return os.path.dirname(specific_file_path) - - model_files = _get_model_files(base_dir, model_name, is_file, folder_exists, version) - model_versions = _extract_model_versions(model_files, model_regex, model_name) - - if len(model_versions) == 0 and must_exist: - if specific_file_path: - return os.path.dirname(specific_file_path) - raise ValueError(f"No model found for {model_name}\nSearched in {os.path.join(base_dir, model_name)}") - - model_file_name = _get_model_file_name(version, model_versions, model_files, model_name, suffix, must_exist) - - if version: - version_dir = os.path.join(base_dir, model_name, f"v{version}") - if os.path.isdir(version_dir): - return os.path.join(version_dir, model_file_name) - - return os.path.join(base_dir, model_name, model_file_name) - def _get_model_folder(base_dir, model_name, must_exist): model_names = [ @@ -741,10 +703,10 @@ def _detector_file_loader(model_name): def load_detector(model_name, *args, **kwargs): - resource = load_resource("flux", model_name, *args, **kwargs) + resource = load_resource("detector", model_name, *args, **kwargs) if resource is not None: return resource - return _detector_file_loader + return _detector_file_loader(model_name) def load_processes(model_name, *args, **kwargs): From 5ebb90149bd3f0970aeac1c17bd12b9815a173c1 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 18 Sep 2024 22:11:48 -0600 Subject: [PATCH 80/94] Fix sampling --- .../processes/DarkNewsTables/DarkNewsDecay.py | 155 +++++++++++++++++- 1 file changed, 154 insertions(+), 1 deletion(-) diff --git a/resources/processes/DarkNewsTables/DarkNewsDecay.py b/resources/processes/DarkNewsTables/DarkNewsDecay.py index 9c076b3d4..0b400c8cd 100644 --- a/resources/processes/DarkNewsTables/DarkNewsDecay.py +++ b/resources/processes/DarkNewsTables/DarkNewsDecay.py @@ -13,6 +13,158 @@ from siren import dataclasses from siren.dataclasses import Particle +# DarkNews methods +import DarkNews +from DarkNews.processes import FermionDileptonDecay, FermionSinglePhotonDecay +from DarkNews import processes as proc +from DarkNews import Cfourvec as Cfv +from DarkNews import phase_space + +def get_decay_momenta_from_vegas_samples(vsamples, MC_case, decay_case, PN_LAB): + """ + Construct the four momenta of all final state particles in the decay process from the + vegas weights. + + Args: + vsamples (np.ndarray): integration samples obtained from vegas + as hypercube coordinates. Always in the interval [0,1]. + + MC_case (DarkNews.process.dec_case): the decay class of DarkNews + + PN_LAB (np.ndarray): four-momentum of the upscattered N in the lab frame: [E, pX, pY, pZ] + + Returns: + dict: each key corresponds to a set of four momenta for a given particle involved, + so the values are 2D np.ndarrays with each row a different event and each column a different + four momentum component. Contains also the weights. + """ + + four_momenta = {} + + # N boost parameters + boost_scattered_N = { + "EP_LAB": PN_LAB.T[0], + "costP_LAB": Cfv.get_cosTheta(PN_LAB), + "phiP_LAB": np.arctan2(PN_LAB.T[2], PN_LAB.T[1]), + } + + ####################### + # DECAY PROCESSES + + if type(decay_case) == proc.FermionDileptonDecay: + + mh = decay_case.m_parent + mf = decay_case.m_daughter + mm = decay_case.mm + mp = decay_case.mm + + if decay_case.vector_on_shell or decay_case.scalar_on_shell: + + if decay_case.vector_on_shell and decay_case.scalar_off_shell: + m_mediator = decay_case.mzprime + elif decay_case.vector_off_shell and decay_case.scalar_on_shell: + m_mediator = decay_case.mhprime + else: + raise NotImplementedError("Both mediators on-shell is not yet implemented.") + + ######################## + ### HNL decay + N_decay_samples = {"unit_cost": np.array(vsamples[0])} + # Ni (k1) --> Nj (k2) Z' (k3) + masses_decay = { + "m1": mh, # Ni + "m2": mf, # Nj + "m3": m_mediator, # Z' + } + # Phnl, Phnl_daughter, Pz' + P1LAB_decay, P2LAB_decay, P3LAB_decay = phase_space.two_body_decay(N_decay_samples, boost=boost_scattered_N, **masses_decay, rng=MC_case.rng) + + # Z' boost parameters + boost_Z = { + "EP_LAB": P3LAB_decay.T[0], + "costP_LAB": Cfv.get_cosTheta(P3LAB_decay), + "phiP_LAB": np.arctan2(P3LAB_decay.T[2], P3LAB_decay.T[1]), + } + + ######################## + ### Z' decay + Z_decay_samples = {} # all uniform + # Z'(k1) --> ell- (k2) ell+ (k3) + masses_decay = { + "m1": m_mediator, # Ni + "m2": mp, # \ell+ + "m3": mm, # \ell- + } + # PZ', pe-, pe+ + P1LAB_decayZ, P2LAB_decayZ, P3LAB_decayZ = phase_space.two_body_decay(Z_decay_samples, boost=boost_Z, **masses_decay, rng=MC_case.rng) + + four_momenta["P_decay_N_parent"] = P1LAB_decay + four_momenta["P_decay_N_daughter"] = P2LAB_decay + four_momenta["P_decay_ell_minus"] = P2LAB_decayZ + four_momenta["P_decay_ell_plus"] = P3LAB_decayZ + + elif decay_case.vector_off_shell and decay_case.scalar_off_shell: + + ######################## + # HNL decay + N_decay_samples = { + "unit_t": vsamples[0], + "unit_u": vsamples[1], + "unit_c3": vsamples[2], + "unit_phi34": vsamples[3], + } + + # Ni (k1) --> ell-(k2) ell+(k3) Nj(k4) + masses_decay = { + "m1": mh, # Ni + "m2": mm, # ell- + "m3": mp, # ell+ + "m4": mf, + } # Nj + # Phnl, pe-, pe+, pnu + ( + P1LAB_decay, + P2LAB_decay, + P3LAB_decay, + P4LAB_decay, + ) = phase_space.three_body_decay(N_decay_samples, boost=boost_scattered_N, **masses_decay, rng=MC_case.rng) + + four_momenta["P_decay_N_parent"] = P1LAB_decay + four_momenta["P_decay_ell_minus"] = P2LAB_decay + four_momenta["P_decay_ell_plus"] = P3LAB_decay + four_momenta["P_decay_N_daughter"] = P4LAB_decay + + elif type(decay_case) == proc.FermionSinglePhotonDecay: + + mh = decay_case.m_parent + mf = decay_case.m_daughter + + ######################## + ### HNL decay + N_decay_samples = {"unit_cost": np.array(vsamples[0])} + # Ni (k1) --> Nj (k2) gamma (k3) + masses_decay = { + "m1": mh, # Ni + "m2": mf, # Nj + "m3": 0.0, # gamma + } + # Phnl, Phnl', Pgamma + P1LAB_decay, P2LAB_decay, P3LAB_decay = phase_space.two_body_decay(N_decay_samples, boost=boost_scattered_N, **masses_decay, rng=MC_case.rng) + + four_momenta["P_decay_N_parent"] = P1LAB_decay + four_momenta["P_decay_N_daughter"] = P2LAB_decay + four_momenta["P_decay_photon"] = P3LAB_decay + + return four_momenta + + +class _FakeMCInterface: + def __init__(self, random): + self.random = random + self.rng_func = np.frompyfunc(lambda x: self.random.Uniform(0, 1), 1, 1) + self.rng = lambda x: self.rng_func(np.empty(x)).astype(float) + + # A class representing a single decay_case DarkNews class # Only handles methods concerning the decay part class PyDarkNewsDecay(DarkNewsDecay): @@ -267,11 +419,12 @@ def SampleRecordFromDarkNews(self, record, random): # Expand dims required to call DarkNews function on signle sample four_momenta = get_decay_momenta_from_vegas_samples( np.expand_dims(PS, 0), + _FakeMCInterface(random), self.dec_case, np.expand_dims(np.array(record.primary_momentum), 0), ) - secondaries = record.GetSecondaryParticleRecords() + secondaries = record.get_secondary_particle_records() if isinstance(self.dec_case, FermionSinglePhotonDecay): gamma_idx = 0 From 1f0cd47832e96f31ce9980fa96f73052980e83ae Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 18 Sep 2024 22:12:11 -0600 Subject: [PATCH 81/94] DipolePortal_CCM --- .../examples/example2/DipolePortal_CCM.py | 111 ++++++++++-------- 1 file changed, 61 insertions(+), 50 deletions(-) diff --git a/resources/examples/example2/DipolePortal_CCM.py b/resources/examples/example2/DipolePortal_CCM.py index 76c6d8d9d..6bd5fa653 100644 --- a/resources/examples/example2/DipolePortal_CCM.py +++ b/resources/examples/example2/DipolePortal_CCM.py @@ -1,13 +1,12 @@ import os import numpy as np - import siren -from siren.SIREN_Controller import SIREN_Controller +from siren import utilities # Define a DarkNews model model_kwargs = { "m4": 0.0235, - "mu_tr_mu4": 6e-7, # GeV^-1 + "mu_tr_mu4": 6e-7, # GeV^-1 "UD4": 0, "Umu4": 0, "epsilon": 0.0, @@ -18,82 +17,94 @@ } # Number of events to inject -events_to_inject = 100000 +events_to_inject = 1 -# Expeirment to run +# Experiment to run experiment = "CCM" - -# Define the controller -controller = SIREN_Controller(events_to_inject, experiment) +detector_model = utilities.load_detector(experiment) # Particle to inject primary_type = siren.dataclasses.Particle.ParticleType.NuMu -xs_path = siren.utilities.get_cross_section_model_path(f"DarkNewsTables-v{siren.utilities.darknews_version()}", must_exist=False) -# Define DarkNews Model -table_dir = os.path.join( - xs_path, - "Dipole_M%2.2e_mu%2.2e" % (model_kwargs["m4"], model_kwargs["mu_tr_mu4"]), +# Load DarkNews processes +primary_processes, secondary_processes = utilities.load_processes( + f"DarkNewsTables-v{siren.utilities.darknews_version()}", + primary_type=primary_type, + detector_model = detector_model, + **model_kwargs, ) -controller.InputDarkNewsModel(primary_type, table_dir, **model_kwargs) -# Primary distributions -primary_injection_distributions = {} -primary_physical_distributions = {} +# Mass distribution +mass_ddist = siren.distributions.PrimaryMass(0) -# energy distribution +# Primary distributions nu_energy = 0.02965 # from pi+ DAR edist = siren.distributions.Monoenergetic(nu_energy) -primary_injection_distributions["energy"] = edist -primary_physical_distributions["energy"] = edist -# fill cross section tables at this energy -controller.DN_processes.FillCrossSectionTablesAtEnergy(nu_energy) - -# Flux normalization: -# using the number quoted in 2105.14020, 4.74e9 nu/m^2/s / (6.2e14 POT/s) * 4*pi*20m^2 to get nu/POT flux_units = siren.distributions.NormalizationConstant(3.76e-2) -primary_physical_distributions["flux_units"] = flux_units -# direction distribution: cone from lower W target +# Cone direction distribution opening_angle = np.arctan(5 / 23.0) -# slightly larger than CCM lower_target_origin = siren.math.Vector3D(0, 0, -0.241) detector_origin = siren.math.Vector3D(23, 0, -0.65) lower_dir = detector_origin - lower_target_origin lower_dir.normalize() lower_inj_ddist = siren.distributions.Cone(lower_dir, opening_angle) -phys_ddist = ( - siren.distributions.IsotropicDirection() -) # truly we are isotropic -primary_injection_distributions["direction"] = lower_inj_ddist -primary_physical_distributions["direction"] = phys_ddist +phys_ddist = siren.distributions.IsotropicDirection() -# Position distribution: consider neutrinos from a point source +# Position distribution max_dist = 25 lower_pos_dist = siren.distributions.PointSourcePositionDistribution( - lower_target_origin - detector_origin, max_dist, set(controller.GetDetectorModelTargets()[0]) + lower_target_origin - detector_origin, max_dist, ) -primary_injection_distributions["position"] = lower_pos_dist - -# SetProcesses -controller.SetProcesses( - primary_type, primary_injection_distributions, primary_physical_distributions -) - -controller.Initialize() +primary_injection_distributions = [ + mass_ddist, # Mass distribution + edist, # Energy distribution + lower_inj_ddist, # Direction distribution + lower_pos_dist # Position distribution +] + +primary_physical_distributions = [ + edist, # Energy distribution + phys_ddist, # Direction distribution +] + +fiducial_volume = siren.utilities.get_fiducial_volume(experiment) +secondary_injection_distributions = {} +for secondary_type in secondary_processes.keys(): + secondary_injection_distributions[secondary_type] = [ + siren.distributions.SecondaryBoundedVertexDistribution(fiducial_volume, max_dist) + ] + +# Define stopping condition for the injector def stop(datum, i): secondary_type = datum.record.signature.secondary_types[i] return secondary_type != siren.dataclasses.Particle.ParticleType.N4 -controller.injector.SetStoppingCondition(stop) +injector = siren.injection.Injector() +injector.number_of_events = 1 +injector.detector_model = detector_model +injector.primary_type = primary_type +injector.primary_interactions = primary_processes[primary_type] +injector.primary_injection_distributions = primary_injection_distributions +injector.secondary_interactions = secondary_processes +injector.secondary_injection_distributions = secondary_injection_distributions +injector.stopping_condition = stop + -events = controller.GenerateEvents(fill_tables_at_exit=False) +# Generate events +events = [injector.generate_event() for _ in range(events_to_inject)] +# Output the events os.makedirs("output", exist_ok=True) -controller.SaveEvents( - "output/CCM_Dipole_M%2.2e_mu%2.2e_example" - % (model_kwargs["m4"], model_kwargs["mu_tr_mu4"]), - fill_tables_at_exit=False -) +weighter = siren.injection.Weighter() +weighter.injectors = [injector] +weighter.detector_model = detector_model +weighter.primary_type = primary_type +weighter.primary_interactions = primary_processes[primary_type] +weighter.secondary_interactions = secondary_processes +weighter.primary_physical_distributions = primary_physical_distributions +weighter.secondary_physical_distributions = {} + +weights = [weighter(event) for event in events] From 7a34462b105cd07d919dc15c92766f40544eadf5 Mon Sep 17 00:00:00 2001 From: Marisol Chavez Estrada Date: Fri, 11 Oct 2024 18:30:32 -0400 Subject: [PATCH 82/94] Add ParticleIDs in InteractionRecord to pybindings --- projects/dataclasses/private/pybindings/dataclasses.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/projects/dataclasses/private/pybindings/dataclasses.cxx b/projects/dataclasses/private/pybindings/dataclasses.cxx index 42b9f071d..8687aead6 100644 --- a/projects/dataclasses/private/pybindings/dataclasses.cxx +++ b/projects/dataclasses/private/pybindings/dataclasses.cxx @@ -160,12 +160,16 @@ PYBIND11_MODULE(dataclasses, m) { .def("__str__", [](InteractionRecord const & r) { return to_str(r); }) .def("__repr__", [](InteractionRecord const & r) { return to_repr(r); }) .def_readwrite("signature",&InteractionRecord::signature) + .def_readwrite("primary_id",&InteractionRecord::primary_id) + .def_readwrite("primary_initial_position",&InteractionRecord::primary_initial_position) .def_readwrite("primary_mass",&InteractionRecord::primary_mass) .def_readwrite("primary_momentum",&InteractionRecord::primary_momentum) .def_readwrite("primary_helicity",&InteractionRecord::primary_helicity) + .def_readwrite("target_id",&InteractionRecord::target_id) .def_readwrite("target_mass",&InteractionRecord::target_mass) .def_readwrite("target_helicity",&InteractionRecord::target_helicity) .def_readwrite("interaction_vertex",&InteractionRecord::interaction_vertex) + .def_readwrite("secondary_ids",&InteractionRecord::secondary_ids) .def_readwrite("secondary_masses",&InteractionRecord::secondary_masses) .def_readwrite("secondary_momenta",&InteractionRecord::secondary_momenta) .def_readwrite("secondary_helicities",&InteractionRecord::secondary_helicities) From 00164a1568ee0105b500b592c8d5e089ec215e51 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Fri, 11 Oct 2024 21:03:13 -0600 Subject: [PATCH 83/94] Updates to cmake --- CMakeLists.txt | 94 ++++++++++++++++++++------- projects/dataclasses/CMakeLists.txt | 5 +- projects/detector/CMakeLists.txt | 2 + projects/distributions/CMakeLists.txt | 2 + projects/geometry/CMakeLists.txt | 2 + projects/injection/CMakeLists.txt | 2 + projects/interactions/CMakeLists.txt | 2 + projects/math/CMakeLists.txt | 4 ++ projects/serialization/CMakeLists.txt | 5 ++ projects/utilities/CMakeLists.txt | 5 ++ 10 files changed, 99 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8defbc1b4..6dcf03d54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ -cmake_minimum_required(VERSION 3.3.2 FATAL_ERROR) -cmake_policy(VERSION 3.3.2) +cmake_minimum_required(VERSION 3.20 FATAL_ERROR) +cmake_policy(VERSION 3.20) if(${CMAKE_HOST_SYSTEM_NAME} MATCHES "Darwin") set(MACOSX TRUE) @@ -11,13 +11,14 @@ SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake ${CMAKE_CURRENT_LIST_DIR}/ message(STATUS "CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}") message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}") -set(CIBUILDWHEEL $ENV{CIBUILDWHEEL}) +set(CIBUILDWHEEL "$ENV{CIBUILDWHEEL}") message(STATUS "CIBUILDWHEEL: ${CIBUILDWHEEL}") -if(${CIBUILDWHEEL}) - set(CI_INSTALL_PREFIX $ENV{CI_INSTALL_PREFIX}) +if(CIBUILDWHEEL STREQUAL "1") + set(CI_INSTALL_PREFIX "$ENV{CI_INSTALL_PREFIX}") message(STATUS "CI_INSTALL_PREFIX: ${CI_INSTALL_PREFIX}") endif() + # parse pyproject.toml for the version include(pyproject) @@ -31,21 +32,31 @@ SET(CMAKE_CXX_STANDARD 14) SET(CMAKE_C_STANDARD 99) # set the build type and appropriate flags -option(CMAKE_BUILD_TYPE "" "Release") -set(_FLAGS "-O2 -Wall -fPIC") -set(_FLAGS_DEBUG "-g -O0 -Wall -fPIC") -set(_FLAGS_RELEASE "-O2 -Wall -fPIC -s") +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") +endif() + +# Create an interface library for SIREN compile options +add_library(siren_compile_options INTERFACE) + +# Specify the compile options +target_compile_options(siren_compile_options INTERFACE + -O2 + -Wall + -fPIC + $<$:-g> + $<$:-O0> + $<$:-O2> + $<$:-s> +) + +# Conditionally add -stdlib=libc++ for Clang if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - set(_FLAGS "${_FLAGS} -stdlib=libc++") - set(_FLAGS_DEBUG "${_FLAGS_DEBUG} -stdlib=libc++") - set(_FLAGS_RELEASE "${_FLAGS_RELEASE} -stdlib=libc++") + target_compile_options(siren_compile_options INTERFACE -stdlib=libc++) endif() -set(CMAKE_CXX_FLAGS ${_FLAGS}) -set(CMAKE_CXX_FLAGS_DEBUG ${_FLAGS_DEBUG}) -set(CMAKE_CXX_FLAGS_RELEASE ${_FLAGS_RELEASE}) # override install locations when building python extensions -if(DEFINED SKBUILD) +if(DEFINED SKBUILD_PLATLIB_DIR) cmake_path(RELATIVE_PATH SKBUILD_HEADERS_DIR BASE_DIRECTORY ${SKBUILD_PLATLIB_DIR} OUTPUT_VARIABLE CMAKE_INSTALL_INCLUDEDIR) cmake_path(RELATIVE_PATH SKBUILD_PLATLIB_DIR BASE_DIRECTORY ${SKBUILD_PLATLIB_DIR} OUTPUT_VARIABLE CMAKE_INSTALL_LIBDIR) message(STATUS "Setting include dir to: ${CMAKE_INSTALL_INCLUDEDIR}") @@ -63,12 +74,42 @@ include(pybind11) # load project dependencies include(rk) +if(TARGET rk_static) + target_link_libraries(rk_static INTERFACE siren_compile_options) +endif() +if(TARGET rk_shared) + target_link_libraries(rk_shared INTERFACE siren_compile_options) +endif() include(cereal) +if(TARGET cereal) + target_link_libraries(cereal INTERFACE siren_compile_options) +endif() include(delabella) +if(TARGET delabella_static) + target_link_libraries(delabella_static INTERFACE siren_compile_options) +endif() +if(TARGET delabella_shared) + target_link_libraries(delabella_shared INTERFACE siren_compile_options) +endif() include(CFITSIO) include(photospline) +if(TARGET photospline) + target_link_libraries(photospline INTERFACE siren_compile_options) +endif() include(googletest) +if(TARGET gtest) + target_link_libraries(gtest INTERFACE siren_compile_options) +endif() +if(TARGET gtest_main) + target_link_libraries(gtest_main INTERFACE siren_compile_options) +endif() +if(TARGET gmock) + target_link_libraries(gmock INTERFACE siren_compile_options) +endif() include(NamedType) +if(TARGET NamedType) + target_link_libraries(NamedType INTERFACE siren_compile_options) +endif() # load macros for googletest include(testing) @@ -87,8 +128,9 @@ add_subdirectory(projects/injection) # define the target library add_library(SIREN SHARED) set_property(TARGET SIREN PROPERTY POSITION_INDEPENDENT_CODE ON) +target_link_libraries(SIREN INTERFACE siren_compile_options) -if(${MACOSX}) +if(DEFINED MACOSX AND MACOSX) if(CMAKE_VERSION VERSION_LESS 3.13) target_link_libraries(SIREN PUBLIC "$<$:LINKER:-undefined,dynamic_lookup>") else() @@ -127,12 +169,15 @@ target_link_libraries(SIREN ) endif() +# Export siren_compile_options +install(TARGETS siren_compile_options EXPORT ${PROJECT_NAME}Config) + # define the install path normally or for python package -if(DEFINED SKBUILD) +if(DEFINED SKBUILD_PLATLIB_DIR) set_target_properties(SIREN PROPERTIES BUILD_WITH_INSTALL_RPATH FALSE LINK_FLAGS "-Wl,-rpath,\\\$ORIGIN") - if(${CIBUILDWHEEL}) + if(DEFINED CIBUILDWHEEL AND CIBUILDWHEEL) message(STATUS "Setting SIREN install lib dir to: ${CI_INSTALL_PREFIX}/lib") message(STATUS "Setting SIREN install include dir to: ${CI_INSTALL_PREFIX}/include") install(TARGETS SIREN @@ -183,7 +228,7 @@ else() endif() # optionally package runtime dependencies -if((DEFINED SKBUILD) AND (PACKAGE_SHARED_DEPS)) +if((DEFINED SKBUILD_PLATLIB_DIR) AND (PACKAGE_SHARED_DEPS)) install(CODE "set(SIREN_LIB_FILE \"${PROJECT_BINARY_DIR}/${CMAKE_SHARED_MODULE_PREFIX}SIREN${CMAKE_SHARED_MODULE_SUFFIX}\")") install(CODE "set(PYTHON_DEP_LIB_DESTINATION \"${SKBUILD_PLATLIB_DIR}/siren.libs/\")") install(CODE [[ @@ -209,7 +254,7 @@ if((DEFINED SKBUILD) AND (PACKAGE_SHARED_DEPS)) endif() # install the python extensions -if(DEFINED SKBUILD) +if(DEFINED SKBUILD_PLATLIB_DIR) install(TARGETS utilities LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/siren) install(TARGETS math @@ -241,7 +286,8 @@ write_basic_package_version_file( VERSION ${PROJECT_VERSION} COMPATIBILITY AnyNewerVersion ) -export(EXPORT ${PROJECT_NAME}Config FILE ${PROJECT_NAME}Config.cmake) +export(EXPORT ${PROJECT_NAME}Config FILE "${PROJECT_NAME}Config.cmake" + NAMESPACE ${PROJECT_NAME}::) # Make importable from install location set(_config_dir share/${PROJECT_NAME}/cmake) @@ -249,7 +295,9 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" DESTINATION ${_config_dir} ) install(EXPORT ${PROJECT_NAME}Config - DESTINATION ${_config_dir} + FILE "${PROJECT_NAME}Config.cmake" + NAMESPACE ${PROJECT_NAME}:: + DESTINATION "${_config_dir}" ) MESSAGE("") diff --git a/projects/dataclasses/CMakeLists.txt b/projects/dataclasses/CMakeLists.txt index 2a7cda1f9..9a5448565 100644 --- a/projects/dataclasses/CMakeLists.txt +++ b/projects/dataclasses/CMakeLists.txt @@ -16,7 +16,10 @@ target_include_directories(SIREN_dataclasses PUBLIC $ ) -target_link_libraries(SIREN_dataclasses PUBLIC +target_link_libraries(SIREN_dataclasses + INTERFACE + siren_compile_options + PUBLIC photospline SIREN_serialization SIREN_utilities diff --git a/projects/detector/CMakeLists.txt b/projects/detector/CMakeLists.txt index 5942a65e4..4a132bd7c 100644 --- a/projects/detector/CMakeLists.txt +++ b/projects/detector/CMakeLists.txt @@ -25,6 +25,8 @@ target_include_directories(SIREN_detector PUBLIC ) target_link_libraries(SIREN_detector + INTERFACE + siren_compile_options PRIVATE $ PUBLIC diff --git a/projects/distributions/CMakeLists.txt b/projects/distributions/CMakeLists.txt index 71faec669..897821a6f 100644 --- a/projects/distributions/CMakeLists.txt +++ b/projects/distributions/CMakeLists.txt @@ -42,6 +42,8 @@ target_include_directories(SIREN_distributions PUBLIC ) target_link_libraries(SIREN_distributions + INTERFACE + siren_compile_options PRIVATE $ pybind11::embed diff --git a/projects/geometry/CMakeLists.txt b/projects/geometry/CMakeLists.txt index fc37d3e00..62b4c0dff 100644 --- a/projects/geometry/CMakeLists.txt +++ b/projects/geometry/CMakeLists.txt @@ -18,6 +18,8 @@ target_include_directories(SIREN_geometry PUBLIC ) target_link_libraries(SIREN_geometry + INTERFACE + siren_compile_options PRIVATE $ PUBLIC diff --git a/projects/injection/CMakeLists.txt b/projects/injection/CMakeLists.txt index e0956aee2..d8e91a2b7 100644 --- a/projects/injection/CMakeLists.txt +++ b/projects/injection/CMakeLists.txt @@ -14,6 +14,8 @@ target_include_directories(SIREN_injection PUBLIC ) target_link_libraries(SIREN_injection + INTERFACE + siren_compile_options PRIVATE $ pybind11::embed diff --git a/projects/interactions/CMakeLists.txt b/projects/interactions/CMakeLists.txt index c6ee384d2..4c0b6505b 100644 --- a/projects/interactions/CMakeLists.txt +++ b/projects/interactions/CMakeLists.txt @@ -26,6 +26,8 @@ target_include_directories(SIREN_interactions PUBLIC ) target_link_libraries(SIREN_interactions + INTERFACE + siren_compile_options PRIVATE $ pybind11::embed diff --git a/projects/math/CMakeLists.txt b/projects/math/CMakeLists.txt index db2aa36c4..1bde95e3a 100644 --- a/projects/math/CMakeLists.txt +++ b/projects/math/CMakeLists.txt @@ -17,6 +17,8 @@ target_include_directories(SIREN_math PUBLIC if(${MACOSX}) target_link_libraries(SIREN_math + INTERFACE + siren_compile_options PUBLIC photospline delabella_shared @@ -26,6 +28,8 @@ target_link_libraries(SIREN_math ) else() target_link_libraries(SIREN_math + INTERFACE + siren_compile_options PUBLIC photospline delabella_shared diff --git a/projects/serialization/CMakeLists.txt b/projects/serialization/CMakeLists.txt index f5e385c9f..c7983051b 100644 --- a/projects/serialization/CMakeLists.txt +++ b/projects/serialization/CMakeLists.txt @@ -4,6 +4,11 @@ target_include_directories(SIREN_serialization INTERFACE $ ) +target_link_libraries(SIREN_serialization + INTERFACE + siren_compile_options +) + install(DIRECTORY "${PROJECT_SOURCE_DIR}/projects/serialization/public/" EXPORT ${PROJECT_NAME}Config DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} diff --git a/projects/utilities/CMakeLists.txt b/projects/utilities/CMakeLists.txt index 5ad24dfaa..a8c9c11af 100644 --- a/projects/utilities/CMakeLists.txt +++ b/projects/utilities/CMakeLists.txt @@ -12,6 +12,11 @@ target_include_directories(SIREN_utilities PUBLIC $ ) +target_link_libraries(SIREN_utilities + INTERFACE + siren_compile_options +) + install(DIRECTORY "${PROJECT_SOURCE_DIR}/projects/utilities/public/" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING From 6e56833ce3194ac8cf5d1253da8cbb39d9fb77a0 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Fri, 11 Oct 2024 21:18:08 -0600 Subject: [PATCH 84/94] FPIC for rk_static --- vendor/rk/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/vendor/rk/CMakeLists.txt b/vendor/rk/CMakeLists.txt index cc15f75cd..f28dd9353 100644 --- a/vendor/rk/CMakeLists.txt +++ b/vendor/rk/CMakeLists.txt @@ -30,6 +30,7 @@ LIST(APPEND rk_HEADERS ) add_library(rk_static STATIC ${rk_SOURCES}) +set_property(TARGET rk_static PROPERTY POSITION_INDEPENDENT_CODE ON) add_library(rk_shared SHARED ${rk_SOURCES}) set_target_properties(rk_static PROPERTIES EXPORT_NAME rk) set_target_properties(rk_shared PROPERTIES EXPORT_NAME rk) From 404562cf8a81d99dae7b18a6a165f9ca45cdfadc Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Fri, 11 Oct 2024 21:24:49 -0600 Subject: [PATCH 85/94] Update pyproject.toml --- pyproject.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 567f40948..41912cfce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,6 @@ build-backend = "scikit_build_core.build" [tool.scikit-build] wheel.packages = [] cmake.build-type = "Release" -#wheel.install-dir = "siren" [tool.scikit-build.cmake.define] CMAKE_PREFIX_PATH="/tmp/downloads/local" @@ -44,7 +43,7 @@ description = "Sampling and Injection for Rare EveNts: A neutrino and rare-proce readme = "README.md" requires-python = ">=3.8" license = {file = "LICENSE"} -keywords = ["physics", "hep", "netrino", "bsm", "simulation", "injection", "weighting"] +keywords = ["physics", "hep", "neutrino", "bsm", "simulation", "injection", "weighting"] authors = [ {name = "Austin Schneider", email = "aschn@mit.edu"}, {name = "Nicholas Kamp", email = "nkamp@fas.harvard.edu"} @@ -85,7 +84,7 @@ DarkNews = ["DarkNews>=0.4.2"] Homepage = "https://github.com/Harvard-Neutrino/SIREN" Documentation = "https://readthedocs.org" Repository = "https://github.com/Harvard-Neutrino/SIREN.git" -Issues = "https://github.com/Harvard-Neutrino/LeptonInjector/issues" +Issues = "https://github.com/Harvard-Neutrino/SIREN/issues" [wheel] no-clean = true From 3ca8e2d631c90b37b16706cb282a0f3328beeccb Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Tue, 15 Oct 2024 13:27:43 -0600 Subject: [PATCH 86/94] Remove extension --- projects/injection/private/Injector.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/injection/private/Injector.cxx b/projects/injection/private/Injector.cxx index d6e8ff059..2d361869f 100644 --- a/projects/injection/private/Injector.cxx +++ b/projects/injection/private/Injector.cxx @@ -496,13 +496,13 @@ Injector::operator bool() const { } void Injector::SaveInjector(std::string const & filename) const { - std::ofstream os(filename+".siren_injector", std::ios::binary); + std::ofstream os(filename, std::ios::binary); ::cereal::BinaryOutputArchive archive(os); this->save(archive,0); } void Injector::LoadInjector(std::string const & filename) { - std::ifstream is(filename+".siren_injector", std::ios::binary); + std::ifstream is(filename, std::ios::binary); ::cereal::BinaryInputArchive archive(is); this->load(archive,0); } From 6adc857e10be0f393c1d80aecdead8f8793380ec Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Tue, 15 Oct 2024 13:28:03 -0600 Subject: [PATCH 87/94] Remove methods that are not needed in the python interface --- projects/injection/private/pybindings/injection.cxx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/projects/injection/private/pybindings/injection.cxx b/projects/injection/private/pybindings/injection.cxx index 74a2ce20b..5159dbc8f 100644 --- a/projects/injection/private/pybindings/injection.cxx +++ b/projects/injection/private/pybindings/injection.cxx @@ -47,7 +47,6 @@ PYBIND11_MODULE(injection,m) { .def_property("primary_type", &Process::GetPrimaryType, &Process::SetPrimaryType) .def_property("interactions", &Process::GetInteractions, &Process::SetInteractions) .def_property("distributions", &PhysicalProcess::GetPhysicalDistributions, &PhysicalProcess::SetPhysicalDistributions) - .def("AddPhysicalDistribution",&PhysicalProcess::AddPhysicalDistribution); class_, Process>(m, "PrimaryInjectionProcess") .def(init<>()) @@ -55,7 +54,6 @@ PYBIND11_MODULE(injection,m) { .def_property("primary_type", &Process::GetPrimaryType, &Process::SetPrimaryType) .def_property("interactions", &Process::GetInteractions, &Process::SetInteractions) .def_property("distributions", &PrimaryInjectionProcess::GetPrimaryInjectionDistributions, &PrimaryInjectionProcess::SetPrimaryInjectionDistributions) - .def("AddPrimaryInjectionDistribution",&PrimaryInjectionProcess::AddPrimaryInjectionDistribution); class_, Process>(m, "SecondaryInjectionProcess") .def(init<>()) @@ -63,8 +61,6 @@ PYBIND11_MODULE(injection,m) { .def_property("secondary_type", &SecondaryInjectionProcess::GetSecondaryType, &SecondaryInjectionProcess::SetSecondaryType) .def_property("interactions", &Process::GetInteractions, &Process::SetInteractions) .def_property("distributions", &SecondaryInjectionProcess::GetSecondaryInjectionDistributions, &SecondaryInjectionProcess::SetSecondaryInjectionDistributions) - .def("AddSecondaryInjectionDistribution",&SecondaryInjectionProcess::AddSecondaryInjectionDistribution); - // Injection From 25c4c7e8d43c18fade27ef26b4220f3550f1fbcf Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Tue, 15 Oct 2024 13:33:45 -0600 Subject: [PATCH 88/94] Add functionality for injecting an unlimited number of events. --- projects/injection/private/Injector.cxx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/projects/injection/private/Injector.cxx b/projects/injection/private/Injector.cxx index 2d361869f..a593e1fb8 100644 --- a/projects/injection/private/Injector.cxx +++ b/projects/injection/private/Injector.cxx @@ -399,7 +399,8 @@ double Injector::GenerationProbability(std::shared_ptr 0) ? events_to_inject : 1; + probability *= stat_weight; // only do this for the primary process } for(auto const & dist : process->GetPrimaryInjectionDistributions()) { double prob = dist->GenerationProbability(detector_model, process->GetInteractions(), datum->record); @@ -415,7 +416,8 @@ double Injector::GenerationProbability(siren::dataclasses::InteractionRecord con double probability = 1.0; if(!process) { // assume we are dealing with the primary process process = primary_process; - probability *= events_to_inject; // only do this for the primary process + unsigned int stat_weight = (events_to_inject > 0) ? events_to_inject : 1; + probability *= stat_weight; // only do this for the primary process } for(auto const & dist : process->GetPrimaryInjectionDistributions()) { double prob = dist->GenerationProbability(detector_model, process->GetInteractions(), record); @@ -492,7 +494,7 @@ void Injector::ResetInjectedEvents() { } Injector::operator bool() const { - return injected_events < events_to_inject; + return events_to_inject == 0 or injected_events < events_to_inject; } void Injector::SaveInjector(std::string const & filename) const { From f74be4660463b58c7975ed10a3b4856b9bbbcc59 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 16 Oct 2024 11:27:47 -0600 Subject: [PATCH 89/94] Fix semicolons in pybindings --- projects/injection/private/pybindings/injection.cxx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/projects/injection/private/pybindings/injection.cxx b/projects/injection/private/pybindings/injection.cxx index 5159dbc8f..6cba39685 100644 --- a/projects/injection/private/pybindings/injection.cxx +++ b/projects/injection/private/pybindings/injection.cxx @@ -39,7 +39,8 @@ PYBIND11_MODULE(injection,m) { class_>(m, "Process") .def_property("primary_type", &Process::GetPrimaryType, &Process::SetPrimaryType) - .def_property("interactions", &Process::GetInteractions, &Process::SetInteractions); + .def_property("interactions", &Process::GetInteractions, &Process::SetInteractions) + ; class_, Process>(m, "PhysicalProcess") .def(init<>()) @@ -47,6 +48,7 @@ PYBIND11_MODULE(injection,m) { .def_property("primary_type", &Process::GetPrimaryType, &Process::SetPrimaryType) .def_property("interactions", &Process::GetInteractions, &Process::SetInteractions) .def_property("distributions", &PhysicalProcess::GetPhysicalDistributions, &PhysicalProcess::SetPhysicalDistributions) + ; class_, Process>(m, "PrimaryInjectionProcess") .def(init<>()) @@ -54,6 +56,7 @@ PYBIND11_MODULE(injection,m) { .def_property("primary_type", &Process::GetPrimaryType, &Process::SetPrimaryType) .def_property("interactions", &Process::GetInteractions, &Process::SetInteractions) .def_property("distributions", &PrimaryInjectionProcess::GetPrimaryInjectionDistributions, &PrimaryInjectionProcess::SetPrimaryInjectionDistributions) + ; class_, Process>(m, "SecondaryInjectionProcess") .def(init<>()) @@ -61,6 +64,7 @@ PYBIND11_MODULE(injection,m) { .def_property("secondary_type", &SecondaryInjectionProcess::GetSecondaryType, &SecondaryInjectionProcess::SetSecondaryType) .def_property("interactions", &Process::GetInteractions, &Process::SetInteractions) .def_property("distributions", &SecondaryInjectionProcess::GetSecondaryInjectionDistributions, &SecondaryInjectionProcess::SetSecondaryInjectionDistributions) + ; // Injection @@ -118,7 +122,8 @@ PYBIND11_MODULE(injection,m) { .def("NormalizedPositionProbability",&PrimaryProcessWeighter::NormalizedPositionProbability) .def("PhysicalProbability",&PrimaryProcessWeighter::PhysicalProbability) .def("GenerationProbability",&PrimaryProcessWeighter::GenerationProbability) - .def("EventWeight",&PrimaryProcessWeighter::EventWeight); + .def("EventWeight",&PrimaryProcessWeighter::EventWeight) + ; class_>(m, "SecondaryProcessWeighter") .def(init, std::shared_ptr, std::shared_ptr>()) @@ -126,7 +131,8 @@ PYBIND11_MODULE(injection,m) { .def("NormalizedPositionProbability",&SecondaryProcessWeighter::NormalizedPositionProbability) .def("PhysicalProbability",&SecondaryProcessWeighter::PhysicalProbability) .def("GenerationProbability",&SecondaryProcessWeighter::GenerationProbability) - .def("EventWeight",&SecondaryProcessWeighter::EventWeight); + .def("EventWeight",&SecondaryProcessWeighter::EventWeight) + ; class_>(m, "Weighter") .def(init>, std::shared_ptr, std::shared_ptr, std::vector>>()) From 82e4905e0eab1fa6dca50ad02a9eb0575e39ba52 Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 23 Oct 2024 14:47:33 -0400 Subject: [PATCH 90/94] Dev/serialization (#85) * Injector serialization via pickle working * Remove cruft * Undo addition to DecaySignature * Remove printouts in DetectorModel serialization * Remove unnecessary cereal macros * Revert changes to link ordering * Remove comments * Don't need global FPIC now that it is handled with an INTERFACE target * Attempt to perform explicit template instantiation for interpolator templates * CMake fixes * Improve logic for finding cfitsio. Make an IMPORT target for cfitsio * Use lists for find_path * Search all paths in secondary searches * Remove printouts * Remove redundant paths for find_library * Link photospline with CFITSIO. Use generator expressions for -s and -stdlib=libc++ * Set policies for macos * Use photospline from icecube git repo. Update photospline and cereal * Remove printouts * Upgrade pybind11 * Use shared_ptr for compatibility of classes without a default constructor * Pickle weighter * Move external headers * pybind11 used in pickle serialization * Pickle serialization for dataclasses * Revert "Upgrade pybind11" This reverts commit add5a6a35600d407e73350b6df7d2869b6fc41ee. --- .gitmodules | 2 +- CMakeLists.txt | 91 +++++++---- cmake/Packages/CFITSIO.cmake | 152 ++++++++++++------ projects/dataclasses/CMakeLists.txt | 5 +- .../private/pybindings/dataclasses.cxx | 23 +++ .../dataclasses/public/SIREN/dataclasses.h | 12 ++ .../public/SIREN/dataclasses/serializable.h | 12 ++ projects/detector/CMakeLists.txt | 16 +- projects/detector/private/Axis1D.cxx | 3 + projects/detector/private/CartesianAxis1D.cxx | 3 + .../CartesianAxisDensityDistribution.cxx | 4 + ...sianAxisExponentialDensityDistribution.cxx | 4 + ...esianAxisPolynomialDensityDistribution.cxx | 4 + .../private/ConstantDensityDistribution.cxx | 9 ++ .../private/ConstantDistribution1D.cxx | 3 + .../detector/private/DensityDistribution.cxx | 3 + .../private/DensityDistribution1D.cxx | 4 + projects/detector/private/DetectorModel.cxx | 3 + projects/detector/private/Distribution1D.cxx | 3 + .../private/ExponentialDistribution1D.cxx | 3 + projects/detector/private/MaterialModel.cxx | 3 + .../private/PolynomialDistribution1D.cxx | 3 + projects/detector/private/RadialAxis1D.cxx | 3 + ...dialAxisExponentialDensityDistribution.cxx | 4 + ...adialAxisPolynomialDensityDistribution.cxx | 9 ++ projects/detector/public/SIREN/detector.h | 26 +++ .../detector/public/SIREN/detector/Axis1D.h | 9 +- .../public/SIREN/detector/CartesianAxis1D.h | 2 + .../CartesianAxisDensityDistribution.h | 7 +- ...tesianAxisExponentialDensityDistribution.h | 2 + ...rtesianAxisPolynomialDensityDistribution.h | 2 + .../detector/ConstantDensityDistribution.h | 9 +- .../SIREN/detector/ConstantDistribution1D.h | 8 +- .../SIREN/detector/DensityDistribution.h | 9 +- .../SIREN/detector/DensityDistribution1D.h | 10 +- .../public/SIREN/detector/DetectorModel.h | 2 + .../public/SIREN/detector/Distribution1D.h | 11 +- .../detector/ExponentialDistribution1D.h | 8 +- .../public/SIREN/detector/MaterialModel.h | 4 +- .../SIREN/detector/PolynomialDistribution1D.h | 8 +- .../public/SIREN/detector/RadialAxis1D.h | 2 + ...RadialAxisExponentialDensityDistribution.h | 2 + .../RadialAxisPolynomialDensityDistribution.h | 7 +- .../public/SIREN/detector/serializable.h | 23 +++ projects/distributions/CMakeLists.txt | 5 +- .../public/SIREN/distributions.h | 37 +++++ .../public/SIREN/distributions/serializable.h | 37 +++++ projects/geometry/CMakeLists.txt | 7 +- projects/geometry/private/Geometry.cxx | 3 + projects/geometry/private/Sphere.cxx | 3 + projects/geometry/public/SIREN/geometry.h | 13 ++ .../geometry/public/SIREN/geometry/Geometry.h | 3 + .../geometry/public/SIREN/geometry/Sphere.h | 4 +- .../public/SIREN/geometry/serializable.h | 12 ++ projects/injection/CMakeLists.txt | 11 +- .../private/pybindings/injection.cxx | 35 +++- projects/injection/public/SIREN/injection.h | 9 ++ .../public/SIREN/injection/Injector.h | 2 - .../public/SIREN/injection/Weighter.h | 7 +- .../public/SIREN/injection/serializable.h | 8 + projects/interactions/CMakeLists.txt | 5 +- .../interactions/public/SIREN/interactions.h | 21 +++ .../public/SIREN/interactions/HNLDecay.h | 2 +- .../public/SIREN/interactions/serializable.h | 16 ++ projects/math/CMakeLists.txt | 6 +- projects/math/public/SIREN/math.h | 13 ++ .../math/public/SIREN/math/serializable.h | 11 ++ projects/serialization/CMakeLists.txt | 14 +- .../serialization/private/serialization.cxx | 11 ++ .../public/SIREN/serialization/ByteString.h | 104 ++++++++++++ projects/utilities/CMakeLists.txt | 5 +- projects/utilities/private/Interpolator.cxx | 19 +++ projects/utilities/public/SIREN/utilities.h | 13 ++ .../public/SIREN/utilities/Interpolator.h | 17 +- .../public/SIREN/utilities/serializable.h | 5 + python/Injector.py | 31 +++- python/Weighter.py | 4 +- python/__init__.py | 6 +- vendor/cereal | 2 +- vendor/photospline | 2 +- 80 files changed, 861 insertions(+), 174 deletions(-) create mode 100644 projects/dataclasses/public/SIREN/dataclasses.h create mode 100644 projects/dataclasses/public/SIREN/dataclasses/serializable.h create mode 100644 projects/detector/private/CartesianAxisDensityDistribution.cxx create mode 100644 projects/detector/private/CartesianAxisExponentialDensityDistribution.cxx create mode 100644 projects/detector/private/CartesianAxisPolynomialDensityDistribution.cxx create mode 100644 projects/detector/private/ConstantDensityDistribution.cxx create mode 100644 projects/detector/private/DensityDistribution1D.cxx create mode 100644 projects/detector/private/RadialAxisExponentialDensityDistribution.cxx create mode 100644 projects/detector/private/RadialAxisPolynomialDensityDistribution.cxx create mode 100644 projects/detector/public/SIREN/detector.h create mode 100644 projects/detector/public/SIREN/detector/serializable.h create mode 100644 projects/distributions/public/SIREN/distributions.h create mode 100644 projects/distributions/public/SIREN/distributions/serializable.h create mode 100644 projects/geometry/public/SIREN/geometry.h create mode 100644 projects/geometry/public/SIREN/geometry/serializable.h create mode 100644 projects/injection/public/SIREN/injection.h create mode 100644 projects/injection/public/SIREN/injection/serializable.h create mode 100644 projects/interactions/public/SIREN/interactions.h create mode 100644 projects/interactions/public/SIREN/interactions/serializable.h create mode 100644 projects/math/public/SIREN/math.h create mode 100644 projects/math/public/SIREN/math/serializable.h create mode 100644 projects/serialization/private/serialization.cxx create mode 100644 projects/serialization/public/SIREN/serialization/ByteString.h create mode 100644 projects/utilities/public/SIREN/utilities.h create mode 100644 projects/utilities/public/SIREN/utilities/serializable.h diff --git a/.gitmodules b/.gitmodules index fd9eb6b5f..1ef853744 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,7 +13,7 @@ url = https://github.com/austinschneider/delabella.git [submodule "vendor/photospline"] path = vendor/photospline - url = https://github.com/austinschneider/photospline.git + url = https://github.com/icecube/photospline.git [submodule "vendor/NamedType"] path = vendor/NamedType url = https://github.com/joboccara/NamedType.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 6dcf03d54..1e22a18ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,10 @@ cmake_minimum_required(VERSION 3.20 FATAL_ERROR) cmake_policy(VERSION 3.20) if(${CMAKE_HOST_SYSTEM_NAME} MATCHES "Darwin") + set(CMAKE_POLICY_DEFAULT_CMP0042 NEW) + cmake_policy(SET CMP0042 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0068 NEW) + cmake_policy(SET CMP0068 NEW) set(MACOSX TRUE) endif() @@ -36,24 +40,50 @@ if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release") endif() -# Create an interface library for SIREN compile options -add_library(siren_compile_options INTERFACE) +function(apply_siren_compile_options target) + # Check if the target is an INTERFACE target + get_target_property(target_type ${target} TYPE) + get_target_property(target_imported ${target} IMPORTED) -# Specify the compile options -target_compile_options(siren_compile_options INTERFACE - -O2 - -Wall - -fPIC - $<$:-g> - $<$:-O0> - $<$:-O2> - $<$:-s> -) + if("${target_type}" STREQUAL "INTERFACE_LIBRARY") + # Apply compile options to INTERFACE target + target_compile_options(${target} INTERFACE + -O2 + -Wall + -fPIC + $<$:-g> + $<$:-O0> + $<$:-O2> + $<$,$>:-s> + $<$:-stdlib=libc++> + ) + elseif(target_imported) + # Apply compile options to non-INTERFACE target (PRIVATE or PUBLIC) + target_compile_options(${target} INTERFACE + -O2 + -Wall + -fPIC + $<$:-g> + $<$:-O0> + $<$:-O2> + $<$,$>:-s> + $<$:-stdlib=libc++> + ) + else() + # Apply compile options to non-INTERFACE target (PRIVATE or PUBLIC) + target_compile_options(${target} PRIVATE + -O2 + -Wall + -fPIC + $<$:-g> + $<$:-O0> + $<$:-O2> + $<$,$>:-s> + $<$:-stdlib=libc++> + ) + endif() +endfunction() -# Conditionally add -stdlib=libc++ for Clang -if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - target_compile_options(siren_compile_options INTERFACE -stdlib=libc++) -endif() # override install locations when building python extensions if(DEFINED SKBUILD_PLATLIB_DIR) @@ -75,40 +105,44 @@ include(pybind11) # load project dependencies include(rk) if(TARGET rk_static) - target_link_libraries(rk_static INTERFACE siren_compile_options) + apply_siren_compile_options(rk_static) endif() if(TARGET rk_shared) - target_link_libraries(rk_shared INTERFACE siren_compile_options) + apply_siren_compile_options(rk_shared) endif() include(cereal) if(TARGET cereal) - target_link_libraries(cereal INTERFACE siren_compile_options) + apply_siren_compile_options(cereal) endif() include(delabella) if(TARGET delabella_static) - target_link_libraries(delabella_static INTERFACE siren_compile_options) + apply_siren_compile_options(delabella_static) endif() if(TARGET delabella_shared) - target_link_libraries(delabella_shared INTERFACE siren_compile_options) + apply_siren_compile_options(delabella_shared) endif() include(CFITSIO) +if(TARGET CFITSIO) + apply_siren_compile_options(CFITSIO) +endif() include(photospline) if(TARGET photospline) - target_link_libraries(photospline INTERFACE siren_compile_options) + apply_siren_compile_options(photospline) + target_link_libraries(photospline PUBLIC CFITSIO) endif() include(googletest) if(TARGET gtest) - target_link_libraries(gtest INTERFACE siren_compile_options) + apply_siren_compile_options(gtest) endif() if(TARGET gtest_main) - target_link_libraries(gtest_main INTERFACE siren_compile_options) + apply_siren_compile_options(gtest_main) endif() if(TARGET gmock) - target_link_libraries(gmock INTERFACE siren_compile_options) + apply_siren_compile_options(gmock) endif() include(NamedType) if(TARGET NamedType) - target_link_libraries(NamedType INTERFACE siren_compile_options) + apply_siren_compile_options(NamedType) endif() # load macros for googletest @@ -128,7 +162,7 @@ add_subdirectory(projects/injection) # define the target library add_library(SIREN SHARED) set_property(TARGET SIREN PROPERTY POSITION_INDEPENDENT_CODE ON) -target_link_libraries(SIREN INTERFACE siren_compile_options) +apply_siren_compile_options(SIREN) if(DEFINED MACOSX AND MACOSX) if(CMAKE_VERSION VERSION_LESS 3.13) @@ -169,9 +203,6 @@ target_link_libraries(SIREN ) endif() -# Export siren_compile_options -install(TARGETS siren_compile_options EXPORT ${PROJECT_NAME}Config) - # define the install path normally or for python package if(DEFINED SKBUILD_PLATLIB_DIR) set_target_properties(SIREN PROPERTIES diff --git a/cmake/Packages/CFITSIO.cmake b/cmake/Packages/CFITSIO.cmake index 1ac0bdaae..4edcad79b 100644 --- a/cmake/Packages/CFITSIO.cmake +++ b/cmake/Packages/CFITSIO.cmake @@ -12,55 +12,105 @@ # CFITSIO_LDFLAGS # ################################################################################ -SET (CFITSIO_FIND_QUIETLY TRUE) -SET (CFITSIO_FIND_REQUIRED TRUE) - -IF (NOT CFITSIO_FOUND) - - # Search user environment for headers, then default paths; extract version - FIND_PATH (CFITSIO_INCLUDE_DIR fitsio.h - PATHS $ENV{CFITSIOROOT}/include - NO_DEFAULT_PATH) - FIND_PATH (CFITSIO_INCLUDE_DIR fitsio.h) - if(CFITSIO_INCLUDE_DIR) - GET_FILENAME_COMPONENT (CFITSIOROOT ${CFITSIO_INCLUDE_DIR} PATH) - else() - FIND_PATH (CFITSIO_INCLUDE_DIR cfitsio/fitsio.h - PATHS $ENV{CFITSIOROOT}/include - ) - SET(CFITSIO_INCLUDE_DIR "${CFITSIO_INCLUDE_DIR}/cfitsio" CACHE PATH "Path to cfitsio headers" FORCE) - endif() - - SET (CFITSIO_VERSION 0) - IF (CFITSIO_INCLUDE_DIR) - FILE (READ "${CFITSIO_INCLUDE_DIR}/fitsio.h" _cfitsio_VERSION) - STRING (REGEX REPLACE ".*define CFITSIO_VERSION ([0-9]+\\.[0-9]+).*" "\\1" - CFITSIO_VERSION "${_cfitsio_VERSION}") - ENDIF (CFITSIO_INCLUDE_DIR) - - # Search user environment for libraries, then default paths - FIND_LIBRARY (CFITSIO_LIBRARIES NAMES cfitsio - PATHS $ENV{CFITSIOROOT}/lib - NO_DEFAULT_PATH) - FIND_LIBRARY (CFITSIO_LIBRARIES NAMES cfitsio) - GET_FILENAME_COMPONENT (CFITSIO_LIB_DIR ${CFITSIO_LIBRARIES} PATH) - - # Set CFITSIO_FOUND and error out if cfitsio is not found - INCLUDE (FindPackageHandleStandardArgs) - FIND_PACKAGE_HANDLE_STANDARD_ARGS (CFITSIO - DEFAULT_MSG CFITSIO_LIBRARIES CFITSIO_INCLUDE_DIR) - ADD_DEFINITIONS ("-I${CFITSIO_INCLUDE_DIR}") - - IF (CFITSIO_FOUND) - # Set flags and print a status message - MESSAGE (STATUS "CFITSIO version ${CFITSIO_VERSION} found:") - - SET (CFITSIO_CPPFLAGS "-I${CFITSIO_INCLUDE_DIR}") - SET (CFITSIO_LDFLAGS "${CFITSIO_LIBRARIES}") - - MESSAGE (STATUS " * includes: ${CFITSIO_INCLUDE_DIR}") - MESSAGE (STATUS " * libs: ${CFITSIO_LIBRARIES}") - ENDIF (CFITSIO_FOUND) - -ENDIF (NOT CFITSIO_FOUND) +include(FindPackageHandleStandardArgs) + +set(CFITSIO_FIND_QUIETLY TRUE) +set(CFITSIO_FIND_REQUIRED TRUE) + +if (NOT CFITSIO_FOUND) + # Manually parse CPLUS_INCLUDE_PATH to add paths to search + if (DEFINED ENV{CPLUS_INCLUDE_PATH}) + string(REPLACE ":" ";" CFITSIO_INCLUDE_SEARCH_PATH_LIST "$ENV{CPLUS_INCLUDE_PATH}") + else() + set(CFITSIO_INCLUDE_SEARCH_PATH_LIST "") + endif() + + list(PREPEND CFITSIO_INCLUDE_SEARCH_PATH_LIST + $ENV{CFITSIOROOT}/include + ) + + # Search user environment for headers, then default paths; extract version + find_path(CFITSIO_INCLUDE_DIR fitsio.h + PATHS ${CFITSIO_INCLUDE_SEARCH_PATH_LIST} + NO_DEFAULT_PATH + ) + if(NOT CFITSIO_INCLUDE_DIR) + unset(CFITSIO_INCLUDE_DIR) + find_path(CFITSIO_INCLUDE_DIR fitsio.h) + endif() + + if(NOT CFITSIO_INCLUDE_DIR) + unset(CFITSIO_INCLUDE_DIR) + find_path(CFITSIO_INCLUDE_DIR cfitsio/fitsio.h + PATHS ${CFITSIO_INCLUDE_SEARCH_PATH_LIST} + NO_DEFAULT_PATH + ) + if(CFITSIO_INCLUDE_DIR) + set(CFITSIO_INCLUDE_DIR "${CFITSIO_INCLUDE_DIR}/cfitsio" CACHE PATH "Path to cfitsio headers" FORCE) + endif() + endif() + + if(NOT CFITSIO_INCLUDE_DIR) + unset(CFITSIO_INCLUDE_DIR) + find_path(CFITSIO_INCLUDE_DIR cfitsio/fitsio.h) + if(CFITSIO_INCLUDE_DIR) + set(CFITSIO_INCLUDE_DIR "${CFITSIO_INCLUDE_DIR}/cfitsio" CACHE PATH "Path to cfitsio headers" FORCE) + endif() + endif() + + if (CFITSIO_INCLUDE_DIR AND EXISTS "${CFITSIO_INCLUDE_DIR}/fitsio.h") + get_filename_component(CFITSIOROOT ${CFITSIO_INCLUDE_DIR} PATH) + set(CFITSIO_VERSION 0) + file(STRINGS "${CFITSIO_INCLUDE_DIR}/fitsio.h" _cfitsio_VERSION REGEX "#define CFITSIO_VERSION[ \t]+([0-9]+\.[0-9]+)") + string(REGEX REPLACE ".*#define CFITSIO_VERSION[ \t]+([0-9]+\.[0-9]+).*" "\\1" CFITSIO_VERSION "${_cfitsio_VERSION}") + else() + set(CFITSIO_INCLUDE_DIR "CFITSIO_INCLUDE_DIR-NOTFOUND") + endif() + + if (DEFINED ENV{LD_LIBRARY_PATH}) + string(REPLACE ":" ";" CFITSIO_LIBRARY_SEARCH_PATH_LIST "$ENV{LD_LIBRARY_PATH}") + else() + set(CFITSIO_LIBRARY_SEARCH_PATH_LIST "") + endif() + + # Search user environment for libraries, then default paths + find_library(CFITSIO_LIBRARIES cfitsio + PATHS ${CFITSIO_LIBRARY_SEARCH_PATH_LIST} + NO_DEFAULT_PATH + ) + + if(NOT CFITSIO_LIBRARIES) + find_library(CFITSIO_LIBRARIES NAMES cfitsio) + endif() + + if (CFITSIO_LIBRARIES) + get_filename_component(CFITSIO_LIB_DIR ${CFITSIO_LIBRARIES} PATH) + else() + set(CFITSIO_LIBRARIES "CFITSIO_LIBRARIES-NOTFOUND") + endif() + + # Set CFITSIO_FOUND and error out if cfitsio is not found + find_package_handle_standard_args(CFITSIO + REQUIRED_VARS CFITSIO_LIBRARIES CFITSIO_INCLUDE_DIR + VERSION_VAR CFITSIO_VERSION + ) + + if (CFITSIO_FOUND) + # Set flags and print a status message + message(STATUS "CFITSIO version ${CFITSIO_VERSION} found:") + + set(CFITSIO_CPPFLAGS "-I${CFITSIO_INCLUDE_DIR}") + set(CFITSIO_LDFLAGS "${CFITSIO_LIBRARIES}") + + message(STATUS " * includes: ${CFITSIO_INCLUDE_DIR}") + message(STATUS " * libs: ${CFITSIO_LIBRARIES}") + + add_library(CFITSIO SHARED IMPORTED) + target_include_directories(CFITSIO INTERFACE ${CFITSIO_INCLUDE_DIR}) + set_target_properties(CFITSIO PROPERTIES + IMPORTED_LOCATION ${CFITSIO_LIBRARIES}) + else() + message(WARNING "CFITSIO not found. Please ensure CFITSIO is installed and the environment variables CFITSIOROOT, CPLUS_INCLUDE_PATH, LIBRARY_PATH, and LD_LIBRARY_PATH are set correctly.") + endif() +endif() diff --git a/projects/dataclasses/CMakeLists.txt b/projects/dataclasses/CMakeLists.txt index 9a5448565..6575de97f 100644 --- a/projects/dataclasses/CMakeLists.txt +++ b/projects/dataclasses/CMakeLists.txt @@ -17,14 +17,13 @@ target_include_directories(SIREN_dataclasses PUBLIC ) target_link_libraries(SIREN_dataclasses - INTERFACE - siren_compile_options PUBLIC photospline - SIREN_serialization SIREN_utilities + SIREN_serialization SIREN_math ) +apply_siren_compile_options(SIREN_dataclasses) install(DIRECTORY "${PROJECT_SOURCE_DIR}/projects/dataclasses/public/" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} diff --git a/projects/dataclasses/private/pybindings/dataclasses.cxx b/projects/dataclasses/private/pybindings/dataclasses.cxx index 8687aead6..353dadeb7 100644 --- a/projects/dataclasses/private/pybindings/dataclasses.cxx +++ b/projects/dataclasses/private/pybindings/dataclasses.cxx @@ -8,6 +8,9 @@ #include "../../public/SIREN/dataclasses/InteractionSignature.h" #include "../../public/SIREN/dataclasses/InteractionRecord.h" #include "../../public/SIREN/dataclasses/InteractionTree.h" +#include "../../../serialization/public/SIREN/serialization/ByteString.h" + +#include "SIREN/dataclasses/serializable.h" #include #include @@ -52,6 +55,10 @@ PYBIND11_MODULE(dataclasses, m) { .def_readwrite("length",&Particle::length) .def_readwrite("helicity",&Particle::helicity) .def("generate_id",&Particle::GenerateID) + .def(pybind11::pickle( + &(siren::serialization::pickle_save), + &(siren::serialization::pickle_load) + )) ; py::enum_(m, "ParticleType", py::arithmetic()) @@ -67,6 +74,10 @@ PYBIND11_MODULE(dataclasses, m) { .def_readwrite("primary_type",&InteractionSignature::primary_type) .def_readwrite("target_type",&InteractionSignature::target_type) .def_readwrite("secondary_types",&InteractionSignature::secondary_types) + .def(pybind11::pickle( + &(siren::serialization::pickle_save), + &(siren::serialization::pickle_load) + )) ; py::class_>(m, "PrimaryDistributionRecord") @@ -174,6 +185,10 @@ PYBIND11_MODULE(dataclasses, m) { .def_readwrite("secondary_momenta",&InteractionRecord::secondary_momenta) .def_readwrite("secondary_helicities",&InteractionRecord::secondary_helicities) .def_readwrite("interaction_parameters",&InteractionRecord::interaction_parameters) + .def(pybind11::pickle( + &(siren::serialization::pickle_save), + &(siren::serialization::pickle_load) + )) ; py::class_>(m, "InteractionTreeDatum") @@ -182,6 +197,10 @@ PYBIND11_MODULE(dataclasses, m) { .def_readwrite("parent",&InteractionTreeDatum::parent) .def_readwrite("daughters",&InteractionTreeDatum::daughters) .def("depth",&InteractionTreeDatum::depth) + .def(pybind11::pickle( + &(siren::serialization::pickle_save), + &(siren::serialization::pickle_load) + )) ; py::class_>(m, "InteractionTree") @@ -189,6 +208,10 @@ PYBIND11_MODULE(dataclasses, m) { .def_readwrite("tree",&InteractionTree::tree) .def("add_entry",static_cast (InteractionTree::*)(InteractionTreeDatum&,std::shared_ptr)>(&InteractionTree::add_entry)) .def("add_entry",static_cast (InteractionTree::*)(InteractionRecord&,std::shared_ptr)>(&InteractionTree::add_entry)) + .def(pybind11::pickle( + &(siren::serialization::pickle_save), + &(siren::serialization::pickle_load) + )) ; m.def("SaveInteractionTrees",&SaveInteractionTrees); diff --git a/projects/dataclasses/public/SIREN/dataclasses.h b/projects/dataclasses/public/SIREN/dataclasses.h new file mode 100644 index 000000000..6c12dcbcb --- /dev/null +++ b/projects/dataclasses/public/SIREN/dataclasses.h @@ -0,0 +1,12 @@ +#ifndef SIREN_dataclasses_dataclasses_H +#define SIREN_dataclasses_dataclasses_H + +#include "SIREN/dataclasses/DecaySignature.h" +#include "SIREN/dataclasses/InteractionRecord.h" +#include "SIREN/dataclasses/InteractionSignature.h" +#include "SIREN/dataclasses/InteractionTree.h" +#include "SIREN/dataclasses/Particle.h" +#include "SIREN/dataclasses/ParticleID.h" +#include "SIREN/dataclasses/ParticleType.h" + +#endif // SIREN_dataclasses_dataclasses_H diff --git a/projects/dataclasses/public/SIREN/dataclasses/serializable.h b/projects/dataclasses/public/SIREN/dataclasses/serializable.h new file mode 100644 index 000000000..bc3108097 --- /dev/null +++ b/projects/dataclasses/public/SIREN/dataclasses/serializable.h @@ -0,0 +1,12 @@ +#ifndef SIREN_dataclasses_serializable_H +#define SIREN_dataclasses_serializable_H + +#include "SIREN/dataclasses/DecaySignature.h" +#include "SIREN/dataclasses/InteractionRecord.h" +#include "SIREN/dataclasses/InteractionSignature.h" +#include "SIREN/dataclasses/InteractionTree.h" +#include "SIREN/dataclasses/Particle.h" +#include "SIREN/dataclasses/ParticleID.h" +#include "SIREN/dataclasses/ParticleType.h" + +#endif // SIREN_dataclasses_serializable_H diff --git a/projects/detector/CMakeLists.txt b/projects/detector/CMakeLists.txt index 4a132bd7c..8f00cee83 100644 --- a/projects/detector/CMakeLists.txt +++ b/projects/detector/CMakeLists.txt @@ -13,6 +13,13 @@ LIST (APPEND detector_SOURCES ${PROJECT_SOURCE_DIR}/projects/detector/private/ExponentialDistribution1D.cxx ${PROJECT_SOURCE_DIR}/projects/detector/private/DensityDistribution.cxx + ${PROJECT_SOURCE_DIR}/projects/detector/private/DensityDistribution1D.cxx + ${PROJECT_SOURCE_DIR}/projects/detector/private/ConstantDensityDistribution.cxx + ${PROJECT_SOURCE_DIR}/projects/detector/private/CartesianAxisDensityDistribution.cxx + ${PROJECT_SOURCE_DIR}/projects/detector/private/CartesianAxisPolynomialDensityDistribution.cxx + ${PROJECT_SOURCE_DIR}/projects/detector/private/CartesianAxisExponentialDensityDistribution.cxx + ${PROJECT_SOURCE_DIR}/projects/detector/private/RadialAxisPolynomialDensityDistribution.cxx + ${PROJECT_SOURCE_DIR}/projects/detector/private/RadialAxisExponentialDensityDistribution.cxx ${PROJECT_SOURCE_DIR}/projects/detector/private/DetectorModel.cxx ${PROJECT_SOURCE_DIR}/projects/detector/private/MaterialModel.cxx ${PROJECT_SOURCE_DIR}/projects/detector/private/Path.cxx @@ -25,18 +32,17 @@ target_include_directories(SIREN_detector PUBLIC ) target_link_libraries(SIREN_detector - INTERFACE - siren_compile_options - PRIVATE - $ PUBLIC photospline - SIREN_serialization SIREN_utilities + SIREN_serialization SIREN_math SIREN_dataclasses SIREN_geometry + PRIVATE + $ ) +apply_siren_compile_options(SIREN_detector) install(DIRECTORY "${PROJECT_SOURCE_DIR}/projects/detector/public/" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} diff --git a/projects/detector/private/Axis1D.cxx b/projects/detector/private/Axis1D.cxx index edaa27a63..600d512f4 100644 --- a/projects/detector/private/Axis1D.cxx +++ b/projects/detector/private/Axis1D.cxx @@ -27,3 +27,6 @@ bool Axis1D::operator!=(const Axis1D& axis) const { } // namespace siren } // namespace detector + +CEREAL_REGISTER_DYNAMIC_INIT(siren_Axis1D); + diff --git a/projects/detector/private/CartesianAxis1D.cxx b/projects/detector/private/CartesianAxis1D.cxx index d74e96265..a4d13de32 100644 --- a/projects/detector/private/CartesianAxis1D.cxx +++ b/projects/detector/private/CartesianAxis1D.cxx @@ -39,3 +39,6 @@ double CartesianAxis1D::GetdX(const math::Vector3D& xi, const math::Vector3D& di } // namespace siren } // namespace detector + +CEREAL_REGISTER_DYNAMIC_INIT(siren_CartesianAxis1D); + diff --git a/projects/detector/private/CartesianAxisDensityDistribution.cxx b/projects/detector/private/CartesianAxisDensityDistribution.cxx new file mode 100644 index 000000000..682cdda29 --- /dev/null +++ b/projects/detector/private/CartesianAxisDensityDistribution.cxx @@ -0,0 +1,4 @@ +#include "SIREN/detector/CartesianAxisDensityDistribution.h" + +CEREAL_REGISTER_DYNAMIC_INIT(siren_CartesianAxisDensityDistribution); + diff --git a/projects/detector/private/CartesianAxisExponentialDensityDistribution.cxx b/projects/detector/private/CartesianAxisExponentialDensityDistribution.cxx new file mode 100644 index 000000000..18c162e75 --- /dev/null +++ b/projects/detector/private/CartesianAxisExponentialDensityDistribution.cxx @@ -0,0 +1,4 @@ +#include "SIREN/detector/CartesianAxisExponentialDensityDistribution.h" + +CEREAL_REGISTER_DYNAMIC_INIT(siren_CartesianAxisExponentialDensityDistribution); + diff --git a/projects/detector/private/CartesianAxisPolynomialDensityDistribution.cxx b/projects/detector/private/CartesianAxisPolynomialDensityDistribution.cxx new file mode 100644 index 000000000..097c7de13 --- /dev/null +++ b/projects/detector/private/CartesianAxisPolynomialDensityDistribution.cxx @@ -0,0 +1,4 @@ +#include "SIREN/detector/CartesianAxisPolynomialDensityDistribution.h" + +CEREAL_REGISTER_DYNAMIC_INIT(siren_CartesianAxisPolynomialDensityDistribution); + diff --git a/projects/detector/private/ConstantDensityDistribution.cxx b/projects/detector/private/ConstantDensityDistribution.cxx new file mode 100644 index 000000000..d6a9ff984 --- /dev/null +++ b/projects/detector/private/ConstantDensityDistribution.cxx @@ -0,0 +1,9 @@ +#include "SIREN/detector/ConstantDensityDistribution.h" + +// Explicit template instantiation +template class siren::detector::DensityDistribution1D< + siren::detector::CartesianAxis1D, + siren::detector::ConstantDistribution1D>; + +CEREAL_REGISTER_DYNAMIC_INIT(siren_ConstantDensityDistribution); + diff --git a/projects/detector/private/ConstantDistribution1D.cxx b/projects/detector/private/ConstantDistribution1D.cxx index 513af79bb..88fe291fb 100644 --- a/projects/detector/private/ConstantDistribution1D.cxx +++ b/projects/detector/private/ConstantDistribution1D.cxx @@ -41,3 +41,6 @@ double ConstantDistribution1D::Evaluate(double x) const { } // namespace siren } // namespace detector + +CEREAL_REGISTER_DYNAMIC_INIT(siren_ConstantDistribution1D); + diff --git a/projects/detector/private/DensityDistribution.cxx b/projects/detector/private/DensityDistribution.cxx index 8d8743108..873bd0fda 100644 --- a/projects/detector/private/DensityDistribution.cxx +++ b/projects/detector/private/DensityDistribution.cxx @@ -21,3 +21,6 @@ bool DensityDistribution::operator!=(const DensityDistribution& dens_distr) cons } // namespace siren } // namespace detector + +CEREAL_REGISTER_DYNAMIC_INIT(siren_DensityDistribution); + diff --git a/projects/detector/private/DensityDistribution1D.cxx b/projects/detector/private/DensityDistribution1D.cxx new file mode 100644 index 000000000..d65683390 --- /dev/null +++ b/projects/detector/private/DensityDistribution1D.cxx @@ -0,0 +1,4 @@ +#include "SIREN/detector/DensityDistribution1D.h" + +CEREAL_REGISTER_DYNAMIC_INIT(siren_DensityDistribution1D); + diff --git a/projects/detector/private/DetectorModel.cxx b/projects/detector/private/DetectorModel.cxx index 3bdc63051..3a19ea23d 100644 --- a/projects/detector/private/DetectorModel.cxx +++ b/projects/detector/private/DetectorModel.cxx @@ -1757,3 +1757,6 @@ double DetectorModel::GetTargetMass(siren::dataclasses::ParticleType target) con double molar_mass = materials_.GetMolarMass(target); // grams per mole return molar_mass * siren::utilities::Constants::GeV_per_amu; } + +CEREAL_REGISTER_DYNAMIC_INIT(siren_DetectorModel); + diff --git a/projects/detector/private/Distribution1D.cxx b/projects/detector/private/Distribution1D.cxx index f6478801c..c2e0f1ef3 100644 --- a/projects/detector/private/Distribution1D.cxx +++ b/projects/detector/private/Distribution1D.cxx @@ -19,3 +19,6 @@ bool Distribution1D::operator!=(const Distribution1D& dist) const { } // namespace siren } // namespace detector + +CEREAL_REGISTER_DYNAMIC_INIT(siren_Distribution1D); + diff --git a/projects/detector/private/ExponentialDistribution1D.cxx b/projects/detector/private/ExponentialDistribution1D.cxx index d9c231e1c..f20663942 100644 --- a/projects/detector/private/ExponentialDistribution1D.cxx +++ b/projects/detector/private/ExponentialDistribution1D.cxx @@ -41,3 +41,6 @@ double ExponentialDistribution1D::Evaluate(double x) const { } // namespace siren } // namespace detector + +CEREAL_REGISTER_DYNAMIC_INIT(siren_ExponentialDistribution1D); + diff --git a/projects/detector/private/MaterialModel.cxx b/projects/detector/private/MaterialModel.cxx index f19ed8f45..871abb59d 100644 --- a/projects/detector/private/MaterialModel.cxx +++ b/projects/detector/private/MaterialModel.cxx @@ -495,3 +495,6 @@ double MaterialModel::GetEmpericalNuclearBindingEnergy(int strange_count, int ne + L * (c0 * lambda0_mass - c1 - c2 * std::abs(S) / std::pow(A, 2.0/3.0)); return binding_energy_in_MeV * 1e-3; // GeV } + +CEREAL_REGISTER_DYNAMIC_INIT(siren_MaterialModel); + diff --git a/projects/detector/private/PolynomialDistribution1D.cxx b/projects/detector/private/PolynomialDistribution1D.cxx index f86a6c3ef..1a5552ec6 100644 --- a/projects/detector/private/PolynomialDistribution1D.cxx +++ b/projects/detector/private/PolynomialDistribution1D.cxx @@ -54,3 +54,6 @@ double PolynomialDistribution1D::Evaluate(double x) const { } // namespace siren } // namespace detector + +CEREAL_REGISTER_DYNAMIC_INIT(siren_PolynomialDistribution1D); + diff --git a/projects/detector/private/RadialAxis1D.cxx b/projects/detector/private/RadialAxis1D.cxx index fadcd199f..a66dbea6a 100644 --- a/projects/detector/private/RadialAxis1D.cxx +++ b/projects/detector/private/RadialAxis1D.cxx @@ -40,3 +40,6 @@ double RadialAxis1D::GetdX(const math::Vector3D& xi, const math::Vector3D& direc } // namespace siren } // namespace detector + +CEREAL_REGISTER_DYNAMIC_INIT(siren_RadialAxis1D); + diff --git a/projects/detector/private/RadialAxisExponentialDensityDistribution.cxx b/projects/detector/private/RadialAxisExponentialDensityDistribution.cxx new file mode 100644 index 000000000..d15219120 --- /dev/null +++ b/projects/detector/private/RadialAxisExponentialDensityDistribution.cxx @@ -0,0 +1,4 @@ +#include "SIREN/detector/RadialAxisExponentialDensityDistribution.h" + +CEREAL_REGISTER_DYNAMIC_INIT(siren_RadialAxisExponentialDensityDistribution); + diff --git a/projects/detector/private/RadialAxisPolynomialDensityDistribution.cxx b/projects/detector/private/RadialAxisPolynomialDensityDistribution.cxx new file mode 100644 index 000000000..16835d4e1 --- /dev/null +++ b/projects/detector/private/RadialAxisPolynomialDensityDistribution.cxx @@ -0,0 +1,9 @@ +#include "SIREN/detector/RadialAxisPolynomialDensityDistribution.h" + +// Explicit template instantiation +template class siren::detector::DensityDistribution1D< + siren::detector::RadialAxis1D, + siren::detector::PolynomialDistribution1D>; + +CEREAL_REGISTER_DYNAMIC_INIT(siren_RadialAxisPolynomialDensityDistribution); + diff --git a/projects/detector/public/SIREN/detector.h b/projects/detector/public/SIREN/detector.h new file mode 100644 index 000000000..9fc8dafd2 --- /dev/null +++ b/projects/detector/public/SIREN/detector.h @@ -0,0 +1,26 @@ +#ifndef SIREN_detector_detector_H +#define SIREN_detector_detector_H + +#include "SIREN/detector/Axis1D.h" +#include "SIREN/detector/CartesianAxis1D.h" +#include "SIREN/detector/CartesianAxisDensityDistribution.h" +#include "SIREN/detector/CartesianAxisExponentialDensityDistribution.h" +#include "SIREN/detector/CartesianAxisPolynomialDensityDistribution.h" +#include "SIREN/detector/ConstantDensityDistribution.h" +#include "SIREN/detector/ConstantDistribution1D.h" +#include "SIREN/detector/Coordinates.h" +#include "SIREN/detector/DensityDistribution.h" +#include "SIREN/detector/DensityDistribution1D.h" +#include "SIREN/detector/DetectorModel.h" +#include "SIREN/detector/DetectorModel.tcc" +#include "SIREN/detector/Distribution1D.h" +#include "SIREN/detector/ExponentialDistribution1D.h" +#include "SIREN/detector/MaterialModel.h" +#include "SIREN/detector/MaterialModel.tcc" +#include "SIREN/detector/Path.h" +#include "SIREN/detector/PolynomialDistribution1D.h" +#include "SIREN/detector/RadialAxis1D.h" +#include "SIREN/detector/RadialAxisExponentialDensityDistribution.h" +#include "SIREN/detector/RadialAxisPolynomialDensityDistribution.h" + +#endif // SIREN_detector_detector_H diff --git a/projects/detector/public/SIREN/detector/Axis1D.h b/projects/detector/public/SIREN/detector/Axis1D.h index d4e393152..bc9170234 100644 --- a/projects/detector/public/SIREN/detector/Axis1D.h +++ b/projects/detector/public/SIREN/detector/Axis1D.h @@ -1,6 +1,6 @@ #pragma once -#ifndef SIREN_Axis1D_H -#define SIREN_Axis1D_H +#ifndef SIREN_detector_Axis1D_H +#define SIREN_detector_Axis1D_H #include // for shared_ptr #include // for uint32_t @@ -57,5 +57,8 @@ friend cereal::access; } // namespace siren CEREAL_CLASS_VERSION(siren::detector::Axis1D, 0); +CEREAL_REGISTER_TYPE(siren::detector::Axis1D); -#endif // SIREN_Axis1D_H +CEREAL_FORCE_DYNAMIC_INIT(siren_Axis1D); + +#endif // SIREN_detector_Axis1D_H diff --git a/projects/detector/public/SIREN/detector/CartesianAxis1D.h b/projects/detector/public/SIREN/detector/CartesianAxis1D.h index 9734d3a98..095cc7c67 100644 --- a/projects/detector/public/SIREN/detector/CartesianAxis1D.h +++ b/projects/detector/public/SIREN/detector/CartesianAxis1D.h @@ -53,4 +53,6 @@ CEREAL_CLASS_VERSION(siren::detector::CartesianAxis1D, 0); CEREAL_REGISTER_TYPE(siren::detector::CartesianAxis1D); CEREAL_REGISTER_POLYMORPHIC_RELATION(siren::detector::Axis1D, siren::detector::CartesianAxis1D); +CEREAL_FORCE_DYNAMIC_INIT(siren_CartesianAxis1D); + #endif // SIREN_CartesianAxis1D_H diff --git a/projects/detector/public/SIREN/detector/CartesianAxisDensityDistribution.h b/projects/detector/public/SIREN/detector/CartesianAxisDensityDistribution.h index c5d07e837..13b697ee1 100644 --- a/projects/detector/public/SIREN/detector/CartesianAxisDensityDistribution.h +++ b/projects/detector/public/SIREN/detector/CartesianAxisDensityDistribution.h @@ -18,6 +18,7 @@ #include "SIREN/detector/CartesianAxis1D.h" #include "SIREN/detector/DensityDistribution.h" #include "SIREN/detector/DensityDistribution1D.h" +#include "SIREN/detector/ConstantDistribution1D.h" namespace siren { namespace detector { @@ -46,8 +47,8 @@ class DensityDistribution1D create() override { - return std::shared_ptr(new T(*this)); + std::shared_ptr create() const override { + return std::shared_ptr(new T(*this)); }; double Derivative(const math::Vector3D& xi, @@ -157,4 +158,6 @@ class DensityDistribution1D #include +#include #include #include -#include #include #include "SIREN/math/Vector3D.h" @@ -121,6 +121,9 @@ class DensityDistribution1D; + // Define the specialization that we plan to use typedef DensityDistribution1D ConstantDensityDistribution; @@ -134,4 +137,6 @@ CEREAL_CLASS_VERSION(siren::detector::ConstantDensityDistribution, 0); CEREAL_REGISTER_TYPE(siren::detector::ConstantDensityDistribution); CEREAL_REGISTER_POLYMORPHIC_RELATION(siren::detector::DensityDistribution, siren::detector::ConstantDensityDistribution); -#endif // SIREN_ConstantDensityDistribution.h +CEREAL_FORCE_DYNAMIC_INIT(siren_ConstantDensityDistribution); + +#endif // SIREN_ConstantDensityDistribution_H diff --git a/projects/detector/public/SIREN/detector/ConstantDistribution1D.h b/projects/detector/public/SIREN/detector/ConstantDistribution1D.h index 279a00d96..0b422aadb 100644 --- a/projects/detector/public/SIREN/detector/ConstantDistribution1D.h +++ b/projects/detector/public/SIREN/detector/ConstantDistribution1D.h @@ -1,6 +1,6 @@ #pragma once -#ifndef SIREN_ConstantDistribution1D_H -#define SIREN_ConstantDistribution1D_H +#ifndef SIREN_detector_ConstantDistribution1D_H +#define SIREN_detector_ConstantDistribution1D_H #include // for shared_ptr #include // for uint32_t @@ -50,4 +50,6 @@ CEREAL_CLASS_VERSION(siren::detector::ConstantDistribution1D, 0); CEREAL_REGISTER_TYPE(siren::detector::ConstantDistribution1D); CEREAL_REGISTER_POLYMORPHIC_RELATION(siren::detector::Distribution1D, siren::detector::ConstantDistribution1D); -#endif // SIREN_ConstantDistribution1D_H +CEREAL_FORCE_DYNAMIC_INIT(siren_ConstantDistribution1D); + +#endif // SIREN_detector_ConstantDistribution1D_H diff --git a/projects/detector/public/SIREN/detector/DensityDistribution.h b/projects/detector/public/SIREN/detector/DensityDistribution.h index 054052833..4bb006923 100644 --- a/projects/detector/public/SIREN/detector/DensityDistribution.h +++ b/projects/detector/public/SIREN/detector/DensityDistribution.h @@ -26,8 +26,8 @@ ******************************************************************************/ #pragma once -#ifndef SIREN_DensityDistribution_H -#define SIREN_DensityDistribution_H +#ifndef SIREN_detector_DensityDistribution_H +#define SIREN_detector_DensityDistribution_H #include // for basic_string #include // for shared_ptr @@ -97,6 +97,9 @@ friend cereal::access; } // namespace siren CEREAL_CLASS_VERSION(siren::detector::DensityDistribution, 0); +CEREAL_REGISTER_TYPE(siren::detector::DensityDistribution) -#endif // SIREN_DensityDistribution_H +CEREAL_FORCE_DYNAMIC_INIT(siren_DensityDistribution); + +#endif // SIREN_detector_DensityDistribution_H diff --git a/projects/detector/public/SIREN/detector/DensityDistribution1D.h b/projects/detector/public/SIREN/detector/DensityDistribution1D.h index 4c3ea0539..4df1a1fba 100644 --- a/projects/detector/public/SIREN/detector/DensityDistribution1D.h +++ b/projects/detector/public/SIREN/detector/DensityDistribution1D.h @@ -7,25 +7,27 @@ #include #include +#include #include #include -#include #include #include "SIREN/math/Vector3D.h" #include "SIREN/math/Polynomial.h" #include "SIREN/detector/Axis1D.h" +#include "SIREN/detector/CartesianAxis1D.h" #include "SIREN/detector/Distribution1D.h" #include "SIREN/detector/DensityDistribution.h" +#include "SIREN/detector/ConstantDistribution1D.h" #include "SIREN/utilities/Integration.h" namespace siren { namespace detector { -template ::value && std::is_base_of::value>::type> -class DensityDistribution1D +template ::value && std::is_base_of::value && not (std::is_same::value && std::is_same::value)>::type> +class __attribute__((visibility("default"))) DensityDistribution1D : public DensityDistribution { using T = DensityDistribution1D; private: @@ -150,4 +152,6 @@ class DensityDistribution1D } // namespace detector } // namespace siren +CEREAL_FORCE_DYNAMIC_INIT(siren_DensityDistribution1D); + #endif // SIREN_DensityDistribution1D.h diff --git a/projects/detector/public/SIREN/detector/DetectorModel.h b/projects/detector/public/SIREN/detector/DetectorModel.h index 7b63ae2d1..58db1e35b 100644 --- a/projects/detector/public/SIREN/detector/DetectorModel.h +++ b/projects/detector/public/SIREN/detector/DetectorModel.h @@ -296,4 +296,6 @@ std::ostream& operator<<(std::ostream& oss, siren::detector::DetectorSector & bc CEREAL_CLASS_VERSION(siren::detector::DetectorModel, 0); +CEREAL_FORCE_DYNAMIC_INIT(siren_DetectorModel); + #endif // SIREN_DetectorModel_H diff --git a/projects/detector/public/SIREN/detector/Distribution1D.h b/projects/detector/public/SIREN/detector/Distribution1D.h index 8ae41bb5a..757319ad8 100644 --- a/projects/detector/public/SIREN/detector/Distribution1D.h +++ b/projects/detector/public/SIREN/detector/Distribution1D.h @@ -1,12 +1,14 @@ #pragma once -#ifndef SIREN_Distribution1D_H -#define SIREN_Distribution1D_H +#ifndef SIREN_detector_Distribution1D_H +#define SIREN_detector_Distribution1D_H #include // for shared_ptr #include // for uint32_t #include #include #include +#include +#include namespace siren { namespace detector { @@ -32,5 +34,8 @@ friend cereal::access; } // namespace siren CEREAL_CLASS_VERSION(siren::detector::Distribution1D, 0); +CEREAL_REGISTER_TYPE(siren::detector::Distribution1D); -#endif // SIREN_Distribution1D_H +CEREAL_FORCE_DYNAMIC_INIT(siren_Distribution1D); + +#endif // SIREN_detector_Distribution1D_H diff --git a/projects/detector/public/SIREN/detector/ExponentialDistribution1D.h b/projects/detector/public/SIREN/detector/ExponentialDistribution1D.h index a2b7a14ec..b2aaff071 100644 --- a/projects/detector/public/SIREN/detector/ExponentialDistribution1D.h +++ b/projects/detector/public/SIREN/detector/ExponentialDistribution1D.h @@ -1,6 +1,6 @@ #pragma once -#ifndef SIREN_ExponentialDistribution1D_H -#define SIREN_ExponentialDistribution1D_H +#ifndef SIREN_detector_ExponentialDistribution1D_H +#define SIREN_detector_ExponentialDistribution1D_H #include // for shared_ptr #include // for uint32_t @@ -51,4 +51,6 @@ CEREAL_CLASS_VERSION(siren::detector::ExponentialDistribution1D, 0); CEREAL_REGISTER_TYPE(siren::detector::ExponentialDistribution1D); CEREAL_REGISTER_POLYMORPHIC_RELATION(siren::detector::Distribution1D, siren::detector::ExponentialDistribution1D); -#endif // SIREN_ExponentialDistribution1D_H +CEREAL_FORCE_DYNAMIC_INIT(siren_ExponentialDistribution1D); + +#endif // SIREN_detector_ExponentialDistribution1D_H diff --git a/projects/detector/public/SIREN/detector/MaterialModel.h b/projects/detector/public/SIREN/detector/MaterialModel.h index 66ba9573e..51d3a3a68 100644 --- a/projects/detector/public/SIREN/detector/MaterialModel.h +++ b/projects/detector/public/SIREN/detector/MaterialModel.h @@ -153,11 +153,13 @@ class MaterialModel { } // namespace detector } // namespace siren +#include "SIREN/detector/MaterialModel.tcc" + CEREAL_CLASS_VERSION(siren::detector::MaterialModel, 0); CEREAL_CLASS_VERSION(siren::detector::MaterialModel::Component, 0); CEREAL_CLASS_VERSION(siren::detector::MaterialModel::MaterialComponent, 0); -#include "SIREN/detector/MaterialModel.tcc" +CEREAL_FORCE_DYNAMIC_INIT(siren_MaterialModel); # endif // SIREN_MaterialModel_H diff --git a/projects/detector/public/SIREN/detector/PolynomialDistribution1D.h b/projects/detector/public/SIREN/detector/PolynomialDistribution1D.h index 5e7fcb25c..ef8981ba9 100644 --- a/projects/detector/public/SIREN/detector/PolynomialDistribution1D.h +++ b/projects/detector/public/SIREN/detector/PolynomialDistribution1D.h @@ -1,6 +1,6 @@ #pragma once -#ifndef SIREN_PolynomialDistribution1D_H -#define SIREN_PolynomialDistribution1D_H +#ifndef SIREN_detector_PolynomialDistribution1D_H +#define SIREN_detector_PolynomialDistribution1D_H #include // for shared_ptr #include // for vector @@ -60,4 +60,6 @@ CEREAL_CLASS_VERSION(siren::detector::PolynomialDistribution1D, 0); CEREAL_REGISTER_TYPE(siren::detector::PolynomialDistribution1D); CEREAL_REGISTER_POLYMORPHIC_RELATION(siren::detector::Distribution1D, siren::detector::PolynomialDistribution1D); -#endif // SIREN_PolynomialDistribution1D_H +CEREAL_FORCE_DYNAMIC_INIT(siren_PolynomialDistribution1D); + +#endif // SIREN_detector_PolynomialDistribution1D_H diff --git a/projects/detector/public/SIREN/detector/RadialAxis1D.h b/projects/detector/public/SIREN/detector/RadialAxis1D.h index c66882136..8b77faa17 100644 --- a/projects/detector/public/SIREN/detector/RadialAxis1D.h +++ b/projects/detector/public/SIREN/detector/RadialAxis1D.h @@ -54,4 +54,6 @@ CEREAL_CLASS_VERSION(siren::detector::RadialAxis1D, 0); CEREAL_REGISTER_TYPE(siren::detector::RadialAxis1D); CEREAL_REGISTER_POLYMORPHIC_RELATION(siren::detector::Axis1D, siren::detector::RadialAxis1D); +CEREAL_FORCE_DYNAMIC_INIT(siren_RadialAxis1D); + #endif // SIREN_RadialAxis1D_H diff --git a/projects/detector/public/SIREN/detector/RadialAxisExponentialDensityDistribution.h b/projects/detector/public/SIREN/detector/RadialAxisExponentialDensityDistribution.h index 04faffafa..dac04be7a 100644 --- a/projects/detector/public/SIREN/detector/RadialAxisExponentialDensityDistribution.h +++ b/projects/detector/public/SIREN/detector/RadialAxisExponentialDensityDistribution.h @@ -32,5 +32,7 @@ CEREAL_CLASS_VERSION(siren::detector::RadialAxisExponentialDensityDistribution, CEREAL_REGISTER_TYPE(siren::detector::RadialAxisExponentialDensityDistribution); CEREAL_REGISTER_POLYMORPHIC_RELATION(siren::detector::DensityDistribution, siren::detector::RadialAxisExponentialDensityDistribution); +CEREAL_FORCE_DYNAMIC_INIT(siren_RadialAxisExponentialDensityDistribution); + #endif // SIREN_RadialAxisExponentialDensityDistribution.h diff --git a/projects/detector/public/SIREN/detector/RadialAxisPolynomialDensityDistribution.h b/projects/detector/public/SIREN/detector/RadialAxisPolynomialDensityDistribution.h index 10b6bf907..888ba8fb3 100644 --- a/projects/detector/public/SIREN/detector/RadialAxisPolynomialDensityDistribution.h +++ b/projects/detector/public/SIREN/detector/RadialAxisPolynomialDensityDistribution.h @@ -158,7 +158,10 @@ class DensityDistribution1D }; */ -typedef DensityDistribution1D RadialAxisPolynomialDensityDistribution; +// Declare the explicit specialization (but do not instantiate) +extern template class DensityDistribution1D; + +typedef DensityDistribution1D RadialAxisPolynomialDensityDistribution; } // namespace detector } // namespace siren @@ -167,4 +170,6 @@ CEREAL_CLASS_VERSION(siren::detector::RadialAxisPolynomialDensityDistribution, 0 CEREAL_REGISTER_TYPE(siren::detector::RadialAxisPolynomialDensityDistribution); CEREAL_REGISTER_POLYMORPHIC_RELATION(siren::detector::DensityDistribution, siren::detector::RadialAxisPolynomialDensityDistribution); +CEREAL_FORCE_DYNAMIC_INIT(siren_RadialAxisPolynomialDensityDistribution); + #endif // SIREN_RadialAxisPolynomialDensityDistribution.h diff --git a/projects/detector/public/SIREN/detector/serializable.h b/projects/detector/public/SIREN/detector/serializable.h new file mode 100644 index 000000000..432f9e4f9 --- /dev/null +++ b/projects/detector/public/SIREN/detector/serializable.h @@ -0,0 +1,23 @@ +#ifndef SIREN_detector_serializable_H +#define SIREN_detector_serializable_H + +#include "SIREN/detector/DensityDistribution.h" +#include "SIREN/detector/Distribution1D.h" +#include "SIREN/detector/ConstantDistribution1D.h" +#include "SIREN/detector/PolynomialDistribution1D.h" +#include "SIREN/detector/ExponentialDistribution1D.h" +#include "SIREN/detector/Axis1D.h" +#include "SIREN/detector/RadialAxis1D.h" +#include "SIREN/detector/CartesianAxis1D.h" +#include "SIREN/detector/DensityDistribution1D.h" +#include "SIREN/detector/ConstantDensityDistribution.h" +#include "SIREN/detector/CartesianAxisDensityDistribution.h" +#include "SIREN/detector/CartesianAxisPolynomialDensityDistribution.h" +#include "SIREN/detector/CartesianAxisExponentialDensityDistribution.h" +#include "SIREN/detector/RadialAxisPolynomialDensityDistribution.h" +#include "SIREN/detector/RadialAxisExponentialDensityDistribution.h" +#include "SIREN/detector/MaterialModel.h" +#include "SIREN/detector/DetectorModel.h" +#include "SIREN/detector/Path.h" + +#endif // SIREN_detector_serializable_H diff --git a/projects/distributions/CMakeLists.txt b/projects/distributions/CMakeLists.txt index 897821a6f..1b73519ce 100644 --- a/projects/distributions/CMakeLists.txt +++ b/projects/distributions/CMakeLists.txt @@ -42,21 +42,20 @@ target_include_directories(SIREN_distributions PUBLIC ) target_link_libraries(SIREN_distributions - INTERFACE - siren_compile_options PRIVATE $ pybind11::embed PUBLIC photospline - SIREN_serialization SIREN_utilities + SIREN_serialization SIREN_math SIREN_dataclasses SIREN_geometry SIREN_detector SIREN_interactions ) +apply_siren_compile_options(SIREN_distributions) install(DIRECTORY "${PROJECT_SOURCE_DIR}/projects/distributions/public/" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} diff --git a/projects/distributions/public/SIREN/distributions.h b/projects/distributions/public/SIREN/distributions.h new file mode 100644 index 000000000..62dbf397f --- /dev/null +++ b/projects/distributions/public/SIREN/distributions.h @@ -0,0 +1,37 @@ +#ifndef SIREN_distributions_distributions_H +#define SIREN_distributions_distributions_H + +#include "SIREN/distributions/Distributions.h" + +#include "SIREN/distributions/primary/direction/PrimaryDirectionDistribution.h" +#include "SIREN/distributions/primary/direction/Cone.h" +#include "SIREN/distributions/primary/direction/FixedDirection.h" +#include "SIREN/distributions/primary/direction/IsotropicDirection.h" + +#include "SIREN/distributions/primary/energy/PrimaryEnergyDistribution.h" +#include "SIREN/distributions/primary/energy/ModifiedMoyalPlusExponentialEnergyDistribution.h" +#include "SIREN/distributions/primary/energy/Monoenergetic.h" +#include "SIREN/distributions/primary/energy/PowerLaw.h" +#include "SIREN/distributions/primary/energy/TabulatedFluxDistribution.h" + +#include "SIREN/distributions/primary/helicity/PrimaryNeutrinoHelicityDistribution.h" + +#include "SIREN/distributions/primary/mass/PrimaryMass.h" + +#include "SIREN/distributions/primary/vertex/VertexPositionDistribution.h" +#include "SIREN/distributions/primary/vertex/ColumnDepthPositionDistribution.h" +#include "SIREN/distributions/primary/vertex/CylinderVolumePositionDistribution.h" +#include "SIREN/distributions/primary/vertex/DecayRangeFunction.h" +#include "SIREN/distributions/primary/vertex/DecayRangePositionDistribution.h" +#include "SIREN/distributions/primary/vertex/DepthFunction.h" +#include "SIREN/distributions/primary/vertex/LeptonDepthFunction.h" +#include "SIREN/distributions/primary/vertex/OrientedCylinderPositionDistribution.h" +#include "SIREN/distributions/primary/vertex/PointSourcePositionDistribution.h" +#include "SIREN/distributions/primary/vertex/RangeFunction.h" +#include "SIREN/distributions/primary/vertex/RangePositionDistribution.h" + +#include "SIREN/distributions/secondary/vertex/SecondaryVertexPositionDistribution.h" +#include "SIREN/distributions/secondary/vertex/SecondaryBoundedVertexDistribution.h" +#include "SIREN/distributions/secondary/vertex/SecondaryPhysicalVertexDistribution.h" + +#endif // SIREN_distributions_distributions_H diff --git a/projects/distributions/public/SIREN/distributions/serializable.h b/projects/distributions/public/SIREN/distributions/serializable.h new file mode 100644 index 000000000..0fa9a2da0 --- /dev/null +++ b/projects/distributions/public/SIREN/distributions/serializable.h @@ -0,0 +1,37 @@ +#ifndef SIREN_distributions_serializable_H +#define SIREN_distributions_serializable_H + +#include "SIREN/distributions/Distributions.h" + +#include "SIREN/distributions/primary/direction/PrimaryDirectionDistribution.h" +#include "SIREN/distributions/primary/direction/Cone.h" +#include "SIREN/distributions/primary/direction/FixedDirection.h" +#include "SIREN/distributions/primary/direction/IsotropicDirection.h" + +#include "SIREN/distributions/primary/energy/PrimaryEnergyDistribution.h" +#include "SIREN/distributions/primary/energy/ModifiedMoyalPlusExponentialEnergyDistribution.h" +#include "SIREN/distributions/primary/energy/Monoenergetic.h" +#include "SIREN/distributions/primary/energy/PowerLaw.h" +#include "SIREN/distributions/primary/energy/TabulatedFluxDistribution.h" + +#include "SIREN/distributions/primary/helicity/PrimaryNeutrinoHelicityDistribution.h" + +#include "SIREN/distributions/primary/mass/PrimaryMass.h" + +#include "SIREN/distributions/primary/vertex/VertexPositionDistribution.h" +#include "SIREN/distributions/primary/vertex/ColumnDepthPositionDistribution.h" +#include "SIREN/distributions/primary/vertex/CylinderVolumePositionDistribution.h" +#include "SIREN/distributions/primary/vertex/DecayRangeFunction.h" +#include "SIREN/distributions/primary/vertex/DecayRangePositionDistribution.h" +#include "SIREN/distributions/primary/vertex/DepthFunction.h" +#include "SIREN/distributions/primary/vertex/LeptonDepthFunction.h" +#include "SIREN/distributions/primary/vertex/OrientedCylinderPositionDistribution.h" +#include "SIREN/distributions/primary/vertex/PointSourcePositionDistribution.h" +#include "SIREN/distributions/primary/vertex/RangeFunction.h" +#include "SIREN/distributions/primary/vertex/RangePositionDistribution.h" + +#include "SIREN/distributions/secondary/vertex/SecondaryVertexPositionDistribution.h" +#include "SIREN/distributions/secondary/vertex/SecondaryBoundedVertexDistribution.h" +#include "SIREN/distributions/secondary/vertex/SecondaryPhysicalVertexDistribution.h" + +#endif // SIREN_distributions_serializable_H diff --git a/projects/geometry/CMakeLists.txt b/projects/geometry/CMakeLists.txt index 62b4c0dff..b884c6b50 100644 --- a/projects/geometry/CMakeLists.txt +++ b/projects/geometry/CMakeLists.txt @@ -18,15 +18,14 @@ target_include_directories(SIREN_geometry PUBLIC ) target_link_libraries(SIREN_geometry - INTERFACE - siren_compile_options - PRIVATE - $ PUBLIC photospline SIREN_serialization SIREN_math + PRIVATE + $ ) +apply_siren_compile_options(SIREN_geometry) install(DIRECTORY "${PROJECT_SOURCE_DIR}/projects/geometry/public/" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} diff --git a/projects/geometry/private/Geometry.cxx b/projects/geometry/private/Geometry.cxx index 67475750a..538fcb286 100644 --- a/projects/geometry/private/Geometry.cxx +++ b/projects/geometry/private/Geometry.cxx @@ -206,3 +206,6 @@ std::vector Geometry::Intersections(siren::math::Vector3 } // namespace geometry } // namespace siren + +CEREAL_REGISTER_DYNAMIC_INIT(siren_Geometry); + diff --git a/projects/geometry/private/Sphere.cxx b/projects/geometry/private/Sphere.cxx index 6bcfac142..2b107945d 100644 --- a/projects/geometry/private/Sphere.cxx +++ b/projects/geometry/private/Sphere.cxx @@ -326,3 +326,6 @@ std::pair Sphere::ComputeDistanceToBorder(const siren::math::Vec } // namespace geometry } // namespace siren + +CEREAL_REGISTER_DYNAMIC_INIT(siren_Sphere); + diff --git a/projects/geometry/public/SIREN/geometry.h b/projects/geometry/public/SIREN/geometry.h new file mode 100644 index 000000000..4853a33ed --- /dev/null +++ b/projects/geometry/public/SIREN/geometry.h @@ -0,0 +1,13 @@ +#ifndef SIREN_geometry_geometry_H +#define SIREN_geometry_geometry_H + +#include "SIREN/geometry/Box.h" +#include "SIREN/geometry/Cylinder.h" +#include "SIREN/geometry/ExtrPoly.h" +#include "SIREN/geometry/Geometry.h" +#include "SIREN/geometry/GeometryMesh.h" +#include "SIREN/geometry/MeshBuilder.h" +#include "SIREN/geometry/Placement.h" +#include "SIREN/geometry/Sphere.h" + +#endif // SIREN_geometry_geometry_H diff --git a/projects/geometry/public/SIREN/geometry/Geometry.h b/projects/geometry/public/SIREN/geometry/Geometry.h index 7dec7874f..9742e3867 100644 --- a/projects/geometry/public/SIREN/geometry/Geometry.h +++ b/projects/geometry/public/SIREN/geometry/Geometry.h @@ -213,7 +213,10 @@ const std::array Geometry_Name = { "sphere", "box", "cylinder", } // namespace siren CEREAL_CLASS_VERSION(siren::geometry::Geometry, 0); +CEREAL_REGISTER_TYPE(siren::geometry::Geometry) CEREAL_CLASS_VERSION(siren::geometry::Geometry::Intersection, 0); CEREAL_CLASS_VERSION(siren::geometry::Geometry::IntersectionList, 0); +CEREAL_FORCE_DYNAMIC_INIT(siren_Geometry); + #endif // SIREN_Geometry_H diff --git a/projects/geometry/public/SIREN/geometry/Sphere.h b/projects/geometry/public/SIREN/geometry/Sphere.h index b97bf9e0a..351291849 100644 --- a/projects/geometry/public/SIREN/geometry/Sphere.h +++ b/projects/geometry/public/SIREN/geometry/Sphere.h @@ -77,7 +77,9 @@ class Sphere : public Geometry { } // namespace siren CEREAL_CLASS_VERSION(siren::geometry::Sphere, 0); -CEREAL_REGISTER_TYPE(siren::geometry::Sphere) +CEREAL_REGISTER_TYPE(siren::geometry::Sphere); CEREAL_REGISTER_POLYMORPHIC_RELATION(siren::geometry::Geometry, siren::geometry::Sphere); +CEREAL_FORCE_DYNAMIC_INIT(siren_Sphere); + #endif // SIREN_Sphere_H diff --git a/projects/geometry/public/SIREN/geometry/serializable.h b/projects/geometry/public/SIREN/geometry/serializable.h new file mode 100644 index 000000000..d5672094c --- /dev/null +++ b/projects/geometry/public/SIREN/geometry/serializable.h @@ -0,0 +1,12 @@ +#ifndef SIREN_geometry_serializable_H +#define SIREN_geometry_serializable_H + +#include "SIREN/geometry/Box.h" +#include "SIREN/geometry/GeometryMesh.h" +#include "SIREN/geometry/Sphere.h" +#include "SIREN/geometry/Placement.h" +#include "SIREN/geometry/Cylinder.h" +#include "SIREN/geometry/ExtrPoly.h" +#include "SIREN/geometry/Geometry.h" + +#endif // SIREN_geometry_serializable_H diff --git a/projects/injection/CMakeLists.txt b/projects/injection/CMakeLists.txt index d8e91a2b7..900fecf72 100644 --- a/projects/injection/CMakeLists.txt +++ b/projects/injection/CMakeLists.txt @@ -14,22 +14,21 @@ target_include_directories(SIREN_injection PUBLIC ) target_link_libraries(SIREN_injection - INTERFACE - siren_compile_options - PRIVATE - $ - pybind11::embed PUBLIC photospline - SIREN_serialization SIREN_utilities + SIREN_serialization SIREN_math SIREN_dataclasses SIREN_geometry SIREN_detector SIREN_interactions SIREN_distributions + PRIVATE + $ + pybind11::embed ) +apply_siren_compile_options(SIREN_injection) install(DIRECTORY "${PROJECT_SOURCE_DIR}/projects/injection/public/" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} diff --git a/projects/injection/private/pybindings/injection.cxx b/projects/injection/private/pybindings/injection.cxx index 6cba39685..8cb3232b6 100644 --- a/projects/injection/private/pybindings/injection.cxx +++ b/projects/injection/private/pybindings/injection.cxx @@ -1,6 +1,15 @@ #include +#include +#include +#include +#include + +#include +#include +#include + #include "../../public/SIREN/injection/Process.h" #include "../../public/SIREN/injection/Injector.h" #include "../../public/SIREN/injection/Weighter.h" @@ -14,17 +23,18 @@ #include "../../../interactions/public/SIREN/interactions/pyDarkNewsCrossSection.h" #include "../../../interactions/public/SIREN/interactions/pyDarkNewsDecay.h" -#include -#include -#include -#include +#include "../../../serialization/public/SIREN/serialization/ByteString.h" -#include -#include -#include +#include "SIREN/dataclasses/serializable.h" +#include "SIREN/detector/serializable.h" +#include "SIREN/distributions/serializable.h" +#include "SIREN/geometry/serializable.h" +#include "SIREN/injection/serializable.h" +#include "SIREN/interactions/serializable.h" +#include "SIREN/math/serializable.h" +#include "SIREN/utilities/serializable.h" PYBIND11_DECLARE_HOLDER_TYPE(T__,std::shared_ptr); -//CEREAL_FORCE_DYNAMIC_INIT(pyDarkNewsCrossSection); using namespace pybind11; @@ -94,6 +104,10 @@ PYBIND11_MODULE(injection,m) { .def("ResetInjectedEvents",&Injector::ResetInjectedEvents) .def("SaveInjector",&Injector::SaveInjector) .def("LoadInjector",&Injector::LoadInjector) + .def(pybind11::pickle( + &(siren::serialization::pickle_save), + &(siren::serialization::pickle_load) + )) ; // class_, Injector>(m, "RangedSIREN") @@ -141,5 +155,10 @@ PYBIND11_MODULE(injection,m) { .def("EventWeight",&Weighter::EventWeight) .def("SaveWeighter",&Weighter::SaveWeighter) .def("LoadWeighter",&Weighter::LoadWeighter) + .def(pybind11::pickle( + &(siren::serialization::pickle_save), + &(siren::serialization::pickle_load) + )) ; } + diff --git a/projects/injection/public/SIREN/injection.h b/projects/injection/public/SIREN/injection.h new file mode 100644 index 000000000..392e665b3 --- /dev/null +++ b/projects/injection/public/SIREN/injection.h @@ -0,0 +1,9 @@ +#ifndef SIREN_injection_injection_H +#define SIREN_injection_injection_H + +#include "SIREN/injection/Injector.h" +#include "SIREN/injection/Process.h" +#include "SIREN/injection/Weighter.h" +#include "SIREN/injection/WeightingUtils.h" + +#endif // SIREN_injection_injection_H diff --git a/projects/injection/public/SIREN/injection/Injector.h b/projects/injection/public/SIREN/injection/Injector.h index bd82e28bf..602c8f756 100644 --- a/projects/injection/public/SIREN/injection/Injector.h +++ b/projects/injection/public/SIREN/injection/Injector.h @@ -121,7 +121,6 @@ friend cereal::access; archive(::cereal::make_nvp("InjectedEvents", injected_events)); archive(::cereal::make_nvp("DetectorModel", detector_model)); // archive(::cereal::make_nvp("SIRENRandom", random)); - // std::cout << "saved SIRENRandom\n"; archive(::cereal::make_nvp("PrimaryProcess", primary_process)); archive(::cereal::make_nvp("SecondaryProcesses", secondary_processes)); } else { @@ -139,7 +138,6 @@ friend cereal::access; archive(::cereal::make_nvp("InjectedEvents", injected_events)); archive(::cereal::make_nvp("DetectorModel", detector_model)); // archive(::cereal::make_nvp("SIRENRandom", random)); - // std::cout << "loaded SIRENRandom\n"; archive(::cereal::make_nvp("PrimaryProcess", _primary_process)); archive(::cereal::make_nvp("SecondaryProcesses", _secondary_processes)); SetPrimaryProcess(_primary_process); diff --git a/projects/injection/public/SIREN/injection/Weighter.h b/projects/injection/public/SIREN/injection/Weighter.h index 93e845cb7..4b8daf857 100644 --- a/projects/injection/public/SIREN/injection/Weighter.h +++ b/projects/injection/public/SIREN/injection/Weighter.h @@ -102,12 +102,17 @@ class Weighter { } template - void load(Archive & archive, std::uint32_t const version) const { + static void load_and_construct(Archive & archive, cereal::construct & construct, std::uint32_t const version) { if(version == 0) { + std::vector> injectors; + std::shared_ptr detector_model; + std::shared_ptr primary_physical_process; + std::vector> secondary_physical_processes; archive(::cereal::make_nvp("Injectors", injectors)); archive(::cereal::make_nvp("DetectorModel", detector_model)); archive(::cereal::make_nvp("PrimaryPhysicalProcess", primary_physical_process)); archive(::cereal::make_nvp("SecondaryPhysicalProcesses", secondary_physical_processes)); + construct(injectors, detector_model, primary_physical_process, secondary_physical_processes); } else { throw std::runtime_error("Weighter only supports version <= 0!"); } diff --git a/projects/injection/public/SIREN/injection/serializable.h b/projects/injection/public/SIREN/injection/serializable.h new file mode 100644 index 000000000..ad1c10b73 --- /dev/null +++ b/projects/injection/public/SIREN/injection/serializable.h @@ -0,0 +1,8 @@ +#ifndef SIREN_injection_serializable_H +#define SIREN_injection_serializable_H + +#include "SIREN/injection/Weighter.h" +#include "SIREN/injection/Process.h" +#include "SIREN/injection/Injector.h" + +#endif // SIREN_injection_serializable_H diff --git a/projects/interactions/CMakeLists.txt b/projects/interactions/CMakeLists.txt index 4c0b6505b..a482fcfce 100644 --- a/projects/interactions/CMakeLists.txt +++ b/projects/interactions/CMakeLists.txt @@ -26,19 +26,18 @@ target_include_directories(SIREN_interactions PUBLIC ) target_link_libraries(SIREN_interactions - INTERFACE - siren_compile_options PRIVATE $ pybind11::embed PUBLIC photospline - SIREN_serialization SIREN_utilities + SIREN_serialization SIREN_math SIREN_dataclasses SIREN_detector ) +apply_siren_compile_options(SIREN_interactions) install(DIRECTORY "${PROJECT_SOURCE_DIR}/projects/interactions/public/" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} diff --git a/projects/interactions/public/SIREN/interactions.h b/projects/interactions/public/SIREN/interactions.h new file mode 100644 index 000000000..5db738aab --- /dev/null +++ b/projects/interactions/public/SIREN/interactions.h @@ -0,0 +1,21 @@ +#ifndef SIREN_interactions_interactions_H +#define SIREN_interactions_interactions_H + +#include "SIREN/interactions/CrossSection.h" +#include "SIREN/interactions/DISFromSpline.h" +#include "SIREN/interactions/DarkNewsCrossSection.h" +#include "SIREN/interactions/DarkNewsDecay.h" +#include "SIREN/interactions/Decay.h" +#include "SIREN/interactions/DipoleFromTable.h" +#include "SIREN/interactions/DummyCrossSection.h" +#include "SIREN/interactions/ElasticScattering.h" +#include "SIREN/interactions/HNLFromSpline.h" +#include "SIREN/interactions/Interaction.h" +#include "SIREN/interactions/InteractionCollection.h" +#include "SIREN/interactions/NeutrissimoDecay.h" +#include "SIREN/interactions/pyCrossSection.h" +#include "SIREN/interactions/pyDarkNewsCrossSection.h" +#include "SIREN/interactions/pyDarkNewsDecay.h" +#include "SIREN/interactions/pyDecay.h" + +#endif // SIREN_interactions_interactions_H diff --git a/projects/interactions/public/SIREN/interactions/HNLDecay.h b/projects/interactions/public/SIREN/interactions/HNLDecay.h index b66714e99..d70fcea53 100644 --- a/projects/interactions/public/SIREN/interactions/HNLDecay.h +++ b/projects/interactions/public/SIREN/interactions/HNLDecay.h @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include diff --git a/projects/interactions/public/SIREN/interactions/serializable.h b/projects/interactions/public/SIREN/interactions/serializable.h new file mode 100644 index 000000000..daf4e5aa6 --- /dev/null +++ b/projects/interactions/public/SIREN/interactions/serializable.h @@ -0,0 +1,16 @@ +#ifndef SIREN_serializable_H +#define SIREN_serializable_H + +#include "SIREN/interactions/DarkNewsCrossSection.h" +#include "SIREN/interactions/NeutrissimoDecay.h" +#include "SIREN/interactions/DarkNewsDecay.h" +#include "SIREN/interactions/HNLFromSpline.h" +#include "SIREN/interactions/Decay.h" +#include "SIREN/interactions/DummyCrossSection.h" +#include "SIREN/interactions/InteractionCollection.h" +#include "SIREN/interactions/DISFromSpline.h" +#include "SIREN/interactions/ElasticScattering.h" +#include "SIREN/interactions/DipoleFromTable.h" +#include "SIREN/interactions/CrossSection.h" + +#endif // SIREN_serializable_H diff --git a/projects/math/CMakeLists.txt b/projects/math/CMakeLists.txt index 1bde95e3a..520079fe8 100644 --- a/projects/math/CMakeLists.txt +++ b/projects/math/CMakeLists.txt @@ -17,8 +17,6 @@ target_include_directories(SIREN_math PUBLIC if(${MACOSX}) target_link_libraries(SIREN_math - INTERFACE - siren_compile_options PUBLIC photospline delabella_shared @@ -28,8 +26,6 @@ target_link_libraries(SIREN_math ) else() target_link_libraries(SIREN_math - INTERFACE - siren_compile_options PUBLIC photospline delabella_shared @@ -41,6 +37,8 @@ target_link_libraries(SIREN_math ) endif() +apply_siren_compile_options(SIREN_math) + install(DIRECTORY "${PROJECT_SOURCE_DIR}/projects/math/public/" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING diff --git a/projects/math/public/SIREN/math.h b/projects/math/public/SIREN/math.h new file mode 100644 index 000000000..3c37c8825 --- /dev/null +++ b/projects/math/public/SIREN/math.h @@ -0,0 +1,13 @@ +#ifndef SIREN_math_math_H +#define SIREN_math_math_H + +#include "SIREN/math/Conversions.h" +#include "SIREN/math/EulerAngles.h" +#include "SIREN/math/EulerQuaternionConversions.h" +#include "SIREN/math/Interpolation.h" +#include "SIREN/math/Matrix3D.h" +#include "SIREN/math/Polynomial.h" +#include "SIREN/math/Quaternion.h" +#include "SIREN/math/Vector3D.h" + +#endif // SIREN_math_math_H diff --git a/projects/math/public/SIREN/math/serializable.h b/projects/math/public/SIREN/math/serializable.h new file mode 100644 index 000000000..8a88a1a65 --- /dev/null +++ b/projects/math/public/SIREN/math/serializable.h @@ -0,0 +1,11 @@ +#ifndef SIREN_math_serializable_H +#define SIREN_math_serializable_H + +#include "SIREN/math/EulerAngles.h" +#include "SIREN/math/Polynomial.h" +#include "SIREN/math/Interpolation.h" +#include "SIREN/math/Quaternion.h" +#include "SIREN/math/Vector3D.h" +#include "SIREN/math/Matrix3D.h" + +#endif // SIREN_math_serializable_H diff --git a/projects/serialization/CMakeLists.txt b/projects/serialization/CMakeLists.txt index c7983051b..ea58132ba 100644 --- a/projects/serialization/CMakeLists.txt +++ b/projects/serialization/CMakeLists.txt @@ -1,13 +1,15 @@ -add_library(SIREN_serialization INTERFACE) -target_include_directories(SIREN_serialization INTERFACE + +LIST (APPEND serialization_SOURCES + ${PROJECT_SOURCE_DIR}/projects/serialization/private/serialization.cxx +) + +add_library(SIREN_serialization OBJECT ${serialization_SOURCES}) +target_include_directories(SIREN_serialization PUBLIC $ $ ) -target_link_libraries(SIREN_serialization - INTERFACE - siren_compile_options -) +apply_siren_compile_options(SIREN_serialization) install(DIRECTORY "${PROJECT_SOURCE_DIR}/projects/serialization/public/" EXPORT ${PROJECT_NAME}Config diff --git a/projects/serialization/private/serialization.cxx b/projects/serialization/private/serialization.cxx new file mode 100644 index 000000000..838790387 --- /dev/null +++ b/projects/serialization/private/serialization.cxx @@ -0,0 +1,11 @@ +// serialization.cxx +#include +#include + +// Register the archives +CEREAL_REGISTER_ARCHIVE(cereal::BinaryOutputArchive); +CEREAL_REGISTER_ARCHIVE(cereal::BinaryInputArchive); + +// Ensure dynamic initialization is not optimized away +CEREAL_REGISTER_DYNAMIC_INIT(siren); +CEREAL_FORCE_DYNAMIC_INIT(siren); diff --git a/projects/serialization/public/SIREN/serialization/ByteString.h b/projects/serialization/public/SIREN/serialization/ByteString.h new file mode 100644 index 000000000..28dc6685a --- /dev/null +++ b/projects/serialization/public/SIREN/serialization/ByteString.h @@ -0,0 +1,104 @@ +#ifndef SIREN_serialization_ByteString_H +#define SIREN_serialization_ByteString_H + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace siren { +namespace serialization { + +template +std::vector to_byte_string(std::shared_ptr obj) { + std::ostringstream oss(std::ios::binary); + { + cereal::BinaryOutputArchive oarchive(oss); + oarchive(obj); + } + size_t n_bytes = oss.tellp(); + std::string str = oss.str(); + if(not (str.size() == n_bytes)) + throw std::runtime_error("str.size() != n_bytes"); + std::vector vec(str.begin(), str.end()); + if(not (vec.size() == n_bytes)) + throw std::runtime_error("vec.size() != n_bytes"); + return vec; +} + +std::string bytes_to_hex_string(std::vector const & bytes) { + std::ostringstream oss; + oss << std::hex << std::setfill('0'); + for (char const & byte : bytes) { + oss << std::setw(2) << (unsigned int)std::uint8_t(byte); + } + std::string s = oss.str(); + if(not (s.size() % 2 == 0)) + throw std::runtime_error("s.size() % 2 != 0"); + if(not (s.size() == 2 * bytes.size())) + throw std::runtime_error("s.size() != 2 * bytes.size()"); + return s; +} + +template +std::shared_ptr from_byte_string(std::vector const & byte_string) { + std::string str(byte_string.begin(), byte_string.end()); + if(not (str.size() == byte_string.size())) + throw std::runtime_error("str.size() != byte_string.size()"); + std::istringstream iss(str, std::ios::binary); + std::shared_ptr obj; + { + cereal::BinaryInputArchive iarchive(iss); + iarchive(obj); + } + size_t n_bytes = iss.tellg(); + if(not (n_bytes == str.size())) + throw std::runtime_error("n_bytes != str.size()"); + return obj; +} + +std::vector hex_string_to_bytes(std::string const & hex_string) { + std::vector bytes; + for (size_t i = 0; i < hex_string.size(); i += 2) { + std::string byte_string = hex_string.substr(i, 2); + char byte = static_cast(std::stoi(byte_string, nullptr, 16)); + bytes.push_back(byte); + } + if(not (bytes.size() == hex_string.size() / 2)) + throw std::runtime_error("bytes.size() != hex_string.size() / 2"); + return bytes; +} + +template +pybind11::tuple pickle_save(std::shared_ptr cpp_obj) { + std::vector byte_string = to_byte_string(cpp_obj); + std::string hex_string = bytes_to_hex_string(byte_string); + return pybind11::make_tuple(hex_string); +} + +template +std::shared_ptr pickle_load(pybind11::tuple t) { + if (t.size() != 1) { + throw std::runtime_error("Invalid state!"); + } + std::string hex_string = t[0].cast(); + std::vector byte_string = hex_string_to_bytes(hex_string); + std::shared_ptr res = from_byte_string(byte_string); + return res; +} + +} // namespace serialization +} // namespace siren + +#endif // SIREN_serialization_ByteString_H diff --git a/projects/utilities/CMakeLists.txt b/projects/utilities/CMakeLists.txt index a8c9c11af..c31d09389 100644 --- a/projects/utilities/CMakeLists.txt +++ b/projects/utilities/CMakeLists.txt @@ -12,10 +12,7 @@ target_include_directories(SIREN_utilities PUBLIC $ ) -target_link_libraries(SIREN_utilities - INTERFACE - siren_compile_options -) +apply_siren_compile_options(SIREN_utilities) install(DIRECTORY "${PROJECT_SOURCE_DIR}/projects/utilities/public/" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} diff --git a/projects/utilities/private/Interpolator.cxx b/projects/utilities/private/Interpolator.cxx index 57646d175..b7a52da8a 100644 --- a/projects/utilities/private/Interpolator.cxx +++ b/projects/utilities/private/Interpolator.cxx @@ -3,6 +3,15 @@ #include #include +// Explicit template instantiation +template struct siren::utilities::TableData1D; +template struct siren::utilities::TableData2D; +template struct siren::utilities::IndexFinderRegular; +template struct siren::utilities::IndexFinderIrregular; +template struct siren::utilities::Indexer1D; +template struct siren::utilities::Interpolator1D; +template struct siren::utilities::Interpolator2D; + using namespace siren::utilities; template<> @@ -29,3 +38,13 @@ bool Interpolator2D::operator==(Interpolator2D const & o return original_table == other.original_table; } +CEREAL_CLASS_VERSION(siren::utilities::TableData1D, 0); +CEREAL_CLASS_VERSION(siren::utilities::TableData2D, 0); +CEREAL_CLASS_VERSION(siren::utilities::IndexFinderRegular, 0); +CEREAL_CLASS_VERSION(siren::utilities::IndexFinderIrregular, 0); +CEREAL_CLASS_VERSION(siren::utilities::Indexer1D, 0); +CEREAL_CLASS_VERSION(siren::utilities::Interpolator1D, 0); +CEREAL_CLASS_VERSION(siren::utilities::Interpolator2D, 0); + +CEREAL_REGISTER_DYNAMIC_INIT(siren_Interpolator); + diff --git a/projects/utilities/public/SIREN/utilities.h b/projects/utilities/public/SIREN/utilities.h new file mode 100644 index 000000000..3bbc257ee --- /dev/null +++ b/projects/utilities/public/SIREN/utilities.h @@ -0,0 +1,13 @@ +#pragma once +#ifndef SIREN_utilities_utilities_H +#define SIREN_utilities_utilities_H + +#include "SIREN/utilities/Constants.h" +#include "SIREN/utilities/Errors.h" +#include "SIREN/utilities/Integration.h" +#include "SIREN/utilities/Interpolator.h" +#include "SIREN/utilities/Pybind11Trampoline.h" +#include "SIREN/utilities/Random.h" +#include "SIREN/utilities/StringManipulation.h" + +#endif // SIREN_utilities_utilities_H diff --git a/projects/utilities/public/SIREN/utilities/Interpolator.h b/projects/utilities/public/SIREN/utilities/Interpolator.h index 6ce95541f..4d1491f9f 100644 --- a/projects/utilities/public/SIREN/utilities/Interpolator.h +++ b/projects/utilities/public/SIREN/utilities/Interpolator.h @@ -702,15 +702,18 @@ struct Interpolator2D { } }; +// Declare the explicit specialization (but do not instantiate) +extern template struct TableData1D; +extern template struct TableData2D; +extern template struct IndexFinderRegular; +extern template struct IndexFinderIrregular; +extern template struct Indexer1D; +extern template struct Interpolator1D; +extern template struct Interpolator2D; + } // namespace utilities } // namespace siren -CEREAL_CLASS_VERSION(siren::utilities::TableData1D, 0); -CEREAL_CLASS_VERSION(siren::utilities::TableData2D, 0); -CEREAL_CLASS_VERSION(siren::utilities::IndexFinderRegular, 0); -CEREAL_CLASS_VERSION(siren::utilities::IndexFinderIrregular, 0); -CEREAL_CLASS_VERSION(siren::utilities::Indexer1D, 0); -CEREAL_CLASS_VERSION(siren::utilities::Interpolator1D, 0); -CEREAL_CLASS_VERSION(siren::utilities::Interpolator2D, 0); +CEREAL_FORCE_DYNAMIC_INIT(siren_Interpolator); #endif // SIREN_Interpolator_H diff --git a/projects/utilities/public/SIREN/utilities/serializable.h b/projects/utilities/public/SIREN/utilities/serializable.h new file mode 100644 index 000000000..136eeb324 --- /dev/null +++ b/projects/utilities/public/SIREN/utilities/serializable.h @@ -0,0 +1,5 @@ +#pragma once +#ifndef SIREN_utilities_serializable_H +#define SIREN_utilities_serializable_H + +#endif // SIREN_utilities_serializable_H diff --git a/python/Injector.py b/python/Injector.py index d7096b594..ed0a7c8d1 100644 --- a/python/Injector.py +++ b/python/Injector.py @@ -16,7 +16,7 @@ if TYPE_CHECKING: import siren -_Injector = _injection.Injector +_Injector = _injection._Injector ParticleType = _dataclasses.ParticleType CrossSection = _interactions.CrossSection @@ -137,6 +137,35 @@ def __initialize_injector(self): if self.__stopping_condition is not None: self.__injector.SetStoppingCondition(self.__stopping_condition) + # Custom method to retrieve the internal state for pickling + def __getstate__(self): + # The seed and stopping condition are the only things we cannot serialize + state = (self.__seed, self.__stopping_condition, self.__injector.__getstate__()) + return state + + # Custom method to restore the state from a pickle + def __setstate__(self, state): + + self.__seed, self.__stopping_condition, injector_state = state + + # Create a new instance of the C++ class and restore its state + self.__injector = _Injector.__new__(_Injector) # Create an empty instance + if self.__injector is None: + raise TypeError("Failed to create C++ Injector object") + self.__injector.__setstate__(injector_state) + self.__number_of_events = self.__injector.EventsToInject() + self.__detector_model = self.__injector.GetDetectorModel() + primary_process = self.__injector.GetPrimaryProcess() + self.__primary_type = primary_process.primary_type + self.__primary_interactions = list(primary_process.interactions.GetCrossSections()) + list(primary_process.interactions.GetDecays()) + self.__primary_injection_distributions = list(primary_process.distributions) + + self.__secondary_interactions = {} + self.__secondary_injection_distributions = {} + for secondary_type, secondary_process in self.__injector.GetSecondaryProcessMap(): + self.__secondary_interactions[secondary_type] = list(secondary_process.interactions.GetCrossSections()) + list(secondary_process.interactions.GetDecays()) + self.__secondary_injection_distributions[secondary_type] = list(secondary_process.distributions) + @property def seed(self): return self.__seed diff --git a/python/Weighter.py b/python/Weighter.py index 145080bda..69f8c4280 100644 --- a/python/Weighter.py +++ b/python/Weighter.py @@ -14,8 +14,8 @@ if TYPE_CHECKING: import siren -_Injector = _injection.Injector -_Weighter = _injection.Weighter +_Injector = _injection._Injector +_Weighter = _injection._Weighter _PyInjector = _Injector_module.Injector diff --git a/python/__init__.py b/python/__init__.py index 950ddd621..e59cd934b 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -8,8 +8,6 @@ from . import injection from . import _util -from . import Injector -from . import Weighter from . import resources # Intropspect package version @@ -34,11 +32,15 @@ # Override the Injector with the python wrapper injection._Injector = injection.Injector +del injection.Injector +from . import Injector injection.Injector = Injector.Injector del Injector # Override the Weighter with the python wrapper injection._Weighter = injection.Weighter +del injection.Weighter +from . import Weighter injection.Weighter = Weighter.Weighter del Weighter diff --git a/vendor/cereal b/vendor/cereal index 02eace19a..d1fcec807 160000 --- a/vendor/cereal +++ b/vendor/cereal @@ -1 +1 @@ -Subproject commit 02eace19a99ce3cd564ca4e379753d69af08c2c8 +Subproject commit d1fcec807b372f04e4c1041b3058e11c12853e6e diff --git a/vendor/photospline b/vendor/photospline index bb68658a8..c6fb3ea9a 160000 --- a/vendor/photospline +++ b/vendor/photospline @@ -1 +1 @@ -Subproject commit bb68658a8776b9dabba8c3d3332b4294474d20c3 +Subproject commit c6fb3ea9a98f93705bc07b288b7f9264e621ac18 From 840da1ffc83afa14d0c1d4324abf068c68e67725 Mon Sep 17 00:00:00 2001 From: Nicholas Kamp Date: Wed, 23 Oct 2024 20:26:55 -0400 Subject: [PATCH 91/94] Get example 1 working --- python/_util.py | 131 ++++++++++ resources/examples/example1/DIS_ATLAS.py | 21 +- resources/examples/example1/DIS_DUNE.py | 71 +++--- resources/examples/example1/DIS_IceCube.py | 17 +- resources/examples/example1/PaperPlots.ipynb | 229 ++++++++++++++++-- .../examples/example2/DipolePortal_CCM.py | 27 ++- resources/examples/example2/PaperPlots.ipynb | 2 +- .../processes/DarkNewsTables/processes.py | 45 ++-- 8 files changed, 414 insertions(+), 129 deletions(-) diff --git a/python/_util.py b/python/_util.py index 35572ea89..956853f0a 100644 --- a/python/_util.py +++ b/python/_util.py @@ -6,6 +6,12 @@ import pathlib import importlib +import time +from siren import dataclasses as _dataclasses +import numpy as np +import awkward as ak +import h5py + THIS_DIR = os.path.abspath(os.path.dirname(__file__)) @@ -661,6 +667,7 @@ def import_resource(resource_type, resource_name): fname = os.path.join(abs_dir, f"{resource_type}.py") if not os.path.isfile(fname): return None + print(fname) return load_module(f"siren-{resource_type}-{resource_name}", fname, persist=False) @@ -835,3 +842,127 @@ def load_detector(): load_detector.__doc__ = detector_docs(detector_name) return load_detector + + + +###### Injector helper functions ####### + +# Generate events using an injector object +# Optionally save events to hdf5, parquet, and/or custom SIREN filetypes +# If the weighter exists, calculate the event weight too +def GenerateEvents(injector, N=None): + if N is None: + N = injector.number_of_events + count = 0 + gen_times = [] + prev_time = time.time() + events = [] + while (injector.injected_events < injector.number_of_events) and (count < N): + print("Injecting Event %d/%d " % (count, N), end="\r") + event = injector.generate_event() + events.append(event) + t = time.time() + gen_times.append(t-prev_time) + prev_time = t + count += 1 + return events,gen_times + +def SaveEvents(events, + weighter=None, + gen_times=None, + save_hdf5=True, + save_parquet=True, + save_siren_events=True, + fid_vol=None, + output_filename=None): + + + # Optionally save things + if save_siren_events: _dataclasses.SaveInteractionTrees(events, output_filename) + # A dictionary containing each dataset we'd like to save + datasets = { + "event_weight":[], # weight of entire event + "event_gen_time":[], # generation time of each event + "event_weight_time":[], # generation time of each event + "num_interactions":[], # number of interactions per event + "vertex":[], # vertex of each interaction in an event + "in_fiducial":[], # whether or not each vertex is in the fiducial volume + "primary_type":[], # primary type of each interaction + "target_type":[], # target type of each interaction + "num_secondaries":[], # number of secondary particles of each interaction + "secondary_types":[], # secondary type of each interaction + "primary_momentum":[], # primary momentum of each interaction + "secondary_momenta":[], # secondary momentum of each interaction + "parent_idx":[], # index of the parent interaction + } + for ie, event in enumerate(events): + print("Saving Event %d/%d " % (ie, len(events)), end="\r") + t0 = time.time() + datasets["event_weight"].append(weighter(event) if weighter is not None else 0) + datasets["event_weight_time"].append(time.time()-t0) + datasets["event_gen_time"].append(gen_times[ie]) + # add empty lists for each per interaction dataset + for k in ["vertex", + "in_fiducial", + "primary_type", + "target_type", + "num_secondaries", + "secondary_types", + "primary_momentum", + "secondary_momenta", + "parent_idx"]: + datasets[k].append([]) + # loop over interactions + for id, datum in enumerate(event.tree): + datasets["vertex"][-1].append(np.array(datum.record.interaction_vertex,dtype=float)) + + # primary particle stuff + datasets["primary_type"][-1].append(int(datum.record.signature.primary_type)) + datasets["primary_momentum"][-1].append(np.array(datum.record.primary_momentum, dtype=float)) + + # check parent idx; match on secondary momenta + if datum.depth()==0: + datasets["parent_idx"][-1].append(-1) + else: + for _id in range(len(datasets["secondary_momenta"][-1])): + for secondary_momentum in datasets["secondary_momenta"][-1][_id]: + if (datasets["primary_momentum"][-1][-1] == secondary_momentum).all(): + datasets["parent_idx"][-1].append(_id) + break + + if fid_vol is not None: + pos = _math.Vector3D(datasets["vertex"][-1][-1]) + dir = _math.Vector3D(datasets["primary_momentum"][-1][-1][1:]) + dir.normalize() + datasets["in_fiducial"][-1].append(fid_vol.IsInside(pos,dir)) + else: + datasets["in_fiducial"][-1].append(False) + + # target particle stuff + datasets["target_type"][-1].append(int(datum.record.signature.target_type)) + + # secondary particle stuff + datasets["secondary_types"][-1].append([]) + datasets["secondary_momenta"][-1].append([]) + for isec, (sec_type, sec_momenta) in enumerate(zip(datum.record.signature.secondary_types, + datum.record.secondary_momenta)): + datasets["secondary_types"][-1][-1].append(int(sec_type)) + datasets["secondary_momenta"][-1][-1].append(np.array(sec_momenta,dtype=float)) + datasets["num_secondaries"][-1].append(isec+1) + datasets["num_interactions"].append(id+1) + + # save events + ak_array = ak.Array(datasets) + if save_hdf5: + fout = h5py.File(output_filename+".hdf5", "w") + group = fout.create_group("Events") + form, length, container = ak.to_buffers(ak.to_packed(ak_array), container=group) + group.attrs["form"] = form.to_json() + group.attrs["length"] = length + fout.close() + if save_parquet: + ak.to_parquet(ak_array,output_filename+".parquet") + +# Load events from the custom SIREN event format +def LoadEvents(filename): + return _dataclasses.LoadInteractionTrees(filename) diff --git a/resources/examples/example1/DIS_ATLAS.py b/resources/examples/example1/DIS_ATLAS.py index add646ed4..c8e202a65 100644 --- a/resources/examples/example1/DIS_ATLAS.py +++ b/resources/examples/example1/DIS_ATLAS.py @@ -1,10 +1,6 @@ import os import siren -try: - from tqdm import tqdm as tqdm -except ImportError: - print("Importing tqdm failed, using default range") - tqdm = lambda x: x +from siren._util import GenerateEvents,SaveEvents seed = 99 @@ -86,11 +82,8 @@ injector.primary_type = primary_type injector.primary_interactions = primary_processes[primary_type] injector.primary_injection_distributions = primary_injection_distributions -injector.secondary_interactions = {} -injector.secondary_injection_distributions = {} -print("Generating events") -events = [injector.generate_event() for _ in tqdm(range(events_to_inject))] +events,gen_times = GenerateEvents(injector) weighter = siren.injection.Weighter() weighter.injectors = [injector] @@ -98,13 +91,9 @@ weighter.primary_type = primary_type weighter.primary_interactions = primary_processes[primary_type] weighter.primary_physical_distributions = primary_physical_distributions -weighter.secondary_interactions = {} -weighter.secondary_physical_distributions = {} - -print("Weighting events") -weights = [weighter(event) for event in tqdm(events)] +# Output events and weights os.makedirs("output", exist_ok=True) - -#TODO save the events and weights +print("Saving events") +SaveEvents(events,weighter,gen_times,output_filename="output/ATLAS") diff --git a/resources/examples/example1/DIS_DUNE.py b/resources/examples/example1/DIS_DUNE.py index 4f094479b..42442d110 100644 --- a/resources/examples/example1/DIS_DUNE.py +++ b/resources/examples/example1/DIS_DUNE.py @@ -1,79 +1,64 @@ import os import siren -from siren import utilities +from siren._util import GenerateEvents,SaveEvents # Number of events to inject events_to_inject = int(1e5) # Experiment to run experiment = "DUNEFD" -detector_model = utilities.load_detector(experiment) +detector_model = siren.utilities.load_detector(experiment) + +# Particle to inject primary_type = siren.dataclasses.Particle.ParticleType.NuMu -target_type = siren.dataclasses.Particle.ParticleType.Nucleon -# Primary interactions and distributions -primary_processes, _ = utilities.load_processes( - "CSMSDISSplines", # model_name +# Cross-section model to use +cross_section_model = "CSMSDISSplines" + +# Load the cross-section model +primary_processes, _ = siren.utilities.load_processes( + cross_section_model, primary_types=[primary_type], - target_types=[target_type], - isoscalar=True, # for isoscalar splines - process_types=["CC"] # specify the process type, e.g., "CC" for charged current + target_types=[siren.dataclasses.Particle.ParticleType.Nucleon], + isoscalar=True, + process_types=["CC"] ) -# Energy distribution -edist = siren.distributions.PowerLaw(1, 1e3, 1e6) - -# Direction distribution -direction_distribution = siren.distributions.IsotropicDirection() - -# Position distribution -muon_range_func = siren.distributions.LeptonDepthFunction() -position_distribution = siren.distributions.ColumnDepthPositionDistribution( - 60, 60.0, muon_range_func) - - -# Define injection distributions -primary_injection_distributions = { - "energy": edist, - "direction": direction_distribution, - "position": position_distribution -} +# Extract the primary cross-sections for the primary type +primary_cross_sections = primary_processes[primary_type] # Set up the Injector injector = siren.injection.Injector() injector.number_of_events = events_to_inject injector.detector_model = detector_model injector.primary_type = primary_type -injector.primary_interactions = primary_processes[primary_type] +injector.primary_interactions = primary_cross_sections + +# Directly set the distributions injector.primary_injection_distributions = [ - siren.distributions.PrimaryMass(0), - edist, - direction_distribution, - position_distribution + siren.distributions.PrimaryMass(0), # Mass distribution + siren.distributions.PowerLaw(1, 1e3, 1e6), # Energy distribution + siren.distributions.IsotropicDirection(), # Direction distribution + siren.distributions.ColumnDepthPositionDistribution(60, 60.0, siren.distributions.LeptonDepthFunction()) # Position distribution ] # Generate events -event = injector.generate_event() +events,gen_times = GenerateEvents(injector) -# Set up the Weighter for event weighting +# Set up the Weighter for event weighting (without position distribution) weighter = siren.injection.Weighter() weighter.injectors = [injector] weighter.detector_model = detector_model weighter.primary_type = primary_type -weighter.primary_interactions = primary_processes[primary_type] +weighter.primary_interactions = primary_cross_sections weighter.primary_physical_distributions = [ - edist, - direction_distribution, + siren.distributions.PowerLaw(1, 1e3, 1e6), # Energy distribution + siren.distributions.IsotropicDirection() # Direction distribution ] -# Compute weight -weight = weighter(event) # Output events and weights os.makedirs("output", exist_ok=True) -print(str(event)) -print(f"Event weight: {weight}") +SaveEvents(events,weighter,gen_times,output_filename="output/DUNE") -# Save events -# TODO diff --git a/resources/examples/example1/DIS_IceCube.py b/resources/examples/example1/DIS_IceCube.py index f4c2bb2d3..725e5db8b 100644 --- a/resources/examples/example1/DIS_IceCube.py +++ b/resources/examples/example1/DIS_IceCube.py @@ -1,13 +1,13 @@ import os import siren -from siren import utilities +from siren._util import GenerateEvents,SaveEvents # Number of events to inject events_to_inject = int(1e5) # Experiment to run experiment = "IceCube" -detector_model = utilities.load_detector(experiment) +detector_model = siren.utilities.load_detector(experiment) # Particle to inject primary_type = siren.dataclasses.Particle.ParticleType.NuMu @@ -16,7 +16,7 @@ cross_section_model = "CSMSDISSplines" # Load the cross-section model -primary_processes, _ = utilities.load_processes( +primary_processes, _ = siren.utilities.load_processes( cross_section_model, primary_types=[primary_type], target_types=[siren.dataclasses.Particle.ParticleType.Nucleon], @@ -43,7 +43,7 @@ ] # Generate events -event = injector.generate_event() +events,gen_times = GenerateEvents(injector) # Set up the Weighter for event weighting (without position distribution) weighter = siren.injection.Weighter() @@ -56,14 +56,7 @@ siren.distributions.IsotropicDirection() # Direction distribution ] -# Compute weight -weight = weighter(event) # Output events and weights os.makedirs("output", exist_ok=True) -print(str(event)) -print(f"Event weight: {weight}") - -# Save events -# injector.SaveEvents("output/IceCube_DIS") - +SaveEvents(events,weighter,gen_times,output_filename="output/IceCube") diff --git a/resources/examples/example1/PaperPlots.ipynb b/resources/examples/example1/PaperPlots.ipynb index 76f8de964..99b91bed3 100644 --- a/resources/examples/example1/PaperPlots.ipynb +++ b/resources/examples/example1/PaperPlots.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "249e815d-3d83-4c81-bce7-bac786f95549", "metadata": {}, "outputs": [], @@ -20,14 +20,14 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "c80f20e3-357d-4157-a279-c8f491f0c50d", "metadata": {}, "outputs": [], "source": [ - "filename = {\"IceCube\":\"IceCube_DIS.parquet\",\n", - " \"DUNE\":\"DUNE_DIS.parquet\",\n", - " \"ATLAS\":\"ATLAS_DIS.parquet\"}\n", + "filename = {\"IceCube\":\"IceCube.parquet\",\n", + " \"DUNE\":\"DUNE.parquet\",\n", + " \"ATLAS\":\"ATLAS.parquet\"}\n", "\n", "Erange = {\"IceCube\":(1e-1,2e6),\n", " \"DUNE\":(1e-1,2e6),\n", @@ -40,7 +40,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "ef6c4d55-6687-425e-a521-de52d27de2f0", "metadata": {}, "outputs": [], @@ -163,10 +163,131 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "eeb54511-c655-478e-9fac-43246279faf4", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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LJZbu3Yt9erVi8qWLUtBQUHUoEEDevnllyktLc3q+k+ePEkPPfQQxcTEUEBAgHjkf58+fdrqcqmpqTR58mSqX7++2B5v95577qH169fb/FoBAAAAoKhWrVpRw4YNadasWTg0dvK6moktW7bQBx98IAIJo9FosdxHH31E48aNE+U6dOhAFSpUoH/++YemTp1KS5YsoU2bNomb/eI2b95MPXr0oIyMDGrUqBG1b9+eDh48SN9++y39/PPPIkBp06ZNieWuXbsmtnP8+HGqVKkS9e7dm65evUqrVq0S04wZM+jZZ5/V/HiA63C15E8A4N1UPpNcLbEdPkdtO1cq59FZbvSYcNw1Y1r3zp07KTw83GHb8SZedffCN/hcQ8A363379rVYbu/evTR+/Hjy8fGh33//nTZu3EiLFi2iU6dOUbdu3ejYsWP05JNPml3/4MGDxeNLL70kgoiFCxeKR/53enq6mJ+ZmVli2ccff1wEErx+rtng7fF2f/vtN9Lr9fT888/TgQMHND8mAAAAAAC28qpggm/oT5w4QV988QVFRERYLPfOO++IWouHH36Y7r777oLng4OD6euvvxY391w7cfTo0SLLzZs3jy5dukT16tUr0XyK/83Pnz9/nubPn19k3uHDh+mXX34RwQuvn7djws2sOAAyGAxivwAAAAA8lV73X64Jx0yl/Qo9j9cEExs2bKBPPvmERowYIW7QLcnJyRG1EWz48OEl5levXp3atWsn/l62bFmReaZ/Dx06VAQchfG/hwwZIv5eunSp2eV4vbz+4kz7sWLFCsrNzVV8xQAAAAAAjuUVwQR3mH7kkUdEv4ePP/7YalluasTNlFjLli3NljE9z82hCjP921HLcTMprlkBAAAA8EScB8LRE2jLK47ohAkT6MyZMzRnzhyKioqyWpbLscjISAoLCzNbpmrVqkXKmkZiSkhIEH9Xq1bN6nJxcXEiMCi+TUvLcQchUyehwtsEAAAAAChNHj+a0+rVq+nzzz8XTY/69esnLc9BAQsJCbFYJjQ0VDympKSUWM7asqblTMuayqluk5cpvE1zsrOzxVR4OwAAAADuwNS3wWHrR54JzXl0zURycjKNGjWKypUrJ/pLeAPupM2dy02TqTYEAAAAAEBrHl0zwcOpXrhwgX766SezOSHMMTVtKtwMqThT0rrC4xMXbhJladnCye7M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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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8sl05JFH0pIlS9SX/TvvvNPlsrfddhudf/75qiwvw8vyOu6++24aO3YsVVc7/ysDV1JGjBihfnbt2pXOOussCgkJoZdffpkGDhxIW7du9eq5AwAAALSHnAlf3sBYQVWZ+Omnn+g///kP3Xjjjdqy9913Hy1dupQGDBhAW7ZsoVmzZtEPP/xAv/32G8XGxtJzzz1H33zzTYvlvvzyS5o2bZoqs2zZMrUML8vr4HUtXryYHnzwwRbL7d27ly677DKyWCz02muv0e+//06ffPIJbd68mS655BLKy8ujSZMmkd2u70IAAAAAANAagqYyUVZWRldddZXqNvTUU0+5LVtcXEyvvvqq+jf/TE1NbXjsiCOOUC0M7Iknnmix7NSpU9VPbtEYOnRow/28jldeeUX9m1saSkub9l184YUXVGvI+PHj6dprr22432w2q31ISEig5cuX048//ujhKwAAAADg30ytcANjBU1lgrse8fiIN998U41hcGfOnDlqvESXLl1o5MiRLR7nFgLGrRTcouCQm5urvvA3LtPYqFGjqHPnzlRbW6u20dgXX3zhcjlu5TjzzDPVvz///HPhMwYAAAAA8K2gqEx8++239Pbbb9M111yjxizorF69Wv0cNmyY08d5AHdycrL695o1a1osx49xC4gzjnU6yrLy8vKG8RCutulsOQAAAICAgkET7U7AVya4yxJXIrhF4F//+pdomR07dqif3DLhSlZWVpOy0uV4P5ov13hAuKtlnS0HAAAAANCWAj5n4qabbqJ9+/bRd999R/Hx+rmjHS0FzF13KO565BiLYdRy7pZ1tpwz3IWKbw668ocy17VuHmvJnNqF5fr52ldsKzAkr0KStzC4x9/jYbwRFRHq9VzsEWH6Ofxz8tzPLy+dG15yrCSv8Z58/f5kpR08d105rOvBVj53truZH90h1Gzyel+kmQxhmuwMqd5dEt0+XltvNWR/JcdbUqZ7pwRDjpVEbmGV15kXkgyJqAj9eqIiory+BkgzJIw4VpJjINmORN/O7s9hti6n2JAMGKJkQ3KBdCTXa6MY9d4MJK2VMzF8+HA1LpUn5ZFMzAPtsDIxZcoU+vrrrw95OR4TwWMTHOMLZsyYQVdccYWanjUYPPnkk/Too4+29W4AAAAA+C0e4yr9IzO008oED2zetGmTR6F0rKCggK6//nrq1KkTPf/8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Y0fqld3V59viwdCOL/EODz/8MD3yyCM++Q4WExPjdl+aV254Jiee7emWW26h8847jyIjI2nixIn07LPPkj9CZSLAcRT77t27KS4uTs2H3N7xm40vAPyc4uP16cDQ+nCM/B+OkX/D8fF/gXaMuEWCv/jyd4a2wl+Y+a/zdXV1rfJ8m38nMrpVwlucKfH9999Te4DKRIDj2QaysrIo0PDFOxAu4IEMx8j/4Rj5Nxwf/xdIx6itWiSaVyj4Fiji4uLUz8rKSpdleBwEa8/nEQZgAwAAAAAYLDs7W/3kFixXHI85yrZHqEwAAAAAABhsyJAh6mdhYWGTAdaNrVixQv1snEHR3qAyAe0K92nkQVL+1rcR/oZj5P9wjPwbjo//wzECiaysLBo+fLj694wZM1o8zunX3DLB5xNPB9temez+MA8YAAAAAEA7cfnll9O7775Ljz32GD3wwAMuy3355Zd09tlnq1mbFi5c2NACwa0Vxx9/PP355580efJkv52pSQKVCQAAAAAAN1atWkU33HBDw+/btm2jgoIC1fqQmZnZcP8XX3xBGRkZTZa99dZb6cUXX6SwsDAaN26cmip23rx5VFJSQiNHjqSffvqJoqKi2u3rj8oEAAAAAIAbCxYsUC0JOjt27HA6mPrTTz+l6dOn05o1a6i+vp569OhBl1xyCd1+++0qY6M9w5gJaFM8JVr37t3VfM9827Nnj8uyPPf0008/TYMGDVK1+qSkJBozZgx99tln2u3MnDlTleVleFlexzPPPKPe0O6sXLlSBcWkp6er6eq6detGN998Mx04cIACDT+n9957jyZNmkS9evVSzzc6Opr69u2rgnNycnLcLo/j4/88fR/A3/i14r8o3nXXXaovNIdL8V8bOWzrzDPPpG+//dbtyzV37lzVNzo1NVX9JZLfX/fff3/D9JCubN26VXWr4L+Ccv9q/sm/b9++3e1ynB1w3333UZ8+fdT2eLunnXaaCsQKJlOmTGn4nHn88cddlsPxAVf42skjA3S3bBezMp1//vmqm1NpaSlVVVWp7k133313u69IKDxmAqCtXHfddXaTycTjdtRt9+7dTstVVlbajznmGFUmMTHRfs4559hPPPFEe2hoqLpv8uTJLrdx6623qjJclpfhZXkdfN+oUaPsVVVVTpebOXNmw/qHDx9uP//88+3du3dXv6enp9u3bNliDyQXX3yxem4hISH2gQMH2idOnGg/9dRT7Wlpaer+mJgY+48//uh0WRwf/+fp+wCa+umnnxquVx07drSfdtpp6trQv3//hvuvvfZau81ma/HSPf/88+pxvuYde+yx6j3G6+D7+vTpY8/Pz3f6ci9evNgeHR2tyh1++OH2Cy64QP10vC9//fVXp8vl5eXZe/furcplZGSo7fF2eft8e/HFF4Pi8C5ZskRd1xyfNY899pjTcjg+AJ5BZQLaDH8x5Qv7TTfdpK1MOL4IDRgwoMkH7ooVK+yxsbHqsdmzZ7dY7osvvlCPcZmVK1c23M/r4HW5qojk5uY2fHi/9tprDfdbLBb7JZdc0lDBcPaFob26+eab7Y8++qh9z549Te4vLy+3X3jhheo5Jycn24uKilosi+Pj3zx9H0BL8+bNs5977rn2X375pcVjH3/8sd1sNqvX8913323y2KpVq9SXWX58zpw5TSri48aNU8vwepvjxzt16qQev/fee5s8xr/z/Z07d3ZaGTzrrLPU47x+Xo/Dt99+q/aDv2CvXbs2oA8zP+9evXrZMzMz7RMmTHBZmcDxAfAcKhPQJkpLS9UHYLdu3ewVFRVuKxP85TU8PFw9zn+ha44/GPixESNGtHiMv/DzY48//niLxxYtWqQei4iIsJeUlDR57K677lKPjR8/vsVy/OU6ISFBPf7999/bgwF/IMfFxann/P777zd5DMfH/3n6PoBDd9VVVzV8gW+MWwX4/quvvrrFMjk5OeqLPT++YcOGJo9Nnz5d3c8tDFartclj/Luj5eE///lPk8f++usvdT9XGnj9rvaT/1AQyG655Rb1PLkCddlll7msTOD4AHgOYyagTdx2221qfMSbb76p+m67M2fOHNUfv0uXLmrWg+a4jz/77bffaO/evQ335+bm0vLly5uUaWzUqFHUuXNnqq2tVdtojGdjcLUcT+/GfaPZ559/TsGAx05wn2tnSZ44Pv7Nm/cBeB5S1fh9wtcvx1gKZ8ega9euDdc2x7XHwfH7hRdeSCEhTT+y+fcLLrjA6bXIsRyvl9ffnGM/Zs+eHbBjZnjA7EsvvUSXXnqp2zn8cXwAvIPKBLQ6/lB9++236ZprrqGxY8dqy69evVr9HDZsmNPHeQB3cnKy+jfPktB8OX6MB04741ino6xjwCIPdnS3TWfLBTL+suEYgN18yjscH//m6fsAPLNly5YW75PNmzerAZeNX2vpMdC9v7xdrrKysmGfAwkPaL/yyivV5BkvvPCC27I4PgDeQWUCWlVxcbGqRPBfQv/1r3+JlnFE0HPLhCs8s0njstLleD+aL9d41iJXyzpbLpC99dZbaj5tng3mlFNOafIYjo9/8/R9AIdu//799M4776h/n3vuuS2OAc/8FBcXJz4G/IcNDrZyd/wcy+Xn56uKQfNtulouPj5e3ZpvM1Dceeed6nm9+uqravYyd3B8ALyDygS0qptuuon27dtHr7/+esMHmQ5/oDJ33aG46xErKyszbDl3yzpbLlDx9HU8DSZ78MEH1V/6GsPx8W+eHh84NBaLRc0Zz9M+DhgwgP75z3+26rXI1bLBeNx//PFHeu2111TXsAkTJmjL4/gAeCfUy+UhiObo/vrrrw95OR4TwX2yHX16Z8yYQVdccQWdfPLJPtjL4GXE8XGGx7WcccYZqssAjxO55557vNxTgMB03XXXqfyJlJQUlX0TEHPHt0NcmbvqqqsoLS1NjZcAAN9DZQJEeGDzpk2bDvnVcgQxcReZ66+/njp16kTPP//8Ia3D0S2gcRO+q+00bu3wdjnHsgkJCaLl2vPxcdVlY9y4cbRz50466aSTVHonBz41h+Pj3zw9PiB36623qq6A3J3mp59+ot69extyDJpfi9wt52rZYDvujsk9PvnkExXQJ4HjA+AddHMCkQ8++ECU/Nj85miBWLx4sUpY5tlHuNmZkyQb3xw4bZp/d/Q7Zo40yV27drncP0dyduPkSce/m88+1JjjscbLNZ75xNU2nS3Xno9Pc3yseHA8D0wcP348ffnllyp11xkcH//m6fsAZCZPnkwvvviiGg/B3Wscszk5OwYlJSVNui7pjgF/yXVMLqG7FvEX58ZdmnTvS+7a5OjeFEjHnWexCg0NpVdeeaXF58z333+vynDFj3/nblAMxwfAO6hMQKviL/0cJ9/85sDTu/LvjQdBDx06VP1csWKF03Vu376dioqK1L8bf5A7/s0DGF0NMHSs07ENx1/pevbs6XabzpYLFDyQkysSGzZsUC0T3H0qMjLSZXkcH//m6fsAZN0LuaWVWy+5IuFq5iSeVpmnV278WkuPge795e1yXAFp3pISCONXnH3O5OXlqcf584V/588bhuMD4CUvMioADNPeQusSExMD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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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TZs2kpqaah717z///DPkcrm5uTJy5EjZfffdzfZ0u0cffbR89dVXYb9WAAAAIFrqXDAxZcoUefDBB61R78MPPyyHHnqofPrpp7LnnnvKMcccI5s3b5ZRo0ZJz549Zd26dVUuN3nyZOnevbu89NJL0qBBAzn++OPNo/7drVs3+eGHH6pcbs2aNWa999xzjwkqdHu63U8++UQGDRokjz32mCevH6itSa9sU13lcmw0yaNtQmTHGMFx/WFnJFTDf6pXr17SpUsXGTNmDCcoQnXqG2Tr1q2mhqBly5YyePDgoOVmzZolV199tSQmJsrHH38skyZNkrfeekv++OMPGThwoMybN08uvvjiKtc/dOhQ83jjjTfK7Nmz5Y033jCP+ndeXp6Zn5+fv8OyF110kcyfP9+sX2s2dHu63Y8++kgSEhLkyiuvlF9++cXzYwIAAFDXTJs2TX7//XcZNmxYTe9KrVenggm9oV+wYIE888wzUr9+/aDltHbA7/fLueeeK0ceeWT58xkZGfL888+bm/vx48fL3LlzKy334osvyooVK2S33XbbofmU/q3PL126VF5++eVK8/Rifv/9903wouvX7QRoMysNgMrKysx+AQAAxKsE39+5JqIz1fQrjD91JpiYOHGiaSp01llnmRv0YIqKikxthDrttNN2mN++fXvp06eP+fe7775baV7g71NOOcUEHBXp3yeffLL59zvvvFPlcrpeXf/2Avvx4YcfSnFxseMrBgAAAKKrTgQT2mH6vPPOk+bNm8sjjzwSsqw2NdJmSkr7MFQl8Lw2h6oo8He0ltNmUlqzAgAAEI80D0S0J3irThzRa665RhYtWiRPPvmkNGzYMGRZLae003RWVlaVZdq2bVuprNJO0+vXrzf/bteuXcjl1q5dawKD7bcZbLns7Gwzbb9NAAAAoCbFfZ6Jzz77TJ5++mnT9Oi4446zltegQNWrVy9omczMTPOYk5Ozw3Khlg0sF1g2UM51m7pMxW1WpbCw0EwVtwMAAFAbBPo2RG395JnwXFzXTOhQrueff740bdq0zgytqp20tXN5YArUhgAAAABei+uaCR1OddmyZfLmm2+aBHAuAk2bKjZD2l4gaV2g6VHF5UItWzHZXVXL7uw2g41YNWLEiEo1EwQUiJblG7f1LwqldcO/RycLF3kQODY1qTqvP5ecFbwfEM+i3a+BPhPei+tgQkdJSkpKkieeeMJMFQWGddWhWDXTdYsWLUxOiA4dOpjnN23aZJofVdVvQod3VYGySss1atRINmzYIEuWLDGJ64Itp4FNxSZNup6ZM2ea5apSsXlTxW1WRTNu6wQAAABEW1wHE6qkpMQkfwtm8eLFZgoMybr77rubPA86otP06dPlkEMO2WEZfV716NGj0vP6twYmOl8zWO/McjpcbGB+sOU0ANFcFQAAAPEowZdgpqitP75b+NeIuD6iWrugyeeqms4++2xT5s477zR/a0ChUlJS5Oijjzb/Hjt27A7r/Ouvv2TKlCnm38cff3yleYG/tYZDk8xVpH9rcyt1wgknVJoX6Bg+efLkKmsnAvuhAUpycnLYxwMAAADwUlwHE+G64YYbxOfzyQsvvCCffvpp+fNaW6EduktLS+XEE0+UPfbYo9Jymqm6VatWJlfFLbfcUmme/q3Pt2nTxiTOq2jPPfeUwYMHm/Xq+vPz88vnffLJJyaztia90/4QAAAA8Sr6WSZIge21uG/mFA5tdvTggw+ajsyaLbtfv37SrFkz+fbbb2XlypWmKdRTTz21w3LaPOqtt96Sww47TEaNGiUffPCB7LXXXjJ79mwzaTOlcePGSXp6+g7LPvPMM/L777+bZlKdOnWSgw46SNasWWOaaGnNyejRo6Vbt27VdAQAAAAAO2omgrjqqqvk888/l8MPP1x++eUXef/9902uB60dmDZtWtDRofr06SM///yzqX3Qztjjx483j/q3Pt+7d+8ql9NgRftGaK2Ibke3p9vV7WuAMXz4cIfTCQAAUHv5fAlRn+Atn19/9kbc0lGgNN+E5tywDSsLxOrQsEBdwdCwqKv3CoF9uDbrKkn1RW9UykJ/ofw792HuizxEMycAAADEhGj3a6DPhPcIJgCEjVoHwFu1LSEdNSkACCYAAAAQE3xRzjNBBmzv1a6fQAAAAADEDGomAAAAEBN8//svmuuHt6iZAAAAABAWggkAAADEhgRf9CcR6dWrl3Tp0kXGjBlT06+41qOZEwAAAOoUTUBM/i1vEEwAAAAgNvh826bobSCK666baOYEAAAAICzUTAAAgDqRZA+xz+fzie9//Rqisv4yaia8xqcAAAAAgLBQMwEAAIDYoBUH0ewzQcWE56iZAAAAABAWaiYAAAAQGyrkgogOqia8Rs0EAAAAgLBQMwEAAIDYQM1ErUPNBAAAAICwUDMBAACA2MkzEcXRnKK57rqKYAKIMwWlZdYyJJoCAD5nAS8QTAAAACA20Gei1qHPBAAAAICwUDMBAACA2KB9GqKaAZs+E16jZgIAAABAWKiZAAAAQGygz0StQ80EAAAAgLBQMwEAAIDY4EvYNkVz/fAUwQQQZ8ghERvqar6Puvq6Y+kYc3yjj2MM/I1gAgAAADHBl+AzU9TWL4zm5DV+HgIAAAAQFmomAAAAEBsYzanWoWYCAAAAQFiomQAAAECMiHIGbPpMeI6aCQAAAABhoWYCAAAAdaPPhJ/RnLxGzQQAAACAsFAzAWdLliwxj5mZmdKoUSOOHKpNbUyEVl37E2vHJtbOQzziGAOIRH5+vsyfP1/atGkjjRs3lkjxqQ9nHTp0kI4dO8obb7zBUQMAAJ7z+XxRn+qCb7/9VkaMGCE///xzpefHjh0rzZo1kx49ekjLli3l//7v/yLeFsEEnKWnp5vHXr16cdQAAECtpfcyXbp0kTFjxkg8euaZZ+Txxx+X1q1blz+3dOlSOe+88yQvL0/q168vJSUlcscdd8ikSZMi2hbBBJwFLsjS0lKOGgAAiF4H7GhOIjJt2jT5/fffZdiwYXF5FqdOnSrdu3eXJk2alD/3yiuvSFFRkdx+++2yYcOG8iDiiSeeiGhbBBNwdthhh5nH7777jqMGAAAQo9atW2f6RFT01VdfSUpKimn+pA466CDp3bu3zJo1K6JtEUzA2RVXXGGaOj3wwAOyfPlyjhwAAPCW9mmI9lQHbNmypbx5uvL7/aY2pmfPnmYgnYr9YVesWBHRtggm4GzXXXc1HXe2bt1qIln9t1aXAQAAIHboqJuLFy8u/1trH3Jzc+XAAw+sVK64uNjUVkSCoWHhbMCAAeaxadOmsmjRIjnzzDPl/PPPN0FGw4YNJTExMeiyOnrCl19+ydEGAADBkbTOsw7mn3zyiXz//fdywAEHyOjRo829WOBeLmDBggVmVKdIEEzA2cSJEysNqaZVZoWFhTJ79uygy2h5LVdXhmIDAACIhabpEyZMkL59+5qRmzZv3iy77LJLef/XQL+KX3/9VU455ZSItkUwAWcHH3wwQUEdEkvJ0EjSxbEBUEdQM+GJQYMGyX/+8x8z9OuaNWukX79+ZtSmhISESqM7lZWVmXmR8Pn1Z2PErZycnPKINDs7u6Z3B7VILAUTAID4vlcI7MMte90naYlpUdtOQWmB3Dn7eu6LZFsmbO37qh2yQzVVt+FOAAAAADFh24BL0cyALXXCN998I/Pnzw9ZRkd70lqLyZMnR7QtggkAAAAgjvTv31/uu+8+a7n7779fDjnkkIi2RZ8JAAAAxAb6THimunoyEExgB0uWLCn/d7t27ap8PhwV1wUAAICatXHjRklLi6yPCsEEdtCxY0fzqG0LS0pKdng+HNuvCwAAoIobhuhmqY7jThNLtvvRV7NgB/shWO/JfvvtN/nss8+kU6dOEW2XYALO1WIM/AUAABCbOnToUGkI//Hjx5spFL23O+OMMyLaLsEEdvDCCy/s1POIz6FYGfa1bom16y8ecYxr/hhzDdcC9JmIqDl5IJjQGomMjAxp0qRJlWVTUlKkTZs2cuKJJ8oll1wS/kYJJlCVs88+e6eeBwAAQM1avHhx+b81Od2QIUNM4rpo42cmRN2sWbPkqquu4kgDAICQoptjYttUF7zwwgty/vnnV8u2aOaEqFi5cqW8+uqrJlW7dvBRDz/8MEcbAAAgyqqzNQnBBDxNy/7OO+/Iyy+/LF999ZWUlZWVd+6pK78EAACACOj9gvabiJayunc/UlpaKuvXr5eCgoKoDN9PMIGIff311yaA0EBChyGrOPJTy5Yt5fjjjzcdfAAAAFA9pk2bJrfeeqtMmjRJCgsLozZ8P8EEwjJ37lwTQLz22muybNmySgFEYHSAk046SQ488EBqJQAAQGyM5hTNdceQH374QQYMGFBeG9GwYUPJzs6OyrYIJuBMq8hef/11E0TMmDGjUgDRoEED2bRpkwkcHnjgARk6dChHFgAAoAbcdtttJpA477zz5O6775bmzZtHbVsEEwipuLhYPvzwQxNAfPrpp+bvQAChYxQfddRRJtnJ0UcfLenp6RxNAAAQPjJge2Lq1Kmy++67y7PPPhv1FiIEEwhaPaYBxFtvvSUbN26s1JG6T58+JoDQ2getNoM3SKYUX+pqgjKX1+0iHo+Ny2uqq9eNVzg2wDbaB2LvvfeulqbmBBOoUqCvQ6AWQqNbDSBOP/10k64dAADAc/SZ8MQee+wh69atk+pAMIGQsrKy5NFHHyX7NQAAQC1x0UUXyfDhw+WPP/6QTp06RXVb1JUiKK2V0KFetfNOjx495KGHHjLJ6AAAAKKBDNjeBROnnnqqHHrooTJhwgSTayJaqJlAlSZOnCgvvviijB8/XnJzc+Wnn36Sn3/+Wa6//nrp37+/nHnmmXLCCSdIZmYmRxAAACCG7LLLLuZx8eLFcswxx0hSUpLJ/ZWQkFBlAKc1GOGiZgJVOvjgg+U///mPrF692uSSOPzww80FqJGtZrc+99xzpUWLFibqjXbECwAA6lifiWhOdcDixYvNFGhpoqNxLlmypPz57adIUDOBkNLS0kzAoNOqVavk1VdfNdMvv/wiW7duNaM96dS4cWOOJAAAQAxYtGhRtW2LYALOtCbimmuuMZM2eXrppZdMEjutvdARAwLDj40YMUImT55sMmAfdNBBHGEAAOCGPBOeaN++vVQXmjkhLN27dzcdspctWyYfffSRyTmRmppqqtJWrFghjz/+uOlboe3zLr30Uvnyyy850gAAAHHG5w8kEkBcysnJkfr168vmzZslOzs76tt688035ZVXXjE1E4FLKzAygyZQAQAAdfdewbYPt/cbI2lJ6VHbTkFJvtw+aViNvtbqPq7aPH3KlCmydu1aGThwoFx33XVm3vz5801/Ce0nq83aw0UzJ3hG35QXXnihmfTi1GZQegFHMkIAAAAAdt5nn30mp512mmzcuNH8wKs/7LZu3bp8/rx58+S4444zTda1hUm4aOaEqNAs2bfddpssWLBAvv32WxNgAAAAhOSrhqkOmDNnjhx//PGmBuaSSy4xLUe2b4ykI3VmZGTI+++/H9G2qJlA1PXp08dMAAAAiL5Ro0ZJQUGBjBs3zuQFUyeffHKlMikpKbL33nubQXUiQc0EAAAAYms0p2hOdcDXX39tBssJBBLBtGnTRlauXBnRtggmAAAAgDiydu1a2W233azldHCcvLy8iLZFMycAAADEBF+Cz0zRXH9dUL9+fVm+fLm13J9//inNmjWLaFvUTAAAAABxpEePHjJjxgxZsmRJ0DKzZ882/SX233//iLZFMAEAAIDYwGhOnrjgggtMB+xTTz1VVq1atcP8devWmTI6wpM+RoJmTgDiQkFpmbVMWiK/nwAA4t9JJ50kQ4YMMaM5derUqXxUTU0qfOyxx8rEiRNly5Ytcvrpp5shYiNBMAEAAIAYEe0Rl+pGnwk1duxY6dy5szzyyCPyxRdfmOc0/5dOOizs1VdfLffee69EimACAAAAiBFvv/22vPbaa6bPgzZH6tixo5x33nkyfPhwSU5Odl5PYmKi3H333XLNNdeYoWK1s3VZWZm0bdtWBg4cGHHH6wCCCQAAAMQGHW0pmiMu1YLRnB544AHp0KGD3H///dK8eXOZMmWK3HzzzfLLL7/ISy+9tNPra9iwoTXfRCQIJgAAAIAY8eGHH0rTpk3L/z7kkENMR+lbbrmlPMCweeyxx+SMM84wgUS00RsRAAAAsYHRnKRiIBGw7777mscVK1Y4HcYrrrhCWrVqJSeffLJ8+umnJhiJlrgPJoqLi+XLL7+Ua6+9Vnr16iUNGjQw7c1atGhherN//PHHIZfXDitHHXWUNGnSRNLT02WPPfaQm266yfSAD2XhwoVyzjnnmDTlqamp5lH/1vZqoeTm5srIkSNl9913N9vT7R599NHy1VdfhfX6AQAAEJl58+aZX/v1Xq5r166SlJQkPp9P7rrrLqfldVSl/v37m5qCevXqSffu3U0tg96nuvjmm29Mp2kdmcmFNmvSAEK3q/eR2k9C71+187XXfP5ohioxQIOBQw891PxbAwiN7PQk/v777yZZh7rooovkqaeeMhdFRQ8//LCMGDHCPH/QQQeZaqVvv/3WjNerN/vfffedudnfng67ddhhh8nWrVtlzz33lL322sts67fffjPb1n3q3bv3DsutWbPGbGf+/PnSsmVL6du3r6xevdpsU40ePVouv/zynXr9OTk5Jgvi5s2bJTs7e6eWBWoThoYFgPDEwr1CYB/uOOIZSUtOj9p2Corz5bZPL9rp13rllVea+7Dt3XnnnaY/g8uyGoAMGDBAMjMzzY/EmzZtMvd6n332mfkBORi9Z+3Zs6ecf/75JqBxtWHDBnn11VflhRdeMMnpAve5OkzsueeeK0OHDjX3pZGK+5qJhIQEOfHEE01Et3LlSvnoo4/kzTfflF9//VXeeOMN09P9mWeekVdeeaXScrNmzTJDZul8rb2YNGmSvPXWW/LHH3+YHvAaoV588cU7bE8DCD05+njjjTeaIEK3o4/6d15enpmfn5+/w7Ia1GggoevXmg3dnm5X91lfh16M2vkG1X+TaptQ8zSHhG2qbeeyOvc31o5NLO1LXRVr1wRQk/SHYR0VSUdZmjNnjpx55plOy7333nsmkNAAYurUqfLf//5Xxo8fb2oItIZDf5jWvhDB6GhOxx13nBnidWeHcW3UqJEZAUrvaXW67LLLpHHjxmabmqhOf2TXUaL0HjkScR9MaASoQ2zpL/7b03ZkWl2lXn755Urz7rnnHlM9pJHbkUceWf58RkaGPP/88+bmXi+GuXPnVlruxRdfNO3Zdttttx2qvvRvfX7p0qU7bE+jzvfff98EL7p+3U6ANrPS/dThvHS/AAAA4lJCNUxh0Jvvf//733LaaaeZJu96H+hi1KhR5vGGG26QHj16lD+vLVueeOIJ8+/HH3/c1JRU1fRd70GLiopMv4dIahG0WZUGNXqPqvfFem9ZWFho7lv1XjkScR9M2Oyzzz7mUW/wA/SkBfpS6EWzvfbt25dnEnz33XcrzQv8fcopp+xwoenfGsCod955p8rldL26/u0F9kN7+Lu2rwMAAEDNWL58uUybNi3o/aQ2cdK+DHpTP2HChErz9LnBgwfL4sWLTW2Gdqb2gja10v4UTz75pPzrX/8yz0Xa46HOBxOBjijaRyFAmxppMyWlbdSqEnheq40qCvwdreW0mVQ0Os8AAADExmhOvihO1fdSZv3v3k6bG2niOdf7wtLSUvOjtAYiGmRoP10vaICiTe8PP/xwsz+BmhHt3xuJOp1nQjtSa/WO0n4VAYsWLTKPOvJTVlZWlctqJFmxbKA6av369ebf7dq1C7nc2rVrTWAQqLIKrCfYctpJSCftoKRlu3TpEsYrBgAAgN5PVaQjb+rkpUWWe7tg95PDhg0zfS20c7cGFj/88EP5PL3/29lO8tpXQ+93tc+wNqfSmgjt7K4Bizbn32+//SQSdTaYKCkpMck89KBqB5hAVU8gKFCh2qZpR5rtL8bAcqGWDSwXWDZQznWbusz2b4Dto06dKm4DAACgNtARh7YfXdPr9Ve8iQ+47bbb5Pbbb/d0W7lh3k9q/wilHbO375z99ddfmyFmbXTQIR1cSDNma/9eDSD0tWsCPA0g9Ef0tLQ08UKdDSZ0JCbNP6G92rUjio7dGw+0g/Ydd9xR5WgAFYMMuGPI0fhR285lde5vrB0b2/7E0nmKV7F2TSB6Kv4YWldoX9mKv/B7XSsRCe0nESmtDdGBezSI0L64Z599tgkiquqXG6k6GUxoVkAdMUkTh3z++edmhKWKAk2btBlSMIGkdRUvxIpNooItWzHZXVXL7uw2t6fDz2pujACNdDX6dk1yAgAAUOMZsKO5/grNx6Mpy6N7u0g6WuvQr5pyIJrqXDChuSMeffRR0x9Ck4QERnOqqEOHDuZRk4lotF5Vv4nA6E+BskrLaScbTRKyZMkSMwxXsOV0SLCK1V66npkzZ5rlqlKxeVPFbW4vGm3+AAAAsHM6/O9+reKIoS73k171C9Z+EdWhTtVPXnfddfLQQw+Zg6uBRLCRk7TXfCDPw/Tp06ssE3i+4pjBFf+O1nIagGxfkwIAABAXEnzRn6rJPv/7wVoH56nYwdrlvjBS1RVI1KlgQpOFaLIRPbjatKlXr15By2r/iaOPPtr8e+zYsTvM/+uvv2TKlCnm38cff3yleYG/degtbatWkf6tPemVVj1VpNkN1eTJk6usnQjsxzHHHCPJycmOrxoAAAA1oU2bNuX3m1XdT2omaq2Z0BYlmkQuEv/3f/8nH3zwQZXzfvnlF1m2bFmV8x577LEd7kl3Vp1o5nTzzTfLfffdV960KVQgUTH40I7ZL7zwgunxfsQRR5jnNf/E+eefb4bq0uc1C2JFmqn67rvvNrkqtAe+/jtA/9bn9eI666yzKi2nY/xqchLNgq3r1wsiPT3dzPvkk0/MkF6a9E77RITjmXe+kfR6f48kFY7i0tBJTUodOutt2VJkLVPmsJ6SghJrmZR69k71WzfkW8skJNl/xUiwdEIs3FxgXUdGU3tmy/wN2/KfRKrU4TyY8bht1jnsj+1XoAyHwQ822s+TJDrsr8vrtlznyl9c6s3xK7Fc62Uu+2J/v/jSEu3rybO/p3yp9vWIw/vFaVv1Qv9o4nN4f4vL/hba90UyHL4qkxy2VT/Nm/2xsRw75Uu1vyZ/kX1fEhzWk5xpP1dlhQ7vKQe2baVketMM2O/wPdWqmf07d+V6+2dovXT7MS5w+Eyqlxb8usjfukWGndRPYkIgH0Q011+NRo4caX5ovvfee00260ANhNZWXHrppebfl112WcQ1CToSld6DHnvssVXWkOg87S+8PW1ir/eekYj7YEJvygM39J07d5YxY8ZUWU77MDzwwAPlf+vJfvDBB01nZo0W+/XrJ82aNZNvv/3WDLelTaGeeuqpHdajzaPeeustOeyww0wKdd3+XnvtJbNnzzaTNlMaN25ceaBQ0TPPPCO///67fPHFF6bD9EEHHSRr1qyRSZMmmd74mga9W7duYR2H7AaNJCOz6pwZXgUTJQ4frr4k+4hSZbYbLN1WqkMw4fAFllhi/yBPSEqIuExymf1muF59+xdPYrE3X4Sl4lEwkZ8SeTDhclNYmOpNMFFa6E0wkeRRMFHsQTCRaN8XX5rDjWNpsUfBhP394i9x2FZ66OvC5xKEuuxvgksw4VAbnOywrUyHYCLZi2AixZtrwqNgIiXL/v4t9SKIctiWy754FUw0aGj/zt1Sar8mMh2uv5Qi++dAZnrw9STHyYiW0aQ33YGbf/XHH3+Yx6efflo++uij8ufffffdSomQteXJ8OHDTX/d3r17m87Qei+oI4pq39w+ffqYfBLRpPeQkWa5rtPBhHaGrtguLVifBB0qq2Iwoa666iqTg0KDih9//NH0xtehtrR2QKdgCe30wvj555/NxaGBwfjx46Vp06amNuLWW28NOrKSBiu6fzq8qy6jkaJecJqp8Jprrol6b3wAAIC6MJqTtlJJTEw0CeJ0stFBcDT52/aWLVtWqQlRVcPw64/Bem+oP2hrM/ni4mJzL6itYPRes7anJ4j7YEKrdXQK16BBg8y0s7QWRBOF7CwdGkyDCZ0AAADgvWnTpu3UcKyaKC6SX/eHDh1qpngU98EEAAAAaoloj7hUjaM51RV1ZjQnAAAAAN6iZgIAAAB1qs8EvEMwUUekJCVKaoihCwtLIh+Wb8tW+wgtaSFGkwgoyC/2ZKSmIodhQF1G5EhwGPWk1DKShkszy9wV2zKch7TBPsSsNHIZftLhfLsMf+qyHtvoPstyPBmpyZ9jP98+h5GGynILvXndKYkRj6hT5jCksMuoUX6H96aUOIwclefRiE+WoZTNtizvX5fX5DJikc9lpCaX8+1wbJw+CFzWY7uOHTaT2sw+FHXBhjJPhvIuWG5/j6e2tI985HcY3azI5f1rkdV4W9LaUAodBsRbujpXvFDsMMJhr92aWstM+XVl0Hn5eQ6fNYh5P/30k8k3sTPz9PlIEUwAAAAgNsRZnonqpCOJ6rQz87RTuS/CY0IwAQAAANRiBx98cMRBQbgIJgAAABAT9IbYF8URl2rqhjvaJk6cKDWF0ZwAAABQp2jSui5duphEcogMNRMAAACoU6M57WzSOgRHzQQAAACAsFAzAQAAgNjAaE61DsFEHdGmaT3JzMoMOn/his3WdZQ4jCduU+owTnixw/jxCQ75AlzyTLhw6QhWZsnJ4HcZ+9xlDHqH/Bri8rodcnmIw7mSZIfKzXX5oefXT7WvwyW/gUsOCYdj43PJgeBwGsrWbbWWScgK/dr9W+yv219UYi3jS03y5HW7ND3wl/o8OVe2PBIJTey5APwF9mMjDu9vn0OeE6fr2CVPTON0e5l0y/l0OJcu+RgSHN7fTrlQMuxvmMIc+3qy29SPOOePy3dH7nr7ezfF8t51/Q5y+X5xeW/OXLjOWiYrxD4nJnjzfYm6iWACAAAAsUEDrCiO5hTVdddR9JkAAAAAEBZqJgAAAFCnRnOCd6iZAAAAABAWaiYAAAAQGxjNqdYhmAAAAABqscTExLCX9fl8UlLiMPpdEDRzAgAAQGxIqIZJRHr16iVdunSRMWPGSDzw+/1hT2VlkQ39TzABAACAOmXatGny+++/y7BhwyQelJWV7TCNGDFC0tLS5IorrpCZM2fKxo0bzTRr1iy58sorJT093ZSJNJigmVMdsWxtntTLDx47pibZq8eKS0MnMevcKtu6jqXr8rxJBuSQcCk1276ewpxCT7ZVZknol9I8074dh31xSvZlLaHJ5hyqQ1fneZNEz5JEykmJ/YPO75KIz2E9ZQ4J8lz4HI6NNYmeQ+LAhPpp1jJ+h+RZLjkTxSVxpeVzwmxrq706PSErJfIRWRz2xZfi8J5ySZrosC0nDteoNVlkgkOyuUKXhH4Jnlx/6Y3tCQYLNuXbD41DEsKktMhva1y2k9HQnlywgUOSvU0uCU0d7Nra/v27emPwY+wvCr+JjOfoM+GJF154QR555BH5/PPP5ZBDDqk0r3v37vLQQw/JscceK4MGDZJ//OMfcv7554e9LWomAAAAgDjyxBNPSJ8+fXYIJCrq37+/9O3bV5588smItkUwAQAAgJignYGjPdUFc+fOlbZt21rLtW7dWubNmxfRtggmAAAAgDiSlJQkv/76q7Xc7NmzTdlIEEwAAACgTo3mFO969+5tAoVHH300aJnHHnvMBBwHHHBARNuiAzYAAAAQR2699Vb54osv5KqrrpK33npLTjvtNOnYsaOZt3jxYnnttdfk+++/N7USN998c0TbIpgAAABAbGA0J09obcPYsWPlggsukClTppjAoSLNL5GZmSnPPvusHHjggRFti2ACAAAAiDNDhgyRgw8+WJ577jmZNGmSLFu2rLzTdb9+/cxwsC1btox4OwQTAAAAiA3UTHiqefPmctNNN5kpWggm6oi0lEQzBbPKIWFQg4zQSaQWLN1k34/0ZGuZrWvtydJ8Cfah3RJDvN6AjCYZniQwSrUkbtq0aKN1Hcn17Mem1CEBXGqzetYyBX/a90cap3uSFExsCcpcOsM5lPE5XFuS6JCgzOEY+3PtSeB8pQ47bUtK55BJrnR1rn1f0hyOTUGxJ8kOExyS9fkLHY5xcejkbT7LfFMmzb6/fpfEdo3S3G6AbIpLI09Ip/It7ymHhJ0u793krGRPkh26JKQrLbAfm7KMyLL0mu04vL9dvjvy1m+1lilxSOiX6rAtl4R0C5bnWMu0bRL8uyGpzCEBKRBEHenTDgAAgJhXTaM59erVS7p06SJjxoyReJaTk2MS2J1xxhly+OGHy/33318+b/78+fLZZ59JQUFBRNugZgIAAAB1yrRp0yQ7217rU5t99tlnZhSnjRs3mg7XmrBP+0sEaLK64447Tl5//XUZOnRo2NuhZgIAAACx1WcimlMdMGfOHDn++ONl8+bNcskll8ibb75pAoqKtKYiIyND3n///Yi2Rc0EAAAAEEdGjRplmi+NGzdOTjjhBPPcySefXKlMSkqK7L333vLzzz9HtC1qJgAAABAjol0rUTdqJr7++mvp3r17eSARTJs2bWTlypURbYtgAgAAAIgja9euld12281arqSkRPLy7KNohkIzJwAAAMSGCiMuRW39dUD9+vVl+fLl1nJ//vmnNGvWLKJt1ZFDCgAAANQNPXr0kBkzZsiSJUuClpk9e7bpL7H//vtHtC1qJuqIZevzJKMgeOxYakueJSJbEksiTkiXnmq/5NJ3aSReWLnYnpitWSv7sHCrl222lvGXhk6mlOKQyMslUZLfb0+WVrDOobrSpcno5kJ7mRKHJFK2rFY+h980EhySzZXYkwuWrXZIiJjlkLwpzX4dl+U4jNttuW7K8rw5B/6t9uvGJfuYS/K70lz7605sWT/i1+WS+M6JS+JFW5I4PTYN0zxK8uiQPLBTw9DzNzpcew77W+JwjJMz7NdEUpr9PVWaZt9WemN7ktF8SzK5hCT7Z0mb9g2sZYodzmWJ5f1t1uPw/i1wOQ8OrystNfh3TEmR/fun2pAB2xMXXHCBGRr21FNPlfHjx0uLFi0qzV+3bp0poyM86WMkqJkAAAAA4shJJ50kQ4YMke+//146deokhx12mHl+8uTJcuyxx8ouu+wiP/74o8lDoUPERoKaCQAAAMQGaiY8M3bsWOncubM88sgj8sUXX5jnFixYYCYdFvbqq6+We++9N+LtEEwAAAAAcSYxMVHuvvtuueaaa8xQsdrZuqysTNq2bSsDBw6MuON1AMEEAAAAYgOjOXmuYcOG1nwTkaDPBAAAABBHBgwYIPfff7+13AMPPGDKRoJgAgAAALEhmtmvK/TH6NWrl3Tp0kXGjBkj8WjixIkyd+5ca7l58+bJpEmTItoWzZwAAABQp0ybNk2ys+3Dw8e74uJiSXAYfj0Ugok6oklWmtTLdBgHPYRVm/JDzi/Ms49lX1hkHy+7tNA+prvLWOENWmZZyyxfuN6TcdRtUrNTrWVKHY5NkkN+g/RG6dYyeau3WMuUrQ09XrvhcK7Edq6KvckX4HM4NgnN61nLlK2yHxsnLq/Lkt/FJT+Ev8ghL4FHfAX2bfnS7TkF/A7Xui859HXjCzFmfjnLOgyHcf59Tez5Dfxb7OfKVz818veLKnLI72LjkiLGIXdLUUGJJ8fPJc9OUa4970qZ5Xy27GDJ0aFpOhzOpYtih8/Hhg3sn9cFDu+XdIfjFypfhct3c7XRioP/1R5Ebf0o9+uvv0rjxo0lEgQTAAAAQC133nnnVfr7u+++2+G5gJKSEvn999/lp59+MnknIkEwAQAAgNjAaE5he/HFF8v/7fP5ZOHChWYKpVWrVmb42EgQTAAAAAC13AsvvGAe/X6/qZHo27evnH/++VWW1aR1bdq0kd69e0tycmTNuQkmAAAAEBvIgB22s88+u/zft99+uwkUKj4XLQQTiNhvM6fId5++Iwt+myk5G9dJcVGR3PrYO9KqXefyMvNnT5cVfy2QjOxsOWDQYI46AABAlCxevFiqC8EEwlZYkC/P3nudTP/us21P+P83Mk0VozDosGOvP323mbfLP7pL89YdOPIAAKCK0ZyieFAYzclzBBMI25j/Gy6//PiNCSJ22aObdPpHD/n83b87/1TUuUsPadV+V1mxZKHM+PYzOeqUizjyAAAAUVRYWChff/21SU6Xk5Nj+lNsTztr33LLLWFvg2ACYZn2zafyy9RJpqbhnBF3Sf+jh5o8E8GCCbXPAYNMU6d5v/xIMAEAAHaU4Ns2RUs01x1j3n33XfnXv/4l69cHz6mlwQXBBJwUlZRKUknwpDT1M+yJpjLT/+7t/8MX75vHfocfJ/886fQdyqakJ0tqvcrr7LxnN/O4etmf0iArePKmdfn2xFhZIZYPWL1oo7VMhkMypfwNoZP1uSScK8yxJ1vKamVPspe3xp5QrcCSXNA1UZeUOpQpdihjS9SV7JB8bHOhJ0ninJKlNbQndyxdlmPflsP+lG0OnRjQX2BPnlWaaz/fxWXeJLZLzcy0lklMs48K4s8tsJbxNQ6dYLDMIbFYgkMCR5dEck4J6Rqne5OQrjR0IkMjxZLQL83+ueYiOcN+bIq32q+tlEz790vuCvt7Ks0hwZstQeiyeWut68hsZc+KnORwLoscrpsSh++ypatzPUl+ty5E0r+teQ6fsahVpk+fLieffLL59ymnnCK//fabSVB3ww03yIIFC+Tzzz83NRU62pOO6hQJaiYQlj/m/mIi2QMHHeO8TIPGzcxjzqYNHHUAALAjRnPyxAMPPCClpaWmdkKT0p177rkmmAjklFi7dq2cddZZ8sknn8isWbMi2pbDzyTAjnI3bzKPjZpsCxBc+HzbLjd/mcOv2QAAAAjL5MmTpUuXLkGzWzdt2lTeeOMNycvLkzvuuEMiQTCBsGRkbmuSs2HdGudl1q5aah6zGjTiqAMAgOCjOUVzqgPWrl0re+yxR/nfSUnbGiMVFPzdzLR+/frSr18/mTBhQkTbIphAWFq17Wge/1rwu/MyM7/7wjx23G1PjjoAAECUZGVlSUlJSaXAQa1YsaJSOc1+vWrVqoi2RTCBsOx74CFmBIAJb78kRYX2zpTzfpkmU7/+2PSz6Nl3IEcdAABU3WciIYpTFbmw4lGbNm1k6dJtLUJUoJZCh4kNKC4ulh9++EGaN28e0bYIJhCWI046SzKzG8jmDevkgZGXlveh2F5paYlM/OhNefimi6TMXyaNm7WUQ44+iaMOAAAQJX379jUjOG3evNn8ffTRR5umTiNGjJAxY8bIhx9+KCeccIKpqTjooIMi2hajOSEsGfWyZMSdj8vdV58rs36YKP867gDZvdt+5fPffOZ+KSkulsXzZ8vWvFyT2C45JVWuvmuMJCXZh44EAAB1UDWN5tSrVy9JTEyUYcOGmSneHHfccfLpp5/KpEmTTCfsli1bysiRI01n6+HDh5sy2sKkYcOGctddd0W0LYIJhK1brz5yx2NjZfQdV8raVcvl12nflL9JTWbsbVeqeWjUtKUMu2207Lrn3hxxAABQo6ZNmybZ2facIrXVwIEDTT6Jim677Tbp2rWrjBs3TjZs2CD/+Mc/5Morr5R27dpFtC2CCRhz/wieHTGgZcsdk6p17dFLnh4/Sb75/AP59sv/mpqI3E0bpKys1DSDatepi3Q/YID0OfQ4SUpOkfzCvzsDBeNzyE6ZGyL5TkDzjg2tZVYttL/uFIekQo2ah07mtfTXVREnvlMJifaWiWUuyeZy7MmUxCF3llPyu0RLUrq8Ym+2U1jqybVVtsl+bflS7B+dfpckUGWhD/K6DSutq9hUvK0KO5RSv8OxcfglsElpY2uZRg7XqC/dnsTMbznnCfUcajj/92NGSEX2a8uXmuhNsrlCh2vdIWmibAzdT82fZT++KQ5Jzlz4i+yf6Xmr7ck2UzLtn7MJDoniyizXjUtCOr/DZ2hiiv2ayG4aOvGiq7QKCWOD2eKQ7LVi4tmYFu0Rl+pGl4mgtGmTTl4imEDEEpOS5JAjT5C9DjiKowkAAFDDBgwYYDphv/zyy1HfFsEEAMSQ/NKtUibbfhnd6s+XFEmWJF/VH9WF/kIp8P/9K3WS/hekbJG/qHy9O1s2UZIkOeg+FEmp/F3zUa+sUFIT7L8yA0CVAqMuRUs01x1DpkyZYvpNVAeCCQCIIS+uel6WFy4r//vQlAHSJekfVZb9sHCCLC/7e8zw/RN6yR6Ju1dZ9ruy72WF/++y+yTsLXv6ql7v96VTZYn/7yEFuyXsJd0Tu1VZdmLRJPm9dG75330S+8oRDY4I+RoBANGltRKFhQ7NbasrmNhll1082Zi2yf3jjz88WRdq1qrlS+Sxu64z5/Sq2x+Wxs1ahCy/cd1qee7+6yQhwScX3/hvadQ0dHkAAFAHVdNoTvHun//8p7z66quSl5cn9ep5038nomBi8eLFnmzMpYMfaoevJ7wjs2f+IP/o1tMaSKiGTZpLWWmpzPtlhnz32Xty7OkXV8t+AqhZhWWF8tnmzyo9d2STIZKa6NDRGAAQFh25KZBL4plnnpH27dtLjTdzOumkk+Tf//532Bu65ppr5J133gl7ecSWn6dNNsHhAYe4N2fo0fdQWTB7usye/h3BBFBHlPhL5Me8qZWeG1R2HMEEgKoxmpMnrr76atlzzz3lo48+kt1331322Wcf6dChg6Sn7ziSm97PPf/889EPJjIzMyOKanR5xI9lixeax0577OW8TLtO29pnL//fskBdVVJWLHM2z640fOwe9bqYDtHntDi/vPPzujXLTQfsYI5JPUo2Fm+q1Kk6mL4JB+zQATuYAxL3l/2lV6UO2MH0T+knB0nf8r+bZrcMWhYAUD1efPHF8hZBRUVFMnXqVDNVpVqCicMPP9wkuYiELn/YYYdFtA7Ejq1bcs1jvUz3hC8Z9baVzdtiHxcfiGcFpQXy+qL/VHruxva3SFJipqQnZpQ/t9UXOhdAqi9V0nxuzYVSfPbcA+GUTd2uLCM5AYgIozl54oUXXpDq4hRMfPLJJxFvaMSIEWZCzUhJSpTUpOBJdpIcktkUV0jKlF4vU/JyN8vGjRulzf+eL7Ekzdm8bt22fUm13CDVS/Ek+Y5LEp9kh225sCW/c0lwlLfUHmQlOiSjqjBKZ3AF9kRT0uTvm9qgXBKH2ZLSOSSbc0pa55BYzL8pdLIv5ct0OcYuGf12ztZ1G0QSKu/f2qJ1DrtiP36FZfYkhakJ9te9umiNtUzixsQdhpndO6nySFDJ/kQRS2Iwa4JBS8I/s45kh2Rz9jxo4ndIrOjLcLhunPbHoW+h5bW7JFW0fV6bzWy2v1+SHRKzuSTkdFGwMT/iJKMNHJKQrl+XZy2z1SFxamGOvUyz9g2sZZIdkvUVOOyP1JakdfDE2WefLdWFoWERlmYt28ii3M2mE3bXngc6LTPv1x/NY5PmrTjqQB2htRyDUgdUeo7O1wCCYjSnWodgAmHp2quP/Dlvtnw6/mU54oQzpGGTZiHLb1y/WiZOeN18SOy5r1vwAcSrBF+CNEtrIWVFf/86zGh3AIBo+P33300Su7Vr15pO2ccee6x5vqysTEpKSiQlJaVmg4lly5bJihUrpKAgeHXowQcfHOlmEGMOP/4M+eiN/8jWLTly++WnyVV3PiaZ2W2rLLt00Vx57oFrJT8vVxKTkmTQ4NOrfX+BWJKRVE+u7HKT5C5YUtO7AgCxJcGt+WFE668jli5dKueee658/fXXlZo/BYKJZ599Vi699FL57LPPZODAgdUfTIwbN05uvvlmWbgw9Mg8+mubRj2Iv2ZOp/3rGnllzD2yYsmfcu05/5Td9uwlnffsIfUbNjVlNm9cKwt+m2GGg/WL39RKnHDOFdK8dfTGOgYAAKjrNmzYIP369TO54vbaay/zw/4TTzxRqczQoUPlsssukw8++KD6g4m33npLTj31VPH7/dKoUSMzbm1WVlbYO4HaafDpF0lRYYG89Z/R4i8rk3mzfzTTDvx+8fkS5JhTLyW/BAAACI4+E5647777TCChed703/rj/vbBRMOGDc1oq999911E2wormBg1apR5HD16tKkeSUx0GKECcWnIecOlZ9+B8t6rT8vM7yeapkwVpdfLkq49D5ZDjztH2nbco8b2EwAAoK54//33zY/99957b8g+ebvssotMnjy5+oOJefPmyQEHHCCXX355RBtHfOi4255y1f89KmtX58q61ctkS862JFqZ2Q2kSfM2dCwF6jAdGnZKceVESUeXtpbURPsQnQDqIGomPPHXX3/J0UcfLQkJoTuJaOdrbRJV7cFEgwYNIsqGjepXPzNFMkPkKCgssY8DvtYyRn9mg3TJbLBryDIFLrkfUu2X5XJLXgeV4DA2d4pDTgGXscJ9iaG3Va+xPWeDv4l93PzcZTnWMinZ9pu0oiYOeRuKHPo6WT6knDjkbPAX269PX5J9DHWfQ74PvyX/gZFozwVQusE+Vv2G4o0R55AoLrOfJ22SarO11D6Gf71Ee06BzSWVr9F8f75ML55R6blDc46S5MTMkOtJbBE6IabfIT9Jmct71yF3i88ln4pLGYfPP5f8GZ7kU2loT3aYtVuTasn94JqLJzkjOeIyS35fbV1HvWahr03VvnV9a5mlSZVr6quS7vC68x3ydLRtHllTc18xg3vGm7S0NMnNtV+DS5Yskfr17ddzKGFdPYcccojMmjUrog0DQF1V4i+RP/IXyrrSFeXPtUloLYk+mowCqOMYzckTe+yxh8ycOVPy8vKkXr2qfwhat26d/Pzzz7L//vtXfzBx6623mg1rO6wbbrghoh1A7HvjudHmMa8g9K9qSZZf51XJ/35hPub0YR7tHVD7FJYVyKtrXqz03Fmpp0u6hM4ODwCAi5NOOkmuvfZaGTFihDz55JNVNnfS+Vu3bpWTTz5Zqj2Y0GhHx6Q95ZRTTAePI488Utq1axe0XdZZZ50V0U6iZr3+7MOm30Pkle9/I5gA6oZESZRdEzpXfs5HkwoANdtnolevXmYAoWHDhpkp3gwbNkxeeuklee6552TGjBlywgknmOf/+OMPeeihh0yKhx9//FH23ntvOeeccyLaVtif6JpJTztsaFsr3ZlQCCZqP5c2186i+SEBIKak+FKkf3LlxKVpCfb2+gAQTdOmTZPs7NB9s2p7n4n//ve/MmTIEHPPHuieoMPA6qT3dRpQvffee5Kc7NDny+tg4j//+Y9cffXV5t/dunWTXXfdVTIz7R2W4EajxTFjxph2bEVFRdK5c2c5/fTT5aqrror4hIfj7iffMI+bthSFLJfs0OG5qJAEhoBPfNIgsYGUlJZUeg4A6jxGc/JMy5YtTeCgQcXHH38sf/75p5SVlUnbtm1Nq6LBgwd7MuJmWMHEww8/LElJSfLOO+/IP//5z4h3An+78sorTf4OPb4DBgwwQdpXX30l119/vXz44YemeVl6evW2q96rR2+n0ZxSHUalcBnNCYh3GYn15Oq2N8iyVQtrelcAAHHu8MMPN1O0hDWuo7a30rTcBBLe0qomDSQ0gJg6daqJJMePHy8LFiwoz1B4yy23eLxVAACAGOGrMKJTNCYqgWMjmND0202bNvV+b+q4QGZxHSGrR48e5c83adKkPAX6448/Lps3b66xfQQAAEDtUVpaKmvWrDH9nINN1d7MSdtZffnll6bdlS2zHtwsX77cdAZSp5122g7z+/bta9q4LV26VCZMmCCnnnrqTh3atZvyJa8kshFUMi3JgFyS7xQ6JN8pyLUnmmrdubG1zBaHJlUlJfYEZRlN7cetcHPoJmD567fa98UhCZfPpV/Kn6EToRkOyfpkoz3xlbR06CtlO8YZ9uPrczhPTj+NJDsUcrhG/QXe9P0p85dFnLTOpUyZ2I9fgsMBLPHb31NJDrky/KX2fZbk0OvxZTokKXS4zn1pDp+LLtefQ6I4p8R2Ltuy7bNDUsWyJfYfpXKL7fuS3c6e7Cp3hT1xlov0RvYmvqWW929ag3RPEtKt2pTvSQLWnK3FnjQPbuHwujZvDd7vscghcW21oc+EZ/S+UtM5TJo0SQoLg99bab+JkpLwv9fCuru88847zQ3t8OHDzfBSmoobkQn0sm/UqJF07NixyjI9e/Y0wYSW3dlgAgBqQrG/WH4q+aXSc0eWtZaUBL43ACBafvjhB9P3tqCgoLxVUbRGrwormHj22WdN7YQmwdDe4ZoRO1ieCY12aOdvt2jRIvOoxzEYrZmoWBYAYl2JlMj00pmVnhvkP0JShGACQBWomfDEbbfdZgKJ8847T+6++25p3ry5REtYwcTtt9++LYmZ3y9//fWXvPhi5UyuKjCfYMJNbu62auBgKc9VYPjdnJycoGW0GqtiVVaosgBqRom/RJYW/CWry1aWP9fc10wSHZoIAQBgowP57L777qYCwIvhXz0PJrT9VbR3DOG555575I477uDwATGssKxA/rP62UrPnZFyqqRL9Q77DAAxJzDqUjTXXweUlJSY7NbVcb8eds0EvJWVlWUe8/LygpbZsmWLeQzV5u3GG2+UESNGVKqZCDSPAoDqliCJsktC5X5gib7IBoMAAIS2xx57yLp166Q68IkeIzp06GAetYN1MIF5gbJVSU1NNRMAxIJUX4ocnjKo0nNpCWk1tj8AYpv+kh7NX9PrSsuaiy66yAyUpLnhOnXqFNVt1ZHKnti3zz77mMf169cH7WA9ffp081gxBwWA2sgnGQn1JK3Cfz4yKQEAPAwmdOTPQw891IzAqrkmarRmYuzYsSaq2X///SPqCKLRUVU5FCDSpk0b6dWrlxkTWI/3TTfdVOmwaPZrrZnQWoejjjqKQwbUYvUS68mN7W6RJSvn1/SuAEBsYTQnT+yyyy7mcfHixXLMMcdIUlKStGzZMujIq3qPHtVg4owzzpBzzjknomDiqaeekpdffplgIoSRI0fK8ccfL/fee68ZejdQA6G1FZdeeqn592WXXSb169sT6myvuMwvxaX+oPObZNmbRuUX2ZP0eOGgfdtYy3w7Y5m1TNGW4Al6AjKaBh89KyBv9ba+KpFIrmcfBrM4P3h/mb93xp68SBo4NCHJsx8baeswHvV6h2vCWqPsUOXsD37tltvq0a8uDokBE7Lt75eEDPs5T/CF3pbL6E7F4k0CveQE+9eBy/645I/wpdiTt/ktiboSGjpc5/klniQg9HVsYN/WJnuyTSlySEiX4kFixfr2Y+Nz+Mx3aQ2Ss8ye/K5eM3tyy63rtkackE4lWRL6uazjjz/WW8s0brmtn2Okch2StPoSvWlEkh/itecXx1DSOnhCg4gAHV21uLg4aKbrSJt+0Wcihhx33HGmfdujjz4qvXv3loEDB5qhYjXb+KZNm6RPnz4mYSAAAEA8omLCG9WZk8w5mPj0009NJr1wzZ07N+xl65LRo0eboGHMmDEyZcoUE0lqE7MbbrhBrrrqKrKNAwAAIKT27dtLzAUTq1atMlMk6koP+kgNHTrUTABQ2xX7i+WXkl8rPTegrJVTcygAdbVmIpqjOUVt1XWWUzDx9ddfR39PAABxR/t0fFf8faXnDio7jGACAKqB5ht79dVXTWuXtWvXmib01113nZk3f/5807fi4IMPlrS0tOgGE/369Qt7AwCAykr9pbKyYLmsKVtb/lxjX2NJtHTIBoC4RwZsz3z22Wdm4KONGzeaTtha49O6devy+fPmzTP9dV9//fWIWsTwzQUA1aygNF+eXPSIvFv0fvlUJA6jAQEA4GDOnDlmhNDNmzfLJZdcIm+++aYJKCo6/PDDJSMjQ95//32JBKM5AQCiJlESpENC+50eYhZA3UQGbG+MGjVKCgoKZNy4cXLCCSeY504++eRKZVJSUmTvvfeWn3/+OaJtEUzUEXn5xVKWEHzc9sxU+6VQXFIW8XjZzRpnWMvMXLjOWiYxxX4z4i+z5yYoctjn5Az7mPj560OPkV5aZB/LPiXTPu57kUNeh4z29jHx8zfY1+PPKfCmJ9tWS24Mh6H3Jcuhs26pw3jt9RzyGyzP9eTa8qWF2Fbxju+3pslNpF5Cxg7NoazbcahgLiqz5xVxucHPSsra6TJZkiVnJJ9a6bnMjvZcMr5ky/4k2K89X+N0axlxyDNhvYaVy7YKvckJYnvfJSTbr4mkdPt7oWiV/b2Q1MSeq6fY4fg12bWxtUyuQ86fgk2hP7fqt7bnzyl0yMOzxeE1lTqc7wyHfB/pDt/P6xy+y1C3fP3119K9e/fyQCJU0uTff/89om0RTABADUjW0YwcghIAqFNINOEJ7Wzdt29fa7mSkhLJy3NImhsCwQQAVLPM5Cy5Y+8HpWDhCo49AMBz9evXl+XLl1vL/fnnn9KsWbOItkUHbAAAAMRUxUQ0p7qgR48eMmPGDFmyZEnQMrNnzzb9Jfbff/+ItkUwAQAAAMSRCy64wHTAPvXUU6tMOr1u3TpTRkd40sdI0MwJAAAAsYE+E5446aSTZMiQIWY0p06dOkmfPn3M85MnT5Zjjz1WJk6cKFu2bJHTTz/dDBFb7TUTAwYMkMMOO8xUn4Ry3333mbIAgLqp2F8s04tmVJqKS+2j5QAAIjN27Fi58cYbzb+/+OIL87hgwQL56KOPpKioSK6++mp58cUXI9xKmDUTGs3oOMD9+/c3STCOOuqoKsvNnTtXJk2aFOk+AgBqqSJ/sXxa8Hml53qWHi3JiQ7D/QKoexJ84nMY+jmS9dcViYmJcvfdd8s111xjhorVztZlZWXStm1bGThwYMQdryNu5tS+fXtZtmyZScM9ZswYufDCCz3ZIQCId5o/Yl3BGiksXVv+XJOExpLgoxsbAMBbDRs2tOabqJFgQmslhg4datpjXXzxxfLXX3/JXXfd5e3eodrs2aGhtczy9aHHId6Ua2+6sHjpJmuZevXTPEmC5JJsrrTInhSsQcusiNfjkhyvJN8hMVam/dfcMktyQeV32Vaaw8dDoUOiJFvysUSHX4kK7edJyhyy3zm8bJfEdi6S2jcKOq+gMEdGTxhV6bmR/7hL0pMyKz3X4i97HopNCfb3VEGZ/TzVS7QnlGyUZk8sltyuSaW/y0pyRWZXLuPLTBFfauhr2WdJTGmb7/p+kVKHXB8uw79scWi61cx+jGWzw3uqSej1lG22J5wsckmg53D8XD5DS3IcXpNDMjmXZKW2MsUOr9vlNTV2SNa3xiUpapI3PyCUlNo//9JDHBt/UYxlpa+GyoNevXqZX+6HDRtmJtRQB+wjjjjCNGM6+uij5Z577pGlS5fK888/L0lJ9OsGgEjklWyR/LK/M6un+VKDZqnO91fOaJ4iKUHLFvgLpOLtc4okhyxbVqF0tr9EknxVf77nl+VLmZRJUsm2jL6pCWmSnJAsiZIoHet13uls2wAQTdOmTZPsbHsQGw+mTJkiCxcurHJez549pUuXLhGtP8mLcWx/+OEHOfLII+XVV1+VFStWyLvvviuZmZV/YQMAuPv33P+TYv/fv3afV+9saZXYssqyrxW8KQXy96/Rx6UcI20SW1dZ9r2iD2WLbCn/+7CkQdIusW2VZccVvCMb/BvL/x6aeJLsmVL1l87Lua/JitIVIv+rKDmx7emyb+P9JT0pQy7cdXilsokp9l91AdRN2idXp2iuP17tu+++Mn/+fNM/QoOEgGeffVZefvnlKpfp1q2bzJo1K6LtelKFoP0nNOoZPHiwfPnllyZ994QJE7xYNQAAAIAQ9P5bg4Lzzz+/UiARoPkktNN1Rdr3+ZdffpGvvvoqotFXPWuP1KBBA/n888/lrLPOkrfeekt69+5teosDACrLTM2W+49/TYoX/t0BGwBAmolwvffee6bW5aqrrqpyvs7T+/SKFi9ebHJQjB8/PjaCCZWSkiJvvPGGCSIefPBBWb58uZerBwAAALCdH3/80bQU2pn+Dx06dJCuXbuaZSMRVjDRr18/2WOPPYLO//e//21e0BVXXBHJvgFAnXXtHrdK/tI1lTpgB3N62sk7dMAORvtTbN8BO5ghaSdU6oDdIrlF0LJnZZ2+rQN2m0blHbABANXjjz/+kAMPPLDKedrEKZhdd93V9LGo9mDCZaOXXXaZmQAAO69eUqYkJPzdUTqUdF+683rTfGlhlw02kpPZh4Rt+5CcZB9KGQCC0g7S0ewkHacdsHNycqR+/fpVzhsxYoRJ5VCV9PR0yc3NjWjbjOEKAAAA1GKZmZmyefPmoCM26VSVTZs2SUaGQw6cEAgm6ogenZtIZlbw8ZQn/rLSuo701NCXy8ZNlce6r0pLhwRwGx2SPyU4JPpp0sw+PPHSufYOsBuX51jLpDdKjziRnFMivgb2X5VLXZJR2RLJqU32xFcJzexDfJatCZ3sUApc9tejzNAO58GljC/VfvwcUqFJ0i6hk8BlpNg/otM22hNO+ovs15YvzZ6gLLGZfUz2hEb2LyWnhHOWZIZ+l/PkkkjO4Vw6/ZIZohlBuXyHa72hQy2TLemkw3UjCQmeJIkrLbAneKvXxn7dbHb4nPUl2M9DtsN3jE3+Bvt32SaHhHQZDucyKdGbz7Zch/3p0Dn4582WJIdrs5owNGx4WrZsKT/99NNOL6fL6LKR8OgbGgAAAEBN0P4SOvDRN99847yMltXhYfv06RPRtgkmAAAAEBsSqmGKQ2eccYbpaH3ppZea/hM22k9Cy2pN0GmnnRbRtuP0kAIAAAB1Q79+/eTQQw+V33//3SSt+/jjj4OW1cTSvXr1kjlz5phEdoccckhE26bPBAAAAGICfSbCN3bsWNNkaf78+XLsscdKw4YNpUePHtK0aVMzf+3atTJz5kzZuHGjqcXo3LmzWSZSBBMAAABALde4cWOZOnWqSc3w+uuvy4YNG+SLL74wAVrFfBMJCQlyyimnyJgxY6RBgwYRb5dgAgAAALGBPBMR0VwTr7zyitxxxx3y0UcfyYwZM2TdunVmXpMmTUxNxT//+U/p1KmTeIVgAgAAAIgju+yyiwwfPrxatkUwAQAAgJhAxUTtQzBRR3z741JJz8iMKKna1szQSa3y1mwRL7gkbytxSHT21+pVnuSZKnFIplT416aQ8xOb25O7+VfZj1+xLVmVckjo55QoziFhVdnSqrNtVpIW+mPGvy7fk9dUttFhPYWlEe+v2dbaPIfEbC6Jw3wRX6AJ2fbEWP6iZE/2119Q7M15cChjS37n3+KQiM/h/eJzuLZ86fbj5y+2X1s+l6SJa7dGnnQyw5uv9tJShw9Iy/eCyttsT4Dpa2xPduh3OJ+bLOfB5TPfJUdh/vqtniRXLXD4nE1yuP58Dsnvlq0Lvs9b8xyuOyAIggkAAADEBEZzqn0IJuqILTkbpaS4KOj8slL7L2YppaF/gdqaa/+1VjaVePLre4nDL8wlW4O/3p35lcrv8ouN5aesxAz7vpTmOdTsOPwyLA6/UDn9Ql/ssJ58+y+OUmapmShwWEeS/afCskKH9RQ5vG6fQ81Esf2a8Ll8vCZEvh236jWH152Q6MlPtr4k+y/VLhIKHWrPrPuS7E3NhMO59DscY9/WQmsZcfgslmLLufI7nEsXZS4/43tzvn0phZ7UjCUnpFVLzURCqv0YJzh8Fie61EwU2q9jF76S4Ocqf6s3LQtQNxFM1BG3Xf7Pmt4FAACA0KKdpZp0zZ7jkAIAAAAIC8EEAAAAYqrPRDSnePTNN9+YzNc1gWACAAAAqMX69+8v9957b/nfAwYMkPvvv79atk2fiTrijsc+krT0epF1wK5n6YC9zt4BO7N5Vu3rgL3egw7YzezDHpauiLEO2MkO69nk0Ok51dIBe4NHHbA3edQB27K/ZlsO14Qv2YMO2Js86oDt8rpTPOqAne5RB+wG9iFvrftSz6MO2GkedcDODt052LkDdpLlXKVXYwdsy/eCK1+jdG86YGfHYQfsNG86YGdnhu6APeykfhITSDQRNn+FC3zixInSoUMHqQ4EE3VERkb9kHkm0h3G+M615FvYrWdr6zo2OdyEFRQ6jEHvMMJSapZDbgeHfAuJnRtZy5Quyw1dYLXDyDQN7NsR23ZUkf1mxO8STBQ4fKM6jBrjt4zg5S9MtW+nxKN9SbAfm7LVDqOSlTncQNljWWtugrI8jyqPSxzuoLbYj40vK92T1+2z3Qw75GRwCVp8Rd7kkJCtDtefw1vcV+KwP5kO74ey0PvjK7Nvx1/mcr4d9qWe/btDch1GsVpnLyJtm0h1SG3gEPQ58NnyyDgGEy5SHM5V7y7Ng87bkmvPp4TYlpWVJStXrqyRbRNMAAAAICZQMRGebt26yVdffSW33nqrdO7c2Ty3cOFCefnll52WP+uss8LcMsEEAAAAUKtdd911ctJJJ8ndd99d/tzkyZPN5IJgAgAAALUfVRNhOeaYY+THH3+U9957T/766y958cUXpVOnTtKnTx+JNpo5AQAAALVc9+7dzaQ0mOjbt6/85z//ifp2CSYAAAAQE7Tjukvn9UjWXxfcdtttss8++1TLtggmAAAAgDgLJqoLwQQAAABigtYbRDNJdd2ol/hbSUmJvP322/L111/L8uXLzXOtW7eWQw45xHTYTkqKPBQgmAAAAADizE8//WQChkWLFlVKaKeee+45ueWWW2TcuHGy9957R7Qdgok6ot+B7SUzKzvo/F8Xb7Cu44BDdw05f+GKzdZ1FNf3JhlQokOW4sIce6KkrA4NrGVyV9iT+SS1qx9yfpklOZkps8whaVBrewZx2WLPGuZzSCLllNjOIVGXWDIMu2Qg3v5DsEppDonQHHJnJTa1H2O/JaGaa/ZqW9vdBJdsyE7tfx0SvDlk2bUl2TMc9jmhgT3RmS/Zg2ReLtngXTJgpzt8VbpkVs50SJDncG2JLSN3isNrKnW4bpo4JKRzSPzpsp56HRt68plu+0XbJbmbS5kGDmVWL9vsSdK6DIdttW1iT9I6Z+mmoPO25jkkRK0ujObkiRUrVshhhx0m69atk+bNm8spp5xiRndSf/75p7zxxhvyxx9/yOGHH26CjpYtW4a9LYIJAAAAII7cd999JpC44IILZPTo0ZKenl5p/qhRo2T48OGmhuL++++Xhx9+OOxtOfxsAwAAAESfz+eL+lQXfPLJJ9KuXTt58skndwgkVFpamjzxxBOmzMcffxzRtggmAAAAgDiydOlSOfDAAyUxMXhTOu18fcABB5iykaCZEwAAAGJoOKcor78OSE1NlZwce1/M3NxcUzYS1EwAAAAAcaRLly5mONhQtQ5LliwxZfbcc8+ItkUwAQAAgJjKgB3NqS4466yzJD8/XwYNGiQTJkzYYf5HH30khx56qBQUFJiykaCZEwAAABBHLrzwQhk/frx8+eWXcswxx0ijRo2kY8eOZp7mndiwYYMZdl2DDS0bCWomAAAAEFNdJqI51QXa8VpHabruuuukXr16sn79epk+fbqZ9N/63PXXX29qKBISIgsHqJmoI9ZtLpD80uAJk7p2aBRRwhvVxCGxTn6RPenV3l2aWcv8PHettUxKpj1RV4JDwqp6zTKtZZIzQiej2jR/vX0du9iTNrnkbitZYN+WZNvPla/M70mCPMkrDr2d5vZkS/619gRwfof99Rfke5MEziF5W0JWWuRJ1TK9SfLoL3FINudw/BLq25OP+QtDn29nlmPjc0j25cuyfwb4HT6TpNieSM5XL9mbxHYOn6Pisi2b+pF1uAxIcvjcchmJs8ghkWZW6+CJV12TySUn2ndm7aYCa5n8Qnuyvjbt7UlR62fYr9ECh2u0aYP0iNbjK+Z2MJYsXLhQHnjgAfnxxx/l119/ldatW8vixYt3ej0pKSly7733yh133GGCiOXLl5vndX09e/aMuON1AFcPAAAAYigBdvTqD2pDmonffvvN1Bjst99+pinSxo0bI1qfBg19+vSRaKGZEwAAABAjjjnmGFm2bJm88847sv/++0uso2YCAAAAMVQzEd31x7qECPswVLfatbcAAABANZs3b5489thjcs4550jXrl1N9mhtjnXXXXc5LT9u3Djp37+/NGzY0HR+7t69u9x///1SXOxRP7MaRM0EAAAAYkKs1kw8+eSTMnr06LCWvfLKK82yGoAMGDBAMjMz5auvvjKjKX344Yfy2WefSXq6vRN9rKJmAgAAAAhhr732kmuuuUZee+01mTNnjpx55plOx+u9994zgYQGEFOnTpX//ve/Jv/DggULTA3Hd999J7fcckutPvbUTAAAACAm+P73XzTXH44LLrggrH4No0aNMo833HCD9OjRo/z5Jk2ayBNPPCEHHXSQPP744yagqF+/vtRG1EwAAAAAHlu+fLlMmzbN/Pu0007bYX7fvn2lbdu2UlhYKBMmTPB020uWLJGlS5dKdaBmoo5oUj9NMrOCt8dbuGKzdR3/aBs6Ac/aTfaEYEm2JF2aTKWxPYnZgqwca5mCfHunpiKHpGtlJfaEVTZZHezJi1zkLg6dONBobE8sJi6vKc8hIV1b+68ovpW5oQs4JJHyWZICur4mf7r9I8+XbE+GJqkOZQpKIl6Pf4t9Fb5kh9+E7Dn/RBySwPkdEnUl1Hdo9+uQLNJ2XbgkrUto4vBeKIv8/a38pfaMdC4JGqXQIYme7XU5JOx0SjiZbV9PosN5SG9kvybS0u3v8bzN9mRyyQ0iT/TY1GEdqUkOnwEOXBLSuXD5Dj+0R5ug83JyHK7N6hLlPhPVmQJ71qxZ5rFRo0bSsWPHKsto8ji96deyp556qmfb7tChgxxwwAEyefJkiTaCCQAAANQpOTk5OyR28yojdMCiRYvMY7t27SQYrZmoWFZt3bq1vKbizz//NH+//fbb5u9evXpJ+/btxSY7OztoAOM1mjkhLFMnfxP2kXvm3zdz1AEAQNDRnKI5BW7itY9CYLrnnns8Pxu5udtq5nUo2GC0Y/b2wc2aNWtkyJAhZvr8889l7dq15X9//fXXTtvu0qVLtTVzIphAWC6/4Az57Zefdnq5J++9UT5/byxHHQAA1Bi90d68eXP5dOONN8bM2ejQoYP4/f4qJ81z4eLCCy80TZwCfTaiiWACYcnbkisXnzVEFv2xwHmZ+2+9Wr784A2OOAAAqJImgov2FGgGVHHyuomTysrKMo95eXkSzJYt2zrH6T546dxzz5VLL71UDjvsMDOilCbd047e0UAwgbC067CLbFi/Ts4/9XhZuWKZtfw9N10hn7y3LZDoM+gYjjoAAIhrHTp0MI+hmhsF5gXKeiUxMVHGjBljmk/psLPa7CkjI8M8v/2kyfQiQTCBsDz3+rvSvEUrWb1yuVxw6vGyft3aKstpldxdN1wm//1gnPn3wYcfL8Nve5ijDgAAduCrhqm67LPPPuZx/fr1lTpYVzR9+nTzWDEHhReCNZOqaiqLcFQ7ggmEpXWbdvLs2HekQcNG8teiP+SiM040TZ8q0ovzzuuHyRcfv2P+PnzwULn81gedE70AAADUVm3atDGjL6mxY3fsL6rZr7VmQptYHXXUUZ5uW+/BdmaKBEPDwujRuclOH4l9uu8lr7z1rpxy3NEy7/fZMuJfp8tND70sKampUlZaKo/ecaX88PW2oc36Hz1Ezrl6VHlbxVD+WGHPIdE02z4O+JZUh8u7gcOY+A7WrdkSca4Kf5l9nPpUh3Hzy4rt45aXOIxl73eJ+VYGbwdazrbPDuPzu5TxOZRxCmMdzpXPIc+E32WgdFu+hTSHY+Nw3fgcxvl3ydvgz7PnbvHVs+cL8KXZ35t+lzwdFmUb7LlvErJTPcm34HPJ3VLkTU4Lsb3HHT4DGnRrbi1TsKnAkzwTLjkkXLRsua39eSg5W0Nfo22b2PMpbN5qz8GxxSHnShuHz2uXvEq216Q6trAfmx/nrgk6b/sfA2tSxX4N0Vp/dRo5cqQcf/zxcu+998qRRx5ZXgOhtRXap0FddtlltTb7teInYkRk7x77yvOvviHJKSky79cZ8tDNl0hRYYE8fOtl5YHEgGNOkYtvuLfa38AAAABemDlzpvTu3bt8+vjjj83zTz/9dKXnV65cWWm54447ToYPH246Wut8DShOOukk6dy5s/z666/Sp08fufPOO2v1SaJmAhHrc3B/GfPsi/Kvc86Qn6Z+I5cNOVhyNm0w8wYNPk0uuKZ2v0kAAED1qJgLIlrrV9r8SDsfDxs2zEw22pF56tSpOzy/bNkyMwVUNWLS6NGjTdCgHaKnTJkixcXF0qlTJ7nhhhvkqquukpQUh6z1Yfrjjz9MwKPb1XwVgwcPlvvvv9/M09fz888/y8knnxxRzQjBBDxxxNHHyEXXj5Kn7r1BcjauN88ddsKZct5Vt3OEAQBATNH8CzszHGv//v1NZ+VwDR061EzV6aWXXpKLL764PMDRFiLr1q0rn6+ZtS+55BITzLjmr6gKwQRCWr7MPXviXj0OkCNPOls+Gfei7N//SDn21Atl3arllcokJm5rWde0RWuOPAAAqCTaIy7VlQbXP/zwg1xwwQVmOFhtRtWvXz/Zf//9K5XR57RG4sMPPySYQPQcsHcX57Ll8brPJ1MnfWqmKt/EPp+M++4Pz/YRAAAAf9OmTFqTon07+vbtK1XR0TX33ntv+f333yUS1EwgpEiq9KpcXx36VQAAANTt0ZxqyuTJk2W//fYLGkgEtGjRwnQujwTBBEJ66PGnnI/QAochXRPqyJsYAACgpmzatEnatWtnLZefny9FRfbhkEMhmEBIQ049w/kITf59tf2C+1+fCQAAgJoazSneNW7cWP766y9ruYULF5raiUgQTNQRWenJkpWRHNWkOC0cEsAttiR3c03009RhWwtXbLaWcXnd2SGOW0CSJSlTqkNip43L7TU7DVvbR57IWWtPJJfe2P7WL3FIdFboUKY0tyjiBFuyyV5EUuyBqq+xfX/9qx0S8aU7fHQ6XFuSFPpbLcFlf/NLPEkk53dIwuWSrM8lIZ0vMyXiZHz+UnsCuASHJGfikhzP4f0rDu8Fp/U4SGwYOmlnWYm9eWq+Q0K/FIfzZPvsc1WQ7/B+cWD7vN5vj2bWdSxaZU/glpsf2S+5AY0dErC6lHHZ51Dfm+mJ3hx/xA7NaaEdq3/77TfZc889gzaF0vlnnOH+w3FV+JkYAAAAMdVnIppTXTBs2DApLS2VE088UX766acd5s+ZM0fOO+88czwCmbjDRTCBsGgbu9deedlMmgTFZtOGdfLp+2/Jd5+9KyUl/AICAABqjiat69Kli0kkF48GDhwoI0aMkPnz58u+++4ru+22mwkc/vvf/0q3bt2ka9eusmDBArn22mtNLUYk4jqYWLNmjbz88sty2mmnya677ippaWlmvN099tjDpDZfvHhxyOW1Q8p9990n3bt3l3r16knDhg1N0pK3337buu1x48aZsrqMLqvr0GG6NOthKDNmzJAhQ4ZI8+bNzf527NhRLr/8cvNaYsn4cW/JheedJ7fdcot5jTaZ2Q3kuUfvk+fuv0Gmf/PfatlHAABQO/NMRHMKJK3TIVFdsl/XVg888IDJfq19IrRvhI7QuXLlSpk9e7Y0atRIHnvsMbn33nsj3k5cBxMakZ199tny5ptvmiDi2GOPlUMOOUQ2bNhgDuBee+0ln3/+eZXLalZALaupzpcsWSJHHHGEGWJL25fpzf4111wTdLtXXnmlyXIYGJZLl9V1XH/99TJgwADzq35VNEjR6FAf27dvb1Ke6xjAjz/+uIki9UKIFR9/9JF5PGnIUElKsreR1jIDjxysY83KzMlfVMMeAgAA1G0XXnihLFu2TKZPny5vvfWWvPHGG+b+dMWKFZ4FUnHdAVujrjvuuEPOP/98ad3674zLW7ZsMQdXD+gpp5xibtK3/3V95MiRMmXKFFMN9NVXX0mTJk3Kaw60xuHBBx80j//85z8rLffee+/J6NGjJTMzUyZNmiQ9evQwz2v6cg0kvvvuO7nllltMtFiRnlQNfEpKSkwUedFFF5nntb2bpjh/9dVXTQ3L1KlTY6K930+zZpn96HvwQc7LdOvZW9586SlZPH92VPcNAADUTozm5D29X9P70cA9qdfiumbi0UcflVtvvbVSIKH0Rv/555+XrKwsU0uh2QEr2rhxozz55JPm3/oYCCSUtjvTGgZ1991377DNUaNGmUet0ah40nQdTzzxhPm31jRs3lx5pKFHHnnE1IYMGjSoPJBQiYmJZh803blWyX322WcSC1atXGke27Rp67xM0+YtzePG9bHVZAsAACCe+f1+88O29nMtK7OPhrcz4jqYCEWbPe2+++7m30uXLq00b8KECaa/hCb76NOnzw7Lag2B+uGHH0yNQsDy5cvNDX/FMhVpFsK2bdtKYWGh2UZF7777btDlNPjRJlrqnXfekVigQY7S1+KqJNBfxOOs2gAAID74JMqjOZX3mqgbPv/8c9PcXn9A1/642n9C/63PaWdsL9TZYEI7Qgc6YLdsue0X84BZs2aZx549e1a57C677GKaUKmKw20FltN52nG6KoF1Bsqq3Nzc8v4QwbZZ1XI1qVnz5ubx99/cmyz9OX+Oecyqv+3YAQAAIDp0pCYNGrRVi7Z+0doJnbTvrj531FFHydVXXx3xduK6z0Qo2sxJq3vS09PlyCOPrDRv0aJF5jFUGvI2bdqYJlKBsq7Lac1ExbKq4qhSwZatarmd0Sg7TbIdEt+E8sui9eX/3r1rD1m8aJGMGfO07DvgeKdkQFd99Ib5VaDbPj2lQ7PMoOWy0u2Jkn5dvMFapk+XbQFPKMvX2xOUzV600Vrm8J5tQs7/7/RlniSkS06yx/+NHRJ1rV262ZOEVVtXOQzz60Ufnzb2YyMu1bYr7efb17yefT159tft280eNPtXWfbH4dAlNPEosV2yQ0I1h2vCqU+XS/K7pqGTV/ockls6JUSsn2ov0yDNk20lO+xzgsN5SM0Ovc/567d68nlTakkcqNIcEvEVl9jfm2UOZZo6fIfZ9ufzmfbP4kN7hP48d00S55Lw9Me53jT7dUnkGmp/fCXeJB/0QsURl6K1/rrg1VdfNf179T5X80hov9zAD9163/nSSy+Z5vfazH6fffaJKHFdnayZ+PXXX020prQztFb7VKQ1BUqHdA1Gmx6pnJwcz5YLtWxVy1VFmx1pmYpTNBx+zInmcc7sn+TBO28ykW4wOu/qq66UWTNmmL8HHb0t+AAAAID3dNRSbZL+6aefyr///W8zgqneY+qkGbE1XYHO0x+AtC9vXNZMXHfddfLBBx/s9HLPPfec6ZsQjA6Pdcwxx5gRnbQfgnaUjif33HOPGcEq2g7sN1B6HtBXpn//nbz96vMy+6fpcs3VV8qBfQ8qbzamYxlP/vYbeeLxMTJr5oxttRL79pa+A46I+v4BAIDah9GcvKG5JPR++KCDgo+6GZgf6O8bd8GEdmyeN2/eTi+nQUIwq1atMhkB//rrLzn88MPNeLtVVclrxxSVl5dn3U52drZnywWW1ZGbXJaryo033mjyawRozUSgiZTX7h79nFx6xnHyx/y5Mnf2z3LBueeGrJ3Yq2tXufOR56KyLwAAANhGEx+3atVKbLRMSoq9CWutbOakbb0CHUV2ZtKOJlXRDNKa50HTiuvwq5oPIjW16nanHTp0MI+aaC5UDUfFshX/vf3oUBUF5lVcThPUBQTbZlXLVUVfkwYcFadoqd+goTz/9qdyyjkXSWpaWtBzoiNnDb/yKpk0eYpk17dnywYAAHVTVEdy+t+kevXqJV26dJExY8ZIPNp3333ll19+sZbTMsEG/6n1NRNe0jF1NZCYM2eOqZnQ5lMasQUTyA+h2QKr8ueff5rO10o7rQQE/r1+/XrTUbqqEZ0C66yYg0Jv+Dt37mxGdNL5mijPZblYkJaWLleOvFMuuPxaWfvnT/LzrJ9k/fp1Zl7jxk1k7x77SL/+h1SobbF3WgMAAIgmbdoTzR9ca9pNN91k7nm1b4R2HaiK9qXQe2PtXxGJuA8mApmnf/vtN3NQP/zwQ9OzPRQdKkurfLSWQFOOb59rYuzYseaxd+/elaqQdIQnjXT1AtUyeiIr0uzXWsOgtQe6jYqOP/54c1J1uXO3ay6kTZx0v9UJJ5wgsSgzK1sOPO54GXwcnasBAEB46DMRnm+++abS31oDc9lll5nm7+PGjZMzzzyz/Edu/cFbWwDNmDFDhg8fLgkJkTVUiutgQmsPNIDQTijatElrJGyBhGrYsKFccsklMnr0aDOc1ldffSWNGzc282bOnCn33Xef+ff2wYIaOXKkCQzuvfdeM+RsoCZBayt0XUpP7vb9Iq688kpT1fbFF1/Is88+KxdeeKF5vrS01Cy3adMmE6gcdthhHhwZAAAAxIv+/ftX2Q9Ym5tr0KD3r9s/rx599FFTM1FSYh9CPBifP9SYnrWc/oqvmaX14A4ZMiRoIHHccceZqSJN7qEByPfff2+CC63d0M7RX375pUl4p52cdfzeqlxxxRXm5CQnJ5tgRofh0uU0INBaDs1GWNW+aOR46qmnmgBi//33N/0jtJZDm1Xp8LVas6HNoXaGdsDWwGXO4pWSFeXqvLVrVsu8Ob/Lpo3b8jI0aNhQdv9HF2na7O+hd1s3tI+zPme5PQfC0jXBO9oHHNytcjLCcMcKd2HbH5ex2F3M/ePvXB/BJDpsKznV/jtC7mr7MS4ttH/4ZLYKfd1tnLfWuo4Eh/0t21hgLSOJDiOMbymyl9nskPm91OGjNdMytnuRQ54El7wOxR6tx+Hrwp9jP35OOSJs23LJPbLZ4Zqob89dkGTJ6+Cal8WXYD/GCQ65ZGyS0u05AzIdciAkJdr3JdnhPZXvcB27bKuNw3Vjy1O0dlO+dR1pDnlQXPIhueSZcOHyvbl849aI1hO4V9i8eXONNf0J7MO4ib9LRqY9X1K4tm7JlSH9u9Toa63OYMLV119/HfaycV8zoTRe0pGbgtGb9u2DCe00PHHiRHnooYfktddekwkTJpimTwcccICpWdDgJBit0dCgQWsapkyZYoKPTp06mWFor7rqqqC95nWdml171KhR8u2335ps1zrM6rBhw6rMhxEL9Ni+9tJ/5IVnn5IF8+ZWWWbX3feQcy+8RE4/O/hoTwAAAAiP3rPWlLgOJiI9sHrTrwFAOLkohg4daqZwet+PHz9eaoNNmzbKeacNlek//mD+DlbJpUHGyGuukHfeel3++8nH0qBBg2reUwAAUBvQZ6L2ietgAtGjgcP5p58s06Z+b/5u2KixHHPcCbLPvj3LmzVpsydNVvfRe+Nlw/r1JugYPHiwTJo0iVMDAAAQBwgmEJZ3335Tfvxhimmfd9xJQ2XUvx+RzArJ9wJOOuV0GXnr/8lN110l49983fT7eP31103fEAAAgEp8bl24whbNdceggoICk15Ak0Hrv4M566yzwt4GwQTC8t7b2/qg9O7TVx596vmQZetlZsojTzwry5ctkx8mf2uGIyOYAAAAiB5NOaD9cLVzuw3BBKrd7F9+MrUS51xwsfMy5154sQkmtGM5AADA9hLEZ6Zoiea6Y8njjz8u119/vfm3JkPeddddJauKFiReoGYCYQkM/9qufXvnZQJlA6NsAQAAIDrBRFJSkhnU55hjjpFoinxAa9RJgZwVq1etcl5m9eptZeNpXGcAAOD9aE7RnJQmAu7SpYsZxj8eLV68WA4++OCoBxKKmgkYy9fnWY9Et47bsoCrvfbqKt9+M0nefes1GXrSthwdvywKnVDtpRdeNI+77vEPpwQ7kSakW59jT1jlksCowCHhUoOs0AmMlq2zv96S0jJPklE1yLIn2Nro8LpbdmjoyXpK8otDzs9qZx8quNThHBQ7JOvzOSTGKkpyuDbLHBLSOWxL8kIfG3E4306J+Jo28Cax3Rr754SvYdXJQSupb79GZWvoY1PPIWldnkMCuBSHhHR+h/dmWYm9TFbzTGuZgtzCiD8HXD4DXJLN5VjOgcrMtif9q59hT/C2zuF1FxTar9FuHbMiTnjatEG6J98dLmW80tjhPKAyTQoczz9uNmvWTJo2bVot26JmAmE5/sQTzfCwH7z3ntx1xx1Bc0wEPP/4g/L1fz8y/Sz+OfgEjjoAAKixmol4d+SRR8r3338vZWX2HzoiRTCBsJx3wQWy2+67myDinrvvkv167CNj//Ok/DxjqixZ/Kcs/etP82997vRj+stzj/3bLNd5193ltLPIhA0AABAtt912mxQVFcnw4cPNYzTRzAlhSU5Olvc/+liOPOxQWbxokfz+229mCkaDjtZt28sr4941HYIAAAC2py0YdIqWaK47lrRq1crk9jr22GNl9913l0MOOUTatWsnCQkJVR6TW265JextcVeHsLXv0EGmzfrJNHN66YX/yKZNm6osl5VdX44dcrqcf9nV0rrNtuzYAAAAiA79EXf06NEyd+5c09TpxRe39VvdPojQcgQTqFH16tWTe+6/X+646y4Z99FX8sf8uZKzaduwsdkNGkqn3faQPfbsLskpf3fA++WnWdJt731qcK8BAEAs0noDEmB7k7DuscceM61B/vnPf5o8E5mZ9kEgwkHNBDyRkpIiXffpZaZgfpn5o1z/zGj5duJX8tdaezZGAAAA7LznnntOMjIy5Ntvv5V99onuD7gEE4i6aVO+kf888bD8NO17jjYAAAiKPhPeWLp0qfTv3z/qgYQimIAzbVf3/nvvytdffinLli6VpORkad++gxkm9oADD9yh/Iypk+XJB++W336eWb68OviQgRx1AACAKGnRooVkZYXOu+IVggkYrRvXC3kkli1dIr17Hiqzf/11h3ljHntUTjjpJHnxlVclMTFR1q9fL5dcdKF8/OGHZn6gc88/jz1Wrr9xpOzbs2fEiZIWrcq1lsnOSPYkOVFuvn1Itf06h04Ms3j1Ius6unZo5EkSJJfkT2kOydBcklq5rKc0NfKPmZyV9vOdkGxPWlfmkpgt1b6epI72hH4JDgnTbGUKNtjPd5LDdV6yzp5szklDe2KshPreJM9KapwRcn6iQ5LC1AZpniRETG9k/5xw2R8XvoTIW4u7vHfXrN/qSZLHNIfX7fI561LGJeGc7bvBlmDU9bvD5bPY5TW5bMuFS5LWUN+tW3Jjp+lxtHNB1JHBnOT444+X119/XQoKCiQtLbpJDckzASsdn/jsU06UX3/5xQQGVU3vvP22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zj77bPPvTz/9VFavXl0t2wUA1AyCCQCIYw888ICppagu+++/v5lU//79CSYAIM7RzAkAAABAWAgmAKCGXX755aZvwUEHHSQlJSU7zL/pppvM/B49ekhBQYEn21y8eLFZp9ZalJWVyaOPPirdunWTjIwMadmypVx88cWyYcMGU7awsFDuvPNO2WOPPSQ9PV1atWolV1xxheTl5XmyLwCA2otgAgBq2IMPPig9e/aU7777Tm6++eZK87TfwT333CPZ2dny1ltvSVpamufbP+OMM+SGG26Q1q1by+GHH26Ci6efftp02taAQR+1udTuu+9u/r1161YTfAwZMsTzfQEA1C70mQCAGpaSkmICBa15uP/++6Vfv35y5JFHyrJly+TMM88Uv98vzz33nHTu3Nnzbf/111+SlJQkc+bMkfbt25vn1q9fLwcccIDMmjXLPGptxJ9//imNGzc28xctWiT77ruvfPLJJzJ58mTp06eP5/sFAKgdqJkAgBigoyC9+OKLJnDQAEJv2E855RRZt26dXHbZZVGtBdBahkAgoTRouOSSS8y/Z8+eLc8//3x5IBHYV63NUF9++WXU9gsAEPsIJgAgRgwePFhGjBhhagb22Wcf86u/Nn/SZlDRorUShx122A7P77rrruaxXbt2stdeewWdv2LFiqjtGwAg9hFMAEAMue+++6RLly6yefNmqVevnmn+pM2gokU7W2tAsT3NTREIJqqSlZVlHr3qEA4AqJ0IJgAghkydOlXmz59v/q2dn3/99deobi8hISGi+QCAuo1vCQCIEdo/QvtJ6PCw5557rhm69ZxzzjGdpAEAiEUEEwAQAwIdr3UEp7POOkv+85//yNVXXy0bN26Uk08+WYqLi2t6FwEA2AHBBADEAM0loTkltL/EE088Uf6cDs2qTZ+uu+66mt5FAAB2QDABADXsm2++kVtvvdVknx43bpzpeK20Y/Qbb7whjRo1kkceeUTef//9mt5VAAAqIZgAgBq0du1aOfXUU6W0tFTGjBljaiYq0tGUNP+E9p/QfhSLFy+usX0FAGB7Pr821AUAxJUOHTqYjtua/E7/XRP69+8vkyZNkq+//tr8GwAQf3YcXBwAEDeuueYakzNizz33lGuvvTbq29P+HU8++aT599y5c6O+PQBAzSKYAIA4Nn78ePM4cODAagkmtCbkpZdeivp2AACxgWZOAAAAAMJCB2wAAAAAYSGYAAAAABAWggkAAAAAYSGYAAAAABAWggkAAAAAYSGYAAAAABAWggkAAAAAYSGYAAAAABAWggkAAAAAYSGYAAAAACDh+H/peHekw1Xr5AAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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22+/marRTzzxhFltafv27Z5uJgAACDBBocFSd0IHEzgA/syrRxp27twp7777rsyZM0dOnz6dParQpk0befTRR00BuMjISE83EwAABLDKPRpKpW6xkhGfYtk5jx86JEc7LrLsfIDfBQ2a6KFBgk4/2rp1q9mnwULVqlXl4YcflkceecTUbAAAAPCmEQcrF6oISSpl2bkAvwsadHnVxYsXm6RmDRRCQkKkc+fOZlTh9ttvN98DAAAACOCg4ZNPPjGPl112mRlR6NOnjxlhgLV1GnTLzMzksgIA4ENsaQlm6WArhISXlaBgr+oGwst51adFqz3rqMKNN97o6ab4La2krZt93V8AAOAbjn73qJyPOmPJuYLDoqVy8zESU6+bJeeD//OqoOGDDz7wdBMAAAD8XlZ6ksRtHi3Rde5kxAG+FzQ4snv3blm/fr3ExcVJgwYNpEuXLmZ/VlaWWZI1PDzc000EAACwREhYmRIJHDLTEqiKDv+o03D48GG55ZZbTPE2rcnw3HPPmWRpu7ffftssu7pq1SqPthMAAMAy5BvAy3j1SMOZM2fkpptukgMHDkjDhg1NrsOMGTNyHdOzZ08ZOHCgfPHFF9K+fXuPtRUAAMCdytz0scRUjXb69bbUeDn8TQ/zdbQtRUIky8LWwd95ddDw0ksvmYBh6NCh5uugoKB8QUP58uXNKMS6des81k4AAAB3u2/zFkmKdrHrVma0eYiypciAC4vlMWuahgDg1dOTPv/8c6lbt65MnDjRBAyFufTSS+Wvv/4q0bYBAAD4quSgSJleqqtkZDHaAD8IGg4ePCjXXnutBAc7bqYmQetUJgAAAH8QExpWIoFDQkaG298H/sGrg4ZSpUpJUlLSRY87dOgQNQcAAIDfCA0ufIYF4AlendNw1VVXydatWyU5OVmioqIKPObUqVOyY8cOuf7660u8fQAAACVlZduOElqxtNOvj0s6IZ1+3GhpmxA4vHqkoXv37nL69Gl56qmnTD2GgjzzzDNy/vx5uffee0u8fQAAACWlQni4VIyIcHorH+7+KU/wX1490jBgwABTJfqdd96RLVu2yN13323279u3T1599VWZN2+e/PTTT9KkSRPp06ePp5sLAAAA+KVQb89pWL58ufTo0cNUg962bZvZr8ur6maz2aRFixam2FtYGNFzUUyfPt1smZmZbv7tAQAAwF94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0rjYVlDAoHr27CnffvutyaY/f/68/PLLLzJs2DC/DRj++OMP+ec//2kSvHWEpbDrgoKvXefOnU3hv0qVKpkRLkfL9oLPYkmbP3++dOvWzVS7L126tDRo0MBUoNcbInDOwoULpXXr1ubfvOa5XXrppabw5tmzZ7mkFsjIyJBrrrnG1DT65JNPuKYu3EDVa5h3a9iwIdfURZ9++qnJg9X/UytUqGBmphw7dkx8AcXd4JJdu3bJ0qVLzT8ADab4w1c0GlS2a9fOVHicN2+enDlzxnQcNFF+wYIFfCr5LHqFyZMnmxsBkyZNkipVqsj69evNghA///yzWSACxaf/1vXm1DPPPGNy3PTG0pgxY2THjh1mOitcM2XKFImLi+MyWuSdd94xNwvstKML5+lNlxEjRpjl91966SVzo/C7776TCxcuiE/QOg2AszIzM7O/fuKJJ2x16tThYhbBSy+9ZCtVqpTtxIkT2fsWLFigNVNsmzdv5hryWfQKJ0+ezLdv7Nix5nN6/Phxj7TJH7311lvmmh48eNDTTfFphw8ftkVHR9s++OADcz0//vhjTzfJZ61Zs8Zcwx9//NHTTfEbv//+uy0sLMw2Y8YMm69iehJc4g1lzX3RsmXLzEjDJZdckr1PCwTqVCUduUHx8Vm0XuXKlfPta9asmXn866+/3PCOgUmnKCimfblm8ODB5v/RG2+80ZLfC2Cl9957z0xVf/TRR332wtLj83J79+6VadOmmXoRjRo1ktDQUDOvUOtBFIVOfdGh8PLly5vVnBo3bmymGvDHybPXevfu3XL11Vfn2qfvd8UVV8iePXvEX/D59b9rqkPp+odPF3nwF564ppmZmWZKghb+1OlJmt/ENXX+mn799deyYsUKefnll8VfeeJzetddd0lISIiZnvj444+b6XX+pCSv6fr16+Wqq64yUzvr1Klj3kuP/+qrr8RneHqoA449+eSTZogw76ZTBIr62tDQUNttt91mu/vuu23lypUz+1q3bm07f/68pZff16cnleS11uMKOm/79u1tt956q81feOrz6+ufRW/9P2HXrl22yMhI28CBA23+xBPXtGzZstnvo687d+6czZ+U5DVNSUmx1a9f3zZ58mTz/f79+/1yelJJXtOtW7fann76aduSJUvMVKWJEyeaz2zDhg1tFy5csPmLkrymV155pa1MmTK2atWq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yR4Tw4CBiIgoPYIGdKWZPXu25hE8++yzUqdOHZ2puUaNGjonA7ouYebos2fPap5AoNi3b5+2JqB7kr1yofUBw7tinRkzZuicDa4EDVu3bjVX8o2cD8C+MCGeZY4Ghq41YJhXDJ06adIkqVmzpjRo0ECHYEWwglYWJJOjJYUo3OWIiZHcGTP6uxhERERhJ01BA6B1ATMTo5sQJkyzzjvAyEnoWjN8+HAJFChLly5dUs1/wOhQGBnK1TwJtKpg0jtrGPkJP4abN2/arDNx4kQNDjDxGlpmMEs1Jsjr16+flgGtIkRERERE/hBhQq3eC5KTk3VuBnT3wSzRaF3A6Em1a9fWXIPKlSt742XIS4zJ3TAHBodypUB08vBhOVpjbornim1sI4XsDBZAREQUiq4EUH0tzS0NBgxZ2rZtW/0hIiIiIqLQwWFDiIiIiIjIKQYNRERERETkFIMGIiIiIiJyikEDERERERE5xaCBiIiIiIicYtBARERERETpM+QqEYW3pORkuXz7ttf2d8mL+yIiIqK0YdBARGm28Pi/MmjnNklI8l5FPy4hSaZ5bW9ERESUFuyeRERpbmHwdsBAREREgYVBAxGlCbokpVfAkC06Kl1eh4iIiFJi9yQiShNTcpI+Rt4xSZZrd7x2NOMSkm2ei4rkfQ4iIiJ/YNBARGly5/YVqb3hinSYHS9ZrttW9L0pKiabT/dPRERE9vG2HRGliSkpOV0CBoiIZPckIiIif2DQQERpknz5VroEDFHZMkp0jlifvw4RERHZYtBARAEPAUOJkY0kIpqXLCIiIn9gTgMReV3hlc2kQLFiXtsfWhgYMBAREfkPgwYi8rqonJkkJk8WHlkiIqIQwbZ+IiIiIiJyikEDERERERE5xaCBiIiIiIicYtBAREREREROMWggIiIiIiKnGDQQEREREZFTDBqIiIiIiMgpBg1EREREROQUgwYiIiIiInKKQQMRERERETnFoIGIiIiIiJxi0EBERERERE4xaCAiIiIiIqcYNBARERERkVMMGoiIiIiIyCkGDURERERE5BSDBiIiIiIicopBAxEREREROcWggYiIiIiInGLQQERERERETjFoCGIHDx6Uxx9/XLJmzSp58uSRrl27SmJior+LRUREREQhJtrfBSDPXL58WerXry+FChWSb775Ri5cuCC9evWSM2fOyHfffcfD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VqyYud7mTwwawlRk5H/TWRAwsALsHhwvHjP38bjxmKUXnms8ZjzXAhc/n2mrt/mT/0tAREREREQBjUEDERERERE5xaAhTGXMmFEGDRqkj8RjxnMtsPDzyePGcy2w8TPKYxaO51qEKRDGcCIiIiIiooDFlgYiIiIiInKKQQMRERERETnFoIGIiIiIiJxi0BACVqxYIe+995489dRTUqhQIYmIiNCf48ePp2m/t27dktGjR8t9990nWbJkkZw5c0rdunXl22+/TXXbb775RtfFNtgW+xgzZozcvn1bAklCQoIMGDBA7rrrLomNjZU8efLIE088IT///LPb+1q7dq352Kf2g0n1LHXo0CHVbW7cuCGhdswA54mz912gQAGn2//444/y+OOPazlQnvLly8s777wjV69elUDizeN27do1WbZsmXTv3l0/W3FxcZIhQwadfLB169by+++/O9w2kM41b18ntmzZIi1btpT8+fNLpkyZpGTJkvL666/L2bNnnW535swZPZZYH8mG2B772bp1qwQibx23bdu2yciRI6VBgwb6nmNiYnSfDz/8sHz00UcO9+fKtW7KlCkSisfsiy++SPW9r1y50uH24XqulShRwqXvxiFDhgTtubZv3z6ZPHmyXmMrVaok0dHRWr5hw4alab+efscdPHhQy1KkSBE91/CI/x86dMjjsjAROgTkyJFDZwy0hpmLcZJ4ApWSRx99VNavX6/7r1+/vp6gqOAkJSVJ7969ZezYsXa37dmzp0ycOFE/MNgua9asut2lS5ekdu3asnr1aj3x/Q0VCXw57t+/XwoWLKhlwwX9t99+0+V4D6hwuGrv3r0yatQoh8v//PNP2bNnj5QuXVoOHDigFxMDPshffvml1KpVS8qUKWN3++nTp+uXeigdM8AX0i+//CKNGjWyGyBgAkLs154JEyZIr1699FiiXPgCRllOnz6tlfN169bphdbfvH3cPv30U3n55Zf19+LFi0vlypX187Zjxw79osDxGDp0qH6xWAuUc83b1wnczGjTpo1en6pVq6aVss2bN+sXJM4LnAv23i/+Jvjb4G9UqlQpeeCBB+Tw4cOyadMmLdv8+fOlWbNmEii8ddxwnIy/MfaBY4bjhJtNGzZskDt37kj16tVl1apV+h1gXZGrV6+ert+4cWO7+3/xxRd1nUDgzXMNQUPHjh31Oo5t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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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MmSIvnzVqlVy0UUXSZs2beSHH37Q80iooV6toCYCAAAAbubqEZT8oyZCmT9/vrRr106effZZWbp0qb5sx44delHDu95xxx0yc+ZMsYogwss0ig+XqOgIS20cTrZWje+QW1AkptSLrf2066WlHskQUxoYuk67DqaJKcVFZSeMqa2gsGAxJS8jz0g7QaE2MSXnWL6RdsLiw8WUvNRcI+0UZRcYaScw3Lff/gNDzNy+wpxCMeXPQDPJ/7Awc6+V0GBzbZlyzNB7SpGh90slz9DnXbP6kUba+eN4jpF2ioM87/GHdTabTR599FGZMmWKHvJVFVEXFxdL8+bNZdCgQZYLqh18+1MEAAAAnk+NnuTKEZT8ZHSm0uLj46udL8IKaiIAAAAAH/D888/L8ePH6+RYBBEAAABwL0ZnMuK2226Tpk2byuWXXy5fffWVHoXJVXw+iCgoKJBly5bJnXfeKb169ZK4uDgJDg6Wxo0b6yr1L774osr9VUHKsGHDpH79+hIeHi6dOnWSe++9VzIzM6vcb+fOnXLNNdfoacVDQ0P1qfpb9UsDAAAATFPdl1TgsHDhQrngggt0HYT63qqKqk3z+SBi5cqVMnjwYHnyySfl4MGD0rdvX30HN2jQQD777DO58MIL5R//+EeFkdozzzwj5557ro7kTjnlFBk+fLikpaXJjBkzpGfPnnqs3YqoYbS6desmb775pg5aRo4cqU/V36eeeqqsXbu2Dm45AACAl1AjM7l68QMffPCBHD58WI/MpL5zqvNqJCb1I/g555wjc+fOlawsMwPs+HwQERgYKJdeeql8++23cuTIEfn888/l/fffl19++UXee+89XcH+6quvyttvv11mv82bN+shsNR6la1QwciCBQtk165durJ927ZtctNNN5U7XnZ2towePVqf3n333XpWQHUcdar+Vg+cWp+TY2ZkBQAAANSM6pXSuXNnmTNnjs/eZQkJCTJx4kT9XVYtt956q9SrV0++//57PcGc6o0zfvx4/d3YCp8PIgYOHKijsrPPPrvcOtVfTHUxUt56660y6x577DGdnbj22mvl/PPPL7k8IiJC3njjDR2cLFq0SH7//fcy+82bN09HfR06dJBHHnmkzDr1t7r8wIED5Y4HAADgtwLrYBGR9evXy2+//SYTJkwQf9CtWzeZPXu2/m6qvg+rLvp5eXn6+6r6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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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VDJhRU38+OOPsn///hrvDwAAANSmr776quRLv/rll1/M6RNPPCHvvvtuyfVvvPGGGU619FCrOqTqI488In369DGjJumX+uXLl8uRI0ekb9++Mn36dOu3V0dics8F8eSTT0rr1q3F70GERlH//ve/a3ygK6+8Up577rka7w8AAIAQFaCjM+k8DmvXri13/a5du8ziVlEXojlz5phgQSd501oFnSm6ffv2MmXKFLnpppskJiZGbLv55pvl+OOPNwGOznit9RlavB0fH19hD6FnnnmmxsdiiFcAAACgki79OjlbTY0aNcostWXBggUlJQhaYK0BUEVBUK0FES+99JK0bdtWvDF27Fj54x//6FUbAAAACEG+HkGpFkdn8qf58+fX2rGqFUSMHj3a6wOdfPLJZgEAAAD8QUdNioyMlHHjxpkl1Fx++eW1diy6MwEAACAsRmfSYVdra5boUEcQAQAAAISYH374wRR0HzhwwBRbn3vuueb64uJiM+WCt4XdXgURa9asMUNV7dmzR/Ly8nxStAEAAIAQp1ONRPi4/TCxc+dOMyrqxx9/XKabkzuIeOqpp8ywtUuXLjVDz9ZqEJGTk2Mqzd9//31zuaqqdYIIAAAAwPcOHTokAwYMkO3bt0vXrl2lf//+Mm/evDLb6Hd4neju7bffrv0gQmfhW7JkiaSmpsqll14qxx13nCQlJdX4RgAAACCMhdiM1f4ya9YsE0BMmjTJnNcf848OIvT7e7du3eSzzz7z6lg1CiIWLVokdevWNbP4+XImPAAAAADV89Zbb5nJ5WbOnFkyX0RF2rVrJ6tWrZJa7yF2+PBhOf300wkgAAAAYC8T4cslDPz666/Ss2dPiYio+iu+FlVr16daDyI0+3CsGwcAAACg9sTFxUlmZuYxt9uxY4ekpKR4dawaRQJjxoyRFStWyJEjR7w6OAAAAFAyOpMvlzDQuXNnU26QnZ1d6TZpaWnyzTffyAknnODVsWr0kN56662m4vvss8+WTZs2eXUDAAAAAHjvoosukoMHD8rEiRPNfBAVueWWW8xIq6NHj679wmrtR/Wf//xHTj31VFPd3apVK7NU1MVJizp0LgkAAACgQozOZMW4cePk2Weflaefflq+/PJLueCCC8z1v/zyizz00ENmcKQvvvhCTjzxRLniiitqP4jQwuozzzxTNm7caOaI0KGkdKlI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TJT09PRKR2DSpbKEQEJCQu0HETUJIAAAAAB/DvEaapo2bSpff/21x/vpPrqvN+xVfAIAAACoNVoPsXv3bvnkk0+qvY9uq8O89u3b16tjE0QAAADAvyJqYQlBl156qSmgvv766019xLFoHYRuq5mZMWPGeHXsEH1IAQAAgNA2YMAAOfPMM+WHH34wk8299957lW6rUy307t1bNm3aZAZGOuOMM7w6duANFg8AAICwQk1EzS1cuNB0Tdq8ebOZ0FnnbuvZs6c0bNjQrD9w4IB89dVXcvjwYZO16NChg9nHWwQRAAAAQJCqX7++rF27VsaPHy8vvfSSHDp0yEzu7C4md88XoZM/X3zxxWay6Lp163p9XIIIAAAA+BfzRHhF54p4/vnn5Z577pF3331XvvzyS0lLSzPrGjRoYDITOsdb+/btxRaCCAAAACAEtGvXzkwGXRsIIgAAAOBXJCKCD6MzAQAAAPAImQgAAAD4FaMzBR8yEQAAAAA8QhABAACAsJixWidb69KlixnmFN6hOxMAAADCwrp16yQ5OdnfNyMkEEQEmab1EyQxqY5Xbew/nGvlthzMyBdbCouKrbSTlesUW6Iif5+kxVvFlu6bioi0kzx0WLpvRp6lxzw6UqypHx9Y903vXs+mdtopamKlHbH5GmiQYKedhGh775VYO3/e4upZei2JSExSrJV2svdniS0plp676Ch7HRsKnXY+M4uKf59gK5Aczi6w0k7z+naetxiJkUBBTUTNfPLJJ9KkSRPp2LGj1Da6MwEAAABBaODAgTJz5sySy4MGDZLZs2fXyrHJRAAAAMC/mCiixlyu/2XdVqxYIW3atJHaQCYCAAAACEJJSUmyd+9evxybTAQAAAD8ikREzZxwwgny0UcfyZ133ikdOnQw1/3888/y3HPPVWv/yy67rIZHJogAAAAAgtLkyZPloosukvvuu6/kulWrVpmlOggiAAAAELxIRdTI8OHD5YsvvpA333xTfv31V1mwYIG0b99e+vbtK75GdyYAAAAgSHXv3t0sSoOIfv36yb///W+fH5cgAgAAAH7liHCYxZfth4O77rpLevToUSvHIogAAAAAQiSIqC0EEQAAAPArx3/LInzZfjhxOp3y2muvyccffyy7d+821zVv3lzOOOMMU4gdFeV9CEAQAQAAAISIr7/+2gQK27ZtKzMRnXr66adl2rRpsmjRIjnxxBO9Og5BBAAAAPyL0Zms2LNnjwwdOlTS0tKkcePGcvHFF5vRmtTWrVvl5Zdfll9++UXOOussE2w0bdq0xsciiAAAAABCwKxZs0wAcc0118icOXMkPj6+zPoZM2bIhAkTTEZi9uzZ8s9//rPGx4qwcHsBAACAGnM4HD5fwsH7778vrVq1kscff7xcAKHi4uJk3rx5Zpv33nvPq2MRRAAAAAAhYOfOnXLaaadJZGRkpdtoUfWpp55qtvUG3ZkAAAAQAMMz+bj9MBAbGysZGRnH3C4zM9Ns6w2CiCCTkVMoxZEFXrWRX1hk5ba0apQotmz45aCVdpITosXmY21DRJS9hJ8zz85tSmyaLLYcPfJDTTnznWJNsaXHvGWKWFNg6f5lePf+LxFtMREdU/kvXh6Jt/f+jbLUVkR0pL2XQGa+lXbiUuLEFmeRnfevS4rFltTEGCvtZOTa+bxU9ZO8+7Lllm3pMzzCUtccW+0gcHTp0sUM66pZhpYtW1a4zY4dO8w23o7ORHcmAAAABMSM1b5cwsFll10mubm5MmTIEFmyZEm59e+++66ceeaZkpeXZ7b1BpkIAAAAIARce+21snjxYlm+fLkMHz5c6tWrJ23btjXrdN6IQ4cOmR4EGmTott4gEwEAAICAKInw5RIOIiMjzahLkydPljp16sjBgwdl/fr1ZtHzet2tt95qMhIREd6FAWQiAAAAgBARExMjM2fOlHvuuccED7t37zbXN2/eXHr16uV1QbUbQQQAAAACYMJq3+UL3E337t3b/Fo/btw4s4Sy2NhY6du3r8/aJ4gAAABAWFi3bp0kJ9sboTCcEUQAAAAgADIRvm0fdlFYDQAAAMAjZCIAAADgV2Qigg+ZCAAAAAAeIRMBAAAAv3L8958v24ddZCIAAACAELBjxw7ZuXNnrRyLIAIAAAD+9d/RmXy1hEsiok2bNnLxxRfXyrEIIgAAAIAQkJycLG3btq2VY1ETAQAAAL9idCY7unTpQncmAAAAANV37bXXyqpVq8zM3L5GJgIAAAB+5XA4zOLL9sPBlVdeKRs2bJChQ4fKLbfcIhdeeKGpk4iNjbV+LIKIIHMoI1/yimO8aiM60s4baftvmWJLw5Q4K+0UOovFlmJLbSUlevd8leasl2CnnXyn2BIVF22lnegEe49TsbPISjtFBWJPrstKM9HtU620U7gvS6yx9BqPiLZXpldUYOc17rL4mRIZG3h/cmMsPeaREfa+oDmLXAF3m7Ly7LyeWjSoY6WdYpcroNpB4IiMjCw5P23aNLNUFVg5nTV/bQfeJxoAAADCiq8HUAqPPISIy4PA0JNtK0IQAQAAAISA4mJ72dNjIYgAAACAX1ETEXyYJwIAAACARwgiAAAA4Fe+nK3a13NQBKJffvlFJk+eLP369ZNOnTqZ825r166VJ598UtLT0706Bt2ZAAAAgBDx7LPPynXXXSf5+fklXcXS0tJK1ufk5MjYsWMlJiZGrrjiihofh0wEAAAAAmJ0Jl8u4eDzzz+Xa665xgQIs2fPNlmHo0dhGjBggKSkpMg777zj1bHIRAAAAAAhYPbs2SZoeO+990xXpopERETIiSeeKD/88INXxyITAQAAgIAYncmXSzhYtWqVnHzyyZUGEG5NmjSRvXv3enUsgggAAAAgBBw5ckRatWp1zO1yc3OloKDAq2PRnQkAAAB+5esRlMIkESH169eXX3/99Zjb/fzzzyYb4Q0yEQAAAEAI6NOnj6xfv16+//77Krs86fpjdXk6FoIIAAAA+BU1EXaMGzdOioqK5MILL5Svv/663PpNmzbJVVddZR7v66+/3qtjEUQAAAAAIWDw4MEyceJE2bx5s5x00knSsWNHEzD85z//kRNOOEG6desmW7ZskVtuucVkLbwR0kHE/v375bnnnpMxY8bIcccdJ3FxcZKQkCCdO3eWCRMmyPbt26vcXwtOZs2aJd27d5c6depIamqqDBw4UF577bVjHnvRokVmW91H99U2dNitwsJCi/cQAAAg+DFPhD0PPPCAPPHEE6bmQWsfdMhXHYlp48aNUq9ePXn00Udl5syZXh/H4Tp6BooQcumll8qLL75oxsPt2rWrmfY7Oztb1q1bJwcOHDBf7t944w0588wzy+2rs/np9atXr5a6devKoEGDJCsrSz766CNxOp1y8803myepIjfeeKPMmTNHoqKizH6JiYlmP62Y1/5nS5culfj4eI/uS0ZGhpkYZNGKHyQhMUm8ER1pp7ooO98ptkRF2olnC53FYsuh9Dwr7SQlxogtRw7lSqjKO2zvvhU7i6y0U1Rgpx0j/feZQ70V3STRSjuF+7LEGkuv8YiYSLHFYelzLj41QWyxef9sSakbZ6WdyAh7Vaux0XYeJ2dRccD9jaqfFGulnWJLX92yszLlrN7HSXp6uiQnJ4s/uL/fvLDsO0mo4933m6rkZGfKpUO6+fW+1jb9ir9hwwbZunWrFBcXS8uWLaV3797m+6kNIT06k0Zb99xzj1x99dXSvHnzkus1GLj22mvl5ZdflosvvthEaZoxKO322283AYSmfTQAaNCggbn+yy+/NBmGBx980Jyec845ZfZ78803TQChgcPKlSulZ8+e5nqdblwDis8++0ymTZtWaQACAAAQbhidyT7txqTfQ93fRa23H8qZiKpopkHTPJmZmfL888+brIXb4cOHzTrtzqRf+vv27Vtm33vvvdcEAtqXbM2aNWXW6QQfmunQbaZOnVpmnbZ1+umnS2xsrPz2228m8vY0Ul/+1S+SmJQUEL/W14mLFlv2HMyx0k5inL24OCPXTtezTEvtKFu/9WVm2PlV3Oav/jYnAsq19HqKio8OuF/GbSnKt5dliYiy8yttpMVf6iMs/Zptc1jI+EQ7v0Inxtv7nDtkKUMWb/E2xVt6HdSJtXebUixl2/Isve/yC4usZSJGnP6HgMhEvLjc95mI/xscXpkIpV/zDx48aE51+FftnWNLSNdEVEVrI7R7k9q5c2eZdUuWLDEBhE7WcXQAobTGQn3++eeyZ8+ekut3795tAojS25SmXZk0lZSfn2+OAQAAAP2RzMczVv/3ZzjtztOlSxeZO3duSD/sH374ofzxj3+UpKQkady4sflxXM/rdVpkbUPYBhFa4OwurG7atGmZddp/TPXq1avCfdu1a2e6SqnSw2e599N1bdu2rXBfd5vubQEAAFA79MfeH374wQyFGqpuueUWEyxoDa72vNEshC46S7VeN2zYMFPb662wDSKeeeYZU6egBc5nn312mXXbtm0zp1VNG96iRYsy21Z3P81EHL0fAABAOGN0JjteeOEFU7erI5JqoPDtt9+arvu6fPfddzJp0iTz3ffhhx8223ojLIMIfRA1SlNa26BpntL0gVY6elNltHDa3ZfP2/0qol2edJvSCwAAAFAZHb41MjJSPvjgA/nHP/5hRifV76W6HH/88Wa6AV2nXbwee+wxCcnRmSZPnixvv/22x/s9/fTTVU7jvWvXLhk+fLgZoencc8+VKVOmSCC6//77zchSAAAAoY7RmezQuSD0e7AO5FMZ93p3HW/IBRFasPzTTz95vJ8G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82T58uVyyy23SO/evaVu3boSHR0tTZo0kXPPPVfee++9KvdftmyZDBs2TBo0aCDx8fHm/TZ16lTzOVmVn3/+Wa644goz3Lf20ddTvbx161bL9zC0TZ48ueRv0b333lvpdjxPwDHojNWAr1133XUuh8Ohs6ObZefOnRVul52d7TrttNPMNnXr1nVdcMEFrqFDh7qioqLMdTfffHOlx7jhhhvMNrqt7qP7aht6Xb9+/Vw5OTk+vIfB6f/+7//M4xMREeE64YQTXCNHjnQNGzbM1bBhQ3N9nTp1XEuXLq1wX56rwMLrv/Z8+OGHJZ9lTZo0cf3pT39yjRo1ytW1a9eS6//yl7+4iouLy+370EMPmfX6edi/f3/zntM29LpOnTq5Dhw4UOExP/vsM1dCQoLZ7vjjj3eNHj3anLrfp2vWrKmFex78Vq1aZT7v3H+Ppk+fXuF2PE/AsRFEwOf0S6h+WI8fP/6YQYT7i1C3bt3K/DFdv369KzEx0ax75513yu33xhtvmHW6zZdffllyvbahbR0rAAlXf/vb31z33HOPa9euXWWuz8zMdF188cXmcatXr57r0KFD5fbluQocvP5r1/Lly10XXnih65NPPim37uWXX3ZFRkaa986zzz5bZt1XX31lvrzq+iVLlpQJyAcPHmz20XaPpuubNWtm1t92221l1ullvb5ly5b8UHIM+jged9xxrubNm7vOP//8SoMIniegeggi4FPp6enmj1vbtm1dWVlZVQYR+kU1JibGrNdf3Y6mH/a6rk+fPuXW9e7d26y79957y6379NNPzbrY2FjXkSNHLN670P+Dm5SUZB67559/vsw6nqvAwus/sFx99dXmfaOBQWmaddDrr7nmmnL7bN++3fxCrus3bdpUZt3cuXPN9R07dnQVFRWVWaeX9Xpd/69//ctH9yg0TJgwwTxO7733nuvyyy+vNIjgeQKqh5oI+NSNN95o6h+efvppU6NQlSVLlpg+9q1atZK+ffuWW6/99tXnn38ue/bsKbl+9+7dsm7dujLblNavXz9p2bKl5Ofnm2OgerQ2olOnTub8zp07ea4CFK//wNOjR49y7xv9bHPXSlT0OdW6deuSz7033nijzDr35YsvvlgiIsr+2dbLo0ePNudff/116/clVKxYsUIeffRRueyyy0w9SmV4noDqI4iAz+gfzPnz58u1114r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zz77TO64444y67Su4P7775fk5GR59dVXJS4uzvrxL730UpkyZYo0b95czjrrLBNUPPHEE6YYWwMFPdVuUZ06dTLnc3JyTNAxcuRI67cFABAaqIkAAB+LiYkxAYJmGmbPni0DBgyQs88+W3bt2iV//vOfxeVyydNPPy0dOnSwfuxff/1VoqKiZNOmTdK6dWtz3cGDB+XUU0+VDRs2mFPNPmzdulXq169v1m/btk1OOukkef/992XVqlXSt29f67cLABDcyEQAQC2NarRgwQITMGjgoF/UL774YklLS5Px48f79Fd/zSq4AwilwcLYsWPN+Y0bN8ozzzxTEkC4b6tmL9Ty5ct9drsAAMGLIAIAasl5550nEydONJmAHj16mF/5tZuTdnfyFc1CDB06tNz1xx13nDlt1aqVdO3atdL1e/bs8dltAwAEL4IIAKhFs2bNki5dukh6errUqVPHdHPS7k6+okXUGkgcTeeWcAcRFUlKSjKntgq9AQChhSACAGrR2rVrZfPmzea8FjV/9913Pj1eRESEV+sBAKgIfz0AoJZo/YPWQegwr1deeaUZgvWKK64wxc8AAAQTgggAqAXugmodkemyyy6Tf//733LzzTfL4cOHZfTo0VJYWMjzAAAIGgQRAFALdC4InRNC6yHmzZtXcp0OsapdnCZPnszzAAAIGgQRAOBjn3zyidx5551mtuhFixaZgmqlBc8vv/yy1KtXTx5++GF56623eC4AAEGBIAIAfOjAgQNyySWXSFFRkcydO9dkIkrT0ZF0/gitj9A6ie3bt/N8AAACnsOlHXUBAEGlTZs2piBbJ63T8/4wcOBAWblypXz88cfmPAAgfJQfPBwAEDQmTZpk5nw4/vjj5ZZbbvH58bR+4/HHHzfnf/zxR58fDwAQmAgiACCILV682JwOHjy4VoIIzXw8++yzPj8OACCw0Z0JAAAAgEcorAYAAADgEYIIAAAAAB4hiAAAAADgEYIIAAAAAB4hiAAAAADgEYIIAAAAAB4hiAAAAADgEYIIAAAAAB4hiAAAAADgEYIIAAAAAOKJ/wfWlg5GsthvtAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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YoWlY5GJAAAAALzsgw8+kMsuu0yaNWsmMTExctppp8kzzzwj+fn5xo+l2gwNtRYGkIkAAACAd6lpHOycy8EPpol4+umndRZBdUeqX7++rFq1Sh588EH56aef5M033zR6rJ9//llq165tqQ2CCAAAAMDLFi5cKHXr1i263KdPHz0p3MSJE4sCi7LccMMNJS5/++23pa5zczqd8uuvv8oPP/yg542wgiACAAAA3sXoTFI8gHA788wz9en+/fvLDSJmz55ddD4kJES2bduml4o0atRIDwNrBUEEAAAAUE4B8uLFi+X777/Xy6ZNm6SgoEAee+wx3dWoMvPmzZMZM2bIjz/+KHl5eXoSuL/+9a9y9913S3h4eKX7f/3113qCODX7dHlmzZqlT1XWQmUgevbsKTfeeGOZ26q2mjRpIt27d6/S8StCEOFnQkNCxBFqrWNfVITDyG2pXytaTEnLyhNfE+YwM+6A1efLDll/ZBprKzTc0PgMzkIxJjXbSDOuIyfElPxNh4y0U3AozUg74W0aiikh4WY+U0IizP1JKjB0myTC3Pgj4THW/mC7OU+YK7IMizZzmzJzzN0mU5+Zg89qLqYs/2m/kXYSDL0Gdh408xmenWXub0Ggjs700ksvybRp06q171133aX3DQsL08OpxsXFybJly+S+++7TXZdUcBIdXf53KdXtSO1/yy23SEJCQrnbXXvttUXnH3nkER0gFL/OLgQRAAAAQBk6dOigZ37u3LmzdOnSRSZNmiRvv/12pY/VggULdACgAgc1lKraV0lNTdUBhapbULUOqpi6LGq7IUOG6MzF5MmTq/zc7Ny5s8aeR4IIAAAA+MDoTDa3Xw033XRTictVHRZ10qRJ+nT8+PFFAYRSp04dmTlzppx77rny4osv6kAiMTGxxL4ZGRly4YUX6u5Pat6H2NhY8UUEEQAAAIAh+/btk5SUFH1+xIgRpdarmoWmTZvKnj17ZNGiRXL11VcXrcvNzZVLL71UZxRUtkIVQFeHauerr77SNR3p6em6XuJkqghbBTHVRRABAAAA71K1MHbWEP63bfWFurjIyEi9mLRhwwZ9mpycLC1btixzm65du+ogQm3rDiJUwfbw4cN1AKJqJ9q2bVut43/00Ufy97//XY4cOVLuNiqoIIgAAAAAqkBlAIp7+OGHdTGySTt27NCnaubpym6He1vl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kLlz50pUVJTx419zzTUyfvx4ady4sQwcOFAHFa+88oouxlaBgjpV3aLatm2rz2dnZ+ugY+jQocZvCwAgMFATAQA2i4iI0AGCyjRMnTpVevXqJRdeeKHs3btX/va3v4nL5ZLXX39dTjnlFOPH3rVrl4SFhcmmTZukefPm+rojR47I2WefLRs2bNCnKvuwfft2qV27tl6/Y8cOOfPMM+Xzzz+XlStXSo8ePYzfLgCAfyMTAQA1NKrR7NmzdcCgAgf1RX348OGSmpoqo0aNsvVXf5VVcAcQigoWbrvtNn1+48aN8sYbbxQFEO7bqrIXytKlS227XQAA/0UQAQA15NJLL5UxY8boTEDnzp31r/yqm5Pq7mQXlYUYMGBAqetPPfVUfdqsWTPp0KFDuev3799v220DAPgvgggAqEFTpkyR9u3bS1pamsTGxupuTqq7k11UEbUKJE6m5pZwBxFliY+P16emCr0BAIGFIAIAatCaNWtky5Yt+rwqav75559tPV5oaKil9QAAlIW/HgBQQ1T9g6qDUMO8Xn/99XoI1uuuu04XPwMA4E8IIgCgBrgLqtWITCNHjpR//etfMnbsWDl27JhcddVVkp+fz/MAAPAbBBEAUAPUXBBqTghVDzFz5syi69QQq6qL07hx43geAAB+gyACAGz29ddfy0MPPaRni543b54uqFZUwfN7770nycnJ8vzzz8vHH3/McwEA8AsEEQBgo8OHD8vVV18tBQUFMmPGDJ2JKE6NjqTmj1D1EapOYufOnTwfAACfF+JSHXUBAH6lRYsWuiBbTVqnzntD7969ZcWKFfLVV1/p8wCA4FF68HAAgN+455579JwPp512mtx77722H0/Vb7z00kv6/G+//Wb78QAAvokgAgD82Pz58/Vpv379aiSIUJmPN9980/bjAAB8G92ZAAAAAHiEwmoAAAAAHiGIAAAAAOARgggAAAAAHiGIAAAAAOARgggAAAAAHiGIAAAAAOARgggAAAAAHiGIAAAAAOARgggAAAAAHiGIAAAAACCe+H/kvwaLVaROmgAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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OX78uFmITwvD9VP8a665RqpUqSKZmZlmdXC96X744YflL3/5i8THx1tSIL5z50556aWXZMCAAdKsWTMTanQo1zPPPFOi18+dO1c6d+4slSpVMmt9aACaMmWKabMV1qxZI5dccom8/fbbUq9ePdM+fY8vv/zSkvMDAGBb1E4Aod2jkZ/eTOum62S4HThwIE+vhz4ePXpUtm3b5vX7zZo1ywxL8sSIESPMa/Xmv2vXrlKhQgVZsWKFjB49WhYuXGjCU0xMjFft++OPP+TQoUMyfvx4U59x/vnnm2B00003mbVFmjRp4tX5AQAIJbWvnifn1Yj36hzO9FOy74trLGsTEKiCPmjoTXStWrWKPUYX6NPtlltuyfM6DRze0noQLbLWWZx0WNazzz4r77777jlft2DBAhMyNFx8/fXX5rVKe2U0dKxevVrGjRsnzz//fM5rZs+eLQMHDixRL4n29Cin0ylnzpwxs0717NnT7NMeFF1XRIPHO++848V3DwBAaAmPrigR5Sp5dY4sy1oDBLagDxp169aV6tWrm7qL1q1bm8X49LFatWrFvk7DybkCSkkMGjQoz5/Dwko2Gk0DiRozZkxOyFBVq1aVmTNnSseOHeXll182YSMhIcE816tXL2nXrt05z537+9IhWapLly45+7Rmo3379pb06AAAEEoSMzIkIj3dq3NkZWTIaUes+TrOlSbh4rSodUBgCfqgUbNmTdM7sWjRIvniiy9y9msPRu7goZv7ht3ftL3r1683X/fr16/A8x06dDDt1yFfixcvlr59+5r92v7Sfg86NOr7778vdKaus2fPevw9AAAQinqvWSHJcRbcPlUYbx5iXWky5OwCecD7MwIBJ+iLwfVmXG/cP/30U/n73/8uV111lSmq3r9/v8yfP18ef/xxufbaa6Vy5crSqFEj6d+/v7z44otmaFJqaqpf2rx582bzqG1q0KBBocdoMMp9rKe0FkMtX748Z196err5/t3vURg9JikpKc8GAACsleKIkRnlbpEsJ70asJ+g79FQurq11l+4azB0xictfq5du7YJF3qT/OOPP5o1JXbv3i0ffvihOS48PFwyMjLKvL06M5Z72FdRtEcj97HeBI0rr7zSDPHS2bl0mJkWg586dcoEs6LosRMmTPDqvQEACGbxEZEF9sUlOy2tskgpHy4p4TGSmJUl9p90H6HG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R48W2Ddx4kTze/rHH3/4pU129Oqrr5prum/fPn83JWgdOHDAFRcX53r77bfNtfzggw/83aSgtXLlSnMNv/vuO383xTZ++eUXV2RkpGvmzJmuYMbQKZSpsDB+5Ty1ePFi06Nx3nnn5ezThR91GJX2EoHfx0BQrVq1AvtatWplHn///Xc/tMiedAiFYkia50aMGGH+Dr3qqqss+7kAVnnzzTfNMPr7778/qC8qd302s3PnTnnppZfMeh7NmjWTiIgIM05S1+soCR2So130lSpVMrNgNW/e3AyB4B8z/1/v7du3y6WXXppnn75fo0aNZMeOHWIX/A7b75pqV7/+g6mTXdiFP65pdna2GTKhC7rq0Cmt17LLNS3r6/nVV1/J0qVL5V//+pfYlT9+R2+++WYJDw83wyYffPBBM+zPTsrymq5Zs0YuueQSM+S0Xr165r30+C+//FKCir+7VGCt4cOHm+7L/JsOXSjpayMiIlzXXnut69Zbb3VVrFjR7OvQoYMrNTXV0rbaYehUWV5vPa6w83br1s11zTXXuOzCX7/Ddvh9DMS/F7Zt2+aKiYlxDR061GUn/rimCQkJOe+jrztz5ozLLsryeqalpbkaNmzoev75582f9+zZY8uhU2V5TTdt2uR69NFHXQsXLjTDqCZPnmx+X5s2beo6e/asyy7K8ppefPHFrgoVKrhq1Kjheuedd1xLlixx3XDDDeb1W7dudQULgobNvPbaa65Ro0a55syZ49qxY4fr7rvvLtH/BPPnzzfH6S/1xo0bc/YfO3bM1axZM/Oc/iWS21tvvVXo/3D5t7lz59r2xq4sr3eoBI2yvKZ2+30MtGuqx1100UXmWDvdFPvrmm7evNn17bfful555RVX7dq1XV26dHFlZWW57KAsr+e4ceNcl156qSsjI8PWQcNf/9+7LV261Byr9wp2UZbX9KKLLjL7v/jii5x96enp5v99fd9gQdCwuXvvvbdE/xO0adPGHPfMM88UeO5///ufeS46Otp1+vTpnP36tf6Pdq4tKSkpZG7sfHm9q1WrVuhf7pdffrnrjjvucNmVL6+p3X8f/XlN9f/71q1bm2t66NAhl92V1e+p29q1a4v9ICfY+ep67t271/x53rx5rlOnTplty5Yt5rg33njjnNc9mJX176iqXLmya/DgwS678uU1bdu2rdmfv6dD/73Xf/eD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AAAAyhsCjXLmo48+snfeecemTJliq1evtmbNmtnll19uN954o2VmZlqyWzV0li3q85Xt3rgj3kkBAAAo1wg0ypnHHnvMmjZtao888ojVq1fPxo0bZ3fffbfNmDHD3njjDUv2mgyCDAAAgMRAoFHOfP7557bnnnvm/f+EE06wQCBg99xzT17wkazUXKq0azK2VK5gFWpULNVjAABQXIsWLXKtEy699FIbMmQIGYeEQmfwciY4yPC0bt3aPS9fvjwOKUoeCjKG/HNPS8vgawMAyWL06NHWvXt3a9SokWVlZVnt2rWtXbt29uSTT9r27SXvhzdmzBhLS0uze++915f0AqkkqWs0br/9dnv00Ufd3/3793dNgOJp3rx59vXXX7v+D3rMmTPHdu/eXey0DR061J5//nmbPn267dy50/bdd1/75z//aTfffHOp9p/44YcfrGLFirbPPvtYqjls7NWWUbtyzNuv2rTSuoyf4P7eUiXdctPTfEwdAKC05OTk2HXXXWcvv/yyVa1a1U455RT3u7phwwb3W33LLbfYSy+9ZCNGjHCvJ6uGDRu68kaNGjXinRQgdQIN9S14/PHH3V0ENf1JBC+++KI9/fTTMW170003uW0zMjKsY8eOVq1aNfvuu+/sjjvucM2ddFGsXDn2AnMks2fPdse9+uqrrXr16pZqFGRk1qka8/bpFSvZpuyk/ZoAQLnVp08fF2S0adPGhg0b5grkHt0EvP/++92jS5cuNnXq1KT9DdSNyAMPPDDeyQDCSso2IFu3brWePXta/fr17ayzzrJEccghh1jv3r3dqE66u9CjR49ibffpp5+6wr6Ci4kTJ9pXX31lH3/8sf3+++/WsmVLGzt2rOtDEUztMBVkFfXQKFORaNSps88+293Jeeihh0r8/gEASAS//fabPfHEE66ZlG7WBQcZkp6ebvfdd59ddNFFNn/+fDdQSujva7j+DqHNpPSsvo6i/QX//qrvRHDtysCBA13LgUqVKrnfXf1/wYIFbl2VaUK9/vrrdvTRR7uygR76O1yadJxw+whO6+TJk+2kk06y7OxsV/PRtWvXfOkrSTojUWsObaMyTSh9JlqmG8ZIbRnJepdChXBVd3744YdRb//XX3/Z4MGDXeFdJ3okS5cudV/qu+66q9D1PFdeeWW+/1eoULw47sEHH3TPd955px1xxBF5r9ep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5s2Winm2detW++KLL+z6669336vs7GyrWLGim0zyggsusJ9++initol2rvl9nZgyZYqdd955Vq9ePatUqZI1a9bMbrjhBlu5cmWh2/39998uP7W+Ol1qe+1n6tSploj8yrdp06bZwIEDrVOnTu49Z2Zmun0ed9xx9vzzz0fcX3Gudy+99JKlYp4NGTKkyPc+atSoiNuX13OtadOmxfp9vP/++5P2XJs3b549++yz7jrbsmVLy8jIcOl74IEHSrTfWH/j/vjjD5eWvffe251retb/FyxYEHNa6AxeTtWsWdPNHhlKM1jrxIqFCjMnnXSSjRs3zu2/Y8eO7qRWwSgnJ8duvfVWe+yxx8Jue9NNN9nTTz/tvmTarlq1am679evXW7t27ezrr792X5Z4UsFDP6a//fab1a9f36VLPwA//vijW670q4BSXHPnzrWHHnoo4vKff/7Z5syZY/vss4/9/vvv7uLj0Rf/jTfesGOPPdb23XffsNsPHjzYFQLize98E/2Iff/999a5c+ewQYUmltR+w3nyySftlltucfmpdOlHW2lZsWKFK9SPHTvWXZxTKc9eeeUVu+qqq9zfTZo0scMPP9x916ZPn+5+WJQX/fv3dz9EoRLpXPP7OqEbIBdeeKG7PrVp08YV5CZPnux+VHVe6FwI9571uejz0efUvHlzO/LII23hwoU2adIkl7YPP/zQunbtaonCr3xTPnmfs/ahPFM+6QbV+PHjbffu3XbUUUfZV1995X4DQgt/J5xwglu/S5cuYfd/6aWXunUSgZ/nmgKNyy67zF3LtW04+n1UQTNUeT3XpHfv3rZ69eqwy9auXWuff/65+/uHH35weZSM59pN/5dfoXQ9vvvuu2PaZ6y/cbrhdPLJJ7uyXIsWLeyQQw6xWbNm2a+//uoCRgUvbdu2jT5BGnUK5c9ll10WePDBBwOjRo0KrFy5UiOPuceSJUti3mevXr3cPlq2bBlYtWpV3uuTJ08OVKtWzS37/PPPC2w3bNgwt0zrTJkyJe917UP70rJbb701EG9nnXWWS0unTp0CW7ZsyXt9xIgRgfT09ECFChUC06dP9+14Bx10kDvegAEDCiy79NJL3bLXX389kOhKI9/at2/v9jl69Oiotps6dWogLS3NHXfkyJF5rytdSp/22a1bt0Cq5dmQIUMCl19+uXv/wXJzcwOPP/543vd/zJgxCXuu+X2dWLZsWaBKlSpuu0GDBuW9npOTE7j44ovd623atHF5FEz/b9WqlVveo0cPt75H+/HS+NdffwUSgZ/5tmvXrkDr1q0DH374YWD79u35ls2YMSNQv359tz/9voTSd1XL9N1NdH6fa/ruaBt9l6JRns+1ojz88MNuf/vvv39Sn2uDBw8O9O7dO/DOO+8E5syZ4z5npb1///4x7S/W3zgtb9CggVvep0+ffMv0f73eqFGjwNatW6NOE4EG/ncilDDQWLt2baBixYpuH2PHji2wXF8aLWvbtm2BZfox17IHHnigwLIff/zRLcvKygqsX78+bp/Wr7/+6tKhL++iRYsKLL/iiivc8gsuuMCX440bNy7veCoQJWrhL175Fmugcd5557ntrrzyygLLlD4V4LVcF/zycq6J9wOkfSfqueb3deK2225z25x44okFlm3atClQo0YNt1w3Y4Ip2NPrNWvWdOtFyss777wzkAjK8vr61ltvuf1Vrlw5sHPnzqQt/PmdZ7EGGpxrkR1wwAEuTx966KECy5LpXIt0vY010Ij1N+7555/PC9x2796db5n+r9e1/KWXXoo6TfTRgG99PtQ/o3Hjxq6JRaiLLrrIPU+YMMGWL1+e9/qyZctcFXDwOsFU1ap25Dt27HDHiJdhw4a5Z703NT0J5aVdVbl+9Cl57bXX3LOqfdWHJlmVdb4VRufniBEj8h03mNLnnbteustLnrVq1Sqv6WQiKo3rhJfP4fan5h5nnnmm+/uTTz4Ju52Wa71Q3v5Ct4uHsr6+eufRtm3bIjZ5SXSJ9JvEuRaemviob4OaZ6kJFEr+G+f9X332KlTIHxro/927d4/5upYR9RZAhA6Covaj4ahtae3atV27yl9++SWv8Oxtp2VqHx2O9qkCkNZVe+pEfH/e61u2bHH9KQ4++OCYj6X2kR988IH7+4orrih03dGjR9vMmTNdx+E99tjDtY9WB7BEmRG0tPNNF8dPP/3UFWzUDvUf//iHa2MaeqH02jorb4tKj9qyeulO9XPNo/2I+oMk4rnm93VC70F9U7ztIu3vrbfeKnAuFPfzUZ7qM1Lb5ngp6+urdx5poAEdMxz1NVLnXRXo1flenVQ1yIFuUiWC0swznXNqd6/+FgpS1QZeAWukPmGca4XfiNP1p7CBPxL9XPNbSX7jinuuxfLbSKABX6hzmhT2BVYncwUa3rrF3U53j4LXjYei0lm9enX32Lhxo1u3JIU/jdihglDdunXt9NNPL3TdN998s8BrKizqQhypE1wq5dszzzxT4LX999/f3n77bddRNVxa1ElVoy6FU97ONVHw4N0F69atW0Kea35fJxYtWpT3d6R9RtpfUWnxtlOLVB1HnSrjpSyvr3q/GllIdN2KFIBqEIx+/frle013pjW4gbbX3/FUmnmmO/GhI7ypAKwRIO+4446o01IezzUF7+oAX5wbcYl+rvkt1t84lTfWrFlTrHNt1apVUd9AoekUfKETVQo7+bxmBioglXS7slaW6fTu1lxyySURR/LRcIEaqUIjQuh4unOj0Tx0R/+vv/5yd8k08ka8lVa+aSQNjXSk6nNd9DTqjWo39EOruzonnniiG7GrLNLit7JMp0aFUxW7RhPSCF4a7joRzzW/88TbX2H7jLS/otIS3JwqnudRWZ9L9913nxt5SvsLN5qeRoLTCDsaLU7njb63M2bMsJtvvtmNjqORcv79739bvJVGnumuu0Z0mzhxoiuoaTs1z9I1Xk2w7rzzTnvwwQejTkt5PNcUZOi6pTxVjUY4yXKuJVo5rLTOtdQK58qB22+/3YYPHx71dhreMtKweqkumfJMVesaqk8uv/zyiOvpghlMdy80tLAK2Brq8LPPPnMXWjVTS8V809B/wapUqWINGza0U045xQUh+hHv06ePa1ZVlhI5z0Kpf4fG4lcAoaaNaiYUr3MNyU21XWqioiaLulGy3377he2/4fXh8Gg41yeeeMKd+6pN080DFQA1/HIqUY1faK2fmqJo2GgF8hraVvmnO/RqAorIXn31VfesIC1SjUR5PtcSEYFGklFHat3FjVZpT0TmVdPpzkFRaVCzj5JuV9Z5VhbpDK7NOOaYY+yggw6KenvdrdGdRRX+NEeC2hF7VZ6pnG8eNdfQncOzzz7bTYClwrRXK8S59v+pBkOd/pRH6iCoce733HPPuJ1rRfH7swtuVqB96g5ocfenbdUENFJags9/P87pkiiLc15NPb2bIiq8KXiN1jnnnOMKfApWNchBPAt/ZX3N6tWrl5sAUZ3nVVPYo0ePfGnhXPv/VFvtNT0r7EZcspxriVYOK2zbklzXaDqVZNT2/P+GJY7qUdptqDWDp4TOYB3Mm3XcWzf478JGu/GWBW9X1nlW1PtTVaJXnRhrOjXZldcOvqi2p4UJDlBKMtN7suRbpPevJgnBI994+9fEUcFVxeXtXNN59s9//tONHqLAQJ28w41uVZbnWlH8vk4Ev99I+Rxpf0V9Pt52CsRizVe/lPb1VeeQmt7l5ubaoEGDYi78BZ9LpXkeFUdZ/CYFS09Pz6sBCn3vnGvhb8SpVkITzyX7uea3WH/jFGh4gzcUdV3TwAXRDnBBoAFfHHHEEe5Zs+qGo5l2dWdGgqs0vb/VESlSBzFvn94xEvH9ea/rC6jOyLHQbLoaHUNtIb2h5GLhdeqSSB3CUinfivv+9cOkJlbFSU+qnmsKMi6++GLXztkLMiKNrJNI55rf1wndkfNm/I72XCju56PCY7jhb8tSaV5f1SxRtWI6p1588cW8medLei7F+5oVj9+kSO+dc83/G3GF5XeyO6AEv3HFPddiOudjmA8EKYgJ+wo3a9asvEnU/vzzz1KZRO2cc85x+9AMziXxxBNPuP1Ur169wKRZqZhvoW688Ua3T82sHu1kRkpnvCfsK60806RLF110Ud4Mr3/88UeJ01qW51pZT9inCfmKmrBv8+bN5XLCvuHDhwcyMzPdDMSxTOAVaunSpW6SP6Xlgw8+CJSnSQ41g7b3+ztx4sR8yzjX8p9zyqPs7Oyw37tkPdfKesK+SL9xpTlhH4EGopoZvGPHjm5Gzk8++aTAsl69erl9HHrooYHVq1fnu5BWq1bNLfv8888LbDds2DC3TOtoXY/20bJlS7fs1ltvjfsnddZZZ+UVTLZu3Zr3+siRI92XVzNuTp8+vcB2PXr0cHn27LPPRtz3qlWr3A+39v/TTz8Vmo5p06YFPvvss8CuXbsKXAxeeeWVQKVKldx+7r777kAi8DvfvvvuOzfza25ubr7Xd+zYERg4cKAr/Oh4yotQOr+0XMf98ssv817fsmVLXgGxW7dugVTLM50bl1xySdRBRiKda7FcJ3SdUn7ouhVq2bJlgSpVqrjtXn755bzXc3JyXD7qdRU4Q88z/b9Vq1ZuufJU63sGDRqUl8a//vorkAj8zjcVfitWrOi+R3q/xfXUU0+561woncdefu6zzz6B7du3B1Ipz3Rtee655wIbN24scJzvv/8+0LRpU7e/du3aFVhe3s+1YGeffbbb/qqrrkqpcy2WQEPXd+WZrlN+/cZpeYMGDdzyvn375lum/+v1vffeO9/vUXERaJRT999/f+Doo4/Oe3iBhr6E3mvXXnttge2aNGni1nv99dfDnqjHHHOMW16rVi13Mnfp0iWvAH3LLbcUeRda62obbevdUTz22GNjOrn99vfffwf2228/l6b69esHzj///ECHDh3yCrZPP/102O3at2/vlvfr16/IO8MHHnhgsS/mymNdOHSX+tRTTw00btw473O88MILCxQOUyXfnnzySfd6vXr1Ap07d3bv/6STTnL/995/7969i8xrHV/pUHqULr2mi3e4H6hkzzOt7+WN9qMfs3APBWqJfK5Fe53QdUrLdN0K58MPP8y7w6drXvfu3QPNmzfPO79+//33sNvNnTs3sOeee7r1tL62O+qoo9z/MzIywt6IiSe/8k3npe7ke4WOSOeRHqHfoxo1ari8bt26deDcc89157T+VtCs/emcmj17diDV8mzdunV5NSBt27Z171u114ccckjed0iF8OXLl4dNR3k910LPO68cMWHChCLTkEzn2pQpU/KVxerUqZP3/Qp+Pfj80PVd6+h67+dv3NixY/Nuvuj8VK25d55WrVo1MH78+JjeI4FGOeVFzYU9wp3EhQUawXeVdXKqelJf+OOPP979oBdF1ZhaV80wtK328dBDD7l9JooNGza4JhEqBOqHo3bt2u5i+u2330bcpjiBhne355FHHikyDQsWLAjcdNNN7g5Yw4YN3V1lpUUXT11Udccx0fiZb1OnTnVBsH5sdfHU/nS+6A6V7voVVSMk33zzjTu+0qHtla4+ffqEvesYL37mmffDFO13PhHPtWiuE8UpxEyePNkV/FSY0516rXvdddcFVqxYUWg6dBdZ62l9bafttZ/gO7mJxI98W7hwYbHOIz20bjBd21RTt++++7rfBRWSdU7r3Hr00UcT6rvnZ55p3XvuuSdwyimnBJo1a+aa/ui963xRjaVqJor6jSuP51qwxx57zK3TokWLYh0/mc610aNHR/19KirQKMlvnG6u6HdUtRsK7vSs/5ekqW2a/om+ZwcAAAAARMaoUwAAAAB8R6ABAAAAwHcEGgAAAAB8R6ABAAAAwHcEGgAAAAB8R6ABAAAAwHcEGgAAAAB8R6ABAAAAwHcEGgAAAAB8R6ABAIAP5s6da5dffrk1atTIKlWqZE2bNrU77rjDtm/fTv4CKJfSAoFAIN6JAAAgmQ0ePNiuu+46y8jIsPbt21u1atXsu+++s7Vr19opp5xiI0eOjHcSAaDMEWgAAFAC7733nl100UV27LHH2ocffmgNGjRwr69cudJat25tS5cutW+++cZOPPFE8hlAuULTKQAAYrRs2TK7+uqrrUmTJjZixIi8IEPq1q1rPXv2dH9/8cUX5DGAcodAAwCQsLZu3WpPPfWUtWvXzmrVqmVZWVmuUH/GGWfYu+++W2B91R7ccMMNtt9++7l+EjVq1HA1DYMGDbLdu3cXWP/33393/SqaNWvm9q0mT9r/aaedZq+//nqR6bvvvvts8+bN9uCDD7pjhapXr557XrhwYcx5AADJiqZTAICEtGTJEuvSpYvNnj3bqlSp4gKGPfbYw9UizJgxw2rWrGmLFi3KW3/SpEluffWLaNy4sR1zzDG2YcMGGzNmjOuQ3blzZxs+fLhVrFjRrT9r1iy3z40bN9oBBxxgLVq0sPT0dBeszJw50/bZZx/75ZdfIqZP+65fv74LgBYvXuy2DfXoo4/a7bff7gIjHRsAypOMeCcAAIBQubm5ds4557gg4+STT7a3337b9txzz7zlChzU2dqzY8cOO++881yQ8a9//cueeeYZy8zMdMsWLFhgnTp1sq+++srVQAwYMMC9/sQTT7gg44EHHrC77ror3/G3bdvmApfCfPrpp2491VpcccUVYdeZNm2ae1aABADlDTUaAICE89lnn9nZZ5/tagx+++0316SpMApEevTo4fpIKLBQM6hgH3/8sZ177rmWnZ3tOmmrWZWaR2k0qKlTp1qrVq2iTqOOp+MWx8CBA+3OO++M+hgAkMzoowEASDijRo1yzxrNqaggQ9Q8Si644IICQYaodkRNnDZt2mRTpkxxrx111FHu+dprr3W1HdHOd+HVeKjWRSPFhz7Uv8RLi3csAChPCDQAAAnnzz//dM8HHnhgsdZXvw1Rp+5w0tLS8pZ56952221uyNmJEye6vh3Vq1e3Nm3a2K233lpks6mcnBybP3+++3vvvfcOu84PP/zgmnRVrlzZ9QUBgPKGQAMAUC6pg7nmt/j555/t/vvvd/041ExLfTdUA6EJ+CJRzYiCDYlU4zJ06NC82pRwtSwAkOoINAAACUejRsncuXOLtX7Dhg3ds/pnROINMeut61Etxj333GNffvmlrVmzxgUIqoV44YUXbPTo0RFrSDw7d+4ssFz70UR+cv311xfrPQBAqiHQAAAkHDVlEhXWt2zZUuT6HTp0cM8ffPBB2L4Ww4YNs3Xr1rnO4JqtO5KMjAzXaVxD4Uqk4W01tK4eoqF2Q6njt/poaF9t27YtMv0AkIoINAAACefMM890I0EtX77cDVurGoJgCiZUA+HROqoF0fq33HJLXrMmryZD/S5Ek/lpxClRjcW8efMKHHvFihU2efJk97cm74tEo1ZJ//793XC8ok7gGj73lVdecel56aWXSpgTAJC8GN4WAJCwHcJVs6BgQP0pNDu4N2Hf9OnTC52wTwGCahLUl0LzbYSbsO/www93+1En8UMOOcR1Bl+1apX9+OOPbn6Mjh07utGoVMsRzh9//OGCIc0Mrk7rhx12mJs3Q/089t9/fzdyVqTO6QBQHhBoAAASlgrxqnn46KOPXH8N9YfYa6+9XKFeQ9927969wGziDz/8sKvt0Azf6oStIOKSSy6xK6+8Ml/QMGLECPeYMGGCW1czfdetW9f23Xdfu+yyy+zCCy/Mm/QvEs0g3rdvXxs7dqxLmwIMDbHbq1evvJoTACivCDQAAAAA+I4+GgAAAAB8R6ABAAAAwHcEGgAAAAB8R6ABAAAAwHcEGgAAAAB8R6ABAAAAwHcEGgAAAAB8R6ABAAAAwHcEGgAAAAB8R6ABAAAAwHcEGgAAAAB8R6ABAAAAwPz2/wBMPkdLjAw7AQAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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mF988YUsWLDAeh+VrrR+/XqZNm1aWNui0gAAAADEoBEjRsj9998f8n7jxo2TAw88MKxt0T0JAAAA0RXJmZuDCdTUIL/NzRANtDQAAAAAcay0tFRSU1PDWgctDQAAAIiuSM7cHOeDGlasWLHVrNB//F0Tn88nv/76q3z88cfSp0+fsLZLpQEAAACIET179tQDvpu8/vrregnVhen0008Pa7tUGgAAABBdjGlwrHv37psqDaqFIT09XfLz85u9b3JyshQWFsrxxx8vF198sfONUmkAAABAPBo2bJh4PB659NJL9RIvli1btulnNYnbiSeeqCd4i7SEHAg9ZsyYTVm+d911V2vvDgAAQEKJ3BwNvy3KjBkzZM6cOXFVYfij5557Ts4991yJhoTrnvT111/L3//+d31CRSuiCgAAAGhptpmgW1pCVRpqamrkrLPOks6dO+smq7feequ1dwkAACDxuCI4T0MgvtOTTPx+v2zYsEHq6uqs4yGcSqhKw4033igLFy6U999/X1599dXW3h0AAAAgLKob1m233SZTp06V+vp64/1ULxsVwepUwlQapkyZIo8++qicccYZcvjhh1NpAAAAiMf0pEittw369ttvZeTIkZtaF/Ly8iQ7Ozsi20qISoOa9OKcc86RTp06yUMPPdTauwMAAACE7fbbb9cVBvU59+6779afdSMlISoN1157rSxdulTefPNNXQMDAABAK2JG6BYxffp0GTBggDz99NNbTPgWCXFfaVDTZj/55JNyyimnyDHHHONoHap/2OZ9xCoqKlpwDwEAAIDtp8Yo7LrrrhGvMMT9PA3l5eU6u7ZDhw56PINT9957r+Tk5GxaunXr1qL7CQAAkJBjGiK1JIiBAwdKSUlJVLYV15WGq666SlatWiXjx483Tq+9ralLqgLStKxcubJF9xMAAADYXhdccIF8+eWXsnjxYom0uO6epMYweL1eeeyxx/SyuXnz5unbZ599ViZPniwFBQXy8ssvN7uelJQUvcSjOn/AWPavD347Rs2pXLjBvuJyc0Zw1u5dpaXZ9ie1c6axLCnT/rrmd8gwlhUt3Wgsy+yUZSwrmbrUvMFO5n3tNbSL/RjUNBrL6qsbxAnb82+XmWwsW76+2vG+pGSY11syr9hYltUtx9H5kb9rZ2evlXpNDutvfmxxtaPnaDs+lb+sM5al9so1lnXu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ZoNWLQ3qulQxq7HMFWxL+VsAAABAG3DWWWfJ888/L3feeafccsstxvu99dZbcuyxx+qUpKlTp25qUVCtDwceeKD88ssvcs0117TpZKRtQaUBAAAACe+HH36QSy65ZNNxWLx4sZSUlOjWhK5du276/ZtvvimdO3fe4nhdeeWV8sgjj0hSUpKMGjVKR7B++umnUlZWJvvuu6988sknkpaWFtPHmEoDAAAAEt6UKVN0y0AoS5cubXZQ86uvvioTJkyQH3/8URobG6VPnz5y+umny9VXX63np4h1jGlAWNSFc/nll+us4fT0dB0nNnDgQDn77LNlyZIlHN0/RK717t1b50arZdWqVQl9fNavXy//+te/5LTTTpN+/frp+D11DqnzR012s2zZMkkUr732mowYMULy8vL0t1ODBw+WcePG6T86iU4dA/Vt3XXXXaf7DasJkdQ3eWpyqKOOOkref//91t7FNmnMmDGb3mvuuuuu1t6dNkPNDaC+DR4+fLi0a9dOv++ob5EPO+wweeWVV1p799DK1Puw6rUfaulpSEE66aSTdPek8vJyqamp0d2Srr/++rioMCi0NMCxl156Sc455xypq6uTnXfeWXbYYQepra3VzXlz5syRd999V/785z9zhP/n4osvlieffFK/4ShqYFQizvfRRH378u9//1vPe7LTTjvJgAEDdM71jBkzpLi4WH94Vk3ABx98sMSzq666Sh5++GHxer0ycuRI3SdWzRKqmrTVB5uPP/445pu0wzF58uRN54CqKOy222763FDvMbNnz9a/v+CCC+SJJ55IiMk2t8XXX38t++2336YPOKH6YycK9UXNoYceqs+d/Px82WuvvfS5pN6L1TfDquLwn//8p7V3E2i71EBoYHtNnjw56Ha7gwUFBcEvvvhiq/KlS5cG16xZw4H9n48//ljVFIKXXXaZvlXLypUrE/r4XH755cE77rgjuGrVqi1+X1lZGTzllFP0MWrXrl1w48aNwXj15ptv6ueZmZkZ/P777zf9vri4OLjzzjvrsmuuuSaYyD799NPg8ccf3+z7zMsvvxz0eDz6OD3//POtsn9tTXV1dbBfv37Brl27Bo855hh9bO68885goqupqQkOHDhQH4+xY8cGGxoatjpus2bNarX9A2IBlQZsN5/PF+zZs6d+8502bRpHMITy8vJgt27dgr169QpW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pQEAAACAFZUGAAAAAFZUGgAAAABYUWkAAAAAYEWlAQAAAIAVlQYAAAAAVlQaAAAAAFhRaQCAKOrZs6e4XK5Ny0EHHRSV7b788stbbFctU6ZMicq2AQCxz9vaOwAAiej444+XzMxM2XHHHaOyvV69esmZZ56pf/7www9l3bp1UdkuACA+UGkAgFbw4IMP6laHaNlzzz31oowYMYJKAwBgu9A9CQAAAIAVlQYAaMbixYvF4/FIXl6e1NTUGI+R6l6kxgd88MEHLXIcly1bptenWiECgYA88sgjsssuu0h6erp07txZLrroItm4caO+b319vdx5550ycOBASUtLky5dusiVV14p1dXVvKYAgBZFpQEAmtGnTx854ogjpKysTP797383e4w+//xzmTNnjr7vYYcd1uLH8fTTT5cbbrhBunbtKoceeqiuRDz55JN68LSqGKhb1c1pwIAB+mdVuVGVjBNPPJHXFADQohjTAAAGV1xxhbz77rsyYcIEOf/887cqV79XLrnkEt060JKWL18uXq9X5s6dKz169NC/27Bhg+y9994ya9YsfataF5YsWSLt27fX5UuXLpXddttN/vvf/8q0adNk33335bUFALQIWhoAwEB9e6+6H/3000/y1VdfbVG2atUqefvtt3W3oXPOOScix1C1GjRVGBRVObj44ov1z7Nnz5Znn312U4WhKSFJtU4on376aUT2CQCQmKg0AECI1gZl/PjxW/xedRPy+Xzyl7/8RXJzc1v8GKpWhkMOOWSr3/fr10/fdu/eXXbaaSdj+Zo1a1p8nwAAiYtKAwBYqG/u1WDoN954Q4qKivTvGhoa5Omnn9Y/X3bZZRE5fmrQs6o4/JGa26Gp0tCcrKwsfVtXVxeR/QIAJCYqDQBgobofqfEMjY2N8tRTT+nfvf7663qeg/32208nG0XkzdntDqscAICWxF8dAAjh0ksv1fGrqtKgKg9NXZUi1coAAEBbQ6UBAEJQXYGOOeYYPU7gtttuk6+//lrPiXDcccdx7AAACYFKAwBsAzVpmnLffffp2wsvvLDZMQcAAMQjKg0AsA3U+IUhQ4bon5OSkuSCCy7guAEAEgaVBgDYRk0RqCeccIIUFBRw3AAACYO2dQDYBn6/X15++WX98+WXXx6xY9azZ08JBoPG8hEjRljLzzrrLL0AANCSqDQAwDZQyUnLly+XvffeWy/huvbaa/WcC2rG6euuuy7ir8H06dPl8ccf1z/Pmzcv4tsDAMQXKg0AYDB//nx54IEHZO3atfLhhx/quREefPDBFjleaq4HZdSoUVGpNCxdulSef/75iG8HABCfXEFbOzcAJLApU6bIgQceKMnJyTJw4EAZO3asHHvssa29WwAARB2VBgAAAABWpCcBAAAAsKLSAAAAAMCKSgMAAAAAKyoNAAAAAKyoNAAAAACwotIAAAAAwIpKAwAAAAArKg0AAAAArKg0AAAAABCb/weVmMZ8fa4MAgAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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RdTv7MePHy///Oc/ZdGiRXLVVVfZVsy7774rv/rVr2TgwIG2xbNmzZqOPVoAAACkBk+cFsRFzJO79e3bV2688Ua59tprbSPC9D589NFH9v/m52Zwhul9iDXmCQAAAEDbPvzwQ/n222/brO288842SapLzAidkZFh455MI8E0GG699VY7+OLvf/+7HaCx2267yR133EHjAQAAIM15PB67xGvbqWynnXaS+fPn2/ELpjHQ6sEHH5S//vWvba6z/fbby8yZM7tGo2H16tV2XINZysvL7c923HFH2W+//eTJJ5+00U9mmutnnnnGRkABAAAA2HxvvvmmffN/+umnb9JgaGXmYzCDnze2fPly+eqrr+Stt96SCRMmSKc1GkxXiLkk6V//+pcEAgE7ANoMwrjgggtsI8Ew4xvMYOnzzz9frr/+ehoNAAAAaSwB0zSkpGeffdb2pPz2t79ts25qr7/++iY/W7x4sZ3DwXxwn/BGg5l5zlx2ZGbYM9NSm1aNGbF95pln2uhVE/G0MdOQmDRpkrz88ssb8mOBVObPzlBrGVvr0aihpevVWs/s4c59BpbqMZalGSVqrTZYF9V6TeFmtTa42zC15s3TY0ONSJMjUtIRgZq1TT+11jJvVVQRp56sdl4i/frxhFbrc9hkjugVVVRgwHE/IiE9ctZXpseN2uPZfoBaC62oUmv+Ad3UWnh9dHGsrsc/EtJjbNt7TpY367HDA7L1546Lz+OTaLnifMNr9ThWAOntk08+sYFDWzI+YdCgQbLddtvZdWPhj3bw8/r1621jYZtttrE9CGauhpwcdxZ4z5497TgHAAAAAFvmu+++s+OE22Lel2u22morOwYi4Y0G02D45S9/aRsLP75uymXy5Mly4oknRrNLAAAApAquT4pKTU2NFBW1PemkmXTZBBK1xXywX1tbKwlvNJipqYcMGbLF6w0fPtwuAAAAALZMfn6+VFdXqwlJZtE+8M/NzZWENxqiaTAAAAAABpGr0endu7d88cUXW7yeWces2ykzQgMAAABd1dixY+2AYRPckyp22203WbFihbz33nubvY65rYld3X333bvGPA0ANk9g3hq1FmnQgwJCa9rujmzlK9CDCGqr9H0GInpaTfdMPR0nJ0vv5owEQtGn6mToiTQen14LVTiu1YzoqTuZO/ZVa4FZelqRPZ6cTL3mSNByHqsj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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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V2AX0wzss/MBqxJPQkKCx200PUcF8khtb9LUJF/ul952nl5ztz4j67L6WbIiK8fyxjVL7/WsXKNAv2aZ2Y/vmnevWXqv813j3zW+a5n7W8vs315GtuP/ofb6d81bbFfqUyfwuueee6RYsWJy/Phxt9vo7LuzZs0ycwj85z//EX8LltJRgYbrxjXjuxa4+PvkuvFdC2z8jYbuNbNdz3+9evWcgzE8Dei1KvRofn4g0BSgoUOHuk0FAteN75r/8TfKNeO7Frj4++S68V2zec9/Vif5AgAAAIKd7Xr+1eDBg82jzrC7fv1653q9G9CjRw9nmU4CfwAAAISSoO7518DdCtbVjh07TB5/2bJlpUyZMs71mr8fExOTYt8+ffrI2LFjJSIiQlq1amVKfy5evNiU1WzcuLEsWrTIlOYEAAAAQkVQB//Lli2TFi1aXHU7ze3X2XZT++6772TChAmyceNGuXz5slSpUkW6du0q/fr1k8jISB+dNQAAAOAfQZ3207x5czOF8tUWd4G/6tixo/z8889mVPb58+dl8+bNMmDAgJAN/KdPny7t27c3E1DkzZtXatasaWYc1oYPPPvnn3/kX//6lxkArneKPH2f7Hpt2rVrZybGK168uLkTl14ZXfB9yir+/cq8mTNnSpMmTczfpo5jq1y5splA8tSpU/wpZkBSUpLccMMNZs6eb775hmt2lc5YvU6pl1q1anHdruLbb781Y1E1LtPJwTQb5dChQ+JLTPJlI2+99ZYJXEePHi3XXHONrFy50gyM/uOPP8xAabi3detW+fHHH80fpzYm+R/n/2ijuWXLllK6dGmZNm2anDx50gQWOlB+xowZfJ34PvHvl5/p36R2kr344otmDJt2cA0bNkw2bdpk0lyRvjFjxsixY8e4TJnw8ccfm45Fiwa08Ew7YAcNGmRKy7/55pum82z58uVy8eJF8SlN+4E9HD16NM264cOHa9qX4/Dhw345p2Bw5coV5/NnnnnGUaFCBb+eT6B48803HXny5HEcOXLEuW7GjBnm+7R27Vq/nlsg4/uUNfz75R0ffvih+Rvds2ePl94xNO3bt89RoEABx+eff26u19dff+3vUwpoS5cuNdfpt99+8/epBI2///7bERER4Zg4cWKOHzuo036QOSVKlEizrkGDBubx4MGDXE4PAn2abn+ZN2+e6fkvWbKkc51O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WtuodOnS8uGHH8qhQ4dk8uTJ0rVrVzOwN3fu3Cbg16VQoULSpUsX2bBhg9SsWdObhwcAAACQDp/MalCwYEF59NFHzaKuXLliBgOHhYWZ4B8AAABAzsuRWQ20579w4cK2Dfx1EPSNN94oefPmNXMdtGrVytwdAQAAAHKSvaY084O3335bHnnkETMfwty5c+WLL76QBg0ayMWLF/19agAAALAZn6T94H/++ecfGTRokIwZM0aeffZZ52W56667uEQAAADIcfT8+9Cnn35q5jJ48sknfXkYAAAAIPSDf50rYNy4cdKtWzepXbu2hIeHm0HFI0aMyND+06ZNk+bNm0uRIkUkX758UqdOHRk9erSZj8AbVq5cKdWrV5fPP/9cKlSoYM5Pj/HTTz955f0BAACAgE37+fnnn2Xjxo0mEL7nnnskV67stT0mTZpkUmqyom/fvmZfDchbtmxp5h1YsmSJDBgwQObMmSMLFy6U6OjobJ3f4cOH5cCBAzJ06FB588035ZprrjGNFf3seh0odQoAAICg7vnX+v7169eXFStWpFj/3HPPmSD7+eeflwceeEDatGljSoBmR61ataR///5mUrFt27aZgbUZMXv2bBP4a8C/evVqWbBggcyYMUP+/vtvcwdBz33IkCFpPpfeVbjaMn36dOc+ycnJcu7cOfn444/Nud1+++3mOKVKlTKNAQAAACCoe/41+N2xY4fExsY6161du1YmTJhgetLvuOMO8/PixYvlm2++MRN+ZVX37t1T/JzROwnWzMIDBw40DRVL8eLFZeLEidK0aVMZP368aQBY5Unbt28vjRo1uup7lylTxvlc04lUixYtnOt0DEDjxo1l69atGTpXAAAAIGCD/y1btpje86ioKOc6DfK1V/zLL7+U+++/36TDVKlSxQyIzU7wnxWahrNmzRrzvHPnzmleb9KkiZQrV0727dsn8+bNk06dOpn12gjI7DwFmtbz+++/p1mvMx1T6hMAAABBn/Zz4sQJKVu2bIp1y5cvN7P+3nfffeZnTXvR3nUthZnTNmzYYB51sq1KlSq53aZhw4Ypts0qze1XepfDkpiYaNKKrGO4o9vEx8enWAAAAICAC/61Uo5rLr8Gsps2bZJbbrklRVpOiRIl5OjRo5LTdu3aZR7Lly/vcRvt+XfdNjvB/80332zSkz777DNT5UfTh06dOiX/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S31u375dpk+fbmb63bhxo1mns/2WK1fOzPKrs/0CAACEmjornpbwotFZ3v/kpUvSetl88zwhb25Jzk1ZdARo8K+Td1kBv6b6WAG/zuqrwb4usbGx3j4sAABAwNDAP6J4vqzvnxguZwvk6HRMsAmvfKs0j98K+P/55x8T7KsaNWo4A34dAwAAAAAgiIP/ypUry549e8xzDfrr1avnDPivu+46b5wjAAAAgEAI/nXwrpbu1F7+1157Te6++24JD+c2FQAAABBovBKla4+/5vd36NBBIiMjpVatWilm99WUH10PAAAAIIiD/++++y7FhF4nT550/vzxxx//7yDh4ebOgOvsvjrbr07yBQAAEGq0Wo8O2s2qU5eYKRgBGvxrb78uFs3/t4J/q0Fw/PhxM8uvLp999plzMrDq1avLH3/8kd1TAAAACChappNqPQhEXk/Or1Chglm0jr9l3759KRoD+nj06FHZunWrtw8PAACQo5KS/1flELBF8H/gwAEpU6ZMutvopF663HfffSn200YAAABAMItPuuzzYxQIj5BCERE+Pw5CX7aD//Lly0upUqVMHn/Dhg3NBF76WKJEiXT30wbD1RoNAAAA3uZISpak0xe89n7JJ733Xp4C/2G160l4rlw+PQ7sIdvBf+nSpU0v/o8//ihz5851rteeftfGgC6FChUSO2nevLn8/PPPbl8bOXKkDBw4MMfPCQAAOzs2bYvsHrRArsT7dkDt9FtaSrGYwl55L+3xJ/BHwAT/ms9/6NAhWb16tVlWrVpl0nn27t1rXps1a5Zz2ypVqjgbA/qolX/y5s0roWrixIkSHx+fYt2XX35p1rdr185v5wUAgF17/HMi8FeFIiOlWFSUz48DZFaYQ4v0e9mIESNk6NChUrZsWalWrZoJgLWqT2JiopkQzKIVfy5duiR2cuONN8rFixczVeVIr5/eNTlz5owULFjQp+cHAECounw8QdbVGOPz4yRE55I6cX2keL5onx8LmZN08YTsmtkwxbpK96+V8DzFsn0pgyVe83rymNb218D/rbfeMmU/Fy1aZO4IaP3/Tz75xDQItL2haUF2m/jr77//ljVr1kjXrl39fSoAAMBHgf/kLiUkLJz8fNik1Od7771n0nn69euXYn10dLQ8/vjjZk4ATXnRtKB//vknW8f666+/ZOHChc4yotu2bZMrV67I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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "for k in filename.keys():\n", " #if k!=\"ATLAS\": continue\n", @@ -240,14 +361,13 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "cb18973f-6f80-418a-b7b0-d7794080b8c5", "metadata": {}, "outputs": [], "source": [ - "from siren.SIREN_Controller import SIREN_Controller\n", - "from siren import math,detector\n", - "def plot_Aeff(data,controller,fid_vol,gamma,**kwargs):\n", + "import siren\n", + "def plot_Aeff(data,detector_model,fid_vol,gamma,**kwargs):\n", " nu_flag = data[\"primary_type\"]==14\n", " nu_momenta = np.squeeze(data[\"primary_momentum\"][nu_flag])\n", " # muon\n", @@ -271,8 +391,8 @@ " pos = math.Vector3D(pos)\n", " dr = math.Vector3D(dr)\n", " dr.normalize()\n", - " geo_pos = controller.detector_model.DetPositionToGeoPosition(pos)\n", - " geo_dr = controller.detector_model.DetDirectionToGeoDirection(dr)\n", + " geo_pos = detector_model.DetPositionToGeoPosition(pos)\n", + " geo_dr = detector_model.DetDirectionToGeoDirection(dr)\n", " ints = fid_vol.Intersections(geo_pos.get(),geo_dr.get())\n", " intersections.append(len(ints)>0)\n", " x,bins = np.histogram(nu_momenta[:,0],weights=np.array(intersections)*data[\"event_weight\"]/dphi_dE,bins=kwargs[\"bins\"])\n", @@ -283,14 +403,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "e799f4ea-6930-4120-96b7-10b4b5e02f8a", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "99999\r" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAvQAAAIiCAYAAACnu1wkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAABZoElEQVR4nO3dB3hUZfb48ZOQQoTQEekg2CgikCAKKMUGFsAOiqIiKqAUWSkr67LyBxZ13VDVVVFXUJcSVhQpUlREIhEW0CACghCwUBOKhADzf867v5udJJMwSSZz7535fp7nPjeZuTNzZzKTOffc8543wuPxeAQAAACAK0XavQMAAAAAio+AHgAAAHAxAnoAAADAxQjoAQAAABcjoAcAAABcjIAeAAAAcDECegAAAMDFCOgBAAAAF4uyewfgn7Nnz8q+ffskPj5eIiIieNkAAAAcxuPxyNGjR6VWrVoSGRm8vDkBvUtoMF+3bl27dwMAAADnsGfPHqlTp44ECwG9S2hm3nqDVKhQwe7dAQAAQB6ZmZkmAWvFbcFCQO8SVpmNBvME9AAAAM4VEeTyaAbFAgAAAC5GQO9w06ZNkyZNmkhiYqLduwIAAAAHivDocFy4oiarYsWKkpGRQckNAACAA2XaFK+RoQcAAABcjIAeAAAAcDECegAAAMDFCOgBAAAAFyOgL2Vz586Vnj17Sr169eS8886Tpk2byksvvSTZ2dml/dAAAAAIA0wsVcpefPFFadCggUyaNElq1Kgha9askWeffVY2bdokb7/9dmk/PAAAAEIcAX0pW7hwoVSvXj3n906dOol2Ch0zZkxOkA8AAAAUFyU3pcw7mLe0bt3arPft21faDw8AAIAQF5YB/datW2XKlCnSt29fad68uURFRUlERISMGzfOr9vPmTNHOnbsKJUrV5Zy5cpJixYtTLbd37r4zz//XGJiYqRRo0YlfCYAAAAId2FZcjNjxgxJSkoq1m2HDBlibqsHAZ07d5by5cvLihUrZMSIEaa8ZunSpRIXF1fg7dPS0szt+/fvz4yvAAAAKLGwzNA3a9ZMhg8fLrNmzZItW7ZInz59/LrdggULTDCuQXxKSoosWbJE5s2bJ9u2bTOZ/tWrV5va+IIcOHBAevToIY0bN5aJEycG8BkBAAAgXIVlhr5fv365fo+M9O+4Zvz48WY9cuRIadWqVc7l1apVk+nTp0uHDh1k6tSpJqivWLFirtsePXpUunbtKqdOnZJVq1aZUh0AAACgpMIyoC+OvXv3yrp168zPvXv3znd9+/btpW7durJnzx5ZtGiR9OrVK+e6rKws6d69u+zatctk8WvVqhXUfQcAAChNp8+elQwHzbFTOSZGIiMiJFwQ0Ptpw4YNZl2lShVp2LChz20SEhJMQK/bWgH9mTNn5N577zUHA1prf8kllwTqbwcAAGC75PSf5LnNG+ToaecE9Kk33CZVY2MlXBDQ+2nnzp1mrTO+FkQz9N7bqoEDB5ra++eff94E92vXrs25rkmTJgUOjNWsvi6WzMxMf3cVAAAgaJl5pwXz4SgsB8UWh9bAq8Jq33WwbN7ge/HixWatdfVXXXVVrmX9+vUF3teECRNMHb61WAcLAAAATqFlNgTz9iOgL2VaN68zw/patJd9QUaNGiUZGRk5i5byAAAAAHlRcuOn+Ph4sz5+/HiB2xw7dsysCyqjKYrY2FizTJs2zSxargMAAOB0yzreKJVjYm0fFBtOCOj91KBBA7MuLFNuXWdtGwhag6+LlvHkbYUJAADgNBrMh9OAVCeg5MZPLVu2NOuDBw/mGvTqLTU11ay9e9QDAAAApYmA3k916tSRxMRE8/Ps2bPzXa/95TVDr2Uy3bp1C9gfSMtttBuO9dgAAACANwL6Ihg9erRZT5w4MVeHGs3aDxgwwPw8aNCggJbGaLlNWlpazqRWAAAAgLcIj7ZbCTMajFsBuNqxY4ccOHDAZOFr166dc3lycrLUrFkz120HDx4skydPlujoaOnSpYtpY7l8+XI5cuSItGvXTpYtWyZxcXEB32erhl473gRi0C0AAEBJHczKkoSlH4b1pE5OiNeiwvXFTklJyXd5enq6WSzeEztZkpKSTOCupTBr1qyR7OxsadSokYwcOVKGDh0qMQEeVU2XGwAAABQmLDP0bkSGHgAAFDZjq07yFGyHT2XJ9auW5LqMDH1FMvQAAADwX3L6T/Lc5g3M2BrGGBQLAADg4sw8wTwI6B2OtpUAAKAgWmZz9HTwS20KEh8VLRWjo+3ejbBDQO9wtK0EAABuoMH82OYtJSqS8DLYwrLLDQAAQKha1vFGqRwT/LaRmpknmLcHAT0AAEAI0WA+XPvAhysCegAAABe2jLTaRgIE9A7HxFIAADgXLSPhBEws5RJMLAUAgPMy862WfOioLjPhPrFTuMZrDEMGAAAIgZaRiraR4YmAHgAAIATQNjJ8UUMPAADg8paRiraR4YuA3uEYFAsAgHs6zNAyEnZgUKxLMCgWAADnd5hhQGp4y2RQLAAAgP+ZeacF84BdGBQLAABchw4zwP8Q0AMAAJQQHWZgJwbFAgCAkECHGYQrAnoAAOC6LjN0mAH+h4De4WhbCQBwKid2mQHCEW0rXYK2lQAAp2XmWy350FHBPC0jYTfaVgIAANdwWpcZHZSqM6UC4YiSGwAAXMpps6TahQ4zCHcE9AAAuJAT69ft6jKjmfmoSDpxI3wR0AMA4DJOnSVVg/mqscEP6IFwx+EsAAAu47T6dUUNO2AfAnoAAFAi1LAD9qLkBgCAEMAsqUD4IqAHACAEUL8OhC9KblwwU2yTJk0kMTHR7l0BAACAA5Ghd7iBAweaxZp5DADgHHb1gXdSD3gA9iOgBwAgRPrAAwhPlNwAABAifeABhCcCegAAXN4Hnh7wQHgjoAcAwMXoAQ+AGvpStn37dnnxxRfl66+/ls2bN0vt2rVl165dvPMAIMTY1Qe+YnS0REWSnwPCGQF9Kfvuu+/ko48+kjZt2ojH45HDhw+X9kMCAGxAH3gAdiGgL2W33nqrdO/e3fz8+OOPy+LFi0v7IQEgLNjVMlLRNhKAkxDQl7JIToMCQMDRMhIA/icsi+62bt0qU6ZMkb59+0rz5s0lKipKIiIiZNy4cX7dfs6cOdKxY0epXLmylCtXTlq0aCGTJk2SbJsyRQAQTmgZCQC5hWWGfsaMGZKUlFSs2w4ZMsTcVg8COnfuLOXLl5cVK1bIiBEjZOHChbJ06VKJi4sL+D4DAJzZMlLRNhKAncIyQ9+sWTMZPny4zJo1S7Zs2SJ9+vTx63YLFiwwwbwG8SkpKbJkyRKZN2+ebNu2zWT6V69eLWPGjCn1/QcAOAdtIwHYLSwz9P369StWnfv48ePNeuTIkdKqVaucy6tVqybTp0+XDh06yNSpU01QX7FixQDvNQDAaS0jFW0jAdgtLAP64ti7d6+sW7fO/Ny7d+9817dv317q1q0re/bskUWLFkmvXr1s2EsACM8OM7SMBBDOCOj9tGHDBrOuUqWKNGzY0Oc2CQkJJqDXbUsa0GdlZZnFkpmZWaL7A4BAocMMADgLAb2fdu7cadb16tUrcBvN0Htvq06cOGEy9urHH380v8+dO9f8npiYKPXr1/d5XxMmTJCxY8f6u3sAEBR0mAEA5yGg99PRo0fNWttUFkQHy+bNpv/2229y11135drO+n3mzJmmdaYvo0aNkmHDhuX8rvdpHTAAgF3oMAMAzkNAX8oaNGggHo+nyLeLjY01CwCgYHSYAQACer/Fx8eb9fHjxwvc5tixY2ZdoUKFgL23pk2bZpYzZ84E7D4BIJDoMAMA9iJDX4RMu9JBrwWxrrO2DYSBAweaRUtuaIUJwInoMAMA9grLiaWKo2XLlmZ98ODBXINevaWmppq1d496AAAAoDSRofdTnTp1TFca7UU/e/Zs+eMf/5jrep0lVjP0WvferVu3gP2BKLkB4KQ+8L56wAMA7EVAXwSjR4+Wnj17ysSJE6Vr1645mXjN2g8YMMD8PGjQoICWxlByAyAv+sADALxFeIrTgsXl1q9fnxOAqx07dsiBAwdMFr527do5lycnJ0vNmjVz3Xbw4MEyefJkiY6Oli5dupg2lsuXL5cjR45Iu3btZNmyZRIXFxfwfbZq6DMyMgI66BaA+zLzrZZ8KEdP2zNLqy+pN9wmVenKBQBiV7wWFa4vdkpKSr7L09PTzWLxnqnVkpSUZAJ3LYVZs2aNZGdnS6NGjWTkyJEydOhQiYmJCei+UnIDwMl94LVtZMXoaLt3AwDCWlhm6N2IDD0AdTArSxKWfuioHvA96/ie8RoAwk0mGXoAgJv6wGtmPiqSZmkAYLewLLkBgFBCH3gACG8E9A5HDT3gPHa1jFS0jQQA5EUNvUtQQw84gxNbRtJlBgDCO16j+BEAipCZd1owDwAAAT0AuLRlpKJtJACAgN4FNfRNmjSRxMREu3cFgMNYbSPpNAMA4Y0aepeghh5wZg94u1pGKtpGAoCz0IceAFyIlpEAALtRcgMAAAC4GAE9AAAA4GJMLOVwTCwF5MakTgAA5MagWJdgUCzApE4AAGfLZGIpACgYkzoBAOAbNfQAXIFJnQAA8I2AHgCKgUmdAABOwaBYAK7FpE4AABDQA3AxJnUCAICSG1e0rWzSpIkkJibavSsAAABwIEpuHG7gwIFmsdogAeHaB/7wqaygPyYAAG5AQA/Ab8npP8lzmzfI0dPBD+gBAIBvdLkB4Bf6wAMA4EwE9ABc2Qde20ZWjI62ezcAALAdAT0A16EHPAAA/0MNPQDX9YHXzHxUJPkIAAAUAT2AYqMPPAAA9iPFBQAAALgYAT0AAADgYgT0DsdMsQAAACgMNfQOx0yxcMIsrYqZWgEAcCYCesAlmKUVAAD4QskN4ALM0goAAApCQA+4gNNmaVXM1AoAgDMQ0AMoMmZqBQDAOaihD4Lt27fLU089JZ9//rmULVtW7r77bnnhhRekXLlywXh4hCi7ZmlVzNQKAIBzENCXsoyMDOncubPUqlVL5syZI4cOHZJhw4bJr7/+KvPmzSvth0cIY5ZWAACgCOhL2auvvir79++X1NRUOf/8881lcXFxcscdd8g333wjrVu35p0IAACAYqOGvpQtWrTIZOitYF7ddtttUr58efnoo49K++EBAAAQ4sIyQ79161ZZunSpyZDrsmXLFjlz5ow8//zz8uyzz57z9lo6ozO4bty4UU6dOiWNGzeW++67T4YOHSrR0dG5tk1LS5MHHngg12VRUVFy8cUXm8eFezCpEwAAcKKwDOhnzJghSUlJxbrtkCFDzG01KNfMu2baV6xYISNGjJCFCxeaAwUtqbEcPnxYKlWqlO9+KleubOrp4Q5M6gQAAJwqLEtumjVrJsOHD5dZs2aZLHmfPn38ut2CBQtMMK9BfEpKiixZssQMbN22bZs0b95cVq9eLWPGjCn1/UdwMakTAABwsrDM0Pfr1y/X75GR/h3XjB8/3qxHjhwprVq1yrm8WrVqMn36dOnQoYNMnTrVBPUVK1bMycQfOXIk331p5v6iiy4q4TNBMDCpEwAAcLKwzNAXx969e2XdunXm5969e+e7vn379lK3bl3JysoyA2Etl112Wb5aea3X/+GHH8x1QFExqRMAAJBwz9AXx4YNG8y6SpUq0rBhQ5/bJCQkyJ49e8y2vXr1Mpd169ZNxo4da1pXVq9e3VymtfbHjh2Tm2++OYjPAIHEpE4AAMApCOj9tHPnTrOuV69egdtoht57W/XYY4/JlClTpHv37qYUR0ttdGIp/V0PAAqimX5dLJmZmf7uKoKASZ0AAIBTUHLjp6NHj5p1uXLlCtxGB8vmDb61w412walQoYLceeed8uSTT0qPHj3k3XffLfTxJkyYYOrwrcU6WAAAAAC8kaEPAu05v3jx4iLdZtSoUSaTb9GDBIJ6AAAA5EVA76f4+HizPn78eIHbaF280mx8ScXGxppFJ7DSRQfSAgAAAHkR0PupQYMGZq2DXgtiXWdtGwgDBw40i2borVaY4cqumVoPn/rfWAYAAACnIaD3U8uWLc364MGDZtCrr043qampZu3dox6BwUytAAAAvjEo1k916tSRxMRE8/Ps2bPzXa+zxGqGXstktFVloGi5TZMmTXIeOxwxUysAAEDBCOiLYPTo0WY9ceJEWb9+fc7lmrUfMGCA+XnQoEEBLY3Rcpu0tLScSa3CkdNmatWJnSpGR9u9GwAAAEaEx+PxSJjRYNwKwNWOHTvkwIEDJgtfu3btnMuTk5OlZs2auW47ePBgmTx5skRHR0uXLl1MG8vly5fLkSNHpF27drJs2TKJi4sL+D5bNfQZGRkBGXTrJgezsiRh6YfipFlae9apb/euAAAAh8m0KV6LCtcXOyUlJd/l6enpZrF4T+xkSUpKMoG7lsKsWbNGsrOzpVGjRjJy5EgZOnSoxMTEBHRf6XLjrJlaNTMfFcmJLQAA4BxhmaF3IzL0uTP0qTfcJlVjgx/QAwAAOC1eI9UIAAAAuBgBPQAAAOBiBPQOR9tKAAAAFIaA3uFoWwkAAIDChGWXGxRvciftB2+Hw6fydxsCAADAfxHQ45yS03+S5zZvcNTkTgAAAPgvSm4czu4aes3ME8wDAAA4FwG9w9ldQ69lNk7LzOtsrTrBEwAAAAjo4TIazI9t3pLZWgEAAP4PNfQosmUdb5TKMfbM0qqZ+ahITiwBAABYCOhRZBrMV421J6AHAABAbqQ6AQAAABcjoHc4u7vcAAAAwNkI6B3O7i43AAAAcDYCegAAAMDFGBTrMoeysiQ7Kytoj3f4VPAeCwAAAEVHQO8y165YJJHnnWf3bgAAAMAhKLkBAAAAXIyAHkWeqVUndwIAAIAzENA7nJPaVmowP7Z5S2ZqBQAAcJAIj8fjsXsncG6ZmZlSsWJFqff+W7K8W08zW2uwaWY+KpJjQAAAgMLitYyMDKlQoYIEC4NiXUiD+aqxwQ/oAQAA4DykWwEAAAAXI6AHAAAAXIyAHgAAAHAxAnoAAADAxQjoAQAAABcjoAcAAABcjIDe4Zw0sRQAAACch4De4QYOHChpaWmybt06u3cFAAAADkRADwAAALgYAT0AAADgYgT0LvNZ525SOSbG7t0AAACAQxDQu0yV2FiJjIiwezcAAADgEAT0pWz79u3y+OOPS6tWrSQ6OloaNGhQ2g8JAACAMBJl9w6Euu+++04++ugjadOmjXg8Hjl8+LDduwQAAIAQQoa+lN16662Snp4u8+fPlyuvvLK0Hw4AAABhhoC+tF/gSF5iAAAAlB7XR5tbt26VKVOmSN++faV58+YSFRUlERERMm7cOL9uP2fOHOnYsaNUrlxZypUrJy1atJBJkyZJdnZ2qe87AAAAIOFeQz9jxgxJSkoq1m2HDBlibqsHAZ07d5by5cvLihUrZMSIEbJw4UJZunSpxMXFBXyfAQAAgEBxfYa+WbNmMnz4cJk1a5Zs2bJF+vTp49ftFixYYIJ5DeJTUlJkyZIlMm/ePNm2bZvJ9K9evVrGjBmT6zZvvfWWyf6fa5k7d24pPVsAAAAgxDL0/fr1K1bN+vjx48165MiRpqWkpVq1ajJ9+nTp0KGDTJ061QT1FStWNNf17NlT2rZte877rl27dhGfBQAAABCmAX1x7N27V9atW2d+7t27d77r27dvL3Xr1pU9e/bIokWLpFevXuZyDeyt4B4AAABwAteX3BTHhg0bzLpKlSrSsGFDn9skJCTk2hYAAAAIuQy9DiQNBK07X758uQTLzp07zbpevXoFbqMZeu9ti+vEiRMmy69+/PFH87tVY5+YmCj169f3ebusrCyzWDIzM0u0HwAAAAhNJQroV61aFbCAPpiOHj1q1tqmsiA6WDYQgfRvv/0md911V67LrN9nzpxp2m36MmHCBBk7dmyJHhsAAAChr8Q19DfddJNp81hcEydONO0hQ1WDBg3E4/EU+XajRo2SYcOG5fyuBxbWWQMAAAAgYAH9BRdcINdee22xb6+tIIMtPj7erI8fP17gNseOHTPrChUqiB1iY2PNMm3aNLOcOXPGlv0AAABACA+Kvfjii6VmzZolPiDQ+wl21lxpF5uCWNdZ29pl4MCBkpaWltOVBwAAAAhYhv7777+XktJacV2CqWXLlmZ98OBBM+jVV6eb1NRUs/buUQ8AAAA4TVi2raxTp47pMKNmz56d73qdJVYz9Fry0q1bN7GTlts0adIkZ38BAAAACfeAXo0ePTpnUO769etzLtes/YABA8zPgwYNsn0iKUpuAAAAUJgITzFasOzfv1/27dsnjRo1ymnvmLctpE7IdM0110hp02DcCsDVjh075MCBAyYLX7t27ZzLk5OT89X7Dx48WCZPnizR0dHSpUsX08ZS++EfOXJE2rVrJ8uWLZO4uDhxAu1yowcXGRkZtg3UBQAAgPPitSLV0J8+fVoeffRReeedd8zvMTEx8thjj5kaeO/AVwdxdurUKSidWfSFS0lJyXd5enq6WSzekzRZkpKSTOCuZS1r1qyR7Oxsc5AycuRIGTp0qHl+AAAAgJMVKaDXbPYHH3wgf/nLX6R169by2Wefmct0vXjxYqlRo4YEW8eOHYvV591y9913m8WpaFsJAACAgJXcNGvWTO677z4z6ZF3Nr5Hjx4mG79kyRJp3LixyZhfffXV9E4PIEpuAAAAnC3TppKbIg2K1RaPGqh70w4sX331lVSpUsWUr3gPMAUAAADgoIC+WrVq8uuvv+a7vGrVqrJy5Upp2rSpqZ3XgaUIDNpWAgAAIGAlN7fffruULVvWZ+92derUKbnnnnvk3//+t0RERFByE0CU3AAAADhbphtKbnr37m3KbrRXuy/aFWbevHnSv39/qVevXqD2EQAAAEAg+9Aj+MjQAwAAOFumGzL0AAAAAJyFgN7hGBQLAACAoJbc6Gyyc+bMMZ1u9u3bJydPnvT9wBERdMMpAkpuAAAAnC3TppKbIs0Uey779++XG264QTZt2nTO2Vs1oAcAAADgoID+mWeekY0bN5rZYp944gm56KKLJD4+PpAPAQAAAKC0AvqPPvpIatSoIWvXrjUzxwIAAABw0aDY33//Xdq1a0cwH0AMigUAAEDQAnotsdGgHoEzcOBASUtLk3Xr1vGyAgAAoHQD+kceeURWrVol6enpgbxbAAAAAMEI6AcNGiS33HKLdO7cWZYsWSJnz54N5N0DAAAAKM1BserVV1+Va6+9Vrp16yZRUVFSs2ZNiYyM9Nm2cseOHYF+eAAAACCsBDSg37Nnj3To0MGstQ99dna27N692+e29KEHAAAAHBbQjxgxwgTw7du3l2HDhplBsuXLlw/kQwAAAAAorYD+008/lfr168uyZcskNjY2kHcd1m0rdTlz5ozduwIAAIBw6EPfpk0bgvkAom0lAAAAghbQN2nSRA4dOhTIuwQAAAAQrID+ySeflM8++0y+/fbbQN4tAAAAgGAE9Pfff78MHz7c9KHX9pUFdbgBAAAA4MBBsWXKlMn5ecCAAYVuq20rT58+HciHBwAAAMJOQAN67T1fGtsCAAAACEJAf/bs2UDeHQAAAIBg1tADAAAACC4CegAAAMDFCOgdTmeJ1f7+iYmJdu8KAAAAQi2gHz9+vHz88ccl2gG9vd4PfGOmWAAAAJRaQP/ss8/KvHnzSnIXMnfuXBkzZkyJ7gMAAAAIV5TcAAAAAOHctlIz7KtWrSr27Q8cOFDSXQAAAADCVokD+mPHjpmlJHTWWAAAAABBDuh37txZkpuHBT2DMWvWLPnmm2/M2YiGDRvKww8/LE899ZRER0fbvXsAAAAI54C+fv36gduTEPXiiy9KgwYNZNKkSVKjRg1Zs2aNGUy8adMmefvtt+3ePQAAAIR7yQ0Kt3DhQqlevXrO7506dRKPx2M6+1hBPgAAAFBcdLkpZd7BvKV169ZmvW/fvtJ+eAAAAIQ41wf0W7dulSlTpkjfvn2lefPmEhUVZQbZjhs3zq/bz5kzRzp27CiVK1eWcuXKSYsWLUzmPDs7u9T2+fPPP5eYmBhp1KhRqT0GAAAAwoPrS25mzJghSUlJxbrtkCFDzG31IKBz585Svnx5WbFihYwYMcKUyixdulTi4uICur9paWnmMfv37y8VKlQI6H0DAAAg/Lg+Q9+sWTMZPny46SSzZcsW6dOnj1+3W7BggQmsNYhPSUmRJUuWmFlvt23bZjL9q1evzjeD7VtvvWWy/+datLONL9rlpkePHtK4cWOZOHFiQJ4/AAAAwpvrM/T9+vXL9XtkpH/HKOPHjzfrkSNHSqtWrXIur1atmkyfPl06dOggU6dONUF9xYoVzXU9e/aUtm3bnvO+a9eune+yo0ePSteuXeXUqVNmIi4t7wEAAAAk3AP64ti7d6+sW7fO/Ny7d+9817dv317q1q0re/bskUWLFkmvXr3M5RrYW8F9UWRlZUn37t1l165dJvNfq1atADwLAAAAoJRLbrQu/fvvvzc/v/POO3Lw4EFHvOYbNmww6ypVqpiJnnxJSEjItW1xnTlzRu69915zAKEHB5dcconfBwGZmZm5FgAAACCoAb12c8nIyDA/P/TQQ7Jjxw5xAmuG23r16hW4jWbovbctroEDB5p6fR1oq8H92rVrc5bCgvQJEybknBHQxdofAAAAIGglN1pL/uGHH5rJk3QypV9++UV2795d4PaFBdiBpPXsqrA6dh0sq0qaGV+8eLFZay1+3kG2K1euNC0zfRk1apQMGzYs53fdD4J6AAAABDWgf/LJJ+WZZ54xHV20+4sOKi2MZrBDjdbNF0dsbKxZAAAAANsCem0nqZ1dtJ3k3XffLc8//7xp2Wi3+Ph4sz5+/HiB2xw7dsys7e4VP23aNLOE4sEOAAAAXNDlpmnTpmZ58MEHTUeZggahBlODBg3MWrvYFMS6ztrWLlqDr4uW3BSnww4AAABCW9C63HTq1Mn2bLelZcuWZq1ddwoa9JqammrW3j3qAQAAAKcJyy43derUkcTERPPz7Nmz812vveI1Q6817N26dRM7ablNkyZNcvYXAAAACFpAb3W50YGh3l1uClqCafTo0WatA3bXr1+fc7lm7QcMGGB+HjRokO1lLlpuk5aWljMRFgAAAOAtwqORdil58cUXTZcb7XDjj+IM/NRg3ArAlZ4FOHDggMnC6wGFJTk5WWrWrJnrtoMHD5bJkydLdHS0dOnSxbSxXL58uRw5ckTatWsny5Ytk7i4OHECq4Zez3g4pXQJAAAA9sdrru9yoy9cSkpKvsvT09PN4j3zal5JSUkmcNeyljVr1kh2drY0atRIRo4cKUOHDpWYmBixG11uAAAAYFuG3pvW0P/pT39yRJcbNyJDDwAA4GyZNmXoS7WG3tvMmTPNTKevvfaa9OvXT2644QbZtm2buW7u3LmydevWYO0KAAAAEDJKvQ+9RQfGXnfddbJv3z5p3ry5aQt59OhRc53WrX/yySfyxhtvBGt3AAAAgJAQtAz9kCFDzAytP/74o3z55Zem642lY8eOpsUl8qNtJQAAABwR0GsW/s9//rNccMEF+breaPeZvXv3BmtXXIW2lQAAAHBEQK9BfGSk74fTNpPnnXdesHYFAAAACBlBC+ivuuoqMyDWl3fffVeuueaaYO0KAAAAEDKCNihWe9Bfe+210rZtW7nrrrtMxl6724wdO9aU43z11VfB2hVXoQ89AAAAHNGHXn399dcyYsQIWb16tZkVVktwrr76annppZckMTExWLvhSvShBwAAcLZMm/rQBzWgt5w8eVIOHToklSpVonbeTwT0AAAAzpZpU0AftJIbb2XLlpVatWrZ8dAAAABASIkKdmZ+06ZN8p///Mcs06dPD+bDAwAAACGn1AL63377LSdwt5Zt27bJ2bNnc7YhoD83BsUCAACg1Gvof/jhh3zB+6+//pprG+thdCBsw4YNpWnTprJgwYKSPnTYoIYeAADA2TLdWEOvHWo2b94sJ06cyLnM+/igatWqcvnll8t3330n+/fvl9TUVLnssstMDT0AAAAAmwP6tWvXmn7yZcqUkYsvvlhatGhhAnhrbQ187dChgwnoW7ZsGYBdBgAAABCQgD4mJkays7OlWrVq8oc//EEefPDBktwdAAAAgCKKlBLYsmWL3HLLLfLLL7/Iww8/bEpwvvnmm5LcJQAAAIBgBfQ6uPXf//63fPLJJ6bkRktwrrzySunXr58psQEAAADg4IDecuONN5rBsS+88IKUL19e3nzzTRPg//3vf5czZ84E4iHCum1lkyZNJDEx0e5dAQAAQKi2rczbf37EiBHyzjvvmN8vueQSOX78uKSnpxPclwBtKwEAAJwt06a2lQHJ0Hs7//zzZebMmfLVV19JQkKCfP/997Jnzx5z3fbt2wP9cAAAAEBYC3hAb2nTpo2kpKTIG2+8ITVq1DD96Zs1aybDhw83Ry8AAAAAHBzQWx566CEzk+zQoUNNUP/yyy/LRRddJK+99lppPzQAAAAQ8gJeQ18YLb8ZMmSILF26VCIjI+X06dPBemjXo4YeAADA2TJDpYa+MJdeeqksXrxYkpOTpUGDBsF8aAAAACAkBTWgt3Tv3l3S0tLseGgAAAAgpNgS0KuYmBi7HhoAAAAIGbYF9AAAAABKjoDe4ZgpFgAAAI7pcoPio8sNAACAs2WGQ5cbAAAAAIFFQA8AAAC4GAE9AAAA4GIE9AAAAICLEdCXsvnz50v79u2lWrVqEhsbKxdeeKEMGzZMDh8+XNoPDQAAgDAQZfcOhLpDhw5Jx44d5Q9/+IMZ9bx582YZO3asbNy4UZYvX2737gEAAMDlCOhLWb9+/XL9rsF92bJlpX///rJ7926pV69eae8CAAAAQhgBvQ2qVKli1tnZ2XY8PAAAQEB5zp6WM6cyHPOqlomtLBER4VNZ7vqAfuvWrbJ06VL55ptvzLJlyxY5c+aMPP/88/Lss8+e8/Zz5swxs7FqCcypU6ekcePGct9998nQoUMlOjo6YPup+6QB/LfffmtKbrp16yaNGjUK2P0DAADYIXNnsuxPfU7OZh91zB+g4e2pElW2qoQL1wf0M2bMkKSkpGLddsiQIea2UVFR0rlzZylfvrysWLFCRowYIQsXLjQHCnFxcQHZz6pVq5pZw9QNN9wg//rXvwJyvwAAAHZm5p0WzIcj15+LaNasmQwfPlxmzZplsvN9+vTx63YLFiwwwbwG8SkpKbJkyRKZN2+ebNu2TZo3by6rV6+WMWPG5LrNW2+9JREREedc5s6dm+/xVq1aJV9++aW88sorkpaWJrfeeqvJ2gMAALiVltkQzNsvKtQGnUZG+neMMn78eLMeOXKktGrVKudybS85ffp06dChg0ydOtUE9dqdRvXs2VPatm17zvuuXbt2vsuuuOIKs7766qvNz3o/ycnJcuedd/q1vwAAAEBIBvTFsXfvXlm3bp35uXfv3vmu177xdevWlT179siiRYukV69e5nIN7K3gviT0AEIz+du3by/xfQEAADhJ/ZuXSWRsZdsHxYaTsAzoN2zYkNNtpmHDhj63SUhIMAG9bmsF9IGipTcej8dMMgUAABBKNJgPpwGpThCWAf3OnTvNurAe8Jqh9962uG688Ubp0qWLNG3a1MwUqwcIL7zwglx++eXSo0ePAm+XlZVlFktmZmaJ9gMAAIQuu9pGns1i5nsnCMuA/ujR/47ELleuXIHb6GDZQATSbdq0kXfffTfnwKBBgwYyYMAAGTZsmMTExBR4uwkTJpj2lgAAAG5rG4ngCsuAPpi0H74uRTVq1CgT9Fv0wMI6awAAAKBoG4mwDejj4+PN+vjx4wVuc+zYMbOuUKGC2EHLc3TRSa90ocUlAABwetvIyOh4KRNT8gYiKJqwDOi17EXpoNeCWNdZ29pl4MCBZtEMfSA67AAAgNCoX3daDbsG89UTxkpEZFiGl7YKy1e8ZcuWZn3w4EFT2+6r001qaqpZe/eoBwAAcHr9ul1tIzUzTzBvj7AM6OvUqSOJiYmmF/3s2bPlj3/8Y67rdZZYzdBryUu3bt3ETpTcAADgTE6tX6dtZPgJy4BejR492sz8OnHiROnatWtOJl6z9tqFRg0aNMj2MhdKbgAAcG65i+OCeWrYw1KER2c4crH169fnBOBqx44dcuDAAZOFr127ds7lycnJUrNmzVy3HTx4sEyePFmio6NNr3htY7l8+XI5cuSItGvXTpYtWyZxcXHiBFYNfUZGhm0DdQEAcBInlrs4oYa9QsOedu9K2Mq0KV6LCoUXLiUlJd/l6enpZrF4T9JkSUpKMoG7lrWsWbNGsrOzpVGjRjJy5EgZOnRooX3ig4WSGwAA3FPuYlf9uqKGPXy5PkMfLsjQAwDwP6dPHpSd8xMclyG/8I71DAwNY5k2Zegjg/ZIAAAAIYqWjbCT60tuAAAAFOUuCFcE9A5HDT0AAP6hXSPCFSU3DqdtK9PS0kzPfAAAACAvAnoAAADAxSi5AQAArpvYSSd1AvBfBPQORw09AMCpmNgJcAb60LsEfegBAE7LzP84r5WjJnZqeHuqRJWtavduIIxl0oceAAC4hZbZOCmY1z7wOlMqEI4YFAsAAFyNSZ0Q7qihBwAArp7YSTPzEZGENAhfvPsBAHApuzrMFNRlhomdAHsQ0DscXW4AAL7QYQaAhS43LkGXGwCAkzvMKLrMINxl2tTlhgw9AAAunFTJacE8XWYA+xDQAwBQDJS8/A9dZgB7EdADAFCMzPz+1OcclSW3q8OMossMYC8CegAAQmBSpej4BrRuBMIUE0sBAOBilLsAIEPvcLStBAB3YFIlAHahbaVL0LYSAJzj9MmDsnN+Qq7LaNkIINOmtpWU3AAAAAAuRkAPAAAAuBg19AAAV7JrUidrYicAcAoCegCA6zCpEwD8DyU3AABXceKkTgBgJwJ6AICrOG1SJ6sXvM6WCgB2IKAHAKAkX6TR8VI9YSyztAKwDTX0DsfEUgDg3EmdlGbmIyL5OgVgHyaWcgkmlgKA/2JSJwBOlWnTxFKkFAAARUbLSABwDgJ6AECR0DISAJyFQbEAAL/RMhIAnIeAHgDgN1pGAoDzENADAFyLlpEAQA190Jw+fVpatWolmzdvlvfee0/uvfde3n8AQgItIwHAXgyKDZKkpCTZv39/sB4OAIJG+79Hla3KKw4ANiGgD4L09HQZO3asTJ06VR588MFgPCSAEGdX28izWYeD/pgAgMIR0AfBkCFD5LbbbpNrrrkmGA8HIMTRNhIAEDKDYrdu3SpTpkyRvn37SvPmzSUqKkoiIiJk3Lhxft1+zpw50rFjR6lcubKUK1dOWrRoIZMmTZLs7OyA7ePixYtl6dKl8sILLwTsPgGEL9pGAgBCKkM/Y8YMU5te3Ky53lYPAjp37izly5eXFStWyIgRI2ThwoUmCI+LiyvR/p08eVIGDRokzz33nNSsWVN27dpVovsDAKe1jdQuM2ViKtq9GwAQ1lydoW/WrJkMHz5cZs2aJVu2bJE+ffr4dbsFCxaYYF6D+JSUFFmyZInMmzdPtm3bZjL9q1evljFjxuS6zVtvvWWy/+da5s6dm3Ob8ePHS0xMjDz11FMBf+4AYDdaRgKAM7g6Q9+vX79cv0dG+nd8ooG2GjlypGklaalWrZpMnz5dOnToYAawalBfseJ/M089e/aUtm3bnvO+a9eubdY//fSTKd/Rg43jx4+byzIzM836xIkTkpGRkXPfAODGtpGamY+IdPXXCACEhLD7T7x3715Zt26d+bl37975rm/fvr3UrVtX9uzZI4sWLZJevXqZyzX4LkoAvnPnTsnKypI777wz33WPPPKIydofO3asRM8FABRtIwEgvIVdQL9hwwazrlKlijRs2NDnNgkJCSag122tgL6orrjiClm5cmWuy3755Rdzf5r5v/766wu9vR4M6GKxsvsAwrdlpKJtJABAwj2g18y5qlevXoHbaIbee9viqFSpkumg480aFNukSRNT1lOYCRMmmN71AJyFlpEAAKdx9aDY4jh69L/dIbRNZUF0sKzdWfFRo0aZOntr0TMGAOxFy0gAgBOFXYbeTg0aNBCPx+PXtrGxsWYB4BxOaxmpaBsJAAi7DH18fLxZW51nfLEGq1aoUEHsNm3aNFOik5iYaPeuAHAY2kYCAMIyQ69ZclVYCYt1nbWtnQYOHGgWLf+hzSXgPHa1jFS0jQQAhGVA37JlS7M+ePCgGfTqq9NNamqqWXv3qLczQ6/LmTNn7N4VAD7QMhIAYLewK7mpU6dOTvnK7Nmz812vs8Rqhl7r17t16yZ20+x8WlpaTu98AAAAIKwDejV69Giznjhxoqxfvz7ncs3aDxgwwPw8aNAgSlwAAADgeBEef9uuOJAG41YArnbs2CEHDhwwWfjatWvnXJ6cnCw1a9bMddvBgwfL5MmTJTo6Wrp06WLaWC5fvlyOHDki7dq1k2XLlklcXJw4hVVDry0snTBYFwhHp08elJ3zE3Jd1vD2VIkqW9W2fQIAOIdd8VqU21+0lJSUfJenp6ebxeI946olKSnJBO5an75mzRrJzs6WRo0ayciRI2Xo0KESExMjTkANPZAbs7QCABBCGfpwQoYecOYsrWToAQB2x2thWUMPwH2YpRUAAN8I6B2OiaWA/2KWVgAAfCOgdzjaVgLOxCytAACncPWgWADhjVlaAQAgoAfgYszSCgAAJTcAAACAq1FD73AMigUAAEBh6EPvEvShR7hP7HQ267D89PH1uS6jBzwAwEmYKRaA4zlxYicAAMIdJTcA/MLETgAAOBMBPQBXTuykfeDLxFS0ezcAALAdAb3DMSgWyI9JnQAA+B8GxboEg2Jht9MnD8rO+QmOmNhJM/MRkcyLBwBwFgbFAnBshxmry0xeTOwEAID9SHEBLkGHGQAA4As19IAL0GEGAAAUhIAecAGndZhRdJkBAMAZCOgBFP0fR3S8VE8Yy8BUAAAcgBp6F7St1OXMmTN27wocxq4OM4ouMwAAOAdtK12CtpXhzVfLyIa3p0pU2aq27RMAAHBGvEbJDQAAAOBiBPQAAACAixHQAwAAAC5GQA8AAAC4GAE9AAAA4GK0rQSKMFurTvBkh7NZh215XAAA4HwE9IAfMncmy/7U5xw3WysAAAAlN4AfmXmCeQAA4FQE9A6ns8Q2adJEEhMT7d6VsKVlNk7LzEdGx5vZWgEAAAjoHW7gwIGSlpYm69ats3tX4KBgvnrCWImIpGIOAABQQw8US/2bl0lkbGVbXj3NzBPMAwAACyk+oBg0mI8qW5XXDgAA2I6SGwAAAMDFCOgBAIDrbNiwQcqUKSOzZ88u1u0bNGhglmDr2LGjRERESDjZtWuXec59+/Yt0f38+c9/NvezatWqYt/HoUOHpGLFivLMM89IKCGgL2X6ptM3X96lWbNmpf3QAIBSDlC8l/POO09q1aolXbp0kT/96U+yY8cOn7d96623zPYanBSkoG00ANXLq1evLkeP+u6+VbZs2XyBqnV/hS3+BlvWPhS0LFiwIGdbvU/v66KioqRy5cqme9t9990nc+fOlVOnTklxDBs2TC699FK59957i3V7hKcqVarIU089JZMnT5affvpJQgU19EHy+uuvS9OmTXN+13/8AAB3a9Sokdx///3m56ysLPntt9/k66+/lueff17Gjx9vsoD/7//9v4BnZA8cOCCTJk0yj1MUerDRvn17n9ddccUVft+PZsafffZZn9dpkJ3XI488InXq1BGPxyOZmZmybds2WbhwocmuX3bZZfL+++/L5Zdf7vfjr1ixwiTM3njjDYmMLF5ucvny5cW6HdxvyJAh8te//lXGjRsn//jHPyQUENAHiQbzbdu2DdbDAQCCoHHjxj4z7atXr5Y+ffrIhAkTTPBb1MC7MNHR0VKzZk15+eWXTWvjCy64wO/bXnfddTJy5MgS74Nm2gs7w5BXv3798n0H6hmG5557zjyPG264QdavX2/OcPhjxowZEhcXJ3feeaeU5GAM4alq1arStWtXee+99+Sll16SChUqiNtRcgMAQIBpFnzx4sUSGxtrMul79uwJ2H1rRnrs2LFy/Phxs3ar+Ph4+dvf/mbKcn799VeTLfXH4cOH5d///rfceOONPgOxlStXmmBNDw709a9Ro4Z06NBBXnvttXPW0HvXaOvZAz1roQcOegA1ePBg+f333/M93unTp82Bmx4gaLmTHuTp7z/++GOR68b1eelZFC1L0vvS8twXX3xRzpw5U+Ra9S1btsgtt9wilSpVMvfXq1cvc2ZHffXVV+Zx9PXT6/SAS99PvsycOVOuvPJKKV++vFn0Zy3h8kX3UzPf+hp4vxZnz571ub3uq44pCMQYh02bNpnyK/1bxcTESP369eXJJ5+UgwcP+tz+7rvvNs95zpw5EgpcH9Bv3bpVpkyZYt68zZs3N1kDfYP4+49B/5D6ZtI3dLly5aRFixbmn292dnZA97N79+4mS6P/WPr3728GZQBAqPF4zsrpkwdds+j+lpZLLrnEBA1aI+5dVx4IDzzwgAn2tJzzhx9+EDcbM2aMWf/rX/8yJTnn8vnnn5vvaF9nvT/++GMTqKakpJiA/+mnn5bbbrvNlEP985//9Hufpk6dar6r9ez6E088YWIErbnWwDevhx9+WEaPHm1+1jMmN910kznroGUdRTFq1Cjp0aOHiWtuv/12GTBggDmY+MMf/lDkcQI7d+6Uq6++2jxv3WeNbbSsSe9fzx7pa6TBuT5HPRDR0iUNfvPSWnN9fnv37jVlU7rozw899JA5wMlL70/PAGkAr6+F/g30oM3XtoH04YcfSps2bcxaYzp97TUm1L/jVVddZQ4C89LLQ6n0yvUlN3raLSkpqVi31T+43lYPAjp37mze3FqXN2LECFPbt3TpUvNhKgkdSa3/UPQNpvev/2T0aFWPjlNTU032AP7xnD0tZ05lBP3lOpuV/x8BAN/OZB2WnfMTXPPyNLw9tVTnlND//RpIBnq2b83ST5w40WRgNZjUwaX++PTTT+XkyZM+r9Og0Vf9uy+alfZVclOcQaoXXnih1K1b15zF0EBUfy/Ml19+adatW7fOd92bb75pDgo0S69BrLeCMrUFvU7ffPONOShTOg5Cs/UaFL/wwgs5pUEaDOrfV6/T/bLGx/3xj3+Uli1b+v14y5YtM39PDYDnzZtnEoxKn4sG9q+88oq5/I477vDr/vSg5+9//3tOIK33o++VRYsWya233mpKTTTRqPTgKCEhwTwPjU808WjdhyZMdYyDxiwazyj9u+vBlB7gaMmTnv1QelZDX3993fW1sJ6Dvj+LMj6jqPTv2qdPH6lWrZp5XM3MW/TvpWcmdJC6Phdv+j7TAzXr/eR2rg/oNUMxfPhw88Fp1aqVGYTkz1G4Zks0mNcg+7PPPjO3VXo6SoN7PYLVrIGe6rLoKSY9KvUn62/V9el+eX+o9Z+7PpbWC+oHqqQtnMJF5s5k2Z/6nJzN9t3VAQCcyAr8rFKHQLr55pvlmmuuMYGeDsTVDOW5aABaUEZSgy5/A3otrfBV7qNBYnG6zujrpAG9vk7nCujT09PN2go8ffGVjNO6aX9pIGwF89b9aWCoz1kDfevv+u6775q1BozezS6sEh0rc38umklWWhZkBcJKKw400H/11VdNzOBvQK9Zd82ue9+P/l00oNeYxArmrTEZGrPoc0hLS8t5Xd9+++2cAN4K5pUGwTr2QbsUaVxkBfTvvPNOzmvh/Rxq165tXgvrTEyg6eNmZmaa19A7mFf6nPUATAP7vAG90ue6fft2c8Dj9lairg/o857+8ne0uwb+Sk8NWcG80iO86dOnmzeovjn0DWi9kXv27OnXwFZ98xbm+uuvN22TNGNDQO9fZp5gHgDy0xJR/V7SM8ualT4XzcAGYlCsnl0uKNNf2qxMu9aG56UB3Pz5881r0rt3b1Naot/n+t1eFL6y/9qlRx05ciTnso0bN5q1r85B7dq18/vx1q5da4JgzXD7ogcU33//vd/3px2D8gaoepChfGXLrev27duXq8+/8lXj3qlTJ7P+z3/+k++1sAJ8b74uCxR97ZRWQPhqFavvUz1Q1CXv+0BjMT3bpH9TPVBxM9cH9MWh9V/W6U/9wOelH0zr9J8ezepRudLA3vsotaTcfjQYLFpm46TMfGR0vJSJCdz7AEDosgIk7RufN/FU0EBB7+vOlaTSAYpab61BrH5fdevWTULldTpX9t3XAcVdd91lzsBr3baWqUybNs1812oAqt1M/C398DXYVstzlfcAVc0M69/I1wFDYWcQ8tJxdRpYFjbIuaBBq0Xd/8Ku8x4/aD03X38TfW76uuo2loyMjIC8FkVljUmcNm1aodvp65d336xBzqHQSjwsA3rrqFOPzBo2bOhzG60n04Bet7UC+kBZsmSJeQMWdnpUB7LoYvH+0MDeYL56wliJiAzLjw5wTmViK5u6dDftb2myZrRMTEzMucxKDBVW022V6PiTRNIzzjoYUDPvOiDTbbQbjH7fauDoT1cTK8AsqLmElpPoom0xtT5aD3Z00Ke+Nprl9pXZLy4NjvXgS/9eeQNf7dxTlPvRALk0SrNK+tz2798v559/fq7rdL4FLVPxPjjQ92pRXwt9znog44seIPjz/rf2YfPmzUWetFPfQ9ptKRTGM4ZlVKKDblS9evUK3EYz9N7bFpdOOKIHDXr6Tt80ekpIWzpplqCwOkM9LermdmSlrf7NyySylL+IfdHMPME8ULCIiMhSHWTqJtp9Rju3aLCgJZsW7b6hdKBhQazr/JlsSWu9tfuI1lkXpZOLU1g9+u+55x6/zlxbr592g9EzFAXR71wN4nXRrLqWs1jdbwJFB4Bq4k8PHLSDjLc1a9b4fT/6PD755BMz4dZFF10kTqC19vrc9KBUuzX5OlD1PuOhr4XOJfDFF1+Ys0be9DJftMxFqyZ8td/UMhh/Anp97ebPn28+M0UJ6DVjr+MxCnsPuYnr21YWhzVdtvegjbx0sGwgMuPa8kpP/2mLMf2nojOS6T9e/TBon9TC2lfp0am1BLKHcSjQYF6DhmAvBPMA/KEBngaOeqZVM+feY6t00KeWdmqw5Kuft3ZY0U5rmq32t/ZYBy5q2YAOSCyslMdJjh07ZrrA6WugNdz+DiC99tprzVqD87y0M4uvnu2aUVbaGz2QdGCo+stf/pKrR/0vv/xSpA581gBWbRHp68yN3p/2lQ+mBx980Kw1uZi3tMZKOFrbKO00Y70W3uVBGrAX9FromSsN3rU5iUXbvA4bNszv/dRmJfHx8aaz0HfffZfv+hMnTuTU2XvTwc36XrHeT24Xlhn6YNLAXJei0oxOKJwCAoBQph0yrPaNGoho4KgdZ/T0v8498uyzz5qOIHlp/3jtUKPBiAa0WoKp2+vkODohlQbnmm23apvPRWeLHTp0qGmvWNy2lXofjz/+uJQGfb76vLRMQ5NqmonWIE5/1sSXdiGxBmaei5610IMibfXoKzDWenw9YNIDIs34a9c6/ZvoQFlfg1dLQmfe1bF4OgmVnjnQLL0exOmZGc386oGZP806NOGnTTj0bIVOxqS/a8cWDe71PaYZbp1fR1tIBou+P7U3vXaH0cy3dtjRv592VdLMtr7Wuo1Fxyno+1knotLXQs9K6WvxwQcfmNf+o48+yvcYGrhri3Ad+6Hlzfq+17+rlkX5+37Q8p733nvPjJ/QswT62mm3Jn1s62BBe/Lr+8+b9f7Je2bFrcIyoNcjuXMNMNHMgbJ7OmAd5KGLv7PEAQCCR7tqWNlKHaypgYgGExqcafZS2wcWVCajHUK0NbIOZtWuappZ10y+dm/TyYQ0sCuKZ555xpTdFFaHXVjbSg2GSiug1xp2pQct+h2sbR91wicNprTeXVsn+kuD9Mcee8x09snbrlMTaFp+odlXHa+m96uBvZa6aj93ffxA0/aOGmhrSY8Gv9oNR+e50Q47GtD7G0doZlsDZO3vrn8jLTnRVptatqsHjdbZgGDSfdHSG53zx5ppVw/AdF99tfHWKoSLL77YrPU9ra+FBu1asuMroNcW3nrwo/enB7A6tlEDcx0XUpTymZtvvtmc8dIWlXrQqsG6VmHo4+t+avlzXrNmzTIlQ/60e3WDCI8/07K5iLaB1A+XHuVqZsQX/YDpPxL9oBT0j0/rv5KTk02Pe32D2E1Pd2ktmZ7qsuMgw65JnayJnX76+PqgTgYDAHAuHcyoWXoN/jR4dCI9K/Hoo4+aVtg62yyc49NPPzUtxDVe1JLoUIjXwjJDb030pKeydNCrr043Oour8u5RH66Y1AkA4CSaydVsvJ4J0eRd3gmFgknr2602jt5141oio2cEdIZWOMvYsWNNdt5X5t6twjKg11MwOhBDe9Fr3ZsOpPCm9XY6CFVr2O3u6Wt3yQ2TOgEAnEhnH9U66d27d9sa0OtMrh9//LEZwKztHXV/tLxExwdoqYzVNQ/OObvTpUsXufXWW/2ejNQNwjKgVzqaXgds6Aexa9euOZl4zdprnZ0aNGhQQCeSKo6BAweaxTqFE+6TOikmdgIAaMca7epjNx2EmZaWZoL6w4cPm/3SgbsaS/iavBL2n9358/8NZA8lrq+h156nVgBuDVDSunjNwnu3CdN6+LwjpvXoXgd86KAZPVrTARTWQBSdslkHVVgz0tnNrpqs0ycPys75CeK0iZ0qNPxfT2cAAAAnoIa+BC+cr1602lJJF4v3rKsW7YuqgbuWtOgEEDrlsXYk0J7B2v6rsD7x4VJy46RJnRQTOwEAAIRYhj5cOClDT4cZAAAA58RroTMaAAAAAAhDBPQAAACAixHQO5zWzzdp0sS02QQAAADyIqB3OG1Zqe2wtGc+AAAAkBcBPQAAAOBiBPQAAACAi4XtTLFukbcP/emTh+R0THbQHv9s1uGgPRYAwH4RERFy7bXXyqpVq+zeFQB+IqB3QQ29LlZf058+vFbKn8eJFQCw265du6Rhw4Zy4403yuLFi4P2uIcPHzaJno8//lh++OEH8/1QqVIladGihXTv3l0eeughKV++fND2B4D9COgBAHCJ5cuXy9133y2HDh2Syy67TO666y6pWrWqHDx4UD7//HN56qmn5O9//7vs2LHD7l0FEEQE9CiSyOh4KRNTkVcNAIJs48aNcuutt5qf3333XbnvvvvybaNlMqNGjeJvA4QZajfg/5slOl6qJ4yViEiOAwGgIKdOnZKXX37ZzB8SHx9vyl90PpFhw4aZchlvv/32mwwdOlQaN24ssbGxUq1aNbnjjjvk22+/zXe/mn3//fffZcqUKT6DedWxY8dcte9vvfWWqYnXdV66nV735z//2ed9paenS69evcw+nXfeedKuXTv59NNPC3zOf/vb36RVq1ZSrlw587w7dOggH374IW8UIAiIzFw2KFbVv3mZRMZWDvq+aGaeYB4ACqYB9/XXXy9ffvmlXHTRRaaeXQP1bdu2yauvvioPPPCAVK783//fWhajAbgGzjfccIP06NHDBPjz5s2TJUuWmPKaK6+80my7fft2U1JTt25dc5+F0ccrKT3w0AC+evXq0q9fP9m/f7988MEHctNNN8ncuXPNvlqysrLM5XqAcMUVV8gjjzwi2dnZpsZfa/r1AGTQoEG8bYBSREDvskGxSoP5qLJV7d41AMjnrMcjh0+dcs0rUzkmRiIjIgJ2f2PGjDHBfJ8+fWTmzJlSpkyZnOsyMjJy/a7B/c8//2wG1OrAWsuzzz4rCQkJ8uijj8qmTZvMZXqfSrvPREaW/sl1fdzevXub0h7N4qvBgwebsw79+/c3+xsXF2cu/8tf/mKCeX3uY8eOzdn+6NGj0rlzZ3n66afl9ttvl1q1apX6fgPhioAeABAwGswnLHVPmUXqDbdJ1QBktNXp06fltddeM8mXpKSkXMG7spIyasOGDbJmzRp5+OGHcwXz6uKLLzbBvJawaOlNs2bN5JdffjHX1alTR4JB9338+PE5wbm6/PLLzYHKG2+8IYsWLTKlQWfPnpUZM2ZIo0aNcgXzSstu/vSnP8ltt90m8+fPJ0sPlCICegAAAuD77783Wenrrrsup6ymIGvXrjXrX3/91WcNu96XtdaAPtjq1asn9evXz3e51sVrQK8HJBrQb9261ZTnaPZdA/q8tFTH+/kAKB0E9AAABICW1KjatWufc1ttO6m0zlyXghw/ftysL7jgArPeu3dvUP5WNWrUKPRy67laz+O7774zy7meB4DSQUAPAEAA6ORO/gbdFSpUMGt/B4zqAFWltepa5uJvHb21nZYD5WUF5b7omYPCLrfKh6znodl6HSwLwB4E9ACAgA4y1bp0N+1voFxyySUmwF23bp0pQyms7MbqXvPVV1/5FdBrW8trrrnGdLp5++23C+10o11nrE431j74OsjQspmC7N69W3766ad8ZTdffPGFWbds2dKsdXIrfc6pqamms010dPQ5nwuAwKMPvcNpy0rtX6ydBQDA6bRjjA4ydcsSyA43UVFR8thjj5nMt3aE8W43rPTyY8eOmZ/btGljgvr33nvPtIPMS7Pwn332Wa7LdKCtdpbRAwBft7ECbu0sY2ndurUZqPr+++/LyZMncy7XNpp6fwXRfR89erR4PJ5cnW/++c9/mlaW3bp1y3nOTzzxhAn+hw8fboL6vHRgr7bjBFB6Ijzen1Y4ltW2cv0/6knz+9fTthIAbLZr1y5p2LCh6VKjrSeVBs3aU14Da+1D37VrV5Mt//HHH802q1evNr3a1c6dO6VTp04mGG7btq2ZlEkDds2Oa+ZeB5R6B+FKe9PffffdpnZdkz2ata9SpYr5XVtbbt682WTzNWC36CRUs2fPNttrv3gNrpOTk83P2vP+ueeeyzUwVw8AtKPNkSNHTPCug3ytPvTaZ19vk7cPvc5gu2zZMtPtRvfp/PPPN2cFdH90hlt9PvocgXCJ1zIyMnJK0oKBkhsAAAKkbNmyJrCdOnWq6eH+j3/8w7SA1K4xjz/+uDRo0CBnWz0Y0LIXbU+5YMGCnL71NWvWNEHxnXfeme/+u3TpYoL16dOnm8G0GmRrZx0NIJo3by6TJ082rTC9vf7662a2V91Wz/pqaZC219TONBqc+6KlOnr/mnXX53DixAlTZqOdbHTiLG96wPLJJ5+Y7jfvvPOOuU8N8nUArR5E6PPWfQNQesjQuwQZegAAAGfLtClDTw09AAAA4GIE9AAAAICLEdC7TP3bPpMysYXPQAgAAIDwQUDvMlFlq0hEBH82AAAA/BeRIQAAAOBiBPQAAACAixHQOxwzxQIAAKAw9KF3Cbv6mgIAAMA/9KEHAAAAUGSU3AAAAAAuRkAPAAAAuBgBPQAAAOBiBPQAAACAixHQAwAAAC5GQA8AAAC4GAE9AAAA4GIE9AAAAICLEdADAAAALkZADwAAALgYAT0AAADgYlF27wD84/F4zDozM5OXDAAAwIEy/y9Os+K2YCGgd4mDBw+add26de3eFQAAAJwjbqtYsaIECwG9S1SpUsWsd+/eHdQ3iBMkJibKunXrJNz2J9CPU9L7K+7ti3q7omx/rm01U6IHwXv27JEKFSpIOHHa50bx2Snd18vf7f3Zjs9O+H12nPad49bPTkZGhtSrVy8nbgsWAnqXiIz873AHDebDLTApU6aMo55zsPYn0I9T0vsr7u2LeruibO/vtrqNk95D4fi5UXx2Svf18nf7otwvn53w+ew47TvH7Z+dyP+L24KFQbFwvIEDB0o47k+gH6ek91fc2xf1dkXZ3mnvDSdx4mvDZ6d0Xy9/t3fie8NJnPj6BGOfnPadU5L7GBiGn50IT7Cr9lEsevpTs/N6KsdpWTfAqfjcAHx2gHD43iFD7xKxsbHy3HPPmTUAPjcA3zmA88TaFK+RoQcAAABcjAw9AAAA4GIE9AAAAICLEdADAAAALkZAH4Lmz58v7du3l2rVqplBGRdeeKEMGzZMDh8+bPeuAa5x+vRpufzyyyUiIkLef/99u3cHcKxVq1aZz0nepVmzZnbvGuAKH3zwgbRp00bOO+88MyFVly5d5Oeffy7SfTCxVAg6dOiQdOzYUf7whz+Y1kmbN2+WsWPHysaNG2X58uV27x7gCklJSbJ//367dwNwjddff12aNm2a87sGJwAK99JLL8moUaNk+PDh8te//lWOHz8un3/+uZw8eVKKgoA+BPXr1y/X7xrcly1bVvr37y+7d+82UxIDKFh6ero5CJ46dao8+OCDvFSAHzSYb9u2La8V4Kft27ebYF4TSE888UTO5bfccosUFSU3YUJP4ajs7Gy7dwVwvCFDhshtt90m11xzjd27AgAIUW+++abExMTII488UuL7IqAPkq1bt8qUKVOkb9++0rx5c4mKijI1huPGjfPr9nPmzDGZ9sqVK0u5cuWkRYsWMmnSpEID9DNnzphTNqmpqSbb2K1bN2nUqFEAnxUQep+dxYsXy9KlS+WFF14I8DMBQvs7p3v37lKmTBmpUaOGOSOs5Z+A22wN4mdnzZo1cumll8rbb78t9evXN4+l23/yySdF33EPgmLw4MEefbnzLs8//7zft42KivLccMMNnttvv91TqVIlc1n79u09J06c8Hm7ihUr5jyO3u7YsWOl8MyA0hXMz87vv//uadSokefFF180v+/cudNs+95775Xa8wPc/rlZv3695+mnn/YsXLjQs3LlSs/EiRPN90+zZs08J0+e5A8MVxkcxM/OJZdc4ilfvrynZs2annfeecezZMkSzy233GJu/+233xZpvwnog+Qf//iHZ/jw4Z5Zs2Z5tmzZ4unTp49fb5Dk5GSznf7Bv/nmm5zL9+/f72nevLm5Tv+R+rJhwwbPl19+6XnllVc8derU8XTq1Mlz+vTpgD83IFQ+O2PGjPFcdtllnlOnTpnfCejhVnZ853hbunSp2XbmzJkBeT5AKH52LrroInP5xx9/nHNZVlaWidn0cYuCgN4mDz74oF9vkMTERLPduHHj8l33xRdfmOtiY2M9R44cKfR+1q5da7adM2dOifcdCMXPzq5du8zvc+fO9Rw+fNgsGzduNNu98cYb5/yMAU4W7O8cVaVKFc+AAQNKtN9AKH922rRpYy7Pm7m/5557PK1atSrSflJD72B79+6VdevWmZ979+6d73rtNV+3bl3JysqSRYsWFXpfrVq1MjVgOqIaCHXF+ezs3LnT/H7nnXea2kddtJZR6YCl2rVrB/lZAO79zrHo9w4Q6vYW87Pj3ebVmybci9q2koDewTZs2JDToaZhw4Y+t0lISMi1bUG+/PJL8wbRSaaAUFecz84VV1whK1euzLW899575roxY8YUb5ASEKbfOUuWLDGDYnWyHCDUbSjmZ0e7qSnvOYI06F+9enXO9v6iD72DacZQFdY3Xo/4vLdVN954o5llTI/8dKZYffNoxw6d9bJHjx5B2HPAfZ+dSpUqmc4E3nbt2mXWTZo0kQ4dOpTiHgPu/c65//77TRDTunVriY+Pl5SUFDNBjh4k33vvvUHYc8Cdnx0N6K+66iozf9CECRPkggsuMB12Dh8+LM8880yR9oGA3sGOHj1q1tr2qCDly5c368zMzJzLNCPy7rvv5rxpGjRoIAMGDJBhw4aZfqdAqCvuZwcIZ8X93GjyaPbs2WZynN9//13q1KljytSee+45vnMQFo4W87MTGRkpH330kZkl9umnnzafn8TERFmxYkWB5TgFIaAPQc8//7xZAJSMHgxrqRqAgulMl7oAKDot09EJpnQpCWroHUxPXarjx48XuM2xY8fMukKFCkHbL8Dp+OwAfG6AcPrOIaB3eHZQ7dmzp8BtrOusbQHw2QH4zgHCK14joHewli1bmvXBgwdzDaLwlpqamtOWEgCfHYDvHCD84jUCegfTgUU6OELpgKO8tK2RHvFpJ5tu3brZsIeAM/HZAfjcAOH0nUNA73CjR48264kTJ8r69etzLtejQO1cowYNGiQVK1a0bR8BJ+KzA/C5AcLlOydCp4stlXtGLvrHtf6gaseOHXLgwAFzVOc9A2VycrLUrFkz120HDx4skydPlujoaNNfXtsi6SQER44ckXbt2smyZcskLi6OVxwhic8OwOcG4DvnHDSgR+lbuXKlHjidc9m5c6fP23/wwQeea665xlOhQgVPXFycp1mzZp6JEyd6srKy+PMhpPHZAfjcAHznFI4MPQAAAOBi1NADAAAALkZADwAAALgYAT0AAADgYgT0AAAAgIsR0AMAAAAuRkAPAAAAuBgBPQAAAOBiBPQAAACAixHQAwAAAC5GQA8AAAC4GAE9AAAA4GIE9AAQYubMmSMRERHnXGrWrBmQx9u1a1e++x43blyht1m1apU8+uij0qRJE6lcubJER0dL1apVpU2bNjJo0CD59NNPxePxlHjfHnjgAbM/9957r1/bv/zyy2Z73S/LpZdemuu5dezYscT7BQCBFBXQewMA2O6bb74x66ZNm0pCQkKB2zVv3jygj1uuXDm58847zc8tWrTwuc2BAwfkvvvuk6VLl5rfa9euLe3atZOKFStKRkaGfPvttzJt2jSztGzZUtavX1+ifXrkkUfkn//8pyxYsEAOHz5sDh4KM3PmzJzbWXr27Ck///yz/PLLL7JkyZIS7Q8AlAYCegAI0YD+sccekyeffDJoj1utWjV56623Crz+yJEj0r59e9m6davJek+fPl06deqUbzsN6jVT/v7775d4n6655hpp3LixbN++XWbNmmWy/wVZt26dbN682Zwt6NOnT87lEyZMyDmrQEAPwIkouQGAEGNltZs1ayZOogcXGsxfeOGFsmbNGp/BvLXfb7zxhqxcubLEj6klMg8//HCu7HtBrOtvueUWOf/880v82AAQLAT0ABBCtJ790KFDjgvod+zYIbNnzzY/a/b9XKUvSuvpffn999/lpZdekrZt20qlSpWkbNmycskll8gzzzwjBw8ezLd93759pUyZMuZAZ9OmTT7v8+TJk/Lee+/lK7cBADcgoAeAECy30Qxz9erVxSk++ugjOXv2rAnkNQNeXPv27ZMrr7xShg8fLtu2bZPExETp1q2bZGVlyQsvvGDGDPz000+5bqODf3UbpZl/X+bPn29KgmrVqiU33XRTsfcPAOxAQA8AIRjQOyk7771frVq1ksjI4n31aNebu+++29S5axZdz0YsW7bMBONaI//000+byx566KF8t7Wy7lpHf+rUqQLLbaxsPgC4CYNiASCEWIHzihUrTP14QRYvXiw33nhj0PZLu9uogs4abNy40ZTi5NWvXz8zkFbpgNQvv/xSrrjiCnnllVckKup/X2H686RJk8w2WnuvA2u9D2puvvlmueCCC0ynmg8//DCnG4/avXu3eb2Ur4MBAHA6AnoACMEBsRqsawBbEK0/d5I9e/bI22+/ne9y7fluBfQff/yxWd9xxx25gnmLZv61q40G8zro1jug1+0ffPBB+etf/ypvvvlmroBes/NaDnTttdeajjgA4DYE9AAQIjTTbGXCX331Valfv744hba0VPv37/d5vdbVe08kdd1118ny5ctzbfPjjz+a9ZgxY8xSGF+Po91uNKDXHvh79+41PfD1Ma1WmwyGBeBWBPQAEGLlNjrjalGC+aFDh5qstU7s5B38fv/99ybTHQhaO68TPOkZBM2GF6eOXm+nNGPfqFGjQrfVSbXyuvjii6VDhw7yxRdfyDvvvCOjRo0y5Tlad68TW3ln7QHATQjoASDEAvrWrVsX6Xaaqc7MzJRjx45J+fLlzWU6+FQ7w2gLzCpVqpR43zQDr4NWdbbWRYsWFavTTd26dc26e/fupstNcWgWXgN6LbPRgF4PZNS9994rcXFxxbpPALAbXW4AIMTq54sT0CstQ7HUqFHDlKOkp6cHZN+0Nv2ee+4xPw8bNizX2QB/de3a1aznzJmTqzynKO666y6pUKGCaXmprTS1Q46i3AaAmxHQA0CI8G4NWRTaez1vQK/lNqqwgbVFNW3aNBPYazB99dVXy2effeZzOy2B8XUgoZl57Tv/9ddfm240vurk9QyAdsA5ffq0z/s+77zzpFevXjllRTpJVfPmzc39AoBbUXIDACFAA+DffvvN/Kz14Zp9Lsjjjz+eq8tN3gy9Zr+TkpKkU6dOZoKqQNFJpbTtZO/evc2AV+1gU6dOHdOGUmd81eBag33tM6/7oIG2ThRl0br7BQsWmBaU2hFn7ty50qJFC6lXr57pLa+DZvW2Z86cMf3kfXXCsbLxOmjYOiAgOw/A7QjoASCEsvNq4cKFhW6bt/48b0CvnWC0L/zatWsDvp96gPDpp5+agH727NkmwP/888/lxIkTEh8fLw0bNpT+/fubAaqdO3fON3hWzybofmlnmg8++EA2bdpkMvZa56/X6cHKbbfdJmXLli1wHzQbrwcLGvzHxMTI/fffH/DnCQDBFOEpbiEiACBkaPZcA9suXbqYAbE6o6rWm/tDS2Q0ENfOOvpzqFq1apU5a6H96vVnAHAKMvQAAJOl/+STT+T11183Nej+BvPetAe+lrpYkz/deuutIfHKajecn3/+2cwyCwBOREAPADAB/YoVK0wbxz59+hTrFTl+/HjObK86+DVUAvrk5GTZunWr3bsBAAWi5AYAAABwMdpWAgAAAC5GQA8AAAC4GAE9AAAA4GIE9AAAAICLEdADAAAALkZADwAAALgYAT0AAADgYgT0AAAAgIsR0AMAAAAuRkAPAAAAuBgBPQAAAOBiBPQAAACAuNf/B1jQPPQ16uQPAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "for k in [\"DUNE\",\"IceCube\"]:\n", - " controller = SIREN_Controller(1,k if k==\"IceCube\" else k+\"FD\")\n", - " for x in controller.detector_model.Sectors:\n", + " detector_model = siren.utilities.load_detector(k if k==\"IceCube\" else k+\"FD\")\n", + " for x in detector_model.Sectors:\n", " if k==\"DUNE\" and x.name==\"dune_far_detector\":\n", " fid_vol = x.geo\n", " elif k==\"IceCube\" and x.name==\"icecube\":\n", @@ -298,7 +436,7 @@ " kwargs = {\"bins\":np.logspace(3,6,20),\n", " \"label\":k if k==\"IceCube\" else k+\" FD (single module)\"}\n", " data = awk.from_parquet(\"output/\"+filename[k])\n", - " plot_Aeff(data,controller,fid_vol,gamma=1 if k==\"DUNE\" else 2, **kwargs)\n", + " plot_Aeff(data,detector_model,fid_vol,gamma=1 if k==\"DUNE\" else 2, **kwargs)\n", "plt.legend()\n", "plt.loglog()\n", "plt.xlim(1e3,1e6)\n", @@ -310,10 +448,49 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "id": "64b70612-9f96-48e5-8809-ee40cef86bbd", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7.53^{+ 1.24}_{- 1.34} \\times 10^{-5}\n", + "5.89^{+ 0.98}_{- 0.76} \\times 10^{-5}\n", + "3.93^{+ 0.14}_{- 0.10} \\times 10^{-5}\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAsoAAAIiCAYAAADRge6vAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAABru0lEQVR4nO3dCbxM9f/H8Y89uyyVQpZKyV6kRKJVv0qLipIWpfATkqS0+lHaEJX2fUNUEkkkiYgoW8iuJNllv//H+/v7nfnPvffMvXPvnTvbfT0fj9Pce+bMmXPOTNdnPvP5fr75UlJSUgwAAABAKvlT/woAAACAQBkAAAAIgYwyAAAA4INAGQAAAPBBoAwAAAD4IFAGAAAAfBAoAwAAAD4IlAEAAAAfBf1WIvsOHz5sGzdutJIlS1q+fPm4lAAAAHFG8+3t3LnTjj32WMufP3TemEA5whQkV65cOdK7BQAAQIStW7fOKlWqFPJ+AuUIUybZu/ClSpWK9O4BAACQQzt27HCJTS9uC4VAOcK8cgsFyQTKAAAA8SuzMlkG8wEAAAA+CJQjZMSIEVarVi1r1KhRpHYJAACAGMqXomF/iGjNS+nSpW379u2UXgAAACRwvEZGGQAAAPBBoAwAAAD4IFAGAAAAfBAoAwAAAD4IlAEAAAAfBMoRQns4AACA5EJ7uAijPRwAAEB8oz0cAAAAkAOUXgAAAAA+CJQBAAAAHwTKAAAAgA8CZQAAEDH58uWzFi1acEWRFAiUAQCIgdWrV7ug8qKLLorq827dutUGDBhgZ555ppUrV84KFSpkFSpUsPPOO8+ee+4527VrV1SPB4hnBWN9AAAAIDqmTJli11xzjf399992yimnWNu2bV2wvGXLFps+fbp1797dhgwZYitXruQlAQiUIzvhiJZDhw7xxgIAxJ0FCxbYpZde6n5+55137Prrr0+3zbRp0+y+++6LwdEB8YnSiwjp2rWrLV682ObMmWN51brB030XAED49u/fb88++6w1atTISpYsaSVKlLBatWpZr169XNlEsD///NN69uxpJ5xwghUpUsTKly9vV111lf3yyy/p9qts8T///OPKK/yCZFFtsYJlzxtvvOHKQ3SblrbTfQ8//LDvvtavX2/t2rVzx1SsWDFr2rSpffXVVyHP+ZlnnrGGDRta8eLF3Xk3a9bMPv3000yvF5CbCJQBAIgTCmRbtmzpguLt27fbzTffbHfeeaeddNJJNnLkSFuzZk1gW5VHnHbaaa5UokaNGvbvf//bWrdubRMnTrQmTZrY7NmzA9uuWLHClVZUrlzZ7TMjCrhzSgG9AuPly5dbp06dXMCsjLbqsceNG5dq23379tmFF15od999t6WkpNitt95qN9xwgzvXyy+/3IYPH57j4wGyixplAADiRP/+/e27776zDh062Ouvv24FChQI3KfAOfj3G2+80X7//XcXGCvQ9DzwwAN2+umn22233WYLFy5067RPOeeccyx//tzPkel527dv70o8lHWWu+66y2XJb7/9dne8RYsWdesfffRRl53WuT/yyCOB7Xfu3Ok+NCiAvvLKK+3YY4/N9eMG0iKjDABAHDh48KC99NJLVrp0aRs6dGiqoFi0XmUYMn/+fJs5c6Z17NgxVZAsyj4rSP75558DJRh//PGHu61UqVJUzkXHPnDgwEDQK3Xr1nUfADZv3mwTJkxw6w4fPmwvvPCCy4gHB8mi8osHH3zQlWV8/PHHUTluIC0yysgy6o4BIPKWLl3qsqhq03bkkUdmuO2sWbPc7aZNm3xrhLUv77Z27dpRf7mqVKlixx9/fLr1qjt+9dVXXaCvWuply5a5Mg1lixUop6WgOvh8gGgjUAYAIA6otEKOO+64TLdVezf5/PPP3RLK7t273e0xxxzjbjds2GDRcPTRR2e43jtX7zwWLVrklszOA4g2AmUAAOJAmTJlwg5mS5Uq5W7VwaJbt26Zbq+BdaJaYJU7hFun7G2nspC0vGDXjzLdGa1XGUnweSi7PHr06LCOCYgmapQBAIgDNWvWdIGj2oymbQOX1hlnnOFuv//++7D2rfZxzZs3t3Xr1tmbb76Z4bbqQuHxSkD8gneVT4Sydu3aVB06PN9++627bdCggbvVpCc657lz59qBAwfCOhcgmgiUAQCIAwULFrTOnTu7TK06RKSdwErrvemlGzdu7ILl999/3z788MN0+1LW+Jtvvkm1TgME1WlCGWi/x3iBrDpNeNR+TgPsPvjgA9u7d29gvdq+aX+h6Nj79evn2r0Fd8J4++233XTZamPnnbPa3ymo7t27t2+wrAGJ6hcNxAKlFwAAxAm1StNAPQWUur344otdX+PffvvNtYGbMWOG1a9f322rIPncc8+16667zvVS1mQdCoSVzVWmWQPhgoNbPe6zzz5zU1jrMXouZZnLli3raoXVQk6dMpR99miQnXogv/feey5oVh9kBa1jx451P48ZM8b3PNThQseqdnAanKhjUXDudfbwWsOJBvHNmzfPhg0b5uqtdUxHHXWUy2LreNR/WeejdUC0EShHCFNYAwBy6ogjjrDJkye7STbUg/jll192rdbUReKOO+6wqlWrBratVq2aK3/QjHaaxMPru1yxYkUXbF599dXp9t+qVSuXDX7++eddUKrgVZ02VDNcp04dF6zecsstqR7zyiuvuNn1tK3+rVOJiIJdBdGhAmWVbGj/yhLrHPbs2ePKLRQUn3/++am21QeBL774wnXDeOutt9w+Vf6hgX+akVDnrWMDYiFfSvD3IsixHTt2uD84+orMG6SQ19vDVe7TPNeOBQAAILfiNWqUAQAAAB8EygAAAIAPAmUAAADAB4P5AABxacvCIRavytXtEetDABAFZJQBAAAAHwTKAAAAgA8CZQAAAMAHgTIAAADgg0AZAAAA8EGgDAAAktrHH3/sps4uW7as5cuXz1avXp3h9oMGDbLTTz/dSpYs6abSvuaaazJ8zJ133un2q6nHYfbwww+76xG86HomIgJlAACQ8Fq0aGFvvPGG7327d++25s2b26OPPhrWvr755hv797//bbNnz7aJEyfa33//bRdffLEdPHgw3bbjx4+377//3o499tgcn0MyqVevnv3++++BZdKkSZaI6KMMAACSWocOHdztL7/8Etb2Co6Dvfzyy1a9enVbvHix1a1bN7B+06ZNLps8YcIEu/TSSyN81ImtYMGCdswxx1iiI6MMAABcNjbt1+Vpl1atWoV9papWrRpyP8r+Btu7d6/16tXLZX2VmT3iiCNckNW0aVN7/fXX7cCBAzF9hbZv3+5uVboR7Oabb7bu3btbnTp1LJbeeecd69y5sytvKFKkiLvGobLrwebMmWOtW7e2MmXKWPHixa1Jkyb20UcfReSYlixZYhUrVrQTTjjBXac//vjDEhEZZQAAYPXr17eHHnrI90qMHj3aFi1aZBdeeGGWrlTp0qWtR48evkF0sF27dtkLL7xgjRs3tksuucQqVKhgW7dutS+++MJuueUW++CDD9zP+fNHP7936NAh6927twsoK1WqFFivemSVdNx9990Waw888ICtWbPGypcv74JT/ZyZqVOnutdT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3RIVgXIE28MtXrzY5syZE6ldIoHs2TQr3QIAiI4WLVrYG2+8EfL+9957z+6991577LHH7Mcff3TTe1944YUuGA5FU4HPmDHDPvzwQzdduKYVP//8823Xrl3u/p49e9q0adPso48+sp9//tmuueYau+6662zhwoWW19WrV89+//33wDJp0iRLVJReICbWDZ7uu75yn+ZRPxYAQHJ79tlnXfb3xhtvdL+/8sordswxx7gAWuvT+ueff+zjjz+2zz//3M466yy37rnnnnMZ4/fff99uu+02mzVrlpvWW9lpue++++ypp56yefPmWd26dS0vK1iwoLu+yYCMMgAAcKpWrZrua3NvUdY2XCkpKS7QPPfcc61ixYqudKFmzZrWuXNn++2333wfc/jwYRs+fLg1bNjQbV+qVClr3ry5ffrppzl6dfbv32/z58+38847L1Ugp/P5/vvvfR9z8OBBO3TokBUtWjSwLn/+/Fa4cGH77rvv3O8KoD/55BP7448/3PmOGjXK9u3bZ+ecc45F2zvvvOOurUocihQp4l6vjDLsom/AW7dubWXKlHGlI02aNHHZ8UhYsmSJe92Vub/55pvdNUpUZJQBAEBA6dKlrUePHr5BdLh69+5tzzzzjAuW2rRp44Je1QS//PLLLiM7c+ZMq127dmB7BZoqXRgzZozVqFHDbr31Vhd0KhC9/PLLXTZX9cLZ8ddff7mg9+ijj061/qijjrKVK1f6PqZkyZJ2xhln2KOPPuqyzkceeaSrcV6/fr0rJZBhw4bZLbfc4s5RgbeCe304qFatmkXbAw88YGvWrLHy5cu749HPGZk6daorPVG9tspFdL669tdee62tW7fO7r777mwfyxlnnOGCdJWqbNiwwR588EFr2bKl+7CiID7RECgDAIAAZRg1ICu7lD0cMmSIGzin4FiBd3AJRK9evVwQ/dprrwXWK0jT0rRpU5s8eXIgkztw4ECXJVXg/a9//SsQrGu9luBSCZVCBAfTXi1xTrK0HTt2dAF2gQIFXAb6oosuCtyvwFnn98UXX7jg9LPPPnOBpjLOtWrVynDfb7/9tsuW6xr5UWCv/et8lMXOjEpJTjzxRLe/xx9/3JWBhKJsuUpHlCGfPn261a9f361XQNu4cWPr16+fXX311amOrW/fvvbEE09keAz6sCMXX3xxYF2dOnXstNNOsypVqtj4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t9xyi+XLl8/KlStn+/btc+tWr17t1oW7VK1a1T1u2rRp7vc77rgjy8fx1ltvBfY3Z86cDLf95ZdfrGPHju55ixQpYqVLl7YTTjjBrrzyShs6dKilpKRk82oA8YEJRyKka9eubtmxY4f7QwHEk5HbSqZb17nMzpgcC4D0du7caR999JELTv/++28bN26cXXvttVamTBl76KGH0m3/yCOPuH9revTokWq9ts+pV1991R2HgtzXXnstZAJo8uTJ9q9//csOHjxo5513nl1xxRV2xBFH2MqVK+2bb76xsWPHun8XCxYk1EDi4t0LAECMffjhh7Z7927r1auXDRkyxAWrXqD88MMP+wbKoe7LieXLl9v06dPtsssus6VLl9r7779vzzzzjBUtWjTdtnfeeacdOnTIvvrqKzv33HNT3acg+8svv7QCBQpE9PiAaCNQRkIbsmxRrA8BAHJMgbEyr3369LEFCxbYlClTbM2aNXb88cdH9eoqgyw33nijLVmyxPr372+jR4+2Dh06pNruzz//dJnjevXqpQuSRRnpCy+8MGrHDeQWapQBAIihxYsX26xZs+yCCy6wo48+2gWphw8fttdffz2qx6Hs8JtvvmlHHnmkK6lQcKyAV0F8Wir7UGD/+++/u0w4kKwIlAEAiCEvEPWythoIV7x4cRcoK2COlgkTJrjA95prrnED85TNbtasmSvFWLFiRaptdb/KM5RZPvPMM+25556zH3/80fbv3x+14wWigUAZAIAYOXDggL399ttWqlQpa9OmjVtXokQJNzBu7dq1rv432gG7Mtoe/ewN6kvrpZdesksvvdR+/vln6969u51++ulWsmRJa9q0qQ0bNsz++eefqB07kFsIlAEAiJFPPvnENm/ebG3btnUdIzxesOpX9pAb/vjjD/v8889da7ezzjorsF7HpYF8KslQaUYwtbH79NNP7ddff3WB8Q033GBVqlSxmTNn2l133WWNGzd2HTyAREagDABAjPhlcaVVq1Z23HHHuUA6GsGmAmG1eUs7aE+Z7ssvv9w2btxoEydO9H3siSeeaP/+979dZlxdM+bPn2+nnnqq67Gs7hxAIiNQBgAgBtatW+daqMk555yTauIQtVXbsGGDm3jknXfeyfVj8Uor1LM57SQmH3zwQZay2/Xr13c1y/L111/n4lEDuY/2cAAAxMAbb7zhBuud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k6cCAAAAEidQnjhxop188snWvXv3DLerWrWq/f777zl5KgAAACBxAuWNGzdanTp1Mt1OdctqmwYAAADkiUC5ePHirqtFZlatWmVly5bNyVMBAAAAiRMoK5v8448/2l9//RVymzVr1rjOGKeddlpOngoAAABInED5hhtusJ07d1qnTp1sz5496e7fv3+/denSxbWL07YAAABAnuijfPPNN9u7775rn376qRvUd9FFF7n1yiBrgJ/Wr1271rWQU69lAAAAIE9klDXT3meffWbt2rWzDRs22CuvvOLWz58/34YPH+6C5Kuuuso+/vjjSB0vAAAAkBgz85UoUcJllfv3728TJkyw3377zQ4fPmyVK1d2k5DUr18/MkcKAAAAJFKg7FHphRYAAADA8nrphcoulD0GAAAAkk2OAuXLL7/clVjce++9tmTJksgdFQAAAJDIgXLDhg3d1NRPPvmk1a5d28466yx7+eWXE3IWvtGjR9sVV1xhVapUsWLFitmpp55qTz/9tGttBwAAgLwnR4Hy3LlzbeHChdajRw8rX768zZo1y+644w6rWLGi3Xjjjfb1119bonjqqaesSJEiNnjwYPv888+tffv29sADD7ge0QAAAMh78qWkpKREYkcHDx608ePH2+uvv25ffPGF+z1fvnwuQ6t+yx07drTjjz/e4pWm4q5QoUKqdQMGDHDdPP744w87+uijw9qPsumlS5e27du3W6lSpSzRrRs83eJB5T7NfdcPWbYo7H3s2TQrgkeU93Qus9PiWbm6PWJ9CACABBFuvBaxQDlt0Pn222+7oHnRokUuYM6fP3/ClTEo4G/durXNmzfPGjRoENZjCJSja8zl5cLelkA5ZwiUAQDJItx4LUelF6EoM9urVy/74Ycf7K677jLF4tnpjrFs2TJ77rnn7KabbrI6depYwYIFXdCtTG84Ro0aZS1atLAjjzzSihcvbvXq1XOlFeEG7NOnT7fChQtbjRo1snzsAAAASGwR66McTLXKyiZ/9NFHgYF9ZcuWzfJ+XnjhBRs6dGi2jkF103qsguuWLVu6iVFUM60OHWpr9+WXX1rRokVDPn7x4sXu8bfffntSlFAAAAAgayKWUVb3iyeeeMJOOeUUa9q0qet+sXPnTrvgggvsgw8+cFNcZ5U6afTu3dvN/Kf2cx06dAjrcePGjXNBroLj2bNn26RJ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06alFC1a1D2+Ro0aKdddd13K+eefn1K4cGH3/N4xr1q1KtXjsnOO2T3PSDxft27dUvLnz59y9tlnp7Rr1y7ljDPOCGzfqlUrd5/237p165S2bdumNGzYMPDYIUOGZOu6h7p28sMPP7jz0P1VqlRx1+Ciiy5KOeKII9y6Cy+8MGXfvn0RuXZ+svLeCXUe3vH07ds3pWDBgiktW7ZMufrqq935aH3lypVT/v7775RrrrnGnZfOT6/ZUUcd5e6vW7duunPMyWsdyj///JNy0003pTq/mjVrun2ddtppqdZrWbt2bYb703XQY3U8ofz8888ppUqVctvpua688kr3vtLflBIlSrjXzM/UqVPdY84555ywzw+IBQJlIMlkJ1B++eWXA0GLn549e7r777777sC6w4cPuwBG62+99daUHTt2BO5TMK1tdd+5557rG3SUKVMmZdasWanue+ihh9x9J510Uobn5heQZWTPnj0pxx13XOAcDh06FLhv0aJF7gOAd1zB+87uOWb3PCPxfApavv/+e9/rMGHChJSNGzemWz9z5kz3uEKFCqWsX78+y9c91P179+4N3HfHHXek7N+/P3DfypUrXSCo+/r16xex90go4bx3MguUy5Url/LTTz+lel/pA4nuU8CrD2DBge3mzZtTTjjhBHf/O++8E7HXOisUtGs/o0aNyvJjwwmUb775ZrfNgAED0t2n6/PNN9/4Po5AGYmCQBlIMt4/9pktW7duDTxG/0gXK1bMZRvTBkoKbipUqOAe88svvwTWf/HFF25d/fr1U2WZPQpGa9eu7bZR1snjPf+wYcPSPUaBVenSpd39ftmu7AbKb731VuAf/OBgzTN8+HDfQDm755jd84zE8z366KMp2XHfffe5x48YMSJigfLbb7/t1h977LHunNMaPXq0u79kyZIuGxqJ90huBsp+10aZbe/+zz//PN39Tz/9tLtPAWWwnLzWWeF9CFy+fHmuBMr6ZkLbzJs3L0v7JlBGoqBGGUhSquXs2LFjyEX1qZ6SJUu69k+q1X3rrbdS7efzzz+3zZs3u7rMU089NdV6Uc1vwYLpxwXnz5/fmjdv7n6eOXNmuvtVF5uW6hurV6/uft6wYYNFyjfffONu27Zta4UKFUp3//XXX+/7uJyeY1bPMxLP57XxCkV1r3qNVQN72223uRpaLd41WrZsmUWKV/97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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "12.95^{+ 1.48}_{- 3.36} \\times 10^{-5}\n", + "8.77^{+ 1.38}_{- 1.93} \\times 10^{-5}\n", + "6.68^{+ 0.21}_{- 0.29} \\times 10^{-5}\n" + ] + }, + { + "data": { + "image/png": "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Ll1cAKmg8rrrrnPP07NnT9/HFi9e3Hr37u0bRGc1Bfoq2XjggQd87x8xYoR17tzZXVtlUPWGQLXQVapUifjXes6cOXbFFVdYgQIFXLlI0aJF3eul13fLli1BzzkUF110kQvSzz33XPfm67HHHrMWLVrYsmXLXBAfbQiUAQCIQa+99pqdffbZdsYZZ9jTTz/tSgNS0qBBA1dzmzQj+u2331rLli1dCULbtm1TDXYUcGlp3LixzZw50woWLOjWDxkyxGU8+/XrZ9dcc41v8KvspgaDpUb70uL5+++/XSlEYAB+8OBBS681a9bYU0895TLpuXL5f/g+fPhw++mnn+yLL75wwelnn33mAs358+e7mXpT8s4777gMu14bPydOnHD71/kosx/O1/qff/6xu+++253XN998Y3Xq1HHrFdDqe2DAgAHWvn37RMfWv39/9yYqtTdIctVVVyWsUyb+wgsvdJ9QqNZbn05EG0ovAITdsLUrfRcglm3cuDFo6UDgoo+7s8Jll10WNBDzc8MNN/iWDTRt2tQuvfRS27Nnjxu0lhpljkUBlxcki7KdGgCn7PKbb75pGaFuEz/++GPCogBcA/UC12WEgu6dO3e60gFli7UoS3v//fe7wFKB+cCBA+2FF16wK6+80g1eU1ZXxzF69OgU971161YXqKqcxC/zq7KVu+66y2V1X3nllbC/1rNnz7YNGzbYbbfdlhAke9l8vWbHjh2zt956K9FjHnjgAVdOkdISjD6Z0Jsi/XyEQm+y9H14yimnuIy3BlHq/LQ+O5BRBgAgDI4fP26PP/54wtca1KUs49VXX52oPZYyrdEmb9687lYBY2q8elS/EgRvnYK1QYMGJbtfQbQ+tt++fbura65fv777KD8ptXnT4lFArsBKgW04KHOetKWZShU0eE81t3qtteTOnTvRNvpagW5KKlSoYO+//74rT9EbEGXxlXENDJLfe+89u/POO6179+4Wbno+UXlNUjpH+frrr5MFu2XLlk3X8+kNlt4QhFI+M2bMGHfOytBff/31Vrp0aff99P3339vkyZOzJSNNoAwAyBKlayWvPY0l55xzTqKyAX38rUBZNbfKiKVGA+n27t2bpmAuMCOYWTZv3mxfffWVC178BrUlpcyxKIN43nnnJbrPyyr+8ssvvo9VUKRANJCCZQWWqndOr927d7vzUCZVVq1a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7/rStXpn+bEAAKIPGWUAAADAB4EyAAAA4INAGQAARIWPP/7YLr/8citVqpTFxcWlOOGK58UXX7Tzzz/fihQp4mZJbNGihS1atCjh/gMHDrgZCE8//XQrXLiw1a1b1z766CPL6TQNe1xcXKKlXr16ltMQKIeJJhupXr261a9fP1y7BAAgR2nevLmNGzcu6P2HDh2yZs2a2ZNPPhnyPs844wx74YUX7KeffrIFCxa4qcCvuOIK27Vrl7u/T58+NnfuXJswYYL9/PPPdtNNN9ktt9xiy5cvt5yudu3a9vvvvycsM2bMsJyGwXxhnHBEy/79+6148eLh2i0AAPifDh06uNsVK1aEfE1uuOGGRF8/99xz9uqrr7p9XHLJJfbdd9+56bybNGni7n/kkUfcNkuXLrVatWrl6GufJ08eO+200ywnI6MMIOQOEkmXWDqXaD4fwE98fLwrVbj00kutXLlyVqhQIatWrZp169bNfv3111QvmjK7ST96T7q0bNkyw4/JSseOHbNXXnnFSpYsaTVr1nTrGjVqZJ988on98ccf7ppNnDjRjh496oLorPbuu++610clDvnz53fXK6UMuyxevNhat27tykpUOtKwYUOXHQ+H1atXu+8dZeE7derkrlFOQ0YZAIAY1K9fP1dyoECnbdu2VqxYMVd+oGzq+++/78oQatSoEfTxderUsccff9z3PtXwrly50pUwZPQxWeHbb7+1q666yv7++2+XIZ05c6arc5YRI0ZY586d3XVSBlVvKPQGo0qVKll+nI8++qj99ttvVqZMGXc8+n9K5syZ465ngQIFXLlI0aJFbdKkSXbzzTfbli1b7IEHHkj3sVx00UUuSD/33HNt27Zt9thjj7n67mXLlrkgPqcgUAYAIMYo8zds2DBXn6vgOLAkUIPb+vbt64LoN954I+g+FPRq8cvKjhw50gWVd911V4YeM2TIELd4FMiqFKJnz54J6w4ePGgZpQztjz/+6OqS9UZBdcga0KeAdPjw4e4affHFFy44/eyzz1ygOX/+fDf2KCXvvPOOq5nWdfZz4sQJt3+dT758+VI9ztdee83OPvtst7+nn37alYEE888//9jdd99tuXLlsm+++SbhuiugbdCggQ0YMMDat2+f6Nj69+9vzzzzTIrHoKy66I2FR9n3Cy+80CpVqmRTp061du3aWU5B6QUAAGGwcePGVMsOtOhj8symbhAnT560xo0bJxs3c80117jbnTt3pmvfU6ZMcQGn9nPqqadm6DHqNqEA1lsU0GqgXuC6cChYsKArH1CWVMGogss333zTBeYDBw50bxquvPJKN3hNWV0dx+jRo1Pc59atW12gqgGIfplfXX+9KVBWV+UeobjsssuCBt1JzZ492zZs2GC33XZbojcner0VJOvNyVtvvZXoMToWlVOktARTtmxZq1y5svs+D4Uy2ypfOeWUU1zGW11FdH5aH03IKAMAEAbHjx9PVHagwWDKTl599dWJ2mopeM1sykoqg6msqAaZq+zCo4ygpLdWWIGmdO3aNcOPUfmDVwLhBbQKrBTUZiZlTVWHrNdMS+7cuRPdr68V6KakQoUKroRF2WnVgatzhjKugUHye++9Z3feead179497Oeg55NWrVolu88rb/n666+TBbta0mPPnj3uDYGC5dSMGTPGnbMy9Ndff72VLl3afcrx/fff2+TJk6MqI02gDORQw9au9F3fu9r5llMxoC9zxfr31jnnnON6z3r0sbkC5d69e7tMWmpUKrF3796Qn091x35lDqLARB/dK4OoGtPrrrsuoUZZmUgFMYHlDaFSoDRr1iwXJCoDm1mPCWb37t22efNml0mVVatWuWumAFUBt8o7FIjp+TwPP/ywXXvtte759XhlipUNVrCma9K0aVNXz63HKuv56aefuhrmadOmpXo8CgIVLN96660us6zgVc+jLhoamHf77be7zLUy2OG2bt26hDdFSakOW32jvW3S48EHH7Q2bdq4a6vrpSx1+fLlQ/pERG+M9EZNnwjojU8gry1ftCBQBrI4EM3M99EV3ljjf8czsR2gAJFIQamE2mJMgXJqg7cCKbMXLFD2+gMrsFEW9+WXX05YrzZo+rhe9cJppaBP2VIFgkmzsOF8TDAKYtV9waNsvfcc2v9ff/2VEER7tm/f7ga67dixwwXTmu9Ag/vOO+88d/8HH3zggukbb7zR9u3b57LZGsQW6qBD1QGrFllBsTLL+vRAXSf0nCp9yIwgWXSsEqwlrd4EeNukhwYD3nLLLe6aqlxGZRSqydZgx1DkzZvXLX5v4qIJgTIAAJkUKCuzlzSjFkwos8ylhWp9Bw8e7G7vuOMO1z5MGT4F0Mp+qlZUmdZQKdhVQKo6a3WJyIzHeOUEwSgY1hKMMvqB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OQvf8QDC3mmi0KkNuarIsT788EM7dOiQ9e3b14YNG+aCVS9QfuKJJ3wD5WD3ZcS6devsm2++sWuvvdbWrFlj77//vr3wwgtWsGDBZNved999duLECfvqq6/s0ksvTXSfguwvv/zScufOHdbjA6IBpRcAMiWA9luAnECBsTKvDz30kAs6Z82aZb/99luWH4cyyHLnnXdahw4dbN++ffbRRx8l227Hjh0uc1yjRo1kQbIoI33FFVe4WyCnIVAGACBMVq1aZd999521atXKTj31VBeknjx50t58880svcbKDr/11ltWsmRJV1KhQFmBroL4pFT2ocD+999/d5lwAP8fgTIAAGHiBaIKTEUD4QoXLuwCZQXMWWXatGku8L3pppvcwLwzzjjDmjZt6kox1q9fn2hb3a/yDGWWL774YnvppZfshx9+sGPHjmXZ8QKRikAZAIAwOH78uL3zzjtWrFgxa9u2rVtXpEgRNzBu8+bNrv43qwN2ZbQ9+r83qC+pV155xdq0aWM///yz9erVy+rVq2dFixa1xo0b24gRI+zvv//OsmMHIgmBMgAAYfDJJ5/Yzp077cYbb3QdIzxesOpX9pAZ/vjjD/v8889da7dGjRolrNdxaSCfSjJUmhFIbew+/fRT++WXX1xgfMcdd1ilSpVswYIFdv/991uDBg1cBw8gpyFQBgAgk7K40rJlSytfvrwLpLMi2FQgrDZvXvmHR5nu6667zrZv327Tp0/3fezZZ59t//rXv1xmXF0zli1bZueff77rsazuHEBOQ3s4AInsWj4syBUpypUCgtiyZYtroSaXXHJJ0Ov07rvvutKGzOSVVqhns1/fZi+ov/rqq1PdV506dVzNcosWLWz27NlhP1Yg0hEo/8/HH3/s+kuq16Saxevdv2rMBg4c6EYNAwAQzLhx49xgvSZNmli1atWS3a8MrzK9ClAzM1D+9ttvXflE1apVrXnz5r7bqMRi6tSpbvDeKaeckuo+VWcN5FQEyv+jj8P0S+XBBx90rXI0oEEfM/3000+uByYAAH40QE5dLdR+TcHwmWee6budAtiFCxfakiVL3GC5zCz/+Pe//22dOnXy3WbAgAE2dOhQN711v379XEs4TYzSrVs3K1OmTLIA/z//+Y/7v94EADkNgfL/dO3aNdGFUdCswRj33HOPG62sQQ0Asg6z/iFaqCRh48aNruQiWJAsClwVKCuYTU+gPGfOHOvYsaPvfQpi1Qpu4sSJrh2dBu4Fo30oUNZxKFBWt45HH33UzQyo9nC1a9d29cx//vmnzZgxw7Zu3WpVqlQJWsYBxDIC5RSUKlXK3eqXCAAAKWVxgwWxHk1jrQ4SKU0lnRJlpLUEo9KPw4cP21133ZViucQ555zj2r7Nnz/fdbVo2LCh67usoHjevHku2N61a5cVKlTIbXv33Xe749anrUBOExevz4wi1Nq1a93gCDU+17J69WrX0uapp55y735Tox/2UaNGufIJNU5Xq5zbb7/d+vTpY3nz5vV9jPavwFgjfDt37mwVK1Z0bXZCtX//fvfLRFOF6h05cq5ha1f6rq/wxposP5atnc8NedsOR2f6rh+7NzIG8xU6taHv+rRMkd2txAGLdaVr9c7uQwCAiBVqvBbRGeUxY8bY8OHD0/XY3r17u8dqWk6N1tW7a3089vDDD9tnn33mAnC/d/PqJamLJpqCdMKECRk+DwAAAESfiO6jXKNGDVc/9d5777lsctKekMFMmTLFBckKjhctWuQ+Tpo0aZLrCVmzZk330ZK6WfiZO3eu+zjq5ZdftlWrVrmZipI2ZgcAAEDsyxNNA+xy5Qotrh8yZIi77d+/v11wwQUJ6zWad/To0W6++5EjR7pgOWnNlXpGimYz0v9VuzV58mRr3759GM4IQCQIVkaSE0oystOWZ7+xSFXxoWbZfQgAIlBEZ5TTY9u2bbZ48WL3/9tuu813ZLDqjo8ePeoGL6REQbba/axfvz7TjhcAAACRKeYCZU236XWsUDsbP15bHm/bYFSCobGOKbX7UcCtgvDABQAAANEvoksv0kO9LCWlvsfKKAduK1dccYW1bNnSzWmfP39+F0SryXqtWrXcDH3BqBelJiYBAABAbIm5QFnTT4sargfj9ZcMzP42aNDA3n333YTguXLlyta9e3fr27ev5cuXL+i+HnnkEbeNR/v0AnEgGkVKGzgAALJbzAXK6aXezFrSStlnLQAAAIgtMVejXLTof7Nhmrs+mIMHD7pbJgQBACD6qAXsGWecYQUKFHCD9DWxWEolkhqbpPjg1FNPdVN9b9q0KdE2H3/8sV1++eVufJMG8Se9P6d64okn3PUIXNIz/Xo0i7lAWSUTsmXLlqDbePd52wIAgMjRvHlzGzdunO9948ePd5OH6VNgzdqrWXc1zijYYPqvv/7a/vWvf7l5FaZPn267d++2q666yv7555+EbZRca9asmT355JOZdk7Rqnbt2vb7778nLJqbIieJudKLunXrulvNU696Y7/OF0uWLHG3gT2WM0pTZWthchIAADLPiy++aPfee6/deeed7uvXXnvNTjvtNBdAa31SCo4Dvfrqq66blSYV04B98SY0W7FiBS9dEnny5HHXN6eKuYxyhQoVrH79+u7/+qFJSrPyKaOsuuLWrVuH7Xl79Ojhfui8Hs4AAEQCTZqlsoLSpUu7UgUlkG699dYUP3nN6L7UWlXlDJdeeqmVK1fOChUqZNWqVbNu3brZr7/+mu5zOXbsmOtKddlllyUK5JSBXrhwYUj72Ldvn7tVmUWkUVMBXSOVNyhOUalDsMx6IMUeimlKlCjhmhlosrQJEyaE5ZhWr17tXkNl7jt16mR//PGH5SQxl1GWAQMG2PXXX29PP/20+3jFyxwry6xOFtKzZ89ks/IBiHyH//wuuw8BiAoKVpVhfeWVV6xq1ap2yy23uDrd7du3u3KE3377LeQuTWndV79+/eyFF15wAZZarGpMkOqIlc19//33bcGCBVajRo00n9Nff/3lPrlVrXGgU045xTZs2JDq4/VYHZuCSiXWIs2jjz7qrqVmEta10/9TM2fOHFd6ojcu3usyadIku/nmm90bmAceeCDdx3PRRRe5QP3cc891E7o99thj1qJFC/dmJac0MojoQHnp0qUJga14PwRjx461qVOnJnqHq28oj34oe/XqZSNGjHDvqtQfWe+wZs2aZXv37rXGjRunq8MFAADRQn8DFdjq76j+nzt37kT3B9bohnNfyjgOGzbMDbZTcByYlFLZhFqqKoh+4403EtYPGTLELZ6///7bvvvuO5fUSjoQP728YH/z5s1uQrFweeedd1x9s843WHCuwYc6l5TazXplJGeffbbbl5J9akGbEl33u+++23LlymXffPON1alTx61XQKu2t0octm/fPuHY+vfvb88880yq18lz1VVXJfy/Zs2aduGFF7p5KhSDtWvXznKCiA6UVZiv4vuktm7d6pbA2fGS0jelAmLVDeud6/Hjx927YH2T9OnTJ9Vv1rSiRhkAcjaNi0lpJtfA4GPatGmZeiwKNDUZlo5Hfw+TBrZeyUJm7EsdI06ePOn+Bif95Paaa65xgfLO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AAAARH6g/NNPP9nNN99s69atcwGzBu2pE4YXKM+cOdP1W54yZYq1adMmHMcMAAAARHbpxdatW+2yyy6zX375xfVSfvbZZ12wHKht27aWN29e++STTzJ6rAAAAEB0BMpDhgyxXbt22bBhw2zq1KnWr1+/ZNsUKlTIateuzYx1AAAAyDmB8vTp0+3cc8+1Xr16pbhd5cqV7ffff8/IUwEAAADREyhv377datasmep2qlvev39/Rp4KAAAAiJ5AuXDhwq6rRWo2btxopUqVyshTAQAAANETKCub/MMPP9hff/0VdJvffvvNdca48MILM/JUAAAAQPQEynfccYcdOHDAunbtaocPH052/7Fjx6x79+6uXZy2BQAAAHJEH+VOnTrZe++9Z59++qkb1HfllVe69coga4Cf1m/evNm1kFOvZQAAACBHZJQ1095nn31mt956q23bts1ee+01t37ZsmU2cuRIFyS3a9fOPv74Y4t0H330kV1//fVWqVIl19Lu/PPPt+eff95lwwEAAJDzZHhmviJFiris8sCBA23atGn266+/2smTJ61ixYpuEpI6depYNHjuuedcGztNmnLqqae66bgfffRRW758ub311lvZfXgAAACItkDZo9ILLdFKmfGyZcsmfH3ppZe6WQb1BsALngEAAJBz5MpocKnscSwIDJI9XqcO9YsGAABAzpKhQPm6665zJRYPP/ywrV692sJt7dq19tJLL1nHjh1dK7o8efK4yUsGDx4c0uMnTpxozZs3t5IlS7qez5pKW9nhUOuOv/nmG8uXL59VrVo1g2cCAACAHBUoX3DBBW5q6v/85z9Wo0YNa9Sokb366qthm4VvzJgxrnuGaoRXrFhhJ06cCPmxvXv3tptuusnmz59vDRo0cB05NLhQQX2LFi3s77//TvHxq1atsuHDh9s999xjxYoVC8PZAJnv+MGtvgsAAMjiQHnJkiVusJuC0jJlyth3331n9957r5UrV87uvPNOmz17dkZ274Lvfv36ucGCylh36NAhpMdNmTLFBbkaaLho0SKbMWOGTZo0ydatW+cy0/PmzXO1x8FoApW2bdvaWWedZU8//XSGzgEAAAA5MFD2gtkXXnjBtYdTG7hrrrnGlTa8++67dvnll1uVKlXsySefdDP0pZUmMlG2+rbbbnMDBXPlCu1whwwZ4m779+/vst4eBfOj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QBlIg8qVK1tcXFyqy7hx47iu2fC6bNq0KWz79F7LWJQZ1yvSjyESzjkcYuU8wkXXIenv38GDB2don+eee26i/TVv3jxsx4vokye7DwCIRo0bN7azzjor6P0p3RfJf4B/++0327hxo/s/uI7RJBa+f2PhHLJL4cKFrX379u7/tWvXztC+rr/+evv999/tjz/+sBkzZoTpCBGtCJSBdOjatat17NiRaxchZs2aZcePH7fy5ctn96EgQsXK90isnEe4lSlTJmyf5A0dOtTdzp07l0AZBMoAol/VqlWz+xAQ4WLleyRWzgOIFtQoA5lozZo1rsatZMmSduTIkaDb1atXz233ySefJFr/999/2/PPP28NGza0EiVKWIECBaxatWr20EMP2a5du1Ksq500aZI1adLEihUr5j6WVLnItGnTkj1GWRg9Rh/5SpUqVRLV5ymrEkx8fLzL5OTKlSvZ8Xz//fcJ+xg9enSyx5555pnuvl9//TXZfWk975TqNlesWGHt2rVzx1moUCGrWbOmDRs2zE6ePBlyvWco1zIj1zHQ4cOH3fHp+fR9kz9/fjvjjDOsTZs2Nn78+GTb6zrrujRo0MBOO+00y5cvn5166qlu+6+++iqk50zv83v1oSmVCaS1pjat5xPqdU/tOLZu3Wr/+te/7Oyzz3bfb8WLF3ev89ixY+3EiRNh+VkLJi3fO8HOI/B43n33XXf9ihQpYmXLlrVbb73VNm/enPAzO3LkSKtTp447Vv1c6NOxHTt2BD2+tP48pkbXOJSxHlrefPNNC4d169ZZ586d3bXV97Sujb6vr7766rA9B2JUPICQnXHGGfH6sXnzzTdDfszFF1/sHvP+++/73r98+XJ3/6mnnhp//PjxhPXbtm2Lr1mzpruvVKlS8Zdddln89ddfn3AMlStXjt+0aVOifWm9lsceeyw+Li4uvnHjxvE333xzfO3atd16rfv4448TPebbb7+Nv+uuu+ILFy7stmnXrp372ltWr16d4vndeOON7nEffvhhovX/93//l3A8Ou5AGzZscOurVKmSbH/pOW/vvo0bNyZaP3fu3PiCBQu6+6pWrRp/yy23xF9++eXx+fLlc9cl2OPScy0zeh1l8+bN8dWrV3ePL1SokDtWHXPTpk3jixcv7o43qZYtW8bnypXLXbPWrVu71+OCCy5IOP5hw4Yle0yw807r8+vx2tbvuFJ7rmDr03o+oV73lF7r77//3n2v6f5KlSq51/nKK6+ML1CggFt3xRVXxB89ejTDP2vBpOV7J9h5eMfTv3//+Dx58sS3aNEivn379u58tL5ixYrxu3fvjr/pppvceen89HN1yimnuPtr1aqV7BzT+/OYkr///ju+Y8eOic6vWrVqbl8XXnhhovVa9D2ZklC+B3/++ef4YsWKue30XDfccIP7vtLv5iJFirjXzM+cOXPcYy655JKQzw+xh0AZyORA+dVXX034Y+unT58+7v4HHnggYd3JkyfdH16t79KlS/z+/fsT7lMwrW1136WXXur7x7JEiRLx3333XaL7Hn/8cXffOeeck+K5+QUSKRk7dqx73N13351ovY5NAem5557rjueff/5J9THpPW+/Yz98+HB8+fLlE67tiRMnEu5buXKle2PiXa+UAuW0Xsv0XkcdX7169dxjW7VqFb9jx45kAcbnn3+e7HHTpk2L3759e7L1CxYscMFB3rx547du3ZrqMabn+TMjUE7P+aS0v9TuP3LkSMJ99957b/yxY8cSvaFTIKj7BgwYELaftWBC+d5JLVAuXbp0/I8//pjo56BJkybuPgW8esMYGNju3Lkz/qyzznL3v/vuu2H5eUwrBe3az8SJE9P82FC+Bzt16uS2GTx4cLL7dH2+/vpr38cRKEMIlIE08P5Ipbbs2bMn4TH646LsnLJkSf/A649y2bJl3WNWrFiRsP6LL75w6+rUqZMoyxwY1NSoUcNto2yJx3v+ESNGJHuMAgJlBXW/X5YmvQGeX3ZYf3zy58/vMjEPPviguz8wmAiWhU7vefsd+9tvv53wBzQw+PGMHDkypEA5rdcyvddxypQp7nHlypWLP3DgQHw4PPLII26fo0aNSvUY0/P8mREop+d8QtlfsPvfeecdt/700093r2tSH330kbu/aNGi7s1COH7WMjNQ9rs2ymx79/u92Xr++efdfQoow/HzmFbem9Z169al+bGhfA/qkwlts3Tp0jTtm0AZQtcLIBPaw6mu0lO0aFHXtujtt992yyOPPJJw3+eff247d+509YTnn39+ovWi2to8eZL/mKomuFmzZq7+dsGCBVajRo1E96ueMynV5akueNmyZbZt2zarWLGihYP2qbo/tbTasGGDG2z07bff2tGjR+3yyy+3+vXr23/+8x9XX3rR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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "base = -5\n", "for k in filename.keys():\n", @@ -349,6 +526,14 @@ "plt.savefig(\"figures/DIS_weight_timing_distributions.pdf\",dpi=100)\n", "plt.show()" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc353395-e198-4352-8524-d0cbdbe0264a", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { @@ -367,7 +552,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.4" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/resources/examples/example2/DipolePortal_CCM.py b/resources/examples/example2/DipolePortal_CCM.py index 6bd5fa653..2ec87a867 100644 --- a/resources/examples/example2/DipolePortal_CCM.py +++ b/resources/examples/example2/DipolePortal_CCM.py @@ -2,6 +2,7 @@ import numpy as np import siren from siren import utilities +from siren._util import GenerateEvents,SaveEvents # Define a DarkNews model model_kwargs = { @@ -17,7 +18,7 @@ } # Number of events to inject -events_to_inject = 1 +events_to_inject = 100 # Experiment to run experiment = "CCM" @@ -26,14 +27,24 @@ # Particle to inject primary_type = siren.dataclasses.Particle.ParticleType.NuMu +table_name = f"DarkNewsTables-v{siren.utilities.darknews_version()}" +table_name += "Dipole_M%2.2e_mu%2.2e"%(model_kwargs["m4"],model_kwargs["mu_tr_mu4"]) + + # Load DarkNews processes primary_processes, secondary_processes = utilities.load_processes( - f"DarkNewsTables-v{siren.utilities.darknews_version()}", + "DarkNewsTables", primary_type=primary_type, detector_model = detector_model, + table_name = table_name, **model_kwargs, ) +print(primary_processes) + +# for cross_section in primary_processes[primary_type].CrossSections: +# print(cross_section) + # Mass distribution mass_ddist = siren.distributions.PrimaryMass(0) @@ -82,18 +93,16 @@ def stop(datum, i): return secondary_type != siren.dataclasses.Particle.ParticleType.N4 injector = siren.injection.Injector() -injector.number_of_events = 1 +injector.number_of_events = events_to_inject injector.detector_model = detector_model injector.primary_type = primary_type injector.primary_interactions = primary_processes[primary_type] injector.primary_injection_distributions = primary_injection_distributions injector.secondary_interactions = secondary_processes injector.secondary_injection_distributions = secondary_injection_distributions -injector.stopping_condition = stop +events,gen_times = GenerateEvents(injector) -# Generate events -events = [injector.generate_event() for _ in range(events_to_inject)] # Output the events os.makedirs("output", exist_ok=True) @@ -107,4 +116,10 @@ def stop(datum, i): weighter.primary_physical_distributions = primary_physical_distributions weighter.secondary_physical_distributions = {} +SaveEvents(events,weighter,gen_times,output_filename="output/CCM_Dipole") + + + weights = [weighter(event) for event in events] + + diff --git a/resources/examples/example2/PaperPlots.ipynb b/resources/examples/example2/PaperPlots.ipynb index ef9d6f36f..a7f2b85ea 100644 --- a/resources/examples/example2/PaperPlots.ipynb +++ b/resources/examples/example2/PaperPlots.ipynb @@ -514,7 +514,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.4" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/resources/processes/DarkNewsTables/processes.py b/resources/processes/DarkNewsTables/processes.py index d9e4b802e..cd393f76d 100644 --- a/resources/processes/DarkNewsTables/processes.py +++ b/resources/processes/DarkNewsTables/processes.py @@ -388,20 +388,23 @@ def load_processes( target_types: Optional[List[Any]] = None, fill_tables_at_start: bool = False, Emax: Optional[float] = None, - m4: Optional[float] = None, - mu_tr_mu4: Optional[float] = None, - UD4: float = 0, - Umu4: float = 0, - epsilon: float = 0.0, - gD: float = 0.0, - decay_product: str = "photon", - noHC: bool = True, - HNLtype: str = "dirac", nuclear_targets: Optional[List[str]] = None, detector_model: Optional[Any] = None, tolerance: float = 1e-6, interp_tolerance: float = 5e-2, always_interpolate: bool = True, + table_name: Optional[str] = None, + **model_kwargs, + # m4: Optional[float] = None, + # mu_tr_mu4: Optional[float] = None, + # UD4: float = 0, + # Umu4: float = 0, + # epsilon: float = 0.0, + # gD: float = 0.0, + # decay_product: str = "photon", + # noHC: bool = True, + # HNLtype: str = "dirac", + ) -> List[Any]: """ Loads and returns a list of cross-section and decay objects based on the given parameters. @@ -411,20 +414,12 @@ def load_processes( target_types (Optional[List[Any]]): List of target particle types. fill_tables_at_start (bool): Whether to fill interpolation tables at start. Emax (Optional[float]): Maximum energy for table filling. - m4 (Optional[float]): Mass parameter. - mu_tr_mu4 (Optional[float]): Transition magnetic moment parameter. - UD4 (float): UD4 parameter. - Umu4 (float): Umu4 parameter. - epsilon (float): Epsilon parameter. - gD (float): gD parameter. - decay_product (str): Type of decay product. - noHC (bool): noHC parameter. - HNLtype (str): Type of HNL (e.g., "dirac"). - nuclear_targets (Optional[List[str]]): List of nuclear targets. detector_model (Optional[Any]): Detector model object. tolerance (float): Tolerance for calculations. interp_tolerance (float): Interpolation tolerance. always_interpolate (bool): Whether to always interpolate. + table_name: Optional[str] = None, + **model_kwargs: dictionary of DarkNews model arguments Returns: List[Any]: A list of loaded cross-section and decay objects. @@ -442,18 +437,10 @@ def load_processes( nuclear_targets = GetDetectorModelTargets(detector_model)[1] base_path = os.path.dirname(os.path.abspath(__file__)) - table_dir = os.path.join(base_path, "Dipole_M%2.2e_mu%2.2e" % (m4, mu_tr_mu4)) + table_dir = os.path.join(base_path, table_name) models = ModelContainer( - nuclear_targets=nuclear_targets, - m4=m4, - mu_tr_mu4=mu_tr_mu4, - UD4=UD4, - Umu4=Umu4, - epsilon=epsilon, - gD=gD, - decay_product=decay_product, - noHC=noHC, + **model_kwargs ) cross_sections = load_cross_sections( From 6210de45180e358285958ab4f1f3ccb873e3cc54 Mon Sep 17 00:00:00 2001 From: Nicholas Kamp Date: Thu, 24 Oct 2024 16:10:55 -0400 Subject: [PATCH 92/94] starting to get second example working. adding functionality to save DarkNews tables and objects. still some issues in the pickling --- python/_util.py | 35 +++++++++++++++++++ .../examples/example2/DipolePortal_CCM.py | 17 ++++++--- .../processes/DarkNewsTables/DarkNewsDecay.py | 6 ++-- .../processes/DarkNewsTables/processes.py | 35 +++++++++++-------- 4 files changed, 72 insertions(+), 21 deletions(-) diff --git a/python/_util.py b/python/_util.py index 956853f0a..06b675c9c 100644 --- a/python/_util.py +++ b/python/_util.py @@ -8,9 +8,16 @@ import time from siren import dataclasses as _dataclasses +from siren import math as _math +from siren.interactions import DarkNewsCrossSection,DarkNewsDecay import numpy as np import awkward as ak import h5py +import pickle +try: + from DarkNews.nuclear_tools import NuclearTarget +except: + pass THIS_DIR = os.path.abspath(os.path.dirname(__file__)) @@ -966,3 +973,31 @@ def SaveEvents(events, # Load events from the custom SIREN event format def LoadEvents(filename): return _dataclasses.LoadInteractionTrees(filename) + +def SaveDarkNewsProcesses(table_dir, + primary_processes, + primary_ups_keys, + secondary_processes, + secondary_dec_keys, + pickles=True): + for primary in primary_processes.keys(): + for xs,ups_key in zip(primary_processes[primary],primary_ups_keys[primary]): + subdir = "_".join(["CrossSection"] + [str(x) if type(x)!=NuclearTarget else str(x.name) for x in ups_key]) + table_subdir = os.path.join(table_dir, subdir) + os.makedirs(table_subdir,exist_ok=True) + print("Saving cross section table at %s" % table_subdir) + xs.FillInterpolationTables() + xs.save_to_table(table_subdir) + # if pickles: + # with open(os.path.join(table_subdir, "xs_object.pkl"),"wb") as f: + # pickle.dump(xs,f) + for secondary in secondary_processes.keys(): + for dec,dec_key in zip(secondary_processes[secondary],secondary_dec_keys[secondary]): + subdir = "_".join(["Decay"] + [str(x) if type(x)!=NuclearTarget else str(x.name) for x in dec_key]) + table_subdir = os.path.join(table_dir, subdir) + os.makedirs(table_subdir,exist_ok=True) + print("Saving decay object at %s" % table_subdir) + dec.save_to_table(table_subdir) + if pickles: + with open(os.path.join(table_subdir, "dec_object.pkl"),"wb") as f: + pickle.dump(dec,f) diff --git a/resources/examples/example2/DipolePortal_CCM.py b/resources/examples/example2/DipolePortal_CCM.py index 2ec87a867..4d7e925f8 100644 --- a/resources/examples/example2/DipolePortal_CCM.py +++ b/resources/examples/example2/DipolePortal_CCM.py @@ -2,7 +2,7 @@ import numpy as np import siren from siren import utilities -from siren._util import GenerateEvents,SaveEvents +from siren._util import GenerateEvents,SaveEvents,get_processes_model_path,SaveDarkNewsProcesses # Define a DarkNews model model_kwargs = { @@ -18,7 +18,7 @@ } # Number of events to inject -events_to_inject = 100 +events_to_inject = 1 # Experiment to run experiment = "CCM" @@ -27,12 +27,14 @@ # Particle to inject primary_type = siren.dataclasses.Particle.ParticleType.NuMu -table_name = f"DarkNewsTables-v{siren.utilities.darknews_version()}" +table_name = f"DarkNewsTables-v{siren.utilities.darknews_version()}/" table_name += "Dipole_M%2.2e_mu%2.2e"%(model_kwargs["m4"],model_kwargs["mu_tr_mu4"]) +table_dir = os.path.join(get_processes_model_path("DarkNewsTables"),table_name) +os.makedirs(table_dir,exist_ok=True) # Load DarkNews processes -primary_processes, secondary_processes = utilities.load_processes( +primary_processes, secondary_processes, primary_ups_keys, secondary_dec_keys = utilities.load_processes( "DarkNewsTables", primary_type=primary_type, detector_model = detector_model, @@ -118,6 +120,13 @@ def stop(datum, i): SaveEvents(events,weighter,gen_times,output_filename="output/CCM_Dipole") +# save cross section tables +SaveDarkNewsProcesses(table_dir, + primary_processes, + primary_ups_keys, + secondary_processes, + secondary_dec_keys) + weights = [weighter(event) for event in events] diff --git a/resources/processes/DarkNewsTables/DarkNewsDecay.py b/resources/processes/DarkNewsTables/DarkNewsDecay.py index 0b400c8cd..6cc408729 100644 --- a/resources/processes/DarkNewsTables/DarkNewsDecay.py +++ b/resources/processes/DarkNewsTables/DarkNewsDecay.py @@ -195,11 +195,11 @@ def load_from_table(self, table_dir): self.decay_norm, self.decay_integrator = pickle.load(f) def save_to_table(self, table_dir): - with open(os.path.join(table_dir, "decay.pkl")) as f: - pickle.dump(f, { + with open(os.path.join(table_dir, "decay.pkl"),'wb') as f: + pickle.dump({ "decay_integrator": self.decay_integrator, "decay_norm": self.decay_norm - }) + }, f) # serialization method def get_representation(self): diff --git a/resources/processes/DarkNewsTables/processes.py b/resources/processes/DarkNewsTables/processes.py index cd393f76d..5e5c63caa 100644 --- a/resources/processes/DarkNewsTables/processes.py +++ b/resources/processes/DarkNewsTables/processes.py @@ -8,6 +8,7 @@ siren._util.load_module("logger", logger_file) from siren.DNModelContainer import ModelContainer +from DarkNews.nuclear_tools import NuclearTarget # Import PyDarkNewsDecay and PyDarkNewsCrossSection decay_file = os.path.join(base_path, "DarkNewsDecay.py") @@ -99,8 +100,8 @@ def load_cross_section_from_table( interp_tolerance=5e-2, always_interpolate=True, ): - subdir = "_".join(["CrossSection"] + [str(x) for x in upscattering_key]) - table_subdir = os.path.join(table_dir, subdir) + # subdir = "_".join(["CrossSection"] + [str(x) if type(x)!=NuclearTarget else str(x.name) for x in upscattering_key]) + # table_subdir = os.path.join(table_dir, subdir) cross_section = load_cross_section( model_container, @@ -109,7 +110,7 @@ def load_cross_section_from_table( interp_tolerance=interp_tolerance, always_interpolate=always_interpolate, ) - cross_section.load_from_table(table_subdir) + cross_section.load_from_table(table_dir) return cross_section @@ -121,8 +122,8 @@ def load_cross_section_from_pickle( always_interpolate=True, ): import pickle - subdir = "_".join(["CrossSection"] + [str(x) for x in upscattering_key]) - table_subdir = os.path.join(table_dir, subdir) + # subdir = "_".join(["CrossSection"] + [str(x) if type(x)!=NuclearTarget else str(x.name) for x in upscattering_key]) + # table_subdir = os.path.join(table_dir, subdir) fname = os.path.join(table_dir, "xs_object.pkl") with open(fname, "rb") as f: xs_obj = pickle.load(f) @@ -165,7 +166,7 @@ def attempt_to_load_cross_section( if len(preferences) == 0: raise ValueError("preferences must have at least one entry") - subdir = "_".join(["CrossSection"] + [str(x) for x in ups_key]) + subdir = "_".join(["CrossSection"] + [str(x) if type(x)!=NuclearTarget else str(x.name) for x in ups_key]) loaded = False cross_section = None for p in preferences: @@ -240,9 +241,9 @@ def load_cross_sections( if table_dir is None: table_dir = "" - cross_sections = [] + cross_sections = {} for ups_key, ups_case in models.ups_cases.items(): - cross_sections.append( + cross_sections[ups_key] = ( attempt_to_load_cross_section(models, ups_key, table_dir, preferences, @@ -365,9 +366,9 @@ def load_decays( if table_dir is None: table_dir = "" - decays = [] + decays = {} for decay_key, dec_case in models.dec_cases.items(): - decays.append(attempt_to_load_decay(models, decay_key, table_dir, preferences)) + decays[decay_key] = attempt_to_load_decay(models, decay_key, table_dir, preferences) return decays @@ -435,6 +436,8 @@ def load_processes( if nuclear_targets is None: nuclear_targets = GetDetectorModelTargets(detector_model)[1] + model_kwargs["nuclear_targets"] = list(nuclear_targets) + if target_types: model_kwargs["nuclear_targets"]+=list(target_types) base_path = os.path.dirname(os.path.abspath(__file__)) table_dir = os.path.join(base_path, table_name) @@ -456,7 +459,7 @@ def load_processes( table_dir=table_dir, ) - cross_sections = [xs for xs in cross_sections if len([s for s in xs.GetPossibleSignatures() if s.primary_type == primary_type])>0] + cross_sections = {k:xs for k,xs in cross_sections.items() if len([s for s in xs.GetPossibleSignatures() if s.primary_type == primary_type])>0} if fill_tables_at_start: if Emax is None: @@ -468,25 +471,29 @@ def load_processes( cross_section.FillInterpolationTables(Emax=Emax) primary_processes = collections.defaultdict(list) + primary_ups_keys = collections.defaultdict(list) # Loop over available cross sections and save those which match primary type - for cross_section in cross_sections: + for ups_key,cross_section in cross_sections.items(): if primary_type == siren.dataclasses.Particle.ParticleType( cross_section.ups_case.nu_projectile.pdgid ): primary_processes[primary_type].append(cross_section) + primary_ups_keys[primary_type].append(ups_key) secondary_processes = collections.defaultdict(list) + secondary_dec_keys = collections.defaultdict(list) # Loop over available decays, group by parent type - for decay in decays: + for dec_key,decay in decays.items(): secondary_type = siren.dataclasses.Particle.ParticleType( decay.dec_case.nu_parent.pdgid ) secondary_processes[secondary_type].append(decay) + secondary_dec_keys[secondary_type].append(dec_key) #holder = Holder() #holder.primary_processes = primary_processes #holder.secondary_processes = secondary_processes - return dict(primary_processes), dict(secondary_processes) + return dict(primary_processes), dict(secondary_processes), dict(primary_ups_keys), dict(secondary_dec_keys) From b3ef5ca4a87a694faa1f00482c87e4611948364b Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Tue, 17 Dec 2024 14:46:17 -0700 Subject: [PATCH 93/94] Support for Interaction class --- projects/interactions/private/pybindings/CrossSection.h | 3 ++- projects/interactions/private/pybindings/Decay.h | 3 ++- .../interactions/private/pybindings/InteractionCollection.h | 2 ++ projects/interactions/private/pybindings/interactions.cxx | 3 +++ 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/projects/interactions/private/pybindings/CrossSection.h b/projects/interactions/private/pybindings/CrossSection.h index 0e8a1ac77..13c71a16f 100644 --- a/projects/interactions/private/pybindings/CrossSection.h +++ b/projects/interactions/private/pybindings/CrossSection.h @@ -6,6 +6,7 @@ #include #include +#include "../../public/SIREN/interactions/Interaction.h" #include "../../public/SIREN/interactions/CrossSection.h" #include "../../public/SIREN/interactions/pyCrossSection.h" #include "../../../dataclasses/public/SIREN/dataclasses/Particle.h" @@ -18,7 +19,7 @@ void register_CrossSection(pybind11::module_ & m) { using namespace pybind11; using namespace siren::interactions; - class_, pyCrossSection>(m, "CrossSection") + class_, pyCrossSection, Interaction>(m, "CrossSection") .def(init<>()) .def("__eq__", [](const CrossSection &self, const CrossSection &other){ return self == other; }) .def("equal", &CrossSection::equal) diff --git a/projects/interactions/private/pybindings/Decay.h b/projects/interactions/private/pybindings/Decay.h index 8c0152428..91ee0a561 100644 --- a/projects/interactions/private/pybindings/Decay.h +++ b/projects/interactions/private/pybindings/Decay.h @@ -6,6 +6,7 @@ #include #include +#include "../../public/SIREN/interactions/Interaction.h" #include "../../public/SIREN/interactions/CrossSection.h" #include "../../public/SIREN/interactions/Decay.h" #include "../../public/SIREN/interactions/pyDecay.h" @@ -17,7 +18,7 @@ void register_Decay(pybind11::module_ & m) { using namespace pybind11; using namespace siren::interactions; - class_, pyDecay>(m, "Decay") + class_, pyDecay, Interaction>(m, "Decay") .def("TotalDecayLength",&Decay::TotalDecayLength) .def("TotalDecayLengthForFinalState",&Decay::TotalDecayLengthForFinalState); diff --git a/projects/interactions/private/pybindings/InteractionCollection.h b/projects/interactions/private/pybindings/InteractionCollection.h index 1df424399..b56074f86 100644 --- a/projects/interactions/private/pybindings/InteractionCollection.h +++ b/projects/interactions/private/pybindings/InteractionCollection.h @@ -6,6 +6,7 @@ #include #include +#include "../../public/SIREN/interactions/Interaction.h" #include "../../public/SIREN/interactions/CrossSection.h" #include "../../public/SIREN/interactions/InteractionCollection.h" #include "../../public/SIREN/interactions/Decay.h" @@ -22,6 +23,7 @@ void register_InteractionCollection(pybind11::module_ & m) { .def(init>>()) .def(init>>()) .def(init>, std::vector>>()) + .def(init>>()) .def(self == self) .def("GetCrossSections",&InteractionCollection::GetCrossSections, return_value_policy::reference_internal) .def("GetDecays",&InteractionCollection::GetDecays, return_value_policy::reference_internal) diff --git a/projects/interactions/private/pybindings/interactions.cxx b/projects/interactions/private/pybindings/interactions.cxx index e030ac759..bf2282e05 100644 --- a/projects/interactions/private/pybindings/interactions.cxx +++ b/projects/interactions/private/pybindings/interactions.cxx @@ -1,6 +1,7 @@ #include +#include "../../public/SIREN/interactions/Interaction.h" #include "../../public/SIREN/interactions/CrossSection.h" #include "../../public/SIREN/interactions/NeutrissimoDecay.h" #include "../../public/SIREN/interactions/InteractionCollection.h" @@ -10,6 +11,7 @@ #include "../../public/SIREN/interactions/DarkNewsCrossSection.h" #include "../../public/SIREN/interactions/DarkNewsDecay.h" +#include "./Interaction.h" #include "./CrossSection.h" #include "./DipoleFromTable.h" #include "./DarkNewsCrossSection.h" @@ -32,6 +34,7 @@ using namespace pybind11; PYBIND11_MODULE(interactions,m) { using namespace siren::interactions; + register_Interaction(m); register_CrossSection(m); register_Decay(m); register_DipoleFromTable(m); From 83fe87b273f79a610ec51627b742339d066c411e Mon Sep 17 00:00:00 2001 From: Austin Schneider Date: Wed, 18 Dec 2024 09:32:35 -0700 Subject: [PATCH 94/94] Interaction pybindings --- .../private/pybindings/Interaction.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 projects/interactions/private/pybindings/Interaction.h diff --git a/projects/interactions/private/pybindings/Interaction.h b/projects/interactions/private/pybindings/Interaction.h new file mode 100644 index 000000000..07abf920a --- /dev/null +++ b/projects/interactions/private/pybindings/Interaction.h @@ -0,0 +1,19 @@ +#include +#include +#include + +#include +#include +#include + +#include "../../public/SIREN/interactions/Interaction.h" +#include "../../../dataclasses/public/SIREN/dataclasses/Particle.h" +#include "../../../geometry/public/SIREN/geometry/Geometry.h" +#include "../../../utilities/public/SIREN/utilities/Random.h" + +void register_Interaction(pybind11::module_ & m) { + using namespace pybind11; + using namespace siren::interactions; + + class_>(m, "Interaction"); +}