diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index efe8dbe84..8ab052b0d 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -72,6 +72,11 @@ class Library: Number of equi-width polar angle bins for angle discretization num_azimuthal : Integral Number of equi-width azimuthal angle bins for angle discretization + nuclides : Iterable of str or 'sum' + The optional user-specified nuclides for which to compute cross + sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides + are not specified by the user, all nuclides in the domain + are included. estimator : str or None The tally estimator used to compute multi-group cross sections. If None, the default for each MGXS type is used. @@ -107,6 +112,7 @@ class Library: self._energy_groups = None self._num_polar = 1 self._num_azimuthal = 1 + self._nuclides = None self._num_delayed_groups = 0 self._correction = 'P0' self._scatter_format = 'legendre' @@ -145,6 +151,7 @@ class Library: clone._energy_groups = copy.deepcopy(self.energy_groups, memo) clone._num_polar = self.num_polar clone._num_azimuthal = self.num_azimuthal + clone._nuclides = self._nuclides clone._num_delayed_groups = self.num_delayed_groups clone._tally_trigger = copy.deepcopy(self.tally_trigger, memo) clone._all_mgxs = copy.deepcopy(self.all_mgxs) @@ -205,6 +212,10 @@ class Library: else: return self._domains + @property + def nuclides(self): + return self._nuclides + @property def energy_groups(self): return self._energy_groups @@ -275,6 +286,11 @@ class Library: cv.check_type('name', name, str) self._name = name + @nuclides.setter + def nuclides(self, nuclides): + cv.check_iterable_type('nuclides', nuclides, str) + self._nuclides = nuclides + @mgxs_types.setter def mgxs_types(self, mgxs_types): all_mgxs_types = openmc.mgxs.MGXS_TYPES + openmc.mgxs.MDGXS_TYPES + \ @@ -524,6 +540,20 @@ class Library: mgxs.legendre_order = self.legendre_order mgxs.histogram_bins = self.histogram_bins + if self.by_nuclide: + try: + domain_nuclides = domain.get_nuclides() + except AttributeError: + domain_nuclides = None + if self.nuclides: + if domain_nuclides: + mgxs.nuclides = [ + nuclide for nuclide in self.nuclides + if nuclide in domain_nuclides + ] + ["total"] + else: + mgxs.nuclides = self.nuclides + self.all_mgxs[domain.id][mgxs_type] = mgxs def add_to_tallies_file(self, tallies_file, merge=True): @@ -590,7 +620,7 @@ class Library: self._sp_filename = statepoint._f.filename self._geometry = statepoint.summary.geometry - self._nuclides = statepoint.summary.nuclides + self._atomic_weight_ratios = statepoint.summary.nuclides if statepoint.run_mode == 'eigenvalue': self._keff = statepoint.keff.n @@ -1005,7 +1035,7 @@ class Library: xsdata.num_azimuthal = self.num_azimuthal if nuclide != 'total': - xsdata.atomic_weight_ratio = self._nuclides[nuclide] + xsdata.atomic_weight_ratio = self._atomic_weight_ratios[nuclide] if subdomain is None: subdomain = 'all' diff --git a/tests/regression_tests/mgxs_library_specific_nuclides/__init__.py b/tests/regression_tests/mgxs_library_specific_nuclides/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/regression_tests/mgxs_library_specific_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_specific_nuclides/inputs_true.dat new file mode 100644 index 000000000..061aa1b95 --- /dev/null +++ b/tests/regression_tests/mgxs_library_specific_nuclides/inputs_true.dat @@ -0,0 +1,218 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + + + + + 1 2 3 + + + 0.0 0.625 20000000.0 + + + 1 + + + 0.0 0.625 20000000.0 + + + 1 + + + 3 + + + 0.0 20000000.0 + + + 2 + + + 3 + + + 383 2 + total + flux + tracklength + + + 1 2 + U235 total + total absorption (n,2n) (n,3n) (n,4n) fission nu-fission kappa-fission scatter inverse-velocity prompt-nu-fission (n,elastic) (n,level) (n,na) (n,nc) (n,gamma) (n,a) (n,Xa) heating damage-energy (n,n1) (n,a0) + tracklength + + + 383 2 + total + flux + analog + + + 1 5 6 + U235 total + scatter nu-scatter + analog + + + 1 2 + U235 total + nu-scatter + analog + + + 1 2 5 30 + U235 total + scatter nu-scatter + analog + + + 1 2 5 + U235 total + nu-scatter scatter nu-fission prompt-nu-fission (n,nc) (n,n1) (n,2n) + analog + + + 1 54 + U235 total + nu-fission prompt-nu-fission + analog + + + 1 5 + U235 total + nu-fission prompt-nu-fission + analog + + + 106 2 + Zr90 total + total absorption (n,2n) (n,3n) (n,4n) fission nu-fission kappa-fission scatter inverse-velocity prompt-nu-fission (n,elastic) (n,level) (n,na) (n,nc) (n,gamma) (n,a) (n,Xa) heating damage-energy (n,n1) (n,a0) + tracklength + + + 106 5 6 + Zr90 total + scatter nu-scatter + analog + + + 106 2 + Zr90 total + nu-scatter + analog + + + 106 2 5 30 + Zr90 total + scatter nu-scatter + analog + + + 106 2 5 + Zr90 total + nu-scatter scatter nu-fission prompt-nu-fission (n,nc) (n,n1) (n,2n) + analog + + + 106 54 + Zr90 total + nu-fission prompt-nu-fission + analog + + + 106 5 + Zr90 total + nu-fission prompt-nu-fission + analog + + + 251 2 + H1 total + total absorption (n,2n) (n,3n) (n,4n) fission nu-fission kappa-fission scatter inverse-velocity prompt-nu-fission (n,elastic) (n,level) (n,na) (n,nc) (n,gamma) (n,a) (n,Xa) heating damage-energy (n,n1) (n,a0) + tracklength + + + 251 5 6 + H1 total + scatter nu-scatter + analog + + + 251 2 + H1 total + nu-scatter + analog + + + 251 2 5 30 + H1 total + scatter nu-scatter + analog + + + 251 2 5 + H1 total + nu-scatter scatter nu-fission prompt-nu-fission (n,nc) (n,n1) (n,2n) + analog + + + 251 54 + H1 total + nu-fission prompt-nu-fission + analog + + + 251 5 + H1 total + nu-fission prompt-nu-fission + analog + + diff --git a/tests/regression_tests/mgxs_library_specific_nuclides/results_true.dat b/tests/regression_tests/mgxs_library_specific_nuclides/results_true.dat new file mode 100644 index 000000000..05ee40902 --- /dev/null +++ b/tests/regression_tests/mgxs_library_specific_nuclides/results_true.dat @@ -0,0 +1 @@ +3e86542d1166b8a0bcc61742b88c9e931d63733477f3274b32b4da64d8f05413fa6330d5615f44f24735c2c2f77d3071f3dce38faba284c321ceab81c1064480 \ No newline at end of file diff --git a/tests/regression_tests/mgxs_library_specific_nuclides/test.py b/tests/regression_tests/mgxs_library_specific_nuclides/test.py new file mode 100644 index 000000000..61910e539 --- /dev/null +++ b/tests/regression_tests/mgxs_library_specific_nuclides/test.py @@ -0,0 +1,71 @@ +import hashlib + +import openmc +import openmc.mgxs +from openmc.examples import pwr_pin_cell + +from tests.testing_harness import PyAPITestHarness + + +class MGXSTestHarness(PyAPITestHarness): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Initialize a two-group structure + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) + + # Initialize MGXS Library for a few cross section types + self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) + self.mgxs_lib.by_nuclide = True + + # Test relevant MGXS types + relevant_MGXS_TYPES = [item for item in openmc.mgxs.MGXS_TYPES + if item != 'current'] + # Add in a subset of openmc.mgxs.ARBITRARY_VECTOR_TYPES and + # openmc.mgxs.ARBITRARY_MATRIX_TYPES so we can see the code works, + # but not use too much resources + relevant_MGXS_TYPES += [ + "(n,elastic)", "(n,level)", "(n,2n)", "(n,na)", "(n,nc)", + "(n,gamma)", "(n,a)", "(n,Xa)", "heating", "damage-energy", + "(n,n1)", "(n,a0)", "(n,nc) matrix", "(n,n1) matrix", + "(n,2n) matrix"] + self.mgxs_lib.mgxs_types = tuple(relevant_MGXS_TYPES) + self.mgxs_lib.energy_groups = energy_groups + self.mgxs_lib.legendre_order = 3 + self.mgxs_lib.domain_type = 'material' + self.mgxs_lib.nuclides = ['U235', 'Zr90', 'H1'] + self.mgxs_lib.build_library() + + # Add tallies + self.mgxs_lib.add_to_tallies_file(self._model.tallies, merge=True) + + def _get_results(self, hash_output=True): + """Digest info in the statepoint and return as a string.""" + + # Read the statepoint file. + sp = openmc.StatePoint(self._sp_name) + + # Load the MGXS library from the statepoint + self.mgxs_lib.load_from_statepoint(sp) + + # Build a string from Pandas Dataframe for each MGXS + outstr = '' + for domain in self.mgxs_lib.domains: + for mgxs_type in self.mgxs_lib.mgxs_types: + mgxs = self.mgxs_lib.get_mgxs(domain, mgxs_type) + df = mgxs.get_pandas_dataframe() + outstr += df.to_string() + '\n' + + # Hash the results if necessary + if hash_output: + sha512 = hashlib.sha512() + sha512.update(outstr.encode('utf-8')) + outstr = sha512.hexdigest() + + return outstr + + +def test_mgxs_library_specific_nuclides(): + model = pwr_pin_cell() + harness = MGXSTestHarness('statepoint.10.h5', model) + harness.main()