mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-27 13:45:36 -04:00
Merge remote-tracking branch 'upstream/develop' into diff_tally6
This commit is contained in:
commit
d602dc0e6a
130 changed files with 8251 additions and 17146 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -89,3 +89,8 @@ docs/source/pythonapi/examples/mgxs
|
|||
docs/source/pythonapi/examples/tracks
|
||||
docs/source/pythonapi/examples/fission-rates
|
||||
docs/source/pythonapi/examples/plots
|
||||
|
||||
# Cython files
|
||||
*.c
|
||||
*.html
|
||||
*.so
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
sudo: false
|
||||
sudo: required
|
||||
dist: trusty
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
|
|
@ -28,7 +29,7 @@ before_install:
|
|||
- conda config --set always_yes yes --set changeps1 no
|
||||
- conda update -q conda
|
||||
- conda info -a
|
||||
- conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION numpy scipy h5py=2.5 pandas
|
||||
- conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION six numpy scipy h5py=2.5 pandas
|
||||
- source activate test-environment
|
||||
|
||||
# Install GCC, MPICH, HDF5, PHDF5
|
||||
|
|
@ -46,14 +47,12 @@ before_script:
|
|||
fi
|
||||
- export OPENMC_CROSS_SECTIONS=$HOME/nndc_hdf5/cross_sections.xml
|
||||
|
||||
- cd data
|
||||
- git clone --branch=master git://github.com/smharper/windowed_multipole_library.git wmp_lib
|
||||
- tar xzvf wmp_lib/multipole_lib.tar.gz
|
||||
- export OPENMC_MULTIPOLE_LIBRARY=$PWD/multipole_lib
|
||||
- cd ..
|
||||
|
||||
script:
|
||||
- cd tests
|
||||
- export OMP_NUM_THREADS=3
|
||||
- export OMP_NUM_THREADS=2
|
||||
- ./travis.sh
|
||||
- cd ..
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
========================
|
||||
cross_sections.xml Files
|
||||
========================
|
||||
|
||||
As a reminder, in order to run a simulation with OpenMC, you will need cross
|
||||
section data for each nuclide in your problem. OpenMC is not currently
|
||||
distributed with cross section data, so you will have to obtain cross section
|
||||
data by other means. The `user's guide`_ offers some helpful advice on how you
|
||||
can obtain cross sections.
|
||||
|
||||
When OpenMC starts up, it needs a cross_sections.xml file that tells it where to
|
||||
find ACE format cross sections. The files in this directory are configured to
|
||||
work with a few common cross section sources.
|
||||
|
||||
- **cross_sections_ascii.xml** -- This file matches ENDF/B-VII.0 cross sections
|
||||
distributed with MCNP5 / MCNP6 beta.
|
||||
|
||||
- **cross_sections_nndc.xml** -- This file matches ENDF/B-VII.1 cross sections
|
||||
distributed from the `NNDC website`_.
|
||||
|
||||
- **cross_sections_serpent.xml** -- This file matches ENDF/B-VII.0 cross
|
||||
sections distributed with Serpent 1.1.7.
|
||||
|
||||
- **cross_sections.xml** - This file matches ENDF/B-VII.0 cross sections
|
||||
distributed with MCNP5 / MCNP6 beta *that have been converted to binary*.
|
||||
|
||||
To use any of these files, you need to follow two steps:
|
||||
|
||||
1. Change the path on the ``<directory>`` element in the cross_sections.xml file
|
||||
to the directory containing the ACE files.
|
||||
|
||||
2. Enter the absolute path of the cross_sections.xml on the ``<cross_sections>``
|
||||
element in your settings.xml, or set the CROSS_SECTIONS environment variable to
|
||||
the full path of the cross_sections.xml file.
|
||||
|
||||
.. _user's guide: http://mit-crpg.github.io/openmc/usersguide/install.html#cross-section-configuration
|
||||
.. _NNDC website: http://www.nndc.bnl.gov/endf/b7.1/acefiles.html
|
||||
|
|
@ -6,21 +6,19 @@ Multi-Group Cross Section Library Format
|
|||
|
||||
OpenMC can be run in continuous-energy mode or multi-group mode, provided the
|
||||
nuclear data is available. In continuous-energy mode, the
|
||||
``cross_sections.xml`` file contains necessary meta-data for each data set,
|
||||
``cross_sections.xml`` file contains necessary meta-data for each dataset,
|
||||
including the name and a file system location where the complete library
|
||||
can be found. In multi-group mode, this ``mgxs.xml`` file contains
|
||||
this same meta-data describing the nuclide or material, but also contains the
|
||||
group-wise nuclear data. This portion of the manual describes the format of
|
||||
the multi-group data library required to be used in the ``mgxs.xml``
|
||||
file.
|
||||
can be found. In multi-group mode, the multi-group meta-data and the
|
||||
nuclear data itself is contained within an ``mgxs.h5`` file. This portion of
|
||||
the manual describes the format of the multi-group data library required
|
||||
to be used in the ``mgxs.h5`` file.
|
||||
|
||||
Similar to the other input file types, the multi-group library is provided in
|
||||
the XML_ format. This library must provide some meta-data about the library
|
||||
itself (such as the number of groups and the group structure, etc.) as well as
|
||||
the actual cross section data itself for each of the necessary nuclides or
|
||||
materials.
|
||||
The multi-group library is provided in the HDF5_ format. This library must
|
||||
provide some meta-data about the library itself (such as the number of
|
||||
groups and the group structure, etc.) as well as the actual cross section
|
||||
data itself for each of the necessary nuclides or materials.
|
||||
|
||||
.. _XML: http://www.w3.org/XML/
|
||||
.. _HDF5: http://www.hdfgroup.org/HDF5/
|
||||
|
||||
.. _mgxs_lib_spec:
|
||||
|
||||
|
|
@ -28,277 +26,139 @@ materials.
|
|||
MGXS Library Specification
|
||||
--------------------------
|
||||
|
||||
The multi-group library meta-data is contained within the groups_,
|
||||
group_structure_, and inverse_velocities_ elements.
|
||||
The actual multi-group data itself is contained within the xsdata_ element.
|
||||
**/**
|
||||
|
||||
.. _groups:
|
||||
:Attributes: - **groups** (*int*) -- Number of energy groups
|
||||
- **group structure** (*double[]*) -- Monotonically increasing
|
||||
list of group boundaries, in units of MeV. The length of this
|
||||
array should be the number of groups plus 1.
|
||||
|
||||
``<groups>`` Element
|
||||
--------------------
|
||||
**/<library name>/**
|
||||
|
||||
The ``<groups>`` element has no attributes and simply provides the number of
|
||||
energy groups contained within the library.
|
||||
The data within <library name> contains the temperature-dependent multi-group
|
||||
data for the nuclide or material that it represents.
|
||||
|
||||
*Default*: None, this must be provided.
|
||||
:Attributes: - **atomic_weight_ratio** (*double*) -- The atomic weight ratio
|
||||
(optional, i.e. it is not meaningful for material-wise data).
|
||||
- **fissionable** (*bool*) -- Whether the dataset is fissionable
|
||||
(True) or not (False).
|
||||
- **representation** (*char[]*) -- The method used to generate and
|
||||
represent the multi-group cross sections. That is, whether they
|
||||
were generated with scalar flux weighting (or reduced to a
|
||||
similar representation) and thus are angle-independent, or if the
|
||||
data was generated with angular dependent fluxes and thus the
|
||||
data is angle-dependent. Valid values are either "isotropic" or
|
||||
"angle".
|
||||
- **num_azimuthal** (*int*) -- Number of equal width angular bins
|
||||
that the azimuthal angular domain is subdivided if the
|
||||
`representation` attribute is "angle". This parameter is
|
||||
ignored otherwise.
|
||||
- **num_polar** (*int*) -- Number of equal width angular bins
|
||||
that the polar angular domain is subdivided if the
|
||||
`representation` attribute is "angle". This parameter is
|
||||
ignored otherwise.
|
||||
- **scatter_format** (*char[]*) -- The representation of the
|
||||
scattering angular distribution. The options are either
|
||||
"legendre", "histogram", or "tabular". If not provided, the
|
||||
default of "legendre" will be assumed.
|
||||
- **order** (*int*) -- Either the Legendre order, number of bins,
|
||||
or number of points (depending on the value of `scatter_format`)
|
||||
used to describe the angular distribution associated with each
|
||||
group-to-group transfer probability.
|
||||
- **scatter_shape** (*char[]*) -- The shape of the provided
|
||||
scatter and multiplicity matrix. The values provided are strings
|
||||
describing the ordering the scattering array is provided in
|
||||
row-major (i.e., C/C++ and Python) indexing. Valid values are
|
||||
"[Order][G][G']" or "[Order][G'][G]" where "G'" denotes the
|
||||
secondary/outgoing energy groups, "G" denotes the incoming
|
||||
energy groups, and "Order" is the angular distribution index.
|
||||
This value is not required; if not the default value of
|
||||
"[Order][G][G']" will be assumed.
|
||||
|
||||
.. _group_structure:
|
||||
**/<library name>/kTs/**
|
||||
|
||||
``<group_structure>`` Element
|
||||
-----------------------------
|
||||
:Datasets:
|
||||
- **<TTT>K** (*double*) -- kT values (in MeV) for each Temperature
|
||||
TTT (in Kelvin), rounded to the nearest integer
|
||||
|
||||
The ``<group_structure>`` element has no attributes and should be provided as a
|
||||
monotonically increasing list of bounding energies, in MeV, for a number of
|
||||
groups. To provide proper energy boundaries, the length of the data within the
|
||||
``<group_structure>`` element should be one more than the number of groups in
|
||||
the problem. For example, a two-group problem could be specified as:
|
||||
**/<library name>/<TTT>K/**
|
||||
|
||||
.. code-block:: xml
|
||||
Temperature-dependent data, provided for temperature <TTT>K.
|
||||
|
||||
<group_structure> 0.0 0.625E-6 20.0 </group_structure>
|
||||
:Datasets: - **total** (*double[]* or *double[][][]*) -- Total cross section.
|
||||
This is a 1-D vector if `representation` is "isotropic", or a 3-D
|
||||
vector if `representation` is "angle" with dimensions of
|
||||
[groups][azimuthal][polar].
|
||||
- **absorption** (*double[]* or *double[][][]*) -- Absorption
|
||||
cross section.
|
||||
This is a 1-D vector if `representation` is "isotropic", or a 3-D
|
||||
vector if `representation` is "angle" with dimensions of
|
||||
[groups][azimuthal][polar].
|
||||
- **fission** (*double[]* or *double[][][]*) -- Fission
|
||||
cross section.
|
||||
This is a 1-D vector if `representation` is "isotropic", or a 3-D
|
||||
vector if `representation` is "angle" with dimensions of
|
||||
[groups][azimuthal][polar]. This is only required if the dataset
|
||||
is fissionable and fission-tallies are expected to be used.
|
||||
- **kappa-fission** (*double[]* or *double[][][]*) -- Kappa-Fission
|
||||
(energy-release from fission) cross section.
|
||||
This is a 1-D vector if `representation` is "isotropic", or a 3-D
|
||||
vector if `representation` is "angle" with dimensions of
|
||||
[groups][azimuthal][polar]. This is only required if the dataset
|
||||
is fissionable and fission-tallies are expected to be used.
|
||||
- **chi** (*double[]* or *double[][][]*) -- Fission neutron energy
|
||||
spectra.
|
||||
This is a 1-D vector if `representation` is "isotropic", or a 3-D
|
||||
vector if `representation` is "angle" with dimensions of
|
||||
[groups][azimuthal][polar]. This is only required if the dataset
|
||||
is fissionable and fission-tallies are expected to be used.
|
||||
- **nu-fission** (*double[]* to *double[][][][]*) -- Nu-Fission
|
||||
cross section.
|
||||
If **chi** is provided, then `nu-fission` has the same
|
||||
dimensionality as `fission`. If **chi** is not provided, then
|
||||
the `nu-fission` data must represent the fission neutron energy
|
||||
spectra as well and thus will have one additional dimension
|
||||
for the outgoing energy group. In this case, `nu-fission` has the
|
||||
same dimensionality as `multiplicity_matrix`.
|
||||
- **inverse_velocities** (*double[]*) -- Average inverse velocity
|
||||
for each of the groups in the library. This dataset is optional.
|
||||
|
||||
*Default*: None, this must be provided.
|
||||
**/<library name>/<TTT>K/scatter_data/**
|
||||
|
||||
.. _inverse_velocities:
|
||||
|
||||
``<inverse_velocities>`` Element
|
||||
--------------------------------
|
||||
|
||||
The ``<inverse_velocities>`` element optionally indicates the average
|
||||
inverse velocity corresponding to each of the groups in the problem.
|
||||
This element should therefore be an array with a length which matches the
|
||||
number of groups set in the groups_ element.
|
||||
|
||||
*Default*: Should this be needed by the presence of an ``inverse-velocity``
|
||||
score in the ``tallies.xml`` file and not provided in this element, OpenMC
|
||||
will simply convert the group mid-point energy to an inverse of the velocity
|
||||
and use this information for tallying.
|
||||
|
||||
.. _xsdata:
|
||||
|
||||
``<xsdata>`` Element
|
||||
--------------------
|
||||
|
||||
The ``<xsdata>`` element contains the nuclide or material-specific meta-data as
|
||||
well as the actual cross section data. The following are the
|
||||
attributes/sub-elements required to describe the meta-data:
|
||||
|
||||
:name:
|
||||
The name of the microscopic or macroscopic data set. An extension to the
|
||||
name must be provided (e.g., the ``.300K`` in ``UO2.300K``). The name and
|
||||
extension together must be twelve or less characters in length. This
|
||||
extension must follow a period and be five characters or less in length.
|
||||
similar to the equivalent in the continuous-energy ``cross_sections.xml``
|
||||
file, is used to denote variants of the particular nuclide or material of
|
||||
interest (i.e. the ``UO2`` data in this example could have been generated
|
||||
at a temperature of 300K).
|
||||
|
||||
*Default*: None, this must be provided.
|
||||
|
||||
:alias:
|
||||
An alternative name to use for the microscopic or macroscopic data set.
|
||||
|
||||
*Default*: If no alias is provided, it will adopt the value of ``name``.
|
||||
|
||||
:kT:
|
||||
The temperature times Boltzmann's constant (in units of MeV) at which the
|
||||
data was generated.
|
||||
|
||||
*Default*: Room temperature, 2.53E-8 MeV
|
||||
|
||||
:fissionable:
|
||||
This element states whether or not the data in question is fissionable.
|
||||
Accepted values are "true" or "false".
|
||||
|
||||
*Default*: None, this element must be provided.
|
||||
|
||||
:representation:
|
||||
This element provides the method used to generate and represent the
|
||||
multi-group cross sections. That is, whether they were generated with
|
||||
scalar flux weighting (or reduced to an equivalent representation)
|
||||
and thus are angle-independent, or if the data was generated with angular
|
||||
dependent fluxes and thus the data is angle-dependent. The options are
|
||||
either "isotropic" or "angle".
|
||||
|
||||
*Default*: "isotropic"
|
||||
|
||||
:num_azimuthal:
|
||||
This element provides the number of equal width angular bins that the
|
||||
azimuthal angular domain is subdivided in the case of angle-dependent
|
||||
cross sections (i.e., "angle" is passed to the ``representation`` element).
|
||||
Note that these bins are equal in azimuthal angle widths, not equal in the
|
||||
cosine of the azimuthal angle widths.
|
||||
|
||||
*Default*: If ``representation`` is "angle", this must be provided. This
|
||||
parameter is not used for other ``representation`` types.
|
||||
|
||||
:num_polar:
|
||||
This element provides the number of equal width angular bins that the
|
||||
polar angular domain is subdivided in the case of angle-dependent
|
||||
cross sections (i.e., "angle" is passed to the ``representation`` element).
|
||||
Note that these bins are equal in polar angle widths, not equal in the
|
||||
cosine of the polar angle widths.
|
||||
|
||||
|
||||
*Default*: If ``representation`` is "angle", this must be provided. This
|
||||
parameter is not used for other ``representation`` types.
|
||||
|
||||
:scatt_type:
|
||||
This element provides the representation of the angular distribution
|
||||
associated with each group-to-group transfer probability. The options are
|
||||
either "legendre", "histogram", or "tabular".
|
||||
The "legendre" option means the angular distribution has been
|
||||
expanded via Legendre polynomials of the order provided in the "order"
|
||||
element.
|
||||
The "histogram" option means the angular distribution is provided in
|
||||
an equi-width histogram format with a number of bins as provided in the
|
||||
"order" element. This is useful when the angular distribution was
|
||||
obtained from a Monte Carlo tally and thus is natively in the histogram
|
||||
format.
|
||||
The "tabular" option means the angular distribution is provided in an
|
||||
equi-spaced point-wise representation.
|
||||
|
||||
*Default*: "legendre"
|
||||
|
||||
:order:
|
||||
This element provides either the Legendre order, number of bins, or number
|
||||
of points used to describe the angular distribution associated with each
|
||||
group-to-group transfer probability. The specific meaning of this bin
|
||||
depends upon the value of ``scatt_type`` as discussed above.
|
||||
|
||||
*Default*: None, this element must be provided.
|
||||
|
||||
:tabular_legendre:
|
||||
This optional element is used to set how the Legendre scattering kernel, if
|
||||
provided via the ``scatt_type`` element above, is represented and thus used
|
||||
during the scattering process. Specifically, the options are to either
|
||||
convert the Legendre expansion to a tabular representation or leave it as
|
||||
a set of Legendre coefficients. Converting to a tabular representation
|
||||
will cost memory but can allow for a decrease in runtime compared to
|
||||
leaving as a set of Legendre coefficients. This element has the following
|
||||
attributes/sub-elements:
|
||||
|
||||
:enable:
|
||||
This attribute/sub-element denotes whether or not the conversion to the
|
||||
tabular format should be performed or not. A value of "true" means
|
||||
the conversion should be performed, "false" means it should not.
|
||||
|
||||
*Default*: "true"
|
||||
|
||||
:num_points:
|
||||
If the conversion is to take place the number of tabular points is
|
||||
required. This attribute/sub-element allows the user to set the desired
|
||||
number of points.
|
||||
|
||||
*Default*: 33
|
||||
|
||||
The following attributes/sub-elements are the cross section values to
|
||||
be used during the transport process.
|
||||
|
||||
:total:
|
||||
This element requires the group-wise total cross section ordered by
|
||||
increasing group index (i.e., fast to thermal). If ``representation`` is
|
||||
"isotropic", then the length of this list should equal the number of
|
||||
groups described in the ``groups`` element. If ``representation`` is
|
||||
"angle", then the length of this list should equal the number of groups
|
||||
times the number of azimuthal angles times the number of polar angles,
|
||||
with the inner-dimension being groups, intermediate-dimension being
|
||||
azimuthal angles and outer-dimension being the polar angles.
|
||||
|
||||
*Default*: If not provided, it will be determined by summing the
|
||||
absorption and scattering cross sections.
|
||||
|
||||
:absorption:
|
||||
This element requires the group-wise absorption cross section ordered by
|
||||
increasing group index (i.e., fast to thermal). If ``representation`` is
|
||||
"isotropic", then the length of this list should equal the number of
|
||||
groups described in the ``groups`` element. If ``representation`` is
|
||||
"angle", then the length of this list should equal the number of groups
|
||||
times the number of azimuthal angles times the number of polar angles,
|
||||
with the inner-dimension being groups, intermediate-dimension being
|
||||
azimuthal angles and outer-dimension being the polar angles.
|
||||
|
||||
*Default*: None, this must be provided.
|
||||
|
||||
:scatter:
|
||||
This element requires the scattering moment matrices presented with the
|
||||
columns representing incoming group and rows representing the outgoing
|
||||
group. That is, down-scatter will be above the diagonal of the resultant
|
||||
matrix. This matrix is repeated for every Legendre order (in order of
|
||||
increasing orders) if ``scatt_type`` is "legendre"; otherwise, this
|
||||
matrix is repeated for every bin of the histogram or tabular
|
||||
representation. Finally, if ``representation`` is "angle", the above
|
||||
is repeated for every azimuthal angle and every polar angle, in that
|
||||
order.
|
||||
|
||||
*Default*: None, this must be provided.
|
||||
|
||||
:multiplicity:
|
||||
This element provides the ratio of neutrons produced in scattering
|
||||
collisions to the neutrons which undergo scattering collisions; that is,
|
||||
the multiplicity provides the code with a scaling factor to account for
|
||||
neutrons being produced in (n,xn) reactions. This information is assumed
|
||||
isotropic and therefore does not need to be repeated for every Legendre
|
||||
moment or histogram/tabular bin. This matrix follows the same arrangement
|
||||
as described for the ``scatter`` element, with the exception of the
|
||||
data needed to provide the scattering type information.
|
||||
|
||||
*Default*: Multiplicities of 1.0 are assumed (i.e., (n,xn) reactions are
|
||||
neglected).
|
||||
|
||||
The following fission-specific data are only needed should ``fissionable``
|
||||
be "true".
|
||||
|
||||
:fission:
|
||||
This element requires the group-wise fission cross section ordered by
|
||||
increasing group index (i.e., fast to thermal). If ``representation`` is
|
||||
"isotropic", then the length of this list should equal the number of
|
||||
groups described in the ``groups`` element. If ``representation`` is
|
||||
"angle", then the length of this list should equal the number of groups
|
||||
times the number of azimuthal angles times the number of polar angles,
|
||||
with the inner-dimension being groups, intermediate-dimension being
|
||||
azimuthal angles and outer-dimension being the polar angles.
|
||||
|
||||
*Default*: None, this is required only if fission tallies are
|
||||
requested and the material is fissionable.
|
||||
|
||||
:kappa_fission:
|
||||
This element requires the group-wise kappa-fission cross section ordered by
|
||||
increasing group index (i.e., fast to thermal). If ``representation`` is
|
||||
"isotropic", then the length of this list should equal the number of
|
||||
groups described in the ``groups`` element. If ``representation`` is
|
||||
"angle", then the length of this list should equal the number of groups
|
||||
times the number of azimuthal angles times the number of polar angles,
|
||||
with the inner-dimension being groups, intermediate-dimension being
|
||||
azimuthal angles and outer-dimension being the polar angles.
|
||||
|
||||
*Default*: None, this is required only if kappa_fission tallies are
|
||||
requested and the material is fissionable.
|
||||
|
||||
:chi:
|
||||
This element requires the group-wise fission spectra ordered by
|
||||
increasing group index (i.e., fast to thermal). This element should be
|
||||
used if making the common approximation that the fission spectra does
|
||||
not depend on incoming energy. If the user does not wish to make this
|
||||
approximation, then this should not be provided and this information
|
||||
included in the ``nu_fission`` element instead. If ``representation`` is
|
||||
"isotropic", then the length of this list should equal the number of
|
||||
groups described in the ``groups`` element. If ``representation`` is
|
||||
"angle", then the length of this list should equal the number of groups
|
||||
times the number of azimuthal angles times the number of polar angles,
|
||||
with the inner-dimension being groups, intermediate-dimension being
|
||||
azimuthal angles and outer-dimension being the polar angles.
|
||||
|
||||
*Default*: None, either this element is provided or ``nu_fission`` is
|
||||
provided in fission matrix form, or the material is not fissionable.
|
||||
|
||||
:nu_fission:
|
||||
This element provides either the group-wise fission production cross
|
||||
section vector (i.e., if ``chi`` is provided), or is the group-wise fission
|
||||
production matrix. If providing the vector, it should be ordered the same
|
||||
as the ``fission`` data. If providing the matrix, it should be ordered
|
||||
the same as the ``multiplicity`` matrix.
|
||||
|
||||
*Default*: None, either this element must be provided if the material
|
||||
is fissionable.
|
||||
Data specific to neutron scattering for the temperature <TTT>K
|
||||
|
||||
:Datasets: - **g_min** (*int[]* or *int[][][]*) --
|
||||
Minimum (most energetic) groups with non-zero values of
|
||||
the scattering matrix provided. If `scatter_shape` is
|
||||
"[Order][G][G']" then `g_min` will describe the minimum values
|
||||
of "G'" for each "G"; if `scatter_shape` is "[Order][G'][G]"
|
||||
then `g_min` will describe the minimum values of "G" for each "G'".
|
||||
These group numbers use the standard
|
||||
ordering where the fastest neutron energy group is group 1 while
|
||||
the slowest neutron energy group is group G.
|
||||
The dimensionality of `g_min` is:
|
||||
`g_min[g]`, or `g_min[num_polar][num_azimuthal][g]`.
|
||||
The former is used when `representation` is "isotropic", and the
|
||||
latter when `representation` is "angle".
|
||||
- **g_max** (*int[]* or *int[][][]*) --
|
||||
Similar to `g_min`, except this dataset describes the maximum
|
||||
(least energetic) groups with non-zero values of
|
||||
the scattering matrix.
|
||||
- **scatter_matrix** (*double[]*) -- Flattened representation of the
|
||||
scattering moment matrices. The pre-flattened array corresponds to
|
||||
the shape provied in `scatter_shape`, but if `representation` is
|
||||
"angle" the dimensionality in `scatter_shape` is prepended by
|
||||
"[num_polar][num_azimuthal]" dimensions. The right-most energy
|
||||
group dimension will only include the entries between `g_min` and
|
||||
`g_max`.
|
||||
dimension has a dimensionality of `g_min` to `g_max`.
|
||||
- **multiplicity_matrix** (*double[]*) -- Flattened representation of
|
||||
the scattering moment matrices. This dataset provides the code with
|
||||
a scaling factor to account for neutrons being produced in (n,xn)
|
||||
reactions. This is assumed isotropic and therefore is not repeated
|
||||
for every Legendre moment or histogram/tabular bin. This dataset is
|
||||
optional, if it is not provided no multiplication (i.e., values of
|
||||
1.0) will be assumed.
|
||||
The pre-flattened array is shapes consistent with `scatter_matrix`
|
||||
except the "[Order]" dimension in `scatter_shape` is ignored since
|
||||
this data is assumed isotropic.
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -345,6 +345,7 @@ Functions
|
|||
.. autosummary::
|
||||
:toctree: generated
|
||||
:nosignatures:
|
||||
:template: myfunction.rst
|
||||
|
||||
openmc.model.create_triso_lattice
|
||||
openmc.model.pack_trisos
|
||||
|
|
@ -353,16 +354,6 @@ Functions
|
|||
:mod:`openmc.data` -- Nuclear Data Interface
|
||||
--------------------------------------------
|
||||
|
||||
Physical Data
|
||||
-------------
|
||||
|
||||
.. autosummary::
|
||||
:toctree: generated
|
||||
:nosignatures:
|
||||
:template: myfunction.rst
|
||||
|
||||
openmc.data.atomic_mass
|
||||
|
||||
Core Classes
|
||||
------------
|
||||
|
||||
|
|
@ -375,11 +366,23 @@ Core Classes
|
|||
openmc.data.Reaction
|
||||
openmc.data.Product
|
||||
openmc.data.Tabulated1D
|
||||
openmc.data.FissionEnergyRelease
|
||||
openmc.data.ThermalScattering
|
||||
openmc.data.CoherentElastic
|
||||
openmc.data.FissionEnergyRelease
|
||||
openmc.data.DataLibrary
|
||||
|
||||
Core Functions
|
||||
--------------
|
||||
|
||||
.. autosummary::
|
||||
:toctree: generated
|
||||
:nosignatures:
|
||||
:template: myfunction.rst
|
||||
|
||||
openmc.data.atomic_mass
|
||||
openmc.data.write_compact_458_library
|
||||
|
||||
Angle-Energy Distributions
|
||||
--------------------------
|
||||
|
||||
|
|
@ -393,6 +396,7 @@ Angle-Energy Distributions
|
|||
openmc.data.CorrelatedAngleEnergy
|
||||
openmc.data.UncorrelatedAngleEnergy
|
||||
openmc.data.NBodyPhaseSpace
|
||||
openmc.data.LaboratoryAngleEnergy
|
||||
openmc.data.AngleDistribution
|
||||
openmc.data.EnergyDistribution
|
||||
openmc.data.ArbitraryTabulated
|
||||
|
|
@ -405,6 +409,24 @@ Angle-Energy Distributions
|
|||
openmc.data.LevelInelastic
|
||||
openmc.data.ContinuousTabular
|
||||
|
||||
Resonance Data
|
||||
--------------
|
||||
|
||||
.. autosummary::
|
||||
:toctree: generated
|
||||
:nosignatures:
|
||||
:template: myclass.rst
|
||||
|
||||
openmc.data.Resonances
|
||||
openmc.data.ResonanceRange
|
||||
openmc.data.SingleLevelBreitWigner
|
||||
openmc.data.MultiLevelBreitWigner
|
||||
openmc.data.ReichMoore
|
||||
openmc.data.RMatrixLimited
|
||||
openmc.data.ParticlePair
|
||||
openmc.data.SpinGroup
|
||||
openmc.data.Unresolved
|
||||
|
||||
ACE Format
|
||||
----------
|
||||
|
||||
|
|
@ -425,9 +447,37 @@ Functions
|
|||
.. autosummary::
|
||||
:toctree: generated
|
||||
:nosignatures:
|
||||
:template: myfunction.rst
|
||||
|
||||
openmc.data.ace.ascii_to_binary
|
||||
openmc.data.write_compact_458_library
|
||||
|
||||
ENDF Format
|
||||
-----------
|
||||
|
||||
Classes
|
||||
+++++++
|
||||
|
||||
.. autosummary::
|
||||
:toctree: generated
|
||||
:nosignatures:
|
||||
:template: myclass.rst
|
||||
|
||||
openmc.data.endf.Evaluation
|
||||
|
||||
Functions
|
||||
+++++++++
|
||||
|
||||
.. autosummary::
|
||||
:toctree: generated
|
||||
:nosignatures:
|
||||
:template: myfunction.rst
|
||||
|
||||
openmc.data.endf.float_endf
|
||||
openmc.data.endf.get_cont_record
|
||||
openmc.data.endf.get_head_record
|
||||
openmc.data.endf.get_tab1_record
|
||||
openmc.data.endf.get_tab2_record
|
||||
openmc.data.endf.get_text_record
|
||||
|
||||
.. _Jupyter: https://jupyter.org/
|
||||
.. _NumPy: http://www.numpy.org/
|
||||
|
|
|
|||
|
|
@ -8,6 +8,26 @@ This quick install guide outlines the basic steps needed to install OpenMC on
|
|||
your computer. For more detailed instructions on configuring and installing
|
||||
OpenMC, see :ref:`usersguide_install` in the User's Manual.
|
||||
|
||||
----------------------------------------
|
||||
Installing on Linux/Mac with conda-forge
|
||||
----------------------------------------
|
||||
|
||||
`Conda <http://conda.pydata.org/docs/>`_ is an open source package management
|
||||
system and environment management system for installing multiple versions of
|
||||
software packages and their dependencies and switching easily between them. If
|
||||
you have `conda` installed on your system, OpenMC can be installed via the
|
||||
`conda-forge` channel. First, add the `conda-forge` channel with:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
conda config --add channels conda-forge
|
||||
|
||||
OpenMC can then be installed with:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
conda install openmc
|
||||
|
||||
--------------------------------
|
||||
Installing on Ubuntu through PPA
|
||||
--------------------------------
|
||||
|
|
|
|||
|
|
@ -121,10 +121,13 @@ multi-group mode.
|
|||
``<cutoff>`` Element
|
||||
--------------------
|
||||
|
||||
The ``<cutoff>`` element indicates the weight cutoff used below which particles
|
||||
undergo Russian roulette. Surviving particles are assigned a user-determined
|
||||
weight. Note that weight cutoffs and Russian rouletting are not turned on by
|
||||
default. This element has the following attributes/sub-elements:
|
||||
The ``<cutoff>`` element indicates two kinds of cutoffs. The first is the weight
|
||||
cutoff used below which particles undergo Russian roulette. Surviving particles
|
||||
are assigned a user-determined weight. Note that weight cutoffs and Russian
|
||||
rouletting are not turned on by default. The second is the energy cutoff which
|
||||
is used to kill particles under certain energy. The energy cutoff should not be
|
||||
used unless you know particles under the energy are of no importance to results
|
||||
you care. This element has the following attributes/sub-elements:
|
||||
|
||||
:weight:
|
||||
The weight below which particles undergo Russian roulette.
|
||||
|
|
@ -137,6 +140,11 @@ default. This element has the following attributes/sub-elements:
|
|||
|
||||
*Default*: 1.0
|
||||
|
||||
:energy:
|
||||
The energy under which particles will be killed.
|
||||
|
||||
*Default*: 0.0
|
||||
|
||||
.. _eigenvalue:
|
||||
|
||||
``<eigenvalue>`` Element
|
||||
|
|
@ -709,6 +717,36 @@ survival biasing, otherwise known as implicit capture or absorption.
|
|||
|
||||
*Default*: false
|
||||
|
||||
.. _tabular_legendre:
|
||||
|
||||
``<tabular_legendre>`` Element
|
||||
---------------------------------
|
||||
|
||||
The optional ``<tabular_legendre>`` element specifies how the multi-group
|
||||
Legendre scattering kernel is represented if encountered in a multi-group
|
||||
problem. Specifically, the options are to either convert the Legendre
|
||||
expansion to a tabular representation or leave it as a set of Legendre
|
||||
coefficients. Converting to a tabular representation will cost memory but can
|
||||
allow for a decrease in runtime compared to leaving as a set of Legendre
|
||||
coefficients. This element has the following attributes/sub-elements:
|
||||
|
||||
:enable:
|
||||
This attribute/sub-element denotes whether or not the conversion of a
|
||||
Legendre scattering expansion to the tabular format should be performed or
|
||||
not. A value of “true” means the conversion should be performed, “false”
|
||||
means it will not.
|
||||
|
||||
*Default*: true
|
||||
|
||||
:num_points:
|
||||
If the conversion is to take place the number of tabular points is
|
||||
required. This attribute/sub-element allows the user to set the desired
|
||||
number of points.
|
||||
|
||||
*Default*: 33
|
||||
|
||||
.. note:: This element is only used in the multi-group :ref:`energy_mode`.
|
||||
|
||||
.. _temperature_default:
|
||||
|
||||
``<temperature_default>`` Element
|
||||
|
|
@ -872,6 +910,19 @@ displayed. This element takes the following attributes:
|
|||
|
||||
*Default*: 5
|
||||
|
||||
``<create_fission_neutrons>`` Element
|
||||
-------------------------------------
|
||||
|
||||
The ``<create_fission_neutrons>`` element indicates whether fission neutrons
|
||||
should be created or not. If this element is set to "true", fission neutrons
|
||||
will be created; otherwise the fission is treated as capture and no fission
|
||||
neutron will be created. Note that this option is only applied to fixed source
|
||||
calculation. For eigenvalue calculation, fission will always be treated as real
|
||||
fission.
|
||||
|
||||
*Default*: true
|
||||
|
||||
|
||||
``<volume_calc>`` Element
|
||||
-------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,38 @@
|
|||
Installation and Configuration
|
||||
==============================
|
||||
|
||||
----------------------------------------
|
||||
Installing on Linux/Mac with conda-forge
|
||||
----------------------------------------
|
||||
|
||||
`Conda <http://conda.pydata.org/docs/>`_ is an open source package management
|
||||
system and environment management system for installing multiple versions of
|
||||
software packages and their dependencies and switching easily between
|
||||
them. `conda-forge <https://conda-forge.github.io/>`_ is a community-led conda
|
||||
channel of installable packages. For instructions on installing conda, please
|
||||
consult their `documentation
|
||||
<http://conda.pydata.org/docs/install/quick.html>`_.
|
||||
|
||||
Once you have `conda` installed on your system, add the `conda-forge` channel to
|
||||
your configuration with:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
conda config --add channels conda-forge
|
||||
|
||||
Once the `conda-forge` channel has been enabled, OpenMC can then be installed
|
||||
with:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
conda install openmc
|
||||
|
||||
It is possible to list all of the versions of OpenMC available on your platform with:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
conda search openmc --channel conda-forge
|
||||
|
||||
-----------------------------
|
||||
Installing on Ubuntu with PPA
|
||||
-----------------------------
|
||||
|
|
@ -51,7 +83,7 @@ Prerequisites
|
|||
installed on your machine. Since a number of Fortran 2003/2008 features
|
||||
are used in the code, it is recommended that you use the latest version of
|
||||
whatever compiler you choose. For gfortran_, it is necessary to use
|
||||
version 4.6.0 or above.
|
||||
version 4.8.0 or above.
|
||||
|
||||
If you are using Debian or a Debian derivative such as Ubuntu, you can
|
||||
install the gfortran compiler using the following command::
|
||||
|
|
@ -407,13 +439,11 @@ extract the ACE data, fix any deficiencies, and create an HDF5 library:
|
|||
|
||||
.. code-block:: sh
|
||||
|
||||
cd openmc/data
|
||||
python get_nndc_data.py
|
||||
openmc-get-nndc-data
|
||||
|
||||
At this point, you should set the :envvar:`OPENMC_CROSS_SECTIONS` environment
|
||||
variable to the absolute path of the file
|
||||
``openmc/data/nndc_hdf5/cross_sections.xml``. This cross section set is used by
|
||||
the test suite.
|
||||
variable to the absolute path of the file ``nndc_hdf5/cross_sections.xml``. This
|
||||
cross section set is used by the test suite.
|
||||
|
||||
Using JEFF Cross Sections from OECD/NEA
|
||||
---------------------------------------
|
||||
|
|
@ -424,12 +454,10 @@ and extract the ACE data, fix any deficiencies, and create an HDF5 library.
|
|||
|
||||
.. code-block:: sh
|
||||
|
||||
cd openmc/data
|
||||
python get_jeff_data.py
|
||||
openmc-get-jeff-data
|
||||
|
||||
At this point, you should set the :envvar:`OPENMC_CROSS_SECTIONS` environment
|
||||
variable to the absolute path of the file
|
||||
``openmc/data/jeff-3.2-hdf5/cross_sections.xml``.
|
||||
variable to the absolute path of the file ``jeff-3.2-hdf5/cross_sections.xml``.
|
||||
|
||||
Using Cross Sections from MCNP
|
||||
------------------------------
|
||||
|
|
@ -441,8 +469,7 @@ format, run the following:
|
|||
|
||||
.. code-block:: sh
|
||||
|
||||
cd openmc/data
|
||||
python convert_mcnp_endf70.py /path/to/mcnpdata/
|
||||
openmc-convert-mcnp70-data /path/to/mcnpdata/
|
||||
|
||||
where ``/path/to/mcnpdata`` is the directory containing the ``endf70[a-k]``
|
||||
files.
|
||||
|
|
@ -452,8 +479,7 @@ the following script:
|
|||
|
||||
.. code-block:: sh
|
||||
|
||||
cd openmc/data
|
||||
python convert_mcnp_endf71.py /path/to/mcnpdata
|
||||
openmc-convert-mcnp71-data /path/to/mcnpdata
|
||||
|
||||
where ``/path/to/mcnpdata`` is the directory containing the ``endf71x`` and
|
||||
``ENDF71SaB`` directories.
|
||||
|
|
@ -470,16 +496,16 @@ that are to be converted:
|
|||
|
||||
1. List each ACE library as a positional argument. This is very useful in
|
||||
conjunction with the usual shell utilities (ls, find, etc.).
|
||||
2. Use the --xml option to specify a pre-v0.9 cross_sections.xml file.
|
||||
3. Use the --xsdir option to specify a MCNP xsdir file.
|
||||
4. Use the --xsdata option to specify a Serpent xsdata file.
|
||||
2. Use the ``--xml`` option to specify a pre-v0.9 cross_sections.xml file.
|
||||
3. Use the ``--xsdir` option to specify a MCNP xsdir file.
|
||||
4. Use the ``--xsdata`` option to specify a Serpent xsdata file.
|
||||
|
||||
The script does not use any extra information from cross_sections.xml/ xsdir/
|
||||
xsdata files to determine whether the nuclide is metastable. Instead, the
|
||||
--metastable argument can be used to specify whether the ZAID naming convention
|
||||
follows the NNDC data convention (1000*Z + A + 300 + 100*m), or the MCNP data
|
||||
convention (essentially the same as NNDC, except that the first metastable state
|
||||
of Am242 is 95242 and the ground state is 95642).
|
||||
``--metastable`` argument can be used to specify whether the ZAID naming
|
||||
convention follows the NNDC data convention (1000*Z + A + 300 + 100*m), or the
|
||||
MCNP data convention (essentially the same as NNDC, except that the first
|
||||
metastable state of Am242 is 95242 and the ground state is 95642).
|
||||
|
||||
The ``openmc-ace-to-hdf5`` script has the following command-line flags:
|
||||
|
||||
|
|
|
|||
|
|
@ -21,44 +21,47 @@ groups = openmc.mgxs.EnergyGroups(group_edges=[1E-11, 0.0635E-6, 10.0E-6,
|
|||
# Instantiate the 7-group (C5G7) cross section data
|
||||
uo2_xsdata = openmc.XSdata('UO2', groups)
|
||||
uo2_xsdata.order = 0
|
||||
uo2_xsdata.total = [0.1779492, 0.3298048, 0.4803882, 0.5543674,
|
||||
0.3118013, 0.3951678, 0.5644058]
|
||||
uo2_xsdata.absorption = [8.0248E-03, 3.7174E-03, 2.6769E-02, 9.6236E-02,
|
||||
3.0020E-02, 1.1126E-01, 2.8278E-01]
|
||||
uo2_xsdata.scatter = [[[0.1275370, 0.0423780, 0.0000094, 0.0000000, 0.0000000, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.3244560, 0.0016314, 0.0000000, 0.0000000, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.0000000, 0.4509400, 0.0026792, 0.0000000, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.4525650, 0.0055664, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0001253, 0.2714010, 0.0102550, 0.0000000],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0012968, 0.2658020, 0.0168090],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0085458, 0.2730800]]]
|
||||
uo2_xsdata.fission = [7.21206E-03, 8.19301E-04, 6.45320E-03,
|
||||
1.85648E-02, 1.78084E-02, 8.30348E-02,
|
||||
2.16004E-01]
|
||||
uo2_xsdata.nu_fission = [2.005998E-02, 2.027303E-03, 1.570599E-02,
|
||||
4.518301E-02, 4.334208E-02, 2.020901E-01,
|
||||
5.257105E-01]
|
||||
uo2_xsdata.chi = [5.8791E-01, 4.1176E-01, 3.3906E-04, 1.1761E-07,
|
||||
0.0000E+00, 0.0000E+00, 0.0000E+00]
|
||||
uo2_xsdata.set_total(
|
||||
[0.1779492, 0.3298048, 0.4803882, 0.5543674, 0.3118013, 0.3951678,
|
||||
0.5644058])
|
||||
uo2_xsdata.set_absorption([8.0248E-03, 3.7174E-03, 2.6769E-02, 9.6236E-02,
|
||||
3.0020E-02, 1.1126E-01, 2.8278E-01])
|
||||
uo2_xsdata.set_scatter_matrix(
|
||||
[[[0.1275370, 0.0423780, 0.0000094, 0.0000000, 0.0000000, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.3244560, 0.0016314, 0.0000000, 0.0000000, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.0000000, 0.4509400, 0.0026792, 0.0000000, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.4525650, 0.0055664, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0001253, 0.2714010, 0.0102550, 0.0000000],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0012968, 0.2658020, 0.0168090],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0085458, 0.2730800]]])
|
||||
uo2_xsdata.set_fission([7.21206E-03, 8.19301E-04, 6.45320E-03,
|
||||
1.85648E-02, 1.78084E-02, 8.30348E-02,
|
||||
2.16004E-01])
|
||||
uo2_xsdata.set_nu_fission([2.005998E-02, 2.027303E-03, 1.570599E-02,
|
||||
4.518301E-02, 4.334208E-02, 2.020901E-01,
|
||||
5.257105E-01])
|
||||
uo2_xsdata.set_chi([5.8791E-01, 4.1176E-01, 3.3906E-04, 1.1761E-07, 0.0000E+00,
|
||||
0.0000E+00, 0.0000E+00])
|
||||
|
||||
h2o_xsdata = openmc.XSdata('LWTR', groups)
|
||||
h2o_xsdata.order = 0
|
||||
h2o_xsdata.total = [0.15920605, 0.412969593, 0.59030986, 0.58435,
|
||||
0.718, 1.2544497, 2.650379]
|
||||
h2o_xsdata.absorption = [6.0105E-04, 1.5793E-05, 3.3716E-04,
|
||||
1.9406E-03, 5.7416E-03, 1.5001E-02,
|
||||
3.7239E-02]
|
||||
h2o_xsdata.scatter = [[[0.0444777, 0.1134000, 0.0007235, 0.0000037, 0.0000001, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.2823340, 0.1299400, 0.0006234, 0.0000480, 0.0000074, 0.0000010],
|
||||
[0.0000000, 0.0000000, 0.3452560, 0.2245700, 0.0169990, 0.0026443, 0.0005034],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0910284, 0.4155100, 0.0637320, 0.0121390],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000714, 0.1391380, 0.5118200, 0.0612290],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0022157, 0.6999130, 0.5373200],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.1324400, 2.4807000]]]
|
||||
h2o_xsdata.set_total([0.15920605, 0.412969593, 0.59030986, 0.58435,
|
||||
0.718, 1.2544497, 2.650379])
|
||||
h2o_xsdata.set_absorption([6.0105E-04, 1.5793E-05, 3.3716E-04,
|
||||
1.9406E-03, 5.7416E-03, 1.5001E-02,
|
||||
3.7239E-02])
|
||||
h2o_xsdata.set_scatter_matrix(
|
||||
[[[0.0444777, 0.1134000, 0.0007235, 0.0000037, 0.0000001, 0.0000000, 0.0000000],
|
||||
[0.0000000, 0.2823340, 0.1299400, 0.0006234, 0.0000480, 0.0000074, 0.0000010],
|
||||
[0.0000000, 0.0000000, 0.3452560, 0.2245700, 0.0169990, 0.0026443, 0.0005034],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0910284, 0.4155100, 0.0637320, 0.0121390],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000714, 0.1391380, 0.5118200, 0.0612290],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0022157, 0.6999130, 0.5373200],
|
||||
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.1324400, 2.4807000]]])
|
||||
|
||||
mg_cross_sections_file = openmc.MGXSLibrary(groups)
|
||||
mg_cross_sections_file.add_xsdatas([uo2_xsdata, h2o_xsdata])
|
||||
mg_cross_sections_file.export_to_xml()
|
||||
mg_cross_sections_file.export_to_hdf5()
|
||||
|
||||
|
||||
###############################################################################
|
||||
|
|
@ -129,7 +132,7 @@ geometry.export_to_xml()
|
|||
# Instantiate a Settings object, set all runtime parameters, and export to XML
|
||||
settings_file = openmc.Settings()
|
||||
settings_file.energy_mode = "multi-group"
|
||||
settings_file.cross_sections = "./mgxs.xml"
|
||||
settings_file.cross_sections = "./mgxs.h5"
|
||||
settings_file.batches = batches
|
||||
settings_file.inactive = inactive
|
||||
settings_file.particles = particles
|
||||
|
|
|
|||
|
|
@ -1,383 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<library>
|
||||
<!-- Before getting to the data, set common information -->
|
||||
<groups> 7 </groups>
|
||||
<group_structure>
|
||||
1E-11 0.0635E-6 10.0E-6 1.0E-4 1.0E-3 0.5 1.0 20.0
|
||||
</group_structure>
|
||||
|
||||
<!--
|
||||
Move on to the data. Each <xsdata> has a unique id and label.
|
||||
-->
|
||||
<xsdata>
|
||||
<!-- Meta data for this data -->
|
||||
<name>UO2</name>
|
||||
<alias>UO2</alias>
|
||||
<kT> 2.53E-8 </kT> <!-- in MeV -->
|
||||
<order>0</order>
|
||||
<fissionable>true</fissionable>
|
||||
<!-- Optional (default is isotropic) -->
|
||||
<representation>isotropic</representation>
|
||||
|
||||
<!-- The data itself, like tallies,
|
||||
goes from low energies (groups) to high energies
|
||||
-->
|
||||
<absorption>
|
||||
8.0248E-03 3.7174E-03 2.6769E-02 9.6236E-02 3.0020E-02 1.1126E-01 2.8278E-01
|
||||
</absorption>
|
||||
|
||||
<nu_fission>
|
||||
2.005998E-02 2.027303E-03 1.570599E-02 4.518301E-02 4.334208E-02 2.020901E-01 5.257105E-01
|
||||
</nu_fission>
|
||||
|
||||
<chi>
|
||||
5.8791E-01 4.1176E-01 3.3906E-04 1.1761E-07 0.0000E+00 0.0000E+00 0.0000E+00
|
||||
</chi>
|
||||
<fission>
|
||||
7.21206E-03 8.19301E-04 6.45320E-03 1.85648E-02 1.78084E-02 8.30348E-02 2.16004E-01
|
||||
</fission>
|
||||
|
||||
<!-- units of MeV/cm -->
|
||||
<!-- If no kappa fission tallies, this is not needed; it will not be loaded
|
||||
if there is no kappa fission scores anyways -->
|
||||
<kappa_fission>
|
||||
1.0 1.0 1.0 1.0 1.0 1.0 1.0
|
||||
</kappa_fission>
|
||||
|
||||
<!-- for consistency must include nu-scatter -->
|
||||
<!-- will be a matrix of (order+1) x g_in x g_out -->
|
||||
<scatter>
|
||||
0.1275370 0.0423780 0.0000094 0.0000000 0.0000000 0.0000000 0.0000000
|
||||
0.0000000 0.3244560 0.0016314 0.0000000 0.0000000 0.0000000 0.0000000
|
||||
0.0000000 0.0000000 0.4509400 0.0026792 0.0000000 0.0000000 0.0000000
|
||||
0.0000000 0.0000000 0.0000000 0.4525650 0.0055664 0.0000000 0.0000000
|
||||
0.0000000 0.0000000 0.0000000 0.0001253 0.2714010 0.0102550 0.0000000
|
||||
0.0000000 0.0000000 0.0000000 0.0000000 0.0012968 0.2658020 0.0168090
|
||||
0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0085458 0.2730800
|
||||
</scatter>
|
||||
|
||||
<!-- If total is not provided, it will be calculated.
|
||||
However, in the C5G7 problems, we want to use a transport-corrected value
|
||||
so we dont want to have it be calculated -->
|
||||
<total>
|
||||
0.1779492 0.3298048 0.4803882 0.5543674000000001 0.3118013 0.39516779999999996 0.5644058
|
||||
</total>
|
||||
|
||||
</xsdata>
|
||||
|
||||
<xsdata>
|
||||
<!-- Meta data for this data -->
|
||||
<name>MOX1</name>
|
||||
<alias>MOX1</alias>
|
||||
<kT> 2.53E-8 </kT> <!-- in MeV -->
|
||||
<order>0</order>
|
||||
<fissionable>true</fissionable>
|
||||
|
||||
<!-- The data itself, like tallies,
|
||||
goes from low energies (groups) to high energies
|
||||
-->
|
||||
<absorption>
|
||||
8.4339E-03 3.7577E-03 2.7970E-02 1.0421E-01 1.3994E-01 4.0918E-01 4.0935E-01
|
||||
</absorption>
|
||||
<!--
|
||||
Since chi_vector is false, this will be a matrix
|
||||
Matrix is g_in, g_out.
|
||||
This is to show that you can either use a chi vector + nu_fission vector,
|
||||
like in the UO2 data, or a nu_fission matrix like here.
|
||||
-->
|
||||
<nu_fission>
|
||||
1.27888062E-02 8.95701528E-03 7.37557218E-06 2.55837033E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
1.49041240E-03 1.04385401E-03 8.59552023E-07 2.98153464E-10 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
9.56411400E-03 6.69850756E-03 5.51582469E-06 1.91327830E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
3.84928781E-02 2.69596154E-02 2.21996483E-05 7.70040890E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
1.80629998E-02 1.26509513E-02 1.04173100E-05 3.61346022E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
3.91930789E-01 2.74500216E-01 2.26034688E-04 7.84048241E-08 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
4.19762096E-01 2.93992687E-01 2.42085585E-04 8.39724109E-08 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
</nu_fission>
|
||||
|
||||
<fission>
|
||||
7.62704E-03 8.76898E-04 5.69835E-03 2.28872E-02 1.07635E-02 2.32757E-01 2.48968E-01
|
||||
</fission>
|
||||
|
||||
<!-- units of MeV/cm -->
|
||||
<kappa_fission>
|
||||
1.0 1.0 1.0 1.0 1.0 1.0 1.0
|
||||
</kappa_fission>
|
||||
|
||||
<!-- for consistency must include nu-scatter -->
|
||||
<!-- will be a matrix of (order+1) x g_in x g_out -->
|
||||
<scatter>
|
||||
1.27537000E-01 4.23780000E-02 9.43740000E-06 5.51630000E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 3.24456000E-01 1.63140000E-03 3.14270000E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 4.50940000E-01 2.67920000E-03 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 4.52565000E-01 5.56640000E-03 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 1.25250000E-04 2.71401000E-01 1.02550000E-02 1.00210000E-08
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 1.29680000E-03 2.65802000E-01 1.68090000E-02
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 8.54580000E-03 2.73080000E-01
|
||||
</scatter>
|
||||
|
||||
<total>
|
||||
0.1783583429163 0.3298451031427 0.4815892 0.5623414 0.421721260021 0.6930878 0.6909757999999999
|
||||
</total>
|
||||
|
||||
</xsdata>
|
||||
|
||||
<xsdata>
|
||||
<!-- Meta data for this data -->
|
||||
<name>MOX2</name>
|
||||
<alias>MOX2</alias>
|
||||
<kT> 2.53E-8 </kT> <!-- in MeV -->
|
||||
<order>0</order>
|
||||
<fissionable>true</fissionable>
|
||||
|
||||
<!-- The data itself, like tallies,
|
||||
goes from low energies (groups) to high energies
|
||||
-->
|
||||
<absorption>
|
||||
0.0090657 0.0042967 0.032881 0.12203 0.18298 0.56846 0.58521
|
||||
</absorption>
|
||||
<!--
|
||||
Since chi_vector is false, this will be a matrix
|
||||
Matrix is g_in, g_out !!! Need to get these values looking right to match
|
||||
output of a nu-fission tally with <energy> filter above <energyout> filter
|
||||
-->
|
||||
<nu_fission>
|
||||
1.40004593E-02 9.80563205E-03 8.07435789E-06 2.80075866E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
2.26856185E-03 1.58885378E-03 1.30832709E-06 4.53820413E-10 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
1.41886199E-02 9.93741584E-03 8.18287404E-06 2.83839974E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
5.54788444E-02 3.88562347E-02 3.19958106E-05 1.10984111E-08 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
2.69085702E-02 1.88462058E-02 1.55187355E-05 5.38299559E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
5.45687127E-01 3.82187973E-01 3.14709185E-04 1.09163414E-07 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
6.13307712E-01 4.29548032E-01 3.53707392E-04 1.22690752E-07 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
</nu_fission>
|
||||
|
||||
<fission>
|
||||
0.00825446 0.00132565 0.00842156 0.032873 0.0159636 0.323794 0.362803
|
||||
</fission>
|
||||
|
||||
<!-- units of MeV/cm -->
|
||||
<kappa_fission>
|
||||
1.0 1.0 1.0 1.0 1.0 1.0 1.0
|
||||
</kappa_fission>
|
||||
|
||||
<!-- for consistency must include nu-scatter -->
|
||||
<!-- will be a matrix of (order+1) x g_in x g_out -->
|
||||
<scatter>
|
||||
1.30457000E-01 4.17920000E-02 8.51050000E-06 5.13290000E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 3.28428000E-01 1.64360000E-03 2.20170000E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 4.58371000E-01 2.53310000E-03 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 4.63709000E-01 5.47660000E-03 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 1.76190000E-04 2.82313000E-01 8.72890000E-03 9.00160000E-09
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 2.27600000E-03 2.49751000E-01 1.31140000E-02
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 8.86450000E-03 2.59529000E-01
|
||||
</scatter>
|
||||
|
||||
<total>
|
||||
0.1813232156329 0.3343683022017 0.4937851 0.5912156 0.47419809900160004 0.833601 0.8536035
|
||||
</total>
|
||||
|
||||
</xsdata>
|
||||
|
||||
<xsdata>
|
||||
<!-- Meta data for this data -->
|
||||
<name>MOX3</name>
|
||||
<alias>MOX3</alias>
|
||||
<kT> 2.53E-8 </kT> <!-- in MeV -->
|
||||
<order>0</order>
|
||||
<fissionable>true</fissionable>
|
||||
|
||||
<!-- The data itself, like tallies,
|
||||
goes from low energies (groups) to high energies
|
||||
-->
|
||||
<absorption>
|
||||
9.48620000E-03 4.65560000E-03 3.62400000E-02 1.32720000E-01 2.08400000E-01 6.58700000E-01 6.90170000E-01
|
||||
</absorption>
|
||||
<!--
|
||||
Since chi_vector is false, this will be a matrix
|
||||
Matrix is g_in, g_out !!! Need to get these values looking right to match
|
||||
output of a nu-fission tally with <energy> filter above <energyout> filter
|
||||
-->
|
||||
<nu_fission>
|
||||
1.48071013E-02 1.03705874E-02 8.53956516E-06 2.96212546E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
2.78640474E-03 1.95154023E-03 1.60697792E-06 5.57413653E-10 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
1.73304404E-02 1.21378819E-02 9.99482763E-06 3.46691346E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
6.59928975E-02 4.62200600E-02 3.80594850E-05 1.32017225E-08 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
3.25131926E-02 2.27715674E-02 1.87510386E-05 6.50418701E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
6.32002662E-01 4.42641588E-01 3.64489161E-04 1.26430632E-07 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
7.28595687E-01 5.10293344E-01 4.20196380E-04 1.45753838E-07 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
</nu_fission>
|
||||
|
||||
<fission>
|
||||
8.67209000E-03 1.62426000E-03 1.02716000E-02 3.90447000E-02 1.92576000E-02 3.74888000E-01 4.30599000E-01
|
||||
</fission>
|
||||
|
||||
<!-- units of MeV/cm -->
|
||||
<kappa_fission>
|
||||
1.0 1.0 1.0 1.0 1.0 1.0 1.0
|
||||
</kappa_fission>
|
||||
|
||||
<!-- for consistency must include nu-scatter -->
|
||||
<!-- will be a matrix of (order+1) x g_in x g_out -->
|
||||
<scatter>
|
||||
1.31504000E-01 4.20460000E-02 8.69720000E-06 5.19380000E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 3.30403000E-01 1.64630000E-03 2.60060000E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 4.61792000E-01 2.47490000E-03 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 4.68021000E-01 5.43300000E-03 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 1.85970000E-04 2.85771000E-01 8.39730000E-03 8.92800000E-09
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 2.39160000E-03 2.47614000E-01 1.23220000E-02
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 8.96810000E-03 2.56093000E-01
|
||||
</scatter>
|
||||
|
||||
<total>
|
||||
1.83044902E-01 3.36704903E-01 5.00506900E-01 6.06174000E-01 5.02754279E-01 9.21027600E-01 9.55231100E-01
|
||||
</total>
|
||||
|
||||
</xsdata>
|
||||
|
||||
<xsdata>
|
||||
<!-- Meta data for this data -->
|
||||
<name>FC</name>
|
||||
<alias>FC</alias>
|
||||
<kT> 2.53E-8 </kT> <!-- in MeV -->
|
||||
<order>0</order>
|
||||
<fissionable>true</fissionable>
|
||||
|
||||
<!-- The data itself, like tallies,
|
||||
goes from low energies (groups) to high energies
|
||||
-->
|
||||
<absorption>
|
||||
5.1132E-04 7.5813E-05 3.1643E-04 1.1675E-03 3.3977E-03 9.1886E-03 2.3244E-02
|
||||
</absorption>
|
||||
|
||||
<nu_fission>
|
||||
1.323401E-08 1.434500E-08 1.128599E-06 1.276299E-05 3.538502E-07 1.740099E-06 5.063302E-06
|
||||
</nu_fission>
|
||||
|
||||
<chi>
|
||||
5.8791E-01 4.1176E-01 3.3906E-04 1.1761E-07 0.0000E+00 0.0000E+00 0.0000E+00
|
||||
</chi>
|
||||
|
||||
<fission>
|
||||
4.79002E-09 5.82564E-09 4.63719E-07 5.24406E-06 1.45390E-07 7.14972E-07 2.08041E-06
|
||||
</fission>
|
||||
|
||||
<!-- units of MeV/cm -->
|
||||
<kappa_fission>
|
||||
1.0 1.0 1.0 1.0 1.0 1.0 1.0
|
||||
</kappa_fission>
|
||||
|
||||
<!-- for consistency must include nu-scatter -->
|
||||
<!-- will be a matrix of (order+1) x g_in x g_out -->
|
||||
<scatter>
|
||||
6.61659000E-02 5.90700000E-02 2.83340000E-04 1.46220000E-06 2.06420000E-08 0.00000000E00 0.00000000E00
|
||||
0.00000000E00 2.40377000E-01 5.24350000E-02 2.49900000E-04 1.92390000E-05 2.98750000E-06 4.21400000E-07
|
||||
0.00000000E00 0.00000000E00 1.83425000E-01 9.22880000E-02 6.93650000E-03 1.07900000E-03 2.05430000E-04
|
||||
0.00000000E00 0.00000000E00 0.00000000E00 7.90769000E-02 1.69990000E-01 2.58600000E-02 4.92560000E-03
|
||||
0.00000000E00 0.00000000E00 0.00000000E00 3.73400000E-05 9.97570000E-02 2.06790000E-01 2.44780000E-02
|
||||
0.00000000E00 0.00000000E00 0.00000000E00 0.00000000E00 9.17420000E-04 3.16774000E-01 2.38760000E-01
|
||||
0.00000000E00 0.00000000E00 0.00000000E00 0.00000000E00 0.00000000E00 4.97930000E-02 1.09910000E00
|
||||
</scatter>
|
||||
|
||||
<total>
|
||||
1.26032048E-01 2.93160367E-01 2.84250824E-01 2.81025244E-01 3.34460185E-01 5.65640735E-01 1.17213908E00
|
||||
</total>
|
||||
|
||||
</xsdata>
|
||||
|
||||
<xsdata>
|
||||
<!-- Meta data for this data -->
|
||||
<name>GT</name>
|
||||
<alias>GT</alias>
|
||||
<kT> 2.53E-8 </kT> <!-- in MeV -->
|
||||
<order>0</order>
|
||||
<fissionable>false</fissionable>
|
||||
|
||||
<!-- The data itself, like tallies,
|
||||
goes from low energies (groups) to high energies
|
||||
-->
|
||||
<absorption>
|
||||
5.11320000E-04 7.58010000E-05 3.15720000E-04 1.15820000E-03 3.39750000E-03 9.18780000E-03 2.32420000E-02
|
||||
</absorption>
|
||||
|
||||
<!-- for consistency must include nu-scatter -->
|
||||
<!-- will be a matrix of (order+1) x g_in x g_out -->
|
||||
<scatter>
|
||||
6.61659000E-02 5.90700000E-02 2.83340000E-04 1.46220000E-06 2.06420000E-08 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 2.40377000E-01 5.24350000E-02 2.49900000E-04 1.92390000E-05 2.98750000E-06 4.21400000E-07
|
||||
0.00000000E+00 0.00000000E+00 1.83297000E-01 9.23970000E-02 6.94460000E-03 1.08030000E-03 2.05670000E-04
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 7.88511000E-02 1.70140000E-01 2.58810000E-02 4.92970000E-03
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 3.73330000E-05 9.97372000E-02 2.06790000E-01 2.44780000E-02
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 9.17260000E-04 3.16765000E-01 2.38770000E-01
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 4.97920000E-02 1.09912000E+00
|
||||
</scatter>
|
||||
|
||||
<total>
|
||||
1.26032043E-01 2.93160349E-01 2.84240290E-01 2.80960000E-01 3.34440033E-01 5.65640060E-01 1.17215400E+00
|
||||
</total>
|
||||
</xsdata>
|
||||
|
||||
<xsdata>
|
||||
<!-- Meta data for this data -->
|
||||
<name>LWTR</name>
|
||||
<alias>LWTR</alias>
|
||||
<kT> 2.53E-8 </kT> <!-- in MeV -->
|
||||
<order>0</order>
|
||||
<fissionable>false</fissionable>
|
||||
|
||||
<!-- The data itself, like tallies,
|
||||
goes from low energies (groups) to high energies
|
||||
-->
|
||||
<absorption>
|
||||
6.0105E-04 1.5793E-05 3.3716E-04 1.9406E-03 5.7416E-03 1.5001E-02 3.7239E-02
|
||||
</absorption>
|
||||
|
||||
<!-- for consistency must include nu-scatter -->
|
||||
<!-- will be a matrix of (order+1) x g_in x g_out -->
|
||||
<scatter>
|
||||
0.0444777 0.1134000 0.0007235 0.0000037 0.0000001 0.0000000 0.0000000
|
||||
0.0000000 0.2823340 0.1299400 0.0006234 0.0000480 0.0000074 0.0000010
|
||||
0.0000000 0.0000000 0.3452560 0.2245700 0.0169990 0.0026443 0.0005034
|
||||
0.0000000 0.0000000 0.0000000 0.0910284 0.4155100 0.0637320 0.0121390
|
||||
0.0000000 0.0000000 0.0000000 0.0000714 0.1391380 0.5118200 0.0612290
|
||||
0.0000000 0.0000000 0.0000000 0.0000000 0.0022157 0.6999130 0.5373200
|
||||
0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.1324400 2.4807000
|
||||
</scatter>
|
||||
|
||||
<total>
|
||||
0.15920605 0.41296959299999997 0.59030986 0.5843499999999999 0.7180000000000001 1.2544497000000001 2.650379
|
||||
</total>
|
||||
|
||||
</xsdata>
|
||||
|
||||
<xsdata>
|
||||
<!-- Meta data for this data -->
|
||||
<name>CR</name>
|
||||
<alias>CR</alias>
|
||||
<kT> 2.53E-8 </kT> <!-- in MeV -->
|
||||
<order>0</order>
|
||||
<fissionable>false</fissionable>
|
||||
|
||||
<!-- The data itself, like tallies,
|
||||
goes from low energies (groups) to high energies
|
||||
-->
|
||||
<absorption>
|
||||
1.70490000E-03 8.36224000E-03 8.37901000E-02 3.97797000E-01 6.98763000E-01 9.29508000E-01 1.17836000E+00
|
||||
</absorption>
|
||||
|
||||
<!-- for consistency must include nu-scatter -->
|
||||
<!-- will be a matrix of (order+1) x g_in x g_out -->
|
||||
<scatter>
|
||||
1.70563000E-01 4.44012000E-02 9.83670000E-05 1.27786000E-07 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 4.71050000E-01 6.85480000E-04 3.91395000E-10 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 8.01859000E-01 7.20132000E-04 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 5.70752000E-01 1.46015000E-03 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 6.55562000E-05 2.07838000E-01 3.81486000E-03 3.69760000E-09
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 1.02427000E-03 2.02465000E-01 4.75290000E-03
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 3.53043000E-03 6.58597000E-01
|
||||
</scatter>
|
||||
|
||||
<total>
|
||||
2.16767595E-01 4.80097720E-01 8.86369232E-01 9.70009150E-01 9.10481420E-01 1.13775017E+00 1.84048743E+00
|
||||
</total>
|
||||
</xsdata>
|
||||
</library>
|
||||
BIN
examples/xml/pincell_multigroup/mgxs.h5
Normal file
BIN
examples/xml/pincell_multigroup/mgxs.h5
Normal file
Binary file not shown.
|
|
@ -28,13 +28,12 @@
|
|||
</source>
|
||||
|
||||
<output>
|
||||
<cross_sections>true</cross_sections>
|
||||
<summary>true</summary>
|
||||
<tallies>true</tallies>
|
||||
</output>
|
||||
|
||||
<survival_biasing>false</survival_biasing>
|
||||
|
||||
<cross_sections>./mg_cross_sections.xml</cross_sections>
|
||||
<cross_sections>./mgxs.h5</cross_sections>
|
||||
|
||||
</settings>
|
||||
|
|
|
|||
|
|
@ -2,14 +2,13 @@ import sys
|
|||
import copy
|
||||
from collections import Iterable
|
||||
|
||||
from six import string_types
|
||||
import numpy as np
|
||||
|
||||
import openmc
|
||||
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 = ['+', '-', '*', '/', '^']
|
||||
|
|
@ -86,18 +85,18 @@ class CrossScore(object):
|
|||
@left_score.setter
|
||||
def left_score(self, left_score):
|
||||
cv.check_type('left_score', left_score,
|
||||
(basestring, CrossScore, AggregateScore))
|
||||
string_types + (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, AggregateScore))
|
||||
string_types + (CrossScore, AggregateScore))
|
||||
self._right_score = right_score
|
||||
|
||||
@binary_op.setter
|
||||
def binary_op(self, binary_op):
|
||||
cv.check_type('binary_op', binary_op, basestring)
|
||||
cv.check_type('binary_op', binary_op, string_types)
|
||||
cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS)
|
||||
self._binary_op = binary_op
|
||||
|
||||
|
|
@ -202,7 +201,7 @@ class CrossNuclide(object):
|
|||
|
||||
@binary_op.setter
|
||||
def binary_op(self, binary_op):
|
||||
cv.check_type('binary_op', binary_op, basestring)
|
||||
cv.check_type('binary_op', binary_op, string_types)
|
||||
cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS)
|
||||
self._binary_op = binary_op
|
||||
|
||||
|
|
@ -343,7 +342,7 @@ class CrossFilter(object):
|
|||
|
||||
@binary_op.setter
|
||||
def binary_op(self, binary_op):
|
||||
cv.check_type('binary_op', binary_op, basestring)
|
||||
cv.check_type('binary_op', binary_op, string_types)
|
||||
cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS)
|
||||
self._binary_op = binary_op
|
||||
|
||||
|
|
@ -495,12 +494,12 @@ class AggregateScore(object):
|
|||
|
||||
@scores.setter
|
||||
def scores(self, scores):
|
||||
cv.check_iterable_type('scores', scores, basestring)
|
||||
cv.check_iterable_type('scores', scores, string_types)
|
||||
self._scores = scores
|
||||
|
||||
@aggregate_op.setter
|
||||
def aggregate_op(self, aggregate_op):
|
||||
cv.check_type('aggregate_op', aggregate_op, (basestring, CrossScore))
|
||||
cv.check_type('aggregate_op', aggregate_op, string_types +(CrossScore,))
|
||||
cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS)
|
||||
self._aggregate_op = aggregate_op
|
||||
|
||||
|
|
@ -575,12 +574,12 @@ class AggregateNuclide(object):
|
|||
@nuclides.setter
|
||||
def nuclides(self, nuclides):
|
||||
cv.check_iterable_type('nuclides', nuclides,
|
||||
(basestring, openmc.Nuclide, CrossNuclide))
|
||||
string_types + (openmc.Nuclide, CrossNuclide))
|
||||
self._nuclides = nuclides
|
||||
|
||||
@aggregate_op.setter
|
||||
def aggregate_op(self, aggregate_op):
|
||||
cv.check_type('aggregate_op', aggregate_op, basestring)
|
||||
cv.check_type('aggregate_op', aggregate_op, string_types)
|
||||
cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS)
|
||||
self._aggregate_op = aggregate_op
|
||||
|
||||
|
|
@ -711,7 +710,7 @@ class AggregateFilter(object):
|
|||
|
||||
@aggregate_op.setter
|
||||
def aggregate_op(self, aggregate_op):
|
||||
cv.check_type('aggregate_op', aggregate_op, basestring)
|
||||
cv.check_type('aggregate_op', aggregate_op, string_types)
|
||||
cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS)
|
||||
self._aggregate_op = aggregate_op
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from xml.etree import ElementTree as ET
|
|||
import sys
|
||||
import warnings
|
||||
|
||||
from six import string_types
|
||||
import numpy as np
|
||||
|
||||
import openmc
|
||||
|
|
@ -12,9 +13,6 @@ import openmc.checkvalue as cv
|
|||
from openmc.surface import Halfspace
|
||||
from openmc.region import Region, Intersection, Complement
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
# A static variable for auto-generated Cell IDs
|
||||
AUTO_CELL_ID = 10000
|
||||
|
|
@ -243,7 +241,7 @@ class Cell(object):
|
|||
@name.setter
|
||||
def name(self, name):
|
||||
if name is not None:
|
||||
cv.check_type('cell name', name, basestring)
|
||||
cv.check_type('cell name', name, string_types)
|
||||
self._name = name
|
||||
else:
|
||||
self._name = ''
|
||||
|
|
@ -251,7 +249,7 @@ class Cell(object):
|
|||
@fill.setter
|
||||
def fill(self, fill):
|
||||
if fill is not None:
|
||||
if isinstance(fill, basestring):
|
||||
if isinstance(fill, string_types):
|
||||
if fill.strip().lower() != 'void':
|
||||
msg = 'Unable to set Cell ID="{0}" to use a non-Material ' \
|
||||
'or Universe fill "{1}"'.format(self._id, fill)
|
||||
|
|
@ -336,7 +334,7 @@ class Cell(object):
|
|||
@distribcell_paths.setter
|
||||
def distribcell_paths(self, distribcell_paths):
|
||||
cv.check_iterable_type('distribcell_paths', distribcell_paths,
|
||||
basestring)
|
||||
string_types)
|
||||
self._distribcell_paths = distribcell_paths
|
||||
|
||||
def add_surface(self, surface, halfspace):
|
||||
|
|
|
|||
|
|
@ -15,13 +15,12 @@ from numbers import Real, Integral
|
|||
from xml.etree import ElementTree as ET
|
||||
import sys
|
||||
|
||||
from six import string_types
|
||||
|
||||
from openmc.clean_xml import clean_xml_indentation
|
||||
from openmc.checkvalue import (check_type, check_length, check_value,
|
||||
check_greater_than, check_less_than)
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
class CMFDMesh(object):
|
||||
"""A structured Cartesian mesh used for Coarse Mesh Finite Difference (CMFD)
|
||||
|
|
@ -339,7 +338,7 @@ class CMFD(object):
|
|||
|
||||
@display.setter
|
||||
def display(self, display):
|
||||
check_type('CMFD display', display, basestring)
|
||||
check_type('CMFD display', display, string_types)
|
||||
check_value('CMFD display', display,
|
||||
['balance', 'dominance', 'entropy', 'source'])
|
||||
self._display = display
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ from .reaction import *
|
|||
from .ace import *
|
||||
from .angle_distribution import *
|
||||
from .function import *
|
||||
from .endf import *
|
||||
from .energy_distribution import *
|
||||
from .product import *
|
||||
from .angle_energy import *
|
||||
|
|
@ -15,3 +16,4 @@ from .thermal import *
|
|||
from .urr import *
|
||||
from .library import *
|
||||
from .fission_energy import *
|
||||
from .resonance import *
|
||||
|
|
|
|||
|
|
@ -20,15 +20,12 @@ from os import SEEK_CUR
|
|||
import struct
|
||||
import sys
|
||||
|
||||
from six import string_types
|
||||
import numpy as np
|
||||
|
||||
from openmc.mixin import EqualityMixin
|
||||
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
def ascii_to_binary(ascii_file, binary_file):
|
||||
"""Convert an ACE file in ASCII format (type 1) to binary format (type 2).
|
||||
|
||||
|
|
@ -156,7 +153,7 @@ class Library(EqualityMixin):
|
|||
"""
|
||||
|
||||
def __init__(self, filename, table_names=None, verbose=False):
|
||||
if isinstance(table_names, basestring):
|
||||
if isinstance(table_names, string_types):
|
||||
table_names = [table_names]
|
||||
if table_names is not None:
|
||||
table_names = set(table_names)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
from collections import Iterable
|
||||
from io import StringIO
|
||||
from numbers import Real
|
||||
from warnings import warn
|
||||
|
||||
import numpy as np
|
||||
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.mixin import EqualityMixin
|
||||
from openmc.stats import Univariate, Tabular, Uniform
|
||||
from openmc.stats import Univariate, Tabular, Uniform, Legendre
|
||||
from .function import INTERPOLATION_SCHEME
|
||||
from .endf import get_head_record, get_cont_record, get_tab1_record, \
|
||||
get_list_record, get_tab2_record
|
||||
|
||||
|
||||
class AngleDistribution(EqualityMixin):
|
||||
|
|
@ -199,3 +203,107 @@ class AngleDistribution(EqualityMixin):
|
|||
mu.append(mu_i)
|
||||
|
||||
return cls(energy, mu)
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, ev, mt):
|
||||
"""Generate an angular distribution from an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ev : openmc.data.endf.Evaluation
|
||||
ENDF evaluation
|
||||
mt : int
|
||||
The MT value of the reaction to get angular distributions for
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.AngleDistribution
|
||||
Angular distribution
|
||||
|
||||
"""
|
||||
file_obj = StringIO(ev.section[4, mt])
|
||||
|
||||
# Read HEAD record
|
||||
items = get_head_record(file_obj)
|
||||
lvt = items[2]
|
||||
ltt = items[3]
|
||||
|
||||
# Read CONT record
|
||||
items = get_cont_record(file_obj)
|
||||
li = items[2]
|
||||
nk = items[4]
|
||||
center_of_mass = (items[3] == 2)
|
||||
|
||||
# Check for obsolete energy transformation matrix. If present, just skip
|
||||
# it and keep reading
|
||||
if lvt > 0:
|
||||
warn('Obsolete energy transformation matrix in MF=4 angular '
|
||||
'distribution.')
|
||||
for _ in range((nk + 5)//6):
|
||||
file_obj.readline()
|
||||
|
||||
if ltt == 0 and li == 1:
|
||||
# Purely isotropic
|
||||
energy = np.array([0., ev.info['energy_max']])
|
||||
mu = [Uniform(-1., 1.), Uniform(-1., 1.)]
|
||||
|
||||
elif ltt == 1 and li == 0:
|
||||
# Legendre polynomial coefficients
|
||||
params, tab2 = get_tab2_record(file_obj)
|
||||
n_energy = params[5]
|
||||
|
||||
energy = np.zeros(n_energy)
|
||||
mu = []
|
||||
for i in range(n_energy):
|
||||
items, al = get_list_record(file_obj)
|
||||
temperature = items[0]
|
||||
energy[i] = items[1]
|
||||
coefficients = np.asarray([1.0] + al)
|
||||
mu.append(Legendre(coefficients))
|
||||
|
||||
elif ltt == 2 and li == 0:
|
||||
# Tabulated probability distribution
|
||||
params, tab2 = get_tab2_record(file_obj)
|
||||
n_energy = params[5]
|
||||
|
||||
energy = np.zeros(n_energy)
|
||||
mu = []
|
||||
for i in range(n_energy):
|
||||
params, f = get_tab1_record(file_obj)
|
||||
temperature = params[0]
|
||||
energy[i] = params[1]
|
||||
if f.n_regions > 1:
|
||||
raise NotImplementedError('Angular distribution with multiple '
|
||||
'interpolation regions not supported.')
|
||||
mu.append(Tabular(f.x, f.y, INTERPOLATION_SCHEME[f.interpolation[0]]))
|
||||
|
||||
elif ltt == 3 and li == 0:
|
||||
# Legendre for low energies / tabulated for high energies
|
||||
params, tab2 = get_tab2_record(file_obj)
|
||||
n_energy_legendre = params[5]
|
||||
|
||||
energy_legendre = np.zeros(n_energy_legendre)
|
||||
mu = []
|
||||
for i in range(n_energy_legendre):
|
||||
items, al = get_list_record(file_obj)
|
||||
temperature = items[0]
|
||||
energy_legendre[i] = items[1]
|
||||
coefficients = np.asarray([1.0] + al)
|
||||
mu.append(Legendre(coefficients))
|
||||
|
||||
params, tab2 = get_tab2_record(file_obj)
|
||||
n_energy_tabulated = params[5]
|
||||
|
||||
energy_tabulated = np.zeros(n_energy_tabulated)
|
||||
for i in range(n_energy_tabulated):
|
||||
params, f = get_tab1_record(file_obj)
|
||||
temperature = params[0]
|
||||
energy_tabulated[i] = params[1]
|
||||
if f.n_regions > 1:
|
||||
raise NotImplementedError('Angular distribution with multiple '
|
||||
'interpolation regions not supported.')
|
||||
mu.append(Tabular(f.x, f.y, INTERPOLATION_SCHEME[f.interpolation[0]]))
|
||||
|
||||
energy = np.concatenate((energy_legendre, energy_tabulated))
|
||||
|
||||
return AngleDistribution(energy, mu)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
from abc import ABCMeta, abstractmethod
|
||||
from io import StringIO
|
||||
|
||||
from six import add_metaclass
|
||||
|
||||
import openmc.data
|
||||
from openmc.mixin import EqualityMixin
|
||||
|
||||
|
||||
@add_metaclass(ABCMeta)
|
||||
class AngleEnergy(EqualityMixin):
|
||||
"""Distribution in angle and energy of a secondary particle."""
|
||||
|
||||
__metaclass = ABCMeta
|
||||
|
||||
@abstractmethod
|
||||
def to_hdf5(self, group):
|
||||
pass
|
||||
|
|
@ -40,7 +41,7 @@ class AngleEnergy(EqualityMixin):
|
|||
|
||||
@staticmethod
|
||||
def from_ace(ace, location_dist, location_start, rx=None):
|
||||
"""Generate an AngleEnergy object from ACE data
|
||||
"""Generate an angle-energy distribution from ACE data
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@ from warnings import warn
|
|||
import numpy as np
|
||||
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.stats import Tabular, Univariate, Discrete, Mixture, Uniform
|
||||
from openmc.stats import Tabular, Univariate, Discrete, Mixture, \
|
||||
Uniform, Legendre
|
||||
from .function import INTERPOLATION_SCHEME
|
||||
from .angle_energy import AngleEnergy
|
||||
from .endf import get_list_record, get_tab2_record
|
||||
|
||||
|
||||
class CorrelatedAngleEnergy(AngleEnergy):
|
||||
|
|
@ -405,3 +407,52 @@ class CorrelatedAngleEnergy(AngleEnergy):
|
|||
mu.append(mu_i)
|
||||
|
||||
return cls(breakpoints, interpolation, energy, energy_out, mu)
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, file_obj):
|
||||
"""Generate correlated angle-energy distribution from an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
file_obj : file-like object
|
||||
ENDF file positioned at the start of a section for a correlated
|
||||
angle-energy distribution
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.CorrelatedAngleEnergy
|
||||
Correlated angle-energy distribution
|
||||
|
||||
"""
|
||||
params, tab2 = get_tab2_record(file_obj)
|
||||
lep = params[3]
|
||||
ne = params[5]
|
||||
energy = np.zeros(ne)
|
||||
n_discrete_energies = np.zeros(ne, dtype=int)
|
||||
energy_out = []
|
||||
mu = []
|
||||
for i in range(ne):
|
||||
items, values = get_list_record(file_obj)
|
||||
energy[i] = items[1]
|
||||
n_discrete_energies[i] = items[2]
|
||||
# TODO: separate out discrete lines
|
||||
n_angle = items[3]
|
||||
n_energy_out = items[5]
|
||||
values = np.asarray(values)
|
||||
values.shape = (n_energy_out, n_angle + 2)
|
||||
|
||||
# Outgoing energy distribution at the i-th incoming energy
|
||||
eout_i = values[:,0]
|
||||
eout_p_i = values[:,1]
|
||||
energy_out_i = Tabular(eout_i, eout_p_i, INTERPOLATION_SCHEME[lep],
|
||||
ignore_negative=True)
|
||||
energy_out.append(energy_out_i)
|
||||
|
||||
# Legendre coefficients used for angular distributions
|
||||
mu_i = []
|
||||
for j in range(n_energy_out):
|
||||
mu_i.append(Legendre(values[j,1:]))
|
||||
mu.append(mu_i)
|
||||
|
||||
return cls(tab2.breakpoints, tab2.interpolation, energy,
|
||||
energy_out, mu)
|
||||
|
|
|
|||
|
|
@ -104,8 +104,8 @@ NATURAL_ABUNDANCE = {
|
|||
'U234': 5.4e-05, 'U235': 0.007204, 'U238': 0.992742
|
||||
}
|
||||
|
||||
ATOMIC_SYMBOL = {1: 'H', 2: 'He', 3: 'Li', 4: 'Be', 5: 'B', 6: 'C', 7: 'N',
|
||||
8: 'O', 9: 'F', 10: 'Ne', 11: 'Na', 12: 'Mg', 13: 'Al',
|
||||
ATOMIC_SYMBOL = {0: 'n', 1: 'H', 2: 'He', 3: 'Li', 4: 'Be', 5: 'B', 6: 'C',
|
||||
7: 'N', 8: 'O', 9: 'F', 10: 'Ne', 11: 'Na', 12: 'Mg', 13: 'Al',
|
||||
14: 'Si', 15: 'P', 16: 'S', 17: 'Cl', 18: 'Ar', 19: 'K',
|
||||
20: 'Ca', 21: 'Sc', 22: 'Ti', 23: 'V', 24: 'Cr', 25: 'Mn',
|
||||
26: 'Fe', 27: 'Co', 28: 'Ni', 29: 'Cu', 30: 'Zn', 31: 'Ga',
|
||||
|
|
@ -129,60 +129,6 @@ ATOMIC_NUMBER = {value: key for key, value in ATOMIC_SYMBOL.items()}
|
|||
|
||||
_ATOMIC_MASS = {}
|
||||
|
||||
REACTION_NAME = {1: '(n,total)', 2: '(n,elastic)', 4: '(n,level)',
|
||||
5: '(n,misc)', 11: '(n,2nd)', 16: '(n,2n)', 17: '(n,3n)',
|
||||
18: '(n,fission)', 19: '(n,f)', 20: '(n,nf)', 21: '(n,2nf)',
|
||||
22: '(n,na)', 23: '(n,n3a)', 24: '(n,2na)', 25: '(n,3na)',
|
||||
27: '(n,absorption)', 28: '(n,np)', 29: '(n,n2a)',
|
||||
30: '(n,2n2a)', 32: '(n,nd)', 33: '(n,nt)', 34: '(n,nHe-3)',
|
||||
35: '(n,nd2a)', 36: '(n,nt2a)', 37: '(n,4n)', 38: '(n,3nf)',
|
||||
41: '(n,2np)', 42: '(n,3np)', 44: '(n,n2p)', 45: '(n,npa)',
|
||||
91: '(n,nc)', 101: '(n,disappear)', 102: '(n,gamma)',
|
||||
103: '(n,p)', 104: '(n,d)', 105: '(n,t)', 106: '(n,3He)',
|
||||
107: '(n,a)', 108: '(n,2a)', 109: '(n,3a)', 111: '(n,2p)',
|
||||
112: '(n,pa)', 113: '(n,t2a)', 114: '(n,d2a)', 115: '(n,pd)',
|
||||
116: '(n,pt)', 117: '(n,da)', 152: '(n,5n)', 153: '(n,6n)',
|
||||
154: '(n,2nt)', 155: '(n,ta)', 156: '(n,4np)', 157: '(n,3nd)',
|
||||
158: '(n,nda)', 159: '(n,2npa)', 160: '(n,7n)', 161: '(n,8n)',
|
||||
162: '(n,5np)', 163: '(n,6np)', 164: '(n,7np)', 165: '(n,4na)',
|
||||
166: '(n,5na)', 167: '(n,6na)', 168: '(n,7na)', 169: '(n,4nd)',
|
||||
170: '(n,5nd)', 171: '(n,6nd)', 172: '(n,3nt)', 173: '(n,4nt)',
|
||||
174: '(n,5nt)', 175: '(n,6nt)', 176: '(n,2n3He)',
|
||||
177: '(n,3n3He)', 178: '(n,4n3He)', 179: '(n,3n2p)',
|
||||
180: '(n,3n3a)', 181: '(n,3npa)', 182: '(n,dt)',
|
||||
183: '(n,npd)', 184: '(n,npt)', 185: '(n,ndt)',
|
||||
186: '(n,np3He)', 187: '(n,nd3He)', 188: '(n,nt3He)',
|
||||
189: '(n,nta)', 190: '(n,2n2p)', 191: '(n,p3He)',
|
||||
192: '(n,d3He)', 193: '(n,3Hea)', 194: '(n,4n2p)',
|
||||
195: '(n,4n2a)', 196: '(n,4npa)', 197: '(n,3p)',
|
||||
198: '(n,n3p)', 199: '(n,3n2pa)', 200: '(n,5n2p)', 444: '(n,damage)',
|
||||
649: '(n,pc)', 699: '(n,dc)', 749: '(n,tc)', 799: '(n,3Hec)',
|
||||
849: '(n,ac)'}
|
||||
REACTION_NAME.update({i: '(n,n{})'.format(i-50) for i in range(50, 91)})
|
||||
REACTION_NAME.update({i: '(n,p{})'.format(i-600) for i in range(600, 649)})
|
||||
REACTION_NAME.update({i: '(n,d{})'.format(i-650) for i in range(650, 699)})
|
||||
REACTION_NAME.update({i: '(n,t{})'.format(i-700) for i in range(700, 749)})
|
||||
REACTION_NAME.update({i: '(n,3He{})'.format(i-750) for i in range(750, 799)})
|
||||
REACTION_NAME.update({i: '(n,a{})'.format(i-800) for i in range(800, 849)})
|
||||
|
||||
SUM_RULES = {1: [2, 3],
|
||||
3: [4, 5, 11, 16, 17, 22, 23, 24, 25, 27, 28, 29, 30, 32, 33, 34, 35,
|
||||
36, 37, 41, 42, 44, 45, 152, 153, 154, 156, 157, 158, 159, 160,
|
||||
161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172,
|
||||
173, 174, 175, 176, 177, 178, 179, 180, 181, 183, 184, 185,
|
||||
186, 187, 188, 189, 190, 194, 195, 196, 198, 199, 200],
|
||||
4: list(range(50, 92)),
|
||||
16: list(range(875, 892)),
|
||||
18: [19, 20, 21, 38],
|
||||
27: [18, 101],
|
||||
101: [102, 103, 104, 105, 106, 107, 108, 109, 111, 112, 113, 114,
|
||||
115, 116, 117, 155, 182, 191, 192, 193, 197],
|
||||
103: list(range(600, 650)),
|
||||
104: list(range(650, 700)),
|
||||
105: list(range(700, 750)),
|
||||
106: list(range(750, 800)),
|
||||
107: list(range(800, 850))}
|
||||
|
||||
|
||||
def atomic_mass(isotope):
|
||||
"""Return atomic mass of isotope in atomic mass units.
|
||||
|
|
@ -207,7 +153,7 @@ def atomic_mass(isotope):
|
|||
mass_file = os.path.join(os.path.dirname(__file__), 'mass.mas12')
|
||||
with open(mass_file, 'r') as ame:
|
||||
# Read lines in file starting at line 40
|
||||
for line in itertools.islice(ame, 40, None):
|
||||
for line in itertools.islice(ame, 39, None):
|
||||
name = '{}{}'.format(line[20:22].strip(), int(line[16:19]))
|
||||
mass = float(line[96:99]) + 1e-6*float(
|
||||
line[100:106] + '.' + line[107:112])
|
||||
|
|
|
|||
419
openmc/data/endf.py
Normal file
419
openmc/data/endf.py
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
"""Module for parsing and manipulating data from ENDF evaluations.
|
||||
|
||||
All the classes and functions in this module are based on document
|
||||
ENDF-102 titled "Data Formats and Procedures for the Evaluated Nuclear
|
||||
Data File ENDF-6". The latest version from June 2009 can be found at
|
||||
http://www-nds.iaea.org/ndspub/documents/endf/endf102/endf102.pdf
|
||||
|
||||
"""
|
||||
from __future__ import print_function, division, unicode_literals
|
||||
|
||||
import io
|
||||
import re
|
||||
import os
|
||||
from math import pi
|
||||
from collections import OrderedDict, Iterable
|
||||
|
||||
import numpy as np
|
||||
from numpy.polynomial.polynomial import Polynomial
|
||||
|
||||
from .function import Tabulated1D, INTERPOLATION_SCHEME
|
||||
from openmc.stats.univariate import Uniform, Tabular, Legendre
|
||||
|
||||
|
||||
LIBRARIES = {0: 'ENDF/B', 1: 'ENDF/A', 2: 'JEFF', 3: 'EFF',
|
||||
4: 'ENDF/B High Energy', 5: 'CENDL', 6: 'JENDL',
|
||||
31: 'INDL/V', 32: 'INDL/A', 33: 'FENDL', 34: 'IRDF',
|
||||
35: 'BROND', 36: 'INGDB-90', 37: 'FENDL/A', 41: 'BROND'}
|
||||
|
||||
SUM_RULES = {1: [2, 3],
|
||||
3: [4, 5, 11, 16, 17, 22, 23, 24, 25, 28, 29, 30, 32, 33, 34, 35,
|
||||
36, 37, 41, 42, 44, 45, 152, 153, 154, 156, 157, 158, 159, 160,
|
||||
161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172,
|
||||
173, 174, 175, 176, 177, 178, 179, 180, 181, 183, 184, 185,
|
||||
186, 187, 188, 189, 190, 194, 195, 196, 198, 199, 200],
|
||||
4: list(range(50, 92)),
|
||||
16: list(range(875, 892)),
|
||||
18: [19, 20, 21, 38],
|
||||
27: [8, 101],
|
||||
101: [102, 103, 104, 105, 106, 107, 108, 109, 111, 112, 113, 114,
|
||||
115, 116, 117, 155, 182, 191, 192, 193, 197],
|
||||
103: list(range(600, 650)),
|
||||
104: list(range(650, 700)),
|
||||
105: list(range(700, 750)),
|
||||
106: list(range(750, 800)),
|
||||
107: list(range(800, 850))}
|
||||
|
||||
_ENDF_FLOAT_RE = re.compile(r'([\s\-\+]?\d*\.\d+)([\+\-]\d+)')
|
||||
|
||||
|
||||
def radiation_type(value):
|
||||
p = {0: 'gamma', 1: 'beta-', 2: 'ec/beta+', 3: 'IT',
|
||||
4: 'alpha', 5: 'neutron', 6: 'sf', 7: 'proton',
|
||||
8: 'e-', 9: 'xray', 10: 'unknown'}
|
||||
if value % 1.0 == 0:
|
||||
return p[int(value)]
|
||||
else:
|
||||
return (p[int(value)], p[int(10*value % 10)])
|
||||
|
||||
|
||||
def float_endf(s):
|
||||
"""Convert string of floating point number in ENDF to float.
|
||||
|
||||
The ENDF-6 format uses an 'e-less' floating point number format,
|
||||
e.g. -1.23481+10. Trying to convert using the float built-in won't work
|
||||
because of the lack of an 'e'. This function allows such strings to be
|
||||
converted while still allowing numbers that are not in exponential notation
|
||||
to be converted as well.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
s : str
|
||||
Floating-point number from an ENDF file
|
||||
|
||||
Returns
|
||||
-------
|
||||
float
|
||||
The number
|
||||
|
||||
"""
|
||||
return float(_ENDF_FLOAT_RE.sub(r'\1e\2', s))
|
||||
|
||||
|
||||
def get_text_record(file_obj):
|
||||
"""Return data from a TEXT record in an ENDF-6 file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
file_obj : file-like object
|
||||
ENDF-6 file to read from
|
||||
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
Text within the TEXT record
|
||||
|
||||
"""
|
||||
return file_obj.readline()[:66]
|
||||
|
||||
|
||||
def get_cont_record(file_obj, skipC=False):
|
||||
"""Return data from a CONT record in an ENDF-6 file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
file_obj : file-like object
|
||||
ENDF-6 file to read from
|
||||
skipC : bool
|
||||
Determine whether to skip the first two quantities (C1, C2) of the CONT
|
||||
record.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list
|
||||
The six items within the CONT record
|
||||
|
||||
"""
|
||||
line = file_obj.readline()
|
||||
if skipC:
|
||||
C1 = None
|
||||
C2 = None
|
||||
else:
|
||||
C1 = float_endf(line[:11])
|
||||
C2 = float_endf(line[11:22])
|
||||
L1 = int(line[22:33])
|
||||
L2 = int(line[33:44])
|
||||
N1 = int(line[44:55])
|
||||
N2 = int(line[55:66])
|
||||
return [C1, C2, L1, L2, N1, N2]
|
||||
|
||||
|
||||
def get_head_record(file_obj):
|
||||
"""Return data from a HEAD record in an ENDF-6 file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
file_obj : file-like object
|
||||
ENDF-6 file to read from
|
||||
|
||||
Returns
|
||||
-------
|
||||
list
|
||||
The six items within the HEAD record
|
||||
|
||||
"""
|
||||
line = file_obj.readline()
|
||||
ZA = int(float_endf(line[:11]))
|
||||
AWR = float_endf(line[11:22])
|
||||
L1 = int(line[22:33])
|
||||
L2 = int(line[33:44])
|
||||
N1 = int(line[44:55])
|
||||
N2 = int(line[55:66])
|
||||
return [ZA, AWR, L1, L2, N1, N2]
|
||||
|
||||
|
||||
def get_list_record(file_obj):
|
||||
"""Return data from a LIST record in an ENDF-6 file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
file_obj : file-like object
|
||||
ENDF-6 file to read from
|
||||
|
||||
Returns
|
||||
-------
|
||||
list
|
||||
The six items within the header
|
||||
list
|
||||
The values within the list
|
||||
|
||||
"""
|
||||
# determine how many items are in list
|
||||
items = get_cont_record(file_obj)
|
||||
NPL = items[4]
|
||||
|
||||
# read items
|
||||
b = []
|
||||
for i in range((NPL - 1)//6 + 1):
|
||||
line = file_obj.readline()
|
||||
n = min(6, NPL - 6*i)
|
||||
for j in range(n):
|
||||
b.append(float_endf(line[11*j:11*(j + 1)]))
|
||||
|
||||
return (items, b)
|
||||
|
||||
|
||||
def get_tab1_record(file_obj):
|
||||
"""Return data from a TAB1 record in an ENDF-6 file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
file_obj : file-like object
|
||||
ENDF-6 file to read from
|
||||
|
||||
Returns
|
||||
-------
|
||||
list
|
||||
The six items within the header
|
||||
openmc.data.Tabulated1D
|
||||
The tabulated function
|
||||
|
||||
"""
|
||||
# Determine how many interpolation regions and total points there are
|
||||
line = file_obj.readline()
|
||||
C1 = float_endf(line[:11])
|
||||
C2 = float_endf(line[11:22])
|
||||
L1 = int(line[22:33])
|
||||
L2 = int(line[33:44])
|
||||
n_regions = int(line[44:55])
|
||||
n_pairs = int(line[55:66])
|
||||
params = [C1, C2, L1, L2]
|
||||
|
||||
# Read the interpolation region data, namely NBT and INT
|
||||
breakpoints = np.zeros(n_regions, dtype=int)
|
||||
interpolation = np.zeros(n_regions, dtype=int)
|
||||
m = 0
|
||||
for i in range((n_regions - 1)//3 + 1):
|
||||
line = file_obj.readline()
|
||||
to_read = min(3, n_regions - m)
|
||||
for j in range(to_read):
|
||||
breakpoints[m] = int(line[0:11])
|
||||
interpolation[m] = int(line[11:22])
|
||||
line = line[22:]
|
||||
m += 1
|
||||
|
||||
# Read tabulated pairs x(n) and y(n)
|
||||
x = np.zeros(n_pairs)
|
||||
y = np.zeros(n_pairs)
|
||||
m = 0
|
||||
for i in range((n_pairs - 1)//3 + 1):
|
||||
line = file_obj.readline()
|
||||
to_read = min(3, n_pairs - m)
|
||||
for j in range(to_read):
|
||||
x[m] = float_endf(line[:11])
|
||||
y[m] = float_endf(line[11:22])
|
||||
line = line[22:]
|
||||
m += 1
|
||||
|
||||
return params, Tabulated1D(x, y, breakpoints, interpolation)
|
||||
|
||||
|
||||
def get_tab2_record(file_obj):
|
||||
# Determine how many interpolation regions and total points there are
|
||||
params = get_cont_record(file_obj)
|
||||
n_regions = params[4]
|
||||
|
||||
# Read the interpolation region data, namely NBT and INT
|
||||
breakpoints = np.zeros(n_regions, dtype=int)
|
||||
interpolation = np.zeros(n_regions, dtype=int)
|
||||
m = 0
|
||||
for i in range((n_regions - 1)//3 + 1):
|
||||
line = file_obj.readline()
|
||||
to_read = min(3, n_regions - m)
|
||||
for j in range(to_read):
|
||||
breakpoints[m] = int(line[0:11])
|
||||
interpolation[m] = int(line[11:22])
|
||||
line = line[22:]
|
||||
m += 1
|
||||
|
||||
return params, Tabulated2D(breakpoints, interpolation)
|
||||
|
||||
|
||||
class Evaluation(object):
|
||||
"""ENDF material evaluation with multiple files/sections
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str
|
||||
Path to ENDF file to read
|
||||
|
||||
Attributes
|
||||
----------
|
||||
info : dict
|
||||
Miscallaneous information about the evaluation.
|
||||
target : dict
|
||||
Information about the target material, such as its mass, isomeric state,
|
||||
whether it's stable, and whether it's fissionable.
|
||||
projectile : dict
|
||||
Information about the projectile such as its mass.
|
||||
reaction_list : list of 4-tuples
|
||||
List of sections in the evaluation. The entries of the tuples are the
|
||||
file (MF), section (MT), number of records (NC), and modification
|
||||
indicator (MOD).
|
||||
|
||||
"""
|
||||
def __init__(self, filename):
|
||||
fh = open(filename, 'r')
|
||||
self.section = {}
|
||||
self.info = {}
|
||||
self.target = {}
|
||||
self.projectile = {}
|
||||
self.reaction_list = []
|
||||
|
||||
# Determine MAT number for this evaluation
|
||||
MF = 0
|
||||
while MF == 0:
|
||||
position = fh.tell()
|
||||
line = fh.readline()
|
||||
MF = int(line[70:72])
|
||||
self.material = int(line[66:70])
|
||||
fh.seek(position)
|
||||
|
||||
while True:
|
||||
# Find next section
|
||||
while True:
|
||||
position = fh.tell()
|
||||
line = fh.readline()
|
||||
MAT = int(line[66:70])
|
||||
MF = int(line[70:72])
|
||||
MT = int(line[72:75])
|
||||
if MT > 0 or MAT == 0:
|
||||
fh.seek(position)
|
||||
break
|
||||
|
||||
# If end of material reached, exit loop
|
||||
if MAT == 0:
|
||||
break
|
||||
|
||||
section_data = ''
|
||||
while True:
|
||||
line = fh.readline()
|
||||
if line[72:75] == ' 0':
|
||||
break
|
||||
else:
|
||||
section_data += line
|
||||
self.section[MF, MT] = section_data
|
||||
|
||||
self._read_header()
|
||||
|
||||
def _read_header(self):
|
||||
file_obj = io.StringIO(self.section[1, 451])
|
||||
|
||||
# Information about target/projectile
|
||||
items = get_head_record(file_obj)
|
||||
self.target['atomic_number'] = items[0] // 1000
|
||||
self.target['mass_number'] = items[0] % 1000
|
||||
self.target['mass'] = items[1]
|
||||
self._LRP = items[2]
|
||||
self.target['fissionable'] = (items[3] == 1)
|
||||
try:
|
||||
global LIBRARIES
|
||||
library = LIBRARIES[items[4]]
|
||||
except KeyError:
|
||||
library = 'Unknown'
|
||||
self.info['modification'] = items[5]
|
||||
|
||||
# Control record 1
|
||||
items = get_cont_record(file_obj)
|
||||
self.target['excitation_energy'] = items[0]
|
||||
self.target['stable'] = (int(items[1]) == 0)
|
||||
self.target['state'] = items[2]
|
||||
self.target['isomeric_state'] = items[3]
|
||||
self.info['format'] = items[5]
|
||||
assert self.info['format'] == 6
|
||||
|
||||
# Control record 2
|
||||
items = get_cont_record(file_obj)
|
||||
self.projectile['mass'] = items[0]
|
||||
self.info['energy_max'] = items[1]
|
||||
library_release = items[2]
|
||||
self.info['sublibrary'] = items[4]
|
||||
library_version = items[5]
|
||||
self.info['library'] = (library, library_version, library_release)
|
||||
|
||||
# Control record 3
|
||||
items = get_cont_record(file_obj)
|
||||
self.target['temperature'] = items[0]
|
||||
self.info['derived'] = (items[2] > 0)
|
||||
NWD = items[4]
|
||||
NXC = items[5]
|
||||
|
||||
# Text records
|
||||
text = [get_text_record(file_obj) for i in range(NWD)]
|
||||
if len(text) >= 5:
|
||||
self.target['zsymam'] = text[0][0:11]
|
||||
self.info['laboratory'] = text[0][11:22]
|
||||
self.info['date'] = text[0][22:32]
|
||||
self.info['author'] = text[0][32:66]
|
||||
self.info['reference'] = text[1][1:22]
|
||||
self.info['date_distribution'] = text[1][22:32]
|
||||
self.info['date_release'] = text[1][33:43]
|
||||
self.info['date_entry'] = text[1][55:63]
|
||||
self.info['identifier'] = text[2:5]
|
||||
self.info['description'] = text[5:]
|
||||
|
||||
# File numbers, reaction designations, and number of records
|
||||
for i in range(NXC):
|
||||
line = file_obj.readline()
|
||||
mf = int(line[22:33])
|
||||
mt = int(line[33:44])
|
||||
nc = int(line[44:55])
|
||||
try:
|
||||
mod = int(line[55:66])
|
||||
except ValueError:
|
||||
# In JEFF 3.2, a few isotopes of U have MOD values that are
|
||||
# missing. This prevents failure on these isotopes.
|
||||
mod = 0
|
||||
self.reaction_list.append((mf, mt, nc, mod))
|
||||
|
||||
|
||||
class Tabulated2D(object):
|
||||
"""Metadata for a two-dimensional function.
|
||||
|
||||
This is a dummy class that is not really used other than to store the
|
||||
interpolation information for a two-dimensional function. Once we refactor
|
||||
to adopt GND-like data containers, this will probably be removed or
|
||||
extended.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
breakpoints : Iterable of int
|
||||
Breakpoints for interpolation regions
|
||||
interpolation : Iterable of int
|
||||
Interpolation scheme identification number, e.g., 3 means y is linear in
|
||||
ln(x).
|
||||
|
||||
"""
|
||||
def __init__(self, breakpoints, interpolation):
|
||||
self.breakpoints = breakpoints
|
||||
self.interpolation = interpolation
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
"""This module contains a few utility functions for reading ENDF_ data. It is by
|
||||
no means enough to read an entire ENDF file. For a more complete ENDF reader,
|
||||
see Pyne_.
|
||||
|
||||
.. _ENDF: http://www.nndc.bnl.gov/endf
|
||||
.. _Pyne: http://www.pyne.io
|
||||
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
def read_float(float_string):
|
||||
"""Parse ENDF 6E11.0 formatted string into a float."""
|
||||
assert len(float_string) == 11
|
||||
pattern = r'([\s\-]\d+\.\d+)([\+\-]\d+)'
|
||||
return float(re.sub(pattern, r'\1e\2', float_string))
|
||||
|
||||
|
||||
def read_CONT_line(line):
|
||||
"""Parse 80-column line from ENDF CONT record into floats and ints."""
|
||||
return (read_float(line[0:11]), read_float(line[11:22]), int(line[22:33]),
|
||||
int(line[33:44]), int(line[44:55]), int(line[55:66]),
|
||||
int(line[66:70]), int(line[70:72]), int(line[72:75]),
|
||||
int(line[75:80]))
|
||||
|
||||
|
||||
def identify_nuclide(fname):
|
||||
"""Read the header of an ENDF file and extract identifying information."""
|
||||
with open(fname, 'r') as fh:
|
||||
# Skip the tape id (TPID).
|
||||
line = fh.readline()
|
||||
|
||||
# Read the first HEAD and CONT info.
|
||||
line = fh.readline()
|
||||
ZA, AW, LRP, LFI, NLIB, NMOD, MAT, MF, MT, NS = read_CONT_line(line)
|
||||
line = fh.readline()
|
||||
ELIS, STA, LIS, LISO, junk, NFOR, MAT, MF, MT, NS = read_CONT_line(line)
|
||||
|
||||
# Return dictionary of the most important identifying information.
|
||||
return {'Z': int(ZA) // 1000,
|
||||
'A': int(ZA) % 1000,
|
||||
'LFI': bool(LFI),
|
||||
'LIS': LIS,
|
||||
'LISO': LISO}
|
||||
|
|
@ -3,19 +3,19 @@ from collections import Iterable
|
|||
from numbers import Integral, Real
|
||||
from warnings import warn
|
||||
|
||||
from six import add_metaclass
|
||||
import numpy as np
|
||||
|
||||
from .function import Tabulated1D, INTERPOLATION_SCHEME
|
||||
from openmc.stats.univariate import Univariate, Tabular, Discrete, Mixture
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.mixin import EqualityMixin
|
||||
from .endf import get_tab1_record, get_tab2_record
|
||||
|
||||
|
||||
@add_metaclass(ABCMeta)
|
||||
class EnergyDistribution(EqualityMixin):
|
||||
"""Abstract superclass for all energy distributions."""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
|
@ -57,6 +57,40 @@ class EnergyDistribution(EqualityMixin):
|
|||
raise ValueError("Unknown energy distribution type: {}"
|
||||
.format(energy_type))
|
||||
|
||||
@staticmethod
|
||||
def from_endf(file_obj, params):
|
||||
"""Generate energy distribution from an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
file_obj : file-like object
|
||||
ENDF file positioned at the start of a section for an energy
|
||||
distribution.
|
||||
params : list
|
||||
List of parameters at the start of the energy distribution that
|
||||
includes the LF value indicating what type of energy distribution is
|
||||
present.
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.EnergyDistribution
|
||||
A sub-class of :class:`openmc.data.EnergyDistribution`
|
||||
|
||||
"""
|
||||
lf = params[3]
|
||||
if lf == 1:
|
||||
return ArbitraryTabulated.from_endf(file_obj, params)
|
||||
elif lf == 5:
|
||||
return GeneralEvaporation.from_endf(file_obj, params)
|
||||
elif lf == 7:
|
||||
return MaxwellEnergy.from_endf(file_obj, params)
|
||||
elif lf == 9:
|
||||
return Evaporation.from_endf(file_obj, params)
|
||||
elif lf == 11:
|
||||
return WattEnergy.from_endf(file_obj, params)
|
||||
elif lf == 12:
|
||||
return MadlandNix.from_endf(file_obj, params)
|
||||
|
||||
|
||||
class ArbitraryTabulated(EnergyDistribution):
|
||||
r"""Arbitrary tabulated function given in ENDF MF=5, LF=1 represented as
|
||||
|
|
@ -88,6 +122,37 @@ class ArbitraryTabulated(EnergyDistribution):
|
|||
def to_hdf5(self, group):
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, file_obj, params):
|
||||
"""Generate arbitrary tabulated distribution from an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
file_obj : file-like object
|
||||
ENDF file positioned at the start of a section for an energy
|
||||
distribution.
|
||||
params : list
|
||||
List of parameters at the start of the energy distribution that
|
||||
includes the LF value indicating what type of energy distribution is
|
||||
present.
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.ArbitraryTabulated
|
||||
Arbitrary tabulated distribution
|
||||
|
||||
"""
|
||||
params, tab2 = get_tab2_record(file_obj)
|
||||
n_energies = params[5]
|
||||
|
||||
energy = np.zeros(n_energies)
|
||||
pdf = []
|
||||
for j in range(n_energies):
|
||||
params, func = get_tab1_record(file_obj)
|
||||
energy[j] = params[1]
|
||||
pdf.append(func)
|
||||
return cls(energy, pdf)
|
||||
|
||||
|
||||
class GeneralEvaporation(EnergyDistribution):
|
||||
r"""General evaporation spectrum given in ENDF MF=5, LF=5 represented as
|
||||
|
|
@ -130,6 +195,31 @@ class GeneralEvaporation(EnergyDistribution):
|
|||
def from_ace(cls, ace, idx=0):
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, file_obj, params):
|
||||
"""Generate general evaporation spectrum from an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
file_obj : file-like object
|
||||
ENDF file positioned at the start of a section for an energy
|
||||
distribution.
|
||||
params : list
|
||||
List of parameters at the start of the energy distribution that
|
||||
includes the LF value indicating what type of energy distribution is
|
||||
present.
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.GeneralEvaporation
|
||||
General evaporation spectrum
|
||||
|
||||
"""
|
||||
u = params[0]
|
||||
params, theta = get_tab1_record(file_obj)
|
||||
params, g = get_tab1_record(file_obj)
|
||||
return cls(theta, g, u)
|
||||
|
||||
|
||||
class MaxwellEnergy(EnergyDistribution):
|
||||
r"""Simple Maxwellian fission spectrum represented as
|
||||
|
|
@ -238,6 +328,30 @@ class MaxwellEnergy(EnergyDistribution):
|
|||
|
||||
return cls(theta, u)
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, file_obj, params):
|
||||
"""Generate Maxwell distribution from an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
file_obj : file-like object
|
||||
ENDF file positioned at the start of a section for an energy
|
||||
distribution.
|
||||
params : list
|
||||
List of parameters at the start of the energy distribution that
|
||||
includes the LF value indicating what type of energy distribution is
|
||||
present.
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.MaxwellEnergy
|
||||
Maxwell distribution
|
||||
|
||||
"""
|
||||
u = params[0]
|
||||
params, theta = get_tab1_record(file_obj)
|
||||
return cls(theta, u)
|
||||
|
||||
|
||||
class Evaporation(EnergyDistribution):
|
||||
r"""Evaporation spectrum represented as
|
||||
|
|
@ -346,6 +460,30 @@ class Evaporation(EnergyDistribution):
|
|||
|
||||
return cls(theta, u)
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, file_obj, params):
|
||||
"""Generate evaporation spectrum from an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
file_obj : file-like object
|
||||
ENDF file positioned at the start of a section for an energy
|
||||
distribution.
|
||||
params : list
|
||||
List of parameters at the start of the energy distribution that
|
||||
includes the LF value indicating what type of energy distribution is
|
||||
present.
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.Evaporation
|
||||
Evaporation spectrum
|
||||
|
||||
"""
|
||||
u = params[0]
|
||||
params, theta = get_tab1_record(file_obj)
|
||||
return cls(theta, u)
|
||||
|
||||
|
||||
class WattEnergy(EnergyDistribution):
|
||||
r"""Energy-dependent Watt spectrum represented as
|
||||
|
|
@ -480,6 +618,31 @@ class WattEnergy(EnergyDistribution):
|
|||
|
||||
return cls(a, b, u)
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, file_obj, params):
|
||||
"""Generate Watt fission spectrum from an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
file_obj : file-like object
|
||||
ENDF file positioned at the start of a section for an energy
|
||||
distribution.
|
||||
params : list
|
||||
List of parameters at the start of the energy distribution that
|
||||
includes the LF value indicating what type of energy distribution is
|
||||
present.
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.WattEnergy
|
||||
Watt fission spectrum
|
||||
|
||||
"""
|
||||
u = params[0]
|
||||
params, a = get_tab1_record(file_obj)
|
||||
params, b = get_tab1_record(file_obj)
|
||||
return cls(a, b, u)
|
||||
|
||||
|
||||
class MadlandNix(EnergyDistribution):
|
||||
r"""Energy-dependent fission neutron spectrum (Madland and Nix) given in
|
||||
|
|
@ -587,6 +750,31 @@ class MadlandNix(EnergyDistribution):
|
|||
tm = Tabulated1D.from_hdf5(group['tm'])
|
||||
return cls(efl, efh, tm)
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, file_obj, params):
|
||||
"""Generate Madland-Nix fission spectrum from an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
file_obj : file-like object
|
||||
ENDF file positioned at the start of a section for an energy
|
||||
distribution.
|
||||
params : list
|
||||
List of parameters at the start of the energy distribution that
|
||||
includes the LF value indicating what type of energy distribution is
|
||||
present.
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.MadlandNix
|
||||
Madland-Nix fission spectrum
|
||||
|
||||
"""
|
||||
params, tm = get_tab1_record(file_obj)
|
||||
efl, efh = params[0:2]
|
||||
return cls(efl, efh, tm)
|
||||
|
||||
|
||||
|
||||
class DiscretePhoton(EnergyDistribution):
|
||||
"""Discrete photon energy distribution
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
from collections import Callable
|
||||
from copy import deepcopy
|
||||
from io import StringIO
|
||||
import sys
|
||||
|
||||
import h5py
|
||||
import numpy as np
|
||||
|
||||
from .data import ATOMIC_SYMBOL
|
||||
from .endf_utils import read_float, read_CONT_line, identify_nuclide
|
||||
from .endf import get_cont_record, get_list_record, Evaluation
|
||||
from .function import Function1D, Tabulated1D, Polynomial, Sum
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.mixin import EqualityMixin
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
def _extract_458_data(filename):
|
||||
def _extract_458_data(ev, units='eV'):
|
||||
"""Read an ENDF file and extract the MF=1, MT=458 values.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str
|
||||
Path to and ENDF file
|
||||
ev : openmc.data.Evaluation
|
||||
ENDF evaluation
|
||||
units : {'eV', 'MeV'}
|
||||
The units that are used in values returned.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
|
@ -37,33 +37,25 @@ def _extract_458_data(filename):
|
|||
caution.
|
||||
|
||||
"""
|
||||
ident = identify_nuclide(filename)
|
||||
cv.check_type('evaluation', ev, Evaluation)
|
||||
cv.check_value('energy units', units, ('eV', 'MeV'))
|
||||
|
||||
if not ident['LFI']:
|
||||
if not ev.target['fissionable']:
|
||||
# This nuclide isn't fissionable.
|
||||
return None
|
||||
|
||||
# Extract the MF=1, MT=458 section.
|
||||
lines = []
|
||||
with open(filename, 'r') as fh:
|
||||
line = fh.readline()
|
||||
while line != '':
|
||||
if line[70:75] == ' 1458':
|
||||
lines.append(line)
|
||||
line = fh.readline()
|
||||
|
||||
if len(lines) == 0:
|
||||
if (1, 458) not in ev.section:
|
||||
# No 458 data here.
|
||||
return None
|
||||
|
||||
file_obj = StringIO(ev.section[1, 458])
|
||||
|
||||
# Read the number of coefficients in this LIST record.
|
||||
NPL = read_CONT_line(lines[1])[4]
|
||||
items = get_cont_record(file_obj)
|
||||
NPL = items[3]
|
||||
|
||||
# Parse the ENDF LIST into an array.
|
||||
data = []
|
||||
for i in range(NPL):
|
||||
row, column = divmod(i, 6)
|
||||
data.append(read_float(lines[2 + row][11*column:11*(column+1)]))
|
||||
items, data = get_list_record(file_obj)
|
||||
|
||||
# Declare the coefficient names and the order they are given in. The LIST
|
||||
# contains a value followed immediately by an uncertainty for each of these
|
||||
|
|
@ -96,12 +88,13 @@ def _extract_458_data(filename):
|
|||
for coeffs in uncertainty.values(): coeffs[2] *= 1e-6
|
||||
|
||||
# Convert eV to MeV.
|
||||
for coeffs in value.values():
|
||||
for i in range(len(coeffs)):
|
||||
coeffs[i] *= 10**(-6 + 6*i)
|
||||
for coeffs in uncertainty.values():
|
||||
for i in range(len(coeffs)):
|
||||
coeffs[i] *= 10**(-6 + 6*i)
|
||||
if units == 'MeV':
|
||||
for coeffs in value.values():
|
||||
for i in range(len(coeffs)):
|
||||
coeffs[i] *= 10**(-6 + 6*i)
|
||||
for coeffs in uncertainty.values():
|
||||
for i in range(len(coeffs)):
|
||||
coeffs[i] *= 10**(-6 + 6*i)
|
||||
|
||||
return value, uncertainty
|
||||
|
||||
|
|
@ -161,20 +154,22 @@ def write_compact_458_library(endf_files, output_name='fission_Q_data.h5',
|
|||
for fname in endf_files:
|
||||
if verbose: print(fname)
|
||||
|
||||
ident = identify_nuclide(fname)
|
||||
ev = Evaluation(fname)
|
||||
|
||||
# Skip non-fissionable nuclides.
|
||||
if not ident['LFI']: continue
|
||||
if not ev.target['fissionable']:
|
||||
continue
|
||||
|
||||
# Get the important bits.
|
||||
data = _extract_458_data(fname)
|
||||
data = _extract_458_data(ev, 'MeV')
|
||||
if data is None: continue
|
||||
value, uncertainty = data
|
||||
|
||||
# Make a group for this isomer.
|
||||
name = ATOMIC_SYMBOL[ident['Z']] + str(ident['A'])
|
||||
if ident['LISO'] != 0:
|
||||
name += '_m' + str(ident['LISO'])
|
||||
name = ATOMIC_SYMBOL[ev.target['atomic_number']] + \
|
||||
str(ev.target['mass_number'])
|
||||
if ev.target['isomeric_state'] != 0:
|
||||
name += '_m' + str(ev.target['isomeric_state'])
|
||||
nuclide_group = out.create_group(name)
|
||||
|
||||
# Write all the coefficients into one array. The first dimension gives
|
||||
|
|
@ -361,7 +356,7 @@ class FissionEnergyRelease(EqualityMixin):
|
|||
self._neutrinos = energy_release
|
||||
|
||||
@classmethod
|
||||
def _from_dictionary(cls, energy_release, incident_neutron):
|
||||
def _from_dictionary(cls, energy_release, incident_neutron, units='eV'):
|
||||
"""Generate fission energy release data from a dictionary.
|
||||
|
||||
Parameters
|
||||
|
|
@ -371,9 +366,10 @@ class FissionEnergyRelease(EqualityMixin):
|
|||
component. The keys are the 2-3 letter strings used in ENDF-102,
|
||||
e.g. 'EFR' and 'ET'. The list will have a length of 1 for Sher-Beck
|
||||
data, more for polynomial data.
|
||||
|
||||
incident_neutron : openmc.data.IncidentNeutron
|
||||
Corresponding incident neutron dataset
|
||||
units : {'eV', 'MeV'}
|
||||
The energy units used in the returned object.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
|
@ -381,6 +377,8 @@ class FissionEnergyRelease(EqualityMixin):
|
|||
Fission energy release data
|
||||
|
||||
"""
|
||||
cv.check_value('energy units', units, ('eV', 'MeV'))
|
||||
|
||||
out = cls()
|
||||
|
||||
# How many coefficients are given for each component? If we only find
|
||||
|
|
@ -414,42 +412,55 @@ class FissionEnergyRelease(EqualityMixin):
|
|||
# MT=18 (n, fission) might not be available so try MT=19 (n, f) as
|
||||
# well.
|
||||
if 18 in incident_neutron.reactions:
|
||||
nu_prompt = [p for p in incident_neutron[18].products
|
||||
if p.particle == 'neutron'
|
||||
and p.emission_mode == 'prompt']
|
||||
nu = [p.yield_ for p in incident_neutron[18].products
|
||||
if p.particle == 'neutron'
|
||||
and p.emission_mode in ('prompt', 'total')]
|
||||
elif 19 in incident_neutron.reactions:
|
||||
nu_prompt = [p for p in incident_neutron[19].products
|
||||
if p.particle == 'neutron'
|
||||
and p.emission_mode == 'prompt']
|
||||
nu = [p.yield_ for p in incident_neutron[19].products
|
||||
if p.particle == 'neutron'
|
||||
and p.emission_mode in ('prompt', 'total')]
|
||||
else:
|
||||
raise ValueError('IncidentNeutron data has no fission '
|
||||
'reaction.')
|
||||
if len(nu_prompt) == 0:
|
||||
if len(nu) == 0:
|
||||
raise ValueError('Nu data is needed to compute fission energy '
|
||||
'release with the Sher-Beck format.')
|
||||
if len(nu_prompt) > 1:
|
||||
raise ValueError('Ambiguous prompt value.')
|
||||
if not isinstance(nu_prompt[0].yield_, Tabulated1D):
|
||||
raise TypeError('Sher-Beck fission energy release currently '
|
||||
'only supports Tabulated1D nu data.')
|
||||
ENP = deepcopy(nu_prompt[0].yield_)
|
||||
ENP.y = (energy_release['ENP'] + 1.307 * ENP.x
|
||||
- 8.07 * (ENP.y - ENP.y[0]))
|
||||
if len(nu) > 1:
|
||||
raise ValueError('Ambiguous prompt/total nu value.')
|
||||
|
||||
nu = nu[0]
|
||||
if units == 'eV':
|
||||
nu_const = 8.07e6
|
||||
else:
|
||||
nu_const = 8.07
|
||||
if isinstance(nu, Tabulated1D):
|
||||
ENP = deepcopy(nu)
|
||||
ENP.y = (energy_release['ENP'] + 1.307 * nu.x
|
||||
- nu_const * (nu.y - nu.y[0]))
|
||||
elif isinstance(nu, Polynomial):
|
||||
if len(nu) == 1:
|
||||
ENP = Polynomial([energy_release['ENP'][0], 1.307])
|
||||
else:
|
||||
ENP = Polynomial(
|
||||
[energy_release['ENP'][0], 1.307 - nu_const*nu.coef[1]]
|
||||
+ [-nu_const*c for c in nu.coef[2:]])
|
||||
|
||||
out.prompt_neutrons = ENP
|
||||
|
||||
return out
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, filename, incident_neutron):
|
||||
def from_endf(cls, ev, incident_neutron, units='eV'):
|
||||
"""Generate fission energy release data from an ENDF file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str
|
||||
Name of the ENDF file containing fission energy release data
|
||||
|
||||
ev : openmc.data.endf.Evaluation
|
||||
ENDF evaluation
|
||||
incident_neutron : openmc.data.IncidentNeutron
|
||||
Corresponding incident neutron dataset
|
||||
units : {'eV', 'MeV'}
|
||||
The energy units used in the returned object.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
|
@ -457,26 +468,26 @@ class FissionEnergyRelease(EqualityMixin):
|
|||
Fission energy release data
|
||||
|
||||
"""
|
||||
cv.check_type('evaluation', ev, Evaluation)
|
||||
|
||||
# Check to make sure this ENDF file matches the expected isomer.
|
||||
ident = identify_nuclide(filename)
|
||||
if ident['Z'] != incident_neutron.atomic_number:
|
||||
if ev.target['atomic_number'] != incident_neutron.atomic_number:
|
||||
raise ValueError('The atomic number of the ENDF evaluation does '
|
||||
'not match the given IncidentNeutron.')
|
||||
if ident['A'] != incident_neutron.mass_number:
|
||||
if ev.target['mass_number'] != incident_neutron.mass_number:
|
||||
raise ValueError('The atomic mass of the ENDF evaluation does '
|
||||
'not match the given IncidentNeutron.')
|
||||
if ident['LISO'] != incident_neutron.metastable:
|
||||
if ev.target['isomeric_state'] != incident_neutron.metastable:
|
||||
raise ValueError('The metastable state of the ENDF evaluation does '
|
||||
'not match the given IncidentNeutron.')
|
||||
if not ident['LFI']:
|
||||
if not ev.target['fissionable']:
|
||||
raise ValueError('The ENDF evaluation is not fissionable.')
|
||||
|
||||
# Read the 458 data from the ENDF file.
|
||||
value, uncertainty = _extract_458_data(filename)
|
||||
value, uncertainty = _extract_458_data(ev, units)
|
||||
|
||||
# Build the object.
|
||||
return cls._from_dictionary(value, incident_neutron)
|
||||
return cls._from_dictionary(value, incident_neutron, units)
|
||||
|
||||
@classmethod
|
||||
def from_hdf5(cls, group):
|
||||
|
|
@ -516,7 +527,6 @@ class FissionEnergyRelease(EqualityMixin):
|
|||
Path to an HDF5 file containing fission energy release data. This
|
||||
file should have been generated form the
|
||||
:func:`openmc.data.write_compact_458_library` function.
|
||||
|
||||
incident_neutron : openmc.data.IncidentNeutron
|
||||
Corresponding incident neutron dataset
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ from abc import ABCMeta, abstractmethod
|
|||
from collections import Iterable, Callable
|
||||
from numbers import Real, Integral
|
||||
|
||||
from six import add_metaclass
|
||||
import numpy as np
|
||||
|
||||
import openmc.data
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.mixin import EqualityMixin
|
||||
|
||||
|
|
@ -11,11 +13,9 @@ INTERPOLATION_SCHEME = {1: 'histogram', 2: 'linear-linear', 3: 'linear-log',
|
|||
4: 'log-linear', 5: 'log-log'}
|
||||
|
||||
|
||||
@add_metaclass(ABCMeta)
|
||||
class Function1D(EqualityMixin):
|
||||
"""A function of one independent variable with HDF5 support."""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abstractmethod
|
||||
def __call__(self): pass
|
||||
|
||||
|
|
@ -423,3 +423,83 @@ class Sum(EqualityMixin):
|
|||
def functions(self, functions):
|
||||
cv.check_type('functions', functions, Iterable, Callable)
|
||||
self._functions = functions
|
||||
|
||||
|
||||
class ResonancesWithBackground(EqualityMixin):
|
||||
"""Cross section in resolved resonance region.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
resonances : openmc.data.Resonances
|
||||
Resolved resonance parameter data
|
||||
background : Callable
|
||||
Background cross section as a function of energy
|
||||
mt : int
|
||||
MT value of the reaction
|
||||
|
||||
Attributes
|
||||
----------
|
||||
resonances : openmc.data.Resonances
|
||||
Resolved resonance parameter data
|
||||
background : Callable
|
||||
Background cross section as a function of energy
|
||||
mt : int
|
||||
MT value of the reaction
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, resonances, background, mt):
|
||||
self.resonances = resonances
|
||||
self.background = background
|
||||
self.mt = mt
|
||||
|
||||
def __call__(self, x):
|
||||
# Get background cross section
|
||||
xs = self.background(x)
|
||||
|
||||
for r in self.resonances:
|
||||
if not isinstance(r, openmc.data.resonance._RESOLVED):
|
||||
continue
|
||||
|
||||
if isinstance(x, Iterable):
|
||||
# Determine which energies are within resolved resonance range
|
||||
within = (r.energy_min <= x) & (x <= r.energy_max)
|
||||
|
||||
# Get resonance cross sections and add to background
|
||||
resonant_xs = r.reconstruct(x[within])
|
||||
xs[within] += resonant_xs[self.mt]
|
||||
else:
|
||||
if r.energy_min <= x <= r.energy_max:
|
||||
resonant_xs = r.reconstruct(x)
|
||||
xs += resonant_xs[self.mt]
|
||||
|
||||
return xs
|
||||
|
||||
@property
|
||||
def background(self):
|
||||
return self._background
|
||||
|
||||
@property
|
||||
def mt(self):
|
||||
return self._mt
|
||||
|
||||
@property
|
||||
def resonances(self):
|
||||
return self._resonances
|
||||
|
||||
@background.setter
|
||||
def background(self, background):
|
||||
cv.check_type('background cross section', background, Callable)
|
||||
self._background = background
|
||||
|
||||
@mt.setter
|
||||
def mt(self, mt):
|
||||
cv.check_type('MT value', mt, Integral)
|
||||
self._mt = mt
|
||||
|
||||
@resonances.setter
|
||||
def resonances(self, resonances):
|
||||
cv.check_type('resolved resonance parameters', resonances,
|
||||
openmc.data.Resonances)
|
||||
self._resonances = resonances
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import openmc.checkvalue as cv
|
|||
from openmc.stats import Tabular, Univariate, Discrete, Mixture
|
||||
from .function import Tabulated1D, INTERPOLATION_SCHEME
|
||||
from .angle_energy import AngleEnergy
|
||||
from .endf import get_list_record, get_tab2_record
|
||||
|
||||
|
||||
class KalbachMann(AngleEnergy):
|
||||
|
|
@ -346,3 +347,54 @@ class KalbachMann(AngleEnergy):
|
|||
km_a.append(Tabulated1D(data[0], data[4]))
|
||||
|
||||
return cls(breakpoints, interpolation, energy, energy_out, km_r, km_a)
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, file_obj):
|
||||
"""Generate Kalbach-Mann distribution from an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
file_obj : file-like object
|
||||
ENDF file positioned at the start of the Kalbach-Mann distribution
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.KalbachMann
|
||||
Kalbach-Mann energy-angle distribution
|
||||
|
||||
"""
|
||||
params, tab2 = get_tab2_record(file_obj)
|
||||
lep = params[3]
|
||||
ne = params[5]
|
||||
energy = np.zeros(ne)
|
||||
n_discrete_energies = np.zeros(ne, dtype=int)
|
||||
energy_out = []
|
||||
precompound = []
|
||||
slope = []
|
||||
for i in range(ne):
|
||||
items, values = get_list_record(file_obj)
|
||||
energy[i] = items[1]
|
||||
n_discrete_energies[i] = items[2]
|
||||
# TODO: split out discrete energies
|
||||
n_angle = items[3]
|
||||
n_energy_out = items[5]
|
||||
values = np.asarray(values)
|
||||
values.shape = (n_energy_out, n_angle + 2)
|
||||
|
||||
# Outgoing energy distribution at the i-th incoming energy
|
||||
eout_i = values[:,0]
|
||||
eout_p_i = values[:,1]
|
||||
energy_out_i = Tabular(eout_i, eout_p_i, INTERPOLATION_SCHEME[lep])
|
||||
energy_out.append(energy_out_i)
|
||||
|
||||
# Precompound and slope factors for Kalbach-Mann
|
||||
r_i = values[:,2]
|
||||
if n_angle == 2:
|
||||
a_i = values[:,3]
|
||||
else:
|
||||
a_i = np.zeros_like(r_i)
|
||||
precompound.append(Tabulated1D(eout_i, r_i))
|
||||
slope.append(Tabulated1D(eout_i, a_i))
|
||||
|
||||
return cls(tab2.breakpoints, tab2.interpolation, energy,
|
||||
energy_out, precompound, slope)
|
||||
|
|
|
|||
139
openmc/data/laboratory.py
Normal file
139
openmc/data/laboratory.py
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
from collections import Iterable
|
||||
from numbers import Real, Integral
|
||||
|
||||
import numpy as np
|
||||
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.stats import Tabular, Univariate, Discrete, Mixture
|
||||
from .angle_energy import AngleEnergy
|
||||
from .function import INTERPOLATION_SCHEME
|
||||
from .endf import get_tab2_record, get_tab1_record
|
||||
|
||||
|
||||
class LaboratoryAngleEnergy(AngleEnergy):
|
||||
"""Laboratory angle-energy distribution
|
||||
|
||||
Parameters
|
||||
----------
|
||||
breakpoints : Iterable of int
|
||||
Breakpoints defining interpolation regions
|
||||
interpolation : Iterable of int
|
||||
Interpolation codes
|
||||
energy : Iterable of float
|
||||
Incoming energies at which distributions exist
|
||||
mu : Iterable of openmc.stats.Univariate
|
||||
Distribution of scattering cosines for each incoming energy
|
||||
energy_out : Iterable of Iterable of openmc.stats.Univariate
|
||||
Distribution of outgoing energies for each incoming energy/scattering
|
||||
cosine
|
||||
|
||||
Attributes
|
||||
----------
|
||||
breakpoints : Iterable of int
|
||||
Breakpoints defining interpolation regions
|
||||
interpolation : Iterable of int
|
||||
Interpolation codes
|
||||
energy : Iterable of float
|
||||
Incoming energies at which distributions exist
|
||||
mu : Iterable of openmc.stats.Univariate
|
||||
Distribution of scattering cosines for each incoming energy
|
||||
energy_out : Iterable of Iterable of openmc.stats.Univariate
|
||||
Distribution of outgoing energies for each incoming energy/scattering
|
||||
cosine
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, breakpoints, interpolation, energy, mu, energy_out):
|
||||
super(LaboratoryAngleEnergy).__init__()
|
||||
self.breakpoints = breakpoints
|
||||
self.interpolation = interpolation
|
||||
self.energy = energy
|
||||
self.mu = mu
|
||||
self.energy_out = energy_out
|
||||
|
||||
@property
|
||||
def breakpoints(self):
|
||||
return self._breakpoints
|
||||
|
||||
@property
|
||||
def interpolation(self):
|
||||
return self._interpolation
|
||||
@property
|
||||
def energy(self):
|
||||
return self._energy
|
||||
|
||||
@property
|
||||
def mu(self):
|
||||
return self._mu
|
||||
|
||||
@property
|
||||
def energy_out(self):
|
||||
return self._energy_out
|
||||
|
||||
@breakpoints.setter
|
||||
def breakpoints(self, breakpoints):
|
||||
cv.check_type('laboratory angle-energy breakpoints', breakpoints,
|
||||
Iterable, Integral)
|
||||
self._breakpoints = breakpoints
|
||||
|
||||
@interpolation.setter
|
||||
def interpolation(self, interpolation):
|
||||
cv.check_type('laboratory angle-energy interpolation', interpolation,
|
||||
Iterable, Integral)
|
||||
self._interpolation = interpolation
|
||||
|
||||
@energy.setter
|
||||
def energy(self, energy):
|
||||
cv.check_type('laboratory angle-energy incoming energy', energy,
|
||||
Iterable, Real)
|
||||
self._energy = energy
|
||||
|
||||
@mu.setter
|
||||
def mu(self, mu):
|
||||
cv.check_type('laboratory angle-energy outgoing cosine', mu,
|
||||
Iterable, Univariate)
|
||||
self._mu = mu
|
||||
|
||||
@energy_out.setter
|
||||
def energy_out(self, energy_out):
|
||||
cv.check_iterable_type('laboratory angle-energy outgoing energy',
|
||||
energy_out, Univariate, 2, 2)
|
||||
self._energy_out = energy_out
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, file_obj):
|
||||
"""Generate laboratory angle-energy distribution from an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
file_obj : file-like object
|
||||
ENDF file positioned at the start of a section for a correlated
|
||||
angle-energy distribution
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.LaboratoryAngleEnergy
|
||||
Laboratory angle-energy distribution
|
||||
|
||||
"""
|
||||
params, tab2 = get_tab2_record(file_obj)
|
||||
ne = params[5]
|
||||
energy = np.zeros(ne)
|
||||
mu = []
|
||||
energy_out = []
|
||||
for i in range(ne):
|
||||
params, tab2mu = get_tab2_record(file_obj)
|
||||
energy[i] = params[1]
|
||||
n_mu = params[5]
|
||||
mu_i = np.zeros(n_mu)
|
||||
p_mu_i = np.zeros(n_mu)
|
||||
energy_out_i = []
|
||||
for j in range(n_mu):
|
||||
params, f = get_tab1_record(file_obj)
|
||||
mu_i[j] = params[1]
|
||||
p_mu_i[j] = sum(f.y)
|
||||
energy_out_i.append(Tabular(f.x, f.y))
|
||||
mu.append(Tabular(mu_i, p_mu_i))
|
||||
energy_out.append(energy_out_i)
|
||||
|
||||
return cls(tab2.breakpoints, tab2.interpolation, energy, mu, energy_out)
|
||||
|
|
@ -4,6 +4,7 @@ import numpy as np
|
|||
|
||||
import openmc.checkvalue as cv
|
||||
from .angle_energy import AngleEnergy
|
||||
from .endf import get_cont_record
|
||||
|
||||
class NBodyPhaseSpace(AngleEnergy):
|
||||
"""N-body phase space distribution
|
||||
|
|
@ -17,7 +18,7 @@ class NBodyPhaseSpace(AngleEnergy):
|
|||
atomic_weight_ratio : float
|
||||
Atomic weight ratio of target nuclide
|
||||
q_value : float
|
||||
Q value for reaction in MeV
|
||||
Q value for reaction in MeV or eV, depending on the data source.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
|
|
@ -28,7 +29,7 @@ class NBodyPhaseSpace(AngleEnergy):
|
|||
atomic_weight_ratio : float
|
||||
Atomic weight ratio of target nuclide
|
||||
q_value : float
|
||||
Q value for reaction in MeV
|
||||
Q value for reaction in MeV or eV, depending on the data source.
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -140,3 +141,25 @@ class NBodyPhaseSpace(AngleEnergy):
|
|||
n_particles = int(ace.xss[idx])
|
||||
total_mass = ace.xss[idx + 1]
|
||||
return cls(total_mass, n_particles, ace.atomic_weight_ratio, q_value)
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, file_obj):
|
||||
"""Generate N-body phase space distribution from an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
file_obj : file-like object
|
||||
ENDF file positions at the start of the N-body phase space
|
||||
distribution
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.NBodyPhaseSpace
|
||||
N-body phase space distribution
|
||||
|
||||
"""
|
||||
items = get_cont_record(file_obj)
|
||||
total_mass = items[0]
|
||||
n_particles = items[5]
|
||||
# TODO: get awr and Q value
|
||||
return cls(total_mass, n_particles, 1.0, 0.0)
|
||||
|
|
|
|||
|
|
@ -5,22 +5,22 @@ from itertools import chain
|
|||
from numbers import Integral, Real
|
||||
from warnings import warn
|
||||
|
||||
from six import string_types
|
||||
import numpy as np
|
||||
import h5py
|
||||
|
||||
from .data import ATOMIC_SYMBOL, SUM_RULES, K_BOLTZMANN
|
||||
from .ace import Table, get_table
|
||||
from .data import ATOMIC_SYMBOL, K_BOLTZMANN
|
||||
from .fission_energy import FissionEnergyRelease
|
||||
from .function import Tabulated1D, Sum
|
||||
from .function import Tabulated1D, Sum, ResonancesWithBackground
|
||||
from .endf import Evaluation, SUM_RULES
|
||||
from .product import Product
|
||||
from .reaction import Reaction, _get_photon_products
|
||||
from .reaction import Reaction, _get_photon_products_ace
|
||||
from .resonance import Resonances, _RESOLVED
|
||||
from .urr import ProbabilityTables
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.mixin import EqualityMixin
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
def _get_metadata(zaid, metastable_scheme='nndc'):
|
||||
"""Return basic identifying data for a nuclide with a given ZAID.
|
||||
|
|
@ -137,6 +137,8 @@ class IncidentNeutron(EqualityMixin):
|
|||
Contains the cross sections, secondary angle and energy distributions,
|
||||
and other associated data for each reaction. The keys are the MT values
|
||||
and the values are Reaction objects.
|
||||
resonances : openmc.data.Resonances or None
|
||||
Resonance parameters
|
||||
summed_reactions : collections.OrderedDict
|
||||
Contains summed cross sections, e.g., the total cross section. The keys
|
||||
are the MT values and the values are Reaction objects.
|
||||
|
|
@ -166,6 +168,7 @@ class IncidentNeutron(EqualityMixin):
|
|||
self.reactions = OrderedDict()
|
||||
self.summed_reactions = OrderedDict()
|
||||
self._urr = {}
|
||||
self._resonances = None
|
||||
|
||||
def __contains__(self, mt):
|
||||
return mt in self.reactions or mt in self.summed_reactions
|
||||
|
|
@ -212,6 +215,10 @@ class IncidentNeutron(EqualityMixin):
|
|||
def reactions(self):
|
||||
return self._reactions
|
||||
|
||||
@property
|
||||
def resonances(self):
|
||||
return self._resonances
|
||||
|
||||
@property
|
||||
def summed_reactions(self):
|
||||
return self._summed_reactions
|
||||
|
|
@ -226,7 +233,7 @@ class IncidentNeutron(EqualityMixin):
|
|||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
cv.check_type('name', name, basestring)
|
||||
cv.check_type('name', name, string_types)
|
||||
self._name = name
|
||||
|
||||
@property
|
||||
|
|
@ -236,7 +243,7 @@ class IncidentNeutron(EqualityMixin):
|
|||
@atomic_number.setter
|
||||
def atomic_number(self, atomic_number):
|
||||
cv.check_type('atomic number', atomic_number, Integral)
|
||||
cv.check_greater_than('atomic number', atomic_number, 0)
|
||||
cv.check_greater_than('atomic number', atomic_number, 0, True)
|
||||
self._atomic_number = atomic_number
|
||||
|
||||
@mass_number.setter
|
||||
|
|
@ -268,6 +275,11 @@ class IncidentNeutron(EqualityMixin):
|
|||
cv.check_type('reactions', reactions, Mapping)
|
||||
self._reactions = reactions
|
||||
|
||||
@resonances.setter
|
||||
def resonances(self, resonances):
|
||||
cv.check_type('resonances', resonances, Resonances)
|
||||
self._resonances = resonances
|
||||
|
||||
@summed_reactions.setter
|
||||
def summed_reactions(self, summed_reactions):
|
||||
cv.check_type('summed reactions', summed_reactions, Mapping)
|
||||
|
|
@ -277,7 +289,7 @@ class IncidentNeutron(EqualityMixin):
|
|||
def urr(self, urr):
|
||||
cv.check_type('probability table dictionary', urr, MutableMapping)
|
||||
for key, value in urr:
|
||||
cv.check_type('probability table temperature', key, basestring)
|
||||
cv.check_type('probability table temperature', key, string_types)
|
||||
cv.check_type('probability tables', value, ProbabilityTables)
|
||||
self._urr = urr
|
||||
|
||||
|
|
@ -363,7 +375,7 @@ class IncidentNeutron(EqualityMixin):
|
|||
return mts
|
||||
|
||||
def export_to_hdf5(self, path, mode='a'):
|
||||
"""Export table to an HDF5 file.
|
||||
"""Export incident neutron data to an HDF5 file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
|
@ -374,6 +386,10 @@ class IncidentNeutron(EqualityMixin):
|
|||
to the :class:`h5py.File` constructor.
|
||||
|
||||
"""
|
||||
# If data come from ENDF, don't allow exporting to HDF5
|
||||
if hasattr(self, '_evaluation'):
|
||||
raise NotImplementedError('Cannot export incident neutron data that '
|
||||
'originated from an ENDF file.')
|
||||
|
||||
f = h5py.File(path, mode, libver='latest')
|
||||
|
||||
|
|
@ -587,7 +603,7 @@ class IncidentNeutron(EqualityMixin):
|
|||
for mt_i in mts])
|
||||
|
||||
# Determine summed cross section
|
||||
rx.products += _get_photon_products(ace, rx)
|
||||
rx.products += _get_photon_products_ace(ace, rx)
|
||||
data.summed_reactions[mt] = rx
|
||||
|
||||
# Read unresolved resonance probability tables
|
||||
|
|
@ -596,3 +612,79 @@ class IncidentNeutron(EqualityMixin):
|
|||
data.urr[strT] = urr
|
||||
|
||||
return data
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, ev_or_filename):
|
||||
"""Generate incident neutron continuous-energy data from an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ev_or_filename : openmc.data.endf.Evaluation or str
|
||||
ENDF evaluation to read from. If given as a string, it is assumed to
|
||||
be the filename for the ENDF file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.IncidentNeutron
|
||||
Incident neutron continuous-energy data
|
||||
|
||||
"""
|
||||
if isinstance(ev_or_filename, Evaluation):
|
||||
ev = ev_or_filename
|
||||
else:
|
||||
ev = Evaluation(ev_or_filename)
|
||||
|
||||
atomic_number = ev.target['atomic_number']
|
||||
mass_number = ev.target['mass_number']
|
||||
metastable = ev.target['isomeric_state']
|
||||
atomic_weight_ratio = ev.target['mass']
|
||||
temperature = ev.target['temperature']
|
||||
|
||||
# Determine name
|
||||
element = ATOMIC_SYMBOL[atomic_number]
|
||||
if metastable > 0:
|
||||
name = '{}{}_m{}'.format(element, mass_number, metastable)
|
||||
else:
|
||||
name = '{}{}'.format(element, mass_number)
|
||||
|
||||
# Instantiate incident neutron data
|
||||
data = cls(name, atomic_number, mass_number, metastable,
|
||||
atomic_weight_ratio, temperature)
|
||||
|
||||
if (2, 151) in ev.section:
|
||||
data.resonances = Resonances.from_endf(ev)
|
||||
|
||||
# Read each reaction
|
||||
for mf, mt, nc, mod in ev.reaction_list:
|
||||
if mf == 3:
|
||||
data.reactions[mt] = Reaction.from_endf(ev, mt)
|
||||
|
||||
# Replace cross sections for elastic, capture, fission
|
||||
try:
|
||||
if any(isinstance(r, _RESOLVED) for r in data.resonances):
|
||||
for mt in (2, 102, 18):
|
||||
if mt in data.reactions:
|
||||
rx = data.reactions[mt]
|
||||
rx.xs['0K'] = ResonancesWithBackground(
|
||||
data.resonances, rx.xs['0K'], mt)
|
||||
except ValueError:
|
||||
# Thrown if multiple resolved ranges (e.g. Pu239 in ENDF/B-VII.1)
|
||||
pass
|
||||
|
||||
# If first-chance, second-chance, etc. fission are present, check
|
||||
# whether energy distributions were specified in MF=5. If not, copy the
|
||||
# energy distribution from MT=18.
|
||||
for mt, rx in data.reactions.items():
|
||||
if mt in (19, 20, 21, 38):
|
||||
if (5, mt) not in ev.section:
|
||||
neutron = data.reactions[18].products[0]
|
||||
rx.products[0].applicability = neutron.applicability
|
||||
rx.products[0].distribution = neutron.distribution
|
||||
|
||||
# Read fission energy release (requires that we already know nu for
|
||||
# fission)
|
||||
if (1, 458) in ev.section:
|
||||
data.fission_energy = FissionEnergyRelease.from_endf(ev, data)
|
||||
|
||||
data._evaluation = ev
|
||||
return data
|
||||
|
|
|
|||
|
|
@ -1,16 +1,15 @@
|
|||
from collections import Iterable
|
||||
from io import StringIO
|
||||
from numbers import Real
|
||||
import sys
|
||||
|
||||
from six import string_types
|
||||
import numpy as np
|
||||
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.mixin import EqualityMixin
|
||||
from .function import Tabulated1D, Polynomial, Function1D
|
||||
from .angle_energy import AngleEnergy
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
from .function import Tabulated1D, Polynomial, Function1D
|
||||
|
||||
|
||||
class Product(EqualityMixin):
|
||||
|
|
@ -114,7 +113,7 @@ class Product(EqualityMixin):
|
|||
|
||||
@particle.setter
|
||||
def particle(self, particle):
|
||||
cv.check_type('product particle type', particle, basestring)
|
||||
cv.check_type('product particle type', particle, string_types)
|
||||
self._particle = particle
|
||||
|
||||
@yield_.setter
|
||||
|
|
|
|||
|
|
@ -3,21 +3,191 @@ from collections import Iterable, Callable, MutableMapping
|
|||
from copy import deepcopy
|
||||
from numbers import Real, Integral
|
||||
from warnings import warn
|
||||
from io import StringIO
|
||||
|
||||
from six import string_types
|
||||
import numpy as np
|
||||
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.mixin import EqualityMixin
|
||||
from openmc.stats import Uniform
|
||||
from openmc.stats import Uniform, Tabular, Legendre
|
||||
from .angle_distribution import AngleDistribution
|
||||
from .angle_energy import AngleEnergy
|
||||
from .function import Tabulated1D, Polynomial, Function1D
|
||||
from .data import REACTION_NAME, K_BOLTZMANN
|
||||
from .correlated import CorrelatedAngleEnergy
|
||||
from .data import ATOMIC_SYMBOL, K_BOLTZMANN
|
||||
from .endf import get_head_record, get_tab1_record, get_list_record, \
|
||||
get_tab2_record, get_cont_record
|
||||
from .energy_distribution import EnergyDistribution, LevelInelastic, \
|
||||
DiscretePhoton
|
||||
from .function import Tabulated1D, Polynomial
|
||||
from .kalbach_mann import KalbachMann
|
||||
from .laboratory import LaboratoryAngleEnergy
|
||||
from .nbody import NBodyPhaseSpace
|
||||
from .product import Product
|
||||
from .uncorrelated import UncorrelatedAngleEnergy
|
||||
|
||||
|
||||
def _get_fission_products(ace):
|
||||
REACTION_NAME = {1: '(n,total)', 2: '(n,elastic)', 4: '(n,level)',
|
||||
5: '(n,misc)', 11: '(n,2nd)', 16: '(n,2n)', 17: '(n,3n)',
|
||||
18: '(n,fission)', 19: '(n,f)', 20: '(n,nf)', 21: '(n,2nf)',
|
||||
22: '(n,na)', 23: '(n,n3a)', 24: '(n,2na)', 25: '(n,3na)',
|
||||
27: '(n,absorption)', 28: '(n,np)', 29: '(n,n2a)',
|
||||
30: '(n,2n2a)', 32: '(n,nd)', 33: '(n,nt)', 34: '(n,nHe-3)',
|
||||
35: '(n,nd2a)', 36: '(n,nt2a)', 37: '(n,4n)', 38: '(n,3nf)',
|
||||
41: '(n,2np)', 42: '(n,3np)', 44: '(n,n2p)', 45: '(n,npa)',
|
||||
91: '(n,nc)', 101: '(n,disappear)', 102: '(n,gamma)',
|
||||
103: '(n,p)', 104: '(n,d)', 105: '(n,t)', 106: '(n,3He)',
|
||||
107: '(n,a)', 108: '(n,2a)', 109: '(n,3a)', 111: '(n,2p)',
|
||||
112: '(n,pa)', 113: '(n,t2a)', 114: '(n,d2a)', 115: '(n,pd)',
|
||||
116: '(n,pt)', 117: '(n,da)', 152: '(n,5n)', 153: '(n,6n)',
|
||||
154: '(n,2nt)', 155: '(n,ta)', 156: '(n,4np)', 157: '(n,3nd)',
|
||||
158: '(n,nda)', 159: '(n,2npa)', 160: '(n,7n)', 161: '(n,8n)',
|
||||
162: '(n,5np)', 163: '(n,6np)', 164: '(n,7np)', 165: '(n,4na)',
|
||||
166: '(n,5na)', 167: '(n,6na)', 168: '(n,7na)', 169: '(n,4nd)',
|
||||
170: '(n,5nd)', 171: '(n,6nd)', 172: '(n,3nt)', 173: '(n,4nt)',
|
||||
174: '(n,5nt)', 175: '(n,6nt)', 176: '(n,2n3He)',
|
||||
177: '(n,3n3He)', 178: '(n,4n3He)', 179: '(n,3n2p)',
|
||||
180: '(n,3n3a)', 181: '(n,3npa)', 182: '(n,dt)',
|
||||
183: '(n,npd)', 184: '(n,npt)', 185: '(n,ndt)',
|
||||
186: '(n,np3He)', 187: '(n,nd3He)', 188: '(n,nt3He)',
|
||||
189: '(n,nta)', 190: '(n,2n2p)', 191: '(n,p3He)',
|
||||
192: '(n,d3He)', 193: '(n,3Hea)', 194: '(n,4n2p)',
|
||||
195: '(n,4n2a)', 196: '(n,4npa)', 197: '(n,3p)',
|
||||
198: '(n,n3p)', 199: '(n,3n2pa)', 200: '(n,5n2p)', 444: '(n,damage)',
|
||||
649: '(n,pc)', 699: '(n,dc)', 749: '(n,tc)', 799: '(n,3Hec)',
|
||||
849: '(n,ac)'}
|
||||
REACTION_NAME.update({i: '(n,n{})'.format(i-50) for i in range(50, 91)})
|
||||
REACTION_NAME.update({i: '(n,p{})'.format(i-600) for i in range(600, 649)})
|
||||
REACTION_NAME.update({i: '(n,d{})'.format(i-650) for i in range(650, 699)})
|
||||
REACTION_NAME.update({i: '(n,t{})'.format(i-700) for i in range(700, 749)})
|
||||
REACTION_NAME.update({i: '(n,3He{})'.format(i-750) for i in range(750, 799)})
|
||||
REACTION_NAME.update({i: '(n,a{})'.format(i-800) for i in range(800, 849)})
|
||||
|
||||
|
||||
def _get_products(ev, mt):
|
||||
"""Generate products from MF=6 in an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ev : openmc.data.endf.Evaluation
|
||||
ENDF evaluation to read from
|
||||
mt : int
|
||||
The MT value of the reaction to get products for
|
||||
|
||||
Returns
|
||||
-------
|
||||
products : list of openmc.data.Product
|
||||
Products of the reaction
|
||||
|
||||
"""
|
||||
file_obj = StringIO(ev.section[6, mt])
|
||||
|
||||
# Read HEAD record
|
||||
items = get_head_record(file_obj)
|
||||
reference_frame = {1: 'laboratory', 2: 'center-of-mass',
|
||||
3: 'light-heavy'}[items[3]]
|
||||
n_products = items[4]
|
||||
|
||||
products = []
|
||||
for i in range(n_products):
|
||||
# Get yield for this product
|
||||
params, yield_ = get_tab1_record(file_obj)
|
||||
|
||||
za = params[0]
|
||||
awr = params[1]
|
||||
lip = params[2]
|
||||
law = params[3]
|
||||
|
||||
if za == 0:
|
||||
p = Product('photon')
|
||||
elif za == 1:
|
||||
p = Product('neutron')
|
||||
elif za == 1000:
|
||||
p = Product('electron')
|
||||
else:
|
||||
z = za // 1000
|
||||
a = za % 1000
|
||||
p = Product('{}{}'.format(ATOMIC_SYMBOL[z], a))
|
||||
|
||||
p.yield_ = yield_
|
||||
|
||||
"""
|
||||
# Set reference frame
|
||||
if reference_frame == 'laboratory':
|
||||
p.center_of_mass = False
|
||||
elif reference_frame == 'center-of-mass':
|
||||
p.center_of_mass = True
|
||||
elif reference_frame == 'light-heavy':
|
||||
p.center_of_mass = (awr <= 4.0)
|
||||
"""
|
||||
|
||||
if law == 0:
|
||||
# No distribution given
|
||||
pass
|
||||
if law == 1:
|
||||
# Continuum energy-angle distribution
|
||||
|
||||
# Peak ahead to determine type of distribution
|
||||
position = file_obj.tell()
|
||||
params = get_cont_record(file_obj)
|
||||
file_obj.seek(position)
|
||||
|
||||
lang = params[2]
|
||||
if lang == 1:
|
||||
p.distribution = [CorrelatedAngleEnergy.from_endf(file_obj)]
|
||||
elif lang == 2:
|
||||
p.distribution = [KalbachMann.from_endf(file_obj)]
|
||||
|
||||
elif law == 2:
|
||||
# Discrete two-body scattering
|
||||
params, tab2 = get_tab2_record(file_obj)
|
||||
ne = params[5]
|
||||
energy = np.zeros(ne)
|
||||
mu = []
|
||||
for i in range(ne):
|
||||
items, values = get_list_record(file_obj)
|
||||
energy[i] = items[1]
|
||||
lang = items[2]
|
||||
if lang == 0:
|
||||
mu.append(Legendre(values))
|
||||
elif lang == 12:
|
||||
mu.append(Tabular(values[::2], values[1::2]))
|
||||
elif lang == 14:
|
||||
mu.append(Tabular(values[::2], values[1::2],
|
||||
'log-linear'))
|
||||
|
||||
angle_dist = AngleDistribution(energy, mu)
|
||||
dist = UncorrelatedAngleEnergy(angle_dist)
|
||||
p.distribution = [dist]
|
||||
# TODO: Add level-inelastic info?
|
||||
|
||||
elif law == 3:
|
||||
# Isotropic discrete emission
|
||||
p.distribution = [UncorrelatedAngleEnergy()]
|
||||
# TODO: Add level-inelastic info?
|
||||
|
||||
elif law == 4:
|
||||
# Discrete two-body recoil
|
||||
pass
|
||||
|
||||
elif law == 5:
|
||||
# Charged particle elastic scattering
|
||||
pass
|
||||
|
||||
elif law == 6:
|
||||
# N-body phase-space distribution
|
||||
p.distribution = [NBodyPhaseSpace.from_endf(file_obj)]
|
||||
|
||||
elif law == 7:
|
||||
# Laboratory energy-angle distribution
|
||||
p.distribution = [LaboratoryAngleEnergy.from_endf(file_obj)]
|
||||
|
||||
products.append(p)
|
||||
|
||||
return products
|
||||
|
||||
|
||||
def _get_fission_products_ace(ace):
|
||||
"""Generate fission products from an ACE table
|
||||
|
||||
Parameters
|
||||
|
|
@ -148,7 +318,149 @@ def _get_fission_products(ace):
|
|||
return products, derived_products
|
||||
|
||||
|
||||
def _get_photon_products(ace, rx):
|
||||
def _get_fission_products_endf(ev):
|
||||
"""Generate fission products from an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ev : openmc.data.endf.Evaluation
|
||||
|
||||
Returns
|
||||
-------
|
||||
products : list of openmc.data.Product
|
||||
Prompt and delayed fission neutrons
|
||||
derived_products : list of openmc.data.Product
|
||||
"Total" fission neutron
|
||||
|
||||
"""
|
||||
products = []
|
||||
derived_products = []
|
||||
|
||||
if (1, 456) in ev.section:
|
||||
prompt_neutron = Product('neutron')
|
||||
prompt_neutron.emission_mode = 'prompt'
|
||||
|
||||
# Prompt nu values
|
||||
file_obj = StringIO(ev.section[1, 456])
|
||||
lnu = get_head_record(file_obj)[3]
|
||||
if lnu == 1:
|
||||
# Polynomial representation
|
||||
items, coefficients = get_list_record(file_obj)
|
||||
prompt_neutron.yield_ = Polynomial(coefficients)
|
||||
elif lnu == 2:
|
||||
# Tabulated representation
|
||||
params, prompt_neutron.yield_ = get_tab1_record(file_obj)
|
||||
|
||||
products.append(prompt_neutron)
|
||||
|
||||
if (1, 452) in ev.section:
|
||||
total_neutron = Product('neutron')
|
||||
total_neutron.emission_mode = 'total'
|
||||
|
||||
# Total nu values
|
||||
file_obj = StringIO(ev.section[1, 452])
|
||||
lnu = get_head_record(file_obj)[3]
|
||||
if lnu == 1:
|
||||
# Polynomial representation
|
||||
items, coefficients = get_list_record(file_obj)
|
||||
total_neutron.yield_ = Polynomial(coefficients)
|
||||
elif lnu == 2:
|
||||
# Tabulated representation
|
||||
params, total_neutron.yield_ = get_tab1_record(file_obj)
|
||||
|
||||
if (1, 456) in ev.section:
|
||||
derived_products.append(total_neutron)
|
||||
else:
|
||||
products.append(total_neutron)
|
||||
|
||||
if (1, 455) in ev.section:
|
||||
file_obj = StringIO(ev.section[1, 455])
|
||||
|
||||
# Determine representation of delayed nu data
|
||||
items = get_head_record(file_obj)
|
||||
ldg = items[2]
|
||||
lnu = items[3]
|
||||
|
||||
if ldg == 0:
|
||||
# Delayed-group constants energy independent
|
||||
items, decay_constants = get_list_record(file_obj)
|
||||
for constant in decay_constants:
|
||||
delayed_neutron = Product('neutron')
|
||||
delayed_neutron.emission_mode = 'delayed'
|
||||
delayed_neutron.decay_rate = constant
|
||||
products.append(delayed_neutron)
|
||||
elif ldg == 1:
|
||||
# Delayed-group constants energy dependent
|
||||
raise NotImplementedError('Delayed neutron with energy-dependent '
|
||||
'group constants.')
|
||||
|
||||
# In MF=1, MT=455, the delayed-group abundances are actually not
|
||||
# specified if the group constants are energy-independent. In this case,
|
||||
# the abundances must be inferred from MF=5, MT=455 where multiple
|
||||
# energy distributions are given.
|
||||
if lnu == 1:
|
||||
# Nu represented as polynomial
|
||||
items, coefficients = get_list_record(file_obj)
|
||||
yield_ = Polynomial(coefficients)
|
||||
for neutron in products[-6:]:
|
||||
neutron.yield_ = deepcopy(yield_)
|
||||
elif lnu == 2:
|
||||
# Nu represented by tabulation
|
||||
params, yield_ = get_tab1_record(file_obj)
|
||||
for neutron in products[-6:]:
|
||||
neutron.yield_ = deepcopy(yield_)
|
||||
|
||||
if (5, 455) in ev.section:
|
||||
file_obj = StringIO(ev.section[5, 455])
|
||||
items = get_head_record(file_obj)
|
||||
nk = items[4]
|
||||
if nk != len(decay_constants):
|
||||
raise ValueError(
|
||||
'Number of delayed neutron fission spectra ({}) does not '
|
||||
'match number of delayed neutron precursors ({}).'.format(
|
||||
nk, len(decay_constants)))
|
||||
for i in range(nk):
|
||||
params, applicability = get_tab1_record(file_obj)
|
||||
dist = UncorrelatedAngleEnergy()
|
||||
dist.energy = EnergyDistribution.from_endf(file_obj, params)
|
||||
|
||||
delayed_neutron = products[1 + i]
|
||||
yield_ = delayed_neutron.yield_
|
||||
|
||||
# Here we handle the fact that the delayed neutron yield is the
|
||||
# product of the total delayed neutron yield and the
|
||||
# "applicability" of the energy distribution law in file 5.
|
||||
if isinstance(yield_, Tabulated1D):
|
||||
if np.all(applicability.y == applicability.y[0]):
|
||||
yield_.y *= applicability.y[0]
|
||||
else:
|
||||
# Get union energy grid and ensure energies are within
|
||||
# interpolable range of both functions
|
||||
max_energy = min(yield_.x[-1], applicability.x[-1])
|
||||
energy = np.union1d(yield_.x, applicability.x)
|
||||
energy = energy[energy <= max_energy]
|
||||
|
||||
# Calculate group yield
|
||||
group_yield = yield_(energy) * applicability(energy)
|
||||
delayed_neutron.yield_ = Tabulated1D(energy, group_yield)
|
||||
elif isinstance(yield_, Polynomial):
|
||||
if len(yield_) == 1:
|
||||
delayed_neutron.yield_ = deepcopy(applicability)
|
||||
delayed_neutron.yield_.y *= yield_.coef[0]
|
||||
else:
|
||||
if np.all(applicability.y == applicability.y[0]):
|
||||
yield_.coef[0] *= applicability.y[0]
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
'Total delayed neutron yield and delayed group '
|
||||
'probability are both energy-dependent.')
|
||||
|
||||
delayed_neutron.distribution.append(dist)
|
||||
|
||||
return products, derived_products
|
||||
|
||||
|
||||
def _get_photon_products_ace(ace, rx):
|
||||
"""Generate photon products from an ACE table
|
||||
|
||||
Parameters
|
||||
|
|
@ -253,6 +565,117 @@ def _get_photon_products(ace, rx):
|
|||
return photons
|
||||
|
||||
|
||||
def _get_photon_products_endf(ev, rx):
|
||||
"""Generate photon products from an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ev : openmc.data.endf.Evaluation
|
||||
ENDF evaluation to read from
|
||||
rx : openmc.data.Reaction
|
||||
Reaction that generates photons
|
||||
|
||||
Returns
|
||||
-------
|
||||
photons : list of openmc.Products
|
||||
Photons produced from reaction with given MT
|
||||
|
||||
"""
|
||||
products = []
|
||||
|
||||
if (12, rx.mt) in ev.section:
|
||||
file_obj = StringIO(ev.section[12, rx.mt])
|
||||
|
||||
items = get_head_record(file_obj)
|
||||
option = items[2]
|
||||
|
||||
if option == 1:
|
||||
# Multiplicities given
|
||||
n_discrete_photon = items[4]
|
||||
if n_discrete_photon > 1:
|
||||
items, total_yield = get_tab1_record(file_obj)
|
||||
for k in range(n_discrete_photon):
|
||||
photon = Product('photon')
|
||||
|
||||
# Get photon yield
|
||||
items, photon.yield_ = get_tab1_record(file_obj)
|
||||
|
||||
# Get photon energy distribution
|
||||
law = items[3]
|
||||
dist = UncorrelatedAngleEnergy()
|
||||
if law == 1:
|
||||
# TODO: Get file 15 distribution
|
||||
pass
|
||||
elif law == 2:
|
||||
energy = items[1]
|
||||
primary_flag = items[2]
|
||||
dist.energy = DiscretePhoton(primary_flag, energy,
|
||||
ev.target['mass'])
|
||||
|
||||
photon.distribution.append(dist)
|
||||
products.append(photon)
|
||||
|
||||
elif option == 2:
|
||||
# Transition probability arrays given
|
||||
ppyield = {}
|
||||
ppyield['type'] = 'transition'
|
||||
ppyield['transition'] = transition = {}
|
||||
|
||||
# Determine whether simple (LG=1) or complex (LG=2) transitions
|
||||
lg = items[3]
|
||||
|
||||
# Get transition data
|
||||
items, values = get_list_record(file_obj)
|
||||
transition['energy_start'] = items[0]
|
||||
transition['energies'] = np.array(values[::lg + 1])
|
||||
transition['direct_probability'] = np.array(values[1::lg + 1])
|
||||
if lg == 2:
|
||||
# Complex case
|
||||
transition['conditional_probability'] = np.array(
|
||||
values[2::lg + 1])
|
||||
|
||||
elif (13, rx.mt) in ev.section:
|
||||
file_obj = StringIO(ev.section[13, rx.mt])
|
||||
|
||||
# Determine option
|
||||
items = get_head_record(file_obj)
|
||||
n_discrete_photon = items[4]
|
||||
if n_discrete_photon > 1:
|
||||
items, total_xs = get_tab1_record(file_obj)
|
||||
for k in range(n_discrete_photon):
|
||||
photon = Product('photon')
|
||||
items, xs = get_tab1_record(file_obj)
|
||||
|
||||
# Re-interpolation photon production cross section and neutron cross
|
||||
# section to union energy grid
|
||||
energy = np.union1d(xs.x, rx.xs['0K'].x)
|
||||
photon_prod_xs = xs(energy)
|
||||
neutron_xs = rx.xs['0K'](energy)
|
||||
idx = np.where(neutron_xs > 0)
|
||||
|
||||
# Calculate yield as ratio
|
||||
yield_ = np.zeros_like(energy)
|
||||
yield_[idx] = photon_prod_xs[idx] / neutron_xs[idx]
|
||||
photon.yield_ = Tabulated1D(energy, yield_)
|
||||
|
||||
# Get photon energy distribution
|
||||
law = items[3]
|
||||
dist = UncorrelatedAngleEnergy()
|
||||
if law == 1:
|
||||
# TODO: Get file 15 distribution
|
||||
pass
|
||||
elif law == 2:
|
||||
energy = items[1]
|
||||
primary_flag = items[2]
|
||||
dist.energy = DiscretePhoton(primary_flag, energy,
|
||||
ev.target['mass'])
|
||||
|
||||
photon.distribution.append(dist)
|
||||
products.append(photon)
|
||||
|
||||
return products
|
||||
|
||||
|
||||
class Reaction(EqualityMixin):
|
||||
"""A nuclear reaction
|
||||
|
||||
|
|
@ -274,9 +697,7 @@ class Reaction(EqualityMixin):
|
|||
mt : int
|
||||
The ENDF MT number for this reaction.
|
||||
q_value : float
|
||||
The Q-value of this reaction in MeV.
|
||||
threshold : float
|
||||
Threshold of the reaction in MeV
|
||||
The Q-value of this reaction in MeV or eV, depending on the data source.
|
||||
xs : dict of str to openmc.data.Function1D
|
||||
Microscopic cross section for this reaction as a function of incident
|
||||
energy; these cross sections are provided in a dictionary where the key
|
||||
|
|
@ -349,8 +770,8 @@ class Reaction(EqualityMixin):
|
|||
def xs(self, xs):
|
||||
cv.check_type('reaction cross section dictionary', xs, MutableMapping)
|
||||
for key, value in xs.items():
|
||||
cv.check_type('reaction cross section temperature', key, basestring)
|
||||
cv.check_type('reaction cross section', value, Function1D)
|
||||
cv.check_type('reaction cross section temperature', key, string_types)
|
||||
cv.check_type('reaction cross section', value, Callable)
|
||||
self._xs = xs
|
||||
|
||||
def to_hdf5(self, group):
|
||||
|
|
@ -397,7 +818,7 @@ class Reaction(EqualityMixin):
|
|||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.ace.Reaction
|
||||
openmc.data.Reaction
|
||||
Reaction data
|
||||
|
||||
"""
|
||||
|
|
@ -500,7 +921,7 @@ class Reaction(EqualityMixin):
|
|||
rx.products.append(neutron)
|
||||
else:
|
||||
assert mt in (18, 19, 20, 21, 38)
|
||||
rx.products, rx.derived_products = _get_fission_products(ace)
|
||||
rx.products, rx.derived_products = _get_fission_products_ace(ace)
|
||||
|
||||
for p in rx.products:
|
||||
if p.emission_mode in ('prompt', 'total'):
|
||||
|
|
@ -568,6 +989,97 @@ class Reaction(EqualityMixin):
|
|||
# ======================================================================
|
||||
# PHOTON PRODUCTION
|
||||
|
||||
rx.products += _get_photon_products(ace, rx)
|
||||
rx.products += _get_photon_products_ace(ace, rx)
|
||||
|
||||
return rx
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, ev, mt):
|
||||
"""Generate a reaction from an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ev : openmc.data.endf.Evaluation
|
||||
ENDF evaluation
|
||||
mt : int
|
||||
The MT value of the reaction to get angular distributions for
|
||||
|
||||
Returns
|
||||
-------
|
||||
rx : openmc.data.Reaction
|
||||
Reaction data
|
||||
|
||||
"""
|
||||
rx = Reaction(mt)
|
||||
|
||||
# Integrated cross section
|
||||
if (3, mt) in ev.section:
|
||||
file_obj = StringIO(ev.section[3, mt])
|
||||
get_head_record(file_obj)
|
||||
params, rx.xs['0K'] = get_tab1_record(file_obj)
|
||||
rx.q_value = params[1]
|
||||
|
||||
# Get fission product yields (nu) as well as delayed neutron energy
|
||||
# distributions
|
||||
if mt in (18, 19, 20, 21, 38):
|
||||
rx.products, rx.derived_products = _get_fission_products_endf(ev)
|
||||
|
||||
if (6, mt) in ev.section:
|
||||
# Product angle-energy distribution
|
||||
for product in _get_products(ev, mt):
|
||||
if mt in (18, 19, 20, 21, 38) and product.particle == 'neutron':
|
||||
rx.products[0].applicability = product.applicability
|
||||
rx.products[0].distribution = product.distribution
|
||||
else:
|
||||
rx.products.append(product)
|
||||
|
||||
elif (4, mt) in ev.section or (5, mt) in ev.section:
|
||||
# Uncorrelated angle-energy distribution
|
||||
neutron = Product('neutron')
|
||||
|
||||
# Note that the energy distribution for MT=455 is read in
|
||||
# _get_fission_products_endf rather than here
|
||||
if (5, mt) in ev.section:
|
||||
file_obj = StringIO(ev.section[5, mt])
|
||||
items = get_head_record(file_obj)
|
||||
nk = items[4]
|
||||
for i in range(nk):
|
||||
params, applicability = get_tab1_record(file_obj)
|
||||
dist = UncorrelatedAngleEnergy()
|
||||
dist.energy = EnergyDistribution.from_endf(file_obj, params)
|
||||
|
||||
neutron.applicability.append(applicability)
|
||||
neutron.distribution.append(dist)
|
||||
elif mt == 2:
|
||||
# Elastic scattering -- no energy distribution is given since it
|
||||
# can be calulcated analytically
|
||||
dist = UncorrelatedAngleEnergy()
|
||||
neutron.distribution.append(dist)
|
||||
elif mt >= 51 and mt < 91:
|
||||
# Level inelastic scattering -- no energy distribution is given
|
||||
# since it can be calculated analytically. Here we determine the
|
||||
# necessary parameters to create a LevelInelastic object
|
||||
dist = UncorrelatedAngleEnergy()
|
||||
|
||||
A = ev.target['mass']
|
||||
threshold = (A + 1.)/A*abs(rx.q_value)
|
||||
mass_ratio = (A/(A + 1.))**2
|
||||
dist.energy = LevelInelastic(threshold, mass_ratio)
|
||||
|
||||
neutron.distribution.append(dist)
|
||||
|
||||
if (4, mt) in ev.section:
|
||||
for dist in neutron.distribution:
|
||||
dist.angle = AngleDistribution.from_endf(ev, mt)
|
||||
|
||||
if mt in (18, 19, 20, 21, 38) and (5, mt) in ev.section:
|
||||
# For fission reactions,
|
||||
rx.products[0].applicability = neutron.applicability
|
||||
rx.products[0].distribution = neutron.distribution
|
||||
else:
|
||||
rx.products.append(neutron)
|
||||
|
||||
if (12, mt) in ev.section or (13, mt) in ev.section:
|
||||
rx.products += _get_photon_products_endf(ev, rx)
|
||||
|
||||
return rx
|
||||
|
|
|
|||
522
openmc/data/reconstruct.pyx
Normal file
522
openmc/data/reconstruct.pyx
Normal file
|
|
@ -0,0 +1,522 @@
|
|||
from libc.stdlib cimport malloc, calloc, free
|
||||
from libc.math cimport cos, sin, sqrt, atan, M_PI
|
||||
|
||||
cimport numpy as np
|
||||
import numpy as np
|
||||
from numpy.linalg import inv
|
||||
cimport cython
|
||||
|
||||
|
||||
cdef extern from "complex.h":
|
||||
double cabs(double complex)
|
||||
double complex conj(double complex)
|
||||
double creal(complex double)
|
||||
double cimag(complex double)
|
||||
double complex cexp(double complex)
|
||||
|
||||
# Physical constants are from CODATA 2014
|
||||
cdef double NEUTRON_MASS_ENERGY = 939.5654133e6 # eV/c^2
|
||||
cdef double HBAR_C = 197.3269788e5 # eV-b^0.5
|
||||
|
||||
|
||||
@cython.cdivision(True)
|
||||
def wave_number(double A, double E):
|
||||
r"""Neutron wave number in center-of-mass system.
|
||||
|
||||
ENDF-102 defines the neutron wave number in the center-of-mass system in
|
||||
Equation D.10 as
|
||||
|
||||
.. math::
|
||||
k = \frac{2m_n}{\hbar} \frac{A}{A + 1} \sqrt{|E|}
|
||||
|
||||
Parameters
|
||||
----------
|
||||
A : double
|
||||
Ratio of target mass to neutron mass
|
||||
E : double
|
||||
Energy in eV
|
||||
|
||||
Returns
|
||||
-------
|
||||
double
|
||||
Neutron wave number in b^-0.5
|
||||
|
||||
"""
|
||||
return A/(A + 1)*sqrt(2*NEUTRON_MASS_ENERGY*abs(E))/HBAR_C
|
||||
|
||||
@cython.cdivision(True)
|
||||
cdef double _wave_number(double A, double E):
|
||||
return A/(A + 1)*sqrt(2*NEUTRON_MASS_ENERGY*abs(E))/HBAR_C
|
||||
|
||||
|
||||
@cython.cdivision(True)
|
||||
cdef double phaseshift(int l, double rho):
|
||||
"""Calculate hardsphere phase shift as given in ENDF-102, Equation D.13
|
||||
|
||||
Parameters
|
||||
----------
|
||||
l : int
|
||||
Angular momentum quantum number
|
||||
rho : float
|
||||
Product of the wave number and the channel radius
|
||||
|
||||
Returns
|
||||
-------
|
||||
double
|
||||
Hardsphere phase shift
|
||||
|
||||
"""
|
||||
if l == 0:
|
||||
return rho
|
||||
elif l == 1:
|
||||
return rho - atan(rho)
|
||||
elif l == 2:
|
||||
return rho - atan(3*rho/(3 - rho**2))
|
||||
elif l == 3:
|
||||
return rho - atan((15*rho - rho**3)/(15 - 6*rho**2))
|
||||
elif l == 4:
|
||||
return rho - atan((105*rho - 10*rho**3)/(105 - 45*rho**2 + rho**4))
|
||||
|
||||
|
||||
@cython.cdivision(True)
|
||||
def penetration_shift(int l, double rho):
|
||||
r"""Calculate shift and penetration factors as given in ENDF-102, Equations D.11
|
||||
and D.12.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
l : int
|
||||
Angular momentum quantum number
|
||||
rho : float
|
||||
Product of the wave number and the channel radius
|
||||
|
||||
Returns
|
||||
-------
|
||||
double
|
||||
Penetration factor for given :math:`l`
|
||||
double
|
||||
Shift factor for given :math:`l`
|
||||
|
||||
"""
|
||||
cdef double den
|
||||
|
||||
if l == 0:
|
||||
return rho, 0.
|
||||
elif l == 1:
|
||||
den = 1 + rho**2
|
||||
return rho**3/den, -1/den
|
||||
elif l == 2:
|
||||
den = 9 + 3*rho**2 + rho**4
|
||||
return rho**5/den, -(18 + 3*rho**2)/den
|
||||
elif l == 3:
|
||||
den = 225 + 45*rho**2 + 6*rho**4 + rho**6
|
||||
return rho**7/den, -(675 + 90*rho**2 + 6*rho**4)/den
|
||||
elif l == 4:
|
||||
den = 11025 + 1575*rho**2 + 135*rho**4 + 10*rho**6 + rho**8
|
||||
return rho**9/den, -(44100 + 4725*rho**2 + 270*rho**4 + 10*rho**6)/den
|
||||
|
||||
|
||||
@cython.boundscheck(False)
|
||||
@cython.wraparound(False)
|
||||
@cython.cdivision(True)
|
||||
def reconstruct_mlbw(mlbw, double E):
|
||||
"""Evaluate cross section using MLBW data.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mlbw : openmc.data.MultiLevelBreitWigner
|
||||
Multi-level Breit-Wigner resonance parameters
|
||||
E : double
|
||||
Energy in eV at which to evaluate the cross section
|
||||
|
||||
Returns
|
||||
-------
|
||||
elastic : double
|
||||
Elastic scattering cross section in barns
|
||||
capture : double
|
||||
Radiative capture cross section in barns
|
||||
fission : double
|
||||
Fission cross section in barns
|
||||
|
||||
"""
|
||||
cdef int i, nJ, ij, l, n_res, i_res
|
||||
cdef double elastic, capture, fission
|
||||
cdef double A, k, rho, rhohat, I
|
||||
cdef double P, S, phi, cos2phi, sin2phi
|
||||
cdef double Ex, Q, rhoc, rhochat, P_c, S_c
|
||||
cdef double jmin, jmax, j, Dl
|
||||
cdef double E_r, gt, gn, gg, gf, gx, P_r, S_r, P_rx
|
||||
cdef double gnE, gtE, Eprime, x, f
|
||||
cdef double *g
|
||||
cdef double (*s)[2]
|
||||
cdef double [:,:] params
|
||||
|
||||
I = mlbw.target_spin
|
||||
A = mlbw.atomic_weight_ratio
|
||||
k = _wave_number(A, E)
|
||||
|
||||
elastic = 0.
|
||||
capture = 0.
|
||||
fission = 0.
|
||||
|
||||
for i, l in enumerate(mlbw._l_values):
|
||||
params = mlbw._parameter_matrix[l]
|
||||
|
||||
rho = k*mlbw.channel_radius[l](E)
|
||||
rhohat = k*mlbw.scattering_radius[l](E)
|
||||
P, S = penetration_shift(l, rho)
|
||||
phi = phaseshift(l, rhohat)
|
||||
cos2phi = cos(2*phi)
|
||||
sin2phi = sin(2*phi)
|
||||
|
||||
# Determine shift and penetration at modified energy
|
||||
if mlbw._competitive[i]:
|
||||
Ex = E + mlbw.q_value[l]*(A + 1)/A
|
||||
rhoc = mlbw.channel_radius[l](Ex)
|
||||
rhochat = mlbw.scattering_radius[l](Ex)
|
||||
P_c, S_c = penetration_shift(l, rhoc)
|
||||
if Ex < 0:
|
||||
P_c = 0
|
||||
|
||||
# Determine range of total angular momentum values based on equation
|
||||
# 41 in LA-UR-12-27079
|
||||
jmin = abs(abs(I - l) - 0.5)
|
||||
jmax = I + l + 0.5
|
||||
nJ = int(jmax - jmin + 1)
|
||||
|
||||
# Determine Dl factor using Equation 43 in LA-UR-12-27079
|
||||
Dl = 2*l + 1
|
||||
g = <double *> malloc(nJ*sizeof(double))
|
||||
for ij in range(nJ):
|
||||
j = jmin + ij
|
||||
g[ij] = (2*j + 1)/(4*I + 2)
|
||||
Dl -= g[ij]
|
||||
|
||||
s = <double (*)[2]> calloc(2*nJ, sizeof(double))
|
||||
for i_res in range(params.shape[0]):
|
||||
# Copy resonance parameters
|
||||
E_r = params[i_res, 0]
|
||||
j = params[i_res, 2]
|
||||
ij = int(j - jmin)
|
||||
gt = params[i_res, 3]
|
||||
gn = params[i_res, 4]
|
||||
gg = params[i_res, 5]
|
||||
gf = params[i_res, 6]
|
||||
gx = params[i_res, 7]
|
||||
P_r = params[i_res, 8]
|
||||
S_r = params[i_res, 9]
|
||||
P_rx = params[i_res, 10]
|
||||
|
||||
# Calculate neutron and total width at energy E
|
||||
gnE = P*gn/P_r # ENDF-102, Equation D.7
|
||||
gtE = gnE + gg + gf
|
||||
if gx > 0:
|
||||
gtE += gx*P_c/P_rx
|
||||
|
||||
Eprime = E_r + (S_r - S)/(2*P_r)*gn # ENDF-102, Equation D.9
|
||||
x = 2*(E - Eprime)/gtE # LA-UR-12-27079, Equation 26
|
||||
f = 2*gnE/(gtE*(1 + x*x)) # Common factor in Equation 40
|
||||
s[ij][0] += f # First sum in Equation 40
|
||||
s[ij][1] += f*x # Second sum in Equation 40
|
||||
capture += f*g[ij]*gg/gtE
|
||||
if gf > 0:
|
||||
fission += f*g[ij]*gf/gtE
|
||||
|
||||
for ij in range(nJ):
|
||||
# Add all but last term of LA-UR-12-27079, Equation 40
|
||||
elastic += g[ij]*((1 - cos2phi - s[ij][0])**2 +
|
||||
(sin2phi + s[ij][1])**2)
|
||||
|
||||
# Add final term with Dl from Equation 40
|
||||
elastic += 2*Dl*(1 - cos2phi)
|
||||
|
||||
# Free memory
|
||||
free(g)
|
||||
free(s)
|
||||
|
||||
capture *= 2*M_PI/(k*k)
|
||||
fission *= 2*M_PI/(k*k)
|
||||
elastic *= M_PI/(k*k)
|
||||
|
||||
return (elastic, capture, fission)
|
||||
|
||||
|
||||
@cython.boundscheck(False)
|
||||
@cython.wraparound(False)
|
||||
@cython.cdivision(True)
|
||||
def reconstruct_slbw(slbw, double E):
|
||||
"""Evaluate cross section using SLBW data.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
slbw : openmc.data.SingleLevelBreitWigner
|
||||
Single-level Breit-Wigner resonance parameters
|
||||
E : double
|
||||
Energy in eV at which to evaluate the cross section
|
||||
|
||||
Returns
|
||||
-------
|
||||
elastic : double
|
||||
Elastic scattering cross section in barns
|
||||
capture : double
|
||||
Radiative capture cross section in barns
|
||||
fission : double
|
||||
Fission cross section in barns
|
||||
|
||||
"""
|
||||
cdef int i, l, i_res
|
||||
cdef double elastic, capture, fission
|
||||
cdef double A, k, rho, rhohat, I
|
||||
cdef double P, S, phi, cos2phi, sin2phi, sinphi2
|
||||
cdef double Ex, rhoc, rhochat, P_c, S_c
|
||||
cdef double E_r, J, gt, gn, gg, gf, gx, P_r, S_r, P_rx
|
||||
cdef double gnE, gtE, Eprime, f
|
||||
cdef double x, theta, psi, chi
|
||||
cdef double [:,:] params
|
||||
|
||||
I = slbw.target_spin
|
||||
A = slbw.atomic_weight_ratio
|
||||
k = _wave_number(A, E)
|
||||
|
||||
elastic = 0.
|
||||
capture = 0.
|
||||
fission = 0.
|
||||
|
||||
for i, l in enumerate(slbw._l_values):
|
||||
params = slbw._parameter_matrix[l]
|
||||
|
||||
rho = k*slbw.channel_radius[l](E)
|
||||
rhohat = k*slbw.scattering_radius[l](E)
|
||||
P, S = penetration_shift(l, rho)
|
||||
phi = phaseshift(l, rhohat)
|
||||
cos2phi = cos(2*phi)
|
||||
sin2phi = sin(2*phi)
|
||||
sinphi2 = sin(phi)**2
|
||||
|
||||
# Add potential scattering -- first term in ENDF-102, Equation D.2
|
||||
elastic += 4*M_PI/(k*k)*(2*l + 1)*sinphi2
|
||||
|
||||
# Determine shift and penetration at modified energy
|
||||
if slbw._competitive[i]:
|
||||
Ex = E + slbw.q_value[l]*(A + 1)/A
|
||||
rhoc = slbw.channel_radius[l](Ex)
|
||||
rhochat = slbw.scattering_radius[l](Ex)
|
||||
P_c, S_c = penetration_shift(l, rhoc)
|
||||
if Ex < 0:
|
||||
P_c = 0
|
||||
|
||||
for i_res in range(params.shape[0]):
|
||||
# Copy resonance parameters
|
||||
E_r = params[i_res, 0]
|
||||
J = params[i_res, 2]
|
||||
gt = params[i_res, 3]
|
||||
gn = params[i_res, 4]
|
||||
gg = params[i_res, 5]
|
||||
gf = params[i_res, 6]
|
||||
gx = params[i_res, 7]
|
||||
P_r = params[i_res, 8]
|
||||
S_r = params[i_res, 9]
|
||||
P_rx = params[i_res, 10]
|
||||
|
||||
# Calculate neutron and total width at energy E
|
||||
gnE = P*gn/P_r # Equation D.7
|
||||
gtE = gnE + gg + gf
|
||||
if gx > 0:
|
||||
gtE += gx*P_c/P_rx
|
||||
|
||||
Eprime = E_r + (S_r - S)/(2*P_r)*gn # Equation D.9
|
||||
gJ = (2*J + 1)/(4*I + 2) # Mentioned in section D.1.1.4
|
||||
|
||||
# Calculate common factor for elastic, capture, and fission
|
||||
# cross sections
|
||||
f = M_PI/(k*k)*gJ*gnE/((E - Eprime)**2 + gtE**2/4)
|
||||
|
||||
# Add contribution to elastic per Equation D.2
|
||||
elastic += f*(gnE*cos2phi - 2*(gg + gf)*sinphi2
|
||||
+ 2*(E - Eprime)*sin2phi)
|
||||
|
||||
# Add contribution to capture per Equation D.3
|
||||
capture += f*gg
|
||||
|
||||
# Add contribution to fission per Equation D.6
|
||||
if gf > 0:
|
||||
fission += f*gf
|
||||
|
||||
return (elastic, capture, fission)
|
||||
|
||||
|
||||
@cython.boundscheck(False)
|
||||
@cython.wraparound(False)
|
||||
@cython.cdivision(True)
|
||||
def reconstruct_rm(rm, double E):
|
||||
"""Evaluate cross section using Reich-Moore data.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rm : openmc.data.ReichMoore
|
||||
Reich-Moore resonance parameters
|
||||
E : double
|
||||
Energy in eV at which to evaluate the cross section
|
||||
|
||||
Returns
|
||||
-------
|
||||
elastic : double
|
||||
Elastic scattering cross section in barns
|
||||
capture : double
|
||||
Radiative capture cross section in barns
|
||||
fission : double
|
||||
Fission cross section in barns
|
||||
|
||||
"""
|
||||
cdef int i, l, m, n, i_res
|
||||
cdef int i_s, num_s, i_J, num_J
|
||||
cdef double elastic, capture, fission, total
|
||||
cdef double A, k, rho, rhohat, I
|
||||
cdef double P, S, phi
|
||||
cdef double smin, smax, s, Jmin, Jmax, J, j
|
||||
cdef double E_r, gn, gg, gfa, gfb, P_r
|
||||
cdef double E_diff, abs_value, gJ
|
||||
cdef double Kr, Ki, x
|
||||
cdef double complex Ubar, U_, factor
|
||||
cdef bint hasfission
|
||||
cdef np.ndarray[double, ndim=2] one
|
||||
cdef np.ndarray[double complex, ndim=2] K, Imat, U
|
||||
cdef double [:,:] params
|
||||
|
||||
# Get nuclear spin
|
||||
I = rm.target_spin
|
||||
|
||||
elastic = 0.
|
||||
fission = 0.
|
||||
total = 0.
|
||||
A = rm.atomic_weight_ratio
|
||||
k = _wave_number(A, E)
|
||||
one = np.eye(3)
|
||||
K = np.zeros((3,3), dtype=complex)
|
||||
|
||||
for i, l in enumerate(rm._l_values):
|
||||
# Check for l-dependent scattering radius
|
||||
rho = k*rm.channel_radius[l](E)
|
||||
rhohat = k*rm.scattering_radius[l](E)
|
||||
|
||||
# Calculate shift and penetrability
|
||||
P, S = penetration_shift(l, rho)
|
||||
|
||||
# Calculate phase shift
|
||||
phi = phaseshift(l, rhohat)
|
||||
|
||||
# Calculate common factor on collision matrix terms (term outside curly
|
||||
# braces in ENDF-102, Eq. D.27)
|
||||
Ubar = cexp(-2j*phi)
|
||||
|
||||
# The channel spin is the vector sum of the target spin, I, and the
|
||||
# neutron spin, 1/2, so can take on values of |I - 1/2| < s < I + 1/2
|
||||
smin = abs(I - 0.5)
|
||||
smax = I + 0.5
|
||||
num_s = int(smax - smin + 1)
|
||||
|
||||
for i_s in range(num_s):
|
||||
s = i_s + smin
|
||||
|
||||
# Total angular momentum is the vector sum of l and s and can assume
|
||||
# values between |l - s| < J < l + s
|
||||
Jmin = abs(l - s)
|
||||
Jmax = l + s
|
||||
num_J = int(Jmax - Jmin + 1)
|
||||
|
||||
for i_J in range(num_J):
|
||||
J = i_J + Jmin
|
||||
|
||||
# Initialize K matrix
|
||||
for m in range(3):
|
||||
for n in range(3):
|
||||
K[m,n] = 0.0
|
||||
|
||||
hasfission = False
|
||||
if (l, J) in rm._parameter_matrix:
|
||||
params = rm._parameter_matrix[l, J]
|
||||
|
||||
for i_res in range(params.shape[0]):
|
||||
# Sometimes, the same (l, J) quantum numbers can occur
|
||||
# for different values of the channel spin, s. In this
|
||||
# case, the sign of the channel spin indicates which
|
||||
# spin is to be used. If the spin is negative assume
|
||||
# this resonance comes from the I - 1/2 channel and vice
|
||||
# versa.
|
||||
j = params[i_res, 2]
|
||||
if l > 0:
|
||||
if (j < 0 and s != smin) or (j > 0 and s != smax):
|
||||
continue
|
||||
|
||||
# Copy resonance parameters
|
||||
E_r = params[i_res, 0]
|
||||
gn = params[i_res, 3]
|
||||
gg = params[i_res, 4]
|
||||
gfa = params[i_res, 5]
|
||||
gfb = params[i_res, 6]
|
||||
P_r = params[i_res, 7]
|
||||
|
||||
# Calculate neutron width at energy E
|
||||
gn = sqrt(P*gn/P_r)
|
||||
|
||||
# Calculate j/2 * inverse of denominator of K matrix terms
|
||||
factor = 0.5j/(E_r - E - 0.5j*gg)
|
||||
|
||||
# Upper triangular portion of K matrix -- see ENDF-102,
|
||||
# Equation D.28
|
||||
K[0,0] = K[0,0] + gn*gn*factor
|
||||
if gfa != 0.0 or gfb != 0.0:
|
||||
# Negate fission widths if necessary
|
||||
gfa = (-1 if gfa < 0 else 1)*sqrt(abs(gfa))
|
||||
gfb = (-1 if gfb < 0 else 1)*sqrt(abs(gfb))
|
||||
|
||||
K[0,1] = K[0,1] + gn*gfa*factor
|
||||
K[0,2] = K[0,2] + gn*gfb*factor
|
||||
K[1,1] = K[1,1] + gfa*gfa*factor
|
||||
K[1,2] = K[1,2] + gfa*gfb*factor
|
||||
K[2,2] = K[2,2] + gfb*gfb*factor
|
||||
hasfission = True
|
||||
|
||||
# Get collision matrix
|
||||
gJ = (2*J + 1)/(4*I + 2)
|
||||
if hasfission:
|
||||
# Copy upper triangular portion of K to lower triangular
|
||||
K[1,0] = K[0,1]
|
||||
K[2,0] = K[0,2]
|
||||
K[2,1] = K[1,2]
|
||||
|
||||
Imat = inv(one - K)
|
||||
U = Ubar*(2*Imat - one) # ENDF-102, Eq. D.27
|
||||
elastic += gJ*cabs(1 - U[0,0])**2 # ENDF-102, Eq. D.24
|
||||
total += 2*gJ*(1 - creal(U[0,0])) # ENDF-102, Eq. D.23
|
||||
|
||||
# Calculate fission from ENDF-102, Eq. D.26
|
||||
fission += 4*gJ*(cabs(Imat[1,0])**2 + cabs(Imat[2,0])**2)
|
||||
else:
|
||||
U_ = Ubar*(2/(1 - K[0,0]) - 1)
|
||||
if abs(creal(K[0,0])) < 3e-4 and abs(phi) < 3e-4:
|
||||
# If K and phi are both very small, the calculated cross
|
||||
# sections can lose precision because the real part of U
|
||||
# ends up very close to unity. To get around this, we
|
||||
# use Euler's formula to express Ubar by real and
|
||||
# imaginary parts, expand cos(2phi) = 1 - 2phi^2 +
|
||||
# O(phi^4), and then simplify
|
||||
Kr = creal(K[0,0])
|
||||
Ki = cimag(K[0,0])
|
||||
x = 2*(-Kr + (Kr*Kr + Ki*Ki)*(1 - phi*phi) + phi*phi -
|
||||
sin(2*phi)*Ki)/((1 - Kr)*(1 - Kr) + Ki*Ki)
|
||||
total += 2*gJ*x
|
||||
elastic += gJ*(x*x + cimag(U_)**2)
|
||||
else:
|
||||
total += 2*gJ*(1 - creal(U_)) # ENDF-102, Eq. D.23
|
||||
elastic += gJ*cabs(1 - U_)**2 # ENDF-102, Eq. D.24
|
||||
|
||||
# Calculate capture as difference of other cross sections as per ENDF-102,
|
||||
# Equation D.25
|
||||
capture = total - elastic - fission
|
||||
|
||||
elastic *= M_PI/(k*k)
|
||||
capture *= M_PI/(k*k)
|
||||
fission *= M_PI/(k*k)
|
||||
|
||||
return (elastic, capture, fission)
|
||||
1063
openmc/data/resonance.py
Normal file
1063
openmc/data/resonance.py
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,14 +1,12 @@
|
|||
import re
|
||||
import sys
|
||||
|
||||
from six import string_types
|
||||
|
||||
import openmc
|
||||
from openmc.checkvalue import check_type, check_length
|
||||
from openmc.data import NATURAL_ABUNDANCE
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
|
||||
class Element(object):
|
||||
"""A natural element used in a material via <element>. Internally, OpenMC will
|
||||
|
|
@ -43,7 +41,7 @@ class Element(object):
|
|||
return False
|
||||
else:
|
||||
return True
|
||||
elif isinstance(other, basestring) and other == self.name:
|
||||
elif isinstance(other, string_types) and other == self.name:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
|
@ -78,7 +76,7 @@ class Element(object):
|
|||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
check_type('element name', name, basestring)
|
||||
check_type('element name', name, string_types)
|
||||
check_length('element name', name, 1, 2)
|
||||
self._name = name
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@ import subprocess
|
|||
from numbers import Integral
|
||||
import sys
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
from six import string_types
|
||||
|
||||
|
||||
def _run(command, output, cwd):
|
||||
|
|
@ -89,7 +88,7 @@ def run(particles=None, threads=None, geometry_debug=False,
|
|||
if geometry_debug:
|
||||
post_args += '-g '
|
||||
|
||||
if isinstance(restart_file, basestring):
|
||||
if isinstance(restart_file, string_types):
|
||||
post_args += '-r {0} '.format(restart_file)
|
||||
|
||||
if tracks:
|
||||
|
|
|
|||
|
|
@ -1,21 +1,17 @@
|
|||
from abc import ABCMeta, abstractproperty
|
||||
from collections import Iterable, OrderedDict
|
||||
import copy
|
||||
from six import with_metaclass
|
||||
from numbers import Real, Integral
|
||||
import sys
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
from six import add_metaclass
|
||||
import numpy as np
|
||||
|
||||
import openmc
|
||||
import openmc.checkvalue as cv
|
||||
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
_FILTER_TYPES = ['universe', 'material', 'cell', 'cellborn', 'surface',
|
||||
'mesh', 'energy', 'energyout', 'mu', 'polar', 'azimuthal',
|
||||
'distribcell', 'delayedgroup']
|
||||
|
|
@ -37,7 +33,8 @@ class FilterMeta(ABCMeta):
|
|||
**kwargs)
|
||||
|
||||
|
||||
class Filter(with_metaclass(FilterMeta, object)):
|
||||
@add_metaclass(FilterMeta)
|
||||
class Filter(object):
|
||||
"""Tally modifier that describes phase-space and other characteristics.
|
||||
|
||||
Parameters
|
||||
|
|
|
|||
|
|
@ -1,21 +1,20 @@
|
|||
from __future__ import division
|
||||
|
||||
import abc
|
||||
from abc import ABCMeta
|
||||
from collections import OrderedDict, Iterable
|
||||
from math import sqrt, floor
|
||||
from numbers import Real, Integral
|
||||
from xml.etree import ElementTree as ET
|
||||
import sys
|
||||
|
||||
from six import add_metaclass, string_types
|
||||
import numpy as np
|
||||
|
||||
import openmc.checkvalue as cv
|
||||
import openmc
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
@add_metaclass(ABCMeta)
|
||||
class Lattice(object):
|
||||
"""A repeating structure wherein each element is a universe.
|
||||
|
||||
|
|
@ -42,10 +41,6 @@ class Lattice(object):
|
|||
of the lattice
|
||||
|
||||
"""
|
||||
|
||||
# This is an abstract class which cannot be instantiated
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
def __init__(self, lattice_id=None, name=''):
|
||||
# Initialize Lattice class attributes
|
||||
self.id = lattice_id
|
||||
|
|
@ -106,7 +101,7 @@ class Lattice(object):
|
|||
@name.setter
|
||||
def name(self, name):
|
||||
if name is not None:
|
||||
cv.check_type('lattice name', name, basestring)
|
||||
cv.check_type('lattice name', name, string_types)
|
||||
self._name = name
|
||||
else:
|
||||
self._name = ''
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import sys
|
||||
|
||||
from openmc.checkvalue import check_type
|
||||
from six import string_types
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
from openmc.checkvalue import check_type
|
||||
|
||||
|
||||
class Macroscopic(object):
|
||||
|
|
@ -34,7 +33,7 @@ class Macroscopic(object):
|
|||
return False
|
||||
else:
|
||||
return True
|
||||
elif isinstance(other, basestring) and other == self.name:
|
||||
elif isinstance(other, string_types) and other == self.name:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
|
@ -55,5 +54,5 @@ class Macroscopic(object):
|
|||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
check_type('name', name, basestring)
|
||||
check_type('name', name, string_types)
|
||||
self._name = name
|
||||
|
|
|
|||
|
|
@ -5,14 +5,13 @@ import warnings
|
|||
from xml.etree import ElementTree as ET
|
||||
import sys
|
||||
|
||||
from six import string_types
|
||||
|
||||
import openmc
|
||||
import openmc.data
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.clean_xml import sort_xml_elements, clean_xml_indentation
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
# A static variable for auto-generated Material IDs
|
||||
AUTO_MATERIAL_ID = 10000
|
||||
|
|
@ -207,7 +206,7 @@ class Material(object):
|
|||
def name(self, name):
|
||||
if name is not None:
|
||||
cv.check_type('name for Material ID="{0}"'.format(self._id),
|
||||
name, basestring)
|
||||
name, string_types)
|
||||
self._name = name
|
||||
else:
|
||||
self._name = ''
|
||||
|
|
@ -256,7 +255,7 @@ class Material(object):
|
|||
warnings.warn('This feature is not yet implemented in a release '
|
||||
'version of openmc')
|
||||
|
||||
if not isinstance(filename, basestring) and filename is not None:
|
||||
if not isinstance(filename, string_types) and filename is not None:
|
||||
msg = 'Unable to add OTF material file to Material ID="{0}" with a ' \
|
||||
'non-string name "{1}"'.format(self._id, filename)
|
||||
raise ValueError(msg)
|
||||
|
|
@ -290,7 +289,7 @@ class Material(object):
|
|||
'macroscopic data-set has already been added'.format(self._id)
|
||||
raise ValueError(msg)
|
||||
|
||||
if not isinstance(nuclide, (openmc.Nuclide, basestring)):
|
||||
if not isinstance(nuclide, string_types + (openmc.Nuclide,)):
|
||||
msg = 'Unable to add a Nuclide to Material ID="{0}" with a ' \
|
||||
'non-Nuclide value "{1}"'.format(self._id, nuclide)
|
||||
raise ValueError(msg)
|
||||
|
|
@ -355,7 +354,7 @@ class Material(object):
|
|||
'has already been added'.format(self._id, macroscopic)
|
||||
raise ValueError(msg)
|
||||
|
||||
if not isinstance(macroscopic, (openmc.Macroscopic, basestring)):
|
||||
if not isinstance(macroscopic, string_types + (openmc.Macroscopic,)):
|
||||
msg = 'Unable to add a Macroscopic to Material ID="{0}" with a ' \
|
||||
'non-Macroscopic value "{1}"'.format(self._id, macroscopic)
|
||||
raise ValueError(msg)
|
||||
|
|
@ -425,7 +424,7 @@ class Material(object):
|
|||
'macroscopic data-set has already been added'.format(self._id)
|
||||
raise ValueError(msg)
|
||||
|
||||
if not isinstance(element, (openmc.Element, basestring)):
|
||||
if not isinstance(element, string_types + (openmc.Element,)):
|
||||
msg = 'Unable to add an Element to Material ID="{0}" with a ' \
|
||||
'non-Element value "{1}"'.format(self._id, element)
|
||||
raise ValueError(msg)
|
||||
|
|
@ -490,7 +489,7 @@ class Material(object):
|
|||
'macroscopic data-set has already been added'.format(self._id)
|
||||
raise ValueError(msg)
|
||||
|
||||
if not isinstance(name, basestring):
|
||||
if not isinstance(name, string_types):
|
||||
msg = 'Unable to add an S(a,b) table to Material ID="{0}" with a ' \
|
||||
'non-string table name "{1}"'.format(self._id, name)
|
||||
raise ValueError(msg)
|
||||
|
|
|
|||
|
|
@ -3,15 +3,13 @@ from numbers import Real, Integral
|
|||
from xml.etree import ElementTree as ET
|
||||
import sys
|
||||
|
||||
from six import string_types
|
||||
import numpy as np
|
||||
|
||||
import openmc.checkvalue as cv
|
||||
import openmc
|
||||
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
# "Static" variable for auto-generated and Mesh IDs
|
||||
AUTO_MESH_ID = 10000
|
||||
|
||||
|
|
@ -131,7 +129,7 @@ class Mesh(object):
|
|||
def name(self, name):
|
||||
if name is not None:
|
||||
cv.check_type('name for mesh ID="{0}"'.format(self._id),
|
||||
name, basestring)
|
||||
name, string_types)
|
||||
self._name = name
|
||||
else:
|
||||
self._name = ''
|
||||
|
|
@ -139,7 +137,7 @@ class Mesh(object):
|
|||
@type.setter
|
||||
def type(self, meshtype):
|
||||
cv.check_type('type for mesh ID="{0}"'.format(self._id),
|
||||
meshtype, basestring)
|
||||
meshtype, string_types)
|
||||
cv.check_value('type for mesh ID="{0}"'.format(self._id),
|
||||
meshtype, ['regular'])
|
||||
self._type = meshtype
|
||||
|
|
@ -286,10 +284,8 @@ class Mesh(object):
|
|||
openmc.XPlane(x0=self.upper_right[0],
|
||||
boundary_type=bc[1])]
|
||||
if len(self.dimension) == 1:
|
||||
yplanes = [openmc.YPlane(y0=np.finfo(np.float).min,
|
||||
boundary_type='reflective'),
|
||||
openmc.YPlane(y0=np.finfo(np.float).max,
|
||||
boundary_type='reflective')]
|
||||
yplanes = [openmc.YPlane(y0=-1e10, boundary_type='reflective'),
|
||||
openmc.YPlane(y0=1e10, boundary_type='reflective')]
|
||||
else:
|
||||
yplanes = [openmc.YPlane(y0=self.lower_left[1],
|
||||
boundary_type=bc[2]),
|
||||
|
|
@ -297,10 +293,15 @@ class Mesh(object):
|
|||
boundary_type=bc[3])]
|
||||
|
||||
if len(self.dimension) <= 2:
|
||||
zplanes = [openmc.ZPlane(z0=np.finfo(np.float).min,
|
||||
boundary_type='reflective'),
|
||||
openmc.ZPlane(z0=np.finfo(np.float).max,
|
||||
boundary_type='reflective')]
|
||||
# Would prefer to have the z ranges be the max supported float, but
|
||||
# these values are apparently different between python and Fortran.
|
||||
# Choosing a safe and sane default.
|
||||
# Values of +/-1e10 are used here as there seems to be an
|
||||
# inconsistency between what numpy uses as the max float and what
|
||||
# Fortran expects for a real(8), so this avoids code complication
|
||||
# and achieves the same goal.
|
||||
zplanes = [openmc.ZPlane(z0=-1e10, boundary_type='reflective'),
|
||||
openmc.ZPlane(z0=1e10, boundary_type='reflective')]
|
||||
else:
|
||||
zplanes = [openmc.ZPlane(z0=self.lower_left[2],
|
||||
boundary_type=bc[4]),
|
||||
|
|
|
|||
|
|
@ -8,10 +8,6 @@ import numpy as np
|
|||
import openmc.checkvalue as cv
|
||||
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
class EnergyGroups(object):
|
||||
"""An energy groups structure used for multi-group cross-sections.
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ from numbers import Integral
|
|||
from collections import OrderedDict
|
||||
from warnings import warn
|
||||
|
||||
from six import string_types
|
||||
import numpy as np
|
||||
|
||||
import openmc
|
||||
|
|
@ -14,10 +15,6 @@ import openmc.checkvalue as cv
|
|||
from openmc.tallies import ESTIMATOR_TYPES
|
||||
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
class Library(object):
|
||||
"""A multi-energy-group and multi-delayed-group cross section library for
|
||||
some energy group structure.
|
||||
|
|
@ -259,7 +256,7 @@ class Library(object):
|
|||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
cv.check_type('name', name, basestring)
|
||||
cv.check_type('name', name, string_types)
|
||||
self._name = name
|
||||
|
||||
@mgxs_types.setter
|
||||
|
|
@ -268,7 +265,7 @@ class Library(object):
|
|||
if mgxs_types == 'all':
|
||||
self._mgxs_types = all_mgxs_types
|
||||
else:
|
||||
cv.check_iterable_type('mgxs_types', mgxs_types, basestring)
|
||||
cv.check_iterable_type('mgxs_types', mgxs_types, string_types)
|
||||
for mgxs_type in mgxs_types:
|
||||
cv.check_value('mgxs_type', mgxs_type, all_mgxs_types)
|
||||
self._mgxs_types = mgxs_types
|
||||
|
|
@ -730,8 +727,8 @@ class Library(object):
|
|||
'since a statepoint has not yet been loaded'
|
||||
raise ValueError(msg)
|
||||
|
||||
cv.check_type('filename', filename, basestring)
|
||||
cv.check_type('directory', directory, basestring)
|
||||
cv.check_type('filename', filename, string_types)
|
||||
cv.check_type('directory', directory, string_types)
|
||||
|
||||
import h5py
|
||||
|
||||
|
|
@ -773,8 +770,8 @@ class Library(object):
|
|||
|
||||
"""
|
||||
|
||||
cv.check_type('filename', filename, basestring)
|
||||
cv.check_type('directory', directory, basestring)
|
||||
cv.check_type('filename', filename, string_types)
|
||||
cv.check_type('directory', directory, string_types)
|
||||
|
||||
# Make directory if it does not exist
|
||||
if not os.path.exists(directory):
|
||||
|
|
@ -808,8 +805,8 @@ class Library(object):
|
|||
|
||||
"""
|
||||
|
||||
cv.check_type('filename', filename, basestring)
|
||||
cv.check_type('directory', directory, basestring)
|
||||
cv.check_type('filename', filename, string_types)
|
||||
cv.check_type('directory', directory, string_types)
|
||||
|
||||
# Make directory if it does not exist
|
||||
if not os.path.exists(directory):
|
||||
|
|
@ -822,11 +819,13 @@ class Library(object):
|
|||
return pickle.load(open(full_filename, 'rb'))
|
||||
|
||||
def get_xsdata(self, domain, xsdata_name, nuclide='total', xs_type='macro',
|
||||
order=None, tabular_legendre=None, tabular_points=33,
|
||||
subdomain=None):
|
||||
order=None, subdomain=None):
|
||||
"""Generates an openmc.XSdata object describing a multi-group cross section
|
||||
data set for eventual combination in to an openmc.MGXSLibrary object
|
||||
(i.e., the library).
|
||||
dataset for writing to an openmc.MGXSLibrary object.
|
||||
|
||||
Note that this method does not build an XSdata
|
||||
object with nested temperature tables. The temperature of each
|
||||
XSdata object will be left at the default value of 300K.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
|
@ -845,18 +844,6 @@ class Library(object):
|
|||
Scattering order for this data entry. Default is None,
|
||||
which will set the XSdata object to use the order of the
|
||||
Library.
|
||||
tabular_legendre : None or bool
|
||||
Flag to denote whether or not the Legendre expansion of the
|
||||
scattering angular distribution is to be converted to a tabular
|
||||
representation by OpenMC. A value of `True` means that it is to be
|
||||
converted while a value of `False` means that it will not be.
|
||||
Defaults to `None` which leaves the default behavior of OpenMC in
|
||||
place (the distribution is converted to a tabular representation).
|
||||
tabular_points : int
|
||||
This parameter is not used unless the ``tabular_legendre``
|
||||
parameter is set to `True`. In this case, this parameter sets the
|
||||
number of equally-spaced points in the domain of [-1,1] to be used
|
||||
in building the tabular distribution. Default is `33`.
|
||||
subdomain : iterable of int
|
||||
This parameter is not used unless using a mesh domain. In that
|
||||
case, the subdomain is an [i,j,k] index (1-based indexing) of the
|
||||
|
|
@ -867,7 +854,7 @@ class Library(object):
|
|||
Returns
|
||||
-------
|
||||
xsdata : openmc.XSdata
|
||||
Multi-Group Cross Section data set object.
|
||||
Multi-Group Cross Section dataset object.
|
||||
|
||||
Raises
|
||||
------
|
||||
|
|
@ -883,17 +870,13 @@ class Library(object):
|
|||
|
||||
cv.check_type('domain', domain, (openmc.Material, openmc.Cell,
|
||||
openmc.Universe, openmc.Mesh))
|
||||
cv.check_type('xsdata_name', xsdata_name, basestring)
|
||||
cv.check_type('nuclide', nuclide, basestring)
|
||||
cv.check_type('xsdata_name', xsdata_name, string_types)
|
||||
cv.check_type('nuclide', nuclide, string_types)
|
||||
cv.check_value('xs_type', xs_type, ['macro', 'micro'])
|
||||
cv.check_type('order', order, (type(None), Integral))
|
||||
if order is not None:
|
||||
cv.check_greater_than('order', order, 0, equality=True)
|
||||
cv.check_less_than('order', order, 10, equality=True)
|
||||
cv.check_type('tabular_legendre', tabular_legendre,
|
||||
(type(None), bool))
|
||||
if tabular_points is not None:
|
||||
cv.check_greater_than('tabular_points', tabular_points, 1)
|
||||
if subdomain is not None:
|
||||
cv.check_iterable_type('subdomain', subdomain, Integral,
|
||||
max_depth=3)
|
||||
|
|
@ -910,7 +893,7 @@ class Library(object):
|
|||
|
||||
# Build & add metadata to XSdata object
|
||||
name = xsdata_name
|
||||
if nuclide is not 'total':
|
||||
if nuclide != 'total':
|
||||
name += '_' + nuclide
|
||||
xsdata = openmc.XSdata(name, self.energy_groups)
|
||||
|
||||
|
|
@ -922,14 +905,12 @@ class Library(object):
|
|||
# the provided order or the Library's order.
|
||||
xsdata.order = min(order, self.legendre_order)
|
||||
|
||||
# Set the tabular_legendre option if needed
|
||||
if tabular_legendre is not None:
|
||||
xsdata.tabular_legendre = {'enable': tabular_legendre,
|
||||
'num_points': tabular_points}
|
||||
# Right now only 'legendre' data and isotropic weighting is supported
|
||||
self.scatter_format = 'legendre'
|
||||
self.representation = 'isotropic'
|
||||
|
||||
if nuclide is not 'total':
|
||||
xsdata.zaid = self._nuclides[nuclide][0]
|
||||
xsdata.awr = self._nuclides[nuclide][1]
|
||||
if nuclide != 'total':
|
||||
xsdata.atomic_weight_ratio = self._nuclides[nuclide][1]
|
||||
|
||||
if subdomain is None:
|
||||
subdomain = 'all'
|
||||
|
|
@ -940,7 +921,7 @@ class Library(object):
|
|||
if 'nu-transport' in self.mgxs_types and self.correction == 'P0':
|
||||
mymgxs = self.get_mgxs(domain, 'nu-transport')
|
||||
xsdata.set_total_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide],
|
||||
subdomains=subdomain)
|
||||
subdomain=subdomain)
|
||||
elif 'total' in self.mgxs_types:
|
||||
mymgxs = self.get_mgxs(domain, 'total')
|
||||
xsdata.set_total_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide],
|
||||
|
|
@ -979,49 +960,55 @@ class Library(object):
|
|||
# If multiplicity matrix is available, prefer that
|
||||
if 'multiplicity matrix' in self.mgxs_types:
|
||||
mymgxs = self.get_mgxs(domain, 'multiplicity matrix')
|
||||
xsdata.set_multiplicity_mgxs(mymgxs, xs_type=xs_type,
|
||||
nuclide=[nuclide],
|
||||
subdomain=subdomain)
|
||||
xsdata.set_multiplicity_matrix_mgxs(mymgxs, xs_type=xs_type,
|
||||
nuclide=[nuclide],
|
||||
subdomain=subdomain)
|
||||
using_multiplicity = True
|
||||
# multiplicity will fall back to using scatter and nu-scatter
|
||||
elif ((('scatter matrix' in self.mgxs_types) and
|
||||
('nu-scatter matrix' in self.mgxs_types))):
|
||||
scatt_mgxs = self.get_mgxs(domain, 'scatter matrix')
|
||||
nuscatt_mgxs = self.get_mgxs(domain, 'nu-scatter matrix')
|
||||
xsdata.set_multiplicity_mgxs(nuscatt_mgxs, scatt_mgxs,
|
||||
xs_type=xs_type, nuclide=[nuclide],
|
||||
subdomain=subdomain)
|
||||
xsdata.set_multiplicity_matrix_mgxs(nuscatt_mgxs, scatt_mgxs,
|
||||
xs_type=xs_type,
|
||||
nuclide=[nuclide],
|
||||
subdomain=subdomain)
|
||||
using_multiplicity = True
|
||||
else:
|
||||
using_multiplicity = False
|
||||
|
||||
if using_multiplicity:
|
||||
nuscatt_mgxs = self.get_mgxs(domain, 'nu-scatter matrix')
|
||||
xsdata.set_scatter_mgxs(nuscatt_mgxs, xs_type=xs_type,
|
||||
nuclide=[nuclide], subdomain=subdomain)
|
||||
xsdata.set_scatter_matrix_mgxs(nuscatt_mgxs, xs_type=xs_type,
|
||||
nuclide=[nuclide],
|
||||
subdomain=subdomain)
|
||||
else:
|
||||
if 'nu-scatter matrix' in self.mgxs_types:
|
||||
nuscatt_mgxs = self.get_mgxs(domain, 'nu-scatter matrix')
|
||||
xsdata.set_scatter_mgxs(nuscatt_mgxs, xs_type=xs_type,
|
||||
nuclide=[nuclide],
|
||||
subdomain=subdomain)
|
||||
xsdata.set_scatter_matrix_mgxs(nuscatt_mgxs, xs_type=xs_type,
|
||||
nuclide=[nuclide],
|
||||
subdomain=subdomain)
|
||||
|
||||
# Since we are not using multiplicity, then
|
||||
# scattering multiplication (nu-scatter) must be
|
||||
# accounted for approximately by using an adjusted
|
||||
# absorption cross section.
|
||||
if 'total' in self.mgxs_types:
|
||||
xsdata.absorption = \
|
||||
np.subtract(xsdata.total,
|
||||
np.sum(xsdata.scatter[0, :, :], axis=1))
|
||||
if 'total' in self.mgxs_types or 'transport' in self.mgxs_types:
|
||||
for i in range(len(xsdata.temperatures)):
|
||||
xsdata._absorption[i] = \
|
||||
np.subtract(xsdata._total[i], np.sum(
|
||||
xsdata._scatter_matrix[i][0, :, :], axis=1))
|
||||
|
||||
return xsdata
|
||||
|
||||
def create_mg_library(self, xs_type='macro', xsdata_names=None,
|
||||
tabular_legendre=None, tabular_points=33):
|
||||
def create_mg_library(self, xs_type='macro', xsdata_names=None):
|
||||
"""Creates an openmc.MGXSLibrary object to contain the MGXS data for the
|
||||
Multi-Group mode of OpenMC.
|
||||
|
||||
Note that this library will not make use of nested temperature tables.
|
||||
Every dataset in the library will be treated as if it was at the same
|
||||
default temperature.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
xs_type: {'macro', 'micro'}
|
||||
|
|
@ -1031,18 +1018,6 @@ class Library(object):
|
|||
xsdata_names : Iterable of str
|
||||
List of names to apply to the "xsdata" entries in the
|
||||
resultant mgxs data file. Defaults to 'set1', 'set2', ...
|
||||
tabular_legendre : None or bool
|
||||
Flag to denote whether or not the Legendre expansion of the
|
||||
scattering angular distribution is to be converted to a tabular
|
||||
representation by OpenMC. A value of `True` means that it is to be
|
||||
converted while a value of `False` means that it will not be.
|
||||
Defaults to `None` which leaves the default behavior of OpenMC in
|
||||
place (the distribution is converted to a tabular representation).
|
||||
tabular_points : int
|
||||
This parameter is not used unless the ``tabular_legendre``
|
||||
parameter is set to `True`. In this case, this parameter sets the
|
||||
number of equally-spaced points in the domain of [-1,1] to be used
|
||||
in building the tabular distribution. Default is `33`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
|
@ -1069,7 +1044,7 @@ class Library(object):
|
|||
|
||||
cv.check_value('xs_type', xs_type, ['macro', 'micro'])
|
||||
if xsdata_names is not None:
|
||||
cv.check_iterable_type('xsdata_names', xsdata_names, basestring)
|
||||
cv.check_iterable_type('xsdata_names', xsdata_names, string_types)
|
||||
|
||||
# If gathering material-specific data, set the xs_type to macro
|
||||
if not self.by_nuclide:
|
||||
|
|
@ -1094,8 +1069,6 @@ class Library(object):
|
|||
|
||||
# Create XSdata and Macroscopic for this domain
|
||||
xsdata = self.get_xsdata(domain, xsdata_name,
|
||||
tabular_legendre=tabular_legendre,
|
||||
tabular_points=tabular_points,
|
||||
subdomain=subdomain)
|
||||
mgxs_file.add_xsdata(xsdata)
|
||||
i += 1
|
||||
|
|
@ -1113,45 +1086,34 @@ class Library(object):
|
|||
xsdata_name = 'set' + str(i + 1)
|
||||
else:
|
||||
xsdata_name = xsdata_names[i]
|
||||
if nuclide is not 'total':
|
||||
if nuclide != 'total':
|
||||
xsdata_name += '_' + nuclide
|
||||
|
||||
xsdata = self.get_xsdata(domain, xsdata_name,
|
||||
nuclide=nuclide, xs_type=xs_type,
|
||||
tabular_legendre=tabular_legendre,
|
||||
tabular_points=tabular_points)
|
||||
nuclide=nuclide, xs_type=xs_type)
|
||||
|
||||
mgxs_file.add_xsdata(xsdata)
|
||||
|
||||
return mgxs_file
|
||||
|
||||
def create_mg_mode(self, xsdata_names=None, tabular_legendre=None,
|
||||
tabular_points=33, bc=['reflective'] * 6):
|
||||
def create_mg_mode(self, xsdata_names=None, bc=['reflective'] * 6):
|
||||
"""Creates an openmc.MGXSLibrary object to contain the MGXS data for the
|
||||
Multi-Group mode of OpenMC as well as the associated openmc.Materials
|
||||
and openmc.Geometry objects. The created Geometry is the same as that
|
||||
used to generate the MGXS data, with the only differences being
|
||||
modifications to point to newly-created Materials which point to the
|
||||
multi-group data. This method only creates a macroscopic
|
||||
MGXS Library even if nuclidic tallies are specified in the Library.
|
||||
and openmc.Geometry objects.
|
||||
|
||||
The created Geometry is the same as that used to generate the MGXS
|
||||
data, with the only differences being modifications to point to
|
||||
newly-created Materials which point to the multi-group data. This
|
||||
method only creates a macroscopic MGXS Library even if nuclidic tallies
|
||||
are specified in the Library. Note that this library will not make
|
||||
use of nested temperature tables. Every dataset in the library will
|
||||
be treated as if it was at the same default temperature.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
xsdata_names : Iterable of str
|
||||
List of names to apply to the "xsdata" entries in the
|
||||
resultant mgxs data file. Defaults to 'set1', 'set2', ...
|
||||
tabular_legendre : None or bool
|
||||
Flag to denote whether or not the Legendre expansion of the
|
||||
scattering angular distribution is to be converted to a tabular
|
||||
representation by OpenMC. A value of `True` means that it is to be
|
||||
converted while a value of `False` means that it will not be.
|
||||
Defaults to `None` which leaves the default behavior of OpenMC in
|
||||
place (the distribution is converted to a tabular representation).
|
||||
tabular_points : int
|
||||
This parameter is not used unless the ``tabular_legendre``
|
||||
parameter is set to `True`. In this case, this parameter sets the
|
||||
number of equally-spaced points in the domain of [-1,1] to be used
|
||||
in building the tabular distribution. Default is `33`.
|
||||
bc : iterable of {'reflective', 'periodic', 'transmission', or 'vacuum'}
|
||||
Boundary conditions for each of the four faces of a rectangle
|
||||
(if applying to a 2D mesh) or six faces of a parallelepiped
|
||||
|
|
@ -1198,8 +1160,7 @@ class Library(object):
|
|||
cv.check_length("domains", self.domains, 1, 1)
|
||||
|
||||
# Get the MGXS File Data
|
||||
mgxs_file = self.create_mg_library('macro', xsdata_names,
|
||||
tabular_legendre, tabular_points)
|
||||
mgxs_file = self.create_mg_library('macro', xsdata_names)
|
||||
|
||||
# Now move on the creating the geometry and assigning materials
|
||||
if self.domain_type == 'mesh':
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ import warnings
|
|||
import os
|
||||
import sys
|
||||
import copy
|
||||
import abc
|
||||
from abc import ABCMeta
|
||||
|
||||
from six import add_metaclass, string_types
|
||||
import numpy as np
|
||||
|
||||
import openmc
|
||||
|
|
@ -15,8 +16,6 @@ from openmc.mgxs import MGXS
|
|||
from openmc.mgxs.mgxs import _DOMAIN_TO_FILTER
|
||||
import openmc.checkvalue as cv
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
# Supported cross section types
|
||||
MDGXS_TYPES = ['delayed-nu-fission',
|
||||
|
|
@ -28,6 +27,7 @@ MDGXS_TYPES = ['delayed-nu-fission',
|
|||
MAX_DELAYED_GROUPS = 8
|
||||
|
||||
|
||||
@add_metaclass(ABCMeta)
|
||||
class MDGXS(MGXS):
|
||||
"""An abstract multi-delayed-group cross section for some energy and delayed
|
||||
group structures within some spatial domain.
|
||||
|
|
@ -117,10 +117,6 @@ class MDGXS(MGXS):
|
|||
The key used to index multi-group cross sections in an HDF5 data store
|
||||
|
||||
"""
|
||||
|
||||
# This is an abstract class which cannot be instantiated
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
def __init__(self, domain=None, domain_type=None, energy_groups=None,
|
||||
delayed_groups=None, by_nuclide=False, name=''):
|
||||
super(MDGXS, self).__init__(domain, domain_type, energy_groups,
|
||||
|
|
@ -322,7 +318,7 @@ class MDGXS(MGXS):
|
|||
filter_bins = []
|
||||
|
||||
# Construct a collection of the domain filter bins
|
||||
if not isinstance(subdomains, basestring):
|
||||
if not isinstance(subdomains, string_types):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral,
|
||||
max_depth=3)
|
||||
for subdomain in subdomains:
|
||||
|
|
@ -330,7 +326,7 @@ class MDGXS(MGXS):
|
|||
filter_bins.append((subdomain,))
|
||||
|
||||
# Construct list of energy group bounds tuples for all requested groups
|
||||
if not isinstance(groups, basestring):
|
||||
if not isinstance(groups, string_types):
|
||||
cv.check_iterable_type('groups', groups, Integral)
|
||||
for group in groups:
|
||||
filters.append(openmc.EnergyFilter)
|
||||
|
|
@ -338,7 +334,7 @@ class MDGXS(MGXS):
|
|||
(self.energy_groups.get_group_bounds(group),))
|
||||
|
||||
# Construct list of delayed group tuples for all requested groups
|
||||
if not isinstance(delayed_groups, basestring):
|
||||
if not isinstance(delayed_groups, string_types):
|
||||
cv.check_type('delayed groups', delayed_groups, list, int)
|
||||
for delayed_group in delayed_groups:
|
||||
filters.append(openmc.DelayedGroupFilter)
|
||||
|
|
@ -434,7 +430,7 @@ class MDGXS(MGXS):
|
|||
|
||||
"""
|
||||
|
||||
cv.check_iterable_type('nuclides', nuclides, basestring)
|
||||
cv.check_iterable_type('nuclides', nuclides, string_types)
|
||||
cv.check_iterable_type('energy_groups', groups, Integral)
|
||||
cv.check_type('delayed groups', delayed_groups, list, int)
|
||||
|
||||
|
|
@ -544,7 +540,7 @@ class MDGXS(MGXS):
|
|||
return
|
||||
|
||||
# Construct a collection of the subdomains to report
|
||||
if not isinstance(subdomains, basestring):
|
||||
if not isinstance(subdomains, string_types):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral)
|
||||
elif self.domain_type == 'distribcell':
|
||||
subdomains = np.arange(self.num_subdomains, dtype=np.int)
|
||||
|
|
@ -561,7 +557,7 @@ class MDGXS(MGXS):
|
|||
elif nuclides == 'sum':
|
||||
nuclides = ['sum']
|
||||
else:
|
||||
cv.check_iterable_type('nuclides', nuclides, basestring)
|
||||
cv.check_iterable_type('nuclides', nuclides, string_types)
|
||||
else:
|
||||
nuclides = ['sum']
|
||||
|
||||
|
|
@ -651,8 +647,8 @@ class MDGXS(MGXS):
|
|||
|
||||
"""
|
||||
|
||||
cv.check_type('filename', filename, basestring)
|
||||
cv.check_type('directory', directory, basestring)
|
||||
cv.check_type('filename', filename, string_types)
|
||||
cv.check_type('directory', directory, string_types)
|
||||
cv.check_value('format', format, ['csv', 'excel', 'pickle', 'latex'])
|
||||
cv.check_value('xs_type', xs_type, ['macro', 'micro'])
|
||||
|
||||
|
|
@ -742,11 +738,11 @@ class MDGXS(MGXS):
|
|||
|
||||
"""
|
||||
|
||||
if not isinstance(groups, basestring):
|
||||
if not isinstance(groups, string_types):
|
||||
cv.check_iterable_type('groups', groups, Integral)
|
||||
if nuclides != 'all' and nuclides != 'sum':
|
||||
cv.check_iterable_type('nuclides', nuclides, basestring)
|
||||
if not isinstance(delayed_groups, basestring):
|
||||
cv.check_iterable_type('nuclides', nuclides, string_types)
|
||||
if not isinstance(delayed_groups, string_types):
|
||||
cv.check_type('delayed groups', delayed_groups, list, int)
|
||||
|
||||
cv.check_value('xs_type', xs_type, ['macro', 'micro'])
|
||||
|
|
@ -821,7 +817,7 @@ class MDGXS(MGXS):
|
|||
columns = ['group in']
|
||||
|
||||
# Select out those groups the user requested
|
||||
if not isinstance(groups, basestring):
|
||||
if not isinstance(groups, string_types):
|
||||
if 'group in' in df:
|
||||
df = df[df['group in'].isin(groups)]
|
||||
if 'group out' in df:
|
||||
|
|
@ -1212,7 +1208,7 @@ class ChiDelayed(MDGXS):
|
|||
filter_bins = []
|
||||
|
||||
# Construct a collection of the domain filter bins
|
||||
if not isinstance(subdomains, basestring):
|
||||
if not isinstance(subdomains, string_types):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral,
|
||||
max_depth=3)
|
||||
for subdomain in subdomains:
|
||||
|
|
@ -1220,7 +1216,7 @@ class ChiDelayed(MDGXS):
|
|||
filter_bins.append((subdomain,))
|
||||
|
||||
# Construct list of energy group bounds tuples for all requested groups
|
||||
if not isinstance(groups, basestring):
|
||||
if not isinstance(groups, string_types):
|
||||
cv.check_iterable_type('groups', groups, Integral)
|
||||
for group in groups:
|
||||
filters.append(openmc.EnergyoutFilter)
|
||||
|
|
@ -1228,7 +1224,7 @@ class ChiDelayed(MDGXS):
|
|||
(self.energy_groups.get_group_bounds(group),))
|
||||
|
||||
# Construct list of delayed group tuples for all requested groups
|
||||
if not isinstance(delayed_groups, basestring):
|
||||
if not isinstance(delayed_groups, string_types):
|
||||
cv.check_type('delayed groups', delayed_groups, list, int)
|
||||
for delayed_group in delayed_groups:
|
||||
filters.append(openmc.DelayedGroupFilter)
|
||||
|
|
@ -1276,7 +1272,7 @@ class ChiDelayed(MDGXS):
|
|||
|
||||
# Get chi delayed for user-specified nuclides in the domain
|
||||
else:
|
||||
cv.check_iterable_type('nuclides', nuclides, basestring)
|
||||
cv.check_iterable_type('nuclides', nuclides, string_types)
|
||||
xs = self.xs_tally.get_values(filters=filters,
|
||||
filter_bins=filter_bins,
|
||||
nuclides=nuclides, value=value)
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@ import warnings
|
|||
import os
|
||||
import sys
|
||||
import copy
|
||||
import abc
|
||||
from abc import ABCMeta
|
||||
import itertools
|
||||
|
||||
from six import add_metaclass, string_types
|
||||
import numpy as np
|
||||
|
||||
import openmc
|
||||
|
|
@ -16,9 +17,6 @@ import openmc.checkvalue as cv
|
|||
from openmc.tallies import ESTIMATOR_TYPES
|
||||
from openmc.mgxs import EnergyGroups
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
# Supported cross section types
|
||||
MGXS_TYPES = ['total',
|
||||
|
|
@ -61,6 +59,7 @@ _DOMAINS = (openmc.Cell,
|
|||
openmc.Mesh)
|
||||
|
||||
|
||||
@add_metaclass(ABCMeta)
|
||||
class MGXS(object):
|
||||
"""An abstract multi-group cross section for some energy group structure
|
||||
within some spatial domain.
|
||||
|
|
@ -145,10 +144,6 @@ class MGXS(object):
|
|||
The key used to index multi-group cross sections in an HDF5 data store
|
||||
|
||||
"""
|
||||
|
||||
# This is an abstract class which cannot be instantiated
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
def __init__(self, domain=None, domain_type=None,
|
||||
energy_groups=None, by_nuclide=False, name=''):
|
||||
self._name = ''
|
||||
|
|
@ -368,7 +363,7 @@ class MGXS(object):
|
|||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
cv.check_type('name', name, basestring)
|
||||
cv.check_type('name', name, string_types)
|
||||
self._name = name
|
||||
|
||||
@by_nuclide.setter
|
||||
|
|
@ -378,7 +373,7 @@ class MGXS(object):
|
|||
|
||||
@nuclides.setter
|
||||
def nuclides(self, nuclides):
|
||||
cv.check_iterable_type('nuclides', nuclides, basestring)
|
||||
cv.check_iterable_type('nuclides', nuclides, string_types)
|
||||
self._nuclides = nuclides
|
||||
|
||||
@estimator.setter
|
||||
|
|
@ -562,7 +557,7 @@ class MGXS(object):
|
|||
|
||||
"""
|
||||
|
||||
cv.check_type('nuclide', nuclide, basestring)
|
||||
cv.check_type('nuclide', nuclide, string_types)
|
||||
|
||||
# Get list of all nuclides in the spatial domain
|
||||
nuclides = self.domain.get_nuclide_densities()
|
||||
|
|
@ -788,7 +783,7 @@ class MGXS(object):
|
|||
filter_bins = []
|
||||
|
||||
# Construct a collection of the domain filter bins
|
||||
if not isinstance(subdomains, basestring):
|
||||
if not isinstance(subdomains, string_types):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral,
|
||||
max_depth=3)
|
||||
for subdomain in subdomains:
|
||||
|
|
@ -796,7 +791,7 @@ class MGXS(object):
|
|||
filter_bins.append((subdomain,))
|
||||
|
||||
# Construct list of energy group bounds tuples for all requested groups
|
||||
if not isinstance(groups, basestring):
|
||||
if not isinstance(groups, string_types):
|
||||
cv.check_iterable_type('groups', groups, Integral)
|
||||
for group in groups:
|
||||
filters.append(openmc.EnergyFilter)
|
||||
|
|
@ -958,7 +953,7 @@ class MGXS(object):
|
|||
"""
|
||||
|
||||
# Construct a collection of the subdomain filter bins to average across
|
||||
if not isinstance(subdomains, basestring):
|
||||
if not isinstance(subdomains, string_types):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral)
|
||||
elif self.domain_type == 'distribcell':
|
||||
subdomains = np.arange(self.num_subdomains)
|
||||
|
|
@ -1013,7 +1008,7 @@ class MGXS(object):
|
|||
|
||||
"""
|
||||
|
||||
cv.check_iterable_type('nuclides', nuclides, basestring)
|
||||
cv.check_iterable_type('nuclides', nuclides, string_types)
|
||||
cv.check_iterable_type('energy_groups', groups, Integral)
|
||||
|
||||
# Build lists of filters and filter bins to slice
|
||||
|
|
@ -1167,7 +1162,7 @@ class MGXS(object):
|
|||
"""
|
||||
|
||||
# Construct a collection of the subdomains to report
|
||||
if not isinstance(subdomains, basestring):
|
||||
if not isinstance(subdomains, string_types):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral)
|
||||
elif self.domain_type == 'distribcell':
|
||||
subdomains = np.arange(self.num_subdomains, dtype=np.int)
|
||||
|
|
@ -1184,7 +1179,7 @@ class MGXS(object):
|
|||
elif nuclides == 'sum':
|
||||
nuclides = ['sum']
|
||||
else:
|
||||
cv.check_iterable_type('nuclides', nuclides, basestring)
|
||||
cv.check_iterable_type('nuclides', nuclides, string_types)
|
||||
else:
|
||||
nuclides = ['sum']
|
||||
|
||||
|
|
@ -1302,7 +1297,7 @@ class MGXS(object):
|
|||
xs_results = h5py.File(filename, 'w')
|
||||
|
||||
# Construct a collection of the subdomains to report
|
||||
if not isinstance(subdomains, basestring):
|
||||
if not isinstance(subdomains, string_types):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral)
|
||||
elif self.domain_type == 'distribcell':
|
||||
subdomains = np.arange(self.num_subdomains, dtype=np.int)
|
||||
|
|
@ -1323,7 +1318,7 @@ class MGXS(object):
|
|||
elif nuclides == 'sum':
|
||||
nuclides = ['sum']
|
||||
else:
|
||||
cv.check_iterable_type('nuclides', nuclides, basestring)
|
||||
cv.check_iterable_type('nuclides', nuclides, string_types)
|
||||
else:
|
||||
nuclides = ['sum']
|
||||
|
||||
|
|
@ -1401,8 +1396,8 @@ class MGXS(object):
|
|||
|
||||
"""
|
||||
|
||||
cv.check_type('filename', filename, basestring)
|
||||
cv.check_type('directory', directory, basestring)
|
||||
cv.check_type('filename', filename, string_types)
|
||||
cv.check_type('directory', directory, string_types)
|
||||
cv.check_value('format', format, ['csv', 'excel', 'pickle', 'latex'])
|
||||
cv.check_value('xs_type', xs_type, ['macro', 'micro'])
|
||||
|
||||
|
|
@ -1488,10 +1483,10 @@ class MGXS(object):
|
|||
|
||||
"""
|
||||
|
||||
if not isinstance(groups, basestring):
|
||||
if not isinstance(groups, string_types):
|
||||
cv.check_iterable_type('groups', groups, Integral)
|
||||
if nuclides != 'all' and nuclides != 'sum':
|
||||
cv.check_iterable_type('nuclides', nuclides, basestring)
|
||||
cv.check_iterable_type('nuclides', nuclides, string_types)
|
||||
cv.check_value('xs_type', xs_type, ['macro', 'micro'])
|
||||
|
||||
# Get a Pandas DataFrame from the derived xs tally
|
||||
|
|
@ -1530,7 +1525,7 @@ class MGXS(object):
|
|||
|
||||
# Override energy groups bounds with indices
|
||||
all_groups = np.arange(self.num_groups, 0, -1, dtype=np.int)
|
||||
all_groups = np.repeat(all_groups, len(query_nuclides))
|
||||
all_groups = np.repeat(all_groups, len(query_nuclides))
|
||||
if 'energy low [MeV]' in df and 'energyout low [MeV]' in df:
|
||||
df.rename(columns={'energy low [MeV]': 'group in'},
|
||||
inplace=True)
|
||||
|
|
@ -1563,7 +1558,7 @@ class MGXS(object):
|
|||
columns = ['group in']
|
||||
|
||||
# Select out those groups the user requested
|
||||
if not isinstance(groups, basestring):
|
||||
if not isinstance(groups, string_types):
|
||||
if 'group in' in df:
|
||||
df = df[df['group in'].isin(groups)]
|
||||
if 'group out' in df:
|
||||
|
|
@ -1616,6 +1611,7 @@ class MGXS(object):
|
|||
return 'cm^-1' if xs_type == 'macro' else 'barns'
|
||||
|
||||
|
||||
@add_metaclass(ABCMeta)
|
||||
class MatrixMGXS(MGXS):
|
||||
"""An abstract multi-group cross section for some energy group structure
|
||||
within some spatial domain. This class is specifically intended for
|
||||
|
|
@ -1703,10 +1699,6 @@ class MatrixMGXS(MGXS):
|
|||
The key used to index multi-group cross sections in an HDF5 data store
|
||||
|
||||
"""
|
||||
|
||||
# This is an abstract class which cannot be instantiated
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
@property
|
||||
def filters(self):
|
||||
# Create the non-domain specific Filters for the Tallies
|
||||
|
|
@ -1786,7 +1778,7 @@ class MatrixMGXS(MGXS):
|
|||
filter_bins = []
|
||||
|
||||
# Construct a collection of the domain filter bins
|
||||
if not isinstance(subdomains, basestring):
|
||||
if not isinstance(subdomains, string_types):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral,
|
||||
max_depth=3)
|
||||
for subdomain in subdomains:
|
||||
|
|
@ -1794,7 +1786,7 @@ class MatrixMGXS(MGXS):
|
|||
filter_bins.append((subdomain,))
|
||||
|
||||
# Construct list of energy group bounds tuples for all requested groups
|
||||
if not isinstance(in_groups, basestring):
|
||||
if not isinstance(in_groups, string_types):
|
||||
cv.check_iterable_type('groups', in_groups, Integral)
|
||||
for group in in_groups:
|
||||
filters.append(openmc.EnergyFilter)
|
||||
|
|
@ -1802,7 +1794,7 @@ class MatrixMGXS(MGXS):
|
|||
self.energy_groups.get_group_bounds(group),))
|
||||
|
||||
# Construct list of energy group bounds tuples for all requested groups
|
||||
if not isinstance(out_groups, basestring):
|
||||
if not isinstance(out_groups, string_types):
|
||||
cv.check_iterable_type('groups', out_groups, Integral)
|
||||
for group in out_groups:
|
||||
filters.append(openmc.EnergyoutFilter)
|
||||
|
|
@ -1948,7 +1940,7 @@ class MatrixMGXS(MGXS):
|
|||
"""
|
||||
|
||||
# Construct a collection of the subdomains to report
|
||||
if not isinstance(subdomains, basestring):
|
||||
if not isinstance(subdomains, string_types):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral)
|
||||
elif self.domain_type == 'distribcell':
|
||||
subdomains = np.arange(self.num_subdomains, dtype=np.int)
|
||||
|
|
@ -1965,7 +1957,7 @@ class MatrixMGXS(MGXS):
|
|||
if nuclides == 'sum':
|
||||
nuclides = ['sum']
|
||||
else:
|
||||
cv.check_iterable_type('nuclides', nuclides, basestring)
|
||||
cv.check_iterable_type('nuclides', nuclides, string_types)
|
||||
else:
|
||||
nuclides = ['sum']
|
||||
|
||||
|
|
@ -3621,21 +3613,21 @@ class ScatterMatrixXS(MatrixMGXS):
|
|||
filter_bins = []
|
||||
|
||||
# Construct a collection of the domain filter bins
|
||||
if not isinstance(subdomains, basestring):
|
||||
if not isinstance(subdomains, string_types):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral, max_depth=3)
|
||||
for subdomain in subdomains:
|
||||
filters.append(_DOMAIN_TO_FILTER[self.domain_type])
|
||||
filter_bins.append((subdomain,))
|
||||
|
||||
# Construct list of energy group bounds tuples for all requested groups
|
||||
if not isinstance(in_groups, basestring):
|
||||
if not isinstance(in_groups, string_types):
|
||||
cv.check_iterable_type('groups', in_groups, Integral)
|
||||
for group in in_groups:
|
||||
filters.append(openmc.EnergyFilter)
|
||||
filter_bins.append((self.energy_groups.get_group_bounds(group),))
|
||||
|
||||
# Construct list of energy group bounds tuples for all requested groups
|
||||
if not isinstance(out_groups, basestring):
|
||||
if not isinstance(out_groups, string_types):
|
||||
cv.check_iterable_type('groups', out_groups, Integral)
|
||||
for group in out_groups:
|
||||
filters.append(openmc.EnergyoutFilter)
|
||||
|
|
@ -3809,7 +3801,7 @@ class ScatterMatrixXS(MatrixMGXS):
|
|||
"""
|
||||
|
||||
# Construct a collection of the subdomains to report
|
||||
if not isinstance(subdomains, basestring):
|
||||
if not isinstance(subdomains, string_types):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral)
|
||||
elif self.domain_type == 'distribcell':
|
||||
subdomains = np.arange(self.num_subdomains, dtype=np.int)
|
||||
|
|
@ -3826,7 +3818,7 @@ class ScatterMatrixXS(MatrixMGXS):
|
|||
if nuclides == 'sum':
|
||||
nuclides = ['sum']
|
||||
else:
|
||||
cv.check_iterable_type('nuclides', nuclides, basestring)
|
||||
cv.check_iterable_type('nuclides', nuclides, string_types)
|
||||
else:
|
||||
nuclides = ['sum']
|
||||
|
||||
|
|
@ -4609,14 +4601,14 @@ class Chi(MGXS):
|
|||
filter_bins = []
|
||||
|
||||
# Construct a collection of the domain filter bins
|
||||
if not isinstance(subdomains, basestring):
|
||||
if not isinstance(subdomains, string_types):
|
||||
cv.check_iterable_type('subdomains', subdomains, Integral, max_depth=3)
|
||||
for subdomain in subdomains:
|
||||
filters.append(_DOMAIN_TO_FILTER[self.domain_type])
|
||||
filter_bins.append((subdomain,))
|
||||
|
||||
# Construct list of energy group bounds tuples for all requested groups
|
||||
if not isinstance(groups, basestring):
|
||||
if not isinstance(groups, string_types):
|
||||
cv.check_iterable_type('groups', groups, Integral)
|
||||
for group in groups:
|
||||
filters.append(openmc.EnergyoutFilter)
|
||||
|
|
@ -4661,7 +4653,7 @@ class Chi(MGXS):
|
|||
|
||||
# Get chi for user-specified nuclides in the domain
|
||||
else:
|
||||
cv.check_iterable_type('nuclides', nuclides, basestring)
|
||||
cv.check_iterable_type('nuclides', nuclides, string_types)
|
||||
xs = self.xs_tally.get_values(filters=filters,
|
||||
filter_bins=filter_bins,
|
||||
nuclides=nuclides, value=value)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -10,6 +10,7 @@ from heapq import heappush, heappop
|
|||
from math import pi, sin, cos, floor, log10, sqrt
|
||||
from abc import ABCMeta, abstractproperty, abstractmethod
|
||||
|
||||
from six import add_metaclass
|
||||
import numpy as np
|
||||
try:
|
||||
import scipy.spatial
|
||||
|
|
@ -95,6 +96,7 @@ class TRISO(openmc.Cell):
|
|||
k_min:k_max+1, j_min:j_max+1, i_min:i_max+1]))
|
||||
|
||||
|
||||
@add_metaclass(ABCMeta)
|
||||
class _Domain(object):
|
||||
"""Container in which to pack particles.
|
||||
|
||||
|
|
@ -123,9 +125,6 @@ class _Domain(object):
|
|||
Volume of the container.
|
||||
|
||||
"""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
def __init__(self, particle_radius, center=[0., 0., 0.]):
|
||||
self._cell_length = None
|
||||
self._limits = None
|
||||
|
|
|
|||
|
|
@ -2,10 +2,9 @@ from numbers import Integral
|
|||
import sys
|
||||
import warnings
|
||||
|
||||
from openmc.checkvalue import check_type
|
||||
from six import string_types
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
from openmc.checkvalue import check_type
|
||||
|
||||
|
||||
class Nuclide(object):
|
||||
|
|
@ -39,7 +38,7 @@ class Nuclide(object):
|
|||
return False
|
||||
else:
|
||||
return True
|
||||
elif isinstance(other, basestring) and other == self.name:
|
||||
elif isinstance(other, string_types) and other == self.name:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
|
@ -73,7 +72,7 @@ class Nuclide(object):
|
|||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
check_type('name', name, basestring)
|
||||
check_type('name', name, string_types)
|
||||
self._name = name
|
||||
|
||||
if '-' in name:
|
||||
|
|
|
|||
|
|
@ -4,14 +4,13 @@ from xml.etree import ElementTree as ET
|
|||
import sys
|
||||
import warnings
|
||||
|
||||
from six import string_types
|
||||
import numpy as np
|
||||
|
||||
import openmc
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.clean_xml import clean_xml_indentation
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
# A static variable for auto-generated Plot IDs
|
||||
AUTO_PLOT_ID = 10000
|
||||
|
|
@ -166,7 +165,7 @@ class Plot(object):
|
|||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
cv.check_type('plot name', name, basestring)
|
||||
cv.check_type('plot name', name, string_types)
|
||||
self._name = name
|
||||
|
||||
@width.setter
|
||||
|
|
@ -191,24 +190,24 @@ class Plot(object):
|
|||
|
||||
@filename.setter
|
||||
def filename(self, filename):
|
||||
cv.check_type('filename', filename, basestring)
|
||||
cv.check_type('filename', filename, string_types)
|
||||
self._filename = filename
|
||||
|
||||
@color.setter
|
||||
def color(self, color):
|
||||
cv.check_type('plot color', color, basestring)
|
||||
cv.check_type('plot color', color, string_types)
|
||||
cv.check_value('plot color', color, ['cell', 'mat'])
|
||||
self._color = color
|
||||
|
||||
@type.setter
|
||||
def type(self, plottype):
|
||||
cv.check_type('plot type', plottype, basestring)
|
||||
cv.check_type('plot type', plottype, string_types)
|
||||
cv.check_value('plot type', plottype, ['slice', 'voxel'])
|
||||
self._type = plottype
|
||||
|
||||
@basis.setter
|
||||
def basis(self, basis):
|
||||
cv.check_type('plot basis', basis, basestring)
|
||||
cv.check_type('plot basis', basis, string_types)
|
||||
cv.check_value('plot basis', basis, ['xy', 'xz', 'yz'])
|
||||
self._basis = basis
|
||||
|
||||
|
|
@ -387,7 +386,7 @@ class Plot(object):
|
|||
cv.check_less_than('alpha', alpha, 1., equality=True)
|
||||
|
||||
# Get a background (R,G,B) tuple to apply in alpha compositing
|
||||
if isinstance(background, basestring):
|
||||
if isinstance(background, string_types):
|
||||
if background == 'white':
|
||||
background = (255, 255, 255)
|
||||
elif background == 'black':
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
from abc import ABCMeta, abstractmethod
|
||||
from collections import Iterable
|
||||
|
||||
from six import add_metaclass
|
||||
import numpy as np
|
||||
|
||||
from openmc.checkvalue import check_type
|
||||
|
||||
|
||||
@add_metaclass(ABCMeta)
|
||||
class Region(object):
|
||||
"""Region of space that can be assigned to a cell.
|
||||
|
||||
|
|
@ -16,9 +18,6 @@ class Region(object):
|
|||
created through operators of the Surface and Region classes.
|
||||
|
||||
"""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
def __and__(self, other):
|
||||
return Intersection(self, other)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,15 +4,13 @@ import warnings
|
|||
from xml.etree import ElementTree as ET
|
||||
import sys
|
||||
|
||||
from six import string_types
|
||||
import numpy as np
|
||||
|
||||
from openmc.clean_xml import clean_xml_indentation
|
||||
import openmc.checkvalue as cv
|
||||
from openmc import Nuclide, VolumeCalculation, Source
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
class Settings(object):
|
||||
"""Settings used for an OpenMC simulation.
|
||||
|
|
@ -89,10 +87,14 @@ class Settings(object):
|
|||
Seed for the linear congruential pseudorandom number generator
|
||||
survival_biasing : bool
|
||||
Indicate whether survival biasing is to be used
|
||||
weight : float
|
||||
Weight cutoff below which particle undergo Russian roulette
|
||||
weight_avg : float
|
||||
Weight assigned to particles that are not killed after Russian roulette
|
||||
cutoff : dict
|
||||
Dictionary defining weight cutoff and energy cutoff. The dictionary may
|
||||
have three keys, 'weight', 'weight_avg' and 'energy'. Value for 'weight'
|
||||
should be a float indicating weight cutoff below which particle undergo
|
||||
Russian roulette. Value for 'weight_avg' should be a float indicating
|
||||
weight assigned to particles that are not killed after Russian
|
||||
roulette. Value of energy should be a float indicating energy in MeV
|
||||
below which particle will be killed.
|
||||
entropy_dimension : tuple or list
|
||||
Number of Shannon entropy mesh cells in the x, y, and z directions,
|
||||
respectively
|
||||
|
|
@ -100,6 +102,13 @@ class Settings(object):
|
|||
Coordinates of the lower-left point of the Shannon entropy mesh
|
||||
entropy_upper_right : tuple or list
|
||||
Coordinates of the upper-right point of the Shannon entropy mesh
|
||||
tabular_legendre : dict
|
||||
Determines if a multi-group scattering moment kernel expanded via
|
||||
Legendre polynomials is to be converted to a tabular distribution or
|
||||
not. Accepted keys are 'enable' and 'num_points'. The value for
|
||||
'enable' is a bool stating whether the conversion to tabular is
|
||||
performed; the value for 'num_points' sets the number of points to use
|
||||
in the tabular distribution, should 'enable' be True.
|
||||
temperature : dict
|
||||
Defines a default temperature and method for treating intermediate
|
||||
temperatures at which nuclear data doesn't exist. Accepted keys are
|
||||
|
|
@ -141,6 +150,8 @@ class Settings(object):
|
|||
The elastic scattering model to use for resonant isotopes
|
||||
volume_calculations : VolumeCalculation or iterable of VolumeCalculation
|
||||
Stochastic volume calculation specifications
|
||||
create_fission_neutrons : bool
|
||||
Indicate whether fission neutrons should be created or not.
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -200,11 +211,12 @@ class Settings(object):
|
|||
self._trace = None
|
||||
self._track = None
|
||||
|
||||
self._tabular_legendre = {}
|
||||
|
||||
self._temperature = {}
|
||||
|
||||
# Cutoff subelement
|
||||
self._weight = None
|
||||
self._weight_avg = None
|
||||
self._cutoff = None
|
||||
|
||||
# Uniform fission source subelement
|
||||
self._ufs_dimension = 1
|
||||
|
|
@ -227,6 +239,8 @@ class Settings(object):
|
|||
self._volume_calculations = cv.CheckedList(
|
||||
VolumeCalculation, 'volume calculations')
|
||||
|
||||
self._create_fission_neutrons = None
|
||||
|
||||
@property
|
||||
def run_mode(self):
|
||||
return self._run_mode
|
||||
|
|
@ -363,6 +377,10 @@ class Settings(object):
|
|||
def verbosity(self):
|
||||
return self._verbosity
|
||||
|
||||
@property
|
||||
def tabular_legendre(self):
|
||||
return self._tabular_legendre
|
||||
|
||||
@property
|
||||
def temperature(self):
|
||||
return self._temperature
|
||||
|
|
@ -376,12 +394,8 @@ class Settings(object):
|
|||
return self._track
|
||||
|
||||
@property
|
||||
def weight(self):
|
||||
return self._weight
|
||||
|
||||
@property
|
||||
def weight_avg(self):
|
||||
return self._weight_avg
|
||||
def cutoff(self):
|
||||
return self._cutoff
|
||||
|
||||
@property
|
||||
def ufs_dimension(self):
|
||||
|
|
@ -427,6 +441,10 @@ class Settings(object):
|
|||
def volume_calculations(self):
|
||||
return self._volume_calculations
|
||||
|
||||
@property
|
||||
def create_fission_neutrons(self):
|
||||
return self._create_fission_neutrons
|
||||
|
||||
@run_mode.setter
|
||||
def run_mode(self, run_mode):
|
||||
if run_mode not in ['eigenvalue', 'fixed source']:
|
||||
|
|
@ -529,7 +547,7 @@ class Settings(object):
|
|||
|
||||
@output_path.setter
|
||||
def output_path(self, output_path):
|
||||
cv.check_type('output path', output_path, basestring)
|
||||
cv.check_type('output path', output_path, string_types)
|
||||
self._output_path = output_path
|
||||
|
||||
@verbosity.setter
|
||||
|
|
@ -585,12 +603,12 @@ class Settings(object):
|
|||
|
||||
@cross_sections.setter
|
||||
def cross_sections(self, cross_sections):
|
||||
cv.check_type('cross sections', cross_sections, basestring)
|
||||
cv.check_type('cross sections', cross_sections, string_types)
|
||||
self._cross_sections = cross_sections
|
||||
|
||||
@multipole_library.setter
|
||||
def multipole_library(self, multipole_library):
|
||||
cv.check_type('cross sections', multipole_library, basestring)
|
||||
cv.check_type('cross sections', multipole_library, string_types)
|
||||
self._multipole_library = multipole_library
|
||||
|
||||
@ptables.setter
|
||||
|
|
@ -614,17 +632,29 @@ class Settings(object):
|
|||
cv.check_type('survival biasing', survival_biasing, bool)
|
||||
self._survival_biasing = survival_biasing
|
||||
|
||||
@weight.setter
|
||||
def weight(self, weight):
|
||||
cv.check_type('weight cutoff', weight, Real)
|
||||
cv.check_greater_than('weight cutoff', weight, 0.0)
|
||||
self._weight = weight
|
||||
@cutoff.setter
|
||||
def cutoff(self, cutoff):
|
||||
if not isinstance(cutoff, Mapping):
|
||||
msg = 'Unable to set cutoff from "{0}" which is not a '\
|
||||
' Python dictionary'.format(cutoff)
|
||||
raise ValueError(msg)
|
||||
for key in cutoff:
|
||||
if key == 'weight':
|
||||
cv.check_type('weight cutoff', cutoff['weight'], Real)
|
||||
cv.check_greater_than('weight cutoff', cutoff['weight'], 0.0)
|
||||
elif key == 'weight_avg':
|
||||
cv.check_type('average survival weight', cutoff['weight_avg'],
|
||||
Real)
|
||||
cv.check_greater_than('average survival weight',
|
||||
cutoff['weight_avg'], 0.0)
|
||||
elif key == 'energy':
|
||||
cv.check_type('energy cutoff', cutoff['energy'], Real)
|
||||
cv.check_greater_than('energy cutoff', cutoff['energy'], 0.0)
|
||||
else:
|
||||
msg = 'Unable to set cutoff to "{0}" which is unsupported by '\
|
||||
'OpenMC'.format(key)
|
||||
|
||||
@weight_avg.setter
|
||||
def weight_avg(self, weight_avg):
|
||||
cv.check_type('average survival weight', weight_avg, Real)
|
||||
cv.check_greater_than('average survival weight', weight_avg, 0.0)
|
||||
self._weight_avg = weight_avg
|
||||
self._cutoff = cutoff
|
||||
|
||||
@entropy_dimension.setter
|
||||
def entropy_dimension(self, dimension):
|
||||
|
|
@ -668,6 +698,19 @@ class Settings(object):
|
|||
cv.check_type('no reduction option', no_reduce, bool)
|
||||
self._no_reduce = no_reduce
|
||||
|
||||
@tabular_legendre.setter
|
||||
def tabular_legendre(self, tabular_legendre):
|
||||
cv.check_type('tabular_legendre settings', tabular_legendre, Mapping)
|
||||
for key, value in tabular_legendre.items():
|
||||
cv.check_value('tabular_legendre key', key,
|
||||
['enable', 'num_points'])
|
||||
if key == 'enable':
|
||||
cv.check_type('enable tabular_legendre', value, bool)
|
||||
elif key == 'num_points':
|
||||
cv.check_type('num_points tabular_legendre', value, Integral)
|
||||
cv.check_greater_than('num_points tabular_legendre', value, 0)
|
||||
self._tabular_legendre = tabular_legendre
|
||||
|
||||
@temperature.setter
|
||||
def temperature(self, temperature):
|
||||
cv.check_type('temperature settings', temperature, Mapping)
|
||||
|
|
@ -826,6 +869,12 @@ class Settings(object):
|
|||
self._volume_calculations = cv.CheckedList(
|
||||
VolumeCalculation, 'stochastic volume calculations', vol_calcs)
|
||||
|
||||
@create_fission_neutrons.setter
|
||||
def create_fission_neutrons(self, create_fission_neutrons):
|
||||
cv.check_type('Whether create fission neutrons',
|
||||
create_fission_neutrons, bool)
|
||||
self._create_fission_neutrons = create_fission_neutrons
|
||||
|
||||
def _create_run_mode_subelement(self):
|
||||
|
||||
if self.run_mode == 'eigenvalue':
|
||||
|
|
@ -990,14 +1039,19 @@ class Settings(object):
|
|||
element.text = str(self._survival_biasing).lower()
|
||||
|
||||
def _create_cutoff_subelement(self):
|
||||
if self._weight is not None:
|
||||
if self._cutoff is not None:
|
||||
element = ET.SubElement(self._settings_file, "cutoff")
|
||||
if 'weight' in self._cutoff:
|
||||
subelement = ET.SubElement(element, "weight")
|
||||
subelement.text = str(self._cutoff['weight'])
|
||||
|
||||
subelement = ET.SubElement(element, "weight")
|
||||
subelement.text = str(self._weight)
|
||||
if 'weight_avg' in self._cutoff:
|
||||
subelement = ET.SubElement(element, "weight_avg")
|
||||
subelement.text = str(self._cutoff['weight_avg'])
|
||||
|
||||
subelement = ET.SubElement(element, "weight_avg")
|
||||
subelement.text = str(self._weight_avg)
|
||||
if 'energy' in self._cutoff:
|
||||
subelement = ET.SubElement(element, "energy")
|
||||
subelement.text = str(self._cutoff['energy'])
|
||||
|
||||
def _create_entropy_subelement(self):
|
||||
if self._entropy_lower_left is not None and \
|
||||
|
|
@ -1051,6 +1105,15 @@ class Settings(object):
|
|||
element = ET.SubElement(self._settings_file, "no_reduce")
|
||||
element.text = str(self._no_reduce).lower()
|
||||
|
||||
def _create_tabular_legendre_subelements(self):
|
||||
if self.tabular_legendre:
|
||||
element = ET.SubElement(self._settings_file, "tabular_legendre")
|
||||
subelement = ET.SubElement(element, "enable")
|
||||
subelement.text = str(self._tabular_legendre['enable']).lower()
|
||||
if 'num_points' in self._tabular_legendre:
|
||||
subelement = ET.SubElement(element, "num_points")
|
||||
subelement.text = str(self._tabular_legendre['num_points'])
|
||||
|
||||
def _create_temperature_subelements(self):
|
||||
if self.temperature:
|
||||
for key, value in sorted(self.temperature.items()):
|
||||
|
|
@ -1121,6 +1184,11 @@ class Settings(object):
|
|||
for r in self.resonance_scattering:
|
||||
elem.append(r.to_xml_element())
|
||||
|
||||
def _create_create_fission_neutrons_subelement(self):
|
||||
if self._create_fission_neutrons is not None:
|
||||
elem = ET.SubElement(self._settings_file, "create_fission_neutrons")
|
||||
elem.text = str(self._create_fission_neutrons).lower()
|
||||
|
||||
def export_to_xml(self, path='settings.xml'):
|
||||
"""Export simulation settings to an XML file.
|
||||
|
||||
|
|
@ -1157,6 +1225,7 @@ class Settings(object):
|
|||
self._create_no_reduce_subelement()
|
||||
self._create_threads_subelement()
|
||||
self._create_verbosity_subelement()
|
||||
self._create_tabular_legendre_subelements()
|
||||
self._create_temperature_subelements()
|
||||
self._create_trace_subelement()
|
||||
self._create_track_subelement()
|
||||
|
|
@ -1164,6 +1233,7 @@ class Settings(object):
|
|||
self._create_dd_subelement()
|
||||
self._create_resonance_scattering_subelement()
|
||||
self._create_volume_calcs_subelement()
|
||||
self._create_create_fission_neutrons_subelement()
|
||||
|
||||
# Clean the indentation in the file to be user-readable
|
||||
clean_xml_indentation(self._settings_file)
|
||||
|
|
|
|||
|
|
@ -2,13 +2,12 @@ from numbers import Real
|
|||
import sys
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
from six import string_types
|
||||
|
||||
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.
|
||||
|
|
@ -79,7 +78,7 @@ class Source(object):
|
|||
|
||||
@file.setter
|
||||
def file(self, filename):
|
||||
cv.check_type('source file', filename, basestring)
|
||||
cv.check_type('source file', filename, string_types)
|
||||
self._file = filename
|
||||
|
||||
@space.setter
|
||||
|
|
|
|||
|
|
@ -9,9 +9,6 @@ import numpy as np
|
|||
import openmc
|
||||
import openmc.checkvalue as cv
|
||||
|
||||
if sys.version > '3':
|
||||
long = int
|
||||
|
||||
|
||||
class StatePoint(object):
|
||||
"""State information on a simulation at a certain point in time (at the end
|
||||
|
|
|
|||
|
|
@ -5,15 +5,14 @@ from numbers import Real
|
|||
import sys
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
from six import add_metaclass
|
||||
import numpy as np
|
||||
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.stats.univariate import Univariate, Uniform
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
@add_metaclass(ABCMeta)
|
||||
class UnitSphere(object):
|
||||
"""Distribution of points on the unit sphere.
|
||||
|
||||
|
|
@ -31,9 +30,6 @@ class UnitSphere(object):
|
|||
Direction from which polar angle is measured
|
||||
|
||||
"""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
def __init__(self, reference_uvw=None):
|
||||
self._reference_uvw = None
|
||||
if reference_uvw is not None:
|
||||
|
|
@ -184,6 +180,7 @@ class Monodirectional(UnitSphere):
|
|||
return element
|
||||
|
||||
|
||||
@add_metaclass(ABCMeta)
|
||||
class Spatial(object):
|
||||
"""Distribution of locations in three-dimensional Euclidean space.
|
||||
|
||||
|
|
@ -191,9 +188,6 @@ class Spatial(object):
|
|||
distributions of source sites.
|
||||
|
||||
"""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
|
|
|||
|
|
@ -4,18 +4,18 @@ from numbers import Real
|
|||
import sys
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
from six import add_metaclass
|
||||
import numpy as np
|
||||
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.mixin import EqualityMixin
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
_INTERPOLATION_SCHEMES = ['histogram', 'linear-linear', 'linear-log',
|
||||
'log-linear', 'log-log']
|
||||
|
||||
|
||||
@add_metaclass(ABCMeta)
|
||||
class Univariate(EqualityMixin):
|
||||
"""Probability distribution of a single random variable.
|
||||
|
||||
|
|
@ -23,9 +23,6 @@ class Univariate(EqualityMixin):
|
|||
specific probability distribution.
|
||||
|
||||
"""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,12 @@ from xml.etree import ElementTree as ET
|
|||
import sys
|
||||
from math import sqrt
|
||||
|
||||
from six import add_metaclass, string_types
|
||||
import numpy as np
|
||||
|
||||
from openmc.checkvalue import check_type, check_value, check_greater_than
|
||||
from openmc.region import Region, Intersection
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
# A static variable for auto-generated Surface IDs
|
||||
AUTO_SURFACE_ID = 10000
|
||||
|
|
@ -134,14 +133,14 @@ class Surface(object):
|
|||
@name.setter
|
||||
def name(self, name):
|
||||
if name is not None:
|
||||
check_type('surface name', name, basestring)
|
||||
check_type('surface name', name, string_types)
|
||||
self._name = name
|
||||
else:
|
||||
self._name = ''
|
||||
|
||||
@boundary_type.setter
|
||||
def boundary_type(self, boundary_type):
|
||||
check_type('boundary type', boundary_type, basestring)
|
||||
check_type('boundary type', boundary_type, string_types)
|
||||
check_value('boundary type', boundary_type, _BC_TYPES)
|
||||
self._boundary_type = boundary_type
|
||||
|
||||
|
|
@ -642,6 +641,7 @@ class ZPlane(Plane):
|
|||
return point[2] - self.z0
|
||||
|
||||
|
||||
@add_metaclass(ABCMeta)
|
||||
class Cylinder(Surface):
|
||||
"""A cylinder whose length is parallel to the x-, y-, or z-axis.
|
||||
|
||||
|
|
@ -677,9 +677,6 @@ class Cylinder(Surface):
|
|||
Type of the surface
|
||||
|
||||
"""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
def __init__(self, surface_id=None, boundary_type='transmission',
|
||||
R=1., name=''):
|
||||
super(Cylinder, self).__init__(surface_id, boundary_type, name=name)
|
||||
|
|
@ -1210,7 +1207,7 @@ class Sphere(Surface):
|
|||
z = point[2] - self.z0
|
||||
return x**2 + y**2 + z**2 - self.r**2
|
||||
|
||||
|
||||
@add_metaclass(ABCMeta)
|
||||
class Cone(Surface):
|
||||
"""A conical surface parallel to the x-, y-, or z-axis.
|
||||
|
||||
|
|
@ -1257,9 +1254,6 @@ class Cone(Surface):
|
|||
Type of the surface
|
||||
|
||||
"""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
def __init__(self, surface_id=None, boundary_type='transmission',
|
||||
x0=0., y0=0., z0=0., R2=1., name=''):
|
||||
super(Cone, self).__init__(surface_id, boundary_type, name=name)
|
||||
|
|
|
|||
|
|
@ -11,15 +11,13 @@ import sys
|
|||
import warnings
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
from six import string_types
|
||||
import numpy as np
|
||||
|
||||
import openmc
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.clean_xml import clean_xml_indentation
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
# "Static" variable for auto-generated Tally IDs
|
||||
AUTO_TALLY_ID = 10000
|
||||
|
|
@ -33,9 +31,9 @@ _PRODUCT_TYPES = ['tensor', 'entrywise']
|
|||
|
||||
# The following indicate acceptable types when setting Tally.scores,
|
||||
# Tally.nuclides, and Tally.filters
|
||||
_SCORE_CLASSES = (basestring, openmc.CrossScore, openmc.AggregateScore)
|
||||
_NUCLIDE_CLASSES = (basestring, openmc.Nuclide, openmc.CrossNuclide,
|
||||
openmc.AggregateNuclide)
|
||||
_SCORE_CLASSES = string_types + (openmc.CrossScore, openmc.AggregateScore)
|
||||
_NUCLIDE_CLASSES = string_types + (openmc.Nuclide, openmc.CrossNuclide,
|
||||
openmc.AggregateNuclide)
|
||||
_FILTER_CLASSES = (openmc.Filter, openmc.CrossFilter, openmc.AggregateFilter)
|
||||
|
||||
# Valid types of estimators
|
||||
|
|
@ -446,7 +444,7 @@ class Tally(object):
|
|||
@name.setter
|
||||
def name(self, name):
|
||||
if name is not None:
|
||||
cv.check_type('tally name', name, basestring)
|
||||
cv.check_type('tally name', name, string_types)
|
||||
self._name = name
|
||||
else:
|
||||
self._name = ''
|
||||
|
|
@ -499,7 +497,7 @@ class Tally(object):
|
|||
raise ValueError(msg)
|
||||
|
||||
# If score is a string, strip whitespace
|
||||
if isinstance(score, basestring):
|
||||
if isinstance(score, string_types):
|
||||
scores[i] = score.strip()
|
||||
|
||||
self._scores = cv.CheckedList(_SCORE_CLASSES, 'tally scores', scores)
|
||||
|
|
@ -1381,7 +1379,7 @@ class Tally(object):
|
|||
|
||||
"""
|
||||
|
||||
cv.check_iterable_type('nuclides', nuclides, basestring)
|
||||
cv.check_iterable_type('nuclides', nuclides, string_types)
|
||||
|
||||
# Determine the score indices from any of the requested scores
|
||||
if nuclides:
|
||||
|
|
@ -1416,7 +1414,7 @@ class Tally(object):
|
|||
"""
|
||||
|
||||
for score in scores:
|
||||
if not isinstance(score, (basestring, openmc.CrossScore)):
|
||||
if not isinstance(score, string_types + (openmc.CrossScore,)):
|
||||
msg = 'Unable to get score indices for score "{0}" in Tally ' \
|
||||
'ID="{1}" since it is not a string or CrossScore'\
|
||||
.format(score, self.id)
|
||||
|
|
@ -1614,7 +1612,7 @@ class Tally(object):
|
|||
column_name = 'score'
|
||||
|
||||
for score in self.scores:
|
||||
if isinstance(score, (basestring, openmc.CrossScore)):
|
||||
if isinstance(score, string_types + (openmc.CrossScore,)):
|
||||
scores.append(str(score))
|
||||
elif isinstance(score, openmc.AggregateScore):
|
||||
scores.append(score.name)
|
||||
|
|
@ -1737,13 +1735,13 @@ class Tally(object):
|
|||
msg = 'The Tally ID="{0}" has no data to export'.format(self.id)
|
||||
raise KeyError(msg)
|
||||
|
||||
if not isinstance(filename, basestring):
|
||||
if not isinstance(filename, string_types):
|
||||
msg = 'Unable to export the results for Tally ID="{0}" to ' \
|
||||
'filename="{1}" since it is not a ' \
|
||||
'string'.format(self.id, filename)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif not isinstance(directory, basestring):
|
||||
elif not isinstance(directory, string_types):
|
||||
msg = 'Unable to export the results for Tally ID="{0}" to ' \
|
||||
'directory="{1}" since it is not a ' \
|
||||
'string'.format(self.id, directory)
|
||||
|
|
@ -2391,11 +2389,11 @@ class Tally(object):
|
|||
raise ValueError(msg)
|
||||
|
||||
# Check that the scores are valid
|
||||
if not isinstance(score1, (basestring, openmc.CrossScore)):
|
||||
if not isinstance(score1, string_types + (openmc.CrossScore,)):
|
||||
msg = 'Unable to swap score1 "{0}" in Tally ID="{1}" since it is ' \
|
||||
'not a string or CrossScore'.format(score1, self.id)
|
||||
raise ValueError(msg)
|
||||
elif not isinstance(score2, (basestring, openmc.CrossScore)):
|
||||
elif not isinstance(score2, string_types + (openmc.CrossScore,)):
|
||||
msg = 'Unable to swap score2 "{0}" in Tally ID="{1}" since it is ' \
|
||||
'not a string or CrossScore'.format(score2, self.id)
|
||||
raise ValueError(msg)
|
||||
|
|
|
|||
|
|
@ -4,10 +4,9 @@ import sys
|
|||
import warnings
|
||||
from collections import Iterable
|
||||
|
||||
import openmc.checkvalue as cv
|
||||
from six import string_types
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
import openmc.checkvalue as cv
|
||||
|
||||
|
||||
class Trigger(object):
|
||||
|
|
@ -77,7 +76,7 @@ class Trigger(object):
|
|||
|
||||
@scores.setter
|
||||
def scores(self, scores):
|
||||
cv.check_type('trigger scores', scores, Iterable, basestring)
|
||||
cv.check_type('trigger scores', scores, Iterable, string_types)
|
||||
|
||||
# Set scores making sure not to have duplicates
|
||||
self._scores = []
|
||||
|
|
|
|||
|
|
@ -3,13 +3,12 @@ from numbers import Integral
|
|||
import random
|
||||
import sys
|
||||
|
||||
from six import string_types
|
||||
import numpy as np
|
||||
|
||||
import openmc
|
||||
import openmc.checkvalue as cv
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
# A dictionary for storing IDs of cell elements that have already been written,
|
||||
# used to optimize the writing process
|
||||
|
|
@ -118,7 +117,7 @@ class Universe(object):
|
|||
@name.setter
|
||||
def name(self, name):
|
||||
if name is not None:
|
||||
cv.check_type('universe name', name, basestring)
|
||||
cv.check_type('universe name', name, string_types)
|
||||
self._name = name
|
||||
else:
|
||||
self._name = ''
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ elif args.xsdata is not None:
|
|||
for line in xsdata:
|
||||
words = line.split()
|
||||
if len(words) >= 9:
|
||||
path = os.path.join(os.path.dirname(args.xsdata, words[8]))
|
||||
path = os.path.join(os.path.dirname(args.xsdata), words[8])
|
||||
if path not in ace_libraries:
|
||||
ace_libraries.append(path)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import print_function
|
||||
from argparse import ArgumentParser
|
||||
import argparse
|
||||
from collections import defaultdict
|
||||
import glob
|
||||
import os
|
||||
|
|
@ -9,8 +9,21 @@ import os
|
|||
import openmc.data
|
||||
|
||||
|
||||
# Get path to MCNP data
|
||||
parser = ArgumentParser()
|
||||
description = """
|
||||
Convert ENDF/B-VII.0 ACE data from the MCNP5/6 distribution into an HDF5 library
|
||||
that can be used by OpenMC. This assumes that you have a directory containing
|
||||
files named endf70a, endf70b, ..., endf70k, and endf70sab.
|
||||
|
||||
"""
|
||||
|
||||
class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter,
|
||||
argparse.RawDescriptionHelpFormatter):
|
||||
pass
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=description,
|
||||
formatter_class=CustomFormatter
|
||||
)
|
||||
parser.add_argument('-d', '--destination', default='mcnp_endfb70',
|
||||
help='Directory to create new library in')
|
||||
parser.add_argument('mcnpdata', help='Directory containing endf70[a-k] and endf70sab')
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import print_function
|
||||
from argparse import ArgumentParser
|
||||
import argparse
|
||||
from collections import defaultdict
|
||||
import glob
|
||||
import os
|
||||
|
|
@ -9,8 +9,21 @@ import os
|
|||
import openmc.data
|
||||
|
||||
|
||||
# Get path to MCNP data
|
||||
parser = ArgumentParser()
|
||||
description = """
|
||||
Convert ENDF/B-VII.1 ACE data from the MCNP6 distribution into an HDF5 library
|
||||
that can be used by OpenMC. This assumes that you have a directory containing
|
||||
subdirectories 'endf71x' and 'ENDF71SaB'.
|
||||
|
||||
"""
|
||||
|
||||
class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter,
|
||||
argparse.RawDescriptionHelpFormatter):
|
||||
pass
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=description,
|
||||
formatter_class=CustomFormatter
|
||||
)
|
||||
parser.add_argument('-d', '--destination', default='mcnp_endfb71',
|
||||
help='Directory to create new library in')
|
||||
parser.add_argument('-f', '--fission_energy_release',
|
||||
|
|
@ -10,18 +10,17 @@ import glob
|
|||
import argparse
|
||||
from string import digits
|
||||
|
||||
from six.moves import input
|
||||
from six.moves.urllib.request import urlopen
|
||||
|
||||
import openmc.data
|
||||
|
||||
try:
|
||||
from urllib.request import urlopen
|
||||
except ImportError:
|
||||
from urllib2 import urlopen
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
askuser = raw_input
|
||||
else:
|
||||
askuser = input
|
||||
description = """
|
||||
Download JEFF 3.2 ACE data from OECD/NEA and convert it to a multi-temperature
|
||||
HDF5 library for use with OpenMC.
|
||||
|
||||
"""
|
||||
|
||||
download_warning = """
|
||||
WARNING: This script will download approximately 9 GB of data. Extracting and
|
||||
|
|
@ -32,14 +31,21 @@ space. Note that if you don't need all 11 temperatures, you can modify the
|
|||
Are you sure you want to continue? ([y]/n)
|
||||
"""
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter,
|
||||
argparse.RawDescriptionHelpFormatter):
|
||||
pass
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=description,
|
||||
formatter_class=CustomFormatter
|
||||
)
|
||||
parser.add_argument('-b', '--batch', action='store_true',
|
||||
help='supresses standard in')
|
||||
parser.add_argument('-d', '--destination', default='jeff-3.2-hdf5',
|
||||
help='Directory to create new library in')
|
||||
args = parser.parse_args()
|
||||
|
||||
response = askuser(download_warning) if not args.batch else 'y'
|
||||
response = input(download_warning) if not args.batch else 'y'
|
||||
if response.lower().startswith('n'):
|
||||
sys.exit()
|
||||
|
||||
|
|
@ -82,7 +88,7 @@ for f in files:
|
|||
files_complete.append(f)
|
||||
continue
|
||||
else:
|
||||
overwrite = askuser('Overwrite {}? ([y]/n) '.format(f))
|
||||
overwrite = input('Overwrite {}? ([y]/n) '.format(f))
|
||||
if overwrite.lower().startswith('n'):
|
||||
continue
|
||||
|
||||
|
|
@ -10,18 +10,27 @@ import glob
|
|||
import hashlib
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
from six.moves import input
|
||||
from six.moves.urllib.request import urlopen
|
||||
|
||||
|
||||
description = """
|
||||
Download and extract windowed multipole data based on ENDF/B-VII.1.
|
||||
|
||||
"""
|
||||
|
||||
class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter,
|
||||
argparse.RawDescriptionHelpFormatter):
|
||||
pass
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=description,
|
||||
formatter_class=CustomFormatter
|
||||
)
|
||||
parser.add_argument('-b', '--batch', action='store_true',
|
||||
help='supresses standard in')
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
from urllib.request import urlopen
|
||||
except ImportError:
|
||||
from urllib2 import urlopen
|
||||
|
||||
cwd = os.getcwd()
|
||||
sys.path.insert(0, os.path.join(cwd, '..'))
|
||||
|
||||
baseUrl = 'https://github.com/smharper/windowed_multipole_library/blob/master/'
|
||||
files = ['multipole_lib.tar.gz?raw=true']
|
||||
|
|
@ -54,10 +63,7 @@ for f in files:
|
|||
filesComplete.append(fname)
|
||||
continue
|
||||
else:
|
||||
if sys.version_info[0] < 3:
|
||||
overwrite = raw_input('Overwrite {0}? ([y]/n) '.format(fname))
|
||||
else:
|
||||
overwrite = input('Overwrite {0}? ([y]/n) '.format(fname))
|
||||
overwrite = input('Overwrite {0}? ([y]/n) '.format(fname))
|
||||
if overwrite.lower().startswith('n'):
|
||||
continue
|
||||
|
||||
|
|
@ -110,10 +116,7 @@ os.rmdir('wmp/multipole_lib')
|
|||
|
||||
# Ask user to delete
|
||||
if not args.batch:
|
||||
if sys.version_info[0] < 3:
|
||||
response = raw_input('Delete *.tar.gz files? ([y]/n) ')
|
||||
else:
|
||||
response = input('Delete *.tar.gz files? ([y]/n) ')
|
||||
response = input('Delete *.tar.gz files? ([y]/n) ')
|
||||
else:
|
||||
response = 'y'
|
||||
|
||||
|
|
@ -10,15 +10,31 @@ import glob
|
|||
import hashlib
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
from six.moves import input
|
||||
from six.moves.urllib.request import urlopen
|
||||
|
||||
import openmc.data
|
||||
|
||||
|
||||
description = """
|
||||
Download ENDF/B-VII.1 ACE data from NNDC and convert it to an HDF5 library for
|
||||
use with OpenMC.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter,
|
||||
argparse.RawDescriptionHelpFormatter):
|
||||
pass
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=description,
|
||||
formatter_class=CustomFormatter
|
||||
)
|
||||
parser.add_argument('-b', '--batch', action='store_true',
|
||||
help='supresses standard in')
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
from urllib.request import urlopen
|
||||
except ImportError:
|
||||
from urllib2 import urlopen
|
||||
|
||||
baseUrl = 'http://www.nndc.bnl.gov/endf/b7.1/aceFiles/'
|
||||
files = ['ENDF-B-VII.1-neutron-293.6K.tar.gz',
|
||||
|
|
@ -50,10 +66,7 @@ for f in files:
|
|||
filesComplete.append(f)
|
||||
continue
|
||||
else:
|
||||
if sys.version_info[0] < 3:
|
||||
overwrite = raw_input('Overwrite {0}? ([y]/n) '.format(f))
|
||||
else:
|
||||
overwrite = input('Overwrite {0}? ([y]/n) '.format(f))
|
||||
overwrite = input('Overwrite {0}? ([y]/n) '.format(f))
|
||||
if overwrite.lower().startswith('n'):
|
||||
continue
|
||||
|
||||
|
|
@ -65,7 +78,8 @@ for f in files:
|
|||
if not chunk: break
|
||||
fh.write(chunk)
|
||||
downloaded += len(chunk)
|
||||
status = '{0:10} [{1:3.2f}%]'.format(downloaded, downloaded * 100. / file_size)
|
||||
status = '{0:10} [{1:3.2f}%]'.format(
|
||||
downloaded, downloaded * 100. / file_size)
|
||||
print(status + chr(8)*len(status), end='')
|
||||
print('')
|
||||
filesComplete.append(f)
|
||||
|
|
@ -99,7 +113,7 @@ for f in files:
|
|||
for filename in glob.glob('nndc/293.6K/ENDF-B-VII.1-neutron-293.6K/*'):
|
||||
shutil.move(filename, 'nndc/293.6K/')
|
||||
|
||||
#===============================================================================
|
||||
# ==============================================================================
|
||||
# EDIT GRAPHITE ZAID (6012 to 6000)
|
||||
|
||||
print('Changing graphite ZAID from 6012 to 6000')
|
||||
|
|
@ -115,10 +129,7 @@ with open(graphite, 'w') as fh:
|
|||
|
||||
# Ask user to delete
|
||||
if not args.batch:
|
||||
if sys.version_info[0] < 3:
|
||||
response = raw_input('Delete *.tar.gz files? ([y]/n) ')
|
||||
else:
|
||||
response = input('Delete *.tar.gz files? ([y]/n) ')
|
||||
response = input('Delete *.tar.gz files? ([y]/n) ')
|
||||
else:
|
||||
response = 'y'
|
||||
|
||||
|
|
@ -130,27 +141,16 @@ if not response or response.lower().startswith('y'):
|
|||
os.remove(f)
|
||||
|
||||
# ==============================================================================
|
||||
# PROMPT USER TO GENERATE HDF5 LIBRARY
|
||||
# GENERATE HDF5 LIBRARY
|
||||
|
||||
# Ask user to convert
|
||||
if not args.batch:
|
||||
if sys.version_info[0] < 3:
|
||||
response = raw_input('Generate HDF5 library? ([y]/n) ')
|
||||
else:
|
||||
response = input('Generate HDF5 library? ([y]/n) ')
|
||||
else:
|
||||
response = 'y'
|
||||
# get a list of all ACE files
|
||||
ace_files = sorted(glob.glob(os.path.join('nndc', '**', '*.ace*')))
|
||||
|
||||
# Convert files if requested
|
||||
if not response or response.lower().startswith('y'):
|
||||
# get a list of all ACE files
|
||||
ace_files = sorted(glob.glob(os.path.join('nndc', '**', '*.ace*')))
|
||||
# Get path to fission energy release data
|
||||
data_dir = os.path.dirname(sys.modules['openmc.data'].__file__)
|
||||
fer_file = os.path.join(data_dir, 'fission_Q_data_endfb71.h5')
|
||||
|
||||
# Ensure 'import openmc.data' works in the openmc-ace-to-xml script
|
||||
cwd = os.getcwd()
|
||||
env = os.environ.copy()
|
||||
env['PYTHONPATH'] = os.path.join(cwd, '..')
|
||||
|
||||
subprocess.call(['../scripts/openmc-ace-to-hdf5', '-d', 'nndc_hdf5',
|
||||
'--fission_energy_release', 'fission_Q_data_endfb71.h5']
|
||||
+ ace_files, env=env)
|
||||
pwd = os.path.dirname(os.path.realpath(__file__))
|
||||
ace2hdf5 = os.path.join(pwd, 'openmc-ace-to-hdf5')
|
||||
subprocess.call([ace2hdf5, '-d', 'nndc_hdf5', '--fission_energy_release',
|
||||
fer_file] + ace_files)
|
||||
|
|
@ -5,6 +5,11 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
import six.moves.tkinter as tk
|
||||
import six.moves.tkinter_filedialog as filedialog
|
||||
import six.moves.tkinter_font as font
|
||||
import six.moves.tkinter_messagebox as messagebox
|
||||
import six.moves.tkinter_ttk as ttk
|
||||
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
||||
from matplotlib.backends.backend_tkagg import NavigationToolbar2TkAgg
|
||||
from matplotlib.figure import Figure
|
||||
|
|
@ -13,19 +18,6 @@ import numpy as np
|
|||
|
||||
from openmc.statepoint import StatePoint
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
import Tkinter as tk
|
||||
import tkFileDialog as filedialog
|
||||
import tkFont as font
|
||||
import tkMessageBox as messagebox
|
||||
import ttk as ttk
|
||||
else:
|
||||
import tkinter as tk
|
||||
import tkinter.filedialog as filedialog
|
||||
import tkinter.font as font
|
||||
import tkinter.messagebox as messagebox
|
||||
import tkinter.ttk as ttk
|
||||
|
||||
|
||||
class MeshPlotter(tk.Frame):
|
||||
def __init__(self, parent, filename):
|
||||
|
|
|
|||
229
scripts/openmc-update-mgxs
Executable file
229
scripts/openmc-update-mgxs
Executable file
|
|
@ -0,0 +1,229 @@
|
|||
#!/usr/bin/env python
|
||||
"""Update OpenMC's deprecated multi-group cross section XML files to the latest
|
||||
HDF5-based format.
|
||||
|
||||
Usage information can be obtained by running 'openmc-update-mgxs --help':
|
||||
|
||||
usage: openmc-update-mgxs [-h] in out
|
||||
|
||||
Update mgxs.xml files to the latest format. This will remove 'outside'
|
||||
attributes/elements from lattices and replace them with 'outer' attributes. For
|
||||
'cell' elements, any 'surfaces' attributes/elements will be renamed
|
||||
'region'. Note that this script will not delete the given files; it will append
|
||||
'.original' to the given files and write new ones.
|
||||
|
||||
positional arguments:
|
||||
in Input mgxs xml file
|
||||
out Output mgxs hdf5 file
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import os
|
||||
from shutil import move
|
||||
import warnings
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import argparse
|
||||
import h5py
|
||||
import numpy as np
|
||||
|
||||
import openmc.mgxs_library
|
||||
|
||||
description = """\
|
||||
Update OpenMC's deprecated multi-group cross section XML files to the latest
|
||||
HDF5-based format."""
|
||||
|
||||
|
||||
def parse_args():
|
||||
"""Read the input files from the commandline."""
|
||||
# Create argument parser
|
||||
parser = argparse.ArgumentParser(description=description,
|
||||
formatter_class=argparse.RawTextHelpFormatter)
|
||||
parser.add_argument('-i', '--input', type=argparse.FileType('r'),
|
||||
help='input XML file')
|
||||
parser.add_argument('-o', '--output', nargs='?', default='',
|
||||
help='output file, in HDF5 format')
|
||||
args = vars(parser.parse_args())
|
||||
|
||||
if args['output'] == '':
|
||||
filename = args['input'].name
|
||||
extension = filenameos.path.splitext()
|
||||
if extension == '.xml':
|
||||
filename = filename[:filename.rfind('.')] + '.h5'
|
||||
args['output'] = filename
|
||||
|
||||
# Parse and return commandline arguments.
|
||||
return args
|
||||
|
||||
|
||||
def get_data(element, entry):
|
||||
value = element.find(entry)
|
||||
if value is not None:
|
||||
value = value.text.strip()
|
||||
else:
|
||||
if entry in element.attrib:
|
||||
value = element.attrib[entry].strip()
|
||||
else:
|
||||
value = None
|
||||
|
||||
return value
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = parse_args()
|
||||
|
||||
# Parse the XML data.
|
||||
tree = ET.parse(args['input'])
|
||||
root = tree.getroot()
|
||||
|
||||
# Get old metadata
|
||||
temp = tree.find('group_structure').text.strip()
|
||||
temp = np.array(temp.split())
|
||||
group_structure = temp.astype(np.float)
|
||||
energy_groups = openmc.mgxs.EnergyGroups(group_structure)
|
||||
temp = tree.find('inverse_velocities')
|
||||
if temp is not None:
|
||||
temp = temp.text.strip()
|
||||
temp = np.array(temp.split())
|
||||
inverse_velocities = temp.astype(np.float)
|
||||
else:
|
||||
inverse_velocities = None
|
||||
|
||||
xsd = []
|
||||
names = []
|
||||
|
||||
# Now move on to the cross section data itself
|
||||
for xsdata_elem in root.iter('xsdata'):
|
||||
name = get_data(xsdata_elem, 'name')
|
||||
|
||||
temperature = get_data(xsdata_elem, 'kT')
|
||||
if temperature is not None:
|
||||
temperature = \
|
||||
float(temperature) / openmc.data.K_BOLTZMANN
|
||||
else:
|
||||
temperature = 294.
|
||||
temperatures = [temperature]
|
||||
|
||||
awr = get_data(xsdata_elem, 'awr')
|
||||
if awr is not None:
|
||||
awr = float(awr)
|
||||
|
||||
representation = get_data(xsdata_elem, 'representation')
|
||||
if representation is None:
|
||||
representation = 'isotropic'
|
||||
if representation == 'angle':
|
||||
n_azi = int(get_data(xsdata_elem, 'num_azimuthal'))
|
||||
n_pol = int(get_data(xsdata_elem, 'num_polar'))
|
||||
|
||||
scatter_format = get_data(xsdata_elem, 'scatt_type')
|
||||
if scatter_format is None:
|
||||
scatter_format = 'legendre'
|
||||
|
||||
order = int(get_data(xsdata_elem, 'order'))
|
||||
|
||||
tab_leg = get_data(xsdata_elem, 'tabular_legendre')
|
||||
if tab_leg is not None:
|
||||
warnings.Warning('The tabular_legendre option has moved to the '
|
||||
'settings.xml file and must be added manually')
|
||||
|
||||
# Either add the data to a previously existing xsdata (if it is
|
||||
# for the same 'name' but a different temperature), or create a
|
||||
# new one.
|
||||
try:
|
||||
# It is in our list, so store that entry
|
||||
i = names.index(name)
|
||||
except ValueError:
|
||||
# It is not in our list, so add it
|
||||
i = -1
|
||||
xsd.append(openmc.XSdata(name, energy_groups,
|
||||
temperatures=temperatures,
|
||||
representation=representation))
|
||||
if awr is not None:
|
||||
xsd[-1].atomic_weight_ratio = awr
|
||||
if representation == 'angle':
|
||||
xsd[-1].num_azimuthal = n_azi
|
||||
xsd[-1].num_polar = n_pol
|
||||
xsd[-1].scatter_format = scatter_format
|
||||
xsd[-1].order = order
|
||||
names.append(name)
|
||||
|
||||
if scatter_format == 'legendre':
|
||||
order_dim = order + 1
|
||||
else:
|
||||
order_dim = order
|
||||
|
||||
if i != -1:
|
||||
xsd[i].add_temperature(temperature)
|
||||
|
||||
temp = get_data(xsdata_elem, 'total')
|
||||
if temp is not None:
|
||||
temp = np.array(temp.split(), dtype=float)
|
||||
total = temp.astype(np.float)
|
||||
total.shape = xsd[i].vector_shape
|
||||
xsd[i].set_total(total, temperature)
|
||||
|
||||
if inverse_velocities is not None:
|
||||
xsd[i].set_inverse_velocities(inverse_velocities, temperature)
|
||||
|
||||
temp = get_data(xsdata_elem, 'absorption')
|
||||
temp = np.array(temp.split())
|
||||
absorption = temp.astype(np.float)
|
||||
absorption.shape = xsd[i].vector_shape
|
||||
xsd[i].set_absorption(absorption, temperature)
|
||||
|
||||
temp = get_data(xsdata_elem, 'scatter')
|
||||
temp = np.array(temp.split())
|
||||
scatter = temp.astype(np.float)
|
||||
scatter.shape = xsd[i].pn_matrix_shape
|
||||
xsd[i].set_scatter_matrix(scatter, temperature)
|
||||
|
||||
temp = get_data(xsdata_elem, 'multiplicity')
|
||||
if temp is not None:
|
||||
temp = np.array(temp.split())
|
||||
multiplicity = temp.astype(np.float)
|
||||
multiplicity.shape = xsd[i].matrix_shape
|
||||
xsd[i].set_multiplicity_matrix(multiplicity, temperature)
|
||||
|
||||
temp = get_data(xsdata_elem, 'fission')
|
||||
if temp is not None:
|
||||
temp = np.array(temp.split())
|
||||
fission = temp.astype(np.float)
|
||||
fission.shape = xsd[i].vector_shape
|
||||
xsd[i].set_fission(fission, temperature)
|
||||
|
||||
temp = get_data(xsdata_elem, 'kappa_fission')
|
||||
if temp is not None:
|
||||
temp = np.array(temp.split())
|
||||
kappa_fission = temp.astype(np.float)
|
||||
kappa_fission.shape = xsd[i].vector_shape
|
||||
xsd[i].set_kappa_fission(kappa_fission, temperature)
|
||||
|
||||
temp = get_data(xsdata_elem, 'chi')
|
||||
if temp is not None:
|
||||
temp = np.array(temp.split())
|
||||
chi = temp.astype(np.float)
|
||||
chi.shape = xsd[i].vector_shape
|
||||
xsd[i].set_chi(chi, temperature)
|
||||
else:
|
||||
chi = None
|
||||
|
||||
temp = get_data(xsdata_elem, 'nu_fission')
|
||||
if temp is not None:
|
||||
temp = np.array(temp.split())
|
||||
nu_fission = temp.astype(np.float)
|
||||
if chi is not None:
|
||||
nu_fission.shape = xsd[i].vector_shape
|
||||
else:
|
||||
nu_fission.shape = xsd[i].matrix_shape
|
||||
xsd[i].set_nu_fission(nu_fission, temperature)
|
||||
|
||||
# Build library as we go, but first we have enough to initialize it
|
||||
lib = openmc.MGXSLibrary(energy_groups)
|
||||
|
||||
lib.add_xsdatas(xsd)
|
||||
|
||||
lib.export_to_hdf5(args['output'])
|
||||
18
setup.py
Normal file → Executable file
18
setup.py
Normal file → Executable file
|
|
@ -1,6 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import glob
|
||||
import numpy as np
|
||||
try:
|
||||
from setuptools import setup
|
||||
have_setuptools = True
|
||||
|
|
@ -8,6 +9,12 @@ except ImportError:
|
|||
from distutils.core import setup
|
||||
have_setuptools = False
|
||||
|
||||
try:
|
||||
from Cython.Build import cythonize
|
||||
have_cython = True
|
||||
except ImportError:
|
||||
have_cython = False
|
||||
|
||||
kwargs = {'name': 'openmc',
|
||||
'version': '0.8.0',
|
||||
'packages': ['openmc', 'openmc.data', 'openmc.mgxs', 'openmc.model',
|
||||
|
|
@ -32,7 +39,7 @@ kwargs = {'name': 'openmc',
|
|||
if have_setuptools:
|
||||
kwargs.update({
|
||||
# Required dependencies
|
||||
'install_requires': ['numpy>=1.9', 'h5py', 'matplotlib'],
|
||||
'install_requires': ['six', 'numpy>=1.9', 'h5py', 'matplotlib'],
|
||||
|
||||
# Optional dependencies
|
||||
'extras_require': {
|
||||
|
|
@ -44,8 +51,15 @@ if have_setuptools:
|
|||
|
||||
# Data files
|
||||
'package_data': {
|
||||
'openmc.data': ['mass.mas12']
|
||||
'openmc.data': ['mass.mas12', 'fission_Q_data_endfb71.h5']
|
||||
},
|
||||
})
|
||||
|
||||
# If Cython is present, add resonance reconstruction capability
|
||||
if have_cython:
|
||||
kwargs.update({
|
||||
'ext_modules': cythonize('openmc/data/reconstruct.pyx'),
|
||||
'include_dirs': [np.get_include()]
|
||||
})
|
||||
|
||||
setup(**kwargs)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
module geometry_header
|
||||
|
||||
use constants, only: HALF, TWO, THREE, INFINITY
|
||||
use algorithm, only: find
|
||||
use constants, only: HALF, TWO, THREE, INFINITY, K_BOLTZMANN, &
|
||||
MATERIAL_VOID, NONE
|
||||
use dict_header, only: DictCharInt, DictIntInt
|
||||
use material_header, only: Material
|
||||
use stl_vector, only: VectorReal
|
||||
use string, only: to_lower
|
||||
|
||||
implicit none
|
||||
|
||||
|
|
@ -319,4 +325,74 @@ contains
|
|||
end if
|
||||
end function get_local_hex
|
||||
|
||||
!===============================================================================
|
||||
! GET_TEMPERATURES returns a list of temperatures that each nuclide/S(a,b) table
|
||||
! appears at in the model. Later, this list is used to determine the actual
|
||||
! temperatures to read (which may be different if interpolation is used)
|
||||
!===============================================================================
|
||||
|
||||
subroutine get_temperatures(cells, materials, material_dict, nuclide_dict, &
|
||||
n_nucs, nuc_temps, sab_dict, n_sabs, sab_temps)
|
||||
type(Cell), allocatable, intent(in) :: cells(:)
|
||||
type(Material), allocatable, intent(in) :: materials(:)
|
||||
type(DictIntInt), intent(in) :: material_dict
|
||||
type(DictCharInt), intent(in) :: nuclide_dict
|
||||
integer, intent(in) :: n_nucs
|
||||
type(VectorReal), allocatable, intent(out) :: nuc_temps(:)
|
||||
type(DictCharInt), optional, intent(in) :: sab_dict
|
||||
integer, optional, intent(in) :: n_sabs
|
||||
type(VectorReal), optional, allocatable, intent(out) :: sab_temps(:)
|
||||
|
||||
integer :: i, j, k
|
||||
integer :: i_nuclide ! index in nuclides array
|
||||
integer :: i_sab ! index in S(a,b) array
|
||||
integer :: i_material
|
||||
real(8) :: temperature ! temperature in Kelvin
|
||||
|
||||
allocate(nuc_temps(n_nucs))
|
||||
if (present(n_sabs) .and. present(sab_temps)) allocate(sab_temps(n_sabs))
|
||||
|
||||
do i = 1, size(cells)
|
||||
do j = 1, size(cells(i) % material)
|
||||
! Skip any non-material cells and void materials
|
||||
if (cells(i) % material(j) == NONE .or. &
|
||||
cells(i) % material(j) == MATERIAL_VOID) cycle
|
||||
|
||||
! Get temperature of cell (rounding to nearest integer)
|
||||
if (size(cells(i) % sqrtkT) > 1) then
|
||||
temperature = cells(i) % sqrtkT(j)**2 / K_BOLTZMANN
|
||||
else
|
||||
temperature = cells(i) % sqrtkT(1)**2 / K_BOLTZMANN
|
||||
end if
|
||||
|
||||
i_material = material_dict % get_key(cells(i) % material(j))
|
||||
associate (mat => materials(i_material))
|
||||
NUC_NAMES_LOOP: do k = 1, size(mat % names)
|
||||
! Get index in nuc_temps array
|
||||
i_nuclide = nuclide_dict % get_key(to_lower(mat % names(k)))
|
||||
|
||||
! Add temperature if it hasn't already been added
|
||||
if (find(nuc_temps(i_nuclide), temperature) == -1) then
|
||||
call nuc_temps(i_nuclide) % push_back(temperature)
|
||||
end if
|
||||
end do NUC_NAMES_LOOP
|
||||
|
||||
if (present(sab_temps) .and. present(sab_dict) .and. &
|
||||
mat % n_sab > 0) then
|
||||
SAB_NAMES_LOOP: do k = 1, size(mat % sab_names)
|
||||
! Get index in nuc_temps array
|
||||
i_sab = sab_dict % get_key(to_lower(mat % sab_names(k)))
|
||||
|
||||
! Add temperature if it hasn't already been added
|
||||
if (find(sab_temps(i_sab), temperature) == -1) then
|
||||
call sab_temps(i_sab) % push_back(temperature)
|
||||
end if
|
||||
end do SAB_NAMES_LOOP
|
||||
end if
|
||||
end associate
|
||||
end do
|
||||
end do
|
||||
|
||||
end subroutine get_temperatures
|
||||
|
||||
end module geometry_header
|
||||
|
|
|
|||
|
|
@ -123,12 +123,15 @@ module global
|
|||
! Midpoint of the energy group structure
|
||||
real(8), allocatable :: energy_bin_avg(:)
|
||||
|
||||
! Inverse velocities of the energy groups (provided or estimated)
|
||||
real(8), allocatable :: inverse_velocities(:)
|
||||
|
||||
! Maximum Data Order
|
||||
integer :: max_order
|
||||
|
||||
! Whether or not to convert Legendres to tabulars
|
||||
logical :: legendre_to_tabular = .True.
|
||||
|
||||
! Number of points to use in the Legendre to tabular conversion
|
||||
integer :: legendre_to_tabular_points = 33
|
||||
|
||||
! ============================================================================
|
||||
! TALLY-RELATED VARIABLES
|
||||
|
||||
|
|
@ -307,6 +310,7 @@ module global
|
|||
|
||||
logical :: survival_biasing = .false.
|
||||
real(8) :: weight_cutoff = 0.25_8
|
||||
real(8) :: energy_cutoff = ZERO
|
||||
real(8) :: weight_survive = ONE
|
||||
|
||||
! ============================================================================
|
||||
|
|
@ -355,6 +359,9 @@ module global
|
|||
! Write out initial source
|
||||
logical :: write_initial_source = .false.
|
||||
|
||||
! Whether create fission neutrons or not. Only applied for MODE_FIXEDSOURCE
|
||||
logical :: create_fission_neutrons = .true.
|
||||
|
||||
! ============================================================================
|
||||
! CMFD VARIABLES
|
||||
|
||||
|
|
@ -472,12 +479,7 @@ contains
|
|||
do i = 1, size(nuclides)
|
||||
call nuclides(i) % clear()
|
||||
end do
|
||||
|
||||
! WARNING: The following statement should work but doesn't under gfortran
|
||||
! 4.6 because of a bug. Technically, commenting this out leaves a memory
|
||||
! leak.
|
||||
|
||||
! deallocate(nuclides)
|
||||
deallocate(nuclides)
|
||||
end if
|
||||
|
||||
if (allocated(nuclides_0K)) then
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ module hdf5_interface
|
|||
module procedure read_attribute_integer_2D
|
||||
module procedure read_attribute_string
|
||||
module procedure read_attribute_string_1D
|
||||
module procedure read_attribute_logical
|
||||
end interface read_attribute
|
||||
|
||||
interface write_attribute
|
||||
|
|
@ -84,12 +85,14 @@ module hdf5_interface
|
|||
|
||||
public :: write_dataset
|
||||
public :: read_dataset
|
||||
public :: attribute_exists
|
||||
public :: write_attribute
|
||||
public :: read_attribute
|
||||
public :: file_create
|
||||
public :: file_open
|
||||
public :: file_close
|
||||
public :: create_group
|
||||
public :: object_exists
|
||||
public :: open_group
|
||||
public :: close_group
|
||||
public :: open_dataset
|
||||
|
|
@ -98,6 +101,7 @@ module hdf5_interface
|
|||
public :: write_attribute_string
|
||||
public :: get_groups
|
||||
public :: get_datasets
|
||||
public :: get_name
|
||||
|
||||
contains
|
||||
|
||||
|
|
@ -213,12 +217,11 @@ contains
|
|||
|
||||
subroutine get_groups(object_id, names)
|
||||
integer(HID_T), intent(in) :: object_id
|
||||
character(len=255), allocatable, intent(out) :: names(:)
|
||||
character(len=150), allocatable, intent(out) :: names(:)
|
||||
|
||||
integer :: n_members, i, group_count, type
|
||||
integer :: hdf5_err
|
||||
character(len=255) :: name
|
||||
|
||||
character(len=150) :: name
|
||||
|
||||
! Get number of members in this location
|
||||
call h5gn_members_f(object_id, './', n_members, hdf5_err)
|
||||
|
|
@ -245,17 +248,49 @@ contains
|
|||
|
||||
end subroutine get_groups
|
||||
|
||||
!===============================================================================
|
||||
! CHECK_ATTRIBUTE Checks to see if an attribute exists in the object
|
||||
!===============================================================================
|
||||
|
||||
function attribute_exists(object_id, name) result(exists)
|
||||
integer(HID_T), intent(in) :: object_id
|
||||
character(*), intent(in) :: name ! name of group
|
||||
logical :: exists
|
||||
|
||||
integer :: hdf5_err ! HDF5 error code
|
||||
|
||||
! Check if attribute exists
|
||||
call h5aexists_by_name_f(object_id, '.', trim(name), exists, hdf5_err)
|
||||
|
||||
end function attribute_exists
|
||||
|
||||
!===============================================================================
|
||||
! CHECK_GROUP Checks to see if a group exists in the object
|
||||
!===============================================================================
|
||||
|
||||
function object_exists(object_id, name) result(exists)
|
||||
integer(HID_T), intent(in) :: object_id
|
||||
character(*), intent(in) :: name ! name of group
|
||||
logical :: exists
|
||||
|
||||
integer :: hdf5_err ! HDF5 error code
|
||||
|
||||
! Check if group exists
|
||||
call h5ltpath_valid_f(object_id, trim(name), .true., exists, hdf5_err)
|
||||
|
||||
end function object_exists
|
||||
|
||||
!===============================================================================
|
||||
! GET_DATASETS Gets a list of all the datasets in a given location.
|
||||
!===============================================================================
|
||||
|
||||
subroutine get_datasets(object_id, names)
|
||||
integer(HID_T), intent(in) :: object_id
|
||||
character(len=255), allocatable, intent(out) :: names(:)
|
||||
character(len=150), allocatable, intent(out) :: names(:)
|
||||
|
||||
integer :: n_members, i, dset_count, type
|
||||
integer :: hdf5_err
|
||||
character(len=255) :: name
|
||||
character(len=150) :: name
|
||||
|
||||
|
||||
! Get number of members in this location
|
||||
|
|
@ -283,6 +318,27 @@ contains
|
|||
|
||||
end subroutine get_datasets
|
||||
|
||||
!===============================================================================
|
||||
! GET_NAME Obtains the name of the current group in group_id
|
||||
!===============================================================================
|
||||
|
||||
function get_name(group_id, name_len_) result(name)
|
||||
integer(HID_T), intent(in) :: group_id
|
||||
integer(SIZE_T), optional, intent(in) :: name_len_
|
||||
|
||||
character(len=150) :: name ! name of group
|
||||
integer(SIZE_T) :: name_len, name_file_len
|
||||
integer :: hdf5_err ! HDF5 error code
|
||||
|
||||
if (present(name_len_)) then
|
||||
name_len = name_len_
|
||||
else
|
||||
name_len = 150
|
||||
end if
|
||||
|
||||
call h5iget_name_f(group_id, name, name_len, name_file_len, hdf5_err)
|
||||
end function get_name
|
||||
|
||||
!===============================================================================
|
||||
! OPEN_GROUP opens an existing HDF5 group
|
||||
!===============================================================================
|
||||
|
|
@ -296,7 +352,7 @@ contains
|
|||
integer :: hdf5_err ! HDF5 error code
|
||||
|
||||
! Check if group exists
|
||||
call h5ltpath_valid_f(group_id, trim(name), .true., exists, hdf5_err)
|
||||
exists = object_exists(group_id, name)
|
||||
|
||||
! open group if it exists
|
||||
if (exists) then
|
||||
|
|
@ -319,7 +375,7 @@ contains
|
|||
logical :: exists ! does the group exist
|
||||
|
||||
! Check if group exists
|
||||
call h5ltpath_valid_f(group_id, trim(name), .true., exists, hdf5_err)
|
||||
exists = object_exists(group_id, name)
|
||||
|
||||
! create group
|
||||
if (exists) then
|
||||
|
|
@ -357,7 +413,7 @@ contains
|
|||
integer :: hdf5_err ! HDF5 error code
|
||||
|
||||
! Check if group exists
|
||||
call h5ltpath_valid_f(group_id, trim(name), .true., exists, hdf5_err)
|
||||
exists = object_exists(group_id, name)
|
||||
|
||||
! open group if it exists
|
||||
if (exists) then
|
||||
|
|
@ -2486,6 +2542,29 @@ contains
|
|||
call h5tclose_f(memtype, hdf5_err)
|
||||
end subroutine read_attribute_string_1D_explicit
|
||||
|
||||
subroutine read_attribute_logical(buffer, obj_id, name)
|
||||
logical, intent(inout), target :: buffer
|
||||
integer(HID_T), intent(in) :: obj_id
|
||||
character(*), intent(in) :: name
|
||||
|
||||
integer, target :: int_buffer
|
||||
integer :: hdf5_err
|
||||
integer(HID_T) :: attr_id
|
||||
type(c_ptr) :: f_ptr
|
||||
|
||||
call h5aopen_f(obj_id, trim(name), attr_id, hdf5_err)
|
||||
f_ptr = c_loc(int_buffer)
|
||||
call h5aread_f(attr_id, H5T_NATIVE_INTEGER, f_ptr, hdf5_err)
|
||||
call h5aclose_f(attr_id, hdf5_err)
|
||||
|
||||
! Convert to Fortran logical
|
||||
if (int_buffer == 0) then
|
||||
buffer = .false.
|
||||
else
|
||||
buffer = .true.
|
||||
end if
|
||||
end subroutine read_attribute_logical
|
||||
|
||||
subroutine get_shape(obj_id, dims)
|
||||
integer(HID_T), intent(in) :: obj_id
|
||||
integer(HSIZE_T), intent(out) :: dims(:)
|
||||
|
|
|
|||
|
|
@ -113,12 +113,6 @@ contains
|
|||
if (run_CE) then
|
||||
! Construct log energy grid for cross-sections
|
||||
call logarithmic_grid()
|
||||
else
|
||||
! Create material macroscopic data for MGXS
|
||||
call time_read_xs%start()
|
||||
call read_mgxs()
|
||||
call create_macro_xs()
|
||||
call time_read_xs%stop()
|
||||
end if
|
||||
|
||||
! Allocate and setup tally stride, matching_bins, and tally maps
|
||||
|
|
|
|||
|
|
@ -1,21 +1,20 @@
|
|||
module input_xml
|
||||
|
||||
use hdf5
|
||||
|
||||
use algorithm, only: find
|
||||
use cmfd_input, only: configure_cmfd
|
||||
use constants
|
||||
use dict_header, only: DictIntInt, ElemKeyValueCI
|
||||
use dict_header, only: DictIntInt, DictCharInt, 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
|
||||
use geometry_header, only: Cell, Lattice, RectLattice, HexLattice, &
|
||||
get_temperatures
|
||||
use global
|
||||
use hdf5_interface
|
||||
use list_header, only: ListChar, ListInt, ListReal
|
||||
use mesh_header, only: RegularMesh
|
||||
use mgxs_data, only: create_macro_xs, read_mgxs
|
||||
use multipole, only: multipole_read
|
||||
use output, only: write_message
|
||||
use plot_header
|
||||
|
|
@ -52,6 +51,17 @@ contains
|
|||
call read_tallies_xml()
|
||||
if (cmfd_run) call configure_cmfd()
|
||||
|
||||
if (.not. run_CE) then
|
||||
! Create material macroscopic data for MGXS
|
||||
call time_read_xs % start()
|
||||
call read_mgxs()
|
||||
call create_macro_xs()
|
||||
call time_read_xs % stop()
|
||||
end if
|
||||
|
||||
! Normalize atom/weight percents
|
||||
if (run_mode /= MODE_PLOTTING) call normalize_ao()
|
||||
|
||||
end subroutine read_input_xml
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -91,6 +101,7 @@ contains
|
|||
type(Node), pointer :: node_trigger => null()
|
||||
type(Node), pointer :: node_keff_trigger => null()
|
||||
type(Node), pointer :: node_vol => null()
|
||||
type(Node), pointer :: node_tab_leg => null()
|
||||
type(NodeList), pointer :: node_scat_list => null()
|
||||
type(NodeList), pointer :: node_source_list => null()
|
||||
type(NodeList), pointer :: node_vol_list => null()
|
||||
|
|
@ -659,8 +670,15 @@ contains
|
|||
! Cutoffs
|
||||
if (check_for_node(doc, "cutoff")) then
|
||||
call get_node_ptr(doc, "cutoff", node_cutoff)
|
||||
call get_node_value(node_cutoff, "weight", weight_cutoff)
|
||||
call get_node_value(node_cutoff, "weight_avg", weight_survive)
|
||||
if (check_for_node(node_cutoff, "weight")) then
|
||||
call get_node_value(node_cutoff, "weight", weight_cutoff)
|
||||
end if
|
||||
if (check_for_node(node_cutoff, "weight_avg")) then
|
||||
call get_node_value(node_cutoff, "weight_avg", weight_survive)
|
||||
end if
|
||||
if (check_for_node(node_cutoff, "energy")) then
|
||||
call get_node_value(node_cutoff, "energy", energy_cutoff)
|
||||
end if
|
||||
end if
|
||||
|
||||
! Particle trace
|
||||
|
|
@ -1102,6 +1120,44 @@ contains
|
|||
end select
|
||||
end if
|
||||
|
||||
! Check whether create fission sites
|
||||
if (run_mode == MODE_FIXEDSOURCE) then
|
||||
if (check_for_node(doc, "create_fission_neutrons")) then
|
||||
call get_node_value(doc, "create_fission_neutrons", temp_str)
|
||||
temp_str = to_lower(temp_str)
|
||||
if (trim(temp_str) == 'true' .or. trim(temp_str) == '1') then
|
||||
create_fission_neutrons = .true.
|
||||
else if (trim(temp_str) == 'false' .or. trim(temp_str) == '0') then
|
||||
create_fission_neutrons = .false.
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check for tabular_legendre options
|
||||
if (check_for_node(doc, "tabular_legendre")) then
|
||||
|
||||
! Get pointer to tabular_legendre node
|
||||
call get_node_ptr(doc, "tabular_legendre", node_tab_leg)
|
||||
|
||||
! Check for enable option
|
||||
if (check_for_node(node_tab_leg, "enable")) then
|
||||
call get_node_value(node_tab_leg, "enable", temp_str)
|
||||
temp_str = to_lower(temp_str)
|
||||
if (trim(temp_str) == 'false' .or. &
|
||||
trim(temp_str) == '0') legendre_to_tabular = .false.
|
||||
end if
|
||||
|
||||
! Check for the number of points
|
||||
if (check_for_node(node_tab_leg, "num_points")) then
|
||||
call get_node_value(node_tab_leg, "num_points", &
|
||||
legendre_to_tabular_points)
|
||||
if (legendre_to_tabular_points <= 1 .and. (.not. run_CE)) then
|
||||
call fatal_error("The 'num_points' subelement/attribute of the &
|
||||
&'tabular_legendre' element must contain a value greater than 1")
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
|
||||
! Close settings XML file
|
||||
call close_xmldoc(doc)
|
||||
|
||||
|
|
@ -1366,11 +1422,7 @@ contains
|
|||
! Read cell temperatures. If the temperature is not specified, set it to
|
||||
! ERROR_REAL for now. During initialization we'll replace ERROR_REAL with
|
||||
! the temperature from the material data.
|
||||
if (.not. run_CE) then
|
||||
! Cell temperatures are not used for MG mode.
|
||||
allocate(c % sqrtkT(1))
|
||||
c % sqrtkT(1) = ZERO
|
||||
else if (check_for_node(node_cell, "temperature")) then
|
||||
if (check_for_node(node_cell, "temperature")) then
|
||||
n = get_arraysize_double(node_cell, "temperature")
|
||||
if (n > 0) then
|
||||
! Make sure this is a "normal" cell.
|
||||
|
|
@ -2048,7 +2100,7 @@ contains
|
|||
if (run_CE) then
|
||||
call read_ce_cross_sections_xml(libraries)
|
||||
else
|
||||
call read_mg_cross_sections_xml(libraries)
|
||||
call read_mg_cross_sections_header(libraries)
|
||||
end if
|
||||
|
||||
! Creating dictionary that maps the name of the material to the entry
|
||||
|
|
@ -2076,18 +2128,17 @@ contains
|
|||
call assign_temperatures(material_temps)
|
||||
|
||||
! Determine desired temperatures for each nuclide and S(a,b) table
|
||||
call get_temperatures(nuc_temps, sab_temps)
|
||||
call get_temperatures(cells, materials, material_dict, nuclide_dict, &
|
||||
n_nuclides_total, nuc_temps, sab_dict, &
|
||||
n_sab_tables, sab_temps)
|
||||
|
||||
! Read continuous-energy cross sections
|
||||
if (run_CE .and. run_mode /= MODE_PLOTTING) then
|
||||
call time_read_xs%start()
|
||||
call time_read_xs % start()
|
||||
call read_ce_cross_sections(libraries, library_dict, nuc_temps, sab_temps)
|
||||
call time_read_xs%stop()
|
||||
call time_read_xs % stop()
|
||||
end if
|
||||
|
||||
! Normalize atom/weight percents
|
||||
if (run_mode /= MODE_PLOTTING) call normalize_ao()
|
||||
|
||||
! Clear dictionary
|
||||
call library_dict % clear()
|
||||
end subroutine read_materials
|
||||
|
|
@ -3332,7 +3383,7 @@ contains
|
|||
! Search through nuclides
|
||||
pair_list => nuclide_dict % keys()
|
||||
do while (associated(pair_list))
|
||||
if (starts_with(pair_list % key, word)) then
|
||||
if (trim(pair_list % key) == trim(word)) then
|
||||
word = pair_list % key(1:150)
|
||||
exit
|
||||
end if
|
||||
|
|
@ -4710,44 +4761,43 @@ contains
|
|||
|
||||
end subroutine read_ce_cross_sections_xml
|
||||
|
||||
subroutine read_mg_cross_sections_xml(libraries)
|
||||
subroutine read_mg_cross_sections_header(libraries)
|
||||
type(Library), allocatable, intent(out) :: libraries(:)
|
||||
|
||||
integer :: i ! loop index
|
||||
integer :: n_libraries
|
||||
logical :: file_exists ! does cross_sections.xml exist?
|
||||
type(Node), pointer :: doc => null()
|
||||
type(Node), pointer :: node_xsdata => null()
|
||||
type(NodeList), pointer :: node_xsdata_list => null()
|
||||
logical :: file_exists ! does mgxs.h5 exist?
|
||||
integer(HID_T) :: file_id
|
||||
real(8), allocatable :: rev_energy_bins(:)
|
||||
character(len=MAX_WORD_LEN), allocatable :: names(:)
|
||||
|
||||
! Check if mgxs.xml exists
|
||||
! Check if MGXS Library exists
|
||||
inquire(FILE=path_cross_sections, EXIST=file_exists)
|
||||
if (.not. file_exists) then
|
||||
! Could not find mgxs.xml file
|
||||
call fatal_error("Cross sections XML file '" &
|
||||
! Could not find MGXS Library file
|
||||
call fatal_error("Cross sections HDF5 file '" &
|
||||
// trim(path_cross_sections) // "' does not exist!")
|
||||
end if
|
||||
|
||||
call write_message("Reading cross sections XML file...", 5)
|
||||
call write_message("Reading cross sections HDF5 file...", 5)
|
||||
|
||||
! Parse mgxs.xml file
|
||||
call open_xmldoc(doc, path_cross_sections)
|
||||
! Open file for reading
|
||||
file_id = file_open(path_cross_sections, 'r', parallel=.true.)
|
||||
|
||||
if (check_for_node(doc, "groups")) then
|
||||
if (attribute_exists(file_id, "groups")) then
|
||||
! Get neutron group count
|
||||
call get_node_value(doc, "groups", energy_groups)
|
||||
call read_attribute(energy_groups, file_id, "groups")
|
||||
else
|
||||
call fatal_error("groups element must exist!")
|
||||
call fatal_error("'groups' attribute must exist!")
|
||||
end if
|
||||
|
||||
allocate(rev_energy_bins(energy_groups + 1))
|
||||
allocate(energy_bins(energy_groups + 1))
|
||||
if (check_for_node(doc, "group_structure")) then
|
||||
if (attribute_exists(file_id, "group structure")) then
|
||||
! Get neutron group structure
|
||||
call get_node_array(doc, "group_structure", energy_bins)
|
||||
call read_attribute(energy_bins, file_id, "group structure")
|
||||
else
|
||||
call fatal_error("group_structures element must exist!")
|
||||
call fatal_error("'group structure' attribute must exist!")
|
||||
end if
|
||||
|
||||
! First reverse the order of energy_groups
|
||||
|
|
@ -4758,45 +4808,28 @@ contains
|
|||
energy_bin_avg(i) = HALF * (energy_bins(i) + energy_bins(i + 1))
|
||||
end do
|
||||
|
||||
allocate(inverse_velocities(energy_groups))
|
||||
if (check_for_node(doc, "inverse_velocities")) then
|
||||
! Get inverse velocities
|
||||
call get_node_array(doc, "inverse_velocities", inverse_velocities)
|
||||
else
|
||||
! If not given, estimate them by using average energy in group which is
|
||||
! assumed to be the midpoint
|
||||
do i = 1, energy_groups
|
||||
inverse_velocities(i) = ONE / &
|
||||
(sqrt(TWO * energy_bin_avg(i) / (MASS_NEUTRON_MEV)) * &
|
||||
C_LIGHT * 100.0_8)
|
||||
end do
|
||||
end if
|
||||
! Get the datasets present in the library
|
||||
call get_groups(file_id, names)
|
||||
n_libraries = size(names)
|
||||
|
||||
! Get node list of all <xsdata>
|
||||
call get_node_list(doc, "xsdata", node_xsdata_list)
|
||||
n_libraries = get_list_size(node_xsdata_list)
|
||||
|
||||
! Allocate xs_listings array
|
||||
! Allocate libraries array
|
||||
if (n_libraries == 0) then
|
||||
call fatal_error("At least one <xsdata> element must be present in &
|
||||
&mgxs.xml file!")
|
||||
call fatal_error("At least one MGXS data set must be present in &
|
||||
&mgxs library file!")
|
||||
else
|
||||
allocate(libraries(n_libraries))
|
||||
end if
|
||||
|
||||
do i = 1, n_libraries
|
||||
! Get pointer to xsdata table XML node
|
||||
call get_list_item(node_xsdata_list, i, node_xsdata)
|
||||
|
||||
! Get name of material
|
||||
allocate(libraries(i) % materials(1))
|
||||
call get_node_value(node_xsdata, "name", libraries(i) % materials(1))
|
||||
libraries(i) % materials(1) = names(i)
|
||||
end do
|
||||
|
||||
! Close cross sections XML file
|
||||
call close_xmldoc(doc)
|
||||
! Close MGXS HDF5 file
|
||||
call file_close(file_id)
|
||||
|
||||
end subroutine read_mg_cross_sections_xml
|
||||
end subroutine read_mg_cross_sections_header
|
||||
|
||||
!===============================================================================
|
||||
! EXPAND_NATURAL_ELEMENT converts natural elements specified using an <element>
|
||||
|
|
@ -5741,7 +5774,7 @@ contains
|
|||
if (run_CE) then
|
||||
awr = nuclides(mat % nuclide(j)) % awr
|
||||
else
|
||||
awr = ONE
|
||||
awr = nuclides_MG(mat % nuclide(j)) % obj % awr
|
||||
end if
|
||||
|
||||
! if given weight percent, convert all values so that they are divided
|
||||
|
|
@ -5766,7 +5799,7 @@ contains
|
|||
if (run_CE) then
|
||||
awr = nuclides(mat % nuclide(j)) % awr
|
||||
else
|
||||
awr = ONE
|
||||
awr = nuclides_MG(mat % nuclide(j)) % obj % awr
|
||||
end if
|
||||
x = mat % atom_density(j)
|
||||
sum_percent = sum_percent + x*awr
|
||||
|
|
@ -5910,7 +5943,7 @@ contains
|
|||
file_id = file_open(libraries(i_library) % path, 'r')
|
||||
group_id = open_group(file_id, name)
|
||||
call nuclides(i_nuclide) % from_hdf5(group_id, nuc_temps(i_nuclide), &
|
||||
temperature_method, temperature_tolerance)
|
||||
temperature_method, temperature_tolerance, master)
|
||||
call close_group(group_id)
|
||||
call file_close(file_id)
|
||||
|
||||
|
|
@ -6041,67 +6074,6 @@ contains
|
|||
end do
|
||||
end subroutine assign_temperatures
|
||||
|
||||
!===============================================================================
|
||||
! GET_TEMPERATURES returns a list of temperatures that each nuclide/S(a,b) table
|
||||
! appears at in the model. Later, this list is used to determine the actual
|
||||
! temperatures to read (which may be different if interpolation is used)
|
||||
!===============================================================================
|
||||
|
||||
subroutine get_temperatures(nuc_temps, sab_temps)
|
||||
type(VectorReal), allocatable, intent(out) :: nuc_temps(:)
|
||||
type(VectorReal), allocatable, intent(out) :: sab_temps(:)
|
||||
|
||||
integer :: i, j, k
|
||||
integer :: i_nuclide ! index in nuclides array
|
||||
integer :: i_sab ! index in S(a,b) array
|
||||
integer :: i_material
|
||||
real(8) :: temperature ! temperature in Kelvin
|
||||
|
||||
allocate(nuc_temps(n_nuclides_total))
|
||||
allocate(sab_temps(n_sab_tables))
|
||||
|
||||
do i = 1, size(cells)
|
||||
do j = 1, size(cells(i) % material)
|
||||
! Skip any non-material cells and void materials
|
||||
if (cells(i) % material(j) == NONE .or. &
|
||||
cells(i) % material(j) == MATERIAL_VOID) cycle
|
||||
|
||||
! Get temperature of cell (rounding to nearest integer)
|
||||
if (size(cells(i) % sqrtkT) > 1) then
|
||||
temperature = cells(i) % sqrtkT(j)**2 / K_BOLTZMANN
|
||||
else
|
||||
temperature = cells(i) % sqrtkT(1)**2 / K_BOLTZMANN
|
||||
end if
|
||||
|
||||
i_material = material_dict % get_key(cells(i) % material(j))
|
||||
associate (mat => materials(i_material))
|
||||
NUC_NAMES_LOOP: do k = 1, size(mat % names)
|
||||
! Get index in nuc_temps array
|
||||
i_nuclide = nuclide_dict % get_key(to_lower(mat % names(k)))
|
||||
|
||||
! Add temperature if it hasn't already been added
|
||||
if (find(nuc_temps(i_nuclide), temperature) == -1) then
|
||||
call nuc_temps(i_nuclide) % push_back(temperature)
|
||||
end if
|
||||
end do NUC_NAMES_LOOP
|
||||
|
||||
if (mat % n_sab > 0) then
|
||||
SAB_NAMES_LOOP: do k = 1, size(mat % sab_names)
|
||||
! Get index in nuc_temps array
|
||||
i_sab = sab_dict % get_key(to_lower(mat % sab_names(k)))
|
||||
|
||||
! Add temperature if it hasn't already been added
|
||||
if (find(sab_temps(i_sab), temperature) == -1) then
|
||||
call sab_temps(i_sab) % push_back(temperature)
|
||||
end if
|
||||
end do SAB_NAMES_LOOP
|
||||
end if
|
||||
end associate
|
||||
end do
|
||||
end do
|
||||
|
||||
end subroutine get_temperatures
|
||||
|
||||
!===============================================================================
|
||||
! READ_0K_ELASTIC_SCATTERING
|
||||
!===============================================================================
|
||||
|
|
@ -6143,7 +6115,7 @@ contains
|
|||
group_id = open_group(file_id, name)
|
||||
method = TEMPERATURE_NEAREST
|
||||
call resonant_nuc % from_hdf5(group_id, temperature, &
|
||||
method, 1000.0_8)
|
||||
method, 1000.0_8, master)
|
||||
call close_group(group_id)
|
||||
call file_close(file_id)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
module mgxs_data
|
||||
|
||||
use constants
|
||||
use constants
|
||||
use algorithm, only: find
|
||||
use error, only: fatal_error
|
||||
use geometry_header, only: get_temperatures
|
||||
use global
|
||||
use hdf5_interface
|
||||
use material_header, only: Material
|
||||
use mgxs_header
|
||||
use output, only: write_message
|
||||
use set_header, only: SetChar
|
||||
use stl_vector, only: VectorReal
|
||||
use string, only: to_lower
|
||||
use xml_interface
|
||||
|
||||
implicit none
|
||||
|
||||
contains
|
||||
|
|
@ -20,52 +22,41 @@ contains
|
|||
!===============================================================================
|
||||
|
||||
subroutine read_mgxs()
|
||||
|
||||
integer :: i ! index in materials array
|
||||
integer :: j ! index over nuclides in material
|
||||
integer :: i_xsdata ! index in <xsdata> list
|
||||
integer :: i_nuclide ! index in nuclides
|
||||
character(20) :: name ! name of isotope, e.g. 92235.03c
|
||||
integer :: i_xsdata ! index in xsdata_dict
|
||||
integer :: i_nuclide ! index in nuclides array
|
||||
character(20) :: name ! name of library to load
|
||||
integer :: representation ! Data representation
|
||||
type(Material), pointer :: mat
|
||||
type(SetChar) :: already_read
|
||||
type(Node), pointer :: doc => null()
|
||||
type(Node), pointer :: node_xsdata
|
||||
type(NodeList), pointer :: node_xsdata_list => null()
|
||||
logical :: file_exists
|
||||
character(MAX_LINE_LEN) :: temp_str
|
||||
type(Material), pointer :: mat
|
||||
type(SetChar) :: already_read
|
||||
integer(HID_T) :: file_id
|
||||
integer(HID_T) :: xsdata_group
|
||||
logical :: file_exists
|
||||
logical :: get_kfiss, get_fiss
|
||||
integer :: l
|
||||
type(DictCharInt) :: xsdata_dict
|
||||
type(VectorReal), allocatable :: temps(:)
|
||||
|
||||
! Check if cross_sections.xml exists
|
||||
! Check if MGXS Library exists
|
||||
inquire(FILE=path_cross_sections, EXIST=file_exists)
|
||||
if (.not. file_exists) then
|
||||
! Could not find cross_sections.xml file
|
||||
call fatal_error("Cross sections XML file '" &
|
||||
! Could not find MGXS Library file
|
||||
call fatal_error("Cross sections HDF5 file '" &
|
||||
&// trim(path_cross_sections) // "' does not exist!")
|
||||
end if
|
||||
|
||||
call write_message("Loading Cross Section Data...", 5)
|
||||
|
||||
! Parse cross_sections.xml file
|
||||
call open_xmldoc(doc, path_cross_sections)
|
||||
! Get temperatures
|
||||
call get_temperatures(cells, materials, material_dict, nuclide_dict, &
|
||||
n_nuclides_total, temps)
|
||||
|
||||
! Get node list of all <xsdata>
|
||||
call get_node_list(doc, "xsdata", node_xsdata_list)
|
||||
! Open file for reading
|
||||
file_id = file_open(path_cross_sections, 'r', parallel=.true.)
|
||||
|
||||
! Build dictionary mapping nuclide names to an index in the <xsdata> node
|
||||
! list
|
||||
do i = 1, get_list_size(node_xsdata_list)
|
||||
! Get pointer to xsdata table XML node
|
||||
call get_list_item(node_xsdata_list, i, node_xsdata)
|
||||
|
||||
! Get name and create pair (name, i)
|
||||
call get_node_value(node_xsdata, "name", name)
|
||||
call xsdata_dict % add_key(to_lower(name), i)
|
||||
end do
|
||||
|
||||
! allocate arrays for ACE table storage and cross section cache
|
||||
! allocate arrays for MGXS storage and cross section cache
|
||||
allocate(nuclides_MG(n_nuclides_total))
|
||||
!$omp parallel
|
||||
allocate(micro_xs(n_nuclides_total))
|
||||
|
|
@ -102,18 +93,22 @@ contains
|
|||
i_xsdata = xsdata_dict % get_key(to_lower(name))
|
||||
i_nuclide = mat % nuclide(j)
|
||||
|
||||
! Get pointer to xsdata table XML node
|
||||
call get_list_item(node_xsdata_list, i_xsdata, node_xsdata)
|
||||
|
||||
call write_message("Loading " // trim(name) // " Data...", 5)
|
||||
|
||||
! Check to make sure cross section set exists in the library
|
||||
if (object_exists(file_id, trim(name))) then
|
||||
xsdata_group = open_group(file_id, trim(name))
|
||||
else
|
||||
call fatal_error("Data for '" // trim(name) // "' does not exist in "&
|
||||
&// trim(path_cross_sections))
|
||||
end if
|
||||
|
||||
! First find out the data representation
|
||||
if (check_for_node(node_xsdata, "representation")) then
|
||||
call get_node_value(node_xsdata, "representation", temp_str)
|
||||
temp_str = trim(to_lower(temp_str))
|
||||
if (temp_str == 'isotropic' .or. temp_str == 'iso') then
|
||||
if (attribute_exists(xsdata_group, "representation")) then
|
||||
call read_attribute(temp_str, xsdata_group, "representation")
|
||||
if (trim(temp_str) == 'isotropic') then
|
||||
representation = MGXS_ISOTROPIC
|
||||
else if (temp_str == 'angle') then
|
||||
else if (trim(temp_str) == 'angle') then
|
||||
representation = MGXS_ANGLE
|
||||
else
|
||||
call fatal_error("Invalid Data Representation!")
|
||||
|
|
@ -132,8 +127,10 @@ contains
|
|||
end select
|
||||
|
||||
! Now read in the data specific to the type we just declared
|
||||
call nuclides_MG(i_nuclide) % obj % init_file(node_xsdata, &
|
||||
energy_groups, get_kfiss, get_fiss, max_order)
|
||||
call nuclides_MG(i_nuclide) % obj % from_hdf5(xsdata_group, &
|
||||
energy_groups, temps(i_nuclide), temperature_method, &
|
||||
temperature_tolerance, get_kfiss, get_fiss, max_order, &
|
||||
legendre_to_tabular, legendre_to_tabular_points)
|
||||
|
||||
! Add name to dictionary
|
||||
call already_read % add(name)
|
||||
|
|
@ -172,28 +169,74 @@ contains
|
|||
subroutine create_macro_xs()
|
||||
integer :: i_mat ! index in materials array
|
||||
type(Material), pointer :: mat ! current material
|
||||
integer :: scatt_type
|
||||
type(VectorReal), allocatable :: kTs(:)
|
||||
|
||||
allocate(macro_xs(n_materials))
|
||||
|
||||
! Get temperatures to read for each material
|
||||
call get_mat_kTs(kTs)
|
||||
|
||||
do i_mat = 1, n_materials
|
||||
mat => materials(i_mat)
|
||||
|
||||
! Check to see how our nuclides are represented
|
||||
! Force all to be the same type
|
||||
! Therefore type(nuclides(mat % nuclide(1)) % obj) dictates type(macroxs)
|
||||
! At the same time, we will find the scattering type, as that will dictate
|
||||
! how we allocate the scatter object within macroxs
|
||||
scatt_type = nuclides_MG(mat % nuclide(1)) % obj % scatt_type
|
||||
select type(nuc => nuclides_MG(mat % nuclide(1)) % obj)
|
||||
type is (MgxsIso)
|
||||
allocate(MgxsIso :: macro_xs(i_mat) % obj)
|
||||
type is (MgxsAngle)
|
||||
allocate(MgxsAngle :: macro_xs(i_mat) % obj)
|
||||
end select
|
||||
call macro_xs(i_mat) % obj % combine(mat, nuclides_MG, energy_groups, &
|
||||
max_order, scatt_type)
|
||||
! Do not read materials which we do not actually use in the problem to
|
||||
! save space
|
||||
if (allocated(kTs(i_mat) % data)) then
|
||||
call macro_xs(i_mat) % obj % combine(kTs(i_mat), mat, nuclides_MG, &
|
||||
energy_groups, max_order, &
|
||||
temperature_tolerance, &
|
||||
temperature_method)
|
||||
end if
|
||||
end do
|
||||
end subroutine create_macro_xs
|
||||
|
||||
!===============================================================================
|
||||
! GET_MAT_kTs returns a list of temperatures (in MeV) that each
|
||||
! material appears at in the model.
|
||||
!===============================================================================
|
||||
|
||||
subroutine get_mat_kTs(kTs)
|
||||
type(VectorReal), allocatable, intent(out) :: kTs(:)
|
||||
|
||||
integer :: i, j
|
||||
integer :: i_material ! Index in materials array
|
||||
real(8) :: kT ! temperature in MeV
|
||||
|
||||
allocate(kTs(size(materials)))
|
||||
|
||||
do i = 1, size(cells)
|
||||
do j = 1, size(cells(i) % material)
|
||||
! Skip any non-material cells and void materials
|
||||
if (cells(i) % material(j) == NONE .or. &
|
||||
cells(i) % material(j) == MATERIAL_VOID) cycle
|
||||
|
||||
! Get temperature of cell (rounding to nearest integer)
|
||||
if (size(cells(i) % sqrtkT) > 1) then
|
||||
kT = cells(i) % sqrtkT(j)**2
|
||||
else
|
||||
kT = cells(i) % sqrtkT(1)**2
|
||||
end if
|
||||
|
||||
i_material = material_dict % get_key(cells(i) % material(j))
|
||||
|
||||
! Add temperature if it hasn't already been added
|
||||
if (find(kTs(i_material), kT) == -1) then
|
||||
call kTs(i_material) % push_back(kT)
|
||||
end if
|
||||
|
||||
end do
|
||||
end do
|
||||
|
||||
end subroutine get_mat_kTs
|
||||
|
||||
|
||||
end module mgxs_data
|
||||
|
|
|
|||
3131
src/mgxs_header.F90
3131
src/mgxs_header.F90
File diff suppressed because it is too large
Load diff
|
|
@ -3,9 +3,7 @@ module nuclide_header
|
|||
use, intrinsic :: ISO_FORTRAN_ENV
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use hdf5, only: HID_T, HSIZE_T, SIZE_T, h5iget_name_f, h5gget_info_f, &
|
||||
h5lget_name_by_idx_f, H5_INDEX_NAME_F, H5_ITER_INC_F
|
||||
use h5lt, only: h5ltpath_valid_f
|
||||
use hdf5, only: HID_T, HSIZE_T, SIZE_T
|
||||
|
||||
use algorithm, only: sort, find
|
||||
use constants
|
||||
|
|
@ -14,7 +12,8 @@ module nuclide_header
|
|||
use endf_header, only: Function1D, Polynomial, Tabulated1D
|
||||
use error, only: fatal_error, warning
|
||||
use hdf5_interface, only: read_attribute, open_group, close_group, &
|
||||
open_dataset, read_dataset, close_dataset, get_shape, get_datasets
|
||||
open_dataset, read_dataset, close_dataset, get_shape, get_datasets, &
|
||||
object_exists, get_name, get_groups
|
||||
use list_header, only: ListInt
|
||||
use math, only: evaluate_legendre
|
||||
use multipole_header, only: MultipoleArray
|
||||
|
|
@ -186,18 +185,16 @@ module nuclide_header
|
|||
|
||||
end subroutine nuclide_clear
|
||||
|
||||
subroutine nuclide_from_hdf5(this, group_id, temperature, method, tolerance)
|
||||
class(Nuclide), intent(inout) :: this
|
||||
integer(HID_T), intent(in) :: group_id
|
||||
subroutine nuclide_from_hdf5(this, group_id, temperature, method, tolerance, &
|
||||
master)
|
||||
class(Nuclide), intent(inout) :: this
|
||||
integer(HID_T), intent(in) :: group_id
|
||||
type(VectorReal), intent(in) :: temperature ! list of desired temperatures
|
||||
integer, intent(inout) :: method
|
||||
real(8), intent(in) :: tolerance
|
||||
integer, intent(inout) :: method
|
||||
real(8), intent(in) :: tolerance
|
||||
logical, intent(in) :: master ! if this is the master proc
|
||||
|
||||
integer :: i
|
||||
integer :: storage_type
|
||||
integer :: max_corder
|
||||
integer :: n_links
|
||||
integer :: hdf5_err
|
||||
integer :: i_closest
|
||||
integer :: n_temperature
|
||||
integer(HID_T) :: urr_group, nu_group
|
||||
|
|
@ -208,21 +205,21 @@ module nuclide_header
|
|||
integer(HID_T) :: total_nu
|
||||
integer(HID_T) :: fer_group ! fission_energy_release group
|
||||
integer(HID_T) :: fer_dset
|
||||
integer(SIZE_T) :: name_len, name_file_len
|
||||
integer(SIZE_T) :: name_len
|
||||
integer(HSIZE_T) :: j
|
||||
integer(HSIZE_T) :: dims(1)
|
||||
character(MAX_WORD_LEN) :: temp_str
|
||||
character(MAX_FILE_LEN), allocatable :: dset_names(:)
|
||||
character(MAX_WORD_LEN), allocatable :: dset_names(:)
|
||||
character(MAX_WORD_LEN), allocatable :: grp_names(:)
|
||||
real(8), allocatable :: temps_available(:) ! temperatures available
|
||||
real(8) :: temp_desired
|
||||
real(8) :: temp_actual
|
||||
logical :: exists
|
||||
type(VectorInt) :: MTs
|
||||
type(VectorInt) :: temps_to_read
|
||||
|
||||
! Get name of nuclide from group
|
||||
name_len = len(this % name)
|
||||
call h5iget_name_f(group_id, this % name, name_len, name_file_len, hdf5_err)
|
||||
this % name = get_name(group_id, name_len)
|
||||
|
||||
! Get rid of leading '/'
|
||||
this % name = trim(this % name(2:))
|
||||
|
|
@ -265,15 +262,17 @@ module nuclide_header
|
|||
call temps_to_read % push_back(nint(temp_actual))
|
||||
|
||||
! Write warning for resonance scattering data if 0K is not available
|
||||
if (abs(temp_actual - temp_desired) > 0 .and. temp_desired == 0) then
|
||||
if (abs(temp_actual - temp_desired) > 0 .and. temp_desired == 0 &
|
||||
.and. master) then
|
||||
call warning(trim(this % name) // " does not contain 0K data &
|
||||
&needed for resonance scattering options selected. Using &
|
||||
&data at " // trim(to_str(nint(temp_actual))) // " K instead.")
|
||||
&data at " // trim(to_str(temp_actual)) &
|
||||
// " K instead.")
|
||||
end if
|
||||
end if
|
||||
else
|
||||
call fatal_error("Nuclear data library does not contain cross sections &
|
||||
&for " // trim(this % name) // " at or near " // &
|
||||
call fatal_error("Nuclear data library does not contain cross &
|
||||
§ions for " // trim(this % name) // " at or near " // &
|
||||
trim(to_str(nint(temp_desired))) // " K.")
|
||||
end if
|
||||
end do
|
||||
|
|
@ -332,12 +331,10 @@ module nuclide_header
|
|||
|
||||
! Get MT values based on group names
|
||||
rxs_group = open_group(group_id, 'reactions')
|
||||
call h5gget_info_f(rxs_group, storage_type, n_links, max_corder, hdf5_err)
|
||||
do j = 0, n_links - 1
|
||||
call h5lget_name_by_idx_f(rxs_group, ".", H5_INDEX_NAME_F, H5_ITER_INC_F, &
|
||||
j, temp_str, hdf5_err, name_len)
|
||||
if (starts_with(temp_str, "reaction_")) then
|
||||
call MTs % push_back(int(str_to_int(temp_str(10:12))))
|
||||
call get_groups(rxs_group, grp_names)
|
||||
do j = 1, size(grp_names)
|
||||
if (starts_with(grp_names(j), "reaction_")) then
|
||||
call MTs % push_back(int(str_to_int(grp_names(j)(10:12))))
|
||||
end if
|
||||
end do
|
||||
|
||||
|
|
@ -353,8 +350,7 @@ module nuclide_header
|
|||
call close_group(rxs_group)
|
||||
|
||||
! Read unresolved resonance probability tables if present
|
||||
call h5ltpath_valid_f(group_id, 'urr', .true., exists, hdf5_err)
|
||||
if (exists) then
|
||||
if (object_exists(group_id, 'urr')) then
|
||||
this % urr_present = .true.
|
||||
allocate(this % urr_data(n_temperature))
|
||||
|
||||
|
|
@ -395,8 +391,7 @@ module nuclide_header
|
|||
end if
|
||||
|
||||
! Check for nu-total
|
||||
call h5ltpath_valid_f(group_id, 'total_nu', .true., exists, hdf5_err)
|
||||
if (exists) then
|
||||
if (object_exists(group_id, 'total_nu')) then
|
||||
nu_group = open_group(group_id, 'total_nu')
|
||||
|
||||
! Read total nu data
|
||||
|
|
@ -415,9 +410,7 @@ module nuclide_header
|
|||
end if
|
||||
|
||||
! Read fission energy release data if present
|
||||
call h5ltpath_valid_f(group_id, 'fission_energy_release', .true., exists, &
|
||||
hdf5_err)
|
||||
if (exists) then
|
||||
if (object_exists(group_id, 'fission_energy_release')) then
|
||||
fer_group = open_group(group_id, 'fission_energy_release')
|
||||
|
||||
! Check to see if this is polynomial or tabulated data
|
||||
|
|
|
|||
|
|
@ -873,8 +873,13 @@ contains
|
|||
write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), &
|
||||
"Total Material"
|
||||
else
|
||||
write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), &
|
||||
trim(nuclides(i_nuclide) % name)
|
||||
if (run_CE) then
|
||||
write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), &
|
||||
trim(nuclides(i_nuclide) % name)
|
||||
else
|
||||
write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), &
|
||||
trim(nuclides_MG(i_nuclide) % obj % name)
|
||||
end if
|
||||
end if
|
||||
|
||||
indent = indent + 2
|
||||
|
|
|
|||
|
|
@ -96,10 +96,11 @@ contains
|
|||
! absorption (including fission)
|
||||
|
||||
if (nuc % fissionable) then
|
||||
call sample_fission(i_nuclide, i_reaction)
|
||||
if (run_mode == MODE_EIGENVALUE) then
|
||||
call sample_fission(i_nuclide, i_reaction)
|
||||
call create_fission_sites(p, i_nuclide, i_reaction, fission_bank, n_bank)
|
||||
elseif (run_mode == MODE_FIXEDSOURCE) then
|
||||
elseif (run_mode == MODE_FIXEDSOURCE .and. create_fission_neutrons) then
|
||||
call sample_fission(i_nuclide, i_reaction)
|
||||
call create_fission_sites(p, i_nuclide, i_reaction, &
|
||||
p % secondary_bank, p % n_secondary)
|
||||
end if
|
||||
|
|
@ -126,6 +127,13 @@ contains
|
|||
if (.not. p % alive) return
|
||||
end if
|
||||
|
||||
! Kill neutron under certain energy
|
||||
if (p % E < energy_cutoff) then
|
||||
p % alive = .false.
|
||||
p % wgt = ZERO
|
||||
p % last_wgt = ZERO
|
||||
end if
|
||||
|
||||
end subroutine sample_reaction
|
||||
|
||||
!===============================================================================
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ contains
|
|||
if (mat % fissionable) then
|
||||
if (run_mode == MODE_EIGENVALUE) then
|
||||
call create_fission_sites(p, fission_bank, n_bank)
|
||||
elseif (run_mode == MODE_FIXEDSOURCE) then
|
||||
elseif (run_mode == MODE_FIXEDSOURCE .and. create_fission_neutrons) then
|
||||
call create_fission_sites(p, p % secondary_bank, p % n_secondary)
|
||||
end if
|
||||
end if
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ module reaction_header
|
|||
|
||||
use constants, only: MAX_WORD_LEN
|
||||
use hdf5_interface, only: read_attribute, open_group, close_group, &
|
||||
open_dataset, read_dataset, close_dataset, get_shape
|
||||
open_dataset, read_dataset, close_dataset, get_shape, get_groups
|
||||
use product_header, only: ReactionProduct
|
||||
use stl_vector, only: VectorInt
|
||||
use string, only: to_str, starts_with
|
||||
|
|
@ -42,17 +42,12 @@ contains
|
|||
integer :: i
|
||||
integer :: cm
|
||||
integer :: n_product
|
||||
integer :: storage_type
|
||||
integer :: max_corder
|
||||
integer :: n_links
|
||||
integer :: hdf5_err
|
||||
integer(HID_T) :: pgroup
|
||||
integer(HID_T) :: xs, temp_group
|
||||
integer(SIZE_T) :: name_len
|
||||
integer(HSIZE_T) :: dims(1)
|
||||
integer(HSIZE_T) :: j
|
||||
character(MAX_WORD_LEN) :: name
|
||||
character(MAX_WORD_LEN) :: temp_str ! temperature dataset name, e.g. '294K'
|
||||
character(MAX_WORD_LEN), allocatable :: grp_names(:)
|
||||
|
||||
call read_attribute(this % Q_value, group_id, 'Q_value')
|
||||
call read_attribute(this % MT, group_id, 'mt')
|
||||
|
|
@ -74,12 +69,10 @@ contains
|
|||
end do
|
||||
|
||||
! Determine number of products
|
||||
call h5gget_info_f(group_id, storage_type, n_links, max_corder, hdf5_err)
|
||||
n_product = 0
|
||||
do j = 0, n_links - 1
|
||||
call h5lget_name_by_idx_f(group_id, ".", H5_INDEX_NAME_F, H5_ITER_INC_F, &
|
||||
j, name, hdf5_err, name_len)
|
||||
if (starts_with(name, "product_")) n_product = n_product + 1
|
||||
call get_groups(group_id, grp_names)
|
||||
do j = 1, size(grp_names)
|
||||
if (starts_with(grp_names(j), "product_")) n_product = n_product + 1
|
||||
end do
|
||||
|
||||
! Read products
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ module sab_header
|
|||
use distribution_univariate, only: Tabular
|
||||
use error, only: warning, fatal_error
|
||||
use hdf5, only: HID_T, HSIZE_T, SIZE_T
|
||||
use h5lt, only: h5ltpath_valid_f, h5iget_name_f
|
||||
use hdf5_interface, only: read_attribute, get_shape, open_group, close_group, &
|
||||
open_dataset, read_dataset, close_dataset, get_datasets
|
||||
open_dataset, read_dataset, close_dataset, get_datasets, object_exists, &
|
||||
get_name
|
||||
use secondary_correlated, only: CorrelatedAngleEnergy
|
||||
use stl_vector, only: VectorInt, VectorReal
|
||||
use string, only: to_str, str_to_int
|
||||
|
|
@ -66,7 +66,7 @@ module sab_header
|
|||
end type SabData
|
||||
|
||||
type SAlphaBeta
|
||||
character(100) :: name ! name of table, e.g. lwtr.10t
|
||||
character(150) :: name ! name of table, e.g. lwtr.10t
|
||||
real(8) :: awr ! weight of nucleus in neutron masses
|
||||
real(8), allocatable :: kTs(:) ! temperatures in MeV (k*T)
|
||||
character(10), allocatable :: nuclides(:) ! List of valid nuclides
|
||||
|
|
@ -92,8 +92,7 @@ contains
|
|||
integer :: n_energy, n_energy_out, n_mu
|
||||
integer :: i_closest
|
||||
integer :: n_temperature
|
||||
integer :: hdf5_err
|
||||
integer(SIZE_T) :: name_len, name_file_len
|
||||
integer(SIZE_T) :: name_len
|
||||
integer(HID_T) :: T_group
|
||||
integer(HID_T) :: elastic_group
|
||||
integer(HID_T) :: inelastic_group
|
||||
|
|
@ -103,11 +102,10 @@ contains
|
|||
integer(HSIZE_T) :: dims3(3)
|
||||
real(8), allocatable :: temp(:,:)
|
||||
character(20) :: type
|
||||
logical :: exists
|
||||
type(CorrelatedAngleEnergy) :: correlated_dist
|
||||
|
||||
character(MAX_WORD_LEN) :: temp_str
|
||||
character(MAX_FILE_LEN), allocatable :: dset_names(:)
|
||||
character(MAX_WORD_LEN), allocatable :: dset_names(:)
|
||||
real(8), allocatable :: temps_available(:) ! temperatures available
|
||||
real(8) :: temp_desired
|
||||
real(8) :: temp_actual
|
||||
|
|
@ -115,7 +113,7 @@ contains
|
|||
|
||||
! Get name of table from group
|
||||
name_len = len(this % name)
|
||||
call h5iget_name_f(group_id, this % name, name_len, name_file_len, hdf5_err)
|
||||
this % name = get_name(group_id, name_len)
|
||||
|
||||
! Get rid of leading '/'
|
||||
this % name = trim(this % name(2:))
|
||||
|
|
@ -207,8 +205,7 @@ contains
|
|||
T_group = open_group(group_id, temp_str)
|
||||
|
||||
! Coherent elastic data
|
||||
call h5ltpath_valid_f(T_group, 'elastic', .true., exists, hdf5_err)
|
||||
if (exists) then
|
||||
if (object_exists(T_group, 'elastic')) then
|
||||
! Read cross section data
|
||||
elastic_group = open_group(T_group, 'elastic')
|
||||
dset_id = open_dataset(elastic_group, 'xs')
|
||||
|
|
@ -250,8 +247,7 @@ contains
|
|||
end if
|
||||
|
||||
! Inelastic data
|
||||
call h5ltpath_valid_f(T_group, 'inelastic', .true., exists, hdf5_err)
|
||||
if (exists) then
|
||||
if (object_exists(T_group, 'inelastic')) then
|
||||
! Read type of inelastic data
|
||||
inelastic_group = open_group(T_group, 'inelastic')
|
||||
|
||||
|
|
|
|||
|
|
@ -41,18 +41,20 @@ module scattdata_header
|
|||
real(8), allocatable :: scattxs(:) ! Isotropic Sigma_{s,g_{in}}
|
||||
|
||||
contains
|
||||
procedure(scattdata_init_), deferred :: init ! Initializes ScattData
|
||||
procedure(scattdata_init_), deferred :: init ! Initializes ScattData
|
||||
procedure(scattdata_calc_f_), deferred :: calc_f ! Calculates f, given mu
|
||||
procedure(scattdata_sample_), deferred :: sample ! sample the scatter event
|
||||
procedure :: get_matrix => scattdata_get_matrix ! Rebuild scattering matrix
|
||||
end type ScattData
|
||||
|
||||
abstract interface
|
||||
subroutine scattdata_init_(this, mult, coeffs)
|
||||
import ScattData
|
||||
class(ScattData), intent(inout) :: this ! Object to work with
|
||||
real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix
|
||||
real(8), intent(in) :: coeffs(:, :, :) ! Coefficients to use
|
||||
subroutine scattdata_init_(this, gmin, gmax, mult, coeffs)
|
||||
import ScattData, Jagged1D, Jagged2D
|
||||
class(ScattData), intent(inout) :: this ! Object to work with
|
||||
integer, intent(in) :: gmin(:) ! Min Gout
|
||||
integer, intent(in) :: gmax(:) ! Max Gout
|
||||
type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix
|
||||
type(Jagged2D), intent(in) :: coeffs(:) ! Coefficients to use
|
||||
end subroutine scattdata_init_
|
||||
|
||||
pure function scattdata_calc_f_(this, gin, gout, mu) result(f)
|
||||
|
|
@ -79,9 +81,9 @@ module scattdata_header
|
|||
! Maximal value for rejection sampling from rectangle
|
||||
type(Jagged1D), allocatable :: max_val(:) ! (Gin % data(Gout))
|
||||
contains
|
||||
procedure :: init => scattdatalegendre_init
|
||||
procedure :: calc_f => scattdatalegendre_calc_f
|
||||
procedure :: sample => scattdatalegendre_sample
|
||||
procedure :: init => scattdatalegendre_init
|
||||
procedure :: calc_f => scattdatalegendre_calc_f
|
||||
procedure :: sample => scattdatalegendre_sample
|
||||
end type ScattDataLegendre
|
||||
|
||||
type, extends(ScattData) :: ScattDataHistogram
|
||||
|
|
@ -90,10 +92,10 @@ module scattdata_header
|
|||
! Histogram of f(mu) (dist has CDF)
|
||||
type(Jagged2D), allocatable :: fmu(:) ! (Gin % data(Order/Nmu x Gout)
|
||||
contains
|
||||
procedure :: init => scattdatahistogram_init
|
||||
procedure :: calc_f => scattdatahistogram_calc_f
|
||||
procedure :: sample => scattdatahistogram_sample
|
||||
procedure :: get_matrix => scattdatahistogram_get_matrix
|
||||
procedure :: init => scattdatahistogram_init
|
||||
procedure :: calc_f => scattdatahistogram_calc_f
|
||||
procedure :: sample => scattdatahistogram_sample
|
||||
procedure :: get_matrix => scattdatahistogram_get_matrix
|
||||
end type ScattDataHistogram
|
||||
|
||||
type, extends(ScattData) :: ScattDataTabular
|
||||
|
|
@ -102,10 +104,10 @@ module scattdata_header
|
|||
! PDF of f(mu) (dist has CDF)
|
||||
type(Jagged2D), allocatable :: fmu(:) ! (Gin % data(Order/Nmu x Gout)
|
||||
contains
|
||||
procedure :: init => scattdatatabular_init
|
||||
procedure :: calc_f => scattdatatabular_calc_f
|
||||
procedure :: sample => scattdatatabular_sample
|
||||
procedure :: get_matrix => scattdatatabular_get_matrix
|
||||
procedure :: init => scattdatatabular_init
|
||||
procedure :: calc_f => scattdatatabular_calc_f
|
||||
procedure :: sample => scattdatatabular_sample
|
||||
procedure :: get_matrix => scattdatatabular_get_matrix
|
||||
end type ScattDataTabular
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -122,13 +124,15 @@ contains
|
|||
! SCATTDATA*_INIT builds the scattdata object
|
||||
!===============================================================================
|
||||
|
||||
subroutine scattdata_init(this, order, energy, mult)
|
||||
class(ScattData), intent(inout) :: this ! Object to work on
|
||||
integer, intent(in) :: order ! Data Order
|
||||
real(8), intent(inout) :: energy(:, :) ! Energy Transfer Matrix
|
||||
real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix
|
||||
subroutine scattdata_init(this, order, gmin, gmax, energy, mult)
|
||||
class(ScattData), intent(inout) :: this ! Object to work on
|
||||
integer, intent(in) :: order ! Data Order
|
||||
integer, intent(in) :: gmin(:) ! Min Gout
|
||||
integer, intent(in) :: gmax(:) ! Max Gout
|
||||
type(Jagged1D), intent(inout) :: energy(:) ! Energy Transfer Matrix
|
||||
type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix
|
||||
|
||||
integer :: groups, gmin, gmax, gin
|
||||
integer :: groups, gin
|
||||
real(8) :: norm
|
||||
|
||||
groups = size(energy, dim=1)
|
||||
|
|
@ -138,83 +142,80 @@ contains
|
|||
allocate(this % energy(groups))
|
||||
allocate(this % mult(groups))
|
||||
allocate(this % dist(groups))
|
||||
! Use energy to find the gmin and gmax values
|
||||
! Also set energy values when doing it
|
||||
|
||||
this % gmin = gmin
|
||||
this % gmax = gmax
|
||||
|
||||
! Set the outgoing energy PDF values
|
||||
do gin = 1, groups
|
||||
! Make sure energy is normalized (i.e., CDF is 1)
|
||||
norm = sum(energy(:, gin))
|
||||
if (norm /= ZERO) energy(:, gin) = energy(:, gin) / norm
|
||||
! Find gmin by checking the P0 moment
|
||||
do gmin = 1, groups
|
||||
if (energy(gmin, gin) > ZERO) exit
|
||||
end do
|
||||
! Find gmax by checking the P0 moment
|
||||
do gmax = groups, 1, -1
|
||||
if (energy(gmax, gin) > ZERO) exit
|
||||
end do
|
||||
! Treat the case of all zeros
|
||||
if (gmin > gmax) then
|
||||
gmin = gin
|
||||
gmax = gin
|
||||
! By not changing energy(gin) here we are leaving it as zero
|
||||
end if
|
||||
allocate(this % energy(gin) % data(gmin:gmax))
|
||||
this % energy(gin) % data(gmin:gmax) = energy(gmin:gmax, gin)
|
||||
allocate(this % mult(gin) % data(gmin:gmax))
|
||||
this % mult(gin) % data(gmin:gmax) = mult(gmin:gmax, gin)
|
||||
allocate(this % dist(gin) % data(order, gmin:gmax))
|
||||
norm = sum(energy(gin) % data(:))
|
||||
if (norm /= ZERO) energy(gin) % data(:) = energy(gin) % data(:) / norm
|
||||
! Set the values
|
||||
allocate(this % energy(gin) % data(gmin(gin):gmax(gin)))
|
||||
this % energy(gin) % data(:) = energy(gin) % data(:)
|
||||
allocate(this % mult(gin) % data(gmin(gin):gmax(gin)))
|
||||
this % mult(gin) % data(gmin(gin):gmax(gin)) = &
|
||||
mult(gin) % data(gmin(gin):gmax(gin))
|
||||
allocate(this % dist(gin) % data(order, gmin(gin):gmax(gin)))
|
||||
this % dist(gin) % data = ZERO
|
||||
this % gmin(gin) = gmin
|
||||
this % gmax(gin) = gmax
|
||||
end do
|
||||
end subroutine scattdata_init
|
||||
|
||||
subroutine scattdatalegendre_init(this, mult, coeffs)
|
||||
class(ScattDataLegendre), intent(inout) :: this ! Object to work on
|
||||
real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix
|
||||
real(8), intent(in) :: coeffs(:, :, :) ! Coefficients to use
|
||||
subroutine scattdatalegendre_init(this, gmin, gmax, mult, coeffs)
|
||||
class(ScattDataLegendre), intent(inout) :: this ! Object to work on
|
||||
integer, intent(in) :: gmin(:) ! Min Gout
|
||||
integer, intent(in) :: gmax(:) ! Max Gout
|
||||
type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix
|
||||
type(Jagged2D), intent(in) :: coeffs(:) ! Coefficients to use
|
||||
|
||||
real(8) :: dmu, mu, f, norm
|
||||
integer :: imu, Nmu, gout, gin, groups, order
|
||||
real(8), allocatable :: energy(:, :)
|
||||
real(8), allocatable :: matrix(:, :, :)
|
||||
type(Jagged1D), allocatable :: energy(:)
|
||||
type(Jagged2D), allocatable :: matrix(:)
|
||||
|
||||
groups = size(coeffs, dim=3)
|
||||
order = size(coeffs, dim=1)
|
||||
groups = size(coeffs)
|
||||
order = size(coeffs(1) % data, dim=1)
|
||||
|
||||
! make a copy of coeffs that we can use to extract data and normalize
|
||||
allocate(matrix(order, groups, groups))
|
||||
matrix (:, :, :)= coeffs
|
||||
allocate(matrix(groups))
|
||||
do gin = 1, groups
|
||||
allocate(matrix(gin) % data(order, gmin(gin):gmax(gin)))
|
||||
matrix(gin) % data = coeffs(gin) % data
|
||||
end do
|
||||
|
||||
! Get scattxs value
|
||||
allocate(this % scattxs(groups))
|
||||
! Get this by summing the un-normalized P0 coefficient in matrix
|
||||
! over all outgoing groups
|
||||
this % scattxs(:) = sum(matrix(1, :, :), dim=1)
|
||||
do gin = 1, groups
|
||||
this % scattxs(gin) = sum(matrix(gin) % data(1, :), dim=1)
|
||||
end do
|
||||
|
||||
allocate(energy(groups, groups))
|
||||
energy(:, :) = ZERO
|
||||
allocate(energy(groups))
|
||||
! Build energy transfer probability matrix from data in matrix
|
||||
! while also normalizing matrix itself (making CDF of f(mu=1)=1)
|
||||
do gin = 1, groups
|
||||
do gout = 1, groups
|
||||
norm = matrix(1, gout, gin)
|
||||
energy(gout, gin) = norm
|
||||
allocate(energy(gin) % data(gmin(gin):gmax(gin)))
|
||||
energy(gin) % data = ZERO
|
||||
do gout = gmin(gin), gmax(gin)
|
||||
norm = matrix(gin) % data(1, gout)
|
||||
energy(gin) % data(gout) = norm
|
||||
if (norm /= ZERO) then
|
||||
matrix(:, gout, gin) = matrix(:, gout, gin) / norm
|
||||
matrix(gin) % data(:, gout) = matrix(gin) % data(:, gout) / norm
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
|
||||
call scattdata_init(this, order, energy, mult)
|
||||
call scattdata_init(this, order, gmin, gmax, energy, mult)
|
||||
|
||||
allocate(this % max_val(groups))
|
||||
! Set dist values from matrix and initialize max_val
|
||||
do gin = 1, groups
|
||||
do gout = this % gmin(gin), this % gmax(gin)
|
||||
this % dist(gin) % data(:, gout) = matrix(:, gout, gin)
|
||||
do gout = gmin(gin), gmax(gin)
|
||||
this % dist(gin) % data(:, gout) = matrix(gin) % data(:, gout)
|
||||
end do
|
||||
allocate(this % max_val(gin) % data(this % gmin(gin):this % gmax(gin)))
|
||||
allocate(this % max_val(gin) % data(gmin(gin):gmax(gin)))
|
||||
this % max_val(gin) % data(:) = ZERO
|
||||
end do
|
||||
|
||||
|
|
@ -223,7 +224,7 @@ contains
|
|||
Nmu = 1001
|
||||
dmu = TWO / real(Nmu - 1, 8)
|
||||
do gin = 1, groups
|
||||
do gout = this % gmin(gin), this % gmax(gin)
|
||||
do gout = gmin(gin), gmax(gin)
|
||||
do imu = 1, Nmu
|
||||
! Update mu. Do first and last seperate to avoid float errors
|
||||
if (imu == 1) then
|
||||
|
|
@ -246,44 +247,51 @@ contains
|
|||
end do
|
||||
end subroutine scattdatalegendre_init
|
||||
|
||||
subroutine scattdatahistogram_init(this, mult, coeffs)
|
||||
class(ScattDataHistogram), intent(inout) :: this ! Object to work on
|
||||
real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix
|
||||
real(8), intent(in) :: coeffs(:, :, :) ! Coefficients to use
|
||||
subroutine scattdatahistogram_init(this, gmin, gmax, mult, coeffs)
|
||||
class(ScattDataHistogram), intent(inout) :: this ! Object to work on
|
||||
integer, intent(in) :: gmin(:) ! Min Gout
|
||||
integer, intent(in) :: gmax(:) ! Max Gout
|
||||
type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix
|
||||
type(Jagged2D), intent(in) :: coeffs(:) ! Coefficients to use
|
||||
|
||||
integer :: imu, gin, gout, groups, order
|
||||
real(8) :: norm
|
||||
real(8), allocatable :: energy(:, :)
|
||||
real(8), allocatable :: matrix(:, :, :)
|
||||
type(Jagged1D), allocatable :: energy(:)
|
||||
type(Jagged2D), allocatable :: matrix(:)
|
||||
|
||||
groups = size(coeffs, dim=3)
|
||||
order = size(coeffs, dim=1)
|
||||
groups = size(coeffs)
|
||||
order = size(coeffs(1) % data, dim=1)
|
||||
|
||||
! make a copy of coeffs that we can use to extract data and normalize
|
||||
allocate(matrix(order, groups, groups))
|
||||
matrix(:, :, :) = coeffs
|
||||
allocate(matrix(groups))
|
||||
do gin = 1, groups
|
||||
allocate(matrix(gin) % data(order, gmin(gin):gmax(gin)))
|
||||
matrix(gin) % data = coeffs(gin) % data
|
||||
end do
|
||||
|
||||
! Get scattxs value
|
||||
allocate(this % scattxs(groups))
|
||||
! Get this by summing the un-normalized P0 coefficient in matrix
|
||||
! over all outgoing groups
|
||||
this % scattxs(:) = sum(sum(matrix(:, :, :), dim=1), dim=1)
|
||||
do gin = 1, groups
|
||||
this % scattxs(gin) = sum(matrix(gin) % data(1, :), dim=1)
|
||||
end do
|
||||
|
||||
allocate(energy(groups, groups))
|
||||
energy(:, :) = ZERO
|
||||
allocate(energy(groups))
|
||||
! Build energy transfer probability matrix from data in matrix
|
||||
! while also normalizing matrix itself (making CDF of f(mu=1)=1)
|
||||
do gin = 1, groups
|
||||
allocate(energy(gin) % data(gmin(gin):gmax(gin)))
|
||||
do gout = 1, groups
|
||||
norm = sum(matrix(:, gout, gin))
|
||||
energy(gout, gin) = norm
|
||||
norm = sum(matrix(gin) % data(:, gout))
|
||||
energy(gin) % data(gout) = norm
|
||||
if (norm /= ZERO) then
|
||||
matrix(:, gout, gin) = matrix(:, gout, gin) / norm
|
||||
matrix(gin) % data(:, gout) = matrix(gin) % data(:, gout) / norm
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
|
||||
call scattdata_init(this, order, energy, mult)
|
||||
call scattdata_init(this, order, gmin, gmax, energy, mult)
|
||||
|
||||
allocate(this % mu(order))
|
||||
this % dmu = TWO / real(order, 8)
|
||||
|
|
@ -296,17 +304,16 @@ contains
|
|||
! also saving the original histogram in fmu
|
||||
allocate(this % fmu(groups))
|
||||
do gin = 1, groups
|
||||
allocate(this % fmu(gin) % data(order, &
|
||||
this % gmin(gin):this % gmax(gin)))
|
||||
do gout = this % gmin(gin), this % gmax(gin)
|
||||
allocate(this % fmu(gin) % data(order, gmin(gin):gmax(gin)))
|
||||
do gout = gmin(gin), gmax(gin)
|
||||
! Store the histogram
|
||||
this % fmu(gin) % data(:, gout) = matrix(:, gout, gin)
|
||||
this % fmu(gin) % data(:, gout) = matrix(gin) % data(:, gout)
|
||||
! Integrate the histogram
|
||||
this % dist(gin) % data(1, gout) = &
|
||||
this % dmu * matrix(1, gout, gin)
|
||||
this % dmu * matrix(gin) % data(1, gout)
|
||||
do imu = 2, order
|
||||
this % dist(gin) % data(imu, gout) = &
|
||||
this % dmu * matrix(imu, gout, gin) + &
|
||||
this % dmu * matrix(gin) % data(imu, gout) + &
|
||||
this % dist(gin) % data(imu - 1, gout)
|
||||
end do
|
||||
|
||||
|
|
@ -323,22 +330,27 @@ contains
|
|||
|
||||
end subroutine scattdatahistogram_init
|
||||
|
||||
subroutine scattdatatabular_init(this, mult, coeffs)
|
||||
class(ScattDataTabular), intent(inout) :: this ! Object to work on
|
||||
real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix
|
||||
real(8), intent(in) :: coeffs(:, :, :) ! Coefficients to use
|
||||
subroutine scattdatatabular_init(this, gmin, gmax, mult, coeffs)
|
||||
class(ScattDataTabular), intent(inout) :: this ! Object to work on
|
||||
integer, intent(in) :: gmin(:) ! Min Gout
|
||||
integer, intent(in) :: gmax(:) ! Max Gout
|
||||
type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix
|
||||
type(Jagged2D), intent(in) :: coeffs(:) ! Coefficients to use
|
||||
|
||||
integer :: imu, gin, gout, groups, order
|
||||
real(8) :: norm
|
||||
real(8), allocatable :: energy(:, :)
|
||||
real(8), allocatable :: matrix(:, :, :)
|
||||
type(Jagged1D), allocatable :: energy(:)
|
||||
type(Jagged2D), allocatable :: matrix(:)
|
||||
|
||||
groups = size(coeffs, dim=3)
|
||||
order = size(coeffs, dim=1)
|
||||
groups = size(coeffs)
|
||||
order = size(coeffs(1) % data, dim=1)
|
||||
|
||||
! make a copy of coeffs that we can use to extract data and normalize
|
||||
allocate(matrix(order, groups, groups))
|
||||
matrix(:, :, :) = coeffs
|
||||
allocate(matrix(groups))
|
||||
do gin = 1, groups
|
||||
allocate(matrix(gin) % data(order, gmin(gin):gmax(gin)))
|
||||
matrix(gin) % data = coeffs(gin) % data
|
||||
end do
|
||||
|
||||
! Build the angular distribution mu values
|
||||
allocate(this % mu(order))
|
||||
|
|
@ -356,39 +368,40 @@ contains
|
|||
! over all outgoing groups
|
||||
do gin = 1, groups
|
||||
norm = ZERO
|
||||
do gout = 1, groups
|
||||
do gout = gmin(gin), gmax(gin)
|
||||
do imu = 2, order
|
||||
norm = norm + HALF * this % dmu * (matrix(imu - 1, gout, gin) + &
|
||||
matrix(imu, gout, gin))
|
||||
norm = norm + HALF * this % dmu * &
|
||||
(matrix(gin) % data(imu - 1, gout) + &
|
||||
matrix(gin) % data(imu, gout))
|
||||
end do
|
||||
end do
|
||||
this % scattxs(gin) = norm
|
||||
end do
|
||||
|
||||
allocate(energy(groups, groups))
|
||||
energy(:, :) = ZERO
|
||||
allocate(energy(groups))
|
||||
! Build energy transfer probability matrix from data in matrix
|
||||
do gin = 1, groups
|
||||
do gout = 1, groups
|
||||
allocate(energy(gin) % data(gmin(gin):gmax(gin)))
|
||||
do gout = gmin(gin), gmax(gin)
|
||||
norm = ZERO
|
||||
do imu = 2, order
|
||||
norm = norm + HALF * this % dmu * &
|
||||
(matrix(imu - 1, gout, gin) + matrix(imu, gout, gin))
|
||||
(matrix(gin) % data(imu - 1, gout) + &
|
||||
matrix(gin) % data(imu, gout))
|
||||
end do
|
||||
energy(gout, gin) = norm
|
||||
energy(gin) % data(gout) = norm
|
||||
end do
|
||||
end do
|
||||
call scattdata_init(this, order, energy, mult)
|
||||
call scattdata_init(this, order, gmin, gmax, energy, mult)
|
||||
|
||||
! Calculate f(mu) and integrate it so we can avoid rejection sampling
|
||||
allocate(this % fmu(groups))
|
||||
do gin = 1, groups
|
||||
allocate(this % fmu(gin) % data(order, &
|
||||
this % gmin(gin):this % gmax(gin)))
|
||||
do gout = this % gmin(gin), this % gmax(gin)
|
||||
allocate(this % fmu(gin) % data(order, gmin(gin):gmax(gin)))
|
||||
do gout = gmin(gin), gmax(gin)
|
||||
! Coeffs contain f(mu), put in f(mu) as that is where the
|
||||
! PDF lives
|
||||
this % fmu(gin) % data(:, gout) = matrix(:, gout, gin)
|
||||
this % fmu(gin) % data(:, gout) = matrix(gin) % data(:, gout)
|
||||
|
||||
! Force positivity
|
||||
do imu = 1, order
|
||||
|
|
@ -640,10 +653,10 @@ contains
|
|||
! using ScattData's information of fmu/dist, energy, and scattxs
|
||||
!===============================================================================
|
||||
|
||||
pure function scattdata_get_matrix(this, req_order) result(matrix)
|
||||
class(ScattData), intent(in) :: this ! Scattering Object to work with
|
||||
integer, intent(in) :: req_order ! Requested order of matrix
|
||||
real(8), allocatable :: matrix(:, :, :) ! Resultant matrix just built
|
||||
subroutine scattdata_get_matrix(this, req_order, matrix)
|
||||
class(ScattData), intent(in) :: this ! Scattering Object to work with
|
||||
integer, intent(in) :: req_order ! Requested order of matrix
|
||||
type(Jagged2D), allocatable, intent(inout) :: matrix(:) ! Resultant matrix just built
|
||||
|
||||
integer :: order, groups, gin, gout
|
||||
|
||||
|
|
@ -651,66 +664,189 @@ contains
|
|||
! Set gin and gout for getting the order
|
||||
order = min(req_order, size(this % dist(1) % data, dim=1))
|
||||
|
||||
allocate(matrix(order, groups, groups))
|
||||
if (allocated(matrix)) deallocate(matrix)
|
||||
allocate(matrix(groups))
|
||||
! Initialize to 0; this way the zero entries in the dense matrix dont
|
||||
! need to be explicitly set, requiring a significant increase in the
|
||||
! lines of code.
|
||||
matrix(:, :, :) = ZERO
|
||||
do gin = 1, groups
|
||||
allocate(matrix(gin) % data(order, groups))
|
||||
do gout = this % gmin(gin), this % gmax(gin)
|
||||
matrix(:, gout, gin) = this % scattxs(gin) * &
|
||||
matrix(gin) % data(:, gout) = this % scattxs(gin) * &
|
||||
this % energy(gin) % data(gout) * &
|
||||
this % dist(gin) % data(1:order, gout)
|
||||
end do
|
||||
end do
|
||||
end function scattdata_get_matrix
|
||||
end subroutine scattdata_get_matrix
|
||||
|
||||
pure function scattdatahistogram_get_matrix(this, req_order) result(matrix)
|
||||
class(ScattDataHistogram), intent(in) :: this ! Scattering Object to work with
|
||||
integer, intent(in) :: req_order ! Requested order of matrix
|
||||
real(8), allocatable :: matrix(:, :, :) ! Resultant matrix just built
|
||||
subroutine scattdatahistogram_get_matrix(this, req_order, matrix)
|
||||
class(ScattDataHistogram), intent(in) :: this ! Scattering Object to work with
|
||||
integer, intent(in) :: req_order ! Requested order of matrix
|
||||
type(Jagged2D), allocatable, intent(inout) :: matrix(:) ! Resultant matrix just built
|
||||
|
||||
integer :: order, groups, gin, gout
|
||||
|
||||
groups = size(this % energy)
|
||||
order = min(req_order, size(this % dist(1) % data, dim=1))
|
||||
|
||||
allocate(matrix(order, groups, groups))
|
||||
if (allocated(matrix)) deallocate(matrix)
|
||||
allocate(matrix(groups))
|
||||
! Initialize to 0; this way the zero entries in the dense matrix dont
|
||||
! need to be explicitly set, requiring a significant increase in the
|
||||
! lines of code.
|
||||
matrix(:, :, :) = ZERO
|
||||
do gin = 1, groups
|
||||
allocate(matrix(gin) % data(order, groups))
|
||||
do gout = this % gmin(gin), this % gmax(gin)
|
||||
matrix(:, gout, gin) = this % scattxs(gin) * &
|
||||
matrix(gin) % data(:, gout) = this % scattxs(gin) * &
|
||||
this % energy(gin) % data(gout) * &
|
||||
this % fmu(gin) % data(1:order, gout)
|
||||
end do
|
||||
end do
|
||||
end function scattdatahistogram_get_matrix
|
||||
end subroutine scattdatahistogram_get_matrix
|
||||
|
||||
pure function scattdatatabular_get_matrix(this, req_order) result(matrix)
|
||||
class(ScattDataTabular), intent(in) :: this ! Scattering Object to work with
|
||||
integer, intent(in) :: req_order ! Requested order of matrix
|
||||
real(8), allocatable :: matrix(:, :, :) ! Resultant matrix just built
|
||||
subroutine scattdatatabular_get_matrix(this, req_order, matrix)
|
||||
class(ScattDataTabular), intent(in) :: this ! Scattering Object to work with
|
||||
integer, intent(in) :: req_order ! Requested order of matrix
|
||||
type(Jagged2D), allocatable, intent(inout) :: matrix(:) ! Resultant matrix just built
|
||||
|
||||
integer :: order, groups, gin, gout
|
||||
|
||||
groups = size(this % energy)
|
||||
order = min(req_order, size(this % dist(1) % data, dim=1))
|
||||
|
||||
allocate(matrix(order, groups, groups))
|
||||
if (allocated(matrix)) deallocate(matrix)
|
||||
allocate(matrix(groups))
|
||||
! Initialize to 0; this way the zero entries in the dense matrix dont
|
||||
! need to be explicitly set, requiring a significant increase in the
|
||||
! lines of code.
|
||||
matrix(:, :, :) = ZERO
|
||||
do gin = 1, groups
|
||||
allocate(matrix(gin) % data(order, groups))
|
||||
do gout = this % gmin(gin), this % gmax(gin)
|
||||
matrix(:, gout, gin) = this % scattxs(gin) * &
|
||||
matrix(gin) % data(:, gout) = this % scattxs(gin) * &
|
||||
this % energy(gin) % data(gout) * &
|
||||
this % fmu(gin) % data(1:order, gout)
|
||||
end do
|
||||
end do
|
||||
end function scattdatatabular_get_matrix
|
||||
end subroutine scattdatatabular_get_matrix
|
||||
|
||||
!===============================================================================
|
||||
! JAGGED_FROM_DENSE_*D Creates a jagged array from a sparse dense matrix.
|
||||
! The user can supply a key which indicates the values to remove, but the
|
||||
! default is ZERO
|
||||
!===============================================================================
|
||||
|
||||
subroutine jagged_from_dense_1D(dense, jagged, lo_bounds_, hi_bounds_, key_)
|
||||
real(8), intent(in) :: dense(:, :)
|
||||
type(Jagged1D), allocatable, intent(inout) :: jagged(:)
|
||||
real(8), intent(in), optional :: key_
|
||||
integer, intent(inout), allocatable, optional :: lo_bounds_(:)
|
||||
integer, intent(inout), allocatable, optional :: hi_bounds_(:)
|
||||
|
||||
real(8) :: key
|
||||
integer :: i, jmin, jmax
|
||||
integer, allocatable :: lo_bounds(:), hi_bounds(:)
|
||||
|
||||
if (present(key_)) then
|
||||
key = key_
|
||||
else
|
||||
key = ZERO
|
||||
end if
|
||||
|
||||
allocate(lo_bounds(size(dense, dim=2)))
|
||||
allocate(hi_bounds(size(dense, dim=2)))
|
||||
|
||||
if (allocated(jagged)) deallocate(jagged)
|
||||
allocate(jagged(size(dense, dim=2)))
|
||||
do i = 1, size(dense, dim=2)
|
||||
! Find the min and max j values
|
||||
do jmin = 1, size(dense, dim=1)
|
||||
if (dense(jmin, i) /= key) exit
|
||||
end do
|
||||
do jmax = size(dense, dim=1), 1, -1
|
||||
if (dense(jmax, i) /= key) exit
|
||||
end do
|
||||
! Treat the case of all values matching the key
|
||||
if (jmin > jmax) then
|
||||
jmin = i
|
||||
jmax = i
|
||||
end if
|
||||
|
||||
! Now store the jagged row
|
||||
allocate(jagged(i) % data(jmin:jmax))
|
||||
jagged(i) % data(jmin:jmax) = dense(jmin:jmax, i)
|
||||
|
||||
lo_bounds(i) = jmin
|
||||
hi_bounds(i) = jmax
|
||||
end do
|
||||
|
||||
if (present(lo_bounds_)) then
|
||||
if (allocated(lo_bounds_)) deallocate(lo_bounds_)
|
||||
allocate(lo_bounds_(size(dense, dim=2)))
|
||||
lo_bounds_ = lo_bounds
|
||||
end if
|
||||
if (present(hi_bounds_)) then
|
||||
if (allocated(hi_bounds_)) deallocate(hi_bounds_)
|
||||
allocate(hi_bounds_(size(dense, dim=2)))
|
||||
hi_bounds_ = hi_bounds
|
||||
end if
|
||||
|
||||
end subroutine jagged_from_dense_1D
|
||||
|
||||
subroutine jagged_from_dense_2D(dense, jagged, lo_bounds_, hi_bounds_, key_)
|
||||
real(8), intent(in) :: dense(:, :, :)
|
||||
type(Jagged2D), allocatable, intent(inout) :: jagged(:)
|
||||
real(8), intent(in), optional :: key_
|
||||
integer, intent(inout), allocatable, optional :: lo_bounds_(:)
|
||||
integer, intent(inout), allocatable, optional :: hi_bounds_(:)
|
||||
|
||||
real(8) :: key
|
||||
integer :: i, jmin, jmax
|
||||
integer, allocatable :: lo_bounds(:), hi_bounds(:)
|
||||
|
||||
if (present(key_)) then
|
||||
key = key_
|
||||
else
|
||||
key = ZERO
|
||||
end if
|
||||
|
||||
allocate(lo_bounds(size(dense, dim=3)))
|
||||
allocate(hi_bounds(size(dense, dim=3)))
|
||||
|
||||
if (allocated(jagged)) deallocate(jagged)
|
||||
allocate(jagged(size(dense, dim=3)))
|
||||
do i = 1, size(dense, dim=3)
|
||||
! Find the min and max j values
|
||||
do jmin = 1, size(dense, dim=2)
|
||||
if (any(dense(:, jmin, i) /= key)) exit
|
||||
end do
|
||||
do jmax = size(dense, dim=2), 1, -1
|
||||
if (any(dense(:, jmax, i) /= key)) exit
|
||||
end do
|
||||
! Treat the case of all values matching the key
|
||||
if (jmin > jmax) then
|
||||
jmin = i
|
||||
jmax = i
|
||||
end if
|
||||
|
||||
! Now store the jagged row
|
||||
allocate(jagged(i) % data(size(dense, dim=1), jmin:jmax))
|
||||
jagged(i) % data(:, jmin:jmax) = dense(:, jmin:jmax, i)
|
||||
|
||||
lo_bounds(i) = jmin
|
||||
hi_bounds(i) = jmax
|
||||
end do
|
||||
|
||||
if (present(lo_bounds_)) then
|
||||
if (allocated(lo_bounds_)) deallocate(lo_bounds_)
|
||||
allocate(lo_bounds_(size(dense, dim=3)))
|
||||
lo_bounds_ = lo_bounds
|
||||
end if
|
||||
if (present(hi_bounds_)) then
|
||||
if (allocated(hi_bounds_)) deallocate(hi_bounds_)
|
||||
allocate(hi_bounds_(size(dense, dim=3)))
|
||||
hi_bounds_ = hi_bounds
|
||||
end if
|
||||
|
||||
end subroutine jagged_from_dense_2D
|
||||
|
||||
end module scattdata_header
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
module secondary_uncorrelated
|
||||
|
||||
use h5lt, only: h5ltpath_valid_f
|
||||
use hdf5, only: HID_T
|
||||
|
||||
use angle_distribution, only: AngleDistribution
|
||||
|
|
@ -9,7 +8,8 @@ module secondary_uncorrelated
|
|||
use energy_distribution, only: EnergyDistribution, LevelInelastic, &
|
||||
ContinuousTabular, MaxwellEnergy, Evaporation, WattEnergy, DiscretePhoton
|
||||
use error, only: warning
|
||||
use hdf5_interface, only: read_attribute, open_group, close_group
|
||||
use hdf5_interface, only: read_attribute, open_group, close_group, &
|
||||
object_exists
|
||||
use random_lcg, only: prn
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -56,25 +56,19 @@ contains
|
|||
class(UncorrelatedAngleEnergy), intent(inout) :: this
|
||||
integer(HID_T), intent(in) :: group_id
|
||||
|
||||
logical :: exists
|
||||
integer :: hdf5_err
|
||||
integer(HID_T) :: energy_group
|
||||
integer(HID_T) :: angle_group
|
||||
character(MAX_WORD_LEN) :: type
|
||||
|
||||
! Check if energy group is present
|
||||
call h5ltpath_valid_f(group_id, 'angle', .true., exists, hdf5_err)
|
||||
|
||||
if (exists) then
|
||||
! Check if angle group is present & read
|
||||
if (object_exists(group_id, 'angle')) then
|
||||
angle_group = open_group(group_id, 'angle')
|
||||
call this%angle%from_hdf5(angle_group)
|
||||
call close_group(angle_group)
|
||||
end if
|
||||
|
||||
! Check if energy group is present
|
||||
call h5ltpath_valid_f(group_id, 'energy', .true., exists, hdf5_err)
|
||||
|
||||
if (exists) then
|
||||
! Check if energy group is present & read
|
||||
if (object_exists(group_id, 'energy')) then
|
||||
energy_group = open_group(group_id, 'energy')
|
||||
call read_attribute(type, energy_group, 'type')
|
||||
select case (type)
|
||||
|
|
|
|||
|
|
@ -284,11 +284,20 @@ contains
|
|||
allocate(str_array(tally % n_nuclide_bins))
|
||||
NUCLIDE_LOOP: do j = 1, tally % n_nuclide_bins
|
||||
if (tally % nuclide_bins(j) > 0) then
|
||||
i_xs = index(nuclides(tally % nuclide_bins(j)) % name, '.')
|
||||
if (i_xs > 0) then
|
||||
str_array(j) = nuclides(tally % nuclide_bins(j)) % name(1 : i_xs-1)
|
||||
if (run_CE) then
|
||||
i_xs = index(nuclides(tally % nuclide_bins(j)) % name, '.')
|
||||
if (i_xs > 0) then
|
||||
str_array(j) = nuclides(tally % nuclide_bins(j)) % name(1 : i_xs-1)
|
||||
else
|
||||
str_array(j) = nuclides(tally % nuclide_bins(j)) % name
|
||||
end if
|
||||
else
|
||||
str_array(j) = nuclides(tally % nuclide_bins(j)) % name
|
||||
i_xs = index(nuclides_MG(tally % nuclide_bins(j)) % obj % name, '.')
|
||||
if (i_xs > 0) then
|
||||
str_array(j) = nuclides_MG(tally % nuclide_bins(j)) % obj % name(1 : i_xs-1)
|
||||
else
|
||||
str_array(j) = nuclides_MG(tally % nuclide_bins(j)) % obj % name
|
||||
end if
|
||||
end if
|
||||
else
|
||||
str_array(j) = 'total'
|
||||
|
|
|
|||
|
|
@ -1158,6 +1158,8 @@ contains
|
|||
! Do same for nucxs, point it to the microscopic nuclide data of interest
|
||||
if (i_nuclide > 0) then
|
||||
nucxs => nuclides_MG(i_nuclide) % obj
|
||||
! And since we haven't calculated this temperature index yet, do so now
|
||||
call nucxs % find_temperature(p % sqrtkT)
|
||||
end if
|
||||
|
||||
i = 0
|
||||
|
|
@ -1237,11 +1239,21 @@ contains
|
|||
else
|
||||
score = p % last_wgt
|
||||
end if
|
||||
score = score * inverse_velocities(p_g) / material_xs % total * flux
|
||||
if (i_nuclide > 0) then
|
||||
score = score * nucxs % get_xs('inv_vel', p_g, UVW=p_uvw) / &
|
||||
matxs % get_xs('total', p_g, UVW=p_uvw) * flux
|
||||
else
|
||||
score = matxs % get_xs('inv_vel', p_g, UVW=p_uvw) * flux
|
||||
end if
|
||||
|
||||
else
|
||||
! For inverse velocity, we need no cross section
|
||||
score = flux * inverse_velocities(p_g)
|
||||
if (i_nuclide > 0) then
|
||||
score = score * nucxs % get_xs('inv_vel', p_g, UVW=p_uvw) * &
|
||||
atom_density * flux
|
||||
else
|
||||
score = flux * matxs % get_xs('inv_vel', p_g, UVW=p_uvw)
|
||||
end if
|
||||
end if
|
||||
|
||||
|
||||
|
|
@ -1862,17 +1874,24 @@ contains
|
|||
|
||||
i_nuclide = t % nuclide_bins(k)
|
||||
|
||||
! Check to see if this nuclide was in the material of our collision.
|
||||
do m = 1, mat % n_nuclides
|
||||
if (mat % nuclide(m) == i_nuclide) then
|
||||
atom_density = mat % atom_density(m)
|
||||
exit
|
||||
end if
|
||||
end do
|
||||
if (i_nuclide > 0) then
|
||||
atom_density = -ONE
|
||||
! Check to see if this nuclide was in the material of our collision
|
||||
do m = 1, mat % n_nuclides
|
||||
if (mat % nuclide(m) == i_nuclide) then
|
||||
atom_density = mat % atom_density(m)
|
||||
exit
|
||||
end if
|
||||
end do
|
||||
else
|
||||
atom_density = ZERO
|
||||
end if
|
||||
|
||||
! Determine score for each bin
|
||||
call score_general(p, t, (k-1)*t % n_score_bins, filter_index, &
|
||||
i_nuclide, atom_density, filter_weight)
|
||||
! If we found the nuclide, determine the score for each bin
|
||||
if (atom_density >= ZERO) then
|
||||
call score_general(p, t, (k-1)*t % n_score_bins, filter_index, &
|
||||
i_nuclide, atom_density, filter_weight)
|
||||
end if
|
||||
|
||||
end do NUCLIDE_LOOP
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,9 @@ contains
|
|||
! Since the MGXS can be angle dependent, this needs to be done
|
||||
! After every collision for the MGXS mode
|
||||
if (p % material /= MATERIAL_VOID) then
|
||||
! Update the temperature index
|
||||
call macro_xs(p % material) % obj % find_temperature(p % sqrtkT)
|
||||
! Get the data
|
||||
call macro_xs(p % material) % obj % calculate_xs(p % g, &
|
||||
p % coord(p % n_coord) % uvw, material_xs)
|
||||
else
|
||||
|
|
|
|||
BIN
tests/1d_mgxs.h5
Normal file
BIN
tests/1d_mgxs.h5
Normal file
Binary file not shown.
9859
tests/1d_mgxs.xml
9859
tests/1d_mgxs.xml
File diff suppressed because it is too large
Load diff
|
|
@ -1,8 +1,9 @@
|
|||
import numpy as np
|
||||
|
||||
import openmc
|
||||
from openmc.source import Source
|
||||
from openmc.stats import Box
|
||||
|
||||
import numpy as np
|
||||
|
||||
class InputSet(object):
|
||||
def __init__(self):
|
||||
|
|
@ -27,37 +28,8 @@ class InputSet(object):
|
|||
fuel.set_density('g/cm3', 10.062)
|
||||
fuel.add_nuclide("U234", 4.9476e-6)
|
||||
fuel.add_nuclide("U235", 4.8218e-4)
|
||||
fuel.add_nuclide("U236", 9.0402e-5)
|
||||
fuel.add_nuclide("U238", 2.1504e-2)
|
||||
fuel.add_nuclide("Np237", 7.3733e-6)
|
||||
fuel.add_nuclide("Pu238", 1.5148e-6)
|
||||
fuel.add_nuclide("Pu239", 1.3955e-4)
|
||||
fuel.add_nuclide("Pu240", 3.4405e-5)
|
||||
fuel.add_nuclide("Pu241", 2.1439e-5)
|
||||
fuel.add_nuclide("Pu242", 3.7422e-6)
|
||||
fuel.add_nuclide("Am241", 4.5041e-7)
|
||||
fuel.add_nuclide("Am242_m1", 9.2301e-9)
|
||||
fuel.add_nuclide("Am243", 4.7878e-7)
|
||||
fuel.add_nuclide("Cm242", 1.0485e-7)
|
||||
fuel.add_nuclide("Cm243", 1.4268e-9)
|
||||
fuel.add_nuclide("Cm244", 8.8756e-8)
|
||||
fuel.add_nuclide("Cm245", 3.5285e-9)
|
||||
fuel.add_nuclide("Mo95", 2.6497e-5)
|
||||
fuel.add_nuclide("Tc99", 3.2772e-5)
|
||||
fuel.add_nuclide("Ru101", 3.0742e-5)
|
||||
fuel.add_nuclide("Ru103", 2.3505e-6)
|
||||
fuel.add_nuclide("Ag109", 2.0009e-6)
|
||||
fuel.add_nuclide("Xe135", 1.0801e-8)
|
||||
fuel.add_nuclide("Cs133", 3.4612e-5)
|
||||
fuel.add_nuclide("Nd143", 2.6078e-5)
|
||||
fuel.add_nuclide("Nd145", 1.9898e-5)
|
||||
fuel.add_nuclide("Sm147", 1.6128e-6)
|
||||
fuel.add_nuclide("Sm149", 1.1627e-7)
|
||||
fuel.add_nuclide("Sm150", 7.1727e-6)
|
||||
fuel.add_nuclide("Sm151", 5.4947e-7)
|
||||
fuel.add_nuclide("Sm152", 3.0221e-6)
|
||||
fuel.add_nuclide("Eu153", 2.6209e-6)
|
||||
fuel.add_nuclide("Gd155", 1.5369e-9)
|
||||
fuel.add_nuclide("O16", 4.5737e-2)
|
||||
|
||||
clad = openmc.Material(name='Cladding', material_id=2)
|
||||
|
|
@ -93,27 +65,10 @@ class InputSet(object):
|
|||
rpv_steel.add_nuclide("Fe58", 0.00282159, 'wo')
|
||||
rpv_steel.add_nuclide("Ni58", 0.0067198, 'wo')
|
||||
rpv_steel.add_nuclide("Ni60", 0.0026776, 'wo')
|
||||
rpv_steel.add_nuclide("Ni61", 0.0001183, 'wo')
|
||||
rpv_steel.add_nuclide("Ni62", 0.0003835, 'wo')
|
||||
rpv_steel.add_nuclide("Ni64", 0.0001008, 'wo')
|
||||
rpv_steel.add_nuclide("Mn55", 0.01, 'wo')
|
||||
rpv_steel.add_nuclide("Mo92", 0.000849, 'wo')
|
||||
rpv_steel.add_nuclide("Mo94", 0.0005418, 'wo')
|
||||
rpv_steel.add_nuclide("Mo95", 0.0009438, 'wo')
|
||||
rpv_steel.add_nuclide("Mo96", 0.0010002, 'wo')
|
||||
rpv_steel.add_nuclide("Mo97", 0.0005796, 'wo')
|
||||
rpv_steel.add_nuclide("Mo98", 0.0014814, 'wo')
|
||||
rpv_steel.add_nuclide("Mo100", 0.0006042, 'wo')
|
||||
rpv_steel.add_nuclide("Si28", 0.00367464, 'wo')
|
||||
rpv_steel.add_nuclide("Si29", 0.00019336, 'wo')
|
||||
rpv_steel.add_nuclide("Si30", 0.000132, 'wo')
|
||||
rpv_steel.add_nuclide("Cr50", 0.00010435, 'wo')
|
||||
rpv_steel.add_nuclide("Cr52", 0.002092475, 'wo')
|
||||
rpv_steel.add_nuclide("Cr53", 0.00024185, 'wo')
|
||||
rpv_steel.add_nuclide("Cr54", 6.1325e-05, 'wo')
|
||||
rpv_steel.add_nuclide("C0", 0.0025, 'wo')
|
||||
rpv_steel.add_nuclide("Cu63", 0.0013696, 'wo')
|
||||
rpv_steel.add_nuclide("Cu65", 0.0006304, 'wo')
|
||||
|
||||
lower_rad_ref = openmc.Material(name='Lower radial reflector',
|
||||
material_id=6)
|
||||
|
|
@ -127,18 +82,8 @@ class InputSet(object):
|
|||
lower_rad_ref.add_nuclide("Fe57", 0.01362750048, 'wo')
|
||||
lower_rad_ref.add_nuclide("Fe58", 0.001848545204, 'wo')
|
||||
lower_rad_ref.add_nuclide("Ni58", 0.055298376566, 'wo')
|
||||
lower_rad_ref.add_nuclide("Ni60", 0.022034425592, 'wo')
|
||||
lower_rad_ref.add_nuclide("Ni61", 0.000973510811, 'wo')
|
||||
lower_rad_ref.add_nuclide("Ni62", 0.003155886695, 'wo')
|
||||
lower_rad_ref.add_nuclide("Ni64", 0.000829500336, 'wo')
|
||||
lower_rad_ref.add_nuclide("Mn55", 0.0182870, 'wo')
|
||||
lower_rad_ref.add_nuclide("Si28", 0.00839976771, 'wo')
|
||||
lower_rad_ref.add_nuclide("Si29", 0.00044199679, 'wo')
|
||||
lower_rad_ref.add_nuclide("Si30", 0.0003017355, 'wo')
|
||||
lower_rad_ref.add_nuclide("Cr50", 0.007251360806, 'wo')
|
||||
lower_rad_ref.add_nuclide("Cr52", 0.145407678031, 'wo')
|
||||
lower_rad_ref.add_nuclide("Cr53", 0.016806340306, 'wo')
|
||||
lower_rad_ref.add_nuclide("Cr54", 0.004261520857, 'wo')
|
||||
lower_rad_ref.add_s_alpha_beta('c_H_in_H2O')
|
||||
|
||||
upper_rad_ref = openmc.Material(name='Upper radial reflector /'
|
||||
|
|
@ -153,18 +98,8 @@ class InputSet(object):
|
|||
upper_rad_ref.add_nuclide("Fe57", 0.01375486056, 'wo')
|
||||
upper_rad_ref.add_nuclide("Fe58", 0.001865821363, 'wo')
|
||||
upper_rad_ref.add_nuclide("Ni58", 0.055815129186, 'wo')
|
||||
upper_rad_ref.add_nuclide("Ni60", 0.022240333032, 'wo')
|
||||
upper_rad_ref.add_nuclide("Ni61", 0.000982608081, 'wo')
|
||||
upper_rad_ref.add_nuclide("Ni62", 0.003185377845, 'wo')
|
||||
upper_rad_ref.add_nuclide("Ni64", 0.000837251856, 'wo')
|
||||
upper_rad_ref.add_nuclide("Mn55", 0.0184579, 'wo')
|
||||
upper_rad_ref.add_nuclide("Si28", 0.00847831314, 'wo')
|
||||
upper_rad_ref.add_nuclide("Si29", 0.00044612986, 'wo')
|
||||
upper_rad_ref.add_nuclide("Si30", 0.000304557, 'wo')
|
||||
upper_rad_ref.add_nuclide("Cr50", 0.00731912987, 'wo')
|
||||
upper_rad_ref.add_nuclide("Cr52", 0.146766614995, 'wo')
|
||||
upper_rad_ref.add_nuclide("Cr53", 0.01696340737, 'wo')
|
||||
upper_rad_ref.add_nuclide("Cr54", 0.004301347765, 'wo')
|
||||
upper_rad_ref.add_s_alpha_beta('c_H_in_H2O')
|
||||
|
||||
bot_plate = openmc.Material(name='Bottom plate region', material_id=8)
|
||||
|
|
@ -178,18 +113,8 @@ class InputSet(object):
|
|||
bot_plate.add_nuclide("Fe57", 0.014750478, 'wo')
|
||||
bot_plate.add_nuclide("Fe58", 0.002000875025, 'wo')
|
||||
bot_plate.add_nuclide("Ni58", 0.059855207342, 'wo')
|
||||
bot_plate.add_nuclide("Ni60", 0.023850159704, 'wo')
|
||||
bot_plate.add_nuclide("Ni61", 0.001053732407, 'wo')
|
||||
bot_plate.add_nuclide("Ni62", 0.003415945715, 'wo')
|
||||
bot_plate.add_nuclide("Ni64", 0.000897854832, 'wo')
|
||||
bot_plate.add_nuclide("Mn55", 0.0197940, 'wo')
|
||||
bot_plate.add_nuclide("Si28", 0.00909197802, 'wo')
|
||||
bot_plate.add_nuclide("Si29", 0.00047842098, 'wo')
|
||||
bot_plate.add_nuclide("Si30", 0.000326601, 'wo')
|
||||
bot_plate.add_nuclide("Cr50", 0.007848910646, 'wo')
|
||||
bot_plate.add_nuclide("Cr52", 0.157390026871, 'wo')
|
||||
bot_plate.add_nuclide("Cr53", 0.018191270146, 'wo')
|
||||
bot_plate.add_nuclide("Cr54", 0.004612692337, 'wo')
|
||||
bot_plate.add_s_alpha_beta('c_H_in_H2O')
|
||||
|
||||
bot_nozzle = openmc.Material(name='Bottom nozzle region',
|
||||
|
|
@ -204,18 +129,8 @@ class InputSet(object):
|
|||
bot_nozzle.add_nuclide("Fe57", 0.01163454624, 'wo')
|
||||
bot_nozzle.add_nuclide("Fe58", 0.001578204652, 'wo')
|
||||
bot_nozzle.add_nuclide("Ni58", 0.047211231662, 'wo')
|
||||
bot_nozzle.add_nuclide("Ni60", 0.018811987544, 'wo')
|
||||
bot_nozzle.add_nuclide("Ni61", 0.000831139127, 'wo')
|
||||
bot_nozzle.add_nuclide("Ni62", 0.002694352115, 'wo')
|
||||
bot_nozzle.add_nuclide("Ni64", 0.000708189552, 'wo')
|
||||
bot_nozzle.add_nuclide("Mn55", 0.0156126, 'wo')
|
||||
bot_nozzle.add_nuclide("Si28", 0.007171335558, 'wo')
|
||||
bot_nozzle.add_nuclide("Si29", 0.000377356542, 'wo')
|
||||
bot_nozzle.add_nuclide("Si30", 0.0002576079, 'wo')
|
||||
bot_nozzle.add_nuclide("Cr50", 0.006190885148, 'wo')
|
||||
bot_nozzle.add_nuclide("Cr52", 0.124142524198, 'wo')
|
||||
bot_nozzle.add_nuclide("Cr53", 0.014348496148, 'wo')
|
||||
bot_nozzle.add_nuclide("Cr54", 0.003638294506, 'wo')
|
||||
bot_nozzle.add_s_alpha_beta('c_H_in_H2O')
|
||||
|
||||
top_nozzle = openmc.Material(name='Top nozzle region', material_id=10)
|
||||
|
|
@ -229,18 +144,8 @@ class InputSet(object):
|
|||
top_nozzle.add_nuclide("Fe57", 0.0101152584, 'wo')
|
||||
top_nozzle.add_nuclide("Fe58", 0.00137211607, 'wo')
|
||||
top_nozzle.add_nuclide("Ni58", 0.04104621835, 'wo')
|
||||
top_nozzle.add_nuclide("Ni60", 0.0163554502, 'wo')
|
||||
top_nozzle.add_nuclide("Ni61", 0.000722605975, 'wo')
|
||||
top_nozzle.add_nuclide("Ni62", 0.002342513875, 'wo')
|
||||
top_nozzle.add_nuclide("Ni64", 0.0006157116, 'wo')
|
||||
top_nozzle.add_nuclide("Mn55", 0.0135739, 'wo')
|
||||
top_nozzle.add_nuclide("Si28", 0.006234853554, 'wo')
|
||||
top_nozzle.add_nuclide("Si29", 0.000328078746, 'wo')
|
||||
top_nozzle.add_nuclide("Si30", 0.0002239677, 'wo')
|
||||
top_nozzle.add_nuclide("Cr50", 0.005382452306, 'wo')
|
||||
top_nozzle.add_nuclide("Cr52", 0.107931450781, 'wo')
|
||||
top_nozzle.add_nuclide("Cr53", 0.012474806806, 'wo')
|
||||
top_nozzle.add_nuclide("Cr54", 0.003163190107, 'wo')
|
||||
top_nozzle.add_s_alpha_beta('c_H_in_H2O')
|
||||
|
||||
top_fa = openmc.Material(name='Top of fuel assemblies', material_id=11)
|
||||
|
|
@ -824,60 +729,59 @@ class AssemblyInputSet(object):
|
|||
|
||||
|
||||
class MGInputSet(InputSet):
|
||||
def build_default_materials_and_geometry(self):
|
||||
def build_default_materials_and_geometry(self, reps=None, as_macro=True):
|
||||
# Define materials needed for 1D/1G slab problem
|
||||
uo2_data = openmc.Macroscopic('uo2_iso')
|
||||
uo2 = openmc.Material(name='UO2', material_id=1)
|
||||
uo2.set_density('macro', 1.0)
|
||||
uo2.add_macroscopic(uo2_data)
|
||||
mat_names = ['uo2', 'clad', 'lwtr']
|
||||
mgxs_reps = ['ang', 'ang_mu', 'iso', 'iso_mu']
|
||||
|
||||
clad_data = openmc.Macroscopic('clad_ang_mu')
|
||||
clad = openmc.Material(name='Clad', material_id=2)
|
||||
clad.set_density('macro', 1.0)
|
||||
clad.add_macroscopic(clad_data)
|
||||
if reps is None:
|
||||
reps = mgxs_reps
|
||||
|
||||
water_data = openmc.Macroscopic('lwtr_iso_mu')
|
||||
water = openmc.Material(name='LWTR', material_id=3)
|
||||
water.set_density('macro', 1.0)
|
||||
water.add_macroscopic(water_data)
|
||||
xs = []
|
||||
mats = []
|
||||
i = 0
|
||||
for mat in mat_names:
|
||||
for rep in reps:
|
||||
i += 1
|
||||
if as_macro:
|
||||
xs.append(openmc.Macroscopic(mat + '_' + rep))
|
||||
mats.append(openmc.Material(name=str(i)))
|
||||
mats[-1].set_density('macro', 1.)
|
||||
mats[-1].add_macroscopic(xs[-1])
|
||||
else:
|
||||
xs.append(openmc.Nuclide(mat + '_' + rep))
|
||||
mats.append(openmc.Material(name=str(i)))
|
||||
mats[-1].set_density('atom/b-cm', 1.)
|
||||
mats[-1].add_nuclide(xs[-1].name, 1.0, 'ao')
|
||||
|
||||
# Define the materials file.
|
||||
self.materials += (uo2, clad, water)
|
||||
# Define the materials file
|
||||
self.xs_data = xs
|
||||
self.materials += mats
|
||||
|
||||
# Define surfaces.
|
||||
|
||||
# Assembly/Problem Boundary
|
||||
left = openmc.XPlane(x0=0.0, surface_id=200,
|
||||
boundary_type='reflective')
|
||||
right = openmc.XPlane(x0=10.0, surface_id=201,
|
||||
boundary_type='reflective')
|
||||
bottom = openmc.YPlane(y0=0.0, surface_id=300,
|
||||
boundary_type='reflective')
|
||||
top = openmc.YPlane(y0=10.0, surface_id=301,
|
||||
boundary_type='reflective')
|
||||
left = openmc.XPlane(x0=0.0, boundary_type='reflective')
|
||||
right = openmc.XPlane(x0=10.0, boundary_type='reflective')
|
||||
bottom = openmc.YPlane(y0=0.0, boundary_type='reflective')
|
||||
top = openmc.YPlane(y0=10.0, boundary_type='reflective')
|
||||
# for each material add a plane
|
||||
planes = [openmc.ZPlane(z0=0.0, boundary_type='reflective')]
|
||||
dz = round(5. / float(len(mats)), 4)
|
||||
for i in range(len(mats) - 1):
|
||||
planes.append(openmc.ZPlane(z0=dz * float(i + 1)))
|
||||
planes.append(openmc.ZPlane(z0=5.0, boundary_type='reflective'))
|
||||
|
||||
down = openmc.ZPlane(z0=0.0, surface_id=0,
|
||||
boundary_type='reflective')
|
||||
fuel_clad_intfc = openmc.ZPlane(z0=2.0, surface_id=1)
|
||||
clad_lwtr_intfc = openmc.ZPlane(z0=2.4, surface_id=2)
|
||||
up = openmc.ZPlane(z0=5.0, surface_id=3,
|
||||
boundary_type='reflective')
|
||||
|
||||
# Define cells
|
||||
c1 = openmc.Cell(cell_id=1)
|
||||
c1.region = +left & -right & +bottom & -top & +down & -fuel_clad_intfc
|
||||
c1.fill = uo2
|
||||
c2 = openmc.Cell(cell_id=2)
|
||||
c2.region = +left & -right & +bottom & -top & +fuel_clad_intfc & -clad_lwtr_intfc
|
||||
c2.fill = clad
|
||||
c3 = openmc.Cell(cell_id=3)
|
||||
c3.region = +left & -right & +bottom & -top & +clad_lwtr_intfc & -up
|
||||
c3.fill = water
|
||||
# Define cells for each material
|
||||
cells = []
|
||||
xy = +left & -right & +bottom & -top
|
||||
for i, mat in enumerate(mats):
|
||||
cells.append(openmc.Cell())
|
||||
cells[-1].region = xy & +planes[i] & -planes[i + 1]
|
||||
cells[-1].fill = mat
|
||||
|
||||
# Define root universe.
|
||||
root = openmc.Universe(universe_id=0, name='root universe')
|
||||
|
||||
root.add_cells((c1, c2, c3))
|
||||
root.add_cells(cells)
|
||||
|
||||
# Assign root universe to geometry
|
||||
self.geometry.root_universe = root
|
||||
|
|
@ -887,9 +791,9 @@ class MGInputSet(InputSet):
|
|||
self.settings.inactive = 5
|
||||
self.settings.particles = 100
|
||||
self.settings.source = Source(space=Box([0.0, 0.0, 0.0],
|
||||
[10.0, 10.0, 2.0]))
|
||||
[10.0, 10.0, 5.]))
|
||||
self.settings.energy_mode = "multi-group"
|
||||
self.settings.cross_sections = "../1d_mgxs.xml"
|
||||
self.settings.cross_sections = "../1d_mgxs.h5"
|
||||
|
||||
def build_defualt_plots(self):
|
||||
plot = openmc.Plot()
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ def cleanup(path):
|
|||
for dirpath, dirnames, filenames in os.walk(path):
|
||||
for fname in filenames:
|
||||
for ext in ['.h5', '.ppm', '.voxel']:
|
||||
if fname.endswith(ext):
|
||||
if fname.endswith(ext) and fname != '1d_mgxs.h5':
|
||||
os.remove(os.path.join(dirpath, fname))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
dfb59bace10a91bb7ffc871d8ee87e91d94754bb8bb002ac6088f80fe0f480741c0489f74b753fc37158d0ff0f1368739ea60638b42083791311eefeac79168e
|
||||
6bcc9cca24d42995bdff9bf9aca5e852c2dbca5cfb42a12ac637def9cf5cac227654182fc9cf9e17d07cf2e9af11fea832e3ae0eb7001cc09856f73d219664f9
|
||||
|
|
@ -1 +1 @@
|
|||
bc8bef8121f9b6470e4fea817a4e48eabb1ecba1f42761a4cbd77d71181bf9e1612df4a3d6ddfbcd08a3086ac873e5f3c3e560bf96b2b7c959a2f7aad7e4e08d
|
||||
a2848fdb0a12c99ce31f4ddee766e0cf33bd5c6feca927bcb4bceca6fbb094bb1309fb8548589a99fcb09a830911457b9175b460aa45773822f8112a34b3b5c1
|
||||
1
tests/test_create_fission_neutrons/inputs_true.dat
Normal file
1
tests/test_create_fission_neutrons/inputs_true.dat
Normal file
|
|
@ -0,0 +1 @@
|
|||
c3581501d1486293c255390251d20584431a198fbb7c07dc2879dc95dc96e26786d3913ce0db8007f542468fd137ff3267824844c03b4687fdad81ea568c92d7
|
||||
3
tests/test_create_fission_neutrons/results_true.dat
Normal file
3
tests/test_create_fission_neutrons/results_true.dat
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
tally 1:
|
||||
sum = 2.056839E+02
|
||||
sum_sq = 4.244628E+03
|
||||
80
tests/test_create_fission_neutrons/test_create_fission_neutrons.py
Executable file
80
tests/test_create_fission_neutrons/test_create_fission_neutrons.py
Executable file
|
|
@ -0,0 +1,80 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.pardir)
|
||||
from testing_harness import PyAPITestHarness
|
||||
import openmc
|
||||
|
||||
|
||||
class CreateFissionNeutronsTestHarness(PyAPITestHarness):
|
||||
def _build_inputs(self):
|
||||
# Material is composed of H-1 and U-235
|
||||
mat = openmc.Material(material_id=1, name='mat')
|
||||
mat.set_density('atom/b-cm', 0.069335)
|
||||
mat.add_nuclide('H1', 40.0)
|
||||
mat.add_nuclide('U235', 1.0)
|
||||
materials_file = openmc.Materials([mat])
|
||||
materials_file.export_to_xml()
|
||||
|
||||
# Cell is box with reflective boundary
|
||||
x1 = openmc.XPlane(surface_id=1, x0=-1)
|
||||
x2 = openmc.XPlane(surface_id=2, x0=1)
|
||||
y1 = openmc.YPlane(surface_id=3, y0=-1)
|
||||
y2 = openmc.YPlane(surface_id=4, y0=1)
|
||||
z1 = openmc.ZPlane(surface_id=5, z0=-1)
|
||||
z2 = openmc.ZPlane(surface_id=6, z0=1)
|
||||
for surface in [x1, x2, y1, y2, z1, z2]:
|
||||
surface.boundary_type = 'reflective'
|
||||
box = openmc.Cell(cell_id=1, name='box')
|
||||
box.region = +x1 & -x2 & +y1 & -y2 & +z1 & -z2
|
||||
box.fill = mat
|
||||
root = openmc.Universe(universe_id=0, name='root universe')
|
||||
root.add_cell(box)
|
||||
geometry = openmc.Geometry(root)
|
||||
geometry.export_to_xml()
|
||||
|
||||
# Set the running parameters
|
||||
settings_file = openmc.Settings()
|
||||
settings_file.run_mode = 'fixed source'
|
||||
settings_file.batches = 10
|
||||
settings_file.particles = 100
|
||||
settings_file.create_fission_neutrons = False
|
||||
bounds = [-1, -1, -1, 1, 1, 1]
|
||||
uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:])
|
||||
watt_dist = openmc.stats.Watt()
|
||||
settings_file.source = openmc.source.Source(space=uniform_dist,
|
||||
energy=watt_dist)
|
||||
settings_file.export_to_xml()
|
||||
|
||||
# Create tallies
|
||||
tallies = openmc.Tallies()
|
||||
tally = openmc.Tally(1)
|
||||
tally.scores = ['flux']
|
||||
tallies.append(tally)
|
||||
tallies.export_to_xml()
|
||||
|
||||
def _get_results(self):
|
||||
"""Digest info in the statepoint and return as a string."""
|
||||
# Read the statepoint file.
|
||||
sp = openmc.StatePoint(self._sp_name)
|
||||
|
||||
# Write out tally data.
|
||||
outstr = ''
|
||||
t = sp.get_tally()
|
||||
outstr += 'tally {0}:\n'.format(t.id)
|
||||
outstr += 'sum = {0:12.6E}\n'.format(t.sum[0, 0, 0])
|
||||
outstr += 'sum_sq = {0:12.6E}\n'.format(t.sum_sq[0, 0, 0])
|
||||
|
||||
return outstr
|
||||
|
||||
def _cleanup(self):
|
||||
super(CreateFissionNeutronsTestHarness, self)._cleanup()
|
||||
f = os.path.join(os.getcwd(), 'tallies.xml')
|
||||
if os.path.exists(f):
|
||||
os.remove(f)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
harness = CreateFissionNeutronsTestHarness('statepoint.10.h5', True)
|
||||
harness.main()
|
||||
1
tests/test_energy_cutoff/inputs_true.dat
Normal file
1
tests/test_energy_cutoff/inputs_true.dat
Normal file
|
|
@ -0,0 +1 @@
|
|||
4dc6a7b131f6757ecc9b06e93d425712f0813c546ed9eaa0aafa4990383b2f3a5b742a5a39ef5f27300d2c861b344e78de2d2c569b9439e7893dc06b03bf3b02
|
||||
3
tests/test_energy_cutoff/results_true.dat
Normal file
3
tests/test_energy_cutoff/results_true.dat
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
tally 1:
|
||||
sum = 0.000000E+00
|
||||
sum_sq = 0.000000E+00
|
||||
84
tests/test_energy_cutoff/test_energy_cutoff.py
Executable file
84
tests/test_energy_cutoff/test_energy_cutoff.py
Executable file
|
|
@ -0,0 +1,84 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.pardir)
|
||||
from testing_harness import PyAPITestHarness
|
||||
import openmc
|
||||
|
||||
|
||||
class EnergyCutoffTestHarness(PyAPITestHarness):
|
||||
def _build_inputs(self):
|
||||
# Set energy cutoff
|
||||
energy_cutoff = 4e-6
|
||||
|
||||
# Material is composed of H-1
|
||||
mat = openmc.Material(material_id=1, name='mat')
|
||||
mat.set_density('atom/b-cm', 0.069335)
|
||||
mat.add_nuclide('H1', 40.0)
|
||||
materials_file = openmc.Materials([mat])
|
||||
materials_file.export_to_xml()
|
||||
|
||||
# Cell is box with reflective boundary
|
||||
x1 = openmc.XPlane(surface_id=1, x0=-1)
|
||||
x2 = openmc.XPlane(surface_id=2, x0=1)
|
||||
y1 = openmc.YPlane(surface_id=3, y0=-1)
|
||||
y2 = openmc.YPlane(surface_id=4, y0=1)
|
||||
z1 = openmc.ZPlane(surface_id=5, z0=-1)
|
||||
z2 = openmc.ZPlane(surface_id=6, z0=1)
|
||||
for surface in [x1, x2, y1, y2, z1, z2]:
|
||||
surface.boundary_type = 'reflective'
|
||||
box = openmc.Cell(cell_id=1, name='box')
|
||||
box.region = +x1 & -x2 & +y1 & -y2 & +z1 & -z2
|
||||
box.fill = mat
|
||||
root = openmc.Universe(universe_id=0, name='root universe')
|
||||
root.add_cell(box)
|
||||
geometry = openmc.Geometry(root)
|
||||
geometry.export_to_xml()
|
||||
|
||||
# Set the running parameters
|
||||
settings_file = openmc.Settings()
|
||||
settings_file.run_mode = 'fixed source'
|
||||
settings_file.batches = 10
|
||||
settings_file.particles = 100
|
||||
settings_file.cutoff = {'energy': energy_cutoff}
|
||||
bounds = [-1, -1, -1, 1, 1, 1]
|
||||
uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:])
|
||||
watt_dist = openmc.stats.Watt()
|
||||
settings_file.source = openmc.source.Source(space=uniform_dist,
|
||||
energy=watt_dist)
|
||||
settings_file.export_to_xml()
|
||||
|
||||
# Tally flux under energy cutoff
|
||||
tallies = openmc.Tallies()
|
||||
tally = openmc.Tally(1)
|
||||
tally.scores = ['flux']
|
||||
energy_filter = openmc.filter.EnergyFilter((0.0, energy_cutoff))
|
||||
tally.filters = [energy_filter]
|
||||
tallies.append(tally)
|
||||
tallies.export_to_xml()
|
||||
|
||||
def _get_results(self):
|
||||
"""Digest info in the statepoint and return as a string."""
|
||||
# Read the statepoint file.
|
||||
sp = openmc.StatePoint(self._sp_name)
|
||||
|
||||
# Write out tally data.
|
||||
outstr = ''
|
||||
t = sp.get_tally()
|
||||
outstr += 'tally {0}:\n'.format(t.id)
|
||||
outstr += 'sum = {0:12.6E}\n'.format(t.sum[0, 0, 0])
|
||||
outstr += 'sum_sq = {0:12.6E}\n'.format(t.sum_sq[0, 0, 0])
|
||||
|
||||
return outstr
|
||||
|
||||
def _cleanup(self):
|
||||
super(EnergyCutoffTestHarness, self)._cleanup()
|
||||
f = os.path.join(os.getcwd(), 'tallies.xml')
|
||||
if os.path.exists(f):
|
||||
os.remove(f)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
harness = EnergyCutoffTestHarness('statepoint.10.h5', True)
|
||||
harness.main()
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue