mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-27 13:45:36 -04:00
SettingsFile now uses source property based off openmc.source.Source.
This commit is contained in:
parent
efc7d2ecbf
commit
db9ac7ba2f
14 changed files with 879 additions and 253 deletions
|
|
@ -1,4 +1,6 @@
|
|||
import openmc
|
||||
from openmc.source import Source
|
||||
from openmc.stats import SpatialBox
|
||||
|
||||
###############################################################################
|
||||
# Simulation Input File Parameters
|
||||
|
|
@ -92,7 +94,7 @@ settings_file = openmc.SettingsFile()
|
|||
settings_file.batches = batches
|
||||
settings_file.inactive = inactive
|
||||
settings_file.particles = particles
|
||||
settings_file.set_source_space('box', [-4, -4, -4, 4, 4, 4])
|
||||
settings_file.source = Source(space=SpatialBox([-4, -4, -4], [4, 4, 4]))
|
||||
settings_file.export_to_xml()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import numpy as np
|
||||
|
||||
import openmc
|
||||
from openmc.source import Source
|
||||
from openmc.stats import SpatialBox
|
||||
|
||||
###############################################################################
|
||||
# Simulation Input File Parameters
|
||||
|
|
@ -117,7 +119,7 @@ settings_file = openmc.SettingsFile()
|
|||
settings_file.batches = batches
|
||||
settings_file.inactive = inactive
|
||||
settings_file.particles = particles
|
||||
settings_file.set_source_space('box', np.concatenate(outer_cube.bounding_box))
|
||||
settings_file.source = Source(space=SpatialBox(*outer_cube.bounding_box))
|
||||
settings_file.export_to_xml()
|
||||
|
||||
###############################################################################
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import openmc
|
||||
|
||||
from openmc.source import Source
|
||||
from openmc.stats import SpatialBox
|
||||
|
||||
###############################################################################
|
||||
# Simulation Input File Parameters
|
||||
|
|
@ -125,7 +126,8 @@ settings_file = openmc.SettingsFile()
|
|||
settings_file.batches = batches
|
||||
settings_file.inactive = inactive
|
||||
settings_file.particles = particles
|
||||
settings_file.set_source_space('box', [-1, -1, -1, 1, 1, 1])
|
||||
settings_file.source = Source(space=SpatialBox(
|
||||
[-1, -1, -1], [1, 1, 1]))
|
||||
settings_file.keff_trigger = {'type' : 'std_dev', 'threshold' : 5E-4}
|
||||
settings_file.trigger_active = True
|
||||
settings_file.trigger_max_batches = 100
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import openmc
|
||||
|
||||
from openmc.source import Source
|
||||
from openmc.stats import SpatialBox
|
||||
|
||||
###############################################################################
|
||||
# Simulation Input File Parameters
|
||||
|
|
@ -136,7 +137,8 @@ settings_file = openmc.SettingsFile()
|
|||
settings_file.batches = batches
|
||||
settings_file.inactive = inactive
|
||||
settings_file.particles = particles
|
||||
settings_file.set_source_space('box', [-1, -1, -1, 1, 1, 1])
|
||||
settings_file.source = Source(space=SpatialBox(
|
||||
[-1, -1, -1], [1, 1, 1]))
|
||||
settings_file.export_to_xml()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import openmc
|
||||
from openmc.source import Source
|
||||
from openmc.stats import SpatialBox
|
||||
|
||||
###############################################################################
|
||||
# Simulation Input File Parameters
|
||||
|
|
@ -125,7 +127,8 @@ settings_file = openmc.SettingsFile()
|
|||
settings_file.batches = batches
|
||||
settings_file.inactive = inactive
|
||||
settings_file.particles = particles
|
||||
settings_file.set_source_space('box', [-1, -1, -1, 1, 1, 1])
|
||||
settings_file.source = Source(space=SpatialBox(
|
||||
[-1, -1, -1], [1, 1, 1]))
|
||||
settings_file.trigger_active = True
|
||||
settings_file.trigger_max_batches = 100
|
||||
settings_file.export_to_xml()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import openmc
|
||||
from openmc.source import Source
|
||||
from openmc.stats import SpatialBox
|
||||
|
||||
###############################################################################
|
||||
# Simulation Input File Parameters
|
||||
|
|
@ -168,8 +170,8 @@ settings_file = openmc.SettingsFile()
|
|||
settings_file.batches = batches
|
||||
settings_file.inactive = inactive
|
||||
settings_file.particles = particles
|
||||
settings_file.set_source_space('box', [-0.62992, -0.62992, -1, \
|
||||
0.62992, 0.62992, 1])
|
||||
settings_file.source = Source(space=SpatialBox(
|
||||
[-0.62992, -0.62992, -1], [0.62992, 0.62992, 1]))
|
||||
settings_file.entropy_lower_left = [-0.39218, -0.39218, -1.e50]
|
||||
settings_file.entropy_upper_right = [0.39218, 0.39218, 1.e50]
|
||||
settings_file.entropy_dimension = [10, 10, 1]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import numpy as np
|
||||
|
||||
import openmc
|
||||
from openmc.stats import SpatialBox
|
||||
from openmc.source import Source
|
||||
|
||||
###############################################################################
|
||||
# Simulation Input File Parameters
|
||||
|
|
@ -84,5 +86,5 @@ settings_file = openmc.SettingsFile()
|
|||
settings_file.batches = batches
|
||||
settings_file.inactive = inactive
|
||||
settings_file.particles = particles
|
||||
settings_file.set_source_space('box', np.concatenate(cell.region.bounding_box))
|
||||
settings_file.source = Source(space=SpatialBox(*cell.region.bounding_box))
|
||||
settings_file.export_to_xml()
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import numpy as np
|
|||
from openmc.clean_xml import *
|
||||
from openmc.checkvalue import (check_type, check_length, check_value,
|
||||
check_greater_than, check_less_than)
|
||||
from openmc.source import Source
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
|
@ -36,8 +37,8 @@ class SettingsFile(object):
|
|||
type are 'variance', 'std_dev', and 'rel_err'. The threshold value
|
||||
should be a float indicating the variance, standard deviation, or
|
||||
relative error used.
|
||||
source_file : str
|
||||
Path to a source file
|
||||
source : openmc.source.Source
|
||||
Distribution of source sites in space, angle, and energy
|
||||
output : dict
|
||||
Dictionary indicating what files to output. Valid keys are 'summary',
|
||||
'cross_sections', 'tallies', and 'distribmats'. Values corresponding to
|
||||
|
|
@ -134,16 +135,7 @@ class SettingsFile(object):
|
|||
self._keff_trigger = None
|
||||
|
||||
# Source subelement
|
||||
self._source_subelement = None
|
||||
self._source_file = None
|
||||
self._source_space_type = None
|
||||
self._source_space_params = None
|
||||
self._source_angle_type = None
|
||||
self._source_angle_interpolation = None
|
||||
self._source_angle_params = None
|
||||
self._source_energy_type = None
|
||||
self._source_energy_interpolation = None
|
||||
self._source_energy_params = None
|
||||
self._source = None
|
||||
|
||||
self._confidence_intervals = None
|
||||
self._cross_sections = None
|
||||
|
|
@ -230,40 +222,8 @@ class SettingsFile(object):
|
|||
return self._keff_trigger
|
||||
|
||||
@property
|
||||
def source_file(self):
|
||||
return self._source_file
|
||||
|
||||
@property
|
||||
def source_space_type(self):
|
||||
return self._source_space_type
|
||||
|
||||
@property
|
||||
def source_space_params(self):
|
||||
return self._source_space_params
|
||||
|
||||
@property
|
||||
def source_angle_type(self):
|
||||
return self._source_angle_type
|
||||
|
||||
@property
|
||||
def source_angle_interpolation(self):
|
||||
return self._source_angle_interpolation
|
||||
|
||||
@property
|
||||
def source_angle_params(self):
|
||||
return self._source_angle_params
|
||||
|
||||
@property
|
||||
def source_energy_type(self):
|
||||
return self._source_energy_type
|
||||
|
||||
@property
|
||||
def source_energy_interpolation(self):
|
||||
return self._source_energy_interpolation
|
||||
|
||||
@property
|
||||
def source_energy_params(self):
|
||||
return self._source_energy_params
|
||||
def source(self):
|
||||
return self._source
|
||||
|
||||
@property
|
||||
def confidence_intervals(self):
|
||||
|
|
@ -478,156 +438,10 @@ class SettingsFile(object):
|
|||
|
||||
self._keff_trigger = keff_trigger
|
||||
|
||||
@source_file.setter
|
||||
def source_file(self, source_file):
|
||||
check_type('source file', source_file, basestring)
|
||||
self._source_file = source_file
|
||||
|
||||
def set_source_space(self, stype, params):
|
||||
"""Defined the spatial bounds of the external/starting source.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
stype : str
|
||||
The type of spatial distribution. Valid options are "box",
|
||||
"fission", and "point". A "box" spatial distribution has coordinates
|
||||
sampled uniformly in a parallelepiped. A "fission" spatial
|
||||
distribution samples locations from a "box" distribution but only
|
||||
locations in fissionable materials are accepted. A "point" spatial
|
||||
distribution has coordinates specified by a triplet.
|
||||
params : Iterable of float
|
||||
For a "box" or "fission" spatial distribution, ``params`` should be
|
||||
given as six real numbers, the first three of which specify the
|
||||
lower-left corner of a parallelepiped and the last three of which
|
||||
specify the upper-right corner. Source sites are sampled uniformly
|
||||
through that parallelepiped.
|
||||
|
||||
For a "point" spatial distribution, ``params`` should be given as
|
||||
three real numbers which specify the (x,y,z) location of an
|
||||
isotropic point source
|
||||
|
||||
"""
|
||||
|
||||
check_type('source space type', stype, basestring)
|
||||
check_value('source space type', stype, ['box', 'fission', 'point'])
|
||||
check_type('source space parameters', params, Iterable, Real)
|
||||
if stype in ['box', 'fission']:
|
||||
check_length('source space parameters for a '
|
||||
'box/fission distribution', params, 6)
|
||||
elif stype == 'point':
|
||||
check_length('source space parameters for a point source',
|
||||
params, 3)
|
||||
|
||||
self._source_space_type = stype
|
||||
self._source_space_params = params
|
||||
|
||||
def set_source_angle(self, stype, params=[], interp='histogram'):
|
||||
"""Defined the angular distribution of the external/starting source.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
stype : str
|
||||
The type of angular distribution. Valid options are "isotropic",
|
||||
"monodirectional", and "tabular". The angle of the particle emitted
|
||||
from a source site is isotropic if the "isotropic" option is
|
||||
given. The angle of the particle emitted from a source site is the
|
||||
direction specified in ``params`` if the "monodirectional" option is
|
||||
given. The "tabular" option produces directions with polar angles
|
||||
sampled from a tabulated distribution.
|
||||
params : Iterable of float
|
||||
For an "isotropic" angular distribution, ``params`` should not
|
||||
be specified.
|
||||
|
||||
For a "monodirectional" angular distribution, ``params`` should
|
||||
be given as three floats which specify the angular cosines
|
||||
with respect to each axis.
|
||||
|
||||
For a "tabular" angular distribution, ``parameters`` provides the
|
||||
:math:`(\mu,p)` pairs defining the tabular distribution. All
|
||||
:math:`\mu` points are given first followed by corresponding
|
||||
:math:`p` points.
|
||||
interp : { 'histogram', 'linear-linear' }
|
||||
For a "tabular" angular distribution, ``interpolation`` can be set
|
||||
to "histogram" or "linear-linear" thereby specifying how tabular
|
||||
points are to be interpolated.
|
||||
|
||||
"""
|
||||
|
||||
check_type('source angle type', stype, basestring)
|
||||
check_value('source angle type', stype,
|
||||
['isotropic', 'monodirectional', 'tabular'])
|
||||
check_type('source angle parameters', params, Iterable, Real)
|
||||
if stype == 'isotropic' and params is not None:
|
||||
msg = 'Unable to set source angle parameters since they are not ' \
|
||||
'it is not supported for isotropic type sources'
|
||||
raise ValueError(msg)
|
||||
elif stype == 'monodirectional':
|
||||
check_length('source angle parameters for a monodirectional '
|
||||
'source', params, 3)
|
||||
elif stype == 'tabular':
|
||||
check_type('source angle interpolation', interp, basestring)
|
||||
check_value('source angle interpolation', interp,
|
||||
['histogram', 'linear-linear'])
|
||||
self._source_angle_interpolation = interp
|
||||
|
||||
self._source_angle_type = stype
|
||||
self._source_angle_params = params
|
||||
|
||||
def set_source_energy(self, stype, params=[], interp='histogram'):
|
||||
"""Defined the energy distribution of the external/starting source.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
stype : str
|
||||
|
||||
The type of energy distribution. Valid options are "monoenergetic",
|
||||
"watt", "maxwell", and "tabular". The "monoenergetic" option
|
||||
produces source sites at a single energy. The "watt" option produces
|
||||
source sites whose energy is sampled from a Watt fission
|
||||
spectrum. The "maxwell" option produce source sites whose energy is
|
||||
sampled from a Maxwell fission spectrum. The "tabular" option
|
||||
produces source sites whose energy is sampled from a tabulated
|
||||
distribution.
|
||||
params : Iterable of float
|
||||
For a "monoenergetic" energy distribution, ``params`` should be
|
||||
given as the energy in MeV of the source sites.
|
||||
|
||||
For a "watt" energy distribution, ``params`` should be given as two
|
||||
real numbers :math:`a` and :math:`b` that parameterize the
|
||||
distribution :math:`p(E) dE = c e^{-E/a} \sinh \sqrt{b \, E} dE`.
|
||||
|
||||
For a "maxwell" energy distribution, ``params`` should be given as
|
||||
one real number :math:`a` that parameterizes the distribution
|
||||
:math:`p(E) dE = c E e^{-E/a} dE`.
|
||||
|
||||
For a "tabular" energy distribution, ``parameters`` provides the
|
||||
:math:`(E,p)` pairs defining the tabular distribution. All :math:`E`
|
||||
points are given first followed by corresponding :math:`p` points.
|
||||
interp : { 'histogram', 'linear-linear' }
|
||||
For a "tabular" energy distribution, ``interpolation`` can be set
|
||||
to "histogram" or "linear-linear" thereby specifying how tabular
|
||||
points are to be interpolated.
|
||||
|
||||
"""
|
||||
|
||||
check_type('source energy type', stype, basestring)
|
||||
check_value('source energy type', stype,
|
||||
['monoenergetic', 'watt', 'maxwell', 'tabular'])
|
||||
check_type('source energy parameters', params, Iterable, Real)
|
||||
if stype in ['monoenergetic', 'maxwell']:
|
||||
check_length('source energy parameters for a monoenergetic '
|
||||
'or Maxwell source', params, 1)
|
||||
elif stype == 'watt':
|
||||
check_length('source energy parameters for a Watt source',
|
||||
params, 2)
|
||||
elif stype == 'tabular':
|
||||
check_type('source energy interpolation', interp, basestring)
|
||||
check_value('source energy interpolation', interp,
|
||||
['histogram', 'linear-linear'])
|
||||
self._source_energy_interpolation = interp
|
||||
|
||||
self._source_energy_type = stype
|
||||
self._source_energy_params = params
|
||||
@source.setter
|
||||
def source(self, source):
|
||||
check_type('source distribution', source, Source)
|
||||
self._source = source
|
||||
|
||||
@output.setter
|
||||
def output(self, output):
|
||||
|
|
@ -966,51 +780,8 @@ class SettingsFile(object):
|
|||
subelement.text = str(self._keff_trigger[key]).lower()
|
||||
|
||||
def _create_source_subelement(self):
|
||||
self._create_source_space_subelement()
|
||||
self._create_source_energy_subelement()
|
||||
self._create_source_angle_subelement()
|
||||
|
||||
def _create_source_space_subelement(self):
|
||||
if self._source_space_params is not None:
|
||||
if self._source_subelement is None:
|
||||
self._source_subelement = ET.SubElement(self._settings_file,
|
||||
"source")
|
||||
|
||||
element = ET.SubElement(self._source_subelement, "space")
|
||||
element.set("type", self._source_space_type)
|
||||
|
||||
subelement = ET.SubElement(element, "parameters")
|
||||
subelement.text = ' '.join(map(str, self._source_space_params))
|
||||
|
||||
def _create_source_angle_subelement(self):
|
||||
if self._source_angle_params is not None:
|
||||
if self._source_subelement is None:
|
||||
self._source_subelement = ET.SubElement(self._settings_file,
|
||||
"source")
|
||||
|
||||
element = ET.SubElement(self._source_subelement, "angle")
|
||||
element.set("type", self._source_angle_type)
|
||||
|
||||
if self.source_angle_interpolation is not None:
|
||||
element.set("interpolation", self.source_angle_interpolation)
|
||||
|
||||
subelement = ET.SubElement(element, "parameters")
|
||||
subelement.text = ' '.join(map(str, self._source_angle_params))
|
||||
|
||||
def _create_source_energy_subelement(self):
|
||||
if self._source_energy_params is not None:
|
||||
if self._source_subelement is None:
|
||||
self._source_subelement = ET.SubElement(self._settings_file,
|
||||
"source")
|
||||
|
||||
element = ET.SubElement(self._source_subelement, "energy")
|
||||
element.set("type", self._source_energy_type)
|
||||
|
||||
if self.source_energy_interpolation is not None:
|
||||
element.set("interpolation", self.source_energy_interpolation)
|
||||
|
||||
subelement = ET.SubElement(element, "parameters")
|
||||
subelement.text = ' '.join(map(str, self._source_energy_params))
|
||||
if self.source is not None:
|
||||
self._settings_file.append(self.source.to_xml())
|
||||
|
||||
def _create_output_subelement(self):
|
||||
if self._output is not None:
|
||||
|
|
|
|||
101
openmc/source.py
Normal file
101
openmc/source.py
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
import sys
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
from openmc.stats.univariate import Univariate
|
||||
from openmc.stats.multivariate import UnitSphere, Spatial
|
||||
import openmc.checkvalue as cv
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
class Source(object):
|
||||
"""Distribution of phase space coordinates for source sites.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
space : openmc.stats.Spatial, optional
|
||||
Spatial distribution of source sites
|
||||
angle : openmc.stats.UnitSphere, optional
|
||||
Angular distribution of source sites
|
||||
energy : openmc.stats.Univariate, optional
|
||||
Energy distribution of source sites
|
||||
filename : str, optional
|
||||
Source file from which sites should be sampled
|
||||
|
||||
Attributes
|
||||
----------
|
||||
space : openmc.stats.Spatial or None
|
||||
Spatial distribution of source sites
|
||||
angle : openmc.stats.UnitSphere or None
|
||||
Angular distribution of source sites
|
||||
energy : openmc.stats.Univariate or None
|
||||
Energy distribution of source sites
|
||||
file : str or None
|
||||
Source file from which sites should be sampled
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, space=None, angle=None, energy=None, filename=None):
|
||||
self._space = None
|
||||
self._angle = None
|
||||
self._energy = None
|
||||
self._probability = None
|
||||
self._file = None
|
||||
|
||||
if space is not None:
|
||||
self.space = space
|
||||
if angle is not None:
|
||||
self.angle = angle
|
||||
if energy is not None:
|
||||
self.energy = energy
|
||||
if filename is not None:
|
||||
self.file = filename
|
||||
|
||||
@property
|
||||
def file(self):
|
||||
return self._file
|
||||
|
||||
@property
|
||||
def space(self):
|
||||
return self._space
|
||||
|
||||
@property
|
||||
def angle(self):
|
||||
return self._angle
|
||||
|
||||
@property
|
||||
def energy(self):
|
||||
return self._energy
|
||||
|
||||
@file.setter
|
||||
def file(self, filename):
|
||||
cv.check_type('source file', filename, basestring)
|
||||
self._file = filename
|
||||
|
||||
@space.setter
|
||||
def space(self, space):
|
||||
cv.check_type('spatial distribution', space, Spatial)
|
||||
self._space = space
|
||||
|
||||
@angle.setter
|
||||
def angle(self, angle):
|
||||
cv.check_type('angular distribution', angle, UnitSphere)
|
||||
self._angle = angle
|
||||
|
||||
@energy.setter
|
||||
def energy(self, energy):
|
||||
cv.check_type('energy distribution', energy, Univariate)
|
||||
self._energy = energy
|
||||
|
||||
def to_xml(self):
|
||||
element = ET.Element("source")
|
||||
if self.file is not None:
|
||||
element.set("file", self.file)
|
||||
if self.space is not None:
|
||||
element.append(self.space.to_xml())
|
||||
if self.angle is not None:
|
||||
element.append(self.angle.to_xml())
|
||||
if self.energy is not None:
|
||||
element.append(self.energy.to_xml())
|
||||
return element
|
||||
2
openmc/stats/__init__.py
Normal file
2
openmc/stats/__init__.py
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
from openmc.stats.univariate import *
|
||||
from openmc.stats.multivariate import *
|
||||
409
openmc/stats/multivariate.py
Normal file
409
openmc/stats/multivariate.py
Normal file
|
|
@ -0,0 +1,409 @@
|
|||
from abc import ABCMeta, abstractmethod
|
||||
from collections import Iterable
|
||||
from math import pi
|
||||
from numbers import Real
|
||||
import sys
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
import numpy as np
|
||||
from numpy.linalg import norm
|
||||
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.stats.univariate import Univariate, Uniform
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
class UnitSphere(object):
|
||||
"""Distribution of points on the unit sphere.
|
||||
|
||||
This abstract class is used for angular distributions, since a direction is
|
||||
represented as a unit vector (i.e., vector on the unit sphere).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Name of the distribution
|
||||
reference_uvw : Iterable of Real
|
||||
Direction from which polar angle is measured
|
||||
|
||||
Attributes
|
||||
----------
|
||||
name : str
|
||||
Name of the distribution
|
||||
reference_uvw : Iterable of Real
|
||||
Direction from which polar angle is measured
|
||||
|
||||
"""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
def __init__(self, name, reference_uvw=None):
|
||||
self.name = name
|
||||
self._reference_uvw = None
|
||||
if reference_uvw is not None:
|
||||
self.reference_uvw = reference_uvw
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def reference_uvw(self):
|
||||
return self._reference_uvw
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
cv.check_type('name', name, basestring)
|
||||
self._name = name
|
||||
|
||||
@reference_uvw.setter
|
||||
def reference_uvw(self, uvw):
|
||||
cv.check_type('reference direction', uvw, Iterable, Real)
|
||||
uvw = np.asarray(uvw)
|
||||
self._reference_uvw = uvw/norm(uvw)
|
||||
|
||||
@abstractmethod
|
||||
def to_xml(self):
|
||||
return ''
|
||||
|
||||
|
||||
class PolarAzimuthal(UnitSphere):
|
||||
"""Angular distribution represented by polar and azimuthal angles
|
||||
|
||||
This distribution allows one to specify the distribution of the cosine of
|
||||
the polar angle and the azimuthal angle independently of once another.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mu : openmc.stats.Univariate
|
||||
Distribution of the cosine of the polar angle
|
||||
phi : openmc.stats.Univariate
|
||||
Distribution of the azimuthal angle
|
||||
name : str, optional
|
||||
Name of the distribution. Defaults to 'angle'.
|
||||
reference_uvw : Iterable of Real
|
||||
Direction from which polar angle is measured. Defaults to the positive
|
||||
z-direction.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
mu : openmc.stats.Univariate
|
||||
Distribution of the cosine of the polar angle
|
||||
phi : openmc.stats.Univariate
|
||||
Distribution of the azimuthal angle
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, mu=None, phi=None, name='angle',reference_uvw=[0., 0., 1.]):
|
||||
super(PolarAzimuthal, self).__init__(name, reference_uvw)
|
||||
if mu is not None:
|
||||
self.mu = mu
|
||||
else:
|
||||
self.mu = Uniform('mu', -1., 1.)
|
||||
|
||||
if phi is not None:
|
||||
self.phi = phi
|
||||
else:
|
||||
self.phi = Uniform('phi', 0., 2*pi)
|
||||
|
||||
@property
|
||||
def mu(self):
|
||||
return self._mu
|
||||
|
||||
@property
|
||||
def phi(self):
|
||||
return self._phi
|
||||
|
||||
@mu.setter
|
||||
def mu(self, mu):
|
||||
cv.check_type('cosine of polar angle', mu, Univariate)
|
||||
self._mu = mu
|
||||
|
||||
@phi.setter
|
||||
def phi(self, phi):
|
||||
cv.check_type('azimuthal angle', phi, Univariate)
|
||||
self._phi = phi
|
||||
|
||||
def to_xml(self):
|
||||
element = ET.Element(self.name)
|
||||
element.set("type", "mu-phi")
|
||||
if self.reference_uvw is not None:
|
||||
element.set("reference_uvw", ' '.join(map(str, self.reference_uvw)))
|
||||
element.append(self.mu.to_xml())
|
||||
element.append(self.phi.to_xml())
|
||||
return element
|
||||
|
||||
|
||||
class Isotropic(UnitSphere):
|
||||
"""Isotropic angular distribution.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str, optional
|
||||
Name of the distribution. Defaults to 'angle'.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, name='angle'):
|
||||
super(Isotropic, self).__init__(name)
|
||||
|
||||
def to_xml(self):
|
||||
element = ET.Element(self.name)
|
||||
element.set("type", "isotropic")
|
||||
return element
|
||||
|
||||
|
||||
class Monodirectional(UnitSphere):
|
||||
"""Monodirectional angular distribution.
|
||||
|
||||
A monodirectional angular distribution is one for which the polar and
|
||||
azimuthal angles are always the same. It is completely specified by the
|
||||
reference direction vector.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str, optional
|
||||
Name of the distribution. Defaults to 'angle'.
|
||||
reference_uvw : Iterable of Real
|
||||
Direction from which polar angle is measured. Defaults to the positive
|
||||
x-direction.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, name='angle', reference_uvw=[1., 0., 0.]):
|
||||
super(Monodirectional, self).__init__(name, reference_uvw)
|
||||
|
||||
def to_xml(self):
|
||||
element = ET.Element(self.name)
|
||||
element.set("type", "monodirectional")
|
||||
if self.reference_uvw is not None:
|
||||
element.set("reference_uvw", ' '.join(map(str, self.reference_uvw)))
|
||||
return element
|
||||
|
||||
|
||||
class Spatial(object):
|
||||
"""Distribution of locations in three-dimensional Euclidean space.
|
||||
|
||||
Classes derived from this abstract class can be used for spatial
|
||||
distributions of source sites.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Name of the distribution
|
||||
|
||||
Attributes
|
||||
----------
|
||||
name : str
|
||||
Name of the distribution
|
||||
|
||||
"""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
cv.check_type('name', name, basestring)
|
||||
self._name = name
|
||||
|
||||
@abstractmethod
|
||||
def to_xml(self):
|
||||
return ''
|
||||
|
||||
|
||||
class SpatialIndependent(Spatial):
|
||||
"""Spatial distribution with independent x, y, and z distributions.
|
||||
|
||||
This distribution allows one to specify a coordinates whose x-, y-, and z-
|
||||
components are sampled independently from one another.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : openmc.stats.Univariate
|
||||
Distribution of x-coordinates
|
||||
y : openmc.stats.Univariate
|
||||
Distribution of y-coordinates
|
||||
z : openmc.stats.Univariate
|
||||
Distribution of z-coordinates
|
||||
name : str
|
||||
Name of the distribution
|
||||
|
||||
Attributes
|
||||
----------
|
||||
x : openmc.stats.Univariate
|
||||
Distribution of x-coordinates
|
||||
y : openmc.stats.Univariate
|
||||
Distribution of y-coordinates
|
||||
z : openmc.stats.Univariate
|
||||
Distribution of z-coordinates
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, x, y, z, name='space'):
|
||||
super(SpatialIndependent, self).__init__(name)
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.z = z
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
return self._x
|
||||
|
||||
@property
|
||||
def y(self):
|
||||
return self._y
|
||||
|
||||
@property
|
||||
def z(self):
|
||||
return self._z
|
||||
|
||||
@x.setter
|
||||
def x(self, x):
|
||||
cv.check_type('x coordinate', x, Univariate)
|
||||
self._x = x
|
||||
|
||||
@y.setter
|
||||
def y(self, y):
|
||||
cv.check_type('y coordinate', y, Univariate)
|
||||
self._y = y
|
||||
|
||||
@x.setter
|
||||
def z(self, z):
|
||||
cv.check_type('z coordinate', z, Univariate)
|
||||
self._z = z
|
||||
|
||||
def to_xml(self):
|
||||
element = ET.Element(self.name)
|
||||
element.set("type", "independent")
|
||||
element.append(self.x.to_xml())
|
||||
element.append(self.y.to_xml())
|
||||
element.append(self.z.to_xml())
|
||||
return element
|
||||
|
||||
|
||||
class SpatialBox(Spatial):
|
||||
"""Uniform distribution of coordinates in a rectangular cuboid.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
lower_left : Iterable of Real
|
||||
Lower-left coordinates of cuboid
|
||||
upper_right : Iterable of Real
|
||||
Upper-right coordinates of cuboid
|
||||
name : str, optional
|
||||
Name of the distribution
|
||||
only_fissionable : bool, optional
|
||||
Whether spatial sites should only be accepted if they occur in
|
||||
fissionable materials
|
||||
|
||||
Attributes
|
||||
----------
|
||||
lower_left : Iterable of Real
|
||||
Lower-left coordinates of cuboid
|
||||
upper_right : Iterable of Real
|
||||
Upper-right coordinates of cuboid
|
||||
only_fissionable : bool, optional
|
||||
Whether spatial sites should only be accepted if they occur in
|
||||
fissionable materials
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, lower_left, upper_right, name='space', only_fissionable=False):
|
||||
super(SpatialBox, self).__init__(name)
|
||||
self.lower_left = lower_left
|
||||
self.upper_right = upper_right
|
||||
self.only_fissionable = only_fissionable
|
||||
|
||||
@property
|
||||
def lower_left(self):
|
||||
return self._lower_left
|
||||
|
||||
@property
|
||||
def upper_right(self):
|
||||
return self._upper_right
|
||||
|
||||
@property
|
||||
def only_fissionable(self):
|
||||
return self._only_fissionable
|
||||
|
||||
@lower_left.setter
|
||||
def lower_left(self, lower_left):
|
||||
cv.check_type('lower left coordinate', lower_left, Iterable, Real)
|
||||
cv.check_length('lower left coordinate', lower_left, 3)
|
||||
self._lower_left = lower_left
|
||||
|
||||
@upper_right.setter
|
||||
def upper_right(self, upper_right):
|
||||
cv.check_type('upper right coordinate', upper_right, Iterable, Real)
|
||||
cv.check_length('upper right coordinate', upper_right, 3)
|
||||
self._upper_right = upper_right
|
||||
|
||||
@only_fissionable.setter
|
||||
def only_fissionable(self, only_fissionable):
|
||||
cv.check_type('only fissionable', only_fissionable, bool)
|
||||
self._only_fissionable = only_fissionable
|
||||
|
||||
def to_xml(self):
|
||||
element = ET.Element(self.name)
|
||||
if self.only_fissionable:
|
||||
element.set("type", "fission")
|
||||
else:
|
||||
element.set("type", "box")
|
||||
params = ET.SubElement(element, "parameters")
|
||||
params.text = ' '.join(map(str, self.lower_left)) + ' ' + \
|
||||
' '.join(map(str, self.upper_right))
|
||||
return element
|
||||
|
||||
|
||||
class SpatialPoint(Spatial):
|
||||
"""Delta function in three dimensions.
|
||||
|
||||
This spatial distribution can be used for a point source where sites are
|
||||
emitted at a specific location given by its Cartesian coordinates.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
xyz : Iterable of Real
|
||||
Cartesian coordinates of location
|
||||
name : str, optional
|
||||
Name of the distribution
|
||||
|
||||
Attributes
|
||||
----------
|
||||
xyz : Iterable of Real
|
||||
Cartesian coordinates of location
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, xyz, name='space'):
|
||||
super(SpatialPoint, self).__init__(name)
|
||||
self.xyz = xyz
|
||||
|
||||
@property
|
||||
def xyz(self):
|
||||
return self._xyz
|
||||
|
||||
@xyz.setter
|
||||
def xyz(self, xyz):
|
||||
cv.check_type('coordinate', xyz, Iterable, Real)
|
||||
cv.check_length('coordinate', xyz, 3)
|
||||
self._xyz = xyz
|
||||
|
||||
def to_xml(self):
|
||||
element = ET.Element(self.name)
|
||||
element.set("type", "point")
|
||||
params = ET.SubElement(element, "parameters")
|
||||
params.text = ' '.join(map(str, self.xyz))
|
||||
return element
|
||||
325
openmc/stats/univariate.py
Normal file
325
openmc/stats/univariate.py
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
from abc import ABCMeta, abstractmethod
|
||||
from collections import Iterable
|
||||
from numbers import Real
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
import openmc.checkvalue as cv
|
||||
|
||||
|
||||
class Univariate(object):
|
||||
"""Probability distribution of a single random variable.
|
||||
|
||||
The Univariate class is an abstract class that can be derived to implement a
|
||||
specific probability distribution.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Name of the distribution
|
||||
|
||||
Attributes
|
||||
----------
|
||||
name : str
|
||||
Name of the distributions
|
||||
|
||||
"""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
cv.check_type('name', name, basestring)
|
||||
self._name = name
|
||||
|
||||
@abstractmethod
|
||||
def to_xml(self):
|
||||
return ''
|
||||
|
||||
|
||||
class Discrete(Univariate):
|
||||
"""Distribution characterized by a probability mass function.
|
||||
|
||||
The Discrete distribution assigns probability values to discrete values of a
|
||||
random variable, rather than expressing the distribution as a continuous
|
||||
random variable.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : Iterable of Real
|
||||
Values of the random variable
|
||||
p : Iterable of Real
|
||||
Discrete probability for each value
|
||||
|
||||
Attributes
|
||||
----------
|
||||
x : Iterable of Real
|
||||
Values of the random variable
|
||||
p : Iterable of Real
|
||||
Discrete probability for each value
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, name, x, p):
|
||||
super(Discrete, self).__init__(name)
|
||||
self.x = x
|
||||
self.p = p
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
return self._x
|
||||
|
||||
@property
|
||||
def p(self):
|
||||
return self._p
|
||||
|
||||
@x.setter
|
||||
def x(self, x):
|
||||
cv.check_type('discrete values', x, Iterable, Real)
|
||||
self._x = x
|
||||
|
||||
@p.setter
|
||||
def p(self, p):
|
||||
cv.check_type('discrete probabilities', p, Iterable, Real)
|
||||
for pk in p:
|
||||
cv.check_greater_than('discrete probability', pk, 0.0, True)
|
||||
self._p = p
|
||||
|
||||
def to_xml(self):
|
||||
element = ET.Element(self.name)
|
||||
element.set("type", "discrete")
|
||||
|
||||
params = ET.SubElement(element, "parameters")
|
||||
params.text = ' '.join(map(str, self.x)) + ' ' + ' '.join(map(str, self.p))
|
||||
|
||||
return element
|
||||
|
||||
|
||||
class Uniform(Univariate):
|
||||
"""Distribution with constant probability over a finite interval [a,b]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
a : float, optional
|
||||
Lower bound of the sampling interval. Defaults to zero.
|
||||
b : float, optional
|
||||
Upper bound of the sampling interval. Defaults to unity.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
a : float
|
||||
Lower bound of the sampling interval
|
||||
b : float
|
||||
Upper bound of the sampling interval
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, name, a=0.0, b=1.0):
|
||||
super(Uniform, self).__init__(name)
|
||||
self.a = a
|
||||
self.b = b
|
||||
|
||||
@property
|
||||
def a(self):
|
||||
return self._a
|
||||
|
||||
@property
|
||||
def b(self):
|
||||
return self._b
|
||||
|
||||
@a.setter
|
||||
def a(self, a):
|
||||
cv.check_type('Uniform a', a, Real)
|
||||
self._a = a
|
||||
|
||||
@b.setter
|
||||
def b(self, b):
|
||||
cv.check_type('Uniform b', b, Real)
|
||||
self._b = b
|
||||
|
||||
def to_xml(self):
|
||||
element = ET.Element(self.name)
|
||||
element.set("type", "uniform")
|
||||
element.set("parameters", '{} {}'.format(self.a, self.b))
|
||||
return element
|
||||
|
||||
|
||||
class Maxwell(Univariate):
|
||||
"""Maxwellian distribution in energy.
|
||||
|
||||
The Maxwellian distribution in energy is characterized by a single parameter
|
||||
:math:`\theta` and has a density function :math:`p(E) dE = c E e^{-E/\theta}
|
||||
dE`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
theta : float
|
||||
Effective temperature for distribution
|
||||
|
||||
Attributes
|
||||
----------
|
||||
theta : float
|
||||
Effective temperature for distribution
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, theta, name='energy'):
|
||||
super(Maxwell, self).__init__(name)
|
||||
self.theta = theta
|
||||
|
||||
@property
|
||||
def theta(self):
|
||||
return self._theta
|
||||
|
||||
@theta.setter
|
||||
def theta(self, theta):
|
||||
cv.check_type('Maxwell temperature', theta, Real)
|
||||
cv.check_greater_than('Maxwell temperature', theta, 0.0)
|
||||
self._theta = theta
|
||||
|
||||
def to_xml(self):
|
||||
element = ET.Element(self.name)
|
||||
element.set("type", "uniform")
|
||||
element.set("parameters", str(self.theta))
|
||||
return element
|
||||
|
||||
|
||||
class Watt(Univariate):
|
||||
"""Watt fission energy spectrum.
|
||||
|
||||
The Watt fission energy spectrum is characterized by two parameters
|
||||
:math:`a` and :math:`b` and has density function :math:`p(E) dE = c e^{-E/a}
|
||||
\sinh \sqrt{b \, E} dE`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
a : float
|
||||
First parameter of distribution
|
||||
b : float
|
||||
Second parameter of distribution
|
||||
name : str, optional
|
||||
Name of the distribution. Defaults to 'energy'.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
a : float
|
||||
First parameter of distribution
|
||||
b : float
|
||||
Second parameter of distribution
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, a, b, name='energy'):
|
||||
super(Watt, self).__init__(name)
|
||||
self.a = a
|
||||
self.b = b
|
||||
|
||||
@property
|
||||
def a(self):
|
||||
return self._a
|
||||
|
||||
@property
|
||||
def b(self):
|
||||
return self._b
|
||||
|
||||
@a.setter
|
||||
def a(self, a):
|
||||
cv.check_type('Watt a', a, Real)
|
||||
cv.check_greater_than('Watt a', a, 0.0)
|
||||
self._a = a
|
||||
|
||||
@b.setter
|
||||
def b(self, b):
|
||||
cv.check_type('Watt b', b, Real)
|
||||
cv.check_greater_than('Watt b', b, 0.0)
|
||||
self._b = b
|
||||
|
||||
def to_xml(self):
|
||||
element = ET.Element(self.name)
|
||||
element.set("type", "watt")
|
||||
element.set("parameters", '{} {}'.format(self.a, self.b))
|
||||
return element
|
||||
|
||||
|
||||
class Tabular(Univariate):
|
||||
"""Piecewise continuous probability distribution.
|
||||
|
||||
This class is used to represent a probability distribution whose density
|
||||
function is tabulated at specific values and is either histogram or linearly
|
||||
interpolated between points.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Name of the distribution
|
||||
x : Iterable of Real
|
||||
Tabulated values of the random variable
|
||||
p : Iterable of Real
|
||||
Tabulated probabilities
|
||||
interpolation : {'histogram', 'linear-linear'}, optional
|
||||
Indicate whether the density function is constant between tabulated
|
||||
points or linearly-interpolated.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
x : Iterable of Real
|
||||
Tabulated values of the random variable
|
||||
p : Iterable of Real
|
||||
Tabulated probabilities
|
||||
interpolation : {'histogram', 'linear-linear'}, optional
|
||||
Indicate whether the density function is constant between tabulated
|
||||
points or linearly-interpolated.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, name, x, p, interpolation='linear-linear'):
|
||||
super(Tabular, self).__init__(name)
|
||||
self.x = x
|
||||
self.p = p
|
||||
self.interpolation = interpolation
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
return self._x
|
||||
|
||||
@property
|
||||
def p(self):
|
||||
return self._p
|
||||
|
||||
@property
|
||||
def interpolation(self):
|
||||
return self._interpolation
|
||||
|
||||
@x.setter
|
||||
def x(self, x):
|
||||
cv.check_type('tabulated values', x, Iterable, Real)
|
||||
self._x = x
|
||||
|
||||
@p.setter
|
||||
def p(self, p):
|
||||
cv.check_type('tabulated probabilities', p, Iterable, Real)
|
||||
for pk in p:
|
||||
cv.check_greater_than('tabulated probability', pk, 0.0, True)
|
||||
self._p = p
|
||||
|
||||
@interpolation.setter
|
||||
def interpolation(self, interpolation):
|
||||
cv.check_value('interpolation', interpolation,
|
||||
['linear-linear', 'histogram'])
|
||||
self._interpolation = interpolation
|
||||
|
||||
def to_xml(self):
|
||||
element = ET.Element(self.name)
|
||||
element.set("type", "tabular")
|
||||
element.set("interpolation", self.interpolation)
|
||||
|
||||
params = ET.SubElement(element, "parameters")
|
||||
params.text = ' '.join(map(str, self.x)) + ' ' + ' '.join(map(str, self.p))
|
||||
|
||||
return element
|
||||
2
setup.py
2
setup.py
|
|
@ -11,7 +11,7 @@ except ImportError:
|
|||
|
||||
kwargs = {'name': 'openmc',
|
||||
'version': '0.7.1',
|
||||
'packages': ['openmc', 'openmc.mgxs'],
|
||||
'packages': ['openmc', 'openmc.mgxs', 'openmc.stats'],
|
||||
'scripts': glob.glob('scripts/openmc-*'),
|
||||
|
||||
# Metadata
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import openmc
|
||||
from openmc.source import Source
|
||||
from openmc.stats import SpatialBox
|
||||
|
||||
|
||||
class InputSet(object):
|
||||
|
|
@ -558,7 +560,8 @@ class InputSet(object):
|
|||
self.settings.batches = 10
|
||||
self.settings.inactive = 5
|
||||
self.settings.particles = 100
|
||||
self.settings.set_source_space('box', (-160, -160, -183, 160, 160, 183))
|
||||
self.settings.source = Source(space=SpatialBox(
|
||||
[-160, -160, -183], [160, 160, 183]))
|
||||
|
||||
def build_defualt_plots(self):
|
||||
plot = openmc.Plot()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue