mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 06:05:58 -04:00
Fixed merge conflicts with develop
This commit is contained in:
commit
b9a81df6bd
25 changed files with 900 additions and 679 deletions
10
docs/source/_static/theme_overrides.css
Normal file
10
docs/source/_static/theme_overrides.css
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/* override table width restrictions */
|
||||
.wy-table-responsive table td, .wy-table-responsive table th {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.wy-table-responsive {
|
||||
margin-bottom: 24px;
|
||||
max-width: 100%;
|
||||
overflow: visible;
|
||||
}
|
||||
|
|
@ -152,7 +152,10 @@ html_title = "OpenMC Documentation"
|
|||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#html_static_path = ['_static']
|
||||
html_static_path = ['_static']
|
||||
|
||||
def setup(app):
|
||||
app.add_stylesheet('theme_overrides.css')
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
|
|
|
|||
|
|
@ -1475,114 +1475,203 @@ The ``<tally>`` element accepts the following sub-elements:
|
|||
*Default*: ``tracklength`` but will revert to ``analog`` if necessary.
|
||||
|
||||
:scores:
|
||||
A space-separated list of the desired responses to be accumulated. Accepted
|
||||
options are "flux", "total", "scatter", "absorption", "fission",
|
||||
"nu-fission", "delayed-nu-fission", "kappa-fission", "nu-scatter",
|
||||
"scatter-N", "scatter-PN", "scatter-YN", "nu-scatter-N", "nu-scatter-PN",
|
||||
"nu-scatter-YN", "flux-YN", "total-YN", "current", "inverse-velocity" and
|
||||
"events". These correspond to the following physical quantities:
|
||||
A space-separated list of the desired responses to be accumulated. The accepted
|
||||
options are listed in the following tables:
|
||||
|
||||
:flux:
|
||||
Total flux in particle-cm per source particle.
|
||||
.. table:: **Flux scores: units are particle-cm per source particle.**
|
||||
|
||||
.. note::
|
||||
The ``analog`` estimator is actually identical to the ``collision``
|
||||
estimator for the flux score.
|
||||
+----------------------+---------------------------------------------------+
|
||||
|Score | Description |
|
||||
+======================+===================================================+
|
||||
|flux |Total flux. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|flux-YN |Spherical harmonic expansion of the direction of |
|
||||
| |motion :math:`\left(\Omega\right)` of the total |
|
||||
| |flux. This score will tally all of the harmonic |
|
||||
| |moments of order 0 to N. N must be between 0 and |
|
||||
| |10. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|
||||
:total:
|
||||
Total reaction rate in reactions per source particle.
|
||||
.. table:: **Reaction scores: units are reactions per source particle.**
|
||||
|
||||
:scatter:
|
||||
Total scattering rate. Can also be identified with the ``scatter-0``
|
||||
response type. Units are reactions per source particle.
|
||||
+----------------------+---------------------------------------------------+
|
||||
|Score | Description |
|
||||
+======================+===================================================+
|
||||
|absorption |Total absorption rate. This accounts for all |
|
||||
| |reactions which do not produce secondary neutrons. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|elastic |Elastic scattering reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|fission |Total fission reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|scatter |Total scattering rate. Can also be identified with |
|
||||
| |the "scatter-0" response type. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|scatter-N |Tally the N\ :sup:`th` \ scattering moment, where N|
|
||||
| |is the Legendre expansion order of the change in |
|
||||
| |particle angle :math:`\left(\mu\right)`. N must be |
|
||||
| |between 0 and 10. As an example, tallying the 2\ |
|
||||
| |:sup:`nd` \ scattering moment would be specified as|
|
||||
| |``<scores>scatter-2</scores>``. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|scatter-PN |Tally all of the scattering moments from order 0 to|
|
||||
| |N, where N is the Legendre expansion order of the |
|
||||
| |change in particle angle |
|
||||
| |:math:`\left(\mu\right)`. That is, "scatter-P1" is |
|
||||
| |equivalent to requesting tallies of "scatter-0" and|
|
||||
| |"scatter-1". Like for "scatter-N", N must be |
|
||||
| |between 0 and 10. As an example, tallying up to the|
|
||||
| |2\ :sup:`nd` \ scattering moment would be specified|
|
||||
| |as ``<scores> scatter-P2 </scores>``. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|scatter-YN |"scatter-YN" is similar to "scatter-PN" except an |
|
||||
| |additional expansion is performed for the incoming |
|
||||
| |particle direction :math:`\left(\Omega\right)` |
|
||||
| |using the real spherical harmonics. This is useful|
|
||||
| |for performing angular flux moment weighting of the|
|
||||
| |scattering moments. Like "scatter-PN", "scatter-YN"|
|
||||
| |will tally all of the moments from order 0 to N; N |
|
||||
| |again must be between 0 and 10. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|total |Total reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|total-YN |The total reaction rate expanded via spherical |
|
||||
| |harmonics about the direction of motion of the |
|
||||
| |neutron, :math:`\Omega`. This score will tally all |
|
||||
| |of the harmonic moments of order 0 to N. N must be|
|
||||
| |between 0 and 10. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,2nd) |(n,2nd) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,2n) |(n,2n) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,3n) |(n,3n) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,na) |(n,n\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,n3a) |(n,n3\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,2na) |(n,2n\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,3na) |(n,3n\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,np) |(n,np) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,n2a) |(n,n2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,2n2a) |(n,2n2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,nd) |(n,nd) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,nt) |(n,nt) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,nHe-3) |(n,n\ :sup:`3`\ He) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,nd2a) |(n,nd2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,nt2a) |(n,nt2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,4n) |(n,4n) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,2np) |(n,2np) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,3np) |(n,3np) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,n2p) |(n,n2p) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,n*X*) |Level inelastic scattering reaction rate. The *X* |
|
||||
| |indicates what which inelastic level, e.g., (n,n3) |
|
||||
| |is third-level inelastic scattering. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,nc) |Continuum level inelastic scattering reaction rate.|
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,gamma) |Radiative capture reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,p) |(n,p) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,d) |(n,d) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,t) |(n,t) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,3He) |(n,\ :sup:`3`\ He) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,a) |(n,\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,2a) |(n,2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,3a) |(n,3\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,2p) |(n,2p) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,pa) |(n,p\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,t2a) |(n,t2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,d2a) |(n,d2\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,pd) |(n,pd) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,pt) |(n,pt) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|(n,da) |(n,d\ :math:`\alpha`\ ) reaction rate. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|*Arbitrary integer* |An arbitrary integer is interpreted to mean the |
|
||||
| |reaction rate for a reaction with a given ENDF MT |
|
||||
| |number. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|
||||
:absorption:
|
||||
Total absorption rate. This accounts for all reactions which do not
|
||||
produce secondary neutrons. Units are reactions per source particle.
|
||||
.. table:: **Particle production scores: units are particles produced per
|
||||
source particles.**
|
||||
|
||||
:fission:
|
||||
Total fission rate in reactions per source particle.
|
||||
+----------------------+---------------------------------------------------+
|
||||
|Score | Description |
|
||||
+======================+===================================================+
|
||||
|delayed-nu-fission |Total production of delayed neutrons due to |
|
||||
| |fission. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|nu-fission |Total production of neutrons due to fission. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|nu-scatter, |These scores are similar in functionality to their |
|
||||
|nu-scatter-N, |``scatter*`` equivalents except the total |
|
||||
|nu-scatter-PN, |production of neutrons due to scattering is scored |
|
||||
|nu-scatter-YN |vice simply the scattering rate. This accounts for |
|
||||
| |multiplicity from (n,2n), (n,3n), and (n,4n) |
|
||||
| |reactions. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|
||||
:nu-fission:
|
||||
Total production of neutrons due to fission. Units are neutrons produced
|
||||
per source neutron.
|
||||
.. table:: **Miscellaneous scores: units are indicated for each.**
|
||||
|
||||
:delayed-nu-fission:
|
||||
Total production of delayed neutrons due to fission. Units are neutrons produced
|
||||
per source neutron.
|
||||
+----------------------+---------------------------------------------------+
|
||||
|Score | Description |
|
||||
+======================+===================================================+
|
||||
|current |Partial currents on the boundaries of each cell in |
|
||||
| |a mesh. Units are particles per source |
|
||||
| |particle. Note that this score can only be used if |
|
||||
| |a mesh filter has been specified. Furthermore, it |
|
||||
| |may not be used in conjunction with any other |
|
||||
| |score. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|events |Number of scoring events. Units are events per |
|
||||
| |source particle. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|inverse-velocity |The flux-weighted inverse velocity where the |
|
||||
| |velocity is in units of centimeters per second. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|kappa-fission |The recoverable energy production rate due to |
|
||||
| |fission. The recoverable energy is defined as the |
|
||||
| |fission product kinetic energy, prompt and delayed |
|
||||
| |neutron kinetic energies, prompt and delayed |
|
||||
| |:math:`\gamma`-ray total energies, and the total |
|
||||
| |energy released by the delayed :math:`\beta` |
|
||||
| |particles. The neutrino energy does not contribute |
|
||||
| |to this response. The prompt and delayed |
|
||||
| |:math:`\gamma`-rays are assumed to deposit their |
|
||||
| |energy locally. Units are MeV per source particle. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|
||||
:kappa-fission:
|
||||
The recoverable energy production rate due to fission. The recoverable
|
||||
energy is defined as the fission product kinetic energy, prompt and
|
||||
delayed neutron kinetic energies, prompt and delayed :math:`\gamma`-ray
|
||||
total energies, and the total energy released by the delayed :math:`\beta`
|
||||
particles. The neutrino energy does not contribute to this response. The
|
||||
prompt and delayed :math:`\gamma`-rays are assumed to deposit their energy
|
||||
locally. Units are MeV per source particle.
|
||||
|
||||
:scatter-N:
|
||||
Tally the N\ :sup:`th` \ scattering moment, where N is the Legendre
|
||||
expansion order of the change in particle angle :math:`\left(\mu\right)`.
|
||||
N must be between 0 and 10. As an example, tallying the 2\ :sup:`nd` \
|
||||
scattering moment would be specified as ``<scores> scatter-2
|
||||
</scores>``. Units are reactions per source particle.
|
||||
|
||||
:scatter-PN:
|
||||
Tally all of the scattering moments from order 0 to N, where N is the
|
||||
Legendre expansion order of the change in particle angle
|
||||
:math:`\left(\mu\right)`. That is, ``scatter-P1`` is equivalent to
|
||||
requesting tallies of ``scatter-0`` and ``scatter-1``. Like for
|
||||
``scatter-N``, N must be between 0 and 10. As an example, tallying up to
|
||||
the 2\ :sup:`nd` \ scattering moment would be specified as ``<scores>
|
||||
scatter-P2 </scores>``. Units are reactions per source particle.
|
||||
|
||||
:scatter-YN:
|
||||
``scatter-YN`` is similar to ``scatter-PN`` except an additional expansion
|
||||
is performed for the incoming particle direction
|
||||
:math:`\left(\Omega\right)` using the real spherical harmonics. This is
|
||||
useful for performing angular flux moment weighting of the scattering
|
||||
moments. Like ``scatter-PN``, ``scatter-YN`` will tally all of the moments
|
||||
from order 0 to N; N again must be between 0 and 10. Units are reactions
|
||||
per source particle.
|
||||
|
||||
:nu-scatter, nu-scatter-N, nu-scatter-PN, nu-scatter-YN:
|
||||
These scores are similar in functionality to their ``scatter*``
|
||||
equivalents except the total production of neutrons due to scattering is
|
||||
scored vice simply the scattering rate. This accounts for multiplicity
|
||||
from (n,2n), (n,3n), and (n,4n) reactions. Units are neutrons produced per
|
||||
source particle.
|
||||
|
||||
:flux-YN:
|
||||
Spherical harmonic expansion of the direction of motion
|
||||
:math:`\left(\Omega\right)` of the total flux. This score will tally all
|
||||
of the harmonic moments of order 0 to N. N must be between 0
|
||||
and 10. Units are particle-cm per source particle.
|
||||
|
||||
:total-YN:
|
||||
The total reaction rate expanded via spherical harmonics about the
|
||||
direction of motion of the neutron, :math:`\Omega`.
|
||||
This score will tally all of the harmonic moments of order 0 to N. N must
|
||||
be between 0 and 10. Units are reactions per source particle.
|
||||
|
||||
:current:
|
||||
Partial currents on the boundaries of each cell in a mesh. Units are
|
||||
particles per source particle.
|
||||
|
||||
.. note::
|
||||
This score can only be used if a mesh filter has been
|
||||
specified. Furthermore, it may not be used in conjunction with any
|
||||
other score.
|
||||
|
||||
:inverse-velocity:
|
||||
The flux-weighted inverse velocity where the velocity is in units of
|
||||
centimeters per second.
|
||||
|
||||
.. note::
|
||||
The ``analog`` estimator is actually identical to the ``collision``
|
||||
estimator for the inverse-velocity score.
|
||||
|
||||
:events:
|
||||
Number of scoring events. Units are events per source particle.
|
||||
.. note::
|
||||
The ``analog`` estimator is actually identical to the ``collision``
|
||||
estimator for the flux and inverse-velocity scores.
|
||||
|
||||
:trigger:
|
||||
Precision trigger applied to all filter bins and nuclides for this tally.
|
||||
|
|
|
|||
|
|
@ -1,409 +0,0 @@
|
|||
import sys
|
||||
from numbers import Integral
|
||||
|
||||
import numpy as np
|
||||
|
||||
from openmc import Filter, Nuclide
|
||||
from openmc.cross import CrossScore, CrossNuclide, CrossFilter
|
||||
from openmc.filter import _FILTER_TYPES
|
||||
import openmc.checkvalue as cv
|
||||
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
# Acceptable tally aggregation operations
|
||||
_TALLY_AGGREGATE_OPS = ['sum', 'avg']
|
||||
|
||||
|
||||
class AggregateScore(object):
|
||||
"""A special-purpose tally score used to encapsulate an aggregate of a
|
||||
subset or all of tally's scores for tally aggregation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scores : Iterable of str or CrossScore
|
||||
The scores included in the aggregation
|
||||
aggregate_op : str
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally's scores with this AggregateScore
|
||||
|
||||
Attributes
|
||||
----------
|
||||
scores : Iterable of str or CrossScore
|
||||
The scores included in the aggregation
|
||||
aggregate_op : str
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally's scores with this AggregateScore
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, scores=None, aggregate_op=None):
|
||||
|
||||
self._scores = None
|
||||
self._aggregate_op = None
|
||||
|
||||
if scores is not None:
|
||||
self.scores = scores
|
||||
if aggregate_op is not None:
|
||||
self.aggregate_op = aggregate_op
|
||||
|
||||
def __hash__(self):
|
||||
return hash(repr(self))
|
||||
|
||||
def __eq__(self, other):
|
||||
return str(other) == str(self)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
|
||||
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._scores = self.scores
|
||||
clone._aggregate_op = self.aggregate_op
|
||||
|
||||
memo[id(self)] = clone
|
||||
|
||||
return clone
|
||||
|
||||
# If this object has been copied before, return the first copy made
|
||||
else:
|
||||
return existing
|
||||
|
||||
def __repr__(self):
|
||||
string = ', '.join(map(str, self.scores))
|
||||
string = '{0}({1})'.format(self.aggregate_op, string)
|
||||
return string
|
||||
|
||||
@property
|
||||
def scores(self):
|
||||
return self._scores
|
||||
|
||||
@property
|
||||
def aggregate_op(self):
|
||||
return self._aggregate_op
|
||||
|
||||
@scores.setter
|
||||
def scores(self, scores):
|
||||
cv.check_iterable_type('scores', scores, basestring)
|
||||
self._scores = scores
|
||||
|
||||
@aggregate_op.setter
|
||||
def aggregate_op(self, aggregate_op):
|
||||
cv.check_type('aggregate_op', aggregate_op, (basestring, CrossScore))
|
||||
cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS)
|
||||
self._aggregate_op = aggregate_op
|
||||
|
||||
|
||||
class AggregateNuclide(object):
|
||||
"""A special-purpose tally nuclide used to encapsulate an aggregate of a
|
||||
subset or all of tally's nuclides for tally aggregation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nuclides : Iterable of str or Nuclide or CrossNuclide
|
||||
The nuclides included in the aggregation
|
||||
aggregate_op : str
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally's nuclides with this AggregateNuclide
|
||||
|
||||
Attributes
|
||||
----------
|
||||
nuclides : Iterable of str or Nuclide or CrossNuclide
|
||||
The nuclides included in the aggregation
|
||||
aggregate_op : str
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally's nuclides with this AggregateNuclide
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, nuclides=None, aggregate_op=None):
|
||||
|
||||
self._nuclides = None
|
||||
self._aggregate_op = None
|
||||
|
||||
if nuclides is not None:
|
||||
self.nuclides = nuclides
|
||||
if aggregate_op is not None:
|
||||
self.aggregate_op = aggregate_op
|
||||
|
||||
def __hash__(self):
|
||||
return hash(repr(self))
|
||||
|
||||
def __eq__(self, other):
|
||||
return str(other) == str(self)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
|
||||
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._nuclides = self.nuclides
|
||||
clone._aggregate_op = self._aggregate_op
|
||||
|
||||
memo[id(self)] = clone
|
||||
|
||||
return clone
|
||||
|
||||
# If this object has been copied before, return the first copy made
|
||||
else:
|
||||
return existing
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
# Append each nuclide in the aggregate to the string
|
||||
string = '{0}('.format(self.aggregate_op)
|
||||
names = [nuclide.name if isinstance(nuclide, Nuclide) else str(nuclide)
|
||||
for nuclide in self.nuclides]
|
||||
string += ', '.join(map(str, names)) + ')'
|
||||
return string
|
||||
|
||||
@property
|
||||
def nuclides(self):
|
||||
return self._nuclides
|
||||
|
||||
@property
|
||||
def aggregate_op(self):
|
||||
return self._aggregate_op
|
||||
|
||||
@nuclides.setter
|
||||
def nuclides(self, nuclides):
|
||||
cv.check_iterable_type('nuclides', nuclides,
|
||||
(basestring, Nuclide, CrossNuclide))
|
||||
self._nuclides = nuclides
|
||||
|
||||
@aggregate_op.setter
|
||||
def aggregate_op(self, aggregate_op):
|
||||
cv.check_type('aggregate_op', aggregate_op, basestring)
|
||||
cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS)
|
||||
self._aggregate_op = aggregate_op
|
||||
|
||||
|
||||
class AggregateFilter(object):
|
||||
"""A special-purpose tally filter used to encapsulate an aggregate of a
|
||||
subset or all of a tally filter's bins for tally aggregation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
aggregate_filter : Filter or CrossFilter
|
||||
The filter included in the aggregation
|
||||
bins : Iterable of tuple
|
||||
The filter bins included in the aggregation
|
||||
aggregate_op : str
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally filter's bins with this AggregateFilter
|
||||
|
||||
Attributes
|
||||
----------
|
||||
type : str
|
||||
The type of the aggregatefilter (e.g., 'sum(energy)', 'sum(cell)')
|
||||
aggregate_filter : filter
|
||||
The filter included in the aggregation
|
||||
aggregate_op : str
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally filter's bins with this AggregateFilter
|
||||
bins : Iterable of tuple
|
||||
The filter bins included in the aggregation
|
||||
num_bins : Integral
|
||||
The number of filter bins (always 1 if aggregate_filter is defined)
|
||||
stride : Integral
|
||||
The number of filter, nuclide and score bins within each of this
|
||||
aggregatefilter's bins.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, aggregate_filter=None, bins=None, aggregate_op=None):
|
||||
|
||||
self._type = '{0}({1})'.format(aggregate_op, aggregate_filter.type)
|
||||
self._bins = None
|
||||
self._stride = None
|
||||
|
||||
self._aggregate_filter = None
|
||||
self._aggregate_op = None
|
||||
|
||||
if aggregate_filter is not None:
|
||||
self.aggregate_filter = aggregate_filter
|
||||
if bins is not None:
|
||||
self.bins = bins
|
||||
if aggregate_op is not None:
|
||||
self.aggregate_op = aggregate_op
|
||||
|
||||
def __hash__(self):
|
||||
return hash(repr(self))
|
||||
|
||||
def __eq__(self, other):
|
||||
return str(other) == str(self)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
|
||||
def __repr__(self):
|
||||
string = 'AggregateFilter\n'
|
||||
string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self.type)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tBins', '=\t', self.bins)
|
||||
return string
|
||||
|
||||
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._aggregate_filter = self.aggregate_filter
|
||||
clone._aggregate_op = self.aggregate_op
|
||||
clone._bins = self._bins
|
||||
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 aggregate_filter(self):
|
||||
return self._aggregate_filter
|
||||
|
||||
@property
|
||||
def aggregate_op(self):
|
||||
return self._aggregate_op
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self._type
|
||||
|
||||
@property
|
||||
def bins(self):
|
||||
return self._bins
|
||||
|
||||
@property
|
||||
def num_bins(self):
|
||||
return 1 if self.aggregate_filter else 0
|
||||
|
||||
@property
|
||||
def stride(self):
|
||||
return self._stride
|
||||
|
||||
@type.setter
|
||||
def type(self, filter_type):
|
||||
if filter_type not in _FILTER_TYPES.values():
|
||||
msg = 'Unable to set AggregateFilter type to "{0}" since it ' \
|
||||
'is not one of the supported types'.format(filter_type)
|
||||
raise ValueError(msg)
|
||||
|
||||
self._type = filter_type
|
||||
|
||||
@aggregate_filter.setter
|
||||
def aggregate_filter(self, aggregate_filter):
|
||||
cv.check_type('aggregate_filter', aggregate_filter, (Filter, CrossFilter))
|
||||
self._aggregate_filter = aggregate_filter
|
||||
|
||||
@bins.setter
|
||||
def bins(self, bins):
|
||||
cv.check_iterable_type('bins', bins, (Integral, tuple))
|
||||
self._bins = bins
|
||||
|
||||
@aggregate_op.setter
|
||||
def aggregate_op(self, aggregate_op):
|
||||
cv.check_type('aggregate_op', aggregate_op, basestring)
|
||||
cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS)
|
||||
self._aggregate_op = aggregate_op
|
||||
|
||||
@stride.setter
|
||||
def stride(self, stride):
|
||||
self._stride = stride
|
||||
|
||||
def get_bin_index(self, filter_bin):
|
||||
"""Returns the index in the AggregateFilter for some bin.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filter_bin : Integral or tuple of Real
|
||||
A tuple of value(s) corresponding to the bin of interest in
|
||||
the aggregated filter. The bin is the integer ID for 'material',
|
||||
'surface', 'cell', 'cellborn', and 'universe' Filters. The bin
|
||||
is the integer cell instance ID for 'distribcell' Filters. The
|
||||
bin is a 2-tuple of floats for 'energy' and 'energyout' filters
|
||||
corresponding to the energy boundaries of the bin of interest.
|
||||
The bin is a (x,y,z) 3-tuple for 'mesh' filters corresponding to
|
||||
the mesh cell of interest.
|
||||
|
||||
Returns
|
||||
-------
|
||||
filter_index : Integral
|
||||
The index in the Tally data array for this filter bin. For an
|
||||
AggregateTally the filter bin index is always unity.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When the filter_bin is not part of the aggregated filter's bins
|
||||
|
||||
"""
|
||||
|
||||
if filter_bin not in self.bins:
|
||||
msg = 'Unable to get the bin index for AggregateFilter since ' \
|
||||
'"{0}" is not one of the bins'.format(filter_bin)
|
||||
raise ValueError(msg)
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_pandas_dataframe(self, datasize, summary=None):
|
||||
"""Builds a Pandas DataFrame for the AggregateFilter's bins.
|
||||
|
||||
This method constructs a Pandas DataFrame object for the AggregateFilter
|
||||
with columns annotated by filter bin information. This is a helper
|
||||
method for the Tally.get_pandas_dataframe(...) method.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
datasize : Integral
|
||||
The total number of bins in the tally corresponding to this filter
|
||||
summary : None or Summary
|
||||
An optional Summary object to be used to construct columns for
|
||||
distribcell tally filters (default is None). NOTE: This parameter
|
||||
is not used by the AggregateFilter and simply mirrors the method
|
||||
signature for the CrossFilter.
|
||||
|
||||
Returns
|
||||
-------
|
||||
pandas.DataFrame
|
||||
A Pandas DataFrame with columns of strings that characterize the
|
||||
aggregatefilter's bins. Each entry in the DataFrame will include
|
||||
one or more aggregation operations used to construct the
|
||||
aggregatefilter's bins. The number of rows in the DataFrame is the
|
||||
same as the total number of bins in the corresponding tally, with
|
||||
the filter bins appropriately tiled to map to the corresponding
|
||||
tally bins.
|
||||
|
||||
See also
|
||||
--------
|
||||
Tally.get_pandas_dataframe(), Filter.get_pandas_dataframe(),
|
||||
CrossFilter.get_pandas_dataframe()
|
||||
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
|
||||
# Construct a sring representing the filter aggregation
|
||||
aggregate_bin = '{0}('.format(self.aggregate_op)
|
||||
aggregate_bin += ', '.join(map(str, self.bins)) + ')'
|
||||
|
||||
# Construct NumPy array of bin repeated for each element in dataframe
|
||||
aggregate_bin_array = np.array([aggregate_bin])
|
||||
aggregate_bin_array = np.repeat(aggregate_bin_array, datasize)
|
||||
|
||||
# Construct Pandas DataFrame for the AggregateFilter
|
||||
df = pd.DataFrame({self.type: aggregate_bin_array})
|
||||
return df
|
||||
|
|
@ -1,16 +1,21 @@
|
|||
import sys
|
||||
from numbers import Integral
|
||||
|
||||
import numpy as np
|
||||
|
||||
from openmc import Filter, Nuclide
|
||||
from openmc.filter import _FILTER_TYPES
|
||||
import openmc.checkvalue as cv
|
||||
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
# Acceptable tally arithmetic binary operations
|
||||
_TALLY_ARITHMETIC_OPS = ['+', '-', '*', '/', '^']
|
||||
|
||||
# Acceptable tally aggregation operations
|
||||
_TALLY_AGGREGATE_OPS = ['sum', 'avg']
|
||||
|
||||
|
||||
class CrossScore(object):
|
||||
"""A special-purpose tally score used to encapsulate all combinations of two
|
||||
|
|
@ -97,17 +102,19 @@ class CrossScore(object):
|
|||
|
||||
@left_score.setter
|
||||
def left_score(self, left_score):
|
||||
cv.check_type('left_score', left_score, (basestring, CrossScore))
|
||||
cv.check_type('left_score', left_score,
|
||||
(basestring, CrossScore, AggregateScore))
|
||||
self._left_score = left_score
|
||||
|
||||
@right_score.setter
|
||||
def right_score(self, right_score):
|
||||
cv.check_type('right_score', right_score, (basestring, CrossScore))
|
||||
cv.check_type('right_score', right_score,
|
||||
(basestring, CrossScore, AggregateScore))
|
||||
self._right_score = right_score
|
||||
|
||||
@binary_op.setter
|
||||
def binary_op(self, binary_op):
|
||||
cv.check_type('binary_op', binary_op, (basestring, CrossScore))
|
||||
cv.check_type('binary_op', binary_op, basestring)
|
||||
cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS)
|
||||
self._binary_op = binary_op
|
||||
|
||||
|
|
@ -214,12 +221,14 @@ class CrossNuclide(object):
|
|||
|
||||
@left_nuclide.setter
|
||||
def left_nuclide(self, left_nuclide):
|
||||
cv.check_type('left_nuclide', left_nuclide, (Nuclide, CrossNuclide))
|
||||
cv.check_type('left_nuclide', left_nuclide,
|
||||
(Nuclide, CrossNuclide, AggregateNuclide))
|
||||
self._left_nuclide = left_nuclide
|
||||
|
||||
@right_nuclide.setter
|
||||
def right_nuclide(self, right_nuclide):
|
||||
cv.check_type('right_nuclide', right_nuclide, (Nuclide, CrossNuclide))
|
||||
cv.check_type('right_nuclide', right_nuclide,
|
||||
(Nuclide, CrossNuclide, AggregateNuclide))
|
||||
self._right_nuclide = right_nuclide
|
||||
|
||||
@binary_op.setter
|
||||
|
|
@ -372,13 +381,15 @@ class CrossFilter(object):
|
|||
|
||||
@left_filter.setter
|
||||
def left_filter(self, left_filter):
|
||||
cv.check_type('left_filter', left_filter, (Filter, CrossFilter))
|
||||
cv.check_type('left_filter', left_filter,
|
||||
(Filter, CrossFilter, AggregateFilter))
|
||||
self._left_filter = left_filter
|
||||
self._bins['left'] = left_filter.bins
|
||||
|
||||
@right_filter.setter
|
||||
def right_filter(self, right_filter):
|
||||
cv.check_type('right_filter', right_filter, (Filter, CrossFilter))
|
||||
cv.check_type('right_filter', right_filter,
|
||||
(Filter, CrossFilter, AggregateFilter))
|
||||
self._right_filter = right_filter
|
||||
self._bins['right'] = right_filter.bins
|
||||
|
||||
|
|
@ -472,3 +483,395 @@ class CrossFilter(object):
|
|||
df = '(' + left_df + ' ' + self.binary_op + ' ' + right_df + ')'
|
||||
|
||||
return df
|
||||
|
||||
class AggregateScore(object):
|
||||
"""A special-purpose tally score used to encapsulate an aggregate of a
|
||||
subset or all of tally's scores for tally aggregation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scores : Iterable of str or CrossScore
|
||||
The scores included in the aggregation
|
||||
aggregate_op : str
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally's scores with this AggregateScore
|
||||
|
||||
Attributes
|
||||
----------
|
||||
scores : Iterable of str or CrossScore
|
||||
The scores included in the aggregation
|
||||
aggregate_op : str
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally's scores with this AggregateScore
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, scores=None, aggregate_op=None):
|
||||
|
||||
self._scores = None
|
||||
self._aggregate_op = None
|
||||
|
||||
if scores is not None:
|
||||
self.scores = scores
|
||||
if aggregate_op is not None:
|
||||
self.aggregate_op = aggregate_op
|
||||
|
||||
def __hash__(self):
|
||||
return hash(repr(self))
|
||||
|
||||
def __eq__(self, other):
|
||||
return str(other) == str(self)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
|
||||
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._scores = self.scores
|
||||
clone._aggregate_op = self.aggregate_op
|
||||
|
||||
memo[id(self)] = clone
|
||||
|
||||
return clone
|
||||
|
||||
# If this object has been copied before, return the first copy made
|
||||
else:
|
||||
return existing
|
||||
|
||||
def __repr__(self):
|
||||
string = ', '.join(map(str, self.scores))
|
||||
string = '{0}({1})'.format(self.aggregate_op, string)
|
||||
return string
|
||||
|
||||
@property
|
||||
def scores(self):
|
||||
return self._scores
|
||||
|
||||
@property
|
||||
def aggregate_op(self):
|
||||
return self._aggregate_op
|
||||
|
||||
@scores.setter
|
||||
def scores(self, scores):
|
||||
cv.check_iterable_type('scores', scores, basestring)
|
||||
self._scores = scores
|
||||
|
||||
@aggregate_op.setter
|
||||
def aggregate_op(self, aggregate_op):
|
||||
cv.check_type('aggregate_op', aggregate_op, (basestring, CrossScore))
|
||||
cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS)
|
||||
self._aggregate_op = aggregate_op
|
||||
|
||||
|
||||
class AggregateNuclide(object):
|
||||
"""A special-purpose tally nuclide used to encapsulate an aggregate of a
|
||||
subset or all of tally's nuclides for tally aggregation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nuclides : Iterable of str or Nuclide or CrossNuclide
|
||||
The nuclides included in the aggregation
|
||||
aggregate_op : str
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally's nuclides with this AggregateNuclide
|
||||
|
||||
Attributes
|
||||
----------
|
||||
nuclides : Iterable of str or Nuclide or CrossNuclide
|
||||
The nuclides included in the aggregation
|
||||
aggregate_op : str
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally's nuclides with this AggregateNuclide
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, nuclides=None, aggregate_op=None):
|
||||
|
||||
self._nuclides = None
|
||||
self._aggregate_op = None
|
||||
|
||||
if nuclides is not None:
|
||||
self.nuclides = nuclides
|
||||
if aggregate_op is not None:
|
||||
self.aggregate_op = aggregate_op
|
||||
|
||||
def __hash__(self):
|
||||
return hash(repr(self))
|
||||
|
||||
def __eq__(self, other):
|
||||
return str(other) == str(self)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
|
||||
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._nuclides = self.nuclides
|
||||
clone._aggregate_op = self._aggregate_op
|
||||
|
||||
memo[id(self)] = clone
|
||||
|
||||
return clone
|
||||
|
||||
# If this object has been copied before, return the first copy made
|
||||
else:
|
||||
return existing
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
# Append each nuclide in the aggregate to the string
|
||||
string = '{0}('.format(self.aggregate_op)
|
||||
names = [nuclide.name if isinstance(nuclide, Nuclide) else str(nuclide)
|
||||
for nuclide in self.nuclides]
|
||||
string += ', '.join(map(str, names)) + ')'
|
||||
return string
|
||||
|
||||
@property
|
||||
def nuclides(self):
|
||||
return self._nuclides
|
||||
|
||||
@property
|
||||
def aggregate_op(self):
|
||||
return self._aggregate_op
|
||||
|
||||
@nuclides.setter
|
||||
def nuclides(self, nuclides):
|
||||
cv.check_iterable_type('nuclides', nuclides,
|
||||
(basestring, Nuclide, CrossNuclide))
|
||||
self._nuclides = nuclides
|
||||
|
||||
@aggregate_op.setter
|
||||
def aggregate_op(self, aggregate_op):
|
||||
cv.check_type('aggregate_op', aggregate_op, basestring)
|
||||
cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS)
|
||||
self._aggregate_op = aggregate_op
|
||||
|
||||
|
||||
class AggregateFilter(object):
|
||||
"""A special-purpose tally filter used to encapsulate an aggregate of a
|
||||
subset or all of a tally filter's bins for tally aggregation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
aggregate_filter : Filter or CrossFilter
|
||||
The filter included in the aggregation
|
||||
bins : Iterable of tuple
|
||||
The filter bins included in the aggregation
|
||||
aggregate_op : str
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally filter's bins with this AggregateFilter
|
||||
|
||||
Attributes
|
||||
----------
|
||||
type : str
|
||||
The type of the aggregatefilter (e.g., 'sum(energy)', 'sum(cell)')
|
||||
aggregate_filter : filter
|
||||
The filter included in the aggregation
|
||||
aggregate_op : str
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
to aggregate across a tally filter's bins with this AggregateFilter
|
||||
bins : Iterable of tuple
|
||||
The filter bins included in the aggregation
|
||||
num_bins : Integral
|
||||
The number of filter bins (always 1 if aggregate_filter is defined)
|
||||
stride : Integral
|
||||
The number of filter, nuclide and score bins within each of this
|
||||
aggregatefilter's bins.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, aggregate_filter=None, bins=None, aggregate_op=None):
|
||||
|
||||
self._type = '{0}({1})'.format(aggregate_op, aggregate_filter.type)
|
||||
self._bins = None
|
||||
self._stride = None
|
||||
|
||||
self._aggregate_filter = None
|
||||
self._aggregate_op = None
|
||||
|
||||
if aggregate_filter is not None:
|
||||
self.aggregate_filter = aggregate_filter
|
||||
if bins is not None:
|
||||
self.bins = bins
|
||||
if aggregate_op is not None:
|
||||
self.aggregate_op = aggregate_op
|
||||
|
||||
def __hash__(self):
|
||||
return hash(repr(self))
|
||||
|
||||
def __eq__(self, other):
|
||||
return str(other) == str(self)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
|
||||
def __repr__(self):
|
||||
string = 'AggregateFilter\n'
|
||||
string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self.type)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tBins', '=\t', self.bins)
|
||||
return string
|
||||
|
||||
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._aggregate_filter = self.aggregate_filter
|
||||
clone._aggregate_op = self.aggregate_op
|
||||
clone._bins = self._bins
|
||||
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 aggregate_filter(self):
|
||||
return self._aggregate_filter
|
||||
|
||||
@property
|
||||
def aggregate_op(self):
|
||||
return self._aggregate_op
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self._type
|
||||
|
||||
@property
|
||||
def bins(self):
|
||||
return self._bins
|
||||
|
||||
@property
|
||||
def num_bins(self):
|
||||
return 1 if self.aggregate_filter else 0
|
||||
|
||||
@property
|
||||
def stride(self):
|
||||
return self._stride
|
||||
|
||||
@type.setter
|
||||
def type(self, filter_type):
|
||||
if filter_type not in _FILTER_TYPES.values():
|
||||
msg = 'Unable to set AggregateFilter type to "{0}" since it ' \
|
||||
'is not one of the supported types'.format(filter_type)
|
||||
raise ValueError(msg)
|
||||
|
||||
self._type = filter_type
|
||||
|
||||
@aggregate_filter.setter
|
||||
def aggregate_filter(self, aggregate_filter):
|
||||
cv.check_type('aggregate_filter', aggregate_filter, (Filter, CrossFilter))
|
||||
self._aggregate_filter = aggregate_filter
|
||||
|
||||
@bins.setter
|
||||
def bins(self, bins):
|
||||
cv.check_iterable_type('bins', bins, (Integral, tuple))
|
||||
self._bins = bins
|
||||
|
||||
@aggregate_op.setter
|
||||
def aggregate_op(self, aggregate_op):
|
||||
cv.check_type('aggregate_op', aggregate_op, basestring)
|
||||
cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS)
|
||||
self._aggregate_op = aggregate_op
|
||||
|
||||
@stride.setter
|
||||
def stride(self, stride):
|
||||
self._stride = stride
|
||||
|
||||
def get_bin_index(self, filter_bin):
|
||||
"""Returns the index in the AggregateFilter for some bin.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filter_bin : Integral or tuple of Real
|
||||
A tuple of value(s) corresponding to the bin of interest in
|
||||
the aggregated filter. The bin is the integer ID for 'material',
|
||||
'surface', 'cell', 'cellborn', and 'universe' Filters. The bin
|
||||
is the integer cell instance ID for 'distribcell' Filters. The
|
||||
bin is a 2-tuple of floats for 'energy' and 'energyout' filters
|
||||
corresponding to the energy boundaries of the bin of interest.
|
||||
The bin is a (x,y,z) 3-tuple for 'mesh' filters corresponding to
|
||||
the mesh cell of interest.
|
||||
|
||||
Returns
|
||||
-------
|
||||
filter_index : Integral
|
||||
The index in the Tally data array for this filter bin. For an
|
||||
AggregateTally the filter bin index is always unity.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
When the filter_bin is not part of the aggregated filter's bins
|
||||
|
||||
"""
|
||||
|
||||
if filter_bin not in self.bins:
|
||||
msg = 'Unable to get the bin index for AggregateFilter since ' \
|
||||
'"{0}" is not one of the bins'.format(filter_bin)
|
||||
raise ValueError(msg)
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_pandas_dataframe(self, datasize, summary=None):
|
||||
"""Builds a Pandas DataFrame for the AggregateFilter's bins.
|
||||
|
||||
This method constructs a Pandas DataFrame object for the AggregateFilter
|
||||
with columns annotated by filter bin information. This is a helper
|
||||
method for the Tally.get_pandas_dataframe(...) method.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
datasize : Integral
|
||||
The total number of bins in the tally corresponding to this filter
|
||||
summary : None or Summary
|
||||
An optional Summary object to be used to construct columns for
|
||||
distribcell tally filters (default is None). NOTE: This parameter
|
||||
is not used by the AggregateFilter and simply mirrors the method
|
||||
signature for the CrossFilter.
|
||||
|
||||
Returns
|
||||
-------
|
||||
pandas.DataFrame
|
||||
A Pandas DataFrame with columns of strings that characterize the
|
||||
aggregatefilter's bins. Each entry in the DataFrame will include
|
||||
one or more aggregation operations used to construct the
|
||||
aggregatefilter's bins. The number of rows in the DataFrame is the
|
||||
same as the total number of bins in the corresponding tally, with
|
||||
the filter bins appropriately tiled to map to the corresponding
|
||||
tally bins.
|
||||
|
||||
See also
|
||||
--------
|
||||
Tally.get_pandas_dataframe(), Filter.get_pandas_dataframe(),
|
||||
CrossFilter.get_pandas_dataframe()
|
||||
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
|
||||
# Construct a sring representing the filter aggregation
|
||||
aggregate_bin = '{0}('.format(self.aggregate_op)
|
||||
aggregate_bin += ', '.join(map(str, self.bins)) + ')'
|
||||
|
||||
# Construct NumPy array of bin repeated for each element in dataframe
|
||||
aggregate_bin_array = np.array([aggregate_bin])
|
||||
aggregate_bin_array = np.repeat(aggregate_bin_array, datasize)
|
||||
|
||||
# Construct Pandas DataFrame for the AggregateFilter
|
||||
df = pd.DataFrame({self.type: aggregate_bin_array})
|
||||
return df
|
||||
|
|
@ -673,9 +673,11 @@ class Filter(object):
|
|||
|
||||
# Assign entry to Lattice Multi-index column
|
||||
else:
|
||||
# Reverse y index per lattice ordering in OpenCG
|
||||
level_dict[lat_id_key][offset] = coords._lattice._id
|
||||
level_dict[lat_x_key][offset] = coords._lat_x
|
||||
level_dict[lat_y_key][offset] = coords._lat_y
|
||||
level_dict[lat_y_key][offset] = \
|
||||
coords._lattice.dimension[1] - coords._lat_y - 1
|
||||
level_dict[lat_z_key][offset] = coords._lat_z
|
||||
|
||||
# Move to next node in LocalCoords linked list
|
||||
|
|
|
|||
|
|
@ -396,7 +396,7 @@ class Library(object):
|
|||
|
||||
cv.check_type('statepoint', statepoint, openmc.StatePoint)
|
||||
|
||||
if not statepoint.with_summary:
|
||||
if statepoint.summary is None:
|
||||
msg = 'Unable to load data from a statepoint which has not been ' \
|
||||
'linked with a summary file'
|
||||
raise ValueError(msg)
|
||||
|
|
@ -568,8 +568,9 @@ class Library(object):
|
|||
for domain in self.domains:
|
||||
for mgxs_type in self.mgxs_types:
|
||||
mgxs = subdomain_avg_library.get_mgxs(domain, mgxs_type)
|
||||
avg_mgxs = mgxs.get_subdomain_avg_xs()
|
||||
subdomain_avg_library.all_mgxs[domain.id][mgxs_type] = avg_mgxs
|
||||
if mgxs.domain_type == 'distribcell':
|
||||
avg_mgxs = mgxs.get_subdomain_avg_xs()
|
||||
subdomain_avg_library.all_mgxs[domain.id][mgxs_type] = avg_mgxs
|
||||
|
||||
return subdomain_avg_library
|
||||
|
||||
|
|
|
|||
|
|
@ -583,7 +583,7 @@ class MGXS(object):
|
|||
|
||||
cv.check_type('statepoint', statepoint, openmc.statepoint.StatePoint)
|
||||
|
||||
if not statepoint.with_summary:
|
||||
if statepoint.summary is None:
|
||||
msg = 'Unable to load data from a statepoint which has not been ' \
|
||||
'linked with a summary file'
|
||||
raise ValueError(msg)
|
||||
|
|
@ -612,6 +612,11 @@ class MGXS(object):
|
|||
filters = []
|
||||
filter_bins = []
|
||||
|
||||
# Clear any tallies previously loaded from a statepoint
|
||||
self._tallies = None
|
||||
self._xs_tally = None
|
||||
self._rxn_rate_tally = None
|
||||
|
||||
# Find, slice and store Tallies from StatePoint
|
||||
# The tally slicing is needed if tally merging was used
|
||||
for tally_type, tally in self.tallies.items():
|
||||
|
|
@ -673,14 +678,14 @@ class MGXS(object):
|
|||
filter_bins = []
|
||||
|
||||
# Construct a collection of the domain filter bins
|
||||
if subdomains != 'all':
|
||||
if not isinstance(subdomains, basestring):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral)
|
||||
for subdomain in subdomains:
|
||||
filters.append(self.domain_type)
|
||||
filter_bins.append((subdomain,))
|
||||
|
||||
# Construct list of energy group bounds tuples for all requested groups
|
||||
if groups != 'all':
|
||||
if not isinstance(groups, basestring):
|
||||
cv.check_iterable_type('groups', groups, Integral)
|
||||
for group in groups:
|
||||
filters.append('energy')
|
||||
|
|
@ -838,7 +843,7 @@ class MGXS(object):
|
|||
"""
|
||||
|
||||
# Construct a collection of the subdomain filter bins to average across
|
||||
if subdomains != 'all':
|
||||
if not isinstance(subdomains, basestring):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral)
|
||||
elif self.domain_type == 'distribcell':
|
||||
subdomains = np.arange(self.num_subdomains)
|
||||
|
|
@ -881,7 +886,7 @@ class MGXS(object):
|
|||
"""
|
||||
|
||||
# Construct a collection of the subdomains to report
|
||||
if subdomains != 'all':
|
||||
if not isinstance(subdomains, basestring):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral)
|
||||
elif self.domain_type == 'distribcell':
|
||||
subdomains = np.arange(self.num_subdomains, dtype=np.int)
|
||||
|
|
@ -1010,7 +1015,7 @@ class MGXS(object):
|
|||
xs_results = h5py.File(filename, 'w')
|
||||
|
||||
# Construct a collection of the subdomains to report
|
||||
if subdomains != 'all':
|
||||
if not isinstance(subdomains, basestring):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral)
|
||||
elif self.domain_type == 'distribcell':
|
||||
subdomains = np.arange(self.num_subdomains, dtype=np.int)
|
||||
|
|
@ -1192,7 +1197,7 @@ class MGXS(object):
|
|||
|
||||
"""
|
||||
|
||||
if groups != 'all':
|
||||
if not isinstance(groups, basestring):
|
||||
cv.check_iterable_type('groups', groups, Integral)
|
||||
if nuclides != 'all' and nuclides != 'sum':
|
||||
cv.check_iterable_type('nuclides', nuclides, basestring)
|
||||
|
|
@ -1252,7 +1257,7 @@ class MGXS(object):
|
|||
columns = ['group in']
|
||||
|
||||
# Select out those groups the user requested
|
||||
if groups != 'all':
|
||||
if not isinstance(groups, basestring):
|
||||
if 'group in' in df:
|
||||
df = df[df['group in'].isin(groups)]
|
||||
if 'group out' in df:
|
||||
|
|
@ -1789,21 +1794,21 @@ class ScatterMatrixXS(MGXS):
|
|||
filter_bins = []
|
||||
|
||||
# Construct a collection of the domain filter bins
|
||||
if subdomains != 'all':
|
||||
if not isinstance(subdomains, basestring):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral)
|
||||
for subdomain in subdomains:
|
||||
filters.append(self.domain_type)
|
||||
filter_bins.append((subdomain,))
|
||||
|
||||
# Construct list of energy group bounds tuples for all requested groups
|
||||
if in_groups != 'all':
|
||||
if not isinstance(in_groups, basestring):
|
||||
cv.check_iterable_type('groups', in_groups, Integral)
|
||||
for group in in_groups:
|
||||
filters.append('energy')
|
||||
filter_bins.append((self.energy_groups.get_group_bounds(group),))
|
||||
|
||||
# Construct list of energy group bounds tuples for all requested groups
|
||||
if out_groups != 'all':
|
||||
if not isinstance(out_groups, basestring):
|
||||
cv.check_iterable_type('groups', out_groups, Integral)
|
||||
for group in out_groups:
|
||||
filters.append('energyout')
|
||||
|
|
@ -1887,7 +1892,7 @@ class ScatterMatrixXS(MGXS):
|
|||
"""
|
||||
|
||||
# Construct a collection of the subdomains to report
|
||||
if subdomains != 'all':
|
||||
if not isinstance(subdomains, basestring):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral)
|
||||
elif self.domain_type == 'distribcell':
|
||||
subdomains = np.arange(self.num_subdomains, dtype=np.int)
|
||||
|
|
@ -1926,12 +1931,6 @@ class ScatterMatrixXS(MGXS):
|
|||
bounds = self.energy_groups.get_group_bounds(group)
|
||||
string += template.format('', group, bounds[0], bounds[1])
|
||||
|
||||
if subdomains == 'all':
|
||||
if self.domain_type == 'distribcell':
|
||||
subdomains = np.arange(self.num_subdomains, dtype=np.int)
|
||||
else:
|
||||
subdomains = [self.domain.id]
|
||||
|
||||
# Loop over all subdomains
|
||||
for subdomain in subdomains:
|
||||
|
||||
|
|
@ -2135,14 +2134,14 @@ class Chi(MGXS):
|
|||
filter_bins = []
|
||||
|
||||
# Construct a collection of the domain filter bins
|
||||
if subdomains != 'all':
|
||||
if not isinstance(subdomains, basestring):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral)
|
||||
for subdomain in subdomains:
|
||||
filters.append(self.domain_type)
|
||||
filter_bins.append((subdomain,))
|
||||
|
||||
# Construct list of energy group bounds tuples for all requested groups
|
||||
if groups != 'all':
|
||||
if not isinstance(groups, basestring):
|
||||
cv.check_iterable_type('groups', groups, Integral)
|
||||
for group in groups:
|
||||
filters.append('energyout')
|
||||
|
|
|
|||
|
|
@ -449,10 +449,6 @@ class StatePoint(object):
|
|||
def summary(self):
|
||||
return self._summary
|
||||
|
||||
@property
|
||||
def with_summary(self):
|
||||
return False if self.summary is None else True
|
||||
|
||||
@sparse.setter
|
||||
def sparse(self, sparse):
|
||||
"""Convert tally data from NumPy arrays to SciPy list of lists (LIL)
|
||||
|
|
|
|||
|
|
@ -367,9 +367,9 @@ class Summary(object):
|
|||
# Set the universes for the lattice
|
||||
lattice.universes = universes
|
||||
|
||||
# Set the distribcell offsets for the lattice
|
||||
if offsets is not None:
|
||||
offsets = np.swapaxes(offsets, 0, 2)
|
||||
lattice.offsets = offsets
|
||||
lattice.offsets = offsets[:, ::-1, :]
|
||||
|
||||
# Add the Lattice to the global dictionary of all Lattices
|
||||
self.lattices[index] = lattice
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ import sys
|
|||
import numpy as np
|
||||
|
||||
from openmc import Mesh, Filter, Trigger, Nuclide
|
||||
from openmc.cross import CrossScore, CrossNuclide, CrossFilter
|
||||
from openmc.aggregate import AggregateScore, AggregateNuclide, AggregateFilter
|
||||
from openmc.arithmetic import *
|
||||
from openmc.filter import _FILTER_TYPES
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.clean_xml import *
|
||||
|
|
@ -2680,11 +2679,11 @@ class Tally(object):
|
|||
new_tally = copy.deepcopy(self)
|
||||
new_tally.sparse = False
|
||||
|
||||
if self.sum is not None:
|
||||
if not self.derived and self.sum is not None:
|
||||
new_sum = self.get_values(scores, filters, filter_bins,
|
||||
nuclides, 'sum')
|
||||
new_tally.sum = new_sum
|
||||
if self.sum_sq is not None:
|
||||
if not self.derived and self.sum_sq is not None:
|
||||
new_sum_sq = self.get_values(scores, filters, filter_bins,
|
||||
nuclides, 'sum_sq')
|
||||
new_tally.sum_sq = new_sum_sq
|
||||
|
|
@ -2749,7 +2748,7 @@ class Tally(object):
|
|||
bin_indices.append(bin_index)
|
||||
num_bins += 1
|
||||
|
||||
find_filter.bins = set(find_filter.bins[bin_indices])
|
||||
find_filter.bins = np.unique(find_filter.bins[bin_indices])
|
||||
find_filter.num_bins = num_bins
|
||||
|
||||
# Update the new tally's filter strides
|
||||
|
|
@ -3106,10 +3105,10 @@ class Tally(object):
|
|||
diag_indices[start:end] = indices + (i * new_filter.num_bins**2)
|
||||
|
||||
# Inject this Tally's data along the diagonal of the diagonalized Tally
|
||||
if self.sum is not None:
|
||||
if not self.derived and self.sum is not None:
|
||||
new_tally._sum = np.zeros(new_tally.shape, dtype=np.float64)
|
||||
new_tally._sum[diag_indices, :, :] = self.sum
|
||||
if self.sum_sq is not None:
|
||||
if not self.derived and self.sum_sq is not None:
|
||||
new_tally._sum_sq = np.zeros(new_tally.shape, dtype=np.float64)
|
||||
new_tally._sum_sq[diag_indices, :, :] = self.sum_sq
|
||||
if self.mean is not None:
|
||||
|
|
|
|||
|
|
@ -1095,14 +1095,14 @@ class RectLattice(Lattice):
|
|||
|
||||
# For 2D Lattices
|
||||
if len(self._dimension) == 2:
|
||||
offset = self._offsets[i[1]-1, i[2]-1, 0, distribcell_index-1]
|
||||
offset = self._offsets[i[3]-1, i[2]-1, i[1]-1, distribcell_index-1]
|
||||
offset += self._universes[i[1]-1][i[2]-1].get_cell_instance(path,
|
||||
distribcell_index)
|
||||
|
||||
# For 3D Lattices
|
||||
else:
|
||||
offset = self._offsets[i[1]-1, i[2]-1, i[3]-1, distribcell_index-1]
|
||||
offset += self._universes[i[1]-1][i[2]-1][i[3]-1].get_cell_instance(
|
||||
offset = self._offsets[i[3]-1, i[2]-1, i[1]-1, distribcell_index-1]
|
||||
offset += self._universes[i[3]-1][i[2]-1][i[1]-1].get_cell_instance(
|
||||
path, distribcell_index)
|
||||
|
||||
return offset
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ module ace
|
|||
use ace_header, only: Nuclide, Reaction, SAlphaBeta, XsListing
|
||||
use constants
|
||||
use distribution_univariate, only: Uniform, Equiprobable, Tabular
|
||||
use endf, only: reaction_name, is_fission, is_disappearance
|
||||
use endf, only: is_fission, is_disappearance
|
||||
use energy_distribution, only: TabularEquiprobable, LevelInelastic, &
|
||||
ContinuousTabular, MaxwellEnergy, Evaporation, WattEnergy, NBodyPhaseSpace
|
||||
use error, only: fatal_error, warning
|
||||
|
|
|
|||
47
src/endf.F90
47
src/endf.F90
|
|
@ -17,6 +17,53 @@ contains
|
|||
character(20) :: string
|
||||
|
||||
select case (MT)
|
||||
! Special reactions for tallies
|
||||
case (SCORE_FLUX)
|
||||
string = "flux"
|
||||
case (SCORE_TOTAL)
|
||||
string = "total"
|
||||
case (SCORE_SCATTER)
|
||||
string = "scatter"
|
||||
case (SCORE_NU_SCATTER)
|
||||
string = "nu-scatter"
|
||||
case (SCORE_SCATTER_N)
|
||||
string = "scatter-n"
|
||||
case (SCORE_SCATTER_PN)
|
||||
string = "scatter-pn"
|
||||
case (SCORE_NU_SCATTER_N)
|
||||
string = "nu-scatter-n"
|
||||
case (SCORE_NU_SCATTER_PN)
|
||||
string = "nu-scatter-pn"
|
||||
case (SCORE_TRANSPORT)
|
||||
string = "transport"
|
||||
case (SCORE_N_1N)
|
||||
string = "n1n"
|
||||
case (SCORE_ABSORPTION)
|
||||
string = "absorption"
|
||||
case (SCORE_FISSION)
|
||||
string = "fission"
|
||||
case (SCORE_NU_FISSION)
|
||||
string = "nu-fission"
|
||||
case (SCORE_DELAYED_NU_FISSION)
|
||||
string = "delayed-nu-fission"
|
||||
case (SCORE_KAPPA_FISSION)
|
||||
string = "kappa-fission"
|
||||
case (SCORE_CURRENT)
|
||||
string = "current"
|
||||
case (SCORE_FLUX_YN)
|
||||
string = "flux-yn"
|
||||
case (SCORE_TOTAL_YN)
|
||||
string = "total-yn"
|
||||
case (SCORE_SCATTER_YN)
|
||||
string = "scatter-yn"
|
||||
case (SCORE_NU_SCATTER_YN)
|
||||
string = "nu-scatter-yn"
|
||||
case (SCORE_EVENTS)
|
||||
string = "events"
|
||||
case (SCORE_INVERSE_VELOCITY)
|
||||
string = "inverse-velocity"
|
||||
|
||||
! Normal ENDF-based reactions
|
||||
case (TOTAL_XS)
|
||||
string = '(n,total)'
|
||||
case (ELASTIC)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ module input_xml
|
|||
use dict_header, only: DictIntInt, ElemKeyValueCI
|
||||
use distribution_multivariate
|
||||
use distribution_univariate
|
||||
use endf, only: reaction_name
|
||||
use energy_grid, only: grid_method, n_log_bins
|
||||
use error, only: fatal_error, warning
|
||||
use geometry_header, only: Cell, Lattice, RectLattice, HexLattice
|
||||
|
|
@ -3246,7 +3247,7 @@ contains
|
|||
call fatal_error("Cannot tally absorption rate with an outgoing &
|
||||
&energy filter.")
|
||||
end if
|
||||
case ('fission')
|
||||
case ('fission', '18')
|
||||
t % score_bins(j) = SCORE_FISSION
|
||||
if (t % find_filter(FILTER_ENERGYOUT) > 0) then
|
||||
call fatal_error("Cannot tally fission rate with an outgoing &
|
||||
|
|
@ -3426,6 +3427,32 @@ contains
|
|||
|
||||
! Deallocate temporary string array of scores
|
||||
deallocate(sarray)
|
||||
|
||||
! Check that no duplicate scores exist
|
||||
j = 1
|
||||
do while (j < n_scores)
|
||||
! Determine number of bins for scores with expansions
|
||||
n_order = t % moment_order(j)
|
||||
select case (t % score_bins(j))
|
||||
case (SCORE_SCATTER_PN, SCORE_NU_SCATTER_PN)
|
||||
n_bins = n_order + 1
|
||||
case (SCORE_FLUX_YN, SCORE_TOTAL_YN, SCORE_SCATTER_YN, &
|
||||
SCORE_NU_SCATTER_YN)
|
||||
n_bins = (n_order + 1)**2
|
||||
case default
|
||||
n_bins = 1
|
||||
end select
|
||||
|
||||
do k = j + n_bins, n_scores
|
||||
if (t % score_bins(j) == t % score_bins(k) .and. &
|
||||
t % moment_order(j) == t % moment_order(k)) then
|
||||
call fatal_error("Duplicate score of type '" // trim(&
|
||||
reaction_name(t % score_bins(j))) // "' found in tally " &
|
||||
// trim(to_str(t % id)))
|
||||
end if
|
||||
end do
|
||||
j = j + n_bins
|
||||
end do
|
||||
else
|
||||
call fatal_error("No <scores> specified on tally " &
|
||||
&// trim(to_str(t % id)) // ".")
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ module particle_header
|
|||
logical :: write_track = .false.
|
||||
|
||||
! Secondary particles created
|
||||
integer :: n_secondary = 0
|
||||
integer(8) :: n_secondary = 0
|
||||
type(Bank) :: secondary_bank(MAX_SECONDARY)
|
||||
|
||||
contains
|
||||
|
|
|
|||
|
|
@ -88,9 +88,14 @@ contains
|
|||
! change when sampling fission sites. The following block handles all
|
||||
! absorption (including fission)
|
||||
|
||||
if (nuc % fissionable .and. run_mode == MODE_EIGENVALUE) then
|
||||
if (nuc % fissionable) then
|
||||
call sample_fission(i_nuclide, i_reaction)
|
||||
call create_fission_sites(p, i_nuclide, i_reaction)
|
||||
if (run_mode == MODE_EIGENVALUE) then
|
||||
call create_fission_sites(p, i_nuclide, i_reaction, fission_bank, n_bank)
|
||||
elseif (run_mode == MODE_FIXEDSOURCE) then
|
||||
call create_fission_sites(p, i_nuclide, i_reaction, &
|
||||
p % secondary_bank, p % n_secondary)
|
||||
end if
|
||||
end if
|
||||
|
||||
! If survival biasing is being used, the following subroutine adjusts the
|
||||
|
|
@ -1071,10 +1076,12 @@ contains
|
|||
! neutrons produced from fission and creates appropriate bank sites.
|
||||
!===============================================================================
|
||||
|
||||
subroutine create_fission_sites(p, i_nuclide, i_reaction)
|
||||
subroutine create_fission_sites(p, i_nuclide, i_reaction, bank_array, size_bank)
|
||||
type(Particle), intent(inout) :: p
|
||||
integer, intent(in) :: i_nuclide
|
||||
integer, intent(in) :: i_reaction
|
||||
type(Bank), intent(inout) :: bank_array(:)
|
||||
integer(8), intent(inout) :: size_bank
|
||||
|
||||
integer :: nu_d(MAX_DELAYED_GROUPS) ! number of delayed neutrons born
|
||||
integer :: i ! loop index
|
||||
|
|
@ -1123,27 +1130,35 @@ contains
|
|||
nu = int(nu_t) + 1
|
||||
end if
|
||||
|
||||
! Check for fission bank size getting hit
|
||||
if (n_bank + nu > size(fission_bank)) then
|
||||
if (master) call warning("Maximum number of sites in fission bank &
|
||||
&reached. This can result in irreproducible results using different &
|
||||
&numbers of processes/threads.")
|
||||
! Check for bank size getting hit. For fixed source calculations, this is a
|
||||
! fatal error. For eigenvalue calculations, it just means that k-effective
|
||||
! was too high for a single batch.
|
||||
if (size_bank + nu > size(bank_array)) then
|
||||
if (run_mode == MODE_FIXEDSOURCE) then
|
||||
call fatal_error("Secondary particle bank size limit reached. If you &
|
||||
&are running a subcritical multiplication problem, k-effective &
|
||||
&may be too close to one.")
|
||||
else
|
||||
if (master) call warning("Maximum number of sites in fission bank &
|
||||
&reached. This can result in irreproducible results using different &
|
||||
&numbers of processes/threads.")
|
||||
end if
|
||||
end if
|
||||
|
||||
! Bank source neutrons
|
||||
if (nu == 0 .or. n_bank == size(fission_bank)) return
|
||||
if (nu == 0 .or. size_bank == size(bank_array)) return
|
||||
|
||||
! Initialize counter of delayed neutrons encountered for each delayed group
|
||||
! to zero.
|
||||
nu_d(:) = 0
|
||||
|
||||
p % fission = .true. ! Fission neutrons will be banked
|
||||
do i = int(n_bank,4) + 1, int(min(n_bank + nu, int(size(fission_bank),8)),4)
|
||||
do i = int(size_bank,4) + 1, int(min(size_bank + nu, int(size(bank_array),8)),4)
|
||||
! Bank source neutrons by copying particle data
|
||||
fission_bank(i) % xyz = p % coord(1) % xyz
|
||||
bank_array(i) % xyz = p % coord(1) % xyz
|
||||
|
||||
! Set weight of fission bank site
|
||||
fission_bank(i) % wgt = ONE/weight
|
||||
bank_array(i) % wgt = ONE/weight
|
||||
|
||||
! Sample cosine of angle -- fission neutrons are always emitted
|
||||
! isotropically. Sometimes in ACE data, fission reactions actually have
|
||||
|
|
@ -1153,17 +1168,17 @@ contains
|
|||
|
||||
! Sample azimuthal angle uniformly in [0,2*pi)
|
||||
phi = TWO*PI*prn()
|
||||
fission_bank(i) % uvw(1) = mu
|
||||
fission_bank(i) % uvw(2) = sqrt(ONE - mu*mu) * cos(phi)
|
||||
fission_bank(i) % uvw(3) = sqrt(ONE - mu*mu) * sin(phi)
|
||||
bank_array(i) % uvw(1) = mu
|
||||
bank_array(i) % uvw(2) = sqrt(ONE - mu*mu) * cos(phi)
|
||||
bank_array(i) % uvw(3) = sqrt(ONE - mu*mu) * sin(phi)
|
||||
|
||||
! Sample secondary energy distribution for fission reaction and set energy
|
||||
! in fission bank
|
||||
fission_bank(i) % E = sample_fission_energy(nuc, nuc%reactions(&
|
||||
i_reaction), p)
|
||||
bank_array(i) % E = sample_fission_energy(nuc, &
|
||||
nuc % reactions(i_reaction), p)
|
||||
|
||||
! Set the delayed group of the neutron
|
||||
fission_bank(i) % delayed_group = p % delayed_group
|
||||
bank_array(i) % delayed_group = p % delayed_group
|
||||
|
||||
! Increment the number of neutrons born delayed
|
||||
if (p % delayed_group > 0) then
|
||||
|
|
@ -1172,7 +1187,7 @@ contains
|
|||
end do
|
||||
|
||||
! increment number of bank sites
|
||||
n_bank = min(n_bank + nu, int(size(fission_bank),8))
|
||||
size_bank = min(size_bank + nu, int(size(bank_array),8))
|
||||
|
||||
! Store total and delayed weight banked for analog fission tallies
|
||||
p % n_bank = nu
|
||||
|
|
|
|||
|
|
@ -310,54 +310,7 @@ contains
|
|||
call write_dataset(tally_group, "n_score_bins", tally%n_score_bins)
|
||||
allocate(str_array(size(tally%score_bins)))
|
||||
do j = 1, size(tally%score_bins)
|
||||
select case(tally%score_bins(j))
|
||||
case (SCORE_FLUX)
|
||||
str_array(j) = "flux"
|
||||
case (SCORE_TOTAL)
|
||||
str_array(j) = "total"
|
||||
case (SCORE_SCATTER)
|
||||
str_array(j) = "scatter"
|
||||
case (SCORE_NU_SCATTER)
|
||||
str_array(j) = "nu-scatter"
|
||||
case (SCORE_SCATTER_N)
|
||||
str_array(j) = "scatter-n"
|
||||
case (SCORE_SCATTER_PN)
|
||||
str_array(j) = "scatter-pn"
|
||||
case (SCORE_NU_SCATTER_N)
|
||||
str_array(j) = "nu-scatter-n"
|
||||
case (SCORE_NU_SCATTER_PN)
|
||||
str_array(j) = "nu-scatter-pn"
|
||||
case (SCORE_TRANSPORT)
|
||||
str_array(j) = "transport"
|
||||
case (SCORE_N_1N)
|
||||
str_array(j) = "n1n"
|
||||
case (SCORE_ABSORPTION)
|
||||
str_array(j) = "absorption"
|
||||
case (SCORE_FISSION)
|
||||
str_array(j) = "fission"
|
||||
case (SCORE_NU_FISSION)
|
||||
str_array(j) = "nu-fission"
|
||||
case (SCORE_DELAYED_NU_FISSION)
|
||||
str_array(j) = "delayed-nu-fission"
|
||||
case (SCORE_KAPPA_FISSION)
|
||||
str_array(j) = "kappa-fission"
|
||||
case (SCORE_CURRENT)
|
||||
str_array(j) = "current"
|
||||
case (SCORE_FLUX_YN)
|
||||
str_array(j) = "flux-yn"
|
||||
case (SCORE_TOTAL_YN)
|
||||
str_array(j) = "total-yn"
|
||||
case (SCORE_SCATTER_YN)
|
||||
str_array(j) = "scatter-yn"
|
||||
case (SCORE_NU_SCATTER_YN)
|
||||
str_array(j) = "nu-scatter-yn"
|
||||
case (SCORE_EVENTS)
|
||||
str_array(j) = "events"
|
||||
case (SCORE_INVERSE_VELOCITY)
|
||||
str_array(j) = "inverse-velocity"
|
||||
case default
|
||||
str_array(j) = reaction_name(tally%score_bins(j))
|
||||
end select
|
||||
str_array(j) = reaction_name(tally%score_bins(j))
|
||||
end do
|
||||
call write_dataset(tally_group, "score_bins", str_array)
|
||||
call write_dataset(tally_group, "n_user_score_bins", tally%n_user_score_bins)
|
||||
|
|
|
|||
|
|
@ -639,54 +639,7 @@ contains
|
|||
call write_dataset(tally_group, "n_score_bins", t%n_score_bins)
|
||||
allocate(str_array(size(t%score_bins)))
|
||||
do j = 1, size(t%score_bins)
|
||||
select case(t%score_bins(j))
|
||||
case (SCORE_FLUX)
|
||||
str_array(j) = "flux"
|
||||
case (SCORE_TOTAL)
|
||||
str_array(j) = "total"
|
||||
case (SCORE_SCATTER)
|
||||
str_array(j) = "scatter"
|
||||
case (SCORE_NU_SCATTER)
|
||||
str_array(j) = "nu-scatter"
|
||||
case (SCORE_SCATTER_N)
|
||||
str_array(j) = "scatter-n"
|
||||
case (SCORE_SCATTER_PN)
|
||||
str_array(j) = "scatter-pn"
|
||||
case (SCORE_NU_SCATTER_N)
|
||||
str_array(j) = "nu-scatter-n"
|
||||
case (SCORE_NU_SCATTER_PN)
|
||||
str_array(j) = "nu-scatter-pn"
|
||||
case (SCORE_TRANSPORT)
|
||||
str_array(j) = "transport"
|
||||
case (SCORE_N_1N)
|
||||
str_array(j) = "n1n"
|
||||
case (SCORE_ABSORPTION)
|
||||
str_array(j) = "absorption"
|
||||
case (SCORE_FISSION)
|
||||
str_array(j) = "fission"
|
||||
case (SCORE_NU_FISSION)
|
||||
str_array(j) = "nu-fission"
|
||||
case (SCORE_DELAYED_NU_FISSION)
|
||||
str_array(j) = "delayed-nu-fission"
|
||||
case (SCORE_KAPPA_FISSION)
|
||||
str_array(j) = "kappa-fission"
|
||||
case (SCORE_CURRENT)
|
||||
str_array(j) = "current"
|
||||
case (SCORE_FLUX_YN)
|
||||
str_array(j) = "flux-yn"
|
||||
case (SCORE_TOTAL_YN)
|
||||
str_array(j) = "total-yn"
|
||||
case (SCORE_SCATTER_YN)
|
||||
str_array(j) = "scatter-yn"
|
||||
case (SCORE_NU_SCATTER_YN)
|
||||
str_array(j) = "nu-scatter-yn"
|
||||
case (SCORE_EVENTS)
|
||||
str_array(j) = "events"
|
||||
case (SCORE_INVERSE_VELOCITY)
|
||||
str_array(j) = "inverse-velocity"
|
||||
case default
|
||||
str_array(j) = reaction_name(t%score_bins(j))
|
||||
end select
|
||||
str_array(j) = reaction_name(t%score_bins(j))
|
||||
end do
|
||||
call write_dataset(tally_group, "score_bins", str_array)
|
||||
|
||||
|
|
|
|||
|
|
@ -202,6 +202,7 @@ contains
|
|||
if (p % n_secondary > 0) then
|
||||
call p % initialize_from_source(p % secondary_bank(p % n_secondary))
|
||||
p % n_secondary = p % n_secondary - 1
|
||||
n_event = 0
|
||||
|
||||
! Enter new particle in particle track file
|
||||
if (p % write_track) call add_particle_track()
|
||||
|
|
|
|||
1
tests/test_asymmetric_lattice/inputs_true.dat
Normal file
1
tests/test_asymmetric_lattice/inputs_true.dat
Normal file
|
|
@ -0,0 +1 @@
|
|||
fe07eb28fd0dbb56edaecd510f5e8e4db7271e5c9aecf3d880cce92b69872a0aacf825b8e88cd2e9b1ff709f578b269b1835f53cf2561a390062e1e7e03b5276
|
||||
1
tests/test_asymmetric_lattice/results_true.dat
Normal file
1
tests/test_asymmetric_lattice/results_true.dat
Normal file
|
|
@ -0,0 +1 @@
|
|||
cea61172ecad5554ef86f52d6adad6ad5e21931cf3d67feb37b8bf9d75e618786f638685e458051d4a39afe1a924fd651cf6674a88cf1f1842fd69cd851e1f17
|
||||
129
tests/test_asymmetric_lattice/test_asymmetric_lattice.py
Normal file
129
tests/test_asymmetric_lattice/test_asymmetric_lattice.py
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
import glob
|
||||
import hashlib
|
||||
sys.path.insert(0, os.pardir)
|
||||
from testing_harness import PyAPITestHarness
|
||||
import openmc
|
||||
from openmc.source import Source
|
||||
from openmc.stats import Box
|
||||
|
||||
|
||||
class AsymmetricLatticeTestHarness(PyAPITestHarness):
|
||||
|
||||
def _build_inputs(self):
|
||||
"""Build an axis-asymmetric lattice of fuel assemblies"""
|
||||
|
||||
# Build full core geometry from underlying input set
|
||||
self._input_set.build_default_materials_and_geometry()
|
||||
|
||||
# Extract all universes from the full core geometry
|
||||
geometry = self._input_set.geometry.geometry
|
||||
all_univs = geometry.get_all_universes()
|
||||
|
||||
# Extract universes encapsulating fuel and water assemblies
|
||||
water = all_univs[7]
|
||||
fuel = all_univs[8]
|
||||
|
||||
# Construct a 3x3 lattice of fuel assemblies
|
||||
core_lat = openmc.RectLattice(name='3x3 Core Lattice', lattice_id=202)
|
||||
core_lat.dimension = (3, 3)
|
||||
core_lat.lower_left = (-32.13, -32.13)
|
||||
core_lat.pitch = (21.42, 21.42)
|
||||
core_lat.universes = [[fuel, water, water],
|
||||
[fuel, fuel, fuel],
|
||||
[water, water, water]]
|
||||
|
||||
# Create bounding surfaces
|
||||
min_x = openmc.XPlane(x0=-32.13, boundary_type='reflective')
|
||||
max_x = openmc.XPlane(x0=+32.13, boundary_type='reflective')
|
||||
min_y = openmc.YPlane(y0=-32.13, boundary_type='reflective')
|
||||
max_y = openmc.YPlane(y0=+32.13, boundary_type='reflective')
|
||||
min_z = openmc.ZPlane(z0=0, boundary_type='reflective')
|
||||
max_z = openmc.ZPlane(z0=+32.13, boundary_type='reflective')
|
||||
|
||||
# Define root universe
|
||||
root_univ = openmc.Universe(universe_id=0, name='root universe')
|
||||
root_cell = openmc.Cell(cell_id=1)
|
||||
root_cell.region = +min_x & -max_x & +min_y & -max_y & +min_z & -max_z
|
||||
root_cell.fill = core_lat
|
||||
root_univ.add_cell(root_cell)
|
||||
|
||||
# Over-ride geometry in the input set with this 3x3 lattice
|
||||
self._input_set.geometry.geometry.root_universe = root_univ
|
||||
|
||||
# Initialize a "distribcell" filter for the fuel pin cell
|
||||
distrib_filter = openmc.Filter(type='distribcell', bins=[27])
|
||||
|
||||
# Initialize the tallies
|
||||
tally = openmc.Tally(name='distribcell tally', tally_id=27)
|
||||
tally.add_filter(distrib_filter)
|
||||
tally.add_score('nu-fission')
|
||||
|
||||
# Initialize the tallies file
|
||||
tallies_file = openmc.TalliesFile()
|
||||
tallies_file.add_tally(tally)
|
||||
|
||||
# Assign the tallies file to the input set
|
||||
self._input_set.tallies = tallies_file
|
||||
|
||||
|
||||
self._input_set.build_default_settings()
|
||||
|
||||
# Specify summary output and correct source sampling box
|
||||
source = Source(space=Box([-32, -32, 0], [32, 32, 32]))
|
||||
source.only_fissionable = True
|
||||
self._input_set.settings.source = source
|
||||
self._input_set.settings.output = {'summary': True}
|
||||
|
||||
# Write input XML files
|
||||
self._input_set.export()
|
||||
|
||||
def _get_results(self, hash_output=True):
|
||||
"""Digest info in statepoint and summary and return as a string."""
|
||||
|
||||
# Read the statepoint file
|
||||
statepoint = glob.glob(os.path.join(os.getcwd(), self._sp_name))[0]
|
||||
sp = openmc.StatePoint(statepoint)
|
||||
|
||||
# Read the summary file
|
||||
summary = glob.glob(os.path.join(os.getcwd(), 'summary.h5'))[0]
|
||||
su = openmc.Summary(summary)
|
||||
sp.link_with_summary(su)
|
||||
|
||||
# Extract the tally of interest
|
||||
tally = sp.get_tally(name='distribcell tally')
|
||||
|
||||
# Create a string of all mean, std. dev. values for both tallies
|
||||
outstr = ''
|
||||
outstr += ', '.join(map(str, tally.mean.flatten())) + '\n'
|
||||
outstr += ', '.join(map(str, tally.std_dev.flatten())) + '\n'
|
||||
|
||||
# Extract fuel assembly lattices from the summary
|
||||
all_cells = su.openmc_geometry.get_all_cells()
|
||||
fuel = all_cells[80].fill
|
||||
core = all_cells[1].fill
|
||||
|
||||
# Append a string of lattice distribcell offsets to the string
|
||||
outstr += ', '.join(map(str, fuel.offsets.flatten())) + '\n'
|
||||
outstr += ', '.join(map(str, core.offsets.flatten())) + '\n'
|
||||
|
||||
# Hash the results if necessary
|
||||
if hash_output:
|
||||
sha512 = hashlib.sha512()
|
||||
sha512.update(outstr.encode('utf-8'))
|
||||
outstr = sha512.hexdigest()
|
||||
|
||||
return outstr
|
||||
|
||||
def _cleanup(self):
|
||||
super(AsymmetricLatticeTestHarness, self)._cleanup()
|
||||
f = os.path.join(os.getcwd(), 'tallies.xml')
|
||||
if os.path.exists(f): os.remove(f)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
harness = AsymmetricLatticeTestHarness('statepoint.10.h5', True)
|
||||
harness.main()
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
<material id="1">
|
||||
<density value="7.5" units="g/cc" />
|
||||
<nuclide name="O-16" xs="71c" ao="1.0" />
|
||||
<nuclide name="U-238" xs="71c" ao="0.0001" />
|
||||
</material>
|
||||
|
||||
</materials>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
tally 1:
|
||||
4.538791E+02
|
||||
2.073271E+04
|
||||
4.563929E+02
|
||||
2.091711E+04
|
||||
leakage:
|
||||
9.830000E+00
|
||||
9.663900E+00
|
||||
9.780000E+00
|
||||
9.566400E+00
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue