From 0e125b254852e9115659913d793c1ec62f5f6a6f Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 27 Jun 2019 11:42:18 -0500 Subject: [PATCH 1/2] Option to pass fission q values to Chain, Operator, Model A dictionary of constant fission q values [eV] can be passed into the initialization of deplete.Chain, deplete.Operator, and model.Model objects. This can be used for direct comparisons with other codes with readily available constant Q-values. Tests have been added on the Chain and Operator side. The additional fiss_q_values passed into Model is forwarded directly on to the Operator call. --- openmc/deplete/abc.py | 7 +++++-- openmc/deplete/chain.py | 24 +++++++++++++++++------ openmc/deplete/nuclide.py | 7 ++++++- openmc/deplete/operator.py | 10 ++++++---- openmc/model/model.py | 10 ++++++++-- tests/unit_tests/test_deplete_chain.py | 12 ++++++++++++ tests/unit_tests/test_deplete_operator.py | 13 ++++++++++++ 7 files changed, 68 insertions(+), 15 deletions(-) diff --git a/openmc/deplete/abc.py b/openmc/deplete/abc.py index 2e598fb74a..bbfdd55f65 100644 --- a/openmc/deplete/abc.py +++ b/openmc/deplete/abc.py @@ -49,6 +49,9 @@ class TransportOperator(metaclass=ABCMeta): Path to the depletion chain XML file. Defaults to the file listed under ``depletion_chain`` in :envvar:`OPENMC_CROSS_SECTIONS` environment variable. + fiss_q_values : dict, optional + Dictionary of nuclides and their fission q values [eV]. If not given, + values will be pulled from the ``chain_file``. Attributes ---------- @@ -58,7 +61,7 @@ class TransportOperator(metaclass=ABCMeta): nuclides with reaction rates. Defaults to 1.0e3. """ - def __init__(self, chain_file=None): + def __init__(self, chain_file=None, fiss_q_values=None): self.dilute_initial = 1.0e3 self.output_dir = '.' @@ -81,7 +84,7 @@ class TransportOperator(metaclass=ABCMeta): warn("Use of OPENMC_DEPLETE_CHAIN is deprecated in favor " "of adding depletion_chain to OPENMC_CROSS_SECTIONS", FutureWarning) - self.chain = Chain.from_xml(chain_file) + self.chain = Chain.from_xml(chain_file, fiss_q_values) @abstractmethod def __call__(self, vec, print_out=True): diff --git a/openmc/deplete/chain.py b/openmc/deplete/chain.py index b8b6a3644a..e4a8dcfad0 100644 --- a/openmc/deplete/chain.py +++ b/openmc/deplete/chain.py @@ -4,16 +4,18 @@ This module contains information about a depletion chain. A depletion chain is loaded from an .xml file and all the nuclides are linked together. """ -from collections import OrderedDict, defaultdict from io import StringIO from itertools import chain import math import re -import os +from collections import OrderedDict, defaultdict +from collections.abc import Mapping + +from openmc.checkvalue import check_type # Try to use lxml if it is available. It preserves the order of attributes and -# provides a pretty-printer by default. If not available, use OpenMC function to -# pretty print. +# provides a pretty-printer by default. If not available, +# use OpenMC function to pretty print. try: import lxml.etree as ET _have_lxml = True @@ -312,22 +314,32 @@ class Chain(object): return chain @classmethod - def from_xml(cls, filename): + def from_xml(cls, filename, fiss_q_values=None): """Reads a depletion chain XML file. Parameters ---------- filename : str The path to the depletion chain XML file. + fiss_q_values : dict, optional + Dictionary of nuclides and their fission q values [eV]. + If not given, values will be pulled from ``filename`` """ chain = cls() + if fiss_q_values is not None: + check_type("fiss_q_values", fiss_q_values, Mapping) + else: + fiss_q_values = {} + # Load XML tree root = ET.parse(str(filename)) for i, nuclide_elem in enumerate(root.findall('nuclide')): - nuc = Nuclide.from_xml(nuclide_elem) + this_q = fiss_q_values.get(nuclide_elem.get("name"), None) + + nuc = Nuclide.from_xml(nuclide_elem, this_q) chain.nuclide_dict[nuc.name] = i # Check for reaction paths diff --git a/openmc/deplete/nuclide.py b/openmc/deplete/nuclide.py index 8a30214c2c..0afec3a0c5 100644 --- a/openmc/deplete/nuclide.py +++ b/openmc/deplete/nuclide.py @@ -112,13 +112,16 @@ class Nuclide(object): return len(self.reactions) @classmethod - def from_xml(cls, element): + def from_xml(cls, element, fiss_q=None): """Read nuclide from an XML element. Parameters ---------- element : xml.etree.ElementTree.Element XML element to write nuclide data to + fiss_q : None or float + User-supplied fission Q value [eV]. + Will be read from the element if not given Returns ------- @@ -153,6 +156,8 @@ class Nuclide(object): target = reaction_elem.get('target') else: target = None + if fiss_q is not None: + Q = fiss_q # Append reaction nuc.reactions.append(ReactionTuple( diff --git a/openmc/deplete/operator.py b/openmc/deplete/operator.py index d284d98567..0effb45e7f 100644 --- a/openmc/deplete/operator.py +++ b/openmc/deplete/operator.py @@ -73,6 +73,9 @@ class Operator(TransportOperator): in the previous results. diff_burnable_mats : bool, optional Whether to differentiate burnable materials with multiple instances + fiss_q_values : dict, optional + Dictionary of nuclides and their fission q values [eV]. If not given, + values will be pulled from the ``chain_file``. Attributes ---------- @@ -110,14 +113,14 @@ class Operator(TransportOperator): """ def __init__(self, geometry, settings, chain_file=None, prev_results=None, - diff_burnable_mats=False): - super().__init__(chain_file) + diff_burnable_mats=False, fiss_q_values=None): + super().__init__(chain_file, fiss_q_values) self.round_number = False self.settings = settings self.geometry = geometry self.diff_burnable_mats = diff_burnable_mats - if prev_results != None: + if prev_results is not None: # Reload volumes into geometry prev_results[-1].transfer_volumes(geometry) @@ -149,7 +152,6 @@ class Operator(TransportOperator): self.reaction_rates = ReactionRates( self.local_mats, self._burnable_nucs, self.chain.reactions) - def __call__(self, vec, power, print_out=True): """Runs a simulation. diff --git a/openmc/model/model.py b/openmc/model/model.py index f66bd8f16d..ae2ecbf0fc 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -124,7 +124,7 @@ class Model(object): self._plots.append(plot) def deplete(self, timesteps, chain_file=None, method='cecm', - **kwargs): + fiss_q_values=None, **kwargs): """Deplete model using specified timesteps/power Parameters @@ -138,6 +138,9 @@ class Model(object): :envvar:`OPENMC_CROSS_SECTIONS` environment variable if it exists. method : str Integration method used for depletion (e.g., 'cecm', 'predictor') + fiss_q_values : dict, optional + Dictionary of nuclides and their fission q values [eV]. + If not given, values will be pulled from the ``chain_file``. **kwargs Keyword arguments passed to integration function (e.g., :func:`openmc.deplete.integrator.cecm`) @@ -149,7 +152,10 @@ class Model(object): import openmc.deplete as dep # Create OpenMC transport operator - op = dep.Operator(self.geometry, self.settings, chain_file) + op = dep.Operator( + self.geometry, self.settings, chain_file, + fiss_q_values=fiss_q_values, + ) # Perform depletion check_value('method', method, ('cecm', 'predictor', 'cf4', 'epc_rk4', diff --git a/tests/unit_tests/test_deplete_chain.py b/tests/unit_tests/test_deplete_chain.py index 1fe83ad98a..dd6817a8e4 100644 --- a/tests/unit_tests/test_deplete_chain.py +++ b/tests/unit_tests/test_deplete_chain.py @@ -231,3 +231,15 @@ def test_getitem(): assert "NucA" == chain["NucA"] assert "NucB" == chain["NucB"] assert "NucC" == chain["NucC"] + + +def test_set_fiss_q(): + """Make sure new fission q values can be set on the chain""" + new_q = {"U235": 2.0E8, "U238": 2.0E8, "U234": 5.0E7} + chain_file = Path(__file__).parents[1] / "chain_simple.xml" + mod_chain = Chain.from_xml(chain_file, new_q) + for name, q in new_q.items(): + chain_nuc = mod_chain[name] + for rx in chain_nuc.reactions: + if rx.type == 'fission': + assert rx.Q == q diff --git a/tests/unit_tests/test_deplete_operator.py b/tests/unit_tests/test_deplete_operator.py index 757b51d923..758143af58 100644 --- a/tests/unit_tests/test_deplete_operator.py +++ b/tests/unit_tests/test_deplete_operator.py @@ -68,3 +68,16 @@ def test_operator_init(bare_xs): 'decay_modes', 'yield_data', 'yield_energies', ]: assert getattr(act_nuc, prop) == getattr(ref_nuc, prop), prop + + +def test_operator_fiss_q(): + """Make sure fission q values can be set""" + new_q = {"U235": 2.0E8, "U238": 2.0E8, "U234": 5.0E7} + chain_file = Path(__file__).parents[1] / "chain_simple.xml" + operator = BareDepleteOperator(chain_file=chain_file, fiss_q_values=new_q) + mod_chain = operator.chain + for name, q in new_q.items(): + chain_nuc = mod_chain[name] + for rx in chain_nuc.reactions: + if rx.type == 'fission': + assert rx.Q == q From 1e6f15236a33e221b5307f1511a0b6c6fd16c827 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 28 Jun 2019 10:21:57 -0500 Subject: [PATCH 2/2] fiss_q_values -> fission_q for passing q values --- openmc/deplete/abc.py | 8 ++++---- openmc/deplete/chain.py | 14 +++++++------- openmc/deplete/nuclide.py | 8 ++++---- openmc/deplete/operator.py | 8 ++++---- openmc/model/model.py | 8 ++++---- tests/unit_tests/test_deplete_operator.py | 2 +- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/openmc/deplete/abc.py b/openmc/deplete/abc.py index bbfdd55f65..1be3e27ff9 100644 --- a/openmc/deplete/abc.py +++ b/openmc/deplete/abc.py @@ -49,8 +49,8 @@ class TransportOperator(metaclass=ABCMeta): Path to the depletion chain XML file. Defaults to the file listed under ``depletion_chain`` in :envvar:`OPENMC_CROSS_SECTIONS` environment variable. - fiss_q_values : dict, optional - Dictionary of nuclides and their fission q values [eV]. If not given, + fission_q : dict, optional + Dictionary of nuclides and their fission Q values [eV]. If not given, values will be pulled from the ``chain_file``. Attributes @@ -61,7 +61,7 @@ class TransportOperator(metaclass=ABCMeta): nuclides with reaction rates. Defaults to 1.0e3. """ - def __init__(self, chain_file=None, fiss_q_values=None): + def __init__(self, chain_file=None, fission_q=None): self.dilute_initial = 1.0e3 self.output_dir = '.' @@ -84,7 +84,7 @@ class TransportOperator(metaclass=ABCMeta): warn("Use of OPENMC_DEPLETE_CHAIN is deprecated in favor " "of adding depletion_chain to OPENMC_CROSS_SECTIONS", FutureWarning) - self.chain = Chain.from_xml(chain_file, fiss_q_values) + self.chain = Chain.from_xml(chain_file, fission_q) @abstractmethod def __call__(self, vec, print_out=True): diff --git a/openmc/deplete/chain.py b/openmc/deplete/chain.py index e4a8dcfad0..643235d9f5 100644 --- a/openmc/deplete/chain.py +++ b/openmc/deplete/chain.py @@ -314,30 +314,30 @@ class Chain(object): return chain @classmethod - def from_xml(cls, filename, fiss_q_values=None): + def from_xml(cls, filename, fission_q=None): """Reads a depletion chain XML file. Parameters ---------- filename : str The path to the depletion chain XML file. - fiss_q_values : dict, optional - Dictionary of nuclides and their fission q values [eV]. + fission_q : dict, optional + Dictionary of nuclides and their fission Q values [eV]. If not given, values will be pulled from ``filename`` """ chain = cls() - if fiss_q_values is not None: - check_type("fiss_q_values", fiss_q_values, Mapping) + if fission_q is not None: + check_type("fission_q", fission_q, Mapping) else: - fiss_q_values = {} + fission_q = {} # Load XML tree root = ET.parse(str(filename)) for i, nuclide_elem in enumerate(root.findall('nuclide')): - this_q = fiss_q_values.get(nuclide_elem.get("name"), None) + this_q = fission_q.get(nuclide_elem.get("name")) nuc = Nuclide.from_xml(nuclide_elem, this_q) chain.nuclide_dict[nuc.name] = i diff --git a/openmc/deplete/nuclide.py b/openmc/deplete/nuclide.py index 0afec3a0c5..88d5ac6eae 100644 --- a/openmc/deplete/nuclide.py +++ b/openmc/deplete/nuclide.py @@ -112,14 +112,14 @@ class Nuclide(object): return len(self.reactions) @classmethod - def from_xml(cls, element, fiss_q=None): + def from_xml(cls, element, fission_q=None): """Read nuclide from an XML element. Parameters ---------- element : xml.etree.ElementTree.Element XML element to write nuclide data to - fiss_q : None or float + fission_q : None or float User-supplied fission Q value [eV]. Will be read from the element if not given @@ -156,8 +156,8 @@ class Nuclide(object): target = reaction_elem.get('target') else: target = None - if fiss_q is not None: - Q = fiss_q + if fission_q is not None: + Q = fission_q # Append reaction nuc.reactions.append(ReactionTuple( diff --git a/openmc/deplete/operator.py b/openmc/deplete/operator.py index 0effb45e7f..ffbffbc734 100644 --- a/openmc/deplete/operator.py +++ b/openmc/deplete/operator.py @@ -73,8 +73,8 @@ class Operator(TransportOperator): in the previous results. diff_burnable_mats : bool, optional Whether to differentiate burnable materials with multiple instances - fiss_q_values : dict, optional - Dictionary of nuclides and their fission q values [eV]. If not given, + fission_q : dict, optional + Dictionary of nuclides and their fission Q values [eV]. If not given, values will be pulled from the ``chain_file``. Attributes @@ -113,8 +113,8 @@ class Operator(TransportOperator): """ def __init__(self, geometry, settings, chain_file=None, prev_results=None, - diff_burnable_mats=False, fiss_q_values=None): - super().__init__(chain_file, fiss_q_values) + diff_burnable_mats=False, fission_q=None): + super().__init__(chain_file, fission_q) self.round_number = False self.settings = settings self.geometry = geometry diff --git a/openmc/model/model.py b/openmc/model/model.py index ae2ecbf0fc..2f515ca78f 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -124,7 +124,7 @@ class Model(object): self._plots.append(plot) def deplete(self, timesteps, chain_file=None, method='cecm', - fiss_q_values=None, **kwargs): + fission_q=None, **kwargs): """Deplete model using specified timesteps/power Parameters @@ -138,8 +138,8 @@ class Model(object): :envvar:`OPENMC_CROSS_SECTIONS` environment variable if it exists. method : str Integration method used for depletion (e.g., 'cecm', 'predictor') - fiss_q_values : dict, optional - Dictionary of nuclides and their fission q values [eV]. + fission_q : dict, optional + Dictionary of nuclides and their fission Q values [eV]. If not given, values will be pulled from the ``chain_file``. **kwargs Keyword arguments passed to integration function (e.g., @@ -154,7 +154,7 @@ class Model(object): # Create OpenMC transport operator op = dep.Operator( self.geometry, self.settings, chain_file, - fiss_q_values=fiss_q_values, + fission_q=fission_q, ) # Perform depletion diff --git a/tests/unit_tests/test_deplete_operator.py b/tests/unit_tests/test_deplete_operator.py index 758143af58..45c2aada4e 100644 --- a/tests/unit_tests/test_deplete_operator.py +++ b/tests/unit_tests/test_deplete_operator.py @@ -74,7 +74,7 @@ def test_operator_fiss_q(): """Make sure fission q values can be set""" new_q = {"U235": 2.0E8, "U238": 2.0E8, "U234": 5.0E7} chain_file = Path(__file__).parents[1] / "chain_simple.xml" - operator = BareDepleteOperator(chain_file=chain_file, fiss_q_values=new_q) + operator = BareDepleteOperator(chain_file=chain_file, fission_q=new_q) mod_chain = operator.chain for name, q in new_q.items(): chain_nuc = mod_chain[name]