diff --git a/.gitignore b/.gitignore index 2ca1c7d145..b72a18c84a 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/.travis.yml b/.travis.yml index 46bb847e6a..676bfb42f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 .. diff --git a/data/readme.rst b/data/readme.rst deleted file mode 100644 index 03685491d0..0000000000 --- a/data/readme.rst +++ /dev/null @@ -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 ```` 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 ```` -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 diff --git a/docs/source/io_formats/mgxs_library.rst b/docs/source/io_formats/mgxs_library.rst index b6708a88db..4e5ea21969 100644 --- a/docs/source/io_formats/mgxs_library.rst +++ b/docs/source/io_formats/mgxs_library.rst @@ -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. -```` Element --------------------- +**//** -The ```` element has no attributes and simply provides the number of -energy groups contained within the library. +The data within 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: +**//kTs/** -```` Element ------------------------------ +:Datasets: + - **K** (*double*) -- kT values (in MeV) for each Temperature + TTT (in Kelvin), rounded to the nearest integer -The ```` 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 -```` element should be one more than the number of groups in -the problem. For example, a two-group problem could be specified as: +**//K/** -.. code-block:: xml +Temperature-dependent data, provided for temperature K. - 0.0 0.625E-6 20.0 +: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. +**//K/scatter_data/** -.. _inverse_velocities: - -```` Element --------------------------------- - -The ```` 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: - -```` Element --------------------- - -The ```` 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 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. \ No newline at end of file diff --git a/docs/source/pythonapi/examples/mgxs-part-iv.ipynb b/docs/source/pythonapi/examples/mgxs-part-iv.ipynb index 0101b402dc..74bbfb7d35 100644 --- a/docs/source/pythonapi/examples/mgxs-part-iv.ipynb +++ b/docs/source/pythonapi/examples/mgxs-part-iv.ipynb @@ -8,9 +8,7 @@ "\n", " - Calculation of multi-group cross sections for a fuel assembly\n", " - Automated creation and storage of MGXS with openmc.mgxs.Library\n", - " - Steady-state pin-by-pin fission rates comparison between continuous-energy and multi-group OpenMC.\n", - "\n", - "Note: This Notebook illustrates the use of Pandas DataFrames to containerize multi-group cross section data. We recommend using Pandas >v0.15.0 or later since OpenMC's Python API leverages the multi-indexing feature included in the most recent releases of Pandas.\n" + " - Steady-state pin-by-pin fission rates comparison between continuous-energy and multi-group OpenMC.\n" ] }, { @@ -431,7 +429,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "" ] @@ -577,7 +575,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/smharper/openmc/openmc/mgxs/library.py:373: RuntimeWarning: The P0 correction will be ignored since the scattering order 0 is greater than zero\n", + "/home/nelsonag/git/openmc/openmc/mgxs/library.py:373: RuntimeWarning: The P0 correction will be ignored since the scattering order 0 is greater than zero\n", " warn(msg, RuntimeWarning)\n" ] } @@ -733,9 +731,9 @@ " Copyright | 2011-2016 Massachusetts Institute of Technology\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", " Version | 0.8.0\n", - " Git SHA1 | b02fa21928a37a2254bec13c9802ff8173b6aefd\n", - " Date/Time | 2016-09-29 23:02:46\n", - " MPI Processes | 1\n", + " Git SHA1 | 9d769378838a8404a7e878a65a6bf7f9fb8e083d\n", + " Date/Time | 2016-10-04 19:54:41\n", + " OpenMP Threads | 8\n", "\n", " ===========================================================================\n", " ========================> INITIALIZATION <=========================\n", @@ -745,12 +743,12 @@ " Reading geometry XML file...\n", " Reading cross sections XML file...\n", " Reading materials XML file...\n", - " Reading U235 from /home/smharper/openmc/data/nndc_hdf5/U235.h5\n", - " Reading U238 from /home/smharper/openmc/data/nndc_hdf5/U238.h5\n", - " Reading O16 from /home/smharper/openmc/data/nndc_hdf5/O16.h5\n", - " Reading Zr90 from /home/smharper/openmc/data/nndc_hdf5/Zr90.h5\n", - " Reading H1 from /home/smharper/openmc/data/nndc_hdf5/H1.h5\n", - " Reading B10 from /home/smharper/openmc/data/nndc_hdf5/B10.h5\n", + " Reading U235 from /opt/xsdata/nndc/U235.h5\n", + " Reading U238 from /opt/xsdata/nndc/U238.h5\n", + " Reading O16 from /opt/xsdata/nndc/O16.h5\n", + " Reading Zr90 from /opt/xsdata/nndc/Zr90.h5\n", + " Reading H1 from /opt/xsdata/nndc/H1.h5\n", + " Reading B10 from /opt/xsdata/nndc/B10.h5\n", " Maximum neutron transport energy: 20.0000 MeV for U235\n", " Reading tallies XML file...\n", " Building neighboring cells lists for each surface...\n", @@ -821,20 +819,20 @@ "\n", " =======================> TIMING STATISTICS <=======================\n", "\n", - " Total time for initialization = 2.9400E-01 seconds\n", - " Reading cross sections = 1.7600E-01 seconds\n", - " Total time in simulation = 7.0412E+01 seconds\n", - " Time in transport only = 7.0399E+01 seconds\n", - " Time in inactive batches = 9.6650E+00 seconds\n", - " Time in active batches = 6.0747E+01 seconds\n", - " Time synchronizing fission bank = 5.0000E-03 seconds\n", - " Sampling source sites = 3.0000E-03 seconds\n", - " SEND/RECV source sites = 2.0000E-03 seconds\n", - " Time accumulating tallies = 0.0000E+00 seconds\n", - " Total time for finalization = 0.0000E+00 seconds\n", - " Total time elapsed = 7.0742E+01 seconds\n", - " Calculation Rate (inactive) = 5173.31 neutrons/second\n", - " Calculation Rate (active) = 3292.34 neutrons/second\n", + " Total time for initialization = 2.5432E-01 seconds\n", + " Reading cross sections = 1.4823E-01 seconds\n", + " Total time in simulation = 7.6226E+00 seconds\n", + " Time in transport only = 7.5567E+00 seconds\n", + " Time in inactive batches = 8.4858E-01 seconds\n", + " Time in active batches = 6.7740E+00 seconds\n", + " Time synchronizing fission bank = 4.9022E-03 seconds\n", + " Sampling source sites = 3.4092E-03 seconds\n", + " SEND/RECV source sites = 1.4584E-03 seconds\n", + " Time accumulating tallies = 1.0030E-04 seconds\n", + " Total time for finalization = 3.2380E-06 seconds\n", + " Total time elapsed = 7.8942E+00 seconds\n", + " Calculation Rate (inactive) = 58922.0 neutrons/second\n", + " Calculation Rate (active) = 29524.6 neutrons/second\n", "\n", " ============================> RESULTS <============================\n", "\n", @@ -972,13 +970,26 @@ "metadata": { "collapsed": false }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/nelsonag/git/openmc/openmc/tallies.py:1945: RuntimeWarning: invalid value encountered in true_divide\n", + " self_rel_err = data['self']['std. dev.'] / data['self']['mean']\n", + "/home/nelsonag/git/openmc/openmc/tallies.py:1946: RuntimeWarning: invalid value encountered in true_divide\n", + " other_rel_err = data['other']['std. dev.'] / data['other']['mean']\n", + "/home/nelsonag/git/openmc/openmc/tallies.py:1947: RuntimeWarning: invalid value encountered in true_divide\n", + " new_tally._mean = data['self']['mean'] / data['other']['mean']\n" + ] + } + ], "source": [ "# Create a MGXS File which can then be written to disk\n", "mgxs_file = mgxs_lib.create_mg_library(xs_type='macro', xsdata_names=['fuel', 'zircaloy', 'water'])\n", "\n", - "# Write the file to disk using the default filename of `mgxs.xml`\n", - "mgxs_file.export_to_xml()" + "# Write the file to disk using the default filename of `mgxs.h5`\n", + "mgxs_file.export_to_hdf5()" ] }, { @@ -1050,7 +1061,7 @@ "outputs": [], "source": [ "# Set the location of the cross sections file\n", - "settings_file.cross_sections = './mgxs.xml'\n", + "settings_file.cross_sections = './mgxs.h5'\n", "settings_file.energy_mode = 'multi-group'\n", "\n", "# Export to \"settings.xml\"\n", @@ -1107,9 +1118,9 @@ " Copyright | 2011-2016 Massachusetts Institute of Technology\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", " Version | 0.8.0\n", - " Git SHA1 | b02fa21928a37a2254bec13c9802ff8173b6aefd\n", - " Date/Time | 2016-09-29 23:04:13\n", - " MPI Processes | 1\n", + " Git SHA1 | 9d769378838a8404a7e878a65a6bf7f9fb8e083d\n", + " Date/Time | 2016-10-04 19:54:49\n", + " OpenMP Threads | 8\n", "\n", " ===========================================================================\n", " ========================> INITIALIZATION <=========================\n", @@ -1117,14 +1128,14 @@ "\n", " Reading settings XML file...\n", " Reading geometry XML file...\n", - " Reading cross sections XML file...\n", + " Reading cross sections HDF5 file...\n", " Reading materials XML file...\n", " Reading tallies XML file...\n", - " Building neighboring cells lists for each surface...\n", " Loading Cross Section Data...\n", " Loading fuel Data...\n", " Loading zircaloy Data...\n", " Loading water Data...\n", + " Building neighboring cells lists for each surface...\n", " Initializing source particles...\n", "\n", " ===========================================================================\n", @@ -1133,56 +1144,56 @@ "\n", " Bat./Gen. k Average k \n", " ========= ======== ==================== \n", - " 1/1 0.99122 \n", - " 2/1 1.03963 \n", - " 3/1 1.01551 \n", - " 4/1 1.03582 \n", - " 5/1 0.99023 \n", - " 6/1 1.00419 \n", - " 7/1 1.02047 \n", - " 8/1 1.05456 \n", - " 9/1 1.01063 \n", - " 10/1 1.03370 \n", - " 11/1 1.04616 \n", - " 12/1 1.04458 1.04537 +/- 0.00079\n", - " 13/1 1.02171 1.03748 +/- 0.00790\n", - " 14/1 1.02060 1.03326 +/- 0.00700\n", - " 15/1 1.01653 1.02992 +/- 0.00637\n", - " 16/1 1.02956 1.02986 +/- 0.00520\n", - " 17/1 1.01145 1.02723 +/- 0.00512\n", - " 18/1 1.03774 1.02854 +/- 0.00463\n", - " 19/1 1.00829 1.02629 +/- 0.00466\n", - " 20/1 1.03624 1.02729 +/- 0.00429\n", - " 21/1 1.03296 1.02780 +/- 0.00391\n", - " 22/1 0.99315 1.02491 +/- 0.00459\n", - " 23/1 0.99628 1.02271 +/- 0.00476\n", - " 24/1 1.04034 1.02397 +/- 0.00459\n", - " 25/1 1.02523 1.02406 +/- 0.00427\n", - " 26/1 1.07905 1.02749 +/- 0.00527\n", - " 27/1 1.01678 1.02686 +/- 0.00499\n", - " 28/1 1.01817 1.02638 +/- 0.00473\n", - " 29/1 1.03293 1.02672 +/- 0.00449\n", - " 30/1 1.01224 1.02600 +/- 0.00432\n", - " 31/1 1.01524 1.02549 +/- 0.00414\n", - " 32/1 1.00996 1.02478 +/- 0.00401\n", - " 33/1 1.05545 1.02612 +/- 0.00406\n", - " 34/1 1.02082 1.02589 +/- 0.00389\n", - " 35/1 0.99120 1.02451 +/- 0.00398\n", - " 36/1 1.03012 1.02472 +/- 0.00383\n", - " 37/1 1.01179 1.02424 +/- 0.00372\n", - " 38/1 1.04023 1.02481 +/- 0.00363\n", - " 39/1 1.05876 1.02598 +/- 0.00369\n", - " 40/1 0.99332 1.02490 +/- 0.00373\n", - " 41/1 1.05319 1.02581 +/- 0.00372\n", - " 42/1 1.03381 1.02606 +/- 0.00361\n", - " 43/1 1.00607 1.02545 +/- 0.00355\n", - " 44/1 1.03957 1.02587 +/- 0.00347\n", - " 45/1 1.02472 1.02584 +/- 0.00337\n", - " 46/1 1.00948 1.02538 +/- 0.00331\n", - " 47/1 1.02380 1.02534 +/- 0.00322\n", - " 48/1 1.05392 1.02609 +/- 0.00322\n", - " 49/1 1.01171 1.02572 +/- 0.00316\n", - " 50/1 1.03942 1.02606 +/- 0.00310\n", + " 1/1 0.99100 \n", + " 2/1 1.02112 \n", + " 3/1 1.04240 \n", + " 4/1 1.01591 \n", + " 5/1 1.02044 \n", + " 6/1 1.04127 \n", + " 7/1 1.01783 \n", + " 8/1 1.03856 \n", + " 9/1 1.03637 \n", + " 10/1 1.03884 \n", + " 11/1 1.04466 \n", + " 12/1 1.01060 1.02763 +/- 0.01703\n", + " 13/1 1.02517 1.02681 +/- 0.00987\n", + " 14/1 1.05287 1.03333 +/- 0.00954\n", + " 15/1 1.04369 1.03540 +/- 0.00768\n", + " 16/1 1.01304 1.03167 +/- 0.00729\n", + " 17/1 1.04258 1.03323 +/- 0.00636\n", + " 18/1 1.02301 1.03195 +/- 0.00565\n", + " 19/1 1.03906 1.03274 +/- 0.00505\n", + " 20/1 1.04148 1.03362 +/- 0.00460\n", + " 21/1 1.01271 1.03172 +/- 0.00457\n", + " 22/1 1.02021 1.03076 +/- 0.00428\n", + " 23/1 0.99553 1.02805 +/- 0.00478\n", + " 24/1 1.02434 1.02778 +/- 0.00443\n", + " 25/1 1.02987 1.02792 +/- 0.00413\n", + " 26/1 1.01676 1.02722 +/- 0.00393\n", + " 27/1 1.02738 1.02723 +/- 0.00369\n", + " 28/1 1.04014 1.02795 +/- 0.00355\n", + " 29/1 1.02831 1.02797 +/- 0.00336\n", + " 30/1 1.02643 1.02789 +/- 0.00319\n", + " 31/1 1.03939 1.02844 +/- 0.00308\n", + " 32/1 1.03282 1.02864 +/- 0.00294\n", + " 33/1 1.00098 1.02744 +/- 0.00306\n", + " 34/1 1.01763 1.02703 +/- 0.00296\n", + " 35/1 1.01412 1.02651 +/- 0.00288\n", + " 36/1 1.01564 1.02609 +/- 0.00280\n", + " 37/1 1.02379 1.02601 +/- 0.00270\n", + " 38/1 1.03648 1.02638 +/- 0.00263\n", + " 39/1 1.03237 1.02659 +/- 0.00254\n", + " 40/1 1.03501 1.02687 +/- 0.00247\n", + " 41/1 1.02054 1.02666 +/- 0.00240\n", + " 42/1 1.05751 1.02763 +/- 0.00252\n", + " 43/1 1.00751 1.02702 +/- 0.00251\n", + " 44/1 1.04743 1.02762 +/- 0.00251\n", + " 45/1 1.05212 1.02832 +/- 0.00254\n", + " 46/1 1.01839 1.02804 +/- 0.00248\n", + " 47/1 1.00424 1.02740 +/- 0.00250\n", + " 48/1 1.03117 1.02750 +/- 0.00243\n", + " 49/1 1.00988 1.02705 +/- 0.00241\n", + " 50/1 1.01943 1.02686 +/- 0.00236\n", " Creating state point statepoint.50.h5...\n", "\n", " ===========================================================================\n", @@ -1192,27 +1203,27 @@ "\n", " =======================> TIMING STATISTICS <=======================\n", "\n", - " Total time for initialization = 2.3000E-02 seconds\n", - " Reading cross sections = 2.0000E-03 seconds\n", - " Total time in simulation = 5.2404E+01 seconds\n", - " Time in transport only = 5.2378E+01 seconds\n", - " Time in inactive batches = 6.5320E+00 seconds\n", - " Time in active batches = 4.5872E+01 seconds\n", - " Time synchronizing fission bank = 1.2000E-02 seconds\n", - " Sampling source sites = 6.0000E-03 seconds\n", - " SEND/RECV source sites = 5.0000E-03 seconds\n", - " Time accumulating tallies = 0.0000E+00 seconds\n", - " Total time for finalization = 0.0000E+00 seconds\n", - " Total time elapsed = 5.2467E+01 seconds\n", - " Calculation Rate (inactive) = 7654.62 neutrons/second\n", - " Calculation Rate (active) = 4359.96 neutrons/second\n", + " Total time for initialization = 9.9611E-02 seconds\n", + " Reading cross sections = 2.2051E-02 seconds\n", + " Total time in simulation = 6.3645E+00 seconds\n", + " Time in transport only = 6.3383E+00 seconds\n", + " Time in inactive batches = 6.3592E-01 seconds\n", + " Time in active batches = 5.7285E+00 seconds\n", + " Time synchronizing fission bank = 5.1108E-03 seconds\n", + " Sampling source sites = 3.7109E-03 seconds\n", + " SEND/RECV source sites = 1.3393E-03 seconds\n", + " Time accumulating tallies = 8.0199E-05 seconds\n", + " Total time for finalization = 2.9170E-06 seconds\n", + " Total time elapsed = 6.4828E+00 seconds\n", + " Calculation Rate (inactive) = 78625.7 neutrons/second\n", + " Calculation Rate (active) = 34912.9 neutrons/second\n", "\n", " ============================> RESULTS <============================\n", "\n", - " k-effective (Collision) = 1.02474 +/- 0.00282\n", - " k-effective (Track-length) = 1.02606 +/- 0.00310\n", - " k-effective (Absorption) = 1.02589 +/- 0.00165\n", - " Combined k-effective = 1.02601 +/- 0.00170\n", + " k-effective (Collision) = 1.02515 +/- 0.00252\n", + " k-effective (Track-length) = 1.02686 +/- 0.00236\n", + " k-effective (Absorption) = 1.02678 +/- 0.00178\n", + " Combined k-effective = 1.02710 +/- 0.00176\n", " Leakage Fraction = 0.00000 +/- 0.00000\n", "\n" ] @@ -1294,8 +1305,8 @@ "output_type": "stream", "text": [ "Continuous-Energy keff = 1.024295\n", - "Multi-Group keff = 1.026013\n", - "bias [pcm]: -171.8\n" + "Multi-Group keff = 1.027098\n", + "bias [pcm]: -280.3\n" ] } ], @@ -1392,7 +1403,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 40, @@ -1401,9 +1412,9 @@ }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAgMAAAEPCAYAAADf8cexAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAIABJREFUeJzt3XmYFNXVx/HvAUXcEFHB1x0EY9wwaNwjGlxwN4oLmGhi\nEjWaGNEoolGMRqNGwZjEiEncA4TE3SjgFoxxhXEjisrmAgIqIgLKMnPfP26N9NT0zNQZZrpnqN/n\nefqBqT5d91ZX3epTt5ZrIQREREQkv9qUuwIiIiJSXkoGREREck7JgIiISM4pGRAREck5JQMiIiI5\np2RAREQk55QMiIiI5JySARERkZxTMiAiIpJzq0wyYGb/NrOnyl0PaVnM7BkzG9cM873bzN5p6vlK\naZnZZWZWlTH2+2ZWZWZbNHe9VgVm1if5vvZq4vluncx3QFPON+8alQyYWTczG25mU83sCzP7LNnp\nnm1m7Zu6kgXlft3MhtTRGAOQqVGvKsxsRtIoir0eKXf9mpOZ9a5n2UcUhIbk1dTKsr0V7AirX5Vm\n9omZPWxmu63EfPdO2tY6TVnflWFmpxQsZ9EfFDN7P3n/wUYWU2v7MLPBZnZUltj6WHSymY0zs4/M\nbKmZzTGzsWb2YzNr18g6l11y8FWs7VWa2TYFoc31vPuyPEc/OQgoXN4vzWxy0nYavT7N7GIzO6Ip\n6+q1mvcDZnYYMBr4ErgTmAS0A/YBrgW2A85owjoW2g4YAjwFvJd678BmKrMlC8DLwHWApd6bVfrq\nlMUNwITUtBkF/9+f5tlxfJ/a33kp3QWMBdoCXwPOAp40s11DCJMbMb99gEuBPwMLm6yWTeMLYADw\nbOFEM+sNbErcFzWli4B/AA+kpt8JjAwhLG1oBslB0f3AQcB/gd8Cc4BOQG/gj8BuwI+brtolFYD3\ngQupY98TQnjCzNbM8n25Cg5hanPMN2vxwCLgNOJydwSOJv4ubQX8oJHz/SWxTT+08lVsHFcyYGZb\nASOB6cC3QwhzC97+k5ldAhzWZLUrUgXq2LGHEJY3Y7kt2cwQwshyVwLiDjCE0NQ75oY8E0K4t643\nm2u7CCFUNsd8HSaGEL7qATGz54g7kjOAcxoxv3ImNg15BDjOzM4OIRT2xgwgJoIblqISIY7qlvUH\n6AbiAcrZIYQ/pN4bZmZb08ABjJm1BdqEEJa5K1sanzW072muH+wyJQLVlqWW+yYzewH4npmdF0KY\nV66KrZQQQuYX8CegEtg9Y3xb4BJgCjF7nw5cCbRLxc0AHgT2Bl4gHglMBb5XEHMKsVu2Mvm3+v/7\nJu//G3iyIL53EnMccDExi/0CeBzYukj5txapf415JtM2Av4KzE7m9wpwciqmuux9U9O3TKafXDCt\nC3BbUr8viVn1/cAWGb7f6cCDGeJuBz4HNknm/Tkwl3i0YqlYI/6YTEqWbzZwM9CxjnV2EPBSEnt2\n8l574EbgI2BBUuYmybJfmsTsl/x9VJH6Dkjeq3M7K/iOj2lg2Z8BxqWm/Rz4HzHDnwe8CBxX8H6H\npP4zknUyh3gUvmNBzN3AO6n5rgMMK1iXbwLnFGkTVcBQ4Jjke/4SeB04IMO63Dr5/Nmp6R2S6Q+l\npvcE7gCmJeV8SDz6X78g5gqKt61NUu1vArAY+AT4W+H7Scw2wL2saBvvJXFre/YzqTIrk+9pOXBw\nwXurJ/U4h1Q7wNf+hgCVBX+nv4cqkn0DsTeoigbaJrAZsAx42LGs1XU7N9k+pyTz2KmZ9ju3E/cD\nXZNteyEwE7gkY32fAl5rIKZPUu5enm0E6Etst58mdZwMXF6kDQxIlXcAsRdmUfLZe4FtUjG/Tj67\nFbGnZ34S+2dgjQzLfRcwr8j0ocl2s0tq+qCkTp8Q285LwNFF9gfpbe6WgphNk/U1mxX7ilOK1KHe\n/VpDL+9pgsOBaSGEFzLG/xU4mXha4Tpgd2AwsC1wbEFcAHoQu+b+miz4qcBtZjYhhPAm8DRxB/0z\n4gqt7gp9s2AexVxI/KJ/C6xHXDl3A3umyi8mfS6xPTAe6Ab8nvhjcRxwu5mtF0L4fYZ5pt0LfJ24\nbO8CnYlHDFtQ+1RIMaub2QZFpi8KK47SA/H6kLHA88B5xIZzLnGnM7zgc7cQ19mtwO+IO4ufATub\n2d5hxRFxIK7HEcnnbwHeSt67A+hHbGwvEHdS/6LgOwkh/NvM3gdOonZ37EnAlIzb2bpFln9eSFoH\ntdfhT4g/2COTf9cEdiJum/9Iwv4MHEFcx5OJR577ENfT6wXzDQXztWQZ904+/xpwCDDUzP4vhDAo\nVcf9iNvOTcQd8TnAPWa2RQjhswzLndY1+ffT1PSDgc1Z8UOyA3B6siz7JDGjge7A8cBPiTtIiDsU\nzGwI8RTCiGTZOhN3PLuZ2TdCCAvNbA1gHHE7u4GYQG1G/B47EHdQjTWDuN32J27DAIcm8x2V1CWt\nsaeGvkv8rl4gbtMQD0yq55llvocQv4e/NaL8U4E1iG1qCTCvmfY71fuEMcBzwPnEH+FfmVnbEMJl\nGebRtkjb+zKEULiuC9tIg9uIme1I3B9MJB5ILiH+NtR7EaKZHQw8DLydfG5t4nbx32Qb/aCgPgG4\nh7jvGwTsSvzeZyefbYy62t/ZSVl3E0+nDyC280NCCONCCJVm9l3iAeEzxG2PpG6Y2cbEH/WlxN+I\nT4jb/m1mtnYI4aYkLst+rX6OzHVdYsZyb8b4nZL4m1PTryX+OPcumDY9mVaYQW5IzByvLZh2LAW9\nAUUy1WI9A5OAtgXTf5bMY7tU+cV6BtLz/Hny2RNTmd1/gc9Istuk7Fr1JJWhE5OTKuDcrOshNb/p\n1MwmC4/qLiiIuy2ZdlHq8xOBFwv+3if5/AmpuAOT6Semyq4kdTQLfCOJvS41/dYk/tKCaVcSs+V1\nU+t9KQ0coRSs33RGXUnBkRvwHwp6Bohd6RUNzHsBMLSBmLuAt1PbZhXwi1TcPcQjvC0KtpeqZLkL\n61n9vZ3WQLnVR0WDgQ2IP8zfIh61VwJHpOJrHe0Qk60aPXzEnWKN3oBkejfiUfl5qek7Jsv1i+Tv\nXZJ6HVFf/Z3bd3XPQC/gTGKSskby3t+Bxwu2xXTPQIPtL5lWo2cgmfY5xfcH1fVpqGfg+iRux9T0\n1ZN1Vv3qVKRunxZOT95r0v1OMq16nzAsFfsQcb/bqYFlfIri+51bC2L6ULBfz7KNEA9UKinYJ9TT\nBgYUTHud2LNRuC/ZOZnXnwumVfeC3ZSa5wPArAzb5F3JOqpeh92AC5JyJhSJXyP192rEo/dHU9O/\noKA3oGD67cSDwvVS00cDHwOrF6y3evdrDb08dxN0SP79PGP8ocQMbFhq+vXEruj0tQVvhBC+ukAo\nhPAx8Uizm6OOxdwaap7f/U9SfmPmewgwO4QwqnpCMu8biV3EvZ3z+4L4w7efmXVsRH0gHjH1IR7p\nV78OJGaIacNTf/+Hmt9DP+IO9wkz26D6RbxIcSHxYrxC00MIj6em9SWu9z+lpv+e2uel7ySeUuhX\nMO1E4o4u61HVr6i97LPriZ8PbGFm36gn5jNgjyQrz+oQ4rr8Y2r6UOLy9E1NHxNC+KrnJ4TwMvHo\nOet2+WviaZjZxKPG7sDPQwg1LkAKISyp/r+ZrZGszxeI66JXhnKOJTmSSm0THxJPPVRvE9W9CYc0\n0x1Fo4G1gMOTOx4Op3FH3qVQva9MX4h5KHGdVb9mFPnsP0Ptc85Nvd8plN5e/0A8gj0gw2enU3Pf\ncyDxYK8uWbaR6pjvZCgfADPbDNge+GsI4avfpxDCK8CT1P6tCRTfF3bJuO2ux4p1OAW4mthzfUw6\nMNX+OhIvOHyGDG0v6W38DjFRWS3V/sYB6xMTHsi2X6uX5zTBguTfdTPGV2ejUwonhhDmmNn85P1C\nxbrEPyUu8Mp4v8g8aeR8twSK3Vv+JnHnml6meoUQlprZIOIplDlm9jyxq+vOEMIcADPrQOzyqbY0\nhFDYFfVxCOGpDMV9GUL4JDUt/f32IG6sc6ktEI9CC00vEle93tPvTUkHhhDeMrOXiEeqtyWTBwDP\nhxCmFVuIIiaFEJ7MGAvwG2IX/USLzwkYB/wthPB8Qcz5xJ6MD8xsAvECtjtDCDPqme+WwAchhC9S\n098seL9QeruE2KCzbpd/Ip5iWpO4Q/4pMemoIdlxXEY8BbBRwVuBuFNrSPdkvsXWRyDZL4R4hffv\niN2ip5jZ08RrSu4u3EE3VgjhYzN7nLh9rE3sav7nys53ZdTTNquXN32b5jOs+JG9gOJd3zOKTGvS\n/U6BKmqv17eTeW6V4fOLMu57gMzbyAhWnCL+LfEar3uJPdJ1nQKpXv63i7z3JvBtM1s91LwQM/17\nU/i78GEDi7IQOIq4DW5G7FXrTDy4q8HMjiTendKTePqnWpYLIDcm/t6eSbxbKK1wn5xlv1avzMlA\nCOFzM5tFPOfoUdcKTKvr6uyVvco5y3zrqmNbYhepV33zqxkYwu+Se6SPJp7fvRwYbGb7hxBeJZ63\nP6XgI/8Gvt2IOmW5+r0N8TzeAIp/7x+l/q618TfCncANZrYJcce6B3HjbxYhhDfM7GvEI8u+xCPf\ns8zskhDClUnMKDMbT8zKDyQmB4PM7KgiPSGNtbLb+9sFSdC/4kEE15nZv5Ptpto9xO7Za4jXMSwi\ndlc/QrbnjLQhtoF0z0a1wiOxgWb2V+KO8iDiUeYgM9sjhFBfb01W1dcs/B+xm7WuJCNz+1tJdbXN\nycT1uAMrrjEhScafBDCz79Uxz5VpU6Va7kZraBsJIXxhZvsQe5wOI253/Yk/bnVtg42xMu1veWES\nlCSpbxIT9H4F0/cH7iOu8zOIvXjLiLeTFl4zV5fq9nkH8ZqDYl6FbPu1hngvIHwY+LGZ7R4avrjr\nXeLC9GDFhWWYWWfi0ee7zrKh+R408SmxTmlbsuLiIYh13rFI3NcL3q+eX/U9qIW2KlZ4CGE68XRK\n9S1HrxLPnZ1M3Inflaprc5lKPMp8trB7y6l6vXel5nfXo474UcSu9P7EbuClxC7hZhNCWJyUMdrM\nVid2w11iZldXn1IKIXxIvLjvJjPbiLhOLiIeqRTzLvCt5P7nwh16ettoLlcAP0z+PRK+6hXYFxgc\nQrimOtDMti3y+bra1lSSnoEGekbiTEKYRLxO58pkp/408Z7syzMvSd3uI3bv7g6cUE+cq/0VkXU/\nU1fbfJT4Y3MSxU/XeTXLfofYTrtRs9fua8m/M7yVzKqhbSTpAXgyeZ2X3LJ+mZntG0J4usgsq5f/\na0Xe2xaYE5rx9swQwsykx+MiM+sVQqhI3jqGmHz3LTxVbWanF5tNkWmzk8+3ydL7mWW/Vh/vEwiv\nJV749JfkR70Gi09HOzv58xFW3KZW6Dzigv/LWTbEL6bYxr6yphLPEX+VHJnZ4cSrsAs9AmxsZicU\nxLUlXpT4OfHcLcSNs5K4Iy50JjWvrl0zucK20PRkXmsAhBAmhxCeLHi93MhlzGI0MUG8NP2GmbU1\nsyzdymOJ6yh9dP8zimzwydHSo8D3iDvPMUXOmTYZM+uUKn8Z8UiuDfHOjLZmtm4q5iNi12F6XRV6\nhHiuNb3cA4nbwqMrWfV6Jd3TfwYOM7Ptk8nVO4B0Ox9I7XVRfQV4um3dk8QOKVZu9fdpZh3MLF3O\npOSz9X1vmYV4lfoZxNMe9T2cJVP7q8ciMuxj6mqbIYT3iaeZDjGzYt274Nv3Nul+J+WnRf5eCjzh\nqF8mWbaRdPtMVPd0Fd2OQrxTYBLwg8K2a2Y9iT01D69k1bO4kXjnw4UF06ovbv6qZ8bMuhHvnkir\ntc0lP+D3Aceb2dfTHzCzDQv+X+9+LcsCuHoGQgjTLD4PehTwppkVPoFwL+LtLrclsa+Z2R3AaWa2\nPnGD3Z14tHtvCGF8sTIa8ArxCx6UXIyxBHgiudhwZfyF2L0z1sxGE69W/S61z3PfQrwt63Yz25UV\nt/jsSbx4axFACGGBmf0DODvpvp1K7L7ZKDW/bYgX640G3iB2xx5DPA+U9YhiUzM7qcj0hSGE9C17\n9QohPG1mw4ELzWxnYtfcsqSe/Yjn+up8wE8yjwozuwc4J9lYnyde4FTdM1Bsp3Qn8fxvID6Jqzk9\naWbvEW+nmkO88OhM4IEQwpfJ0fT0ZP29TmykBxEv1Dm7jnlCbLRPA9eYWXdW3Fp4GPDb5Aeiud1A\nrOMg4pXj883sWeJppzWJz7DoS7xtNd0dOjGZ9ptk2ZcB94cQ3rF4a+HlSa/Vg8Rzpt2Ip1F+T9wR\nHkjs2foH8fz26sQu9KXEhKKxatQzhHBXXYEFMVnbX10mAgeY2UDidzY9hPCiq9bxIGgr4EYzO5GY\nvMwl3i2zN/EH4c06P11TU+93qi0B+prZ7cSLSg8lbrNXFrm+qLEK119920j19R+/MrM9iMnzu8Tz\n5mcm/6/xBMqUXxB/9J8zs1uJ12v8jHh7bFP0StUrhPBR8nv3IzPrHkKYQjzgPZv4uzKSeHrrTGJP\n+fapWUwEDjKzc4gHHlNDCBOI15bsC7xoZn8mbjOdiLdDfov4/UAD+7WsC+F+EX8sbyZubF8QL3x6\nGvgJya0OSVwb4s69+qFDM4jdmKun5jctqXSx21eeSE07lbghLaXmQ4dqxLLiNptjUp/fMpmefmDH\nOcSLShYTE5dv1FH+hsTkYQ4rHv7xvSJ134B4pP058RaQPxK79b4qO1mpNxJvNVlA3HCfTde5nvUw\nPZlfsde0grjbiE8LS39+CPH8V3r6D4n3ti5M1u0rwFVAl4bWWfJe4UOHPiM29O7ELPn8IvHVD5CZ\nR+qBVPUse9H1WyTuP8DYgr9PJ57bnZus67eJtzhW357Vjtj9+3Ky7J8RG+oPU/O9C3grNW1t4imP\nD4jb+2Tizrowpm1S7+uL1PU9YHiGtlcJ/KyO9+8k7uSrb2XclPhjPI8VDwv6v2Qeg1OfvYR4YeMy\naj906BhiG1+QvP5HTD66Je93I7aLd4gJ1FzgMYrcBuzYz5yS1KNXA3G1tkUytL+62gAx+X0q2f6/\nul2OjLcWFszHiAc/jyVtYQlxvzEO+FHhts6K/dLAOubVZPudgn3CAmLCMiaJn4XvoUOvNhCTvrWw\nwW2EeCR/HyseEvdesk13LdIG0g8d6kNs7wuJp0zuAXqkYq5IPtshNf2H6W2+jmW6C/ikjve6E9vO\nLan5vkXc10wiHmReQbzYtPCz2xL3S9XbXOE8NiJeWzGDuF+ZSeyBPaUgpt79WpaXJTMSaVZJT0MF\ncFJIPcI06fKcRdyhn1aO+onkiZndBhwbQujQYLDkwiozhLG0HFb8Xt1ziBlvsQuAvkM88rmzOesl\nIiLFuUctFMngAjPbhdiVuJx4LvJgYhf4zOogi0Pu9iSeSqoIITxTjsqKiOSdkgFpDs8SH67yS+KF\nPO8Rz81elYr7CfEOgpdp/NCfItI4OkcsX9E1AyIiIjnX4nsGklu9DmbFlZQi0jjtiVePjw1Nd+tY\nk1ObF2lSmdp9i08GiDuFljogiUhrdBLx0b4tldq8SNOrt92XJRlInsr1C+IDE14l3jP9Uh3hMwA4\n/G7YIPUQpicGQp/0oIjEu3g9BjrjATbxnV65++v9Gg5KGcQ1Rad/MvBaNhh2Qa3pp4Zb3WVc8Vim\nx1Z/5aCDHnTFv1frIY4N68KcotMnDbybHYZ9t9b0E8Pf3WX85D+3+z7wasMhtXhH8binjm1q8kDY\ntvZ2PuAPtxUJrtvCN+fz4Hf/Bs34qNn6ONr9DACOuBs2SD05ua42Dxzy0/tc9Xn0olqDzNVvL/8p\n1dW+lR64sH6jOx5f53tXDZzPRcNqPxjxOfZ0lfFWKPbU3vo9+G7d9Spm3y3HuuKf/rCeQRKv+AVc\ncl3t6S/6hlzY6Gj/c78qg++Gu3kTN3OXwel1bVcDqT3oL8RHM2TXt28lY8b8Ehpo9yVPBpJHal5P\nfBb1i8QlHmtm24TiTxKM3YQbfB02To362H692tPA//DTxgxmvJVvx7BtrzUbDkpZg+2KTm+z3rqs\n0av2e1uGYk/ybMCULKPYrtCpl+9X8eM6hySoW0fWKjp99fXWomOvrrWm9wjpweEy+NC33HXkJ/Xb\n2hm/Xh3b1GodYb3a9e3cy5f1tl/RMEre9e5s90mb37Z2+16jY/E2D3TqVVF0ep06ObcBZ5sHsJ4L\nGg4qsP0G7ep8b9312rB9r9rvf8CGRaLr9knwJ+is4/uuOm5TbADBerxbz8i763aAHYq8P8f389Wu\nl/+RCsuDc4ynzxvzY1LXdtWR4iMd1xoAtl6dOn01LEG97b4czxkYSLzF7M4QwmTis8YXE58sKCKr\nJrV7kRaspMlAMpLSLhQMghHi7QyPg7OvS0RaBbV7kZav1D0DGxKfzZ7udJ3DigEXRGTVonYv0sK1\nhrsJoicGxmsECnXYsjx1KbN1+h9S7iqUxab9c3oQ+X8nuj8yeeSrvD2y5vUdyz5b2lQ1Ko0nBsZr\nBAp12KI8dWkBDu9f/FqaVd6RJzQcs0ryt3v4L+nBHcePz3atS6mTgY+Jz6fvkpreBZhd7yf7DKvz\nwqG8Waf/oeWuQlls1n+vclehPDbp7/7Itv17sm3/njWmLaj4mFt3GdpUtfJoXLtXm68hv8lAY34U\nVwX+dh9Hx967xpTevSsZMaLYKPc1lfQ0QQhhGXE42D7V0ywOvN2H+seqFpFWSu1epOUrx2mCocDt\nZjaRFbcYrQXcXoa6iEhpqN2LtGAlTwZCCKPNbEPgcmI34SvAwSGEj0pdFxEpDbV7kZatLBcQhhBu\nAm4qR9kiUh5q9yItV+u5m+BhYPWMsYc5592Y57E5H3r3zZkT3EVUbLqzK/5dtnKXUbm97wlbf8P3\nCNcdG/G0s18+fb0r/r65DV8ck3Z+v1+54p891H/x4n+vqOcRq0Wc/MjNrviD8D3ydQZV+B9YXUZL\ncbXNRyudd9lM9D1RcP27ZvnmD6zWdrkrvscBH7jLuODxb7viL7Ffu8s4Z5sbXPE7Pf2OK/7H+97o\nigd4/1TfvqVtqGw4KOVfdzofI7+puwi413zxP/A9Gpp22Z7MWY4nEIqIiEgLomRAREQk55QMiIiI\n5JySARERkZxTMiAiIpJzSgZERERyTsmAiIhIzikZEBERyTklAyIiIjmnZEBERCTnlAyIiIjknJIB\nERGRnGs9AxWdF6BrtoFF2uy3yDXr07sMd1fnD/N+4fvAJ87BKABzDqzxJ/udu4zfbDfYFf9c2M8V\nfyJ3uOIBlm/u3Cz3rXKXcfWNvgGajjz77+4yOMoXfu/iY13xX669pi+eWcB/XJ8pq47AhtnD12m7\n0DX7eV/4qnNo20d8HwBWY5nvA4/5t+XT2d8V/1A4wl3GEK52xffc93lX/M1zB7riAayzb/94I6e7\ny3hwzxNc8Wd1v85dxs2r+Za9w+I5rvh2ry2C2xuOU8+AiIhIzikZEBERyTklAyIiIjmnZEBERCTn\nlAyIiIjknJIBERGRnFMyICIiknNKBkRERHJOyYCIiEjOKRkQERHJOSUDIiIiOdd6xia4yMCyPd+/\n6qK1XLPufNX57upYpe8Z4t/s9Iy7jN0Y6orvzMfuMu6z7/g+8LsFrvCRvsftA3BZ10G++Lt94wwA\n3Pmz41zxD9HPXUZ40FevSy+50BX/KIe44ltb5t/hlLms1mtm5viuNt01/xPfHeWKv5ohrniABZVr\n+D4w+qfuMvouzTZmS7Uvvu8b0wJgWtUmrviK53zPz79gr1+54gGOCru64n/215fdZdiPfOMfHMs+\n7jJuvupcV/yCP3ZxxS9dJ1sbam37BxEREWliSgZERERyTsmAiIhIzikZEBERyTklAyIiIjmnZEBE\nRCTnlAyIiIjknJIBERGRnFMyICIiknNKBkRERHJOyYCIiEjOKRkQERHJudYzUNHfA2yXbUCOquAc\nuGbdRtRnuK+Ml77uG0wE4EvfOBzMWHtLdxln242u+At+fq0rfj4dXfEAx9toV/x53/21u4xuNs0V\nf1r4vbuMsy7p7op/nR1d8RXX+AZF6fCRbwCvcjuw7WNs1PbNzPE78ppr/vPbrO+K/3XwD2i2RtvT\nXPEX7PFHdxnBN3YY+HdFdOsz2xW/6FHfceZGzHXFAxz8+VhX/PU/PM9dxpy2vv18l6rvuct4a9Dm\nrvhNlsxyxU967URGZIhTz4CIiEjOKRkQERHJOSUDIiIiOadkQEREJOeUDIiIiOSckgEREZGcUzIg\nIiKSc0oGREREck7JgIiISM4pGRAREck5JQMiIiI513rGJngT+CJbaPtDP3XN+ssL1nNXZ47zmftd\nHvncXUb7tSpd8RPp5y7jO+E+V/yuvO4r4Ff+fPOBIQe54ocy2F3Gu3Rxxc+ls7uMnrzlij+AH7vi\nH5zc3xXPYvPFl9ngW4fRy/H4+dDPt3zWw9e+LuZSVzzAxa8MdcWHnavcZfCir43tzX/9ZTzpq9dI\nfM/oP3+uf0yGCzr7xlWZxjh3GV2dX5WF291l/IZzXfEXj/dtUwMWVkCG0QlK2jNgZkPMrCr1eqOU\ndRCR0lK7F2n5ytEzMAnoA1Sn8cvLUAcRKS21e5EWrBzJwPIQwkdlKFdEykftXqQFK8cFhD3MbKaZ\nTTWzu83MN5iziLRGavciLVipk4Hnge8DBwNnAF2Bp81s7RLXQ0RKR+1epIUr6WmCEELhtcGTzOxF\n4F3geOC2ej88YiCslbqCf48TYQ/nFdUieTBtJEwfWWPS4srPylKVxrb7gY9Ax/Y1p524E/Tv2Ry1\nFFkFPDUS/j2qxqTxlfMzfbSstxaGED4zs7eB7g0GDxgGW/Vq/kqJrAq69Y+vAmstrmDB6F3KVKEV\nsrb7YYdCr01LVCmRVcH+/eOrQO+FFYzot2uDHy3rQ4fMbB1ga+DDctZDREpH7V6k5Sn1cwZ+a2b7\nmtmWZrYXcB/xFqORDXxURFoptXuRlq/Upwk2Iz4KaQPgI+AZYI8QwiclroeIlI7avUgLV+oLCHW1\nn0jOqN2LtHwaqEhERCTnWs9ARZfNBZuZKXSdpb5Z789z7upszA2u+FE7n+ouI0xo64o/ad3gLuNf\nX9vfFR+VdW0nAAATn0lEQVRu99VpypDNXPEAH9lGrvjZYX13GavhW47Tbbi7jDOqfIMb3VLxZ18B\n3gf6+sblKbsrTj2fDXtlfzbRhvjOOlz1jm8b2LDH6a54gDbP+tpk1We+OgH8u/cervh18Q+attFg\nX72O+o3vERJtrvDvu6pO8dWpatdN3GWwja9e/2ZPdxGf4xuYjb7OAccGZItXz4CIiEjOKRkQERHJ\nOSUDIiIiOadkQEREJOeUDIiIiOSckgEREZGcUzIgIiKSc0oGREREck7JgIiISM4pGRAREck5JQMi\nIiI512rGJjh3wl/YvNeGmWLHcrBr3ptmHPOg0LHhHld8eMpdBKNOOsIVf+KMB91l9Fnsq9g/v3+4\nK36E+QesO5vfu+KXWDt3Ge+EbVzxB0z/r7uMmycPdMUfc8i9rvi+Rz3tiud9wLfZltVbtg3v29cy\nxw8MvvFC2jzme+78wH/e7IoHeGZwL1f8RHZxl3H2Fc4xLfq4i4AzfeG/scGu+Bd/v5uvAGA4vrEi\nbuE0dxm/m3KhK/7k3e90l3EED7niL6y61BXfpWIjRoxoOE49AyIiIjmnZEBERCTnlAyIiIjknJIB\nERGRnFMyICIiknNKBkRERHJOyYCIiEjOKRkQERHJOSUDIiIiOadkQEREJOeUDIiIiOSckgEREZGc\nazUDFQ19dzC2TrZBP87d5krXvH8bfumv0JNn++IvNHcRJ550vyv+9a39ud0OP/LV67jhvsGQjmtE\nncL5vjrZ6ZXuMsZzgu8DE/zrj+N89dqRTr75ewcd+tIZX2azKjdltcqumeM7t5nrmn84s8pXoV38\n2/Jmgz9wxe/NBHcZ4SzfQEVvrb+lu4xtbbor/rYls13xP2r3F1c8wPZMccX35xvuMpjpa/fvhR7u\nIsJb57vi19vc990eu+ytTHHqGRAREck5JQMiIiI5p2RAREQk55QMiIiI5JySARERkZxTMiAiIpJz\nSgZERERyTsmAiIhIzikZEBERyTklAyIiIjmnZEBERCTnWs3YBL/Y8ko232bDTLHnzh3qmvc2nU92\n1+fFb9/oim/3/lJ3GZ/je+b4rpU/dpcxhfdd8UePa+uKv+6ds1zxABe8+kdXfNW+vjoB9PnP+q74\nT/u1c5fR8RBfvW5/1DnexajLfPEd5vniy2zBlM6w+qaZ4/u+Ot41/+UH+NbP9Ikbu+IBTme4K/6x\nI/zbsg32xV+292XuMg4Px7nij2rXxxU/dPTFrniAIUet7opv134bdxmHf2e0K/6hq/zr772Lsv2u\nVTuKB1zx3VfP9j2pZ0BERCTnlAyIiIjknJIBERGRnFMyICIiknNKBkRERHJOyYCIiEjOKRkQERHJ\nOSUDIiIiOadkQEREJOeUDIiIiOSckgEREZGcazVjE1z30sXY/F6ZYgd++yrXvHe01931OYZ7XPEn\nhL+7y3jsoyNd8cMbMcbC5sE3NsHy3YMrfps277jiAc7f+Veu+GtPG+Iuo/N833P6X+/kLoJenX3x\n37H7XfH/rLrLFd+mYioTd3V9pLzaGbS3zOFhM9/sB29yqSv+n/TzFQBMm7m1K75t/+XuMnrvNdYV\nfyDj3GWM5WBX/IhBP3TFj7/mm654gPfYwhXf6/033WXss9kzrng7xrd/BHjAjnbFt8W5jVi28RKa\ntGfAzL5lZg+a2UwzqzKzWr9mZna5mc0ys8Vm9piZdW/KOohIaandi7R+TX2aYG3gFeBMoFaKZGaD\ngJ8CpwG7AYuAsWbmHxJORFoKtXuRVq5JTxOEEMYAYwDMrFj/3s+BK0IIDycxJwNzgKMB31iRItIi\nqN2LtH4lu4DQzLoCGwNPVE8LISwAXgD2LFU9RKR01O5FWodS3k2wMbELcU5q+pzkPRFZ9ajdi7QC\nurVQREQk50p5a+FswIAu1DxK6AK83OCnbzqXsM56NaftfyL27f5NV0ORVcS8kY/z6ajHa0yz+YvL\nUZXGt/urB8K6qTZ/WP/4EpFapo98iekjJ9SY9sJn2Y75S5YMhBCmm9lsoA/wGoCZdQB2B/7Y4AzO\nHIr1yPacAZG869T/ADr1P6DGtPicgR+UtB4r1e4vHAbbq82LZNW1/zfp2r/mMxt6VKzBJbs0/NyH\nJk0GzGxtoDvxSACgm5n1BOaFEN4HbgB+aWZTgBnAFcAHwANNWQ8RKR21e5HWr6l7BnYFniJeMBSA\n65PpdwCnhhCuNbO1gOFAR+A/wCEhhKVNXA8RKR21e5FWrqmfMzCeBi5KDCFcBlzWlOWKSPmo3Yu0\nfrqbQEREJOcsBP/ACqVkZr2AiZ0n3Eu7Xttn+sxN/MRVxuE83nBQ2m6+POrKidkHXKl2cWWl7wMX\n+HO7d671je7Sg/dc8fNYyxUPsOaiJb74tZ3fE/AGvgFkvr71DHcZNtVXry8X+9bfK2v3dMVPqWjD\nybu8DLBLCKHC9eESqm7z7D4ROmS/gNDO9u3LKg/z1esDNvJ9ANjy0rmu+MrL/fuJq22gK/6YcK+7\njG141xV/RzjRFX/ykf9wxQPYQ772ZQ/5949Vs3zrw07374vClGwDCVVr28Y3UNGAGRWMOOCb0EC7\nV8+AiIhIzikZEBERyTklAyIiIjmnZEBERCTnlAyIiIjknJIBERGRnFMyICIiknNKBkRERHJOyYCI\niEjOKRkQERHJOSUDIiIiOdfUQxg3mxHWn56WLXe5k1Nc836+6hvu+uzZwRd/8ZONGAPiPt8zqznQ\nX8REsj/7HaD77r46PfxCP1c8wMmTfc8pD9Oc3xOw8XFruOLb/N2//qrG+eo17KBzXPEXXzLUFd9h\nXgVxtOHW4ed/uJrNemUfD+D8s/7gmv+2h73iij+AC13xAPOGrOmK/3M43l3GhR/d7Yq/sfOP3WW8\nHg53xY+zY1zx399utCseoOoSX/u68opz3WVMpZsrflhle3cZ/+g+wBV/oXPwzy7zN2JEhjj1DIiI\niOSckgEREZGcUzIgIiKSc0oGREREck7JgIiISM4pGRAREck5JQMiIiI5p2RAREQk55QMiIiI5JyS\nARERkZxTMiAiIpJzSgZERERyrtUMVPQgRzGRbIOWvBG2c837nKHD3fUJj1f5PvAbf971zGDfAEr9\nuMddxkR2ccXbQ74Bexabb6AWgFG7HOmK7//mg+4y1v/uEld8uNu5voG2rzo/MM4Zv9x88ZXO+DL7\n3ZhB8JZjIK2+vvkfj29ArMu50lcAwJTzXeFTt93aXcRjG+3jih/4ys3uMip/6xsUqO+tY1zx/7um\nqyse4FM6uuIvumqYuwy7qNIVP77tne4yrrSLXfHr8rkrfn/7KFOcegZERERyTsmAiIhIzikZEBER\nyTklAyIiIjmnZEBERCTnlAyIiIjknJIBERGRnFMyICIiknNKBkRERHJOyYCIiEjOKRkQERHJuVYz\nNsFS2rGE9plin7W9XPO+/7yD3fU5+i++Z3VPuHAHdxn7MMEVP/sFf24X+jmfV/++7xn9q4Xv+eYP\nnHDIQ6748Kh/3AAO9X1Xd3Ciu4if99zZFf9U2N8V/1rf3V3xdPCNK1F2l9wCbJI9ftchrtn/+nu+\nsQau/L7/+zvthqGu+D+Fc9xlPGZPuOJ/vNON7jJwjs1xP/1c8ZvxgSseoDfPu+J3uugldxn/+69v\nnV+5j++3B2AHJrni32dzV7yRbRnUMyAiIpJzSgZERERyTsmAiIhIzikZEBERyTklAyIiIjmnZEBE\nRCTnlAyIiIjknJIBERGRnFMyICIiknNKBkRERHJOyYCIiEjOKRkQERHJuVYzUNG9HEM7ts8Uu4Q1\nXPO+xga563PTj37iir+F09xlMN43GJKt5y/CTvINxFE13Venrbr5B+6Y8WhnXxlzfXUCWLKOL35n\nXnGX8YM3Rrni99/uX74CtvaF0w5Y4PxMWfUEemQPv9Y5+wt8g3SFds5BvYDh+/gGHvrb2I/cZSxa\nb7wr/uDK+91lbFTpG0hoh9V+5IqvxN+G21aNccVPGtnXXcZTA/Z0xT+LLx5gcVjTFf/aTb4BynZo\nX5Eprkl7BszsW2b2oJnNNLMqMzsy9f5tyfTC1yNNWQcRKS21e5HWr6lPE6wNvAKcCXWOm/go0AXY\nOHn1b+I6iEhpqd2LtHJNepoghDAGGANgZnX1qS0JIfj7wkSkRVK7F2n9ynEB4X5mNsfMJpvZTWbW\nqQx1EJHSUrsXacFKfQHho8A9wHTi5U+/AR4xsz1DCL4r2USktVC7F2nhSpoMhBBGF/z5PzN7HZgK\n7Ac8Vd9n5w+8ijbrrVtj2lr9D2et/oc3dTVFWr/PR8LCmnczLG4zvyxVaXy7v5l4OUKh/ZOXiNQy\nYSRMqNnux7fN1u7LemthCGG6mX0MdKeBZKDjsIto1yvbrYUiubdu//gqsFa7Cha8uWuZKrRC9nZ/\nBq5bC0Xybtf+8VWgd/sKRvyo4XZf1ocOmdlmwAbAh+Wsh4iUjtq9SMvTpD0DZrY2MduvvqK4m5n1\nBOYlryHEc4ezk7hrgLeBsU1ZDxEpHbV7kdavqU8T7Ers9gvJ6/pk+h3Ee5B3Ak4GOgKziDuDS0MI\ny5q4HiJSOmr3Iq1cUz9nYDz1n3rwPw9SRFo0tXuR1q/VjE0w9/UtYFm2i4l67v68a96H87C7PvfY\nsa744ZzhLmO33i+64o8b7V+Ow6/+hyv+GnzjOMxkU1c8wAXme8j8dZ1/4S7jMi5zxe9sL7vLOGO7\nYa740ZXH+wqY+rgvvsN0X3y59dgd1uqVPf5a512KE3zP9OfY3r54gOdmuMIXjtvKXcQan3zqih9z\n1nfcZTDI14kz/oPNXPE77fWCKx7gtbt8z+g/6OQH3GX0nuGr1/iu+7rLOA7fPviJ/zvCFV+xbAAj\nMsRp1EIREZGcUzIgIiKSc0oGREREck7JgIiISM4pGRAREcm51p0MjBtZ7hqUxTMjZ5W7CmXx6cjH\nyl2Fslgy6v5yV6Hl+DSfbR6AZ/K57J+OHFfuKpTFSyNLe/dPK08GRjUcswp6ZlQ+n+Ka12Rg6d/9\nt0Stsubns80D8Ew+l33+qHy2+wmjlAyIiIhICSkZEBERyTklAyIiIjnXGh5H3B6AGZNrv7NwPkyu\nqDV58epvuQqYxRx3pRbjK2N2I0ZrnRY+Kzp90fxlTKuo/V6YXvu7aMj8Ct95qTdY4oqfYb5HpULd\n323lZ4tYXFH7vXfCQncZC3nHFT/XZrrLqAy+5rW88vWi08Nnn7O8oth7vnVXWfnVhaftXR8svVi/\nL4u0+cr5sLiO7bx4c6nH277wmet6CyCOy+QwbV7d7y2aD9NqL3vVBgt8ZXzUwRcPMGm5L36Ob9tf\n3L7u/Wnl/IVF2z0zVneVsaBiqiseoMK5+mZ96v8t+TJ8UnT6F/OX8l5F7fcqpvnmP3n5V9tUve3e\nQnA+z7vEzGwA8Ldy10NkFXJSCCHL48rLQm1epFnU2+5bQzKwAXAwMAP4sry1EWnV2gNbAWNDqONw\npAVQmxdpUpnafYtPBkRERKR56QJCERGRnFMyICIiknNKBkRERHJOyYCIiEjOKRkQERHJuVaZDJjZ\nWWY23cy+MLPnzeyb5a5TczOzIWZWlXq9Ue56NTUz+5aZPWhmM5NlPLJIzOVmNsvMFpvZY2bWvRx1\nbUoNLbeZ3VZk/T9SrvqWQ97avdp8jZhVrs1Dy2r3rS4ZMLMTgOuBIcA3gFeBsWa2YVkrVhqTgC7A\nxslrn/JWp1msDbwCnAnUuu/VzAYBPwVOA3YDFhHXf7tSVrIZ1LvciUepuf77l6Zq5Zfjdq82v+q2\neWhB7b41PI44bSAwPIRwJ4CZnQEcBpwKXFvOipXA8hDCR+WuRHMKIYwBxgCYmRUJ+TlwRQjh4STm\nZGAOcDQwulT1bGoZlhtgyaq+/uuR13avNr+KtnloWe2+VfUMmNnqwC7AE9XTQnxq0uPAnuWqVwn1\nSLqTpprZ3Wa2ebkrVEpm1pWYGReu/wXAC+Rj/e9nZnPMbLKZ3WRmncpdoVLIebtXm893m4cStftW\nlQwAGwJtodbIQnOIG8yq7Hng+8THtJ4BdAWeNrO1y1mpEtuY2JWWx/X/KHAy8G3gAqA38Eg9RxOr\nkry2e7X5fLd5KGG7b42nCXIphDC24M9JZvYi8C5wPHBbeWolpRJCKOwO/Z+ZvQ5MBfYDnipLpaRZ\nqc1LKdt9a+sZ+BioJF5MUagLMLv01SmfEMJnxDFYV4mrajOaDRha/4QQphPbQx7Wv9o9avOp6bla\n99Was923qmQghLAMmAj0qZ6WdJf0AZ4tV73KwczWAbYGPix3XUolaQizqbn+OwC7k7/1vxmwATlY\n/2r3kdp8lNc2D83b7lvjaYKhwO1mNhF4kXiV8VrA7eWsVHMzs98CDxG7CTcFfgUsB0aWs15NLTkf\n2p14NADQzcx6AvNCCO8DNwC/NLMpxCFurwA+AB4oQ3WbTH3LnbyGAPcQd4zdgWuIR4lja89tlZS7\ndq82v2q3eWhh7T6E0OpexHsyZwBfAM8Bu5a7TiVY5pHEBvAF8B4wAuha7no1w3L2BqqI3cKFr1sL\nYi4DZgGLk0bRvdz1bs7lJo5HPibZIXwJTAP+BGxU7nqX+DvKVbtXm1+123xDy17qdm9JhURERCSn\nWtU1AyIiItL0lAyIiIjknJIBERGRnFMyICIiknNKBkRERHJOyYCIiEjOKRkQERHJOSUDIiIiOadk\nQEREJOeUDIiIiOSckgEREZGc+3+u/WAkCNBx+gAAAABJRU5ErkJggg==\n", + "image/png": "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\nrkJggg==\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -1433,7 +1444,7 @@ "collapsed": true }, "source": [ - "We also see very good agreement between the fission rate distributions, though these should converge closer together with an increasing number of particle histories in both the continuous-energy run to generate the multi-group cross sections, and in the multi-group calculation itself." + "We also see good agreement between the fission rate distributions, though these should converge closer together with an increasing number of particle histories in both the continuous-energy run to generate the multi-group cross sections, and in the multi-group calculation itself." ] }, { diff --git a/docs/source/pythonapi/index.rst b/docs/source/pythonapi/index.rst index d76be2b4b5..7e310857cf 100644 --- a/docs/source/pythonapi/index.rst +++ b/docs/source/pythonapi/index.rst @@ -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/ diff --git a/docs/source/quickinstall.rst b/docs/source/quickinstall.rst index 7faa4978dd..8e970d9587 100644 --- a/docs/source/quickinstall.rst +++ b/docs/source/quickinstall.rst @@ -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 `_ 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 -------------------------------- diff --git a/docs/source/usersguide/input.rst b/docs/source/usersguide/input.rst index 611cb0400d..b275774002 100644 --- a/docs/source/usersguide/input.rst +++ b/docs/source/usersguide/input.rst @@ -121,10 +121,13 @@ multi-group mode. ```` Element -------------------- -The ```` 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 ```` 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: ```` Element @@ -709,6 +717,36 @@ survival biasing, otherwise known as implicit capture or absorption. *Default*: false +.. _tabular_legendre: + +```` Element +--------------------------------- + +The optional ```` 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: ```` Element @@ -872,6 +910,19 @@ displayed. This element takes the following attributes: *Default*: 5 +```` Element +------------------------------------- + +The ```` 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 + + ```` Element ------------------------- diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index 3dab08e9d3..bc5cbfadf3 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -4,6 +4,38 @@ Installation and Configuration ============================== +---------------------------------------- +Installing on Linux/Mac with conda-forge +---------------------------------------- + +`Conda `_ 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 `_ is a community-led conda +channel of installable packages. For instructions on installing conda, please +consult their `documentation +`_. + +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: diff --git a/examples/python/pincell_multigroup/build-xml.py b/examples/python/pincell_multigroup/build-xml.py index de76e59f05..216c565397 100644 --- a/examples/python/pincell_multigroup/build-xml.py +++ b/examples/python/pincell_multigroup/build-xml.py @@ -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 diff --git a/examples/xml/pincell_multigroup/mg_cross_sections.xml b/examples/xml/pincell_multigroup/mg_cross_sections.xml deleted file mode 100644 index 19d319f23e..0000000000 --- a/examples/xml/pincell_multigroup/mg_cross_sections.xml +++ /dev/null @@ -1,383 +0,0 @@ - - - - 7 - - 1E-11 0.0635E-6 10.0E-6 1.0E-4 1.0E-3 0.5 1.0 20.0 - - - - - - UO2 - UO2 - 2.53E-8 - 0 - true - - isotropic - - - - 8.0248E-03 3.7174E-03 2.6769E-02 9.6236E-02 3.0020E-02 1.1126E-01 2.8278E-01 - - - - 2.005998E-02 2.027303E-03 1.570599E-02 4.518301E-02 4.334208E-02 2.020901E-01 5.257105E-01 - - - - 5.8791E-01 4.1176E-01 3.3906E-04 1.1761E-07 0.0000E+00 0.0000E+00 0.0000E+00 - - - 7.21206E-03 8.19301E-04 6.45320E-03 1.85648E-02 1.78084E-02 8.30348E-02 2.16004E-01 - - - - - - 1.0 1.0 1.0 1.0 1.0 1.0 1.0 - - - - - - 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 - - - - - 0.1779492 0.3298048 0.4803882 0.5543674000000001 0.3118013 0.39516779999999996 0.5644058 - - - - - - - MOX1 - MOX1 - 2.53E-8 - 0 - true - - - - 8.4339E-03 3.7577E-03 2.7970E-02 1.0421E-01 1.3994E-01 4.0918E-01 4.0935E-01 - - - - 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 - - - - 7.62704E-03 8.76898E-04 5.69835E-03 2.28872E-02 1.07635E-02 2.32757E-01 2.48968E-01 - - - - - 1.0 1.0 1.0 1.0 1.0 1.0 1.0 - - - - - - 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 - - - - 0.1783583429163 0.3298451031427 0.4815892 0.5623414 0.421721260021 0.6930878 0.6909757999999999 - - - - - - - MOX2 - MOX2 - 2.53E-8 - 0 - true - - - - 0.0090657 0.0042967 0.032881 0.12203 0.18298 0.56846 0.58521 - - - - 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 - - - - 0.00825446 0.00132565 0.00842156 0.032873 0.0159636 0.323794 0.362803 - - - - - 1.0 1.0 1.0 1.0 1.0 1.0 1.0 - - - - - - 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 - - - - 0.1813232156329 0.3343683022017 0.4937851 0.5912156 0.47419809900160004 0.833601 0.8536035 - - - - - - - MOX3 - MOX3 - 2.53E-8 - 0 - true - - - - 9.48620000E-03 4.65560000E-03 3.62400000E-02 1.32720000E-01 2.08400000E-01 6.58700000E-01 6.90170000E-01 - - - - 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 - - - - 8.67209000E-03 1.62426000E-03 1.02716000E-02 3.90447000E-02 1.92576000E-02 3.74888000E-01 4.30599000E-01 - - - - - 1.0 1.0 1.0 1.0 1.0 1.0 1.0 - - - - - - 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 - - - - 1.83044902E-01 3.36704903E-01 5.00506900E-01 6.06174000E-01 5.02754279E-01 9.21027600E-01 9.55231100E-01 - - - - - - - FC - FC - 2.53E-8 - 0 - true - - - - 5.1132E-04 7.5813E-05 3.1643E-04 1.1675E-03 3.3977E-03 9.1886E-03 2.3244E-02 - - - - 1.323401E-08 1.434500E-08 1.128599E-06 1.276299E-05 3.538502E-07 1.740099E-06 5.063302E-06 - - - - 5.8791E-01 4.1176E-01 3.3906E-04 1.1761E-07 0.0000E+00 0.0000E+00 0.0000E+00 - - - - 4.79002E-09 5.82564E-09 4.63719E-07 5.24406E-06 1.45390E-07 7.14972E-07 2.08041E-06 - - - - - 1.0 1.0 1.0 1.0 1.0 1.0 1.0 - - - - - - 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 - - - - 1.26032048E-01 2.93160367E-01 2.84250824E-01 2.81025244E-01 3.34460185E-01 5.65640735E-01 1.17213908E00 - - - - - - - GT - GT - 2.53E-8 - 0 - false - - - - 5.11320000E-04 7.58010000E-05 3.15720000E-04 1.15820000E-03 3.39750000E-03 9.18780000E-03 2.32420000E-02 - - - - - - 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 - - - - 1.26032043E-01 2.93160349E-01 2.84240290E-01 2.80960000E-01 3.34440033E-01 5.65640060E-01 1.17215400E+00 - - - - - - LWTR - LWTR - 2.53E-8 - 0 - false - - - - 6.0105E-04 1.5793E-05 3.3716E-04 1.9406E-03 5.7416E-03 1.5001E-02 3.7239E-02 - - - - - - 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 - - - - 0.15920605 0.41296959299999997 0.59030986 0.5843499999999999 0.7180000000000001 1.2544497000000001 2.650379 - - - - - - - CR - CR - 2.53E-8 - 0 - false - - - - 1.70490000E-03 8.36224000E-03 8.37901000E-02 3.97797000E-01 6.98763000E-01 9.29508000E-01 1.17836000E+00 - - - - - - 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 - - - - 2.16767595E-01 4.80097720E-01 8.86369232E-01 9.70009150E-01 9.10481420E-01 1.13775017E+00 1.84048743E+00 - - - diff --git a/examples/xml/pincell_multigroup/mgxs.h5 b/examples/xml/pincell_multigroup/mgxs.h5 new file mode 100644 index 0000000000..fe93c44bfa Binary files /dev/null and b/examples/xml/pincell_multigroup/mgxs.h5 differ diff --git a/examples/xml/pincell_multigroup/settings.xml b/examples/xml/pincell_multigroup/settings.xml index dfd2fac813..ab716d9e47 100644 --- a/examples/xml/pincell_multigroup/settings.xml +++ b/examples/xml/pincell_multigroup/settings.xml @@ -28,13 +28,12 @@ - true true true false - ./mg_cross_sections.xml + ./mgxs.h5 diff --git a/openmc/arithmetic.py b/openmc/arithmetic.py index 1632520c5f..f549537206 100644 --- a/openmc/arithmetic.py +++ b/openmc/arithmetic.py @@ -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 diff --git a/openmc/cell.py b/openmc/cell.py index 1cfc09f372..f950963d27 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -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): diff --git a/openmc/cmfd.py b/openmc/cmfd.py index 76d8685ff1..51acf4d426 100644 --- a/openmc/cmfd.py +++ b/openmc/cmfd.py @@ -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 diff --git a/openmc/data/__init__.py b/openmc/data/__init__.py index e60878d601..3f42ef90e1 100644 --- a/openmc/data/__init__.py +++ b/openmc/data/__init__.py @@ -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 * diff --git a/openmc/data/ace.py b/openmc/data/ace.py index 831e40fc81..d7ec97edce 100644 --- a/openmc/data/ace.py +++ b/openmc/data/ace.py @@ -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) diff --git a/openmc/data/angle_distribution.py b/openmc/data/angle_distribution.py index 80b6cdbdb1..669951059c 100644 --- a/openmc/data/angle_distribution.py +++ b/openmc/data/angle_distribution.py @@ -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) diff --git a/openmc/data/angle_energy.py b/openmc/data/angle_energy.py index 4a5e391e3f..8bf95152a9 100644 --- a/openmc/data/angle_energy.py +++ b/openmc/data/angle_energy.py @@ -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 ---------- diff --git a/openmc/data/correlated.py b/openmc/data/correlated.py index d6ce8ab470..dac1968ad4 100644 --- a/openmc/data/correlated.py +++ b/openmc/data/correlated.py @@ -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) diff --git a/openmc/data/data.py b/openmc/data/data.py index 574ae541aa..46fcdf36f6 100644 --- a/openmc/data/data.py +++ b/openmc/data/data.py @@ -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]) diff --git a/openmc/data/endf.py b/openmc/data/endf.py new file mode 100644 index 0000000000..0c590be0a8 --- /dev/null +++ b/openmc/data/endf.py @@ -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 diff --git a/openmc/data/endf_utils.py b/openmc/data/endf_utils.py deleted file mode 100644 index 1a77c60a5e..0000000000 --- a/openmc/data/endf_utils.py +++ /dev/null @@ -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} diff --git a/openmc/data/energy_distribution.py b/openmc/data/energy_distribution.py index a160906353..c1762d5bc1 100644 --- a/openmc/data/energy_distribution.py +++ b/openmc/data/energy_distribution.py @@ -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 diff --git a/data/fission_Q_data_endfb71.h5 b/openmc/data/fission_Q_data_endfb71.h5 similarity index 100% rename from data/fission_Q_data_endfb71.h5 rename to openmc/data/fission_Q_data_endfb71.h5 diff --git a/openmc/data/fission_energy.py b/openmc/data/fission_energy.py index 6352915cc6..1746d62c8e 100644 --- a/openmc/data/fission_energy.py +++ b/openmc/data/fission_energy.py @@ -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 diff --git a/openmc/data/function.py b/openmc/data/function.py index 94a2f0911e..ed338f8035 100644 --- a/openmc/data/function.py +++ b/openmc/data/function.py @@ -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 diff --git a/openmc/data/kalbach_mann.py b/openmc/data/kalbach_mann.py index 5aca17ba9f..e84e6a77a0 100644 --- a/openmc/data/kalbach_mann.py +++ b/openmc/data/kalbach_mann.py @@ -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) diff --git a/openmc/data/laboratory.py b/openmc/data/laboratory.py new file mode 100644 index 0000000000..be449b79a0 --- /dev/null +++ b/openmc/data/laboratory.py @@ -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) diff --git a/openmc/data/nbody.py b/openmc/data/nbody.py index a34380dc93..b186c253a5 100644 --- a/openmc/data/nbody.py +++ b/openmc/data/nbody.py @@ -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) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index c638dfd9bd..4ce5608607 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -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 diff --git a/openmc/data/product.py b/openmc/data/product.py index 753888f6df..bcffec0daf 100644 --- a/openmc/data/product.py +++ b/openmc/data/product.py @@ -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 diff --git a/openmc/data/reaction.py b/openmc/data/reaction.py index eb33e1395f..c724474c9f 100644 --- a/openmc/data/reaction.py +++ b/openmc/data/reaction.py @@ -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 diff --git a/openmc/data/reconstruct.pyx b/openmc/data/reconstruct.pyx new file mode 100644 index 0000000000..f63a155b15 --- /dev/null +++ b/openmc/data/reconstruct.pyx @@ -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 = malloc(nJ*sizeof(double)) + for ij in range(nJ): + j = jmin + ij + g[ij] = (2*j + 1)/(4*I + 2) + Dl -= g[ij] + + s = 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) diff --git a/openmc/data/resonance.py b/openmc/data/resonance.py new file mode 100644 index 0000000000..77d522a044 --- /dev/null +++ b/openmc/data/resonance.py @@ -0,0 +1,1063 @@ +from collections import defaultdict, MutableSequence, Iterable +import io + +import numpy as np +from numpy.polynomial import Polynomial +import pandas as pd + +from .endf import get_head_record, get_cont_record, get_tab1_record, get_list_record +try: + from .reconstruct import wave_number, penetration_shift, reconstruct_mlbw, \ + reconstruct_slbw, reconstruct_rm + _reconstruct = True +except ImportError: + _reconstruct = False +import openmc.checkvalue as cv + +class Resonances(object): + """Resolved and unresolved resonance data + + Parameters + ---------- + ranges : list of openmc.data.ResonanceRange + Distinct energy ranges for resonance data + + Attributes + ---------- + ranges : list of openmc.data.ResonanceRange + Distinct energy ranges for resonance data + resolved : openmc.data.ResonanceRange or None + Resolved resonance range + unresolved : openmc.data.Unresolved or None + Unresolved resonance range + + """ + + def __init__(self, ranges): + self.ranges = ranges + + def __iter__(self): + for r in self.ranges: + yield r + + @property + def ranges(self): + return self._ranges + + @property + def resolved(self): + resolved_ranges = [r for r in self.ranges + if not isinstance(r, Unresolved)] + if len(resolved_ranges) > 1: + raise ValueError('More than one resolved range present') + elif len(resolved_ranges) == 0: + return None + else: + return resolved_ranges[0] + + @property + def unresolved(self): + for r in self.ranges: + if isinstance(r, Unresolved): + return r + else: + return None + + @ranges.setter + def ranges(self, ranges): + cv.check_type('resonance ranges', ranges, MutableSequence) + self._ranges = cv.CheckedList(ResonanceRange, 'resonance ranges', + ranges) + + @classmethod + def from_endf(cls, ev): + """Generate resonance data from an ENDF evaluation. + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + ENDF evaluation + + Returns + ------- + openmc.data.Resonances + Resonance data + + """ + file_obj = io.StringIO(ev.section[2, 151]) + + # Determine whether discrete or continuous representation + items = get_head_record(file_obj) + n_isotope = items[4] # Number of isotopes + + ranges = [] + for iso in range(n_isotope): + items = get_cont_record(file_obj) + abundance = items[1] + fission_widths = (items[3] == 1) # fission widths are given? + n_ranges = items[4] # number of resonance energy ranges + + for j in range(n_ranges): + items = get_cont_record(file_obj) + resonance_flag = items[2] # flag for resolved (1)/unresolved (2) + formalism = items[3] # resonance formalism + + if resonance_flag in (0, 1): + # resolved resonance region + erange = _FORMALISMS[formalism].from_endf(ev, file_obj, items) + + elif resonance_flag == 2: + # unresolved resonance region + erange = Unresolved.from_endf(file_obj, items, fission_widths) + + #erange.material = self + ranges.append(erange) + + return cls(ranges) + + +class ResonanceRange(object): + """Resolved resonance range + + Parameters + ---------- + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV + channel : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + scattering : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + + Attributes + ---------- + channel_radius : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + energy_max : float + Maximum energy of the resolved resonance range in eV + energy_min : float + Minimum energy of the resolved resonance range in eV + scattering_radius : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energ + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + + """ + def __init__(self, target_spin, energy_min, energy_max, channel, scattering): + self.target_spin = target_spin + self.energy_min = energy_min + self.energy_max = energy_max + self.channel_radius = channel + self.scattering_radius = scattering + + self._prepared = False + self._parameter_matrix = {} + + @classmethod + def from_endf(cls, ev, file_obj, items): + """Create resonance range from an ENDF evaluation. + + This factory method is only used when LRU=0, indicating that only a + scattering radius appears in MF=2, MT=151. All subclasses of + ResonanceRange override this method with their own. + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + ENDF evaluation + file_obj : file-like object + ENDF file positioned at the second record of a resonance range + subsection in MF=2, MT=151 + items : list + Items from the CONT record at the start of the resonance range + subsection + + Returns + ------- + openmc.data.ResonanceRange + Resonance range data + + """ + energy_min, energy_max = items[0:2] + + # For scattering radius-only, NRO must be zero + assert items[4] == 0 + + # Get energy-independent scattering radius + items = get_cont_record(file_obj) + target_spin = items[0] + ap = Polynomial((items[1],)) + + # Calculate channel radius from ENDF-102 equation D.14 + a = Polynomial((0.123 * (1.008665*ev.target['mass'])**(1./3.) + 0.08,)) + + return cls(target_spin, energy_min, energy_max, {0: a}, {0: ap}) + + def reconstruct(self, energies): + """Evaluate cross section at specified energies. + + Parameters + ---------- + energies : float or Iterable of float + Energies at which the cross section should be evaluated + + Returns + ------- + 3-tuple of float or numpy.ndarray + Elastic, capture, and fission cross sections at the specified + energies + + """ + if not _reconstruct: + raise RuntimeError("Resonance reconstruction not available.") + + # Pre-calculate penetrations and shifts for resonances + if not self._prepared: + self._prepare_resonances() + + if isinstance(energies, Iterable): + elastic = np.zeros_like(energies) + capture = np.zeros_like(energies) + fission = np.zeros_like(energies) + + for i, E in enumerate(energies): + xse, xsg, xsf = self._reconstruct(self, E) + elastic[i] = xse + capture[i] = xsg + fission[i] = xsf + else: + elastic, capture, fission = self._reconstruct(self, energies) + + return {2: elastic, 102: capture, 18: fission} + + +class MultiLevelBreitWigner(ResonanceRange): + """Multi-level Breit-Wigner resolved resonance formalism data. + + Multi-level Breit-Wigner resolved resonance data is identified by LRF=2 in + the ENDF-6 format. + + Parameters + ---------- + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV + channel : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + scattering : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + + Attributes + ---------- + atomic_weight_ratio : float + Atomic weight ratio of the target nuclide given as a function of + l-value. Note that this may be different than the value for the + evaluation as a whole. + channel_radius : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + energy_max : float + Maximum energy of the resolved resonance range in eV + energy_min : float + Minimum energy of the resolved resonance range in eV + parameters : pandas.DataFrame + Energies, spins, and resonances widths for each resonance + q_value : dict + Q-value to be added to incident particle's center-of-mass energy to + determine the channel energy for use in the penetrability factor. The + keys of the dictionary are l-values. + scattering_radius : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + + """ + + def __init__(self, target_spin, energy_min, energy_max, channel, scattering): + super(MultiLevelBreitWigner, self).__init__( + target_spin, energy_min, energy_max, channel, scattering) + self.parameters = None + self.q_value = {} + self.atomic_weight_ratio = None + + # Set resonance reconstruction function + if _reconstruct: + self._reconstruct = reconstruct_mlbw + else: + self._reconstruct = None + + @classmethod + def from_endf(cls, ev, file_obj, items): + """Create MLBW data from an ENDF evaluation. + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + ENDF evaluation + file_obj : file-like object + ENDF file positioned at the second record of a resonance range + subsection in MF=2, MT=151 + items : list + Items from the CONT record at the start of the resonance range + subsection + + Returns + ------- + openmc.data.MultiLevelBreitWigner + Multi-level Breit-Wigner resonance parameters + + """ + + # Read energy-dependent scattering radius if present + energy_min, energy_max = items[0:2] + nro, naps = items[4:6] + if nro != 0: + params, ape = get_tab1_record(file_obj) + + # Other scatter radius parameters + items = get_cont_record(file_obj) + target_spin = items[0] + ap = Polynomial((items[1],)) # energy-independent scattering-radius + NLS = items[4] # number of l-values + + # Read resonance widths, J values, etc + channel_radius = {} + scattering_radius = {} + q_value = {} + records = [] + for l in range(NLS): + items, values = get_list_record(file_obj) + l_value = items[2] + awri = items[0] + q_value[l_value] = items[1] + competitive = items[3] + + # Calculate channel radius from ENDF-102 equation D.14 + a = Polynomial((0.123 * (1.008665*awri)**(1./3.) + 0.08,)) + + # Construct scattering and channel radius + if nro == 0: + scattering_radius[l_value] = ap + if naps == 0: + channel_radius[l_value] = a + elif naps == 1: + channel_radius[l_value] = ap + elif nro == 1: + scattering_radius[l_value] = ape + if naps == 0: + channel_radius[l_value] = a + elif naps == 1: + channel_radius[l_value] = ape + elif naps == 2: + channel_radius[l_value] = ap + + energy = values[0::6] + spin = values[1::6] + gt = np.asarray(values[2::6]) + gn = np.asarray(values[3::6]) + gg = np.asarray(values[4::6]) + gf = np.asarray(values[5::6]) + if competitive > 0: + gx = gt - (gn + gg + gf) + else: + gx = np.zeros_like(gt) + + for i, E in enumerate(energy): + records.append([energy[i], l_value, spin[i], gt[i], gn[i], + gg[i], gf[i], gx[i]]) + + columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', + 'captureWidth', 'fissionWidth', 'competitiveWidth'] + parameters = pd.DataFrame.from_records(records, columns=columns) + + # Create instance of class + mlbw = cls(target_spin, energy_min, energy_max, + channel_radius, scattering_radius) + mlbw.q_value = q_value + mlbw.atomic_weight_ratio = awri + mlbw.parameters = parameters + + return mlbw + + def _prepare_resonances(self): + df = self.parameters.copy() + + # Penetration and shift factors + p = np.zeros(len(df)) + s = np.zeros(len(df)) + + # Penetration and shift factors for competitive reaction + px = np.zeros(len(df)) + sx = np.zeros(len(df)) + + l_values = [] + competitive = [] + + A = self.atomic_weight_ratio + for i, E, l, J, gt, gn, gg, gf, gx in df.itertuples(): + if l not in l_values: + l_values.append(l) + competitive.append(gx > 0) + + # Determine penetration and shift corresponding to resonance energy + k = wave_number(A, E) + rho = k*self.channel_radius[l](E) + rhohat = k*self.scattering_radius[l](E) + p[i], s[i] = penetration_shift(l, rho) + + # Determine penetration at modified energy for competitive reaction + if gx > 0: + Ex = E + self.q[l]*(A + 1)/A + rho = k*self.channel_radius[l](Ex) + rhohat = k*self.scattering_radius[l](Ex) + px[i], sx[i] = penetration_shift(l, rho) + else: + px[i] = sx[i] = 0.0 + + df['p'] = p + df['s'] = s + df['px'] = px + df['sx'] = sx + + self._l_values = np.array(l_values) + self._competitive = np.array(competitive) + for l in l_values: + self._parameter_matrix[l] = df[df.L == l].as_matrix() + + self._prepared = True + + +class SingleLevelBreitWigner(MultiLevelBreitWigner): + """Single-level Breit-Wigner resolved resonance formalism data. + + Single-level Breit-Wigner resolved resonance data is is identified by LRF=1 + in the ENDF-6 format. + + Parameters + ---------- + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV + channel : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + scattering : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + + Attributes + ---------- + atomic_weight_ratio : float + Atomic weight ratio of the target nuclide given as a function of + l-value. Note that this may be different than the value for the + evaluation as a whole. + channel_radius : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + energy_max : float + Maximum energy of the resolved resonance range in eV + energy_min : float + Minimum energy of the resolved resonance range in eV + parameters : pandas.DataFrame + Energies, spins, and resonances widths for each resonance + q_value : dict + Q-value to be added to incident particle's center-of-mass energy to + determine the channel energy for use in the penetrability factor. The + keys of the dictionary are l-values. + scattering_radius : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + + """ + + def __init__(self, target_spin, energy_min, energy_max, channel, scattering): + super(SingleLevelBreitWigner, self).__init__( + target_spin, energy_min, energy_max, channel, scattering) + + # Set resonance reconstruction function + if _reconstruct: + self._reconstruct = reconstruct_slbw + else: + self._reconstruct = None + + +class ReichMoore(ResonanceRange): + """Reich-Moore resolved resonance formalism data. + + Reich-Moore resolved resonance data is identified by LRF=3 in the ENDF-6 + format. + + Parameters + ---------- + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV + channel : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + scattering : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + + Attributes + ---------- + angle_distribution : bool + Indicate whether parameters can be used to compute angular distributions + atomic_weight_ratio : float + Atomic weight ratio of the target nuclide given as a function of + l-value. Note that this may be different than the value for the + evaluation as a whole. + channel_radius : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + energy_max : float + Maximum energy of the resolved resonance range in eV + energy_min : float + Minimum energy of the resolved resonance range in eV + num_l_convergence : int + Number of l-values which must be used to converge the calculation + scattering_radius : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + parameters : pandas.DataFrame + Energies, spins, and resonances widths for each resonance + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + + """ + + def __init__(self, target_spin, energy_min, energy_max, channel, scattering): + super(ReichMoore, self).__init__( + target_spin, energy_min, energy_max, channel, scattering) + self.parameters = None + self.angle_distribution = False + self.num_l_convergence = 0 + + # Set resonance reconstruction function + if _reconstruct: + self._reconstruct = reconstruct_rm + else: + self._reconstruct = None + + @classmethod + def from_endf(cls, ev, file_obj, items): + """Create Reich-Moore resonance data from an ENDF evaluation. + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + ENDF evaluation + file_obj : file-like object + ENDF file positioned at the second record of a resonance range + subsection in MF=2, MT=151 + items : list + Items from the CONT record at the start of the resonance range + subsection + + Returns + ------- + openmc.data.ReichMoore + Reich-Moore resonance parameters + + """ + # Read energy-dependent scattering radius if present + energy_min, energy_max = items[0:2] + nro, naps = items[4:6] + if nro != 0: + params, ape = get_tab1_record(file_obj) + + # Other scatter radius parameters + items = get_cont_record(file_obj) + target_spin = items[0] + ap = Polynomial((items[1],)) + angle_distribution = (items[3] == 1) # Flag for angular distribution + NLS = items[4] # Number of l-values + num_l_convergence = items[5] # Number of l-values for convergence + + # Read resonance widths, J values, etc + channel_radius = {} + scattering_radius = {} + records = [] + for i in range(NLS): + items, values = get_list_record(file_obj) + apl = Polynomial((items[1],)) if items[1] != 0.0 else ap + l_value = items[2] + awri = items[0] + + # Calculate channel radius from ENDF-102 equation D.14 + a = Polynomial((0.123 * (1.008665*awri)**(1./3.) + 0.08,)) + + # Construct scattering and channel radius + if nro == 0: + scattering_radius[l_value] = apl + if naps == 0: + channel_radius[l_value] = a + elif naps == 1: + channel_radius[l_value] = apl + elif nro == 1: + if naps == 0: + channel_radius[l_value] = a + scattering_radius[l_value] = ape + elif naps == 1: + channel_radius[l_value] = scattering_radius[l_value] = ape + elif naps == 2: + channel_radius[l_value] = apl + scattering_radius[l_value] = ape + + energy = values[0::6] + spin = values[1::6] + gn = values[2::6] + gg = values[3::6] + gfa = values[4::6] + gfb = values[5::6] + + for i, E in enumerate(energy): + records.append([energy[i], l_value, spin[i], gn[i], gg[i], + gfa[i], gfb[i]]) + + # Create pandas DataFrame with resonance data + columns = ['energy', 'L', 'J', 'neutronWidth', 'captureWidth', + 'fissionWidthA', 'fissionWidthB'] + parameters = pd.DataFrame.from_records(records, columns=columns) + + # Create instance of ReichMoore + rm = cls(target_spin, energy_min, energy_max, + channel_radius, scattering_radius) + rm.parameters = parameters + rm.angle_distribution = angle_distribution + rm.num_l_convergence = num_l_convergence + rm.atomic_weight_ratio = awri + + return rm + + def _prepare_resonances(self): + df = self.parameters.copy() + + # Penetration and shift factors + p = np.zeros(len(df)) + s = np.zeros(len(df)) + + l_values = [] + lj_values = [] + + A = self.atomic_weight_ratio + for i, E, l, J, gn, gg, gfa, gfb in df.itertuples(): + if l not in l_values: + l_values.append(l) + if (l, abs(J)) not in lj_values: + lj_values.append((l, abs(J))) + + # Determine penetration and shift corresponding to resonance energy + k = wave_number(A, E) + rho = k*self.channel_radius[l](E) + rhohat = k*self.scattering_radius[l](E) + p[i], s[i] = penetration_shift(l, rho) + + df['p'] = p + df['s'] = s + + self._l_values = np.array(l_values) + for (l, J) in lj_values: + self._parameter_matrix[l, J] = df[(df.L == l) & + (abs(df.J) == J)].as_matrix() + + self._prepared = True + + +class RMatrixLimited(ResonanceRange): + """R-matrix limited resolved resonance formalism data. + + R-matrix limited resolved resonance data is identified by LRF=7 in the + ENDF-6 format. + + Parameters + ---------- + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV + particle_pairs : list of dict + List of particle pairs. Each particle pair is represented by a + dictionary that contains the mass, atomic number, spin, and parity of + each particle as well as other characteristics. + spin_groups : list of dict + List of spin groups. Each spin group is characterized by channels, + resonance energies, and resonance widths. + + Attributes + ---------- + reduced_width : bool + Flag indicating whether channel widths in eV or reduced-width amplitudes + in eV^1/2 are given + formalism : int + Flag to specify which formulae for the R-matrix are to be used + particle_pairs : list of dict + List of particle pairs. Each particle pair is represented by a + dictionary that contains the mass, atomic number, spin, and parity of + each particle as well as other characteristics. + spin_groups : list of dict + List of spin groups. Each spin group is characterized by channels, + resonance energies, and resonance widths. + + """ + + def __init__(self, energy_min, energy_max, particle_pairs, spin_groups): + super(RMatrixLimited, self).__init__(0.0, energy_min, energy_max, + None, None) + self.reduced_width = False + self.formalism = 3 + self.particle_pairs = particle_pairs + self.spin_groups = spin_groups + + @classmethod + def from_endf(cls, ev, file_obj, items): + """Read R-Matrix limited resonance data from an ENDF evaluation. + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + ENDF evaluation + file_obj : file-like object + ENDF file positioned at the second record of a resonance range + subsection in MF=2, MT=151 + items : list + Items from the CONT record at the start of the resonance range + subsection + + Returns + ------- + openmc.data.RMatrixLimited + R-matrix limited resonance parameters + + """ + energy_min, energy_max = items[0:2] + + items = get_cont_record(file_obj) + reduced_width = (items[2] == 1) # reduced width amplitude? + formalism = items[3] # Specify which formulae are used + n_spin_groups = items[4] # Number of Jpi values (NJS) + + particle_pairs = [] + spin_groups = [] + + items, values = get_list_record(file_obj) + n_pairs = items[5]//2 # Number of particle pairs (NPP) + for i in range(n_pairs): + first = {'mass': values[12*i], + 'z': int(values[12*i + 2]), + 'spin': values[12*i + 4], + 'parity': values[12*i + 10]} + second = {'mass': values[12*i + 1], + 'z': int(values[12*i + 3]), + 'spin': values[12*i + 5], + 'parity': values[12*i + 11]} + + q_value = values[12*i + 6] + penetrability = values[12*i + 7] + shift = values[12*i + 8] + mt = int(values[12*i + 9]) + + particle_pairs.append(ParticlePair( + first, second, q_value, penetrability, shift, mt)) + + # loop over spin groups + for i in range(n_spin_groups): + items, values = get_list_record(file_obj) + J = items[0] + if J == 0.0: + parity = '+' if items[1] == 1.0 else '-' + else: + parity = '+' if J > 0. else '-' + J = abs(J) + kbk = items[2] + kps = items[3] + n_channels = items[5] + channels = [] + for j in range(n_channels): + channel = {} + channel['particle_pair'] = particle_pairs[ + int(values[6*j]) - 1] + channel['l'] = values[6*j + 1] + channel['spin'] = values[6*j + 2] + channel['boundary'] = values[6*j + 3] + channel['effective_radius'] = values[6*j + 4] + channel['true_radius'] = values[6*j + 5] + channels.append(channel) + + # Read resonance energies and widths + items, values = get_list_record(file_obj) + n_resonances = items[3] + records = [] + m = n_channels//6 + 1 + for j in range(n_resonances): + energy = values[6*m*j] + records.append([energy] + [values[6*m*j + k + 1] + for k in range(n_channels)]) + + # Determine column names + columns = ['energy'] + for channel in channels: + mt = channel['particle_pair'].mt + if mt == 2: + columns.append('neutronWidth') + elif mt == 18: + columns.append('fissionWidth') + elif mt == 102: + columns.append('captureWidth') + else: + columns.append('width (MT={})'.format(mt)) + + # Create Pandas dataframe with resonance parameters + parameters = pd.DataFrame.from_records(records, columns=columns) + + # Construct SpinGroup instance and add to list + sg = SpinGroup(J, parity, channels, parameters) + spin_groups.append(sg) + + # Optional extension (Background R-Matrix) + if kbk > 0: + items, values = get_list_record(file_obj) + lbk = items[4] + if lbk == 1: + params, rbr = get_tab1_record(file_obj) + params, rbi = get_tab1_record(file_obj) + + # Optional extension (Tabulated phase shifts) + if kps > 0: + items, values = get_list_record(file_obj) + lps = items[4] + if lps == 1: + params, psr = get_tab1_record(file_obj) + params, psi = get_tab1_record(file_obj) + + rml = cls(energy_min, energy_max, particle_pairs, spin_groups) + rml.reduced_width = reduced_width + rml.formalism = formalism + + return rml + + +class ParticlePair(object): + def __init__(self, first, second, q_value, penetrability, + shift, mt): + self.first = first + self.second = second + self.q_value = q_value + self.penetrability = penetrability + self.shift = shift + self.mt = mt + + +class SpinGroup(object): + """Resonance spin group + + Attributes + ---------- + spin : float + Total angular momentum (nuclear spin) + parity : {'+', '-'} + Even (+) or odd(-) parity + channels : list of openmc.data.Channel + Available channels + parameters : pandas.DataFrame + Energies/widths for each resonance/channel + + """ + + def __init__(self, spin, parity, channels, parameters): + self.spin = spin + self.parity = parity + self.channels = channels + self.parameters = parameters + + def __repr__(self): + return ''.format(self.spin, self.parity) + + +class Unresolved(ResonanceRange): + """Unresolved resonance parameters as identified by LRU=2 in MF=2. + + Parameters + ---------- + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + energy_min : float + Minimum energy of the unresolved resonance range in eV + energy_max : float + Maximum energy of the unresolved resonance range in eV + scatter : openmc.data.Function1D + Scattering radii as a function of energy + + Attributes + ---------- + add_to_background : bool + If True, file 3 contains partial cross sections to be added to the + average unresolved cross sections calculated from parameters. + energies : Iterable of float + Energies at which parameters are tabulated + energy_max : float + Maximum energy of the unresolved resonance range in eV + energy_min : float + Minimum energy of the unresolved resonance range in eV + parameters : list of pandas.DataFrame + Average resonance parameters at each energy + scattering_radius : openmc.data.Function1D + Scattering radii as a function of energy + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + + """ + + def __init__(self, target_spin, energy_min, energy_max, scatter): + super(Unresolved, self).__init__( + target_spin, energy_min, energy_max, None, scatter) + self.energies = None + self.parameters = None + self.add_to_background = False + + @classmethod + def from_endf(cls, file_obj, items, fission_widths): + """Read unresolved resonance data from an ENDF evaluation. + + Parameters + ---------- + file_obj : file-like object + ENDF file positioned at the second record of a resonance range + subsection in MF=2, MT=151 + items : list + Items from the CONT record at the start of the resonance range + subsection + fission_widths : bool + Whether fission widths are given + + Returns + ------- + openmc.data.Unresolved + Unresolved resonance region parameters + + """ + # Read energy-dependent scattering radius if present + energy_min, energy_max = items[0:2] + nro = items[4] + if nro != 0: + params, scattering_radius = get_tab1_record(file_obj) + + # Get SPI, AP, and LSSF + formalism = items[3] + if not (fission_widths and formalism == 1): + items = get_cont_record(file_obj) + target_spin = items[0] + if nro == 0: + scattering_radius = items[1] + add_to_background = (items[2] == 0) + + if not fission_widths and formalism == 1: + # Case A -- fission widths not given, all parameters are + # energy-independent + NLS = items[4] + columns = ['L', 'J', 'd', 'amun', 'gn', 'gg', 'gf'] + records = [] + for ls in range(NLS): + items, values = get_list_record(file_obj) + l = items[2] + NJS = items[5] + for j in range(NJS): + d, j, amun, gn, gg = values[6*j:6*j + 5] + records.append([l, j, d, amun, gn, gg, 0.0]) + parameters = pd.DataFrame.from_records(records, columns=columns) + energies = None + + elif fission_widths and formalism == 1: + # Case B -- fission widths given, only fission widths are + # energy-dependent + items, energies = get_list_record(file_obj) + target_spin = items[0] + if nro == 0: + scattering_radius = items[1] + add_to_background = (items[2] == 0) + NE, NLS = items[4:6] + l_values = np.zeros(NLS, int) + records = [[] for e in energies] + columns = ['L', 'J', 'd', 'amun', 'gn0', 'gg', 'gf'] + for ls in range(NLS): + items = get_cont_record(file_obj) + l = items[2] + NJS = items[4] + for j in range(NJS): + items, values = get_list_record(file_obj) + muf = items[3] + d = values[0] + j = values[1] + amun = values[2] + gn0 = values[3] + gg = values[4] + gf = values[6:] + for k, gf_i in enumerate(gf): + records[k].append([l, j, d, amun, gn0, gg, gf]) + parameters = [pd.DataFrame(r, columns=columns) for r in records] + + elif formalism == 2: + # Case C -- all parameters are energy-dependent + NLS = items[4] + columns = ['L', 'J', 'E', 'd', 'gx', 'gn0', 'gg', 'gf'] + records = [] + for ls in range(NLS): + items = get_cont_record(file_obj) + l = items[2] + NJS = items[4] + for j in range(NJS): + items, values = get_list_record(file_obj) + ne = items[5] + j = items[0] + amux = values[2] + amun = values[3] + amug = values[4] + amuf = values[5] + for k in range(1, ne + 1): + E = values[6*k] + d = values[6*k + 1] + gx = values[6*k + 2] + gn0 = values[6*k + 3] + gg = values[6*k + 4] + gf = values[6*k + 5] + records.append([l, j, E, d, gx, gn0, gg, gf]) + parameters = pd.DataFrame.from_records(records, columns=columns) + energies = None + + urr = cls(target_spin, energy_min, energy_max, scattering_radius) + urr.parameters = parameters + urr.add_to_background = add_to_background + urr.energies = energies + + return urr + + +_FORMALISMS = {0: ResonanceRange, + 1: SingleLevelBreitWigner, + 2: MultiLevelBreitWigner, + 3: ReichMoore, + 7: RMatrixLimited} + +_RESOLVED = (SingleLevelBreitWigner, MultiLevelBreitWigner, + ReichMoore, RMatrixLimited) diff --git a/openmc/element.py b/openmc/element.py index 1b16806148..e1484198cf 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -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 . 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 diff --git a/openmc/executor.py b/openmc/executor.py index fbd9e5d82a..a20437e1cd 100644 --- a/openmc/executor.py +++ b/openmc/executor.py @@ -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: diff --git a/openmc/filter.py b/openmc/filter.py index d11af96f52..72a7db47ae 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -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 diff --git a/openmc/lattice.py b/openmc/lattice.py index c6a5af4109..95c16841ff 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -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 = '' diff --git a/openmc/macroscopic.py b/openmc/macroscopic.py index a1ca62c9ab..4d35891417 100644 --- a/openmc/macroscopic.py +++ b/openmc/macroscopic.py @@ -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 diff --git a/openmc/material.py b/openmc/material.py index 0639db5629..6f9c4ba15f 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -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) diff --git a/openmc/mesh.py b/openmc/mesh.py index 420dba0661..d626d728a2 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -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]), diff --git a/openmc/mgxs/groups.py b/openmc/mgxs/groups.py index 068977d888..9441a80511 100644 --- a/openmc/mgxs/groups.py +++ b/openmc/mgxs/groups.py @@ -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. diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index 4b68952a67..a8f54d16c0 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -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': diff --git a/openmc/mgxs/mdgxs.py b/openmc/mgxs/mdgxs.py index 2c616b3682..101edec1d2 100644 --- a/openmc/mgxs/mdgxs.py +++ b/openmc/mgxs/mdgxs.py @@ -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) diff --git a/openmc/mgxs/mgxs.py b/openmc/mgxs/mgxs.py index 65802f2ef0..b839e92151 100644 --- a/openmc/mgxs/mgxs.py +++ b/openmc/mgxs/mgxs.py @@ -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) diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 37ad6c1be4..2a8b0f6b76 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -1,82 +1,21 @@ from collections import Iterable from numbers import Real, Integral -from xml.etree import ElementTree as ET import sys +from six import string_types import numpy as np +import h5py import openmc import openmc.mgxs from openmc.checkvalue import check_type, check_value, check_greater_than, \ check_iterable_type -from openmc.clean_xml import sort_xml_elements, clean_xml_indentation -if sys.version_info[0] >= 3: - basestring = str # Supported incoming particle MGXS angular treatment representations _REPRESENTATIONS = ['isotropic', 'angle'] - - -def ndarray_to_string(arr): - """Converts a numpy ndarray in to a join with spaces between entries - similar to ' '.join(map(str,arr)) but applied to all sub-dimensions. - - Parameters - ---------- - arr : numpy.ndarray - Array to combine in to a string - - Returns - ------- - text : str - String representation of array in arr - - """ - - shape = arr.shape - ndim = arr.ndim - tab = ' ' - indent = '\n' + tab + tab - text = indent - - if ndim == 1: - text += tab - for i in range(shape[0]): - text += '{:.7E} '.format(arr[i]) - text += indent - elif ndim == 2: - for i in range(shape[0]): - text += tab - for j in range(shape[1]): - text += '{:.7E} '.format(arr[i, j]) - text += indent - elif ndim == 3: - for i in range(shape[0]): - for j in range(shape[1]): - text += tab - for k in range(shape[2]): - text += '{:.7E} '.format(arr[i, j, k]) - text += indent - elif ndim == 4: - for i in range(shape[0]): - for j in range(shape[1]): - for k in range(shape[2]): - text += tab - for l in range(shape[3]): - text += '{:.7E} '.format(arr[i, j, k, l]) - text += indent - elif ndim == 5: - for i in range(shape[0]): - for j in range(shape[1]): - for k in range(shape[2]): - for l in range(shape[3]): - text += tab - for m in range(shape[4]): - text += '{:.7E} '.format(arr[i, j, k, l, m]) - text += indent - - return text +_SCATTER_TYPES = ['tabular', 'legendre', 'histogram'] +_SCATTER_SHAPES = ["[Order][G][G']"] class XSdata(object): @@ -85,162 +24,140 @@ class XSdata(object): Parameters ---------- - name : str, optional + name : str Name of the mgxs data set. energy_groups : openmc.mgxs.EnergyGroups - Energygroup structure + Energy group structure representation : {'isotropic', 'angle'}, optional Method used in generating the MGXS (isotropic or angle-dependent flux weighting). Defaults to 'isotropic' + temperatures : Iterable of float + Temperatures (in units of Kelvin) of the provided datasets. Defaults + to a single temperature at 294K. Attributes ---------- name : str Unique identifier for the xsdata object - alias : str - Separate unique identifier for the xsdata object - awr : float + aromic_weight_ratio : float Atomic weight ratio of an isotope. That is, the ratio of the mass of the isotope to the mass of a single neutron. - kT : float - Temperature (in units of MeV). + temperatures : numpy.ndarray + Temperatures (in units of Kelvin) of the provided datasets. Defaults + to a single temperature at 294K. energy_groups : openmc.mgxs.EnergyGroups Energy group structure fissionable : bool Whether or not this is a fissionable data set. - scatt_type : {'legendre', 'histogram', or 'tabular'} + scatter_format : {'legendre', 'histogram', or 'tabular'} Angular distribution representation (legendre, histogram, or tabular) + scatter_shapes : {"[Order][G][G']"} + Dimensionality of the scattering and multiplicity matrices order : int 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. - tabular_legendre : dict - Set how to treat the Legendre scattering kernel (tabular or leave in - Legendre polynomial form). Dict contains two keys: 'enable' and - 'num_points'. 'enable' is a boolean and 'num_points' is the - number of points to use, if 'enable' is True. representation : {'isotropic', 'angle'} Method used in generating the MGXS (isotropic or angle-dependent flux weighting). num_azimuthal : int Number of equal width angular bins that the azimuthal angular domain is - subdivided into. This only applies when ``representation`` is "angle". + subdivided into. This only applies when :attr:`XSdata.representation` + is "angle". num_polar : int Number of equal width angular bins that the polar angular domain is - subdivided into. This only applies when ``representation`` is "angle". + subdivided into. This only applies when :attr:`XSdata.representation` + is "angle". use_chi : bool Whether or not a chi vector or nu-fission matrix was used. vector_shape : iterable of int Dimensionality of vector multi-group cross sections (e.g., the total cross section). The return result depends on the value of - ``representation``. + :attr:`XSdata.representation`. matrix_shape : iterable of int Dimensionality of matrix multi-group cross sections (e.g., the fission matrix cross section). The return result depends on the - value of ``representation``. + value of :attr:`XSdata.representation`. pn_matrix_shape : iterable of int Dimensionality of scattering matrix data (e.g., the scattering matrix cross section). The return result depends on the - value of ``representation``. - total : numpy.ndarray - 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. - absorption : numpy.ndarray - 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`` attribute. 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. - scatter : numpy.ndarray + value of :attr:`XSdata.representation`. + total : dict of numpy.ndarray + Group-wise total cross section. + absorption : dict of numpy.ndarray + Group-wise absorption cross section. + scatter_matrix : dict of numpy.ndarray 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. - multiplicity : numpy.ndarray + down-scatter will be above the diagonal of the resultant matrix. + multiplicity_matrix : dict of numpy.ndarray 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 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`` attribute, with the exception of the data - needed to provide the scattering type information. - fission : numpy.ndarray - 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`` attribute. 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. - kappa_fission : numpy.ndarray - 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 in the - ``groups`` attribute. 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. - chi : numpy.ndarray + (n,xn) reactions. + fission : dict of numpy.ndarray + Group-wise fission cross section. + kappa_fission : dict of numpy.ndarray + Group-wise kappa-fission cross section. + chi : dict of numpy.ndarray Group-wise fission spectra ordered by increasing group index (i.e., - fast to thermal). This attribute should be used if making the common + fast to thermal). This attribute 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 + 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 - 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. - nu_fission : numpy.ndarray - 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. + :attr:`XSdata.nu_fission` attribute instead. + nu_fission : dict of numpy.ndarray + Group-wise fission production cross section vector (i.e., if + :attr:`XSdata.chi` is provided), or is the group-wise fission + production matrix. + inverse_velocities : dict of numpy.ndarray + Inverse of velocities, in units of sec/cm. + + Notes + ----- + The parameters containing cross section data have dimensionalities which + depend upon the value of :attr:`XSdata.representation` as well as the + number of Legendre or other angular dimensions as described by + :attr:`XSdata.order`. The :attr:`XSdata.vector_shape`, + :attr:`XSdata.matrix_shape`, and :attr:`XSdata.pn_matrix_shape` properties + are provided to obtain the dimensionality of the data for each temperature. + + The following are cross sections which should use each of these properties: + + vector_shape : + total, absorption, fission, kappa_fission, chi, nu_fission (if chi is + provided), inverse_velocities + matrix_shape : + multiplicity_matrix, nu_fission (if chi is not provided) + pn_matrix_shape : + scatter_matrix """ - def __init__(self, name, energy_groups, representation='isotropic'): + def __init__(self, name, energy_groups, temperatures=[294.], + representation='isotropic'): # Initialize class attributes - self._name = name - self._energy_groups = energy_groups - self._representation = representation - self._alias = None - self._awr = None - self._kT = None + self.name = name + self.energy_groups = energy_groups + self.temperatures = temperatures + self.representation = representation + self._atomic_weight_ratio = None self._fissionable = False - self._scatt_type = 'legendre' + self._scatter_format = 'legendre' + self._scatter_shape = "[Order][G][G']" self._order = None - self._tabular_legendre = None self._num_polar = None self._num_azimuthal = None - self._total = None - self._absorption = None - self._scatter = None - self._multiplicity = None - self._fission = None - self._nu_fission = None - self._kappa_fission = None - self._chi = None self._use_chi = None + self._total = len(temperatures) * [None] + self._absorption = len(temperatures) * [None] + self._scatter_matrix = len(temperatures) * [None] + self._multiplicity_matrix = len(temperatures) * [None] + self._fission = len(temperatures) * [None] + self._nu_fission = len(temperatures) * [None] + self._kappa_fission = len(temperatures) * [None] + self._chi = len(temperatures) * [None] + self._inverse_velocities = len(temperatures) * [None] @property def name(self): @@ -255,29 +172,29 @@ class XSdata(object): return self._representation @property - def alias(self): - return self._alias + def atomic_weight_ratio(self): + return self._atomic_weight_ratio @property - def awr(self): - return self._awr + def fissionable(self): + return self._fissionable @property - def kT(self): - return self._kT + def temperatures(self): + return self._temperatures @property - def scatt_type(self): - return self._scatt_type + def scatter_format(self): + return self._scatter_format + + @property + def scatter_shape(self): + return self._scatter_shape @property def order(self): return self._order - @property - def tabular_legendre(self): - return self._tabular_legendre - @property def num_polar(self): return self._num_polar @@ -299,12 +216,12 @@ class XSdata(object): return self._absorption @property - def scatter(self): - return self._scatter + def scatter_matrix(self): + return self._scatter_matrix @property - def multiplicity(self): - return self._multiplicity + def multiplicity_matrix(self): + return self._multiplicity_matrix @property def fission(self): @@ -324,43 +241,43 @@ class XSdata(object): @property def num_orders(self): - if (self._order is not None) and (self._scatt_type is not None): - if self._scatt_type is 'legendre': + if self._order is not None: + if self._scatter_format in (None, 'legendre'): return self._order + 1 else: return self._order @property def vector_shape(self): - if self.representation is 'isotropic': + if self.representation == 'isotropic': return (self.energy_groups.num_groups,) - elif self.representation is 'angle': + elif self.representation == 'angle': return (self.num_polar, self.num_azimuthal, self.energy_groups.num_groups) @property def matrix_shape(self): - if self.representation is 'isotropic': + if self.representation == 'isotropic': return (self.energy_groups.num_groups, self.energy_groups.num_groups) - elif self.representation is 'angle': + elif self.representation == 'angle': return (self.num_polar, self.num_azimuthal, self.energy_groups.num_groups, self.energy_groups.num_groups) @property def pn_matrix_shape(self): - if self.representation is 'isotropic': + if self.representation == 'isotropic': return (self.num_orders, self.energy_groups.num_groups, self.energy_groups.num_groups) - elif self.representation is 'angle': + elif self.representation == 'angle': return (self.num_polar, self.num_azimuthal, self.num_orders, self.energy_groups.num_groups, self.energy_groups.num_groups) @name.setter def name(self, name): - check_type('name for XSdata', name, basestring) + check_type('name for XSdata', name, string_types) self._name = name @energy_groups.setter @@ -380,34 +297,30 @@ class XSdata(object): check_value('representation', representation, _REPRESENTATIONS) self._representation = representation - @alias.setter - def alias(self, alias): - if alias is not None: - check_type('alias', alias, basestring) - self._alias = alias - else: - self._alias = self._name + @atomic_weight_ratio.setter + def atomic_weight_ratio(self, atomic_weight_ratio): + # Check validity of type and that the atomic_weight_ratio value is > 0 + check_type('atomic_weight_ratio', atomic_weight_ratio, Real) + check_greater_than('atomic_weight_ratio', atomic_weight_ratio, 0.0) + self._atomic_weight_ratio = atomic_weight_ratio - @awr.setter - def awr(self, awr): - # Check validity of type and that the awr value is > 0 - check_type('awr', awr, Real) - check_greater_than('awr', awr, 0.0) - self._awr = awr + @temperatures.setter + def temperatures(self, temperatures): + check_iterable_type('temperatures', temperatures, Real) - @kT.setter - def kT(self, kT): - # Check validity of type and that the kT value is >= 0 - check_type('kT', kT, Real) - check_greater_than('kT', kT, 0.0, equality=True) - self._kT = kT + self._temperatures = np.array(temperatures) - @scatt_type.setter - def scatt_type(self, scatt_type): + @scatter_format.setter + def scatter_format(self, scatter_format): # check to see it is of a valid type and value - check_value('scatt_type', scatt_type, ['legendre', 'histogram', - 'tabular']) - self._scatt_type = scatt_type + check_value('scatter_format', scatter_format, _SCATTER_TYPES) + self._scatter_format = scatter_format + + @scatter_shape.setter + def scatter_shape(self, scatter_shape): + # check to see it is of a valid type and value + check_value('scatter_shape', scatter_shape, _SCATTER_SHAPES) + self._scatter_shape = scatter_shape @order.setter def order(self, order): @@ -416,39 +329,16 @@ class XSdata(object): check_greater_than('order', order, 0, equality=True) self._order = order - @tabular_legendre.setter - def tabular_legendre(self, tabular_legendre): - # Check to make sure this is a dict and it has our keys with the - # right values. - check_type('tabular_legendre', tabular_legendre, dict) - if 'enable' in tabular_legendre: - enable = tabular_legendre['enable'] - check_type('enable', enable, bool) - else: - msg = 'The tabular_legendre dict must include a value keyed by ' \ - '"enable"' - raise ValueError(msg) - if 'num_points' in tabular_legendre: - num_points = tabular_legendre['num_points'] - check_type('num_points', num_points, Integral) - check_greater_than('num_points', num_points, 0) - else: - if not enable: - num_points = 1 - else: - num_points = 33 - self._tabular_legendre = {'enable': enable, 'num_points': num_points} - @num_polar.setter def num_polar(self, num_polar): # Make sure we have positive ints - check_value('num_polar', num_polar, Integral) + check_type('num_polar', num_polar, Integral) check_greater_than('num_polar', num_polar, 0) self._num_polar = num_polar @num_azimuthal.setter def num_azimuthal(self, num_azimuthal): - check_value('num_azimuthal', num_azimuthal, Integral) + check_type('num_azimuthal', num_azimuthal, Integral) check_greater_than('num_azimuthal', num_azimuthal, 0) self._num_azimuthal = num_azimuthal @@ -457,102 +347,261 @@ class XSdata(object): check_type('use_chi', use_chi, bool) self._use_chi = use_chi - @total.setter - def total(self, total): + def add_temperature(self, temperature): + """This method re-sizes the attributes of this XSdata object so that it + can accomodate an additional temperature. Note that the set_* methods + will still need to be executed. + + Parameters + ---------- + temperature : float + Temperature (in units of Kelvin) of the provided dataset. + + """ + check_type('temperature', temperature, Real) + + temp_store = self.temperatures.tolist().append(temperature) + self.temperatures = temp_store + + self._total.append(None) + self._absorption.append(None) + self._scatter_matrix.append(None) + self._multiplicity_matrix.append(None) + self._fission.append(None) + self._nu_fission.append(None) + self._kappa_fission.append(None) + self._chi.append(None) + self._inverse_velocities.append(None) + + def set_total(self, total, temperature=294.): + """This method sets the cross section for this XSdata object at the + provided temperature. + + Parameters + ---------- + total: np.ndarray + Total Cross Section + temperature : float + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). + + See also + -------- + openmc.mgxs_library.set_total_mgxs() + + """ check_type('total', total, Iterable, expected_iter_type=Real) - # Convert to a numpy array so we can easily get the shape for - # checking - nptotal = np.asarray(total) - check_value('total shape', nptotal.shape, [self.vector_shape]) + # Convert to a numpy array so we can easily get the shape for checking + total = np.asarray(total) + check_value('total shape', total.shape, [self.vector_shape]) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - self._total = nptotal + i = np.where(self.temperatures == temperature)[0][0] + self._total[i] = total - @absorption.setter - def absorption(self, absorption): + def set_absorption(self, absorption, temperature=294.): + """This method sets the cross section for this XSdata object at the + provided temperature. + + Parameters + ---------- + absorption: np.ndarray + Absorption Cross Section + temperature : float + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). + + See also + -------- + openmc.mgxs_library.set_absorption_mgxs() + + """ check_type('absorption', absorption, Iterable, expected_iter_type=Real) - # Convert to a numpy array so we can easily get the shape for - # checking - npabsorption = np.asarray(absorption) - check_value('absorption shape', npabsorption.shape, - [self.vector_shape]) + # Convert to a numpy array so we can easily get the shape for checking + absorption = np.asarray(absorption) + check_value('absorption shape', absorption.shape, [self.vector_shape]) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - self._absorption = npabsorption + i = np.where(self.temperatures == temperature)[0][0] + self._absorption[i] = absorption - @fission.setter - def fission(self, fission): + def set_fission(self, fission, temperature=294.): + """This method sets the cross section for this XSdata object at the + provided temperature. + + Parameters + ---------- + fission: np.ndarray + Fission Cross Section + temperature : float + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). + + See also + -------- + openmc.mgxs_library.set_fission_mgxs() + + """ check_type('fission', fission, Iterable, expected_iter_type=Real) - # Convert to a numpy array so we can easily get the shape for - # checking - npfission = np.asarray(fission) - check_value('fission shape', npfission.shape, [self.vector_shape]) + # Convert to a numpy array so we can easily get the shape for checking + fission = np.asarray(fission) + check_value('fission shape', fission.shape, [self.vector_shape]) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - self._fission = npfission + i = np.where(self.temperatures == temperature)[0][0] + self._fission[i] = fission - if np.sum(self._fission) > 0.0: + if np.sum(fission) > 0.0: self._fissionable = True - @kappa_fission.setter - def kappa_fission(self, kappa_fission): + def set_kappa_fission(self, kappa_fission, temperature=294.): + """This method sets the cross section for this XSdata object at the + provided temperature. + + Parameters + ---------- + kappa_fission: np.ndarray + Kappa-Fission Cross Section + temperature : float + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). + + See also + -------- + openmc.mgxs_library.set_kappa_fission_mgxs() + + """ check_type('kappa_fission', kappa_fission, Iterable, expected_iter_type=Real) - # Convert to a numpy array so we can easily get the shape for - # checking - npkappa_fission = np.asarray(kappa_fission) - check_value('kappa fission shape', npkappa_fission.shape, + # Convert to a numpy array so we can easily get the shape for checking + kappa_fission = np.asarray(kappa_fission) + check_value('kappa fission shape', kappa_fission.shape, [self.vector_shape]) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - self._kappa_fission = npkappa_fission + i = np.where(self.temperatures == temperature)[0][0] + self._kappa_fission[i] = kappa_fission - if np.sum(self._kappa_fission) > 0.0: + if np.sum(kappa_fission) > 0.0: self._fissionable = True - @chi.setter - def chi(self, chi): + def set_chi(self, chi, temperature=294.): + """This method sets the cross section for this XSdata object at the + provided temperature. + + Parameters + ---------- + chi: np.ndarray + Fission Spectrum + temperature : float + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). + + See also + -------- + openmc.mgxs_library.set_chi_mgxs() + + """ if self.use_chi is not None: if not self.use_chi: - msg = 'Providing "chi" when "nu-fission" already provided as a' \ - 'matrix' + msg = 'Providing "chi" when "nu-fission" already provided ' \ + 'as a matrix' raise ValueError(msg) check_type('chi', chi, Iterable, expected_iter_type=Real) - # Convert to a numpy array so we can easily get the shape for - # checking - npchi = np.asarray(chi) + # Convert to a numpy array so we can easily get the shape for checking + chi = np.asarray(chi) # Check the shape - if npchi.shape != self.vector_shape: + if chi.shape != self.vector_shape: msg = 'Provided chi iterable does not have the expected shape.' raise ValueError(msg) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - self._chi = npchi + i = np.where(self.temperatures == temperature)[0][0] + self._chi[i] = chi if self.use_chi is not None: self.use_chi = True - @scatter.setter - def scatter(self, scatter): - # Convert to a numpy array so we can easily get the shape for - # checking - npscatter = np.asarray(scatter) - check_iterable_type('scatter', npscatter, Real, - max_depth=len(npscatter.shape)) - check_value('scatter shape', npscatter.shape, [self.pn_matrix_shape]) + def set_scatter_matrix(self, scatter, temperature=294.): + """This method sets the cross section for this XSdata object at the + provided temperature. - self._scatter = npscatter + Parameters + ---------- + scatter: np.ndarray + Scattering Matrix Cross Section + temperature : float + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). - @multiplicity.setter - def multiplicity(self, multiplicity): - # Convert to a numpy array so we can easily get the shape for - # checking - npmultiplicity = np.asarray(multiplicity) - check_iterable_type('multiplicity', npmultiplicity, Real, - max_depth=len(npmultiplicity.shape)) - check_value('multiplicity shape', npmultiplicity.shape, + See also + -------- + openmc.mgxs_library.set_scatter_matrix_mgxs() + + """ + # Convert to a numpy array so we can easily get the shape for checking + scatter = np.asarray(scatter) + check_iterable_type('scatter', scatter, Real, + max_depth=len(scatter.shape)) + check_value('scatter shape', scatter.shape, [self.pn_matrix_shape]) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) + + i = np.where(self.temperatures == temperature)[0][0] + self._scatter_matrix[i] = scatter + + def set_multiplicity_matrix(self, multiplicity, temperature=294.): + """This method sets the cross section for this XSdata object at the + provided temperature. + + Parameters + ---------- + multiplicity: np.ndarray + Multiplicity Matrix Cross Section + temperature : float + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). + + See also + -------- + openmc.mgxs_library.set_multiplicity_matrix_mgxs() + + """ + # Convert to a numpy array so we can easily get the shape for checking + multiplicity = np.asarray(multiplicity) + check_iterable_type('multiplicity', multiplicity, Real, + max_depth=len(multiplicity.shape)) + check_value('multiplicity shape', multiplicity.shape, [self.matrix_shape]) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - self._multiplicity = npmultiplicity + i = np.where(self.temperatures == temperature)[0][0] + self._multiplicity_matrix[i] = multiplicity - @nu_fission.setter - def nu_fission(self, nu_fission): + def set_nu_fission(self, nu_fission, temperature=294.): + """This method sets the cross section for this XSdata object at the + provided temperature. + + Parameters + ---------- + nu_fission: np.ndarray + Nu-fission Cross Section + temperature : float + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). + + See also + -------- + openmc.mgxs_library.set_nu_fission_mgxs() + + """ # The NuFissionXS class does not have the capability to produce # a fission matrix and therefore if this path is pursued, we know # chi must be used. @@ -563,33 +612,63 @@ class XSdata(object): # chi already has been set. If not, we just check that this is OK # and set the use_chi flag accordingly - # Convert to a numpy array so we can easily get the shape for - # checking - npnu_fission = np.asarray(nu_fission) + # Convert to a numpy array so we can easily get the shape for checking + nu_fission = np.asarray(nu_fission) - check_iterable_type('nu_fission', npnu_fission, Real, - max_depth=len(npnu_fission.shape)) + check_iterable_type('nu_fission', nu_fission, Real, + max_depth=len(nu_fission.shape)) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) if self.use_chi is not None: if self.use_chi: - check_value('nu_fission shape', npnu_fission.shape, + check_value('nu_fission shape', nu_fission.shape, [self.vector_shape]) else: - check_value('nu_fission shape', npnu_fission.shape, + check_value('nu_fission shape', nu_fission.shape, [self.matrix_shape]) else: - check_value('nu_fission shape', npnu_fission.shape, + check_value('nu_fission shape', nu_fission.shape, [self.vector_shape, self.matrix_shape]) # Find out if we have a nu-fission matrix or vector # and set a flag to allow other methods to check this later. - self.use_chi = (npnu_fission.shape == self.vector_shape) + if nu_fission.shape == self.vector_shape: + self.use_chi = True + else: + self.use_chi = False - self._nu_fission = npnu_fission - if np.sum(self._nu_fission) > 0.0: + i = np.where(self.temperatures == temperature)[0][0] + self._nu_fission[i] = nu_fission + if np.sum(nu_fission) > 0.0: self._fissionable = True - def set_total_mgxs(self, total, nuclide='total', xs_type='macro', - subdomain='all'): + def set_inverse_velocities(self, inv_vel, temperature=294.): + """This method sets the inverse velocities for this XSdata object at the + provided temperature. + + Parameters + ---------- + inv_vel: np.ndarray + Inverse velocities in units of sec/cm. + temperature : float + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). + + """ + check_type('inverse velocities', inv_vel, Iterable, + expected_iter_type=Real) + # Convert to a numpy array so we can easily get the shape for checking + inv_vel = np.asarray(inv_vel) + check_value('inverse velocities shape', inv_vel.shape, + [self.vector_shape]) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) + + i = np.where(self.temperatures == temperature)[0][0] + self._inverse_velocities[i] = inv_vel + + def set_total_mgxs(self, total, temperature=294., nuclide='total', + xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.TotalXS or openmc.mgxs.TransportXS to be used to set the total cross section for this XSdata object. @@ -599,6 +678,9 @@ class XSdata(object): total: openmc.mgxs.TotalXS or openmc.mgxs.TransportXS MGXS Object containing the total or transport cross section for the domain of interest. + temperature : float + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -621,16 +703,19 @@ class XSdata(object): check_value('energy_groups', total.energy_groups, [self.energy_groups]) check_value('domain_type', total.domain_type, ['universe', 'cell', 'material', 'mesh']) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - if self.representation is 'isotropic': - self._total = total.get_xs(nuclides=nuclide, xs_type=xs_type, - subdomains=subdomain) - elif self.representation is 'angle': + i = np.where(self.temperatures == temperature)[0][0] + if self.representation == 'isotropic': + self._total[i] = total.get_xs(nuclides=nuclide, xs_type=xs_type, + subdomains=subdomain) + elif self.representation == 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) - def set_absorption_mgxs(self, absorption, nuclide='total', - xs_type='macro', subdomain=None): + def set_absorption_mgxs(self, absorption, temperature=294., + nuclide='total', xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.AbsorptionXS to be used to set the absorption cross section for this XSdata object. @@ -639,6 +724,9 @@ class XSdata(object): absorption: openmc.mgxs.AbsorptionXS MGXS Object containing the absorption cross section for the domain of interest. + temperature : float + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -661,17 +749,20 @@ class XSdata(object): [self.energy_groups]) check_value('domain_type', absorption.domain_type, ['universe', 'cell', 'material', 'mesh']) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - if self.representation is 'isotropic': - self._absorption = absorption.get_xs(nuclides=nuclide, - xs_type=xs_type, - subdomains=subdomain) - elif self.representation is 'angle': + i = np.where(self.temperatures == temperature)[0][0] + if self.representation == 'isotropic': + self._absorption[i] = absorption.get_xs(nuclides=nuclide, + xs_type=xs_type, + subdomains=subdomain) + elif self.representation == 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) - def set_fission_mgxs(self, fission, nuclide='total', xs_type='macro', - subdomain=None): + def set_fission_mgxs(self, fission, temperature=294., nuclide='total', + xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.FissionXS to be used to set the fission cross section for this XSdata object. @@ -680,6 +771,9 @@ class XSdata(object): fission: openmc.mgxs.FissionXS MGXS Object containing the fission cross section for the domain of interest. + temperature : float + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -702,17 +796,20 @@ class XSdata(object): [self.energy_groups]) check_value('domain_type', fission.domain_type, ['universe', 'cell', 'material', 'mesh']) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - if self.representation is 'isotropic': - self._fission = fission.get_xs(nuclides=nuclide, - xs_type=xs_type, - subdomains=subdomain) - elif self.representation is 'angle': + i = np.where(self.temperatures == temperature)[0][0] + if self.representation == 'isotropic': + self._fission[i] = fission.get_xs(nuclides=nuclide, + xs_type=xs_type, + subdomains=subdomain) + elif self.representation == 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) - def set_nu_fission_mgxs(self, nu_fission, nuclide='total', - xs_type='macro', subdomain=None): + def set_nu_fission_mgxs(self, nu_fission, temperature=294., + nuclide='total', xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.NuFissionXS to be used to set the nu-fission cross section for this XSdata object. @@ -721,6 +818,9 @@ class XSdata(object): nu_fission: openmc.mgxs.NuFissionXS MGXS Object containing the nu-fission cross section for the domain of interest. + temperature : float + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -744,12 +844,15 @@ class XSdata(object): [self.energy_groups]) check_value('domain_type', nu_fission.domain_type, ['universe', 'cell', 'material', 'mesh']) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - if self.representation is 'isotropic': - self._nu_fission = nu_fission.get_xs(nuclides=nuclide, - xs_type=xs_type, - subdomains=subdomain) - elif self.representation is 'angle': + i = np.where(self.temperatures == temperature)[0][0] + if self.representation == 'isotropic': + self._nu_fission[i] = nu_fission.get_xs(nuclides=nuclide, + xs_type=xs_type, + subdomains=subdomain) + elif self.representation == 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) @@ -761,8 +864,9 @@ class XSdata(object): if np.sum(self._nu_fission) > 0.0: self._fissionable = True - def set_kappa_fission_mgxs(self, k_fission, nuclide='total', - xs_type='macro', subdomain=None): + def set_kappa_fission_mgxs(self, k_fission, temperature=294., + nuclide='total', xs_type='macro', + subdomain=None): """This method allows for an openmc.mgxs.KappaFissionXS to be used to set the kappa-fission cross section for this XSdata object. @@ -772,6 +876,9 @@ class XSdata(object): kappa_fission: openmc.mgxs.KappaFissionXS MGXS Object containing the kappa-fission cross section for the domain of interest. + temperature : float + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -794,17 +901,20 @@ class XSdata(object): [self.energy_groups]) check_value('domain_type', k_fission.domain_type, ['universe', 'cell', 'material', 'mesh']) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - if self.representation is 'isotropic': - self._kappa_fission = k_fission.get_xs(nuclides=nuclide, - xs_type=xs_type, - subdomains=subdomain) - elif self.representation is 'angle': + i = np.where(self.temperatures == temperature)[0][0] + if self.representation == 'isotropic': + self._kappa_fission[i] = k_fission.get_xs(nuclides=nuclide, + xs_type=xs_type, + subdomains=subdomain) + elif self.representation == 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) - def set_chi_mgxs(self, chi, nuclide='total', xs_type='macro', - subdomain=None): + def set_chi_mgxs(self, chi, temperature=294., nuclide='total', + xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.Chi to be used to set chi for this XSdata object. @@ -812,6 +922,9 @@ class XSdata(object): ---------- chi: openmc.mgxs.Chi MGXS Object containing chi for the domain of interest. + temperature : float + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -839,19 +952,23 @@ class XSdata(object): check_value('energy_groups', chi.energy_groups, [self.energy_groups]) check_value('domain_type', chi.domain_type, ['universe', 'cell', 'material', 'mesh']) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - if self.representation is 'isotropic': - self._chi = chi.get_xs(nuclides=nuclide, - xs_type=xs_type, subdomains=subdomain) - elif self.representation is 'angle': + i = np.where(self.temperatures == temperature)[0][0] + if self.representation == 'isotropic': + self._chi[i] = chi.get_xs(nuclides=nuclide, + xs_type=xs_type, subdomains=subdomain) + elif self.representation == 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) if self.use_chi is not None: self.use_chi = True - def set_scatter_mgxs(self, scatter, nuclide='total', xs_type='macro', - subdomain=None): + def set_scatter_matrix_mgxs(self, scatter, temperature=294., + nuclide='total', xs_type='macro', + subdomain=None): """This method allows for an openmc.mgxs.ScatterMatrixXS to be used to set the scatter matrix cross section for this XSdata object. If the XSdata.order attribute has not yet been set, then @@ -862,6 +979,9 @@ class XSdata(object): scatter: openmc.mgxs.ScatterMatrixXS MGXS Object containing the scatter matrix cross section for the domain of interest. + temperature : float + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -884,8 +1004,10 @@ class XSdata(object): [self.energy_groups]) check_value('domain_type', scatter.domain_type, ['universe', 'cell', 'material', 'mesh']) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - if self.scatt_type != 'legendre': + if self.scatter_format != 'legendre': msg = 'Anisotropic scattering representations other than ' \ 'Legendre expansions have not yet been implemented in ' \ 'openmc.mgxs.' @@ -901,24 +1023,27 @@ class XSdata(object): check_value('legendre_order', scatter.legendre_order, [self.order]) - if self.representation is 'isotropic': + i = np.where(self.temperatures == temperature)[0][0] + if self.representation == 'isotropic': # Get the scattering orders in the outermost dimension - self._scatter = np.zeros((self.num_orders, - self.energy_groups.num_groups, - self.energy_groups.num_groups)) + self._scatter_matrix[i] = np.zeros((self.num_orders, + self.energy_groups.num_groups, + self.energy_groups.num_groups)) for moment in range(self.num_orders): - self._scatter[moment, :, :] = \ + self._scatter_matrix[i][moment, :, :] = \ scatter.get_xs(nuclides=nuclide, xs_type=xs_type, moment=moment, subdomains=subdomain) - elif self.representation is 'angle': + elif self.representation == 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) - def set_multiplicity_mgxs(self, nuscatter, scatter=None, nuclide='total', - xs_type='macro', subdomain=None): + def set_multiplicity_matrix_mgxs(self, nuscatter, scatter=None, + temperature=294., nuclide='total', + xs_type='macro', subdomain=None): """This method allows for either the direct use of only an - openmc.mgxs.MultiplicityMatrixXS OR an openmc.mgxs.NuScatterMatrixXS and + openmc.mgxs.MultiplicityMatrixXS OR + an openmc.mgxs.NuScatterMatrixXS and openmc.mgxs.ScatterMatrixXS to be used to set the scattering multiplicity for this XSdata object. Multiplicity, in OpenMC parlance, is a factor used to account for the production @@ -935,6 +1060,9 @@ class XSdata(object): scatter: openmc.mgxs.ScatterMatrixXS MGXS Object containing the scattering matrix cross section for the domain of interest. + temperature : float + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -958,6 +1086,9 @@ class XSdata(object): [self.energy_groups]) check_value('domain_type', nuscatter.domain_type, ['universe', 'cell', 'material', 'mesh']) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) + if scatter is not None: check_type('scatter', scatter, openmc.mgxs.ScatterMatrixXS) if isinstance(nuscatter, openmc.mgxs.MultiplicityMatrixXS): @@ -970,102 +1101,174 @@ class XSdata(object): check_value('domain_type', scatter.domain_type, ['universe', 'cell', 'material', 'mesh']) - if self.representation is 'isotropic': + i = np.where(self.temperatures == temperature)[0][0] + if self.representation == 'isotropic': nuscatt = nuscatter.get_xs(nuclides=nuclide, xs_type=xs_type, moment=0, subdomains=subdomain) if isinstance(nuscatter, openmc.mgxs.MultiplicityMatrixXS): - self._multiplicity = nuscatt + self._multiplicity_matrix[i] = nuscatt else: scatt = scatter.get_xs(nuclides=nuclide, xs_type=xs_type, moment=0, subdomains=subdomain) - self._multiplicity = np.divide(nuscatt, scatt) - elif self.representation is 'angle': + self._multiplicity_matrix[i] = np.divide(nuscatt, scatt) + elif self.representation == 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) - self._multiplicity = np.nan_to_num(self._multiplicity) + self._multiplicity_matrix[i] = \ + np.nan_to_num(self._multiplicity_matrix[i]) - def _get_xsdata_xml(self): - element = ET.Element('xsdata') - element.set('name', self._name) + def to_hdf5(self, file): + """Write XSdata to an HDF5 file - if self._alias is not None: - subelement = ET.SubElement(element, 'alias') - subelement.text = self.alias + Parameters + ---------- + file : h5py.File + HDF5 File (a root Group) to write to - if self._kT is not None: - subelement = ET.SubElement(element, 'kT') - subelement.text = str(self._kT) + """ + grp = file.create_group(self.name) + if self.atomic_weight_ratio is not None: + grp.attrs['atomic_weight_ratio'] = self.atomic_weight_ratio + if self.fissionable is not None: + grp.attrs['fissionable'] = self.fissionable + if self.representation is not None: + grp.attrs['representation'] = np.string_(self.representation) + if self.representation == 'angle': + if self.num_azimuthal is not None: + grp.attrs['num_azimuthal'] = self.num_azimuthal + if self.num_polar is not None: + grp.attrs['num_polar'] = self.num_polar + if self.scatter_format is not None: + grp.attrs['scatter_format'] = np.string_(self.scatter_format) + if self.scatter_shape is not None: + grp.attrs['scatter_shape'] = np.string_(self.scatter_shape) + if self.order is not None: + grp.attrs['order'] = self.order - if self._awr is not None: - subelement = ET.SubElement(element, 'awr') - subelement.text = str(self._awr) + ktg = grp.create_group('kTs') + for temperature in self.temperatures: + temp_label = str(int(np.round(temperature))) + "K" + kT = temperature * openmc.data.K_BOLTZMANN + ktg.create_dataset(temp_label, data=kT) - if self._fissionable is not None: - subelement = ET.SubElement(element, 'fissionable') - subelement.text = str(self._fissionable) + # Create the temperature datasets + for i, temperature in enumerate(self.temperatures): + xs_grp = grp.create_group(str(int(np.round(temperature))) + "K") + if self._total[i] is None: + raise ValueError('total data must be provided when writing ' + 'the HDF5 library') + xs_grp.create_dataset("total", data=self._total[i]) + if self._absorption[i] is None: + raise ValueError('absorption data must be provided when ' + 'writing the HDF5 library') + xs_grp.create_dataset("absorption", data=self._absorption[i]) + if self.fissionable: + if self._fission[i] is not None: + xs_grp.create_dataset("fission", data=self._fission[i]) + if self._kappa_fission[i] is not None: + xs_grp.create_dataset("kappa-fission", + data=self._kappa_fission[i]) + if self._chi[i] is not None: + xs_grp.create_dataset("chi", data=self._chi[i]) + if self._nu_fission[i] is None: + raise ValueError('nu-fission data must be provided when ' + 'writing the HDF5 library') + xs_grp.create_dataset("nu-fission", data=self._nu_fission[i]) - if self._representation is not None: - subelement = ET.SubElement(element, 'representation') - subelement.text = self._representation + if self._scatter_matrix[i] is None: + raise ValueError('Scatter matrix must be provided when ' + 'writing the HDF5 library') - if self._representation == 'angle': - if self._num_azimuthal is not None: - subelement = ET.SubElement(element, 'num_azimuthal') - subelement.text = str(self._num_azimuthal) - if self._num_polar is not None: - subelement = ET.SubElement(element, 'num_polar') - subelement.text = str(self._num_polar) + # Get the sparse scattering data to print to the library + G = self.energy_groups.num_groups + if self.representation == 'isotropic': + g_out_bounds = np.zeros((G, 2), dtype=np.int) + for g_in in range(G): + nz = np.nonzero(self._scatter_matrix[i][0, g_in, :]) + g_out_bounds[g_in, 0] = nz[0][0] + g_out_bounds[g_in, 1] = nz[0][-1] + # Now create the flattened scatter matrix array + matrix = self._scatter_matrix[i] + flat_scatt = [] + for g_in in range(G): + for g_out in range(g_out_bounds[g_in, 0], + g_out_bounds[g_in, 1] + 1): + for l in range(len(matrix[:, g_in, g_out])): + flat_scatt.append(matrix[l, g_in, g_out]) + # And write it. + scatt_grp = xs_grp.create_group('scatter_data') + scatt_grp.create_dataset("scatter_matrix", + data=np.array(flat_scatt)) + # Repeat for multiplicity + if self._multiplicity_matrix[i] is not None: + # Now create the flattened scatter matrix array + matrix = self._multiplicity_matrix[i][:, :] + flat_mult = [] + for g_in in range(G): + for g_out in range(g_out_bounds[g_in, 0], + g_out_bounds[g_in, 1] + 1): + flat_mult.append(matrix[g_in, g_out]) + scatt_grp.create_dataset("multiplicity_matrix", + data=np.array(flat_mult)) - if self._scatt_type is not None: - subelement = ET.SubElement(element, 'scatt_type') - subelement.text = self._scatt_type + # And finally, adjust g_out_bounds for 1-based group counting + # and write it. + g_out_bounds[:, :] += 1 + scatt_grp.create_dataset("g_min", data=g_out_bounds[:, 0]) + scatt_grp.create_dataset("g_max", data=g_out_bounds[:, 1]) - if self._order is not None: - subelement = ET.SubElement(element, 'order') - subelement.text = str(self._order) + elif self.representation == 'angle': + Np = self.num_polar + Na = self.num_azimuthal + g_out_bounds = np.zeros((Np, Na, G, 2), dtype=np.int) + for p in range(Np): + for a in range(Na): + for g_in in range(G): + matrix = self._scatter_matrix[i][p, a, 0, g_in, :] + nz = np.nonzero(matrix) + g_out_bounds[p, a, g_in, 0] = nz[0][0] + g_out_bounds[p, a, g_in, 1] = nz[0][-1] + # Now create the flattened scatter matrix array + flat_scatt = [] + for p in range(Np): + for a in range(Na): + matrix = self._scatter_matrix[i][p, a, :, :, :] + for g_in in range(G): + for g_out in range(g_out_bounds[p, a, g_in, 0], + g_out_bounds[p, a, g_in, 1] + 1): + for l in range(len(matrix[:, g_in, g_out])): + flat_scatt.append(matrix[l, g_in, g_out]) + # And write it. + scatt_grp = xs_grp.create_group('scatter_data') + scatt_grp.create_dataset("scatter_matrix", + data=np.array(flat_scatt)) + # Repeat for multiplicity + if self._multiplicity_matrix[i] is not None: + # Now create the flattened scatter matrix array + flat_mult = [] + for p in range(Np): + for a in range(Na): + matrix = self._multiplicity_matrix[i][p, a, :, :] + for g_in in range(G): + for g_out in range(g_out_bounds[p, a, g_in, 0], + g_out_bounds[p, a, g_in, 1] + 1): + flat_mult.append(matrix[g_in, g_out]) + # And write it. + scatt_grp.create_dataset("multiplicity_matrix", + data=np.array(flat_mult)) - if self._tabular_legendre is not None: - subelement = ET.SubElement(element, 'tabular_legendre') - subelement.set('enable', str(self._tabular_legendre['enable'])) - subelement.set('num_points', - str(self._tabular_legendre['num_points'])) + # And finally, adjust g_out_bounds for 1-based group counting + # and write it. + g_out_bounds[:, :, :, :] += 1 + scatt_grp.create_dataset("g_min", data=g_out_bounds[:, :, :, 0]) + scatt_grp.create_dataset("g_max", data=g_out_bounds[:, :, :, 1]) - if self._total is not None: - subelement = ET.SubElement(element, 'total') - subelement.text = ndarray_to_string(self._total) - - if self._absorption is not None: - subelement = ET.SubElement(element, 'absorption') - subelement.text = ndarray_to_string(self._absorption) - - if self._scatter is not None: - subelement = ET.SubElement(element, 'scatter') - subelement.text = ndarray_to_string(self._scatter) - - if self._multiplicity is not None: - subelement = ET.SubElement(element, 'multiplicity') - subelement.text = ndarray_to_string(self._multiplicity) - - if self._fissionable: - if self._fission is not None: - subelement = ET.SubElement(element, 'fission') - subelement.text = ndarray_to_string(self._fission) - - if self._kappa_fission is not None: - subelement = ET.SubElement(element, 'k_fission') - subelement.text = ndarray_to_string(self._kappa_fission) - - if self._nu_fission is not None: - subelement = ET.SubElement(element, 'nu_fission') - subelement.text = ndarray_to_string(self._nu_fission) - - if self._chi is not None: - subelement = ET.SubElement(element, 'chi') - subelement.text = ndarray_to_string(self._chi) - - return element + # Add the kinetics data + if self._inverse_velocities[i] is not None: + xs_grp.create_dataset("inverse_velocities", + data=self._inverse_velocities[i]) class MGXSLibrary(object): @@ -1073,41 +1276,35 @@ class MGXSLibrary(object): Corresponds directly to the MG version of the cross_sections.xml input file. + Parameters + ---------- + energy_groups : openmc.mgxs.EnergyGroups + Energy group structure + Attributes ---------- energy_groups : openmc.mgxs.EnergyGroups Energy group structure. - inverse_velocities : Iterable of Real - Inverse of velocities, units of sec/cm xsdatas : Iterable of openmc.XSdata Iterable of multi-Group cross section data objects """ def __init__(self, energy_groups): + self.energy_groups = energy_groups self._xsdatas = [] - self._energy_groups = energy_groups - self._inverse_velocities = None - self._cross_sections_file = ET.Element('cross_sections') - - @property - def inverse_velocities(self): - return self._inverse_velocities @property def energy_groups(self): return self._energy_groups + @property + def temperatures(self): + return self._temperatures + @property def xsdatas(self): return self._xsdatas - @inverse_velocities.setter - def inverse_velocities(self, inverse_velocities): - check_type('inverse_velocities', inverse_velocities, Iterable, Real) - check_greater_than('number of inverse_velocities', - len(inverse_velocities), 0.0) - self._inverse_velocities = np.array(inverse_velocities) - @energy_groups.setter def energy_groups(self, energy_groups): check_type('energy groups', energy_groups, openmc.mgxs.EnergyGroups) @@ -1163,52 +1360,24 @@ class MGXSLibrary(object): self._xsdatas.remove(xsdata) - def _create_groups_subelement(self): - if self._energy_groups is not None: - element = ET.SubElement(self._cross_sections_file, 'groups') - element.text = str(self._energy_groups.num_groups) - - def _create_group_structure_subelement(self): - if self._energy_groups is not None: - element = ET.SubElement(self._cross_sections_file, - 'group_structure') - element.text = ' '.join(map(str, self._energy_groups.group_edges)) - - def _create_inverse_velocities_subelement(self): - if self._inverse_velocities is not None: - element = ET.SubElement(self._cross_sections_file, - 'inverse_velocities') - element.text = ' '.join(map(str, self._inverse_velocities)) - - def _create_xsdata_subelements(self): - for xsdata in self._xsdatas: - xml_element = xsdata._get_xsdata_xml() - self._cross_sections_file.append(xml_element) - - def export_to_xml(self, filename='mgxs.xml'): - """Create an mgxs.xml file that can be used for a - simulation. + def export_to_hdf5(self, filename='mgxs.h5'): + """Create an hdf5 file that can be used for a simulation. Parameters ---------- - filename : str, optional - filename of file, default is mgxs.xml + filename : str + Filename of file, default is mgxs.h5. """ - # Reset xml element tree - self._cross_sections_file.clear() + check_type('filename', filename, string_types) - self._create_groups_subelement() - self._create_group_structure_subelement() - self._create_inverse_velocities_subelement() - self._create_xsdata_subelements() + # Create and write to the HDF5 file + file = h5py.File(filename, "w") + file.attrs['groups'] = self.energy_groups.num_groups + file.attrs['group structure'] = self.energy_groups.group_edges - # Clean the indentation in the file to be user-readable - sort_xml_elements(self._cross_sections_file) - clean_xml_indentation(self._cross_sections_file) + for xsdata in self._xsdatas: + xsdata.to_hdf5(file) - # Write the XML Tree to the xsdatas.xml file - tree = ET.ElementTree(self._cross_sections_file) - tree.write(filename, xml_declaration=True, - encoding='utf-8', method='xml') + file.close() diff --git a/openmc/model/triso.py b/openmc/model/triso.py index 5525ea559c..046bd45159 100644 --- a/openmc/model/triso.py +++ b/openmc/model/triso.py @@ -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 diff --git a/openmc/nuclide.py b/openmc/nuclide.py index 11c59e6879..5b844582c6 100644 --- a/openmc/nuclide.py +++ b/openmc/nuclide.py @@ -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: diff --git a/openmc/plots.py b/openmc/plots.py index 6915604a3c..48af6f23c3 100644 --- a/openmc/plots.py +++ b/openmc/plots.py @@ -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': diff --git a/openmc/region.py b/openmc/region.py index a1b9e9fd0d..ce970f8120 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -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) diff --git a/openmc/settings.py b/openmc/settings.py index 335de839a5..a214b02f3a 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -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) diff --git a/openmc/source.py b/openmc/source.py index ee32cd0f4b..1aee435147 100644 --- a/openmc/source.py +++ b/openmc/source.py @@ -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 diff --git a/openmc/statepoint.py b/openmc/statepoint.py index aef9b8f09a..d0e4dbdd53 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -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 diff --git a/openmc/stats/multivariate.py b/openmc/stats/multivariate.py index e49a94ee19..ca25cf5fb3 100644 --- a/openmc/stats/multivariate.py +++ b/openmc/stats/multivariate.py @@ -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 diff --git a/openmc/stats/univariate.py b/openmc/stats/univariate.py index ce0f0fae1d..dcbb9982c7 100644 --- a/openmc/stats/univariate.py +++ b/openmc/stats/univariate.py @@ -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 diff --git a/openmc/surface.py b/openmc/surface.py index c33c4ee74c..c88c4ccc7c 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -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) diff --git a/openmc/tallies.py b/openmc/tallies.py index a0d0a0e455..3ba24b7827 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -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) diff --git a/openmc/trigger.py b/openmc/trigger.py index f23838dcff..69ec8c6200 100644 --- a/openmc/trigger.py +++ b/openmc/trigger.py @@ -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 = [] diff --git a/openmc/universe.py b/openmc/universe.py index c8fb89a384..545b05d5a1 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -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 = '' diff --git a/scripts/openmc-ace-to-hdf5 b/scripts/openmc-ace-to-hdf5 index dd115d175c..bfc1c1a54d 100755 --- a/scripts/openmc-ace-to-hdf5 +++ b/scripts/openmc-ace-to-hdf5 @@ -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) diff --git a/data/convert_mcnp_70.py b/scripts/openmc-convert-mcnp70-data similarity index 85% rename from data/convert_mcnp_70.py rename to scripts/openmc-convert-mcnp70-data index e68bd848e1..a3081e3ee1 100755 --- a/data/convert_mcnp_70.py +++ b/scripts/openmc-convert-mcnp70-data @@ -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') diff --git a/data/convert_mcnp_71.py b/scripts/openmc-convert-mcnp71-data similarity index 84% rename from data/convert_mcnp_71.py rename to scripts/openmc-convert-mcnp71-data index 7e7fd923f1..9440959197 100755 --- a/data/convert_mcnp_71.py +++ b/scripts/openmc-convert-mcnp71-data @@ -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', diff --git a/data/get_jeff_data.py b/scripts/openmc-get-jeff-data similarity index 92% rename from data/get_jeff_data.py rename to scripts/openmc-get-jeff-data index d0e5839b93..3166b3854e 100755 --- a/data/get_jeff_data.py +++ b/scripts/openmc-get-jeff-data @@ -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 diff --git a/data/get_multipole_data.py b/scripts/openmc-get-multipole-data similarity index 85% rename from data/get_multipole_data.py rename to scripts/openmc-get-multipole-data index d51c196dcc..bf0add2840 100755 --- a/data/get_multipole_data.py +++ b/scripts/openmc-get-multipole-data @@ -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' diff --git a/data/get_nndc_data.py b/scripts/openmc-get-nndc-data similarity index 70% rename from data/get_nndc_data.py rename to scripts/openmc-get-nndc-data index 5bec3865ec..fe9d3ff5bd 100755 --- a/data/get_nndc_data.py +++ b/scripts/openmc-get-nndc-data @@ -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) diff --git a/scripts/openmc-plot-mesh-tally b/scripts/openmc-plot-mesh-tally index 04f1f06c6c..cf17fabe9a 100755 --- a/scripts/openmc-plot-mesh-tally +++ b/scripts/openmc-plot-mesh-tally @@ -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): diff --git a/scripts/openmc-update-mgxs b/scripts/openmc-update-mgxs new file mode 100755 index 0000000000..658be9fef7 --- /dev/null +++ b/scripts/openmc-update-mgxs @@ -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']) diff --git a/setup.py b/setup.py old mode 100644 new mode 100755 index 4479bb82c5..0885c28a86 --- a/setup.py +++ b/setup.py @@ -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) diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 1d1826fbfb..9f4be90b9b 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -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 diff --git a/src/global.F90 b/src/global.F90 index 12e8fba55f..96e93c3705 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -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 diff --git a/src/hdf5_interface.F90 b/src/hdf5_interface.F90 index 136628162c..ce689afa3b 100644 --- a/src/hdf5_interface.F90 +++ b/src/hdf5_interface.F90 @@ -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(:) diff --git a/src/initialize.F90 b/src/initialize.F90 index 2bcf2e01f2..4fe6f8769c 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -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 diff --git a/src/input_xml.F90 b/src/input_xml.F90 index bb6024ea7c..cb13623b8c 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -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 - 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 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 @@ -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) diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index 05d6eb5ec6..857b2ded05 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -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 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 - 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 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 diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index 9409398b3e..feb4d46a89 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -1,41 +1,78 @@ module mgxs_header - use constants, only: MAX_FILE_LEN, ZERO, ONE, TWO, PI + use, intrinsic :: ISO_FORTRAN_ENV + use, intrinsic :: ISO_C_BINDING + + use hdf5, only: HID_T, HSIZE_T, SIZE_T + + use algorithm, only: find, sort + use constants, only: MAX_WORD_LEN, ZERO, ONE, TWO, PI use error, only: fatal_error - use, intrinsic :: ISO_FORTRAN_ENV, only: OUTPUT_UNIT - use list_header, only: ListInt + use hdf5_interface use material_header, only: material - use math, only: calc_pn, calc_rn, expand_harmonic, & - evaluate_legendre + use math, only: evaluate_legendre use nuclide_header, only: MaterialMacroXS use random_lcg, only: prn use scattdata_header use string - use xml_interface + use stl_vector, only: VectorInt, VectorReal + +!=============================================================================== +! XS* contains the temperature-dependent cross section data for an MGXS +!=============================================================================== + + type :: XsDataIso + ! Microscopic cross sections + real(8), allocatable :: total(:) ! total cross section + real(8), allocatable :: absorption(:) ! absorption cross section + class(ScattData), allocatable :: scatter ! scattering info + real(8), allocatable :: nu_fission(:) ! fission production + real(8), allocatable :: k_fission(:) ! kappa-fission + real(8), allocatable :: fission(:) ! fission + real(8), allocatable :: chi(:, :) ! Fission Spectra + real(8), allocatable :: inv_vel(:) ! Inverse velocities + end type XsDataIso + + type :: XsDataAngle + ! Microscopic cross sections + ! In all cases, right-most indices are theta, phi + real(8), allocatable :: total(:, :, :) ! total cross section + real(8), allocatable :: absorption(:, :, :) ! absorption cross section + type(ScattDataContainer), allocatable :: scatter(:, :) ! scattering info + real(8), allocatable :: nu_fission(:, :, :) ! fission production + real(8), allocatable :: k_fission(:, :, :) ! kappa-fission + real(8), allocatable :: fission(:, :, :) ! fission + real(8), allocatable :: chi(:, :, :, :) ! Fission Spectra + real(8), allocatable :: inv_vel(:, :, :) ! Inverse velocities + end type XsDataAngle !=============================================================================== ! MGXS contains the base mgxs data for a nuclide/material !=============================================================================== type, abstract :: Mgxs - character(len=104) :: name ! name of dataset, e.g. 92235.03c - real(8) :: awr ! Atomic Weight Ratio - real(8) :: kT ! temperature in MeV (k*T) + character(len=MAX_WORD_LEN) :: name ! name of dataset, e.g. UO2 + real(8) :: awr ! Atomic Weight Ratio + real(8), allocatable :: kTs(:) ! temperature in MeV (k*T) ! Fission information - logical :: fissionable ! mgxs object is fissionable? - integer :: scatt_type ! either legendre, histogram, or tabular. + logical :: fissionable ! mgxs object is fissionable? + integer :: scatter_format ! either legendre, histogram, or tabular. + + ! Caching information + integer :: index_temp ! temperature index for nuclide contains - procedure(mgxs_init_file_), deferred :: init_file ! Initialize the data - procedure(mgxs_get_xs_), deferred :: get_xs ! Get the requested xs + procedure(mgxs_from_hdf5_), deferred :: from_hdf5 ! Load the data procedure(mgxs_combine_), deferred :: combine ! initializes object + procedure(mgxs_get_xs_), deferred :: get_xs ! Get the requested xs ! Sample the outgoing energy from a fission event procedure(mgxs_sample_fission_), deferred :: sample_fission_energy ! Sample the outgoing energy and angle from a scatter event procedure(mgxs_sample_scatter_), deferred :: sample_scatter ! Calculate the material specific MGXS data from the nuclides procedure(mgxs_calculate_xs_), deferred :: calculate_xs + procedure :: find_temperature => mgxs_find_temperature end type Mgxs !=============================================================================== @@ -51,18 +88,38 @@ module mgxs_header !=============================================================================== abstract interface - subroutine mgxs_init_file_(this, node_xsdata, groups, get_kfiss, get_fiss, & - max_order) - import Mgxs, Node - class(Mgxs), intent(inout) :: this ! Working Object - type(Node), pointer, intent(in) :: node_xsdata ! Data from MGXS xml - integer, intent(in) :: groups ! Number of Energy groups - logical, intent(in) :: get_kfiss ! Need Kappa-Fission? - logical, intent(in) :: get_fiss ! Should we get fiss data? - integer, intent(in) :: max_order ! Maximum requested order - end subroutine mgxs_init_file_ + subroutine mgxs_from_hdf5_(this, xs_id, groups, temperature, method, & + tolerance, get_kfiss, get_fiss, max_order, & + legendre_to_tabular, legendre_to_tabular_points) + import Mgxs, HID_T, VectorReal + class(Mgxs), intent(inout) :: this ! Working Object + integer(HID_T), intent(in) :: xs_id ! Library data + integer, intent(in) :: groups ! Number of Energy groups + type(VectorReal), intent(in) :: temperature ! list of desired temperatures + integer, intent(inout) :: method ! Type of temperature access + real(8), intent(in) :: tolerance ! Tolerance on method + logical, intent(in) :: get_kfiss ! Need Kappa-Fission? + logical, intent(in) :: get_fiss ! Should we get fiss data? + integer, intent(in) :: max_order ! Maximum requested order + logical, intent(in) :: legendre_to_tabular ! Convert Legendres to Tabular? + integer, intent(in) :: legendre_to_tabular_points ! Number of points to use + ! in that conversion + end subroutine mgxs_from_hdf5_ - pure function mgxs_get_xs_(this,xstype,gin,gout,uvw,mu) result(xs) + subroutine mgxs_combine_(this, temps, mat, nuclides, groups, max_order, & + tolerance, method) + import Mgxs, Material, MgxsContainer, VectorReal + class(Mgxs), intent(inout) :: this ! The Mgxs to initialize + type(VectorReal), intent(in) :: temps ! Temperatures to obtain + type(Material), pointer, intent(in) :: mat ! base material + type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from + integer, intent(in) :: groups ! Number of E groups + integer, intent(in) :: max_order ! Maximum requested order + real(8), intent(in) :: tolerance ! Tolerance on method + integer, intent(in) :: method ! Type of temperature access + end subroutine mgxs_combine_ + + pure function mgxs_get_xs_(this, xstype, gin, gout, uvw, mu) result(xs_val) import Mgxs class(Mgxs), intent(in) :: this character(*), intent(in) :: xstype ! Cross Section Type @@ -70,35 +127,12 @@ module mgxs_header integer, optional, intent(in) :: gout ! Outgoing Group real(8), optional, intent(in) :: uvw(3) ! Requested Angle real(8), optional, intent(in) :: mu ! Change in angle - real(8) :: xs ! Resultant xs + real(8) :: xs_val ! Resultant xs end function mgxs_get_xs_ - pure function mgxs_calc_f_(this,gin,gout,mu,uvw,iazi,ipol) result(f) - import Mgxs - class(Mgxs), intent(in) :: this - integer, intent(in) :: gin ! Incoming Energy Group - integer, intent(in) :: gout ! Outgoing Energy Group - real(8), intent(in) :: mu ! Angle of interest - real(8), intent(in), optional :: uvw(3) ! Direction vector - integer, intent(in), optional :: iazi ! Incoming Energy Group - integer, intent(in), optional :: ipol ! Outgoing Energy Group - real(8) :: f ! Return value of f(mu) - - end function mgxs_calc_f_ - - subroutine mgxs_combine_(this, mat, nuclides, groups, max_order, scatt_type) - import Mgxs, Material, MgxsContainer - class(Mgxs), intent(inout) :: this ! The Mgxs to initialize - type(Material), pointer, intent(in) :: mat ! base material - type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from - integer, intent(in) :: groups ! Number of E groups - integer, intent(in) :: max_order ! Maximum requested order - integer, intent(in) :: scatt_type ! Legendre or Tabular Scatt? - end subroutine mgxs_combine_ - function mgxs_sample_fission_(this, gin, uvw) result(gout) import Mgxs - class(Mgxs), intent(in) :: this ! Data to work with + class(Mgxs), intent(in) :: this integer, intent(in) :: gin ! Incoming energy group real(8), intent(in) :: uvw(3) ! Particle Direction integer :: gout ! Sampled outgoing group @@ -107,7 +141,7 @@ module mgxs_header subroutine mgxs_sample_scatter_(this, uvw, gin, gout, mu, wgt) import Mgxs - class(Mgxs), intent(in) :: this + class(Mgxs), intent(in) :: this real(8), intent(in) :: uvw(3) ! Incoming neutron direction integer, intent(in) :: gin ! Incoming neutron group integer, intent(out) :: gout ! Sampled outgoin group @@ -130,18 +164,9 @@ module mgxs_header !=============================================================================== type, extends(Mgxs) :: MgxsIso - - ! Microscopic cross sections - real(8), allocatable :: total(:) ! total cross section - real(8), allocatable :: absorption(:) ! absorption cross section - class(ScattData), allocatable :: scatter ! scattering information - real(8), allocatable :: nu_fission(:) ! fission matrix (Gout x Gin) - real(8), allocatable :: k_fission(:) ! kappa-fission - real(8), allocatable :: fission(:) ! neutron production - real(8), allocatable :: chi(:, :) ! Fission Spectra - + type(XsDataIso), allocatable :: xs(:) ! One for every temperature contains - procedure :: init_file => mgxsiso_init_file ! Initialize Nuclidic MGXS Data + procedure :: from_hdf5 => mgxsiso_from_hdf5 ! Initialize Nuclidic MGXS Data procedure :: get_xs => mgxsiso_get_xs ! Gets Size of Data w/in Object procedure :: combine => mgxsiso_combine ! inits object procedure :: sample_fission_energy => mgxsiso_sample_fission_energy @@ -155,23 +180,14 @@ module mgxs_header !=============================================================================== type, extends(Mgxs) :: MgxsAngle - - ! Microscopic cross sections - real(8), allocatable :: total(:, :, :) ! total cross section - real(8), allocatable :: absorption(:, :, :) ! absorption cross section - type(ScattDataContainer), allocatable :: scatter(:, :) ! scattering information - real(8), allocatable :: nu_fission(:, :, :) ! fission matrix (Gout x Gin) - real(8), allocatable :: k_fission(:, :, :) ! kappa-fission - real(8), allocatable :: fission(:, :, :) ! neutron production - real(8), allocatable :: chi(:, :, :, :) ! Fission Spectra - ! In all cases, right-most indices are theta, phi - integer :: n_pol ! Number of polar angles - integer :: n_azi ! Number of azimuthal angles - real(8), allocatable :: polar(:) ! polar angles - real(8), allocatable :: azimuthal(:) ! azimuthal angles + type(XsDataAngle), allocatable :: xs(:) ! One for every temperature + integer :: n_pol ! Number of polar angles + integer :: n_azi ! Number of azimuthal angles + real(8), allocatable :: polar(:) ! polar angles + real(8), allocatable :: azimuthal(:) ! azimuthal angles contains - procedure :: init_file => mgxsang_init_file ! Initialize Nuclidic MGXS Data + procedure :: from_hdf5 => mgxsang_from_hdf5 ! Initialize Nuclidic MGXS Data procedure :: get_xs => mgxsang_get_xs ! Gets Size of Data w/in Object procedure :: combine => mgxsang_combine ! inits object procedure :: sample_fission_energy => mgxsang_sample_fission_energy @@ -182,1046 +198,1032 @@ module mgxs_header contains !=============================================================================== -! MGXS*_INIT reads in the data from the XML file. At the point of entry -! the file would have been opened and metadata read. This routine begins with -! the xsdata object node itself. +! MGXS*_FROM_HDF5 reads in the data from the HDF5 Library. At the point of entry +! the file would have been opened and metadata read. !=============================================================================== - subroutine mgxs_init_file(this, node_xsdata) - class(Mgxs), intent(inout) :: this ! Working Object - type(Node), pointer, intent(in) :: node_xsdata ! Data from MGXS xml + subroutine mgxs_from_hdf5(this, xs_id, temperature, method, tolerance, & + temps_to_read, order_dim) + class(Mgxs), intent(inout) :: this ! Working Object + integer(HID_T), intent(in) :: xs_id ! Group in H5 file + type(VectorReal), intent(in) :: temperature ! list of desired temperatures + integer, intent(inout) :: method ! Type of temperature access + real(8), intent(in) :: tolerance ! Tolerance on method + type(VectorInt), intent(out) :: temps_to_read ! Temperatures to read + integer, intent(out) :: order_dim ! Scattering data order size - character(MAX_LINE_LEN) :: temp_str + integer(SIZE_T) :: name_len + integer(HID_T) :: kT_group + character(MAX_WORD_LEN), allocatable :: dset_names(:) + real(8), allocatable :: temps_available(:) ! temperatures available + real(8) :: temp_desired + real(8) :: temp_actual + character(MAX_WORD_LEN) :: temp_str + real(8) :: dangle + integer :: ipol, iazi - ! Load the nuclide metadata - call get_node_value(node_xsdata, "name", this % name) - this % name = to_lower(this % name) - if (check_for_node(node_xsdata, "kT")) then - call get_node_value(node_xsdata, "kT", this % kT) - else - this % kT = ZERO - end if - if (check_for_node(node_xsdata, "awr")) then - call get_node_value(node_xsdata, "awr", this % awr) + ! Get name of dataset from group + name_len = len(this % name) + this % name = get_name(xs_id, name_len) + + ! Get rid of leading '/' + this % name = trim(this % name(2:)) + + if (attribute_exists(xs_id, "atomic_weight_ratio")) then + call read_attribute(this % awr, xs_id, "atomic_weight_ratio") else this % awr = -ONE end if - if (check_for_node(node_xsdata, "scatt_type")) then - call get_node_value(node_xsdata, "scatt_type", temp_str) - temp_str = trim(to_lower(temp_str)) - if (temp_str == 'legendre') then - this % scatt_type = ANGLE_LEGENDRE - else if (temp_str == 'histogram') then - this % scatt_type = ANGLE_HISTOGRAM - else if (temp_str == 'tabular') then - this % scatt_type = ANGLE_TABULAR - else - call fatal_error("Invalid scatt_type option!") - end if - else - this % scatt_type = ANGLE_LEGENDRE + + ! Determine temperatures available + kT_group = open_group(xs_id, 'kTs') + call get_datasets(kT_group, dset_names) + allocate(temps_available(size(dset_names))) + do i = 1, size(dset_names) + ! Read temperature value + call read_dataset(temps_available(i), kT_group, trim(dset_names(i))) + ! Convert MeV to Kelvin + temps_available(i) = temps_available(i) / K_BOLTZMANN + end do + call sort(temps_available) + + ! If only one temperature is available, revert to nearest temperature + if (size(temps_available) == 1 .and. & + method == TEMPERATURE_INTERPOLATION) then + call warning("Cross sections for " // trim(this % name) // " are only & + &available at one temperature. Reverting to nearest temperature & + &method.") + method = TEMPERATURE_NEAREST end if - if (check_for_node(node_xsdata, "fissionable")) then - call get_node_value(node_xsdata, "fissionable", temp_str) - temp_str = to_lower(temp_str) - if (trim(temp_str) == 'true' .or. trim(temp_str) == '1') then - this % fissionable = .true. + select case (method) + case (TEMPERATURE_NEAREST) + ! Determine actual temperatures to read + TEMP_LOOP: do i = 1, temperature % size() + temp_desired = temperature % data(i) + i_closest = minloc(abs(temps_available - temp_desired), dim=1) + temp_actual = temps_available(i_closest) + if (abs(temp_actual - temp_desired) < tolerance) then + if (find(temps_to_read, nint(temp_actual)) == -1) then + call temps_to_read % push_back(nint(temp_actual)) + end if + else + call fatal_error("MGXS library does not contain cross sections & + &for " // trim(this % name) // " at or near " // & + trim(to_str(nint(temp_desired))) // " K.") + end if + end do TEMP_LOOP + + case (TEMPERATURE_INTERPOLATION) + ! If temperature interpolation or multipole is selected, get a list of + ! bounding temperatures for each actual temperature present in the model + TEMPS_LOOP: do i = 1, temperature % size() + temp_desired = temperature % data(i) + + do j = 1, size(temps_available) - 1 + if (temps_available(j) <= temp_desired .and. & + temp_desired < temps_available(j + 1)) then + if (find(temps_to_read, nint(temps_available(j))) == -1) then + call temps_to_read % push_back(nint(temps_available(j))) + end if + if (find(temps_to_read, nint(temps_available(j + 1))) == -1) then + call temps_to_read % push_back(nint(temps_available(j + 1))) + end if + cycle TEMPS_LOOP + end if + end do + + call fatal_error("MGXS library does not contain cross sections & + &for " // trim(this % name) // " at temperatures that bound " // & + trim(to_str(nint(temp_desired))) // " K.") + end do TEMPS_LOOP + end select + + ! Sort temperatures to read + call sort(temps_to_read) + + ! Get temperatures + n_temperature = temps_to_read % size() + allocate(this % kTs(n_temperature)) + do i = 1, n_temperature + ! Get temperature as a string + temp_str = trim(to_str(temps_to_read % data(i))) // "K" + + ! Read exact temperature value + call read_dataset(this % kTs(i), kT_group, trim(temp_str)) + end do + call close_group(kT_group) + + ! Allocate the XS object for the number of temperatures + select type(this) + type is (MgxsIso) + allocate(this % xs(n_temperature)) + type is (MgxsAngle) + allocate(this % xs(n_temperature)) + end select + + ! Load the remaining metadata + if (attribute_exists(xs_id, "scatter_format")) then + call read_attribute(temp_str, xs_id, "scatter_format") + temp_str = trim(temp_str) + if (to_lower(temp_str) == 'legendre') then + this % scatter_format = ANGLE_LEGENDRE + else if (to_lower(temp_str) == 'histogram') then + this % scatter_format = ANGLE_HISTOGRAM + else if (to_lower(temp_str) == 'tabular') then + this % scatter_format = ANGLE_TABULAR else - this % fissionable = .false. + call fatal_error("Invalid scatter_format option!") end if + else + this % scatter_format = ANGLE_LEGENDRE + end if + if (attribute_exists(xs_id, "scatter_shape")) then + call read_attribute(temp_str, xs_id, "scatter_shape") + temp_str = trim(temp_str) + if (to_lower(temp_str) /= "[order][g][g']") then + call fatal_error("Invalid scatter_shape option!") + end if + end if + if (attribute_exists(xs_id, "fissionable")) then + call read_attribute(this % fissionable, xs_id, "fissionable") else call fatal_error("Fissionable element must be set!") end if - end subroutine mgxs_init_file - - subroutine mgxsiso_init_file(this, node_xsdata, groups, get_kfiss, get_fiss, & - max_order) - class(MgxsIso), intent(inout) :: this ! Working Object - type(Node), pointer, intent(in) :: node_xsdata ! Data from MGXS xml - integer, intent(in) :: groups ! Number of Energy groups - logical, intent(in) :: get_kfiss ! Need Kappa-Fission? - logical, intent(in) :: get_fiss ! Need fiss data? - integer, intent(in) :: max_order ! Maximum requested order - - type(Node), pointer :: node_legendre_mu - character(MAX_LINE_LEN) :: temp_str - logical :: enable_leg_mu - real(8), allocatable :: temp_arr(:), temp_2d(:, :) - real(8), allocatable :: temp_mult(:, :) - real(8), allocatable :: scatt_coeffs(:, :, :) - real(8), allocatable :: input_scatt(:, :, :) - real(8), allocatable :: temp_scatt(:, :, :) - real(8) :: dmu, mu, norm - integer :: order, order_dim, gin, gout, l, arr_len - integer :: legendre_mu_points, imu - - ! Call generic data gathering routine (will populate the metadata) - call mgxs_init_file(this, node_xsdata) - - ! Load the more specific data - allocate(this % nu_fission(groups)) - allocate(this % chi(groups,groups)) - if (this % fissionable) then - if (check_for_node(node_xsdata, "chi")) then - ! Chi was provided, that means they are giving chi and nu-fission - ! vectors - ! Get chi - allocate(temp_arr(groups)) - call get_node_array(node_xsdata, "chi", temp_arr) - do gin = 1, groups - do gout = 1, groups - this % chi(gout, gin) = temp_arr(gout) - end do - ! Normalize chi so its CDF goes to 1 - this % chi(:, gin) = this % chi(:, gin) / sum(this % chi(:, gin)) - end do - deallocate(temp_arr) - - ! Get nu_fission (as a vector) - if (check_for_node(node_xsdata, "nu_fission")) then - call get_node_array(node_xsdata, "nu_fission", this % nu_fission) - else - call fatal_error("If fissionable, must provide nu_fission!") - end if - - else - ! chi isnt provided but is within nu_fission, existing as a matrix - ! So, get nu_fission (as a matrix) - if (check_for_node(node_xsdata, "nu_fission")) then - allocate(temp_arr(groups*groups)) - call get_node_array(node_xsdata, "nu_fission", temp_arr) - allocate(temp_2d(groups, groups)) - temp_2d = reshape(temp_arr, (/groups, groups/)) - deallocate(temp_arr) - else - call fatal_error("If fissionable, must provide nu_fission!") - end if - - ! Set the vector nu-fission from the matrix nu-fission - do gin = 1, groups - this % nu_fission(gin) = sum(temp_2d(:, gin)) - end do - - ! Now pull out information needed for chi - this % chi(:, :) = temp_2d - ! Normalize chi so its CDF goes to 1 - do gin = 1, groups - this % chi(:, gin) = this % chi(:, gin) / sum(this % chi(:, gin)) - end do - deallocate(temp_2d) - end if - ! If we have a need* for the fission and kappa-fission x/s, get them - ! (*Need is defined as will be using it to tally) - if (get_fiss) then - allocate(this % fission(groups)) - if (check_for_node(node_xsdata, "fission")) then - call get_node_array(node_xsdata, "fission", this % fission) - else - call fatal_error("Fission data missing, required due to fission& - & tallies in tallies.xml file!") - end if - end if - if (get_kfiss) then - allocate(this % k_fission(groups)) - if (check_for_node(node_xsdata, "kappa_fission")) then - call get_node_array(node_xsdata, "kappa_fission", this % k_fission) - else - call fatal_error("kappa_fission data missing, required due to & - &kappa-fission tallies in tallies.xml file!") - end if - end if - else - this % nu_fission = ZERO - this % chi = ZERO - end if - - allocate(this % absorption(groups)) - if (check_for_node(node_xsdata, "absorption")) then - call get_node_array(node_xsdata, "absorption", this % absorption) - else - call fatal_error("Must provide absorption!") - end if - - ! Get multiplication data if present - allocate(temp_mult(groups, groups)) - if (check_for_node(node_xsdata, "multiplicity")) then - arr_len = get_arraysize_double(node_xsdata, "multiplicity") - if (arr_len == groups * groups) then - allocate(temp_arr(arr_len)) - call get_node_array(node_xsdata, "multiplicity", temp_arr) - temp_mult(:, :) = reshape(temp_arr, (/groups, groups/)) - deallocate(temp_arr) - else - call fatal_error("Multiplicity length not same as number of groups& - & squared!") - end if - else - temp_mult(:, :) = ONE - end if - - ! Get scattering treatment information - ! Tabular_legendre tells us if we are to treat the provided - ! Legendre polynomials as tabular data (if enable is true, default) - ! or leaving them as Legendres (if enable is false) - - ! Set the default (Convert to tabular format w/ 33 points) - enable_leg_mu = .true. - legendre_mu_points = 33 - ! Get the user-provided values - if (check_for_node(node_xsdata, "tabular_legendre")) then - call get_node_ptr(node_xsdata, "tabular_legendre", node_legendre_mu) - if (check_for_node(node_legendre_mu, "enable")) then - call get_node_value(node_legendre_mu, "enable", temp_str) - temp_str = trim(to_lower(temp_str)) - if (temp_str == 'true' .or. temp_str == '1') then - enable_leg_mu = .true. - elseif (temp_str == 'false' .or. temp_str == '0') then - enable_leg_mu = .false. - else - call fatal_error("Unrecognized tabular_legendre/enable: " & - // temp_str) - end if - end if - ! Ok, so if we need to convert to a tabular form, get the user provided - ! number of points - if (enable_leg_mu) then - if (check_for_node(node_legendre_mu, "num_points")) then - call get_node_value(node_legendre_mu, "num_points", & - legendre_mu_points) - if (legendre_mu_points <= 0) & - call fatal_error("num_points element must be positive& - & and non-zero!") - else - ! Set the default number of points (0.0625 spacing) - legendre_mu_points = 33 - end if - end if - end if - ! Get the library's value for the order - if (check_for_node(node_xsdata, "order")) then - call get_node_value(node_xsdata, "order", order) + if (attribute_exists(xs_id, "order")) then + call read_attribute(order_dim, xs_id, "order") else call fatal_error("Order must be provided!") end if - ! Before retrieving the data, store the dimensionality of the data in - ! order_dim. For Legendre data, we usually refer to it as Pn where - ! n is the order. However Pn has n+1 sets of points (since you need to + ! Store the dimensionality of the data in order_dim. + ! For Legendre data, we usually refer to it as Pn where n is the order. + ! However Pn has n+1 sets of points (since you need to ! the count the P0 moment). Adjust for that. Histogram and Tabular ! formats dont need this adjustment. - if (this % scatt_type == ANGLE_LEGENDRE) then - order_dim = order + 1 + if (this % scatter_format == ANGLE_LEGENDRE) then + order_dim = order_dim + 1 else - order_dim = order + order_dim = order_dim end if - ! The input is gathered in the more user-friendly facing format of - ! Gout x Gin x Order. We will get it in that format in input_scatt, - ! but then need to convert it to a more useful ordering for processing - ! (Order x Gout x Gin). - allocate(input_scatt(groups, groups, order_dim)) - if (check_for_node(node_xsdata, "scatter")) then - allocate(temp_arr(groups * groups * order_dim)) - call get_node_array(node_xsdata, "scatter", temp_arr) - input_scatt = reshape(temp_arr, (/groups, groups, order_dim/)) - deallocate(temp_arr) - - ! Compare the number of orders given with the maximum order of the - ! problem. Strip off the supefluous orders if needed. - if (this % scatt_type == ANGLE_LEGENDRE) then - order = min(order_dim - 1, max_order) - order_dim = order + 1 - end if - allocate(temp_scatt(groups, groups, order_dim)) - temp_scatt(:, :, :) = input_scatt(:, :, 1:order_dim) - - ! Take input format (groups, groups, order) and convert to - ! the more useful format needed for scattdata: (order, groups, groups) - ! However, if scatt_type was ANGLE_LEGENDRE (i.e., the data was - ! provided as Legendre coefficients), and the user requested that - ! these legendres be converted to tabular form (note this is also - ! the default behavior), convert that now. - if (this % scatt_type == ANGLE_LEGENDRE .and. enable_leg_mu) then - ! Convert input parameters to what we need for the rest. - this % scatt_type = ANGLE_TABULAR - order_dim = legendre_mu_points - order = order_dim - dmu = TWO / real(order - 1, 8) - - allocate(scatt_coeffs(order_dim, groups, groups)) - do gin = 1, groups - do gout = 1, groups - norm = ZERO - do imu = 1, order_dim - if (imu == 1) then - mu = -ONE - else if (imu == order_dim) then - mu = ONE - else - mu = -ONE + real(imu - 1, 8) * dmu - end if - scatt_coeffs(imu, gout, gin) = & - evaluate_legendre(temp_scatt(gout, gin, :),mu) - ! Ensure positivity of distribution - if (scatt_coeffs(imu, gout, gin) < ZERO) & - scatt_coeffs(imu, gout, gin) = ZERO - ! And accrue the integral - if (imu > 1) then - norm = norm + HALF * dmu * & - (scatt_coeffs(imu - 1, gout, gin) + & - scatt_coeffs(imu, gout, gin)) - end if - end do - ! Now that we have the integral, lets ensure that the distribution - ! is normalized such that it preserves the original scattering xs - if (norm > ZERO) then - scatt_coeffs(:, gout, gin) = scatt_coeffs(:, gout, gin) * & - temp_scatt(gout, gin, 1) / norm - end if - end do - end do + ! Get angular meta-data and allocate as needed based off of the + ! information therein + select type(this) + type is (MgxsAngle) + if (attribute_exists(xs_id, "num_polar")) then + call read_attribute(this % n_pol, xs_id, "num_polar") else - ! Sticking with current representation, carry forward but change - ! the array ordering - allocate(scatt_coeffs(order_dim, groups, groups)) - do gin = 1, groups - do gout = 1, groups - do l = 1, order_dim - scatt_coeffs(l, gout, gin) = temp_scatt(gout, gin, l) - end do - end do - end do + call fatal_error("num_polar must be provided!") end if - deallocate(temp_scatt) - else - call fatal_error("Must provide scatter!") - end if - ! Allocate and initialize our ScattData Object. - if (this % scatt_type == ANGLE_HISTOGRAM) then - allocate(ScattDataHistogram :: this % scatter) - else if (this % scatt_type == ANGLE_TABULAR) then - allocate(ScattDataTabular :: this % scatter) - else if (this % scatt_type == ANGLE_LEGENDRE) then - allocate(ScattDataLegendre :: this % scatter) - end if + if (attribute_exists(xs_id, "num_azimuthal")) then + call read_attribute(this % n_azi, xs_id, "num_azimuthal") + else + call fatal_error("num_azimuthal must be provided!") + end if - ! Initialize the ScattData Object - call this % scatter % init(temp_mult, scatt_coeffs) - - ! Check sigA to ensure it is not 0 since it is - ! often divided by in the tally routines - ! (This may happen with Helium data) - do gin = 1, groups - if (this % absorption(gin) == ZERO) this % absorption(gin) = 1E-10_8 - end do - - ! Get, or infer, total xs data. - allocate(this % total(groups)) - if (check_for_node(node_xsdata, "total")) then - call get_node_array(node_xsdata, "total", this % total) - else - this % total(:) = this % absorption(:) + this % scatter % scattxs(:) - end if - - ! Deallocate temporaries for the next material - deallocate(input_scatt, scatt_coeffs, temp_mult) - - ! Finally, check sigT to ensure it is not 0 since it is - ! often divided by in the tally routines - do gin = 1, groups - if (this % total(gin) == ZERO) this % total(gin) = 1E-10_8 - end do - - - end subroutine mgxsiso_init_file - - subroutine mgxsang_init_file(this, node_xsdata, groups, get_kfiss, get_fiss, & - max_order) - class(MgxsAngle), intent(inout) :: this ! Working Object - type(Node), pointer, intent(in) :: node_xsdata ! Data from MGXS xml - integer, intent(in) :: groups ! Number of Energy groups - logical, intent(in) :: get_kfiss ! Need Kappa-Fission? - logical, intent(in) :: get_fiss ! Should we get fiss data? - integer, intent(in) :: max_order ! Maximum requested order - - type(Node), pointer :: node_legendre_mu - character(MAX_LINE_LEN) :: temp_str - logical :: enable_leg_mu - real(8), allocatable :: temp_arr(:), temp_4d(:, :, :, :) - real(8), allocatable :: temp_mult(:, :, :, :) - real(8), allocatable :: scatt_coeffs(:, :, :, :, :) - real(8), allocatable :: input_scatt(:, :, :, :, :) - real(8), allocatable :: temp_scatt(:, :, :, :, :) - real(8) :: dmu, mu, norm, dangle - integer :: order, order_dim, gin, gout, l, arr_len - integer :: legendre_mu_points, imu, ipol, iazi - - ! Call generic data gathering routine (will populate the metadata) - call mgxs_init_file(this, node_xsdata) - - if (check_for_node(node_xsdata, "num_polar")) then - call get_node_value(node_xsdata, "num_polar", this % n_pol) - else - call fatal_error("num_polar must be provided!") - end if - - if (check_for_node(node_xsdata, "num_azimuthal")) then - call get_node_value(node_xsdata, "num_azimuthal", this % n_azi) - else - call fatal_error("num_azimuthal must be provided!") - end if - - ! Load angle data, if present (else equally spaced) - allocate(this % polar(this % n_pol)) - allocate(this % azimuthal(this % n_azi)) - if (check_for_node(node_xsdata, "polar")) then - call fatal_error("User-Specified polar angle bins not yet supported!") - ! When this feature is supported, this line will be activated - call get_node_array(node_xsdata, "polar", this % polar) - else + ! Set angle data to use equally-spaced bins + allocate(this % polar(this % n_pol)) dangle = PI / real(this % n_pol, 8) do ipol = 1, this % n_pol this % polar(ipol) = (real(ipol, 8) - HALF) * dangle end do - end if - if (check_for_node(node_xsdata, "azimuthal")) then - call fatal_error("User-Specified azimuthal angle bins not yet supported!") - ! When this feature is supported, this line will be activated - call get_node_array(node_xsdata, "azimuthal", this % azimuthal) - else + allocate(this % azimuthal(this % n_azi)) dangle = TWO * PI / real(this % n_azi, 8) do iazi = 1, this % n_azi this % azimuthal(iazi) = -PI + (real(iazi, 8) - HALF) * dangle end do - end if - - ! Load the more specific data - allocate(this % nu_fission(groups, this % n_azi, this % n_pol)) - allocate(this % chi(groups, groups, this % n_azi, this % n_pol)) - if (this % fissionable) then - if (check_for_node(node_xsdata, "chi")) then - ! Chi was provided, that means they are giving chi and nu-fission - ! vectors - ! Get chi - allocate(temp_arr(1 * groups * this % n_azi * this % n_pol)) - call get_node_array(node_xsdata, "chi", temp_arr) - ! Initialize counter for temp_arr - l = 0 - gin = 1 - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gout = 1, groups - l = l + 1 - this % chi(gout, gin, iazi, ipol) = temp_arr(l) - end do - ! Normalize chi so its CDF goes to 1 - this % chi(:, gin, iazi, ipol) = & - this % chi(:, gin, iazi, ipol) / & - sum(this % chi(:, gin, iazi, ipol)) - end do - end do - - ! Now set all the other gin values - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 2, groups - this % chi(:, gin, iazi, ipol) = & - this % chi(:, 1, iazi, ipol) - end do - end do - end do - deallocate(temp_arr) - - ! Get nu_fission (as a vector) - if (check_for_node(node_xsdata, "nu_fission")) then - allocate(temp_arr(groups * this % n_azi * this % n_pol)) - call get_node_array(node_xsdata, "nu_fission", temp_arr) - this % nu_fission(:, :, :) = reshape(temp_arr, (/groups, & - this % n_azi, this % n_pol/)) - deallocate(temp_arr) - else - call fatal_error("If fissionable, must provide nu_fission!") - end if - - else - ! chi isnt provided but is within nu_fission, existing as a matrix - ! So, get nu_fission (as a matrix) - if (check_for_node(node_xsdata, "nu_fission")) then - allocate(temp_arr(groups * groups * this % n_azi * this % n_pol)) - call get_node_array(node_xsdata, "nu_fission", temp_arr) - allocate(temp_4d(groups, groups, this % n_azi,this % n_pol)) - temp_4d(:, :, :, :) = reshape(temp_arr, (/groups, groups, & - this % n_azi, this % n_pol/)) - deallocate(temp_arr) - else - call fatal_error("If fissionable, must provide nu_fission!") - end if - - ! Set the vector nu-fission from the matrix nu-fission - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, groups - this % nu_fission(gin, iazi, ipol) = & - sum(temp_4d(:, gin, iazi, ipol)) - end do - end do - end do - - ! Now pull out information needed for chi - this % chi = temp_4d - ! Normalize chi so its CDF goes to 1 - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, groups - this % chi(:, gin, iazi, ipol) = & - this % chi(:, gin, iazi, ipol) / & - sum(this % chi(:, gin, iazi, ipol)) - end do - end do - end do - deallocate(temp_4d) - end if - - ! If we have a need* for the fission and kappa-fission x/s, get them - ! (*Need is defined as will be using it to tally) - if (get_fiss) then - if (check_for_node(node_xsdata, "fission")) then - allocate(temp_arr(groups * this % n_azi * this % n_pol)) - call get_node_array(node_xsdata, "fission", temp_arr) - allocate(this % fission(groups, this % n_azi, this % n_pol)) - this % fission(:, :, :) = reshape(temp_arr, (/groups, this % n_azi, & - this % n_pol/)) - deallocate(temp_arr) - else - call fatal_error("Fission data missing, required due to fission& - & tallies in tallies.xml file!") - end if - end if - if (get_kfiss) then - if (check_for_node(node_xsdata, "kappa_fission")) then - allocate(temp_arr(groups * this % n_azi * this % n_pol)) - call get_node_array(node_xsdata, "kappa_fission", temp_arr) - allocate(this % k_fission(groups, this % n_azi, this % n_pol)) - this % k_fission(:, :, :) = reshape(temp_arr, (/groups, & - this % n_azi, this % n_pol/)) - deallocate(temp_arr) - else - call fatal_error("kappa_fission data missing, required due to & - &kappa-fission tallies in tallies.xml file!") - end if - end if - else - this % nu_fission(:, :, :) = ZERO - this % chi(:, :, :, :) = ZERO - end if - - if (check_for_node(node_xsdata, "absorption")) then - allocate(temp_arr(groups * this % n_azi * this % n_pol)) - call get_node_array(node_xsdata, "absorption", temp_arr) - allocate(this % absorption(groups, this % n_azi, this % n_pol)) - this % absorption(:, :, :) = reshape(temp_arr, (/groups, this % n_azi, & - this % n_pol/)) - deallocate(temp_arr) - else - call fatal_error("Must provide absorption!") - end if - - ! Get multiplication data if present - allocate(temp_mult(groups,groups, this % n_azi, this % n_pol)) - if (check_for_node(node_xsdata, "multiplicity")) then - arr_len = get_arraysize_double(node_xsdata, "multiplicity") - if (arr_len == groups * groups * this % n_azi * this % n_pol) then - allocate(temp_arr(arr_len)) - call get_node_array(node_xsdata, "multiplicity", temp_arr) - temp_mult(:, :, :, :) = reshape(temp_arr, (/groups, groups, & - this % n_azi, this % n_pol/)) - deallocate(temp_arr) - else - call fatal_error("Multiplicity length not same as number of groups& - & squared!") - end if - else - temp_mult(:, :, :, :) = ONE - end if - - ! Get scattering treatment information - ! Tabular_legendre tells us if we are to treat the provided - ! Legendre polynomials as tabular data (if enable is true) or leaving - ! them as Legendres (if enable is false, or the default) - - ! Set the default (leave as Legendre polynomials) - enable_leg_mu = .false. - if (check_for_node(node_xsdata, "tabular_legendre")) then - call get_node_ptr(node_xsdata, "tabular_legendre", node_legendre_mu) - if (check_for_node(node_legendre_mu, "enable")) then - call get_node_value(node_legendre_mu, "enable", temp_str) - temp_str = trim(to_lower(temp_str)) - if (temp_str == 'true' .or. temp_str == '1') then - enable_leg_mu = .true. - elseif (temp_str == 'false' .or. temp_str == '0') then - enable_leg_mu = .false. - else - call fatal_error("Unrecognized tabular_legendre/enable: " & - // temp_str) - end if - end if - ! Ok, so if we need to convert to a tabular form, get the user provided - ! number of points - if (enable_leg_mu) then - if (check_for_node(node_legendre_mu, "num_points")) then - call get_node_value(node_legendre_mu, "num_points", & - legendre_mu_points) - if (legendre_mu_points <= 0) & - call fatal_error("num_points element must be positive& - & and non-zero!") - else - ! Set the default number of points (0.0625 spacing) - legendre_mu_points = 33 - end if - end if - end if - - ! Get the library's value for the order - if (check_for_node(node_xsdata, "order")) then - call get_node_value(node_xsdata, "order", order) - else - call fatal_error("Order must be provided!") - end if - - ! Before retrieving the data, store the dimensionality of the data in - ! order_dim. For Legendre data, we usually refer to it as Pn where - ! n is the order. However Pn has n+1 sets of points (since you need to - ! the count the P0 moment). Adjust for that. Histogram and Tabular - ! formats dont need this adjustment. - if (this % scatt_type == ANGLE_LEGENDRE) then - order_dim = order + 1 - else - order_dim = order - end if - - ! The input is gathered in the more user-friendly facing format of - ! Gout x Gin x Order x Azi x Pol. We will get it in that format in - ! input_scatt, but then need to convert it to a more useful ordering - ! for processing (Order x Gout x Gin x Azi x Pol). - allocate(input_scatt(groups, groups, order_dim, this % n_azi, & - this % n_pol)) - if (check_for_node(node_xsdata, "scatter")) then - allocate(temp_arr(groups * groups * order_dim * this % n_azi * & - this % n_pol)) - call get_node_array(node_xsdata, "scatter", temp_arr) - input_scatt(:, :, :, :, :) = reshape(temp_arr, (/groups, groups, & - order_dim, this % n_azi, this % n_pol/)) - deallocate(temp_arr) - - ! Compare the number of orders given with the maximum order of the - ! problem. Strip off the supefluous orders if needed. - if (this % scatt_type == ANGLE_LEGENDRE) then - order = min(order_dim - 1, max_order) - order_dim = order + 1 - end if - - allocate(temp_scatt(groups, groups, order_dim, this % n_azi, & - this % n_pol)) - temp_scatt(:, :, :, :, :) = input_scatt(:, :, 1:order_dim, :, :) - - ! Take input format (groups, groups, order) and convert to - ! the more useful format needed for scattdata: (order, groups, groups) - ! However, if scatt_type was ANGLE_LEGENDRE (i.e., the data was - ! provided as Legendre coefficients), and the user requested that - ! these legendres be converted to tabular form (note this is also - ! the default behavior), convert that now. - if (this % scatt_type == ANGLE_LEGENDRE .and. enable_leg_mu) then - - ! Convert input parameters to what we need for the rest. - this % scatt_type = ANGLE_TABULAR - order_dim = legendre_mu_points - order = order_dim - dmu = TWO / real(order - 1, 8) - - allocate(scatt_coeffs(order_dim, groups, groups, this % n_azi, & - this % n_pol)) - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, groups - do gout = 1, groups - norm = ZERO - do imu = 1, order_dim - if (imu == 1) then - mu = -ONE - else if (imu == order_dim) then - mu = ONE - else - mu = -ONE + real(imu - 1, 8) * dmu - end if - scatt_coeffs(imu, gout, gin, iazi, ipol) = & - evaluate_legendre(temp_scatt(gout, gin, :, iazi, ipol), mu) - ! Ensure positivity of distribution - if (scatt_coeffs(imu, gout, gin, iazi, ipol) < ZERO) & - scatt_coeffs(imu, gout, gin, iazi, ipol) = ZERO - ! And accrue the integral - if (imu > 1) then - norm = norm + HALF * dmu * & - (scatt_coeffs(imu - 1, gout, gin, iazi, ipol) + & - scatt_coeffs(imu, gout, gin, iazi, ipol)) - end if - end do - ! Now that we have the integral, lets ensure that the distribution - ! is normalized such that it preserves the original scattering xs - if (norm > ZERO) then - scatt_coeffs(:, gout, gin, iazi, ipol) = & - scatt_coeffs(:, gout, gin, iazi, ipol) * & - temp_scatt(gout, gin, 1, iazi, ipol) / norm - end if - end do - end do - end do - end do - else - ! Sticking with current representation, carry forward but change - ! the array ordering - allocate(scatt_coeffs(order_dim, groups, groups, this % n_azi, & - this % n_pol)) - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, groups - do gout = 1, groups - do l = 1, order_dim - scatt_coeffs(l, gout, gin, iazi, ipol) = & - temp_scatt(gout, gin, l, iazi, ipol) - end do - end do - end do - end do - end do - end if - deallocate(temp_scatt) - else - call fatal_error("Must provide scatter!") - end if - - allocate(this % scatter(this % n_azi, this % n_pol)) - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - ! Allocate and initialize our ScattData Object. - if (this % scatt_type == ANGLE_HISTOGRAM) then - allocate(ScattDataHistogram :: this % scatter(iazi, ipol) % obj) - else if (this % scatt_type == ANGLE_TABULAR) then - allocate(ScattDataTabular :: this % scatter(iazi, ipol) % obj) - else if (this % scatt_type == ANGLE_LEGENDRE) then - allocate(ScattDataLegendre :: this % scatter(iazi, ipol) % obj) - end if - - ! Initialize the ScattData Object - call this % scatter(iazi, ipol) % obj % init(& - temp_mult(:, :, iazi, ipol), & - scatt_coeffs(:, :, :, iazi, ipol)) - end do - end do - ! Deallocate temporaries for the next material - deallocate(input_scatt, scatt_coeffs, temp_mult) - - allocate(this % total(groups, this % n_azi, this % n_pol)) - if (check_for_node(node_xsdata, "total")) then - allocate(temp_arr(groups * this % n_azi * this % n_pol)) - call get_node_array(node_xsdata, "total", temp_arr) - this % total(:, :, :) = reshape(temp_arr, (/groups, this % n_azi, & - this % n_pol/)) - deallocate(temp_arr) - else - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - this % total(:, iazi, ipol) = this % absorption(:, iazi, ipol) + & - this % scatter(iazi, ipol) % obj % scattxs(:) - end do - end do - end if - - end subroutine mgxsang_init_file - -!=============================================================================== -! MGXS*_GET_XS returns the requested data cross section data -!=============================================================================== - - pure function mgxsiso_get_xs(this, xstype, gin, gout, uvw, mu) result(xs) - class(MgxsIso), intent(in) :: this ! The Mgxs to initialize - character(*) , intent(in) :: xstype ! Type of xs requested - integer, intent(in) :: gin ! Incoming Energy group - integer, optional, intent(in) :: gout ! Outgoing Energy group - real(8), optional, intent(in) :: uvw(3) ! Requested Angle - real(8), optional, intent(in) :: mu ! Change in angle - real(8) :: xs ! Requested x/s - - select case(xstype) - case('total') - xs = this % total(gin) - case('absorption') - xs = this % absorption(gin) - case('fission') - if (allocated(this % fission)) then - xs = this % fission(gin) - else - xs = ZERO - end if - case('kappa_fission') - if (allocated(this % k_fission)) then - xs = this % k_fission(gin) - else - xs = ZERO - end if - case('nu_fission') - xs = this % nu_fission(gin) - case('chi') - if (present(gout)) then - xs = this % chi(gout,gin) - else - ! Not sure youd want a 1 or a 0, but here you go! - xs = sum(this % chi(:, gin)) - end if - case('scatter') - if (present(gout)) then - if (gout < this % scatter % gmin(gin) .or. & - gout > this % scatter % gmax(gin)) then - xs = ZERO - else - xs = this % scatter % scattxs(gin) * & - this % scatter % energy(gin) % data(gout) - end if - else - xs = this % scatter % scattxs(gin) - end if - case('scatter/mult') - if (present(gout)) then - if (gout < this % scatter % gmin(gin) .or. & - gout > this % scatter % gmax(gin)) then - xs = ZERO - else - xs = this % scatter % scattxs(gin) * & - this % scatter % energy(gin) % data(gout) / & - this % scatter % mult(gin) % data(gout) - end if - else - xs = this % scatter % scattxs(gin) / & - (dot_product(this % scatter % mult(gin) % data, & - this % scatter % energy(gin) % data)) - end if - case('scatter*f_mu/mult','scatter*f_mu') - if (present(gout)) then - if (gout < this % scatter % gmin(gin) .or. & - gout > this % scatter % gmax(gin)) then - xs = ZERO - else - xs = this % scatter % scattxs(gin) * & - this % scatter % energy(gin) % data(gout) * & - this % scatter % calc_f(gin, gout, mu) - if (xstype == 'scatter*f_mu/mult') then - xs = xs / this % scatter % mult(gin) % data(gout) - end if - end if - else - xs = ZERO - ! TODO (Not likely needed) - ! (asking for f_mu without asking for a group or mu would mean the - ! user of this code wants the complete 1-outgoing group distribution - ! which Im not sure what they would do with that. - end if - case default - xs = ZERO end select - end function mgxsiso_get_xs + end subroutine mgxs_from_hdf5 - pure function mgxsang_get_xs(this, xstype, gin, gout, uvw, mu) result(xs) - class(MgxsAngle), intent(in) :: this ! The Mgxs to initialize - character(*) , intent(in) :: xstype ! Type of xs requested - integer, intent(in) :: gin ! Incoming Energy group - integer, optional, intent(in) :: gout ! Outgoing Energy group - real(8), optional, intent(in) :: uvw(3) ! Requested Angle - real(8), optional, intent(in) :: mu ! Change in angle - real(8) :: xs ! Requested x/s + subroutine mgxsiso_from_hdf5(this, xs_id, groups, temperature, method, & + tolerance, get_kfiss, get_fiss, max_order, & + legendre_to_tabular, legendre_to_tabular_points) + class(MgxsIso), intent(inout) :: this ! Working Object + integer(HID_T), intent(in) :: xs_id ! Group in H5 file + integer, intent(in) :: groups ! Number of Energy groups + type(VectorReal), intent(in) :: temperature ! list of desired temperatures + integer, intent(inout) :: method ! Type of temperature access + real(8), intent(in) :: tolerance ! Tolerance on method + logical, intent(in) :: get_kfiss ! Need Kappa-Fission? + logical, intent(in) :: get_fiss ! Should we get fiss data? + integer, intent(in) :: max_order ! Maximum requested order + logical, intent(in) :: legendre_to_tabular ! Convert Legendres to Tabular? + integer, intent(in) :: legendre_to_tabular_points ! Number of points to use + ! in that conversion - integer :: iazi, ipol + character(MAX_LINE_LEN) :: temp_str + integer(HID_T) :: xsdata_grp, scatt_grp + real(8), allocatable :: temp_arr(:), temp_2d(:, :) + real(8) :: dmu, mu, norm + integer :: order, order_dim, gin, gout, l, imu, length + type(VectorInt) :: temps_to_read + integer :: t + type(Jagged2D), allocatable :: input_scatt(:), scatt_coeffs(:) + type(Jagged1D), allocatable :: temp_mult(:) + integer, allocatable :: gmin(:), gmax(:) + + ! Call generic data gathering routine (will populate the metadata) + call mgxs_from_hdf5(this, xs_id, temperature, method, tolerance, & + temps_to_read, order_dim) + + ! Load the more specific data + do t = 1, temps_to_read % size() + associate(xs => this % xs(t)) + ! Get temperature as a string + temp_str = trim(to_str(temps_to_read % data(t))) // "K" + xsdata_grp = open_group(xs_id, trim(temp_str)) + allocate(xs % nu_fission(groups)) + allocate(xs % chi(groups, groups)) + if (this % fissionable) then + if (object_exists(xsdata_grp, "chi")) then + ! Chi was provided, that means we need chi and nu-fission vectors + ! Get chi + allocate(temp_arr(groups)) + call read_dataset(temp_arr, xsdata_grp, "chi") + do gin = 1, groups + do gout = 1, groups + xs % chi(gout, gin) = temp_arr(gout) + end do + ! Normalize chi so its CDF goes to 1 + xs % chi(:, gin) = xs % chi(:, gin) / sum(xs % chi(:, gin)) + end do + deallocate(temp_arr) + + ! Get nu_fission (as a vector) + if (object_exists(xsdata_grp, "nu-fission")) then + call read_dataset(xs % nu_fission, xsdata_grp, "nu-fission") + else + call fatal_error("If fissionable, must provide nu-fission!") + end if - if (present(uvw)) then - call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) - select case(xstype) - case('total') - xs = this % total(gin, iazi, ipol) - case('absorption') - xs = this % absorption(gin, iazi, ipol) - case('fission') - if (allocated(this % fission)) then - xs = this % fission(gin, iazi, ipol) - else - xs = ZERO - end if - case('kappa_fission') - if (allocated(this % k_fission)) then - xs = this % k_fission(gin, iazi, ipol) - else - xs = ZERO - end if - case('nu_fission') - xs = this % nu_fission(gin, iazi, ipol) - case('chi') - if (present(gout)) then - xs = this % chi(gout, gin, iazi, ipol) - else - ! Not sure you would want a 1 or a 0, but here you go! - xs = sum(this % chi(:, gin, iazi, ipol)) - end if - case('scatter') - if (present(gout)) then - if (gout < this % scatter(iazi, ipol) % obj % gmin(gin) .or. & - gout > this % scatter(iazi, ipol) % obj % gmax(gin)) then - xs = ZERO else - xs = this % scatter(iazi, ipol) % obj % scattxs(gin) * & - this % scatter(iazi, ipol) % obj % energy(gin) % data(gout) + ! chi isnt provided but is within nu_fission, existing as a matrix + ! So, get nu_fission (as a matrix) + if (object_exists(xsdata_grp, "nu-fission")) then + allocate(temp_2d(groups, groups)) + call read_dataset(temp_2d, xsdata_grp, "nu-fission") + else + call fatal_error("If fissionable, must provide nu-fission!") + end if + + ! Set the vector nu-fission from the matrix nu-fission + do gin = 1, groups + xs % nu_fission(gin) = sum(temp_2d(:, gin)) + end do + + ! Now pull out information needed for chi + xs % chi(:, :) = temp_2d + ! Normalize chi so its CDF goes to 1 + do gin = 1, groups + xs % chi(:, gin) = xs % chi(:, gin) / sum(xs % chi(:, gin)) + end do + deallocate(temp_2d) end if - else - xs = this % scatter(iazi, ipol) % obj % scattxs(gin) - end if - case('scatter/mult') - if (present(gout)) then - if (gout < this % scatter(iazi, ipol) % obj % gmin(gin) .or. & - gout > this % scatter(iazi, ipol) % obj % gmax(gin)) then - xs = ZERO - else - xs = this % scatter(iazi, ipol) % obj % scattxs(gin) * & - this % scatter(iazi, ipol) % obj % energy(gin) % data(gout) / & - this % scatter(iazi, ipol) % obj % mult(gin) % data(gout) + + ! If we have a need* for the fission and kappa-fission x/s, get them + ! (*Need is defined as will be using it to tally) + if (get_fiss) then + if (object_exists(xsdata_grp, "fission")) then + allocate(xs % fission(groups)) + call read_dataset(xs % fission, xsdata_grp, "fission") + else + call fatal_error("Fission data missing, required due to fission& + & tallies in tallies.xml file!") + end if end if - else - xs = this % scatter(iazi, ipol) % obj % scattxs(gin) / & - (dot_product(this % scatter(iazi, ipol) % obj % mult(gin) % data, & - this % scatter(iazi, ipol) % obj % energy(gin) % data)) - end if - case('scatter*f_mu/mult','scatter*f_mu') - if (present(gout)) then - if (gout < this % scatter(iazi, ipol) % obj % gmin(gin) .or. & - gout > this % scatter(iazi, ipol) % obj % gmax(gin)) then - xs = ZERO - else - xs = this % scatter(iazi, ipol) % obj % scattxs(gin) * & - this % scatter(iazi, ipol) % obj % energy(gin) % data(gout) - xs = xs * this % scatter(iazi, ipol) % obj % calc_f(gin, gout, mu) - if (xstype == 'scatter*f_mu/mult') then - xs = xs / & - this % scatter(iazi, ipol) % obj % mult(gin) % data(gout) + if (get_kfiss) then + if (object_exists(xsdata_grp, "kappa-fission")) then + allocate(xs % k_fission(groups)) + call read_dataset(xs % k_fission, xsdata_grp, "kappa-fission") + else + call fatal_error("kappa-fission data missing, required due to & + &kappa-fission tallies in tallies.xml file!") end if end if else - xs = ZERO - ! TODO (Not likely needed) - ! (asking for f_mu without asking for a group or mu would mean the - ! user of this code wants the complete 1-outgoing group distribution - ! which Im not sure what they would do with that. + xs % nu_fission = ZERO + xs % chi = ZERO end if - case default - xs = ZERO - end select - else - xs = ZERO - end if - end function mgxsang_get_xs + if (object_exists(xsdata_grp, "absorption")) then + allocate(xs % absorption(groups)) + call read_dataset(xs % absorption, xsdata_grp, "absorption") + else + call fatal_error("Must provide absorption!") + end if + + ! Get scattering data + if (.not. object_exists(xsdata_grp, "scatter_data")) & + call fatal_error("Must provide 'scatter_data'") + scatt_grp = open_group(xsdata_grp, 'scatter_data') + ! First get the outgoing group boundary indices + if (object_exists(scatt_grp, "g_min")) then + allocate(gmin(groups)) + call read_dataset(gmin, scatt_grp, "g_min") + else + call fatal_error("'g_min' for the scatter_data must be provided") + end if + if (object_exists(scatt_grp, "g_max")) then + allocate(gmax(groups)) + call read_dataset(gmax, scatt_grp, "g_max") + else + call fatal_error("'g_max' for the scatter_data must be provided") + end if + + ! Now use this information to find the length of a container array + ! to hold the flattened data + length = 0 + do gin = 1, groups + length = length + order_dim * (gmax(gin) - gmin(gin) + 1) + end do + ! Allocate flattened array + allocate(temp_arr(length)) + if (.not. object_exists(scatt_grp, 'scatter_matrix')) & + call fatal_error("'scatter_matrix' must be provided") + call read_dataset(temp_arr, scatt_grp, "scatter_matrix") + + ! Compare the number of orders given with the maximum order of the + ! problem. Strip off the supefluous orders if needed. + if (this % scatter_format == ANGLE_LEGENDRE) then + order = min(order_dim - 1, max_order) + order_dim = order + 1 + end if + + ! Convert temp_arr to a jagged array ((gin) % data(l, gout)) for passing + ! to ScattData + allocate(input_scatt(groups)) + index = 1 + do gin = 1, groups + allocate(input_scatt(gin) % data(order_dim, gmin(gin):gmax(gin))) + do gout = gmin(gin), gmax(gin) + do l = 1, order_dim + input_scatt(gin) % data(l, gout) = temp_arr(index) + index = index + 1 + end do + end do + end do + deallocate(temp_arr) + + ! Finally convert the legendre to tabular if needed + allocate(scatt_coeffs(groups)) + if (this % scatter_format == ANGLE_LEGENDRE .and. & + legendre_to_tabular) then + this % scatter_format = ANGLE_TABULAR + order_dim = legendre_to_tabular_points + order = order_dim + dmu = TWO / real(order - 1, 8) + do gin = 1, groups + allocate(scatt_coeffs(gin) % data(order_dim, gmin(gin):gmax(gin))) + do gout = gmin(gin), gmax(gin) + norm = ZERO + do imu = 1, order_dim + if (imu == 1) then + mu = -ONE + else if (imu == order_dim) then + mu = ONE + else + mu = -ONE + real(imu - 1, 8) * dmu + end if + scatt_coeffs(gin) % data(imu, gout) = & + evaluate_legendre(input_scatt(gin) % data(:, gout), mu) + ! Ensure positivity of distribution + if (scatt_coeffs(gin) % data(imu, gout) < ZERO) & + scatt_coeffs(gin) % data(imu, gout) = ZERO + ! And accrue the integral + if (imu > 1) then + norm = norm + HALF * dmu * & + (scatt_coeffs(gin) % data(imu - 1, gout) + & + scatt_coeffs(gin) % data(imu, gout)) + end if + end do ! mu + ! Now that we have the integral, lets ensure that the distribution + ! is normalized such that it preserves the original scattering xs + if (norm > ZERO) then + scatt_coeffs(gin) % data(:, gout) = & + scatt_coeffs(gin) % data(:, gout) * & + input_scatt(gin) % data(1, gout) / norm + end if + end do ! gout + end do ! gin + else + ! Sticking with current representation + do gin = 1, groups + allocate(scatt_coeffs(gin) % data(order_dim, gmin(gin):gmax(gin))) + scatt_coeffs(gin) % data(:, :) = & + input_scatt(gin) % data(1:order_dim, :) + end do + end if + deallocate(input_scatt) + + ! Now get the multiplication matrix + if (object_exists(scatt_grp, 'multiplicity_matrix')) then + ! Now use this information to find the length of a container array + ! to hold the flattened data + length = 0 + do gin = 1, groups + length = length + (gmax(gin) - gmin(gin) + 1) + end do + ! Allocate flattened array + allocate(temp_arr(length)) + call read_dataset(temp_arr, scatt_grp, "multiplicity_matrix") + + ! Convert temp_arr to a jagged array ((gin) % data(gout)) for passing + ! to ScattData + allocate(temp_mult(groups)) + index = 1 + do gin = 1, groups + allocate(temp_mult(gin) % data(gmin(gin):gmax(gin))) + do gout = gmin(gin), gmax(gin) + temp_mult(gin) % data(gout) = temp_arr(index) + index = index + 1 + end do + end do + deallocate(temp_arr) + else + ! Default to multiplicities of 1.0 + allocate(temp_mult(groups)) + do gin = 1, groups + allocate(temp_mult(gin) % data(gmin(gin):gmax(gin))) + temp_mult(gin) % data = ONE + end do + end if + + ! Allocate and initialize our ScattData Object. + if (this % scatter_format == ANGLE_HISTOGRAM) then + allocate(ScattDataHistogram :: xs % scatter) + else if (this % scatter_format == ANGLE_TABULAR) then + allocate(ScattDataTabular :: xs % scatter) + else if (this % scatter_format == ANGLE_LEGENDRE) then + allocate(ScattDataLegendre :: xs % scatter) + end if + + ! Initialize the ScattData Object + call xs % scatter % init(gmin, gmax, temp_mult, scatt_coeffs) + + ! Check sigA to ensure it is not 0 since it is + ! often divided by in the tally routines + ! (This may happen with Helium data) + do gin = 1, groups + if (xs % absorption(gin) == ZERO) xs % absorption(gin) = 1E-10_8 + end do + + ! Get, or infer, total xs data. + allocate(xs % total(groups)) + if (object_exists(xsdata_grp, "total")) then + call read_dataset(xs % total, xsdata_grp, "total") + else + xs % total(:) = xs % absorption(:) + xs % scatter % scattxs(:) + end if + + ! Check sigT to ensure it is not 0 since it is + ! often divided by in the tally routines + do gin = 1, groups + if (xs % total(gin) == ZERO) xs % total(gin) = 1E-10_8 + end do + + ! Get kinetics data + if (object_exists(xsdata_grp, "inverse_velocities")) then + allocate(xs % inv_vel(groups)) + call read_dataset(xs % inv_vel, xsdata_grp, "inverse_velocities") + end if + + ! Close the groups we have opened and deallocate + call close_group(xsdata_grp) + call close_group(scatt_grp) + deallocate(scatt_coeffs, temp_mult) + end associate ! xs + end do ! Temperatures + end subroutine mgxsiso_from_hdf5 + + subroutine mgxsang_from_hdf5(this, xs_id, groups, temperature, method, & + tolerance, get_kfiss, get_fiss, max_order, & + legendre_to_tabular, legendre_to_tabular_points) + class(MgxsAngle), intent(inout) :: this ! Working Object + integer(HID_T), intent(in) :: xs_id ! Group in H5 file + integer, intent(in) :: groups ! Number of Energy groups + type(VectorReal), intent(in) :: temperature ! list of desired temperatures + integer, intent(inout) :: method ! Type of temperature access + real(8), intent(in) :: tolerance ! Tolerance on method + logical, intent(in) :: get_kfiss ! Need Kappa-Fission? + logical, intent(in) :: get_fiss ! Should we get fiss data? + integer, intent(in) :: max_order ! Maximum requested order + logical, intent(in) :: legendre_to_tabular ! Convert Legendres to Tabular? + integer, intent(in) :: legendre_to_tabular_points ! Number of points to use + ! in that conversion + + character(MAX_LINE_LEN) :: temp_str + integer(HID_T) :: xsdata_grp, scatt_grp + integer, allocatable :: int_arr(:) + real(8), allocatable :: temp_arr(:), temp_4d(:, :, :, :) + real(8) :: dmu, mu, norm + integer :: order, order_dim, gin, gout, l, imu + type(VectorInt) :: temps_to_read + integer :: t, length, ipol, iazi + type(Jagged2D), allocatable :: input_scatt(:, :, :), scatt_coeffs(:, :, :) + type(Jagged1D), allocatable :: temp_mult(:, :, :) + integer, allocatable :: gmin(:, :, :), gmax(:, :, :) + + ! Call generic data gathering routine (will populate the metadata) + call mgxs_from_hdf5(this, xs_id, temperature, method, tolerance, & + temps_to_read, order_dim) + + ! Load the more specific data + do t = 1, temps_to_read % size() + associate(xs => this % xs(t)) + ! Get temperature as a string + temp_str = trim(to_str(temps_to_read % data(t))) // "K" + xsdata_grp = open_group(xs_id, trim(temp_str)) + allocate(xs % nu_fission(groups, this % n_azi, this % n_pol)) + allocate(xs % chi(groups, groups, this % n_azi, this % n_pol)) + if (this % fissionable) then + if (object_exists(xsdata_grp, "chi")) then + ! Chi was provided, that means we need chi and nu-fission vectors + ! Get chi + allocate(temp_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, xsdata_grp, "chi") + ! Initialize counter for temp_arr + l = 0 + gin = 1 + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gout = 1, groups + l = l + 1 + xs % chi(gout, gin, iazi, ipol) = temp_arr(l) + end do + ! Normalize chi so its CDF goes to 1 + xs % chi(:, gin, iazi, ipol) = & + xs % chi(:, gin, iazi, ipol) / & + sum(xs % chi(:, gin, iazi, ipol)) + end do + end do + + ! Now set all the other gin values + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 2, groups + xs % chi(:, gin, iazi, ipol) = & + xs % chi(:, 1, iazi, ipol) + end do + end do + end do + deallocate(temp_arr) + + ! Get nu_fission (as a vector) + if (object_exists(xsdata_grp, "nu-fission")) then + allocate(temp_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, xsdata_grp, "nu-fission") + xs % nu_fission = reshape(temp_arr, (/groups, this % n_azi, & + this % n_pol/)) + deallocate(temp_arr) + else + call fatal_error("If fissionable, must provide nu-fission!") + end if + + else + ! chi isnt provided but is within nu_fission, existing as a matrix + ! So, get nu_fission (as a matrix) + if (object_exists(xsdata_grp, "nu-fission")) then + allocate(temp_arr(groups * groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, xsdata_grp, "nu-fission") + allocate(temp_4d(groups, groups, this % n_azi, this % n_pol)) + temp_4d(:, :, :, :) = reshape(temp_arr, (/groups, groups, & + this % n_azi, this % n_pol/)) + deallocate(temp_arr) + else + call fatal_error("If fissionable, must provide nu-fission!") + end if + + ! Set the vector nu-fission from the matrix nu-fission + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + xs % nu_fission(gin, iazi, ipol) = & + sum(temp_4d(:, gin, iazi, ipol)) + end do + end do + end do + + ! Now pull out information needed for chi + xs % chi = temp_4d + ! Normalize chi so its CDF goes to 1 + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + xs % chi(:, gin, iazi, ipol) = & + xs % chi(:, gin, iazi, ipol) / & + sum(xs % chi(:, gin, iazi, ipol)) + end do + end do + end do + deallocate(temp_4d) + end if + + ! If we have a need* for the fission and kappa-fission x/s, get them + ! (*Need is defined as will be using it to tally) + if (get_fiss) then + if (object_exists(xsdata_grp, "fission")) then + allocate(temp_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, xsdata_grp, "fission") + allocate(xs % fission(groups, this % n_azi, this % n_pol)) + xs % fission = reshape(temp_arr, (/groups, this % n_azi, & + this % n_pol/)) + deallocate(temp_arr) + else + call fatal_error("Fission data missing, required due to fission& + & tallies in tallies.xml file!") + end if + end if + if (get_kfiss) then + if (object_exists(xsdata_grp, "kappa-fission")) then + allocate(temp_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, xsdata_grp, "kappa-fission") + allocate(xs % k_fission(groups, this % n_azi, this % n_pol)) + xs % k_fission = reshape(temp_arr, (/groups, this % n_azi, & + this % n_pol/)) + deallocate(temp_arr) + else + call fatal_error("kappa_fission data missing, required due to & + &kappa-fission tallies in tallies.xml file!") + end if + end if + else + xs % nu_fission = ZERO + xs % chi = ZERO + end if + + if (object_exists(xsdata_grp, "absorption")) then + allocate(temp_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, xsdata_grp, "absorption") + allocate(xs % absorption(groups, this % n_azi, this % n_pol)) + xs % absorption = reshape(temp_arr, (/groups, this % n_azi, & + this % n_pol/)) + deallocate(temp_arr) + else + call fatal_error("Must provide absorption!") + end if + + ! Get scattering data + if (.not. object_exists(xsdata_grp, "scatter_data")) & + call fatal_error("Must provide 'scatter_data'") + scatt_grp = open_group(xsdata_grp, 'scatter_data') + ! First get the outgoing group boundary indices + if (object_exists(scatt_grp, "g_min")) then + allocate(int_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(int_arr, scatt_grp, "g_min") + allocate(gmin(groups, this % n_azi, this % n_pol)) + gmin = reshape(int_arr, (/groups, this % n_azi, this % n_pol/)) + deallocate(int_arr) + else + call fatal_error("'g_min' for the scatter_data must be provided") + end if + if (object_exists(scatt_grp, "g_max")) then + allocate(int_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(int_arr, scatt_grp, "g_max") + allocate(gmax(groups, this % n_azi, this % n_pol)) + gmax = reshape(int_arr, (/groups, this % n_azi, this % n_pol/)) + deallocate(int_arr) + else + call fatal_error("'g_max' for the scatter_data must be provided") + end if + + ! Now use this information to find the length of a container array + ! to hold the flattened data + length = 0 + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + length = length + order_dim * (gmax(gin, iazi, ipol) - & + gmin(gin, iazi, ipol) + 1) + end do + end do + end do + ! Allocate flattened array + allocate(temp_arr(length)) + if (.not. object_exists(scatt_grp, 'scatter_matrix')) & + call fatal_error("'scatter_matrix' must be provided") + call read_dataset(temp_arr, scatt_grp, "scatter_matrix") + + ! Compare the number of orders given with the maximum order of the + ! problem. Strip off the superfluous orders if needed. + if (this % scatter_format == ANGLE_LEGENDRE) then + order = min(order_dim - 1, max_order) + order_dim = order + 1 + end if + + ! Convert temp_arr to a jagged array ((gin) % data(l, gout)) for passing + ! to ScattData + allocate(input_scatt(groups, this % n_azi, this % n_pol)) + index = 1 + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + allocate(input_scatt(gin, iazi, ipol) % data(order_dim, & + gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) + do gout = gmin(gin, iazi, ipol), gmax(gin, iazi, ipol) + do l = 1, order_dim + input_scatt(gin, iazi, ipol) % data(l, gout) = & + temp_arr(index) + index = index + 1 + end do ! gout + end do ! order + end do ! gin + end do ! iazi + end do ! ipol + deallocate(temp_arr) + + ! Finally convert the legendre to tabular if needed + allocate(scatt_coeffs(groups, this % n_azi, this % n_pol)) + if (this % scatter_format == ANGLE_LEGENDRE .and. & + legendre_to_tabular) then + this % scatter_format = ANGLE_TABULAR + order_dim = legendre_to_tabular_points + order = order_dim + dmu = TWO / real(order - 1, 8) + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + allocate(scatt_coeffs(gin, iazi, ipol) % data(& + order_dim, & + gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) + do gout = gmin(gin, iazi, ipol), gmax(gin, iazi, ipol) + norm = ZERO + do imu = 1, order_dim + if (imu == 1) then + mu = -ONE + else if (imu == order_dim) then + mu = ONE + else + mu = -ONE + real(imu - 1, 8) * dmu + end if + scatt_coeffs(gin, iazi, ipol) % data(imu, gout) = & + evaluate_legendre(& + input_scatt(gin, iazi, ipol) % data(:, gout), mu) + ! Ensure positivity of distribution + if (scatt_coeffs(gin, iazi, ipol) % data(imu, gout) < ZERO) & + scatt_coeffs(gin, iazi, ipol) % data(imu, gout) = ZERO + ! And accrue the integral + if (imu > 1) then + norm = norm + HALF * dmu * & + (scatt_coeffs(gin, iazi, ipol) % data(imu - 1, gout) + & + scatt_coeffs(gin, iazi, ipol) % data(imu, gout)) + end if + end do ! mu + ! Now that we have the integral, lets ensure that the distribution + ! is normalized such that it preserves the original scattering xs + if (norm > ZERO) then + scatt_coeffs(gin, iazi, ipol) % data(:, gout) = & + scatt_coeffs(gin, iazi, ipol) % data(:, gout) * & + input_scatt(gin, iazi, ipol) % data(1, gout) / & + norm + end if + end do ! gout + end do ! gin + end do ! iazi + end do ! ipol + else + ! Sticking with current representation, carry forward + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + allocate(scatt_coeffs(gin, iazi, ipol) % data(order_dim, & + gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) + scatt_coeffs(gin, iazi, ipol) % data(:, :) = & + input_scatt(gin, iazi, ipol) % data(1:order_dim, :) + end do + end do + end do + end if + deallocate(input_scatt) + + ! Now get the multiplication matrix + if (object_exists(scatt_grp, 'multiplicity_matrix')) then + ! Now use this information to find the length of a container array + ! to hold the flattened data + length = 0 + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + length = length + (gmax(gin, iazi, ipol) - gmin(gin, iazi, ipol) + 1) + end do + end do + end do + ! Allocate flattened array + allocate(temp_arr(length)) + call read_dataset(temp_arr, scatt_grp, "multiplicity_matrix") + ! Convert temp_arr to a jagged array ((gin) % data(gout)) for passing + ! to ScattData + allocate(temp_mult(groups, this % n_azi, this % n_pol)) + index = 1 + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + allocate(temp_mult(gin, iazi, ipol) % data( & + gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) + do gout = gmin(gin, iazi, ipol), gmax(gin, iazi, ipol) + temp_mult(gin, iazi, ipol) % data(gout) = temp_arr(index) + index = index + 1 + end do + end do + end do + end do + deallocate(temp_arr) + else + allocate(temp_mult(groups, this % n_azi, this % n_pol)) + ! Default to multiplicities of 1.0 + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + allocate(temp_mult(gin, iazi, ipol) % data( & + gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) + temp_mult(gin, iazi, ipol) % data = ONE + end do + end do + end do + end if + + ! Allocate and initialize our ScattData Object. + allocate(xs % scatter(this % n_azi, this % n_pol)) + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + ! Allocate and initialize our ScattData Object. + if (this % scatter_format == ANGLE_HISTOGRAM) then + allocate(ScattDataHistogram :: xs % scatter(iazi, ipol) % obj) + else if (this % scatter_format == ANGLE_TABULAR) then + allocate(ScattDataTabular :: xs % scatter(iazi, ipol) % obj) + else if (this % scatter_format == ANGLE_LEGENDRE) then + allocate(ScattDataLegendre :: xs % scatter(iazi, ipol) % obj) + end if + + ! Initialize the ScattData Object + call xs % scatter(iazi, ipol) % obj % init(gmin(:, iazi, ipol), & + gmax(:, iazi, ipol), temp_mult(:, iazi, ipol), & + scatt_coeffs(:, iazi, ipol)) + end do + end do + + ! Check sigA to ensure it is not 0 since it is + ! often divided by in the tally routines + ! (This may happen with Helium data) + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + if (xs % absorption(gin, iazi, ipol) == ZERO) then + xs % absorption(gin, iazi, ipol) = 1E-10_8 + end if + end do + end do + end do + + allocate(xs % total(groups, this % n_azi, this % n_pol)) + if (object_exists(xsdata_grp, "total")) then + allocate(temp_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, xsdata_grp, "total") + xs % total = reshape(temp_arr, (/groups, this % n_azi, & + this % n_pol/)) + deallocate(temp_arr) + else + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + xs % total(:, iazi, ipol) = xs % absorption(:, iazi, ipol) + & + xs % scatter(iazi, ipol) % obj % scattxs(:) + end do + end do + end if + + ! Check sigT to ensure it is not 0 since it is often divided by in + ! the tally routines + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + if (xs % total(gin, iazi, ipol) == ZERO) then + xs % total(gin, iazi, ipol) = 1E-10_8 + end if + end do + end do + end do + + ! Get kinetics data + if (object_exists(xsdata_grp, "inverse_velocities")) then + allocate(xs % inv_vel(groups, this % n_azi, this % n_pol)) + allocate(temp_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, xsdata_grp, "inverse_velocities") + xs % inv_vel = reshape(temp_arr, (/groups, this % n_azi, & + this % n_pol/)) + deallocate(temp_arr) + end if + + ! Close the groups we have opened and deallocate + call close_group(xsdata_grp) + call close_group(scatt_grp) + deallocate(scatt_coeffs, temp_mult) + end associate ! xs + end do ! Temperatures + end subroutine mgxsang_from_hdf5 !=============================================================================== -! MACROXS*_COMBINE Builds a macroscopic Mgxs object from microscopic Mgxs -! objects +! MGXS*_COMBINE Builds a macroscopic Mgxs object from microscopic Mgxs objects !=============================================================================== - subroutine mgxs_combine(this, mat, scatt_type) + subroutine mgxs_combine(this, temps, mat, nuclides, max_order, & + scatter_format, order_dim) class(Mgxs), intent(inout) :: this ! The Mgxs to initialize + type(VectorReal), intent(in) :: temps ! Temperatures to obtain type(Material), pointer, intent(in) :: mat ! base material - integer, intent(in) :: scatt_type ! How is data presented + type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from + integer, intent(in) :: max_order ! Maximum requested order + integer, intent(out) :: scatter_format ! Type of scatter + integer, intent(out) :: order_dim ! Scattering data order size + + integer :: t, mat_max_order, order ! Fill in meta-data from material information if (mat % name == "") then - this % name = trim(to_str(mat % id)) + this % name = trim(to_str(mat % id)) else - this % name = mat % name + this % name = trim(mat % name) end if this % fissionable = mat % fissionable - this % scatt_type = scatt_type ! The following info we should initialize, but we dont need it nor ! does it have guaranteed meaning. this % awr = -ONE - this % kT = -ONE - end subroutine mgxs_combine + allocate(this % kTs(temps % size())) + do t = 1, temps % size() + this % kTs(t) = temps % data(t) + end do - subroutine mgxsiso_combine(this, mat, nuclides, groups, max_order, scatt_type) - class(MgxsIso), intent(inout) :: this ! The Mgxs to initialize - type(Material), pointer, intent(in) :: mat ! base material - type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from - integer, intent(in) :: groups ! Number of E groups - integer, intent(in) :: max_order ! Maximum requested order - integer, intent(in) :: scatt_type ! How is data presented - - integer :: i ! loop index over nuclides - integer :: gin, gout ! group indices - real(8) :: atom_density ! atom density of a nuclide - real(8) :: norm, nuscatt - integer :: mat_max_order, order, order_dim, nuc_order_dim - real(8), allocatable :: temp_mult(:, :), mult_num(:, :), mult_denom(:, :) - real(8), allocatable :: scatt_coeffs(:, :, :) - - ! Set the meta-data - call mgxs_combine(this, mat, scatt_type) + ! Allocate the XS object for the number of temperatures + select type(this) + type is (MgxsIso) + allocate(this % xs(temps % size())) + type is (MgxsAngle) + allocate(this % xs(temps % size())) + end select ! Determine the scattering type of our data and ensure all scattering orders ! are the same. + scatter_format = nuclides(mat % nuclide(1)) % obj % scatter_format select type(nuc => nuclides(mat % nuclide(1)) % obj) type is (MgxsIso) - order = size(nuc % scatter % dist(1) % data, dim=1) + order = size(nuc % xs(1) % scatter % dist(1) % data, dim=1) + type is (MgxsAngle) + order = size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, dim=1) end select ! If we have tabular only data, then make sure all datasets have same size - if (scatt_type == ANGLE_HISTOGRAM) then + if (scatter_format == ANGLE_HISTOGRAM) then ! Check all scattering data to ensure it is the same size do i = 2, mat % n_nuclides select type(nuc => nuclides(mat % nuclide(i)) % obj) type is (MgxsIso) - if (order /= size(nuc % scatter % dist(1) % data, dim=1)) & + if (order /= size(nuc % xs(1) % scatter % dist(1) % data, dim=1)) & + call fatal_error("All histogram scattering entries must be& + & same length!") + type is (MgxsAngle) + if (order /= size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, dim=1)) & call fatal_error("All histogram scattering entries must be& & same length!") end select end do ! Ok, got our order, store the dimensionality order_dim = order - - ! Set our Scatter Object Type - allocate(ScattDataHistogram :: this % scatter) - - else if (scatt_type == ANGLE_TABULAR) then + else if (scatter_format == ANGLE_TABULAR) then ! Check all scattering data to ensure it is the same size do i = 2, mat % n_nuclides select type(nuc => nuclides(mat % nuclide(i)) % obj) type is (MgxsIso) - if (order /= size(nuc % scatter % dist(1) % data, dim=1)) & + if (order /= size(nuc % xs(1) % scatter % dist(1) % data, dim=1)) & + call fatal_error("All tabular scattering entries must be& + & same length!") + type is (MgxsAngle) + if (order /= size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, dim=1)) & call fatal_error("All tabular scattering entries must be& & same length!") end select end do ! Ok, got our order, store the dimensionality order_dim = order - - ! Set our Scatter Object Type - allocate(ScattDataTabular :: this % scatter) - - else if (scatt_type == ANGLE_LEGENDRE) then + else if (scatter_format == ANGLE_LEGENDRE) then ! Need to determine the maximum scattering order of all data in this material mat_max_order = 0 do i = 1, mat % n_nuclides select type(nuc => nuclides(mat % nuclide(i)) % obj) type is (MgxsIso) - if (size(nuc % scatter % dist(1) % data, dim=1) > mat_max_order) & - mat_max_order = size(nuc % scatter % dist(1) % data, dim=1) + if (size(nuc % xs(1) % scatter % dist(1) % data, & + dim=1) > mat_max_order) & + mat_max_order = size(nuc % xs(1) % scatter % dist(1) % data, & + dim=1) + type is (MgxsAngle) + if (size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, & + dim=1) > mat_max_order) & + mat_max_order = & + size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, & + dim=1) end select end do @@ -1229,146 +1231,279 @@ module mgxs_header ! the problem wide max scatt order and use whichever is lower order = min(mat_max_order, max_order) ! Ok, got our order, store the dimensionality - order_dim = order + 1 - - ! Set our Scatter Object Type - allocate(ScattDataLegendre :: this % scatter) + order_dim = order end if - ! Allocate and initialize data needed for macro_xs(i_mat) object - allocate(this % total(groups)) - this % total(:) = ZERO - allocate(this % absorption(groups)) - this % absorption(:) = ZERO - allocate(this % fission(groups)) - this % fission(:) = ZERO - allocate(this % k_fission(groups)) - this % k_fission(:) = ZERO - allocate(this % nu_fission(groups)) - this % nu_fission(:) = ZERO - allocate(this % chi(groups,groups)) - this % chi(:, :) = ZERO - allocate(temp_mult(groups,groups)) - temp_mult(:, :) = ZERO - allocate(mult_num(groups,groups)) - mult_num(:, :) = ZERO - allocate(mult_denom(groups,groups)) - mult_denom(:, :) = ZERO - allocate(scatt_coeffs(order_dim,groups,groups)) - scatt_coeffs(:, :, :) = ZERO + end subroutine mgxs_combine - ! Add contribution from each nuclide in material - do i = 1, mat % n_nuclides - ! Copy atom density of nuclide in material - atom_density = mat % atom_density(i) - - ! Perform our operations which depend upon the type - select type(nuc => nuclides(mat % nuclide(i)) % obj) - type is (MgxsIso) - ! Add contributions to total, absorption, and fission data (if necessary) - this % total(:) = this % total(:) + atom_density * nuc % total(:) - this % absorption(:) = this % absorption(:) + & - atom_density * nuc % absorption(:) - if (nuc % fissionable) then - this % chi(:, :) = this % chi(:, :) + atom_density * nuc % chi(:, :) - this % nu_fission(:) = this % nu_fission(:)+ atom_density * & - nuc % nu_fission(:) - if (allocated(nuc % fission)) then - this % fission(:) = this % fission(:) + atom_density * nuc % fission(:) - end if - if (allocated(nuc % k_fission)) then - this % k_fission(:) = this % k_fission(:) + atom_density * & - nuc % k_fission(:) - end if - end if - - ! Get the multiplication matrix - ! To combine from nuclidic data we need to use the final relationship - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - ! Developed as follows: - ! mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - ! nuscatt_{i,g,g'} can be reconstructed from scatter % energy and - ! scatter % scattxs - do gin = 1, groups - do gout = nuc % scatter % gmin(gin), nuc % scatter % gmax(gin) - nuscatt = nuc % scatter % scattxs(gin) * & - nuc % scatter % energy(gin) % data(gout) - mult_num(gout, gin) = mult_num(gout, gin) + atom_density * & - nuscatt - if (nuc % scatter % mult(gin) % data(gout) > ZERO) then - mult_denom(gout, gin) = mult_denom(gout,gin) + atom_density * & - nuscatt / nuc % scatter % mult(gin) % data(gout) - else - ! Avoid division by zero - mult_denom(gout, gin) = mult_denom(gout,gin) + atom_density - end if - end do - end do - - ! Get the complete scattering matrix - nuc_order_dim = size(nuc % scatter % dist(1) % data, dim=1) - scatt_coeffs(1:min(nuc_order_dim, order_dim), :, :) = & - scatt_coeffs(1:min(nuc_order_dim, order_dim), :, :) + & - atom_density * & - nuc % scatter % get_matrix(min(nuc_order_dim, order_dim)) - - type is (MgxsAngle) - call fatal_error("Invalid passing of MgxsAngle to MgxsIso object") - end select - end do - - ! Obtain temp_mult - do gin = 1, groups - do gout = 1, groups - if (mult_denom(gout, gin) > ZERO) then - temp_mult(gout, gin) = mult_num(gout, gin) / mult_denom(gout, gin) - else - temp_mult(gout, gin) = ONE - end if - end do - end do - - ! Initialize the ScattData Object - call this % scatter % init(temp_mult, scatt_coeffs) - - ! Now normalize chi - if (mat % fissionable) then - do gin = 1, groups - norm = sum(this % chi(:, gin)) - if (norm > ZERO) then - this % chi(:, gin) = this % chi(:, gin) / norm - end if - end do - end if - - ! Deallocate temporaries - deallocate(scatt_coeffs, temp_mult, mult_num, mult_denom) - - end subroutine mgxsiso_combine - - subroutine mgxsang_combine(this, mat, nuclides, groups, max_order, scatt_type) - class(MgxsAngle), intent(inout) :: this ! The Mgxs to initialize + subroutine mgxsiso_combine(this, temps, mat, nuclides, groups, max_order, & + tolerance, method) + class(MgxsIso), intent(inout) :: this ! The Mgxs to initialize + type(VectorReal), intent(in) :: temps ! Temperatures to obtain [MeV] type(Material), pointer, intent(in) :: mat ! base material type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from integer, intent(in) :: groups ! Number of E groups integer, intent(in) :: max_order ! Maximum requested order - integer, intent(in) :: scatt_type ! Legendre or Tabular Scatt? + real(8), intent(in) :: tolerance ! Tolerance on method + integer, intent(in) :: method ! Type of temperature access + + integer :: i ! loop index over nuclides + integer :: t ! Index in to temps + integer :: gin, gout ! group indices + real(8) :: atom_density ! atom density of a nuclide + real(8) :: norm, nuscatt + integer :: order_dim, nuc_order_dim + real(8), allocatable :: temp_mult(:, :), mult_num(:, :), mult_denom(:, :) + real(8), allocatable :: scatt_coeffs(:, :, :) + integer :: nuc_t + integer, allocatable :: nuc_ts(:) + real(8) :: temp_actual, temp_desired, interp + integer :: scatter_format + type(Jagged2D), allocatable :: nuc_matrix(:) + integer, allocatable :: gmin(:), gmax(:) + type(Jagged2D), allocatable :: jagged_scatt(:) + type(Jagged1D), allocatable :: jagged_mult(:) + + ! Set the meta-data + call mgxs_combine(this, temps, mat, nuclides, max_order, scatter_format, & + order_dim) + + ! Create the Xs Data for each temperature + TEMP_LOOP: do t = 1, temps % size() + ! Allocate and initialize the data needed for macro_xs(i_mat) object + allocate(this % xs(t) % total(groups)) + this % xs(t) % total(:) = ZERO + allocate(this % xs(t) % absorption(groups)) + this % xs(t) % absorption(:) = ZERO + allocate(this % xs(t) % fission(groups)) + this % xs(t) % fission(:) = ZERO + allocate(this % xs(t) % k_fission(groups)) + this % xs(t) % k_fission(:) = ZERO + allocate(this % xs(t) % nu_fission(groups)) + this % xs(t) % nu_fission(:) = ZERO + allocate(this % xs(t) % chi(groups,groups)) + this % xs(t) % chi(:, :) = ZERO + allocate(this % xs(t) % inv_vel(groups)) + this % xs(t) % inv_vel(:) = ZERO + allocate(temp_mult(groups,groups)) + temp_mult(:, :) = ZERO + allocate(mult_num(groups,groups)) + mult_num(:, :) = ZERO + allocate(mult_denom(groups,groups)) + mult_denom(:, :) = ZERO + allocate(scatt_coeffs(order_dim,groups,groups)) + scatt_coeffs(:, :, :) = ZERO + + this % scatter_format = scatter_format + if (scatter_format == ANGLE_LEGENDRE) then + allocate(ScattDataLegendre :: this % xs(t) % scatter) + else if (scatter_format == ANGLE_TABULAR) then + allocate(ScattDataTabular :: this % xs(t) % scatter) + else if (scatter_format == ANGLE_HISTOGRAM) then + allocate(ScattDataHistogram :: this % xs(t) % scatter) + end if + + ! Add contribution from each nuclide in material + NUC_LOOP: do i = 1, mat % n_nuclides + associate(nuc => nuclides(mat % nuclide(i)) % obj) + ! Copy atom density of nuclide in material + atom_density = mat % atom_density(i) + + select case (method) + case (TEMPERATURE_NEAREST) + ! Determine actual temperatures to read + temp_desired = temps % data(i) + allocate(nuc_ts(1)) + nuc_ts(1) = minloc(abs(nuc % kTs - temp_desired), dim=1) + temp_actual = nuc % kTs(nuc_ts(1)) + if (abs(temp_actual - temp_desired) >= K_BOLTZMANN * tolerance) then + call fatal_error("MGXS library does not contain cross sections & + &for " // trim(this % name) // " at or near " // & + trim(to_str(nint(temp_desired / K_BOLTZMANN))) // " K.") + end if + + case (TEMPERATURE_INTERPOLATION) + ! If temperature interpolation or multipole is selected, get a + ! list of bounding temperatures for each actual temperature + ! present in the model + temp_desired = temps % data(i) + allocate(nuc_ts(2)) + do j = 1, size(nuc % kTs) - 1 + if (nuc % kTs(j) <= temp_desired .and. & + temp_desired < nuc % kTs(j + 1)) then + nuc_ts(1) = j + nuc_ts(2) = j + 1 + end if + end do + + call fatal_error("Nuclear data library does not contain cross sections & + &for " // trim(this % name) // " at temperatures that bound " // & + trim(to_str(nint(temp_desired / K_BOLTZMANN))) // " K.") + end select + + select type(nuc) + type is (MgxsIso) + do j = 1, size(nuc_ts) + nuc_t = nuc_ts(j) + if (size(nuc_ts) == 1) then + interp = ONE + else if (j == 1) then + interp = (ONE - (temp_desired - nuc % kTs(nuc_ts(1))) / & + (nuc % kTs(nuc_ts(2)) - nuc % kTs(nuc_ts(1)))) + else + interp = ONE - interp + end if + + ! Perform our operations which depend upon the type + ! Add contributions to total, absorption, and fission data (if necessary) + this % xs(t) % total = this % xs(t) % total + & + atom_density * nuc % xs(nuc_t) % total * interp + this % xs(t) % absorption = this % xs(t) % absorption + & + atom_density * nuc % xs(nuc_t) % absorption * interp + if (nuc % fissionable) then + this % xs(t) % chi = this % xs(t) % chi + & + atom_density * nuc % xs(nuc_t) % chi * interp + this % xs(t) % nu_fission = this % xs(t) % nu_fission + & + atom_density * nuc % xs(nuc_t) % nu_fission * interp + if (allocated(nuc % xs(nuc_t) % fission)) then + this % xs(t) % fission = this % xs(t) % fission + & + atom_density * nuc % xs(nuc_t) % fission * interp + end if + if (allocated(nuc % xs(nuc_t) % k_fission)) then + this % xs(t) % k_fission = this % xs(t) % k_fission + & + atom_density * nuc % xs(nuc_t) % k_fission * interp + end if + end if + if (allocated(nuc % xs(nuc_t) % inv_vel)) then + this % xs(t) % inv_vel = this % xs(t) % inv_vel + & + atom_density * nuc % xs(nuc_t) % inv_vel * interp + end if + + ! We will next gather the multiplicity and scattering matrices. + ! To avoid multiple re-allocations as we resize the storage + ! matrix (and/or to avoidlots of duplicate code), we will use a + ! dense matrix for this storage, with a reduction to the sparse + ! format at the end. + + ! Get the multiplicity_matrix + ! To combine from nuclidic data we need to use the final relationship + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + ! Developed as follows: + ! mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + ! nuscatt_{i,g,g'} can be reconstructed from scatter % energy and + ! scatter % scattxs + do gin = 1, groups + do gout = nuc % xs(nuc_t) % scatter % gmin(gin), nuc % xs(nuc_t) % scatter % gmax(gin) + nuscatt = nuc % xs(nuc_t) % scatter % scattxs(gin) * & + nuc % xs(nuc_t) % scatter % energy(gin) % data(gout) + mult_num(gout, gin) = mult_num(gout, gin) + atom_density * & + nuscatt * interp + if (nuc % xs(nuc_t) % scatter % mult(gin) % data(gout) > ZERO) then + mult_denom(gout, gin) = mult_denom(gout,gin) + atom_density * & + nuscatt / nuc % xs(nuc_t) % scatter % mult(gin) % data(gout) * & + interp + else + ! Avoid division by zero + mult_denom(gout, gin) = mult_denom(gout,gin) + atom_density * & + interp + end if + end do + end do + + ! Get the complete scattering matrix + nuc_order_dim = size(nuc % xs(nuc_t) % scatter % dist(1) % data, dim=1) + nuc_order_dim = min(nuc_order_dim, order_dim) + call nuc % xs(nuc_t) % scatter % get_matrix(nuc_order_dim, & + nuc_matrix) + do gin = 1, groups + do gout = nuc % xs(nuc_t) % scatter % gmin(gin), & + nuc % xs(nuc_t) % scatter % gmax(gin) + scatt_coeffs(1:nuc_order_dim, gout, gin) = & + scatt_coeffs(1: nuc_order_dim, gout, gin) + & + atom_density * interp * & + nuc_matrix(gin) % data(1:nuc_order_dim, gout) + end do + end do + end do + + type is (MgxsAngle) + call fatal_error("Invalid passing of MgxsAngle to MgxsIso object") + end select + + ! Obtain temp_mult + do gin = 1, groups + do gout = 1, groups + if (mult_denom(gout, gin) > ZERO) then + temp_mult(gout, gin) = mult_num(gout, gin) / mult_denom(gout, gin) + else + temp_mult(gout, gin) = ONE + end if + end do + end do + + ! Now create our jagged data from the dense data + call jagged_from_dense_2D(scatt_coeffs, jagged_scatt, gmin, gmax) + call jagged_from_dense_1D(temp_mult, jagged_mult) + + ! Initialize the ScattData Object + call this % xs(t) % scatter % init(gmin, gmax, jagged_mult, & + jagged_scatt) + + ! Now normalize chi + if (mat % fissionable) then + do gin = 1, groups + norm = sum(this % xs(t) % chi(:, gin)) + if (norm > ZERO) then + this % xs(t) % chi(:, gin) = this % xs(t) % chi(:, gin) / norm + end if + end do + end if + + ! Deallocate temporaries + deallocate(jagged_mult, jagged_scatt, gmin, gmax, scatt_coeffs, & + temp_mult, mult_num, mult_denom) + end associate ! nuc + end do NUC_LOOP + end do TEMP_LOOP + + end subroutine mgxsiso_combine + + subroutine mgxsang_combine(this, temps, mat, nuclides, groups, max_order, & + tolerance, method) + class(MgxsAngle), intent(inout) :: this ! The Mgxs to initialize + type(VectorReal), intent(in) :: temps ! Temperatures to obtain + type(Material), pointer, intent(in) :: mat ! base material + type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from + integer, intent(in) :: groups ! Number of E groups + integer, intent(in) :: max_order ! Maximum requested order + real(8), intent(in) :: tolerance ! Tolerance on method + integer, intent(in) :: method ! Type of temperature access integer :: i ! loop index over nuclides + integer :: t ! temperature loop index integer :: gin, gout ! group indices real(8) :: atom_density ! atom density of a nuclide integer :: ipol, iazi, n_pol, n_azi real(8) :: norm, nuscatt - integer :: mat_max_order, order, order_dim, nuc_order_dim + integer :: order_dim, nuc_order_dim real(8), allocatable :: temp_mult(:, :, :, :), mult_num(:, :, :, :) real(8), allocatable :: mult_denom(:, :, :, :), scatt_coeffs(:, :, :, :, :) + integer :: nuc_t + integer, allocatable :: nuc_ts(:) + real(8) :: temp_actual, temp_desired, interp + integer :: scatter_format + type(Jagged2D), allocatable :: nuc_matrix(:) + integer, allocatable :: gmin(:), gmax(:) + type(Jagged2D), allocatable :: jagged_scatt(:) + type(Jagged1D), allocatable :: jagged_mult(:) ! Set the meta-data - call mgxs_combine(this, mat, scatt_type) + call mgxs_combine(this, temps, mat, nuclides, max_order, scatter_format, & + order_dim) ! Get the number of each polar and azi angles and make sure all the ! NuclideAngle types have the same number of these angles @@ -1392,266 +1527,479 @@ module mgxs_header end select end do - ! Determine the scattering type of our data and ensure all scattering orders - ! are the same. - select type(nuc => nuclides(mat % nuclide(1)) % obj) - type is (MgxsAngle) - order = size(nuc % scatter(1,1) % obj % dist(1) % data, dim=1) - end select - ! If we have tabular only data, then make sure all datasets have same size - if (scatt_type == ANGLE_HISTOGRAM) then - ! Check all scattering data to ensure it is the same size - ! order = size(nuclides(mat % nuclide(1)) % obj % scatter % data,dim=1) - do i = 2, mat % n_nuclides - select type(nuc => nuclides(mat % nuclide(i)) % obj) - type is (MgxsAngle) - if (order /= size(nuc % scatter(1,1) % obj % dist(1) % data, dim=1)) & - call fatal_error("All histogram scattering entries must be& - & same length!") - end select - end do - ! Ok, got our order, store the dimensionality - order_dim = order + ! Create the Xs Data for each temperature + TEMP_LOOP: do t = 1, temps % size() + ! Allocate and initialize the data needed for macro_xs(i_mat) object + allocate(this % xs(t) % total(groups, n_azi, n_pol)) + this % xs(t) % total = ZERO + allocate(this % xs(t) % absorption(groups, n_azi, n_pol)) + this % xs(t) % absorption = ZERO + allocate(this % xs(t) % fission(groups, n_azi, n_pol)) + this % xs(t) % fission = ZERO + allocate(this % xs(t) % k_fission(groups, n_azi, n_pol)) + this % xs(t) % k_fission = ZERO + allocate(this % xs(t) % nu_fission(groups, n_azi, n_pol)) + this % xs(t) % nu_fission = ZERO + allocate(this % xs(t) % chi(groups, groups, n_azi, n_pol)) + this % xs(t) % chi = ZERO + allocate(this % xs(t) % inv_vel(groups, n_azi, n_pol)) + this % xs(t) % inv_vel = ZERO + allocate(temp_mult(groups, groups, n_azi, n_pol)) + temp_mult = ZERO + allocate(mult_num(groups, groups, n_azi, n_pol)) + mult_num = ZERO + allocate(mult_denom(groups, groups, n_azi, n_pol)) + mult_denom = ZERO + allocate(scatt_coeffs(order_dim, groups, groups, n_azi, n_pol)) + scatt_coeffs = ZERO - ! Set our Scatter Object Type - allocate(this % scatter(n_azi, n_pol)) + allocate(this % xs(t) % scatter(n_azi, n_pol)) do ipol = 1, n_pol do iazi = 1, n_azi - allocate(ScattDataHistogram :: this % scatter(iazi, ipol) % obj) - end do - end do - - else if (scatt_type == ANGLE_TABULAR) then - ! Check all scattering data to ensure it is the same size - do i = 2, mat % n_nuclides - select type(nuc => nuclides(mat % nuclide(i)) % obj) - type is (MgxsAngle) - if (order /= size(nuc % scatter(1, 1) % obj % dist(1) % data, dim=1)) & - call fatal_error("All tabular scattering entries must be& - & same length!") - end select - end do - ! Ok, got our order, store the dimensionality - order_dim = order - - ! Set our Scatter Object Type - allocate(this % scatter(n_azi, n_pol)) - do ipol = 1, n_pol - do iazi = 1, n_azi - allocate(ScattDataTabular :: this % scatter(iazi, ipol) % obj) - end do - end do - - else if (scatt_type == ANGLE_LEGENDRE) then - ! Need to determine the maximum scattering order of all data in this material - mat_max_order = 0 - do i = 1, mat % n_nuclides - select type(nuc => nuclides(mat % nuclide(i)) % obj) - type is (MgxsAngle) - if (size(nuc % scatter(1,1) % obj % dist(1) % data, dim=1) > mat_max_order) & - mat_max_order = size(nuc % scatter(1,1) % obj% dist(1) % data, dim=1) - end select - end do - - ! Now need to compare this material maximum scattering order with - ! the problem wide max scatt order and use whichever is lower - order = min(mat_max_order, max_order) - ! Ok, got our order, store the dimensionality - order_dim = order + 1 - - ! Set our Scatter Object Type - allocate(this % scatter(n_azi, n_pol)) - do ipol = 1, n_pol - do iazi = 1, n_azi - allocate(ScattDataLegendre :: this % scatter(iazi, ipol) % obj) - end do - end do - end if - - ! Allocate and initialize data within macro_xs(i_mat) object - allocate(this % total(groups, n_azi, n_pol)) - this % total(:, :, :) = ZERO - allocate(this % absorption(groups, n_azi, n_pol)) - this % absorption(:, :, :) = ZERO - allocate(this % fission(groups, n_azi, n_pol)) - this % fission(:, :, :) = ZERO - allocate(this % k_fission(groups, n_azi, n_pol)) - this % k_fission(:, :, :) = ZERO - allocate(this % nu_fission(groups, n_azi, n_pol)) - this % nu_fission(:, :, :) = ZERO - allocate(this % chi(groups, groups, n_azi, n_pol)) - this % chi(:, :, :, :) = ZERO - allocate(temp_mult(groups, groups, n_azi, n_pol)) - temp_mult(:, :, :, :) = ZERO - allocate(mult_num(groups, groups, n_azi, n_pol)) - mult_num(:, :, :, :) = ZERO - allocate(mult_denom(groups, groups, n_azi, n_pol)) - mult_denom(:, :, :, :) = ZERO - allocate(scatt_coeffs(order_dim, groups, groups, n_azi, n_pol)) - scatt_coeffs(:, :, :, :, :) = ZERO - - ! Add contribution from each nuclide in material - do i = 1, mat % n_nuclides - ! Copy atom density of nuclide in material - atom_density = mat % atom_density(i) - - ! Perform our operations which depend upon the type - select type(nuc => nuclides(mat % nuclide(i)) % obj) - type is (MgxsIso) - call fatal_error("Invalid passing of MgxsIso to MgxsAngle object") - type is (MgxsAngle) - ! Add contributions to total, absorption, and fission data (if necessary) - this % total(:, :, :) = this % total(:, :, :) + & - atom_density * nuc % total(:, :, :) - this % absorption(:, :, :) = this % absorption(:, :, :) + & - atom_density * nuc % absorption(:, :, :) - if (nuc % fissionable) then - this % chi = this % chi + atom_density * nuc % chi - this % nu_fission(:, :, :) = this % nu_fission(:, :, :) + & - atom_density * nuc % nu_fission(:, :, :) - if (allocated(nuc % fission)) then - this % fission(:, :, :) = this % fission(:, :, :) + & - atom_density * nuc % fission(:, :, :) + if (scatter_format == ANGLE_LEGENDRE) then + allocate(ScattDataLegendre :: & + this % xs(t) % scatter(iazi, ipol) % obj) + else if (scatter_format == ANGLE_TABULAR) then + allocate(ScattDataTabular :: & + this % xs(t) % scatter(iazi, ipol) % obj) + else if (scatter_format == ANGLE_HISTOGRAM) then + allocate(ScattDataHistogram :: & + this % xs(t) % scatter(iazi, ipol) % obj) end if - if (allocated(nuc % k_fission)) then - this % k_fission(:, :, :) = this % k_fission(:, :, :) + & - atom_density * nuc % k_fission(:, :, :) - end if - end if + end do + end do - ! Get the multiplication matrix - ! To combine from nuclidic data we need to use the final relationship - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - ! Developed as follows: - ! mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - ! nuscatt_{i,g,g'} can be reconstructed from scatter % energy and - ! scatter % scattxs - do ipol = 1, n_pol - do iazi = 1, n_azi - do gin = 1, groups - do gout = nuc % scatter(iazi, ipol) % obj % gmin(gin), & - nuc % scatter(iazi, ipol) % obj % gmax(gin) - nuscatt = nuc % scatter(iazi, ipol) % obj % scattxs(gin) * & - nuc % scatter(iazi, ipol) % obj % energy(gin) % data(gout) - mult_num(gout, gin, iazi, ipol) = mult_num(gout, gin, iazi, ipol) + & - atom_density * nuscatt - if (nuc % scatter(iazi, ipol) % obj % mult(gin) % data(gout) > ZERO) then - mult_denom(gout, gin, iazi, ipol) = & - mult_denom(gout, gin, iazi, ipol) + & - atom_density * nuscatt / & - nuc % scatter(iazi, ipol) % obj % mult(gin) % data(gout) - else - ! Avoid division by zero - mult_denom(gout, gin, iazi, ipol) = & - mult_denom(gout,gin, iazi, ipol) + atom_density + ! Add contribution from each nuclide in material + NUC_LOOP: do i = 1, mat % n_nuclides + associate(nuc => nuclides(mat % nuclide(i)) % obj) + + select case (method) + case (TEMPERATURE_NEAREST) + ! Determine actual temperatures to read + temp_desired = temps % data(i) + allocate(nuc_ts(1)) + nuc_ts(1) = minloc(abs(nuc % kTs - temp_desired), dim=1) + temp_actual = nuc % kTs(nuc_ts(1)) + if (abs(temp_actual - temp_desired) >= K_BOLTZMANN * tolerance) then + call fatal_error("MGXS library does not contain cross sections & + &for " // trim(this % name) // " at or near " // & + trim(to_str(nint(temp_desired / K_BOLTZMANN))) // " K.") + end if + + case (TEMPERATURE_INTERPOLATION) + ! If temperature interpolation or multipole is selected, get a + ! list of bounding temperatures for each actual temperature + ! present in the model + temp_desired = temps % data(i) + allocate(nuc_ts(2)) + do j = 1, size(nuc % kTs) - 1 + if (nuc % kTs(j) <= temp_desired .and. & + temp_desired < nuc % kTs(j + 1)) then + nuc_ts(1) = j + nuc_ts(2) = j + 1 + end if + end do + + call fatal_error("Nuclear data library does not contain cross sections & + &for " // trim(this % name) // " at temperatures that bound " // & + trim(to_str(nint(temp_desired / K_BOLTZMANN))) // " K.") + end select + + ! Copy atom density of nuclide in material + atom_density = mat % atom_density(i) + + select type(nuc) + type is (MgxsAngle) + do j = 1, size(nuc_ts) + nuc_t = nuc_ts(j) + if (size(nuc_ts) == 1) then + interp = ONE + else if (j == 1) then + interp = (ONE - (temp_desired - nuc % kTs(nuc_ts(1))) / & + (nuc % kTs(nuc_ts(2)) - nuc % kTs(nuc_ts(1)))) + else + interp = ONE - interp + end if + ! Perform our operations which depend upon the type + ! Add contributions to total, absorption, and fission data + ! (if necessary) + this % xs(t) % total = this % xs(t) % total + & + atom_density * nuc % xs(nuc_t) % total * interp + this % xs(t) % absorption = this % xs(t) % absorption + & + atom_density * nuc % xs(nuc_t) % absorption * interp + if (allocated(nuc % xs(nuc_t) % inv_vel)) then + this % xs(t) % inv_vel = this % xs(t) % inv_vel + & + atom_density * nuc % xs(nuc_t) % inv_vel * interp + end if + if (nuc % fissionable) then + this % xs(t) % chi = this % xs(t) % chi + & + atom_density * nuc % xs(nuc_t) % chi * interp + this % xs(t) % nu_fission = this % xs(t) % nu_fission + & + atom_density * nuc % xs(nuc_t) % nu_fission * interp + if (allocated(nuc % xs(nuc_t) % fission)) then + this % xs(t) % fission = this % xs(t) % fission + & + atom_density * nuc % xs(nuc_t) % fission * interp end if + if (allocated(nuc % xs(nuc_t) % k_fission)) then + this % xs(t) % k_fission = this % xs(t) % k_fission + & + atom_density * nuc % xs(nuc_t) % k_fission * interp + end if + end if + + ! We will next gather the multiplicity and scattering matrices. + ! To avoid multiple re-allocations as we resize the storage + ! matrix (and/or to avoidlots of duplicate code), we will use a + ! dense matrix for this storage, with a reduction to the sparse + ! format at the end. + + ! Get the multiplicity_matrix + ! To combine from nuclidic data we need to use the final relationship + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + ! Developed as follows: + ! mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + ! nuscatt_{i,g,g'} can be reconstructed from scatter % energy and + ! scatter % scattxs + do ipol = 1, n_pol + do iazi = 1, n_azi + do gin = 1, groups + do gout = nuc % xs(nuc_t) % scatter(iazi, ipol) %obj % gmin(gin), & + nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % gmax(gin) + nuscatt = nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % scattxs(gin) * & + nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % energy(gin) % data(gout) + mult_num(gout, gin, iazi, ipol) = & + mult_num(gout, gin, iazi, ipol) + atom_density * & + nuscatt * interp + if (nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) > ZERO) then + mult_denom(gout, gin, iazi, ipol) = & + mult_denom(gout, gin, iazi, ipol) + atom_density * & + interp * nuscatt / & + nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) + else + ! Avoid division by zero + mult_denom(gout, gin, iazi, ipol) = & + mult_denom(gout, gin, iazi, ipol) + atom_density * & + interp + end if + end do + end do + + ! Get the complete scattering matrix + nuc_order_dim = & + size(nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % & + dist(1) % data, dim=1) + nuc_order_dim = min(nuc_order_dim, order_dim) + call nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % & + get_matrix(nuc_order_dim, nuc_matrix) + do gin = 1, groups + do gout = & + nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % gmin(gin), & + nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % gmax(gin) + scatt_coeffs(1:nuc_order_dim, gout, gin, iazi, ipol) = & + scatt_coeffs(1: nuc_order_dim, gout, gin, iazi, ipol) + & + atom_density * interp * & + nuc_matrix(gin) % data(1:nuc_order_dim, gout) + end do ! gout + end do ! gin + end do ! iazi + end do ! ipol + end do + type is (MgxsIso) + call fatal_error("Invalid passing of MgxsIso to MgxsAngle object") + end select + + ! Obtain temp_mult, create jaged arrays and initialize the + ! ScattData object. + do ipol = 1, n_pol + do iazi = 1, n_azi + ! Obtain temp_mult + do gin = 1, groups + do gout = 1, groups + if (mult_denom(gout, gin, iazi, ipol) > ZERO) then + temp_mult(gout, gin, iazi, ipol) = & + mult_num(gout, gin, iazi, ipol) / & + mult_denom(gout, gin, iazi, ipol) + else + temp_mult(gout, gin, iazi, ipol) = ONE + end if + end do end do + + ! Now create our jagged data from the dense data + call jagged_from_dense_2D(scatt_coeffs(:, :, :, iazi, ipol), & + jagged_scatt) + call jagged_from_dense_1D(temp_mult(:, :, iazi, ipol), & + jagged_mult, gmin, gmax) + + ! Initialize the ScattData Object + call this % xs(t) % scatter(iazi, ipol) % obj % init(gmin, & + gmax, jagged_mult, jagged_scatt) + deallocate(jagged_scatt, jagged_mult, gmin, gmax) end do end do - end do - ! Get the complete scattering matrix - nuc_order_dim = size(nuc % scatter(1, 1) % obj % dist(1) % data, dim=1) - do ipol = 1, n_pol - do iazi = 1, n_azi - scatt_coeffs(1:min(nuc_order_dim, order_dim), :, :, iazi, ipol) = & - scatt_coeffs(1:min(nuc_order_dim, order_dim), :, :, iazi, ipol) + & - atom_density * nuc % scatter(iazi, ipol) % obj % get_matrix(& - min(nuc_order_dim, order_dim)) - end do - end do - end select - end do + ! Now normalize chi + if (mat % fissionable) then + do ipol = 1, n_pol + do iazi = 1, n_azi + do gin = 1, groups + norm = sum(this % xs(t) % chi(:, gin, iazi, ipol)) + if (norm > ZERO) then + this % xs(t) % chi(:, gin, iazi, ipol) = & + this % xs(t) % chi(:, gin, iazi, ipol) / norm + end if + end do + end do + end do + end if - ! Obtain temp_mult - do ipol = 1, n_pol - do iazi = 1, n_azi - do gin = 1, groups - do gout = 1, groups - if (mult_denom(gout, gin, iazi, ipol) > ZERO) then - temp_mult(gout, gin, iazi, ipol) = & - mult_num(gout, gin, iazi, ipol) / & - mult_denom(gout, gin, iazi, ipol) - else - temp_mult(gout, gin, iazi, ipol) = ONE - end if - end do - end do - end do - end do - - ! Initialize the ScattData Object - do ipol = 1, n_pol - do iazi = 1, n_azi - call this % scatter(iazi, ipol) % obj % init( & - temp_mult(:, :, iazi, ipol), scatt_coeffs(:, :, :, iazi, ipol)) - end do - end do - - ! Now normalize chi - if (mat % fissionable) then - do ipol = 1, n_pol - do iazi = 1, n_azi - do gin = 1, groups - norm = sum(this % chi(:, gin, iazi, ipol)) - if (norm > ZERO) then - this % chi(:, gin, iazi, ipol) = this % chi(:, gin, iazi, ipol) / norm - end if - end do - end do - end do - end if - - ! Deallocate temporaries for the next material - deallocate(scatt_coeffs, temp_mult) + ! Deallocate temporaries + deallocate(scatt_coeffs, temp_mult, mult_num, mult_denom) + end associate ! nuc + end do NUC_LOOP + end do TEMP_LOOP end subroutine mgxsang_combine +!=============================================================================== +! MGXS*_GET_XS returns the requested data cross section data +!=============================================================================== + + pure function mgxsiso_get_xs(this, xstype, gin, gout, uvw, mu) result(xs) + class(MgxsIso), intent(in) :: this ! The Xs to get data from + character(*) , intent(in) :: xstype ! Type of xs requested + integer, intent(in) :: gin ! Incoming Energy group + integer, optional, intent(in) :: gout ! Outgoing Energy group + real(8), optional, intent(in) :: uvw(3) ! Requested Angle + real(8), optional, intent(in) :: mu ! Change in angle + real(8) :: xs ! Requested x/s + integer :: t ! temperature index + + t = this % index_temp + + select case(xstype) + case('total') + xs = this % xs(t) % total(gin) + case('absorption') + xs = this % xs(t) % absorption(gin) + case('fission') + if (allocated(this % xs(t) % fission)) then + xs = this % xs(t) % fission(gin) + else + xs = ZERO + end if + case('kappa_fission') + if (allocated(this % xs(t) % k_fission)) then + xs = this % xs(t) % k_fission(gin) + else + xs = ZERO + end if + case('nu_fission') + xs = this % xs(t) % nu_fission(gin) + case('chi') + if (present(gout)) then + xs = this % xs(t) % chi(gout,gin) + else + ! Not sure youd want a 1 or a 0, but here you go! + xs = sum(this % xs(t) % chi(:, gin)) + end if + case('scatter') + if (present(gout)) then + if (gout < this % xs(t) % scatter % gmin(gin) .or. & + gout > this % xs(t) % scatter % gmax(gin)) then + xs = ZERO + else + xs = this % xs(t) % scatter % scattxs(gin) * & + this % xs(t) % scatter % energy(gin) % data(gout) + end if + else + xs = this % xs(t) % scatter % scattxs(gin) + end if + case('scatter/mult') + if (present(gout)) then + if (gout < this % xs(t) % scatter % gmin(gin) .or. & + gout > this % xs(t) % scatter % gmax(gin)) then + xs = ZERO + else + xs = this % xs(t) % scatter % scattxs(gin) * & + this % xs(t) % scatter % energy(gin) % data(gout) / & + this % xs(t) % scatter % mult(gin) % data(gout) + end if + else + xs = this % xs(t) % scatter % scattxs(gin) / & + (dot_product(this % xs(t) % scatter % mult(gin) % data, & + this % xs(t) % scatter % energy(gin) % data)) + end if + case('scatter*f_mu/mult','scatter*f_mu') + if (present(gout)) then + if (gout < this % xs(t) % scatter % gmin(gin) .or. & + gout > this % xs(t) % scatter % gmax(gin)) then + xs = ZERO + else + xs = this % xs(t) % scatter % scattxs(gin) * & + this % xs(t) % scatter % energy(gin) % data(gout) * & + this % xs(t) % scatter % calc_f(gin, gout, mu) + if (xstype == 'scatter*f_mu/mult') then + xs = xs / this % xs(t) % scatter % mult(gin) % data(gout) + end if + end if + else + xs = ZERO + ! TODO (Not likely needed) + ! (asking for f_mu without asking for a group or mu would mean the + ! user of this code wants the complete 1-outgoing group distribution + ! which Im not sure what they would do with that. + end if + case('inv_vel') + xs = this % xs(t) % inv_vel(gin) + case default + xs = ZERO + end select + end function mgxsiso_get_xs + + pure function mgxsang_get_xs(this, xstype, gin, gout, uvw, mu) result(xs) + class(MgxsAngle), intent(in) :: this ! The Mgxs to initialize + character(*) , intent(in) :: xstype ! Type of xs requested + integer, intent(in) :: gin ! Incoming Energy group + integer, optional, intent(in) :: gout ! Outgoing Energy group + real(8), optional, intent(in) :: uvw(3) ! Requested Angle + real(8), optional, intent(in) :: mu ! Change in angle + real(8) :: xs ! Requested x/s + + integer :: iazi, ipol, t + + t = this % index_temp + + if (present(uvw)) then + call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) + select case(xstype) + case('total') + xs = this % xs(t) % total(gin, iazi, ipol) + case('absorption') + xs = this % xs(t) % absorption(gin, iazi, ipol) + case('fission') + if (allocated(this % xs(t) % fission)) then + xs = this % xs(t) % fission(gin, iazi, ipol) + else + xs = ZERO + end if + case('kappa_fission') + if (allocated(this % xs(t) % k_fission)) then + xs = this % xs(t) % k_fission(gin, iazi, ipol) + else + xs = ZERO + end if + case('nu_fission') + xs = this % xs(t) % nu_fission(gin, iazi, ipol) + case('chi') + if (present(gout)) then + xs = this % xs(t) % chi(gout, gin, iazi, ipol) + else + ! Not sure you would want a 1 or a 0, but here you go! + xs = sum(this % xs(t) % chi(:, gin, iazi, ipol)) + end if + case('scatter') + if (present(gout)) then + if (gout < this % xs(t) % scatter(iazi, ipol) % obj % gmin(gin) .or. & + gout > this % xs(t) % scatter(iazi, ipol) % obj % gmax(gin)) then + xs = ZERO + else + xs = this % xs(t) % scatter(iazi, ipol) % obj % scattxs(gin) * & + this % xs(t) % scatter(iazi, ipol) % obj % energy(gin) % data(gout) + end if + else + xs = this % xs(t) % scatter(iazi, ipol) % obj % scattxs(gin) + end if + case('scatter/mult') + if (present(gout)) then + if (gout < this % xs(t) % scatter(iazi, ipol) % obj % gmin(gin) .or. & + gout > this % xs(t) % scatter(iazi, ipol) % obj % gmax(gin)) then + xs = ZERO + else + xs = this % xs(t) % scatter(iazi, ipol) % obj % scattxs(gin) * & + this % xs(t) % scatter(iazi, ipol) % obj % energy(gin) % data(gout) / & + this % xs(t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) + end if + else + xs = this % xs(t) % scatter(iazi, ipol) % obj % scattxs(gin) / & + (dot_product(this % xs(t) % scatter(iazi, ipol) % obj % mult(gin) % data, & + this % xs(t) % scatter(iazi, ipol) % obj % energy(gin) % data)) + end if + case('scatter*f_mu/mult','scatter*f_mu') + if (present(gout)) then + if (gout < this % xs(t) % scatter(iazi, ipol) % obj % gmin(gin) .or. & + gout > this % xs(t) % scatter(iazi, ipol) % obj % gmax(gin)) then + xs = ZERO + else + xs = this % xs(t) % scatter(iazi, ipol) % obj % scattxs(gin) * & + this % xs(t) % scatter(iazi, ipol) % obj % energy(gin) % data(gout) + xs = xs * this % xs(t) % scatter(iazi, ipol) % obj % calc_f(gin, gout, mu) + if (xstype == 'scatter*f_mu/mult') then + xs = xs / & + this % xs(t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) + end if + end if + else + xs = ZERO + ! TODO (Not likely needed) + ! (asking for f_mu without asking for a group or mu would mean the + ! user of this code wants the complete 1-outgoing group distribution + ! which Im not sure what they would do with that. + end if + case('inv_vel') + xs = this % xs(t) % inv_vel(gin, iazi, ipol) + case default + xs = ZERO + end select + else + xs = ZERO + end if + end function mgxsang_get_xs + !=============================================================================== ! MGXS*_SAMPLE_FISSION_ENERGY samples the outgoing energy from a fission event !=============================================================================== function mgxsiso_sample_fission_energy(this, gin, uvw) result(gout) class(MgxsIso), intent(in) :: this ! Data to work with - integer, intent(in) :: gin ! Incoming energy group - real(8), intent(in) :: uvw(3) ! Particle Direction - integer :: gout ! Sampled outgoing group - real(8) :: xi ! Our random number - real(8) :: prob ! Running probability + integer, intent(in) :: gin ! Incoming energy group + real(8), intent(in) :: uvw(3) ! Particle Direction + integer :: gout ! Sampled outgoing group + real(8) :: xi ! Our random number + real(8) :: prob ! Running probability xi = prn() gout = 1 - prob = this % chi(gout,gin) + prob = this % xs(this % index_temp) % chi(gout,gin) do while (prob < xi) gout = gout + 1 - prob = prob + this % chi(gout,gin) + prob = prob + this % xs(this % index_temp) % chi(gout,gin) end do end function mgxsiso_sample_fission_energy function mgxsang_sample_fission_energy(this, gin, uvw) result(gout) class(MgxsAngle), intent(in) :: this ! Data to work with - integer, intent(in) :: gin ! Incoming energy group - real(8), intent(in) :: uvw(3) ! Particle Direction - integer :: gout ! Sampled outgoing group - real(8) :: xi ! Our random number - real(8) :: prob ! Running probability - integer :: iazi, ipol + integer, intent(in) :: gin ! Incoming energy group + real(8), intent(in) :: uvw(3) ! Particle Direction + integer :: gout ! Sampled outgoing group + real(8) :: xi ! Our random number + real(8) :: prob ! Running probability + integer :: iazi, ipol ! Angle indices call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) xi = prn() gout = 1 - prob = this % chi(gout, gin, iazi, ipol) + prob = this % xs(this % index_temp) % chi(gout, gin, iazi, ipol) do while (prob < xi) gout = gout + 1 - prob = prob + this % chi(gout, gin, iazi, ipol) + prob = prob + this % xs(this % index_temp) % chi(gout, gin, iazi, ipol) end do end function mgxsang_sample_fission_energy @@ -1662,28 +2010,29 @@ module mgxs_header subroutine mgxsiso_sample_scatter(this, uvw, gin, gout, mu, wgt) class(MgxsIso), intent(in) :: this - real(8), intent(in) :: uvw(3) ! Incoming neutron direction - integer, intent(in) :: gin ! Incoming neutron group - integer, intent(out) :: gout ! Sampled outgoin group - real(8), intent(out) :: mu ! Sampled change in angle - real(8), intent(inout) :: wgt ! Particle weight + real(8), intent(in) :: uvw(3) ! Incoming neutron direction + integer, intent(in) :: gin ! Incoming neutron group + integer, intent(out) :: gout ! Sampled outgoin group + real(8), intent(out) :: mu ! Sampled change in angle + real(8), intent(inout) :: wgt ! Particle weight - call this % scatter % sample(gin, gout, mu, wgt) + call this % xs(this % index_temp) % scatter % sample(gin, gout, mu, wgt) end subroutine mgxsiso_sample_scatter subroutine mgxsang_sample_scatter(this, uvw, gin, gout, mu, wgt) class(MgxsAngle), intent(in) :: this - real(8), intent(in) :: uvw(3) ! Incoming neutron direction - integer, intent(in) :: gin ! Incoming neutron group - integer, intent(out) :: gout ! Sampled outgoin group - real(8), intent(out) :: mu ! Sampled change in angle - real(8), intent(inout) :: wgt ! Particle weight + real(8), intent(in) :: uvw(3) ! Incoming neutron direction + integer, intent(in) :: gin ! Incoming neutron group + integer, intent(out) :: gout ! Sampled outgoin group + real(8), intent(out) :: mu ! Sampled change in angle + real(8), intent(inout) :: wgt ! Particle weight integer :: iazi, ipol ! Angular indices call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) - call this % scatter(iazi, ipol) % obj % sample(gin, gout, mu, wgt) + call this % xs(this % index_temp) % scatter(iazi, ipol) % obj % sample( & + gin, gout, mu, wgt) end subroutine mgxsang_sample_scatter @@ -1698,11 +2047,11 @@ module mgxs_header real(8), intent(in) :: uvw(3) ! Incoming neutron direction type(MaterialMacroXS), intent(inout) :: xs ! Resultant Mgxs Data - xs % total = this % total(gin) - xs % elastic = this % scatter % scattxs(gin) - xs % absorption = this % absorption(gin) - xs % fission = this % fission(gin) - xs % nu_fission = this % nu_fission(gin) + xs % total = this % xs(this % index_temp) % total(gin) + xs % elastic = this % xs(this % index_temp) % scatter % scattxs(gin) + xs % absorption = this % xs(this % index_temp) % absorption(gin) + xs % fission = this % xs(this % index_temp) % fission(gin) + xs % nu_fission = this % xs(this % index_temp) % nu_fission(gin) end subroutine mgxsiso_calculate_xs @@ -1715,16 +2064,34 @@ module mgxs_header integer :: iazi, ipol call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) - xs % total = this % total(gin, iazi, ipol) - xs % elastic = this % scatter(iazi, ipol) % obj % scattxs(gin) - xs % absorption = this % absorption(gin, iazi, ipol) - xs % fission = this % fission(gin, iazi, ipol) - xs % nu_fission = this % nu_fission(gin, iazi, ipol) + xs % total = this % xs(this % index_temp) % & + total(gin, iazi, ipol) + xs % elastic = this % xs(this % index_temp) % & + scatter(iazi, ipol) % obj % scattxs(gin) + xs % absorption = this % xs(this % index_temp) % & + absorption(gin, iazi, ipol) + xs % fission = this % xs(this % index_temp) % & + fission(gin, iazi, ipol) + xs % nu_fission = this % xs(this % index_temp) % & + nu_fission(gin, iazi, ipol) end subroutine mgxsang_calculate_xs !=============================================================================== -! find_angle finds the closest angle on the data grid and returns that index +! MGXS_FIND_TEMPERATURE sets the temperature index for the given +! sqrt(temperature), (with temperature in units of MeV) +!=============================================================================== + + subroutine mgxs_find_temperature(this, sqrtkT) + class(Mgxs), intent(inout) :: this + real(8), intent(in) :: sqrtkT ! Temperature (in units of of MeV) + + this % index_temp = minloc(abs(this % kTs - (sqrtkT * sqrtkT)), dim=1) + + end subroutine mgxs_find_temperature + +!=============================================================================== +! FIND_ANGLE finds the closest angle on the data grid and returns that index !=============================================================================== pure subroutine find_angle(polar, azimuthal, uvw, i_azi, i_pol) diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index d07ccbe5a2..63bd4417bc 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -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 diff --git a/src/output.F90 b/src/output.F90 index f46abb3ce7..f188874d26 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -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 diff --git a/src/physics.F90 b/src/physics.F90 index 6a6a9787d5..842540d166 100644 --- a/src/physics.F90 +++ b/src/physics.F90 @@ -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 !=============================================================================== diff --git a/src/physics_mg.F90 b/src/physics_mg.F90 index 2e5e467c14..c60fc6e2e1 100644 --- a/src/physics_mg.F90 +++ b/src/physics_mg.F90 @@ -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 diff --git a/src/reaction_header.F90 b/src/reaction_header.F90 index a7896e9ff3..12b3888c4b 100644 --- a/src/reaction_header.F90 +++ b/src/reaction_header.F90 @@ -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 diff --git a/src/sab_header.F90 b/src/sab_header.F90 index dcf5df979a..bf81a5d902 100644 --- a/src/sab_header.F90 +++ b/src/sab_header.F90 @@ -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') diff --git a/src/scattdata_header.F90 b/src/scattdata_header.F90 index d4643a0721..6004cbd190 100644 --- a/src/scattdata_header.F90 +++ b/src/scattdata_header.F90 @@ -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 diff --git a/src/secondary_uncorrelated.F90 b/src/secondary_uncorrelated.F90 index fc215484a9..40aa827da6 100644 --- a/src/secondary_uncorrelated.F90 +++ b/src/secondary_uncorrelated.F90 @@ -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) diff --git a/src/state_point.F90 b/src/state_point.F90 index 9ec2e82e2e..cf334787a6 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -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' diff --git a/src/tally.F90 b/src/tally.F90 index 4e327385d7..606186b773 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -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 diff --git a/src/tracking.F90 b/src/tracking.F90 index 7bdd32c227..8350d284aa 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -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 diff --git a/tests/1d_mgxs.h5 b/tests/1d_mgxs.h5 new file mode 100644 index 0000000000..3befba1940 Binary files /dev/null and b/tests/1d_mgxs.h5 differ diff --git a/tests/1d_mgxs.xml b/tests/1d_mgxs.xml deleted file mode 100644 index 8704b49ad4..0000000000 --- a/tests/1d_mgxs.xml +++ /dev/null @@ -1,9859 +0,0 @@ - - - 1 - 0.0000000E+00 2.0000000E+01 - - - uo2_iso - uo2_iso - 2.5300000E-08 - 5 - true - isotropic - - 4.1022364E-01 - - - 3.4687432E-02 - - - 4.9631431E-02 - - - 1.0000000E+00 - - - 2.0019027E-02 - - - 3.7564339E-01 - - 4.4983802E-02 - - 2.2781624E-02 - - 1.1639469E-02 - - 7.1975833E-03 - - 3.5887673E-03 - - - 1.0002764E+00 - - - - - clad_iso - clad_iso - 2.5300000E-08 - 5 - false - isotropic - - 3.0736836E-01 - - - 1.7027907E-03 - - - 3.0566993E-01 - - 4.1625057E-02 - - 2.2287832E-02 - - 3.9580806E-03 - - 3.3420849E-03 - - 1.3963828E-03 - - - 1.0000372E+00 - - - - - lwtr_iso - lwtr_iso - 2.5300000E-08 - 5 - false - isotropic - - 9.6904862E-01 - - - 1.0230968E-02 - - - 9.5881780E-01 - - 3.9202760E-01 - - 1.2865356E-01 - - 9.5231115E-03 - - -1.9647208E-02 - - 5.9291968E-04 - - - 1.0000000E+00 - - - - - uo2_iso_mu - uo2_iso_mu - 2.5300000E-08 - 32 - true - isotropic - histogram - - 4.1022364E-01 - - - 3.4687432E-02 - - - 4.9631431E-02 - - - 1.0000000E+00 - - - 2.0019027E-02 - - - 9.7621928E-03 - - 9.6669975E-03 - - 9.6217012E-03 - - 9.6029285E-03 - - 9.6155223E-03 - - 9.6417022E-03 - - 9.6845888E-03 - - 9.7355785E-03 - - 9.7971852E-03 - - 9.8708684E-03 - - 9.9451996E-03 - - 1.0026273E-02 - - 1.0121536E-02 - - 1.0227606E-02 - - 1.0340467E-02 - - 1.0461281E-02 - - 1.0600371E-02 - - 1.0742182E-02 - - 1.0892295E-02 - - 1.1062409E-02 - - 1.1236639E-02 - - 1.1440302E-02 - - 1.1662283E-02 - - 1.1931512E-02 - - 1.2259589E-02 - - 1.2696194E-02 - - 1.3272953E-02 - - 1.4078939E-02 - - 1.5238289E-02 - - 1.6956791E-02 - - 1.9602217E-02 - - 2.3848802E-02 - - - 1.0002764E+00 - - - - - clad_iso_mu - clad_iso_mu - 2.5300000E-08 - 32 - false - isotropic - histogram - - 3.0736836E-01 - - - 1.7027907E-03 - - - 8.7275040E-03 - - 8.3252599E-03 - - 8.0120655E-03 - - 7.7711039E-03 - - 7.5947251E-03 - - 7.4705350E-03 - - 7.3804037E-03 - - 7.3241515E-03 - - 7.3010244E-03 - - 7.3107188E-03 - - 7.3487081E-03 - - 7.4144814E-03 - - 7.5104992E-03 - - 7.6438156E-03 - - 7.7974114E-03 - - 7.9812213E-03 - - 8.1816102E-03 - - 8.4284406E-03 - - 8.6892059E-03 - - 8.9675370E-03 - - 9.2626673E-03 - - 9.6121293E-03 - - 9.9669464E-03 - - 1.0354054E-02 - - 1.0794903E-02 - - 1.1296566E-02 - - 1.1883978E-02 - - 1.2592532E-02 - - 1.3494682E-02 - - 1.4666635E-02 - - 1.6229823E-02 - - 1.8334594E-02 - - - 1.0000372E+00 - - - - - lwtr_iso_mu - lwtr_iso_mu - 2.5300000E-08 - 32 - false - isotropic - histogram - - 9.6904862E-01 - - - 1.0230968E-02 - - - 5.8755233E-03 - - 1.0934725E-02 - - 1.1142414E-02 - - 1.0437139E-02 - - 1.0756915E-02 - - 1.0623054E-02 - - 1.1295335E-02 - - 1.1326212E-02 - - 1.1795885E-02 - - 1.2179916E-02 - - 1.2528003E-02 - - 1.3121696E-02 - - 1.3563685E-02 - - 1.4242846E-02 - - 1.4567732E-02 - - 1.5913317E-02 - - 1.6851680E-02 - - 2.0792196E-02 - - 2.4129531E-02 - - 2.8258248E-02 - - 3.2040957E-02 - - 3.6266761E-02 - - 4.0455247E-02 - - 4.4731350E-02 - - 4.8820583E-02 - - 5.3746086E-02 - - 5.7743648E-02 - - 6.3513540E-02 - - 6.7353451E-02 - - 7.2430683E-02 - - 8.0723820E-02 - - 8.0655621E-02 - - - 1.0000000E+00 - - - - - uo2_ang - uo2_ang - 2.5300000E-08 - 5 - true - 32 - 1 - angle - - 4.0734790E-01 - - 4.0709470E-01 - - 4.0665280E-01 - - 4.0605122E-01 - - 4.0509226E-01 - - 4.0399893E-01 - - 4.0264927E-01 - - 4.0112684E-01 - - 3.9937450E-01 - - 3.9743081E-01 - - 3.9533879E-01 - - 3.9307550E-01 - - 3.9084961E-01 - - 3.8878017E-01 - - 3.8751931E-01 - - 3.8693825E-01 - - 3.9039929E-01 - - 4.0037023E-01 - - 4.1057791E-01 - - 4.1924835E-01 - - 4.2629128E-01 - - 4.3202621E-01 - - 4.3673213E-01 - - 4.4062993E-01 - - 4.4385222E-01 - - 4.4647166E-01 - - 4.4861335E-01 - - 4.5026817E-01 - - 4.5165329E-01 - - 4.5255720E-01 - - 4.5310208E-01 - - 4.5337269E-01 - - - 3.1599020E-02 - - 3.1371085E-02 - - 3.1023091E-02 - - 3.0539250E-02 - - 2.9839460E-02 - - 2.9013479E-02 - - 2.8058288E-02 - - 2.7047229E-02 - - 2.5977776E-02 - - 2.4952391E-02 - - 2.4009896E-02 - - 2.3244570E-02 - - 2.2725200E-02 - - 2.2489873E-02 - - 2.2624168E-02 - - 2.3059735E-02 - - 2.4782557E-02 - - 2.8553081E-02 - - 3.3194318E-02 - - 3.8038660E-02 - - 4.2666012E-02 - - 4.6923885E-02 - - 5.0708283E-02 - - 5.3996846E-02 - - 5.6845491E-02 - - 5.9213445E-02 - - 6.1182604E-02 - - 6.2742563E-02 - - 6.3985293E-02 - - 6.4852148E-02 - - 6.5364227E-02 - - 6.5703785E-02 - - - 4.5146530E-02 - - 4.4766687E-02 - - 4.4155441E-02 - - 4.3323960E-02 - - 4.2141314E-02 - - 4.0739637E-02 - - 3.9143652E-02 - - 3.7465300E-02 - - 3.5735871E-02 - - 3.4113931E-02 - - 3.2678644E-02 - - 3.1591060E-02 - - 3.0966537E-02 - - 3.0821062E-02 - - 3.1238242E-02 - - 3.2075654E-02 - - 3.4603728E-02 - - 3.9898114E-02 - - 4.6725370E-02 - - 5.4142159E-02 - - 6.1436273E-02 - - 6.8238302E-02 - - 7.4365771E-02 - - 7.9727018E-02 - - 8.4398863E-02 - - 8.8315890E-02 - - 9.1574736E-02 - - 9.4183896E-02 - - 9.6266615E-02 - - 9.7706019E-02 - - 9.8564505E-02 - - 9.9171965E-02 - - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - - 1.8183034E-02 - - 1.8028751E-02 - - 1.7777081E-02 - - 1.7434939E-02 - - 1.6947918E-02 - - 1.6371445E-02 - - 1.5714505E-02 - - 1.5023310E-02 - - 1.4310527E-02 - - 1.3640363E-02 - - 1.3045308E-02 - - 1.2590537E-02 - - 1.2323486E-02 - - 1.2250235E-02 - - 1.2408325E-02 - - 1.2741816E-02 - - 1.3791905E-02 - - 1.6011218E-02 - - 1.8846275E-02 - - 2.1907807E-02 - - 2.4909120E-02 - - 2.7704245E-02 - - 3.0220623E-02 - - 3.2422114E-02 - - 3.4339614E-02 - - 3.5947934E-02 - - 3.7286018E-02 - - 3.8357139E-02 - - 3.9212858E-02 - - 3.9804080E-02 - - 4.0156625E-02 - - 4.0404918E-02 - - - 3.7585902E-01 - - 4.4872720E-02 - - 2.2814276E-02 - - 1.1556342E-02 - - 7.2018303E-03 - - 3.6175403E-03 - - - - 3.7582315E-01 - - 4.4995749E-02 - - 2.2725116E-02 - - 1.1466478E-02 - - 7.0875483E-03 - - 3.5308164E-03 - - - - 3.7572011E-01 - - 4.4992452E-02 - - 2.2759820E-02 - - 1.1516099E-02 - - 7.0323440E-03 - - 3.5020003E-03 - - - - 3.7562995E-01 - - 4.5132914E-02 - - 2.2777514E-02 - - 1.1548988E-02 - - 7.0831467E-03 - - 3.5299129E-03 - - - - 3.7536612E-01 - - 4.5293164E-02 - - 2.2890080E-02 - - 1.1675089E-02 - - 7.1438522E-03 - - 3.5771809E-03 - - - - 3.7510372E-01 - - 4.5594244E-02 - - 2.2986083E-02 - - 1.1616892E-02 - - 7.1593645E-03 - - 3.5827527E-03 - - - - 3.7471139E-01 - - 4.5893399E-02 - - 2.3129097E-02 - - 1.1710573E-02 - - 7.2294990E-03 - - 3.6035030E-03 - - - - 3.7417853E-01 - - 4.6212271E-02 - - 2.3407493E-02 - - 1.1803607E-02 - - 7.2768873E-03 - - 3.6185275E-03 - - - - 3.7350485E-01 - - 4.6653124E-02 - - 2.3603271E-02 - - 1.1928427E-02 - - 7.3368483E-03 - - 3.6311780E-03 - - - - 3.7257204E-01 - - 4.7127424E-02 - - 2.3927026E-02 - - 1.2138279E-02 - - 7.4376541E-03 - - 3.6855451E-03 - - - - 3.7144563E-01 - - 4.7675499E-02 - - 2.4252831E-02 - - 1.2320100E-02 - - 7.5749097E-03 - - 3.7669728E-03 - - - - 3.6996977E-01 - - 4.8300830E-02 - - 2.4647138E-02 - - 1.2560662E-02 - - 7.7886594E-03 - - 3.8654464E-03 - - - - 3.6821602E-01 - - 4.8824396E-02 - - 2.5017750E-02 - - 1.2840163E-02 - - 7.9274823E-03 - - 3.9779025E-03 - - - - 3.6638016E-01 - - 4.9306135E-02 - - 2.5474307E-02 - - 1.3192593E-02 - - 8.2112330E-03 - - 4.1160831E-03 - - - - 3.6503713E-01 - - 4.9560796E-02 - - 2.5756337E-02 - - 1.3455138E-02 - - 8.3858370E-03 - - 4.2114689E-03 - - - - 3.6400368E-01 - - 4.9633132E-02 - - 2.5987536E-02 - - 1.3659891E-02 - - 8.5714354E-03 - - 4.3181256E-03 - - - - 3.6576117E-01 - - 4.8863049E-02 - - 2.5525363E-02 - - 1.3370670E-02 - - 8.3567729E-03 - - 4.1905625E-03 - - - - 3.7192172E-01 - - 4.6844936E-02 - - 2.3959446E-02 - - 1.2270393E-02 - - 7.5751281E-03 - - 3.7309644E-03 - - - - 3.7748124E-01 - - 4.4748629E-02 - - 2.2514789E-02 - - 1.1348962E-02 - - 6.9297472E-03 - - 3.4104693E-03 - - - - 3.8128097E-01 - - 4.3075850E-02 - - 2.1398961E-02 - - 1.0675116E-02 - - 6.5306660E-03 - - 3.2210938E-03 - - - - 3.8373406E-01 - - 4.1672472E-02 - - 2.0547117E-02 - - 1.0330913E-02 - - 6.3048028E-03 - - 3.1386749E-03 - - - - 3.8520439E-01 - - 4.0681902E-02 - - 2.0057126E-02 - - 1.0056063E-02 - - 6.1829817E-03 - - 3.0802737E-03 - - - - 3.8614505E-01 - - 3.9879282E-02 - - 1.9626439E-02 - - 9.9375963E-03 - - 6.1229946E-03 - - 3.0426688E-03 - - - - 3.8675390E-01 - - 3.9278504E-02 - - 1.9339777E-02 - - 9.8184985E-03 - - 6.0956157E-03 - - 3.0580002E-03 - - - - 3.8705360E-01 - - 3.8883125E-02 - - 1.9159064E-02 - - 9.7301477E-03 - - 6.0595588E-03 - - 3.0225068E-03 - - - - 3.8731880E-01 - - 3.8576519E-02 - - 1.9045072E-02 - - 9.7127863E-03 - - 6.0463869E-03 - - 3.0519472E-03 - - - - 3.8756725E-01 - - 3.8382695E-02 - - 1.8916082E-02 - - 9.6925622E-03 - - 6.0590015E-03 - - 2.9913798E-03 - - - - 3.8761982E-01 - - 3.8249486E-02 - - 1.8841512E-02 - - 9.6699646E-03 - - 6.0488356E-03 - - 3.0212480E-03 - - - - 3.8779017E-01 - - 3.8052198E-02 - - 1.8815974E-02 - - 9.5833623E-03 - - 5.9965640E-03 - - 2.9751261E-03 - - - - 3.8780028E-01 - - 3.7931450E-02 - - 1.8735581E-02 - - 9.6072395E-03 - - 5.9416328E-03 - - 3.0080955E-03 - - - - 3.8782277E-01 - - 3.7963999E-02 - - 1.8776116E-02 - - 9.6491264E-03 - - 5.9087373E-03 - - 3.0066367E-03 - - - - 3.8767898E-01 - - 3.7876954E-02 - - 1.8837344E-02 - - 9.7088929E-03 - - 5.9136976E-03 - - 3.0171235E-03 - - - 1.0002763E+00 - - - 1.0002760E+00 - - - 1.0002658E+00 - - - 1.0002710E+00 - - - 1.0002776E+00 - - - 1.0002767E+00 - - - 1.0002833E+00 - - - 1.0002791E+00 - - - 1.0002788E+00 - - - 1.0002858E+00 - - - 1.0002884E+00 - - - 1.0002916E+00 - - - 1.0003039E+00 - - - 1.0003181E+00 - - - 1.0003365E+00 - - - 1.0003544E+00 - - - 1.0003372E+00 - - - 1.0002764E+00 - - - 1.0002508E+00 - - - 1.0002343E+00 - - - 1.0002360E+00 - - - 1.0002375E+00 - - - 1.0002331E+00 - - - 1.0002344E+00 - - - 1.0002385E+00 - - - 1.0002316E+00 - - - 1.0002360E+00 - - - 1.0002360E+00 - - - 1.0002354E+00 - - - 1.0002349E+00 - - - 1.0002325E+00 - - - 1.0002268E+00 - - - - - clad_ang - clad_ang - 2.5300000E-08 - 5 - false - 32 - 1 - angle - - 3.1005638E-01 - - 3.0999067E-01 - - 3.0994879E-01 - - 3.0987779E-01 - - 3.0961631E-01 - - 3.0948272E-01 - - 3.0913340E-01 - - 3.0868239E-01 - - 3.0799925E-01 - - 3.0712597E-01 - - 3.0590948E-01 - - 3.0432728E-01 - - 3.0235012E-01 - - 2.9996873E-01 - - 2.9743091E-01 - - 2.9739624E-01 - - 3.0835788E-01 - - 3.1305337E-01 - - 3.1379599E-01 - - 3.1314506E-01 - - 3.1216249E-01 - - 3.1129786E-01 - - 3.1059203E-01 - - 3.1009561E-01 - - 3.0977837E-01 - - 3.0951041E-01 - - 3.0930940E-01 - - 3.0929712E-01 - - 3.0925741E-01 - - 3.0917641E-01 - - 3.0919741E-01 - - 3.0912502E-01 - - - 1.3490691E-03 - - 1.3463259E-03 - - 1.3498512E-03 - - 1.3366347E-03 - - 1.3288899E-03 - - 1.3176269E-03 - - 1.3059971E-03 - - 1.2891508E-03 - - 1.2713136E-03 - - 1.2555332E-03 - - 1.2394055E-03 - - 1.2170158E-03 - - 1.1969201E-03 - - 1.1849620E-03 - - 1.1899173E-03 - - 1.2761137E-03 - - 1.6244505E-03 - - 1.9090551E-03 - - 2.0837409E-03 - - 2.1976011E-03 - - 2.2746911E-03 - - 2.3308251E-03 - - 2.3700744E-03 - - 2.3981231E-03 - - 2.4248079E-03 - - 2.4441792E-03 - - 2.4510541E-03 - - 2.4640212E-03 - - 2.4741885E-03 - - 2.4697219E-03 - - 2.4721421E-03 - - 2.4729172E-03 - - - 3.0860746E-01 - - 5.0621457E-02 - - 2.7347709E-02 - - 4.7204795E-03 - - 4.0838896E-03 - - 1.6974585E-03 - - - - 3.0865194E-01 - - 5.0806752E-02 - - 2.6916586E-02 - - 4.8439138E-03 - - 4.1728626E-03 - - 1.7130886E-03 - - - - 3.0861586E-01 - - 5.0757624E-02 - - 2.7196188E-02 - - 4.8679553E-03 - - 4.0626181E-03 - - 1.7815988E-03 - - - - 3.0850283E-01 - - 5.0925397E-02 - - 2.7204505E-02 - - 4.8109149E-03 - - 4.1177685E-03 - - 1.7500469E-03 - - - - 3.0831737E-01 - - 5.1138142E-02 - - 2.7308021E-02 - - 4.8683307E-03 - - 4.0620680E-03 - - 1.6728150E-03 - - - - 3.0815133E-01 - - 5.1220538E-02 - - 2.7286345E-02 - - 4.8715905E-03 - - 4.0963982E-03 - - 1.6783881E-03 - - - - 3.0777979E-01 - - 5.1536936E-02 - - 2.7522750E-02 - - 4.9751865E-03 - - 4.1461347E-03 - - 1.7481718E-03 - - - - 3.0740186E-01 - - 5.1745014E-02 - - 2.7548398E-02 - - 4.9705992E-03 - - 4.2128374E-03 - - 1.7852471E-03 - - - - 3.0674467E-01 - - 5.2102012E-02 - - 2.7721735E-02 - - 4.9326171E-03 - - 4.2065723E-03 - - 1.7520577E-03 - - - - 3.0588587E-01 - - 5.2410298E-02 - - 2.7935183E-02 - - 5.1068594E-03 - - 4.2771962E-03 - - 1.7875734E-03 - - - - 3.0465659E-01 - - 5.2543078E-02 - - 2.7962434E-02 - - 5.0839680E-03 - - 4.3050048E-03 - - 1.8499733E-03 - - - - 3.0312229E-01 - - 5.2483292E-02 - - 2.8137041E-02 - - 5.2734764E-03 - - 4.4574974E-03 - - 1.8578935E-03 - - - - 3.0117092E-01 - - 5.2332000E-02 - - 2.8003257E-02 - - 5.2432554E-03 - - 4.5485878E-03 - - 1.8980534E-03 - - - - 2.9880209E-01 - - 5.1679340E-02 - - 2.7750518E-02 - - 5.3056401E-03 - - 4.5878997E-03 - - 1.9401945E-03 - - - - 2.9627667E-01 - - 5.0169523E-02 - - 2.7059202E-02 - - 5.2026216E-03 - - 4.5921641E-03 - - 1.8856744E-03 - - - - 2.9609986E-01 - - 4.6032461E-02 - - 2.4630572E-02 - - 4.5841577E-03 - - 3.9297754E-03 - - 1.6420383E-03 - - - - 3.0675667E-01 - - 3.7400062E-02 - - 1.9426565E-02 - - 2.7294131E-03 - - 2.0654845E-03 - - 6.7157182E-04 - - - - 3.1112942E-01 - - 3.2514340E-02 - - 1.7042298E-02 - - 2.2975512E-03 - - 1.7171252E-03 - - 6.1586296E-04 - - - - 3.1168284E-01 - - 2.9994361E-02 - - 1.5982971E-02 - - 2.2082409E-03 - - 1.7621544E-03 - - 6.7848731E-04 - - - - 3.1094402E-01 - - 2.9043011E-02 - - 1.5559822E-02 - - 2.3867453E-03 - - 1.8805422E-03 - - 8.0257257E-04 - - - - 3.0988917E-01 - - 2.8642621E-02 - - 1.5527633E-02 - - 2.5363175E-03 - - 2.0667848E-03 - - 8.9512793E-04 - - - - 3.0900783E-01 - - 2.8683967E-02 - - 1.5531635E-02 - - 2.6907133E-03 - - 2.2374989E-03 - - 9.9838820E-04 - - - - 3.0823110E-01 - - 2.8772506E-02 - - 1.5617343E-02 - - 2.7855260E-03 - - 2.3324886E-03 - - 1.0334317E-03 - - - - 3.0768619E-01 - - 2.9118421E-02 - - 1.5860568E-02 - - 2.8469804E-03 - - 2.4600144E-03 - - 1.0754851E-03 - - - - 3.0729355E-01 - - 2.9429106E-02 - - 1.6138063E-02 - - 2.9901807E-03 - - 2.5154903E-03 - - 1.1139796E-03 - - - - 3.0707342E-01 - - 2.9773340E-02 - - 1.6110013E-02 - - 2.9606704E-03 - - 2.6433692E-03 - - 1.1310602E-03 - - - - 3.0685025E-01 - - 3.0055483E-02 - - 1.6246774E-02 - - 3.1035410E-03 - - 2.6316501E-03 - - 1.1158252E-03 - - - - 3.0681469E-01 - - 3.0238686E-02 - - 1.6524723E-02 - - 3.0402635E-03 - - 2.6108287E-03 - - 1.1691486E-03 - - - - 3.0690606E-01 - - 3.0618190E-02 - - 1.6493402E-02 - - 3.0268029E-03 - - 2.5956288E-03 - - 1.0751657E-03 - - - - 3.0676357E-01 - - 3.0613175E-02 - - 1.6679358E-02 - - 2.8764512E-03 - - 2.5398735E-03 - - 1.0482210E-03 - - - - 3.0676223E-01 - - 3.0798581E-02 - - 1.6764686E-02 - - 3.1471928E-03 - - 2.7160881E-03 - - 1.2265875E-03 - - - - 3.0687178E-01 - - 3.0702117E-02 - - 1.6628813E-02 - - 2.8692462E-03 - - 2.4997850E-03 - - 9.3974161E-04 - - - 1.0000416E+00 - - - 1.0000513E+00 - - - 1.0000397E+00 - - - 1.0000409E+00 - - - 1.0000455E+00 - - - 1.0000417E+00 - - - 1.0000452E+00 - - - 1.0000431E+00 - - - 1.0000455E+00 - - - 1.0000451E+00 - - - 1.0000445E+00 - - - 1.0000482E+00 - - - 1.0000507E+00 - - - 1.0000542E+00 - - - 1.0000545E+00 - - - 1.0000461E+00 - - - 1.0000114E+00 - - - 1.0000112E+00 - - - 1.0000195E+00 - - - 1.0000216E+00 - - - 1.0000279E+00 - - - 1.0000307E+00 - - - 1.0000302E+00 - - - 1.0000313E+00 - - - 1.0000334E+00 - - - 1.0000309E+00 - - - 1.0000325E+00 - - - 1.0000318E+00 - - - 1.0000346E+00 - - - 1.0000335E+00 - - - 1.0000285E+00 - - - 1.0000358E+00 - - - - - lwtr_ang - lwtr_ang - 2.5300000E-08 - 5 - false - 32 - 1 - angle - - 8.3129229E-01 - - 8.3203829E-01 - - 8.3332424E-01 - - 8.3539719E-01 - - 8.3799288E-01 - - 8.4156597E-01 - - 8.4594074E-01 - - 8.5122773E-01 - - 8.5788274E-01 - - 8.6633387E-01 - - 8.7719846E-01 - - 8.9195077E-01 - - 9.1326621E-01 - - 9.4469159E-01 - - 9.9368716E-01 - - 1.0616854E+00 - - 1.0982938E+00 - - 1.0997200E+00 - - 1.0855410E+00 - - 1.0676695E+00 - - 1.0508172E+00 - - 1.0369337E+00 - - 1.0255762E+00 - - 1.0162841E+00 - - 1.0086633E+00 - - 1.0025783E+00 - - 9.9737297E-01 - - 9.9326768E-01 - - 9.9030852E-01 - - 9.8792719E-01 - - 9.8610453E-01 - - 9.8540665E-01 - - - 7.7368065E-03 - - 7.7519393E-03 - - 7.7819449E-03 - - 7.8285240E-03 - - 7.8881877E-03 - - 7.9652685E-03 - - 8.0588251E-03 - - 8.1724303E-03 - - 8.3079937E-03 - - 8.4749946E-03 - - 8.6811506E-03 - - 8.9456784E-03 - - 9.3049336E-03 - - 9.8025199E-03 - - 1.0529992E-02 - - 1.1498571E-02 - - 1.2065971E-02 - - 1.2168395E-02 - - 1.2053690E-02 - - 1.1870414E-02 - - 1.1678759E-02 - - 1.1516371E-02 - - 1.1377145E-02 - - 1.1262809E-02 - - 1.1166687E-02 - - 1.1090107E-02 - - 1.1022668E-02 - - 1.0968772E-02 - - 1.0931381E-02 - - 1.0898236E-02 - - 1.0872094E-02 - - 1.0866295E-02 - - - 8.2371185E-01 - - 3.5234207E-01 - - 1.1927931E-01 - - 7.4555729E-03 - - -1.8093822E-02 - - 4.7584668E-04 - - - - 8.2420033E-01 - - 3.5255993E-01 - - 1.1937026E-01 - - 7.2853742E-03 - - -1.8313481E-02 - - 4.3042936E-04 - - - - 8.2554395E-01 - - 3.5269171E-01 - - 1.1923224E-01 - - 7.3701368E-03 - - -1.8272340E-02 - - 4.4800957E-04 - - - - 8.2759297E-01 - - 3.5316566E-01 - - 1.1927088E-01 - - 7.3660347E-03 - - -1.8328170E-02 - - 4.1130682E-04 - - - - 8.3010220E-01 - - 3.5369971E-01 - - 1.1938537E-01 - - 7.4104975E-03 - - -1.8303317E-02 - - 4.1953876E-04 - - - - 8.3343687E-01 - - 3.5441436E-01 - - 1.1949872E-01 - - 7.5322327E-03 - - -1.8306753E-02 - - 4.5747101E-04 - - - - 8.3787092E-01 - - 3.5551997E-01 - - 1.1969232E-01 - - 7.5811660E-03 - - -1.8329166E-02 - - 4.7852748E-04 - - - - 8.4310387E-01 - - 3.5672367E-01 - - 1.1987885E-01 - - 7.6564988E-03 - - -1.8365527E-02 - - 4.5067238E-04 - - - - 8.4958953E-01 - - 3.5843887E-01 - - 1.2018528E-01 - - 7.7892315E-03 - - -1.8386164E-02 - - 4.8596316E-04 - - - - 8.5783406E-01 - - 3.6063097E-01 - - 1.2066889E-01 - - 7.9351893E-03 - - -1.8471175E-02 - - 4.7399741E-04 - - - - 8.6863002E-01 - - 3.6377631E-01 - - 1.2139807E-01 - - 8.1733217E-03 - - -1.8540490E-02 - - 5.0406643E-04 - - - - 8.8306988E-01 - - 3.6819641E-01 - - 1.2250274E-01 - - 8.4479144E-03 - - -1.8664160E-02 - - 5.3786229E-04 - - - - 9.0387733E-01 - - 3.7488040E-01 - - 1.2420959E-01 - - 8.7500816E-03 - - -1.8976448E-02 - - 4.9664889E-04 - - - - 9.3478951E-01 - - 3.8530100E-01 - - 1.2704555E-01 - - 9.1818403E-03 - - -1.9402464E-02 - - 5.3777400E-04 - - - - 9.8306151E-01 - - 4.0212328E-01 - - 1.3182489E-01 - - 9.8420986E-03 - - -2.0147587E-02 - - 5.9236718E-04 - - - - 1.0501953E+00 - - 4.2587762E-01 - - 1.3867637E-01 - - 1.0689470E-02 - - -2.1155894E-02 - - 6.5005469E-04 - - - - 1.0862685E+00 - - 4.3797788E-01 - - 1.4197736E-01 - - 1.1172759E-02 - - -2.1737067E-02 - - 6.5599084E-04 - - - - 1.0874414E+00 - - 4.3717092E-01 - - 1.4142760E-01 - - 1.1235986E-02 - - -2.1646253E-02 - - 6.5585383E-04 - - - - 1.0736455E+00 - - 4.3084349E-01 - - 1.3933736E-01 - - 1.1186759E-02 - - -2.1309779E-02 - - 6.3989000E-04 - - - - 1.0558960E+00 - - 4.2321090E-01 - - 1.3684390E-01 - - 1.1034633E-02 - - -2.0842589E-02 - - 6.8339604E-04 - - - - 1.0391120E+00 - - 4.1635648E-01 - - 1.3463939E-01 - - 1.0869743E-02 - - -2.0503958E-02 - - 6.5877305E-04 - - - - 1.0254663E+00 - - 4.1079355E-01 - - 1.3288830E-01 - - 1.0692002E-02 - - -2.0222325E-02 - - 7.2411022E-04 - - - - 1.0142449E+00 - - 4.0621344E-01 - - 1.3145072E-01 - - 1.0526222E-02 - - -1.9995334E-02 - - 6.8891812E-04 - - - - 1.0049846E+00 - - 4.0236090E-01 - - 1.3022093E-01 - - 1.0429641E-02 - - -1.9811424E-02 - - 7.3287561E-04 - - - - 9.9758865E-01 - - 3.9933064E-01 - - 1.2934518E-01 - - 1.0285856E-02 - - -1.9735216E-02 - - 6.4095239E-04 - - - - 9.9137092E-01 - - 3.9669204E-01 - - 1.2850897E-01 - - 1.0180247E-02 - - -1.9595919E-02 - - 7.4239863E-04 - - - - 9.8633885E-01 - - 3.9464706E-01 - - 1.2782783E-01 - - 1.0115679E-02 - - -1.9489063E-02 - - 6.7732699E-04 - - - - 9.8241480E-01 - - 3.9293162E-01 - - 1.2725328E-01 - - 1.0076113E-02 - - -1.9411729E-02 - - 6.7080378E-04 - - - - 9.7912906E-01 - - 3.9164180E-01 - - 1.2687293E-01 - - 9.9947816E-03 - - -1.9390105E-02 - - 6.8484948E-04 - - - - 9.7702901E-01 - - 3.9079267E-01 - - 1.2678305E-01 - - 1.0006132E-02 - - -1.9296574E-02 - - 7.3827259E-04 - - - - 9.7553202E-01 - - 3.9010913E-01 - - 1.2644932E-01 - - 9.9292219E-03 - - -1.9314591E-02 - - 7.3482134E-04 - - - - 9.7483429E-01 - - 3.8985598E-01 - - 1.2640804E-01 - - 9.9206549E-03 - - -1.9266376E-02 - - 7.6472379E-04 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - - - uo2_ang_mu - uo2_ang_mu - 2.5300000E-08 - 32 - true - 32 - 1 - angle - histogram - - 4.0734790E-01 - - 4.0709470E-01 - - 4.0665280E-01 - - 4.0605122E-01 - - 4.0509226E-01 - - 4.0399893E-01 - - 4.0264927E-01 - - 4.0112684E-01 - - 3.9937450E-01 - - 3.9743081E-01 - - 3.9533879E-01 - - 3.9307550E-01 - - 3.9084961E-01 - - 3.8878017E-01 - - 3.8751931E-01 - - 3.8693825E-01 - - 3.9039929E-01 - - 4.0037023E-01 - - 4.1057791E-01 - - 4.1924835E-01 - - 4.2629128E-01 - - 4.3202621E-01 - - 4.3673213E-01 - - 4.4062993E-01 - - 4.4385222E-01 - - 4.4647166E-01 - - 4.4861335E-01 - - 4.5026817E-01 - - 4.5165329E-01 - - 4.5255720E-01 - - 4.5310208E-01 - - 4.5337269E-01 - - - 3.1599020E-02 - - 3.1371085E-02 - - 3.1023091E-02 - - 3.0539250E-02 - - 2.9839460E-02 - - 2.9013479E-02 - - 2.8058288E-02 - - 2.7047229E-02 - - 2.5977776E-02 - - 2.4952391E-02 - - 2.4009896E-02 - - 2.3244570E-02 - - 2.2725200E-02 - - 2.2489873E-02 - - 2.2624168E-02 - - 2.3059735E-02 - - 2.4782557E-02 - - 2.8553081E-02 - - 3.3194318E-02 - - 3.8038660E-02 - - 4.2666012E-02 - - 4.6923885E-02 - - 5.0708283E-02 - - 5.3996846E-02 - - 5.6845491E-02 - - 5.9213445E-02 - - 6.1182604E-02 - - 6.2742563E-02 - - 6.3985293E-02 - - 6.4852148E-02 - - 6.5364227E-02 - - 6.5703785E-02 - - - 4.5146530E-02 - - 4.4766687E-02 - - 4.4155441E-02 - - 4.3323960E-02 - - 4.2141314E-02 - - 4.0739637E-02 - - 3.9143652E-02 - - 3.7465300E-02 - - 3.5735871E-02 - - 3.4113931E-02 - - 3.2678644E-02 - - 3.1591060E-02 - - 3.0966537E-02 - - 3.0821062E-02 - - 3.1238242E-02 - - 3.2075654E-02 - - 3.4603728E-02 - - 3.9898114E-02 - - 4.6725370E-02 - - 5.4142159E-02 - - 6.1436273E-02 - - 6.8238302E-02 - - 7.4365771E-02 - - 7.9727018E-02 - - 8.4398863E-02 - - 8.8315890E-02 - - 9.1574736E-02 - - 9.4183896E-02 - - 9.6266615E-02 - - 9.7706019E-02 - - 9.8564505E-02 - - 9.9171965E-02 - - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - - 1.8183034E-02 - - 1.8028751E-02 - - 1.7777081E-02 - - 1.7434939E-02 - - 1.6947918E-02 - - 1.6371445E-02 - - 1.5714505E-02 - - 1.5023310E-02 - - 1.4310527E-02 - - 1.3640363E-02 - - 1.3045308E-02 - - 1.2590537E-02 - - 1.2323486E-02 - - 1.2250235E-02 - - 1.2408325E-02 - - 1.2741816E-02 - - 1.3791905E-02 - - 1.6011218E-02 - - 1.8846275E-02 - - 2.1907807E-02 - - 2.4909120E-02 - - 2.7704245E-02 - - 3.0220623E-02 - - 3.2422114E-02 - - 3.4339614E-02 - - 3.5947934E-02 - - 3.7286018E-02 - - 3.8357139E-02 - - 3.9212858E-02 - - 3.9804080E-02 - - 4.0156625E-02 - - 4.0404918E-02 - - - 9.8066123E-03 - - 9.6646401E-03 - - 9.6663597E-03 - - 9.6289590E-03 - - 9.6096138E-03 - - 9.6458323E-03 - - 9.7060173E-03 - - 9.7686742E-03 - - 9.7497590E-03 - - 9.8863575E-03 - - 9.9653503E-03 - - 1.0024461E-02 - - 1.0143433E-02 - - 1.0224038E-02 - - 1.0343441E-02 - - 1.0433289E-02 - - 1.0526146E-02 - - 1.0783759E-02 - - 1.0949268E-02 - - 1.1096291E-02 - - 1.1232675E-02 - - 1.1455467E-02 - - 1.1650746E-02 - - 1.1903201E-02 - - 1.2297735E-02 - - 1.2748370E-02 - - 1.3264457E-02 - - 1.4048689E-02 - - 1.5280440E-02 - - 1.6908123E-02 - - 1.9601832E-02 - - 2.3844984E-02 - - - - 9.7708240E-03 - - 9.6914019E-03 - - 9.6149267E-03 - - 9.5973173E-03 - - 9.6433893E-03 - - 9.6506128E-03 - - 9.7039801E-03 - - 9.6956785E-03 - - 9.7873194E-03 - - 9.8654118E-03 - - 9.9413480E-03 - - 1.0063248E-02 - - 1.0102923E-02 - - 1.0232802E-02 - - 1.0308882E-02 - - 1.0501651E-02 - - 1.0589986E-02 - - 1.0719182E-02 - - 1.0893048E-02 - - 1.1057750E-02 - - 1.1303383E-02 - - 1.1462120E-02 - - 1.1668725E-02 - - 1.1965138E-02 - - 1.2270967E-02 - - 1.2704483E-02 - - 1.3318045E-02 - - 1.4113776E-02 - - 1.5284443E-02 - - 1.6903540E-02 - - 1.9623766E-02 - - 2.3773086E-02 - - - - 9.7573912E-03 - - 9.6754767E-03 - - 9.6414920E-03 - - 9.5888776E-03 - - 9.6229707E-03 - - 9.6517720E-03 - - 9.7047117E-03 - - 9.7260741E-03 - - 9.8017859E-03 - - 9.8536413E-03 - - 9.9389825E-03 - - 1.0024606E-02 - - 1.0138509E-02 - - 1.0234629E-02 - - 1.0324330E-02 - - 1.0453936E-02 - - 1.0578467E-02 - - 1.0739823E-02 - - 1.0879319E-02 - - 1.1046986E-02 - - 1.1241981E-02 - - 1.1441204E-02 - - 1.1664457E-02 - - 1.1957610E-02 - - 1.2276940E-02 - - 1.2759947E-02 - - 1.3279607E-02 - - 1.4124886E-02 - - 1.5267698E-02 - - 1.6982394E-02 - - 1.9550155E-02 - - 2.3789453E-02 - - - - 9.7595941E-03 - - 9.6406785E-03 - - 9.6091241E-03 - - 9.6094212E-03 - - 9.6096714E-03 - - 9.6231813E-03 - - 9.6784094E-03 - - 9.7493834E-03 - - 9.7951671E-03 - - 9.8514115E-03 - - 9.9241369E-03 - - 1.0012170E-02 - - 1.0117529E-02 - - 1.0213412E-02 - - 1.0335767E-02 - - 1.0447944E-02 - - 1.0584231E-02 - - 1.0753231E-02 - - 1.0883138E-02 - - 1.1065663E-02 - - 1.1250080E-02 - - 1.1439297E-02 - - 1.1646700E-02 - - 1.1958053E-02 - - 1.2287514E-02 - - 1.2721568E-02 - - 1.3290189E-02 - - 1.4110041E-02 - - 1.5281715E-02 - - 1.6979118E-02 - - 1.9608566E-02 - - 2.3793845E-02 - - - - 9.7316881E-03 - - 9.6194631E-03 - - 9.6065192E-03 - - 9.5773341E-03 - - 9.6080573E-03 - - 9.6136679E-03 - - 9.6707217E-03 - - 9.7207622E-03 - - 9.7745677E-03 - - 9.8542855E-03 - - 9.9290325E-03 - - 1.0013807E-02 - - 1.0087705E-02 - - 1.0212493E-02 - - 1.0318553E-02 - - 1.0440413E-02 - - 1.0586043E-02 - - 1.0693482E-02 - - 1.0881032E-02 - - 1.1028668E-02 - - 1.1236016E-02 - - 1.1448039E-02 - - 1.1645248E-02 - - 1.1940864E-02 - - 1.2280554E-02 - - 1.2704859E-02 - - 1.3284908E-02 - - 1.4087561E-02 - - 1.5269781E-02 - - 1.6974160E-02 - - 1.9647654E-02 - - 2.3878185E-02 - - - - 9.7161201E-03 - - 9.6202380E-03 - - 9.5797790E-03 - - 9.5545189E-03 - - 9.5785124E-03 - - 9.5970413E-03 - - 9.6077970E-03 - - 9.7078158E-03 - - 9.7457417E-03 - - 9.8241572E-03 - - 9.9053715E-03 - - 9.9664533E-03 - - 1.0069700E-02 - - 1.0182303E-02 - - 1.0310258E-02 - - 1.0426742E-02 - - 1.0561490E-02 - - 1.0707708E-02 - - 1.0863937E-02 - - 1.1051125E-02 - - 1.1221704E-02 - - 1.1442069E-02 - - 1.1658848E-02 - - 1.1941489E-02 - - 1.2275743E-02 - - 1.2702110E-02 - - 1.3323051E-02 - - 1.4108176E-02 - - 1.5289516E-02 - - 1.6993392E-02 - - 1.9675117E-02 - - 2.3895695E-02 - - - - 9.6862964E-03 - - 9.6118860E-03 - - 9.5204994E-03 - - 9.5427943E-03 - - 9.5461966E-03 - - 9.5657839E-03 - - 9.5949449E-03 - - 9.6654696E-03 - - 9.7413833E-03 - - 9.7999604E-03 - - 9.8652718E-03 - - 9.9395415E-03 - - 1.0066252E-02 - - 1.0162957E-02 - - 1.0288525E-02 - - 1.0410136E-02 - - 1.0544012E-02 - - 1.0683294E-02 - - 1.0857487E-02 - - 1.1034643E-02 - - 1.1202400E-02 - - 1.1413244E-02 - - 1.1649707E-02 - - 1.1927823E-02 - - 1.2268032E-02 - - 1.2711207E-02 - - 1.3301163E-02 - - 1.4107114E-02 - - 1.5299888E-02 - - 1.7035047E-02 - - 1.9688248E-02 - - 2.3980184E-02 - - - - 9.6789320E-03 - - 9.5794368E-03 - - 9.5136834E-03 - - 9.4987637E-03 - - 9.5122403E-03 - - 9.5462846E-03 - - 9.5893599E-03 - - 9.6291844E-03 - - 9.6755880E-03 - - 9.7758823E-03 - - 9.8512097E-03 - - 9.9153183E-03 - - 1.0010492E-02 - - 1.0132751E-02 - - 1.0249082E-02 - - 1.0374304E-02 - - 1.0525789E-02 - - 1.0647590E-02 - - 1.0816183E-02 - - 1.1002705E-02 - - 1.1172733E-02 - - 1.1391942E-02 - - 1.1634015E-02 - - 1.1896152E-02 - - 1.2250313E-02 - - 1.2701494E-02 - - 1.3297953E-02 - - 1.4128277E-02 - - 1.5304878E-02 - - 1.7057822E-02 - - 1.9759949E-02 - - 2.4058227E-02 - - - - 9.6295658E-03 - - 9.5389047E-03 - - 9.4742925E-03 - - 9.4575039E-03 - - 9.4670086E-03 - - 9.5016333E-03 - - 9.5287576E-03 - - 9.5962610E-03 - - 9.6450345E-03 - - 9.7355000E-03 - - 9.8168240E-03 - - 9.8832939E-03 - - 9.9783337E-03 - - 1.0096077E-02 - - 1.0226691E-02 - - 1.0343925E-02 - - 1.0478576E-02 - - 1.0624400E-02 - - 1.0795052E-02 - - 1.0971506E-02 - - 1.1155210E-02 - - 1.1359948E-02 - - 1.1600072E-02 - - 1.1891155E-02 - - 1.2217464E-02 - - 1.2687949E-02 - - 1.3279851E-02 - - 1.4139232E-02 - - 1.5331088E-02 - - 1.7109049E-02 - - 1.9804341E-02 - - 2.4140346E-02 - - - - 9.5761863E-03 - - 9.4820918E-03 - - 9.4335419E-03 - - 9.4124923E-03 - - 9.4238881E-03 - - 9.4447526E-03 - - 9.4999957E-03 - - 9.5315541E-03 - - 9.6078277E-03 - - 9.7003335E-03 - - 9.7574525E-03 - - 9.8379436E-03 - - 9.9462733E-03 - - 1.0053971E-02 - - 1.0174903E-02 - - 1.0296178E-02 - - 1.0416178E-02 - - 1.0598338E-02 - - 1.0736969E-02 - - 1.0921999E-02 - - 1.1103049E-02 - - 1.1337535E-02 - - 1.1560952E-02 - - 1.1844754E-02 - - 1.2186109E-02 - - 1.2650980E-02 - - 1.3288356E-02 - - 1.4113781E-02 - - 1.5336174E-02 - - 1.7136757E-02 - - 1.9885917E-02 - - 2.4274812E-02 - - - - 9.5122168E-03 - - 9.4370370E-03 - - 9.3789842E-03 - - 9.3641793E-03 - - 9.3461446E-03 - - 9.3736151E-03 - - 9.4378621E-03 - - 9.4888307E-03 - - 9.5578870E-03 - - 9.6287585E-03 - - 9.7018579E-03 - - 9.7842398E-03 - - 9.8853931E-03 - - 9.9928939E-03 - - 1.0118830E-02 - - 1.0234335E-02 - - 1.0390558E-02 - - 1.0549529E-02 - - 1.0695492E-02 - - 1.0871300E-02 - - 1.1074656E-02 - - 1.1276285E-02 - - 1.1528116E-02 - - 1.1795259E-02 - - 1.2170410E-02 - - 1.2620687E-02 - - 1.3248447E-02 - - 1.4113310E-02 - - 1.5330992E-02 - - 1.7146317E-02 - - 1.9971083E-02 - - 2.4420125E-02 - - - - 9.4655965E-03 - - 9.3472543E-03 - - 9.3135845E-03 - - 9.2723897E-03 - - 9.2802062E-03 - - 9.3207904E-03 - - 9.3438769E-03 - - 9.4089282E-03 - - 9.4772470E-03 - - 9.5593066E-03 - - 9.6350349E-03 - - 9.7156422E-03 - - 9.8254749E-03 - - 9.9256153E-03 - - 1.0046422E-02 - - 1.0170127E-02 - - 1.0324109E-02 - - 1.0494779E-02 - - 1.0643991E-02 - - 1.0830850E-02 - - 1.1006031E-02 - - 1.1226896E-02 - - 1.1461160E-02 - - 1.1751421E-02 - - 1.2117075E-02 - - 1.2580807E-02 - - 1.3191655E-02 - - 1.4078045E-02 - - 1.5308284E-02 - - 1.7194422E-02 - - 2.0045307E-02 - - 2.4607445E-02 - - - - 9.3803794E-03 - - 9.2679518E-03 - - 9.2244314E-03 - - 9.2113545E-03 - - 9.2138570E-03 - - 9.2462589E-03 - - 9.2883856E-03 - - 9.3378797E-03 - - 9.4087558E-03 - - 9.4791189E-03 - - 9.5459849E-03 - - 9.6532937E-03 - - 9.7407231E-03 - - 9.8542750E-03 - - 9.9718785E-03 - - 1.0102253E-02 - - 1.0257191E-02 - - 1.0422947E-02 - - 1.0576154E-02 - - 1.0751370E-02 - - 1.0937694E-02 - - 1.1150504E-02 - - 1.1403363E-02 - - 1.1690271E-02 - - 1.2041631E-02 - - 1.2515941E-02 - - 1.3148002E-02 - - 1.4030663E-02 - - 1.5293666E-02 - - 1.7182409E-02 - - 2.0111404E-02 - - 2.4776028E-02 - - - - 9.3172617E-03 - - 9.2089569E-03 - - 9.1486659E-03 - - 9.1277777E-03 - - 9.1461098E-03 - - 9.1678665E-03 - - 9.2093270E-03 - - 9.2630599E-03 - - 9.3084731E-03 - - 9.4133582E-03 - - 9.4836368E-03 - - 9.5792942E-03 - - 9.6772510E-03 - - 9.7775420E-03 - - 9.9042034E-03 - - 1.0042269E-02 - - 1.0180349E-02 - - 1.0339342E-02 - - 1.0499500E-02 - - 1.0689206E-02 - - 1.0856780E-02 - - 1.1064872E-02 - - 1.1313606E-02 - - 1.1607748E-02 - - 1.1964604E-02 - - 1.2435691E-02 - - 1.3060461E-02 - - 1.3974178E-02 - - 1.5269813E-02 - - 1.7174181E-02 - - 2.0168154E-02 - - 2.5006625E-02 - - - - 9.2675186E-03 - - 9.1560947E-03 - - 9.1099682E-03 - - 9.0686023E-03 - - 9.0949282E-03 - - 9.1189359E-03 - - 9.1587135E-03 - - 9.2079644E-03 - - 9.2872523E-03 - - 9.3678425E-03 - - 9.4331971E-03 - - 9.5255074E-03 - - 9.6234797E-03 - - 9.7408756E-03 - - 9.8464228E-03 - - 9.9839770E-03 - - 1.0134229E-02 - - 1.0296950E-02 - - 1.0437157E-02 - - 1.0621205E-02 - - 1.0805038E-02 - - 1.1016214E-02 - - 1.1261528E-02 - - 1.1539985E-02 - - 1.1895722E-02 - - 1.2371092E-02 - - 1.3001136E-02 - - 1.3913205E-02 - - 1.5214879E-02 - - 1.7172526E-02 - - 2.0220324E-02 - - 2.5144658E-02 - - - - 9.2487420E-03 - - 9.1281258E-03 - - 9.0754703E-03 - - 9.0528962E-03 - - 9.0607826E-03 - - 9.0836186E-03 - - 9.1336267E-03 - - 9.1791302E-03 - - 9.2456080E-03 - - 9.3262261E-03 - - 9.3970635E-03 - - 9.4814471E-03 - - 9.5988170E-03 - - 9.7082444E-03 - - 9.8223867E-03 - - 9.9431245E-03 - - 1.0105918E-02 - - 1.0235908E-02 - - 1.0399441E-02 - - 1.0585520E-02 - - 1.0757015E-02 - - 1.0981562E-02 - - 1.1194196E-02 - - 1.1486474E-02 - - 1.1845432E-02 - - 1.2322129E-02 - - 1.2940763E-02 - - 1.3835543E-02 - - 1.5166292E-02 - - 1.7159569E-02 - - 2.0241404E-02 - - 2.5261208E-02 - - - - 9.3326963E-03 - - 9.2136145E-03 - - 9.1672115E-03 - - 9.1448034E-03 - - 9.1509378E-03 - - 9.1710414E-03 - - 9.2163629E-03 - - 9.2665486E-03 - - 9.3325121E-03 - - 9.4016396E-03 - - 9.5034088E-03 - - 9.5773816E-03 - - 9.6674816E-03 - - 9.7850853E-03 - - 9.9014422E-03 - - 1.0023693E-02 - - 1.0166562E-02 - - 1.0315995E-02 - - 1.0472398E-02 - - 1.0641203E-02 - - 1.0830711E-02 - - 1.1048828E-02 - - 1.1263336E-02 - - 1.1551095E-02 - - 1.1894787E-02 - - 1.2358496E-02 - - 1.2983340E-02 - - 1.3874895E-02 - - 1.5186930E-02 - - 1.7144384E-02 - - 2.0133533E-02 - - 2.5038814E-02 - - - - 9.5906528E-03 - - 9.4714149E-03 - - 9.4373276E-03 - - 9.4092245E-03 - - 9.4080878E-03 - - 9.4464166E-03 - - 9.4856267E-03 - - 9.5436808E-03 - - 9.6059463E-03 - - 9.6771305E-03 - - 9.7582049E-03 - - 9.8361595E-03 - - 9.9382461E-03 - - 1.0051079E-02 - - 1.0152805E-02 - - 1.0287101E-02 - - 1.0441087E-02 - - 1.0565078E-02 - - 1.0711502E-02 - - 1.0891178E-02 - - 1.1071184E-02 - - 1.1292859E-02 - - 1.1522246E-02 - - 1.1788324E-02 - - 1.2135266E-02 - - 1.2615017E-02 - - 1.3201487E-02 - - 1.4060330E-02 - - 1.5281894E-02 - - 1.7084038E-02 - - 1.9845860E-02 - - 2.4315267E-02 - - - - 9.8248104E-03 - - 9.7323237E-03 - - 9.6774360E-03 - - 9.6780777E-03 - - 9.6806071E-03 - - 9.7078157E-03 - - 9.7458638E-03 - - 9.8100671E-03 - - 9.8562275E-03 - - 9.9244575E-03 - - 1.0022233E-02 - - 1.0083426E-02 - - 1.0184960E-02 - - 1.0286955E-02 - - 1.0393298E-02 - - 1.0523934E-02 - - 1.0674383E-02 - - 1.0799950E-02 - - 1.0950769E-02 - - 1.1117330E-02 - - 1.1304368E-02 - - 1.1511486E-02 - - 1.1731876E-02 - - 1.2009368E-02 - - 1.2343059E-02 - - 1.2776813E-02 - - 1.3375541E-02 - - 1.4170942E-02 - - 1.5323633E-02 - - 1.7010159E-02 - - 1.9570530E-02 - - 2.3678539E-02 - - - - 1.0003922E-02 - - 9.9126090E-03 - - 9.8710015E-03 - - 9.8670066E-03 - - 9.8659781E-03 - - 9.8893674E-03 - - 9.9377144E-03 - - 9.9843851E-03 - - 1.0043716E-02 - - 1.0114248E-02 - - 1.0187530E-02 - - 1.0267347E-02 - - 1.0358552E-02 - - 1.0462167E-02 - - 1.0591882E-02 - - 1.0702606E-02 - - 1.0831901E-02 - - 1.0977238E-02 - - 1.1108339E-02 - - 1.1308120E-02 - - 1.1462407E-02 - - 1.1644185E-02 - - 1.1896695E-02 - - 1.2152261E-02 - - 1.2470909E-02 - - 1.2904242E-02 - - 1.3463705E-02 - - 1.4217800E-02 - - 1.5306830E-02 - - 1.6913123E-02 - - 1.9352840E-02 - - 2.3210338E-02 - - - - 1.0110150E-02 - - 1.0038689E-02 - - 1.0006487E-02 - - 9.9882512E-03 - - 1.0012465E-02 - - 1.0038003E-02 - - 1.0080385E-02 - - 1.0133099E-02 - - 1.0195776E-02 - - 1.0230495E-02 - - 1.0337794E-02 - - 1.0414378E-02 - - 1.0494026E-02 - - 1.0600307E-02 - - 1.0712290E-02 - - 1.0823942E-02 - - 1.0947285E-02 - - 1.1079870E-02 - - 1.1237336E-02 - - 1.1392659E-02 - - 1.1573008E-02 - - 1.1782567E-02 - - 1.1965944E-02 - - 1.2231191E-02 - - 1.2530296E-02 - - 1.2940908E-02 - - 1.3487030E-02 - - 1.4206747E-02 - - 1.5258559E-02 - - 1.6813287E-02 - - 1.9165344E-02 - - 2.2905494E-02 - - - - 1.0214736E-02 - - 1.0132229E-02 - - 1.0105238E-02 - - 1.0076016E-02 - - 1.0102342E-02 - - 1.0126079E-02 - - 1.0166649E-02 - - 1.0211271E-02 - - 1.0274414E-02 - - 1.0328594E-02 - - 1.0415141E-02 - - 1.0493084E-02 - - 1.0583179E-02 - - 1.0679080E-02 - - 1.0785554E-02 - - 1.0896861E-02 - - 1.1025180E-02 - - 1.1151734E-02 - - 1.1308616E-02 - - 1.1460250E-02 - - 1.1631030E-02 - - 1.1818829E-02 - - 1.2020589E-02 - - 1.2270878E-02 - - 1.2564608E-02 - - 1.2974969E-02 - - 1.3498179E-02 - - 1.4207601E-02 - - 1.5228538E-02 - - 1.6730509E-02 - - 1.9011440E-02 - - 2.2710972E-02 - - - - 1.0268267E-02 - - 1.0196885E-02 - - 1.0157361E-02 - - 1.0140649E-02 - - 1.0169437E-02 - - 1.0183304E-02 - - 1.0243979E-02 - - 1.0276945E-02 - - 1.0343732E-02 - - 1.0412311E-02 - - 1.0476453E-02 - - 1.0547309E-02 - - 1.0646659E-02 - - 1.0745962E-02 - - 1.0848409E-02 - - 1.0960759E-02 - - 1.1082990E-02 - - 1.1214082E-02 - - 1.1358598E-02 - - 1.1499661E-02 - - 1.1661477E-02 - - 1.1836025E-02 - - 1.2058652E-02 - - 1.2293116E-02 - - 1.2566338E-02 - - 1.2977505E-02 - - 1.3480636E-02 - - 1.4176526E-02 - - 1.5190195E-02 - - 1.6660100E-02 - - 1.8910243E-02 - - 2.2560488E-02 - - - - 1.0317792E-02 - - 1.0247350E-02 - - 1.0209518E-02 - - 1.0176974E-02 - - 1.0202003E-02 - - 1.0234569E-02 - - 1.0290041E-02 - - 1.0329819E-02 - - 1.0401460E-02 - - 1.0453530E-02 - - 1.0512745E-02 - - 1.0606160E-02 - - 1.0688319E-02 - - 1.0769020E-02 - - 1.0865579E-02 - - 1.0991642E-02 - - 1.1131957E-02 - - 1.1257621E-02 - - 1.1387433E-02 - - 1.1532542E-02 - - 1.1687029E-02 - - 1.1880598E-02 - - 1.2082924E-02 - - 1.2307513E-02 - - 1.2595319E-02 - - 1.2957554E-02 - - 1.3464867E-02 - - 1.4143088E-02 - - 1.5132042E-02 - - 1.6579665E-02 - - 1.8862731E-02 - - 2.2454495E-02 - - - - 1.0353436E-02 - - 1.0273106E-02 - - 1.0227967E-02 - - 1.0220784E-02 - - 1.0226684E-02 - - 1.0260876E-02 - - 1.0312588E-02 - - 1.0358157E-02 - - 1.0401938E-02 - - 1.0498406E-02 - - 1.0534029E-02 - - 1.0633113E-02 - - 1.0711786E-02 - - 1.0806930E-02 - - 1.0902341E-02 - - 1.1005862E-02 - - 1.1140903E-02 - - 1.1256190E-02 - - 1.1418216E-02 - - 1.1551704E-02 - - 1.1699315E-02 - - 1.1876316E-02 - - 1.2095791E-02 - - 1.2321059E-02 - - 1.2598778E-02 - - 1.2945785E-02 - - 1.3441410E-02 - - 1.4150310E-02 - - 1.5110707E-02 - - 1.6555004E-02 - - 1.8801362E-02 - - 2.2362745E-02 - - - - 1.0368488E-02 - - 1.0298130E-02 - - 1.0243651E-02 - - 1.0237480E-02 - - 1.0271825E-02 - - 1.0283702E-02 - - 1.0344999E-02 - - 1.0388950E-02 - - 1.0443402E-02 - - 1.0499057E-02 - - 1.0554275E-02 - - 1.0647638E-02 - - 1.0712690E-02 - - 1.0827382E-02 - - 1.0931601E-02 - - 1.1018556E-02 - - 1.1152881E-02 - - 1.1290059E-02 - - 1.1420028E-02 - - 1.1563732E-02 - - 1.1705467E-02 - - 1.1895794E-02 - - 1.2092710E-02 - - 1.2310135E-02 - - 1.2594991E-02 - - 1.2963713E-02 - - 1.3446042E-02 - - 1.4105472E-02 - - 1.5078624E-02 - - 1.6548015E-02 - - 1.8734322E-02 - - 2.2344993E-02 - - - - 1.0381081E-02 - - 1.0306858E-02 - - 1.0277150E-02 - - 1.0252664E-02 - - 1.0290401E-02 - - 1.0294657E-02 - - 1.0329546E-02 - - 1.0392619E-02 - - 1.0438626E-02 - - 1.0515024E-02 - - 1.0591864E-02 - - 1.0665572E-02 - - 1.0764627E-02 - - 1.0867664E-02 - - 1.0949159E-02 - - 1.1055591E-02 - - 1.1176115E-02 - - 1.1296618E-02 - - 1.1417920E-02 - - 1.1572450E-02 - - 1.1714864E-02 - - 1.1894815E-02 - - 1.2080388E-02 - - 1.2311306E-02 - - 1.2600200E-02 - - 1.2956245E-02 - - 1.3438289E-02 - - 1.4113577E-02 - - 1.5087407E-02 - - 1.6503410E-02 - - 1.8740374E-02 - - 2.2290166E-02 - - - - 1.0379499E-02 - - 1.0316828E-02 - - 1.0280998E-02 - - 1.0282758E-02 - - 1.0275605E-02 - - 1.0306117E-02 - - 1.0348208E-02 - - 1.0378745E-02 - - 1.0464787E-02 - - 1.0530463E-02 - - 1.0608232E-02 - - 1.0674147E-02 - - 1.0763998E-02 - - 1.0837280E-02 - - 1.0949195E-02 - - 1.1058508E-02 - - 1.1190589E-02 - - 1.1322242E-02 - - 1.1432422E-02 - - 1.1582770E-02 - - 1.1718207E-02 - - 1.1912632E-02 - - 1.2075287E-02 - - 1.2309263E-02 - - 1.2598203E-02 - - 1.2947275E-02 - - 1.3422204E-02 - - 1.4101792E-02 - - 1.5074531E-02 - - 1.6493963E-02 - - 1.8703917E-02 - - 2.2279156E-02 - - - - 1.0425160E-02 - - 1.0318223E-02 - - 1.0301788E-02 - - 1.0294047E-02 - - 1.0284686E-02 - - 1.0349566E-02 - - 1.0366017E-02 - - 1.0397170E-02 - - 1.0476721E-02 - - 1.0527169E-02 - - 1.0602826E-02 - - 1.0679945E-02 - - 1.0766188E-02 - - 1.0868516E-02 - - 1.0967919E-02 - - 1.1069388E-02 - - 1.1166089E-02 - - 1.1293657E-02 - - 1.1442396E-02 - - 1.1579055E-02 - - 1.1756181E-02 - - 1.1901153E-02 - - 1.2075228E-02 - - 1.2329489E-02 - - 1.2582177E-02 - - 1.2965246E-02 - - 1.3451596E-02 - - 1.4114325E-02 - - 1.5048259E-02 - - 1.6478843E-02 - - 1.8702139E-02 - - 2.2209013E-02 - - - - 1.0403120E-02 - - 1.0338330E-02 - - 1.0290627E-02 - - 1.0277361E-02 - - 1.0322671E-02 - - 1.0363565E-02 - - 1.0362094E-02 - - 1.0440786E-02 - - 1.0485173E-02 - - 1.0557958E-02 - - 1.0608779E-02 - - 1.0701287E-02 - - 1.0735526E-02 - - 1.0841760E-02 - - 1.0953485E-02 - - 1.1083460E-02 - - 1.1193252E-02 - - 1.1297597E-02 - - 1.1457508E-02 - - 1.1572681E-02 - - 1.1742409E-02 - - 1.1907920E-02 - - 1.2078022E-02 - - 1.2328222E-02 - - 1.2585186E-02 - - 1.2967887E-02 - - 1.3432333E-02 - - 1.4108413E-02 - - 1.5033330E-02 - - 1.6472418E-02 - - 1.8651936E-02 - - 2.2205180E-02 - - - - 1.0383972E-02 - - 1.0327340E-02 - - 1.0320447E-02 - - 1.0278943E-02 - - 1.0322805E-02 - - 1.0366993E-02 - - 1.0395218E-02 - - 1.0418111E-02 - - 1.0463460E-02 - - 1.0564171E-02 - - 1.0601357E-02 - - 1.0671268E-02 - - 1.0756633E-02 - - 1.0863620E-02 - - 1.0982943E-02 - - 1.1088262E-02 - - 1.1182298E-02 - - 1.1297412E-02 - - 1.1404871E-02 - - 1.1585288E-02 - - 1.1730768E-02 - - 1.1878353E-02 - - 1.2074551E-02 - - 1.2333404E-02 - - 1.2612428E-02 - - 1.2970577E-02 - - 1.3454326E-02 - - 1.4077858E-02 - - 1.5040384E-02 - - 1.6507810E-02 - - 1.8671362E-02 - - 2.2195534E-02 - - - - 1.0393621E-02 - - 1.0343827E-02 - - 1.0278122E-02 - - 1.0307024E-02 - - 1.0321853E-02 - - 1.0374136E-02 - - 1.0395136E-02 - - 1.0457919E-02 - - 1.0485306E-02 - - 1.0588898E-02 - - 1.0597124E-02 - - 1.0623537E-02 - - 1.0731134E-02 - - 1.0828231E-02 - - 1.0959209E-02 - - 1.1072327E-02 - - 1.1248877E-02 - - 1.1263490E-02 - - 1.1402046E-02 - - 1.1566689E-02 - - 1.1767919E-02 - - 1.1861445E-02 - - 1.2076314E-02 - - 1.2322575E-02 - - 1.2537228E-02 - - 1.2963070E-02 - - 1.3353083E-02 - - 1.4108968E-02 - - 1.5044977E-02 - - 1.6501651E-02 - - 1.8769742E-02 - - 2.2133504E-02 - - - 1.0002763E+00 - - - 1.0002760E+00 - - - 1.0002658E+00 - - - 1.0002710E+00 - - - 1.0002776E+00 - - - 1.0002767E+00 - - - 1.0002833E+00 - - - 1.0002791E+00 - - - 1.0002788E+00 - - - 1.0002858E+00 - - - 1.0002884E+00 - - - 1.0002916E+00 - - - 1.0003039E+00 - - - 1.0003181E+00 - - - 1.0003365E+00 - - - 1.0003544E+00 - - - 1.0003372E+00 - - - 1.0002764E+00 - - - 1.0002508E+00 - - - 1.0002343E+00 - - - 1.0002360E+00 - - - 1.0002375E+00 - - - 1.0002331E+00 - - - 1.0002344E+00 - - - 1.0002385E+00 - - - 1.0002316E+00 - - - 1.0002360E+00 - - - 1.0002360E+00 - - - 1.0002354E+00 - - - 1.0002349E+00 - - - 1.0002325E+00 - - - 1.0002268E+00 - - - - - clad_ang_mu - clad_ang_mu - 2.5300000E-08 - 32 - false - 32 - 1 - angle - histogram - - 3.1005638E-01 - - 3.0999067E-01 - - 3.0994879E-01 - - 3.0987779E-01 - - 3.0961631E-01 - - 3.0948272E-01 - - 3.0913340E-01 - - 3.0868239E-01 - - 3.0799925E-01 - - 3.0712597E-01 - - 3.0590948E-01 - - 3.0432728E-01 - - 3.0235012E-01 - - 2.9996873E-01 - - 2.9743091E-01 - - 2.9739624E-01 - - 3.0835788E-01 - - 3.1305337E-01 - - 3.1379599E-01 - - 3.1314506E-01 - - 3.1216249E-01 - - 3.1129786E-01 - - 3.1059203E-01 - - 3.1009561E-01 - - 3.0977837E-01 - - 3.0951041E-01 - - 3.0930940E-01 - - 3.0929712E-01 - - 3.0925741E-01 - - 3.0917641E-01 - - 3.0919741E-01 - - 3.0912502E-01 - - - 1.3490691E-03 - - 1.3463259E-03 - - 1.3498512E-03 - - 1.3366347E-03 - - 1.3288899E-03 - - 1.3176269E-03 - - 1.3059971E-03 - - 1.2891508E-03 - - 1.2713136E-03 - - 1.2555332E-03 - - 1.2394055E-03 - - 1.2170158E-03 - - 1.1969201E-03 - - 1.1849620E-03 - - 1.1899173E-03 - - 1.2761137E-03 - - 1.6244505E-03 - - 1.9090551E-03 - - 2.0837409E-03 - - 2.1976011E-03 - - 2.2746911E-03 - - 2.3308251E-03 - - 2.3700744E-03 - - 2.3981231E-03 - - 2.4248079E-03 - - 2.4441792E-03 - - 2.4510541E-03 - - 2.4640212E-03 - - 2.4741885E-03 - - 2.4697219E-03 - - 2.4721421E-03 - - 2.4729172E-03 - - - 8.6638893E-03 - - 8.2719674E-03 - - 7.8055649E-03 - - 7.4105610E-03 - - 7.2544086E-03 - - 7.0854147E-03 - - 6.9965517E-03 - - 7.0314805E-03 - - 6.8552954E-03 - - 6.9138525E-03 - - 6.9528906E-03 - - 7.0689776E-03 - - 7.0720596E-03 - - 7.2523539E-03 - - 7.5405167E-03 - - 7.7624175E-03 - - 7.9838046E-03 - - 8.1702629E-03 - - 8.4784584E-03 - - 8.8970906E-03 - - 9.3105862E-03 - - 9.7826390E-03 - - 1.0253151E-02 - - 1.0659455E-02 - - 1.1134076E-02 - - 1.1649276E-02 - - 1.2603655E-02 - - 1.3342297E-02 - - 1.4372697E-02 - - 1.5779610E-02 - - 1.7933383E-02 - - 2.0318816E-02 - - - - 8.6137649E-03 - - 8.0815773E-03 - - 7.7778880E-03 - - 7.4879636E-03 - - 7.2446680E-03 - - 7.0652074E-03 - - 6.9244607E-03 - - 6.9131046E-03 - - 6.9017486E-03 - - 6.9408066E-03 - - 6.9814132E-03 - - 7.0440438E-03 - - 7.1589812E-03 - - 7.3353447E-03 - - 7.5896522E-03 - - 7.7529390E-03 - - 8.0199791E-03 - - 8.3484454E-03 - - 8.5960425E-03 - - 8.9554799E-03 - - 9.2763754E-03 - - 9.7440398E-03 - - 1.0084034E-02 - - 1.0634976E-02 - - 1.1176800E-02 - - 1.1768004E-02 - - 1.2488944E-02 - - 1.3414293E-02 - - 1.4307639E-02 - - 1.5845012E-02 - - 1.7838866E-02 - - 2.0339442E-02 - - - - 8.6069286E-03 - - 8.1600584E-03 - - 7.7753343E-03 - - 7.5082514E-03 - - 7.2541589E-03 - - 7.1052368E-03 - - 7.0049508E-03 - - 6.9087178E-03 - - 6.8877253E-03 - - 6.9276318E-03 - - 6.9580813E-03 - - 7.0116019E-03 - - 7.1577180E-03 - - 7.3369857E-03 - - 7.5182280E-03 - - 7.7277374E-03 - - 7.9440018E-03 - - 8.2744779E-03 - - 8.6378977E-03 - - 8.8881451E-03 - - 9.2653867E-03 - - 9.6492794E-03 - - 1.0205685E-02 - - 1.0657959E-02 - - 1.1210208E-02 - - 1.1713716E-02 - - 1.2497402E-02 - - 1.3347079E-02 - - 1.4469243E-02 - - 1.5835834E-02 - - 1.7754882E-02 - - 2.0415319E-02 - - - - 8.6357058E-03 - - 8.1456937E-03 - - 7.7155413E-03 - - 7.4818571E-03 - - 7.2524325E-03 - - 7.0736756E-03 - - 7.0115740E-03 - - 6.8735456E-03 - - 6.8726489E-03 - - 6.9218219E-03 - - 6.9136015E-03 - - 7.0770385E-03 - - 7.1125358E-03 - - 7.2947303E-03 - - 7.5540473E-03 - - 7.7247333E-03 - - 7.9593143E-03 - - 8.2175104E-03 - - 8.5783123E-03 - - 8.9662416E-03 - - 9.2850446E-03 - - 9.7500218E-03 - - 1.0192206E-02 - - 1.0589252E-02 - - 1.1196518E-02 - - 1.1754610E-02 - - 1.2477858E-02 - - 1.3364244E-02 - - 1.4489097E-02 - - 1.5799582E-02 - - 1.7806262E-02 - - 2.0415575E-02 - - - - 8.6187094E-03 - - 8.1028888E-03 - - 7.7502930E-03 - - 7.4368288E-03 - - 7.2053294E-03 - - 7.0754195E-03 - - 6.9609624E-03 - - 6.9199506E-03 - - 6.8721819E-03 - - 6.9170716E-03 - - 6.9278240E-03 - - 7.0082024E-03 - - 7.1469258E-03 - - 7.2928174E-03 - - 7.4578635E-03 - - 7.7005853E-03 - - 7.9397817E-03 - - 8.2897923E-03 - - 8.5642424E-03 - - 8.9336425E-03 - - 9.2822429E-03 - - 9.6866617E-03 - - 1.0169638E-02 - - 1.0601319E-02 - - 1.1134062E-02 - - 1.1797713E-02 - - 1.2521413E-02 - - 1.3398584E-02 - - 1.4465948E-02 - - 1.5920693E-02 - - 1.7831503E-02 - - 2.0386280E-02 - - - - 8.5957828E-03 - - 8.0917421E-03 - - 7.7483058E-03 - - 7.4335661E-03 - - 7.2051598E-03 - - 7.0542832E-03 - - 6.9482999E-03 - - 6.8660522E-03 - - 6.8566650E-03 - - 6.8895446E-03 - - 6.9769966E-03 - - 7.0151292E-03 - - 7.1289919E-03 - - 7.2728159E-03 - - 7.4843447E-03 - - 7.6904746E-03 - - 7.9728210E-03 - - 8.2376090E-03 - - 8.5714149E-03 - - 8.9027889E-03 - - 9.2973443E-03 - - 9.6952072E-03 - - 1.0177798E-02 - - 1.0619290E-02 - - 1.1136220E-02 - - 1.1749356E-02 - - 1.2532485E-02 - - 1.3371645E-02 - - 1.4476030E-02 - - 1.5936887E-02 - - 1.7814576E-02 - - 2.0401706E-02 - - - - 8.5762717E-03 - - 8.0787798E-03 - - 7.6957274E-03 - - 7.4218081E-03 - - 7.1969403E-03 - - 7.0456914E-03 - - 6.9243998E-03 - - 6.8670339E-03 - - 6.8410876E-03 - - 6.8440959E-03 - - 6.9114894E-03 - - 6.9709444E-03 - - 7.1246584E-03 - - 7.2467020E-03 - - 7.4540634E-03 - - 7.6790984E-03 - - 7.9072251E-03 - - 8.2202101E-03 - - 8.5598098E-03 - - 8.9093117E-03 - - 9.2775317E-03 - - 9.6625479E-03 - - 1.0156279E-02 - - 1.0632045E-02 - - 1.1116292E-02 - - 1.1767916E-02 - - 1.2489983E-02 - - 1.3349302E-02 - - 1.4524155E-02 - - 1.5953415E-02 - - 1.7870641E-02 - - 2.0504336E-02 - - - - 8.5580155E-03 - - 8.0552826E-03 - - 7.6847006E-03 - - 7.3901486E-03 - - 7.1714794E-03 - - 6.9956094E-03 - - 6.8966894E-03 - - 6.8584904E-03 - - 6.8074847E-03 - - 6.8182305E-03 - - 6.8700458E-03 - - 6.9598760E-03 - - 7.0775275E-03 - - 7.2721659E-03 - - 7.4256244E-03 - - 7.6626570E-03 - - 7.8956048E-03 - - 8.2476025E-03 - - 8.5876768E-03 - - 8.8916497E-03 - - 9.2599869E-03 - - 9.6607086E-03 - - 1.0104818E-02 - - 1.0621057E-02 - - 1.1139577E-02 - - 1.1789513E-02 - - 1.2505652E-02 - - 1.3335138E-02 - - 1.4480446E-02 - - 1.5926378E-02 - - 1.7926012E-02 - - 2.0526011E-02 - - - - 8.5161659E-03 - - 8.0446298E-03 - - 7.6545410E-03 - - 7.3722009E-03 - - 7.1148071E-03 - - 6.9727284E-03 - - 6.8574133E-03 - - 6.7687628E-03 - - 6.7671107E-03 - - 6.8028617E-03 - - 6.8012426E-03 - - 6.9205557E-03 - - 7.0398688E-03 - - 7.2416867E-03 - - 7.3960899E-03 - - 7.6495518E-03 - - 7.9006016E-03 - - 8.1906074E-03 - - 8.4993478E-03 - - 8.8863636E-03 - - 9.2483009E-03 - - 9.6547452E-03 - - 1.0109959E-02 - - 1.0588004E-02 - - 1.1123575E-02 - - 1.1768480E-02 - - 1.2510924E-02 - - 1.3377043E-02 - - 1.4514862E-02 - - 1.5985046E-02 - - 1.7920853E-02 - - 2.0545741E-02 - - - - 8.4881904E-03 - - 8.0008968E-03 - - 7.5800933E-03 - - 7.3219921E-03 - - 7.0930406E-03 - - 6.9243759E-03 - - 6.8395166E-03 - - 6.7595356E-03 - - 6.7209304E-03 - - 6.7524289E-03 - - 6.7924495E-03 - - 6.8886916E-03 - - 7.0061035E-03 - - 7.1949742E-03 - - 7.3557793E-03 - - 7.6015942E-03 - - 7.8273839E-03 - - 8.1635087E-03 - - 8.4872268E-03 - - 8.8563257E-03 - - 9.1982925E-03 - - 9.6315629E-03 - - 1.0058991E-02 - - 1.0542942E-02 - - 1.1120245E-02 - - 1.1716127E-02 - - 1.2496242E-02 - - 1.3357995E-02 - - 1.4520670E-02 - - 1.5968277E-02 - - 1.7999571E-02 - - 2.0619911E-02 - - - - 8.4547550E-03 - - 7.9415583E-03 - - 7.5504996E-03 - - 7.2492760E-03 - - 7.0388623E-03 - - 6.9114334E-03 - - 6.7880701E-03 - - 6.7298137E-03 - - 6.6707776E-03 - - 6.6865113E-03 - - 6.7469676E-03 - - 6.8440431E-03 - - 6.9530093E-03 - - 7.1334872E-03 - - 7.3320937E-03 - - 7.5447909E-03 - - 7.7926035E-03 - - 8.1024597E-03 - - 8.4776176E-03 - - 8.7989469E-03 - - 9.1860513E-03 - - 9.6106103E-03 - - 1.0035921E-02 - - 1.0516926E-02 - - 1.1111883E-02 - - 1.1693054E-02 - - 1.2421315E-02 - - 1.3359879E-02 - - 1.4448956E-02 - - 1.5939312E-02 - - 1.7946680E-02 - - 2.0638422E-02 - - - - 8.4199682E-03 - - 7.9132357E-03 - - 7.5289024E-03 - - 7.2000914E-03 - - 6.9952420E-03 - - 6.8508371E-03 - - 6.7532303E-03 - - 6.6833325E-03 - - 6.6177839E-03 - - 6.6622382E-03 - - 6.7105208E-03 - - 6.7909136E-03 - - 6.9136513E-03 - - 7.0763901E-03 - - 7.2891302E-03 - - 7.5133811E-03 - - 7.7798727E-03 - - 8.0728234E-03 - - 8.3719982E-03 - - 8.7418259E-03 - - 9.0827206E-03 - - 9.5593221E-03 - - 9.9725625E-03 - - 1.0449294E-02 - - 1.0985324E-02 - - 1.1627712E-02 - - 1.2345830E-02 - - 1.3279892E-02 - - 1.4416720E-02 - - 1.5897541E-02 - - 1.7949472E-02 - - 2.0670535E-02 - - - - 8.3808798E-03 - - 7.8549469E-03 - - 7.4548947E-03 - - 7.1338816E-03 - - 6.9441484E-03 - - 6.7971643E-03 - - 6.6772004E-03 - - 6.6034372E-03 - - 6.5689962E-03 - - 6.6291014E-03 - - 6.6629260E-03 - - 6.7229080E-03 - - 6.8650107E-03 - - 7.0400011E-03 - - 7.2281319E-03 - - 7.4627838E-03 - - 7.7395439E-03 - - 8.0343750E-03 - - 8.3395359E-03 - - 8.6563579E-03 - - 9.0736921E-03 - - 9.4975103E-03 - - 9.9294641E-03 - - 1.0370071E-02 - - 1.0916688E-02 - - 1.1554450E-02 - - 1.2270239E-02 - - 1.3181629E-02 - - 1.4291357E-02 - - 1.5819158E-02 - - 1.7859062E-02 - - 2.0611377E-02 - - - - 8.3161285E-03 - - 7.8077760E-03 - - 7.3959293E-03 - - 7.1090603E-03 - - 6.8980291E-03 - - 6.7587447E-03 - - 6.6504860E-03 - - 6.5749792E-03 - - 6.5613818E-03 - - 6.5416597E-03 - - 6.6015118E-03 - - 6.7070747E-03 - - 6.8290963E-03 - - 7.0031900E-03 - - 7.1846853E-03 - - 7.4125063E-03 - - 7.6750420E-03 - - 7.9813021E-03 - - 8.2806571E-03 - - 8.6141119E-03 - - 8.9704813E-03 - - 9.3882871E-03 - - 9.8368112E-03 - - 1.0298412E-02 - - 1.0822136E-02 - - 1.1413491E-02 - - 1.2145337E-02 - - 1.3048321E-02 - - 1.4114237E-02 - - 1.5706737E-02 - - 1.7654188E-02 - - 2.0500295E-02 - - - - 8.3192873E-03 - - 7.7697531E-03 - - 7.3819594E-03 - - 7.0971817E-03 - - 6.8836908E-03 - - 6.7313952E-03 - - 6.6234836E-03 - - 6.5684539E-03 - - 6.5572540E-03 - - 6.5781759E-03 - - 6.6163018E-03 - - 6.6999200E-03 - - 6.8297696E-03 - - 6.9564324E-03 - - 7.1572917E-03 - - 7.4359960E-03 - - 7.6444528E-03 - - 7.9171531E-03 - - 8.2232683E-03 - - 8.5632604E-03 - - 8.9017284E-03 - - 9.3233527E-03 - - 9.7185361E-03 - - 1.0167756E-02 - - 1.0690318E-02 - - 1.1287654E-02 - - 1.1955699E-02 - - 1.2797701E-02 - - 1.3915636E-02 - - 1.5417831E-02 - - 1.7413631E-02 - - 2.0132344E-02 - - - - 8.3402366E-03 - - 7.8783074E-03 - - 7.5306252E-03 - - 7.2763123E-03 - - 7.0815582E-03 - - 6.9389151E-03 - - 6.8574149E-03 - - 6.7982581E-03 - - 6.7740232E-03 - - 6.7825822E-03 - - 6.8155653E-03 - - 6.8794036E-03 - - 7.0109342E-03 - - 7.1732489E-03 - - 7.3504593E-03 - - 7.5193707E-03 - - 7.7780813E-03 - - 8.0399365E-03 - - 8.3133536E-03 - - 8.6051891E-03 - - 8.9148994E-03 - - 9.3197524E-03 - - 9.7034206E-03 - - 1.0115863E-02 - - 1.0600845E-02 - - 1.1142903E-02 - - 1.1780624E-02 - - 1.2556047E-02 - - 1.3579729E-02 - - 1.4891180E-02 - - 1.6672103E-02 - - 1.9078712E-02 - - - - 8.8088395E-03 - - 8.4507679E-03 - - 8.1708811E-03 - - 7.9801672E-03 - - 7.8027326E-03 - - 7.7405325E-03 - - 7.6178992E-03 - - 7.5796349E-03 - - 7.5729815E-03 - - 7.5709385E-03 - - 7.6313441E-03 - - 7.6551420E-03 - - 7.7197992E-03 - - 7.8770525E-03 - - 7.9879526E-03 - - 8.1371998E-03 - - 8.3342910E-03 - - 8.5247565E-03 - - 8.7962504E-03 - - 9.0806648E-03 - - 9.3313150E-03 - - 9.6858805E-03 - - 1.0017311E-02 - - 1.0396502E-02 - - 1.0810783E-02 - - 1.1308495E-02 - - 1.1873348E-02 - - 1.2517849E-02 - - 1.3292300E-02 - - 1.4204872E-02 - - 1.5413040E-02 - - 1.6865149E-02 - - - - 9.0402122E-03 - - 8.7656934E-03 - - 8.5418137E-03 - - 8.3375574E-03 - - 8.2205328E-03 - - 8.0954859E-03 - - 8.0140696E-03 - - 7.9720195E-03 - - 7.9707073E-03 - - 7.9496524E-03 - - 7.9729738E-03 - - 8.0286530E-03 - - 8.0949490E-03 - - 8.2040408E-03 - - 8.3348436E-03 - - 8.4638271E-03 - - 8.5967473E-03 - - 8.8120082E-03 - - 9.0406595E-03 - - 9.2571730E-03 - - 9.4741636E-03 - - 9.7864082E-03 - - 1.0105154E-02 - - 1.0426882E-02 - - 1.0815324E-02 - - 1.1263114E-02 - - 1.1718090E-02 - - 1.2294266E-02 - - 1.2954841E-02 - - 1.3732023E-02 - - 1.4787929E-02 - - 1.6057604E-02 - - - - 9.1615425E-03 - - 8.8847745E-03 - - 8.6630839E-03 - - 8.4765570E-03 - - 8.3309009E-03 - - 8.2383585E-03 - - 8.1836800E-03 - - 8.1120640E-03 - - 8.1261785E-03 - - 8.0708249E-03 - - 8.1480561E-03 - - 8.1784637E-03 - - 8.2346151E-03 - - 8.3274337E-03 - - 8.4147598E-03 - - 8.5448285E-03 - - 8.7091710E-03 - - 8.8843142E-03 - - 9.0949279E-03 - - 9.2936363E-03 - - 9.5389840E-03 - - 9.7958383E-03 - - 1.0086138E-02 - - 1.0400309E-02 - - 1.0727798E-02 - - 1.1115580E-02 - - 1.1556966E-02 - - 1.2062390E-02 - - 1.2723933E-02 - - 1.3461879E-02 - - 1.4407800E-02 - - 1.5727050E-02 - - - - 9.1377654E-03 - - 8.8751018E-03 - - 8.6821226E-03 - - 8.4858221E-03 - - 8.3554460E-03 - - 8.2804350E-03 - - 8.2266991E-03 - - 8.1758459E-03 - - 8.1472390E-03 - - 8.1455783E-03 - - 8.1349878E-03 - - 8.1925776E-03 - - 8.2538648E-03 - - 8.3264317E-03 - - 8.4644531E-03 - - 8.6009391E-03 - - 8.7147401E-03 - - 8.9206598E-03 - - 9.1064325E-03 - - 9.2780740E-03 - - 9.4991589E-03 - - 9.7677443E-03 - - 1.0040842E-02 - - 1.0310399E-02 - - 1.0637483E-02 - - 1.1002699E-02 - - 1.1454957E-02 - - 1.1928711E-02 - - 1.2543618E-02 - - 1.3315003E-02 - - 1.4311921E-02 - - 1.5626273E-02 - - - - 9.1477964E-03 - - 8.8569131E-03 - - 8.6480911E-03 - - 8.4806682E-03 - - 8.3743826E-03 - - 8.2509863E-03 - - 8.2112855E-03 - - 8.1583830E-03 - - 8.1332616E-03 - - 8.1132990E-03 - - 8.1560439E-03 - - 8.1779291E-03 - - 8.2488074E-03 - - 8.3305803E-03 - - 8.4259072E-03 - - 8.5822114E-03 - - 8.7017305E-03 - - 8.8788944E-03 - - 9.0655429E-03 - - 9.2582475E-03 - - 9.4805275E-03 - - 9.7278007E-03 - - 9.9553998E-03 - - 1.0269546E-02 - - 1.0586672E-02 - - 1.0921006E-02 - - 1.1328973E-02 - - 1.1802691E-02 - - 1.2450626E-02 - - 1.3255698E-02 - - 1.4251456E-02 - - 1.5657809E-02 - - - - 9.0883340E-03 - - 8.8433984E-03 - - 8.6289182E-03 - - 8.4439323E-03 - - 8.3093188E-03 - - 8.2332632E-03 - - 8.1799745E-03 - - 8.1280446E-03 - - 8.0845653E-03 - - 8.1128997E-03 - - 8.1014997E-03 - - 8.1603558E-03 - - 8.2532133E-03 - - 8.3021938E-03 - - 8.4337253E-03 - - 8.5567067E-03 - - 8.6772027E-03 - - 8.8890649E-03 - - 9.0381936E-03 - - 9.2474046E-03 - - 9.4507499E-03 - - 9.7047326E-03 - - 9.9402566E-03 - - 1.0205441E-02 - - 1.0504990E-02 - - 1.0882385E-02 - - 1.1274627E-02 - - 1.1783289E-02 - - 1.2386232E-02 - - 1.3164784E-02 - - 1.4270026E-02 - - 1.5728107E-02 - - - - 9.0807708E-03 - - 8.8015024E-03 - - 8.5814276E-03 - - 8.4248165E-03 - - 8.2946254E-03 - - 8.2126919E-03 - - 8.1370075E-03 - - 8.0715301E-03 - - 8.0815288E-03 - - 8.0835771E-03 - - 8.1054492E-03 - - 8.1477700E-03 - - 8.2076231E-03 - - 8.2545960E-03 - - 8.4024583E-03 - - 8.5599026E-03 - - 8.6575633E-03 - - 8.8233051E-03 - - 9.0064404E-03 - - 9.2354725E-03 - - 9.4557209E-03 - - 9.6788857E-03 - - 9.8947250E-03 - - 1.0174410E-02 - - 1.0498117E-02 - - 1.0823664E-02 - - 1.1218924E-02 - - 1.1737640E-02 - - 1.2318916E-02 - - 1.3224386E-02 - - 1.4293237E-02 - - 1.5742419E-02 - - - - 9.0662532E-03 - - 8.7875937E-03 - - 8.5608939E-03 - - 8.3990606E-03 - - 8.2689578E-03 - - 8.1502455E-03 - - 8.0945876E-03 - - 8.0499873E-03 - - 8.0046473E-03 - - 8.0312744E-03 - - 8.0845285E-03 - - 8.0864516E-03 - - 8.1794243E-03 - - 8.2886692E-03 - - 8.3753921E-03 - - 8.5095259E-03 - - 8.6235784E-03 - - 8.8149234E-03 - - 9.0064533E-03 - - 9.1933604E-03 - - 9.4366281E-03 - - 9.6340012E-03 - - 9.8577424E-03 - - 1.0162178E-02 - - 1.0489950E-02 - - 1.0830480E-02 - - 1.1216758E-02 - - 1.1718234E-02 - - 1.2372964E-02 - - 1.3217004E-02 - - 1.4300060E-02 - - 1.5874384E-02 - - - - 9.0385593E-03 - - 8.7911739E-03 - - 8.5398942E-03 - - 8.3506015E-03 - - 8.2438909E-03 - - 8.1613890E-03 - - 8.0460870E-03 - - 8.0305903E-03 - - 8.0028889E-03 - - 8.0232434E-03 - - 8.0276194E-03 - - 8.1064278E-03 - - 8.1288298E-03 - - 8.2312446E-03 - - 8.3452218E-03 - - 8.4759402E-03 - - 8.6203085E-03 - - 8.7737100E-03 - - 8.9852040E-03 - - 9.1640184E-03 - - 9.3706145E-03 - - 9.6371098E-03 - - 9.8385671E-03 - - 1.0187163E-02 - - 1.0453859E-02 - - 1.0791575E-02 - - 1.1239213E-02 - - 1.1704998E-02 - - 1.2413952E-02 - - 1.3197580E-02 - - 1.4388298E-02 - - 1.5983777E-02 - - - - 9.0381972E-03 - - 8.7249421E-03 - - 8.5299403E-03 - - 8.3296610E-03 - - 8.1906552E-03 - - 8.0856852E-03 - - 8.0084895E-03 - - 7.9976213E-03 - - 7.9681027E-03 - - 7.9954298E-03 - - 8.0300023E-03 - - 8.0899341E-03 - - 8.1518784E-03 - - 8.2341280E-03 - - 8.3101161E-03 - - 8.4644180E-03 - - 8.6281121E-03 - - 8.7991411E-03 - - 8.9588100E-03 - - 9.1981791E-03 - - 9.3869641E-03 - - 9.6145258E-03 - - 9.9132005E-03 - - 1.0156461E-02 - - 1.0475933E-02 - - 1.0810611E-02 - - 1.1229999E-02 - - 1.1691965E-02 - - 1.2394061E-02 - - 1.3229214E-02 - - 1.4413895E-02 - - 1.6023151E-02 - - - - 8.9900779E-03 - - 8.7242101E-03 - - 8.4738461E-03 - - 8.3135886E-03 - - 8.1704723E-03 - - 8.0916227E-03 - - 8.0054050E-03 - - 7.9890825E-03 - - 7.9822260E-03 - - 7.9494275E-03 - - 8.0343148E-03 - - 8.0498187E-03 - - 8.1090198E-03 - - 8.2328458E-03 - - 8.3082672E-03 - - 8.4585469E-03 - - 8.6087756E-03 - - 8.8041342E-03 - - 8.9504229E-03 - - 9.1682953E-03 - - 9.3389911E-03 - - 9.6352014E-03 - - 9.8666333E-03 - - 1.0149489E-02 - - 1.0464017E-02 - - 1.0804437E-02 - - 1.1200629E-02 - - 1.1730829E-02 - - 1.2396625E-02 - - 1.3311556E-02 - - 1.4467897E-02 - - 1.6069551E-02 - - - - 9.0103050E-03 - - 8.7325667E-03 - - 8.5095225E-03 - - 8.3198922E-03 - - 8.1828827E-03 - - 8.0755069E-03 - - 7.9981914E-03 - - 7.9413633E-03 - - 7.9823990E-03 - - 7.9246563E-03 - - 7.9815454E-03 - - 8.0345931E-03 - - 8.0725191E-03 - - 8.2341012E-03 - - 8.3041608E-03 - - 8.3831836E-03 - - 8.6106789E-03 - - 8.7518346E-03 - - 8.9641474E-03 - - 9.0978032E-03 - - 9.3592003E-03 - - 9.5996223E-03 - - 9.9237621E-03 - - 1.0175830E-02 - - 1.0455459E-02 - - 1.0836548E-02 - - 1.1244650E-02 - - 1.1760188E-02 - - 1.2384627E-02 - - 1.3346254E-02 - - 1.4480133E-02 - - 1.6136563E-02 - - - - 9.0228604E-03 - - 8.6804828E-03 - - 8.4614534E-03 - - 8.2426545E-03 - - 8.1392111E-03 - - 8.0814949E-03 - - 7.9912702E-03 - - 7.9974952E-03 - - 7.9421615E-03 - - 7.9138029E-03 - - 7.9451587E-03 - - 8.0340001E-03 - - 8.0954821E-03 - - 8.1764077E-03 - - 8.3095930E-03 - - 8.4157262E-03 - - 8.6168490E-03 - - 8.7576427E-03 - - 8.9333274E-03 - - 9.1895534E-03 - - 9.3857577E-03 - - 9.6418300E-03 - - 9.8564788E-03 - - 1.0150132E-02 - - 1.0487898E-02 - - 1.0870470E-02 - - 1.1271947E-02 - - 1.1778020E-02 - - 1.2502739E-02 - - 1.3339816E-02 - - 1.4543555E-02 - - 1.6130789E-02 - - - - 9.0622003E-03 - - 8.7178702E-03 - - 8.4596226E-03 - - 8.2747360E-03 - - 8.1644825E-03 - - 8.0165944E-03 - - 7.9932716E-03 - - 7.9360246E-03 - - 7.9425974E-03 - - 7.9418553E-03 - - 7.9541528E-03 - - 8.0182907E-03 - - 8.0812624E-03 - - 8.0915456E-03 - - 8.2908500E-03 - - 8.4101146E-03 - - 8.5246086E-03 - - 8.7454336E-03 - - 8.9623361E-03 - - 9.1273983E-03 - - 9.3738784E-03 - - 9.6552369E-03 - - 9.8941901E-03 - - 1.0161555E-02 - - 1.0501008E-02 - - 1.0866011E-02 - - 1.1314128E-02 - - 1.1790338E-02 - - 1.2447300E-02 - - 1.3396964E-02 - - 1.4531939E-02 - - 1.6115773E-02 - - - - 8.9679455E-03 - - 8.7523346E-03 - - 8.4194831E-03 - - 8.2562897E-03 - - 8.2501744E-03 - - 8.0453964E-03 - - 7.9636250E-03 - - 7.9278064E-03 - - 7.9395130E-03 - - 7.8808053E-03 - - 7.8942591E-03 - - 7.9779525E-03 - - 8.1203535E-03 - - 8.1780129E-03 - - 8.2976996E-03 - - 8.3927501E-03 - - 8.5693973E-03 - - 8.7760972E-03 - - 8.9639268E-03 - - 9.1777904E-03 - - 9.3233365E-03 - - 9.6757573E-03 - - 9.8043550E-03 - - 1.0142972E-02 - - 1.0460099E-02 - - 1.0900581E-02 - - 1.1166513E-02 - - 1.1798843E-02 - - 1.2569032E-02 - - 1.3335377E-02 - - 1.4567713E-02 - - 1.6266042E-02 - - - - 9.0235493E-03 - - 8.7359753E-03 - - 8.4400355E-03 - - 8.2314136E-03 - - 8.1409585E-03 - - 8.0562549E-03 - - 8.0165174E-03 - - 7.9631855E-03 - - 7.9527283E-03 - - 7.9590026E-03 - - 7.9558654E-03 - - 7.9982172E-03 - - 7.9903743E-03 - - 8.1472328E-03 - - 8.3527175E-03 - - 8.3019999E-03 - - 8.5775481E-03 - - 8.8353190E-03 - - 8.9853803E-03 - - 9.0836784E-03 - - 9.4481131E-03 - - 9.5401367E-03 - - 9.8920227E-03 - - 1.0186917E-02 - - 1.0500634E-02 - - 1.0833697E-02 - - 1.1379042E-02 - - 1.1793671E-02 - - 1.2553389E-02 - - 1.3369577E-02 - - 1.4595165E-02 - - 1.6031466E-02 - - - 1.0000416E+00 - - - 1.0000513E+00 - - - 1.0000397E+00 - - - 1.0000409E+00 - - - 1.0000455E+00 - - - 1.0000417E+00 - - - 1.0000452E+00 - - - 1.0000431E+00 - - - 1.0000455E+00 - - - 1.0000451E+00 - - - 1.0000445E+00 - - - 1.0000482E+00 - - - 1.0000507E+00 - - - 1.0000542E+00 - - - 1.0000545E+00 - - - 1.0000461E+00 - - - 1.0000114E+00 - - - 1.0000112E+00 - - - 1.0000195E+00 - - - 1.0000216E+00 - - - 1.0000279E+00 - - - 1.0000307E+00 - - - 1.0000302E+00 - - - 1.0000313E+00 - - - 1.0000334E+00 - - - 1.0000309E+00 - - - 1.0000325E+00 - - - 1.0000318E+00 - - - 1.0000346E+00 - - - 1.0000335E+00 - - - 1.0000285E+00 - - - 1.0000358E+00 - - - - - lwtr_ang_mu - lwtr_ang_mu - 2.5300000E-08 - 32 - false - 32 - 1 - angle - histogram - - 8.3129229E-01 - - 8.3203829E-01 - - 8.3332424E-01 - - 8.3539719E-01 - - 8.3799288E-01 - - 8.4156597E-01 - - 8.4594074E-01 - - 8.5122773E-01 - - 8.5788274E-01 - - 8.6633387E-01 - - 8.7719846E-01 - - 8.9195077E-01 - - 9.1326621E-01 - - 9.4469159E-01 - - 9.9368716E-01 - - 1.0616854E+00 - - 1.0982938E+00 - - 1.0997200E+00 - - 1.0855410E+00 - - 1.0676695E+00 - - 1.0508172E+00 - - 1.0369337E+00 - - 1.0255762E+00 - - 1.0162841E+00 - - 1.0086633E+00 - - 1.0025783E+00 - - 9.9737297E-01 - - 9.9326768E-01 - - 9.9030852E-01 - - 9.8792719E-01 - - 9.8610453E-01 - - 9.8540665E-01 - - - 7.7368065E-03 - - 7.7519393E-03 - - 7.7819449E-03 - - 7.8285240E-03 - - 7.8881877E-03 - - 7.9652685E-03 - - 8.0588251E-03 - - 8.1724303E-03 - - 8.3079937E-03 - - 8.4749946E-03 - - 8.6811506E-03 - - 8.9456784E-03 - - 9.3049336E-03 - - 9.8025199E-03 - - 1.0529992E-02 - - 1.1498571E-02 - - 1.2065971E-02 - - 1.2168395E-02 - - 1.2053690E-02 - - 1.1870414E-02 - - 1.1678759E-02 - - 1.1516371E-02 - - 1.1377145E-02 - - 1.1262809E-02 - - 1.1166687E-02 - - 1.1090107E-02 - - 1.1022668E-02 - - 1.0968772E-02 - - 1.0931381E-02 - - 1.0898236E-02 - - 1.0872094E-02 - - 1.0866295E-02 - - - 5.0690953E-03 - - 8.8284325E-03 - - 9.0078067E-03 - - 8.3473577E-03 - - 8.6118779E-03 - - 8.5008333E-03 - - 9.0278160E-03 - - 9.0320024E-03 - - 9.3778370E-03 - - 9.6052477E-03 - - 9.9703821E-03 - - 1.0342612E-02 - - 1.0646441E-02 - - 1.1197549E-02 - - 1.1382812E-02 - - 1.2469275E-02 - - 1.3368771E-02 - - 1.7162734E-02 - - 2.0335842E-02 - - 2.4108518E-02 - - 2.7585384E-02 - - 3.1409361E-02 - - 3.5211839E-02 - - 3.9132244E-02 - - 4.2882641E-02 - - 4.7206070E-02 - - 5.1012876E-02 - - 5.6053305E-02 - - 5.9624825E-02 - - 6.4222850E-02 - - 7.1113785E-02 - - 7.1863425E-02 - - - - 5.0668773E-03 - - 8.8623444E-03 - - 8.9736897E-03 - - 8.4193826E-03 - - 8.6200366E-03 - - 8.5331711E-03 - - 9.0253536E-03 - - 9.0024868E-03 - - 9.3587966E-03 - - 9.6337679E-03 - - 9.9001048E-03 - - 1.0351369E-02 - - 1.0700823E-02 - - 1.1172796E-02 - - 1.1445656E-02 - - 1.2427412E-02 - - 1.3375674E-02 - - 1.7104580E-02 - - 2.0306601E-02 - - 2.4056263E-02 - - 2.7577305E-02 - - 3.1469932E-02 - - 3.5286392E-02 - - 3.9182103E-02 - - 4.2943152E-02 - - 4.7360483E-02 - - 5.1005109E-02 - - 5.6171187E-02 - - 5.9667108E-02 - - 6.4232789E-02 - - 7.1121280E-02 - - 7.1846306E-02 - - - - 5.0585819E-03 - - 8.8480548E-03 - - 9.0578095E-03 - - 8.4267843E-03 - - 8.6269032E-03 - - 8.5421136E-03 - - 9.0526837E-03 - - 9.0736449E-03 - - 9.4245294E-03 - - 9.6888060E-03 - - 9.9567766E-03 - - 1.0375670E-02 - - 1.0725481E-02 - - 1.1243110E-02 - - 1.1484936E-02 - - 1.2521826E-02 - - 1.3438046E-02 - - 1.7151864E-02 - - 2.0343472E-02 - - 2.4110251E-02 - - 2.7659343E-02 - - 3.1511614E-02 - - 3.5309076E-02 - - 3.9196826E-02 - - 4.3043312E-02 - - 4.7345488E-02 - - 5.1124137E-02 - - 5.6080519E-02 - - 5.9764341E-02 - - 6.4292466E-02 - - 7.1165161E-02 - - 7.1900319E-02 - - - - 5.0739533E-03 - - 8.8878014E-03 - - 9.0739746E-03 - - 8.4571184E-03 - - 8.6763187E-03 - - 8.5845734E-03 - - 9.0893274E-03 - - 9.1072493E-03 - - 9.4607350E-03 - - 9.7370233E-03 - - 1.0006337E-02 - - 1.0437546E-02 - - 1.0767301E-02 - - 1.1309766E-02 - - 1.1552543E-02 - - 1.2572863E-02 - - 1.3499221E-02 - - 1.7217227E-02 - - 2.0383163E-02 - - 2.4178222E-02 - - 2.7731888E-02 - - 3.1561770E-02 - - 3.5431417E-02 - - 3.9298803E-02 - - 4.3075219E-02 - - 4.7440921E-02 - - 5.1196928E-02 - - 5.6281715E-02 - - 5.9863517E-02 - - 6.4363763E-02 - - 7.1290039E-02 - - 7.1984722E-02 - - - - 5.0933569E-03 - - 8.9571748E-03 - - 9.1350789E-03 - - 8.5026806E-03 - - 8.7154122E-03 - - 8.6182850E-03 - - 9.1387403E-03 - - 9.1503576E-03 - - 9.5054271E-03 - - 9.8046510E-03 - - 1.0063015E-02 - - 1.0512898E-02 - - 1.0850976E-02 - - 1.1369711E-02 - - 1.1602210E-02 - - 1.2644534E-02 - - 1.3573331E-02 - - 1.7276147E-02 - - 2.0485160E-02 - - 2.4267827E-02 - - 2.7795345E-02 - - 3.1650606E-02 - - 3.5516413E-02 - - 3.9384282E-02 - - 4.3193261E-02 - - 4.7565933E-02 - - 5.1283045E-02 - - 5.6364736E-02 - - 5.9999740E-02 - - 6.4499325E-02 - - 7.1460960E-02 - - 7.2121578E-02 - - - - 5.1073627E-03 - - 9.0205393E-03 - - 9.1796662E-03 - - 8.5645656E-03 - - 8.7990379E-03 - - 8.7021912E-03 - - 9.2162069E-03 - - 9.2138958E-03 - - 9.5751521E-03 - - 9.8799162E-03 - - 1.0149817E-02 - - 1.0595940E-02 - - 1.0925157E-02 - - 1.1451227E-02 - - 1.1697295E-02 - - 1.2747125E-02 - - 1.3679064E-02 - - 1.7388258E-02 - - 2.0589616E-02 - - 2.4369432E-02 - - 2.7920510E-02 - - 3.1792267E-02 - - 3.5621878E-02 - - 3.9491661E-02 - - 4.3278532E-02 - - 4.7679951E-02 - - 5.1436615E-02 - - 5.6547886E-02 - - 6.0145268E-02 - - 6.4662138E-02 - - 7.1681806E-02 - - 7.2326892E-02 - - - - 5.1442091E-03 - - 9.0852521E-03 - - 9.2735609E-03 - - 8.6388628E-03 - - 8.8708740E-03 - - 8.7690933E-03 - - 9.2934119E-03 - - 9.3186161E-03 - - 9.6592707E-03 - - 9.9678700E-03 - - 1.0236163E-02 - - 1.0694734E-02 - - 1.1025890E-02 - - 1.1566030E-02 - - 1.1820104E-02 - - 1.2881706E-02 - - 1.3817409E-02 - - 1.7525018E-02 - - 2.0707299E-02 - - 2.4504049E-02 - - 2.8056398E-02 - - 3.1942086E-02 - - 3.5781215E-02 - - 3.9676732E-02 - - 4.3508487E-02 - - 4.7899374E-02 - - 5.1653601E-02 - - 5.6724194E-02 - - 6.0363176E-02 - - 6.4884496E-02 - - 7.1995314E-02 - - 7.2586420E-02 - - - - 5.1859947E-03 - - 9.1884111E-03 - - 9.3553722E-03 - - 8.7326674E-03 - - 8.9615831E-03 - - 8.8682756E-03 - - 9.3981872E-03 - - 9.4022342E-03 - - 9.7833217E-03 - - 1.0082626E-02 - - 1.0346345E-02 - - 1.0823172E-02 - - 1.1169852E-02 - - 1.1713674E-02 - - 1.1957780E-02 - - 1.3030310E-02 - - 1.3974055E-02 - - 1.7679518E-02 - - 2.0873339E-02 - - 2.4674002E-02 - - 2.8233633E-02 - - 3.2098518E-02 - - 3.5967409E-02 - - 3.9901149E-02 - - 4.3708564E-02 - - 4.8163155E-02 - - 5.1864987E-02 - - 5.6965609E-02 - - 6.0598955E-02 - - 6.5237827E-02 - - 7.2317026E-02 - - 7.2846315E-02 - - - - 5.2179276E-03 - - 9.2840460E-03 - - 9.4689692E-03 - - 8.8426310E-03 - - 9.0784020E-03 - - 8.9710561E-03 - - 9.5058449E-03 - - 9.5242525E-03 - - 9.8985438E-03 - - 1.0230104E-02 - - 1.0489612E-02 - - 1.0966586E-02 - - 1.1313882E-02 - - 1.1867051E-02 - - 1.2127596E-02 - - 1.3217267E-02 - - 1.4158489E-02 - - 1.7874095E-02 - - 2.1071639E-02 - - 2.4904630E-02 - - 2.8444961E-02 - - 3.2350782E-02 - - 3.6218293E-02 - - 4.0127228E-02 - - 4.3958446E-02 - - 4.8412743E-02 - - 5.2176893E-02 - - 5.7339635E-02 - - 6.0969984E-02 - - 6.5571180E-02 - - 7.2752295E-02 - - 7.3254466E-02 - - - - 5.2716442E-03 - - 9.4281164E-03 - - 9.6132026E-03 - - 8.9742401E-03 - - 9.2100433E-03 - - 9.1094424E-03 - - 9.6671272E-03 - - 9.6893875E-03 - - 1.0054424E-02 - - 1.0384782E-02 - - 1.0663088E-02 - - 1.1145331E-02 - - 1.1502660E-02 - - 1.2069220E-02 - - 1.2330654E-02 - - 1.3451168E-02 - - 1.4376732E-02 - - 1.8119744E-02 - - 2.1312268E-02 - - 2.5156150E-02 - - 2.8702855E-02 - - 3.2612605E-02 - - 3.6519082E-02 - - 4.0492357E-02 - - 4.4282144E-02 - - 4.8807320E-02 - - 5.2599863E-02 - - 5.7759050E-02 - - 6.1395630E-02 - - 6.6046712E-02 - - 7.3333461E-02 - - 7.3753560E-02 - - - - 5.3238344E-03 - - 9.5970913E-03 - - 9.7854600E-03 - - 9.1224140E-03 - - 9.3984166E-03 - - 9.2843910E-03 - - 9.8479041E-03 - - 9.8775712E-03 - - 1.0248815E-02 - - 1.0588076E-02 - - 1.0866467E-02 - - 1.1377201E-02 - - 1.1745016E-02 - - 1.2324752E-02 - - 1.2591933E-02 - - 1.3738942E-02 - - 1.4661945E-02 - - 1.8420789E-02 - - 2.1616210E-02 - - 2.5483933E-02 - - 2.9053296E-02 - - 3.3018657E-02 - - 3.6902567E-02 - - 4.0918920E-02 - - 4.4768920E-02 - - 4.9324206E-02 - - 5.3104469E-02 - - 5.8346792E-02 - - 6.2007342E-02 - - 6.6700912E-02 - - 7.4111114E-02 - - 7.4471661E-02 - - - - 5.4122500E-03 - - 9.8114809E-03 - - 9.9988824E-03 - - 9.3373137E-03 - - 9.6193550E-03 - - 9.5022652E-03 - - 1.0091629E-02 - - 1.0102292E-02 - - 1.0507181E-02 - - 1.0845994E-02 - - 1.1145961E-02 - - 1.1663724E-02 - - 1.2054675E-02 - - 1.2641320E-02 - - 1.2925378E-02 - - 1.4109631E-02 - - 1.5019788E-02 - - 1.8801255E-02 - - 2.2007215E-02 - - 2.5928762E-02 - - 2.9530128E-02 - - 3.3525210E-02 - - 3.7488914E-02 - - 4.1518826E-02 - - 4.5409731E-02 - - 5.0007891E-02 - - 5.3821041E-02 - - 5.9155539E-02 - - 6.2863258E-02 - - 6.7589912E-02 - - 7.5149452E-02 - - 7.5483624E-02 - - - - 5.5291381E-03 - - 1.0106920E-02 - - 1.0289680E-02 - - 9.6380580E-03 - - 9.9265277E-03 - - 9.8058620E-03 - - 1.0411771E-02 - - 1.0436031E-02 - - 1.0855919E-02 - - 1.1210324E-02 - - 1.1523264E-02 - - 1.2064653E-02 - - 1.2477020E-02 - - 1.3073068E-02 - - 1.3372106E-02 - - 1.4596687E-02 - - 1.5522669E-02 - - 1.9346144E-02 - - 2.2590235E-02 - - 2.6577078E-02 - - 3.0198519E-02 - - 3.4263702E-02 - - 3.8312940E-02 - - 4.2417033E-02 - - 4.6331184E-02 - - 5.1039786E-02 - - 5.4923952E-02 - - 6.0373272E-02 - - 6.4126997E-02 - - 6.8933518E-02 - - 7.6721947E-02 - - 7.6881324E-02 - - - - 5.7051926E-03 - - 1.0534340E-02 - - 1.0734999E-02 - - 1.0047973E-02 - - 1.0355258E-02 - - 1.0218464E-02 - - 1.0877782E-02 - - 1.0922582E-02 - - 1.1349348E-02 - - 1.1717445E-02 - - 1.2048634E-02 - - 1.2622834E-02 - - 1.3044209E-02 - - 1.3697572E-02 - - 1.4007429E-02 - - 1.5297796E-02 - - 1.6229092E-02 - - 2.0130646E-02 - - 2.3419720E-02 - - 2.7507372E-02 - - 3.1241243E-02 - - 3.5411821E-02 - - 3.9541855E-02 - - 4.3748213E-02 - - 4.7789294E-02 - - 5.2605069E-02 - - 5.6580575E-02 - - 6.2218120E-02 - - 6.6002923E-02 - - 7.0996802E-02 - - 7.9059610E-02 - - 7.9125302E-02 - - - - 5.9798621E-03 - - 1.1178770E-02 - - 1.1398960E-02 - - 1.0686315E-02 - - 1.1015007E-02 - - 1.0888426E-02 - - 1.1578312E-02 - - 1.1599595E-02 - - 1.2096215E-02 - - 1.2485774E-02 - - 1.2847301E-02 - - 1.3454293E-02 - - 1.3910042E-02 - - 1.4624946E-02 - - 1.4951480E-02 - - 1.6345303E-02 - - 1.7294576E-02 - - 2.1305917E-02 - - 2.4724135E-02 - - 2.8975117E-02 - - 3.2851405E-02 - - 3.7179235E-02 - - 4.1473071E-02 - - 4.5870569E-02 - - 5.0061541E-02 - - 5.5118747E-02 - - 5.9217709E-02 - - 6.5121185E-02 - - 6.9056004E-02 - - 7.4268036E-02 - - 8.2796332E-02 - - 8.2707329E-02 - - - - 6.3814382E-03 - - 1.2092503E-02 - - 1.2307256E-02 - - 1.1538828E-02 - - 1.1908080E-02 - - 1.1757836E-02 - - 1.2534374E-02 - - 1.2563508E-02 - - 1.3099926E-02 - - 1.3526120E-02 - - 1.3927022E-02 - - 1.4604411E-02 - - 1.5096848E-02 - - 1.5885767E-02 - - 1.6230507E-02 - - 1.7756050E-02 - - 1.8747181E-02 - - 2.2956423E-02 - - 2.6549953E-02 - - 3.1007445E-02 - - 3.5079178E-02 - - 3.9663485E-02 - - 4.4205438E-02 - - 4.8827182E-02 - - 5.3252335E-02 - - 5.8585422E-02 - - 6.2916830E-02 - - 6.9202743E-02 - - 7.3345048E-02 - - 7.8865458E-02 - - 8.8060504E-02 - - 8.7720181E-02 - - - - 6.5814203E-03 - - 1.2589556E-02 - - 1.2831098E-02 - - 1.2021990E-02 - - 1.2420962E-02 - - 1.2274328E-02 - - 1.3072229E-02 - - 1.3125790E-02 - - 1.3684984E-02 - - 1.4120320E-02 - - 1.4541810E-02 - - 1.5241834E-02 - - 1.5792664E-02 - - 1.6581300E-02 - - 1.6973815E-02 - - 1.8580511E-02 - - 1.9572617E-02 - - 2.3865583E-02 - - 2.7520381E-02 - - 3.2101383E-02 - - 3.6273771E-02 - - 4.0991031E-02 - - 4.5628107E-02 - - 5.0375712E-02 - - 5.4927552E-02 - - 6.0463390E-02 - - 6.4846891E-02 - - 7.1361573E-02 - - 7.5574981E-02 - - 8.1252683E-02 - - 9.0772914E-02 - - 9.0305344E-02 - - - - 6.5954047E-03 - - 1.2649872E-02 - - 1.2894758E-02 - - 1.2088299E-02 - - 1.2500706E-02 - - 1.2323868E-02 - - 1.3135140E-02 - - 1.3183877E-02 - - 1.3757540E-02 - - 1.4215358E-02 - - 1.4630076E-02 - - 1.5341576E-02 - - 1.5875377E-02 - - 1.6697400E-02 - - 1.7075964E-02 - - 1.8685615E-02 - - 1.9688554E-02 - - 2.3959638E-02 - - 2.7582865E-02 - - 3.2154359E-02 - - 3.6319478E-02 - - 4.0991674E-02 - - 4.5627244E-02 - - 5.0390376E-02 - - 5.4901681E-02 - - 6.0435636E-02 - - 6.4805706E-02 - - 7.1338882E-02 - - 7.5494665E-02 - - 8.1186566E-02 - - 9.0719563E-02 - - 9.0193680E-02 - - - - 6.5336047E-03 - - 1.2512090E-02 - - 1.2764479E-02 - - 1.1984145E-02 - - 1.2375802E-02 - - 1.2210337E-02 - - 1.3005945E-02 - - 1.3053548E-02 - - 1.3626485E-02 - - 1.4068961E-02 - - 1.4494598E-02 - - 1.5200428E-02 - - 1.5722617E-02 - - 1.6508783E-02 - - 1.6910525E-02 - - 1.8489314E-02 - - 1.9473998E-02 - - 2.3688731E-02 - - 2.7256893E-02 - - 3.1731269E-02 - - 3.5822276E-02 - - 4.0457390E-02 - - 4.5020879E-02 - - 4.9721896E-02 - - 5.4161674E-02 - - 5.9588663E-02 - - 6.3895979E-02 - - 7.0351683E-02 - - 7.4478980E-02 - - 8.0093110E-02 - - 8.9495166E-02 - - 8.8945256E-02 - - - - 6.4468824E-03 - - 1.2344191E-02 - - 1.2577769E-02 - - 1.1799198E-02 - - 1.2185250E-02 - - 1.2024671E-02 - - 1.2823561E-02 - - 1.2867050E-02 - - 1.3414223E-02 - - 1.3868383E-02 - - 1.4274902E-02 - - 1.4957665E-02 - - 1.5477639E-02 - - 1.6280478E-02 - - 1.6660201E-02 - - 1.8210099E-02 - - 1.9176459E-02 - - 2.3317865E-02 - - 2.6814611E-02 - - 3.1226187E-02 - - 3.5261695E-02 - - 3.9778054E-02 - - 4.4282066E-02 - - 4.8849080E-02 - - 5.3188035E-02 - - 5.8562223E-02 - - 6.2824222E-02 - - 6.9127893E-02 - - 7.3188187E-02 - - 7.8690046E-02 - - 8.7933862E-02 - - 8.7463314E-02 - - - - 6.3504172E-03 - - 1.2150642E-02 - - 1.2387727E-02 - - 1.1620660E-02 - - 1.2007755E-02 - - 1.1841239E-02 - - 1.2616226E-02 - - 1.2659354E-02 - - 1.3210608E-02 - - 1.3647237E-02 - - 1.4056090E-02 - - 1.4738601E-02 - - 1.5248667E-02 - - 1.6022604E-02 - - 1.6399027E-02 - - 1.7924821E-02 - - 1.8865800E-02 - - 2.2962104E-02 - - 2.6396869E-02 - - 3.0722714E-02 - - 3.4680261E-02 - - 3.9148700E-02 - - 4.3549586E-02 - - 4.8057389E-02 - - 5.2369847E-02 - - 5.7634643E-02 - - 6.1797568E-02 - - 6.8018235E-02 - - 7.1991375E-02 - - 7.7432633E-02 - - 8.6562066E-02 - - 8.6040544E-02 - - - - 6.2807225E-03 - - 1.2005102E-02 - - 1.2236833E-02 - - 1.1484849E-02 - - 1.1844265E-02 - - 1.1694745E-02 - - 1.2469442E-02 - - 1.2503258E-02 - - 1.3035750E-02 - - 1.3456731E-02 - - 1.3869786E-02 - - 1.4538788E-02 - - 1.5043345E-02 - - 1.5804904E-02 - - 1.6173155E-02 - - 1.7678967E-02 - - 1.8617817E-02 - - 2.2640680E-02 - - 2.6043512E-02 - - 3.0350793E-02 - - 3.4235767E-02 - - 3.8635112E-02 - - 4.3006209E-02 - - 4.7438737E-02 - - 5.1680206E-02 - - 5.6869882E-02 - - 6.0948428E-02 - - 6.7112720E-02 - - 7.1046470E-02 - - 7.6389984E-02 - - 8.5416908E-02 - - 8.4912400E-02 - - - - 6.2384011E-03 - - 1.1883626E-02 - - 1.2102819E-02 - - 1.1362792E-02 - - 1.1727085E-02 - - 1.1577991E-02 - - 1.2321572E-02 - - 1.2368887E-02 - - 1.2886627E-02 - - 1.3323476E-02 - - 1.3712662E-02 - - 1.4368905E-02 - - 1.4867001E-02 - - 1.5621404E-02 - - 1.6001770E-02 - - 1.7495457E-02 - - 1.8410484E-02 - - 2.2403739E-02 - - 2.5792442E-02 - - 3.0003874E-02 - - 3.3860219E-02 - - 3.8194472E-02 - - 4.2513447E-02 - - 4.6944801E-02 - - 5.1102508E-02 - - 5.6230364E-02 - - 6.0282905E-02 - - 6.6396185E-02 - - 7.0267237E-02 - - 7.5567209E-02 - - 8.4430462E-02 - - 8.3984117E-02 - - - - 6.1845926E-03 - - 1.1774745E-02 - - 1.2008907E-02 - - 1.1282463E-02 - - 1.1630642E-02 - - 1.1486008E-02 - - 1.2212483E-02 - - 1.2255192E-02 - - 1.2777462E-02 - - 1.3204562E-02 - - 1.3600398E-02 - - 1.4255316E-02 - - 1.4736561E-02 - - 1.5470029E-02 - - 1.5845176E-02 - - 1.7313807E-02 - - 1.8247178E-02 - - 2.2230316E-02 - - 2.5531152E-02 - - 2.9731972E-02 - - 3.3558284E-02 - - 3.7872884E-02 - - 4.2109048E-02 - - 4.6517240E-02 - - 5.0645413E-02 - - 5.5683251E-02 - - 5.9750465E-02 - - 6.5766931E-02 - - 6.9579667E-02 - - 7.4872290E-02 - - 8.3643239E-02 - - 8.3206968E-02 - - - - 6.1719734E-03 - - 1.1719545E-02 - - 1.1917909E-02 - - 1.1189341E-02 - - 1.1548606E-02 - - 1.1416064E-02 - - 1.2129643E-02 - - 1.2168083E-02 - - 1.2694983E-02 - - 1.3100793E-02 - - 1.3481593E-02 - - 1.4146417E-02 - - 1.4630389E-02 - - 1.5367839E-02 - - 1.5730917E-02 - - 1.7184516E-02 - - 1.8089440E-02 - - 2.2023196E-02 - - 2.5336832E-02 - - 2.9501303E-02 - - 3.3286048E-02 - - 3.7579302E-02 - - 4.1818920E-02 - - 4.6160226E-02 - - 5.0276169E-02 - - 5.5322377E-02 - - 5.9292479E-02 - - 6.5292838E-02 - - 6.9134443E-02 - - 7.4296625E-02 - - 8.3006295E-02 - - 8.2573545E-02 - - - - 6.1382782E-03 - - 1.1652027E-02 - - 1.1858603E-02 - - 1.1149474E-02 - - 1.1500153E-02 - - 1.1352538E-02 - - 1.2052433E-02 - - 1.2104328E-02 - - 1.2615826E-02 - - 1.3028027E-02 - - 1.3393814E-02 - - 1.4056119E-02 - - 1.4520800E-02 - - 1.5244525E-02 - - 1.5619872E-02 - - 1.7065448E-02 - - 1.7976677E-02 - - 2.1928655E-02 - - 2.5188600E-02 - - 2.9345474E-02 - - 3.3098490E-02 - - 3.7352890E-02 - - 4.1577882E-02 - - 4.5851588E-02 - - 4.9907550E-02 - - 5.5007580E-02 - - 5.8924848E-02 - - 6.4866195E-02 - - 6.8653679E-02 - - 7.3799695E-02 - - 8.2491620E-02 - - 8.2047228E-02 - - - - 6.1241006E-03 - - 1.1590726E-02 - - 1.1801215E-02 - - 1.1080585E-02 - - 1.1434054E-02 - - 1.1286311E-02 - - 1.2000496E-02 - - 1.2020032E-02 - - 1.2555074E-02 - - 1.2968561E-02 - - 1.3345040E-02 - - 1.3984260E-02 - - 1.4471501E-02 - - 1.5187071E-02 - - 1.5527587E-02 - - 1.6969733E-02 - - 1.7880430E-02 - - 2.1827072E-02 - - 2.5070882E-02 - - 2.9204178E-02 - - 3.2920367E-02 - - 3.7138445E-02 - - 4.1355200E-02 - - 4.5651496E-02 - - 4.9686415E-02 - - 5.4664866E-02 - - 5.8632525E-02 - - 6.4518086E-02 - - 6.8341097E-02 - - 7.3449748E-02 - - 8.2031901E-02 - - 8.1619798E-02 - - - - 6.1062727E-03 - - 1.1540200E-02 - - 1.1761046E-02 - - 1.1040109E-02 - - 1.1412932E-02 - - 1.1240736E-02 - - 1.1950046E-02 - - 1.1997678E-02 - - 1.2505989E-02 - - 1.2930265E-02 - - 1.3303213E-02 - - 1.3935054E-02 - - 1.4397122E-02 - - 1.5128867E-02 - - 1.5487202E-02 - - 1.6938379E-02 - - 1.7810772E-02 - - 2.1723430E-02 - - 2.4973244E-02 - - 2.9068452E-02 - - 3.2834028E-02 - - 3.7010997E-02 - - 4.1148015E-02 - - 4.5454526E-02 - - 4.9470264E-02 - - 5.4447102E-02 - - 5.8392796E-02 - - 6.4249338E-02 - - 6.8034422E-02 - - 7.3189468E-02 - - 8.1672467E-02 - - 8.1260364E-02 - - - - 6.0833777E-03 - - 1.1517436E-02 - - 1.1712978E-02 - - 1.1032819E-02 - - 1.1358893E-02 - - 1.1208870E-02 - - 1.1912352E-02 - - 1.1958737E-02 - - 1.2469851E-02 - - 1.2881147E-02 - - 1.3237414E-02 - - 1.3873203E-02 - - 1.4346868E-02 - - 1.5065060E-02 - - 1.5417558E-02 - - 1.6865782E-02 - - 1.7748238E-02 - - 2.1647065E-02 - - 2.4885779E-02 - - 2.8999390E-02 - - 3.2709869E-02 - - 3.6878634E-02 - - 4.1028900E-02 - - 4.5288735E-02 - - 4.9351482E-02 - - 5.4263443E-02 - - 5.8208019E-02 - - 6.4026596E-02 - - 6.7817431E-02 - - 7.2944166E-02 - - 8.1408951E-02 - - 8.0980011E-02 - - - - 6.0960595E-03 - - 1.1509277E-02 - - 1.1717750E-02 - - 1.1016084E-02 - - 1.1324287E-02 - - 1.1181299E-02 - - 1.1926512E-02 - - 1.1924795E-02 - - 1.2430825E-02 - - 1.2836520E-02 - - 1.3191644E-02 - - 1.3847845E-02 - - 1.4306693E-02 - - 1.5047376E-02 - - 1.5361189E-02 - - 1.6797970E-02 - - 1.7681035E-02 - - 2.1572902E-02 - - 2.4843981E-02 - - 2.8950004E-02 - - 3.2646669E-02 - - 3.6798605E-02 - - 4.0927881E-02 - - 4.5165770E-02 - - 4.9225435E-02 - - 5.4165928E-02 - - 5.8066998E-02 - - 6.3897046E-02 - - 6.7667188E-02 - - 7.2785603E-02 - - 8.1253392E-02 - - 8.0864443E-02 - - - - 6.0706294E-03 - - 1.1507691E-02 - - 1.1695334E-02 - - 1.0977998E-02 - - 1.1320263E-02 - - 1.1167309E-02 - - 1.1887145E-02 - - 1.1908635E-02 - - 1.2405259E-02 - - 1.2838152E-02 - - 1.3210507E-02 - - 1.3849960E-02 - - 1.4283591E-02 - - 1.5028182E-02 - - 1.5329706E-02 - - 1.6759635E-02 - - 1.7685388E-02 - - 2.1572849E-02 - - 2.4772494E-02 - - 2.8864133E-02 - - 3.2582677E-02 - - 3.6784719E-02 - - 4.0900801E-02 - - 4.5137865E-02 - - 4.9135372E-02 - - 5.4093178E-02 - - 5.8034149E-02 - - 6.3786244E-02 - - 6.7502120E-02 - - 7.2584553E-02 - - 8.1167082E-02 - - 8.0688398E-02 - - - - 6.0461907E-03 - - 1.1481547E-02 - - 1.1737058E-02 - - 1.0999643E-02 - - 1.1361089E-02 - - 1.1125441E-02 - - 1.1866202E-02 - - 1.1842566E-02 - - 1.2424994E-02 - - 1.2799184E-02 - - 1.3219862E-02 - - 1.3773742E-02 - - 1.4257782E-02 - - 1.4972557E-02 - - 1.5426839E-02 - - 1.6740630E-02 - - 1.7654390E-02 - - 2.1573482E-02 - - 2.4801577E-02 - - 2.8800263E-02 - - 3.2583876E-02 - - 3.6801622E-02 - - 4.0806074E-02 - - 4.5107401E-02 - - 4.9075545E-02 - - 5.3960225E-02 - - 5.7982974E-02 - - 6.3859228E-02 - - 6.7502946E-02 - - 7.2470281E-02 - - 8.1149466E-02 - - 8.0629616E-02 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - - - \ No newline at end of file diff --git a/tests/input_set.py b/tests/input_set.py index 94576acf0d..0d5a78bab9 100644 --- a/tests/input_set.py +++ b/tests/input_set.py @@ -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() diff --git a/tests/run_tests.py b/tests/run_tests.py index 87282055c2..28bedab0dc 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -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)) diff --git a/tests/test_asymmetric_lattice/inputs_true.dat b/tests/test_asymmetric_lattice/inputs_true.dat index 9d278724f8..7e48dcf430 100644 --- a/tests/test_asymmetric_lattice/inputs_true.dat +++ b/tests/test_asymmetric_lattice/inputs_true.dat @@ -1 +1 @@ -dfb59bace10a91bb7ffc871d8ee87e91d94754bb8bb002ac6088f80fe0f480741c0489f74b753fc37158d0ff0f1368739ea60638b42083791311eefeac79168e \ No newline at end of file +6bcc9cca24d42995bdff9bf9aca5e852c2dbca5cfb42a12ac637def9cf5cac227654182fc9cf9e17d07cf2e9af11fea832e3ae0eb7001cc09856f73d219664f9 \ No newline at end of file diff --git a/tests/test_asymmetric_lattice/results_true.dat b/tests/test_asymmetric_lattice/results_true.dat index a33b9c9e59..c753afbc78 100644 --- a/tests/test_asymmetric_lattice/results_true.dat +++ b/tests/test_asymmetric_lattice/results_true.dat @@ -1 +1 @@ -bc8bef8121f9b6470e4fea817a4e48eabb1ecba1f42761a4cbd77d71181bf9e1612df4a3d6ddfbcd08a3086ac873e5f3c3e560bf96b2b7c959a2f7aad7e4e08d \ No newline at end of file +a2848fdb0a12c99ce31f4ddee766e0cf33bd5c6feca927bcb4bceca6fbb094bb1309fb8548589a99fcb09a830911457b9175b460aa45773822f8112a34b3b5c1 \ No newline at end of file diff --git a/tests/test_create_fission_neutrons/inputs_true.dat b/tests/test_create_fission_neutrons/inputs_true.dat new file mode 100644 index 0000000000..8a1a17b9e9 --- /dev/null +++ b/tests/test_create_fission_neutrons/inputs_true.dat @@ -0,0 +1 @@ +c3581501d1486293c255390251d20584431a198fbb7c07dc2879dc95dc96e26786d3913ce0db8007f542468fd137ff3267824844c03b4687fdad81ea568c92d7 \ No newline at end of file diff --git a/tests/test_create_fission_neutrons/results_true.dat b/tests/test_create_fission_neutrons/results_true.dat new file mode 100644 index 0000000000..be7c5c438d --- /dev/null +++ b/tests/test_create_fission_neutrons/results_true.dat @@ -0,0 +1,3 @@ +tally 1: +sum = 2.056839E+02 +sum_sq = 4.244628E+03 diff --git a/tests/test_create_fission_neutrons/test_create_fission_neutrons.py b/tests/test_create_fission_neutrons/test_create_fission_neutrons.py new file mode 100755 index 0000000000..80da831cc0 --- /dev/null +++ b/tests/test_create_fission_neutrons/test_create_fission_neutrons.py @@ -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() diff --git a/tests/test_energy_cutoff/inputs_true.dat b/tests/test_energy_cutoff/inputs_true.dat new file mode 100644 index 0000000000..0630d2acc2 --- /dev/null +++ b/tests/test_energy_cutoff/inputs_true.dat @@ -0,0 +1 @@ +4dc6a7b131f6757ecc9b06e93d425712f0813c546ed9eaa0aafa4990383b2f3a5b742a5a39ef5f27300d2c861b344e78de2d2c569b9439e7893dc06b03bf3b02 \ No newline at end of file diff --git a/tests/test_energy_cutoff/results_true.dat b/tests/test_energy_cutoff/results_true.dat new file mode 100644 index 0000000000..5ad463b774 --- /dev/null +++ b/tests/test_energy_cutoff/results_true.dat @@ -0,0 +1,3 @@ +tally 1: +sum = 0.000000E+00 +sum_sq = 0.000000E+00 diff --git a/tests/test_energy_cutoff/test_energy_cutoff.py b/tests/test_energy_cutoff/test_energy_cutoff.py new file mode 100755 index 0000000000..6467a59255 --- /dev/null +++ b/tests/test_energy_cutoff/test_energy_cutoff.py @@ -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() diff --git a/tests/test_filter_mesh/inputs_true.dat b/tests/test_filter_mesh/inputs_true.dat index b683ebaeb0..d98e2f6f78 100644 --- a/tests/test_filter_mesh/inputs_true.dat +++ b/tests/test_filter_mesh/inputs_true.dat @@ -1 +1 @@ -5a9e65b8a8c9d7c575fc48c5d289bbc805739729a33d83aa79985473d83c8cc3a0c7dad8e95221090917c35ac4842667c8c9daecd06dc6b909a92475f5083753 \ No newline at end of file +c0882d16048d434219d32ed7b875615e00142b55ab78be5b51e0195e23cb534a3aa5a8e9c212f0bfff96c452177315deb1264421d688438814560b4131c88930 \ No newline at end of file diff --git a/tests/test_filter_mesh/results_true.dat b/tests/test_filter_mesh/results_true.dat index 2cc3c9532b..06cd450eff 100644 --- a/tests/test_filter_mesh/results_true.dat +++ b/tests/test_filter_mesh/results_true.dat @@ -1 +1 @@ -89387dd9e5b962c773e1782ff829846968dc456d899963f5dd98761fbde73a3f81676717ff3599bc26a1b77247826c38756735a9b2b329b80ad66286a62bd3f9 \ No newline at end of file +041b7e79d384771bad5bc6800138bd20be6af7d6e1543bdcfef521de3df33ef7b7aca00ea3ccb0234c3a4d7d738dfe17987b5c1a59474efef630217f8ee1af1e \ No newline at end of file diff --git a/tests/test_iso_in_lab/inputs_true.dat b/tests/test_iso_in_lab/inputs_true.dat index 310bccb139..454f891cd6 100644 --- a/tests/test_iso_in_lab/inputs_true.dat +++ b/tests/test_iso_in_lab/inputs_true.dat @@ -1 +1 @@ -4b3d0270a479e65579b305d1c2339b76971790bc7371c685efa6e2d341980fec301cf0859c34796ae04ae98aa01ab8b4905a8d8a3a916895c36d82ca6b58fb39 \ No newline at end of file +57d1ece4aa9633e5fc6d2fce9f7bba444d02046e0cdadc6e53efdf591b6e50fd0e5a14b956b7ad10710b4535b10354899e2ffc783fd78de5ccd09a061cb5678d \ No newline at end of file diff --git a/tests/test_iso_in_lab/results_true.dat b/tests/test_iso_in_lab/results_true.dat index 354ccb0f8c..5b2c5dd001 100644 --- a/tests/test_iso_in_lab/results_true.dat +++ b/tests/test_iso_in_lab/results_true.dat @@ -1,2 +1,2 @@ k-combined: -9.638450E-01 1.237705E-02 +9.753410E-01 6.608245E-02 diff --git a/tests/test_mg_basic/inputs_true.dat b/tests/test_mg_basic/inputs_true.dat index fad74ca827..08917ab7db 100644 --- a/tests/test_mg_basic/inputs_true.dat +++ b/tests/test_mg_basic/inputs_true.dat @@ -1 +1 @@ -e843dbee8b989142d68e78f7a3e83309a9982c0127974ba4b6a58c823ce298e8fffc8828b48aa696f045818a2a80ef4003f5a191f33aacef7d7dd72c950855a6 \ No newline at end of file +115218221500e60ea43145875324a9a6800366fcc97357ef4cd8182f9253e114cbe1c7481dd3bdd8d7dce5983e2cb757ae0a2e05ede236d94cba7909703ba7f7 \ No newline at end of file diff --git a/tests/test_mg_basic/results_true.dat b/tests/test_mg_basic/results_true.dat index 7cdda73b5d..01b7925469 100644 --- a/tests/test_mg_basic/results_true.dat +++ b/tests/test_mg_basic/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.047136E+00 2.765964E-02 +1.160653E+00 6.227102E-02 diff --git a/tests/test_mg_max_order/inputs_true.dat b/tests/test_mg_max_order/inputs_true.dat index d827cfaa49..3056e8cbdf 100644 --- a/tests/test_mg_max_order/inputs_true.dat +++ b/tests/test_mg_max_order/inputs_true.dat @@ -1 +1 @@ -7d508b1f3a2661566b8e8cb76fee61aecb96e8b60d633b06f13c4600bd854ea3366cdebd033c0a71ffb8adb90a9aeb64fe5ac0ef3235260921f5689c93e54305 \ No newline at end of file +139d760cd83eab001ed3fd52d7146fb5f30b7021b26ada6a1e425f5446185ac6fa61ac2ac58aa9e895981e10540160b7ae7428c833024679ef1ca762715e2d51 \ No newline at end of file diff --git a/tests/test_mg_max_order/results_true.dat b/tests/test_mg_max_order/results_true.dat index 4db04e0897..0e470e2cdb 100644 --- a/tests/test_mg_max_order/results_true.dat +++ b/tests/test_mg_max_order/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.102093E+00 4.962190E-02 +1.098323E+00 1.979833E-02 diff --git a/tests/test_mg_max_order/test_mg_max_order.py b/tests/test_mg_max_order/test_mg_max_order.py index da699316ca..8c7948a323 100644 --- a/tests/test_mg_max_order/test_mg_max_order.py +++ b/tests/test_mg_max_order/test_mg_max_order.py @@ -2,83 +2,26 @@ import os import sys + sys.path.insert(0, os.pardir) -from testing_harness import TestHarness, PyAPITestHarness +from testing_harness import PyAPITestHarness from input_set import MGInputSet -import openmc -class MGNuclideInputSet(MGInputSet): - def build_default_materials_and_geometry(self): - # 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) - - clad_data = openmc.Macroscopic('clad_iso') - clad = openmc.Material(name='Clad', material_id=2) - clad.set_density('macro', 1.0) - clad.add_macroscopic(clad_data) - - water_data = openmc.Macroscopic('lwtr_iso') - water = openmc.Material(name='LWTR', material_id=3) - water.set_density('macro', 1.0) - water.add_macroscopic(water_data) - - # Define the materials file. - self.materials += (uo2, clad, water) - - # 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') - - 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 root universe. - root = openmc.Universe(universe_id=0, name='root universe') - - root.add_cells((c1,c2,c3)) - - # Define the geometry file. - geometry = openmc.Geometry() - geometry.root_universe = root - - self.geometry = geometry class MGMaxOrderTestHarness(PyAPITestHarness): def __init__(self, statepoint_name, tallies_present, mg=False): PyAPITestHarness.__init__(self, statepoint_name, tallies_present) - self._input_set = MGNuclideInputSet() + self._input_set = MGInputSet() def _build_inputs(self): + """Write input XML files.""" + reps = ['iso'] + self._input_set.build_default_materials_and_geometry(reps=reps) + self._input_set.build_default_settings() # Set P1 scattering self._input_set.settings.max_order = 1 - # Call standard input build - super(MGMaxOrderTestHarness, self)._build_inputs() + self._input_set.export() + if __name__ == '__main__': harness = MGMaxOrderTestHarness('statepoint.10.*', False, mg=True) diff --git a/tests/test_mg_nuclide/inputs_true.dat b/tests/test_mg_nuclide/inputs_true.dat index 18811f2854..57aa5d33f0 100644 --- a/tests/test_mg_nuclide/inputs_true.dat +++ b/tests/test_mg_nuclide/inputs_true.dat @@ -1 +1 @@ -be296da93031694b2915e1a10e3e6fd663d612cdd29a84745e3ccb0065c088b4bcda45f6919962f6ee784efe52ebe178bf7d3ce019859637ae57c2da1e240a04 \ No newline at end of file +6d03b988671fe21dfe2a908685536edb3059e5bdda7974ddfa65c7f63cecb7f6b3fce49bc1533ef2787e284121779653cb14a66cfd709258e4b07d8bd7571843 \ No newline at end of file diff --git a/tests/test_mg_nuclide/results_true.dat b/tests/test_mg_nuclide/results_true.dat index 7cdda73b5d..01b7925469 100644 --- a/tests/test_mg_nuclide/results_true.dat +++ b/tests/test_mg_nuclide/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.047136E+00 2.765964E-02 +1.160653E+00 6.227102E-02 diff --git a/tests/test_mg_nuclide/test_mg_nuclide.py b/tests/test_mg_nuclide/test_mg_nuclide.py index 89694eea25..b94af258f2 100644 --- a/tests/test_mg_nuclide/test_mg_nuclide.py +++ b/tests/test_mg_nuclide/test_mg_nuclide.py @@ -2,81 +2,22 @@ import os import sys + sys.path.insert(0, os.pardir) -from testing_harness import TestHarness, PyAPITestHarness +from testing_harness import PyAPITestHarness from input_set import MGInputSet -import openmc -class MGNuclideInputSet(MGInputSet): - def build_default_materials_and_geometry(self): - # Define materials needed for 1D/1G slab problem - # This time do using nuclide, not macroscopic - uo2 = openmc.Material(name='UO2', material_id=1) - uo2.set_density('sum', 1.0) - uo2.add_nuclide("uo2_iso", 1.0) - - clad = openmc.Material(name='Clad', material_id=2) - clad.set_density('sum', 1.0) - clad.add_nuclide("clad_ang_mu", 1.0) - - # water_data = openmc.Nuclide('lwtr_iso_mu', '71c') - water = openmc.Material(name='LWTR', material_id=3) - water.set_density('sum', 1.0) - water.add_nuclide("lwtr_iso_mu", 1.0) - - # Define the materials file. - self.materials.default_xs = '71c' - self.materials += (uo2, clad, water) - - # 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') - - 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 root universe. - root = openmc.Universe(universe_id=0, name='root universe') - - root.add_cells((c1,c2,c3)) - - # Define the geometry file. - geometry = openmc.Geometry() - geometry.root_universe = root - - self.geometry = geometry class MGNuclideTestHarness(PyAPITestHarness): def __init__(self, statepoint_name, tallies_present, mg=False): PyAPITestHarness.__init__(self, statepoint_name, tallies_present) - self._input_set = MGNuclideInputSet() + self._input_set = MGInputSet() def _build_inputs(self): - super(MGNuclideTestHarness, self)._build_inputs() - + """Write input XML files.""" + self._input_set.build_default_materials_and_geometry(as_macro=False) + self._input_set.build_default_settings() + self._input_set.export() if __name__ == '__main__': diff --git a/tests/test_mg_tallies/inputs_true.dat b/tests/test_mg_tallies/inputs_true.dat index e1f3385a43..6b0ff76b15 100644 --- a/tests/test_mg_tallies/inputs_true.dat +++ b/tests/test_mg_tallies/inputs_true.dat @@ -1 +1 @@ -b607875dcaecb7110e396a62100182818b8b2853ec9921194b7ab00d6156373b01394ad8bd729babf7d258e6d9c599f6944c6857cd9d2f65ea98e245ee3cf010 \ No newline at end of file +8c496e13f9456bedcc0789ffdca81913596cca3c7867717ced38c3063b6cdc8949bd204c98723b72c1b456e3fc85fc90e6710482b0c74e5e29283902a5d9ed50 \ No newline at end of file diff --git a/tests/test_mg_tallies/results_true.dat b/tests/test_mg_tallies/results_true.dat index cb0498e511..b540d9a492 100644 --- a/tests/test_mg_tallies/results_true.dat +++ b/tests/test_mg_tallies/results_true.dat @@ -1,2906 +1 @@ -k-combined: -1.047136E+00 2.765964E-02 -tally 1: -2.490837E+00 -1.335515E+00 -8.299408E-02 -1.628477E-03 -3.917892E+00 -3.395475E+00 -3.777816E-02 -3.574150E-04 -9.366009E-02 -2.196850E-03 -2.099094E+00 -8.919271E-01 -7.540489E-02 -1.194829E-03 -3.366752E+00 -2.321133E+00 -3.536709E-02 -2.711517E-04 -8.768256E-02 -1.666633E-03 -2.667561E+00 -1.528159E+00 -6.981409E-02 -1.036744E-03 -3.696781E+00 -2.912439E+00 -2.768232E-02 -1.628195E-04 -6.863038E-02 -1.000769E-03 -2.643152E+00 -1.461242E+00 -7.777503E-02 -1.277892E-03 -3.881716E+00 -3.158579E+00 -3.318888E-02 -2.353505E-04 -8.228231E-02 -1.446581E-03 -2.379478E+00 -1.220072E+00 -7.149541E-02 -1.036720E-03 -3.597267E+00 -2.694760E+00 -3.098378E-02 -1.953397E-04 -7.681538E-02 -1.200655E-03 -3.128432E+00 -2.123023E+00 -8.683081E-02 -1.593217E-03 -4.568791E+00 -4.439900E+00 -3.595477E-02 -2.733665E-04 -8.913952E-02 -1.680246E-03 -3.320603E+00 -2.324411E+00 -9.169756E-02 -1.769612E-03 -4.811447E+00 -4.885591E+00 -3.780490E-02 -3.050758E-04 -9.372640E-02 -1.875147E-03 -3.709821E+00 -2.847102E+00 -1.037249E-01 -2.264974E-03 -5.329369E+00 -5.878403E+00 -4.295875E-02 -3.964777E-04 -1.065039E-01 -2.436949E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.410307E+00 -1.211320E+00 -7.104710E-02 -1.056830E-03 -3.619111E+00 -2.712466E+00 -3.046789E-02 -2.019483E-04 -7.553639E-02 -1.241275E-03 -2.413065E+00 -1.186499E+00 -7.505466E-02 -1.154624E-03 -3.609948E+00 -2.664048E+00 -3.294274E-02 -2.242161E-04 -8.167207E-02 -1.378144E-03 -2.579691E+00 -1.399684E+00 -7.252523E-02 -1.085979E-03 -3.762646E+00 -2.966415E+00 -3.021298E-02 -1.872587E-04 -7.490441E-02 -1.150985E-03 -2.707136E+00 -1.528526E+00 -7.153411E-02 -1.046460E-03 -3.793295E+00 -2.976791E+00 -2.857458E-02 -1.671752E-04 -7.084247E-02 -1.027542E-03 -3.155079E+00 -2.066218E+00 -9.171950E-02 -1.711836E-03 -4.700403E+00 -4.503318E+00 -3.904100E-02 -3.167906E-04 -9.679096E-02 -1.947152E-03 -2.955891E+00 -1.796192E+00 -8.526700E-02 -1.464085E-03 -4.355866E+00 -3.839684E+00 -3.605221E-02 -2.663621E-04 -8.938111E-02 -1.637194E-03 -3.157638E+00 -2.088634E+00 -8.917486E-02 -1.627414E-03 -4.530493E+00 -4.262890E+00 -3.711278E-02 -2.791427E-04 -9.201048E-02 -1.715750E-03 -3.237824E+00 -2.159909E+00 -9.708289E-02 -1.898400E-03 -4.765807E+00 -4.617662E+00 -4.179332E-02 -3.503645E-04 -1.036145E-01 -2.153514E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.616860E+00 -1.407243E+00 -7.221083E-02 -1.059301E-03 -3.719840E+00 -2.827103E+00 -2.963219E-02 -1.775955E-04 -7.346451E-02 -1.091590E-03 -2.536174E+00 -1.301621E+00 -7.790327E-02 -1.242427E-03 -3.836384E+00 -2.980367E+00 -3.409705E-02 -2.443384E-04 -8.453386E-02 -1.501825E-03 -2.326398E+00 -1.111745E+00 -6.380790E-02 -8.422824E-04 -3.373074E+00 -2.338678E+00 -2.619114E-02 -1.463613E-04 -6.493342E-02 -8.996094E-04 -2.745209E+00 -1.561299E+00 -7.557988E-02 -1.164281E-03 -3.914803E+00 -3.154166E+00 -3.099509E-02 -1.948889E-04 -7.684344E-02 -1.197884E-03 -2.737388E+00 -1.515779E+00 -7.304714E-02 -1.077128E-03 -3.854064E+00 -2.996781E+00 -2.937470E-02 -1.746013E-04 -7.282614E-02 -1.073187E-03 -2.731962E+00 -1.617682E+00 -7.685258E-02 -1.239175E-03 -4.057901E+00 -3.505399E+00 -3.210546E-02 -2.150275E-04 -7.959627E-02 -1.321666E-03 -2.826797E+00 -1.654653E+00 -8.798649E-02 -1.562942E-03 -4.238099E+00 -3.671654E+00 -3.864939E-02 -3.007708E-04 -9.582007E-02 -1.848687E-03 -2.503072E+00 -1.321745E+00 -6.623202E-02 -9.120239E-04 -3.541728E+00 -2.623055E+00 -2.654018E-02 -1.469478E-04 -6.579875E-02 -9.032144E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.383417E+00 -1.171863E+00 -6.968054E-02 -9.924374E-04 -3.486989E+00 -2.493855E+00 -2.962148E-02 -1.817051E-04 -7.343795E-02 -1.116850E-03 -2.666159E+00 -1.492268E+00 -7.417343E-02 -1.141120E-03 -3.912196E+00 -3.186439E+00 -3.075257E-02 -1.953163E-04 -7.624217E-02 -1.200511E-03 -2.689651E+00 -1.483190E+00 -8.007622E-02 -1.328579E-03 -4.015410E+00 -3.294872E+00 -3.443210E-02 -2.525628E-04 -8.536450E-02 -1.552377E-03 -3.141608E+00 -2.000672E+00 -8.238823E-02 -1.366316E-03 -4.442048E+00 -3.976219E+00 -3.282615E-02 -2.177028E-04 -8.138301E-02 -1.338110E-03 -3.294568E+00 -2.201280E+00 -8.370459E-02 -1.449531E-03 -4.567777E+00 -4.247816E+00 -3.258414E-02 -2.266289E-04 -8.078302E-02 -1.392974E-03 -3.058734E+00 -1.911285E+00 -8.780153E-02 -1.572171E-03 -4.531361E+00 -4.177302E+00 -3.703146E-02 -2.828466E-04 -9.180888E-02 -1.738516E-03 -2.639291E+00 -1.470166E+00 -8.380168E-02 -1.469150E-03 -3.995402E+00 -3.337545E+00 -3.720130E-02 -2.907469E-04 -9.222996E-02 -1.787075E-03 -2.360183E+00 -1.196310E+00 -7.336179E-02 -1.123869E-03 -3.552179E+00 -2.637131E+00 -3.222538E-02 -2.218615E-04 -7.989359E-02 -1.363671E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.177844E+00 -9.998272E-01 -6.808817E-02 -9.543925E-04 -3.302614E+00 -2.268097E+00 -3.001326E-02 -1.847730E-04 -7.440926E-02 -1.135706E-03 -2.459342E+00 -1.286534E+00 -6.409323E-02 -8.519553E-04 -3.511461E+00 -2.568245E+00 -2.550853E-02 -1.387171E-04 -6.324108E-02 -8.526242E-04 -2.712538E+00 -1.496273E+00 -7.040893E-02 -1.033599E-03 -3.801423E+00 -2.967673E+00 -2.785218E-02 -1.687241E-04 -6.905150E-02 -1.037062E-03 -3.078971E+00 -1.928690E+00 -8.927133E-02 -1.655293E-03 -4.508330E+00 -4.154031E+00 -3.778191E-02 -3.038622E-04 -9.366939E-02 -1.867688E-03 -3.040055E+00 -1.908677E+00 -8.543146E-02 -1.469528E-03 -4.395363E+00 -3.943052E+00 -3.551022E-02 -2.539139E-04 -8.803740E-02 -1.560681E-03 -2.854688E+00 -1.652859E+00 -8.501906E-02 -1.459424E-03 -4.215336E+00 -3.600073E+00 -3.650039E-02 -2.691434E-04 -9.049224E-02 -1.654289E-03 -2.563883E+00 -1.375196E+00 -8.901196E-02 -1.610331E-03 -4.042903E+00 -3.361278E+00 -4.116155E-02 -3.428545E-04 -1.020482E-01 -2.107354E-03 -2.353136E+00 -1.260383E+00 -7.514099E-02 -1.159881E-03 -3.611322E+00 -2.808437E+00 -3.349306E-02 -2.280172E-04 -8.303643E-02 -1.401507E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.585363E+00 -1.416531E+00 -7.208386E-02 -1.068367E-03 -3.721777E+00 -2.868016E+00 -2.981132E-02 -1.871051E-04 -7.390860E-02 -1.150041E-03 -3.227353E+00 -2.189454E+00 -8.161989E-02 -1.366996E-03 -4.465292E+00 -4.143037E+00 -3.169508E-02 -2.069605E-04 -7.857885E-02 -1.272082E-03 -3.101358E+00 -2.022582E+00 -8.316566E-02 -1.469875E-03 -4.433641E+00 -4.167950E+00 -3.363316E-02 -2.428472E-04 -8.338377E-02 -1.492660E-03 -3.342682E+00 -2.353374E+00 -9.542381E-02 -1.892530E-03 -4.916807E+00 -5.068483E+00 -4.010858E-02 -3.330650E-04 -9.943770E-02 -2.047183E-03 -2.733720E+00 -1.608810E+00 -7.575232E-02 -1.234497E-03 -3.955386E+00 -3.353987E+00 -3.126476E-02 -2.114507E-04 -7.751200E-02 -1.299681E-03 -2.532385E+00 -1.341692E+00 -7.908024E-02 -1.289149E-03 -3.816608E+00 -3.020090E+00 -3.480705E-02 -2.494950E-04 -8.629409E-02 -1.533520E-03 -2.651467E+00 -1.472579E+00 -7.547436E-02 -1.201468E-03 -3.877983E+00 -3.154531E+00 -3.166886E-02 -2.150564E-04 -7.851384E-02 -1.321843E-03 -2.404559E+00 -1.241962E+00 -6.952417E-02 -1.036673E-03 -3.551485E+00 -2.687553E+00 -2.947110E-02 -1.929942E-04 -7.306514E-02 -1.186238E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.740199E+00 -1.663131E+00 -8.719535E-02 -1.596752E-03 -4.146740E+00 -3.682203E+00 -3.870935E-02 -3.136109E-04 -9.596871E-02 -1.927608E-03 -3.006650E+00 -1.972749E+00 -8.846181E-02 -1.643195E-03 -4.449165E+00 -4.222523E+00 -3.779771E-02 -2.999515E-04 -9.370858E-02 -1.843651E-03 -2.669269E+00 -1.482479E+00 -7.250461E-02 -1.097959E-03 -3.815372E+00 -3.039000E+00 -2.952621E-02 -1.837209E-04 -7.320176E-02 -1.129240E-03 -2.906350E+00 -1.760817E+00 -8.559496E-02 -1.527401E-03 -4.338708E+00 -3.888336E+00 -3.663301E-02 -2.834528E-04 -9.082102E-02 -1.742242E-03 -2.633801E+00 -1.566751E+00 -7.851898E-02 -1.276803E-03 -3.867974E+00 -3.237952E+00 -3.370851E-02 -2.331450E-04 -8.357057E-02 -1.433025E-03 -2.946914E+00 -1.857842E+00 -7.586572E-02 -1.217999E-03 -4.089763E+00 -3.522165E+00 -2.980738E-02 -1.901498E-04 -7.389883E-02 -1.168755E-03 -2.884789E+00 -1.801722E+00 -7.517555E-02 -1.168857E-03 -4.085136E+00 -3.522983E+00 -2.985774E-02 -1.859368E-04 -7.402368E-02 -1.142860E-03 -2.740499E+00 -1.588007E+00 -7.592011E-02 -1.232446E-03 -3.959573E+00 -3.327411E+00 -3.134446E-02 -2.121705E-04 -7.770960E-02 -1.304106E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.212799E+00 -1.000035E+00 -7.449165E-02 -1.135538E-03 -3.466616E+00 -2.419923E+00 -3.399202E-02 -2.463541E-04 -8.427346E-02 -1.514215E-03 -2.591189E+00 -1.530310E+00 -7.305643E-02 -1.114250E-03 -3.732882E+00 -3.031120E+00 -3.039294E-02 -1.919600E-04 -7.535057E-02 -1.179882E-03 -2.719836E+00 -1.670890E+00 -8.176774E-02 -1.472662E-03 -4.030045E+00 -3.607044E+00 -3.530219E-02 -2.721266E-04 -8.752165E-02 -1.672625E-03 -2.201534E+00 -1.026489E+00 -7.361463E-02 -1.156634E-03 -3.444005E+00 -2.510736E+00 -3.352726E-02 -2.491193E-04 -8.312121E-02 -1.531211E-03 -2.649820E+00 -1.500516E+00 -6.849773E-02 -9.733415E-04 -3.744876E+00 -2.926356E+00 -2.706771E-02 -1.530408E-04 -6.710661E-02 -9.406650E-04 -2.788908E+00 -1.667764E+00 -7.477958E-02 -1.148212E-03 -4.029335E+00 -3.403340E+00 -3.033277E-02 -1.914118E-04 -7.520139E-02 -1.176512E-03 -2.810664E+00 -1.609682E+00 -6.917229E-02 -9.875658E-04 -3.854296E+00 -3.029615E+00 -2.634304E-02 -1.483398E-04 -6.531000E-02 -9.117703E-04 -2.647586E+00 -1.416013E+00 -7.421099E-02 -1.112815E-03 -3.826931E+00 -2.947306E+00 -3.083732E-02 -1.923794E-04 -7.645229E-02 -1.182459E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -tally 2: -3.995283E+01 -3.210141E+02 -3.996387E+01 -3.211916E+02 -6.783537E+00 -9.416330E+00 -6.783789E+00 -9.417032E+00 -1.239468E+02 -3.134204E+03 -1.239468E+02 -3.134204E+03 +6ab4a178b642f886eea9fddbdf67a8d6d3e0d1968f06ee52d7fd5ecdc1b4a796398e9b3a8c15ac72fb1a011d13a5fcc59a868781d38fb11787e060bb2e602a7b \ No newline at end of file diff --git a/tests/test_mg_tallies/test_mg_tallies.py b/tests/test_mg_tallies/test_mg_tallies.py index c9c5e95be2..b9bbcb5542 100644 --- a/tests/test_mg_tallies/test_mg_tallies.py +++ b/tests/test_mg_tallies/test_mg_tallies.py @@ -3,38 +3,84 @@ import os import sys sys.path.insert(0, os.pardir) -from testing_harness import TestHarness, PyAPITestHarness +from testing_harness import HashedPyAPITestHarness import openmc -class MGTalliesTestHarness(PyAPITestHarness): +class MGTalliesTestHarness(HashedPyAPITestHarness): def _build_inputs(self): + """Write input XML files.""" + self._input_set.build_default_materials_and_geometry(as_macro=False) + self._input_set.build_default_settings() + # Instantiate a tally mesh mesh = openmc.Mesh(mesh_id=1) mesh.type = 'regular' - mesh.dimension = [17, 17, 1] + mesh.dimension = [1, 1, 10] mesh.lower_left = [0.0, 0.0, 0.0] - mesh.upper_right = [21.42, 21.42, 100.0] + mesh.upper_right = [10, 10, 5] # Instantiate some tally filters energy_filter = openmc.EnergyFilter([0.0, 20.0]) energyout_filter = openmc.EnergyoutFilter([0.0, 20.0]) mesh_filter = openmc.MeshFilter(mesh) - mat_filter = openmc.MaterialFilter([1,2,3]) + mat_ids = [mat.id for mat in self._input_set.materials] + mat_filter = openmc.MaterialFilter(mat_ids) - tally1 = openmc.Tally(tally_id=1) - tally1.filters = [mesh_filter] - tally1.scores = ['total', 'absorption', 'flux', - 'fission', 'nu-fission'] + nuclides = [xs.name for xs in self._input_set.xs_data] - tally2 = openmc.Tally(tally_id=2) - tally2.filters = [mat_filter, energy_filter, energyout_filter] - tally2.scores = ['scatter', 'nu-scatter'] + scores= {False: ['total', 'absorption', 'flux', 'fission', 'nu-fission'], + True: ['total', 'absorption', 'fission', 'nu-fission']} - self._input_set.tallies = openmc.Tallies([tally1, tally2]) + tallies = [] + for do_nuclides in [False, True]: + tallies.append(openmc.Tally()) + tallies[-1].filters = [mesh_filter] + tallies[-1].estimator = 'analog' + tallies[-1].scores = scores[do_nuclides] + if do_nuclides: + tallies[-1].nuclides = nuclides - super(MGTalliesTestHarness, self)._build_inputs() + tallies.append(openmc.Tally()) + tallies[-1].filters = [mesh_filter] + tallies[-1].estimator = 'tracklength' + tallies[-1].scores = scores[do_nuclides] + if do_nuclides: + tallies[-1].nuclides = nuclides + + tallies.append(openmc.Tally()) + tallies[-1].filters = [mat_filter, energy_filter] + tallies[-1].estimator = 'analog' + tallies[-1].scores = scores[do_nuclides] + ['scatter', + 'nu-scatter'] + if do_nuclides: + tallies[-1].nuclides = nuclides + + tallies.append(openmc.Tally()) + tallies[-1].filters = [mat_filter, energy_filter] + tallies[-1].estimator = 'collision' + tallies[-1].scores = scores[do_nuclides] + if do_nuclides: + tallies[-1].nuclides = nuclides + + tallies.append(openmc.Tally()) + tallies[-1].filters = [mat_filter, energy_filter] + tallies[-1].estimator = 'tracklength' + tallies[-1].scores = scores[do_nuclides] + if do_nuclides: + tallies[-1].nuclides = nuclides + + tallies.append(openmc.Tally()) + tallies[-1].filters = [mat_filter, energy_filter, + energyout_filter] + tallies[-1].scores = ['scatter', 'nu-scatter', 'nu-fission'] + if do_nuclides: + tallies[-1].nuclides = nuclides + + self._input_set.tallies = openmc.Tallies(tallies) + + self._input_set.export() def _cleanup(self): super(MGTalliesTestHarness, self)._cleanup() diff --git a/tests/test_mgxs_library_ce_to_mg/results_true.dat b/tests/test_mgxs_library_ce_to_mg/results_true.dat index 6710c82be1..0b73724c9c 100644 --- a/tests/test_mgxs_library_ce_to_mg/results_true.dat +++ b/tests/test_mgxs_library_ce_to_mg/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.140804E+00 2.937150E-02 +1.140724E+00 2.952379E-02 diff --git a/tests/test_mgxs_library_ce_to_mg/test_mgxs_library_ce_to_mg.py b/tests/test_mgxs_library_ce_to_mg/test_mgxs_library_ce_to_mg.py index baa54b018b..eee528e88e 100644 --- a/tests/test_mgxs_library_ce_to_mg/test_mgxs_library_ce_to_mg.py +++ b/tests/test_mgxs_library_ce_to_mg/test_mgxs_library_ce_to_mg.py @@ -61,14 +61,14 @@ class MGXSTestHarness(PyAPITestHarness): self._input_set.geometry = self.mgxs_lib.create_mg_mode() # Modify settings so we can run in MG mode - self._input_set.settings.cross_sections = './mgxs.xml' + self._input_set.settings.cross_sections = './mgxs.h5' self._input_set.settings.energy_mode = 'multi-group' # Write modified input files self._input_set.settings.export_to_xml() self._input_set.geometry.export_to_xml() self._input_set.materials.export_to_xml() - self._input_set.mgxs_file.export_to_xml() + self._input_set.mgxs_file.export_to_hdf5() # Dont need tallies.xml, so remove the file if os.path.exists('./tallies.xml'): os.remove('./tallies.xml') @@ -83,9 +83,8 @@ class MGXSTestHarness(PyAPITestHarness): returncode = openmc.run(openmc_exec=self._opts.exe) def _cleanup(self): - return super(MGXSTestHarness, self)._cleanup() - f = os.path.join(os.getcwd(), 'mgxs.xml') + f = os.path.join(os.getcwd(), 'mgxs.h5') if os.path.exists(f): os.remove(f) diff --git a/tests/test_mgxs_library_mesh/inputs_true.dat b/tests/test_mgxs_library_mesh/inputs_true.dat index 6e3fc6e63e..a87549a607 100644 --- a/tests/test_mgxs_library_mesh/inputs_true.dat +++ b/tests/test_mgxs_library_mesh/inputs_true.dat @@ -1 +1 @@ -88b1a1b52bcae466bab63038d03e9b2fb9f2a28aac3d73573ca00d5f0c116aa9e1c97341215b80266e8317a0549f11d9adcb8726c82fcc1741a5a730e10c8186 \ No newline at end of file +5011f0aec7bb04e22f96cec2c23ae485fe21371dc03e16cb38695b3765cb92545459a897184b501bb99f8e7d162cfbf85eb3fb52ce2d82b2d2ca722b567cbff3 \ No newline at end of file diff --git a/tests/test_mgxs_library_mesh/results_true.dat b/tests/test_mgxs_library_mesh/results_true.dat index 8ad0f2eee1..16d20391cf 100644 --- a/tests/test_mgxs_library_mesh/results_true.dat +++ b/tests/test_mgxs_library_mesh/results_true.dat @@ -1,168 +1,168 @@ mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.640786 0.044177 -1 1 2 1 1 total 0.615276 0.104046 -2 2 1 1 1 total 0.660597 0.128423 -3 2 2 1 1 total 0.646999 0.186709 - mesh 1 group in nuclide mean std. dev. - x y z -0 1 1 1 1 total 0.36665 0.048814 -1 1 2 1 1 total 0.36356 0.074111 -2 2 1 1 1 total 0.40784 0.096486 -3 2 2 1 1 total 0.41456 0.160443 +0 1 1 1 1 total 0.654966 0.098415 +1 1 2 1 1 total 0.639357 0.282107 +2 2 1 1 1 total 0.713534 0.079789 +3 2 2 1 1 total 0.641095 0.091519 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.366650 0.048814 -1 1 2 1 1 total 0.363560 0.074111 -2 2 1 1 1 total 0.407840 0.096486 -3 2 2 1 1 total 0.414593 0.160436 +0 1 1 1 1 total 0.413423 0.087250 +1 1 2 1 1 total 0.392074 0.244272 +2 2 1 1 1 total 0.458841 0.087921 +3 2 2 1 1 total 0.403898 0.074343 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.025749 0.002863 -1 1 2 1 1 total 0.022988 0.004099 -2 2 1 1 1 total 0.028400 0.005275 -3 2 2 1 1 total 0.027589 0.010350 +0 1 1 1 1 total 0.413423 0.087250 +1 1 2 1 1 total 0.392074 0.244272 +2 2 1 1 1 total 0.458841 0.087921 +3 2 2 1 1 total 0.403898 0.074343 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.015861 0.002876 -1 1 2 1 1 total 0.014403 0.003542 -2 2 1 1 1 total 0.017280 0.004371 -3 2 2 1 1 total 0.018061 0.010110 +0 1 1 1 1 total 0.021476 0.004248 +1 1 2 1 1 total 0.020653 0.008355 +2 2 1 1 1 total 0.027384 0.003568 +3 2 2 1 1 total 0.021826 0.004584 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.009888 0.001077 -1 1 2 1 1 total 0.008585 0.001552 -2 2 1 1 1 total 0.011121 0.002456 -3 2 2 1 1 total 0.009527 0.003659 +0 1 1 1 1 total 0.013234 0.004146 +1 1 2 1 1 total 0.012342 0.006800 +2 2 1 1 1 total 0.016807 0.003428 +3 2 2 1 1 total 0.013253 0.004795 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.026065 0.002907 -1 1 2 1 1 total 0.022596 0.004062 -2 2 1 1 1 total 0.029084 0.006430 -3 2 2 1 1 total 0.025066 0.009687 +0 1 1 1 1 total 0.008241 0.001798 +1 1 2 1 1 total 0.008311 0.003296 +2 2 1 1 1 total 0.010577 0.001333 +3 2 2 1 1 total 0.008573 0.002017 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 1.938476 0.211550 -1 1 2 1 1 total 1.682799 0.303764 -2 2 1 1 1 total 2.177360 0.480780 -3 2 2 1 1 total 1.864890 0.715661 +0 1 1 1 1 total 0.020322 0.004415 +1 1 2 1 1 total 0.020546 0.008145 +2 2 1 1 1 total 0.026008 0.003213 +3 2 2 1 1 total 0.021015 0.004911 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.615037 0.041754 -1 1 2 1 1 total 0.592288 0.100439 -2 2 1 1 1 total 0.632196 0.123878 -3 2 2 1 1 total 0.619410 0.177190 +0 1 1 1 1 total 1.596880 0.348354 +1 1 2 1 1 total 1.610266 0.638515 +2 2 1 1 1 total 2.048209 0.257682 +3 2 2 1 1 total 1.660283 0.390011 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.584014 0.054315 -1 1 2 1 1 total 0.587256 0.084833 -2 2 1 1 1 total 0.622514 0.111323 -3 2 2 1 1 total 0.613792 0.168612 +0 1 1 1 1 total 0.633490 0.094536 +1 1 2 1 1 total 0.618705 0.273934 +2 2 1 1 1 total 0.686150 0.076703 +3 2 2 1 1 total 0.619269 0.087616 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.638348 0.097266 +1 1 2 1 1 total 0.588378 0.266032 +2 2 1 1 1 total 0.698373 0.092394 +3 2 2 1 1 total 0.625643 0.075089 mesh 1 group in group out nuclide moment mean std. dev. x y z -0 1 1 1 1 1 total P0 0.584014 0.054315 -1 1 1 1 1 1 total P1 0.243427 0.025488 -2 1 1 1 1 1 total P2 0.089236 0.007357 -3 1 1 1 1 1 total P3 0.008994 0.005768 -4 1 2 1 1 1 total P0 0.587256 0.084833 -5 1 2 1 1 1 total P1 0.245120 0.041033 -6 1 2 1 1 1 total P2 0.086784 0.016255 -7 1 2 1 1 1 total P3 0.008660 0.004755 -8 2 1 1 1 1 total P0 0.622514 0.111323 -9 2 1 1 1 1 total P1 0.239376 0.042594 -10 2 1 1 1 1 total P2 0.088386 0.017200 -11 2 1 1 1 1 total P3 -0.001243 0.005639 -12 2 2 1 1 1 total P0 0.612950 0.167940 -13 2 2 1 1 1 total P1 0.226176 0.061882 -14 2 2 1 1 1 total P2 0.086593 0.026126 -15 2 2 1 1 1 total P3 0.009672 0.011995 +0 1 1 1 1 1 total P0 0.638348 0.097266 +1 1 1 1 1 1 total P1 0.247099 0.035574 +2 1 1 1 1 1 total P2 0.092195 0.010891 +3 1 1 1 1 1 total P3 0.013224 0.004528 +4 1 2 1 1 1 total P0 0.588378 0.266032 +5 1 2 1 1 1 total P1 0.221552 0.102564 +6 1 2 1 1 1 total P2 0.069798 0.034699 +7 1 2 1 1 1 total P3 -0.003039 0.009633 +8 2 1 1 1 1 total P0 0.698373 0.092394 +9 2 1 1 1 1 total P1 0.261835 0.035253 +10 2 1 1 1 1 total P2 0.096206 0.013947 +11 2 1 1 1 1 total P3 0.016973 0.004808 +12 2 2 1 1 1 total P0 0.625643 0.075089 +13 2 2 1 1 1 total P1 0.244646 0.028604 +14 2 2 1 1 1 total P2 0.088580 0.012369 +15 2 2 1 1 1 total P3 0.019989 0.013950 mesh 1 group in group out nuclide moment mean std. dev. x y z -0 1 1 1 1 1 total P0 0.584014 0.054315 -1 1 1 1 1 1 total P1 0.243427 0.025488 -2 1 1 1 1 1 total P2 0.089236 0.007357 -3 1 1 1 1 1 total P3 0.008994 0.005768 -4 1 2 1 1 1 total P0 0.587256 0.084833 -5 1 2 1 1 1 total P1 0.245120 0.041033 -6 1 2 1 1 1 total P2 0.086784 0.016255 -7 1 2 1 1 1 total P3 0.008660 0.004755 -8 2 1 1 1 1 total P0 0.622514 0.111323 -9 2 1 1 1 1 total P1 0.239376 0.042594 -10 2 1 1 1 1 total P2 0.088386 0.017200 -11 2 1 1 1 1 total P3 -0.001243 0.005639 -12 2 2 1 1 1 total P0 0.613792 0.168612 -13 2 2 1 1 1 total P1 0.226142 0.061856 -14 2 2 1 1 1 total P2 0.086174 0.025979 -15 2 2 1 1 1 total P3 0.009721 0.012027 +0 1 1 1 1 1 total P0 0.638348 0.097266 +1 1 1 1 1 1 total P1 0.247099 0.035574 +2 1 1 1 1 1 total P2 0.092195 0.010891 +3 1 1 1 1 1 total P3 0.013224 0.004528 +4 1 2 1 1 1 total P0 0.588378 0.266032 +5 1 2 1 1 1 total P1 0.221552 0.102564 +6 1 2 1 1 1 total P2 0.069798 0.034699 +7 1 2 1 1 1 total P3 -0.003039 0.009633 +8 2 1 1 1 1 total P0 0.698373 0.092394 +9 2 1 1 1 1 total P1 0.261835 0.035253 +10 2 1 1 1 1 total P2 0.096206 0.013947 +11 2 1 1 1 1 total P3 0.016973 0.004808 +12 2 2 1 1 1 total P0 0.625643 0.075089 +13 2 2 1 1 1 total P1 0.244646 0.028604 +14 2 2 1 1 1 total P2 0.088580 0.012369 +15 2 2 1 1 1 total P3 0.019989 0.013950 + mesh 1 group in group out nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 1.0 0.153265 +1 1 2 1 1 1 total 1.0 0.454973 +2 2 1 1 1 1 total 1.0 0.146747 +3 2 2 1 1 1 total 1.0 0.141824 mesh 1 group in group out nuclide mean std. dev. x y z -0 1 1 1 1 1 total 1.000000 0.088094 -1 1 2 1 1 1 total 1.000000 0.126864 -2 2 1 1 1 1 total 1.000000 0.160891 -3 2 2 1 1 1 total 1.001374 0.305883 - mesh 1 group in group out nuclide mean std. dev. - x y z -0 1 1 1 1 1 total 0.027395 0.004680 -1 1 2 1 1 1 total 0.019384 0.002846 -2 2 1 1 1 1 total 0.022914 0.006025 -3 2 2 1 1 1 total 0.029629 0.006292 +0 1 1 1 1 1 total 0.021059 0.003031 +1 1 2 1 1 1 total 0.017348 0.008786 +2 2 1 1 1 1 total 0.020409 0.003354 +3 2 2 1 1 1 total 0.011105 0.003806 mesh 1 group out nuclide mean std. dev. x y z -0 1 1 1 1 total 1.0 0.220956 -1 1 2 1 1 total 1.0 0.132140 -2 2 1 1 1 total 1.0 0.316565 -3 2 2 1 1 total 1.0 0.181577 +0 1 1 1 1 total 1.0 0.135958 +1 1 2 1 1 total 1.0 0.557756 +2 2 1 1 1 total 1.0 0.201340 +3 2 2 1 1 total 1.0 0.475608 mesh 1 group out nuclide mean std. dev. x y z -0 1 1 1 1 total 1.0 0.222246 -1 1 2 1 1 total 1.0 0.132140 -2 2 1 1 1 total 1.0 0.316565 -3 2 2 1 1 total 1.0 0.181577 +0 1 1 1 1 total 1.0 0.133151 +1 1 2 1 1 total 1.0 0.557756 +2 2 1 1 1 total 1.0 0.201340 +3 2 2 1 1 total 1.0 0.475608 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 3.610522e-07 3.169931e-08 -1 1 2 1 1 total 3.097784e-07 5.252025e-08 -2 2 1 1 1 total 3.942353e-07 8.459167e-08 -3 2 2 1 1 total 3.799163e-07 1.806470e-07 +0 1 1 1 1 total 4.697405e-07 8.304381e-08 +1 1 2 1 1 total 4.173069e-07 1.694647e-07 +2 2 1 1 1 total 6.581421e-07 1.337227e-07 +3 2 2 1 1 total 4.714011e-07 1.140489e-07 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.025920 0.002893 -1 1 2 1 1 total 0.022467 0.004039 -2 2 1 1 1 total 0.028922 0.006394 -3 2 2 1 1 total 0.024923 0.009632 +0 1 1 1 1 total 0.020173 0.004383 +1 1 2 1 1 total 0.020397 0.008086 +2 2 1 1 1 total 0.025824 0.003192 +3 2 2 1 1 total 0.020865 0.004879 mesh 1 delayedgroup group in nuclide mean std. dev. x y z -0 1 1 1 1 1 total 0.000004 4.432732e-07 -1 1 1 1 2 1 total 0.000026 2.653319e-06 -2 1 1 1 3 1 total 0.000024 2.402270e-06 -3 1 1 1 4 1 total 0.000054 5.464055e-06 -4 1 1 1 5 1 total 0.000026 2.663025e-06 -5 1 1 1 6 1 total 0.000010 1.038005e-06 -6 1 2 1 1 1 total 0.000004 6.987770e-07 -7 1 2 1 2 1 total 0.000023 4.115234e-06 -8 1 2 1 3 1 total 0.000021 3.816392e-06 -9 1 2 1 4 1 total 0.000049 8.885822e-06 -10 1 2 1 5 1 total 0.000024 4.378290e-06 -11 1 2 1 6 1 total 0.000009 1.745695e-06 -12 2 1 1 1 1 total 0.000005 1.098837e-06 -13 2 1 1 2 1 total 0.000029 6.436855e-06 -14 2 1 1 3 1 total 0.000027 5.926286e-06 -15 2 1 1 4 1 total 0.000061 1.359391e-05 -16 2 1 1 5 1 total 0.000029 6.489015e-06 -17 2 1 1 6 1 total 0.000011 2.574270e-06 -18 2 2 1 1 1 total 0.000004 1.660497e-06 -19 2 2 1 2 1 total 0.000025 9.701974e-06 -20 2 2 1 3 1 total 0.000023 9.005217e-06 -21 2 2 1 4 1 total 0.000054 2.084107e-05 -22 2 2 1 5 1 total 0.000026 9.981045e-06 -23 2 2 1 6 1 total 0.000010 3.987979e-06 +0 1 1 1 1 1 total 0.000005 1.004627e-06 +1 1 1 1 2 1 total 0.000025 5.397916e-06 +2 1 1 1 3 1 total 0.000025 5.274991e-06 +3 1 1 1 4 1 total 0.000058 1.230430e-05 +4 1 1 1 5 1 total 0.000026 5.548686e-06 +5 1 1 1 6 1 total 0.000011 2.306996e-06 +6 1 2 1 1 1 total 0.000004 1.779307e-06 +7 1 2 1 2 1 total 0.000024 9.648451e-06 +8 1 2 1 3 1 total 0.000024 9.479454e-06 +9 1 2 1 4 1 total 0.000056 2.231366e-05 +10 1 2 1 5 1 total 0.000026 1.028267e-05 +11 1 2 1 6 1 total 0.000011 4.268087e-06 +12 2 1 1 1 1 total 0.000006 7.462931e-07 +13 2 1 1 2 1 total 0.000031 3.842628e-06 +14 2 1 1 3 1 total 0.000031 3.666739e-06 +15 2 1 1 4 1 total 0.000071 8.228956e-06 +16 2 1 1 5 1 total 0.000031 3.416811e-06 +17 2 1 1 6 1 total 0.000013 1.429034e-06 +18 2 2 1 1 1 total 0.000005 1.049553e-06 +19 2 2 1 2 1 total 0.000025 5.392757e-06 +20 2 2 1 3 1 total 0.000024 5.145263e-06 +21 2 2 1 4 1 total 0.000056 1.156820e-05 +22 2 2 1 5 1 total 0.000025 4.880083e-06 +23 2 2 1 6 1 total 0.000010 2.037276e-06 mesh 1 delayedgroup group out nuclide mean std. dev. x y z 0 1 1 1 1 1 total 0.0 0.000000 1 1 1 1 2 1 total 0.0 0.000000 2 1 1 1 3 1 total 0.0 0.000000 -3 1 1 1 4 1 total 1.0 1.414214 -4 1 1 1 5 1 total 0.0 0.000000 +3 1 1 1 4 1 total 0.0 0.000000 +4 1 1 1 5 1 total 1.0 1.414214 5 1 1 1 6 1 total 0.0 0.000000 6 1 2 1 1 1 total 0.0 0.000000 7 1 2 1 2 1 total 0.0 0.000000 @@ -184,53 +184,53 @@ 23 2 2 1 6 1 total 0.0 0.000000 mesh 1 delayedgroup group in nuclide mean std. dev. x y z -0 1 1 1 1 1 total 0.000166 0.000023 -1 1 1 1 2 1 total 0.000989 0.000136 -2 1 1 1 3 1 total 0.000907 0.000123 -3 1 1 1 4 1 total 0.002087 0.000282 -4 1 1 1 5 1 total 0.001014 0.000137 -5 1 1 1 6 1 total 0.000400 0.000054 -6 1 2 1 1 1 total 0.000167 0.000030 -7 1 2 1 2 1 total 0.001002 0.000178 -8 1 2 1 3 1 total 0.000926 0.000165 -9 1 2 1 4 1 total 0.002149 0.000384 -10 1 2 1 5 1 total 0.001056 0.000189 -11 1 2 1 6 1 total 0.000417 0.000076 -12 2 1 1 1 1 total 0.000171 0.000039 -13 2 1 1 2 1 total 0.001003 0.000226 -14 2 1 1 3 1 total 0.000918 0.000208 -15 2 1 1 4 1 total 0.002100 0.000477 -16 2 1 1 5 1 total 0.000996 0.000228 -17 2 1 1 6 1 total 0.000394 0.000090 -18 2 2 1 1 1 total 0.000171 0.000082 -19 2 2 1 2 1 total 0.001007 0.000480 -20 2 2 1 3 1 total 0.000929 0.000445 -21 2 2 1 4 1 total 0.002143 0.001028 -22 2 2 1 5 1 total 0.001026 0.000492 -23 2 2 1 6 1 total 0.000408 0.000196 +0 1 1 1 1 1 total 0.000227 0.000061 +1 1 1 1 2 1 total 0.001228 0.000327 +2 1 1 1 3 1 total 0.001206 0.000320 +3 1 1 1 4 1 total 0.002835 0.000748 +4 1 1 1 5 1 total 0.001300 0.000340 +5 1 1 1 6 1 total 0.000540 0.000141 +6 1 2 1 1 1 total 0.000218 0.000074 +7 1 2 1 2 1 total 0.001182 0.000400 +8 1 2 1 3 1 total 0.001160 0.000393 +9 1 2 1 4 1 total 0.002726 0.000926 +10 1 2 1 5 1 total 0.001249 0.000428 +11 1 2 1 6 1 total 0.000519 0.000177 +12 2 1 1 1 1 total 0.000226 0.000033 +13 2 1 1 2 1 total 0.001207 0.000174 +14 2 1 1 3 1 total 0.001175 0.000167 +15 2 1 1 4 1 total 0.002721 0.000378 +16 2 1 1 5 1 total 0.001207 0.000160 +17 2 1 1 6 1 total 0.000502 0.000067 +18 2 2 1 1 1 total 0.000220 0.000068 +19 2 2 1 2 1 total 0.001178 0.000355 +20 2 2 1 3 1 total 0.001150 0.000343 +21 2 2 1 4 1 total 0.002675 0.000783 +22 2 2 1 5 1 total 0.001199 0.000341 +23 2 2 1 6 1 total 0.000499 0.000142 mesh 1 delayedgroup group in nuclide mean std. dev. x y z -0 1 1 1 1 1 total 0.00000 0.000000 -1 1 1 1 2 1 total 0.00000 0.000000 -2 1 1 1 3 1 total 0.00000 0.000000 -3 1 1 1 4 1 total 0.30278 0.428196 -4 1 1 1 5 1 total 0.00000 0.000000 -5 1 1 1 6 1 total 0.00000 0.000000 -6 1 2 1 1 1 total 0.00000 0.000000 -7 1 2 1 2 1 total 0.00000 0.000000 -8 1 2 1 3 1 total 0.00000 0.000000 -9 1 2 1 4 1 total 0.00000 0.000000 -10 1 2 1 5 1 total 0.00000 0.000000 -11 1 2 1 6 1 total 0.00000 0.000000 -12 2 1 1 1 1 total 0.00000 0.000000 -13 2 1 1 2 1 total 0.00000 0.000000 -14 2 1 1 3 1 total 0.00000 0.000000 -15 2 1 1 4 1 total 0.00000 0.000000 -16 2 1 1 5 1 total 0.00000 0.000000 -17 2 1 1 6 1 total 0.00000 0.000000 -18 2 2 1 1 1 total 0.00000 0.000000 -19 2 2 1 2 1 total 0.00000 0.000000 -20 2 2 1 3 1 total 0.00000 0.000000 -21 2 2 1 4 1 total 0.00000 0.000000 -22 2 2 1 5 1 total 0.00000 0.000000 -23 2 2 1 6 1 total 0.00000 0.000000 +0 1 1 1 1 1 total 0.00000 0.00000 +1 1 1 1 2 1 total 0.00000 0.00000 +2 1 1 1 3 1 total 0.00000 0.00000 +3 1 1 1 4 1 total 0.00000 0.00000 +4 1 1 1 5 1 total 0.84949 1.20136 +5 1 1 1 6 1 total 0.00000 0.00000 +6 1 2 1 1 1 total 0.00000 0.00000 +7 1 2 1 2 1 total 0.00000 0.00000 +8 1 2 1 3 1 total 0.00000 0.00000 +9 1 2 1 4 1 total 0.00000 0.00000 +10 1 2 1 5 1 total 0.00000 0.00000 +11 1 2 1 6 1 total 0.00000 0.00000 +12 2 1 1 1 1 total 0.00000 0.00000 +13 2 1 1 2 1 total 0.00000 0.00000 +14 2 1 1 3 1 total 0.00000 0.00000 +15 2 1 1 4 1 total 0.00000 0.00000 +16 2 1 1 5 1 total 0.00000 0.00000 +17 2 1 1 6 1 total 0.00000 0.00000 +18 2 2 1 1 1 total 0.00000 0.00000 +19 2 2 1 2 1 total 0.00000 0.00000 +20 2 2 1 3 1 total 0.00000 0.00000 +21 2 2 1 4 1 total 0.00000 0.00000 +22 2 2 1 5 1 total 0.00000 0.00000 +23 2 2 1 6 1 total 0.00000 0.00000 diff --git a/tests/test_tallies/inputs_true.dat b/tests/test_tallies/inputs_true.dat index 5f4bebb0d2..d716a171ce 100644 --- a/tests/test_tallies/inputs_true.dat +++ b/tests/test_tallies/inputs_true.dat @@ -1 +1 @@ -96d2f92c6017e62d688e3ca245c2ff7904a92816d188d096829440cd8fcfd4f8639dc67c12d54b324081c19e1c7dd2e79c1caeac53d7826399f11766826d5410 \ No newline at end of file +b112ccd96ff89c706c62b4c334021e352de78fc494c4c0513ca7a924bb2e9b18139c5b4fd50c9a92fff07525cc1d9b1464fcc5ca24293e6fd3a8d03d9e12b171 \ No newline at end of file diff --git a/tests/test_tallies/results_true.dat b/tests/test_tallies/results_true.dat index 108c7ee800..6b3bbf4d53 100644 --- a/tests/test_tallies/results_true.dat +++ b/tests/test_tallies/results_true.dat @@ -1 +1 @@ -a6afd2f11affce2467d77b8477881ab20091f67df4f632226ec2dd5d4cd7fabb9ac3e182563bb467ed249e4b3fe95b319cb688d653757f8ea154759b8a7f50e1 \ No newline at end of file +1e0ce3915c37809cf147e5c0634b696bafd99fa3f41573235d884e54a9a62e8440234a4ee1bf4ce94b363e7afde2ded7c0fd22d0dd897b8aacf1ee017b974449 \ No newline at end of file diff --git a/tests/test_tally_aggregation/inputs_true.dat b/tests/test_tally_aggregation/inputs_true.dat index 6d2990754d..d0f617dbfe 100644 --- a/tests/test_tally_aggregation/inputs_true.dat +++ b/tests/test_tally_aggregation/inputs_true.dat @@ -1 +1 @@ -4a4e481b9af3612c71bdc93245011555807061bbd9d9be4c5b399f2c38820d38d9ce3ac6255d045415a216737eac65fb0f0b6e331e49b90bf8edc814d0f2f0e8 \ No newline at end of file +e6604f58a6a3115b902364ac9c73fcb8babb9df0c527b0b04780fefda61fb41856cffac548a1f81fba5fdac8ab55dd00f683b724c732ed54506933e9d943574d \ No newline at end of file diff --git a/tests/test_tally_aggregation/results_true.dat b/tests/test_tally_aggregation/results_true.dat index 6c2d7a5193..929fc9fcf8 100644 --- a/tests/test_tally_aggregation/results_true.dat +++ b/tests/test_tally_aggregation/results_true.dat @@ -1 +1 @@ -840d2648f9ba782926c71baa84e5a2ad31331e156740a3d1e9d86af8f1f0d301ef8c0f69474975d365dbcf8d229a68c62d3e60286d18045e5254373f4e1010bf \ No newline at end of file +2fba1e497435b63ee277a1c8a0ecc566440c56a25cdfef1b790b839fc93da1414bd1af38a63a64fcf3e868d1347ad138f528ae12c1067aea29733670d2c9128f \ No newline at end of file diff --git a/tests/test_tally_aggregation/test_tally_aggregation.py b/tests/test_tally_aggregation/test_tally_aggregation.py index 955d7fecbb..f1915b261e 100644 --- a/tests/test_tally_aggregation/test_tally_aggregation.py +++ b/tests/test_tally_aggregation/test_tally_aggregation.py @@ -16,9 +16,9 @@ class TallyAggregationTestHarness(PyAPITestHarness): self._input_set.settings.output = {'summary': True} # Initialize the nuclides + u234 = openmc.Nuclide('U234') u235 = openmc.Nuclide('U235') u238 = openmc.Nuclide('U238') - pu239 = openmc.Nuclide('Pu239') # Initialize the filters energy_filter = openmc.EnergyFilter([0.0, 0.253e-6, 1.0e-3, 1.0, 20.0]) @@ -28,7 +28,7 @@ class TallyAggregationTestHarness(PyAPITestHarness): tally = openmc.Tally(name='distribcell tally') tally.filters = [energy_filter, distrib_filter] tally.scores = ['nu-fission', 'total'] - tally.nuclides = [u235, u238, pu239] + tally.nuclides = [u234, u235, u238] tallies_file = openmc.Tallies([tally]) # Export tallies to file @@ -59,7 +59,7 @@ class TallyAggregationTestHarness(PyAPITestHarness): outstr += ', '.join(map(str, tally_sum.std_dev)) # Sum across all nuclides - tally_sum = tally.summation(nuclides=['U235', 'U238', 'Pu239']) + tally_sum = tally.summation(nuclides=['U234', 'U235', 'U238']) outstr += ', '.join(map(str, tally_sum.mean)) outstr += ', '.join(map(str, tally_sum.std_dev)) diff --git a/tests/test_tally_arithmetic/inputs_true.dat b/tests/test_tally_arithmetic/inputs_true.dat index b0da0ed247..8cf6c4ff5d 100644 --- a/tests/test_tally_arithmetic/inputs_true.dat +++ b/tests/test_tally_arithmetic/inputs_true.dat @@ -1 +1 @@ -6747131dad4c1efd8c87d857ce9127cb16ec883fdf5fabe309d82732d47851424273e9ad4878a335555d8b25bb0c0a15e68ac30e355ae346e9885c499e9ec979 \ No newline at end of file +530c54691a4f2df131627849dd58c5e6f331ede786c1ffff0b1126c4c0fe64929a15113699103a05f2c6178ec90be4a3d6fc12b80c32ec608ed4a59c965ef2e4 \ No newline at end of file diff --git a/tests/test_tally_arithmetic/test_tally_arithmetic.py b/tests/test_tally_arithmetic/test_tally_arithmetic.py index 6e52313ef7..d28db3e959 100644 --- a/tests/test_tally_arithmetic/test_tally_arithmetic.py +++ b/tests/test_tally_arithmetic/test_tally_arithmetic.py @@ -19,9 +19,9 @@ class TallyArithmeticTestHarness(PyAPITestHarness): tallies_file = openmc.Tallies() # Initialize the nuclides + u234 = openmc.Nuclide('U234') u235 = openmc.Nuclide('U235') u238 = openmc.Nuclide('U238') - pu239 = openmc.Nuclide('Pu239') # Initialize Mesh mesh = openmc.Mesh(mesh_id=1) @@ -40,7 +40,7 @@ class TallyArithmeticTestHarness(PyAPITestHarness): tally = openmc.Tally(name='tally 1') tally.filters = [material_filter, energy_filter, distrib_filter] tally.scores = ['nu-fission', 'total'] - tally.nuclides = [u235, pu239] + tally.nuclides = [u234, u235] tallies_file.append(tally) tally = openmc.Tally(name='tally 2') diff --git a/tests/test_tally_slice_merge/inputs_true.dat b/tests/test_tally_slice_merge/inputs_true.dat index 7a747e6b52..ef2595fbfd 100644 --- a/tests/test_tally_slice_merge/inputs_true.dat +++ b/tests/test_tally_slice_merge/inputs_true.dat @@ -1 +1 @@ -144dd4059444fad5e2e4fa20681fbdc74c0e5cbf3265104a0b49d87c768798eaeb25e3c6c795bcac2eebdde784c51588006d62c9f25be96dda5c51011a76b7c1 \ No newline at end of file +41b06951808ee7ed1e44defbaadff7305737ae494e8e98c682aefa272c0682cbd8803dd2658d8e7d78e3f5f7fb1e9f0f5e443a9374a68474bd25d0d649ac6924 \ No newline at end of file diff --git a/tests/test_tally_slice_merge/results_true.dat b/tests/test_tally_slice_merge/results_true.dat index 278d8ee108..0f43b35e1f 100644 --- a/tests/test_tally_slice_merge/results_true.dat +++ b/tests/test_tally_slice_merge/results_true.dat @@ -1,36 +1,36 @@ cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-07 U235 fission 1.08e-01 7.94e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-07 U235 nu-fission 2.64e-01 1.94e-02 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-07 U238 fission 1.51e-07 1.00e-08 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-07 U238 nu-fission 3.76e-07 2.50e-08 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 6.25e-07 2.00e+01 U235 fission 3.12e-02 2.56e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 6.25e-07 2.00e+01 U235 nu-fission 7.65e-02 6.24e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 6.25e-07 2.00e+01 U238 fission 2.00e-02 1.30e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 6.25e-07 2.00e+01 U238 nu-fission 5.56e-02 3.78e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 27 0.00e+00 6.25e-07 U235 fission 4.43e-02 7.21e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 27 0.00e+00 6.25e-07 U235 nu-fission 1.08e-01 1.76e-02 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 27 0.00e+00 6.25e-07 U238 fission 6.14e-08 9.64e-09 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 27 0.00e+00 6.25e-07 U238 nu-fission 1.53e-07 2.40e-08 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 27 6.25e-07 2.00e+01 U235 fission 1.39e-02 1.06e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 27 6.25e-07 2.00e+01 U235 nu-fission 3.40e-02 2.61e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 27 6.25e-07 2.00e+01 U238 fission 9.72e-03 1.21e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 27 6.25e-07 2.00e+01 U238 nu-fission 2.71e-02 3.80e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-07 U235 fission 1.08e-01 7.94e-03 -1 21 0.00e+00 6.25e-07 U235 nu-fission 2.64e-01 1.94e-02 -2 21 0.00e+00 6.25e-07 U238 fission 1.51e-07 1.00e-08 -3 21 0.00e+00 6.25e-07 U238 nu-fission 3.76e-07 2.50e-08 -4 21 6.25e-07 2.00e+01 U235 fission 3.12e-02 2.56e-03 -5 21 6.25e-07 2.00e+01 U235 nu-fission 7.65e-02 6.24e-03 -6 21 6.25e-07 2.00e+01 U238 fission 2.00e-02 1.30e-03 -7 21 6.25e-07 2.00e+01 U238 nu-fission 5.56e-02 3.78e-03 -8 27 0.00e+00 6.25e-07 U235 fission 4.43e-02 7.21e-03 -9 27 0.00e+00 6.25e-07 U235 nu-fission 1.08e-01 1.76e-02 -10 27 0.00e+00 6.25e-07 U238 fission 6.14e-08 9.64e-09 -11 27 0.00e+00 6.25e-07 U238 nu-fission 1.53e-07 2.40e-08 -12 27 6.25e-07 2.00e+01 U235 fission 1.39e-02 1.06e-03 -13 27 6.25e-07 2.00e+01 U235 nu-fission 3.40e-02 2.61e-03 -14 27 6.25e-07 2.00e+01 U238 fission 9.72e-03 1.21e-03 -15 27 6.25e-07 2.00e+01 U238 nu-fission 2.71e-02 3.80e-03 +0 21 0.00e+00 6.25e-07 U235 fission 2.36e-01 2.26e-02 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 21 0.00e+00 6.25e-07 U235 nu-fission 5.74e-01 5.51e-02 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 21 0.00e+00 6.25e-07 U238 fission 3.19e-07 3.06e-08 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 21 0.00e+00 6.25e-07 U238 nu-fission 7.96e-07 7.63e-08 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 21 6.25e-07 2.00e+01 U235 fission 2.82e-02 1.82e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 21 6.25e-07 2.00e+01 U235 nu-fission 6.92e-02 4.42e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 21 6.25e-07 2.00e+01 U238 fission 1.98e-02 1.74e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 21 6.25e-07 2.00e+01 U238 nu-fission 5.54e-02 4.65e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 27 0.00e+00 6.25e-07 U235 fission 1.11e-01 1.16e-02 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 27 0.00e+00 6.25e-07 U235 nu-fission 2.71e-01 2.83e-02 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 27 0.00e+00 6.25e-07 U238 fission 1.53e-07 1.67e-08 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 27 0.00e+00 6.25e-07 U238 nu-fission 3.81e-07 4.15e-08 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 27 6.25e-07 2.00e+01 U235 fission 2.00e-02 2.72e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 27 6.25e-07 2.00e+01 U235 nu-fission 4.89e-02 6.62e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 27 6.25e-07 2.00e+01 U238 fission 1.06e-02 6.18e-04 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 27 6.25e-07 2.00e+01 U238 nu-fission 2.91e-02 1.85e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 21 0.00e+00 6.25e-07 U235 fission 2.36e-01 2.26e-02 +1 21 0.00e+00 6.25e-07 U235 nu-fission 5.74e-01 5.51e-02 +2 21 0.00e+00 6.25e-07 U238 fission 3.19e-07 3.06e-08 +3 21 0.00e+00 6.25e-07 U238 nu-fission 7.96e-07 7.63e-08 +4 21 6.25e-07 2.00e+01 U235 fission 2.82e-02 1.82e-03 +5 21 6.25e-07 2.00e+01 U235 nu-fission 6.92e-02 4.42e-03 +6 21 6.25e-07 2.00e+01 U238 fission 1.98e-02 1.74e-03 +7 21 6.25e-07 2.00e+01 U238 nu-fission 5.54e-02 4.65e-03 +8 27 0.00e+00 6.25e-07 U235 fission 1.11e-01 1.16e-02 +9 27 0.00e+00 6.25e-07 U235 nu-fission 2.71e-01 2.83e-02 +10 27 0.00e+00 6.25e-07 U238 fission 1.53e-07 1.67e-08 +11 27 0.00e+00 6.25e-07 U238 nu-fission 3.81e-07 4.15e-08 +12 27 6.25e-07 2.00e+01 U235 fission 2.00e-02 2.72e-03 +13 27 6.25e-07 2.00e+01 U235 nu-fission 4.89e-02 6.62e-03 +14 27 6.25e-07 2.00e+01 U238 fission 1.06e-02 6.18e-04 +15 27 6.25e-07 2.00e+01 U238 nu-fission 2.91e-02 1.85e-03 sum(distribcell) energy low [MeV] energy high [MeV] nuclide score mean std. dev. 0 (0, 100, 2000, 30000) 0.00e+00 6.25e-07 U235 fission 0.00e+00 0.00e+00 1 (0, 100, 2000, 30000) 0.00e+00 6.25e-07 U235 nu-fission 0.00e+00 0.00e+00 @@ -49,19 +49,19 @@ 14 (500, 5000, 50000) 6.25e-07 2.00e+01 U238 fission 0.00e+00 0.00e+00 15 (500, 5000, 50000) 6.25e-07 2.00e+01 U238 nu-fission 0.00e+00 0.00e+00 sum(mesh) energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 ((1, 1, 1), (1, 2, 1)) 0.00e+00 6.25e-07 U235 fission 8.54e-03 1.30e-03 -1 ((1, 1, 1), (1, 2, 1)) 0.00e+00 6.25e-07 U235 nu-fission 2.08e-02 3.17e-03 -2 ((1, 1, 1), (1, 2, 1)) 0.00e+00 6.25e-07 U238 fission 1.21e-08 1.74e-09 -3 ((1, 1, 1), (1, 2, 1)) 0.00e+00 6.25e-07 U238 nu-fission 3.01e-08 4.34e-09 -4 ((1, 1, 1), (1, 2, 1)) 6.25e-07 2.00e+01 U235 fission 2.20e-03 6.05e-04 -5 ((1, 1, 1), (1, 2, 1)) 6.25e-07 2.00e+01 U235 nu-fission 5.38e-03 1.48e-03 -6 ((1, 1, 1), (1, 2, 1)) 6.25e-07 2.00e+01 U238 fission 1.40e-03 7.17e-04 -7 ((1, 1, 1), (1, 2, 1)) 6.25e-07 2.00e+01 U238 nu-fission 3.84e-03 1.97e-03 -8 ((2, 1, 1), (2, 2, 1)) 0.00e+00 6.25e-07 U235 fission 9.40e-03 1.62e-03 -9 ((2, 1, 1), (2, 2, 1)) 0.00e+00 6.25e-07 U235 nu-fission 2.29e-02 3.95e-03 -10 ((2, 1, 1), (2, 2, 1)) 0.00e+00 6.25e-07 U238 fission 1.34e-08 2.08e-09 -11 ((2, 1, 1), (2, 2, 1)) 0.00e+00 6.25e-07 U238 nu-fission 3.33e-08 5.18e-09 -12 ((2, 1, 1), (2, 2, 1)) 6.25e-07 2.00e+01 U235 fission 9.41e-04 2.52e-04 -13 ((2, 1, 1), (2, 2, 1)) 6.25e-07 2.00e+01 U235 nu-fission 2.31e-03 6.13e-04 -14 ((2, 1, 1), (2, 2, 1)) 6.25e-07 2.00e+01 U238 fission 7.54e-04 3.45e-04 -15 ((2, 1, 1), (2, 2, 1)) 6.25e-07 2.00e+01 U238 nu-fission 2.12e-03 1.02e-03 +0 ((1, 1, 1), (1, 2, 1)) 0.00e+00 6.25e-07 U235 fission 1.12e-02 2.45e-03 +1 ((1, 1, 1), (1, 2, 1)) 0.00e+00 6.25e-07 U235 nu-fission 2.74e-02 5.96e-03 +2 ((1, 1, 1), (1, 2, 1)) 0.00e+00 6.25e-07 U238 fission 1.56e-08 3.04e-09 +3 ((1, 1, 1), (1, 2, 1)) 0.00e+00 6.25e-07 U238 nu-fission 3.89e-08 7.57e-09 +4 ((1, 1, 1), (1, 2, 1)) 6.25e-07 2.00e+01 U235 fission 1.15e-03 4.71e-04 +5 ((1, 1, 1), (1, 2, 1)) 6.25e-07 2.00e+01 U235 nu-fission 2.81e-03 1.15e-03 +6 ((1, 1, 1), (1, 2, 1)) 6.25e-07 2.00e+01 U238 fission 3.25e-04 9.99e-05 +7 ((1, 1, 1), (1, 2, 1)) 6.25e-07 2.00e+01 U238 nu-fission 8.81e-04 2.68e-04 +8 ((2, 1, 1), (2, 2, 1)) 0.00e+00 6.25e-07 U235 fission 1.44e-02 5.57e-03 +9 ((2, 1, 1), (2, 2, 1)) 0.00e+00 6.25e-07 U235 nu-fission 3.51e-02 1.36e-02 +10 ((2, 1, 1), (2, 2, 1)) 0.00e+00 6.25e-07 U238 fission 1.95e-08 7.37e-09 +11 ((2, 1, 1), (2, 2, 1)) 0.00e+00 6.25e-07 U238 nu-fission 4.86e-08 1.84e-08 +12 ((2, 1, 1), (2, 2, 1)) 6.25e-07 2.00e+01 U235 fission 2.55e-03 1.30e-03 +13 ((2, 1, 1), (2, 2, 1)) 6.25e-07 2.00e+01 U235 nu-fission 6.23e-03 3.16e-03 +14 ((2, 1, 1), (2, 2, 1)) 6.25e-07 2.00e+01 U238 fission 8.62e-04 4.53e-04 +15 ((2, 1, 1), (2, 2, 1)) 6.25e-07 2.00e+01 U238 nu-fission 2.30e-03 1.21e-03 diff --git a/tests/testing_harness.py b/tests/testing_harness.py index 5300131642..150d124c8c 100644 --- a/tests/testing_harness.py +++ b/tests/testing_harness.py @@ -24,7 +24,7 @@ class TestHarness(object): self.parser = OptionParser() self.parser.add_option('--exe', dest='exe', default='openmc') self.parser.add_option('--mpi_exec', dest='mpi_exec', default=None) - self.parser.add_option('--mpi_np', dest='mpi_np', type=int, default=3) + self.parser.add_option('--mpi_np', dest='mpi_np', type=int, default=2) self.parser.add_option('--update', dest='update', action='store_true', default=False) self._opts = None diff --git a/tests/travis_install.sh b/tests/travis_install.sh index df1c81314b..2e35c4f65b 100755 --- a/tests/travis_install.sh +++ b/tests/travis_install.sh @@ -8,7 +8,7 @@ if [[ ! -e $HOME/mpich_install/bin/mpiexec ]]; then tar -xzvf mpich-3.1.3.tar.gz >/dev/null 2>&1 cd mpich-3.1.3 ./configure --prefix=$HOME/mpich_install -q - make >/dev/null 2>&1 + make -j 2 >/dev/null 2>&1 make install >/dev/null 2>&1 cd .. fi @@ -22,7 +22,7 @@ if [[ ! -e $HOME/phdf5_install/bin/h5pfc ]]; then ./configure \ --prefix=$HOME/phdf5_install -q --enable-fortran \ --enable-fortran2003 --enable-parallel - make >/dev/null 2>&1 + make -j 2 >/dev/null 2>&1 make install >/dev/null 2>&1 cd .. fi @@ -33,7 +33,7 @@ if [[ ! -e $HOME/hdf5_install/bin/h5fc ]]; then cd hdf5-1.8.15 CC=gcc FC=gfortran ./configure --prefix=$HOME/hdf5_install -q \ --enable-fortran --enable-fortran2003 - make -j >/dev/null 2>&1 + make -j 2 >/dev/null 2>&1 make install >/dev/null 2>&1 cd .. fi