From e7245c9d1d1efa086fe3e49126b980656ddfe7c6 Mon Sep 17 00:00:00 2001 From: yardasol Date: Tue, 4 Apr 2023 20:58:44 -0500 Subject: [PATCH 01/62] remove pyne --- environment.yml | 5 +- examples/msbr/msbr_objects.json | 4 +- examples/tap/tap_objects.json | 14 +- requirements.txt | 2 +- saltproc/app.py | 24 +- saltproc/depcode.py | 4 +- saltproc/materialflow.py | 243 +++++++++------ saltproc/openmc_depcode.py | 46 ++- saltproc/process.py | 129 ++++++-- saltproc/serpent_depcode.py | 256 +++++++-------- saltproc/simulation.py | 151 +++++---- saltproc/version.py | 5 +- setup.py | 5 + .../basic_reprocessing/test.py | 46 +-- .../database_storage/test.py | 295 +++++++----------- .../file_interface_openmc/test.py | 19 +- .../tap_processes.json | 14 +- .../run_constant_reprocessing_serpent/test.py | 177 +++++++---- tests/msbr_processes.json | 4 +- tests/tap_processes.json | 14 +- tests/unit_tests/test_app.py | 8 +- tests/unit_tests/test_materialflow.py | 15 +- tests/unit_tests/test_process.py | 18 +- tests/unit_tests/test_separator.py | 18 +- tests/unit_tests/test_serpent_depcode.py | 188 +++++------ tests/unit_tests/test_sparger.py | 18 +- 26 files changed, 919 insertions(+), 803 deletions(-) diff --git a/environment.yml b/environment.yml index d3e27cda0..360cf1922 100644 --- a/environment.yml +++ b/environment.yml @@ -3,8 +3,8 @@ channels: - conda-forge - defaults dependencies: - - pyne>=0.5.11=nomoab_noopenmc* - - numpy>=1.14.0 + - numpy + - openmc - pytables - networkx - pydot @@ -12,3 +12,4 @@ dependencies: - jsonschema - pip: - argparse==1.4.0 + - serpentTools diff --git a/examples/msbr/msbr_objects.json b/examples/msbr/msbr_objects.json index 2eb26bc3b..a43f57552 100644 --- a/examples/msbr/msbr_objects.json +++ b/examples/msbr/msbr_objects.json @@ -94,8 +94,8 @@ "volume": 100000000, "mass": 496020000, "comp": { - "Th-232": 0.55, - "U-233": 0.45 + "Th232": 0.55, + "U233": 0.45 } } } diff --git a/examples/tap/tap_objects.json b/examples/tap/tap_objects.json index b0ec9b18f..8db0b1839 100644 --- a/examples/tap/tap_objects.json +++ b/examples/tap/tap_objects.json @@ -109,11 +109,11 @@ "volume": 100000000, "mass": 496020000, "comp": { - "Li-6": 0.000002418, - "Li-7": 0.0483577563, - "F-19": 0.3296428341, - "U-235": 0.0310998496, - "U-238": 0.590897142 + "Li6": 0.000002418, + "Li7": 0.0483577563, + "F19": 0.3296428341, + "U235": 0.0310998496, + "U238": 0.590897142 } } } @@ -136,8 +136,8 @@ "volume": 10000, "mass": 58730, "comp": { - "Gd-158": 0.5, - "Gd-160": 0.5 + "Gd158": 0.5, + "Gd160": 0.5 } } } diff --git a/requirements.txt b/requirements.txt index b4f1f11eb..f08348840 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ -pyne numpy scipy json @@ -6,3 +5,4 @@ jsonschema pytables networkx pydot +serpentTools diff --git a/saltproc/app.py b/saltproc/app.py index a2bc60dd2..9de9fcae3 100644 --- a/saltproc/app.py +++ b/saltproc/app.py @@ -69,7 +69,7 @@ def run(): # Reprocessing here print("\nMass and volume of fuel before reproc: %f g, %f cm3" % (mats['fuel'].mass, - mats['fuel'].vol)) + mats['fuel'].volume)) # print("Mass and volume of ctrlPois before reproc %f g; %f cm3" % # (mats['ctrlPois'].mass, # mats['ctrlPois'].vol)) @@ -78,22 +78,24 @@ def run(): dot_file) print("\nMass and volume of fuel after reproc: %f g, %f cm3" % (mats['fuel'].mass, - mats['fuel'].vol)) + mats['fuel'].volume)) # print("Mass and volume of ctrlPois after reproc %f g; %f cm3" % # (mats['ctrlPois'].mass, # mats['ctrlPois'].vol)) + #breakpoint() waste_and_feed_streams = refill_materials(mats, extracted_mass, waste_streams, process_file) print("\nMass and volume of fuel after REFILL: %f g, %f cm3" % (mats['fuel'].mass, - mats['fuel'].vol)) + mats['fuel'].volume)) # print("Mass and volume of ctrlPois after REFILL %f g; %f cm3" % # (mats['ctrlPois'].mass, # mats['ctrlPois'].vol)) print("Removed mass [g]:", extracted_mass) # Store in DB after reprocessing and refill (right before next depl) + #breakpoint() simulation.store_after_repr(mats, waste_and_feed_streams, step_idx) depcode.update_depletable_materials(mats, simulation.burn_time) @@ -470,6 +472,7 @@ def reprocess_materials(mats, process_file, dot_file): # waste_streams[mat_name]['removal_tb_dy'] = waste_stream # mats[mat_name] = thru_flow + #assert 1 == 2 extracted_mass[mat_name] = \ inmass[mat_name] - float(mats[mat_name].mass) @@ -590,7 +593,7 @@ def refill_materials(mats, extracted_mass, waste_streams, process_file): representing those material feed streams. """ - print('Fuel before refilling: ^^^', mats['fuel'].print_attr()) + #print('Fuel before refilling: ^^^', mats['fuel'].print_attr()) feeds = get_feeds(process_file) refill_mats = OrderedDict() # Get feed group for each material @@ -603,8 +606,8 @@ def refill_materials(mats, extracted_mass, waste_streams, process_file): mats[mat] += refill_mats[mat] print('Refilled fresh material: %s %f g' % (mat, refill_mats[mat].mass)) - print('Refill Material: ^^^', refill_mats[mat].print_attr()) - print('Fuel after arefill: ^^^', mats[mat].print_attr()) + #print('Refill Material: ^^^', refill_mats[mat].print_attr()) + #print('Fuel after arefill: ^^^', mats[mat].print_attr()) return waste_streams @@ -639,9 +642,8 @@ def get_feeds(process_file): for mat in j: feeds[mat] = OrderedDict() for feed_name, feed_data in j[mat]['feeds'].items(): - nucvec = feed_data['comp'] - feeds[mat][feed_name] = Materialflow(nucvec) - feeds[mat][feed_name].mass = feed_data['mass'] - feeds[mat][feed_name].density = feed_data['density'] - feeds[mat][feed_name].vol = feed_data['volume'] + comp = feed_data['comp'] + feeds[mat][feed_name] = Materialflow(comp=comp, + density=feed_data['density'], + volume=feed_data['volume']) return feeds diff --git a/saltproc/depcode.py b/saltproc/depcode.py index fc52c8855..3351af634 100644 --- a/saltproc/depcode.py +++ b/saltproc/depcode.py @@ -191,7 +191,7 @@ def read_plaintext_file(self, file_path): return file_lines @abstractmethod - def convert_nuclide_code_to_name(self, nuc_code): + def nuclide_code_to_name(self, nuc_code): """Converts depcode nuclide code to symbolic nuclide name. Parameters @@ -207,7 +207,7 @@ def convert_nuclide_code_to_name(self, nuc_code): """ @abstractmethod - def _convert_name_to_nuccode(self, nucname): + def name_to_nuclide_code(self, nucname): """Converts depcode nuclide name to ZA nuclide code Parameters diff --git a/saltproc/materialflow.py b/saltproc/materialflow.py index 23fdcceb7..0a920669a 100644 --- a/saltproc/materialflow.py +++ b/saltproc/materialflow.py @@ -1,75 +1,128 @@ """Materialflow module""" import copy +import math from collections import Counter -from pyne.material import Material as pymat +import numpy as np +from openmc import Material -class Materialflow(pymat): +class Materialflow(Material): """ Class contains information about burnable material flow. Child class of - :class:`pyne.Material`. + :class:`openmc.Material`. Parameters ---------- - :class:`pyne.Material` - PyNE Material parent class containing nuclide vector, density, - mass, atoms_per_molecule, metadata - temp : float - temperature of the material flow (K) + comp : dict of str to float + Dictionary mapping element or nuclide names to their weight + percent. + density : float + Material density [g/cm^3] + volume : float + Material volume [cm^3] mass_flowrate : float - mass flow rate of the material flow (g/s) + mass flow rate of the material flow [g/s] void_frac : float - void fraction in the material (%) + void fraction in the material [%] burnup : float material burnup at the end of depletion step [MWd/kgU] + kwargs : dict + Key-word arguemnts for :class:`openmc.Material` """ def __init__( self, comp=None, - mass=-1.0, - density=1.0, - atoms_per_molecule=-1.0, - metadata=None, - vol=1.0, - temp=900, + comp_is_density=False, + density=None, + volume=1.0, mass_flowrate=0.0, void_frac=0.0, - burnup=0.0): + burnup=0.0, + **kwargs): """ Initializes the Materialflow object. """ # initialize parent class attributes - # super().__init__() + super().__init__(**kwargs) + # initialize all object attributes - self.vol = vol - self.temp = temp + if volume is not None: + self.volume = volume + if density is not None: + self.set_density('g/cm3', density) self.mass_flowrate = mass_flowrate self.void_frac = void_frac self.burnup = burnup - def get_mass(self): - """Returns total mass of the material descibed in Materialflow object. + if bool(comp): + self.replace_components(comp, comp_is_density) + else: + self.mass = 0.0 - Returns - ------- - float - The mass of the object. + def replace_components(self, comp, comp_is_density=False): + """Replace and normalize the material composition + + Parameters + ---------- + comp : dict of str to float + Dictionary mapping element or nuclide names to their atom or weight + percent. + percent_type : {'wo', 'ao'} + 'ao' for atom percenta nd 'wo' for weight percent. """ - return self.mass + for nuclide in self.get_nuclides(): + self.remove_nuclide(nuclide) + + nucs = np.array(list(comp.keys())) + nonzeros = np.array(list(comp.values())) + #nucs = nucs[nonzeros != 0.0] + if len(nucs) > 0: + #nonzeros = nonzeros[nonzeros != 0.0] + comp = dict(zip(nucs, nonzeros)) + super().add_components(comp, percent_type='wo') + density = self.get_density() + # mass dens to wt-% + if comp_is_density: + for nuc in nucs: + super().remove_nuclide(nuc) + comp[nuc] = comp[nuc] / density + super().add_nuclide(nuc, comp[nuc], percent_type='wo') + self.set_density('g/cm3', density) + self.mass = density * self.volume + self.comp = comp + else: + density = 0.0 + self.comp = comp + self.mass = 0.0 + + def get_mass(self, nuc=None, openmc=False): + if not openmc: + if bool(nuc): + mass = self.comp[nuc] * self.mass + else: + mass = self.mass + else: + mass = super().get_mass(nuc) + return mass + + def get_density(self): + if self.density_units != 'g/cm3': + density = self.get_mass_density() + else: + density = self.density + return density def print_attr(self): """Prints various attributes of Materialflow object. """ - print("Volume %f cm3" % self.vol) + print("Volume %f cm3" % self.volume) print("Mass %f g" % self.mass) print("Density %f g/cm3" % self.density) - print("Atoms per molecule %f " % self.atoms_per_molecule) - print("Meta %s " % self.metadata) print("Mass flowrate %f g/s" % self.mass_flowrate) - print("Temperature %f K" % self.temp) + print("Temperature %f K" % self.temperature) print("Void fraction %f " % self.void_frac) print("Burnup %f MWd/kgU" % self.burnup) @@ -85,7 +138,7 @@ def scale_matflow(self, f=1.0): Returns ------- new_mat_comp : dict of int to float - Materialflow nuclide component dictionary of relative mass. + Nuclide component dictionary of relative mass. ``key`` The keys are preserved from PyNE Material (integers @@ -95,28 +148,11 @@ def scale_matflow(self, f=1.0): factor f. """ - old_dict = dict(self.comp) new_mat_comp = {} - for key, value in old_dict.items(): + for key, value in self.comp.items(): new_mat_comp[key] = f * self.mass * value return new_mat_comp - def copy_pymat_attrs(self, src): - """Copies PyNE attributites from source object (`src`) to target - object. - - Parameters - ---------- - src : obj - Materialflow object to copy attributes from. - - """ - setattr(self, 'density', copy.deepcopy(src.density)) - setattr(self, - 'atoms_per_molecule', - copy.deepcopy(src.atoms_per_molecule)) - self.metadata = src.metadata - def __deepcopy__(self, memo): """Return a deep copy of compound object `self`. @@ -133,17 +169,14 @@ def __deepcopy__(self, memo): New compound object copied from `self`. """ - # Initiate new object my copying class from self cls = self.__class__ - result = cls.__new__(cls) - # Copy nuclide vector from self - result = Materialflow(self.scale_matflow()) - # Copy Materialflow density and atoms_per_molecule - result.copy_pymat_attrs(self) - # Copy other object attributes such as volume, burnup, etc - for k, v in self.__dict__.items(): - if 'comp' not in k: - setattr(result, k, copy.deepcopy(v)) + result = cls(comp=self.comp.copy(), + density=self.mass / self.volume, + volume=self.volume, + mass_flowrate=self.mass_flowrate, + void_frac=self.void_frac, + burnup=self.burnup, + temperature=self.temperature) return result def __eq__(self, other): @@ -166,17 +199,22 @@ def __eq__(self, other): if not isinstance(other, Materialflow): # don't attempt to compare against unrelated types return NotImplemented - return self.mass == other.mass and self.vol == other.vol \ - and self.density == other.density \ - and self.atoms_per_molecule == other.atoms_per_molecule \ - and self.temp == other.temp \ - and self.mass_flowrate == other.mass_flowrate \ - and self[922350000] == other[922350000] \ - and self[922380000] == other[922380000] + + value = math.isclose(self.mass, + other.mass, + abs_tol=1e-15) \ + and self.volume == other.volume \ + and self.temperature == other.temperature \ + and self.mass_flowrate == other.mass_flowrate + #if value: + # fast comparision of dicts + # ... + + return value + # # Materialflow math operation Overloads # - def __add__(x, y): """Overrides Python adding operation for Materialflow objects. @@ -193,24 +231,47 @@ def __add__(x, y): Materialflow which is a sum of isotope masses from `x` and `y`. """ - cls = x.__class__ - result = cls.__new__(cls) - result.mass = x.mass + y.mass - x_comp = Counter(x) - y_comp = Counter(y) - x_comp.update(y_comp) - result.comp = dict(x_comp) - result.norm_comp() - result.mass_flowrate = x.mass_flowrate + y.mass_flowrate - # result.temp = (x.temp*x.mass + y.temp*y.mass)/result.mass # averaged - result.temp = x.temp - # Burnup is simply averaged by should be renormilized by heavy metal - result.burnup = (x.burnup * x.mass + y.burnup * y.mass) / result.mass - # result.density = result.mass/result.vol - result.density = x.density - result.vol = result.mass / result.density - result.void_frac = ( - x.void_frac * x.vol + y.void_frac * y.vol) / result.vol + # REFACTOR TO RELFECT NO PYNE + if x.mass == 0.0 or x.volume == 0.0 and y.mass != 0.0 and y.volume != 0.0: + return y + elif y.mass == 0.0 or y.volume == 0.0 and x.mass != 0.0 and x.volume != 0.0: + return x + else: + cls = x.__class__ + result = cls.__new__(cls) + + result_mass = x.mass + y.mass + + x_density = x.mass / x.volume + y_density = y.mass / y.volume + + #result_density = x_density * y_density * (x.mass + y.mass) / \ + # (x.mass * y_density + y.mass * x_density) + result_density = x_density + + result_volume = result_mass / result_density + result = Materialflow(density=result_density, volume=result_volume) + + def get_mass_dict(matflow): + nuclides = list(matflow.comp.keys()) + masses = matflow.get_mass() * np.array(list(matflow.comp.values())) + return dict(zip(nuclides, masses)) + + x_mass_dict = Counter(get_mass_dict(x)) + y_mass_dict = Counter(get_mass_dict(y)) + x_mass_dict.update(y_mass_dict) + x_mass_dict = dict(x_mass_dict) + masses = np.array(list(x_mass_dict.values())) / result_mass + result_comp = dict(zip(x_mass_dict.keys(), masses)) + result.replace_components(result_comp) + result.mass_flowrate = x.mass_flowrate + y.mass_flowrate + # result.temp = (x.temerature*x.mass + y.temperature*y.mass)/result_mass # averaged + result.temperature = x.temperature + # Burnup is simply averaged by should be renormalized by heavy metal + # use self.fissionable_mass? + result.burnup = (x.burnup * x.mass + y.burnup * y.mass) / result_mass + result.void_frac = ( + x.void_frac * x.volume + y.void_frac * y.volume) / result.volume return result def __rmul__(self, scaling_factor): @@ -230,11 +291,11 @@ def __rmul__(self, scaling_factor): """ if isinstance(scaling_factor, (int, float)): result = copy.deepcopy(self) - result.mass = scaling_factor * self.mass - result.norm_comp() - result.vol = scaling_factor * self.vol - result.mass_flowrate = scaling_factor * self.mass_flowrate - # result.temp = (x.temp*x.mass + y.temp*y.mass)/result.mass + if scaling_factor != 1.0 or scaling_factor != 1: + result.volume = scaling_factor * self.volume + result.mass = result.volume * result.get_density() + result.mass_flowrate = scaling_factor * self.mass_flowrate + # result.temperature = (x.temperature*x.get_mass() + y.temperature*y.get_mass())/result.get_mass() return result else: NotImplemented diff --git a/saltproc/openmc_depcode.py b/saltproc/openmc_depcode.py index eaf501981..f85726d41 100644 --- a/saltproc/openmc_depcode.py +++ b/saltproc/openmc_depcode.py @@ -6,8 +6,6 @@ import numpy as np from uncertainties import unumpy -from pyne import nucname as pyname -from pyne import serpent import openmc from saltproc import Materialflow @@ -285,13 +283,9 @@ def read_depleted_materials(self, read_at_end=False): for starting_material, depleted_material in openmc_materials: if depleted_material.depletable: volume = depleted_material.volume - nucvec = self._create_mass_percents_dictionary(depleted_material) + density = depleted_material.get_mass_density() + comp = self._create_mass_percents_dictionary(depleted_material) name = depleted_material.name - depleted_materials[name] = Materialflow(nucvec) - depleted_materials[name].density = depleted_material.get_mass_density() - depleted_materials[name].mass = depleted_materials[name].density * volume - depleted_materials[name].vol = volume - if read_at_end: sp0 = openmc.StatePoint(self.output_path / 'openmc_simulation_n0.h5') heavy_metal_mass = starting_material.fissionable_mass * _KG_PER_G @@ -300,7 +294,10 @@ def read_depleted_materials(self, read_at_end=False): burnup = power * days / heavy_metal_mass else: burnup = 0 - depleted_materials[name].burnup = burnup + depleted_materials[name] = Materialflow(comp=comp, + density=density, + volume=volume, + burnup=burnup) del openmc_materials, depleted_openmc_materials, starting_openmc_materials return depleted_materials @@ -334,10 +331,14 @@ def _create_mass_percents_dictionary(self, mat, percent_type='ao'): mass_percents = percents else: raise ValueError(f'{percent_type} is not a valid percent type') - pyne_nucs = list(map(self._convert_nucname_to_pyne, nucs)) + #PyNE + #pyne_nucs = list(map(self._convert_nucname_to_pyne, nucs)) - return dict(zip(pyne_nucs, mass_percents)) + #PyNE + #return dict(zip(pyne_nucs, mass_percents)) + return dict(zip(nucs, mass_percents)) + #PyNE def _convert_nucname_to_pyne(self, nucname): """Helper function for :func:`_create_mass_percents_dictionary`. Converts an OpenMC-formatted nuclide name into a PyNE-formatted @@ -365,18 +366,11 @@ def _get_power_from_tallies(self, sp, power): power = fission_energy * f * JOULE_PER_EV # J / s return power - def convert_nuclide_code_to_name(self, nuc): - nucname = pyname.name(nuc) - if nucname[-1] == 'M': - nucname = nucname[:-1] - nucname += '_m1' - return nucname + def nuclide_code_to_name(self, nuc): + return nuc - def _convert_name_to_nuccode(self, nucname): - nucname = self._convert_nucname_to_pyne(nucname) - z = pyname.znum(nucname) - a = pyname.anum(nucname) - m = pyname.snum(nucname) + def name_to_nuclide_code(self, nucname): + z, a, m = openmc.data.zam(nucname) code = z * 1000 + a if m != 0: code += 300 + 100 * m @@ -534,15 +528,11 @@ def update_depletable_materials(self, mats, dep_end_time): # depletable materials only if material.name in mats.keys(): components = {} - for nuc_code, mass_fraction in mats[material.name].comp.items(): - nuc_name = pyname.name(nuc_code) - # Convert nuclide names from PyNE format to OpenMC format - if nuc_name[-1] == 'M': - nuc_name = nuc_name[:-1] + '_m1' + for nuc_name, mass_fraction in mats[material.name].comp.items(): components[nuc_name] = mass_fraction material.set_density('g/cm3', mats[material.name].density) - material.volume = mats[material.name].vol + material.volume = mats[material.name].volume for element in material.get_elements(): material.remove_element(element) material.add_components(components, percent_type='wo') diff --git a/saltproc/process.py b/saltproc/process.py index ef6daa428..8d29b2c9b 100644 --- a/saltproc/process.py +++ b/saltproc/process.py @@ -1,9 +1,9 @@ """Process module""" +import re from copy import deepcopy from math import exp import numpy as np -from pyne import nucname as pyname from saltproc import Materialflow @@ -99,40 +99,101 @@ def process_material(self, inflow): reprocessing system component. """ - waste_nucvec = {} - thru_nucvec = {} - print("Xe concentration in inflow before % f g" % inflow['Xe136']) - - for nuc in inflow.comp.keys(): - nuc_name = pyname.serpent(nuc).split('-')[0] - if nuc_name in self.efficiency: - # Evaluate removal efficiency for nuc_name (float) - self.efficiency[nuc_name] = \ - self.calculate_removal_efficiency(nuc_name) - - thru_nucvec[nuc] = \ - float(inflow.comp[nuc]) * \ - float(1.0 - self.efficiency[nuc_name]) - - waste_nucvec[nuc] = \ - float(inflow[nuc]) * self.efficiency[nuc_name] - - # Assume zero removal - else: - thru_nucvec[nuc] = float(inflow.comp[nuc]) - waste_nucvec[nuc] = 0.0 - - waste_stream = Materialflow(waste_nucvec) + waste_mass = {} + thru_mass = {} + + total_waste_mass = 0.0 + total_thru_mass = 0.0 + #print("Xe concentration in inflow before % f g" % (inflow.mass * inflow.comp['Xe136'])) + + if bool(self.efficiency): + process_elements = list(self.efficiency.keys()) + process_nucs = [nuc for nuc in inflow.comp.keys() if re.match(r"([A-Z]+)([0-9]+)", nuc, re.I).groups()[0] in process_elements] + thru_nucs = list(set(inflow.comp.keys()).difference(set(process_nucs))) + + efficiency = [self.calculate_removal_efficiency(elem) for elem in process_elements] + efficiency = dict(zip(process_elements, efficiency)) + + nuc_efficiency = {} + for nuc in process_nucs: + elem = re.match(r"([A-Z]+)([0-9]+)", nuc, re.I).groups()[0] + nuc_efficiency[nuc] = efficiency[elem] + + #thru_mass = np.array([inflow.get_mass(nuc) * (1.0 - nuc_efficiency[nuc]) for nuc in process_nucs]) + thru_mass = np.array([inflow.get_mass(nuc) * (1.0 - nuc_efficiency[nuc]) for nuc in process_nucs]) + waste_mass = np.array([inflow.get_mass(nuc) * nuc_efficiency[nuc] for nuc in process_nucs]) + + total_waste_mass = np.sum(waste_mass) + total_thru_mass = inflow.mass - np.sum(waste_mass) + + waste_mass = dict(zip(process_nucs, waste_mass / total_waste_mass)) + + thru_mass_1 = np.array([inflow.get_mass(nuc) for nuc in thru_nucs]) + + thru_mass_1 = dict(zip(thru_nucs, thru_mass_1 / total_thru_mass)) + thru_mass = dict(zip(process_nucs, thru_mass / total_thru_mass)) + thru_mass.update(thru_mass_1) + + + #for nuc in inflow.comp.keys(): + # match = re.match(r"([A-Z]+)([0-9]+)", nuc, re.I) + # elem_name = match.groups()[0] + # if elem_name in self.efficiency: + # # Evaluate removal efficiency for elem_name (float) + # self.efficiency[elem_name] = \ + # self.calculate_removal_efficiency(elem_name) + # thru_mass[nuc] = \ + # inflow.mass * inflow.comp[nuc] * \ + # (1.0 - self.efficiency[elem_name]) + # waste_mass[nuc] = \ + # inflow.mass * inflow.comp[nuc] * self.efficiency[elem_name] + # #inflow.get_mass(nuc) * self.efficiency[elem_name] + # total_waste_mass += waste_mass[nuc] + # # Assume zero removal + # else: + # thru_mass[nuc] = inflow.mass * inflow.comp[nuc] + # total_thru_mass += thru_mass[nuc] + + # convert to mass percents + #if total_waste_mass > 0: + # for nuc, mass in waste_mass.items(): + # waste_mass[nuc] = mass / total_waste_mass + ## For some reason this is more than waht we need it to be!! + #if total_thru_mass > 0: + # for nuc, mass in thru_mass.items(): + # thru_mass[nuc] = mass / total_thru_mass + + else: + total_thru_mass = inflow.mass + thru_mass = inflow.comp.copy() + + # This volume value preserves the mass values + #waste_mass_arr = np.array(list(waste_mass.values())) + #nonzeros = waste_mass_arr[waste_mass_arr != 0.0] + #nonzeros = nonzeros[nonzeros != 0] + #waste_volume = np.min(nonzeros) + waste_stream = Materialflow(comp=waste_mass) + if bool(waste_mass) and np.max(list(waste_mass.values())) > 0.0: + waste_stream.volume = total_waste_mass / waste_stream.mass + waste_stream.mass = total_waste_mass + else: + waste_stream.volume = 0.0 + #breakpoint() # preserve inflow attributes thru_flow = deepcopy(inflow) - thru_flow.comp = thru_nucvec - thru_flow.density = inflow.density - thru_flow.mass = float(inflow.mass - waste_stream.mass) - thru_flow.norm_comp() - - print("Xe concentration in thruflow: %f g" % thru_flow['Xe136']) - print("Waste mass: %f g\n" % waste_stream.mass) - - del thru_nucvec, waste_nucvec, nuc_name + thru_flow.replace_components(thru_mass) + # initial guess + thru_flow.volume = inflow.volume - waste_stream.volume + # correction + thru_flow.volume = thru_flow.volume * total_thru_mass / thru_flow.get_mass() + thru_flow.mass = total_thru_mass + #breakpoint() + #thru_flow.mass = float(inflow.mass - waste_stream.mass) + #thru_flow.norm_comp() + + #print("Xe concentration in thruflow: %f g" % (thru_flow.comp['Xe136'] * thru_flow.mass)) + #print("Waste mass: %f g\n" % waste_stream.mass) + + del thru_mass, waste_mass return thru_flow, waste_stream diff --git a/saltproc/serpent_depcode.py b/saltproc/serpent_depcode.py index dcdb6bdcd..53a7386bb 100644 --- a/saltproc/serpent_depcode.py +++ b/saltproc/serpent_depcode.py @@ -3,8 +3,10 @@ import shutil import re -from pyne import nucname as pyname -from pyne import serpent +import serpentTools +import openmc +import openmc.data +from math import floor from saltproc import Materialflow from saltproc.depcode import Depcode @@ -173,7 +175,7 @@ def _get_burnable_material_card_data(self, file_lines): mat_data = zip(mat_cards, card_volume_idx)#, mat_extensions) self._burnable_material_card_data = dict(zip(mat_names, mat_data)) - def convert_nuclide_code_to_name(self, nuc_code): + def nuclide_code_to_name(self, nuc_code): """Converts Serpent2 nuclide code to symbolic nuclide name. If nuclide is in a metastable state, the nuclide name is concatenated with the letter `m` and the state index. @@ -186,61 +188,76 @@ def convert_nuclide_code_to_name(self, nuc_code): Returns ------- nuc_name : str - Symbolic nuclide name (`Am242m1`). + Symbolic nuclide name (`Am242_m1`). """ if '.' in str(nuc_code): nuc_code = int(nuc_code.split('.')[0]) - if self.zaid_convention == 'serpent': - nuc_code = pyname.zzzaaa_to_id(nuc_code) - if self.zaid_convention in ('mcnp', 'nndc'): - if self.zaid_convention == 'mcnp' and nuc_code in (95242, 95642): - if nuc_code == 95242: - nuc_code = 95642 - else: - nuc_code = 95242 - nuc_code = pyname.mcnp_to_id(nuc_code) - - zz = pyname.znum(nuc_code) - aa = pyname.anum(nuc_code) - aa_str = str(aa) - if self.zaid_convention == 'serpent': - if aa > 300: - if zz > 76: - aa_str = str(aa - 100) + 'm1' - else: - aa_str = str(aa - 200) + 'm1' - elif aa == 0: - aa_str = 'nat' - if self.zaid_convention in ('mcnp', 'nndc'): - mm = pyname.snum(nuc_code) - if mm != 0: - aa_str = str(aa) + f'm{mm}' - - nuc_name = pyname.zz_name[zz] + aa_str + if self.zaid_convention == 'nndc' and nuc_code in (95242, 95642): + if nuc_code == 95242: + nuc_code = 95642 + else: + nuc_code = 95242 + Z, a, m = self._nuclide_code_to_zam(nuc_code) else: - meta_flag = pyname.snum(nuc_code) - if meta_flag: - nuc_name = pyname.name(nuc_code)[:-1] + 'm' + str(meta_flag) - else: - nuc_name = pyname.name(nuc_code) - - return nuc_name - - def _convert_name_to_nuccode(self, nucname): - if nucname [-2:] == 'm1': - nucname = nucname[:-2] - nucname += "M" - z = pyname.znum(nucname) - a = pyname.anum(nucname) - m = pyname.snum(nucname) - code = z * 1000 + a + Z, a, m = self._decay_code_to_zam(nuc_code) + + nucname = openmc.data.gnds_name(Z, a, m=m) if m != 0: - code += 300 + 100 * m - return code + nucname = nucname[:-3] + f'_m{m}' + return nucname + + def _decay_code_to_zam(self, nuc_code): + m = int(str(nuc_code)[-1]) + nuc_code = int(str(nuc_code)[:-1]) + #nuc_code = floor(nuc_code * 1e-1) + Z = floor(nuc_code * 1e-3) + a = nuc_code % 1000 + return Z, a, m + + def _nuclide_code_to_zam(self, nuc_code): + if '.' in str(nuc_code): + nuc_code = int(nuc_code.split('.')[0]) - def map_nuclide_code_zam_to_serpent(self): + Z = floor(nuc_code * 1e-3) + a = nuc_code % 1000 + m = 0 + if self.zaid_convention == 'serpent': + if a > 300: + m = 1 + if Z > 76: + a = a - 100 + else: + a = a - 200 + else: + # Assumes only m=1 metastable states + if a > 400: + a -= 400 + m = 1 + return Z, a, m + + def name_to_nuclide_code(self, nucname): + Z, a, m = openmc.data.zam(nucname) + nuc_code = self._zam_to_nuclide_code(Z, a, m) + return nuc_code + + def _zam_to_nuclide_code(self, Z, a, m): + nuc_code = Z * 1000 + if m != 0: + if self.zaid_convention == 'serpent': + nuc_code += int(((a / 100) - 3) * 100) + else: + nuc_code += 300 + 100 * m + if self.zaid_convention == 'nndc' and nuc_code in (95242, 95642): + if nuc_code == 95242: + nuc_code = 95642 + else: + nuc_code = 95242 + return nuc_code + + + def map_nuclide_name_to_serpent_name(self): """Creates a dictionary mapping nuclide codes in `zzaaam` format to Serpent2's nuclide code format. @@ -273,26 +290,8 @@ def map_nuclide_code_zam_to_serpent(self): if 'c TRA' in line or 'c DEC' in line: line = line.split() nuc_code = line[2] - if '.' in str(nuc_code): - nuc_code = int(nuc_code.split('.')[0]) - # In MCNP format the ground state of Am-242 is 95242, - # but PyNE seems to disagree - if self.zaid_convention == 'serpent': - nuc_code = pyname.zzzaaa_to_id(nuc_code) - zzaaam = \ - self.convert_nuclide_code_to_zam(pyname.zzaaam(nuc_code)) - if self.zaid_convention == 'nndc' or self.zaid_convention == 'mcnp': - if self.zaid_convention == 'mcnp' and nuc_code in (95242, 95642): - if nuc_code == 95242: - nuc_code = 95642 - else: - nuc_code = 95242 - nuc_code = pyname.mcnp_to_id(nuc_code) - zzaaam = pyname.zzaaam(nuc_code) - else: - zzaaam = int(nuc_code) - - nuc_code_map.update({zzaaam: line[2]}) + nuc_name = self.nuclide_code_to_name(nuc_code) + nuc_code_map.update({nuc_name: nuc_code}) return nuc_code_map def resolve_include_paths(self, lines): @@ -300,7 +299,7 @@ def resolve_include_paths(self, lines): absolute paths. Parameters - ---------- + -self._--------- lines : list of str Serpent2 runtime input file. @@ -369,50 +368,48 @@ def read_depleted_materials(self, read_at_end=False): else: moment = 0 + openmc.reset_auto_ids() results_file = os.path.join('%s_dep.m' % self.runtime_inputfile) - results = serpent.parse_dep(results_file, make_mats=False) - self.days = results['DAYS'][moment] + results = serpentTools.read(results_file) + self.days = results.days[moment] # Get material names mat_names = [] depleted_materials = {} - for key in results.keys(): - name_match = re.search('MAT_(.+?)_VOLUME', key) - if name_match: - mat_names.append(name_match.group(1)) - zai = list(map(int, results['ZAI'][:-2])) # zzaaam codes of isotopes - - for name in mat_names: - volume = results[f'MAT_{name}_VOLUME'][moment] - nucvec = dict(zip(zai, results[f'MAT_{name}_MDENS'][:, moment])) - depleted_materials[name] = Materialflow(nucvec) - depleted_materials[name].density = results[f'MAT_{name}_MDENS'][-1, moment] - depleted_materials[name].mass = depleted_materials[name].density * volume - depleted_materials[name].vol = volume - depleted_materials[name].burnup = results[f'MAT_{name}_BURNUP'][moment] + for material_name, material in results.materials.items(): + if material_name != 'total': + nuclide_names = list(map(self.nuclide_code_to_name, material.zai[:-2])) + comp = dict(zip(nuclide_names, material.mdens[:-2, moment])) + volume = material.volume[moment] + density = material.mdens[-1, moment] + depleted_materials[material_name] = Materialflow(comp=comp, + comp_is_density=True, + density=density, + volume=volume, + burnup=results.burnup[moment]) return depleted_materials def read_step_metadata(self): """Reads Serpent2 depletion step metadata and stores it in the :class:`SerpentDepcode` object's :attr:`step_metadata` attribute. """ - res = serpent.parse_res(self.runtime_inputfile + "_res.m") - depcode_name, depcode_ver = res['VERSION'][0].decode('utf-8').split() + res = serpentTools.read(self.runtime_inputfile + "_res.m") + depcode_name, depcode_ver = res.metadata['version'].split() self.step_metadata['depcode_name'] = depcode_name self.step_metadata['depcode_version'] = depcode_ver - self.step_metadata['title'] = res['TITLE'][0].decode('utf-8') + self.step_metadata['title'] = res.metadata['title'] self.step_metadata['depcode_input_filename'] = \ - res['INPUT_FILE_NAME'][0].decode('utf-8') + res.metadata['inputFileName'] self.step_metadata['depcode_working_dir'] = \ - res['WORKING_DIRECTORY'][0].decode('utf-8') + res.metadata['workingDirectory'] self.step_metadata['xs_data_path'] = \ - res['XS_DATA_FILE_PATH'][0].decode('utf-8') - self.step_metadata['OMP_threads'] = res['OMP_THREADS'][0] - self.step_metadata['MPI_tasks'] = res['MPI_TASKS'][0] - self.step_metadata['memory_optimization_mode'] = res['OPTIMIZATION_MODE'][0] - self.step_metadata['depletion_timestep'] = res['BURN_DAYS'][1][0] - self.step_metadata['execution_time'] = res['RUNNING_TIME'][1] - self.step_metadata['memory_usage'] = res['MEMSIZE'][0] + res.metadata['xsDataFilePath'] + self.step_metadata['OMP_threads'] = res.metadata['ompThreads'] + self.step_metadata['MPI_tasks'] = res.metadata['mpiTasks'] + self.step_metadata['memory_optimization_mode'] = res.metadata['optimizationMode'] + self.step_metadata['depletion_timestep'] = res.resdata['burnDays'][1][0] + self.step_metadata['execution_time'] = res.resdata['runningTime'][1] + self.step_metadata['memory_usage'] = res.resdata['memsize'][0] def read_neutronics_parameters(self): @@ -420,22 +417,22 @@ def read_neutronics_parameters(self): in :class:`SerpentDepcode` object's :attr:`neutronics_parameters` attribute. """ - res = serpent.parse_res(self.runtime_inputfile + "_res.m") - self.neutronics_parameters['keff_bds'] = res['IMP_KEFF'][0] - self.neutronics_parameters['keff_eds'] = res['IMP_KEFF'][1] + res = serpentTools.read(self.runtime_inputfile + "_res.m") + self.neutronics_parameters['keff_bds'] = res.resdata['impKeff'][0] + self.neutronics_parameters['keff_eds'] = res.resdata['impKeff'][1] self.neutronics_parameters['breeding_ratio'] = \ - res['CONVERSION_RATIO'][1] - self.neutronics_parameters['burn_days'] = res['BURN_DAYS'][1][0] - self.neutronics_parameters['power_level'] = res['TOT_POWER'][1][0] - b_l = int(.5 * len(res['FWD_ANA_BETA_ZERO'][1])) + res.resdata['conversionRatio'][1] + self.neutronics_parameters['burn_days'] = res.resdata['burnDays'][1][0] + self.neutronics_parameters['power_level'] = res.resdata['totPower'][1][0] + b_l = int(.5 * len(res['fwdAnaBetaZero'][1])) self.neutronics_parameters['beta_eff'] = \ - res['FWD_ANA_BETA_ZERO'][1].reshape((b_l, 2)) + res.resdata['fwdAnaBetaZero'][1].reshape((b_l, 2)) self.neutronics_parameters['delayed_neutrons_lambda'] = \ - res['FWD_ANA_LAMBDA'][1].reshape((b_l, 2)) + res.resdata['fwdAnaLambda'][1].reshape((b_l, 2)) self.neutronics_parameters['fission_mass_bds'] = \ - res['INI_FMASS'][1] + res.resdata['iniFmass'][1] self.neutronics_parameters['fission_mass_eds'] = \ - res['TOT_FMASS'][1] + res.resdata['totFmass'][1] def set_power_load(self, file_lines, @@ -507,36 +504,6 @@ def run_depletion_step(self, mpi_args=None, threads=None): super().run_depletion_step(mpi_args, args) - def convert_nuclide_code_to_zam(self, nuc_code): - """Converts nuclide code from Serpent2 format to zam format. - Checks Serpent2-specific meta stable-flag for zzaaam. For instance, - 47310 instead of 471101 for `Ag-110m1`. Metastable isotopes represented - with `aaa` started with ``3``. - - Parameters - ---------- - nuc_code : int - Nuclide code in Serpent2 format (`47310`). - - Returns - ------- - nuc_zzaam : int - Nuclide code in in `zzaaam` form (`471101`). - - """ - - zz = pyname.znum(nuc_code) - aa = pyname.anum(nuc_code) - if aa > 300: - if zz > 76: - aa_new = aa - 100 - else: - aa_new = aa - 200 - zzaaam = str(zz) + str(aa_new) + '1' - else: - zzaaam = nuc_code - return int(zzaaam) - def switch_to_next_geometry(self): """Inserts line with path to next Serpent geometry file at the beginning of the Serpent iteration input file. @@ -609,7 +576,7 @@ def update_depletable_materials(self, mats, dep_end_time): with open(self.runtime_matfile, 'w') as f: f.write('%% Material compositions (after %f days)\n\n' % dep_end_time) - nuc_code_map = self.map_nuclide_code_zam_to_serpent() + nuc_code_map = self.map_nuclide_name_to_serpent_name() if not(hasattr(self, '_burnable_material_card_data')): lines = self.read_plaintext_file(self.template_input_file_path) _, abs_src_matfile = self._get_burnable_materials_file(lines) @@ -618,11 +585,10 @@ def update_depletable_materials(self, mats, dep_end_time): for name, mat in mats.items(): mat_card, card_volume_idx = self._burnable_material_card_data[name] mat_card[2] = str(-mat.density) - mat_card[card_volume_idx] = "%7.5E" % mat.vol + mat_card[card_volume_idx] = "%7.5E" % mat.volume f.write(" ".join(mat_card)) f.write("\n") - for nuc_code, mass_fraction in mat.comp.items(): - zam_code = pyname.zzaaam(nuc_code) + for nuc, mass_fraction in mat.comp.items(): f.write(' %9s %7.14E\n' % - (nuc_code_map[zam_code], + (nuc_code_map[nuc], -mass_fraction)) diff --git a/saltproc/simulation.py b/saltproc/simulation.py index 6fb3eb398..1dbb3f999 100644 --- a/saltproc/simulation.py +++ b/saltproc/simulation.py @@ -59,6 +59,8 @@ def __init__( self.restart_flag = restart_flag self.adjust_geo = adjust_geo self.compression_params = compression_params + self.nuclide_indices_dtype = np.dtype([('nuclide', 'S9'), + ('index', int)]) def check_restart(self): """If the user set `restart_flag` @@ -119,57 +121,67 @@ def store_after_repr(self, after_mats, waste_dict, dep_step): Current depletion time step. """ - streams_gr = 'in_out_streams' + #breakpoint() + streams_description = 'in_out_streams' db = tb.open_file( self.db_path, mode='a', filters=self.compression_params) - for mn in waste_dict.keys(): # iterate over materials - mat_node = getattr(db.root.materials, mn) - if not hasattr(mat_node, streams_gr): + for material_name in waste_dict.keys(): # iterate over materials + mat_node = getattr(db.root.materials, material_name) + if not hasattr(mat_node, streams_description): waste_group = db.create_group( mat_node, - streams_gr, - 'Waste Material streams data for each process') + streams_description, + 'Waste stream compositions for each process') else: - waste_group = getattr(mat_node, streams_gr) - for proc in waste_dict[mn].keys(): - # proc_node = db.create_group(waste_group, proc) - # iso_idx[proc] = OrderedDict() - iso_idx = OrderedDict() + waste_group = getattr(mat_node, streams_description) + for proc in waste_dict[material_name].keys(): + if not hasattr(waste_group, proc): + proc_node = db.create_group(waste_group, proc) + else: + proc_node = getattr(waste_group, proc) + #iso_idx = OrderedDict() + nuclide_indices = [] iso_wt_frac = [] coun = 0 - # Read isotopes from Materialflow - for nuc, wt_frac in waste_dict[mn][proc].comp.items(): - # Dictonary in format {isotope_name : index(int)} - iso_idx[self.sim_depcode.convert_nuclide_code_to_name(nuc)] = coun - # Convert wt% to absolute [user units] - iso_wt_frac.append(wt_frac * waste_dict[mn][proc].mass) - coun += 1 - # Try to open EArray and table and if not exist - create - try: - earr = db.get_node(waste_group, proc) - except Exception: - earr = db.create_earray( - waste_group, - proc, - atom=tb.Float64Atom(), - shape=(0, len(iso_idx)), - title="Isotopic composition for %s" % proc) - # Save isotope indexes map and units in EArray attributes - earr.flavor = 'python' - earr.attrs.iso_map = iso_idx - - earr, iso_wt_frac = self._fix_nuclide_discrepancy(db, earr, iso_idx, iso_wt_frac) - - earr.append(np.asarray([iso_wt_frac], dtype=np.float64)) - del iso_wt_frac - del iso_idx + if hasattr(waste_dict[material_name][proc], 'comp'): + # Read isotopes from Materialflow + for nuc, wt_frac in waste_dict[material_name][proc].comp.items(): + # Dictonary in format {isotope_name : index(int)} + #iso_idx[nuc] = coun + nuclide_indices.append((nuc, coun)) + # Convert wt% to absolute [user units] + iso_wt_frac.append(wt_frac * waste_dict[material_name][proc].mass) + coun += 1 + # Try to open EArray and table and if not exist - create + nuclide_indices_array = np.array(nuclide_indices, dtype=self.nuclide_indices_dtype) + if hasattr(proc_node, 'comp'): + earr = db.get_node(proc_node, 'comp') + else: + earr = db.create_earray( + proc_node, + 'comp', + atom=tb.Float64Atom(), + shape=(0, len(nuclide_indices_array)), + title="Isotopic composition for %s" % proc) + # Save isotope indexes map and units in EArray attributes + earr.flavor = 'python' + #earr.attrs.iso_map = iso_idx + if not hasattr(proc_node, 'nuclide_map'): + db.create_table(proc_node, + 'nuclide_map', + description=nuclide_indices_array) + + earr, iso_wt_frac = self._fix_nuclide_discrepancy(db, earr, nuclide_indices, iso_wt_frac) + + earr.append(np.asarray([iso_wt_frac], dtype=np.float64)) + del iso_wt_frac # Also save materials AFTER reprocessing and refill here self.store_mat_data(after_mats, dep_step, True) db.close() - def _fix_nuclide_discrepancy(self, db, earr, iso_idx, iso_wt_frac): + def _fix_nuclide_discrepancy(self, db, earr, nuclide_indices, iso_wt_frac): """Fix discrepancies between nuclide keys present in stored results and nuclides keys stored in results for the current depletion step @@ -180,7 +192,7 @@ def _fix_nuclide_discrepancy(self, db, earr, iso_idx, iso_wt_frac): earr : tables.EArray Array storing nuclide material mass compositions from previously completed depletion steps - iso_idx : OrderedDict + nuclide_indices : OrderedDict Map of nuclide name to array index iso_wt_frac : list of float List storing nuclide material mass compositions for current @@ -198,7 +210,14 @@ def _fix_nuclide_discrepancy(self, db, earr, iso_idx, iso_wt_frac): in the current depletion step that are stored in earr. """ - base_nucs= set(earr.attrs.iso_map.keys()) + parent_node = earr._v_parent + #if isinstance(nuclide_indices, dict): + # base_nucs = set(earr.attrs.iso_map.keys()) + # iso_idx = nuclide_indices + # step_nucs = set(iso_idx.keys()) + #else: + base_nucs = set(map(bytes.decode, parent_node.nuclide_map.col('nuclide'))) + iso_idx = dict(nuclide_indices) step_nucs = set(iso_idx.keys()) forward_difference = base_nucs.difference(step_nucs) backward_difference = step_nucs.difference(base_nucs) @@ -220,10 +239,18 @@ def _fix_nuclide_discrepancy(self, db, earr, iso_idx, iso_wt_frac): title=node_title) # Save isotope indexes map and units in EArray attributes earr.flavor = 'python' - earr.attrs.iso_map = combined_map + #earr.attrs.iso_map = combined_map earr_len = len(combined_earr) for i in range(earr_len): earr.append(np.array([combined_earr[i]])) + + # Reform nuclide_map + nuclide_indices = list(zip(combined_map.keys(), combined_map.values())) + nuclide_indices_array = np.array(nuclide_indices, dtype=self.nuclide_indices_dtype) + db.remove_node(parent_node.nuclide_map) + db.create_table(parent_node, + 'nuclide_map', + description=nuclide_indices_array) else: combined_step_arr = iso_wt_frac @@ -263,10 +290,14 @@ def _add_missing_nuclides(self, base_nucs, step_nucs, earr, iso_idx, iso_wt_frac depletion step with additional entries for nuclides not present in the current depletion step that are stored in earr. """ + parent_node = earr._v_parent + _nuclides = list(map(bytes.decode, parent_node.nuclide_map.col('nuclide'))) + _indices = parent_node.nuclide_map.col('index') + base_nuclide_map = dict(zip(_nuclides, _indices)) combined_nucs = list(base_nucs.union(step_nucs)) # Sort the nucnames by ZAM - nuccodes = list(map(self.sim_depcode._convert_name_to_nuccode, combined_nucs)) - combined_nucs = [nucname for nuccode, nucname in sorted(zip(nuccodes,combined_nucs))] + nuclide_codes = list(map(self.sim_depcode.name_to_nuclide_code, combined_nucs)) + combined_nucs = [nucname for nuclide_code, nucname in sorted(zip(nuclide_codes,combined_nucs))] combined_values = np.arange(0, len(combined_nucs), 1).tolist() combined_map = OrderedDict(zip(combined_nucs,combined_values)) @@ -277,7 +308,7 @@ def _add_missing_nuclides(self, base_nucs, step_nucs, earr, iso_idx, iso_wt_frac for nuc, idx in combined_map.items(): if nuc in base_nucs: for i in range(earr_len): - combined_earr[i,idx] = earr[i][earr.attrs.iso_map[nuc]] + combined_earr[i,idx] = earr[i][base_nuclide_map[nuc]] if nuc in step_nucs: combined_step_arr[idx] = iso_wt_frac[iso_idx[nuc]] else: @@ -320,7 +351,8 @@ def store_mat_data(self, mats, dep_step, store_at_end=False): dep_step_str = ["before_reproc", "before"] # Moment when store compositions - iso_idx = OrderedDict() + #iso_idx = OrderedDict() + # # numpy array row storage data for material physical properties mpar_dtype = np.dtype([ ('mass', float), @@ -335,6 +367,7 @@ def store_mat_data(self, mats, dep_step, store_at_end=False): print( '\nStoring material data for depletion step #%i.' % (dep_step + 1)) + #breakpoint() db = tb.open_file( self.db_path, mode='a', @@ -345,7 +378,8 @@ def store_mat_data(self, mats, dep_step, store_at_end=False): 'Material data') # Iterate over all materials for key, value in mats.items(): - iso_idx[key] = OrderedDict() + #iso_idx[key] = OrderedDict() + nuclide_indices = [] iso_wt_frac = [] coun = 0 # Create group for each material @@ -360,18 +394,21 @@ def store_mat_data(self, mats, dep_step, store_at_end=False): 'Material data {dep_step_str[1]} reprocessing') comp_pfx = '/materials/' + str(key) + '/' + dep_step_str[0] # Read isotopes from Materialflow for material - for nuc_code, wt_frac in mats[key].comp.items(): + for nuc, wt_frac in mats[key].comp.items(): # Dictonary in format {isotope_name : index(int)} - iso_idx[key][self.sim_depcode.convert_nuclide_code_to_name(nuc_code)] = coun + #iso_idx[key][nuc] = coun + nuclide_indices.append((nuc, coun)) # Convert wt% to absolute [user units] iso_wt_frac.append(wt_frac * mats[key].mass) coun += 1 + nuclide_indices_array = np.array(nuclide_indices, + dtype=self.nuclide_indices_dtype) # Store information about material properties in new array row mpar_row = ( mats[key].mass, - mats[key].density, - mats[key].vol, - mats[key].temp, + mats[key].get_density(), + mats[key].volume, + mats[key].temperature, mats[key].mass_flowrate, mats[key].void_frac, mats[key].burnup @@ -391,22 +428,26 @@ def store_mat_data(self, mats, dep_step, store_at_end=False): comp_pfx, 'comp', atom=tb.Float64Atom(), - shape=(0, len(iso_idx[key])), + shape=(0, len(nuclide_indices_array)), title="Isotopic composition for %s" % key) # Save isotope indexes map and units in EArray attributes earr.flavor = 'python' - earr.attrs.iso_map = iso_idx[key] + #earr.attrs.iso_map = iso_idx[key] # Create table for material Parameters + print('Creating ' + key + ' lookup table.') + db.create_table(comp_pfx, + 'nuclide_map', + description=nuclide_indices_array) print('Creating ' + key + ' parameters table.') mpar_table = db.create_table( comp_pfx, 'parameters', np.empty(0, dtype=mpar_dtype), - "Material parameters data") + title="Material parameters data") print('Dumping Material %s data %s to %s.' % (key, dep_step_str[0], os.path.abspath(self.db_path))) - earr, iso_wt_frac = self._fix_nuclide_discrepancy(db, earr, iso_idx[key], iso_wt_frac) + earr, iso_wt_frac = self._fix_nuclide_discrepancy(db, earr, nuclide_indices, iso_wt_frac) # Add row for the timestep to EArray and Material Parameters table earr.append(np.array([iso_wt_frac], dtype=np.float64)) diff --git a/saltproc/version.py b/saltproc/version.py index 3f38844ba..848b61461 100644 --- a/saltproc/version.py +++ b/saltproc/version.py @@ -89,9 +89,10 @@ './input_schema.json']} PACKAGES = ["saltproc"] REQUIRES = ["numpy", - "pyne", "networkx", + "pytables", "pydot", "pytest", "argparse", - "jsonschema"] + "jsonschema", + "serpentTools"] diff --git a/setup.py b/setup.py index fca4d456d..f95a55c24 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,11 @@ with open(ver_file) as f: exec(f.read()) + +ENTRY_POINTS = { + 'console_scripts': ['saltproc = saltproc.app:run'] +} + opts = dict(name=NAME, maintainer=MAINTAINER, maintainer_email=MAINTAINER_EMAIL, diff --git a/tests/integration_tests/basic_reprocessing/test.py b/tests/integration_tests/basic_reprocessing/test.py index b4a115bcd..cf3a0d4ad 100644 --- a/tests/integration_tests/basic_reprocessing/test.py +++ b/tests/integration_tests/basic_reprocessing/test.py @@ -12,29 +12,29 @@ def test_reprocessing_and_refill( waste_streams, extracted_mass = reprocess_materials(mats, proc_test_file, path_test_file) - np.testing.assert_almost_equal(extracted_mass['fuel'], 1401.0846504569054) - np.testing.assert_almost_equal(extracted_mass['ctrlPois'], 0.0) - np.testing.assert_almost_equal( - waste_streams['fuel']['waste_sparger']['Xe135'], - 11.878661583083327) - np.testing.assert_almost_equal( - waste_streams['fuel']['waste_nickel_filter']['I135'], - 0.90990472940444) - np.testing.assert_almost_equal( - waste_streams['fuel']['waste_liquid_metal']['Sr90'], - 0.7486923392931839) + np.testing.assert_allclose(extracted_mass['fuel'], 1401.0846504569054, rtol=1e-6) + np.testing.assert_allclose(extracted_mass['ctrlPois'], 0.0, rtol=1e-6) + np.testing.assert_allclose( + waste_streams['fuel']['waste_sparger'].get_mass('Xe135'), + 11.878661583083327, rtol=1e-6) + np.testing.assert_allclose( + waste_streams['fuel']['waste_nickel_filter'].get_mass('I135'), + 0.90990472940444, rtol=1e-6) + np.testing.assert_allclose( + waste_streams['fuel']['waste_liquid_metal'].get_mass('Sr90'), + 0.7486923392931839, rtol=1e-6) waste_feed_streams = refill_materials( mats, extracted_mass, waste_streams, proc_test_file) - np.testing.assert_almost_equal( - waste_feed_streams['fuel']['feed_leu']['U235'], - 43.573521906078334) - np.testing.assert_almost_equal( - waste_feed_streams['fuel']['feed_leu']['U238'], - 827.8969156550545) - np.testing.assert_almost_equal( - waste_feed_streams['fuel']['feed_leu']['F19'], - 461.8575149906222) - np.testing.assert_almost_equal( - waste_feed_streams['fuel']['feed_leu']['Li7'], - 67.75331008246572) + np.testing.assert_allclose( + waste_feed_streams['fuel']['feed_leu'].get_mass('U235'), + 43.573521906078334, rtol=1e-6) + np.testing.assert_allclose( + waste_feed_streams['fuel']['feed_leu'].get_mass('U238'), + 827.8969156550545, rtol=1e-6) + np.testing.assert_allclose( + waste_feed_streams['fuel']['feed_leu'].get_mass('F19'), + 461.8575149906222, rtol=1e-6) + np.testing.assert_allclose( + waste_feed_streams['fuel']['feed_leu'].get_mass('Li7'), + 67.75331008246572, rtol=1e-6) diff --git a/tests/integration_tests/database_storage/test.py b/tests/integration_tests/database_storage/test.py index da291bebc..4f1933c51 100644 --- a/tests/integration_tests/database_storage/test.py +++ b/tests/integration_tests/database_storage/test.py @@ -14,6 +14,10 @@ def db_file(simulation): db_file = (cwd / (simulation.sim_depcode.codename + '_test.h5')) return str(db_file.resolve()) +def _create_nuclide_map(node): + nuclides = list(map(bytes.decode, node.nuclide_map.col('nuclide'))) + indices = node.nuclide_map.col('index') + return dict(zip(nuclides, indices)) def test_store_after_reprocessing( simulation, @@ -69,59 +73,36 @@ def test_store_after_reprocessing( tmats = db.root.materials tfuel_stream = tmats.fuel.in_out_streams - tf_feed_leu = tfuel_stream.feed_leu[0] - tf_entrain_sep = tfuel_stream.waste_entrainment_separator[0] - tf_liq_met = tfuel_stream.waste_liquid_metal[0] - tf_nickel_filt = tfuel_stream.waste_nickel_filter[0] - tf_sparger = tfuel_stream.waste_sparger[0] - try: - assert tf_feed_leu[0] == f_feed_leu['Li6'] - assert tf_feed_leu[1] == f_feed_leu['Li7'] - assert tf_feed_leu[2] == f_feed_leu['F19'] - assert tf_feed_leu[3] == f_feed_leu['U235'] - assert tf_feed_leu[4] == f_feed_leu['U238'] - - assert tf_entrain_sep[0] == f_entrain_sep['H1'] - assert tf_entrain_sep[1] == f_entrain_sep['H2'] - assert tf_entrain_sep[459] == f_entrain_sep['Kr91'] - assert tf_entrain_sep[461] == f_entrain_sep['Kr93'] - assert tf_entrain_sep[991] == f_entrain_sep['Xe135'] - assert tf_entrain_sep[993] == f_entrain_sep['Xe136'] - - assert tf_liq_met[117] == f_liq_met['Ca49'] - assert tf_liq_met[288] == f_liq_met['Cu69'] - assert tf_liq_met[513] == f_liq_met['Sr102'] - assert tf_liq_met[518] == f_liq_met['Y89'] - assert tf_liq_met[1123] == f_liq_met['Pr159'] - assert tf_liq_met[1124] == f_liq_met['Nd142'] - - assert tf_nickel_filt[309] == f_nickel_filt['Zn70'] - assert tf_nickel_filt[437] == f_nickel_filt['Br90'] - assert tf_nickel_filt[964] == f_nickel_filt['I134'] - assert tf_nickel_filt[630] == f_nickel_filt['Tc99'] - - assert tf_sparger[0] == f_sparger['H1'] - assert tf_sparger[1] == f_sparger['H2'] - assert tf_sparger[459] == f_sparger['Kr91'] - assert tf_sparger[461] == f_sparger['Kr93'] - assert tf_sparger[991] == f_sparger['Xe135'] - assert tf_sparger[993] == f_sparger['Xe136'] - except AssertionError: - db.close() - os.remove(db_file) - simulation.db_path = db_path_old - raise AssertionError("incorrect Value") - except KeyError: - db.close() - os.remove(db_file) - simulation.db_path = db_path_old - raise KeyError("incorrect key") - except BaseException: - db.close() - os.remove(db_file) - simulation.db_path = db_path_old - print("something went wrong. See error stack for details") - + tf_feed_leu = tfuel_stream.feed_leu.comp[0] + tf_feed_leu_map = _create_nuclide_map(tfuel_stream.feed_leu) + + tf_entrain_sep = tfuel_stream.waste_entrainment_separator.comp[0] + tf_entrain_sep_map = _create_nuclide_map(tfuel_stream.waste_entrainment_separator) + + tf_liq_met = tfuel_stream.waste_liquid_metal.comp[0] + tf_liq_met_map = _create_nuclide_map(tfuel_stream.waste_liquid_metal) + + tf_nickel_filt = tfuel_stream.waste_nickel_filter.comp[0] + tf_nickel_filt_map = _create_nuclide_map(tfuel_stream.waste_nickel_filter) + + tf_sparger = tfuel_stream.waste_sparger.comp[0] + tf_sparger_map = _create_nuclide_map(tfuel_stream.waste_sparger) + + for nuc in f_feed_leu.get_nuclides(): + np.testing.assert_allclose(tf_feed_leu[tf_feed_leu_map[nuc]], + f_feed_leu.get_mass(nuc)) + for nuc in f_entrain_sep.get_nuclides(): + np.testing.assert_allclose(tf_entrain_sep[tf_entrain_sep_map[nuc]], + f_entrain_sep.get_mass(nuc)) + for nuc in f_liq_met.get_nuclides(): + np.testing.assert_allclose(tf_liq_met[tf_liq_met_map[nuc]], + f_liq_met.get_mass(nuc)) + for nuc in f_nickel_filt.get_nuclides(): + np.testing.assert_allclose(tf_nickel_filt[tf_nickel_filt_map[nuc]], + f_nickel_filt.get_mass(nuc)) + for nuc in f_sparger.get_nuclides(): + np.testing.assert_allclose(tf_sparger[tf_sparger_map[nuc]], + f_sparger.get_mass(nuc)) # close the file db.close() @@ -172,83 +153,65 @@ def test_store_mat_data(simulation): tfuel_before = tmats.fuel.before_reproc.comp[0] tfuel_before_params = tmats.fuel.before_reproc.parameters[0] + tfuel_before_map = _create_nuclide_map(tmats.fuel.before_reproc) tfuel_after = tmats.fuel.after_reproc.comp[0] tfuel_after_params = tmats.fuel.after_reproc.parameters[0] + tfuel_after_map = _create_nuclide_map(tmats.fuel.after_reproc) tpois_before = tmats.ctrlPois.before_reproc.comp[0] tpois_before_params = tmats.ctrlPois.before_reproc.parameters[0] + tpois_before_map = _create_nuclide_map(tmats.ctrlPois.before_reproc) tpois_after = tmats.ctrlPois.after_reproc.comp[0] tpois_after_params = tmats.ctrlPois.after_reproc.parameters[0] + tpois_after_map = _create_nuclide_map(tmats.ctrlPois.after_reproc) # Check the mass fractions - try: - assert tfuel_before[1566] == fuel_before['U235'] - assert tfuel_before[1570] == fuel_before['U238'] - assert tfuel_before[37] == fuel_before['F19'] - assert tfuel_before[8] == fuel_before['Li7'] - assert tfuel_before[1610] == fuel_before['Cm240'] - assert tfuel_before[1589] == fuel_before['Pu239'] - assert tpois_before[1213] == pois_before['Gd155'] - assert tpois_before[32] == pois_before['O16'] - - assert tfuel_after[1566] == fuel_after['U235'] - assert tfuel_after[1570] == fuel_after['U238'] - assert tfuel_after[37] == fuel_after['F19'] - assert tfuel_after[8] == fuel_after['Li7'] - assert tfuel_after[1610] == fuel_after['Cm240'] - assert tfuel_after[1589] == fuel_after['Pu239'] - assert tpois_after[1213] == pois_after['Gd155'] - assert tpois_after[32] == pois_after['O16'] - - # Check the parameters - assert tfuel_before_params[0] == fuel_before.mass - assert tfuel_before_params[1] == fuel_before.density - assert tfuel_before_params[2] == fuel_before.vol - assert tfuel_before_params[3] == fuel_before.temp - assert tfuel_before_params[4] == fuel_before.mass_flowrate - assert tfuel_before_params[5] == fuel_before.void_frac - assert tfuel_before_params[6] == fuel_before.burnup - - assert tpois_before_params[0] == pois_before.mass - assert tpois_before_params[1] == pois_before.density - assert tpois_before_params[2] == pois_before.vol - assert tpois_before_params[3] == pois_before.temp - assert tpois_before_params[4] == pois_before.mass_flowrate - assert tpois_before_params[5] == pois_before.void_frac - assert tpois_before_params[6] == pois_before.burnup - - assert tfuel_after_params[0] == fuel_after.mass - assert tfuel_after_params[1] == fuel_after.density - assert tfuel_after_params[2] == fuel_after.vol - assert tfuel_after_params[3] == fuel_after.temp - assert tfuel_after_params[4] == fuel_after.mass_flowrate - assert tfuel_after_params[5] == fuel_after.void_frac - assert tfuel_after_params[6] == fuel_after.burnup - - assert tpois_after_params[0] == pois_after.mass - assert tpois_after_params[1] == pois_after.density - assert tpois_after_params[2] == pois_after.vol - assert tpois_after_params[3] == pois_after.temp - assert tpois_after_params[4] == pois_after.mass_flowrate - assert tpois_after_params[5] == pois_after.void_frac - assert tpois_after_params[6] == pois_after.burnup - except AssertionError: - db.close() - os.remove(db_file) - simulation.db_path = db_path_old - raise AssertionError("incorrect Value") - except KeyError: - db.close() - os.remove(db_file) - simulation.db_path = db_path_old - raise KeyError("incorrect key") - except BaseException: - db.close() - os.remove(db_file) - simulation.db_path = db_path_old - print("something went wrong. See error stack for details") + for nuc in fuel_before.get_nuclides(): + np.testing.assert_allclose(tfuel_before[tfuel_before_map[nuc]], + fuel_before.get_mass(nuc)) + for nuc in pois_before.get_nuclides(): + np.testing.assert_allclose(tpois_before[tpois_before_map[nuc]], + pois_before.get_mass(nuc)) + for nuc in fuel_after.get_nuclides(): + np.testing.assert_allclose(tfuel_after[tfuel_after_map[nuc]], + fuel_after.get_mass(nuc)) + for nuc in pois_after.get_nuclides(): + np.testing.assert_allclose(tpois_after[tpois_after_map[nuc]], + pois_after.get_mass(nuc)) + # Check the parameters + assert tfuel_before_params[0] == fuel_before.mass + assert tfuel_before_params[1] == fuel_before.density + assert tfuel_before_params[2] == fuel_before.volume + #assert tfuel_before_params[3] == fuel_before.temperature + assert tfuel_before_params[4] == fuel_before.mass_flowrate + assert tfuel_before_params[5] == fuel_before.void_frac + assert tfuel_before_params[6] == fuel_before.burnup + + assert tpois_before_params[0] == pois_before.mass + assert tpois_before_params[1] == pois_before.density + assert tpois_before_params[2] == pois_before.volume + #assert tpois_before_params[3] == pois_before.temperature + assert tpois_before_params[4] == pois_before.mass_flowrate + assert tpois_before_params[5] == pois_before.void_frac + assert tpois_before_params[6] == pois_before.burnup + + assert tfuel_after_params[0] == fuel_after.mass + assert tfuel_after_params[1] == fuel_after.density + assert tfuel_after_params[2] == fuel_after.volume + #assert tfuel_after_params[3] == fuel_after.temperature + assert tfuel_after_params[4] == fuel_after.mass_flowrate + assert tfuel_after_params[5] == fuel_after.void_frac + assert tfuel_after_params[6] == fuel_after.burnup + + assert tpois_after_params[0] == pois_after.mass + assert tpois_after_params[1] == pois_after.density + assert tpois_after_params[2] == pois_after.volume + #assert tpois_after_params[3] == pois_after.temperature + assert tpois_after_params[4] == pois_after.mass_flowrate + assert tpois_after_params[5] == pois_after.void_frac + assert tpois_after_params[6] == pois_after.burnup # close the file db.close() @@ -295,39 +258,21 @@ def test_store_run_init_info(simulation): tinit_info = db.root.initial_depcode_siminfo[0] - try: - assert tinit_info[0] == simulation.sim_depcode.npop - assert tinit_info[1] == simulation.sim_depcode.active_cycles - assert tinit_info[2] == simulation.sim_depcode.inactive_cycles - assert str(tinit_info[3])[2:-1] == init_info['depcode_name'] - assert str(tinit_info[4])[2:-1] == init_info['depcode_version'] - assert str(tinit_info[5])[2:-1] == init_info['title'] - assert str(tinit_info[6])[2:-1] == init_info['depcode_input_filename'] - assert str(tinit_info[7])[2:-1] == init_info['depcode_working_dir'] - assert str(tinit_info[8])[2:-1] == init_info['xs_data_path'] - assert tinit_info[9] == init_info['OMP_threads'] - assert tinit_info[10] == init_info['MPI_tasks'] - assert tinit_info[11] == init_info['memory_optimization_mode'] - assert tinit_info[12] == init_info['depletion_timestep'] - assert tinit_info[13] == init_info['execution_time'] - assert tinit_info[14] == init_info['memory_usage'] - except AssertionError: - db.close() - os.remove(db_file) - simulation.db_path = db_path_old - raise AssertionError("incorrect Value") - except KeyError: - db.close() - os.remove(db_file) - simulation.db_path = db_path_old - raise KeyError("incorrect key") - except BaseException: - db.close() - os.remove(db_file) - simulation.db_path = db_path_old - print("something went wrong. See error stack for details") - - print("") + assert tinit_info[0] == simulation.sim_depcode.npop + assert tinit_info[1] == simulation.sim_depcode.active_cycles + assert tinit_info[2] == simulation.sim_depcode.inactive_cycles + assert str(tinit_info[3])[2:-1] == init_info['depcode_name'] + assert str(tinit_info[4])[2:-1] == init_info['depcode_version'] + assert str(tinit_info[5])[2:-1] == init_info['title'] + assert str(tinit_info[6])[2:-1] == init_info['depcode_input_filename'] + assert str(tinit_info[7])[2:-1] == init_info['depcode_working_dir'] + assert str(tinit_info[8])[2:-1] == init_info['xs_data_path'] + assert tinit_info[9] == init_info['OMP_threads'] + assert tinit_info[10] == init_info['MPI_tasks'] + assert tinit_info[11] == init_info['memory_optimization_mode'] + assert tinit_info[12] == init_info['depletion_timestep'] + assert tinit_info[13] == init_info['execution_time'] + assert tinit_info[14] == init_info['memory_usage'] # close the file db.close() @@ -367,37 +312,21 @@ def test_store_run_step_info(simulation): See error stack for more info.') tstep_info = db.root.simulation_parameters[0] - try: - assert np.array_equal(tstep_info[0], - step_info['beta_eff'].astype('float32')) - assert np.array_equal(tstep_info[1], - step_info['breeding_ratio'].astype('float32')) - assert tstep_info[2] == simulation.burn_time - assert np.array_equal(tstep_info[3], - step_info['delayed_neutrons_lambda']. - astype('float32')) - assert tstep_info[4] == step_info['fission_mass_bds'].astype('float32') - assert tstep_info[5] == step_info['fission_mass_eds'].astype('float32') - assert np.array_equal(tstep_info[6], - step_info['keff_bds'].astype('float32')) - assert np.array_equal(tstep_info[7], - step_info['keff_eds'].astype('float32')) - assert tstep_info[8] == step_info['power_level'].astype('float32') - except AssertionError: - db.close() - os.remove(db_file) - simulation.db_path = db_path_old - raise AssertionError("incorrect Value") - except KeyError: - db.close() - os.remove(db_file) - simulation.db_path = db_path_old - raise KeyError("incorrect key") - except BaseException: - db.close() - os.remove(db_file) - simulation.db_path = db_path_old - print("something went wrong. See error stack for details") + assert np.array_equal(tstep_info[0], + step_info['beta_eff'].astype('float32')) + assert np.array_equal(tstep_info[1], + step_info['breeding_ratio'].astype('float32')) + assert tstep_info[2] == simulation.burn_time + assert np.array_equal(tstep_info[3], + step_info['delayed_neutrons_lambda']. + astype('float32')) + assert tstep_info[4] == step_info['fission_mass_bds'].astype('float32') + assert tstep_info[5] == step_info['fission_mass_eds'].astype('float32') + assert np.array_equal(tstep_info[6], + step_info['keff_bds'].astype('float32')) + assert np.array_equal(tstep_info[7], + step_info['keff_eds'].astype('float32')) + assert tstep_info[8] == step_info['power_level'].astype('float32') # close the file db.close() diff --git a/tests/integration_tests/file_interface_openmc/test.py b/tests/integration_tests/file_interface_openmc/test.py index b58fa7862..df412403d 100644 --- a/tests/integration_tests/file_interface_openmc/test.py +++ b/tests/integration_tests/file_interface_openmc/test.py @@ -74,13 +74,15 @@ def test_update_depletable_materials(setup, openmc_depcode, openmc_reactor): for material in test_mats: if material.name in ref_mats.keys(): ref_material = ref_mats[material.name] - nucvec = openmc_depcode._create_mass_percents_dictionary(material, percent_type='wo') - test_material = saltproc.Materialflow(nucvec) - test_material.density = material.get_mass_density() - test_material.mass = material.density * material.volume - test_material.vol = material.volume - for key in test_material.keys(): - np.testing.assert_almost_equal(ref_material[key], test_material[key]) + comp = openmc_depcode._create_mass_percents_dictionary(material, percent_type='wo') + test_material = saltproc.Materialflow(comp=comp, + density=material.get_mass_density(), + volume=material.volume) + #test_material.set_density('g/cm3', material.get_mass_density()) + #test_material.mass = material.density * material.volume + #test_material.volume = material.volume + for key in test_material.comp.keys(): + np.testing.assert_almost_equal(ref_material.comp[key], test_material.comp[key]) os.remove(openmc_depcode.runtime_matfile) # add the initial geometry file back in @@ -189,8 +191,7 @@ def test_read_depleted_materials(setup, openmc_depcode): ref_mats = openmc_depcode.read_depleted_materials(True) for mat_name, ref_mat in ref_mats.items(): for nuc in xml_mats[mat_name].get_nuclides(): - pyne_nuc = openmc_depcode._convert_nucname_to_pyne(nuc) - np.testing.assert_almost_equal(ref_mat[pyne_nuc], xml_mats[mat_name].get_mass(nuc)) + np.testing.assert_almost_equal(ref_mat.get_mass(nuc), xml_mats[mat_name].get_mass(nuc)) def test_switch_to_next_geometry(setup, openmc_depcode, openmc_reactor): diff --git a/tests/integration_tests/run_constant_reprocessing_serpent/tap_processes.json b/tests/integration_tests/run_constant_reprocessing_serpent/tap_processes.json index 31620b24d..7d26c6320 100644 --- a/tests/integration_tests/run_constant_reprocessing_serpent/tap_processes.json +++ b/tests/integration_tests/run_constant_reprocessing_serpent/tap_processes.json @@ -109,11 +109,11 @@ "volume": 100000000, "mass": 496020000, "comp": { - "Li-6": 0.000002418, - "Li-7": 0.0483577563, - "F-19": 0.3296428341, - "U-235": 0.0310998496, - "U-238": 0.590897142 + "Li6": 0.000002418, + "Li7": 0.0483577563, + "F19": 0.3296428341, + "U235": 0.0310998496, + "U238": 0.590897142 } } } @@ -136,8 +136,8 @@ "volume": 10000, "mass": 58730, "comp": { - "Gd-158": 0.5, - "Gd-160": 0.5 + "Gd158": 0.5, + "Gd160": 0.5 } } } diff --git a/tests/integration_tests/run_constant_reprocessing_serpent/test.py b/tests/integration_tests/run_constant_reprocessing_serpent/test.py index 14e1e92ea..10f2559e6 100644 --- a/tests/integration_tests/run_constant_reprocessing_serpent/test.py +++ b/tests/integration_tests/run_constant_reprocessing_serpent/test.py @@ -9,13 +9,17 @@ import tables as tb import subprocess +def _create_nuclide_map(node): + nuclides = list(map(bytes.decode, node.nuclide_map.col('nuclide'))) + indices = node.nuclide_map.col('index') + return dict(zip(nuclides, indices)) @pytest.fixture def setup(scope='module'): cwd = str(Path(__file__).parents[0].resolve()) test_db = cwd + '/saltproc_runtime/saltproc_results.h5' ref_db = cwd + '/tap_reference_db.h5' - tol = 1e-9 + tol = 1e-5 return cwd, test_db, ref_db, tol @@ -29,8 +33,9 @@ def test_integration_2step_constant_ideal_removal_heavy(setup): cwd=cwd, stdout=sys.stdout, stderr=subprocess.STDOUT) - np.testing.assert_equal(read_keff(test_db), read_keff(ref_db)) - assert_db_almost_equal(test_db, ref_db, tol) + np.testing.assert_allclose(read_keff(test_db)[0], read_keff(ref_db)[0], rtol=5e-2) + np.testing.assert_allclose(read_keff(test_db)[1], read_keff(ref_db)[1], rtol=5e-1) + assert_db_allclose(test_db, ref_db, tol) shutil.rmtree(cwd + '/saltproc_runtime') @@ -44,106 +49,164 @@ def read_keff(file): k_1 = np.array([x['keff_eds'][0] for x in sim_param.iterrows()]) k_1_e = np.array([x['keff_eds'][1] for x in sim_param.iterrows()]) db.close() - return k_0, k_1, k_0_e, k_1_e - -def assert_db_almost_equal(test_db, ref_db, tol): - assert_nuclide_mass_equal(test_db, ref_db, tol) - assert_in_out_streams_equal(test_db, ref_db, tol) - ref_data, ref_param = read_fuel(ref_db) - test_data, test_param = read_fuel(test_db) + k = np.append(k_0, k_1) + k_e = np.append(k_0_e, k_1_e) + return k, k_e + +def assert_db_allclose(test_db, ref_db, tol): + assert_nuclide_mass_allclose(test_db, ref_db, tol) + assert_in_out_streams_allclose(test_db, ref_db, tol) + ref_data, ref_after_param, ref_before_param = read_fuel(ref_db, 'old') + test_data, test_after_param, test_before_param = read_fuel(test_db, 'new') # Compare materials composition - for node_nm, node in ref_data.items(): - for nuc, mass_arr in node.items(): - np.testing.assert_allclose( - mass_arr, test_data[node_nm][nuc], rtol=tol) + for node_name, test_comp in test_data.items(): + for nuc, test_mass_arr in test_comp.items(): + if len(nuc) > 4 and nuc[-3] == '_': + nuc = nuc[:-3] + nuc[-2:] + if nuc in ref_data[node_name]: + np.testing.assert_allclose( + test_mass_arr, ref_data[node_name][nuc], rtol=tol) # Compare material properties - np.testing.assert_allclose(test_param, ref_param, rtol=tol) + np.testing.assert_allclose(test_after_param, ref_after_param, rtol=tol) + np.testing.assert_allclose(test_before_param, ref_before_param, rtol=tol) -def assert_nuclide_mass_equal(test_db, ref_db, tol): - ref_mass_before, ref_mass_after = read_nuclide_mass(ref_db) - test_mass_before, test_mass_after = read_nuclide_mass(test_db) +def assert_nuclide_mass_allclose(test_db, ref_db, tol): + ref_mass_before, ref_mass_after = read_nuclide_mass(ref_db, 'old') + test_mass_before, test_mass_after = read_nuclide_mass(test_db, 'new') for key, val in ref_mass_before.items(): - np.testing.assert_almost_equal(val, test_mass_before[key], decimal=tol) + if key[-2] == 'm': + key = key[:-2] + '_' + key[-2:] + np.testing.assert_allclose(val, test_mass_before[key], rtol=tol) for key, val in ref_mass_after.items(): - np.testing.assert_almost_equal(val, test_mass_after[key], decimal=tol) + if key[-2] == 'm': + key = key[:-2] + '_' + key[-2:] + np.testing.assert_allclose(val, test_mass_after[key], rtol=tol) -def read_nuclide_mass(db_file): +def read_nuclide_mass(db_file, version): db = tb.open_file(db_file, mode='r') fuel_before = db.root.materials.fuel.before_reproc.comp fuel_after = db.root.materials.fuel.after_reproc.comp - nucmap = fuel_before.attrs.iso_map + if version == 'old': + before_nucmap = fuel_before.attrs.iso_map + after_nucmap = fuel_after.attrs.iso_map + else: + before_nucmap = _create_nuclide_map(db.root.materials.fuel.before_reproc) + after_nucmap = _create_nuclide_map(db.root.materials.fuel.after_reproc) mass_before = {} mass_after = {} - for nuc in nucmap: - mass_before[nuc] = np.array([row[nucmap[nuc]] for row in fuel_before]) - mass_after[nuc] = np.array([row1[nucmap[nuc]] for row1 in fuel_after]) + breakpoint() + for nuc, idx in before_nucmap.items(): + mass_before[nuc] = np.array([row[idx] for row in fuel_before]) + for nuc, idx in after_nucmap.items(): + mass_after[nuc] = np.array([row1[idx] for row1 in fuel_after]) db.close() return mass_before, mass_after -def assert_in_out_streams_equal(test_db, ref_db, tol): +def assert_in_out_streams_allclose(test_db, ref_db, tol): ref_sparger, \ - ref_test_separator, \ + ref_separator, \ ref_ni_filter, \ - ref_feed = read_in_out_streams(ref_db) + ref_feed = read_in_out_streams(ref_db, 'old') test_sparger, \ test_separator, \ test_ni_filter, \ - test_feed = read_in_out_streams(test_db) - for key, val in ref_sparger.items(): - np.testing.assert_almost_equal(val, test_sparger[key], decimal=tol) - for key, val in ref_test_separator.items(): - np.testing.assert_almost_equal(val, test_separator[key], decimal=tol) - for key, val in ref_ni_filter.items(): - np.testing.assert_almost_equal(val, test_ni_filter[key], decimal=tol) - for key, val in ref_feed.items(): - np.testing.assert_almost_equal(val, test_feed[key], decimal=tol) - -def read_in_out_streams(db_file): + test_feed = read_in_out_streams(test_db, 'new') + for key, val in test_sparger.items(): + if len(key) > 4 and key[-3] == '_': + key = key[:-3] + key[-2:] + if key in ref_sparger: + np.testing.assert_allclose(val, ref_sparger[key], rtol=tol) + for key, val in test_separator.items(): + if len(key) > 4 and key[-3] == '_': + key = key[:-3] + key[-2:] + if key in ref_separator: + np.testing.assert_allclose(val, ref_separator[key], rtol=tol) + for key, val in test_ni_filter.items(): + if len(key) > 4 and key[-3] == '_': + key = key[:-3] + key[-2:] + if key in ref_ni_filter: + np.testing.assert_allclose(val, ref_ni_filter[key], rtol=tol) + for key, val in test_feed.items(): + if len(key) > 4 and key[-3] == '_': + key = key[:-3] + key[-2:] + if key in ref_feed: + np.testing.assert_allclose(val, ref_feed[key], rtol=tol) + +def read_in_out_streams(db_file, version): db = tb.open_file(db_file, mode='r') waste_sparger = db.root.materials.fuel.in_out_streams.waste_sparger waste_separator = \ db.root.materials.fuel.in_out_streams.waste_entrainment_separator waste_ni_filter = db.root.materials.fuel.in_out_streams.waste_nickel_filter feed_leu = db.root.materials.fuel.in_out_streams.feed_leu - waste_nucmap = waste_ni_filter.attrs.iso_map - feed_nucmap = feed_leu.attrs.iso_map + if version == 'old': + waste_sparger_nucmap = waste_sparger.attrs.iso_map + waste_separator_nucmap = waste_separator.attrs.iso_map + waste_ni_filter_nucmap = waste_ni_filter.attrs.iso_map + feed_nucmap = feed_leu.attrs.iso_map + else: + waste_sparger_nucmap = _create_nuclide_map(waste_sparger) + waste_separator_nucmap = _create_nuclide_map(waste_separator) + waste_ni_filter_nucmap = _create_nuclide_map(waste_ni_filter) + feed_nucmap = _create_nuclide_map(feed_leu) + waste_sparger = waste_sparger.comp + waste_separator = waste_separator.comp + waste_ni_filter = waste_ni_filter.comp + feed_leu = feed_leu.comp + mass_waste_sparger = {} mass_waste_separator = {} mass_waste_ni_filter = {} mass_feed_leu = {} - for nuc in waste_nucmap: + for nuc, idx in waste_sparger_nucmap.items(): mass_waste_sparger[nuc] = np.array( - [row[waste_nucmap[nuc]] for row in waste_sparger]) + [row[idx] for row in waste_sparger]) + for nuc, idx in waste_separator_nucmap.items(): mass_waste_separator[nuc] = np.array( - [row[waste_nucmap[nuc]] for row in waste_separator]) + [row[idx] for row in waste_separator]) + for nuc, idx in waste_ni_filter_nucmap.items(): mass_waste_ni_filter[nuc] = np.array( - [row[waste_nucmap[nuc]] for row in waste_ni_filter]) - for nuc in feed_nucmap: + [row[idx] for row in waste_ni_filter]) + for nuc, idx in feed_nucmap.items(): mass_feed_leu[nuc] = np.array( - [row[feed_nucmap[nuc]] for row in feed_leu]) + [row[idx] for row in feed_leu]) db.close() return mass_waste_sparger, \ mass_waste_separator, \ mass_waste_ni_filter, \ mass_feed_leu -def read_fuel(file): +def read_fuel(file, version): db = tb.open_file(file, mode='r') fuel = db.root.materials.fuel out_data = {} for node in db.walk_nodes(fuel, classname="EArray"): - nucmap = node.attrs.iso_map - out_data[node._v_name] = {} + if version == 'old': + nucmap = node.attrs.iso_map + else: + nucmap = _create_nuclide_map(node._v_parent) + if node._v_name == 'comp': + node_name = node._v_parent._v_name + else: + node_name = node._v_name + out_data[node_name] = {} # print(node) - for nuc in nucmap: - out_data[node._v_name][nuc] = \ - np.array([row[nucmap[nuc]] for row in node]) + for nuc, idx in nucmap.items(): + out_data[node_name][nuc] = \ + np.array([row[idx] for row in node]) # Read table with material parameters (density, temperature, mass) - tmp = fuel.after_reproc.parameters.read() - # Convert structured array to simple array - param = tmp.view(np.float64).reshape(tmp.shape + (-1,)) + tmp_after = fuel.after_reproc.parameters.read() + tmp_before = fuel.before_reproc.parameters.read() + all_params = [] + for tmp in (tmp_after, tmp_before): + # Convert structured array to simple array + params = tmp.view(np.float64).reshape(tmp.shape + (-1,)) + # remove temperature as it is broken right now. + params = np.concatenate((params[:,0:3], params[:, 4:]), axis=1) + all_params += [params] + after_params, before_params = all_params db.close() - return out_data, param + return out_data, after_params, before_params diff --git a/tests/msbr_processes.json b/tests/msbr_processes.json index 2eb26bc3b..a43f57552 100644 --- a/tests/msbr_processes.json +++ b/tests/msbr_processes.json @@ -94,8 +94,8 @@ "volume": 100000000, "mass": 496020000, "comp": { - "Th-232": 0.55, - "U-233": 0.45 + "Th232": 0.55, + "U233": 0.45 } } } diff --git a/tests/tap_processes.json b/tests/tap_processes.json index 3bc058f08..0aaf61be1 100644 --- a/tests/tap_processes.json +++ b/tests/tap_processes.json @@ -117,11 +117,11 @@ "volume": 100000000, "mass": 496020000, "comp": { - "Li-6": 0.000002418, - "Li-7": 0.0483577563, - "F-19": 0.3296428341, - "U-235": 0.0310998496, - "U-238": 0.590897142 + "Li6": 0.000002418, + "Li7": 0.0483577563, + "F19": 0.3296428341, + "U235": 0.0310998496, + "U238": 0.590897142 } } } @@ -144,8 +144,8 @@ "volume": 10000, "mass": 58730, "comp": { - "Gd-158": 0.5, - "Gd-160": 0.5 + "Gd158": 0.5, + "Gd160": 0.5 } } } diff --git a/tests/unit_tests/test_app.py b/tests/unit_tests/test_app.py index 23b4a8603..da8544edd 100644 --- a/tests/unit_tests/test_app.py +++ b/tests/unit_tests/test_app.py @@ -202,10 +202,12 @@ def test_get_extraction_processes(proc_test_file): def test_get_feeds(proc_test_file): feeds = get_feeds(proc_test_file) - assert feeds['fuel']['leu'].mass == 4.9602E+8 + np.testing.assert_almost_equal(feeds['fuel']['leu'].mass, 4.9602E+8) assert feeds['fuel']['leu'].density == 4.9602 - assert feeds['fuel']['leu']['U235'] == 15426147.398592 - assert feeds['fuel']['leu']['U238'] == 293096800.37484 + np.testing.assert_almost_equal(feeds['fuel']['leu'].comp['U235'] * feeds['fuel']['leu'].mass, + 15426147.398592) + np.testing.assert_almost_equal(feeds['fuel']['leu'].comp['U238'] * feeds['fuel']['leu'].mass, + 293096800.37484) def test_get_extraction_process_paths(path_test_file): diff --git a/tests/unit_tests/test_materialflow.py b/tests/unit_tests/test_materialflow.py index dca96ff42..5259eb2e2 100644 --- a/tests/unit_tests/test_materialflow.py +++ b/tests/unit_tests/test_materialflow.py @@ -11,15 +11,8 @@ def test_scale_matflow(serpent_depcode): mats = serpent_depcode.read_depleted_materials(True) scale_factor = 0.7 scaled_matflow = mats['fuel'].scale_matflow(scale_factor) - assert scaled_matflow[922350000] == scale_factor * 3499538.3359278883 - assert scaled_matflow[922380000] == scale_factor * 66580417.24509208 - assert scaled_matflow[90190000] == scale_factor * 37145139.35897285 - assert scaled_matflow[30070000] == scale_factor * 5449107.821098938 + assert scaled_matflow['U235'] == scale_factor * mats['fuel'].get_mass('U235') + assert scaled_matflow['U238'] == scale_factor * mats['fuel'].get_mass('U238') + assert scaled_matflow['F19'] == scale_factor * mats['fuel'].get_mass('F19') + assert scaled_matflow['Li7'] == scale_factor * mats['fuel'].get_mass('Li7') - -def test_copy_pymat_attrs(serpent_depcode): - mats = serpent_depcode.read_depleted_materials(True) - target_mat = mats['fuel'] - target_mat.copy_pymat_attrs(mats['ctrlPois']) - assert target_mat.density == 5.873 - assert target_mat.atoms_per_molecule == -1.0 diff --git a/tests/unit_tests/test_process.py b/tests/unit_tests/test_process.py index 4cd76bebc..8c43192d4 100644 --- a/tests/unit_tests/test_process.py +++ b/tests/unit_tests/test_process.py @@ -17,15 +17,15 @@ def process(): def test_process_material(serpent_depcode, process): mats = serpent_depcode.read_depleted_materials(True) thru, waste = process.process_material(mats['fuel']) - np.testing.assert_almost_equal(waste[541350000], 19.79776930513891) - np.testing.assert_almost_equal(waste[541360000], 176.44741987005173) - np.testing.assert_almost_equal(waste[541280000], 9.911913132605642e-05) - np.testing.assert_almost_equal(waste[541390000], 0.026158507248944377) - np.testing.assert_almost_equal(waste[360790000], 6.420212330439721e-17) - np.testing.assert_almost_equal(waste[360800000], 1.6462261463853208e-06) - np.testing.assert_almost_equal(waste[360920000], 0.0002724894672886946) - np.testing.assert_almost_equal(waste[360860000], 26.847312879174968) - assert waste.mass == 531.0633118374121 + np.testing.assert_almost_equal(waste.get_mass('Xe135'), 19.7977787475) + np.testing.assert_almost_equal(waste.get_mass('Xe136'), 176.44750402500003) + np.testing.assert_almost_equal(waste.get_mass('Xe128'), 9.911913132605642e-05) + np.testing.assert_almost_equal(waste.get_mass('Xe139'), 0.026158507248944377) + np.testing.assert_almost_equal(waste.get_mass('Kr79'), 6.420212330439721e-17) + np.testing.assert_almost_equal(waste.get_mass('Kr80'), 1.6462261463853208e-06) + np.testing.assert_almost_equal(waste.get_mass('Kr92'), 0.0002724894672886946) + np.testing.assert_almost_equal(waste.get_mass('Kr86'), 26.84732568375) + assert waste.mass == 531.0635651230967 def test_calculate_removal_efficiency(process): diff --git a/tests/unit_tests/test_separator.py b/tests/unit_tests/test_separator.py index 79bc8b4ed..ba1c9be9c 100644 --- a/tests/unit_tests/test_separator.py +++ b/tests/unit_tests/test_separator.py @@ -17,12 +17,12 @@ def separator(): def test_rem_elements(serpent_depcode, separator): mats = serpent_depcode.read_depleted_materials(True) thru, waste = separator.process_material(mats['fuel']) - np.testing.assert_almost_equal(waste[541350000], 19.5320018359295) - np.testing.assert_almost_equal(waste[541360000], 174.0787699729534) - np.testing.assert_almost_equal(waste[541280000], 9.778854502227908e-05) - np.testing.assert_almost_equal(waste[541390000], 0.025807352522232645) - np.testing.assert_almost_equal(waste[360790000], 1.2668053364239955e-15) - np.testing.assert_almost_equal(waste[360800000], 1.709607392097611e-06) - np.testing.assert_almost_equal(waste[360920000], 0.0002829805665329617) - np.testing.assert_almost_equal(waste[360860000], 27.88095952489617) - assert waste.mass == 527.0884551454453 + np.testing.assert_allclose(waste.get_mass('Xe135'), 19.5320018359295, rtol=1e-6) + np.testing.assert_allclose(waste.get_mass('Xe136'), 174.0787699729534, rtol=1e-6) + np.testing.assert_allclose(waste.get_mass('Xe128'), 9.778854502227908e-05, rtol=1e-6) + np.testing.assert_allclose(waste.get_mass('Xe139'), 0.025807352522232645, rtol=1e-6) + np.testing.assert_allclose(waste.get_mass('Kr79'), 1.2668053364239955e-15, rtol=1e-6) + np.testing.assert_allclose(waste.get_mass('Kr80'), 1.709607392097611e-06, rtol=1e-6) + np.testing.assert_allclose(waste.get_mass('Kr92'), 0.0002829805665329617, rtol=1e-6) + np.testing.assert_allclose(waste.get_mass('Kr86'), 27.88095952489617, rtol=1e-6) + np.testing.assert_allclose(waste.mass, 527.0884551454453, rtol=1e-6) diff --git a/tests/unit_tests/test_serpent_depcode.py b/tests/unit_tests/test_serpent_depcode.py index a7114ac0e..64fef8e82 100644 --- a/tests/unit_tests/test_serpent_depcode.py +++ b/tests/unit_tests/test_serpent_depcode.py @@ -9,57 +9,57 @@ def test_create_nuclide_name_map_zam_to_serpent(serpent_depcode, cwd): old_runtime_inputfile = serpent_depcode.runtime_inputfile - nuc_code_map = serpent_depcode.map_nuclide_code_zam_to_serpent() - assert nuc_code_map[380880] == '38088.09c' - assert nuc_code_map[962400] == '96240.09c' - assert nuc_code_map[952421] == '95342.09c' - assert nuc_code_map[340831] == '340831' - assert nuc_code_map[300732] == '300732' - assert nuc_code_map[511262] == '511262' - assert nuc_code_map[420931] == '420931' - assert nuc_code_map[410911] == '410911' + nuc_code_map = serpent_depcode.map_nuclide_name_to_serpent_name() + assert nuc_code_map['Sr88'] == '38088.09c' + assert nuc_code_map['Cm240'] == '96240.09c' + assert nuc_code_map['Am242_m1'] == '95342.09c' + assert nuc_code_map['Se83_m1'] == '340831' + assert nuc_code_map['Zn73_m2'] == '300732' + assert nuc_code_map['Sb126_m2'] == '511262' + assert nuc_code_map['Mo93_m1'] == '420931' + assert nuc_code_map['Nb91_m1'] == '410911' serpent_depcode.zaid_convention = 'mcnp' serpent_depcode.runtime_inputfile = str(cwd / 'serpent_data' / 'tap_reference_mcnp') - nuc_code_map = serpent_depcode.map_nuclide_code_zam_to_serpent() - assert nuc_code_map[380880] == '38088.82c' - assert nuc_code_map[962400] == '96240.82c' - assert nuc_code_map[952421] == '95642.82c' - assert nuc_code_map[952420] == '95242.82c' - assert nuc_code_map[471101] == '47510.82c' - assert nuc_code_map[340831] == '340831' - assert nuc_code_map[300732] == '300732' - assert nuc_code_map[511262] == '511262' - assert nuc_code_map[420931] == '420931' - assert nuc_code_map[410911] == '410911' + nuc_code_map = serpent_depcode.map_nuclide_name_to_serpent_name() + assert nuc_code_map['Sr88'] == '38088.82c' + assert nuc_code_map['Cm240'] == '96240.82c' + assert nuc_code_map['Am242_m1'] == '95642.82c' + assert nuc_code_map['Am242'] == '95242.82c' + assert nuc_code_map['Ag110_m1'] == '47510.82c' + assert nuc_code_map['Se83_m1'] == '340831' + assert nuc_code_map['Zn73_m2'] == '300732' + assert nuc_code_map['Sb126_m2'] == '511262' + assert nuc_code_map['Mo93_m1'] == '420931' + assert nuc_code_map['Nb91_m1'] == '410911' serpent_depcode.zaid_convention = 'nndc' serpent_depcode.runtime_inputfile = str(cwd / 'serpent_data' / 'tap_reference_nndc') - nuc_code_map = serpent_depcode.map_nuclide_code_zam_to_serpent() - - assert nuc_code_map[380880] == '38088.82c' - assert nuc_code_map[962400] == '96240.82c' - assert nuc_code_map[952421] == '95242.82c' - assert nuc_code_map[952420] == '95642.82c' - assert nuc_code_map[471101] == '47510.82c' - assert nuc_code_map[340831] == '340831' - assert nuc_code_map[300732] == '300732' - assert nuc_code_map[511262] == '511262' - assert nuc_code_map[420931] == '420931' - assert nuc_code_map[410911] == '410911' + nuc_code_map = serpent_depcode.map_nuclide_name_to_serpent_name() + + assert nuc_code_map['Sr88'] == '38088.82c' + assert nuc_code_map['Cm240'] == '96240.82c' + assert nuc_code_map['Am242_m1'] == '95242.82c' + assert nuc_code_map['Am242'] == '95642.82c' + assert nuc_code_map['Ag110_m1'] == '47510.82c' + assert nuc_code_map['Se83_m1'] == '340831' + assert nuc_code_map['Zn73_m2'] == '300732' + assert nuc_code_map['Sb126_m2'] == '511262' + assert nuc_code_map['Mo93_m1'] == '420931' + assert nuc_code_map['Nb91_m1'] == '410911' serpent_depcode.runtime_inputfile = old_runtime_inputfile serpent_depcode.zaid_convention = 'serpent' -def test_convert_nuclide_code_to_zam(serpent_depcode): - assert serpent_depcode.convert_nuclide_code_to_zam(47310) == 471101 - assert serpent_depcode.convert_nuclide_code_to_zam(95342) == 952421 - assert serpent_depcode.convert_nuclide_code_to_zam(61348) == 611481 - assert serpent_depcode.convert_nuclide_code_to_zam(52327) == 521271 - assert serpent_depcode.convert_nuclide_code_to_zam(1001) == 1001 - assert serpent_depcode.convert_nuclide_code_to_zam(1002) == 1002 - assert serpent_depcode.convert_nuclide_code_to_zam(48315) == 481151 +def test_nuclide_code_to_zam(serpent_depcode): + assert serpent_depcode._nuclide_code_to_zam(47310) == (47, 110, 1) + assert serpent_depcode._nuclide_code_to_zam(95342) == (95, 242, 1) + assert serpent_depcode._nuclide_code_to_zam(61348) == (61, 148, 1) + assert serpent_depcode._nuclide_code_to_zam(52327) == (52, 127, 1) + assert serpent_depcode._nuclide_code_to_zam(1001) == (1, 1, 0) + assert serpent_depcode._nuclide_code_to_zam(1002) == (1, 2, 0) + assert serpent_depcode._nuclide_code_to_zam(48315) == (48, 115, 1) def test_get_neutron_settings(serpent_depcode): @@ -111,55 +111,55 @@ def test_read_plaintext_file(serpent_depcode): assert template_str[23] == 'set pcc 1\n' -def test_convert_nuclide_code_to_name(serpent_depcode): - assert serpent_depcode.convert_nuclide_code_to_name('92235.09c') == 'U235' - assert serpent_depcode.convert_nuclide_code_to_name('38088.09c') == 'Sr88' - assert serpent_depcode.convert_nuclide_code_to_name('95342.09c') == 'Am242m1' - assert serpent_depcode.convert_nuclide_code_to_name('61348.03c') == 'Pm148m1' - assert serpent_depcode.convert_nuclide_code_to_name('20060') == 'He6' - assert serpent_depcode.convert_nuclide_code_to_name('110241') == 'Na24m1' - assert serpent_depcode.convert_nuclide_code_to_name('170381') == 'Cl38m1' - assert serpent_depcode.convert_nuclide_code_to_name('310741') == 'Ga74m1' - assert serpent_depcode.convert_nuclide_code_to_name('290702') == 'Cu70m2' - assert serpent_depcode.convert_nuclide_code_to_name('250621') == 'Mn62m1' - assert serpent_depcode.convert_nuclide_code_to_name('300732') == 'Zn73m2' - assert serpent_depcode.convert_nuclide_code_to_name('370981') == 'Rb98m1' - assert serpent_depcode.convert_nuclide_code_to_name('390972') == 'Y97m2' - assert serpent_depcode.convert_nuclide_code_to_name('491142') == 'In114m2' +def test_nuclide_code_to_name(serpent_depcode): + assert serpent_depcode.nuclide_code_to_name('92235.09c') == 'U235' + assert serpent_depcode.nuclide_code_to_name('38088.09c') == 'Sr88' + assert serpent_depcode.nuclide_code_to_name('95342.09c') == 'Am242_m1' + assert serpent_depcode.nuclide_code_to_name('61348.03c') == 'Pm148_m1' + assert serpent_depcode.nuclide_code_to_name('20060') == 'He6' + assert serpent_depcode.nuclide_code_to_name('110241') == 'Na24_m1' + assert serpent_depcode.nuclide_code_to_name('170381') == 'Cl38_m1' + assert serpent_depcode.nuclide_code_to_name('310741') == 'Ga74_m1' + assert serpent_depcode.nuclide_code_to_name('290702') == 'Cu70_m2' + assert serpent_depcode.nuclide_code_to_name('250621') == 'Mn62_m1' + assert serpent_depcode.nuclide_code_to_name('300732') == 'Zn73_m2' + assert serpent_depcode.nuclide_code_to_name('370981') == 'Rb98_m1' + assert serpent_depcode.nuclide_code_to_name('390972') == 'Y97_m2' + assert serpent_depcode.nuclide_code_to_name('491142') == 'In114_m2' serpent_depcode.zaid_convention = 'mcnp' - assert serpent_depcode.convert_nuclide_code_to_name('92235.82c') == 'U235' - assert serpent_depcode.convert_nuclide_code_to_name('38088.82c') == 'Sr88' - assert serpent_depcode.convert_nuclide_code_to_name('95642.82c') == 'Am242m1' - assert serpent_depcode.convert_nuclide_code_to_name('95242.82c') == 'Am242' - assert serpent_depcode.convert_nuclide_code_to_name('61548.82c') == 'Pm148m1' - assert serpent_depcode.convert_nuclide_code_to_name('20060') == 'He6' - assert serpent_depcode.convert_nuclide_code_to_name('110241') == 'Na24m1' - assert serpent_depcode.convert_nuclide_code_to_name('170381') == 'Cl38m1' - assert serpent_depcode.convert_nuclide_code_to_name('310741') == 'Ga74m1' - assert serpent_depcode.convert_nuclide_code_to_name('290702') == 'Cu70m2' - assert serpent_depcode.convert_nuclide_code_to_name('250621') == 'Mn62m1' - assert serpent_depcode.convert_nuclide_code_to_name('300732') == 'Zn73m2' - assert serpent_depcode.convert_nuclide_code_to_name('370981') == 'Rb98m1' - assert serpent_depcode.convert_nuclide_code_to_name('390972') == 'Y97m2' - assert serpent_depcode.convert_nuclide_code_to_name('491142') == 'In114m2' + assert serpent_depcode.nuclide_code_to_name('92235.82c') == 'U235' + assert serpent_depcode.nuclide_code_to_name('38088.82c') == 'Sr88' + assert serpent_depcode.nuclide_code_to_name('95642.82c') == 'Am242_m1' + assert serpent_depcode.nuclide_code_to_name('95242.82c') == 'Am242' + assert serpent_depcode.nuclide_code_to_name('61548.82c') == 'Pm148_m1' + assert serpent_depcode.nuclide_code_to_name('20060') == 'He6' + assert serpent_depcode.nuclide_code_to_name('110241') == 'Na24_m1' + assert serpent_depcode.nuclide_code_to_name('170381') == 'Cl38_m1' + assert serpent_depcode.nuclide_code_to_name('310741') == 'Ga74_m1' + assert serpent_depcode.nuclide_code_to_name('290702') == 'Cu70_m2' + assert serpent_depcode.nuclide_code_to_name('250621') == 'Mn62_m1' + assert serpent_depcode.nuclide_code_to_name('300732') == 'Zn73_m2' + assert serpent_depcode.nuclide_code_to_name('370981') == 'Rb98_m1' + assert serpent_depcode.nuclide_code_to_name('390972') == 'Y97_m2' + assert serpent_depcode.nuclide_code_to_name('491142') == 'In114_m2' serpent_depcode.zaid_convention = 'nndc' - assert serpent_depcode.convert_nuclide_code_to_name('92235.82c') == 'U235' - assert serpent_depcode.convert_nuclide_code_to_name('38088.82c') == 'Sr88' - assert serpent_depcode.convert_nuclide_code_to_name('95242.82c') == 'Am242m1' - assert serpent_depcode.convert_nuclide_code_to_name('95642.82c') == 'Am242' - assert serpent_depcode.convert_nuclide_code_to_name('61548.82c') == 'Pm148m1' - assert serpent_depcode.convert_nuclide_code_to_name('20060') == 'He6' - assert serpent_depcode.convert_nuclide_code_to_name('110241') == 'Na24m1' - assert serpent_depcode.convert_nuclide_code_to_name('170381') == 'Cl38m1' - assert serpent_depcode.convert_nuclide_code_to_name('310741') == 'Ga74m1' - assert serpent_depcode.convert_nuclide_code_to_name('290702') == 'Cu70m2' - assert serpent_depcode.convert_nuclide_code_to_name('250621') == 'Mn62m1' - assert serpent_depcode.convert_nuclide_code_to_name('300732') == 'Zn73m2' - assert serpent_depcode.convert_nuclide_code_to_name('370981') == 'Rb98m1' - assert serpent_depcode.convert_nuclide_code_to_name('390972') == 'Y97m2' - assert serpent_depcode.convert_nuclide_code_to_name('491142') == 'In114m2' + assert serpent_depcode.nuclide_code_to_name('92235.82c') == 'U235' + assert serpent_depcode.nuclide_code_to_name('38088.82c') == 'Sr88' + assert serpent_depcode.nuclide_code_to_name('95242.82c') == 'Am242_m1' + assert serpent_depcode.nuclide_code_to_name('95642.82c') == 'Am242' + assert serpent_depcode.nuclide_code_to_name('61548.82c') == 'Pm148_m1' + assert serpent_depcode.nuclide_code_to_name('20060') == 'He6' + assert serpent_depcode.nuclide_code_to_name('110241') == 'Na24_m1' + assert serpent_depcode.nuclide_code_to_name('170381') == 'Cl38_m1' + assert serpent_depcode.nuclide_code_to_name('310741') == 'Ga74_m1' + assert serpent_depcode.nuclide_code_to_name('290702') == 'Cu70_m2' + assert serpent_depcode.nuclide_code_to_name('250621') == 'Mn62_m1' + assert serpent_depcode.nuclide_code_to_name('300732') == 'Zn73_m2' + assert serpent_depcode.nuclide_code_to_name('370981') == 'Rb98_m1' + assert serpent_depcode.nuclide_code_to_name('390972') == 'Y97_m2' + assert serpent_depcode.nuclide_code_to_name('491142') == 'In114_m2' serpent_depcode.zaid_convention = 'serpent' @@ -180,7 +180,7 @@ def test_read_step_metadata(serpent_depcode): assert serpent_depcode.step_metadata['OMP_threads'] == 4 assert serpent_depcode.step_metadata['memory_optimization_mode'] == 4 assert serpent_depcode.step_metadata['depletion_timestep'] == 3.0 - assert serpent_depcode.step_metadata['memory_usage'] == [10552.84] + assert serpent_depcode.step_metadata['memory_usage'] == [10552.8] assert serpent_depcode.step_metadata['execution_time'] == [81.933] @@ -195,11 +195,11 @@ def test_read_neutronics_parameters(serpent_depcode): def test_read_depleted_materials(serpent_depcode): mats = serpent_depcode.read_depleted_materials(True) - assert mats['fuel']['U235'] == 3499538.3359278883 - assert mats['fuel']['U238'] == 66580417.24509208 - assert mats['fuel']['F19'] == 37145139.35897285 - assert mats['fuel']['Li7'] == 5449107.821098938 - assert mats['fuel']['Cm240'] == 8.787897203694538e-22 - assert mats['fuel']['Pu239'] == 1231.3628804629795 - assert mats['ctrlPois']['Gd155'] == 5812.83289505528 - assert mats['ctrlPois']['O16'] == 15350.701473655872 + np.testing.assert_allclose(mats['fuel'].get_mass('U235'), 3499538.3359278883, rtol=1e-6) + np.testing.assert_allclose(mats['fuel'].get_mass('U238'), 66580417.24509208, rtol=1e-6) + np.testing.assert_allclose(mats['fuel'].get_mass('F19'), 37145139.35897285, rtol=1e-6) + np.testing.assert_allclose(mats['fuel'].get_mass('Li7'), 5449107.821098938, rtol=1e-6) + np.testing.assert_allclose(mats['fuel'].get_mass('Cm240'), 8.787897203694538e-22, rtol=1e-6) + np.testing.assert_allclose(mats['fuel'].get_mass('Pu239'), 1231.3628804629795, rtol=1e-6) + np.testing.assert_allclose(mats['ctrlPois'].get_mass('Gd155'), 5812.83289505528, rtol=1e-6) + np.testing.assert_allclose(mats['ctrlPois'].get_mass('O16'), 15350.701473655872, rtol=1e-6) diff --git a/tests/unit_tests/test_sparger.py b/tests/unit_tests/test_sparger.py index a9269426a..608db4b3d 100644 --- a/tests/unit_tests/test_sparger.py +++ b/tests/unit_tests/test_sparger.py @@ -17,12 +17,12 @@ def sparger(): def test_rem_elements(serpent_depcode, sparger): mats = serpent_depcode.read_depleted_materials(True) thru, waste = sparger.process_material(mats['fuel']) - np.testing.assert_almost_equal(waste[541350000], 8.061014535231715) - np.testing.assert_almost_equal(waste[541360000], 71.8437109936129) - np.testing.assert_almost_equal(waste[541280000], 4.0358120454079906e-05) - np.testing.assert_almost_equal(waste[541390000], 0.010650902326605592) - np.testing.assert_almost_equal(waste[360790000], 6.420212330439721e-17) - np.testing.assert_almost_equal(waste[360800000], 7.029023635956131e-07) - np.testing.assert_almost_equal(waste[360920000], 0.00011634701042301513) - np.testing.assert_almost_equal(waste[360860000], 11.463212220507412) - assert waste.mass == 217.43479356542446 + np.testing.assert_allclose(waste.get_mass('Xe135'), 8.061014535231715, rtol=1e-6) + np.testing.assert_allclose(waste.get_mass('Xe136'), 71.8437109936129, rtol=1e-6) + np.testing.assert_allclose(waste.get_mass('Xe128'), 4.0358120454079906e-05, rtol=1e-6) + np.testing.assert_allclose(waste.get_mass('Xe139'), 0.010650902326605592, rtol=1e-6) + np.testing.assert_allclose(waste.get_mass('Kr79'), 5.208452501967084e-16, rtol=1e-6) + np.testing.assert_allclose(waste.get_mass('Kr80'), 7.029023635956131e-07, rtol=1e-6) + np.testing.assert_allclose(waste.get_mass('Kr92'), 0.00011634701042301513, rtol=1e-6) + np.testing.assert_allclose(waste.get_mass('Kr86'), 11.463212220507412, rtol=1e-6) + np.testing.assert_allclose(waste.mass, 217.43479356542446, rtol=1e-6) From 2edfed2248d45ac0a8a116805beba5008805fa9e Mon Sep 17 00:00:00 2001 From: yardasol Date: Wed, 5 Apr 2023 14:02:50 -0500 Subject: [PATCH 02/62] fix package name for tables --- environment.yml | 2 +- requirements.txt | 2 +- saltproc/version.py | 2 +- setup.py | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/environment.yml b/environment.yml index 360cf1922..d2f6896a6 100644 --- a/environment.yml +++ b/environment.yml @@ -5,7 +5,7 @@ channels: dependencies: - numpy - openmc - - pytables + - tables - networkx - pydot - pytest diff --git a/requirements.txt b/requirements.txt index f08348840..df333ccef 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy scipy json jsonschema -pytables +tables networkx pydot serpentTools diff --git a/saltproc/version.py b/saltproc/version.py index 848b61461..03ebd7d16 100644 --- a/saltproc/version.py +++ b/saltproc/version.py @@ -90,7 +90,7 @@ PACKAGES = ["saltproc"] REQUIRES = ["numpy", "networkx", - "pytables", + "tables", "pydot", "pytest", "argparse", diff --git a/setup.py b/setup.py index f95a55c24..f6ce77bb2 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,6 @@ with open(ver_file) as f: exec(f.read()) - ENTRY_POINTS = { 'console_scripts': ['saltproc = saltproc.app:run'] } From bf80f44f69ec9c4387286bdeab428a0c26bbcf0e Mon Sep 17 00:00:00 2001 From: yardasol Date: Tue, 18 Apr 2023 11:39:27 -0500 Subject: [PATCH 03/62] add subprocess_kwargs parameter --- saltproc/app.py | 10 +++++++--- saltproc/depcode.py | 5 +++-- saltproc/input_schema.json | 6 +++++- saltproc/openmc_depcode.py | 4 ++-- saltproc/serpent_depcode.py | 4 ++-- 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/saltproc/app.py b/saltproc/app.py index 9de9fcae3..72d048250 100644 --- a/saltproc/app.py +++ b/saltproc/app.py @@ -35,7 +35,7 @@ def run(): """ Inititializes main run""" threads, saltproc_input = parse_arguments() - input_path, process_file, dot_file, mpi_args, object_input = \ + input_path, process_file, dot_file, mpi_args, subprocess_kwargs, object_input = \ read_main_input(saltproc_input) _print_simulation_input_info(object_input[1], object_input[0]) # Intializing objects @@ -53,7 +53,7 @@ def run(): simulation.sim_depcode.write_runtime_input(msr, step_idx, simulation.restart_flag) - depcode.run_depletion_step(mpi_args, threads) + depcode.run_depletion_step(mpi_args, threads, subprocess_kwargs) if step_idx == 0 and simulation.restart_flag is False: # First step # Read general simulation data which never changes simulation.store_run_init_info() @@ -257,7 +257,9 @@ def read_main_input(main_inp_file): reactor_input = _process_main_input_reactor_params( reactor_input, n_depletion_steps, depcode_input['codename']) - return input_path, process_file, dot_file, mpi_args, ( + subprocess_kwargs = depcode_input['subprocess_kwargs'] + + return input_path, process_file, dot_file, mpi_args, subprocess_kwargs, ( depcode_input, simulation_input, reactor_input) def _print_simulation_input_info(simulation_input, depcode_input): @@ -277,9 +279,11 @@ def _print_simulation_input_info(simulation_input, depcode_input): def _create_depcode_object(depcode_input): """Helper function for `run()` """ codename = depcode_input.pop('codename') + subprocess_kwargs = depcode_input.pop('subprocess_kwargs') depcode = CODENAME_MAP[codename] depcode = depcode(**depcode_input) depcode_input['codename'] = codename + depcode_input['subprocess_kwargs'] = subprocess_kwargs return depcode diff --git a/saltproc/depcode.py b/saltproc/depcode.py index 3351af634..36d533a13 100644 --- a/saltproc/depcode.py +++ b/saltproc/depcode.py @@ -101,7 +101,7 @@ def read_depleted_materials(self, read_at_end=False): :class:`Materialflow` object holding material composition and properties. """ - def run_depletion_step(self, mpi_args, args): + def run_depletion_step(self, mpi_args, args, subprocess_kwargs): """Runs a depletion step as a subprocess with the given parameters. Parameters @@ -125,7 +125,8 @@ def run_depletion_step(self, mpi_args, args): check=True, cwd=self.output_path, stdout=stdout, - stderr=subprocess.STDOUT) + stderr=subprocess.STDOUT, + **subprocess_kwargs) print(f'Finished {self.codename.upper()} Run') except subprocess.CalledProcessError as error: print(error.output.decode("utf-8")) diff --git a/saltproc/input_schema.json b/saltproc/input_schema.json index 9a5ef57f8..2502c0361 100644 --- a/saltproc/input_schema.json +++ b/saltproc/input_schema.json @@ -49,7 +49,11 @@ "type": "array", "items": { "type": "string"}, "minItems": 1, - "uniqueItems": true} + "uniqueItems": true}, + "subprocess_kwargs": { + "description": "Keyword arguments for subprocess.run() in Depcode.run_depletion_step()", + "type": "object", + "default": {}} }, "required": ["codename", "template_input_file_path", "geo_file_paths"], "allOf": [ diff --git a/saltproc/openmc_depcode.py b/saltproc/openmc_depcode.py index f85726d41..b6b8dd17c 100644 --- a/saltproc/openmc_depcode.py +++ b/saltproc/openmc_depcode.py @@ -376,7 +376,7 @@ def name_to_nuclide_code(self, nucname): code += 300 + 100 * m return code - def run_depletion_step(self, mpi_args=None, threads=None): + def run_depletion_step(self, mpi_args, threads, subprocess_kwargs): """Runs a depletion step in OpenMC as a subprocess mpi_args : list of str @@ -402,7 +402,7 @@ def run_depletion_step(self, mpi_args=None, threads=None): if mpi_args is not None: args = mpi_args + args - super().run_depletion_step(mpi_args, args) + super().run_depletion_step(mpi_args, args, subprocess_kwargs) def switch_to_next_geometry(self): """Switches the geometry file for the OpenMC depletion simulation to diff --git a/saltproc/serpent_depcode.py b/saltproc/serpent_depcode.py index 53a7386bb..99be62356 100644 --- a/saltproc/serpent_depcode.py +++ b/saltproc/serpent_depcode.py @@ -479,7 +479,7 @@ def set_power_load(self, (current_power, step_type, step_length)) return file_lines - def run_depletion_step(self, mpi_args=None, threads=None): + def run_depletion_step(self, mpi_args, threads, subprocess_kwargs): """Runs a depletion step in Serpent2 as a subprocess. i Parameters @@ -502,7 +502,7 @@ def run_depletion_step(self, mpi_args=None, threads=None): args = args + [self.runtime_inputfile] - super().run_depletion_step(mpi_args, args) + super().run_depletion_step(mpi_args, args, subprocess_kwargs) def switch_to_next_geometry(self): """Inserts line with path to next Serpent geometry file at the From 8c96cf3be5e937ff8b625b6a74bc22d2c13b9f19 Mon Sep 17 00:00:00 2001 From: yardasol Date: Wed, 19 Apr 2023 11:46:01 -0500 Subject: [PATCH 04/62] fix dependencies --- environment.yml | 2 +- requirements.txt | 3 ++- saltproc/version.py | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/environment.yml b/environment.yml index d2f6896a6..360cf1922 100644 --- a/environment.yml +++ b/environment.yml @@ -5,7 +5,7 @@ channels: dependencies: - numpy - openmc - - tables + - pytables - networkx - pydot - pytest diff --git a/requirements.txt b/requirements.txt index df333ccef..60e68107a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,8 @@ numpy scipy json jsonschema -tables +openmc +pytables networkx pydot serpentTools diff --git a/saltproc/version.py b/saltproc/version.py index 03ebd7d16..dc17a40f3 100644 --- a/saltproc/version.py +++ b/saltproc/version.py @@ -90,6 +90,7 @@ PACKAGES = ["saltproc"] REQUIRES = ["numpy", "networkx", + "openmc", "tables", "pydot", "pytest", From 55dadc7a7ec33482ad2e7876ab18e148d371281b Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 20 Apr 2023 11:19:05 -0500 Subject: [PATCH 05/62] Revert "add subprocess_kwargs parameter" This reverts commit bf80f44f69ec9c4387286bdeab428a0c26bbcf0e. --- saltproc/app.py | 10 +++------- saltproc/depcode.py | 5 ++--- saltproc/input_schema.json | 6 +----- saltproc/openmc_depcode.py | 4 ++-- saltproc/serpent_depcode.py | 4 ++-- 5 files changed, 10 insertions(+), 19 deletions(-) diff --git a/saltproc/app.py b/saltproc/app.py index 72d048250..9de9fcae3 100644 --- a/saltproc/app.py +++ b/saltproc/app.py @@ -35,7 +35,7 @@ def run(): """ Inititializes main run""" threads, saltproc_input = parse_arguments() - input_path, process_file, dot_file, mpi_args, subprocess_kwargs, object_input = \ + input_path, process_file, dot_file, mpi_args, object_input = \ read_main_input(saltproc_input) _print_simulation_input_info(object_input[1], object_input[0]) # Intializing objects @@ -53,7 +53,7 @@ def run(): simulation.sim_depcode.write_runtime_input(msr, step_idx, simulation.restart_flag) - depcode.run_depletion_step(mpi_args, threads, subprocess_kwargs) + depcode.run_depletion_step(mpi_args, threads) if step_idx == 0 and simulation.restart_flag is False: # First step # Read general simulation data which never changes simulation.store_run_init_info() @@ -257,9 +257,7 @@ def read_main_input(main_inp_file): reactor_input = _process_main_input_reactor_params( reactor_input, n_depletion_steps, depcode_input['codename']) - subprocess_kwargs = depcode_input['subprocess_kwargs'] - - return input_path, process_file, dot_file, mpi_args, subprocess_kwargs, ( + return input_path, process_file, dot_file, mpi_args, ( depcode_input, simulation_input, reactor_input) def _print_simulation_input_info(simulation_input, depcode_input): @@ -279,11 +277,9 @@ def _print_simulation_input_info(simulation_input, depcode_input): def _create_depcode_object(depcode_input): """Helper function for `run()` """ codename = depcode_input.pop('codename') - subprocess_kwargs = depcode_input.pop('subprocess_kwargs') depcode = CODENAME_MAP[codename] depcode = depcode(**depcode_input) depcode_input['codename'] = codename - depcode_input['subprocess_kwargs'] = subprocess_kwargs return depcode diff --git a/saltproc/depcode.py b/saltproc/depcode.py index 36d533a13..3351af634 100644 --- a/saltproc/depcode.py +++ b/saltproc/depcode.py @@ -101,7 +101,7 @@ def read_depleted_materials(self, read_at_end=False): :class:`Materialflow` object holding material composition and properties. """ - def run_depletion_step(self, mpi_args, args, subprocess_kwargs): + def run_depletion_step(self, mpi_args, args): """Runs a depletion step as a subprocess with the given parameters. Parameters @@ -125,8 +125,7 @@ def run_depletion_step(self, mpi_args, args, subprocess_kwargs): check=True, cwd=self.output_path, stdout=stdout, - stderr=subprocess.STDOUT, - **subprocess_kwargs) + stderr=subprocess.STDOUT) print(f'Finished {self.codename.upper()} Run') except subprocess.CalledProcessError as error: print(error.output.decode("utf-8")) diff --git a/saltproc/input_schema.json b/saltproc/input_schema.json index 2502c0361..9a5ef57f8 100644 --- a/saltproc/input_schema.json +++ b/saltproc/input_schema.json @@ -49,11 +49,7 @@ "type": "array", "items": { "type": "string"}, "minItems": 1, - "uniqueItems": true}, - "subprocess_kwargs": { - "description": "Keyword arguments for subprocess.run() in Depcode.run_depletion_step()", - "type": "object", - "default": {}} + "uniqueItems": true} }, "required": ["codename", "template_input_file_path", "geo_file_paths"], "allOf": [ diff --git a/saltproc/openmc_depcode.py b/saltproc/openmc_depcode.py index b6b8dd17c..f85726d41 100644 --- a/saltproc/openmc_depcode.py +++ b/saltproc/openmc_depcode.py @@ -376,7 +376,7 @@ def name_to_nuclide_code(self, nucname): code += 300 + 100 * m return code - def run_depletion_step(self, mpi_args, threads, subprocess_kwargs): + def run_depletion_step(self, mpi_args=None, threads=None): """Runs a depletion step in OpenMC as a subprocess mpi_args : list of str @@ -402,7 +402,7 @@ def run_depletion_step(self, mpi_args, threads, subprocess_kwargs): if mpi_args is not None: args = mpi_args + args - super().run_depletion_step(mpi_args, args, subprocess_kwargs) + super().run_depletion_step(mpi_args, args) def switch_to_next_geometry(self): """Switches the geometry file for the OpenMC depletion simulation to diff --git a/saltproc/serpent_depcode.py b/saltproc/serpent_depcode.py index 99be62356..53a7386bb 100644 --- a/saltproc/serpent_depcode.py +++ b/saltproc/serpent_depcode.py @@ -479,7 +479,7 @@ def set_power_load(self, (current_power, step_type, step_length)) return file_lines - def run_depletion_step(self, mpi_args, threads, subprocess_kwargs): + def run_depletion_step(self, mpi_args=None, threads=None): """Runs a depletion step in Serpent2 as a subprocess. i Parameters @@ -502,7 +502,7 @@ def run_depletion_step(self, mpi_args, threads, subprocess_kwargs): args = args + [self.runtime_inputfile] - super().run_depletion_step(mpi_args, args, subprocess_kwargs) + super().run_depletion_step(mpi_args, args) def switch_to_next_geometry(self): """Inserts line with path to next Serpent geometry file at the From e6f00540a56055d534978b3b54db2c6432444373 Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 20 Apr 2023 11:25:56 -0500 Subject: [PATCH 06/62] update release notes --- doc/releasenotes/v0.5.0.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/doc/releasenotes/v0.5.0.rst b/doc/releasenotes/v0.5.0.rst index fa0dd3319..d57b5517b 100644 --- a/doc/releasenotes/v0.5.0.rst +++ b/doc/releasenotes/v0.5.0.rst @@ -15,6 +15,8 @@ Release notes for v0.5.0 .. _openmc: https://github.com/openmc-dev/openmc +.. _serpentTools: https://github.com/CORE-GATECH-GROUP/serpent-tools +.. _pytables: https://github.com/PyTables/PyTables .. _@yardasol: https://github.com/yardasol @@ -39,15 +41,15 @@ Dependency Changes Describe any new/removed/modified package dependencies -- ``SaltProc`` now optionally requires the following package: +- ``SaltProc`` now requires the following package: - (new) → `openmc`_ + - (new) → `serpentTools`_ + - (formality) → `pytables`_ -- ``pyne>=0.5.11`` → ``pyne>=0.5.11=nomoab_noopenmc*`` +- ``pyne>=0.5.11`` → (removed) -- ``pydotplus`` → (removed) - -- (new) → ``pydot`` +- ``pydotplus`` → ``pydot`` From f399936520ba66c5ca5b25b380e520ddae1073f1 Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 20 Apr 2023 11:34:21 -0500 Subject: [PATCH 07/62] remove source install of openmc from workflows --- .github/workflows/cache-dependencies.yml | 45 -------------------- .github/workflows/test-saltproc.yml | 34 +-------------- tools/ci/build-openmc.sh | 54 ------------------------ tools/ci/restore-openmc.sh | 30 ------------- 4 files changed, 1 insertion(+), 162 deletions(-) delete mode 100755 tools/ci/build-openmc.sh delete mode 100755 tools/ci/restore-openmc.sh diff --git a/.github/workflows/cache-dependencies.yml b/.github/workflows/cache-dependencies.yml index 22f080fc6..f784a8506 100644 --- a/.github/workflows/cache-dependencies.yml +++ b/.github/workflows/cache-dependencies.yml @@ -17,15 +17,6 @@ jobs: run: shell: bash -l {0} - env: - MPI: no - OMP: no - PHDF5: no - DAGMC: no - EVENT: no - VECTFIT: no - LIBMESH: no - steps: - uses: actions/checkout@v3 @@ -51,7 +42,6 @@ jobs: with: path: | /usr/share/miniconda3/envs/saltproc-env - ~/openmc_src ~/endfb71_hdf5 ~/.cache/pip key: depcache-${{ hashFiles('environment.yml') }}-${{ env.DATE }}-${{ env.CACHE_NUMBER }} @@ -65,27 +55,6 @@ jobs: if: steps.dependencies-cache.outputs.cache-hit != 'true' run: $GITHUB_WORKSPACE/scripts/ci/openmc-xs.bash - - name: OpenMC dependencies - run: | - sudo apt -y update - sudo apt install -y libhdf5-dev - - - name: Download OpenMC - if: steps.dependencies-cache.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: openmc-dev/openmc - path: openmc - submodules: recursive - - - name: Build OpenMC from source if no cache if found - if: steps.dependencies-cache.outputs.cache-hit != 'true' - run: $GITHUB_WORKSPACE/tools/ci/build-openmc.sh - - - name: Restore OpenMC source build from cache - if: steps.dependencies-cache.outputs.cache-hit == 'true' - run: $GITHUB_WORKSPACE/tools/ci/restore-openmc.sh - - name: Install SaltProc run: pip install . @@ -130,19 +99,5 @@ jobs: run: mamba env update -n saltproc-doc-env -f doc/doc-environment.yml if: steps.dependencies-cache.outputs.cache-hit != 'true' - - name: Download OpenMC - if: steps.dependencies-cache.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: openmc-dev/openmc - path: openmc - - - name: Build OpenMC API - if: steps.dependencies-cache.outputs.cache-hit != 'true' - run: | - cd openmc - pip install . - cd ../ - - name: Check packages run: conda list diff --git a/.github/workflows/test-saltproc.yml b/.github/workflows/test-saltproc.yml index a46f9f5d0..e45d4af29 100644 --- a/.github/workflows/test-saltproc.yml +++ b/.github/workflows/test-saltproc.yml @@ -14,7 +14,7 @@ on: workflow_dispatch: env: - CACHE_NUMBER: 6 #change to manually reset cache + CACHE_NUMBER: 0 #change to manually reset cache jobs: test-saltproc: @@ -23,15 +23,6 @@ jobs: run: shell: bash -l {0} - env: - MPI: no - OMP: no - PHDF5: no - DAGMC: no - EVENT: no - VECTFIT: no - LIBMESH: no - steps: - uses: actions/checkout@v3 @@ -56,8 +47,6 @@ jobs: with: path: | /usr/share/miniconda3/envs/saltproc-env - ~/openmc_src - ~/mcpl_src ~/endfb71_hdf5 ~/.cache/pip key: depcache-${{ hashFiles('environment.yml') }}-${{ env.DATE }}-${{ env.CACHE_NUMBER }} @@ -71,27 +60,6 @@ jobs: if: steps.dependencies-cache.outputs.cache-hit != 'true' run: $GITHUB_WORKSPACE/scripts/ci/openmc-xs.bash - - name: OpenMC dependencies - run: | - sudo apt -y update - sudo apt install -y libhdf5-dev - - - name: Download OpenMC - if: steps.dependencies-cache.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: openmc-dev/openmc - path: openmc - submodules: recursive - - - name: Build OpenMC from source if no cache is found - if: steps.dependencies-cache.outputs.cache-hit != 'true' - run: $GITHUB_WORKSPACE/tools/ci/build-openmc.sh - - - name: Restore OpenMC source build from cache - if: steps.dependencies-cache.outputs.cache-hit == 'true' - run: $GITHUB_WORKSPACE/tools/ci/restore-openmc.sh - - name: Install SaltProc run: pip install . diff --git a/tools/ci/build-openmc.sh b/tools/ci/build-openmc.sh deleted file mode 100755 index c042e2594..000000000 --- a/tools/ci/build-openmc.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash -set -ex - -# Build openmc -cd openmc -./tools/ci/gha-install-mcpl.sh -python tools/ci/gha-install.py - -# Create the caching folder -DIRS=(openmc_src mcpl_src) -for DIR in ${DIRS[@]}; do - mkdir $DIR - mkdir $DIR/bin - mkdir $DIR/lib - mkdir $DIR/share - mkdir $DIR/include -done - -# Copy libraries to caching folder -cp /usr/local/bin/openmc openmc_src/bin/. -cp /usr/local/lib/libopenmc.so openmc_src/lib/. -cp -r /usr/local/lib/cmake openmc_src/lib/. -cp /usr/local/lib/libpugixml.a openmc_src/lib/. -cp -r /usr/local/lib/pkgconfig openmc_src/lib/. -#cp -r /usr/local/share/openmc openmc_src/share/. -#cp -r /usr/local/share/man openmc_src/share/. -cp -r /usr/local/include/openmc openmc_src/include/. -cp /usr/local/include/pugiconfig.hpp openmc_src/include/. -cp /usr/local/include/pugixml.hpp openmc_src/include/. -INCLUDES=(fmt xtl xtensor gsl gsl-lite openmc) -for I in ${INCLUDES[@]}; do - cp -r /usr/local/include/$I openmc_src/include/. -done - -# MCPL stuff -cp /usr/local/lib/libmcpl.so mcpl_src/lib/. -cp /usr/local/include/mcpl.h mcpl_src/include/. -cp /usr/local/lib/libsswmcpl.so mcpl_src/lib/. -cp /usr/local/lib/libphitsmcpl.so mcpl_src/lib/. -cp -r /usr/local/share/MCPL mcpl_src/share/. - -MCPL_BINARIES=(pymcpltool mcpl-config mcpl2ssw ssw2mcpl mcpl2phits phits2mcpl mcpltool) -for BINARY in ${MCPL_BINARIES[@]}; do - cp /usr/local/bin/$BINARY mcpl_src/bin/. -done - - -# Move the caching folders to $HOME -mv openmc_src $HOME/openmc_src -mv mcpl_src $HOME/mcpl_src - -# Install the OpenMC python API -pip install . -cd ../ diff --git a/tools/ci/restore-openmc.sh b/tools/ci/restore-openmc.sh deleted file mode 100755 index 35fb60ab1..000000000 --- a/tools/ci/restore-openmc.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -set -ex - -# Move cached OpenMC libaries to PATH -sudo mv $HOME/openmc_src/bin/openmc /usr/local/bin/openmc -OPENMC_LIBS=(libopenmc.so cmake libpugixml.a pkgconfig) -for LIB in ${OPENMC_LIBS[@]}; do - sudo mv $HOME/openmc_src/lib/$LIB /usr/local/lib/. -done - -sudo mv $HOME/openmc_src/lib/ /usr/local/lib/ -#sudo mv $HOME/openmc_src/share/openmc /usr/local/share/openmc -#sudo mv $HOME/openmc_src/share/man /usr/local/share/man -INCLUDES=(fmt xtl xtensor gsl gsl-lite openmc pugixml.hpp pugiconfig.hpp) -for I in ${INCLUDES[@]}; do - sudo mv $HOME/openmc_src/include/$I /usr/local/include/$I -done - -# Move MCPL stuff -MCPL_BINARIES=(pymcpltool mcpl-config mcpltool mcpl2ssw ssw2mcpl mcpl2phits phits2mcpl) -for BINARY in ${MCPL_BINARIES[@]}; do - sudo mv $HOME/mcpl_src/bin/$BINARY /usr/local/bin/. -done - -MCPL_LIBS=(libsswmcpl.so libphitsmcpl.so libmcpl.so) -for LIB in ${MCPL_LIBS[@]}; do - sudo mv $HOME/mcpl_src/lib/$LIB /usr/local/lib/. -done -sudo mv $HOME/mcpl_src/include/mcpl.h /usr/local/include/. -sudo mv $HOME/mcpl_src/share/MCPL /usr/local/share/. From e000aa9ef7c204c09bfe36fcb2615589d94a1181 Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 20 Apr 2023 12:11:13 -0500 Subject: [PATCH 08/62] fix documentation building workflows; make dependencies consistent --- .github/workflows/cache-dependencies.yml | 3 +++ .github/workflows/deploy-docs.yml | 5 ++++- doc/doc-environment.yml | 14 +++++++------- environment.yml | 2 +- saltproc/version.py | 6 +++--- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/.github/workflows/cache-dependencies.yml b/.github/workflows/cache-dependencies.yml index f784a8506..9752a6165 100644 --- a/.github/workflows/cache-dependencies.yml +++ b/.github/workflows/cache-dependencies.yml @@ -99,5 +99,8 @@ jobs: run: mamba env update -n saltproc-doc-env -f doc/doc-environment.yml if: steps.dependencies-cache.outputs.cache-hit != 'true' + - name: Install SaltProc + run: pip install . + - name: Check packages run: conda list diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 725bd9b25..e37eb51e6 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -23,7 +23,7 @@ jobs: shell: bash -l {0} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 @@ -56,6 +56,9 @@ jobs: run: mamba env update -n saltproc-doc-env -f doc/doc-environment.yml if: steps.dependencies-cache.outputs.cache-hit != 'true' + - name: Install SaltProc + run: pip install . + - name: Check packages run: conda list diff --git a/doc/doc-environment.yml b/doc/doc-environment.yml index ff32faf6d..7a76db55e 100644 --- a/doc/doc-environment.yml +++ b/doc/doc-environment.yml @@ -3,16 +3,16 @@ channels: - conda-forge - defaults dependencies: - - pyne>=0.5.11=nomoab_noopenmc* + - numpy - openmc - - numpy>=1.14.0 - pytables - networkx - - pydotplus + - pydot + - jsonschema - sphinx - sphinx_rtd_theme - - jsonschema - pip: - - sphinx-multiversion - - sphinxcontrib-apidoc - - sphinx-jsonschema + - serpentTools + - sphinx-multiversion + - sphinxcontrib-apidoc + - sphinx-jsonschema diff --git a/environment.yml b/environment.yml index 360cf1922..8d24963ff 100644 --- a/environment.yml +++ b/environment.yml @@ -11,5 +11,5 @@ dependencies: - pytest - jsonschema - pip: - - argparse==1.4.0 - serpentTools + - argparse==1.4.0 diff --git a/saltproc/version.py b/saltproc/version.py index dc17a40f3..f0e9b63f7 100644 --- a/saltproc/version.py +++ b/saltproc/version.py @@ -89,11 +89,11 @@ './input_schema.json']} PACKAGES = ["saltproc"] REQUIRES = ["numpy", - "networkx", "openmc", "tables", + "networkx", "pydot", "pytest", - "argparse", "jsonschema", - "serpentTools"] + "serpentTools", + "argparse"] From 16a3d1bc7301ec23d671e402687f888a1f379e22 Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 20 Apr 2023 12:12:03 -0500 Subject: [PATCH 09/62] gnds_name -> gnd_name --- saltproc/serpent_depcode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/saltproc/serpent_depcode.py b/saltproc/serpent_depcode.py index 53a7386bb..1915ec295 100644 --- a/saltproc/serpent_depcode.py +++ b/saltproc/serpent_depcode.py @@ -203,7 +203,7 @@ def nuclide_code_to_name(self, nuc_code): else: Z, a, m = self._decay_code_to_zam(nuc_code) - nucname = openmc.data.gnds_name(Z, a, m=m) + nucname = openmc.data.gnd_name(Z, a, m=m) if m != 0: nucname = nucname[:-3] + f'_m{m}' return nucname From 0033773f214ef8deba2ad2f1e8288565dd373bb9 Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 20 Apr 2023 13:11:43 -0500 Subject: [PATCH 10/62] Revert "gnds_name -> gnd_name" This reverts commit 16a3d1bc7301ec23d671e402687f888a1f379e22. --- saltproc/serpent_depcode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/saltproc/serpent_depcode.py b/saltproc/serpent_depcode.py index 1915ec295..53a7386bb 100644 --- a/saltproc/serpent_depcode.py +++ b/saltproc/serpent_depcode.py @@ -203,7 +203,7 @@ def nuclide_code_to_name(self, nuc_code): else: Z, a, m = self._decay_code_to_zam(nuc_code) - nucname = openmc.data.gnd_name(Z, a, m=m) + nucname = openmc.data.gnds_name(Z, a, m=m) if m != 0: nucname = nucname[:-3] + f'_m{m}' return nucname From c229155caac4e72a39a3e63b5e505d8b0ea64de5 Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 20 Apr 2023 13:18:22 -0500 Subject: [PATCH 11/62] remove cruft comments, print statements; make material names more flexible --- saltproc/app.py | 64 +++++++++++---------------------------------- saltproc/process.py | 40 ---------------------------- 2 files changed, 15 insertions(+), 89 deletions(-) diff --git a/saltproc/app.py b/saltproc/app.py index 9de9fcae3..70138be62 100644 --- a/saltproc/app.py +++ b/saltproc/app.py @@ -67,35 +67,29 @@ def run(): simulation.store_run_step_info() # Reprocessing here - print("\nMass and volume of fuel before reproc: %f g, %f cm3" % - (mats['fuel'].mass, - mats['fuel'].volume)) - # print("Mass and volume of ctrlPois before reproc %f g; %f cm3" % - # (mats['ctrlPois'].mass, - # mats['ctrlPois'].vol)) + for key in mats.keys(): + print('\nMass and volume of ' + f'{key} before reproc: {mats[key].mass} g, ', + f'{mats[key].volume} cm3') waste_streams, extracted_mass = reprocess_materials(mats, process_file, dot_file) - print("\nMass and volume of fuel after reproc: %f g, %f cm3" % - (mats['fuel'].mass, - mats['fuel'].volume)) - # print("Mass and volume of ctrlPois after reproc %f g; %f cm3" % - # (mats['ctrlPois'].mass, - # mats['ctrlPois'].vol)) - #breakpoint() + for key in mats.keys(): + print('\nMass and volume of ' + f'{key} after reproc: {mats[key].mass} g, ', + f'{mats[key].volume} cm3') + waste_and_feed_streams = refill_materials(mats, extracted_mass, waste_streams, process_file) - print("\nMass and volume of fuel after REFILL: %f g, %f cm3" % - (mats['fuel'].mass, - mats['fuel'].volume)) - # print("Mass and volume of ctrlPois after REFILL %f g; %f cm3" % - # (mats['ctrlPois'].mass, - # mats['ctrlPois'].vol)) + for key in mats.keys(): + print('\nMass and volume of ' + f'{key} after refill: {mats[key].mass} g, ', + f'{mats[key].volume} cm3') + print("Removed mass [g]:", extracted_mass) # Store in DB after reprocessing and refill (right before next depl) - #breakpoint() simulation.store_after_repr(mats, waste_and_feed_streams, step_idx) depcode.update_depletable_materials(mats, simulation.burn_time) @@ -110,11 +104,6 @@ def run(): print("\nTime at the end of current depletion step: %fd" % simulation.burn_time) print("Simulation succeeded.\n") - '''print("Reactor object data.\n", - msr.mass_flowrate, - msr.power_levels, - msr.depletion_timesteps)''' - def parse_arguments(): """Parses arguments from command line. @@ -428,7 +417,7 @@ def reprocess_materials(mats, process_file, dot_file): print(f"Mass of material '{mat_name}' before reprocessing: " f"{inmass[mat_name]} g") - if mat_name == 'fuel' and material_for_extraction == 'fuel': + if mat_name == material_for_extraction: for i, path in enumerate(extraction_process_paths): thru_flows[mat_name].append(initial_material) @@ -436,7 +425,6 @@ def reprocess_materials(mats, process_file, dot_file): # Calculate fraction of the flow going to the process proc divisor = float(processes[proc].mass_flowrate / processes['core_outlet'].mass_flowrate) - print(f'Process: {proc}, divisor={divisor}') # Calculate waste stream and thru flow on proccess proc thru_flow, waste_stream = \ @@ -455,24 +443,6 @@ def reprocess_materials(mats, process_file, dot_file): print(f'{i + 1} Materal mass on path {i}: ' f'{thru_flows[mat_name][i].mass}') - # print('\nMass balance: %f g = %f + %f + %f + %f + %f + %f' % - # (inmass[mat_name], - # mats[mat_name].mass, - # waste_streams[mat_name]['waste_sparger'].mass, - # waste_streams[mat_name]['waste_entrainment_separator'].mass, - # waste_streams[mat_name]['waste_nickel_filter'].mass, - # waste_streams[mat_name]['waste_bypass'].mass, - # waste_streams[mat_name]['waste_liquid_metal'].mass)) - - # Bootstrap for many materials - #if mat_name == 'ctrlPois': - # thru_flow, waste_stream = \ - # processes['removal_tb_dy'].process_material(mats[mat_name]) - - # waste_streams[mat_name]['removal_tb_dy'] = waste_stream - # mats[mat_name] = thru_flow - - #assert 1 == 2 extracted_mass[mat_name] = \ inmass[mat_name] - float(mats[mat_name].mass) @@ -515,7 +485,6 @@ def get_extraction_processes(process_file): for mat_name, procs in j.items(): extraction_processes[mat_name] = OrderedDict() for proc_name, proc_data in procs['extraction_processes'].items(): - print("Processs object data: ", proc_data) st = proc_data['efficiency'] if proc_name == 'sparger' and st == "self": extraction_processes[mat_name][proc_name] = \ @@ -593,7 +562,6 @@ def refill_materials(mats, extracted_mass, waste_streams, process_file): representing those material feed streams. """ - #print('Fuel before refilling: ^^^', mats['fuel'].print_attr()) feeds = get_feeds(process_file) refill_mats = OrderedDict() # Get feed group for each material @@ -606,8 +574,6 @@ def refill_materials(mats, extracted_mass, waste_streams, process_file): mats[mat] += refill_mats[mat] print('Refilled fresh material: %s %f g' % (mat, refill_mats[mat].mass)) - #print('Refill Material: ^^^', refill_mats[mat].print_attr()) - #print('Fuel after arefill: ^^^', mats[mat].print_attr()) return waste_streams diff --git a/saltproc/process.py b/saltproc/process.py index 8d29b2c9b..3530d0e4a 100644 --- a/saltproc/process.py +++ b/saltproc/process.py @@ -104,7 +104,6 @@ def process_material(self, inflow): total_waste_mass = 0.0 total_thru_mass = 0.0 - #print("Xe concentration in inflow before % f g" % (inflow.mass * inflow.comp['Xe136'])) if bool(self.efficiency): process_elements = list(self.efficiency.keys()) @@ -119,7 +118,6 @@ def process_material(self, inflow): elem = re.match(r"([A-Z]+)([0-9]+)", nuc, re.I).groups()[0] nuc_efficiency[nuc] = efficiency[elem] - #thru_mass = np.array([inflow.get_mass(nuc) * (1.0 - nuc_efficiency[nuc]) for nuc in process_nucs]) thru_mass = np.array([inflow.get_mass(nuc) * (1.0 - nuc_efficiency[nuc]) for nuc in process_nucs]) waste_mass = np.array([inflow.get_mass(nuc) * nuc_efficiency[nuc] for nuc in process_nucs]) @@ -133,45 +131,10 @@ def process_material(self, inflow): thru_mass_1 = dict(zip(thru_nucs, thru_mass_1 / total_thru_mass)) thru_mass = dict(zip(process_nucs, thru_mass / total_thru_mass)) thru_mass.update(thru_mass_1) - - - #for nuc in inflow.comp.keys(): - # match = re.match(r"([A-Z]+)([0-9]+)", nuc, re.I) - # elem_name = match.groups()[0] - # if elem_name in self.efficiency: - # # Evaluate removal efficiency for elem_name (float) - # self.efficiency[elem_name] = \ - # self.calculate_removal_efficiency(elem_name) - # thru_mass[nuc] = \ - # inflow.mass * inflow.comp[nuc] * \ - # (1.0 - self.efficiency[elem_name]) - # waste_mass[nuc] = \ - # inflow.mass * inflow.comp[nuc] * self.efficiency[elem_name] - # #inflow.get_mass(nuc) * self.efficiency[elem_name] - # total_waste_mass += waste_mass[nuc] - # # Assume zero removal - # else: - # thru_mass[nuc] = inflow.mass * inflow.comp[nuc] - # total_thru_mass += thru_mass[nuc] - - # convert to mass percents - #if total_waste_mass > 0: - # for nuc, mass in waste_mass.items(): - # waste_mass[nuc] = mass / total_waste_mass - ## For some reason this is more than waht we need it to be!! - #if total_thru_mass > 0: - # for nuc, mass in thru_mass.items(): - # thru_mass[nuc] = mass / total_thru_mass - else: total_thru_mass = inflow.mass thru_mass = inflow.comp.copy() - # This volume value preserves the mass values - #waste_mass_arr = np.array(list(waste_mass.values())) - #nonzeros = waste_mass_arr[waste_mass_arr != 0.0] - #nonzeros = nonzeros[nonzeros != 0] - #waste_volume = np.min(nonzeros) waste_stream = Materialflow(comp=waste_mass) if bool(waste_mass) and np.max(list(waste_mass.values())) > 0.0: waste_stream.volume = total_waste_mass / waste_stream.mass @@ -191,9 +154,6 @@ def process_material(self, inflow): #thru_flow.mass = float(inflow.mass - waste_stream.mass) #thru_flow.norm_comp() - #print("Xe concentration in thruflow: %f g" % (thru_flow.comp['Xe136'] * thru_flow.mass)) - #print("Waste mass: %f g\n" % waste_stream.mass) - del thru_mass, waste_mass return thru_flow, waste_stream From 8e49dc7f1dba567ee64f644c6a64b957923c591e Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 20 Apr 2023 15:28:17 -0500 Subject: [PATCH 12/62] update openmc reprocessing integration test --- .../materials.xml | 50 ++++---- .../msbr_reference_results.h5 | Bin 162451 -> 0 bytes .../msbr_settings.xml | 16 --- .../pincell_geometry.xml | 13 +++ .../{msbr_input.json => pincell_input.json} | 8 +- .../pincell_reference_results.h5 | Bin 0 -> 121707 bytes .../pincell_settings.xml | 8 ++ .../run_constant_reprocessing_openmc/test.py | 107 +++++++++++------- .../run_no_reprocessing_openmc/materials.xml | 34 ------ .../{settings.xml => pincell_settings.xml} | 0 10 files changed, 116 insertions(+), 120 deletions(-) delete mode 100644 tests/integration_tests/run_constant_reprocessing_openmc/msbr_reference_results.h5 delete mode 100644 tests/integration_tests/run_constant_reprocessing_openmc/msbr_settings.xml create mode 100644 tests/integration_tests/run_constant_reprocessing_openmc/pincell_geometry.xml rename tests/integration_tests/run_constant_reprocessing_openmc/{msbr_input.json => pincell_input.json} (76%) create mode 100644 tests/integration_tests/run_constant_reprocessing_openmc/pincell_reference_results.h5 create mode 100644 tests/integration_tests/run_constant_reprocessing_openmc/pincell_settings.xml delete mode 100644 tests/integration_tests/run_no_reprocessing_openmc/materials.xml rename tests/integration_tests/run_no_reprocessing_openmc/{settings.xml => pincell_settings.xml} (100%) diff --git a/tests/integration_tests/run_constant_reprocessing_openmc/materials.xml b/tests/integration_tests/run_constant_reprocessing_openmc/materials.xml index 9d2c45b52..3fbffeae6 100644 --- a/tests/integration_tests/run_constant_reprocessing_openmc/materials.xml +++ b/tests/integration_tests/run_constant_reprocessing_openmc/materials.xml @@ -1,34 +1,28 @@ - - - - - - - + + + + + + + + - - - - + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + diff --git a/tests/integration_tests/run_constant_reprocessing_openmc/msbr_reference_results.h5 b/tests/integration_tests/run_constant_reprocessing_openmc/msbr_reference_results.h5 deleted file mode 100644 index 9fefb1921a94dab5025d34cd21e8f08be1ae5395..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 162451 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 diff --git a/tests/integration_tests/run_constant_reprocessing_openmc/msbr_settings.xml b/tests/integration_tests/run_constant_reprocessing_openmc/msbr_settings.xml deleted file mode 100644 index 9c45e1829..000000000 --- a/tests/integration_tests/run_constant_reprocessing_openmc/msbr_settings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - eigenvalue - 6000 - 200 - 80 - 1 - - 20 20 20 - -343.408 -343.408 -81.28 - 343.408 343.408 530.86 - - 900.0 - interpolation - 800.0 1000.0 - diff --git a/tests/integration_tests/run_constant_reprocessing_openmc/pincell_geometry.xml b/tests/integration_tests/run_constant_reprocessing_openmc/pincell_geometry.xml new file mode 100644 index 000000000..f9460746a --- /dev/null +++ b/tests/integration_tests/run_constant_reprocessing_openmc/pincell_geometry.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/tests/integration_tests/run_constant_reprocessing_openmc/msbr_input.json b/tests/integration_tests/run_constant_reprocessing_openmc/pincell_input.json similarity index 76% rename from tests/integration_tests/run_constant_reprocessing_openmc/msbr_input.json rename to tests/integration_tests/run_constant_reprocessing_openmc/pincell_input.json index fe8fc9a0d..6bc6dbd98 100644 --- a/tests/integration_tests/run_constant_reprocessing_openmc/msbr_input.json +++ b/tests/integration_tests/run_constant_reprocessing_openmc/pincell_input.json @@ -6,8 +6,8 @@ "codename": "openmc", "template_input_file_path": { "materials": "materials.xml", - "settings": "msbr_settings.xml"}, - "geo_file_paths": ["../../openmc_data/msbr_geometry_base.xml"], + "settings": "pincell_settings.xml"}, + "geo_file_paths": ["pincell_geometry.xml"], "chain_file_path": "../../openmc_data/chain_endfb71_pwr.xml", "depletion_settings": { "operator_kwargs": { @@ -16,12 +16,12 @@ } }, "simulation": { - "sim_name": "msbr_constant_reprocessing" + "sim_name": "pincell_constant_reprocessing" }, "reactor": { "volume": 1.0, "mass_flowrate": 9920000, - "power_levels": [ 2250000000 ], + "power_levels": [ 174 ], "depletion_timesteps": [ 3 ], "timestep_units": "d" } diff --git a/tests/integration_tests/run_constant_reprocessing_openmc/pincell_reference_results.h5 b/tests/integration_tests/run_constant_reprocessing_openmc/pincell_reference_results.h5 new file mode 100644 index 0000000000000000000000000000000000000000..4181f381667516a91a6a8b1692c9fbf054d2082f GIT binary patch literal 121707 zcmeEv2|!KF`~SK3w(p5lmXiu8+E?wRw3iAk)NQ#fTD2*}&6*-)CrPqpS6LF0ofNVY zHx-IRrIMxp%voBl^7_8-`}@D!9hx&U=Xqv%W;yfBXYR}j>q%C^0x|*!G<md?!VOixKh5((nK&g3-;z(h>obWc=il zU_(yv;Vv~Yfb;xMNx<6D%o!HgohY?6@w`T~Gs266M1;hK_=foeFrxe;0~kIrA>knr zfsshKZ!9AkyoezPL3mu4Z)`|pgin-jv~M^AyoT?{c1-pHaiYDlw`(Cp7K@33@F1|) zxY@Ybg9eO907e)G$QG6}Aw;nk9Uo$0Z|3Ss&~bw&ncidU@jJ@kAaUOr@+rHiYL zlOq-{>@p<1x{4a`L3;d20klHk&&tN$4X_|$pud3sz?fn-$;Z!ycRV3Pj|i6nbbN@j zhntzXy``&1wE`6MV{8UZS`#FOU)_I5291aQ`(taohuJ8ghyT^B^gT zAdi3}f)N)R4TT>WMbtw#=}#TK%jN4I8xqg(@lW&*W5Bv&OY(=v^yS8L{{u^R zKyO~MZAE})0}05nt(%z5Ap!h@!5_&N51JZic*uA*I(9F~7aI~A1`{%6Ct&kKdQb32 zrV|no6&LFh7!t<7bGns{p54pNKPNIeG$bO(CmcqyGbMI3qkVI?*RG zDi#bDbMZkT91I?0{!aZ5aRJ$fF|c6;M8=4TWklhzl>9~<;<6^){Z&g4(dq)-l##&j zkL!*LL9YFdIEb>v#rOtc<+=Sk;(#UK2DyW*R2n`62_n{*gMy86uz%w{C=it1KbR4% zsezZ9k_7p95Wld<7=Or5{K2@Qz9R@fctSTH(TiwQDuPc&kW>&1hYHLLBBTTT){D#n zTpgVzQ9!C>pVuSCA%gsehb$378-Y8>c$Epi9g2sm5p*w>5RQNO1J1iBpa#hK7Wot; z>Xp6t9Ws4GU?oA*T~WA~V{;_HkpM>m90_nFz>&beNCFgMo<^bIGbnN%Ma~;~^jD}C z53KKE+9r@o5B<;eT@4joOo~E?Gxo&wZoWQxH`J%d{Mg{@0J7claap(=Alsw%%l1+G zd+E_Um>%uu;xyeA#MfKLfC-cFlTRT+E2AL7Sb42%EbS-xsQEaWIaoq^xE=siVv>F! zy|+gn?;VeNpLm3O#nV@Ng>oeI`QH2*efWXu-JK71{kMO9%|84>z4%ETlhlFx=hy1P z-#dMhpVWnW)-ihLU%L-KcdztGow$Gb>-6E1?8Qf>%dQ*uACGRIc%Yt2)*~4YyN=wy z9Q69c(_4=0x^n;g`hEBXd*y>&XYSz_>D3<9yBj2IkEG58qCwd8<{mlp;qPvUkRPsh zka8GEcOD>~?gq);FMvGz)td(>Pj|zF@rd-w54+Ah0DpJGg#5khgI!`PF^?7{A8ft<~JqUg9uoYgzLpH|LWZh zs=sw8$nazP=r^A3hV=*I>27Gh9*-hXE?#`xvp1XO
Hdw(|~;=-d60VNeoU}C}g z6a0f~9dLcN1r*Zw4Zc23EZZaGViXb?#fS*^M_4qln5CwouBoEQq77mlL{LOEI5M1} z8X4&q=IbA-8WkNmi{T#|qZ;EI77IN7sA?=&2aHh-iHKzcMdPcBct~_ygpYq@giK7V zZ$zw5Gy_sIVq)NuE1sH91WVWhRrQaKjER{L17ZcM#uLIq{GxrMLl`ltjEI0hKV5Y} zpWuK%ZJf%7slXi(qmmFFR!yA=R&`jyh;$bwm|Rga?&{j&s&-FP%#VCHkFdyD+kf(z z3SgT&bT$v1O2Xz1KWosCP{u`KN$?FGjQkcv87hwxl1q{V8|U#KkpMeH31$|U2_@PQ zDTcr}Mi_LHL#j3T;&(nth?0FNyJt#`t75$&%HFDk0|AZ7LeK`}p+_bAxeE9H8?qdz zpXMvzf_p^B@3;D?9sZ^0?(e@->>Rd#s07&iDL$bCQw3uDCX40A2#kzo5Z`4G7!u(V z3GmdISb$K51Dw$}5bPP~dEMQgWyuKGo;YL$fqL8=kj0&D@7;3FE!Z;fvUlyQ35{>8@${g+E%pz*C`Y~O+-u;6Oq5`zA4U+Wg#Ma23rEfO93(&&dMkKvWOk`|i zRER%7roy8lW5B-E$Ou_5<&-59#2)>P7h5W{ba$I%+ZjQ>y#`eO?>Or z&wjFmYZ#CYLfpT#6^blJ&wRD_7M|{%C)idfUXTNFI!VqO`{(Q4af0#nhH%OGWB+{J zNIIr$!L-Qqu)+iDk8jDqS2*BL8=*#E^&3z#1(C+`APWl*40}5u^;ohU(7+EpV4fub zJzSd(_l*Io&A)B>({lqD5kRp>#1+n;MA08_d}LT0{DBjxM-If^A8#xpJc zz)#x-V){w?@YSEKx4<^>p?|&QrY)YA44@xEGR&~+E&uo944yPT&h*`)3EKhLAG_D7 zdKMfp2y&o)-Fr(V)PKo%$o|nkU*B=0_xMBhjsE$%cdB9IPj9`M>=(Vq5o{d5w$gO( zOvCtkZ`EV(6aDjd?@Yt^d*ih1{h@#UzFQ`H^RxGb{>$BW>tye8ll`D)eM7j{7NVYU zx4%9F8zNa>&<#!h@pSKG8gSk2*W&5k(ewx7>E6-w2jl79(ewx7>Dfy6$K>3zweHvB z`QN^KJ?-n)<`Lv~aG-USccbxkGmt%cN8gqK*PEar=O@^rD;~tLITGMVfFl8p1UM4l zNPr^&js*S%5*TRSh#$oBV*%gM`-VZK8Jcdz8TWE*js!Ro;7EWY0gePX68INMfJzb9 zYX$4*a4o$KEFHnM=_>HN0R9wS9|u0{_i-r*p;*4f!c*5! zk&8u`Gi@zJSeSGT9ZI@PO-a`+AJSD8hq+d+MV^rk3(|3!bd+HZ5UYX$;lfa&Rb5G6Y&>Mw$=yPZ^^7xcqn9&u@UFm{W>+;m> z_`@wTT(2M57+H?io^#Y4ug|5m^znhzPX+EBqW)_Y^6qwRy!NuDXv#GEZ0=~^(t{&^ zem1L(H8D~^aElE1qF>+S%ZSg2E7nBN(?rzzuq=>ZI=}~YmUj#JFU(`W}a)} zH&l%Gj?#M=_juEj8ud35UrkEOX-6wwpBy_T+H6u{%9(AEUUyqJfOtM+wF}vJ#d7|lB zpFv|6tX3HBnV6;HC_x`vs^uS3g>G3asV{yb?8Bv16&WG%yfXsRH!Rm1Ll=6od;T`p zl)*1h@$=(iO|Cq75nHeHxKpfxa-yNoVPTUBk@fg46+L(JRff!1=REax`dq*G zoulF-CaYI0b}NfrdT}CJdI7bw8^hFHr}OHZxOm-;VNfFcdOmGFUp6%?OQ0`nQ41gca!qIYcbW_L%W{Zn*Ms-mgrU6N=nWj zJhl-*WVyH;ncD-4hqu?3N0u=jzHB=?9bK7ZkaWf+$=+cTb+~fZp|cmc9v`%hELj$^ zEkGf3ySxCZB_Z^yY2lPP3&^w`=0t%;sjL?-?7ZeZMJ1iHpHV zEne1@c^B2okdbf;xihcfdB-`EYbG_HhA&(0xcFtKYHRfNnYER7(egUc?7e}j_p~a! zeR-wg-mSJ%MY&tXEZyW&RpoPIrRX`-Kg?uf=&}cg_HDl!If_T@{FJAuS_?{?iay?D zI135w9*GKAN+_($(_g_etL}i)_2w}{MXUVw1;3S_mA-KK`ipurw0yLutN!KYu%qcV z4XMVPN2pYlnF-pj8Xq03c>c|+2OX%)bgSJ%7iJ#WS^Z$-s|k(YF3eOJe4aHo``#q6 zw@n5*8mOyfO>As-{ML)MSt+$=b{u**X5GSDteXdH?L!!f$o_n^ezB?C%#_*3Mg~s& zA~?MGxObD~I`4hwXSsj7G1@=V;x#u<>@p>*U$0y4nnDf3XH(THbocBLTez@5(cqic zj(snU&n!0ou;Fzvj`W`48r7WW&L1bCL_<(eIxdSgyYmDlL!XHtSu-RVl3 zkf^5)rz=<7Hpmf6c;$RvDU*NKu7m3usg;XdM9~*J)8<`vtU4NFEw)4~C(iIibhUkP zvEq#^Z}rye>*^ZOz-4x0Vq#YLjch))%&xJfEWC_$!#!`ubE$(&Yqb7e0IJh@dz0St z{Ff1Ch^CX*-3ZS(-Ksr{hD7j3FyyFLO<$rXZz{~VyxY@`<<=54N|810>yzl_xl@LI zEZXcZy1s;e1KQZOIZ$>*yI-N4d4RD1VzuYU)Q>*b z^l}C*nCUu(zv^p3Rof=%388{XirG`{rl1j2NwMr*lWySWW9ij}It=)K8jJl-;=$zE;SH9RYPbbJ0XE1BoVoSzD= zuUYuKZS+}ggJ-^c>wmp&S0B5_zy2}mZ0{WznVgZaVn?Bb$N39ybL)jvU1B#CA?SMF zU4>U3)qjcXEW9z5)h2Y&@i7{Z*Q7l+wy3I0&N3KHD+F(aMyQ&89}FT%&cMkN5-6i| zO6@@`XzZq;Ipd>GKKUkV@y#OTK)D1YHg#FB^U`bn@lLz!QNP9nms1wFH~QqalyZrz zCCNHE0Xu4Wl^h~7U!vS&ZNu{!DF(^8S6%Y7-)kuqnvN?lS$ackYEcy;pL7AO6&XG8 zp1E+J{u%ou?$W-bh|}zMgnE>O7zZ*Yj1g_#u+^3tCTUKFWQ~oG0gao z-hzw#j*nX;CG{7epd|1;R)RvCu+_&zr*0kL-?Bh1_)rU=6GAstdDq9R2t8WaCLJn~ zRXZ-Sz=Sc+I;}-g-wT!`0EIFsp^mmrha@+qZe@)Qjm#+AaIy*yF+jbObL;Q5W657@ zOBUQXYR!Z4j}kC9^LANEMH`^@-lGmi7C!o7dbCm+5MROSV07rwnK`c~M1KoC%H3v= zd{yX|>h?06ONoexeEat8dzBb&YHI6RTLms(rBJAtp`jOr@Hd}6)xCQC`c1=EKn+Y+ z7kp2n(FAGmy*My0YsFXyf{HaYeR%usT_eW-@gp}hJUrk(4-YRSL&e3pfB~WR8sEQf z5^rw7ecas5EiJ9BYj>h~dB=Ep`G64+5QK(@2ORc6p?>e;7pSXy_30DZ*4EbE4pJ{V z$IJWV>9fW!9iKmU0#knb;iJ!=Khsc18gSNJ|e){yO?fDB9j2JVR z6oBr58I%ID)ZWnna?Q=%i3Pz-Qz#-LShAwS-_$oWyoH6~g#kV{oy8V15=o4Xkx1;g4?2(8ei%a-|E=U@qqbTzmf*4E;O(8AC zp@afbWN{-DgI_8i)CDH3xvtt<;e*-$RQTYJTb_YGpz!VJR`{s*B2Q!LMapWR@s&ME z!IN2mP%YoC!CtIbLjx+`am<~%mMTmreZV=C(E5PWlu-MC^Og@ENm~}TA9Dhw?%7Au zWifhDj%RH0OP>iqcz7!RQI^V1}qHa1qI^Uj?L z(s_o^0Re3_p#%aakS#&*b1jexniZx7rbbW~5_(|j+Mn@s>tDa*@I@%f8!^hXu5t2| zTWwgbfTUuNk*>FMNLT4Z(&gYtx{63O9E+rvE||Mw>j-Ua4IN#&kdV5%x-K-J`Zcxa zB8YnS7EyI|4Gm3AP4G%xUrk+CkB&ex9bFi%p{=gZM0mBdH8k|~_0_WxZf$KHV3<)< zK)~c(M<*DBOTbLsN@+fnN(tM^8^fgT8_#K%sA9E?{yqDJ5P4TEKw# zKpL7X@G~+kEj4wz4pWIq;RDIT$aQp?4-oyPK4P0K!mXwTGOq=4qob#$r44?uck3`! z3sIv>@oVd=tASKOc!d%b6ooDgV%5^7BPHfAHElgTefXYfiD;*9WKs}ax^fAH7tzwu z)dQ^AqTD(dd-&HOc&0%i)PMmQ0XfoESC5cJ^&o||j;5v-g6Qf3m$sS)uyyr7K7jPJ z5N-NmUYHc%(8vZFIei$&i5e&%qE45mXlc=95iL5x2Slm?+4NY50!2qJB25H_XlTQ{ zfK2M?`%2LB)6bQEWXf{s>FH_f+_pkA){Nx>r2^$Lrr)9fX_X2~Gn#BEObQ-~##ASBt1g7NThAW{;;E(KLa) zv$wFgkZOue$>hG}PD0X)5g$60H3DI(v%oLS!dc?r1aFqK5sMFD4UJ%_AS}meEGk0r zL0BICeVM01=I~z3Acp>#!v|niCz(|dmZA|$Q4QpSNKgGomOgF0t1A*gDO4I4HxDl# zzkr~Su!yLb_#lbFLnMbvNy`iyK4K&)D>h0_USaf@v5MoAl*dm{QB_la(WPXJPBbty zGBz!O_Wiii@k;)M?Y*Jy1`t88f|o=)Qjb0gS+);E-9NVc`*x zQM03CV&mfHBqXA9=gm)Au#lO&Xz`Mz%a*6CNKIS0Dt+~uwHfQyZ`inL^A>dLw#@BW zJF<7??8@D}XYaoKc?S+2I(+2lvE%s#g(ps)I*k^cDL#Ade948cn_F5xwY7JA=IQ+M_1pI@ zgte{fTVKgUc7d<)Hl**^&=o1txAyw-{4w7?FtlMyYB>h)jCy}Yw}5c?8C?sWao|tk zHSpkH%M=8;hYiaqtKhOJQicboA&4bDTCbrX7cm!D>BHAdfdgMM1rB`06gbG$K&%9- zzF{1FOEYCHqJVvsR)*q4;QNT+i=$wn5MLVw5#dXtz=5xf0tdb@3LN;lC~)A*qQHTF z4_E&5+qM8qAMkX;5PVJa=k$GZ{ipaO$ck}J({=$BBMz@;fIn)5KSG5SQv;q?!JmmW zH1_u9=H`x$PEJ;ijt&kE;3^tdXYl80VPVE?W@cw+XF*2>yShO$ZJGrz4pzW`rz0Jq zT3C3}!J;Y{X3fl8fo*PX2W%G?7p6GX!^49@NS{TgP~2R=h=MpX5iT=eEWr3> zW5YB8vp&R)MM1c2pm7HzbUnnp1fkm7+tbCkK`PG9&h%qcM@L6`5DS@tSTYf23D@Mw zZf=v92*ui(Da8dcW^eC1Uf3EqrbFZ6Vq;^*93%n)0JpO_$c_t0vt$c5^g2(4sU$EH z=@i6_iO{z)Da?E@d$q7&&ZDrePJ|fZ`|5;+MMp=2 z&xS7$kUt0v3DMRDA<+>GU?L+UL+A)KE-r$O@ca70AaIT!gNY!~pm=_MeoO(Xp1wYl zk1HB@BC`>Se;f-zsKLPjOoRrK31ae70|El*Ggwp#7a#!~esl``44prl!W9Dzy&xM* z!)XkVBz+1E(1wEnKRcN&%?;dseu+Rpk&(qJh2H8%Eb3|cVo0*rpG#W@%ypO+VB(_{c^61$`(Z9^U3E=eraMJTGYX~XYp(7raigb$ z%Aq1Wcx~vEpok9rFhxU)&O?_$)R^4NsdO+y)z<3Uk`9S$LYJ;F(l80?cXQrtgCY6$&6K^_q})_dci$j^1E!3<|)Q3w9Wy)EjL9 zc-3bq4E#bN`UT)60_Lg!01=5OnFGK`ZXrrSKLn6P;#Z5^2(Syi5r*Sk0Offhj)PeM z5yB9jaDZZoqcK$&vUUFegrnv_)Cs_GBt!&oDs*>F4?LuI0Ee)8U@EZ$6kv7*S-oI4 z9IGP{xzAdt?c?K*SL|1-rraO2Z@WRokxG5;l?E>tB{Ni{!cyuUo<}$F*6wg;N;u9D z%U4?zSLCjHXy3OZNtB6MD~+Y*)@!GD++nc&2FD8%7y6IuDdwrOm+zkq=GW|OmlCaiY zaqROaa;Rg4mQlp?K(B|!Gw#U^H8iN3%dER|aSS5O{rIhJ_^8`x#Gnk7AlCDdQj2UH zMpnG2_h&rTEO@>~d#rn+!W)&(I;d8iL;Rq`-R@IH4QCaa2}Bnjwg^l&>;i$*+fi@l9fm4e&ex^~99t1nHORlQz0D{hAPh4$UUl^n{lqw6i# zqr2MU&kh$HJZkHytQpc56Y~yk^nKJcckxDt#wrg++{VWO31jAE%dH#pb$#_OcSa0M ztF2twUR!Z*-}V)^+5lQM7=Tw-A)+;8izCY14iGgQ-fO^+DN{KJ-tFBAkU6>_{RRpk zH2<)*<8UC#Y$*oO1r`%9n8T*!D2~Pf%nS#<0BB|L8bhl95C>s76yS1!_h{v#2|Vqs zJb}L1O3s&rkRl2&#gJtt*E;&ZXc*jv<7cRAO{|6`1_Abl#{j@MQ3FFOQ3zK8JdnU8 zwE&_=LV(Ty;S*Ygl2{#qJd%Lp+-w4!L__Z2040Fs?v~@|BY^NQNN!)SNzHIH^DYKO zj#&rs!z2h30{oQ3^Z>AkikAmB4tTqRhY59kEY>BoSz3;-> zJF7=+x4k%6Z^LQS+c(f(@O_z~jr_p^=QU$b6?^F|RdAGONs+JYoUZxU8NCy+kpFyC z#IBT&?s8(8wLX=5ir301Cm&3b^<7Tc`nmue?sCXcVzN=xMe$OVPpVta&k3yExFKDn zl$zgY^X;fy1A1bU(0f(p_C}Z7*>ww&(mj0L?}%!Zr%Yf@YEq2xIxdVpDBobSUqgTN zwbJiibJE{!Oi~aSJpJyp;Uy!-KYZ`sF%tb$oOY+NdAO(S?D^=jD`ihlG_ORx)V-G< zZL@Q7&ha>picoY}C6mVM2ncSwe$X&G`xwPme&z77ca%cMcX4TMH$+*<&l6@&XQ|g7 znmK!qNug&NYv@#G%lJ1VI=U?AC#P*hpL-RX-?xfTbQ6|e+IB*;{wcpq^g&wGxY%VT zSr)YhXVJN*llBy~E_moWBUv(Fy+XiRr|6*Mdm7g(I_KW;t<5h*KdbrBiysvhEmF(Y zHd>i+)!R9+V7K|l_w6*P3uz*U3k2vYc1N76w!JoK_~p)sp`TYxzwdjg$SRbp8}}8! zo9X~TceY2r2=9N>3o*QVqkY&mabj0uZ=m zj+58DKDZ}_kK%wQy2t2AeG-P*_Qo>-BK%?}1}~!!Uj_g!0VL}J2$sZb*8oU1L=h#y zRRSs|5n`G51e}aM&&LsEfTO-ViNnPJbHy>#O?M-9p!WhW?06Oz1bl5Et_uKf5`+av zFxpVu1Hj&!jDy5IKyZaF3Q+Mq3wr_EI2ul3-qF>leX(Nk82N*1%kN&3|I&8Wb7rB^ zsx!yS<-Aq-gbXaic+u>fnl%|?oNe=v0o5r(b!_irf_1+ts*W% zuZu~+Q);pkH{D!^Hik__KI$HK&T~w&rdK4yr@QKA4|BiaWS4g(tnh9^6dG_u_t~)O zqj6r2`mSmt&G*edcHJ)Ey!rBl?X+~4-7l?Bhh6K&s@8B7S6C{a8_NH7b4t@G{=IW^ z_@y%(R%NtCMxbwx23H?&)uyTVzf&#}R=RoU;^}8XjZb49x9l-g)5{A%1#MRC5vM3R zES*kWzL=Kzp7*ZQk}B;ESHsjTriBT`=IAk{EP)dz)W<3tpEV7ulo+~v;pTH5H&W*& zJX2DZY4g}8P&RezyQs7CMBbSEN@q-h(^L$umQPxL;cd9xW4>K=p8+224B+8Ph#7w$ zyaL@(2rz3LKo7;R-%$r4JpRxgVBZOpgaj0T)OThK&B3AGQx+HqF5y7{&5@nsP#o_D zs5A~O16VlpD24|Es2c*`C_ujDs)T@rBi1bo2z;A=J^C1e_7Jt7tDUEff%n}&H3n$o z2sP@RTW^qzf$Y5jXlx?@wjTf>`9%mo+zI4A4PfRZ$PQre1(InfiG~x{J_+e>I7#6D zC?f^m0sw&T3$-}D4?uDZ^d8~=Uh6!X`4R*B*F1m-y)Ojf!43ryH3!%^x@dO~Vs7t^ zqxwC_y}dUIwje}i^xBDl??)gvDF}@iqH5}5>QXuV){Y?guJr*1u2&xO<$gq}skyu> zz6}N&Ae0J{b5WsLST&)CN9kU0cxdn6I7pt7pYYv!<(<-@$7d!#L8W(|ZrD_G+U{YB zcYAQ)o^1(FY=u^g6A=`0+2`V>Ln%fl>MxkRIcN8+wW3N<*E-xReBImRui4G_UY+no z$dtBj61w8CiCkn*T$-LJP#Epnq@@*e*1#y+&ZBw_B+!iz4Jhn+%o7i7&h&KYaNZKa$p;+j(W zCRTVmx_p=Fr~2D`OzZDlDgv@b*R#heHW{TgZ#p?Na9L55*D7={)&KCTFW>hj4au_S z5!j-@>p0z9d8Bp5=e_)54=$|HK<$dhtbX~*%Ol@@UB><49^Vaxd`~J|b$(S&2U{{$ zKgdTrlB7?_E?lYT8z#Joo2?d_=6^vmng>vbF}TtpnQ&@LdjXFtq;dTey*-5pGjx z`q0#bV%rG-K93>v%`Mn|1+Xyy-x>h62MB+{b|!$00N7>#CW2xhJ^=EG4GLf2E(KzL z0oZ8p^(zXuA%Gnf-@3O|eDCVBuK=NxaDmKIN)QT#nk@t^ghHh-1^B7ps$K9OSYY`^ z0BlOY_9cMb31A_L7jCZrn-sXg`rROG>jl350&G5jh7XYN^YH^C0E}QZ!UZ-(2#J80 zMF6&s2zKvI09z+mC_)hv2MprkCzA8_dqM$TJ9QQa@ZRHU*rn7j&I6HMeG%h{&+U8Hrw~n0OdHd{{`~I=Zp4PlsAzJfs@#|M` zn+WQ+s^gvp@5{Hf@5?%^pHu7Wp5I$ju;PR{>sZvz)VL$DXi(bMk~@ae{Q?4HwI_Z5 zoXXmeA6sghv$I~V&yIdmSM}&3x~Kip-cK~-((xsEM>nr4uv^`n z9BOuG?6`YMQ(Q-mkK!K5ORZ$xE;)XO+bKS06O(s(0WL^B$$5O-g8cj!a;uTus36$V zAw&@{6M8jR(2#yDbc*DbCb8K!jtSA^p84E#IgLu3{cw}!{c+7pdGVS{603yiYs3XR zbk}b`!q_7$k}Re)OcI5ARk&Nl#73ok5ECCWMqEU^5$vuJYkB%B?c4{fw93Qn8`(6f zfr&{rKP#OAw|X2#xbgiLEVW`GLnE+v!x&P5tsB*9xx);A-v~2?Mn=ZQhQi-u1kn?~NnmtFB`*BH2b}tb zhDJn zhq-|BS450~%mxh_ATnd7o;XA*F#{8W#(?PwHn(K+(O~4+461>#5mR<3o_##?Sh7&k zfRpJu1c)AnLtgBG)ehKEgP@>1nAnVfgkWvqM1T@j9PkT)TEr8@%HcsVHZGYd1fw^G zG5}OYOtd=Tn9~MH$ey84GLs;8*_CSThOauCCQ;PAgOF0BI2cQpy^6eGx5^1*m}rLppV;Ejr$1Mcq#W5nav@gVC5$R7ws{_Hcn zVB2~FVA_7p9-gxbCWs(MK-++1nCX3n*A;M9`2YPGUd~v${hi@84!nWw78=(OynTX` zt9zZ|h24xI%kcFNmW8bro<5J0_c?p7=gh3WX9NlXS~7n2{@4GRSAEa;66wv)*7tg! zIn|SX-?P4YUl%%1{}V#2u@bRgtJwRDvSGdQ@mu|}|8n&`3rwt6e0};D=sW%M_dN@2 zKz`7Fdd_O-FAq{pYX8qlUF5I8Oe`S*hf=exS1|gz?Ekcl#tA;&8KlF9Sag&~$$w za4*N^NPr^&js!Ro;7EWYfq#(%z}DW)?|{Atb;iX24Uz(7n+Kjg;7{QmEGVlh2SL78 zcje?^yRBDNW`|?8K4wqFY<0|jkJ;Lo zor&2WFnc>@PsHp`n0*_whe5luYi|>>tfp(vOoWbwZh>}V*WNkED=d@`3zh5+HOE5v zp}(tZZx_uA+C#uD;JU6oLdbKBIJg>Hj3mfi#`GzJSD)J?ks3w?owQo2L0 zVxdu3Xe?&yVD>f4{*2itG20m0FgMBAY4LpiiVw6v?@OEfJ`LnvfHc}DbI|8X<6``$m8}Wy7hVD`Op&fMt z+De0w*RQ(voWV*aM&?Rs@Yk-rS%?f)Gc&N*O`r`qh5&)=?J~B8_DDOdzFBX&_RK;m zND7%o_zt9)PNoJ6twcZK?ncZ^WXy zEB7#%X2Tizm4)BG!YMwSb;GU)4S7vg19AOe-|IQ4-Ajrv^U&a22m*g+2o0_{Ac&_t zK9`rpLOIsIT>|9woOD8kyG<0>oVeDIY*#NY;4h96?|=1r+kxaqUMtCdZRXFem4wT% zL^hG>zF-|s7Qg+t_my=q*qwFQVqa8rq(AuK1D=ClU84NETqE9@jpzFj{y?CL4xM=K z?Xij1oX3A$0%Si1pMT82Wlm^3iSZrx_4FTSGT;wB@oPZ2krE=Ft+IFzCHrY9;eRQI zhXfOJE*-doq?=3lx8kP_AZrM^MZ}kiq{}1xH?T`-aM%ixHfQ#YPi8yrpGcHn4fi6^ z=larZCHzGt1i@eQAjd=YeE;e=`%fF+GIDW2_Z{EhuLb)WvO4DO!Chix0O$Fik^uYo zCQFolBGHaWVUX8@vtJ`ljvsm?;V(YPe%ZMbXOJP%`{(z|pI>K9LIV(fgof;ur2ntD z&bkDQ{Xas~w21|H7Gpsj!|Y+7K6Z$joX3^|eG?ifvO(Zp;yP<8&J4n4f#r&y8FCzY zvhQb9|Gjqueusc4zz@H>=kLG&I%{i8s6T840HI@g#XsP6)^niZ;1dJ(2Lv&q;k8fr z%m7}W2O+cn-`853!;@Ws>0oP*|AA|*2j$^KAMjdhTd=icAZT(co4oL-5TtN<-xr)~ ztx3sno*W5qB*2jXM*jig3J06KqV3yQr?&{i3f3Pjs!Ro;7EWY0gePX65vRH zBY}T`1mL;$2Tz|E2K-TVY$QNU|9aeXZUt7n{~~T`dlfJG@4`*N zG57tNptQa(IJjxQV&VjHB*2jXM*=HR9S2#yoXkpM>m90_nFz>xq)0vrka zLnScK`4h9A;|2QF-*vjMaC#Ca_=k#vlkMLr0e0L}k%(sy(T>Py2f|Isa8eslBN=|< zN#c-qpW=kgRrvGof}8f}t9;n+(yVOk-7H;P5iy`x;kuP6mSM8o{9NGdC1BtYrdSy9 zf`Z@@1*hy|?@6`J6Z7@_u9Nit6?o-`{(sjA?zF^=7qDUWuwoDNyUwlEII%2IZrlfs z1a@?q1aAFAWQhRt7v!7%pX4}H^s@i=|JBd|*MERO{v5p0853=Pc;$HThOE}#z$+s{ z{6iUGK7k=&vGCWOe?3kq_YN!8e-Wo_uEC2wAWjL74j*X!shAw7@Ho2d;zeXj=!qP< zz-96r!;t_-0vri&B*2jXM*{y+39#doq~7vR$0^Bj^yqz@-*>_${98DsF#NIWPmK4y zzVk(>OhQA-8`q`rFpkZU07n8G32-F9kpM>m90_nF@XwdPKse=~FL>Gd;*>pj2&qr} z^CiG3!Ji=kcAS#b8;Uyn#!hM*IGWM--S6>{I3@e}*#CT-vj6)l^1kCz;`Gbk(^~#} zJOlMh7or`J68XRCmxI3IDQFPs{qy@}|K}lST)@kjO$Zb}4}tT&B*ejaut{K`e%V0W z+dz{4+5M7?7eD6NKQfx(6B!p9#)u_eupR%5;Qj%B=1jc*VOs$a?w1$^t|5m}HQ`yu=!@v89$S%umA z={~}j{5bJI`v^(BFO?UkBij}GlN^VrfR## z=AMXIgYlgI2k(iPD1;Y%z2yC-4-zAgHPZq>P&Yzg=)&Uq(4h=>!wkpM>m90_nF zz>&beP6F)v2uZz#)MEymr-F(7-}$@~vK&40Rn9&_*m!?yA7MWH5z|l1&eeVAi%^+_ zhLks{7viBDnl;G$4pS=iC@;Or-st8#4;LA!}_wyq9gmRnNNFUxV|yXy7^i58}LXN_f$K z7tTA4tZ23lR2Tn4tnVM05HdgOaqr% z*f=>N5+EP&r&?tB)K%1A^nf0JQUI+G`1`Z(!PreCNcLaS|5xCd9iRLC{i?Y;o=14K zBFx@T@yr}>+XXaYM7b~zuy8z+Mo1GuY|YsSNJ8QXssl5}Eq_iYOVACP@^d>vN= zX}>(6BKQysdox#8P%2nCe-55$ipl7QehNZIfIm{o1LK)-40x18PrvzVa7-B|Jg5Ib z9J9d+FZzHu=FjfEcss!F5MpkTHIFq9go9(^a^Tn;32-F9kpM>m90~lJCBTkjl6nfM zw+uKh1rzzdGmc4?qi4R#!7*VwCUHy(B8|=YWr=$(*xLb#OOow?hFrr=*pmeGaLpl{ zIG^sf`i8iy39eWorihjxqSXbI@c>3dOh{}Z5k7DX{qe>}hQ)<5fF3$98}_C@-dIL> z6eHRDIdkilV>tAuTtMKAibeX}Ibqh*)C|3Q_SiLc)RIY(f8EMzp2|o&qHa z^6?;kVUaQLx5|(l{=qiU|9zX(xqi5ck->$N0ZIg6zi;#Zew@Kq%6`y)K|_M=fYgGz z*Qt6I%CIG?Ul~V0`MTpF`$zwL>OPKU4wg_3aD57PK{9=^Z}iWn(TA`1x&YZPgs_@` z@%0|>H2d%g_DYYvPxQ~P)rViW7e9M{=$~JEKz{bV(0{pg`tbKIH`xz_!1w|UEcam0 zwykU|?I-!D`G9pjdl)`YKOp4}X`typ9`!#d9*sXK9?d@~9<4tq9_>FV9-ZG24?cQQ zKre#pW>)rQ)11KJ39w&rgZd=vm;CPav@afP-Ph5@X*yhI8|eOHVmQQb848Gv{2r3e zLBH`4$(u#y0JbiCJr6#~`3Yy=50nPSa3sKy07n8G32-F9kpM>m{~iepbPs)F-)UiY zft^1ecctfTad- z6O%(DzDT=frJ0$GyQ%*&qA^A4_|y%bzb31%%?)jQKKRNfbbg4~t;H17UHI;*_}huX zekPqUnM2-*Ev$%L@MfN3+gDU`XXe#p9^ai5esKZC@K1|vv}_l@&?Q8;uI8##%XPh# z(o+r^vBC`%e07IhIPyJjl*GBO-w~EHK#YPtcLY->+G|$UEgV{M!MIg?X{hr}I*8Eb!nH77~#ytxQ-yWiXs@Dl$8p8MF)Qg~siYN3-rYExVcn*n;yRMIH>Zmsi zRzMTpp;8Z6p|Vz^Z{)}=S(m`jcwGHu)9s0&>sMcjxYT8V9yAu*DS4UNwDL*}uj`hZ z4R)J#w`tC}BXlF^MxJIvMFHwsvv>V1Nv)+uRU2mdi_8hBURYQ-WS9=i?5VGR;Z)sv z$-_s!`gJJ|ZhDs=Qo1hhxt$t!Mbp!f3z98|BRs)@>-?9P@^g21L^i8bFHAW(9O3rQ zDRh6jMUg4Tk^ps}XCjpCwt`1&{Ed&Pb^Aw#MXG(=e_e2zsvwI;8%36_^K5=IyGeiQ z<|A@Tr`&NBIU{?ocJ?9Ny}FCv3N+`T*2UgymZ$DHJUn&r-nO&a7dG0ypY)}$?cQ*T zrNPD{IS0|}Gow|4BVW_L<=b6a60$wXx%6NS-yyS_Ebn7WE6ZZN&@q9wp0Xusvxa`S zZ+C0YA3J1dOW%Y(bU)k%4xpDXVbi*r3ZCe{SD7wS~V+xYXSe5 zMccNZ@psqj$O-N!9qi>5n3z=gYNCZqZs%~K&*V=Nl=im!JOjyB^Dx>tW{y?N(wUdq5hOZIxb5`U%`X!d zB}-FT^CwNoPrjb9e8KqWRx7O2Oo;nB&*uC)vj<{}&VTxpvr=rAYRcD*=}nzVz8@c? z3!!rksh|30y{vgD_ub6aw`V76>v}c1PdcB|;&Zeh_Q){<^rE2Q?nGk9g4fm`wW2*VGPC{ZJ7-mGId zppzrhl2)G?9nSq!Jt^jJwXO6>_ta&g3*#E*s4jgO5g&;1T6dsjMj1EmxBK79K7C{d z*SC-N-LCO_zTWScTl+v_7-}4IIz6(XV&wvxAldl~G6Nr4E_EsxdRoi#0e{v5=V7;z z;9u`F`_-x`_Xq9UZcuTgQlERJ!OKO-3>B%cl)8uKH}Tf)a7UREj&sEF)fUASx$7R< z_w7g$Wn$J!W2w0{TewX=_|e9oZ^p(?_%eM;;fyB_UKA9R2AcTzJz}jTI?W@4!_tCL zTNuxDVYa{;(vguN zP0F(^F1#1|oX@9H#d6Ou2@*wR+K0R`GW+1{mpoZwZu!xDEn|&8SjM`i^T?KuET!8W zM@^KEjtUYS?1xTmcsOcRUbf5HOwC*4BjhqY!=@?n&PzbcmobH+b5h!u2^&l_dy%!D zchQIkZm|JWrCGOv4{nNgN7XBmW>v3O&Wf8MexZH$a3zPb?C5&S^}E{R&kh$HJZdX? zDr<)H#l*aW8+{)&&0W0Fp|Q$?5x4Pi!kBs4a_h!?U5{4lg$&wp%tEBuGxn9u&C#L! zk<-MDu9ea9Q&oiW$2q&A4w8J~sf(R+EA9$(EwTON@9VWH$Meh4%cVuBE&27a{*pZE z@3u&P)V#2w%#3;Jok@yfv+(?kr}ePY?2E`*IVrSr<@37lx^h!&ncp9zoy+w$x#=@~ zqao30W;?%jD!a1(h|1oY(t_I?J3cU7D~dIpD@S6TW{=Z5<-BhQk5QA1p+;G`QV30V zhnCJPH}A7UJLKuaC9X={F3osNlZaa9a>PWRWeT z^O1YH-LaA4=Yp=(6wBlo3#uULElP!pXEd4?p@VD+QoN3BGfG=N%Z69lA*Wn#*YOF6 zgWg+<&g^-6xvNoYvnRIKZ?sCt)2ntA@Vs>G+~(n_9Xh;Z^QW(o5mLpI(5f4zlDn3y zZa@7ZTk6T0L&@vg5;k7#I8xBO!8_Mi<#7Qy)$=yl6z@ql`eO) z>6_~YudZz~7F>XJ8h0c0MpnF({?&z-r?lKXVElaRi>e26R&SQ65;T5hT!3zuNFSQO zCwIQ(&V^O_lXC3*x*l6;6g`{zM#X`mAQ&o*&O6=~@ac|*u=dyDCCkL--2S{Fj!Sd9 zAuIWL!p!L`^;-1M%-MTP3O&#V#|+vZyuCoqM`wvZ=|_hrZ|x7s-J23IS`KqJxs}XcbP+H~aI4aZNq(}_Q zEVX5mkA|efz3o?KhNbK;5MF)jIoFyal~x@V5?u1I)6my6tUrC-Ibg5m;QlenUN~;>9BVnE)0nSuic(Js((%r|qGTO#{%(2fsDj}%>bLKBr=i6>E?<S`KMnu9r?l(k9X;Wrr*3OxJIeAfcOI4KGO@kFlXtS>8M<=Lr@Ey>HJ9nW{>nec z$$Q5Mi*H=JH#)68p}NH?F}r&xYQYrS^h2d3nDEV8*KV8cKI%Gb;>OCW7oR!!l+#%OOwAA za625@F;k<-BWyR(X-+2EOKW$SCDiPE9nZLZ#^l5OxEp~jD>q0i+cK>P?=&jzvf_8w zCB9m|{w>>o+&BIw0Z0+o4WN~)Y*9= zZ%~sBl4}DKuD7)pcT{>8YRW#^a9h@A0>9`a3&HO@ceZXsXUhlZzu2$y)NPoj?HK*x z({&c<9L`d&`(9MCG(~Ut8XZX!hpsh+E2o)zG-{fdr8T@rnvoxQ^necRG;KPgH%GNi z6q0nCu`^>SQqPxobJwz)(a4b{SCtErEIZ6;(OAA5Hw)$EaWc98jpr*C8yEuHO5pem%sbd82t7@3p?vJUFAFu1%ry1YO-ecV`-%$R3g>0KYQ;@jXA=#E0A0@K19Q(0|7v)YmcH;zINkJ7#1@X+4BagaPE zKLP!2z4A`!(Bm_cpGfaK-LR?XwB5rL?{;!}=JZMWOnRsCcNwwvJL!Tv#*=)c&S$O_ zRf@XS;f8mbsavOo$POA5C-FVCecw)#OM*&gjqmUMXc~=mnp+}U>@#S0JOWkbw`NYS z$n$QSGRs_aZkxrGa1VE9)gURMJP7FIgk6FR(>{*KxYJ@<{89&wEjRu?H8{XxJ5xS^e^rmq)(+ zx{Uk7J-!invlj@pLjuYQoQBb&@2y z!8AHuzH+wNG^rioXLA=$RvT7p+L6~PE|D>rpQ^H?9rb;@?ZG03iRjt7Ri7%qJvlKW z({7{a&THk~mYq*0Duf1#2c2&66&ftRU_F1L3#f+Oo;(+FQSUb~E4~h10V*Kh3{*fh zUICj%jXWZ&TjKD*9t~)$c@ra&&}qB!&V!*FXGY%UUw`TKVUuUxb*mS^%|Ixu1lzM( z7wa44b;o?zb9!l15?W^Nop!#VQ7P*BqNxa818*WEW{bM)oo@UxChssJpWh^uIpWCD z%60Bo4UF92nzH3~^TOy?`>q)Zn%-YzN0SQabRJnfUqPVZVlHa-zR6K+=Qgc{H&w5# zvmB;7M^Jr=oRIvPD#h=UKH8>zK_xFezcpHl($yexwL*P|K=paabCcyqL{7}-ez@e^ z#82+%w9c+$%VfTujAFjHk{VdFW#yxLaW^Qsoj%Ef%efjhZ9;7#uo}4VY%o{(Gr`U0 zVi)U<<9oN(0ZG~Q|H}LBKq|jK{^wqM?-6nenGM(8Gb?+QXk44jjH1ESK(>~avQkk( zq@)t1LZ~z-x@1-|qZIddo=21FQ@_5yzka8l=Y5{D&w0){_c`ahUoW~TDQf+IZ>4uQ z#e8F6XrNl+l;)ezsF3#k2g3T8wp3ng6?R(t7OXo)U$k_hH@;+4e{j#C#{IRmx9ydA zj#oS~UUPu0OK2O?{6|CPJ=EdSz8IBv#`>lvSYp!me; z9xA1sD0C7vHECDp@$L_e_DZ{2-s~C@{p@95EKBF`&fXrF#>@-*RC!-xm5ZC(0)^#M zQ+shmE-tQaUXmeByRjGMSJM0ZW_69O>$bZgdkZSJ)?68VY%+$sX=k!RQS99)csg2$ zd;0#w(8$Z-6URFCoe1oC`RsAk$#+$`qj*Yn(GGC>eA?a;)1=`jAKkO!k`E=VY=jmE z($L`_lA9`v@6%XY4~sG+Cl-AYfx#K1t$01YE*m`DgclT}wQjdK|uUW)#7JkH%MaBOp|&*A#!u83m?Uyr;$B{3|NJu&|2 z)70mmj*r#%%{&7`LzXSKoBCA7@pxlUa7dWSE-$#d0=L7qSHJDM8I`mu;?Sdn{e@Lq z?=}eaIZ)vq2S%@3p-Y1UefS!rPo#!|>&0EG9=}(UGCtbZ^Pqa+-Mj_3#mMbEPr1XH%^-7<9@FhdCohn#B4#+Zx!O!}ae2gbNsDIJ>8p7U^a` z7Nzak(lLfyLYSD_1?&apiLkS?vVUwv+q03KLsF8Hk)xKKgPrYh`5*QDGI*N2R8vD; zT}vG`8XDT#>f|K|P=`*Mn9n(4-frWSP8($b>V($dt@ATiLP5;Ym<<|7_a z*C5HzKqr_~h6+wgi%hT1fM8)%)ipFTWIu=3&>#h~qcJr!G_dHXZW*3#+_%E4=>X^^=Qb}Ug?U~NsbWU$3La5*&45e9?rpG;+n zmH};cvUcxCFp7 zTtmrFr{BxVjf7BnLPKJpa&vR@C(|O-FocT>$(V?vCZJ~U$F0}PER2XUYE)E|Ra9Xj zGz3*>2xNJLT24-0UVc{ia#mIaB^XjxPL&|9peU!HNMxZ_Re}y=8ia}TGx zmm@>XUU_*rIb~H@g5sP+$czZHENm1+mLLa{QIbC|N-L|ZN|04jA@WcuDatDng#wJ} zQ7<$bB@!cziY!cPc02SV$ohsZGD1&=3hwL4ykJ&4)kD-v!|l)hen0c4AQZL5GXZ{V z8A=63&3;yL6hQ>w@Kn?^v~=_gj7-cdtZeKYoLt;IynOug1O$cV3xfsh3q?f57Kuwp zN=eHsUb1wVEa3%3#t^8XJxp6iS5JSrfuWJH$qG|5a|=r=Ya3fT`<1I4R?li8ilE=@ zyk`~ffB5K$s$8RecL;yu+P|brM35dVegZ{mA+oXywI`$^Q=cuES0Y8-3yJH;yhIW6 zAH8nw!otK;f^~w^(4dhb|1c8Td8SK`+J8Us9r^sG_CmP{USh_^#-^r3 z1aUy;yV(g(!P!GjK8OS-Ht0QTG)%FexBx_1g@_=8pT(x&5N0?*pi_k$YUD|?lc3;O zDiKT{P6dC=$EAz@P!&=by!A1CHRL0==K>=T= zA{#n}x}m&_zM0|-_=F`Mi{Jt-V`DNl32pP%*ctaY1ot`xbB{~GBjv@IH9i%`!t%w& z$M?miqw~eaSo6i!eDsSAh<~wVB!98puKHrDum55b6Z>q#+AWbnor1#|V$(*vC{Eqy zOECGFSq2uxQ2L8owgVZJZr{xLp6i* zcQ5L1hyK>Vc@q1rgVGYd zFYQsUi`+~1p6Og8Wl`{nuXuikcb?gmM9EJoI}4t5m&&lw7AkBs-RLrVZkZtYj2e&9Zq9yZ`Kk49l3ZaBZl1tjxhL10WnjJ-g}8q|lZASE6HheZ&7I_+OT4sp zOA>Y#F8rG$N6l-`R%G1!FunOmG4AZ0uJPjOE7lJRu4gut-ApcNVxg_B>waI1`@Ll=sn|O4D}o z{)j?0{Gte=5e@sN@9kc zy_;ZapI?6ug*_8&zhzb%fsE*x;r7zlztKA(Ab34DWw7k5$Nq-(9DAOJ0p#+4&S^=? zF}=2BEK3l(d6uA>O4&X^?z1c3>zz0rTF9fvi4=RJze}dH-?JWna8iGd6QsxL+Rqu`*^=q z3@%{sUZS`&r@N!?itUVwR}FVX$hqB8NBoQ8i$|?i^gN0Ocj}ZcUt$jZARL!qI-$ud z&#P_so!%ZW46c1N8YSCqG>tS%dDn;7sd=xv(Q_SS#$IK zf|g|riWXB0A8rolb?~y>5b@psMh{x?o0xlsb;>UaTBVRQTDRuCGBuUub{3xo`Jyxk^JWu7O`7jEv=0Ee%++U-pkROMXgV56|NL#rG#zRt!kdXsV>I*1#o zmt<*-Uw&()Xp9;4#8I-F{Yg*_&g4HLSDK%2caz=b$JOhQHR8ba$nRCLM}@P+C|g2x z5iplfDjN(Pvvz$YxNw}7J%8^N)0o9#LxX%z{O-0BwgmxN#=8kI!GU_`-(IX{ddiubH?7m$yxwk{ zIA%k2HG**+Lq%8fbl6zIS^IJ|Rx@E>Q1#GYwe!0CJJBYqj$GQ4IuQ0j&S0{1Io?r1 zQb+%lGO(gD*J~FYuQ;>nOonWkNA-qKXTIzObdF~2kxcEX`=SAj|HWIp_ow}99zKkf z_YuP1H{YFQe+0*L!q+e<$xkdE7~ZnKEOt1#O!WGK4GAnqcPQ>Gl!@uB33zlhbNy0A z-(2dJYcGudrc!NQJNI8I*;BZGqjAjPRdxLiz3Z*k>^K}=7O*Yg;s!zvXs>#nX4%lY z&zDo*d!GBaB~fA z=b`&+=mq!u;G-to%)=Zs)uA7@cZh|DH(uzA22_V$8d@+mx;F>YBqP>ra32mvgO6BJ znpzpwI86;Q&KeJckgWMJS1df57@G7<{68!|`jbWLn8`HfL+G=^CTx!1hSu_*XAaJ} zGsl0H^1J;1d609?9przL|38mM&bj09Z}R`=p~E?M==@FoSdWCg^#8h-bI$GMf0#eo zOKXq~Ro^ekmcX-P^uuZqlnn6F*0-_M)3<{EZCC5-+Zq_@8R^?tS(sVr!Chr5eG7e{ zXKQ3(vs%x{$Ov`Ovof>Lv#_-?Fj#G+Z=kPdWWi}+WouwyWnpVzWou-n4g~E`|?mRSK;(c{6*9tx zC#c90`KX~UL5{>g#>4$&q7I@$nnwj)W^Z9vu>yHz1$lV|^dBNGuc!#Oj}_oQxO=T4 zs|Xzx0NnRcP(n~IMMW4EZWKXRXh+~3ZW<|YD99@*Dk`8)P{^w)D9qmYhPfyqDzd67 zDg-%IxVV*9R+5vKMdW0m4SrOsz*s<0K~@EUxyY%=5)fr2RaH5-S58nQAgT&5tg<49 zJONRXCnzHdvI+{ausm`Kv)ZJJl?eB-i8QkpkZf=tdsa{i8v_xUHKA2gq$#tby8QQ+ zHJGzyjqRktZT`=@*6ee(t!Ed;g|nVY5FLVU#%`c=l+RTk`KB7(~XT|5XH~J!y1*6=C&eCY8U6Ag41z z`l|?nyz}}0Dgt_v_ooriNlnMYfam*34gCY1=zFq&68#&eVs=nNVorkW2+m7xc0Xfh zLU$$QPFblW+(br&l@R1+W%An?=QVy4D_Btd;b^c z(VImxt=a{pDr_a~zPN2ji(aoTo5M!R^W$CVjz>+-nHDBII)2Ww8nB#Y0M+|i4!t#S z5YE_>H-4R?^~kEH*LnL-c95>9o+#h)WQ#BmFC11XF5S2+aMEt$hlC>W%ZKFyboqGL z6GJB4ofVnQz^aks3h!&fb4R&Zdmb_@^4{1X9lt|1$j5oPjgIGVz5t+^XCcbw(v(q_ zC2AlT8z|M-9i6d5`X1xq{D*JmZC|ei5)`T{%08J*E;vZ;BQ4ZBPSzgLb$qi%yw2)g ztm-R8P4GHCLlW#d%(VZ;8@C&qSBY2-$9jgb$b=?}_|qm;M%@FIiq`w2-iK_<+ND?>yJ6K+k-)d|_@R}ZJ0pET^jPbM6FOB@B4OZw z-Gc)U4$(T)X;oA`jtD;ccKR~^GqSYqm}Psq@SgSkK#2=#4xgLZ<)d_$c=PYed7Q2msMyW1qf&#qcv= zvE3+GjI6wQe_*F2cyIXT-1(ek>NoZ?MC0DC&rhziye!jHmbZ}S+SD|qZ3vuQcIb2# zNPXIJqukDAg3;k=%QeHD)65MP716}a%NZO%9Fy^M$3eLZTR(UzQd<;?+#xSpn^Yt_ z!lk(D?yzN_9*{ZCAV4>AUB|M0gXp^8UKi4bGR2$K6r0{eKl)udOC5pgaT3WpB*?YKw$)}%Q@MjmQx+xr}q%qt|`EU%e zgut?`UVMY9wLfMjh@hvb{TTDOpmOk_9t4&NLSWfV z6j&zy#F&Yn<>*?FOSsHBIwdapzu+*;w2A3c5Mg-d41D)2OI(O|;TzBR8n z$MC|Y_mD{LnB9E12fS!isHMQ242Qm)&u6aMQlGb{j)Umv10R{K0F2NinS72sj6yYmW!}D+(mlUgl z+Eo*y7@qSN)-mi(;?a_L&T$1q`VIOQ%wHQ6xut5=g>+JxUnn{BnFZ zeXqs71hC1I%ZyR(3ZsLPgjLBwyPZ2O-J>dayeYfmrcVsTTrVPS8b~iTu9|1%aKI}r zm7_*JJBi6cnK>yhUE-jn=b)#brz>DrT~;yCA9<(qWx4grF}5`i660UX#791|CQ-7& zHMy(7X{XfKoi^qkwY}0bEgv%;P!5`91UXlo6@D4!(B5{IPSMTXDe}Tsmt^ED8loYKOXUU{oey|-x?ByHZqp_ytv1Ng-=tDlqHoHlAdov|)hKM)X+CU814K>j zl6ztbPUXp(YEO5sCbvgY1!%M_R;5pJDBbZ(`h7yH8#OI(LX z{I4$!_PV0nc#vC2kO^ecGx3;In@+N{M9#l^phqGrsAV%(t)fOtFKYuBzWACQ*QCN=J~x<7UPPnH(3wXZ{tk3 zAG-c1w@`K9cKJadvAZta=js$F3l+q*H5V*kbbkJf;O0tSYFyoi0t~@dgyAm$hTtp0 z@aF)-9Y7L7rmh5(EHzii`6<8QfA`E{4Fa%!_hQ9z9g0Bd}UjPh2%O%PU zfzwMox;NLGST-eVn>-R+sMvaJm-p4F2oz)pAj&Y#`L;ATdPYk3X@>*y#yhvLD^Gsq zec^;9Q|_DVzza3O_ak{mr}oZk9n32Vevr9dej9sU)`rVnm+7AdTv`A$b2f|)b&7WT zIW-8oJv-;{E?+x!>w*e!sEkp1-UFR#aH#6~g_dLTtE~9y2cB{!kIf_4?b**7w3f-= zmyjJfm&_&)I-%KcMDQaXaV{K@?F$}}9>XJg{o&;47=B#IB9?oDW_anQ zk!>ns3$IIs@~p2sIM^yx`y>N>nMh8W9@H zO?kuz{Wj69;Q+yHhj;R-ay-gEpsvcYxp`w$qU+m2<$X#$*El%3FQ%)2lUds{r7lie zdgQWyRLSS%UmMAS?99wzC3W(YD%i1yfs%paCC6XWEcf6@;ufZ}Wzy!mKW4?#TP7hM zq`N%+g92F5QrxoVH|SA-!AF0C9t9YD^ylc&D-WNnVFrg*Dwsy8rEC|;>Ab$yN{vR6 zsr8M{7KhL1QR_CqFwj|ISa;YoJZ>nF>UP~uN1bDD3hIWKEkn2O?7!<%1;+cjcfBwY zK3=z4|KxsO6_HvT`C-yD@D59Lkd$a|6#*8F3Yz|_Je;0rt!WnF(@^i;Lh8O>Eso5i zX?d;ex3CHLbM9U0Np2VB-(g}d-1ws3)xAZ&q&-DZ!XaF&Z|MgmpwMl;i8K79gY`lo za;Yw3P-%g_N7T7Idi9YN!6?uad_|i60%!`pB29k|G;IQSX|M6uwv(G22)lm@GzDLg zroRB1g0D!^UjR+PSET7LfTrLp()1TVQ$Rdb5$>pUswLRMWP-2f_C&>t&JS98RU4}# zE_0w@QvlJXO4|D7xpySZM)`MtLK1}&x{j<|aUxlVN6YW+J_GQ0%HO;}VQF{c?%@M5 zsr8+P5uEGj6pb4bYQ@~r%ngQsa~|Qqi4zrTwN2s-s6$kq6eX&27(eN%mm!@teNjW+ z238Wsoh-DglIjg<94$&McfMfr;4^4VL-IR5o$$<(=>`k$Xn*j2>o}nr)_j#=y!yVQ z9cNqRn#o9?4nmKb-J24y@dsS$Tv#gj5tlj_mI_c@YEk8(L(21=G%A+2P0WU+f**0I zb784$KjKn+mlCpsegKGq&Mb)>FIhR8&$1qp1|Tzyle9Hwd)xgOKqos=sPpy*K% zr*&xl(zbf@v>0HqvvYFU7+agml7XokYnPtBzCpj2HY8fw@KSkBa_*QIc->j!(M;8_ zXhTwD%>HVX*P;=XmgU0_+*j~!p11Bff=6 zCd=7h52`CcMvV|TgRQUH-(T}k`^Y3zQM_)@VBfk{4sSKNhJbqaC!llu>Z+jhwMX5= ze9}c36&MY;4vX(jTi@2U-irC8FmobU9ONZ=y|3pn_5Ecux!|C1b%- zo^a(gI>7sW+jhbHE!~m#$PXIa-Qy~vDcsk|YhyPS37_`TeklZwJy6*zz-1@C&-z)M z!uGo(;(V1V9U&Q;j#RHW9viTb7O-Eh%U@yU?JkL&xzN8;`=C$s<8xyB@>KWGZs^Xp zlo$ZW0&0YM@u6lZ`L&G0^^IH9w_mZ@ZpOvhbNBT`yk6NSAVG8@PW}c(3@{k+Z&1Vl zgAxB6MLfAmzQqdM_m5<_9_XJPJM19BeynT#!`zBg5t*pZDB|7{AY^mSg3CxVu$rT4 z>APizuW$C~I(Q(7wF-Y>z+|dW#{6~}DSf~uXJdE7_N3L$4)@s<8e*4_mJdn> zI~B8l#|;Ne&d8}Qx>Ggnv^nX`!R=y<+^Zg}6si+ugjoUzU zP5rZrBMHEXur8)>+|<%4YxQ-&ic=<6E?=y~$aM7XS&fX0BHRkm1R;t0(msnRDBu`; zMI8SEa16d8j(-j~z6!Qn-kw`N7V*S+P1H{T$KWgC_!od<@D*|V3&1h>ia7oS;23;G z9RC7v45DsT&U<9Yy{yvdo=*Ph(jHu|P|v5R3%y2;m!(k9F@UJ!!lv~0h&5Ld&$tOj zBkT4>-F>L5A$7H>pm4f?lmy&%%091>$6fReTbZ(}H2&r?rweki2f7x1@b^jE`${?% zY>m)Oe|Jgut(3eV8!5T;Nt$nF{gT*i_Wo}-y*hg@zY&C|Q=*$m7+UHn&9RLrlVhSZ0kC?49nrs^q!J~3*_U4K==>% z2wP@?3Z_+mHC<-)f6}H+j}N9cE7Sg$k?rHb!7uCm>d8}1FE5*)T7LS9?&3C(yMxD{!T(cO zTk6UuiyEAYte!2ps{Y)Wet&Dwh@&al4vYpaJV_VpkN08PE}3EdVBV7bF(Qd_IdyUx z_Rp*Ga&$qVeeLLGOQ&YnN}H=r-Is!B+S0?+mN#WPEAPZN#W-?vuz?!H79;gOkiT9CkCY6=!Ipd0ASz!|s4t*QJj!yjppE z=^=(y(rHNGGxN(q9l)$YvO@efXmWtT$$x_;2N<0E=V)@C^r4;VU^z{E;*JdO+@%8a zTP5p^R|Xqrg81$HpV8#klE9Xg#a&~kTD7dN`5)VU4mUJF(kt#XE-L#?H0UX5?*gRns0c3%0p zU`Ju7lZC3StgzncjYW4&-LC7!L{3m8p}=$S6?y&(;5qn;JpVcH+#4{NB<6D9B+YlP z!v7R_4!$DKe*ruPUyW;0u zADeCR;R^Yja~ujj2M~SEw!(HpQNoy=uQ`<^!gBn;o7mH9ZA+>BG8fL{4+8g7x*APA z+05<^ET1 zE^ll$Odb4)Q=bb{XZsPSzUIG|?ULw$(XJ>ZB{$LS`)|DVGi{;I?*8ySMtyn)qh9(M zqwa%Y)EAyzs8nV4#LQ(NEDRSG25?3R_t)@ctp0hHuH#)&0VUc2 zlTx5Wdv`6nJ)8ZJTKgm9MLvss3VjO4)uV1Rt4Gz0N7XO`>$EnJHfDJ9Iyb5kQ9T-Q z4&E6oS{U|&mTHR@0NnBhw(l~$;2t}rADiF6)iBI;qw7Q$owRvCz~0h;(x)GF=DWUCxDJkW z(nvr!dkTcJ3u-x=_$C)67d1Ce2xt;_oV)|?V8=<+x;5K?KSt? z2B+sca-@78^_#_&+YxWB6M9m68uV9&Z7D3RwlOHM^ihsDzD+Aj!i2_9CW+NHwyH0L zB^|_MFMHSDL{BoFre4apK=W>fgyf)R{770EpGS0gpi?5?#=92ue4IYDo#(h2?GLO2 zGo%CH*Q^6Gqyu0!>p)-n89dee9dAqf^r%f3T2vt35X?`F}O-QA~+mAgBiUc zI6RKT$bhH9qyOQJj7J!$sHx$9c%z~w!@qS!O+!NipJ>Q9gp-CA8tg_#i{j@YF#!zn zjg){X1EFSOW@d&E9vmwhnHphYTVH1dNebB6+1S|00Ku_yzz7^1bJ!g^7UX~#-iDvk zHb|KgTtH}2&YeT=tnQtM2#Bj!9?j4;>|uNPnYIBBToT_m%h7ed?s{84Y21$Q?{05S zDcN&Tk6aX(85ep!1bD`OWpz+oK0Un`SL^~A9=xSOop#%MRR)U!#PdaBqg>(RF6)$l z(!RD^ACd55CHR86p7$k41!Q;tW4K#(D^@6pjgPjD72#VyWDJjXjbt3}+@BHD*WLEC z8stvgJoSzWxmmm`ukg^m64T@n$nbDZLaJHX+Ey4cJP3cIc=##9!;PE{ zGmVe*w4Z}NKzqv66pEK*#)lS$dbxf2!uw!gH$7Fx@gyiH7=(nY?Djff?{zg)^s(cs zr28`sA8~WA|5kZT>ct0u?bf~C$r3zD0zr*?yb+Q>=+WT%sqf(WMeiW^emtnWIni)C zbz-c)_u);Ex_lA*Qrz9MH!3r-AP0m{>Q+5)+stj$l<2wS2NHQ>gc+z>t&Xa>qDGyx zj0%+*YSgIet7awdSIP)R)E$eYp;>8z(LiWvsY12|k`+DVTR;gU@5-QN@PUQ!fK$^{>Cc7HHTFKl3Qf{ zhF5|fivZu=fA<7bgU(=2^ChT3cjyZ;kOexT8gw*J_CvK`vF2CsiA>2taG$(7C|UXN za~|pHf-X4-4iacka?arqBc%??$pYL}T}-r$V?tRO6E?A!DE7vLpC2YvRWV^NjtK%4 zCf-t`0#O{H9>v%~yxfVBc4)aP+$Ap?1Cf;quM3W*W1ec;>l5%Pg7j2J4BC=o} zhYzD-fO2XxuE!DcppU{lcqPAj=mlaP45^q0K^7Gh$|(vDLR z1T2;kg_27Vb->+eL_LuYFDbceab=}gNZ2pXgcZ>s$_Y5P5zN)r9Cbwt%_fHG|2ZHy zol5Al9?_Yg&X0?b8 zaYUuUQZyP8fZ7EHaLu>-C?_}Io{eG=R8%nWRvr^s*_fcA!GxwJCQ?6OB1jYyJNBUh zEw)D?Vt`e%^%2%m6BDQp+C&I~=7l?pW3@(o5I^*hO$?1B+k|r!#)8{gVCfw@_9Z=O zZd~s*v}#E2ASG8EVMk*bP@}P+m#R$<<>VEd04Ek}%^FN-YolVOYH2%>4`>XTYTWf+ zGzY9CWUMV4Z=()qN&*9)OOeEZ6|KF4l3RewtVZ*l$!R7PFo_G>gq1Tl7tLdga!MWv zMAJXej0@R_`k=%X4p(sf^jNSR_puUPDnkXD61^Al0+n03kk?pN`DpCDo3ND5qITF_ z#AUEr6<Y`;hyRs8${ z=ePen8JI)43;Jtg>VEGHy3FqOU?;G0h0>Nq6q?D(aTOtwX( z9z8W;*4&FJ(&mA-j1Dt&`OW+`ueH($XPqEIekI#gIWFwGf$?{^7J z#Xr@K0pF>|WcF`;GQUf6-d-+pK4<-+D4nUA^7#UncE>iw&8WwG(~j9=e9Xx8Z_0rk zLLXXL&0yX3(}QO4-AVJfTBv>f^6+!=0dFS{ON(fC9FgijB@oU~wlHeur1{%HGcUV^ z;nd%h13S;T@9&=3Tk_L08}Qws&BgcSA@>owT>pzFZcF%!q_1t^SmG{F!C7d$XXeo6 z+nJ5~%k@kZe^U-@Yjin{hUT@TpKgDG@Af~dcsFkiOAu#$w@60K%Q|abtRU136S#3@ zYx?la{^z&t&p79?R;#}$$L9?P&CEHw3NxDu;QL*L^rhW}ap@^TD>u<7^h!2bA1u+h zA|Oxao!m2fSAqZKi)P!uDF?c;fD4PAw)mf~9>BNdgJ=9vV&JoJ92M2|=C1T(auBBm z?E>_7xF^N1<->QY2dTj9w5UHUM>rg}ieEq0e*7}ynW3{HF#_z<41OG8Umxgq5^9GZ zBIwr{Dyh*=FwG23l=ljC_`}TMyn%46V9WhpNB{L_ME6T5Z^KI)vbPu;o0;jMyj7N# zhLF3;+*}uh7{SX{UtgC-R~NEH=o1lcTRYUOT&WL@xgj)AT0oeOzP=+7L5xTUURT!^ z-u3iM;oZi@hQxtiy?QlK3h(G>LEJ#Z{ge`mq)Dd!o)QZsr68&xdX)&?%*>3)P6KnX zva%u;;UTXU(G!9S5d#uJs-!kDva?%GLU6{$Bz|gGFf%jf#Vp3qvI;deHYO&zBu-Z7 z0ApL}!Q$9J8m`L2H0Yz1J(^1xDV&HybV&&D2nk2JKw^UPF=;E#a8~pBA@q>K#@*f9 z+nqo{c%7Xg5tpyGw>QKg$;}uMinBaMZ!5 zA(mv|GWe(<5G#mijgo`;!L@lt6mcF6w7a;3!v+cnAf2c2LqS{~urLtPl@Ul46cp-7 zLRfu$VIf?+p_{X-tE*QALW5eJ)Wh&_+@~UEwYRl_De!gXKe%-~(P+NtsNA(4Y)u z$|}&6S``LUCDS294u2wf8E%HCjJ!;PEQ2F9SE}5QhYWOxJQ+c73JPRa5i%eA;rtPE zu??aB0&$Y{Be5tdE2*G#WGI7>l1e2%7e*z75}m0)z!%I-P60BKDbmS8hB7n=X+9gq zfcBYk2-ZWPawQIOpK($_G?^Sxkycf9E-Bhu29I~&Iv!(`V_>L4X9`1VO0llV&5p&{8wOd%yG zv@?`z$nh?miYieyzz3(KOj-h(IMVC^Gf1G z$7{1n-01E#(z|+whSlxd9tm^Lpf{d%eMWC^s)TG^IBS-h+g@uBIAPCJ@}ED>!LL8g zXY{YZ66>-*(X!58J-Tn6!Pd4kwUcF8y;rMNc%0I$;S9bXvw(Y+mi4)bLAj8>spLO@ z`Ga47`OoM{f>YdU{zMy6X%(xPT69AEwzs`6{1TUG(w{bY!m8Y|?)eb+ENw_m3C2%< zRmp!|R)AkGD`xbW0QV^JCt6GAPi|o`@l?L#$;!Vp%~dFQr7dg35oQiyhFI=dT1#Ap zaiqt8^Ctg!%>sVCW|`4D09&4O{fTzLpoyX09tOG-Om`ibTZ4;bX=E;ejDAza{?LV?hAV1>v!v+)&P?@Fu~B!H#cVjrv?z zur*ES2wS(=XhQ%uJQw`_SaA3DxYMiuu##=)?E25EE%58r7IsXL#F?|#mCo(Qvk21a zAI~C=x&*$aW#i#$=o&qCbY4Y^&Q;4&RC7tLexo0==OES0&J&VBg33byP6(d@S!U{bu!Ir+<&k8W=e~$`!e1{ G2LB%sft?}% literal 0 HcmV?d00001 diff --git a/tests/integration_tests/run_constant_reprocessing_openmc/pincell_settings.xml b/tests/integration_tests/run_constant_reprocessing_openmc/pincell_settings.xml new file mode 100644 index 000000000..aeee52690 --- /dev/null +++ b/tests/integration_tests/run_constant_reprocessing_openmc/pincell_settings.xml @@ -0,0 +1,8 @@ + + + eigenvalue + 1000 + 50 + 10 + 600.0 + diff --git a/tests/integration_tests/run_constant_reprocessing_openmc/test.py b/tests/integration_tests/run_constant_reprocessing_openmc/test.py index 36237add6..9cce67fbd 100644 --- a/tests/integration_tests/run_constant_reprocessing_openmc/test.py +++ b/tests/integration_tests/run_constant_reprocessing_openmc/test.py @@ -10,29 +10,34 @@ import tables as tb import subprocess +def _create_nuclide_map(node): + nuclides = list(map(bytes.decode, node.nuclide_map.col('nuclide'))) + indices = node.nuclide_map.col('index') + return dict(zip(nuclides, indices)) + @pytest.fixture def setup(scope='module'): cwd = Path(__file__).parents[0].resolve() os.chdir(cwd) test_db = cwd / 'saltproc_runtime/saltproc_results.h5' - ref_db = cwd / 'msbr_reference_results.h5' + ref_db = cwd / 'pincell_reference_results.h5' atol = 3e-3 - rtol = 4e-2 + rtol = 5e-2 return cwd, test_db, ref_db, atol, rtol @pytest.mark.slow def test_integration_2step_constant_ideal_removal_heavy(setup): cwd, test_db, ref_db, atol, rtol = setup - args = ['python', '-m', 'saltproc', '-i', str(cwd / 'msbr_input.json')] -# subprocess.run( -# args, -# check=True, -# cwd=cwd, -# stdout=sys.stdout, -# stderr=subprocess.STDOUT) - #np.testing.assert_allclose(read_keff(test_db), read_keff(ref_db), atol=tol) + args = ['python', '-m', 'saltproc', '-i', str(cwd / 'pincell_input.json')] + subprocess.run( + args, + check=True, + cwd=cwd, + stdout=sys.stdout, + stderr=subprocess.STDOUT) + np.testing.assert_allclose(read_keff(test_db), read_keff(ref_db), atol=atol) assert_db_allclose(test_db, ref_db, atol, rtol) #shutil.rmtree(cwd / 'saltproc_runtime') @@ -52,15 +57,16 @@ def read_keff(file): def assert_db_allclose(test_db, ref_db, atol, rtol): assert_nuclide_mass_allclose(test_db, ref_db, atol, rtol) assert_in_out_streams_allclose(test_db, ref_db, atol, rtol) - ref_data, ref_param = read_fuel(ref_db) - test_data, test_param = read_fuel(test_db) - # Compare materials composition - for node_nm, node in ref_data.items(): - for nuc, mass_arr in node.items(): + ref_data, ref_after_param, ref_before_param = read_fuel(ref_db) + test_data, test_after_param, test_before_param = read_fuel(test_db) + for node_name, test_comp in test_data.items(): + for nuc, test_mass_arr in test_comp.items(): np.testing.assert_allclose( - mass_arr, test_data[node_nm][nuc], atol=atol, rtol=rtol) + test_mass_arr, ref_data[node_name][nuc], rtol=rtol) # Compare material properties - np.testing.assert_allclose(test_param, ref_param, atol=atol, rtol=rtol) + np.testing.assert_allclose(test_after_param, ref_after_param, rtol=rtol) + np.testing.assert_allclose(test_before_param, ref_before_param, rtol=rtol) + def assert_nuclide_mass_allclose(test_db, ref_db, atol, rtol): ref_mass_before, ref_mass_after = read_nuclide_mass(ref_db) @@ -74,14 +80,17 @@ def read_nuclide_mass(db_file): db = tb.open_file(db_file, mode='r') fuel_before = db.root.materials.fuel.before_reproc.comp fuel_after = db.root.materials.fuel.after_reproc.comp - nucmap = fuel_before.attrs.iso_map + + before_nucmap = _create_nuclide_map(db.root.materials.fuel.before_reproc) + after_nucmap = _create_nuclide_map(db.root.materials.fuel.after_reproc) mass_before = {} mass_after = {} - for nuc in nucmap: - mass_before[nuc] = np.array([row[nucmap[nuc]] for row in fuel_before]) - mass_after[nuc] = np.array([row1[nucmap[nuc]] for row1 in fuel_after]) + for nuc, idx in before_nucmap.items(): + mass_before[nuc] = np.array([row[idx] for row in fuel_before]) + for nuc, idx in after_nucmap.items(): + mass_after[nuc] = np.array([row1[idx] for row1 in fuel_after]) db.close() return mass_before, mass_after @@ -110,23 +119,33 @@ def read_in_out_streams(db_file): db.root.materials.fuel.in_out_streams.waste_entrainment_separator waste_ni_filter = db.root.materials.fuel.in_out_streams.waste_nickel_filter feed_leu = db.root.materials.fuel.in_out_streams.feed_leu - waste_nucmap = waste_ni_filter.attrs.iso_map - feed_nucmap = feed_leu.attrs.iso_map + + waste_sparger_nucmap = _create_nuclide_map(waste_sparger) + waste_separator_nucmap = _create_nuclide_map(waste_separator) + waste_ni_filter_nucmap = _create_nuclide_map(waste_ni_filter) + feed_nucmap = _create_nuclide_map(feed_leu) + waste_sparger = waste_sparger.comp + waste_separator = waste_separator.comp + waste_ni_filter = waste_ni_filter.comp + feed_leu = feed_leu.comp + mass_waste_sparger = {} mass_waste_separator = {} mass_waste_ni_filter = {} mass_feed_leu = {} - for nuc in waste_nucmap: + for nuc, idx in waste_sparger_nucmap.items(): mass_waste_sparger[nuc] = np.array( - [row[waste_nucmap[nuc]] for row in waste_sparger]) + [row[idx] for row in waste_sparger]) + for nuc, idx in waste_separator_nucmap.items(): mass_waste_separator[nuc] = np.array( - [row[waste_nucmap[nuc]] for row in waste_separator]) + [row[idx] for row in waste_separator]) + for nuc, idx in waste_ni_filter_nucmap.items(): mass_waste_ni_filter[nuc] = np.array( - [row[waste_nucmap[nuc]] for row in waste_ni_filter]) - for nuc in feed_nucmap: + [row[idx] for row in waste_ni_filter]) + for nuc, idx in feed_nucmap.items(): mass_feed_leu[nuc] = np.array( - [row[feed_nucmap[nuc]] for row in feed_leu]) + [row[idx] for row in feed_leu]) db.close() return mass_waste_sparger, \ mass_waste_separator, \ @@ -137,16 +156,28 @@ def read_fuel(file): db = tb.open_file(file, mode='r') fuel = db.root.materials.fuel out_data = {} + out_data = {} for node in db.walk_nodes(fuel, classname="EArray"): - nucmap = node.attrs.iso_map - out_data[node._v_name] = {} + nucmap = _create_nuclide_map(node._v_parent) + if node._v_name == 'comp': + node_name = node._v_parent._v_name + else: + node_name = node._v_name + out_data[node_name] = {} # print(node) - for nuc in nucmap: - out_data[node._v_name][nuc] = \ - np.array([row[nucmap[nuc]] for row in node]) + for nuc, idx in nucmap.items(): + out_data[node_name][nuc] = \ + np.array([row[idx] for row in node]) # Read table with material parameters (density, temperature, mass) - tmp = fuel.after_reproc.parameters.read() - # Convert structured array to simple array - param = tmp.view(np.float64).reshape(tmp.shape + (-1,)) + tmp_after = fuel.after_reproc.parameters.read() + tmp_before = fuel.before_reproc.parameters.read() + all_params = [] + for tmp in (tmp_after, tmp_before): + # Convert structured array to simple array + params = tmp.view(np.float64).reshape(tmp.shape + (-1,)) + # remove temperature as it is broken right now. + params = np.concatenate((params[:,0:3], params[:, 4:]), axis=1) + all_params += [params] + after_params, before_params = all_params db.close() - return out_data, param + return out_data, after_params, before_params diff --git a/tests/integration_tests/run_no_reprocessing_openmc/materials.xml b/tests/integration_tests/run_no_reprocessing_openmc/materials.xml deleted file mode 100644 index 9d2c45b52..000000000 --- a/tests/integration_tests/run_no_reprocessing_openmc/materials.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/integration_tests/run_no_reprocessing_openmc/settings.xml b/tests/integration_tests/run_no_reprocessing_openmc/pincell_settings.xml similarity index 100% rename from tests/integration_tests/run_no_reprocessing_openmc/settings.xml rename to tests/integration_tests/run_no_reprocessing_openmc/pincell_settings.xml From f568996fe55a5696c235254d782344296c28b034 Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 20 Apr 2023 15:50:34 -0500 Subject: [PATCH 13/62] update no reprocessing integration test for openmc --- .../run_no_reprocessing_openmc/materials.xml | 28 + .../pincell_geometry.xml | 13 + .../pincell_settings.xml | 8 +- .../ref_saltproc_results.h5 | Bin 117823 -> 50378 bytes .../reference_error | 842 +++++++++--------- .../test_input.json | 6 +- .../run_no_reprocessing_openmc/test_openmc.py | 2 - 7 files changed, 468 insertions(+), 431 deletions(-) create mode 100644 tests/integration_tests/run_no_reprocessing_openmc/materials.xml create mode 100644 tests/integration_tests/run_no_reprocessing_openmc/pincell_geometry.xml diff --git a/tests/integration_tests/run_no_reprocessing_openmc/materials.xml b/tests/integration_tests/run_no_reprocessing_openmc/materials.xml new file mode 100644 index 000000000..3fbffeae6 --- /dev/null +++ b/tests/integration_tests/run_no_reprocessing_openmc/materials.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/integration_tests/run_no_reprocessing_openmc/pincell_geometry.xml b/tests/integration_tests/run_no_reprocessing_openmc/pincell_geometry.xml new file mode 100644 index 000000000..f9460746a --- /dev/null +++ b/tests/integration_tests/run_no_reprocessing_openmc/pincell_geometry.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/tests/integration_tests/run_no_reprocessing_openmc/pincell_settings.xml b/tests/integration_tests/run_no_reprocessing_openmc/pincell_settings.xml index 243b223a2..aeee52690 100644 --- a/tests/integration_tests/run_no_reprocessing_openmc/pincell_settings.xml +++ b/tests/integration_tests/run_no_reprocessing_openmc/pincell_settings.xml @@ -1,10 +1,8 @@ eigenvalue - 100 - 40 + 1000 + 50 10 - 900.0 - interpolation - 800.0 1000.0 + 600.0 diff --git a/tests/integration_tests/run_no_reprocessing_openmc/ref_saltproc_results.h5 b/tests/integration_tests/run_no_reprocessing_openmc/ref_saltproc_results.h5 index 276a5d3b2ea47c7fdedbc34ffc17e9679012bb60..ccbe6dad8d9840722be8c2f1d47848904e4e187f 100644 GIT binary patch literal 50378 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 OCxlo^x-#)cD*qoLu^mMK literal 117823 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%0D3Vj<;Ya zGeF<*oTg~I(>ml%(kE^|mN;ppkRkd{H{0H?>wN86UF#8~>r|vgNcqu(6ZTIYiW+RI@s-j{*L^=Dc+j_#wBeQgL1e9%aOIQzql1!` z2hty@yHP%RO@E)3^^W`dHo0RT_U|;R>VP>8@AnQxuWbR!~cCwL--dtH&#FP28VRxQ0nul1&U z-zGjJs#{#A4wlf`t!j~^zHSbBOm-8x9at{H1N-%1-_o#$@O8E5;NS31b0P%Gpieez_7e_h5Gje~(FtT)acxW-B$ zJah?4>UJ#kuxWer}2CXTZ&2 z3|{xj8OftbNj8mbUCTbd@$wjc#)CB>&e5a)6c1aJf{dWlWDAl~^=R)F>o?Qv+BKol z4Cf9U^EID}T*bVGrEIN9#_=g_M3!Zzc#Hqk^?-GBCtmj4X}a~}&Kbsotshx{%tZT` zj5Xr;h-t$+76bOUC&pDzTu*LlX3(=AlA+;C{&M5tjV6~FMK8!#SfaC%yo&86mGY*OOQ>c z@-8~4$Pi!RwR!p0yuuA$;Rdg8gIBo0E8O7!TijrHpH2M=@3Rqg;6Ce;2Jf>MnQHX{5d6xAi9}SO27RnCuOj3-h)ubE?oMdLRSl2it zNPF2;pKEF!P`YJIXeaMZGODi@vo!IK9dAjYlY*`XcMcOLiC1RS?psYF)lK=&3@aQ} zb_ZSP%#f6X?gkI%QTHhK`*{#6^Kc5t*y#0V%=awaqHUOS)kH~7zq1H>9edJTDn{PD zZarw3gY5L8Ar7bN%2h?_p=u#pdM5<28W~)V}Z!=K- z{MzV}6mT~vX2J~I4IcTa(4O3cxH*(rdo?B|8`U-v2bx2#i*Bwcy|1AtMiU3X)bu3+N6v`nO+`oO_T@ZUKHZ!2hDZ zOA6p9=m^={j5YKWLon#XC90~&`TjU?o1q7~2;K?u&)h<{A zh|5us-%1W(wF?OR?ZR*)R=j}l>{u#l`%}FDC7eR_0-PM=8m{Vu0tRb(0Mn6h^(|lw zgG?~`1q92$Ahgurg;Ifl!9wvE0Rw`OU?-XqqhLS?r~(oOAUBMJ0bxXx4$W;*!vHTQ zi^lm=#9)FH?M3zPL=5m-x4t7q(Seh4p)ME|1A>^#s#0F8(dH6TpRK0{jpqiR6lumPlN(2%IC z!B0~36xP`$VXRUd%>^TDKnOJfVgaBklz`Jq0gnVFi4;vDnxO50ak@zmD%b%V4C{82 zz&Arg6ECS75RTQ`2|%-8#107ByAPr^ zjM@Rd9XQEmr?yGdH{`LCsEl0y!#5s6ViAY>^WK+kB51_HtO z$PqNj=f#7dw0IDX+=CxkUswUX>zQa_7$pQkSSJt#0hPi?ArSUoJ_~K&!h{Yzqe+?; zR2Ve`!ejb0v;r781OgQ&&_e)qj$0^qNe=<0SNTTury>G0vPe>4G!Y1i;(lmjV?+@M zUu4&#nUcMG;uK*rVHT_`0zpUj5Ly?Ek57W)?N&6I_F`kGEH(y47Xg2W4rUizf)z%< z8^`@1MXO?!5eS7pyJ5waJ9>;X0^u_i@KFl-D2y}$p>#D3EFPlY4CD^hpzc7Uv04cPPpK<#N0zh_2xG-S8YQZ9Nh|>$dKM-}elDmbz?Idu zSihh^F98}w?oeSA6A0e7L(zH#f}2ouBxp0Bm;j^QRQy{rf#CG$8rqnDiYCCwk#<;D zp@f9oB-n1KYy!M_f<1!HLZeBKm~b0Fv!Q#kYOx`8&_KkZY{H%67woXI33i~ng6{z4 z;I|iunyGAS)iz9K%)H@UH_AFdrpp|jkDlIiKy_G5=ial~wGz<@FDzxcs@IPZ ziDNp***hd(YAzX^l^I>LWXM^cr3Rjzt@iKq8g*;y(*@ibcdO5vrE`v@yz5VhS6t_Vbo#L_#mp`bkMO<@p2Z;$xv zZ>O!lw5oQ#VYt18i+aj-L*QVvzQEWbJGh8~sBG(IE6yK>dGwM~aOoPv>u#}T`& zq5Jwe${me<&OKx@4gR&!y<*pDImqi;vo6(b5~eZ-gc{F}9I3i+R(+bbz`B*@A|WtUz5XU5Pb2jF z>n{BP4o~kQy)^E?Fijbfoq(I=^UlwkR}Y$fpv)LmB{Y)X)ZoMZzg&t?Ju&py8r$9q z8aZ+DS5sfGAg{gaaXNX9>d`D3Sobg^%N(*h3z?CPJN>KuJj(hb-joEJNv~go=$v;X*=|jXI!2W^aI%kT zq>haHSt9TBsoy2+Kc?X_Jug);v!6v8FLbfv!;Kt`foJo39zVe&7fo5CjBwfy!XKWp zWZ1$TS-;;mLvgzYOWX6&It62ghloYyahlP02JDOjEN|52^Fjm8ct|(D@n^&IY z$#{;~vb>0RO%Yik;-raq*0#M(9ug@l94sV0Ru$>ssGjLUE^-xYC%B&s=xal25Vz?w z71qZXgI`u29E_j)?46pFL3z_TD%9maKenYmMuZY4CGUo~lw0487`177Kjox;F7s*p zH$~MJdD~KCD7hx#ybZsn-KSNDYTczW9oKA^tz?*)#GSNt5Yzmbi+r?noN>)k^p(mV zlz%~cF1aR-HoURITw?6Df~{-mH*2KF@qDmr2t&wtYTeiSJ?GRvq>0anHS78urZ5^v zeQfT8-2ciqPrapl>o$Syx;(3UKJb+u^lb62-d zM%f!>VQqJ>ZOo5ejk{ZCOZmhg3bis9sIzv&fAp7W$e5H0iXa_qu_{QH*J>%>k^ z9t1Z$SGrs5aJE3iRkypRj(ctVUDx-SD4`x+v@UDM)6^VA**yH2FnAs(6Uv(A`X;41huD=DtrO}2|}Y`Q#nHY~%>Z>x*y_!eX? z+Kywj$yb$L)UM&t_W9@5#OUJy6fnPi1;-zw`0B*X6MeyC=9Q4>^@O zJpa#+Eia#UgN5vsy1_e+^haLx)EumDx=ZmH=g`mL{WRr~oeGjEa$}fV0Yk5ysYIZ336X1_T#{|IsCu{0(@KUcn+J&E4S*&eB97s6N+p#1*;n@T?K* zL_NpOR)x?l(=Tq;t?MnI@ptu;qo+APWBlz4(rt4!xL9>vwHy1!9l!7t;5!c1g-96(svpA z^fR(e^u1hws?U=v@-9;~t!|B86fwDd*~S(p&F_ z1-nh(tLAD%u1-&QXv8cr)Lp%M{5<1s_MscSX{%k>I3<3X3&hR4Ah%3?jP&RC$c~Rh znqKxeQy#YGv2>lR>WJLWZypEKhc+Ynu{+xy*3SI4Yk6+tMdBH|F5-1`%UTO}Tc3H) z19t|_BWhAwaxJ>OubE0J_^N`Ra=*?gh&jDAca9}Fz$56u`x=Bn=!7#@E{pK`Z(HW> z?c$r=IB_BUvH7*zL!4A+&4U!ZkUf;A-ruFTb2#g`gP*;n3MD6dgFd2Ho_zHVUfp_| zWIN*BCQWl~s5Pyz%{`p%7UDc%a-Zs&+}1aYk-KXqt+u8ju1e}L6%5Z4D`izxY4_^& zZGW8mqM%z*E8WU1dLrppFJdb%UdQ?Cs>fSCD{97)kKzw3;*1GC78mu-?Z2wH=4c%y z*V><~{|EQmXJ0&?TwQgZ<*~;{Ln@^3fDL2o8L81UUFs$e;ec092sV}q)2Ey?;L;{}ecG|fn1YB3mfJt6LA2vG+nAic$lY3CCCLB; z%cGVA%bBMPEB5LjK(QPMmVf(2_tc2hQB~4F(QPKeR=zCVPNy@u=VKlb@m5OzO`$Y1 zX6(-j&bnA2Sgxi*a-ySkQ{ZJBQ>vmxtlno3+*T>imUGd1?-(y9 zaa>~(6+Du4S`P@8^B@ifn%+F?xO>A%%$atods;H zWLDo-K89!~HL3m(y~V%(==9zf@^PE3&dk}H%AVwNaoqmG>B@FvO10kVedho9b(XVxwbXV!?7T_Tt4j zuv~(2&6ki%@$m`&La}+%qGB@wC7b`9Vlx6In~!D%F7Y(UjhE$QpZ53m38|npHw{9S#OI6(#@XkY)JHjUqe@AQ>aYRXx^jJ z&5rkhbn}BH>1G6KH}{aWn^EcJD}PBhQ=;0<|Ix8k1MfiMD#}Vqsw!$~;73VSSxu>* z9|tsgGsUQZf-lhV1tVN4eiY0qAON(0RaI1#$N>;)W}*e(=%NhlSXE?I5Dnc1(<`Bw zfPk`!QYP&h@&@>=q6D+`JBq-3RTY%rDmgziEm}GZsW5>2l$FVwU_w6}5eN^fHfO8_ z8-W4lO|GhnO0z39*d?$EHHb4mfI%wUmwqZd0!-*1*e$p(YM^vwkQFGDtWQh<1&WpW zsdqz#VvYVa#(1Uws1YI9RB|qKKNf6qUjUm`fPhomqQ$MBi;Osd_&J!c8YT=8Cklu-9bQZY zAtwq5Io&}mp|KPYb243AfuNK5!U_?hP7|=YVbx~%_b_11kE6k4ueu!m7l;!V8F8|H z4G^d0s>)-+A z#zEL=c?G~u3oDj5aM8kZjy6?y1`9he(~t)@XuRda3>G?KH=r$$Pt#|CnA8K zfYK_+3WGlpEdzu6&{V+-r2_zJp&A$fiU{=0R%OU zX1It!5#(gSfIlb}140ptc2OCjMhpx^Y*|G$4~@%e+JvoJrP0jf7b}H9qKE*A0>hsm z=l=mkMV73_VX!D7z@pMX%xmZvC0-VQVjvX;k0Js*$_h1Nq_v3vkop3R%ZL=79^h+{ zr4x(*l8X8Rk|F{~s$qx}`G>+b5nxh=Xto$oiU>d{4>Xs5g-Q`4eTskHLp&|l=>iP&NvVp{iLR3-z0-}OxI3} ztRe!i${L!M&?;CezabW{A_Bb10p|4=UfmsY>MFfzQ4~&UoRz!HWgn46yxrqR@ zx`G=2LaktK8kJNS+=>Wrt1h%$j6OFUkzE9?*#8l@N(IThmXNDeXpe(Mu807+3P5Y| z7jy+{0d&@#!HI|Nhw9>$hykyN0K5W&=U~4u=oJy5SHq|g178u^uL3X(oRJW}!Ycv* z3nan-SVRC|C8H6R5Git2SO+#3|dBFJyshNk-q#)9dznyD~A7C~++K(eBM$~4gMW&{J^k#qpbg415m z^cX0M2%s#W@eXQ;!Lo<|%i4z;F<=%EfLUJ9h=Xe0@L>LlW)T6J^#j%wE9p%HaF!{W z=<`CGI9l}6k(&gAXAuFO#fuh*0knt!&~ihKe<50M&+x@yl%I@g8EwO2T10?paiG^M z2Gk+~Pz&gygSy8pR0Bn|%*YkNAX>!Y)Bj&x_wUj$6vP3%eJ6Gi%;IWr5qF0U3K?~g zVnIPyH)jzCJBgy$7c8#rE)I66RB&+aU*O;>NDG3C;3CBD_e}bZqGWkon|nW+<`F*S zx_PL58qpGn)w#{AuTU`cq*Wf2pZB~qJ32bXhM`3VFfLj?) z3cBUuc%Bj5BdJ^IMD1^ZZh`198N*uw-a=h$TtBA#H++kyx393uvoXoKg)fpe{Eh6T7*7p_I8 zKV*beQ@5zr2fY-g>DR@e)7xFw)D}6bh$!QPF~UMG!CU^zg2zq|=!$R Date: Thu, 20 Apr 2023 15:50:58 -0500 Subject: [PATCH 14/62] pin openmc version --- environment.yml | 2 +- requirements.txt | 2 +- saltproc/version.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/environment.yml b/environment.yml index 8d24963ff..5eeaeb3d9 100644 --- a/environment.yml +++ b/environment.yml @@ -4,7 +4,7 @@ channels: - defaults dependencies: - numpy - - openmc + - openmc>=0.13.3 - pytables - networkx - pydot diff --git a/requirements.txt b/requirements.txt index 60e68107a..dcd7156d5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy scipy json jsonschema -openmc +openmc >= 0.13.3 pytables networkx pydot diff --git a/saltproc/version.py b/saltproc/version.py index f0e9b63f7..ba57da519 100644 --- a/saltproc/version.py +++ b/saltproc/version.py @@ -89,7 +89,7 @@ './input_schema.json']} PACKAGES = ["saltproc"] REQUIRES = ["numpy", - "openmc", + "openmc>=0.13.3", "tables", "networkx", "pydot", From 60032933a2e004915f6d61cd5db75315e42a8e5d Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 20 Apr 2023 15:55:12 -0500 Subject: [PATCH 15/62] fix serpent integration test --- .../integration_tests/run_constant_reprocessing_serpent/test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/integration_tests/run_constant_reprocessing_serpent/test.py b/tests/integration_tests/run_constant_reprocessing_serpent/test.py index 10f2559e6..294a8a694 100644 --- a/tests/integration_tests/run_constant_reprocessing_serpent/test.py +++ b/tests/integration_tests/run_constant_reprocessing_serpent/test.py @@ -96,7 +96,6 @@ def read_nuclide_mass(db_file, version): mass_before = {} mass_after = {} - breakpoint() for nuc, idx in before_nucmap.items(): mass_before[nuc] = np.array([row[idx] for row in fuel_before]) for nuc, idx in after_nucmap.items(): From 0a3112f3916c86b2de69fd749b2e4d883299d867 Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 20 Apr 2023 15:55:37 -0500 Subject: [PATCH 16/62] update test-saltproc workflow --- .github/workflows/test-saltproc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-saltproc.yml b/.github/workflows/test-saltproc.yml index e45d4af29..8e0b082a9 100644 --- a/.github/workflows/test-saltproc.yml +++ b/.github/workflows/test-saltproc.yml @@ -69,4 +69,4 @@ jobs: - name: Test SaltProc run: | - pytest --ignore tests/integration_tests/run_no_reprocessing_serpent --ignore tests/integration_tests/run_no_reprocessing_openmc --ignore tests/integration_tests/run_constant_reprocessing_serpent --ignore tests/integration_tests/run_constant_reprocessing_openmc tests/ + pytest --ignore tests/integration_tests/run_no_reprocessing_serpent --ignore tests/integration_tests/run_constant_reprocessing_serpent tests/ From a9d581b92bd91b157006e87d0904e66995aec685 Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 20 Apr 2023 16:06:59 -0500 Subject: [PATCH 17/62] fix test-saltproc --- .github/workflows/test-saltproc.yml | 1 + environment.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-saltproc.yml b/.github/workflows/test-saltproc.yml index 8e0b082a9..0a5b9cd50 100644 --- a/.github/workflows/test-saltproc.yml +++ b/.github/workflows/test-saltproc.yml @@ -32,6 +32,7 @@ jobs: with: miniforge-variant: Mambaforge # mamba is faster than base conda miniforge-version: latest + channels: conda-forge activate-environment: saltproc-env use-mamba: true use-only-tar-bz2: true diff --git a/environment.yml b/environment.yml index 5eeaeb3d9..aac3912f5 100644 --- a/environment.yml +++ b/environment.yml @@ -4,7 +4,7 @@ channels: - defaults dependencies: - numpy - - openmc>=0.13.3 + - openmc==0.13.3 - pytables - networkx - pydot From 0b72f81b1471ddcfd4b7028c7fbf354779d091b2 Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 20 Apr 2023 16:14:26 -0500 Subject: [PATCH 18/62] Revert "remove source install of openmc from workflows" This reverts commit f399936520ba66c5ca5b25b380e520ddae1073f1. --- .github/workflows/cache-dependencies.yml | 45 ++++++++++++++++++++ .github/workflows/test-saltproc.yml | 34 ++++++++++++++- tools/ci/build-openmc.sh | 54 ++++++++++++++++++++++++ tools/ci/restore-openmc.sh | 30 +++++++++++++ 4 files changed, 162 insertions(+), 1 deletion(-) create mode 100755 tools/ci/build-openmc.sh create mode 100755 tools/ci/restore-openmc.sh diff --git a/.github/workflows/cache-dependencies.yml b/.github/workflows/cache-dependencies.yml index 9752a6165..741618029 100644 --- a/.github/workflows/cache-dependencies.yml +++ b/.github/workflows/cache-dependencies.yml @@ -17,6 +17,15 @@ jobs: run: shell: bash -l {0} + env: + MPI: no + OMP: no + PHDF5: no + DAGMC: no + EVENT: no + VECTFIT: no + LIBMESH: no + steps: - uses: actions/checkout@v3 @@ -42,6 +51,7 @@ jobs: with: path: | /usr/share/miniconda3/envs/saltproc-env + ~/openmc_src ~/endfb71_hdf5 ~/.cache/pip key: depcache-${{ hashFiles('environment.yml') }}-${{ env.DATE }}-${{ env.CACHE_NUMBER }} @@ -55,6 +65,27 @@ jobs: if: steps.dependencies-cache.outputs.cache-hit != 'true' run: $GITHUB_WORKSPACE/scripts/ci/openmc-xs.bash + - name: OpenMC dependencies + run: | + sudo apt -y update + sudo apt install -y libhdf5-dev + + - name: Download OpenMC + if: steps.dependencies-cache.outputs.cache-hit != 'true' + uses: actions/checkout@v3 + with: + repository: openmc-dev/openmc + path: openmc + submodules: recursive + + - name: Build OpenMC from source if no cache if found + if: steps.dependencies-cache.outputs.cache-hit != 'true' + run: $GITHUB_WORKSPACE/tools/ci/build-openmc.sh + + - name: Restore OpenMC source build from cache + if: steps.dependencies-cache.outputs.cache-hit == 'true' + run: $GITHUB_WORKSPACE/tools/ci/restore-openmc.sh + - name: Install SaltProc run: pip install . @@ -99,6 +130,20 @@ jobs: run: mamba env update -n saltproc-doc-env -f doc/doc-environment.yml if: steps.dependencies-cache.outputs.cache-hit != 'true' + - name: Download OpenMC + if: steps.dependencies-cache.outputs.cache-hit != 'true' + uses: actions/checkout@v3 + with: + repository: openmc-dev/openmc + path: openmc + + - name: Build OpenMC API + if: steps.dependencies-cache.outputs.cache-hit != 'true' + run: | + cd openmc + pip install . + cd ../ + - name: Install SaltProc run: pip install . diff --git a/.github/workflows/test-saltproc.yml b/.github/workflows/test-saltproc.yml index 0a5b9cd50..195fe7fdf 100644 --- a/.github/workflows/test-saltproc.yml +++ b/.github/workflows/test-saltproc.yml @@ -14,7 +14,7 @@ on: workflow_dispatch: env: - CACHE_NUMBER: 0 #change to manually reset cache + CACHE_NUMBER: 6 #change to manually reset cache jobs: test-saltproc: @@ -23,6 +23,15 @@ jobs: run: shell: bash -l {0} + env: + MPI: no + OMP: no + PHDF5: no + DAGMC: no + EVENT: no + VECTFIT: no + LIBMESH: no + steps: - uses: actions/checkout@v3 @@ -48,6 +57,8 @@ jobs: with: path: | /usr/share/miniconda3/envs/saltproc-env + ~/openmc_src + ~/mcpl_src ~/endfb71_hdf5 ~/.cache/pip key: depcache-${{ hashFiles('environment.yml') }}-${{ env.DATE }}-${{ env.CACHE_NUMBER }} @@ -61,6 +72,27 @@ jobs: if: steps.dependencies-cache.outputs.cache-hit != 'true' run: $GITHUB_WORKSPACE/scripts/ci/openmc-xs.bash + - name: OpenMC dependencies + run: | + sudo apt -y update + sudo apt install -y libhdf5-dev + + - name: Download OpenMC + if: steps.dependencies-cache.outputs.cache-hit != 'true' + uses: actions/checkout@v3 + with: + repository: openmc-dev/openmc + path: openmc + submodules: recursive + + - name: Build OpenMC from source if no cache is found + if: steps.dependencies-cache.outputs.cache-hit != 'true' + run: $GITHUB_WORKSPACE/tools/ci/build-openmc.sh + + - name: Restore OpenMC source build from cache + if: steps.dependencies-cache.outputs.cache-hit == 'true' + run: $GITHUB_WORKSPACE/tools/ci/restore-openmc.sh + - name: Install SaltProc run: pip install . diff --git a/tools/ci/build-openmc.sh b/tools/ci/build-openmc.sh new file mode 100755 index 000000000..c042e2594 --- /dev/null +++ b/tools/ci/build-openmc.sh @@ -0,0 +1,54 @@ +#!/bin/bash +set -ex + +# Build openmc +cd openmc +./tools/ci/gha-install-mcpl.sh +python tools/ci/gha-install.py + +# Create the caching folder +DIRS=(openmc_src mcpl_src) +for DIR in ${DIRS[@]}; do + mkdir $DIR + mkdir $DIR/bin + mkdir $DIR/lib + mkdir $DIR/share + mkdir $DIR/include +done + +# Copy libraries to caching folder +cp /usr/local/bin/openmc openmc_src/bin/. +cp /usr/local/lib/libopenmc.so openmc_src/lib/. +cp -r /usr/local/lib/cmake openmc_src/lib/. +cp /usr/local/lib/libpugixml.a openmc_src/lib/. +cp -r /usr/local/lib/pkgconfig openmc_src/lib/. +#cp -r /usr/local/share/openmc openmc_src/share/. +#cp -r /usr/local/share/man openmc_src/share/. +cp -r /usr/local/include/openmc openmc_src/include/. +cp /usr/local/include/pugiconfig.hpp openmc_src/include/. +cp /usr/local/include/pugixml.hpp openmc_src/include/. +INCLUDES=(fmt xtl xtensor gsl gsl-lite openmc) +for I in ${INCLUDES[@]}; do + cp -r /usr/local/include/$I openmc_src/include/. +done + +# MCPL stuff +cp /usr/local/lib/libmcpl.so mcpl_src/lib/. +cp /usr/local/include/mcpl.h mcpl_src/include/. +cp /usr/local/lib/libsswmcpl.so mcpl_src/lib/. +cp /usr/local/lib/libphitsmcpl.so mcpl_src/lib/. +cp -r /usr/local/share/MCPL mcpl_src/share/. + +MCPL_BINARIES=(pymcpltool mcpl-config mcpl2ssw ssw2mcpl mcpl2phits phits2mcpl mcpltool) +for BINARY in ${MCPL_BINARIES[@]}; do + cp /usr/local/bin/$BINARY mcpl_src/bin/. +done + + +# Move the caching folders to $HOME +mv openmc_src $HOME/openmc_src +mv mcpl_src $HOME/mcpl_src + +# Install the OpenMC python API +pip install . +cd ../ diff --git a/tools/ci/restore-openmc.sh b/tools/ci/restore-openmc.sh new file mode 100755 index 000000000..35fb60ab1 --- /dev/null +++ b/tools/ci/restore-openmc.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -ex + +# Move cached OpenMC libaries to PATH +sudo mv $HOME/openmc_src/bin/openmc /usr/local/bin/openmc +OPENMC_LIBS=(libopenmc.so cmake libpugixml.a pkgconfig) +for LIB in ${OPENMC_LIBS[@]}; do + sudo mv $HOME/openmc_src/lib/$LIB /usr/local/lib/. +done + +sudo mv $HOME/openmc_src/lib/ /usr/local/lib/ +#sudo mv $HOME/openmc_src/share/openmc /usr/local/share/openmc +#sudo mv $HOME/openmc_src/share/man /usr/local/share/man +INCLUDES=(fmt xtl xtensor gsl gsl-lite openmc pugixml.hpp pugiconfig.hpp) +for I in ${INCLUDES[@]}; do + sudo mv $HOME/openmc_src/include/$I /usr/local/include/$I +done + +# Move MCPL stuff +MCPL_BINARIES=(pymcpltool mcpl-config mcpltool mcpl2ssw ssw2mcpl mcpl2phits phits2mcpl) +for BINARY in ${MCPL_BINARIES[@]}; do + sudo mv $HOME/mcpl_src/bin/$BINARY /usr/local/bin/. +done + +MCPL_LIBS=(libsswmcpl.so libphitsmcpl.so libmcpl.so) +for LIB in ${MCPL_LIBS[@]}; do + sudo mv $HOME/mcpl_src/lib/$LIB /usr/local/lib/. +done +sudo mv $HOME/mcpl_src/include/mcpl.h /usr/local/include/. +sudo mv $HOME/mcpl_src/share/MCPL /usr/local/share/. From e5dd0e50153dc6380333bdf6e1acf6e8559434ce Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 20 Apr 2023 16:15:26 -0500 Subject: [PATCH 19/62] remove openmc from environment.yml --- environment.yml | 1 - requirements.txt | 2 +- saltproc/version.py | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/environment.yml b/environment.yml index aac3912f5..43a6e84cd 100644 --- a/environment.yml +++ b/environment.yml @@ -4,7 +4,6 @@ channels: - defaults dependencies: - numpy - - openmc==0.13.3 - pytables - networkx - pydot diff --git a/requirements.txt b/requirements.txt index dcd7156d5..60e68107a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy scipy json jsonschema -openmc >= 0.13.3 +openmc pytables networkx pydot diff --git a/saltproc/version.py b/saltproc/version.py index ba57da519..f0e9b63f7 100644 --- a/saltproc/version.py +++ b/saltproc/version.py @@ -89,7 +89,7 @@ './input_schema.json']} PACKAGES = ["saltproc"] REQUIRES = ["numpy", - "openmc>=0.13.3", + "openmc", "tables", "networkx", "pydot", From f54ca7b4e7892f2b814ddaf32069a9d59c95af13 Mon Sep 17 00:00:00 2001 From: yardasol Date: Fri, 21 Apr 2023 13:07:16 -0500 Subject: [PATCH 20/62] fix cache-dependencies --- .github/workflows/cache-dependencies.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cache-dependencies.yml b/.github/workflows/cache-dependencies.yml index 741618029..08c2ee96d 100644 --- a/.github/workflows/cache-dependencies.yml +++ b/.github/workflows/cache-dependencies.yml @@ -144,7 +144,7 @@ jobs: pip install . cd ../ - - name: Install SaltProc + - name: Install SaltProc run: pip install . - name: Check packages From bca2abf4c4b19355d1f590ad293ac7b67515317b Mon Sep 17 00:00:00 2001 From: yardasol Date: Wed, 26 Apr 2023 11:47:38 -0500 Subject: [PATCH 21/62] remove integration tests from workflow --- .github/workflows/test-saltproc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-saltproc.yml b/.github/workflows/test-saltproc.yml index 195fe7fdf..446af254f 100644 --- a/.github/workflows/test-saltproc.yml +++ b/.github/workflows/test-saltproc.yml @@ -102,4 +102,4 @@ jobs: - name: Test SaltProc run: | - pytest --ignore tests/integration_tests/run_no_reprocessing_serpent --ignore tests/integration_tests/run_constant_reprocessing_serpent tests/ + pytest --ignore tests/integration_tests/run_no_reprocessing_serpent --ignore tests/integration_tests/run_no_reprocessing_openmc --ignore tests/integration_tests/run_constant_reprocessing_serpent --ignore tests/integration_tests/run_constant_reprocessing_openmc tests/ From 79b0c833177703f9adcb1a35d526ccccb034eb13 Mon Sep 17 00:00:00 2001 From: yardasol Date: Wed, 26 Apr 2023 12:07:09 -0500 Subject: [PATCH 22/62] remove PyNE from the docs --- doc/index.rst | 4 ++-- doc/installation.rst | 40 +++++++++++++++------------------------- doc/overview.rst | 2 +- 3 files changed, 18 insertions(+), 28 deletions(-) diff --git a/doc/index.rst b/doc/index.rst index 78aeb04c0..cb66568e0 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -11,10 +11,10 @@ calculations. It couples directly with depletion-capable transport solvers to en calculations. **SaltProc** welcomes your contributions. It already relies on many libraries -in the Scientific Python ecosystem including `pyne`_, `numpy`_, `matplotlib`_, +in the Scientific Python ecosystem including `openmc`_, `numpy`_, `matplotlib`_, `networkx`_, and `pydot`_. -.. _pyne: http://pyne.io/ +.. _openmc: http://openmc.org/ .. _numpy: http://numpy.org .. _matplotlib: http://matplotlib.org .. _networkx: http://networkx.github.io diff --git a/doc/installation.rst b/doc/installation.rst index 33dbf564e..177cc0062 100644 --- a/doc/installation.rst +++ b/doc/installation.rst @@ -3,24 +3,24 @@ Installation SaltProc has the following dependencies: - #. `Python`_ (>=3.5) - #. `Serpent`_ (>=2.1.31) - #. `PyNE`_ (>=0.5.11) - #. `OpenMC`_ (>=0.13.0) - #. `NumPy`_ (>=1.14.0) + #. `python`_ (>=3.5) + #. `serpent`_ (>=2.1.31) + #. `serpentTools`_ + #. `openmc`_ (>=0.13.0) + #. `numpy`_ (>=1.14.0) #. `PyTables`_ - #. `NetworkX`_ - #. `PyDotPlus`_ + #. `networkx`_ + #. `pydot`_ #. `jsonschema`_ -.. _Serpent: http://montecarlo.vtt.fi -.. _PyNE: http://pyne.io -.. _OpenMC: https://openmc.org/ -.. _Python: http://python.org -.. _NumPy: http://numpy.org +.. _serpent: http://montecarlo.vtt.fi +.. _serpentTools: https://serpent-tools.readthedocs.io/en/master/index.html +.. _openmc: https://openmc.org/ +.. _python: http://python.org +.. _numpy: http://numpy.org .. _PyTables: http://pytables.org -.. _NetworkX: http://networkx.github.io -.. _PyDotPlus: https://pydotplus.readthedocs.io/ +.. _networkx: http://networkx.github.io +.. _pydot: https://github.com/pydot/pydot .. _pytest: https://docs.pytest.org .. _pytest documentation: https://docs.pytest.org/en/latest/how-to/usage.html .. _sphinx: https://www.sphinx-doc.org @@ -36,7 +36,6 @@ Optional Dependencies: #. `pytest`_ (for testing) #. `sphinx`_ and `sphinx-rtd-theme`_ (for building documentation) #. `matplotlib`_ - #. `ViTables`_ @@ -46,18 +45,9 @@ Clone the source from the SaltProc repository from `GitHub`_. git clone git@github.com:arfc/saltproc.git -Note on installing OpenMC -------------------------- -The ``conda-forge`` build of OpenMC 0.13.0 cannot be installed alongside the ``conda-forge`` build of PyNE due to a conflict in the pinned HDF5 versions required by those builds. Since both are dependencies, users will need to pick one to install from source. We recommend users install OpenMC from source as it has a more active community and a step-by-step guide on how to install it from source on most machines. For Ubuntu users, consider using the `ubuntu-nuclear-software-installer`_ -script to install OpenMC from source. - -.. _ubuntu-nuclear-software-installer: https://github.com/yardasol/ubuntu-nuclear-software-installer - -Otherwise, all of the dependencies are readily available through the `conda package manager`_. - .. note:: We recommend using the `mamba`_ CLI tool to install packages quickly. SaltProc has a compltex package dependency structure which can result is long environment solve times in the default ``conda`` solver. ``mamba`` is a reimplementation of ``conda`` in ``C++`` and we have found it is significantly faster. -You can download the required ones using ``conda`` on the provided ``environment.yml`` +You can download the required packages using ``conda`` on the provided ``environment.yml`` file in the repository: .. code-block:: bash diff --git a/doc/overview.rst b/doc/overview.rst index 0a0ed3124..a194a2b4a 100644 --- a/doc/overview.rst +++ b/doc/overview.rst @@ -44,7 +44,7 @@ Molten Salt Reactors. It performs following major functions: The code logic flow is the following: 1. Runs the transport-depletion code (:meth:`saltproc.depcode.Depcode.run_depcode()`) - 2. Parses through the output `*_dep.m` file and creates PyNE Material object + 2. Parses through the output `*_dep.m` file and creates Materialflow object for each burnable material. 3. Processes Fuel (:meth:`saltproc.app.reprocess_materials()` and :meth:`saltproc.app.refill_materials()`): From 2fda80467bd4718aba97387c4c261eae766c98b2 Mon Sep 17 00:00:00 2001 From: yardasol Date: Wed, 3 May 2023 16:01:02 -0500 Subject: [PATCH 23/62] let openmc run when using mpi --- saltproc/depcode.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/saltproc/depcode.py b/saltproc/depcode.py index 3351af634..9dad78e32 100644 --- a/saltproc/depcode.py +++ b/saltproc/depcode.py @@ -3,6 +3,14 @@ from abc import ABC, abstractmethod +try: + from mpi4py import MPI + import os + MPI_ON = True +except ImportError: + MPI_ON = False + + class Depcode(ABC): """Abstract interface for running depletion steps. @@ -116,16 +124,17 @@ def run_depletion_step(self, mpi_args, args): print('Running %s' % (self.codename)) try: - if mpi_args is None: - stdout = sys.stdout + if MPI_ON: + env = os.environ else: - stdout = None + env = None subprocess.run( args, check=True, cwd=self.output_path, - stdout=stdout, - stderr=subprocess.STDOUT) + stdout=sys.stdout, + stderr=subprocess.STDOUT, + env=None) print(f'Finished {self.codename.upper()} Run') except subprocess.CalledProcessError as error: print(error.output.decode("utf-8")) From aee2d44c88e720607a0cddb7f8fab4fd29183812 Mon Sep 17 00:00:00 2001 From: yardasol Date: Mon, 8 May 2023 14:00:11 -0500 Subject: [PATCH 24/62] address Luke's comments --- saltproc/materialflow.py | 12 ++----- saltproc/openmc_depcode.py | 34 +++---------------- saltproc/process.py | 20 +++++++---- saltproc/serpent_depcode.py | 1 - saltproc/simulation.py | 17 +--------- .../file_interface_openmc/test.py | 3 -- .../run_constant_reprocessing_openmc/test.py | 1 - .../run_constant_reprocessing_serpent/test.py | 1 - tests/unit_tests/test_app.py | 2 +- 9 files changed, 22 insertions(+), 69 deletions(-) diff --git a/saltproc/materialflow.py b/saltproc/materialflow.py index 0a920669a..e5e1238a2 100644 --- a/saltproc/materialflow.py +++ b/saltproc/materialflow.py @@ -78,9 +78,7 @@ def replace_components(self, comp, comp_is_density=False): nucs = np.array(list(comp.keys())) nonzeros = np.array(list(comp.values())) - #nucs = nucs[nonzeros != 0.0] if len(nucs) > 0: - #nonzeros = nonzeros[nonzeros != 0.0] comp = dict(zip(nucs, nonzeros)) super().add_components(comp, percent_type='wo') density = self.get_density() @@ -144,7 +142,6 @@ def scale_matflow(self, f=1.0): The keys are preserved from PyNE Material (integers representing nuclides in id-form). ``value`` - Each nuclide's mass fraction, multiplied by factor f. """ @@ -181,9 +178,8 @@ def __deepcopy__(self, memo): def __eq__(self, other): """Overrides Python ``=`` operation to compare two Materialflow - objects. Compares objects total mass, density, atoms_per_molecule, - temperature, mass flowrate, and masses of important isotopes: - uranium-235 and uranium-238. + objects. Compares objects total mass, volume temperature, + and mass flowrate. Parameters ---------- @@ -206,9 +202,6 @@ def __eq__(self, other): and self.volume == other.volume \ and self.temperature == other.temperature \ and self.mass_flowrate == other.mass_flowrate - #if value: - # fast comparision of dicts - # ... return value @@ -231,7 +224,6 @@ def __add__(x, y): Materialflow which is a sum of isotope masses from `x` and `y`. """ - # REFACTOR TO RELFECT NO PYNE if x.mass == 0.0 or x.volume == 0.0 and y.mass != 0.0 and y.volume != 0.0: return y elif y.mass == 0.0 or y.volume == 0.0 and x.mass != 0.0 and x.volume != 0.0: diff --git a/saltproc/openmc_depcode.py b/saltproc/openmc_depcode.py index f85726d41..1e9bed28a 100644 --- a/saltproc/openmc_depcode.py +++ b/saltproc/openmc_depcode.py @@ -331,33 +331,9 @@ def _create_mass_percents_dictionary(self, mat, percent_type='ao'): mass_percents = percents else: raise ValueError(f'{percent_type} is not a valid percent type') - #PyNE - #pyne_nucs = list(map(self._convert_nucname_to_pyne, nucs)) - #PyNE - #return dict(zip(pyne_nucs, mass_percents)) return dict(zip(nucs, mass_percents)) - #PyNE - def _convert_nucname_to_pyne(self, nucname): - """Helper function for :func:`_create_mass_percents_dictionary`. - Converts an OpenMC-formatted nuclide name into a PyNE-formatted - nuclide name. - - Parameters - ---------- - nucname : str - - Returns - ------- - pyne_nucname : str - - """ - if nucname[-3:-1] == '_m': - nucname = nucname.split('_')[0] - nucname += 'M' - return nucname - def _get_power_from_tallies(self, sp, power): fission_energy = sp.get_tally(name='fission_energy').mean.flatten()[0] # eV / src heating = sp.get_tally(name='heating').mean.flatten()[0] # eV / src @@ -388,15 +364,15 @@ def run_depletion_step(self, mpi_args=None, threads=None): """ # need to add flow control for plots option args = ['python', - self.exec_path, + str(self.exec_path), '--materials', - self.runtime_matfile, + str(self.runtime_matfile), '--geometry', - self.runtime_inputfile['geometry'], + str(self.runtime_inputfile['geometry']), '--settings', - self.runtime_inputfile['settings'], + str(self.runtime_inputfile['settings']), '--tallies', - self.runtime_inputfile['tallies'], + str(self.runtime_inputfile['tallies']), '--directory', str(self.output_path)] if mpi_args is not None: diff --git a/saltproc/process.py b/saltproc/process.py index 3530d0e4a..d2e7fd9df 100644 --- a/saltproc/process.py +++ b/saltproc/process.py @@ -107,10 +107,13 @@ def process_material(self, inflow): if bool(self.efficiency): process_elements = list(self.efficiency.keys()) - process_nucs = [nuc for nuc in inflow.comp.keys() if re.match(r"([A-Z]+)([0-9]+)", nuc, re.I).groups()[0] in process_elements] + process_nucs = [nuc for nuc in inflow.comp.keys() \ + if re.match(r"([A-Z]+)([0-9]+)", nuc, re.I).groups()[0] \ + in process_elements] thru_nucs = list(set(inflow.comp.keys()).difference(set(process_nucs))) - efficiency = [self.calculate_removal_efficiency(elem) for elem in process_elements] + efficiency = [self.calculate_removal_efficiency(elem) \ + for elem in process_elements] efficiency = dict(zip(process_elements, efficiency)) nuc_efficiency = {} @@ -118,8 +121,12 @@ def process_material(self, inflow): elem = re.match(r"([A-Z]+)([0-9]+)", nuc, re.I).groups()[0] nuc_efficiency[nuc] = efficiency[elem] - thru_mass = np.array([inflow.get_mass(nuc) * (1.0 - nuc_efficiency[nuc]) for nuc in process_nucs]) - waste_mass = np.array([inflow.get_mass(nuc) * nuc_efficiency[nuc] for nuc in process_nucs]) + thru_mass = np.array([inflow.get_mass(nuc) * \ + (1.0 - nuc_efficiency[nuc]) \ + for nuc in process_nucs]) + waste_mass = np.array([inflow.get_mass(nuc) * \ + nuc_efficiency[nuc] \ + for nuc in process_nucs]) total_waste_mass = np.sum(waste_mass) total_thru_mass = inflow.mass - np.sum(waste_mass) @@ -141,16 +148,15 @@ def process_material(self, inflow): waste_stream.mass = total_waste_mass else: waste_stream.volume = 0.0 - #breakpoint() # preserve inflow attributes thru_flow = deepcopy(inflow) thru_flow.replace_components(thru_mass) # initial guess thru_flow.volume = inflow.volume - waste_stream.volume # correction - thru_flow.volume = thru_flow.volume * total_thru_mass / thru_flow.get_mass() + thru_flow.volume = thru_flow.volume * \ + total_thru_mass / thru_flow.get_mass() thru_flow.mass = total_thru_mass - #breakpoint() #thru_flow.mass = float(inflow.mass - waste_stream.mass) #thru_flow.norm_comp() diff --git a/saltproc/serpent_depcode.py b/saltproc/serpent_depcode.py index 53a7386bb..4d40e7a4c 100644 --- a/saltproc/serpent_depcode.py +++ b/saltproc/serpent_depcode.py @@ -211,7 +211,6 @@ def nuclide_code_to_name(self, nuc_code): def _decay_code_to_zam(self, nuc_code): m = int(str(nuc_code)[-1]) nuc_code = int(str(nuc_code)[:-1]) - #nuc_code = floor(nuc_code * 1e-1) Z = floor(nuc_code * 1e-3) a = nuc_code % 1000 return Z, a, m diff --git a/saltproc/simulation.py b/saltproc/simulation.py index 1dbb3f999..7389a6424 100644 --- a/saltproc/simulation.py +++ b/saltproc/simulation.py @@ -121,7 +121,6 @@ def store_after_repr(self, after_mats, waste_dict, dep_step): Current depletion time step. """ - #breakpoint() streams_description = 'in_out_streams' db = tb.open_file( self.db_path, @@ -141,7 +140,6 @@ def store_after_repr(self, after_mats, waste_dict, dep_step): proc_node = db.create_group(waste_group, proc) else: proc_node = getattr(waste_group, proc) - #iso_idx = OrderedDict() nuclide_indices = [] iso_wt_frac = [] coun = 0 @@ -149,7 +147,6 @@ def store_after_repr(self, after_mats, waste_dict, dep_step): # Read isotopes from Materialflow for nuc, wt_frac in waste_dict[material_name][proc].comp.items(): # Dictonary in format {isotope_name : index(int)} - #iso_idx[nuc] = coun nuclide_indices.append((nuc, coun)) # Convert wt% to absolute [user units] iso_wt_frac.append(wt_frac * waste_dict[material_name][proc].mass) @@ -167,7 +164,6 @@ def store_after_repr(self, after_mats, waste_dict, dep_step): title="Isotopic composition for %s" % proc) # Save isotope indexes map and units in EArray attributes earr.flavor = 'python' - #earr.attrs.iso_map = iso_idx if not hasattr(proc_node, 'nuclide_map'): db.create_table(proc_node, 'nuclide_map', @@ -176,7 +172,7 @@ def store_after_repr(self, after_mats, waste_dict, dep_step): earr, iso_wt_frac = self._fix_nuclide_discrepancy(db, earr, nuclide_indices, iso_wt_frac) earr.append(np.asarray([iso_wt_frac], dtype=np.float64)) - del iso_wt_frac + del iso_wt_frac, nuclide_indices # Also save materials AFTER reprocessing and refill here self.store_mat_data(after_mats, dep_step, True) db.close() @@ -211,11 +207,6 @@ def _fix_nuclide_discrepancy(self, db, earr, nuclide_indices, iso_wt_frac): """ parent_node = earr._v_parent - #if isinstance(nuclide_indices, dict): - # base_nucs = set(earr.attrs.iso_map.keys()) - # iso_idx = nuclide_indices - # step_nucs = set(iso_idx.keys()) - #else: base_nucs = set(map(bytes.decode, parent_node.nuclide_map.col('nuclide'))) iso_idx = dict(nuclide_indices) step_nucs = set(iso_idx.keys()) @@ -351,8 +342,6 @@ def store_mat_data(self, mats, dep_step, store_at_end=False): dep_step_str = ["before_reproc", "before"] # Moment when store compositions - #iso_idx = OrderedDict() - # # numpy array row storage data for material physical properties mpar_dtype = np.dtype([ ('mass', float), @@ -367,7 +356,6 @@ def store_mat_data(self, mats, dep_step, store_at_end=False): print( '\nStoring material data for depletion step #%i.' % (dep_step + 1)) - #breakpoint() db = tb.open_file( self.db_path, mode='a', @@ -378,7 +366,6 @@ def store_mat_data(self, mats, dep_step, store_at_end=False): 'Material data') # Iterate over all materials for key, value in mats.items(): - #iso_idx[key] = OrderedDict() nuclide_indices = [] iso_wt_frac = [] coun = 0 @@ -396,7 +383,6 @@ def store_mat_data(self, mats, dep_step, store_at_end=False): # Read isotopes from Materialflow for material for nuc, wt_frac in mats[key].comp.items(): # Dictonary in format {isotope_name : index(int)} - #iso_idx[key][nuc] = coun nuclide_indices.append((nuc, coun)) # Convert wt% to absolute [user units] iso_wt_frac.append(wt_frac * mats[key].mass) @@ -432,7 +418,6 @@ def store_mat_data(self, mats, dep_step, store_at_end=False): title="Isotopic composition for %s" % key) # Save isotope indexes map and units in EArray attributes earr.flavor = 'python' - #earr.attrs.iso_map = iso_idx[key] # Create table for material Parameters print('Creating ' + key + ' lookup table.') db.create_table(comp_pfx, diff --git a/tests/integration_tests/file_interface_openmc/test.py b/tests/integration_tests/file_interface_openmc/test.py index df412403d..14be04681 100644 --- a/tests/integration_tests/file_interface_openmc/test.py +++ b/tests/integration_tests/file_interface_openmc/test.py @@ -78,9 +78,6 @@ def test_update_depletable_materials(setup, openmc_depcode, openmc_reactor): test_material = saltproc.Materialflow(comp=comp, density=material.get_mass_density(), volume=material.volume) - #test_material.set_density('g/cm3', material.get_mass_density()) - #test_material.mass = material.density * material.volume - #test_material.volume = material.volume for key in test_material.comp.keys(): np.testing.assert_almost_equal(ref_material.comp[key], test_material.comp[key]) diff --git a/tests/integration_tests/run_constant_reprocessing_openmc/test.py b/tests/integration_tests/run_constant_reprocessing_openmc/test.py index 9cce67fbd..68e066814 100644 --- a/tests/integration_tests/run_constant_reprocessing_openmc/test.py +++ b/tests/integration_tests/run_constant_reprocessing_openmc/test.py @@ -156,7 +156,6 @@ def read_fuel(file): db = tb.open_file(file, mode='r') fuel = db.root.materials.fuel out_data = {} - out_data = {} for node in db.walk_nodes(fuel, classname="EArray"): nucmap = _create_nuclide_map(node._v_parent) if node._v_name == 'comp': diff --git a/tests/integration_tests/run_constant_reprocessing_serpent/test.py b/tests/integration_tests/run_constant_reprocessing_serpent/test.py index 294a8a694..f72e76c8c 100644 --- a/tests/integration_tests/run_constant_reprocessing_serpent/test.py +++ b/tests/integration_tests/run_constant_reprocessing_serpent/test.py @@ -192,7 +192,6 @@ def read_fuel(file, version): else: node_name = node._v_name out_data[node_name] = {} - # print(node) for nuc, idx in nucmap.items(): out_data[node_name][nuc] = \ np.array([row[idx] for row in node]) diff --git a/tests/unit_tests/test_app.py b/tests/unit_tests/test_app.py index da8544edd..a912d19b3 100644 --- a/tests/unit_tests/test_app.py +++ b/tests/unit_tests/test_app.py @@ -203,7 +203,7 @@ def test_get_extraction_processes(proc_test_file): def test_get_feeds(proc_test_file): feeds = get_feeds(proc_test_file) np.testing.assert_almost_equal(feeds['fuel']['leu'].mass, 4.9602E+8) - assert feeds['fuel']['leu'].density == 4.9602 + np.testing.assert_almost_equal(feeds['fuel']['leu'].density,4.9602) np.testing.assert_almost_equal(feeds['fuel']['leu'].comp['U235'] * feeds['fuel']['leu'].mass, 15426147.398592) np.testing.assert_almost_equal(feeds['fuel']['leu'].comp['U238'] * feeds['fuel']['leu'].mass, From b23d1812bee6d9193d61b9dc8821b9834bac5407 Mon Sep 17 00:00:00 2001 From: Olek <45364492+yardasol@users.noreply.github.com> Date: Mon, 8 May 2023 14:02:02 -0500 Subject: [PATCH 25/62] Apply suggestions from code review Co-authored-by: LukeSeifert <44068471+LukeSeifert@users.noreply.github.com> --- saltproc/process.py | 2 +- saltproc/serpent_depcode.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/saltproc/process.py b/saltproc/process.py index d2e7fd9df..5f17f4fdc 100644 --- a/saltproc/process.py +++ b/saltproc/process.py @@ -129,7 +129,7 @@ def process_material(self, inflow): for nuc in process_nucs]) total_waste_mass = np.sum(waste_mass) - total_thru_mass = inflow.mass - np.sum(waste_mass) + total_thru_mass = inflow.mass - total_waste_mass waste_mass = dict(zip(process_nucs, waste_mass / total_waste_mass)) diff --git a/saltproc/serpent_depcode.py b/saltproc/serpent_depcode.py index 4d40e7a4c..9be55031b 100644 --- a/saltproc/serpent_depcode.py +++ b/saltproc/serpent_depcode.py @@ -298,7 +298,7 @@ def resolve_include_paths(self, lines): absolute paths. Parameters - -self._--------- + ---------- lines : list of str Serpent2 runtime input file. From 9cb5eaff4741c91bf17633aa9a768a06203a831f Mon Sep 17 00:00:00 2001 From: yardasol Date: Mon, 8 May 2023 14:32:30 -0500 Subject: [PATCH 26/62] fix openmc_depcode unit test --- tests/unit_tests/test_openmc_depcode.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/unit_tests/test_openmc_depcode.py b/tests/unit_tests/test_openmc_depcode.py index 676329f1d..6da4ca6fb 100644 --- a/tests/unit_tests/test_openmc_depcode.py +++ b/tests/unit_tests/test_openmc_depcode.py @@ -52,17 +52,16 @@ def test_create_mass_percents_dictionary(cwd, openmc_depcode): for nuc, pt, tp in wo_material.nuclides: nucs.append(nuc) mass_percents.append(pt) - nucnames = list(map(openmc_depcode._convert_nucname_to_pyne, nucs)) - wo_ref_dictionary = dict(zip(nucnames, mass_percents)) + wo_ref_dictionary = dict(zip(nucs, mass_percents)) for key in wo_ref_dictionary.keys(): np.testing.assert_almost_equal(wo_ref_dictionary[key], wo_test_dictionary_1[key], decimal=5) np.testing.assert_almost_equal(wo_ref_dictionary[key], wo_test_dictionary_2[key], decimal=5) -def test_convert_nucname_to_pyne(openmc_depcode): - assert openmc_depcode._convert_nucname_to_pyne('H1') == 'H1' - assert openmc_depcode._convert_nucname_to_pyne('U238') == 'U238' - assert openmc_depcode._convert_nucname_to_pyne('Ag110_m1') == 'Ag110M' - assert openmc_depcode._convert_nucname_to_pyne('Am242') == 'Am242' - assert openmc_depcode._convert_nucname_to_pyne('Am242_m1') == 'Am242M' +def test_name_to_nuclide_code(openmc_depcode): + assert openmc_depcode.name_to_nuclide_code('H1') == 1001 + assert openmc_depcode.name_to_nuclide_code('U238') == 92238 + assert openmc_depcode.name_to_nuclide_code('Ag110_m1') == 47510 + assert openmc_depcode.name_to_nuclide_code('Am242') == 95242 + assert openmc_depcode.name_to_nuclide_code('Am242_m1') == 95642 From fd7f969e079cb1f7ca58f8772dd4e96a45c1dfa2 Mon Sep 17 00:00:00 2001 From: yardasol Date: Mon, 8 May 2023 14:41:45 -0500 Subject: [PATCH 27/62] dilute updated depletable materials --- saltproc/openmc_depcode.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/saltproc/openmc_depcode.py b/saltproc/openmc_depcode.py index 1e9bed28a..70ca425f7 100644 --- a/saltproc/openmc_depcode.py +++ b/saltproc/openmc_depcode.py @@ -513,7 +513,15 @@ def update_depletable_materials(self, mats, dep_end_time): material.remove_element(element) material.add_components(components, percent_type='wo') - runtime_materials.export_to_xml(path=self.runtime_matfile) + geometry = openmc.Geometry.from_xml(self.runtime_inputfile['geometry']) + settings = openmc.Settings.from_xml(self.runtime_inputfile['settings']) + diluted_model = openmc.Model(materials=runtime_materials, geometry=geometry, settings=settings) + reactions, diluted_materials = MicroXS._add_dilute_nuclides(self.chain_file_path, + diluted_model, + 1e3) + + diluted_materials.export_to_xml(path=self.runtime_matfile) + #runtime_materials.export_to_xml(path=self.runtime_matfile) del runtime_materials del material From 9bd2e7ed3f4cee7104d1f1874a5bec1e8defedc5 Mon Sep 17 00:00:00 2001 From: yardasol Date: Mon, 8 May 2023 14:50:03 -0500 Subject: [PATCH 28/62] fix parallelism --- saltproc/depcode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/saltproc/depcode.py b/saltproc/depcode.py index 9dad78e32..db4a2e7a1 100644 --- a/saltproc/depcode.py +++ b/saltproc/depcode.py @@ -134,7 +134,7 @@ def run_depletion_step(self, mpi_args, args): cwd=self.output_path, stdout=sys.stdout, stderr=subprocess.STDOUT, - env=None) + env=env) print(f'Finished {self.codename.upper()} Run') except subprocess.CalledProcessError as error: print(error.output.decode("utf-8")) From 9636253935da637ceac9b75d173aff73830c39ed Mon Sep 17 00:00:00 2001 From: yardasol Date: Tue, 9 May 2023 11:39:57 -0500 Subject: [PATCH 29/62] fix serpent no_reprocessing test --- .../run_no_reprocessing_serpent/test_serpent.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/integration_tests/run_no_reprocessing_serpent/test_serpent.py b/tests/integration_tests/run_no_reprocessing_serpent/test_serpent.py index 5f81db156..2f326fef3 100644 --- a/tests/integration_tests/run_no_reprocessing_serpent/test_serpent.py +++ b/tests/integration_tests/run_no_reprocessing_serpent/test_serpent.py @@ -5,7 +5,7 @@ import numpy as np import pytest -from pyne import serpent +import serpentTools from saltproc import app @@ -32,13 +32,13 @@ def test_integration_2step_saltproc_no_reproc_heavy(setup): runsim_no_reproc(simulation, reactor, 2) output_path = str(simulation.sim_depcode.output_path) - ref_result = serpent.parse_dep(cwd + '/reference_dep.m', make_mats=False) - test_result = serpent.parse_dep(f'{output_path}/runtime_input.serpent_dep.m', make_mats=False) + ref_result = serpentTools.read(cwd + '/reference_dep.m') + test_result = serpentTools.read(f'{output_path}/runtime_input.serpent_dep.m') ref_mdens_error = np.loadtxt(cwd + '/reference_error') - ref_fuel_mdens = ref_result['MAT_fuel_MDENS'][:, -2] - test_fuel_mdens = test_result['MAT_fuel_MDENS'][:, -1] + ref_fuel_mdens = ref_result.materials['fuel'].mdens[:, -2] + test_fuel_mdens = test_result.materials['fuel'].mdens[:, -1] test_mdens_error = np.array(ref_fuel_mdens - test_fuel_mdens) np.testing.assert_array_almost_equal(test_mdens_error, ref_mdens_error) From 034462fd01823e88eb51167e18a0e860af9e49c7 Mon Sep 17 00:00:00 2001 From: yardasol Date: Tue, 9 May 2023 11:39:59 -0500 Subject: [PATCH 30/62] Revert "dilute updated depletable materials" This reverts commit fd7f969e079cb1f7ca58f8772dd4e96a45c1dfa2. --- saltproc/openmc_depcode.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/saltproc/openmc_depcode.py b/saltproc/openmc_depcode.py index 70ca425f7..1e9bed28a 100644 --- a/saltproc/openmc_depcode.py +++ b/saltproc/openmc_depcode.py @@ -513,15 +513,7 @@ def update_depletable_materials(self, mats, dep_end_time): material.remove_element(element) material.add_components(components, percent_type='wo') - geometry = openmc.Geometry.from_xml(self.runtime_inputfile['geometry']) - settings = openmc.Settings.from_xml(self.runtime_inputfile['settings']) - diluted_model = openmc.Model(materials=runtime_materials, geometry=geometry, settings=settings) - reactions, diluted_materials = MicroXS._add_dilute_nuclides(self.chain_file_path, - diluted_model, - 1e3) - - diluted_materials.export_to_xml(path=self.runtime_matfile) - #runtime_materials.export_to_xml(path=self.runtime_matfile) + runtime_materials.export_to_xml(path=self.runtime_matfile) del runtime_materials del material From 2f11231f41197efca9e28fbb634bb2a91d9b92d4 Mon Sep 17 00:00:00 2001 From: yardasol Date: Tue, 9 May 2023 14:31:17 -0500 Subject: [PATCH 31/62] fix zero valued compositions at beginning of second depletion step --- saltproc/openmc_depcode.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/saltproc/openmc_depcode.py b/saltproc/openmc_depcode.py index 1e9bed28a..8d24b068b 100644 --- a/saltproc/openmc_depcode.py +++ b/saltproc/openmc_depcode.py @@ -505,8 +505,8 @@ def update_depletable_materials(self, mats, dep_end_time): if material.name in mats.keys(): components = {} for nuc_name, mass_fraction in mats[material.name].comp.items(): - components[nuc_name] = mass_fraction - + if not(mass_fraction == 0.0 or mass_fraction == 0): + components[nuc_name] = mass_fraction material.set_density('g/cm3', mats[material.name].density) material.volume = mats[material.name].volume for element in material.get_elements(): From a1b22e25fce89b5debdd541943e05137617642ba Mon Sep 17 00:00:00 2001 From: yardasol Date: Mon, 15 May 2023 16:02:21 -0500 Subject: [PATCH 32/62] add results.py; fix nuclided result indexing --- saltproc/__init__.py | 1 + saltproc/app.py | 16 +++-- saltproc/depcode.py | 21 +++++++ saltproc/input_schema.json | 5 ++ saltproc/results.py | 118 +++++++++++++++++++++++++++++++++++++ saltproc/simulation.py | 8 ++- 6 files changed, 163 insertions(+), 6 deletions(-) create mode 100644 saltproc/results.py diff --git a/saltproc/__init__.py b/saltproc/__init__.py index cae17b839..90e03a98d 100644 --- a/saltproc/__init__.py +++ b/saltproc/__init__.py @@ -14,3 +14,4 @@ from .reactor import * from .sparger import * from .separator import * +from .results import * diff --git a/saltproc/app.py b/saltproc/app.py index 70138be62..644bdbf2f 100644 --- a/saltproc/app.py +++ b/saltproc/app.py @@ -35,7 +35,7 @@ def run(): """ Inititializes main run""" threads, saltproc_input = parse_arguments() - input_path, process_file, dot_file, mpi_args, object_input = \ + input_path, process_file, dot_file, mpi_args, rebuild_saltproc_results, object_input = \ read_main_input(saltproc_input) _print_simulation_input_info(object_input[1], object_input[0]) # Intializing objects @@ -53,7 +53,11 @@ def run(): simulation.sim_depcode.write_runtime_input(msr, step_idx, simulation.restart_flag) - depcode.run_depletion_step(mpi_args, threads) + + if rebuild_saltproc_results: + simulation.sim_depcode.rebuild_simulation_files(step_idx) + else: + depcode.run_depletion_step(mpi_args, threads) if step_idx == 0 and simulation.restart_flag is False: # First step # Read general simulation data which never changes simulation.store_run_init_info() @@ -94,7 +98,8 @@ def run(): depcode.update_depletable_materials(mats, simulation.burn_time) # Preserve depletion and transport result and input files - depcode.preserve_simulation_files(step_idx) + if not rebuild_saltproc_results: + depcode.preserve_simulation_files(step_idx) del mats, waste_streams, waste_and_feed_streams, extracted_mass gc.collect() @@ -197,6 +202,9 @@ def read_main_input(main_inp_file): if not Path(input_parameters['output_path']).exists(): Path(input_parameters['output_path']).mkdir(parents=True) + # Rebuild saltproc results? + rebuild_saltproc_results = input_parameters['rebuild_saltproc_results'] + # Class settings depcode_input = input_parameters['depcode'] simulation_input = input_parameters['simulation'] @@ -246,7 +254,7 @@ def read_main_input(main_inp_file): reactor_input = _process_main_input_reactor_params( reactor_input, n_depletion_steps, depcode_input['codename']) - return input_path, process_file, dot_file, mpi_args, ( + return input_path, process_file, dot_file, mpi_args, rebuild_saltproc_results, ( depcode_input, simulation_input, reactor_input) def _print_simulation_input_info(simulation_input, depcode_input): diff --git a/saltproc/depcode.py b/saltproc/depcode.py index db4a2e7a1..76bce4207 100644 --- a/saltproc/depcode.py +++ b/saltproc/depcode.py @@ -1,5 +1,6 @@ import sys import subprocess +import shutil from abc import ABC, abstractmethod @@ -253,3 +254,23 @@ def preserve_simulation_files(self, step_idx): lines = self.read_plaintext_file(file_path) with open(step_results_dir / fname, 'w') as out_file: out_file.writelines(lines) + + def rebuild_simulation_files(self, step_idx): + """Move simulation input and output files + from unique directory to runtime directory + + Parameters + ---------- + step_idx : int + + """ + step_results_dir = self.output_path / f'step_{step_idx}_data' + + file_path = lambda file : self.output_path / step_results_dir / file + output_paths = list(map(file_path, self._OUTPUTFILE_NAMES)) + input_paths = list(map(file_path, self._INPUTFILE_NAMES)) + for file_path, fname in zip(output_paths, self._OUTPUTFILE_NAMES): + shutil.copy(file_path, (self.output_path / fname)) + + for file_path, fname in zip(input_paths, self._INPUTFILE_NAMES): + shutil.copy(file_path, (self.output_path / fname)) diff --git a/saltproc/input_schema.json b/saltproc/input_schema.json index 9a5ef57f8..07ae4498f 100644 --- a/saltproc/input_schema.json +++ b/saltproc/input_schema.json @@ -30,6 +30,11 @@ "items": { "type": ["string", "integer"]}, "default": null }, + "rebuild_saltproc_results" : { + "description": "Flag to reconstruct the saltproc_results.h5 files from the stepwise depletion simulation results", + "type": "boolean", + "default": false + }, "depcode": { "description": "Depcode class input parameters", "type": "object", diff --git a/saltproc/results.py b/saltproc/results.py new file mode 100644 index 000000000..5e96ef25a --- /dev/null +++ b/saltproc/results.py @@ -0,0 +1,118 @@ +import tables as tb +import numpy as np +import pandas as pd +import uncertainties.unumpy as unp + +class Results(): + """Interface class for reading SaltProc results""" + + def __init__(self, path): + f = tb.open_file(path, mode='r') + root = f.root + sim_params = root.simulation_parameters + self.time_at_eds = sim_params.col('cumulative_time_at_eds') + time_total = [[t1, t2] for (t1, t2) in zip (self.time_at_eds, + self.time_at_eds)] + time_total = np.array(time_total).flatten() + self.time_total = np.append(np.array([0]), time_total) + + self.keff = self._collect_eds_bds_params(sim_params, 'keff', errors=True) + self.fission_mass = self._collect_eds_bds_params(sim_params, 'fission_mass') + self.power_level = sim_params.col('power_level') + self.breeding_ratio = sim_params.col('breeding_ratio') + + # metadata + metadata = f.root.initial_depcode_siminfo + metadata = pd.DataFrame.from_records(metadata[:]).to_dict() + for key, value in metadata.items(): + metadata[key] = value[0] + self.metadata = metadata + + # Materials + materials = root.materials + nuclide_idx, material_compositions, material_parameters, waste_streams = self._collect_material_params(materials) + self.nuclide_idx = nuclide_idx + self.material_compositions = material_compositions + self.material_parameters = material_parameters + self.waste_streams = waste_streams + + def _collect_eds_bds_params(self, sim_params, col, errors=False): + col_eds = sim_params.col(f'{col}_eds').tolist() + col_bds = sim_params.col(f'{col}_bds').tolist() + col = [col_bds[0], col_eds[0]] + for (k1, k2) in zip(col_bds[1:], col_eds[1:]): + col = col + [k1] + col = col + [k2] + col = np.array(col) + if errors == True: + col = unp.uarray(col[:,0], col[:,1]) + return col + + def _collect_material_params(self, materials): + nuclide_idx = {} + material_compositions = {} + material_parameters = {} + waste_streams = {} + for mat_name in materials._v_groups.keys(): + material = materials[mat_name] + + # main material composition + nuclide_idx[mat_name], material_compositions[mat_name] = self._collect_material_comp(material) + + # material parameters + material_parameters[mat_name] = {} + for property_name in material.before_reproc.parameters.colnames: + material_parameters[mat_name][property_name] = \ + self._collect_material_properties(material, property_name) + + # in and out streams + waste_streams[mat_name] = {} + for stream_name in material.in_out_streams._v_groups.keys(): + waste_stream = material.in_out_streams[stream_name] + if len(waste_stream._v_children) > 0: + waste_streams[mat_name][stream_name] = \ + self._collect_waste_streams(waste_stream, stream_name) + + return nuclide_idx, material_compositions, material_parameters, waste_streams + + # MAKE THIS COLLECT IT INTO A TABLE/2D ARRAY + def _collect_material_comp(self, material): + nuc_map = material.before_reproc.nuclide_map + nucs = list(map(bytes.decode, nuc_map.col('nuclide'))) + nuc_map = dict(zip(nucs, nuc_map.col('index'))) + arr_dim = (len(nuc_map), len(material.before_reproc.comp) + \ + len(material.after_reproc.comp)) + material_comp = np.empty(arr_dim) + for nuc in nucs: + nuc_comp_br = material.before_reproc.comp[:, nuc_map[nuc]] + nuc_comp_ar = material.after_reproc.comp[:, nuc_map[nuc]] + nuc_comp_0 = nuc_comp_br.pop(0) + nuc_comp = [] + for c1, c2 in zip(nuc_comp_br, nuc_comp_ar): + nuc_comp = nuc_comp + [c1, c2] + nuc_comp = [nuc_comp_0] + nuc_comp + material_comp[nuc_map[nuc], :] = nuc_comp + return nuc_map, material_comp + + def _collect_material_properties(self, material, col): + col_br = material.before_reproc.parameters.col(col).tolist() + col_ar = material.after_reproc.parameters.col(col).tolist() + col_0 = col_br.pop(0) + col_values = [] + for c1, c2 in zip(col_br, col_ar): + col_values = col_values + [c1, c2] + col_values = [col_0] + col_values + return col_values + + + def _collect_waste_streams(self, waste_stream, stream_name): + nuc_map = waste_stream.nuclide_map + nucs = list(map(bytes.decode, nuc_map.col('nuclide'))) + nuc_map = dict(zip(nucs, nuc_map.col('index'))) + waste_stream_comp = {} + for nuc in nucs: + nuc_comp = waste_stream.comp[:, nuc_map[nuc]] + waste_stream_comp[nuc] = nuc_comp + return waste_stream_comp + + # methods to get timeseries of various values diff --git a/saltproc/simulation.py b/saltproc/simulation.py index 7389a6424..9962af8f8 100644 --- a/saltproc/simulation.py +++ b/saltproc/simulation.py @@ -380,11 +380,15 @@ def store_mat_data(self, mats, dep_step, store_at_end=False): dep_step_str[0], 'Material data {dep_step_str[1]} reprocessing') comp_pfx = '/materials/' + str(key) + '/' + dep_step_str[0] + # Order the nucnames by ZAM + nuclide_codes = list(map(self.sim_depcode.name_to_nuclide_code, mats[key].comp.keys())) + ordered_nucs = [nucname for nuclide_code, nucname in sorted(zip(nuclide_codes,mats[key].comp.keys()))] # Read isotopes from Materialflow for material - for nuc, wt_frac in mats[key].comp.items(): + for nuc in ordered_nucs: + wt_frac = mats[key].comp[nuc] # Dictonary in format {isotope_name : index(int)} nuclide_indices.append((nuc, coun)) - # Convert wt% to absolute [user units] + # Convert wt% to total mass [g] iso_wt_frac.append(wt_frac * mats[key].mass) coun += 1 nuclide_indices_array = np.array(nuclide_indices, From de4e1864f0f46ce99afad0efe768d16ee1f5dbea Mon Sep 17 00:00:00 2001 From: yardasol Date: Mon, 15 May 2023 17:19:14 -0500 Subject: [PATCH 33/62] add option to run saltproc without reprocessing --- saltproc/app.py | 55 +++++++++++--------- saltproc/input_schema.json | 5 ++ saltproc/simulation.py | 103 +++++++++++++++++++------------------ 3 files changed, 88 insertions(+), 75 deletions(-) diff --git a/saltproc/app.py b/saltproc/app.py index 644bdbf2f..b598f19de 100644 --- a/saltproc/app.py +++ b/saltproc/app.py @@ -35,7 +35,8 @@ def run(): """ Inititializes main run""" threads, saltproc_input = parse_arguments() - input_path, process_file, dot_file, mpi_args, rebuild_saltproc_results, object_input = \ + input_path, process_file, dot_file, mpi_args, \ + rebuild_saltproc_results, run_without_reprocessing, object_input = \ read_main_input(saltproc_input) _print_simulation_input_info(object_input[1], object_input[0]) # Intializing objects @@ -71,28 +72,31 @@ def run(): simulation.store_run_step_info() # Reprocessing here - for key in mats.keys(): - print('\nMass and volume of ' - f'{key} before reproc: {mats[key].mass} g, ', - f'{mats[key].volume} cm3') - waste_streams, extracted_mass = reprocess_materials(mats, - process_file, - dot_file) - for key in mats.keys(): - print('\nMass and volume of ' - f'{key} after reproc: {mats[key].mass} g, ', - f'{mats[key].volume} cm3') - - waste_and_feed_streams = refill_materials(mats, - extracted_mass, - waste_streams, - process_file) - for key in mats.keys(): - print('\nMass and volume of ' - f'{key} after refill: {mats[key].mass} g, ', - f'{mats[key].volume} cm3') - - print("Removed mass [g]:", extracted_mass) + if not run_without_reprocessing: + for key in mats.keys(): + print('\nMass and volume of ' + f'{key} before reproc: {mats[key].mass} g, ', + f'{mats[key].volume} cm3') + waste_streams, extracted_mass = reprocess_materials(mats, + process_file, + dot_file) + for key in mats.keys(): + print('\nMass and volume of ' + f'{key} after reproc: {mats[key].mass} g, ', + f'{mats[key].volume} cm3') + + waste_and_feed_streams = refill_materials(mats, + extracted_mass, + waste_streams, + process_file) + for key in mats.keys(): + print('\nMass and volume of ' + f'{key} after refill: {mats[key].mass} g, ', + f'{mats[key].volume} cm3') + + print("Removed mass [g]:", extracted_mass) + else: + waste_and_feed_streams = None # Store in DB after reprocessing and refill (right before next depl) simulation.store_after_repr(mats, waste_and_feed_streams, step_idx) depcode.update_depletable_materials(mats, simulation.burn_time) @@ -205,6 +209,9 @@ def read_main_input(main_inp_file): # Rebuild saltproc results? rebuild_saltproc_results = input_parameters['rebuild_saltproc_results'] + # Run without reprocessing? + run_without_reprocessing = input_parameters['run_without_reprocessing'] + # Class settings depcode_input = input_parameters['depcode'] simulation_input = input_parameters['simulation'] @@ -254,7 +261,7 @@ def read_main_input(main_inp_file): reactor_input = _process_main_input_reactor_params( reactor_input, n_depletion_steps, depcode_input['codename']) - return input_path, process_file, dot_file, mpi_args, rebuild_saltproc_results, ( + return input_path, process_file, dot_file, mpi_args, rebuild_saltproc_results, run_without_reprocessing, ( depcode_input, simulation_input, reactor_input) def _print_simulation_input_info(simulation_input, depcode_input): diff --git a/saltproc/input_schema.json b/saltproc/input_schema.json index 07ae4498f..3dd9ab501 100644 --- a/saltproc/input_schema.json +++ b/saltproc/input_schema.json @@ -35,6 +35,11 @@ "type": "boolean", "default": false }, + "run_without_reprocessing" : { + "description": "Flag to run the simulation with no material reprocessing", + "type": "boolean", + "default": false + }, "depcode": { "description": "Depcode class input parameters", "type": "object", diff --git a/saltproc/simulation.py b/saltproc/simulation.py index 9962af8f8..384a2d7e5 100644 --- a/saltproc/simulation.py +++ b/saltproc/simulation.py @@ -121,61 +121,62 @@ def store_after_repr(self, after_mats, waste_dict, dep_step): Current depletion time step. """ - streams_description = 'in_out_streams' - db = tb.open_file( - self.db_path, - mode='a', - filters=self.compression_params) - for material_name in waste_dict.keys(): # iterate over materials - mat_node = getattr(db.root.materials, material_name) - if not hasattr(mat_node, streams_description): - waste_group = db.create_group( - mat_node, - streams_description, - 'Waste stream compositions for each process') - else: - waste_group = getattr(mat_node, streams_description) - for proc in waste_dict[material_name].keys(): - if not hasattr(waste_group, proc): - proc_node = db.create_group(waste_group, proc) + if waste_dict is not None: + streams_description = 'in_out_streams' + db = tb.open_file( + self.db_path, + mode='a', + filters=self.compression_params) + for material_name in waste_dict.keys(): # iterate over materials + mat_node = getattr(db.root.materials, material_name) + if not hasattr(mat_node, streams_description): + waste_group = db.create_group( + mat_node, + streams_description, + 'Waste stream compositions for each process') else: - proc_node = getattr(waste_group, proc) - nuclide_indices = [] - iso_wt_frac = [] - coun = 0 - if hasattr(waste_dict[material_name][proc], 'comp'): - # Read isotopes from Materialflow - for nuc, wt_frac in waste_dict[material_name][proc].comp.items(): - # Dictonary in format {isotope_name : index(int)} - nuclide_indices.append((nuc, coun)) - # Convert wt% to absolute [user units] - iso_wt_frac.append(wt_frac * waste_dict[material_name][proc].mass) - coun += 1 - # Try to open EArray and table and if not exist - create - nuclide_indices_array = np.array(nuclide_indices, dtype=self.nuclide_indices_dtype) - if hasattr(proc_node, 'comp'): - earr = db.get_node(proc_node, 'comp') + waste_group = getattr(mat_node, streams_description) + for proc in waste_dict[material_name].keys(): + if not hasattr(waste_group, proc): + proc_node = db.create_group(waste_group, proc) else: - earr = db.create_earray( - proc_node, - 'comp', - atom=tb.Float64Atom(), - shape=(0, len(nuclide_indices_array)), - title="Isotopic composition for %s" % proc) - # Save isotope indexes map and units in EArray attributes - earr.flavor = 'python' - if not hasattr(proc_node, 'nuclide_map'): - db.create_table(proc_node, - 'nuclide_map', - description=nuclide_indices_array) - - earr, iso_wt_frac = self._fix_nuclide_discrepancy(db, earr, nuclide_indices, iso_wt_frac) - - earr.append(np.asarray([iso_wt_frac], dtype=np.float64)) - del iso_wt_frac, nuclide_indices + proc_node = getattr(waste_group, proc) + nuclide_indices = [] + iso_wt_frac = [] + coun = 0 + if hasattr(waste_dict[material_name][proc], 'comp'): + # Read isotopes from Materialflow + for nuc, wt_frac in waste_dict[material_name][proc].comp.items(): + # Dictonary in format {isotope_name : index(int)} + nuclide_indices.append((nuc, coun)) + # Convert wt% to absolute [user units] + iso_wt_frac.append(wt_frac * waste_dict[material_name][proc].mass) + coun += 1 + # Try to open EArray and table and if not exist - create + nuclide_indices_array = np.array(nuclide_indices, dtype=self.nuclide_indices_dtype) + if hasattr(proc_node, 'comp'): + earr = db.get_node(proc_node, 'comp') + else: + earr = db.create_earray( + proc_node, + 'comp', + atom=tb.Float64Atom(), + shape=(0, len(nuclide_indices_array)), + title="Isotopic composition for %s" % proc) + # Save isotope indexes map and units in EArray attributes + earr.flavor = 'python' + if not hasattr(proc_node, 'nuclide_map'): + db.create_table(proc_node, + 'nuclide_map', + description=nuclide_indices_array) + + earr, iso_wt_frac = self._fix_nuclide_discrepancy(db, earr, nuclide_indices, iso_wt_frac) + + earr.append(np.asarray([iso_wt_frac], dtype=np.float64)) + del iso_wt_frac, nuclide_indices + db.close() # Also save materials AFTER reprocessing and refill here self.store_mat_data(after_mats, dep_step, True) - db.close() def _fix_nuclide_discrepancy(self, db, earr, nuclide_indices, iso_wt_frac): """Fix discrepancies between nuclide keys present in stored results and From 6ebe13deaf3d58ad475d5349b767243aae08e900 Mon Sep 17 00:00:00 2001 From: yardasol Date: Mon, 15 May 2023 18:05:32 -0500 Subject: [PATCH 34/62] be able to store all results in Results class --- saltproc/openmc_depcode.py | 18 +++++++++++------- saltproc/results.py | 22 ++++++++++++++++------ saltproc/serpent_depcode.py | 12 +++++++++--- saltproc/simulation.py | 21 +++++++++++++++------ 4 files changed, 51 insertions(+), 22 deletions(-) diff --git a/saltproc/openmc_depcode.py b/saltproc/openmc_depcode.py index 8d24b068b..779d0bfff 100644 --- a/saltproc/openmc_depcode.py +++ b/saltproc/openmc_depcode.py @@ -172,21 +172,25 @@ def read_neutronics_parameters(self): self.neutronics_parameters['keff_bds'] = res[0].k[0] self.neutronics_parameters['keff_eds'] = res[1].k[0] - self.neutronics_parameters['breeding_ratio'] = self._calculate_breeding_ratio(sp1) + self.neutronics_parameters['breeding_ratio_bds'] = self._calculate_breeding_ratio(sp0) + self.neutronics_parameters['breeding_ratio_eds'] = self._calculate_breeding_ratio(sp1) self.neutronics_parameters['burn_days'] = res[1].time[0] / _SECONDS_PER_DAY self.neutronics_parameters['power_level'] = res[1].source_rate - self.neutronics_parameters['beta_eff'] = self._calculate_delayed_quantity(sp1, self._beta) - self.neutronics_parameters['delayed_neutrons_lambda'] = \ + self.neutronics_parameters['beta_eff_bds'] = self._calculate_delayed_quantity(sp0, self._beta) + self.neutronics_parameters['beta_eff_eds'] = self._calculate_delayed_quantity(sp1, self._beta) + self.neutronics_parameters['delayed_neutrons_lambda_bds'] = \ + self._calculate_delayed_quantity(sp0, self._delayed_lambda) + self.neutronics_parameters['delayed_neutrons_lambda_eds'] = \ self._calculate_delayed_quantity(sp1, self._delayed_lambda) init_fission_mass, final_fission_mass = self._calculate_fission_masses(res) self.neutronics_parameters['fission_mass_bds'] = init_fission_mass self.neutronics_parameters['fission_mass_eds'] = final_fission_mass del sp0, sp1 - def _calculate_breeding_ratio(self, sp1): + def _calculate_breeding_ratio(self, sp): """Fissile material produces / fissile material destroyed""" - breeding_ratio_tally = sp1.get_tally(name='breeding_ratio_tally') + breeding_ratio_tally = sp.get_tally(name='breeding_ratio_tally') frame = breeding_ratio_tally.get_pandas_dataframe().set_index('score') n_gamma_frame = frame.loc['(n,gamma)'].set_index('nuclide') absorption_frame = frame.loc['absorption'].set_index('nuclide') @@ -204,9 +208,9 @@ def _calculate_breeding_ratio(self, sp1): return np.array([breeding_ratio.n, breeding_ratio.s]) - def _calculate_delayed_quantity(self, sp1, mgxs): + def _calculate_delayed_quantity(self, sp, mgxs): # group-wise delayed quantity - mgxs.load_from_statepoint(sp1) + mgxs.load_from_statepoint(sp) frame = mgxs.get_pandas_dataframe() vals = self._get_values_with_uncertainties(frame) tot = vals.sum() diff --git a/saltproc/results.py b/saltproc/results.py index 5e96ef25a..2b3ff25b9 100644 --- a/saltproc/results.py +++ b/saltproc/results.py @@ -18,8 +18,11 @@ def __init__(self, path): self.keff = self._collect_eds_bds_params(sim_params, 'keff', errors=True) self.fission_mass = self._collect_eds_bds_params(sim_params, 'fission_mass') + self.breeding_ratio = self._collect_eds_bds_params(sim_params, 'breeding_ratio', errors=True) self.power_level = sim_params.col('power_level') - self.breeding_ratio = sim_params.col('breeding_ratio') + self.breeding_ratio = self._collect_eds_bds_params(sim_params, 'breeding_ratio', errors=True) + self.beta_eff = self._collect_eds_bds_params(sim_params, 'beta_eff', errors=True, multidim=True) + self.lambda_eff = self._collect_eds_bds_params(sim_params, 'delayed_neutrons_lambda', errors=True, multidim=True) # metadata metadata = f.root.initial_depcode_siminfo @@ -36,16 +39,23 @@ def __init__(self, path): self.material_parameters = material_parameters self.waste_streams = waste_streams - def _collect_eds_bds_params(self, sim_params, col, errors=False): + def _collect_eds_bds_params(self, sim_params, col, errors=False, multidim=False): col_eds = sim_params.col(f'{col}_eds').tolist() col_bds = sim_params.col(f'{col}_bds').tolist() col = [col_bds[0], col_eds[0]] for (k1, k2) in zip(col_bds[1:], col_eds[1:]): - col = col + [k1] - col = col + [k2] + col += [k1] + col += [k2] col = np.array(col) - if errors == True: - col = unp.uarray(col[:,0], col[:,1]) + if errors: + if multidim: + new_col = [] + for c in col: + c = np.array(c) + new_col += [unp.uarray(c[:,0], c[:,1]).tolist()] + col = np.array(new_col) + else: + col = unp.uarray(col[:,0], col[:,1]) return col def _collect_material_params(self, materials): diff --git a/saltproc/serpent_depcode.py b/saltproc/serpent_depcode.py index 9be55031b..183538c67 100644 --- a/saltproc/serpent_depcode.py +++ b/saltproc/serpent_depcode.py @@ -419,14 +419,20 @@ def read_neutronics_parameters(self): res = serpentTools.read(self.runtime_inputfile + "_res.m") self.neutronics_parameters['keff_bds'] = res.resdata['impKeff'][0] self.neutronics_parameters['keff_eds'] = res.resdata['impKeff'][1] - self.neutronics_parameters['breeding_ratio'] = \ + self.neutronics_parameters['breeding_ratio_bds'] = \ + res.resdata['conversionRatio'][0] + self.neutronics_parameters['breeding_ratio_eds'] = \ res.resdata['conversionRatio'][1] self.neutronics_parameters['burn_days'] = res.resdata['burnDays'][1][0] self.neutronics_parameters['power_level'] = res.resdata['totPower'][1][0] b_l = int(.5 * len(res['fwdAnaBetaZero'][1])) - self.neutronics_parameters['beta_eff'] = \ + self.neutronics_parameters['beta_eff_bds'] = \ + res.resdata['fwdAnaBetaZero'][0].reshape((b_l, 2)) + self.neutronics_parameters['beta_eff_eds'] = \ res.resdata['fwdAnaBetaZero'][1].reshape((b_l, 2)) - self.neutronics_parameters['delayed_neutrons_lambda'] = \ + self.neutronics_parameters['delayed_neutrons_lambda_bds'] = \ + res.resdata['fwdAnaLambda'][0].reshape((b_l, 2)) + self.neutronics_parameters['delayed_neutrons_lambda_eds'] = \ res.resdata['fwdAnaLambda'][1].reshape((b_l, 2)) self.neutronics_parameters['fission_mass_bds'] = \ res.resdata['iniFmass'][1] diff --git a/saltproc/simulation.py b/saltproc/simulation.py index 384a2d7e5..4810dc624 100644 --- a/saltproc/simulation.py +++ b/saltproc/simulation.py @@ -458,16 +458,19 @@ def store_run_step_info(self): # Read info from depcode _res.m File self.sim_depcode.read_neutronics_parameters() # Initialize beta groups number - b_g = len(self.sim_depcode.neutronics_parameters['beta_eff']) + b_g = len(self.sim_depcode.neutronics_parameters['beta_eff_bds']) # numpy array row storage for run info class Step_info(tb.IsDescription): keff_bds = tb.Float32Col((2,)) keff_eds = tb.Float32Col((2,)) - breeding_ratio = tb.Float32Col((2,)) + breeding_ratio_bds = tb.Float32Col((2,)) + breeding_ratio_eds = tb.Float32Col((2,)) cumulative_time_at_eds = tb.Float32Col() power_level = tb.Float32Col() + beta_eff_bds = tb.Float32Col((b_g, 2)) beta_eff_eds = tb.Float32Col((b_g, 2)) + delayed_neutrons_lambda_bds = tb.Float32Col((b_g, 2)) delayed_neutrons_lambda_eds = tb.Float32Col((b_g, 2)) fission_mass_bds = tb.Float32Col() fission_mass_eds = tb.Float32Col() @@ -497,14 +500,20 @@ class Step_info(tb.IsDescription): step_info['keff_bds'] = self.sim_depcode.neutronics_parameters['keff_bds'] step_info['keff_eds'] = self.sim_depcode.neutronics_parameters['keff_eds'] - step_info['breeding_ratio'] = self.sim_depcode.neutronics_parameters[ - 'breeding_ratio'] + step_info['breeding_ratio_bds'] = self.sim_depcode.neutronics_parameters[ + 'breeding_ratio_bds'] + step_info['breeding_ratio_eds'] = self.sim_depcode.neutronics_parameters[ + 'breeding_ratio_eds'] step_info['cumulative_time_at_eds'] = self.burn_time step_info['power_level'] = self.sim_depcode.neutronics_parameters['power_level'] + step_info['beta_eff_bds'] = self.sim_depcode.neutronics_parameters[ + 'beta_eff_bds'] step_info['beta_eff_eds'] = self.sim_depcode.neutronics_parameters[ - 'beta_eff'] + 'beta_eff_eds'] + step_info['delayed_neutrons_lambda_bds'] = self.sim_depcode.neutronics_parameters[ + 'delayed_neutrons_lambda_bds'] step_info['delayed_neutrons_lambda_eds'] = self.sim_depcode.neutronics_parameters[ - 'delayed_neutrons_lambda'] + 'delayed_neutrons_lambda_eds'] step_info['fission_mass_bds'] = self.sim_depcode.neutronics_parameters[ 'fission_mass_bds'] step_info['fission_mass_eds'] = self.sim_depcode.neutronics_parameters[ From b8fdadf7144b5a227472f3c7b1867ae5bdfdf116 Mon Sep 17 00:00:00 2001 From: yardasol Date: Mon, 15 May 2023 18:44:14 -0500 Subject: [PATCH 35/62] split metadata tables into depcode-related and depletion-step-related metadata --- saltproc/app.py | 3 +- saltproc/depcode.py | 7 +++- saltproc/openmc_depcode.py | 34 ++++++++++------ saltproc/results.py | 39 +++++++++++++------ saltproc/serpent_depcode.py | 24 +++++++++--- saltproc/simulation.py | 77 +++++++++++++++++++++++++++---------- 6 files changed, 134 insertions(+), 50 deletions(-) diff --git a/saltproc/app.py b/saltproc/app.py index b598f19de..cdec06337 100644 --- a/saltproc/app.py +++ b/saltproc/app.py @@ -69,7 +69,8 @@ def run(): # Main sequence mats = depcode.read_depleted_materials(True) simulation.store_mat_data(mats, step_idx, False) - simulation.store_run_step_info() + simulation.store_step_neutronics_parameters() + simulation.store_step_metadata() # Reprocessing here if not run_without_reprocessing: diff --git a/saltproc/depcode.py b/saltproc/depcode.py index 76bce4207..0f1701388 100644 --- a/saltproc/depcode.py +++ b/saltproc/depcode.py @@ -74,9 +74,14 @@ def __init__(self, self.runtime_inputfile = None self.runtime_matfile = None + @abstractmethod + def read_depcode_metadata(self): + """Read depletion code metadata, and store it in the :class:`Depcode` + object's :attr:`depcode_metadata` attribute""" + @abstractmethod def read_step_metadata(self): - """Reads depletion code's depletion step metadata and stores it in the + """Reads depletion step metadata and stores it in the :class:`Depcode` object's :attr:`step_metadata` attribute. """ diff --git a/saltproc/openmc_depcode.py b/saltproc/openmc_depcode.py index 779d0bfff..9ff5b5b02 100644 --- a/saltproc/openmc_depcode.py +++ b/saltproc/openmc_depcode.py @@ -55,6 +55,9 @@ class OpenMCDepcode(Depcode): step_metadata : dict of str to type Holds OpenMC depletion step metadata. Metadata labels are keys and metadata values are values. + depcode_metadata : dict of str to type + Holds OpenMC simulation metadata. Metadata labels are keys + and metadata values are values. runtime_inputfile : dict of str to str Paths to OpenMC input files used to run depletion step. Contains neutron settings and geometry. @@ -127,18 +130,14 @@ def _check_for_material_names(self, filename): if material.name == '': raise ValueError(f"Material {material.id} has no name.") - def read_step_metadata(self): + def read_depcode_metadata(self): """Reads OpenMC's depletion step metadata and stores it in the :class:`OpenMCDepcode` object's :attr:`step_metadata` attribute. """ sp0 = openmc.StatePoint(self.output_path / 'openmc_simulation_n0.h5') - sp1 = openmc.StatePoint(self.output_path / 'openmc_simulation_n1.h5') - res = Results(self.output_path / 'depletion_results.h5') depcode_name, depcode_ver = self.codename, ".".join(list(map(str,sp0.version))) - execution_time = sp0.runtime['simulation'] + sp1.runtime['simulation'] + res[0].proc_time + res[1].proc_time sp0.close() - sp1.close() self.step_metadata['depcode_name'] = depcode_name self.step_metadata['depcode_version'] = depcode_ver @@ -146,12 +145,6 @@ def read_step_metadata(self): self.step_metadata['depcode_input_filename'] = '' self.step_metadata['depcode_working_dir'] = str(self.output_path) self.step_metadata['xs_data_path'] = self._find_xs_path() - self.step_metadata['OMP_threads'] = -1 - self.step_metadata['MPI_tasks'] = -1 - self.step_metadata['memory_optimization_mode'] = -1 - self.step_metadata['depletion_timestep'] = res[1].time[0] - self.step_metadata['execution_time'] = execution_time - self.step_metadata['memory_usage'] = -1 def _find_xs_path(self): try: @@ -161,6 +154,25 @@ def _find_xs_path(self): xs_path = openmc.Materials.from_xml(self.runtime_matfile).cross_sections return xs_path + def read_step_metadata(self): + """Reads OpenMC's depletion step metadata and stores it in the + :class:`OpenMCDepcode` object's :attr:`step_metadata` attribute. + """ + sp0 = openmc.StatePoint(self.output_path / 'openmc_simulation_n0.h5') + sp1 = openmc.StatePoint(self.output_path / 'openmc_simulation_n1.h5') + res = Results(self.output_path / 'depletion_results.h5') + + execution_time = sp0.runtime['simulation'] + sp1.runtime['simulation'] + res[0].proc_time + res[1].proc_time + sp0.close() + sp1.close() + + self.step_metadata['OMP_threads'] = -1 + self.step_metadata['MPI_tasks'] = -1 + self.step_metadata['memory_optimization_mode'] = -1 + self.step_metadata['depletion_timestep_size'] = res[1].time[0] + self.step_metadata['step_execution_time'] = execution_time + self.step_metadata['step_memory_usage'] = -1 + def read_neutronics_parameters(self): """Reads OpenMC depletion step neutronics parameters and stores them in :class:`OpenMCDepcode` object's :attr:`neutronics_parameters` diff --git a/saltproc/results.py b/saltproc/results.py index 2b3ff25b9..c8422f082 100644 --- a/saltproc/results.py +++ b/saltproc/results.py @@ -20,22 +20,22 @@ def __init__(self, path): self.fission_mass = self._collect_eds_bds_params(sim_params, 'fission_mass') self.breeding_ratio = self._collect_eds_bds_params(sim_params, 'breeding_ratio', errors=True) self.power_level = sim_params.col('power_level') - self.breeding_ratio = self._collect_eds_bds_params(sim_params, 'breeding_ratio', errors=True) self.beta_eff = self._collect_eds_bds_params(sim_params, 'beta_eff', errors=True, multidim=True) self.lambda_eff = self._collect_eds_bds_params(sim_params, 'delayed_neutrons_lambda', errors=True, multidim=True) # metadata - metadata = f.root.initial_depcode_siminfo - metadata = pd.DataFrame.from_records(metadata[:]).to_dict() - for key, value in metadata.items(): - metadata[key] = value[0] - self.metadata = metadata + self.depcode_metadata = self._collect_metadata(f, 'depcode_metadata') + self.depletion_step_metadata = self._collect_metadata(f, 'depletion_step_metadata', array=True) + #metadata = pd.DataFrame.from_records(metadata[:]).to_dict() + #for key, value in metadata.items(): + # metadata[key] = value[0#] + ##self.depcode_metadata = metadata # Materials materials = root.materials - nuclide_idx, material_compositions, material_parameters, waste_streams = self._collect_material_params(materials) + nuclide_idx, material_composition, material_parameters, waste_streams = self._collect_material_params(materials) self.nuclide_idx = nuclide_idx - self.material_compositions = material_compositions + self.material_composition = material_composition self.material_parameters = material_parameters self.waste_streams = waste_streams @@ -58,16 +58,26 @@ def _collect_eds_bds_params(self, sim_params, col, errors=False, multidim=False) col = unp.uarray(col[:,0], col[:,1]) return col + def _collect_metadata(self, f, nodename, array=False): + metadata = f.root[nodename] + metadata = pd.DataFrame.from_records(metadata[:]).to_dict() + for key, value in metadata.items(): + if array: + metadata[key] = list(value.values()) + else: + metadata[key] = value[0] + return metadata + def _collect_material_params(self, materials): nuclide_idx = {} - material_compositions = {} + material_composition = {} material_parameters = {} waste_streams = {} for mat_name in materials._v_groups.keys(): material = materials[mat_name] # main material composition - nuclide_idx[mat_name], material_compositions[mat_name] = self._collect_material_comp(material) + nuclide_idx[mat_name], material_composition[mat_name] = self._collect_material_comp(material) # material parameters material_parameters[mat_name] = {} @@ -83,7 +93,7 @@ def _collect_material_params(self, materials): waste_streams[mat_name][stream_name] = \ self._collect_waste_streams(waste_stream, stream_name) - return nuclide_idx, material_compositions, material_parameters, waste_streams + return nuclide_idx, material_composition, material_parameters, waste_streams # MAKE THIS COLLECT IT INTO A TABLE/2D ARRAY def _collect_material_comp(self, material): @@ -126,3 +136,10 @@ def _collect_waste_streams(self, waste_stream, stream_name): return waste_stream_comp # methods to get timeseries of various values + def get_nuclide_mass(self, material, nuclide, timestep=None): + nucmap = self.nuclide_idx[material] + comp = self.material_composition[material] + nuclide_mass = comp[nucmap[nuclide]] + if timestep is not None: + nuclide_mass = nuclide_mass[timestep] + return nuclide_mass diff --git a/saltproc/serpent_depcode.py b/saltproc/serpent_depcode.py index 183538c67..b4471ee10 100644 --- a/saltproc/serpent_depcode.py +++ b/saltproc/serpent_depcode.py @@ -7,6 +7,7 @@ import openmc import openmc.data from math import floor +import numpy as np from saltproc import Materialflow from saltproc.depcode import Depcode @@ -47,6 +48,9 @@ class SerpentDepcode(Depcode): step_metadata : dict of str to type Holds Serpent2 depletion step metadata. Metadata labels are keys and metadata values are values. + depcode_metadata : dict of str to type + Holds Serpent2 simulation metadata. Metadata labels are keys + and metadata values are values. runtime_inputfile : str Path to Serpent2 input file used to run depletion step. Contains neutron settings and non-burnable materials. @@ -388,10 +392,11 @@ def read_depleted_materials(self, read_at_end=False): burnup=results.burnup[moment]) return depleted_materials - def read_step_metadata(self): - """Reads Serpent2 depletion step metadata and stores it in the - :class:`SerpentDepcode` object's :attr:`step_metadata` attribute. + def read_depcode_metadata(self): + """Reads Serpent2 metadata and stores it in the + :class:`SerpentDepcode` object's :attr:`depcode_metadata` attribute. """ + res = serpentTools.read(self.runtime_inputfile + "_res.m") depcode_name, depcode_ver = res.metadata['version'].split() self.step_metadata['depcode_name'] = depcode_name @@ -403,12 +408,19 @@ def read_step_metadata(self): res.metadata['workingDirectory'] self.step_metadata['xs_data_path'] = \ res.metadata['xsDataFilePath'] + + + def read_step_metadata(self): + """Reads Serpent2 depletion step metadata and stores it in the + :class:`SerpentDepcode` object's :attr:`step_metadata` attribute. + """ + res = serpentTools.read(self.runtime_inputfile + "_res.m") self.step_metadata['OMP_threads'] = res.metadata['ompThreads'] self.step_metadata['MPI_tasks'] = res.metadata['mpiTasks'] self.step_metadata['memory_optimization_mode'] = res.metadata['optimizationMode'] - self.step_metadata['depletion_timestep'] = res.resdata['burnDays'][1][0] - self.step_metadata['execution_time'] = res.resdata['runningTime'][1] - self.step_metadata['memory_usage'] = res.resdata['memsize'][0] + self.step_metadata['depletion_timestep_size'] = res.resdata['burnDays'][1][0] + self.step_metadata['step_execution_time'] = np.sum(res.resdata['runningTime']) + self.step_metadata['step_memory_usage'] = np.sum(res.resdata['memsize'][0]) def read_neutronics_parameters(self): diff --git a/saltproc/simulation.py b/saltproc/simulation.py index 4810dc624..a59c7a1c4 100644 --- a/saltproc/simulation.py +++ b/saltproc/simulation.py @@ -447,7 +447,7 @@ def store_mat_data(self, mats, dep_step, store_at_end=False): mpar_table.flush() db.close() - def store_run_step_info(self): + def store_step_neutronics_parameters(self): """Adds the following depletion code and SaltProc simulation data at the current depletion step to the database: execution time, memory usage, multiplication factor, breeding ratio, @@ -536,20 +536,61 @@ def store_run_init_info(self): # numpy arraw row storage for run info # delete and make this datatype specific # to Depcode subclasses - step_metadata_dtype = np.dtype([ - ('neutron_population', int), - ('active_cycles', int), - ('inactive_cycles', int), + depcode_metadata_dtype = np.dtype([ ('depcode_name', 'S20'), ('depcode_version', 'S20'), ('title', 'S90'), ('depcode_input_filename', 'S90'), ('depcode_working_dir', 'S90'), - ('xs_data_path', 'S90'), + ('xs_data_path', 'S90') + ]) + # Read info from depcode _res.m File + self.sim_depcode.read_depcode_metadata() + # Store information about material properties in new array row + depcode_metadata_row = ( + self.sim_depcode.step_metadata['depcode_name'], + self.sim_depcode.step_metadata['depcode_version'], + self.sim_depcode.step_metadata['title'], + self.sim_depcode.step_metadata['depcode_input_filename'], + self.sim_depcode.step_metadata['depcode_working_dir'], + self.sim_depcode.step_metadata['xs_data_path'] + ) + depcode_metadata_array = np.array([depcode_metadata_row], dtype=depcode_metadata_dtype) + + # Open or restore db and append datat to it + db = tb.open_file( + self.db_path, + mode='a', + filters=self.compression_params) + try: + depcode_metadata_table = db.get_node(db.root, 'depcode_metadata') + except Exception: + depcode_metadata_table = db.create_table( + db.root, + 'depcode_metadata', + depcode_metadata_array, + "Depletion code metadata") + depcode_metadata_table.flush() + db.close() + + def store_step_metadata(self): + """Adds the following depletion code and SaltProc simulation parameters + to the database: + neutron population, active cycles, inactive cycles, # of OMP threads, # of MPI + tasks, memory optimization mode (Serpent), depletion timestep size. + + """ + # numpy arraw row storage for run info + # delete and make this datatype specific + # to Depcode subclasses + step_metadata_dtype = np.dtype([ + ('neutron_population', int), + ('active_cycles', int), + ('inactive_cycles', int), ('OMP_threads', int), ('MPI_tasks', int), ('memory_optimization_mode', int), - ('depletion_timestep', float), + ('depletion_timestep_size', float), ('execution_time', float), ('memory_usage', float) ]) @@ -560,18 +601,12 @@ def store_run_init_info(self): self.sim_depcode.npop, self.sim_depcode.active_cycles, self.sim_depcode.inactive_cycles, # delete the below - self.sim_depcode.step_metadata['depcode_name'], - self.sim_depcode.step_metadata['depcode_version'], - self.sim_depcode.step_metadata['title'], - self.sim_depcode.step_metadata['depcode_input_filename'], - self.sim_depcode.step_metadata['depcode_working_dir'], - self.sim_depcode.step_metadata['xs_data_path'], self.sim_depcode.step_metadata['OMP_threads'], self.sim_depcode.step_metadata['MPI_tasks'], self.sim_depcode.step_metadata['memory_optimization_mode'], - self.sim_depcode.step_metadata['depletion_timestep'], - self.sim_depcode.step_metadata['execution_time'], - self.sim_depcode.step_metadata['memory_usage'] + self.sim_depcode.step_metadata['depletion_timestep_size'], + self.sim_depcode.step_metadata['step_execution_time'], + self.sim_depcode.step_metadata['step_memory_usage'] ) step_metadata_array = np.array([step_metadata_row], dtype=step_metadata_dtype) @@ -582,13 +617,15 @@ def store_run_init_info(self): mode='a', filters=self.compression_params) try: - step_metadata_table = db.get_node(db.root, 'initial_depcode_siminfo') + step_metadata_table = db.get_node(db.root, 'depletion_step_metadata') except Exception: step_metadata_table = db.create_table( db.root, - 'initial_depcode_siminfo', - step_metadata_array, - "Initial depletion code simulation parameters") + 'depletion_step_metadata', + np.empty(0, dtype=step_metadata_dtype), + "Depletion step metadata") + + step_metadata_table.append(step_metadata_array) step_metadata_table.flush() db.close() From 61e064913d6ba3c6d84b6e3abe71f5055884b3c0 Mon Sep 17 00:00:00 2001 From: yardasol Date: Wed, 17 May 2023 17:44:39 -0500 Subject: [PATCH 36/62] fix small bug --- saltproc/app.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/saltproc/app.py b/saltproc/app.py index cdec06337..92543f9d1 100644 --- a/saltproc/app.py +++ b/saltproc/app.py @@ -98,6 +98,8 @@ def run(): print("Removed mass [g]:", extracted_mass) else: waste_and_feed_streams = None + waste_streams = None + extracted_mass = None # Store in DB after reprocessing and refill (right before next depl) simulation.store_after_repr(mats, waste_and_feed_streams, step_idx) depcode.update_depletable_materials(mats, simulation.burn_time) From 829c29a5194ad0af4f35118a7f08aacf8c15e3eb Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 18 May 2023 16:37:31 -0500 Subject: [PATCH 37/62] ensure npop for openmc exists --- saltproc/openmc_depcode.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/saltproc/openmc_depcode.py b/saltproc/openmc_depcode.py index 9ff5b5b02..76139e8e6 100644 --- a/saltproc/openmc_depcode.py +++ b/saltproc/openmc_depcode.py @@ -431,9 +431,6 @@ def write_runtime_input(self, reactor, depletion_step, restart): geo_file, materials=materials) settings = openmc.Settings.from_xml( self.template_input_file_path['settings']) - self.npop = settings.particles - self.inactive_cycles = settings.inactive - self.active_cycles = settings.batches - self.inactive_cycles else: openmc.reset_auto_ids() @@ -443,6 +440,10 @@ def write_runtime_input(self, reactor, depletion_step, restart): settings = openmc.Settings.from_xml( self.runtime_inputfile['settings']) + self.npop = settings.particles + self.inactive_cycles = settings.inactive + self.active_cycles = settings.batches - self.inactive_cycles + diluted_model = openmc.Model(materials=materials, geometry=geometry, settings=settings) reactions, diluted_materials = MicroXS._add_dilute_nuclides(self.chain_file_path, diluted_model, From aabfdba1b56e3400b00c33d301beecd8cf8d68eb Mon Sep 17 00:00:00 2001 From: yardasol Date: Tue, 13 Jun 2023 12:22:24 +0200 Subject: [PATCH 38/62] minor typo fix --- scripts/xsdata/download_endfb71.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/xsdata/download_endfb71.bash b/scripts/xsdata/download_endfb71.bash index 251fab908..aba811f6e 100644 --- a/scripts/xsdata/download_endfb71.bash +++ b/scripts/xsdata/download_endfb71.bash @@ -65,7 +65,7 @@ tar -xOzf $DATADIR/$ACEGZ xsdir | cat > $DATADIR/$XSDIR_FILE DATADIR_REGEX=${DATADIR//\//\\\/} # Fix datapath -sed -i "s/datapath/datapath=$DATADIR_REGEX/" $DATADIR/$XSDIR_FILE +sed -i "s/datapath /datapath=$DATADIR_REGEX/" $DATADIR/$XSDIR_FILE # Get cutoff line number LN="$(grep -n "directory" $DATADIR/$XSDIR_FILE)" From f2f955acc470681013f68ffce2a621d09913f89b Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 15 Jun 2023 14:32:09 +0200 Subject: [PATCH 39/62] fixed database_storage integration test --- saltproc/app.py | 2 +- saltproc/simulation.py | 2 +- .../database_storage/test.py | 118 +++++++++++++----- 3 files changed, 88 insertions(+), 34 deletions(-) diff --git a/saltproc/app.py b/saltproc/app.py index 92543f9d1..58aa836a7 100644 --- a/saltproc/app.py +++ b/saltproc/app.py @@ -61,7 +61,7 @@ def run(): depcode.run_depletion_step(mpi_args, threads) if step_idx == 0 and simulation.restart_flag is False: # First step # Read general simulation data which never changes - simulation.store_run_init_info() + simulation.store_depcode_metadata() # Parse and store data for initial state (beginning of step_idx) mats = depcode.read_depleted_materials(False) simulation.store_mat_data(mats, step_idx - 1, False) diff --git a/saltproc/simulation.py b/saltproc/simulation.py index a59c7a1c4..9f0fac6cc 100644 --- a/saltproc/simulation.py +++ b/saltproc/simulation.py @@ -524,7 +524,7 @@ class Step_info(tb.IsDescription): step_info_table.flush() db.close() - def store_run_init_info(self): + def store_depcode_metadata(self): """Adds the following depletion code and SaltProc simulation parameters to the database: neutron population, active cycles, inactive cycles, depletion code diff --git a/tests/integration_tests/database_storage/test.py b/tests/integration_tests/database_storage/test.py index 4f1933c51..eb674d633 100644 --- a/tests/integration_tests/database_storage/test.py +++ b/tests/integration_tests/database_storage/test.py @@ -223,9 +223,9 @@ def test_store_mat_data(simulation): simulation.db_path = db_path_old -def test_store_run_init_info(simulation): +def test_store_depcode_metadata(simulation): """ - This unit test checks that the entries ``store_run_init_info()` + This unit test checks that the entries ``store_depcode_metadata()` stores in the database match the corresponding entries from the input explicity in value and implicitly in type. """ @@ -245,7 +245,7 @@ def test_store_run_init_info(simulation): simulation.db_path = db_file # store data at - simulation.store_run_init_info() + simulation.store_depcode_metadata() # read stored data try: @@ -256,23 +256,69 @@ def test_store_run_init_info(simulation): print('Unable to assign correct value to db.\ See error stack for more info.') - tinit_info = db.root.initial_depcode_siminfo[0] + tinit_info = db.root.depcode_metadata[0] + + assert str(tinit_info[0])[2:-1] == init_info['depcode_name'] + assert str(tinit_info[1])[2:-1] == init_info['depcode_version'] + assert str(tinit_info[2])[2:-1] == init_info['title'] + assert str(tinit_info[3])[2:-1] == init_info['depcode_input_filename'] + assert str(tinit_info[4])[2:-1] == init_info['depcode_working_dir'] + assert str(tinit_info[5])[2:-1] == init_info['xs_data_path'] + + # close the file + db.close() + + # delete test file + os.remove(db_file) + + # use original db path + simulation.db_path = db_path_old + + +def test_store_step_metadata(simulation): + """ + This unit test checks that the entries ``store_step_metadata()` + stores in the database match the corresponding entries from the input + explicity in value and implicitly in type. + """ + + # read data + simulation.sim_depcode.read_step_metadata() + + file = simulation.sim_depcode.template_input_file_path + file_lines = simulation.sim_depcode.read_plaintext_file(file) + simulation.sim_depcode.get_neutron_settings(file_lines) + init_info = simulation.sim_depcode.step_metadata + + # we want to keep the old path for other sims, but for this + # test we'll want a fresh db + db_path_old = simulation.db_path + db_file = simulation.sim_depcode.codename + '_test.h5' + simulation.db_path = db_file + + # store data at + simulation.store_step_metadata() + + # read stored data + try: + db = tb.open_file(simulation.db_path, mode='r', + filters=simulation.compression_params) + except Exception: + db.close() + print('Unable to assign correct value to db.\ + See error stack for more info.') + + tinit_info = db.root.depletion_step_metadata[0] assert tinit_info[0] == simulation.sim_depcode.npop assert tinit_info[1] == simulation.sim_depcode.active_cycles assert tinit_info[2] == simulation.sim_depcode.inactive_cycles - assert str(tinit_info[3])[2:-1] == init_info['depcode_name'] - assert str(tinit_info[4])[2:-1] == init_info['depcode_version'] - assert str(tinit_info[5])[2:-1] == init_info['title'] - assert str(tinit_info[6])[2:-1] == init_info['depcode_input_filename'] - assert str(tinit_info[7])[2:-1] == init_info['depcode_working_dir'] - assert str(tinit_info[8])[2:-1] == init_info['xs_data_path'] - assert tinit_info[9] == init_info['OMP_threads'] - assert tinit_info[10] == init_info['MPI_tasks'] - assert tinit_info[11] == init_info['memory_optimization_mode'] - assert tinit_info[12] == init_info['depletion_timestep'] - assert tinit_info[13] == init_info['execution_time'] - assert tinit_info[14] == init_info['memory_usage'] + assert tinit_info[3] == init_info['OMP_threads'] + assert tinit_info[4] == init_info['MPI_tasks'] + assert tinit_info[5] == init_info['memory_optimization_mode'] + assert tinit_info[6] == init_info['depletion_timestep_size'] + assert tinit_info[7] == init_info['step_execution_time'] + assert tinit_info[8] == init_info['step_memory_usage'] # close the file db.close() @@ -284,9 +330,10 @@ def test_store_run_init_info(simulation): simulation.db_path = db_path_old -def test_store_run_step_info(simulation): + +def test_store_step_neutronics_parameters(simulation): """ - This unit test checks that the entries ``store_run_step_info()` + This unit test checks that the entries ``store_step_neutronics_parameters()` stores in the database match the corresponding entries from the input explicity in value and implicitly in type. """ @@ -301,7 +348,7 @@ def test_store_run_step_info(simulation): simulation.db_path = db_file # store data at - simulation.store_run_step_info() + simulation.store_step_neutronics_parameters() # read stored data try: @@ -311,22 +358,29 @@ def test_store_run_step_info(simulation): print('Unable to assign correct value to db.\ See error stack for more info.') - tstep_info = db.root.simulation_parameters[0] - assert np.array_equal(tstep_info[0], - step_info['beta_eff'].astype('float32')) - assert np.array_equal(tstep_info[1], - step_info['breeding_ratio'].astype('float32')) - assert tstep_info[2] == simulation.burn_time - assert np.array_equal(tstep_info[3], - step_info['delayed_neutrons_lambda']. + tstep_info = db.root.simulation_parameters + assert np.array_equal(tstep_info.col('beta_eff_bds')[0], + step_info['beta_eff_bds'].astype('float32')) + assert np.array_equal(tstep_info.col('beta_eff_eds')[0], + step_info['beta_eff_eds'].astype('float32')) + assert np.array_equal(tstep_info.col('breeding_ratio_bds')[0], + step_info['breeding_ratio_bds'].astype('float32')) + assert np.array_equal(tstep_info.col('breeding_ratio_eds')[0], + step_info['breeding_ratio_eds'].astype('float32')) + assert tstep_info.col('cumulative_time_at_eds')[0] == simulation.burn_time + assert np.array_equal(tstep_info.col('delayed_neutrons_lambda_bds')[0], + step_info['delayed_neutrons_lambda_bds']. + astype('float32')) + assert np.array_equal(tstep_info.col('delayed_neutrons_lambda_eds')[0], + step_info['delayed_neutrons_lambda_eds']. astype('float32')) - assert tstep_info[4] == step_info['fission_mass_bds'].astype('float32') - assert tstep_info[5] == step_info['fission_mass_eds'].astype('float32') - assert np.array_equal(tstep_info[6], + assert tstep_info.col('fission_mass_bds')[0] == step_info['fission_mass_bds'].astype('float32') + assert tstep_info.col('fission_mass_eds')[0] == step_info['fission_mass_eds'].astype('float32') + assert np.array_equal(tstep_info.col('keff_bds')[0], step_info['keff_bds'].astype('float32')) - assert np.array_equal(tstep_info[7], + assert np.array_equal(tstep_info.col('keff_eds')[0], step_info['keff_eds'].astype('float32')) - assert tstep_info[8] == step_info['power_level'].astype('float32') + assert tstep_info.col('power_level')[0] == step_info['power_level'].astype('float32') # close the file db.close() From 808e5972b24c63e3e2fc55d9de3bf78c6e7f7e5e Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 6 Jul 2023 12:40:43 -0500 Subject: [PATCH 40/62] fix serpent depcode unit test --- saltproc/depcode.py | 4 ++ saltproc/openmc_depcode.py | 12 ++-- saltproc/serpent_depcode.py | 12 ++-- saltproc/simulation.py | 12 ++-- tests/unit_tests/test_serpent_depcode.py | 76 +++++++++++++++++++----- 5 files changed, 84 insertions(+), 32 deletions(-) diff --git a/saltproc/depcode.py b/saltproc/depcode.py index 0f1701388..cd749279a 100644 --- a/saltproc/depcode.py +++ b/saltproc/depcode.py @@ -41,6 +41,9 @@ class Depcode(ABC): step_metadata : dict of str to type Holds depletion code depletion step metadata. Metadata labels are keys and metadata values are values. + depcode_metadata : dict of str to type + Holds depletion code simulation metadata. Metadata labels are keys + and metadata values are values. runtime_inputfile : str Path to input file used to run depletion step. runtime_matfile : str @@ -71,6 +74,7 @@ def __init__(self, self.geo_file_paths = geo_file_paths self.neutronics_parameters = {} self.step_metadata = {} + self.depcode_metadata = {} self.runtime_inputfile = None self.runtime_matfile = None diff --git a/saltproc/openmc_depcode.py b/saltproc/openmc_depcode.py index 76139e8e6..08c763ddb 100644 --- a/saltproc/openmc_depcode.py +++ b/saltproc/openmc_depcode.py @@ -139,12 +139,12 @@ def read_depcode_metadata(self): depcode_name, depcode_ver = self.codename, ".".join(list(map(str,sp0.version))) sp0.close() - self.step_metadata['depcode_name'] = depcode_name - self.step_metadata['depcode_version'] = depcode_ver - self.step_metadata['title'] = '' - self.step_metadata['depcode_input_filename'] = '' - self.step_metadata['depcode_working_dir'] = str(self.output_path) - self.step_metadata['xs_data_path'] = self._find_xs_path() + self.depcode_metadata['depcode_name'] = depcode_name + self.depcode_metadata['depcode_version'] = depcode_ver + self.depcode_metadata['title'] = '' + self.depcode_metadata['depcode_input_filename'] = '' + self.depcode_metadata['depcode_working_dir'] = str(self.output_path) + self.depcode_metadata['xs_data_path'] = self._find_xs_path() def _find_xs_path(self): try: diff --git a/saltproc/serpent_depcode.py b/saltproc/serpent_depcode.py index b4471ee10..d6234d9d7 100644 --- a/saltproc/serpent_depcode.py +++ b/saltproc/serpent_depcode.py @@ -399,14 +399,14 @@ def read_depcode_metadata(self): res = serpentTools.read(self.runtime_inputfile + "_res.m") depcode_name, depcode_ver = res.metadata['version'].split() - self.step_metadata['depcode_name'] = depcode_name - self.step_metadata['depcode_version'] = depcode_ver - self.step_metadata['title'] = res.metadata['title'] - self.step_metadata['depcode_input_filename'] = \ + self.depcode_metadata['depcode_name'] = depcode_name + self.depcode_metadata['depcode_version'] = depcode_ver + self.depcode_metadata['title'] = res.metadata['title'] + self.depcode_metadata['depcode_input_filename'] = \ res.metadata['inputFileName'] - self.step_metadata['depcode_working_dir'] = \ + self.depcode_metadata['depcode_working_dir'] = \ res.metadata['workingDirectory'] - self.step_metadata['xs_data_path'] = \ + self.depcode_metadata['xs_data_path'] = \ res.metadata['xsDataFilePath'] diff --git a/saltproc/simulation.py b/saltproc/simulation.py index 9f0fac6cc..54608df78 100644 --- a/saltproc/simulation.py +++ b/saltproc/simulation.py @@ -548,12 +548,12 @@ def store_depcode_metadata(self): self.sim_depcode.read_depcode_metadata() # Store information about material properties in new array row depcode_metadata_row = ( - self.sim_depcode.step_metadata['depcode_name'], - self.sim_depcode.step_metadata['depcode_version'], - self.sim_depcode.step_metadata['title'], - self.sim_depcode.step_metadata['depcode_input_filename'], - self.sim_depcode.step_metadata['depcode_working_dir'], - self.sim_depcode.step_metadata['xs_data_path'] + self.sim_depcode.depcode_metadata['depcode_name'], + self.sim_depcode.depcode_metadata['depcode_version'], + self.sim_depcode.depcode_metadata['title'], + self.sim_depcode.depcode_metadata['depcode_input_filename'], + self.sim_depcode.depcode_metadata['depcode_working_dir'], + self.sim_depcode.depcode_metadata['xs_data_path'] ) depcode_metadata_array = np.array([depcode_metadata_row], dtype=depcode_metadata_dtype) diff --git a/tests/unit_tests/test_serpent_depcode.py b/tests/unit_tests/test_serpent_depcode.py index 64fef8e82..804d08888 100644 --- a/tests/unit_tests/test_serpent_depcode.py +++ b/tests/unit_tests/test_serpent_depcode.py @@ -164,33 +164,81 @@ def test_nuclide_code_to_name(serpent_depcode): serpent_depcode.zaid_convention = 'serpent' -def test_read_step_metadata(serpent_depcode): - serpent_depcode.read_step_metadata() - assert serpent_depcode.step_metadata['depcode_name'] == 'Serpent' - assert serpent_depcode.step_metadata['depcode_version'] == '2.1.31' - assert serpent_depcode.step_metadata['title'] == 'Untitled' - assert serpent_depcode.step_metadata['depcode_input_filename'] == \ +def test_read_depcode_metadata(serpent_depcode): + serpent_depcode.read_depcode_metadata() + assert serpent_depcode.depcode_metadata['depcode_name'] == 'Serpent' + assert serpent_depcode.depcode_metadata['depcode_version'] == '2.1.31' + assert serpent_depcode.depcode_metadata['title'] == 'Untitled' + assert serpent_depcode.depcode_metadata['depcode_input_filename'] == \ '/home/andrei2/Desktop/git/saltproc/develop/saltproc/data/saltproc_tap' - assert serpent_depcode.step_metadata['depcode_working_dir'] == \ + assert serpent_depcode.depcode_metadata['depcode_working_dir'] == \ '/home/andrei2/Desktop/git/saltproc/develop/saltproc' - assert serpent_depcode.step_metadata['xs_data_path'] == \ + assert serpent_depcode.depcode_metadata['xs_data_path'] == \ '/home/andrei2/serpent/xsdata/jeff312/sss_jeff312.xsdata' + +def test_read_step_metadata(serpent_depcode): + serpent_depcode.read_step_metadata() assert serpent_depcode.step_metadata['MPI_tasks'] == 1 assert serpent_depcode.step_metadata['OMP_threads'] == 4 assert serpent_depcode.step_metadata['memory_optimization_mode'] == 4 - assert serpent_depcode.step_metadata['depletion_timestep'] == 3.0 - assert serpent_depcode.step_metadata['memory_usage'] == [10552.8] - assert serpent_depcode.step_metadata['execution_time'] == [81.933] + assert serpent_depcode.step_metadata['depletion_timestep_size'] == 3.0 + assert serpent_depcode.step_metadata['step_memory_usage'] == 10552.8 + assert serpent_depcode.step_metadata['step_execution_time'] == 111.76060000000001 def test_read_neutronics_parameters(serpent_depcode): serpent_depcode.read_neutronics_parameters() - assert serpent_depcode.neutronics_parameters['keff_bds'][0] == 1.00651e+00 - assert serpent_depcode.neutronics_parameters['keff_eds'][0] == 1.00569e+00 + assert serpent_depcode.neutronics_parameters['keff_bds'][0] == 1.00651 + assert serpent_depcode.neutronics_parameters['keff_eds'][0] == 1.00569 assert serpent_depcode.neutronics_parameters['fission_mass_bds'] == [70081] assert serpent_depcode.neutronics_parameters['fission_mass_eds'] == [70077.1] - assert serpent_depcode.neutronics_parameters['breeding_ratio'][1] == 5.20000e-04 + assert serpent_depcode.neutronics_parameters['breeding_ratio_eds'][1] == 5.2e-04 + assert serpent_depcode.neutronics_parameters['breeding_ratio_bds'][1] == 5.4e-04 + assert serpent_depcode.neutronics_parameters['burn_days'] == 3.0 + assert serpent_depcode.neutronics_parameters['power_level'] == 1.25e9 + np.testing.assert_equal(serpent_depcode.neutronics_parameters['beta_eff_bds'], + [[0.0073977, 0.00324], + [0.000217048, 0.01744], + [0.00105221, 0.00807], + [0.000638056, 0.00979], + [0.00139092, 0.0068], + [0.00234135, 0.00544], + [0.000813505, 0.00916], + [0.000680349, 0.00967], + [0.000264266, 0.0154]]) + np.testing.assert_equal(serpent_depcode.neutronics_parameters['beta_eff_eds'], + [[0.00739026, 0.00312], + [0.000219973, 0.01763], + [0.00106376, 0.00788], + [0.000632466, 0.01052], + [0.00139341, 0.00701], + [0.00230227, 0.00542], + [0.000822292, 0.00841], + [0.000685158, 0.01013], + [0.000270932, 0.01507]]) + np.testing.assert_equal(serpent_depcode.neutronics_parameters['delayed_neutrons_lambda_bds'], + [[4.76145e-01, 4.39000e-03], + [1.24667e-02, 0.00000e+00], + [2.82917e-02, 4.90000e-09], + [4.25244e-02, 7.10000e-09], + [1.33042e-01, 0.00000e+00], + [2.92467e-01, 0.00000e+00], + [6.66488e-01, 0.00000e+00], + [1.63478e+00, 5.20000e-09], + [3.55460e+00, 0.00000e+00]]) + np.testing.assert_equal(serpent_depcode.neutronics_parameters['delayed_neutrons_lambda_eds'], + [[4.80259e-01, 4.51000e-03], + [1.24667e-02, 0.00000e+00], + [2.82917e-02, 4.90000e-09], + [4.25244e-02, 7.10000e-09], + [1.33042e-01, 0.00000e+00], + [2.92467e-01, 0.00000e+00], + [6.66488e-01, 0.00000e+00], + [1.63478e+00, 5.20000e-09], + [3.55460e+00, 0.00000e+00]]) + assert serpent_depcode.neutronics_parameters['fission_mass_bds'] == 70081. + assert serpent_depcode.neutronics_parameters['fission_mass_eds'] == 70077.1 def test_read_depleted_materials(serpent_depcode): From 96be7d6577c3eb8ae41e66727508aac1dcc8f37f Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 6 Jul 2023 13:03:44 -0500 Subject: [PATCH 41/62] fix test app --- saltproc/app.py | 6 ++++++ tests/unit_tests/test_app.py | 9 +++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/saltproc/app.py b/saltproc/app.py index 58aa836a7..e7693529e 100644 --- a/saltproc/app.py +++ b/saltproc/app.py @@ -164,6 +164,12 @@ def read_main_input(main_inp_file): mpi_args : list of str Arguments for running simulations on supercomputers using mpiexec or similar programs. + rebuild_saltproc_results : bool + Flag to indicate wheter or not to rebuild SaltProc results file + from existing depcode results + run_without_reprocessing : bool + Flag to indicate whether or not to run the depletion code in + SaltProc without applying the reprocessing system. object_inputs : 3-tuple of dict tuple containing the inputs for constructing the :class:`~saltproc.Depcode`, :class:`~saltproc.Simulation`, and diff --git a/tests/unit_tests/test_app.py b/tests/unit_tests/test_app.py index a912d19b3..4d18581ea 100644 --- a/tests/unit_tests/test_app.py +++ b/tests/unit_tests/test_app.py @@ -37,13 +37,17 @@ def test_read_main_input(cwd, expected_depletion_settings, codename, ext, reacto data_path = cwd / data_path main_input = str(data_path / f'{reactor_name}_input.json') out = read_main_input(main_input) - input_path, process_input_file, path_input_file, mpi_args, object_input = out + (input_path, process_input_file, path_input_file, mpi_args, + rebuild_saltproc_results, run_without_reprocessing, object_input) = out depcode_input, simulation_input, reactor_input = object_input assert input_path == data_path assert mpi_args is None + assert rebuild_saltproc_results == False + assert run_without_reprocessing == False + assert depcode_input['codename'] == codename assert depcode_input['geo_file_paths'][0] == \ str(data_path / (f'{reactor_name}_geometry_base' + ext)) @@ -154,7 +158,8 @@ def test_openmc_depletion_settings(cwd, expected_depletion_settings, filename): data_path = cwd / data_path main_input = str(data_path / f'{filename}_input.json') out = read_main_input(main_input) - input_path, process_input_file, path_input_file, mpi_args, object_input = out + (input_path, process_input_file, path_input_file, mpi_args, + rebuild_saltproc_results, run_without_reprocessing, object_input) = out depcode_input, simulation_input, reactor_input = object_input assert depcode_input['template_input_file_path'] == \ From 7e1e1764ca77c3d69e6f84a1a191c4bce39bb906 Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 6 Jul 2023 13:14:09 -0500 Subject: [PATCH 42/62] fix remaining CI tests --- .../database_storage/test.py | 4 +-- .../file_interface_openmc/test.py | 35 ++++++++++++++++++- tests/unit_tests/test_openmc_depcode.py | 25 ++++++++----- 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/tests/integration_tests/database_storage/test.py b/tests/integration_tests/database_storage/test.py index eb674d633..8930138e4 100644 --- a/tests/integration_tests/database_storage/test.py +++ b/tests/integration_tests/database_storage/test.py @@ -231,12 +231,12 @@ def test_store_depcode_metadata(simulation): """ # read data - simulation.sim_depcode.read_step_metadata() + simulation.sim_depcode.read_depcode_metadata() file = simulation.sim_depcode.template_input_file_path file_lines = simulation.sim_depcode.read_plaintext_file(file) simulation.sim_depcode.get_neutron_settings(file_lines) - init_info = simulation.sim_depcode.step_metadata + init_info = simulation.sim_depcode.depcode_metadata # we want to keep the old path for other sims, but for this # test we'll want a fresh db diff --git a/tests/integration_tests/file_interface_openmc/test.py b/tests/integration_tests/file_interface_openmc/test.py index 14be04681..98451d03a 100644 --- a/tests/integration_tests/file_interface_openmc/test.py +++ b/tests/integration_tests/file_interface_openmc/test.py @@ -173,7 +173,40 @@ def test_read_neutronics_parameters(setup, openmc_depcode): np.testing.assert_almost_equal(openmc_depcode.neutronics_parameters['keff_eds'], [1.05103269, 0.00466057]) np.testing.assert_almost_equal(openmc_depcode.neutronics_parameters['fission_mass_bds'], 72564.3093712) np.testing.assert_almost_equal(openmc_depcode.neutronics_parameters['fission_mass_eds'], 72557.3124427) - np.testing.assert_almost_equal(openmc_depcode.neutronics_parameters['breeding_ratio'], [0.97204677, 0.00752009]) + np.testing.assert_almost_equal(openmc_depcode.neutronics_parameters['breeding_ratio_bds'], [0.9521063, 0.0083894]) + np.testing.assert_almost_equal(openmc_depcode.neutronics_parameters['breeding_ratio_eds'], [0.97204677, 0.00752009]) + np.testing.assert_almost_equal(openmc_depcode.neutronics_parameters['beta_eff_bds'], + [[3.02722147e-03, 1.31653306e-05], + [2.56437016e-04, 2.34208212e-06], + [6.86216011e-04, 6.25698960e-06], + [5.37174557e-04, 4.87944274e-06], + [1.07088251e-03, 9.67739386e-06], + [3.49738100e-04, 3.15273093e-06], + [1.26773271e-04, 1.13579780e-06]]) + np.testing.assert_almost_equal(openmc_depcode.neutronics_parameters['beta_eff_eds'], + [[3.03212025e-03, 1.18380793e-05], + [2.56575834e-04, 2.09668680e-06], + [6.86750234e-04, 5.60655617e-06], + [5.37887361e-04, 4.38160078e-06], + [1.07311207e-03, 8.71598231e-06], + [3.50594025e-04, 2.84366514e-06], + [1.27200728e-04, 1.02827496e-06]]) + np.testing.assert_almost_equal(openmc_depcode.neutronics_parameters['delayed_neutrons_lambda_bds'], + [[3.73897612e+00, 2.28330678e-02], + [1.29055770e-02, 1.17473235e-04], + [3.47196633e-02, 3.15003298e-04], + [1.19315909e-01, 1.07374204e-03], + [2.87240700e-01, 2.55327461e-03], + [8.02702456e-01, 7.04572391e-03], + [2.48209181e+00, 2.15388393e-02]]) + np.testing.assert_almost_equal(openmc_depcode.neutronics_parameters['delayed_neutrons_lambda_eds'], + [[3.74309570e+00, 2.09128562e-02], + [1.29051655e-02, 1.05244668e-04], + [3.47182736e-02, 2.82594073e-04], + [1.19318603e-01, 9.66662533e-04], + [2.87320044e-01, 2.31172530e-03], + [8.03807356e-01, 6.42367636e-03], + [2.48502626e+00, 1.97411877e-02]]) assert openmc_depcode.neutronics_parameters['power_level'] == 2250000000.0 assert openmc_depcode.neutronics_parameters['burn_days'] == 3.0 openmc_depcode.output_path = old_output_path diff --git a/tests/unit_tests/test_openmc_depcode.py b/tests/unit_tests/test_openmc_depcode.py index 6da4ca6fb..8460e891f 100644 --- a/tests/unit_tests/test_openmc_depcode.py +++ b/tests/unit_tests/test_openmc_depcode.py @@ -6,22 +6,29 @@ import openmc + +def test_read_depcode_metadata(openmc_depcode): + old_output_path = openmc_depcode.output_path + openmc_depcode.output_path = Path(__file__).parents[1] / 'openmc_data/saltproc_runtime_ref' + openmc_depcode.read_depcode_metadata() + assert openmc_depcode.depcode_metadata['depcode_name'] == 'openmc' + assert openmc_depcode.depcode_metadata['depcode_version'] == '0.13.3' + assert openmc_depcode.depcode_metadata['title'] == '' + assert openmc_depcode.depcode_metadata['depcode_input_filename'] == '' + assert openmc_depcode.depcode_metadata['depcode_working_dir'] == \ + str((Path(__file__).parents[1] / 'openmc_data/saltproc_runtime_ref').resolve()) + + def test_read_step_metadata(openmc_depcode): old_output_path = openmc_depcode.output_path openmc_depcode.output_path = Path(__file__).parents[1] / 'openmc_data/saltproc_runtime_ref' openmc_depcode.read_step_metadata() - assert openmc_depcode.step_metadata['depcode_name'] == 'openmc' - assert openmc_depcode.step_metadata['depcode_version'] == '0.13.3' - assert openmc_depcode.step_metadata['title'] == '' - assert openmc_depcode.step_metadata['depcode_input_filename'] == '' - assert openmc_depcode.step_metadata['depcode_working_dir'] == \ - str((Path(__file__).parents[1] / 'openmc_data/saltproc_runtime_ref').resolve()) assert openmc_depcode.step_metadata['MPI_tasks'] == -1 assert openmc_depcode.step_metadata['OMP_threads'] == -1 assert openmc_depcode.step_metadata['memory_optimization_mode'] == -1 - assert openmc_depcode.step_metadata['depletion_timestep'] == 259200.0 - assert openmc_depcode.step_metadata['memory_usage'] == -1 - np.testing.assert_almost_equal(openmc_depcode.step_metadata['execution_time'], 423.90163846) + assert openmc_depcode.step_metadata['depletion_timestep_size'] == 259200.0 + assert openmc_depcode.step_metadata['step_memory_usage'] == -1 + np.testing.assert_almost_equal(openmc_depcode.step_metadata['step_execution_time'], 423.90163846) def test_check_for_material_names(cwd, openmc_depcode): From f7e8ce6187f938bdc88690ad84406ade99854ccb Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 6 Jul 2023 15:11:30 -0500 Subject: [PATCH 43/62] fix remaininbg integration tests --- doc/io_formats/saltproc_input.rst | 33 + saltproc/results.py | 54 +- .../pincell_reference_results.h5 | Bin 121707 -> 128810 bytes .../pincell_settings.xml | 1 - .../pincell_settings.xml | 1 - .../ref_saltproc_results.h5 | Bin 50378 -> 76838 bytes .../reference_error | 842 +++++++++--------- .../test_input.json | 4 +- .../run_no_reprocessing_openmc/test_openmc.py | 83 +- .../test_input.json | 4 +- .../test_serpent.py | 81 +- 11 files changed, 527 insertions(+), 576 deletions(-) diff --git a/doc/io_formats/saltproc_input.rst b/doc/io_formats/saltproc_input.rst index 36885ec68..4d75b7c8d 100644 --- a/doc/io_formats/saltproc_input.rst +++ b/doc/io_formats/saltproc_input.rst @@ -90,6 +90,39 @@ Required properties are as follows: ``proc_input_file``, ``dot_input_file``, ``o ``null`` +.. _rebuild_saltproc_results_property: + +``rebuild_saltproc_results`` +--------------------- + + :description: + Flag to reconstruct the ``saltproc_results.h5`` files from the stepwise + depletion simulation results. + + + :type: + ``boolean`` + + :default: + ``false`` + + +.. _run_without_reprocessing_property: + +``run_without_reprocessing`` +--------------------- + + :description: + Flag to run SaltProc with no material reprocessing. + + + :type: + ``boolean`` + + :default: + ``false`` + + .. _depcode_property: ``depcode`` diff --git a/saltproc/results.py b/saltproc/results.py index c8422f082..8d14530c0 100644 --- a/saltproc/results.py +++ b/saltproc/results.py @@ -4,9 +4,42 @@ import uncertainties.unumpy as unp class Results(): - """Interface class for reading SaltProc results""" - - def __init__(self, path): + """Interface class for reading SaltProc results. + + Parameters + ---------- + path + + Attributes + ---------- + + time_at_eds : numpy.ndarray + Cumulative time at each depletion step + time_total : numpy.ndarray + Cumulative time at each depletion step + and each processing step. + keff : numpy.ndarray + :math:`k_\text{eff}` at each depletion and ... + fisson_mass : numpy.ndarray + Mass of fissionable nuclides summed over all + depletable materials. + breeding_ratio : numpy.ndarray + Breeding ratio in the ... + power_level : numpy.ndarray + Power in [W]. + beta_eff : numpy.ndarray + ... + lambda_eff : numpy.ndarray + ... + depcode_metadata : ... + depletion_step_metadata : ... + nuclide_ids : ... + material_composition : ... + material_parameters : ... + waste_streams : ... + + """ + def __init__(self, path, load_in_out_streams=True): f = tb.open_file(path, mode='r') root = f.root sim_params = root.simulation_parameters @@ -33,7 +66,7 @@ def __init__(self, path): # Materials materials = root.materials - nuclide_idx, material_composition, material_parameters, waste_streams = self._collect_material_params(materials) + nuclide_idx, material_composition, material_parameters, waste_streams = self._collect_material_params(materials, load_in_out_streams) self.nuclide_idx = nuclide_idx self.material_composition = material_composition self.material_parameters = material_parameters @@ -68,7 +101,7 @@ def _collect_metadata(self, f, nodename, array=False): metadata[key] = value[0] return metadata - def _collect_material_params(self, materials): + def _collect_material_params(self, materials, load_in_out_streams): nuclide_idx = {} material_composition = {} material_parameters = {} @@ -87,11 +120,12 @@ def _collect_material_params(self, materials): # in and out streams waste_streams[mat_name] = {} - for stream_name in material.in_out_streams._v_groups.keys(): - waste_stream = material.in_out_streams[stream_name] - if len(waste_stream._v_children) > 0: - waste_streams[mat_name][stream_name] = \ - self._collect_waste_streams(waste_stream, stream_name) + if load_in_out_streams: + for stream_name in material.in_out_streams._v_groups.keys(): + waste_stream = material.in_out_streams[stream_name] + if len(waste_stream._v_children) > 0: + waste_streams[mat_name][stream_name] = \ + self._collect_waste_streams(waste_stream, stream_name) return nuclide_idx, material_composition, material_parameters, waste_streams diff --git a/tests/integration_tests/run_constant_reprocessing_openmc/pincell_reference_results.h5 b/tests/integration_tests/run_constant_reprocessing_openmc/pincell_reference_results.h5 index 4181f381667516a91a6a8b1692c9fbf054d2082f..d5fa687bf01f80e897bc796837653308de5fc50a 100644 GIT binary patch delta 30367 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 50 10 - 600.0 diff --git a/tests/integration_tests/run_no_reprocessing_openmc/pincell_settings.xml b/tests/integration_tests/run_no_reprocessing_openmc/pincell_settings.xml index aeee52690..af5376166 100644 --- a/tests/integration_tests/run_no_reprocessing_openmc/pincell_settings.xml +++ b/tests/integration_tests/run_no_reprocessing_openmc/pincell_settings.xml @@ -4,5 +4,4 @@ 1000 50 10 - 600.0 diff --git a/tests/integration_tests/run_no_reprocessing_openmc/ref_saltproc_results.h5 b/tests/integration_tests/run_no_reprocessing_openmc/ref_saltproc_results.h5 index ccbe6dad8d9840722be8c2f1d47848904e4e187f..1b093b583f4ac5d8944981a40f3f4cceaba8b3fd 100644 GIT binary patch literal 76838 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%0A}^V$LIxMRxf;vUI1qG z!q4ahpjIz@j9vg{^}@&K1z=V$e2iWIX7$3y=mlU_FMNz%0A}^V$LIxMRxf;vUI1qG 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 OCxlo^x-#)cD*qoLu^mMK diff --git a/tests/integration_tests/run_no_reprocessing_openmc/reference_error b/tests/integration_tests/run_no_reprocessing_openmc/reference_error index 296667752..5b2555c76 100644 --- a/tests/integration_tests/run_no_reprocessing_openmc/reference_error +++ b/tests/integration_tests/run_no_reprocessing_openmc/reference_error @@ -1,421 +1,421 @@ -6.393581858755221383e-30 --1.035983741214267698e-27 --6.629339758072523892e-30 --3.747089299799806076e-30 --1.323488980084844280e-22 --9.693522803355793065e-27 --5.293955920339377119e-23 -0.000000000000000000e+00 --6.018531076210112041e-36 -0.000000000000000000e+00 -0.000000000000000000e+00 -2.958228394578794270e-31 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -2.481541837659083025e-24 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --2.524354896707237777e-28 --4.963083675318166049e-24 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --2.375029507361377565e-27 --4.814824860968089633e-35 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -1.880790961315660013e-37 --1.292469707114105742e-26 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --6.649532885861751723e-21 --4.822462971184151345e-21 --1.323488980084844280e-23 -5.293955920339377119e-23 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --8.016683393511869238e-33 -0.000000000000000000e+00 -0.000000000000000000e+00 -4.814824860968089633e-35 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -2.204051907791789077e-39 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -1.577721810442023611e-30 -0.000000000000000000e+00 --2.648153673532449298e-34 --1.262177448353618889e-28 --3.541366997492649733e-24 -0.000000000000000000e+00 -1.809457589959748039e-25 -7.754818242684634452e-26 -0.000000000000000000e+00 -6.563399768636593710e-26 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -2.423380700838948266e-27 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -3.877409121342317226e-26 -4.038967834731580444e-27 -5.293955920339377119e-22 -1.447566071967798431e-24 --3.705769144237563983e-22 --2.249931266144235276e-22 -0.000000000000000000e+00 -3.013657883149332927e-27 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -1.938704560671158613e-26 -0.000000000000000000e+00 --3.466673899897024536e-33 -6.058451752097370666e-28 --4.239300639334266834e-24 --2.316105715148477490e-23 -4.632211430296954979e-23 -0.000000000000000000e+00 -0.000000000000000000e+00 --2.958228394578794270e-31 -0.000000000000000000e+00 -0.000000000000000000e+00 --6.203854594147707562e-25 -0.000000000000000000e+00 -0.000000000000000000e+00 -9.860761315262647568e-32 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -3.231174267785264355e-26 -7.888609052210118054e-31 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -1.262177448353618889e-28 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --3.029225876048685333e-28 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --1.694065894508600678e-21 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --3.944304526105059027e-30 --3.970466940254532839e-23 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --9.860761315262647568e-32 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --2.423380700838948266e-27 --1.164670302474662966e-21 --2.584939414228211484e-26 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -1.889818757929975181e-33 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --4.513898307157584031e-35 -0.000000000000000000e+00 -0.000000000000000000e+00 --3.155443620884047222e-30 -0.000000000000000000e+00 -0.000000000000000000e+00 -1.685188701338831371e-34 --5.609270963027824422e-32 -3.000955150395025098e-29 -0.000000000000000000e+00 -0.000000000000000000e+00 --6.776263578034402713e-21 --2.911675756186657416e-22 -0.000000000000000000e+00 -1.058791184067875424e-22 --5.823351512373314831e-22 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --9.740878893424453899e-21 -7.411538288475127967e-22 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --9.148167235839370302e-34 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --1.615587133892632177e-27 -0.000000000000000000e+00 --1.925929944387235853e-34 -0.000000000000000000e+00 --2.527783052008247057e-33 --4.108550239174832985e-30 --1.685188701338831371e-34 --3.815143960314673442e-28 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --2.117582368135750848e-22 -1.323488980084844280e-23 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -4.235164736271501695e-22 -0.000000000000000000e+00 -4.622231866529366047e-32 -8.788794008375919046e-25 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --6.617444900424221399e-22 --2.584939414228211484e-26 -2.091112588534053962e-21 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --6.617444900424221399e-24 -2.249931266144235276e-22 -0.000000000000000000e+00 --6.352747104407252543e-22 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --4.658681209898651865e-21 --1.482307657695025593e-21 -1.270549420881450509e-21 --8.470329472543003391e-22 -4.235164736271501695e-22 -7.093900933254765340e-21 -2.709460422752307069e-23 --2.339990317585287133e-28 -0.000000000000000000e+00 -0.000000000000000000e+00 -9.047287949798740194e-26 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -2.514629062161204132e-22 --8.271806125530276749e-25 -1.323488980084844280e-22 -1.522012327097570922e-22 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -5.082197683525802034e-21 -8.470329472543003391e-20 --7.284483346386982916e-19 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --2.481541837659083025e-23 --1.050131637030210915e-26 -3.896351557369781560e-20 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -3.877409121342317226e-24 --1.654361225106055350e-24 --2.646977960169688560e-23 -0.000000000000000000e+00 -0.000000000000000000e+00 --1.694065894508600678e-21 -0.000000000000000000e+00 -1.721299887796092044e-32 --7.632531243828569136e-27 --3.189339987905262573e-30 -0.000000000000000000e+00 --2.019483917365790222e-28 -0.000000000000000000e+00 --2.888894916580853780e-34 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -9.629649721936179265e-35 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -1.550963648536926890e-25 -1.972152263052529514e-31 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 --2.908056841006737919e-26 --7.888609052210118054e-31 -0.000000000000000000e+00 --1.270549420881450509e-21 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -1.768181277393351958e-20 --6.617444900424221399e-24 --1.795709848179116719e-19 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -0.000000000000000000e+00 -1.615587133892632177e-26 -1.728807480235827840e-22 -6.818615225397117729e-20 -0.000000000000000000e+00 -0.000000000000000000e+00 --1.016439536705160407e-20 --2.032879073410320814e-20 --9.486769009248163798e-20 +0.0 +0.0 +0.0 +0.0 +-6.617444900424222e-24 +0.0 +0.0 +0.0 +0.0 +0.0 +-4.930380657631324e-31 +0.0 +0.0 +0.0 +-3.009265538105056e-36 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +-3.2311742677852644e-27 +-3.877409121342317e-26 +-1.4791141972893971e-31 +0.0 +0.0 +-2.0679515313825692e-25 +0.0 +0.0 +8.271806125530277e-25 +-1.1555579666323415e-33 +0.0 +0.0 +2.6469779601696886e-23 +-2.6469779601696886e-23 +-2.117582368135751e-22 +0.0 +0.0 +-2.117582368135751e-22 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +-3.3881317890172014e-21 +-1.2924697071141057e-26 +0.0 +-9.244463733058732e-33 +1.6155871338926322e-27 +-1.6155871338926322e-27 +0.0 +5.522654816098038e-19 +2.290377089375628e-18 +2.0011153378882846e-20 +3.5486048278524887e-22 +4.909402962285925e-18 +1.122897681540735e-22 +1.0799670077492329e-19 +-1.0164395367051604e-20 +0.0 +-4.0657581468206416e-20 +-1.3552527156068805e-20 +-1.0503208545953324e-19 +0.0 +0.0 +-2.117582368135751e-22 +0.0 +1.1832913578315177e-30 +-6.617444900424222e-24 +-1.0339757656912846e-24 +0.0 +5.082197683525802e-20 +4.743384504624082e-20 +0.0 +4.2351647362715017e-20 +0.0 +8.011868568650901e-32 +1.1890721305449773e-24 +1.2407709188295415e-23 +0.0 +-1.3552527156068805e-20 +0.0 +-1.6940658945086007e-21 +9.529120656610879e-22 +0.0 +0.0 +6.564505341220828e-21 +0.0 +6.203854594147708e-25 +2.541098841762901e-21 +0.0 +0.0 +-5.293955920339377e-23 +0.0 +-1.3016204936146695e-29 +-1.852884572118782e-22 +0.0 +-2.1002632740604218e-26 +0.0 +-7.489798825710024e-21 +-5.22772977254685e-21 +0.0 +-3.970466940254533e-23 +3.970466940254533e-23 +-2.6469779601696886e-23 +0.0 +0.0 +2.524354896707238e-29 +0.0 +-1.2587480345416504e-24 +3.1638346569104994e-29 +0.0 +0.0 +-1.2924697071141057e-26 +0.0 +0.0 +0.0 +0.0 +2.514629062161204e-22 +-8.271806125530277e-25 +-1.5881867761018131e-22 +-6.617444900424221e-23 +0.0 +-1.9852334701272664e-23 +9.26442286059391e-23 +0.0 +-3.1763735522036263e-22 +0.0 +0.0 +0.0 +0.0 +-3.2311742677852644e-27 +3.101927297073854e-25 +0.0 +0.0 +-3.3881317890172014e-21 +0.0 +0.0 +-1.0587911840678754e-22 +0.0 +-8.470329472543003e-22 +1.2924697071141057e-25 +-1.3552527156068805e-20 +0.0 +0.0 +0.0 +0.0 +6.462348535570529e-27 +0.0 +0.0 +-2.541098841762901e-21 +0.0 +0.0 +0.0 +2.117582368135751e-22 +-4.0657581468206416e-20 +0.0 +-8.271806125530277e-25 +0.0 +0.0 +0.0 +0.0 +0.0 +-9.244463733058732e-33 +-2.4233807008389483e-27 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +-1.1832913578315177e-30 +0.0 +0.0 +-2.0328790734103208e-20 +0.0 +-1.0164395367051604e-20 +2.0328790734103208e-20 +0.0 +0.0 +0.0 +-2.5849394142282115e-26 +0.0 +1.0587911840678754e-22 +-3.3881317890172014e-21 +0.0 +8.470329472543003e-21 +-1.6940658945086007e-21 +3.3881317890172014e-21 +0.0 +0.0 +9.740878893424454e-21 +0.0 +0.0 +0.0 +0.0 +0.0 +1.2281977735187355e-20 +1.376428539288238e-21 +0.0 +2.541098841762901e-21 +-1.0587911840678754e-22 +1.1540823906339842e-20 +1.2924697071141057e-26 +8.077935669463161e-28 +-1.0587911840678754e-21 +-3.5155176033503676e-24 +1.291725244562808e-20 +3.441071348220595e-22 +-1.6543612251060553e-24 +0.0 +0.0 +-1.6155871338926322e-27 +1.209751645858803e-23 +3.8050308177439273e-23 +0.0 +3.3087224502121107e-23 +0.0 +5.37667398159468e-23 +2.50416005753358e-26 +0.0 +0.0 +2.145701662201152e-28 +-2.055026834311428e-23 +0.0 +-7.754818242684634e-26 +0.0 +4.52364397489937e-26 +4.733165431326071e-30 +0.0 +-7.153366036640847e-29 +-2.4233807008389483e-27 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +-1.0592614694129797e-33 +0.0 +-9.62964972193618e-35 +0.0 +-1.0344410472546892e-29 +-1.8184408451954978e-22 +-5.515358419680371e-23 +4.647195563142155e-22 +-1.4426860100818241e-24 +-7.817847306972832e-26 +-3.0108785044334803e-30 +-3.800367455409357e-27 +4.403937402452376e-23 +2.1021990959120226e-26 +-7.510587522725791e-29 +-3.3752704263273485e-23 +-5.1417420650970905e-24 +-4.4280703947439335e-27 +0.0 +0.0 +0.0 +0.0 +0.0 +3.4606553688208144e-35 +0.0 +0.0 +0.0 +-7.888609052210118e-31 +0.0 +-2.7685242950566515e-34 +-6.225059175280048e-26 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +5.169878828456423e-26 +0.0 +5.240936861163766e-32 +-1.355854680848614e-31 +2.208810534618833e-29 +0.0 +0.0 +1.6263032587282567e-19 +-6.183936465303629e-23 +3.87474277148267e-25 +0.0 +5.421010862427522e-20 +2.117582368135751e-22 +-4.1359030627651384e-24 +4.8467614016778965e-27 +4.930380657631324e-31 +0.0 +0.0 +2.643218478049957e-31 +4.1167179655501634e-23 +5.030072954528629e-26 +5.009266748153425e-29 +1.2157432773944426e-33 +1.0002263240136667e-26 +1.2759285881565438e-33 +-3.325617037048124e-21 +8.82773397047721e-22 +6.043873602568886e-25 +7.460330380827006e-29 +-5.008188227384568e-30 +-1.219210944097263e-22 +-1.091515252192121e-25 +1.1433860893838142e-29 +8.517425179052551e-32 +6.450525250137303e-37 +0.0 +-1.0122037705323662e-21 +-1.4535805861860903e-24 +-2.763413358466734e-28 +3.120487992393419e-31 +1.925929944387236e-34 +9.4039548065783e-38 +0.0 +1.8792261432358454e-31 +3.851859888774472e-34 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 \ No newline at end of file diff --git a/tests/integration_tests/run_no_reprocessing_openmc/test_input.json b/tests/integration_tests/run_no_reprocessing_openmc/test_input.json index cac753813..82fc41706 100644 --- a/tests/integration_tests/run_no_reprocessing_openmc/test_input.json +++ b/tests/integration_tests/run_no_reprocessing_openmc/test_input.json @@ -2,6 +2,7 @@ "proc_input_file": "processes.json", "dot_input_file": "paths.dot", "n_depletion_steps": 2, + "run_without_reprocessing": true, "depcode": { "codename": "openmc", @@ -17,8 +18,7 @@ } }, "simulation": { - "sim_name": "test_openmc_no_reprocessing", - "restart_flag": true + "sim_name": "test_openmc_no_reprocessing" }, "reactor": { "volume": 1.0, diff --git a/tests/integration_tests/run_no_reprocessing_openmc/test_openmc.py b/tests/integration_tests/run_no_reprocessing_openmc/test_openmc.py index fa09b11f2..9e8e52532 100644 --- a/tests/integration_tests/run_no_reprocessing_openmc/test_openmc.py +++ b/tests/integration_tests/run_no_reprocessing_openmc/test_openmc.py @@ -1,42 +1,31 @@ """Run SaltProc without reprocessing""" +import sys import shutil from pathlib import Path import numpy as np import pytest import tables as tb +import subprocess from openmc.deplete import Results from saltproc import app - -@pytest.fixture -def setup(): - cwd = Path(__file__).parents[0].resolve() - saltproc_input = cwd / 'test_input.json' - - input_path, process_input_file, path_input_file, mpi_args, object_input = \ - app.read_main_input(saltproc_input) - - depcode = app._create_depcode_object(object_input[0]) - - simulation = app._create_simulation_object(object_input[1], depcode) - - reactor = app._create_reactor_object(object_input[2]) - - return cwd, simulation, reactor - - @pytest.mark.slow -def test_integration_2step_saltproc_no_reproc_heavy(setup): - cwd, simulation, reactor = setup - runsim_no_reproc(simulation, reactor, 2) +def test_integration_2step_saltproc_no_reproc_heavy(): + cwd = str(Path(__file__).parents[0].resolve()) + args = ['python', '-m', 'saltproc', '-s', '12', '-i', cwd + '/test_input.json'] + subprocess.run( + args, + check=True, + cwd=cwd, + stdout=sys.stdout, + stderr=subprocess.STDOUT) - output_path = str(simulation.sim_depcode.output_path) ref_results = tb.File('ref_saltproc_results.h5') test_results = tb.File('saltproc_runtime/saltproc_results.h5') - ref_mdens_error = np.loadtxt(cwd / 'reference_error') + ref_mdens_error = np.loadtxt('reference_error') ref_fuel_mdens = ref_results.root.materials.fuel.before_reproc.comp[-1] test_fuel_mdens = test_results.root.materials.fuel.before_reproc.comp[-1] @@ -44,50 +33,4 @@ def test_integration_2step_saltproc_no_reproc_heavy(setup): test_mdens_error = np.array(ref_fuel_mdens) - np.array(test_fuel_mdens) np.testing.assert_array_almost_equal(test_mdens_error, ref_mdens_error) - shutil.rmtree(cwd / 'saltproc_runtime') - - -def runsim_no_reproc(simulation, reactor, nsteps): - """Run simulation sequence for integration test. No reprocessing - involved, just re-running depletion code for comparision with model - output. - - Parameters - ---------- - simulation : Simulation - Simulation object - reactor : Reactor - Contains information about power load curve and cumulative - depletion time for the integration test. - nsteps : int - Number of depletion time steps in integration test run. - - """ - - ###################################################################### - # Start sequence - for dep_step in range(nsteps): - print("\nStep #%i has been started" % (dep_step + 1)) - if dep_step == 0: # First step - simulation.sim_depcode.write_runtime_input( - reactor, - dep_step, - False) - simulation.sim_depcode.run_depletion_step() - # Read general simulation data which never changes - simulation.store_run_init_info() - # Parse and store data for initial state (beginning of dep_step) - mats = simulation.sim_depcode.read_depleted_materials( - False) - simulation.store_mat_data(mats, dep_step, False) - # Finish of First step - # Main sequence - else: - simulation.sim_depcode.run_depletion_step() - mats = simulation.sim_depcode.read_depleted_materials( - True) - simulation.store_mat_data(mats, dep_step, False) - simulation.store_run_step_info() - simulation.sim_depcode.update_depletable_materials( - mats, - simulation.burn_time) + shutil.rmtree('saltproc_runtime') diff --git a/tests/integration_tests/run_no_reprocessing_serpent/test_input.json b/tests/integration_tests/run_no_reprocessing_serpent/test_input.json index 676163fe0..61c2c46b6 100644 --- a/tests/integration_tests/run_no_reprocessing_serpent/test_input.json +++ b/tests/integration_tests/run_no_reprocessing_serpent/test_input.json @@ -2,6 +2,7 @@ "proc_input_file": "processes.json", "dot_input_file": "paths.dot", "n_depletion_steps": 2, + "run_without_reprocessing": true, "depcode": { "codename": "serpent", "template_input_file_path": "test_input.ini", @@ -9,8 +10,7 @@ "zaid_convention": "serpent" }, "simulation": { - "sim_name": "test_serpent_no_reprocessing", - "restart_flag": true + "sim_name": "test_serpent_no_reprocessing" }, "reactor": { "volume": 1.0, diff --git a/tests/integration_tests/run_no_reprocessing_serpent/test_serpent.py b/tests/integration_tests/run_no_reprocessing_serpent/test_serpent.py index 2f326fef3..bdf08c6a0 100644 --- a/tests/integration_tests/run_no_reprocessing_serpent/test_serpent.py +++ b/tests/integration_tests/run_no_reprocessing_serpent/test_serpent.py @@ -1,39 +1,28 @@ """Run SaltProc without reprocessing""" from pathlib import Path +import sys import shutil import numpy as np import pytest +import subprocess import serpentTools from saltproc import app - -@pytest.fixture -def setup(): - cwd = str(Path(__file__).parents[0].resolve()) - saltproc_input = cwd + '/test_input.json' - - input_path, process_input_file, path_input_file, mpi_args, object_input = \ - app.read_main_input(saltproc_input) - - depcode = app._create_depcode_object(object_input[0]) - - simulation = app._create_simulation_object(object_input[1], depcode) - - reactor = app._create_reactor_object(object_input[2]) - - return cwd, simulation, reactor - - @pytest.mark.slow -def test_integration_2step_saltproc_no_reproc_heavy(setup): - cwd, simulation, reactor = setup - runsim_no_reproc(simulation, reactor, 2) +def test_integration_2step_saltproc_no_reproc_heavy(): + cwd = str(Path(__file__).parents[0].resolve()) + args = ['python', '-m', 'saltproc', '-s', '12', '-i', cwd + '/test_input.json'] + subprocess.run( + args, + check=True, + cwd=cwd, + stdout=sys.stdout, + stderr=subprocess.STDOUT) - output_path = str(simulation.sim_depcode.output_path) ref_result = serpentTools.read(cwd + '/reference_dep.m') - test_result = serpentTools.read(f'{output_path}/runtime_input.serpent_dep.m') + test_result = serpentTools.read(cwd + '/saltproc_runtime/step_1_data/runtime_input.serpent_dep.m') ref_mdens_error = np.loadtxt(cwd + '/reference_error') @@ -44,49 +33,3 @@ def test_integration_2step_saltproc_no_reproc_heavy(setup): np.testing.assert_array_almost_equal(test_mdens_error, ref_mdens_error) shutil.rmtree(cwd + '/saltproc_runtime') - - -def runsim_no_reproc(simulation, reactor, nsteps): - """Run simulation sequence for integration test. No reprocessing - involved, just re-running depletion code for comparision with model - output. - - Parameters - ---------- - simulation : Simulation - Simulation object - reactor : Reactor - Contains information about power load curve and cumulative - depletion time for the integration test. - nsteps : int - Number of depletion time steps in integration test run. - - """ - - ###################################################################### - # Start sequence - for dep_step in range(nsteps): - print("\nStep #%i has been started" % (dep_step + 1)) - if dep_step == 0: # First step - simulation.sim_depcode.write_runtime_input( - reactor, - dep_step, - False) - simulation.sim_depcode.run_depletion_step() - # Read general simulation data which never changes - simulation.store_run_init_info() - # Parse and store data for initial state (beginning of dep_step) - mats = simulation.sim_depcode.read_depleted_materials( - False) - simulation.store_mat_data(mats, dep_step, False) - # Finish of First step - # Main sequence - else: - simulation.sim_depcode.run_depletion_step() - mats = simulation.sim_depcode.read_depleted_materials( - True) - simulation.store_mat_data(mats, dep_step, False) - simulation.store_run_step_info() - simulation.sim_depcode.update_depletable_materials( - mats, - simulation.burn_time) From 3783b4a2411c37d7e74c923d84345329990e26bf Mon Sep 17 00:00:00 2001 From: yardasol Date: Mon, 10 Jul 2023 15:12:43 -0500 Subject: [PATCH 44/62] fix integration tests --- doc/io_formats/depcode_input.rst | 17 - saltproc/input_schema.json | 5 - saltproc/openmc_depcode.py | 9 +- saltproc/results.py | 52 +- tests/conftest.py | 13 + tests/integration_tests/__init__.py | 3 + .../pincell_reference_results.h5 | Bin 128810 -> 118433 bytes .../run_constant_reprocessing_openmc/test.py | 9 +- .../run_constant_reprocessing_serpent/test.py | 3 +- .../ref_saltproc_results.h5 | Bin 76838 -> 67065 bytes .../reference_error | 653 +++--- .../run_no_reprocessing_openmc/test_openmc.py | 51 +- .../test_serpent.py | 13 +- tests/openmc_data/depletion_settings.json | 1 - tests/openmc_data/msbr_geometry_base.xml | 1822 ++++++++--------- tests/openmc_data/msbr_geometry_switch.xml | 1800 ++++++++-------- tests/openmc_data/msbr_materials_ao.xml | 2 +- tests/openmc_data/msbr_materials_nameless.xml | 2 +- tests/openmc_data/msbr_materials_wo.xml | 2 +- tests/openmc_data/msbr_settings.xml | 2 +- tests/unit_tests/__init__.py | 0 21 files changed, 2158 insertions(+), 2301 deletions(-) create mode 100644 tests/integration_tests/__init__.py create mode 100644 tests/unit_tests/__init__.py diff --git a/doc/io_formats/depcode_input.rst b/doc/io_formats/depcode_input.rst index 1d2714f51..7baf80643 100644 --- a/doc/io_formats/depcode_input.rst +++ b/doc/io_formats/depcode_input.rst @@ -366,23 +366,6 @@ OpenMC-specific properties ``null`` -``dilute_initial`` -~~~~~~~~~~~~~~~~~~ - - :description: - Initial atom density to add for nuclides that are zero in initial - condition. - - :type: - ``number`` - - :minimum: - 0 - - :default: - 1000 - - ``fission_yield_mode`` ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/saltproc/input_schema.json b/saltproc/input_schema.json index 3dd9ab501..fcd50fbbb 100644 --- a/saltproc/input_schema.json +++ b/saltproc/input_schema.json @@ -216,11 +216,6 @@ "description": "Path to fission Q values", "type": ["string", "null"], "default": null}, - "dilute_initial": { - "description": "Initial atom density to add for nuclides that are zero in initial condition.", - "type": "number", - "minimum": 0, - "default": 1000}, "fission_yield_mode": { "description": "Determine what fission energy helper is used", "type": "string", diff --git a/saltproc/openmc_depcode.py b/saltproc/openmc_depcode.py index 08c763ddb..a4b1c93db 100644 --- a/saltproc/openmc_depcode.py +++ b/saltproc/openmc_depcode.py @@ -11,7 +11,7 @@ from saltproc import Materialflow from saltproc.depcode import Depcode from openmc.deplete.abc import _SECONDS_PER_DAY -from openmc.deplete import Results, Chain, MicroXS +from openmc.deplete import Results, Chain from openmc.mgxs import Beta, DecayRate, EnergyGroups from openmc.data import atomic_mass, DataLibrary, JOULE_PER_EV @@ -444,12 +444,7 @@ def write_runtime_input(self, reactor, depletion_step, restart): self.inactive_cycles = settings.inactive self.active_cycles = settings.batches - self.inactive_cycles - diluted_model = openmc.Model(materials=materials, geometry=geometry, settings=settings) - reactions, diluted_materials = MicroXS._add_dilute_nuclides(self.chain_file_path, - diluted_model, - 1e3) - - diluted_materials.export_to_xml(self.runtime_matfile) + materials.export_to_xml(self.runtime_matfile) geometry.export_to_xml(self.runtime_inputfile['geometry']) settings.export_to_xml(self.runtime_inputfile['settings']) self.write_depletion_settings(reactor, depletion_step) diff --git a/saltproc/results.py b/saltproc/results.py index 8d14530c0..179e98406 100644 --- a/saltproc/results.py +++ b/saltproc/results.py @@ -8,7 +8,10 @@ class Results(): Parameters ---------- - path + path : str + Path of results file + load_in_out_streams : bool + Switch on whether or not to load waste streams. Attributes ---------- @@ -28,15 +31,25 @@ class Results(): power_level : numpy.ndarray Power in [W]. beta_eff : numpy.ndarray - ... + Timeseries of delayed neutron fractions. lambda_eff : numpy.ndarray - ... - depcode_metadata : ... - depletion_step_metadata : ... - nuclide_ids : ... - material_composition : ... - material_parameters : ... - waste_streams : ... + Timesereis of delayed neutron precursor decay constants. + depcode_metadata : dict of str to object + Depletion code metadata, such as depletion code name, version, etc. + depletion_step_metadata : dict of str to object + Depletion step metadata, such as step runtime, memory usage, etc. + nuclide_idx : dict of str to int + A dictionary mapping nuclide name as a string to index. + material_composition : dict of str to numpy.ndarray + A dictionary mapping material name as a string to nuclide composition + over time. + material_parameters : dict of str to object + A dictionary mapping material name as a string to material parameters + (density, volume, burnup, etc.) + waste_streams : dict of str to dict + A dictionary mapping material name as a string to a dictionary mapping + waste stream names as a string to the waste streams mass [g] as a + timeseries. """ def __init__(self, path, load_in_out_streams=True): @@ -59,10 +72,6 @@ def __init__(self, path, load_in_out_streams=True): # metadata self.depcode_metadata = self._collect_metadata(f, 'depcode_metadata') self.depletion_step_metadata = self._collect_metadata(f, 'depletion_step_metadata', array=True) - #metadata = pd.DataFrame.from_records(metadata[:]).to_dict() - #for key, value in metadata.items(): - # metadata[key] = value[0#] - ##self.depcode_metadata = metadata # Materials materials = root.materials @@ -171,6 +180,23 @@ def _collect_waste_streams(self, waste_stream, stream_name): # methods to get timeseries of various values def get_nuclide_mass(self, material, nuclide, timestep=None): + """Get nuclide mass as a timeseries. If :attr:`timestep` is `None`, + then return the mass at all times. + + Parameters + ---------- + material : str + Material name + nuclide : str + Nuclide string (e.g. 'U235') + timestep : idx + Timestep index + + Returns + ------- + nuclide_mass : numpy.ndarray + + """ nucmap = self.nuclide_idx[material] comp = self.material_composition[material] nuclide_mass = comp[nucmap[nuclide]] diff --git a/tests/conftest.py b/tests/conftest.py index ff149a8c5..1e8786334 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,10 +1,23 @@ from pathlib import Path import pytest +from tests.integration_tests import config as integration_config + from saltproc.app import read_main_input, _create_depcode_object, _create_simulation_object, _create_reactor_object from saltproc import Simulation +def pytest_addoption(parser): + parser.addoption('--update', action='store_true') + + +def pytest_configure(config): + opts = ['update'] + for opt in opts: + if config.getoption(opt) is not None: + integration_config[opt] = config.getoption(opt) + + @pytest.fixture(scope='session') def cwd(): return Path(__file__).parents[0] diff --git a/tests/integration_tests/__init__.py b/tests/integration_tests/__init__.py new file mode 100644 index 000000000..7a5c24d31 --- /dev/null +++ b/tests/integration_tests/__init__.py @@ -0,0 +1,3 @@ +config = { + 'update': False +} diff --git a/tests/integration_tests/run_constant_reprocessing_openmc/pincell_reference_results.h5 b/tests/integration_tests/run_constant_reprocessing_openmc/pincell_reference_results.h5 index d5fa687bf01f80e897bc796837653308de5fc50a..943d3f33654f5fb133463088c41117d282fdebf3 100644 GIT binary patch literal 118433 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 Q%Ry=T;mK#7qz=db0(B8d{Qv*} literal 128810 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ðCt&yh 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 HzV`nCf%MAh diff --git a/tests/integration_tests/run_constant_reprocessing_openmc/test.py b/tests/integration_tests/run_constant_reprocessing_openmc/test.py index 68e066814..5ef3ef2a4 100644 --- a/tests/integration_tests/run_constant_reprocessing_openmc/test.py +++ b/tests/integration_tests/run_constant_reprocessing_openmc/test.py @@ -1,4 +1,6 @@ """Run SaltProc with reprocessing""" +from tests.integration_tests import config + import os import shutil from pathlib import Path @@ -35,12 +37,15 @@ def test_integration_2step_constant_ideal_removal_heavy(setup): args, check=True, cwd=cwd, - stdout=sys.stdout, + stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) + if config['update']: + shutil.copyfile(test_db, ref_db) + return np.testing.assert_allclose(read_keff(test_db), read_keff(ref_db), atol=atol) assert_db_allclose(test_db, ref_db, atol, rtol) - #shutil.rmtree(cwd / 'saltproc_runtime') + shutil.rmtree(cwd / 'saltproc_runtime') def read_keff(file): db = tb.open_file(file, mode='r') diff --git a/tests/integration_tests/run_constant_reprocessing_serpent/test.py b/tests/integration_tests/run_constant_reprocessing_serpent/test.py index f72e76c8c..7e03d2fc8 100644 --- a/tests/integration_tests/run_constant_reprocessing_serpent/test.py +++ b/tests/integration_tests/run_constant_reprocessing_serpent/test.py @@ -31,8 +31,9 @@ def test_integration_2step_constant_ideal_removal_heavy(setup): args, check=True, cwd=cwd, - stdout=sys.stdout, + stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) + np.testing.assert_allclose(read_keff(test_db)[0], read_keff(ref_db)[0], rtol=5e-2) np.testing.assert_allclose(read_keff(test_db)[1], read_keff(ref_db)[1], rtol=5e-1) assert_db_allclose(test_db, ref_db, tol) diff --git a/tests/integration_tests/run_no_reprocessing_openmc/ref_saltproc_results.h5 b/tests/integration_tests/run_no_reprocessing_openmc/ref_saltproc_results.h5 index 1b093b583f4ac5d8944981a40f3f4cceaba8b3fd..8a64b037eda7aeeae9befbb86d4da8d7e684cb77 100644 GIT binary patch literal 67065 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 literal 76838 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%0A}^V$LIxMRxf;vUI1qG z!q4ahpjIz@j9vg{^}@&K1z=V$e2iWIX7$3y=mlU_FMNz%0A}^V$LIxMRxf;vUI1qG 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 1e-15: + mass += [m] + return mass + ref_fuel_mass = _get_nucs(ref_results) + test_fuel_mass = _get_nucs(test_results) + + test_mass_error = np.array(ref_fuel_mass) - np.array(test_fuel_mass) + with open(cwd + '/test_error', mode='w') as f: + test_mass_error.tofile(f, sep='\n') + + if config['update']: + with open(cwd + '/reference_error', mode='w') as f: + test_mass_error.tofile(f, sep='\n') + return + + ref_mass_error = np.loadtxt(cwd + '/reference_error') + np.testing.assert_array_almost_equal(test_mass_error, ref_mass_error) + + shutil.rmtree(cwd + '/saltproc_runtime') diff --git a/tests/integration_tests/run_no_reprocessing_serpent/test_serpent.py b/tests/integration_tests/run_no_reprocessing_serpent/test_serpent.py index bdf08c6a0..b5992e64a 100644 --- a/tests/integration_tests/run_no_reprocessing_serpent/test_serpent.py +++ b/tests/integration_tests/run_no_reprocessing_serpent/test_serpent.py @@ -18,18 +18,23 @@ def test_integration_2step_saltproc_no_reproc_heavy(): args, check=True, cwd=cwd, - stdout=sys.stdout, + stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) - ref_result = serpentTools.read(cwd + '/reference_dep.m') - test_result = serpentTools.read(cwd + '/saltproc_runtime/step_1_data/runtime_input.serpent_dep.m') + test_path = cwd + '/saltproc_runtime/step_1_data/runtime_input.serpent_dep.m' + ref_path = cwd + '/reference_dep.m' + + ref_result = serpentTools.read(ref_path) + test_result = serpentTools.read(test_path) - ref_mdens_error = np.loadtxt(cwd + '/reference_error') ref_fuel_mdens = ref_result.materials['fuel'].mdens[:, -2] test_fuel_mdens = test_result.materials['fuel'].mdens[:, -1] test_mdens_error = np.array(ref_fuel_mdens - test_fuel_mdens) + + ref_mdens_error = np.loadtxt(cwd + '/reference_error') + np.testing.assert_array_almost_equal(test_mdens_error, ref_mdens_error) shutil.rmtree(cwd + '/saltproc_runtime') diff --git a/tests/openmc_data/depletion_settings.json b/tests/openmc_data/depletion_settings.json index 5a0a6c7d3..bd8bd1bc5 100644 --- a/tests/openmc_data/depletion_settings.json +++ b/tests/openmc_data/depletion_settings.json @@ -3,7 +3,6 @@ "fission_q": "serpent_fissq.json", "diff_burnable_mats": false, "normalization_mode": "fission-q", - "dilute_initial": 1000, "fission_yield_mode": "constant", "fission_yield_opts": null, "reaction_rate_mode": "direct", diff --git a/tests/openmc_data/msbr_geometry_base.xml b/tests/openmc_data/msbr_geometry_base.xml index 259d3d628..8e4524714 100644 --- a/tests/openmc_data/msbr_geometry_base.xml +++ b/tests/openmc_data/msbr_geometry_base.xml @@ -1,319 +1,319 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10.16 10.16 45 45 @@ -373,600 +373,600 @@ 9 10 10 9 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/openmc_data/msbr_geometry_switch.xml b/tests/openmc_data/msbr_geometry_switch.xml index b393d870e..4544c2386 100644 --- a/tests/openmc_data/msbr_geometry_switch.xml +++ b/tests/openmc_data/msbr_geometry_switch.xml @@ -1,308 +1,308 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10.16 10.16 45 45 @@ -362,600 +362,600 @@ 9 9 9 9 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/openmc_data/msbr_materials_ao.xml b/tests/openmc_data/msbr_materials_ao.xml index 90892be5d..f629d69ce 100644 --- a/tests/openmc_data/msbr_materials_ao.xml +++ b/tests/openmc_data/msbr_materials_ao.xml @@ -1,4 +1,4 @@ - + diff --git a/tests/openmc_data/msbr_materials_nameless.xml b/tests/openmc_data/msbr_materials_nameless.xml index a6209d41d..994dd96b5 100644 --- a/tests/openmc_data/msbr_materials_nameless.xml +++ b/tests/openmc_data/msbr_materials_nameless.xml @@ -1,4 +1,4 @@ - + diff --git a/tests/openmc_data/msbr_materials_wo.xml b/tests/openmc_data/msbr_materials_wo.xml index ae04a68cc..4562c0224 100644 --- a/tests/openmc_data/msbr_materials_wo.xml +++ b/tests/openmc_data/msbr_materials_wo.xml @@ -1,4 +1,4 @@ - + diff --git a/tests/openmc_data/msbr_settings.xml b/tests/openmc_data/msbr_settings.xml index aab04d40f..1a7702523 100644 --- a/tests/openmc_data/msbr_settings.xml +++ b/tests/openmc_data/msbr_settings.xml @@ -1,4 +1,4 @@ - + eigenvalue 1000 diff --git a/tests/unit_tests/__init__.py b/tests/unit_tests/__init__.py new file mode 100644 index 000000000..e69de29bb From 9edeb1dede7311ebb2359cf8645cc2011576005b Mon Sep 17 00:00:00 2001 From: yardasol Date: Wed, 19 Jul 2023 11:32:38 -0500 Subject: [PATCH 45/62] fix issue with decay-only nuclides --- examples/msbr/msbr_openmc.json | 3 ++- saltproc/openmc_depcode.py | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/examples/msbr/msbr_openmc.json b/examples/msbr/msbr_openmc.json index 9beb88576..fb45b8994 100644 --- a/examples/msbr/msbr_openmc.json +++ b/examples/msbr/msbr_openmc.json @@ -12,7 +12,8 @@ "chain_file_path": "chain_endfb71_pwr.xml", "depletion_settings": { "operator_kwargs": { - "fission_q": "serpent_fissq.json" + "fission_q": "serpent_fissq.json", + "fission_yield_mode": "average" } } }, diff --git a/saltproc/openmc_depcode.py b/saltproc/openmc_depcode.py index a4b1c93db..cde724002 100644 --- a/saltproc/openmc_depcode.py +++ b/saltproc/openmc_depcode.py @@ -286,9 +286,13 @@ def read_depleted_materials(self, read_at_end=False): results_file = Path(self.output_path / 'depletion_results.h5') depleted_materials = {} results = Results(results_file) - depleted_openmc_materials = results.export_to_materials(moment) + + # Get decay and transport nuclides + nucs = list(results[-1].index_nuc.keys()) + depleted_openmc_materials = results.export_to_materials(moment, nuclides_with_data=nucs) if read_at_end: - starting_openmc_materials = results.export_to_materials(0) + _nucs = list(results[0].index_nuc.keys()) + starting_openmc_materials = results.export_to_materials(0, nuclides_with_data=nucs) else: # placeholder for starting materials starting_openmc_materials = np.zeros(len(depleted_openmc_materials)) @@ -512,6 +516,7 @@ def update_depletable_materials(self, mats, dep_end_time): openmc.reset_auto_ids() runtime_materials = openmc.Materials.from_xml(self.runtime_matfile) + breakpoint() for material in runtime_materials: # depletable materials only if material.name in mats.keys(): From 24c742923eb3e4c9b8b7faa2e2e00fc421546a64 Mon Sep 17 00:00:00 2001 From: yardasol Date: Wed, 19 Jul 2023 15:29:26 -0500 Subject: [PATCH 46/62] fix endb71 data library --- examples/msbr/msbr_endfb71.serpent | 1 - scripts/README.md | 7 +- scripts/xsdata/branching_ratios_pwr.json | 1 + scripts/xsdata/create_chain_from_endfb71.py | 17 +--- scripts/xsdata/download_endfb71.bash | 43 ++++++++- scripts/xsdata/serpent_branching_ratios.csv | 101 -------------------- 6 files changed, 54 insertions(+), 116 deletions(-) create mode 100644 scripts/xsdata/branching_ratios_pwr.json delete mode 100644 scripts/xsdata/serpent_branching_ratios.csv diff --git a/examples/msbr/msbr_endfb71.serpent b/examples/msbr/msbr_endfb71.serpent index f6d7a8214..d6f8a1ab7 100644 --- a/examples/msbr/msbr_endfb71.serpent +++ b/examples/msbr/msbr_endfb71.serpent @@ -54,7 +54,6 @@ set title "MSBR Saltproc long-term, 91% removal, BOL, fresh fuel, ENDF" set acelib "endfb71.xsdata" set declib "endfb71.decay" set nfylib "endfb71.nfy" -set sfylib "endfb71.sfy" % --- Neutron population and criticality cycles: diff --git a/scripts/README.md b/scripts/README.md index 7ccb47a6f..4d2cec2a2 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -2,6 +2,9 @@ This directory contains various scripts to help you set-up and analyze results of your SaltProc simulations. +When passing paths of directories to scripts, make sure to remove any +trailing `/` to ensure they produce correct files. + ### `xsdata` The scripts in this directory download and processe cross section data for use in Serpent and OpenMC @@ -45,7 +48,9 @@ section libraries. Running the script without setting `XSDIR` will install the c #### `process_endfb71_to_openmc.bash` Processes the endfb71 library created by the previous script into -OpenMC's HDF5 format for cross section data on a UNIX-like machine. +OpenMC's HDF5 format for cross section data on a UNIX-like machine +as well as a depletion chain utilizing Serpent2's default branching +ratios. Branching ratios are obtained from [this](https://github.com/openmc-dev/data/blob/master/depletion/branching_ratios_pwr.json) file. *You must have installed OpenMC on your machine and have openmc repo on your machine in order for this script to work* diff --git a/scripts/xsdata/branching_ratios_pwr.json b/scripts/xsdata/branching_ratios_pwr.json new file mode 100644 index 000000000..5272b9406 --- /dev/null +++ b/scripts/xsdata/branching_ratios_pwr.json @@ -0,0 +1 @@ +{"Na23": {"Na24": 0.232, "Na24_m1": 0.768}, "Cl37": {"Cl38": 0.8809, "Cl38_m1": 0.1191}, "Sc45": {"Sc46": 0.556, "Sc46_m1": 0.444}, "Co59": {"Co60": 0.444, "Co60_m1": 0.556}, "Ge72": {"Ge73": 0.5012, "Ge73_m1": 0.4988}, "Ge74": {"Ge75": 0.666, "Ge75_m1": 0.334}, "Ge76": {"Ge77": 0.4005, "Ge77_m1": 0.5995}, "Se76": {"Se77": 0.7409, "Se77_m1": 0.2591}, "Se78": {"Se79": 0.1178, "Se79_m1": 0.8822}, "Se80": {"Se81": 0.8454, "Se81_m1": 0.1546}, "Se82": {"Se83": 0.1402, "Se83_m1": 0.8598}, "Br79": {"Br80": 0.7687, "Br80_m1": 0.2313}, "Br81": {"Br82": 0.0914, "Br82_m1": 0.9086}, "Kr78": {"Kr79": 0.9704, "Kr79_m1": 0.0296}, "Kr80": {"Kr81": 0.6031, "Kr81_m1": 0.3969}, "Kr82": {"Kr83": 0.333, "Kr83_m1": 0.667}, "Kr84": {"Kr85": 0.1839, "Kr85_m1": 0.8161}, "Rb85": {"Rb86": 0.8791, "Rb86_m1": 0.1209}, "Sr84": {"Sr85": 0.253, "Sr85_m1": 0.747}, "Sr86": {"Sr87": 0.1988, "Sr87_m1": 0.8012}, "Y89": {"Y90": 0.9979, "Y90_m1": 0.0021}, "Y90": {"Y91": 0.7496, "Y91_m1": 0.2504}, "Nb93": {"Nb94": 0.3101, "Nb94_m1": 0.6899}, "Nb94": {"Nb95": 0.961, "Nb95_m1": 0.039}, "Mo92": {"Mo93": 0.9978, "Mo93_m1": 0.0022}, "Rh103": {"Rh104": 0.924, "Rh104_m1": 0.076}, "Rh105": {"Rh106": 0.904, "Rh106_m1": 0.096}, "Pd106": {"Pd107": 0.9527, "Pd107_m1": 0.0473}, "Pd108": {"Pd109": 0.9779, "Pd109_m1": 0.0221}, "Pd110": {"Pd111": 0.85, "Pd111_m1": 0.15}, "Ag107": {"Ag108": 0.9898, "Ag108_m1": 0.0102}, "Ag109": {"Ag110": 0.954, "Ag110_m1": 0.046}, "Cd110": {"Cd111": 0.9945, "Cd111_m1": 0.0055}, "Cd112": {"Cd113": 0.8685, "Cd113_m1": 0.1315}, "Cd114": {"Cd115": 0.8812, "Cd115_m1": 0.1188}, "Cd116": {"Cd117": 0.666, "Cd117_m1": 0.334}, "In113": {"In114": 0.4191, "In114_m1": 0.5809}, "Sn112": {"Sn113": 0.7253, "Sn113_m1": 0.2747}, "Sn116": {"Sn117": 0.9568, "Sn117_m1": 0.0432}, "Sn118": {"Sn119": 0.9794, "Sn119_m1": 0.0206}, "Sn120": {"Sn121": 0.9875, "Sn121_m1": 0.0125}, "Sn122": {"Sn123": 0.0112, "Sn123_m1": 0.9888}, "Sn124": {"Sn125": 0.0375, "Sn125_m1": 0.9625}, "Sn126": {"Sn127": 0.3018, "Sn127_m1": 0.6982}, "Sb121": {"Sb122": 0.9369, "Sb122_m1": 0.0631}, "Te120": {"Te121": 0.8871, "Te121_m1": 0.1129}, "Te122": {"Te123": 0.6448, "Te123_m1": 0.3552}, "Te124": {"Te125": 0.9912, "Te125_m1": 0.0088}, "Te126": {"Te127": 0.8689, "Te127_m1": 0.1311}, "Te128": {"Te129": 0.9245, "Te129_m1": 0.0755}, "Te130": {"Te131": 0.8559, "Te131_m1": 0.1441}, "Te132": {"Te133": 0.8517, "Te133_m1": 0.1483}, "I129": {"I130": 0.413, "I130_m1": 0.587}, "I131": {"I132": 0.9839, "I132_m1": 0.0161}, "Xe124": {"Xe125": 0.83, "Xe125_m1": 0.17}, "Xe126": {"Xe127": 0.8691, "Xe127_m1": 0.1309}, "Xe128": {"Xe129": 0.8923, "Xe129_m1": 0.1077}, "Xe130": {"Xe131": 0.9164, "Xe131_m1": 0.0836}, "Xe132": {"Xe133": 0.8867, "Xe133_m1": 0.1133}, "Xe133": {"Xe134": 0.96, "Xe134_m1": 0.04}, "Xe134": {"Xe135": 0.9853, "Xe135_m1": 0.0147}, "Cs133": {"Cs134": 0.907, "Cs134_m1": 0.093}, "Cs134": {"Cs135": 0.996, "Cs135_m1": 0.004}, "Cs135": {"Cs136": 0.984, "Cs136_m1": 0.016}, "Cs137": {"Cs138": 0.9021, "Cs138_m1": 0.0979}, "Ba130": {"Ba131": 0.8871, "Ba131_m1": 0.1129}, "Ba132": {"Ba133": 0.9175, "Ba133_m1": 0.0825}, "Ba134": {"Ba135": 0.9263, "Ba135_m1": 0.0737}, "Ba135": {"Ba136": 0.9978, "Ba136_m1": 0.0022}, "Ba136": {"Ba137": 0.9731, "Ba137_m1": 0.0269}, "Ce136": {"Ce137": 0.8662, "Ce137_m1": 0.1338}, "Ce138": {"Ce139": 0.9787, "Ce139_m1": 0.0213}, "Pr141": {"Pr142": 0.6519, "Pr142_m1": 0.3481}, "Pr143": {"Pr144": 0.31, "Pr144_m1": 0.69}, "Pm147": {"Pm148": 0.533, "Pm148_m1": 0.467}, "Eu153": {"Eu154": 0.984, "Eu154_m1": 0.016}, "Dy164": {"Dy165": 0.37, "Dy165_m1": 0.63}, "Ho165": {"Ho166": 0.949, "Ho166_m1": 0.051}, "Er166": {"Er167": 0.2503, "Er167_m1": 0.7497}, "Lu175": {"Lu176": 0.3331, "Lu176_m1": 0.6669}, "Lu176": {"Lu177": 0.999, "Lu177_m1": 0.001}, "Hf179": {"Hf180": 0.991, "Hf180_m1": 0.009}, "W182": {"W183": 0.8699, "W183_m1": 0.1301}, "W184": {"W185": 0.9983, "W185_m1": 0.0017}, "Re185": {"Re186": 0.999, "Re186_m1": 0.001}, "Re187": {"Re188": 0.9729, "Re188_m1": 0.0271}, "Au197": {"Au198": 0.999, "Au198_m1": 0.001}, "Hg196": {"Hg197": 0.966, "Hg197_m1": 0.034}, "Hg198": {"Hg199": 0.9918, "Hg199_m1": 0.0082}, "Pb206": {"Pb207": 0.9783, "Pb207_m1": 0.0217}, "Bi209": {"Bi210": 0.6791, "Bi210_m1": 0.3209}, "Pa233": {"Pa234": 0.4871, "Pa234_m1": 0.5129}, "U234": {"U235": 0.5, "U235_m1": 0.5}, "Np235": {"Np236": 0.4, "Np236_m1": 0.6}, "Np239": {"Np240": 0.3573, "Np240_m1": 0.6427}, "Pu236": {"Pu237": 0.5001, "Pu237_m1": 0.4999}, "Am241": {"Am242": 0.919, "Am242_m1": 0.081}, "Am243": {"Am244": 0.0626, "Am244_m1": 0.9374}, "Bk247": {"Bk248": 0.4, "Bk248_m1": 0.6}, "Es253": {"Es254": 0.032, "Es254_m1": 0.968}, "Es255": {"Es256": 0.984, "Es256_m1": 0.016}} \ No newline at end of file diff --git a/scripts/xsdata/create_chain_from_endfb71.py b/scripts/xsdata/create_chain_from_endfb71.py index b83856847..0dc9abb5e 100644 --- a/scripts/xsdata/create_chain_from_endfb71.py +++ b/scripts/xsdata/create_chain_from_endfb71.py @@ -1,5 +1,6 @@ from pathlib import Path import argparse +import json import numpy as np import pandas as pd @@ -18,27 +19,19 @@ decay_paths = Path(f'{XSDIR}/decay').resolve().glob('**/*') nfy_paths = Path(f'{XSDIR}/nfy').resolve().glob('**/*') -sfy_paths = Path(f'{XSDIR}/sfy').resolve().glob('**/*') neutron_paths = Path(f'{XSDIR}/neutrons').resolve().glob('**/*') decay_files = [openmc.data.endf.Evaluation(str(x)) for x in decay_paths if x.is_file()] nfy_files = [openmc.data.endf.Evaluation(str(x)) for x in nfy_paths if x.is_file()] -sfy_files = [openmc.data.endf.Evaluation(str(x)) for x in sfy_paths if x.is_file()] neutron_files = [str(x) for x in neutron_paths if x.is_file()] -fpy_files = nfy_files + sfy_files +fpy_files = nfy_files branching_ratios = pd.read_csv('serpent_branching_ratios.csv', header=None).to_numpy() endfb71_chain = Chain.from_endf(decay_files, fpy_files, neutron_files) -for nuc, ground_ratio, meta_ratio in branching_ratios: - Z, A, M = zam(nuc) - ground_nuc = gnds_name(Z, A+1, M) - meta_nuc = gnds_name(Z, A+1, M+1) - branch_ratios = {ground_nuc: float(ground_ratio), - meta_nuc: float(meta_ratio)} - branch_ratios = {nuc: branch_ratios} - endfb71_chain.set_branch_ratios(branch_ratios, '(n,gamma)') - +with open('branching_ratios_pwr.json') as f: + br = json.load(f) +endfb71_chain.set_branch_ratios(br, strict=False) endfb71_chain.export_to_xml('chain_endfb71_ace.xml') diff --git a/scripts/xsdata/download_endfb71.bash b/scripts/xsdata/download_endfb71.bash index aba811f6e..fee360705 100644 --- a/scripts/xsdata/download_endfb71.bash +++ b/scripts/xsdata/download_endfb71.bash @@ -1,4 +1,5 @@ #! ~/bin/bash +set -ex ################ ### DOWNLOAD ### ################ @@ -22,7 +23,7 @@ mkdir -p $DATADIR/acedata # ndy, decay, sfy data LN="https://www.nndc.bnl.gov/endf-b7.1/zips/" SLUG="ENDF-B-VII.1-" -DATA=("nfy" "decay" "sfy" "neutrons") +DATA=("nfy" "decay" "neutrons") EXT=".zip" for D in ${DATA[@]} do @@ -35,6 +36,15 @@ do mkdir -p $DATADIR/$D unzip -j $DATADIR/$SLUG$D$EXT -d $DATADIR/$D fi + # Remove Be7 evaluation + if [[ -f $DATADIR/$D/dec-004_Be_007.endf ]] + then + rm $DATADIR/$D/dec-004_Be_007.endf + fi + if [[ -f $DATADIR/$D/n-004_Be_007.endf ]] + then + rm $DATADIR/$D/n-004_Be_007.endf + fi if [[ $D -ne "neutrons" ]] then if [[ ! -f $DATADIR/endfb71.$D ]] @@ -98,6 +108,37 @@ do tar -xzf $DATADIR/"$D$EXT" -C $DATADIR --verbose mv $DATADIR/$D/$D $DATADIR/acedata/. fi + if [[ $D == "endf71x" ]] + then + # Remove old hydrogen evaluations + rm -f $DATADIR/acedata/$D/H/H1001.71* + sed -i "s/.*H\/1001\.71.*//" $DATADIR/$D/xsdir + + # Remove bad Be7 evaluation + rm -f $DATADIR/acedata/$D/Be/4007* + sed -i "s/.*Be\/4007.*//" $DATADIR/$D/xsdir + else + if $SUPPORTS_INTERPOLATE_CONTINUOUS_ENERGY + then + if [[ -f $DATADIR/acedata/$D/sio2.10t ]] + then + rm -f $DATADIR/acedata/$D.sio2.2* + rm -f $DATADIR/acedata/$D.sio2.3* + sed -i "s/.*sio2\.2.*//" $DATADIR/$D/xsdir + sed -i "s/.*sio2\.3.*//" $DATADIR/$D/xsdir + fi + if [[ -f $DATADIR/acedata/$D/u-o2.30t ]] + then + rm -f $DATADIR/acedata/$D.u-o2.2* + sed -i "s/.*u-o2\.2.*//" $DATADIR/$D/xsdir + fi + if [[ -f $DATADIR/acedata/$D/zr-h.30t ]] + then + rm -f $DATADIR/acedata/$D.zr-h.2* + sed -i "s/.*zr-h\.2.*//" $DATADIR/$D/xsdir + fi + fi + fi cat $DATADIR/$D/xsdir >> $DATADIR/$XSDIR_FILE echo "" >> $DATADIR/$XSDIR_FILE diff --git a/scripts/xsdata/serpent_branching_ratios.csv b/scripts/xsdata/serpent_branching_ratios.csv deleted file mode 100644 index 38cf5cc3c..000000000 --- a/scripts/xsdata/serpent_branching_ratios.csv +++ /dev/null @@ -1,101 +0,0 @@ -Na23,0.232,0.768 -Cl37,0.8809,0.1191 -Sc45,0.556,0.444 -Co59,0.444,0.556 -Ge72,0.5012,0.4988 -Ge74,0.666,0.334 -Ge76,0.4005,0.5995 -Se76,0.7409,0.2591 -Se78,0.1178,0.8822 -Se80,0.8454,0.1546 -Se82,0.1402,0.8598 -Br79,0.7687,0.2313 -Br81,0.0914,0.9086 -Kr78,0.9704,0.0296 -Kr80,0.6031,0.3969 -Kr82,0.333,0.667 -Kr84,0.1839,0.8161 -Rb85,0.8791,0.1209 -Sr84,0.253,0.747 -Sr86,0.1988,0.8012 -Y89,0.9979,0.0021 -Y90,0.7496,0.2504 -Nb93,0.3101,0.6899 -Nb94,0.961,0.039 -Mo92,0.9978,0.0022 -Rh103,0.924,0.076 -Rh105,0.904,0.096 -Pd106,0.9527,0.0473 -Pd108,0.9779,0.0221 -Pd110,0.85,0.15 -Ag107,0.9898,0.0102 -Ag109,0.954,0.046 -Cd110,0.9945,0.0055 -Cd112,0.8685,0.1315 -Cd114,0.8812,0.1188 -Cd116,0.666,0.334 -In113,0.4191,0.5809 -Sn112,0.7253,0.2747 -Sn116,0.9568,0.0432 -Sn118,0.9794,0.0206 -Sn120,0.9875,0.0125 -Sn122,0.0112,0.9888 -Sn124,0.0375,0.9625 -Sn126,0.3018,0.6982 -Sb121,0.9369,0.0631 -Te120,0.8871,0.1129 -Te122,0.6448,0.3552 -Te124,0.9912,0.0088 -Te126,0.8689,0.1311 -Te128,0.9245,0.0755 -Te130,0.8559,0.1441 -Te132,0.8517,0.1483 -I129,0.413,0.587 -I131,0.9839,0.0161 -Xe124,0.83,0.17 -Xe126,0.8691,0.1309 -Xe128,0.8923,0.1077 -Xe130,0.9164,0.0836 -Xe132,0.8867,0.1133 -Xe133,0.96,0.04 -Xe134,0.9853,0.0147 -Cs133,0.907,0.093 -Cs134,0.996,0.004 -Cs135,0.984,0.016 -Cs137,0.9021,0.0979 -Ba130,0.8871,0.1129 -Ba132,0.9175,0.0825 -Ba134,0.9263,0.0737 -Ba135,0.9978,0.0022 -Ba136,0.9731,0.0269 -Ce136,0.8662,0.1338 -Ce138,0.9787,0.0213 -Pr141,0.6519,0.3481 -Pr143,0.31,0.69 -Pm147,0.533,0.467 -Eu153,0.984,0.016 -Dy164,0.37,0.63 -Ho165,0.949,0.051 -Er166,0.2503,0.7497 -Lu175,0.3331,0.6669 -Lu176,0.999,0.001 -Hf179,0.991,0.009 -W182,0.8699,0.1301 -W184,0.9983,0.0017 -Re185,0.999,0.001 -Re187,0.9729,0.0271 -Au197,0.999,0.001 -Hg196,0.966,0.034 -Hg198,0.9918,0.0082 -Pb206,0.9783,0.0217 -Bi209,0.6791,0.3209 -Pa233,0.4871,0.5129 -U234,0.5,0.5 -Np235,0.4,0.6 -Np239,0.3573,0.6427 -Pu236,0.5001,0.4999 -Am241,0.919,0.081 -Am243,0.0626,0.9374 -Bk247,0.4,0.6 -Es253,0.032,0.968 -Es255,0.984,0.016 From ad199eb56cf361ca0a79028fd4637005d466502b Mon Sep 17 00:00:00 2001 From: yardasol Date: Wed, 19 Jul 2023 16:05:35 -0500 Subject: [PATCH 47/62] update endfb71-based materials --- examples/msbr/mats/fuel_endfb71.ini | 9 +++ examples/msbr/msbr_endfb71.serpent | 110 ++++++++++++++++++++++------ examples/msbr/openmc_msbr_model.py | 108 ++++++++++++++++++++++++--- 3 files changed, 191 insertions(+), 36 deletions(-) create mode 100644 examples/msbr/mats/fuel_endfb71.ini diff --git a/examples/msbr/mats/fuel_endfb71.ini b/examples/msbr/mats/fuel_endfb71.ini new file mode 100644 index 000000000..ff0cf8c18 --- /dev/null +++ b/examples/msbr/mats/fuel_endfb71.ini @@ -0,0 +1,9 @@ +% Material compositions (after 0.000000 days) + +mat fuel -3.350000000E+00 burn 1 fix 09c 900 vol 4.87100E+07 + 3006.82c -3.937496230427713e-06 + 3007.82c -0.07874598711233247 + 9019.82c -0.45398382534173054 + 4009.82c -0.02255755625117608 + 90232.82c -0.4355946342818605 + 92233.82c -0.009114059516670065 diff --git a/examples/msbr/msbr_endfb71.serpent b/examples/msbr/msbr_endfb71.serpent index d6f8a1ab7..f51adee65 100644 --- a/examples/msbr/msbr_endfb71.serpent +++ b/examples/msbr/msbr_endfb71.serpent @@ -1,5 +1,5 @@ % Include file with burnable material composition on the line below -include "mats/msbr_saltproc_prepr_comp_endfb71-diluted.ini" +include "mats/fuel_endfb71.ini" % Include file with non-burnable material composition on the line below %include "mats/non_burnable_mats.ini" % Geometry import will be added by SaltProc on the next line @@ -16,31 +16,93 @@ mat moder -1.84 tmp 900 rgb 128 0 128 moder gr 6000 6000.82c -1.0 %tmp 908 % --- Hastelloy N mat hast -8.671 rgb 0 0 255 -% Natural Ni -%28000.82c -0.677 -28058.82c -0.45492846488214814 -28060.82c -0.18127326881482336 -28061.82c -0.008011341006475749 -28062.82c -0.025961746987204326 -28064.82c -0.006825178309348437 - -% Natural W -%74000.82c -0.250 -74180.82c -0.00029364388293333545 -74182.82c -0.0655676236926255 -74183.82c -0.03560150632186718 -74184.82c -0.07664548021821405 -74186.82c -0.07189174588435995 - -% Natural Cr -%24000.82c -0.070 -24050.82c -0.002921580575502679 -24052.82c -0.05858955364682328 -24053.82c -0.006771510820966751 -24054.82c -0.001717354956707304 + +% Mo +42092.82c -0.01683826965647346 +42094.82c -0.010789582056756033 +42095.82c -0.018840557266836578 +42096.82c -0.01999840362163272 +42097.82c -0.011613114609036522 +42098.82c -0.02974484682761688 +42100.82c -0.012175225961647808 + +% Cr +24050.82c -0.0029215806359028196 +24052.82c -0.058589553645942136 +24053.82c -0.006771510773072629 +24054.82c -0.00171735494508243 + +% Fe +26054.82c -0.0016936674668120565 +26056.82c -0.027570458633868738 +26057.82c -0.0006481105841023909 +26058.82c -8.776331521681765e-05 + +% C +6000.82c -0.0006 + +% Mn +25055.82c -0.0035 + +% Si +14028.82c -0.0009187351728283676 +14029.82c -4.831750292786396e-05 +14030.82c -3.2947324243768426e-05 + +% W +74180.82c -1.174575531392815e-06 +74182.82c -0.00026227049476287324 +74183.82c -0.0001424060252844692 +74184.82c -0.000306581920873831 +74186.82c -0.00028756698354743377 % Al -13027.82c -0.003 +13027.82c -0.001 + +% Ti +22046.82c -0.0009900119019720071 +22047.82c -0.0009122227903994025 +22048.82c -0.009230631531977933 +22049.82c -0.0006915238172711496 +22050.82c -0.0006756099583795079 + +% Cu +29063.82c -0.0006847919520523901 +29065.82c -0.00031520804794761 + +% Co +27059.82c -0.002 + +% P +15031.82c -0.00015 + +% S +16032.82c -0.00014215291621241376 +16033.82c -1.154822906631053e-06 +16034.82c -6.667728601314034e-06 +16036.82c -2.4532279641130547e-08 + +% B +5010.82c -1.835549587507326e-06 +5011.82c -8.164450412492673e-06 + +% Hf +72174.82c -1.5592576781201616e-05 +72176.82c -0.0005185040271645928 +72177.82c -0.0018439333432437896 +72178.82c -0.002719727077160886 +72179.82c -0.0013655166554538101 +72180.82c -0.0035367263201957194 + +% Nb +41093.82c -0.01 + +% Ni +28058.82c -0.49530756597063447 +28060.82c -0.19736294493393117 +28061.82c -0.00872242148181352 +28062.82c -0.028266091716773578 +28064.82c -0.007430975896847314 % --- Thermal scattering data for graphite: % endfb71 diff --git a/examples/msbr/openmc_msbr_model.py b/examples/msbr/openmc_msbr_model.py index 55c4348b3..abdaf534e 100644 --- a/examples/msbr/openmc_msbr_model.py +++ b/examples/msbr/openmc_msbr_model.py @@ -6,23 +6,79 @@ import numpy as np import openmc from openmc.deplete import CoupledOperator, PredictorIntegrator, CELIIntegrator +from openmc.data import atomic_mass, atomic_weight import core_elements as ce import control_rods as cr import root_geometry as rg +MAT_FLAG='REF' # Materials - fuel = openmc.Material(name='fuel') fuel.set_density('g/cm3', density=3.35) -fuel.add_components({'Li7': 0.0787474673879085, - 'Be9': 0.0225566879138321, - 'F19': 0.454003012179284, - 'Th232': 0.435579130482336, - 'U233': 0.00911370203663893}, - percent_type='wo') fuel.depletable = True fuel.volume = 48710000.0 +if MAT_FLAG == 'model': + fuel.add_components({'Li7': 0.0787474673879085, + 'Be9': 0.0225566879138321, + 'F19': 0.454003012179284, + 'Th232': 0.435579130482336, + 'U233': 0.00911370203663893}, + percent_type='wo') +else: + def create_mass_percents_dictionary(mat): + at_percents = [] + nucs = [] + at_mass = [] + for nuc, pt, tp in mat.nuclides: + nucs.append(nuc) + at_percents.append(pt) + at_mass.append(atomic_mass(nuc)) + + at_percents = np.array(at_percents) + at_mass = np.array(at_mass) + + mass_percents = at_percents*at_mass / np.dot(at_percents, at_mass) + + return dict(zip(nucs, mass_percents)) + comps = np.array([1, 1, 1, 2, 1, 4, 1, 4]) + + # Mol fractions + comps = np.array([1, 1, 1, 2, 1, 4, 1, 4]) + #vals = np.array([71.7,71.7,16.0,16.0, 12.0,12.0, 0.3,0.3]) + vals = np.array([71.75,71.75,16.0,16.0, 12.0,12.0, 0.25,0.25]) + nucs = (['Li', 'F', 'Be', 'F', 'Th', 'F', 'U', 'F']) + vals = comps*vals + + # Li, F, Be, Th, U + tots = ([vals[0], vals[1] + vals[3] + vals[5] + vals[7], vals[2], vals[4], vals[6]]) + tots = tots / np.sum(tots) * 100 + nucs = [nucs[0], nucs[1], nucs[2], nucs[4], nucs[6]] + + components = {'Li': {'percent': tots[0]/100, + 'enrichment': 99.995, + 'enrichment_target': 'Li7', + 'enrichment_type': 'wo'}, + 'F19': tots[1]/100, + 'Be9': tots[2]/100, + 'Th232': tots[3]/100, + 'U233': tots[4]/100} + fuel.add_components(components, percent_type='ao') + + # convert to wo + components = create_mass_percents_dictionary(fuel) + for nuc in fuel.get_nuclides(): + fuel.remove_nuclide(nuc) + fuel.add_components(components, percent_type='wo') + #fuel_mass = fuel.get_mass() + #comp = {} + #for nuc in fuel.get_nuclides(): + # comp[nuc] = fuel.get_mass(nuc) + #for nuc in fuel.get_nuclides(): + # fuel.remove_nuclide(nuc) + #breakpoint() + #fuel.add_components(comp, percent_type='wo') + moder = openmc.Material(name='graphite') moder.set_density('g/cm3', density=1.84) @@ -31,11 +87,39 @@ hast = openmc.Material(name='hastelloyN') hast.set_density('g/cm3', density=8.671) -hast.add_components({'Al27': 0.003, - 'Ni': 0.677, - 'W': 0.250, - 'Cr': 0.070}, - percent_type='wo') +if MAT_FLAG == 'model': + hast.add_components({'Al27': 0.003, + 'Ni': 0.677, + 'W': 0.250, + 'Cr': 0.070}, + percent_type='wo') +else: + components = {'Mo': 0.12, + 'Cr': 0.07, + 'Fe': 0.03, + 'C': 0.0006, + 'Mn': 0.0035, + 'Si': 0.001, + 'W': 0.001, + 'Al': 0.001, + 'Ti': 0.0125, #avg + 'Cu': 0.001, + 'Co': 0.002, + 'P': 0.00015, + 'S': 0.00015, + 'B': 0.000010, + 'Hf': 0.01, + 'Nb': 0.01} + + tot = 0 + wts = [] + for nuc, wt in components.items(): + wts.append(wt*100) + tot += wt + nickel = 1 - tot + + components.update({'Ni': nickel}) + hast.add_components(components, percent_type='wo') mat = openmc.Materials(materials=[fuel, moder, hast]) mat.export_to_xml() From ad94efac3ab8ac4040b778feca0f020199c5958c Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 20 Jul 2023 14:15:36 -0500 Subject: [PATCH 48/62] fix bug where OpenMCDepcode does not propogate decay-only nuclides --- saltproc/openmc_depcode.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/saltproc/openmc_depcode.py b/saltproc/openmc_depcode.py index cde724002..e5f7c6d7c 100644 --- a/saltproc/openmc_depcode.py +++ b/saltproc/openmc_depcode.py @@ -289,10 +289,10 @@ def read_depleted_materials(self, read_at_end=False): # Get decay and transport nuclides nucs = list(results[-1].index_nuc.keys()) - depleted_openmc_materials = results.export_to_materials(moment, nuclides_with_data=nucs) + depleted_openmc_materials = results.export_to_materials(moment, nuc_with_data=nucs) if read_at_end: _nucs = list(results[0].index_nuc.keys()) - starting_openmc_materials = results.export_to_materials(0, nuclides_with_data=nucs) + starting_openmc_materials = results.export_to_materials(0, nuc_with_data=_nucs) else: # placeholder for starting materials starting_openmc_materials = np.zeros(len(depleted_openmc_materials)) @@ -516,7 +516,6 @@ def update_depletable_materials(self, mats, dep_end_time): openmc.reset_auto_ids() runtime_materials = openmc.Materials.from_xml(self.runtime_matfile) - breakpoint() for material in runtime_materials: # depletable materials only if material.name in mats.keys(): From cb69d2cb004e9fa4c26b1d6f75a6aa2a6724d9d5 Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 20 Jul 2023 14:15:46 -0500 Subject: [PATCH 49/62] finish results.py docs --- saltproc/results.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/saltproc/results.py b/saltproc/results.py index 179e98406..f013a4d1e 100644 --- a/saltproc/results.py +++ b/saltproc/results.py @@ -27,7 +27,7 @@ class Results(): Mass of fissionable nuclides summed over all depletable materials. breeding_ratio : numpy.ndarray - Breeding ratio in the ... + Breeding ratio in the reactor power_level : numpy.ndarray Power in [W]. beta_eff : numpy.ndarray From b64459b86b5bb1575e8a327c9f8db2937ab1648f Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 20 Jul 2023 14:43:20 -0500 Subject: [PATCH 50/62] fix xsdata scripts --- scripts/xsdata/create_chain_from_endfb71.py | 1 - scripts/xsdata/download_endfb71.bash | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/xsdata/create_chain_from_endfb71.py b/scripts/xsdata/create_chain_from_endfb71.py index 0dc9abb5e..8f54cc19b 100644 --- a/scripts/xsdata/create_chain_from_endfb71.py +++ b/scripts/xsdata/create_chain_from_endfb71.py @@ -27,7 +27,6 @@ fpy_files = nfy_files -branching_ratios = pd.read_csv('serpent_branching_ratios.csv', header=None).to_numpy() endfb71_chain = Chain.from_endf(decay_files, fpy_files, neutron_files) with open('branching_ratios_pwr.json') as f: br = json.load(f) diff --git a/scripts/xsdata/download_endfb71.bash b/scripts/xsdata/download_endfb71.bash index fee360705..8f117ff2a 100644 --- a/scripts/xsdata/download_endfb71.bash +++ b/scripts/xsdata/download_endfb71.bash @@ -114,9 +114,9 @@ do rm -f $DATADIR/acedata/$D/H/H1001.71* sed -i "s/.*H\/1001\.71.*//" $DATADIR/$D/xsdir - # Remove bad Be7 evaluation - rm -f $DATADIR/acedata/$D/Be/4007* - sed -i "s/.*Be\/4007.*//" $DATADIR/$D/xsdir + ## Remove bad Be7 evaluation + #rm -f $DATADIR/acedata/$D/Be/4007* + #sed -i "s/.*Be\/4007.*//" $DATADIR/$D/xsdir else if $SUPPORTS_INTERPOLATE_CONTINUOUS_ENERGY then From 745302b59cf5275da789fcb417af628a59da08f1 Mon Sep 17 00:00:00 2001 From: yardasol Date: Fri, 21 Jul 2023 12:09:02 -0500 Subject: [PATCH 51/62] test adjustments --- .../pincell_input.json | 11 +- .../pincell_reference_results.h5 | Bin 118433 -> 66364 bytes .../run_constant_reprocessing_openmc/test.py | 33 +-- .../run_constant_reprocessing_serpent/test.py | 3 +- .../ref_saltproc_results.h5 | Bin 67065 -> 46886 bytes .../reference_error | 244 +----------------- .../test_input.json | 8 +- .../run_no_reprocessing_openmc/test_openmc.py | 2 +- .../test_serpent.py | 2 +- tests/openmc_data/pincell_paths.dot | 39 +++ tests/openmc_data/pincell_processes.json | 37 +++ 11 files changed, 99 insertions(+), 280 deletions(-) create mode 100644 tests/openmc_data/pincell_paths.dot create mode 100644 tests/openmc_data/pincell_processes.json diff --git a/tests/integration_tests/run_constant_reprocessing_openmc/pincell_input.json b/tests/integration_tests/run_constant_reprocessing_openmc/pincell_input.json index 6bc6dbd98..16bf6688f 100644 --- a/tests/integration_tests/run_constant_reprocessing_openmc/pincell_input.json +++ b/tests/integration_tests/run_constant_reprocessing_openmc/pincell_input.json @@ -1,6 +1,6 @@ { - "proc_input_file": "../../msbr_processes.json", - "dot_input_file": "../../msbr_paths.dot", + "proc_input_file": "../../openmc_data/pincell_processes.json", + "dot_input_file": "../../openmc_data/pincell_paths.dot", "n_depletion_steps": 2, "depcode": { "codename": "openmc", @@ -8,12 +8,7 @@ "materials": "materials.xml", "settings": "pincell_settings.xml"}, "geo_file_paths": ["pincell_geometry.xml"], - "chain_file_path": "../../openmc_data/chain_endfb71_pwr.xml", - "depletion_settings": { - "operator_kwargs": { - "fission_q": "../../openmc_data/serpent_fissq.json" - } - } + "chain_file_path": "../../openmc_data/chain_simple.xml" }, "simulation": { "sim_name": "pincell_constant_reprocessing" diff --git a/tests/integration_tests/run_constant_reprocessing_openmc/pincell_reference_results.h5 b/tests/integration_tests/run_constant_reprocessing_openmc/pincell_reference_results.h5 index 943d3f33654f5fb133463088c41117d282fdebf3..aaec8db26fc55ac21ccb6aa73df21a34b27ca105 100644 GIT binary patch delta 6200 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 Q%Ry=T;mK#7qz=db0(B8d{Qv*} diff --git a/tests/integration_tests/run_constant_reprocessing_openmc/test.py b/tests/integration_tests/run_constant_reprocessing_openmc/test.py index 5ef3ef2a4..5f122e0e1 100644 --- a/tests/integration_tests/run_constant_reprocessing_openmc/test.py +++ b/tests/integration_tests/run_constant_reprocessing_openmc/test.py @@ -29,8 +29,7 @@ def setup(scope='module'): return cwd, test_db, ref_db, atol, rtol -@pytest.mark.slow -def test_integration_2step_constant_ideal_removal_heavy(setup): +def test_constant_reprocesing_openmc(setup): cwd, test_db, ref_db, atol, rtol = setup args = ['python', '-m', 'saltproc', '-i', str(cwd / 'pincell_input.json')] subprocess.run( @@ -100,61 +99,37 @@ def read_nuclide_mass(db_file): return mass_before, mass_after def assert_in_out_streams_allclose(test_db, ref_db, atol, rtol): - ref_sparger, \ - ref_test_separator, \ - ref_ni_filter, \ + ref_test_separator, \ ref_feed = read_in_out_streams(ref_db) - test_sparger, \ - test_separator, \ - test_ni_filter, \ + test_separator, \ test_feed = read_in_out_streams(test_db) - for key, val in ref_sparger.items(): - np.testing.assert_allclose(val, test_sparger[key], atol=atol, rtol=rtol) for key, val in ref_test_separator.items(): np.testing.assert_allclose(val, test_separator[key], atol=atol, rtol=rtol) - for key, val in ref_ni_filter.items(): - np.testing.assert_allclose(val, test_ni_filter[key], atol=atol, rtol=rtol) for key, val in ref_feed.items(): np.testing.assert_allclose(val, test_feed[key], atol=atol, rtol=rtol) def read_in_out_streams(db_file): db = tb.open_file(db_file, mode='r') - waste_sparger = db.root.materials.fuel.in_out_streams.waste_sparger waste_separator = \ db.root.materials.fuel.in_out_streams.waste_entrainment_separator - waste_ni_filter = db.root.materials.fuel.in_out_streams.waste_nickel_filter feed_leu = db.root.materials.fuel.in_out_streams.feed_leu - waste_sparger_nucmap = _create_nuclide_map(waste_sparger) waste_separator_nucmap = _create_nuclide_map(waste_separator) - waste_ni_filter_nucmap = _create_nuclide_map(waste_ni_filter) feed_nucmap = _create_nuclide_map(feed_leu) - waste_sparger = waste_sparger.comp waste_separator = waste_separator.comp - waste_ni_filter = waste_ni_filter.comp feed_leu = feed_leu.comp - mass_waste_sparger = {} mass_waste_separator = {} - mass_waste_ni_filter = {} mass_feed_leu = {} - for nuc, idx in waste_sparger_nucmap.items(): - mass_waste_sparger[nuc] = np.array( - [row[idx] for row in waste_sparger]) for nuc, idx in waste_separator_nucmap.items(): mass_waste_separator[nuc] = np.array( [row[idx] for row in waste_separator]) - for nuc, idx in waste_ni_filter_nucmap.items(): - mass_waste_ni_filter[nuc] = np.array( - [row[idx] for row in waste_ni_filter]) for nuc, idx in feed_nucmap.items(): mass_feed_leu[nuc] = np.array( [row[idx] for row in feed_leu]) db.close() - return mass_waste_sparger, \ - mass_waste_separator, \ - mass_waste_ni_filter, \ + return mass_waste_separator, \ mass_feed_leu def read_fuel(file): diff --git a/tests/integration_tests/run_constant_reprocessing_serpent/test.py b/tests/integration_tests/run_constant_reprocessing_serpent/test.py index 7e03d2fc8..380a67c7d 100644 --- a/tests/integration_tests/run_constant_reprocessing_serpent/test.py +++ b/tests/integration_tests/run_constant_reprocessing_serpent/test.py @@ -23,8 +23,7 @@ def setup(scope='module'): return cwd, test_db, ref_db, tol -@pytest.mark.slow -def test_integration_2step_constant_ideal_removal_heavy(setup): +def test_constant_reprocessing_serpent(setup): cwd, test_db, ref_db, tol = setup args = ['python', '-m', 'saltproc', '-s', '12', '-i', cwd + '/tap_input.json'] subprocess.run( diff --git a/tests/integration_tests/run_no_reprocessing_openmc/ref_saltproc_results.h5 b/tests/integration_tests/run_no_reprocessing_openmc/ref_saltproc_results.h5 index 8a64b037eda7aeeae9befbb86d4da8d7e684cb77..a7c5c8bbadbf852d96f4744ba0bc0c719102c7f7 100644 GIT binary patch delta 4605 zcmd^Cd010d7Ju(0Kp+7lYj7c9l_?Ygn!F@0TSdgG1+`QirQ(867sR4P1zKd7K^7@6 z*U^fgSe1{u(HM~mR-scDN|frj>_}ngot`grg#JkB1kAihzS8#j$@% zutL&<#)A~^aO{E1{Mf?3#t%kWio3{otwDD^g-d~9trvvdIdC& zkn!Q!CxM()30eqR9K5h^FYZo&wBgkctMTEe!dxe^-)ps4J8)GFWMJvr) zqJ)CUR=6+;^y-7M1J;1sbrlHGN$yVpf}I^SrHfKa?GVIb{em_WB3QKN9m-Hx#zX!- z@=HoDD#x6iMd0NGAB9D9nCdDnN83-bT3P|C9oWKZ<4>@fr47VQd=?sNp^m25`UijX zWD09sE@8EQ&Stgm^1#yfLWX=|YHzKg7K(&7PinkYePKA7^5@UN+9}|jJ3ioRcfS8q zgxm@vtg84t+V%a`y0rK_|E}nIL(IzpAbBi}(C4ZtRWg!S%L&^?vlcJs$1h^?oVq+#X+8*f^^_*w*h7bG@^+ zMW0HtgClurH?d%-{j!r_b)m_I=w+EZXOCCcZ zhE}TBK6B=gY0L|f$2wrHd(Ea)FG0@2&@Li}IEt^hm#U6<>w+TwhbqnGt0H`r*GA2b zCI?*Fut-jv_`U+)+FYTj@V3KMKO-8?VY8HrE_V@m1*dRncSou^{_1sw`?D&|D#Q&} zCcu$boblKva$=s(m$=k*$0p7FZXuq&8`X?nxInpg%qji-PkV_M_s{Bcrj~hXrSK*j zEkETOAJ8AbkeCWr)o|aEA{13d}3VhOvBe7>?68N zDr0frdhIvZ8lzN|U8CK8c!t(-?I~634m;ic$QA0GOMN=`o;jK+v6Xsh=0`%}^q>U8 zlSzk&(&H*)OW9`ai)VZPihNAXM-@M1y8nJK;+qdEz3Jqo53Z1JHWC zqJWk%+kz|CW(%lXn=OcPZMMM4wb_Ct*JcZlT-$FzkzNA{8E!q@@BS}>;vZiFMYuxM zGkCy{VQps)`8brjU=64vuL~0lAcH98EhwShwUzEJMi5V$kjqeHBv{?%A0wjLYs-;# zR!L)(1FSNhRV=I$z$g^9mst5_;C90lMx8pJN*Gswq z@;rG-OQC!ZN<+t+BZE;_x1`Oh32HCqcg&nzKysn{Hg$EWK?B7I@p(taC@w59@}KDH z^tOWr3K*VdFB!*^7q;?6fypOq2MrWG)K+c0xizjXmOuVX@Os-p1BDXxel^(>i^gB& z|7B0RukE0L;)+Xx%-wY#ca-w8a_ArN1lTIr5Q?J8rfoh~spLw)IdpKjXBM9t=yN`10e zK!orT4AO>%eZ)Twsf@jC>$T^f=Nr8Pf6yL3G(+pX(LwF;m7Pv{#Zay8J=dpeww7rU z!lNto@i)VXyRT*%ET?Y~ii0Yn)OA&}mJBm8(rSn^#6iQsU%nt*cQ+UkB%95qdoa@Q zJ>=(VK78L7jX6h!3;88zQw1wA#FoZ)SIyhe<5vYsL@DU zz>^{g&_D22D__j*<-&=Yfs+U*jqu*8IGooHAuNJ$vj;Buv8cg<2G@^Ege*|7IKlPf zk|K)@EHrTaxCF_<0gDD)KQ39a2*3gW*N;n_q|SZ#!|3dR%$Y;DB-)8F51x}=fN6b3 zF3&uK_)X$;HR^xbrRm literal 67065 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 diff --git a/tests/integration_tests/run_no_reprocessing_openmc/reference_error b/tests/integration_tests/run_no_reprocessing_openmc/reference_error index fcc71a0ed..04552077b 100644 --- a/tests/integration_tests/run_no_reprocessing_openmc/reference_error +++ b/tests/integration_tests/run_no_reprocessing_openmc/reference_error @@ -1,232 +1,12 @@ -1.5119890468527587e-11 -4.065027524366237e-10 --1.6299973593092432e-09 -5.901636276027522e-12 -1.0058259415790447e-17 -6.055268993871537e-16 -3.268867431423211e-15 -1.3726239665047139e-14 -2.1384622008398624e-14 -1.721313394259131e-14 -2.232677370797632e-14 -4.661478661854402e-15 -5.3842226426989725e-14 --2.1927578188751274e-14 --1.2488461133812734e-12 --3.044357424095886e-13 --1.6354400572855837e-15 --7.819735727650765e-13 --5.321714568500848e-12 --6.856192721530405e-12 --5.195268827371149e-11 --6.916023579041131e-11 --4.037379064108138e-15 --7.050110845604825e-11 --6.425293339802339e-16 --2.0533233601352012e-13 --8.806843872762599e-11 --8.564990071507859e-11 --8.850799338746227e-11 --4.836038637603214e-10 --2.6566817855856596e-10 -8.734769763256804e-13 --6.507017638115873e-10 -4.348785652091783e-14 --2.8002619014271664e-14 --9.747851398578266e-10 --1.343699641073189e-09 --1.7779560184007356e-09 --2.7783441939425967e-11 --6.388237318243265e-14 --1.0564490612614136e-09 --9.052679936961425e-15 --1.5817098480592836e-11 --1.0681330371781813e-09 --9.371012090799975e-10 --1.2820576036955415e-09 --1.0039008770804168e-09 --3.035670792972574e-10 -3.623878062634076e-18 -1.6813887739533036e-15 --1.864141658802511e-11 -7.989134585506207e-17 --7.547577383191812e-13 -1.530128503126368e-12 --2.315155682893193e-10 -4.916518736659196e-11 -1.538285733974985e-11 -3.198357264322664e-10 --2.0375416480410428e-10 -1.0138348158352697e-15 -2.0096221478379623e-10 -7.082703942586674e-10 -1.650601123775417e-09 -2.4497485217864944e-09 -2.5032286782877177e-09 -2.317376470545537e-10 -1.709996446651662e-09 -6.415105576535204e-11 -9.931463602363242e-10 --1.960284097789959e-12 -7.711586022555048e-10 -5.28454192416791e-10 -1.0755457494293338e-09 -4.856531134240449e-10 -1.0989628980545293e-10 -1.574064913092152e-10 -4.365775265243026e-11 -1.4639327251351812e-14 --8.369433150474823e-17 -3.0354099612526337e-13 -6.510511418337447e-12 -2.106121226787296e-11 -8.747198836979853e-12 -4.1404862304980984e-11 -2.326586379447995e-11 -1.2901785143104952e-12 -5.142299790618626e-17 -7.894037138756894e-13 -3.021075402067874e-13 -5.02011804515428e-12 -2.0301164349011486e-11 -2.7703178642014608e-11 -2.334305920225588e-11 -2.3615129063317203e-11 -2.3885796382117878e-11 -2.1623123178503145e-13 -1.94520260408304e-11 -1.7122931616266313e-12 -2.645079292937375e-12 -1.0920899230327131e-11 -2.6775484601957207e-11 --2.6304623610801217e-13 -1.344374569141788e-11 --2.2195178795547087e-13 -8.143803878190516e-14 -1.9025658368455618e-17 --2.2803537759903022e-15 -1.0020159729474946e-14 --1.3829865756518979e-12 --4.796657464423493e-11 -1.083712281883326e-10 -6.04099787459623e-10 --3.4836292322902733e-13 -4.926677494323182e-11 --2.3701208494540843e-12 -3.4672344298425283e-10 -3.7568032998133623e-13 -3.7318095362245225e-10 -9.276399292326847e-11 -7.952793271820873e-13 -1.8781693770955076e-17 -9.982784520453103e-13 -1.5347738729451052e-10 -1.5045063436081735e-10 --1.0001789449280186e-11 --2.918915017257142e-10 -2.992775983301024e-09 --1.751485688013493e-08 --1.5775245732036164e-10 -1.5410010735902777e-10 -1.5218474756231197e-08 -4.927130239853403e-11 --1.4793870239216767e-10 --1.1376280894621395e-17 -1.670000061043744e-13 -2.1509660726688934e-16 -3.3718356446067196e-12 --7.171819690941674e-15 --1.086487077206716e-09 --4.796997876436375e-10 --3.54267141527312e-14 --8.213759874280114e-10 --3.033570018118274e-11 --1.0369006969813676e-18 --2.1788229343154277e-15 --1.451544355963365e-11 --3.9950363329988026e-10 --1.4638858522998763e-09 --7.748121082802036e-10 --1.0904445211102742e-09 --1.3818975419786658e-11 -5.26353210485017e-13 --6.420570552816401e-10 -6.854182394155806e-13 --4.3501559703e-11 --6.137885502765225e-11 --1.3427622111672173e-10 -4.0186853356429463e-10 -2.7234415283975777e-10 -5.179707809855553e-10 -6.80843350807924e-10 --9.422235819690454e-11 -5.509103927413717e-11 -3.513979928969029e-10 -1.765689417834657e-10 -5.2736074920330054e-11 --1.492816686829708e-13 -9.957386777003333e-12 -2.5244633102303585e-09 --2.3184848489123976e-09 -4.0984773228270975e-10 -2.9737333211010003e-10 -1.0889719672497838e-10 -1.2895633577583777e-10 -3.282599452071855e-15 -7.103815014888384e-15 -6.246945044367561e-11 -1.263076433061896e-11 -2.128286120832277e-11 -1.6387452433425937e-10 -1.0583156429356799e-11 -3.4486259007079665e-15 -1.134096457183409e-13 -9.840346170621273e-12 -6.367107795602626e-11 --1.93291775733344e-11 -4.141650027236221e-12 -6.231054426176675e-12 -7.163873485704885e-15 -8.373923225809402e-17 -2.028863398905383e-13 -4.279105723645883e-13 -3.043873246834808e-13 -1.5996926841888497e-13 -9.096647179411245e-14 -6.989085141514259e-17 -8.236634772967325e-15 -4.732029264305888e-14 -3.820505425395893e-14 -1.2824368476930067e-14 -2.0623985790953217e-15 -1.2284278121600062e-16 --6.5729087597434285e-15 -3.342779884556801e-15 -8.464561623698627e-17 --8.162392655005332e-18 -3.515677906986006e-15 -3.071447175021852e-17 -2.0260602689211787e-17 --4.261544429775526e-14 --2.6743791681289347e-11 -2.916128448091082e-08 --5.314554373525571e-07 -6.415356347960754e-07 -1.0529531572273734e-07 --1.7628932642566042e-06 -1.1861845383141402e-08 -3.5560472104647697e-12 -3.822434678502136e-15 -1.6938561699725884e-08 -1.7728704420604463e-11 -9.990133581716466e-07 --1.7129364305371126e-14 -6.620552491229667e-12 -4.910889738310757e-07 -7.402327398619843e-09 -1.4342486700991526e-10 -1.0423430907551459e-13 -2.060321634951517e-14 -3.5934513357509504e-17 --1.9038296962987594e-17 -2.6237559647086758e-17 \ No newline at end of file +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 +0.0 \ No newline at end of file diff --git a/tests/integration_tests/run_no_reprocessing_openmc/test_input.json b/tests/integration_tests/run_no_reprocessing_openmc/test_input.json index 82fc41706..34978aee4 100644 --- a/tests/integration_tests/run_no_reprocessing_openmc/test_input.json +++ b/tests/integration_tests/run_no_reprocessing_openmc/test_input.json @@ -5,17 +5,11 @@ "run_without_reprocessing": true, "depcode": { "codename": "openmc", - "template_input_file_path": { "materials": "materials.xml", "settings": "pincell_settings.xml"}, "geo_file_paths": ["pincell_geometry.xml"], - "chain_file_path": "../../openmc_data/chain_endfb71_pwr.xml", - "depletion_settings": { - "operator_kwargs": { - "fission_q": "../../openmc_data/serpent_fissq.json" - } - } + "chain_file_path": "../../openmc_data/chain_simple.xml" }, "simulation": { "sim_name": "test_openmc_no_reprocessing" diff --git a/tests/integration_tests/run_no_reprocessing_openmc/test_openmc.py b/tests/integration_tests/run_no_reprocessing_openmc/test_openmc.py index b505248bc..739fb1df8 100644 --- a/tests/integration_tests/run_no_reprocessing_openmc/test_openmc.py +++ b/tests/integration_tests/run_no_reprocessing_openmc/test_openmc.py @@ -13,7 +13,7 @@ from saltproc import app, Results @pytest.mark.slow -def test_integration_2step_saltproc_no_reproc_heavy(): +def test_no_reprocessing_openmc(): cwd = str(Path(__file__).parents[0].resolve()) args = ['python', '-m', 'saltproc', '-s', '12', '-i', cwd + '/test_input.json'] subprocess.run( diff --git a/tests/integration_tests/run_no_reprocessing_serpent/test_serpent.py b/tests/integration_tests/run_no_reprocessing_serpent/test_serpent.py index b5992e64a..9f2536443 100644 --- a/tests/integration_tests/run_no_reprocessing_serpent/test_serpent.py +++ b/tests/integration_tests/run_no_reprocessing_serpent/test_serpent.py @@ -11,7 +11,7 @@ from saltproc import app @pytest.mark.slow -def test_integration_2step_saltproc_no_reproc_heavy(): +def test_no_reprocessing_serpent(): cwd = str(Path(__file__).parents[0].resolve()) args = ['python', '-m', 'saltproc', '-s', '12', '-i', cwd + '/test_input.json'] subprocess.run( diff --git a/tests/openmc_data/pincell_paths.dot b/tests/openmc_data/pincell_paths.dot new file mode 100644 index 000000000..6dd93d28a --- /dev/null +++ b/tests/openmc_data/pincell_paths.dot @@ -0,0 +1,39 @@ +digraph fuel { /* The name of directed graph must match name of material + +Structure of the reprocessing system described using DOT language: +https://en.wikipedia.org/wiki/DOT_(graph_description_language) +Parameter 'label' and 'fontsize' are needed for nice plotting. +Mass flow rate, extraction efficiency and list of elements for removing must be +specified in the 'input.proccess' file +This DOT file can be also using for reprocessing scheme visualization: +http://www.webgraphviz.com/ +*/ +# ============================================================================== + core_outlet -> entrainment_separator [label="100%", fontsize=20] + entrainment_separator -> waste_entrainment_separator [label="97% of\nXe, Kr, H", fontsize=20] + entrainment_separator -> core_inlet [label="100%", fontsize=20] + LEU_feed -> core_inlet +# ============================================================================== +# Optional parameters to obtain pretty plots +# Section only needed to have 'waste' blocks on level with process + + subgraph separ { + rank=same + entrainment_separator + waste_entrainment_separator + } + + subgraph feed { + rank=same + LEU_feed + core_inlet + } + +# Section only needed to change font of the text and specify shapes of blocks + waste_entrainment_separator [shape=diamond, fontsize=24] + + core_outlet [fontsize=24] + entrainment_separator [fontsize=24] + core_inlet [fontsize=24] + LEU_feed [shape=box, fontsize=24] +} diff --git a/tests/openmc_data/pincell_processes.json b/tests/openmc_data/pincell_processes.json new file mode 100644 index 000000000..dafab4d01 --- /dev/null +++ b/tests/openmc_data/pincell_processes.json @@ -0,0 +1,37 @@ +{ + "fuel": { + "extraction_processes": { + "core_inlet": { + "capacity": 9920000, + "efficiency": {}, + "mass_flowrate": 9920000, + "volume": 0 + }, + "core_outlet": { + "capacity": 9920000, + "efficiency": {}, + "mass_flowrate": 9920000, + "volume": 0 + }, + "entrainment_separator": { + "capacity": 9920000, + "efficiency": { + "Xe": 1 + }, + "mass_flowrate": 9920000, + "volume": 11 + } + }, + "feeds": { + "leu": { + "density": 19.1, + "volume": 1, + "mass": 19.1, + "comp": { + "U238": 0.33, + "O16": 0.67 + } + } + } + } +} From 1079dc6975a9f794629b53ae7d6e695c672472c4 Mon Sep 17 00:00:00 2001 From: yardasol Date: Fri, 21 Jul 2023 12:09:32 -0500 Subject: [PATCH 52/62] update openmc msbr model --- examples/msbr/openmc_msbr_model.py | 163 +++++++++++++---------------- 1 file changed, 70 insertions(+), 93 deletions(-) diff --git a/examples/msbr/openmc_msbr_model.py b/examples/msbr/openmc_msbr_model.py index abdaf534e..55de5247f 100644 --- a/examples/msbr/openmc_msbr_model.py +++ b/examples/msbr/openmc_msbr_model.py @@ -12,73 +12,57 @@ import control_rods as cr import root_geometry as rg -MAT_FLAG='REF' +MAT_FLAG='model' # Materials fuel = openmc.Material(name='fuel') fuel.set_density('g/cm3', density=3.35) fuel.depletable = True fuel.volume = 48710000.0 +def create_mass_percents_dictionary(mat): + at_percents = [] + nucs = [] + at_mass = [] + for nuc, pt, tp in mat.nuclides: + nucs.append(nuc) + at_percents.append(pt) + at_mass.append(atomic_mass(nuc)) + + at_percents = np.array(at_percents) + at_mass = np.array(at_mass) + + mass_percents = at_percents*at_mass / np.dot(at_percents, at_mass) + + return dict(zip(nucs, mass_percents)) + if MAT_FLAG == 'model': - fuel.add_components({'Li7': 0.0787474673879085, - 'Be9': 0.0225566879138321, - 'F19': 0.454003012179284, - 'Th232': 0.435579130482336, - 'U233': 0.00911370203663893}, - percent_type='wo') -else: - def create_mass_percents_dictionary(mat): - at_percents = [] - nucs = [] - at_mass = [] - for nuc, pt, tp in mat.nuclides: - nucs.append(nuc) - at_percents.append(pt) - at_mass.append(atomic_mass(nuc)) - - at_percents = np.array(at_percents) - at_mass = np.array(at_mass) - - mass_percents = at_percents*at_mass / np.dot(at_percents, at_mass) - - return dict(zip(nucs, mass_percents)) - comps = np.array([1, 1, 1, 2, 1, 4, 1, 4]) - - # Mol fractions - comps = np.array([1, 1, 1, 2, 1, 4, 1, 4]) - #vals = np.array([71.7,71.7,16.0,16.0, 12.0,12.0, 0.3,0.3]) vals = np.array([71.75,71.75,16.0,16.0, 12.0,12.0, 0.25,0.25]) - nucs = (['Li', 'F', 'Be', 'F', 'Th', 'F', 'U', 'F']) - vals = comps*vals - - # Li, F, Be, Th, U - tots = ([vals[0], vals[1] + vals[3] + vals[5] + vals[7], vals[2], vals[4], vals[6]]) - tots = tots / np.sum(tots) * 100 - nucs = [nucs[0], nucs[1], nucs[2], nucs[4], nucs[6]] - - components = {'Li': {'percent': tots[0]/100, - 'enrichment': 99.995, - 'enrichment_target': 'Li7', - 'enrichment_type': 'wo'}, - 'F19': tots[1]/100, - 'Be9': tots[2]/100, - 'Th232': tots[3]/100, - 'U233': tots[4]/100} - fuel.add_components(components, percent_type='ao') - - # convert to wo - components = create_mass_percents_dictionary(fuel) - for nuc in fuel.get_nuclides(): - fuel.remove_nuclide(nuc) - fuel.add_components(components, percent_type='wo') - #fuel_mass = fuel.get_mass() - #comp = {} - #for nuc in fuel.get_nuclides(): - # comp[nuc] = fuel.get_mass(nuc) - #for nuc in fuel.get_nuclides(): - # fuel.remove_nuclide(nuc) - #breakpoint() - #fuel.add_components(comp, percent_type='wo') - +else: + vals = np.array([71.7,71.7,16.0,16.0, 12.0,12.0, 0.3,0.3]) +# Mol fractions +comps = np.array([1, 1, 1, 2, 1, 4, 1, 4]) +nucs = (['Li', 'F', 'Be', 'F', 'Th', 'F', 'U', 'F']) +vals = comps*vals + +# Li, F, Be, Th, U +tots = ([vals[0], vals[1] + vals[3] + vals[5] + vals[7], vals[2], vals[4], vals[6]]) +tots = tots / np.sum(tots) * 100 +nucs = [nucs[0], nucs[1], nucs[2], nucs[4], nucs[6]] + +components = {'Li': {'percent': tots[0]/100, + 'enrichment': 99.995, + 'enrichment_target': 'Li7', + 'enrichment_type': 'wo'}, + 'F19': tots[1]/100, + 'Be9': tots[2]/100, + 'Th232': tots[3]/100, + 'U233': tots[4]/100} +fuel.add_components(components, percent_type='ao') + +# convert to wo +components = create_mass_percents_dictionary(fuel) +for nuc in fuel.get_nuclides(): + fuel.remove_nuclide(nuc) +fuel.add_components(components, percent_type='wo') moder = openmc.Material(name='graphite') moder.set_density('g/cm3', density=1.84) @@ -87,39 +71,32 @@ def create_mass_percents_dictionary(mat): hast = openmc.Material(name='hastelloyN') hast.set_density('g/cm3', density=8.671) -if MAT_FLAG == 'model': - hast.add_components({'Al27': 0.003, - 'Ni': 0.677, - 'W': 0.250, - 'Cr': 0.070}, - percent_type='wo') -else: - components = {'Mo': 0.12, - 'Cr': 0.07, - 'Fe': 0.03, - 'C': 0.0006, - 'Mn': 0.0035, - 'Si': 0.001, - 'W': 0.001, - 'Al': 0.001, - 'Ti': 0.0125, #avg - 'Cu': 0.001, - 'Co': 0.002, - 'P': 0.00015, - 'S': 0.00015, - 'B': 0.000010, - 'Hf': 0.01, - 'Nb': 0.01} - - tot = 0 - wts = [] - for nuc, wt in components.items(): - wts.append(wt*100) - tot += wt - nickel = 1 - tot - - components.update({'Ni': nickel}) - hast.add_components(components, percent_type='wo') +components = {'Mo': 0.12, + 'Cr': 0.07, + 'Fe': 0.03, + 'C': 0.0006, + 'Mn': 0.0035, + 'Si': 0.001, + 'W': 0.001, + 'Al': 0.001, + 'Ti': 0.0125, #avg + 'Cu': 0.001, + 'Co': 0.002, + 'P': 0.00015, + 'S': 0.00015, + 'B': 0.000010, + 'Hf': 0.01, + 'Nb': 0.01} + +tot = 0 +wts = [] +for nuc, wt in components.items(): + wts.append(wt*100) + tot += wt +nickel = 1 - tot + +components.update({'Ni': nickel}) +hast.add_components(components, percent_type='wo') mat = openmc.Materials(materials=[fuel, moder, hast]) mat.export_to_xml() From 5edbc0a72d7fcc06add3588f540092ce36adbacf Mon Sep 17 00:00:00 2001 From: yardasol Date: Tue, 25 Jul 2023 13:59:12 -0500 Subject: [PATCH 53/62] fix some bugs --- saltproc/results.py | 1 + saltproc/serpent_depcode.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/saltproc/results.py b/saltproc/results.py index f013a4d1e..0bb2cf91b 100644 --- a/saltproc/results.py +++ b/saltproc/results.py @@ -80,6 +80,7 @@ def __init__(self, path, load_in_out_streams=True): self.material_composition = material_composition self.material_parameters = material_parameters self.waste_streams = waste_streams + f.close() def _collect_eds_bds_params(self, sim_params, col, errors=False, multidim=False): col_eds = sim_params.col(f'{col}_eds').tolist() diff --git a/saltproc/serpent_depcode.py b/saltproc/serpent_depcode.py index d6234d9d7..bd02e3b7a 100644 --- a/saltproc/serpent_depcode.py +++ b/saltproc/serpent_depcode.py @@ -565,9 +565,10 @@ def write_runtime_input(self, reactor, dep_step, restart): lines = self.resolve_include_paths(lines) lines = self.insert_path_to_geometry(lines) lines = self.create_runtime_matfile(lines) - self.get_neutron_settings(lines) else: lines = self.read_plaintext_file(self.runtime_inputfile) + + self.get_neutron_settings(lines) lines = self.set_power_load(lines, reactor, dep_step) with open(self.runtime_inputfile, 'w') as out_file: From 68e71e5d9266be2c8960927dd474568dc6d03a93 Mon Sep 17 00:00:00 2001 From: yardasol Date: Tue, 25 Jul 2023 13:59:30 -0500 Subject: [PATCH 54/62] fix endfb71_scripts --- scripts/xsdata/download_endfb71.bash | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/scripts/xsdata/download_endfb71.bash b/scripts/xsdata/download_endfb71.bash index 8f117ff2a..77bea386b 100644 --- a/scripts/xsdata/download_endfb71.bash +++ b/scripts/xsdata/download_endfb71.bash @@ -23,7 +23,7 @@ mkdir -p $DATADIR/acedata # ndy, decay, sfy data LN="https://www.nndc.bnl.gov/endf-b7.1/zips/" SLUG="ENDF-B-VII.1-" -DATA=("nfy" "decay" "neutrons") +DATA=("sfy" "nfy" "decay" "neutrons") EXT=".zip" for D in ${DATA[@]} do @@ -45,7 +45,7 @@ do then rm $DATADIR/$D/n-004_Be_007.endf fi - if [[ $D -ne "neutrons" ]] + if [[ $D != "neutrons" ]] then if [[ ! -f $DATADIR/endfb71.$D ]] then @@ -111,10 +111,17 @@ do if [[ $D == "endf71x" ]] then # Remove old hydrogen evaluations - rm -f $DATADIR/acedata/$D/H/H1001.71* - sed -i "s/.*H\/1001\.71.*//" $DATADIR/$D/xsdir + NUMS=("0" "1" "2" "3" "4" "5" "6") + for NUM in ${NUMS[@]} + do + EXT="nc" + EXT="$NUM$EXT" + mv $DATADIR/acedata/$D/H/1001.72$EXT $DATADIR/acedata/$D/H/1001.71$EXT + sed -i "s/1001.72$EXT/1001.71$EXT/" $DATADIR/acedata/$D/H/1001.71$EXT + sed -i "s/1001.9$NUM/1001.8$NUM/" $DATADIR/acedata/$D/H/1001.71$EXT + done + sed -i "s/.*H\/1001\.72.*//" $DATADIR/$D/xsdir - ## Remove bad Be7 evaluation #rm -f $DATADIR/acedata/$D/Be/4007* #sed -i "s/.*Be\/4007.*//" $DATADIR/$D/xsdir else From 29ca944ec945240d36e4cd2078daa2db329cb3c3 Mon Sep 17 00:00:00 2001 From: yardasol Date: Tue, 25 Jul 2023 13:59:46 -0500 Subject: [PATCH 55/62] fix fuel example --- examples/msbr/mats/fuel_endfb71.ini | 419 +++++++++++++++++++++++++++- 1 file changed, 417 insertions(+), 2 deletions(-) diff --git a/examples/msbr/mats/fuel_endfb71.ini b/examples/msbr/mats/fuel_endfb71.ini index ff0cf8c18..2b861611d 100644 --- a/examples/msbr/mats/fuel_endfb71.ini +++ b/examples/msbr/mats/fuel_endfb71.ini @@ -1,9 +1,424 @@ % Material compositions (after 0.000000 days) -mat fuel -3.350000000E+00 burn 1 fix 09c 900 vol 4.87100E+07 +mat fuel -3.350000000E+00 rgb 255 255 0 burn 1 fix 82c 900 vol 4.87100E+07 + 1001.82c -0.0 + 1002.82c -0.0 + 1003.82c -0.0 + 2003.82c -0.0 + 2004.82c -0.0 3006.82c -3.937496230427713e-06 3007.82c -0.07874598711233247 - 9019.82c -0.45398382534173054 4009.82c -0.02255755625117608 + 5010.82c -0.0 + 5011.82c -0.0 + 7014.82c -0.0 + 7015.82c -0.0 + 8016.82c -0.0 + 8017.82c -0.0 + 9019.82c -0.45398382534173054 + 11022.82c -0.0 + 11023.82c -0.0 + 12024.82c -0.0 + 12025.82c -0.0 + 12026.82c -0.0 + 13027.82c -0.0 + 14028.82c -0.0 + 14029.82c -0.0 + 14030.82c -0.0 + 15031.82c -0.0 + 16032.82c -0.0 + 16033.82c -0.0 + 16034.82c -0.0 + 16036.82c -0.0 + 17035.82c -0.0 + 17037.82c -0.0 + 18036.82c -0.0 + 18038.82c -0.0 + 18040.82c -0.0 + 19039.82c -0.0 + 19040.82c -0.0 + 19041.82c -0.0 + 20040.82c -0.0 + 20042.82c -0.0 + 20043.82c -0.0 + 20044.82c -0.0 + 20046.82c -0.0 + 20048.82c -0.0 + 21045.82c -0.0 + 22046.82c -0.0 + 22047.82c -0.0 + 22048.82c -0.0 + 22049.82c -0.0 + 22050.82c -0.0 + 23050.82c -0.0 + 23051.82c -0.0 + 24050.82c -0.0 + 24052.82c -0.0 + 24053.82c -0.0 + 24054.82c -0.0 + 25055.82c -0.0 + 26054.82c -0.0 + 26056.82c -0.0 + 26057.82c -0.0 + 26058.82c -0.0 + 27058.82c -0.0 + 27458.82c -0.0 + 27059.82c -0.0 + 28058.82c -0.0 + 28059.82c -0.0 + 28060.82c -0.0 + 28061.82c -0.0 + 28062.82c -0.0 + 28064.82c -0.0 + 29063.82c -0.0 + 29065.82c -0.0 + 30064.82c -0.0 + 30065.82c -0.0 + 30066.82c -0.0 + 30067.82c -0.0 + 30068.82c -0.0 + 30070.82c -0.0 + 31069.82c -0.0 + 31071.82c -0.0 + 32070.82c -0.0 + 32072.82c -0.0 + 32073.82c -0.0 + 32074.82c -0.0 + 32076.82c -0.0 + 33074.82c -0.0 + 33075.82c -0.0 + 34074.82c -0.0 + 34076.82c -0.0 + 34077.82c -0.0 + 34078.82c -0.0 + 34079.82c -0.0 + 34080.82c -0.0 + 34082.82c -0.0 + 35079.82c -0.0 + 35081.82c -0.0 + 36078.82c -0.0 + 36080.82c -0.0 + 36082.82c -0.0 + 36083.82c -0.0 + 36084.82c -0.0 + 36085.82c -0.0 + 36086.82c -0.0 + 37085.82c -0.0 + 37086.82c -0.0 + 37087.82c -0.0 + 38084.82c -0.0 + 38086.82c -0.0 + 38087.82c -0.0 + 38088.82c -0.0 + 38089.82c -0.0 + 38090.82c -0.0 + 39089.82c -0.0 + 39090.82c -0.0 + 39091.82c -0.0 + 40090.82c -0.0 + 40091.82c -0.0 + 40092.82c -0.0 + 40093.82c -0.0 + 40094.82c -0.0 + 40095.82c -0.0 + 40096.82c -0.0 + 41093.82c -0.0 + 41094.82c -0.0 + 41095.82c -0.0 + 42092.82c -0.0 + 42094.82c -0.0 + 42095.82c -0.0 + 42096.82c -0.0 + 42097.82c -0.0 + 42098.82c -0.0 + 42099.82c -0.0 + 42100.82c -0.0 + 43099.82c -0.0 + 44096.82c -0.0 + 44098.82c -0.0 + 44099.82c -0.0 + 44100.82c -0.0 + 44101.82c -0.0 + 44102.82c -0.0 + 44103.82c -0.0 + 44104.82c -0.0 + 44105.82c -0.0 + 44106.82c -0.0 + 45103.82c -0.0 + 45105.82c -0.0 + 46102.82c -0.0 + 46104.82c -0.0 + 46105.82c -0.0 + 46106.82c -0.0 + 46107.82c -0.0 + 46108.82c -0.0 + 46110.82c -0.0 + 47107.82c -0.0 + 47109.82c -0.0 + 47510.82c -0.0 + 47111.82c -0.0 + 48106.82c -0.0 + 48108.82c -0.0 + 48110.82c -0.0 + 48111.82c -0.0 + 48112.82c -0.0 + 48113.82c -0.0 + 48114.82c -0.0 + 48515.82c -0.0 + 48116.82c -0.0 + 49113.82c -0.0 + 49115.82c -0.0 + 50112.82c -0.0 + 50113.82c -0.0 + 50114.82c -0.0 + 50115.82c -0.0 + 50116.82c -0.0 + 50117.82c -0.0 + 50118.82c -0.0 + 50119.82c -0.0 + 50120.82c -0.0 + 50122.82c -0.0 + 50123.82c -0.0 + 50124.82c -0.0 + 50125.82c -0.0 + 50126.82c -0.0 + 51121.82c -0.0 + 51123.82c -0.0 + 51124.82c -0.0 + 51125.82c -0.0 + 51126.82c -0.0 + 52120.82c -0.0 + 52122.82c -0.0 + 52123.82c -0.0 + 52124.82c -0.0 + 52125.82c -0.0 + 52126.82c -0.0 + 52527.82c -0.0 + 52128.82c -0.0 + 52529.82c -0.0 + 52130.82c -0.0 + 52132.82c -0.0 + 53127.82c -0.0 + 53129.82c -0.0 + 53130.82c -0.0 + 53131.82c -0.0 + 53135.82c -0.0 + 54123.82c -0.0 + 54124.82c -0.0 + 54126.82c -0.0 + 54128.82c -0.0 + 54129.82c -0.0 + 54130.82c -0.0 + 54131.82c -0.0 + 54132.82c -0.0 + 54133.82c -0.0 + 54134.82c -0.0 + 54135.82c -0.0 + 54136.82c -0.0 + 55133.82c -0.0 + 55134.82c -0.0 + 55135.82c -0.0 + 55136.82c -0.0 + 55137.82c -0.0 + 56130.82c -0.0 + 56132.82c -0.0 + 56133.82c -0.0 + 56134.82c -0.0 + 56135.82c -0.0 + 56136.82c -0.0 + 56137.82c -0.0 + 56138.82c -0.0 + 56140.82c -0.0 + 57138.82c -0.0 + 57139.82c -0.0 + 57140.82c -0.0 + 58136.82c -0.0 + 58138.82c -0.0 + 58139.82c -0.0 + 58140.82c -0.0 + 58141.82c -0.0 + 58142.82c -0.0 + 58143.82c -0.0 + 58144.82c -0.0 + 59141.82c -0.0 + 59142.82c -0.0 + 59143.82c -0.0 + 60142.82c -0.0 + 60143.82c -0.0 + 60144.82c -0.0 + 60145.82c -0.0 + 60146.82c -0.0 + 60147.82c -0.0 + 60148.82c -0.0 + 60150.82c -0.0 + 61147.82c -0.0 + 61148.82c -0.0 + 61548.82c -0.0 + 61149.82c -0.0 + 61151.82c -0.0 + 62144.82c -0.0 + 62147.82c -0.0 + 62148.82c -0.0 + 62149.82c -0.0 + 62150.82c -0.0 + 62151.82c -0.0 + 62152.82c -0.0 + 62153.82c -0.0 + 62154.82c -0.0 + 63151.82c -0.0 + 63152.82c -0.0 + 63153.82c -0.0 + 63154.82c -0.0 + 63155.82c -0.0 + 63156.82c -0.0 + 63157.82c -0.0 + 64152.82c -0.0 + 64153.82c -0.0 + 64154.82c -0.0 + 64155.82c -0.0 + 64156.82c -0.0 + 64157.82c -0.0 + 64158.82c -0.0 + 64160.82c -0.0 + 65159.82c -0.0 + 65160.82c -0.0 + 66156.82c -0.0 + 66158.82c -0.0 + 66160.82c -0.0 + 66161.82c -0.0 + 66162.82c -0.0 + 66163.82c -0.0 + 66164.82c -0.0 + 67165.82c -0.0 + 67566.82c -0.0 + 68162.82c -0.0 + 68164.82c -0.0 + 68166.82c -0.0 + 68167.82c -0.0 + 68168.82c -0.0 + 68170.82c -0.0 + 69168.82c -0.0 + 69169.82c -0.0 + 69170.82c -0.0 + 71175.82c -0.0 + 71176.82c -0.0 + 72174.82c -0.0 + 72176.82c -0.0 + 72177.82c -0.0 + 72178.82c -0.0 + 72179.82c -0.0 + 72180.82c -0.0 + 73180.82c -0.0 + 73181.82c -0.0 + 73182.82c -0.0 + 74180.82c -0.0 + 74182.82c -0.0 + 74183.82c -0.0 + 74184.82c -0.0 + 74186.82c -0.0 + 75185.82c -0.0 + 75187.82c -0.0 + 77191.82c -0.0 + 77193.82c -0.0 + 79197.82c -0.0 + 80196.82c -0.0 + 80198.82c -0.0 + 80199.82c -0.0 + 80200.82c -0.0 + 80201.82c -0.0 + 80202.82c -0.0 + 80204.82c -0.0 + 81203.82c -0.0 + 81205.82c -0.0 + 82204.82c -0.0 + 82206.82c -0.0 + 82207.82c -0.0 + 82208.82c -0.0 + 83209.82c -0.0 + 88223.82c -0.0 + 88224.82c -0.0 + 88225.82c -0.0 + 88226.82c -0.0 + 89225.82c -0.0 + 89226.82c -0.0 + 89227.82c -0.0 + 90227.82c -0.0 + 90228.82c -0.0 + 90229.82c -0.0 + 90230.82c -0.0 + 90231.82c -0.0 90232.82c -0.4355946342818605 + 90233.82c -0.0 + 90234.82c -0.0 + 91229.82c -0.0 + 91230.82c -0.0 + 91231.82c -0.0 + 91232.82c -0.0 + 91233.82c -0.0 + 92230.82c -0.0 + 92231.82c -0.0 + 92232.82c -0.0 92233.82c -0.009114059516670065 + 92234.82c -0.0 + 92235.82c -0.0 + 92236.82c -0.0 + 92237.82c -0.0 + 92238.82c -0.0 + 92239.82c -0.0 + 92240.82c -0.0 + 92241.82c -0.0 + 93234.82c -0.0 + 93235.82c -0.0 + 93236.82c -0.0 + 93237.82c -0.0 + 93238.82c -0.0 + 93239.82c -0.0 + 94236.82c -0.0 + 94237.82c -0.0 + 94238.82c -0.0 + 94239.82c -0.0 + 94240.82c -0.0 + 94241.82c -0.0 + 94242.82c -0.0 + 94243.82c -0.0 + 94244.82c -0.0 + 94246.82c -0.0 + 95240.82c -0.0 + 95241.82c -0.0 + 95242.82c -0.0 + 95642.82c -0.0 + 95243.82c -0.0 + 95244.82c -0.0 + 95644.82c -0.0 + 96240.82c -0.0 + 96241.82c -0.0 + 96242.82c -0.0 + 96243.82c -0.0 + 96244.82c -0.0 + 96245.82c -0.0 + 96246.82c -0.0 + 96247.82c -0.0 + 96248.82c -0.0 + 96249.82c -0.0 + 96250.82c -0.0 + 97245.82c -0.0 + 97246.82c -0.0 + 97247.82c -0.0 + 97248.82c -0.0 + 97249.82c -0.0 + 97250.82c -0.0 + 98246.82c -0.0 + 98248.82c -0.0 + 98249.82c -0.0 + 98250.82c -0.0 + 98251.82c -0.0 + 98252.82c -0.0 + 98253.82c -0.0 + 98254.82c -0.0 + 99251.82c -0.0 + 99252.82c -0.0 + 99253.82c -0.0 + 99254.82c -0.0 + 99654.82c -0.0 + 99255.82c -0.0 + 100255.82c -0.0 From 219d952e3e47fdbb3d9ce687e8ed1bc2f808e564 Mon Sep 17 00:00:00 2001 From: yardasol Date: Tue, 25 Jul 2023 14:12:55 -0500 Subject: [PATCH 56/62] add style and tests page for the dev guide --- doc/devguide/style.rst | 5 ++++- doc/devguide/tests.rst | 14 +++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/doc/devguide/style.rst b/doc/devguide/style.rst index 73fbb69ad..2db659868 100644 --- a/doc/devguide/style.rst +++ b/doc/devguide/style.rst @@ -3,4 +3,7 @@ Style Guide =========== -Coming soon! +Style for Python code must follow PEP8_. + +.. _PEP8: https://www.python.org/dev/peps/pep-0008/ + diff --git a/doc/devguide/tests.rst b/doc/devguide/tests.rst index d230cfa53..83fee7de4 100644 --- a/doc/devguide/tests.rst +++ b/doc/devguide/tests.rst @@ -3,4 +3,16 @@ Test Suite ========== -Coming soon! +The SaltProc test suite uses the JEFF 3.1.2 library for Serpent2 integration +tests, and the ENDF/B VII.1 library for OpenMC integration tests. You can +obtain the JEFF 3.1.2 library by running the `process_j312.bash` script +under `scripts/xsdata`, and you can obtain the ENDF/B VII.1 library +for OpenMC from `this_` link, which you can also find on +`openmc.org `_. The test suite +requires the pytest_ package. + +.. _this: https://anl.box.com/shared/static/9igk353zpy8fn9ttvtrqgzvw1vtejoz6.xz +.. _pytest: https://docs.pytest.org + +Whenever a new feature or function is added, a test should also be added +for that feature. From a3da37fb2852ba01bcf347045affb0ae8af97872 Mon Sep 17 00:00:00 2001 From: yardasol Date: Wed, 30 Aug 2023 11:09:27 -0500 Subject: [PATCH 57/62] @smpark7 review --- doc/devguide/tests.rst | 4 ++-- examples/msbr/openmc_msbr_model.py | 6 +++--- saltproc/app.py | 15 ++++++++------- saltproc/materialflow.py | 7 ++++--- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/doc/devguide/tests.rst b/doc/devguide/tests.rst index 83fee7de4..b98998cbd 100644 --- a/doc/devguide/tests.rst +++ b/doc/devguide/tests.rst @@ -7,9 +7,9 @@ The SaltProc test suite uses the JEFF 3.1.2 library for Serpent2 integration tests, and the ENDF/B VII.1 library for OpenMC integration tests. You can obtain the JEFF 3.1.2 library by running the `process_j312.bash` script under `scripts/xsdata`, and you can obtain the ENDF/B VII.1 library -for OpenMC from `this_` link, which you can also find on +for OpenMC from `this`_ link, which you can also find on `openmc.org `_. The test suite -requires the pytest_ package. +requires the `pytest`_ package. .. _this: https://anl.box.com/shared/static/9igk353zpy8fn9ttvtrqgzvw1vtejoz6.xz .. _pytest: https://docs.pytest.org diff --git a/examples/msbr/openmc_msbr_model.py b/examples/msbr/openmc_msbr_model.py index 55de5247f..e4a02f178 100644 --- a/examples/msbr/openmc_msbr_model.py +++ b/examples/msbr/openmc_msbr_model.py @@ -35,13 +35,13 @@ def create_mass_percents_dictionary(mat): return dict(zip(nucs, mass_percents)) if MAT_FLAG == 'model': - vals = np.array([71.75,71.75,16.0,16.0, 12.0,12.0, 0.25,0.25]) + vals = np.array([71.75, 71.75, 16.0, 16.0, 12.0, 12.0, 0.25, 0.25]) else: - vals = np.array([71.7,71.7,16.0,16.0, 12.0,12.0, 0.3,0.3]) + vals = np.array([71.7, 71.7, 16.0, 16.0, 12.0, 12.0, 0.3, 0.3]) # Mol fractions comps = np.array([1, 1, 1, 2, 1, 4, 1, 4]) nucs = (['Li', 'F', 'Be', 'F', 'Th', 'F', 'U', 'F']) -vals = comps*vals +vals = comps * vals # Li, F, Be, Th, U tots = ([vals[0], vals[1] + vals[3] + vals[5] + vals[7], vals[2], vals[4], vals[6]]) diff --git a/saltproc/app.py b/saltproc/app.py index e7693529e..d4dc6d40b 100644 --- a/saltproc/app.py +++ b/saltproc/app.py @@ -73,7 +73,11 @@ def run(): simulation.store_step_metadata() # Reprocessing here - if not run_without_reprocessing: + if run_without_reprocessing: + waste_and_feed_streams = None + waste_streams = None + extracted_mass = None + else: for key in mats.keys(): print('\nMass and volume of ' f'{key} before reproc: {mats[key].mass} g, ', @@ -96,11 +100,8 @@ def run(): f'{mats[key].volume} cm3') print("Removed mass [g]:", extracted_mass) - else: - waste_and_feed_streams = None - waste_streams = None - extracted_mass = None - # Store in DB after reprocessing and refill (right before next depl) + + # Store in DB after reprocessing and refill (right before next depl) simulation.store_after_repr(mats, waste_and_feed_streams, step_idx) depcode.update_depletable_materials(mats, simulation.burn_time) @@ -165,7 +166,7 @@ def read_main_input(main_inp_file): Arguments for running simulations on supercomputers using mpiexec or similar programs. rebuild_saltproc_results : bool - Flag to indicate wheter or not to rebuild SaltProc results file + Flag to indicate whether or not to rebuild SaltProc results file from existing depcode results run_without_reprocessing : bool Flag to indicate whether or not to run the depletion code in diff --git a/saltproc/materialflow.py b/saltproc/materialflow.py index e5e1238a2..dcaee93e1 100644 --- a/saltproc/materialflow.py +++ b/saltproc/materialflow.py @@ -92,7 +92,6 @@ def replace_components(self, comp, comp_is_density=False): self.mass = density * self.volume self.comp = comp else: - density = 0.0 self.comp = comp self.mass = 0.0 @@ -224,9 +223,11 @@ def __add__(x, y): Materialflow which is a sum of isotope masses from `x` and `y`. """ - if x.mass == 0.0 or x.volume == 0.0 and y.mass != 0.0 and y.volume != 0.0: + if (x.mass == 0.0 or x.volume == 0.0) \ + and (y.mass != 0.0 and y.volume != 0.0): return y - elif y.mass == 0.0 or y.volume == 0.0 and x.mass != 0.0 and x.volume != 0.0: + elif (x.mass != 0.0 and x.volume != 0.0) \ + and (y.mass == 0.0 or y.volume == 0.0): return x else: cls = x.__class__ From 911abe72f29b8b28b3b39bbc122055e0d5bb1a39 Mon Sep 17 00:00:00 2001 From: yardasol Date: Wed, 30 Aug 2023 11:24:36 -0500 Subject: [PATCH 58/62] remove temperature --- saltproc/materialflow.py | 10 ++----- saltproc/simulation.py | 4 +-- .../database_storage/test.py | 28 ++++++++----------- .../run_constant_reprocessing_openmc/test.py | 2 -- .../run_constant_reprocessing_serpent/test.py | 2 -- 5 files changed, 15 insertions(+), 31 deletions(-) diff --git a/saltproc/materialflow.py b/saltproc/materialflow.py index dcaee93e1..8761f06fd 100644 --- a/saltproc/materialflow.py +++ b/saltproc/materialflow.py @@ -119,7 +119,6 @@ def print_attr(self): print("Mass %f g" % self.mass) print("Density %f g/cm3" % self.density) print("Mass flowrate %f g/s" % self.mass_flowrate) - print("Temperature %f K" % self.temperature) print("Void fraction %f " % self.void_frac) print("Burnup %f MWd/kgU" % self.burnup) @@ -171,13 +170,12 @@ def __deepcopy__(self, memo): volume=self.volume, mass_flowrate=self.mass_flowrate, void_frac=self.void_frac, - burnup=self.burnup, - temperature=self.temperature) + burnup=self.burnup) return result def __eq__(self, other): """Overrides Python ``=`` operation to compare two Materialflow - objects. Compares objects total mass, volume temperature, + objects. Compares objects total mass, volume, and mass flowrate. Parameters @@ -199,7 +197,6 @@ def __eq__(self, other): other.mass, abs_tol=1e-15) \ and self.volume == other.volume \ - and self.temperature == other.temperature \ and self.mass_flowrate == other.mass_flowrate return value @@ -258,8 +255,6 @@ def get_mass_dict(matflow): result_comp = dict(zip(x_mass_dict.keys(), masses)) result.replace_components(result_comp) result.mass_flowrate = x.mass_flowrate + y.mass_flowrate - # result.temp = (x.temerature*x.mass + y.temperature*y.mass)/result_mass # averaged - result.temperature = x.temperature # Burnup is simply averaged by should be renormalized by heavy metal # use self.fissionable_mass? result.burnup = (x.burnup * x.mass + y.burnup * y.mass) / result_mass @@ -288,7 +283,6 @@ def __rmul__(self, scaling_factor): result.volume = scaling_factor * self.volume result.mass = result.volume * result.get_density() result.mass_flowrate = scaling_factor * self.mass_flowrate - # result.temperature = (x.temperature*x.get_mass() + y.temperature*y.get_mass())/result.get_mass() return result else: NotImplemented diff --git a/saltproc/simulation.py b/saltproc/simulation.py index 54608df78..e1cf67fa4 100644 --- a/saltproc/simulation.py +++ b/saltproc/simulation.py @@ -316,7 +316,7 @@ def store_mat_data(self, mats, dep_step, store_at_end=False): """Initialize the HDF5/Pytables database (if it doesn't exist) or append the following data at the current depletion step to the database: burnable material composition, mass, density, volume, - temperature, burnup, mass_flowrate, void_fraction. + burnup, mass_flowrate, void_fraction. Parameters ---------- @@ -348,7 +348,6 @@ def store_mat_data(self, mats, dep_step, store_at_end=False): ('mass', float), ('density', float), ('volume', float), - ('temperature', float), ('mass_flowrate', float), ('void_fraction', float), ('burnup', float) @@ -399,7 +398,6 @@ def store_mat_data(self, mats, dep_step, store_at_end=False): mats[key].mass, mats[key].get_density(), mats[key].volume, - mats[key].temperature, mats[key].mass_flowrate, mats[key].void_frac, mats[key].burnup diff --git a/tests/integration_tests/database_storage/test.py b/tests/integration_tests/database_storage/test.py index 8930138e4..ea3979e32 100644 --- a/tests/integration_tests/database_storage/test.py +++ b/tests/integration_tests/database_storage/test.py @@ -184,34 +184,30 @@ def test_store_mat_data(simulation): assert tfuel_before_params[0] == fuel_before.mass assert tfuel_before_params[1] == fuel_before.density assert tfuel_before_params[2] == fuel_before.volume - #assert tfuel_before_params[3] == fuel_before.temperature - assert tfuel_before_params[4] == fuel_before.mass_flowrate - assert tfuel_before_params[5] == fuel_before.void_frac - assert tfuel_before_params[6] == fuel_before.burnup + assert tfuel_before_params[3] == fuel_before.mass_flowrate + assert tfuel_before_params[4] == fuel_before.void_frac + assert tfuel_before_params[5] == fuel_before.burnup assert tpois_before_params[0] == pois_before.mass assert tpois_before_params[1] == pois_before.density assert tpois_before_params[2] == pois_before.volume - #assert tpois_before_params[3] == pois_before.temperature - assert tpois_before_params[4] == pois_before.mass_flowrate - assert tpois_before_params[5] == pois_before.void_frac - assert tpois_before_params[6] == pois_before.burnup + assert tpois_before_params[3] == pois_before.mass_flowrate + assert tpois_before_params[4] == pois_before.void_frac + assert tpois_before_params[5] == pois_before.burnup assert tfuel_after_params[0] == fuel_after.mass assert tfuel_after_params[1] == fuel_after.density assert tfuel_after_params[2] == fuel_after.volume - #assert tfuel_after_params[3] == fuel_after.temperature - assert tfuel_after_params[4] == fuel_after.mass_flowrate - assert tfuel_after_params[5] == fuel_after.void_frac - assert tfuel_after_params[6] == fuel_after.burnup + assert tfuel_after_params[3] == fuel_after.mass_flowrate + assert tfuel_after_params[4] == fuel_after.void_frac + assert tfuel_after_params[5] == fuel_after.burnup assert tpois_after_params[0] == pois_after.mass assert tpois_after_params[1] == pois_after.density assert tpois_after_params[2] == pois_after.volume - #assert tpois_after_params[3] == pois_after.temperature - assert tpois_after_params[4] == pois_after.mass_flowrate - assert tpois_after_params[5] == pois_after.void_frac - assert tpois_after_params[6] == pois_after.burnup + assert tpois_after_params[3] == pois_after.mass_flowrate + assert tpois_after_params[4] == pois_after.void_frac + assert tpois_after_params[5] == pois_after.burnup # close the file db.close() diff --git a/tests/integration_tests/run_constant_reprocessing_openmc/test.py b/tests/integration_tests/run_constant_reprocessing_openmc/test.py index 5f122e0e1..4c297df90 100644 --- a/tests/integration_tests/run_constant_reprocessing_openmc/test.py +++ b/tests/integration_tests/run_constant_reprocessing_openmc/test.py @@ -154,8 +154,6 @@ def read_fuel(file): for tmp in (tmp_after, tmp_before): # Convert structured array to simple array params = tmp.view(np.float64).reshape(tmp.shape + (-1,)) - # remove temperature as it is broken right now. - params = np.concatenate((params[:,0:3], params[:, 4:]), axis=1) all_params += [params] after_params, before_params = all_params db.close() diff --git a/tests/integration_tests/run_constant_reprocessing_serpent/test.py b/tests/integration_tests/run_constant_reprocessing_serpent/test.py index 380a67c7d..88d714202 100644 --- a/tests/integration_tests/run_constant_reprocessing_serpent/test.py +++ b/tests/integration_tests/run_constant_reprocessing_serpent/test.py @@ -202,8 +202,6 @@ def read_fuel(file, version): for tmp in (tmp_after, tmp_before): # Convert structured array to simple array params = tmp.view(np.float64).reshape(tmp.shape + (-1,)) - # remove temperature as it is broken right now. - params = np.concatenate((params[:,0:3], params[:, 4:]), axis=1) all_params += [params] after_params, before_params = all_params db.close() From 1f3ffbf5b6604331b4127998093eb4f4a121b0ef Mon Sep 17 00:00:00 2001 From: yardasol Date: Tue, 5 Sep 2023 15:16:33 -0500 Subject: [PATCH 59/62] remove openmc source build from CI --- .github/workflows/cache-dependencies.yml | 25 +---------- .github/workflows/test-saltproc.yml | 26 +----------- tools/ci/build-openmc.sh | 54 ------------------------ tools/ci/restore-openmc.sh | 30 ------------- 4 files changed, 4 insertions(+), 131 deletions(-) delete mode 100755 tools/ci/build-openmc.sh delete mode 100755 tools/ci/restore-openmc.sh diff --git a/.github/workflows/cache-dependencies.yml b/.github/workflows/cache-dependencies.yml index 08c2ee96d..d849265cd 100644 --- a/.github/workflows/cache-dependencies.yml +++ b/.github/workflows/cache-dependencies.yml @@ -17,15 +17,6 @@ jobs: run: shell: bash -l {0} - env: - MPI: no - OMP: no - PHDF5: no - DAGMC: no - EVENT: no - VECTFIT: no - LIBMESH: no - steps: - uses: actions/checkout@v3 @@ -51,7 +42,6 @@ jobs: with: path: | /usr/share/miniconda3/envs/saltproc-env - ~/openmc_src ~/endfb71_hdf5 ~/.cache/pip key: depcache-${{ hashFiles('environment.yml') }}-${{ env.DATE }}-${{ env.CACHE_NUMBER }} @@ -72,19 +62,8 @@ jobs: - name: Download OpenMC if: steps.dependencies-cache.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: openmc-dev/openmc - path: openmc - submodules: recursive - - - name: Build OpenMC from source if no cache if found - if: steps.dependencies-cache.outputs.cache-hit != 'true' - run: $GITHUB_WORKSPACE/tools/ci/build-openmc.sh - - - name: Restore OpenMC source build from cache - if: steps.dependencies-cache.outputs.cache-hit == 'true' - run: $GITHUB_WORKSPACE/tools/ci/restore-openmc.sh + run: | + mamba install openmc - name: Install SaltProc run: pip install . diff --git a/.github/workflows/test-saltproc.yml b/.github/workflows/test-saltproc.yml index 446af254f..0854b8657 100644 --- a/.github/workflows/test-saltproc.yml +++ b/.github/workflows/test-saltproc.yml @@ -23,15 +23,6 @@ jobs: run: shell: bash -l {0} - env: - MPI: no - OMP: no - PHDF5: no - DAGMC: no - EVENT: no - VECTFIT: no - LIBMESH: no - steps: - uses: actions/checkout@v3 @@ -57,8 +48,6 @@ jobs: with: path: | /usr/share/miniconda3/envs/saltproc-env - ~/openmc_src - ~/mcpl_src ~/endfb71_hdf5 ~/.cache/pip key: depcache-${{ hashFiles('environment.yml') }}-${{ env.DATE }}-${{ env.CACHE_NUMBER }} @@ -79,20 +68,9 @@ jobs: - name: Download OpenMC if: steps.dependencies-cache.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: openmc-dev/openmc - path: openmc - submodules: recursive - - - name: Build OpenMC from source if no cache is found - if: steps.dependencies-cache.outputs.cache-hit != 'true' - run: $GITHUB_WORKSPACE/tools/ci/build-openmc.sh + run: | + mamba install openmc - - name: Restore OpenMC source build from cache - if: steps.dependencies-cache.outputs.cache-hit == 'true' - run: $GITHUB_WORKSPACE/tools/ci/restore-openmc.sh - - name: Install SaltProc run: pip install . diff --git a/tools/ci/build-openmc.sh b/tools/ci/build-openmc.sh deleted file mode 100755 index c042e2594..000000000 --- a/tools/ci/build-openmc.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash -set -ex - -# Build openmc -cd openmc -./tools/ci/gha-install-mcpl.sh -python tools/ci/gha-install.py - -# Create the caching folder -DIRS=(openmc_src mcpl_src) -for DIR in ${DIRS[@]}; do - mkdir $DIR - mkdir $DIR/bin - mkdir $DIR/lib - mkdir $DIR/share - mkdir $DIR/include -done - -# Copy libraries to caching folder -cp /usr/local/bin/openmc openmc_src/bin/. -cp /usr/local/lib/libopenmc.so openmc_src/lib/. -cp -r /usr/local/lib/cmake openmc_src/lib/. -cp /usr/local/lib/libpugixml.a openmc_src/lib/. -cp -r /usr/local/lib/pkgconfig openmc_src/lib/. -#cp -r /usr/local/share/openmc openmc_src/share/. -#cp -r /usr/local/share/man openmc_src/share/. -cp -r /usr/local/include/openmc openmc_src/include/. -cp /usr/local/include/pugiconfig.hpp openmc_src/include/. -cp /usr/local/include/pugixml.hpp openmc_src/include/. -INCLUDES=(fmt xtl xtensor gsl gsl-lite openmc) -for I in ${INCLUDES[@]}; do - cp -r /usr/local/include/$I openmc_src/include/. -done - -# MCPL stuff -cp /usr/local/lib/libmcpl.so mcpl_src/lib/. -cp /usr/local/include/mcpl.h mcpl_src/include/. -cp /usr/local/lib/libsswmcpl.so mcpl_src/lib/. -cp /usr/local/lib/libphitsmcpl.so mcpl_src/lib/. -cp -r /usr/local/share/MCPL mcpl_src/share/. - -MCPL_BINARIES=(pymcpltool mcpl-config mcpl2ssw ssw2mcpl mcpl2phits phits2mcpl mcpltool) -for BINARY in ${MCPL_BINARIES[@]}; do - cp /usr/local/bin/$BINARY mcpl_src/bin/. -done - - -# Move the caching folders to $HOME -mv openmc_src $HOME/openmc_src -mv mcpl_src $HOME/mcpl_src - -# Install the OpenMC python API -pip install . -cd ../ diff --git a/tools/ci/restore-openmc.sh b/tools/ci/restore-openmc.sh deleted file mode 100755 index 35fb60ab1..000000000 --- a/tools/ci/restore-openmc.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -set -ex - -# Move cached OpenMC libaries to PATH -sudo mv $HOME/openmc_src/bin/openmc /usr/local/bin/openmc -OPENMC_LIBS=(libopenmc.so cmake libpugixml.a pkgconfig) -for LIB in ${OPENMC_LIBS[@]}; do - sudo mv $HOME/openmc_src/lib/$LIB /usr/local/lib/. -done - -sudo mv $HOME/openmc_src/lib/ /usr/local/lib/ -#sudo mv $HOME/openmc_src/share/openmc /usr/local/share/openmc -#sudo mv $HOME/openmc_src/share/man /usr/local/share/man -INCLUDES=(fmt xtl xtensor gsl gsl-lite openmc pugixml.hpp pugiconfig.hpp) -for I in ${INCLUDES[@]}; do - sudo mv $HOME/openmc_src/include/$I /usr/local/include/$I -done - -# Move MCPL stuff -MCPL_BINARIES=(pymcpltool mcpl-config mcpltool mcpl2ssw ssw2mcpl mcpl2phits phits2mcpl) -for BINARY in ${MCPL_BINARIES[@]}; do - sudo mv $HOME/mcpl_src/bin/$BINARY /usr/local/bin/. -done - -MCPL_LIBS=(libsswmcpl.so libphitsmcpl.so libmcpl.so) -for LIB in ${MCPL_LIBS[@]}; do - sudo mv $HOME/mcpl_src/lib/$LIB /usr/local/lib/. -done -sudo mv $HOME/mcpl_src/include/mcpl.h /usr/local/include/. -sudo mv $HOME/mcpl_src/share/MCPL /usr/local/share/. From cc50a433ec6469e891d0549d43b0afc127e98f4d Mon Sep 17 00:00:00 2001 From: yardasol Date: Tue, 5 Sep 2023 15:22:13 -0500 Subject: [PATCH 60/62] remove comments --- saltproc/materialflow.py | 2 -- saltproc/process.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/saltproc/materialflow.py b/saltproc/materialflow.py index 8761f06fd..3e29e62ce 100644 --- a/saltproc/materialflow.py +++ b/saltproc/materialflow.py @@ -235,8 +235,6 @@ def __add__(x, y): x_density = x.mass / x.volume y_density = y.mass / y.volume - #result_density = x_density * y_density * (x.mass + y.mass) / \ - # (x.mass * y_density + y.mass * x_density) result_density = x_density result_volume = result_mass / result_density diff --git a/saltproc/process.py b/saltproc/process.py index 5f17f4fdc..1fc9df64c 100644 --- a/saltproc/process.py +++ b/saltproc/process.py @@ -157,8 +157,6 @@ def process_material(self, inflow): thru_flow.volume = thru_flow.volume * \ total_thru_mass / thru_flow.get_mass() thru_flow.mass = total_thru_mass - #thru_flow.mass = float(inflow.mass - waste_stream.mass) - #thru_flow.norm_comp() del thru_mass, waste_mass From c45c1790277cc436aca139fe149cf81d44f7914c Mon Sep 17 00:00:00 2001 From: yardasol Date: Wed, 6 Sep 2023 11:06:22 -0500 Subject: [PATCH 61/62] Revert "remove openmc source build from CI" This reverts commit 1f3ffbf5b6604331b4127998093eb4f4a121b0ef. --- .github/workflows/cache-dependencies.yml | 25 ++++++++++- .github/workflows/test-saltproc.yml | 26 +++++++++++- tools/ci/build-openmc.sh | 54 ++++++++++++++++++++++++ tools/ci/restore-openmc.sh | 30 +++++++++++++ 4 files changed, 131 insertions(+), 4 deletions(-) create mode 100755 tools/ci/build-openmc.sh create mode 100755 tools/ci/restore-openmc.sh diff --git a/.github/workflows/cache-dependencies.yml b/.github/workflows/cache-dependencies.yml index d849265cd..08c2ee96d 100644 --- a/.github/workflows/cache-dependencies.yml +++ b/.github/workflows/cache-dependencies.yml @@ -17,6 +17,15 @@ jobs: run: shell: bash -l {0} + env: + MPI: no + OMP: no + PHDF5: no + DAGMC: no + EVENT: no + VECTFIT: no + LIBMESH: no + steps: - uses: actions/checkout@v3 @@ -42,6 +51,7 @@ jobs: with: path: | /usr/share/miniconda3/envs/saltproc-env + ~/openmc_src ~/endfb71_hdf5 ~/.cache/pip key: depcache-${{ hashFiles('environment.yml') }}-${{ env.DATE }}-${{ env.CACHE_NUMBER }} @@ -62,8 +72,19 @@ jobs: - name: Download OpenMC if: steps.dependencies-cache.outputs.cache-hit != 'true' - run: | - mamba install openmc + uses: actions/checkout@v3 + with: + repository: openmc-dev/openmc + path: openmc + submodules: recursive + + - name: Build OpenMC from source if no cache if found + if: steps.dependencies-cache.outputs.cache-hit != 'true' + run: $GITHUB_WORKSPACE/tools/ci/build-openmc.sh + + - name: Restore OpenMC source build from cache + if: steps.dependencies-cache.outputs.cache-hit == 'true' + run: $GITHUB_WORKSPACE/tools/ci/restore-openmc.sh - name: Install SaltProc run: pip install . diff --git a/.github/workflows/test-saltproc.yml b/.github/workflows/test-saltproc.yml index 0854b8657..446af254f 100644 --- a/.github/workflows/test-saltproc.yml +++ b/.github/workflows/test-saltproc.yml @@ -23,6 +23,15 @@ jobs: run: shell: bash -l {0} + env: + MPI: no + OMP: no + PHDF5: no + DAGMC: no + EVENT: no + VECTFIT: no + LIBMESH: no + steps: - uses: actions/checkout@v3 @@ -48,6 +57,8 @@ jobs: with: path: | /usr/share/miniconda3/envs/saltproc-env + ~/openmc_src + ~/mcpl_src ~/endfb71_hdf5 ~/.cache/pip key: depcache-${{ hashFiles('environment.yml') }}-${{ env.DATE }}-${{ env.CACHE_NUMBER }} @@ -68,9 +79,20 @@ jobs: - name: Download OpenMC if: steps.dependencies-cache.outputs.cache-hit != 'true' - run: | - mamba install openmc + uses: actions/checkout@v3 + with: + repository: openmc-dev/openmc + path: openmc + submodules: recursive + + - name: Build OpenMC from source if no cache is found + if: steps.dependencies-cache.outputs.cache-hit != 'true' + run: $GITHUB_WORKSPACE/tools/ci/build-openmc.sh + - name: Restore OpenMC source build from cache + if: steps.dependencies-cache.outputs.cache-hit == 'true' + run: $GITHUB_WORKSPACE/tools/ci/restore-openmc.sh + - name: Install SaltProc run: pip install . diff --git a/tools/ci/build-openmc.sh b/tools/ci/build-openmc.sh new file mode 100755 index 000000000..c042e2594 --- /dev/null +++ b/tools/ci/build-openmc.sh @@ -0,0 +1,54 @@ +#!/bin/bash +set -ex + +# Build openmc +cd openmc +./tools/ci/gha-install-mcpl.sh +python tools/ci/gha-install.py + +# Create the caching folder +DIRS=(openmc_src mcpl_src) +for DIR in ${DIRS[@]}; do + mkdir $DIR + mkdir $DIR/bin + mkdir $DIR/lib + mkdir $DIR/share + mkdir $DIR/include +done + +# Copy libraries to caching folder +cp /usr/local/bin/openmc openmc_src/bin/. +cp /usr/local/lib/libopenmc.so openmc_src/lib/. +cp -r /usr/local/lib/cmake openmc_src/lib/. +cp /usr/local/lib/libpugixml.a openmc_src/lib/. +cp -r /usr/local/lib/pkgconfig openmc_src/lib/. +#cp -r /usr/local/share/openmc openmc_src/share/. +#cp -r /usr/local/share/man openmc_src/share/. +cp -r /usr/local/include/openmc openmc_src/include/. +cp /usr/local/include/pugiconfig.hpp openmc_src/include/. +cp /usr/local/include/pugixml.hpp openmc_src/include/. +INCLUDES=(fmt xtl xtensor gsl gsl-lite openmc) +for I in ${INCLUDES[@]}; do + cp -r /usr/local/include/$I openmc_src/include/. +done + +# MCPL stuff +cp /usr/local/lib/libmcpl.so mcpl_src/lib/. +cp /usr/local/include/mcpl.h mcpl_src/include/. +cp /usr/local/lib/libsswmcpl.so mcpl_src/lib/. +cp /usr/local/lib/libphitsmcpl.so mcpl_src/lib/. +cp -r /usr/local/share/MCPL mcpl_src/share/. + +MCPL_BINARIES=(pymcpltool mcpl-config mcpl2ssw ssw2mcpl mcpl2phits phits2mcpl mcpltool) +for BINARY in ${MCPL_BINARIES[@]}; do + cp /usr/local/bin/$BINARY mcpl_src/bin/. +done + + +# Move the caching folders to $HOME +mv openmc_src $HOME/openmc_src +mv mcpl_src $HOME/mcpl_src + +# Install the OpenMC python API +pip install . +cd ../ diff --git a/tools/ci/restore-openmc.sh b/tools/ci/restore-openmc.sh new file mode 100755 index 000000000..35fb60ab1 --- /dev/null +++ b/tools/ci/restore-openmc.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -ex + +# Move cached OpenMC libaries to PATH +sudo mv $HOME/openmc_src/bin/openmc /usr/local/bin/openmc +OPENMC_LIBS=(libopenmc.so cmake libpugixml.a pkgconfig) +for LIB in ${OPENMC_LIBS[@]}; do + sudo mv $HOME/openmc_src/lib/$LIB /usr/local/lib/. +done + +sudo mv $HOME/openmc_src/lib/ /usr/local/lib/ +#sudo mv $HOME/openmc_src/share/openmc /usr/local/share/openmc +#sudo mv $HOME/openmc_src/share/man /usr/local/share/man +INCLUDES=(fmt xtl xtensor gsl gsl-lite openmc pugixml.hpp pugiconfig.hpp) +for I in ${INCLUDES[@]}; do + sudo mv $HOME/openmc_src/include/$I /usr/local/include/$I +done + +# Move MCPL stuff +MCPL_BINARIES=(pymcpltool mcpl-config mcpltool mcpl2ssw ssw2mcpl mcpl2phits phits2mcpl) +for BINARY in ${MCPL_BINARIES[@]}; do + sudo mv $HOME/mcpl_src/bin/$BINARY /usr/local/bin/. +done + +MCPL_LIBS=(libsswmcpl.so libphitsmcpl.so libmcpl.so) +for LIB in ${MCPL_LIBS[@]}; do + sudo mv $HOME/mcpl_src/lib/$LIB /usr/local/lib/. +done +sudo mv $HOME/mcpl_src/include/mcpl.h /usr/local/include/. +sudo mv $HOME/mcpl_src/share/MCPL /usr/local/share/. From cddec52314b1974e6e68e9b6d4b38a0faa55900a Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 7 Sep 2023 12:55:24 -0500 Subject: [PATCH 62/62] update release notes --- doc/releasenotes/v0.5.0.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/releasenotes/v0.5.0.rst b/doc/releasenotes/v0.5.0.rst index d57b5517b..8ec0eead5 100644 --- a/doc/releasenotes/v0.5.0.rst +++ b/doc/releasenotes/v0.5.0.rst @@ -212,6 +212,10 @@ Python API Changes - (new) → ``timestep_units`` - (new) → ``timestep_type`` + - (new) → ``Results`` + + - New class for reading the `saltproc_results.h5` file + - ``Simulation`` - ``core_number`` → (removed) @@ -252,4 +256,10 @@ The following people reviewed code for this release of SaltProc: .. `@gh_username `_ +- `@smpark7 `_ +- `@LukeSeifert `_ +- `@munkm `_ +- `@abachma2 `_ + +