diff --git a/docs/source/usersguide/depletion.rst b/docs/source/usersguide/depletion.rst index 261900ce61a..9a22adf0160 100644 --- a/docs/source/usersguide/depletion.rst +++ b/docs/source/usersguide/depletion.rst @@ -449,3 +449,42 @@ to transfer xenon from one material to another, you'd use:: ... integrator.add_transfer_rate(mat1, ['Xe'], 0.1, destination_material=mat2) + +Comparing to Other Codes +======================== + +Comparing depletion results from OpenMC with those from another code, such as +MCNP or Serpent, requires more than constructing equivalent transport models. +At each depletion step, differences in the transport solution, nuclear data, +reaction rate normalization, and numerical integration can all affect the +result. Small differences can also accumulate over successive depletion steps. + +For a meaningful comparison, align as many of the following inputs and methods +as possible: + +- Geometry and material definitions and associated physical properties such as + temperature +- Neutron cross section library (e.g., ENDF/B-VIII.0) +- Treatment of thermal scattering and unresolved resonance probability tables +- Neutron reactions accounted for in the depletion chain +- Decay data in the depletion chain +- Isomeric branching ratios for reactions in the depletion chain +- Fission product yields in the depletion chain +- Fission product yield interpolation method + (``CoupledOperator(fission_yield_mode=...)``) +- Reaction rate normalization, including fission Q values + (``CoupledOperator(fission_q=...)``) +- Depletion integration method (``PredictorIntegrator``, ``CECMIntegrator``, + etc.) and time-step sizes + +When comparing to codes that use ACE format cross sections, it is recommended to +directly convert the ACE files to HDF5 format using functionality from the +:mod:`openmc.data` module (see :ref:`create_xs_library`). Some of the +LANL-distributed ACE libraries used with MCNP have also been converted to HDF5 +format and are available for download at https://openmc.org/data. + +Even after these choices have been aligned, exact agreement should not be +expected. Codes may use different approximations or numerical methods that +cannot be configured identically. When investigating a discrepancy, first +compare transport results and one-group reaction rates at the initial time, then +compare changes over subsequent timesteps. diff --git a/openmc/model/model.py b/openmc/model/model.py index 11c26d4e719..56c0e7a49fa 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -265,22 +265,22 @@ def add_kinetics_parameters_tallies(self, num_groups: int | None = None): denom_tally = openmc.Tally(name='IFP denominator') denom_tally.scores = ['ifp-denominator'] self.tallies.append(denom_tally) - - # TODO: This should also be incorporated into lower-level calls in + + # TODO: This should also be incorporated into lower-level calls in # settings.py, but it requires information about the tallies currently # on the active Model def _assign_fw_cadis_tally_IDs(self): - # Verify that all tallies assigned as targets on WeightWindowGenerators - # exist within model.tallies. If this is the case, convert the .targets + # Verify that all tallies assigned as targets on WeightWindowGenerators + # exist within model.tallies. If this is the case, convert the .targets # attribute of each WeightWindowGenerator to a sequence of tally IDs. if len(self.settings.weight_window_generators) == 0: return - + # List of valid tally IDs reference_tally_ids = np.asarray([tal.id for tal in self.tallies]) - + for wwg in self.settings.weight_window_generators: - # Only proceeds if the "targets" attribute is an openmc.Tallies, + # Only proceeds if the "targets" attribute is an openmc.Tallies, # which means it hasn't been checked against model.tallies. if isinstance(wwg.targets, openmc.Tallies): id_vec = [] @@ -291,7 +291,7 @@ def _assign_fw_cadis_tally_IDs(self): if tal == reference_tal: id_next = reference_tal.id break - + if id_next == None: raise RuntimeError( f'Local FW-CADIS target tally {tal.id} not found on model.tallies!') @@ -1750,8 +1750,8 @@ def differentiate_mats(self, diff_volume_method: str = None, depletable_only: bo def _auto_generate_mgxs_lib( model: openmc.model.model, groups: openmc.mgxs.EnergyGroups, - correction: str | none, - directory: pathlike, + correction: str | None, + directory: PathLike, ) -> openmc.mgxs.Library: """ Automatically generate a multi-group cross section libray from a model @@ -1958,7 +1958,7 @@ def _isothermal_infinite_media_mgxs( # Set materials on the model model.materials = [material] - if temperature != None: + if temperature is not None: model.materials[-1].temperature = temperature # Settings @@ -1985,7 +1985,7 @@ def _isothermal_infinite_media_mgxs( mgxs_lib = Model._auto_generate_mgxs_lib( model, groups, correction, directory) - if temperature != None: + if temperature is not None: return mgxs_lib.get_xsdata(domain=material, xsdata_name=name, temperature=temperature) else: @@ -2058,12 +2058,12 @@ def _generate_infinite_medium_mgxs( ) temp_settings = {} - if temperature_settings == None: + if temperature_settings is None: temp_settings = self.settings.temperature else: temp_settings = temperature_settings - if temperatures == None: + if temperatures is None: mgxs_sets = [] for material in self.materials: xs_data = Model._isothermal_infinite_media_mgxs( @@ -2236,7 +2236,7 @@ def _isothermal_stochastic_slab_mgxs( model = openmc.Model() model.geometry = stoch_geom - if temperature != None: + if temperature is not None: for material in model.geometry.get_all_materials().values(): material.temperature = temperature @@ -2260,7 +2260,7 @@ def _isothermal_stochastic_slab_mgxs( model, groups, correction, directory) # Fetch all of the isothermal results. - if temperature != None: + if temperature is not None: return { mat.name : mgxs_lib.get_xsdata(domain=mat, xsdata_name=mat.name, temperature=temperature) @@ -2346,12 +2346,12 @@ def _generate_stochastic_slab_mgxs( ) temp_settings = {} - if temperature_settings == None: + if temperature_settings is None: temp_settings = self.settings.temperature else: temp_settings = temperature_settings - if temperatures == None: + if temperatures is None: mgxs_sets = Model._isothermal_stochastic_slab_mgxs( geo, groups, @@ -2444,7 +2444,7 @@ def _isothermal_materialwise_mgxs( model = copy.deepcopy(input_model) model.tallies = openmc.Tallies() - if temperature != None: + if temperature is not None: for material in model.geometry.get_all_materials().values(): material.temperature = temperature @@ -2460,7 +2460,7 @@ def _isothermal_materialwise_mgxs( model, groups, correction, directory) # Fetch all of the isothermal results. - if temperature != None: + if temperature is not None: return { mat.name : mgxs_lib.get_xsdata(domain=mat, xsdata_name=mat.name, temperature=temperature) @@ -2515,12 +2515,12 @@ def _generate_material_wise_mgxs( entries in openmc.Settings.temperature_settings. """ temp_settings = {} - if temperature_settings == None: + if temperature_settings is None: temp_settings = self.settings.temperature else: temp_settings = temperature_settings - if temperatures == None: + if temperatures is None: mgxs_sets = Model._isothermal_materialwise_mgxs( self, groups, diff --git a/tests/unit_tests/test_lib.py b/tests/unit_tests/test_lib.py index 51e648dcf93..6926bc11b18 100644 --- a/tests/unit_tests/test_lib.py +++ b/tests/unit_tests/test_lib.py @@ -251,9 +251,9 @@ def test_material(lib_init): m.name = "Not hot borated water" assert m.name == "Not hot borated water" - assert m.depletable == False + assert not m.depletable m.depletable = True - assert m.depletable == True + assert m.depletable def test_properties_density(lib_init):