Merge remote-tracking branch 'upstream/develop' into 2d-mesh-tally

This commit is contained in:
Sam Shaner 2016-09-12 09:50:17 -04:00
commit 5affc137e1
180 changed files with 4667 additions and 4932 deletions

View file

@ -42,7 +42,7 @@ install: true
before_script:
- if [[ ! -e $HOME/nndc_hdf5/cross_sections.xml ]]; then
wget https://anl.box.com/shared/static/dqkwdl7o4lauo91h3mgrn9qno6a3c8mp.xz -O - | tar -C $HOME -xvJ;
wget https://anl.box.com/shared/static/68b2yhu8e6mx1f6hnbzz9mxsgg42d9ls.xz -O - | tar -C $HOME -xvJ;
fi
- export OPENMC_CROSS_SECTIONS=$HOME/nndc_hdf5/cross_sections.xml

View file

@ -16,29 +16,53 @@ Incident Neutron Data
- **metastable** (*int*) -- Metastable state (0=ground, 1=first
excited, etc.)
- **atomic_weight_ratio** (*double*) -- Mass in units of neutron masses
- **temperature** (*double*) -- Temperature in MeV
- **n_reaction** (*int*) -- Number of reactions
:Datasets: - **energy** (*double[]*) -- Energy points at which cross sections are tabulated
**/<nuclide name>/kTs/**
<TTT>K is the temperature in Kelvin, rounded to the nearest integer, of the
temperature-dependent data set. For example, the data set corresponding to
300 Kelvin would be located at `300K`.
:Datasets:
- **<TTT>K** (*double*) -- kT values (in MeV) for each Temperature
TTT (in Kelvin)
**/<nuclide name>/reactions/reaction_<mt>/**
:Attributes: - **mt** (*int*) -- ENDF MT reaction number
- **label** (*char[]*) -- Name of the reaction
- **Q_value** (*double*) -- Q value in MeV
- **threshold_idx** (*int*) -- Index on the energy grid that the
reaction threshold corresponds to
- **center_of_mass** (*int*) -- Whether the reference frame for
scattering is center-of-mass (1) or laboratory (0)
- **n_product** (*int*) -- Number of reaction products
:Datasets: - **xs** (*double[]*) -- Cross section values tabulated against the nuclide energy grid
**/<nuclide name>/reactions/reaction_<mt>/<TTT>K/**
<TTT>K is the temperature in Kelvin, rounded to the nearest integer, of the
temperature-dependent data set. For example, the data set corresponding to
300 Kelvin would be located at `300K`.
:Datasets:
- **xs** (*double[]*) -- Cross section values tabulated against the
nuclide energy grid for temperature TTT (in Kelvin)
:Attributes:
- **threshold_idx** (*int*) -- Index on the energy
grid that the reaction threshold corresponds to for
temperature TTT (in Kelvin)
**/<nuclide name>/reactions/reaction_<mt>/product_<j>/**
Reaction product data is described in :ref:`product`.
**/<nuclide name>/urr**
**/<nuclide name>/urr/<TTT>K/**
<TTT>K is the temperature in Kelvin, rounded to the nearest integer, of the
temperature-dependent data set. For example, the data set corresponding to
300 Kelvin would be located at `300K`.
:Attributes: - **interpolation** (*int*) -- interpolation scheme
- **inelastic** (*int*) -- flag indicating inelastic scattering
@ -92,32 +116,48 @@ Thermal Neutron Scattering Data
**/<thermal name>/**
:Attributes: - **atomic_weight_ratio** (*double*) -- Mass in units of neutron masses
- **temperature** (*double*) -- Temperature in MeV
- **zaids** (*int[]*) -- ZAID identifiers for which the thermal
- **nuclides** (*char[][]*) -- Names of nuclides for which the thermal
scattering data applies to
**/<thermal name>/elastic/**
:Datasets: - **xs** (:ref:`tabulated <1d_tabulated>`) -- Thermal inelastic
scattering cross section
- **mu_out** (*double[][]*) -- Distribution of outgoing energies
and angles for coherent elastic scattering
**/<thermal name>/inelastic/**
:Attributes:
- **secondary_mode** (*char[]*) -- Indicates how the inelastic
outgoing angle-energy distributions are represented ('equal',
'skewed', or 'continuous').
**/<thermal name>/kTs/**
<TTT>K is the temperature in Kelvin, rounded to the nearest integer, of the
temperature-dependent data set. For example, the data set corresponding to
300 Kelvin would be located at `300K`.
:Datasets:
- **<TTT>K** (*double*) -- kT values (in MeV) for each Temperature
TTT (in Kelvin)
**/<thermal name>/elastic/<TTT>K/**
<TTT>K is the temperature in Kelvin, rounded to the nearest integer, of the
temperature-dependent data set. For example, the data set corresponding to
300 Kelvin would be located at `300K`.
:Datasets: - **xs** (:ref:`tabulated <1d_tabulated>`) -- Thermal inelastic
scattering cross section
scattering cross section for temperature TTT (in Kelvin)
- **mu_out** (*double[][]*) -- Distribution of outgoing energies
and angles for coherent elastic scattering for temperature TTT
(in Kelvin)
**/<thermal name>/inelastic/<TTT>K/**
<TTT>K is the temperature in Kelvin, rounded to the nearest integer, of the
temperature-dependent data set. For example, the data set corresponding to
300 Kelvin would be located at `300K`.
:Datasets: - **xs** (:ref:`tabulated <1d_tabulated>`) -- Thermal inelastic
scattering cross section for temperature TTT (in Kelvin)
- **energy_out** (*double[][]*) -- Distribution of outgoing
energies for each incoming energy. Only present if secondary mode
is not continuous.
energies for each incoming energy for temperature TTT (in Kelvin).
Only present if secondary mode is not continuous.
- **mu_out** (*double[][][]*) -- Distribution of scattering cosines
for each pair of incoming and outgoing energies. Only present if
secondary mode is not continuous.
for each pair of incoming and outgoing energies. for temperature
TTT (in Kelvin). Only present if secondary mode is not continuous.
If the secondary mode is continuous, the outgoing energy-angle distribution is
given as a :ref:`correlated angle-energy distribution

View file

@ -53,12 +53,12 @@ speed up the calculation.
Logarithmic Mapping
+++++++++++++++++++
To speed up energy grid searches, OpenMC uses logarithmic mapping technique
[Brown]_ to limit the range of energies that must be searched for each
nuclide. The entire energy range is divided up into equal-lethargy segments, and
the bounding energies of each segment are mapped to bounding indices on each of
the nuclide energy grids. By default, OpenMC uses 8000 equal-lethargy segments
as recommended by Brown.
To speed up energy grid searches, OpenMC uses a `logarithmic mapping technique`_
to limit the range of energies that must be searched for each nuclide. The
entire energy range is divided up into equal-lethargy segments, and the bounding
energies of each segment are mapped to bounding indices on each of the nuclide
energy grids. By default, OpenMC uses 8000 equal-lethargy segments as
recommended by Brown.
Other Methods
+++++++++++++
@ -74,9 +74,9 @@ offers support for an experimental data format called windowed multipole (WMP).
This data format requires less memory than pointwise cross sections, and it
allows on-the-fly Doppler broadening to arbitrary temperature.
The multipole method was introduced by [Hwang]_ and the faster windowed
multipole method by [Josey]_. In the multipole format, cross section resonances
are represented by poles, :math:`p_j`, and residues, :math:`r_j`, in the complex
The multipole method was introduced by Hwang_ and the faster windowed multipole
method by Josey_. In the multipole format, cross section resonances are
represented by poles, :math:`p_j`, and residues, :math:`r_j`, in the complex
plane. The 0K cross sections in the resolved resonance region can be computed
by summing up a contribution from each pole:
@ -232,21 +232,10 @@ sections. This allows flexibility for the model to use highly anisotropic
scattering information in the water while the fuel can be simulated with linear
or even isotropic scattering.
.. only:: html
.. rubric:: References
.. [Brown] Forrest B. Brown, "New Hash-based Energy Lookup Algorithm for Monte
Carlo codes," LA-UR-14-24530, Los Alamos National Laboratory (2014).
.. [Hwang] R. N. Hwang, "A Rigorous Pole Representation of Multilevel Cross
Sections and Its Practical Application," *Nucl. Sci. Eng.*, **96**,
192-209 (1987).
.. [Josey] Colin Josey, Pablo Ducru, Benoit Forget, and Kord Smith, "Windowed
Multipole for Cross Section Doppler Broadening," *J. Comp. Phys*,
**307**, 715-727 (2016). http://dx.doi.org/10.1016/j.jcp.2015.08.013
.. _logarithmic mapping technique:
https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/la-ur-14-24530.pdf
.. _Hwang: http://www.ans.org/pubs/journals/nse/a_16381
.. _Josey: http://dx.doi.org/10.1016/j.jcp.2015.08.013
.. _MCNP: http://mcnp.lanl.gov
.. _Serpent: http://montecarlo.vtt.fi
.. _NJOY: http://t2.lanl.gov/codes.shtml

View file

@ -214,7 +214,6 @@
"source": [
"# Instantiate a Materials collection and export to XML\n",
"materials_file = openmc.Materials([inf_medium])\n",
"materials_file.default_xs = '71c'\n",
"materials_file.export_to_xml()"
]
},
@ -499,23 +498,37 @@
"output_type": "stream",
"text": [
"\n",
" .d88888b. 888b d888 .d8888b.\n",
" d88P\" \"Y88b 8888b d8888 d88P Y88b\n",
" 888 888 88888b.d88888 888 888\n",
" 888 888 88888b. .d88b. 88888b. 888Y88888P888 888 \n",
" 888 888 888 \"88b d8P Y8b 888 \"88b 888 Y888P 888 888 \n",
" 888 888 888 888 88888888 888 888 888 Y8P 888 888 888\n",
" Y88b. .d88P 888 d88P Y8b. 888 888 888 \" 888 Y88b d88P\n",
" \"Y88888P\" 88888P\" \"Y8888 888 888 888 888 \"Y8888P\"\n",
"__________________888______________________________________________________\n",
" 888\n",
" 888\n",
" %%%%%%%%%%%%%%%\n",
" %%%%%%%%%%%%%%%%%%%%%%%%\n",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n",
" %%%%%%%%%%%%%%%%%%%%%%%%\n",
" %%%%%%%%%%%%%%%%%%%%%%%%\n",
" ############### %%%%%%%%%%%%%%%%%%%%%%%%\n",
" ################## %%%%%%%%%%%%%%%%%%%%%%%\n",
" ################### %%%%%%%%%%%%%%%%%%%%%%%\n",
" #################### %%%%%%%%%%%%%%%%%%%%%%\n",
" ##################### %%%%%%%%%%%%%%%%%%%%%\n",
" ###################### %%%%%%%%%%%%%%%%%%%%\n",
" ####################### %%%%%%%%%%%%%%%%%%\n",
" ####################### %%%%%%%%%%%%%%%%%\n",
" ###################### %%%%%%%%%%%%%%%%%\n",
" #################### %%%%%%%%%%%%%%%%%\n",
" ################# %%%%%%%%%%%%%%%%%\n",
" ############### %%%%%%%%%%%%%%%%\n",
" ############ %%%%%%%%%%%%%%%\n",
" ######## %%%%%%%%%%%%%%\n",
" %%%%%%%%%%%\n",
"\n",
" Copyright: 2011-2016 Massachusetts Institute of Technology\n",
" License: http://openmc.readthedocs.io/en/latest/license.html\n",
" Version: 0.7.1\n",
" Git SHA1: 3d68c07625e33cd64188df03ee03e9c31b3d4b74\n",
" Date/Time: 2016-07-22 21:03:18\n",
" | The OpenMC Monte Carlo Code\n",
" 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 | fbebf7bf709fe2fe1813af95bff9b29c0d59312c\n",
" Date/Time | 2016-08-31 10:40:13\n",
" OpenMP Threads | 4\n",
"\n",
" ===========================================================================\n",
" ========================> INITIALIZATION <=========================\n",
@ -525,12 +538,12 @@
" Reading geometry XML file...\n",
" Reading cross sections XML file...\n",
" Reading materials XML file...\n",
" Reading H1.71c from /home/romano/openmc/data/nndc_hdf5/H1_71c.h5\n",
" Reading O16.71c from /home/romano/openmc/data/nndc_hdf5/O16_71c.h5\n",
" Reading U235.71c from /home/romano/openmc/data/nndc_hdf5/U235_71c.h5\n",
" Reading U238.71c from /home/romano/openmc/data/nndc_hdf5/U238_71c.h5\n",
" Reading Zr90.71c from /home/romano/openmc/data/nndc_hdf5/Zr90_71c.h5\n",
" Maximum neutron transport energy: 20.0000 MeV for H1.71c\n",
" Reading H1 from /home/romano/openmc/data/nndc_hdf5/H1.h5\n",
" Reading O16 from /home/romano/openmc/data/nndc_hdf5/O16.h5\n",
" Reading U235 from /home/romano/openmc/data/nndc_hdf5/U235.h5\n",
" Reading U238 from /home/romano/openmc/data/nndc_hdf5/U238.h5\n",
" Reading Zr90 from /home/romano/openmc/data/nndc_hdf5/Zr90.h5\n",
" Maximum neutron transport energy: 20.0000 MeV for H1\n",
" Reading tallies XML file...\n",
" Building neighboring cells lists for each surface...\n",
" Initializing source particles...\n",
@ -600,20 +613,20 @@
"\n",
" =======================> TIMING STATISTICS <=======================\n",
"\n",
" Total time for initialization = 3.2300E-01 seconds\n",
" Reading cross sections = 1.6900E-01 seconds\n",
" Total time in simulation = 1.9882E+01 seconds\n",
" Time in transport only = 1.9869E+01 seconds\n",
" Time in inactive batches = 2.6590E+00 seconds\n",
" Time in active batches = 1.7223E+01 seconds\n",
" Total time for initialization = 3.9900E-01 seconds\n",
" Reading cross sections = 2.6500E-01 seconds\n",
" Total time in simulation = 1.1488E+01 seconds\n",
" Time in transport only = 1.1152E+01 seconds\n",
" Time in inactive batches = 1.2180E+00 seconds\n",
" Time in active batches = 1.0270E+01 seconds\n",
" Time synchronizing fission bank = 4.0000E-03 seconds\n",
" Sampling source sites = 4.0000E-03 seconds\n",
" SEND/RECV source sites = 0.0000E+00 seconds\n",
" Sampling source sites = 3.0000E-03 seconds\n",
" SEND/RECV source sites = 1.0000E-03 seconds\n",
" Time accumulating tallies = 0.0000E+00 seconds\n",
" Total time for finalization = 0.0000E+00 seconds\n",
" Total time elapsed = 2.0217E+01 seconds\n",
" Calculation Rate (inactive) = 9402.03 neutrons/second\n",
" Calculation Rate (active) = 5806.19 neutrons/second\n",
" Total time for finalization = 1.0000E-03 seconds\n",
" Total time elapsed = 1.1901E+01 seconds\n",
" Calculation Rate (inactive) = 20525.5 neutrons/second\n",
" Calculation Rate (active) = 9737.10 neutrons/second\n",
"\n",
" ============================> RESULTS <============================\n",
"\n",
@ -894,7 +907,7 @@
" <td>6.250000e-07</td>\n",
" <td>total</td>\n",
" <td>(((total / flux) - (absorption / flux)) - (sca...</td>\n",
" <td>-3.774758e-15</td>\n",
" <td>-2.886580e-15</td>\n",
" <td>0.011292</td>\n",
" </tr>\n",
" <tr>\n",
@ -904,7 +917,7 @@
" <td>2.000000e+01</td>\n",
" <td>total</td>\n",
" <td>(((total / flux) - (absorption / flux)) - (sca...</td>\n",
" <td>1.443290e-15</td>\n",
" <td>-5.551115e-16</td>\n",
" <td>0.002570</td>\n",
" </tr>\n",
" </tbody>\n",
@ -917,8 +930,8 @@
"1 1 6.25e-07 2.00e+01 total \n",
"\n",
" score mean std. dev. \n",
"0 (((total / flux) - (absorption / flux)) - (sca... -3.77e-15 1.13e-02 \n",
"1 (((total / flux) - (absorption / flux)) - (sca... 1.44e-15 2.57e-03 "
"0 (((total / flux) - (absorption / flux)) - (sca... -2.89e-15 1.13e-02 \n",
"1 (((total / flux) - (absorption / flux)) - (sca... -5.55e-16 2.57e-03 "
]
},
"execution_count": 22,
@ -1167,21 +1180,21 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"display_name": "Python 3",
"language": "python",
"name": "python2"
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.11"
"pygments_lexer": "ipython3",
"version": "3.5.2"
}
},
"nbformat": 4,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -105,7 +105,6 @@
"source": [
"# Instantiate a Materials collection\n",
"materials_file = openmc.Materials((fuel, water, zircaloy))\n",
"materials_file.default_xs = '71c'\n",
"\n",
"# Export to \"materials.xml\"\n",
"materials_file.export_to_xml()"
@ -339,7 +338,7 @@
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///9yEhLpgJFNv8Tq\nQYT7AAAAAWJLR0QAiAUdSAAAAAd0SU1FB+AIHQwUARggawYAAALKSURBVGje7dpLcqQwDAbgHHE2\nYeEj+D4cwQucBUfo+3CEXoSp8OhuhF70T4qpKXmdr21LogK2Pj7A8QmNP+HDhw8fPnz48Kf6VH9G\n+66vy+je8k19jnf8C5dXIPv86ms56lPdjvaYbyodx3ze+XLE76cXFiD4zPji99z0/AJ4n1lfvJ6f\nnl0A6x+578efMSg1wPr172/jPO5yFXM+Ef78gdblM+WPHyguP//t1/g6pA0wfln+ho/fwgYYn19C\n/xwDvwHGc9OvC+hs37DTrwuwfWanXxdQTC9Mvyygs3wjTL8uwPJpn/tNDbSGz7T0SBEWw4vLXzbQ\n6b6RoveIoO6TvPxlA63qs7z8ZQPF9F+SH22vbX8OQKf5Rtv+EgDNJ3X58wZaxWd1+fMGiuFvir8b\nvjp8J/tGy/6jAmRvhW8fwL3vVT+o3grfPoB7r/IpALI3tz8FoJN84/NV873hB8UnM3xzANtf8nb4\ndwmg3grfFEDJO8JPE0i9Ff4pAYL3pI8mkHor/HMCeO9JH00g9SafEsh7T/ppARBvp48UwJnelT5S\nACd7O31TAlnvKx9SQCd7B58KgPO+8iMFuPWe9E8F8BveWX7bAjzX9y4//Jve+fhsH6Ctv7n8PTzj\nvY/v9gEOHz58+PBX+6v/f/wPvnd54f3j6venE/yl769Xv7+j3x/o98/V32/o9+fl389Xnx+g5x/o\n+Qt6/oOeP6HnX+j5G3z+h54/ouefV5/foufP6Pk3ev4On/+j9w/o/Qd6/4Le/6D3T/D9V67Y/ZsV\nQBq+s+8f0ftP+P41axXguP9NWgDuu/Cdfv+N3r/D9/9TAID+A7T/Ae2/gPs/0P4TtP8F7r9J3AIO\n9P+g/Udw/9Oygbf7r9D+L7j/DO1/Q/vv4P4/tP8Q7n9E+y/h/k+0/xTuf4X7b+H+X7T/+BPuf3aM\n8OHDhw8fPnz4w/4vzcvgeY10sY0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTYtMDgtMjlUMTI6MjA6\nMDEtMDQ6MDBSHRTRAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE2LTA4LTI5VDEyOjIwOjAxLTA0OjAw\nI0CsbQAAAABJRU5ErkJggg==\n",
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///9yEhLpgJFNv8Tq\nQYT7AAAAAWJLR0QAiAUdSAAAAAd0SU1FB+AJAwQmKDRX/78AAALKSURBVGje7dpLcqQwDAbgHHE2\nYeEj+D4cwQucBUfo+3CEXoSp8OhuhF70T4qpKXmdr21LogK2Pj7A8QmNP+HDhw8fPnz48Kf6VH9G\n+66vy+je8k19jnf8C5dXIPv86ms56lPdjvaYbyodx3ze+XLE76cXFiD4zPji99z0/AJ4n1lfvJ6f\nnl0A6x+578efMSg1wPr172/jPO5yFXM+Ef78gdblM+WPHyguP//t1/g6pA0wfln+ho/fwgYYn19C\n/xwDvwHGc9OvC+hs37DTrwuwfWanXxdQTC9Mvyygs3wjTL8uwPJpn/tNDbSGz7T0SBEWw4vLXzbQ\n6b6RoveIoO6TvPxlA63qs7z8ZQPF9F+SH22vbX8OQKf5Rtv+EgDNJ3X58wZaxWd1+fMGiuFvir8b\nvjp8J/tGy/6jAmRvhW8fwL3vVT+o3grfPoB7r/IpALI3tz8FoJN84/NV873hB8UnM3xzANtf8nb4\ndwmg3grfFEDJO8JPE0i9Ff4pAYL3pI8mkHor/HMCeO9JH00g9SafEsh7T/ppARBvp48UwJnelT5S\nACd7O31TAlnvKx9SQCd7B58KgPO+8iMFuPWe9E8F8BveWX7bAjzX9y4//Jve+fhsH6Ctv7n8PTzj\nvY/v9gEOHz58+PBX+6v/f/wPvnd54f3j6venE/yl769Xv7+j3x/o98/V32/o9+fl389Xnx+g5x/o\n+Qt6/oOeP6HnX+j5G3z+h54/ouefV5/foufP6Pk3ev4On/+j9w/o/Qd6/4Le/6D3T/D9V67Y/ZsV\nQBq+s+8f0ftP+P41axXguP9NWgDuu/Cdfv+N3r/D9/9TAID+A7T/Ae2/gPs/0P4TtP8F7r9J3AIO\n9P+g/Udw/9Oygbf7r9D+L7j/DO1/Q/vv4P4/tP8Q7n9E+y/h/k+0/xTuf4X7b+H+X7T/+BPuf3aM\n8OHDhw8fPnz4w/4vzcvgeY10sY0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTYtMDktMDNUMDQ6Mzg6\nNDAtMDQ6MDBo/hqzAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE2LTA5LTAzVDA0OjM4OjQwLTA0OjAw\nGaOiDwAAAABJRU5ErkJggg==\n",
"text/plain": [
"<IPython.core.display.Image object>"
]
@ -551,25 +550,39 @@
"name": "stdout",
"output_type": "stream",
"text": [
"rm: cannot remove 'statepoint.*': No such file or directory\n",
"\n",
" .d88888b. 888b d888 .d8888b.\n",
" d88P\" \"Y88b 8888b d8888 d88P Y88b\n",
" 888 888 88888b.d88888 888 888\n",
" 888 888 88888b. .d88b. 88888b. 888Y88888P888 888 \n",
" 888 888 888 \"88b d8P Y8b 888 \"88b 888 Y888P 888 888 \n",
" 888 888 888 888 88888888 888 888 888 Y8P 888 888 888\n",
" Y88b. .d88P 888 d88P Y8b. 888 888 888 \" 888 Y88b d88P\n",
" \"Y88888P\" 88888P\" \"Y8888 888 888 888 888 \"Y8888P\"\n",
"__________________888______________________________________________________\n",
" 888\n",
" 888\n",
" %%%%%%%%%%%%%%%\n",
" %%%%%%%%%%%%%%%%%%%%%%%%\n",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n",
" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n",
" %%%%%%%%%%%%%%%%%%%%%%%%\n",
" %%%%%%%%%%%%%%%%%%%%%%%%\n",
" ############### %%%%%%%%%%%%%%%%%%%%%%%%\n",
" ################## %%%%%%%%%%%%%%%%%%%%%%%\n",
" ################### %%%%%%%%%%%%%%%%%%%%%%%\n",
" #################### %%%%%%%%%%%%%%%%%%%%%%\n",
" ##################### %%%%%%%%%%%%%%%%%%%%%\n",
" ###################### %%%%%%%%%%%%%%%%%%%%\n",
" ####################### %%%%%%%%%%%%%%%%%%\n",
" ####################### %%%%%%%%%%%%%%%%%\n",
" ###################### %%%%%%%%%%%%%%%%%\n",
" #################### %%%%%%%%%%%%%%%%%\n",
" ################# %%%%%%%%%%%%%%%%%\n",
" ############### %%%%%%%%%%%%%%%%\n",
" ############ %%%%%%%%%%%%%%%\n",
" ######## %%%%%%%%%%%%%%\n",
" %%%%%%%%%%%\n",
"\n",
" 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: 26bdadd79aac3712450d8c0612ac3edcb68e720f\n",
" Date/Time: 2016-08-29 12:20:02\n",
" MPI Processes: 1\n",
" | The OpenMC Monte Carlo Code\n",
" 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 | 623b705a399f16c8e5063732bc6e6a357611542d\n",
" Date/Time | 2016-09-03 04:38:41\n",
" OpenMP Threads | 4\n",
"\n",
" ===========================================================================\n",
" ========================> INITIALIZATION <=========================\n",
@ -579,13 +592,13 @@
" Reading geometry XML file...\n",
" Reading cross sections XML file...\n",
" Reading materials XML file...\n",
" Reading U235.71c from /Users/sam/git/openmc-sam/data/nndc_hdf5/U235_71c.h5\n",
" Reading U238.71c from /Users/sam/git/openmc-sam/data/nndc_hdf5/U238_71c.h5\n",
" Reading O16.71c from /Users/sam/git/openmc-sam/data/nndc_hdf5/O16_71c.h5\n",
" Reading H1.71c from /Users/sam/git/openmc-sam/data/nndc_hdf5/H1_71c.h5\n",
" Reading B10.71c from /Users/sam/git/openmc-sam/data/nndc_hdf5/B10_71c.h5\n",
" Reading Zr90.71c from /Users/sam/git/openmc-sam/data/nndc_hdf5/Zr90_71c.h5\n",
" Maximum neutron transport energy: 20.0000 MeV for U235.71c\n",
" Reading U235 from /opt/xsdata/nndc_new/U235.h5\n",
" Reading U238 from /opt/xsdata/nndc_new/U238.h5\n",
" Reading O16 from /opt/xsdata/nndc_new/O16.h5\n",
" Reading H1 from /opt/xsdata/nndc_new/H1.h5\n",
" Reading B10 from /opt/xsdata/nndc_new/B10.h5\n",
" Reading Zr90 from /opt/xsdata/nndc_new/Zr90.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",
" Initializing source particles...\n",
@ -625,20 +638,20 @@
"\n",
" =======================> TIMING STATISTICS <=======================\n",
"\n",
" Total time for initialization = 4.6800E-01 seconds\n",
" Reading cross sections = 2.8200E-01 seconds\n",
" Total time in simulation = 1.8453E+01 seconds\n",
" Time in transport only = 1.8432E+01 seconds\n",
" Time in inactive batches = 2.5060E+00 seconds\n",
" Time in active batches = 1.5947E+01 seconds\n",
" Time synchronizing fission bank = 2.0000E-03 seconds\n",
" Sampling source sites = 0.0000E+00 seconds\n",
" SEND/RECV source sites = 1.0000E-03 seconds\n",
" Time accumulating tallies = 1.0000E-03 seconds\n",
" Total time for finalization = 3.0000E-03 seconds\n",
" Total time elapsed = 1.8947E+01 seconds\n",
" Calculation Rate (inactive) = 4988.03 neutrons/second\n",
" Calculation Rate (active) = 2351.54 neutrons/second\n",
" Total time for initialization = 3.8900E-01 seconds\n",
" Reading cross sections = 2.7000E-01 seconds\n",
" Total time in simulation = 4.6960E+00 seconds\n",
" Time in transport only = 4.6760E+00 seconds\n",
" Time in inactive batches = 6.6400E-01 seconds\n",
" Time in active batches = 4.0320E+00 seconds\n",
" Time synchronizing fission bank = 1.0000E-03 seconds\n",
" Sampling source sites = 1.0000E-03 seconds\n",
" SEND/RECV source sites = 0.0000E+00 seconds\n",
" Time accumulating tallies = 0.0000E+00 seconds\n",
" Total time for finalization = 1.0000E-03 seconds\n",
" Total time elapsed = 5.0960E+00 seconds\n",
" Calculation Rate (inactive) = 18825.3 neutrons/second\n",
" Calculation Rate (active) = 9300.60 neutrons/second\n",
"\n",
" ============================> RESULTS <============================\n",
"\n",
@ -1728,21 +1741,21 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"display_name": "Python 3",
"language": "python",
"name": "python2"
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.12"
"pygments_lexer": "ipython3",
"version": "3.5.2"
}
},
"nbformat": 4,

View file

@ -281,6 +281,8 @@ based on the recommended value in LA-UR-14-24530_.
.. note:: This element is not used in the multi-group :ref:`energy_mode`.
.. _multipole_library:
``<multipole_library>`` Element
-------------------------------
@ -290,8 +292,8 @@ OpenMC can use it for on-the-fly Doppler-broadening of resolved resonance range
cross sections. If this element is absent from the settings.xml file, the
:envvar:`OPENMC_MULTIPOLE_LIBRARY` environment variable will be used.
.. note:: The <use_windowed_multipole> element must also be set to "true"
for windowed multipole functionality.
.. note:: The :ref:`temperature_method` must also be set to "multipole" for
windowed multipole functionality.
``<max_order>`` Element
---------------------------
@ -395,19 +397,16 @@ attributes or sub-elements:
:scatterer:
An element with attributes/sub-elements called ``nuclide``, ``method``,
``xs_label``, ``xs_label_0K``, ``E_min``, and ``E_max``. The ``nuclide``
attribute is the name, as given by the ``name`` attribute within the
``nuclide`` sub-element of the ``material`` element in ``materials.xml``,
of the nuclide to which a resonance scattering treatment is to be applied.
``E_min``, and ``E_max``. The ``nuclide`` attribute is the name, as given
by the ``name`` attribute within the ``nuclide`` sub-element of the
``material`` element in ``materials.xml``, of the nuclide to which a
resonance scattering treatment is to be applied.
The ``method`` attribute gives the type of resonance scattering treatment
that is to be applied to the ``nuclide``. Acceptable inputs - none of
which are case-sensitive - for the ``method`` attribute are ``ARES``,
``CXS``, ``WCM``, and ``DBRC``. Descriptions of each of these methods
are documented here_. The ``xs_label`` attribute gives the label for the
cross section data of the ``nuclide`` at a given temperature. The
``xs_label_0K`` gives the label for the 0 K cross section data for the
``nuclide``. The ``E_min`` attribute gives the minimum energy above
which the ``method`` is applied. The ``E_max`` attribute gives the
are documented here_. The ``E_min`` attribute gives the minimum energy
above which the ``method`` is applied. The ``E_max`` attribute gives the
maximum energy below which the ``method`` is applied. One example would
be as follows:
@ -419,16 +418,12 @@ attributes or sub-elements:
<scatterer>
<nuclide>U-238</nuclide>
<method>ARES</method>
<xs_label>92238.72c</xs_label>
<xs_label_0K>92238.00c</xs_label_0K>
<E_min>5.0e-6</E_min>
<E_max>40.0e-6</E_max>
</scatterer>
<scatterer>
<nuclide>Pu-239</nuclide>
<method>dbrc</method>
<xs_label>94239.72c</xs_label>
<xs_label_0K>94239.00c</xs_label_0K>
<E_min>0.01e-6</E_min>
<E_max>210.0e-6</E_max>
</scatterer>
@ -714,6 +709,45 @@ survival biasing, otherwise known as implicit capture or absorption.
*Default*: false
.. _temperature_default:
``<temperature_default>`` Element
---------------------------------
The ``<temperature_default>`` element specifies a default temperature in Kelvin
that is to be applied to cells in the absence of an explicit cell temperature or
a material default temperature.
*Default*: 293.6 K
.. _temperature_method:
``<temperature_method>`` Element
--------------------------------
The ``<temperature_method>`` element has an accepted value of "nearest" or
"interpolation". A value of "nearest" indicates that for each cell, the nearest
temperature at which cross sections are given is to be applied, within a given
tolerance (see :ref:`temperature_tolerance`). A value of "multipole" indicates
that the windowed multipole method should be used to evaluate
temperature-dependent cross sections in the resolved resonance range (a
:ref:`windowed multipole library <multipole_library>` must also be available).
*Default*: "nearest"
.. _temperature_tolerance:
``<temperature_tolerance>`` Element
-----------------------------------
The ``<temperature_tolerance>`` element specifies a tolerance in Kelvin that is
to be applied when the "nearest" temperature method is used. For example, if a
cell temperature is 340 K and the tolerance is 15 K, then the closest
temperature in the range of 325 K to 355 K will be used to evaluate cross
sections.
*Default*: 10 K
``<threads>`` Element
---------------------
@ -1090,7 +1124,9 @@ Each ``<cell>`` element can have the following attributes or sub-elements:
specified for the "distributed temperature" feature. This will give each
unique instance of the cell its own temperature.
*Default*: The temperature of the coldest nuclide in the cell's material(s)
*Default*: If a material default temperature is supplied, it is used. In the
absence of a material default temperature, the :ref:`global default
temperature <temperature_default>` is used.
:rotation:
If the cell is filled with a universe, this element specifies the angles in
@ -1295,6 +1331,14 @@ Each ``material`` element can have the following attributes or sub-elements:
*Default*: ""
:temperature:
An element with no attributes which is used to set the default temperature
of the material in Kelvin.
*Default*: If a material default temperature is not given and a cell
temperature is not specified, the :ref:`global default temperature
<temperature_default>` is used.
:density:
An element with attributes/sub-elements called ``value`` and ``units``. The
``value`` attribute is the numeric value of the density while the ``units``
@ -1315,17 +1359,16 @@ Each ``material`` element can have the following attributes or sub-elements:
``nuclide``, ``element``, or ``sab`` quantity.
:nuclide:
An element with attributes/sub-elements called ``name``, ``xs``, and ``ao``
An element with attributes/sub-elements called ``name``, and ``ao``
or ``wo``. The ``name`` attribute is the name of the cross-section for a
desired nuclide while the ``xs`` attribute is the cross-section
identifier. Finally, the ``ao`` and ``wo`` attributes specify the atom or
desired nuclide. Finally, the ``ao`` and ``wo`` attributes specify the atom or
weight percent of that nuclide within the material, respectively. One
example would be as follows:
.. code-block:: xml
<nuclide name="H-1" xs="70c" ao="2.0" />
<nuclide name="O-16" xs="70c" ao="1.0" />
<nuclide name="H1" ao="2.0" />
<nuclide name="O16" ao="1.0" />
.. note:: If one nuclide is specified in atom percent, all others must also
be given in atom percent. The same applies for weight percentages.
@ -1349,11 +1392,10 @@ Each ``material`` element can have the following attributes or sub-elements:
Specifies that a natural element is present in the material. The natural
element is split up into individual isotopes based on `IUPAC Isotopic
Compositions of the Elements 2009`_. This element has
attributes/sub-elements called ``name``, ``xs``, and ``ao``. The ``name``
attribute is the atomic symbol of the element while the ``xs`` attribute is
the cross-section identifier. Finally, the ``ao`` attribute specifies the
atom percent of the element within the material, respectively. One example
would be as follows:
attributes/sub-elements called ``name``, and ``ao``. The ``name``
attribute is the atomic symbol of the element. Finally, the ``ao``
attribute specifies the atom percent of the element within the material,
respectively. One example would be as follows:
.. code-block:: xml
@ -1383,10 +1425,9 @@ Each ``material`` element can have the following attributes or sub-elements:
multi-group :ref:`energy_mode`.
:sab:
Associates an S(a,b) table with the material. This element has
attributes/sub-elements called ``name`` and ``xs``. The ``name`` attribute
is the name of the S(a,b) table that should be associated with the material,
and ``xs`` is the cross-section identifier for the table.
Associates an S(a,b) table with the material. This element has one
attribute/sub-element called ``name``. The ``name`` attribute
is the name of the S(a,b) table that should be associated with the material.
*Default*: None
@ -1397,14 +1438,13 @@ Each ``material`` element can have the following attributes or sub-elements:
recognizes that some multi-group libraries may be providing material
specific macroscopic cross sections instead of always providing nuclide
specific data like in the continuous-energy case. To that end, the
macroscopic element has attributes/sub-elements called ``name``, and ``xs``.
macroscopic element has one attribute/sub-element called ``name``.
The ``name`` attribute is the name of the cross-section for a
desired nuclide while the ``xs`` attribute is the cross-section
identifier. One example would be as follows:
desired nuclide. One example would be as follows:
.. code-block:: xml
<macroscopic name="UO2" xs="71c" />
<macroscopic name="UO2" />
.. note:: This element is only used in the multi-group :ref:`energy_mode`.
@ -1413,18 +1453,6 @@ Each ``material`` element can have the following attributes or sub-elements:
.. _IUPAC Isotopic Compositions of the Elements 2009:
http://pac.iupac.org/publications/pac/pdf/2011/pdf/8302x0397.pdf
``<default_xs>`` Element
------------------------
In some circumstances, the cross-section identifier may be the same for many or
all nuclides in a given problem. In this case, rather than specifying the
``xs=...`` attribute on every nuclide, a ``<default_xs>`` element can be used to
set the default cross-section identifier for any nuclide without an identifier
explicitly listed. This element has no attributes and accepts a 3-letter string
that indicates the default cross-section identifier, e.g. "70c".
*Default*: None
------------------------------------
Tallies Specification -- tallies.xml
------------------------------------

View file

@ -25,7 +25,7 @@ moderator = openmc.Material(material_id=41, name='moderator')
moderator.set_density('g/cc', 1.0)
moderator.add_nuclide(h1, 2.)
moderator.add_nuclide(o16, 1.)
moderator.add_s_alpha_beta('c_H_in_H2O', '71t')
moderator.add_s_alpha_beta('c_H_in_H2O')
fuel = openmc.Material(material_id=40, name='fuel')
fuel.set_density('g/cc', 4.5)
@ -33,7 +33,6 @@ fuel.add_nuclide(u235, 1.)
# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials([moderator, fuel])
materials_file.default_xs = '71c'
materials_file.export_to_xml()

View file

@ -34,11 +34,10 @@ moderator = openmc.Material(material_id=3, name='moderator')
moderator.set_density('g/cc', 1.0)
moderator.add_nuclide(h1, 2.)
moderator.add_nuclide(o16, 1.)
moderator.add_s_alpha_beta('c_H_in_H2O', '71t')
moderator.add_s_alpha_beta('c_H_in_H2O')
# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials([fuel1, fuel2, moderator])
materials_file.default_xs = '71c'
materials_file.export_to_xml()

View file

@ -29,7 +29,7 @@ moderator = openmc.Material(material_id=2, name='moderator')
moderator.set_density('g/cc', 1.0)
moderator.add_nuclide(h1, 2.)
moderator.add_nuclide(o16, 1.)
moderator.add_s_alpha_beta('c_H_in_H2O', '71t')
moderator.add_s_alpha_beta('c_H_in_H2O')
iron = openmc.Material(material_id=3, name='iron')
iron.set_density('g/cc', 7.9)
@ -37,7 +37,6 @@ iron.add_nuclide(fe56, 1.)
# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials([moderator, fuel, iron])
materials_file.default_xs = '71c'
materials_file.export_to_xml()

View file

@ -28,11 +28,10 @@ moderator = openmc.Material(material_id=2, name='moderator')
moderator.set_density('g/cc', 1.0)
moderator.add_nuclide(h1, 2.)
moderator.add_nuclide(o16, 1.)
moderator.add_s_alpha_beta('c_H_in_H2O', '71t')
moderator.add_s_alpha_beta('c_H_in_H2O')
# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials((moderator, fuel))
materials_file.default_xs = '71c'
materials_file.export_to_xml()

View file

@ -28,11 +28,10 @@ moderator = openmc.Material(material_id=2, name='moderator')
moderator.set_density('g/cc', 1.0)
moderator.add_nuclide(h1, 2.)
moderator.add_nuclide(o16, 1.)
moderator.add_s_alpha_beta('c_H_in_H2O', '71t')
moderator.add_s_alpha_beta('c_H_in_H2O')
# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials([moderator, fuel])
materials_file.default_xs = '71c'
materials_file.export_to_xml()

View file

@ -98,11 +98,10 @@ borated_water.add_nuclide(h1, 4.9457e-2)
borated_water.add_nuclide(h2, 7.4196e-6)
borated_water.add_nuclide(o16, 2.4672e-2)
borated_water.add_nuclide(o17, 6.0099e-5)
borated_water.add_s_alpha_beta('c_H_in_H2O', '71t')
borated_water.add_s_alpha_beta('c_H_in_H2O')
# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials([uo2, helium, zircaloy, borated_water])
materials_file.default_xs = '71c'
materials_file.export_to_xml()

View file

@ -19,7 +19,7 @@ groups = openmc.mgxs.EnergyGroups(group_edges=[1E-11, 0.0635E-6, 10.0E-6,
1.0E-4, 1.0E-3, 0.5, 1.0, 20.0])
# Instantiate the 7-group (C5G7) cross section data
uo2_xsdata = openmc.XSdata('UO2.300K', groups)
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]
@ -41,7 +41,7 @@ uo2_xsdata.nu_fission = [2.005998E-02, 2.027303E-03, 1.570599E-02,
uo2_xsdata.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.300K', groups)
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]
@ -66,8 +66,8 @@ mg_cross_sections_file.export_to_xml()
###############################################################################
# Instantiate some Macroscopic Data
uo2_data = openmc.Macroscopic('UO2', '300K')
h2o_data = openmc.Macroscopic('LWTR', '300K')
uo2_data = openmc.Macroscopic('UO2')
h2o_data = openmc.Macroscopic('LWTR')
# Instantiate some Materials and register the appropriate Macroscopic objects
uo2 = openmc.Material(material_id=1, name='UO2 fuel')
@ -80,7 +80,6 @@ water.add_macroscopic(h2o_data)
# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials([uo2, water])
materials_file.default_xs = '300K'
materials_file.export_to_xml()

View file

@ -25,7 +25,6 @@ fuel.add_nuclide(u235, 1.)
# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials([fuel])
materials_file.default_xs = '71c'
materials_file.export_to_xml()

View file

@ -1,8 +1,6 @@
<?xml version="1.0"?>
<materials>
<default_xs>71c</default_xs>
<material id="40">
<density value="4.5" units="g/cc" />
<nuclide name="U235" ao="1.0" />
@ -12,7 +10,7 @@
<density value="1.0" units="g/cc" />
<nuclide name="H1" ao="2.0" />
<nuclide name="O16" ao="1.0" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O"/>
</material>
</materials>

View file

@ -1,8 +1,6 @@
<?xml version="1.0"?>
<materials>
<default_xs>71c</default_xs>
<material id="1">
<density value="4.5" units="g/cc" />
<nuclide name="U235" ao="1.0" />
@ -17,7 +15,7 @@
<density value="1.0" units="g/cc" />
<nuclide name="O16" ao="1.0" />
<nuclide name="H1" ao="2.0" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
</materials>

View file

@ -1,8 +1,6 @@
<?xml version="1.0"?>
<materials>
<default_xs>71c</default_xs>
<!-- Definition of materials -->
<material id="1">
<density value="4.5" units="g/cc" />
@ -13,7 +11,7 @@
<density value="1.0" units="g/cc" />
<nuclide name="H1" ao="2.0" />
<nuclide name="O16" ao="1.0" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
</materials>

View file

@ -1,8 +1,6 @@
<?xml version="1.0"?>
<materials>
<default_xs>71c</default_xs>
<!-- Definition of materials -->
<material id="1">
<density value="4.5" units="g/cc" />
@ -13,7 +11,7 @@
<density value="1.0" units="g/cc" />
<nuclide name="H1" ao="2.0" />
<nuclide name="O16" ao="1.0" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
</materials>

View file

@ -1,9 +1,6 @@
<?xml version="1.0"?>
<materials>
<!-- By default, use 300K cross sections -->
<default_xs>71c</default_xs>
<!--
Since O-18 is not present in ENDF/B-VII, it was necessary to combine the
atom densities for O-17 and O-18 in any materials containing Oxygen.
@ -64,7 +61,7 @@
<nuclide name="H2" ao="7.4196e-06" />
<nuclide name="O16" ao="2.4672e-02" />
<nuclide name="O17" ao="6.0099e-05" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
</materials>

View file

@ -1,8 +1,5 @@
<?xml version="1.0"?>
<materials>
<!-- Set default xs set to use 300K data -->
<default_xs>300K</default_xs>
<!-- UO2 -->
<material id="1">
<density units="macro" value="1.0" />

View file

@ -11,8 +11,8 @@
-->
<xsdata>
<!-- Meta data for this data -->
<name>UO2.300K</name>
<alias>UO2.300K</alias>
<name>UO2</name>
<alias>UO2</alias>
<kT> 2.53E-8 </kT> <!-- in MeV -->
<order>0</order>
<fissionable>true</fissionable>
@ -67,8 +67,8 @@
<xsdata>
<!-- Meta data for this data -->
<name>MOX1.300K</name>
<alias>MOX1.300K</alias>
<name>MOX1</name>
<alias>MOX1</alias>
<kT> 2.53E-8 </kT> <!-- in MeV -->
<order>0</order>
<fissionable>true</fissionable>
@ -124,8 +124,8 @@
<xsdata>
<!-- Meta data for this data -->
<name>MOX2.300K</name>
<alias>MOX2.300K</alias>
<name>MOX2</name>
<alias>MOX2</alias>
<kT> 2.53E-8 </kT> <!-- in MeV -->
<order>0</order>
<fissionable>true</fissionable>
@ -180,8 +180,8 @@
<xsdata>
<!-- Meta data for this data -->
<name>MOX3.300K</name>
<alias>MOX3.300K</alias>
<name>MOX3</name>
<alias>MOX3</alias>
<kT> 2.53E-8 </kT> <!-- in MeV -->
<order>0</order>
<fissionable>true</fissionable>
@ -236,8 +236,8 @@
<xsdata>
<!-- Meta data for this data -->
<name>FC.300K</name>
<alias>FC.300K</alias>
<name>FC</name>
<alias>FC</alias>
<kT> 2.53E-8 </kT> <!-- in MeV -->
<order>0</order>
<fissionable>true</fissionable>
@ -286,8 +286,8 @@
<xsdata>
<!-- Meta data for this data -->
<name>GT.300K</name>
<alias>GT.300K</alias>
<name>GT</name>
<alias>GT</alias>
<kT> 2.53E-8 </kT> <!-- in MeV -->
<order>0</order>
<fissionable>false</fissionable>
@ -318,8 +318,8 @@
<xsdata>
<!-- Meta data for this data -->
<name>LWTR.300K</name>
<alias>LWTR.300K</alias>
<name>LWTR</name>
<alias>LWTR</alias>
<kT> 2.53E-8 </kT> <!-- in MeV -->
<order>0</order>
<fissionable>false</fissionable>
@ -351,8 +351,8 @@
<xsdata>
<!-- Meta data for this data -->
<name>CR.300K</name>
<alias>CR.300K</alias>
<name>CR</name>
<alias>CR</alias>
<kT> 2.53E-8 </kT> <!-- in MeV -->
<order>0</order>
<fissionable>false</fissionable>

View file

@ -1,8 +1,6 @@
<?xml version="1.0"?>
<materials>
<default_xs>71c</default_xs>
<material id="1">
<density value="4.5" units="g/cc" />
<nuclide name="U235" ao="1.0" />

View file

@ -218,3 +218,8 @@ def atomic_mass(isotope):
isotope = isotope[:isotope.find('_')]
return _ATOMIC_MASS.get(isotope.lower())
# The value of the Boltzman constant in units of MeV / K
# Values here are from the Committee on Data for Science and Technology
# (CODATA) 2010 recommendation (doi:10.1103/RevModPhys.84.1527).
K_BOLTZMANN = 8.6173324E-11

View file

@ -1,13 +1,14 @@
from __future__ import division, unicode_literals
import sys
from collections import OrderedDict, Iterable, Mapping
from collections import OrderedDict, Iterable, Mapping, MutableMapping
from itertools import chain
from numbers import Integral, Real
from warnings import warn
import numpy as np
import h5py
from .data import ATOMIC_SYMBOL, SUM_RULES
from .data import ATOMIC_SYMBOL, SUM_RULES, K_BOLTZMANN
from .ace import Table, get_table
from .fission_energy import FissionEnergyRelease
from .function import Tabulated1D, Sum
@ -21,6 +22,73 @@ 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.
Parameters
----------
zaid : int
ZAID (1000*Z + A) obtained from a library
metastable_scheme : {'nndc', 'mcnp'}
Determine how ZAID identifiers are to be interpreted in the case of
a metastable nuclide. Because the normal ZAID (=1000*Z + A) does not
encode metastable information, different conventions are used among
different libraries. In MCNP libraries, the convention is to add 400
for a metastable nuclide except for Am242m, for which 95242 is
metastable and 95642 (or 1095242 in newer libraries) is the ground
state. For NNDC libraries, ZAID is given as 1000*Z + A + 100*m.
Returns
-------
name : str
Name of the table
element : str
The atomic symbol of the isotope in the table; e.g., Zr.
Z : int
Number of protons in the nucleus
mass_number : int
Number of nucleons in the nucleus
metastable : int
Metastable state of the nucleus. A value of zero indicates ground state.
"""
cv.check_type('zaid', zaid, int)
cv.check_value('metastable_scheme', metastable_scheme, ['nndc', 'mcnp'])
Z = zaid // 1000
mass_number = zaid % 1000
if metastable_scheme == 'mcnp':
if zaid > 1000000:
# New SZA format
Z = Z % 1000
if zaid == 1095242:
metastable = 0
else:
metastable = zaid // 1000000
else:
if zaid == 95242:
metastable = 1
elif zaid == 95642:
metastable = 0
else:
metastable = 1 if mass_number > 300 else 0
elif metastable_scheme == 'nndc':
metastable = 1 if mass_number > 300 else 0
while mass_number > 3 * Z:
mass_number -= 100
# Determine name
element = ATOMIC_SYMBOL[Z]
name = '{}{}'.format(element, mass_number)
if metastable > 0:
name += '_m{}'.format(metastable)
return (name, element, Z, mass_number, metastable)
class IncidentNeutron(EqualityMixin):
"""Continuous-energy neutron interaction data.
@ -31,7 +99,7 @@ class IncidentNeutron(EqualityMixin):
Parameters
----------
name : str
Name of the table
Name of the nuclide using the GND naming convention
atomic_number : int
Number of protons in the nucleus
mass_number : int
@ -40,8 +108,9 @@ class IncidentNeutron(EqualityMixin):
Metastable state of the nucleus. A value of zero indicates ground state.
atomic_weight_ratio : float
Atomic mass ratio of the target nuclide.
temperature : float
Temperature of the target nuclide in MeV.
kTs : Iterable of float
List of temperatures of the target nuclide in the data set.
The temperatures have units of MeV.
Attributes
----------
@ -51,8 +120,10 @@ class IncidentNeutron(EqualityMixin):
Atomic symbol of the nuclide, e.g., 'Zr'
atomic_weight_ratio : float
Atomic weight ratio of the target nuclide.
energy : numpy.ndarray
energy : dict of numpy.ndarray
The energy values (MeV) at which reaction cross-sections are tabulated.
They keys of the dict are the temperature string ('294K') for each
set of energies
fission_energy : None or openmc.data.FissionEnergyRelease
The energy released by fission, tabulated by component (e.g. prompt
neutrons or beta particles) and dependent on incident neutron energy
@ -61,7 +132,7 @@ class IncidentNeutron(EqualityMixin):
metastable : int
Metastable state of the nucleus. A value of zero indicates ground state.
name : str
ZAID identifier of the table, e.g. 92235.70c.
Name of the nuclide using the GND naming convention
reactions : collections.OrderedDict
Contains the cross sections, secondary angle and energy distributions,
and other associated data for each reaction. The keys are the MT values
@ -69,27 +140,32 @@ class IncidentNeutron(EqualityMixin):
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.
temperature : float
Temperature of the target nuclide in MeV.
urr : None or openmc.data.ProbabilityTables
Unresolved resonance region probability tables
temperatures : list of str
List of string representations the temperatures of the target nuclide
in the data set. The temperatures are strings of the temperature,
rounded to the nearest integer; e.g., '294K'
kTs : Iterable of float
List of temperatures of the target nuclide in the data set.
The temperatures have units of MeV.
urr : dict
Dictionary whose keys are temperatures (e.g., '294K') and values are
unresolved resonance region probability tables.
"""
def __init__(self, name, atomic_number, mass_number, metastable,
atomic_weight_ratio, temperature):
atomic_weight_ratio, kTs):
self.name = name
self.atomic_number = atomic_number
self.mass_number = mass_number
self.metastable = metastable
self.atomic_weight_ratio = atomic_weight_ratio
self.temperature = temperature
self._energy = None
self.kTs = kTs
self.energy = {}
self._fission_energy = None
self.reactions = OrderedDict()
self.summed_reactions = OrderedDict()
self.urr = None
self._urr = {}
def __contains__(self, mt):
return mt in self.reactions or mt in self.summed_reactions
@ -128,18 +204,10 @@ class IncidentNeutron(EqualityMixin):
def atomic_weight_ratio(self):
return self._atomic_weight_ratio
@property
def energy(self):
return self._energy
@property
def fission_energy(self):
return self._fission_energy
@property
def temperature(self):
return self._temperature
@property
def reactions(self):
return self._reactions
@ -152,6 +220,10 @@ class IncidentNeutron(EqualityMixin):
def urr(self):
return self._urr
@property
def temperatures(self):
return ["{}K".format(int(round(kT / K_BOLTZMANN))) for kT in self.kTs]
@name.setter
def name(self, name):
cv.check_type('name', name, basestring)
@ -159,7 +231,7 @@ class IncidentNeutron(EqualityMixin):
@property
def atomic_symbol(self):
return atomic_symbol[self.atomic_number]
return ATOMIC_SYMBOL[self.atomic_number]
@atomic_number.setter
def atomic_number(self, atomic_number):
@ -185,17 +257,6 @@ class IncidentNeutron(EqualityMixin):
cv.check_greater_than('atomic weight ratio', atomic_weight_ratio, 0.0)
self._atomic_weight_ratio = atomic_weight_ratio
@temperature.setter
def temperature(self, temperature):
cv.check_type('temperature', temperature, Real)
cv.check_greater_than('temperature', temperature, 0.0, True)
self._temperature = temperature
@energy.setter
def energy(self, energy):
cv.check_type('energy grid', energy, Iterable, Real)
self._energy = energy
@fission_energy.setter
def fission_energy(self, fission_energy):
cv.check_type('fission energy release', fission_energy,
@ -214,10 +275,61 @@ class IncidentNeutron(EqualityMixin):
@urr.setter
def urr(self, urr):
cv.check_type('probability tables', urr,
(ProbabilityTables, type(None)))
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 tables', value, ProbabilityTables)
self._urr = urr
def add_temperature_from_ace(self, ace_or_filename, metastable_scheme='nndc'):
"""Append data from an ACE file at a different temperature.
Parameters
----------
ace_or_filename : openmc.data.ace.Table or str
ACE table to read from. If given as a string, it is assumed to be
the filename for the ACE file.
metastable_scheme : {'nndc', 'mcnp'}
Determine how ZAID identifiers are to be interpreted in the case of
a metastable nuclide. Because the normal ZAID (=1000*Z + A) does not
encode metastable information, different conventions are used among
different libraries. In MCNP libraries, the convention is to add 400
for a metastable nuclide except for Am242m, for which 95242 is
metastable and 95642 (or 1095242 in newer libraries) is the ground
state. For NNDC libraries, ZAID is given as 1000*Z + A + 100*m.
"""
data = IncidentNeutron.from_ace(ace_or_filename, metastable_scheme)
# Check if temprature already exists
strT = data.temperatures[0]
if strT in self.temperatures:
warn('Cross sections at T={} already exist.'.format(strT))
return
# Check that name matches
if data.name != self.name:
raise ValueError('Data provided for an incorrect nuclide.')
# Add temperature
self.kTs += data.kTs
# Add energy grid
self.energy[strT] = data.energy[strT]
# Add normal and summed reactions
for mt in chain(data.reactions, data.summed_reactions):
if mt not in self:
raise ValueError("Tried to add cross sections for MT={} at T={}"
" but this reaction doesn't exist.".format(
mt, strT))
self[mt].xs[strT] = data[mt].xs[strT]
# Add probability tables
if strT in data.urr:
self.urr[strT] = data.urr[strT]
def get_reaction_components(self, mt):
"""Determine what reactions make up summed reaction.
@ -271,10 +383,14 @@ class IncidentNeutron(EqualityMixin):
g.attrs['A'] = self.mass_number
g.attrs['metastable'] = self.metastable
g.attrs['atomic_weight_ratio'] = self.atomic_weight_ratio
g.attrs['temperature'] = self.temperature
ktg = g.create_group('kTs')
for i, temperature in enumerate(self.temperatures):
ktg.create_dataset(temperature, data=self.kTs[i])
# Write energy grid
g.create_dataset('energy', data=self.energy)
eg = g.create_group('energy')
for temperature in self.temperatures:
eg.create_dataset(temperature, data=self.energy[temperature])
# Write reaction data
rxs_group = g.create_group('reactions')
@ -288,9 +404,11 @@ class IncidentNeutron(EqualityMixin):
rx.derived_products[0].to_hdf5(tgroup)
# Write unresolved resonance probability tables
if self.urr is not None:
if self.urr:
urr_group = g.create_group('urr')
self.urr.to_hdf5(urr_group)
for temperature, urr in self.urr.items():
tgroup = urr_group.create_group(temperature)
urr.to_hdf5(tgroup)
# Write fission energy release data
if self.fission_energy is not None:
@ -327,13 +445,18 @@ class IncidentNeutron(EqualityMixin):
mass_number = group.attrs['A']
metastable = group.attrs['metastable']
atomic_weight_ratio = group.attrs['atomic_weight_ratio']
temperature = group.attrs['temperature']
kTg = group['kTs']
kTs = []
for temp in kTg:
kTs.append(kTg[temp].value)
data = cls(name, atomic_number, mass_number, metastable,
atomic_weight_ratio, temperature)
atomic_weight_ratio, kTs)
# Read energy grid
data.energy = group['energy'].value
e_group = group['energy']
for temperature, dset in e_group.items():
data.energy[temperature] = dset.value
# Read reaction data
rxs_group = group['reactions']
@ -347,21 +470,21 @@ class IncidentNeutron(EqualityMixin):
tgroup = group['total_nu']
rx.derived_products.append(Product.from_hdf5(tgroup))
# Build summed reactions. Start from the highest MT number because high
# MTs never depend on lower MTs.
# Build summed reactions. Start from the highest MT number because
# high MTs never depend on lower MTs.
for mt_sum in sorted(SUM_RULES, reverse=True):
if mt_sum not in data:
xs_components = [data[mt].xs for mt in SUM_RULES[mt_sum]
if mt in data]
if len(xs_components) > 0:
rxn = Reaction(mt_sum)
rxn.xs = Sum(xs_components)
data.summed_reactions[mt_sum] = rxn
rxs = [data[mt] for mt in SUM_RULES[mt_sum] if mt in data]
if len(rxs) > 0:
data.summed_reactions[mt_sum] = rx = Reaction(mt_sum)
for T in data.temperatures:
rx.xs[T] = Sum([rx.xs[T] for rx in rxs])
# Read unresolved resonance probability tables
if 'urr' in group:
urr_group = group['urr']
data.urr = ProbabilityTables.from_hdf5(urr_group)
for temperature, tgroup in urr_group.items():
data.urr[temperature] = ProbabilityTables.from_hdf5(tgroup)
# Read fission energy release data
if 'fission_energy_release' in group:
@ -376,9 +499,9 @@ class IncidentNeutron(EqualityMixin):
Parameters
----------
ace : openmc.data.ace.Table or str
ACE table to read from. If given as a string, it is assumed to be
the filename for the ACE file.
ace_or_filename : openmc.data.ace.Table or str
ACE table to read from. If the value is a string, it is assumed to
be the filename for the ACE file.
metastable_scheme : {'nndc', 'mcnp'}
Determine how ZAID identifiers are to be interpreted in the case of
a metastable nuclide. Because the normal ZAID (=1000*Z + A) does not
@ -394,6 +517,8 @@ class IncidentNeutron(EqualityMixin):
Incident neutron continuous-energy data
"""
# First obtain the data for the first provided ACE table/file
if isinstance(ace_or_filename, Table):
ace = ace_or_filename
else:
@ -401,55 +526,35 @@ class IncidentNeutron(EqualityMixin):
# If mass number hasn't been specified, make an educated guess
zaid, xs = ace.name.split('.')
zaid = int(zaid)
Z = zaid // 1000
mass_number = zaid % 1000
name, element, Z, mass_number, metastable = \
_get_metadata(int(zaid), metastable_scheme)
if metastable_scheme == 'mcnp':
if zaid > 1000000:
# New SZA format
Z = Z % 1000
if zaid == 1095242:
metastable = 0
else:
metastable = zaid // 1000000
else:
if zaid == 95242:
metastable = 1
elif zaid == 95642:
metastable = 0
else:
metastable = 1 if mass_number > 300 else 0
elif metastable_scheme == 'nndc':
metastable = 1 if mass_number > 300 else 0
while mass_number > 3*Z:
mass_number -= 100
# Determine name for group
element = ATOMIC_SYMBOL[Z]
if metastable > 0:
name = '{}{}_m{}.{}'.format(element, mass_number, metastable, xs)
else:
name = '{}{}.{}'.format(element, mass_number, xs)
# Assign temperature to the running list
kTs = [ace.temperature]
data = cls(name, Z, mass_number, metastable,
ace.atomic_weight_ratio, ace.temperature)
ace.atomic_weight_ratio, kTs)
# Get string of temperature to use as a dictionary key
strT = data.temperatures[0]
# Read energy grid
n_energy = ace.nxs[3]
energy = ace.xss[ace.jxs[1]:ace.jxs[1] + n_energy]
data.energy = energy
total_xs = ace.xss[ace.jxs[1] + n_energy:ace.jxs[1] + 2*n_energy]
absorption_xs = ace.xss[ace.jxs[1] + 2*n_energy:ace.jxs[1] + 3*n_energy]
data.energy[strT] = energy
total_xs = ace.xss[ace.jxs[1] + n_energy:ace.jxs[1] + 2 * n_energy]
absorption_xs = ace.xss[ace.jxs[1] + 2 * n_energy:ace.jxs[1] +
3 * n_energy]
# Create summed reactions (total and absorption)
total = Reaction(1)
total.xs = Tabulated1D(energy, total_xs)
total.xs[strT] = Tabulated1D(energy, total_xs)
data.summed_reactions[1] = total
absorption = Reaction(27)
absorption.xs = Tabulated1D(energy, absorption_xs)
data.summed_reactions[27] = absorption
if np.count_nonzero(absorption_xs) > 0:
absorption = Reaction(27)
absorption.xs[strT] = Tabulated1D(energy, absorption_xs)
data.summed_reactions[27] = absorption
# Read each reaction
n_reaction = ace.nxs[4] + 1
@ -478,13 +583,16 @@ class IncidentNeutron(EqualityMixin):
warn('Photon production is present for MT={} but no '
'reaction components exist.'.format(mt))
continue
rx.xs = Sum([data.reactions[mt_i].xs for mt_i in mts])
rx.xs[strT] = Sum([data.reactions[mt_i].xs[strT]
for mt_i in mts])
# Determine summed cross section
rx.products += _get_photon_products(ace, rx)
data.summed_reactions[mt] = rx
# Read unresolved resonance probability tables
data.urr = ProbabilityTables.from_ace(ace)
urr = ProbabilityTables.from_ace(ace)
if urr is not None:
data.urr[strT] = urr
return data

View file

@ -1,7 +1,7 @@
from __future__ import division, unicode_literals
from collections import Iterable, Callable
from collections import Iterable, Callable, MutableMapping
from copy import deepcopy
from numbers import Real
from numbers import Real, Integral
from warnings import warn
import numpy as np
@ -11,8 +11,8 @@ from openmc.mixin import EqualityMixin
from openmc.stats import Uniform
from .angle_distribution import AngleDistribution
from .angle_energy import AngleEnergy
from .function import Tabulated1D, Polynomial
from .data import REACTION_NAME
from .function import Tabulated1D, Polynomial, Function1D
from .data import REACTION_NAME, K_BOLTZMANN
from .product import Product
from .uncorrelated import UncorrelatedAngleEnergy
@ -211,7 +211,7 @@ def _get_photon_products(ace, rx):
# Get photon production cross section
photon_prod_xs = ace.xss[idx + 2:idx + 2 + n_energy]
neutron_xs = rx.xs(energy)
neutron_xs = list(rx.xs.values())[0](energy)
idx = np.where(neutron_xs > 0.)
# Calculate photon yield
@ -261,8 +261,7 @@ class Reaction(EqualityMixin):
Parameters
----------
mt : int
The ENDF MT number for this reaction. On occasion, MCNP uses MT numbers
that don't correspond exactly to the ENDF specification.
The ENDF MT number for this reaction.
Attributes
----------
@ -274,16 +273,12 @@ class Reaction(EqualityMixin):
The ENDF MT number for this reaction.
q_value : float
The Q-value of this reaction in MeV.
table : openmc.data.ace.Table
The ACE table which contains this reaction.
threshold : float
Threshold of the reaction in MeV
threshold_idx : int
The index on the energy grid corresponding to the threshold of this
reaction.
xs : callable
xs : dict of str to openmc.data.Function1D
Microscopic cross section for this reaction as a function of incident
energy
energy; these cross sections are provided in a dictionary where the key
is the temperature of the cross section set.
products : Iterable of openmc.data.Product
Reaction products
derived_products : Iterable of openmc.data.Product
@ -293,13 +288,13 @@ class Reaction(EqualityMixin):
"""
def __init__(self, mt):
self.center_of_mass = True
self._center_of_mass = True
self._q_value = 0.
self._xs = {}
self._products = []
self._derived_products = []
self.mt = mt
self.q_value = 0.
self.threshold_idx = 0
self._xs = None
self.products = []
self.derived_products = []
def __repr__(self):
if self.mt in REACTION_NAME:
@ -320,8 +315,8 @@ class Reaction(EqualityMixin):
return self._products
@property
def threshold(self):
return self.xs.x[0]
def derived_products(self):
return self._derived_products
@property
def xs(self):
@ -342,12 +337,18 @@ class Reaction(EqualityMixin):
cv.check_type('reaction products', products, Iterable, Product)
self._products = products
@derived_products.setter
def derived_products(self, derived_products):
cv.check_type('reaction derived products', derived_products,
Iterable, Product)
self._derived_products = derived_products
@xs.setter
def xs(self, xs):
cv.check_type('reaction cross section', xs, Callable)
if isinstance(xs, Tabulated1D):
for y in xs.y:
cv.check_greater_than('reaction cross section', y, 0.0, True)
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)
self._xs = xs
def to_hdf5(self, group):
@ -366,10 +367,16 @@ class Reaction(EqualityMixin):
else:
group.attrs['label'] = np.string_(self.mt)
group.attrs['Q_value'] = self.q_value
group.attrs['threshold_idx'] = self.threshold_idx + 1
group.attrs['center_of_mass'] = 1 if self.center_of_mass else 0
if self.xs is not None:
group.create_dataset('xs', data=self.xs.y)
for T in self.xs:
Tgroup = group.create_group(T)
if self.xs[T] is not None:
dset = Tgroup.create_dataset('xs', data=self.xs[T].y)
if hasattr(self.xs[T], '_threshold_idx'):
threshold_idx = self.xs[T]._threshold_idx + 1
else:
threshold_idx = 1
dset.attrs['threshold_idx'] = threshold_idx
for i, p in enumerate(self.products):
pgroup = group.create_group('product_{}'.format(i))
p.to_hdf5(pgroup)
@ -382,8 +389,9 @@ class Reaction(EqualityMixin):
----------
group : h5py.Group
HDF5 group to write to
energy : Iterable of float
Array of energies at which cross sections are tabulated at
energy : dict
Dictionary whose keys are temperatures (e.g., '300K') and values are
arrays of energies at which cross sections are tabulated at.
Returns
-------
@ -391,16 +399,27 @@ class Reaction(EqualityMixin):
Reaction data
"""
mt = group.attrs['mt']
rx = cls(mt)
rx.q_value = group.attrs['Q_value']
rx.threshold_idx = group.attrs['threshold_idx'] - 1
rx.center_of_mass = bool(group.attrs['center_of_mass'])
# Read cross section
if 'xs' in group:
xs = group['xs'].value
rx.xs = Tabulated1D(energy[rx.threshold_idx:], xs)
# Read cross section at each temperature
for T, Tgroup in group.items():
if T.endswith('K'):
if 'xs' in Tgroup:
# Make sure temperature has associated energy grid
if T not in energy:
raise ValueError(
'Could not create reaction cross section for MT={} '
'at T={} because no corresponding energy grid '
'exists.'.format(mt, T))
xs = Tgroup['xs'].value
threshold_idx = Tgroup['xs'].attrs['threshold_idx'] - 1
tabulated_xs = Tabulated1D(energy[T][threshold_idx:], xs)
tabulated_xs._threshold_idx = threshold_idx
rx.xs[T] = tabulated_xs
# Determine number of products
n_product = 0
@ -421,6 +440,10 @@ class Reaction(EqualityMixin):
n_grid = ace.nxs[3]
grid = ace.xss[ace.jxs[1]:ace.jxs[1] + n_grid]
# Convert data temperature to a "300.0K" number for indexing
# temperature data
strT = str(int(round(ace.temperature / K_BOLTZMANN))) + "K"
if i_reaction > 0:
mt = int(ace.xss[ace.jxs[3] + i_reaction - 1])
rx = cls(mt)
@ -435,11 +458,11 @@ class Reaction(EqualityMixin):
loc = int(ace.xss[ace.jxs[6] + i_reaction - 1])
# Determine starting index on energy grid
rx.threshold_idx = int(ace.xss[ace.jxs[7] + loc - 1]) - 1
threshold_idx = int(ace.xss[ace.jxs[7] + loc - 1]) - 1
# Determine number of energies in reaction
n_energy = int(ace.xss[ace.jxs[7] + loc])
energy = grid[rx.threshold_idx:rx.threshold_idx + n_energy]
energy = grid[threshold_idx:threshold_idx + n_energy]
# Read reaction cross section
xs = ace.xss[ace.jxs[7] + loc + 1:ace.jxs[7] + loc + 1 + n_energy]
@ -450,7 +473,9 @@ class Reaction(EqualityMixin):
"to zero.".format(rx.mt, ace.name))
xs[xs < 0.0] = 0.0
rx.xs = Tabulated1D(energy, xs)
tabulated_xs = Tabulated1D(energy, xs)
tabulated_xs._threshold_idx = threshold_idx
rx.xs[strT] = tabulated_xs
# ==================================================================
# YIELD AND ANGLE-ENERGY DISTRIBUTION
@ -509,7 +534,9 @@ class Reaction(EqualityMixin):
"Setting to zero.".format(ace.name))
elastic_xs[elastic_xs < 0.0] = 0.0
rx.xs = Tabulated1D(grid, elastic_xs)
tabulated_xs = Tabulated1D(grid, elastic_xs)
tabulated_xs._threshold_idx = 0
rx.xs[strT] = tabulated_xs
# No energy distribution for elastic scattering
neutron = Product('neutron')

View file

@ -8,6 +8,7 @@ import h5py
import openmc.checkvalue as cv
from openmc.mixin import EqualityMixin
from .data import K_BOLTZMANN, ATOMIC_SYMBOL
from .ace import Table, get_table
from .angle_energy import AngleEnergy
from .function import Tabulated1D
@ -89,8 +90,7 @@ class CoherentElastic(EqualityMixin):
if isinstance(E, Iterable):
E = np.asarray(E)
idx = np.searchsorted(self.bragg_edges, E)
return self.factors[idx]/E
return self.factors[idx] / E
def __len__(self):
return len(self.bragg_edges)
@ -156,11 +156,12 @@ class ThermalScattering(EqualityMixin):
Parameters
----------
name : str
ZAID identifier of the table, e.g. lwtr.10t.
Name of the material using GND convention, e.g. c_H_in_H2O
atomic_weight_ratio : float
Atomic mass ratio of the target nuclide.
temperature : float
Temperature of the target nuclide in eV.
kTs : Iterable of float
List of temperatures of the target nuclide in the data set.
The temperatures have units of MeV.
Attributes
----------
@ -173,25 +174,33 @@ class ThermalScattering(EqualityMixin):
Inelastic scattering cross section derived in the incoherent
approximation
name : str
Name of the table, e.g. lwtr.20t.
temperature : float
Temperature of the target nuclide in eV.
zaids : Iterable of int
ZAID identifiers that the thermal scattering data applies to
Name of the material using GND convention, e.g. c_H_in_H2O
temperatures : Iterable of str
List of string representations the temperatures of the target nuclide
in the data set. The temperatures are strings of the temperature,
rounded to the nearest integer; e.g., '294K'
kTs : Iterable of float
List of temperatures of the target nuclide in the data set.
The temperatures have units of MeV.
nuclides : Iterable of str
Nuclide names that the thermal scattering data applies to
"""
def __init__(self, name, atomic_weight_ratio, temperature):
def __init__(self, name, atomic_weight_ratio, kTs):
self.name = name
self.atomic_weight_ratio = atomic_weight_ratio
self.temperature = temperature
self.elastic_xs = None
self.elastic_mu_out = None
self.inelastic_xs = None
self.inelastic_e_out = None
self.inelastic_mu_out = None
self.kTs = kTs
self.temperatures = [str(int(round(kT / K_BOLTZMANN))) + "K"
for kT in kTs]
self.elastic_xs = {}
self.elastic_mu_out = {}
self.inelastic_xs = {}
self.inelastic_e_out = {}
self.inelastic_mu_out = {}
self.inelastic_dist = {}
self.secondary_mode = None
self.zaids = []
self.nuclides = []
def __repr__(self):
if hasattr(self, 'name'):
@ -217,26 +226,193 @@ class ThermalScattering(EqualityMixin):
# Write basic data
g = f.create_group(self.name)
g.attrs['atomic_weight_ratio'] = self.atomic_weight_ratio
g.attrs['temperature'] = self.temperature
g.attrs['zaids'] = self.zaids
g.attrs['nuclides'] = np.array(self.nuclides, dtype='S')
g.attrs['secondary_mode'] = np.string_(self.secondary_mode)
ktg = g.create_group('kTs')
for i, temperature in enumerate(self.temperatures):
ktg.create_dataset(temperature, data=self.kTs[i])
# Write thermal elastic scattering
if self.elastic_xs is not None:
elastic_group = g.create_group('elastic')
self.elastic_xs.to_hdf5(elastic_group, 'xs')
if self.elastic_mu_out is not None:
elastic_group.create_dataset('mu_out', data=self.elastic_mu_out)
for T in self.temperatures:
Tg = g.create_group(T)
# Write thermal elastic scattering
if self.elastic_xs:
elastic_group = Tg.create_group('elastic')
# Write thermal inelastic scattering
if self.inelastic_xs is not None:
inelastic_group = g.create_group('inelastic')
self.inelastic_xs.to_hdf5(inelastic_group, 'xs')
inelastic_group.attrs['secondary_mode'] = np.string_(self.secondary_mode)
if self.secondary_mode in ('equal', 'skewed'):
inelastic_group.create_dataset('energy_out', data=self.inelastic_e_out)
inelastic_group.create_dataset('mu_out', data=self.inelastic_mu_out)
elif self.secondary_mode == 'continuous':
self.inelastic_dist.to_hdf5(inelastic_group)
self.elastic_xs[T].to_hdf5(elastic_group, 'xs')
if self.elastic_mu_out:
elastic_group.create_dataset('mu_out',
data=self.elastic_mu_out[T])
# Write thermal inelastic scattering
if self.inelastic_xs:
inelastic_group = Tg.create_group('inelastic')
self.inelastic_xs[T].to_hdf5(inelastic_group, 'xs')
if self.secondary_mode in ('equal', 'skewed'):
inelastic_group.create_dataset('energy_out',
data=self.inelastic_e_out[T])
inelastic_group.create_dataset('mu_out',
data=self.inelastic_mu_out[T])
elif self.secondary_mode == 'continuous':
self.inelastic_dist[T].to_hdf5(inelastic_group)
f.close()
def add_temperature_from_ace(self, ace_or_filename, name=None):
"""Add data to the ThermalScattering object from an ACE file at a
different temperature.
Parameters
----------
ace_or_filename : openmc.data.ace.Table or str
ACE table to read from. If given as a string, it is assumed to be
the filename for the ACE file.
name : str
GND-conforming name of the material, e.g. c_H_in_H2O. If none is
passed, the appropriate name is guessed based on the name of the ACE
table.
Returns
-------
openmc.data.ThermalScattering
Thermal scattering data
"""
if isinstance(ace_or_filename, Table):
ace = ace_or_filename
else:
ace = get_table(ace_or_filename)
# Get new name that is GND-consistent
ace_name, xs = ace.name.split('.')
if name is None:
if ace_name.lower() in _THERMAL_NAMES:
name = _THERMAL_NAMES[ace_name.lower()]
else:
# Make an educated guess? This actually works well for JEFF-3.2
# which stupidly uses names like lw00.32t, lw01.32t, etc. for
# different temperatures
matches = get_close_matches(
ace_name.lower(), _THERMAL_NAMES.keys(), cutoff=0.5)
if len(matches) > 0:
name = _THERMAL_NAMES[matches[0]]
else:
# OK, we give up. Just use the ACE name.
name = 'c_' + ace.name
warn('Thermal scattering material "{}" is not recognized. '
'Assigning a name of {}.'.format(ace.name, name))
# If this ACE data matches the data within self then get the data
if ace.temperature not in self.kTs:
if name == self.name:
# Add temperature and kTs
strT = str(int(round(ace.temperature / K_BOLTZMANN))) + "K"
self.temperatures.append(strT)
self.kTs.append(ace.temperature)
# Incoherent inelastic scattering cross section
idx = ace.jxs[1]
n_energy = int(ace.xss[idx])
energy = ace.xss[idx + 1: idx + 1 + n_energy]
xs = ace.xss[idx + 1 + n_energy: idx + 1 + 2 * n_energy]
self.inelastic_xs[strT] = Tabulated1D(energy, xs)
# Make sure secondary_mode is always equal. This should always
# be the case, but to reduce future debugging should something
# change, this will alert the developers to the issue.
if ace.nxs[7] == 0:
secondary_mode = 'equal'
elif ace.nxs[7] == 1:
secondary_mode = 'skewed'
elif ace.nxs[7] == 2:
secondary_mode = 'continuous'
if secondary_mode != self.secondary_mode:
raise ValueError('Secondary Modes are inconsistent.')
n_energy_out = ace.nxs[4]
if self.secondary_mode in ('equal', 'skewed'):
n_mu = ace.nxs[3]
idx = ace.jxs[3]
self.inelastic_e_out[strT] = \
ace.xss[idx:idx + n_energy * n_energy_out * (n_mu + 2):
n_mu + 2]
self.inelastic_e_out[strT].shape = \
(n_energy, n_energy_out)
self.inelastic_mu_out[strT] = \
ace.xss[idx:idx + n_energy * n_energy_out * (n_mu + 2)]
self.inelastic_mu_out[strT].shape = \
(n_energy, n_energy_out, n_mu + 2)
self.inelastic_mu_out[strT] = \
self.inelastic_mu_out[strT][:, :, 1:]
else:
n_mu = ace.nxs[3] - 1
idx = ace.jxs[3]
locc = ace.xss[idx:idx + n_energy].astype(int)
n_energy_out = \
ace.xss[idx + n_energy:idx + 2 * n_energy].astype(int)
energy_out = []
mu_out = []
for i in range(n_energy):
idx = locc[i]
# Outgoing energy distribution for incoming energy i
e = ace.xss[idx + 1:idx + 1 + n_energy_out[i]*(n_mu + 3):
n_mu + 3]
p = ace.xss[idx + 2:idx + 2 + n_energy_out[i]*(n_mu + 3):
n_mu + 3]
c = ace.xss[idx + 3:idx + 3 + n_energy_out[i]*(n_mu + 3):
n_mu + 3]
eout_i = Tabular(e, p, 'linear-linear', ignore_negative=True)
eout_i.c = c
# Outgoing angle distribution for each
# (incoming, outgoing) energy pair
mu_i = []
for j in range(n_energy_out[i]):
mu = ace.xss[idx + 4:idx + 4 + n_mu]
p_mu = 1. / n_mu * np.ones(n_mu)
mu_ij = Discrete(mu, p_mu)
mu_ij.c = np.cumsum(p_mu)
mu_i.append(mu_ij)
idx += 3 + n_mu
energy_out.append(eout_i)
mu_out.append(mu_i)
# Create correlated angle-energy distribution
breakpoints = [n_energy]
interpolation = [2]
energy = self.inelastic_xs[strT].x
self.inelastic_dist[strT] = CorrelatedAngleEnergy(
breakpoints, interpolation, energy, energy_out, mu_out)
# Incoherent/coherent elastic scattering cross section
idx = ace.jxs[4]
if idx != 0:
n_energy = int(ace.xss[idx])
energy = ace.xss[idx + 1: idx + 1 + n_energy]
P = ace.xss[idx + 1 + n_energy: idx + 1 + 2 * n_energy]
if ace.nxs[5] == 4:
self.elastic_xs[strT] = CoherentElastic(energy, P)
else:
self.elastic_xs[strT] = Tabulated1D(energy, P)
# Angular distribution
n_mu = ace.nxs[6]
if n_mu != -1:
idx = ace.jxs[6]
self.elastic_mu_out[strT] = \
ace.xss[idx:idx + n_energy * n_mu]
self.elastic_mu_out[strT].shape = \
(n_energy, n_mu)
else:
raise ValueError('Data provided for an incorrect library')
else:
raise Warning('Temperature data set already within '
'IncidentNeutron object')
@classmethod
def from_hdf5(cls, group_or_filename):
@ -263,35 +439,49 @@ class ThermalScattering(EqualityMixin):
name = group.name[1:]
atomic_weight_ratio = group.attrs['atomic_weight_ratio']
temperature = group.attrs['temperature']
table = cls(name, atomic_weight_ratio, temperature)
table.zaids = group.attrs['zaids']
kTg = group['kTs']
kTs = []
for temp in kTg:
kTs.append(kTg[temp].value)
temperatures = [str(int(round(kT / K_BOLTZMANN))) + "K" for kT in kTs]
table = cls(name, atomic_weight_ratio, kTs)
table.nuclides = [nuc.decode() for nuc in group.attrs['nuclides']]
table.secondary_mode = group.attrs['secondary_mode'].decode()
# Read thermal elastic scattering
if 'elastic' in group:
elastic_group = group['elastic']
for T in temperatures:
Tgroup = group[T]
if 'elastic' in Tgroup:
elastic_group = Tgroup['elastic']
# Cross section
elastic_xs_type = elastic_group['xs'].attrs['type'].decode()
if elastic_xs_type == 'tab1':
table.elastic_xs = Tabulated1D.from_hdf5(elastic_group['xs'])
elif elastic_xs_type == 'bragg':
table.elastic_xs = CoherentElastic.from_hdf5(elastic_group['xs'])
# Cross section
elastic_xs_type = elastic_group['xs'].attrs['type'].decode()
if elastic_xs_type == 'Tabulated1D':
table.elastic_xs[T] = \
Tabulated1D.from_hdf5(elastic_group['xs'])
elif elastic_xs_type == 'bragg':
table.elastic_xs[T] = \
CoherentElastic.from_hdf5(elastic_group['xs'])
# Angular distribution
if 'mu_out' in elastic_group:
table.elastic_mu_out = elastic_group['mu_out'].value
# Angular distribution
if 'mu_out' in elastic_group:
table.elastic_mu_out[T] = \
elastic_group['mu_out'].value
# Read thermal inelastic scattering
if 'inelastic' in group:
inelastic_group = group['inelastic']
table.secondary_mode = inelastic_group.attrs['secondary_mode'].decode()
table.inelastic_xs = Tabulated1D.from_hdf5(inelastic_group['xs'])
if table.secondary_mode in ('equal', 'skewed'):
table.inelastic_e_out = inelastic_group['energy_out']
table.inelastic_mu_out = inelastic_group['mu_out']
elif table.secondary_mode == 'continuous':
table.inelastic_dist = AngleEnergy.from_hdf5(inelastic_group)
# Read thermal inelastic scattering
if 'inelastic' in Tgroup:
inelastic_group = Tgroup['inelastic']
table.inelastic_xs[T] = \
Tabulated1D.from_hdf5(inelastic_group['xs'])
if table.secondary_mode in ('equal', 'skewed'):
table.inelastic_e_out[T] = \
inelastic_group['energy_out']
table.inelastic_mu_out[T] = \
inelastic_group['mu_out']
elif table.secondary_mode == 'continuous':
table.inelastic_dist[T] = \
AngleEnergy.from_hdf5(inelastic_group)
return table
@ -301,7 +491,7 @@ class ThermalScattering(EqualityMixin):
Parameters
----------
ace : openmc.data.ace.Table or str
ace_or_filename : openmc.data.ace.Table or str
ACE table to read from. If given as a string, it is assumed to be
the filename for the ACE file.
name : str
@ -324,7 +514,7 @@ class ThermalScattering(EqualityMixin):
ace_name, xs = ace.name.split('.')
if name is None:
if ace_name.lower() in _THERMAL_NAMES:
name = _THERMAL_NAMES[ace_name.lower()] + '.' + xs
name = _THERMAL_NAMES[ace_name.lower()]
else:
# Make an educated guess?? This actually works well for JEFF-3.2
# which stupidly uses names like lw00.32t, lw01.32t, etc. for
@ -332,21 +522,25 @@ class ThermalScattering(EqualityMixin):
matches = get_close_matches(
ace_name.lower(), _THERMAL_NAMES.keys(), cutoff=0.5)
if len(matches) > 0:
name = _THERMAL_NAMES[matches[0]] + '.' + xs
name = _THERMAL_NAMES[matches[0]]
else:
# OK, we give up. Just use the ACE name.
name = 'c_' + ace.name
warn('Thermal scattering material "{}" is not recognized. '
'Assigning a name of {}.'.format(ace.name, name))
table = cls(name, ace.atomic_weight_ratio, ace.temperature)
# Assign temperature to the running list
kTs = [ace.temperature]
temperatures = [str(int(round(ace.temperature / K_BOLTZMANN))) + "K"]
table = cls(name, ace.atomic_weight_ratio, kTs)
# Incoherent inelastic scattering cross section
idx = ace.jxs[1]
n_energy = int(ace.xss[idx])
energy = ace.xss[idx+1 : idx+1+n_energy]
xs = ace.xss[idx+1+n_energy : idx+1+2*n_energy]
table.inelastic_xs = Tabulated1D(energy, xs)
table.inelastic_xs[temperatures[0]] = Tabulated1D(energy, xs)
if ace.nxs[7] == 0:
table.secondary_mode = 'equal'
@ -359,34 +553,45 @@ class ThermalScattering(EqualityMixin):
if table.secondary_mode in ('equal', 'skewed'):
n_mu = ace.nxs[3]
idx = ace.jxs[3]
table.inelastic_e_out = ace.xss[idx:idx+n_energy*n_energy_out*(n_mu+2):n_mu+2]
table.inelastic_e_out.shape = (n_energy, n_energy_out)
table.inelastic_e_out[temperatures[0]] = \
ace.xss[idx:idx + n_energy * n_energy_out * (n_mu + 2):
n_mu + 2]
table.inelastic_e_out[temperatures[0]].shape = \
(n_energy, n_energy_out)
table.inelastic_mu_out = ace.xss[idx:idx+n_energy*n_energy_out*(n_mu+2)]
table.inelastic_mu_out.shape = (n_energy, n_energy_out, n_mu+2)
table.inelastic_mu_out = table.inelastic_mu_out[:, :, 1:]
table.inelastic_mu_out[temperatures[0]] = \
ace.xss[idx:idx + n_energy * n_energy_out * (n_mu + 2)]
table.inelastic_mu_out[temperatures[0]].shape = \
(n_energy, n_energy_out, n_mu+2)
table.inelastic_mu_out[temperatures[0]] = \
table.inelastic_mu_out[temperatures[0]][:, :, 1:]
else:
n_mu = ace.nxs[3] - 1
idx = ace.jxs[3]
locc = ace.xss[idx:idx + n_energy].astype(int)
n_energy_out = ace.xss[idx + n_energy:idx + 2*n_energy].astype(int)
n_energy_out = \
ace.xss[idx + n_energy:idx + 2 * n_energy].astype(int)
energy_out = []
mu_out = []
for i in range(n_energy):
idx = locc[i]
# Outgoing energy distribution for incoming energy i
e = ace.xss[idx + 1:idx + 1 + n_energy_out[i]*(n_mu + 3):n_mu + 3]
p = ace.xss[idx + 2:idx + 2 + n_energy_out[i]*(n_mu + 3):n_mu + 3]
c = ace.xss[idx + 3:idx + 3 + n_energy_out[i]*(n_mu + 3):n_mu + 3]
e = ace.xss[idx + 1:idx + 1 + n_energy_out[i]*(n_mu + 3):
n_mu + 3]
p = ace.xss[idx + 2:idx + 2 + n_energy_out[i]*(n_mu + 3):
n_mu + 3]
c = ace.xss[idx + 3:idx + 3 + n_energy_out[i]*(n_mu + 3):
n_mu + 3]
eout_i = Tabular(e, p, 'linear-linear', ignore_negative=True)
eout_i.c = c
# Outgoing angle distribution for each (incoming, outgoing) energy pair
# Outgoing angle distribution for each
# (incoming, outgoing) energy pair
mu_i = []
for j in range(n_energy_out[i]):
mu = ace.xss[idx + 4:idx + 4 + n_mu]
p_mu = 1./n_mu*np.ones(n_mu)
p_mu = 1. / n_mu * np.ones(n_mu)
mu_ij = Discrete(mu, p_mu)
mu_ij.c = np.cumsum(p_mu)
mu_i.append(mu_ij)
@ -398,31 +603,35 @@ class ThermalScattering(EqualityMixin):
# Create correlated angle-energy distribution
breakpoints = [n_energy]
interpolation = [2]
energy = table.inelastic_xs.x
table.inelastic_dist = CorrelatedAngleEnergy(
energy = table.inelastic_xs[temperatures[0]].x
table.inelastic_dist[temperatures[0]] = CorrelatedAngleEnergy(
breakpoints, interpolation, energy, energy_out, mu_out)
# Incoherent/coherent elastic scattering cross section
idx = ace.jxs[4]
if idx != 0:
n_energy = int(ace.xss[idx])
energy = ace.xss[idx+1 : idx+1+n_energy]
P = ace.xss[idx+1+n_energy : idx+1+2*n_energy]
energy = ace.xss[idx + 1: idx + 1 + n_energy]
P = ace.xss[idx + 1 + n_energy: idx + 1 + 2 * n_energy]
if ace.nxs[5] == 4:
table.elastic_xs = CoherentElastic(energy, P)
table.elastic_xs[temperatures[0]] = CoherentElastic(energy, P)
else:
table.elastic_xs = Tabulated1D(energy, P)
table.elastic_xs[temperatures[0]] = Tabulated1D(energy, P)
# Angular distribution
n_mu = ace.nxs[6]
if n_mu != -1:
idx = ace.jxs[6]
table.elastic_mu_out = ace.xss[idx:idx + n_energy*n_mu]
table.elastic_mu_out.shape = (n_energy, n_mu)
table.elastic_mu_out[temperatures[0]] = \
ace.xss[idx:idx + n_energy * n_mu]
table.elastic_mu_out[temperatures[0]].shape = \
(n_energy, n_mu)
# Get relevant ZAIDs
pairs = np.fromiter(map(lambda p: p[0], ace.pairs), int)
table.zaids = pairs[np.nonzero(pairs)]
# Get relevant nuclides
for zaid, awr in ace.pairs:
if zaid > 0:
Z, A = divmod(zaid, 1000)
table.nuclides.append(ATOMIC_SYMBOL[Z] + str(A))
return table

View file

@ -19,38 +19,28 @@ class Element(object):
----------
name : str
Chemical symbol of the element, e.g. Pu
xs : str
Cross section identifier, e.g. 71c
Attributes
----------
name : str
Chemical symbol of the element, e.g. Pu
xs : str
Cross section identifier, e.g. 71c
scattering : {'data', 'iso-in-lab', None}
The type of angular scattering distribution to use
"""
def __init__(self, name='', xs=None):
def __init__(self, name=''):
# Initialize class attributes
self._name = ''
self._xs = None
self._scattering = None
# Set class attributes
self.name = name
if xs is not None:
self.xs = xs
def __eq__(self, other):
if isinstance(other, Element):
if self.name != other.name:
return False
elif self.xs != other.xs:
return False
else:
return True
elif isinstance(other, basestring) and other == self.name:
@ -72,17 +62,12 @@ class Element(object):
def __repr__(self):
string = 'Element - {0}\n'.format(self._name)
string += '{0: <16}{1}{2}\n'.format('\tXS', '=\t', self._xs)
if self.scattering is not None:
string += '{0: <16}{1}{2}\n'.format('\tscattering', '=\t',
self.scattering)
return string
@property
def xs(self):
return self._xs
@property
def name(self):
return self._name
@ -91,11 +76,6 @@ class Element(object):
def scattering(self):
return self._scattering
@xs.setter
def xs(self, xs):
check_type('cross section identifier', xs, basestring)
self._xs = xs
@name.setter
def name(self, name):
check_type('element name', name, basestring)
@ -127,6 +107,6 @@ class Element(object):
isotopes = []
for isotope, abundance in sorted(NATURAL_ABUNDANCE.items()):
if re.match(r'{}\d+'.format(self.name), isotope):
nuc = openmc.Nuclide(isotope, self.xs)
nuc = openmc.Nuclide(isotope)
isotopes.append((nuc, abundance))
return isotopes

View file

@ -13,35 +13,25 @@ class Macroscopic(object):
----------
name : str
Name of the macroscopic data, e.g. UO2
xs : str
Cross section identifier, e.g. 71c
Attributes
----------
name : str
Name of the nuclide, e.g. UO2
xs : str
Cross section identifier, e.g. 71c
"""
def __init__(self, name='', xs=None):
def __init__(self, name=''):
# Initialize class attributes
self._name = ''
self._xs = None
# Set the Macroscopic class attributes
self.name = name
if xs is not None:
self.xs = xs
def __eq__(self, other):
if isinstance(other, Macroscopic):
if self.name != other.name:
return False
elif self.xs != other.xs:
return False
else:
return True
elif isinstance(other, basestring) and other == self.name:
@ -53,27 +43,17 @@ class Macroscopic(object):
return not self == other
def __hash__(self):
return hash((self._name, self._xs))
return hash((self._name))
def __repr__(self):
string = 'Nuclide - {0}\n'.format(self._name)
string += '{0: <16}{1}{2}\n'.format('\tXS', '=\t', self._xs)
return string
@property
def name(self):
return self._name
@property
def xs(self):
return self._xs
@name.setter
def name(self, name):
check_type('name', name, basestring)
self._name = name
@xs.setter
def xs(self, xs):
check_type('cross-section identifier', xs, basestring)
self._xs = xs

View file

@ -41,11 +41,19 @@ class Material(object):
name : str, optional
Name of the material. If not specified, the name will be the empty
string.
temperature : str, optional
The temperature identifier applied to this material. The units are
in Kelvin and the temperature rounded to the nearest integer.
For example, a tempreature of 293.6K would be provided as '294K'
Attributes
----------
id : int
Unique identifier for the material
temperature : str
The temperature identifier applied to this material. The units are
in Kelvin and the temperature rounded to the nearest integer.
For example, a tempreature of 293.6K would be provided as '294K'
density : float
Density of the material (units defined separately)
density_units : str
@ -63,10 +71,11 @@ class Material(object):
"""
def __init__(self, material_id=None, name=''):
def __init__(self, material_id=None, name='', temperature=None):
# Initialize class attributes
self.id = material_id
self.name = name
self.temperature = temperature
self._density = None
self._density_units = ''
@ -80,7 +89,7 @@ class Material(object):
# A list of tuples (element, percent, percent type)
self._elements = []
# If specified, a list of tuples of (table name, xs identifier)
# If specified, a list of table names
self._sab = []
# If true, the material will be initialized as distributed
@ -120,6 +129,8 @@ class Material(object):
string = 'Material\n'
string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id)
string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name)
string += '{0: <16}{1}{2}\n'.format('\Temperature', '=\t',
self._temperature)
string += '{0: <16}{1}{2}'.format('\tDensity', '=\t', self._density)
string += ' [{0}]\n'.format(self._density_units)
@ -127,13 +138,12 @@ class Material(object):
string += '{0: <16}\n'.format('\tS(a,b) Tables')
for sab in self._sab:
string += '{0: <16}{1}[{2}{3}]\n'.format('\tS(a,b)', '=\t',
sab[0], sab[1])
string += '{0: <16}{1}{2}\n'.format('\tS(a,b)', '=\t', sab)
string += '{0: <16}\n'.format('\tNuclides')
for nuclide, percent, percent_type in self._nuclides:
string += '{0: <16}'.format('\t{0.name}.{0.xs}'.format(nuclide))
string += '{0: <16}'.format('\t{0.name}'.format(nuclide))
string += '=\t{0: <12} [{1}]\n'.format(percent, percent_type)
if self._macroscopic is not None:
@ -143,7 +153,7 @@ class Material(object):
string += '{0: <16}\n'.format('\tElements')
for element, percent, percent_type in self._elements:
string += '{0: <16}'.format('\t{0.name}.{0.xs}'.format(element))
string += '{0: <16}'.format('\t{0.name}'.format(element))
string += '=\t{0: <12} [{1}]\n'.format(percent, percent_type)
return string
@ -156,6 +166,10 @@ class Material(object):
def name(self):
return self._name
@property
def temperature(self):
return self._temperature
@property
def density(self):
return self._density
@ -201,6 +215,15 @@ class Material(object):
else:
self._name = ''
@temperature.setter
def temperature(self, temperature):
if temperature is not None:
cv.check_type('Temperature for Material ID="{0}"'.format(self._id),
temperature, basestring)
self._temperature = temperature
else:
self._temperature = ''
def set_density(self, units, density=None):
"""Set the density of the material
@ -458,15 +481,13 @@ class Material(object):
if element == elm:
self._nuclides.remove(elm)
def add_s_alpha_beta(self, name, xs):
def add_s_alpha_beta(self, name):
r"""Add an :math:`S(\alpha,\beta)` table to the material
Parameters
----------
name : str
Name of the :math:`S(\alpha,\beta)` table
xs : str
Cross section identifier, e.g. '71t'
"""
@ -480,18 +501,14 @@ class Material(object):
'non-string table name "{1}"'.format(self._id, name)
raise ValueError(msg)
if not isinstance(xs, basestring):
msg = 'Unable to add an S(a,b) table to Material ID="{0}" with a ' \
'non-string cross-section identifier "{1}"'.format(self._id, xs)
raise ValueError(msg)
new_name = openmc.data.get_thermal_name(name)
if new_name != name:
msg = 'OpenMC S(a,b) tables follow the GND naming convention. ' \
'Table "{}" is being renamed as "{}".'.format(name, new_name)
warnings.warn(msg)
self._sab.append((new_name, xs))
self._sab.append(new_name)
def make_isotropic_in_lab(self):
for nuclide, percent, percent_type in self._nuclides:
@ -554,9 +571,6 @@ class Material(object):
else:
xml_element.set("wo", str(nuclide[1]))
if nuclide[0].xs is not None:
xml_element.set("xs", nuclide[0].xs)
if not nuclide[0].scattering is None:
xml_element.set("scattering", nuclide[0].scattering)
@ -566,9 +580,6 @@ class Material(object):
xml_element = ET.Element("macroscopic")
xml_element.set("name", macroscopic.name)
if macroscopic.xs is not None:
xml_element.set("xs", macroscopic.xs)
return xml_element
def _get_element_xml(self, element, distrib=False):
@ -581,9 +592,6 @@ class Material(object):
else:
xml_element.set("wo", str(element[1]))
if element[0].xs is not None:
xml_element.set("xs", element[0].xs)
if not element[0].scattering is None:
xml_element.set("scattering", element[0].scattering)
@ -622,6 +630,11 @@ class Material(object):
if len(self._name) > 0:
element.set("name", str(self._name))
# Create temperature XML subelement
if len(self.temperature) > 0:
subelement = ET.SubElement(element, "temperature")
subelement.text = self.temperature
# Create density XML subelement
subelement = ET.SubElement(element, "density")
if self._density_units is not 'sum':
@ -686,8 +699,7 @@ class Material(object):
if len(self._sab) > 0:
for sab in self._sab:
subelement = ET.SubElement(element, "sab")
subelement.set("name", sab[0])
subelement.set("xs", sab[1])
subelement.set("name", sab)
return element
@ -712,30 +724,14 @@ class Materials(cv.CheckedList):
materials : Iterable of openmc.Material
Materials to add to the collection
Attributes
----------
default_xs : str
The default cross section identifier applied to a nuclide when none is
specified
"""
def __init__(self, materials=None):
super(Materials, self).__init__(Material, 'materials collection')
self._default_xs = None
self._materials_file = ET.Element("materials")
if materials is not None:
self += materials
@property
def default_xs(self):
return self._default_xs
@default_xs.setter
def default_xs(self, xs):
cv.check_type('default xs', xs, basestring)
self._default_xs = xs
def add_material(self, material):
"""Append material to collection
@ -817,10 +813,6 @@ class Materials(cv.CheckedList):
material.make_isotropic_in_lab()
def _create_material_subelements(self):
if self._default_xs is not None:
subelement = ET.SubElement(self._materials_file, "default_xs")
subelement.text = self._default_xs
for material in self:
xml_element = material.get_material_xml()
self._materials_file.append(xml_element)

View file

@ -822,8 +822,8 @@ class Library(object):
return pickle.load(open(full_filename, 'rb'))
def get_xsdata(self, domain, xsdata_name, nuclide='total', xs_type='macro',
xs_id='1m', order=None, tabular_legendre=None,
tabular_points=33, subdomain=None):
order=None, tabular_legendre=None, tabular_points=33,
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).
@ -841,8 +841,6 @@ class Library(object):
Provide the macro or micro cross section in units of cm^-1 or
barns. Defaults to 'macro'. If the Library object is not tallied by
nuclide this will be set to 'macro' regardless.
xs_ids : str
Cross section set identifier. Defaults to '1m'.
order : int
Scattering order for this data entry. Default is None,
which will set the XSdata object to use the order of the
@ -888,7 +886,6 @@ class Library(object):
cv.check_type('xsdata_name', xsdata_name, basestring)
cv.check_type('nuclide', nuclide, basestring)
cv.check_value('xs_type', xs_type, ['macro', 'micro'])
cv.check_type('xs_id', xs_id, basestring)
cv.check_type('order', order, (type(None), Integral))
if order is not None:
cv.check_greater_than('order', order, 0, equality=True)
@ -915,7 +912,6 @@ class Library(object):
name = xsdata_name
if nuclide is not 'total':
name += '_' + nuclide
name += '.' + xs_id
xsdata = openmc.XSdata(name, self.energy_groups)
if order is None:
@ -1022,8 +1018,7 @@ class Library(object):
return xsdata
def create_mg_library(self, xs_type='macro', xsdata_names=None,
xs_ids=None, tabular_legendre=None,
tabular_points=33):
tabular_legendre=None, tabular_points=33):
"""Creates an openmc.MGXSLibrary object to contain the MGXS data for the
Multi-Group mode of OpenMC.
@ -1036,10 +1031,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', ...
xs_ids : str or Iterable of str
Cross section set identifier (i.e., '71c') for all
data sets (if only str) or for each individual one
(if iterable of str). Defaults to '1m'.
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
@ -1087,26 +1078,6 @@ class Library(object):
# Initialize file
mgxs_file = openmc.MGXSLibrary(self.energy_groups)
# Get the number of domains to size arrays with
if self.domain_type is 'mesh':
num_domains = np.sum(d.num_mesh_cells for d in self.domains)
else:
num_domains = len(self.domains)
# Set id names
if xs_ids is not None:
if isinstance(xs_ids, basestring):
# If we only have a string lets convert it now to a list
# of strings.
all_xs_ids = [xs_ids] * num_domains
else:
cv.check_iterable_type('xs_ids', xs_ids, basestring)
cv.check_length('xs_ids', xs_ids, num_domains, num_domains)
all_xs_ids = xs_ids
else:
all_xs_ids = ['1m'] * num_domains
if self.domain_type == 'mesh':
# Create the xsdata objects and add to the mgxs_file
i = 0
@ -1123,7 +1094,6 @@ class Library(object):
# Create XSdata and Macroscopic for this domain
xsdata = self.get_xsdata(domain, xsdata_name,
xs_id=all_xs_ids[i],
tabular_legendre=tabular_legendre,
tabular_points=tabular_points,
subdomain=subdomain)
@ -1148,7 +1118,6 @@ class Library(object):
xsdata = self.get_xsdata(domain, xsdata_name,
nuclide=nuclide, xs_type=xs_type,
xs_id=all_xs_ids[i],
tabular_legendre=tabular_legendre,
tabular_points=tabular_points)
@ -1156,9 +1125,8 @@ class Library(object):
return mgxs_file
def create_mg_mode(self, xsdata_names=None, xs_ids=None,
tabular_legendre=None, tabular_points=33,
bc=['reflective'] * 6):
def create_mg_mode(self, xsdata_names=None, tabular_legendre=None,
tabular_points=33, 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
@ -1172,10 +1140,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', ...
xs_ids : str or Iterable of str
Cross section set identifier (i.e., '71c') for all
data sets (if only str) or for each individual one
(if iterable of str). Defaults to '1m'.
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
@ -1234,7 +1198,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, xs_ids,
mgxs_file = self.create_mg_library('macro', xsdata_names,
tabular_legendre, tabular_points)
# Now move on the creating the geometry and assigning materials
@ -1251,10 +1215,10 @@ class Library(object):
for i, subdomain in enumerate(self.domains[0].cell_generator()):
xsdata = mgxs_file.xsdatas[i]
[name, id] = xsdata.name.split('.')
# Build the macroscopic and assign it to the cell of
# interest
macroscopic = openmc.Macroscopic(name=name, xs=id)
macroscopic = openmc.Macroscopic(name=xsdata.name)
# Create Material and add to collection
material = openmc.Material(name=xsdata.name)
@ -1275,9 +1239,8 @@ class Library(object):
# Create the xsdata object and add it to the mgxs_file
for i, domain in enumerate(self.domains):
xsdata = mgxs_file.xsdatas[i]
[name, id] = xsdata.name.split('.')
macroscopic = openmc.Macroscopic(name=name, xs=id)
macroscopic = openmc.Macroscopic(name=xsdata.name)
# Create Material and add to collection
material = openmc.Material(name=xsdata.name)

View file

@ -99,9 +99,6 @@ class XSdata(object):
Unique identifier for the xsdata object
alias : str
Separate unique identifier for the xsdata object
zaid : int
1000*(atomic number) + mass number. As an example, the zaid of U235
would be 92235.
awr : float
Atomic weight ratio of an isotope. That is, the ratio of the mass
of the isotope to the mass of a single neutron.
@ -227,7 +224,6 @@ class XSdata(object):
self._energy_groups = energy_groups
self._representation = representation
self._alias = None
self._zaid = None
self._awr = None
self._kT = None
self._fissionable = False
@ -262,10 +258,6 @@ class XSdata(object):
def alias(self):
return self._alias
@property
def zaid(self):
return self._zaid
@property
def awr(self):
return self._awr
@ -396,13 +388,6 @@ class XSdata(object):
else:
self._alias = self._name
@zaid.setter
def zaid(self, zaid):
# Check type and value
check_type('zaid', zaid, Integral)
check_greater_than('zaid', zaid, 0)
self._zaid = zaid
@awr.setter
def awr(self, awr):
# Check validity of type and that the awr value is > 0
@ -1013,18 +998,10 @@ class XSdata(object):
subelement = ET.SubElement(element, 'kT')
subelement.text = str(self._kT)
if self._zaid is not None:
subelement = ET.SubElement(element, 'zaid')
subelement.text = str(self._zaid)
if self._awr is not None:
subelement = ET.SubElement(element, 'awr')
subelement.text = str(self._awr)
if self._kT is not None:
subelement = ET.SubElement(element, 'kT')
subelement.text = str(self._kT)
if self._fissionable is not None:
subelement = ET.SubElement(element, 'fissionable')
subelement.text = str(self._fissionable)

View file

@ -15,42 +15,28 @@ class Nuclide(object):
----------
name : str
Name of the nuclide, e.g. U235
xs : str
Cross section identifier, e.g. 71c
Attributes
----------
name : str
Name of the nuclide, e.g. U235
xs : str
Cross section identifier, e.g. 71c
zaid : int
1000*(atomic number) + mass number. As an example, the zaid of U235
would be 92235.
scattering : 'data' or 'iso-in-lab' or None
The type of angular scattering distribution to use
"""
def __init__(self, name='', xs=None):
def __init__(self, name=''):
# Initialize class attributes
self._name = ''
self._xs = None
self._zaid = None
self._scattering = None
# Set the Material class attributes
self.name = name
if xs is not None:
self.xs = xs
def __eq__(self, other):
if isinstance(other, Nuclide):
if self.name != other.name:
return False
elif self.xs != other.xs:
return False
else:
return True
elif isinstance(other, basestring) and other == self.name:
@ -72,9 +58,6 @@ class Nuclide(object):
def __repr__(self):
string = 'Nuclide - {0}\n'.format(self._name)
string += '{0: <16}{1}{2}\n'.format('\tXS', '=\t', self.xs)
if self.zaid is not None:
string += '{0: <16}{1}{2}\n'.format('\tZAID', '=\t', self.zaid)
if self.scattering is not None:
string += '{0: <16}{1}{2}\n'.format('\tscattering', '=\t',
self.scattering)
@ -84,14 +67,6 @@ class Nuclide(object):
def name(self):
return self._name
@property
def xs(self):
return self._xs
@property
def zaid(self):
return self._zaid
@property
def scattering(self):
return self._scattering
@ -111,19 +86,8 @@ class Nuclide(object):
'"{}" is being renamed as "{}".'.format(name, self._name)
warnings.warn(msg)
@xs.setter
def xs(self, xs):
check_type('cross-section identifier', xs, basestring)
self._xs = xs
@zaid.setter
def zaid(self, zaid):
check_type('zaid', zaid, Integral)
self._zaid = zaid
@scattering.setter
def scattering(self, scattering):
if not scattering in ['data', 'iso-in-lab']:
msg = 'Unable to set scattering for Nuclide to {0} ' \
'which is not "data" or "iso-in-lab"'.format(scattering)

View file

@ -1,4 +1,4 @@
from collections import Iterable, MutableSequence
from collections import Iterable, MutableSequence, Mapping
from numbers import Real, Integral
import warnings
from xml.etree import ElementTree as ET
@ -78,8 +78,6 @@ class Settings(object):
cross section library. If it is not set, the
:envvar:`OPENMC_MULTIPOLE_LIBRARY` environment variable will be used. A
multipole library is optional.
energy_grid : {'nuclide', 'logarithm', 'material-union'}
Set the method used to search energy grids.
energy_mode : {'continuous-energy', 'multi-group'}
Set whether the calculation should be continuous-energy or multi-group.
max_order : int
@ -103,6 +101,14 @@ 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
temperature : dict
Defines a default temperature and method for treating intermediate
temperatures at which nuclear data doesn't exist. Accepted keys are
'default', 'method', and 'tolerance'. The value for 'default' should be
a float representing the default temperature in Kelvin. The value for
'method' should be 'nearest' or 'multipole'. If the method is
'nearest', 'tolerance' indicates a range of temperature within which
cross sections may be used.
trigger_active : bool
Indicate whether tally triggers are used
trigger_max_batches : int
@ -130,9 +136,6 @@ class Settings(object):
Coordinates of the lower-left point of the UFS mesh
ufs_upper_right : tuple or list
Coordinates of the upper-right point of the UFS mesh
use_windowed_multipole : bool
Whether or not windowed multipole can be used to evaluate resolved
resonance cross sections.
resonance_scattering : ResonanceScattering or iterable of ResonanceScattering
The elastic scattering model to use for resonant isotopes
volume_calculations : VolumeCalculation or iterable of VolumeCalculation
@ -160,7 +163,6 @@ class Settings(object):
self._confidence_intervals = None
self._cross_sections = None
self._multipole_library = None
self._energy_grid = None
self._ptables = None
self._run_cmfd = None
self._seed = None
@ -197,6 +199,8 @@ class Settings(object):
self._trace = None
self._track = None
self._temperature = {}
# Cutoff subelement
self._weight = None
self._weight_avg = None
@ -216,7 +220,6 @@ class Settings(object):
self._settings_file = ET.Element("settings")
self._run_mode_subelement = None
self._multipole_active = None
self._resonance_scattering = cv.CheckedList(
ResonanceScattering, 'resonance scattering models')
@ -271,10 +274,6 @@ class Settings(object):
def multipole_library(self):
return self._multipole_library
@property
def energy_grid(self):
return self._energy_grid
@property
def ptables(self):
return self._ptables
@ -363,6 +362,10 @@ class Settings(object):
def verbosity(self):
return self._verbosity
@property
def temperature(self):
return self._temperature
@property
def trace(self):
return self._trace
@ -415,10 +418,6 @@ class Settings(object):
def dd_count_interactions(self):
return self._dd_count_interactions
@property
def use_windowed_multipole(self):
return self._multipole_active
@property
def resonance_scattering(self):
return self._resonance_scattering
@ -593,12 +592,6 @@ class Settings(object):
cv.check_type('cross sections', multipole_library, basestring)
self._multipole_library = multipole_library
@energy_grid.setter
def energy_grid(self, energy_grid):
cv.check_value('energy grid', energy_grid,
['nuclide', 'logarithm', 'material-union'])
self._energy_grid = energy_grid
@ptables.setter
def ptables(self, ptables):
cv.check_type('probability tables', ptables, bool)
@ -674,6 +667,21 @@ class Settings(object):
cv.check_type('no reduction option', no_reduce, bool)
self._no_reduce = no_reduce
@temperature.setter
def temperature(self, temperature):
cv.check_type('temperature settings', temperature, Mapping)
for key, value in temperature.items():
cv.check_value('temperature key', key,
['default', 'method', 'tolerance'])
if key == 'default':
cv.check_type('default temperature', value, Real)
elif key == 'method':
cv.check_value('temperature method', value,
['nearest', 'interpolation', 'multipole'])
elif key == 'tolerance':
cv.check_type('temperature tolerance', value, Real)
self._temperature = temperature
@threads.setter
def threads(self, threads):
cv.check_type('number of threads', threads, Integral)
@ -801,11 +809,6 @@ class Settings(object):
self._dd_count_interactions = interactions
@use_windowed_multipole.setter
def use_windowed_multipole(self, active):
cv.check_type('use_windowed_multipole', active, bool)
self._multipole_active = active
@resonance_scattering.setter
def resonance_scattering(self, res):
if not isinstance(res, MutableSequence):
@ -963,11 +966,6 @@ class Settings(object):
element = ET.SubElement(self._settings_file, "multipole_library")
element.text = str(self._multipole_library)
def _create_energy_grid_subelement(self):
if self._energy_grid is not None:
element = ET.SubElement(self._settings_file, "energy_grid")
element.text = str(self._energy_grid)
def _create_ptables_subelement(self):
if self._ptables is not None:
element = ET.SubElement(self._settings_file, "ptables")
@ -1050,6 +1048,13 @@ class Settings(object):
element = ET.SubElement(self._settings_file, "no_reduce")
element.text = str(self._no_reduce).lower()
def _create_temperature_subelements(self):
if self.temperature:
for key, value in self.temperature.items():
element = ET.SubElement(self._settings_file,
"temperature_{}".format(key))
element.text = str(value)
def _create_threads_subelement(self):
if self._threads is not None:
element = ET.SubElement(self._settings_file, "threads")
@ -1107,20 +1112,10 @@ class Settings(object):
subelement = ET.SubElement(element, "count_interactions")
subelement.text = str(self._dd_count_interactions).lower()
def _create_use_multipole_subelement(self):
if self._multipole_active is not None:
element = ET.SubElement(self._settings_file,
"use_windowed_multipole")
element.text = str(self._multipole_active)
def _create_resonance_scattering_subelement(self):
if len(self.resonance_scattering) > 0:
elem = ET.SubElement(self._settings_file, 'resonance_scattering')
for r in self.resonance_scattering:
if r.nuclide.name != r.nuclide_0K.name:
raise ValueError("The nuclide and nuclide_0K attributes of "
"a ResonantScattering object must have "
"identical names.")
elem.append(r.to_xml_element())
def export_to_xml(self):
@ -1142,7 +1137,6 @@ class Settings(object):
self._create_confidence_intervals()
self._create_cross_sections_subelement()
self._create_multipole_library_subelement()
self._create_energy_grid_subelement()
self._create_energy_mode_subelement()
self._create_max_order_subelement()
self._create_ptables_subelement()
@ -1155,11 +1149,11 @@ class Settings(object):
self._create_no_reduce_subelement()
self._create_threads_subelement()
self._create_verbosity_subelement()
self._create_temperature_subelements()
self._create_trace_subelement()
self._create_track_subelement()
self._create_ufs_subelement()
self._create_dd_subelement()
self._create_use_multipole_subelement()
self._create_resonance_scattering_subelement()
self._create_volume_calcs_subelement()
@ -1175,14 +1169,26 @@ class Settings(object):
class ResonanceScattering(object):
"""Specification of the elastic scattering model for resonant isotopes
Parameters
----------
nuclide : openmc.Nuclide
The nuclide affected by this resonance scattering treatment.
method : {'ARES', 'CXS', 'DBRC', 'WCM'}
The method used to sample outgoing scattering energies. Valid options
are 'ARES', 'CXS' (constant cross section), 'DBRC' (Doppler broadening
rejection correction), and 'WCM' (weight correction method).
E_min : float
The minimum energy above which the specified method is applied. By
default, CXS will be used below E_min.
E_max : float
The maximum energy below which the specified method is applied. By
default, the asymptotic target-at-rest model is applied above E_max.
Attributes
----------
nuclide : openmc.Nuclide
The nuclide affected by this resonance scattering treatment.
nuclide_0K : openmc.Nuclide
This should be the same isotope as the nuclide attribute above, but it
should have an xs attribute that identifies 0 Kelvin data.
method : str
method : {'ARES', 'CXS', 'DBRC', 'WCM'}
The method used to sample outgoing scattering energies. Valid options
are 'ARES', 'CXS' (constant cross section), 'DBRC' (Doppler broadening
rejection correction), and 'WCM' (weight correction method).
@ -1195,21 +1201,20 @@ class ResonanceScattering(object):
"""
def __init__(self):
self._nuclide = None
self._nuclide_0K = None
self._method = None
def __init__(self, nuclide, method='CXS', E_min=None, E_max=None):
self._E_min = None
self._E_max = None
self.nuclide = nuclide
self.method = method
if E_min is not None:
self.E_min = E_min
if E_max is not None:
self.E_max = E_max
@property
def nuclide(self):
return self._nuclide
@property
def nuclide_0K(self):
return self._nuclide_0K
@property
def method(self):
return self._method
@ -1227,11 +1232,6 @@ class ResonanceScattering(object):
cv.check_type('nuclide', nuc, Nuclide)
self._nuclide = nuc
@nuclide_0K.setter
def nuclide_0K(self, nuc):
cv.check_type('nuclide_0K', nuc, Nuclide)
self._nuclide_0K = nuc
@method.setter
def method(self, m):
cv.check_value('method', m, ('ARES', 'CXS', 'DBRC', 'WCM'))
@ -1264,10 +1264,6 @@ class ResonanceScattering(object):
if self.method is not None:
subelement = ET.SubElement(scatterer, 'method')
subelement.text = self.method
subelement = ET.SubElement(scatterer, 'xs_label')
subelement.text = '{0.name}.{0.xs}'.format(self.nuclide)
subelement = ET.SubElement(scatterer, 'xs_label_0K')
subelement.text = '{0.name}.{0.xs}'.format(self.nuclide_0K)
if self.E_min is not None:
subelement = ET.SubElement(scatterer, 'E_min')
subelement.text = str(self.E_min)

View file

@ -83,11 +83,10 @@ class Summary(object):
n_nuclides = self._f['nuclides/n_nuclides_total'].value
names = self._f['nuclides/names'].value
awrs = self._f['nuclides/awrs'].value
zaids = self._f['nuclides/zaids'].value
for n in range(n_nuclides):
name = names[n].decode()
name = name[:name.find('.')]
self.nuclides[name] = (zaids[n], awrs[n])
self.nuclides[name] = awrs[n]
def _read_geometry(self):
# Read in and initialize the Materials and Geometry
@ -124,22 +123,21 @@ class Summary(object):
if 'sab_names' in self._f['materials'][key]:
sab_tables = self._f['materials'][key]['sab_names'].value
for sab_table in sab_tables:
name, xs = sab_table.decode().split('.')
material.add_s_alpha_beta(name, xs)
name = sab_table.decode()
material.add_s_alpha_beta(name)
# Set the Material's density to atom/b-cm as used by OpenMC
material.set_density(density=density, units='atom/b-cm')
# Add all nuclides to the Material
for fullname, density in zip(nuclides, nuc_densities):
fullname = fullname.decode().strip()
name, xs = fullname.split('.')
name = fullname.decode().strip()
if 'nat' in name:
material.add_element(openmc.Element(name=name, xs=xs),
material.add_element(openmc.Element(name=name),
percent=density, percent_type='ao')
else:
material.add_nuclide(openmc.Nuclide(name=name, xs=xs),
material.add_nuclide(openmc.Nuclide(name=name),
percent=density, percent_type='ao')
# Add the Material to the global dictionary of all Materials

View file

@ -115,6 +115,7 @@ elif args.xsdata is not None:
else:
ace_libraries = args.libraries
nuclides = {}
library = openmc.data.DataLibrary()
for filename in ace_libraries:
@ -125,46 +126,87 @@ for filename in ace_libraries:
lib = openmc.data.ace.Library(filename)
for table in lib.tables:
if table.name.endswith('c'):
name, xs = table.name.split('.')
if xs.endswith('c'):
# Continuous-energy neutron data
try:
neutron = openmc.data.IncidentNeutron.from_ace(
table, args.metastable)
except Exception as e:
print('Failed to convert {}: {}'.format(table.name, e))
continue
if name not in nuclides:
try:
neutron = openmc.data.IncidentNeutron.from_ace(
table, args.metastable)
except Exception as e:
print('Failed to convert {}: {}'.format(table.name, e))
continue
# Fission energy release data, if available
if args.fission_energy_release is not None:
fer = openmc.data.FissionEnergyRelease.from_compact_hdf5(
args.fission_energy_release, neutron)
if fer is not None:
neutron.fission_energy = fer
# Fission energy release data, if available
if args.fission_energy_release is not None:
fer = openmc.data.FissionEnergyRelease.from_compact_hdf5(
args.fission_energy_release, neutron)
if fer is not None:
neutron.fission_energy = fer
print('Converting {} (ACE) to {} (HDF5)'.format(table.name,
neutron.name))
print('Converting {} (ACE) to {} (HDF5)'.format(table.name,
neutron.name))
# Determine filename
outfile = os.path.join(args.destination,
neutron.name.replace('.', '_') + '.h5')
neutron.export_to_hdf5(outfile, 'w')
# Determine filename
outfile = os.path.join(args.destination,
neutron.name.replace('.', '_') + '.h5')
neutron.export_to_hdf5(outfile, 'w')
# Register with library
library.register_file(outfile)
# Register with library
library.register_file(outfile)
elif table.name.endswith('t'):
# Add nuclide to list
nuclides[name] = outfile
else:
# Then we only need to append the data
try:
neutron = \
openmc.data.IncidentNeutron.from_hdf5(nuclides[name])
print('Converting {} (ACE) to {} (HDF5)'.format(table.name,
neutron.name))
neutron.add_temperature_from_ace(table, args.metastable)
neutron.export_to_hdf5(nuclides[name] + '_1', 'w')
os.rename(nuclides[name] + '_1', nuclides[name])
except Exception as e:
print('Failed to convert {}: {}'.format(table.name, e))
continue
elif xs.endswith('t'):
# Adjust name to be the new thermal scattering name
name = openmc.data.get_thermal_name(name)
# Thermal scattering data
thermal = openmc.data.ThermalScattering.from_ace(table)
print('Converting {} (ACE) to {} (HDF5)'.format(table.name,
thermal.name))
if name not in nuclides:
try:
thermal = openmc.data.ThermalScattering.from_ace(table)
except Exception as e:
print('Failed to convert {}: {}'.format(table.name, e))
continue
print('Converting {} (ACE) to {} (HDF5)'.format(table.name,
thermal.name))
# Determine filename
outfile = os.path.join(args.destination,
thermal.name.replace('.', '_') + '.h5')
thermal.export_to_hdf5(outfile, 'w')
# Determine filename
outfile = os.path.join(args.destination,
thermal.name.replace('.', '_') + '.h5')
thermal.export_to_hdf5(outfile, 'w')
# Register with library
library.register_file(outfile, 'thermal')
# Register with library
library.register_file(outfile, 'thermal')
# Add data to list
nuclides[name] = outfile
else:
# Then we only need to append the data
try:
thermal = openmc.data.ThermalScattering.from_hdf5(nuclides[name])
print('Converting {} (ACE) to {} (HDF5)'.format(table.name,
thermal.name))
thermal.add_temperature_from_ace(table)
thermal.export_to_hdf5(nuclides[name] + '_1', 'w')
os.rename(nuclides[name] + '_1', nuclides[name])
except Exception as e:
print('Failed to convert {}: {}'.format(table.name, e))
continue
# Write cross_sections.xml
libpath = os.path.join(args.destination, 'cross_sections.xml')

275
src/algorithm.F90 Normal file
View file

@ -0,0 +1,275 @@
module algorithm
use constants
use stl_vector, only: VectorInt, VectorReal
implicit none
integer, parameter :: MAX_ITERATION = 64
interface binary_search
module procedure binary_search_real, binary_search_int4, binary_search_int8
end interface binary_search
interface sort
module procedure sort_int, sort_real, sort_vector_int, sort_vector_real
end interface sort
interface find
module procedure find_int, find_real, find_vector_int, find_vector_real
end interface find
contains
!===============================================================================
! BINARY_SEARCH performs a binary search of an array to find where a specific
! value lies in the array. This is used extensively for energy grid searching
!===============================================================================
pure function binary_search_real(array, n, val) result(array_index)
integer, intent(in) :: n
real(8), intent(in) :: array(n)
real(8), intent(in) :: val
integer :: array_index
integer :: L
integer :: R
integer :: n_iteration
L = 1
R = n
if (val < array(L) .or. val > array(R)) then
array_index = -1
return
end if
n_iteration = 0
do while (R - L > 1)
! Find values at midpoint
array_index = L + (R - L)/2
if (val >= array(array_index)) then
L = array_index
else
R = array_index
end if
! check for large number of iterations
n_iteration = n_iteration + 1
if (n_iteration == MAX_ITERATION) then
array_index = -2
return
end if
end do
array_index = L
end function binary_search_real
pure function binary_search_int4(array, n, val) result(array_index)
integer, intent(in) :: n
integer, intent(in) :: array(n)
integer, intent(in) :: val
integer :: array_index
integer :: L
integer :: R
integer :: n_iteration
L = 1
R = n
if (val < array(L) .or. val > array(R)) then
array_index = -1
return
end if
n_iteration = 0
do while (R - L > 1)
! Find values at midpoint
array_index = L + (R - L)/2
if (val >= array(array_index)) then
L = array_index
else
R = array_index
end if
! check for large number of iterations
n_iteration = n_iteration + 1
if (n_iteration == MAX_ITERATION) then
array_index = -2
return
end if
end do
array_index = L
end function binary_search_int4
pure function binary_search_int8(array, n, val) result(array_index)
integer, intent(in) :: n
integer(8), intent(in) :: array(n)
integer(8), intent(in) :: val
integer :: array_index
integer :: L
integer :: R
integer :: n_iteration
L = 1
R = n
if (val < array(L) .or. val > array(R)) then
array_index = -1
return
end if
n_iteration = 0
do while (R - L > 1)
! Find values at midpoint
array_index = L + (R - L)/2
if (val >= array(array_index)) then
L = array_index
else
R = array_index
end if
! check for large number of iterations
n_iteration = n_iteration + 1
if (n_iteration == MAX_ITERATION) then
array_index = -2
return
end if
end do
array_index = L
end function binary_search_int8
!===============================================================================
! SORT sorts an array in place using an insertion sort.
!===============================================================================
pure subroutine sort_int(array)
integer, intent(inout) :: array(:)
integer :: k, m
integer :: temp
if (size(array) > 1) then
SORT: do k = 2, size(array)
! Save value to move
m = k
temp = array(k)
MOVE_OVER: do while (m > 1)
! Check if insertion value is greater than (m-1)th value
if (temp >= array(m - 1)) exit
! Move values over until hitting one that's not larger
array(m) = array(m - 1)
m = m - 1
end do MOVE_OVER
! Put the original value into its new position
array(m) = temp
end do SORT
end if
end subroutine sort_int
pure subroutine sort_real(array)
real(8), intent(inout) :: array(:)
integer :: k, m
real(8) :: temp
if (size(array) > 1) then
SORT: do k = 2, size(array)
! Save value to move
m = k
temp = array(k)
MOVE_OVER: do while (m > 1)
! Check if insertion value is greater than (m-1)th value
if (temp >= array(m - 1)) exit
! Move values over until hitting one that's not larger
array(m) = array(m - 1)
m = m - 1
end do MOVE_OVER
! Put the original value into its new position
array(m) = temp
end do SORT
end if
end subroutine sort_real
pure subroutine sort_vector_int(vec)
type(VectorInt), intent(inout) :: vec
call sort_int(vec % data(1:vec%size()))
end subroutine sort_vector_int
pure subroutine sort_vector_real(vec)
type(VectorReal), intent(inout) :: vec
call sort_real(vec % data(1:vec%size()))
end subroutine sort_vector_real
!===============================================================================
! FIND determines the index of the first occurrence of a value in an array. If
! the value does not appear in the array, -1 is returned.
!===============================================================================
pure function find_int(array, val) result(index)
integer, intent(in) :: array(:)
integer, intent(in) :: val
integer :: index
integer :: i
index = -1
do i = 1, size(array)
if (array(i) == val) then
index = i
exit
end if
end do
end function find_int
pure function find_real(array, val) result(index)
real(8), intent(in) :: array(:)
real(8), intent(in) :: val
integer :: index
integer :: i
index = -1
do i = 1, size(array)
if (array(i) == val) then
index = i
exit
end if
end do
end function find_real
pure function find_vector_int(vec, val) result(index)
type(VectorInt), intent(in) :: vec
integer, intent(in) :: val
integer :: index
index = find_int(vec % data(1:vec % size()), val)
end function find_vector_int
pure function find_vector_real(vec, val) result(index)
type(VectorReal), intent(in) :: vec
real(8), intent(in) :: val
integer :: index
index = find_real(vec % data(1:vec % size()), val)
end function find_vector_real
end module algorithm

View file

@ -2,12 +2,12 @@ module angle_distribution
use hdf5, only: HID_T, HSIZE_T
use algorithm, only: binary_search
use constants, only: ZERO, ONE, HISTOGRAM, LINEAR_LINEAR
use distribution_univariate, only: DistributionContainer, Tabular
use hdf5_interface, only: read_attribute, get_shape, read_dataset, &
open_dataset, close_dataset
use random_lcg, only: prn
use search, only: binary_search
implicit none
private

View file

@ -213,13 +213,13 @@ contains
subroutine cmfd_reweight(new_weights)
use algorithm, only: binary_search
use constants, only: ZERO, ONE
use error, only: warning, fatal_error
use global, only: meshes, source_bank, work, n_user_meshes, cmfd, &
master
use mesh_header, only: RegularMesh
use mesh, only: count_bank_sites, get_mesh_indices
use search, only: binary_search
use string, only: to_str
#ifdef MPI

View file

@ -268,6 +268,12 @@ module constants
JENDL_33 = 7, &
JENDL_40 = 8
! Temperature treatment method
integer, parameter :: &
TEMPERATURE_NEAREST = 1, &
TEMPERATURE_INTERPOLATION = 2, &
TEMPERATURE_MULTIPOLE = 3
! ============================================================================
! TALLY-RELATED CONSTANTS
@ -407,12 +413,6 @@ module constants
integer, parameter :: ERROR_INT = -huge(0)
real(8), parameter :: ERROR_REAL = -huge(0.0_8) * 0.917826354_8
! Energy grid methods
integer, parameter :: &
GRID_NUCLIDE = 1, & ! unique energy grid for each nuclide
GRID_MAT_UNION = 2, & ! material union grids with pointers
GRID_LOGARITHM = 3 ! lethargy mapping
! Running modes
integer, parameter :: &
MODE_FIXEDSOURCE = 1, & ! Fixed source mode

View file

@ -1,7 +1,8 @@
module cross_section
use algorithm, only: binary_search
use constants
use energy_grid, only: grid_method, log_spacing
use energy_grid, only: log_spacing
use error, only: fatal_error
use global
use list_header, only: ListElemInt
@ -14,7 +15,6 @@ module cross_section
use particle_header, only: Particle
use random_lcg, only: prn, future_prn, prn_set_stream
use sab_header, only: SAlphaBeta
use search, only: binary_search
implicit none
@ -37,7 +37,6 @@ contains
! union grid
real(8) :: atom_density ! atom density of a nuclide
logical :: check_sab ! should we check for S(a,b) table?
type(Material), pointer :: mat ! current material
! Set all material macroscopic cross sections to zero
material_xs % total = ZERO
@ -49,89 +48,83 @@ contains
! Exit subroutine if material is void
if (p % material == MATERIAL_VOID) return
mat => materials(p % material)
! Find energy index on energy grid
if (grid_method == GRID_MAT_UNION) then
i_grid = find_energy_index(mat, p % E)
else if (grid_method == GRID_LOGARITHM) then
associate (mat => materials(p % material))
! Find energy index on energy grid
i_grid = int(log(p % E/energy_min_neutron)/log_spacing)
end if
! Determine if this material has S(a,b) tables
check_sab = (mat % n_sab > 0)
! Determine if this material has S(a,b) tables
check_sab = (mat % n_sab > 0)
! Initialize position in i_sab_nuclides
j = 1
! Initialize position in i_sab_nuclides
j = 1
! Add contribution from each nuclide in material
do i = 1, mat % n_nuclides
! ========================================================================
! CHECK FOR S(A,B) TABLE
! Add contribution from each nuclide in material
do i = 1, mat % n_nuclides
! ========================================================================
! CHECK FOR S(A,B) TABLE
i_sab = 0
i_sab = 0
! Check if this nuclide matches one of the S(a,b) tables specified -- this
! relies on i_sab_nuclides being in sorted order
if (check_sab) then
if (i == mat % i_sab_nuclides(j)) then
! Get index in sab_tables
i_sab = mat % i_sab_tables(j)
! Check if this nuclide matches one of the S(a,b) tables specified -- this
! relies on i_sab_nuclides being in sorted order
if (check_sab) then
if (i == mat % i_sab_nuclides(j)) then
! Get index in sab_tables
i_sab = mat % i_sab_tables(j)
! If particle energy is greater than the highest energy for the S(a,b)
! table, don't use the S(a,b) table
if (p % E > sab_tables(i_sab) % threshold_inelastic) i_sab = 0
! If particle energy is greater than the highest energy for the S(a,b)
! table, don't use the S(a,b) table
if (p % E > sab_tables(i_sab) % data(1) % threshold_inelastic) i_sab = 0
! Increment position in i_sab_nuclides
j = j + 1
! Increment position in i_sab_nuclides
j = j + 1
! Don't check for S(a,b) tables if there are no more left
if (j > mat % n_sab) check_sab = .false.
! Don't check for S(a,b) tables if there are no more left
if (j > mat % n_sab) check_sab = .false.
end if
end if
end if
! ========================================================================
! CALCULATE MICROSCOPIC CROSS SECTION
! ========================================================================
! CALCULATE MICROSCOPIC CROSS SECTION
! Determine microscopic cross sections for this nuclide
i_nuclide = mat % nuclide(i)
! Determine microscopic cross sections for this nuclide
i_nuclide = mat % nuclide(i)
! Calculate microscopic cross section for this nuclide
if (p % E /= micro_xs(i_nuclide) % last_E &
.or. p % sqrtkT /= micro_xs(i_nuclide) % last_sqrtkT) then
call calculate_nuclide_xs(i_nuclide, i_sab, p % E, p % material, i, &
i_grid, p % sqrtkT)
else if (i_sab /= micro_xs(i_nuclide) % last_index_sab) then
call calculate_nuclide_xs(i_nuclide, i_sab, p % E, p % material, i, &
i_grid, p % sqrtkT)
end if
! Calculate microscopic cross section for this nuclide
if (p % E /= micro_xs(i_nuclide) % last_E &
.or. p % sqrtkT /= micro_xs(i_nuclide) % last_sqrtkT) then
call calculate_nuclide_xs(i_nuclide, i_sab, p % E, i_grid, p % sqrtkT)
else if (i_sab /= micro_xs(i_nuclide) % last_index_sab) then
call calculate_nuclide_xs(i_nuclide, i_sab, p % E, i_grid, p % sqrtkT)
end if
! ========================================================================
! ADD TO MACROSCOPIC CROSS SECTION
! ========================================================================
! ADD TO MACROSCOPIC CROSS SECTION
! Copy atom density of nuclide in material
atom_density = mat % atom_density(i)
! Copy atom density of nuclide in material
atom_density = mat % atom_density(i)
! Add contributions to material macroscopic total cross section
material_xs % total = material_xs % total + &
atom_density * micro_xs(i_nuclide) % total
! Add contributions to material macroscopic total cross section
material_xs % total = material_xs % total + &
atom_density * micro_xs(i_nuclide) % total
! Add contributions to material macroscopic scattering cross section
material_xs % elastic = material_xs % elastic + &
atom_density * micro_xs(i_nuclide) % elastic
! Add contributions to material macroscopic scattering cross section
material_xs % elastic = material_xs % elastic + &
atom_density * micro_xs(i_nuclide) % elastic
! Add contributions to material macroscopic absorption cross section
material_xs % absorption = material_xs % absorption + &
atom_density * micro_xs(i_nuclide) % absorption
! Add contributions to material macroscopic absorption cross section
material_xs % absorption = material_xs % absorption + &
atom_density * micro_xs(i_nuclide) % absorption
! Add contributions to material macroscopic fission cross section
material_xs % fission = material_xs % fission + &
atom_density * micro_xs(i_nuclide) % fission
! Add contributions to material macroscopic fission cross section
material_xs % fission = material_xs % fission + &
atom_density * micro_xs(i_nuclide) % fission
! Add contributions to material macroscopic nu-fission cross section
material_xs % nu_fission = material_xs % nu_fission + &
atom_density * micro_xs(i_nuclide) % nu_fission
end do
! Add contributions to material macroscopic nu-fission cross section
material_xs % nu_fission = material_xs % nu_fission + &
atom_density * micro_xs(i_nuclide) % nu_fission
end do
end associate
end subroutine calculate_xs
@ -140,169 +133,162 @@ contains
! given index in the nuclides array at the energy of the given particle
!===============================================================================
subroutine calculate_nuclide_xs(i_nuclide, i_sab, E, i_mat, i_nuc_mat, &
i_log_union, sqrtkT)
subroutine calculate_nuclide_xs(i_nuclide, i_sab, E, i_log_union, sqrtkT)
integer, intent(in) :: i_nuclide ! index into nuclides array
integer, intent(in) :: i_sab ! index into sab_tables array
real(8), intent(in) :: E ! energy
integer, intent(in) :: i_mat ! index into materials array
integer, intent(in) :: i_nuc_mat ! index into nuclides array for a material
integer, intent(in) :: i_log_union ! index into logarithmic mapping array or
! material union energy grid
real(8), intent(in) :: sqrtkT ! Square root of kT, material dependent
logical :: use_mp ! true if XS can be calculated with windowed multipole
integer :: i_temp ! index for temperature
integer :: i_grid ! index on nuclide energy grid
integer :: i_low ! lower logarithmic mapping index
integer :: i_high ! upper logarithmic mapping index
real(8) :: f ! interp factor on nuclide energy grid
real(8) :: kT ! temperature in MeV
real(8) :: sigT, sigA, sigF ! Intermediate multipole variables
type(Nuclide), pointer :: nuc
type(Material), pointer :: mat
! Set pointer to nuclide and material
nuc => nuclides(i_nuclide)
mat => materials(i_mat)
! Check to see if there is multipole data present at this energy
use_mp = .false.
if (nuc % mp_present) then
if (E >= nuc % multipole % start_E/1.0e6_8 .and. &
E <= nuc % multipole % end_E/1.0e6_8) then
use_mp = .true.
end if
end if
! Evaluate multipole or interpolate
if (use_mp) then
! Call multipole kernel
call multipole_eval(nuc % multipole, E, sqrtkT, sigT, sigA, sigF)
micro_xs(i_nuclide) % total = sigT
micro_xs(i_nuclide) % absorption = sigA
micro_xs(i_nuclide) % elastic = sigT - sigA
if (nuc % fissionable) then
micro_xs(i_nuclide) % fission = sigF
micro_xs(i_nuclide) % nu_fission = sigF * nuc % nu(E, EMISSION_TOTAL)
associate (nuc => nuclides(i_nuclide))
! Check to see if there is multipole data present at this energy
use_mp = .false.
if (nuc % mp_present) then
if (E >= nuc % multipole % start_E/1.0e6_8 .and. &
E <= nuc % multipole % end_E/1.0e6_8) then
use_mp = .true.
else
! If using multipole data but outside the RRR, pick the nearest
! temperature. Note that there is no tolerance here, so this
! temperature could be very far off!
kT = sqrtkT**2
i_temp = minloc(abs(nuclides(i_nuclide) % kTs - kT), dim=1)
end if
else
micro_xs(i_nuclide) % fission = ZERO
micro_xs(i_nuclide) % nu_fission = ZERO
! If not using multipole data, do a linear search on temperature
kT = sqrtkT**2
do i_temp = 1, size(nuclides(i_nuclide) % kTs)
if (abs(nuclides(i_nuclide) % kTs(i_temp) - kT) < &
K_BOLTZMANN*temperature_tolerance) exit
end do
end if
! Ensure these values are set
! Note, the only time either is used is in one of 4 places:
! 1. physics.F90 - scatter - For inelastic scatter.
! 2. physics.F90 - sample_fission - For partial fissions.
! 3. tally.F90 - score_general - For tallying on MTxxx reactions.
! 4. cross_section.F90 - calculate_urr_xs - For unresolved purposes.
! It is worth noting that none of these occur in the resolved
! resonance range, so the value here does not matter.
micro_xs(i_nuclide) % index_grid = 0
micro_xs(i_nuclide) % interp_factor = ZERO
else
! Determine index on nuclide energy grid
select case (grid_method)
case (GRID_MAT_UNION)
! Evaluate multipole or interpolate
if (use_mp) then
! Call multipole kernel
call multipole_eval(nuc % multipole, E, sqrtkT, sigT, sigA, sigF)
i_grid = mat % nuclide_grid_index(i_nuc_mat, i_log_union)
micro_xs(i_nuclide) % total = sigT
micro_xs(i_nuclide) % absorption = sigA
micro_xs(i_nuclide) % elastic = sigT - sigA
case (GRID_LOGARITHM)
! Determine the energy grid index using a logarithmic mapping to reduce
! the energy range over which a binary search needs to be performed
if (E < nuc % energy(1)) then
i_grid = 1
elseif (E > nuc % energy(nuc % n_grid)) then
i_grid = nuc % n_grid - 1
if (nuc % fissionable) then
micro_xs(i_nuclide) % fission = sigF
micro_xs(i_nuclide) % nu_fission = sigF * nuc % nu(E, EMISSION_TOTAL)
else
! Determine bounding indices based on which equal log-spaced interval
! the energy is in
i_low = nuc % grid_index(i_log_union)
i_high = nuc % grid_index(i_log_union + 1) + 1
! Perform binary search over reduced range
i_grid = binary_search(nuc % energy(i_low:i_high), &
i_high - i_low + 1, E) + i_low - 1
micro_xs(i_nuclide) % fission = ZERO
micro_xs(i_nuclide) % nu_fission = ZERO
end if
case (GRID_NUCLIDE)
! Perform binary search on the nuclide energy grid in order to determine
! which points to interpolate between
! Ensure these values are set
! Note, the only time either is used is in one of 4 places:
! 1. physics.F90 - scatter - For inelastic scatter.
! 2. physics.F90 - sample_fission - For partial fissions.
! 3. tally.F90 - score_general - For tallying on MTxxx reactions.
! 4. cross_section.F90 - calculate_urr_xs - For unresolved purposes.
! It is worth noting that none of these occur in the resolved
! resonance range, so the value here does not matter.
micro_xs(i_nuclide) % index_temp = i_temp
micro_xs(i_nuclide) % index_grid = 0
micro_xs(i_nuclide) % interp_factor = ZERO
else
associate (grid => nuc % grid(i_temp), xs => nuc % sum_xs(i_temp))
! Determine the energy grid index using a logarithmic mapping to reduce
! the energy range over which a binary search needs to be performed
if (E <= nuc % energy(1)) then
i_grid = 1
elseif (E > nuc % energy(nuc % n_grid)) then
i_grid = nuc % n_grid - 1
else
i_grid = binary_search(nuc % energy, nuc % n_grid, E)
if (E < grid % energy(1)) then
i_grid = 1
elseif (E > grid % energy(size(grid % energy))) then
i_grid = size(grid % energy) - 1
else
! Determine bounding indices based on which equal log-spaced interval
! the energy is in
i_low = grid % grid_index(i_log_union)
i_high = grid % grid_index(i_log_union + 1) + 1
! Perform binary search over reduced range
i_grid = binary_search(grid % energy(i_low:i_high), &
i_high - i_low + 1, E) + i_low - 1
end if
! check for rare case where two energy points are the same
if (grid % energy(i_grid) == grid % energy(i_grid + 1)) &
i_grid = i_grid + 1
! calculate interpolation factor
f = (E - grid % energy(i_grid)) / &
(grid % energy(i_grid + 1) - grid % energy(i_grid))
micro_xs(i_nuclide) % index_temp = i_temp
micro_xs(i_nuclide) % index_grid = i_grid
micro_xs(i_nuclide) % interp_factor = f
! Initialize nuclide cross-sections to zero
micro_xs(i_nuclide) % fission = ZERO
micro_xs(i_nuclide) % nu_fission = ZERO
! Calculate microscopic nuclide total cross section
micro_xs(i_nuclide) % total = (ONE - f) * xs % total(i_grid) &
+ f * xs % total(i_grid + 1)
! Calculate microscopic nuclide elastic cross section
micro_xs(i_nuclide) % elastic = (ONE - f) * xs % elastic(i_grid) &
+ f * xs % elastic(i_grid + 1)
! Calculate microscopic nuclide absorption cross section
micro_xs(i_nuclide) % absorption = (ONE - f) * xs % absorption( &
i_grid) + f * xs % absorption(i_grid + 1)
if (nuc % fissionable) then
! Calculate microscopic nuclide total cross section
micro_xs(i_nuclide) % fission = (ONE - f) * xs % fission(i_grid) &
+ f * xs % fission(i_grid + 1)
! Calculate microscopic nuclide nu-fission cross section
micro_xs(i_nuclide) % nu_fission = (ONE - f) * xs % nu_fission( &
i_grid) + f * xs % nu_fission(i_grid + 1)
end if
end associate
end if
! Initialize sab treatment to false
micro_xs(i_nuclide) % index_sab = NONE
micro_xs(i_nuclide) % elastic_sab = ZERO
! Initialize URR probability table treatment to false
micro_xs(i_nuclide) % use_ptable = .false.
! If there is S(a,b) data for this nuclide, we need to do a few
! things. Since the total cross section was based on non-S(a,b) data, we
! need to correct it by subtracting the non-S(a,b) elastic cross section and
! then add back in the calculated S(a,b) elastic+inelastic cross section.
if (i_sab > 0) call calculate_sab_xs(i_nuclide, i_sab, E, sqrtkT)
! if the particle is in the unresolved resonance range and there are
! probability tables, we need to determine cross sections from the table
if (urr_ptables_on .and. nuc % urr_present .and. .not. use_mp) then
if (E > nuc % urr_data(i_temp) % energy(1) .and. E < nuc % &
urr_data(i_temp) % energy(nuc % urr_data(i_temp) % n_energy)) then
call calculate_urr_xs(i_nuclide, i_temp, E)
end if
end select
! check for rare case where two energy points are the same
if (nuc % energy(i_grid) == nuc % energy(i_grid+1)) i_grid = i_grid + 1
! calculate interpolation factor
f = (E - nuc%energy(i_grid))/(nuc%energy(i_grid+1) - nuc%energy(i_grid))
micro_xs(i_nuclide) % index_grid = i_grid
micro_xs(i_nuclide) % interp_factor = f
! Initialize nuclide cross-sections to zero
micro_xs(i_nuclide) % fission = ZERO
micro_xs(i_nuclide) % nu_fission = ZERO
! Calculate microscopic nuclide total cross section
micro_xs(i_nuclide) % total = (ONE - f) * nuc % total(i_grid) &
+ f * nuc % total(i_grid+1)
! Calculate microscopic nuclide elastic cross section
micro_xs(i_nuclide) % elastic = (ONE - f) * nuc % elastic(i_grid) &
+ f * nuc % elastic(i_grid+1)
! Calculate microscopic nuclide absorption cross section
micro_xs(i_nuclide) % absorption = (ONE - f) * nuc % absorption( &
i_grid) + f * nuc % absorption(i_grid+1)
if (nuc % fissionable) then
! Calculate microscopic nuclide total cross section
micro_xs(i_nuclide) % fission = (ONE - f) * nuc % fission(i_grid) &
+ f * nuc % fission(i_grid+1)
! Calculate microscopic nuclide nu-fission cross section
micro_xs(i_nuclide) % nu_fission = (ONE - f) * nuc % nu_fission( &
i_grid) + f * nuc % nu_fission(i_grid+1)
end if
end if
! Initialize sab treatment to false
micro_xs(i_nuclide) % index_sab = NONE
micro_xs(i_nuclide) % elastic_sab = ZERO
! Initialize URR probability table treatment to false
micro_xs(i_nuclide) % use_ptable = .false.
! If there is S(a,b) data for this nuclide, we need to do a few
! things. Since the total cross section was based on non-S(a,b) data, we
! need to correct it by subtracting the non-S(a,b) elastic cross section and
! then add back in the calculated S(a,b) elastic+inelastic cross section.
if (i_sab > 0) call calculate_sab_xs(i_nuclide, i_sab, E)
! if the particle is in the unresolved resonance range and there are
! probability tables, we need to determine cross sections from the table
if (urr_ptables_on .and. nuc % urr_present) then
if (E > nuc % urr_data % energy(1) .and. &
E < nuc % urr_data % energy(nuc % urr_data % n_energy)) then
call calculate_urr_xs(i_nuclide, E)
end if
end if
micro_xs(i_nuclide) % last_E = E
micro_xs(i_nuclide) % last_index_sab = i_sab
micro_xs(i_nuclide) % last_sqrtkT = sqrtkT
micro_xs(i_nuclide) % last_E = E
micro_xs(i_nuclide) % last_index_sab = i_sab
micro_xs(i_nuclide) % last_sqrtkT = sqrtkT
end associate
end subroutine calculate_nuclide_xs
@ -312,75 +298,85 @@ contains
! whatever data were taken from the normal Nuclide table.
!===============================================================================
subroutine calculate_sab_xs(i_nuclide, i_sab, E)
subroutine calculate_sab_xs(i_nuclide, i_sab, E, sqrtkT)
integer, intent(in) :: i_nuclide ! index into nuclides array
integer, intent(in) :: i_sab ! index into sab_tables array
real(8), intent(in) :: E ! energy
real(8), intent(in) :: sqrtkT ! temperature
integer :: i_grid ! index on S(a,b) energy grid
integer :: i_temp ! temperature index
real(8) :: f ! interp factor on S(a,b) energy grid
real(8) :: inelastic ! S(a,b) inelastic cross section
real(8) :: elastic ! S(a,b) elastic cross section
type(SAlphaBeta), pointer :: sab
real(8) :: kT
! Set flag that S(a,b) treatment should be used for scattering
micro_xs(i_nuclide) % index_sab = i_sab
! Determine temperature for S(a,b) table
kT = sqrtkT**2
do i_temp = 1, size(sab_tables(i_sab) % kTs)
if (abs(sab_tables(i_sab) % kTs(i_temp) - kT) < &
K_BOLTZMANN*temperature_tolerance) exit
end do
! Get pointer to S(a,b) table
sab => sab_tables(i_sab)
associate (sab => sab_tables(i_sab) % data(i_temp))
! Get index and interpolation factor for inelastic grid
if (E < sab % inelastic_e_in(1)) then
i_grid = 1
f = ZERO
else
i_grid = binary_search(sab % inelastic_e_in, sab % n_inelastic_e_in, E)
f = (E - sab%inelastic_e_in(i_grid)) / &
(sab%inelastic_e_in(i_grid+1) - sab%inelastic_e_in(i_grid))
end if
! Get index and interpolation factor for inelastic grid
if (E < sab % inelastic_e_in(1)) then
i_grid = 1
f = ZERO
else
i_grid = binary_search(sab % inelastic_e_in, sab % n_inelastic_e_in, E)
f = (E - sab%inelastic_e_in(i_grid)) / &
(sab%inelastic_e_in(i_grid+1) - sab%inelastic_e_in(i_grid))
end if
! Calculate S(a,b) inelastic scattering cross section
inelastic = (ONE - f) * sab % inelastic_sigma(i_grid) + &
f * sab % inelastic_sigma(i_grid + 1)
! Calculate S(a,b) inelastic scattering cross section
inelastic = (ONE - f) * sab % inelastic_sigma(i_grid) + &
f * sab % inelastic_sigma(i_grid + 1)
! Check for elastic data
if (E < sab % threshold_elastic) then
! Determine whether elastic scattering is given in the coherent or
! incoherent approximation. For coherent, the cross section is
! represented as P/E whereas for incoherent, it is simply P
! Check for elastic data
if (E < sab % threshold_elastic) then
! Determine whether elastic scattering is given in the coherent or
! incoherent approximation. For coherent, the cross section is
! represented as P/E whereas for incoherent, it is simply P
if (sab % elastic_mode == SAB_ELASTIC_EXACT) then
if (E < sab % elastic_e_in(1)) then
! If energy is below that of the lowest Bragg peak, the elastic
! cross section will be zero
elastic = ZERO
if (sab % elastic_mode == SAB_ELASTIC_EXACT) then
if (E < sab % elastic_e_in(1)) then
! If energy is below that of the lowest Bragg peak, the elastic
! cross section will be zero
elastic = ZERO
else
i_grid = binary_search(sab % elastic_e_in, &
sab % n_elastic_e_in, E)
elastic = sab % elastic_P(i_grid) / E
end if
else
i_grid = binary_search(sab % elastic_e_in, &
sab % n_elastic_e_in, E)
elastic = sab % elastic_P(i_grid) / E
! Determine index on elastic energy grid
if (E < sab % elastic_e_in(1)) then
i_grid = 1
else
i_grid = binary_search(sab % elastic_e_in, &
sab % n_elastic_e_in, E)
end if
! Get interpolation factor for elastic grid
f = (E - sab%elastic_e_in(i_grid))/(sab%elastic_e_in(i_grid+1) - &
sab%elastic_e_in(i_grid))
! Calculate S(a,b) elastic scattering cross section
elastic = (ONE - f) * sab % elastic_P(i_grid) + &
f * sab % elastic_P(i_grid + 1)
end if
else
! Determine index on elastic energy grid
if (E < sab % elastic_e_in(1)) then
i_grid = 1
else
i_grid = binary_search(sab % elastic_e_in, &
sab % n_elastic_e_in, E)
end if
! Get interpolation factor for elastic grid
f = (E - sab%elastic_e_in(i_grid))/(sab%elastic_e_in(i_grid+1) - &
sab%elastic_e_in(i_grid))
! Calculate S(a,b) elastic scattering cross section
elastic = (ONE - f) * sab % elastic_P(i_grid) + &
f * sab % elastic_P(i_grid + 1)
! No elastic data
elastic = ZERO
end if
else
! No elastic data
elastic = ZERO
end if
end associate
! Correct total and elastic cross sections
micro_xs(i_nuclide) % total = micro_xs(i_nuclide) % total - &
@ -390,6 +386,9 @@ contains
! Store S(a,b) elastic cross section for sampling later
micro_xs(i_nuclide) % elastic_sab = elastic
! Save temperature index
micro_xs(i_nuclide) % index_temp_sab = i_temp
end subroutine calculate_sab_xs
!===============================================================================
@ -397,9 +396,9 @@ contains
! from probability tables
!===============================================================================
subroutine calculate_urr_xs(i_nuclide, E)
subroutine calculate_urr_xs(i_nuclide, i_temp, E)
integer, intent(in) :: i_nuclide ! index into nuclides array
integer, intent(in) :: i_temp ! temperature index
real(8), intent(in) :: E ! energy
integer :: i_energy ! index for energy
@ -414,7 +413,7 @@ contains
micro_xs(i_nuclide) % use_ptable = .true.
associate (nuc => nuclides(i_nuclide), urr => nuclides(i_nuclide) % urr_data)
associate (nuc => nuclides(i_nuclide), urr => nuclides(i_nuclide) % urr_data(i_temp))
! determine energy table
i_energy = 1
do
@ -433,7 +432,7 @@ contains
! random number for the same nuclide at different temperatures, therefore
! preserving correlation of temperature in probability tables.
call prn_set_stream(STREAM_URR_PTABLE)
r = future_prn(int(nuc_zaid_dict % get_key(nuc % zaid), 8))
r = future_prn(int(i_nuclide, 8))
call prn_set_stream(STREAM_TRACKING)
i_low = 1
@ -497,10 +496,10 @@ contains
f = micro_xs(i_nuclide) % interp_factor
! Determine inelastic scattering cross section
associate (rxn => nuc % reactions(nuc % urr_inelastic))
if (i_energy >= rxn % threshold) then
inelastic = (ONE - f) * rxn % sigma(i_energy - rxn%threshold + 1) + &
f * rxn % sigma(i_energy - rxn%threshold + 2)
associate (xs => nuc % reactions(nuc % urr_inelastic) % xs(i_temp))
if (i_energy >= xs % threshold) then
inelastic = (ONE - f) * xs % value(i_energy - xs % threshold + 1) + &
f * xs % value(i_energy - xs % threshold + 2)
end if
end associate
end if

View file

@ -4,6 +4,7 @@ module eigenvalue
use message_passing
#endif
use algorithm, only: binary_search
use constants, only: ZERO
use error, only: fatal_error, warning
use global
@ -11,7 +12,6 @@ module eigenvalue
use mesh, only: count_bank_sites
use mesh_header, only: RegularMesh
use random_lcg, only: prn, set_particle_seed, advance_prn_seed
use search, only: binary_search
use string, only: to_str
implicit none

View file

@ -2,10 +2,10 @@ module endf_header
use hdf5, only: HID_T, HSIZE_T
use algorithm, only: binary_search
use constants, only: ZERO, HISTOGRAM, LINEAR_LINEAR, LINEAR_LOG, &
LOG_LINEAR, LOG_LOG
use hdf5_interface
use search, only: binary_search
implicit none

View file

@ -2,12 +2,12 @@ module energy_distribution
use hdf5
use algorithm, only: binary_search
use constants, only: ZERO, ONE, HALF, TWO, PI, HISTOGRAM, LINEAR_LINEAR
use endf_header, only: Tabulated1D
use hdf5_interface
use math, only: maxwell_spectrum, watt_spectrum
use random_lcg, only: prn
use search, only: binary_search
!===============================================================================
! ENERGYDISTRIBUTION (abstract) defines an energy distribution that is a

View file

@ -13,64 +13,18 @@ module energy_grid
contains
!===============================================================================
! UNIONIZED_GRID creates a unionized energy grid, for the entire problem or for
! each material, composed of the grids from each nuclide in the entire problem,
! or each material, respectively. Right now, the grid for each nuclide is added
! into a linked list one at a time with an effective insertion sort. Could be
! done with a hash for all energy points and then a quicksort at the end (what
! hash function to use?)
!===============================================================================
subroutine unionized_grid()
integer :: i ! index in nuclides array
integer :: j ! index in materials array
type(ListReal) :: list
type(Nuclide), pointer :: nuc
type(Material), pointer :: mat
call write_message("Creating unionized energy grid...", 5)
! add grid points for each nuclide in the material
do j = 1, n_materials
mat => materials(j)
do i = 1, mat % n_nuclides
nuc => nuclides(mat % nuclide(i))
call add_grid_points(list, nuc % energy)
end do
! set size of unionized material energy grid
mat % n_grid = list % size()
! create allocated array from linked list
allocate(mat % e_grid(mat % n_grid))
do i = 1, mat % n_grid
mat % e_grid(i) = list % get_item(i)
end do
! delete linked list and dictionary
call list % clear()
end do
! Set pointers to unionized energy grid for each nuclide
call grid_pointers()
end subroutine unionized_grid
!===============================================================================
! LOGARITHMIC_GRID determines a logarithmic mapping for energies to bounding
! indices on a nuclide energy grid
!===============================================================================
subroutine logarithmic_grid()
integer :: i, j, k ! Loop indices
integer :: t ! temperature index
integer :: M ! Number of equally log-spaced bins
real(8) :: E_max ! Maximum energy in MeV
real(8) :: E_min ! Minimum energy in MeV
real(8), allocatable :: umesh(:) ! Equally log-spaced energy grid
type(Nuclide), pointer :: nuc
! Set minimum/maximum energies
E_max = energy_max_neutron
@ -85,123 +39,29 @@ contains
umesh(:) = [(i*log_spacing, i=0, M)]
do i = 1, n_nuclides_total
! Allocate logarithmic mapping for nuclide
nuc => nuclides(i)
allocate(nuc % grid_index(0:M))
associate (nuc => nuclides(i))
do t = 1, size(nuc % grid)
! Allocate logarithmic mapping for nuclide
allocate(nuc % grid(t) % grid_index(0:M))
! Determine corresponding indices in nuclide grid to energies on
! equal-logarithmic grid
j = 1
do k = 0, M
do while (log(nuc%energy(j + 1)/E_min) <= umesh(k))
! Ensure that for isotopes where maxval(nuc % energy) << E_max
! that there are no out-of-bounds issues.
if (j + 1 == nuc % n_grid) then
exit
end if
j = j + 1
! Determine corresponding indices in nuclide grid to energies on
! equal-logarithmic grid
j = 1
do k = 0, M
do while (log(nuc % grid(t) % energy(j + 1)/E_min) <= umesh(k))
! Ensure that for isotopes where maxval(nuc % energy) << E_max
! that there are no out-of-bounds issues.
if (j + 1 == size(nuc % grid(t) % energy)) exit
j = j + 1
end do
nuc % grid(t) % grid_index(k) = j
end do
end do
nuc % grid_index(k) = j
end do
end associate
end do
deallocate(umesh)
end subroutine logarithmic_grid
!===============================================================================
! ADD_GRID_POINTS adds energy points from the 'energy' array into a linked list
! of points already stored from previous arrays.
!===============================================================================
subroutine add_grid_points(list, energy)
type(ListReal) :: list
real(8), intent(in) :: energy(:)
integer :: i ! index in energy array
integer :: n ! size of energy array
integer :: current ! current index
real(8) :: E ! actual energy value
i = 1
n = size(energy)
! Set current index to beginning of the list
current = 1
do while (i <= n)
E = energy(i)
! If we've reached the end of the grid energy list, add the remaining
! energy points to the end
if (current > list % size()) then
! Finish remaining energies
do while (i <= n)
call list % append(energy(i))
i = i + 1
end do
exit
end if
if (E < list % get_item(current)) then
! Insert new energy in this position
call list % insert(current, E)
! Advance index in linked list and in new energy grid
i = i + 1
current = current + 1
elseif (E == list % get_item(current)) then
! Found the exact same energy, no need to store duplicates so just
! skip and move to next index
i = i + 1
current = current + 1
else
current = current + 1
end if
end do
end subroutine add_grid_points
!===============================================================================
! GRID_POINTERS creates an array of pointers (ints) for each nuclide to link
! each point on the nuclide energy grid to one on a unionized energy grid
!===============================================================================
subroutine grid_pointers()
integer :: i ! loop index for nuclides
integer :: j ! loop index for nuclide energy grid
integer :: k ! loop index for materials
integer :: index_e ! index on union energy grid
real(8) :: union_energy ! energy on union grid
real(8) :: energy ! energy on nuclide grid
type(Nuclide), pointer :: nuc
type(Material), pointer :: mat
do k = 1, n_materials
mat => materials(k)
allocate(mat % nuclide_grid_index(mat % n_nuclides, mat % n_grid))
do i = 1, mat % n_nuclides
nuc => nuclides(mat % nuclide(i))
index_e = 1
energy = nuc % energy(index_e)
do j = 1, mat % n_grid
union_energy = mat % e_grid(j)
if (union_energy >= energy .and. index_e < nuc % n_grid) then
index_e = index_e + 1
energy = nuc % energy(index_e)
end if
mat % nuclide_grid_index(i,j) = index_e - 1
end do
end do
end do
end subroutine grid_pointers
end module energy_grid

View file

@ -248,14 +248,15 @@ contains
! ======================================================================
! AT LOWEST UNIVERSE, TERMINATE SEARCH
! Set the particle material
! Save previous material and temperature
p % last_material = p % material
if (size(c % material) == 1) then
! Only one material for this cell; assign that one to the particle.
p % material = c % material(1)
else
! Distributed instances of this cell have different materials.
! Determine which instance this is and assign the matching material.
p % last_sqrtkT = p % sqrtkT
! Get distributed offset
if (size(c % material) > 1 .or. size(c % sqrtkT) > 1) then
! Distributed instances of this cell have different
! materials/temperatures. Determine which instance this is for
! assigning the matching material/temperature.
distribcell_index = c % distribcell_index
offset = 0
do k = 1, p % n_coord
@ -276,37 +277,20 @@ contains
end if
end if
end do
p % material = c % material(offset + 1)
end if
! Set the particle temperature
if (size(c % sqrtkT) == 1) then
! Only one temperature for this cell; assign that one to the particle.
p % sqrtkT = c % sqrtkT(1)
! Save the material
if (size(c % material) > 1) then
p % material = c % material(offset + 1)
else
! Distributed instances of this cell have different temperatures.
! Determine which instance this is and assign the matching temp.
distribcell_index = c % distribcell_index
offset = 0
do k = 1, p % n_coord
if (cells(p % coord(k) % cell) % type == CELL_FILL) then
offset = offset + cells(p % coord(k) % cell) % &
offset(distribcell_index)
elseif (cells(p % coord(k) % cell) % type == CELL_LATTICE) then
if (lattices(p % coord(k + 1) % lattice) % obj &
% are_valid_indices([&
p % coord(k + 1) % lattice_x, &
p % coord(k + 1) % lattice_y, &
p % coord(k + 1) % lattice_z])) then
offset = offset + lattices(p % coord(k + 1) % lattice) % obj % &
offset(distribcell_index, &
p % coord(k + 1) % lattice_x, &
p % coord(k + 1) % lattice_y, &
p % coord(k + 1) % lattice_z)
end if
end if
end do
p % material = c % material(1)
end if
! Save the temperature
if (size(c % sqrtkT) > 1) then
p % sqrtkT = c % sqrtkT(offset + 1)
else
p % sqrtkT = c % sqrtkT(1)
end if
elseif (c % type == CELL_FILL) then CELL_TYPE

View file

@ -77,9 +77,6 @@ module global
! Dictionaries to look up cross sections and listings
type(DictCharInt) :: nuclide_dict
! Default xs identifier (e.g. 70c or 300K)
character(5):: default_xs
! ============================================================================
! CONTINUOUS-ENERGY CROSS SECTION RELATED VARIABLES
@ -102,13 +99,10 @@ module global
! What to assume for expanding natural elements
integer :: default_expand = ENDF_BVII1
! Whether or not windowed multipole cross sections should be used.
logical :: multipole_active = .false.
! Total amount of nuclide ZAID and dictionary of nuclide ZAID and index --
! this is used when sampling unresolved resonance probability tables
integer(8) :: n_nuc_zaid_total
type(DictIntInt) :: nuc_zaid_dict
! Default temperature and method for choosing temperatures
integer :: temperature_method = TEMPERATURE_NEAREST
real(8) :: temperature_tolerance = 10.0_8
real(8) :: temperature_default = 293.6_8
! ============================================================================
! MULTI-GROUP CROSS SECTION RELATED VARIABLES
@ -433,7 +427,6 @@ module global
! Various output options
logical :: output_summary = .true.
logical :: output_xs = .false.
logical :: output_tallies = .true.
! ============================================================================

View file

@ -73,6 +73,7 @@ module hdf5_interface
module procedure read_attribute_integer_1D
module procedure read_attribute_integer_2D
module procedure read_attribute_string
module procedure read_attribute_string_1D
end interface read_attribute
interface write_attribute
@ -95,6 +96,8 @@ module hdf5_interface
public :: close_dataset
public :: get_shape
public :: write_attribute_string
public :: get_groups
public :: get_datasets
contains
@ -204,6 +207,82 @@ contains
call h5fclose_f(file_id, hdf5_err)
end subroutine file_close
!===============================================================================
! GET_GROUPS Gets a list of all the groups in a given location.
!===============================================================================
subroutine get_groups(object_id, names)
integer(HID_T), intent(in) :: object_id
character(len=255), allocatable, intent(out) :: names(:)
integer :: n_members, i, group_count, type
integer :: hdf5_err
character(len=255) :: name
! Get number of members in this location
call h5gn_members_f(object_id, './', n_members, hdf5_err)
! Get the number of groups
group_count = 0
do i = 0, n_members - 1
call h5gget_obj_info_idx_f(object_id, "./", i, name, type, hdf5_err)
if (type == H5G_GROUP_F) then
group_count = group_count + 1
end if
end do
! Now we can allocate the storage for the ids
allocate(names(group_count))
group_count = 0
do i = 0, n_members - 1
call h5gget_obj_info_idx_f(object_id, "./", i, name, type, hdf5_err)
if (type == H5G_GROUP_F) then
group_count = group_count + 1
names(group_count) = trim(name)
end if
end do
end subroutine get_groups
!===============================================================================
! 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(:)
integer :: n_members, i, dset_count, type
integer :: hdf5_err
character(len=255) :: name
! Get number of members in this location
call h5gn_members_f(object_id, './', n_members, hdf5_err)
! Get the number of datasets
dset_count = 0
do i = 0, n_members - 1
call h5gget_obj_info_idx_f(object_id, "./", i, name, type, hdf5_err)
if (type == H5G_DATASET_F ) then
dset_count = dset_count + 1
end if
end do
! Now we can allocate the storage for the ids
allocate(names(dset_count))
dset_count = 0
do i = 0, n_members - 1
call h5gget_obj_info_idx_f(object_id, "./", i, name, type, hdf5_err)
if (type == H5G_DATASET_F ) then
dset_count = dset_count + 1
names(dset_count) = trim(name)
end if
end do
end subroutine get_datasets
!===============================================================================
! OPEN_GROUP opens an existing HDF5 group
!===============================================================================
@ -2347,6 +2426,66 @@ contains
call h5tclose_f(memtype, hdf5_err)
end subroutine read_attribute_string
subroutine read_attribute_string_1D(buffer, obj_id, name)
character(*), target, allocatable, intent(inout) :: buffer(:)
integer(HID_T), intent(in) :: obj_id
character(*), intent(in) :: name
integer :: hdf5_err
integer(HID_T) :: space_id
integer(HID_T) :: attr_id
integer(HSIZE_T) :: dims(1)
integer(HSIZE_T) :: maxdims(1)
call h5aopen_f(obj_id, trim(name), attr_id, hdf5_err)
if (allocated(buffer)) then
dims(:) = shape(buffer)
else
call h5aget_space_f(attr_id, space_id, hdf5_err)
call h5sget_simple_extent_dims_f(space_id, dims, maxdims, hdf5_err)
allocate(buffer(dims(1)))
call h5sclose_f(space_id, hdf5_err)
end if
call read_attribute_string_1D_explicit(attr_id, dims, buffer)
call h5aclose_f(attr_id, hdf5_err)
end subroutine read_attribute_string_1D
subroutine read_attribute_string_1D_explicit(attr_id, dims, buffer)
integer(HID_T), intent(in) :: attr_id
integer(HSIZE_T), intent(in) :: dims(1)
character(*), target, intent(inout) :: buffer(dims(1))
integer :: hdf5_err
integer(HID_T) :: filetype
integer(HID_T) :: memtype
integer(SIZE_T) :: size
integer(SIZE_T) :: n
type(c_ptr) :: f_ptr
! Make sure buffer is large enough
call h5aget_type_f(attr_id, filetype, hdf5_err)
call h5tget_size_f(filetype, size, hdf5_err)
if (size > len(buffer(1)) + 1) then
call fatal_error("Character buffer is not long enough to &
&read HDF5 string array.")
end if
! Get datatype in memory based on Fortran character
n = len(buffer(1))
call h5tcopy_f(H5T_FORTRAN_S1, memtype, hdf5_err)
call h5tset_size_f(memtype, n, hdf5_err)
! Get pointer to start of string
f_ptr = c_loc(buffer(1)(1:1))
call h5aread_f(attr_id, memtype, f_ptr, hdf5_err)
call h5tclose_f(filetype, hdf5_err)
call h5tclose_f(memtype, hdf5_err)
end subroutine read_attribute_string_1D_explicit
subroutine get_shape(obj_id, dims)
integer(HID_T), intent(in) :: obj_id
integer(HSIZE_T), intent(out) :: dims(:)

View file

@ -4,7 +4,7 @@ module initialize
use constants
use dict_header, only: DictIntInt, ElemKeyValueII
use set_header, only: SetInt
use energy_grid, only: logarithmic_grid, grid_method, unionized_grid
use energy_grid, only: logarithmic_grid, grid_method
use error, only: fatal_error, warning
use geometry, only: neighbor_lists, count_instance, calc_offsets, &
maximum_levels
@ -17,7 +17,7 @@ module initialize
use material_header, only: Material
use mgxs_data, only: read_mgxs, create_macro_xs
use output, only: title, header, print_version, write_message, &
print_usage, write_xs_summary, print_plot
print_usage, print_plot
use random_lcg, only: initialize_prng
use state_point, only: load_state_point
use string, only: to_str, starts_with, ends_with, str_to_int
@ -111,20 +111,8 @@ contains
if (run_mode /= MODE_PLOTTING) then
! Construct information needed for nuclear data
if (run_CE) then
! Set undefined cell temperatures to match the material data.
call lookup_material_temperatures()
! Construct unionized or log energy grid for cross-sections
select case (grid_method)
case (GRID_NUCLIDE)
continue
case (GRID_MAT_UNION)
call time_unionize%start()
call unionized_grid()
call time_unionize%stop()
case (GRID_LOGARITHM)
call logarithmic_grid()
end select
! Construct log energy grid for cross-sections
call logarithmic_grid()
else
! Create material macroscopic data for MGXS
call time_read_xs%start()
@ -158,9 +146,6 @@ contains
else
! Write summary information
if (output_summary) call write_summary()
! Write cross section information
if (output_xs) call write_xs_summary()
end if
end if
@ -1005,57 +990,4 @@ contains
end subroutine allocate_offsets
!===============================================================================
! LOOKUP_MATERIAL_TEMPERATURES If any cells have undefined temperatures, try to
! find their temperatures from material data.
!===============================================================================
subroutine lookup_material_temperatures()
integer :: i, j, k
real(8) :: min_temp
logical :: warning_given
warning_given = .false.
do i = 1, n_cells
! Ignore non-normal cells and cells with defined temperature.
if (cells(i) % type /= CELL_NORMAL) cycle
if (cells(i) % sqrtkT(1) /= ERROR_REAL) cycle
! Set the number of temperatures equal to the number of materials.
deallocate(cells(i) % sqrtkT)
allocate(cells(i) % sqrtkT(size(cells(i) % material)))
! Check each of the cell materials for temperature data.
do j = 1, size(cells(i) % material)
! Arbitrarily set void regions to 0K.
if (cells(i) % material(j) == MATERIAL_VOID) then
cells(i) % sqrtkT(j) = ZERO
cycle
end if
associate (mat => materials(cells(i) % material(j)))
! Find the temperature of the coldest nuclide.
min_temp = nuclides(mat % nuclide(1)) % kT
do k = 2, mat % n_nuclides
! Warn the user if the nuclides don't have identical temperatues.
if (nuclides(mat % nuclide(k)) % kT /= min_temp &
.and. .not. warning_given .and. multipole_active) then
call warning("OpenMC cannot &
&identify the temperature of at least one cell. For the &
&purposes of multipole cross section evaluations, all cells &
&with unknown temperature will be set to the coldest &
&temperature found in the nuclear data for that cell's &
&material")
warning_given = .true.
end if
min_temp = min(min_temp, nuclides(mat % nuclide(k)) % kT)
end do
! Set the temperature for this cell instance.
cells(i) % sqrtkT(j) = sqrt(min_temp)
end associate
end do
end do
end subroutine lookup_material_temperatures
end module initialize

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,7 @@ module material_header
type Material
integer :: id ! unique identifier
character(len=104) :: name = "" ! User-defined name
character(len=104) :: name = "" ! User-defined name
integer :: n_nuclides ! number of nuclides
integer, allocatable :: nuclide(:) ! index in nuclides array
real(8) :: density ! total atom density in atom/b-cm

View file

@ -1,14 +1,14 @@
module mesh
use constants
use global
use mesh_header
use search, only: binary_search
#ifdef MPI
use message_passing
#endif
use algorithm, only: binary_search
use constants
use global
use mesh_header
implicit none
contains

View file

@ -89,7 +89,7 @@ contains
end do
! ==========================================================================
! READ ALL ACE CROSS SECTION TABLES
! READ ALL MGXS CROSS SECTION TABLES
! Loop over all files
MATERIAL_LOOP: do i = 1, n_materials

View file

@ -19,7 +19,6 @@ module mgxs_header
type, abstract :: Mgxs
character(len=104) :: name ! name of dataset, e.g. 92235.03c
integer :: zaid ! Z and A identifier, e.g. 92235
real(8) :: awr ! Atomic Weight Ratio
real(8) :: kT ! temperature in MeV (k*T)
@ -29,7 +28,6 @@ module mgxs_header
contains
procedure(mgxs_init_file_), deferred :: init_file ! Initialize the data
procedure(mgxs_print_), deferred :: print ! Writes object info
procedure(mgxs_get_xs_), deferred :: get_xs ! Get the requested xs
procedure(mgxs_combine_), deferred :: combine ! initializes object
! Sample the outgoing energy from a fission event
@ -64,12 +62,6 @@ module mgxs_header
integer, intent(in) :: max_order ! Maximum requested order
end subroutine mgxs_init_file_
subroutine mgxs_print_(this, unit)
import Mgxs
class(Mgxs),intent(in) :: this
integer, optional, intent(in) :: unit
end subroutine mgxs_print_
pure function mgxs_get_xs_(this,xstype,gin,gout,uvw,mu) result(xs)
import Mgxs
class(Mgxs), intent(in) :: this
@ -150,7 +142,6 @@ module mgxs_header
contains
procedure :: init_file => mgxsiso_init_file ! Initialize Nuclidic MGXS Data
procedure :: print => mgxsiso_print ! Writes nuclide info
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
@ -181,7 +172,6 @@ module mgxs_header
contains
procedure :: init_file => mgxsang_init_file ! Initialize Nuclidic MGXS Data
procedure :: print => mgxsang_print ! Writes nuclide info
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
@ -211,11 +201,6 @@ module mgxs_header
else
this % kT = ZERO
end if
if (check_for_node(node_xsdata, "zaid")) then
call get_node_value(node_xsdata, "zaid", this % zaid)
else
this % zaid = 0
end if
if (check_for_node(node_xsdata, "awr")) then
call get_node_value(node_xsdata, "awr", this % awr)
else
@ -957,164 +942,6 @@ module mgxs_header
end subroutine mgxsang_init_file
!===============================================================================
! MGXS*_PRINT displays information about a continuous-energy neutron
! cross_section table and its reactions and secondary angle/energy distributions
!===============================================================================
subroutine mgxs_print(this, unit_)
class(Mgxs), intent(in) :: this
integer, intent(in) :: unit_
character(MAX_LINE_LEN) :: temp_str
! Basic nuclide information
write(unit_,*) 'MGXS Entry: ' // trim(this % name)
if (this % zaid > 0) then
write(unit_,*) ' ZAID = ' // trim(to_str(this % zaid))
else if (this % zaid < 0) then
write(unit_,*) ' Material id = ' // trim(to_str(-this % zaid))
end if
if (this % awr > ZERO) then
write(unit_,*) ' AWR = ' // trim(to_str(this % awr))
end if
if (this % kT > ZERO) then
write(unit_,*) ' kT = ' // trim(to_str(this % kT))
end if
if (this % scatt_type == ANGLE_LEGENDRE) then
temp_str = "Legendre"
write(unit_,*) ' Scattering Type = ' // trim(temp_str)
select type(this)
type is (MgxsIso)
temp_str = to_str(size(this % scatter % dist(1) % data,dim=1) - 1)
end select
write(unit_,*) ' Scattering Order = ' // trim(temp_str)
else if (this % scatt_type == ANGLE_HISTOGRAM) then
temp_str = "Histogram"
write(unit_,*) ' Scattering Type = ' // trim(temp_str)
select type(this)
type is (MgxsIso)
temp_str = to_str(size(this % scatter % dist(1) % data,dim=1))
end select
write(unit_,*) ' Num. Distribution Bins = ' // trim(temp_str)
else if (this % scatt_type == ANGLE_TABULAR) then
temp_str = "Tabular"
write(unit_,*) ' Scattering Type = ' // trim(temp_str)
select type(this)
type is (MgxsIso)
temp_str = to_str(size(this % scatter % dist(1) % data,dim=1))
end select
write(unit_,*) ' Num. Distribution Points = ' // trim(temp_str)
end if
write(unit_,*) ' Fissionable = ', this % fissionable
end subroutine mgxs_print
subroutine mgxsiso_print(this, unit)
class(MgxsIso), intent(in) :: this
integer, optional, intent(in) :: unit
integer :: unit_ ! unit to write to
integer :: size_total, size_scattmat, size_mgxs
integer :: gin
! set default unit for writing information
if (present(unit)) then
unit_ = unit
else
unit_ = OUTPUT_UNIT
end if
! Write Basic Nuclide Information
call mgxs_print(this, unit_)
! Determine size of mgxs and scattering matrices
size_scattmat = 0
do gin = 1, size(this % scatter % energy)
size_scattmat = size_scattmat + &
2 * size(this % scatter % energy(gin) % data) + &
size(this % scatter % dist(gin) % data)
end do
size_scattmat = size_scattmat + size(this % scatter % scattxs)
size_scattmat = size_scattmat * 8
size_mgxs = size(this % total) + size(this % absorption) + &
size(this % nu_fission) + size(this % k_fission) + &
size(this % fission) + size(this % chi)
size_mgxs = size_mgxs * 8
! Calculate total memory
size_total = size_scattmat + size_mgxs
! Write memory used
write(unit_,*) ' Memory Requirements'
write(unit_,*) ' Cross sections = ' // trim(to_str(size_mgxs)) // ' bytes'
write(unit_,*) ' Scattering Matrices = ' // &
trim(to_str(size_scattmat)) // ' bytes'
write(unit_,*) ' Total = ' // trim(to_str(size_total)) // ' bytes'
! Blank line at end of nuclide
write(unit_,*)
end subroutine mgxsiso_print
subroutine mgxsang_print(this, unit)
class(MgxsAngle), intent(in) :: this
integer, optional, intent(in) :: unit
integer :: unit_ ! unit to write to
integer :: size_total, size_scattmat, size_mgxs
integer :: ipol, iazi, gin
! set default unit for writing information
if (present(unit)) then
unit_ = unit
else
unit_ = OUTPUT_UNIT
end if
! Write Basic Nuclide Information
call mgxs_print(this, unit_)
write(unit_,*) ' # of Polar Angles = ' // trim(to_str(this % n_pol))
write(unit_,*) ' # of Azimuthal Angles = ' // trim(to_str(this % n_azi))
! Determine size of mgxs and scattering matrices
size_scattmat = 0
do ipol = 1, this % n_pol
do iazi = 1, this % n_azi
do gin = 1, size(this % scatter(iazi, ipol) % obj % energy)
size_scattmat = size_scattmat + &
2 * size(this % scatter(iazi, ipol) % obj % energy(gin) % data) + &
size(this % scatter(iazi, ipol) % obj % dist(gin) % data)
end do
size_scattmat = size_scattmat + &
size(this % scatter(iazi, ipol) % obj % scattxs)
end do
end do
size_scattmat = size_scattmat * 8
size_mgxs = size(this % total) + size(this % absorption) + &
size(this % nu_fission) + size(this % k_fission) + &
size(this % fission) + size(this % chi)
size_mgxs = size_mgxs * 8
! Calculate total memory
size_total = size_scattmat + size_mgxs
! Write memory used
write(unit_,*) ' Memory Requirements'
write(unit_,*) ' Cross sections = ' // trim(to_str(size_mgxs)) // ' bytes'
write(unit_,*) ' Scattering Matrices = ' // &
trim(to_str(size_scattmat)) // ' bytes'
write(unit_,*) ' Total = ' // trim(to_str(size_total)) // ' bytes'
! Blank line at end of nuclide
write(unit_,*)
end subroutine mgxsang_print
!===============================================================================
! MGXS*_GET_XS returns the requested data cross section data
!===============================================================================
@ -1319,7 +1146,6 @@ module mgxs_header
else
this % name = mat % name
end if
this % zaid = -mat % id
this % fissionable = mat % fissionable
this % scatt_type = scatt_type

View file

@ -28,13 +28,8 @@ contains
integer(HID_T) :: group_id
! Intermediate loading components
character(len=10) :: version
integer :: NMT
integer :: i, j
integer, allocatable :: MT(:)
logical :: accumulated_fission
character(len=24) :: MT_n ! Takes the form '/nuclide/reactions/MT???'
integer :: is_fissionable
character(len=10) :: version
associate (nuc => nuclides(i_table))
@ -80,111 +75,8 @@ contains
call read_dataset(multipole % curvefit, group_id, "curvefit")
! Delete ACE pointwise data
call read_dataset(nuc % n_grid, group_id, "n_grid")
deallocate(nuc % energy)
deallocate(nuc % total)
deallocate(nuc % elastic)
deallocate(nuc % fission)
deallocate(nuc % nu_fission)
deallocate(nuc % absorption)
allocate(nuc % energy(nuc % n_grid))
allocate(nuc % total(nuc % n_grid))
allocate(nuc % elastic(nuc % n_grid))
allocate(nuc % fission(nuc % n_grid))
allocate(nuc % nu_fission(nuc % n_grid))
allocate(nuc % absorption(nuc % n_grid))
nuc % total(:) = ZERO
nuc % absorption(:) = ZERO
nuc % fission(:) = ZERO
! Read in new energy axis (converting eV to MeV)
call read_dataset(nuc % energy, group_id, "energy_points")
nuc % energy = nuc % energy / 1.0e6_8
! Get count and list of MT tables
call read_dataset(NMT, group_id, "MT_count")
allocate(MT(NMT))
call read_dataset(MT, group_id, "MT_list")
call close_group(group_id)
accumulated_fission = .false.
! Loop over each MT entry and load it into a reaction.
do i = 1, NMT
write(MT_n, '(A, I3.3)') '/nuclide/reactions/MT', MT(i)
group_id = open_group(file_id, MT_n)
! Each MT needs to be treated slightly differently.
select case (MT(i))
case(ELASTIC)
call read_dataset(nuc % elastic, group_id, "MT_sigma")
nuc % total(:) = nuc % total + nuc % elastic
case(N_FISSION)
call read_dataset(nuc % fission, group_id, "MT_sigma")
nuc % total(:) = nuc % total + nuc % fission
nuc % absorption(:) = nuc % absorption + nuc % fission
accumulated_fission = .true.
case default
! Search through all of our secondary reactions
do j = 1, size(nuc % reactions)
if (nuc % reactions(j) % MT == MT(i)) then
! Match found
! Individual Fission components exist, so remove the combined
! fission cross section.
if ( (MT(i) == N_F .or. MT(i) == N_NF .or. MT(i) == N_2NF &
.or. MT(i) == N_3NF) .and. accumulated_fission) then
nuc % total(:) = nuc % total - nuc % fission
nuc % absorption(:) = nuc % absorption - nuc % fission
nuc % fission(:) = ZERO
accumulated_fission = .false.
end if
deallocate(nuc % reactions(j) % sigma)
allocate(nuc % reactions(j) % sigma(nuc % n_grid))
call read_dataset(nuc % reactions(j) % sigma, &
group_id, "MT_sigma")
call read_dataset(nuc % reactions(j) % Q_value, &
group_id, "Q_value")
call read_dataset(nuc % reactions(j) % threshold, &
group_id, "threshold")
nuc % reactions(j) % threshold = 1 ! TODO: reconsider implications.
nuc % reactions(j) % Q_value = nuc % reactions(j) % Q_value &
/ 1.0e6_8
! Accumulate total
if (MT(i) /= N_LEVEL .and. MT(i) <= N_DA) then
nuc % total(:) = nuc % total + nuc % reactions(j) % sigma
end if
! Accumulate absorption
if (MT(i) >= N_GAMMA .and. MT(i) <= N_DA) then
nuc % absorption(:) = nuc % absorption &
+ nuc % reactions(j) % sigma
end if
! Accumulate fission (if needed)
if ( (MT(i) == N_F .or. MT(i) == N_NF .or. MT(i) == N_2NF &
.or. MT(i) == N_3NF) ) then
nuc % fission(:) = nuc % fission + nuc % reactions(j) % sigma
nuc % absorption(:) = nuc % absorption &
+ nuc % reactions(j) % sigma
end if
end if
end do
end select
call close_group(group_id)
end do
! Close file
call file_close(file_id)

View file

@ -7,20 +7,21 @@ module nuclide_header
h5lget_name_by_idx_f, H5_INDEX_NAME_F, H5_ITER_INC_F
use h5lt, only: h5ltpath_valid_f
use algorithm, only: sort, find
use constants
use dict_header, only: DictIntInt
use endf, only: reaction_name, is_fission, is_disappearance
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
open_dataset, read_dataset, close_dataset, get_shape, get_datasets
use list_header, only: ListInt
use math, only: evaluate_legendre
use multipole_header, only: MultipoleArray
use product_header, only: AngleEnergyContainer
use reaction_header, only: Reaction
use secondary_uncorrelated, only: UncorrelatedAngleEnergy
use stl_vector, only: VectorInt
use stl_vector, only: VectorInt, VectorReal
use string
use urr_header, only: UrrData
use xml_interface
@ -32,29 +33,37 @@ module nuclide_header
! for continuous-energy neutron transport.
!===============================================================================
type :: Nuclide
! Nuclide meta-data
character(20) :: name ! name of nuclide, e.g. U235.71c
integer :: zaid ! Z and A identifier, e.g. 92235
integer :: metastable ! metastable state
real(8) :: awr ! Atomic Weight Ratio
real(8) :: kT ! temperature in MeV (k*T)
! Fission information
logical :: fissionable = .false. ! nuclide is fissionable?
! Energy grid information
integer :: n_grid ! # of nuclide grid points
type EnergyGrid
integer, allocatable :: grid_index(:) ! log grid mapping indices
real(8), allocatable :: energy(:) ! energy values corresponding to xs
end type EnergyGrid
! Microscopic cross sections
type SumXS
real(8), allocatable :: total(:) ! total cross section
real(8), allocatable :: elastic(:) ! elastic scattering
real(8), allocatable :: fission(:) ! fission
real(8), allocatable :: nu_fission(:) ! neutron production
real(8), allocatable :: absorption(:) ! absorption (MT > 100)
real(8), allocatable :: heating(:) ! heating
end type SumXS
type :: Nuclide
! Nuclide meta-data
character(20) :: name ! name of nuclide, e.g. U235.71c
integer :: Z ! atomic number
integer :: A ! mass number
integer :: metastable ! metastable state
real(8) :: awr ! Atomic Weight Ratio
real(8), allocatable :: kTs(:) ! temperature in MeV (k*T)
! Fission information
logical :: fissionable = .false. ! nuclide is fissionable?
! Energy grid for each temperature
type(EnergyGrid), allocatable :: grid(:)
! Microscopic cross sections
type(SumXS), allocatable :: sum_xs(:)
! Resonance scattering info
logical :: resonant = .false. ! resonant scatterer?
@ -77,7 +86,7 @@ module nuclide_header
! Unresolved resonance data
logical :: urr_present = .false.
integer :: urr_inelastic
type(UrrData), pointer :: urr_data => null()
type(UrrData), allocatable :: urr_data(:)
! Multipole data
logical :: mp_present = .false.
@ -94,7 +103,6 @@ module nuclide_header
contains
procedure :: clear => nuclide_clear
procedure :: print => nuclide_print
procedure :: from_hdf5 => nuclide_from_hdf5
procedure :: nu => nuclide_nu
procedure, private :: create_derived => nuclide_create_derived
@ -106,10 +114,8 @@ module nuclide_header
!===============================================================================
type Nuclide0K
character(10) :: nuclide ! name of nuclide, e.g. U-238
character(10) :: nuclide ! name of nuclide, e.g. U238
character(16) :: scheme = 'ares' ! target velocity sampling scheme
character(10) :: name ! name of nuclide, e.g. 92235.03c
character(10) :: name_0K ! name of 0K nuclide, e.g. 92235.00c
real(8) :: E_min = 0.01e-6_8 ! lower cutoff energy for res scattering
real(8) :: E_max = 1000.0e-6_8 ! upper cutoff energy for res scattering
end type Nuclide0K
@ -133,6 +139,7 @@ module nuclide_header
! Information for S(a,b) use
integer :: index_sab ! index in sab_tables (zero means no table)
integer :: last_index_sab = 0 ! index in sab_tables last used by this nuclide
integer :: index_temp_sab ! temperature index for sab_tables
real(8) :: elastic_sab ! microscopic elastic scattering on S(a,b) table
! Information for URR probability table use
@ -175,24 +182,27 @@ module nuclide_header
subroutine nuclide_clear(this)
class(Nuclide), intent(inout) :: this ! The Nuclide object to clear
if (associated(this % urr_data)) deallocate(this % urr_data)
if (associated(this % multipole)) deallocate(this % multipole)
end subroutine nuclide_clear
subroutine nuclide_from_hdf5(this, group_id)
class(Nuclide), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
subroutine nuclide_from_hdf5(this, group_id, temperature, method, tolerance)
class(Nuclide), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
type(VectorReal), intent(in) :: temperature ! list of desired temperatures
integer, intent(in) :: method
real(8), intent(in) :: tolerance
integer :: i
integer :: Z
integer :: A
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
integer(HID_T) :: energy_dset
integer(HID_T) :: energy_group, energy_dset
integer(HID_T) :: kT_group
integer(HID_T) :: rxs_group
integer(HID_T) :: rx_group
integer(HID_T) :: total_nu
@ -201,9 +211,14 @@ module nuclide_header
integer(SIZE_T) :: name_len, name_file_len
integer(HSIZE_T) :: j
integer(HSIZE_T) :: dims(1)
character(MAX_WORD_LEN) :: temp
type(VectorInt) :: MTs
character(MAX_WORD_LEN) :: temp_str
character(MAX_FILE_LEN), allocatable :: dset_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)
@ -212,29 +227,90 @@ module nuclide_header
! Get rid of leading '/'
this % name = trim(this % name(2:))
call read_attribute(Z, group_id, 'Z')
call read_attribute(A, group_id, 'A')
call read_attribute(this % Z, group_id, 'Z')
call read_attribute(this % A, group_id, 'A')
call read_attribute(this % metastable, group_id, 'metastable')
this % zaid = 1000*Z + A + 400*this % metastable
call read_attribute(this % awr, group_id, 'atomic_weight_ratio')
call read_attribute(this % kT, group_id, 'temperature')
kT_group = open_group(group_id, 'kTs')
! Read energy grid
energy_dset = open_dataset(group_id, 'energy')
call get_shape(energy_dset, dims)
this % n_grid = int(dims(1), 4)
allocate(this % energy(this % n_grid))
call read_dataset(this % energy, energy_dset)
call close_dataset(energy_dset)
! Determine temperatures available
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)))
temps_available(i) = temps_available(i) / K_BOLTZMANN
end do
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))
! Write warning for resonance scattering data if 0K is not available
if (abs(temp_actual - temp_desired) > 0 .and. temp_desired == 0) 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.")
end if
end if
else
call fatal_error("Nuclear data 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)
! TODO: Get bounding temperatures
call fatal_error("Temperature interpolation not yet implemented")
case (TEMPERATURE_MULTIPOLE)
! Add first available temperature
call temps_to_read % push_back(nint(temps_available(1)))
end select
! Sort temperatures to read
call sort(temps_to_read)
n_temperature = temps_to_read % size()
allocate(this % kTs(n_temperature))
allocate(this % grid(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))
! Read energy grid
energy_group = open_group(group_id, 'energy')
energy_dset = open_dataset(energy_group, temp_str)
call get_shape(energy_dset, dims)
allocate(this % grid(i) % energy(int(dims(1), 4)))
call read_dataset(this % grid(i) % energy, energy_dset)
call close_dataset(energy_dset)
call close_group(energy_group)
end do
call close_group(kT_group)
! 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, hdf5_err, name_len)
if (starts_with(temp, "reaction_")) then
call MTs % push_back(int(str_to_int(temp(10:12))))
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))))
end if
end do
@ -243,7 +319,8 @@ module nuclide_header
do i = 1, size(this % reactions)
rx_group = open_group(rxs_group, 'reaction_' // trim(&
zero_padded(MTs % data(i), 3)))
call this % reactions(i) % from_hdf5(rx_group)
call this % reactions(i) % from_hdf5(rx_group, temps_to_read)
call close_group(rx_group)
end do
call close_group(rxs_group)
@ -252,32 +329,42 @@ module nuclide_header
call h5ltpath_valid_f(group_id, 'urr', .true., exists, hdf5_err)
if (exists) then
this % urr_present = .true.
allocate(this % urr_data)
urr_group = open_group(group_id, 'urr')
call this % urr_data % from_hdf5(urr_group)
allocate(this % urr_data(n_temperature))
do i = 1, n_temperature
! Get temperature as a string
temp_str = trim(to_str(temps_to_read % data(i))) // "K"
! Read probability tables for i-th temperature
urr_group = open_group(group_id, 'urr/' // trim(temp_str))
call this % urr_data(i) % from_hdf5(urr_group)
call close_group(urr_group)
! Check for negative values
if (any(this % urr_data(i) % prob < ZERO)) then
call warning("Negative value(s) found on probability table &
&for nuclide " // this % name // " at " // trim(temp_str))
end if
end do
! if the inelastic competition flag indicates that the inelastic cross
! section should be determined from a normal reaction cross section, we
! need to get the index of the reaction
if (this % urr_data % inelastic_flag > 0) then
do i = 1, size(this % reactions)
if (this % reactions(i) % MT == this % urr_data % inelastic_flag) then
this % urr_inelastic = i
if (n_temperature > 0) then
if (this % urr_data(1) % inelastic_flag > 0) then
do i = 1, size(this % reactions)
if (this % reactions(i) % MT == this % urr_data(1) % inelastic_flag) then
this % urr_inelastic = i
end if
end do
! Abort if no corresponding inelastic reaction was found
if (this % urr_inelastic == NONE) then
call fatal_error("Could not find inelastic reaction specified on &
&unresolved resonance probability table.")
end if
end do
! Abort if no corresponding inelastic reaction was found
if (this % urr_inelastic == NONE) then
call fatal_error("Could not find inelastic reaction specified on &
&unresolved resonance probability table.")
end if
end if
! Check for negative values
if (any(this % urr_data % prob < ZERO)) then
call warning("Negative value(s) found on probability table &
&for nuclide " // this % name)
end if
end if
! Check for nu-total
@ -287,8 +374,8 @@ module nuclide_header
! Read total nu data
total_nu = open_dataset(nu_group, 'yield')
call read_attribute(temp, total_nu, 'type')
select case (temp)
call read_attribute(temp_str, total_nu, 'type')
select case (temp_str)
case ('Tabulated1D')
allocate(Tabulated1D :: this % total_nu)
case ('Polynomial')
@ -308,8 +395,8 @@ module nuclide_header
! Check to see if this is polynomial or tabulated data
fer_dset = open_dataset(fer_group, 'q_prompt')
call read_attribute(temp, fer_dset, 'type')
if (temp == 'Polynomial') then
call read_attribute(temp_str, fer_dset, 'type')
if (temp_str == 'Polynomial') then
! Read the prompt Q-value
allocate(Polynomial :: this % fission_q_prompt)
call this % fission_q_prompt % from_hdf5(fer_dset)
@ -320,7 +407,7 @@ module nuclide_header
fer_dset = open_dataset(fer_group, 'q_recoverable')
call this % fission_q_recov % from_hdf5(fer_dset)
call close_dataset(fer_dset)
else if (temp == 'Tabulated1D') then
else if (temp_str == 'Tabulated1D') then
! Read the prompt Q-value
allocate(Tabulated1D :: this % fission_q_prompt)
call this % fission_q_prompt % from_hdf5(fer_dset)
@ -345,108 +432,125 @@ module nuclide_header
subroutine nuclide_create_derived(this)
class(Nuclide), intent(inout) :: this
integer :: i
integer :: j
integer :: k
integer :: i, j, k
integer :: t
integer :: m
integer :: n
integer :: n_grid
integer :: i_fission
type(ListInt) :: MTs
integer :: n_temperature
type(VectorInt) :: MTs
! Allocate and initialize derived cross sections
allocate(this % total(this % n_grid))
allocate(this % elastic(this % n_grid))
allocate(this % fission(this % n_grid))
allocate(this % nu_fission(this % n_grid))
allocate(this % absorption(this % n_grid))
this % total(:) = ZERO
this % elastic(:) = ZERO
this % fission(:) = ZERO
this % nu_fission(:) = ZERO
this % absorption(:) = ZERO
n_temperature = size(this % kTs)
allocate(this % sum_xs(n_temperature))
do i = 1, n_temperature
! Allocate and initialize derived cross sections
n_grid = size(this % grid(i) % energy)
allocate(this % sum_xs(i) % total(n_grid))
allocate(this % sum_xs(i) % elastic(n_grid))
allocate(this % sum_xs(i) % fission(n_grid))
allocate(this % sum_xs(i) % nu_fission(n_grid))
allocate(this % sum_xs(i) % absorption(n_grid))
this % sum_xs(i) % total(:) = ZERO
this % sum_xs(i) % elastic(:) = ZERO
this % sum_xs(i) % fission(:) = ZERO
this % sum_xs(i) % nu_fission(:) = ZERO
this % sum_xs(i) % absorption(:) = ZERO
end do
i_fission = 0
do i = 1, size(this % reactions)
call MTs % append(this % reactions(i) % MT)
call MTs % push_back(this % reactions(i) % MT)
call this % reaction_index % add_key(this % reactions(i) % MT, i)
associate (rx => this % reactions(i))
j = rx % threshold
n = size(rx % sigma)
! Skip total inelastic level scattering, gas production cross sections
! (MT=200+), etc.
if (rx % MT == N_LEVEL .or. rx % MT == N_NONELASTIC) cycle
if (rx % MT > N_5N2P .and. rx % MT < N_P0) cycle
! Skip level cross sections if total is available
if (rx % MT >= N_P0 .and. rx % MT <= N_PC .and. MTs % contains(N_P)) cycle
if (rx % MT >= N_D0 .and. rx % MT <= N_DC .and. MTs % contains(N_D)) cycle
if (rx % MT >= N_T0 .and. rx % MT <= N_TC .and. MTs % contains(N_T)) cycle
if (rx % MT >= N_3HE0 .and. rx % MT <= N_3HEC .and. MTs % contains(N_3HE)) cycle
if (rx % MT >= N_A0 .and. rx % MT <= N_AC .and. MTs % contains(N_A)) cycle
if (rx % MT >= N_2N0 .and. rx % MT <= N_2NC .and. MTs % contains(N_2N)) cycle
if (rx % MT >= N_P0 .and. rx % MT <= N_PC .and. find(MTs, N_P) /= -1) cycle
if (rx % MT >= N_D0 .and. rx % MT <= N_DC .and. find(MTs, N_D) /= -1) cycle
if (rx % MT >= N_T0 .and. rx % MT <= N_TC .and. find(MTs, N_T) /= -1) cycle
if (rx % MT >= N_3HE0 .and. rx % MT <= N_3HEC .and. find(MTs, N_3HE) /= -1) cycle
if (rx % MT >= N_A0 .and. rx % MT <= N_AC .and. find(MTs, N_A) /= -1) cycle
if (rx % MT >= N_2N0 .and. rx % MT <= N_2NC .and. find(MTs, N_2N) /= -1) cycle
! Copy elastic
if (rx % MT == ELASTIC) this % elastic(:) = rx % sigma
do t = 1, n_temperature
j = rx % xs(t) % threshold
n = size(rx % xs(t) % value)
! Add contribution to total cross section
this % total(j:j+n-1) = this % total(j:j+n-1) + rx % sigma
! Copy elastic
if (rx % MT == ELASTIC) this % sum_xs(t) % elastic(:) = rx % xs(t) % value
! Add contribution to absorption cross section
if (is_disappearance(rx % MT)) then
this % absorption(j:j+n-1) = this % absorption(j:j+n-1) + rx % sigma
end if
! Add contribution to total cross section
this % sum_xs(t) % total(j:j+n-1) = this % sum_xs(t) % total(j:j+n-1) + &
rx % xs(t) % value
! Information about fission reactions
if (rx % MT == N_FISSION) then
allocate(this % index_fission(1))
elseif (rx % MT == N_F) then
allocate(this % index_fission(PARTIAL_FISSION_MAX))
this % has_partial_fission = .true.
end if
! Add contribution to absorption cross section
if (is_disappearance(rx % MT)) then
this % sum_xs(t) % absorption(j:j+n-1) = this % sum_xs(t) % &
absorption(j:j+n-1) + rx % xs(t) % value
end if
! Add contribution to fission cross section
if (is_fission(rx % MT)) then
this % fissionable = .true.
this % fission(j:j+n-1) = this % fission(j:j+n-1) + rx % sigma
! Also need to add fission cross sections to absorption
this % absorption(j:j+n-1) = this % absorption(j:j+n-1) + rx % sigma
! If total fission reaction is present, there's no need to store the
! reaction cross-section since it was copied to this % fission
if (rx % MT == N_FISSION) deallocate(rx % sigma)
! Keep track of this reaction for easy searching later
i_fission = i_fission + 1
this % index_fission(i_fission) = i
this % n_fission = this % n_fission + 1
! <<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<<<
! Before the secondary distribution refactor, when the angle/energy
! distribution was uncorrelated, no angle was actually sampled. With
! the refactor, an angle is always sampled for an uncorrelated
! distribution even when no angle distribution exists in the ACE file
! (isotropic is assumed). To preserve the RNG stream, we explicitly
! mark fission reactions so that we avoid the angle sampling.
do k = 1, size(rx % products)
if (rx % products(k) % particle == NEUTRON) then
do m = 1, size(rx % products(k) % distribution)
associate (aedist => rx % products(k) % distribution(m) % obj)
select type (aedist)
type is (UncorrelatedAngleEnergy)
aedist % fission = .true.
end select
end associate
end do
! Information about fission reactions
if (t == 1) then
if (rx % MT == N_FISSION) then
allocate(this % index_fission(1))
elseif (rx % MT == N_F) then
allocate(this % index_fission(PARTIAL_FISSION_MAX))
this % has_partial_fission = .true.
end if
end do
! <<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<<<
end if
end associate
end do
end if
! Add contribution to fission cross section
if (is_fission(rx % MT)) then
this % fissionable = .true.
this % sum_xs(t) % fission(j:j+n-1) = this % sum_xs(t) % &
fission(j:j+n-1) + rx % xs(t) % value
! Also need to add fission cross sections to absorption
this % sum_xs(t) % absorption(j:j+n-1) = this % sum_xs(t) % &
absorption(j:j+n-1) + rx % xs(t) % value
! If total fission reaction is present, there's no need to store the
! reaction cross-section since it was copied to this % fission
if (rx % MT == N_FISSION) deallocate(rx % xs(t) % value)
! Keep track of this reaction for easy searching later
if (t == 1) then
i_fission = i_fission + 1
this % index_fission(i_fission) = i
this % n_fission = this % n_fission + 1
! <<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<
! Before the secondary distribution refactor, when the angle/energy
! distribution was uncorrelated, no angle was actually sampled. With
! the refactor, an angle is always sampled for an uncorrelated
! distribution even when no angle distribution exists in the ACE file
! (isotropic is assumed). To preserve the RNG stream, we explicitly
! mark fission reactions so that we avoid the angle sampling.
do k = 1, size(rx % products)
if (rx % products(k) % particle == NEUTRON) then
do m = 1, size(rx % products(k) % distribution)
associate (aedist => rx % products(k) % distribution(m) % obj)
select type (aedist)
type is (UncorrelatedAngleEnergy)
aedist % fission = .true.
end select
end associate
end do
end if
end do
! <<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<
end if
end if ! fission
end do ! temperature
end associate ! rx
end do ! reactions
! Determine number of delayed neutron precursors
if (this % fissionable) then
@ -459,17 +563,16 @@ module nuclide_header
end if
! Calculate nu-fission cross section
if (this % fissionable) then
do i = 1, size(this % energy)
this % nu_fission(i) = this % nu(this % energy(i), EMISSION_TOTAL) * &
this % fission(i)
end do
else
this % nu_fission(:) = ZERO
end if
! Clear MTs set
call MTs % clear()
do t = 1, n_temperature
if (this % fissionable) then
do i = 1, size(this % sum_xs(t) % fission)
this % sum_xs(t) % nu_fission(i) = this % nu(this % grid(t) % energy(i), &
EMISSION_TOTAL) * this % sum_xs(t) % fission(i)
end do
else
this % sum_xs(t) % nu_fission(:) = ZERO
end if
end do
end subroutine nuclide_create_derived
!===============================================================================
@ -537,86 +640,4 @@ module nuclide_header
end function nuclide_nu
!===============================================================================
! NUCLIDE*_PRINT displays information about a continuous-energy neutron
! cross_section table and its reactions and secondary angle/energy distributions
!===============================================================================
subroutine nuclide_print(this, unit)
class(Nuclide), intent(in) :: this
integer, intent(in), optional :: unit
integer :: i ! loop index over nuclides
integer :: unit_ ! unit to write to
integer :: size_xs ! memory used for cross-sections (bytes)
integer :: size_urr ! memory used for probability tables (bytes)
! set default unit for writing information
if (present(unit)) then
unit_ = unit
else
unit_ = OUTPUT_UNIT
end if
! Initialize totals
size_urr = 0
size_xs = 0
! Basic nuclide information
write(unit_,*) 'Nuclide ' // trim(this % name)
write(unit_,*) ' zaid = ' // trim(to_str(this % zaid))
write(unit_,*) ' awr = ' // trim(to_str(this % awr))
write(unit_,*) ' kT = ' // trim(to_str(this % kT))
write(unit_,*) ' # of grid points = ' // trim(to_str(this % n_grid))
write(unit_,*) ' Fissionable = ', this % fissionable
write(unit_,*) ' # of fission reactions = ' // trim(to_str(this % n_fission))
write(unit_,*) ' # of reactions = ' // trim(to_str(size(this % reactions)))
! Information on each reaction
write(unit_,*) ' Reaction Q-value COM IE'
do i = 1, size(this % reactions)
associate (rxn => this % reactions(i))
write(unit_,'(3X,A11,1X,F8.3,3X,L1,3X,I6)') &
reaction_name(rxn % MT), rxn % Q_value, rxn % scatter_in_cm, &
rxn % threshold
! Accumulate data size
size_xs = size_xs + (this % n_grid - rxn%threshold + 1) * 8
end associate
end do
! Add memory required for summary reactions (total, absorption, fission,
! nu-fission)
size_xs = 8 * this % n_grid * 4
! Write information about URR probability tables
size_urr = 0
if (this % urr_present) then
associate(urr => this % urr_data)
write(unit_,*) ' Unresolved resonance probability table:'
write(unit_,*) ' # of energies = ' // trim(to_str(urr % n_energy))
write(unit_,*) ' # of probabilities = ' // trim(to_str(urr % n_prob))
write(unit_,*) ' Interpolation = ' // trim(to_str(urr % interp))
write(unit_,*) ' Inelastic flag = ' // trim(to_str(urr % inelastic_flag))
write(unit_,*) ' Absorption flag = ' // trim(to_str(urr % absorption_flag))
write(unit_,*) ' Multiply by smooth? ', urr % multiply_smooth
write(unit_,*) ' Min energy = ', trim(to_str(urr % energy(1)))
write(unit_,*) ' Max energy = ', trim(to_str(urr % energy(urr % n_energy)))
! Calculate memory used by probability tables and add to total
size_urr = urr % n_energy * (urr % n_prob * 6 + 1) * 8
end associate
end if
! Write memory used
write(unit_,*) ' Memory Requirements'
write(unit_,*) ' Cross sections = ' // trim(to_str(size_xs)) // ' bytes'
write(unit_,*) ' Probability Tables = ' // &
trim(to_str(size_urr)) // ' bytes'
! Blank line at end of nuclide
write(unit_,*)
end subroutine nuclide_print
end module nuclide_header

View file

@ -330,57 +330,6 @@ contains
end subroutine print_particle
!===============================================================================
! WRITE_XS_SUMMARY writes information about each nuclide and S(a,b) table to a
! file called cross_sections.out. This file shows the list of reactions as well
! as information about their secondary angle/energy distributions, how much
! memory is consumed, thresholds, etc.
!===============================================================================
subroutine write_xs_summary()
integer :: i ! loop index
integer :: unit_xs ! cross_sections.out file unit
character(MAX_FILE_LEN) :: path ! path of summary file
! Create filename for log file
path = trim(path_output) // "cross_sections.out"
! Open log file for writing
open(NEWUNIT=unit_xs, FILE=path, STATUS='replace', ACTION='write')
if (run_CE) then
! Write header
call header("CROSS SECTION TABLES", unit=unit_xs)
NUCLIDE_LOOP: do i = 1, n_nuclides_total
! Print information about nuclide
call nuclides(i) % print(unit=unit_xs)
end do NUCLIDE_LOOP
SAB_TABLES_LOOP: do i = 1, n_sab_tables
! Print information about S(a,b) table
call sab_tables(i) % print(unit=unit_xs)
end do SAB_TABLES_LOOP
else
! Write header
call header("MGXS LIBRARY TABLES", unit=unit_xs)
NuclideMG_LOOP: do i = 1, n_nuclides_total
! Print information about nuclide
call nuclides_mg(i) % obj % print(unit=unit_xs)
end do NuclideMG_LOOP
call header("MATERIAL MGXS TABLES", unit=unit_xs)
MATERIAL_LOOP: do i = 1, n_materials
! Print information about Materials
call macro_xs(i) % obj % print(unit=unit_xs)
end do MATERIAL_LOOP
end if
! Close cross section summary file
close(unit_xs)
end subroutine write_xs_summary
!===============================================================================
! PRINT_COLUMNS displays a header listing what physical values will displayed
! below them

View file

@ -88,6 +88,7 @@ module particle_header
! Temperature of the current cell
real(8) :: sqrtkT ! sqrt(k_Boltzmann * temperature) in MeV
real(8) :: last_sqrtKT ! last temperature
! Statistical data
integer :: n_collision ! # of collisions
@ -129,6 +130,7 @@ contains
this % cell_born = NONE
this % material = NONE
this % last_material = NONE
this % last_sqrtkT = NONE
this % wgt = ONE
this % last_wgt = ONE
this % absorb_wgt = ZERO

View file

@ -1,5 +1,6 @@
module physics
use algorithm, only: binary_search
use constants
use cross_section, only: elastic_xs_0K
use endf, only: reaction_name
@ -15,7 +16,6 @@ module physics
use physics_common
use random_lcg, only: prn, advance_prn_seed, prn_set_stream
use reaction_header, only: Reaction
use search, only: binary_search
use secondary_uncorrelated, only: UncorrelatedAngleEnergy
use string, only: to_str
@ -59,7 +59,7 @@ contains
! Advance URR seed stream 'N' times after energy changes
if (p % E /= p % last_E) then
call prn_set_stream(STREAM_URR_PTABLE)
call advance_prn_seed(n_nuc_zaid_total)
call advance_prn_seed(size(nuclides, kind=8))
call prn_set_stream(STREAM_TRACKING)
endif
@ -200,6 +200,7 @@ contains
integer :: i
integer :: i_grid
integer :: i_temp
real(8) :: f
real(8) :: prob
real(8) :: cutoff
@ -219,6 +220,7 @@ contains
end if
! Get grid index and interpolatoin factor and sample fission cdf
i_temp = micro_xs(i_nuclide) % index_temp
i_grid = micro_xs(i_nuclide) % index_grid
f = micro_xs(i_nuclide) % interp_factor
cutoff = prn() * micro_xs(i_nuclide) % fission
@ -229,13 +231,13 @@ contains
FISSION_REACTION_LOOP: do i = 1, nuc % n_fission
i_reaction = nuc % index_fission(i)
associate (rxn => nuc % reactions(i_reaction))
associate (xs => nuc % reactions(i_reaction) % xs(i_temp))
! if energy is below threshold for this reaction, skip it
if (i_grid < rxn % threshold) cycle
if (i_grid < xs % threshold) cycle
! add to cumulative probability
prob = prob + ((ONE - f)*rxn%sigma(i_grid - rxn%threshold + 1) &
+ f*(rxn%sigma(i_grid - rxn%threshold + 2)))
prob = prob + ((ONE - f) * xs % value(i_grid - xs % threshold + 1) &
+ f*(xs % value(i_grid - xs % threshold + 2)))
end associate
! Create fission bank sites if fission occurs
@ -294,6 +296,7 @@ contains
integer, intent(in) :: i_nuc_mat
integer :: i
integer :: i_temp
integer :: i_grid
real(8) :: f
real(8) :: prob
@ -301,6 +304,7 @@ contains
real(8) :: uvw_new(3) ! outgoing uvw for iso-in-lab scattering
real(8) :: uvw_old(3) ! incoming uvw for iso-in-lab scattering
real(8) :: phi ! azimuthal angle for iso-in-lab scattering
real(8) :: kT ! temperature in MeV
type(Nuclide), pointer :: nuc
! copy incoming direction
@ -308,6 +312,7 @@ contains
! Get pointer to nuclide and grid index/interpolation factor
nuc => nuclides(i_nuclide)
i_temp = micro_xs(i_nuclide) % index_temp
i_grid = micro_xs(i_nuclide) % index_grid
f = micro_xs(i_nuclide) % interp_factor
@ -328,8 +333,15 @@ contains
p % E, p % coord(1) % uvw, p % mu)
else
! Determine temperature
if (temperature_method == TEMPERATURE_MULTIPOLE) then
kT = p % sqrtkT**2
else
kT = nuc % kTs(micro_xs(i_nuclide) % index_temp)
end if
! Perform collision physics for elastic scattering
call elastic_scatter(i_nuclide, nuc % reactions(1), &
call elastic_scatter(i_nuclide, nuc % reactions(1), kT, &
p % E, p % coord(1) % uvw, p % mu, p % wgt)
end if
@ -352,22 +364,24 @@ contains
&// trim(nuc % name))
end if
associate (rxn => nuc % reactions(i))
associate (rx => nuc % reactions(i))
! Skip fission reactions
if (rxn % MT == N_FISSION .or. rxn % MT == N_F .or. rxn % MT == N_NF &
.or. rxn % MT == N_2NF .or. rxn % MT == N_3NF) cycle
if (rx % MT == N_FISSION .or. rx % MT == N_F .or. rx % MT == N_NF &
.or. rx % MT == N_2NF .or. rx % MT == N_3NF) cycle
! some materials have gas production cross sections with MT > 200 that
! are duplicates. Also MT=4 is total level inelastic scattering which
! should be skipped
if (rxn % MT >= 200 .or. rxn % MT == N_LEVEL) cycle
if (rx % MT >= 200 .or. rx % MT == N_LEVEL) cycle
! if energy is below threshold for this reaction, skip it
if (i_grid < rxn % threshold) cycle
associate (xs => rx % xs(i_temp))
! if energy is below threshold for this reaction, skip it
if (i_grid < xs % threshold) cycle
! add to cumulative probability
prob = prob + ((ONE - f)*rxn%sigma(i_grid - rxn%threshold + 1) &
+ f*(rxn%sigma(i_grid - rxn%threshold + 2)))
! add to cumulative probability
prob = prob + ((ONE - f)*xs % value(i_grid - xs % threshold + 1) &
+ f*(xs % value(i_grid - xs % threshold + 2)))
end associate
end associate
end do
@ -401,9 +415,10 @@ contains
! target.
!===============================================================================
subroutine elastic_scatter(i_nuclide, rxn, E, uvw, mu_lab, wgt)
subroutine elastic_scatter(i_nuclide, rxn, kT, E, uvw, mu_lab, wgt)
integer, intent(in) :: i_nuclide
type(Reaction), intent(in) :: rxn
real(8), intent(in) :: kT ! temperature in MeV
real(8), intent(inout) :: E
real(8), intent(inout) :: uvw(3)
real(8), intent(out) :: mu_lab
@ -430,7 +445,7 @@ contains
! Sample velocity of target nucleus
if (.not. micro_xs(i_nuclide) % use_ptable) then
call sample_target_velocity(nuc, v_t, E, uvw, v_n, wgt, &
& micro_xs(i_nuclide) % elastic)
micro_xs(i_nuclide) % elastic, kT)
else
v_t = ZERO
end if
@ -494,6 +509,7 @@ contains
integer :: i ! incoming energy bin
integer :: j ! outgoing energy bin
integer :: k ! outgoing cosine bin
integer :: i_temp ! temperature index
integer :: n_energy_out ! number of outgoing energy bins
real(8) :: f ! interpolation factor
real(8) :: r ! used for skewed sampling & continuous
@ -502,7 +518,6 @@ contains
real(8) :: mu_ijk ! outgoing cosine k for E_in(i) and E_out(j)
real(8) :: mu_i1jk ! outgoing cosine k for E_in(i+1) and E_out(j)
real(8) :: prob ! probability for sampling Bragg edge
type(SAlphaBeta), pointer :: sab
! Following are needed only for SAB_SECONDARY_CONT scattering
integer :: l ! sampled incoming E bin (is i or i + 1)
real(8) :: E_i_1, E_i_J ! endpoints on outgoing grid i
@ -514,213 +529,216 @@ contains
real(8) :: frac ! interpolation factor on outgoing energy
real(8) :: r1 ! RNG for outgoing energy
i_temp = micro_xs(i_nuclide) % index_temp_sab
! Get pointer to S(a,b) table
sab => sab_tables(i_sab)
associate (sab => sab_tables(i_sab) % data(i_temp))
! Determine whether inelastic or elastic scattering will occur
if (prn() < micro_xs(i_nuclide) % elastic_sab / &
micro_xs(i_nuclide) % elastic) then
! elastic scattering
! Determine whether inelastic or elastic scattering will occur
if (prn() < micro_xs(i_nuclide) % elastic_sab / &
micro_xs(i_nuclide) % elastic) then
! elastic scattering
! Get index and interpolation factor for elastic grid
if (E < sab % elastic_e_in(1)) then
i = 1
f = ZERO
else
i = binary_search(sab % elastic_e_in, sab % n_elastic_e_in, E)
f = (E - sab%elastic_e_in(i)) / &
(sab%elastic_e_in(i+1) - sab%elastic_e_in(i))
end if
! Select treatment based on elastic mode
if (sab % elastic_mode == SAB_ELASTIC_DISCRETE) then
! With this treatment, we interpolate between two discrete cosines
! corresponding to neighboring incoming energies. This is used for
! data derived in the incoherent approximation
! Sample outgoing cosine bin
k = 1 + int(prn() * sab % n_elastic_mu)
! Determine outgoing cosine corresponding to E_in(i) and E_in(i+1)
mu_ijk = sab % elastic_mu(k,i)
mu_i1jk = sab % elastic_mu(k,i+1)
! Cosine of angle between incoming and outgoing neutron
mu = (1 - f)*mu_ijk + f*mu_i1jk
elseif (sab % elastic_mode == SAB_ELASTIC_EXACT) then
! This treatment is used for data derived in the coherent
! approximation, i.e. for crystalline structures that have Bragg
! edges.
! Sample a Bragg edge between 1 and i
prob = prn() * sab % elastic_P(i+1)
if (prob < sab % elastic_P(1)) then
k = 1
! Get index and interpolation factor for elastic grid
if (E < sab % elastic_e_in(1)) then
i = 1
f = ZERO
else
k = binary_search(sab % elastic_P(1:i+1), i+1, prob)
i = binary_search(sab % elastic_e_in, sab % n_elastic_e_in, E)
f = (E - sab%elastic_e_in(i)) / &
(sab%elastic_e_in(i+1) - sab%elastic_e_in(i))
end if
! Characteristic scattering cosine for this Bragg edge
mu = ONE - TWO*sab % elastic_e_in(k) / E
! Select treatment based on elastic mode
if (sab % elastic_mode == SAB_ELASTIC_DISCRETE) then
! With this treatment, we interpolate between two discrete cosines
! corresponding to neighboring incoming energies. This is used for
! data derived in the incoherent approximation
end if
! Sample outgoing cosine bin
k = 1 + int(prn() * sab % n_elastic_mu)
! Outgoing energy is same as incoming energy -- no need to do anything
! Determine outgoing cosine corresponding to E_in(i) and E_in(i+1)
mu_ijk = sab % elastic_mu(k,i)
mu_i1jk = sab % elastic_mu(k,i+1)
else
! Perform inelastic calculations
! Cosine of angle between incoming and outgoing neutron
mu = (1 - f)*mu_ijk + f*mu_i1jk
! Get index and interpolation factor for inelastic grid
if (E < sab % inelastic_e_in(1)) then
i = 1
f = ZERO
else
i = binary_search(sab % inelastic_e_in, sab % n_inelastic_e_in, E)
f = (E - sab%inelastic_e_in(i)) / &
(sab%inelastic_e_in(i+1) - sab%inelastic_e_in(i))
end if
elseif (sab % elastic_mode == SAB_ELASTIC_EXACT) then
! This treatment is used for data derived in the coherent
! approximation, i.e. for crystalline structures that have Bragg
! edges.
! Now that we have an incoming energy bin, we need to determine the
! outgoing energy bin. This will depend on the "secondary energy
! mode". If the mode is 0, then the outgoing energy bin is chosen from a
! set of equally-likely bins. If the mode is 1, then the first
! two and last two bins are skewed to have lower probabilities than the
! other bins (0.1 for the first and last bins and 0.4 for the second and
! second to last bins, relative to a normal bin probability of 1).
! Finally, if the mode is 2, then a continuous distribution (with
! accompanying PDF and CDF is utilized)
if ((sab % secondary_mode == SAB_SECONDARY_EQUAL) .or. &
(sab % secondary_mode == SAB_SECONDARY_SKEWED)) then
if (sab % secondary_mode == SAB_SECONDARY_EQUAL) then
! All bins equally likely
j = 1 + int(prn() * sab % n_inelastic_e_out)
elseif (sab % secondary_mode == SAB_SECONDARY_SKEWED) then
! Distribution skewed away from edge points
! Determine number of outgoing energy and angle bins
n_energy_out = sab % n_inelastic_e_out
r = prn() * (n_energy_out - 3)
if (r > ONE) then
! equally likely N-4 middle bins
j = int(r) + 2
elseif (r > 0.6_8) then
! second to last bin has relative probability of 0.4
j = n_energy_out - 1
elseif (r > HALF) then
! last bin has relative probability of 0.1
j = n_energy_out
elseif (r > 0.1_8) then
! second bin has relative probability of 0.4
j = 2
! Sample a Bragg edge between 1 and i
prob = prn() * sab % elastic_P(i+1)
if (prob < sab % elastic_P(1)) then
k = 1
else
! first bin has relative probability of 0.1
j = 1
k = binary_search(sab % elastic_P(1:i+1), i+1, prob)
end if
! Characteristic scattering cosine for this Bragg edge
mu = ONE - TWO*sab % elastic_e_in(k) / E
end if
! Determine outgoing energy corresponding to E_in(i) and E_in(i+1)
E_ij = sab % inelastic_e_out(j,i)
E_i1j = sab % inelastic_e_out(j,i+1)
! Outgoing energy
E = (1 - f)*E_ij + f*E_i1j
! Sample outgoing cosine bin
k = 1 + int(prn() * sab % n_inelastic_mu)
! Determine outgoing cosine corresponding to E_in(i) and E_in(i+1)
mu_ijk = sab % inelastic_mu(k,j,i)
mu_i1jk = sab % inelastic_mu(k,j,i+1)
! Cosine of angle between incoming and outgoing neutron
mu = (1 - f)*mu_ijk + f*mu_i1jk
else if (sab % secondary_mode == SAB_SECONDARY_CONT) then
! Continuous secondary energy - this is to be similar to
! Law 61 interpolation on outgoing energy
! Sample between ith and (i+1)th bin
r = prn()
if (f > r) then
l = i + 1
else
l = i
end if
! Determine endpoints on grid i
n_energy_out = sab % inelastic_data(i) % n_e_out
E_i_1 = sab % inelastic_data(i) % e_out(1)
E_i_J = sab % inelastic_data(i) % e_out(n_energy_out)
! Determine endpoints on grid i + 1
n_energy_out = sab % inelastic_data(i + 1) % n_e_out
E_i1_1 = sab % inelastic_data(i + 1) % e_out(1)
E_i1_J = sab % inelastic_data(i + 1) % e_out(n_energy_out)
E_1 = E_i_1 + f * (E_i1_1 - E_i_1)
E_J = E_i_J + f * (E_i1_J - E_i_J)
! Determine outgoing energy bin
! (First reset n_energy_out to the right value)
n_energy_out = sab % inelastic_data(l) % n_e_out
r1 = prn()
c_j = sab % inelastic_data(l) % e_out_cdf(1)
do j = 1, n_energy_out - 1
c_j1 = sab % inelastic_data(l) % e_out_cdf(j + 1)
if (r1 < c_j1) exit
c_j = c_j1
end do
! check to make sure k is <= n_energy_out - 1
j = min(j, n_energy_out - 1)
! Get the data to interpolate between
E_l_j = sab % inelastic_data(l) % e_out(j)
p_l_j = sab % inelastic_data(l) % e_out_pdf(j)
! Next part assumes linear-linear interpolation in standard
E_l_j1 = sab % inelastic_data(l) % e_out(j + 1)
p_l_j1 = sab % inelastic_data(l) % e_out_pdf(j + 1)
! Find secondary energy (variable E)
frac = (p_l_j1 - p_l_j) / (E_l_j1 - E_l_j)
if (frac == ZERO) then
E = E_l_j + (r1 - c_j) / p_l_j
else
E = E_l_j + (sqrt(max(ZERO, p_l_j * p_l_j + &
TWO * frac * (r1 - c_j))) - p_l_j) / frac
end if
! Now interpolate between incident energy bins i and i + 1
if (l == i) then
E = E_1 + (E - E_i_1) * (E_J - E_1) / (E_i_J - E_i_1)
else
E = E_1 + (E - E_i1_1) * (E_J - E_1) / (E_i1_J - E_i1_1)
end if
! Find angular distribution for closest outgoing energy bin
if (r1 - c_j < c_j1 - r1) then
j = j
else
j = j + 1
end if
! Sample outgoing cosine bin
k = 1 + int(prn() * sab % n_inelastic_mu)
! Will use mu from the randomly chosen incoming and closest outgoing
! energy bins
mu = sab % inelastic_data(l) % mu(k, j)
! Outgoing energy is same as incoming energy -- no need to do anything
else
call fatal_error("Invalid secondary energy mode on S(a,b) table " &
&// trim(sab % name))
end if ! (inelastic secondary energy treatment)
end if ! (elastic or inelastic)
! Perform inelastic calculations
! Get index and interpolation factor for inelastic grid
if (E < sab % inelastic_e_in(1)) then
i = 1
f = ZERO
else
i = binary_search(sab % inelastic_e_in, sab % n_inelastic_e_in, E)
f = (E - sab%inelastic_e_in(i)) / &
(sab%inelastic_e_in(i+1) - sab%inelastic_e_in(i))
end if
! Now that we have an incoming energy bin, we need to determine the
! outgoing energy bin. This will depend on the "secondary energy
! mode". If the mode is 0, then the outgoing energy bin is chosen from a
! set of equally-likely bins. If the mode is 1, then the first
! two and last two bins are skewed to have lower probabilities than the
! other bins (0.1 for the first and last bins and 0.4 for the second and
! second to last bins, relative to a normal bin probability of 1).
! Finally, if the mode is 2, then a continuous distribution (with
! accompanying PDF and CDF is utilized)
if ((sab_tables(i_sab) % secondary_mode == SAB_SECONDARY_EQUAL) .or. &
(sab_tables(i_sab) % secondary_mode == SAB_SECONDARY_SKEWED)) then
if (sab_tables(i_sab) % secondary_mode == SAB_SECONDARY_EQUAL) then
! All bins equally likely
j = 1 + int(prn() * sab % n_inelastic_e_out)
elseif (sab_tables(i_sab) % secondary_mode == SAB_SECONDARY_SKEWED) then
! Distribution skewed away from edge points
! Determine number of outgoing energy and angle bins
n_energy_out = sab % n_inelastic_e_out
r = prn() * (n_energy_out - 3)
if (r > ONE) then
! equally likely N-4 middle bins
j = int(r) + 2
elseif (r > 0.6_8) then
! second to last bin has relative probability of 0.4
j = n_energy_out - 1
elseif (r > HALF) then
! last bin has relative probability of 0.1
j = n_energy_out
elseif (r > 0.1_8) then
! second bin has relative probability of 0.4
j = 2
else
! first bin has relative probability of 0.1
j = 1
end if
end if
! Determine outgoing energy corresponding to E_in(i) and E_in(i+1)
E_ij = sab % inelastic_e_out(j,i)
E_i1j = sab % inelastic_e_out(j,i+1)
! Outgoing energy
E = (1 - f)*E_ij + f*E_i1j
! Sample outgoing cosine bin
k = 1 + int(prn() * sab % n_inelastic_mu)
! Determine outgoing cosine corresponding to E_in(i) and E_in(i+1)
mu_ijk = sab % inelastic_mu(k,j,i)
mu_i1jk = sab % inelastic_mu(k,j,i+1)
! Cosine of angle between incoming and outgoing neutron
mu = (1 - f)*mu_ijk + f*mu_i1jk
else if (sab_tables(i_sab) % secondary_mode == SAB_SECONDARY_CONT) then
! Continuous secondary energy - this is to be similar to
! Law 61 interpolation on outgoing energy
! Sample between ith and (i+1)th bin
r = prn()
if (f > r) then
l = i + 1
else
l = i
end if
! Determine endpoints on grid i
n_energy_out = sab % inelastic_data(i) % n_e_out
E_i_1 = sab % inelastic_data(i) % e_out(1)
E_i_J = sab % inelastic_data(i) % e_out(n_energy_out)
! Determine endpoints on grid i + 1
n_energy_out = sab % inelastic_data(i + 1) % n_e_out
E_i1_1 = sab % inelastic_data(i + 1) % e_out(1)
E_i1_J = sab % inelastic_data(i + 1) % e_out(n_energy_out)
E_1 = E_i_1 + f * (E_i1_1 - E_i_1)
E_J = E_i_J + f * (E_i1_J - E_i_J)
! Determine outgoing energy bin
! (First reset n_energy_out to the right value)
n_energy_out = sab % inelastic_data(l) % n_e_out
r1 = prn()
c_j = sab % inelastic_data(l) % e_out_cdf(1)
do j = 1, n_energy_out - 1
c_j1 = sab % inelastic_data(l) % e_out_cdf(j + 1)
if (r1 < c_j1) exit
c_j = c_j1
end do
! check to make sure k is <= n_energy_out - 1
j = min(j, n_energy_out - 1)
! Get the data to interpolate between
E_l_j = sab % inelastic_data(l) % e_out(j)
p_l_j = sab % inelastic_data(l) % e_out_pdf(j)
! Next part assumes linear-linear interpolation in standard
E_l_j1 = sab % inelastic_data(l) % e_out(j + 1)
p_l_j1 = sab % inelastic_data(l) % e_out_pdf(j + 1)
! Find secondary energy (variable E)
frac = (p_l_j1 - p_l_j) / (E_l_j1 - E_l_j)
if (frac == ZERO) then
E = E_l_j + (r1 - c_j) / p_l_j
else
E = E_l_j + (sqrt(max(ZERO, p_l_j * p_l_j + &
TWO * frac * (r1 - c_j))) - p_l_j) / frac
end if
! Now interpolate between incident energy bins i and i + 1
if (l == i) then
E = E_1 + (E - E_i_1) * (E_J - E_1) / (E_i_J - E_i_1)
else
E = E_1 + (E - E_i1_1) * (E_J - E_1) / (E_i1_J - E_i1_1)
end if
! Find angular distribution for closest outgoing energy bin
if (r1 - c_j < c_j1 - r1) then
j = j
else
j = j + 1
end if
! Sample outgoing cosine bin
k = 1 + int(prn() * sab % n_inelastic_mu)
! Will use mu from the randomly chosen incoming and closest outgoing
! energy bins
mu = sab % inelastic_data(l) % mu(k, j)
else
call fatal_error("Invalid secondary energy mode on S(a,b) table " &
// trim(sab_tables(i_sab) % name))
end if ! (inelastic secondary energy treatment)
end if ! (elastic or inelastic)
end associate
! Because of floating-point roundoff, it may be possible for mu to be
! outside of the range [-1,1). In these cases, we just set mu to exactly
@ -741,19 +759,19 @@ contains
! implemented here.
!===============================================================================
subroutine sample_target_velocity(nuc, v_target, E, uvw, v_neut, wgt, xs_eff)
subroutine sample_target_velocity(nuc, v_target, E, uvw, v_neut, wgt, xs_eff, kT)
type(Nuclide), intent(in) :: nuc ! target nuclide at temperature T
real(8), intent(out) :: v_target(3) ! target velocity
real(8), intent(in) :: v_neut(3) ! neutron velocity
real(8), intent(in) :: E ! particle energy
real(8), intent(in) :: uvw(3) ! direction cosines
real(8), intent(in) :: v_neut(3) ! neutron velocity
real(8), intent(inout) :: wgt ! particle weight
real(8), intent(in) :: xs_eff ! effective elastic xs at temperature T
real(8), intent(in) :: kT ! equilibrium temperature of target in MeV
real(8) :: awr ! target/neutron mass ratio
real(8) :: kT ! equilibrium temperature of target in MeV
real(8) :: E_rel ! trial relative energy
real(8) :: xs_0K ! 0K xs at E_rel
real(8) :: xs_eff ! effective elastic xs at temperature T
real(8) :: wcf ! weight correction factor
real(8) :: E_red ! reduced energy (same as used by Cullen in SIGMA1)
real(8) :: E_low ! lowest practical relative energy
@ -782,7 +800,6 @@ contains
character(80) :: sampling_scheme ! method of target velocity sampling
kT = nuc % kT
awr = nuc % awr
! check if nuclide is a resonant scatterer
@ -817,12 +834,12 @@ contains
case ('cxs')
! sample target velocity with the constant cross section (cxs) approx.
call sample_cxs_target_velocity(nuc, v_target, E, uvw)
call sample_cxs_target_velocity(nuc, v_target, E, uvw, kT)
case ('wcm')
! sample target velocity with the constant cross section (cxs) approx.
call sample_cxs_target_velocity(nuc, v_target, E, uvw)
call sample_cxs_target_velocity(nuc, v_target, E, uvw, kT)
! adjust weight as prescribed by the weight correction method (wcm)
E_rel = dot_product((v_neut - v_target), (v_neut - v_target))
@ -874,7 +891,7 @@ contains
do
! sample target velocity with the constant cross section (cxs) approx.
call sample_cxs_target_velocity(nuc, v_target, E, uvw)
call sample_cxs_target_velocity(nuc, v_target, E, uvw, kT)
! perform Doppler broadening rejection correction (dbrc)
E_rel = dot_product((v_neut - v_target), (v_neut - v_target))
@ -986,13 +1003,13 @@ contains
! can be found in FRA-TM-123.
!===============================================================================
subroutine sample_cxs_target_velocity(nuc, v_target, E, uvw)
subroutine sample_cxs_target_velocity(nuc, v_target, E, uvw, kT)
type(Nuclide), intent(in) :: nuc ! target nuclide at temperature
real(8), intent(out) :: v_target(3)
real(8), intent(in) :: E
real(8), intent(in) :: uvw(3)
real(8), intent(in) :: kT ! equilibrium temperature of target in MeV
real(8) :: kT ! equilibrium temperature of target in MeV
real(8) :: awr ! target/neutron mass ratio
real(8) :: alpha ! probability of sampling f2 over f1
real(8) :: mu ! cosine of angle between neutron and target vel
@ -1004,7 +1021,6 @@ contains
real(8) :: beta_vt_sq ! (beta * speed of target)^2
real(8) :: vt ! speed of target
kT = nuc % kT
awr = nuc % awr
beta_vn = sqrt(awr * E / kT)

View file

@ -7,6 +7,7 @@ module reaction_header
use hdf5_interface, only: read_attribute, open_group, close_group, &
open_dataset, read_dataset, close_dataset, get_shape
use product_header, only: ReactionProduct
use stl_vector, only: VectorInt
use string, only: to_str, starts_with
implicit none
@ -16,12 +17,16 @@ module reaction_header
! distributions for a single reaction in a continuous-energy ACE-format table
!===============================================================================
type TemperatureXS
integer :: threshold ! Energy grid index of threshold
real(8), allocatable :: value(:) ! Cross section values
end type TemperatureXS
type Reaction
integer :: MT ! ENDF MT value
real(8) :: Q_value ! Reaction Q value
integer :: threshold ! Energy grid index of threshold
logical :: scatter_in_cm ! scattering system in center-of-mass?
real(8), allocatable :: sigma(:) ! Cross section values
type(TemperatureXS), allocatable :: xs(:)
type(ReactionProduct), allocatable :: products(:)
contains
procedure :: from_hdf5 => reaction_from_hdf5
@ -29,9 +34,10 @@ module reaction_header
contains
subroutine reaction_from_hdf5(this, group_id)
subroutine reaction_from_hdf5(this, group_id, temperatures)
class(Reaction), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
type(VectorInt), intent(in) :: temperatures
integer :: i
integer :: cm
@ -41,24 +47,31 @@ contains
integer :: n_links
integer :: hdf5_err
integer(HID_T) :: pgroup
integer(HID_T) :: xs
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'
call read_attribute(this % Q_value, group_id, 'Q_value')
call read_attribute(this % MT, group_id, 'mt')
call read_attribute(this % threshold, group_id, 'threshold_idx')
call read_attribute(cm, group_id, 'center_of_mass')
this % scatter_in_cm = (cm == 1)
! Read cross section
xs = open_dataset(group_id, 'xs')
call get_shape(xs, dims)
allocate(this % sigma(dims(1)))
call read_dataset(this % sigma, xs)
call close_dataset(xs)
! Read cross section and threshold_idx data
allocate(this % xs(temperatures % size()))
do i = 1, temperatures % size()
temp_str = trim(to_str(temperatures % data(i))) // "K"
temp_group = open_group(group_id, temp_str)
xs = open_dataset(temp_group, 'xs')
call read_attribute(this % xs(i) % threshold, xs, 'threshold_idx')
call get_shape(xs, dims)
allocate(this % xs(i) % value(dims(1)))
call read_dataset(this % xs(i) % value, xs)
call close_dataset(xs)
call close_group(temp_group)
end do
! Determine number of products
call h5gget_info_f(group_id, storage_type, n_links, max_corder, hdf5_err)

View file

@ -4,6 +4,8 @@ element materials {
(element name { xsd:string { maxLength="52" } } |
attribute name { xsd:string { maxLength="52" } })? &
element temperature { xsd:double }? &
element density {
(element value { xsd:double } | attribute value { xsd:double })? &
(element units { xsd:string { maxLength = "10" } } |
@ -12,8 +14,6 @@ element materials {
element nuclide {
(element name { xsd:string } | attribute name { xsd:string }) &
(element xs { xsd:string { maxLength = "5" } } |
attribute xs { xsd:string { maxLength = "5" } })? &
(element scattering { ( "data" | "iso-in-lab" ) } |
attribute scattering { ( "data" | "iso-in-lab" ) })? &
(
@ -24,16 +24,12 @@ element materials {
element macroscopic {
(element name { xsd:string } |
attribute name { xsd:string }) &
(element xs { xsd:string { maxLength = "5" } } |
attribute xs { xsd:string { maxLength = "5" } })
attribute name { xsd:string })
}* &
element element {
(element name { xsd:string { maxLength = "2" } } |
attribute name { xsd:string { maxLength = "2" } }) &
(element xs { xsd:string { maxLength = "5" } } |
attribute xs { xsd:string { maxLength = "5" } })? &
(element scattering { ( "data" | "iso-in-lab" ) } |
attribute scattering { ( "data" | "iso-in-lab" ) })? &
(
@ -43,11 +39,7 @@ element materials {
}* &
element sab {
(element name { xsd:string } | attribute name { xsd:string }) &
(element xs { xsd:string { maxLength = "5" } } |
attribute xs { xsd:string { maxLength = "5" } })?
(element name { xsd:string } | attribute name { xsd:string })
}*
}+ &
element default_xs { xsd:string { maxLength = "5" } }?
}+
}

View file

@ -1,248 +1,186 @@
<?xml version="1.0" encoding="UTF-8"?>
<element name="materials" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
<interleave>
<oneOrMore>
<element name="material">
<interleave>
<oneOrMore>
<element name="material">
<interleave>
<choice>
<element name="id">
<data type="int"/>
</element>
<attribute name="id">
<data type="int"/>
</attribute>
</choice>
<optional>
<choice>
<element name="id">
<data type="int"/>
<element name="name">
<data type="string">
<param name="maxLength">52</param>
</data>
</element>
<attribute name="id">
<data type="int"/>
<attribute name="name">
<data type="string">
<param name="maxLength">52</param>
</data>
</attribute>
</choice>
<optional>
</optional>
<optional>
<element name="temperature">
<data type="double"/>
</element>
</optional>
<element name="density">
<interleave>
<optional>
<choice>
<element name="value">
<data type="double"/>
</element>
<attribute name="value">
<data type="double"/>
</attribute>
</choice>
</optional>
<choice>
<element name="name">
<element name="units">
<data type="string">
<param name="maxLength">52</param>
<param name="maxLength">10</param>
</data>
</element>
<attribute name="name">
<attribute name="units">
<data type="string">
<param name="maxLength">52</param>
<param name="maxLength">10</param>
</data>
</attribute>
</choice>
</optional>
<element name="density">
</interleave>
</element>
<zeroOrMore>
<element name="nuclide">
<interleave>
<choice>
<element name="name">
<data type="string"/>
</element>
<attribute name="name">
<data type="string"/>
</attribute>
</choice>
<optional>
<choice>
<element name="value">
<data type="double"/>
<element name="scattering">
<choice>
<value>data</value>
<value>iso-in-lab</value>
</choice>
</element>
<attribute name="value">
<data type="double"/>
<attribute name="scattering">
<choice>
<value>data</value>
<value>iso-in-lab</value>
</choice>
</attribute>
</choice>
</optional>
<choice>
<element name="units">
<data type="string">
<param name="maxLength">10</param>
</data>
</element>
<attribute name="units">
<data type="string">
<param name="maxLength">10</param>
</data>
</attribute>
<choice>
<element name="ao">
<data type="double"/>
</element>
<attribute name="ao">
<data type="double"/>
</attribute>
</choice>
<choice>
<element name="wo">
<data type="double"/>
</element>
<attribute name="wo">
<data type="double"/>
</attribute>
</choice>
</choice>
</interleave>
</element>
<zeroOrMore>
<element name="nuclide">
<interleave>
</zeroOrMore>
<zeroOrMore>
<element name="macroscopic">
<choice>
<element name="name">
<data type="string"/>
</element>
<attribute name="name">
<data type="string"/>
</attribute>
</choice>
</element>
</zeroOrMore>
<zeroOrMore>
<element name="element">
<interleave>
<choice>
<element name="name">
<data type="string">
<param name="maxLength">2</param>
</data>
</element>
<attribute name="name">
<data type="string">
<param name="maxLength">2</param>
</data>
</attribute>
</choice>
<optional>
<choice>
<element name="name">
<data type="string"/>
<element name="scattering">
<choice>
<value>data</value>
<value>iso-in-lab</value>
</choice>
</element>
<attribute name="name">
<data type="string"/>
<attribute name="scattering">
<choice>
<value>data</value>
<value>iso-in-lab</value>
</choice>
</attribute>
</choice>
<optional>
<choice>
<element name="xs">
<data type="string">
<param name="maxLength">5</param>
</data>
</element>
<attribute name="xs">
<data type="string">
<param name="maxLength">5</param>
</data>
</attribute>
</choice>
</optional>
<optional>
<choice>
<element name="scattering">
<choice>
<value>data</value>
<value>iso-in-lab</value>
</choice>
</element>
<attribute name="scattering">
<choice>
<value>data</value>
<value>iso-in-lab</value>
</choice>
</attribute>
</choice>
</optional>
</optional>
<choice>
<choice>
<choice>
<element name="ao">
<data type="double"/>
</element>
<attribute name="ao">
<data type="double"/>
</attribute>
</choice>
<choice>
<element name="wo">
<data type="double"/>
</element>
<attribute name="wo">
<data type="double"/>
</attribute>
</choice>
</choice>
</interleave>
</element>
</zeroOrMore>
<zeroOrMore>
<element name="macroscopic">
<interleave>
<choice>
<element name="name">
<data type="string"/>
<element name="ao">
<data type="double"/>
</element>
<attribute name="name">
<data type="string"/>
<attribute name="ao">
<data type="double"/>
</attribute>
</choice>
<choice>
<element name="xs">
<data type="string">
<param name="maxLength">5</param>
</data>
<element name="wo">
<data type="double"/>
</element>
<attribute name="xs">
<data type="string">
<param name="maxLength">5</param>
</data>
<attribute name="wo">
<data type="double"/>
</attribute>
</choice>
</interleave>
</element>
</zeroOrMore>
<zeroOrMore>
<element name="element">
<interleave>
<choice>
<element name="name">
<data type="string">
<param name="maxLength">2</param>
</data>
</element>
<attribute name="name">
<data type="string">
<param name="maxLength">2</param>
</data>
</attribute>
</choice>
<optional>
<choice>
<element name="xs">
<data type="string">
<param name="maxLength">5</param>
</data>
</element>
<attribute name="xs">
<data type="string">
<param name="maxLength">5</param>
</data>
</attribute>
</choice>
</optional>
<optional>
<choice>
<element name="scattering">
<choice>
<value>data</value>
<value>iso-in-lab</value>
</choice>
</element>
<attribute name="scattering">
<choice>
<value>data</value>
<value>iso-in-lab</value>
</choice>
</attribute>
</choice>
</optional>
<choice>
<choice>
<element name="ao">
<data type="double"/>
</element>
<attribute name="ao">
<data type="double"/>
</attribute>
</choice>
<choice>
<element name="wo">
<data type="double"/>
</element>
<attribute name="wo">
<data type="double"/>
</attribute>
</choice>
</choice>
</interleave>
</element>
</zeroOrMore>
<zeroOrMore>
<element name="sab">
<interleave>
<choice>
<element name="name">
<data type="string"/>
</element>
<attribute name="name">
<data type="string"/>
</attribute>
</choice>
<optional>
<choice>
<element name="xs">
<data type="string">
<param name="maxLength">5</param>
</data>
</element>
<attribute name="xs">
<data type="string">
<param name="maxLength">5</param>
</data>
</attribute>
</choice>
</optional>
</interleave>
</element>
</zeroOrMore>
</interleave>
</element>
</oneOrMore>
<optional>
<element name="default_xs">
<data type="string">
<param name="maxLength">5</param>
</data>
</element>
</optional>
</interleave>
</choice>
</interleave>
</element>
</zeroOrMore>
<zeroOrMore>
<element name="sab">
<choice>
<element name="name">
<data type="string"/>
</element>
<attribute name="name">
<data type="string"/>
</attribute>
</choice>
</element>
</zeroOrMore>
</interleave>
</element>
</oneOrMore>
</element>

View file

@ -128,6 +128,12 @@ element settings {
element survival_biasing { xsd:boolean }? &
element temperature_default { xsd:double }? &
element temperature_method { xsd:string }? &
element temperature_tolerance { xsd:double }? &
element threads { xsd:positiveInteger }? &
element trace { list { xsd:positiveInteger+ } }? &
@ -170,10 +176,6 @@ element settings {
attribute nuclide { xsd:string { maxLength = "12" } }) &
(element method { xsd:string { maxLength = "16" } } |
attribute method { xsd:string { maxLength = "16" } }) &
(element xs_label { xsd:string { maxLength = "12" } } |
attribute xs_label { xsd:string { maxLength = "12" } }) &
(element xs_label_0K { xsd:string { maxLength = "12" } } |
attribute xs_label_0K { xsd:string { maxLength = "12" } }) &
(element E_min { xsd:double } |
attribute E_min { xsd:double }) &
(element E_max { xsd:double } |

View file

@ -565,6 +565,21 @@
<data type="boolean"/>
</element>
</optional>
<optional>
<element name="temperature_default">
<data type="double"/>
</element>
</optional>
<optional>
<element name="temperature_method">
<data type="string"/>
</element>
</optional>
<optional>
<element name="temperature_tolerance">
<data type="double"/>
</element>
</optional>
<optional>
<element name="threads">
<data type="positiveInteger"/>
@ -778,30 +793,6 @@
</data>
</attribute>
</choice>
<choice>
<element name="xs_label">
<data type="string">
<param name="maxLength">12</param>
</data>
</element>
<attribute name="xs_label">
<data type="string">
<param name="maxLength">12</param>
</data>
</attribute>
</choice>
<choice>
<element name="xs_label_0K">
<data type="string">
<param name="maxLength">12</param>
</data>
</element>
<attribute name="xs_label_0K">
<data type="string">
<param name="maxLength">12</param>
</data>
</attribute>
</choice>
<choice>
<element name="E_min">
<data type="double"/>

View file

@ -2,14 +2,18 @@ module sab_header
use, intrinsic :: ISO_FORTRAN_ENV
use algorithm, only: find, sort
use constants
use dict_header, only: DictIntInt
use distribution_univariate, only: Tabular
use hdf5, only: HID_T, HSIZE_T
use h5lt, only: h5ltpath_valid_f
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
open_dataset, read_dataset, close_dataset, get_datasets
use secondary_correlated, only: CorrelatedAngleEnergy
use string, only: to_str
use stl_vector, only: VectorInt, VectorReal
use string, only: to_str, str_to_int
implicit none
@ -32,13 +36,7 @@ module sab_header
! of light isotopes such as water, graphite, Be, etc
!===============================================================================
type SAlphaBeta
character(100) :: name ! name of table, e.g. lwtr.10t
real(8) :: awr ! weight of nucleus in neutron masses
real(8) :: kT ! temperature in MeV (k*T)
integer :: n_zaid ! Number of valid zaids
integer, allocatable :: zaid(:) ! List of valid Z and A identifiers, e.g. 6012
type SabData
! threshold for S(a,b) treatment (usually ~4 eV)
real(8) :: threshold_inelastic
real(8) :: threshold_elastic = ZERO
@ -47,7 +45,6 @@ module sab_header
integer :: n_inelastic_e_in ! # of incoming E for inelastic
integer :: n_inelastic_e_out ! # of outgoing E for inelastic
integer :: n_inelastic_mu ! # of outgoing angles for inelastic
integer :: secondary_mode ! secondary mode (equal/skewed/continuous)
real(8), allocatable :: inelastic_e_in(:)
real(8), allocatable :: inelastic_sigma(:)
! The following are used only if secondary_mode is 0 or 1
@ -66,104 +63,41 @@ module sab_header
real(8), allocatable :: elastic_e_in(:)
real(8), allocatable :: elastic_P(:)
real(8), allocatable :: elastic_mu(:,:)
end type SabData
type SAlphaBeta
character(100) :: 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
integer :: secondary_mode ! secondary mode (equal/skewed/continuous)
! cross sections and distributions at each temperature
type(SabData), allocatable :: data(:)
contains
procedure :: print => salphabeta_print
procedure :: from_hdf5 => salphabeta_from_hdf5
end type SAlphaBeta
contains
!===============================================================================
! PRINT_SAB_TABLE displays information about a S(a,b) table containing data
! describing thermal scattering from bound materials such as hydrogen in water.
!===============================================================================
subroutine salphabeta_print(this, unit)
class(SAlphaBeta), intent(in) :: this
integer, intent(in), optional :: unit
integer :: size_sab ! memory used by S(a,b) table
integer :: unit_ ! unit to write to
integer :: i ! Loop counter for parsing through this % zaid
integer :: char_count ! Counter for the number of characters on a line
! set default unit for writing information
if (present(unit)) then
unit_ = unit
else
unit_ = OUTPUT_UNIT
end if
! Basic S(a,b) table information
write(unit_,*) 'S(a,b) Table ' // trim(this % name)
write(unit_,'(A)',advance="no") ' zaids = '
! Initialize the counter based on the above string
char_count = 11
do i = 1, this % n_zaid
! Deal with a line thats too long
if (char_count >= 73) then ! 73 = 80 - (5 ZAID chars + 1 space + 1 comma)
! End the line
write(unit_,*) ""
! Add 11 leading blanks
write(unit_,'(A)', advance="no") " "
! reset the counter to 11
char_count = 11
end if
if (i < this % n_zaid) then
! Include a comma
write(unit_,'(A)',advance="no") trim(to_str(this % zaid(i))) // ", "
char_count = char_count + len(trim(to_str(this % zaid(i)))) + 2
else
! Don't include a comma, since we are all done
write(unit_,'(A)',advance="no") trim(to_str(this % zaid(i)))
end if
end do
write(unit_,*) "" ! Move to next line
write(unit_,*) ' awr = ' // trim(to_str(this % awr))
write(unit_,*) ' kT = ' // trim(to_str(this % kT))
! Inelastic data
write(unit_,*) ' # of Incoming Energies (Inelastic) = ' // &
trim(to_str(this % n_inelastic_e_in))
write(unit_,*) ' # of Outgoing Energies (Inelastic) = ' // &
trim(to_str(this % n_inelastic_e_out))
write(unit_,*) ' # of Outgoing Angles (Inelastic) = ' // &
trim(to_str(this % n_inelastic_mu))
write(unit_,*) ' Threshold for Inelastic = ' // &
trim(to_str(this % threshold_inelastic))
! Elastic data
if (this % n_elastic_e_in > 0) then
write(unit_,*) ' # of Incoming Energies (Elastic) = ' // &
trim(to_str(this % n_elastic_e_in))
write(unit_,*) ' # of Outgoing Angles (Elastic) = ' // &
trim(to_str(this % n_elastic_mu))
write(unit_,*) ' Threshold for Elastic = ' // &
trim(to_str(this % threshold_elastic))
end if
! Determine memory used by S(a,b) table and write out
size_sab = 8 * (this % n_inelastic_e_in * (2 + this % n_inelastic_e_out * &
(1 + this % n_inelastic_mu)) + this % n_elastic_e_in * &
(2 + this % n_elastic_mu))
write(unit_,*) ' Memory Used = ' // trim(to_str(size_sab)) // ' bytes'
! Blank line at end
write(unit_,*)
end subroutine salphabeta_print
subroutine salphabeta_from_hdf5(this, group_id)
subroutine salphabeta_from_hdf5(this, group_id, temperature, tolerance)
class(SAlphaBeta), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
type(VectorReal), intent(in) :: temperature ! list of temperatures
real(8), intent(in) :: tolerance
integer :: i, j
integer :: t
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(HID_T) :: T_group
integer(HID_T) :: elastic_group
integer(HID_T) :: inelastic_group
integer(HID_T) :: dset_id
integer(HID_T) :: kT_group
integer(HSIZE_T) :: dims2(2)
integer(HSIZE_T) :: dims3(3)
real(8), allocatable :: temp(:,:)
@ -171,143 +105,210 @@ contains
logical :: exists
type(CorrelatedAngleEnergy) :: correlated_dist
character(MAX_WORD_LEN) :: temp_str
character(MAX_FILE_LEN), allocatable :: dset_names(:)
real(8), allocatable :: temps_available(:) ! temperatures available
real(8) :: temp_desired
real(8) :: temp_actual
type(VectorInt) :: temps_to_read
! 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)
! Get rid of leading '/'
this % name = trim(this % name(2:))
call read_attribute(this % awr, group_id, 'atomic_weight_ratio')
call read_attribute(this % kT, group_id, 'temperature')
call read_attribute(this % zaid, group_id, 'zaids')
this % n_zaid = size(this % zaid)
call read_attribute(this % nuclides, group_id, 'nuclides')
call read_attribute(type, group_id, 'secondary_mode')
select case (type)
case ('equal')
this % secondary_mode = SAB_SECONDARY_EQUAL
case ('skewed')
this % secondary_mode = SAB_SECONDARY_SKEWED
case ('continuous')
this % secondary_mode = SAB_SECONDARY_CONT
end select
! Coherent elastic data
call h5ltpath_valid_f(group_id, 'elastic', .true., exists, hdf5_err)
if (exists) then
! Read cross section data
elastic_group = open_group(group_id, 'elastic')
dset_id = open_dataset(elastic_group, 'xs')
call read_attribute(type, dset_id, 'type')
call get_shape(dset_id, dims2)
allocate(temp(dims2(1), dims2(2)))
call read_dataset(temp, dset_id)
call close_dataset(dset_id)
! Read temperatures
kT_group = open_group(group_id, 'kTs')
! Set cross section data and type
this % n_elastic_e_in = int(dims2(1), 4)
allocate(this % elastic_e_in(this % n_elastic_e_in))
allocate(this % elastic_P(this % n_elastic_e_in))
this % elastic_e_in(:) = temp(:, 1)
this % elastic_P(:) = temp(:, 2)
select case (type)
case ('tab1')
this % elastic_mode = SAB_ELASTIC_DISCRETE
case ('bragg')
this % elastic_mode = SAB_ELASTIC_EXACT
end select
deallocate(temp)
! Determine temperatures available
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)))
temps_available(i) = temps_available(i) / K_BOLTZMANN
end do
! Set elastic threshold
this % threshold_elastic = this % elastic_e_in(this % n_elastic_e_in)
! Read angle distribution
if (this % elastic_mode /= SAB_ELASTIC_EXACT) then
dset_id = open_dataset(elastic_group, 'mu_out')
call get_shape(dset_id, dims2)
this % n_elastic_mu = int(dims2(1), 4)
allocate(this % elastic_mu(dims2(1), dims2(2)))
call read_dataset(this % elastic_mu, dset_id)
call close_dataset(dset_id)
! 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("Nuclear data 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
call close_group(elastic_group)
end if
! TODO: If using interpolation, add a block to add bounding temperatures for
! each
! Inelastic data
call h5ltpath_valid_f(group_id, 'inelastic', .true., exists, hdf5_err)
if (exists) then
! Read type of inelastic data
inelastic_group = open_group(group_id, 'inelastic')
call read_attribute(type, inelastic_group, 'secondary_mode')
select case (type)
case ('equal')
this % secondary_mode = SAB_SECONDARY_EQUAL
case ('skewed')
this % secondary_mode = SAB_SECONDARY_SKEWED
case ('continuous')
this % secondary_mode = SAB_SECONDARY_CONT
end select
! Sort temperatures to read
call sort(temps_to_read)
! Read cross section data
dset_id = open_dataset(inelastic_group, 'xs')
call get_shape(dset_id, dims2)
allocate(temp(dims2(1), dims2(2)))
call read_dataset(temp, dset_id)
call close_dataset(dset_id)
n_temperature = temps_to_read % size()
allocate(this % kTs(n_temperature))
allocate(this % data(n_temperature))
! Set cross section data
this % n_inelastic_e_in = int(dims2(1), 4)
allocate(this % inelastic_e_in(this % n_inelastic_e_in))
allocate(this % inelastic_sigma(this % n_inelastic_e_in))
this % inelastic_e_in(:) = temp(:, 1)
this % inelastic_sigma(:) = temp(:, 2)
deallocate(temp)
do t = 1, n_temperature
! Get temperature as a string
temp_str = trim(to_str(temps_to_read % data(t))) // "K"
! Set inelastic threshold
this % threshold_inelastic = this % inelastic_e_in(this % n_inelastic_e_in)
! Read exact temperature value
call read_dataset(this % kTs(t), kT_group, temp_str)
if (this % secondary_mode /= SAB_SECONDARY_CONT) then
! Read energy distribution
dset_id = open_dataset(inelastic_group, 'energy_out')
! Open group for temperature i
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
! Read cross section data
elastic_group = open_group(T_group, 'elastic')
dset_id = open_dataset(elastic_group, 'xs')
call read_attribute(type, dset_id, 'type')
call get_shape(dset_id, dims2)
this % n_inelastic_e_out = int(dims2(1), 4)
allocate(this % inelastic_e_out(dims2(1), dims2(2)))
call read_dataset(this % inelastic_e_out, dset_id)
allocate(temp(dims2(1), dims2(2)))
call read_dataset(temp, dset_id)
call close_dataset(dset_id)
! Set cross section data and type
this % data(t) % n_elastic_e_in = int(dims2(1), 4)
allocate(this % data(t) % elastic_e_in(this % data(t) % n_elastic_e_in))
allocate(this % data(t) % elastic_P(this % data(t) % n_elastic_e_in))
this % data(t) % elastic_e_in(:) = temp(:, 1)
this % data(t) % elastic_P(:) = temp(:, 2)
select case (type)
case ('tab1')
this % data(t) % elastic_mode = SAB_ELASTIC_DISCRETE
case ('bragg')
this % data(t) % elastic_mode = SAB_ELASTIC_EXACT
end select
deallocate(temp)
! Set elastic threshold
this % data(t) % threshold_elastic = this % data(t) % elastic_e_in(&
this % data(t) % n_elastic_e_in)
! Read angle distribution
dset_id = open_dataset(inelastic_group, 'mu_out')
call get_shape(dset_id, dims3)
this % n_inelastic_mu = int(dims3(1), 4)
allocate(this % inelastic_mu(dims3(1), dims3(2), dims3(3)))
call read_dataset(this % inelastic_mu, dset_id)
call close_dataset(dset_id)
else
! Read correlated angle-energy distribution
call correlated_dist % from_hdf5(inelastic_group)
if (this % data(t) % elastic_mode /= SAB_ELASTIC_EXACT) then
dset_id = open_dataset(elastic_group, 'mu_out')
call get_shape(dset_id, dims2)
this % data(t) % n_elastic_mu = int(dims2(1), 4)
allocate(this % data(t) % elastic_mu(dims2(1), dims2(2)))
call read_dataset(this % data(t) % elastic_mu, dset_id)
call close_dataset(dset_id)
end if
! Convert to S(a,b) native format
n_energy = size(correlated_dist % energy)
allocate(this % inelastic_data(n_energy))
do i = 1, n_energy
associate (edist => correlated_dist % distribution(i))
! Get number of outgoing energies for incoming energy i
n_energy_out = size(edist % e_out)
this % inelastic_data(i) % n_e_out = n_energy_out
allocate(this % inelastic_data(i) % e_out(n_energy_out))
allocate(this % inelastic_data(i) % e_out_pdf(n_energy_out))
allocate(this % inelastic_data(i) % e_out_cdf(n_energy_out))
! Copy outgoing energy distribution
this % inelastic_data(i) % e_out(:) = edist % e_out
this % inelastic_data(i) % e_out_pdf(:) = edist % p
this % inelastic_data(i) % e_out_cdf(:) = edist % c
do j = 1, n_energy_out
select type (adist => edist % angle(j) % obj)
type is (Tabular)
! On first pass, allocate space for angles
if (j == 1) then
n_mu = size(adist % x)
this % n_inelastic_mu = n_mu
allocate(this % inelastic_data(i) % mu(n_mu, n_energy_out))
end if
! Copy outgoing angles
this % inelastic_data(i) % mu(:, j) = adist % x
end select
end do
end associate
end do
call close_group(elastic_group)
end if
call close_group(inelastic_group)
end if
! Inelastic data
call h5ltpath_valid_f(T_group, 'inelastic', .true., exists, hdf5_err)
if (exists) then
! Read type of inelastic data
inelastic_group = open_group(T_group, 'inelastic')
! Read cross section data
dset_id = open_dataset(inelastic_group, 'xs')
call get_shape(dset_id, dims2)
allocate(temp(dims2(1), dims2(2)))
call read_dataset(temp, dset_id)
call close_dataset(dset_id)
! Set cross section data
this % data(t) % n_inelastic_e_in = int(dims2(1), 4)
allocate(this % data(t) % inelastic_e_in(this % data(t) % n_inelastic_e_in))
allocate(this % data(t) % inelastic_sigma(this % data(t) % n_inelastic_e_in))
this % data(t) % inelastic_e_in(:) = temp(:, 1)
this % data(t) % inelastic_sigma(:) = temp(:, 2)
deallocate(temp)
! Set inelastic threshold
this % data(t) % threshold_inelastic = this % data(t) % inelastic_e_in(&
this % data(t) % n_inelastic_e_in)
if (this % secondary_mode /= SAB_SECONDARY_CONT) then
! Read energy distribution
dset_id = open_dataset(inelastic_group, 'energy_out')
call get_shape(dset_id, dims2)
this % data(t) % n_inelastic_e_out = int(dims2(1), 4)
allocate(this % data(t) % inelastic_e_out(dims2(1), dims2(2)))
call read_dataset(this % data(t) % inelastic_e_out, dset_id)
call close_dataset(dset_id)
! Read angle distribution
dset_id = open_dataset(inelastic_group, 'mu_out')
call get_shape(dset_id, dims3)
this % data(t) % n_inelastic_mu = int(dims3(1), 4)
allocate(this % data(t) % inelastic_mu(dims3(1), dims3(2), dims3(3)))
call read_dataset(this % data(t) % inelastic_mu, dset_id)
call close_dataset(dset_id)
else
! Read correlated angle-energy distribution
call correlated_dist % from_hdf5(inelastic_group)
! Convert to S(a,b) native format
n_energy = size(correlated_dist % energy)
allocate(this % data(t) % inelastic_data(n_energy))
do i = 1, n_energy
associate (edist => correlated_dist % distribution(i))
! Get number of outgoing energies for incoming energy i
n_energy_out = size(edist % e_out)
this % data(t) % inelastic_data(i) % n_e_out = n_energy_out
allocate(this % data(t) % inelastic_data(i) % e_out(n_energy_out))
allocate(this % data(t) % inelastic_data(i) % e_out_pdf(n_energy_out))
allocate(this % data(t) % inelastic_data(i) % e_out_cdf(n_energy_out))
! Copy outgoing energy distribution
this % data(t) % inelastic_data(i) % e_out(:) = edist % e_out
this % data(t) % inelastic_data(i) % e_out_pdf(:) = edist % p
this % data(t) % inelastic_data(i) % e_out_cdf(:) = edist % c
do j = 1, n_energy_out
select type (adist => edist % angle(j) % obj)
type is (Tabular)
! On first pass, allocate space for angles
if (j == 1) then
n_mu = size(adist % x)
this % data(t) % n_inelastic_mu = n_mu
allocate(this % data(t) % inelastic_data(i) % mu(&
n_mu, n_energy_out))
end if
! Copy outgoing angles
this % data(t) % inelastic_data(i) % mu(:, j) = adist % x
end select
end do
end associate
end do
end if
call close_group(inelastic_group)
end if
call close_group(T_group)
end do
call close_group(kT_group)
end subroutine salphabeta_from_hdf5
end module sab_header

View file

@ -1,10 +1,10 @@
module scattdata_header
use algorithm, only: binary_search
use constants
use error, only: fatal_error
use math
use random_lcg, only: prn
use search, only: binary_search
implicit none

View file

@ -1,143 +0,0 @@
module search
use constants
implicit none
integer, parameter :: MAX_ITERATION = 64
interface binary_search
module procedure binary_search_real, binary_search_int4, binary_search_int8
end interface binary_search
contains
!===============================================================================
! BINARY_SEARCH performs a binary search of an array to find where a specific
! value lies in the array. This is used extensively for energy grid searching
!===============================================================================
pure function binary_search_real(array, n, val) result(array_index)
integer, intent(in) :: n
real(8), intent(in) :: array(n)
real(8), intent(in) :: val
integer :: array_index
integer :: L
integer :: R
integer :: n_iteration
L = 1
R = n
if (val < array(L) .or. val > array(R)) then
array_index = -1
return
end if
n_iteration = 0
do while (R - L > 1)
! Find values at midpoint
array_index = L + (R - L)/2
if (val >= array(array_index)) then
L = array_index
else
R = array_index
end if
! check for large number of iterations
n_iteration = n_iteration + 1
if (n_iteration == MAX_ITERATION) then
array_index = -2
return
end if
end do
array_index = L
end function binary_search_real
pure function binary_search_int4(array, n, val) result(array_index)
integer, intent(in) :: n
integer, intent(in) :: array(n)
integer, intent(in) :: val
integer :: array_index
integer :: L
integer :: R
integer :: n_iteration
L = 1
R = n
if (val < array(L) .or. val > array(R)) then
array_index = -1
return
end if
n_iteration = 0
do while (R - L > 1)
! Find values at midpoint
array_index = L + (R - L)/2
if (val >= array(array_index)) then
L = array_index
else
R = array_index
end if
! check for large number of iterations
n_iteration = n_iteration + 1
if (n_iteration == MAX_ITERATION) then
array_index = -2
return
end if
end do
array_index = L
end function binary_search_int4
pure function binary_search_int8(array, n, val) result(array_index)
integer, intent(in) :: n
integer(8), intent(in) :: array(n)
integer(8), intent(in) :: val
integer :: array_index
integer :: L
integer :: R
integer :: n_iteration
L = 1
R = n
if (val < array(L) .or. val > array(R)) then
array_index = -1
return
end if
n_iteration = 0
do while (R - L > 1)
! Find values at midpoint
array_index = L + (R - L)/2
if (val >= array(array_index)) then
L = array_index
else
R = array_index
end if
! check for large number of iterations
n_iteration = n_iteration + 1
if (n_iteration == MAX_ITERATION) then
array_index = -2
return
end if
end do
array_index = L
end function binary_search_int8
end module search

View file

@ -2,13 +2,13 @@ module secondary_correlated
use hdf5, only: HID_T, HSIZE_T
use algorithm, only: binary_search
use angleenergy_header, only: AngleEnergy
use constants, only: ZERO, ONE, HALF, TWO, HISTOGRAM, LINEAR_LINEAR
use distribution_univariate, only: DistributionContainer, Tabular
use hdf5_interface, only: get_shape, read_attribute, open_dataset, &
read_dataset, close_dataset
use random_lcg, only: prn
use search, only: binary_search
!===============================================================================
! CORRELATEDANGLEENERGY represents a correlated angle-energy distribution. This

View file

@ -2,12 +2,12 @@ module secondary_kalbach
use hdf5, only: HID_T, HSIZE_T
use algorithm, only: binary_search
use angleenergy_header, only: AngleEnergy
use constants, only: ZERO, HALF, ONE, TWO, HISTOGRAM, LINEAR_LINEAR
use hdf5_interface, only: read_attribute, read_dataset, open_dataset, &
close_dataset, get_shape
use random_lcg, only: prn
use search, only: binary_search
!===============================================================================
! KalbachMann represents a correlated angle-energy distribution with the angular

View file

@ -1,5 +1,11 @@
module source
use hdf5, only: HID_T
#ifdef MPI
use message_passing
#endif
use algorithm, only: binary_search
use bank_header, only: Bank
use constants
use distribution_univariate, only: Discrete
@ -12,17 +18,10 @@ module source
use output, only: write_message
use particle_header, only: Particle
use random_lcg, only: prn, set_particle_seed, prn_set_stream
use search, only: binary_search
use string, only: to_str
use math
use state_point, only: read_source_bank, write_source_bank
#ifdef MPI
use message_passing
#endif
use hdf5, only: HID_T
implicit none
contains

View file

@ -115,36 +115,31 @@ contains
integer :: i
character(12), allocatable :: nucnames(:)
real(8), allocatable :: awrs(:)
integer, allocatable :: zaids(:)
! Write useful data from nuclide objects
nuclide_group = create_group(file_id, "nuclides")
call write_dataset(nuclide_group, "n_nuclides_total", n_nuclides_total)
! Build array of nuclide names, awrs, and zaids
! Build array of nuclide names and awrs
allocate(nucnames(n_nuclides_total))
allocate(awrs(n_nuclides_total))
allocate(zaids(n_nuclides_total))
do i = 1, n_nuclides_total
if (run_CE) then
nucnames(i) = nuclides(i) % name
awrs(i) = nuclides(i) % awr
zaids(i) = nuclides(i) % zaid
else
nucnames(i) = nuclides_MG(i) % obj % name
awrs(i) = nuclides_MG(i) % obj % awr
zaids(i) = nuclides_MG(i) % obj % zaid
end if
end do
! Write nuclide names, awrs and zaids
! Write nuclide names and awrs
call write_dataset(nuclide_group, "names", nucnames)
call write_dataset(nuclide_group, "awrs", awrs)
call write_dataset(nuclide_group, "zaids", zaids)
call close_group(nuclide_group)
deallocate(nucnames, awrs, zaids)
deallocate(nucnames, awrs)
end subroutine write_nuclides
@ -527,10 +522,10 @@ contains
call write_dataset(material_group, "index", i)
! Write name for this material
call write_dataset(material_group, "name", m%name)
call write_dataset(material_group, "name", m % name)
! Write atom density with units
call write_dataset(material_group, "atom_density", m%density)
call write_dataset(material_group, "atom_density", m % density)
call write_attribute_string(material_group, "atom_density", "units", &
"atom/b-cm")
@ -572,7 +567,6 @@ contains
integer(HID_T), intent(in) :: file_id
integer :: i, j, k
integer :: i_xs
integer :: n_order ! loop index for moment orders
integer :: nm_order ! loop index for Ynm moment orders
integer(HID_T) :: tallies_group
@ -635,12 +629,7 @@ contains
allocate(str_array(t%n_nuclide_bins))
NUCLIDE_LOOP: do j = 1, t%n_nuclide_bins
if (t%nuclide_bins(j) > 0) then
i_xs = index(nuclides(t%nuclide_bins(j))%name, '.')
if (i_xs > 0) then
str_array(j) = nuclides(t%nuclide_bins(j))%name(1 : i_xs-1)
else
str_array(j) = nuclides(t%nuclide_bins(j))%name
end if
str_array(j) = nuclides(t % nuclide_bins(j)) % name
else
str_array(j) = 'total'
end if

View file

@ -1,5 +1,10 @@
module tally
#ifdef MPI
use message_passing
#endif
use algorithm, only: binary_search
use constants
use error, only: fatal_error
use geometry_header
@ -12,15 +17,10 @@ module tally
use mesh_header, only: RegularMesh
use output, only: header
use particle_header, only: LocalCoord, Particle
use search, only: binary_search
use string, only: to_str
use tally_header, only: TallyResult
use tally_filter
#ifdef MPI
use message_passing
#endif
implicit none
integer :: position(N_FILTER_TYPES - 3) = 0 ! Tally map positioning array
@ -89,6 +89,7 @@ contains
integer :: l ! loop index for nuclides in material
integer :: m ! loop index for reactions
integer :: q ! loop index for scoring bins
integer :: i_temp ! temperature index
integer :: i_nuc ! index in nuclides array (from material)
integer :: i_energy ! index in nuclide energy grid
integer :: score_bin ! scoring bin, e.g. SCORE_FLUX
@ -888,16 +889,18 @@ contains
if (i_nuclide > 0) then
if (nuclides(i_nuclide)%reaction_index%has_key(score_bin)) then
m = nuclides(i_nuclide)%reaction_index%get_key(score_bin)
associate (rxn => nuclides(i_nuclide) % reactions(m))
! Retrieve index on nuclide energy grid and interpolation
! factor
i_energy = micro_xs(i_nuclide) % index_grid
f = micro_xs(i_nuclide) % interp_factor
if (i_energy >= rxn % threshold) then
score = ((ONE - f) * rxn % sigma(i_energy - &
rxn%threshold + 1) + f * rxn % sigma(i_energy - &
rxn%threshold + 2)) * atom_density * flux
! Retrieve temperature and energy grid index and interpolation
! factor
i_temp = micro_xs(i_nuclide) % index_temp
i_energy = micro_xs(i_nuclide) % index_grid
f = micro_xs(i_nuclide) % interp_factor
associate (xs => nuclides(i_nuclide) % reactions(m) % xs(i_temp))
if (i_energy >= xs % threshold) then
score = ((ONE - f) * xs % value(i_energy - &
xs % threshold + 1) + f * xs % value(i_energy - &
xs % threshold + 2)) * atom_density * flux
end if
end associate
end if
@ -912,15 +915,18 @@ contains
if (nuclides(i_nuc)%reaction_index%has_key(score_bin)) then
m = nuclides(i_nuc)%reaction_index%get_key(score_bin)
associate (rxn => nuclides(i_nuc) % reactions(m))
! Retrieve index on nuclide energy grid and interpolation
! factor
i_energy = micro_xs(i_nuc) % index_grid
f = micro_xs(i_nuc) % interp_factor
if (i_energy >= rxn % threshold) then
score = score + ((ONE - f) * rxn % sigma(i_energy - &
rxn%threshold + 1) + f * rxn % sigma(i_energy - &
rxn%threshold + 2)) * atom_density_ * flux
! Retrieve temperature and energy grid index and interpolation
! factor
i_temp = micro_xs(i_nuc) % index_temp
i_energy = micro_xs(i_nuc) % index_grid
f = micro_xs(i_nuc) % interp_factor
associate (xs => nuclides(i_nuc) % reactions(m) % xs(i_temp))
if (i_energy >= xs % threshold) then
score = score + ((ONE - f) * xs % value(i_energy - &
xs % threshold + 1) + f * xs % value(i_energy - &
xs % threshold + 2)) * atom_density_ * flux
end if
end associate
end if

View file

@ -1,5 +1,6 @@
module tally_filter
use algorithm, only: binary_search
use constants, only: ONE, NO_BIN_FOUND, FP_PRECISION
use dict_header, only: DictIntInt
use geometry_header, only: BASE_UNIVERSE, RectLattice, HexLattice
@ -11,7 +12,6 @@ module tally_filter
mesh_intersects_1d, mesh_intersects_2d, &
mesh_intersects_3d
use particle_header, only: Particle
use search, only: binary_search
use string, only: to_str
use tally_filter_header, only: TallyFilter, TallyFilterContainer

View file

@ -84,9 +84,10 @@ contains
! Calculate microscopic and macroscopic cross sections
if (run_CE) then
! If the material is the same as the last material and the energy of the
! particle hasn't changed, we don't need to lookup cross sections again.
if (p % material /= p % last_material) call calculate_xs(p)
! If the material is the same as the last material and the temperature
! hasn't changed, we don't need to lookup cross sections again.
if (p % material /= p % last_material .or. &
p % sqrtkT /= p % last_sqrtkT) call calculate_xs(p)
else
! Since the MGXS can be angle dependent, this needs to be done
! After every collision for the MGXS mode

View file

@ -4,8 +4,8 @@
<group_structure> 0.0000000E+00 2.0000000E+01 </group_structure>
<xsdata>
<name> uo2_iso.71c </name>
<alias> uo2_iso.71c </alias>
<name> uo2_iso </name>
<alias> uo2_iso </alias>
<kT> 2.5300000E-08 </kT>
<order> 5 </order>
<fissionable> true </fissionable>
@ -44,8 +44,8 @@
</xsdata>
<xsdata>
<name> clad_iso.71c </name>
<alias> clad_iso.71c </alias>
<name> clad_iso </name>
<alias> clad_iso </alias>
<kT> 2.5300000E-08 </kT>
<order> 5 </order>
<fissionable> false </fissionable>
@ -75,8 +75,8 @@
</xsdata>
<xsdata>
<name> lwtr_iso.71c </name>
<alias> lwtr_iso.71c </alias>
<name> lwtr_iso </name>
<alias> lwtr_iso </alias>
<kT> 2.5300000E-08 </kT>
<order> 5 </order>
<fissionable> false </fissionable>
@ -106,8 +106,8 @@
</xsdata>
<xsdata>
<name> uo2_iso_mu.71c </name>
<alias> uo2_iso_mu.71c </alias>
<name> uo2_iso_mu </name>
<alias> uo2_iso_mu </alias>
<kT> 2.5300000E-08 </kT>
<order> 32 </order>
<fissionable> true </fissionable>
@ -199,8 +199,8 @@
</xsdata>
<xsdata>
<name> clad_iso_mu.71c </name>
<alias> clad_iso_mu.71c </alias>
<name> clad_iso_mu </name>
<alias> clad_iso_mu </alias>
<kT> 2.5300000E-08 </kT>
<order> 32 </order>
<fissionable> false </fissionable>
@ -283,8 +283,8 @@
</xsdata>
<xsdata>
<name> lwtr_iso_mu.71c </name>
<alias> lwtr_iso_mu.71c </alias>
<name> lwtr_iso_mu </name>
<alias> lwtr_iso_mu </alias>
<kT> 2.5300000E-08 </kT>
<order> 32 </order>
<fissionable> false </fissionable>
@ -367,8 +367,8 @@
</xsdata>
<xsdata>
<name> uo2_ang.71c </name>
<alias> uo2_ang.71c </alias>
<name> uo2_ang </name>
<alias> uo2_ang </alias>
<kT> 2.5300000E-08 </kT>
<order> 5 </order>
<fissionable> true </fissionable>
@ -1246,8 +1246,8 @@
</xsdata>
<xsdata>
<name> clad_ang.71c </name>
<alias> clad_ang.71c </alias>
<name> clad_ang </name>
<alias> clad_ang </alias>
<kT> 2.5300000E-08 </kT>
<order> 5 </order>
<fissionable> false </fissionable>
@ -1930,8 +1930,8 @@
</xsdata>
<xsdata>
<name> lwtr_ang.71c </name>
<alias> lwtr_ang.71c </alias>
<name> lwtr_ang </name>
<alias> lwtr_ang </alias>
<kT> 2.5300000E-08 </kT>
<order> 5 </order>
<fissionable> false </fissionable>
@ -2614,8 +2614,8 @@
</xsdata>
<xsdata>
<name> uo2_ang_mu.71c </name>
<alias> uo2_ang_mu.71c </alias>
<name> uo2_ang_mu </name>
<alias> uo2_ang_mu </alias>
<kT> 2.5300000E-08 </kT>
<order> 32 </order>
<fissionable> true </fissionable>
@ -5158,8 +5158,8 @@
</xsdata>
<xsdata>
<name> clad_ang_mu.71c </name>
<alias> clad_ang_mu.71c </alias>
<name> clad_ang_mu </name>
<alias> clad_ang_mu </alias>
<kT> 2.5300000E-08 </kT>
<order> 32 </order>
<fissionable> false </fissionable>
@ -7507,8 +7507,8 @@
</xsdata>
<xsdata>
<name> lwtr_ang_mu.71c </name>
<alias> lwtr_ang_mu.71c </alias>
<name> lwtr_ang_mu </name>
<alias> lwtr_ang_mu </alias>
<kT> 2.5300000E-08 </kT>
<order> 32 </order>
<fissionable> false </fissionable>

View file

@ -74,7 +74,7 @@ class InputSet(object):
cold_water.add_nuclide("O16", 1.0)
cold_water.add_nuclide("B10", 6.490e-4)
cold_water.add_nuclide("B11", 2.689e-3)
cold_water.add_s_alpha_beta('c_H_in_H2O', '71t')
cold_water.add_s_alpha_beta('c_H_in_H2O')
hot_water = openmc.Material(name='Hot borated water', material_id=4)
hot_water.set_density('atom/b-cm', 0.06614)
@ -82,7 +82,7 @@ class InputSet(object):
hot_water.add_nuclide("O16", 1.0)
hot_water.add_nuclide("B10", 6.490e-4)
hot_water.add_nuclide("B11", 2.689e-3)
hot_water.add_s_alpha_beta('c_H_in_H2O', '71t')
hot_water.add_s_alpha_beta('c_H_in_H2O')
rpv_steel = openmc.Material(name='Reactor pressure vessel steel',
material_id=5)
@ -139,7 +139,7 @@ class InputSet(object):
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', '71t')
lower_rad_ref.add_s_alpha_beta('c_H_in_H2O')
upper_rad_ref = openmc.Material(name='Upper radial reflector /'
'Top plate region', material_id=7)
@ -165,7 +165,7 @@ class InputSet(object):
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', '71t')
upper_rad_ref.add_s_alpha_beta('c_H_in_H2O')
bot_plate = openmc.Material(name='Bottom plate region', material_id=8)
bot_plate.set_density('g/cm3', 7.184)
@ -190,7 +190,7 @@ class InputSet(object):
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', '71t')
bot_plate.add_s_alpha_beta('c_H_in_H2O')
bot_nozzle = openmc.Material(name='Bottom nozzle region',
material_id=9)
@ -216,7 +216,7 @@ class InputSet(object):
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', '71t')
bot_nozzle.add_s_alpha_beta('c_H_in_H2O')
top_nozzle = openmc.Material(name='Top nozzle region', material_id=10)
top_nozzle.set_density('g/cm3', 1.746)
@ -241,7 +241,7 @@ class InputSet(object):
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', '71t')
top_nozzle.add_s_alpha_beta('c_H_in_H2O')
top_fa = openmc.Material(name='Top of fuel assemblies', material_id=11)
top_fa.set_density('g/cm3', 3.044)
@ -254,7 +254,7 @@ class InputSet(object):
top_fa.add_nuclide("Zr92", 0.14759527104, 'wo')
top_fa.add_nuclide("Zr94", 0.15280552077, 'wo')
top_fa.add_nuclide("Zr96", 0.02511169542, 'wo')
top_fa.add_s_alpha_beta('c_H_in_H2O', '71t')
top_fa.add_s_alpha_beta('c_H_in_H2O')
bot_fa = openmc.Material(name='Bottom of fuel assemblies',
material_id=12)
@ -268,10 +268,9 @@ class InputSet(object):
bot_fa.add_nuclide("Zr92", 0.1274914944, 'wo')
bot_fa.add_nuclide("Zr94", 0.1319920622, 'wo')
bot_fa.add_nuclide("Zr96", 0.0216912612, 'wo')
bot_fa.add_s_alpha_beta('c_H_in_H2O', '71t')
bot_fa.add_s_alpha_beta('c_H_in_H2O')
# Define the materials file.
self.materials.default_xs = '71c'
self.materials += (fuel, clad, cold_water, hot_water, rpv_steel,
lower_rad_ref, upper_rad_ref, bot_plate,
bot_nozzle, top_nozzle, top_fa, bot_fa)
@ -612,10 +611,9 @@ class PinCellInputSet(object):
hot_water.add_nuclide("O16", 2.4672e-2)
hot_water.add_nuclide("B10", 8.0042e-6)
hot_water.add_nuclide("B11", 3.2218e-5)
hot_water.add_s_alpha_beta('c_H_in_H2O', '71t')
hot_water.add_s_alpha_beta('c_H_in_H2O')
# Define the materials file.
self.materials.default_xs = '71c'
self.materials += (fuel, clad, hot_water)
# Instantiate ZCylinder surfaces
@ -714,10 +712,9 @@ class AssemblyInputSet(object):
hot_water.add_nuclide("O16", 2.4672e-2)
hot_water.add_nuclide("B10", 8.0042e-6)
hot_water.add_nuclide("B11", 3.2218e-5)
hot_water.add_s_alpha_beta('c_H_in_H2O', '71t')
hot_water.add_s_alpha_beta('c_H_in_H2O')
# Define the materials file.
self.materials.default_xs = '71c'
self.materials += (fuel, clad, hot_water)
# Instantiate ZCylinder surfaces
@ -829,23 +826,22 @@ class AssemblyInputSet(object):
class MGInputSet(InputSet):
def build_default_materials_and_geometry(self):
# Define materials needed for 1D/1G slab problem
uo2_data = openmc.Macroscopic('uo2_iso', '71c')
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_ang_mu', '71c')
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)
water_data = openmc.Macroscopic('lwtr_iso_mu', '71c')
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)
# Define the materials file.
self.materials.default_xs = '71c'
self.materials += (uo2, clad, water)
# Define surfaces.

View file

@ -1 +1 @@
a55899cd2ed0a8ec5d44003139da639f87f5f03ee76b2d6577db6a8c2014849e4277f8e68fa874ac6795e4cbc4eb6e4031d726cafe6e663e84787d1ecd8e7f86
dfb59bace10a91bb7ffc871d8ee87e91d94754bb8bb002ac6088f80fe0f480741c0489f74b753fc37158d0ff0f1368739ea60638b42083791311eefeac79168e

View file

@ -1,12 +1,12 @@
<?xml version="1.0"?>
<materials>
<!-- Definition of materials -->
<!-- Definition of materials -->
<material id="1">
<density value="19" units="g/cc" />
<nuclide name="U235" xs="71c" wo="0.21" />
<nuclide name="U238" xs="71c" wo="0.68" />
<nuclide name="O16" xs="71c" wo="0.11" />
<nuclide name="U235" wo="0.21" />
<nuclide name="U238" wo="0.68" />
<nuclide name="O16" wo="0.11" />
</material>
</materials>

View file

@ -1,12 +1,12 @@
<?xml version="1.0"?>
<materials>
<!-- Definition of materials -->
<!-- Definition of materials -->
<material id="1">
<density value="19" units="g/cc" />
<nuclide name="U235" xs="71c" wo="0.21" />
<nuclide name="U238" xs="71c" wo="0.68" />
<nuclide name="O16" xs="71c" wo="0.11" />
<nuclide name="U235" wo="0.21" />
<nuclide name="U238" wo="0.68" />
<nuclide name="O16" wo="0.11" />
</material>
</materials>

View file

@ -1,8 +1,6 @@
<?xml version="1.0"?>
<materials>
<default_xs>71c</default_xs>
<material id="1">
<density value="4.5" units="g/cc" />
<nuclide name="U235" ao="1.0" />

View file

@ -2,8 +2,9 @@
<materials>
<material id="1">
<temperature>294</temperature>
<density value="4.5" units="g/cc" />
<nuclide name="U235" xs="71c" ao="1.0" />
<nuclide name="U235" ao="1.0" />
</material>
</materials>

View file

@ -3,24 +3,24 @@
<material id="1">
<density value="0.1" units="atom/b-cm" />
<nuclide name="U235" xs="71c" ao="1.0" />
<nuclide name="U235" ao="1.0" />
</material>
<material id="2">
<density value="4.5e22" units="atom/cm3" />
<nuclide name="U235" xs="71c" ao="1.0" />
<nuclide name="U235" ao="1.0" />
</material>
<material id="3">
<density value="12.3e3" units="kg/m3" />
<nuclide name="U235" xs="71c" ao="1.0" />
<nuclide name="U235" ao="1.0" />
</material>
<material id="4">
<density units="sum" />
<nuclide name="U235" xs="71c" ao="0.3e-2" />
<nuclide name="U238" xs="71c" ao="0.5e-1" />
<nuclide name="H1" xs="71c" ao="0.1e-2" />
<nuclide name="U235" ao="0.3e-2" />
<nuclide name="U238" ao="0.5e-1" />
<nuclide name="H1" ao="0.1e-2" />
</material>
</materials>

View file

@ -1 +1 @@
46df57157980545d90b482acfb01f525b84c0e623fa93a5d9c08a65723d677ef1c092360219a3c7fcf5110c6ba32f1eacbd5c5eaed40be4bfe154f302400c0a4
6ae54c198e7659503d297e40be746a5bd72b35909fceed4b3ef357876b781946c0ea5021342556ef21f4034fa9e42b2c6014077c0efd3459dc063e6da4b12b59

View file

@ -29,7 +29,6 @@ class DistribmatTestHarness(PyAPITestHarness):
light_fuel.add_nuclide('U235', 1.0)
mats_file = openmc.Materials([moderator, dense_fuel, light_fuel])
mats_file.default_xs = '71c'
mats_file.export_to_xml()

View file

@ -3,7 +3,7 @@
<material id="1">
<density value="4.5" units="g/cc" />
<nuclide name="U235" xs="71c" ao="1.0" />
<nuclide name="U235" ao="1.0" />
</material>
</materials>

View file

@ -3,7 +3,7 @@
<material id="1">
<density value="4.5" units="g/cc" />
<nuclide name="U235" xs="71c" ao="1.0" />
<nuclide name="U235" ao="1.0" />
</material>
</materials>

View file

@ -3,9 +3,9 @@
<material id="1">
<density value="4.5" units="g/cc" />
<nuclide name="U235" xs="71c" ao="1.0" />
<nuclide name="H1" xs="71c" ao="0.5" />
<nuclide name="C0" xs="71c" ao="0.5" />
<nuclide name="U235" ao="1.0" />
<nuclide name="H1" ao="0.5" />
<nuclide name="C0" ao="0.5" />
</material>
</materials>

View file

@ -1,7 +1,7 @@
<?xml version="1.0"?>
<settings>
<energy_grid>nuclide</energy_grid>
<log_grid_bins>20000</log_grid_bins>
<eigenvalue>
<batches>10</batches>

View file

@ -1,6 +1,5 @@
<?xml version="1.0"?>
<materials>
<default_xs>71c</default_xs>
<material id="1">
<density value="20" units="g/cc" />
<nuclide name="U233" ao="1.0" />

View file

@ -3,7 +3,7 @@
<material id="1">
<density value="4.5" units="g/cc" />
<nuclide name="U235" xs="71c" ao="1.0" />
<nuclide name="U235" ao="1.0" />
</material>
</materials>

View file

@ -1,8 +1,6 @@
<?xml version="1.0"?>
<materials>
<default_xs>71c</default_xs>
<!-- Definition of materials -->
<material id="1">
<density value="4.5" units="g/cc" />

View file

@ -1,9 +1,6 @@
<?xml version="1.0"?>
<materials>
<default_xs>71c</default_xs>
<!-- Definition of materials -->
<material id="1">
<density value="4.5" units="g/cc" />
<nuclide name="U235" ao="1.0" />

View file

@ -1,8 +1,6 @@
<?xml version="1.0"?>
<materials>
<default_xs>71c</default_xs>
<!-- Fuel composition -->
<material id="1">
<density value="10.062" units="g/cm3" />

View file

@ -1,18 +1,19 @@
<?xml version='1.0' encoding='utf-8'?>
<materials>
<default_xs>71c</default_xs>
<material id="1" name="fuel">
<density units="g/cc" value="4.5" />
<nuclide ao="1.0" name="U235" />
<material id="1" name="fuel">
<density units="g/cc" value="4.5" />
<nuclide ao="1.0" name="U235" />
</material>
<material id="2" name="moderator">
<density units="g/cc" value="1.0" />
<nuclide ao="1.0" name="O16" />
<nuclide ao="2.0" name="H1" />
<sab name="c_H_in_H2O" xs="71t" />
<material id="2" name="moderator">
<density units="g/cc" value="1.0" />
<nuclide ao="1.0" name="O16" />
<nuclide ao="2.0" name="H1" />
<sab name="c_H_in_H2O" />
</material>
<material id="3" name="iron">
<density units="g/cc" value="7.9" />
<nuclide ao="1.0" name="Fe56" />
<material id="3" name="iron">
<density units="g/cc" value="7.9" />
<nuclide ao="1.0" name="Fe56" />
</material>
</materials>

View file

@ -1,8 +1,6 @@
<?xml version="1.0"?>
<materials>
<default_xs>71c</default_xs>
<!-- Fuel composition -->
<material id="1">
<density value="10.062" units="g/cm3" />
@ -59,7 +57,7 @@
<nuclide name="O16" ao="1.0" />
<nuclide name="B10" ao="6.490e-4" />
<nuclide name="B11" ao="2.689e-3" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
<!-- Hot borated water -->
@ -69,7 +67,7 @@
<nuclide name="O16" ao="1.0" />
<nuclide name="B10" ao="6.490e-4" />
<nuclide name="B11" ao="2.689e-3" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
<!-- RPV Composition -->
@ -128,7 +126,7 @@
<nuclide name="Cr52" wo="0.145407678031" />
<nuclide name="Cr53" wo="0.016806340306" />
<nuclide name="Cr54" wo="0.004261520857" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
<!-- Upper radial reflector / Top plate region -->
@ -155,7 +153,7 @@
<nuclide name="Cr52" wo="0.146766614995" />
<nuclide name="Cr53" wo="0.01696340737" />
<nuclide name="Cr54" wo="0.004301347765" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
<!-- Bottom plate region -->
@ -182,7 +180,7 @@
<nuclide name="Cr52" wo="0.157390026871" />
<nuclide name="Cr53" wo="0.018191270146" />
<nuclide name="Cr54" wo="0.004612692337" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
<!-- Bottom nozzle region -->
@ -209,7 +207,7 @@
<nuclide name="Cr52" wo="0.124142524198" />
<nuclide name="Cr53" wo="0.014348496148" />
<nuclide name="Cr54" wo="0.003638294506" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
<!-- Top nozzle region -->
@ -236,7 +234,7 @@
<nuclide name="Cr52" wo="0.107931450781" />
<nuclide name="Cr53" wo="0.012474806806" />
<nuclide name="Cr54" wo="0.003163190107" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
<!-- Top of Fuel Assemblies -->
@ -251,7 +249,7 @@
<nuclide name="Zr92" wo="0.14759527104" />
<nuclide name="Zr94" wo="0.15280552077" />
<nuclide name="Zr96" wo="0.02511169542" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
<!-- Bottom of Fuel Assemblies -->
@ -266,7 +264,7 @@
<nuclide name="Zr92" wo="0.1274914944" />
<nuclide name="Zr94" wo="0.1319920622" />
<nuclide name="Zr96" wo="0.0216912612" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
</materials>

View file

@ -1,8 +1,6 @@
<?xml version="1.0"?>
<materials>
<default_xs>71c</default_xs>
<!-- Fuel composition -->
<material id="1">
<density value="10.062" units="g/cm3" />
@ -59,7 +57,7 @@
<nuclide name="O16" ao="1.0" />
<nuclide name="B10" ao="6.490e-4" />
<nuclide name="B11" ao="2.689e-3" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
<!-- Hot borated water -->
@ -69,7 +67,7 @@
<nuclide name="O16" ao="1.0" />
<nuclide name="B10" ao="6.490e-4" />
<nuclide name="B11" ao="2.689e-3" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
<!-- RPV Composition -->
@ -128,7 +126,7 @@
<nuclide name="Cr52" wo="0.145407678031" />
<nuclide name="Cr53" wo="0.016806340306" />
<nuclide name="Cr54" wo="0.004261520857" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
<!-- Upper radial reflector / Top plate region -->
@ -155,7 +153,7 @@
<nuclide name="Cr52" wo="0.146766614995" />
<nuclide name="Cr53" wo="0.01696340737" />
<nuclide name="Cr54" wo="0.004301347765" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
<!-- Bottom plate region -->
@ -182,7 +180,7 @@
<nuclide name="Cr52" wo="0.157390026871" />
<nuclide name="Cr53" wo="0.018191270146" />
<nuclide name="Cr54" wo="0.004612692337" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
<!-- Bottom nozzle region -->
@ -209,7 +207,7 @@
<nuclide name="Cr52" wo="0.124142524198" />
<nuclide name="Cr53" wo="0.014348496148" />
<nuclide name="Cr54" wo="0.003638294506" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
<!-- Top nozzle region -->
@ -236,7 +234,7 @@
<nuclide name="Cr52" wo="0.107931450781" />
<nuclide name="Cr53" wo="0.012474806806" />
<nuclide name="Cr54" wo="0.003163190107" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
<!-- Top of Fuel Assemblies -->
@ -251,7 +249,7 @@
<nuclide name="Zr92" wo="0.14759527104" />
<nuclide name="Zr94" wo="0.15280552077" />
<nuclide name="Zr96" wo="0.02511169542" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
<!-- Bottom of Fuel Assemblies -->
@ -266,7 +264,7 @@
<nuclide name="Zr92" wo="0.1274914944" />
<nuclide name="Zr94" wo="0.1319920622" />
<nuclide name="Zr96" wo="0.0216912612" />
<sab name="c_H_in_H2O" xs="71t" />
<sab name="c_H_in_H2O" />
</material>
</materials>

Some files were not shown because too many files have changed in this diff Show more