Merge branch 'develop' into iso-lab

This commit is contained in:
Will Boyd 2015-05-25 01:14:23 -04:00
commit 42a8dc3c05
5 changed files with 874 additions and 682 deletions

View file

@ -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 *

310
src/utils/openmc/filter.py Normal file
View file

@ -0,0 +1,310 @@
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._num_bins = 0
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 can_merge(self, filter):
if not isinstance(filter, Filter):
return False
# Filters must be of the same type
elif self.type != filter.type:
return False
# Distribcell filters cannot have more than one bin
elif self.type == 'distribcell':
return False
# Mesh filters cannot have more than one bin
elif self.type == 'mesh':
return False
# Different energy bins are not mergeable
elif 'energy' in self.type:
return False
else:
return True
def merge(self, filter):
if not self.can_merge(filter):
msg = 'Unable to merge {0} with {1} filters'.format(self._type, filter._type)
raise ValueError(msg)
# Create deep copy of filter to return as merged filter
merged_filter = copy.deepcopy(self)
# Merge unique filter bins
merged_bins = list(set(self._bins + filter._bins))
merged_filter.bins = merged_bins
merged_filter.num_bins = len(merged_bins)
return merged_filter
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

331
src/utils/openmc/mesh.py Normal file
View file

@ -0,0 +1,331 @@
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 __eq__(self, mesh2):
# Check type
if self._type != mesh2._type:
return False
# Check dimension
elif self._dimension != mesh2._dimension:
return False
# Check width
elif self._width != mesh2._width:
return False
# Check lower left / upper right
elif self._lower_left != mesh2._lower_left and \
self._upper_right != mesh2._upper_right:
return False
else:
return True
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

View file

@ -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=''):
@ -746,7 +70,7 @@ class Tally(object):
clone._triggers = []
for trigger in self._triggers:
trigger.add_trigger(trigger)
clone.add_trigger(trigger)
memo[id(self)] = clone
@ -1100,6 +424,74 @@ class Tally(object):
return string
def can_merge(self, tally):
if not isinstance(tally, Tally):
return False
# Must have same estimator
if self._estimator != tally._estimator:
return False
# Must have same nuclides
if len(self._nuclides) != len(tally._nuclides):
return False
for nuclide in self._nuclides:
if not nuclide in tally._nuclides:
return False
# Must have same or mergeable filters
if len(self._filters) != len(tally._filters):
return False
# Look to see if all filters are the same, or one or more can be merged
for filter1 in self._filters:
mergeable_filter = False
for filter2 in tally._filters:
if filter1 == filter2 or filter1.can_merge(filter2):
mergeable_filter = True
break
# If no mergeable filter was found, the tallies are not mergable
if not mergeable_filter:
return False
# Tallies are mergeable if all conditional checks passed
return True
def merge(self, tally):
if not self.can_merge(tally):
msg = 'Unable to merge tally ID={0} with {1}'.format(tally.id, self.id)
raise ValueError(msg)
# Create deep copy of tally to return as merged tally
merged_tally = copy.deepcopy(self)
# Differentiate Tally with a new auto-generated Tally ID
merged_tally.id = None
# Merge filters
for i, filter1 in enumerate(merged_tally._filters):
for filter2 in tally._filters:
if filter1 != filter2 and filter1.can_merge(filter2):
merged_filter = filter1.merge(filter2)
merged_tally._filters[i] = merged_filter
break
# Add scores from second tally to merged tally
for score in tally._scores:
merged_tally.add_score(score)
# Add triggers from second tally to merged tally
for trigger in tally._triggers:
merged_tally.add_trigger(trigger)
return merged_tally
def get_tally_xml(self):
@ -1443,19 +835,62 @@ class TalliesFile(object):
self._tallies_file = ET.Element("tallies")
def add_tally(self, tally):
def add_tally(self, tally, merge=False):
if not isinstance(tally, Tally):
msg = 'Unable to add a non-Tally {0} to the TalliesFile'.format(tally)
raise ValueError(msg)
self._tallies.append(tally)
if merge:
merged = False
# Look for a tally to merge with this one
for i, tally2 in enumerate(self._tallies):
# If a mergeable tally is found
if tally2.can_merge(tally):
# Replace tally 2 with the merged tally
merged_tally = tally2.merge(tally)
self._tallies[i] = merged_tally
merged = True
break
# If not mergeable tally was found, simply add this tally
if not merged:
self._tallies.append(tally)
else:
self._tallies.append(tally)
def remove_tally(self, tally):
self._tallies.remove(tally)
def merge_tallies(self):
for i, tally1 in enumerate(self._tallies):
for j, tally2 in enumerate(self._tallies):
# Do not merge the same tally with itself
if i == j:
continue
# If the two tallies are mergeable
if tally1.can_merge(tally2):
# Replace tally 1 with the merged tally
merged_tally = tally1.merge(tally2)
self._tallies[i] = merged_tally
# Remove tally 2 since it is no longer needed
self._tallies.pop(j)
# Continue iterating from the first loop
break
def add_mesh(self, mesh):
if not isinstance(mesh, Mesh):

114
src/utils/openmc/trigger.py Normal file
View file

@ -0,0 +1,114 @@
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)