diff --git a/src/utils/openmc/__init__.py b/src/utils/openmc/__init__.py index 42ee1eebf..d966a155a 100644 --- a/src/utils/openmc/__init__.py +++ b/src/utils/openmc/__init__.py @@ -6,10 +6,12 @@ from openmc.plots import * from openmc.settings import * from openmc.surface import * from openmc.universe import * +from openmc.mesh import * +from openmc.filter import * +from openmc.trigger import * from openmc.tallies import * from openmc.cmfd import * from openmc.executor import * -#from statepoint import * try: from openmc.opencg_compatible import * diff --git a/src/utils/openmc/filter.py b/src/utils/openmc/filter.py new file mode 100644 index 000000000..8b3cb6ca0 --- /dev/null +++ b/src/utils/openmc/filter.py @@ -0,0 +1,267 @@ +import copy + +from openmc import Mesh +from openmc.checkvalue import * +from openmc.constants import * + + +class Filter(object): + + # Initialize Filter class attributes + def __init__(self, type=None, bins=None): + + self.type = type + self.bins = bins + self._mesh = None + self._offset = -1 + self._stride = None + + + def __eq__(self, filter2): + + # Check type + if self._type != filter2._type: + return False + + # Check number of bins + elif len(self._bins) != len(filter2._bins): + return False + + # Check bin edges + elif not np.allclose(self._bins, filter2._bins): + return False + + else: + return True + + + def __hash__(self): + hashable = [] + hashable.append(self._type) + hashable.append(self._bins) + return hash(tuple(hashable)) + + + def __deepcopy__(self, memo): + + existing = memo.get(id(self)) + + # If this is the first time we have tried to copy this object, create a copy + if existing is None: + + clone = type(self).__new__(type(self)) + clone._type = self._type + clone._bins = copy.deepcopy(self._bins, memo) + clone._num_bins = self._num_bins + clone._mesh = copy.deepcopy(self._mesh, memo) + clone._offset = self._offset + clone._stride = self._stride + + memo[id(self)] = clone + + return clone + + # If this object has been copied before, return the first copy made + else: + return existing + + + @property + def type(self): + return self._type + + + @property + def bins(self): + return self._bins + + + @property + def num_bins(self): + return self._num_bins + + + @property + def mesh(self): + return self._mesh + + + @property + def offset(self): + return self._offset + + + @property + def stride(self): + return self._stride + + + @type.setter + def type(self, type): + + if type is None: + self._type = type + + elif not type in FILTER_TYPES.values(): + msg = 'Unable to set Filter type to {0} since it is not one ' \ + 'of the supported types'.format(type) + raise ValueError(msg) + + self._type = type + + + @bins.setter + def bins(self, bins): + + if bins is None: + self.num_bins = 0 + + elif self._type is None: + msg = 'Unable to set bins for Filter to {0} since ' \ + 'the Filter type has not yet been set'.format(bins) + raise ValueError(msg) + + # If the bin edge is a single value, it is a Cell, Material, etc. ID + if not isinstance(bins, (tuple, list, np.ndarray)): + bins = [bins] + + # If the bins are in a collection, convert it to a list + else: + bins = list(bins) + + if self._type in ['cell', 'cellborn', 'surface', 'material', + 'universe', 'distribcell']: + + for edge in bins: + + if not is_integer(edge): + msg = 'Unable to add bin {0} to a {1} Filter since ' \ + 'it is a non-integer'.format(edge, self._type) + raise ValueError(msg) + + elif edge < 0: + msg = 'Unable to add bin {0} to a {1} Filter since ' \ + 'it is a negative integer'.format(edge, self._type) + raise ValueError(msg) + + + elif self._type in ['energy', 'energyout']: + + for edge in bins: + + if not is_integer(edge) and not is_float(edge): + msg = 'Unable to add bin edge {0} to {1} Filter since ' \ + 'it is a non-integer or floating point ' \ + 'value'.format(edge, self._type) + raise ValueError(msg) + + elif edge < 0.: + msg = 'Unable to add bin edge {0} to {1} Filter since it ' \ + 'is a negative value'.format(edge, self._type) + raise ValueError(msg) + + # Check that bin edges are monotonically increasing + for index in range(len(bins)): + + if index > 0 and bins[index] < bins[index-1]: + msg = 'Unable to add bin edges {0} to {1} Filter since ' \ + 'they are not monotonically ' \ + 'increasing'.format(bins, self._type) + raise ValueError(msg) + + + # mesh filters + elif self._type == 'mesh': + + if not len(bins) == 1: + msg = 'Unable to add bins {0} to a mesh Filter since ' \ + 'only a single mesh can be used per tally'.format(bins) + raise ValueError(msg) + + elif not is_integer(bins[0]): + msg = 'Unable to add bin {0} to mesh Filter since it ' \ + 'is a non-integer'.format(bins[0]) + raise ValueError(msg) + + elif bins[0] < 0: + msg = 'Unable to add bin {0} to mesh Filter since it ' \ + 'is a negative integer'.format(bins[0]) + raise ValueError(msg) + + # If all error checks passed, add bin edges + self._bins = bins + + + # FIXME + @num_bins.setter + def num_bins(self, num_bins): + + if not is_integer(num_bins) or num_bins < 0: + msg = 'Unable to set the number of bins {0} for a {1} Filter ' \ + 'since it is not a positive ' \ + 'integer'.format(num_bins, self._type) + raise ValueError(msg) + + self._num_bins = num_bins + + + @mesh.setter + def mesh(self, mesh): + + if not isinstance(mesh, Mesh): + msg = 'Unable to set Mesh to {0} for Filter since it is not a ' \ + 'Mesh object'.format(mesh) + raise ValueError(msg) + + self._mesh = mesh + self.type = 'mesh' + self.bins = self._mesh._id + + + @offset.setter + def offset(self, offset): + + if not is_integer(offset): + msg = 'Unable to set offset {0} for a {1} Filter since it is a ' \ + 'non-integer value'.format(offset, self._type) + raise ValueError(msg) + + self._offset = offset + + + @stride.setter + def stride(self, stride): + + if not is_integer(stride): + msg = 'Unable to set stride {0} for a {1} Filter since it is a ' \ + 'non-integer value'.format(stride, self._type) + raise ValueError(msg) + + if stride < 0: + msg = 'Unable to set stride {0} for a {1} Filter since it is a ' \ + 'negative value'.format(stride, self._type) + raise ValueError(msg) + + self._stride = stride + + + def get_bin_index(self, bin): + + try: + index = self._bins.index(bin) + + except ValueError: + msg = 'Unable to get the bin index for Filter since {0} ' \ + 'is not one of the bins'.format(bin) + raise ValueError(msg) + + return index + + + def __repr__(self): + + string = 'Filter\n' + string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._type) + string += '{0: <16}{1}{2}\n'.format('\tBins', '=\t', self._bins) + string += '{0: <16}{1}{2}\n'.format('\tOffset', '=\t', self._offset) + return string diff --git a/src/utils/openmc/mesh.py b/src/utils/openmc/mesh.py new file mode 100644 index 000000000..bfa555f49 --- /dev/null +++ b/src/utils/openmc/mesh.py @@ -0,0 +1,308 @@ +import copy +from xml.etree import ElementTree as ET + +from openmc.checkvalue import * + + +# "Static" variable for auto-generated and Mesh IDs +AUTO_MESH_ID = 10000 + + +def reset_auto_mesh_id(): + global AUTO_MESH_ID + AUTO_MESH_ID = 10000 + + +class Mesh(object): + + def __init__(self, mesh_id=None, name=''): + + # Initialize Mesh class attributes + self.id = mesh_id + self.name = name + self._type = 'rectangular' + self._dimension = None + self._lower_left = None + self._upper_right = None + self._width = None + + + def __deepcopy__(self, memo): + + existing = memo.get(id(self)) + + # If this is the first time we have tried to copy this object, create a copy + if existing is None: + + clone = type(self).__new__(type(self)) + clone._id = self._id + clone._name = self._name + clone._type = self._type + clone._dimension = copy.deepcopy(self._dimension, memo) + clone._lower_left = copy.deepcopy(self._lower_left, memo) + clone._upper_right = copy.deepcopy(self._upper_right, memo) + clone._width = copy.deepcopy(self._width, memo) + + memo[id(self)] = clone + + return clone + + # If this object has been copied before, return the first copy made + else: + return existing + + + @property + def id(self): + return self._id + + + @property + def name(self): + return self._name + + + @property + def type(self): + return self._type + + + @property + def dimension(self): + return self._dimension + + + @property + def lower_left(self): + return self._lower_left + + + @property + def upper_right(self): + return self._upper_right + + + @property + def width(self): + return self._width + + + @property + def num_mesh_cells(self): + return np.prod(self._dimension) + + + @id.setter + def id(self, mesh_id): + + if mesh_id is None: + global AUTO_MESH_ID + self._id = AUTO_MESH_ID + AUTO_MESH_ID += 1 + + # Check that the ID is an integer and wasn't already used + elif not is_integer(mesh_id): + msg = 'Unable to set a non-integer Mesh ID {0}'.format(mesh_id) + raise ValueError(msg) + + elif mesh_id < 0: + msg = 'Unable to set Mesh ID to {0} since it must be a ' \ + 'non-negative integer'.format(mesh_id) + raise ValueError(msg) + + else: + self._id = mesh_id + + + @name.setter + def name(self, name): + + if not is_string(name): + msg = 'Unable to set name for Mesh ID={0} with a non-string ' \ + 'value {1}'.format(self._id, name) + raise ValueError(msg) + + else: + self._name = name + + + @type.setter + def type(self, type): + + if not is_string(type): + msg = 'Unable to set Mesh ID={0} for type {1} which is not ' \ + 'a string'.format(self._id, type) + raise ValueError(msg) + + elif not type in ['rectangular', 'hexagonal']: + msg = 'Unable to set Mesh ID={0} for type {1} which since ' \ + 'only rectangular and hexagonal meshes are ' \ + 'supported '.format(self._id, type) + raise ValueError(msg) + + self._type = type + + + @dimension.setter + def dimension(self, dimension): + + if not isinstance(dimension, (tuple, list, np.ndarray)): + msg = 'Unable to set Mesh ID={0} with dimension {1} which is ' \ + 'not a Python list, tuple or NumPy ' \ + 'array'.format(self._id, dimension) + raise ValueError(msg) + + elif len(dimension) != 2 and len(dimension) != 3: + msg = 'Unable to set Mesh ID={0} with dimension {1} since it ' \ + 'must include 2 or 3 dimensions'.format(self._id, dimension) + raise ValueError(msg) + + for dim in dimension: + + if not is_integer(dim): + msg = 'Unable to set Mesh ID={0} with dimension {1} which ' \ + 'is a non-integer'.format(self._id, dim) + raise ValueError(msg) + + self._dimension = dimension + + + @lower_left.setter + def lower_left(self, lower_left): + + if not isinstance(lower_left, (tuple, list, np.ndarray)): + msg = 'Unable to set Mesh ID={0} with lower_left {1} which is ' \ + 'not a Python list, tuple or NumPy ' \ + 'array'.format(self._id, lower_left) + raise ValueError(msg) + + elif len(lower_left) != 2 and len(lower_left) != 3: + msg = 'Unable to set Mesh ID={0} with lower_left {1} since it ' \ + 'must include 2 or 3 dimensions'.format(self._id, lower_left) + raise ValueError(msg) + + for coord in lower_left: + + if not is_integer(coord) and not is_float(coord): + msg = 'Unable to set Mesh ID={0} with lower_left {1} which ' \ + 'is neither neither an integer nor a floating point ' \ + 'value'.format(self._id, coord) + raise ValueError(msg) + + self._lower_left = lower_left + + + @upper_right.setter + def upper_right(self, upper_right): + + if not isinstance(upper_right, (tuple, list, np.ndarray)): + msg = 'Unable to set Mesh ID={0} with upper_right {1} which ' \ + 'is not a Python list, tuple or NumPy ' \ + 'array'.format(self._id, upper_right) + raise ValueError(msg) + + if len(upper_right) != 2 and len(upper_right) != 3: + msg = 'Unable to set Mesh ID={0} with upper_right {1} since it ' \ + 'must include 2 or 3 dimensions'.format(self._id, upper_right) + raise ValueError(msg) + + for coord in upper_right: + + if not is_integer(coord) and not is_float(coord): + msg = 'Unable to set Mesh ID={0} with upper_right {1} which ' \ + 'is neither an integer nor a floating point ' \ + 'value'.format(self._id, coord) + raise ValueError(msg) + + self._upper_right = upper_right + + + @width.setter + def width(self, width): + + if not width is None: + + if not isinstance(width, (tuple, list, np.ndarray)): + msg = 'Unable to set Mesh ID={0} with width {1} which ' \ + 'is not a Python list, tuple or NumPy ' \ + 'array'.format(self._id, width) + raise ValueError(msg) + + if len(width) != 2 and len(width) != 3: + msg = 'Unable to set Mesh ID={0} with width {1} since it must ' \ + 'include 2 or 3 dimensions'.format(self._id, width) + raise ValueError(msg) + + for dim in width: + + if not is_integer(dim) and not is_float(dim): + msg = 'Unable to set Mesh ID={0} with width {1} which is ' \ + 'neither an integer nor a floating point ' \ + 'value'.format(self._id, width) + raise ValueError(msg) + + self._width = width + + + def __repr__(self): + + string = 'Mesh\n' + string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id) + string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name) + string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._type) + string += '{0: <16}{1}{2}\n'.format('\tBasis', '=\t', self._dimension) + string += '{0: <16}{1}{2}\n'.format('\tWidth', '=\t', self._lower_left) + string += '{0: <16}{1}{2}\n'.format('\tOrigin', '=\t', self._upper_right) + string += '{0: <16}{1}{2}\n'.format('\tPixels', '=\t', self._width) + return string + + + def get_mesh_xml(self): + + element = ET.Element("mesh") + element.set("id", str(self._id)) + element.set("type", self._type) + + if len(self._dimension) == 2: + subelement = ET.SubElement(element, "dimension") + subelement.text = '{0} {1}'.format(self._dimension[0], + self._dimension[1]) + else: + subelement = ET.SubElement(element, "dimension") + subelement.text = '{0} {1} {2}'.format(self._dimension[0], + self._dimension[1], + self._dimension[2]) + + if len(self._lower_left) == 2: + subelement = ET.SubElement(element, "lower_left") + subelement.text = '{0} {1}'.format(self._lower_left[0], + self._lower_left[1]) + else: + subelement = ET.SubElement(element, "lower_left") + subelement.text = '{0} {1} {2}'.format(self._lower_left[0], + self._lower_left[1], + self._lower_left[2]) + + if not self._upper_right is None: + if len(self._upper_right) == 2: + subelement = ET.SubElement(element, "upper_right") + subelement.text = '{0} {1}'.format(self._upper_right[0], + self._upper_right[1]) + else: + subelement = ET.SubElement(element, "upper_right") + subelement.text = '{0} {1} {2}'.format(self._upper_right[0], + self._upper_right[1], + self._upper_right[2]) + + if not self._width is None: + if len(self._width) == 2: + subelement = ET.SubElement(element, "width") + subelement.text = '{0} {1}'.format(self._width[0], + self._width[1]) + else: + subelement = ET.SubElement(element, "width") + subelement.text = '{0} {1} {2}'.format(self._width[0], + self._width[1], + self._width[2]) + + return element diff --git a/src/utils/openmc/tallies.py b/src/utils/openmc/tallies.py index 14ca91f6f..f2799dcd3 100644 --- a/src/utils/openmc/tallies.py +++ b/src/utils/openmc/tallies.py @@ -2,15 +2,13 @@ import copy import os from xml.etree import ElementTree as ET -from openmc import Nuclide +from openmc import Mesh, Filter, Trigger, Nuclide from openmc.clean_xml import * from openmc.checkvalue import * -from openmc.constants import * -# "Static" variables for auto-generated Tally and Mesh IDs +# "Static" variable for auto-generated Tally IDs AUTO_TALLY_ID = 10000 -AUTO_MESH_ID = 10000 def reset_auto_tally_id(): @@ -18,680 +16,6 @@ def reset_auto_tally_id(): AUTO_TALLY_ID = 10000 -def reset_auto_mesh_id(): - global AUTO_MESH_ID - AUTO_MESH_ID = 10000 - - -class Filter(object): - - # Initialize Filter class attributes - def __init__(self, type=None, bins=None): - - self.type = type - self.bins = bins - self._mesh = None - self._offset = -1 - self._stride = None - - - def __eq__(self, filter2): - - # Check type - if self._type != filter2._type: - return False - - # Check number of bins - elif len(self._bins) != len(filter2._bins): - return False - - # Check bin edges - elif not np.allclose(self._bins, filter2._bins): - return False - - else: - return True - - - def __hash__(self): - hashable = [] - hashable.append(self._type) - hashable.append(self._bins) - return hash(tuple(hashable)) - - - def __deepcopy__(self, memo): - - existing = memo.get(id(self)) - - # If this is the first time we have tried to copy this object, create a copy - if existing is None: - - clone = type(self).__new__(type(self)) - clone._type = self._type - clone._bins = copy.deepcopy(self._bins, memo) - clone._num_bins = self._num_bins - clone._mesh = copy.deepcopy(self._mesh, memo) - clone._offset = self._offset - clone._stride = self._stride - - memo[id(self)] = clone - - return clone - - # If this object has been copied before, return the first copy made - else: - return existing - - - @property - def type(self): - return self._type - - - @property - def bins(self): - return self._bins - - - @property - def num_bins(self): - return self._num_bins - - - @property - def mesh(self): - return self._mesh - - - @property - def offset(self): - return self._offset - - - @property - def stride(self): - return self._stride - - - @type.setter - def type(self, type): - - if type is None: - self._type = type - - elif not type in FILTER_TYPES.values(): - msg = 'Unable to set Filter type to {0} since it is not one ' \ - 'of the supported types'.format(type) - raise ValueError(msg) - - self._type = type - - - @bins.setter - def bins(self, bins): - - if bins is None: - self.num_bins = 0 - - elif self._type is None: - msg = 'Unable to set bins for Filter to {0} since ' \ - 'the Filter type has not yet been set'.format(bins) - raise ValueError(msg) - - # If the bin edge is a single value, it is a Cell, Material, etc. ID - if not isinstance(bins, (tuple, list, np.ndarray)): - bins = [bins] - - # If the bins are in a collection, convert it to a list - else: - bins = list(bins) - - if self._type in ['cell', 'cellborn', 'surface', 'material', - 'universe', 'distribcell']: - - for edge in bins: - - if not is_integer(edge): - msg = 'Unable to add bin {0} to a {1} Filter since ' \ - 'it is a non-integer'.format(edge, self._type) - raise ValueError(msg) - - elif edge < 0: - msg = 'Unable to add bin {0} to a {1} Filter since ' \ - 'it is a negative integer'.format(edge, self._type) - raise ValueError(msg) - - - elif self._type in ['energy', 'energyout']: - - for edge in bins: - - if not is_integer(edge) and not is_float(edge): - msg = 'Unable to add bin edge {0} to {1} Filter since ' \ - 'it is a non-integer or floating point ' \ - 'value'.format(edge, self._type) - raise ValueError(msg) - - elif edge < 0.: - msg = 'Unable to add bin edge {0} to {1} Filter since it ' \ - 'is a negative value'.format(edge, self._type) - raise ValueError(msg) - - # Check that bin edges are monotonically increasing - for index in range(len(bins)): - - if index > 0 and bins[index] < bins[index-1]: - msg = 'Unable to add bin edges {0} to {1} Filter since ' \ - 'they are not monotonically ' \ - 'increasing'.format(bins, self._type) - raise ValueError(msg) - - - # mesh filters - elif self._type == 'mesh': - - if not len(bins) == 1: - msg = 'Unable to add bins {0} to a mesh Filter since ' \ - 'only a single mesh can be used per tally'.format(bins) - raise ValueError(msg) - - elif not is_integer(bins[0]): - msg = 'Unable to add bin {0} to mesh Filter since it ' \ - 'is a non-integer'.format(bins[0]) - raise ValueError(msg) - - elif bins[0] < 0: - msg = 'Unable to add bin {0} to mesh Filter since it ' \ - 'is a negative integer'.format(bins[0]) - raise ValueError(msg) - - # If all error checks passed, add bin edges - self._bins = bins - - - # FIXME - @num_bins.setter - def num_bins(self, num_bins): - - if not is_integer(num_bins) or num_bins < 0: - msg = 'Unable to set the number of bins {0} for a {1} Filter ' \ - 'since it is not a positive ' \ - 'integer'.format(num_bins, self._type) - raise ValueError(msg) - - self._num_bins = num_bins - - - @mesh.setter - def mesh(self, mesh): - - if not isinstance(mesh, Mesh): - msg = 'Unable to set Mesh to {0} for Filter since it is not a ' \ - 'Mesh object'.format(mesh) - raise ValueError(msg) - - self._mesh = mesh - self.type = 'mesh' - self.bins = self._mesh._id - - - @offset.setter - def offset(self, offset): - - if not is_integer(offset): - msg = 'Unable to set offset {0} for a {1} Filter since it is a ' \ - 'non-integer value'.format(offset, self._type) - raise ValueError(msg) - - self._offset = offset - - - @stride.setter - def stride(self, stride): - - if not is_integer(stride): - msg = 'Unable to set stride {0} for a {1} Filter since it is a ' \ - 'non-integer value'.format(stride, self._type) - raise ValueError(msg) - - if stride < 0: - msg = 'Unable to set stride {0} for a {1} Filter since it is a ' \ - 'negative value'.format(stride, self._type) - raise ValueError(msg) - - self._stride = stride - - - def get_bin_index(self, bin): - - try: - index = self._bins.index(bin) - - except ValueError: - msg = 'Unable to get the bin index for Filter since {0} ' \ - 'is not one of the bins'.format(bin) - raise ValueError(msg) - - return index - - - def __repr__(self): - - string = 'Filter\n' - string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._type) - string += '{0: <16}{1}{2}\n'.format('\tBins', '=\t', self._bins) - string += '{0: <16}{1}{2}\n'.format('\tOffset', '=\t', self._offset) - return string - - - -class Mesh(object): - - def __init__(self, mesh_id=None, name=''): - - # Initialize Mesh class attributes - self.id = mesh_id - self.name = name - self._type = 'rectangular' - self._dimension = None - self._lower_left = None - self._upper_right = None - self._width = None - - - def __deepcopy__(self, memo): - - existing = memo.get(id(self)) - - # If this is the first time we have tried to copy this object, create a copy - if existing is None: - - clone = type(self).__new__(type(self)) - clone._id = self._id - clone._name = self._name - clone._type = self._type - clone._dimension = copy.deepcopy(self._dimension, memo) - clone._lower_left = copy.deepcopy(self._lower_left, memo) - clone._upper_right = copy.deepcopy(self._upper_right, memo) - clone._width = copy.deepcopy(self._width, memo) - - memo[id(self)] = clone - - return clone - - # If this object has been copied before, return the first copy made - else: - return existing - - - @property - def id(self): - return self._id - - - @property - def name(self): - return self._name - - - @property - def type(self): - return self._type - - - @property - def dimension(self): - return self._dimension - - - @property - def lower_left(self): - return self._lower_left - - - @property - def upper_right(self): - return self._upper_right - - - @property - def width(self): - return self._width - - - @property - def num_mesh_cells(self): - return np.prod(self._dimension) - - - @id.setter - def id(self, mesh_id): - - if mesh_id is None: - global AUTO_MESH_ID - self._id = AUTO_MESH_ID - AUTO_MESH_ID += 1 - - # Check that the ID is an integer and wasn't already used - elif not is_integer(mesh_id): - msg = 'Unable to set a non-integer Mesh ID {0}'.format(mesh_id) - raise ValueError(msg) - - elif mesh_id < 0: - msg = 'Unable to set Mesh ID to {0} since it must be a ' \ - 'non-negative integer'.format(mesh_id) - raise ValueError(msg) - - else: - self._id = mesh_id - - - @name.setter - def name(self, name): - - if not is_string(name): - msg = 'Unable to set name for Mesh ID={0} with a non-string ' \ - 'value {1}'.format(self._id, name) - raise ValueError(msg) - - else: - self._name = name - - - @type.setter - def type(self, type): - - if not is_string(type): - msg = 'Unable to set Mesh ID={0} for type {1} which is not ' \ - 'a string'.format(self._id, type) - raise ValueError(msg) - - elif not type in ['rectangular', 'hexagonal']: - msg = 'Unable to set Mesh ID={0} for type {1} which since ' \ - 'only rectangular and hexagonal meshes are ' \ - 'supported '.format(self._id, type) - raise ValueError(msg) - - self._type = type - - - @dimension.setter - def dimension(self, dimension): - - if not isinstance(dimension, (tuple, list, np.ndarray)): - msg = 'Unable to set Mesh ID={0} with dimension {1} which is ' \ - 'not a Python list, tuple or NumPy ' \ - 'array'.format(self._id, dimension) - raise ValueError(msg) - - elif len(dimension) != 2 and len(dimension) != 3: - msg = 'Unable to set Mesh ID={0} with dimension {1} since it ' \ - 'must include 2 or 3 dimensions'.format(self._id, dimension) - raise ValueError(msg) - - for dim in dimension: - - if not is_integer(dim): - msg = 'Unable to set Mesh ID={0} with dimension {1} which ' \ - 'is a non-integer'.format(self._id, dim) - raise ValueError(msg) - - self._dimension = dimension - - - @lower_left.setter - def lower_left(self, lower_left): - - if not isinstance(lower_left, (tuple, list, np.ndarray)): - msg = 'Unable to set Mesh ID={0} with lower_left {1} which is ' \ - 'not a Python list, tuple or NumPy ' \ - 'array'.format(self._id, lower_left) - raise ValueError(msg) - - elif len(lower_left) != 2 and len(lower_left) != 3: - msg = 'Unable to set Mesh ID={0} with lower_left {1} since it ' \ - 'must include 2 or 3 dimensions'.format(self._id, lower_left) - raise ValueError(msg) - - for coord in lower_left: - - if not is_integer(coord) and not is_float(coord): - msg = 'Unable to set Mesh ID={0} with lower_left {1} which ' \ - 'is neither neither an integer nor a floating point ' \ - 'value'.format(self._id, coord) - raise ValueError(msg) - - self._lower_left = lower_left - - - @upper_right.setter - def upper_right(self, upper_right): - - if not isinstance(upper_right, (tuple, list, np.ndarray)): - msg = 'Unable to set Mesh ID={0} with upper_right {1} which ' \ - 'is not a Python list, tuple or NumPy ' \ - 'array'.format(self._id, upper_right) - raise ValueError(msg) - - if len(upper_right) != 2 and len(upper_right) != 3: - msg = 'Unable to set Mesh ID={0} with upper_right {1} since it ' \ - 'must include 2 or 3 dimensions'.format(self._id, upper_right) - raise ValueError(msg) - - for coord in upper_right: - - if not is_integer(coord) and not is_float(coord): - msg = 'Unable to set Mesh ID={0} with upper_right {1} which ' \ - 'is neither an integer nor a floating point ' \ - 'value'.format(self._id, coord) - raise ValueError(msg) - - self._upper_right = upper_right - - - @width.setter - def width(self, width): - - if not width is None: - - if not isinstance(width, (tuple, list, np.ndarray)): - msg = 'Unable to set Mesh ID={0} with width {1} which ' \ - 'is not a Python list, tuple or NumPy ' \ - 'array'.format(self._id, width) - raise ValueError(msg) - - if len(width) != 2 and len(width) != 3: - msg = 'Unable to set Mesh ID={0} with width {1} since it must ' \ - 'include 2 or 3 dimensions'.format(self._id, width) - raise ValueError(msg) - - for dim in width: - - if not is_integer(dim) and not is_float(dim): - msg = 'Unable to set Mesh ID={0} with width {1} which is ' \ - 'neither an integer nor a floating point ' \ - 'value'.format(self._id, width) - raise ValueError(msg) - - self._width = width - - - def __repr__(self): - - string = 'Mesh\n' - string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id) - string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name) - string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._type) - string += '{0: <16}{1}{2}\n'.format('\tBasis', '=\t', self._dimension) - string += '{0: <16}{1}{2}\n'.format('\tWidth', '=\t', self._lower_left) - string += '{0: <16}{1}{2}\n'.format('\tOrigin', '=\t', self._upper_right) - string += '{0: <16}{1}{2}\n'.format('\tPixels', '=\t', self._width) - return string - - - def get_mesh_xml(self): - - element = ET.Element("mesh") - element.set("id", str(self._id)) - element.set("type", self._type) - - if len(self._dimension) == 2: - subelement = ET.SubElement(element, "dimension") - subelement.text = '{0} {1}'.format(self._dimension[0], - self._dimension[1]) - else: - subelement = ET.SubElement(element, "dimension") - subelement.text = '{0} {1} {2}'.format(self._dimension[0], - self._dimension[1], - self._dimension[2]) - - if len(self._lower_left) == 2: - subelement = ET.SubElement(element, "lower_left") - subelement.text = '{0} {1}'.format(self._lower_left[0], - self._lower_left[1]) - else: - subelement = ET.SubElement(element, "lower_left") - subelement.text = '{0} {1} {2}'.format(self._lower_left[0], - self._lower_left[1], - self._lower_left[2]) - - if not self._upper_right is None: - if len(self._upper_right) == 2: - subelement = ET.SubElement(element, "upper_right") - subelement.text = '{0} {1}'.format(self._upper_right[0], - self._upper_right[1]) - else: - subelement = ET.SubElement(element, "upper_right") - subelement.text = '{0} {1} {2}'.format(self._upper_right[0], - self._upper_right[1], - self._upper_right[2]) - - if not self._width is None: - if len(self._width) == 2: - subelement = ET.SubElement(element, "width") - subelement.text = '{0} {1}'.format(self._width[0], - self._width[1]) - else: - subelement = ET.SubElement(element, "width") - subelement.text = '{0} {1} {2}'.format(self._width[0], - self._width[1], - self._width[2]) - - return element - - -class Trigger(object): - - def __init__(self, trigger_type, threshold): - - # Initialize Mesh class attributes - self.trigger_type = trigger_type - self.threshold = threshold - self._scores = [] - - - def __deepcopy__(self, memo): - - existing = memo.get(id(self)) - - # If this is first time we have tried to copy this object, create a copy - if existing is None: - - clone = type(self).__new__(type(self)) - clone._trigger_type = self._trigger_type - clone._threshold = self._threshold - - clone._scores = [] - for score in self._scores: - clone.add_score(score) - - memo[id(self)] = clone - - return clone - - # If this object has been copied before, return the first copy made - else: - return existing - - - @property - def trigger_type(self): - return self._trigger_type - - - @property - def threshold(self): - return self._threshold - - - @property - def scores(self): - return self._scores - - - @trigger_type.setter - def trigger_type(self, trigger_type): - - if not trigger_type in ['variance', 'std_dev', 'rel_err']: - msg = 'Unable to create a tally trigger with ' \ - 'type {0}'.format(trigger_type) - raise ValueError(msg) - - self._trigger_type = trigger_type - - - @threshold.setter - def threshold(self, threshold): - - if not is_float(threshold): - msg = 'Unable to set a tally trigger threshold with ' \ - 'threshold {0}'.format(threshold) - raise ValueError(msg) - - self._threshold = threshold - - - def add_score(self, score): - - if not is_string(score): - 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) - - - def __repr__(self): - - string = 'Trigger\n' - string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._trigger_type) - string += '{0: <16}{1}{2}\n'.format('\tThreshold', '=\t', self._threshold) - string += '{0: <16}{1}{2}\n'.format('\tScores', '=\t', self._scores) - return string - - - def get_trigger_xml(self, element): - - subelement = ET.SubElement(element, "trigger") - subelement.set("type", self._trigger_type) - subelement.set("threshold", str(self._threshold)) - - # Scores - if len(self._scores) != 0: - - scores = '' - for score in self._scores: - scores += '{0} '.format(score) - - scores.rstrip(' ') - subelement.set("scores", scores) - - class Tally(object): def __init__(self, tally_id=None, name=''): diff --git a/src/utils/openmc/trigger.py b/src/utils/openmc/trigger.py new file mode 100644 index 000000000..7a27c668d --- /dev/null +++ b/src/utils/openmc/trigger.py @@ -0,0 +1,115 @@ +from xml.etree import ElementTree as ET + +from openmc.checkvalue import * + + +class Trigger(object): + + def __init__(self, trigger_type, threshold): + + # Initialize Mesh class attributes + self.trigger_type = trigger_type + self.threshold = threshold + self._scores = [] + + + def __deepcopy__(self, memo): + + existing = memo.get(id(self)) + + # If this is first time we have tried to copy this object, create a copy + if existing is None: + + clone = type(self).__new__(type(self)) + clone._trigger_type = self._trigger_type + clone._threshold = self._threshold + + clone._scores = [] + for score in self._scores: + clone.add_score(score) + + memo[id(self)] = clone + + return clone + + # If this object has been copied before, return the first copy made + else: + return existing + + + @property + def trigger_type(self): + return self._trigger_type + + + @property + def threshold(self): + return self._threshold + + + @property + def scores(self): + return self._scores + + + @trigger_type.setter + def trigger_type(self, trigger_type): + + if not trigger_type in ['variance', 'std_dev', 'rel_err']: + msg = 'Unable to create a tally trigger with ' \ + 'type {0}'.format(trigger_type) + raise ValueError(msg) + + self._trigger_type = trigger_type + + + @threshold.setter + def threshold(self, threshold): + + if not is_float(threshold): + msg = 'Unable to set a tally trigger threshold with ' \ + 'threshold {0}'.format(threshold) + raise ValueError(msg) + + self._threshold = threshold + + + def add_score(self, score): + + if not is_string(score): + 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) + + + def __repr__(self): + + string = 'Trigger\n' + string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._trigger_type) + string += '{0: <16}{1}{2}\n'.format('\tThreshold', '=\t', self._threshold) + string += '{0: <16}{1}{2}\n'.format('\tScores', '=\t', self._scores) + return string + + + def get_trigger_xml(self, element): + + subelement = ET.SubElement(element, "trigger") + subelement.set("type", self._trigger_type) + subelement.set("threshold", str(self._threshold)) + + # Scores + if len(self._scores) != 0: + + scores = '' + for score in self._scores: + scores += '{0} '.format(score) + + scores.rstrip(' ') + subelement.set("scores", scores) +__author__ = 'wboyd'