def get_tally(self, scores=[], filters=[], nuclides=[],
name=None, id=None, estimator=None, exact_filters=False,
exact_nuclides=False, exact_scores=False,
multiply_density=None, derivative=None, filter_type=None):
"""Finds and returns a Tally object with certain properties.
This routine searches the list of Tallies and returns the first Tally
found which satisfies all of the input parameters.
NOTE: If any of the "exact" parameters are False (default), the input
parameters do not need to match the complete Tally specification and may
only represent a subset of the Tally's properties. If an "exact"
parameter is True then number of scores, filters, or nuclides in the
parameters must precisely match those of any matching Tally.
Parameters
----------
scores : list, optional
A list of one or more score strings (default is []).
filters : list, optional
A list of Filter objects (default is []).
nuclides : list, optional
A list of Nuclide objects (default is []).
name : str, optional
The name specified for the Tally (default is None).
id : Integral, optional
The id specified for the Tally (default is None).
estimator: str, optional
The type of estimator ('tracklength', 'analog'; default is None).
exact_filters : bool
If True, the number of filters in the parameters must be identical
to those in the matching Tally. If False (default), the filters in
the parameters may be a subset of those in the matching Tally.
exact_nuclides : bool
If True, the number of nuclides in the parameters must be identical
to those in the matching Tally. If False (default), the nuclides in
the parameters may be a subset of those in the matching Tally.
exact_scores : bool
If True, the number of scores in the parameters must be identical to
those in the matching Tally. If False (default), the scores in the
parameters may be a subset of those in the matching Tally. Default
is None (no check).
multiply_density : bool, optional
If not None, the Tally must have the multiply_density attribute set
to the same value as this parameter.
derivative : openmc.TallyDerivative, optional
TallyDerivative object to match.
filter_type : type, optional
If not None, the Tally must have at least one Filter that is an
instance of this type. For example `openmc.MeshFilter`.
Returns
-------
tally : openmc.Tally
A tally matching the specified criteria
Raises
------
LookupError
If a Tally meeting all of the input parameters cannot be found in
the statepoint.
"""
tally = None
# Iterate over all tallies to find the appropriate one
for test_tally in self.tallies.values():
# Determine if Tally has queried name
if name and name != test_tally.name:
continue
# Determine if Tally has queried id
if id and id != test_tally.id:
continue
# Determine if Tally has queried estimator, only move on to next tally
# if the estimator is both specified and the tally estimtor does not
# match
if estimator is not None and estimator != test_tally.estimator:
continue
# The number of filters, nuclides and scores must exactly match
if exact_scores and len(scores) != test_tally.num_scores:
continue
if exact_nuclides and nuclides and len(nuclides) != test_tally.num_nuclides:
continue
if exact_nuclides and not nuclides and test_tally.nuclides != ['total']:
continue
if exact_filters and len(filters) != test_tally.num_filters:
continue
if derivative is not None and derivative != test_tally.derivative:
continue
if multiply_density is not None and multiply_density != test_tally.multiply_density:
continue
# Determine if Tally has the queried score(s)
if scores:
if not all(score in test_tally.scores for score in scores):
continue
# Determine if Tally has the queried Filter(s)
if filters:
contains_filters = True
# Iterate over the Filters requested by the user
for outer_filter in filters:
contains_filters = False
# Test if requested filter is a subset of any of the test
# tally's filters and if so continue to next filter
for inner_filter in test_tally.filters:
if inner_filter.is_subset(outer_filter):
contains_filters = True
break
if not contains_filters:
break
if not contains_filters:
continue
if filter_type is not None:
if not any(isinstance(f, filter_type) for f in test_tally.filters):
continue
# Determine if Tally has the queried Nuclide(s)
if nuclides:
if not all(nuclide in test_tally.nuclides for nuclide in nuclides):
continue
# If the current Tally met user's request, break loop and return it
tally = test_tally
break
# If we did not find the Tally, return an error message
if tally is None:
# Build a detailed error message with search criteria
criteria = []
if name is not None:
criteria.append(f"name='{name}'")
if id is not None:
criteria.append(f"id={id}")
if estimator is not None:
criteria.append(f"estimator='{estimator}'")
if scores:
criteria.append(f"scores={scores}")
if filters:
criteria.append(f"filters={filters}")
if nuclides:
criteria.append(f"nuclides={nuclides}")
if filter_type is not None:
criteria.append(f"filter_type={filter_type}")
if multiply_density is not None:
criteria.append(f"multiply_density={multiply_density}")
if derivative is not None:
criteria.append(f"derivative={derivative}")
criteria_str = ", ".join(criteria) if criteria else "no criteria specified"
# Get list of available values for each search criterion
available_parts = []
if name is not None:
available_names = [f"'{t.name}'" for t in self.tallies.values() if t.name]
names_str = ", ".join(available_names) if available_names else "no named tallies"
available_parts.append(f"names: {names_str}")
if id is not None:
available_ids = [str(t.id) for t in self.tallies.values()]
ids_str = ", ".join(available_ids) if available_ids else "no IDs"
available_parts.append(f"IDs: {ids_str}")
if estimator is not None:
available_estimators = list(set(t.estimator for t in self.tallies.values()))
estimators_str = ", ".join(f"'{e}'" for e in available_estimators) if available_estimators else "none"
available_parts.append(f"estimators: {estimators_str}")
if scores:
available_scores = list(set(score for t in self.tallies.values() for score in t.scores))
scores_str = ", ".join(available_scores) if available_scores else "none"
available_parts.append(f"scores: {scores_str}")
if nuclides:
available_nuclides = list(set(nuc for t in self.tallies.values() for nuc in t.nuclides))
nuclides_str = ", ".join(available_nuclides) if available_nuclides else "none"
available_parts.append(f"nuclides: {nuclides_str}")
if filter_type is not None:
available_filter_types = list(set(type(f).__name__ for t in self.tallies.values() for f in t.filters))
filter_types_str = ", ".join(available_filter_types) if available_filter_types else "none"
available_parts.append(f"filter types: {filter_types_str}")
if multiply_density is not None:
available_multiply_density = list(set(str(t.multiply_density) for t in self.tallies.values()))
multiply_density_str = ", ".join(available_multiply_density)
available_parts.append(f"multiply_density values: {multiply_density_str}")
available_str = "; ".join(available_parts) if available_parts else "no tallies available"
error_msg = (f"Unable to get Tally with {criteria_str}. "
f"Available: {available_str}")
raise LookupError(error_msg)
return tally
update statepoint to