"""
Classes to represent MCNP cells.
"""
#at
# Author: Anton Travleev, anton.travleev@kit.edu
# Developed at INR, Karlsruhe Institute of Technology
#at
from .surfaces import Volume, Surface
from .material import Material # for checks only
from . import formatter
def _fill_entries(fillstr):
# assumes that fillstr is a string
vals = fillstr.split(':')
Imin = int(vals[0])
Imax, Jmin = map(int, vals[1].split())
Jmax, Kmin = map(int, vals[2].split())
array = vals[3].split()
Kmax = int(array.pop(0))
return ([Imin, Imax, Jmin, Jmax, Kmin, Kmax], array)
[docs]class CellOpts(dict):
"""A dictioary to store cell options.
This is a dictionary that allows only particular string keys. Additionally,
its string representation can be used directly in the input file within
cell card.
"""
#: tuple of valid cell option names.
VALIDKEYS = ('imp:n', 'u', 'fill', 'tmp', 'lat')
def __setitem__(self, key, value):
"""
Check additionally that key is a valid MCNP cell option
"""
k = key.lower()
if k not in self.VALIDKEYS:
raise KeyError('Wrong key ', key)
super(CellOpts, self).__setitem__(key, value)
def __str__(self):
res = ''
for (k, v) in sorted(self.items(), key=lambda x: x[0]):
if k in ['u', 'fill', 'lat', 'tmp'] and v == 0:
# do not print default values.
pass
else:
if k == 'tmp':
v *= 8.617343e-11
if hasattr(v, 'nominal_value'):
# v is of uncertanties.ufloat type. Only its nominal
# value is needed:
v = v.nominal_value
elif isinstance(v, tuple) and len(v) == 2:
v = v[0]
fmt = '{0}={1:12.6e} '
elif k == 'fill' and isinstance(v, str) and ':' in v:
# if fill array is given, represent it by multiline
# vals = v.split(':')
# Imin = int(vals[0])
# Imax, Jmin = map(int, vals[1].split())
# Jmax, Kmin = map(int, vals[2].split())
# array = vals[3].split()
# Kmax = int(array.pop(0))
([Imin, Imax, Jmin, Jmax, Kmin, Kmax], array) = _fill_entries(v)
fmt = ' fill={0}:{1} {2}:{3} {4}:{5}'.format(Imin, Imax, Jmin, Jmax, Kmin, Kmax)
# check that fill array has seferal universes. Otherwise represent it using repetition syntax
if len(set(array)) == 1:
if len(array) > 1:
fmt += ' {0} {1}R'.format(array[0], len(array)-1)
else:
fmt += ' {0}'.format(array[0])
else:
ef = '{{0:>{0}}}'.format(max( map(len, array)) + 1) # formatter for fill array entries
array = map(int, array)
for k in range(Kmin, Kmax+1):
fmt += '\nc k={0}'.format(k)
for j in range(Jmin, Jmax+1):
fmt += '\n '
for i in range(Imin, Imax+1):
fmt += ef.format(array.pop(0))
fmt += ' {0}{1}' # placeholders for k, v
k = ''
v = ''
else:
fmt = '{0}={1} '
res += fmt.format(k, v)
return res
[docs] def getvalue(self, key):
"""Returns meaningfull part of the value for options 'fill', 'u' and 'lat'.
In general, 'fill' is a (mulli-line) string that can optionally contain comments.
This method returns a list of values of this cell option.
If options were not defined, return 0.
"""
if key == 'fill':
v = self.get(key, 0)
if isinstance(v, str) and ':' in v:
([Imin, Imax, Jmin, Jmax, Kmin, Kmax], array) = _fill_entries(v)
array = map(int, array)
return [Imin, Imax, Jmin, Jmax, Kmin, Kmax] + array
else:
return int(v)
elif key == 'u':
return int(self.get(key, 0))
elif key == 'lat':
return int(self.get(key, 0))
else:
raise NotImplementedError
class Cell(object):
"""Representation of the MCNP cell card.
This is a container for cell material, density, geometry description and options,
that can generate string representation of the cell for the MCNP input file.
Constructor can take optional keyword arguments to specify cell paramters and options:
>>> c = Cell(mat=1, rho=-10., vol=(-1, 1), cmt='comment', ID=10, 'imp:n'=2.5)
>>> print c
10 1 -10.0 -1 imp:n=2.5 $ comment
Cell parameters can be changed after initialization by setting the correspondent attributes:
>>> c.ID = 5
>>> c.mat = 4
>>> c.rho = -1.
>>> c.vol = (-1, 'a')
>>> c.opt['imp:n'] = 0
>>> print c
5 4 -1.0 -a imp:n=0 $ comment
"""
def __init__(self, **kwargs):
self.__v = '{geom}'
self.__m = 0
self.__r = 1.0
self.__o = CellOpts()
self.__o['imp:n'] = 0
self.__c = 'comment'
self.__id = '{ID}'
for (n,v) in kwargs.items():
if n == 'vol':
self.vol = v
elif n == 'mat':
self.mat = v
elif n == 'rho':
self.rho = v
elif n == 'cmt':
self.cmt = v
elif n == 'ID':
self.ID = v
elif n in CellOpts.VALIDKEYS:
self.__o[n] = v
else:
raise TypeError(n, ' is an invalid keyword argument for this function.')
return
@property
def vol(self):
"""Cell geometry (cell volume).
Can be set to an integer, string, or to an instance of the Volume()
class.
The setter method accepts also a tuple of the form (sign, def), which
is transformed to an instance of the Volume() class.
>>> c1 = Cell()
>>> c2 = Cell()
>>> c1.vol = Volume(-1, ['px', 0.])
>>> c2.vol = (-1, ['px', 0.])
>>> c1.vol == c2.vol
True
"""
return self.__v
@vol.setter
def vol(self, value):
if isinstance(value, tuple):
v = Volume(*value)
else:
v = value
self.__v = v
return
@property
def mat(self):
"""Material of the cell.
Can be an integer or an instance of the Material() class.
"""
return self.__m
@mat.setter
def mat(self, value):
self.__m = value
@property
def rho(self):
"""Cell density.
"""
return self.__r
@rho.setter
def rho(self, value):
self.__r = value
@property
def opt(self):
"""Dictionary of cell options.
An instance of the CellOpt() class.
"""
return self.__o
@property
def cmt(self):
"""Cell comment.
"""
return self.__c
@cmt.setter
def cmt(self, v):
self.__c = v
@property
def ID(self):
"""Cell ID.
At initialization set to the string '{ID}'.
"""
return self.__id
@ID.setter
def ID(self, v):
self.__id = v
def card(self, formatted=True):
"""Returns a string representing the cell in the MCNP input file.
If optional argument formatted set to True (default), the returned
string can contain new-line characters delimiting the string to lines
that fit to 80-characters limit imposed by the MCNP input file syntax.
Representation of cell ID, material and volume depends on the type of
correspondent attributes.
If cell ID is a positive integer or a string, it is printed as is.
Otherwise, placeholder {ID} is printed.
If mat is an nonnegative integer or a string, it is printed
together with density rho. Otherwise, placeholder {mat} {rho} is
printed.
If vol is an instance of the Volume() class containing definitions that
utilize the Surface() class, or if it is an instance of the Surface()
class, placeholder {geom} is printed. Otherwise, the string
representation of vol is printed.
"""
# cell ID
ID = self.__id
if isinstance(ID, int) and ID > 0 or isinstance(ID, str):
cellID = str(ID)
else:
cellID = '{ID}'
# material ID and density
# Density can be of uncertainties.Variable class. Use its nominal value
rho = self.__r
if hasattr(rho, 'nominal_value'):
rho = rho.nominal_value
elif isinstance(rho, tuple) and len(rho) == 2:
rho = rho[0]
mat = self.__m
if isinstance(mat, int):
if mat != 0:
matID = '{0} {1}'.format(mat, rho)
else:
matID = '0 '
elif isinstance(mat, str):
matID = '{0} {1}'.format(mat, rho)
else:
matID = '{mat} {rho}' # placeholder for both material ID and density/concentration
# volume representation
vol = self.__v
if isinstance(vol, Volume):
ff = True # flag to print vol directly. If the volume contains definitions of the Surface type, set this flag to False
for s in vol.surfaces():
if isinstance(s, Surface):
ff = False
break
if ff:
volID = str(vol)
else:
volID = '{geom}'
elif isinstance(vol, Surface):
volID = '{geom}'
elif vol is None:
volID = '{geom}'
else:
volID = str(vol)
# compile the whole string for the cell representation:
res = '{0} {1} {2} {3}'.format(cellID, matID, volID, str(self.opt))
# add comment, if necessary
cmt = self.__c
if len(cmt) > 0:
res += ' $ ' + cmt
# wrap lines to fit to 80 character line
if formatted:
res = formatter.format_card(res)
return res
def __str__(self):
return self.card(True)