diff --git a/examples/python/basic/build-xml.py b/examples/python/basic/build-xml.py index 97591c992..eb8fbd23f 100644 --- a/examples/python/basic/build-xml.py +++ b/examples/python/basic/build-xml.py @@ -109,29 +109,20 @@ energyout_filter = openmc.Filter(type='energyout', bins=[0., 20.]) # Instantiate the first Tally first_tally = openmc.Tally(tally_id=1, name='first tally') -first_tally.add_filter(cell_filter) -scores = ['total', 'scatter', 'nu-scatter', \ +first_tally.filters = [cell_filter] +scores = ['total', 'scatter', 'nu-scatter', 'absorption', 'fission', 'nu-fission'] -for score in scores: - first_tally.add_score(score) +first_tally.scores = scores # Instantiate the second Tally second_tally = openmc.Tally(tally_id=2, name='second tally') -second_tally.add_filter(cell_filter) -second_tally.add_filter(energy_filter) -scores = ['total', 'scatter', 'nu-scatter', \ - 'absorption', 'fission', 'nu-fission'] -for score in scores: - second_tally.add_score(score) +second_tally.filters = [cell_filter, energy_filter] +second_tally.scores = scores # Instantiate the third Tally third_tally = openmc.Tally(tally_id=3, name='third tally') -third_tally.add_filter(cell_filter) -third_tally.add_filter(energy_filter) -third_tally.add_filter(energyout_filter) -scores = ['scatter', 'nu-scatter', 'nu-fission'] -for score in scores: - third_tally.add_score(score) +third_tally.filters = [cell_filter, energy_filter, energyout_filter] +third_tally.scores = ['scatter', 'nu-scatter', 'nu-fission'] # Instantiate a TalliesFile, register all Tallies, and export to XML tallies_file = openmc.TalliesFile() diff --git a/examples/python/lattice/hexagonal/build-xml.py b/examples/python/lattice/hexagonal/build-xml.py index 1125e8ce0..d1144cd91 100644 --- a/examples/python/lattice/hexagonal/build-xml.py +++ b/examples/python/lattice/hexagonal/build-xml.py @@ -166,8 +166,8 @@ plot_file.export_to_xml() # Instantiate a distribcell Tally tally = openmc.Tally(tally_id=1) -tally.add_filter(openmc.Filter(type='distribcell', bins=[cell2.id])) -tally.add_score('total') +tally.filters = [openmc.Filter(type='distribcell', bins=[cell2.id])] +tally.scores = ['total'] # Instantiate a TalliesFile, register Tally/Mesh, and export to XML tallies_file = openmc.TalliesFile() diff --git a/examples/python/lattice/nested/build-xml.py b/examples/python/lattice/nested/build-xml.py index 389af8e9b..e4ac84839 100644 --- a/examples/python/lattice/nested/build-xml.py +++ b/examples/python/lattice/nested/build-xml.py @@ -175,8 +175,8 @@ mesh_filter.mesh = mesh # Instantiate the Tally tally = openmc.Tally(tally_id=1) -tally.add_filter(mesh_filter) -tally.add_score('total') +tally.filters = [mesh_filter] +tally.scores = ['total'] # Instantiate a TalliesFile, register Tally/Mesh, and export to XML tallies_file = openmc.TalliesFile() diff --git a/examples/python/lattice/simple/build-xml.py b/examples/python/lattice/simple/build-xml.py index e648c3d5b..78ee61eb4 100644 --- a/examples/python/lattice/simple/build-xml.py +++ b/examples/python/lattice/simple/build-xml.py @@ -167,13 +167,13 @@ mesh_filter.mesh = mesh # Instantiate tally Trigger trigger = openmc.Trigger(trigger_type='rel_err', threshold=1E-2) -trigger.add_score('all') +trigger.scores = ['all'] # Instantiate the Tally tally = openmc.Tally(tally_id=1) -tally.add_filter(mesh_filter) -tally.add_score('total') -tally.add_trigger(trigger) +tally.filters = [mesh_filter] +tally.scores = ['total'] +tally.triggers = [trigger] # Instantiate a TalliesFile, register Tally/Mesh, and export to XML tallies_file = openmc.TalliesFile() diff --git a/examples/python/pincell/build-xml.py b/examples/python/pincell/build-xml.py index ca71b04e5..aa8714838 100644 --- a/examples/python/pincell/build-xml.py +++ b/examples/python/pincell/build-xml.py @@ -196,11 +196,8 @@ mesh_filter.mesh = mesh # Instantiate the Tally tally = openmc.Tally(tally_id=1, name='tally 1') -tally.add_filter(energy_filter) -tally.add_filter(mesh_filter) -tally.add_score('flux') -tally.add_score('fission') -tally.add_score('nu-fission') +tally.filters = [energy_filter, mesh_filter] +tally.scores = ['flux', 'fission', 'nu-fission'] # Instantiate a TalliesFile, register all Tallies, and export to XML tallies_file = openmc.TalliesFile() diff --git a/openmc/checkvalue.py b/openmc/checkvalue.py index 787052f5d..0e9dc9ef4 100644 --- a/openmc/checkvalue.py +++ b/openmc/checkvalue.py @@ -41,9 +41,9 @@ def check_type(name, value, expected_type, expected_iter_type=None): Description of value being checked value : object Object to check type of - expected_type : type + expected_type : type or Iterable of type type to check object against - expected_iter_type : type or None, optional + expected_iter_type : type or Iterable of type or None, optional Expected type of each element in value, assuming it is iterable. If None, no check will be performed. @@ -57,9 +57,15 @@ def check_type(name, value, expected_type, expected_iter_type=None): if expected_iter_type: for item in value: if not _isinstance(item, expected_iter_type): - msg = 'Unable to set "{0}" to "{1}" since each item must be ' \ - 'of type "{2}"'.format(name, value, - expected_iter_type.__name__) + if isinstance(expected_iter_type, Iterable): + msg = 'Unable to set "{0}" to "{1}" since each item must be ' \ + 'one of the following types: "{2}"'.format( + name, value, ', '.join([t.__name__ for t in + expected_iter_type])) + else: + msg = 'Unable to set "{0}" to "{1}" since each item must be ' \ + 'of type "{2}"'.format(name, value, + expected_iter_type.__name__) raise ValueError(msg) diff --git a/openmc/mgxs/mgxs.py b/openmc/mgxs/mgxs.py index 875a82c46..ad987d70f 100644 --- a/openmc/mgxs/mgxs.py +++ b/openmc/mgxs/mgxs.py @@ -510,27 +510,27 @@ class MGXS(object): # Create each Tally needed to compute the multi group cross section for score, key, filters in zip(scores, keys, all_filters): self.tallies[key] = openmc.Tally(name=self.name) - self.tallies[key].add_score(score) + self.tallies[key].scores.append(score) self.tallies[key].estimator = estimator - self.tallies[key].add_filter(domain_filter) + self.tallies[key].filters.append(domain_filter) # If a tally trigger was specified, add it to each tally if self.tally_trigger: trigger_clone = copy.deepcopy(self.tally_trigger) - trigger_clone.add_score(score) - self.tallies[key].add_trigger(trigger_clone) + trigger_clone.scores.append(score) + self.tallies[key].triggers.append(trigger_clone) # Add all non-domain specific Filters (e.g., 'energy') to the Tally for add_filter in filters: - self.tallies[key].add_filter(add_filter) + self.tallies[key].filters.append(add_filter) # If this is a by-nuclide cross-section, add all nuclides to Tally if self.by_nuclide and score != 'flux': all_nuclides = self.domain.get_all_nuclides() for nuclide in all_nuclides: - self.tallies[key].add_nuclide(nuclide) + self.tallies[key].nuclides.append(nuclide) else: - self.tallies[key].add_nuclide('total') + self.tallies[key].nuclides.append('total') def _compute_xs(self): """Performs generic cleanup after a subclass' uses tally arithmetic to @@ -552,7 +552,7 @@ class MGXS(object): self.xs_tally._nuclides = [] nuclides = self.domain.get_all_nuclides() for nuclide in nuclides: - self.xs_tally.add_nuclide(openmc.Nuclide(nuclide)) + self.xs_tally.nuclides.append(openmc.Nuclide(nuclide)) # Remove NaNs which may have resulted from divide-by-zero operations self.xs_tally._mean = np.nan_to_num(self.xs_tally.mean) @@ -2087,7 +2087,7 @@ class Chi(MGXS): super(Chi, self)._compute_xs() # Add the coarse energy filter back to the nu-fission tally - nu_fission_in.add_filter(energy_filter) + nu_fission_in.filters.append(energy_filter) return self._xs_tally @@ -2179,7 +2179,7 @@ class Chi(MGXS): xs_tally = nu_fission_out / nu_fission_in # Add the coarse energy filter back to the nu-fission tally - nu_fission_in.add_filter(energy_filter) + nu_fission_in.filters.append(energy_filter) xs = xs_tally.get_values(filters=filters, filter_bins=filter_bins, value=value) diff --git a/openmc/statepoint.py b/openmc/statepoint.py index f5b5b2e72..05a389611 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -389,7 +389,7 @@ class StatePoint(object): new_filter.mesh = self.meshes[key] # Add Filter to the Tally - tally.add_filter(new_filter) + tally.filters.append(new_filter) # Read Nuclide bins nuclide_names = \ @@ -398,7 +398,7 @@ class StatePoint(object): # Add all Nuclides to the Tally for name in nuclide_names: nuclide = openmc.Nuclide(name.decode().strip()) - tally.add_nuclide(nuclide) + tally.nuclides.append(nuclide) scores = self._f['{0}{1}/score_bins'.format( base, tally_key)].value @@ -425,7 +425,7 @@ class StatePoint(object): pattern = r'-n$|-pn$|-yn$' score = re.sub(pattern, '-' + moments[j].decode(), score) - tally.add_score(score) + tally.scores.append(score) # Add Tally to the global dictionary of all Tallies tally.sparse = self.sparse diff --git a/openmc/summary.py b/openmc/summary.py index d22e367c9..a4d1d694c 100644 --- a/openmc/summary.py +++ b/openmc/summary.py @@ -276,7 +276,7 @@ class Summary(object): # Get the distribcell index ind = self._f['geometry/cells'][key]['distribcell_index'].value if ind != 0: - cell.distribcell_index = ind + cell.distribcell_index = ind # Add the Cell to the global dictionary of all Cells self.cells[index] = cell @@ -539,7 +539,7 @@ class Summary(object): # If this is a moment, use generic moment order pattern = r'-n$|-pn$|-yn$' score = re.sub(pattern, '-' + moments[j].decode(), score) - tally.add_score(score) + tally.scores.append(score) # Read filter metadata num_filters = self._f['{0}/n_filters'.format(subbase)].value @@ -560,7 +560,7 @@ class Summary(object): new_filter.num_bins = num_bins # Add Filter to the Tally - tally.add_filter(new_filter) + tally.filters.append(new_filter) # Add Tally to the global dictionary of all Tallies self.tallies[tally_id] = tally diff --git a/openmc/tallies.py b/openmc/tallies.py index d1666694f..f471dbdf3 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -7,8 +7,9 @@ import os import pickle import itertools from numbers import Integral, Real -from xml.etree import ElementTree as ET import sys +import warnings +from xml.etree import ElementTree as ET import numpy as np @@ -18,10 +19,13 @@ from openmc.filter import _FILTER_TYPES import openmc.checkvalue as cv from openmc.clean_xml import * - if sys.version_info[0] >= 3: basestring = str + +# DeprecationWarning filter for the Tally.add_*(...) methods +warnings.simplefilter('always', DeprecationWarning) + # "Static" variable for auto-generated Tally IDs AUTO_TALLY_ID = 10000 @@ -75,7 +79,7 @@ class Tally(object): num_bins : Integral Total number of bins for the tally shape : 3-tuple of Integral - The shape of the tally data array ordered as the number of filter bins, + The shape of the tally data array ordered as the number of filter bins, nuclide bins and score bins num_realizations : Integral Total number of realizations @@ -145,19 +149,19 @@ class Tally(object): clone._filters = [] for self_filter in self.filters: - clone.add_filter(copy.deepcopy(self_filter, memo)) + clone.filters.append(copy.deepcopy(self_filter, memo)) clone._nuclides = [] for nuclide in self.nuclides: - clone.add_nuclide(copy.deepcopy(nuclide, memo)) + clone.nuclides.append(copy.deepcopy(nuclide, memo)) clone._scores = [] for score in self.scores: - clone.add_score(score) + clone.scores.append(score) clone._triggers = [] for trigger in self.triggers: - clone.add_trigger(trigger) + clone.triggers.append(trigger) memo[id(self)] = clone @@ -423,6 +427,11 @@ class Tally(object): ['analog', 'tracklength', 'collision']) self._estimator = estimator + @triggers.setter + def triggers(self, triggers): + cv.check_type('tally triggers', trigger, Iterable, Trigger) + self._triggers = triggers + def add_trigger(self, trigger): """Add a tally trigger to the tally @@ -433,13 +442,11 @@ class Tally(object): """ - if not isinstance(trigger, Trigger): - msg = 'Unable to add a tally trigger for Tally ID="{0}" to ' \ - 'since "{1}" is not a Trigger'.format(self.id, trigger) - raise ValueError(msg) - - if trigger not in self.triggers: - self.triggers.append(trigger) + warnings.warn("Tally.add_trigger(...) has been deprecated and may be " + "removed in a future version. Tally triggers should be " + "defined using the triggers property directly.", + DeprecationWarning) + self.triggers.append(trigger) @id.setter def id(self, tally_id): @@ -460,6 +467,55 @@ class Tally(object): else: self._name = '' + @filters.setter + def filters(self, filters): + cv.check_type('tally filters', filters, Iterable, + (Filter, CrossFilter, AggregateFilter)) + + # If the filter is already in the Tally, raise an error + for i, f in enumerate(filters[:-1]): + if f in filters[i+1:]: + msg = 'Unable to add a duplicate filter "{0}" to Tally ID="{1}" ' \ + 'since duplicate filters are not supported in the OpenMC ' \ + 'Python API'.format(f, self.id) + raise ValueError(msg) + + self._filters = filters + + @nuclides.setter + def nuclides(self, nuclides): + cv.check_type('tally nuclides', nuclides, Iterable, + (basestring, Nuclide, CrossNuclide, AggregateNuclide)) + + # If the nuclide is already in the Tally, raise an error + for i, nuclide in enumerate(nuclides[:-1]): + if nuclide in nuclides[i+1:]: + msg = 'Unable to add a duplicate nuclide "{0}" to Tally ID="{1}" ' \ + 'since duplicate nuclides are not supported in the OpenMC ' \ + 'Python API'.format(nuclide, self.id) + raise ValueError(msg) + + self._nuclides = nuclides + + @scores.setter + def scores(self, scores): + cv.check_type('tally scores', scores, Iterable, + (basestring, CrossScore, AggregateScore)) + + for i, score in enumerate(scores[:-1]): + # If the score is already in the Tally, raise an error + if score in scores[i+1:]: + msg = 'Unable to add a duplicate score "{0}" to Tally ID="{1}" ' \ + 'since duplicate scores are not supported in the OpenMC ' \ + 'Python API'.format(score, self.id) + raise ValueError(msg) + + # If score is a string, strip whitespace + if isinstance(score, basestring): + scores[i] = score.strip() + + self._scores = scores + def add_filter(self, new_filter): """Add a filter to the tally @@ -475,19 +531,11 @@ class Tally(object): """ - if not isinstance(new_filter, (Filter, CrossFilter, AggregateFilter)): - msg = 'Unable to add Filter "{0}" to Tally ID="{1}" since it is ' \ - 'not a Filter object'.format(new_filter, self.id) - raise ValueError(msg) - - # If the filter is already in the Tally, raise an error - if new_filter in self.filters: - msg = 'Unable to add a duplicate filter "{0}" to Tally ID="{1}" ' \ - 'since duplicate filters are not supported in the OpenMC ' \ - 'Python API'.format(new_filter, self.id) - raise ValueError(msg) - - self._filters.append(new_filter) + warnings.warn("Tally.add_filter(...) has been deprecated and may be " + "removed in a future version. Tally filters should be " + "defined using the filters property directly.", + DeprecationWarning) + self.filters.append(new_filter) def add_nuclide(self, nuclide): """Specify that scores for a particular nuclide should be accumulated @@ -504,20 +552,11 @@ class Tally(object): """ - if not isinstance(nuclide, (basestring, Nuclide, - CrossNuclide, AggregateNuclide)): - msg = 'Unable to add nuclide "{0}" to Tally ID="{1}" since it is ' \ - 'not a Nuclide object'.format(nuclide) - raise ValueError(msg) - - # If the nuclide is already in the Tally, raise an error - if nuclide in self.nuclides: - msg = 'Unable to add a duplicate nuclide "{0}" to Tally ID="{1}" ' \ - 'since duplicate nuclides are not supported in the OpenMC ' \ - 'Python API'.format(nuclide, self.id) - raise ValueError(msg) - - self._nuclides.append(nuclide) + warnings.warn("Tally.add_nuclide(...) has been deprecated and may be " + "removed in a future version. Tally nuclides should be " + "defined using the nuclides property directly.", + DeprecationWarning) + self.nuclides.append(nuclide) def add_score(self, score): """Specify a quantity to be scored @@ -533,24 +572,11 @@ class Tally(object): """ - if not isinstance(score, (basestring, CrossScore, AggregateScore)): - msg = 'Unable to add score "{0}" to Tally ID="{1}" since it is ' \ - 'not a string'.format(score, self.id) - raise ValueError(msg) - - # If the score is already in the Tally, raise an error - if score in self.scores: - msg = 'Unable to add a duplicate score "{0}" to Tally ID="{1}" ' \ - 'since duplicate scores are not supported in the OpenMC ' \ - 'Python API'.format(score, self.id) - raise ValueError(msg) - - # Normal score strings - if isinstance(score, basestring): - self._scores.append(score.strip()) - # CrossScores and AggrgateScore - else: - self._scores.append(score) + warnings.warn("Tally.add_score(...) has been deprecated and may be " + "removed in a future version. Tally scores should be " + "defined using the scores property directly.", + DeprecationWarning) + self.scores.append(score) @num_realizations.setter def num_realizations(self, num_realizations): @@ -771,11 +797,11 @@ class Tally(object): # Add unique scores from second tally to merged tally for score in tally.scores: if score not in merged_tally.scores: - merged_tally.add_score(score) + merged_tally.scores.append(score) # Add triggers from second tally to merged tally for trigger in tally.triggers: - merged_tally.add_trigger(trigger) + merged_tally.triggers.append(trigger) return merged_tally @@ -1723,33 +1749,33 @@ class Tally(object): # Add filters to the new tally if filter_product == 'entrywise': for self_filter in self_copy.filters: - new_tally.add_filter(self_filter) + new_tally.filters.append(self_filter) else: all_filters = [self_copy.filters, other_copy.filters] for self_filter, other_filter in itertools.product(*all_filters): new_filter = CrossFilter(self_filter, other_filter, binary_op) - new_tally.add_filter(new_filter) + new_tally.filters.append(new_filter) # Add nuclides to the new tally if nuclide_product == 'entrywise': for self_nuclide in self_copy.nuclides: - new_tally.add_nuclide(self_nuclide) + new_tally.nuclides.append(self_nuclide) else: all_nuclides = [self_copy.nuclides, other_copy.nuclides] for self_nuclide, other_nuclide in itertools.product(*all_nuclides): new_nuclide = \ CrossNuclide(self_nuclide, other_nuclide, binary_op) - new_tally.add_nuclide(new_nuclide) + new_tally.nuclides.append(new_nuclide) # Add scores to the new tally if score_product == 'entrywise': for self_score in self_copy.scores: - new_tally.add_score(self_score) + new_tally.scores.append(self_score) else: all_scores = [self_copy.scores, other_copy.scores] for self_score, other_score in itertools.product(*all_scores): new_score = CrossScore(self_score, other_score, binary_op) - new_tally.add_score(new_score) + new_tally.scores.append(new_score) # Update the new tally's filter strides new_tally._update_filter_strides() @@ -1812,14 +1838,14 @@ class Tally(object): filter_copy = copy.deepcopy(other_filter) other._mean = np.repeat(other.mean, filter_copy.num_bins, axis=0) other._std_dev = np.repeat(other.std_dev, filter_copy.num_bins, axis=0) - other.add_filter(filter_copy) + other.filters.append(filter_copy) # Add filters present in other but not in self to self for self_filter in self_missing_filters: filter_copy = copy.deepcopy(self_filter) self._mean = np.repeat(self.mean, filter_copy.num_bins, axis=0) self._std_dev = np.repeat(self.std_dev, filter_copy.num_bins, axis=0) - self.add_filter(filter_copy) + self.filters.append(filter_copy) # Align other filters with self filters for i, self_filter in enumerate(self.filters): @@ -1842,7 +1868,7 @@ class Tally(object): np.tile(other.std_dev, (1, self.num_nuclides, 1)) # Add nuclides to each tally such that each tally contains the complete - # set of nuclides necessary to perform an entrywise product. New + # set of nuclides necessary to perform an entrywise product. New # nuclides added to a tally will have all their scores set to zero. else: @@ -1858,7 +1884,7 @@ class Tally(object): np.insert(other.mean, other.num_nuclides, 0, axis=1) other._std_dev = \ np.insert(other.std_dev, other.num_nuclides, 0, axis=1) - other.add_nuclide(nuclide) + other.nuclides.append(nuclide) # Add nuclides present in other but not in self to self for nuclide in self_missing_nuclides: @@ -1866,7 +1892,7 @@ class Tally(object): np.insert(self.mean, self.num_nuclides, 0, axis=1) self._std_dev = \ np.insert(self.std_dev, self.num_nuclides, 0, axis=1) - self.add_nuclide(nuclide) + self.nuclides.append(nuclide) # Align other nuclides with self nuclides for i, nuclide in enumerate(self.nuclides): @@ -1899,13 +1925,13 @@ class Tally(object): for score in other_missing_scores: other._mean = np.insert(other.mean, other.num_scores, 0, axis=2) other._std_dev = np.insert(other.std_dev, other.num_scores, 0, axis=2) - other.add_score(score) + other.scores.append(score) # Add scores present in other but not in self to self for score in self_missing_scores: self._mean = np.insert(self.mean, self.num_scores, 0, axis=2) self._std_dev = np.insert(self.std_dev, self.num_scores, 0, axis=2) - self.add_score(score) + self.scores.append(score) # Align other scores with self scores for i, score in enumerate(self.scores): @@ -2210,12 +2236,9 @@ class Tally(object): new_tally.with_summary = self.with_summary new_tally.num_realization = self.num_realizations - for self_filter in self.filters: - new_tally.add_filter(self_filter) - for nuclide in self.nuclides: - new_tally.add_nuclide(nuclide) - for score in self.scores: - new_tally.add_score(score) + new_tally.filters = self.filters + new_tally.nuclides = self.nuclides + new_tally.scores = self.scores # If this tally operand is sparse, sparsify the new tally new_tally.sparse = self.sparse @@ -2284,12 +2307,9 @@ class Tally(object): new_tally.with_summary = self.with_summary new_tally.num_realization = self.num_realizations - for self_filter in self.filters: - new_tally.add_filter(self_filter) - for nuclide in self.nuclides: - new_tally.add_nuclide(nuclide) - for score in self.scores: - new_tally.add_score(score) + new_tally.filters = self.filters + new_tally.nuclides = self.nuclides + new_tally.scores = self.scores # If this tally operand is sparse, sparsify the new tally new_tally.sparse = self.sparse @@ -2359,12 +2379,9 @@ class Tally(object): new_tally.with_summary = self.with_summary new_tally.num_realization = self.num_realizations - for self_filter in self.filters: - new_tally.add_filter(self_filter) - for nuclide in self.nuclides: - new_tally.add_nuclide(nuclide) - for score in self.scores: - new_tally.add_score(score) + new_tally.filters = self.filters + new_tally.nuclides = self.nuclides + new_tally.scores = self.scores # If this tally operand is sparse, sparsify the new tally new_tally.sparse = self.sparse @@ -2434,12 +2451,9 @@ class Tally(object): new_tally.with_summary = self.with_summary new_tally.num_realization = self.num_realizations - for self_filter in self.filters: - new_tally.add_filter(self_filter) - for nuclide in self.nuclides: - new_tally.add_nuclide(nuclide) - for score in self.scores: - new_tally.add_score(score) + new_tally.filters = self.filters + new_tally.nuclides = self.nuclides + new_tally.scores = self.scores # If this tally operand is sparse, sparsify the new tally new_tally.sparse = self.sparse @@ -2513,12 +2527,9 @@ class Tally(object): new_tally.with_summary = self.with_summary new_tally.num_realization = self.num_realizations - for self_filter in self.filters: - new_tally.add_filter(self_filter) - for nuclide in self.nuclides: - new_tally.add_nuclide(nuclide) - for score in self.scores: - new_tally.add_score(score) + new_tally.filters = self.filters + new_tally.nuclides = self.nuclides + new_tally.scores = self.scores # If original tally was sparse, sparsify the exponentiated tally new_tally.sparse = self.sparse @@ -2853,11 +2864,11 @@ class Tally(object): if not remove_filter: filter_sum = \ AggregateFilter(self_filter, filter_bins, 'sum') - tally_sum.add_filter(filter_sum) + tally_sum.filters.append(filter_sum) # Add a copy of each filter not summed across to the tally sum else: - tally_sum.add_filter(copy.deepcopy(self_filter)) + tally_sum.filters.append(copy.deepcopy(self_filter)) # Add a copy of this tally's filters to the tally sum else: @@ -2875,7 +2886,7 @@ class Tally(object): # Add AggregateNuclide to the tally sum nuclide_sum = AggregateNuclide(nuclides, 'sum') - tally_sum.add_nuclide(nuclide_sum) + tally_sum.nuclides.append(nuclide_sum) # Add a copy of this tally's nuclides to the tally sum else: @@ -2893,7 +2904,7 @@ class Tally(object): # Add AggregateScore to the tally sum score_sum = AggregateScore(scores, 'sum') - tally_sum.add_score(score_sum) + tally_sum.scores.append(score_sum) # Add a copy of this tally's scores to the tally sum else: @@ -2946,7 +2957,7 @@ class Tally(object): # Add the new filter to a copy of this Tally new_tally = copy.deepcopy(self) - new_tally.add_filter(new_filter) + new_tally.filters.append(new_filter) # Determine "base" indices along the new "diagonal", and the factor # by which the "base" indices should be repeated to account for all diff --git a/openmc/trigger.py b/openmc/trigger.py index bcac8c31c..f03703328 100644 --- a/openmc/trigger.py +++ b/openmc/trigger.py @@ -1,6 +1,7 @@ from numbers import Real from xml.etree import ElementTree as ET import sys +import warnings from openmc.checkvalue import check_type, check_value @@ -8,6 +9,10 @@ if sys.version_info[0] >= 3: basestring = str +# DeprecationWarning filter for the Trigger.add_score(...) method +warnings.simplefilter('always', DeprecationWarning) + + class Trigger(object): """A criterion for when to finish a simulation based on tally uncertainties. @@ -46,9 +51,7 @@ class Trigger(object): clone._trigger_type = self._trigger_type clone._threshold = self._threshold - clone._scores = [] - for score in self._scores: - clone.add_score(score) + clone.scores = self.scores memo[id(self)] = clone @@ -97,6 +100,17 @@ class Trigger(object): check_type('tally trigger threshold', threshold, Real) self._threshold = threshold + @scores.setter + def scores(self, scores): + cv.check_type('trigger scores', scores, Iterable, basestring) + + # Set scores making sure not to have duplicates + self._scores = [] + for score in scores: + if score not in self._scores: + self._scores.append(score) + + def add_score(self, score): """Add a score to the list of scores to be checked against the trigger. @@ -107,16 +121,11 @@ class Trigger(object): """ - if not isinstance(score, basestring): - msg = 'Unable to add score "{0}" to tally trigger since ' \ - 'it is not a string'.format(score) - raise ValueError(msg) - - # If the score is already in the Tally, don't add it again - if score in self._scores: - return - else: - self._scores.append(score) + warnings.warn("Trigger.add_score(...) has been deprecated and may be " + "removed in a future version. Tally trigger scores should " + "be defined using the scores property directly.", + DeprecationWarning) + self.scores.append(score) def get_trigger_xml(self, element): """Return XML representation of the trigger diff --git a/tests/test_tallies/test_tallies.py b/tests/test_tallies/test_tallies.py index 9fca93bca..81e8641de 100644 --- a/tests/test_tallies/test_tallies.py +++ b/tests/test_tallies/test_tallies.py @@ -23,19 +23,19 @@ class TalliesTestHarness(PyAPITestHarness): azimuthal_bins = (-3.1416, -1.8850, -0.6283, 0.6283, 1.8850, 3.1416) azimuthal_filter1 = Filter(type='azimuthal', bins=azimuthal_bins) azimuthal_tally1 = Tally() - azimuthal_tally1.add_filter(azimuthal_filter1) - azimuthal_tally1.add_score('flux') + azimuthal_tally1.filters = [azimuthal_filter1] + azimuthal_tally1.scores = ['flux'] azimuthal_tally1.estimator = 'tracklength' azimuthal_tally2 = Tally() - azimuthal_tally2.add_filter(azimuthal_filter1) - azimuthal_tally2.add_score('flux') + azimuthal_tally2.filters = [azimuthal_filter1] + azimuthal_tally2.scores = ['flux'] azimuthal_tally2.estimator = 'analog' azimuthal_filter2 = Filter(type='azimuthal', bins=(5,)) azimuthal_tally3 = Tally() - azimuthal_tally3.add_filter(azimuthal_filter2) - azimuthal_tally3.add_score('flux') + azimuthal_tally3.filters = [azimuthal_filter2] + azimuthal_tally3.scores = ['flux'] azimuthal_tally3.estimator = 'tracklength' mesh_2x2 = Mesh(mesh_id=1) @@ -44,154 +44,129 @@ class TalliesTestHarness(PyAPITestHarness): mesh_2x2.dimension = [2, 2] mesh_filter = Filter(type='mesh', bins=(1,)) azimuthal_tally4 = Tally() - azimuthal_tally4.add_filter(azimuthal_filter2) - azimuthal_tally4.add_filter(mesh_filter) - azimuthal_tally4.add_score('flux') + azimuthal_tally4.filters = [azimuthal_filter2, mesh_filter] + azimuthal_tally4.scores = ['flux'] azimuthal_tally4.estimator = 'tracklength' cellborn_tally = Tally() - cellborn_tally.add_filter(Filter(type='cellborn', bins=(10, 21, 22, 23))) - cellborn_tally.add_score('total') + cellborn_tally.filters = [Filter(type='cellborn', bins=(10, 21, 22, 23))] + cellborn_tally.scores = ['total'] dg_tally = Tally() - dg_tally.add_filter(Filter(type='delayedgroup', bins=(1, 2, 3, 4, 5, 6))) - dg_tally.add_score('delayed-nu-fission') + dg_tally.filters = [Filter(type='delayedgroup', bins=(1, 2, 3, 4, 5, 6))] + dg_tally.scores = ['delayed-nu-fission'] four_groups = (0.0, 0.253e-6, 1.0e-3, 1.0, 20.0) energy_filter = Filter(type='energy', bins=four_groups) energy_tally = Tally() - energy_tally.add_filter(energy_filter) - energy_tally.add_score('total') + energy_tally.filters = [energy_filter] + energy_tally.scores = ['total'] energyout_filter = Filter(type='energyout', bins=four_groups) energyout_tally = Tally() - energyout_tally.add_filter(energyout_filter) - energyout_tally.add_score('scatter') + energyout_tally.filters = [energyout_filter] + energyout_tally.scores = ['scatter'] transfer_tally = Tally() - transfer_tally.add_filter(energy_filter) - transfer_tally.add_filter(energyout_filter) - transfer_tally.add_score('scatter') - transfer_tally.add_score('nu-fission') + transfer_tally.filters = [energy_filter, energyout_filter] + transfer_tally.scores = ['scatter', 'nu-fission'] material_tally = Tally() - material_tally.add_filter(Filter(type='material', bins=(1, 2, 3, 4))) - material_tally.add_score('total') + material_tally.filters = [Filter(type='material', bins=(1, 2, 3, 4))] + material_tally.scores = ['total'] mu_tally1 = Tally() - mu_tally1.add_filter(Filter(type='mu', bins=(-1.0, -0.5, 0.0, 0.5, 1.0))) - mu_tally1.add_score('scatter') - mu_tally1.add_score('nu-scatter') + mu_tally1.filters = [Filter(type='mu', bins=(-1.0, -0.5, 0.0, 0.5, 1.0))] + mu_tally1.scores = ['scatter', 'nu-scatter'] mu_filter = Filter(type='mu', bins=(5,)) mu_tally2 = Tally() - mu_tally2.add_filter(mu_filter) - mu_tally2.add_score('scatter') - mu_tally2.add_score('nu-scatter') + mu_tally2.filters = [mu_filter] + mu_tally2.scores = ['scatter', 'nu-scatter'] mu_tally3 = Tally() - mu_tally3.add_filter(mu_filter) - mu_tally3.add_filter(mesh_filter) - mu_tally3.add_score('scatter') - mu_tally3.add_score('nu-scatter') + mu_tally3.filters = [mu_filter, mesh_filter] + mu_tally3.scores = ['scatter', 'nu-scatter'] polar_bins = (0.0, 0.6283, 1.2566, 1.8850, 2.5132, 3.1416) polar_filter = Filter(type='polar', bins=polar_bins) polar_tally1 = Tally() - polar_tally1.add_filter(polar_filter) - polar_tally1.add_score('flux') + polar_tally1.filters = [polar_filter] + polar_tally1.scores = ['flux'] polar_tally1.estimator = 'tracklength' polar_tally2 = Tally() - polar_tally2.add_filter(polar_filter) - polar_tally2.add_score('flux') + polar_tally2.filters = [polar_filter] + polar_tally2.scores = ['flux'] polar_tally2.estimator = 'analog' polar_filter2 = Filter(type='polar', bins=(5,)) polar_tally3 = Tally() - polar_tally3.add_filter(polar_filter2) - polar_tally3.add_score('flux') + polar_tally3.filters = [polar_filter2] + polar_tally3.scores = ['flux'] polar_tally3.estimator = 'tracklength' polar_tally4 = Tally() - polar_tally4.add_filter(polar_filter2) - polar_tally4.add_filter(mesh_filter) - polar_tally4.add_score('flux') + polar_tally4.filters = [polar_filter2, mesh_filter] + polar_tally4.scores = ['flux'] polar_tally4.estimator = 'tracklength' universe_tally = Tally() - universe_tally.add_filter(Filter(type='universe', bins=(1, 2, 3, 4))) - universe_tally.add_score('total') + universe_tally.filters = [Filter(type='universe', bins=(1, 2, 3, 4))] + universe_tally.scores = ['total'] cell_filter = Filter(type='cell', bins=(10, 21, 22, 23)) score_tallies = [Tally(), Tally(), Tally()] for t in score_tallies: - t.add_filter(cell_filter) - t.add_score('absorption') - t.add_score('delayed-nu-fission') - t.add_score('events') - t.add_score('fission') - t.add_score('inverse-velocity') - t.add_score('kappa-fission') - t.add_score('(n,2n)') - t.add_score('(n,n1)') - t.add_score('(n,gamma)') - t.add_score('nu-fission') - t.add_score('scatter') - t.add_score('elastic') - t.add_score('total') + t.filters = [cell_filter] + t.scores = ['absorption', 'delayed-nu-fission', 'events', 'fission', + 'inverse-velocity', 'kappa-fission', '(n,2n)', '(n,n1)', + '(n,gamma)', 'nu-fission', 'scatter', 'elastic', 'total'] score_tallies[0].estimator = 'tracklength' score_tallies[1].estimator = 'analog' score_tallies[2].estimator = 'collision' cell_filter2 = Filter(type='cell', bins=(21, 22, 23, 27, 28, 29)) flux_tallies = [Tally() for i in range(4)] - [t.add_filter(cell_filter2) for t in flux_tallies] - flux_tallies[0].add_score('flux') - [t.add_score('flux-y5') for t in flux_tallies[1:]] + for t in flux_tallies: + t.filters = [cell_filter2] + flux_tallies[0].scores = ['flux'] + for t in flux_tallies[1:]: + t.scores = ['flux-y5'] flux_tallies[1].estimator = 'tracklength' flux_tallies[2].estimator = 'analog' flux_tallies[3].estimator = 'collision' scatter_tally1 = Tally() - scatter_tally1.add_filter(cell_filter) - scatter_tally1.add_score('scatter') - scatter_tally1.add_score('scatter-1') - scatter_tally1.add_score('scatter-2') - scatter_tally1.add_score('scatter-3') - scatter_tally1.add_score('scatter-4') - scatter_tally1.add_score('nu-scatter') - scatter_tally1.add_score('nu-scatter-1') - scatter_tally1.add_score('nu-scatter-2') - scatter_tally1.add_score('nu-scatter-3') - scatter_tally1.add_score('nu-scatter-4') + scatter_tally1.filters = [cell_filter] + scatter_tally1.scores = ['scatter', 'scatter-1', 'scatter-2', 'scatter-3', + 'scatter-4', 'nu-scatter', 'nu-scatter-1', + 'nu-scatter-2', 'nu-scatter-3', 'nu-scatter-4'] scatter_tally2 = Tally() - scatter_tally2.add_filter(cell_filter) - scatter_tally2.add_score('scatter-p4') - scatter_tally2.add_score('scatter-y4') - scatter_tally2.add_score('nu-scatter-p4') - scatter_tally2.add_score('nu-scatter-y3') + scatter_tally2.filters = [cell_filter] + scatter_tally2.scores = ['scatter-p4', 'scatter-y4', 'nu-scatter-p4', + 'nu-scatter-y3'] total_tallies = [Tally() for i in range(4)] - [t.add_filter(cell_filter) for t in total_tallies] - total_tallies[0].add_score('total') - [t.add_score('total-y4') for t in total_tallies[1:]] - [t.add_nuclide('U-235') for t in total_tallies[1:]] - [t.add_nuclide('total') for t in total_tallies[1:]] + for t in total_tallies: + t.filters = [cell_filter] + total_tallies[0].scores = ['total'] + for t in total_tallies[1:]: + t.scores = ['total-y4'] + t.nuclides = ['U-235', 'total'] total_tallies[1].estimator = 'tracklength' total_tallies[2].estimator = 'analog' total_tallies[3].estimator = 'collision' questionable_tally = Tally() - questionable_tally.add_score('transport') - questionable_tally.add_score('n1n') + questionable_tally.scores = ['transport', 'n1n'] all_nuclide_tallies = [Tally(), Tally()] for t in all_nuclide_tallies: - t.add_filter(cell_filter) - t.add_nuclide('all') - t.add_score('total') + t.filters = [cell_filter] + t.nuclides = ['all'] + t.scores = ['total'] all_nuclide_tallies[0].estimator = 'tracklength' all_nuclide_tallies[0].estimator = 'collision' diff --git a/tests/test_tally_aggregation/test_tally_aggregation.py b/tests/test_tally_aggregation/test_tally_aggregation.py index a5c8d9414..7d682b698 100644 --- a/tests/test_tally_aggregation/test_tally_aggregation.py +++ b/tests/test_tally_aggregation/test_tally_aggregation.py @@ -30,13 +30,9 @@ class TallyAggregationTestHarness(PyAPITestHarness): # Initialized the tallies tally = openmc.Tally(name='distribcell tally') - tally.add_filter(energy_filter) - tally.add_filter(distrib_filter) - tally.add_score('nu-fission') - tally.add_score('total') - tally.add_nuclide(u235) - tally.add_nuclide(u238) - tally.add_nuclide(pu239) + tally.filters = [energy_filter, distrib_filter] + tally.scores = ['nu-fission', 'total'] + tally.nuclides = [u235, u238, pu239] tallies_file.add_tally(tally) # Export tallies to file diff --git a/tests/test_tally_arithmetic/test_tally_arithmetic.py b/tests/test_tally_arithmetic/test_tally_arithmetic.py index 1954334b7..cf8d012e8 100644 --- a/tests/test_tally_arithmetic/test_tally_arithmetic.py +++ b/tests/test_tally_arithmetic/test_tally_arithmetic.py @@ -40,22 +40,15 @@ class TallyArithmeticTestHarness(PyAPITestHarness): # Initialized the tallies tally = openmc.Tally(name='tally 1') - tally.add_filter(material_filter) - tally.add_filter(energy_filter) - tally.add_filter(distrib_filter) - tally.add_score('nu-fission') - tally.add_score('total') - tally.add_nuclide(u235) - tally.add_nuclide(pu239) + tally.filters = [material_filter, energy_filter, distrib_filter] + tally.scores = ['nu-fission', 'total'] + tally.nuclides = [u235, pu239] tallies_file.add_tally(tally) tally = openmc.Tally(name='tally 2') - tally.add_filter(energy_filter) - tally.add_filter(mesh_filter) - tally.add_score('total') - tally.add_score('fission') - tally.add_nuclide(u238) - tally.add_nuclide(u235) + tally.filters = [energy_filter, mesh_filter] + tally.scores = ['total', 'fission'] + tally.nuclides = [u238, u235] tallies_file.add_tally(tally) tallies_file.add_mesh(mesh)