mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-25 20:45:35 -04:00
Merge remote-tracking branch 'upstream/develop' into 2d-mesh-tally
This commit is contained in:
commit
5affc137e1
180 changed files with 4667 additions and 4932 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
------------------------------------
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
275
src/algorithm.F90
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
! ============================================================================
|
||||
|
|
|
|||
|
|
@ -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(:)
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
10
src/mesh.F90
10
src/mesh.F90
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
456
src/physics.F90
456
src/physics.F90
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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" } }?
|
||||
}+
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 } |
|
||||
|
|
|
|||
|
|
@ -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"/>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
143
src/search.F90
143
src/search.F90
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
a55899cd2ed0a8ec5d44003139da639f87f5f03ee76b2d6577db6a8c2014849e4277f8e68fa874ac6795e4cbc4eb6e4031d726cafe6e663e84787d1ecd8e7f86
|
||||
dfb59bace10a91bb7ffc871d8ee87e91d94754bb8bb002ac6088f80fe0f480741c0489f74b753fc37158d0ff0f1368739ea60638b42083791311eefeac79168e
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
46df57157980545d90b482acfb01f525b84c0e623fa93a5d9c08a65723d677ef1c092360219a3c7fcf5110c6ba32f1eacbd5c5eaed40be4bfe154f302400c0a4
|
||||
6ae54c198e7659503d297e40be746a5bd72b35909fceed4b3ef357876b781946c0ea5021342556ef21f4034fa9e42b2c6014077c0efd3459dc063e6da4b12b59
|
||||
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue