From f741c210ddf74bade0f2fdf354287047c3b330c3 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Fri, 15 Dec 2017 13:03:45 -0500 Subject: [PATCH 001/100] limited functionality for RM covariance only --- examples/jupyter/mgxs-part-i.ipynb | 610 +++------------------------- openmc/data/endf.py | 2 +- openmc/data/neutron.py | 21 +- openmc/data/resonance_covariance.py | 232 +++++++++++ 4 files changed, 312 insertions(+), 553 deletions(-) create mode 100644 openmc/data/resonance_covariance.py diff --git a/examples/jupyter/mgxs-part-i.ipynb b/examples/jupyter/mgxs-part-i.ipynb index 6fa0c02b14..660c916baf 100644 --- a/examples/jupyter/mgxs-part-i.ipynb +++ b/examples/jupyter/mgxs-part-i.ipynb @@ -28,9 +28,7 @@ { "cell_type": "code", "execution_count": 1, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { @@ -134,9 +132,7 @@ { "cell_type": "code", "execution_count": 2, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", @@ -157,9 +153,7 @@ { "cell_type": "code", "execution_count": 3, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "# Instantiate some Nuclides\n", @@ -180,9 +174,7 @@ { "cell_type": "code", "execution_count": 4, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "# Instantiate a Material and register the Nuclides\n", @@ -205,9 +197,7 @@ { "cell_type": "code", "execution_count": 5, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "# Instantiate a Materials collection and export to XML\n", @@ -225,9 +215,7 @@ { "cell_type": "code", "execution_count": 6, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "# Instantiate boundary Planes\n", @@ -247,9 +235,7 @@ { "cell_type": "code", "execution_count": 7, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# Instantiate a Cell\n", @@ -272,9 +258,7 @@ { "cell_type": "code", "execution_count": 8, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "# Instantiate Universe\n", @@ -292,9 +276,7 @@ { "cell_type": "code", "execution_count": 9, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# Create Geometry and set root Universe\n", @@ -315,9 +297,7 @@ { "cell_type": "code", "execution_count": 10, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "# OpenMC simulation parameters\n", @@ -351,9 +331,7 @@ { "cell_type": "code", "execution_count": 11, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# Instantiate a 2-group EnergyGroups object\n", @@ -390,9 +368,7 @@ { "cell_type": "code", "execution_count": 12, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [], "source": [ "# Instantiate a few different sections\n", @@ -415,21 +391,19 @@ { "cell_type": "code", "execution_count": 13, - "metadata": { - "collapsed": false - }, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ "OrderedDict([('flux', Tally\n", - " \tID =\t10000\n", + " \tID =\t1\n", " \tName =\t\n", " \tFilters =\tCellFilter, EnergyFilter\n", " \tNuclides =\ttotal \n", " \tScores =\t['flux']\n", " \tEstimator =\ttracklength), ('absorption', Tally\n", - " \tID =\t10001\n", + " \tID =\t2\n", " \tName =\t\n", " \tFilters =\tCellFilter, EnergyFilter\n", " \tNuclides =\ttotal \n", @@ -456,10 +430,19 @@ { "cell_type": "code", "execution_count": 14, - "metadata": { - "collapsed": false - }, - "outputs": [], + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/icmeyer/miniconda3/lib/python3.6/site-packages/openmc-0.9.0-py3.6-linux-x86_64.egg/openmc/mixin.py:61: IDWarning: Another CellFilter instance already exists with id=3.\n", + " warn(msg, IDWarning)\n", + "/home/icmeyer/miniconda3/lib/python3.6/site-packages/openmc-0.9.0-py3.6-linux-x86_64.egg/openmc/mixin.py:61: IDWarning: Another EnergyFilter instance already exists with id=4.\n", + " warn(msg, IDWarning)\n" + ] + } + ], "source": [ "# Instantiate an empty Tallies object\n", "tallies_file = openmc.Tallies()\n", @@ -486,172 +469,9 @@ }, { "cell_type": "code", - "execution_count": 15, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\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", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2017 Massachusetts Institute of Technology\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.8.0\n", - " Git SHA1 | 43b141e9ba542da8b28c078cf2df8a6777cfb2ad\n", - " Date/Time | 2017-02-28 11:52:00\n", - " OpenMP Threads | 4\n", - "\n", - " ===========================================================================\n", - " ========================> INITIALIZATION <=========================\n", - " ===========================================================================\n", - "\n", - " Reading settings XML file...\n", - " Reading geometry XML file...\n", - " Reading materials XML file...\n", - " Reading cross sections XML file...\n", - " Reading H1 from\n", - " /home/wbinventor/Documents/NSE-CRPG-Codes/openmc/data/nndc_hdf5/H1.h5\n", - " Reading O16 from\n", - " /home/wbinventor/Documents/NSE-CRPG-Codes/openmc/data/nndc_hdf5/O16.h5\n", - " Reading U235 from\n", - " /home/wbinventor/Documents/NSE-CRPG-Codes/openmc/data/nndc_hdf5/U235.h5\n", - " Reading U238 from\n", - " /home/wbinventor/Documents/NSE-CRPG-Codes/openmc/data/nndc_hdf5/U238.h5\n", - " Reading Zr90 from\n", - " /home/wbinventor/Documents/NSE-CRPG-Codes/openmc/data/nndc_hdf5/Zr90.h5\n", - " Maximum neutron transport energy: 2.00000E+07 eV for H1\n", - " Reading tallies XML file...\n", - " Building neighboring cells lists for each surface...\n", - " Initializing source particles...\n", - "\n", - " ===========================================================================\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - " ===========================================================================\n", - "\n", - " Bat./Gen. k Average k \n", - " ========= ======== ==================== \n", - " 1/1 1.11184 \n", - " 2/1 1.15820 \n", - " 3/1 1.18468 \n", - " 4/1 1.17492 \n", - " 5/1 1.19645 \n", - " 6/1 1.18436 \n", - " 7/1 1.14070 \n", - " 8/1 1.15150 \n", - " 9/1 1.19202 \n", - " 10/1 1.17677 \n", - " 11/1 1.20272 \n", - " 12/1 1.21366 1.20819 +/- 0.00547\n", - " 13/1 1.15906 1.19181 +/- 0.01668\n", - " 14/1 1.14687 1.18058 +/- 0.01629\n", - " 15/1 1.14570 1.17360 +/- 0.01442\n", - " 16/1 1.13480 1.16713 +/- 0.01343\n", - " 17/1 1.17680 1.16852 +/- 0.01144\n", - " 18/1 1.16866 1.16853 +/- 0.00990\n", - " 19/1 1.19253 1.17120 +/- 0.00913\n", - " 20/1 1.18124 1.17220 +/- 0.00823\n", - " 21/1 1.19206 1.17401 +/- 0.00766\n", - " 22/1 1.17681 1.17424 +/- 0.00700\n", - " 23/1 1.17634 1.17440 +/- 0.00644\n", - " 24/1 1.13659 1.17170 +/- 0.00654\n", - " 25/1 1.17144 1.17169 +/- 0.00609\n", - " 26/1 1.20649 1.17386 +/- 0.00610\n", - " 27/1 1.11238 1.17024 +/- 0.00678\n", - " 28/1 1.18911 1.17129 +/- 0.00647\n", - " 29/1 1.14681 1.17000 +/- 0.00626\n", - " 30/1 1.12152 1.16758 +/- 0.00641\n", - " 31/1 1.12729 1.16566 +/- 0.00639\n", - " 32/1 1.15399 1.16513 +/- 0.00612\n", - " 33/1 1.13547 1.16384 +/- 0.00599\n", - " 34/1 1.17723 1.16440 +/- 0.00576\n", - " 35/1 1.09296 1.16154 +/- 0.00622\n", - " 36/1 1.19621 1.16287 +/- 0.00612\n", - " 37/1 1.12560 1.16149 +/- 0.00605\n", - " 38/1 1.17872 1.16211 +/- 0.00586\n", - " 39/1 1.17721 1.16263 +/- 0.00568\n", - " 40/1 1.13724 1.16178 +/- 0.00555\n", - " 41/1 1.18526 1.16254 +/- 0.00542\n", - " 42/1 1.13779 1.16177 +/- 0.00531\n", - " 43/1 1.15066 1.16143 +/- 0.00516\n", - " 44/1 1.12174 1.16026 +/- 0.00514\n", - " 45/1 1.17478 1.16068 +/- 0.00501\n", - " 46/1 1.14146 1.16014 +/- 0.00489\n", - " 47/1 1.20464 1.16135 +/- 0.00491\n", - " 48/1 1.15119 1.16108 +/- 0.00479\n", - " 49/1 1.17938 1.16155 +/- 0.00468\n", - " 50/1 1.15798 1.16146 +/- 0.00457\n", - " Creating state point statepoint.50.h5...\n", - "\n", - " ===========================================================================\n", - " ======================> SIMULATION FINISHED <======================\n", - " ===========================================================================\n", - "\n", - "\n", - " =======================> TIMING STATISTICS <=======================\n", - "\n", - " Total time for initialization = 3.0114E-01 seconds\n", - " Reading cross sections = 1.8743E-01 seconds\n", - " Total time in simulation = 9.7641E+00 seconds\n", - " Time in transport only = 9.5168E+00 seconds\n", - " Time in inactive batches = 1.2602E+00 seconds\n", - " Time in active batches = 8.5039E+00 seconds\n", - " Time synchronizing fission bank = 5.4293E-03 seconds\n", - " Sampling source sites = 4.3508E-03 seconds\n", - " SEND/RECV source sites = 9.9399E-04 seconds\n", - " Time accumulating tallies = 1.2758E-04 seconds\n", - " Total time for finalization = 3.6982E-04 seconds\n", - " Total time elapsed = 1.0075E+01 seconds\n", - " Calculation Rate (inactive) = 19838.7 neutrons/second\n", - " Calculation Rate (active) = 11759.3 neutrons/second\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 1.15984 +/- 0.00411\n", - " k-effective (Track-length) = 1.16146 +/- 0.00457\n", - " k-effective (Absorption) = 1.16177 +/- 0.00380\n", - " Combined k-effective = 1.16105 +/- 0.00364\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", - "\n" - ] - }, - { - "data": { - "text/plain": [ - "0" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "# Run OpenMC\n", "openmc.run()" @@ -673,10 +493,8 @@ }, { "cell_type": "code", - "execution_count": 16, - "metadata": { - "collapsed": false - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "# Load the last statepoint file\n", @@ -699,10 +517,8 @@ }, { "cell_type": "code", - "execution_count": 17, - "metadata": { - "collapsed": false - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "# Load the tallies from the statepoint into each MGXS object\n", @@ -734,28 +550,9 @@ }, { "cell_type": "code", - "execution_count": 18, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Multi-Group XS\n", - "\tReaction Type =\ttotal\n", - "\tDomain Type =\tcell\n", - "\tDomain ID =\t1\n", - "\tCross Sections [cm^-1]:\n", - " Group 1 [0.625 - 20000000.0eV]:\t6.81e-01 +/- 2.69e-01%\n", - " Group 2 [0.0 - 0.625 eV]:\t1.40e+00 +/- 5.93e-01%\n", - "\n", - "\n", - "\n" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "total.print_xs()" ] @@ -769,58 +566,9 @@ }, { "cell_type": "code", - "execution_count": 19, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\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", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellgroup innuclidemeanstd. dev.
111total0.6677870.001802
012total1.2920130.007642
\n", - "
" - ], - "text/plain": [ - " cell group in nuclide mean std. dev.\n", - "1 1 1 total 0.667787 0.001802\n", - "0 1 2 total 1.292013 0.007642" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "df = scattering.get_pandas_dataframe()\n", "df.head(10)" @@ -835,10 +583,8 @@ }, { "cell_type": "code", - "execution_count": 20, - "metadata": { - "collapsed": false - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "absorption.export_xs_data(filename='absorption-xs', format='excel')" @@ -853,10 +599,8 @@ }, { "cell_type": "code", - "execution_count": 21, - "metadata": { - "collapsed": false - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "total.build_hdf5_store(filename='mgxs', append=True)\n", @@ -880,68 +624,9 @@ }, { "cell_type": "code", - "execution_count": 22, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\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", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellenergy low [eV]energy high [eV]nuclidescoremeanstd. dev.
010.0006.250000e-01total(((total / flux) - (absorption / flux)) - (sca...-1.110223e-150.011292
110.6252.000000e+07total(((total / flux) - (absorption / flux)) - (sca...1.776357e-150.002570
\n", - "
" - ], - "text/plain": [ - " cell energy low [eV] energy high [eV] nuclide \\\n", - "0 1 0.00e+00 6.25e-01 total \n", - "1 1 6.25e-01 2.00e+07 total \n", - "\n", - " score mean std. dev. \n", - "0 (((total / flux) - (absorption / flux)) - (sca... -1.11e-15 1.13e-02 \n", - "1 (((total / flux) - (absorption / flux)) - (sca... 1.78e-15 2.57e-03 " - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "# Use tally arithmetic to compute the difference between the total, absorption and scattering\n", "difference = total.xs_tally - absorption.xs_tally - scattering.xs_tally\n", @@ -959,68 +644,9 @@ }, { "cell_type": "code", - "execution_count": 23, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\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", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellenergy low [eV]energy high [eV]nuclidescoremeanstd. dev.
010.0006.250000e-01total((absorption / flux) / (total / flux))0.0761150.000649
110.6252.000000e+07total((absorption / flux) / (total / flux))0.0192630.000095
\n", - "
" - ], - "text/plain": [ - " cell energy low [eV] energy high [eV] nuclide \\\n", - "0 1 0.00e+00 6.25e-01 total \n", - "1 1 6.25e-01 2.00e+07 total \n", - "\n", - " score mean std. dev. \n", - "0 ((absorption / flux) / (total / flux)) 7.61e-02 6.49e-04 \n", - "1 ((absorption / flux) / (total / flux)) 1.93e-02 9.46e-05 " - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "# Use tally arithmetic to compute the absorption-to-total MGXS ratio\n", "absorption_to_total = absorption.xs_tally / total.xs_tally\n", @@ -1031,68 +657,9 @@ }, { "cell_type": "code", - "execution_count": 24, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\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", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellenergy low [eV]energy high [eV]nuclidescoremeanstd. dev.
010.0006.250000e-01total((scatter / flux) / (total / flux))0.9238850.007736
110.6252.000000e+07total((scatter / flux) / (total / flux))0.9807370.003737
\n", - "
" - ], - "text/plain": [ - " cell energy low [eV] energy high [eV] nuclide \\\n", - "0 1 0.00e+00 6.25e-01 total \n", - "1 1 6.25e-01 2.00e+07 total \n", - "\n", - " score mean std. dev. \n", - "0 ((scatter / flux) / (total / flux)) 9.24e-01 7.74e-03 \n", - "1 ((scatter / flux) / (total / flux)) 9.81e-01 3.74e-03 " - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "# Use tally arithmetic to compute the scattering-to-total MGXS ratio\n", "scattering_to_total = scattering.xs_tally / total.xs_tally\n", @@ -1110,68 +677,9 @@ }, { "cell_type": "code", - "execution_count": 25, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\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", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellenergy low [eV]energy high [eV]nuclidescoremeanstd. dev.
010.0006.250000e-01total(((absorption / flux) / (total / flux)) + ((sc...1.00.007763
110.6252.000000e+07total(((absorption / flux) / (total / flux)) + ((sc...1.00.003739
\n", - "
" - ], - "text/plain": [ - " cell energy low [eV] energy high [eV] nuclide \\\n", - "0 1 0.00e+00 6.25e-01 total \n", - "1 1 6.25e-01 2.00e+07 total \n", - "\n", - " score mean std. dev. \n", - "0 (((absorption / flux) / (total / flux)) + ((sc... 1.00e+00 7.76e-03 \n", - "1 (((absorption / flux) / (total / flux)) + ((sc... 1.00e+00 3.74e-03 " - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "# Use tally arithmetic to ensure that the absorption- and scattering-to-total MGXS ratios sum to unity\n", "sum_ratio = absorption_to_total + scattering_to_total\n", @@ -1197,9 +705,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.2" + "version": "3.6.3" } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } diff --git a/openmc/data/endf.py b/openmc/data/endf.py index 0fa75ded89..e2876a951f 100644 --- a/openmc/data/endf.py +++ b/openmc/data/endf.py @@ -288,7 +288,7 @@ class Evaluation(object): Attributes ---------- info : dict - Miscallaneous information about the evaluation. + Miscellaneous information about the evaluation. target : dict Information about the target material, such as its mass, isomeric state, whether it's stable, and whether it's fissionable. diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index ed2f4f8b75..6703077074 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -25,6 +25,7 @@ from .njoy import make_ace from .product import Product from .reaction import Reaction, _get_photon_products_ace from . import resonance as res +from . import resonance_covariance as res_cov from .urr import ProbabilityTables import openmc.checkvalue as cv from openmc.mixin import EqualityMixin @@ -151,6 +152,8 @@ class IncidentNeutron(EqualityMixin): and the values are Reaction objects. resonances : openmc.data.Resonances or None Resonance parameters + resonance_covariance : openmc.data.ResonanceCovariance or None + Covariance for resonance parameters summed_reactions : collections.OrderedDict Contains summed cross sections, e.g., the total cross section. The keys are the MT values and the values are Reaction objects. @@ -231,6 +234,10 @@ class IncidentNeutron(EqualityMixin): def resonances(self): return self._resonances + @property + def resonance_covariance(self): + return self._resoncance_covariance + @property def summed_reactions(self): return self._summed_reactions @@ -292,6 +299,11 @@ class IncidentNeutron(EqualityMixin): cv.check_type('resonances', resonances, res.Resonances) self._resonances = resonances + @resonance_covariance.setter + def resonance_covariance(self, resonance_covariance): + cv.check_type('resonances', resonances, res.ResonanceCovariance) + self._resonacne_covariance = resonance_covariance + @summed_reactions.setter def summed_reactions(self, summed_reactions): cv.check_type('summed reactions', summed_reactions, Mapping) @@ -748,7 +760,7 @@ class IncidentNeutron(EqualityMixin): return data @classmethod - def from_endf(cls, ev_or_filename): + def from_endf(cls, ev_or_filename, get_covariance=False): """Generate incident neutron continuous-energy data from an ENDF evaluation Parameters @@ -757,6 +769,10 @@ class IncidentNeutron(EqualityMixin): ENDF evaluation to read from. If given as a string, it is assumed to be the filename for the ENDF file. + get_covariance : bool + Flag to indicate whether or not covariance data from File 32 should be + retrieved + Returns ------- openmc.data.IncidentNeutron @@ -788,6 +804,9 @@ class IncidentNeutron(EqualityMixin): if (2, 151) in ev.section: data.resonances = res.Resonances.from_endf(ev) + if (32, 151) in ev.section and get_covariance: + data.res_covariance = res_cov.ResonanceCovariance.from_endf(ev) + # Read each reaction for mf, mt, nc, mod in ev.reaction_list: if mf == 3: diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py new file mode 100644 index 0000000000..dc1a7f8cbb --- /dev/null +++ b/openmc/data/resonance_covariance.py @@ -0,0 +1,232 @@ +from collections import defaultdict, MutableSequence, Iterable +import io + +import numpy as np +from numpy.polynomial import Polynomial +import pandas as pd + +from .data import NEUTRON_MASS +from .endf import get_head_record, get_cont_record, get_tab1_record, get_list_record +import openmc.checkvalue as cv +from .resonance import ResonanceRange + +class ResonanceCovariance(object): + """Resolved resonance covariance data + + Parameters + ---------- + ranges : list of openmc.data.ResonanceRange + Distinct energy ranges for resonance data + + Attributes + ---------- + ranges : list of openmc.data.ResonanceRange + Distinct energy ranges for resonance data + resolved : openmc.data.ResonanceRange or None + Resolved resonance range + unresolved : openmc.data.Unresolved or None + Unresolved resonance range + + """ + + def __init__(self, ranges): + self.ranges = ranges + + def __iter__(self): + for r in self.ranges: + yield r + + @property + def ranges(self): + return self._ranges + + @ranges.setter + def ranges(self, ranges): + cv.check_type('resonance ranges', ranges, MutableSequence) + self._ranges = cv.CheckedList(ResonanceRange, 'resonance ranges', + ranges) + + @classmethod + def from_endf(cls, ev): + """Generate resonance covariance data from an ENDF evaluation. + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + ENDF evaluation + + Returns + ------- + openmc.data.ResonanceCovariance + Resonance covariance data + + """ + file_obj = io.StringIO(ev.section[32, 151]) + + # Determine whether discrete or continuous representation + items = get_head_record(file_obj) + n_isotope = items[4] # Number of isotopes + + ranges = [] + for iso in range(n_isotope): + items = get_cont_record(file_obj) + abundance = items[1] + fission_widths = (items[3] == 1) # fission widths are given? + n_ranges = items[4] # number of resonance energy ranges + + for j in range(n_ranges): + items = get_cont_record(file_obj) + resonance_flag = items[2] # flag for resolved (1)/unresolved (2) + formalism = items[3] # resonance formalism + + # Throw error for unsupported formalisms + if formalism in [0,1,2,7]: + raise TypeError('LRF= ', formalism, + ' covariance not supported for this formalism') + + if resonance_flag in (0, 1): + # resolved resonance region + erange = _FORMALISMS[formalism].from_endf(ev, file_obj, items) + + elif resonance_flag == 2: + raise TypeError('Unresolved resonance not supported') + + #erange.material = self + ranges.append(erange) + + return cls(ranges) + + +class ReichMooreCovariance(ResonanceRange): + """Reich-Moore resolved resonance formalism covariance data. + + Reich-Moore resolved resonance data is identified by LRF=3 in the ENDF-6 + format. + + + Parameters + ---------- + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV + channel : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + scattering : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + + Attributes + ---------- + cov_paramaters: list + The parameters that are included in the covariance matrix + covariance_matrix : array + The covariance matrix contained within the ENDF evaluation + + + """ + + def __init__(self, energy_min, energy_max): + self.parameters = None + self.covariance = None + + @classmethod + def from_endf(cls, ev, file_obj, items): + """Create Reich-Moore resonance covariance data from an ENDF evaluation. + Includes the resonance parameters contained separately in File 32. + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + ENDF evaluation + file_obj : file-like object + ENDF file positioned at the second record of a resonance range + subsection in MF=2, MT=151 + items : list + Items from the CONT record at the start of the resonance range + subsection + + Returns + ------- + openmc.data.ReichMooreCovariance + Reich-Moore resonance covariance parameters + + """ + # Read energy-dependent scattering radius if present + energy_min, energy_max = items[0:2] + nro, naps = items[4:6] + if nro != 0: + params, ape = get_tab1_record(file_obj) + + # Other scatter radius parameters + items = get_cont_record(file_obj) + target_spin = items[0] + ap = Polynomial((items[1],)) + LCOMP = items[3] # Flag for compatibility 0,1,2 - 2 is compact form + NLS = items[4] # Number of l-values + + + # Build covariance matrix for General Resolved Resonance Formats + if LCOMP == 1: + items = get_cont_record(file_obj) + awri = items[0] + num_short_range = items[4] #Number of short range type resonance + #covariances + num_long_range = items[5] #Number of long range type resonance + #covariances + # Read resonance widths, J values, etc + channel_radius = {} + scattering_radius = {} + records = [] + for i in range(num_short_range): + items, values = get_list_record(file_obj) + num_parameters = items[2] + num_res = items[5] + num_par_vals = num_res*6 + res_values = values[:num_par_vals] + cov_values = values[num_par_vals:] + + energy = res_values[0::6] + spin = res_values[1::6] + gn = res_values[2::6] + gg = res_values[3::6] + gfa = res_values[4::6] + gfb = res_values[5::6] + + for i, E in enumerate(energy): + records.append([energy[i], spin[i], gn[i], gg[i], + gfa[i], gfb[i]]) + + #Build the upper-triangular covariance matrix + cov_dim = num_parameters*num_res + cov = np.zeros([cov_dim,cov_dim]) + indices = np.triu_indices(cov_dim) + cov[indices] = cov_values + + # Create pandas DataFrame with resonance data + columns = ['energy', 'J', 'neutronWidth', 'captureWidth', + 'fissionWidthA', 'fissionWidthB'] + parameters = pd.DataFrame.from_records(records, columns=columns) + + # Create instance of ReichMooreCovariance + rmc = cls(energy_min, energy_max) + rmc.parameters = parameters + rmc.covariance = cov + + return rmc + + elif LCOMP in [0,2]: + TypeError('LCOMP = ',LCOMP,' not supported') + + +# _FORMALISMS = {0: ResonanceRange, +# 1: SingleLevelBreitWigner, +# 2: MultiLevelBreitWigner, +# 3: ReichMoore, +# 7: RMatrixLimited} +_FORMALISMS = {3: ReichMooreCovariance} + + From 8bd02e7890c1f889d2d0ea1b97a0d94bdfd6bbfb Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 30 Jan 2018 14:01:52 -0500 Subject: [PATCH 002/100] Limited functionality for MLBW/SLBW covariances --- openmc/data/resonance_covariance.py | 182 +++++++++++++++++++++++++++- 1 file changed, 177 insertions(+), 5 deletions(-) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index dc1a7f8cbb..fdf4ba22ea 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -80,9 +80,9 @@ class ResonanceCovariance(object): formalism = items[3] # resonance formalism # Throw error for unsupported formalisms - if formalism in [0,1,2,7]: + if formalism in [0,1,7]: raise TypeError('LRF= ', formalism, - ' covariance not supported for this formalism') + 'covariance not supported for this formalism') if resonance_flag in (0, 1): # resolved resonance region @@ -96,6 +96,174 @@ class ResonanceCovariance(object): return cls(ranges) +class MultiLevelBreitWignerCovariance(ResonanceRange): + """Multi-level Breit-Wigner resolved resonance formalism covariance data. + + Multi-level Breit-Wigner resolved resonance data is identified by LRF=2 in + the ENDF-6 format. + + Parameters + ---------- + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV + channel : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + scattering : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + + Attributes + ---------- + cov_paramaters: list + The parameters that are included in the covariance matrix + covariance_matrix : array + The covariance matrix contained within the ENDF evaluation + + """ + + def __init__(self, energy_min, energy_max): + self.parameters = None + self.covariance = None + + @classmethod + def from_endf(cls, ev, file_obj, items): + """Create MLBW covariance data from an ENDF evaluation. + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + ENDF evaluation + file_obj : file-like object + ENDF file positioned at the second record of a resonance range + subsection in MF=2, MT=151 + items : list + Items from the CONT record at the start of the resonance range + subsection + + Returns + ------- + openmc.data.MultiLevelBreitWignerCovariance + Multi-level Breit-Wigner resonance covariance parameters + + """ + + # Read energy-dependent scattering radius if present + energy_min, energy_max = items[0:2] + nro, naps = items[4:6] + if nro != 0: + params, ape = get_tab1_record(file_obj) + + # Other scatter radius parameters + items = get_cont_record(file_obj) + target_spin = items[0] + ap = Polynomial((items[1],)) # energy-independent scattering-radius + LCOMP = items[3] # Flag for compatibility 0,1,2 - 2 is compact form + NLS = items[4] # number of l-values + + # Build covariance matrix for General Resolved Resonance Formats + if LCOMP == 1: + items = get_cont_record(file_obj) + num_short_range = items[4] #Number of short range type resonance + #covariances + num_long_range = items[5] #Number of long range type resonance + #covariances + + # Read resonance widths, J values, etc + records = [] + for i in range(num_short_range): + items, values = get_list_record(file_obj) + num_parameters = items[2] + num_res = items[5] + num_par_vals = num_res*6 + res_values = values[:num_par_vals] + cov_values = values[num_par_vals:] + + energy = res_values[0::6] + spin = res_values[1::6] + gt = res_values[2::6] + gn = res_values[3::6] + gg = res_values[4::6] + gf = res_values[5::6] + + for i, E in enumerate(energy): + records.append([energy[i], spin[i], gt[i], gn[i], + gg[i], gf[i]]) + + #Build the upper-triangular covariance matrix + cov_dim = num_parameters*num_res + cov = np.zeros([cov_dim,cov_dim]) + indices = np.triu_indices(cov_dim) + cov[indices] = cov_values + + #Create pandas DataFrame with resonance data, currently + #redundant with data.IncidentNeutron.resonance + columns = ['energy', 'J', 'totalWidth', 'neutronWidth', + 'captureWidth', 'fissionWidth'] + parameters = pd.DataFrame.from_records(records, columns=columns) + + # Create instance of class + mlbw = cls(energy_min, energy_max) + mlbw.parameters = parameters + mlbw.covariance = cov + + return mlbw + + elif LCOMP in [0,2]: + raise TypeError('LCOMP = ' + str(LCOMP) + ' not supported') + +class SingleLevelBreitWignerCovariance(MultiLevelBreitWignerCovariance): + """Single-level Breit-Wigner resolved resonance formalism covariance data. + + Single-level Breit-Wigner resolved resonance data is is identified by LRF=1 + in the ENDF-6 format. + + Parameters + ---------- + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV + channel : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + scattering : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + + Attributes + ---------- + atomic_weight_ratio : float + Atomic weight ratio of the target nuclide given as a function of + l-value. Note that this may be different than the value for the + evaluation as a whole. + channel_radius : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + energy_max : float + Maximum energy of the resolved resonance range in eV + energy_min : float + Minimum energy of the resolved resonance range in eV + parameters : pandas.DataFrame + Energies, spins, and resonances widths for each resonance + q_value : dict + Q-value to be added to incident particle's center-of-mass energy to + determine the channel energy for use in the penetrability factor. The + keys of the dictionary are l-values. + scattering_radius : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + + """ + class ReichMooreCovariance(ResonanceRange): """Reich-Moore resolved resonance formalism covariance data. @@ -121,6 +289,8 @@ class ReichMooreCovariance(ResonanceRange): Attributes ---------- + num_parameters: list + Number of parameters used in each subsection cov_paramaters: list The parameters that are included in the covariance matrix covariance_matrix : array @@ -130,6 +300,7 @@ class ReichMooreCovariance(ResonanceRange): """ def __init__(self, energy_min, energy_max): + self.num_parameters = None self.parameters = None self.covariance = None @@ -172,7 +343,6 @@ class ReichMooreCovariance(ResonanceRange): # Build covariance matrix for General Resolved Resonance Formats if LCOMP == 1: items = get_cont_record(file_obj) - awri = items[0] num_short_range = items[4] #Number of short range type resonance #covariances num_long_range = items[5] #Number of long range type resonance @@ -219,7 +389,7 @@ class ReichMooreCovariance(ResonanceRange): return rmc elif LCOMP in [0,2]: - TypeError('LCOMP = ',LCOMP,' not supported') + raise TypeError('LCOMP = ' + str(LCOMP) + ' not supported') # _FORMALISMS = {0: ResonanceRange, @@ -227,6 +397,8 @@ class ReichMooreCovariance(ResonanceRange): # 2: MultiLevelBreitWigner, # 3: ReichMoore, # 7: RMatrixLimited} -_FORMALISMS = {3: ReichMooreCovariance} +_FORMALISMS = {1: SingleLevelBreitWignerCovariance, + 2: MultiLevelBreitWignerCovariance, + 3: ReichMooreCovariance} From b6082acc59698d9e2e0248b243883e70035180d2 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Thu, 1 Feb 2018 18:55:33 -0500 Subject: [PATCH 003/100] Added some capability for LCOMP=2 format --- openmc/data/endf.py | 62 ++++++++++++++++++++++ openmc/data/resonance_covariance.py | 82 +++++++++++++++++++++++++++-- 2 files changed, 140 insertions(+), 4 deletions(-) diff --git a/openmc/data/endf.py b/openmc/data/endf.py index e2876a951f..aa185ca03f 100644 --- a/openmc/data/endf.py +++ b/openmc/data/endf.py @@ -72,6 +72,24 @@ def float_endf(s): return float(ENDF_FLOAT_RE.sub(r'\1e\2', s)) +def int_endf(s): + """Conver string to int. Used for INTG records where blank entries + indicate a 0. + + Parameters + ---------- + s : str + Integer or spaces + + Returns + ------- + integer + The number or 0 + """ + s = s.strip() + return int(s) if s else 0 + + def get_text_record(file_obj): """Return data from a TEXT record in an ENDF-6 file. @@ -250,6 +268,50 @@ def get_tab2_record(file_obj): return params, Tabulated2D(breakpoints, interpolation) +def get_intg_record(file_obj): + """ + Return data from an INTG record in an ENDF-6 file. + + Parameters + ---------- + file_obj : file-like object + ENDF-6 file to read from + + Returns + ------- + array + The correlation matrix described in the INTG record + """ + # determine how many items are in list and NDIGIT + items = get_cont_record(file_obj) + NDIGIT = int(items[2]) + NNN = int(items[3]) # Number of parameters + NM = int(items[4]) # Lines to read + NROW_RULES = {2: 18,3: 12,4: 11,5: 9,6: 8} + NROW = NROW_RULES[NDIGIT] + + # read lines and build correlation matrix + corr = np.identity(NNN) + for i in range(NM): + line = file_obj.readline() + ii = int_endf(line[:5]) - 1 #-1 to account for 0 indexing + jj = int_endf(line[5:10]) - 1 + factor = 10**NDIGIT + for j in range(NROW): + if jj+j >= ii: + break + element = int_endf(line[11+(NDIGIT+1)*j:11+(NDIGIT+1)*(j+1)]) + if element > 0: + corr[ii,jj] = (element+0.5)/factor + elif element < 0: + corr[ii,jj] = (element-0.5)/factor + + #Symmetrize the correlation matrix + corr = corr + corr.T - np.diag(corr.diagonal()) + return corr + + + def get_evaluations(filename): """Return a list of all evaluations within an ENDF file. diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index fdf4ba22ea..dc77988bb3 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -6,7 +6,7 @@ from numpy.polynomial import Polynomial import pandas as pd from .data import NEUTRON_MASS -from .endf import get_head_record, get_cont_record, get_tab1_record, get_list_record +from .endf import get_head_record, get_cont_record, get_tab1_record, get_list_record, get_intg_record import openmc.checkvalue as cv from .resonance import ResonanceRange @@ -80,7 +80,7 @@ class ResonanceCovariance(object): formalism = items[3] # resonance formalism # Throw error for unsupported formalisms - if formalism in [0,1,7]: + if formalism in [0,7]: raise TypeError('LRF= ', formalism, 'covariance not supported for this formalism') @@ -213,7 +213,44 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): return mlbw - elif LCOMP in [0,2]: + elif LCOMP == 2: #Compact format - Resonances and individual + #uncertainties followed by compact correlations + items, values = get_list_record(file_obj) + num_res = items[5] + energy = values[0::12] + spin = values[1::12] + gt = values[2::12] + gn = values[3::12] + gg = values[4::12] + gf = values[5::12] + par_unc = [] + for i in range(num_res): + res_unc = values[i*12+6:i*12+12] + #Delete 0 values (not provided in evaluation) + res_unc = [x for x in res_unc if x != 0.0] + par_unc.extend(res_unc) + + records = [] + for i, E in enumerate(energy): + records.append([energy[i], spin[i], gt[i], gn[i], + gg[i], gf[i]]) + + corr = get_intg_record(file_obj) + cov = np.diag(par_unc).dot(corr).dot(np.diag(par_unc)) + + # Create pandas DataFrame with resonacne data + columns = ['energy', 'J', 'totalWidth', 'neutronWidth', + 'captureWidth', 'fissionWidth'] + parameters = pd.DataFrame.from_records(records, columns=columns) + + # Create instance of ReichMooreCovariance + mlbw = cls(energy_min, energy_max) + mlbw.parameters = parameters + mlbw.covariance = cov + + return mlbw + + elif LCOMP == 0 : raise TypeError('LCOMP = ' + str(LCOMP) + ' not supported') class SingleLevelBreitWignerCovariance(MultiLevelBreitWignerCovariance): @@ -388,7 +425,44 @@ class ReichMooreCovariance(ResonanceRange): return rmc - elif LCOMP in [0,2]: + elif LCOMP == 2: #Compact format - Resonances and individual + #uncertainties followed by compact correlations + items, values = get_list_record(file_obj) + num_res = items[5] + energy = values[0::12] + spin = values[1::12] + gn = values[2::12] + gfa = values[3::12] + gfb = values[4::12] + par_unc = [] + for i in range(num_res): + res_unc = values[i*12+6:i*12+12] + #Delete 0 values (not provided in evaluation) + res_unc = [x for x in res_unc if x != 0.0] + par_unc.extend(res_unc) + + records = [] + for i, E in enumerate(energy): + records.append([energy[i], spin[i], gn[i], + gfa[i], gfb[i]]) + + corr = get_intg_record(file_obj) + cov = np.diag(par_unc).dot(corr).dot(np.diag(par_unc)) + + # Create pandas DataFrame with resonacne data + columns = ['energy', 'J', 'neutronWidth', + 'fissionWidthA', 'fissionWidthB'] + parameters = pd.DataFrame.from_records(records, columns=columns) + + # Create instance of ReichMooreCovariance + rmc = cls(energy_min, energy_max) + rmc.parameters = parameters + rmc.covariance = cov + + return rmc + + + elif LCOMP == 0: raise TypeError('LCOMP = ' + str(LCOMP) + ' not supported') From 27b6abee2db205675e7259e3914dbfde6e991e35 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 6 Feb 2018 18:45:19 -0500 Subject: [PATCH 004/100] Added capability for LCOMP=0 --- openmc/data/resonance_covariance.py | 60 +++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index dc77988bb3..261b2fb7b7 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -123,6 +123,8 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): The parameters that are included in the covariance matrix covariance_matrix : array The covariance matrix contained within the ENDF evaluation + lcomp : int + Flag indicating the format of the covariance matrix """ @@ -210,6 +212,7 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): mlbw = cls(energy_min, energy_max) mlbw.parameters = parameters mlbw.covariance = cov + mlbw.lcomp = LCOMP return mlbw @@ -243,15 +246,63 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): 'captureWidth', 'fissionWidth'] parameters = pd.DataFrame.from_records(records, columns=columns) - # Create instance of ReichMooreCovariance + # Create instance of MultiLevelBreitWignerCovariance mlbw = cls(energy_min, energy_max) mlbw.parameters = parameters mlbw.covariance = cov + mlbw.lcomp = LCOMP return mlbw elif LCOMP == 0 : - raise TypeError('LCOMP = ' + str(LCOMP) + ' not supported') + cov = np.zeros([5,5]) +# test2 = np.pad(test,((0,2),(0,2)),'constant',constant_values=0) + records = [] + cov_index = 0 + for i in range(NLS): + items, values = get_list_record(file_obj) + num_res = items[5] + for j in range(num_res): + one_res = values[18*j:18*(j+1)] + res_values = one_res[:6] + cov_values = one_res[6:] + + energy = res_values[0] + spin = res_values[1] + gt = res_values[2] + gn = res_values[3] + gg = res_values[4] + gf = res_values[5] + records.append([energy, spin, gn, gg, gf]) + + #Populate the coviariance matrix for this resonance + #There are no covariances between resonances in LCOMP=0 + cov[cov_index,cov_index]=cov_values[0] + cov[cov_index+1,cov_index+1]=cov_values[10] + cov[cov_index+2,cov_index+2:cov_index+3]=cov_values[1:2] + cov[cov_index+2,cov_index+4]=cov_values[4] + cov[cov_index+3,cov_index+3] = cov_values[3] + cov[cov_index+3,cov_index+4] = cov_values[5] + cov[cov_index+4,cov_index+4] = cov_values[6] + cov_index += 5 + if j < num_res: #Pad matrix for additional values + cov = np.pad(cov,((0,5),(0,5)),'constant', + constant_values=0) + + + #Create pandas DataFrame with resonance data, currently + #redundant with data.IncidentNeutron.resonance + columns = ['energy', 'J', 'neutronWidth', + 'captureWidth', 'fissionWidth'] + parameters = pd.DataFrame.from_records(records, columns=columns) + + # Create instance of class + mlbw = cls(energy_min, energy_max) + mlbw.parameters = parameters + mlbw.covariance = cov + mlbw.lcomp = LCOMP + + return mlbw class SingleLevelBreitWignerCovariance(MultiLevelBreitWignerCovariance): """Single-level Breit-Wigner resolved resonance formalism covariance data. @@ -461,11 +512,6 @@ class ReichMooreCovariance(ResonanceRange): return rmc - - elif LCOMP == 0: - raise TypeError('LCOMP = ' + str(LCOMP) + ' not supported') - - # _FORMALISMS = {0: ResonanceRange, # 1: SingleLevelBreitWigner, # 2: MultiLevelBreitWigner, From c27aeb3b22428b93561ba1013c306034b7aafd3c Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Wed, 7 Feb 2018 18:35:04 -0500 Subject: [PATCH 005/100] fixed an issue causing LCOMP=2 to fail --- openmc/data/resonance_covariance.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index 261b2fb7b7..fc5f107094 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -229,9 +229,15 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): par_unc = [] for i in range(num_res): res_unc = values[i*12+6:i*12+12] - #Delete 0 values (not provided in evaluation) - res_unc = [x for x in res_unc if x != 0.0] - par_unc.extend(res_unc) + #Delete 0 values (not provided, no fission width) + # DAJ/DGT always zero, DGF sometimes none zero [1,2,5] + res_unc_nonzero = [] + for j in range(6): + if j in [1,2,5] and res_unc[j] != 0.0 : + res_unc_nonzero.append(res_unc[j]) + elif j in [0,3,4]: + res_unc_nonzero.append(res_unc[j]) + par_unc.extend(res_unc_nonzero) records = [] for i, E in enumerate(energy): @@ -285,7 +291,7 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): cov[cov_index+3,cov_index+4] = cov_values[5] cov[cov_index+4,cov_index+4] = cov_values[6] cov_index += 5 - if j < num_res: #Pad matrix for additional values + if j < num_res-1: #Pad matrix for additional values cov = np.pad(cov,((0,5),(0,5)),'constant', constant_values=0) @@ -473,6 +479,7 @@ class ReichMooreCovariance(ResonanceRange): rmc = cls(energy_min, energy_max) rmc.parameters = parameters rmc.covariance = cov + rmc.lcomp = LCOMP return rmc @@ -509,6 +516,7 @@ class ReichMooreCovariance(ResonanceRange): rmc = cls(energy_min, energy_max) rmc.parameters = parameters rmc.covariance = cov + rmc.lcomp = LCOMP return rmc From 756690c5718c6d5993b83cad34358f831207c84f Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Mon, 19 Mar 2018 23:07:37 -0400 Subject: [PATCH 006/100] Sampling covariance working for one nuclide --- openmc/data/resonance_covariance.py | 52 +++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index fc5f107094..da84225578 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -10,6 +10,49 @@ from .endf import get_head_record, get_cont_record, get_tab1_record, get_list_re import openmc.checkvalue as cv from .resonance import ResonanceRange +### Under Construction START +def sample_resonance_parameters(nuclide, n_samples): + """Return a IncidentNeutron object with n_samples of xs + + Parameters + ---------- + nuclide: IncidentNeutron object with resonance covariance data + + Returns + ------- + ev : openmc.data.endf.Evaluation + + """ + nparams,params = nuclide.res_covariance.ranges[0].parameters.shape + cov = nuclide.res_covariance.ranges[0].covariance + covsize = cov.shape[0] + formalism = nuclide.res_covariance.ranges[0].formalism + samples = [] + if formalism == 'mlbw': + if covsize/nparams == 3: + param_list = ['energy','neutronWidth','captureWidth'] + mean_array = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters[param_list]) + spin = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters['J']) + gf = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters['fissionWidth']) + mean = mean_array.flatten() + for i in range(n_samples): + sample = np.random.multivariate_normal(mean,cov) + energy = sample[0::3] + gn = sample[1::3] + gg = sample[2::3] + gt = gn + gg + gf + records = [] + for j, E in enumerate(energy): + records.append([energy[j], spin[j], gt[j], gn[j], + gg[j], gf[j]]) + columns = ['energy', 'J', 'totalWidth', 'neutronWidth', + 'captureWidth', 'fissionWidth'] + sample_params = pd.DataFrame.from_records(records, columns=columns) + samples.append(sample_params) + + return samples +### Under Construction END + class ResonanceCovariance(object): """Resolved resonance covariance data @@ -131,6 +174,8 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): def __init__(self, energy_min, energy_max): self.parameters = None self.covariance = None + self.num_parameters = None + self.formalism = 'mlbw' @classmethod def from_endf(cls, ev, file_obj, items): @@ -213,12 +258,14 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): mlbw.parameters = parameters mlbw.covariance = cov mlbw.lcomp = LCOMP + mlbw.num_paramaters = num_paramaters return mlbw elif LCOMP == 2: #Compact format - Resonances and individual #uncertainties followed by compact correlations items, values = get_list_record(file_obj) + mean = items num_res = items[5] energy = values[0::12] spin = values[1::12] @@ -358,6 +405,8 @@ class SingleLevelBreitWignerCovariance(MultiLevelBreitWignerCovariance): """ + def __init__(self, energy_min, energy_max): + self.formalism = 'slbw' class ReichMooreCovariance(ResonanceRange): """Reich-Moore resolved resonance formalism covariance data. @@ -397,6 +446,8 @@ class ReichMooreCovariance(ResonanceRange): self.num_parameters = None self.parameters = None self.covariance = None + self.num_paramaters = None + self.formalism = 'rm' @classmethod def from_endf(cls, ev, file_obj, items): @@ -480,6 +531,7 @@ class ReichMooreCovariance(ResonanceRange): rmc.parameters = parameters rmc.covariance = cov rmc.lcomp = LCOMP + rmc.num_parameters = num_parameters return rmc From 00b12a12288a4fca4ce8387abbfe37b6c24783cf Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 20 Mar 2018 12:20:31 -0400 Subject: [PATCH 007/100] Sampling for almost all possible File 32 --- openmc/data/resonance_covariance.py | 94 ++++++++++++++++++++++++----- 1 file changed, 80 insertions(+), 14 deletions(-) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index da84225578..aaecccac4a 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -25,10 +25,13 @@ def sample_resonance_parameters(nuclide, n_samples): """ nparams,params = nuclide.res_covariance.ranges[0].parameters.shape cov = nuclide.res_covariance.ranges[0].covariance + cov = cov + cov.T - np.diag(cov.diagonal()) #symmetrizing covariance matrix covsize = cov.shape[0] formalism = nuclide.res_covariance.ranges[0].formalism samples = [] - if formalism == 'mlbw': + + ### Handling MLBW Sampling ### + if formalism == 'mlbw' or formalism == 'slbw': if covsize/nparams == 3: param_list = ['energy','neutronWidth','captureWidth'] mean_array = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters[param_list]) @@ -50,6 +53,70 @@ def sample_resonance_parameters(nuclide, n_samples): sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) + elif covsize/nparams == 4: + param_list = ['energy','neutronWidth','captureWidth','fissionWidth'] + mean_array = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters[param_list]) + spin = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters['J']) + mean = mean_array.flatten() + for i in range(n_samples): + sample = np.random.multivariate_normal(mean,cov) + energy = sample[0::4] + gn = sample[1::4] + gg = sample[2::4] + gf = sample[3::4] + gt = gn + gg + gf + records = [] + for j, E in enumerate(energy): + records.append([energy[j], spin[j], gt[j], gn[j], + gg[j], gf[j]]) + columns = ['energy', 'J', 'totalWidth', 'neutronWidth', + 'captureWidth', 'fissionWidth'] + sample_params = pd.DataFrame.from_records(records, columns=columns) + samples.append(sample_params) + + elif covsize/nparams == 5: + param_list = ['energy','neutronWidth','captureWidth','fissionWidth'] + mean_array = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters[param_list]) + spin = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters['J']) + mean = mean_array.flatten() + for i in range(n_samples): + sample = np.random.multivariate_normal(mean,cov) + energy = sample[0::4] + gn = sample[1::4] + gg = sample[2::4] + gf = sample[3::4] + gt = gn + gg + gf + records = [] + for j, E in enumerate(energy): + records.append([energy[j], spin[j], gt[j], gn[j], + gg[j], gf[j]]) + columns = ['energy', 'J', 'totalWidth', 'neutronWidth', + 'captureWidth', 'fissionWidth'] + sample_params = pd.DataFrame.from_records(records, columns=columns) + samples.append(sample_params) + ### Handling RM Sampling ### + if formalism == 'rm': + if covsize/nparams == 3: + param_list = ['energy','neutronWidth','captureWidth'] + mean_array = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters[param_list]) + spin = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters['J']) + gfa = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters['fissionWidthA']) + gfb = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters['fissionWidthB']) + mean = mean_array.flatten() + for i in range(n_samples): + sample = np.random.multivariate_normal(mean,cov) + energy = sample[0::3] + gn = sample[1::3] + gg = sample[2::3] + records = [] + for j, E in enumerate(energy): + records.append([energy[j], spin[j], gn[j], + gg[j], gfa[j], gfb[j]]) + columns = ['energy', 'J', 'neutronWidth', + 'captureWidth', 'fissionWidthA','fissionWidthB'] + sample_params = pd.DataFrame.from_records(records, columns=columns) + samples.append(sample_params) + return samples ### Under Construction END @@ -258,7 +325,7 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): mlbw.parameters = parameters mlbw.covariance = cov mlbw.lcomp = LCOMP - mlbw.num_paramaters = num_paramaters + mlbw.num_parameters = num_parameters return mlbw @@ -308,8 +375,7 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): return mlbw elif LCOMP == 0 : - cov = np.zeros([5,5]) -# test2 = np.pad(test,((0,2),(0,2)),'constant',constant_values=0) + cov = np.zeros([4,4]) records = [] cov_index = 0 for i in range(NLS): @@ -326,26 +392,26 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): gn = res_values[3] gg = res_values[4] gf = res_values[5] - records.append([energy, spin, gn, gg, gf]) + records.append([energy, spin, gt, gn, gg, gf]) #Populate the coviariance matrix for this resonance #There are no covariances between resonances in LCOMP=0 cov[cov_index,cov_index]=cov_values[0] - cov[cov_index+1,cov_index+1]=cov_values[10] - cov[cov_index+2,cov_index+2:cov_index+3]=cov_values[1:2] - cov[cov_index+2,cov_index+4]=cov_values[4] - cov[cov_index+3,cov_index+3] = cov_values[3] - cov[cov_index+3,cov_index+4] = cov_values[5] - cov[cov_index+4,cov_index+4] = cov_values[6] - cov_index += 5 + cov[cov_index+1,cov_index+1:cov_index+2]=cov_values[1:2] + cov[cov_index+1,cov_index+3]=cov_values[4] + cov[cov_index+2,cov_index+2] = cov_values[3] + cov[cov_index+2,cov_index+3] = cov_values[5] + cov[cov_index+3,cov_index+3] = cov_values[6] + + cov_index += 4 if j < num_res-1: #Pad matrix for additional values - cov = np.pad(cov,((0,5),(0,5)),'constant', + cov = np.pad(cov,((0,4),(0,4)),'constant', constant_values=0) #Create pandas DataFrame with resonance data, currently #redundant with data.IncidentNeutron.resonance - columns = ['energy', 'J', 'neutronWidth', + columns = ['energy', 'J', 'totalWidth','neutronWidth', 'captureWidth', 'fissionWidth'] parameters = pd.DataFrame.from_records(records, columns=columns) From 9156410d65fc4133186cd39002c8ff4c8613f999 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Fri, 6 Apr 2018 11:38:58 -0400 Subject: [PATCH 008/100] added function to handle dicts of values --- openmc/data/grid.py | 68 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/openmc/data/grid.py b/openmc/data/grid.py index e63919ac29..6339916fec 100644 --- a/openmc/data/grid.py +++ b/openmc/data/grid.py @@ -31,6 +31,7 @@ def linearize(x, f, tolerance=0.001): # Initialize stack x_stack = [x[0]] y_stack = [f(x[0])] + print(y_stack) for i in range(x.shape[0] - 1): x_stack.insert(0, x[i + 1]) @@ -112,3 +113,70 @@ def thin(x, y, tolerance=0.001): y_out[i_remove] = np.nan return x_out[np.isfinite(x_out)], y_out[np.isfinite(y_out)] + +def linearizeIter(x, f, tolerance=0.001, unified=True): + """Return a tabulated representation of multiple functions of one + variable. + + Parameters + ---------- + x : Iterable of float + Initial x values at which the function should be evaluated + f : Callable + Function of a single variable that returns a dictionary + tolerance : float + Tolerance on the interpolation error + unified : boolean + Flag to indicate usage of a unified grid for all functions + if True, or independent grids if False + + Returns + ------- + numpy.ndarray + Tabulated values of the independent variable + dictionary of numpy.ndarray's + Tabulated values of the dependent variable + + """ + if unified==True: + # Initialize dictionary of output + y_dict = f(x[0]) + + for item in y_dict: + #Initialize output + x_out = [] + y_out = [] + print(str(item)) + #Initialize stacks + x_stack = [x[0]] + print(y_dict) + y_stack = [y_dict[item]] + for i in range(x.shape[0] - 1): + print(x_stack) + x_stack.insert(0, x[i + 1]) + print(x_stack) + y_stack.insert(0, f(x[i + 1])[item]) + + while True: + x_high, x_low = x_stack[-2:] + y_high, y_low = y_stack[-2:] + x_mid = 0.5*(x_low + x_high) + y_mid = f(x_mid)[item] + + y_interp = y_low + (y_high - y_low)/(x_high - x_low)*(x_mid - x_low) + error = abs((y_interp - y_mid)/y_mid) + if error > tolerance: + x_stack.insert(-1, x_mid) + y_stack.insert(-1, y_mid) + else: + x_out.append(x_stack.pop()) + y_out.append(y_stack.pop()) + if len(x_stack) == 1: + break + + x_out.append(x_stack.pop()) + y_out.append(y_stack.pop()) + x=np.array(x_out) #Use x_out for initial x values in next item + + y_dict_out = f(np.array(x_out)) + return np.array(x_out), y_dict_out From 1d8ac57f9a1a6266f5e4651d554fb9971422e8be Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Fri, 6 Apr 2018 12:09:10 -0400 Subject: [PATCH 009/100] removed print statements --- openmc/data/grid.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/openmc/data/grid.py b/openmc/data/grid.py index 6339916fec..9f40792040 100644 --- a/openmc/data/grid.py +++ b/openmc/data/grid.py @@ -31,7 +31,6 @@ def linearize(x, f, tolerance=0.001): # Initialize stack x_stack = [x[0]] y_stack = [f(x[0])] - print(y_stack) for i in range(x.shape[0] - 1): x_stack.insert(0, x[i + 1]) @@ -145,16 +144,12 @@ def linearizeIter(x, f, tolerance=0.001, unified=True): for item in y_dict: #Initialize output x_out = [] - y_out = [] - print(str(item)) + #Initialize stacks x_stack = [x[0]] - print(y_dict) y_stack = [y_dict[item]] for i in range(x.shape[0] - 1): - print(x_stack) x_stack.insert(0, x[i + 1]) - print(x_stack) y_stack.insert(0, f(x[i + 1])[item]) while True: @@ -170,12 +165,11 @@ def linearizeIter(x, f, tolerance=0.001, unified=True): y_stack.insert(-1, y_mid) else: x_out.append(x_stack.pop()) - y_out.append(y_stack.pop()) + y_stack.pop() if len(x_stack) == 1: break x_out.append(x_stack.pop()) - y_out.append(y_stack.pop()) x=np.array(x_out) #Use x_out for initial x values in next item y_dict_out = f(np.array(x_out)) From 77b514950e8633d9dab8f944cddea3f2930a39c3 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 10 Apr 2018 12:32:29 -0400 Subject: [PATCH 010/100] Added more resonance sampling capability --- openmc/data/resonance_covariance.py | 37 +++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index aaecccac4a..c68414bcef 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -1,4 +1,5 @@ from collections import defaultdict, MutableSequence, Iterable +import warnings import io import numpy as np @@ -30,6 +31,10 @@ def sample_resonance_parameters(nuclide, n_samples): formalism = nuclide.res_covariance.ranges[0].formalism samples = [] + print("nparams,params:",nparams, params) + print("covsize",covsize) + print("formalism:",formalism) + ### Handling MLBW Sampling ### if formalism == 'mlbw' or formalism == 'slbw': if covsize/nparams == 3: @@ -117,6 +122,27 @@ def sample_resonance_parameters(nuclide, n_samples): sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) + elif covsize/nparams == 5: + param_list = ['energy','neutronWidth','captureWidth','fissionWidthA','fissionWidthB'] + mean_array = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters[param_list]) + spin = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters['J']) + mean = mean_array.flatten() + for i in range(n_samples): + sample = np.random.multivariate_normal(mean,cov) + energy = sample[0::5] + gn = sample[1::5] + gg = sample[2::5] + gfa = sample[3::5] + gfb = sample[4::5] + records = [] + for j, E in enumerate(energy): + records.append([energy[j], spin[j], gn[j], + gg[j], gfa[j], gfb[j]]) + columns = ['energy', 'J', 'neutronWidth', + 'captureWidth', 'fissionWidthA','fissionWidthB'] + sample_params = pd.DataFrame.from_records(records, columns=columns) + samples.append(sample_params) + return samples ### Under Construction END @@ -181,11 +207,13 @@ class ResonanceCovariance(object): for iso in range(n_isotope): items = get_cont_record(file_obj) abundance = items[1] - fission_widths = (items[3] == 1) # fission widths are given? + fission_widths = (items[3] == 1) # Flag for fission widths n_ranges = items[4] # number of resonance energy ranges + print('there are',n_ranges,'ranges') for j in range(n_ranges): items = get_cont_record(file_obj) + print("Line with unresovled flag:",items) resonance_flag = items[2] # flag for resolved (1)/unresolved (2) formalism = items[3] # resonance formalism @@ -199,9 +227,9 @@ class ResonanceCovariance(object): erange = _FORMALISMS[formalism].from_endf(ev, file_obj, items) elif resonance_flag == 2: - raise TypeError('Unresolved resonance not supported') - - #erange.material = self + warnings.warn('Unresolved resonance not supported.' + 'Covariance values for the' + 'unresolved region not imported.') ranges.append(erange) return cls(ranges) @@ -554,6 +582,7 @@ class ReichMooreCovariance(ResonanceRange): # Build covariance matrix for General Resolved Resonance Formats if LCOMP == 1: items = get_cont_record(file_obj) + print("in resonance_covariance.py", items) num_short_range = items[4] #Number of short range type resonance #covariances num_long_range = items[5] #Number of long range type resonance From 0a1408def10740676cd7933e791856a28a3d9920 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 17 Apr 2018 16:12:02 -0400 Subject: [PATCH 011/100] Sampling and reconstructing working for large files --- openmc/data/endf.py | 8 +++++++- openmc/data/neutron.py | 13 ++++++++++--- openmc/data/resonance_covariance.py | 8 +++----- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/openmc/data/endf.py b/openmc/data/endf.py index 6018719d2c..e2de655bc8 100644 --- a/openmc/data/endf.py +++ b/openmc/data/endf.py @@ -67,7 +67,13 @@ def float_endf(s): The number """ - return float(ENDF_FLOAT_RE.sub(r'\1e\2', s)) + try: + return float(ENDF_FLOAT_RE.sub(r'\1e\2', s)) + except: + if ENDF_FLOAT_RE.sub(r'\1e\2', s).isspace(): + return 0 + else: + raise TypeError('Expected float value or blank entry') def int_endf(s): diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 824dded24c..e35dd5ab36 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -1,6 +1,6 @@ +from __future__ import division, unicode_literals import sys -from collections import OrderedDict -from collections.abc import Iterable, Mapping, MutableMapping +from collections import OrderedDict, Iterable, Mapping, MutableMapping from io import StringIO from itertools import chain from math import log10 @@ -10,6 +10,7 @@ import shutil import tempfile from warnings import warn +from six import string_types import numpy as np import h5py @@ -109,7 +110,6 @@ class IncidentNeutron(EqualityMixin): :meth:`IncidentNeutron.from_ace`. Parameters - ---------- name : str Name of the nuclide using the GND naming convention atomic_number : int @@ -889,3 +889,10 @@ class IncidentNeutron(EqualityMixin): data[2].xs['0K'] = xs return data +import sys +from collections import OrderedDict +from collections.abc import Iterable, Mapping, MutableMapping +from io import StringIO +from itertools import chain +from math import log10 +from numbers import Integral, Real diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index c68414bcef..d52da4fe71 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -4,6 +4,7 @@ import io import numpy as np from numpy.polynomial import Polynomial +from scipy import sparse import pandas as pd from .data import NEUTRON_MASS @@ -11,7 +12,6 @@ from .endf import get_head_record, get_cont_record, get_tab1_record, get_list_re import openmc.checkvalue as cv from .resonance import ResonanceRange -### Under Construction START def sample_resonance_parameters(nuclide, n_samples): """Return a IncidentNeutron object with n_samples of xs @@ -24,6 +24,7 @@ def sample_resonance_parameters(nuclide, n_samples): ev : openmc.data.endf.Evaluation """ + print('begin sampling') nparams,params = nuclide.res_covariance.ranges[0].parameters.shape cov = nuclide.res_covariance.ranges[0].covariance cov = cov + cov.T - np.diag(cov.diagonal()) #symmetrizing covariance matrix @@ -128,6 +129,7 @@ def sample_resonance_parameters(nuclide, n_samples): spin = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters['J']) mean = mean_array.flatten() for i in range(n_samples): + print("On sample",i) sample = np.random.multivariate_normal(mean,cov) energy = sample[0::5] gn = sample[1::5] @@ -144,7 +146,6 @@ def sample_resonance_parameters(nuclide, n_samples): samples.append(sample_params) return samples -### Under Construction END class ResonanceCovariance(object): """Resolved resonance covariance data @@ -209,11 +210,9 @@ class ResonanceCovariance(object): abundance = items[1] fission_widths = (items[3] == 1) # Flag for fission widths n_ranges = items[4] # number of resonance energy ranges - print('there are',n_ranges,'ranges') for j in range(n_ranges): items = get_cont_record(file_obj) - print("Line with unresovled flag:",items) resonance_flag = items[2] # flag for resolved (1)/unresolved (2) formalism = items[3] # resonance formalism @@ -582,7 +581,6 @@ class ReichMooreCovariance(ResonanceRange): # Build covariance matrix for General Resolved Resonance Formats if LCOMP == 1: items = get_cont_record(file_obj) - print("in resonance_covariance.py", items) num_short_range = items[4] #Number of short range type resonance #covariances num_long_range = items[5] #Number of long range type resonance From 9e321f70ea5a4151be47a92ed310b526cc3d0ef9 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 29 May 2018 13:25:05 -0400 Subject: [PATCH 012/100] Fixed l-values, added subset capability --- openmc/data/resonance_covariance.py | 232 ++++++++++++++++++++++++---- 1 file changed, 198 insertions(+), 34 deletions(-) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index d52da4fe71..7f134da4b2 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -12,7 +12,53 @@ from .endf import get_head_record, get_cont_record, get_tab1_record, get_list_re import openmc.checkvalue as cv from .resonance import ResonanceRange -def sample_resonance_parameters(nuclide, n_samples): +def res_subset(nuclide, parameter_str, bounds): + """Produce a subset of resonance paramaters and the covariance matrix + to an IncidentNeutron objecti + + Parameters + ---------- + nuclide: ResonanceCovariance object + parameter_str: paramater to be discriminated + (i.e. 'energy','captureWidth','fissionWidthA'...) + bounds: np.array [low numerical bound, high numerical bound] + + Returns + ------- + parameters_subset : Dataframe of a subset of parameters + (maintains indexing) + cov_subset: subset of covariance matrix (upper triangular) + + """ + parameters = nuclide.parameters + cov = nuclide.covariance + mpar = nuclide.mpar + mask1 = parameters[parameter_str]>=bounds[0] + mask2 = parameters[parameter_str]<=bounds[1] + mask = mask1 & mask2 + parameters_subset=parameters[mask] + indices = parameters_subset.index.values + sub_cov_dim = len(indices)*mpar + oldvalues = [] + for index1 in indices: + print("Current index:",index1) + for i in range(mpar): + print("i is:", i) + for index2 in indices: + for j in range(mpar): + print("j is:", i) + if index2*mpar+j >= index1*mpar+i: + print(cov[index1*mpar+i,index2*mpar+j]) + oldvalues.append(cov[index1*mpar+i,index2*mpar+j]) + + cov_subset = np.zeros([sub_cov_dim,sub_cov_dim]) + tri_indices = np.triu_indices(sub_cov_dim) + cov_subset[tri_indices] = oldvalues + + nuclide.parameters_subset = parameters_subset + nuclide.cov_subset = cov_subset + +def sample_resonance_parameters(nuclide, n_samples, use_subset=False): """Return a IncidentNeutron object with n_samples of xs Parameters @@ -25,11 +71,17 @@ def sample_resonance_parameters(nuclide, n_samples): """ print('begin sampling') - nparams,params = nuclide.res_covariance.ranges[0].parameters.shape - cov = nuclide.res_covariance.ranges[0].covariance + if use_subset==False: + parameters = nuclide.parameters + cov = nuclide.covariance + else: + parameters = nuclide.parameters_subset + cov = nuclide.cov_subset + nparams,params = parameters.shape cov = cov + cov.T - np.diag(cov.diagonal()) #symmetrizing covariance matrix covsize = cov.shape[0] - formalism = nuclide.res_covariance.ranges[0].formalism + formalism = nuclide.formalism + mpar = nuclide.mpar samples = [] print("nparams,params:",nparams, params) @@ -38,11 +90,11 @@ def sample_resonance_parameters(nuclide, n_samples): ### Handling MLBW Sampling ### if formalism == 'mlbw' or formalism == 'slbw': - if covsize/nparams == 3: + if mpar == 3: param_list = ['energy','neutronWidth','captureWidth'] - mean_array = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters[param_list]) - spin = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters['J']) - gf = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters['fissionWidth']) + mean_array = pd.DataFrame.as_matrix(parameters[param_list]) + spin = pd.DataFrame.as_matrix(parameters['J']) + gf = pd.DataFrame.as_matrix(parameters['fissionWidth']) mean = mean_array.flatten() for i in range(n_samples): sample = np.random.multivariate_normal(mean,cov) @@ -59,10 +111,10 @@ def sample_resonance_parameters(nuclide, n_samples): sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) - elif covsize/nparams == 4: + elif mpar == 4: param_list = ['energy','neutronWidth','captureWidth','fissionWidth'] - mean_array = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters[param_list]) - spin = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters['J']) + mean_array = pd.DataFrame.as_matrix(parameters[param_list]) + spin = pd.DataFrame.as_matrix(parameters['J']) mean = mean_array.flatten() for i in range(n_samples): sample = np.random.multivariate_normal(mean,cov) @@ -80,10 +132,10 @@ def sample_resonance_parameters(nuclide, n_samples): sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) - elif covsize/nparams == 5: + elif mpar == 5: param_list = ['energy','neutronWidth','captureWidth','fissionWidth'] - mean_array = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters[param_list]) - spin = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters['J']) + mean_array = pd.DataFrame.as_matrix(parameters[param_list]) + spin = pd.DataFrame.as_matrix(parameters['J']) mean = mean_array.flatten() for i in range(n_samples): sample = np.random.multivariate_normal(mean,cov) @@ -102,12 +154,12 @@ def sample_resonance_parameters(nuclide, n_samples): samples.append(sample_params) ### Handling RM Sampling ### if formalism == 'rm': - if covsize/nparams == 3: + if mpar == 3: param_list = ['energy','neutronWidth','captureWidth'] - mean_array = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters[param_list]) - spin = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters['J']) - gfa = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters['fissionWidthA']) - gfb = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters['fissionWidthB']) + mean_array = pd.DataFrame.as_matrix(parameters[param_list]) + spin = pd.DataFrame.as_matrix(parameters['J']) + gfa = pd.DataFrame.as_matrix(parameters['fissionWidthA']) + gfb = pd.DataFrame.as_matrix(parameters['fissionWidthB']) mean = mean_array.flatten() for i in range(n_samples): sample = np.random.multivariate_normal(mean,cov) @@ -123,10 +175,10 @@ def sample_resonance_parameters(nuclide, n_samples): sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) - elif covsize/nparams == 5: + elif mpar == 5: param_list = ['energy','neutronWidth','captureWidth','fissionWidthA','fissionWidthB'] - mean_array = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters[param_list]) - spin = pd.DataFrame.as_matrix(nuclide.res_covariance.ranges[0].parameters['J']) + mean_array = pd.DataFrame.as_matrix(parameters[param_list]) + spin = pd.DataFrame.as_matrix(parameters['J']) mean = mean_array.flatten() for i in range(n_samples): print("On sample",i) @@ -145,7 +197,7 @@ def sample_resonance_parameters(nuclide, n_samples): sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) - return samples + nuclide.samples = samples class ResonanceCovariance(object): """Resolved resonance covariance data @@ -184,13 +236,14 @@ class ResonanceCovariance(object): ranges) @classmethod - def from_endf(cls, ev): + def from_endf(cls, ev, resonances): """Generate resonance covariance data from an ENDF evaluation. Parameters ---------- ev : openmc.data.endf.Evaluation ENDF evaluation + resonances : Resonance object Returns ------- @@ -223,7 +276,7 @@ class ResonanceCovariance(object): if resonance_flag in (0, 1): # resolved resonance region - erange = _FORMALISMS[formalism].from_endf(ev, file_obj, items) + erange = _FORMALISMS[formalism].from_endf(ev, file_obj, items, resonances) elif resonance_flag == 2: warnings.warn('Unresolved resonance not supported.' @@ -256,7 +309,7 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): Attributes ---------- - cov_paramaters: list + cov_parameters: list The parameters that are included in the covariance matrix covariance_matrix : array The covariance matrix contained within the ENDF evaluation @@ -272,7 +325,7 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): self.formalism = 'mlbw' @classmethod - def from_endf(cls, ev, file_obj, items): + def from_endf(cls, ev, file_obj, items, resonances): """Create MLBW covariance data from an ENDF evaluation. Parameters @@ -285,6 +338,7 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): items : list Items from the CONT record at the start of the resonance range subsection + resonances : Resonance object Returns ------- @@ -347,10 +401,29 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): 'captureWidth', 'fissionWidth'] parameters = pd.DataFrame.from_records(records, columns=columns) + #Determine mpar (number of parameters for each resonance in + #covariance matrix) + nparams,params = parameters.shape + covsize = cov.shape[0] + mpar = int(covsize/nparams) + + #Use l-values and competitiveWidth from File 2 data + #Resort File 2 by energy to match File 32 + file2parameters=resonances.ranges[0].parameters.sort_values(by=['energy']) + file2parameters=file2parameters.reset_index(drop=True) + #Sort File 32 parameters by energy as well (maintaining index) + parameters_sort = parameters.sort_values(by=['energy']) + #Add in values (.values converts to array first to ignore index) + parameters_sort['L'] = file2parameters['L'].values + parameters_sort['competitiveWidth'] = file2parameters['competitiveWidth'].values + #Resort to File 32 order (essential for use with covariance!) + parameters = parameters_sort.sort_index() + # Create instance of class mlbw = cls(energy_min, energy_max) mlbw.parameters = parameters mlbw.covariance = cov + mlbw.mpar = mpar mlbw.lcomp = LCOMP mlbw.num_parameters = num_parameters @@ -393,10 +466,30 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): 'captureWidth', 'fissionWidth'] parameters = pd.DataFrame.from_records(records, columns=columns) + #Determine mpar (number of parameters for each resonance in + #covariance matrix) + nparams,params = parameters.shape + covsize = cov.shape[0] + mpar = int(covsize/nparams) + + #Use l-values and competitiveWidth from File 2 data + #Resort File 2 by energy to match File 32 + file2parameters=resonances.ranges[0].parameters.sort_values(by=['energy']) + file2parameters=file2parameters.reset_index(drop=True) + #Sort File 32 parameters by energy as well (maintaining index) + parameters_sort = parameters.sort_values(by=['energy']) + #Add in values (.values converts to array first to ignore index) + parameters_sort['L'] = file2parameters['L'].values + parameters_sort['competitiveWidth'] = file2parameters['competitiveWidth'].values + #Resort to File 32 order (essential for use with covariance!) + parameters = parameters_sort.sort_index() + + # Create instance of MultiLevelBreitWignerCovariance mlbw = cls(energy_min, energy_max) mlbw.parameters = parameters mlbw.covariance = cov + mlbw.mpar = mpar mlbw.lcomp = LCOMP return mlbw @@ -442,14 +535,41 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): 'captureWidth', 'fissionWidth'] parameters = pd.DataFrame.from_records(records, columns=columns) + #Determine mpar (number of parameters for each resonance in + #covariance matrix) + nparams,params = parameters.shape + covsize = cov.shape[0] + mpar = int(covsize/nparams) + + #Use l-values and competitiveWidth from File 2 data + #Resort File 2 by energy to match File 32 + file2parameters=resonances.ranges[0].parameters.sort_values(by=['energy']) + file2parameters=file2parameters.reset_index(drop=True) + #Sort File 32 parameters by energy as well (maintaining index) + parameters_sort = parameters.sort_values(by=['energy']) + #Add in values (.values converts to array first to ignore index) + parameters_sort['L'] = file2parameters['L'].values + parameters_sort['competitiveWidth'] = file2parameters['competitiveWidth'].values + #Resort to File 32 order (essential for use with covariance!) + parameters = parameters_sort.sort_index() + + # Create instance of class mlbw = cls(energy_min, energy_max) mlbw.parameters = parameters mlbw.covariance = cov + mlbw.mpar = mpar mlbw.lcomp = LCOMP return mlbw + def subset(self, parameter_str, bounds): + res_subset(self, parameter_str, bounds) + + def sample(self, n_samples, use_subset=False): + sample_resonance_parameters(self,n_samples,use_subset) + + class SingleLevelBreitWignerCovariance(MultiLevelBreitWignerCovariance): """Single-level Breit-Wigner resolved resonance formalism covariance data. @@ -527,7 +647,7 @@ class ReichMooreCovariance(ResonanceRange): ---------- num_parameters: list Number of parameters used in each subsection - cov_paramaters: list + cov_parameters: list The parameters that are included in the covariance matrix covariance_matrix : array The covariance matrix contained within the ENDF evaluation @@ -539,11 +659,11 @@ class ReichMooreCovariance(ResonanceRange): self.num_parameters = None self.parameters = None self.covariance = None - self.num_paramaters = None + self.num_parameters = None self.formalism = 'rm' @classmethod - def from_endf(cls, ev, file_obj, items): + def from_endf(cls, ev, file_obj, items, resonances): """Create Reich-Moore resonance covariance data from an ENDF evaluation. Includes the resonance parameters contained separately in File 32. @@ -557,6 +677,7 @@ class ReichMooreCovariance(ResonanceRange): items : list Items from the CONT record at the start of the resonance range subsection + resonances : Resonance object Returns ------- @@ -619,10 +740,28 @@ class ReichMooreCovariance(ResonanceRange): 'fissionWidthA', 'fissionWidthB'] parameters = pd.DataFrame.from_records(records, columns=columns) + #Determine mpar (number of parameters for each resonance in + #covariance matrix) + nparams,params = parameters.shape + covsize = cov.shape[0] + mpar = int(covsize/nparams) + + #Use l-values and competitiveWidth from File 2 data + #Resort File 2 by energy to match File 32 + file2parameters=resonances.ranges[0].parameters.sort_values(by=['energy']) + file2parameters=file2parameters.reset_index(drop=True) + #Sort File 32 parameters by energy as well (maintaining index) + parameters_sort = parameters.sort_values(by=['energy']) + #Add in values (.values converts to array first to ignore index) + parameters_sort['L'] = file2parameters['L'].values + #Resort to File 32 order (essential for use with covariance!) + parameters = parameters_sort.sort_index() + # Create instance of ReichMooreCovariance rmc = cls(energy_min, energy_max) rmc.parameters = parameters rmc.covariance = cov + rmc.mpar = mpar rmc.lcomp = LCOMP rmc.num_parameters = num_parameters @@ -635,8 +774,9 @@ class ReichMooreCovariance(ResonanceRange): energy = values[0::12] spin = values[1::12] gn = values[2::12] - gfa = values[3::12] - gfb = values[4::12] + gg = values[3::12] + gfa = values[4::12] + gfb = values[5::12] par_unc = [] for i in range(num_res): res_unc = values[i*12+6:i*12+12] @@ -646,25 +786,49 @@ class ReichMooreCovariance(ResonanceRange): records = [] for i, E in enumerate(energy): - records.append([energy[i], spin[i], gn[i], + records.append([energy[i], spin[i], gn[i], gg[i], gfa[i], gfb[i]]) corr = get_intg_record(file_obj) cov = np.diag(par_unc).dot(corr).dot(np.diag(par_unc)) # Create pandas DataFrame with resonacne data - columns = ['energy', 'J', 'neutronWidth', + columns = ['energy', 'J', 'neutronWidth', 'captureWidth', 'fissionWidthA', 'fissionWidthB'] parameters = pd.DataFrame.from_records(records, columns=columns) + #Determine mpar (number of parameters for each resonance in + #covariance matrix) + nparams,params = parameters.shape + covsize = cov.shape[0] + mpar = int(covsize/nparams) + + #Use l-values and competitiveWidth from File 2 data + #Resort File 2 by energy to match File 32 + file2parameters=resonances.ranges[0].parameters.sort_values(by=['energy']) + file2parameters=file2parameters.reset_index(drop=True) + #Sort File 32 parameters by energy as well (maintaining index) + parameters_sort = parameters.sort_values(by=['energy']) + #Add in values (.values converts to array first to ignore index) + parameters_sort['L'] = file2parameters['L'].values + #Resort to File 32 order (essential for use with covariance!) + parameters = parameters_sort.sort_index() + # Create instance of ReichMooreCovariance rmc = cls(energy_min, energy_max) rmc.parameters = parameters rmc.covariance = cov + rmc.mpar = mpar rmc.lcomp = LCOMP return rmc + def subset(self, parameter_str, bounds): + res_subset(self, parameter_str, bounds) + + def sample(self, n_samples, use_subset=False): + sample_resonance_parameters(self,n_samples,use_subset) + # _FORMALISMS = {0: ResonanceRange, # 1: SingleLevelBreitWigner, # 2: MultiLevelBreitWigner, From 79b473fa5b3674683277eff8df7a9e582177bfcf Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Mon, 4 Jun 2018 19:00:07 -0400 Subject: [PATCH 013/100] Initial implementation of MGXS C++ code --- src/constants.h | 60 +++ src/hdf5_interface.cpp | 146 ++++++++ src/hdf5_interface.h | 29 ++ src/mgxs.h | 95 +++++ src/scattdata.cpp | 831 +++++++++++++++++++++++++++++++++++++++++ src/scattdata.h | 106 ++++++ src/string_functions.h | 54 +++ src/xsdata.cpp | 782 ++++++++++++++++++++++++++++++++++++++ src/xsdata.h | 72 ++++ 9 files changed, 2175 insertions(+) create mode 100644 src/constants.h create mode 100644 src/mgxs.h create mode 100644 src/scattdata.cpp create mode 100644 src/scattdata.h create mode 100644 src/string_functions.h create mode 100644 src/xsdata.cpp create mode 100644 src/xsdata.h diff --git a/src/constants.h b/src/constants.h new file mode 100644 index 0000000000..b14984a146 --- /dev/null +++ b/src/constants.h @@ -0,0 +1,60 @@ + +#ifndef CONSTANTS_H +#define CONSTANTS_H + +#include +#include + +namespace openmc { + +typedef std::array dir_arr; +typedef std::vector double_1dvec; +typedef std::vector > double_2dvec; +typedef std::vector > > double_3dvec; +typedef std::vector > > > double_4dvec; +typedef std::vector > > > > double_5dvec; +typedef std::vector > > > > > double_6dvec; +typedef std::vector int_1dvec; +typedef std::vector > int_2dvec; +typedef std::vector > > int_3dvec; + +int constexpr MAX_SAMPLE {10000}; + +constexpr std::array VERSION {0, 10, 0}; +constexpr std::array VERSION_PARTICLE_RESTART {2, 0}; + +// Maximum number of words in a single line, length of line, and length of +// single word +constexpr int MAX_WORDS {500}; +constexpr int MAX_LINE_LEN {250}; +constexpr int MAX_WORD_LEN {150}; +constexpr int MAX_FILE_LEN {255}; + +// Physical Constants +constexpr double K_BOLTZMANN {8.6173303e-5}; // Boltzmann constant in eV/K + +// Angular distribution type +constexpr int ANGLE_ISOTROPIC {1}; +constexpr int ANGLE_32_EQUI {2}; +constexpr int ANGLE_TABULAR {3}; +constexpr int ANGLE_LEGENDRE {4}; +constexpr int ANGLE_HISTOGRAM {5}; + +// MGXS Table Types +constexpr int MGXS_ISOTROPIC {1}; // Isotroically weighted data +constexpr int MGXS_ANGLE {2}; // Data by angular bins + +// Flag to denote this was a macroscopic data object +constexpr double MACROSCOPIC_AWR {-2.}; + +// Number of mu bins to use when converting Legendres to tabular type +constexpr int DEFAULT_NMU {33}; + +// Temperature treatment method +constexpr int TEMPERATURE_NEAREST {1}; +constexpr int TEMPERATURE_INTERPOLATION {2}; + + +} // namespace openmc + +#endif // CONSTANTS_H \ No newline at end of file diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index 8a8391bb54..3d2f3ee7ba 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -447,6 +447,152 @@ read_complex(hid_t obj_id, const char* name, double _Complex* buffer, bool indep } +void +read_nd_vector(hid_t obj_id, const char* name, std::vector& result, + bool must_have) +{ + if (object_exists(obj_id, name)) { + read_double(obj_id, name, &result[0], true); + } else if (must_have) { + fatal_error(std::string("Must provide " + std::string(name) + "!")); + } +} + + +void +read_nd_vector(hid_t obj_id, const char* name, + std::vector >& result, bool must_have) +{ + if (object_exists(obj_id, name)) { + int dim1 = result.size(); + int dim2 = result[0].size(); + std::vector temp_arr = std::vector(dim1 * dim2); + read_double(obj_id, name, &temp_arr[0], true); + + int temp_idx = 0; + for (int i = 0; i < dim1; i++) { + for (int j = 0; j < dim2; j++) { + result[i][j] = temp_arr[temp_idx++]; + } + } + } else if (must_have) { + fatal_error(std::string("Must provide " + std::string(name) + "!")); + } +} + + +void +read_nd_vector(hid_t obj_id, const char* name, + std::vector > >& result, + bool must_have) +{ + if (object_exists(obj_id, name)) { + dim1 = result.size(); + dim2 = result[0].size(); + dim3 = result[0][0].size(); + std::vector temp_arr = std::vector(dim1 * dim2 * dim3); + read_double(obj_id, name, &temp_arr[0], true); + + int temp_idx = 0; + for (int i = 0; i < dim1; i++) { + for (int j = 0; j < dim2; j++) { + for (int k = 0; k < dim3; k++) { + result[i][j][k] = temp_arr[temp_idx++]; + } + } + } + } else if (must_have) { + fatal_error(std::string("Must provide " + std::string(name) + "!")); + } +} + +void +read_nd_vector(hid_t obj_id, const char* name, + std::vector > >& result, + bool must_have) +{ + if (object_exists(obj_id, name)) { + dim1 = result.size(); + dim2 = result[0].size(); + dim3 = result[0][0].size(); + std::vector temp_arr = std::vector(dim1 * dim2 * dim3); + read_int(obj_id, name, &temp_arr[0], true); + + int temp_idx = 0; + for (int i = 0; i < dim1; i++) { + for (int j = 0; j < dim2; j++) { + for (int k = 0; k < dim3; k++) { + result[i][j][k] = temp_arr[temp_idx++]; + } + } + } + } else if (must_have) { + fatal_error(std::string("Must provide " + std::string(name) + "!")); + } +} + +void +read_nd_vector(hid_t obj_id, const char* name, + std::vector > > >& result, + bool must_have) +{ + if (object_exists(obj_id, name)) { + dim1 = result.size(); + dim2 = result[0].size(); + dim3 = result[0][0].size(); + dim4 = result[0][0][0].size(); + std::vector temp_arr = std::vector( + dim1 * dim2 * dim3 * dim4); + read_double(obj_id, name, &temp_arr[0], true); + + int temp_idx = 0; + for (int i = 0; i < dim1; i++) { + for (int j = 0; j < dim2; j++) { + for (int k = 0; k < dim3; k++) { + for (int l = 0; l < dim4; l++) { + result[i][j][k][l] = temp_arr[temp_idx++]; + } + } + } + } + } else if (must_have) { + fatal_error(std::string("Must provide " + std::string(name) + "!")); + } +} + +void +read_nd_vector(hid_t obj_id, const char* name, + std::vector > > > >& result, + bool must_have) +{ + if (object_exists(obj_id, name)) { + dim1 = result.size(); + dim2 = result[0].size(); + dim3 = result[0][0].size(); + dim4 = result[0][0][0].size(); + dim5 = result[0][0][0][0].size(); + std::vector temp_arr = std::vector( + dim1 * dim2 * dim3 * dim4 * dim5); + read_double(obj_id, name, &temp_arr[0], true); + + int temp_idx = 0; + for (int i = 0; i < dim1; i++) { + for (int j = 0; j < dim2; j++) { + for (int k = 0; k < dim3; k++) { + for (int l = 0; l < dim4; l++) { + for (int m = 0; m < dim5; m++) { + result[i][j][k][l][m] = temp_arr[temp_idx++]; + } + } + } + } + } + } else if (must_have) { + fatal_error(std::string("Must provide " + std::string(name) + "!")); + } +} + + void read_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, double* results) { diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index e38a31e997..734cf0f919 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -55,6 +55,35 @@ extern "C" void read_string(hid_t obj_id, const char* name, size_t slen, extern "C" void read_complex(hid_t obj_id, const char* name, double _Complex* buffer, bool indep); +void +read_nd_vector(hid_t obj_id, const char* name, std::vector& result, + bool must_have = false); + +void +read_nd_vector(hid_t obj_id, const char* name, + std::vector >& result, + bool must_have = false); + +void +read_nd_vector(hid_t obj_id, const char* name, + std::vector > >& result, + bool must_have = false); + +void +read_nd_vector(hid_t obj_id, const char* name, + std::vector > >& result, + bool must_have = false); + +void +read_nd_vector(hid_t obj_id, const char* name, + std::vector > > >& result, + bool must_have = false); + +void +read_nd_vector(hid_t obj_id, const char* name, + std::vector > > > >& result, + bool must_have = false); + extern "C" void read_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, double* results); diff --git a/src/mgxs.h b/src/mgxs.h new file mode 100644 index 0000000000..8ed4ba99e3 --- /dev/null +++ b/src/mgxs.h @@ -0,0 +1,95 @@ +//! \file mgxs.h +//! A collection of classes for Multi-Group Cross Section data + +#ifndef MGXS_H +#define MGXS_H + +#include +#include +#include +#include +#include +#include + +#include "constants.h" +#include "hdf5_interface.h" +#include "math_functions.h" +#include "random_lcg.h" +#include "scattdata.h" +#include "string_functions.h" +#include "xsdata.h" + + +namespace openmc { + + +//============================================================================== +// MGXS contains the mgxs data for a nuclide/material +//============================================================================== + +class Mgxs { + private: + std::string name; // name of dataset, e.g., UO2 + double awr; // atomic weight ratio + double_1dvec kTs; // temperature in eV (k * T) + int scatter_format; // flag for if this is legendre, histogram, or tabular + int num_delayed_groups; // number of delayed neutron groups + int num_groups; // number of energy groups + int index_temp; // cache of temperature index + double last_sqrtkT; // cache of the temperature corresponding to index_temp + std::vector xs; // Cross section data + int n_pol; + int n_azi; + int index_pol; // cache fof the angle indices + int index_azi; + double_1dvec polar; + double_1dvec azimuthal; + dir_arr last_uvw; + void _metadata_from_hdf5(hid_t xs_id, int in_num_groups, + int in_num_delayed_groups, double_1dvec temperature, int& method, + double tolerance, double_1dvec& temps_to_read, int& order_dim); + + public: + bool fissionable; // Is this fissionable + void init(const std::string& in_name, double in_awr, double_1dvec& in_kTs, + bool in_fissionable, int in_scatter_format, int in_num_groups, + int in_num_delayed_groups, double_1dvec& in_polar, + double_1dvec& in_azimuthal); + void build_macro(const std::string& in_name, double_1dvec& mat_kTs, + std::vector& micros, double_1dvec& atom_densities, + int& method, double tolerance); + void combine(std::vector& micros, double_1dvec& scalars, + int_1dvec& micro_ts, int this_t); + void from_hdf5(hid_t xs_id, int energy_groups, int delayed_groups, + double_1dvec temperature, int& method, + double tolerance, int max_order, + bool legendre_to_tabular, + int legendre_to_tabular_points); + double get_xs(const char* xstype, int gin, int* gout, double* mu, + int* dg); + void sample_fission_energy(int gin, double nu_fission, int& dg, int& gout); + void sample_scatter(dir_arr& uvw, int gin, int& gout, double& mu, + double& wgt); + void calculate_xs(int gin, double sqrtkT, dir_arr& uvw, double& total_xs, + double& abs_xs, double& nu_fiss_xs); + bool equiv(const Mgxs& that); + inline void set_temperature_index(double sqrtkT); + inline void set_angle_index(dir_arr& uvw); +}; + +extern "C" void read_mgxs_library(hid_t file_id, int n_nuclides, char** names, + int energy_groups, int delayed_groups, int n_temps, double temps[], + int& method, double tolerance, int max_order, bool legendre_to_tabular, + int legendre_to_tabular_points); +extern "C" bool query_fissionable(const int i_nuclides[], const int n_nuclides); +void create_macro_xs(int n_materials, double_2dvec& mat_kTs, + std::vector& mat_names, double_1dvec& atom_densities, + int& method, double tolerance); + + +// Storage for the MGXS data +std::vector nuclides_MG; +std::vector macro_xs; + +} // namespace openmc +#endif // MGXS_H \ No newline at end of file diff --git a/src/scattdata.cpp b/src/scattdata.cpp new file mode 100644 index 0000000000..8283febc88 --- /dev/null +++ b/src/scattdata.cpp @@ -0,0 +1,831 @@ +#include "scattdata.h" + +namespace openmc { + +//============================================================================== +// Methods for use by all extended types +//============================================================================== + + + +//============================================================================== +// ScattData base-class methods +//============================================================================== + +void ScattData::generic_init(int order, int_1dvec in_gmin, + int_1dvec in_gmax, double_2dvec in_energy, double_2dvec in_mult) +{ + int groups = in_energy.size(); + + gmin = in_gmin; + gmax = in_gmax; + energy.resize(groups); + mult.resize(groups); + dist.resize(groups); + + for (int gin = 0; gin < groups; gin++) { + // Make sure the energy is normalized + double norm = std::accumulate(in_energy[gin].begin(), + in_energy[gin].end(), 0.); + + if (norm != 0.) { + for (auto& n : in_energy[gin]) n /= norm; + } + + // Store the inputted data + energy[gin] = in_energy[gin]; + mult[gin] = in_mult[gin]; + + // Initialize the distribution data + dist[gin].resize(in_gmax[gin] - in_gmin[gin] + 1); + for (auto& v : dist[gin]) { + v.resize(order); + for (auto& n : v) n = 0.; + } + } +} + + +void ScattData::sample_energy(int gin, int& gout, int& i_gout) +{ + // Sample the outgoing group + double xi = prn(); + i_gout = 0; //TODO: + 1? + gout = gmin[gin]; + double prob = energy[gin][i_gout]; + while((prob < xi) && (gout < gmax[gin])) { + gout++; + i_gout++; + prob += energy[gin][i_gout]; + } +} + + +double ScattData::get_xs(const char* xstype, int gin, int* gout, double* mu) +{ + // Set the outgoing group offset index as needed + int i_gout = 0; + if (gout != nullptr) { + // short circuit the function if gout is from a zero portion of the + // scattering matrix + if ((*gout < gmin[gin]) || (*gout >= gmax[gin])) { // > gmax? + return 0.; + } + i_gout = *gout - gmin[gin]; + } + + double val = 0.; + if (std::strcmp(xstype, "scatter")) { + if (gout != nullptr) { + val = scattxs[gin] * energy[gin][i_gout]; + } else { + val = scattxs[gin]; + } + } else if (std::strcmp(xstype, "scatter/mult")) { + if (gout != nullptr) { + val = scattxs[gin] * energy[gin][i_gout] / mult[gin][i_gout]; + } else { + val = scattxs[gin] / std::inner_product(mult[gin].begin(), + mult[gin].end(), + energy[gin].begin(), 0.0); + } + } else if (std::strcmp(xstype, "scatter*f_mu/mult")) { + if ((gout != nullptr) && (mu != nullptr)) { + val = scattxs[gin] * energy[gin][i_gout] * calc_f(gin, *gout, *mu); + } else { + // This is not an expected path (asking for f_mu without asking for a + // group or mu is not useful + fatal_error("Invalid call to get_xs"); + } + } else if (std::strcmp(xstype, "scatter*f_mu")) { + if ((gout != nullptr) && (mu != nullptr)) { + val = scattxs[gin] * energy[gin][i_gout] * calc_f(gin, *gout, *mu) / + mult[gin][i_gout]; + } else { + // This is not an expected path (asking for f_mu without asking for a + // group or mu is not useful + fatal_error("Invalid call to get_xs"); + } + } + return val; +} + + +//============================================================================== +// ScattDataLegendre methods +//============================================================================== + +void ScattDataLegendre::init(int_1dvec in_gmin, int_1dvec in_gmax, + double_2dvec in_mult, double_3dvec coeffs) +{ + int groups = coeffs.size(); + int order = coeffs[0].size(); + + // make a copy of coeffs that we can use to both extract data and normalize + double_3dvec matrix = coeffs; + + // Get the scattering cross section value by summing the un-normalized P0 + // coefficient in the variable matrix over all outgoing groups. + scattxs.resize(groups); + for (int gin = 0; gin < groups; gin++) { + int num_groups = gmax[gin] - gmin[gin] + 1; + scattxs[gin] = 0.; + for (int i_gout = 0; i_gout < num_groups; i_gout++) { + scattxs[gin] = std::accumulate(matrix[gin][i_gout].begin(), + matrix[gin][i_gout].end(), + scattxs[gin]); + } + } + + // Build the energy transfer matrix from data in the variable matrix while + // also normalizing the variable matrix itself + // (forcing the CDF of f(mu=1) == 1) + double_2dvec in_energy; + in_energy.resize(groups); + for (int gin = 0; gin < groups; gin++) { + int num_groups = gmax[gin] - gmin[gin] + 1; + in_energy[gin].resize(num_groups); + for (int i_gout = 0; i_gout < num_groups; i_gout++) { + double norm = matrix[gin][i_gout][0]; + in_energy[gin][i_gout] = norm; + if (norm != 0.) { + for (auto& n : matrix[gin][i_gout]) n /= norm; + } + } + } + + // Initialize the base class attributes + ScattData::generic_init(order, in_gmin, in_gmax, in_energy, in_mult); + + // Set the distribution (sdata.dist) values and initialize max_val + max_val.resize(groups); + for (int gin = 0; gin < groups; gin++) { + int num_groups = gmax[gin] - gmin[gin] + 1; + for (int i_gout = 0; i_gout < num_groups; i_gout++) { + dist[gin][i_gout] = matrix[gin][i_gout]; + } + max_val[gin].resize(num_groups); + for (auto& n : max_val[gin]) n = 0.; + } + + // Now update the maximum value + update_max_val(); +} + + +void ScattDataLegendre::update_max_val() +{ + int groups = max_val.size(); + // Step through the polynomial with fixed number of points to identify the + // maximal value + int Nmu = 1001; + double dmu = 2. / (Nmu - 1); + for (int gin = 0; gin < groups; gin++) { + int num_groups = gmax[gin] - gmin[gin] + 1; + for (int i_gout = 0; i_gout < num_groups; i_gout++) { + for (int imu = 0; imu < Nmu; imu++) { + double mu; + if (imu == 0) { + mu = -1.; + } else if (imu == (Nmu - 1)) { + mu = 1.; + } else { + mu = -1. + (imu - 1) * dmu; + } + + // Calculate probability + double f = evaluate_legendre_c(dist[gin][i_gout].size() - 1, + dist[gin][i_gout].data(), mu); + + // if this is a new maximum, store it + if (f > max_val[gin][i_gout]) max_val[gin][i_gout] = f; + } // end imu loop + + // Since we may not have caught the true max, add 10% margin + max_val[gin][i_gout] *= 1.1; + } + } +} + + +double ScattDataLegendre::calc_f(int gin, int gout, double mu) +{ + // TODO: gout >= or gout >? + double f; + if ((gout < gmin[gin]) || (gout >= gmax[gin])) { + f = 0.; + } else { + // TODO: size() -1 or just size? + int i_gout = gout - gmin[gin]; //TODO: + 1? + f = evaluate_legendre_c(dist[gin][i_gout].size() - 1, + dist[gin][i_gout].data(), mu); + } + return f; +} + + +void ScattDataLegendre::sample(int gin, int& gout, double& mu, double& wgt) +{ + // Sample the outgoing energy using the base-class method + int i_gout; + sample_energy(gin, gout, i_gout); + + // Now we can sample mu using the scattering kernel using rejection + // sampling from a rectangular bounding box + double M = max_val[gin][i_gout]; + int samples = 0; + + while(true) { + double mu = 2. * prn() - 1.; + double f = calc_f(gin, gout, mu); + if (f > 0.) { + double u = prn() * M; + if (u <= f) break; + } + samples++; + if (samples > MAX_SAMPLE) { + fatal_error("Maximum number of Legendre expansion samples reached"); + } + }; + + // Update the weight to reflect neutron multiplicity + wgt *= mult[gin][i_gout]; +} + + +void ScattDataLegendre::combine(std::vector those_scatts, + double_1dvec& scalars) +{ + int groups = energy.size(); + // Find the maximum order in the data set + int max_order = get_order(); + for (int i = 0; i < those_scatts.size(); i++) { + // Lets also make sure these items are combineable + ScattDataLegendre* that = dynamic_cast(those_scatts[i]); + if (!equiv(*that)) { + fatal_error("Cannot combine the ScattData objects!"); + } + int that_order = that->get_order(); + if (that_order > max_order) max_order = that_order; + } + max_order++; // Add one since this is a Legendre + + // Now allocate and zero our storage spaces + double_3dvec this_matrix = get_matrix(max_order); + double_2dvec mult_numer(groups, double_1dvec(groups, 0.)); + double_2dvec mult_denom(groups, double_1dvec(groups, 0.)); + + // Build the dense scattering and multiplicity matrices + // Get the multiplicity_matrix + // To combine from nuclidic data we need to use the final relationship + // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + // sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + // Developed as follows: + // mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} + // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) + // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + // sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + // nuscatt_{i,g,g'} can be reconstructed from the energy and scattxs member + // variables + for (int i = 0; i < those_scatts.size(); i++) { + ScattDataLegendre* that = dynamic_cast(those_scatts[i]); + + // Build the dense matrix for that object + double_3dvec that_matrix = that->get_matrix(max_order); + + // Now add that to this for the scattering and multiplicity + for (int gin = 0; gin < groups; gin++) { + // Only spend time adding that's gmin to gmax data since the rest will + // be zeros + for (int gout = that->gmin[gin]; gout <= that->gmax[gin]; gout++) { + // Do the scattering matrix + for (int l = 0; l < max_order; l++) { + this_matrix[gin][gout][l] += scalars[i] * that_matrix[gin][gout][l]; + } + + // Incorporate that's contribution to the multiplicity matrix data + double nuscatt = that->scattxs[gin] * that->energy[gin][gout]; + mult_numer[gin][gout] += scalars[i] * nuscatt; + if (that->mult[gin][gout] > 0.) { + mult_denom[gin][gout] += scalars[i] * nuscatt / that->mult[gin][gout]; + } else { + mult_denom[gin][gout] += scalars[i]; + } + } + } + } + + // Combine mult_numer and mult_denom into the combined multiplicity matrix + double_2dvec this_mult(groups, double_1dvec(groups, 1.)); + for (int gin = 0; gin < groups; gin++) { + for (int gout = 0; gout < groups; gout++) { + if (mult_denom[gin][gout] > 0.) { + this_mult[gin][gout] = mult_numer[gin][gout] / mult_denom[gin][gout]; + } + } + } + mult_numer.clear(); + mult_denom.clear(); + + // We have the data, now we need to convert to a jagged array and then use + // the initialize function to store it on the object. + int_1dvec in_gmin(groups); + int_1dvec in_gmax(groups); + double_3dvec sparse_scatter(groups); + double_2dvec sparse_mult(groups); + for (int gin = 0; gin < groups; gin++) { + // Find the minimum and maximum group boundaries + int gmin_; + for (gmin_ = 0; gmin_ < groups; gmin_++) { + bool non_zero = std::all_of(this_matrix[gin][gmin_].begin(), + this_matrix[gin][gmin_].end(), + [](double val){return val > 0.;}); + if (non_zero) break; + } + int gmax_; + for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) { + bool non_zero = std::all_of(this_matrix[gin][gmax_].begin(), + this_matrix[gin][gmax_].end(), + [](double val){return val > 0.;}); + if (non_zero) break; + } + + // treat the case of all values being 0 + if (gmin_ > gmax_) { + gmin_ = gin; + gmax_ = gin; + } + + // Store the group bounds + in_gmin[gin] = gmin_; + in_gmax[gin] = gmax_; + + // Store the data in the compressed format + sparse_scatter[gin].resize(gmax_ - gmin_ + 1); + sparse_mult[gin].resize(gmax_ - gmin_ + 1); + int i_gout = 0; + for (int gout = gmin_; gout <= gmax_; gout++) { + sparse_scatter[gin][i_gout] = this_matrix[gin][gout]; + sparse_mult[gin][i_gout] = this_mult[gin][gout]; + } + } + + // Got everything we need, store it. + init(in_gmin, in_gmax, sparse_mult, sparse_scatter); +} + + +bool ScattDataLegendre::equiv(const ScattDataLegendre& that) +{ + // ensure that the number of groups match + return (this->energy.size() == that.energy.size()); +} + + +double_3dvec ScattDataLegendre::get_matrix(int max_order) +{ + // Get the sizes and initialize the data to 0 + int groups = energy.size(); + int order_dim = max_order + 1; + double_3dvec matrix = double_3dvec(groups, double_2dvec(order_dim, + double_1dvec(order_dim, 0.))); + + for (int gin = 0; gin < groups; gin++) { + for (int i_gout = 0; i_gout < energy[0].size(); i_gout++) { + int gout = i_gout + gmin[gin]; + for (int l = 0; l < order_dim; l++) { + matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] * + dist[gin][i_gout][l]; + } + } + } + return matrix; +} + +//============================================================================== +// ScattDataHistogram methods +//============================================================================== + +void ScattDataHistogram::init(int_1dvec in_gmin, int_1dvec in_gmax, + double_2dvec in_mult, double_3dvec coeffs) +{ + int groups = coeffs.size(); + int order = coeffs[0].size(); + + // make a copy of coeffs that we can use to both extract data and normalize + double_3dvec matrix = coeffs; + + // Get the scattering cross section value by summing the distribution + // over all the histogram bins in angle and outgoing energy groups + scattxs.resize(groups); + for (int gin = 0; gin < groups; gin++) { + scattxs[gin] = 0.; + for (int i_gout = 0; i_gout < matrix[gin].size(); i_gout++) { + scattxs[gin] += std::accumulate(matrix[gin][i_gout].begin(), + matrix[gin][i_gout].end(), 0.); + } + } + + // Build the energy transfer matrix from data in the variable matrix + double_2dvec in_energy; + in_energy.resize(groups); + for (int gin = 0; gin < groups; gin++) { + int num_groups = gmax[gin] - gmin[gin] + 1; + in_energy[gin].resize(num_groups); + for (int i_gout = 0; i_gout < num_groups; i_gout++) { + double norm = std::accumulate(matrix[gin][i_gout].begin(), + matrix[gin][i_gout].end(), 0.); + if (norm != 0.) { + for (auto& n : matrix[gin][i_gout]) n /= norm; + } + } + } + + // Initialize the base class attributes + ScattData::generic_init(order, in_gmin, in_gmax, in_energy, + in_mult); + + // Build the angular distributio mu values + mu = double_1dvec(order); + dmu = 2. / order; + mu[0] = -1.; + for (int imu = 1; imu < order; imu++) { + mu[imu] = -1. + (imu - 1) * dmu; + } + + // Calculate f(mu) and integrate it so we can avoid rejection sampling + fmu.resize(groups); + for (int gin = 0; gin < groups; gin++) { + int num_groups = gmax[gin] - gmin[gin] + 1; + fmu[gin].resize(num_groups); + for (int i_gout = 0; i_gout < num_groups; i_gout) { + fmu[gin][i_gout].resize(order); + // The variable matrix contains f(mu); so directly assign it + fmu[gin][i_gout] = matrix[gin][i_gout]; + + // Integrate the histogram + dist[gin][i_gout][0] = dmu * matrix[gin][i_gout][0]; + for (int imu = 1; imu < order; imu++) { + dist[gin][i_gout][imu] = dmu * matrix[gin][i_gout][imu] + + dist[gin][i_gout][imu - 1]; + } + + // Now re-normalize for integral to unity + double norm = dist[gin][i_gout][order - 1]; + if (norm > 0.) { + for (int imu = 0; imu < order; imu++) { + fmu[gin][i_gout][imu] /= norm; + dist[gin][i_gout][imu] /= norm; + } + } + } + } +} + + +double ScattDataHistogram::calc_f(int gin, int gout, double mu) +{ + // TODO: gout >= or gout >? + double f; + if ((gout < gmin[gin]) || (gout >= gmax[gin])) { + f = 0.; + } else { + // Find mu bin + int i_gout = gout - gmin[gin]; //TODO: + 1? + int imu; + if (mu == 1.) { + // use size -2 to have the index one before the end + imu = this->mu.size() - 2; + } else { + imu = std::floor((mu + 1.) / dmu + 1.); + } + + f = fmu[gin][i_gout][imu]; + } + return f; +} + + +void ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt) +{ + // Sample the outgoing energy using the base-class method + int i_gout; + sample_energy(gin, gout, i_gout); + + // Determine the outgoing cosine bin + double xi = prn(); + + int imu; + if (xi < dist[gin][i_gout][0]) { + imu = 1; + } else { + // TODO lower_bound? + 1? + imu = std::upper_bound(dist[gin][i_gout].begin(), + dist[gin][i_gout].end(), xi) - + dist[gin][i_gout].begin(); + } + + // Randomly select mu within the imu bin + mu = prn() * dmu + this->mu[imu]; + + if (mu < -1.) { + mu = -1.; + } else if (mu > 1.) { + mu = 1.; + } + + // Update the weight to reflect neutron multiplicity + wgt *= mult[gin][i_gout]; +} + + +bool ScattDataHistogram::equiv(const ScattDataHistogram& that) +{ + bool match = false; + if (this->energy.size() == that.energy.size() && + this->dmu == that.dmu && + std::equal(this->mu.begin(), this->mu.end(), that.mu.begin())) { + match = true; + } + return match; +} + + +double_3dvec ScattDataHistogram::get_matrix(int max_order) +{ + // Get the sizes and initialize the data to 0 + int groups = energy.size(); + // We ignore the requested order for Histogram and Tabular representations + int order_dim = get_order(); + double_3dvec matrix = double_3dvec(groups, double_2dvec(order_dim, + double_1dvec(order_dim, 0.))); + + for (int gin = 0; gin < groups; gin++) { + for (int i_gout = 0; i_gout < energy[0].size(); i_gout++) { + int gout = i_gout + gmin[gin]; + for (int l = 0; l < order_dim; l++) { + matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] * + fmu[gin][i_gout][l]; + } + } + } + return matrix; +} + +//============================================================================== +// ScattDataTabular methods +//============================================================================== + +void ScattDataTabular::init(int_1dvec in_gmin, int_1dvec in_gmax, + double_2dvec in_mult, double_3dvec coeffs) +{ + int groups = coeffs.size(); + int order = coeffs[0].size(); + + // make a copy of coeffs that we can use to both extract data and normalize + double_3dvec matrix = coeffs; + + // Build the angular distribution mu values + mu = double_1dvec(order); + dmu = 2. / (order - 1); + mu[0] = -1.; + for (int imu = 1; imu < order - 1; imu++) { + mu[imu] = -1. + (imu - 1) * dmu; + } + mu[order - 1] = 1.; + + // Get the scattering cross section value by integrating the distribution + // over all mu points and then combining over all outgoing groups + scattxs.resize(groups); + for (int gin = 0; gin < groups; gin++) { + scattxs[gin] = 0.; + for (int i_gout = 0; i_gout < matrix[gin].size(); i_gout++) { + for (int imu = 1; imu < order; imu++) { + scattxs[gin] += 0.5 * dmu * (matrix[gin][i_gout][imu - 1] + + matrix[gin][i_gout][imu]); + } + } + } + + // Build the energy transfer matrix from data in the variable matrix + double_2dvec in_energy; + in_energy.resize(groups); + for (int gin = 0; gin < groups; gin++) { + int num_groups = gmax[gin] - gmin[gin] + 1; + in_energy[gin].resize(num_groups); + for (int i_gout = 0; i_gout < num_groups; i_gout++) { + double norm = 0.; + for (int imu = 1; imu < order; imu++) { + norm += 0.5 * dmu * (matrix[gin][i_gout][imu - 1] + + matrix[gin][i_gout][imu]); + } + if (norm != 0.) { + for (auto& n : matrix[gin][i_gout]) n /= norm; + } + } + } + + // Initialize the base class attributes + ScattData::generic_init(order, in_gmin, in_gmax, in_energy, + in_mult); + + // Calculate f(mu) and integrate it so we can avoid rejection sampling + fmu.resize(groups); + for (int gin = 0; gin < groups; gin++) { + int num_groups = gmax[gin] - gmin[gin] + 1; + fmu[gin].resize(num_groups); + for (int i_gout = 0; i_gout < num_groups; i_gout) { + fmu[gin][i_gout].resize(order); + // The variable matrix contains f(mu); so directly assign it + fmu[gin][i_gout] = matrix[gin][i_gout]; + + // Ensure positivity + for (auto& val : fmu[gin][i_gout]) { + if (val < 0.) val = 0.; + } + + // Now re-normalize for numerical integration issues and to take care of + // the above negative fix-up. Also accrue the CDF + double norm = 0.; + for (int imu = 1; imu < order; imu++) { + norm += 0.5 * dmu * (fmu[gin][i_gout][imu - 1] + + fmu[gin][i_gout][imu]); + // incorporate to the CDF + dist[gin][i_gout][imu] = norm; + } + + // now do the normalization + if (norm > 0.) { + for (int imu = 0; imu < order; imu++) { + fmu[gin][i_gout][imu] /= norm; + dist[gin][i_gout][imu] /= norm; + } + } + } + } +} + + +double ScattDataTabular::calc_f(int gin, int gout, double mu) +{ + // TODO: gout >= or gout >? + double f; + if ((gout < gmin[gin]) || (gout >= gmax[gin])) { + f = 0.; + } else { + // Find mu bin + int i_gout = gout - gmin[gin]; //TODO: + 1? + int imu; + if (mu == 1.) { + // use size -2 to have the index one before the end + imu = this->mu.size() - 2; + } else { + imu = std::floor((mu + 1.) / dmu + 1.); + } + + double r = (mu - this->mu[imu]) / (this->mu[imu + 1] - this->mu[imu]); + f = (1. - r) * fmu[gin][i_gout][imu] + r * fmu[gin][i_gout][imu + 1]; + } + return f; +} + + +void ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt) +{ + // Sample the outgoing energy using the base-class method + int i_gout; + sample_energy(gin, gout, i_gout); + + // Determine the outgoing cosine bin + int NP = this->mu.size(); + double xi = prn(); + + double c_k = dist[gin][i_gout][0]; + int k; + for (k = 0; k < NP - 2; k++) { + double c_k1 = dist[gin][i_gout][k + 1]; + if (xi < c_k1) break; + c_k = c_k1; + } + + // Check to make sure k is <= NP - 1 + k = std::min(k, NP - 1); + + // Find the pdf values we want + double p0 = fmu[gin][i_gout][k]; + double mu0 = this -> mu[k]; + double p1 = fmu[gin][i_gout][k + 1]; + double mu1 = this -> mu[k + 1]; + + if (p0 == p1) { + mu = mu0 + (xi - c_k) / p0; + } else { + double frac = (p1 - p0) / (mu1 - mu0); + mu = mu0 + (std::sqrt(std::max(0., p0 * p0 + 2. * frac * (xi - c_k))) + - p0) / frac; + } + + if (mu < -1.) { + mu = -1.; + } else if (mu > 1.) { + mu = 1.; + } + + // Update the weight to reflect neutron multiplicity + wgt *= mult[gin][i_gout]; +} + + +bool ScattDataTabular::equiv(const ScattDataTabular& that) +{ + bool match = false; + if (this->energy.size() == that.energy.size() && + this->dmu == that.dmu && + std::equal(this->mu.begin(), this->mu.end(), that.mu.begin())) { + match = true; + } + return match; +} + + +double_3dvec ScattDataTabular::get_matrix(int max_order) +{ + // Get the sizes and initialize the data to 0 + int groups = energy.size(); + // We ignore the requested order for Histogram and Tabular representations + int order_dim = get_order(); + double_3dvec matrix = double_3dvec(groups, double_2dvec(order_dim, + double_1dvec(order_dim, 0.))); + + for (int gin = 0; gin < groups; gin++) { + for (int i_gout = 0; i_gout < energy[0].size(); i_gout++) { + int gout = i_gout + gmin[gin]; + for (int l = 0; l < order_dim; l++) { + matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] * + fmu[gin][i_gout][l]; + } + } + } + return matrix; +} + + +void convert_legendre_to_tabular(ScattDataLegendre& leg, + ScattDataTabular& tab, int n_mu) +{ + // Copy the obvious data + tab.energy = leg.energy; + tab.mult = leg.mult; + tab.gmin = leg.gmin; + tab.gmax = leg.gmax; + + // Build mu and dmu + tab.mu = double_1dvec(n_mu); + tab.dmu = 2. / (n_mu - 1); + tab.mu[0] = -1.; + for (int imu = 1; imu < n_mu - 1; imu++) { + tab.mu[imu] = -1. + (imu - 1) * tab.dmu; + } + tab.mu[n_mu - 1] = 1.; + + // Calculate f(mu) and integrate it so we can avoid rejection sampling + int groups = tab.energy.size(); + tab.fmu.resize(groups); + for (int gin = 0; gin < groups; gin++) { + int num_groups = tab.gmax[gin] - tab.gmin[gin] + 1; + tab.fmu[gin].resize(num_groups); + for (int i_gout = 0; i_gout < num_groups; i_gout) { + tab.fmu[gin][i_gout].resize(n_mu); + for (int imu = 0; imu < n_mu; imu++) { + tab.fmu[gin][i_gout][imu] = + evaluate_legendre_c(leg.dist[gin][i_gout].size() - 1, + leg.dist[gin][i_gout].data(), tab.mu[imu]); + } + + // Ensure positivity + for (auto& val : tab.fmu[gin][i_gout]) { + if (val < 0.) val = 0.; + } + + // Now re-normalize for numerical integration issues and to take care of + // the above negative fix-up. Also accrue the CDF + double norm = 0.; + for (int imu = 1; imu < n_mu; imu++) { + norm += 0.5 * tab.dmu * (tab.fmu[gin][i_gout][imu - 1] + + tab.fmu[gin][i_gout][imu]); + // incorporate to the CDF + tab.dist[gin][i_gout][imu] = norm; + } + + // now do the normalization + if (norm > 0.) { + for (int imu = 0; imu < n_mu; imu++) { + tab.fmu[gin][i_gout][imu] /= norm; + tab.dist[gin][i_gout][imu] /= norm; + } + } + } + } +} + +} // namespace openmc diff --git a/src/scattdata.h b/src/scattdata.h new file mode 100644 index 0000000000..787a8f005d --- /dev/null +++ b/src/scattdata.h @@ -0,0 +1,106 @@ +//! \file scattdata.h +//! A collection of multi-group scattering data classes + +#ifndef SCATTDATA_H +#define SCATTDATA_H + +#include +#include +#include +#include + +#include "constants.h" +#include "math_functions.h" +#include "random_lcg.h" +#include "error.h" + +namespace openmc { + +//============================================================================== +// SCATTDATA contains all the data needed to describe the scattering energy and +// angular distribution data +//============================================================================== +// temporary declaations so we can name our friend functions +class ScattDataLegendre; +class ScattDataTabular; + +class ScattData { + protected: + double_2dvec energy; // Normalized p0 matrix for sampling Eout + double_2dvec mult; // nu-scatter multiplication (nu-scatt/scatt) + double_3dvec dist; // Angular distribution + int_1dvec gmin; // minimum outgoing group + int_1dvec gmax; // maximum outgoing group + public: + double_1dvec scattxs; // Isotropic Sigma_{s,g_{in}} + virtual double calc_f(int gin, int gout, double mu) = 0; + virtual void sample(int gin, int& gout, double& mu, double& wgt) = 0; + virtual void init(int_1dvec in_gmin, int_1dvec in_gmax, + double_2dvec in_mult, double_3dvec coeffs) = 0; + void sample_energy(int gin, int& gout, int& i_gout); + double get_xs(const char* xstype, int gin, int* gout, double* mu); + void generic_init(int order, int_1dvec in_gmin, int_1dvec in_gmax, + double_2dvec in_energy, double_2dvec in_mult); + virtual void combine(std::vector those_scatts, + double_1dvec& scalars) = 0; + virtual int get_order() = 0; + virtual double_3dvec get_matrix(int max_order) = 0; +}; + +class ScattDataLegendre: public ScattData { + protected: + // Maximal value for rejection sampling from a rectangle + double_2dvec max_val; + friend void convert_legendre_to_tabular(ScattDataLegendre& leg, + ScattDataTabular& tab, int n_mu); + public: + void init(int_1dvec in_gmin, int_1dvec in_gmax, double_2dvec in_mult, + double_3dvec coeffs); + void update_max_val(); + double calc_f(int gin, int gout, double mu); + void sample(int gin, int& gout, double& mu, double& wgt); + bool equiv(const ScattDataLegendre& that); + void combine(std::vector those_scatts, double_1dvec& scalars); + int get_order() {return dist[0][0].size() - 1;}; + double_3dvec get_matrix(int max_order); +}; + +class ScattDataHistogram: public ScattData { + protected: + double_1dvec mu; + double dmu; + double_3dvec fmu; + public: + void init(int_1dvec in_gmin, int_1dvec in_gmax, double_2dvec in_mult, + double_3dvec coeffs); + double calc_f(int gin, int gout, double mu); + void sample(int gin, int& gout, double& mu, double& wgt); + void combine(std::vector those_scatts, double_1dvec& scalars); + bool equiv(const ScattDataHistogram& that); + int get_order() {return dist[0][0].size();}; + double_3dvec get_matrix(int max_order); +}; + +class ScattDataTabular: public ScattData { + protected: + double_1dvec mu; + double dmu; + double_3dvec fmu; + friend void convert_legendre_to_tabular(ScattDataLegendre& leg, + ScattDataTabular& tab, int n_mu); + public: + void init(int_1dvec in_gmin, int_1dvec in_gmax, double_2dvec in_mult, + double_3dvec coeffs); + double calc_f(int gin, int gout, double mu); + void sample(int gin, int& gout, double& mu, double& wgt); + void combine(std::vector those_scatts, double_1dvec& scalars); + bool equiv(const ScattDataTabular& that); + int get_order() {return dist[0][0].size();}; + double_3dvec get_matrix(int max_order); +}; + +void convert_legendre_to_tabular(ScattDataLegendre& leg, + ScattDataTabular& tab, int n_mu); + +} // namespace openmc +#endif // SCATTDATA_H \ No newline at end of file diff --git a/src/string_functions.h b/src/string_functions.h new file mode 100644 index 0000000000..94d4ce6278 --- /dev/null +++ b/src/string_functions.h @@ -0,0 +1,54 @@ +//! \file string_functions.h +//! A collection of helper routines for C-strings and STL strings + +#ifndef STRING_FUNCTIONS_H +#define STRING_FUNCTIONS_H + +// for string functions +#include +#include +#include +#include + +namespace openmc { + +void strtrim(char* str) +{ + int start = 0; // number of leading spaces + char* buffer = str; + + while (*str && *str++ == ' ') ++start; + + while (*str++); // move to end of string + + // backup over trailing spaces + int end = str - buffer - 1; + while (end > 0 && buffer[end - 1] == ' ') --end; + buffer[end] = 0; // remove trailing spaces + + // exit if no leading spaces or string is now empty + if (end <= start || start == 0) return; + str = buffer + start; + + while ((*buffer++ = *str++)); // remove leading spaces: K&R +} + +std::string strtrim(std::string in_str) +{ + std::string str = in_str; + // perform the left trim + str.erase(str.begin(), std::find_if(str.begin(), str.end(), + std::not1(std::ptr_fun(std::isspace)))); + // perform the right trim + str.erase(std::find_if(str.rbegin(), str.rend(), + std::not1(std::ptr_fun(std::isspace))).base(), + str.end()); +} + +void to_lower(std::string& str) +{ + for (int i = 0; i < str.size(); i++) str[i] = std::tolower(str[i]); +} + +} // namespace openmc +#endif // STRING_FUNCTIONS_H \ No newline at end of file diff --git a/src/xsdata.cpp b/src/xsdata.cpp new file mode 100644 index 0000000000..a027b18dd4 --- /dev/null +++ b/src/xsdata.cpp @@ -0,0 +1,782 @@ +#include "xsdata.h" + +namespace openmc { + +//============================================================================== +// XsData class methods +//============================================================================== + +XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable, + int scatter_format, int n_pol, int n_azi) +{ + // check to make sure scatter format is OK before we allocate + if (scatter_format != ANGLE_HISTOGRAM && scatter_format != ANGLE_TABULAR && + scatter_format != ANGLE_LEGENDRE) { + fatal_error("Invalid scatter_format!"); + } + // allocate all [temperature][phi][theta][in group] quantities + total = double_3dvec(n_pol, double_2dvec(n_azi, + double_1dvec(energy_groups, 0.))); + absorption = double_3dvec(n_pol, double_2dvec(n_azi, + double_1dvec(energy_groups, 0.))); + inverse_velocity = double_3dvec(n_pol, + double_2dvec(n_azi, double_1dvec(energy_groups, 0.))); + if (fissionable) { + fission = double_3dvec(n_pol, double_2dvec(n_azi, + double_1dvec(energy_groups, 0.))); + prompt_nu_fission = double_3dvec(n_pol, double_2dvec(n_azi, + double_1dvec(energy_groups, 0.))); + kappa_fission = double_3dvec(n_pol, double_2dvec(n_azi, + double_1dvec(energy_groups, 0.))); + } + + // allocate decay_rate; [temperature][phi][theta][delayed group] + decay_rate = double_3dvec(n_pol, double_2dvec(n_azi, + double_1dvec(num_delayed_groups, 0.))); + + if (fissionable) { + // allocate delayed_nu_fission; [temperature][phi][theta][in group][out group] + delayed_nu_fission = double_4dvec(n_pol, double_3dvec(n_azi, + double_2dvec(energy_groups, double_1dvec(energy_groups, 0.)))); + + // chi_prompt; [temperature][phi][theta][in group][delayed group] + chi_prompt = double_4dvec(n_pol, double_3dvec(n_azi, + double_2dvec(energy_groups, double_1dvec(num_delayed_groups, 0.)))); + + // chi_delayed; [temperature][phi][theta][in group][out group][delay group] + chi_delayed = double_5dvec(n_pol, double_4dvec(n_azi, + double_3dvec(energy_groups, double_2dvec(energy_groups, + double_1dvec(num_delayed_groups, 0.))))); + } + + scatter.resize(n_pol); + for (int p = 0; p < n_pol; p++) { + scatter[p].resize(n_azi); + for (int a = 0; a < n_azi; a++) { + if (scatter_format == ANGLE_HISTOGRAM) { + scatter[p][a] = new ScattDataHistogram; + } else if (scatter_format == ANGLE_TABULAR) { + scatter[p][a] = new ScattDataTabular; + } else if (scatter_format == ANGLE_LEGENDRE) { + scatter[p][a] = new ScattDataLegendre; + } + } + } +} + +XsData::~XsData() +{ + for (int p = 0; p < scatter.size(); p++) { + for (int a = 0; a < scatter[p].size(); a++) delete scatter[p][a]; + scatter[p].clear(); + } + scatter.clear(); +} + + +void XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, + int final_scatter_format, int order_data, int max_order, + int legendre_to_tabular_points) +{ + // Reconstruct the dimension information so it doesn't need to be passed + int n_pol = total.size(); + int n_azi = total[0].size(); + int energy_groups = total[0][0].size(); + int delayed_groups = decay_rate[0][0].size(); + + // Set the fissionable-specific data + if (fissionable) { + _fissionable_from_hdf5(xsdata_grp, n_pol, n_azi, energy_groups, + delayed_groups); + } + // Get the non-fission-specific data + read_nd_vector(xsdata_grp, "decay_rate", decay_rate); + read_nd_vector(xsdata_grp, "absorption", absorption, true); + read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); + + // Get scattering data + _scatter_from_hdf5(xsdata_grp, n_pol, n_azi, energy_groups, scatter_format, + final_scatter_format, order_data, max_order, + legendre_to_tabular_points); + + // Check absorption to ensure it is not 0 since it is often the + // denominator in tally methods + for (int p = 0; p < n_pol; p++) { + for (int a = 0; a < n_azi; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + if (absorption[gin][p][a] == 0.) { + absorption[p][a][gin] = 1.e-10; + } + } + } + } + + // Get or calculate the total x/s + if (object_exists(xsdata_grp, "total")) { + read_nd_vector(xsdata_grp, "total", total); + } else { + for (int p = 0; p < n_pol; p++) { + for (int a = 0; a < n_azi; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + total[p][a][gin] = absorption[p][a][gin] + + scatter[p][a]->scattxs[gin]; + } + } + } + } + + // Check total to ensure it is not 0 since it is often the denominator in + // tally methods + for (int p = 0; p < n_pol; p++) { + for (int a = 0; a < n_azi; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + if (total[p][a][gin] == 0.) total[p][a][gin] = 1.e-10; + } + } + } +} + + +void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, + int energy_groups, int delayed_groups) +{ + double_4dvec temp_beta = + double_4dvec(n_pol, double_3dvec(n_azi, + double_2dvec(energy_groups, double_1dvec(delayed_groups, 0.)))); + + // Set/get beta + if (object_exists(xsdata_grp, "beta")) { + hid_t xsdata = open_dataset(xsdata_grp, "beta"); + int ndims = dataset_ndims(xsdata); + + if (ndims == 3) { + // Beta is input as [delayed group] + double_1dvec temp_arr = double_1dvec(n_pol * n_azi * delayed_groups); + read_nd_vector(xsdata_grp, "beta", temp_arr); + + // Broadcast to all incoming groups + int temp_idx = 0; + for (int p = 0; p < n_pol; p++) { + for (int a = 0; a < n_azi; a++) { + for (int dg = 0; dg < delayed_groups; dg++) { + // Set the first group index and copy the rest + temp_beta[p][a][0][dg] = temp_arr[temp_idx++]; + for (int gin = 1; gin < energy_groups; gin++) { + temp_beta[p][a][gin] = temp_beta[p][a][0]; + } + } + } + } + } else if (ndims == 4) { + // Beta is input as [in group][delayed group] + read_nd_vector(xsdata_grp, "beta", temp_beta); + } else { + fatal_error("beta must be provided as a 1D or 2D array!"); + } + } + + // If chi is provided, set chi-prompt and chi-delayed + if (object_exists(xsdata_grp, "chi")) { + double_3dvec temp_arr = double_3dvec(n_pol, double_2dvec(n_azi, + double_1dvec(energy_groups))); + read_nd_vector(xsdata_grp, "chi", temp_arr); + + int temp_idx = 0; + for (int p = 0; p < n_pol; p++) { + for (int a = 0; a < n_azi; a++) { + // First set the first group + for (int gout = 0; gout < energy_groups; gout++) { + chi_prompt[p][a][0][gout] = temp_arr[p][a][temp_idx++]; + } + + // Now normalize this data + double chi_sum = std::accumulate(chi_prompt[p][a][0].begin(), + chi_prompt[p][a][0].end(), + 0.); + if (chi_sum <= 0.) { + fatal_error("Encountered chi for a group that is <= 0!"); + } + for (int gout = 0; gout < energy_groups; gout++) { + chi_prompt[p][a][0][gout] /= chi_sum; + } + + // And extend to the remaining incoming groups + for (int gin = 1; gin < energy_groups; gin++) { + chi_prompt[p][a][gin] = chi_prompt[p][a][0]; + } + + // Finally set chi-delayed equal to chi-prompt + // Set chi-delayed to chi-prompt + for(int gin = 0; gin < energy_groups; gin++) { + for (int gout = 0; gout < energy_groups; gout++) { + for (int dg = 0; dg < delayed_groups; dg++) { + chi_delayed[p][a][gin][gout][dg] = + chi_prompt[p][a][gin][gout]; + } + } + } + } + } + } + + // If nu-fission is provided, set prompt- and delayed-nu-fission; + // if nu-fission is a matrix, set chi-prompt and chi-delayed. + if (object_exists(xsdata_grp, "nu-fission")) { + hid_t xsdata = open_dataset(xsdata_grp, "nu-fission"); + int ndims = dataset_ndims(xsdata); + + if (ndims == 3) { + // nu-fission is a 3-d array + read_nd_vector(xsdata_grp, "nu-fission", prompt_nu_fission); + + // set delayed-nu-fission and correct prompt-nu-fission with beta + for (int p = 0; p < n_pol; p++) { + for (int a = 0; a < n_azi; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + for (int dg = 0; dg < delayed_groups; dg++) { + delayed_nu_fission[p][a][gin][dg] = + temp_beta[p][a][gin][dg] * + prompt_nu_fission[p][a][gin]; + } + + // Correct the prompt-nu-fission using the delayed neutron fraction + if (delayed_groups > 0) { + double beta_sum = std::accumulate(temp_beta[p][a][gin].begin(), + temp_beta[p][a][gin].end(), 0.); + prompt_nu_fission[p][a][gin] *= (1. - beta_sum); + } + } + } + } + + } else if (ndims == 4) { + // nu-fission is a matrix + read_nd_vector(xsdata_grp, "nu_fission", chi_prompt); + + // Normalize the chi info so the CDF is 1. + for (int p = 0; p < n_pol; p++) { + for (int a = 0; a < n_azi; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + double chi_sum = std::accumulate(chi_prompt[p][a][gin].begin(), + chi_prompt[p][a][gin].end(), 0.); + if (chi_sum >= 0.) { + for (int gout = 0; gout < energy_groups; gout++) { + chi_prompt[p][a][gin][gout] /= chi_sum; + } + } else { + fatal_error("Encountered chi for a group that is <= 0!"); + } + } + + // set chi-delayed to chi-prompt + for (int gin = 0; gin < energy_groups; gin++) { + for (int gout = 0; gout < energy_groups; gout++) { + for (int dg = 0; dg < delayed_groups; dg++) { + chi_delayed[p][a][gin][gout][dg] = + chi_prompt[p][a][gin][gout]; + } + } + } + + // Set the vector nu-fission from the matrix nu-fission + for (int gin = 0; gin < energy_groups; gin++) { + double sum = std::accumulate(chi_prompt[p][a][gin].begin(), + chi_prompt[p][a][gin].end(), 0.); + prompt_nu_fission[p][a][gin] = sum; + } + + // Set the delayed-nu-fission and correct prompt-nu-fission with beta + for (int gin = 0; gin < energy_groups; gin++) { + for (int dg = 0; dg < delayed_groups; dg++) { + delayed_nu_fission[p][a][gin][dg] = + temp_beta[p][a][gin][dg] * + prompt_nu_fission[p][a][gin]; + } + + // Correct prompt-nu-fission using the delayed neutron fraction + if (delayed_groups > 0) { + double beta_sum = std::accumulate(temp_beta[p][a][gin].begin(), + temp_beta[p][a][gin].end(), 0.); + prompt_nu_fission[p][a][gin] *= (1. - beta_sum); + } + } + } + } + } else { + fatal_error("beta must be provided as a 3D or 4D array!"); + } + + close_dataset(xsdata); + } + + // If chi-prompt is provided, set chi-prompt + if (object_exists(xsdata_grp, "chi-prompt")) { + double_3dvec temp_arr = double_3dvec(n_pol, double_2dvec(n_azi, + double_1dvec(energy_groups))); + read_nd_vector(xsdata_grp, "chi-prompt", temp_arr); + + for (int a = 0; a < n_azi; a++) { + for (int p = 0; p < n_pol; p++) { + for (int gin = 0; gin < energy_groups; gin++) { + for (int gout = 0; gout < energy_groups; gout++) { + chi_prompt[p][a][gin][gout] = temp_arr[p][a][gout]; + } + + // Normalize chi so its CDF goes to 1 + double chi_sum = std::accumulate(chi_prompt[p][a][gin].begin(), + chi_prompt[p][a][gin].end(), 0.); + if (chi_sum >= 0.) { + for (int gout = 0; gout < energy_groups; gout++) { + chi_prompt[p][a][gin][gout] /= chi_sum; + } + } else { + fatal_error("Encountered chi-prompt for a group that is <= 0.!"); + } + } + } + } + } + + // If chi-delayed is provided, set chi-delayed + if (object_exists(xsdata_grp, "chi-delayed")) { + hid_t xsdata = open_dataset(xsdata_grp, "chi-delayed"); + int ndims = dataset_ndims(xsdata); + close_dataset(xsdata); + + if (ndims == 3) { + // chi-delayed is a [in group] vector + double_3dvec temp_arr = double_3dvec(n_pol, double_2dvec(n_azi, + double_1dvec(energy_groups))); + read_nd_vector(xsdata_grp, "chi-delayed", temp_arr); + + for (int a = 0; a < n_azi; a++) { + for (int p = 0; p < n_pol; p++) { + // normalize the chi CDF to 1 + double chi_sum = std::accumulate(temp_arr[p][a].begin(), + temp_arr[p][a].end(), 0.); + if (chi_sum <= 0.) { + fatal_error("Encountered chi-delayed for a group that is <= 0!"); + } + + // set chi-delayed + for (int gin = 0; gin < energy_groups; gin++) { + for (int gout = 0; gout < energy_groups; gout++) { + for (int dg = 0; dg < delayed_groups; dg++) { + chi_delayed[p][a][gin][gout][dg] = + temp_arr[p][a][gout] / chi_sum; + } + } + } + } + } + } else if (ndims == 4) { + // chi_delayed is a matrix + read_nd_vector(xsdata_grp, "chi-delayed", chi_delayed); + + // Normalize the chi info so the CDF is 1. + for (int a = 0; a < n_azi; a++) { + for (int p = 0; p < n_pol; p++) { + for (int dg = 0; dg < delayed_groups; dg++) { + for (int gin = 0; gin < energy_groups; gin++) { + double chi_sum = 0.; + for (int gout = 0; gout < energy_groups; gout++) { + chi_sum += chi_delayed[p][a][gin][gout][dg]; + } + + if (chi_sum > 0.) { + for (int gout = 0; gout < energy_groups; gout++) { + chi_delayed[p][a][gin][gout][dg] /= chi_sum; + } + } else { + fatal_error("Encountered chi-delayed for a group that is <= 0!"); + } + } + } + } + } + } else { + fatal_error("chi-delayed must be provided as a 3D or 4D array!"); + } + } + + // Get prompt-nu-fission, if present + if (object_exists(xsdata_grp, "prompt-nu-fission")) { + hid_t xsdata = open_dataset(xsdata_grp, "prompt-nu-fission"); + int ndims = dataset_ndims(xsdata); + close_dataset(xsdata); + + if (ndims == 3) { + // prompt-nu-fission is a [in group] vector + read_nd_vector(xsdata_grp, "prompt-nu-fission", + prompt_nu_fission); + } else if (ndims == 4) { + // prompt nu fission is a matrix, + // so set prompt_nu_fiss & chi_prompt + double_4dvec temp_arr = double_4dvec(n_pol, double_3dvec(n_azi, + double_2dvec(energy_groups, double_1dvec(energy_groups)))); + read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_arr); + + // The prompt_nu_fission vector from the matrix form + for (int a = 0; a < n_azi; a++) { + for (int p = 0; p < n_pol; p++) { + for (int gin = 0; gin < energy_groups; gin++) { + double prompt_sum = std::accumulate(temp_arr[p][a][gin].begin(), + temp_arr[p][a][gin].end(), 0.); + prompt_nu_fission[p][a][gin] = prompt_sum; + } + + // The chi_prompt data is just the normalized fission matrix + for (int gin= 0; gin < energy_groups; gin++) { + if (prompt_nu_fission[p][a][gin] > 0.) { + for (int gout = 0; gout < energy_groups; gout++) { + chi_prompt[p][a][gin][gout] = + temp_arr[p][a][gin][gout] / + prompt_nu_fission[p][a][gin]; + } + } else { + fatal_error("Encountered chi-prompt for a group that is <= 0!"); + } + } + } + } + + } else { + fatal_error("prompt-nu-fission must be provided as a 3D or 4D array!"); + } + } + + // Get delayed-nu-fission, if present + if (object_exists(xsdata_grp, "delayed-nu-fission")) { + hid_t xsdata = open_dataset(xsdata_grp, "delayed-nu-fission"); + int ndims = dataset_ndims(xsdata); + + if (ndims == 3) { + // delayed-nu-fission is a [in group] vector + if (temp_beta[0][0][0][0] == 0.) { + fatal_error("cannot set delayed-nu-fission with a 1D array if " + "beta is not provided"); + } + double_3dvec temp_arr = double_3dvec(n_pol, double_2dvec(n_azi, + double_1dvec(energy_groups))); + read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); + + for (int p = 0; p < n_pol; p++) { + for (int a = 0; a < n_azi; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + for (int dg = 0; dg < delayed_groups; dg++) { + // Set delayed-nu-fission using beta + delayed_nu_fission[p][a][gin][dg] = + temp_beta[p][a][gin][dg] * temp_arr[p][a][gin]; + } + } + } + } + + } else if (ndims == 4) { + // delayed nu fission is a [pol][azi][energy_group][delayed_group] matrix; + // matrix use this to set delayed-nu-fission separately for each + // delayed group + std::vector dims(ndims); + get_shape(xsdata, &dims[0]); + + if (dims[2] != delayed_groups) { + fatal_error("The delayed-nu-fission matrix was input with a 1st " + "dimension not equal to the number of delayed groups"); + } + if (dims[3] != energy_groups) { + fatal_error("The delayed-nu-fission matrix was input with a 2nd " + "dimension not equal to the number of energy groups"); + } + if (delayed_groups == energy_groups) { + warning("delayed-nu-fission was input as a dimension-4 matrix " + "with the same number of delayed groups and energy " + "groups. OpenMC assumes the dimensions in the matrix " + "are [delayed_groups][energy_groups]. Currently, " + "delayed-nu-fission cannot be set as a group-by-group " + "matrix"); + } + + read_nd_vector(xsdata_grp, "delayed-nu-fission", + delayed_nu_fission); + + } else if (ndims == 5) { + // This will contain delayed-nu-fision and chi-delayed data + double_5dvec temp_arr = double_5dvec(n_pol, double_4dvec(n_azi, + double_3dvec(energy_groups, double_2dvec(energy_groups, + double_1dvec(delayed_groups))))); + read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); + + // Set the 4D delayed-nu-fission matrix and 5D chi-delayed matrix + // from the 5D delayed-nu-fission matrix + for (int p = 0; p < n_pol; p++) { + for (int a = 0; a < n_azi; a++) { + for (int dg = 0; dg < delayed_groups; dg++) { + for (int gin = 0; gin < energy_groups; gin++) { + double gout_sum = 0.; + for (int gout = 0; gout < energy_groups; gout++) { + gout_sum += temp_arr[p][a][gin][gout][dg]; + chi_delayed[p][a][gin][gout][dg] = + temp_arr[p][a][gin][gout][dg]; + } + delayed_nu_fission[p][a][gin][dg] = gout_sum; + // Normalize chi-delayed + if (gout_sum > 0.) { + for (int gout = 0; gout < energy_groups; gout++) { + chi_delayed[p][a][gin][gout][dg] /= gout_sum; + } + } else { + fatal_error("Encountered chi-delayed for a group that is <= 0!"); + } + } + } + } + } + + } else { + fatal_error("prompt-nu-fission must be provided as a 3D, 4D, or 5D " + "array!"); + } + close_dataset(xsdata); + } + + // Get the fission and kappa_fission data xs + read_nd_vector(xsdata_grp, "fission", fission); + read_nd_vector(xsdata_grp, "kappa-fission", kappa_fission); +} + + +void XsData::_scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, + int energy_groups, int scatter_format, int final_scatter_format, + int order_data, int max_order, int legendre_to_tabular_points) +{ + if (!object_exists(xsdata_grp, "scatter_data")) { + fatal_error("Must provide scatter_data group!"); + } + hid_t scatt_grp = open_group(xsdata_grp, "scatter_data"); + + // Get the outgoing group boundary indices + int_3dvec gmin = int_3dvec(n_pol, int_2dvec(n_azi, + int_1dvec(energy_groups))); + read_nd_vector(scatt_grp, "g_min", gmin, true); + int_3dvec gmax = int_3dvec(n_pol, int_2dvec(n_azi, + int_1dvec(energy_groups))); + read_nd_vector(scatt_grp, "g_max", gmax, true); + + // Make gmin and gmax start from 0 vice 1 as they do in the library + for (int p = 0; p < n_pol; p++) { + for (int a = 0; a < n_azi; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + gmin[p][a][gin] -= 1; + gmax[p][a][gin] -= 1; + } + } + } + + // Now use this info to find the length of a vector to hold the flattened + // data. + int length = 0; + for (int p = 0; p < n_pol; p++) { + for (int a = 0; a < n_azi; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + length += order_data * (gmax[p][a][gin] - gmin[p][a][gin] + 1); + } + } + } + double_1dvec temp_arr = double_1dvec(length); + read_nd_vector(scatt_grp, "scatter_matrix", temp_arr, true); + + // Compare the number of orders given with the max order of the problem; + // strip off the superfluous orders if needed + int order_dim; + if (scatter_format == ANGLE_LEGENDRE) { + order_dim = std::min(order_data - 1, max_order) + 1; + } else { + order_dim = order_data; + } + + // convert the flattened temp_arr to a jagged array for passing to + // scatt data + double_5dvec input_scatt = + double_5dvec(n_pol, double_4dvec(n_azi, double_3dvec(energy_groups))); + + int temp_idx = 0; + for (int p = 0; p < n_pol; p++) { + for (int a = 0; a < n_azi; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + input_scatt[p][a][gin].resize(gmax[p][a][gin] - gmin[p][a][gin] + 1); + for (int i_gout = 0; i_gout < input_scatt[p][a][gin].size(); i_gout++) { + input_scatt[p][a][gin][i_gout].resize(order_dim); + for (int l = 0; l < order_dim; l++) { + input_scatt[p][a][gin][i_gout][l] = temp_arr[temp_idx++]; + } + // Adjust index for the orders we didnt take + temp_idx += (order_data - order_dim); + } + } + } + } + temp_arr.clear(); + + // Get multiplication matrix + double_4dvec temp_mult = double_4dvec(n_pol, double_3dvec(n_azi, + double_2dvec(energy_groups))); + if (object_exists(scatt_grp, "multiplicity_matrix")) { + temp_arr.resize(length); + read_nd_vector(scatt_grp, "multiplicity_matrix", temp_arr); + + // convert the flat temp_arr to a jagged array for passing to scatt data + int temp_idx = 0; + for (int p = 0; p < n_pol; p++) { + for (int a = 0; a < n_azi; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + temp_mult[p][a][gin].resize(gmax[p][a][gin] - gmin[p][a][gin] + 1); + for (int i_gout = 0; i_gout < temp_mult[p][a][gin].size(); i_gout++) { + temp_mult[p][a][gin][i_gout] = temp_arr[temp_idx++]; + } + } + } + } + } else { + // Use a default: multiplicities are 1.0. + for (int p = 0; p < n_pol; p++) { + for (int a = 0; a < n_azi; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + temp_mult[p][a][gin].resize(gmax[p][a][gin] - gmin[p][a][gin] + 1); + for (int i_gout = 0; i_gout < temp_mult[p][a][gin].size(); i_gout++) { + temp_mult[p][a][gin][i_gout] = 1.; + } + } + } + } + } + close_group(scatt_grp); + + // Finally, convert the Legendre data to tabular, if needed + if (scatter_format == ANGLE_LEGENDRE && + final_scatter_format == ANGLE_TABULAR) { + for (int p = 0; p < n_pol; p++) { + for (int a = 0; a < n_azi; a++) { + ScattDataLegendre legendre_scatt; + legendre_scatt.init(gmin[p][a], gmax[p][a], temp_mult[p][a], + input_scatt[p][a]); + + // Now create a tabular version of legendre_scatt + convert_legendre_to_tabular(legendre_scatt, + *static_cast(scatter[p][a]), + legendre_to_tabular_points); + + scatter_format = final_scatter_format; + } + } + } else { + // We are sticking with the current representation + // Initialize the ScattData object with this data + for (int p = 0; p < n_pol; p++) { + for (int a = 0; a < n_azi; a++) { + scatter[p][a]->init(gmin[p][a], gmax[p][a], temp_mult[p][a], + input_scatt[p][a]); + } + } + } +} + + +void XsData::combine(std::vector those_xs, double_1dvec& scalars) +{ + // Combine the non-scattering data + for (int i = 0; i < those_xs.size(); i++) { + XsData* that = those_xs[i]; + if (!equiv(*that)) fatal_error("Cannot combine the XsData objects!"); + double scalar = scalars[i]; + for (int p = 0; p < total.size(); p++) { + for (int a = 0; a < total[p].size(); a++) { + for (int gin = 0; gin < total[p][a].size(); gin++) { + total[p][a][gin] += scalar * that->total[p][a][gin]; + absorption[p][a][gin] += scalar * that->absorption[p][a][gin]; + inverse_velocity[p][a][gin] += + scalar * that->inverse_velocity[p][a][gin]; + + prompt_nu_fission[p][a][gin] += + scalar * that->prompt_nu_fission[p][a][gin]; + kappa_fission[p][a][gin] += + scalar * that->kappa_fission[p][a][gin]; + fission[p][a][gin] += + scalar * that->fission[p][a][gin]; + + for (int dg = 0; dg < delayed_nu_fission[p][a][gin].size(); dg++) { + delayed_nu_fission[p][a][gin][dg] += + scalar * that->delayed_nu_fission[p][a][gin][dg]; + } + + for (int gout = 0; gout < chi_prompt[p][a][gin].size(); gout++) { + chi_prompt[p][a][gin][gout] += + scalar * that->chi_prompt[p][a][gin][gout]; + + for (int dg = 0; dg < chi_delayed[p][a][gin][gout].size(); dg++) { + chi_delayed[p][a][gin][gout][dg] += + scalar * that->chi_delayed[p][a][gin][gout][dg]; + } + } + } + + for (int dg = 0; dg < decay_rate[p][a].size(); dg++) { + decay_rate[p][a][dg] += scalar * that->decay_rate[p][a][dg]; + } + + // Normalize chi + for (int gin = 0; gin < chi_prompt[p][a].size(); gin++) { + double norm = std::accumulate(chi_prompt[p][a][gin].begin(), + chi_prompt[p][a][gin].end(), 0.); + if (norm > 0.) { + for (int gout = 0; gout < chi_prompt[p][a][gin].size(); gout++) { + chi_prompt[p][a][gin][gout] /= norm; + } + } + + for (int dg = 0; dg < chi_delayed[p][a][gin][0].size(); dg++) { + norm = 0.; + for (int gout = 0; gout < chi_delayed[p][a][gin].size(); gout++) { + norm += chi_delayed[p][a][gin][gout][dg]; + } + if (norm > 0.) { + for (int gout = 0; gout < chi_delayed[p][a][gin].size(); gout++) { + chi_delayed[p][a][gin][gout][dg] /= norm; + } + } + } + } + } + } + } + + // Allow the ScattData object to combine itself + for (int p = 0; p < total.size(); p++) { + for (int a = 0; a < total[p].size(); a++) { + // Build vector of the scattering objects to incorporate + std::vector those_scatts(those_xs.size()); + for (int i = 0; i < those_xs.size(); i++) { + those_scatts[i] = those_xs[i]->scatter[p][a]; + } + + // Now combine these guys + scatter[p][a]->combine(those_scatts, scalars); + } + } +} + + +bool XsData::equiv(const XsData& that) +{ + bool match = false; + // check n_pol (total.size()), n_azi (total[0].size()), and + // groups (total[0][0].size()) + // This assumes correct initializatino of the remaining cross sections + if ((total.size() == that.total.size()) && + (total[0].size() == that.total[0].size()) && + (total[0][0].size() == that.total[0][0].size())) { + match = true; + } + return match; +} + +} //namespace openmc diff --git a/src/xsdata.h b/src/xsdata.h new file mode 100644 index 0000000000..1c1f8241b7 --- /dev/null +++ b/src/xsdata.h @@ -0,0 +1,72 @@ +//! \file xsdata.h +//! A collection of classes for containing the Multi-Group Cross Section data + +#ifndef XSDATA_H +#define XSDATA_H + +#include +#include +#include +#include +#include +#include +#include + +#include "constants.h" +#include "hdf5_interface.h" +#include "math_functions.h" +#include "random_lcg.h" +#include "scattdata.h" + + +namespace openmc { + +//============================================================================== +// XSDATA contains the temperature-independent cross section data for an MGXS +//============================================================================== + +class XsData { + private: + void _scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, + int energy_groups, int scatter_format, int final_scatter_format, + int order_data, int max_order, int legendre_to_tabular_points); + void _fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, + int energy_groups, int delayed_groups); + public: + // The following quantities have the following dimensions: + // [phi][theta][incoming group] + double_3dvec total; + double_3dvec absorption; + double_3dvec prompt_nu_fission; + double_3dvec kappa_fission; + double_3dvec fission; + double_3dvec inverse_velocity; + // decay_rate has the following dimensions: + // [phi][theta][delayed group] + double_3dvec decay_rate; + // delayed_nu_fission has the following dimensions: + // [phi][theta][incoming group][delayed group] + double_4dvec delayed_nu_fission; + // chi_prompt has the following dimensions: + // [phi][theta][incoming group][outgoing group] + double_4dvec chi_prompt; + // chi_delayed has the following dimensions: + // [phi][theta][incoming group][outgoing group][delayed group] + double_5dvec chi_delayed; + // scatter has the following dimensions: [phi][theta] + std::vector > scatter; + + XsData() = default; + XsData(int num_groups, int num_delayed_groups, bool fissionable, + int scatter_format, int n_pol, int n_azi); + ~XsData(); + void from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, + int final_scatter_format, int order_data, int max_order, + int legendre_to_tabular_points); + void combine(std::vector those_xs, double_1dvec& scalars); + bool equiv(const XsData& that); +}; + + +} //namespace openmc +#endif // XSDATA_H \ No newline at end of file From 4355faed6edc277e3026f4049737d26e6a5163b3 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Mon, 4 Jun 2018 19:00:17 -0400 Subject: [PATCH 014/100] this flie too --- src/mgxs.cpp | 671 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 671 insertions(+) create mode 100644 src/mgxs.cpp diff --git a/src/mgxs.cpp b/src/mgxs.cpp new file mode 100644 index 0000000000..277cccd075 --- /dev/null +++ b/src/mgxs.cpp @@ -0,0 +1,671 @@ +#include "mgxs.h" + +namespace openmc { + +//============================================================================== +// Mgxs base-class methods +//============================================================================== + +void Mgxs::init(const std::string& in_name, double in_awr, + double_1dvec& in_kTs, bool in_fissionable, + int in_scatter_format, int in_num_groups, + int in_num_delayed_groups, double_1dvec& in_polar, + double_1dvec& in_azimuthal) +{ + name = in_name; + awr = in_awr; + kTs = in_kTs; + fissionable = in_fissionable; + scatter_format = in_scatter_format; + num_groups = in_num_groups; + num_delayed_groups = in_num_delayed_groups; + xs.resize(in_kTs.size()); + polar = in_polar; + azimuthal = in_azimuthal; + n_pol = polar.size(); + n_azi = azimuthal.size(); +} + + +void Mgxs::_metadata_from_hdf5(hid_t xs_id, int in_num_groups, + int in_num_delayed_groups, double_1dvec temperature, int& method, + double tolerance, double_1dvec& temps_to_read, int& order_dim) +{ + // get name + char char_name[MAX_WORD_LEN]; + get_name(xs_id, char_name); + std::string in_name(char_name, std::strlen(char_name)); + // remove the leading '/' + in_name = in_name.substr(1); + + // Get the AWR + double in_awr; + if (attribute_exists(xs_id, "atomic_weight_ratio")) { + read_attr_double(xs_id, "atomic_weight_ratio", &in_awr); + } else { + in_awr = MACROSCOPIC_AWR; + } + + // Determine the available temperatures + hid_t kT_group = open_group(xs_id, "kTs"); + int num_temps = get_num_datasets(kT_group); + char** dset_names = new char*[num_temps]; + get_datasets(kT_group, dset_names); + double_1dvec available_temps(num_temps); + for (int i = 0; i < num_temps; i++) { + read_double(kT_group, dset_names[i], &available_temps[i], true); + + // convert eV to Kelvin + available_temps[i] /= K_BOLTZMANN; + } + std::sort(available_temps.begin(), available_temps.end()); + + // If only one temperature is available, lets just use nearest temperature + // interpolation + if ((num_temps == 1) && (method == TEMPERATURE_INTERPOLATION)) { + warning("Cross sections for " + strtrim(name) + " are only available " + + "at one temperature. Reverying to the nearest temperature " + + "method."); + method = TEMPERATURE_NEAREST; + } + + switch(method) { + case TEMPERATURE_NEAREST: + // Find the minimum difference + for (int i = 0; i < temperature.size(); i++) { + std::valarray temp_diff(available_temps.data(), + available_temps.size()); + temp_diff = std::abs(temp_diff - temperature[i]); + int i_closest = std::min_element(std::begin(temp_diff), std::end(temp_diff)) - + std::begin(temp_diff); + double temp_actual = available_temps[i_closest]; + + if (std::abs(temp_actual - temperature[i]) < tolerance) { + if (std::find(temps_to_read.begin(), temps_to_read.end(), + std::round(temp_actual)) != temps_to_read.end()) { + temps_to_read.push_back(std::round(temp_actual)); + } else { + fatal_error("MGXS Library does not contain cross section for " + + name + " at or near " + + std::to_string(std::round(temperature[i])) + " K."); + } + } + } + break; + + case TEMPERATURE_INTERPOLATION: + for (int i = 0; i < temperature.size(); i++) { + for (int j = 0; j < num_temps - 1; j++) { + if ((available_temps[j] <= temperature[i]) && + (temperature[i] < available_temps[j + 1])) { + if (std::find(temps_to_read.begin(), + temps_to_read.end(), + std::round(available_temps[j])) != temps_to_read.end()) { + temps_to_read.push_back(std::round(available_temps[j])); + } + + if (std::find(temps_to_read.begin(), temps_to_read.end(), + std::round(available_temps[j + 1])) != temps_to_read.end()) { + temps_to_read.push_back(std::round(available_temps[j + 1])); + } + continue; + } + } + + fatal_error("MGXS Library does not contain cross sections for " + + name + " at temperatures that bound " + + std::to_string(std::round(temperature[i]))); + } + } + std::sort(temps_to_read.begin(), temps_to_read.end()); + + // Get the library's temperatures + int n_temperature = temps_to_read.size(); + double_1dvec in_kTs(n_temperature); + for (int i = 0; i < n_temperature; i++) { + std::string temp_str(std::to_string(temps_to_read[i]) + "K"); + + //read exact temperature value + read_double(kT_group, temp_str.c_str(), &in_kTs[i], true); + } + close_group(kT_group); + + // Load the remaining metadata + int in_scatter_format; + if (attribute_exists(xs_id, "scatter_format")) { + std::string temp_str(MAX_WORD_LEN, ' '); + read_attr_string(xs_id, "scatter_format", MAX_WORD_LEN, &temp_str[0]); + strtrim(temp_str); + to_lower(temp_str); + if (temp_str == "legendre") { + in_scatter_format = ANGLE_LEGENDRE; + } else if (temp_str == "histogram") { + in_scatter_format = ANGLE_HISTOGRAM; + } else if (temp_str == "tabular") { + in_scatter_format = ANGLE_TABULAR; + } else { + fatal_error("Invalid scatter_format option!"); + } + } else { + in_scatter_format = ANGLE_LEGENDRE; + } + + if (attribute_exists(xs_id, "scatter_shape")) { + std::string temp_str(MAX_WORD_LEN, ' '); + read_attr_string(xs_id, "scatter_shape", MAX_WORD_LEN, &temp_str[0]); + strtrim(temp_str); + to_lower(temp_str); + if (temp_str != "[g][g\'][order]") { + fatal_error("Invalid scatter_shape option!"); + } + } + //TODO: do i even need this flag? - it should be easy to self-determine + bool in_fissionable = false; + if (attribute_exists(xs_id, "fissionable")) { + int int_fiss; + read_attr_int(xs_id, "fissionable", &int_fiss); + in_fissionable = (bool)int_fiss; + } else { + fatal_error("Fissionable element must be set!"); + } + + // Get the library's value for the order + if (attribute_exists(xs_id, "order")) { + read_attr_int(xs_id, "order", &order_dim); + } else { + fatal_error("Order must be provided!"); + } + + // Store the dimensionality of the data in order_dim. + // For Legendre data, we usually refer to it as Pn where n is the order. + // However Pn has n+1 sets of points (since you need to count the P0 + // moment). Adjust for that. Histogram and Tabular formats dont need this + // adjustment. + if (scatter_format == ANGLE_LEGENDRE) { + order_dim = order_dim + 1; + } + + // Get the angular information + bool is_angular = false; + if (attribute_exists(xs_id, "representation")) { + std::string temp_str(MAX_WORD_LEN, ' '); + read_attr_string(xs_id, "representation", MAX_WORD_LEN, &temp_str[0]); + strtrim(temp_str); + to_lower(temp_str); + if (temp_str == "angle") { + is_angular = true; + } else if (temp_str != "isotropic") { + fatal_error("Invalid Data Representation!"); + } + } + + if (is_angular) { + if (attribute_exists(xs_id, "num_polar")) { + read_attr_int(xs_id, "num_polar", &n_pol); + } else { + fatal_error("num_polar must be provided!"); + } + if (attribute_exists(xs_id, "num_azimuthal")) { + read_attr_int(xs_id, "num_azimuthal", &n_azi); + } else { + fatal_error("num_azimuthal must be provided!"); + } + } else { + n_pol = 1; + n_azi = 1; + } + + // Set the angular bins to use equally-spaced bins + double_1dvec in_polar(n_pol); + double dangle = PI / n_pol; + for (int p = 0; p < n_pol; p++) { + in_polar[p] = (p + 0.5) * dangle; + } + double_1dvec in_azimuthal(n_azi); + dangle = 2. * PI / n_azi; + for (int a = 0; a < n_azi; a++) { + in_azimuthal[a] = (a + 0.5) * dangle - PI; + } + + // Finally use this data to initialize the MGXS Object + init(in_name, in_awr, in_kTs, in_fissionable, in_scatter_format, in_num_groups, + in_num_delayed_groups, in_polar, in_azimuthal); +} + + +void Mgxs::from_hdf5(hid_t xs_id, int energy_groups, int delayed_groups, + double_1dvec temperature, int& method, double tolerance, + int max_order, bool legendre_to_tabular, + int legendre_to_tabular_points) +{ + // Call generic data gathering routine (will populate the metadata) + int order_data; + double_1dvec temps_to_read; + _metadata_from_hdf5(xs_id, energy_groups, delayed_groups, temperature, + method, tolerance, temps_to_read, order_data); + + // Set number of energy and delayed groups + num_groups = energy_groups; + num_delayed_groups = delayed_groups; + + int final_scatter_format; + if (scatter_format == ANGLE_LEGENDRE && legendre_to_tabular) { + final_scatter_format = ANGLE_TABULAR; + } else { + final_scatter_format = scatter_format; + } + + // Load the more specific XsData information + for (int t = 0; t < temps_to_read.size(); t++) { + xs[t] = XsData(energy_groups, delayed_groups, fissionable, + final_scatter_format, n_pol, n_azi); + // Get the temperature as a string and then open the HDF5 group + std::string temp_str = std::to_string(temps_to_read[t]) + "K"; + hid_t xsdata_grp = open_group(xs_id, temp_str.c_str()); + + xs[t].from_hdf5(xsdata_grp, fissionable, scatter_format, + final_scatter_format, order_data, max_order, + legendre_to_tabular_points); + close_group(xsdata_grp); + + } // end temperature loop +} + + +void Mgxs::build_macro(const std::string& in_name, double_1dvec& mat_kTs, + std::vector& micros, double_1dvec& atom_densities, + int& method, double tolerance) +{ + // Get the minimum data needed to initialize: + // Dont need awr, but lets just initialize it anyways + double in_awr = -1.; + // start with the assumption it is not fissionable + bool in_fissionable = false; + for (int m = 0; m < micros.size(); m++) { + if (micros[m].fissionable) in_fissionable = true; + } + // Force all of the following data to be the same; these will be verified + // to be true later + int in_scatter_format = micros[0].scatter_format; + int in_num_groups = micros[0].num_groups; + int in_num_delayed_groups = micros[0].num_delayed_groups; + double_1dvec in_polar = micros[0].polar; + double_1dvec in_azimuthal = micros[0].azimuthal; + + init(in_name, in_awr, mat_kTs, in_fissionable, in_scatter_format, in_num_groups, + in_num_delayed_groups, in_polar, in_azimuthal); + + // Create the xs data for each temperature + for (int t = 0; t < mat_kTs.size(); t++) { + double temp_desired = mat_kTs[t]; + + // Create the list of temperature indices and interpolation factors for + // each microscopic data at the material temperature + int_1dvec micro_t(micros.size(), 0); + double_1dvec micro_t_interp(micros.size(), 0.); + for (int m = 0; m < micros.size(); m++) { + switch(method) { + case TEMPERATURE_NEAREST: + { + // Find the nearest temperature + std::valarray temp_diff(micros[m].kTs.data(), + micros[m].kTs.size()); + temp_diff = std::abs(temp_diff - temp_desired); + micro_t[m] = std::min_element(std::begin(temp_diff), + std::end(temp_diff)) - + std::begin(temp_diff); + double temp_actual = micros[m].kTs[micro_t[m]]; + + if (std::abs(temp_actual - temp_desired) >= K_BOLTZMANN * tolerance) { + fatal_error("MGXS Library does not contain cross section for " + + name + " at or near " + + std::to_string(std::round(temp_desired / K_BOLTZMANN)) + + " K."); + } + } + break; + case TEMPERATURE_INTERPOLATION: + // Get a list of bounding temperatures for each actual temperature + // present in the model + for (int k = 0; k < micros[m].kTs.size() - 1; k++) { + if ((micros[m].kTs[k] <= temp_desired) && + (temp_desired < micros[m].kTs[k + 1])) { + micro_t[m] = k; + if (k == 0) { + micro_t_interp[m] = (temp_desired - micros[m].kTs[k]) / + (micros[m].kTs[k + 1] - micros[m].kTs[k]); + } else { + micro_t_interp[m] = 1.; + } + } + } + } // end switch + } // end microscopic temperature loop + + // We are about to loop through each of the microscopic objects + // and incorporate the contribution of each microscopic data at + // one of the two temperature interpolants to this macroscopic quantity. + // If we are doing nearest temperature interpolation, then we don't need + // to do the 2nd temperature + int num_interp_points = 2; + if (method == TEMPERATURE_NEAREST) num_interp_points = 1; + for (int interp_point = 0; interp_point < num_interp_points; interp_point++) { + double_1dvec interp(micros.size()); + double_1dvec temp_indices(micros.size()); + for (int m = 0; m < micros.size(); m++) { + interp[m] = (1. - micro_t_interp[m]) * atom_densities[m]; + temp_indices[m] = micro_t[m] + interp_point; + } + combine(micros, interp, micro_t, t); + } // end loop to sum all micros across the temperatures + } // end temperature (t) loop + +} + + +void Mgxs::combine(std::vector& micros, double_1dvec& scalars, + int_1dvec& micro_ts, int this_t) +{ + // Build the vector of pointers to the xs objects within micros + std::vector those_xs(micros.size()); + for (int i = 0; i < micros.size(); i++) { + if (!xs[this_t].equiv(micros[i].xs[micro_ts[i]])) { + fatal_error("Cannot combine the Mgxs objects!"); + } + those_xs[i] = &(micros[i].xs[micro_ts[i]]); + } + + xs[this_t].combine(those_xs, scalars); +} + + +double Mgxs::get_xs(const char* xstype, int gin, int* gout, double* mu, int* dg) +{ + // This method assumes that the temperature and angle indices are set + double val; + if (std::strcmp(xstype, "total")) { + val = xs[index_temp].total[index_pol][index_azi][gin]; + } else if (std::strcmp(xstype, "absorption")) { + val = xs[index_temp].absorption[index_pol][index_azi][gin]; + } else if (std::strcmp(xstype, "inverse-velocity")) { + val = xs[index_temp].inverse_velocity[index_pol][index_azi][gin]; + } else if (std::strcmp(xstype, "decay rate")) { + if (dg != nullptr) { + val = xs[index_temp].decay_rate[index_pol][index_azi][*dg + 1]; + } else { + val = xs[index_temp].decay_rate[index_pol][index_azi][0]; + } + } else if ((std::strcmp(xstype, "scatter")) || + (std::strcmp(xstype, "scatter/mult")) || + (std::strcmp(xstype, "scatter*f_mu/mult")) || + (std::strcmp(xstype, "scatter*f_mu"))) { + val = xs[index_temp].scatter[index_pol] + [index_azi]->get_xs(xstype, gin, gout, mu); + } else if (fissionable && std::strcmp(xstype, "fission")) { + val = xs[index_temp].fission[index_pol][index_azi][gin]; + } else if (fissionable && std::strcmp(xstype, "kappa-fission")) { + val = xs[index_temp].kappa_fission[index_pol][index_azi][gin]; + } else if (fissionable && std::strcmp(xstype, "prompt-nu-fission")) { + val = xs[index_temp].prompt_nu_fission[index_pol][index_azi][gin]; + } else if (fissionable && std::strcmp(xstype, "delayed-nu-fission")) { + if (dg != nullptr) { + val = xs[index_temp].delayed_nu_fission[index_pol][index_azi][gin][*dg]; + } else { + val = 0.; + for (auto& num : xs[index_temp].delayed_nu_fission[index_pol] + [index_azi][gin]) { + val += num; + } + } + } else if (fissionable && std::strcmp(xstype, "nu-fission")) { + val = xs[index_temp].prompt_nu_fission[index_pol][index_azi][gin]; + for (auto& num : xs[index_temp].delayed_nu_fission[index_pol] + [index_azi][gin]) { + val += num; + } + } else if (fissionable && std::strcmp(xstype, "chi-prompt")) { + if (gout != nullptr) { + val = xs[index_temp].chi_prompt[index_pol][index_azi][gin][*gout]; + } else { + // provide an outgoing group-wise sum + val = 0.; + for (auto& num : xs[index_temp].chi_prompt[index_pol][index_azi][gin]) { + val += num; + } + } + } else if (fissionable && std::strcmp(xstype, "chi-delayed")) { + if (gout != nullptr) { + if (dg != nullptr) { + val = xs[index_temp].chi_delayed[index_pol][index_azi][gin][*gout][*dg]; + } else { + val = xs[index_temp].chi_delayed[index_pol][index_azi][gin][*gout][0]; + } + } else { + if (dg != nullptr) { + val = 0.; + for (int i = 0; i < xs[index_temp].chi_delayed[index_pol] + [index_azi][gin].size(); i++) { + val += xs[index_temp].chi_delayed[index_pol][index_azi][gin][i][*dg]; + } + } else { + val = 0.; + for (int i = 0; i < xs[index_temp].chi_delayed[index_pol] + [index_azi][gin].size(); i++) { + for (auto& num : xs[index_temp].chi_delayed[index_pol] + [index_azi][gin][i]) { + val += num; + } + } + } + } + } else { + val = 0.; + } + return val; +} + + +void Mgxs::sample_fission_energy(int gin, double nu_fission, int& dg, int& gout) +{ + // This method assumes that the temperature and angle indices are set + // Find the probability of having a prompt neutron + double prob_prompt = + xs[index_temp].prompt_nu_fission[index_pol][index_azi][gin] / + nu_fission; + + // sample random numbers + double xi_pd = prn(); + double xi_gout = prn(); + + // Select whether the neutron is prompt or delayed + if (xi_pd <= prob_prompt) { + // the neutron is prompt + + // set the delayed group for the particle to be 0, indicating prompt + dg = 0; + + // sample the outgoing energy group + gout = 0; + double prob_gout = + xs[index_temp].chi_prompt[index_pol][index_azi][gin][gout]; + while (prob_gout < xi_gout) { + gout++; + prob_gout += xs[index_temp].chi_prompt[index_pol][index_azi][gin][gout]; + } + + } else { + // the neutron is delayed + + // get the delayed group + dg = 0; + while (xi_pd >= prob_prompt) { + dg++; + prob_prompt += + xs[index_temp].delayed_nu_fission[index_pol][index_azi][gin][dg] / + nu_fission; + } + + // adjust dg in case of round-off error + dg = std::min(dg, num_delayed_groups); + + // sample the outgoing energy group + gout = 0; + double prob_gout = + xs[index_temp].chi_delayed[index_pol][index_azi][gin][gout][dg]; + while (prob_gout < xi_gout) { + gout++; + prob_gout += + xs[index_temp].chi_delayed[index_pol][index_azi][gin][gout][dg]; + } + } +} + + +void Mgxs::sample_scatter(dir_arr& uvw, int gin, int& gout, double& mu, + double& wgt) +{ + // This method assumes that the temperature and angle indices are set + // Sample the data + xs[index_temp].scatter[index_pol][index_azi]->sample(gin, gout, mu, wgt); +} + + +void Mgxs::calculate_xs(int gin, double sqrtkT, dir_arr& uvw, double& total_xs, + double& abs_xs, double& nu_fiss_xs) +{ + // Set our indices + set_temperature_index(sqrtkT); + set_angle_index(uvw); + total_xs = xs[index_temp].total[index_pol][index_azi][gin]; + abs_xs = xs[index_temp].absorption[index_pol][index_azi][gin]; + + // nu-fission is made up of the prompt and all the delayed nu_fission data + nu_fiss_xs = xs[index_temp].prompt_nu_fission[index_pol][index_azi][gin]; + for (auto& val : xs[index_temp].delayed_nu_fission[index_pol][index_azi][gin]) { + nu_fiss_xs += val; + } +} + + +bool Mgxs::equiv(const Mgxs& that) +{ + bool match = false; + + if ((num_delayed_groups == that.num_delayed_groups) && + (num_groups == that.num_groups) && + (n_pol == that.n_pol) && + (n_azi == that.n_azi) && + (std::equal(polar.begin(), polar.end(), that.polar.begin())) && + (std::equal(azimuthal.begin(), azimuthal.end(), that.azimuthal.begin())) && + (scatter_format == that.scatter_format)) { + match = true; + } + return match; +} + + +inline void Mgxs::set_temperature_index(double sqrtkT) +{ + // See if we need to find the new index + if (sqrtkT != last_sqrtkT) { + double kT = sqrtkT * sqrtkT; + + // initialize vector for storage of the differences + std::valarray temp_diff(kTs.data(), kTs.size()); + + // Find the minimum difference of kT and kTs + temp_diff = std::abs(temp_diff - kT); + index_temp = std::min_element(std::begin(temp_diff), std::end(temp_diff)) - + std::begin(temp_diff); + + // store this temperature as the last one used + last_sqrtkT = sqrtkT; + } +} + + +inline void Mgxs::set_angle_index(dir_arr& uvw) +{ + // See if we need to find the new index + if (uvw != last_uvw) { + // convert uvw to polar and azimuthal angles + double my_pol = std::acos(uvw[2]); + double my_azi = std::atan2(uvw[1], uvw[0]); + + // Find the location, assuming equal-bin angles + double delta_angle = PI / n_pol; + index_pol = std::floor(my_pol / delta_angle + 1.); + delta_angle = PI / n_azi; + index_azi = std::floor((my_azi + PI) / delta_angle + 1.); + + // store this direction as the last one used + last_uvw = uvw; + } +} + +//============================================================================== +// Mgxs data loading methods +//============================================================================== + +void read_mgxs_library(hid_t file_id, int n_nuclides, char** names, + int energy_groups, int delayed_groups, int n_temps, double temps[], + int& method, double tolerance, int max_order, bool legendre_to_tabular, + int legendre_to_tabular_points) +{ + //!! mgxs_data.F90 will be modified to just create the list of names + //!! in the order needed + // Convert temps to a vector for the from_hdf5 function + double_1dvec temperature; + temperature.assign(temps, temps + n_temps); + nuclides_MG.resize(n_nuclides); + for (int i = 0; i < n_nuclides; i++) { + // TODO: Replacement for write_message + // write_message("Loading " + std::string(names[i]) + " data...", 6); + + // Check to make sure cross section set exists in the library + hid_t xs_grp; + if (object_exists(file_id, names[i])) { + xs_grp = open_group(file_id, names[i]); + } else { + fatal_error("Data for " + std::string(names[i]) + " does not exist in " + + "provided MGXS Library"); + } + + nuclides_MG[i].from_hdf5(xs_grp, energy_groups, delayed_groups, + temperature, method, tolerance, max_order, legendre_to_tabular, + legendre_to_tabular_points); + } +} + + +bool query_fissionable(const int i_nuclides[], const int n_nuclides) +{ + bool result = false; + for (int i = 0; i < n_nuclides; i++) { + if (nuclides_MG[i_nuclides[i]].fissionable) result = true; + } + return result; +} + + +void create_macro_xs(int n_materials, double_2dvec& mat_kTs, + std::vector& mat_names, + double_1dvec& atom_densities, int& method, + double tolerance) +{ + // TODO mat_kTs needs to be converted from Fortran + // it is currently an array of type(VectorReal), a wrapper should convert to + // the vector. + macro_xs.resize(n_materials); + + for (int m = 0; m < n_materials; m++) + { + if (mat_kTs[m].size() > 0) { + macro_xs[m].build_macro(mat_names[m], mat_kTs[m], nuclides_MG, + atom_densities, method, tolerance); + } + } +} + + +} // namespace openmc \ No newline at end of file From 13f163a25ac7a0629177c39e0172b3275ff4d730 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Fri, 8 Jun 2018 16:18:37 -0400 Subject: [PATCH 015/100] Tied in the Mgxs cpp code in to the main body of Fortran. This commit stores progress getting microscopic data loaded on the C++ side. The next will be building the macroscopic cross sections, and then actually using the C++ during the fortran simulation --- CMakeLists.txt | 4 + src/constants.h | 10 ++ src/hdf5_interface.cpp | 30 ++--- src/hdf5_interface.h | 1 + src/input_xml.F90 | 3 +- src/math_functions.h | 12 +- src/mgxs.cpp | 128 ++++++++++---------- src/mgxs.h | 33 ++--- src/mgxs_data.F90 | 111 ++++++++++++++++- src/mgxs_header.F90 | 4 +- src/scattdata.cpp | 265 ++++++++++++++++++++++++++++++++++++++--- src/settings.F90 | 14 +-- src/string_functions.h | 41 +++---- src/xsdata.cpp | 57 +++------ src/xsdata.h | 6 +- 15 files changed, 512 insertions(+), 207 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dc5558de18..362e98a830 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -432,17 +432,21 @@ set(LIBOPENMC_FORTRAN_SRC src/tallies/trigger_header.F90 ) set(LIBOPENMC_CXX_SRC + src/constants.h src/initialize.cpp src/finalize.cpp src/hdf5_interface.cpp src/math_functions.cpp src/message_passing.cpp + src/mgxs.cpp src/plot.cpp src/random_lcg.cpp + src/scattdata.cpp src/simulation.cpp src/state_point.cpp src/surface.cpp src/xml_interface.cpp + src/xsdata.cpp src/pugixml/pugixml.cpp) add_library(libopenmc SHARED ${LIBOPENMC_FORTRAN_SRC} ${LIBOPENMC_CXX_SRC}) set_target_properties(libopenmc PROPERTIES diff --git a/src/constants.h b/src/constants.h index b14984a146..4129305bf9 100644 --- a/src/constants.h +++ b/src/constants.h @@ -1,7 +1,10 @@ +//! \file constants.h +//! A collection of constants #ifndef CONSTANTS_H #define CONSTANTS_H +#include #include #include @@ -54,6 +57,13 @@ constexpr int DEFAULT_NMU {33}; constexpr int TEMPERATURE_NEAREST {1}; constexpr int TEMPERATURE_INTERPOLATION {2}; +// TODO: cmath::M_PI has 3 more digits precision than the Fortran constant we +// use so for now we will reuse the Fortran constant until we are OK with +// modifying test results +constexpr double PI {3.1415926535898}; + +const double SQRT_PI {std::sqrt(PI)}; + } // namespace openmc diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index 3d2f3ee7ba..39e0162b58 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -487,9 +487,9 @@ read_nd_vector(hid_t obj_id, const char* name, bool must_have) { if (object_exists(obj_id, name)) { - dim1 = result.size(); - dim2 = result[0].size(); - dim3 = result[0][0].size(); + int dim1 = result.size(); + int dim2 = result[0].size(); + int dim3 = result[0][0].size(); std::vector temp_arr = std::vector(dim1 * dim2 * dim3); read_double(obj_id, name, &temp_arr[0], true); @@ -512,9 +512,9 @@ read_nd_vector(hid_t obj_id, const char* name, bool must_have) { if (object_exists(obj_id, name)) { - dim1 = result.size(); - dim2 = result[0].size(); - dim3 = result[0][0].size(); + int dim1 = result.size(); + int dim2 = result[0].size(); + int dim3 = result[0][0].size(); std::vector temp_arr = std::vector(dim1 * dim2 * dim3); read_int(obj_id, name, &temp_arr[0], true); @@ -537,10 +537,10 @@ read_nd_vector(hid_t obj_id, const char* name, bool must_have) { if (object_exists(obj_id, name)) { - dim1 = result.size(); - dim2 = result[0].size(); - dim3 = result[0][0].size(); - dim4 = result[0][0][0].size(); + int dim1 = result.size(); + int dim2 = result[0].size(); + int dim3 = result[0][0].size(); + int dim4 = result[0][0][0].size(); std::vector temp_arr = std::vector( dim1 * dim2 * dim3 * dim4); read_double(obj_id, name, &temp_arr[0], true); @@ -566,11 +566,11 @@ read_nd_vector(hid_t obj_id, const char* name, bool must_have) { if (object_exists(obj_id, name)) { - dim1 = result.size(); - dim2 = result[0].size(); - dim3 = result[0][0].size(); - dim4 = result[0][0][0].size(); - dim5 = result[0][0][0][0].size(); + int dim1 = result.size(); + int dim2 = result[0].size(); + int dim3 = result[0][0].size(); + int dim4 = result[0][0][0].size(); + int dim5 = result[0][0][0][0].size(); std::vector temp_arr = std::vector( dim1 * dim2 * dim3 * dim4 * dim5); read_double(obj_id, name, &temp_arr[0], true); diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index 734cf0f919..fd03eb4c67 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -7,6 +7,7 @@ #include #include #include +#include #include diff --git a/src/input_xml.F90 b/src/input_xml.F90 index f8cf50dd3c..8d4c8de817 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -19,7 +19,7 @@ module input_xml use material_header use mesh_header use message_passing - use mgxs_data, only: create_macro_xs, read_mgxs + use mgxs_data, only: create_macro_xs, read_mgxs, read_mgxs2 use mgxs_header use nuclide_header use output, only: title, header, print_plot @@ -84,6 +84,7 @@ contains else ! Create material macroscopic data for MGXS call read_mgxs() + call read_mgxs2() call create_macro_xs() end if call time_read_xs % stop() diff --git a/src/math_functions.h b/src/math_functions.h index 68e89251e3..2ceea98d87 100644 --- a/src/math_functions.h +++ b/src/math_functions.h @@ -7,22 +7,12 @@ #include #include +#include "constants.h" #include "random_lcg.h" namespace openmc { -//============================================================================== -// Module constants. -//============================================================================== - -// TODO: cmath::M_PI has 3 more digits precision than the Fortran constant we -// use so for now we will reuse the Fortran constant until we are OK with -// modifying test results -extern "C" constexpr double PI {3.1415926535898}; - -extern "C" const double SQRT_PI {std::sqrt(PI)}; - //============================================================================== //! Calculate the percentile of the standard normal distribution with a //! specified probability level. diff --git a/src/mgxs.cpp b/src/mgxs.cpp index 277cccd075..9c11da8ac8 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -6,11 +6,11 @@ namespace openmc { // Mgxs base-class methods //============================================================================== -void Mgxs::init(const std::string& in_name, double in_awr, - double_1dvec& in_kTs, bool in_fissionable, - int in_scatter_format, int in_num_groups, - int in_num_delayed_groups, double_1dvec& in_polar, - double_1dvec& in_azimuthal) +void Mgxs::init(const std::string& in_name, const double in_awr, + const double_1dvec& in_kTs, const bool in_fissionable, + const int in_scatter_format, const int in_num_groups, + const int in_num_delayed_groups, const double_1dvec& in_polar, + const double_1dvec& in_azimuthal) { name = in_name; awr = in_awr; @@ -27,9 +27,10 @@ void Mgxs::init(const std::string& in_name, double in_awr, } -void Mgxs::_metadata_from_hdf5(hid_t xs_id, int in_num_groups, - int in_num_delayed_groups, double_1dvec temperature, int& method, - double tolerance, double_1dvec& temps_to_read, int& order_dim) +void Mgxs::_metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, + const int in_num_delayed_groups, double_1dvec& temperature, int& method, + const double tolerance, int_1dvec& temps_to_read, int& order_dim, + bool& is_isotropic) { // get name char char_name[MAX_WORD_LEN]; @@ -49,7 +50,10 @@ void Mgxs::_metadata_from_hdf5(hid_t xs_id, int in_num_groups, // Determine the available temperatures hid_t kT_group = open_group(xs_id, "kTs"); int num_temps = get_num_datasets(kT_group); - char** dset_names = new char*[num_temps]; + char* dset_names[num_temps]; + for (int i = 0; i < num_temps; i++) { + dset_names[i] = new char[151]; + } get_datasets(kT_group, dset_names); double_1dvec available_temps(num_temps); for (int i = 0; i < num_temps; i++) { @@ -82,11 +86,11 @@ void Mgxs::_metadata_from_hdf5(hid_t xs_id, int in_num_groups, if (std::abs(temp_actual - temperature[i]) < tolerance) { if (std::find(temps_to_read.begin(), temps_to_read.end(), - std::round(temp_actual)) != temps_to_read.end()) { + std::round(temp_actual)) == temps_to_read.end()) { temps_to_read.push_back(std::round(temp_actual)); } else { fatal_error("MGXS Library does not contain cross section for " + - name + " at or near " + + in_name + " at or near " + std::to_string(std::round(temperature[i])) + " K."); } } @@ -100,20 +104,20 @@ void Mgxs::_metadata_from_hdf5(hid_t xs_id, int in_num_groups, (temperature[i] < available_temps[j + 1])) { if (std::find(temps_to_read.begin(), temps_to_read.end(), - std::round(available_temps[j])) != temps_to_read.end()) { - temps_to_read.push_back(std::round(available_temps[j])); + std::round(available_temps[j])) == temps_to_read.end()) { + temps_to_read.push_back(std::round((int)available_temps[j])); } if (std::find(temps_to_read.begin(), temps_to_read.end(), - std::round(available_temps[j + 1])) != temps_to_read.end()) { - temps_to_read.push_back(std::round(available_temps[j + 1])); + std::round(available_temps[j + 1])) == temps_to_read.end()) { + temps_to_read.push_back(std::round((int) available_temps[j + 1])); } continue; } } fatal_error("MGXS Library does not contain cross sections for " + - name + " at temperatures that bound " + + in_name + " at temperatures that bound " + std::to_string(std::round(temperature[i]))); } } @@ -135,13 +139,12 @@ void Mgxs::_metadata_from_hdf5(hid_t xs_id, int in_num_groups, if (attribute_exists(xs_id, "scatter_format")) { std::string temp_str(MAX_WORD_LEN, ' '); read_attr_string(xs_id, "scatter_format", MAX_WORD_LEN, &temp_str[0]); - strtrim(temp_str); - to_lower(temp_str); - if (temp_str == "legendre") { + to_lower(strtrim(temp_str)); + if (temp_str.compare(0, 8, "legendre") == 0) { in_scatter_format = ANGLE_LEGENDRE; - } else if (temp_str == "histogram") { + } else if (temp_str.compare(0, 9, "histogram") == 0) { in_scatter_format = ANGLE_HISTOGRAM; - } else if (temp_str == "tabular") { + } else if (temp_str.compare(0, 7, "tabular") == 0) { in_scatter_format = ANGLE_TABULAR; } else { fatal_error("Invalid scatter_format option!"); @@ -153,9 +156,8 @@ void Mgxs::_metadata_from_hdf5(hid_t xs_id, int in_num_groups, if (attribute_exists(xs_id, "scatter_shape")) { std::string temp_str(MAX_WORD_LEN, ' '); read_attr_string(xs_id, "scatter_shape", MAX_WORD_LEN, &temp_str[0]); - strtrim(temp_str); - to_lower(temp_str); - if (temp_str != "[g][g\'][order]") { + to_lower(strtrim(temp_str)); + if (temp_str.compare(0, 14, "[g][g\'][order]") != 0) { fatal_error("Invalid scatter_shape option!"); } } @@ -181,25 +183,24 @@ void Mgxs::_metadata_from_hdf5(hid_t xs_id, int in_num_groups, // However Pn has n+1 sets of points (since you need to count the P0 // moment). Adjust for that. Histogram and Tabular formats dont need this // adjustment. - if (scatter_format == ANGLE_LEGENDRE) { + if (in_scatter_format == ANGLE_LEGENDRE) { order_dim = order_dim + 1; } // Get the angular information - bool is_angular = false; + is_isotropic = true; if (attribute_exists(xs_id, "representation")) { std::string temp_str(MAX_WORD_LEN, ' '); read_attr_string(xs_id, "representation", MAX_WORD_LEN, &temp_str[0]); - strtrim(temp_str); - to_lower(temp_str); - if (temp_str == "angle") { - is_angular = true; - } else if (temp_str != "isotropic") { + to_lower(strtrim(temp_str)); + if (temp_str.compare(0, 5, "angle") == 0) { + is_isotropic = false; + } else if (temp_str.compare(0, 9, "isotropic") != 0) { fatal_error("Invalid Data Representation!"); } } - if (is_angular) { + if (!is_isotropic) { if (attribute_exists(xs_id, "num_polar")) { read_attr_int(xs_id, "num_polar", &n_pol); } else { @@ -228,31 +229,27 @@ void Mgxs::_metadata_from_hdf5(hid_t xs_id, int in_num_groups, } // Finally use this data to initialize the MGXS Object - init(in_name, in_awr, in_kTs, in_fissionable, in_scatter_format, in_num_groups, - in_num_delayed_groups, in_polar, in_azimuthal); + init(in_name, in_awr, in_kTs, in_fissionable, in_scatter_format, + in_num_groups, in_num_delayed_groups, in_polar, in_azimuthal); } void Mgxs::from_hdf5(hid_t xs_id, int energy_groups, int delayed_groups, - double_1dvec temperature, int& method, double tolerance, + double_1dvec& temperature, int& method, double tolerance, int max_order, bool legendre_to_tabular, int legendre_to_tabular_points) { // Call generic data gathering routine (will populate the metadata) int order_data; - double_1dvec temps_to_read; + int_1dvec temps_to_read; + bool is_isotropic; _metadata_from_hdf5(xs_id, energy_groups, delayed_groups, temperature, - method, tolerance, temps_to_read, order_data); + method, tolerance, temps_to_read, order_data, is_isotropic); // Set number of energy and delayed groups - num_groups = energy_groups; - num_delayed_groups = delayed_groups; - - int final_scatter_format; - if (scatter_format == ANGLE_LEGENDRE && legendre_to_tabular) { - final_scatter_format = ANGLE_TABULAR; - } else { - final_scatter_format = scatter_format; + int final_scatter_format = scatter_format; + if (legendre_to_tabular) { + if (scatter_format == ANGLE_LEGENDRE) final_scatter_format = ANGLE_TABULAR; } // Load the more specific XsData information @@ -265,7 +262,7 @@ void Mgxs::from_hdf5(hid_t xs_id, int energy_groups, int delayed_groups, xs[t].from_hdf5(xsdata_grp, fissionable, scatter_format, final_scatter_format, order_data, max_order, - legendre_to_tabular_points); + legendre_to_tabular_points, is_isotropic); close_group(xsdata_grp); } // end temperature loop @@ -607,9 +604,9 @@ inline void Mgxs::set_angle_index(dir_arr& uvw) // Mgxs data loading methods //============================================================================== -void read_mgxs_library(hid_t file_id, int n_nuclides, char** names, - int energy_groups, int delayed_groups, int n_temps, double temps[], - int& method, double tolerance, int max_order, bool legendre_to_tabular, +void add_mgxs(hid_t file_id, char* name, int energy_groups, + int delayed_groups, int n_temps, double temps[], int& method, + double tolerance, int max_order, bool legendre_to_tabular, int legendre_to_tabular_points) { //!! mgxs_data.F90 will be modified to just create the list of names @@ -617,28 +614,29 @@ void read_mgxs_library(hid_t file_id, int n_nuclides, char** names, // Convert temps to a vector for the from_hdf5 function double_1dvec temperature; temperature.assign(temps, temps + n_temps); - nuclides_MG.resize(n_nuclides); - for (int i = 0; i < n_nuclides; i++) { - // TODO: Replacement for write_message - // write_message("Loading " + std::string(names[i]) + " data...", 6); - // Check to make sure cross section set exists in the library - hid_t xs_grp; - if (object_exists(file_id, names[i])) { - xs_grp = open_group(file_id, names[i]); - } else { - fatal_error("Data for " + std::string(names[i]) + " does not exist in " - + "provided MGXS Library"); - } + // TODO: C++ replacement for write_message + // write_message("Loading " + std::string(names[i]) + " data...", 6); - nuclides_MG[i].from_hdf5(xs_grp, energy_groups, delayed_groups, - temperature, method, tolerance, max_order, legendre_to_tabular, - legendre_to_tabular_points); + // Check to make sure cross section set exists in the library + hid_t xs_grp; + if (object_exists(file_id, name)) { + xs_grp = open_group(file_id, name); + } else { + fatal_error("Data for " + std::string(name) + " does not exist in " + + "provided MGXS Library"); } + + Mgxs mg; + mg.from_hdf5(xs_grp, energy_groups, delayed_groups, + temperature, method, tolerance, max_order, legendre_to_tabular, + legendre_to_tabular_points); + + nuclides_MG.push_back(mg); } -bool query_fissionable(const int i_nuclides[], const int n_nuclides) +bool query_fissionable(const int n_nuclides, const int i_nuclides[]) { bool result = false; for (int i = 0; i < n_nuclides; i++) { diff --git a/src/mgxs.h b/src/mgxs.h index 8ed4ba99e3..8c13cf7cb4 100644 --- a/src/mgxs.h +++ b/src/mgxs.h @@ -10,6 +10,7 @@ #include #include #include +#include #include "constants.h" #include "hdf5_interface.h" @@ -22,7 +23,6 @@ namespace openmc { - //============================================================================== // MGXS contains the mgxs data for a nuclide/material //============================================================================== @@ -45,26 +45,27 @@ class Mgxs { double_1dvec polar; double_1dvec azimuthal; dir_arr last_uvw; - void _metadata_from_hdf5(hid_t xs_id, int in_num_groups, - int in_num_delayed_groups, double_1dvec temperature, int& method, - double tolerance, double_1dvec& temps_to_read, int& order_dim); + void _metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, + const int in_num_delayed_groups, double_1dvec& temperature, + int& method, const double tolerance, int_1dvec& temps_to_read, + int& order_dim, bool& is_isotropic); public: bool fissionable; // Is this fissionable - void init(const std::string& in_name, double in_awr, double_1dvec& in_kTs, - bool in_fissionable, int in_scatter_format, int in_num_groups, - int in_num_delayed_groups, double_1dvec& in_polar, - double_1dvec& in_azimuthal); + void init(const std::string& in_name, const double in_awr, + const double_1dvec& in_kTs, const bool in_fissionable, + const int in_scatter_format, const int in_num_groups, + const int in_num_delayed_groups, const double_1dvec& in_polar, + const double_1dvec& in_azimuthal); void build_macro(const std::string& in_name, double_1dvec& mat_kTs, std::vector& micros, double_1dvec& atom_densities, int& method, double tolerance); void combine(std::vector& micros, double_1dvec& scalars, int_1dvec& micro_ts, int this_t); void from_hdf5(hid_t xs_id, int energy_groups, int delayed_groups, - double_1dvec temperature, int& method, - double tolerance, int max_order, - bool legendre_to_tabular, - int legendre_to_tabular_points); + double_1dvec& temperature, int& method, double tolerance, + int max_order, bool legendre_to_tabular, + int legendre_to_tabular_points); double get_xs(const char* xstype, int gin, int* gout, double* mu, int* dg); void sample_fission_energy(int gin, double nu_fission, int& dg, int& gout); @@ -77,11 +78,11 @@ class Mgxs { inline void set_angle_index(dir_arr& uvw); }; -extern "C" void read_mgxs_library(hid_t file_id, int n_nuclides, char** names, - int energy_groups, int delayed_groups, int n_temps, double temps[], - int& method, double tolerance, int max_order, bool legendre_to_tabular, +extern "C" void add_mgxs(hid_t file_id, char* name, int energy_groups, + int delayed_groups, int n_temps, double temps[], int& method, + double tolerance, int max_order, bool legendre_to_tabular, int legendre_to_tabular_points); -extern "C" bool query_fissionable(const int i_nuclides[], const int n_nuclides); +extern "C" bool query_fissionable(const int n_nuclides, const int i_nuclides[]); void create_macro_xs(int n_materials, double_2dvec& mat_kTs, std::vector& mat_names, double_1dvec& atom_densities, int& method, double tolerance); diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index e0631d16c5..6be463a91e 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -1,5 +1,7 @@ module mgxs_data + use, intrinsic :: ISO_C_BINDING + use constants use algorithm, only: find use dict_header, only: DictCharInt @@ -11,10 +13,40 @@ module mgxs_data use nuclide_header, only: n_nuclides use set_header, only: SetChar use settings - use stl_vector, only: VectorReal + use stl_vector, only: VectorReal, VectorChar use string, only: to_lower implicit none + interface + subroutine add_mgxs_c(file_id, name, energy_groups, delayed_groups, & + n_temps, temps, method, tolerance, max_order, legendre_to_tabular, & + legendre_to_tabular_points) bind(C, name='add_mgxs') + use ISO_C_BINDING + import HID_T + implicit none + integer(HID_T), value, intent(in) :: file_id + character(kind=C_CHAR),intent(in) :: name(*) + integer(C_INT), value, intent(in) :: energy_groups + integer(C_INT), value, intent(in) :: delayed_groups + integer(C_INT), value, intent(in) :: n_temps + real(C_DOUBLE), intent(in) :: temps(1:n_temps) + integer(C_INT), intent(inout) :: method + real(C_DOUBLE), value, intent(in) :: tolerance + integer(C_INT), value, intent(in) :: max_order + logical(C_BOOL),value, intent(in) :: legendre_to_tabular + integer(C_INT), value, intent(in) :: legendre_to_tabular_points + end subroutine add_mgxs_c + + function query_fissionable_c(n_nuclides, i_nuclides) result(result) & + bind(C, name='query_fissionable') + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: n_nuclides + integer(C_INT), intent(in) :: i_nuclides(1:n_nuclides) + logical(C_BOOL) :: result + end function query_fissionable_c + end interface + contains !=============================================================================== @@ -165,6 +197,83 @@ contains end subroutine read_mgxs + subroutine read_mgxs2() + integer :: i ! index in materials array + integer :: j ! index over nuclides in material + integer :: i_nuclide ! index in nuclides array + character(20) :: name ! name of library to load + type(Material), pointer :: mat + type(SetChar) :: already_read + integer(HID_T) :: file_id + logical :: file_exists + type(VectorReal), allocatable, target :: temps(:) + character(MAX_WORD_LEN) :: word + integer, allocatable :: array(:) + + ! Check if MGXS Library exists + inquire(FILE=path_cross_sections, EXIST=file_exists) + if (.not. file_exists) then + + ! Could not find MGXS Library file + call fatal_error("Cross sections HDF5 file '" & + // trim(path_cross_sections) // "' does not exist!") + end if + + call write_message("Loading cross section data...", 5) + + ! Get temperatures + call get_temperatures(temps) + + ! Open file for reading + file_id = file_open(path_cross_sections, 'r', parallel=.true.) + + ! Read filetype + call read_attribute(word, file_id, "filetype") + if (word /= 'mgxs') then + call fatal_error("Provided MGXS Library is not a MGXS Library file.") + end if + + ! Read revision number for the MGXS Library file and make sure it matches + ! with the current version + call read_attribute(array, file_id, "version") + if (any(array /= VERSION_MGXS_LIBRARY)) then + call fatal_error("MGXS Library file version does not match current & + &version supported by OpenMC.") + end if + + ! ========================================================================== + ! READ ALL MGXS CROSS SECTION TABLES + + ! Loop over all files + MATERIAL_LOOP: do i = 1, n_materials + mat => materials(i) + + NUCLIDE_LOOP: do j = 1, mat % n_nuclides + name = trim(mat % names(j)) // C_NULL_CHAR + i_nuclide = mat % nuclide(j) + + if (.not. already_read % contains(name)) then + call add_mgxs_c(file_id, name, & + num_energy_groups, num_delayed_groups, & + temps(i_nuclide) % size(), temps(i_nuclide) % data, & + temperature_method, temperature_tolerance, max_order, & + logical(legendre_to_tabular, C_BOOL), legendre_to_tabular_points) + + call already_read % add(name) + end if + end do NUCLIDE_LOOP + + mat % fissionable = query_fissionable_c(mat % n_nuclides, mat % nuclide) + + end do MATERIAL_LOOP + + call file_close(file_id) + + ! Avoid some valgrind leak errors + call already_read % clear() + + end subroutine read_mgxs2 + !=============================================================================== ! CREATE_MACRO_XS generates the macroscopic xs from the microscopic input data !=============================================================================== diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index 5abeccbcfa..be3e4e9d4d 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -215,10 +215,10 @@ module mgxs_header type(MgxsContainer), target, allocatable :: macro_xs(:) ! Number of energy groups - integer :: num_energy_groups + integer(C_INT) :: num_energy_groups ! Number of delayed groups - integer :: num_delayed_groups + integer(C_INT) :: num_delayed_groups ! Energy group structure with decreasing energy real(8), allocatable :: energy_bins(:) diff --git a/src/scattdata.cpp b/src/scattdata.cpp index 8283febc88..cb72f42298 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -2,12 +2,6 @@ namespace openmc { -//============================================================================== -// Methods for use by all extended types -//============================================================================== - - - //============================================================================== // ScattData base-class methods //============================================================================== @@ -128,7 +122,7 @@ void ScattDataLegendre::init(int_1dvec in_gmin, int_1dvec in_gmax, // coefficient in the variable matrix over all outgoing groups. scattxs.resize(groups); for (int gin = 0; gin < groups; gin++) { - int num_groups = gmax[gin] - gmin[gin] + 1; + int num_groups = in_gmax[gin] - in_gmin[gin] + 1; scattxs[gin] = 0.; for (int i_gout = 0; i_gout < num_groups; i_gout++) { scattxs[gin] = std::accumulate(matrix[gin][i_gout].begin(), @@ -143,7 +137,7 @@ void ScattDataLegendre::init(int_1dvec in_gmin, int_1dvec in_gmax, double_2dvec in_energy; in_energy.resize(groups); for (int gin = 0; gin < groups; gin++) { - int num_groups = gmax[gin] - gmin[gin] + 1; + int num_groups = in_gmax[gin] - in_gmin[gin] + 1; in_energy[gin].resize(num_groups); for (int i_gout = 0; i_gout < num_groups; i_gout++) { double norm = matrix[gin][i_gout][0]; @@ -430,7 +424,7 @@ void ScattDataHistogram::init(int_1dvec in_gmin, int_1dvec in_gmax, double_2dvec in_energy; in_energy.resize(groups); for (int gin = 0; gin < groups; gin++) { - int num_groups = gmax[gin] - gmin[gin] + 1; + int num_groups = in_gmax[gin] - in_gmin[gin] + 1; in_energy[gin].resize(num_groups); for (int i_gout = 0; i_gout < num_groups; i_gout++) { double norm = std::accumulate(matrix[gin][i_gout].begin(), @@ -572,6 +566,128 @@ double_3dvec ScattDataHistogram::get_matrix(int max_order) return matrix; } + +void ScattDataHistogram::combine(std::vector those_scatts, + double_1dvec& scalars) +{ + int groups = energy.size(); + // Find the maximum order in the data set + int max_order = get_order(); + for (int i = 0; i < those_scatts.size(); i++) { + // Lets also make sure these items are combineable + ScattDataHistogram* that = dynamic_cast(those_scatts[i]); + if (!equiv(*that)) { + fatal_error("Cannot combine the ScattData objects!"); + } + int that_order = that->get_order(); + if (that_order > max_order) max_order = that_order; + } + max_order++; // Add one since this is a Legendre + + // Now allocate and zero our storage spaces + double_3dvec this_matrix = get_matrix(max_order); + double_2dvec mult_numer(groups, double_1dvec(groups, 0.)); + double_2dvec mult_denom(groups, double_1dvec(groups, 0.)); + + // Build the dense scattering and multiplicity matrices + // Get the multiplicity_matrix + // To combine from nuclidic data we need to use the final relationship + // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + // sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + // Developed as follows: + // mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} + // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) + // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + // sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + // nuscatt_{i,g,g'} can be reconstructed from the energy and scattxs member + // variables + for (int i = 0; i < those_scatts.size(); i++) { + ScattDataHistogram* that = dynamic_cast(those_scatts[i]); + + // Build the dense matrix for that object + double_3dvec that_matrix = that->get_matrix(max_order); + + // Now add that to this for the scattering and multiplicity + for (int gin = 0; gin < groups; gin++) { + // Only spend time adding that's gmin to gmax data since the rest will + // be zeros + for (int gout = that->gmin[gin]; gout <= that->gmax[gin]; gout++) { + // Do the scattering matrix + for (int l = 0; l < max_order; l++) { + this_matrix[gin][gout][l] += scalars[i] * that_matrix[gin][gout][l]; + } + + // Incorporate that's contribution to the multiplicity matrix data + double nuscatt = that->scattxs[gin] * that->energy[gin][gout]; + mult_numer[gin][gout] += scalars[i] * nuscatt; + if (that->mult[gin][gout] > 0.) { + mult_denom[gin][gout] += scalars[i] * nuscatt / that->mult[gin][gout]; + } else { + mult_denom[gin][gout] += scalars[i]; + } + } + } + } + + // Combine mult_numer and mult_denom into the combined multiplicity matrix + double_2dvec this_mult(groups, double_1dvec(groups, 1.)); + for (int gin = 0; gin < groups; gin++) { + for (int gout = 0; gout < groups; gout++) { + if (mult_denom[gin][gout] > 0.) { + this_mult[gin][gout] = mult_numer[gin][gout] / mult_denom[gin][gout]; + } + } + } + mult_numer.clear(); + mult_denom.clear(); + + // We have the data, now we need to convert to a jagged array and then use + // the initialize function to store it on the object. + int_1dvec in_gmin(groups); + int_1dvec in_gmax(groups); + double_3dvec sparse_scatter(groups); + double_2dvec sparse_mult(groups); + for (int gin = 0; gin < groups; gin++) { + // Find the minimum and maximum group boundaries + int gmin_; + for (gmin_ = 0; gmin_ < groups; gmin_++) { + bool non_zero = std::all_of(this_matrix[gin][gmin_].begin(), + this_matrix[gin][gmin_].end(), + [](double val){return val > 0.;}); + if (non_zero) break; + } + int gmax_; + for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) { + bool non_zero = std::all_of(this_matrix[gin][gmax_].begin(), + this_matrix[gin][gmax_].end(), + [](double val){return val > 0.;}); + if (non_zero) break; + } + + // treat the case of all values being 0 + if (gmin_ > gmax_) { + gmin_ = gin; + gmax_ = gin; + } + + // Store the group bounds + in_gmin[gin] = gmin_; + in_gmax[gin] = gmax_; + + // Store the data in the compressed format + sparse_scatter[gin].resize(gmax_ - gmin_ + 1); + sparse_mult[gin].resize(gmax_ - gmin_ + 1); + int i_gout = 0; + for (int gout = gmin_; gout <= gmax_; gout++) { + sparse_scatter[gin][i_gout] = this_matrix[gin][gout]; + sparse_mult[gin][i_gout] = this_mult[gin][gout]; + } + } + + // Got everything we need, store it. + init(in_gmin, in_gmax, sparse_mult, sparse_scatter); +} + //============================================================================== // ScattDataTabular methods //============================================================================== @@ -611,7 +727,7 @@ void ScattDataTabular::init(int_1dvec in_gmin, int_1dvec in_gmax, double_2dvec in_energy; in_energy.resize(groups); for (int gin = 0; gin < groups; gin++) { - int num_groups = gmax[gin] - gmin[gin] + 1; + int num_groups = in_gmax[gin] - in_gmin[gin] + 1; in_energy[gin].resize(num_groups); for (int i_gout = 0; i_gout < num_groups; i_gout++) { double norm = 0.; @@ -769,15 +885,132 @@ double_3dvec ScattDataTabular::get_matrix(int max_order) return matrix; } +void ScattDataTabular::combine(std::vector those_scatts, + double_1dvec& scalars) +{ + int groups = energy.size(); + // Find the maximum order in the data set + int max_order = get_order(); + for (int i = 0; i < those_scatts.size(); i++) { + // Lets also make sure these items are combineable + ScattDataTabular* that = dynamic_cast(those_scatts[i]); + if (!equiv(*that)) { + fatal_error("Cannot combine the ScattData objects!"); + } + int that_order = that->get_order(); + if (that_order > max_order) max_order = that_order; + } + max_order++; // Add one since this is a Legendre + + // Now allocate and zero our storage spaces + double_3dvec this_matrix = get_matrix(max_order); + double_2dvec mult_numer(groups, double_1dvec(groups, 0.)); + double_2dvec mult_denom(groups, double_1dvec(groups, 0.)); + + // Build the dense scattering and multiplicity matrices + // Get the multiplicity_matrix + // To combine from nuclidic data we need to use the final relationship + // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + // sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + // Developed as follows: + // mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} + // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) + // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + // sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + // nuscatt_{i,g,g'} can be reconstructed from the energy and scattxs member + // variables + for (int i = 0; i < those_scatts.size(); i++) { + ScattDataTabular* that = dynamic_cast(those_scatts[i]); + + // Build the dense matrix for that object + double_3dvec that_matrix = that->get_matrix(max_order); + + // Now add that to this for the scattering and multiplicity + for (int gin = 0; gin < groups; gin++) { + // Only spend time adding that's gmin to gmax data since the rest will + // be zeros + for (int gout = that->gmin[gin]; gout <= that->gmax[gin]; gout++) { + // Do the scattering matrix + for (int l = 0; l < max_order; l++) { + this_matrix[gin][gout][l] += scalars[i] * that_matrix[gin][gout][l]; + } + + // Incorporate that's contribution to the multiplicity matrix data + double nuscatt = that->scattxs[gin] * that->energy[gin][gout]; + mult_numer[gin][gout] += scalars[i] * nuscatt; + if (that->mult[gin][gout] > 0.) { + mult_denom[gin][gout] += scalars[i] * nuscatt / that->mult[gin][gout]; + } else { + mult_denom[gin][gout] += scalars[i]; + } + } + } + } + + // Combine mult_numer and mult_denom into the combined multiplicity matrix + double_2dvec this_mult(groups, double_1dvec(groups, 1.)); + for (int gin = 0; gin < groups; gin++) { + for (int gout = 0; gout < groups; gout++) { + if (mult_denom[gin][gout] > 0.) { + this_mult[gin][gout] = mult_numer[gin][gout] / mult_denom[gin][gout]; + } + } + } + mult_numer.clear(); + mult_denom.clear(); + + // We have the data, now we need to convert to a jagged array and then use + // the initialize function to store it on the object. + int_1dvec in_gmin(groups); + int_1dvec in_gmax(groups); + double_3dvec sparse_scatter(groups); + double_2dvec sparse_mult(groups); + for (int gin = 0; gin < groups; gin++) { + // Find the minimum and maximum group boundaries + int gmin_; + for (gmin_ = 0; gmin_ < groups; gmin_++) { + bool non_zero = std::all_of(this_matrix[gin][gmin_].begin(), + this_matrix[gin][gmin_].end(), + [](double val){return val > 0.;}); + if (non_zero) break; + } + int gmax_; + for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) { + bool non_zero = std::all_of(this_matrix[gin][gmax_].begin(), + this_matrix[gin][gmax_].end(), + [](double val){return val > 0.;}); + if (non_zero) break; + } + + // treat the case of all values being 0 + if (gmin_ > gmax_) { + gmin_ = gin; + gmax_ = gin; + } + + // Store the group bounds + in_gmin[gin] = gmin_; + in_gmax[gin] = gmax_; + + // Store the data in the compressed format + sparse_scatter[gin].resize(gmax_ - gmin_ + 1); + sparse_mult[gin].resize(gmax_ - gmin_ + 1); + int i_gout = 0; + for (int gout = gmin_; gout <= gmax_; gout++) { + sparse_scatter[gin][i_gout] = this_matrix[gin][gout]; + sparse_mult[gin][i_gout] = this_mult[gin][gout]; + } + } + + // Got everything we need, store it. + init(in_gmin, in_gmax, sparse_mult, sparse_scatter); +} + void convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, int n_mu) { - // Copy the obvious data - tab.energy = leg.energy; - tab.mult = leg.mult; - tab.gmin = leg.gmin; - tab.gmax = leg.gmax; + tab.generic_init(n_mu, leg.gmin, leg.gmax, leg.energy, leg.mult); // Build mu and dmu tab.mu = double_1dvec(n_mu); @@ -794,7 +1027,7 @@ void convert_legendre_to_tabular(ScattDataLegendre& leg, for (int gin = 0; gin < groups; gin++) { int num_groups = tab.gmax[gin] - tab.gmin[gin] + 1; tab.fmu[gin].resize(num_groups); - for (int i_gout = 0; i_gout < num_groups; i_gout) { + for (int i_gout = 0; i_gout < num_groups; i_gout++) { tab.fmu[gin][i_gout].resize(n_mu); for (int imu = 0; imu < n_mu; imu++) { tab.fmu[gin][i_gout][imu] = diff --git a/src/settings.F90 b/src/settings.F90 index aef1c011be..0ed51d119a 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -18,9 +18,9 @@ module settings logical :: urr_ptables_on = .true. ! Default temperature and method for choosing temperatures - integer :: temperature_method = TEMPERATURE_NEAREST + integer(C_INT) :: temperature_method = TEMPERATURE_NEAREST logical :: temperature_multipole = .false. - real(8) :: temperature_tolerance = 10.0_8 + real(C_DOUBLE) :: temperature_tolerance = 10.0_8 real(8) :: temperature_default = 293.6_8 real(8) :: temperature_range(2) = [ZERO, ZERO] @@ -30,13 +30,16 @@ module settings ! MULTI-GROUP CROSS SECTION RELATED VARIABLES ! Maximum Data Order - integer :: max_order + integer(C_INT) :: max_order ! Whether or not to convert Legendres to tabulars logical :: legendre_to_tabular = .true. ! Number of points to use in the Legendre to tabular conversion - integer :: legendre_to_tabular_points = 33 + integer(C_INT) :: legendre_to_tabular_points = 33 + + ! ============================================================================ + ! SIMULATION VARIABLES ! Assume all tallies are spatially distinct logical :: assume_separate = .false. @@ -44,9 +47,6 @@ module settings ! Use confidence intervals for results instead of standard deviations logical :: confidence_intervals = .false. - ! ============================================================================ - ! SIMULATION VARIABLES - integer(C_INT64_T), bind(C) :: n_particles = 0 ! # of particles per generation integer(C_INT32_T), bind(C) :: n_batches ! # of batches integer(C_INT32_T), bind(C) :: n_inactive ! # of inactive batches diff --git a/src/string_functions.h b/src/string_functions.h index 94d4ce6278..d44982bbd3 100644 --- a/src/string_functions.h +++ b/src/string_functions.h @@ -12,39 +12,26 @@ namespace openmc { -void strtrim(char* str) +std::string& strtrim(std::string& s) { - int start = 0; // number of leading spaces - char* buffer = str; - - while (*str && *str++ == ' ') ++start; - - while (*str++); // move to end of string - - // backup over trailing spaces - int end = str - buffer - 1; - while (end > 0 && buffer[end - 1] == ' ') --end; - buffer[end] = 0; // remove trailing spaces - - // exit if no leading spaces or string is now empty - if (end <= start || start == 0) return; - str = buffer + start; - - while ((*buffer++ = *str++)); // remove leading spaces: K&R + const char* t = " \t\n\r\f\v"; + s.erase(s.find_last_not_of(t) + 1); + s.erase(0, s.find_first_not_of(t)); + return s; } -std::string strtrim(std::string in_str) + +char* strtrim(char* c_str) { - std::string str = in_str; - // perform the left trim - str.erase(str.begin(), std::find_if(str.begin(), str.end(), - std::not1(std::ptr_fun(std::isspace)))); - // perform the right trim - str.erase(std::find_if(str.rbegin(), str.rend(), - std::not1(std::ptr_fun(std::isspace))).base(), - str.end()); + std::string std_str; + std_str.assign(c_str); + strtrim(std_str); + int length = std_str.copy(c_str, std_str.size()); + c_str[length] = '\0'; + return c_str; } + void to_lower(std::string& str) { for (int i = 0; i < str.size(); i++) str[i] = std::tolower(str[i]); diff --git a/src/xsdata.cpp b/src/xsdata.cpp index a027b18dd4..42e32baa37 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -41,7 +41,7 @@ XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable, // chi_prompt; [temperature][phi][theta][in group][delayed group] chi_prompt = double_4dvec(n_pol, double_3dvec(n_azi, - double_2dvec(energy_groups, double_1dvec(num_delayed_groups, 0.)))); + double_2dvec(energy_groups, double_1dvec(energy_groups, 0.)))); // chi_delayed; [temperature][phi][theta][in group][out group][delay group] chi_delayed = double_5dvec(n_pol, double_4dvec(n_azi, @@ -64,19 +64,10 @@ XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable, } } -XsData::~XsData() -{ - for (int p = 0; p < scatter.size(); p++) { - for (int a = 0; a < scatter[p].size(); a++) delete scatter[p][a]; - scatter[p].clear(); - } - scatter.clear(); -} - void XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, int final_scatter_format, int order_data, int max_order, - int legendre_to_tabular_points) + int legendre_to_tabular_points, bool is_isotropic) { // Reconstruct the dimension information so it doesn't need to be passed int n_pol = total.size(); @@ -87,7 +78,7 @@ void XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, // Set the fissionable-specific data if (fissionable) { _fissionable_from_hdf5(xsdata_grp, n_pol, n_azi, energy_groups, - delayed_groups); + delayed_groups, is_isotropic); } // Get the non-fission-specific data read_nd_vector(xsdata_grp, "decay_rate", decay_rate); @@ -104,9 +95,7 @@ void XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, for (int p = 0; p < n_pol; p++) { for (int a = 0; a < n_azi; a++) { for (int gin = 0; gin < energy_groups; gin++) { - if (absorption[gin][p][a] == 0.) { - absorption[p][a][gin] = 1.e-10; - } + if (absorption[p][a][gin] == 0.) absorption[p][a][gin] = 1.e-10; } } } @@ -138,7 +127,7 @@ void XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, - int energy_groups, int delayed_groups) + int energy_groups, int delayed_groups, bool is_isotropic) { double_4dvec temp_beta = double_4dvec(n_pol, double_3dvec(n_azi, @@ -149,6 +138,8 @@ void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, hid_t xsdata = open_dataset(xsdata_grp, "beta"); int ndims = dataset_ndims(xsdata); + if (is_isotropic) ndims += 2; + if (ndims == 3) { // Beta is input as [delayed group] double_1dvec temp_arr = double_1dvec(n_pol * n_azi * delayed_groups); @@ -171,7 +162,7 @@ void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Beta is input as [in group][delayed group] read_nd_vector(xsdata_grp, "beta", temp_beta); } else { - fatal_error("beta must be provided as a 1D or 2D array!"); + fatal_error("beta must be provided as a 3D or 4D array!"); } } @@ -181,12 +172,11 @@ void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, double_1dvec(energy_groups))); read_nd_vector(xsdata_grp, "chi", temp_arr); - int temp_idx = 0; for (int p = 0; p < n_pol; p++) { for (int a = 0; a < n_azi; a++) { // First set the first group for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[p][a][0][gout] = temp_arr[p][a][temp_idx++]; + chi_prompt[p][a][0][gout] = temp_arr[p][a][gout]; } // Now normalize this data @@ -224,6 +214,7 @@ void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (object_exists(xsdata_grp, "nu-fission")) { hid_t xsdata = open_dataset(xsdata_grp, "nu-fission"); int ndims = dataset_ndims(xsdata); + if (is_isotropic) ndims += 2; if (ndims == 3) { // nu-fission is a 3-d array @@ -303,7 +294,7 @@ void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } } } else { - fatal_error("beta must be provided as a 3D or 4D array!"); + fatal_error("nu-fission must be provided as a 3D or 4D array!"); } close_dataset(xsdata); @@ -341,6 +332,7 @@ void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (object_exists(xsdata_grp, "chi-delayed")) { hid_t xsdata = open_dataset(xsdata_grp, "chi-delayed"); int ndims = dataset_ndims(xsdata); + if (is_isotropic) ndims += 2; close_dataset(xsdata); if (ndims == 3) { @@ -403,6 +395,7 @@ void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (object_exists(xsdata_grp, "prompt-nu-fission")) { hid_t xsdata = open_dataset(xsdata_grp, "prompt-nu-fission"); int ndims = dataset_ndims(xsdata); + if (is_isotropic) ndims += 2; close_dataset(xsdata); if (ndims == 3) { @@ -449,6 +442,7 @@ void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (object_exists(xsdata_grp, "delayed-nu-fission")) { hid_t xsdata = open_dataset(xsdata_grp, "delayed-nu-fission"); int ndims = dataset_ndims(xsdata); + if (is_isotropic) ndims += 2; if (ndims == 3) { // delayed-nu-fission is a [in group] vector @@ -473,29 +467,6 @@ void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } } else if (ndims == 4) { - // delayed nu fission is a [pol][azi][energy_group][delayed_group] matrix; - // matrix use this to set delayed-nu-fission separately for each - // delayed group - std::vector dims(ndims); - get_shape(xsdata, &dims[0]); - - if (dims[2] != delayed_groups) { - fatal_error("The delayed-nu-fission matrix was input with a 1st " - "dimension not equal to the number of delayed groups"); - } - if (dims[3] != energy_groups) { - fatal_error("The delayed-nu-fission matrix was input with a 2nd " - "dimension not equal to the number of energy groups"); - } - if (delayed_groups == energy_groups) { - warning("delayed-nu-fission was input as a dimension-4 matrix " - "with the same number of delayed groups and energy " - "groups. OpenMC assumes the dimensions in the matrix " - "are [delayed_groups][energy_groups]. Currently, " - "delayed-nu-fission cannot be set as a group-by-group " - "matrix"); - } - read_nd_vector(xsdata_grp, "delayed-nu-fission", delayed_nu_fission); diff --git a/src/xsdata.h b/src/xsdata.h index 1c1f8241b7..fec28aece1 100644 --- a/src/xsdata.h +++ b/src/xsdata.h @@ -11,6 +11,7 @@ #include #include #include +#include #include "constants.h" #include "hdf5_interface.h" @@ -31,7 +32,7 @@ class XsData { int energy_groups, int scatter_format, int final_scatter_format, int order_data, int max_order, int legendre_to_tabular_points); void _fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, - int energy_groups, int delayed_groups); + int energy_groups, int delayed_groups, bool is_isotropic); public: // The following quantities have the following dimensions: // [phi][theta][incoming group] @@ -59,10 +60,9 @@ class XsData { XsData() = default; XsData(int num_groups, int num_delayed_groups, bool fissionable, int scatter_format, int n_pol, int n_azi); - ~XsData(); void from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, int final_scatter_format, int order_data, int max_order, - int legendre_to_tabular_points); + int legendre_to_tabular_points, bool is_isotropic); void combine(std::vector those_xs, double_1dvec& scalars); bool equiv(const XsData& that); }; From ce919a0ad85b9ee0023ded1224bb05686edb1e94 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sat, 9 Jun 2018 08:53:40 -0400 Subject: [PATCH 016/100] extended to being able to combine microscopic data into macroscopic. Seems to work, next step is to actually incorporate the C++ data into the transport and tallying process. That will be the true test --- src/input_xml.F90 | 3 +- src/material_header.F90 | 2 +- src/mgxs.cpp | 84 ++++++++++++++++------------ src/mgxs.h | 12 ++-- src/mgxs_data.F90 | 47 ++++++++++++++++ src/scattdata.cpp | 119 +++++++++++++++++----------------------- src/scattdata.h | 19 +++---- src/xsdata.cpp | 67 +++++++++++----------- 8 files changed, 199 insertions(+), 154 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 8d4c8de817..507bdf8a9c 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -19,7 +19,7 @@ module input_xml use material_header use mesh_header use message_passing - use mgxs_data, only: create_macro_xs, read_mgxs, read_mgxs2 + use mgxs_data, only: create_macro_xs, read_mgxs, read_mgxs2, create_macro_xs2 use mgxs_header use nuclide_header use output, only: title, header, print_plot @@ -86,6 +86,7 @@ contains call read_mgxs() call read_mgxs2() call create_macro_xs() + call create_macro_xs2() end if call time_read_xs % stop() end if diff --git a/src/material_header.F90 b/src/material_header.F90 index 038e529bee..7fbfe553b3 100644 --- a/src/material_header.F90 +++ b/src/material_header.F90 @@ -34,7 +34,7 @@ module material_header integer :: n_nuclides = 0 ! number of nuclides integer, allocatable :: nuclide(:) ! index in nuclides array real(8) :: density ! total atom density in atom/b-cm - real(8), allocatable :: atom_density(:) ! nuclide atom density in atom/b-cm + real(C_DOUBLE), allocatable :: atom_density(:) ! nuclide atom density in atom/b-cm real(8) :: density_gpcc ! total density in g/cm^3 ! To improve performance of tallying, we store an array (direct address diff --git a/src/mgxs.cpp b/src/mgxs.cpp index 9c11da8ac8..35ac42f171 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -266,11 +266,14 @@ void Mgxs::from_hdf5(hid_t xs_id, int energy_groups, int delayed_groups, close_group(xsdata_grp); } // end temperature loop + + // Make sure the scattering format is updated to the final case + scatter_format = final_scatter_format; } void Mgxs::build_macro(const std::string& in_name, double_1dvec& mat_kTs, - std::vector& micros, double_1dvec& atom_densities, + std::vector& micros, double_1dvec& atom_densities, int& method, double tolerance) { // Get the minimum data needed to initialize: @@ -279,21 +282,25 @@ void Mgxs::build_macro(const std::string& in_name, double_1dvec& mat_kTs, // start with the assumption it is not fissionable bool in_fissionable = false; for (int m = 0; m < micros.size(); m++) { - if (micros[m].fissionable) in_fissionable = true; + if (micros[m]->fissionable) in_fissionable = true; } // Force all of the following data to be the same; these will be verified // to be true later - int in_scatter_format = micros[0].scatter_format; - int in_num_groups = micros[0].num_groups; - int in_num_delayed_groups = micros[0].num_delayed_groups; - double_1dvec in_polar = micros[0].polar; - double_1dvec in_azimuthal = micros[0].azimuthal; + int in_scatter_format = micros[0]->scatter_format; + int in_num_groups = micros[0]->num_groups; + int in_num_delayed_groups = micros[0]->num_delayed_groups; + double_1dvec in_polar = micros[0]->polar; + double_1dvec in_azimuthal = micros[0]->azimuthal; - init(in_name, in_awr, mat_kTs, in_fissionable, in_scatter_format, in_num_groups, - in_num_delayed_groups, in_polar, in_azimuthal); + init(in_name, in_awr, mat_kTs, in_fissionable, in_scatter_format, + in_num_groups, in_num_delayed_groups, in_polar, in_azimuthal); // Create the xs data for each temperature for (int t = 0; t < mat_kTs.size(); t++) { + xs[t]= XsData(in_num_groups, in_num_delayed_groups, in_fissionable, + in_scatter_format, in_polar.size(), in_azimuthal.size()); + + // Find the right temperature index to use double temp_desired = mat_kTs[t]; // Create the list of temperature indices and interpolation factors for @@ -305,13 +312,13 @@ void Mgxs::build_macro(const std::string& in_name, double_1dvec& mat_kTs, case TEMPERATURE_NEAREST: { // Find the nearest temperature - std::valarray temp_diff(micros[m].kTs.data(), - micros[m].kTs.size()); + std::valarray temp_diff(micros[m]->kTs.data(), + micros[m]->kTs.size()); temp_diff = std::abs(temp_diff - temp_desired); micro_t[m] = std::min_element(std::begin(temp_diff), std::end(temp_diff)) - std::begin(temp_diff); - double temp_actual = micros[m].kTs[micro_t[m]]; + double temp_actual = micros[m]->kTs[micro_t[m]]; if (std::abs(temp_actual - temp_desired) >= K_BOLTZMANN * tolerance) { fatal_error("MGXS Library does not contain cross section for " + @@ -324,13 +331,13 @@ void Mgxs::build_macro(const std::string& in_name, double_1dvec& mat_kTs, case TEMPERATURE_INTERPOLATION: // Get a list of bounding temperatures for each actual temperature // present in the model - for (int k = 0; k < micros[m].kTs.size() - 1; k++) { - if ((micros[m].kTs[k] <= temp_desired) && - (temp_desired < micros[m].kTs[k + 1])) { + for (int k = 0; k < micros[m]->kTs.size() - 1; k++) { + if ((micros[m]->kTs[k] <= temp_desired) && + (temp_desired < micros[m]->kTs[k + 1])) { micro_t[m] = k; if (k == 0) { - micro_t_interp[m] = (temp_desired - micros[m].kTs[k]) / - (micros[m].kTs[k + 1] - micros[m].kTs[k]); + micro_t_interp[m] = (temp_desired - micros[m]->kTs[k]) / + (micros[m]->kTs[k + 1] - micros[m]->kTs[k]); } else { micro_t_interp[m] = 1.; } @@ -353,23 +360,23 @@ void Mgxs::build_macro(const std::string& in_name, double_1dvec& mat_kTs, interp[m] = (1. - micro_t_interp[m]) * atom_densities[m]; temp_indices[m] = micro_t[m] + interp_point; } + combine(micros, interp, micro_t, t); } // end loop to sum all micros across the temperatures } // end temperature (t) loop - } -void Mgxs::combine(std::vector& micros, double_1dvec& scalars, +void Mgxs::combine(std::vector& micros, double_1dvec& scalars, int_1dvec& micro_ts, int this_t) { // Build the vector of pointers to the xs objects within micros std::vector those_xs(micros.size()); for (int i = 0; i < micros.size(); i++) { - if (!xs[this_t].equiv(micros[i].xs[micro_ts[i]])) { + if (!xs[this_t].equiv(micros[i]->xs[micro_ts[i]])) { fatal_error("Cannot combine the Mgxs objects!"); } - those_xs[i] = &(micros[i].xs[micro_ts[i]]); + those_xs[i] = &(micros[i]->xs[micro_ts[i]]); } xs[this_t].combine(those_xs, scalars); @@ -646,24 +653,31 @@ bool query_fissionable(const int n_nuclides, const int i_nuclides[]) } -void create_macro_xs(int n_materials, double_2dvec& mat_kTs, - std::vector& mat_names, - double_1dvec& atom_densities, int& method, - double tolerance) +void create_macro_xs(char* mat_name, const int n_nuclides, + const int i_nuclides[], const int n_temps, const double temps[], + const double atom_densities[], int& method, const double tolerance) { - // TODO mat_kTs needs to be converted from Fortran - // it is currently an array of type(VectorReal), a wrapper should convert to - // the vector. - macro_xs.resize(n_materials); + Mgxs macro; + if (n_temps > 0) { + // // Convert temps to a vector + double_1dvec temperature; + temperature.assign(temps, temps + n_temps); - for (int m = 0; m < n_materials; m++) - { - if (mat_kTs[m].size() > 0) { - macro_xs[m].build_macro(mat_names[m], mat_kTs[m], nuclides_MG, - atom_densities, method, tolerance); + // Convert atom_densities to a vector + double_1dvec atom_densities_vec; + atom_densities_vec.assign(atom_densities, atom_densities + n_nuclides); + + // Build array of pointers to nuclides_MG's Mgxs objects needed for this + // material + std::vector mgxs_ptr(n_nuclides); + for (int n = 0; n < n_nuclides; n++) { + mgxs_ptr[n] = &nuclides_MG[i_nuclides[n] - 1]; } + + macro.build_macro(mat_name, temperature, mgxs_ptr, atom_densities_vec, + method, tolerance); } + macro_xs.push_back(macro); } - } // namespace openmc \ No newline at end of file diff --git a/src/mgxs.h b/src/mgxs.h index 8c13cf7cb4..90ed520d9a 100644 --- a/src/mgxs.h +++ b/src/mgxs.h @@ -58,9 +58,9 @@ class Mgxs { const int in_num_delayed_groups, const double_1dvec& in_polar, const double_1dvec& in_azimuthal); void build_macro(const std::string& in_name, double_1dvec& mat_kTs, - std::vector& micros, double_1dvec& atom_densities, + std::vector& micros, double_1dvec& atom_densities, int& method, double tolerance); - void combine(std::vector& micros, double_1dvec& scalars, + void combine(std::vector& micros, double_1dvec& scalars, int_1dvec& micro_ts, int this_t); void from_hdf5(hid_t xs_id, int energy_groups, int delayed_groups, double_1dvec& temperature, int& method, double tolerance, @@ -82,10 +82,12 @@ extern "C" void add_mgxs(hid_t file_id, char* name, int energy_groups, int delayed_groups, int n_temps, double temps[], int& method, double tolerance, int max_order, bool legendre_to_tabular, int legendre_to_tabular_points); + extern "C" bool query_fissionable(const int n_nuclides, const int i_nuclides[]); -void create_macro_xs(int n_materials, double_2dvec& mat_kTs, - std::vector& mat_names, double_1dvec& atom_densities, - int& method, double tolerance); + +extern "C" void create_macro_xs(char* mat_name, const int n_nuclides, + const int i_nuclides[], const int n_temps, const double temps[], + const double atom_densities[], int& method, const double tolerance); // Storage for the MGXS data diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index 6be463a91e..a61bb65a2b 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -45,6 +45,20 @@ module mgxs_data integer(C_INT), intent(in) :: i_nuclides(1:n_nuclides) logical(C_BOOL) :: result end function query_fissionable_c + + subroutine create_macro_xs_c(name, n_nuclides, i_nuclides, n_temps, temps, & + atom_densities, method, tolerance) bind(C, name='create_macro_xs') + use ISO_C_BINDING + implicit none + character(kind=C_CHAR),intent(in) :: name(*) + integer(C_INT), value, intent(in) :: n_nuclides + integer(C_INT), intent(in) :: i_nuclides(1:n_nuclides) + integer(C_INT), value, intent(in) :: n_temps + real(C_DOUBLE), intent(in) :: temps(1:n_temps) + real(C_DOUBLE), intent(in) :: atom_densities(1:n_nuclides) + integer(C_INT), intent(inout) :: method + real(C_DOUBLE), value, intent(in) :: tolerance + end subroutine create_macro_xs_c end interface contains @@ -316,6 +330,39 @@ contains end subroutine create_macro_xs + + subroutine create_macro_xs2() + integer :: i_mat ! index in materials array + type(Material), pointer :: mat ! current material + type(VectorReal), allocatable :: kTs(:) + character(MAX_WORD_LEN) :: name ! name of material + + ! Get temperatures to read for each material + call get_mat_kTs(kTs) + + ! Force all nuclides in a material to be the same representation. + ! Therefore type(nuclides(mat % nuclide(1)) % obj) dictates type(macroxs). + ! At the same time, we will find the scattering type, as that will dictate + ! how we allocate the scatter object within macroxs.allocate(macro_xs(n_materials)) + do i_mat = 1, n_materials + + ! Get the material + mat => materials(i_mat) + + name = trim(mat % name) // C_NULL_CHAR + + ! Do not read materials which we do not actually use in the problem to + ! reduce storage + if (allocated(kTs(i_mat) % data)) then + call create_macro_xs_c(name, mat % n_nuclides, mat % nuclide, & + kTs(i_mat) % size(), kTs(i_mat) % data, mat % atom_density, & + temperature_method, temperature_tolerance) + end if + end do + + end subroutine create_macro_xs2 + + !=============================================================================== ! GET_MAT_kTs returns a list of temperatures (in eV) that each ! material appears at in the model. diff --git a/src/scattdata.cpp b/src/scattdata.cpp index cb72f42298..dc4d169a7c 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -109,11 +109,11 @@ double ScattData::get_xs(const char* xstype, int gin, int* gout, double* mu) // ScattDataLegendre methods //============================================================================== -void ScattDataLegendre::init(int_1dvec in_gmin, int_1dvec in_gmax, - double_2dvec in_mult, double_3dvec coeffs) +void ScattDataLegendre::init(int_1dvec& in_gmin, int_1dvec& in_gmax, + double_2dvec& in_mult, double_3dvec& coeffs) { int groups = coeffs.size(); - int order = coeffs[0].size(); + int order = coeffs[0][0].size(); // make a copy of coeffs that we can use to both extract data and normalize double_3dvec matrix = coeffs; @@ -250,13 +250,12 @@ void ScattDataLegendre::sample(int gin, int& gout, double& mu, double& wgt) void ScattDataLegendre::combine(std::vector those_scatts, double_1dvec& scalars) { - int groups = energy.size(); - // Find the maximum order in the data set - int max_order = get_order(); + // Find the max order in the data set and make sure we can combine the sets + int max_order = 0; for (int i = 0; i < those_scatts.size(); i++) { // Lets also make sure these items are combineable ScattDataLegendre* that = dynamic_cast(those_scatts[i]); - if (!equiv(*that)) { + if (!that) { fatal_error("Cannot combine the ScattData objects!"); } int that_order = that->get_order(); @@ -264,6 +263,9 @@ void ScattDataLegendre::combine(std::vector those_scatts, } max_order++; // Add one since this is a Legendre + // Get the groups as a shorthand + int groups = dynamic_cast(those_scatts[0])->energy.size(); + // Now allocate and zero our storage spaces double_3dvec this_matrix = get_matrix(max_order); double_2dvec mult_numer(groups, double_1dvec(groups, 0.)); @@ -369,23 +371,16 @@ void ScattDataLegendre::combine(std::vector those_scatts, } -bool ScattDataLegendre::equiv(const ScattDataLegendre& that) -{ - // ensure that the number of groups match - return (this->energy.size() == that.energy.size()); -} - - double_3dvec ScattDataLegendre::get_matrix(int max_order) { // Get the sizes and initialize the data to 0 int groups = energy.size(); int order_dim = max_order + 1; - double_3dvec matrix = double_3dvec(groups, double_2dvec(order_dim, + double_3dvec matrix = double_3dvec(groups, double_2dvec(groups, double_1dvec(order_dim, 0.))); for (int gin = 0; gin < groups; gin++) { - for (int i_gout = 0; i_gout < energy[0].size(); i_gout++) { + for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) { int gout = i_gout + gmin[gin]; for (int l = 0; l < order_dim; l++) { matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] * @@ -400,11 +395,11 @@ double_3dvec ScattDataLegendre::get_matrix(int max_order) // ScattDataHistogram methods //============================================================================== -void ScattDataHistogram::init(int_1dvec in_gmin, int_1dvec in_gmax, - double_2dvec in_mult, double_3dvec coeffs) +void ScattDataHistogram::init(int_1dvec& in_gmin, int_1dvec& in_gmax, + double_2dvec& in_mult, double_3dvec& coeffs) { int groups = coeffs.size(); - int order = coeffs[0].size(); + int order = coeffs[0][0].size(); // make a copy of coeffs that we can use to both extract data and normalize double_3dvec matrix = coeffs; @@ -452,7 +447,7 @@ void ScattDataHistogram::init(int_1dvec in_gmin, int_1dvec in_gmax, for (int gin = 0; gin < groups; gin++) { int num_groups = gmax[gin] - gmin[gin] + 1; fmu[gin].resize(num_groups); - for (int i_gout = 0; i_gout < num_groups; i_gout) { + for (int i_gout = 0; i_gout < num_groups; i_gout++) { fmu[gin][i_gout].resize(order); // The variable matrix contains f(mu); so directly assign it fmu[gin][i_gout] = matrix[gin][i_gout]; @@ -533,29 +528,17 @@ void ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt) } -bool ScattDataHistogram::equiv(const ScattDataHistogram& that) -{ - bool match = false; - if (this->energy.size() == that.energy.size() && - this->dmu == that.dmu && - std::equal(this->mu.begin(), this->mu.end(), that.mu.begin())) { - match = true; - } - return match; -} - - double_3dvec ScattDataHistogram::get_matrix(int max_order) { // Get the sizes and initialize the data to 0 int groups = energy.size(); // We ignore the requested order for Histogram and Tabular representations int order_dim = get_order(); - double_3dvec matrix = double_3dvec(groups, double_2dvec(order_dim, + double_3dvec matrix = double_3dvec(groups, double_2dvec(groups, double_1dvec(order_dim, 0.))); for (int gin = 0; gin < groups; gin++) { - for (int i_gout = 0; i_gout < energy[0].size(); i_gout++) { + for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) { int gout = i_gout + gmin[gin]; for (int l = 0; l < order_dim; l++) { matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] * @@ -570,19 +553,23 @@ double_3dvec ScattDataHistogram::get_matrix(int max_order) void ScattDataHistogram::combine(std::vector those_scatts, double_1dvec& scalars) { - int groups = energy.size(); - // Find the maximum order in the data set - int max_order = get_order(); + // Find the max order in the data set and make sure we can combine the sets + int max_order; for (int i = 0; i < those_scatts.size(); i++) { // Lets also make sure these items are combineable ScattDataHistogram* that = dynamic_cast(those_scatts[i]); - if (!equiv(*that)) { + if (!that) { + fatal_error("Cannot combine the ScattData objects!"); + } + if (i == 0) { + max_order = that->get_order(); + } else if (max_order != that->get_order()) { fatal_error("Cannot combine the ScattData objects!"); } - int that_order = that->get_order(); - if (that_order > max_order) max_order = that_order; } - max_order++; // Add one since this is a Legendre + + // Get the groups as a shorthand + int groups = dynamic_cast(those_scatts[0])->energy.size(); // Now allocate and zero our storage spaces double_3dvec this_matrix = get_matrix(max_order); @@ -692,11 +679,11 @@ void ScattDataHistogram::combine(std::vector those_scatts, // ScattDataTabular methods //============================================================================== -void ScattDataTabular::init(int_1dvec in_gmin, int_1dvec in_gmax, - double_2dvec in_mult, double_3dvec coeffs) +void ScattDataTabular::init(int_1dvec& in_gmin, int_1dvec& in_gmax, + double_2dvec& in_mult, double_3dvec& coeffs) { int groups = coeffs.size(); - int order = coeffs[0].size(); + int order = coeffs[0][0].size(); // make a copy of coeffs that we can use to both extract data and normalize double_3dvec matrix = coeffs; @@ -742,15 +729,14 @@ void ScattDataTabular::init(int_1dvec in_gmin, int_1dvec in_gmax, } // Initialize the base class attributes - ScattData::generic_init(order, in_gmin, in_gmax, in_energy, - in_mult); + ScattData::generic_init(order, in_gmin, in_gmax, in_energy, in_mult); // Calculate f(mu) and integrate it so we can avoid rejection sampling fmu.resize(groups); for (int gin = 0; gin < groups; gin++) { int num_groups = gmax[gin] - gmin[gin] + 1; fmu[gin].resize(num_groups); - for (int i_gout = 0; i_gout < num_groups; i_gout) { + for (int i_gout = 0; i_gout < num_groups; i_gout++) { fmu[gin][i_gout].resize(order); // The variable matrix contains f(mu); so directly assign it fmu[gin][i_gout] = matrix[gin][i_gout]; @@ -852,29 +838,17 @@ void ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt) } -bool ScattDataTabular::equiv(const ScattDataTabular& that) -{ - bool match = false; - if (this->energy.size() == that.energy.size() && - this->dmu == that.dmu && - std::equal(this->mu.begin(), this->mu.end(), that.mu.begin())) { - match = true; - } - return match; -} - - double_3dvec ScattDataTabular::get_matrix(int max_order) { // Get the sizes and initialize the data to 0 int groups = energy.size(); // We ignore the requested order for Histogram and Tabular representations int order_dim = get_order(); - double_3dvec matrix = double_3dvec(groups, double_2dvec(order_dim, + double_3dvec matrix = double_3dvec(groups, double_2dvec(groups, double_1dvec(order_dim, 0.))); for (int gin = 0; gin < groups; gin++) { - for (int i_gout = 0; i_gout < energy[0].size(); i_gout++) { + for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) { int gout = i_gout + gmin[gin]; for (int l = 0; l < order_dim; l++) { matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] * @@ -888,22 +862,27 @@ double_3dvec ScattDataTabular::get_matrix(int max_order) void ScattDataTabular::combine(std::vector those_scatts, double_1dvec& scalars) { - int groups = energy.size(); - // Find the maximum order in the data set - int max_order = get_order(); + // Find the max order in the data set and make sure we can combine the sets + int max_order; for (int i = 0; i < those_scatts.size(); i++) { // Lets also make sure these items are combineable ScattDataTabular* that = dynamic_cast(those_scatts[i]); - if (!equiv(*that)) { + if (!that) { + fatal_error("Cannot combine the ScattData objects!"); + } + if (i == 0) { + max_order = that->get_order(); + } else if (max_order != that->get_order()) { fatal_error("Cannot combine the ScattData objects!"); } - int that_order = that->get_order(); - if (that_order > max_order) max_order = that_order; } - max_order++; // Add one since this is a Legendre + + // Get the groups as a shorthand + int groups = dynamic_cast(those_scatts[0])->energy.size(); // Now allocate and zero our storage spaces - double_3dvec this_matrix = get_matrix(max_order); + double_3dvec this_matrix = double_3dvec(groups, double_2dvec(groups, + double_1dvec(max_order, 0.))); double_2dvec mult_numer(groups, double_1dvec(groups, 0.)); double_2dvec mult_denom(groups, double_1dvec(groups, 0.)); @@ -999,6 +978,7 @@ void ScattDataTabular::combine(std::vector those_scatts, for (int gout = gmin_; gout <= gmax_; gout++) { sparse_scatter[gin][i_gout] = this_matrix[gin][gout]; sparse_mult[gin][i_gout] = this_mult[gin][gout]; + i_gout++; } } @@ -1011,6 +991,7 @@ void convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, int n_mu) { tab.generic_init(n_mu, leg.gmin, leg.gmax, leg.energy, leg.mult); + tab.scattxs = leg.scattxs; // Build mu and dmu tab.mu = double_1dvec(n_mu); diff --git a/src/scattdata.h b/src/scattdata.h index 787a8f005d..6e24a50bc9 100644 --- a/src/scattdata.h +++ b/src/scattdata.h @@ -35,8 +35,8 @@ class ScattData { double_1dvec scattxs; // Isotropic Sigma_{s,g_{in}} virtual double calc_f(int gin, int gout, double mu) = 0; virtual void sample(int gin, int& gout, double& mu, double& wgt) = 0; - virtual void init(int_1dvec in_gmin, int_1dvec in_gmax, - double_2dvec in_mult, double_3dvec coeffs) = 0; + virtual void init(int_1dvec& in_gmin, int_1dvec& in_gmax, + double_2dvec& in_mult, double_3dvec& coeffs) = 0; void sample_energy(int gin, int& gout, int& i_gout); double get_xs(const char* xstype, int gin, int* gout, double* mu); void generic_init(int order, int_1dvec in_gmin, int_1dvec in_gmax, @@ -54,12 +54,11 @@ class ScattDataLegendre: public ScattData { friend void convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, int n_mu); public: - void init(int_1dvec in_gmin, int_1dvec in_gmax, double_2dvec in_mult, - double_3dvec coeffs); + void init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, + double_3dvec& coeffs); void update_max_val(); double calc_f(int gin, int gout, double mu); void sample(int gin, int& gout, double& mu, double& wgt); - bool equiv(const ScattDataLegendre& that); void combine(std::vector those_scatts, double_1dvec& scalars); int get_order() {return dist[0][0].size() - 1;}; double_3dvec get_matrix(int max_order); @@ -71,12 +70,11 @@ class ScattDataHistogram: public ScattData { double dmu; double_3dvec fmu; public: - void init(int_1dvec in_gmin, int_1dvec in_gmax, double_2dvec in_mult, - double_3dvec coeffs); + void init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, + double_3dvec& coeffs); double calc_f(int gin, int gout, double mu); void sample(int gin, int& gout, double& mu, double& wgt); void combine(std::vector those_scatts, double_1dvec& scalars); - bool equiv(const ScattDataHistogram& that); int get_order() {return dist[0][0].size();}; double_3dvec get_matrix(int max_order); }; @@ -89,12 +87,11 @@ class ScattDataTabular: public ScattData { friend void convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, int n_mu); public: - void init(int_1dvec in_gmin, int_1dvec in_gmax, double_2dvec in_mult, - double_3dvec coeffs); + void init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, + double_3dvec& coeffs); double calc_f(int gin, int gout, double mu); void sample(int gin, int& gout, double& mu, double& wgt); void combine(std::vector those_scatts, double_1dvec& scalars); - bool equiv(const ScattDataTabular& that); int get_order() {return dist[0][0].size();}; double_3dvec get_matrix(int max_order); }; diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 42e32baa37..49b07453df 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -666,26 +666,27 @@ void XsData::combine(std::vector those_xs, double_1dvec& scalars) absorption[p][a][gin] += scalar * that->absorption[p][a][gin]; inverse_velocity[p][a][gin] += scalar * that->inverse_velocity[p][a][gin]; + if (that->prompt_nu_fission.size() > 0) { + prompt_nu_fission[p][a][gin] += + scalar * that->prompt_nu_fission[p][a][gin]; + kappa_fission[p][a][gin] += + scalar * that->kappa_fission[p][a][gin]; + fission[p][a][gin] += + scalar * that->fission[p][a][gin]; - prompt_nu_fission[p][a][gin] += - scalar * that->prompt_nu_fission[p][a][gin]; - kappa_fission[p][a][gin] += - scalar * that->kappa_fission[p][a][gin]; - fission[p][a][gin] += - scalar * that->fission[p][a][gin]; + for (int dg = 0; dg < delayed_nu_fission[p][a][gin].size(); dg++) { + delayed_nu_fission[p][a][gin][dg] += + scalar * that->delayed_nu_fission[p][a][gin][dg]; + } - for (int dg = 0; dg < delayed_nu_fission[p][a][gin].size(); dg++) { - delayed_nu_fission[p][a][gin][dg] += - scalar * that->delayed_nu_fission[p][a][gin][dg]; - } + for (int gout = 0; gout < chi_prompt[p][a][gin].size(); gout++) { + chi_prompt[p][a][gin][gout] += + scalar * that->chi_prompt[p][a][gin][gout]; - for (int gout = 0; gout < chi_prompt[p][a][gin].size(); gout++) { - chi_prompt[p][a][gin][gout] += - scalar * that->chi_prompt[p][a][gin][gout]; - - for (int dg = 0; dg < chi_delayed[p][a][gin][gout].size(); dg++) { - chi_delayed[p][a][gin][gout][dg] += - scalar * that->chi_delayed[p][a][gin][gout][dg]; + for (int dg = 0; dg < chi_delayed[p][a][gin][gout].size(); dg++) { + chi_delayed[p][a][gin][gout][dg] += + scalar * that->chi_delayed[p][a][gin][gout][dg]; + } } } } @@ -695,23 +696,25 @@ void XsData::combine(std::vector those_xs, double_1dvec& scalars) } // Normalize chi - for (int gin = 0; gin < chi_prompt[p][a].size(); gin++) { - double norm = std::accumulate(chi_prompt[p][a][gin].begin(), - chi_prompt[p][a][gin].end(), 0.); - if (norm > 0.) { - for (int gout = 0; gout < chi_prompt[p][a][gin].size(); gout++) { - chi_prompt[p][a][gin][gout] /= norm; - } - } - - for (int dg = 0; dg < chi_delayed[p][a][gin][0].size(); dg++) { - norm = 0.; - for (int gout = 0; gout < chi_delayed[p][a][gin].size(); gout++) { - norm += chi_delayed[p][a][gin][gout][dg]; - } + if (chi_prompt.size() > 0) { + for (int gin = 0; gin < chi_prompt[p][a].size(); gin++) { + double norm = std::accumulate(chi_prompt[p][a][gin].begin(), + chi_prompt[p][a][gin].end(), 0.); if (norm > 0.) { + for (int gout = 0; gout < chi_prompt[p][a][gin].size(); gout++) { + chi_prompt[p][a][gin][gout] /= norm; + } + } + + for (int dg = 0; dg < chi_delayed[p][a][gin][0].size(); dg++) { + norm = 0.; for (int gout = 0; gout < chi_delayed[p][a][gin].size(); gout++) { - chi_delayed[p][a][gin][gout][dg] /= norm; + norm += chi_delayed[p][a][gin][gout][dg]; + } + if (norm > 0.) { + for (int gout = 0; gout < chi_delayed[p][a][gin].size(); gout++) { + chi_delayed[p][a][gin][gout][dg] /= norm; + } } } } From 0054759c3a51e5e0221e799dbfeca4c00141a18f Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sat, 9 Jun 2018 08:54:21 -0400 Subject: [PATCH 017/100] fixed line indentation so we can see if travis works with this --- src/mgxs_data.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index a61bb65a2b..6977378801 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -268,10 +268,10 @@ contains if (.not. already_read % contains(name)) then call add_mgxs_c(file_id, name, & - num_energy_groups, num_delayed_groups, & - temps(i_nuclide) % size(), temps(i_nuclide) % data, & - temperature_method, temperature_tolerance, max_order, & - logical(legendre_to_tabular, C_BOOL), legendre_to_tabular_points) + num_energy_groups, num_delayed_groups, & + temps(i_nuclide) % size(), temps(i_nuclide) % data, & + temperature_method, temperature_tolerance, max_order, & + logical(legendre_to_tabular, C_BOOL), legendre_to_tabular_points) call already_read % add(name) end if From 59c4bc3fc4e4a2f3cf5345d240a18db7925ccc1f Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sun, 10 Jun 2018 05:53:22 -0400 Subject: [PATCH 018/100] fixing bugs found from the mg_basic test which exercises many more Mgxs data formats --- src/mgxs.cpp | 4 ++-- src/scattdata.cpp | 6 ++++-- src/xsdata.cpp | 17 +++++++++-------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/mgxs.cpp b/src/mgxs.cpp index 35ac42f171..42df45ef0a 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -646,8 +646,8 @@ void add_mgxs(hid_t file_id, char* name, int energy_groups, bool query_fissionable(const int n_nuclides, const int i_nuclides[]) { bool result = false; - for (int i = 0; i < n_nuclides; i++) { - if (nuclides_MG[i_nuclides[i]].fissionable) result = true; + for (int n = 0; n < n_nuclides; n++) { + if (nuclides_MG[i_nuclides[n] - 1].fissionable) result = true; } return result; } diff --git a/src/scattdata.cpp b/src/scattdata.cpp index dc4d169a7c..d23169fa87 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -267,7 +267,8 @@ void ScattDataLegendre::combine(std::vector those_scatts, int groups = dynamic_cast(those_scatts[0])->energy.size(); // Now allocate and zero our storage spaces - double_3dvec this_matrix = get_matrix(max_order); + double_3dvec this_matrix = double_3dvec(groups, double_2dvec(groups, + double_1dvec(max_order, 0.))); double_2dvec mult_numer(groups, double_1dvec(groups, 0.)); double_2dvec mult_denom(groups, double_1dvec(groups, 0.)); @@ -572,7 +573,8 @@ void ScattDataHistogram::combine(std::vector those_scatts, int groups = dynamic_cast(those_scatts[0])->energy.size(); // Now allocate and zero our storage spaces - double_3dvec this_matrix = get_matrix(max_order); + double_3dvec this_matrix = double_3dvec(groups, double_2dvec(groups, + double_1dvec(max_order, 0.))); double_2dvec mult_numer(groups, double_1dvec(groups, 0.)); double_2dvec mult_denom(groups, double_1dvec(groups, 0.)); diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 49b07453df..8afdb7f039 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -35,9 +35,9 @@ XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable, double_1dvec(num_delayed_groups, 0.))); if (fissionable) { - // allocate delayed_nu_fission; [temperature][phi][theta][in group][out group] + // allocate delayed_nu_fission; [temperature][phi][theta][in group][delay group] delayed_nu_fission = double_4dvec(n_pol, double_3dvec(n_azi, - double_2dvec(energy_groups, double_1dvec(energy_groups, 0.)))); + double_2dvec(energy_groups, double_1dvec(num_delayed_groups, 0.)))); // chi_prompt; [temperature][phi][theta][in group][delayed group] chi_prompt = double_4dvec(n_pol, double_3dvec(n_azi, @@ -129,11 +129,15 @@ void XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, int energy_groups, int delayed_groups, bool is_isotropic) { + + // Get the fission and kappa_fission data xs; these are optional + read_nd_vector(xsdata_grp, "fission", fission); + read_nd_vector(xsdata_grp, "kappa-fission", kappa_fission); + + // Set/get beta double_4dvec temp_beta = double_4dvec(n_pol, double_3dvec(n_azi, double_2dvec(energy_groups, double_1dvec(delayed_groups, 0.)))); - - // Set/get beta if (object_exists(xsdata_grp, "beta")) { hid_t xsdata = open_dataset(xsdata_grp, "beta"); int ndims = dataset_ndims(xsdata); @@ -442,6 +446,7 @@ void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (object_exists(xsdata_grp, "delayed-nu-fission")) { hid_t xsdata = open_dataset(xsdata_grp, "delayed-nu-fission"); int ndims = dataset_ndims(xsdata); + close_dataset(xsdata); if (is_isotropic) ndims += 2; if (ndims == 3) { @@ -507,12 +512,8 @@ void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, fatal_error("prompt-nu-fission must be provided as a 3D, 4D, or 5D " "array!"); } - close_dataset(xsdata); } - // Get the fission and kappa_fission data xs - read_nd_vector(xsdata_grp, "fission", fission); - read_nd_vector(xsdata_grp, "kappa-fission", kappa_fission); } From 6c8de73e3e6e0eabbbac8daa64276dfa3eb1dfd9 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sun, 10 Jun 2018 14:23:08 -0400 Subject: [PATCH 019/100] Implemented sample_scatter in C++ --- src/constants.h | 1 - src/mgxs.cpp | 72 +++++++++++++++++++++++++++++++----------- src/mgxs.h | 25 +++++++++------ src/nuclide_header.F90 | 8 ++--- src/physics_mg.F90 | 28 ++++++++++++---- src/scattdata.cpp | 60 +++++++++++++++++++---------------- src/scattdata.h | 8 ++--- src/tracking.F90 | 23 ++++++++++++++ 8 files changed, 156 insertions(+), 69 deletions(-) diff --git a/src/constants.h b/src/constants.h index 4129305bf9..8290aa8c9c 100644 --- a/src/constants.h +++ b/src/constants.h @@ -10,7 +10,6 @@ namespace openmc { -typedef std::array dir_arr; typedef std::vector double_1dvec; typedef std::vector > double_2dvec; typedef std::vector > > double_3dvec; diff --git a/src/mgxs.cpp b/src/mgxs.cpp index 42df45ef0a..ec711e1307 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -24,6 +24,13 @@ void Mgxs::init(const std::string& in_name, const double in_awr, azimuthal = in_azimuthal; n_pol = polar.size(); n_azi = azimuthal.size(); + index_temp = 0; + last_sqrtkT = 0.; + index_pol = 0; + index_azi = 0; + last_uvw[0] = 1.; + last_uvw[1] = 0.; + last_uvw[2] = 0.; } @@ -383,7 +390,8 @@ void Mgxs::combine(std::vector& micros, double_1dvec& scalars, } -double Mgxs::get_xs(const char* xstype, int gin, int* gout, double* mu, int* dg) +double Mgxs::get_xs(const char* xstype, const int gin, int* gout, double* mu, + int* dg) { // This method assumes that the temperature and angle indices are set double val; @@ -469,7 +477,8 @@ double Mgxs::get_xs(const char* xstype, int gin, int* gout, double* mu, int* dg) } -void Mgxs::sample_fission_energy(int gin, double nu_fission, int& dg, int& gout) +void Mgxs::sample_fission_energy(const int gin, const double nu_fission, + int& dg, int& gout) { // This method assumes that the temperature and angle indices are set // Find the probability of having a prompt neutron @@ -525,8 +534,7 @@ void Mgxs::sample_fission_energy(int gin, double nu_fission, int& dg, int& gout) } -void Mgxs::sample_scatter(dir_arr& uvw, int gin, int& gout, double& mu, - double& wgt) +void Mgxs::sample_scatter(const int gin, int& gout, double& mu, double& wgt) { // This method assumes that the temperature and angle indices are set // Sample the data @@ -534,8 +542,8 @@ void Mgxs::sample_scatter(dir_arr& uvw, int gin, int& gout, double& mu, } -void Mgxs::calculate_xs(int gin, double sqrtkT, dir_arr& uvw, double& total_xs, - double& abs_xs, double& nu_fiss_xs) +void Mgxs::calculate_xs(const int gin, const double sqrtkT, const double uvw[3], + double& total_xs, double& abs_xs, double& nu_fiss_xs) { // Set our indices set_temperature_index(sqrtkT); @@ -543,10 +551,14 @@ void Mgxs::calculate_xs(int gin, double sqrtkT, dir_arr& uvw, double& total_xs, total_xs = xs[index_temp].total[index_pol][index_azi][gin]; abs_xs = xs[index_temp].absorption[index_pol][index_azi][gin]; - // nu-fission is made up of the prompt and all the delayed nu_fission data - nu_fiss_xs = xs[index_temp].prompt_nu_fission[index_pol][index_azi][gin]; - for (auto& val : xs[index_temp].delayed_nu_fission[index_pol][index_azi][gin]) { - nu_fiss_xs += val; + if (fissionable) { + // nu-fission is made up of the prompt and all the delayed nu_fission data + nu_fiss_xs = xs[index_temp].prompt_nu_fission[index_pol][index_azi][gin]; + for (auto& val : xs[index_temp].delayed_nu_fission[index_pol][index_azi][gin]) { + nu_fiss_xs += val; + } + } else { + nu_fiss_xs = 0.; } } @@ -568,7 +580,7 @@ bool Mgxs::equiv(const Mgxs& that) } -inline void Mgxs::set_temperature_index(double sqrtkT) +inline void Mgxs::set_temperature_index(const double sqrtkT) { // See if we need to find the new index if (sqrtkT != last_sqrtkT) { @@ -588,27 +600,30 @@ inline void Mgxs::set_temperature_index(double sqrtkT) } -inline void Mgxs::set_angle_index(dir_arr& uvw) +inline void Mgxs::set_angle_index(const double uvw[3]) { // See if we need to find the new index - if (uvw != last_uvw) { + if ((uvw[0] != last_uvw[0]) || (uvw[1] != last_uvw[1]) || + (uvw[2] != last_uvw[2])) { // convert uvw to polar and azimuthal angles double my_pol = std::acos(uvw[2]); double my_azi = std::atan2(uvw[1], uvw[0]); // Find the location, assuming equal-bin angles double delta_angle = PI / n_pol; - index_pol = std::floor(my_pol / delta_angle + 1.); - delta_angle = PI / n_azi; - index_azi = std::floor((my_azi + PI) / delta_angle + 1.); + index_pol = std::floor(my_pol / delta_angle); + delta_angle = 2. * PI / n_azi; + index_azi = std::floor((my_azi + PI) / delta_angle); // store this direction as the last one used - last_uvw = uvw; + last_uvw[0] = uvw[0]; + last_uvw[1] = uvw[1]; + last_uvw[2] = uvw[2]; } } //============================================================================== -// Mgxs data loading methods +// Mgxs data loading interface methods //============================================================================== void add_mgxs(hid_t file_id, char* name, int energy_groups, @@ -680,4 +695,25 @@ void create_macro_xs(char* mat_name, const int n_nuclides, macro_xs.push_back(macro); } +//============================================================================== +// Mgxs tracking/transport/tallying interface methods +//============================================================================== + +void calculate_xs(const int i_mat, const int gin, const double sqrtkT, + const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs) +{ + macro_xs[i_mat - 1].calculate_xs(gin - 1, sqrtkT, uvw, total_xs, abs_xs, + nu_fiss_xs); +} + +void scatter(const int i_mat, const int gin, int& gout, double& mu, + double& wgt, double uvw[3]) +{ + int gout_c = gout - 1; + macro_xs[i_mat - 1].sample_scatter(gin - 1, gout_c, mu, wgt); + gout = gout_c + 1; + + rotate_angle_c(uvw, mu, nullptr); +} + } // namespace openmc \ No newline at end of file diff --git a/src/mgxs.h b/src/mgxs.h index 90ed520d9a..14c4e4e89c 100644 --- a/src/mgxs.h +++ b/src/mgxs.h @@ -44,7 +44,7 @@ class Mgxs { int index_azi; double_1dvec polar; double_1dvec azimuthal; - dir_arr last_uvw; + double last_uvw[3]; void _metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, const int in_num_delayed_groups, double_1dvec& temperature, int& method, const double tolerance, int_1dvec& temps_to_read, @@ -66,16 +66,16 @@ class Mgxs { double_1dvec& temperature, int& method, double tolerance, int max_order, bool legendre_to_tabular, int legendre_to_tabular_points); - double get_xs(const char* xstype, int gin, int* gout, double* mu, + double get_xs(const char* xstype, const int gin, int* gout, double* mu, int* dg); - void sample_fission_energy(int gin, double nu_fission, int& dg, int& gout); - void sample_scatter(dir_arr& uvw, int gin, int& gout, double& mu, - double& wgt); - void calculate_xs(int gin, double sqrtkT, dir_arr& uvw, double& total_xs, - double& abs_xs, double& nu_fiss_xs); + void sample_fission_energy(const int gin, const double nu_fission, + int& dg, int& gout); + void sample_scatter(const int gin, int& gout, double& mu, double& wgt); + void calculate_xs(const int gin, const double sqrtkT, const double uvw[3], + double& total_xs, double& abs_xs, double& nu_fiss_xs); bool equiv(const Mgxs& that); - inline void set_temperature_index(double sqrtkT); - inline void set_angle_index(dir_arr& uvw); + inline void set_temperature_index(const double sqrtkT); + inline void set_angle_index(const double uvw[3]); }; extern "C" void add_mgxs(hid_t file_id, char* name, int energy_groups, @@ -89,6 +89,13 @@ extern "C" void create_macro_xs(char* mat_name, const int n_nuclides, const int i_nuclides[], const int n_temps, const double temps[], const double atom_densities[], int& method, const double tolerance); +extern "C" void calculate_xs(const int i_mat, const int gin, + const double sqrtkT, const double uvw[3], double& total_xs, + double& abs_xs, double& nu_fiss_xs); + +extern "C" void scatter(const int i_mat, const int gin, int& gout, double& mu, + double& wgt, double uvw[3]); + // Storage for the MGXS data std::vector nuclides_MG; diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index ebabe5cdbc..94aa1928ad 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -166,10 +166,10 @@ module nuclide_header !=============================================================================== type MaterialMacroXS - real(8) :: total ! macroscopic total xs - real(8) :: absorption ! macroscopic absorption xs - real(8) :: fission ! macroscopic fission xs - real(8) :: nu_fission ! macroscopic production xs + real(C_DOUBLE) :: total ! macroscopic total xs + real(C_DOUBLE) :: absorption ! macroscopic absorption xs + real(C_DOUBLE) :: fission ! macroscopic fission xs + real(C_DOUBLE) :: nu_fission ! macroscopic production xs end type MaterialMacroXS !=============================================================================== diff --git a/src/physics_mg.F90 b/src/physics_mg.F90 index eb82085941..3030fc099b 100644 --- a/src/physics_mg.F90 +++ b/src/physics_mg.F90 @@ -22,6 +22,20 @@ module physics_mg implicit none + interface + subroutine scatter_c(i_mat, gin, gout, mu, wgt, uvw) & + bind(C, name='scatter') + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: i_mat + integer(C_INT), value, intent(in) :: gin + integer(C_INT), intent(inout) :: gout + real(C_DOUBLE), intent(inout) :: mu + real(C_DOUBLE), intent(inout) :: wgt + real(C_DOUBLE), intent(inout) :: uvw(1:3) + end subroutine scatter_c + end interface + contains !=============================================================================== @@ -143,16 +157,18 @@ contains type(Particle), intent(inout) :: p - call macro_xs(p % material) % obj % sample_scatter(p % coord(1) % uvw, & - p % last_g, p % g, & - p % mu, p % wgt) + ! call macro_xs(p % material) % obj % sample_scatter(p % coord(1) % uvw, & + ! p % last_g, p % g, p % mu, p % wgt) + + ! Convert change in angle (mu) to new direction + ! p % coord(1) % uvw = rotate_angle(p % coord(1) % uvw, p % mu) + + call scatter_c(p % material, p % last_g, p % g, p % mu, p % wgt, & + p % coord(1) % uvw) ! Update energy value for downstream compatability (in tallying) p % E = energy_bin_avg(p % g) - ! Convert change in angle (mu) to new direction - p % coord(1) % uvw = rotate_angle(p % coord(1) % uvw, p % mu) - ! Set event component p % event = EVENT_SCATTER diff --git a/src/scattdata.cpp b/src/scattdata.cpp index d23169fa87..aef620ac5d 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -44,7 +44,8 @@ void ScattData::sample_energy(int gin, int& gout, int& i_gout) { // Sample the outgoing group double xi = prn(); - i_gout = 0; //TODO: + 1? + + i_gout = 0; gout = gmin[gin]; double prob = energy[gin][i_gout]; while((prob < xi) && (gout < gmax[gin])) { @@ -247,7 +248,7 @@ void ScattDataLegendre::sample(int gin, int& gout, double& mu, double& wgt) } -void ScattDataLegendre::combine(std::vector those_scatts, +void ScattDataLegendre::combine(std::vector& those_scatts, double_1dvec& scalars) { // Find the max order in the data set and make sure we can combine the sets @@ -294,6 +295,7 @@ void ScattDataLegendre::combine(std::vector those_scatts, for (int gin = 0; gin < groups; gin++) { // Only spend time adding that's gmin to gmax data since the rest will // be zeros + int i_gout = 0; for (int gout = that->gmin[gin]; gout <= that->gmax[gin]; gout++) { // Do the scattering matrix for (int l = 0; l < max_order; l++) { @@ -301,13 +303,14 @@ void ScattDataLegendre::combine(std::vector those_scatts, } // Incorporate that's contribution to the multiplicity matrix data - double nuscatt = that->scattxs[gin] * that->energy[gin][gout]; + double nuscatt = that->scattxs[gin] * that->energy[gin][i_gout]; mult_numer[gin][gout] += scalars[i] * nuscatt; - if (that->mult[gin][gout] > 0.) { - mult_denom[gin][gout] += scalars[i] * nuscatt / that->mult[gin][gout]; + if (that->mult[gin][i_gout] > 0.) { + mult_denom[gin][gout] += scalars[i] * nuscatt / that->mult[gin][i_gout]; } else { mult_denom[gin][gout] += scalars[i]; } + i_gout++; } } } @@ -336,14 +339,14 @@ void ScattDataLegendre::combine(std::vector those_scatts, for (gmin_ = 0; gmin_ < groups; gmin_++) { bool non_zero = std::all_of(this_matrix[gin][gmin_].begin(), this_matrix[gin][gmin_].end(), - [](double val){return val > 0.;}); + [](double val){return val != 0.;}); if (non_zero) break; } int gmax_; for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) { bool non_zero = std::all_of(this_matrix[gin][gmax_].begin(), this_matrix[gin][gmax_].end(), - [](double val){return val > 0.;}); + [](double val){return val != 0.;}); if (non_zero) break; } @@ -425,6 +428,7 @@ void ScattDataHistogram::init(int_1dvec& in_gmin, int_1dvec& in_gmax, for (int i_gout = 0; i_gout < num_groups; i_gout++) { double norm = std::accumulate(matrix[gin][i_gout].begin(), matrix[gin][i_gout].end(), 0.); + in_energy[gin][i_gout] = norm; if (norm != 0.) { for (auto& n : matrix[gin][i_gout]) n /= norm; } @@ -440,7 +444,7 @@ void ScattDataHistogram::init(int_1dvec& in_gmin, int_1dvec& in_gmax, dmu = 2. / order; mu[0] = -1.; for (int imu = 1; imu < order; imu++) { - mu[imu] = -1. + (imu - 1) * dmu; + mu[imu] = -1. + imu * dmu; } // Calculate f(mu) and integrate it so we can avoid rejection sampling @@ -507,7 +511,7 @@ void ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt) int imu; if (xi < dist[gin][i_gout][0]) { - imu = 1; + imu = 0; } else { // TODO lower_bound? + 1? imu = std::upper_bound(dist[gin][i_gout].begin(), @@ -551,7 +555,7 @@ double_3dvec ScattDataHistogram::get_matrix(int max_order) } -void ScattDataHistogram::combine(std::vector those_scatts, +void ScattDataHistogram::combine(std::vector& those_scatts, double_1dvec& scalars) { // Find the max order in the data set and make sure we can combine the sets @@ -600,6 +604,7 @@ void ScattDataHistogram::combine(std::vector those_scatts, for (int gin = 0; gin < groups; gin++) { // Only spend time adding that's gmin to gmax data since the rest will // be zeros + int i_gout = 0; for (int gout = that->gmin[gin]; gout <= that->gmax[gin]; gout++) { // Do the scattering matrix for (int l = 0; l < max_order; l++) { @@ -607,13 +612,14 @@ void ScattDataHistogram::combine(std::vector those_scatts, } // Incorporate that's contribution to the multiplicity matrix data - double nuscatt = that->scattxs[gin] * that->energy[gin][gout]; + double nuscatt = that->scattxs[gin] * that->energy[gin][i_gout]; mult_numer[gin][gout] += scalars[i] * nuscatt; - if (that->mult[gin][gout] > 0.) { - mult_denom[gin][gout] += scalars[i] * nuscatt / that->mult[gin][gout]; + if (that->mult[gin][i_gout] > 0.) { + mult_denom[gin][gout] += scalars[i] * nuscatt / that->mult[gin][i_gout]; } else { mult_denom[gin][gout] += scalars[i]; } + i_gout++; } } } @@ -642,14 +648,14 @@ void ScattDataHistogram::combine(std::vector those_scatts, for (gmin_ = 0; gmin_ < groups; gmin_++) { bool non_zero = std::all_of(this_matrix[gin][gmin_].begin(), this_matrix[gin][gmin_].end(), - [](double val){return val > 0.;}); + [](double val){return val != 0.;}); if (non_zero) break; } int gmax_; for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) { bool non_zero = std::all_of(this_matrix[gin][gmax_].begin(), this_matrix[gin][gmax_].end(), - [](double val){return val > 0.;}); + [](double val){return val != 0.;}); if (non_zero) break; } @@ -695,7 +701,7 @@ void ScattDataTabular::init(int_1dvec& in_gmin, int_1dvec& in_gmax, dmu = 2. / (order - 1); mu[0] = -1.; for (int imu = 1; imu < order - 1; imu++) { - mu[imu] = -1. + (imu - 1) * dmu; + mu[imu] = -1. + imu * dmu; } mu[order - 1] = 1.; @@ -724,9 +730,7 @@ void ScattDataTabular::init(int_1dvec& in_gmin, int_1dvec& in_gmax, norm += 0.5 * dmu * (matrix[gin][i_gout][imu - 1] + matrix[gin][i_gout][imu]); } - if (norm != 0.) { - for (auto& n : matrix[gin][i_gout]) n /= norm; - } + in_energy[gin][i_gout] = norm; } } @@ -806,14 +810,14 @@ void ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt) double c_k = dist[gin][i_gout][0]; int k; - for (k = 0; k < NP - 2; k++) { + for (k = 0; k < NP - 1; k++) { double c_k1 = dist[gin][i_gout][k + 1]; if (xi < c_k1) break; c_k = c_k1; } // Check to make sure k is <= NP - 1 - k = std::min(k, NP - 1); + k = std::min(k, NP - 2); // Find the pdf values we want double p0 = fmu[gin][i_gout][k]; @@ -861,7 +865,7 @@ double_3dvec ScattDataTabular::get_matrix(int max_order) return matrix; } -void ScattDataTabular::combine(std::vector those_scatts, +void ScattDataTabular::combine(std::vector& those_scatts, double_1dvec& scalars) { // Find the max order in the data set and make sure we can combine the sets @@ -910,6 +914,7 @@ void ScattDataTabular::combine(std::vector those_scatts, for (int gin = 0; gin < groups; gin++) { // Only spend time adding that's gmin to gmax data since the rest will // be zeros + int i_gout = 0; for (int gout = that->gmin[gin]; gout <= that->gmax[gin]; gout++) { // Do the scattering matrix for (int l = 0; l < max_order; l++) { @@ -917,13 +922,14 @@ void ScattDataTabular::combine(std::vector those_scatts, } // Incorporate that's contribution to the multiplicity matrix data - double nuscatt = that->scattxs[gin] * that->energy[gin][gout]; + double nuscatt = that->scattxs[gin] * that->energy[gin][i_gout]; mult_numer[gin][gout] += scalars[i] * nuscatt; - if (that->mult[gin][gout] > 0.) { - mult_denom[gin][gout] += scalars[i] * nuscatt / that->mult[gin][gout]; + if (that->mult[gin][i_gout] > 0.) { + mult_denom[gin][gout] += scalars[i] * nuscatt / that->mult[gin][i_gout]; } else { mult_denom[gin][gout] += scalars[i]; } + i_gout++; } } } @@ -952,14 +958,14 @@ void ScattDataTabular::combine(std::vector those_scatts, for (gmin_ = 0; gmin_ < groups; gmin_++) { bool non_zero = std::all_of(this_matrix[gin][gmin_].begin(), this_matrix[gin][gmin_].end(), - [](double val){return val > 0.;}); + [](double val){return val != 0.;}); if (non_zero) break; } int gmax_; for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) { bool non_zero = std::all_of(this_matrix[gin][gmax_].begin(), this_matrix[gin][gmax_].end(), - [](double val){return val > 0.;}); + [](double val){return val != 0.;}); if (non_zero) break; } diff --git a/src/scattdata.h b/src/scattdata.h index 6e24a50bc9..4553156e0d 100644 --- a/src/scattdata.h +++ b/src/scattdata.h @@ -41,7 +41,7 @@ class ScattData { double get_xs(const char* xstype, int gin, int* gout, double* mu); void generic_init(int order, int_1dvec in_gmin, int_1dvec in_gmax, double_2dvec in_energy, double_2dvec in_mult); - virtual void combine(std::vector those_scatts, + virtual void combine(std::vector& those_scatts, double_1dvec& scalars) = 0; virtual int get_order() = 0; virtual double_3dvec get_matrix(int max_order) = 0; @@ -59,7 +59,7 @@ class ScattDataLegendre: public ScattData { void update_max_val(); double calc_f(int gin, int gout, double mu); void sample(int gin, int& gout, double& mu, double& wgt); - void combine(std::vector those_scatts, double_1dvec& scalars); + void combine(std::vector& those_scatts, double_1dvec& scalars); int get_order() {return dist[0][0].size() - 1;}; double_3dvec get_matrix(int max_order); }; @@ -74,7 +74,7 @@ class ScattDataHistogram: public ScattData { double_3dvec& coeffs); double calc_f(int gin, int gout, double mu); void sample(int gin, int& gout, double& mu, double& wgt); - void combine(std::vector those_scatts, double_1dvec& scalars); + void combine(std::vector& those_scatts, double_1dvec& scalars); int get_order() {return dist[0][0].size();}; double_3dvec get_matrix(int max_order); }; @@ -91,7 +91,7 @@ class ScattDataTabular: public ScattData { double_3dvec& coeffs); double calc_f(int gin, int gout, double mu); void sample(int gin, int& gout, double& mu, double& wgt); - void combine(std::vector those_scatts, double_1dvec& scalars); + void combine(std::vector& those_scatts, double_1dvec& scalars); int get_order() {return dist[0][0].size();}; double_3dvec get_matrix(int max_order); }; diff --git a/src/tracking.F90 b/src/tracking.F90 index 3fe6a065b7..2ba62a8dd8 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -1,5 +1,7 @@ module tracking + use, intrinsic :: ISO_C_BINDING + use constants use error, only: warning, write_message use geometry_header, only: cells @@ -27,6 +29,21 @@ module tracking implicit none + interface + subroutine calculate_xs_c(i_mat, gin, sqrtkT, uvw, total_xs, abs_xs, & + nu_fiss_xs) bind(C, name='calculate_xs') + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: i_mat + integer(C_INT), value, intent(in) :: gin + real(C_DOUBLE), value, intent(in) :: sqrtkT + real(C_DOUBLE), intent(in) :: uvw(1:3) + real(C_DOUBLE), intent(inout) :: total_xs + real(C_DOUBLE), intent(inout) :: abs_xs + real(C_DOUBLE), intent(inout) :: nu_fiss_xs + end subroutine calculate_xs_c + end interface + contains !=============================================================================== @@ -112,8 +129,14 @@ contains end if else ! Get the MG data + !!TODO: Remove Fortran call - needed until I'm done replacing Fortran + !!with C++ code because it sets index_temp call macro_xs(p % material) % obj % calculate_xs(p % g, p % sqrtkT, & p % coord(p % n_coord) % uvw, material_xs) + call calculate_xs_c(p % material, p % g, p % sqrtkT, & + p % coord(p % n_coord) % uvw, material_xs % total, & + material_xs % absorption, material_xs % nu_fission) + ! Finally, update the particle group while we have already checked ! for if multi-group From b1c73918a8f111f3f3b5e7b2e240b57403c1d2d8 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Wed, 13 Jun 2018 20:22:51 -0400 Subject: [PATCH 020/100] It works! Replaced all mgxs_header functionality with the C++ version and a mgxs_interface module to act as the go-between the C++ and Fortran --- CMakeLists.txt | 5 +- src/api.F90 | 2 - src/cmfd_input.F90 | 4 +- src/constants.F90 | 19 ++ src/constants.h | 17 ++ src/input_xml.F90 | 10 +- src/mgxs.cpp | 265 +++++++----------- src/mgxs.h | 47 +--- src/mgxs_data.F90 | 414 +++++++++++++--------------- src/mgxs_header.F90 | 1 - src/mgxs_interface.F90 | 201 ++++++++++++++ src/mgxs_interface.cpp | 247 +++++++++++++++++ src/mgxs_interface.h | 66 +++++ src/output.F90 | 6 +- src/particle_restart.F90 | 2 +- src/physics_mg.F90 | 33 +-- src/scattdata.cpp | 46 ++-- src/scattdata.h | 2 +- src/simulation.F90 | 2 +- src/source.F90 | 2 +- src/state_point.F90 | 11 +- src/string_functions.cpp | 30 ++ src/string_functions.h | 31 +-- src/summary.F90 | 24 +- src/tallies/tally.F90 | 259 +++++++++-------- src/tallies/tally_filter_energy.F90 | 2 +- src/tracking.F90 | 21 +- src/xsdata.cpp | 15 + src/xsdata.h | 1 + 29 files changed, 1111 insertions(+), 674 deletions(-) create mode 100644 src/mgxs_interface.F90 create mode 100644 src/mgxs_interface.cpp create mode 100644 src/mgxs_interface.h create mode 100644 src/string_functions.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 362e98a830..a13f30b575 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -363,7 +363,7 @@ set(LIBOPENMC_FORTRAN_SRC src/mesh_header.F90 src/message_passing.F90 src/mgxs_data.F90 - src/mgxs_header.F90 + src/mgxs_interface.F90 src/multipole_header.F90 src/nuclide_header.F90 src/output.F90 @@ -380,7 +380,6 @@ set(LIBOPENMC_FORTRAN_SRC src/reaction_header.F90 src/relaxng src/sab_header.F90 - src/scattdata_header.F90 src/secondary_correlated.F90 src/secondary_kalbach.F90 src/secondary_nbody.F90 @@ -439,11 +438,13 @@ set(LIBOPENMC_CXX_SRC src/math_functions.cpp src/message_passing.cpp src/mgxs.cpp + src/mgxs_interface.cpp src/plot.cpp src/random_lcg.cpp src/scattdata.cpp src/simulation.cpp src/state_point.cpp + src/string_functions.cpp src/surface.cpp src/xml_interface.cpp src/xsdata.cpp diff --git a/src/api.F90 b/src/api.F90 index da50007d68..f32de6bebb 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -309,7 +309,6 @@ contains subroutine free_memory() use cmfd_header - use mgxs_header use plot_header use sab_header use settings @@ -327,7 +326,6 @@ contains call free_memory_simulation() call free_memory_nuclide() call free_memory_settings() - call free_memory_mgxs() call free_memory_sab() call free_memory_source() call free_memory_mesh() diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index 549cff4191..1e4b8f3742 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -3,8 +3,8 @@ module cmfd_input use, intrinsic :: ISO_C_BINDING use cmfd_header - use mesh_header, only: mesh_dict - use mgxs_header, only: energy_bins + use mesh_header, only: mesh_dict + use mgxs_interface, only: energy_bins, num_energy_groups use tally use tally_header use timer_header diff --git a/src/constants.F90 b/src/constants.F90 index d1893bf9e1..430cc27151 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -402,6 +402,25 @@ module constants DIFF_NUCLIDE_DENSITY = 2, & DIFF_TEMPERATURE = 3 + + ! Mgxs::get_xs enumerated types + integer(C_INT), parameter :: & + MG_GET_XS_TOTAL = 0, & + MG_GET_XS_ABSORPTION = 1, & + MG_GET_XS_INVERSE_VELOCITY = 2, & + MG_GET_XS_DECAY_RATE = 3, & + MG_GET_XS_SCATTER = 4, & + MG_GET_XS_SCATTER_MULT = 5, & + MG_GET_XS_SCATTER_FMU_MULT = 6, & + MG_GET_XS_SCATTER_FMU = 7, & + MG_GET_XS_FISSION = 8, & + MG_GET_XS_KAPPA_FISSION = 9, & + MG_GET_XS_PROMPT_NU_FISSION = 10, & + MG_GET_XS_DELAYED_NU_FISSION = 11, & + MG_GET_XS_NU_FISSION = 12, & + MG_GET_XS_CHI_PROMPT = 13, & + MG_GET_XS_CHI_DELAYED = 14 + ! ============================================================================ ! RANDOM NUMBER STREAM CONSTANTS diff --git a/src/constants.h b/src/constants.h index 8290aa8c9c..3ddadb5a10 100644 --- a/src/constants.h +++ b/src/constants.h @@ -63,6 +63,23 @@ constexpr double PI {3.1415926535898}; const double SQRT_PI {std::sqrt(PI)}; +// Mgxs::get_xs enumerated types +constexpr int MG_GET_XS_TOTAL {0}; +constexpr int MG_GET_XS_ABSORPTION {1}; +constexpr int MG_GET_XS_INVERSE_VELOCITY {2}; +constexpr int MG_GET_XS_DECAY_RATE {3}; +constexpr int MG_GET_XS_SCATTER {4}; +constexpr int MG_GET_XS_SCATTER_MULT {5}; +constexpr int MG_GET_XS_SCATTER_FMU_MULT {6}; +constexpr int MG_GET_XS_SCATTER_FMU {7}; +constexpr int MG_GET_XS_FISSION {8}; +constexpr int MG_GET_XS_KAPPA_FISSION {9}; +constexpr int MG_GET_XS_PROMPT_NU_FISSION {10}; +constexpr int MG_GET_XS_DELAYED_NU_FISSION {11}; +constexpr int MG_GET_XS_NU_FISSION {12}; +constexpr int MG_GET_XS_CHI_PROMPT {13}; +constexpr int MG_GET_XS_CHI_DELAYED {14}; + } // namespace openmc diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 507bdf8a9c..189ca7c212 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -19,8 +19,8 @@ module input_xml use material_header use mesh_header use message_passing - use mgxs_data, only: create_macro_xs, read_mgxs, read_mgxs2, create_macro_xs2 - use mgxs_header + use mgxs_data, only: create_macro_xs, read_mgxs + use mgxs_interface use nuclide_header use output, only: title, header, print_plot use plot_header @@ -84,9 +84,7 @@ contains else ! Create material macroscopic data for MGXS call read_mgxs() - call read_mgxs2() call create_macro_xs() - call create_macro_xs2() end if call time_read_xs % stop() end if @@ -3856,7 +3854,7 @@ contains if (run_CE) then awr = nuclides(mat % nuclide(j)) % awr else - awr = nuclides_MG(mat % nuclide(j)) % obj % awr + awr = get_awr_c(mat % nuclide(j)) end if ! if given weight percent, convert all values so that they are divided @@ -3881,7 +3879,7 @@ contains if (run_CE) then awr = nuclides(mat % nuclide(j)) % awr else - awr = nuclides_MG(mat % nuclide(j)) % obj % awr + awr = get_awr_c(mat % nuclide(j)) end if x = mat % atom_density(j) sum_percent = sum_percent + x*awr diff --git a/src/mgxs.cpp b/src/mgxs.cpp index ec711e1307..4f92a64eee 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -2,6 +2,11 @@ namespace openmc { +// Storage for the MGXS data +std::vector nuclides_MG; +std::vector macro_xs; + + //============================================================================== // Mgxs base-class methods //============================================================================== @@ -390,112 +395,149 @@ void Mgxs::combine(std::vector& micros, double_1dvec& scalars, } -double Mgxs::get_xs(const char* xstype, const int gin, int* gout, double* mu, +double Mgxs::get_xs(const int xstype, const int gin, int* gout, double* mu, int* dg) { // This method assumes that the temperature and angle indices are set double val; - if (std::strcmp(xstype, "total")) { + switch(xstype) { + case MG_GET_XS_TOTAL: val = xs[index_temp].total[index_pol][index_azi][gin]; - } else if (std::strcmp(xstype, "absorption")) { + break; + case MG_GET_XS_ABSORPTION: val = xs[index_temp].absorption[index_pol][index_azi][gin]; - } else if (std::strcmp(xstype, "inverse-velocity")) { + break; + case MG_GET_XS_INVERSE_VELOCITY: val = xs[index_temp].inverse_velocity[index_pol][index_azi][gin]; - } else if (std::strcmp(xstype, "decay rate")) { + break; + case MG_GET_XS_DECAY_RATE: if (dg != nullptr) { val = xs[index_temp].decay_rate[index_pol][index_azi][*dg + 1]; } else { val = xs[index_temp].decay_rate[index_pol][index_azi][0]; } - } else if ((std::strcmp(xstype, "scatter")) || - (std::strcmp(xstype, "scatter/mult")) || - (std::strcmp(xstype, "scatter*f_mu/mult")) || - (std::strcmp(xstype, "scatter*f_mu"))) { + break; + case MG_GET_XS_SCATTER: + case MG_GET_XS_SCATTER_MULT: + case MG_GET_XS_SCATTER_FMU_MULT: + case MG_GET_XS_SCATTER_FMU: val = xs[index_temp].scatter[index_pol] [index_azi]->get_xs(xstype, gin, gout, mu); - } else if (fissionable && std::strcmp(xstype, "fission")) { - val = xs[index_temp].fission[index_pol][index_azi][gin]; - } else if (fissionable && std::strcmp(xstype, "kappa-fission")) { - val = xs[index_temp].kappa_fission[index_pol][index_azi][gin]; - } else if (fissionable && std::strcmp(xstype, "prompt-nu-fission")) { - val = xs[index_temp].prompt_nu_fission[index_pol][index_azi][gin]; - } else if (fissionable && std::strcmp(xstype, "delayed-nu-fission")) { - if (dg != nullptr) { - val = xs[index_temp].delayed_nu_fission[index_pol][index_azi][gin][*dg]; + break; + case MG_GET_XS_FISSION: + if (fissionable) { + val = xs[index_temp].fission[index_pol][index_azi][gin]; } else { val = 0.; - for (auto& num : xs[index_temp].delayed_nu_fission[index_pol] - [index_azi][gin]) { - val += num; - } } - } else if (fissionable && std::strcmp(xstype, "nu-fission")) { - val = xs[index_temp].prompt_nu_fission[index_pol][index_azi][gin]; - for (auto& num : xs[index_temp].delayed_nu_fission[index_pol] - [index_azi][gin]) { - val += num; - } - } else if (fissionable && std::strcmp(xstype, "chi-prompt")) { - if (gout != nullptr) { - val = xs[index_temp].chi_prompt[index_pol][index_azi][gin][*gout]; + break; + case MG_GET_XS_KAPPA_FISSION: + if (fissionable) { + val = xs[index_temp].kappa_fission[index_pol][index_azi][gin]; } else { - // provide an outgoing group-wise sum val = 0.; - for (auto& num : xs[index_temp].chi_prompt[index_pol][index_azi][gin]) { - val += num; - } } - } else if (fissionable && std::strcmp(xstype, "chi-delayed")) { - if (gout != nullptr) { + break; + case MG_GET_XS_PROMPT_NU_FISSION: + if (fissionable) { + val = xs[index_temp].prompt_nu_fission[index_pol][index_azi][gin]; + } else { + val = 0.; + } + break; + case MG_GET_XS_DELAYED_NU_FISSION: + if (fissionable) { if (dg != nullptr) { - val = xs[index_temp].chi_delayed[index_pol][index_azi][gin][*gout][*dg]; + val = xs[index_temp].delayed_nu_fission[index_pol][index_azi][gin][*dg]; } else { - val = xs[index_temp].chi_delayed[index_pol][index_azi][gin][*gout][0]; + val = 0.; + for (auto& num : xs[index_temp].delayed_nu_fission[index_pol] + [index_azi][gin]) { + val += num; + } } } else { - if (dg != nullptr) { + val = 0.; + } + break; + case MG_GET_XS_NU_FISSION: + if (fissionable) { + val = xs[index_temp].nu_fission[index_pol][index_azi][gin]; + } else { + val = 0.; + } + break; + case MG_GET_XS_CHI_PROMPT: + if (fissionable) { + if (gout != nullptr) { + val = xs[index_temp].chi_prompt[index_pol][index_azi][gin][*gout]; + } else { + // provide an outgoing group-wise sum val = 0.; - for (int i = 0; i < xs[index_temp].chi_delayed[index_pol] - [index_azi][gin].size(); i++) { - val += xs[index_temp].chi_delayed[index_pol][index_azi][gin][i][*dg]; + for (auto& num : xs[index_temp].chi_prompt[index_pol][index_azi][gin]) { + val += num; + } + } + } else { + val = 0.; + } + break; + case MG_GET_XS_CHI_DELAYED: + if (fissionable) { + if (gout != nullptr) { + if (dg != nullptr) { + val = xs[index_temp].chi_delayed[index_pol][index_azi][gin][*gout][*dg]; + } else { + val = xs[index_temp].chi_delayed[index_pol][index_azi][gin][*gout][0]; } } else { - val = 0.; - for (int i = 0; i < xs[index_temp].chi_delayed[index_pol] - [index_azi][gin].size(); i++) { - for (auto& num : xs[index_temp].chi_delayed[index_pol] - [index_azi][gin][i]) { - val += num; + if (dg != nullptr) { + val = 0.; + for (int i = 0; i < xs[index_temp].chi_delayed[index_pol] + [index_azi][gin].size(); i++) { + val += xs[index_temp].chi_delayed[index_pol][index_azi][gin][i][*dg]; + } + } else { + val = 0.; + for (int i = 0; i < xs[index_temp].chi_delayed[index_pol] + [index_azi][gin].size(); i++) { + for (auto& num : xs[index_temp].chi_delayed[index_pol] + [index_azi][gin][i]) { + val += num; + } } } } + } else { + val = 0.; } - } else { + break; + default: val = 0.; } return val; } -void Mgxs::sample_fission_energy(const int gin, const double nu_fission, - int& dg, int& gout) +void Mgxs::sample_fission_energy(const int gin, int& dg, int& gout) { // This method assumes that the temperature and angle indices are set + double nu_fission = xs[index_temp].nu_fission[index_pol][index_azi][gin]; + // Find the probability of having a prompt neutron double prob_prompt = - xs[index_temp].prompt_nu_fission[index_pol][index_azi][gin] / - nu_fission; + xs[index_temp].prompt_nu_fission[index_pol][index_azi][gin]; // sample random numbers - double xi_pd = prn(); + double xi_pd = prn() * nu_fission; double xi_gout = prn(); // Select whether the neutron is prompt or delayed if (xi_pd <= prob_prompt) { // the neutron is prompt - // set the delayed group for the particle to be 0, indicating prompt - dg = 0; + // set the delayed group for the particle to be -1, indicating prompt + dg = -1; // sample the outgoing energy group gout = 0; @@ -514,12 +556,11 @@ void Mgxs::sample_fission_energy(const int gin, const double nu_fission, while (xi_pd >= prob_prompt) { dg++; prob_prompt += - xs[index_temp].delayed_nu_fission[index_pol][index_azi][gin][dg] / - nu_fission; + xs[index_temp].delayed_nu_fission[index_pol][index_azi][gin][dg]; } // adjust dg in case of round-off error - dg = std::min(dg, num_delayed_groups); + dg = std::min(dg, num_delayed_groups - 1); // sample the outgoing energy group gout = 0; @@ -552,11 +593,7 @@ void Mgxs::calculate_xs(const int gin, const double sqrtkT, const double uvw[3], abs_xs = xs[index_temp].absorption[index_pol][index_azi][gin]; if (fissionable) { - // nu-fission is made up of the prompt and all the delayed nu_fission data - nu_fiss_xs = xs[index_temp].prompt_nu_fission[index_pol][index_azi][gin]; - for (auto& val : xs[index_temp].delayed_nu_fission[index_pol][index_azi][gin]) { - nu_fiss_xs += val; - } + nu_fiss_xs = xs[index_temp].nu_fission[index_pol][index_azi][gin]; } else { nu_fiss_xs = 0.; } @@ -580,7 +617,7 @@ bool Mgxs::equiv(const Mgxs& that) } -inline void Mgxs::set_temperature_index(const double sqrtkT) +void Mgxs::set_temperature_index(const double sqrtkT) { // See if we need to find the new index if (sqrtkT != last_sqrtkT) { @@ -600,7 +637,7 @@ inline void Mgxs::set_temperature_index(const double sqrtkT) } -inline void Mgxs::set_angle_index(const double uvw[3]) +void Mgxs::set_angle_index(const double uvw[3]) { // See if we need to find the new index if ((uvw[0] != last_uvw[0]) || (uvw[1] != last_uvw[1]) || @@ -622,98 +659,4 @@ inline void Mgxs::set_angle_index(const double uvw[3]) } } -//============================================================================== -// Mgxs data loading interface methods -//============================================================================== - -void add_mgxs(hid_t file_id, char* name, int energy_groups, - int delayed_groups, int n_temps, double temps[], int& method, - double tolerance, int max_order, bool legendre_to_tabular, - int legendre_to_tabular_points) -{ - //!! mgxs_data.F90 will be modified to just create the list of names - //!! in the order needed - // Convert temps to a vector for the from_hdf5 function - double_1dvec temperature; - temperature.assign(temps, temps + n_temps); - - // TODO: C++ replacement for write_message - // write_message("Loading " + std::string(names[i]) + " data...", 6); - - // Check to make sure cross section set exists in the library - hid_t xs_grp; - if (object_exists(file_id, name)) { - xs_grp = open_group(file_id, name); - } else { - fatal_error("Data for " + std::string(name) + " does not exist in " - + "provided MGXS Library"); - } - - Mgxs mg; - mg.from_hdf5(xs_grp, energy_groups, delayed_groups, - temperature, method, tolerance, max_order, legendre_to_tabular, - legendre_to_tabular_points); - - nuclides_MG.push_back(mg); -} - - -bool query_fissionable(const int n_nuclides, const int i_nuclides[]) -{ - bool result = false; - for (int n = 0; n < n_nuclides; n++) { - if (nuclides_MG[i_nuclides[n] - 1].fissionable) result = true; - } - return result; -} - - -void create_macro_xs(char* mat_name, const int n_nuclides, - const int i_nuclides[], const int n_temps, const double temps[], - const double atom_densities[], int& method, const double tolerance) -{ - Mgxs macro; - if (n_temps > 0) { - // // Convert temps to a vector - double_1dvec temperature; - temperature.assign(temps, temps + n_temps); - - // Convert atom_densities to a vector - double_1dvec atom_densities_vec; - atom_densities_vec.assign(atom_densities, atom_densities + n_nuclides); - - // Build array of pointers to nuclides_MG's Mgxs objects needed for this - // material - std::vector mgxs_ptr(n_nuclides); - for (int n = 0; n < n_nuclides; n++) { - mgxs_ptr[n] = &nuclides_MG[i_nuclides[n] - 1]; - } - - macro.build_macro(mat_name, temperature, mgxs_ptr, atom_densities_vec, - method, tolerance); - } - macro_xs.push_back(macro); -} - -//============================================================================== -// Mgxs tracking/transport/tallying interface methods -//============================================================================== - -void calculate_xs(const int i_mat, const int gin, const double sqrtkT, - const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs) -{ - macro_xs[i_mat - 1].calculate_xs(gin - 1, sqrtkT, uvw, total_xs, abs_xs, - nu_fiss_xs); -} - -void scatter(const int i_mat, const int gin, int& gout, double& mu, - double& wgt, double uvw[3]) -{ - int gout_c = gout - 1; - macro_xs[i_mat - 1].sample_scatter(gin - 1, gout_c, mu, wgt); - gout = gout_c + 1; - - rotate_angle_c(uvw, mu, nullptr); -} - } // namespace openmc \ No newline at end of file diff --git a/src/mgxs.h b/src/mgxs.h index 14c4e4e89c..2fc3e2bec2 100644 --- a/src/mgxs.h +++ b/src/mgxs.h @@ -29,29 +29,31 @@ namespace openmc { class Mgxs { private: - std::string name; // name of dataset, e.g., UO2 - double awr; // atomic weight ratio double_1dvec kTs; // temperature in eV (k * T) int scatter_format; // flag for if this is legendre, histogram, or tabular int num_delayed_groups; // number of delayed neutron groups int num_groups; // number of energy groups - int index_temp; // cache of temperature index double last_sqrtkT; // cache of the temperature corresponding to index_temp std::vector xs; // Cross section data int n_pol; int n_azi; - int index_pol; // cache fof the angle indices - int index_azi; double_1dvec polar; double_1dvec azimuthal; - double last_uvw[3]; void _metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, const int in_num_delayed_groups, double_1dvec& temperature, int& method, const double tolerance, int_1dvec& temps_to_read, int& order_dim, bool& is_isotropic); + bool equiv(const Mgxs& that); public: + std::string name; // name of dataset, e.g., UO2 + double awr; // atomic weight ratio bool fissionable; // Is this fissionable + // TODO: The following attributes be private when Fortran is fully replaced + int index_pol; // cache for the angle indices + int index_azi; + double last_uvw[3]; // cache of the angle corresponding to the above indices + int index_temp; // cache of temperature index void init(const std::string& in_name, const double in_awr, const double_1dvec& in_kTs, const bool in_fissionable, const int in_scatter_format, const int in_num_groups, @@ -66,40 +68,15 @@ class Mgxs { double_1dvec& temperature, int& method, double tolerance, int max_order, bool legendre_to_tabular, int legendre_to_tabular_points); - double get_xs(const char* xstype, const int gin, int* gout, double* mu, + double get_xs(const int xstype, const int gin, int* gout, double* mu, int* dg); - void sample_fission_energy(const int gin, const double nu_fission, - int& dg, int& gout); + void sample_fission_energy(const int gin, int& dg, int& gout); void sample_scatter(const int gin, int& gout, double& mu, double& wgt); void calculate_xs(const int gin, const double sqrtkT, const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs); - bool equiv(const Mgxs& that); - inline void set_temperature_index(const double sqrtkT); - inline void set_angle_index(const double uvw[3]); + void set_temperature_index(const double sqrtkT); + void set_angle_index(const double uvw[3]); }; -extern "C" void add_mgxs(hid_t file_id, char* name, int energy_groups, - int delayed_groups, int n_temps, double temps[], int& method, - double tolerance, int max_order, bool legendre_to_tabular, - int legendre_to_tabular_points); - -extern "C" bool query_fissionable(const int n_nuclides, const int i_nuclides[]); - -extern "C" void create_macro_xs(char* mat_name, const int n_nuclides, - const int i_nuclides[], const int n_temps, const double temps[], - const double atom_densities[], int& method, const double tolerance); - -extern "C" void calculate_xs(const int i_mat, const int gin, - const double sqrtkT, const double uvw[3], double& total_xs, - double& abs_xs, double& nu_fiss_xs); - -extern "C" void scatter(const int i_mat, const int gin, int& gout, double& mu, - double& wgt, double uvw[3]); - - -// Storage for the MGXS data -std::vector nuclides_MG; -std::vector macro_xs; - } // namespace openmc #endif // MGXS_H \ No newline at end of file diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index 6977378801..0278c96eb6 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -9,7 +9,7 @@ module mgxs_data use geometry_header, only: get_temperatures, cells use hdf5_interface use material_header, only: Material, materials, n_materials - use mgxs_header + use mgxs_interface use nuclide_header, only: n_nuclides use set_header, only: SetChar use settings @@ -17,50 +17,6 @@ module mgxs_data use string, only: to_lower implicit none - interface - subroutine add_mgxs_c(file_id, name, energy_groups, delayed_groups, & - n_temps, temps, method, tolerance, max_order, legendre_to_tabular, & - legendre_to_tabular_points) bind(C, name='add_mgxs') - use ISO_C_BINDING - import HID_T - implicit none - integer(HID_T), value, intent(in) :: file_id - character(kind=C_CHAR),intent(in) :: name(*) - integer(C_INT), value, intent(in) :: energy_groups - integer(C_INT), value, intent(in) :: delayed_groups - integer(C_INT), value, intent(in) :: n_temps - real(C_DOUBLE), intent(in) :: temps(1:n_temps) - integer(C_INT), intent(inout) :: method - real(C_DOUBLE), value, intent(in) :: tolerance - integer(C_INT), value, intent(in) :: max_order - logical(C_BOOL),value, intent(in) :: legendre_to_tabular - integer(C_INT), value, intent(in) :: legendre_to_tabular_points - end subroutine add_mgxs_c - - function query_fissionable_c(n_nuclides, i_nuclides) result(result) & - bind(C, name='query_fissionable') - use ISO_C_BINDING - implicit none - integer(C_INT), value, intent(in) :: n_nuclides - integer(C_INT), intent(in) :: i_nuclides(1:n_nuclides) - logical(C_BOOL) :: result - end function query_fissionable_c - - subroutine create_macro_xs_c(name, n_nuclides, i_nuclides, n_temps, temps, & - atom_densities, method, tolerance) bind(C, name='create_macro_xs') - use ISO_C_BINDING - implicit none - character(kind=C_CHAR),intent(in) :: name(*) - integer(C_INT), value, intent(in) :: n_nuclides - integer(C_INT), intent(in) :: i_nuclides(1:n_nuclides) - integer(C_INT), value, intent(in) :: n_temps - real(C_DOUBLE), intent(in) :: temps(1:n_temps) - real(C_DOUBLE), intent(in) :: atom_densities(1:n_nuclides) - integer(C_INT), intent(inout) :: method - real(C_DOUBLE), value, intent(in) :: tolerance - end subroutine create_macro_xs_c - end interface - contains !=============================================================================== @@ -68,150 +24,150 @@ contains ! nuclides and sab_tables arrays !=============================================================================== + ! subroutine read_mgxs() + ! integer :: i ! index in materials array + ! integer :: j ! index over nuclides in material + ! integer :: i_nuclide ! index in nuclides array + ! character(20) :: name ! name of library to load + ! integer :: representation ! Data representation + ! character(MAX_LINE_LEN) :: temp_str + ! type(Material), pointer :: mat + ! type(SetChar) :: already_read + ! integer(HID_T) :: file_id + ! integer(HID_T) :: xsdata_group + ! logical :: file_exists + ! type(VectorReal), allocatable :: temps(:) + ! character(MAX_WORD_LEN) :: word + ! integer, allocatable :: array(:) + + ! ! Check if MGXS Library exists + ! inquire(FILE=path_cross_sections, EXIST=file_exists) + ! if (.not. file_exists) then + + ! ! Could not find MGXS Library file + ! call fatal_error("Cross sections HDF5 file '" & + ! // trim(path_cross_sections) // "' does not exist!") + ! end if + + ! call write_message("Loading cross section data...", 5) + + ! ! Get temperatures + ! call get_temperatures(temps) + + ! ! Open file for reading + ! file_id = file_open(path_cross_sections, 'r', parallel=.true.) + + ! ! Read filetype + ! call read_attribute(word, file_id, "filetype") + ! if (word /= 'mgxs') then + ! call fatal_error("Provided MGXS Library is not a MGXS Library file.") + ! end if + + ! ! Read revision number for the MGXS Library file and make sure it matches + ! ! with the current version + ! call read_attribute(array, file_id, "version") + ! if (any(array /= VERSION_MGXS_LIBRARY)) then + ! call fatal_error("MGXS Library file version does not match current & + ! &version supported by OpenMC.") + ! end if + + ! ! allocate arrays for MGXS storage and cross section cache + ! allocate(nuclides_MG(n_nuclides)) + + ! ! ========================================================================== + ! ! READ ALL MGXS CROSS SECTION TABLES + + ! ! Loop over all files + ! MATERIAL_LOOP: do i = 1, n_materials + ! mat => materials(i) + + ! NUCLIDE_LOOP: do j = 1, mat % n_nuclides + ! name = mat % names(j) + + ! if (.not. already_read % contains(name)) then + ! i_nuclide = mat % nuclide(j) + + ! call write_message("Loading " // trim(name) // " data...", 6) + + ! ! Check to make sure cross section set exists in the library + ! if (object_exists(file_id, trim(name))) then + ! xsdata_group = open_group(file_id, trim(name)) + ! else + ! call fatal_error("Data for '" // trim(name) // "' does not exist in "& + ! &// trim(path_cross_sections)) + ! end if + + ! ! First find out the data representation + ! if (attribute_exists(xsdata_group, "representation")) then + + ! call read_attribute(temp_str, xsdata_group, "representation") + + ! if (trim(temp_str) == 'isotropic') then + ! representation = MGXS_ISOTROPIC + ! else if (trim(temp_str) == 'angle') then + ! representation = MGXS_ANGLE + ! else + ! call fatal_error("Invalid Data Representation!") + ! end if + ! else + ! ! Default to isotropic representation + ! representation = MGXS_ISOTROPIC + ! end if + + ! ! Now allocate accordingly + ! select case(representation) + + ! case(MGXS_ISOTROPIC) + ! allocate(MgxsIso :: nuclides_MG(i_nuclide) % obj) + + ! case(MGXS_ANGLE) + ! allocate(MgxsAngle :: nuclides_MG(i_nuclide) % obj) + + ! end select + + ! ! Now read in the data specific to the type we just declared + ! call nuclides_MG(i_nuclide) % obj % from_hdf5(xsdata_group, & + ! num_energy_groups, num_delayed_groups, temps(i_nuclide), & + ! temperature_method, temperature_tolerance, max_order, & + ! legendre_to_tabular, legendre_to_tabular_points) + + ! ! Add name to dictionary + ! call already_read % add(name) + + ! call close_group(xsdata_group) + + ! end if + ! end do NUCLIDE_LOOP + ! end do MATERIAL_LOOP + + ! ! Avoid some valgrind leak errors + ! call already_read % clear() + + ! ! Loop around material + ! MATERIAL_LOOP3: do i = 1, n_materials + + ! ! Get material + ! mat => materials(i) + + ! ! Loop around nuclides in material + ! NUCLIDE_LOOP2: do j = 1, mat % n_nuclides + + ! ! Is this fissionable? + ! if (nuclides_MG(mat % nuclide(j)) % obj % fissionable) then + ! mat % fissionable = .true. + ! end if + ! if (mat % fissionable) then + ! exit NUCLIDE_LOOP2 + ! end if + + ! end do NUCLIDE_LOOP2 + ! end do MATERIAL_LOOP3 + + ! call file_close(file_id) + + ! end subroutine read_mgxs + subroutine read_mgxs() - integer :: i ! index in materials array - integer :: j ! index over nuclides in material - integer :: i_nuclide ! index in nuclides array - character(20) :: name ! name of library to load - integer :: representation ! Data representation - character(MAX_LINE_LEN) :: temp_str - type(Material), pointer :: mat - type(SetChar) :: already_read - integer(HID_T) :: file_id - integer(HID_T) :: xsdata_group - logical :: file_exists - type(VectorReal), allocatable :: temps(:) - character(MAX_WORD_LEN) :: word - integer, allocatable :: array(:) - - ! Check if MGXS Library exists - inquire(FILE=path_cross_sections, EXIST=file_exists) - if (.not. file_exists) then - - ! Could not find MGXS Library file - call fatal_error("Cross sections HDF5 file '" & - // trim(path_cross_sections) // "' does not exist!") - end if - - call write_message("Loading cross section data...", 5) - - ! Get temperatures - call get_temperatures(temps) - - ! Open file for reading - file_id = file_open(path_cross_sections, 'r', parallel=.true.) - - ! Read filetype - call read_attribute(word, file_id, "filetype") - if (word /= 'mgxs') then - call fatal_error("Provided MGXS Library is not a MGXS Library file.") - end if - - ! Read revision number for the MGXS Library file and make sure it matches - ! with the current version - call read_attribute(array, file_id, "version") - if (any(array /= VERSION_MGXS_LIBRARY)) then - call fatal_error("MGXS Library file version does not match current & - &version supported by OpenMC.") - end if - - ! allocate arrays for MGXS storage and cross section cache - allocate(nuclides_MG(n_nuclides)) - - ! ========================================================================== - ! READ ALL MGXS CROSS SECTION TABLES - - ! Loop over all files - MATERIAL_LOOP: do i = 1, n_materials - mat => materials(i) - - NUCLIDE_LOOP: do j = 1, mat % n_nuclides - name = mat % names(j) - - if (.not. already_read % contains(name)) then - i_nuclide = mat % nuclide(j) - - call write_message("Loading " // trim(name) // " data...", 6) - - ! Check to make sure cross section set exists in the library - if (object_exists(file_id, trim(name))) then - xsdata_group = open_group(file_id, trim(name)) - else - call fatal_error("Data for '" // trim(name) // "' does not exist in "& - &// trim(path_cross_sections)) - end if - - ! First find out the data representation - if (attribute_exists(xsdata_group, "representation")) then - - call read_attribute(temp_str, xsdata_group, "representation") - - if (trim(temp_str) == 'isotropic') then - representation = MGXS_ISOTROPIC - else if (trim(temp_str) == 'angle') then - representation = MGXS_ANGLE - else - call fatal_error("Invalid Data Representation!") - end if - else - ! Default to isotropic representation - representation = MGXS_ISOTROPIC - end if - - ! Now allocate accordingly - select case(representation) - - case(MGXS_ISOTROPIC) - allocate(MgxsIso :: nuclides_MG(i_nuclide) % obj) - - case(MGXS_ANGLE) - allocate(MgxsAngle :: nuclides_MG(i_nuclide) % obj) - - end select - - ! Now read in the data specific to the type we just declared - call nuclides_MG(i_nuclide) % obj % from_hdf5(xsdata_group, & - num_energy_groups, num_delayed_groups, temps(i_nuclide), & - temperature_method, temperature_tolerance, max_order, & - legendre_to_tabular, legendre_to_tabular_points) - - ! Add name to dictionary - call already_read % add(name) - - call close_group(xsdata_group) - - end if - end do NUCLIDE_LOOP - end do MATERIAL_LOOP - - ! Avoid some valgrind leak errors - call already_read % clear() - - ! Loop around material - MATERIAL_LOOP3: do i = 1, n_materials - - ! Get material - mat => materials(i) - - ! Loop around nuclides in material - NUCLIDE_LOOP2: do j = 1, mat % n_nuclides - - ! Is this fissionable? - if (nuclides_MG(mat % nuclide(j)) % obj % fissionable) then - mat % fissionable = .true. - end if - if (mat % fissionable) then - exit NUCLIDE_LOOP2 - end if - - end do NUCLIDE_LOOP2 - end do MATERIAL_LOOP3 - - call file_close(file_id) - - end subroutine read_mgxs - - subroutine read_mgxs2() integer :: i ! index in materials array integer :: j ! index over nuclides in material integer :: i_nuclide ! index in nuclides array @@ -286,55 +242,55 @@ contains ! Avoid some valgrind leak errors call already_read % clear() - end subroutine read_mgxs2 + end subroutine read_mgxs !=============================================================================== ! CREATE_MACRO_XS generates the macroscopic xs from the microscopic input data !=============================================================================== + ! subroutine create_macro_xs() + ! integer :: i_mat ! index in materials array + ! type(Material), pointer :: mat ! current material + ! type(VectorReal), allocatable :: kTs(:) + + ! allocate(macro_xs(n_materials)) + + ! ! Get temperatures to read for each material + ! call get_mat_kTs(kTs) + + ! ! Force all nuclides in a material to be the same representation. + ! ! Therefore type(nuclides(mat % nuclide(1)) % obj) dictates type(macroxs). + ! ! At the same time, we will find the scattering type, as that will dictate + ! ! how we allocate the scatter object within macroxs.allocate(macro_xs(n_materials)) + ! do i_mat = 1, n_materials + + ! ! Get the material + ! mat => materials(i_mat) + + ! ! Get the scattering type for the first nuclide + ! select type(nuc => nuclides_MG(mat % nuclide(1)) % obj) + ! type is (MgxsIso) + ! allocate(MgxsIso :: macro_xs(i_mat) % obj) + ! type is (MgxsAngle) + ! allocate(MgxsAngle :: macro_xs(i_mat) % obj) + ! end select + + ! ! Do not read materials which we do not actually use in the problem to + ! ! reduce storage + ! if (allocated(kTs(i_mat) % data)) then + ! call macro_xs(i_mat) % obj % combine(kTs(i_mat), mat, nuclides_MG, & + ! num_energy_groups, num_delayed_groups, max_order, & + ! temperature_tolerance, temperature_method) + ! end if + ! end do + + ! end subroutine create_macro_xs + + subroutine create_macro_xs() integer :: i_mat ! index in materials array type(Material), pointer :: mat ! current material type(VectorReal), allocatable :: kTs(:) - - allocate(macro_xs(n_materials)) - - ! Get temperatures to read for each material - call get_mat_kTs(kTs) - - ! Force all nuclides in a material to be the same representation. - ! Therefore type(nuclides(mat % nuclide(1)) % obj) dictates type(macroxs). - ! At the same time, we will find the scattering type, as that will dictate - ! how we allocate the scatter object within macroxs.allocate(macro_xs(n_materials)) - do i_mat = 1, n_materials - - ! Get the material - mat => materials(i_mat) - - ! Get the scattering type for the first nuclide - select type(nuc => nuclides_MG(mat % nuclide(1)) % obj) - type is (MgxsIso) - allocate(MgxsIso :: macro_xs(i_mat) % obj) - type is (MgxsAngle) - allocate(MgxsAngle :: macro_xs(i_mat) % obj) - end select - - ! Do not read materials which we do not actually use in the problem to - ! reduce storage - if (allocated(kTs(i_mat) % data)) then - call macro_xs(i_mat) % obj % combine(kTs(i_mat), mat, nuclides_MG, & - num_energy_groups, num_delayed_groups, max_order, & - temperature_tolerance, temperature_method) - end if - end do - - end subroutine create_macro_xs - - - subroutine create_macro_xs2() - integer :: i_mat ! index in materials array - type(Material), pointer :: mat ! current material - type(VectorReal), allocatable :: kTs(:) character(MAX_WORD_LEN) :: name ! name of material ! Get temperatures to read for each material @@ -360,7 +316,7 @@ contains end if end do - end subroutine create_macro_xs2 + end subroutine create_macro_xs !=============================================================================== diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index be3e4e9d4d..09db7217ea 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -11,7 +11,6 @@ module mgxs_header use math, only: evaluate_legendre use nuclide_header, only: MaterialMacroXS use random_lcg, only: prn - use scattdata_header use string use stl_vector, only: VectorInt, VectorReal diff --git a/src/mgxs_interface.F90 b/src/mgxs_interface.F90 new file mode 100644 index 0000000000..7404af686d --- /dev/null +++ b/src/mgxs_interface.F90 @@ -0,0 +1,201 @@ +module mgxs_interface + + use, intrinsic :: ISO_C_BINDING + + use hdf5_interface + + implicit none + + interface + + subroutine add_mgxs_c(file_id, name, energy_groups, delayed_groups, & + n_temps, temps, method, tolerance, max_order, legendre_to_tabular, & + legendre_to_tabular_points) bind(C) + use ISO_C_BINDING + import HID_T + implicit none + integer(HID_T), value, intent(in) :: file_id + character(kind=C_CHAR),intent(in) :: name(*) + integer(C_INT), value, intent(in) :: energy_groups + integer(C_INT), value, intent(in) :: delayed_groups + integer(C_INT), value, intent(in) :: n_temps + real(C_DOUBLE), intent(in) :: temps(1:n_temps) + integer(C_INT), intent(inout) :: method + real(C_DOUBLE), value, intent(in) :: tolerance + integer(C_INT), value, intent(in) :: max_order + logical(C_BOOL),value, intent(in) :: legendre_to_tabular + integer(C_INT), value, intent(in) :: legendre_to_tabular_points + end subroutine add_mgxs_c + + function query_fissionable_c(n_nuclides, i_nuclides) result(result) bind(C) + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: n_nuclides + integer(C_INT), intent(in) :: i_nuclides(1:n_nuclides) + logical(C_BOOL) :: result + end function query_fissionable_c + + subroutine create_macro_xs_c(name, n_nuclides, i_nuclides, n_temps, temps, & + atom_densities, method, tolerance) bind(C) + use ISO_C_BINDING + implicit none + character(kind=C_CHAR),intent(in) :: name(*) + integer(C_INT), value, intent(in) :: n_nuclides + integer(C_INT), intent(in) :: i_nuclides(1:n_nuclides) + integer(C_INT), value, intent(in) :: n_temps + real(C_DOUBLE), intent(in) :: temps(1:n_temps) + real(C_DOUBLE), intent(in) :: atom_densities(1:n_nuclides) + integer(C_INT), intent(inout) :: method + real(C_DOUBLE), value, intent(in) :: tolerance + end subroutine create_macro_xs_c + + subroutine calculate_xs_c(i_mat, gin, sqrtkT, uvw, total_xs, abs_xs, & + nu_fiss_xs) bind(C) + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: i_mat + integer(C_INT), value, intent(in) :: gin + real(C_DOUBLE), value, intent(in) :: sqrtkT + real(C_DOUBLE), intent(in) :: uvw(1:3) + real(C_DOUBLE), intent(inout) :: total_xs + real(C_DOUBLE), intent(inout) :: abs_xs + real(C_DOUBLE), intent(inout) :: nu_fiss_xs + end subroutine calculate_xs_c + + subroutine sample_scatter_c(i_mat, gin, gout, mu, wgt, uvw) bind(C) + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: i_mat + integer(C_INT), value, intent(in) :: gin + integer(C_INT), intent(inout) :: gout + real(C_DOUBLE), intent(inout) :: mu + real(C_DOUBLE), intent(inout) :: wgt + real(C_DOUBLE), intent(inout) :: uvw(1:3) + end subroutine sample_scatter_c + + subroutine sample_fission_energy_c(i_mat, gin, dg, gout) bind(C) + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: i_mat + integer(C_INT), value, intent(in) :: gin + integer(C_INT), intent(inout) :: dg + integer(C_INT), intent(inout) :: gout + end subroutine sample_fission_energy_c + + subroutine get_name_c(index, name_len, name) bind(C) + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: index + integer(C_INT), value, intent(in) :: name_len + character(kind=C_CHAR), intent(inout) :: name(name_len) + end subroutine get_name_c + + function get_awr_c(index) result(awr) bind(C) + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: index + real(C_DOUBLE) :: awr + end function get_awr_c + + function get_nuclide_xs_c(index, xstype, gin, gout, mu, dg) result(val) & + bind(C) + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: index + integer(C_INT), value, intent(in) :: xstype + integer(C_INT), value, intent(in) :: gin + integer(C_INT), optional, intent(in) :: gout + real(C_DOUBLE), optional, intent(in) :: mu + integer(C_INT), optional, intent(in) :: dg + real(C_DOUBLE) :: val + end function get_nuclide_xs_c + + function get_macro_xs_c(index, xstype, gin, gout, mu, dg) result(val) & + bind(C) + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: index + integer(C_INT), value, intent(in) :: xstype + integer(C_INT), value, intent(in) :: gin + integer(C_INT), optional, intent(in) :: gout + real(C_DOUBLE), optional, intent(in) :: mu + integer(C_INT), optional, intent(in) :: dg + real(C_DOUBLE) :: val + end function get_macro_xs_c + + subroutine set_nuclide_angle_index_c(index, uvw, last_pol, last_azi, & + last_uvw) bind(C) + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: index + real(C_DOUBLE), intent(in) :: uvw(1:3) + integer(C_INT), intent(inout) :: last_pol + integer(C_INT), intent(inout) :: last_azi + real(C_DOUBLE), intent(inout) :: last_uvw(1:3) + end subroutine set_nuclide_angle_index_c + + subroutine reset_nuclide_angle_index_c(index, last_pol, last_azi, & + last_uvw) bind(C) + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: index + integer(C_INT), value, intent(in) :: last_pol + integer(C_INT), value, intent(in) :: last_azi + real(C_DOUBLE), intent(in) :: last_uvw(1:3) + end subroutine reset_nuclide_angle_index_c + + subroutine set_macro_angle_index_c(index, uvw, last_pol, last_azi, & + last_uvw) bind(C) + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: index + real(C_DOUBLE), intent(in) :: uvw(1:3) + integer(C_INT), intent(inout) :: last_pol + integer(C_INT), intent(inout) :: last_azi + real(C_DOUBLE), intent(inout) :: last_uvw(1:3) + end subroutine set_macro_angle_index_c + + subroutine reset_macro_angle_index_c(index, last_pol, last_azi, & + last_uvw) bind(C) + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: index + integer(C_INT), value, intent(in) :: last_pol + integer(C_INT), value, intent(in) :: last_azi + real(C_DOUBLE), intent(in) :: last_uvw(1:3) + end subroutine reset_macro_angle_index_c + + function set_nuclide_temperature_index_c(index, sqrtkT) result(last_temp) & + bind(C) + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: index + real(C_DOUBLE), value, intent(in) :: sqrtkT + integer(C_INT) :: last_temp + end function set_nuclide_temperature_index_c + + subroutine reset_nuclide_temperature_index_c(index, last_temp) bind(C) + use ISO_C_BINDING + implicit none + integer(C_INT), value, intent(in) :: index + integer(C_INT), value, intent(in) :: last_temp + end subroutine reset_nuclide_temperature_index_c + + end interface + + ! Number of energy groups + integer(C_INT) :: num_energy_groups + + ! Number of delayed groups + integer(C_INT) :: num_delayed_groups + + ! Energy group structure with decreasing energy + real(8), allocatable :: energy_bins(:) + + ! Midpoint of the energy group structure + real(8), allocatable :: energy_bin_avg(:) + + ! Energy group structure with increasing energy + real(8), allocatable :: rev_energy_bins(:) + +end module mgxs_interface \ No newline at end of file diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp new file mode 100644 index 0000000000..60afc28487 --- /dev/null +++ b/src/mgxs_interface.cpp @@ -0,0 +1,247 @@ +#include "mgxs_interface.h" + +namespace openmc { + +//============================================================================== +// Mgxs data loading interface methods +//============================================================================== + +void add_mgxs_c(hid_t file_id, char* name, int energy_groups, + int delayed_groups, int n_temps, double temps[], int& method, + double tolerance, int max_order, bool legendre_to_tabular, + int legendre_to_tabular_points) +{ + //!! mgxs_data.F90 will be modified to just create the list of names + //!! in the order needed + // Convert temps to a vector for the from_hdf5 function + double_1dvec temperature; + temperature.assign(temps, temps + n_temps); + + // TODO: C++ replacement for write_message + // write_message("Loading " + std::string(names[i]) + " data...", 6); + + // Check to make sure cross section set exists in the library + hid_t xs_grp; + if (object_exists(file_id, name)) { + xs_grp = open_group(file_id, name); + } else { + fatal_error("Data for " + std::string(name) + " does not exist in " + + "provided MGXS Library"); + } + + Mgxs mg; + mg.from_hdf5(xs_grp, energy_groups, delayed_groups, + temperature, method, tolerance, max_order, legendre_to_tabular, + legendre_to_tabular_points); + + nuclides_MG.push_back(mg); +} + + +bool query_fissionable_c(const int n_nuclides, const int i_nuclides[]) +{ + bool result = false; + for (int n = 0; n < n_nuclides; n++) { + if (nuclides_MG[i_nuclides[n] - 1].fissionable) result = true; + } + return result; +} + + +void create_macro_xs_c(char* mat_name, const int n_nuclides, + const int i_nuclides[], const int n_temps, const double temps[], + const double atom_densities[], int& method, const double tolerance) +{ + Mgxs macro; + if (n_temps > 0) { + // // Convert temps to a vector + double_1dvec temperature; + temperature.assign(temps, temps + n_temps); + + // Convert atom_densities to a vector + double_1dvec atom_densities_vec; + atom_densities_vec.assign(atom_densities, atom_densities + n_nuclides); + + // Build array of pointers to nuclides_MG's Mgxs objects needed for this + // material + std::vector mgxs_ptr(n_nuclides); + for (int n = 0; n < n_nuclides; n++) { + mgxs_ptr[n] = &nuclides_MG[i_nuclides[n] - 1]; + } + + macro.build_macro(mat_name, temperature, mgxs_ptr, atom_densities_vec, + method, tolerance); + } + macro_xs.push_back(macro); +} + +//============================================================================== +// Mgxs tracking/transport/tallying interface methods +//============================================================================== + +void calculate_xs_c(const int i_mat, const int gin, const double sqrtkT, + const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs) +{ + macro_xs[i_mat - 1].calculate_xs(gin - 1, sqrtkT, uvw, total_xs, abs_xs, + nu_fiss_xs); +} + + +void sample_scatter_c(const int i_mat, const int gin, int& gout, double& mu, + double& wgt, double uvw[3]) +{ + int gout_c = gout - 1; + macro_xs[i_mat - 1].sample_scatter(gin - 1, gout_c, mu, wgt); + + // adjust return value for fortran indexing + gout = gout_c + 1; + + // Rotate the angle + rotate_angle_c(uvw, mu, nullptr); +} + + +void sample_fission_energy_c(const int i_mat, const int gin, int& dg, int& gout) +{ + int dg_c = 0; + int gout_c = 0; + macro_xs[i_mat - 1].sample_fission_energy(gin - 1, dg_c, gout_c); + + // adjust return values for fortran indexing + dg = dg_c + 1; + gout = gout_c + 1; +} + + +void get_name_c(const int index, int name_len, char* name) +{ + // First blank out our input string + std::string str(name_len, ' '); + std::strcpy(name, str.c_str()); + + // Now get the data and copy to the C-string + str = nuclides_MG[index - 1].name; + std::strcpy(name, str.c_str()); + + // Finally, remove the null terminator + name[std::strlen(name)] = ' '; +} + + +double get_awr_c(const int index) +{ + return nuclides_MG[index - 1].awr; +} + + +double get_nuclide_xs_c(const int index, const int xstype, const int gin, + int* gout, double* mu, int* dg) +{ + int gout_c; + int* gout_c_p; + int dg_c; + int* dg_c_p; + if (gout != nullptr) { + gout_c = *gout - 1; + gout_c_p = &gout_c; + } else { + gout_c_p = gout; + } + if (dg != nullptr) { + dg_c = *dg - 1; + dg_c_p = &dg_c; + } else { + dg_c_p = dg; + } + return nuclides_MG[index - 1].get_xs(xstype, gin - 1, gout_c_p, mu, dg_c_p); +} + + +double get_macro_xs_c(const int index, const int xstype, const int gin, + int* gout, double* mu, int* dg) +{ + int gout_c; + int* gout_c_p; + int dg_c; + int* dg_c_p; + if (gout != nullptr) { + gout_c = *gout - 1; + gout_c_p = &gout_c; + } else { + gout_c_p = gout; + } + if (dg != nullptr) { + dg_c = *dg - 1; + dg_c_p = &dg_c; + } else { + dg_c_p = dg; + } + return macro_xs[index - 1].get_xs(xstype, gin - 1, gout_c_p, mu, dg_c_p); +} + + +void set_nuclide_angle_index_c(const int index, const double uvw[3], + int& last_pol, int& last_azi, double last_uvw[3]) +{ + // Store the old + last_pol = nuclides_MG[index - 1].index_pol; + last_azi = nuclides_MG[index - 1].index_azi; + last_uvw[0] = nuclides_MG[index - 1].last_uvw[0]; + last_uvw[1] = nuclides_MG[index - 1].last_uvw[1]; + last_uvw[2] = nuclides_MG[index - 1].last_uvw[2]; + + // Update the values + nuclides_MG[index - 1].set_angle_index(uvw); +} + + +void reset_nuclide_angle_index_c(const int index, const int last_pol, + const int last_azi, const double last_uvw[3]) +{ + nuclides_MG[index - 1].index_pol = last_pol; + nuclides_MG[index - 1].index_azi = last_azi; + nuclides_MG[index - 1].last_uvw[0] = last_uvw[0]; + nuclides_MG[index - 1].last_uvw[1] = last_uvw[1]; + nuclides_MG[index - 1].last_uvw[2] = last_uvw[2]; +} + + +void set_macro_angle_index_c(const int index, const double uvw[3], + int& last_pol, int& last_azi, double last_uvw[3]) +{ + // Store the old + last_pol = macro_xs[index - 1].index_pol; + last_azi = macro_xs[index - 1].index_azi; + last_uvw[0] = macro_xs[index - 1].last_uvw[0]; + last_uvw[1] = macro_xs[index - 1].last_uvw[1]; + last_uvw[2] = macro_xs[index - 1].last_uvw[2]; + + // Update the values + macro_xs[index - 1].set_angle_index(uvw); +} + + +void reset_macro_angle_index_c(const int index, const int last_pol, + const int last_azi, const double last_uvw[3]) +{ + macro_xs[index - 1].index_pol = last_pol; + macro_xs[index - 1].index_azi = last_azi; + macro_xs[index - 1].last_uvw[0] = last_uvw[0]; + macro_xs[index - 1].last_uvw[1] = last_uvw[1]; + macro_xs[index - 1].last_uvw[2] = last_uvw[2]; +} + + +int set_nuclide_temperature_index_c(const int index, const double sqrtkT) +{ + int old = nuclides_MG[index - 1].index_temp; + nuclides_MG[index - 1].set_temperature_index(sqrtkT); + return old; +} + +void reset_nuclide_temperature_index_c(const int index, const int last_temp) +{ + nuclides_MG[index - 1].index_temp = last_temp; +} + +} // namespace openmc \ No newline at end of file diff --git a/src/mgxs_interface.h b/src/mgxs_interface.h new file mode 100644 index 0000000000..197ecb0bf9 --- /dev/null +++ b/src/mgxs_interface.h @@ -0,0 +1,66 @@ +//! \file mgxs_interface.h +//! A collection of C interfaces to the C++ Mgxs class + +#ifndef MGXS_INTERFACE_H +#define MGXS_INTERFACE_H + +#include "mgxs.h" + + +namespace openmc { + +extern std::vector nuclides_MG; +extern std::vector macro_xs; + + +extern "C" void add_mgxs_c(hid_t file_id, char* name, int energy_groups, + int delayed_groups, int n_temps, double temps[], int& method, + double tolerance, int max_order, bool legendre_to_tabular, + int legendre_to_tabular_points); + +extern "C" bool query_fissionable_c(const int n_nuclides, const int i_nuclides[]); + +extern "C" void create_macro_xs_c(char* mat_name, const int n_nuclides, + const int i_nuclides[], const int n_temps, const double temps[], + const double atom_densities[], int& method, const double tolerance); + +extern "C" void calculate_xs_c(const int i_mat, const int gin, + const double sqrtkT, const double uvw[3], double& total_xs, + double& abs_xs, double& nu_fiss_xs); + +extern "C" void sample_scatter_c(const int i_mat, const int gin, int& gout, + double& mu, double& wgt, double uvw[3]); + +extern "C" void sample_fission_energy_c(const int i_mat, const int gin, + int& dg, int& gout); + +extern "C" void get_name_c(const int index, int name_len, char* name); + +extern "C" double get_awr_c(const int index); + +extern "C" double get_nuclide_xs_c(const int index, const int xstype, + const int gin, int* gout, double* mu, int* dg); + +extern "C" double get_macro_xs_c(const int index, const int xstype, + const int gin, int* gout, double* mu, int* dg); + +extern "C" void set_nuclide_angle_index_c(const int index, const double uvw[3], + int& last_pol, int& last_azi, double last_uvw[3]); + +extern "C" void reset_nuclide_angle_index_c(const int index, const int last_pol, + const int last_azi, const double last_uvw[3]); + +extern "C" void set_macro_angle_index_c(const int index, const double uvw[3], + int& last_pol, int& last_azi, double last_uvw[3]); + +extern "C" void reset_macro_angle_index_c(const int index, const int last_pol, + const int last_azi, const double last_uvw[3]); + +extern "C" int set_nuclide_temperature_index_c(const int index, + const double sqrtkT); + +extern "C" void reset_nuclide_temperature_index_c(const int index, + const int last_temp); + +} // namespace openmc +#endif // MGXS_INTERFACE_H \ No newline at end of file diff --git a/src/output.F90 b/src/output.F90 index 23d9512eee..9c5d9cb451 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -12,7 +12,7 @@ module output use math, only: t_percentile use mesh_header, only: RegularMesh, meshes use message_passing, only: master, n_procs - use mgxs_header, only: nuclides_MG + use mgxs_interface use nuclide_header use particle_header, only: LocalCoord, Particle use plot_header @@ -680,6 +680,7 @@ contains character(36) :: score_name ! names of scoring function ! to be applied at write-time type(TallyFilterMatch), allocatable :: matches(:) + character(MAX_WORD_LEN) :: temp_name ! Skip if there are no tallies if (n_tallies == 0) return @@ -843,8 +844,9 @@ contains write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), & trim(nuclides(i_nuclide) % name) else + call get_name_c(i_nuclide, len(temp_name), temp_name) write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), & - trim(nuclides_MG(i_nuclide) % obj % name) + trim(temp_name) end if end if diff --git a/src/particle_restart.F90 b/src/particle_restart.F90 index c3d25151b6..200773c256 100644 --- a/src/particle_restart.F90 +++ b/src/particle_restart.F90 @@ -6,7 +6,7 @@ module particle_restart use constants use error, only: write_message use hdf5_interface, only: file_open, file_close, read_dataset, HID_T - use mgxs_header, only: energy_bin_avg + use mgxs_interface, only: energy_bin_avg use nuclide_header, only: micro_xs, n_nuclides use output, only: print_particle use particle_header, only: Particle diff --git a/src/physics_mg.F90 b/src/physics_mg.F90 index 3030fc099b..797514e25f 100644 --- a/src/physics_mg.F90 +++ b/src/physics_mg.F90 @@ -8,13 +8,12 @@ module physics_mg use material_header, only: Material, materials use math, only: rotate_angle use mesh_header, only: meshes - use mgxs_header + use mgxs_interface use message_passing use nuclide_header, only: material_xs use particle_header, only: Particle use physics_common use random_lcg, only: prn - use scattdata_header use settings use simulation_header use string, only: to_str @@ -22,20 +21,6 @@ module physics_mg implicit none - interface - subroutine scatter_c(i_mat, gin, gout, mu, wgt, uvw) & - bind(C, name='scatter') - use ISO_C_BINDING - implicit none - integer(C_INT), value, intent(in) :: i_mat - integer(C_INT), value, intent(in) :: gin - integer(C_INT), intent(inout) :: gout - real(C_DOUBLE), intent(inout) :: mu - real(C_DOUBLE), intent(inout) :: wgt - real(C_DOUBLE), intent(inout) :: uvw(1:3) - end subroutine scatter_c - end interface - contains !=============================================================================== @@ -157,14 +142,8 @@ contains type(Particle), intent(inout) :: p - ! call macro_xs(p % material) % obj % sample_scatter(p % coord(1) % uvw, & - ! p % last_g, p % g, p % mu, p % wgt) - - ! Convert change in angle (mu) to new direction - ! p % coord(1) % uvw = rotate_angle(p % coord(1) % uvw, p % mu) - - call scatter_c(p % material, p % last_g, p % g, p % mu, p % wgt, & - p % coord(1) % uvw) + call sample_scatter_c(p % material, p % last_g, p % g, p % mu, p % wgt, & + p % coord(1) % uvw) ! Update energy value for downstream compatability (in tallying) p % E = energy_bin_avg(p % g) @@ -194,10 +173,6 @@ contains real(8) :: mu ! fission neutron angular cosine real(8) :: phi ! fission neutron azimuthal angle real(8) :: weight ! weight adjustment for ufs method - class(Mgxs), pointer :: xs - - ! Get Pointers - xs => macro_xs(p % material) % obj ! TODO: Heat generation from fission @@ -277,7 +252,7 @@ contains ! Sample secondary energy distribution for fission reaction and set energy ! in fission bank - call xs % sample_fission_energy(p % g, bank_array(i) % uvw, dg, gout) + call sample_fission_energy_c(p % material, p % g, dg, gout) bank_array(i) % E = real(gout, 8) bank_array(i) % delayed_group = dg diff --git a/src/scattdata.cpp b/src/scattdata.cpp index aef620ac5d..b12ec1acb7 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -56,35 +56,38 @@ void ScattData::sample_energy(int gin, int& gout, int& i_gout) } -double ScattData::get_xs(const char* xstype, int gin, int* gout, double* mu) +double ScattData::get_xs(const int xstype, int gin, int* gout, double* mu) { // Set the outgoing group offset index as needed int i_gout = 0; if (gout != nullptr) { // short circuit the function if gout is from a zero portion of the // scattering matrix - if ((*gout < gmin[gin]) || (*gout >= gmax[gin])) { // > gmax? + if ((*gout < gmin[gin]) || (*gout > gmax[gin])) { // > gmax? return 0.; } i_gout = *gout - gmin[gin]; } double val = 0.; - if (std::strcmp(xstype, "scatter")) { + switch(xstype) { + case MG_GET_XS_SCATTER: if (gout != nullptr) { val = scattxs[gin] * energy[gin][i_gout]; } else { val = scattxs[gin]; } - } else if (std::strcmp(xstype, "scatter/mult")) { + break; + case MG_GET_XS_SCATTER_MULT: if (gout != nullptr) { val = scattxs[gin] * energy[gin][i_gout] / mult[gin][i_gout]; } else { - val = scattxs[gin] / std::inner_product(mult[gin].begin(), - mult[gin].end(), - energy[gin].begin(), 0.0); + val = scattxs[gin] / + std::inner_product(mult[gin].begin(), mult[gin].end(), + energy[gin].begin(), 0.0); } - } else if (std::strcmp(xstype, "scatter*f_mu/mult")) { + break; + case MG_GET_XS_SCATTER_FMU_MULT: if ((gout != nullptr) && (mu != nullptr)) { val = scattxs[gin] * energy[gin][i_gout] * calc_f(gin, *gout, *mu); } else { @@ -92,7 +95,8 @@ double ScattData::get_xs(const char* xstype, int gin, int* gout, double* mu) // group or mu is not useful fatal_error("Invalid call to get_xs"); } - } else if (std::strcmp(xstype, "scatter*f_mu")) { + break; + case MG_GET_XS_SCATTER_FMU: if ((gout != nullptr) && (mu != nullptr)) { val = scattxs[gin] * energy[gin][i_gout] * calc_f(gin, *gout, *mu) / mult[gin][i_gout]; @@ -101,6 +105,7 @@ double ScattData::get_xs(const char* xstype, int gin, int* gout, double* mu) // group or mu is not useful fatal_error("Invalid call to get_xs"); } + break; } return val; } @@ -205,13 +210,11 @@ void ScattDataLegendre::update_max_val() double ScattDataLegendre::calc_f(int gin, int gout, double mu) { - // TODO: gout >= or gout >? double f; - if ((gout < gmin[gin]) || (gout >= gmax[gin])) { + if ((gout < gmin[gin]) || (gout > gmax[gin])) { f = 0.; } else { - // TODO: size() -1 or just size? - int i_gout = gout - gmin[gin]; //TODO: + 1? + int i_gout = gout - gmin[gin]; f = evaluate_legendre_c(dist[gin][i_gout].size() - 1, dist[gin][i_gout].data(), mu); } @@ -479,19 +482,18 @@ void ScattDataHistogram::init(int_1dvec& in_gmin, int_1dvec& in_gmax, double ScattDataHistogram::calc_f(int gin, int gout, double mu) { - // TODO: gout >= or gout >? double f; - if ((gout < gmin[gin]) || (gout >= gmax[gin])) { + if ((gout < gmin[gin]) || (gout > gmax[gin])) { f = 0.; } else { // Find mu bin - int i_gout = gout - gmin[gin]; //TODO: + 1? + int i_gout = gout - gmin[gin]; int imu; if (mu == 1.) { // use size -2 to have the index one before the end imu = this->mu.size() - 2; } else { - imu = std::floor((mu + 1.) / dmu + 1.); + imu = std::floor((mu + 1.) / dmu + 1.) - 1; } f = fmu[gin][i_gout][imu]; @@ -776,19 +778,18 @@ void ScattDataTabular::init(int_1dvec& in_gmin, int_1dvec& in_gmax, double ScattDataTabular::calc_f(int gin, int gout, double mu) { - // TODO: gout >= or gout >? double f; - if ((gout < gmin[gin]) || (gout >= gmax[gin])) { + if ((gout < gmin[gin]) || (gout > gmax[gin])) { f = 0.; } else { // Find mu bin - int i_gout = gout - gmin[gin]; //TODO: + 1? + int i_gout = gout - gmin[gin]; int imu; if (mu == 1.) { // use size -2 to have the index one before the end imu = this->mu.size() - 2; } else { - imu = std::floor((mu + 1.) / dmu + 1.); + imu = std::floor((mu + 1.) / dmu + 1.) - 1; } double r = (mu - this->mu[imu]) / (this->mu[imu + 1] - this->mu[imu]); @@ -1006,7 +1007,7 @@ void convert_legendre_to_tabular(ScattDataLegendre& leg, tab.dmu = 2. / (n_mu - 1); tab.mu[0] = -1.; for (int imu = 1; imu < n_mu - 1; imu++) { - tab.mu[imu] = -1. + (imu - 1) * tab.dmu; + tab.mu[imu] = -1. + imu * tab.dmu; } tab.mu[n_mu - 1] = 1.; @@ -1032,6 +1033,7 @@ void convert_legendre_to_tabular(ScattDataLegendre& leg, // Now re-normalize for numerical integration issues and to take care of // the above negative fix-up. Also accrue the CDF double norm = 0.; + tab.dist[gin][i_gout][0] = 0.; for (int imu = 1; imu < n_mu; imu++) { norm += 0.5 * tab.dmu * (tab.fmu[gin][i_gout][imu - 1] + tab.fmu[gin][i_gout][imu]); diff --git a/src/scattdata.h b/src/scattdata.h index 4553156e0d..a9a236b2b7 100644 --- a/src/scattdata.h +++ b/src/scattdata.h @@ -38,7 +38,7 @@ class ScattData { virtual void init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, double_3dvec& coeffs) = 0; void sample_energy(int gin, int& gout, int& i_gout); - double get_xs(const char* xstype, int gin, int* gout, double* mu); + double get_xs(const int xstype, int gin, int* gout, double* mu); void generic_init(int order, int_1dvec in_gmin, int_1dvec in_gmax, double_2dvec in_energy, double_2dvec in_mult); virtual void combine(std::vector& those_scatts, diff --git a/src/simulation.F90 b/src/simulation.F90 index 4f6163429e..ffcfb8bab8 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -20,7 +20,7 @@ module simulation use geometry_header, only: n_cells use material_header, only: n_materials, materials use message_passing - use mgxs_header, only: energy_bins, energy_bin_avg + use mgxs_interface, only: energy_bins, energy_bin_avg use nuclide_header, only: micro_xs, n_nuclides use output, only: header, print_columns, & print_batch_keff, print_generation, print_runtime, & diff --git a/src/source.F90 b/src/source.F90 index 3683611315..a6b6a92ac2 100644 --- a/src/source.F90 +++ b/src/source.F90 @@ -14,7 +14,7 @@ module source use hdf5_interface use math use message_passing, only: rank - use mgxs_header, only: rev_energy_bins, num_energy_groups + use mgxs_interface, only: rev_energy_bins, num_energy_groups use output, only: write_message use particle_header, only: Particle use random_lcg, only: prn, set_particle_seed, prn_set_stream diff --git a/src/state_point.F90 b/src/state_point.F90 index 27fdd969b5..ebb473d496 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -22,7 +22,7 @@ module state_point use hdf5_interface use mesh_header, only: RegularMesh, meshes, n_meshes use message_passing - use mgxs_header, only: nuclides_MG + use mgxs_interface use nuclide_header, only: nuclides use output, only: time_stamp use random_lcg, only: openmc_get_seed, openmc_set_seed @@ -73,6 +73,7 @@ contains character(MAX_WORD_LEN), allocatable :: str_array(:) character(C_CHAR), pointer :: string(:) character(len=:, kind=C_CHAR), allocatable :: filename_ + character(MAX_WORD_LEN, kind=C_CHAR) :: temp_name err = 0 if (present(filename)) then @@ -307,11 +308,13 @@ contains str_array(j) = nuclides(tally % nuclide_bins(j)) % name end if else - i_xs = index(nuclides_MG(tally % nuclide_bins(j)) % obj % name, '.') + call get_name_c(tally % nuclide_bins(j), len(temp_name), & + temp_name) + i_xs = index(temp_name, '.') if (i_xs > 0) then - str_array(j) = nuclides_MG(tally % nuclide_bins(j)) % obj % name(1 : i_xs-1) + str_array(j) = trim(temp_name(1 : i_xs-1)) else - str_array(j) = nuclides_MG(tally % nuclide_bins(j)) % obj % name + str_array(j) = trim(temp_name) end if end if else diff --git a/src/string_functions.cpp b/src/string_functions.cpp new file mode 100644 index 0000000000..f41ec40c1e --- /dev/null +++ b/src/string_functions.cpp @@ -0,0 +1,30 @@ +#include "string_functions.h" + +namespace openmc { + +std::string& strtrim(std::string& s) +{ + const char* t = " \t\n\r\f\v"; + s.erase(s.find_last_not_of(t) + 1); + s.erase(0, s.find_first_not_of(t)); + return s; +} + + +char* strtrim(char* c_str) +{ + std::string std_str; + std_str.assign(c_str); + strtrim(std_str); + int length = std_str.copy(c_str, std_str.size()); + c_str[length] = '\0'; + return c_str; +} + + +void to_lower(std::string& str) +{ + for (int i = 0; i < str.size(); i++) str[i] = std::tolower(str[i]); +} + +} // namespace openmc \ No newline at end of file diff --git a/src/string_functions.h b/src/string_functions.h index d44982bbd3..bf30612fe8 100644 --- a/src/string_functions.h +++ b/src/string_functions.h @@ -4,38 +4,15 @@ #ifndef STRING_FUNCTIONS_H #define STRING_FUNCTIONS_H -// for string functions -#include -#include -#include #include namespace openmc { -std::string& strtrim(std::string& s) -{ - const char* t = " \t\n\r\f\v"; - s.erase(s.find_last_not_of(t) + 1); - s.erase(0, s.find_first_not_of(t)); - return s; -} +std::string& strtrim(std::string& s); +char* strtrim(char* c_str); -char* strtrim(char* c_str) -{ - std::string std_str; - std_str.assign(c_str); - strtrim(std_str); - int length = std_str.copy(c_str, std_str.size()); - c_str[length] = '\0'; - return c_str; -} - - -void to_lower(std::string& str) -{ - for (int i = 0; i < str.size(); i++) str[i] = std::tolower(str[i]); -} +void to_lower(std::string& str); } // namespace openmc -#endif // STRING_FUNCTIONS_H \ No newline at end of file +#endif // STRING_FUNCTIONS_H diff --git a/src/summary.F90 b/src/summary.F90 index bd6ef7158d..cae81a88bc 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -8,7 +8,7 @@ module summary use material_header, only: Material, n_materials use mesh_header, only: RegularMesh use message_passing - use mgxs_header, only: nuclides_MG + use mgxs_interface use nuclide_header use output, only: time_stamp use settings, only: run_CE @@ -94,7 +94,7 @@ contains num_nuclides = 0 num_macros = 0 do i = 1, n_nuclides - if (nuclides_MG(i) % obj % awr /= MACROSCOPIC_AWR) then + if (get_awr_c(i) /= MACROSCOPIC_AWR) then num_nuclides = num_nuclides + 1 else num_macros = num_macros + 1 @@ -119,12 +119,14 @@ contains nuc_names(i) = nuclides(i) % name awrs(i) = nuclides(i) % awr else - if (nuclides_MG(i) % obj % awr /= MACROSCOPIC_AWR) then - nuc_names(j) = nuclides_MG(i) % obj % name - awrs(j) = nuclides_MG(i) % obj % awr + if (get_awr_c(i) /= MACROSCOPIC_AWR) then + call get_name_c(i, len(nuc_names(j)), nuc_names(j)) + nuc_names(j) = trim(nuc_names(j)) + awrs(j) = get_awr_c(i) j = j + 1 else - macro_names(k) = nuclides_MG(i) % obj % name + call get_name_c(i, len(macro_names(k)), macro_names(k)) + macro_names(k) = trim(macro_names(k)) k = k + 1 end if end if @@ -458,7 +460,7 @@ contains num_nuclides = 0 num_macros = 0 do j = 1, m % n_nuclides - if (nuclides_MG(m % nuclide(j)) % obj % awr /= MACROSCOPIC_AWR) then + if (get_awr_c(m % nuclide(j)) /= MACROSCOPIC_AWR) then num_nuclides = num_nuclides + 1 else num_macros = num_macros + 1 @@ -484,12 +486,14 @@ contains k = 1 n = 1 do j = 1, m % n_nuclides - if (nuclides_MG(m % nuclide(j)) % obj % awr /= MACROSCOPIC_AWR) then - nuc_names(k) = nuclides_MG(m % nuclide(j)) % obj % name + if (get_awr_c(m % nuclide(j)) /= MACROSCOPIC_AWR) then + call get_name_c(m % nuclide(j), len(nuc_names(k)), nuc_names(k)) + nuc_names(k) = trim(nuc_names(k)) nuc_densities(k) = m % atom_density(j) k = k + 1 else - macro_names(n) = nuclides_MG(m % nuclide(j)) % obj % name + call get_name_c(m % nuclide(j), len(macro_names(n)), macro_names(n)) + macro_names(n) = trim(macro_names(n)) n = n + 1 end if end do diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index ef8b5915c1..4c24717b43 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -10,7 +10,7 @@ module tally use math, only: t_percentile use mesh_header, only: RegularMesh, meshes use message_passing - use mgxs_header + use mgxs_interface use nuclide_header use output, only: header use particle_header, only: LocalCoord, Particle @@ -1229,8 +1229,14 @@ contains real(8) :: p_uvw(3) ! Particle's current uvw integer :: p_g ! Particle group to use for getting info ! to tally with. - class(Mgxs), pointer :: matxs - class(Mgxs), pointer :: nucxs + ! Storage of the indices the Mgxs object arrived with for resetting later + integer(C_INT) :: last_nuc_azi + integer(C_INT) :: last_nuc_pol + integer(C_INT) :: last_mat_azi + integer(C_INT) :: last_mat_pol + integer(C_INT) :: last_nuc_temp + real(C_DOUBLE) :: last_mat_uvw(3) + real(C_DOUBLE) :: last_nuc_uvw(3) ! Set the direction and group to use with get_xs if (t % estimator == ESTIMATOR_ANALOG .or. & @@ -1268,13 +1274,15 @@ contains ! To significantly reduce de-referencing, point matxs to the ! macroscopic Mgxs for the material of interest - matxs => macro_xs(p % material) % obj + call set_macro_angle_index_c(p % material, p_uvw, last_mat_pol, & + last_mat_azi, last_mat_uvw) ! Do same for nucxs, point it to the microscopic nuclide data of interest if (i_nuclide > 0) then - nucxs => nuclides_MG(i_nuclide) % obj ! And since we haven't calculated this temperature index yet, do so now - call nucxs % find_temperature(p % sqrtkT) + last_nuc_temp = set_nuclide_temperature_index_c(i_nuclide, p % sqrtkT) + call set_nuclide_angle_index_c(i_nuclide, p_uvw, last_nuc_pol, & + last_nuc_azi, last_nuc_uvw) end if i = 0 @@ -1329,13 +1337,13 @@ contains if (i_nuclide > 0) then score = score * atom_density * & - nucxs % get_xs('total', p_g, UVW=p_uvw) / & - matxs % get_xs('total', p_g, UVW=p_uvw) * flux + get_nuclide_xs_c(i_nuclide, MG_GET_XS_TOTAL, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_TOTAL, p_g) * flux end if else if (i_nuclide > 0) then - score = nucxs % get_xs('total', p_g, UVW=p_uvw) * & + score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_TOTAL, p_g) * & atom_density * flux else score = material_xs % total * flux @@ -1358,19 +1366,23 @@ contains end if if (i_nuclide > 0) then - score = score * nucxs % get_xs('inverse-velocity', p_g, UVW=p_uvw) & - / matxs % get_xs('absorption', p_g, UVW=p_uvw) * flux + score = score * get_nuclide_xs_c(i_nuclide, & + MG_GET_XS_INVERSE_VELOCITY, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) * flux else - score = score * matxs % get_xs('inverse-velocity', p_g, UVW=p_uvw) & - / matxs % get_xs('absorption', p_g, UVW=p_uvw) * flux + score = score * get_macro_xs_c(p % material, & + MG_GET_XS_INVERSE_VELOCITY, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) * flux end if else if (i_nuclide > 0) then - score = flux * nucxs % get_xs('inverse-velocity', p_g, UVW=p_uvw) + score = flux * get_nuclide_xs_c(i_nuclide, & + MG_GET_XS_INVERSE_VELOCITY, p_g) else - score = flux * matxs % get_xs('inverse-velocity', p_g, UVW=p_uvw) + score = flux * get_macro_xs_c(p % material, & + MG_GET_XS_INVERSE_VELOCITY, p_g) end if end if @@ -1392,21 +1404,23 @@ contains ! adjust the score by the actual probability for that nuclide. if (i_nuclide > 0) then score = score * atom_density * & - nucxs % get_xs('scatter*f_mu/mult', p % last_g, p % g, & - UVW=p_uvw, MU=p % mu) / & - matxs % get_xs('scatter*f_mu/mult', p % last_g, p % g, & - UVW=p_uvw, MU=p % mu) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_SCATTER_FMU_MULT, & + p % last_g, p % g, MU=p % mu) / & + get_macro_xs_c(p % material, MG_GET_XS_SCATTER_FMU_MULT, & + p % last_g, p % g, MU=p % mu) end if else if (i_nuclide > 0) then score = atom_density * flux * & - nucxs % get_xs('scatter/mult', p_g, UVW=p_uvw) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_SCATTER_MULT, & + p_g, MU=p % mu) else ! Get the scattering x/s and take away ! the multiplication baked in to sigS score = flux * & - matxs % get_xs('scatter/mult', p_g, UVW=p_uvw) + get_macro_xs_c(p % material, MG_GET_XS_SCATTER_MULT, & + p_g, MU=p % mu) end if end if @@ -1428,19 +1442,20 @@ contains ! adjust the score by the actual probability for that nuclide. if (i_nuclide > 0) then score = score * atom_density * & - nucxs % get_xs('scatter*f_mu', p % last_g, p % g, & - UVW=p_uvw, MU=p % mu) / & - matxs % get_xs('scatter*f_mu', p % last_g, p % g, & - UVW=p_uvw, MU=p % mu) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_SCATTER_FMU, & + p % last_g, p % g, MU=p % mu) / & + get_macro_xs_c(p % material, MG_GET_XS_SCATTER_FMU, & + p % last_g, p % g, MU=p % mu) end if else if (i_nuclide > 0) then - score = nucxs % get_xs('scatter', p_g, UVW=p_uvw) * & - atom_density * flux + score = atom_density * flux * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_SCATTER, p_g) else ! Get the scattering x/s, which includes multiplication - score = matxs % get_xs('scatter', p_g, UVW=p_uvw) * flux + score = flux * & + get_macro_xs_c(p % material, MG_GET_XS_SCATTER, p_g) end if end if @@ -1460,13 +1475,13 @@ contains end if if (i_nuclide > 0) then score = score * atom_density * & - nucxs % get_xs('absorption', p_g, UVW=p_uvw) / & - matxs % get_xs('absorption', p_g, UVW=p_uvw) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_ABSORPTION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if else if (i_nuclide > 0) then - score = nucxs % get_xs('absorption', p_g, UVW=p_uvw) * & - atom_density * flux + score = atom_density * flux * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_ABSORPTION, p_g) else score = material_xs % absorption * flux end if @@ -1491,19 +1506,19 @@ contains end if if (i_nuclide > 0) then score = score * atom_density * & - nucxs % get_xs('fission', p_g, UVW=p_uvw) / & - matxs % get_xs('absorption', p_g, UVW=p_uvw) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) else score = score * & - matxs % get_xs('fission', p_g, UVW=p_uvw) / & - matxs % get_xs('absorption', p_g, UVW=p_uvw) + get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if else if (i_nuclide > 0) then - score = nucxs % get_xs('fission', p_g, UVW=p_uvw) * & + score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) * & atom_density * flux else - score = matxs % get_xs('fission', p_g, UVW=p_uvw) * flux + score = get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) * flux end if end if @@ -1529,12 +1544,12 @@ contains score = p % absorb_wgt * flux if (i_nuclide > 0) then score = score * atom_density * & - nucxs % get_xs('nu-fission', p_g, UVW=p_uvw) / & - matxs % get_xs('absorption', p_g, UVW=p_uvw) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) else score = score * & - matxs % get_xs('nu-fission', p_g, UVW=p_uvw) / & - matxs % get_xs('absorption', p_g, UVW=p_uvw) + get_macro_xs_c(p % material, MG_GET_XS_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if else ! Skip any non-fission events @@ -1547,17 +1562,17 @@ contains score = keff * p % wgt_bank * flux if (i_nuclide > 0) then score = score * atom_density * & - nucxs % get_xs('fission', p_g, UVW=p_uvw) / & - matxs % get_xs('fission', p_g, UVW=p_uvw) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) end if end if else if (i_nuclide > 0) then - score = nucxs % get_xs('nu-fission', p_g, UVW=p_uvw) * & + score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_NU_FISSION, p_g) * & atom_density * flux else - score = matxs % get_xs('nu-fission', p_g, UVW=p_uvw) * flux + score = get_macro_xs_c(p % material, MG_GET_XS_NU_FISSION, p_g) * flux end if end if @@ -1583,12 +1598,12 @@ contains score = p % absorb_wgt * flux if (i_nuclide > 0) then score = score * atom_density * & - nucxs % get_xs('prompt-nu-fission', p_g, UVW=p_uvw) / & - matxs % get_xs('absorption', p_g, UVW=p_uvw) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_PROMPT_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) else score = score * & - matxs % get_xs('prompt-nu-fission', p_g, UVW=p_uvw) / & - matxs % get_xs('absorption', p_g, UVW=p_uvw) + get_macro_xs_c(p % material, MG_GET_XS_PROMPT_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if else ! Skip any non-fission events @@ -1602,17 +1617,17 @@ contains / real(p % n_bank, 8)) * flux if (i_nuclide > 0) then score = score * atom_density * & - nucxs % get_xs('fission', p_g, UVW=p_uvw) / & - matxs % get_xs('fission', p_g, UVW=p_uvw) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) end if end if else if (i_nuclide > 0) then - score = nucxs % get_xs('prompt-nu-fission', p_g, UVW=p_uvw) * & + score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_PROMPT_NU_FISSION, p_g) * & atom_density * flux else - score = matxs % get_xs('prompt-nu-fission', p_g, UVW=p_uvw) * flux + score = get_macro_xs_c(p % material, MG_GET_XS_PROMPT_NU_FISSION, p_g) * flux end if end if @@ -1638,7 +1653,7 @@ contains ! No fission events occur if survival biasing is on -- need to ! calculate fraction of absorptions that would have resulted in ! nu-fission - if (matxs % get_xs('absorption', p_g, UVW=p_uvw) > ZERO) then + if (get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) > ZERO) then if (dg_filter > 0) then select type(filt => filters(t % filter(dg_filter)) % obj) @@ -1653,13 +1668,13 @@ contains score = p % absorb_wgt * flux if (i_nuclide > 0) then - score = score * nucxs % get_xs('delayed-nu-fission', & - p_g, UVW=p_uvw, dg=d) / & - matxs % get_xs('absorption', p_g, UVW=p_uvw) + score = score * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) else - score = score * matxs % get_xs('delayed-nu-fission', & - p_g, UVW=p_uvw, dg=d) / & - matxs % get_xs('absorption', p_g, UVW=p_uvw) + score = score * & + get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if call score_fission_delayed_dg(t, d_bin, score, score_index) @@ -1669,11 +1684,13 @@ contains else score = p % absorb_wgt * flux if (i_nuclide > 0) then - score = score * nucxs % get_xs('delayed-nu-fission', p_g, & - UVW=p_uvw) / matxs % get_xs('absorption', p_g, UVW=p_uvw) + score = score * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) else - score = score * matxs % get_xs('delayed-nu-fission', p_g, & - UVW=p_uvw) / matxs % get_xs('absorption', p_g, UVW=p_uvw) + score = score * & + get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if end if end if @@ -1703,8 +1720,8 @@ contains if (i_nuclide > 0) then score = score * atom_density * & - nucxs % get_xs('fission', p_g, UVW=p_uvw) / & - matxs % get_xs('fission', p_g, UVW=p_uvw) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) end if call score_fission_delayed_dg(t, d_bin, score, score_index) @@ -1715,8 +1732,8 @@ contains score = keff * p % wgt_bank / p % n_bank * sum(p % n_delayed_bank) * flux if (i_nuclide > 0) then score = score * atom_density * & - nucxs % get_xs('fission', p_g, UVW=p_uvw) / & - matxs % get_xs('fission', p_g, UVW=p_uvw) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) end if end if end if @@ -1735,11 +1752,11 @@ contains d = filt % groups(d_bin) if (i_nuclide > 0) then - score = nucxs % get_xs('delayed-nu-fission', p_g, & - UVW=p_uvw, dg=d) * atom_density * flux + score = atom_density * flux * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) else - score = matxs % get_xs('delayed-nu-fission', p_g, & - UVW=p_uvw, dg=d) * flux + score = flux * & + get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) end if call score_fission_delayed_dg(t, d_bin, score, score_index) @@ -1748,11 +1765,12 @@ contains end select else if (i_nuclide > 0) then - score = nucxs % get_xs('delayed-nu-fission', p_g, UVW=p_uvw) & - * atom_density * flux + score = atom_density * flux * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g) + else - score = matxs % get_xs('delayed-nu-fission', p_g, UVW=p_uvw) & - * flux + score = flux * & + get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g) end if end if end if @@ -1767,7 +1785,7 @@ contains ! No fission events occur if survival biasing is on -- need to ! calculate fraction of absorptions that would have resulted in ! nu-fission - if (matxs % get_xs('absorption', p_g, UVW=p_uvw) > ZERO) then + if (get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) > ZERO) then if (dg_filter > 0) then select type(filt => filters(t % filter(dg_filter)) % obj) @@ -1782,17 +1800,15 @@ contains score = p % absorb_wgt * flux if (i_nuclide > 0) then - score = score * nucxs % get_xs('decay rate', p_g, & - UVW=p_uvw, dg=d) * & - nucxs % get_xs('delayed-nu-fission', p_g, & - UVW=p_uvw, dg=d) / matxs % get_xs('absorption', & - p_g, UVW=p_uvw) + score = score * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) else - score = score * matxs % get_xs('decay rate', p_g, & - UVW=p_uvw, dg=d) * & - matxs % get_xs('delayed-nu-fission', p_g, & - UVW=p_uvw, dg=d) / matxs % get_xs('absorption', & - p_g, UVW=p_uvw) + score = score * & + get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if call score_fission_delayed_dg(t, d_bin, score, score_index) @@ -1809,15 +1825,15 @@ contains ! for all delayed groups. do d = 1, num_delayed_groups if (i_nuclide > 0) then - score = score + p % absorb_wgt * & - nucxs % get_xs('decay rate', p_g, UVW=p_uvw, dg=d) * & - nucxs % get_xs('delayed-nu-fission', p_g, UVW=p_uvw, & - dg=d) / matxs % get_xs('absorption', p_g, UVW=p_uvw) * flux + score = score + p % absorb_wgt * flux * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) else - score = score + p % absorb_wgt * & - matxs % get_xs('decay rate', p_g, UVW=p_uvw, dg=d) * & - matxs % get_xs('delayed-nu-fission', p_g, UVW=p_uvw, & - dg=d) / matxs % get_xs('absorption', p_g, UVW=p_uvw) * flux + score = score + p % absorb_wgt * flux * & + get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if end do end if @@ -1846,13 +1862,13 @@ contains if (i_nuclide > 0) then score = score + keff * atom_density * & fission_bank(n_bank - p % n_bank + k) % wgt * & - nucxs % get_xs('decay rate', p_g, UVW=p_uvw, dg=g) * & - nucxs % get_xs('fission', p_g, UVW=p_uvw) / & - matxs % get_xs('fission', p_g, UVW=p_uvw) * flux + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) * flux else score = score + keff * & fission_bank(n_bank - p % n_bank + k) % wgt * & - matxs % get_xs('decay rate', p_g, UVW=p_uvw, dg=g) * flux + get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * flux end if ! if the delayed group filter is present, tally to corresponding @@ -1904,13 +1920,13 @@ contains d = filt % groups(d_bin) if (i_nuclide > 0) then - score = nucxs % get_xs('decay rate', p_g, UVW=p_uvw, dg=d) * & - nucxs % get_xs('delayed-nu-fission', p_g, UVW=p_uvw, & - dg=d) * atom_density * flux + score = atom_density * flux * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) else - score = matxs % get_xs('decay rate', p_g, UVW=p_uvw, dg=d) * & - matxs % get_xs('delayed-nu-fission', p_g, UVW=p_uvw, & - dg=d) * flux + score = flux * & + get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) end if call score_fission_delayed_dg(t, d_bin, score, score_index) @@ -1927,12 +1943,12 @@ contains do d = 1, num_delayed_groups if (i_nuclide > 0) then score = score + atom_density * flux * & - nucxs % get_xs('decay rate', p_g, UVW=p_uvw, dg=d) * & - nucxs % get_xs('delayed-nu-fission', p_g, UVW=p_uvw, dg=d) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) else score = score + flux * & - matxs % get_xs('decay rate', p_g, UVW=p_uvw, dg=d) * & - matxs % get_xs('delayed-nu-fission', p_g, UVW=p_uvw, dg=d) + get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) end if end do end if @@ -1957,19 +1973,20 @@ contains end if if (i_nuclide > 0) then score = score * atom_density * & - nucxs % get_xs('kappa-fission', p_g, UVW=p_uvw) / & - matxs % get_xs('absorption', p_g, UVW=p_uvw) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_KAPPA_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) else score = score * & - matxs % get_xs('kappa-fission', p_g, UVW=p_uvw) / & - matxs % get_xs('absorption', p_g, UVW=p_uvw) + get_macro_xs_c(p % material, MG_GET_XS_KAPPA_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if else if (i_nuclide > 0) then - score = nucxs % get_xs('kappa-fission', p_g, UVW=p_uvw) * & + score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_KAPPA_FISSION, p_g) * & atom_density * flux else - score = matxs % get_xs('kappa-fission', p_g, UVW=p_uvw) * flux + score = flux * & + get_macro_xs_c(p % material, MG_GET_XS_KAPPA_FISSION, p_g) end if end if @@ -1989,7 +2006,15 @@ contains end do SCORE_LOOP - nullify(matxs, nucxs) + ! Reset temporary Mgxs indices + call reset_macro_angle_index_c(p % material, last_mat_pol, last_mat_azi, & + last_mat_uvw); + + if (i_nuclide > 0) then + call reset_nuclide_temperature_index_c(i_nuclide, last_nuc_temp) + call reset_nuclide_angle_index_c(i_nuclide, last_nuc_pol, last_nuc_azi, & + last_nuc_uvw) + end if end subroutine score_general_mg !=============================================================================== diff --git a/src/tallies/tally_filter_energy.F90 b/src/tallies/tally_filter_energy.F90 index 93da69edda..f230d438e8 100644 --- a/src/tallies/tally_filter_energy.F90 +++ b/src/tallies/tally_filter_energy.F90 @@ -6,7 +6,7 @@ module tally_filter_energy use constants use error use hdf5_interface - use mgxs_header, only: num_energy_groups, rev_energy_bins + use mgxs_interface, only: num_energy_groups, rev_energy_bins use particle_header, only: Particle use settings, only: run_CE use string, only: to_str diff --git a/src/tracking.F90 b/src/tracking.F90 index 2ba62a8dd8..c832ca9ccc 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -9,7 +9,7 @@ module tracking check_cell_overlap use material_header, only: materials, Material use message_passing - use mgxs_header + use mgxs_interface use nuclide_header use particle_header, only: LocalCoord, Particle use physics, only: collision @@ -29,21 +29,6 @@ module tracking implicit none - interface - subroutine calculate_xs_c(i_mat, gin, sqrtkT, uvw, total_xs, abs_xs, & - nu_fiss_xs) bind(C, name='calculate_xs') - use ISO_C_BINDING - implicit none - integer(C_INT), value, intent(in) :: i_mat - integer(C_INT), value, intent(in) :: gin - real(C_DOUBLE), value, intent(in) :: sqrtkT - real(C_DOUBLE), intent(in) :: uvw(1:3) - real(C_DOUBLE), intent(inout) :: total_xs - real(C_DOUBLE), intent(inout) :: abs_xs - real(C_DOUBLE), intent(inout) :: nu_fiss_xs - end subroutine calculate_xs_c - end interface - contains !=============================================================================== @@ -129,10 +114,6 @@ contains end if else ! Get the MG data - !!TODO: Remove Fortran call - needed until I'm done replacing Fortran - !!with C++ code because it sets index_temp - call macro_xs(p % material) % obj % calculate_xs(p % g, p % sqrtkT, & - p % coord(p % n_coord) % uvw, material_xs) call calculate_xs_c(p % material, p % g, p % sqrtkT, & p % coord(p % n_coord) % uvw, material_xs % total, & material_xs % absorption, material_xs % nu_fission) diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 8afdb7f039..b79d02e200 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -24,6 +24,8 @@ XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable, if (fissionable) { fission = double_3dvec(n_pol, double_2dvec(n_azi, double_1dvec(energy_groups, 0.))); + nu_fission = double_3dvec(n_pol, double_2dvec(n_azi, + double_1dvec(energy_groups, 0.))); prompt_nu_fission = double_3dvec(n_pol, double_2dvec(n_azi, double_1dvec(energy_groups, 0.))); kappa_fission = double_3dvec(n_pol, double_2dvec(n_azi, @@ -514,6 +516,17 @@ void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } } + // Combine prompt_nu_fission and delayed_nu_fission into nu_fission + for (int p = 0; p < n_pol; p++) { + for (int a = 0; a < n_azi; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + nu_fission[p][a][gin] = + std::accumulate(delayed_nu_fission[p][a][gin].begin(), + delayed_nu_fission[p][a][gin].end(), + prompt_nu_fission[p][a][gin]); + } + } + } } @@ -668,6 +681,8 @@ void XsData::combine(std::vector those_xs, double_1dvec& scalars) inverse_velocity[p][a][gin] += scalar * that->inverse_velocity[p][a][gin]; if (that->prompt_nu_fission.size() > 0) { + nu_fission[p][a][gin] += + scalar * that->nu_fission[p][a][gin]; prompt_nu_fission[p][a][gin] += scalar * that->prompt_nu_fission[p][a][gin]; kappa_fission[p][a][gin] += diff --git a/src/xsdata.h b/src/xsdata.h index fec28aece1..478f2e7aa1 100644 --- a/src/xsdata.h +++ b/src/xsdata.h @@ -38,6 +38,7 @@ class XsData { // [phi][theta][incoming group] double_3dvec total; double_3dvec absorption; + double_3dvec nu_fission; double_3dvec prompt_nu_fission; double_3dvec kappa_fission; double_3dvec fission; From a32678865d2af29d7171bd2aa85bcfcf2d77a9e8 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Wed, 13 Jun 2018 20:24:16 -0400 Subject: [PATCH 021/100] Cathartically removing the fortran Mgxs code --- src/mgxs_header.F90 | 3592 -------------------------------------- src/scattdata_header.F90 | 852 --------- 2 files changed, 4444 deletions(-) delete mode 100644 src/mgxs_header.F90 delete mode 100644 src/scattdata_header.F90 diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 deleted file mode 100644 index 09db7217ea..0000000000 --- a/src/mgxs_header.F90 +++ /dev/null @@ -1,3592 +0,0 @@ -module mgxs_header - - use, intrinsic :: ISO_FORTRAN_ENV - use, intrinsic :: ISO_C_BINDING - - use algorithm, only: find, sort - use constants, only: MAX_WORD_LEN, ZERO, ONE, TWO, PI, MACROSCOPIC_AWR - use error, only: fatal_error - use hdf5_interface - use material_header, only: material - use math, only: evaluate_legendre - use nuclide_header, only: MaterialMacroXS - use random_lcg, only: prn - use string - use stl_vector, only: VectorInt, VectorReal - -!=============================================================================== -! XS* contains the temperature-dependent cross section data for an MGXS -!=============================================================================== - - type :: XsDataIso - ! Microscopic cross sections - real(8), allocatable :: total(:) ! total cross section - real(8), allocatable :: absorption(:) ! absorption cross section - class(ScattData), allocatable :: scatter ! scattering info - real(8), allocatable :: delayed_nu_fission(:,:) ! Delayed fission matrix (Dg x Gin) - real(8), allocatable :: prompt_nu_fission(:) ! Prompt fission vector (Gin) - real(8), allocatable :: kappa_fission(:) ! Kappa fission - real(8), allocatable :: fission(:) ! Neutron production - real(8), allocatable :: decay_rate(:) ! Delayed neutron precursor decay rate - real(8), allocatable :: inverse_velocity(:) ! Inverse neutron velocity - real(8), allocatable :: chi_delayed(:, :, :) ! Delayed fission spectra - real(8), allocatable :: chi_prompt(:, :) ! Prompt fission spectra - end type XsDataIso - - type :: XsDataAngle - ! Microscopic cross sections - ! In all cases, right-most indices are theta, phi - real(8), allocatable :: total(:, :, :) ! total cross section - real(8), allocatable :: absorption(:, :, :) ! absorption cross section - type(ScattDataContainer), allocatable :: scatter(:, :) ! scattering info - real(8), allocatable :: delayed_nu_fission(:, :, :, :) ! Delayed fission matrix (Gout x Gin) - real(8), allocatable :: prompt_nu_fission(:, :, :) ! Prompt fission matrix (Gout x Gin) - real(8), allocatable :: kappa_fission(:, :, :) ! Kappa fission - real(8), allocatable :: fission(:, :, :) ! Neutron production - real(8), allocatable :: decay_rate(:, :, :) ! Delayed neutron precursor decay rate - real(8), allocatable :: inverse_velocity(:, :, :) ! Inverse neutron velocity - real(8), allocatable :: chi_delayed(:, :, :, :, :) ! Delayed fission spectra - real(8), allocatable :: chi_prompt(:, :, :, :) ! Prompt fission spectra - end type XsDataAngle - -!=============================================================================== -! MGXS contains the base mgxs data for a nuclide/material -!=============================================================================== - - type, abstract :: Mgxs - character(len=MAX_WORD_LEN) :: name ! name of dataset, e.g. UO2 - real(8) :: awr ! Atomic Weight Ratio - real(8), allocatable :: kTs(:) ! temperature in eV (k*T) - - ! Fission information - logical :: fissionable ! mgxs object is fissionable? - integer :: scatter_format ! either legendre, histogram, or tabular. - integer :: num_delayed_groups ! Num delayed groups - - ! Caching information - integer :: index_temp ! temperature index for nuclide - - contains - procedure(mgxs_from_hdf5_), deferred :: from_hdf5 ! Load the data - procedure(mgxs_combine_), deferred :: combine ! initializes object - procedure(mgxs_get_xs_), deferred :: get_xs ! Get the requested xs - - ! Sample the outgoing energy from a fission event - procedure(mgxs_sample_fission_), deferred :: sample_fission_energy - - ! Sample the outgoing energy and angle from a scatter event - procedure(mgxs_sample_scatter_), deferred :: sample_scatter - - ! Calculate the material specific MGXS data from the nuclides - procedure(mgxs_calculate_xs_), deferred :: calculate_xs - - ! Find the temperature - procedure :: find_temperature => mgxs_find_temperature - end type Mgxs - -!=============================================================================== -! MGXSCONTAINER pointer array for storing Nuclides -!=============================================================================== - - type MgxsContainer - class(Mgxs), pointer :: obj - end type MgxsContainer - -!=============================================================================== -! Interfaces for MGXS -!=============================================================================== - - abstract interface - subroutine mgxs_from_hdf5_(this, xs_id, energy_groups, delayed_groups, & - temperature, method, tolerance, max_order, legendre_to_tabular, & - legendre_to_tabular_points) - import Mgxs, HID_T, VectorReal - class(Mgxs), intent(inout) :: this ! Working Object - integer(HID_T), intent(in) :: xs_id ! Library data - integer, intent(in) :: energy_groups ! Number of energy groups - integer, intent(in) :: delayed_groups ! Number of delayed groups - type(VectorReal), intent(in) :: temperature ! list of desired temperatures - integer, intent(inout) :: method ! Type of temperature access - real(8), intent(in) :: tolerance ! Tolerance on method - integer, intent(in) :: max_order ! Maximum requested order - logical, intent(in) :: legendre_to_tabular ! Convert Legendres to Tabular? - integer, intent(in) :: legendre_to_tabular_points ! Number of points to use - ! in that conversion - end subroutine mgxs_from_hdf5_ - - subroutine mgxs_combine_(this, temps, mat, nuclides, energy_groups, & - delayed_groups, max_order, tolerance, method) - import Mgxs, Material, MgxsContainer, VectorReal - class(Mgxs), intent(inout) :: this ! The Mgxs to initialize - type(VectorReal), intent(in) :: temps ! Temperatures to obtain - type(Material), pointer, intent(in) :: mat ! base material - type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from - integer, intent(in) :: energy_groups ! Number of energy groups - integer, intent(in) :: delayed_groups ! Number of delayed groups - integer, intent(in) :: max_order ! Maximum requested order - real(8), intent(in) :: tolerance ! Tolerance on method - integer, intent(in) :: method ! Type of temperature access - end subroutine mgxs_combine_ - - pure function mgxs_get_xs_(this, xstype, gin, gout, uvw, mu, dg) result(xs_val) - import Mgxs - class(Mgxs), intent(in) :: this - character(*), intent(in) :: xstype ! Cross Section Type - integer, intent(in) :: gin ! Incoming Energy group - integer, optional, intent(in) :: gout ! Outgoing Group - real(8), optional, intent(in) :: uvw(3) ! Requested Angle - real(8), optional, intent(in) :: mu ! Change in angle - integer, optional, intent(in) :: dg ! Delayed group - real(8) :: xs_val ! Resultant xs - end function mgxs_get_xs_ - - subroutine mgxs_sample_fission_(this, gin, uvw, dg, gout) - import Mgxs - class(Mgxs), intent(in) :: this - integer, intent(in) :: gin ! Incoming energy group - real(8), intent(in) :: uvw(3) ! Particle Direction - integer, intent(out) :: dg ! Delayed group - integer, intent(out) :: gout ! Sampled outgoing group - - end subroutine mgxs_sample_fission_ - - subroutine mgxs_sample_scatter_(this, uvw, gin, gout, mu, wgt) - import Mgxs - class(Mgxs), intent(in) :: this - real(8), intent(in) :: uvw(3) ! Incoming neutron direction - integer, intent(in) :: gin ! Incoming neutron group - integer, intent(out) :: gout ! Sampled outgoin group - real(8), intent(out) :: mu ! Sampled change in angle - real(8), intent(inout) :: wgt ! Particle weight - end subroutine mgxs_sample_scatter_ - - subroutine mgxs_calculate_xs_(this, gin, sqrtkT, uvw, xs) - import Mgxs, MaterialMacroXS - class(Mgxs), intent(inout) :: this - integer, intent(in) :: gin ! Incoming neutron group - real(8), intent(in) :: sqrtkT ! Material temperature - real(8), intent(in) :: uvw(3) ! Incoming neutron direction - type(MaterialMacroXS), intent(inout) :: xs ! Resultant Mgxs Data - end subroutine mgxs_calculate_xs_ - end interface - -!=============================================================================== -! MGXSISO contains the base MGXS data specifically for -! isotropically weighted MGXS -!=============================================================================== - - type, extends(Mgxs) :: MgxsIso - type(XsDataIso), allocatable :: xs(:) ! One for every temperature - contains - procedure :: from_hdf5 => mgxsiso_from_hdf5 ! Initialize Nuclidic MGXS Data - procedure :: get_xs => mgxsiso_get_xs ! Gets Size of Data w/in Object - procedure :: combine => mgxsiso_combine ! inits object - procedure :: sample_fission_energy => mgxsiso_sample_fission_energy - procedure :: sample_scatter => mgxsiso_sample_scatter - procedure :: calculate_xs => mgxsiso_calculate_xs - end type MgxsIso - -!=============================================================================== -! MGXSANGLE contains the base MGXS data specifically for -! angular flux weighted MGXS -!=============================================================================== - - type, extends(Mgxs) :: MgxsAngle - type(XsDataAngle), allocatable :: xs(:) ! One for every temperature - integer :: n_pol ! Number of polar angles - integer :: n_azi ! Number of azimuthal angles - real(8), allocatable :: polar(:) ! polar angles - real(8), allocatable :: azimuthal(:) ! azimuthal angles - - contains - procedure :: from_hdf5 => mgxsang_from_hdf5 ! Initialize Nuclidic MGXS Data - procedure :: get_xs => mgxsang_get_xs ! Gets Size of Data w/in Object - procedure :: combine => mgxsang_combine ! inits object - procedure :: sample_fission_energy => mgxsang_sample_fission_energy - procedure :: sample_scatter => mgxsang_sample_scatter - procedure :: calculate_xs => mgxsang_calculate_xs - end type MgxsAngle - - ! Cross section arrays - type(MgxsContainer), allocatable, target :: nuclides_MG(:) - - ! Cross section caches - type(MgxsContainer), target, allocatable :: macro_xs(:) - - ! Number of energy groups - integer(C_INT) :: num_energy_groups - - ! Number of delayed groups - integer(C_INT) :: num_delayed_groups - - ! Energy group structure with decreasing energy - real(8), allocatable :: energy_bins(:) - - ! Midpoint of the energy group structure - real(8), allocatable :: energy_bin_avg(:) - - ! Energy group structure with increasing energy - real(8), allocatable :: rev_energy_bins(:) - -contains - -!=============================================================================== -! MGXS*_FROM_HDF5 reads in the data from the HDF5 Library. At the point of entry -! the file would have been opened and metadata read. -!=============================================================================== - - subroutine mgxs_from_hdf5(this, xs_id, temperature, method, tolerance, & - temps_to_read, order_dim) - class(Mgxs), intent(inout) :: this ! Working Object - integer(HID_T), intent(in) :: xs_id ! Group in H5 file - type(VectorReal), intent(in) :: temperature ! list of desired temperatures - integer, intent(inout) :: method ! Type of temperature access - real(8), intent(in) :: tolerance ! Tolerance on method - type(VectorInt), intent(out) :: temps_to_read ! Temperatures to read - integer, intent(out) :: order_dim ! Scattering data order size - - integer(HID_T) :: kT_group - character(MAX_WORD_LEN), allocatable :: dset_names(:) - real(8), allocatable :: temps_available(:) ! temperatures available - real(8) :: temp_desired - real(8) :: temp_actual - character(MAX_WORD_LEN) :: temp_str - real(8) :: dangle - integer :: ipol, iazi - - ! Get name of dataset from group - this % name = get_name(xs_id) - - ! Get rid of leading '/' - this % name = trim(this % name(2:)) - - if (attribute_exists(xs_id, "atomic_weight_ratio")) then - call read_attribute(this % awr, xs_id, "atomic_weight_ratio") - else - this % awr = MACROSCOPIC_AWR - end if - - ! Determine temperatures available - kT_group = open_group(xs_id, 'kTs') - call get_datasets(kT_group, dset_names) - allocate(temps_available(size(dset_names))) - do i = 1, size(dset_names) - ! Read temperature value - call read_dataset(temps_available(i), kT_group, trim(dset_names(i))) - ! Convert eV to Kelvin - temps_available(i) = temps_available(i) / K_BOLTZMANN - end do - call sort(temps_available) - - ! If only one temperature is available, revert to nearest temperature - if (size(temps_available) == 1 .and. & - method == TEMPERATURE_INTERPOLATION) then - call warning("Cross sections for " // trim(this % name) // " are only & - &available at one temperature. Reverting to nearest temperature & - &method.") - method = TEMPERATURE_NEAREST - end if - - select case (method) - case (TEMPERATURE_NEAREST) - ! Determine actual temperatures to read - TEMP_LOOP: do i = 1, temperature % size() - temp_desired = temperature % data(i) - i_closest = minloc(abs(temps_available - temp_desired), dim=1) - temp_actual = temps_available(i_closest) - if (abs(temp_actual - temp_desired) < tolerance) then - if (find(temps_to_read, nint(temp_actual)) == -1) then - call temps_to_read % push_back(nint(temp_actual)) - end if - else - call fatal_error("MGXS library does not contain cross sections & - &for " // trim(this % name) // " at or near " // & - trim(to_str(nint(temp_desired))) // " K.") - end if - end do TEMP_LOOP - - case (TEMPERATURE_INTERPOLATION) - ! If temperature interpolation or multipole is selected, get a list of - ! bounding temperatures for each actual temperature present in the model - TEMPS_LOOP: do i = 1, temperature % size() - temp_desired = temperature % data(i) - - do j = 1, size(temps_available) - 1 - if (temps_available(j) <= temp_desired .and. & - temp_desired < temps_available(j + 1)) then - if (find(temps_to_read, nint(temps_available(j))) == -1) then - call temps_to_read % push_back(nint(temps_available(j))) - end if - if (find(temps_to_read, nint(temps_available(j + 1))) == -1) then - call temps_to_read % push_back(nint(temps_available(j + 1))) - end if - cycle TEMPS_LOOP - end if - end do - - call fatal_error("MGXS library does not contain cross sections & - &for " // trim(this % name) // " at temperatures that bound " // & - trim(to_str(nint(temp_desired))) // " K.") - end do TEMPS_LOOP - end select - - ! Sort temperatures to read - call sort(temps_to_read) - - ! Get temperatures - n_temperature = temps_to_read % size() - allocate(this % kTs(n_temperature)) - do i = 1, n_temperature - ! Get temperature as a string - temp_str = trim(to_str(temps_to_read % data(i))) // "K" - - ! Read exact temperature value - call read_dataset(this % kTs(i), kT_group, trim(temp_str)) - end do - call close_group(kT_group) - - ! Allocate the XS object for the number of temperatures - select type(this) - type is (MgxsIso) - allocate(this % xs(n_temperature)) - type is (MgxsAngle) - allocate(this % xs(n_temperature)) - end select - - ! Load the remaining metadata - if (attribute_exists(xs_id, "scatter_format")) then - call read_attribute(temp_str, xs_id, "scatter_format") - temp_str = trim(temp_str) - if (to_lower(temp_str) == 'legendre') then - this % scatter_format = ANGLE_LEGENDRE - else if (to_lower(temp_str) == 'histogram') then - this % scatter_format = ANGLE_HISTOGRAM - else if (to_lower(temp_str) == 'tabular') then - this % scatter_format = ANGLE_TABULAR - else - call fatal_error("Invalid scatter_format option!") - end if - else - this % scatter_format = ANGLE_LEGENDRE - end if - if (attribute_exists(xs_id, "scatter_shape")) then - call read_attribute(temp_str, xs_id, "scatter_shape") - temp_str = trim(temp_str) - if (to_lower(temp_str) /= "[g][g'][order]") then - call fatal_error("Invalid scatter_shape option!") - end if - end if - if (attribute_exists(xs_id, "fissionable")) then - call read_attribute(this % fissionable, xs_id, "fissionable") - else - call fatal_error("Fissionable element must be set!") - end if - - ! Get the library's value for the order - if (attribute_exists(xs_id, "order")) then - call read_attribute(order_dim, xs_id, "order") - else - call fatal_error("Order must be provided!") - end if - - ! Store the dimensionality of the data in order_dim. - ! For Legendre data, we usually refer to it as Pn where n is the order. - ! However Pn has n+1 sets of points (since you need to count the P0 - ! moment). Adjust for that. Histogram and Tabular formats dont need this - ! adjustment. - if (this % scatter_format == ANGLE_LEGENDRE) then - order_dim = order_dim + 1 - else - order_dim = order_dim - end if - - ! Get angular meta-data and allocate as needed based off of the - ! information therein - select type(this) - type is (MgxsAngle) - if (attribute_exists(xs_id, "num_polar")) then - call read_attribute(this % n_pol, xs_id, "num_polar") - else - call fatal_error("num_polar must be provided!") - end if - - if (attribute_exists(xs_id, "num_azimuthal")) then - call read_attribute(this % n_azi, xs_id, "num_azimuthal") - else - call fatal_error("num_azimuthal must be provided!") - end if - - ! Set angle data to use equally-spaced bins - allocate(this % polar(this % n_pol)) - dangle = PI / real(this % n_pol, 8) - do ipol = 1, this % n_pol - this % polar(ipol) = (real(ipol, 8) - HALF) * dangle - end do - allocate(this % azimuthal(this % n_azi)) - dangle = TWO * PI / real(this % n_azi, 8) - do iazi = 1, this % n_azi - this % azimuthal(iazi) = -PI + (real(iazi, 8) - HALF) * dangle - end do - end select - - end subroutine mgxs_from_hdf5 - - subroutine mgxsiso_from_hdf5(this, xs_id, energy_groups, delayed_groups, & - temperature, method, tolerance, max_order, & - legendre_to_tabular, legendre_to_tabular_points) - class(MgxsIso), intent(inout) :: this ! Working Object - integer(HID_T), intent(in) :: xs_id ! Group in H5 file - integer, intent(in) :: energy_groups ! Number of energy groups - integer, intent(in) :: delayed_groups ! Number of delayed groups - type(VectorReal), intent(in) :: temperature ! list of desired temperatures - integer, intent(inout) :: method ! Type of temperature access - real(8), intent(in) :: tolerance ! Tolerance on method - integer, intent(in) :: max_order ! Maximum requested order - logical, intent(in) :: legendre_to_tabular ! Convert Legendres to Tabular? - integer, intent(in) :: legendre_to_tabular_points ! Number of points to use - ! in that conversion - - character(MAX_LINE_LEN) :: temp_str - integer(HID_T) :: xsdata, xsdata_grp, scatt_grp - integer :: ndims - integer(HSIZE_T) :: dims(2) - real(8), allocatable :: temp_arr(:), temp_2d(:, :) - real(8), allocatable :: temp_beta(:, :), temp_3d(:, :, :) - real(8) :: dmu, mu, norm, chi_sum - integer :: order, order_dim, gin, gout, l, imu, length - type(VectorInt) :: temps_to_read - integer :: t, dg, order_data - type(Jagged2D), allocatable :: input_scatt(:), scatt_coeffs(:) - type(Jagged1D), allocatable :: temp_mult(:) - integer, allocatable :: gmin(:), gmax(:) - - ! Call generic data gathering routine (will populate the metadata) - call mgxs_from_hdf5(this, xs_id, temperature, method, tolerance, & - temps_to_read, order_data) - - ! Set the number of delayed groups - this % num_delayed_groups = delayed_groups - - ! Load the more specific data - do t = 1, temps_to_read % size() - associate(xs => this % xs(t)) - - ! Get temperature as a string - temp_str = trim(to_str(temps_to_read % data(t))) // "K" - xsdata_grp = open_group(xs_id, trim(temp_str)) - - ! Allocate data for all the cross sections - allocate(xs % total(energy_groups)) - allocate(xs % absorption(energy_groups)) - allocate(xs % delayed_nu_fission(delayed_groups, energy_groups)) - allocate(xs % prompt_nu_fission(energy_groups)) - allocate(xs % fission(energy_groups)) - allocate(xs % kappa_fission(energy_groups)) - allocate(xs % decay_rate(delayed_groups)) - allocate(xs % inverse_velocity(energy_groups)) - allocate(xs % chi_delayed(delayed_groups, energy_groups, & - energy_groups)) - allocate(xs % chi_prompt(energy_groups, energy_groups)) - - ! Set all fissionable terms to zero - xs % delayed_nu_fission = ZERO - xs % prompt_nu_fission = ZERO - xs % fission = ZERO - xs % kappa_fission = ZERO - xs % chi_delayed = ZERO - xs % chi_prompt = ZERO - xs % decay_rate = ZERO - xs % inverse_velocity = ZERO - - if (this % fissionable) then - - ! Allocate temporary array for beta - allocate(temp_beta(delayed_groups, energy_groups)) - - ! Set beta - if (object_exists(xsdata_grp, "beta")) then - - ! Get the dimensions of the beta dataset - xsdata = open_dataset(xsdata_grp, "beta") - call get_ndims(xsdata, ndims) - - ! Beta is input as (delayed_groups) - if (ndims == 1) then - - ! Allocate temporary array for beta - allocate(temp_arr(delayed_groups)) - - ! Read beta - call read_dataset(temp_arr, xsdata_grp, "beta") - - do dg = 1, delayed_groups - do gin = 1, energy_groups - temp_beta(dg, gin) = temp_arr(dg) - end do - end do - - ! Deallocate temporary beta array - deallocate(temp_arr) - - ! Beta is input as (delayed_groups, energy_groups) - else if (ndims == 2) then - - ! Allocate temporary array for beta - allocate(temp_arr(delayed_groups * energy_groups)) - - ! Read beta - call read_dataset(temp_arr, xsdata_grp, "beta") - - ! Reshape array and set to dedicated beta array - temp_beta = reshape(temp_arr, (/delayed_groups, energy_groups/)) - - ! Deallocate temporary beta array - deallocate(temp_arr) - - else - call fatal_error("beta must be provided as a 1D or 2D array") - end if - - call close_dataset(xsdata) - else - temp_beta = ZERO - end if - - ! If chi provided, set chi-prompt and chi-delayed - if (object_exists(xsdata_grp, "chi")) then - - ! Allocate temporary array for chi - allocate(temp_arr(energy_groups)) - - ! Read chi - call read_dataset(temp_arr, xsdata_grp, "chi") - - do gin = 1, energy_groups - do gout = 1, energy_groups - xs % chi_prompt(gout, gin) = temp_arr(gout) - end do - - ! Normalize chi-prompt so its CDF goes to 1 - chi_sum =sum(xs % chi_prompt(:, gin)) - if (chi_sum == ZERO) then - call fatal_error("Encountered chi for a group that sums to & - &zero") - else - xs % chi_prompt(:, gin) = xs % chi_prompt(:, gin) / chi_sum - end if - end do - - ! Set chi-delayed to chi-prompt - do dg = 1, delayed_groups - xs % chi_delayed(dg, :, :) = xs % chi_prompt(:, :) - end do - - ! Deallocate temporary chi array - deallocate(temp_arr) - end if - - ! If nu-fission provided, set prompt-nu_-ission and - ! delayed-nu-fission. If nu fission is a matrix, set chi-prompt and - ! chi-delayed. - if (object_exists(xsdata_grp, "nu-fission")) then - - ! Get the dimensions of the nu-fission dataset - xsdata = open_dataset(xsdata_grp, "nu-fission") - call get_ndims(xsdata, ndims) - - ! If nu-fission is a vector - if (ndims == 1) then - - ! Get nu-fission - call read_dataset(xs % prompt_nu_fission, xsdata_grp, & - "nu-fission") - - ! Set delayed-nu-fission and correct prompt-nu-fission with - ! beta - do gin = 1, energy_groups - do dg = 1, delayed_groups - - ! Set delayed-nu-fission using delayed neutron fraction - xs % delayed_nu_fission(dg, gin) = temp_beta(dg, gin) * & - xs % prompt_nu_fission(gin) - end do - - ! Correct prompt-nu-fission using delayed neutron fraction - if (delayed_groups > 0) then - xs % prompt_nu_fission(gin) = (1 - sum(temp_beta(:, gin))) & - * xs % prompt_nu_fission(gin) - end if - end do - - ! If nu-fission is a matrix, set prompt-nu-fission, - ! delayed-nu-fission, chi-prompt, and chi-delayed. - else if (ndims == 2) then - - ! chi is embedded in nu-fission -> extract chi - allocate(temp_arr(energy_groups * energy_groups)) - call read_dataset(temp_arr, xsdata_grp, "nu-fission") - allocate(temp_2d(energy_groups, energy_groups)) - temp_2d = reshape(temp_arr, (/energy_groups, energy_groups/)) - - ! Deallocate temporary 1D array for nu-fission matrix - deallocate(temp_arr) - - ! Set the vector nu-fission from the matrix nu-fission - do gin = 1, energy_groups - xs % prompt_nu_fission(gin) = sum(temp_2d(:, gin)) - end do - - ! Set delayed-nu-fission and correct prompt-nu-fission with - ! beta - do gin = 1, energy_groups - do dg = 1, delayed_groups - - ! Set delayed-nu-fission using delayed neutron fraction - xs % delayed_nu_fission(dg, gin) = temp_beta(dg, gin) * & - xs % prompt_nu_fission(gin) - end do - - ! Correct prompt-nu-fission using delayed neutron fraction - if (delayed_groups > 0) then - xs % prompt_nu_fission(gin) = (1 - sum(temp_beta(:, gin))) & - * xs % prompt_nu_fission(gin) - end if - end do - - ! Now pull out information needed for chi - xs % chi_prompt(:, :) = temp_2d - - ! Deallocate temporary 2D array for nu-fission matrix - deallocate(temp_2d) - - ! Normalize chi so its CDF goes to 1 - do gin = 1, energy_groups - chi_sum = sum(xs % chi_prompt(:, gin)) - if (chi_sum == ZERO) then - call fatal_error("Encountered chi for a group that sums to & - &zero") - else - xs % chi_prompt(:, gin) = xs % chi_prompt(:, gin) / chi_sum - end if - end do - - ! Set chi-delayed to chi-prompt - do dg = 1, delayed_groups - xs % chi_delayed(dg, :, :) = xs % chi_prompt(:, :) - end do - else - call fatal_error("nu-fission must be provided as a 1D or 2D & - &array") - end if - - call close_dataset(xsdata) - end if - - ! If chi-prompt provided, set chi-prompt - if (object_exists(xsdata_grp, "chi-prompt")) then - - ! Allocate temporary array for chi-prompt - allocate(temp_arr(energy_groups)) - - ! Get array with chi-prompt - call read_dataset(temp_arr, xsdata_grp, "chi-prompt") - - do gin = 1, energy_groups - do gout = 1, energy_groups - xs % chi_prompt(gout, gin) = temp_arr(gout) - end do - - ! Normalize chi so its CDF goes to 1 - chi_sum = sum(xs % chi_prompt(:, gin)) - if (chi_sum == ZERO) then - call fatal_error("Encountered chi prompt for a group that & - &sums to zero") - else - xs % chi_prompt(:, gin) = xs % chi_prompt(:, gin) / chi_sum - end if - end do - - ! Deallocate temporary array for chi-prompt - deallocate(temp_arr) - end if - - ! If chi-delayed provided, set chi-delayed - if (object_exists(xsdata_grp, "chi-delayed")) then - - ! Get the dimensions of the chi-delayed dataset - xsdata = open_dataset(xsdata_grp, "chi-delayed") - call get_ndims(xsdata, ndims) - - ! If chi-delayed is a vector - if (ndims == 1) then - - ! Allocate temporary array for chi-delayed - allocate(temp_arr(energy_groups)) - - ! Get chi-delayed - call read_dataset(temp_arr, xsdata_grp, "chi-delayed") - - do dg = 1, delayed_groups - do gin = 1, energy_groups - do gout = 1, energy_groups - xs % chi_delayed(dg, gout, gin) = temp_arr(gout) - end do - - ! Normalize chi so its CDF goes to 1 - chi_sum = sum(xs % chi_delayed(dg, :, gin)) - if (chi_sum == ZERO) then - call fatal_error("Encountered chi delayed for a group & - &that sums to zero") - else - xs % chi_delayed(dg, :, gin) = & - xs % chi_delayed(dg, :, gin) / chi_sum - end if - end do - end do - - ! Deallocate temporary array for chi-delayed - deallocate(temp_arr) - - else if (ndims == 2) then - - ! Allocate temporary array for chi-delayed - allocate(temp_arr(delayed_groups * energy_groups)) - - ! Get chi-delayed - call read_dataset(temp_arr, xsdata_grp, "chi-delayed") - allocate(temp_2d(delayed_groups, energy_groups)) - temp_2d = reshape(temp_arr, (/delayed_groups, energy_groups/)) - - do dg = 1, delayed_groups - do gin = 1, energy_groups - do gout = 1, energy_groups - xs % chi_delayed(dg, gout, gin) = temp_2d(dg, gout) - end do - - ! Normalize chi so its CDF goes to 1 - chi_sum = sum(xs % chi_delayed(dg, :, gin)) - if (chi_sum == ZERO) then - call fatal_error("Encountered chi delayed for a group & - &that sums to zero") - else - xs % chi_delayed(dg, :, gin) = & - xs % chi_delayed(dg, :, gin) / chi_sum - end if - end do - end do - - ! Deallocate temporary arrays for chi-delayed - deallocate(temp_arr) - deallocate(temp_2d) - - else - call fatal_error("chi-delayed must be provided as a 1D or 2D & - &array") - end if - - call close_dataset(xsdata) - end if - - ! If prompt-nu-fission present, set prompt-nu-fission - if (object_exists(xsdata_grp, "prompt-nu-fission")) then - - ! Get the dimensions of the prompt-nu-fission dataset - xsdata = open_dataset(xsdata_grp, "prompt-nu-fission") - call get_ndims(xsdata, ndims) - - ! If prompt-nu-fission is a vector - if (ndims == 1) then - - ! Set prompt_nu_fission - call read_dataset(xs % prompt_nu_fission, xsdata_grp, & - "prompt-nu-fission") - - ! If prompt-nu-fission is a matrix, set prompt_nu_fission and - ! chi_prompt. - else if (ndims == 2) then - - ! chi_prompt is embedded in prompt_nu_fission -> extract - ! chi_prompt - allocate(temp_arr(energy_groups * energy_groups)) - call read_dataset(temp_arr, xsdata_grp, "prompt-nu-fission") - allocate(temp_2d(energy_groups, energy_groups)) - temp_2d = reshape(temp_arr, (/energy_groups, energy_groups/)) - - ! Deallocate temporary 1D array for prompt_nu_fission matrix - deallocate(temp_arr) - - ! Set the vector prompt-nu-fission from the matrix - ! prompt-nu-fission - do gin = 1, energy_groups - xs % prompt_nu_fission(gin) = sum(temp_2d(:, gin)) - end do - - ! Now pull out information needed for chi - xs % chi_prompt(:, :) = temp_2d - - ! Deallocate temporary 2D array for nu_fission matrix - deallocate(temp_2d) - - ! Normalize chi so its CDF goes to 1 - do gin = 1, energy_groups - chi_sum = sum(xs % chi_prompt(:, gin)) - if (chi_sum == ZERO) then - call fatal_error("Encountered chi prompt for a group & - &that sums to zero") - else - xs % chi_prompt(:, gin) = xs % chi_prompt(:, gin) / chi_sum - end if - end do - else - call fatal_error("prompt-nu-fission must be provided as a 1D & - &or 2D array") - end if - - call close_dataset(xsdata) - end if - - ! If delayed-nu-fission provided, set delayed-nu-fission. If - ! delayed-nu-fission is a matrix, set chi-delayed. - if (object_exists(xsdata_grp, "delayed-nu-fission")) then - - ! Get the dimensions of the delayed-nu-fission dataset - xsdata = open_dataset(xsdata_grp, "delayed-nu-fission") - call get_ndims(xsdata, ndims) - - ! If delayed-nu-fission is a vector - if (ndims == 1) then - - ! If beta is zeros, raise error - if (temp_beta(1,1) == ZERO) then - call fatal_error("cannot set delayed-nu-fission with a 1D & - &array if beta not provided") - end if - - ! Allocate temporary array for delayed-nu-fission - allocate(temp_arr(energy_groups)) - - ! Get delayed-nu-fission - call read_dataset(temp_arr, xsdata_grp, "delayed-nu-fission") - - do gin = 1, energy_groups - do dg = 1, delayed_groups - - ! Set delayed-nu-fission using delayed neutron fraction - xs % delayed_nu_fission(dg, gin) = temp_beta(dg, gin) * & - temp_arr(gin) - end do - end do - - ! Deallocate temporary delayed-nu-fission array - deallocate(temp_arr) - - ! If delayed-nu-fission is a (delayed_group, energy_group) - ! matrix, set delayed-nu-fission separately for each delayed - ! group. - else if (ndims == 2) then - - ! Get the shape of delayed-nu-fission - call get_shape(xsdata, dims) - - ! Issue error if 1st dimension not correct - if (dims(1) /= delayed_groups) then - call fatal_error("The delayed-nu-fission matrix was input & - &with a 1st dimension not equal to the number of & - &delayed groups.") - end if - - ! Issue error if 2nd dimension not correct - if (dims(2) /= energy_groups) then - call fatal_error("The delayed-nu-fission matrix was input & - &with a 2nd dimension not equal to the number of & - &energy groups.") - end if - - ! Issue warning if delayed_groups == energy_groups - if (delayed_groups == energy_groups) then - call warning("delayed-nu-fission was input as a dimension & - &2 matrix with the same number of delayed groups and & - &groups. It is important to know that OpenMC assumes & - &the dimensions in the matrix are (delayed_groups, & - &energy_groups). Currently, delayed-nu-fission cannot & - &be set as a group by group matrix.") - end if - - ! Get delayed-nu-fission - allocate(temp_arr(delayed_groups * energy_groups)) - call read_dataset(temp_arr, xsdata_grp, "delayed-nu-fission") - xs % delayed_nu_fission = reshape(temp_arr, (/delayed_groups, & - energy_groups/)) - - ! Deallocate temporary array for delayed-nu-fission matrix - deallocate(temp_arr) - - ! If delayed nu-fission is a 3D matrix, set delayed_nu_fission - ! and chi_delayed. - else if (ndims == 3) then - - ! chi_delayed is embedded in delayed_nu_fission -> extract - ! chi_delayed - allocate(temp_arr(delayed_groups * energy_groups * & - energy_groups)) - call read_dataset(temp_arr, xsdata_grp, "delayed-nu-fission") - allocate(temp_3d(delayed_groups, energy_groups, energy_groups)) - temp_3d = reshape(temp_arr, (/delayed_groups, energy_groups, & - energy_groups/)) - - ! Deallocate temporary 1D array for delayed_nu_fission matrix - deallocate(temp_arr) - - ! Set the 2D delayed-nu-fission matrix and 3D chi_dealyed matrix - ! from the 3D delayed-nu-fission matrix - do dg = 1, delayed_groups - do gin = 1, energy_groups - xs % delayed_nu_fission(dg, gin) = sum(temp_3d(dg, :, gin)) - do gout = 1, energy_groups - xs % chi_delayed(dg, gout, gin) = temp_3d(dg, gout, gin) - end do - end do - end do - - ! Normalize chi_delayed so its CDF goes to 1 - do dg = 1, delayed_groups - do gin = 1, energy_groups - chi_sum = sum(xs % chi_delayed(dg, :, gin)) - if (chi_sum == ZERO) then - call fatal_error("Encountered chi delayed for a group & - &that sums to zero") - else - xs % chi_delayed(dg, :, gin) = & - xs % chi_delayed(dg, :, gin) / chi_sum - end if - end do - end do - - ! Deallocate temporary 3D matrix for delayed_nu_fission - deallocate(temp_3d) - else - call fatal_error("delayed-nu-fission must be provided as a & - &1D, 2D, or 3D array") - end if - - call close_dataset(xsdata) - end if - - ! Deallocate temporary beta array - deallocate(temp_beta) - - ! chi-prompt, chi-delayed, prompt-nu-fission, and delayed-nu-fission - ! have been set; Now we will check for the rest of the XS that are - ! unique to fissionable isotopes - - ! Get fission xs - if (object_exists(xsdata_grp, "fission")) then - call read_dataset(xs % fission, xsdata_grp, "fission") - end if - - ! Get kappa-fission xs - if (object_exists(xsdata_grp, "kappa-fission")) then - call read_dataset(xs % kappa_fission, xsdata_grp, "kappa-fission") - end if - - ! Get decay rate xs - if (object_exists(xsdata_grp, "decay rate")) then - call read_dataset(xs % decay_rate, xsdata_grp, "decay rate") - end if - end if - - ! All the XS unique to fissionable isotopes have been set; Now set all - ! the generation XS - - if (object_exists(xsdata_grp, "absorption")) then - call read_dataset(xs % absorption, xsdata_grp, "absorption") - else - call fatal_error("Must provide absorption!") - end if - - ! Get inverse velocity - if (object_exists(xsdata_grp, "inverse-velocity")) then - call read_dataset(xs % inverse_velocity, xsdata_grp, & - "inverse-velocity") - end if - - ! Get scattering data - if (.not. object_exists(xsdata_grp, "scatter_data")) & - call fatal_error("Must provide 'scatter_data'") - - scatt_grp = open_group(xsdata_grp, 'scatter_data') - - ! First get the outgoing group boundary indices - if (object_exists(scatt_grp, "g_min")) then - allocate(gmin(energy_groups)) - call read_dataset(gmin, scatt_grp, "g_min") - else - call fatal_error("'g_min' for the scatter_data must be provided") - end if - - if (object_exists(scatt_grp, "g_max")) then - allocate(gmax(energy_groups)) - call read_dataset(gmax, scatt_grp, "g_max") - else - call fatal_error("'g_max' for the scatter_data must be provided") - end if - - ! Now use this information to find the length of a container array - ! to hold the flattened data - length = 0 - - do gin = 1, energy_groups - length = length + order_data * (gmax(gin) - gmin(gin) + 1) - end do - - ! Allocate flattened array - allocate(temp_arr(length)) - - if (.not. object_exists(scatt_grp, 'scatter_matrix')) & - call fatal_error("'scatter_matrix' must be provided") - call read_dataset(temp_arr, scatt_grp, "scatter_matrix") - - ! Compare the number of orders given with the maximum order of the - ! problem. Strip off the supefluous orders if needed. - if (this % scatter_format == ANGLE_LEGENDRE) then - order = min(order_data - 1, max_order) - order_dim = order + 1 - else - order_dim = order_data - end if - - ! Convert temp_arr to a jagged array ((gin) % data(l, gout)) for - ! passing to ScattData - allocate(input_scatt(energy_groups)) - - index = 1 - do gin = 1, energy_groups - allocate(input_scatt(gin) % data(order_dim, gmin(gin):gmax(gin))) - do gout = gmin(gin), gmax(gin) - do l = 1, order_dim - input_scatt(gin) % data(l, gout) = temp_arr(index) - index = index + 1 - end do - ! Adjust index for the orders we didnt take - index = index + (order_data - order_dim) - end do - end do - - deallocate(temp_arr) - - ! Finally convert the legendre to tabular if needed - allocate(scatt_coeffs(energy_groups)) - - if (this % scatter_format == ANGLE_LEGENDRE .and. & - legendre_to_tabular) then - - this % scatter_format = ANGLE_TABULAR - order_dim = legendre_to_tabular_points - order = order_dim - dmu = TWO / real(order - 1, 8) - - do gin = 1, energy_groups - allocate(scatt_coeffs(gin) % data(order_dim, gmin(gin):gmax(gin))) - do gout = gmin(gin), gmax(gin) - - norm = ZERO - - do imu = 1, order_dim - - if (imu == 1) then - mu = -ONE - else if (imu == order_dim) then - mu = ONE - else - mu = -ONE + real(imu - 1, 8) * dmu - end if - - scatt_coeffs(gin) % data(imu, gout) = & - evaluate_legendre(input_scatt(gin) % data(:, gout), mu) - - ! Ensure positivity of distribution - if (scatt_coeffs(gin) % data(imu, gout) < ZERO) & - scatt_coeffs(gin) % data(imu, gout) = ZERO - - ! And accrue the integral - if (imu > 1) then - norm = norm + HALF * dmu * & - (scatt_coeffs(gin) % data(imu - 1, gout) + & - scatt_coeffs(gin) % data(imu, gout)) - end if - end do ! mu - - ! Now that we have the integral, lets ensure that the - ! distribution is normalized such that it preserves the original - ! scattering xs - if (norm > ZERO) then - scatt_coeffs(gin) % data(:, gout) = & - scatt_coeffs(gin) % data(:, gout) * & - input_scatt(gin) % data(1, gout) / norm - end if - end do ! gout - end do ! gin - else - - ! Sticking with current representation - do gin = 1, energy_groups - allocate(scatt_coeffs(gin) % data(order_dim, gmin(gin):gmax(gin))) - scatt_coeffs(gin) % data(:, :) = & - input_scatt(gin) % data(1:order_dim, :) - end do - end if - - deallocate(input_scatt) - - ! Now get the multiplication matrix - if (object_exists(scatt_grp, 'multiplicity_matrix')) then - - ! Now use this information to find the length of a container array - ! to hold the flattened data - length = 0 - - do gin = 1, energy_groups - length = length + (gmax(gin) - gmin(gin) + 1) - end do - - ! Allocate flattened array - allocate(temp_arr(length)) - call read_dataset(temp_arr, scatt_grp, "multiplicity_matrix") - - ! Convert temp_arr to a jagged array ((gin) % data(gout)) for - ! passing to ScattData - allocate(temp_mult(energy_groups)) - - index = 1 - do gin = 1, energy_groups - - allocate(temp_mult(gin) % data(gmin(gin):gmax(gin))) - - do gout = gmin(gin), gmax(gin) - temp_mult(gin) % data(gout) = temp_arr(index) - index = index + 1 - end do - end do - deallocate(temp_arr) - else - - ! Default to multiplicities of 1.0 - allocate(temp_mult(energy_groups)) - - do gin = 1, energy_groups - allocate(temp_mult(gin) % data(gmin(gin):gmax(gin))) - temp_mult(gin) % data = ONE - end do - end if - - ! Allocate and initialize our ScattData Object. - if (this % scatter_format == ANGLE_HISTOGRAM) then - allocate(ScattDataHistogram :: xs % scatter) - else if (this % scatter_format == ANGLE_TABULAR) then - allocate(ScattDataTabular :: xs % scatter) - else if (this % scatter_format == ANGLE_LEGENDRE) then - allocate(ScattDataLegendre :: xs % scatter) - end if - - ! Initialize the ScattData Object - call xs % scatter % init(gmin, gmax, temp_mult, scatt_coeffs) - - ! Check sigA to ensure it is not 0 since it is - ! often divided by in the tally routines - ! (This may happen with Helium data) - do gin = 1, energy_groups - if (xs % absorption(gin) == ZERO) xs % absorption(gin) = 1E-10_8 - end do - - ! Get, or infer, total xs data. - if (object_exists(xsdata_grp, "total")) then - call read_dataset(xs % total, xsdata_grp, "total") - else - xs % total(:) = xs % absorption(:) + xs % scatter % scattxs(:) - end if - - ! Check sigT to ensure it is not 0 since it is - ! often divided by in the tally routines - do gin = 1, energy_groups - if (xs % total(gin) == ZERO) xs % total(gin) = 1E-10_8 - end do - - ! Close the groups we have opened and deallocate - call close_group(xsdata_grp) - call close_group(scatt_grp) - deallocate(scatt_coeffs, temp_mult) - end associate ! xs - end do ! Temperatures - - end subroutine mgxsiso_from_hdf5 - - subroutine mgxsang_from_hdf5(this, xs_id, energy_groups, delayed_groups, & - temperature, method, tolerance, max_order, legendre_to_tabular, & - legendre_to_tabular_points) - class(MgxsAngle), intent(inout) :: this ! Working Object - integer(HID_T), intent(in) :: xs_id ! Group in H5 file - integer, intent(in) :: energy_groups ! Number of energy groups - integer, intent(in) :: delayed_groups ! Number of energy groups - type(VectorReal), intent(in) :: temperature ! list of desired temperatures - integer, intent(inout) :: method ! Type of temperature access - real(8), intent(in) :: tolerance ! Tolerance on method - integer, intent(in) :: max_order ! Maximum requested order - logical, intent(in) :: legendre_to_tabular ! Convert Legendres to Tabular? - integer, intent(in) :: legendre_to_tabular_points ! Number of points to use - ! in that conversion - - character(MAX_LINE_LEN) :: temp_str - integer(HID_T) :: xsdata, xsdata_grp, scatt_grp - integer :: ndims - integer(HSIZE_T) :: dims(4) - integer, allocatable :: int_arr(:) - real(8), allocatable :: temp_1d(:), temp_3d(:, :, :) - real(8), allocatable :: temp_4d(:, :, :, :), temp_5d(:, :, :, :, :) - real(8), allocatable :: temp_beta(:, :, :, :) - real(8) :: dmu, mu, norm, chi_sum - integer :: order, order_dim, gin, gout, l, imu, dg - type(VectorInt) :: temps_to_read - integer :: t, length, ipol, iazi, order_data - type(Jagged2D), allocatable :: input_scatt(:, :, :), scatt_coeffs(:, :, :) - type(Jagged1D), allocatable :: temp_mult(:, :, :) - integer, allocatable :: gmin(:, :, :), gmax(:, :, :) - - ! Call generic data gathering routine (will populate the metadata) - call mgxs_from_hdf5(this, xs_id, temperature, method, tolerance, & - temps_to_read, order_data) - - ! Set the number of delayed groups - this % num_delayed_groups = delayed_groups - - ! Load the more specific data - do t = 1, temps_to_read % size() - associate(xs => this % xs(t)) - - ! Get temperature as a string - temp_str = trim(to_str(temps_to_read % data(t))) // "K" - xsdata_grp = open_group(xs_id, trim(temp_str)) - - ! Load the more specific data - allocate(xs % prompt_nu_fission(energy_groups, this % n_azi, & - this % n_pol)) - allocate(xs % delayed_nu_fission(delayed_groups, energy_groups, & - this % n_azi, this % n_pol)) - allocate(xs % chi_prompt(energy_groups, energy_groups, this % n_azi, & - this % n_pol)) - allocate(xs % chi_delayed(delayed_groups, energy_groups, & - energy_groups, this % n_azi, this % n_pol)) - allocate(xs % total(energy_groups, this % n_azi, this % n_pol)) - allocate(xs % absorption(energy_groups, this % n_azi, this % n_pol)) - allocate(xs % fission(energy_groups, this % n_azi, this % n_pol)) - allocate(xs % kappa_fission(energy_groups, this % n_azi, & - this % n_pol)) - allocate(xs % decay_rate(delayed_groups, this % n_azi, this % n_pol)) - allocate(xs % inverse_velocity(energy_groups, this % n_azi, & - this % n_pol)) - - ! Set all fissionable terms to zero - xs % delayed_nu_fission = ZERO - xs % prompt_nu_fission = ZERO - xs % fission = ZERO - xs % kappa_fission = ZERO - xs % chi_delayed = ZERO - xs % chi_prompt = ZERO - xs % decay_rate = ZERO - xs % inverse_velocity = ZERO - - if (this % fissionable) then - - ! Allocate temporary array for beta - allocate(temp_beta(delayed_groups, energy_groups, this % n_azi, & - this % n_pol)) - - ! Set beta - if (object_exists(xsdata_grp, "beta")) then - - ! Get the dimensions of the beta dataset - xsdata = open_dataset(xsdata_grp, "beta") - call get_ndims(xsdata, ndims) - - ! Beta is input as (delayed_groups, n_azi, n_pol) - if (ndims == 3) then - - ! Allocate temporary arrays for beta - allocate(temp_1d(delayed_groups * this % n_azi * this % n_pol)) - allocate(temp_3d(delayed_groups, this % n_azi, this % n_pol)) - - ! Read beta - call read_dataset(temp_1d, xsdata_grp, "beta") - temp_3d = reshape(temp_1d, (/delayed_groups, this % n_azi, & - this % n_pol/)) - - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do dg = 1, delayed_groups - do gin = 1, energy_groups - temp_beta(dg, gin, iazi, ipol) = temp_3d(dg, iazi, ipol) - end do - end do - end do - end do - - ! Deallocate temporary beta arrays - deallocate(temp_1d) - deallocate(temp_3d) - - ! Beta is input as (delayed_groups, energy_groups, n_azi, n_pol) - else if (ndims == 4) then - - ! Allocate temporary array for beta - allocate(temp_1d(delayed_groups * energy_groups * this % n_azi & - * this % n_pol)) - - ! Read beta - call read_dataset(temp_1d, xsdata_grp, "beta") - - ! Reshape array and set to dedicated beta array - temp_beta = reshape(temp_1d, (/delayed_groups, & - energy_groups, this % n_azi, this % n_pol/)) - - ! Deallocate temporary beta array - deallocate(temp_1d) - - else - call fatal_error("beta must be provided as a 3D or 4D array") - end if - - call close_dataset(xsdata) - else - temp_beta = ZERO - end if - - ! If chi provided, set chi-prompt and chi-delayed - if (object_exists(xsdata_grp, "chi")) then - - ! Allocate temporary array for chi - allocate(temp_1d(energy_groups * this % n_azi * this % n_pol)) - allocate(temp_3d(energy_groups, this % n_azi, this % n_pol)) - - ! Read chi - call read_dataset(temp_1d, xsdata_grp, "chi") - temp_3d = reshape(temp_1d, (/energy_groups, this % n_azi, & - this % n_pol/)) - - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - do gout = 1, energy_groups - xs % chi_prompt(gout, gin, iazi, ipol) = & - temp_3d(gout, iazi, ipol) - end do - - ! Normalize chi-prompt so its CDF goes to 1 - chi_sum = sum(xs % chi_prompt(:, gin, iazi, ipol)) - if (chi_sum == ZERO) then - call fatal_error("Encountered chi for a group that sums& - & to zero") - else - xs % chi_prompt(:, gin, iazi, ipol) = & - xs % chi_prompt(:, gin, iazi, ipol) / chi_sum - end if - end do - end do - end do - - ! Set chi-delayed to chi-prompt - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do dg = 1, delayed_groups - xs % chi_delayed(dg, :, :, iazi, ipol) = & - xs % chi_prompt(:, :, iazi, ipol) - end do - end do - end do - - ! Deallocate temporary chi arrays - deallocate(temp_1d) - deallocate(temp_3d) - end if - - ! If nu-fission provided, set prompt-nu_-ission and - ! delayed-nu-fission. If nu fission is a matrix, set chi-prompt and - ! chi-delayed. - if (object_exists(xsdata_grp, "nu-fission")) then - - ! Get the dimensions of the nu-fission dataset - xsdata = open_dataset(xsdata_grp, "nu-fission") - call get_ndims(xsdata, ndims) - - ! If nu-fission is a 3D array - if (ndims == 3) then - - ! Get nu-fission - call read_dataset(xs % prompt_nu_fission, xsdata_grp, & - "nu-fission") - - ! Set delayed-nu-fission and correct prompt-nu-fission with - ! beta - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - do dg = 1, delayed_groups - - ! Set delayed-nu-fission using delayed neutron fraction - xs % delayed_nu_fission(dg, gin, iazi, ipol) = & - temp_beta(dg, gin, iazi, ipol) * & - xs % prompt_nu_fission(gin, iazi, ipol) - end do - - ! Correct prompt-nu-fission using delayed neutron fraction - if (delayed_groups > 0) then - xs % prompt_nu_fission(gin, iazi, ipol) = & - (1 - sum(temp_beta(:, gin, iazi, ipol))) * & - xs % prompt_nu_fission(gin, iazi, ipol) - end if - end do - end do - end do - - ! If nu-fission is a matrix, set prompt-nu-fission, - ! delayed-nu-fission, chi-prompt, and chi-delayed. - else if (ndims == 4) then - - ! chi is embedded in nu-fission -> extract chi - allocate(temp_1d(energy_groups * energy_groups * & - this % n_azi * this % n_pol)) - call read_dataset(temp_1d, xsdata_grp, "nu-fission") - allocate(temp_4d(energy_groups, energy_groups, this % n_azi, & - this % n_pol)) - temp_4d = reshape(temp_1d, (/energy_groups, energy_groups, & - this % n_azi, this % n_pol /)) - - ! Deallocate temporary 1D array for nu-fission matrix - deallocate(temp_1d) - - ! Set the vector nu-fission from the matrix nu-fission - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - xs % prompt_nu_fission(gin, iazi, ipol) = & - sum(temp_4d(:, gin, iazi, ipol)) - end do - end do - end do - - ! Set delayed-nu-fission and correct prompt-nu-fission with - ! beta - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - do dg = 1, delayed_groups - - ! Set delayed-nu-fission using delayed neutron fraction - xs % delayed_nu_fission(dg, gin, iazi, ipol) = & - temp_beta(dg, gin, iazi, ipol) * & - xs % prompt_nu_fission(gin, iazi, ipol) - end do - - ! Correct prompt-nu-fission using delayed neutron fraction - if (delayed_groups > 0) then - xs % prompt_nu_fission(gin, iazi, ipol) = & - (1 - sum(temp_beta(:, gin, iazi, ipol))) * & - xs % prompt_nu_fission(gin, iazi, ipol) - end if - end do - end do - end do - - ! Now pull out information needed for chi - xs % chi_prompt(:, :, :, :) = temp_4d - - ! Deallocate temporary 4D array for nu-fission matrix - deallocate(temp_4d) - - ! Normalize chi so its CDF goes to 1 - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - chi_sum = sum(xs % chi_prompt(:, gin, iazi, ipol)) - if (chi_sum == ZERO) then - call fatal_error("Encountered chi for a group that & - &sums to zero") - else - xs % chi_prompt(:, gin, iazi, ipol) = & - xs % chi_prompt(:, gin, iazi, ipol) / chi_sum - end if - end do - - ! Set chi-delayed to chi-prompt - do dg = 1, delayed_groups - xs % chi_delayed(dg, :, :, iazi, ipol) = & - xs % chi_prompt(:, :, iazi, ipol) - end do - end do - end do - else - call fatal_error("nu-fission must be provided as a 3D or & - &4D array") - end if - - call close_dataset(xsdata) - end if - - ! If chi-prompt provided, set chi-prompt - if (object_exists(xsdata_grp, "chi-prompt")) then - - ! Allocate temporary array for chi-prompt - allocate(temp_1d(energy_groups * this % n_azi * this % n_pol)) - allocate(temp_3d(energy_groups, this % n_azi, this % n_pol)) - - ! Get array with chi-prompt - call read_dataset(temp_1d, xsdata_grp, "chi-prompt") - temp_3d = reshape(temp_1d, (/energy_groups, this % n_azi, & - this % n_pol/)) - - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - do gout = 1, energy_groups - xs % chi_prompt(gout, gin, iazi, ipol) = & - temp_3d(gout, iazi, ipol) - end do - - ! Normalize chi so its CDF goes to 1 - chi_sum = sum(xs % chi_prompt(:, gin, iazi, ipol)) - if (chi_sum == ZERO) then - call fatal_error("Encountered chi prompt for a group that& - & sums to zero") - else - xs % chi_prompt(:, gin, iazi, ipol) = & - xs % chi_prompt(:, gin, iazi, ipol) / chi_sum - end if - end do - end do - end do - - ! Deallocate temporary arrays for chi-prompt - deallocate(temp_1d) - deallocate(temp_3d) - end if - - ! If chi-delayed provided, set chi-delayed - if (object_exists(xsdata_grp, "chi-delayed")) then - - ! Get the dimensions of the chi-delayed dataset - xsdata = open_dataset(xsdata_grp, "chi-delayed") - call get_ndims(xsdata, ndims) - - ! chi-delayed is input as (energy_groups, n_azi, n_pol) - if (ndims == 3) then - - ! Allocate temporary array for chi-prompt - allocate(temp_1d(energy_groups * this % n_azi * this % n_pol)) - allocate(temp_3d(energy_groups, this % n_azi, this % n_pol)) - - ! Get array with chi-prompt - call read_dataset(temp_1d, xsdata_grp, "chi-delayed") - temp_3d = reshape(temp_1d, (/energy_groups, this % n_azi, & - this % n_pol/)) - - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do dg = 1, delayed_groups - do gin = 1, energy_groups - do gout = 1, energy_groups - xs % chi_delayed(dg, gout, gin, iazi, ipol) = & - temp_3d(gout, iazi, ipol) - end do - - ! Normalize chi so its CDF goes to 1 - chi_sum = sum(xs % chi_delayed(dg, :, gin, iazi, ipol)) - if (chi_sum == ZERO) then - call fatal_error("Encountered chi delayed for a group& - & that sums to zero") - else - xs % chi_delayed(dg, :, gin, iazi, ipol) = & - xs % chi_delayed(dg, :, gin, iazi, ipol) / & - chi_sum - end if - end do - end do - end do - end do - - ! Deallocate temporary arrays for chi-delayed - deallocate(temp_1d) - deallocate(temp_3d) - - ! chi-delayed is input as (delayed_groups, energy_groups, n_azi, - ! n_pol) - else if (ndims == 4) then - - ! Allocate temporary array for chi-delayed - allocate(temp_1d(delayed_groups * energy_groups * this % n_azi & - * this % n_pol)) - allocate(temp_4d(delayed_groups, energy_groups, this % n_azi, & - this % n_pol)) - - ! Get chi-delayed - call read_dataset(temp_1d, xsdata_grp, "chi-delayed") - temp_4d = reshape(temp_1d, (/delayed_groups, energy_groups, & - this % n_azi, this % n_pol/)) - - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do dg = 1, delayed_groups - do gin = 1, energy_groups - do gout = 1, energy_groups - xs % chi_delayed(dg, gout, gin, iazi, ipol) = & - temp_4d(dg, gout, iazi, ipol) - end do - - ! Normalize chi so its CDF goes to 1 - chi_sum = sum(xs % chi_delayed(dg, :, gin, iazi, ipol)) - if (chi_sum == ZERO) then - call fatal_error("Encountered chi delayed for a group& - & that sums to zero") - else - xs % chi_delayed(dg, :, gin, iazi, ipol) = & - xs % chi_delayed(dg, :, gin, iazi, ipol) / & - chi_sum - end if - end do - end do - end do - end do - - ! Deallocate temporary arrays for chi-delayed - deallocate(temp_1d) - deallocate(temp_4d) - - else - call fatal_error("chi-delayed must be provided as a 3D or 4D & - &array") - end if - - call close_dataset(xsdata) - end if - - ! If prompt-nu-fission present, set prompt-nu-fission - if (object_exists(xsdata_grp, "prompt-nu-fission")) then - - ! Get the dimensions of the prompt-nu-fission dataset - xsdata = open_dataset(xsdata_grp, "prompt-nu-fission") - call get_ndims(xsdata, ndims) - - ! If prompt-nu-fission is a vector for each azi and pol - if (ndims == 3) then - - ! Set prompt_nu_fission - call read_dataset(xs % prompt_nu_fission, xsdata_grp, & - "prompt-nu-fission") - - ! If prompt-nu-fission is a matrix for each azi and pol, - ! set prompt_nu_fission and chi_prompt. - else if (ndims == 4) then - - ! chi_prompt is embedded in prompt_nu_fission -> extract - ! chi_prompt - allocate(temp_1d(energy_groups * energy_groups & - * this % n_azi * this % n_pol)) - allocate(temp_4d(energy_groups, energy_groups, this % n_azi, & - this % n_pol)) - call read_dataset(temp_1d, xsdata_grp, "prompt-nu-fission") - temp_4d = reshape(temp_1d, (/energy_groups, energy_groups, & - this % n_azi, this % n_pol/)) - - ! Deallocate temporary 1D array for prompt_nu_fission matrix - deallocate(temp_1d) - - ! Set the vector prompt-nu-fission from the matrix - ! prompt-nu-fission - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - xs % prompt_nu_fission(gin, iazi, ipol) = & - sum(temp_4d(:, gin, iazi, ipol)) - end do - end do - end do - - ! Now pull out information needed for chi - xs % chi_prompt(:, :, :, :) = temp_4d - - ! Deallocate temporary 4D array for nu_fission matrix - deallocate(temp_4d) - - ! Normalize chi so its CDF goes to 1 - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - chi_sum = sum(xs % chi_prompt(:, gin, iazi, ipol)) - if (chi_sum == ZERO) then - call fatal_error("Encountered chi prompt for a group & - &that sums to zero") - else - xs % chi_prompt(:, gin, iazi, ipol) = & - xs % chi_prompt(:, gin, iazi, ipol) / chi_sum - end if - end do - end do - end do - else - call fatal_error("prompt-nu-fission must be provided as a 3D & - &or 4D array") - end if - - call close_dataset(xsdata) - end if - - ! If delayed-nu-fission provided, set delayed-nu-fission. If - ! delayed-nu-fission is a matrix, set chi-delayed. - if (object_exists(xsdata_grp, "delayed-nu-fission")) then - - ! Get the dimensions of the delayed-nu-fission dataset - xsdata = open_dataset(xsdata_grp, "delayed-nu-fission") - call get_ndims(xsdata, ndims) - - ! delayed-nu-fission is input as (energy_groups, n_azi, n_pol) - if (ndims == 3) then - - ! If beta is zeros, raise error - if (temp_beta(1,1,1,1) == ZERO) then - call fatal_error("cannot set delayed-nu-fission with a 3D & - &array if beta not provided") - end if - - ! Allocate temporary arrays for delayed-nu-fission - allocate(temp_1d(energy_groups * this % n_azi * this % n_pol)) - allocate(temp_3d(energy_groups, this % n_azi, this % n_pol)) - - ! Get delayed-nu-fission - call read_dataset(temp_1d, xsdata_grp, "delayed-nu-fission") - temp_3d = reshape(temp_1d, (/energy_groups, this % n_azi, & - this % n_pol/)) - - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - do dg = 1, delayed_groups - - ! Set delayed-nu-fission using delayed neutron fraction - xs % delayed_nu_fission(dg, gin, iazi, ipol) = & - temp_beta(dg, gin, iazi, ipol) * & - temp_3d(gin, iazi, ipol) - end do - end do - end do - end do - - ! Deallocate temporary delayed-nu-fission arrays - deallocate(temp_1d) - deallocate(temp_3d) - - ! If delayed-nu-fission is a (delayed_group, energy_group, - ! n_azi, n_pol) matrix, set delayed-nu-fission separately for - ! each delayed group. - else if (ndims == 4) then - - ! Get the shape of delayed-nu-fission - call get_shape(xsdata, dims) - - ! Issue error if 1st dimension not correct - if (dims(1) /= delayed_groups) then - call fatal_error("The delayed-nu-fission matrix was input & - &with a 1st dimension not equal to the number of & - &delayed groups.") - end if - - ! Issue error if 2nd dimension not correct - if (dims(2) /= energy_groups) then - call fatal_error("The delayed-nu-fission matrix was input & - &with a 2nd dimension not equal to the number of & - &energy groups.") - end if - - ! Issue warning if delayed_groups == energy_groups - if (delayed_groups == energy_groups) then - call warning("delayed-nu-fission was input as a dimension & - &4 matrix with the same number of delayed groups and & - &groups. It is important to know that OpenMC assumes & - &the dimensions in the matrix are (delayed_groups, & - &energy_groups, n_azi, n_pol). Currently, & - &delayed-nu-fission cannot be set as a group by group & - &matrix.") - end if - - ! Get delayed-nu-fission - allocate(temp_1d(delayed_groups * energy_groups * this % n_azi & - * this % n_pol)) - call read_dataset(temp_1d, xsdata_grp, "delayed-nu-fission") - xs % delayed_nu_fission = reshape(temp_1d, (/delayed_groups, & - energy_groups, this % n_azi, this % n_pol /)) - - ! Deallocate temporary array for delayed-nu-fission matrix - deallocate(temp_1d) - - ! If delayed nu-fission is a 5D matrix, set delayed_nu_fission - ! and chi_delayed. - else if (ndims == 5) then - - ! chi_delayed is embedded in delayed_nu_fission -> extract - ! chi_delayed - allocate(temp_1d(delayed_groups * energy_groups * & - energy_groups * this % n_azi * this % n_pol)) - allocate(temp_5d(delayed_groups, energy_groups, energy_groups, & - this % n_azi, this % n_pol)) - call read_dataset(temp_1d, xsdata_grp, "delayed-nu-fission") - temp_5d = reshape(temp_1d, (/delayed_groups, energy_groups, & - energy_groups, this % n_azi, this % n_pol/)) - - ! Deallocate temporary 1D array for delayed_nu_fission matrix - deallocate(temp_1d) - - ! Set the 4D delayed-nu-fission matrix and 5D chi_delayed matrix - ! from the 5D delayed-nu-fission matrix - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do dg = 1, delayed_groups - do gin = 1, energy_groups - xs % delayed_nu_fission(dg, gin, iazi, ipol) = & - sum(temp_5d(dg, :, gin, iazi, ipol)) - do gout = 1, energy_groups - xs % chi_delayed(dg, gout, gin, iazi, ipol) = & - temp_5d(dg, gout, gin, iazi, ipol) - end do - end do - end do - end do - end do - - ! Normalize chi_delayed so its CDF goes to 1 - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do dg = 1, delayed_groups - do gin = 1, energy_groups - chi_sum = sum(xs % chi_delayed(dg, :, gin, iazi, ipol)) - if (chi_sum == ZERO) then - call fatal_error("Encountered chi delayed for a group& - & that sums to zero") - else - xs % chi_delayed(dg, :, gin, iazi, ipol) = & - xs % chi_delayed(dg, :, gin, iazi, ipol) / & - chi_sum - end if - end do - end do - end do - end do - - ! Deallocate temporary 5D matrix for delayed_nu_fission - deallocate(temp_5d) - else - call fatal_error("delayed-nu-fission must be provided as a & - &3D, 4D, or 5D array") - end if - - call close_dataset(xsdata) - end if - - ! Deallocate temporary beta array - deallocate(temp_beta) - - ! chi-prompt, chi-delayed, prompt-nu-fission, and delayed-nu-fission - ! have been set; Now we will check for the rest of the XS that are - ! unique to fissionable isotopes - - ! Set fission xs - if (object_exists(xsdata_grp, "fission")) then - - ! Allocate temporary array for fission - allocate(temp_1d(energy_groups * this % n_azi * this % n_pol)) - - ! Get fission array - call read_dataset(temp_1d, xsdata_grp, "fission") - xs % fission(:, :, :) = reshape(temp_1d, (/energy_groups, & - this % n_azi, this % n_pol/)) - - ! Deallocate temporary array for fission - deallocate(temp_1d) - end if - - ! Set kappa-fission xs - if (object_exists(xsdata_grp, "kappa-fission")) then - - ! Allocate temporary array for kappa-fission - allocate(temp_1d(energy_groups * this % n_azi * this % n_pol)) - - ! Get kappa-fission array - call read_dataset(temp_1d, xsdata_grp, "kappa-fission") - xs % kappa_fission(:, :, :) = reshape(temp_1d, (/energy_groups, & - this % n_azi, this % n_pol/)) - - ! Deallocate temporary array for kappa-fission - deallocate(temp_1d) - end if - - ! Set decay rate - if (object_exists(xsdata_grp, "decay rate")) then - - ! Allocate temporary array for decay rate - allocate(temp_1d(this % n_azi * this % n_pol * delayed_groups)) - - ! Get decay rate array - call read_dataset(temp_1d, xsdata_grp, "decay rate") - xs % decay_rate(:, :, :) = reshape(temp_1d, (/delayed_groups, & - this % n_azi, this % n_pol/)) - - ! Deallocate temporary array for decay rate - deallocate(temp_1d) - end if - end if - - ! All the XS unique to fissionable isotopes have been set; Now set all - ! the generation XS - - if (object_exists(xsdata_grp, "absorption")) then - - ! Allocate temporary array for absorption xs - allocate(temp_1d(energy_groups * this % n_azi * this % n_pol)) - - ! Read in absorption xs - call read_dataset(temp_1d, xsdata_grp, "absorption") - - xs % absorption = reshape(temp_1d, (/energy_groups, this % n_azi, & - this % n_pol/)) - - ! Deallocate temporary array for absorption xs - deallocate(temp_1d) - else - call fatal_error("Must provide absorption!") - end if - - if (object_exists(xsdata_grp, "inverse-velocity")) then - - ! Allocate temporary array for inverse velocity - allocate(temp_1d(energy_groups * this % n_azi * this % n_pol)) - - ! Read in inverse velocity - call read_dataset(temp_1d, xsdata_grp, "inverse-velocity") - - xs % inverse_velocity = reshape(temp_1d, (/energy_groups, & - this % n_azi, this % n_pol/)) - - ! Deallocate temporary array for inverse velocity - deallocate(temp_1d) - end if - - ! Get scattering data - if (.not. object_exists(xsdata_grp, "scatter_data")) & - call fatal_error("Must provide 'scatter_data'") - - scatt_grp = open_group(xsdata_grp, 'scatter_data') - - ! First get the outgoing group boundary indices - if (object_exists(scatt_grp, "g_min")) then - - allocate(int_arr(energy_groups * this % n_azi * this % n_pol)) - - call read_dataset(int_arr, scatt_grp, "g_min") - allocate(gmin(energy_groups, this % n_azi, this % n_pol)) - gmin = reshape(int_arr, (/energy_groups, this % n_azi, & - this % n_pol/)) - - deallocate(int_arr) - else - call fatal_error("'g_min' for the scatter_data must be provided") - end if - - if (object_exists(scatt_grp, "g_max")) then - - allocate(int_arr(energy_groups * this % n_azi * this % n_pol)) - - call read_dataset(int_arr, scatt_grp, "g_max") - allocate(gmax(energy_groups, this % n_azi, this % n_pol)) - gmax = reshape(int_arr, (/energy_groups, this % n_azi, & - this % n_pol/)) - - deallocate(int_arr) - else - call fatal_error("'g_max' for the scatter_data must be provided") - end if - - ! Now use this information to find the length of a container array - ! to hold the flattened data - length = 0 - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - length = length + order_data * (gmax(gin, iazi, ipol) - & - gmin(gin, iazi, ipol) + 1) - end do - end do - end do - - ! Allocate flattened array - allocate(temp_1d(length)) - - if (.not. object_exists(scatt_grp, 'scatter_matrix')) & - call fatal_error("'scatter_matrix' must be provided") - call read_dataset(temp_1d, scatt_grp, "scatter_matrix") - - ! Compare the number of orders given with the maximum order of the - ! problem. Strip off the superfluous orders if needed. - if (this % scatter_format == ANGLE_LEGENDRE) then - order = min(order_data - 1, max_order) - order_dim = order + 1 - else - order_dim = order_data - end if - - ! Convert temp_1d to a jagged array ((gin) % data(l, gout)) for - ! passing to ScattData - allocate(input_scatt(energy_groups, this % n_azi, this % n_pol)) - - index = 1 - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - allocate(input_scatt(gin, iazi, ipol) % data(order_dim, & - gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) - do gout = gmin(gin, iazi, ipol), gmax(gin, iazi, ipol) - do l = 1, order_dim - input_scatt(gin, iazi, ipol) % data(l, gout) = & - temp_1d(index) - index = index + 1 - end do ! gout - ! Adjust index for the orders we didnt take - index = index + (order_data - order_dim) - end do ! order - end do ! gin - end do ! iazi - end do ! ipol - - deallocate(temp_1d) - - ! Finally convert the legendre to tabular if needed - allocate(scatt_coeffs(energy_groups, this % n_azi, this % n_pol)) - - if (this % scatter_format == ANGLE_LEGENDRE .and. & - legendre_to_tabular) then - - this % scatter_format = ANGLE_TABULAR - order_dim = legendre_to_tabular_points - order = order_dim - dmu = TWO / real(order - 1, 8) - - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - allocate(scatt_coeffs(gin, iazi, ipol) % data(& - order_dim, & - gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) - - do gout = gmin(gin, iazi, ipol), gmax(gin, iazi, ipol) - norm = ZERO - do imu = 1, order_dim - if (imu == 1) then - mu = -ONE - else if (imu == order_dim) then - mu = ONE - else - mu = -ONE + real(imu - 1, 8) * dmu - end if - - scatt_coeffs(gin, iazi, ipol) % data(imu, gout) = & - evaluate_legendre(& - input_scatt(gin, iazi, ipol) % data(:, gout), mu) - - ! Ensure positivity of distribution - if (scatt_coeffs(gin, iazi, ipol) % data(imu, gout) < ZERO) & - scatt_coeffs(gin, iazi, ipol) % data(imu, gout) = ZERO - - ! And accrue the integral - if (imu > 1) then - norm = norm + HALF * dmu * & - (scatt_coeffs(gin, iazi, ipol) % data(imu - 1, gout) + & - scatt_coeffs(gin, iazi, ipol) % data(imu, gout)) - end if - end do ! mu - - ! Now that we have the integral, lets ensure that the distribution - ! is normalized such that it preserves the original scattering xs - if (norm > ZERO) then - scatt_coeffs(gin, iazi, ipol) % data(:, gout) = & - scatt_coeffs(gin, iazi, ipol) % data(:, gout) * & - input_scatt(gin, iazi, ipol) % data(1, gout) / & - norm - end if - end do ! gout - end do ! gin - end do ! iazi - end do ! ipol - else - ! Sticking with current representation, carry forward - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - allocate(scatt_coeffs(gin, iazi, ipol) % data(order_dim, & - gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) - scatt_coeffs(gin, iazi, ipol) % data(:, :) = & - input_scatt(gin, iazi, ipol) % data(1:order_dim, :) - end do - end do - end do - end if - - deallocate(input_scatt) - - ! Now get the multiplication matrix - if (object_exists(scatt_grp, 'multiplicity_matrix')) then - - ! Now use this information to find the length of a container array - ! to hold the flattened data - length = 0 - - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - length = length + (gmax(gin, iazi, ipol) - gmin(gin, iazi, ipol) + 1) - end do - end do - end do - - ! Allocate flattened array - allocate(temp_1d(length)) - call read_dataset(temp_1d, scatt_grp, "multiplicity_matrix") - - ! Convert temp_1d to a jagged array ((gin) % data(gout)) for passing - ! to ScattData - allocate(temp_mult(energy_groups, this % n_azi, this % n_pol)) - - index = 1 - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - allocate(temp_mult(gin, iazi, ipol) % data( & - gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) - do gout = gmin(gin, iazi, ipol), gmax(gin, iazi, ipol) - temp_mult(gin, iazi, ipol) % data(gout) = temp_1d(index) - index = index + 1 - end do - end do - end do - end do - deallocate(temp_1d) - else - - allocate(temp_mult(energy_groups, this % n_azi, this % n_pol)) - - ! Default to multiplicities of 1.0 - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - allocate(temp_mult(gin, iazi, ipol) % data( & - gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) - temp_mult(gin, iazi, ipol) % data = ONE - end do - end do - end do - end if - - ! Allocate and initialize our ScattData Object. - allocate(xs % scatter(this % n_azi, this % n_pol)) - - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - - ! Allocate and initialize our ScattData Object. - if (this % scatter_format == ANGLE_HISTOGRAM) then - allocate(ScattDataHistogram :: xs % scatter(iazi, ipol) % obj) - else if (this % scatter_format == ANGLE_TABULAR) then - allocate(ScattDataTabular :: xs % scatter(iazi, ipol) % obj) - else if (this % scatter_format == ANGLE_LEGENDRE) then - allocate(ScattDataLegendre :: xs % scatter(iazi, ipol) % obj) - end if - - ! Initialize the ScattData Object - call xs % scatter(iazi, ipol) % obj % init(gmin(:, iazi, ipol), & - gmax(:, iazi, ipol), temp_mult(:, iazi, ipol), & - scatt_coeffs(:, iazi, ipol)) - end do - end do - - ! Check sigA to ensure it is not 0 since it is - ! often divided by in the tally routines - ! (This may happen with Helium data) - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - if (xs % absorption(gin, iazi, ipol) == ZERO) then - xs % absorption(gin, iazi, ipol) = 1E-10_8 - end if - end do - end do - end do - - if (object_exists(xsdata_grp, "total")) then - - allocate(temp_1d(energy_groups * this % n_azi * this % n_pol)) - call read_dataset(temp_1d, xsdata_grp, "total") - xs % total = reshape(temp_1d, (/energy_groups, this % n_azi, & - this % n_pol/)) - - deallocate(temp_1d) - else - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - xs % total(:, iazi, ipol) = xs % absorption(:, iazi, ipol) + & - xs % scatter(iazi, ipol) % obj % scattxs(:) - end do - end do - end if - - ! Check sigT to ensure it is not 0 since it is often divided by in - ! the tally routines - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, energy_groups - if (xs % total(gin, iazi, ipol) == ZERO) then - xs % total(gin, iazi, ipol) = 1E-10_8 - end if - end do - end do - end do - - ! Close the groups we have opened and deallocate - call close_group(xsdata_grp) - call close_group(scatt_grp) - deallocate(scatt_coeffs, temp_mult) - - end associate ! xs - end do ! Temperatures - end subroutine mgxsang_from_hdf5 - -!=============================================================================== -! MGXS*_COMBINE Builds a macroscopic Mgxs object from microscopic Mgxs objects -!=============================================================================== - - subroutine mgxs_combine(this, temps, mat, nuclides, max_order, & - scatter_format, order_dim) - class(Mgxs), intent(inout) :: this ! The Mgxs to initialize - type(VectorReal), intent(in) :: temps ! Temperatures to obtain - type(Material), pointer, intent(in) :: mat ! base material - type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from - integer, intent(in) :: max_order ! Maximum requested order - integer, intent(out) :: scatter_format ! Type of scatter - integer, intent(out) :: order_dim ! Scattering data order size - - integer :: t, mat_max_order, order - - ! Fill in meta-data from material information - if (mat % name == "") then - this % name = trim(to_str(mat % id)) - else - this % name = trim(mat % name) - end if - - ! Set whether this material is fissionable - this % fissionable = mat % fissionable - - ! The following info we should initialize, but we dont need it nor - ! does it have guaranteed meaning. - this % awr = -ONE - - allocate(this % kTs(temps % size())) - - do t = 1, temps % size() - this % kTs(t) = temps % data(t) - end do - - ! Allocate the XS object for the number of temperatures - select type(this) - type is (MgxsIso) - allocate(this % xs(temps % size())) - type is (MgxsAngle) - allocate(this % xs(temps % size())) - end select - - ! Determine the scattering type of our data and ensure all scattering orders - ! are the same. - scatter_format = nuclides(mat % nuclide(1)) % obj % scatter_format - - select type(nuc => nuclides(mat % nuclide(1)) % obj) - type is (MgxsIso) - order = size(nuc % xs(1) % scatter % dist(1) % data, dim=1) - type is (MgxsAngle) - order = size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, dim=1) - end select - - ! If we have tabular only data, then make sure all datasets have same size - if (scatter_format == ANGLE_HISTOGRAM) then - ! Check all scattering data to ensure it is the same size - do i = 2, mat % n_nuclides - select type(nuc => nuclides(mat % nuclide(i)) % obj) - type is (MgxsIso) - if (order /= size(nuc % xs(1) % scatter % dist(1) % data, dim=1)) & - call fatal_error("All histogram scattering entries must be& - & same length!") - type is (MgxsAngle) - if (order /= size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, dim=1)) & - call fatal_error("All histogram scattering entries must be& - & same length!") - end select - end do - - ! Ok, got our order, store the dimensionality - order_dim = order - - else if (scatter_format == ANGLE_TABULAR) then - ! Check all scattering data to ensure it is the same size - do i = 2, mat % n_nuclides - select type(nuc => nuclides(mat % nuclide(i)) % obj) - type is (MgxsIso) - if (order /= size(nuc % xs(1) % scatter % dist(1) % data, dim=1)) & - call fatal_error("All tabular scattering entries must be& - & same length!") - type is (MgxsAngle) - if (order /= size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, dim=1)) & - call fatal_error("All tabular scattering entries must be& - & same length!") - end select - end do - - ! Ok, got our order, store the dimensionality - order_dim = order - - else if (scatter_format == ANGLE_LEGENDRE) then - - ! Need to determine the maximum scattering order of all data in this material - mat_max_order = 0 - - do i = 1, mat % n_nuclides - select type(nuc => nuclides(mat % nuclide(i)) % obj) - type is (MgxsIso) - if (size(nuc % xs(1) % scatter % dist(1) % data, & - dim=1) > mat_max_order) & - mat_max_order = size(nuc % xs(1) % scatter % dist(1) % data, & - dim=1) - type is (MgxsAngle) - if (size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, & - dim=1) > mat_max_order) & - mat_max_order = & - size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, & - dim=1) - end select - end do - - ! Now need to compare this material maximum scattering order with - ! the problem wide max scatt order and use whichever is lower - order = min(mat_max_order, max_order + 1) - - ! Ok, got our order, store the dimensionality - order_dim = order - end if - - end subroutine mgxs_combine - - subroutine mgxsiso_combine(this, temps, mat, nuclides, energy_groups, & - delayed_groups, max_order, tolerance, method) - class(MgxsIso), intent(inout) :: this ! The Mgxs to initialize - type(VectorReal), intent(in) :: temps ! Temperatures to obtain [MeV] - type(Material), pointer, intent(in) :: mat ! base material - type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from - integer, intent(in) :: energy_groups ! Number of energy groups - integer, intent(in) :: delayed_groups ! Number of delayed groups - integer, intent(in) :: max_order ! Maximum requested order - real(8), intent(in) :: tolerance ! Tolerance on method - integer, intent(in) :: method ! Type of temperature access - - integer :: i ! loop index over nuclides - integer :: t ! Index in to temps - integer :: gin, gout ! group indices - integer :: dg ! delayed group index - real(8) :: atom_density ! atom density of a nuclide - real(8) :: norm, nuscatt - integer :: order_dim, nuc_order_dim - real(8), allocatable :: temp_mult(:, :), mult_num(:, :), mult_denom(:, :) - real(8), allocatable :: scatt_coeffs(:, :, :) - integer :: nuc_t - integer, allocatable :: nuc_ts(:) - real(8) :: temp_actual, temp_desired, interp - integer :: scatter_format - type(Jagged2D), allocatable :: nuc_matrix(:) - integer, allocatable :: gmin(:), gmax(:) - type(Jagged2D), allocatable :: jagged_scatt(:) - type(Jagged1D), allocatable :: jagged_mult(:) - - ! Set the meta-data - call mgxs_combine(this, temps, mat, nuclides, max_order, scatter_format, & - order_dim) - - ! Set the number of delayed groups - this % num_delayed_groups = delayed_groups - - ! Create the Xs Data for each temperature - TEMP_LOOP: do t = 1, temps % size() - - ! Allocate and initialize the data needed for macro_xs(i_mat) object - allocate(this % xs(t) % total(energy_groups)) - this % xs(t) % total(:) = ZERO - - allocate(this % xs(t) % absorption(energy_groups)) - this % xs(t) % absorption(:) = ZERO - - allocate(this % xs(t) % fission(energy_groups)) - this % xs(t) % fission(:) = ZERO - - allocate(this % xs(t) % kappa_fission(energy_groups)) - this % xs(t) % kappa_fission(:) = ZERO - - allocate(this % xs(t) % prompt_nu_fission(energy_groups)) - this % xs(t) % prompt_nu_fission(:) = ZERO - - allocate(this % xs(t) % delayed_nu_fission(delayed_groups, & - energy_groups)) - this % xs(t) % delayed_nu_fission(:, :) = ZERO - - allocate(this % xs(t) % chi_prompt(energy_groups, energy_groups)) - this % xs(t) % chi_prompt(:, :) = ZERO - - allocate(this % xs(t) % chi_delayed(delayed_groups, energy_groups, & - energy_groups)) - this % xs(t) % chi_delayed(:, :, :) = ZERO - - allocate(this % xs(t) % inverse_velocity(energy_groups)) - this % xs(t) % inverse_velocity(:) = ZERO - - allocate(this % xs(t) % decay_rate(delayed_groups)) - this % xs(t) % decay_rate(:) = ZERO - - allocate(temp_mult(energy_groups, energy_groups)) - temp_mult(:, :) = ZERO - - allocate(mult_num(energy_groups, energy_groups)) - mult_num(:, :) = ZERO - - allocate(mult_denom(energy_groups, energy_groups)) - mult_denom(:, :) = ZERO - - allocate(scatt_coeffs(order_dim, energy_groups, energy_groups)) - scatt_coeffs(:, :, :) = ZERO - - this % scatter_format = scatter_format - - if (scatter_format == ANGLE_LEGENDRE) then - allocate(ScattDataLegendre :: this % xs(t) % scatter) - else if (scatter_format == ANGLE_TABULAR) then - allocate(ScattDataTabular :: this % xs(t) % scatter) - else if (scatter_format == ANGLE_HISTOGRAM) then - allocate(ScattDataHistogram :: this % xs(t) % scatter) - end if - - ! Add contribution from each nuclide in material - NUC_LOOP: do i = 1, mat % n_nuclides - associate(nuc => nuclides(mat % nuclide(i)) % obj) - - ! Copy atom density of nuclide in material - atom_density = mat % atom_density(i) - - select case (method) - case (TEMPERATURE_NEAREST) - - ! Determine actual temperatures to read - temp_desired = temps % data(i) - allocate(nuc_ts(1)) - - nuc_ts(1) = minloc(abs(nuc % kTs - temp_desired), dim=1) - temp_actual = nuc % kTs(nuc_ts(1)) - - if (abs(temp_actual - temp_desired) >= K_BOLTZMANN * tolerance) then - call fatal_error("MGXS library does not contain cross sections & - &for " // trim(this % name) // " at or near " // & - trim(to_str(nint(temp_desired / K_BOLTZMANN))) // " K.") - end if - - case (TEMPERATURE_INTERPOLATION) - - ! If temperature interpolation or multipole is selected, get a - ! list of bounding temperatures for each actual temperature - ! present in the model - temp_desired = temps % data(i) - allocate(nuc_ts(2)) - - do j = 1, size(nuc % kTs) - 1 - if (nuc % kTs(j) <= temp_desired .and. & - temp_desired < nuc % kTs(j + 1)) then - nuc_ts(1) = j - nuc_ts(2) = j + 1 - end if - end do - - call fatal_error("Nuclear data library does not contain cross sections & - &for " // trim(this % name) // " at temperatures that bound " // & - trim(to_str(nint(temp_desired / K_BOLTZMANN))) // " K.") - end select - - select type(nuc) - type is (MgxsIso) - do j = 1, size(nuc_ts) - - nuc_t = nuc_ts(j) - - if (size(nuc_ts) == 1) then - interp = ONE - else if (j == 1) then - interp = (ONE - (temp_desired - nuc % kTs(nuc_ts(1))) / & - (nuc % kTs(nuc_ts(2)) - nuc % kTs(nuc_ts(1)))) - else - interp = ONE - interp - end if - - ! Perform our operations which depend upon the type - ! Add contributions to total, absorption, and fission data (if necessary) - this % xs(t) % total = this % xs(t) % total + & - atom_density * nuc % xs(nuc_t) % total * interp - - this % xs(t) % absorption = this % xs(t) % absorption + & - atom_density * nuc % xs(nuc_t) % absorption * interp - - this % xs(t) % decay_rate = this % xs(t) % decay_rate + & - atom_density * nuc % xs(nuc_t) % decay_rate * interp - - this % xs(t) % inverse_velocity = & - this % xs(t) % inverse_velocity + & - atom_density * nuc % xs(nuc_t) % inverse_velocity * interp - - if (nuc % fissionable) then - - this % xs(t) % chi_prompt = this % xs(t) % chi_prompt + & - atom_density * nuc % xs(nuc_t) % chi_prompt * interp - - this % xs(t) % chi_delayed = this % xs(t) % chi_delayed + & - atom_density * nuc % xs(nuc_t) % chi_delayed * interp - - this % xs(t) % prompt_nu_fission = this % xs(t) % & - prompt_nu_fission + atom_density * nuc % xs(nuc_t) % & - prompt_nu_fission * interp - - this % xs(t) % delayed_nu_fission = this % xs(t) % & - delayed_nu_fission + atom_density * nuc % xs(nuc_t) % & - delayed_nu_fission * interp - - this % xs(t) % fission = this % xs(t) % fission + & - atom_density * nuc % xs(nuc_t) % fission * interp - - this % xs(t) % kappa_fission = this % xs(t) % kappa_fission +& - atom_density * nuc % xs(nuc_t) % kappa_fission * interp - end if - - ! We will next gather the multiplicity and scattering matrices. - ! To avoid multiple re-allocations as we resize the storage - ! matrix (and/or to avoidlots of duplicate code), we will use a - ! dense matrix for this storage, with a reduction to the sparse - ! format at the end. - - ! Get the multiplicity_matrix - ! To combine from nuclidic data we need to use the final relationship - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - ! Developed as follows: - ! mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - ! nuscatt_{i,g,g'} can be reconstructed from scatter % energy and - ! scatter % scattxs - do gin = 1, energy_groups - do gout = nuc % xs(nuc_t) % scatter % gmin(gin), nuc % xs(nuc_t) % scatter % gmax(gin) - - nuscatt = nuc % xs(nuc_t) % scatter % scattxs(gin) * & - nuc % xs(nuc_t) % scatter % energy(gin) % data(gout) - - mult_num(gout, gin) = mult_num(gout, gin) + atom_density * & - nuscatt * interp - - if (nuc % xs(nuc_t) % scatter % mult(gin) % data(gout) > ZERO) then - mult_denom(gout, gin) = mult_denom(gout,gin) + atom_density * & - nuscatt / nuc % xs(nuc_t) % scatter % mult(gin) % data(gout) * & - interp - else - ! Avoid division by zero - mult_denom(gout, gin) = mult_denom(gout,gin) + atom_density * & - interp - end if - end do - end do - - ! Get the complete scattering matrix - nuc_order_dim = size(nuc % xs(nuc_t) % scatter % dist(1) % data, dim=1) - nuc_order_dim = min(nuc_order_dim, order_dim) - - call nuc % xs(nuc_t) % scatter % get_matrix(nuc_order_dim, & - nuc_matrix) - - do gin = 1, energy_groups - do gout = nuc % xs(nuc_t) % scatter % gmin(gin), & - nuc % xs(nuc_t) % scatter % gmax(gin) - scatt_coeffs(1:nuc_order_dim, gout, gin) = & - scatt_coeffs(1: nuc_order_dim, gout, gin) + & - atom_density * interp * & - nuc_matrix(gin) % data(1:nuc_order_dim, gout) - end do - end do - end do - - type is (MgxsAngle) - call fatal_error("Invalid passing of MgxsAngle to MgxsIso object") - end select - - ! Obtain temp_mult - do gin = 1, energy_groups - do gout = 1, energy_groups - if (mult_denom(gout, gin) > ZERO) then - temp_mult(gout, gin) = mult_num(gout, gin) / mult_denom(gout, gin) - else - temp_mult(gout, gin) = ONE - end if - end do - end do - - ! Now create our jagged data from the dense data - call jagged_from_dense_2D(scatt_coeffs, jagged_scatt, gmin, gmax) - call jagged_from_dense_1D(temp_mult, jagged_mult) - - ! Initialize the ScattData Object - call this % xs(t) % scatter % init(gmin, gmax, jagged_mult, & - jagged_scatt) - - ! Now normalize chi - if (mat % fissionable) then - do gin = 1, energy_groups - norm = sum(this % xs(t) % chi_prompt(:, gin)) - if (norm > ZERO) then - this % xs(t) % chi_prompt(:, gin) = & - this % xs(t) % chi_prompt(:, gin) / norm - end if - end do - - do dg = 1, delayed_groups - do gin = 1, energy_groups - norm = sum(this % xs(t) % chi_delayed(dg, :, gin)) - if (norm > ZERO) then - this % xs(t) % chi_delayed(dg, :, gin) = & - this % xs(t) % chi_delayed(dg, :, gin) / norm - end if - end do - end do - end if - - ! Deallocate temporaries - deallocate(jagged_mult, jagged_scatt, gmin, gmax, scatt_coeffs, & - temp_mult, mult_num, mult_denom) - end associate ! nuc - end do NUC_LOOP - end do TEMP_LOOP - - end subroutine mgxsiso_combine - - subroutine mgxsang_combine(this, temps, mat, nuclides, energy_groups, & - delayed_groups, max_order, tolerance, method) - class(MgxsAngle), intent(inout) :: this ! The Mgxs to initialize - type(VectorReal), intent(in) :: temps ! Temperatures to obtain - type(Material), pointer, intent(in) :: mat ! base material - type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from - integer, intent(in) :: energy_groups ! Number of energy groups - integer, intent(in) :: delayed_groups ! Number of delayed groups - integer, intent(in) :: max_order ! Maximum requested order - real(8), intent(in) :: tolerance ! Tolerance on method - integer, intent(in) :: method ! Type of temperature access - - integer :: i ! loop index over nuclides - integer :: t ! temperature loop index - integer :: gin, gout ! group indices - integer :: dg ! delayed group index - real(8) :: atom_density ! atom density of a nuclide - integer :: ipol, iazi, n_pol, n_azi - real(8) :: norm, nuscatt - integer :: order_dim, nuc_order_dim - real(8), allocatable :: temp_mult(:, :, :, :), mult_num(:, :, :, :) - real(8), allocatable :: mult_denom(:, :, :, :), scatt_coeffs(:, :, :, :, :) - integer :: nuc_t - integer, allocatable :: nuc_ts(:) - real(8) :: temp_actual, temp_desired, interp - integer :: scatter_format - type(Jagged2D), allocatable :: nuc_matrix(:) - integer, allocatable :: gmin(:), gmax(:) - type(Jagged2D), allocatable :: jagged_scatt(:) - type(Jagged1D), allocatable :: jagged_mult(:) - - ! Set the meta-data - call mgxs_combine(this, temps, mat, nuclides, max_order, scatter_format, & - order_dim) - - ! Set the number of delayed groups - this % num_delayed_groups = delayed_groups - - ! Get the number of each polar and azi angles and make sure all the - ! NuclideAngle types have the same number of these angles - n_pol = -1 - n_azi = -1 - - do i = 1, mat % n_nuclides - select type(nuc => nuclides(mat % nuclide(i)) % obj) - type is (MgxsAngle) - - if (n_pol == -1) then - n_pol = nuc % n_pol - n_azi = nuc % n_azi - - allocate(this % polar(n_pol)) - this % polar(:) = nuc % polar(:) - - allocate(this % azimuthal(n_azi)) - this % azimuthal(:) = nuc % azimuthal(:) - else - if ((n_pol /= nuc % n_pol) .or. (n_azi /= nuc % n_azi)) then - call fatal_error("All angular data must be same length!") - end if - end if - end select - end do - - ! Create the Xs Data for each temperature - TEMP_LOOP: do t = 1, temps % size() - - ! Allocate and initialize the data needed for macro_xs(i_mat) object - allocate(this % xs(t) % total(energy_groups, n_azi, n_pol)) - this % xs(t) % total = ZERO - - allocate(this % xs(t) % absorption(energy_groups, n_azi, n_pol)) - this % xs(t) % absorption = ZERO - - allocate(this % xs(t) % fission(energy_groups, n_azi, n_pol)) - this % xs(t) % fission = ZERO - - allocate(this % xs(t) % decay_rate(delayed_groups, n_azi, n_pol)) - this % xs(t) % decay_rate = ZERO - - allocate(this % xs(t) % inverse_velocity(energy_groups, n_azi, n_pol)) - this % xs(t) % inverse_velocity = ZERO - - allocate(this % xs(t) % kappa_fission(energy_groups, n_azi, n_pol)) - this % xs(t) % kappa_fission = ZERO - - allocate(this % xs(t) % prompt_nu_fission(energy_groups, n_azi, n_pol)) - this % xs(t) % prompt_nu_fission = ZERO - - allocate(this % xs(t) % delayed_nu_fission(delayed_groups, & - energy_groups, n_azi, n_pol)) - this % xs(t) % delayed_nu_fission = ZERO - - allocate(this % xs(t) % chi_prompt(energy_groups, energy_groups, & - n_azi, n_pol)) - this % xs(t) % chi_prompt = ZERO - - allocate(this % xs(t) % chi_delayed(delayed_groups, energy_groups, & - energy_groups, n_azi, n_pol)) - this % xs(t) % chi_delayed = ZERO - - allocate(temp_mult(energy_groups, energy_groups, n_azi, n_pol)) - temp_mult = ZERO - - allocate(mult_num(energy_groups, energy_groups, n_azi, n_pol)) - mult_num = ZERO - - allocate(mult_denom(energy_groups, energy_groups, n_azi, n_pol)) - mult_denom = ZERO - - allocate(scatt_coeffs(order_dim, energy_groups, energy_groups, n_azi, n_pol)) - scatt_coeffs = ZERO - - allocate(this % xs(t) % scatter(n_azi, n_pol)) - - do ipol = 1, n_pol - do iazi = 1, n_azi - if (scatter_format == ANGLE_LEGENDRE) then - allocate(ScattDataLegendre :: & - this % xs(t) % scatter(iazi, ipol) % obj) - else if (scatter_format == ANGLE_TABULAR) then - allocate(ScattDataTabular :: & - this % xs(t) % scatter(iazi, ipol) % obj) - else if (scatter_format == ANGLE_HISTOGRAM) then - allocate(ScattDataHistogram :: & - this % xs(t) % scatter(iazi, ipol) % obj) - end if - end do - end do - - ! Add contribution from each nuclide in material - NUC_LOOP: do i = 1, mat % n_nuclides - associate(nuc => nuclides(mat % nuclide(i)) % obj) - - select case (method) - case (TEMPERATURE_NEAREST) - - ! Determine actual temperatures to read - temp_desired = temps % data(i) - allocate(nuc_ts(1)) - - nuc_ts(1) = minloc(abs(nuc % kTs - temp_desired), dim=1) - temp_actual = nuc % kTs(nuc_ts(1)) - - if (abs(temp_actual - temp_desired) >= K_BOLTZMANN * tolerance) then - call fatal_error("MGXS library does not contain cross sections & - &for " // trim(this % name) // " at or near " // & - trim(to_str(nint(temp_desired / K_BOLTZMANN))) // " K.") - end if - - case (TEMPERATURE_INTERPOLATION) - - ! If temperature interpolation or multipole is selected, get a - ! list of bounding temperatures for each actual temperature - ! present in the model - temp_desired = temps % data(i) - allocate(nuc_ts(2)) - - do j = 1, size(nuc % kTs) - 1 - if (nuc % kTs(j) <= temp_desired .and. & - temp_desired < nuc % kTs(j + 1)) then - nuc_ts(1) = j - nuc_ts(2) = j + 1 - end if - end do - - call fatal_error("Nuclear data library does not contain cross sections & - &for " // trim(this % name) // " at temperatures that bound " // & - trim(to_str(nint(temp_desired / K_BOLTZMANN))) // " K.") - end select - - ! Copy atom density of nuclide in material - atom_density = mat % atom_density(i) - - select type(nuc) - type is (MgxsAngle) - do j = 1, size(nuc_ts) - - nuc_t = nuc_ts(j) - - if (size(nuc_ts) == 1) then - interp = ONE - else if (j == 1) then - interp = (ONE - (temp_desired - nuc % kTs(nuc_ts(1))) / & - (nuc % kTs(nuc_ts(2)) - nuc % kTs(nuc_ts(1)))) - else - interp = ONE - interp - end if - - ! Perform our operations which depend upon the type - ! Add contributions to total, absorption, and fission data - ! (if necessary) - this % xs(t) % total = this % xs(t) % total + & - atom_density * nuc % xs(nuc_t) % total * interp - - this % xs(t) % absorption = this % xs(t) % absorption + & - atom_density * nuc % xs(nuc_t) % absorption * interp - - this % xs(t) % decay_rate = this % xs(t) % decay_rate + & - atom_density * nuc % xs(nuc_t) % decay_rate * interp - - this % xs(t) % inverse_velocity = & - this % xs(t) % inverse_velocity + & - atom_density * nuc % xs(nuc_t) % inverse_velocity * interp - - if (nuc % fissionable) then - - this % xs(t) % chi_prompt = this % xs(t) % chi_prompt + & - atom_density * nuc % xs(nuc_t) % chi_prompt * interp - - this % xs(t) % chi_delayed = this % xs(t) % chi_delayed + & - atom_density * nuc % xs(nuc_t) % chi_delayed * interp - - this % xs(t) % prompt_nu_fission = & - this % xs(t) % prompt_nu_fission + atom_density * & - nuc % xs(nuc_t) % prompt_nu_fission * interp - - this % xs(t) % delayed_nu_fission = & - this % xs(t) % delayed_nu_fission + atom_density * & - nuc % xs(nuc_t) % delayed_nu_fission * interp - - this % xs(t) % fission = this % xs(t) % fission + & - atom_density * nuc % xs(nuc_t) % fission * interp - - this % xs(t) % kappa_fission = this % xs(t) % kappa_fission & - + atom_density * nuc % xs(nuc_t) % kappa_fission * interp - - end if - - ! We will next gather the multiplicity and scattering matrices. - ! To avoid multiple re-allocations as we resize the storage - ! matrix (and/or to avoidlots of duplicate code), we will use a - ! dense matrix for this storage, with a reduction to the sparse - ! format at the end. - - ! Get the multiplicity_matrix - ! To combine from nuclidic data we need to use the final relationship - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - ! Developed as follows: - ! mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - ! nuscatt_{i,g,g'} can be reconstructed from scatter % energy and - ! scatter % scattxs - do ipol = 1, n_pol - do iazi = 1, n_azi - do gin = 1, energy_groups - do gout = nuc % xs(nuc_t) % scatter(iazi, ipol) %obj % gmin(gin), & - nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % gmax(gin) - - nuscatt = nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % scattxs(gin) * & - nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % energy(gin) % data(gout) - - mult_num(gout, gin, iazi, ipol) = & - mult_num(gout, gin, iazi, ipol) + atom_density * & - nuscatt * interp - - if (nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) > ZERO) then - mult_denom(gout, gin, iazi, ipol) = & - mult_denom(gout, gin, iazi, ipol) + atom_density * & - interp * nuscatt / & - nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) - else - ! Avoid division by zero - mult_denom(gout, gin, iazi, ipol) = & - mult_denom(gout, gin, iazi, ipol) + atom_density * & - interp - end if - end do - end do - - ! Get the complete scattering matrix - nuc_order_dim = & - size(nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % & - dist(1) % data, dim=1) - nuc_order_dim = min(nuc_order_dim, order_dim) - - call nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % & - get_matrix(nuc_order_dim, nuc_matrix) - - do gin = 1, energy_groups - do gout = & - nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % gmin(gin), & - nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % gmax(gin) - scatt_coeffs(1:nuc_order_dim, gout, gin, iazi, ipol) = & - scatt_coeffs(1: nuc_order_dim, gout, gin, iazi, ipol) + & - atom_density * interp * & - nuc_matrix(gin) % data(1:nuc_order_dim, gout) - end do ! gout - end do ! gin - end do ! iazi - end do ! ipol - end do - type is (MgxsIso) - call fatal_error("Invalid passing of MgxsIso to MgxsAngle object") - end select - - ! Obtain temp_mult, create jaged arrays and initialize the - ! ScattData object. - do ipol = 1, n_pol - do iazi = 1, n_azi - ! Obtain temp_mult - do gin = 1, energy_groups - do gout = 1, energy_groups - if (mult_denom(gout, gin, iazi, ipol) > ZERO) then - temp_mult(gout, gin, iazi, ipol) = & - mult_num(gout, gin, iazi, ipol) / & - mult_denom(gout, gin, iazi, ipol) - else - temp_mult(gout, gin, iazi, ipol) = ONE - end if - end do - end do - - ! Now create our jagged data from the dense data - call jagged_from_dense_2D(scatt_coeffs(:, :, :, iazi, ipol), & - jagged_scatt, gmin, gmax) - call jagged_from_dense_1D(temp_mult(:, :, iazi, ipol), & - jagged_mult) - - ! Initialize the ScattData Object - call this % xs(t) % scatter(iazi, ipol) % obj % init(gmin, & - gmax, jagged_mult, jagged_scatt) - deallocate(jagged_scatt, jagged_mult, gmin, gmax) - end do - end do - - ! Now normalize chi - if (mat % fissionable) then - do ipol = 1, n_pol - do iazi = 1, n_azi - do gin = 1, energy_groups - norm = sum(this % xs(t) % chi_prompt(:, gin, iazi, ipol)) - if (norm > ZERO) then - this % xs(t) % chi_prompt(:, gin, iazi, ipol) = & - this % xs(t) % chi_prompt(:, gin, iazi, ipol) / norm - end if - end do - end do - end do - - do dg = 1, delayed_groups - do ipol = 1, n_pol - do iazi = 1, n_azi - do gin = 1, energy_groups - norm = sum(this % xs(t) % chi_delayed(dg, :, gin, iazi, ipol)) - if (norm > ZERO) then - this % xs(t) % chi_delayed(dg, :, gin, iazi, ipol) = & - this % xs(t) % chi_delayed(dg, :, gin, iazi, ipol)& - / norm - end if - end do - end do - end do - end do - - end if - - ! Deallocate temporaries - deallocate(scatt_coeffs, temp_mult, mult_num, mult_denom) - end associate ! nuc - end do NUC_LOOP - - end do TEMP_LOOP - - end subroutine mgxsang_combine - -!=============================================================================== -! MGXS*_GET_XS returns the requested data cross section data -!=============================================================================== - - pure function mgxsiso_get_xs(this, xstype, gin, gout, uvw, mu, dg) result(xs) - class(MgxsIso), intent(in) :: this ! The Xs to get data from - character(*) , intent(in) :: xstype ! Type of xs requested - integer, intent(in) :: gin ! Incoming Energy group - integer, optional, intent(in) :: gout ! Outgoing Energy group - real(8), optional, intent(in) :: uvw(3) ! Requested Angle - real(8), optional, intent(in) :: mu ! Change in angle - integer, optional, intent(in) :: dg ! Delayed group - real(8) :: xs ! Requested x/s - integer :: t ! temperature index - - t = this % index_temp - - select case(xstype) - - case('total') - xs = this % xs(t) % total(gin) - - case('absorption') - xs = this % xs(t) % absorption(gin) - - case('fission') - xs = this % xs(t) % fission(gin) - - case('kappa-fission') - xs = this % xs(t) % kappa_fission(gin) - - case('inverse-velocity') - xs = this % xs(t) % inverse_velocity(gin) - - case('decay rate') - if (present(dg)) then - xs = this % xs(t) % decay_rate(dg) - else - xs = this % xs(t) % decay_rate(1) - end if - - case('prompt-nu-fission') - xs = this % xs(t) % prompt_nu_fission(gin) - - case('delayed-nu-fission') - if (present(dg)) then - xs = this % xs(t) % delayed_nu_fission(dg, gin) - else - xs = sum(this % xs(t) % delayed_nu_fission(:, gin)) - end if - - case('nu-fission') - xs = this % xs(t) % prompt_nu_fission(gin) + & - sum(this % xs(t) % delayed_nu_fission(:, gin)) - - case('chi-prompt') - if (present(gout)) then - xs = this % xs(t) % chi_prompt(gout,gin) - else - ! Not sure youd want a 1 or a 0, but here you go! - xs = sum(this % xs(t) % chi_prompt(:, gin)) - end if - - case('chi-delayed') - if (present(gout)) then - if (present(dg)) then - xs = this % xs(t) % chi_delayed(dg, gout, gin) - else - xs = this % xs(t) % chi_delayed(1, gout, gin) - end if - else - if (present(dg)) then - xs = sum(this % xs(t) % chi_delayed(dg, :, gin)) - else - xs = sum(this % xs(t) % chi_delayed(dg, :, gin)) - end if - end if - - case('scatter') - if (present(gout)) then - if (gout < this % xs(t) % scatter % gmin(gin) .or. & - gout > this % xs(t) % scatter % gmax(gin)) then - xs = ZERO - else - xs = this % xs(t) % scatter % scattxs(gin) * & - this % xs(t) % scatter % energy(gin) % data(gout) - end if - else - xs = this % xs(t) % scatter % scattxs(gin) - end if - - case('scatter/mult') - if (present(gout)) then - if (gout < this % xs(t) % scatter % gmin(gin) .or. & - gout > this % xs(t) % scatter % gmax(gin)) then - xs = ZERO - else - xs = this % xs(t) % scatter % scattxs(gin) * & - this % xs(t) % scatter % energy(gin) % data(gout) / & - this % xs(t) % scatter % mult(gin) % data(gout) - end if - else - xs = this % xs(t) % scatter % scattxs(gin) / & - (dot_product(this % xs(t) % scatter % mult(gin) % data, & - this % xs(t) % scatter % energy(gin) % data)) - end if - - case('scatter*f_mu/mult','scatter*f_mu') - if (present(gout)) then - if (gout < this % xs(t) % scatter % gmin(gin) .or. & - gout > this % xs(t) % scatter % gmax(gin)) then - xs = ZERO - else - xs = this % xs(t) % scatter % scattxs(gin) * & - this % xs(t) % scatter % energy(gin) % data(gout) * & - this % xs(t) % scatter % calc_f(gin, gout, mu) - if (xstype == 'scatter*f_mu/mult') then - xs = xs / this % xs(t) % scatter % mult(gin) % data(gout) - end if - end if - else - xs = ZERO - ! TODO (Not likely needed) - ! (asking for f_mu without asking for a group or mu would mean the - ! user of this code wants the complete 1-outgoing group distribution - ! which Im not sure what they would do with that. - end if - - case default - xs = ZERO - end select - - end function mgxsiso_get_xs - - pure function mgxsang_get_xs(this, xstype, gin, gout, uvw, mu, dg) result(xs) - class(MgxsAngle), intent(in) :: this ! The Mgxs to initialize - character(*) , intent(in) :: xstype ! Type of xs requested - integer, intent(in) :: gin ! Incoming Energy group - integer, optional, intent(in) :: gout ! Outgoing Energy group - real(8), optional, intent(in) :: uvw(3) ! Requested Angle - real(8), optional, intent(in) :: mu ! Change in angle - integer, optional, intent(in) :: dg ! Delayed group - real(8) :: xs ! Requested x/s - - integer :: iazi, ipol, t - - t = this % index_temp - - if (present(uvw)) then - - call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) - - select case(xstype) - - case('total') - xs = this % xs(t) % total(gin, iazi, ipol) - - case('absorption') - xs = this % xs(t) % absorption(gin, iazi, ipol) - - case('fission') - xs = this % xs(t) % fission(gin, iazi, ipol) - - case('kappa-fission') - xs = this % xs(t) % kappa_fission(gin, iazi, ipol) - - case('prompt-nu-fission') - xs = this % xs(t) % prompt_nu_fission(gin, iazi, ipol) - - case('delayed-nu-fission') - if (present(dg)) then - xs = this % xs(t) % delayed_nu_fission(dg, gin, iazi, ipol) - else - xs = sum(this % xs(t) % delayed_nu_fission(:, gin, iazi, ipol)) - end if - - case('nu-fission') - xs = this % xs(t) % prompt_nu_fission(gin, iazi, ipol) + & - sum(this % xs(t) % delayed_nu_fission(:, gin, iazi, ipol)) - - case('chi-prompt') - if (present(gout)) then - xs = this % xs(t) % chi_prompt(gout, gin, iazi, ipol) - else - ! Not sure you would want a 1 or a 0, but here you go! - xs = sum(this % xs(t) % chi_prompt(:, gin, iazi, ipol)) - end if - - case('chi-delayed') - if (present(gout)) then - if (present(dg)) then - xs = this % xs(t) % chi_delayed(dg, gout, gin, iazi, ipol) - else - xs = this % xs(t) % chi_delayed(1, gout, gin, iazi, ipol) - end if - else - if (present(dg)) then - xs = sum(this % xs(t) % chi_delayed(dg, :, gin, iazi, ipol)) - else - xs = sum(this % xs(t) % chi_delayed(1, :, gin, iazi, ipol)) - end if - end if - - case('decay rate') - if (present(dg)) then - xs = this % xs(t) % decay_rate(iazi, ipol, dg) - else - xs = this % xs(t) % decay_rate(iazi, ipol, 1) - end if - - case('inverse-velocity') - xs = this % xs(t) % inverse_velocity(gin, iazi, ipol) - - case('scatter') - if (present(gout)) then - if (gout < this % xs(t) % scatter(iazi, ipol) % obj % gmin(gin) .or. & - gout > this % xs(t) % scatter(iazi, ipol) % obj % gmax(gin)) then - xs = ZERO - else - xs = this % xs(t) % scatter(iazi, ipol) % obj % scattxs(gin) * & - this % xs(t) % scatter(iazi, ipol) % obj % energy(gin) % data(gout) - end if - else - xs = this % xs(t) % scatter(iazi, ipol) % obj % scattxs(gin) - end if - - case('scatter/mult') - if (present(gout)) then - if (gout < this % xs(t) % scatter(iazi, ipol) % obj % gmin(gin) .or. & - gout > this % xs(t) % scatter(iazi, ipol) % obj % gmax(gin)) then - xs = ZERO - else - xs = this % xs(t) % scatter(iazi, ipol) % obj % scattxs(gin) * & - this % xs(t) % scatter(iazi, ipol) % obj % energy(gin) % data(gout) / & - this % xs(t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) - end if - else - xs = this % xs(t) % scatter(iazi, ipol) % obj % scattxs(gin) / & - (dot_product(this % xs(t) % scatter(iazi, ipol) % obj % mult(gin) % data, & - this % xs(t) % scatter(iazi, ipol) % obj % energy(gin) % data)) - end if - - case('scatter*f_mu/mult','scatter*f_mu') - if (present(gout)) then - if (gout < this % xs(t) % scatter(iazi, ipol) % obj % gmin(gin) .or. & - gout > this % xs(t) % scatter(iazi, ipol) % obj % gmax(gin)) then - xs = ZERO - else - xs = this % xs(t) % scatter(iazi, ipol) % obj % scattxs(gin) * & - this % xs(t) % scatter(iazi, ipol) % obj % energy(gin) % data(gout) - xs = xs * this % xs(t) % scatter(iazi, ipol) % obj % calc_f(gin, gout, mu) - if (xstype == 'scatter*f_mu/mult') then - xs = xs / & - this % xs(t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) - end if - end if - else - xs = ZERO - ! TODO (Not likely needed) - ! (asking for f_mu without asking for a group or mu would mean the - ! user of this code wants the complete 1-outgoing group distribution - ! which Im not sure what they would do with that. - end if - - case default - xs = ZERO - - end select - - else - xs = ZERO - end if - - end function mgxsang_get_xs - -!=============================================================================== -! MGXS*_SAMPLE_FISSION_ENERGY samples the outgoing energy from a fission event -!=============================================================================== - - subroutine mgxsiso_sample_fission_energy(this, gin, uvw, dg, gout) - - class(MgxsIso), intent(in) :: this ! Data to work with - integer, intent(in) :: gin ! Incoming energy group - real(8), intent(in) :: uvw(3) ! Particle Direction - integer, intent(out) :: dg ! Delayed group - integer, intent(out) :: gout ! Sampled outgoing group - real(8) :: xi_pd ! Our random number for prompt/delayed - real(8) :: xi_gout ! Our random number for gout - real(8) :: prob_gout ! Running probability for gout - - ! Get nu and nu_prompt - real(8) :: prob_prompt - - prob_prompt = this % get_xs('prompt-nu-fission', gin) / & - this % get_xs('nu-fission', gin) - - ! Sample random numbers - xi_pd = prn() - xi_gout = prn() - - ! Neutron is born prompt - if (xi_pd <= prob_prompt) then - - ! set the delayed group for the particle born from fission to 0 - dg = 0 - - gout = 1 - prob_gout = this % get_xs('chi-prompt', gin, gout) - - do while (prob_gout < xi_gout) - gout = gout + 1 - prob_gout = prob_gout + this % get_xs('chi-prompt', gin, gout) - end do - - ! Neutron is born delayed - else - - ! Get the delayed group - dg = 0 - - do while (xi_pd >= prob_prompt) - dg = dg + 1 - prob_prompt = prob_prompt + & - this % get_xs('delayed-nu-fission', gin, dg=dg) & - / this % get_xs('nu-fission', gin) - end do - - ! Adjust dg in case of round off error - dg = min(dg, this % num_delayed_groups) - - ! Get the outgoing group - gout = 1 - prob_gout = this % get_xs('chi-delayed', gin, gout, dg=dg) - - do while (prob_gout < xi_gout) - gout = gout + 1 - prob_gout = prob_gout + this % get_xs('chi-delayed', gin, gout, dg=dg) - end do - end if - - end subroutine mgxsiso_sample_fission_energy - - subroutine mgxsang_sample_fission_energy(this, gin, uvw, dg, gout) - class(MgxsAngle), intent(in) :: this ! Data to work with - integer, intent(in) :: gin ! Incoming energy group - real(8), intent(in) :: uvw(3) ! Direction vector - integer, intent(out) :: dg ! Delayed group - integer, intent(out) :: gout ! Sampled outgoing group - real(8) :: xi_pd ! Our random number for prompt/delayed - real(8) :: xi_gout ! Our random number for gout - real(8) :: prob_gout ! Running probability for gout - real(8) :: prob_prompt - - ! Get nu and nu_prompt - prob_prompt = this % get_xs('prompt-nu-fission', gin, uvw=uvw) / & - this % get_xs('nu-fission', gin, uvw=uvw) - - ! Sample random numbers - xi_pd = prn() - xi_gout = prn() - - ! Neutron is born prompt - if (xi_pd <= prob_prompt) then - - ! set the delayed group for the particle born from fission to 0 - dg = 0 - - gout = 1 - prob_gout = this % get_xs('chi-prompt', gin, gout, uvw=uvw) - - do while (prob_gout < xi_gout) - gout = gout + 1 - prob_gout = prob_gout + & - this % get_xs('chi-prompt', gin, gout, uvw=uvw) - end do - - ! Neutron is born delayed - else - - ! Get the delayed group - dg = 0 - - do while (xi_pd >= prob_prompt) - dg = dg + 1 - prob_prompt = prob_prompt + & - this % get_xs('delayed-nu-fission', gin, uvw=uvw, dg=dg) / & - this % get_xs('nu-fission', gin, uvw=uvw) - end do - - ! Adjust dg in case of round off error - dg = min(dg, this % num_delayed_groups) - - ! Get the outgoing group - gout = 1 - prob_gout = this % get_xs('chi-delayed', gin, gout, uvw=uvw, dg=dg) - - do while (prob_gout < xi_gout) - gout = gout + 1 - prob_gout = prob_gout + & - this % get_xs('chi-delayed', gin, gout, uvw=uvw, dg=dg) - end do - end if - - end subroutine mgxsang_sample_fission_energy - -!=============================================================================== -! MGXS*_SAMPLE_SCATTER Selects outgoing energy and angle after a scatter event -!=============================================================================== - - subroutine mgxsiso_sample_scatter(this, uvw, gin, gout, mu, wgt) - class(MgxsIso), intent(in) :: this - real(8), intent(in) :: uvw(3) ! Incoming neutron direction - integer, intent(in) :: gin ! Incoming neutron group - integer, intent(out) :: gout ! Sampled outgoin group - real(8), intent(out) :: mu ! Sampled change in angle - real(8), intent(inout) :: wgt ! Particle weight - - call this % xs(this % index_temp) % scatter % sample(gin, gout, mu, wgt) - - end subroutine mgxsiso_sample_scatter - - subroutine mgxsang_sample_scatter(this, uvw, gin, gout, mu, wgt) - class(MgxsAngle), intent(in) :: this - real(8), intent(in) :: uvw(3) ! Incoming neutron direction - integer, intent(in) :: gin ! Incoming neutron group - integer, intent(out) :: gout ! Sampled outgoin group - real(8), intent(out) :: mu ! Sampled change in angle - real(8), intent(inout) :: wgt ! Particle weight - - integer :: iazi, ipol ! Angular indices - - call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) - call this % xs(this % index_temp) % scatter(iazi, ipol) % obj % sample( & - gin, gout, mu, wgt) - - end subroutine mgxsang_sample_scatter - -!=============================================================================== -! MGXS*_CALCULATE_XS determines the multi-group cross sections -! for the material the particle is currently traveling through. -!=============================================================================== - - subroutine mgxsiso_calculate_xs(this, gin, sqrtkT, uvw, xs) - class(MgxsIso), intent(inout) :: this - integer, intent(in) :: gin ! Incoming neutron group - real(8), intent(in) :: sqrtkT ! Material temperature - real(8), intent(in) :: uvw(3) ! Incoming neutron direction - type(MaterialMacroXS), intent(inout) :: xs ! Resultant Mgxs Data - - ! Update the temperature index - call this % find_temperature(sqrtkT) - - xs % total = this % xs(this % index_temp) % total(gin) - xs % absorption = this % xs(this % index_temp) % absorption(gin) - xs % nu_fission = & - this % xs(this % index_temp) % prompt_nu_fission(gin) + & - sum(this % xs(this % index_temp) % delayed_nu_fission(:, gin)) - - end subroutine mgxsiso_calculate_xs - - subroutine mgxsang_calculate_xs(this, gin, sqrtkT, uvw, xs) - class(MgxsAngle), intent(inout) :: this - integer, intent(in) :: gin ! Incoming neutron group - real(8), intent(in) :: sqrtkT ! Material temperature - real(8), intent(in) :: uvw(3) ! Incoming neutron direction - type(MaterialMacroXS), intent(inout) :: xs ! Resultant Mgxs Data - - integer :: iazi, ipol - - ! Update the temperature and angle indices - call this % find_temperature(sqrtkT) - call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) - - xs % total = this % xs(this % index_temp) % & - total(gin, iazi, ipol) - xs % absorption = this % xs(this % index_temp) % & - absorption(gin, iazi, ipol) - xs % nu_fission = this % xs(this % index_temp) % & - prompt_nu_fission(gin, iazi, ipol) + & - sum(this % xs(this % index_temp) % & - delayed_nu_fission(:, gin, iazi, ipol)) - - end subroutine mgxsang_calculate_xs - -!=============================================================================== -! MGXS_FIND_TEMPERATURE sets the temperature index for the given -! sqrt(temperature), (with temperature in units of eV) -!=============================================================================== - - subroutine mgxs_find_temperature(this, sqrtkT) - class(Mgxs), intent(inout) :: this - real(8), intent(in) :: sqrtkT ! Temperature (in units of eV) - - this % index_temp = minloc(abs(this % kTs - (sqrtkT * sqrtkT)), dim=1) - - end subroutine mgxs_find_temperature - -!=============================================================================== -! FIND_ANGLE finds the closest angle on the data grid and returns that index -!=============================================================================== - - pure subroutine find_angle(polar, azimuthal, uvw, i_azi, i_pol) - real(8), intent(in) :: polar(:) ! Polar angles [0,pi] - real(8), intent(in) :: azimuthal(:) ! Azi. angles [-pi,pi] - real(8), intent(in) :: uvw(3) ! Direction of motion - integer, intent(inout) :: i_pol ! Closest polar bin - integer, intent(inout) :: i_azi ! Closest azi bin - - real(8) :: my_pol, my_azi, dangle - - ! Convert uvw to polar and azi - - my_pol = acos(uvw(3)) - my_azi = atan2(uvw(2), uvw(1)) - - ! Search for equi-binned angles - dangle = PI / real(size(polar),8) - i_pol = floor(my_pol / dangle + ONE) - dangle = TWO * PI / real(size(azimuthal),8) - i_azi = floor((my_azi + PI) / dangle + ONE) - - end subroutine find_angle - -!=============================================================================== -! FREE_MEMORY_MGXS deallocates global arrays defined in this module -!=============================================================================== - - subroutine free_memory_mgxs() - if (allocated(nuclides_MG)) deallocate(nuclides_MG) - if (allocated(macro_xs)) deallocate(macro_xs) - if (allocated(energy_bins)) deallocate(energy_bins) - if (allocated(energy_bin_avg)) deallocate(energy_bin_avg) - end subroutine free_memory_mgxs - -end module mgxs_header diff --git a/src/scattdata_header.F90 b/src/scattdata_header.F90 deleted file mode 100644 index 511e2a2376..0000000000 --- a/src/scattdata_header.F90 +++ /dev/null @@ -1,852 +0,0 @@ -module scattdata_header - - use algorithm, only: binary_search - use constants - use error, only: fatal_error - use math - use random_lcg, only: prn - - implicit none - - -!=============================================================================== -! JAGGED1D and JAGGED2D is a type which allows for jagged 1-D or 2-D array. -!=============================================================================== - - type :: Jagged2D - real(8), allocatable :: data(:, :) - end type Jagged2D - - type :: Jagged1D - real(8), allocatable :: data(:) - end type Jagged1D - -!=============================================================================== -! SCATTDATA contains all the data to describe the scattering energy and -! angular distribution -!=============================================================================== - - type, abstract :: ScattData - ! The data attribute of the energy, mult, and dist arrays - ! are not necessarily 1-indexed as they instead will be allocated - ! from a minimum outgoing group to an outgoing minimum group. - ! Normalized p0 matrix on its own for sampling energy - type(Jagged1D), allocatable :: energy(:) ! (Gin % data(Gout)) - ! Nu-scatter multiplication (i.e. nu-scatt/scatt) - type(Jagged1D), allocatable :: mult(:) ! (Gin % data(Gout)) - ! Angular distribution - type(Jagged2D), allocatable :: dist(:) ! (Gin % data(Order/Nmu, Gout) - integer, allocatable :: gmin(:) ! Minimum outgoing group - integer, allocatable :: gmax(:) ! Maximum outgoing group - real(8), allocatable :: scattxs(:) ! Isotropic Sigma_{s,g_{in}} - - contains - procedure(scattdata_init_), deferred :: init ! Initializes ScattData - procedure(scattdata_calc_f_), deferred :: calc_f ! Calculates f, given mu - procedure(scattdata_sample_), deferred :: sample ! sample the scatter event - procedure :: get_matrix => scattdata_get_matrix ! Rebuild scattering matrix - end type ScattData - - abstract interface - subroutine scattdata_init_(this, gmin, gmax, mult, coeffs) - import ScattData, Jagged1D, Jagged2D - class(ScattData), intent(inout) :: this ! Object to work with - integer, intent(in) :: gmin(:) ! Min Gout - integer, intent(in) :: gmax(:) ! Max Gout - type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix - type(Jagged2D), intent(in) :: coeffs(:) ! Coefficients to use - end subroutine scattdata_init_ - - pure function scattdata_calc_f_(this, gin, gout, mu) result(f) - import ScattData - class(ScattData), intent(in) :: this ! Scattering Object to work with - integer, intent(in) :: gin ! Incoming Energy Group - integer, intent(in) :: gout ! Outgoing Energy Group - real(8), intent(in) :: mu ! Angle of interest - real(8) :: f ! Return value of f(mu) - - end function scattdata_calc_f_ - - subroutine scattdata_sample_(this, gin, gout, mu, wgt) - import ScattData - class(ScattData), intent(in) :: this ! Scattering Object to work with - integer, intent(in) :: gin ! Incoming neutron group - integer, intent(out) :: gout ! Sampled outgoin group - real(8), intent(out) :: mu ! Sampled change in angle - real(8), intent(inout) :: wgt ! Particle weight - end subroutine scattdata_sample_ - end interface - - type, extends(ScattData) :: ScattDataLegendre - ! Maximal value for rejection sampling from rectangle - type(Jagged1D), allocatable :: max_val(:) ! (Gin % data(Gout)) - contains - procedure :: init => scattdatalegendre_init - procedure :: calc_f => scattdatalegendre_calc_f - procedure :: sample => scattdatalegendre_sample - end type ScattDataLegendre - - type, extends(ScattData) :: ScattDataHistogram - real(8), allocatable :: mu(:) ! Mu bins - real(8) :: dmu ! Mu spacing - ! Histogram of f(mu) (dist has CDF) - type(Jagged2D), allocatable :: fmu(:) ! (Gin % data(Order/Nmu x Gout) - contains - procedure :: init => scattdatahistogram_init - procedure :: calc_f => scattdatahistogram_calc_f - procedure :: sample => scattdatahistogram_sample - procedure :: get_matrix => scattdatahistogram_get_matrix - end type ScattDataHistogram - - type, extends(ScattData) :: ScattDataTabular - real(8), allocatable :: mu(:) ! Mu bins - real(8) :: dmu ! Mu spacing - ! PDF of f(mu) (dist has CDF) - type(Jagged2D), allocatable :: fmu(:) ! (Gin % data(Order/Nmu x Gout) - contains - procedure :: init => scattdatatabular_init - procedure :: calc_f => scattdatatabular_calc_f - procedure :: sample => scattdatatabular_sample - procedure :: get_matrix => scattdatatabular_get_matrix - end type ScattDataTabular - -!=============================================================================== -! SCATTDATACONTAINER allocatable array for storing ScattData Objects (for angle) -!=============================================================================== - - type ScattDataContainer - class(ScattData), allocatable :: obj - end type ScattDataContainer - -contains - -!=============================================================================== -! SCATTDATA*_INIT builds the scattdata object -!=============================================================================== - - subroutine scattdata_init(this, order, gmin, gmax, energy, mult) - class(ScattData), intent(inout) :: this ! Object to work on - integer, intent(in) :: order ! Data Order - integer, intent(in) :: gmin(:) ! Min Gout - integer, intent(in) :: gmax(:) ! Max Gout - type(Jagged1D), intent(inout) :: energy(:) ! Energy Transfer Matrix - type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix - - integer :: groups, gin - real(8) :: norm - - groups = size(energy, dim=1) - - allocate(this % gmin(groups)) - allocate(this % gmax(groups)) - allocate(this % energy(groups)) - allocate(this % mult(groups)) - allocate(this % dist(groups)) - - this % gmin = gmin - this % gmax = gmax - - ! Set the outgoing energy PDF values - do gin = 1, groups - ! Make sure energy is normalized (i.e., CDF is 1) - norm = sum(energy(gin) % data(:)) - if (norm /= ZERO) energy(gin) % data(:) = energy(gin) % data(:) / norm - ! Set the values - allocate(this % energy(gin) % data(gmin(gin):gmax(gin))) - this % energy(gin) % data(:) = energy(gin) % data(:) - allocate(this % mult(gin) % data(gmin(gin):gmax(gin))) - this % mult(gin) % data(gmin(gin):gmax(gin)) = & - mult(gin) % data(gmin(gin):gmax(gin)) - allocate(this % dist(gin) % data(order, gmin(gin):gmax(gin))) - this % dist(gin) % data = ZERO - end do - end subroutine scattdata_init - - subroutine scattdatalegendre_init(this, gmin, gmax, mult, coeffs) - class(ScattDataLegendre), intent(inout) :: this ! Object to work on - integer, intent(in) :: gmin(:) ! Min Gout - integer, intent(in) :: gmax(:) ! Max Gout - type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix - type(Jagged2D), intent(in) :: coeffs(:) ! Coefficients to use - - real(8) :: dmu, mu, f, norm - integer :: imu, Nmu, gout, gin, groups, order - type(Jagged1D), allocatable :: energy(:) - type(Jagged2D), allocatable :: matrix(:) - - groups = size(coeffs) - order = size(coeffs(1) % data, dim=1) - - ! make a copy of coeffs that we can use to extract data and normalize - allocate(matrix(groups)) - do gin = 1, groups - allocate(matrix(gin) % data(order, gmin(gin):gmax(gin))) - matrix(gin) % data = coeffs(gin) % data - end do - - ! Get scattxs value - allocate(this % scattxs(groups)) - ! Get this by summing the un-normalized P0 coefficient in matrix - ! over all outgoing groups - do gin = 1, groups - this % scattxs(gin) = sum(matrix(gin) % data(1, :), dim=1) - end do - - allocate(energy(groups)) - ! Build energy transfer probability matrix from data in matrix - ! while also normalizing matrix itself (making CDF of f(mu=1)=1) - do gin = 1, groups - allocate(energy(gin) % data(gmin(gin):gmax(gin))) - energy(gin) % data = ZERO - do gout = gmin(gin), gmax(gin) - norm = matrix(gin) % data(1, gout) - energy(gin) % data(gout) = norm - if (norm /= ZERO) then - matrix(gin) % data(:, gout) = matrix(gin) % data(:, gout) / norm - end if - end do - end do - - call scattdata_init(this, order, gmin, gmax, energy, mult) - - allocate(this % max_val(groups)) - ! Set dist values from matrix and initialize max_val - do gin = 1, groups - do gout = gmin(gin), gmax(gin) - this % dist(gin) % data(:, gout) = matrix(gin) % data(:, gout) - end do - allocate(this % max_val(gin) % data(gmin(gin):gmax(gin))) - this % max_val(gin) % data(:) = ZERO - end do - - ! Step through the polynomial with fixed number of points to identify - ! the maximal value. - Nmu = 1001 - dmu = TWO / real(Nmu - 1, 8) - do gin = 1, groups - do gout = gmin(gin), gmax(gin) - do imu = 1, Nmu - ! Update mu. Do first and last seperate to avoid float errors - if (imu == 1) then - mu = -ONE - else if (imu == Nmu) then - mu = ONE - else - mu = -ONE + real(imu - 1, 8) * dmu - end if - ! Calculate probability - f = this % calc_f(gin,gout,mu) - ! If this is a new max, store it. - if (f > this % max_val(gin) % data(gout)) & - this % max_val(gin) % data(gout) = f - end do - ! Finally, since we may not have caught the exact max, add 10% margin - this % max_val(gin) % data(gout) = & - this % max_val(gin) % data(gout) * 1.1_8 - end do - end do - end subroutine scattdatalegendre_init - - subroutine scattdatahistogram_init(this, gmin, gmax, mult, coeffs) - class(ScattDataHistogram), intent(inout) :: this ! Object to work on - integer, intent(in) :: gmin(:) ! Min Gout - integer, intent(in) :: gmax(:) ! Max Gout - type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix - type(Jagged2D), intent(in) :: coeffs(:) ! Coefficients to use - - integer :: imu, gin, gout, groups, order - real(8) :: norm - type(Jagged1D), allocatable :: energy(:) - type(Jagged2D), allocatable :: matrix(:) - - groups = size(coeffs) - order = size(coeffs(1) % data, dim=1) - - ! make a copy of coeffs that we can use to extract data and normalize - allocate(matrix(groups)) - do gin = 1, groups - allocate(matrix(gin) % data(order, gmin(gin):gmax(gin))) - matrix(gin) % data(:, :) = coeffs(gin) % data(:, :) - end do - - ! Get scattxs value - allocate(this % scattxs(groups)) - ! Get this by summing the un-normalized angular distribution in matrix - ! over all outgoing groups - do gin = 1, groups - this % scattxs(gin) = sum(matrix(gin) % data(:, :)) - end do - - allocate(energy(groups)) - ! Build energy transfer probability matrix from data in matrix - ! while also normalizing matrix itself (making CDF of f(mu=1)=1) - do gin = 1, groups - allocate(energy(gin) % data(gmin(gin):gmax(gin))) - do gout = gmin(gin), gmax(gin) - norm = sum(matrix(gin) % data(:, gout)) - energy(gin) % data(gout) = norm - if (norm /= ZERO) then - matrix(gin) % data(:, gout) = matrix(gin) % data(:, gout) / norm - end if - end do - end do - - call scattdata_init(this, order, gmin, gmax, energy, mult) - - allocate(this % mu(order)) - this % dmu = TWO / real(order, 8) - this % mu(1) = -ONE - do imu = 2, order - this % mu(imu) = -ONE + real(imu - 1, 8) * this % dmu - end do - - ! Integrate this histogram so we can avoid rejection sampling while - ! also saving the original histogram in fmu - allocate(this % fmu(groups)) - do gin = 1, groups - allocate(this % fmu(gin) % data(order, gmin(gin):gmax(gin))) - do gout = gmin(gin), gmax(gin) - ! Store the histogram - this % fmu(gin) % data(:, gout) = matrix(gin) % data(:, gout) - ! Integrate the histogram - this % dist(gin) % data(1, gout) = & - this % dmu * matrix(gin) % data(1, gout) - do imu = 2, order - this % dist(gin) % data(imu, gout) = & - this % dmu * matrix(gin) % data(imu, gout) + & - this % dist(gin) % data(imu - 1, gout) - end do - - ! Normalize the integral to unity - norm = this % dist(gin) % data(order, gout) - if (norm > ZERO) then - this % fmu(gin) % data(:, gout) = & - this % fmu(gin) % data(:, gout) / norm - this % dist(gin) % data(:, gout) = & - this % dist(gin) % data(:, gout) / norm - end if - end do - end do - - end subroutine scattdatahistogram_init - - subroutine scattdatatabular_init(this, gmin, gmax, mult, coeffs) - class(ScattDataTabular), intent(inout) :: this ! Object to work on - integer, intent(in) :: gmin(:) ! Min Gout - integer, intent(in) :: gmax(:) ! Max Gout - type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix - type(Jagged2D), intent(in) :: coeffs(:) ! Coefficients to use - - integer :: imu, gin, gout, groups, order - real(8) :: norm - type(Jagged1D), allocatable :: energy(:) - type(Jagged2D), allocatable :: matrix(:) - - groups = size(coeffs) - order = size(coeffs(1) % data, dim=1) - - ! make a copy of coeffs that we can use to extract data and normalize - allocate(matrix(groups)) - do gin = 1, groups - allocate(matrix(gin) % data(order, gmin(gin):gmax(gin))) - matrix(gin) % data = coeffs(gin) % data - end do - - ! Build the angular distribution mu values - allocate(this % mu(order)) - this % dmu = TWO / real(order - 1, 8) - this % mu(1) = -ONE - do imu = 2, order - 1 - this % mu(imu) = -ONE + real(imu - 1, 8) * this % dmu - end do - this % mu(order) = ONE - - ! Get scattxs - allocate(this % scattxs(groups)) - ! Get this by integrating the scattering distribution over all mu points - ! and then combining over all outgoing groups - ! over all outgoing groups - do gin = 1, groups - norm = ZERO - do gout = gmin(gin), gmax(gin) - do imu = 2, order - norm = norm + HALF * this % dmu * & - (matrix(gin) % data(imu - 1, gout) + & - matrix(gin) % data(imu, gout)) - end do - end do - this % scattxs(gin) = norm - end do - - allocate(energy(groups)) - ! Build energy transfer probability matrix from data in matrix - do gin = 1, groups - allocate(energy(gin) % data(gmin(gin):gmax(gin))) - do gout = gmin(gin), gmax(gin) - norm = ZERO - do imu = 2, order - norm = norm + HALF * this % dmu * & - (matrix(gin) % data(imu - 1, gout) + & - matrix(gin) % data(imu, gout)) - end do - energy(gin) % data(gout) = norm - end do - end do - call scattdata_init(this, order, gmin, gmax, energy, mult) - - ! Calculate f(mu) and integrate it so we can avoid rejection sampling - allocate(this % fmu(groups)) - do gin = 1, groups - allocate(this % fmu(gin) % data(order, gmin(gin):gmax(gin))) - do gout = gmin(gin), gmax(gin) - ! Coeffs contain f(mu), put in f(mu) as that is where the - ! PDF lives - this % fmu(gin) % data(:, gout) = matrix(gin) % data(:, gout) - - ! Force positivity - do imu = 1, order - if (this % fmu(gin) % data(imu, gout) < ZERO) then - this % fmu(gin) % data(imu, gout) = ZERO - end if - end do - - ! Re-normalize fmu for numerical integration issues and in case - ! the negative fix-up introduced un-normalized data while - ! accruing the CDF - norm = ZERO - do imu = 2, order - norm = norm + HALF * this % dmu * & - (this % fmu(gin) % data(imu - 1, gout) + & - this % fmu(gin) % data(imu, gout)) - this % dist(gin) % data(imu, gout) = norm - end do - if (norm > ZERO) then - this % fmu(gin) % data(:, gout) = & - this % fmu(gin) % data(:, gout) / norm - this % dist(gin) % data(:, gout) = & - this % dist(gin) % data(:, gout) / norm - end if - end do - end do - end subroutine scattdatatabular_init - -!=============================================================================== -! SCATTDATA_*_CALC_F Calculates the value of f given mu (and gin,gout pair) -!=============================================================================== - - pure function scattdatalegendre_calc_f(this, gin, gout, mu) result(f) - class(ScattDataLegendre), intent(in) :: this ! The ScattData to evaluate - integer, intent(in) :: gin ! Incoming Energy Group - integer, intent(in) :: gout ! Outgoing Energy Group - real(8), intent(in) :: mu ! Angle of interest - real(8) :: f ! Return value of f(mu) - - ! Plug mu in to the legendre expansion and go from there - if (gout < this % gmin(gin) .or. gout > this % gmax(gin)) then - f = ZERO - else - f = evaluate_legendre(this % dist(gin) % data(:, gout), mu) - end if - - end function scattdatalegendre_calc_f - - pure function scattdatahistogram_calc_f(this, gin, gout, mu) result(f) - class(ScattDataHistogram), intent(in) :: this ! The ScattData to evaluate - integer, intent(in) :: gin ! Incoming Energy Group - integer, intent(in) :: gout ! Outgoing Energy Group - real(8), intent(in) :: mu ! Angle of interest - real(8) :: f ! Return value of f(mu) - - integer :: imu - - if (gout < this % gmin(gin) .or. gout > this % gmax(gin)) then - f = ZERO - else - ! Find mu bin - if (mu == ONE) then - imu = size(this % fmu(gin) % data, dim=1) - else - imu = floor((mu + ONE) / this % dmu + ONE) - end if - - f = this % fmu(gin) % data(imu, gout) - end if - - end function scattdatahistogram_calc_f - - pure function scattdatatabular_calc_f(this, gin, gout, mu) result(f) - class(ScattDataTabular), intent(in) :: this ! The ScattData to evaluate - integer, intent(in) :: gin ! Incoming Energy Group - integer, intent(in) :: gout ! Outgoing Energy Group - real(8), intent(in) :: mu ! Angle of interest - real(8) :: f ! Return value of f(mu) - - integer :: imu - real(8) :: r - - if (gout < this % gmin(gin) .or. gout > this % gmax(gin)) then - f = ZERO - else - ! Find mu bin - if (mu == ONE) then - imu = size(this % fmu(gin) % data, dim=1) - 1 - else - imu = floor((mu + ONE) / this % dmu + ONE) - end if - - ! Now interpolate to find f(mu) - r = (mu - this % mu(imu)) / (this % mu(imu + 1) - this % mu(imu)) - f = (ONE - r) * this % fmu(gin) % data(imu, gout) + & - r * this % fmu(gin) % data(imu + 1, gout) - end if - - end function scattdatatabular_calc_f - -!=============================================================================== -! SCATTDATA*_SCATTER Samples the outgoing energy and change in angle. -!=============================================================================== - - subroutine scattdatalegendre_sample(this, gin, gout, mu, wgt) - class(ScattDataLegendre), intent(in) :: this ! Scattering object to use - integer, intent(in) :: gin ! Incoming neutron group - integer, intent(out) :: gout ! Sampled outgoin group - real(8), intent(out) :: mu ! Sampled change in angle - real(8), intent(inout) :: wgt ! Particle weight - - real(8) :: xi ! Our random number - real(8) :: prob ! Running probability - real(8) :: u, f, M - integer :: samples - - xi = prn() - gout = this % gmin(gin) - prob = this % energy(gin) % data(gout) - - do while ((prob < xi) .and. (gout < this % gmax(gin))) - gout = gout + 1 - prob = prob + this % energy(gin) % data(gout) - end do - - ! Now we can sample mu using the legendre representation of the scattering - ! kernel in data(1:this % order) - - ! Do with rejection sampling from a rectangular bounding box - ! Set maximal value - M = this % max_val(gin) % data(gout) - samples = 0 - do - mu = TWO * prn() - ONE - f = this % calc_f(gin, gout, mu) - if (f > ZERO) then - u = prn() * M - if (u <= f) then - exit - end if - end if - samples = samples + 1 - if (samples > MAX_SAMPLE) then - call fatal_error("Maximum number of Legendre expansion samples reached!") - end if - end do - - wgt = wgt * this % mult(gin) % data(gout) - - end subroutine scattdatalegendre_sample - - subroutine scattdatahistogram_sample(this, gin, gout, mu, wgt) - class(ScattDataHistogram), intent(in) :: this ! Scattering object to use - integer, intent(in) :: gin ! Incoming neutron group - integer, intent(out) :: gout ! Sampled outgoin group - real(8), intent(out) :: mu ! Sampled change in angle - real(8), intent(inout) :: wgt ! Particle weight - - real(8) :: xi ! Our random number - real(8) :: prob ! Running probability - integer :: imu - - xi = prn() - gout = this % gmin(gin) - prob = this % energy(gin) % data(gout) - - do while ((prob < xi) .and. (gout < this % gmax(gin))) - gout = gout + 1 - prob = prob + this % energy(gin) % data(gout) - end do - - xi = prn() - if (xi < this % dist(gin) % data(1, gout)) then - imu = 1 - else - imu = binary_search(this % dist(gin) % data(:, gout), & - size(this % dist(gin) % data(:, gout)), xi) + 1 - end if - - ! Randomly select a mu in this bin. - mu = prn() * this % dmu + this % mu(imu) - - wgt = wgt * this % mult(gin) % data(gout) - - end subroutine scattdatahistogram_sample - - subroutine scattdatatabular_sample(this, gin, gout, mu, wgt) - class(ScattDataTabular), intent(in) :: this ! Scattering object to use - integer, intent(in) :: gin ! Incoming neutron group - integer, intent(out) :: gout ! Sampled outgoin group - real(8), intent(out) :: mu ! Sampled change in angle - real(8), intent(inout) :: wgt ! Particle weight - - real(8) :: xi ! Our random number - real(8) :: prob ! Running probability - real(8) :: mu0, frac, mu1 - real(8) :: c_k, c_k1, p0, p1 - integer :: k, NP - - xi = prn() - gout = this % gmin(gin) - prob = this % energy(gin) % data(gout) - - do while ((prob < xi) .and. (gout < this % gmax(gin))) - gout = gout + 1 - prob = prob + this % energy(gin) % data(gout) - end do - - ! determine outgoing cosine bin - NP = size(this % dist(gin) % data(:, gout)) - xi = prn() - - c_k = this % dist(gin) % data(1, gout) - do k = 1, NP - 1 - c_k1 = this % dist(gin) % data(k + 1, gout) - if (xi < c_k1) exit - c_k = c_k1 - end do - - ! check to make sure k is <= NP - 1 - k = min(k, NP - 1) - - p0 = this % fmu(gin) % data(k, gout) - mu0 = this % mu(k) - ! Linear-linear interpolation to find mu value w/in bin. - p1 = this % fmu(gin) % data(k + 1, gout) - mu1 = this % mu(k + 1) - - if (p0 == p1) then - mu = mu0 + (xi - c_k) / p0 - else - frac = (p1 - p0) / (mu1 - mu0) - mu = mu0 + & - (sqrt(max(ZERO, p0 * p0 + TWO * frac * (xi - c_k))) - p0) / frac - end if - - if (mu <= -ONE) then - mu = -ONE - else if (mu >= ONE) then - mu = ONE - end if - - wgt = wgt * this % mult(gin) % data(gout) - - end subroutine scattdatatabular_sample - -!=============================================================================== -! SCATTDATA*_GET_MATRIX Reproduces the original scattering matrix (densely) -! using ScattData's information of fmu/dist, energy, and scattxs -!=============================================================================== - - subroutine scattdata_get_matrix(this, req_order, matrix) - class(ScattData), intent(in) :: this ! Scattering Object to work with - integer, intent(in) :: req_order ! Requested order of matrix - type(Jagged2D), allocatable, intent(inout) :: matrix(:) ! Resultant matrix just built - - integer :: order, groups, gin, gout - - groups = size(this % energy) - ! Set gin and gout for getting the order - order = min(req_order, size(this % dist(1) % data, dim=1)) - - if (allocated(matrix)) deallocate(matrix) - allocate(matrix(groups)) - ! Initialize to 0; this way the zero entries in the dense matrix dont - ! need to be explicitly set, requiring a significant increase in the - ! lines of code. - do gin = 1, groups - allocate(matrix(gin) % data(order, groups)) - do gout = this % gmin(gin), this % gmax(gin) - matrix(gin) % data(:, gout) = this % scattxs(gin) * & - this % energy(gin) % data(gout) * & - this % dist(gin) % data(1:order, gout) - end do - end do - end subroutine scattdata_get_matrix - - subroutine scattdatahistogram_get_matrix(this, req_order, matrix) - class(ScattDataHistogram), intent(in) :: this ! Scattering Object to work with - integer, intent(in) :: req_order ! Requested order of matrix - type(Jagged2D), allocatable, intent(inout) :: matrix(:) ! Resultant matrix just built - - integer :: order, groups, gin, gout - - groups = size(this % energy) - order = min(req_order, size(this % dist(1) % data, dim=1)) - - if (allocated(matrix)) deallocate(matrix) - allocate(matrix(groups)) - ! Initialize to 0; this way the zero entries in the dense matrix dont - ! need to be explicitly set, requiring a significant increase in the - ! lines of code. - do gin = 1, groups - allocate(matrix(gin) % data(order, groups)) - do gout = this % gmin(gin), this % gmax(gin) - matrix(gin) % data(:, gout) = this % scattxs(gin) * & - this % energy(gin) % data(gout) * & - this % fmu(gin) % data(1:order, gout) - end do - end do - end subroutine scattdatahistogram_get_matrix - - subroutine scattdatatabular_get_matrix(this, req_order, matrix) - class(ScattDataTabular), intent(in) :: this ! Scattering Object to work with - integer, intent(in) :: req_order ! Requested order of matrix - type(Jagged2D), allocatable, intent(inout) :: matrix(:) ! Resultant matrix just built - - integer :: order, groups, gin, gout - - groups = size(this % energy) - order = min(req_order, size(this % dist(1) % data, dim=1)) - - if (allocated(matrix)) deallocate(matrix) - allocate(matrix(groups)) - ! Initialize to 0; this way the zero entries in the dense matrix dont - ! need to be explicitly set, requiring a significant increase in the - ! lines of code. - do gin = 1, groups - allocate(matrix(gin) % data(order, groups)) - do gout = this % gmin(gin), this % gmax(gin) - matrix(gin) % data(:, gout) = this % scattxs(gin) * & - this % energy(gin) % data(gout) * & - this % fmu(gin) % data(1:order, gout) - end do - end do - end subroutine scattdatatabular_get_matrix - -!=============================================================================== -! JAGGED_FROM_DENSE_*D Creates a jagged array from a sparse dense matrix. -! The user can supply a key which indicates the values to remove, but the -! default is ZERO -!=============================================================================== - - subroutine jagged_from_dense_1D(dense, jagged, lo_bounds_, hi_bounds_, key_) - real(8), intent(in) :: dense(:, :) - type(Jagged1D), allocatable, intent(inout) :: jagged(:) - real(8), intent(in), optional :: key_ - integer, intent(inout), allocatable, optional :: lo_bounds_(:) - integer, intent(inout), allocatable, optional :: hi_bounds_(:) - - real(8) :: key - integer :: i, jmin, jmax - integer, allocatable :: lo_bounds(:), hi_bounds(:) - - if (present(key_)) then - key = key_ - else - key = ZERO - end if - - allocate(lo_bounds(size(dense, dim=2))) - allocate(hi_bounds(size(dense, dim=2))) - - if (allocated(jagged)) deallocate(jagged) - allocate(jagged(size(dense, dim=2))) - do i = 1, size(dense, dim=2) - ! Find the min and max j values - do jmin = 1, size(dense, dim=1) - if (dense(jmin, i) /= key) exit - end do - do jmax = size(dense, dim=1), 1, -1 - if (dense(jmax, i) /= key) exit - end do - ! Treat the case of all values matching the key - if (jmin > jmax) then - jmin = i - jmax = i - end if - - ! Now store the jagged row - allocate(jagged(i) % data(jmin:jmax)) - jagged(i) % data(jmin:jmax) = dense(jmin:jmax, i) - - lo_bounds(i) = jmin - hi_bounds(i) = jmax - end do - - if (present(lo_bounds_)) then - if (allocated(lo_bounds_)) deallocate(lo_bounds_) - allocate(lo_bounds_(size(dense, dim=2))) - lo_bounds_ = lo_bounds - end if - if (present(hi_bounds_)) then - if (allocated(hi_bounds_)) deallocate(hi_bounds_) - allocate(hi_bounds_(size(dense, dim=2))) - hi_bounds_ = hi_bounds - end if - - end subroutine jagged_from_dense_1D - - subroutine jagged_from_dense_2D(dense, jagged, lo_bounds_, hi_bounds_, key_) - real(8), intent(in) :: dense(:, :, :) - type(Jagged2D), allocatable, intent(inout) :: jagged(:) - real(8), intent(in), optional :: key_ - integer, intent(inout), allocatable, optional :: lo_bounds_(:) - integer, intent(inout), allocatable, optional :: hi_bounds_(:) - - real(8) :: key - integer :: i, jmin, jmax - integer, allocatable :: lo_bounds(:), hi_bounds(:) - - if (present(key_)) then - key = key_ - else - key = ZERO - end if - - allocate(lo_bounds(size(dense, dim=3))) - allocate(hi_bounds(size(dense, dim=3))) - - if (allocated(jagged)) deallocate(jagged) - allocate(jagged(size(dense, dim=3))) - do i = 1, size(dense, dim=3) - ! Find the min and max j values - do jmin = 1, size(dense, dim=2) - if (any(dense(:, jmin, i) /= key)) exit - end do - do jmax = size(dense, dim=2), 1, -1 - if (any(dense(:, jmax, i) /= key)) exit - end do - ! Treat the case of all values matching the key - if (jmin > jmax) then - jmin = i - jmax = i - end if - - ! Now store the jagged row - allocate(jagged(i) % data(size(dense, dim=1), jmin:jmax)) - jagged(i) % data(:, jmin:jmax) = dense(:, jmin:jmax, i) - - lo_bounds(i) = jmin - hi_bounds(i) = jmax - end do - - if (present(lo_bounds_)) then - if (allocated(lo_bounds_)) deallocate(lo_bounds_) - allocate(lo_bounds_(size(dense, dim=3))) - lo_bounds_ = lo_bounds - end if - if (present(hi_bounds_)) then - if (allocated(hi_bounds_)) deallocate(hi_bounds_) - allocate(hi_bounds_(size(dense, dim=3))) - hi_bounds_ = hi_bounds - end if - - end subroutine jagged_from_dense_2D - -end module scattdata_header From 7fd4cbb1403b04f7a609ba4379b3fe78229fd118 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Wed, 13 Jun 2018 20:26:20 -0400 Subject: [PATCH 022/100] whoops, missed some code i could remove --- src/mgxs_data.F90 | 183 ---------------------------------------------- 1 file changed, 183 deletions(-) diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index 0278c96eb6..8c48d5c98e 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -24,149 +24,6 @@ contains ! nuclides and sab_tables arrays !=============================================================================== - ! subroutine read_mgxs() - ! integer :: i ! index in materials array - ! integer :: j ! index over nuclides in material - ! integer :: i_nuclide ! index in nuclides array - ! character(20) :: name ! name of library to load - ! integer :: representation ! Data representation - ! character(MAX_LINE_LEN) :: temp_str - ! type(Material), pointer :: mat - ! type(SetChar) :: already_read - ! integer(HID_T) :: file_id - ! integer(HID_T) :: xsdata_group - ! logical :: file_exists - ! type(VectorReal), allocatable :: temps(:) - ! character(MAX_WORD_LEN) :: word - ! integer, allocatable :: array(:) - - ! ! Check if MGXS Library exists - ! inquire(FILE=path_cross_sections, EXIST=file_exists) - ! if (.not. file_exists) then - - ! ! Could not find MGXS Library file - ! call fatal_error("Cross sections HDF5 file '" & - ! // trim(path_cross_sections) // "' does not exist!") - ! end if - - ! call write_message("Loading cross section data...", 5) - - ! ! Get temperatures - ! call get_temperatures(temps) - - ! ! Open file for reading - ! file_id = file_open(path_cross_sections, 'r', parallel=.true.) - - ! ! Read filetype - ! call read_attribute(word, file_id, "filetype") - ! if (word /= 'mgxs') then - ! call fatal_error("Provided MGXS Library is not a MGXS Library file.") - ! end if - - ! ! Read revision number for the MGXS Library file and make sure it matches - ! ! with the current version - ! call read_attribute(array, file_id, "version") - ! if (any(array /= VERSION_MGXS_LIBRARY)) then - ! call fatal_error("MGXS Library file version does not match current & - ! &version supported by OpenMC.") - ! end if - - ! ! allocate arrays for MGXS storage and cross section cache - ! allocate(nuclides_MG(n_nuclides)) - - ! ! ========================================================================== - ! ! READ ALL MGXS CROSS SECTION TABLES - - ! ! Loop over all files - ! MATERIAL_LOOP: do i = 1, n_materials - ! mat => materials(i) - - ! NUCLIDE_LOOP: do j = 1, mat % n_nuclides - ! name = mat % names(j) - - ! if (.not. already_read % contains(name)) then - ! i_nuclide = mat % nuclide(j) - - ! call write_message("Loading " // trim(name) // " data...", 6) - - ! ! Check to make sure cross section set exists in the library - ! if (object_exists(file_id, trim(name))) then - ! xsdata_group = open_group(file_id, trim(name)) - ! else - ! call fatal_error("Data for '" // trim(name) // "' does not exist in "& - ! &// trim(path_cross_sections)) - ! end if - - ! ! First find out the data representation - ! if (attribute_exists(xsdata_group, "representation")) then - - ! call read_attribute(temp_str, xsdata_group, "representation") - - ! if (trim(temp_str) == 'isotropic') then - ! representation = MGXS_ISOTROPIC - ! else if (trim(temp_str) == 'angle') then - ! representation = MGXS_ANGLE - ! else - ! call fatal_error("Invalid Data Representation!") - ! end if - ! else - ! ! Default to isotropic representation - ! representation = MGXS_ISOTROPIC - ! end if - - ! ! Now allocate accordingly - ! select case(representation) - - ! case(MGXS_ISOTROPIC) - ! allocate(MgxsIso :: nuclides_MG(i_nuclide) % obj) - - ! case(MGXS_ANGLE) - ! allocate(MgxsAngle :: nuclides_MG(i_nuclide) % obj) - - ! end select - - ! ! Now read in the data specific to the type we just declared - ! call nuclides_MG(i_nuclide) % obj % from_hdf5(xsdata_group, & - ! num_energy_groups, num_delayed_groups, temps(i_nuclide), & - ! temperature_method, temperature_tolerance, max_order, & - ! legendre_to_tabular, legendre_to_tabular_points) - - ! ! Add name to dictionary - ! call already_read % add(name) - - ! call close_group(xsdata_group) - - ! end if - ! end do NUCLIDE_LOOP - ! end do MATERIAL_LOOP - - ! ! Avoid some valgrind leak errors - ! call already_read % clear() - - ! ! Loop around material - ! MATERIAL_LOOP3: do i = 1, n_materials - - ! ! Get material - ! mat => materials(i) - - ! ! Loop around nuclides in material - ! NUCLIDE_LOOP2: do j = 1, mat % n_nuclides - - ! ! Is this fissionable? - ! if (nuclides_MG(mat % nuclide(j)) % obj % fissionable) then - ! mat % fissionable = .true. - ! end if - ! if (mat % fissionable) then - ! exit NUCLIDE_LOOP2 - ! end if - - ! end do NUCLIDE_LOOP2 - ! end do MATERIAL_LOOP3 - - ! call file_close(file_id) - - ! end subroutine read_mgxs - subroutine read_mgxs() integer :: i ! index in materials array integer :: j ! index over nuclides in material @@ -248,45 +105,6 @@ contains ! CREATE_MACRO_XS generates the macroscopic xs from the microscopic input data !=============================================================================== - ! subroutine create_macro_xs() - ! integer :: i_mat ! index in materials array - ! type(Material), pointer :: mat ! current material - ! type(VectorReal), allocatable :: kTs(:) - - ! allocate(macro_xs(n_materials)) - - ! ! Get temperatures to read for each material - ! call get_mat_kTs(kTs) - - ! ! Force all nuclides in a material to be the same representation. - ! ! Therefore type(nuclides(mat % nuclide(1)) % obj) dictates type(macroxs). - ! ! At the same time, we will find the scattering type, as that will dictate - ! ! how we allocate the scatter object within macroxs.allocate(macro_xs(n_materials)) - ! do i_mat = 1, n_materials - - ! ! Get the material - ! mat => materials(i_mat) - - ! ! Get the scattering type for the first nuclide - ! select type(nuc => nuclides_MG(mat % nuclide(1)) % obj) - ! type is (MgxsIso) - ! allocate(MgxsIso :: macro_xs(i_mat) % obj) - ! type is (MgxsAngle) - ! allocate(MgxsAngle :: macro_xs(i_mat) % obj) - ! end select - - ! ! Do not read materials which we do not actually use in the problem to - ! ! reduce storage - ! if (allocated(kTs(i_mat) % data)) then - ! call macro_xs(i_mat) % obj % combine(kTs(i_mat), mat, nuclides_MG, & - ! num_energy_groups, num_delayed_groups, max_order, & - ! temperature_tolerance, temperature_method) - ! end if - ! end do - - ! end subroutine create_macro_xs - - subroutine create_macro_xs() integer :: i_mat ! index in materials array type(Material), pointer :: mat ! current material @@ -318,7 +136,6 @@ contains end subroutine create_macro_xs - !=============================================================================== ! GET_MAT_kTs returns a list of temperatures (in eV) that each ! material appears at in the model. From 7c819f02bc15f7367a56617c211ea98f0a1bc59b Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Thu, 14 Jun 2018 20:22:31 -0400 Subject: [PATCH 023/100] got it working with OpenMP --- src/mgxs.cpp | 156 +++++++++++++++-------------- src/mgxs.h | 50 ++++++---- src/mgxs_data.F90 | 23 ++++- src/mgxs_interface.F90 | 69 ++++--------- src/mgxs_interface.cpp | 221 ++++++++++++++++++----------------------- src/mgxs_interface.h | 49 ++++----- src/physics_mg.F90 | 22 +++- src/tallies/tally.F90 | 218 +++++++++++++++++++--------------------- src/tracking.F90 | 12 ++- 9 files changed, 404 insertions(+), 416 deletions(-) diff --git a/src/mgxs.cpp b/src/mgxs.cpp index 4f92a64eee..3a079a9325 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -15,7 +15,7 @@ void Mgxs::init(const std::string& in_name, const double in_awr, const double_1dvec& in_kTs, const bool in_fissionable, const int in_scatter_format, const int in_num_groups, const int in_num_delayed_groups, const double_1dvec& in_polar, - const double_1dvec& in_azimuthal) + const double_1dvec& in_azimuthal, const int n_threads) { name = in_name; awr = in_awr; @@ -29,20 +29,23 @@ void Mgxs::init(const std::string& in_name, const double in_awr, azimuthal = in_azimuthal; n_pol = polar.size(); n_azi = azimuthal.size(); - index_temp = 0; - last_sqrtkT = 0.; - index_pol = 0; - index_azi = 0; - last_uvw[0] = 1.; - last_uvw[1] = 0.; - last_uvw[2] = 0.; + cache.resize(n_threads); + for (int thread = 0; thread < n_threads; thread++) { + cache[thread].sqrtkT = 0.; + cache[thread].t = 0; + cache[thread].p = 0; + cache[thread].a = 0; + cache[thread].uvw[0] = 1.; + cache[thread].uvw[1] = 0.; + cache[thread].uvw[2] = 0.; + } } void Mgxs::_metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, const int in_num_delayed_groups, double_1dvec& temperature, int& method, const double tolerance, int_1dvec& temps_to_read, int& order_dim, - bool& is_isotropic) + bool& is_isotropic, const int n_threads) { // get name char char_name[MAX_WORD_LEN]; @@ -242,21 +245,23 @@ void Mgxs::_metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, // Finally use this data to initialize the MGXS Object init(in_name, in_awr, in_kTs, in_fissionable, in_scatter_format, - in_num_groups, in_num_delayed_groups, in_polar, in_azimuthal); + in_num_groups, in_num_delayed_groups, in_polar, in_azimuthal, + n_threads); } -void Mgxs::from_hdf5(hid_t xs_id, int energy_groups, int delayed_groups, - double_1dvec& temperature, int& method, double tolerance, - int max_order, bool legendre_to_tabular, - int legendre_to_tabular_points) +void Mgxs::from_hdf5(hid_t xs_id, const int energy_groups, + const int delayed_groups, double_1dvec& temperature, int& method, + const double tolerance, const int max_order, + const bool legendre_to_tabular, const int legendre_to_tabular_points, + const int n_threads) { // Call generic data gathering routine (will populate the metadata) int order_data; int_1dvec temps_to_read; bool is_isotropic; _metadata_from_hdf5(xs_id, energy_groups, delayed_groups, temperature, - method, tolerance, temps_to_read, order_data, is_isotropic); + method, tolerance, temps_to_read, order_data, is_isotropic, n_threads); // Set number of energy and delayed groups int final_scatter_format = scatter_format; @@ -285,8 +290,8 @@ void Mgxs::from_hdf5(hid_t xs_id, int energy_groups, int delayed_groups, void Mgxs::build_macro(const std::string& in_name, double_1dvec& mat_kTs, - std::vector& micros, double_1dvec& atom_densities, - int& method, double tolerance) + std::vector& micros, double_1dvec& atom_densities, int& method, + const double tolerance, const int n_threads) { // Get the minimum data needed to initialize: // Dont need awr, but lets just initialize it anyways @@ -305,7 +310,8 @@ void Mgxs::build_macro(const std::string& in_name, double_1dvec& mat_kTs, double_1dvec in_azimuthal = micros[0]->azimuthal; init(in_name, in_awr, mat_kTs, in_fissionable, in_scatter_format, - in_num_groups, in_num_delayed_groups, in_polar, in_azimuthal); + in_num_groups, in_num_delayed_groups, in_polar, in_azimuthal, + n_threads); // Create the xs data for each temperature for (int t = 0; t < mat_kTs.size(); t++) { @@ -395,52 +401,52 @@ void Mgxs::combine(std::vector& micros, double_1dvec& scalars, } -double Mgxs::get_xs(const int xstype, const int gin, int* gout, double* mu, - int* dg) +double Mgxs::get_xs(const int tid, const int xstype, const int gin, + int* gout, double* mu, int* dg) { // This method assumes that the temperature and angle indices are set double val; switch(xstype) { case MG_GET_XS_TOTAL: - val = xs[index_temp].total[index_pol][index_azi][gin]; + val = xs[cache[tid].t].total[cache[tid].p][cache[tid].a][gin]; break; case MG_GET_XS_ABSORPTION: - val = xs[index_temp].absorption[index_pol][index_azi][gin]; + val = xs[cache[tid].t].absorption[cache[tid].p][cache[tid].a][gin]; break; case MG_GET_XS_INVERSE_VELOCITY: - val = xs[index_temp].inverse_velocity[index_pol][index_azi][gin]; + val = xs[cache[tid].t].inverse_velocity[cache[tid].p][cache[tid].a][gin]; break; case MG_GET_XS_DECAY_RATE: if (dg != nullptr) { - val = xs[index_temp].decay_rate[index_pol][index_azi][*dg + 1]; + val = xs[cache[tid].t].decay_rate[cache[tid].p][cache[tid].a][*dg + 1]; } else { - val = xs[index_temp].decay_rate[index_pol][index_azi][0]; + val = xs[cache[tid].t].decay_rate[cache[tid].p][cache[tid].a][0]; } break; case MG_GET_XS_SCATTER: case MG_GET_XS_SCATTER_MULT: case MG_GET_XS_SCATTER_FMU_MULT: case MG_GET_XS_SCATTER_FMU: - val = xs[index_temp].scatter[index_pol] - [index_azi]->get_xs(xstype, gin, gout, mu); + val = xs[cache[tid].t].scatter[cache[tid].p] + [cache[tid].a]->get_xs(xstype, gin, gout, mu); break; case MG_GET_XS_FISSION: if (fissionable) { - val = xs[index_temp].fission[index_pol][index_azi][gin]; + val = xs[cache[tid].t].fission[cache[tid].p][cache[tid].a][gin]; } else { val = 0.; } break; case MG_GET_XS_KAPPA_FISSION: if (fissionable) { - val = xs[index_temp].kappa_fission[index_pol][index_azi][gin]; + val = xs[cache[tid].t].kappa_fission[cache[tid].p][cache[tid].a][gin]; } else { val = 0.; } break; case MG_GET_XS_PROMPT_NU_FISSION: if (fissionable) { - val = xs[index_temp].prompt_nu_fission[index_pol][index_azi][gin]; + val = xs[cache[tid].t].prompt_nu_fission[cache[tid].p][cache[tid].a][gin]; } else { val = 0.; } @@ -448,11 +454,11 @@ double Mgxs::get_xs(const int xstype, const int gin, int* gout, double* mu, case MG_GET_XS_DELAYED_NU_FISSION: if (fissionable) { if (dg != nullptr) { - val = xs[index_temp].delayed_nu_fission[index_pol][index_azi][gin][*dg]; + val = xs[cache[tid].t].delayed_nu_fission[cache[tid].p][cache[tid].a][gin][*dg]; } else { val = 0.; - for (auto& num : xs[index_temp].delayed_nu_fission[index_pol] - [index_azi][gin]) { + for (auto& num : xs[cache[tid].t].delayed_nu_fission[cache[tid].p] + [cache[tid].a][gin]) { val += num; } } @@ -462,7 +468,7 @@ double Mgxs::get_xs(const int xstype, const int gin, int* gout, double* mu, break; case MG_GET_XS_NU_FISSION: if (fissionable) { - val = xs[index_temp].nu_fission[index_pol][index_azi][gin]; + val = xs[cache[tid].t].nu_fission[cache[tid].p][cache[tid].a][gin]; } else { val = 0.; } @@ -470,11 +476,11 @@ double Mgxs::get_xs(const int xstype, const int gin, int* gout, double* mu, case MG_GET_XS_CHI_PROMPT: if (fissionable) { if (gout != nullptr) { - val = xs[index_temp].chi_prompt[index_pol][index_azi][gin][*gout]; + val = xs[cache[tid].t].chi_prompt[cache[tid].p][cache[tid].a][gin][*gout]; } else { // provide an outgoing group-wise sum val = 0.; - for (auto& num : xs[index_temp].chi_prompt[index_pol][index_azi][gin]) { + for (auto& num : xs[cache[tid].t].chi_prompt[cache[tid].p][cache[tid].a][gin]) { val += num; } } @@ -486,23 +492,23 @@ double Mgxs::get_xs(const int xstype, const int gin, int* gout, double* mu, if (fissionable) { if (gout != nullptr) { if (dg != nullptr) { - val = xs[index_temp].chi_delayed[index_pol][index_azi][gin][*gout][*dg]; + val = xs[cache[tid].t].chi_delayed[cache[tid].p][cache[tid].a][gin][*gout][*dg]; } else { - val = xs[index_temp].chi_delayed[index_pol][index_azi][gin][*gout][0]; + val = xs[cache[tid].t].chi_delayed[cache[tid].p][cache[tid].a][gin][*gout][0]; } } else { if (dg != nullptr) { val = 0.; - for (int i = 0; i < xs[index_temp].chi_delayed[index_pol] - [index_azi][gin].size(); i++) { - val += xs[index_temp].chi_delayed[index_pol][index_azi][gin][i][*dg]; + for (int i = 0; i < xs[cache[tid].t].chi_delayed[cache[tid].p] + [cache[tid].a][gin].size(); i++) { + val += xs[cache[tid].t].chi_delayed[cache[tid].p][cache[tid].a][gin][i][*dg]; } } else { val = 0.; - for (int i = 0; i < xs[index_temp].chi_delayed[index_pol] - [index_azi][gin].size(); i++) { - for (auto& num : xs[index_temp].chi_delayed[index_pol] - [index_azi][gin][i]) { + for (int i = 0; i < xs[cache[tid].t].chi_delayed[cache[tid].p] + [cache[tid].a][gin].size(); i++) { + for (auto& num : xs[cache[tid].t].chi_delayed[cache[tid].p] + [cache[tid].a][gin][i]) { val += num; } } @@ -519,14 +525,15 @@ double Mgxs::get_xs(const int xstype, const int gin, int* gout, double* mu, } -void Mgxs::sample_fission_energy(const int gin, int& dg, int& gout) +void Mgxs::sample_fission_energy(const int tid, const int gin, int& dg, + int& gout) { // This method assumes that the temperature and angle indices are set - double nu_fission = xs[index_temp].nu_fission[index_pol][index_azi][gin]; + double nu_fission = xs[cache[tid].t].nu_fission[cache[tid].p][cache[tid].a][gin]; // Find the probability of having a prompt neutron double prob_prompt = - xs[index_temp].prompt_nu_fission[index_pol][index_azi][gin]; + xs[cache[tid].t].prompt_nu_fission[cache[tid].p][cache[tid].a][gin]; // sample random numbers double xi_pd = prn() * nu_fission; @@ -542,10 +549,10 @@ void Mgxs::sample_fission_energy(const int gin, int& dg, int& gout) // sample the outgoing energy group gout = 0; double prob_gout = - xs[index_temp].chi_prompt[index_pol][index_azi][gin][gout]; + xs[cache[tid].t].chi_prompt[cache[tid].p][cache[tid].a][gin][gout]; while (prob_gout < xi_gout) { gout++; - prob_gout += xs[index_temp].chi_prompt[index_pol][index_azi][gin][gout]; + prob_gout += xs[cache[tid].t].chi_prompt[cache[tid].p][cache[tid].a][gin][gout]; } } else { @@ -556,7 +563,7 @@ void Mgxs::sample_fission_energy(const int gin, int& dg, int& gout) while (xi_pd >= prob_prompt) { dg++; prob_prompt += - xs[index_temp].delayed_nu_fission[index_pol][index_azi][gin][dg]; + xs[cache[tid].t].delayed_nu_fission[cache[tid].p][cache[tid].a][gin][dg]; } // adjust dg in case of round-off error @@ -565,35 +572,36 @@ void Mgxs::sample_fission_energy(const int gin, int& dg, int& gout) // sample the outgoing energy group gout = 0; double prob_gout = - xs[index_temp].chi_delayed[index_pol][index_azi][gin][gout][dg]; + xs[cache[tid].t].chi_delayed[cache[tid].p][cache[tid].a][gin][gout][dg]; while (prob_gout < xi_gout) { gout++; prob_gout += - xs[index_temp].chi_delayed[index_pol][index_azi][gin][gout][dg]; + xs[cache[tid].t].chi_delayed[cache[tid].p][cache[tid].a][gin][gout][dg]; } } } -void Mgxs::sample_scatter(const int gin, int& gout, double& mu, double& wgt) +void Mgxs::sample_scatter(const int tid, const int gin, int& gout, double& mu, + double& wgt) { // This method assumes that the temperature and angle indices are set // Sample the data - xs[index_temp].scatter[index_pol][index_azi]->sample(gin, gout, mu, wgt); + xs[cache[tid].t].scatter[cache[tid].p][cache[tid].a]->sample(gin, gout, mu, wgt); } -void Mgxs::calculate_xs(const int gin, const double sqrtkT, const double uvw[3], - double& total_xs, double& abs_xs, double& nu_fiss_xs) +void Mgxs::calculate_xs(const int tid, const int gin, const double sqrtkT, + const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs) { // Set our indices - set_temperature_index(sqrtkT); - set_angle_index(uvw); - total_xs = xs[index_temp].total[index_pol][index_azi][gin]; - abs_xs = xs[index_temp].absorption[index_pol][index_azi][gin]; + set_temperature_index(tid, sqrtkT); + set_angle_index(tid, uvw); + total_xs = xs[cache[tid].t].total[cache[tid].p][cache[tid].a][gin]; + abs_xs = xs[cache[tid].t].absorption[cache[tid].p][cache[tid].a][gin]; if (fissionable) { - nu_fiss_xs = xs[index_temp].nu_fission[index_pol][index_azi][gin]; + nu_fiss_xs = xs[cache[tid].t].nu_fission[cache[tid].p][cache[tid].a][gin]; } else { nu_fiss_xs = 0.; } @@ -617,10 +625,10 @@ bool Mgxs::equiv(const Mgxs& that) } -void Mgxs::set_temperature_index(const double sqrtkT) +void Mgxs::set_temperature_index(const int tid, const double sqrtkT) { // See if we need to find the new index - if (sqrtkT != last_sqrtkT) { + if (sqrtkT != cache[tid].sqrtkT) { double kT = sqrtkT * sqrtkT; // initialize vector for storage of the differences @@ -628,34 +636,34 @@ void Mgxs::set_temperature_index(const double sqrtkT) // Find the minimum difference of kT and kTs temp_diff = std::abs(temp_diff - kT); - index_temp = std::min_element(std::begin(temp_diff), std::end(temp_diff)) - + cache[tid].t = std::min_element(std::begin(temp_diff), std::end(temp_diff)) - std::begin(temp_diff); // store this temperature as the last one used - last_sqrtkT = sqrtkT; + cache[tid].sqrtkT = sqrtkT; } } -void Mgxs::set_angle_index(const double uvw[3]) +void Mgxs::set_angle_index(const int tid, const double uvw[3]) { // See if we need to find the new index - if ((uvw[0] != last_uvw[0]) || (uvw[1] != last_uvw[1]) || - (uvw[2] != last_uvw[2])) { + if ((uvw[0] != cache[tid].uvw[0]) || (uvw[1] != cache[tid].uvw[1]) || + (uvw[2] != cache[tid].uvw[2])) { // convert uvw to polar and azimuthal angles double my_pol = std::acos(uvw[2]); double my_azi = std::atan2(uvw[1], uvw[0]); // Find the location, assuming equal-bin angles double delta_angle = PI / n_pol; - index_pol = std::floor(my_pol / delta_angle); + cache[tid].p = std::floor(my_pol / delta_angle); delta_angle = 2. * PI / n_azi; - index_azi = std::floor((my_azi + PI) / delta_angle); + cache[tid].a = std::floor((my_azi + PI) / delta_angle); // store this direction as the last one used - last_uvw[0] = uvw[0]; - last_uvw[1] = uvw[1]; - last_uvw[2] = uvw[2]; + cache[tid].uvw[0] = uvw[0]; + cache[tid].uvw[1] = uvw[1]; + cache[tid].uvw[2] = uvw[2]; } } diff --git a/src/mgxs.h b/src/mgxs.h index 2fc3e2bec2..1c98417d69 100644 --- a/src/mgxs.h +++ b/src/mgxs.h @@ -23,6 +23,18 @@ namespace openmc { +//============================================================================== +// Cache contains the cached data for an MGXS object +//============================================================================== + +struct CacheData { + double sqrtkT; // last temperature corresponding to t + int t; // temperature index + int p; // polar angle index + int a; // azimuthal angle index + double uvw[3]; // last angle that corresponds to p and a +}; + //============================================================================== // MGXS contains the mgxs data for a nuclide/material //============================================================================== @@ -33,7 +45,6 @@ class Mgxs { int scatter_format; // flag for if this is legendre, histogram, or tabular int num_delayed_groups; // number of delayed neutron groups int num_groups; // number of energy groups - double last_sqrtkT; // cache of the temperature corresponding to index_temp std::vector xs; // Cross section data int n_pol; int n_azi; @@ -42,7 +53,7 @@ class Mgxs { void _metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, const int in_num_delayed_groups, double_1dvec& temperature, int& method, const double tolerance, int_1dvec& temps_to_read, - int& order_dim, bool& is_isotropic); + int& order_dim, bool& is_isotropic, const int n_threads); bool equiv(const Mgxs& that); public: @@ -50,32 +61,31 @@ class Mgxs { double awr; // atomic weight ratio bool fissionable; // Is this fissionable // TODO: The following attributes be private when Fortran is fully replaced - int index_pol; // cache for the angle indices - int index_azi; - double last_uvw[3]; // cache of the angle corresponding to the above indices - int index_temp; // cache of temperature index + std::vector cache; // index and data cache void init(const std::string& in_name, const double in_awr, const double_1dvec& in_kTs, const bool in_fissionable, const int in_scatter_format, const int in_num_groups, const int in_num_delayed_groups, const double_1dvec& in_polar, - const double_1dvec& in_azimuthal); + const double_1dvec& in_azimuthal, const int n_threads); void build_macro(const std::string& in_name, double_1dvec& mat_kTs, std::vector& micros, double_1dvec& atom_densities, - int& method, double tolerance); + int& method, const double tolerance, const int n_threads); void combine(std::vector& micros, double_1dvec& scalars, int_1dvec& micro_ts, int this_t); - void from_hdf5(hid_t xs_id, int energy_groups, int delayed_groups, - double_1dvec& temperature, int& method, double tolerance, - int max_order, bool legendre_to_tabular, - int legendre_to_tabular_points); - double get_xs(const int xstype, const int gin, int* gout, double* mu, - int* dg); - void sample_fission_energy(const int gin, int& dg, int& gout); - void sample_scatter(const int gin, int& gout, double& mu, double& wgt); - void calculate_xs(const int gin, const double sqrtkT, const double uvw[3], - double& total_xs, double& abs_xs, double& nu_fiss_xs); - void set_temperature_index(const double sqrtkT); - void set_angle_index(const double uvw[3]); + void from_hdf5(hid_t xs_id, const int energy_groups, + const int delayed_groups, double_1dvec& temperature, int& method, + const double tolerance, const int max_order, + const bool legendre_to_tabular, const int legendre_to_tabular_points, + const int n_threads); + double get_xs(const int tid, const int xstype, const int gin, int* gout, + double* mu, int* dg); + void sample_fission_energy(const int tid, const int gin, int& dg, int& gout); + void sample_scatter(const int tid, const int gin, int& gout, double& mu, + double& wgt); + void calculate_xs(const int tid, const int gin, const double sqrtkT, + const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs); + void set_temperature_index(const int tid, const double sqrtkT); + void set_angle_index(const int tid, const double uvw[3]); }; } // namespace openmc diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index 8c48d5c98e..ef416125e7 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -2,6 +2,10 @@ module mgxs_data use, intrinsic :: ISO_C_BINDING +#ifdef _OPENMP + use omp_lib +#endif + use constants use algorithm, only: find use dict_header, only: DictCharInt @@ -36,6 +40,13 @@ contains type(VectorReal), allocatable, target :: temps(:) character(MAX_WORD_LEN) :: word integer, allocatable :: array(:) + integer(C_INT) :: n_threads + +#ifdef _OPENMP + n_threads = OMP_GET_MAX_THREADS() +#else + n_threads = 1 +#endif ! Check if MGXS Library exists inquire(FILE=path_cross_sections, EXIST=file_exists) @@ -84,7 +95,8 @@ contains num_energy_groups, num_delayed_groups, & temps(i_nuclide) % size(), temps(i_nuclide) % data, & temperature_method, temperature_tolerance, max_order, & - logical(legendre_to_tabular, C_BOOL), legendre_to_tabular_points) + logical(legendre_to_tabular, C_BOOL), & + legendre_to_tabular_points, n_threads) call already_read % add(name) end if @@ -110,6 +122,13 @@ contains type(Material), pointer :: mat ! current material type(VectorReal), allocatable :: kTs(:) character(MAX_WORD_LEN) :: name ! name of material + integer(C_INT) :: n_threads + +#ifdef _OPENMP + n_threads = OMP_GET_MAX_THREADS() +#else + n_threads = 1 +#endif ! Get temperatures to read for each material call get_mat_kTs(kTs) @@ -130,7 +149,7 @@ contains if (allocated(kTs(i_mat) % data)) then call create_macro_xs_c(name, mat % n_nuclides, mat % nuclide, & kTs(i_mat) % size(), kTs(i_mat) % data, mat % atom_density, & - temperature_method, temperature_tolerance) + temperature_method, temperature_tolerance, n_threads) end if end do diff --git a/src/mgxs_interface.F90 b/src/mgxs_interface.F90 index 7404af686d..34b0fb6112 100644 --- a/src/mgxs_interface.F90 +++ b/src/mgxs_interface.F90 @@ -10,7 +10,7 @@ module mgxs_interface subroutine add_mgxs_c(file_id, name, energy_groups, delayed_groups, & n_temps, temps, method, tolerance, max_order, legendre_to_tabular, & - legendre_to_tabular_points) bind(C) + legendre_to_tabular_points, n_threads) bind(C) use ISO_C_BINDING import HID_T implicit none @@ -25,6 +25,7 @@ module mgxs_interface integer(C_INT), value, intent(in) :: max_order logical(C_BOOL),value, intent(in) :: legendre_to_tabular integer(C_INT), value, intent(in) :: legendre_to_tabular_points + integer(C_INT), value, intent(in) :: n_threads end subroutine add_mgxs_c function query_fissionable_c(n_nuclides, i_nuclides) result(result) bind(C) @@ -36,7 +37,7 @@ module mgxs_interface end function query_fissionable_c subroutine create_macro_xs_c(name, n_nuclides, i_nuclides, n_temps, temps, & - atom_densities, method, tolerance) bind(C) + atom_densities, method, tolerance, n_threads) bind(C) use ISO_C_BINDING implicit none character(kind=C_CHAR),intent(in) :: name(*) @@ -47,13 +48,15 @@ module mgxs_interface real(C_DOUBLE), intent(in) :: atom_densities(1:n_nuclides) integer(C_INT), intent(inout) :: method real(C_DOUBLE), value, intent(in) :: tolerance + integer(C_INT), value, intent(in) :: n_threads end subroutine create_macro_xs_c - subroutine calculate_xs_c(i_mat, gin, sqrtkT, uvw, total_xs, abs_xs, & + subroutine calculate_xs_c(i_mat, tid, gin, sqrtkT, uvw, total_xs, abs_xs, & nu_fiss_xs) bind(C) use ISO_C_BINDING implicit none integer(C_INT), value, intent(in) :: i_mat + integer(C_INT), value, intent(in) :: tid integer(C_INT), value, intent(in) :: gin real(C_DOUBLE), value, intent(in) :: sqrtkT real(C_DOUBLE), intent(in) :: uvw(1:3) @@ -62,10 +65,11 @@ module mgxs_interface real(C_DOUBLE), intent(inout) :: nu_fiss_xs end subroutine calculate_xs_c - subroutine sample_scatter_c(i_mat, gin, gout, mu, wgt, uvw) bind(C) + subroutine sample_scatter_c(i_mat, tid, gin, gout, mu, wgt, uvw) bind(C) use ISO_C_BINDING implicit none integer(C_INT), value, intent(in) :: i_mat + integer(C_INT), value, intent(in) :: tid integer(C_INT), value, intent(in) :: gin integer(C_INT), intent(inout) :: gout real(C_DOUBLE), intent(inout) :: mu @@ -73,10 +77,11 @@ module mgxs_interface real(C_DOUBLE), intent(inout) :: uvw(1:3) end subroutine sample_scatter_c - subroutine sample_fission_energy_c(i_mat, gin, dg, gout) bind(C) + subroutine sample_fission_energy_c(i_mat, tid, gin, dg, gout) bind(C) use ISO_C_BINDING implicit none integer(C_INT), value, intent(in) :: i_mat + integer(C_INT), value, intent(in) :: tid integer(C_INT), value, intent(in) :: gin integer(C_INT), intent(inout) :: dg integer(C_INT), intent(inout) :: gout @@ -97,11 +102,12 @@ module mgxs_interface real(C_DOUBLE) :: awr end function get_awr_c - function get_nuclide_xs_c(index, xstype, gin, gout, mu, dg) result(val) & + function get_nuclide_xs_c(index, tid, xstype, gin, gout, mu, dg) result(val) & bind(C) use ISO_C_BINDING implicit none integer(C_INT), value, intent(in) :: index + integer(C_INT), value, intent(in) :: tid integer(C_INT), value, intent(in) :: xstype integer(C_INT), value, intent(in) :: gin integer(C_INT), optional, intent(in) :: gout @@ -110,11 +116,12 @@ module mgxs_interface real(C_DOUBLE) :: val end function get_nuclide_xs_c - function get_macro_xs_c(index, xstype, gin, gout, mu, dg) result(val) & + function get_macro_xs_c(index, tid, xstype, gin, gout, mu, dg) result(val) & bind(C) use ISO_C_BINDING implicit none integer(C_INT), value, intent(in) :: index + integer(C_INT), value, intent(in) :: tid integer(C_INT), value, intent(in) :: xstype integer(C_INT), value, intent(in) :: gin integer(C_INT), optional, intent(in) :: gout @@ -123,63 +130,29 @@ module mgxs_interface real(C_DOUBLE) :: val end function get_macro_xs_c - subroutine set_nuclide_angle_index_c(index, uvw, last_pol, last_azi, & - last_uvw) bind(C) + subroutine set_nuclide_angle_index_c(index, tid, uvw) bind(C) use ISO_C_BINDING implicit none integer(C_INT), value, intent(in) :: index + integer(C_INT), value, intent(in) :: tid real(C_DOUBLE), intent(in) :: uvw(1:3) - integer(C_INT), intent(inout) :: last_pol - integer(C_INT), intent(inout) :: last_azi - real(C_DOUBLE), intent(inout) :: last_uvw(1:3) end subroutine set_nuclide_angle_index_c - subroutine reset_nuclide_angle_index_c(index, last_pol, last_azi, & - last_uvw) bind(C) - use ISO_C_BINDING - implicit none - integer(C_INT), value, intent(in) :: index - integer(C_INT), value, intent(in) :: last_pol - integer(C_INT), value, intent(in) :: last_azi - real(C_DOUBLE), intent(in) :: last_uvw(1:3) - end subroutine reset_nuclide_angle_index_c - - subroutine set_macro_angle_index_c(index, uvw, last_pol, last_azi, & - last_uvw) bind(C) + subroutine set_macro_angle_index_c(index, tid, uvw) bind(C) use ISO_C_BINDING implicit none integer(C_INT), value, intent(in) :: index + integer(C_INT), value, intent(in) :: tid real(C_DOUBLE), intent(in) :: uvw(1:3) - integer(C_INT), intent(inout) :: last_pol - integer(C_INT), intent(inout) :: last_azi - real(C_DOUBLE), intent(inout) :: last_uvw(1:3) end subroutine set_macro_angle_index_c - subroutine reset_macro_angle_index_c(index, last_pol, last_azi, & - last_uvw) bind(C) - use ISO_C_BINDING - implicit none - integer(C_INT), value, intent(in) :: index - integer(C_INT), value, intent(in) :: last_pol - integer(C_INT), value, intent(in) :: last_azi - real(C_DOUBLE), intent(in) :: last_uvw(1:3) - end subroutine reset_macro_angle_index_c - - function set_nuclide_temperature_index_c(index, sqrtkT) result(last_temp) & - bind(C) + subroutine set_nuclide_temperature_index_c(index, tid, sqrtkT) bind(C) use ISO_C_BINDING implicit none integer(C_INT), value, intent(in) :: index + integer(C_INT), value, intent(in) :: tid real(C_DOUBLE), value, intent(in) :: sqrtkT - integer(C_INT) :: last_temp - end function set_nuclide_temperature_index_c - - subroutine reset_nuclide_temperature_index_c(index, last_temp) bind(C) - use ISO_C_BINDING - implicit none - integer(C_INT), value, intent(in) :: index - integer(C_INT), value, intent(in) :: last_temp - end subroutine reset_nuclide_temperature_index_c + end subroutine set_nuclide_temperature_index_c end interface diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 60afc28487..6c9dc9f42e 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -6,10 +6,11 @@ namespace openmc { // Mgxs data loading interface methods //============================================================================== -void add_mgxs_c(hid_t file_id, char* name, int energy_groups, - int delayed_groups, int n_temps, double temps[], int& method, - double tolerance, int max_order, bool legendre_to_tabular, - int legendre_to_tabular_points) +void add_mgxs_c(hid_t file_id, char* name, const int energy_groups, + const int delayed_groups, const int n_temps, double temps[], int& method, + const double tolerance, const int max_order, + const bool legendre_to_tabular, const int legendre_to_tabular_points, + const int n_threads) { //!! mgxs_data.F90 will be modified to just create the list of names //!! in the order needed @@ -32,7 +33,7 @@ void add_mgxs_c(hid_t file_id, char* name, int energy_groups, Mgxs mg; mg.from_hdf5(xs_grp, energy_groups, delayed_groups, temperature, method, tolerance, max_order, legendre_to_tabular, - legendre_to_tabular_points); + legendre_to_tabular_points, n_threads); nuclides_MG.push_back(mg); } @@ -50,7 +51,8 @@ bool query_fissionable_c(const int n_nuclides, const int i_nuclides[]) void create_macro_xs_c(char* mat_name, const int n_nuclides, const int i_nuclides[], const int n_temps, const double temps[], - const double atom_densities[], int& method, const double tolerance) + const double atom_densities[], int& method, const double tolerance, + const int n_threads) { Mgxs macro; if (n_temps > 0) { @@ -70,7 +72,7 @@ void create_macro_xs_c(char* mat_name, const int n_nuclides, } macro.build_macro(mat_name, temperature, mgxs_ptr, atom_densities_vec, - method, tolerance); + method, tolerance, n_threads); } macro_xs.push_back(macro); } @@ -79,19 +81,20 @@ void create_macro_xs_c(char* mat_name, const int n_nuclides, // Mgxs tracking/transport/tallying interface methods //============================================================================== -void calculate_xs_c(const int i_mat, const int gin, const double sqrtkT, - const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs) +void calculate_xs_c(const int i_mat, const int tid, const int gin, + const double sqrtkT, const double uvw[3], double& total_xs, double& abs_xs, + double& nu_fiss_xs) { - macro_xs[i_mat - 1].calculate_xs(gin - 1, sqrtkT, uvw, total_xs, abs_xs, + macro_xs[i_mat - 1].calculate_xs(tid, gin - 1, sqrtkT, uvw, total_xs, abs_xs, nu_fiss_xs); } -void sample_scatter_c(const int i_mat, const int gin, int& gout, double& mu, - double& wgt, double uvw[3]) +void sample_scatter_c(const int i_mat, const int tid, const int gin, int& gout, + double& mu, double& wgt, double uvw[3]) { int gout_c = gout - 1; - macro_xs[i_mat - 1].sample_scatter(gin - 1, gout_c, mu, wgt); + macro_xs[i_mat - 1].sample_scatter(tid, gin - 1, gout_c, mu, wgt); // adjust return value for fortran indexing gout = gout_c + 1; @@ -101,11 +104,12 @@ void sample_scatter_c(const int i_mat, const int gin, int& gout, double& mu, } -void sample_fission_energy_c(const int i_mat, const int gin, int& dg, int& gout) +void sample_fission_energy_c(const int i_mat, const int tid, const int gin, + int& dg, int& gout) { int dg_c = 0; int gout_c = 0; - macro_xs[i_mat - 1].sample_fission_energy(gin - 1, dg_c, gout_c); + macro_xs[i_mat - 1].sample_fission_energy(tid, gin - 1, dg_c, gout_c); // adjust return values for fortran indexing dg = dg_c + 1; @@ -113,6 +117,82 @@ void sample_fission_energy_c(const int i_mat, const int gin, int& dg, int& gout) } +double get_nuclide_xs_c(const int index, const int tid, const int xstype, + const int gin, int* gout, double* mu, int* dg) +{ + int gout_c; + int* gout_c_p; + int dg_c; + int* dg_c_p; + if (gout != nullptr) { + gout_c = *gout - 1; + gout_c_p = &gout_c; + } else { + gout_c_p = gout; + } + if (dg != nullptr) { + dg_c = *dg - 1; + dg_c_p = &dg_c; + } else { + dg_c_p = dg; + } + return nuclides_MG[index - 1].get_xs(tid, xstype, gin - 1, gout_c_p, mu, + dg_c_p); +} + + +double get_macro_xs_c(const int index, const int tid, const int xstype, + const int gin, int* gout, double* mu, int* dg) +{ + int gout_c; + int* gout_c_p; + int dg_c; + int* dg_c_p; + if (gout != nullptr) { + gout_c = *gout - 1; + gout_c_p = &gout_c; + } else { + gout_c_p = gout; + } + if (dg != nullptr) { + dg_c = *dg - 1; + dg_c_p = &dg_c; + } else { + dg_c_p = dg; + } + return macro_xs[index - 1].get_xs(tid, xstype, gin - 1, gout_c_p, mu, + dg_c_p); +} + + +void set_nuclide_angle_index_c(const int index, const int tid, + const double uvw[3]) +{ + // Update the values + nuclides_MG[index - 1].set_angle_index(tid, uvw); +} + + +void set_macro_angle_index_c(const int index, const int tid, + const double uvw[3]) +{ + // Update the values + macro_xs[index - 1].set_angle_index(tid, uvw); +} + + +void set_nuclide_temperature_index_c(const int index, const int tid, + const double sqrtkT) +{ + // Update the values + nuclides_MG[index - 1].set_temperature_index(tid, sqrtkT); +} + + +//============================================================================== +// Mgxs general methods +//============================================================================== + void get_name_c(const int index, int name_len, char* name) { // First blank out our input string @@ -133,115 +213,4 @@ double get_awr_c(const int index) return nuclides_MG[index - 1].awr; } - -double get_nuclide_xs_c(const int index, const int xstype, const int gin, - int* gout, double* mu, int* dg) -{ - int gout_c; - int* gout_c_p; - int dg_c; - int* dg_c_p; - if (gout != nullptr) { - gout_c = *gout - 1; - gout_c_p = &gout_c; - } else { - gout_c_p = gout; - } - if (dg != nullptr) { - dg_c = *dg - 1; - dg_c_p = &dg_c; - } else { - dg_c_p = dg; - } - return nuclides_MG[index - 1].get_xs(xstype, gin - 1, gout_c_p, mu, dg_c_p); -} - - -double get_macro_xs_c(const int index, const int xstype, const int gin, - int* gout, double* mu, int* dg) -{ - int gout_c; - int* gout_c_p; - int dg_c; - int* dg_c_p; - if (gout != nullptr) { - gout_c = *gout - 1; - gout_c_p = &gout_c; - } else { - gout_c_p = gout; - } - if (dg != nullptr) { - dg_c = *dg - 1; - dg_c_p = &dg_c; - } else { - dg_c_p = dg; - } - return macro_xs[index - 1].get_xs(xstype, gin - 1, gout_c_p, mu, dg_c_p); -} - - -void set_nuclide_angle_index_c(const int index, const double uvw[3], - int& last_pol, int& last_azi, double last_uvw[3]) -{ - // Store the old - last_pol = nuclides_MG[index - 1].index_pol; - last_azi = nuclides_MG[index - 1].index_azi; - last_uvw[0] = nuclides_MG[index - 1].last_uvw[0]; - last_uvw[1] = nuclides_MG[index - 1].last_uvw[1]; - last_uvw[2] = nuclides_MG[index - 1].last_uvw[2]; - - // Update the values - nuclides_MG[index - 1].set_angle_index(uvw); -} - - -void reset_nuclide_angle_index_c(const int index, const int last_pol, - const int last_azi, const double last_uvw[3]) -{ - nuclides_MG[index - 1].index_pol = last_pol; - nuclides_MG[index - 1].index_azi = last_azi; - nuclides_MG[index - 1].last_uvw[0] = last_uvw[0]; - nuclides_MG[index - 1].last_uvw[1] = last_uvw[1]; - nuclides_MG[index - 1].last_uvw[2] = last_uvw[2]; -} - - -void set_macro_angle_index_c(const int index, const double uvw[3], - int& last_pol, int& last_azi, double last_uvw[3]) -{ - // Store the old - last_pol = macro_xs[index - 1].index_pol; - last_azi = macro_xs[index - 1].index_azi; - last_uvw[0] = macro_xs[index - 1].last_uvw[0]; - last_uvw[1] = macro_xs[index - 1].last_uvw[1]; - last_uvw[2] = macro_xs[index - 1].last_uvw[2]; - - // Update the values - macro_xs[index - 1].set_angle_index(uvw); -} - - -void reset_macro_angle_index_c(const int index, const int last_pol, - const int last_azi, const double last_uvw[3]) -{ - macro_xs[index - 1].index_pol = last_pol; - macro_xs[index - 1].index_azi = last_azi; - macro_xs[index - 1].last_uvw[0] = last_uvw[0]; - macro_xs[index - 1].last_uvw[1] = last_uvw[1]; - macro_xs[index - 1].last_uvw[2] = last_uvw[2]; -} - - -int set_nuclide_temperature_index_c(const int index, const double sqrtkT) -{ - int old = nuclides_MG[index - 1].index_temp; - nuclides_MG[index - 1].set_temperature_index(sqrtkT); - return old; -} - -void reset_nuclide_temperature_index_c(const int index, const int last_temp) -{ - nuclides_MG[index - 1].index_temp = last_temp; -} - } // namespace openmc \ No newline at end of file diff --git a/src/mgxs_interface.h b/src/mgxs_interface.h index 197ecb0bf9..4e10682669 100644 --- a/src/mgxs_interface.h +++ b/src/mgxs_interface.h @@ -13,54 +13,47 @@ extern std::vector nuclides_MG; extern std::vector macro_xs; -extern "C" void add_mgxs_c(hid_t file_id, char* name, int energy_groups, - int delayed_groups, int n_temps, double temps[], int& method, - double tolerance, int max_order, bool legendre_to_tabular, - int legendre_to_tabular_points); +extern "C" void add_mgxs_c(hid_t file_id, char* name, const int energy_groups, + const int delayed_groups, const int n_temps, double temps[], int& method, + const double tolerance, const int max_order, + const bool legendre_to_tabular, const int legendre_to_tabular_points, + const int n_threads); extern "C" bool query_fissionable_c(const int n_nuclides, const int i_nuclides[]); extern "C" void create_macro_xs_c(char* mat_name, const int n_nuclides, const int i_nuclides[], const int n_temps, const double temps[], - const double atom_densities[], int& method, const double tolerance); + const double atom_densities[], int& method, const double tolerance, + const int n_threads); -extern "C" void calculate_xs_c(const int i_mat, const int gin, +extern "C" void calculate_xs_c(const int i_mat, const int tid, const int gin, const double sqrtkT, const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs); -extern "C" void sample_scatter_c(const int i_mat, const int gin, int& gout, - double& mu, double& wgt, double uvw[3]); +extern "C" void sample_scatter_c(const int i_mat, const int tid, const int gin, + int& gout, double& mu, double& wgt, double uvw[3]); -extern "C" void sample_fission_energy_c(const int i_mat, const int gin, - int& dg, int& gout); +extern "C" void sample_fission_energy_c(const int i_mat, const int tid, + const int gin, int& dg, int& gout); extern "C" void get_name_c(const int index, int name_len, char* name); extern "C" double get_awr_c(const int index); -extern "C" double get_nuclide_xs_c(const int index, const int xstype, - const int gin, int* gout, double* mu, int* dg); +extern "C" double get_nuclide_xs_c(const int index, const int tid, + const int xstype, const int gin, int* gout, double* mu, int* dg); -extern "C" double get_macro_xs_c(const int index, const int xstype, - const int gin, int* gout, double* mu, int* dg); +extern "C" double get_macro_xs_c(const int index, const int tid, + const int xstype, const int gin, int* gout, double* mu, int* dg); -extern "C" void set_nuclide_angle_index_c(const int index, const double uvw[3], - int& last_pol, int& last_azi, double last_uvw[3]); +extern "C" void set_nuclide_angle_index_c(const int index, const int tid, + const double uvw[3]); -extern "C" void reset_nuclide_angle_index_c(const int index, const int last_pol, - const int last_azi, const double last_uvw[3]); +extern "C" void set_macro_angle_index_c(const int index, const int tid, + const double uvw[3]); -extern "C" void set_macro_angle_index_c(const int index, const double uvw[3], - int& last_pol, int& last_azi, double last_uvw[3]); - -extern "C" void reset_macro_angle_index_c(const int index, const int last_pol, - const int last_azi, const double last_uvw[3]); - -extern "C" int set_nuclide_temperature_index_c(const int index, +extern "C" void set_nuclide_temperature_index_c(const int index, const int tid, const double sqrtkT); -extern "C" void reset_nuclide_temperature_index_c(const int index, - const int last_temp); - } // namespace openmc #endif // MGXS_INTERFACE_H \ No newline at end of file diff --git a/src/physics_mg.F90 b/src/physics_mg.F90 index 797514e25f..d04d4cb85d 100644 --- a/src/physics_mg.F90 +++ b/src/physics_mg.F90 @@ -2,6 +2,10 @@ module physics_mg ! This module contains the multi-group specific physics routines so as to not ! hinder performance of the CE versions with multiple if-thens. +#ifdef _OPENMP + use omp_lib +#endif + use bank_header use constants use error, only: fatal_error, warning, write_message @@ -141,9 +145,15 @@ contains subroutine scatter(p) type(Particle), intent(inout) :: p + integer(C_INT) :: tid +#ifdef _OPENMP + tid = OMP_GET_THREAD_NUM() +#else + tid = 0 +#endif - call sample_scatter_c(p % material, p % last_g, p % g, p % mu, p % wgt, & - p % coord(1) % uvw) + call sample_scatter_c(p % material, tid, p % last_g, p % g, p % mu, & + p % wgt, p % coord(1) % uvw) ! Update energy value for downstream compatability (in tallying) p % E = energy_bin_avg(p % g) @@ -173,6 +183,12 @@ contains real(8) :: mu ! fission neutron angular cosine real(8) :: phi ! fission neutron azimuthal angle real(8) :: weight ! weight adjustment for ufs method + integer(C_INT) :: tid +#ifdef _OPENMP + tid = OMP_GET_THREAD_NUM() +#else + tid = 0 +#endif ! TODO: Heat generation from fission @@ -252,7 +268,7 @@ contains ! Sample secondary energy distribution for fission reaction and set energy ! in fission bank - call sample_fission_energy_c(p % material, p % g, dg, gout) + call sample_fission_energy_c(p % material, tid, p % g, dg, gout) bank_array(i) % E = real(gout, 8) bank_array(i) % delayed_group = dg diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index 4c24717b43..f6839081d3 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -2,6 +2,10 @@ module tally use, intrinsic :: ISO_C_BINDING +#ifdef _OPENMP + use omp_lib +#endif + use algorithm, only: binary_search use constants use dict_header, only: EMPTY @@ -1229,14 +1233,12 @@ contains real(8) :: p_uvw(3) ! Particle's current uvw integer :: p_g ! Particle group to use for getting info ! to tally with. - ! Storage of the indices the Mgxs object arrived with for resetting later - integer(C_INT) :: last_nuc_azi - integer(C_INT) :: last_nuc_pol - integer(C_INT) :: last_mat_azi - integer(C_INT) :: last_mat_pol - integer(C_INT) :: last_nuc_temp - real(C_DOUBLE) :: last_mat_uvw(3) - real(C_DOUBLE) :: last_nuc_uvw(3) + integer(C_INT) :: tid +#ifdef _OPENMP + tid = OMP_GET_THREAD_NUM() +#else + tid = 0 +#endif ! Set the direction and group to use with get_xs if (t % estimator == ESTIMATOR_ANALOG .or. & @@ -1274,15 +1276,13 @@ contains ! To significantly reduce de-referencing, point matxs to the ! macroscopic Mgxs for the material of interest - call set_macro_angle_index_c(p % material, p_uvw, last_mat_pol, & - last_mat_azi, last_mat_uvw) + call set_macro_angle_index_c(p % material, tid, p_uvw) ! Do same for nucxs, point it to the microscopic nuclide data of interest if (i_nuclide > 0) then ! And since we haven't calculated this temperature index yet, do so now - last_nuc_temp = set_nuclide_temperature_index_c(i_nuclide, p % sqrtkT) - call set_nuclide_angle_index_c(i_nuclide, p_uvw, last_nuc_pol, & - last_nuc_azi, last_nuc_uvw) + call set_nuclide_temperature_index_c(i_nuclide, tid, p % sqrtkT) + call set_nuclide_angle_index_c(i_nuclide, tid, p_uvw) end if i = 0 @@ -1336,14 +1336,14 @@ contains end if if (i_nuclide > 0) then - score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_TOTAL, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_TOTAL, p_g) * flux + score = score * flux * atom_density * & + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_TOTAL, p_g) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_TOTAL, p_g) end if else if (i_nuclide > 0) then - score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_TOTAL, p_g) * & + score = get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_TOTAL, p_g) * & atom_density * flux else score = material_xs % total * flux @@ -1366,22 +1366,22 @@ contains end if if (i_nuclide > 0) then - score = score * get_nuclide_xs_c(i_nuclide, & + score = score * flux * get_nuclide_xs_c(i_nuclide, tid, & MG_GET_XS_INVERSE_VELOCITY, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) * flux + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) else - score = score * get_macro_xs_c(p % material, & + score = score * flux * get_macro_xs_c(p % material, tid, & MG_GET_XS_INVERSE_VELOCITY, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) * flux + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) end if else if (i_nuclide > 0) then - score = flux * get_nuclide_xs_c(i_nuclide, & + score = flux * get_nuclide_xs_c(i_nuclide, tid, & MG_GET_XS_INVERSE_VELOCITY, p_g) else - score = flux * get_macro_xs_c(p % material, & + score = flux * get_macro_xs_c(p % material, tid, & MG_GET_XS_INVERSE_VELOCITY, p_g) end if end if @@ -1404,22 +1404,22 @@ contains ! adjust the score by the actual probability for that nuclide. if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_SCATTER_FMU_MULT, & + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_SCATTER_FMU_MULT, & p % last_g, p % g, MU=p % mu) / & - get_macro_xs_c(p % material, MG_GET_XS_SCATTER_FMU_MULT, & + get_macro_xs_c(p % material, tid, MG_GET_XS_SCATTER_FMU_MULT, & p % last_g, p % g, MU=p % mu) end if else if (i_nuclide > 0) then score = atom_density * flux * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_SCATTER_MULT, & + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_SCATTER_MULT, & p_g, MU=p % mu) else ! Get the scattering x/s and take away ! the multiplication baked in to sigS score = flux * & - get_macro_xs_c(p % material, MG_GET_XS_SCATTER_MULT, & + get_macro_xs_c(p % material, tid, MG_GET_XS_SCATTER_MULT, & p_g, MU=p % mu) end if end if @@ -1442,20 +1442,20 @@ contains ! adjust the score by the actual probability for that nuclide. if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_SCATTER_FMU, & + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_SCATTER_FMU, & p % last_g, p % g, MU=p % mu) / & - get_macro_xs_c(p % material, MG_GET_XS_SCATTER_FMU, & + get_macro_xs_c(p % material, tid, MG_GET_XS_SCATTER_FMU, & p % last_g, p % g, MU=p % mu) end if else if (i_nuclide > 0) then score = atom_density * flux * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_SCATTER, p_g) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_SCATTER, p_g) else ! Get the scattering x/s, which includes multiplication score = flux * & - get_macro_xs_c(p % material, MG_GET_XS_SCATTER, p_g) + get_macro_xs_c(p % material, tid, MG_GET_XS_SCATTER, p_g) end if end if @@ -1475,13 +1475,13 @@ contains end if if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_ABSORPTION, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_ABSORPTION, p_g) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) end if else if (i_nuclide > 0) then score = atom_density * flux * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_ABSORPTION, p_g) else score = material_xs % absorption * flux end if @@ -1506,19 +1506,19 @@ contains end if if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) else score = score * & - get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, tid, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) end if else if (i_nuclide > 0) then - score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) * & + score = get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_FISSION, p_g) * & atom_density * flux else - score = get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) * flux + score = get_macro_xs_c(p % material, tid, MG_GET_XS_FISSION, p_g) * flux end if end if @@ -1544,12 +1544,12 @@ contains score = p % absorb_wgt * flux if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_NU_FISSION, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) else score = score * & - get_macro_xs_c(p % material, MG_GET_XS_NU_FISSION, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, tid, MG_GET_XS_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) end if else ! Skip any non-fission events @@ -1562,17 +1562,17 @@ contains score = keff * p % wgt_bank * flux if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_FISSION, p_g) end if end if else if (i_nuclide > 0) then - score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_NU_FISSION, p_g) * & + score = get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_NU_FISSION, p_g) * & atom_density * flux else - score = get_macro_xs_c(p % material, MG_GET_XS_NU_FISSION, p_g) * flux + score = get_macro_xs_c(p % material, tid, MG_GET_XS_NU_FISSION, p_g) * flux end if end if @@ -1598,12 +1598,12 @@ contains score = p % absorb_wgt * flux if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_PROMPT_NU_FISSION, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_PROMPT_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) else score = score * & - get_macro_xs_c(p % material, MG_GET_XS_PROMPT_NU_FISSION, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, tid, MG_GET_XS_PROMPT_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) end if else ! Skip any non-fission events @@ -1617,17 +1617,17 @@ contains / real(p % n_bank, 8)) * flux if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_FISSION, p_g) end if end if else if (i_nuclide > 0) then - score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_PROMPT_NU_FISSION, p_g) * & + score = get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_PROMPT_NU_FISSION, p_g) * & atom_density * flux else - score = get_macro_xs_c(p % material, MG_GET_XS_PROMPT_NU_FISSION, p_g) * flux + score = get_macro_xs_c(p % material, tid, MG_GET_XS_PROMPT_NU_FISSION, p_g) * flux end if end if @@ -1653,7 +1653,7 @@ contains ! No fission events occur if survival biasing is on -- need to ! calculate fraction of absorptions that would have resulted in ! nu-fission - if (get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) > ZERO) then + if (get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) > ZERO) then if (dg_filter > 0) then select type(filt => filters(t % filter(dg_filter)) % obj) @@ -1669,12 +1669,12 @@ contains score = p % absorb_wgt * flux if (i_nuclide > 0) then score = score * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) else score = score * & - get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) end if call score_fission_delayed_dg(t, d_bin, score, score_index) @@ -1685,12 +1685,12 @@ contains score = p % absorb_wgt * flux if (i_nuclide > 0) then score = score * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) else score = score * & - get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) end if end if end if @@ -1720,8 +1720,8 @@ contains if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_FISSION, p_g) end if call score_fission_delayed_dg(t, d_bin, score, score_index) @@ -1732,8 +1732,8 @@ contains score = keff * p % wgt_bank / p % n_bank * sum(p % n_delayed_bank) * flux if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_FISSION, p_g) end if end if end if @@ -1753,10 +1753,10 @@ contains if (i_nuclide > 0) then score = atom_density * flux * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) else score = flux * & - get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) + get_macro_xs_c(p % material, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) end if call score_fission_delayed_dg(t, d_bin, score, score_index) @@ -1766,11 +1766,11 @@ contains else if (i_nuclide > 0) then score = atom_density * flux * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g) else score = flux * & - get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g) + get_macro_xs_c(p % material, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g) end if end if end if @@ -1785,7 +1785,7 @@ contains ! No fission events occur if survival biasing is on -- need to ! calculate fraction of absorptions that would have resulted in ! nu-fission - if (get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) > ZERO) then + if (get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) > ZERO) then if (dg_filter > 0) then select type(filt => filters(t % filter(dg_filter)) % obj) @@ -1801,14 +1801,14 @@ contains score = p % absorb_wgt * flux if (i_nuclide > 0) then score = score * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) else score = score * & - get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_macro_xs_c(p % material, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) end if call score_fission_delayed_dg(t, d_bin, score, score_index) @@ -1826,14 +1826,14 @@ contains do d = 1, num_delayed_groups if (i_nuclide > 0) then score = score + p % absorb_wgt * flux * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) else score = score + p % absorb_wgt * flux * & - get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_macro_xs_c(p % material, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) end if end do end if @@ -1862,13 +1862,13 @@ contains if (i_nuclide > 0) then score = score + keff * atom_density * & fission_bank(n_bank - p % n_bank + k) % wgt * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) * flux + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_FISSION, p_g) * flux else score = score + keff * & fission_bank(n_bank - p % n_bank + k) % wgt * & - get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * flux + get_macro_xs_c(p % material, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * flux end if ! if the delayed group filter is present, tally to corresponding @@ -1921,12 +1921,12 @@ contains if (i_nuclide > 0) then score = atom_density * flux * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) else score = flux * & - get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) + get_macro_xs_c(p % material, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_macro_xs_c(p % material, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) end if call score_fission_delayed_dg(t, d_bin, score, score_index) @@ -1943,12 +1943,12 @@ contains do d = 1, num_delayed_groups if (i_nuclide > 0) then score = score + atom_density * flux * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) else score = score + flux * & - get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) + get_macro_xs_c(p % material, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_macro_xs_c(p % material, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) end if end do end if @@ -1973,20 +1973,20 @@ contains end if if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, MG_GET_XS_KAPPA_FISSION, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_KAPPA_FISSION, p_g) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) else score = score * & - get_macro_xs_c(p % material, MG_GET_XS_KAPPA_FISSION, p_g) / & - get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, tid, MG_GET_XS_KAPPA_FISSION, p_g) / & + get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) end if else if (i_nuclide > 0) then - score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_KAPPA_FISSION, p_g) * & + score = get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_KAPPA_FISSION, p_g) * & atom_density * flux else score = flux * & - get_macro_xs_c(p % material, MG_GET_XS_KAPPA_FISSION, p_g) + get_macro_xs_c(p % material, tid, MG_GET_XS_KAPPA_FISSION, p_g) end if end if @@ -2005,16 +2005,6 @@ contains t % results(RESULT_VALUE, score_index, filter_index) + score end do SCORE_LOOP - - ! Reset temporary Mgxs indices - call reset_macro_angle_index_c(p % material, last_mat_pol, last_mat_azi, & - last_mat_uvw); - - if (i_nuclide > 0) then - call reset_nuclide_temperature_index_c(i_nuclide, last_nuc_temp) - call reset_nuclide_angle_index_c(i_nuclide, last_nuc_pol, last_nuc_azi, & - last_nuc_uvw) - end if end subroutine score_general_mg !=============================================================================== diff --git a/src/tracking.F90 b/src/tracking.F90 index c832ca9ccc..80fb55a800 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -2,6 +2,10 @@ module tracking use, intrinsic :: ISO_C_BINDING +#ifdef _OPENMP + use omp_lib +#endif + use constants use error, only: warning, write_message use geometry_header, only: cells @@ -48,6 +52,12 @@ contains real(8) :: d_collision ! sampled distance to collision real(8) :: distance ! distance particle travels logical :: found_cell ! found cell which particle is in? + integer(C_INT) :: tid +#ifdef _OPENMP + tid = OMP_GET_THREAD_NUM() +#else + tid = 0 +#endif ! Display message if high verbosity or trace is on if (verbosity >= 9 .or. trace) then @@ -114,7 +124,7 @@ contains end if else ! Get the MG data - call calculate_xs_c(p % material, p % g, p % sqrtkT, & + call calculate_xs_c(p % material, tid, p % g, p % sqrtkT, & p % coord(p % n_coord) % uvw, material_xs % total, & material_xs % absorption, material_xs % nu_fission) From 9fd65822f07176393c3a45ffedf764d57d65e50f Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Fri, 15 Jun 2018 06:53:43 -0400 Subject: [PATCH 024/100] Fixing two failing tests - further inspection needed on mgxs_library_ce_to_mg; --- src/scattdata.cpp | 6 ++++-- src/xsdata.cpp | 12 ++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/scattdata.cpp b/src/scattdata.cpp index b12ec1acb7..dd8ca07e43 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -234,7 +234,7 @@ void ScattDataLegendre::sample(int gin, int& gout, double& mu, double& wgt) int samples = 0; while(true) { - double mu = 2. * prn() - 1.; + mu = 2. * prn() - 1.; double f = calc_f(gin, gout, mu); if (f > 0.) { double u = prn() * M; @@ -370,6 +370,7 @@ void ScattDataLegendre::combine(std::vector& those_scatts, for (int gout = gmin_; gout <= gmax_; gout++) { sparse_scatter[gin][i_gout] = this_matrix[gin][gout]; sparse_mult[gin][i_gout] = this_mult[gin][gout]; + i_gout++; } } @@ -442,7 +443,7 @@ void ScattDataHistogram::init(int_1dvec& in_gmin, int_1dvec& in_gmax, ScattData::generic_init(order, in_gmin, in_gmax, in_energy, in_mult); - // Build the angular distributio mu values + // Build the angular distribution mu values mu = double_1dvec(order); dmu = 2. / order; mu[0] = -1.; @@ -678,6 +679,7 @@ void ScattDataHistogram::combine(std::vector& those_scatts, for (int gout = gmin_; gout <= gmax_; gout++) { sparse_scatter[gin][i_gout] = this_matrix[gin][gout]; sparse_mult[gin][i_gout] = this_mult[gin][gout]; + i_gout++; } } diff --git a/src/xsdata.cpp b/src/xsdata.cpp index b79d02e200..62bfdc9161 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -248,7 +248,7 @@ void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } else if (ndims == 4) { // nu-fission is a matrix - read_nd_vector(xsdata_grp, "nu_fission", chi_prompt); + read_nd_vector(xsdata_grp, "nu-fission", chi_prompt); // Normalize the chi info so the CDF is 1. for (int p = 0; p < n_pol; p++) { @@ -256,6 +256,9 @@ void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, for (int gin = 0; gin < energy_groups; gin++) { double chi_sum = std::accumulate(chi_prompt[p][a][gin].begin(), chi_prompt[p][a][gin].end(), 0.); + // Set the vector nu-fission from the matrix nu-fission + prompt_nu_fission[p][a][gin] = chi_sum; + if (chi_sum >= 0.) { for (int gout = 0; gout < energy_groups; gout++) { chi_prompt[p][a][gin][gout] /= chi_sum; @@ -275,13 +278,6 @@ void XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } } - // Set the vector nu-fission from the matrix nu-fission - for (int gin = 0; gin < energy_groups; gin++) { - double sum = std::accumulate(chi_prompt[p][a][gin].begin(), - chi_prompt[p][a][gin].end(), 0.); - prompt_nu_fission[p][a][gin] = sum; - } - // Set the delayed-nu-fission and correct prompt-nu-fission with beta for (int gin = 0; gin < energy_groups; gin++) { for (int dg = 0; dg < delayed_groups; dg++) { From 39c063830cd87210d089f4e9c928038afe8eedc1 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Fri, 15 Jun 2018 19:46:25 -0400 Subject: [PATCH 025/100] minor changes, still not passing the test --- src/math_functions.cpp | 2 +- src/scattdata.cpp | 23 ++++++++++------------- src/scattdata.h | 4 ++-- src/xsdata.cpp | 3 ++- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/math_functions.cpp b/src/math_functions.cpp index 159e0a4e23..31f86ea5f6 100644 --- a/src/math_functions.cpp +++ b/src/math_functions.cpp @@ -97,7 +97,7 @@ void calc_pn_c(int n, double x, double pnx[]) { } // Use recursion relation to build the higher orders - for (int l = 1; l < n; l ++) { + for (int l = 1; l < n; l++) { pnx[l + 1] = ((2 * l + 1) * x * pnx[l] - l * pnx[l - 1]) / (l + 1); } } diff --git a/src/scattdata.cpp b/src/scattdata.cpp index dd8ca07e43..6bce75c646 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -6,8 +6,8 @@ namespace openmc { // ScattData base-class methods //============================================================================== -void ScattData::generic_init(int order, int_1dvec in_gmin, - int_1dvec in_gmax, double_2dvec in_energy, double_2dvec in_mult) +void ScattData::generic_init(int order, int_1dvec& in_gmin, + int_1dvec& in_gmax, double_2dvec& in_energy, double_2dvec& in_mult) { int groups = in_energy.size(); @@ -18,18 +18,17 @@ void ScattData::generic_init(int order, int_1dvec in_gmin, dist.resize(groups); for (int gin = 0; gin < groups; gin++) { - // Make sure the energy is normalized - double norm = std::accumulate(in_energy[gin].begin(), - in_energy[gin].end(), 0.); - - if (norm != 0.) { - for (auto& n : in_energy[gin]) n /= norm; - } - // Store the inputted data energy[gin] = in_energy[gin]; mult[gin] = in_mult[gin]; + // Make sure the energy is normalized + double norm = std::accumulate(energy[gin].begin(), energy[gin].end(), 0.); + + if (norm != 0.) { + for (auto& n : energy[gin]) n /= norm; + } + // Initialize the distribution data dist[gin].resize(in_gmax[gin] - in_gmin[gin] + 1); for (auto& v : dist[gin]) { @@ -131,9 +130,7 @@ void ScattDataLegendre::init(int_1dvec& in_gmin, int_1dvec& in_gmax, int num_groups = in_gmax[gin] - in_gmin[gin] + 1; scattxs[gin] = 0.; for (int i_gout = 0; i_gout < num_groups; i_gout++) { - scattxs[gin] = std::accumulate(matrix[gin][i_gout].begin(), - matrix[gin][i_gout].end(), - scattxs[gin]); + scattxs[gin] += matrix[gin][i_gout][0]; } } diff --git a/src/scattdata.h b/src/scattdata.h index a9a236b2b7..456610655f 100644 --- a/src/scattdata.h +++ b/src/scattdata.h @@ -39,8 +39,8 @@ class ScattData { double_2dvec& in_mult, double_3dvec& coeffs) = 0; void sample_energy(int gin, int& gout, int& i_gout); double get_xs(const int xstype, int gin, int* gout, double* mu); - void generic_init(int order, int_1dvec in_gmin, int_1dvec in_gmax, - double_2dvec in_energy, double_2dvec in_mult); + void generic_init(int order, int_1dvec& in_gmin, int_1dvec& in_gmax, + double_2dvec& in_energy, double_2dvec& in_mult); virtual void combine(std::vector& those_scatts, double_1dvec& scalars) = 0; virtual int get_order() = 0; diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 62bfdc9161..655bf9a891 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -602,7 +602,7 @@ void XsData::_scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, double_4dvec temp_mult = double_4dvec(n_pol, double_3dvec(n_azi, double_2dvec(energy_groups))); if (object_exists(scatt_grp, "multiplicity_matrix")) { - temp_arr.resize(length); + temp_arr.resize(length / order_data); read_nd_vector(scatt_grp, "multiplicity_matrix", temp_arr); // convert the flat temp_arr to a jagged array for passing to scatt data @@ -630,6 +630,7 @@ void XsData::_scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } } } + temp_arr.clear(); close_group(scatt_grp); // Finally, convert the Legendre data to tabular, if needed From 3cdb1bbb87a1de1220485e6d52ae271da8dbfd72 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Fri, 15 Jun 2018 20:39:57 -0400 Subject: [PATCH 026/100] Whew, there we go. Fixed. --- src/mgxs.h | 1 - src/scattdata.cpp | 60 +++++++++++++++++++++++++++++++++-------------- src/xsdata.h | 4 ---- 3 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/mgxs.h b/src/mgxs.h index 1c98417d69..d7b9a814a4 100644 --- a/src/mgxs.h +++ b/src/mgxs.h @@ -10,7 +10,6 @@ #include #include #include -#include #include "constants.h" #include "hdf5_interface.h" diff --git a/src/scattdata.cpp b/src/scattdata.cpp index 6bce75c646..1e33c07c17 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -337,16 +337,24 @@ void ScattDataLegendre::combine(std::vector& those_scatts, // Find the minimum and maximum group boundaries int gmin_; for (gmin_ = 0; gmin_ < groups; gmin_++) { - bool non_zero = std::all_of(this_matrix[gin][gmin_].begin(), - this_matrix[gin][gmin_].end(), - [](double val){return val != 0.;}); + bool non_zero = false; + for (int l = 0; l < this_matrix[gin][gmin_].size(); l++) { + if (this_matrix[gin][gmin_][l] != 0.) { + non_zero = true; + break; + } + } if (non_zero) break; } int gmax_; for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) { - bool non_zero = std::all_of(this_matrix[gin][gmax_].begin(), - this_matrix[gin][gmax_].end(), - [](double val){return val != 0.;}); + bool non_zero = false; + for (int l = 0; l < this_matrix[gin][gmax_].size(); l++) { + if (this_matrix[gin][gmax_][l] != 0.) { + non_zero = true; + break; + } + } if (non_zero) break; } @@ -646,16 +654,24 @@ void ScattDataHistogram::combine(std::vector& those_scatts, // Find the minimum and maximum group boundaries int gmin_; for (gmin_ = 0; gmin_ < groups; gmin_++) { - bool non_zero = std::all_of(this_matrix[gin][gmin_].begin(), - this_matrix[gin][gmin_].end(), - [](double val){return val != 0.;}); + bool non_zero = false; + for (int l = 0; l < this_matrix[gin][gmin_].size(); l++) { + if (this_matrix[gin][gmin_][l] != 0.) { + non_zero = true; + break; + } + } if (non_zero) break; } int gmax_; for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) { - bool non_zero = std::all_of(this_matrix[gin][gmax_].begin(), - this_matrix[gin][gmax_].end(), - [](double val){return val != 0.;}); + bool non_zero = false; + for (int l = 0; l < this_matrix[gin][gmax_].size(); l++) { + if (this_matrix[gin][gmax_][l] != 0.) { + non_zero = true; + break; + } + } if (non_zero) break; } @@ -956,16 +972,24 @@ void ScattDataTabular::combine(std::vector& those_scatts, // Find the minimum and maximum group boundaries int gmin_; for (gmin_ = 0; gmin_ < groups; gmin_++) { - bool non_zero = std::all_of(this_matrix[gin][gmin_].begin(), - this_matrix[gin][gmin_].end(), - [](double val){return val != 0.;}); + bool non_zero = false; + for (int l = 0; l < this_matrix[gin][gmin_].size(); l++) { + if (this_matrix[gin][gmin_][l] != 0.) { + non_zero = true; + break; + } + } if (non_zero) break; } int gmax_; for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) { - bool non_zero = std::all_of(this_matrix[gin][gmax_].begin(), - this_matrix[gin][gmax_].end(), - [](double val){return val != 0.;}); + bool non_zero = false; + for (int l = 0; l < this_matrix[gin][gmax_].size(); l++) { + if (this_matrix[gin][gmax_][l] != 0.) { + non_zero = true; + break; + } + } if (non_zero) break; } diff --git a/src/xsdata.h b/src/xsdata.h index 478f2e7aa1..3d6f1f7bba 100644 --- a/src/xsdata.h +++ b/src/xsdata.h @@ -7,11 +7,7 @@ #include #include #include -#include -#include -#include #include -#include #include "constants.h" #include "hdf5_interface.h" From 863f91b1e7fc21a7252b338f13be323a3d94c099 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sat, 16 Jun 2018 09:25:49 -0400 Subject: [PATCH 027/100] clearing up const and making use of generic base class methods --- src/api.F90 | 2 +- src/scattdata.cpp | 505 +++++++++++++++------------------------------- src/scattdata.h | 60 +++--- src/settings.F90 | 2 +- src/xsdata.cpp | 27 ++- src/xsdata.h | 23 ++- 6 files changed, 232 insertions(+), 387 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index ec17472ea2..8afc6061cd 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -129,7 +129,7 @@ contains index_ufs_mesh = -1 keff = ONE legendre_to_tabular = .true. - legendre_to_tabular_points = 33 + legendre_to_tabular_points = C_NONE n_batch_interval = 1 n_lost_particles = 0 n_particles = 0 diff --git a/src/scattdata.cpp b/src/scattdata.cpp index ad6a1db697..c0515f1ba2 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -41,6 +41,125 @@ ScattData::generic_init(int order, int_1dvec& in_gmin, int_1dvec& in_gmax, //============================================================================== +void +ScattData::generic_combine(const int max_order, + const std::vector& those_scatts, const double_1dvec& scalars, + int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& sparse_mult, + double_3dvec& sparse_scatter) +{ + int groups = those_scatts[0] -> energy.size(); + + // Now allocate and zero our storage spaces + double_3dvec this_matrix = double_3dvec(groups, double_2dvec(groups, + double_1dvec(max_order, 0.))); + double_2dvec mult_numer(groups, double_1dvec(groups, 0.)); + double_2dvec mult_denom(groups, double_1dvec(groups, 0.)); + + // Build the dense scattering and multiplicity matrices + // Get the multiplicity_matrix + // To combine from nuclidic data we need to use the final relationship + // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + // sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + // Developed as follows: + // mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} + // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) + // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + // sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + // nuscatt_{i,g,g'} can be reconstructed from the energy and scattxs member + // variables + for (int i = 0; i < those_scatts.size(); i++) { + ScattData* that = those_scatts[i]; + + // Build the dense matrix for that object + double_3dvec that_matrix = that->get_matrix(max_order); + + // Now add that to this for the scattering and multiplicity + for (int gin = 0; gin < groups; gin++) { + // Only spend time adding that's gmin to gmax data since the rest will + // be zeros + int i_gout = 0; + for (int gout = that->gmin[gin]; gout <= that->gmax[gin]; gout++) { + // Do the scattering matrix + for (int l = 0; l < max_order; l++) { + this_matrix[gin][gout][l] += scalars[i] * that_matrix[gin][gout][l]; + } + + // Incorporate that's contribution to the multiplicity matrix data + double nuscatt = that->scattxs[gin] * that->energy[gin][i_gout]; + mult_numer[gin][gout] += scalars[i] * nuscatt; + if (that->mult[gin][i_gout] > 0.) { + mult_denom[gin][gout] += scalars[i] * nuscatt / that->mult[gin][i_gout]; + } else { + mult_denom[gin][gout] += scalars[i]; + } + i_gout++; + } + } + } + + // Combine mult_numer and mult_denom into the combined multiplicity matrix + double_2dvec this_mult(groups, double_1dvec(groups, 1.)); + for (int gin = 0; gin < groups; gin++) { + for (int gout = 0; gout < groups; gout++) { + if (mult_denom[gin][gout] > 0.) { + this_mult[gin][gout] = mult_numer[gin][gout] / mult_denom[gin][gout]; + } + } + } + mult_numer.clear(); + mult_denom.clear(); + + // We have the data, now we need to convert to a jagged array and then use + // the initialize function to store it on the object. + for (int gin = 0; gin < groups; gin++) { + // Find the minimum and maximum group boundaries + int gmin_; + for (gmin_ = 0; gmin_ < groups; gmin_++) { + bool non_zero = false; + for (int l = 0; l < this_matrix[gin][gmin_].size(); l++) { + if (this_matrix[gin][gmin_][l] != 0.) { + non_zero = true; + break; + } + } + if (non_zero) break; + } + int gmax_; + for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) { + bool non_zero = false; + for (int l = 0; l < this_matrix[gin][gmax_].size(); l++) { + if (this_matrix[gin][gmax_][l] != 0.) { + non_zero = true; + break; + } + } + if (non_zero) break; + } + + // treat the case of all values being 0 + if (gmin_ > gmax_) { + gmin_ = gin; + gmax_ = gin; + } + + // Store the group bounds + in_gmin[gin] = gmin_; + in_gmax[gin] = gmax_; + + // Store the data in the compressed format + sparse_scatter[gin].resize(gmax_ - gmin_ + 1); + sparse_mult[gin].resize(gmax_ - gmin_ + 1); + int i_gout = 0; + for (int gout = gmin_; gout <= gmax_; gout++) { + sparse_scatter[gin][i_gout] = this_matrix[gin][gout]; + sparse_mult[gin][i_gout] = this_mult[gin][gout]; + i_gout++; + } + } +} + +//============================================================================== + void ScattData::sample_energy(int gin, int& gout, int& i_gout) { @@ -60,7 +179,8 @@ ScattData::sample_energy(int gin, int& gout, int& i_gout) //============================================================================== double -ScattData::get_xs(const int xstype, int gin, int* gout, double* mu) +ScattData::get_xs(const int xstype, const int gin, const int* gout, + const double* mu) { // Set the outgoing group offset index as needed int i_gout = 0; @@ -214,7 +334,7 @@ ScattDataLegendre::update_max_val() //============================================================================== double -ScattDataLegendre::calc_f(int gin, int gout, double mu) +ScattDataLegendre::calc_f(const int gin, const int gout, const double mu) { double f; if ((gout < gmin[gin]) || (gout > gmax[gin])) { @@ -230,7 +350,7 @@ ScattDataLegendre::calc_f(int gin, int gout, double mu) //============================================================================== void -ScattDataLegendre::sample(int gin, int& gout, double& mu, double& wgt) +ScattDataLegendre::sample(const int gin, int& gout, double& mu, double& wgt) { // Sample the outgoing energy using the base-class method int i_gout; @@ -261,8 +381,8 @@ ScattDataLegendre::sample(int gin, int& gout, double& mu, double& wgt) //============================================================================== void -ScattDataLegendre::combine(std::vector& those_scatts, - double_1dvec& scalars) +ScattDataLegendre::combine(const std::vector& those_scatts, + const double_1dvec& scalars) { // Find the max order in the data set and make sure we can combine the sets int max_order = 0; @@ -277,120 +397,18 @@ ScattDataLegendre::combine(std::vector& those_scatts, } max_order++; // Add one since this is a Legendre - // Get the groups as a shorthand - int groups = dynamic_cast(those_scatts[0])->energy.size(); + int groups = those_scatts[0] -> energy.size(); - // Now allocate and zero our storage spaces - double_3dvec this_matrix = double_3dvec(groups, double_2dvec(groups, - double_1dvec(max_order, 0.))); - double_2dvec mult_numer(groups, double_1dvec(groups, 0.)); - double_2dvec mult_denom(groups, double_1dvec(groups, 0.)); - - // Build the dense scattering and multiplicity matrices - // Get the multiplicity_matrix - // To combine from nuclidic data we need to use the final relationship - // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - // sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - // Developed as follows: - // mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} - // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) - // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - // sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - // nuscatt_{i,g,g'} can be reconstructed from the energy and scattxs member - // variables - for (int i = 0; i < those_scatts.size(); i++) { - ScattDataLegendre* that = dynamic_cast(those_scatts[i]); - - // Build the dense matrix for that object - double_3dvec that_matrix = that->get_matrix(max_order); - - // Now add that to this for the scattering and multiplicity - for (int gin = 0; gin < groups; gin++) { - // Only spend time adding that's gmin to gmax data since the rest will - // be zeros - int i_gout = 0; - for (int gout = that->gmin[gin]; gout <= that->gmax[gin]; gout++) { - // Do the scattering matrix - for (int l = 0; l < max_order; l++) { - this_matrix[gin][gout][l] += scalars[i] * that_matrix[gin][gout][l]; - } - - // Incorporate that's contribution to the multiplicity matrix data - double nuscatt = that->scattxs[gin] * that->energy[gin][i_gout]; - mult_numer[gin][gout] += scalars[i] * nuscatt; - if (that->mult[gin][i_gout] > 0.) { - mult_denom[gin][gout] += scalars[i] * nuscatt / that->mult[gin][i_gout]; - } else { - mult_denom[gin][gout] += scalars[i]; - } - i_gout++; - } - } - } - - // Combine mult_numer and mult_denom into the combined multiplicity matrix - double_2dvec this_mult(groups, double_1dvec(groups, 1.)); - for (int gin = 0; gin < groups; gin++) { - for (int gout = 0; gout < groups; gout++) { - if (mult_denom[gin][gout] > 0.) { - this_mult[gin][gout] = mult_numer[gin][gout] / mult_denom[gin][gout]; - } - } - } - mult_numer.clear(); - mult_denom.clear(); - - // We have the data, now we need to convert to a jagged array and then use - // the initialize function to store it on the object. int_1dvec in_gmin(groups); int_1dvec in_gmax(groups); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); - for (int gin = 0; gin < groups; gin++) { - // Find the minimum and maximum group boundaries - int gmin_; - for (gmin_ = 0; gmin_ < groups; gmin_++) { - bool non_zero = false; - for (int l = 0; l < this_matrix[gin][gmin_].size(); l++) { - if (this_matrix[gin][gmin_][l] != 0.) { - non_zero = true; - break; - } - } - if (non_zero) break; - } - int gmax_; - for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) { - bool non_zero = false; - for (int l = 0; l < this_matrix[gin][gmax_].size(); l++) { - if (this_matrix[gin][gmax_][l] != 0.) { - non_zero = true; - break; - } - } - if (non_zero) break; - } - // treat the case of all values being 0 - if (gmin_ > gmax_) { - gmin_ = gin; - gmax_ = gin; - } - - // Store the group bounds - in_gmin[gin] = gmin_; - in_gmax[gin] = gmax_; - - // Store the data in the compressed format - sparse_scatter[gin].resize(gmax_ - gmin_ + 1); - sparse_mult[gin].resize(gmax_ - gmin_ + 1); - int i_gout = 0; - for (int gout = gmin_; gout <= gmax_; gout++) { - sparse_scatter[gin][i_gout] = this_matrix[gin][gout]; - sparse_mult[gin][i_gout] = this_mult[gin][gout]; - i_gout++; - } - } + // The rest of the steps do not depend on the type of angular representation + // so we use a base class method to sum up xs and create new energy and mult + // matrices + ScattData::generic_combine(max_order, those_scatts, scalars, in_gmin, in_gmax, + sparse_mult, sparse_scatter); // Got everything we need, store it. init(in_gmin, in_gmax, sparse_mult, sparse_scatter); @@ -399,7 +417,7 @@ ScattDataLegendre::combine(std::vector& those_scatts, //============================================================================== double_3dvec -ScattDataLegendre::get_matrix(int max_order) +ScattDataLegendre::get_matrix(const int max_order) { // Get the sizes and initialize the data to 0 int groups = energy.size(); @@ -504,7 +522,7 @@ ScattDataHistogram::init(int_1dvec& in_gmin, int_1dvec& in_gmax, //============================================================================== double -ScattDataHistogram::calc_f(int gin, int gout, double mu) +ScattDataHistogram::calc_f(const int gin, const int gout, const double mu) { double f; if ((gout < gmin[gin]) || (gout > gmax[gin])) { @@ -528,7 +546,7 @@ ScattDataHistogram::calc_f(int gin, int gout, double mu) //============================================================================== void -ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt) +ScattDataHistogram::sample(const int gin, int& gout, double& mu, double& wgt) { // Sample the outgoing energy using the base-class method int i_gout; @@ -563,7 +581,7 @@ ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt) //============================================================================== double_3dvec -ScattDataHistogram::get_matrix(int max_order) +ScattDataHistogram::get_matrix(const int max_order) { // Get the sizes and initialize the data to 0 int groups = energy.size(); @@ -587,8 +605,8 @@ ScattDataHistogram::get_matrix(int max_order) //============================================================================== void -ScattDataHistogram::combine(std::vector& those_scatts, - double_1dvec& scalars) +ScattDataHistogram::combine(const std::vector& those_scatts, + const double_1dvec& scalars) { // Find the max order in the data set and make sure we can combine the sets int max_order; @@ -605,120 +623,18 @@ ScattDataHistogram::combine(std::vector& those_scatts, } } - // Get the groups as a shorthand - int groups = dynamic_cast(those_scatts[0])->energy.size(); + int groups = those_scatts[0] -> energy.size(); - // Now allocate and zero our storage spaces - double_3dvec this_matrix = double_3dvec(groups, double_2dvec(groups, - double_1dvec(max_order, 0.))); - double_2dvec mult_numer(groups, double_1dvec(groups, 0.)); - double_2dvec mult_denom(groups, double_1dvec(groups, 0.)); - - // Build the dense scattering and multiplicity matrices - // Get the multiplicity_matrix - // To combine from nuclidic data we need to use the final relationship - // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - // sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - // Developed as follows: - // mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} - // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) - // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - // sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - // nuscatt_{i,g,g'} can be reconstructed from the energy and scattxs member - // variables - for (int i = 0; i < those_scatts.size(); i++) { - ScattDataHistogram* that = dynamic_cast(those_scatts[i]); - - // Build the dense matrix for that object - double_3dvec that_matrix = that->get_matrix(max_order); - - // Now add that to this for the scattering and multiplicity - for (int gin = 0; gin < groups; gin++) { - // Only spend time adding that's gmin to gmax data since the rest will - // be zeros - int i_gout = 0; - for (int gout = that->gmin[gin]; gout <= that->gmax[gin]; gout++) { - // Do the scattering matrix - for (int l = 0; l < max_order; l++) { - this_matrix[gin][gout][l] += scalars[i] * that_matrix[gin][gout][l]; - } - - // Incorporate that's contribution to the multiplicity matrix data - double nuscatt = that->scattxs[gin] * that->energy[gin][i_gout]; - mult_numer[gin][gout] += scalars[i] * nuscatt; - if (that->mult[gin][i_gout] > 0.) { - mult_denom[gin][gout] += scalars[i] * nuscatt / that->mult[gin][i_gout]; - } else { - mult_denom[gin][gout] += scalars[i]; - } - i_gout++; - } - } - } - - // Combine mult_numer and mult_denom into the combined multiplicity matrix - double_2dvec this_mult(groups, double_1dvec(groups, 1.)); - for (int gin = 0; gin < groups; gin++) { - for (int gout = 0; gout < groups; gout++) { - if (mult_denom[gin][gout] > 0.) { - this_mult[gin][gout] = mult_numer[gin][gout] / mult_denom[gin][gout]; - } - } - } - mult_numer.clear(); - mult_denom.clear(); - - // We have the data, now we need to convert to a jagged array and then use - // the initialize function to store it on the object. int_1dvec in_gmin(groups); int_1dvec in_gmax(groups); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); - for (int gin = 0; gin < groups; gin++) { - // Find the minimum and maximum group boundaries - int gmin_; - for (gmin_ = 0; gmin_ < groups; gmin_++) { - bool non_zero = false; - for (int l = 0; l < this_matrix[gin][gmin_].size(); l++) { - if (this_matrix[gin][gmin_][l] != 0.) { - non_zero = true; - break; - } - } - if (non_zero) break; - } - int gmax_; - for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) { - bool non_zero = false; - for (int l = 0; l < this_matrix[gin][gmax_].size(); l++) { - if (this_matrix[gin][gmax_][l] != 0.) { - non_zero = true; - break; - } - } - if (non_zero) break; - } - // treat the case of all values being 0 - if (gmin_ > gmax_) { - gmin_ = gin; - gmax_ = gin; - } - - // Store the group bounds - in_gmin[gin] = gmin_; - in_gmax[gin] = gmax_; - - // Store the data in the compressed format - sparse_scatter[gin].resize(gmax_ - gmin_ + 1); - sparse_mult[gin].resize(gmax_ - gmin_ + 1); - int i_gout = 0; - for (int gout = gmin_; gout <= gmax_; gout++) { - sparse_scatter[gin][i_gout] = this_matrix[gin][gout]; - sparse_mult[gin][i_gout] = this_mult[gin][gout]; - i_gout++; - } - } + // The rest of the steps do not depend on the type of angular representation + // so we use a base class method to sum up xs and create new energy and mult + // matrices + ScattData::generic_combine(max_order, those_scatts, scalars, in_gmin, in_gmax, + sparse_mult, sparse_scatter); // Got everything we need, store it. init(in_gmin, in_gmax, sparse_mult, sparse_scatter); @@ -818,7 +734,7 @@ ScattDataTabular::init(int_1dvec& in_gmin, int_1dvec& in_gmax, //============================================================================== double -ScattDataTabular::calc_f(int gin, int gout, double mu) +ScattDataTabular::calc_f(const int gin, const int gout, const double mu) { double f; if ((gout < gmin[gin]) || (gout > gmax[gin])) { @@ -843,7 +759,7 @@ ScattDataTabular::calc_f(int gin, int gout, double mu) //============================================================================== void -ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt) +ScattDataTabular::sample(const int gin, int& gout, double& mu, double& wgt) { // Sample the outgoing energy using the base-class method int i_gout; @@ -891,7 +807,7 @@ ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt) //============================================================================== double_3dvec -ScattDataTabular::get_matrix(int max_order) +ScattDataTabular::get_matrix(const int max_order) { // Get the sizes and initialize the data to 0 int groups = energy.size(); @@ -915,8 +831,8 @@ ScattDataTabular::get_matrix(int max_order) //============================================================================== void -ScattDataTabular::combine(std::vector& those_scatts, - double_1dvec& scalars) +ScattDataTabular::combine(const std::vector& those_scatts, + const double_1dvec& scalars) { // Find the max order in the data set and make sure we can combine the sets int max_order; @@ -933,120 +849,18 @@ ScattDataTabular::combine(std::vector& those_scatts, } } - // Get the groups as a shorthand - int groups = dynamic_cast(those_scatts[0])->energy.size(); + int groups = those_scatts[0] -> energy.size(); - // Now allocate and zero our storage spaces - double_3dvec this_matrix = double_3dvec(groups, double_2dvec(groups, - double_1dvec(max_order, 0.))); - double_2dvec mult_numer(groups, double_1dvec(groups, 0.)); - double_2dvec mult_denom(groups, double_1dvec(groups, 0.)); - - // Build the dense scattering and multiplicity matrices - // Get the multiplicity_matrix - // To combine from nuclidic data we need to use the final relationship - // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - // sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - // Developed as follows: - // mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} - // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) - // mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - // sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - // nuscatt_{i,g,g'} can be reconstructed from the energy and scattxs member - // variables - for (int i = 0; i < those_scatts.size(); i++) { - ScattDataTabular* that = dynamic_cast(those_scatts[i]); - - // Build the dense matrix for that object - double_3dvec that_matrix = that->get_matrix(max_order); - - // Now add that to this for the scattering and multiplicity - for (int gin = 0; gin < groups; gin++) { - // Only spend time adding that's gmin to gmax data since the rest will - // be zeros - int i_gout = 0; - for (int gout = that->gmin[gin]; gout <= that->gmax[gin]; gout++) { - // Do the scattering matrix - for (int l = 0; l < max_order; l++) { - this_matrix[gin][gout][l] += scalars[i] * that_matrix[gin][gout][l]; - } - - // Incorporate that's contribution to the multiplicity matrix data - double nuscatt = that->scattxs[gin] * that->energy[gin][i_gout]; - mult_numer[gin][gout] += scalars[i] * nuscatt; - if (that->mult[gin][i_gout] > 0.) { - mult_denom[gin][gout] += scalars[i] * nuscatt / that->mult[gin][i_gout]; - } else { - mult_denom[gin][gout] += scalars[i]; - } - i_gout++; - } - } - } - - // Combine mult_numer and mult_denom into the combined multiplicity matrix - double_2dvec this_mult(groups, double_1dvec(groups, 1.)); - for (int gin = 0; gin < groups; gin++) { - for (int gout = 0; gout < groups; gout++) { - if (mult_denom[gin][gout] > 0.) { - this_mult[gin][gout] = mult_numer[gin][gout] / mult_denom[gin][gout]; - } - } - } - mult_numer.clear(); - mult_denom.clear(); - - // We have the data, now we need to convert to a jagged array and then use - // the initialize function to store it on the object. int_1dvec in_gmin(groups); int_1dvec in_gmax(groups); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); - for (int gin = 0; gin < groups; gin++) { - // Find the minimum and maximum group boundaries - int gmin_; - for (gmin_ = 0; gmin_ < groups; gmin_++) { - bool non_zero = false; - for (int l = 0; l < this_matrix[gin][gmin_].size(); l++) { - if (this_matrix[gin][gmin_][l] != 0.) { - non_zero = true; - break; - } - } - if (non_zero) break; - } - int gmax_; - for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) { - bool non_zero = false; - for (int l = 0; l < this_matrix[gin][gmax_].size(); l++) { - if (this_matrix[gin][gmax_][l] != 0.) { - non_zero = true; - break; - } - } - if (non_zero) break; - } - // treat the case of all values being 0 - if (gmin_ > gmax_) { - gmin_ = gin; - gmax_ = gin; - } - - // Store the group bounds - in_gmin[gin] = gmin_; - in_gmax[gin] = gmax_; - - // Store the data in the compressed format - sparse_scatter[gin].resize(gmax_ - gmin_ + 1); - sparse_mult[gin].resize(gmax_ - gmin_ + 1); - int i_gout = 0; - for (int gout = gmin_; gout <= gmax_; gout++) { - sparse_scatter[gin][i_gout] = this_matrix[gin][gout]; - sparse_mult[gin][i_gout] = this_mult[gin][gout]; - i_gout++; - } - } + // The rest of the steps do not depend on the type of angular representation + // so we use a base class method to sum up xs and create new energy and mult + // matrices + ScattData::generic_combine(max_order, those_scatts, scalars, in_gmin, in_gmax, + sparse_mult, sparse_scatter); // Got everything we need, store it. init(in_gmin, in_gmax, sparse_mult, sparse_scatter); @@ -1060,6 +874,17 @@ void convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, int n_mu) { + // See if the user wants us to figure out how many points to use + if (n_mu == C_NONE) { + // then we will use 2 pts if its P0 or P1 (super fast), or the default if + // a higher order + if (leg.get_order() <= 1) { + n_mu = 2; + } else { + n_mu = DEFAULT_NMU; + } + } + tab.generic_init(n_mu, leg.gmin, leg.gmax, leg.energy, leg.mult); tab.scattxs = leg.scattxs; diff --git a/src/scattdata.h b/src/scattdata.h index e5f115e615..9b362b9644 100644 --- a/src/scattdata.h +++ b/src/scattdata.h @@ -16,35 +16,42 @@ namespace openmc { -//============================================================================== -// SCATTDATA contains all the data needed to describe the scattering energy and -// angular distribution data -//============================================================================== // temporary declaations so we can name our friend functions class ScattDataLegendre; class ScattDataTabular; +//============================================================================== +// SCATTDATA contains all the data needed to describe the scattering energy and +// angular distribution data +//============================================================================== + class ScattData { protected: + void generic_init(int order, int_1dvec& in_gmin, int_1dvec& in_gmax, + double_2dvec& in_energy, double_2dvec& in_mult); + void generic_combine(const int max_order, + const std::vector& those_scatts, + const double_1dvec& scalars, int_1dvec& in_gmin, + int_1dvec& in_gmax, double_2dvec& sparse_mult, + double_3dvec& sparse_scatter); + public: double_2dvec energy; // Normalized p0 matrix for sampling Eout double_2dvec mult; // nu-scatter multiplication (nu-scatt/scatt) double_3dvec dist; // Angular distribution int_1dvec gmin; // minimum outgoing group int_1dvec gmax; // maximum outgoing group - public: double_1dvec scattxs; // Isotropic Sigma_{s,g_{in}} - virtual double calc_f(int gin, int gout, double mu) = 0; - virtual void sample(int gin, int& gout, double& mu, double& wgt) = 0; + virtual double calc_f(const int gin, const int gout, const double mu) = 0; + virtual void sample(const int gin, int& gout, double& mu, double& wgt) = 0; virtual void init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, double_3dvec& coeffs) = 0; void sample_energy(int gin, int& gout, int& i_gout); - double get_xs(const int xstype, int gin, int* gout, double* mu); - void generic_init(int order, int_1dvec& in_gmin, int_1dvec& in_gmax, - double_2dvec& in_energy, double_2dvec& in_mult); - virtual void combine(std::vector& those_scatts, - double_1dvec& scalars) = 0; + double get_xs(const int xstype, const int gin, const int* gout, + const double* mu); + virtual void combine(const std::vector& those_scatts, + const double_1dvec& scalars) = 0; virtual int get_order() = 0; - virtual double_3dvec get_matrix(int max_order) = 0; + virtual double_3dvec get_matrix(const int max_order) = 0; }; //============================================================================== @@ -61,11 +68,12 @@ class ScattDataLegendre: public ScattData { void init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, double_3dvec& coeffs); void update_max_val(); - double calc_f(int gin, int gout, double mu); - void sample(int gin, int& gout, double& mu, double& wgt); - void combine(std::vector& those_scatts, double_1dvec& scalars); + double calc_f(const int gin, const int gout, const double mu); + void sample(const int gin, int& gout, double& mu, double& wgt); + void combine(const std::vector& those_scatts, + const double_1dvec& scalars); int get_order() {return dist[0][0].size() - 1;}; - double_3dvec get_matrix(int max_order); + double_3dvec get_matrix(const int max_order); }; //============================================================================== @@ -81,11 +89,12 @@ class ScattDataHistogram: public ScattData { public: void init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, double_3dvec& coeffs); - double calc_f(int gin, int gout, double mu); - void sample(int gin, int& gout, double& mu, double& wgt); - void combine(std::vector& those_scatts, double_1dvec& scalars); + double calc_f(const int gin, const int gout, const double mu); + void sample(const int gin, int& gout, double& mu, double& wgt); + void combine(const std::vector& those_scatts, + const double_1dvec& scalars); int get_order() {return dist[0][0].size();}; - double_3dvec get_matrix(int max_order); + double_3dvec get_matrix(const int max_order); }; //============================================================================== @@ -103,11 +112,12 @@ class ScattDataTabular: public ScattData { public: void init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, double_3dvec& coeffs); - double calc_f(int gin, int gout, double mu); - void sample(int gin, int& gout, double& mu, double& wgt); - void combine(std::vector& those_scatts, double_1dvec& scalars); + double calc_f(const int gin, const int gout, const double mu); + void sample(const int gin, int& gout, double& mu, double& wgt); + void combine(const std::vector& those_scatts, + const double_1dvec& scalars); int get_order() {return dist[0][0].size();}; - double_3dvec get_matrix(int max_order); + double_3dvec get_matrix(const int max_order); }; //============================================================================== diff --git a/src/settings.F90 b/src/settings.F90 index 0ed51d119a..5994651608 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -36,7 +36,7 @@ module settings logical :: legendre_to_tabular = .true. ! Number of points to use in the Legendre to tabular conversion - integer(C_INT) :: legendre_to_tabular_points = 33 + integer(C_INT) :: legendre_to_tabular_points = C_NONE ! ============================================================================ ! SIMULATION VARIABLES diff --git a/src/xsdata.cpp b/src/xsdata.cpp index ddfe4c0fdf..991e2a9010 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -6,8 +6,9 @@ namespace openmc { // XsData class methods //============================================================================== -XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable, - int scatter_format, int n_pol, int n_azi) +XsData::XsData(const int energy_groups, const int num_delayed_groups, + const bool fissionable, const int scatter_format, + const int n_pol, const int n_azi) { // check to make sure scatter format is OK before we allocate if (scatter_format != ANGLE_HISTOGRAM && scatter_format != ANGLE_TABULAR && @@ -69,9 +70,10 @@ XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable, //============================================================================== void -XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, - int final_scatter_format, int order_data, int max_order, - int legendre_to_tabular_points, bool is_isotropic) +XsData::from_hdf5(const hid_t xsdata_grp, const bool fissionable, + const int scatter_format, const int final_scatter_format, + const int order_data, const int max_order, + const int legendre_to_tabular_points, const bool is_isotropic) { // Reconstruct the dimension information so it doesn't need to be passed int n_pol = total.size(); @@ -132,8 +134,9 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, //============================================================================== void -XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, - int energy_groups, int delayed_groups, bool is_isotropic) +XsData::_fissionable_from_hdf5(const hid_t xsdata_grp, const int n_pol, + const int n_azi, const int energy_groups, const int delayed_groups, + const bool is_isotropic) { // Get the fission and kappa_fission data xs; these are optional @@ -532,9 +535,10 @@ XsData::_fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, //============================================================================== void -XsData::_scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, - int energy_groups, int scatter_format, int final_scatter_format, - int order_data, int max_order, int legendre_to_tabular_points) +XsData::_scatter_from_hdf5(const hid_t xsdata_grp, const int n_pol, + const int n_azi, const int energy_groups, int scatter_format, + const int final_scatter_format, const int order_data, const int max_order, + const int legendre_to_tabular_points) { if (!object_exists(xsdata_grp, "scatter_data")) { fatal_error("Must provide scatter_data group!"); @@ -671,7 +675,8 @@ XsData::_scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, //============================================================================== void -XsData::combine(std::vector those_xs, double_1dvec& scalars) +XsData::combine(const std::vector those_xs, + const double_1dvec& scalars) { // Combine the non-scattering data for (int i = 0; i < those_xs.size(); i++) { diff --git a/src/xsdata.h b/src/xsdata.h index 3d6f1f7bba..4d3a5d5d40 100644 --- a/src/xsdata.h +++ b/src/xsdata.h @@ -24,9 +24,10 @@ namespace openmc { class XsData { private: - void _scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, - int energy_groups, int scatter_format, int final_scatter_format, - int order_data, int max_order, int legendre_to_tabular_points); + void _scatter_from_hdf5(const hid_t xsdata_grp, const int n_pol, + const int n_azi, const int energy_groups, int scatter_format, + const int final_scatter_format, const int order_data, + const int max_order, const int legendre_to_tabular_points); void _fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, int energy_groups, int delayed_groups, bool is_isotropic); public: @@ -55,12 +56,16 @@ class XsData { std::vector > scatter; XsData() = default; - XsData(int num_groups, int num_delayed_groups, bool fissionable, - int scatter_format, int n_pol, int n_azi); - void from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, - int final_scatter_format, int order_data, int max_order, - int legendre_to_tabular_points, bool is_isotropic); - void combine(std::vector those_xs, double_1dvec& scalars); + XsData(const int num_groups, const int num_delayed_groups, + const bool fissionable, const int scatter_format, const int n_pol, + const int n_azi); + void from_hdf5(const hid_t xsdata_grp, const bool fissionable, + const int scatter_format, const int final_scatter_format, + const int order_data, const int max_order, + const int legendre_to_tabular_points, + const bool is_isotropic); + void combine(const std::vector those_xs, + const double_1dvec& scalars); bool equiv(const XsData& that); }; From 35c62affe63e457413e3467cabd77cbd54c9a962 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sat, 16 Jun 2018 13:37:50 -0400 Subject: [PATCH 028/100] Replaced all polar and azimuthal indices with just a 1d angle index. Also fixed mg_max_order --- src/hdf5_interface.cpp | 22 ++ src/hdf5_interface.h | 4 + src/mgxs.cpp | 128 ++++---- src/mgxs.h | 12 +- src/scattdata.cpp | 6 +- src/xsdata.cpp | 690 ++++++++++++++++++----------------------- src/xsdata.h | 46 +-- 7 files changed, 431 insertions(+), 477 deletions(-) diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index 39e0162b58..a81f26e231 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -481,6 +481,28 @@ read_nd_vector(hid_t obj_id, const char* name, } +void +read_nd_vector(hid_t obj_id, const char* name, + std::vector >& result, bool must_have) +{ + if (object_exists(obj_id, name)) { + int dim1 = result.size(); + int dim2 = result[0].size(); + std::vector temp_arr = std::vector(dim1 * dim2); + read_int(obj_id, name, &temp_arr[0], true); + + int temp_idx = 0; + for (int i = 0; i < dim1; i++) { + for (int j = 0; j < dim2; j++) { + result[i][j] = temp_arr[temp_idx++]; + } + } + } else if (must_have) { + fatal_error(std::string("Must provide " + std::string(name) + "!")); + } +} + + void read_nd_vector(hid_t obj_id, const char* name, std::vector > >& result, diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index 59a914f52e..b00fe7c879 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -65,6 +65,10 @@ read_nd_vector(hid_t obj_id, const char* name, std::vector >& result, bool must_have = false); +void +read_nd_vector(hid_t obj_id, const char* name, + std::vector >& result, bool must_have = false); + void read_nd_vector(hid_t obj_id, const char* name, std::vector > >& result, diff --git a/src/mgxs.cpp b/src/mgxs.cpp index ab2970b2f3..81a510e30b 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -34,11 +34,10 @@ Mgxs::init(const std::string& in_name, const double in_awr, for (int thread = 0; thread < n_threads; thread++) { cache[thread].sqrtkT = 0.; cache[thread].t = 0; - cache[thread].p = 0; cache[thread].a = 0; - cache[thread].uvw[0] = 1.; - cache[thread].uvw[1] = 0.; - cache[thread].uvw[2] = 0.; + cache[thread].u = 0.; + cache[thread].v = 0.; + cache[thread].w = 0.; } } @@ -48,7 +47,7 @@ void Mgxs::_metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, const int in_num_delayed_groups, double_1dvec& temperature, int& method, const double tolerance, int_1dvec& temps_to_read, int& order_dim, - bool& is_isotropic, const int n_threads) + const int n_threads) { // get name char char_name[MAX_WORD_LEN]; @@ -179,7 +178,7 @@ Mgxs::_metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, fatal_error("Invalid scatter_shape option!"); } } - //TODO: do i even need this flag? - it should be easy to self-determine + bool in_fissionable = false; if (attribute_exists(xs_id, "fissionable")) { int int_fiss; @@ -264,9 +263,8 @@ Mgxs::from_hdf5(hid_t xs_id, const int energy_groups, // Call generic data gathering routine (will populate the metadata) int order_data; int_1dvec temps_to_read; - bool is_isotropic; _metadata_from_hdf5(xs_id, energy_groups, delayed_groups, temperature, - method, tolerance, temps_to_read, order_data, is_isotropic, n_threads); + method, tolerance, temps_to_read, order_data, n_threads); // Set number of energy and delayed groups int final_scatter_format = scatter_format; @@ -284,7 +282,7 @@ Mgxs::from_hdf5(hid_t xs_id, const int energy_groups, xs[t].from_hdf5(xsdata_grp, fissionable, scatter_format, final_scatter_format, order_data, max_order, - legendre_to_tabular_points, is_isotropic); + legendre_to_tabular_points, is_isotropic, n_pol, n_azi); close_group(xsdata_grp); } // end temperature loop @@ -419,45 +417,41 @@ Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, double val; switch(xstype) { case MG_GET_XS_TOTAL: - val = xs[cache[tid].t].total[cache[tid].p][cache[tid].a][gin]; + val = xs[cache[tid].t].total[cache[tid].a][gin]; break; - case MG_GET_XS_ABSORPTION: - val = xs[cache[tid].t].absorption[cache[tid].p][cache[tid].a][gin]; - break; - case MG_GET_XS_INVERSE_VELOCITY: - val = xs[cache[tid].t].inverse_velocity[cache[tid].p][cache[tid].a][gin]; - break; - case MG_GET_XS_DECAY_RATE: - if (dg != nullptr) { - val = xs[cache[tid].t].decay_rate[cache[tid].p][cache[tid].a][*dg + 1]; + case MG_GET_XS_NU_FISSION: + if (fissionable) { + val = xs[cache[tid].t].nu_fission[cache[tid].a][gin]; } else { - val = xs[cache[tid].t].decay_rate[cache[tid].p][cache[tid].a][0]; + val = 0.; } break; - case MG_GET_XS_SCATTER: - case MG_GET_XS_SCATTER_MULT: - case MG_GET_XS_SCATTER_FMU_MULT: - case MG_GET_XS_SCATTER_FMU: - val = xs[cache[tid].t].scatter[cache[tid].p] - [cache[tid].a]->get_xs(xstype, gin, gout, mu); + case MG_GET_XS_ABSORPTION: + val = xs[cache[tid].t].absorption[cache[tid].a][gin]; break; case MG_GET_XS_FISSION: if (fissionable) { - val = xs[cache[tid].t].fission[cache[tid].p][cache[tid].a][gin]; + val = xs[cache[tid].t].fission[cache[tid].a][gin]; } else { val = 0.; } break; case MG_GET_XS_KAPPA_FISSION: if (fissionable) { - val = xs[cache[tid].t].kappa_fission[cache[tid].p][cache[tid].a][gin]; + val = xs[cache[tid].t].kappa_fission[cache[tid].a][gin]; } else { val = 0.; } break; + case MG_GET_XS_SCATTER: + case MG_GET_XS_SCATTER_MULT: + case MG_GET_XS_SCATTER_FMU_MULT: + case MG_GET_XS_SCATTER_FMU: + val = xs[cache[tid].t].scatter[cache[tid].a]->get_xs(xstype, gin, gout, mu); + break; case MG_GET_XS_PROMPT_NU_FISSION: if (fissionable) { - val = xs[cache[tid].t].prompt_nu_fission[cache[tid].p][cache[tid].a][gin]; + val = xs[cache[tid].t].prompt_nu_fission[cache[tid].a][gin]; } else { val = 0.; } @@ -465,10 +459,10 @@ Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, case MG_GET_XS_DELAYED_NU_FISSION: if (fissionable) { if (dg != nullptr) { - val = xs[cache[tid].t].delayed_nu_fission[cache[tid].p][cache[tid].a][gin][*dg]; + val = xs[cache[tid].t].delayed_nu_fission[cache[tid].a][gin][*dg]; } else { val = 0.; - for (auto& num : xs[cache[tid].t].delayed_nu_fission[cache[tid].p] + for (auto& num : xs[cache[tid].t].delayed_nu_fission [cache[tid].a][gin]) { val += num; } @@ -477,21 +471,14 @@ Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, val = 0.; } break; - case MG_GET_XS_NU_FISSION: - if (fissionable) { - val = xs[cache[tid].t].nu_fission[cache[tid].p][cache[tid].a][gin]; - } else { - val = 0.; - } - break; case MG_GET_XS_CHI_PROMPT: if (fissionable) { if (gout != nullptr) { - val = xs[cache[tid].t].chi_prompt[cache[tid].p][cache[tid].a][gin][*gout]; + val = xs[cache[tid].t].chi_prompt[cache[tid].a][gin][*gout]; } else { // provide an outgoing group-wise sum val = 0.; - for (auto& num : xs[cache[tid].t].chi_prompt[cache[tid].p][cache[tid].a][gin]) { + for (auto& num : xs[cache[tid].t].chi_prompt[cache[tid].a][gin]) { val += num; } } @@ -503,22 +490,22 @@ Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, if (fissionable) { if (gout != nullptr) { if (dg != nullptr) { - val = xs[cache[tid].t].chi_delayed[cache[tid].p][cache[tid].a][gin][*gout][*dg]; + val = xs[cache[tid].t].chi_delayed[cache[tid].a][gin][*gout][*dg]; } else { - val = xs[cache[tid].t].chi_delayed[cache[tid].p][cache[tid].a][gin][*gout][0]; + val = xs[cache[tid].t].chi_delayed[cache[tid].a][gin][*gout][0]; } } else { if (dg != nullptr) { val = 0.; - for (int i = 0; i < xs[cache[tid].t].chi_delayed[cache[tid].p] + for (int i = 0; i < xs[cache[tid].t].chi_delayed [cache[tid].a][gin].size(); i++) { - val += xs[cache[tid].t].chi_delayed[cache[tid].p][cache[tid].a][gin][i][*dg]; + val += xs[cache[tid].t].chi_delayed[cache[tid].a][gin][i][*dg]; } } else { val = 0.; - for (int i = 0; i < xs[cache[tid].t].chi_delayed[cache[tid].p] + for (int i = 0; i < xs[cache[tid].t].chi_delayed [cache[tid].a][gin].size(); i++) { - for (auto& num : xs[cache[tid].t].chi_delayed[cache[tid].p] + for (auto& num : xs[cache[tid].t].chi_delayed [cache[tid].a][gin][i]) { val += num; } @@ -529,6 +516,16 @@ Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, val = 0.; } break; + case MG_GET_XS_INVERSE_VELOCITY: + val = xs[cache[tid].t].inverse_velocity[cache[tid].a][gin]; + break; + case MG_GET_XS_DECAY_RATE: + if (dg != nullptr) { + val = xs[cache[tid].t].decay_rate[cache[tid].a][*dg + 1]; + } else { + val = xs[cache[tid].t].decay_rate[cache[tid].a][0]; + } + break; default: val = 0.; } @@ -541,11 +538,11 @@ void Mgxs::sample_fission_energy(const int tid, const int gin, int& dg, int& gout) { // This method assumes that the temperature and angle indices are set - double nu_fission = xs[cache[tid].t].nu_fission[cache[tid].p][cache[tid].a][gin]; + double nu_fission = xs[cache[tid].t].nu_fission[cache[tid].a][gin]; // Find the probability of having a prompt neutron double prob_prompt = - xs[cache[tid].t].prompt_nu_fission[cache[tid].p][cache[tid].a][gin]; + xs[cache[tid].t].prompt_nu_fission[cache[tid].a][gin]; // sample random numbers double xi_pd = prn() * nu_fission; @@ -561,10 +558,10 @@ Mgxs::sample_fission_energy(const int tid, const int gin, int& dg, int& gout) // sample the outgoing energy group gout = 0; double prob_gout = - xs[cache[tid].t].chi_prompt[cache[tid].p][cache[tid].a][gin][gout]; + xs[cache[tid].t].chi_prompt[cache[tid].a][gin][gout]; while (prob_gout < xi_gout) { gout++; - prob_gout += xs[cache[tid].t].chi_prompt[cache[tid].p][cache[tid].a][gin][gout]; + prob_gout += xs[cache[tid].t].chi_prompt[cache[tid].a][gin][gout]; } } else { @@ -575,7 +572,7 @@ Mgxs::sample_fission_energy(const int tid, const int gin, int& dg, int& gout) while (xi_pd >= prob_prompt) { dg++; prob_prompt += - xs[cache[tid].t].delayed_nu_fission[cache[tid].p][cache[tid].a][gin][dg]; + xs[cache[tid].t].delayed_nu_fission[cache[tid].a][gin][dg]; } // adjust dg in case of round-off error @@ -584,11 +581,11 @@ Mgxs::sample_fission_energy(const int tid, const int gin, int& dg, int& gout) // sample the outgoing energy group gout = 0; double prob_gout = - xs[cache[tid].t].chi_delayed[cache[tid].p][cache[tid].a][gin][gout][dg]; + xs[cache[tid].t].chi_delayed[cache[tid].a][gin][gout][dg]; while (prob_gout < xi_gout) { gout++; prob_gout += - xs[cache[tid].t].chi_delayed[cache[tid].p][cache[tid].a][gin][gout][dg]; + xs[cache[tid].t].chi_delayed[cache[tid].a][gin][gout][dg]; } } } @@ -601,7 +598,7 @@ Mgxs::sample_scatter(const int tid, const int gin, int& gout, double& mu, { // This method assumes that the temperature and angle indices are set // Sample the data - xs[cache[tid].t].scatter[cache[tid].p][cache[tid].a]->sample(gin, gout, mu, wgt); + xs[cache[tid].t].scatter[cache[tid].a]->sample(gin, gout, mu, wgt); } //============================================================================== @@ -613,11 +610,11 @@ Mgxs::calculate_xs(const int tid, const int gin, const double sqrtkT, // Set our indices set_temperature_index(tid, sqrtkT); set_angle_index(tid, uvw); - total_xs = xs[cache[tid].t].total[cache[tid].p][cache[tid].a][gin]; - abs_xs = xs[cache[tid].t].absorption[cache[tid].p][cache[tid].a][gin]; + total_xs = xs[cache[tid].t].total[cache[tid].a][gin]; + abs_xs = xs[cache[tid].t].absorption[cache[tid].a][gin]; if (fissionable) { - nu_fiss_xs = xs[cache[tid].t].nu_fission[cache[tid].p][cache[tid].a][gin]; + nu_fiss_xs = xs[cache[tid].t].nu_fission[cache[tid].a][gin]; } else { nu_fiss_xs = 0.; } @@ -670,22 +667,25 @@ void Mgxs::set_angle_index(const int tid, const double uvw[3]) { // See if we need to find the new index - if ((uvw[0] != cache[tid].uvw[0]) || (uvw[1] != cache[tid].uvw[1]) || - (uvw[2] != cache[tid].uvw[2])) { + if (!is_isotropic && + ((uvw[0] != cache[tid].u) || (uvw[1] != cache[tid].v) || + (uvw[2] != cache[tid].w))) { // convert uvw to polar and azimuthal angles double my_pol = std::acos(uvw[2]); double my_azi = std::atan2(uvw[1], uvw[0]); // Find the location, assuming equal-bin angles double delta_angle = PI / n_pol; - cache[tid].p = std::floor(my_pol / delta_angle); + int p = std::floor(my_pol / delta_angle); delta_angle = 2. * PI / n_azi; - cache[tid].a = std::floor((my_azi + PI) / delta_angle); + int a = std::floor((my_azi + PI) / delta_angle); + + cache[tid].a = n_azi * p + a; // store this direction as the last one used - cache[tid].uvw[0] = uvw[0]; - cache[tid].uvw[1] = uvw[1]; - cache[tid].uvw[2] = uvw[2]; + cache[tid].u = uvw[0]; + cache[tid].v = uvw[1]; + cache[tid].w = uvw[2]; } } diff --git a/src/mgxs.h b/src/mgxs.h index d7b9a814a4..2a79bfe2a8 100644 --- a/src/mgxs.h +++ b/src/mgxs.h @@ -29,9 +29,11 @@ namespace openmc { struct CacheData { double sqrtkT; // last temperature corresponding to t int t; // temperature index - int p; // polar angle index - int a; // azimuthal angle index - double uvw[3]; // last angle that corresponds to p and a + int a; // angle index + // last angle that corresponds to p and a + double u; + double v; + double w; }; //============================================================================== @@ -45,6 +47,8 @@ class Mgxs { int num_delayed_groups; // number of delayed neutron groups int num_groups; // number of energy groups std::vector xs; // Cross section data + // MGXS Incoming Flux Angular grid information + bool is_isotropic; // used to skip search for angle indices if isotropic int n_pol; int n_azi; double_1dvec polar; @@ -52,7 +56,7 @@ class Mgxs { void _metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, const int in_num_delayed_groups, double_1dvec& temperature, int& method, const double tolerance, int_1dvec& temps_to_read, - int& order_dim, bool& is_isotropic, const int n_threads); + int& order_dim, const int n_threads); bool equiv(const Mgxs& that); public: diff --git a/src/scattdata.cpp b/src/scattdata.cpp index c0515f1ba2..e321bc2759 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -876,9 +876,9 @@ convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, { // See if the user wants us to figure out how many points to use if (n_mu == C_NONE) { - // then we will use 2 pts if its P0 or P1 (super fast), or the default if - // a higher order - if (leg.get_order() <= 1) { + // then we will use 2 pts if its P0, or the default if a higher order + // TODO use an error minimization algorithm that also picks n_mu + if (leg.get_order() == 0) { n_mu = 2; } else { n_mu = DEFAULT_NMU; diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 991e2a9010..05e6ab01bb 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -10,59 +10,49 @@ XsData::XsData(const int energy_groups, const int num_delayed_groups, const bool fissionable, const int scatter_format, const int n_pol, const int n_azi) { + int n_ang = n_pol * n_azi; + // check to make sure scatter format is OK before we allocate if (scatter_format != ANGLE_HISTOGRAM && scatter_format != ANGLE_TABULAR && scatter_format != ANGLE_LEGENDRE) { fatal_error("Invalid scatter_format!"); } // allocate all [temperature][phi][theta][in group] quantities - total = double_3dvec(n_pol, double_2dvec(n_azi, - double_1dvec(energy_groups, 0.))); - absorption = double_3dvec(n_pol, double_2dvec(n_azi, - double_1dvec(energy_groups, 0.))); - inverse_velocity = double_3dvec(n_pol, - double_2dvec(n_azi, double_1dvec(energy_groups, 0.))); + total = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); + absorption = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); + inverse_velocity = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); if (fissionable) { - fission = double_3dvec(n_pol, double_2dvec(n_azi, - double_1dvec(energy_groups, 0.))); - nu_fission = double_3dvec(n_pol, double_2dvec(n_azi, - double_1dvec(energy_groups, 0.))); - prompt_nu_fission = double_3dvec(n_pol, double_2dvec(n_azi, - double_1dvec(energy_groups, 0.))); - kappa_fission = double_3dvec(n_pol, double_2dvec(n_azi, - double_1dvec(energy_groups, 0.))); + fission = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); + nu_fission = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); + prompt_nu_fission = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); + kappa_fission = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); } // allocate decay_rate; [temperature][phi][theta][delayed group] - decay_rate = double_3dvec(n_pol, double_2dvec(n_azi, - double_1dvec(num_delayed_groups, 0.))); + decay_rate = double_2dvec(n_ang, double_1dvec(num_delayed_groups, 0.)); if (fissionable) { // allocate delayed_nu_fission; [temperature][phi][theta][in group][delay group] - delayed_nu_fission = double_4dvec(n_pol, double_3dvec(n_azi, - double_2dvec(energy_groups, double_1dvec(num_delayed_groups, 0.)))); + delayed_nu_fission = double_3dvec(n_ang, double_2dvec(energy_groups, + double_1dvec(num_delayed_groups, 0.))); // chi_prompt; [temperature][phi][theta][in group][delayed group] - chi_prompt = double_4dvec(n_pol, double_3dvec(n_azi, - double_2dvec(energy_groups, double_1dvec(energy_groups, 0.)))); + chi_prompt = double_3dvec(n_ang, double_2dvec(energy_groups, + double_1dvec(energy_groups, 0.))); // chi_delayed; [temperature][phi][theta][in group][out group][delay group] - chi_delayed = double_5dvec(n_pol, double_4dvec(n_azi, - double_3dvec(energy_groups, double_2dvec(energy_groups, - double_1dvec(num_delayed_groups, 0.))))); + chi_delayed = double_4dvec(n_ang, double_3dvec(energy_groups, + double_2dvec(energy_groups, double_1dvec(num_delayed_groups, 0.)))); } - scatter.resize(n_pol); - for (int p = 0; p < n_pol; p++) { - scatter[p].resize(n_azi); - for (int a = 0; a < n_azi; a++) { - if (scatter_format == ANGLE_HISTOGRAM) { - scatter[p][a] = new ScattDataHistogram; - } else if (scatter_format == ANGLE_TABULAR) { - scatter[p][a] = new ScattDataTabular; - } else if (scatter_format == ANGLE_LEGENDRE) { - scatter[p][a] = new ScattDataLegendre; - } + scatter.resize(n_ang); + for (int a = 0; a < n_ang; a++) { + if (scatter_format == ANGLE_HISTOGRAM) { + scatter[a] = new ScattDataHistogram; + } else if (scatter_format == ANGLE_TABULAR) { + scatter[a] = new ScattDataTabular; + } else if (scatter_format == ANGLE_LEGENDRE) { + scatter[a] = new ScattDataLegendre; } } } @@ -73,13 +63,13 @@ void XsData::from_hdf5(const hid_t xsdata_grp, const bool fissionable, const int scatter_format, const int final_scatter_format, const int order_data, const int max_order, - const int legendre_to_tabular_points, const bool is_isotropic) + const int legendre_to_tabular_points, const bool is_isotropic, + const int n_pol, const int n_azi) { // Reconstruct the dimension information so it doesn't need to be passed - int n_pol = total.size(); - int n_azi = total[0].size(); - int energy_groups = total[0][0].size(); - int delayed_groups = decay_rate[0][0].size(); + int n_ang = n_pol * n_azi; + int energy_groups = total[0].size(); + int delayed_groups = decay_rate[0].size(); // Set the fissionable-specific data if (fissionable) { @@ -98,11 +88,9 @@ XsData::from_hdf5(const hid_t xsdata_grp, const bool fissionable, // Check absorption to ensure it is not 0 since it is often the // denominator in tally methods - for (int p = 0; p < n_pol; p++) { - for (int a = 0; a < n_azi; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - if (absorption[p][a][gin] == 0.) absorption[p][a][gin] = 1.e-10; - } + for (int a = 0; a < n_ang; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + if (absorption[a][gin] == 0.) absorption[a][gin] = 1.e-10; } } @@ -110,23 +98,17 @@ XsData::from_hdf5(const hid_t xsdata_grp, const bool fissionable, if (object_exists(xsdata_grp, "total")) { read_nd_vector(xsdata_grp, "total", total); } else { - for (int p = 0; p < n_pol; p++) { - for (int a = 0; a < n_azi; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - total[p][a][gin] = absorption[p][a][gin] + - scatter[p][a]->scattxs[gin]; - } + for (int a = 0; a < n_ang; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + total[a][gin] = absorption[a][gin] + scatter[a]->scattxs[gin]; } } } - // Check total to ensure it is not 0 since it is often the denominator in - // tally methods - for (int p = 0; p < n_pol; p++) { - for (int a = 0; a < n_azi; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - if (total[p][a][gin] == 0.) total[p][a][gin] = 1.e-10; - } + // Fix if total is 0, since it is in the denominator when tallying + for (int a = 0; a < n_ang; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + if (total[a][gin] == 0.) total[a][gin] = 1.e-10; } } } @@ -138,15 +120,14 @@ XsData::_fissionable_from_hdf5(const hid_t xsdata_grp, const int n_pol, const int n_azi, const int energy_groups, const int delayed_groups, const bool is_isotropic) { - + int n_ang = n_pol * n_azi; // Get the fission and kappa_fission data xs; these are optional read_nd_vector(xsdata_grp, "fission", fission); read_nd_vector(xsdata_grp, "kappa-fission", kappa_fission); // Set/get beta - double_4dvec temp_beta = - double_4dvec(n_pol, double_3dvec(n_azi, - double_2dvec(energy_groups, double_1dvec(delayed_groups, 0.)))); + double_3dvec temp_beta =double_3dvec(n_ang, double_2dvec(energy_groups, + double_1dvec(delayed_groups, 0.))); if (object_exists(xsdata_grp, "beta")) { hid_t xsdata = open_dataset(xsdata_grp, "beta"); int ndims = dataset_ndims(xsdata); @@ -160,14 +141,12 @@ XsData::_fissionable_from_hdf5(const hid_t xsdata_grp, const int n_pol, // Broadcast to all incoming groups int temp_idx = 0; - for (int p = 0; p < n_pol; p++) { - for (int a = 0; a < n_azi; a++) { - for (int dg = 0; dg < delayed_groups; dg++) { - // Set the first group index and copy the rest - temp_beta[p][a][0][dg] = temp_arr[temp_idx++]; - for (int gin = 1; gin < energy_groups; gin++) { - temp_beta[p][a][gin] = temp_beta[p][a][0]; - } + for (int a = 0; a < n_ang; a++) { + for (int dg = 0; dg < delayed_groups; dg++) { + // Set the first group index and copy the rest + temp_beta[a][0][dg] = temp_arr[temp_idx++]; + for (int gin = 1; gin < energy_groups; gin++) { + temp_beta[a][gin] = temp_beta[a][0]; } } } @@ -181,41 +160,38 @@ XsData::_fissionable_from_hdf5(const hid_t xsdata_grp, const int n_pol, // If chi is provided, set chi-prompt and chi-delayed if (object_exists(xsdata_grp, "chi")) { - double_3dvec temp_arr = double_3dvec(n_pol, double_2dvec(n_azi, - double_1dvec(energy_groups))); + double_2dvec temp_arr = double_2dvec(n_ang, double_1dvec(energy_groups)); read_nd_vector(xsdata_grp, "chi", temp_arr); - for (int p = 0; p < n_pol; p++) { - for (int a = 0; a < n_azi; a++) { - // First set the first group + for (int a = 0; a < n_ang; a++) { + // First set the first group + for (int gout = 0; gout < energy_groups; gout++) { + chi_prompt[a][0][gout] = temp_arr[a][gout]; + } + + // Now normalize this data + double chi_sum = std::accumulate(chi_prompt[a][0].begin(), + chi_prompt[a][0].end(), + 0.); + if (chi_sum <= 0.) { + fatal_error("Encountered chi for a group that is <= 0!"); + } + for (int gout = 0; gout < energy_groups; gout++) { + chi_prompt[a][0][gout] /= chi_sum; + } + + // And extend to the remaining incoming groups + for (int gin = 1; gin < energy_groups; gin++) { + chi_prompt[a][gin] = chi_prompt[a][0]; + } + + // Finally set chi-delayed equal to chi-prompt + // Set chi-delayed to chi-prompt + for(int gin = 0; gin < energy_groups; gin++) { for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[p][a][0][gout] = temp_arr[p][a][gout]; - } - - // Now normalize this data - double chi_sum = std::accumulate(chi_prompt[p][a][0].begin(), - chi_prompt[p][a][0].end(), - 0.); - if (chi_sum <= 0.) { - fatal_error("Encountered chi for a group that is <= 0!"); - } - for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[p][a][0][gout] /= chi_sum; - } - - // And extend to the remaining incoming groups - for (int gin = 1; gin < energy_groups; gin++) { - chi_prompt[p][a][gin] = chi_prompt[p][a][0]; - } - - // Finally set chi-delayed equal to chi-prompt - // Set chi-delayed to chi-prompt - for(int gin = 0; gin < energy_groups; gin++) { - for (int gout = 0; gout < energy_groups; gout++) { - for (int dg = 0; dg < delayed_groups; dg++) { - chi_delayed[p][a][gin][gout][dg] = - chi_prompt[p][a][gin][gout]; - } + for (int dg = 0; dg < delayed_groups; dg++) { + chi_delayed[a][gin][gout][dg] = + chi_prompt[a][gin][gout]; } } } @@ -234,21 +210,18 @@ XsData::_fissionable_from_hdf5(const hid_t xsdata_grp, const int n_pol, read_nd_vector(xsdata_grp, "nu-fission", prompt_nu_fission); // set delayed-nu-fission and correct prompt-nu-fission with beta - for (int p = 0; p < n_pol; p++) { - for (int a = 0; a < n_azi; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - for (int dg = 0; dg < delayed_groups; dg++) { - delayed_nu_fission[p][a][gin][dg] = - temp_beta[p][a][gin][dg] * - prompt_nu_fission[p][a][gin]; - } + for (int a = 0; a < n_ang; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + for (int dg = 0; dg < delayed_groups; dg++) { + delayed_nu_fission[a][gin][dg] = + temp_beta[a][gin][dg] * prompt_nu_fission[a][gin]; + } - // Correct the prompt-nu-fission using the delayed neutron fraction - if (delayed_groups > 0) { - double beta_sum = std::accumulate(temp_beta[p][a][gin].begin(), - temp_beta[p][a][gin].end(), 0.); - prompt_nu_fission[p][a][gin] *= (1. - beta_sum); - } + // Correct the prompt-nu-fission using the delayed neutron fraction + if (delayed_groups > 0) { + double beta_sum = std::accumulate(temp_beta[a][gin].begin(), + temp_beta[a][gin].end(), 0.); + prompt_nu_fission[a][gin] *= (1. - beta_sum); } } } @@ -258,47 +231,45 @@ XsData::_fissionable_from_hdf5(const hid_t xsdata_grp, const int n_pol, read_nd_vector(xsdata_grp, "nu-fission", chi_prompt); // Normalize the chi info so the CDF is 1. - for (int p = 0; p < n_pol; p++) { - for (int a = 0; a < n_azi; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - double chi_sum = std::accumulate(chi_prompt[p][a][gin].begin(), - chi_prompt[p][a][gin].end(), 0.); - // Set the vector nu-fission from the matrix nu-fission - prompt_nu_fission[p][a][gin] = chi_sum; + for (int a = 0; a < n_ang; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + double chi_sum = std::accumulate(chi_prompt[a][gin].begin(), + chi_prompt[a][gin].end(), 0.); + // Set the vector nu-fission from the matrix nu-fission + prompt_nu_fission[a][gin] = chi_sum; - if (chi_sum >= 0.) { - for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[p][a][gin][gout] /= chi_sum; - } - } else { - fatal_error("Encountered chi for a group that is <= 0!"); - } - } - - // set chi-delayed to chi-prompt - for (int gin = 0; gin < energy_groups; gin++) { + if (chi_sum >= 0.) { for (int gout = 0; gout < energy_groups; gout++) { - for (int dg = 0; dg < delayed_groups; dg++) { - chi_delayed[p][a][gin][gout][dg] = - chi_prompt[p][a][gin][gout]; - } + chi_prompt[a][gin][gout] /= chi_sum; + } + } else { + fatal_error("Encountered chi for a group that is <= 0!"); + } + } + + // set chi-delayed to chi-prompt + for (int gin = 0; gin < energy_groups; gin++) { + for (int gout = 0; gout < energy_groups; gout++) { + for (int dg = 0; dg < delayed_groups; dg++) { + chi_delayed[a][gin][gout][dg] = + chi_prompt[a][gin][gout]; } } + } - // Set the delayed-nu-fission and correct prompt-nu-fission with beta - for (int gin = 0; gin < energy_groups; gin++) { - for (int dg = 0; dg < delayed_groups; dg++) { - delayed_nu_fission[p][a][gin][dg] = - temp_beta[p][a][gin][dg] * - prompt_nu_fission[p][a][gin]; - } + // Set the delayed-nu-fission and correct prompt-nu-fission with beta + for (int gin = 0; gin < energy_groups; gin++) { + for (int dg = 0; dg < delayed_groups; dg++) { + delayed_nu_fission[a][gin][dg] = + temp_beta[a][gin][dg] * + prompt_nu_fission[a][gin]; + } - // Correct prompt-nu-fission using the delayed neutron fraction - if (delayed_groups > 0) { - double beta_sum = std::accumulate(temp_beta[p][a][gin].begin(), - temp_beta[p][a][gin].end(), 0.); - prompt_nu_fission[p][a][gin] *= (1. - beta_sum); - } + // Correct prompt-nu-fission using the delayed neutron fraction + if (delayed_groups > 0) { + double beta_sum = std::accumulate(temp_beta[a][gin].begin(), + temp_beta[a][gin].end(), 0.); + prompt_nu_fission[a][gin] *= (1. - beta_sum); } } } @@ -311,27 +282,24 @@ XsData::_fissionable_from_hdf5(const hid_t xsdata_grp, const int n_pol, // If chi-prompt is provided, set chi-prompt if (object_exists(xsdata_grp, "chi-prompt")) { - double_3dvec temp_arr = double_3dvec(n_pol, double_2dvec(n_azi, - double_1dvec(energy_groups))); + double_2dvec temp_arr = double_2dvec(n_ang, double_1dvec(energy_groups)); read_nd_vector(xsdata_grp, "chi-prompt", temp_arr); - for (int a = 0; a < n_azi; a++) { - for (int p = 0; p < n_pol; p++) { - for (int gin = 0; gin < energy_groups; gin++) { - for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[p][a][gin][gout] = temp_arr[p][a][gout]; - } + for (int a = 0; a < n_ang; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + for (int gout = 0; gout < energy_groups; gout++) { + chi_prompt[a][gin][gout] = temp_arr[a][gout]; + } - // Normalize chi so its CDF goes to 1 - double chi_sum = std::accumulate(chi_prompt[p][a][gin].begin(), - chi_prompt[p][a][gin].end(), 0.); - if (chi_sum >= 0.) { - for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[p][a][gin][gout] /= chi_sum; - } - } else { - fatal_error("Encountered chi-prompt for a group that is <= 0.!"); + // Normalize chi so its CDF goes to 1 + double chi_sum = std::accumulate(chi_prompt[a][gin].begin(), + chi_prompt[a][gin].end(), 0.); + if (chi_sum >= 0.) { + for (int gout = 0; gout < energy_groups; gout++) { + chi_prompt[a][gin][gout] /= chi_sum; } + } else { + fatal_error("Encountered chi-prompt for a group that is <= 0.!"); } } } @@ -346,26 +314,22 @@ XsData::_fissionable_from_hdf5(const hid_t xsdata_grp, const int n_pol, if (ndims == 3) { // chi-delayed is a [in group] vector - double_3dvec temp_arr = double_3dvec(n_pol, double_2dvec(n_azi, - double_1dvec(energy_groups))); + double_2dvec temp_arr = double_2dvec(n_ang, double_1dvec(energy_groups)); read_nd_vector(xsdata_grp, "chi-delayed", temp_arr); - for (int a = 0; a < n_azi; a++) { - for (int p = 0; p < n_pol; p++) { - // normalize the chi CDF to 1 - double chi_sum = std::accumulate(temp_arr[p][a].begin(), - temp_arr[p][a].end(), 0.); - if (chi_sum <= 0.) { - fatal_error("Encountered chi-delayed for a group that is <= 0!"); - } + for (int a = 0; a < n_ang; a++) { + // normalize the chi CDF to 1 + double chi_sum = std::accumulate(temp_arr[a].begin(), + temp_arr[a].end(), 0.); + if (chi_sum <= 0.) { + fatal_error("Encountered chi-delayed for a group that is <= 0!"); + } - // set chi-delayed - for (int gin = 0; gin < energy_groups; gin++) { - for (int gout = 0; gout < energy_groups; gout++) { - for (int dg = 0; dg < delayed_groups; dg++) { - chi_delayed[p][a][gin][gout][dg] = - temp_arr[p][a][gout] / chi_sum; - } + // set chi-delayed + for (int gin = 0; gin < energy_groups; gin++) { + for (int gout = 0; gout < energy_groups; gout++) { + for (int dg = 0; dg < delayed_groups; dg++) { + chi_delayed[a][gin][gout][dg] = temp_arr[a][gout] / chi_sum; } } } @@ -375,22 +339,20 @@ XsData::_fissionable_from_hdf5(const hid_t xsdata_grp, const int n_pol, read_nd_vector(xsdata_grp, "chi-delayed", chi_delayed); // Normalize the chi info so the CDF is 1. - for (int a = 0; a < n_azi; a++) { - for (int p = 0; p < n_pol; p++) { - for (int dg = 0; dg < delayed_groups; dg++) { - for (int gin = 0; gin < energy_groups; gin++) { - double chi_sum = 0.; - for (int gout = 0; gout < energy_groups; gout++) { - chi_sum += chi_delayed[p][a][gin][gout][dg]; - } + for (int a = 0; a < n_ang; a++) { + for (int dg = 0; dg < delayed_groups; dg++) { + for (int gin = 0; gin < energy_groups; gin++) { + double chi_sum = 0.; + for (int gout = 0; gout < energy_groups; gout++) { + chi_sum += chi_delayed[a][gin][gout][dg]; + } - if (chi_sum > 0.) { - for (int gout = 0; gout < energy_groups; gout++) { - chi_delayed[p][a][gin][gout][dg] /= chi_sum; - } - } else { - fatal_error("Encountered chi-delayed for a group that is <= 0!"); + if (chi_sum > 0.) { + for (int gout = 0; gout < energy_groups; gout++) { + chi_delayed[a][gin][gout][dg] /= chi_sum; } + } else { + fatal_error("Encountered chi-delayed for a group that is <= 0!"); } } } @@ -414,30 +376,27 @@ XsData::_fissionable_from_hdf5(const hid_t xsdata_grp, const int n_pol, } else if (ndims == 4) { // prompt nu fission is a matrix, // so set prompt_nu_fiss & chi_prompt - double_4dvec temp_arr = double_4dvec(n_pol, double_3dvec(n_azi, - double_2dvec(energy_groups, double_1dvec(energy_groups)))); + double_3dvec temp_arr = double_3dvec(n_ang, double_2dvec(energy_groups, + double_1dvec(energy_groups))); read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_arr); // The prompt_nu_fission vector from the matrix form - for (int a = 0; a < n_azi; a++) { - for (int p = 0; p < n_pol; p++) { - for (int gin = 0; gin < energy_groups; gin++) { - double prompt_sum = std::accumulate(temp_arr[p][a][gin].begin(), - temp_arr[p][a][gin].end(), 0.); - prompt_nu_fission[p][a][gin] = prompt_sum; - } + for (int a = 0; a < n_ang; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + double prompt_sum = std::accumulate(temp_arr[a][gin].begin(), + temp_arr[a][gin].end(), 0.); + prompt_nu_fission[a][gin] = prompt_sum; + } - // The chi_prompt data is just the normalized fission matrix - for (int gin= 0; gin < energy_groups; gin++) { - if (prompt_nu_fission[p][a][gin] > 0.) { - for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[p][a][gin][gout] = - temp_arr[p][a][gin][gout] / - prompt_nu_fission[p][a][gin]; - } - } else { - fatal_error("Encountered chi-prompt for a group that is <= 0!"); + // The chi_prompt data is just the normalized fission matrix + for (int gin= 0; gin < energy_groups; gin++) { + if (prompt_nu_fission[a][gin] > 0.) { + for (int gout = 0; gout < energy_groups; gout++) { + chi_prompt[a][gin][gout] = + temp_arr[a][gin][gout] / prompt_nu_fission[a][gin]; } + } else { + fatal_error("Encountered chi-prompt for a group that is <= 0!"); } } } @@ -455,23 +414,20 @@ XsData::_fissionable_from_hdf5(const hid_t xsdata_grp, const int n_pol, if (is_isotropic) ndims += 2; if (ndims == 3) { - // delayed-nu-fission is a [in group] vector - if (temp_beta[0][0][0][0] == 0.) { + // delayed-nu-fission is an [in group] vector + if (temp_beta[0][0][0] == 0.) { fatal_error("cannot set delayed-nu-fission with a 1D array if " "beta is not provided"); } - double_3dvec temp_arr = double_3dvec(n_pol, double_2dvec(n_azi, - double_1dvec(energy_groups))); + double_2dvec temp_arr = double_2dvec(n_ang, double_1dvec(energy_groups)); read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); - for (int p = 0; p < n_pol; p++) { - for (int a = 0; a < n_azi; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - for (int dg = 0; dg < delayed_groups; dg++) { - // Set delayed-nu-fission using beta - delayed_nu_fission[p][a][gin][dg] = - temp_beta[p][a][gin][dg] * temp_arr[p][a][gin]; - } + for (int a = 0; a < n_ang; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + for (int dg = 0; dg < delayed_groups; dg++) { + // Set delayed-nu-fission using beta + delayed_nu_fission[a][gin][dg] = + temp_beta[a][gin][dg] * temp_arr[a][gin]; } } } @@ -482,32 +438,28 @@ XsData::_fissionable_from_hdf5(const hid_t xsdata_grp, const int n_pol, } else if (ndims == 5) { // This will contain delayed-nu-fision and chi-delayed data - double_5dvec temp_arr = double_5dvec(n_pol, double_4dvec(n_azi, - double_3dvec(energy_groups, double_2dvec(energy_groups, - double_1dvec(delayed_groups))))); + double_4dvec temp_arr = double_4dvec(n_ang, double_3dvec(energy_groups, + double_2dvec(energy_groups, double_1dvec(delayed_groups)))); read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); - // Set the 4D delayed-nu-fission matrix and 5D chi-delayed matrix - // from the 5D delayed-nu-fission matrix - for (int p = 0; p < n_pol; p++) { - for (int a = 0; a < n_azi; a++) { - for (int dg = 0; dg < delayed_groups; dg++) { - for (int gin = 0; gin < energy_groups; gin++) { - double gout_sum = 0.; + // Set the 3D delayed-nu-fission matrix and 4D chi-delayed matrix + // from the 4D delayed-nu-fission matrix + for (int a = 0; a < n_ang; a++) { + for (int dg = 0; dg < delayed_groups; dg++) { + for (int gin = 0; gin < energy_groups; gin++) { + double gout_sum = 0.; + for (int gout = 0; gout < energy_groups; gout++) { + gout_sum += temp_arr[a][gin][gout][dg]; + chi_delayed[a][gin][gout][dg] = temp_arr[a][gin][gout][dg]; + } + delayed_nu_fission[a][gin][dg] = gout_sum; + // Normalize chi-delayed + if (gout_sum > 0.) { for (int gout = 0; gout < energy_groups; gout++) { - gout_sum += temp_arr[p][a][gin][gout][dg]; - chi_delayed[p][a][gin][gout][dg] = - temp_arr[p][a][gin][gout][dg]; - } - delayed_nu_fission[p][a][gin][dg] = gout_sum; - // Normalize chi-delayed - if (gout_sum > 0.) { - for (int gout = 0; gout < energy_groups; gout++) { - chi_delayed[p][a][gin][gout][dg] /= gout_sum; - } - } else { - fatal_error("Encountered chi-delayed for a group that is <= 0!"); + chi_delayed[a][gin][gout][dg] /= gout_sum; } + } else { + fatal_error("Encountered chi-delayed for a group that is <= 0!"); } } } @@ -520,14 +472,12 @@ XsData::_fissionable_from_hdf5(const hid_t xsdata_grp, const int n_pol, } // Combine prompt_nu_fission and delayed_nu_fission into nu_fission - for (int p = 0; p < n_pol; p++) { - for (int a = 0; a < n_azi; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - nu_fission[p][a][gin] = - std::accumulate(delayed_nu_fission[p][a][gin].begin(), - delayed_nu_fission[p][a][gin].end(), - prompt_nu_fission[p][a][gin]); - } + for (int a = 0; a < n_ang; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + nu_fission[a][gin] = + std::accumulate(delayed_nu_fission[a][gin].begin(), + delayed_nu_fission[a][gin].end(), + prompt_nu_fission[a][gin]); } } } @@ -540,37 +490,32 @@ XsData::_scatter_from_hdf5(const hid_t xsdata_grp, const int n_pol, const int final_scatter_format, const int order_data, const int max_order, const int legendre_to_tabular_points) { + int n_ang = n_pol * n_azi; if (!object_exists(xsdata_grp, "scatter_data")) { fatal_error("Must provide scatter_data group!"); } hid_t scatt_grp = open_group(xsdata_grp, "scatter_data"); // Get the outgoing group boundary indices - int_3dvec gmin = int_3dvec(n_pol, int_2dvec(n_azi, - int_1dvec(energy_groups))); + int_2dvec gmin = int_2dvec(n_ang, int_1dvec(energy_groups)); read_nd_vector(scatt_grp, "g_min", gmin, true); - int_3dvec gmax = int_3dvec(n_pol, int_2dvec(n_azi, - int_1dvec(energy_groups))); + int_2dvec gmax = int_2dvec(n_ang, int_1dvec(energy_groups)); read_nd_vector(scatt_grp, "g_max", gmax, true); // Make gmin and gmax start from 0 vice 1 as they do in the library - for (int p = 0; p < n_pol; p++) { - for (int a = 0; a < n_azi; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - gmin[p][a][gin] -= 1; - gmax[p][a][gin] -= 1; - } + for (int a = 0; a < n_ang; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + gmin[a][gin] -= 1; + gmax[a][gin] -= 1; } } // Now use this info to find the length of a vector to hold the flattened // data. int length = 0; - for (int p = 0; p < n_pol; p++) { - for (int a = 0; a < n_azi; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - length += order_data * (gmax[p][a][gin] - gmin[p][a][gin] + 1); - } + for (int a = 0; a < n_ang; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + length += order_data * (gmax[a][gin] - gmin[a][gin] + 1); } } double_1dvec temp_arr = double_1dvec(length); @@ -587,55 +532,48 @@ XsData::_scatter_from_hdf5(const hid_t xsdata_grp, const int n_pol, // convert the flattened temp_arr to a jagged array for passing to // scatt data - double_5dvec input_scatt = - double_5dvec(n_pol, double_4dvec(n_azi, double_3dvec(energy_groups))); + double_4dvec input_scatt = + double_4dvec(n_ang, double_3dvec(energy_groups)); int temp_idx = 0; - for (int p = 0; p < n_pol; p++) { - for (int a = 0; a < n_azi; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - input_scatt[p][a][gin].resize(gmax[p][a][gin] - gmin[p][a][gin] + 1); - for (int i_gout = 0; i_gout < input_scatt[p][a][gin].size(); i_gout++) { - input_scatt[p][a][gin][i_gout].resize(order_dim); - for (int l = 0; l < order_dim; l++) { - input_scatt[p][a][gin][i_gout][l] = temp_arr[temp_idx++]; - } - // Adjust index for the orders we didnt take - temp_idx += (order_data - order_dim); + for (int a = 0; a < n_ang; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + input_scatt[a][gin].resize(gmax[a][gin] - gmin[a][gin] + 1); + for (int i_gout = 0; i_gout < input_scatt[a][gin].size(); i_gout++) { + input_scatt[a][gin][i_gout].resize(order_dim); + for (int l = 0; l < order_dim; l++) { + input_scatt[a][gin][i_gout][l] = temp_arr[temp_idx++]; } + // Adjust index for the orders we didnt take + temp_idx += (order_data - order_dim); } } } temp_arr.clear(); // Get multiplication matrix - double_4dvec temp_mult = double_4dvec(n_pol, double_3dvec(n_azi, - double_2dvec(energy_groups))); + double_3dvec temp_mult = double_3dvec(n_ang, double_2dvec(energy_groups)); if (object_exists(scatt_grp, "multiplicity_matrix")) { temp_arr.resize(length / order_data); read_nd_vector(scatt_grp, "multiplicity_matrix", temp_arr); // convert the flat temp_arr to a jagged array for passing to scatt data int temp_idx = 0; - for (int p = 0; p < n_pol; p++) { - for (int a = 0; a < n_azi; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - temp_mult[p][a][gin].resize(gmax[p][a][gin] - gmin[p][a][gin] + 1); - for (int i_gout = 0; i_gout < temp_mult[p][a][gin].size(); i_gout++) { - temp_mult[p][a][gin][i_gout] = temp_arr[temp_idx++]; - } + for (int a = 0; a < n_ang; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + temp_mult[a][gin].resize(gmax[a][gin] - gmin[a][gin] + 1); + for (int i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { + temp_mult[a][gin][i_gout] = temp_arr[temp_idx++]; } } } } else { // Use a default: multiplicities are 1.0. - for (int p = 0; p < n_pol; p++) { - for (int a = 0; a < n_azi; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - temp_mult[p][a][gin].resize(gmax[p][a][gin] - gmin[p][a][gin] + 1); - for (int i_gout = 0; i_gout < temp_mult[p][a][gin].size(); i_gout++) { - temp_mult[p][a][gin][i_gout] = 1.; - } + for (int a = 0; a < n_ang; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + temp_mult[a][gin].resize(gmax[a][gin] - gmin[a][gin] + 1); + for (int i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { + temp_mult[a][gin][i_gout] = 1.; } } } @@ -646,28 +584,22 @@ XsData::_scatter_from_hdf5(const hid_t xsdata_grp, const int n_pol, // Finally, convert the Legendre data to tabular, if needed if (scatter_format == ANGLE_LEGENDRE && final_scatter_format == ANGLE_TABULAR) { - for (int p = 0; p < n_pol; p++) { - for (int a = 0; a < n_azi; a++) { - ScattDataLegendre legendre_scatt; - legendre_scatt.init(gmin[p][a], gmax[p][a], temp_mult[p][a], - input_scatt[p][a]); + for (int a = 0; a < n_ang; a++) { + ScattDataLegendre legendre_scatt; + legendre_scatt.init(gmin[a], gmax[a], temp_mult[a], input_scatt[a]); - // Now create a tabular version of legendre_scatt - convert_legendre_to_tabular(legendre_scatt, - *static_cast(scatter[p][a]), - legendre_to_tabular_points); + // Now create a tabular version of legendre_scatt + convert_legendre_to_tabular(legendre_scatt, + *static_cast(scatter[a]), + legendre_to_tabular_points); - scatter_format = final_scatter_format; - } + scatter_format = final_scatter_format; } } else { // We are sticking with the current representation // Initialize the ScattData object with this data - for (int p = 0; p < n_pol; p++) { - for (int a = 0; a < n_azi; a++) { - scatter[p][a]->init(gmin[p][a], gmax[p][a], temp_mult[p][a], - input_scatt[p][a]); - } + for (int a = 0; a < n_ang; a++) { + scatter[a]->init(gmin[a], gmax[a], temp_mult[a], input_scatt[a]); } } } @@ -675,7 +607,7 @@ XsData::_scatter_from_hdf5(const hid_t xsdata_grp, const int n_pol, //============================================================================== void -XsData::combine(const std::vector those_xs, +XsData::combine(const std::vector& those_xs, const double_1dvec& scalars) { // Combine the non-scattering data @@ -683,64 +615,60 @@ XsData::combine(const std::vector those_xs, XsData* that = those_xs[i]; if (!equiv(*that)) fatal_error("Cannot combine the XsData objects!"); double scalar = scalars[i]; - for (int p = 0; p < total.size(); p++) { - for (int a = 0; a < total[p].size(); a++) { - for (int gin = 0; gin < total[p][a].size(); gin++) { - total[p][a][gin] += scalar * that->total[p][a][gin]; - absorption[p][a][gin] += scalar * that->absorption[p][a][gin]; - inverse_velocity[p][a][gin] += - scalar * that->inverse_velocity[p][a][gin]; - if (that->prompt_nu_fission.size() > 0) { - nu_fission[p][a][gin] += - scalar * that->nu_fission[p][a][gin]; - prompt_nu_fission[p][a][gin] += - scalar * that->prompt_nu_fission[p][a][gin]; - kappa_fission[p][a][gin] += - scalar * that->kappa_fission[p][a][gin]; - fission[p][a][gin] += - scalar * that->fission[p][a][gin]; + for (int a = 0; a < total.size(); a++) { + for (int gin = 0; gin < total[a].size(); gin++) { + total[a][gin] += scalar * that->total[a][gin]; + absorption[a][gin] += scalar * that->absorption[a][gin]; + if (i == 0) { + inverse_velocity[a][gin] = that->inverse_velocity[a][gin]; + } + if (that->prompt_nu_fission.size() > 0) { + nu_fission[a][gin] += scalar * that->nu_fission[a][gin]; + prompt_nu_fission[a][gin] += + scalar * that->prompt_nu_fission[a][gin]; + kappa_fission[a][gin] += scalar * that->kappa_fission[a][gin]; + fission[a][gin] += scalar * that->fission[a][gin]; - for (int dg = 0; dg < delayed_nu_fission[p][a][gin].size(); dg++) { - delayed_nu_fission[p][a][gin][dg] += - scalar * that->delayed_nu_fission[p][a][gin][dg]; - } + for (int dg = 0; dg < delayed_nu_fission[a][gin].size(); dg++) { + delayed_nu_fission[a][gin][dg] += + scalar * that->delayed_nu_fission[a][gin][dg]; + } - for (int gout = 0; gout < chi_prompt[p][a][gin].size(); gout++) { - chi_prompt[p][a][gin][gout] += - scalar * that->chi_prompt[p][a][gin][gout]; + for (int gout = 0; gout < chi_prompt[a][gin].size(); gout++) { + chi_prompt[a][gin][gout] += + scalar * that->chi_prompt[a][gin][gout]; - for (int dg = 0; dg < chi_delayed[p][a][gin][gout].size(); dg++) { - chi_delayed[p][a][gin][gout][dg] += - scalar * that->chi_delayed[p][a][gin][gout][dg]; - } + for (int dg = 0; dg < chi_delayed[a][gin][gout].size(); dg++) { + chi_delayed[a][gin][gout][dg] += + scalar * that->chi_delayed[a][gin][gout][dg]; } } } + } - for (int dg = 0; dg < decay_rate[p][a].size(); dg++) { - decay_rate[p][a][dg] += scalar * that->decay_rate[p][a][dg]; - } + for (int dg = 0; dg < decay_rate[a].size(); dg++) { + decay_rate[a][dg] += scalar * that->decay_rate[a][dg]; + } - // Normalize chi - if (chi_prompt.size() > 0) { - for (int gin = 0; gin < chi_prompt[p][a].size(); gin++) { - double norm = std::accumulate(chi_prompt[p][a][gin].begin(), - chi_prompt[p][a][gin].end(), 0.); - if (norm > 0.) { - for (int gout = 0; gout < chi_prompt[p][a][gin].size(); gout++) { - chi_prompt[p][a][gin][gout] /= norm; - } + // Normalize chi + if (chi_prompt.size() > 0) { + for (int gin = 0; gin < chi_prompt[a].size(); gin++) { + double norm = std::accumulate(chi_prompt[a][gin].begin(), + chi_prompt[a][gin].end(), 0.); + if (norm > 0.) { + for (int gout = 0; gout < chi_prompt[a][gin].size(); gout++) { + chi_prompt[a][gin][gout] /= norm; } + } - for (int dg = 0; dg < chi_delayed[p][a][gin][0].size(); dg++) { - norm = 0.; - for (int gout = 0; gout < chi_delayed[p][a][gin].size(); gout++) { - norm += chi_delayed[p][a][gin][gout][dg]; - } - if (norm > 0.) { - for (int gout = 0; gout < chi_delayed[p][a][gin].size(); gout++) { - chi_delayed[p][a][gin][gout][dg] /= norm; - } + for (int dg = 0; dg < chi_delayed[a][gin][0].size(); dg++) { + norm = 0.; + for (int gout = 0; gout < chi_delayed[a][gin].size(); gout++) { + norm += chi_delayed[a][gin][gout][dg]; + } + if (norm > 0.) { + for (int gout = 0; gout < chi_delayed[a][gin].size(); gout++) { + chi_delayed[a][gin][gout][dg] /= norm; } } } @@ -750,17 +678,15 @@ XsData::combine(const std::vector those_xs, } // Allow the ScattData object to combine itself - for (int p = 0; p < total.size(); p++) { - for (int a = 0; a < total[p].size(); a++) { - // Build vector of the scattering objects to incorporate - std::vector those_scatts(those_xs.size()); - for (int i = 0; i < those_xs.size(); i++) { - those_scatts[i] = those_xs[i]->scatter[p][a]; - } - - // Now combine these guys - scatter[p][a]->combine(those_scatts, scalars); + for (int a = 0; a < total.size(); a++) { + // Build vector of the scattering objects to incorporate + std::vector those_scatts(those_xs.size()); + for (int i = 0; i < those_xs.size(); i++) { + those_scatts[i] = those_xs[i]->scatter[a]; } + + // Now combine these guys + scatter[a]->combine(those_scatts, scalars); } } @@ -770,12 +696,8 @@ bool XsData::equiv(const XsData& that) { bool match = false; - // check n_pol (total.size()), n_azi (total[0].size()), and - // groups (total[0][0].size()) - // This assumes correct initializatino of the remaining cross sections - if ((total.size() == that.total.size()) && - (total[0].size() == that.total[0].size()) && - (total[0][0].size() == that.total[0][0].size())) { + if ((absorption.size() == that.absorption.size()) && + (absorption[0].size() == that.absorption[0].size())) { match = true; } return match; diff --git a/src/xsdata.h b/src/xsdata.h index 4d3a5d5d40..dd18a8ce9b 100644 --- a/src/xsdata.h +++ b/src/xsdata.h @@ -28,32 +28,34 @@ class XsData { const int n_azi, const int energy_groups, int scatter_format, const int final_scatter_format, const int order_data, const int max_order, const int legendre_to_tabular_points); - void _fissionable_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, - int energy_groups, int delayed_groups, bool is_isotropic); + void _fissionable_from_hdf5(const hid_t xsdata_grp, const int n_pol, + const int n_azi, const int energy_groups, const int delayed_groups, + const bool is_isotropic); public: // The following quantities have the following dimensions: - // [phi][theta][incoming group] - double_3dvec total; - double_3dvec absorption; - double_3dvec nu_fission; - double_3dvec prompt_nu_fission; - double_3dvec kappa_fission; - double_3dvec fission; - double_3dvec inverse_velocity; + // [angle][incoming group] + double_2dvec total; + double_2dvec absorption; + double_2dvec nu_fission; + double_2dvec prompt_nu_fission; + double_2dvec kappa_fission; + double_2dvec fission; + double_2dvec inverse_velocity; + // decay_rate has the following dimensions: - // [phi][theta][delayed group] - double_3dvec decay_rate; + // [angle][delayed group] + double_2dvec decay_rate; // delayed_nu_fission has the following dimensions: - // [phi][theta][incoming group][delayed group] - double_4dvec delayed_nu_fission; + // [angle][incoming group][delayed group] + double_3dvec delayed_nu_fission; // chi_prompt has the following dimensions: - // [phi][theta][incoming group][outgoing group] - double_4dvec chi_prompt; + // [angle][incoming group][outgoing group] + double_3dvec chi_prompt; // chi_delayed has the following dimensions: - // [phi][theta][incoming group][outgoing group][delayed group] - double_5dvec chi_delayed; - // scatter has the following dimensions: [phi][theta] - std::vector > scatter; + // [angle][incoming group][outgoing group][delayed group] + double_4dvec chi_delayed; + // scatter has the following dimensions: [angle] + std::vector scatter; XsData() = default; XsData(const int num_groups, const int num_delayed_groups, @@ -63,8 +65,8 @@ class XsData { const int scatter_format, const int final_scatter_format, const int order_data, const int max_order, const int legendre_to_tabular_points, - const bool is_isotropic); - void combine(const std::vector those_xs, + const bool is_isotropic, const int n_pol, const int n_azi); + void combine(const std::vector& those_xs, const double_1dvec& scalars); bool equiv(const XsData& that); }; From 857737b3994ef477a68c4ee2e740f1eb83a66ad0 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sun, 17 Jun 2018 04:46:29 -0400 Subject: [PATCH 029/100] minor tweaks --- src/mgxs.cpp | 67 +++++++++++++++++++++++------------------------ src/scattdata.cpp | 12 +++------ 2 files changed, 37 insertions(+), 42 deletions(-) diff --git a/src/mgxs.cpp b/src/mgxs.cpp index 81a510e30b..f6be84a25b 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -414,31 +414,32 @@ Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, double* mu, int* dg) { // This method assumes that the temperature and angle indices are set + XsData* xs_t = &xs[cache[tid].t]; double val; switch(xstype) { case MG_GET_XS_TOTAL: - val = xs[cache[tid].t].total[cache[tid].a][gin]; + val = xs_t->total[cache[tid].a][gin]; break; case MG_GET_XS_NU_FISSION: if (fissionable) { - val = xs[cache[tid].t].nu_fission[cache[tid].a][gin]; + val = xs_t->nu_fission[cache[tid].a][gin]; } else { val = 0.; } break; case MG_GET_XS_ABSORPTION: - val = xs[cache[tid].t].absorption[cache[tid].a][gin]; + val = xs_t->absorption[cache[tid].a][gin]; break; case MG_GET_XS_FISSION: if (fissionable) { - val = xs[cache[tid].t].fission[cache[tid].a][gin]; + val = xs_t->fission[cache[tid].a][gin]; } else { val = 0.; } break; case MG_GET_XS_KAPPA_FISSION: if (fissionable) { - val = xs[cache[tid].t].kappa_fission[cache[tid].a][gin]; + val = xs_t->kappa_fission[cache[tid].a][gin]; } else { val = 0.; } @@ -447,11 +448,11 @@ Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, case MG_GET_XS_SCATTER_MULT: case MG_GET_XS_SCATTER_FMU_MULT: case MG_GET_XS_SCATTER_FMU: - val = xs[cache[tid].t].scatter[cache[tid].a]->get_xs(xstype, gin, gout, mu); + val = xs_t->scatter[cache[tid].a]->get_xs(xstype, gin, gout, mu); break; case MG_GET_XS_PROMPT_NU_FISSION: if (fissionable) { - val = xs[cache[tid].t].prompt_nu_fission[cache[tid].a][gin]; + val = xs_t->prompt_nu_fission[cache[tid].a][gin]; } else { val = 0.; } @@ -459,11 +460,10 @@ Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, case MG_GET_XS_DELAYED_NU_FISSION: if (fissionable) { if (dg != nullptr) { - val = xs[cache[tid].t].delayed_nu_fission[cache[tid].a][gin][*dg]; + val = xs_t->delayed_nu_fission[cache[tid].a][gin][*dg]; } else { val = 0.; - for (auto& num : xs[cache[tid].t].delayed_nu_fission - [cache[tid].a][gin]) { + for (auto& num : xs_t->delayed_nu_fission[cache[tid].a][gin]) { val += num; } } @@ -474,11 +474,11 @@ Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, case MG_GET_XS_CHI_PROMPT: if (fissionable) { if (gout != nullptr) { - val = xs[cache[tid].t].chi_prompt[cache[tid].a][gin][*gout]; + val = xs_t->chi_prompt[cache[tid].a][gin][*gout]; } else { // provide an outgoing group-wise sum val = 0.; - for (auto& num : xs[cache[tid].t].chi_prompt[cache[tid].a][gin]) { + for (auto& num : xs_t->chi_prompt[cache[tid].a][gin]) { val += num; } } @@ -490,23 +490,20 @@ Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, if (fissionable) { if (gout != nullptr) { if (dg != nullptr) { - val = xs[cache[tid].t].chi_delayed[cache[tid].a][gin][*gout][*dg]; + val = xs_t->chi_delayed[cache[tid].a][gin][*gout][*dg]; } else { - val = xs[cache[tid].t].chi_delayed[cache[tid].a][gin][*gout][0]; + val = xs_t->chi_delayed[cache[tid].a][gin][*gout][0]; } } else { if (dg != nullptr) { val = 0.; - for (int i = 0; i < xs[cache[tid].t].chi_delayed - [cache[tid].a][gin].size(); i++) { - val += xs[cache[tid].t].chi_delayed[cache[tid].a][gin][i][*dg]; + for (int i = 0; i < xs_t->chi_delayed[cache[tid].a][gin].size(); i++) { + val += xs_t->chi_delayed[cache[tid].a][gin][i][*dg]; } } else { val = 0.; - for (int i = 0; i < xs[cache[tid].t].chi_delayed - [cache[tid].a][gin].size(); i++) { - for (auto& num : xs[cache[tid].t].chi_delayed - [cache[tid].a][gin][i]) { + for (int i = 0; i < xs_t->chi_delayed[cache[tid].a][gin].size(); i++) { + for (auto& num : xs_t->chi_delayed[cache[tid].a][gin][i]) { val += num; } } @@ -517,13 +514,13 @@ Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, } break; case MG_GET_XS_INVERSE_VELOCITY: - val = xs[cache[tid].t].inverse_velocity[cache[tid].a][gin]; + val = xs_t->inverse_velocity[cache[tid].a][gin]; break; case MG_GET_XS_DECAY_RATE: if (dg != nullptr) { - val = xs[cache[tid].t].decay_rate[cache[tid].a][*dg + 1]; + val = xs_t->decay_rate[cache[tid].a][*dg + 1]; } else { - val = xs[cache[tid].t].decay_rate[cache[tid].a][0]; + val = xs_t->decay_rate[cache[tid].a][0]; } break; default: @@ -538,11 +535,12 @@ void Mgxs::sample_fission_energy(const int tid, const int gin, int& dg, int& gout) { // This method assumes that the temperature and angle indices are set - double nu_fission = xs[cache[tid].t].nu_fission[cache[tid].a][gin]; + XsData* xs_t = &xs[cache[tid].t]; + double nu_fission = xs_t->nu_fission[cache[tid].a][gin]; // Find the probability of having a prompt neutron double prob_prompt = - xs[cache[tid].t].prompt_nu_fission[cache[tid].a][gin]; + xs_t->prompt_nu_fission[cache[tid].a][gin]; // sample random numbers double xi_pd = prn() * nu_fission; @@ -558,10 +556,10 @@ Mgxs::sample_fission_energy(const int tid, const int gin, int& dg, int& gout) // sample the outgoing energy group gout = 0; double prob_gout = - xs[cache[tid].t].chi_prompt[cache[tid].a][gin][gout]; + xs_t->chi_prompt[cache[tid].a][gin][gout]; while (prob_gout < xi_gout) { gout++; - prob_gout += xs[cache[tid].t].chi_prompt[cache[tid].a][gin][gout]; + prob_gout += xs_t->chi_prompt[cache[tid].a][gin][gout]; } } else { @@ -572,7 +570,7 @@ Mgxs::sample_fission_energy(const int tid, const int gin, int& dg, int& gout) while (xi_pd >= prob_prompt) { dg++; prob_prompt += - xs[cache[tid].t].delayed_nu_fission[cache[tid].a][gin][dg]; + xs_t->delayed_nu_fission[cache[tid].a][gin][dg]; } // adjust dg in case of round-off error @@ -581,11 +579,11 @@ Mgxs::sample_fission_energy(const int tid, const int gin, int& dg, int& gout) // sample the outgoing energy group gout = 0; double prob_gout = - xs[cache[tid].t].chi_delayed[cache[tid].a][gin][gout][dg]; + xs_t->chi_delayed[cache[tid].a][gin][gout][dg]; while (prob_gout < xi_gout) { gout++; prob_gout += - xs[cache[tid].t].chi_delayed[cache[tid].a][gin][gout][dg]; + xs_t->chi_delayed[cache[tid].a][gin][gout][dg]; } } } @@ -610,11 +608,12 @@ Mgxs::calculate_xs(const int tid, const int gin, const double sqrtkT, // Set our indices set_temperature_index(tid, sqrtkT); set_angle_index(tid, uvw); - total_xs = xs[cache[tid].t].total[cache[tid].a][gin]; - abs_xs = xs[cache[tid].t].absorption[cache[tid].a][gin]; + XsData* xs_t = &xs[cache[tid].t]; + total_xs = xs_t->total[cache[tid].a][gin]; + abs_xs = xs_t->absorption[cache[tid].a][gin]; if (fissionable) { - nu_fiss_xs = xs[cache[tid].t].nu_fission[cache[tid].a][gin]; + nu_fiss_xs = xs_t->nu_fission[cache[tid].a][gin]; } else { nu_fiss_xs = 0.; } diff --git a/src/scattdata.cpp b/src/scattdata.cpp index e321bc2759..9d7bad591f 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -609,16 +609,14 @@ ScattDataHistogram::combine(const std::vector& those_scatts, const double_1dvec& scalars) { // Find the max order in the data set and make sure we can combine the sets - int max_order; + int max_order = those_scatts[0]->get_order(); for (int i = 0; i < those_scatts.size(); i++) { // Lets also make sure these items are combineable ScattDataHistogram* that = dynamic_cast(those_scatts[i]); if (!that) { fatal_error("Cannot combine the ScattData objects!"); } - if (i == 0) { - max_order = that->get_order(); - } else if (max_order != that->get_order()) { + if (max_order != that->get_order()) { fatal_error("Cannot combine the ScattData objects!"); } } @@ -835,16 +833,14 @@ ScattDataTabular::combine(const std::vector& those_scatts, const double_1dvec& scalars) { // Find the max order in the data set and make sure we can combine the sets - int max_order; + int max_order = those_scatts[0]->get_order(); for (int i = 0; i < those_scatts.size(); i++) { // Lets also make sure these items are combineable ScattDataTabular* that = dynamic_cast(those_scatts[i]); if (!that) { fatal_error("Cannot combine the ScattData objects!"); } - if (i == 0) { - max_order = that->get_order(); - } else if (max_order != that->get_order()) { + if (max_order != that->get_order()) { fatal_error("Cannot combine the ScattData objects!"); } } From 1343ef2000051cf48dfd36595b2931b2a1f6a75b Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sun, 17 Jun 2018 05:41:32 -0400 Subject: [PATCH 030/100] Bug is fixed! is_isotropic was initialized in from_hdf5, not in init. Therefore it wasnt initialized correctly by build_macro --- src/mgxs.cpp | 47 ++++++++++++++++++++++++++--------------------- src/mgxs.h | 7 ++++--- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/mgxs.cpp b/src/mgxs.cpp index f6be84a25b..f975bd5861 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -15,8 +15,9 @@ void Mgxs::init(const std::string& in_name, const double in_awr, const double_1dvec& in_kTs, const bool in_fissionable, const int in_scatter_format, const int in_num_groups, - const int in_num_delayed_groups, const double_1dvec& in_polar, - const double_1dvec& in_azimuthal, const int n_threads) + const int in_num_delayed_groups, const bool in_is_isotropic, + const double_1dvec& in_polar, const double_1dvec& in_azimuthal, + const int n_threads) { name = in_name; awr = in_awr; @@ -26,10 +27,11 @@ Mgxs::init(const std::string& in_name, const double in_awr, num_groups = in_num_groups; num_delayed_groups = in_num_delayed_groups; xs.resize(in_kTs.size()); + is_isotropic = in_is_isotropic; + n_pol = in_polar.size(); + n_azi = in_azimuthal.size(); polar = in_polar; azimuthal = in_azimuthal; - n_pol = polar.size(); - n_azi = azimuthal.size(); cache.resize(n_threads); for (int thread = 0; thread < n_threads; thread++) { cache[thread].sqrtkT = 0.; @@ -205,50 +207,52 @@ Mgxs::_metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, } // Get the angular information - is_isotropic = true; + int in_n_pol; + int in_n_azi; + bool in_is_isotropic = true; if (attribute_exists(xs_id, "representation")) { std::string temp_str(MAX_WORD_LEN, ' '); read_attr_string(xs_id, "representation", MAX_WORD_LEN, &temp_str[0]); to_lower(strtrim(temp_str)); if (temp_str.compare(0, 5, "angle") == 0) { - is_isotropic = false; + in_is_isotropic = false; } else if (temp_str.compare(0, 9, "isotropic") != 0) { fatal_error("Invalid Data Representation!"); } } - if (!is_isotropic) { + if (!in_is_isotropic) { if (attribute_exists(xs_id, "num_polar")) { - read_attr_int(xs_id, "num_polar", &n_pol); + read_attr_int(xs_id, "num_polar", &in_n_pol); } else { fatal_error("num_polar must be provided!"); } if (attribute_exists(xs_id, "num_azimuthal")) { - read_attr_int(xs_id, "num_azimuthal", &n_azi); + read_attr_int(xs_id, "num_azimuthal", &in_n_azi); } else { fatal_error("num_azimuthal must be provided!"); } } else { - n_pol = 1; - n_azi = 1; + in_n_pol = 1; + in_n_azi = 1; } // Set the angular bins to use equally-spaced bins - double_1dvec in_polar(n_pol); - double dangle = PI / n_pol; - for (int p = 0; p < n_pol; p++) { + double_1dvec in_polar(in_n_pol); + double dangle = PI / in_n_pol; + for (int p = 0; p < in_n_pol; p++) { in_polar[p] = (p + 0.5) * dangle; } - double_1dvec in_azimuthal(n_azi); - dangle = 2. * PI / n_azi; - for (int a = 0; a < n_azi; a++) { + double_1dvec in_azimuthal(in_n_azi); + dangle = 2. * PI / in_n_azi; + for (int a = 0; a < in_n_azi; a++) { in_azimuthal[a] = (a + 0.5) * dangle - PI; } // Finally use this data to initialize the MGXS Object init(in_name, in_awr, in_kTs, in_fissionable, in_scatter_format, - in_num_groups, in_num_delayed_groups, in_polar, in_azimuthal, - n_threads); + in_num_groups, in_num_delayed_groups, in_is_isotropic, in_polar, + in_azimuthal, n_threads); } //============================================================================== @@ -311,12 +315,13 @@ Mgxs::build_macro(const std::string& in_name, double_1dvec& mat_kTs, int in_scatter_format = micros[0]->scatter_format; int in_num_groups = micros[0]->num_groups; int in_num_delayed_groups = micros[0]->num_delayed_groups; + bool in_is_isotropic = micros[0]->is_isotropic; double_1dvec in_polar = micros[0]->polar; double_1dvec in_azimuthal = micros[0]->azimuthal; init(in_name, in_awr, mat_kTs, in_fissionable, in_scatter_format, - in_num_groups, in_num_delayed_groups, in_polar, in_azimuthal, - n_threads); + in_num_groups, in_num_delayed_groups, in_is_isotropic, in_polar, + in_azimuthal, n_threads); // Create the xs data for each temperature for (int t = 0; t < mat_kTs.size(); t++) { diff --git a/src/mgxs.h b/src/mgxs.h index 2a79bfe2a8..79f473c0a2 100644 --- a/src/mgxs.h +++ b/src/mgxs.h @@ -30,7 +30,7 @@ struct CacheData { double sqrtkT; // last temperature corresponding to t int t; // temperature index int a; // angle index - // last angle that corresponds to p and a + // last angle that corresponds to a double u; double v; double w; @@ -68,8 +68,9 @@ class Mgxs { void init(const std::string& in_name, const double in_awr, const double_1dvec& in_kTs, const bool in_fissionable, const int in_scatter_format, const int in_num_groups, - const int in_num_delayed_groups, const double_1dvec& in_polar, - const double_1dvec& in_azimuthal, const int n_threads); + const int in_num_delayed_groups, const bool in_is_isotropic, + const double_1dvec& in_polar, const double_1dvec& in_azimuthal, + const int n_threads); void build_macro(const std::string& in_name, double_1dvec& mat_kTs, std::vector& micros, double_1dvec& atom_densities, int& method, const double tolerance, const int n_threads); From 8c2a88243ba6915abaff34ceb6778c913d3a9ee9 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sun, 17 Jun 2018 10:10:53 -0400 Subject: [PATCH 031/100] Docs added --- src/mgxs.cpp | 4 +- src/mgxs.h | 176 +++++++++++++++++++++++++++++----- src/scattdata.cpp | 18 ++-- src/scattdata.h | 239 ++++++++++++++++++++++++++++++++++++---------- src/xsdata.cpp | 10 +- src/xsdata.h | 75 ++++++++++++--- 6 files changed, 420 insertions(+), 102 deletions(-) diff --git a/src/mgxs.cpp b/src/mgxs.cpp index f975bd5861..d30417c28e 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -46,7 +46,7 @@ Mgxs::init(const std::string& in_name, const double in_awr, //============================================================================== void -Mgxs::_metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, +Mgxs::metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, const int in_num_delayed_groups, double_1dvec& temperature, int& method, const double tolerance, int_1dvec& temps_to_read, int& order_dim, const int n_threads) @@ -267,7 +267,7 @@ Mgxs::from_hdf5(hid_t xs_id, const int energy_groups, // Call generic data gathering routine (will populate the metadata) int order_data; int_1dvec temps_to_read; - _metadata_from_hdf5(xs_id, energy_groups, delayed_groups, temperature, + metadata_from_hdf5(xs_id, energy_groups, delayed_groups, temperature, method, tolerance, temps_to_read, order_data, n_threads); // Set number of energy and delayed groups diff --git a/src/mgxs.h b/src/mgxs.h index 79f473c0a2..c0cec59416 100644 --- a/src/mgxs.h +++ b/src/mgxs.h @@ -42,6 +42,7 @@ struct CacheData { class Mgxs { private: + double_1dvec kTs; // temperature in eV (k * T) int scatter_format; // flag for if this is legendre, histogram, or tabular int num_delayed_groups; // number of delayed neutron groups @@ -53,43 +54,174 @@ class Mgxs { int n_azi; double_1dvec polar; double_1dvec azimuthal; - void _metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, + + //! \brief Initializes the Mgxs object metadata from the HDF5 file + //! + //! @param xs_id HDF5 group id for the cross section data. + //! @param in_num_groups Number of energy groups. + //! @param in_num_delayed_groups Number of delayed groups. + //! @param temperature Temperatures to read. + //! @param method Method of choosing nearest temperatures. + //! @param tolerance Tolerance of temperature selection method. + //! @param temps_to_read Resultant list of temperatures in the library + //! to read which correspond to the requested temperatures. + //! @param order_dim Resultant dimensionality of the scattering order. + //! @param n_threads Number of threads at runtime. + void + metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, const int in_num_delayed_groups, double_1dvec& temperature, int& method, const double tolerance, int_1dvec& temps_to_read, int& order_dim, const int n_threads); - bool equiv(const Mgxs& that); - public: - std::string name; // name of dataset, e.g., UO2 - double awr; // atomic weight ratio - bool fissionable; // Is this fissionable - // TODO: The following attributes be private when Fortran is fully replaced - std::vector cache; // index and data cache - void init(const std::string& in_name, const double in_awr, + //! \brief Initializes the Mgxs object metadata + //! + //! @param in_name Name of the object. + //! @param in_awr atomic-weight ratio. + //! @param in_kTs temperatures (in units of eV) that data is available. + //! @param in_fissionable Is this item fissionable or not. + //! @param in_scatter_format Denotes whether Legendre, Tabular, or + //! Histogram scattering is used. + //! @param in_num_groups Number of energy groups. + //! @param in_num_delayed_groups Number of delayed groups. + //! @param in_is_isotropic Is this an isotropic or angular with respect to + //! the incoming particle. + //! @param in_polar Polar angle grid. + //! @param in_azimuthal Azimuthal angle grid. + //! @param n_threads Number of threads at runtime. + void + init(const std::string& in_name, const double in_awr, const double_1dvec& in_kTs, const bool in_fissionable, const int in_scatter_format, const int in_num_groups, const int in_num_delayed_groups, const bool in_is_isotropic, const double_1dvec& in_polar, const double_1dvec& in_azimuthal, const int n_threads); - void build_macro(const std::string& in_name, double_1dvec& mat_kTs, - std::vector& micros, double_1dvec& atom_densities, - int& method, const double tolerance, const int n_threads); - void combine(std::vector& micros, double_1dvec& scalars, - int_1dvec& micro_ts, int this_t); - void from_hdf5(hid_t xs_id, const int energy_groups, + + //! \brief Performs the actual act of combining the microscopic data for a + //! single temperature. + //! + //! @param micros Microscopic objects to combine. + //! @param scalars Scalars to multiply the microscopic data by. + //! @param micro_ts The temperature index of the microscopic objects that + //! corresponds to the temperature of interest. + //! @param this_t The temperature index of the macroscopic object. + void + combine(std::vector& micros, double_1dvec& scalars, + int_1dvec& micro_ts, int this_t); + + //! \brief Checks to see if this and that are able to be combined + //! + //! This comparison is used when building macroscopic cross sections + //! from microscopic cross sections. + //! @param that The other Mgxs to compare to this one. + //! @return True if they can be combined, False otherwise. + bool equiv(const Mgxs& that); + + public: + + std::string name; // name of dataset, e.g., UO2 + double awr; // atomic weight ratio + bool fissionable; // Is this fissionable + std::vector cache; // index and data cache + + //! \brief Initializes and populates all data to build a macroscopic + //! cross section from microscopic cross section. + //! + //! @param in_name Name of the object. + //! @param mat_kTs temperatures (in units of eV) that data is needed. + //! @param micros Microscopic objects to combine. + //! @param atom_densities Atom densities of those microscopic quantities. + //! @param method Method of choosing nearest temperatures. + //! @param tolerance Tolerance of temperature selection method. + //! @param n_threads Number of threads at runtime. + void + build_macro(const std::string& in_name, double_1dvec& mat_kTs, + std::vector& micros, double_1dvec& atom_densities, + int& method, const double tolerance, const int n_threads); + + //! \brief Loads the Mgxs object from the HDF5 file + //! + //! @param xs_id HDF5 group id for the cross section data. + //! @param energy_groups Number of energy groups. + //! @param delayed_groups Number of delayed groups. + //! @param temperature Temperatures to read. + //! @param method Method of choosing nearest temperatures. + //! @param tolerance Tolerance of temperature selection method. + //! @param max_order Maximum order requested by the user; + //! this is only used for Legendre scattering. + //! @param legendre_to_tabular Flag to denote if any Legendre provided + //! should be converted to a Tabular representation. + //! @param legendre_to_tabular_points If a conversion is requested, this + //! provides the number of points to use in the tabular representation. + //! @param n_threads Number of threads at runtime. + void + from_hdf5(hid_t xs_id, const int energy_groups, const int delayed_groups, double_1dvec& temperature, int& method, const double tolerance, const int max_order, const bool legendre_to_tabular, const int legendre_to_tabular_points, const int n_threads); - double get_xs(const int tid, const int xstype, const int gin, int* gout, + + //! \brief Provides a cross section value given certain parameters + //! + //! @param xstype Type of cross section requested, according to the + //! enumerated constants. + //! @param gin Incoming energy group. + //! @param gout Outgoing energy group; use nullptr if irrelevant, or if a + //! sum is requested. + //! @param mu Cosine of the change-in-angle, for scattering quantities; + //! use nullptr if irrelevant. + //! @param dg delayed group index; use nullptr if irrelevant. + //! @return Requested cross section value. + double + get_xs(const int tid, const int xstype, const int gin, int* gout, double* mu, int* dg); - void sample_fission_energy(const int tid, const int gin, int& dg, int& gout); - void sample_scatter(const int tid, const int gin, int& gout, double& mu, + + //! \brief Samples the fission neutron energy and if prompt or delayed. + //! + //! @param tid Thread id to use when using the index cache. + //! @param gin Incoming energy group. + //! @param dg Sampled delayed group index. + //! @param gout Sampled outgoing energy group. + void + sample_fission_energy(const int tid, const int gin, int& dg, int& gout); + + //! \brief Samples the outgoing energy and angle from a scatter event. + //! + //! @param tid Thread id to use when using the index cache. + //! @param gin Incoming energy group. + //! @param gout Sampled outgoing energy group. + //! @param mu Sampled cosine of the change-in-angle. + //! @param wgt Weight of the particle to be adjusted. + void + sample_scatter(const int tid, const int gin, int& gout, double& mu, double& wgt); - void calculate_xs(const int tid, const int gin, const double sqrtkT, - const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs); - void set_temperature_index(const int tid, const double sqrtkT); - void set_angle_index(const int tid, const double uvw[3]); + + //! \brief Calculates cross section quantities needed for tracking. + //! + //! @param tid Thread id to use when using the index cache. + //! @param gin Incoming energy group. + //! @param sqrtkT Temperature of the material. + //! @param uvw Incoming particle direction. + //! @param total_xs Resultant total cross section. + //! @param abs_xs Resultant absorption cross section. + //! @param nu_fiss_xs Resultant nu-fission cross section. + void + calculate_xs(const int tid, const int gin, const double sqrtkT, + const double uvw[3], double& total_xs, double& abs_xs, + double& nu_fiss_xs); + + //! \brief Sets the temperature index in cache given a temperature + //! + //! @param tid Thread id to use when setting the index cache. + //! @param sqrtkT Temperature of the material. + void + set_temperature_index(const int tid, const double sqrtkT); + + //! \brief Sets the angle index in cache given a direction + //! + //! @param tid Thread id to use when setting the index cache. + //! @param uvw Incoming particle direction. + void + set_angle_index(const int tid, const double uvw[3]); }; } // namespace openmc diff --git a/src/scattdata.cpp b/src/scattdata.cpp index 9d7bad591f..952c05f647 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -7,7 +7,7 @@ namespace openmc { //============================================================================== void -ScattData::generic_init(int order, int_1dvec& in_gmin, int_1dvec& in_gmax, +ScattData::base_init(int order, int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_energy, double_2dvec& in_mult) { int groups = in_energy.size(); @@ -42,7 +42,7 @@ ScattData::generic_init(int order, int_1dvec& in_gmin, int_1dvec& in_gmax, //============================================================================== void -ScattData::generic_combine(const int max_order, +ScattData::base_combine(const int max_order, const std::vector& those_scatts, const double_1dvec& scalars, int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& sparse_mult, double_3dvec& sparse_scatter) @@ -277,7 +277,7 @@ ScattDataLegendre::init(int_1dvec& in_gmin, int_1dvec& in_gmax, } // Initialize the base class attributes - ScattData::generic_init(order, in_gmin, in_gmax, in_energy, in_mult); + ScattData::base_init(order, in_gmin, in_gmax, in_energy, in_mult); // Set the distribution (sdata.dist) values and initialize max_val max_val.resize(groups); @@ -407,7 +407,7 @@ ScattDataLegendre::combine(const std::vector& those_scatts, // The rest of the steps do not depend on the type of angular representation // so we use a base class method to sum up xs and create new energy and mult // matrices - ScattData::generic_combine(max_order, those_scatts, scalars, in_gmin, in_gmax, + ScattData::base_combine(max_order, those_scatts, scalars, in_gmin, in_gmax, sparse_mult, sparse_scatter); // Got everything we need, store it. @@ -479,7 +479,7 @@ ScattDataHistogram::init(int_1dvec& in_gmin, int_1dvec& in_gmax, } // Initialize the base class attributes - ScattData::generic_init(order, in_gmin, in_gmax, in_energy, + ScattData::base_init(order, in_gmin, in_gmax, in_energy, in_mult); // Build the angular distribution mu values @@ -631,7 +631,7 @@ ScattDataHistogram::combine(const std::vector& those_scatts, // The rest of the steps do not depend on the type of angular representation // so we use a base class method to sum up xs and create new energy and mult // matrices - ScattData::generic_combine(max_order, those_scatts, scalars, in_gmin, in_gmax, + ScattData::base_combine(max_order, those_scatts, scalars, in_gmin, in_gmax, sparse_mult, sparse_scatter); // Got everything we need, store it. @@ -691,7 +691,7 @@ ScattDataTabular::init(int_1dvec& in_gmin, int_1dvec& in_gmax, } // Initialize the base class attributes - ScattData::generic_init(order, in_gmin, in_gmax, in_energy, in_mult); + ScattData::base_init(order, in_gmin, in_gmax, in_energy, in_mult); // Calculate f(mu) and integrate it so we can avoid rejection sampling fmu.resize(groups); @@ -855,7 +855,7 @@ ScattDataTabular::combine(const std::vector& those_scatts, // The rest of the steps do not depend on the type of angular representation // so we use a base class method to sum up xs and create new energy and mult // matrices - ScattData::generic_combine(max_order, those_scatts, scalars, in_gmin, in_gmax, + ScattData::base_combine(max_order, those_scatts, scalars, in_gmin, in_gmax, sparse_mult, sparse_scatter); // Got everything we need, store it. @@ -881,7 +881,7 @@ convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, } } - tab.generic_init(n_mu, leg.gmin, leg.gmax, leg.energy, leg.mult); + tab.base_init(n_mu, leg.gmin, leg.gmax, leg.energy, leg.mult); tab.scattxs = leg.scattxs; // Build mu and dmu diff --git a/src/scattdata.h b/src/scattdata.h index 9b362b9644..69ce9e2450 100644 --- a/src/scattdata.h +++ b/src/scattdata.h @@ -27,31 +27,104 @@ class ScattDataTabular; class ScattData { protected: - void generic_init(int order, int_1dvec& in_gmin, int_1dvec& in_gmax, - double_2dvec& in_energy, double_2dvec& in_mult); - void generic_combine(const int max_order, - const std::vector& those_scatts, - const double_1dvec& scalars, int_1dvec& in_gmin, - int_1dvec& in_gmax, double_2dvec& sparse_mult, - double_3dvec& sparse_scatter); + //! \brief Initializes the attributes of the base class. + void + base_init(int order, int_1dvec& in_gmin, int_1dvec& in_gmax, + double_2dvec& in_energy, double_2dvec& in_mult); + + //! \brief Combines microscopic ScattDatas into a macroscopic one. + void + base_combine(const int max_order, + const std::vector& those_scatts, + const double_1dvec& scalars, int_1dvec& in_gmin, int_1dvec& in_gmax, + double_2dvec& sparse_mult, double_3dvec& sparse_scatter); + public: + double_2dvec energy; // Normalized p0 matrix for sampling Eout double_2dvec mult; // nu-scatter multiplication (nu-scatt/scatt) double_3dvec dist; // Angular distribution int_1dvec gmin; // minimum outgoing group int_1dvec gmax; // maximum outgoing group double_1dvec scattxs; // Isotropic Sigma_{s,g_{in}} - virtual double calc_f(const int gin, const int gout, const double mu) = 0; - virtual void sample(const int gin, int& gout, double& mu, double& wgt) = 0; - virtual void init(int_1dvec& in_gmin, int_1dvec& in_gmax, - double_2dvec& in_mult, double_3dvec& coeffs) = 0; - void sample_energy(int gin, int& gout, int& i_gout); - double get_xs(const int xstype, const int gin, const int* gout, - const double* mu); - virtual void combine(const std::vector& those_scatts, - const double_1dvec& scalars) = 0; - virtual int get_order() = 0; - virtual double_3dvec get_matrix(const int max_order) = 0; + + //! \brief Calculates the value of normalized f(mu). + //! + //! The value of f(mu) is normalized as in the integral of f(mu)dmu across + //! [-1,1] is 1. + //! + //! @param gin Incoming energy group of interest. + //! @param gout Outgoing energy group of interest. + //! @param mu Cosine of the change-in-angle of interest. + //! @return The value of f(mu). + virtual double + calc_f(const int gin, const int gout, const double mu) = 0; + + //! \brief Samples the outgoing energy and angle from the ScattData info. + //! + //! @param gin Incoming energy group. + //! @param gout Sampled outgoing energy group. + //! @param mu Sampled cosine of the change-in-angle. + //! @param wgt Weight of the particle to be adjusted. + virtual void + sample(const int gin, int& gout, double& mu, double& wgt) = 0; + + //! \brief Initializes the ScattData object from a given scatter and + //! multiplicity matrix. + //! + //! @param in_gmin List of minimum outgoing groups for every incoming group + //! @param in_gmax List of maximum outgoing groups for every incoming group + //! @param in_mult Input sparse multiplicity matrix + //! @param coeffs Input sparse scattering matrix + virtual void + init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, + double_3dvec& coeffs) = 0; + + //! \brief Combines the microscopic data. + //! + //! @param those_scatts Microscopic objects to combine. + //! @param scalars Scalars to multiply the microscopic data by. + virtual void + combine(const std::vector& those_scatts, + const double_1dvec& scalars) = 0; + + //! \brief Getter for the dimensionality of the scattering order. + //! + //! If Legendre this is the "n" in "Pn"; for Tabular, this is the number + //! of points, and for Histogram this is the number of bins. + //! + //! @return The order. + virtual int + get_order() = 0; + + //! \brief Builds a dense scattering matrix from the constituent parts + //! + //! @param max_order If Legendre this is the maximum value of "n" in "Pn" + //! requested; ignored otherwise. + //! @return The dense scattering matrix. + virtual double_3dvec + get_matrix(const int max_order) = 0; + + //! \brief Samples the outgoing energy from the ScattData info. + //! + //! @param gin Incoming energy group. + //! @param gout Sampled outgoing energy group. + //! @param i_gout Sampled outgoing energy group index. + void + sample_energy(int gin, int& gout, int& i_gout); + + //! \brief Provides a cross section value given certain parameters + //! + //! @param xstype Type of cross section requested, according to the + //! enumerated constants. + //! @param gin Incoming energy group. + //! @param gout Outgoing energy group; use nullptr if irrelevant, or if a + //! sum is requested. + //! @param mu Cosine of the change-in-angle, for scattering quantities; + //! use nullptr if irrelevant. + //! @return Requested cross section value. + double + get_xs(const int xstype, const int gin, const int* gout, const double* mu); }; //============================================================================== @@ -59,21 +132,44 @@ class ScattData { //============================================================================== class ScattDataLegendre: public ScattData { + protected: + // Maximal value for rejection sampling from a rectangle double_2dvec max_val; - friend void convert_legendre_to_tabular(ScattDataLegendre& leg, - ScattDataTabular& tab, int n_mu); + + // Friend convert_legendre_to_tabular so it has access to protected + // parameters + friend void + convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, + int n_mu); + public: - void init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, - double_3dvec& coeffs); - void update_max_val(); - double calc_f(const int gin, const int gout, const double mu); - void sample(const int gin, int& gout, double& mu, double& wgt); - void combine(const std::vector& those_scatts, - const double_1dvec& scalars); - int get_order() {return dist[0][0].size() - 1;}; - double_3dvec get_matrix(const int max_order); + + void + init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, + double_3dvec& coeffs); + + void + combine(const std::vector& those_scatts, + const double_1dvec& scalars); + + //! \brief Find the maximal value of the angular distribution to use as a + // bounding box with rejection sampling. + void + update_max_val(); + + double + calc_f(const int gin, const int gout, const double mu); + + void + sample(const int gin, int& gout, double& mu, double& wgt); + + int + get_order() {return dist[0][0].size() - 1;}; + + double_3dvec + get_matrix(const int max_order); }; //============================================================================== @@ -82,19 +178,34 @@ class ScattDataLegendre: public ScattData { //============================================================================== class ScattDataHistogram: public ScattData { + protected: - double_1dvec mu; - double dmu; - double_3dvec fmu; + + double_1dvec mu; // Angle distribution mu bin boundaries + double dmu; // Quick storage of the spacing between the mu bin points + double_3dvec fmu; // The angular distribution histogram + public: - void init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, - double_3dvec& coeffs); - double calc_f(const int gin, const int gout, const double mu); - void sample(const int gin, int& gout, double& mu, double& wgt); - void combine(const std::vector& those_scatts, - const double_1dvec& scalars); - int get_order() {return dist[0][0].size();}; - double_3dvec get_matrix(const int max_order); + + void + init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, + double_3dvec& coeffs); + + void + combine(const std::vector& those_scatts, + const double_1dvec& scalars); + + double + calc_f(const int gin, const int gout, const double mu); + + void + sample(const int gin, int& gout, double& mu, double& wgt); + + int + get_order() {return dist[0][0].size();}; + + double_3dvec + get_matrix(const int max_order); }; //============================================================================== @@ -103,20 +214,38 @@ class ScattDataHistogram: public ScattData { //============================================================================== class ScattDataTabular: public ScattData { + protected: - double_1dvec mu; - double dmu; - double_3dvec fmu; - friend void convert_legendre_to_tabular(ScattDataLegendre& leg, - ScattDataTabular& tab, int n_mu); + + double_1dvec mu; // Angle distribution mu grid points + double dmu; // Quick storage of the spacing between the mu points + double_3dvec fmu; // The angular distribution function + + // Friend convert_legendre_to_tabular so it has access to protected + // parameters + friend void + convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, + int n_mu); + public: - void init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, - double_3dvec& coeffs); - double calc_f(const int gin, const int gout, const double mu); - void sample(const int gin, int& gout, double& mu, double& wgt); - void combine(const std::vector& those_scatts, - const double_1dvec& scalars); - int get_order() {return dist[0][0].size();}; + + void + init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, + double_3dvec& coeffs); + + void + combine(const std::vector& those_scatts, + const double_1dvec& scalars); + + double + calc_f(const int gin, const int gout, const double mu); + + void + sample(const int gin, int& gout, double& mu, double& wgt); + + int + get_order() {return dist[0][0].size();}; + double_3dvec get_matrix(const int max_order); }; @@ -124,6 +253,12 @@ class ScattDataTabular: public ScattData { // Function to convert Legendre functions to tabular //============================================================================== +//! \brief Converts a ScattDatalegendre to a ScattDataHistogram +//! +//! @param leg The initial ScattDataLegendre object. +//! @param leg The resultant ScattDataTabular object. +//! @param n_mu The number of mu points to use when building the +//! ScattDataTabular object. void convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, int n_mu); diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 05e6ab01bb..b447ee0ae5 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -73,8 +73,8 @@ XsData::from_hdf5(const hid_t xsdata_grp, const bool fissionable, // Set the fissionable-specific data if (fissionable) { - _fissionable_from_hdf5(xsdata_grp, n_pol, n_azi, energy_groups, - delayed_groups, is_isotropic); + fission_from_hdf5(xsdata_grp, n_pol, n_azi, energy_groups, delayed_groups, + is_isotropic); } // Get the non-fission-specific data read_nd_vector(xsdata_grp, "decay_rate", decay_rate); @@ -82,7 +82,7 @@ XsData::from_hdf5(const hid_t xsdata_grp, const bool fissionable, read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); // Get scattering data - _scatter_from_hdf5(xsdata_grp, n_pol, n_azi, energy_groups, scatter_format, + scatter_from_hdf5(xsdata_grp, n_pol, n_azi, energy_groups, scatter_format, final_scatter_format, order_data, max_order, legendre_to_tabular_points); @@ -116,7 +116,7 @@ XsData::from_hdf5(const hid_t xsdata_grp, const bool fissionable, //============================================================================== void -XsData::_fissionable_from_hdf5(const hid_t xsdata_grp, const int n_pol, +XsData::fission_from_hdf5(const hid_t xsdata_grp, const int n_pol, const int n_azi, const int energy_groups, const int delayed_groups, const bool is_isotropic) { @@ -485,7 +485,7 @@ XsData::_fissionable_from_hdf5(const hid_t xsdata_grp, const int n_pol, //============================================================================== void -XsData::_scatter_from_hdf5(const hid_t xsdata_grp, const int n_pol, +XsData::scatter_from_hdf5(const hid_t xsdata_grp, const int n_pol, const int n_azi, const int energy_groups, int scatter_format, const int final_scatter_format, const int order_data, const int max_order, const int legendre_to_tabular_points) diff --git a/src/xsdata.h b/src/xsdata.h index dd18a8ce9b..adf80cad2b 100644 --- a/src/xsdata.h +++ b/src/xsdata.h @@ -23,15 +23,23 @@ namespace openmc { //============================================================================== class XsData { + private: - void _scatter_from_hdf5(const hid_t xsdata_grp, const int n_pol, - const int n_azi, const int energy_groups, int scatter_format, + //! \brief Reads scattering data from the HDF5 file + void + scatter_from_hdf5(const hid_t xsdata_grp, const int n_pol, const int n_azi, + const int energy_groups, int scatter_format, const int final_scatter_format, const int order_data, const int max_order, const int legendre_to_tabular_points); - void _fissionable_from_hdf5(const hid_t xsdata_grp, const int n_pol, - const int n_azi, const int energy_groups, const int delayed_groups, + + //! \brief Reads fission data from the HDF5 file + void + fission_from_hdf5(const hid_t xsdata_grp, const int n_pol, const int n_azi, + const int energy_groups, const int delayed_groups, const bool is_isotropic); + public: + // The following quantities have the following dimensions: // [angle][incoming group] double_2dvec total; @@ -58,17 +66,60 @@ class XsData { std::vector scatter; XsData() = default; + + //! \brief Constructs the XsData object metadata. + //! + //! @param num_groups Number of energy groups. + //! @param num_delayed_groups Number of delayed groups. + //! @param fissionable Is this a fissionable data set or not. + //! @param scatter_format The scattering representation of the file. + //! @param n_pol Number of polar angles. + //! @param n_azi Number of azimuthal angles. XsData(const int num_groups, const int num_delayed_groups, const bool fissionable, const int scatter_format, const int n_pol, const int n_azi); - void from_hdf5(const hid_t xsdata_grp, const bool fissionable, - const int scatter_format, const int final_scatter_format, - const int order_data, const int max_order, - const int legendre_to_tabular_points, - const bool is_isotropic, const int n_pol, const int n_azi); - void combine(const std::vector& those_xs, - const double_1dvec& scalars); - bool equiv(const XsData& that); + + //! \brief Loads the XsData object from the HDF5 file + //! + //! @param xs_id HDF5 group id for the cross section data. + //! @param fissionable Is this a fissionable data set or not. + //! @param scatter_format The scattering representation of the file. + //! @param final_scatter_format The scattering representation after reading; + //! this is different from scatter_format if converting a Legendre to + //! a tabular representation. + //! @param order_data The dimensionality of the scattering data in the file. + //! @param max_order Maximum order requested by the user; + //! this is only used for Legendre scattering. + //! @param legendre_to_tabular Flag to denote if any Legendre provided + //! should be converted to a Tabular representation. + //! @param legendre_to_tabular_points If a conversion is requested, this + //! provides the number of points to use in the tabular representation. + //! @param is_isotropic Is this an isotropic or angular with respect to + //! the incoming particle. + //! @param n_pol Number of polar angles. + //! @param n_azi Number of azimuthal angles. + void + from_hdf5(const hid_t xsdata_grp, const bool fissionable, + const int scatter_format, const int final_scatter_format, + const int order_data, const int max_order, + const int legendre_to_tabular_points, const bool is_isotropic, + const int n_pol, const int n_azi); + + //! \brief Combines the microscopic data to a macroscopic object. + //! + //! @param micros Microscopic objects to combine. + //! @param scalars Scalars to multiply the microscopic data by. + void + combine(const std::vector& those_xs, const double_1dvec& scalars); + + //! \brief Checks to see if this and that are able to be combined + //! + //! This comparison is used when building macroscopic cross sections + //! from microscopic cross sections. + //! @param that The other XsData to compare to this one. + //! @return True if they can be combined. + bool + equiv(const XsData& that); }; From a1a033f1b73b29cc0961ab062303d82c66908e8f Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sun, 17 Jun 2018 10:58:28 -0400 Subject: [PATCH 032/100] including write_message access from the C side --- src/error.F90 | 9 +++++++++ src/error.h | 21 ++++++++++++++++++++- src/mgxs_interface.cpp | 3 +-- src/mgxs_interface.h | 1 + 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/error.F90 b/src/error.F90 index d041051d29..82b142b51e 100644 --- a/src/error.F90 +++ b/src/error.F90 @@ -265,4 +265,13 @@ contains end subroutine write_message + subroutine write_message_from_c(message, message_len, level) bind(C) + integer(C_INT), intent(in), value :: message_len + character(kind=C_CHAR), intent(in) :: message(message_len) + integer(C_INT), intent(in), value :: level + character(message_len+1) :: message_out + write(message_out, *) message + call write_message(message_out, level) + end subroutine write_message_from_c + end module error diff --git a/src/error.h b/src/error.h index 45d8bcdede..356dfd8010 100644 --- a/src/error.h +++ b/src/error.h @@ -11,7 +11,8 @@ namespace openmc { extern "C" void fatal_error_from_c(const char* message, int message_len); extern "C" void warning_from_c(const char* message, int message_len); - +extern "C" void write_message_from_c(const char* message, int message_len, + int level); inline void fatal_error(const char *message) @@ -43,5 +44,23 @@ void warning(const std::stringstream& message) warning(message.str()); } +inline +void write_message(const char* message, int level) +{ + write_message_from_c(message, strlen(message), level); +} + +inline +void write_message(const std::string& message, int level) +{ + write_message_from_c(message.c_str(), message.length(), level); +} + +inline +void write_message(const std::stringstream& message, int level) +{ + write_message(message.str(), level); +} + } // namespace openmc #endif // ERROR_H diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 29202e49d5..45234f454d 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -19,8 +19,7 @@ add_mgxs_c(hid_t file_id, char* name, const int energy_groups, double_1dvec temperature; temperature.assign(temps, temps + n_temps); - // TODO: C++ replacement for write_message - // write_message("Loading " + std::string(names[i]) + " data...", 6); + write_message("Loading " + std::string(name) + " data...", 6); // Check to make sure cross section set exists in the library hid_t xs_grp; diff --git a/src/mgxs_interface.h b/src/mgxs_interface.h index 09993e9811..785f72b32f 100644 --- a/src/mgxs_interface.h +++ b/src/mgxs_interface.h @@ -4,6 +4,7 @@ #ifndef MGXS_INTERFACE_H #define MGXS_INTERFACE_H +#include "error.h" #include "mgxs.h" From b704480f9fcf51618af425cff11cf7fc6e0e0107 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Tue, 19 Jun 2018 07:03:54 -0400 Subject: [PATCH 033/100] Fixed python-side conversion of MGXS mesh to a lattice for input. --- openmc/mesh.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/openmc/mesh.py b/openmc/mesh.py index 3f53582d5e..f7cba22f8d 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -208,12 +208,12 @@ class Mesh(IDManagerMixin): shape = np.array(lattice.shape) width = lattice.pitch*shape - + mesh = cls(mesh_id, name) mesh.lower_left = lattice.lower_left mesh.upper_right = lattice.lower_left + width mesh.dimension = shape*division - + return mesh def to_xml_element(self): @@ -333,14 +333,16 @@ class Mesh(IDManagerMixin): if n_dim == 1: universe_array = np.array([universes]) elif n_dim == 2: - universe_array = np.empty(self.dimension, dtype=openmc.Universe) + universe_array = np.empty(self.dimension[::-1], + dtype=openmc.Universe) i = 0 for y in range(self.dimension[1] - 1, -1, -1): for x in range(self.dimension[0]): universe_array[y][x] = universes[i] i += 1 else: - universe_array = np.empty(self.dimension, dtype=openmc.Universe) + universe_array = np.empty(self.dimension[::-1], + dtype=openmc.Universe) i = 0 for z in range(self.dimension[2]): for y in range(self.dimension[1] - 1, -1, -1): From a85829e22f8591eaddb2d3a1f1f246e3de02e440 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Thu, 21 Jun 2018 14:05:57 -0500 Subject: [PATCH 034/100] more l-value changes --- openmc/data/resonance_covariance.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index 7f134da4b2..b35c070949 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -41,14 +41,10 @@ def res_subset(nuclide, parameter_str, bounds): sub_cov_dim = len(indices)*mpar oldvalues = [] for index1 in indices: - print("Current index:",index1) for i in range(mpar): - print("i is:", i) for index2 in indices: for j in range(mpar): - print("j is:", i) if index2*mpar+j >= index1*mpar+i: - print(cov[index1*mpar+i,index2*mpar+j]) oldvalues.append(cov[index1*mpar+i,index2*mpar+j]) cov_subset = np.zeros([sub_cov_dim,sub_cov_dim]) @@ -70,7 +66,6 @@ def sample_resonance_parameters(nuclide, n_samples, use_subset=False): ev : openmc.data.endf.Evaluation """ - print('begin sampling') if use_subset==False: parameters = nuclide.parameters cov = nuclide.covariance @@ -84,9 +79,6 @@ def sample_resonance_parameters(nuclide, n_samples, use_subset=False): mpar = nuclide.mpar samples = [] - print("nparams,params:",nparams, params) - print("covsize",covsize) - print("formalism:",formalism) ### Handling MLBW Sampling ### if formalism == 'mlbw' or formalism == 'slbw': @@ -181,7 +173,6 @@ def sample_resonance_parameters(nuclide, n_samples, use_subset=False): spin = pd.DataFrame.as_matrix(parameters['J']) mean = mean_array.flatten() for i in range(n_samples): - print("On sample",i) sample = np.random.multivariate_normal(mean,cov) energy = sample[0::5] gn = sample[1::5] From 267acf627feafa2883545fd2d3433654b44c302b Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Thu, 21 Jun 2018 20:45:10 -0400 Subject: [PATCH 035/100] resolving @paulromano comments, including intent(inout) items at the end, consistent usage of const qualifiers --- src/constants.h | 2 +- src/mgxs.cpp | 143 ++++++++++++++++++------------ src/mgxs.h | 119 ++++++++++++------------- src/mgxs_data.F90 | 27 +----- src/mgxs_interface.F90 | 36 +++----- src/mgxs_interface.cpp | 84 ++++++++---------- src/mgxs_interface.h | 49 +++++------ src/physics_mg.F90 | 20 +---- src/scattdata.cpp | 45 +++++----- src/scattdata.h | 129 ++++++++++++++------------- src/tallies/tally.F90 | 196 +++++++++++++++++++---------------------- src/tracking.F90 | 12 +-- src/xsdata.cpp | 28 +++--- src/xsdata.h | 28 +++--- 14 files changed, 421 insertions(+), 497 deletions(-) diff --git a/src/constants.h b/src/constants.h index 3b20e68f6a..016a6b3484 100644 --- a/src/constants.h +++ b/src/constants.h @@ -21,7 +21,7 @@ typedef std::vector int_1dvec; typedef std::vector > int_2dvec; typedef std::vector > > int_3dvec; -int constexpr MAX_SAMPLE {10000}; +constexpr int MAX_SAMPLE {10000}; constexpr std::array VERSION {0, 10, 0}; constexpr std::array VERSION_PARTICLE_RESTART {2, 0}; diff --git a/src/mgxs.cpp b/src/mgxs.cpp index d30417c28e..748e7e9498 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -12,13 +12,12 @@ std::vector macro_xs; //============================================================================== void -Mgxs::init(const std::string& in_name, const double in_awr, - const double_1dvec& in_kTs, const bool in_fissionable, - const int in_scatter_format, const int in_num_groups, - const int in_num_delayed_groups, const bool in_is_isotropic, - const double_1dvec& in_polar, const double_1dvec& in_azimuthal, - const int n_threads) +Mgxs::init(const std::string& in_name, double in_awr, + const double_1dvec& in_kTs, bool in_fissionable, int in_scatter_format, + int in_num_groups, int in_num_delayed_groups, bool in_is_isotropic, + const double_1dvec& in_polar, const double_1dvec& in_azimuthal) { + // Set the metadata name = in_name; awr = in_awr; kTs = in_kTs; @@ -32,6 +31,13 @@ Mgxs::init(const std::string& in_name, const double in_awr, n_azi = in_azimuthal.size(); polar = in_polar; azimuthal = in_azimuthal; + + // Set the cross section index cache +#ifdef _OPENMP + int n_threads = omp_get_max_threads(); +#else + int n_threads = 1; +#endif cache.resize(n_threads); for (int thread = 0; thread < n_threads; thread++) { cache[thread].sqrtkT = 0.; @@ -46,10 +52,9 @@ Mgxs::init(const std::string& in_name, const double in_awr, //============================================================================== void -Mgxs::metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, - const int in_num_delayed_groups, double_1dvec& temperature, int& method, - const double tolerance, int_1dvec& temps_to_read, int& order_dim, - const int n_threads) +Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, + int in_num_delayed_groups, const double_1dvec& temperature, + double tolerance, int_1dvec& temps_to_read, int& order_dim, int& method) { // get name char char_name[MAX_WORD_LEN]; @@ -252,23 +257,20 @@ Mgxs::metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, // Finally use this data to initialize the MGXS Object init(in_name, in_awr, in_kTs, in_fissionable, in_scatter_format, in_num_groups, in_num_delayed_groups, in_is_isotropic, in_polar, - in_azimuthal, n_threads); + in_azimuthal); } //============================================================================== -void -Mgxs::from_hdf5(hid_t xs_id, const int energy_groups, - const int delayed_groups, double_1dvec& temperature, int& method, - const double tolerance, const int max_order, - const bool legendre_to_tabular, const int legendre_to_tabular_points, - const int n_threads) +Mgxs::Mgxs(hid_t xs_id, int energy_groups, int delayed_groups, + const double_1dvec& temperature, double tolerance, int max_order, + bool legendre_to_tabular, int legendre_to_tabular_points, int& method) { // Call generic data gathering routine (will populate the metadata) int order_data; int_1dvec temps_to_read; metadata_from_hdf5(xs_id, energy_groups, delayed_groups, temperature, - method, tolerance, temps_to_read, order_data, n_threads); + tolerance, temps_to_read, order_data, method); // Set number of energy and delayed groups int final_scatter_format = scatter_format; @@ -297,10 +299,9 @@ Mgxs::from_hdf5(hid_t xs_id, const int energy_groups, //============================================================================== -void -Mgxs::build_macro(const std::string& in_name, double_1dvec& mat_kTs, - std::vector& micros, double_1dvec& atom_densities, int& method, - const double tolerance, const int n_threads) +Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs, + const std::vector& micros, const double_1dvec& atom_densities, + double tolerance, int& method) { // Get the minimum data needed to initialize: // Dont need awr, but lets just initialize it anyways @@ -321,7 +322,7 @@ Mgxs::build_macro(const std::string& in_name, double_1dvec& mat_kTs, init(in_name, in_awr, mat_kTs, in_fissionable, in_scatter_format, in_num_groups, in_num_delayed_groups, in_is_isotropic, in_polar, - in_azimuthal, n_threads); + in_azimuthal); // Create the xs data for each temperature for (int t = 0; t < mat_kTs.size(); t++) { @@ -397,8 +398,8 @@ Mgxs::build_macro(const std::string& in_name, double_1dvec& mat_kTs, //============================================================================== void -Mgxs::combine(std::vector& micros, double_1dvec& scalars, - int_1dvec& micro_ts, int this_t) +Mgxs::combine(const std::vector& micros, const double_1dvec& scalars, + const int_1dvec& micro_ts, int this_t) { // Build the vector of pointers to the xs objects within micros std::vector those_xs(micros.size()); @@ -415,36 +416,42 @@ Mgxs::combine(std::vector& micros, double_1dvec& scalars, //============================================================================== double -Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, - double* mu, int* dg) +Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) { // This method assumes that the temperature and angle indices are set +#ifdef _OPENMP + int tid = omp_get_thread_num(); XsData* xs_t = &xs[cache[tid].t]; + int a = cache[tid].a; +#else + XsData* xs_t = &xs[cache[0].t]; + int a = cache[0].a; +#endif double val; switch(xstype) { case MG_GET_XS_TOTAL: - val = xs_t->total[cache[tid].a][gin]; + val = xs_t->total[a][gin]; break; case MG_GET_XS_NU_FISSION: if (fissionable) { - val = xs_t->nu_fission[cache[tid].a][gin]; + val = xs_t->nu_fission[a][gin]; } else { val = 0.; } break; case MG_GET_XS_ABSORPTION: - val = xs_t->absorption[cache[tid].a][gin]; + val = xs_t->absorption[a][gin]; break; case MG_GET_XS_FISSION: if (fissionable) { - val = xs_t->fission[cache[tid].a][gin]; + val = xs_t->fission[a][gin]; } else { val = 0.; } break; case MG_GET_XS_KAPPA_FISSION: if (fissionable) { - val = xs_t->kappa_fission[cache[tid].a][gin]; + val = xs_t->kappa_fission[a][gin]; } else { val = 0.; } @@ -453,11 +460,11 @@ Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, case MG_GET_XS_SCATTER_MULT: case MG_GET_XS_SCATTER_FMU_MULT: case MG_GET_XS_SCATTER_FMU: - val = xs_t->scatter[cache[tid].a]->get_xs(xstype, gin, gout, mu); + val = xs_t->scatter[a]->get_xs(xstype, gin, gout, mu); break; case MG_GET_XS_PROMPT_NU_FISSION: if (fissionable) { - val = xs_t->prompt_nu_fission[cache[tid].a][gin]; + val = xs_t->prompt_nu_fission[a][gin]; } else { val = 0.; } @@ -465,10 +472,10 @@ Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, case MG_GET_XS_DELAYED_NU_FISSION: if (fissionable) { if (dg != nullptr) { - val = xs_t->delayed_nu_fission[cache[tid].a][gin][*dg]; + val = xs_t->delayed_nu_fission[a][gin][*dg]; } else { val = 0.; - for (auto& num : xs_t->delayed_nu_fission[cache[tid].a][gin]) { + for (auto& num : xs_t->delayed_nu_fission[a][gin]) { val += num; } } @@ -479,11 +486,11 @@ Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, case MG_GET_XS_CHI_PROMPT: if (fissionable) { if (gout != nullptr) { - val = xs_t->chi_prompt[cache[tid].a][gin][*gout]; + val = xs_t->chi_prompt[a][gin][*gout]; } else { // provide an outgoing group-wise sum val = 0.; - for (auto& num : xs_t->chi_prompt[cache[tid].a][gin]) { + for (auto& num : xs_t->chi_prompt[a][gin]) { val += num; } } @@ -495,20 +502,20 @@ Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, if (fissionable) { if (gout != nullptr) { if (dg != nullptr) { - val = xs_t->chi_delayed[cache[tid].a][gin][*gout][*dg]; + val = xs_t->chi_delayed[a][gin][*gout][*dg]; } else { - val = xs_t->chi_delayed[cache[tid].a][gin][*gout][0]; + val = xs_t->chi_delayed[a][gin][*gout][0]; } } else { if (dg != nullptr) { val = 0.; - for (int i = 0; i < xs_t->chi_delayed[cache[tid].a][gin].size(); i++) { - val += xs_t->chi_delayed[cache[tid].a][gin][i][*dg]; + for (int i = 0; i < xs_t->chi_delayed[a][gin].size(); i++) { + val += xs_t->chi_delayed[a][gin][i][*dg]; } } else { val = 0.; - for (int i = 0; i < xs_t->chi_delayed[cache[tid].a][gin].size(); i++) { - for (auto& num : xs_t->chi_delayed[cache[tid].a][gin][i]) { + for (int i = 0; i < xs_t->chi_delayed[a][gin].size(); i++) { + for (auto& num : xs_t->chi_delayed[a][gin][i]) { val += num; } } @@ -519,13 +526,13 @@ Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, } break; case MG_GET_XS_INVERSE_VELOCITY: - val = xs_t->inverse_velocity[cache[tid].a][gin]; + val = xs_t->inverse_velocity[a][gin]; break; case MG_GET_XS_DECAY_RATE: if (dg != nullptr) { - val = xs_t->decay_rate[cache[tid].a][*dg + 1]; + val = xs_t->decay_rate[a][*dg + 1]; } else { - val = xs_t->decay_rate[cache[tid].a][0]; + val = xs_t->decay_rate[a][0]; } break; default: @@ -537,9 +544,14 @@ Mgxs::get_xs(const int tid, const int xstype, const int gin, int* gout, //============================================================================== void -Mgxs::sample_fission_energy(const int tid, const int gin, int& dg, int& gout) +Mgxs::sample_fission_energy(int gin, int& dg, int& gout) { // This method assumes that the temperature and angle indices are set +#ifdef _OPENMP + int tid = omp_get_thread_num(); +#else + int tid = 0; +#endif XsData* xs_t = &xs[cache[tid].t]; double nu_fission = xs_t->nu_fission[cache[tid].a][gin]; @@ -596,23 +608,32 @@ Mgxs::sample_fission_energy(const int tid, const int gin, int& dg, int& gout) //============================================================================== void -Mgxs::sample_scatter(const int tid, const int gin, int& gout, double& mu, - double& wgt) +Mgxs::sample_scatter(int gin, int& gout, double& mu, double& wgt) { // This method assumes that the temperature and angle indices are set // Sample the data +#ifdef _OPENMP + int tid = omp_get_thread_num(); +#else + int tid = 0; +#endif xs[cache[tid].t].scatter[cache[tid].a]->sample(gin, gout, mu, wgt); } //============================================================================== void -Mgxs::calculate_xs(const int tid, const int gin, const double sqrtkT, - const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs) +Mgxs::calculate_xs(int gin, double sqrtkT, const double uvw[3], + double& total_xs, double& abs_xs, double& nu_fiss_xs) { // Set our indices - set_temperature_index(tid, sqrtkT); - set_angle_index(tid, uvw); +#ifdef _OPENMP + int tid = omp_get_thread_num(); +#else + int tid = 0; +#endif + set_temperature_index(sqrtkT); + set_angle_index(uvw); XsData* xs_t = &xs[cache[tid].t]; total_xs = xs_t->total[cache[tid].a][gin]; abs_xs = xs_t->absorption[cache[tid].a][gin]; @@ -646,9 +667,14 @@ Mgxs::equiv(const Mgxs& that) //============================================================================== void -Mgxs::set_temperature_index(const int tid, const double sqrtkT) +Mgxs::set_temperature_index(double sqrtkT) { // See if we need to find the new index +#ifdef _OPENMP + int tid = omp_get_thread_num(); +#else + int tid = 0; +#endif if (sqrtkT != cache[tid].sqrtkT) { double kT = sqrtkT * sqrtkT; @@ -668,9 +694,14 @@ Mgxs::set_temperature_index(const int tid, const double sqrtkT) //============================================================================== void -Mgxs::set_angle_index(const int tid, const double uvw[3]) +Mgxs::set_angle_index(const double uvw[3]) { // See if we need to find the new index +#ifdef _OPENMP + int tid = omp_get_thread_num(); +#else + int tid = 0; +#endif if (!is_isotropic && ((uvw[0] != cache[tid].u) || (uvw[1] != cache[tid].v) || (uvw[2] != cache[tid].w))) { diff --git a/src/mgxs.h b/src/mgxs.h index c0cec59416..8ef174269a 100644 --- a/src/mgxs.h +++ b/src/mgxs.h @@ -11,6 +11,10 @@ #include #include + #ifdef _OPENMP + # include + #endif + #include "constants.h" #include "hdf5_interface.h" #include "math_functions.h" @@ -55,24 +59,6 @@ class Mgxs { double_1dvec polar; double_1dvec azimuthal; - //! \brief Initializes the Mgxs object metadata from the HDF5 file - //! - //! @param xs_id HDF5 group id for the cross section data. - //! @param in_num_groups Number of energy groups. - //! @param in_num_delayed_groups Number of delayed groups. - //! @param temperature Temperatures to read. - //! @param method Method of choosing nearest temperatures. - //! @param tolerance Tolerance of temperature selection method. - //! @param temps_to_read Resultant list of temperatures in the library - //! to read which correspond to the requested temperatures. - //! @param order_dim Resultant dimensionality of the scattering order. - //! @param n_threads Number of threads at runtime. - void - metadata_from_hdf5(const hid_t xs_id, const int in_num_groups, - const int in_num_delayed_groups, double_1dvec& temperature, - int& method, const double tolerance, int_1dvec& temps_to_read, - int& order_dim, const int n_threads); - //! \brief Initializes the Mgxs object metadata //! //! @param in_name Name of the object. @@ -87,14 +73,28 @@ class Mgxs { //! the incoming particle. //! @param in_polar Polar angle grid. //! @param in_azimuthal Azimuthal angle grid. - //! @param n_threads Number of threads at runtime. void - init(const std::string& in_name, const double in_awr, - const double_1dvec& in_kTs, const bool in_fissionable, - const int in_scatter_format, const int in_num_groups, - const int in_num_delayed_groups, const bool in_is_isotropic, - const double_1dvec& in_polar, const double_1dvec& in_azimuthal, - const int n_threads); + init(const std::string& in_name, double in_awr, const double_1dvec& in_kTs, + bool in_fissionable, int in_scatter_format, int in_num_groups, + int in_num_delayed_groups, bool in_is_isotropic, + const double_1dvec& in_polar, const double_1dvec& in_azimuthal); + + //! \brief Initializes the Mgxs object metadata from the HDF5 file + //! + //! @param xs_id HDF5 group id for the cross section data. + //! @param in_num_groups Number of energy groups. + //! @param in_num_delayed_groups Number of delayed groups. + //! @param temperature Temperatures to read. + //! @param tolerance Tolerance of temperature selection method. + //! @param temps_to_read Resultant list of temperatures in the library + //! to read which correspond to the requested temperatures. + //! @param order_dim Resultant dimensionality of the scattering order. + //! @param method Method of choosing nearest temperatures. + void + metadata_from_hdf5(hid_t xs_id, int in_num_groups, + int in_num_delayed_groups, const double_1dvec& temperature, + double tolerance, int_1dvec& temps_to_read, int& order_dim, + int& method); //! \brief Performs the actual act of combining the microscopic data for a //! single temperature. @@ -105,8 +105,8 @@ class Mgxs { //! corresponds to the temperature of interest. //! @param this_t The temperature index of the macroscopic object. void - combine(std::vector& micros, double_1dvec& scalars, - int_1dvec& micro_ts, int this_t); + combine(const std::vector& micros, const double_1dvec& scalars, + const int_1dvec& micro_ts, int this_t); //! \brief Checks to see if this and that are able to be combined //! @@ -123,28 +123,14 @@ class Mgxs { bool fissionable; // Is this fissionable std::vector cache; // index and data cache - //! \brief Initializes and populates all data to build a macroscopic - //! cross section from microscopic cross section. - //! - //! @param in_name Name of the object. - //! @param mat_kTs temperatures (in units of eV) that data is needed. - //! @param micros Microscopic objects to combine. - //! @param atom_densities Atom densities of those microscopic quantities. - //! @param method Method of choosing nearest temperatures. - //! @param tolerance Tolerance of temperature selection method. - //! @param n_threads Number of threads at runtime. - void - build_macro(const std::string& in_name, double_1dvec& mat_kTs, - std::vector& micros, double_1dvec& atom_densities, - int& method, const double tolerance, const int n_threads); + Mgxs() = default; - //! \brief Loads the Mgxs object from the HDF5 file + //! \brief Constructor that loads the Mgxs object from the HDF5 file //! //! @param xs_id HDF5 group id for the cross section data. //! @param energy_groups Number of energy groups. //! @param delayed_groups Number of delayed groups. //! @param temperature Temperatures to read. - //! @param method Method of choosing nearest temperatures. //! @param tolerance Tolerance of temperature selection method. //! @param max_order Maximum order requested by the user; //! this is only used for Legendre scattering. @@ -152,13 +138,24 @@ class Mgxs { //! should be converted to a Tabular representation. //! @param legendre_to_tabular_points If a conversion is requested, this //! provides the number of points to use in the tabular representation. - //! @param n_threads Number of threads at runtime. - void - from_hdf5(hid_t xs_id, const int energy_groups, - const int delayed_groups, double_1dvec& temperature, int& method, - const double tolerance, const int max_order, - const bool legendre_to_tabular, const int legendre_to_tabular_points, - const int n_threads); + //! @param method Method of choosing nearest temperatures. + Mgxs(hid_t xs_id, int energy_groups, + int delayed_groups, const double_1dvec& temperature, double tolerance, + int max_order, bool legendre_to_tabular, + int legendre_to_tabular_points, int& method); + + //! \brief Constructor that initializes and populates all data to build a + //! macroscopic cross section from microscopic cross section. + //! + //! @param in_name Name of the object. + //! @param mat_kTs temperatures (in units of eV) that data is needed. + //! @param micros Microscopic objects to combine. + //! @param atom_densities Atom densities of those microscopic quantities. + //! @param tolerance Tolerance of temperature selection method. + //! @param method Method of choosing nearest temperatures. + Mgxs(const std::string& in_name, const double_1dvec& mat_kTs, + const std::vector& micros, const double_1dvec& atom_densities, + double tolerance, int& method); //! \brief Provides a cross section value given certain parameters //! @@ -172,32 +169,27 @@ class Mgxs { //! @param dg delayed group index; use nullptr if irrelevant. //! @return Requested cross section value. double - get_xs(const int tid, const int xstype, const int gin, int* gout, - double* mu, int* dg); + get_xs(int xstype, int gin, int* gout, double* mu, int* dg); //! \brief Samples the fission neutron energy and if prompt or delayed. //! - //! @param tid Thread id to use when using the index cache. //! @param gin Incoming energy group. //! @param dg Sampled delayed group index. //! @param gout Sampled outgoing energy group. void - sample_fission_energy(const int tid, const int gin, int& dg, int& gout); + sample_fission_energy(int gin, int& dg, int& gout); //! \brief Samples the outgoing energy and angle from a scatter event. //! - //! @param tid Thread id to use when using the index cache. //! @param gin Incoming energy group. //! @param gout Sampled outgoing energy group. //! @param mu Sampled cosine of the change-in-angle. //! @param wgt Weight of the particle to be adjusted. void - sample_scatter(const int tid, const int gin, int& gout, double& mu, - double& wgt); + sample_scatter(int gin, int& gout, double& mu, double& wgt); //! \brief Calculates cross section quantities needed for tracking. //! - //! @param tid Thread id to use when using the index cache. //! @param gin Incoming energy group. //! @param sqrtkT Temperature of the material. //! @param uvw Incoming particle direction. @@ -205,23 +197,20 @@ class Mgxs { //! @param abs_xs Resultant absorption cross section. //! @param nu_fiss_xs Resultant nu-fission cross section. void - calculate_xs(const int tid, const int gin, const double sqrtkT, - const double uvw[3], double& total_xs, double& abs_xs, - double& nu_fiss_xs); + calculate_xs(int gin, double sqrtkT, const double uvw[3], + double& total_xs, double& abs_xs, double& nu_fiss_xs); //! \brief Sets the temperature index in cache given a temperature //! - //! @param tid Thread id to use when setting the index cache. //! @param sqrtkT Temperature of the material. void - set_temperature_index(const int tid, const double sqrtkT); + set_temperature_index(double sqrtkT); //! \brief Sets the angle index in cache given a direction //! - //! @param tid Thread id to use when setting the index cache. //! @param uvw Incoming particle direction. void - set_angle_index(const int tid, const double uvw[3]); + set_angle_index(const double uvw[3]); }; } // namespace openmc diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index ef416125e7..1b3ed35113 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -2,10 +2,6 @@ module mgxs_data use, intrinsic :: ISO_C_BINDING -#ifdef _OPENMP - use omp_lib -#endif - use constants use algorithm, only: find use dict_header, only: DictCharInt @@ -40,13 +36,6 @@ contains type(VectorReal), allocatable, target :: temps(:) character(MAX_WORD_LEN) :: word integer, allocatable :: array(:) - integer(C_INT) :: n_threads - -#ifdef _OPENMP - n_threads = OMP_GET_MAX_THREADS() -#else - n_threads = 1 -#endif ! Check if MGXS Library exists inquire(FILE=path_cross_sections, EXIST=file_exists) @@ -91,12 +80,11 @@ contains i_nuclide = mat % nuclide(j) if (.not. already_read % contains(name)) then - call add_mgxs_c(file_id, name, & - num_energy_groups, num_delayed_groups, & + call add_mgxs_c(file_id, name, num_energy_groups, num_delayed_groups, & temps(i_nuclide) % size(), temps(i_nuclide) % data, & - temperature_method, temperature_tolerance, max_order, & + temperature_tolerance, max_order, & logical(legendre_to_tabular, C_BOOL), & - legendre_to_tabular_points, n_threads) + legendre_to_tabular_points, temperature_method) call already_read % add(name) end if @@ -122,13 +110,6 @@ contains type(Material), pointer :: mat ! current material type(VectorReal), allocatable :: kTs(:) character(MAX_WORD_LEN) :: name ! name of material - integer(C_INT) :: n_threads - -#ifdef _OPENMP - n_threads = OMP_GET_MAX_THREADS() -#else - n_threads = 1 -#endif ! Get temperatures to read for each material call get_mat_kTs(kTs) @@ -149,7 +130,7 @@ contains if (allocated(kTs(i_mat) % data)) then call create_macro_xs_c(name, mat % n_nuclides, mat % nuclide, & kTs(i_mat) % size(), kTs(i_mat) % data, mat % atom_density, & - temperature_method, temperature_tolerance, n_threads) + temperature_tolerance, temperature_method) end if end do diff --git a/src/mgxs_interface.F90 b/src/mgxs_interface.F90 index 34b0fb6112..2a579e930a 100644 --- a/src/mgxs_interface.F90 +++ b/src/mgxs_interface.F90 @@ -9,8 +9,8 @@ module mgxs_interface interface subroutine add_mgxs_c(file_id, name, energy_groups, delayed_groups, & - n_temps, temps, method, tolerance, max_order, legendre_to_tabular, & - legendre_to_tabular_points, n_threads) bind(C) + n_temps, temps, tolerance, max_order, legendre_to_tabular, & + legendre_to_tabular_points, method) bind(C) use ISO_C_BINDING import HID_T implicit none @@ -20,12 +20,11 @@ module mgxs_interface integer(C_INT), value, intent(in) :: delayed_groups integer(C_INT), value, intent(in) :: n_temps real(C_DOUBLE), intent(in) :: temps(1:n_temps) - integer(C_INT), intent(inout) :: method real(C_DOUBLE), value, intent(in) :: tolerance integer(C_INT), value, intent(in) :: max_order logical(C_BOOL),value, intent(in) :: legendre_to_tabular integer(C_INT), value, intent(in) :: legendre_to_tabular_points - integer(C_INT), value, intent(in) :: n_threads + integer(C_INT), intent(inout) :: method end subroutine add_mgxs_c function query_fissionable_c(n_nuclides, i_nuclides) result(result) bind(C) @@ -37,7 +36,7 @@ module mgxs_interface end function query_fissionable_c subroutine create_macro_xs_c(name, n_nuclides, i_nuclides, n_temps, temps, & - atom_densities, method, tolerance, n_threads) bind(C) + atom_densities, tolerance, method) bind(C) use ISO_C_BINDING implicit none character(kind=C_CHAR),intent(in) :: name(*) @@ -46,17 +45,15 @@ module mgxs_interface integer(C_INT), value, intent(in) :: n_temps real(C_DOUBLE), intent(in) :: temps(1:n_temps) real(C_DOUBLE), intent(in) :: atom_densities(1:n_nuclides) - integer(C_INT), intent(inout) :: method real(C_DOUBLE), value, intent(in) :: tolerance - integer(C_INT), value, intent(in) :: n_threads + integer(C_INT), intent(inout) :: method end subroutine create_macro_xs_c - subroutine calculate_xs_c(i_mat, tid, gin, sqrtkT, uvw, total_xs, abs_xs, & + subroutine calculate_xs_c(i_mat, gin, sqrtkT, uvw, total_xs, abs_xs, & nu_fiss_xs) bind(C) use ISO_C_BINDING implicit none integer(C_INT), value, intent(in) :: i_mat - integer(C_INT), value, intent(in) :: tid integer(C_INT), value, intent(in) :: gin real(C_DOUBLE), value, intent(in) :: sqrtkT real(C_DOUBLE), intent(in) :: uvw(1:3) @@ -65,11 +62,10 @@ module mgxs_interface real(C_DOUBLE), intent(inout) :: nu_fiss_xs end subroutine calculate_xs_c - subroutine sample_scatter_c(i_mat, tid, gin, gout, mu, wgt, uvw) bind(C) + subroutine sample_scatter_c(i_mat, gin, gout, mu, wgt, uvw) bind(C) use ISO_C_BINDING implicit none integer(C_INT), value, intent(in) :: i_mat - integer(C_INT), value, intent(in) :: tid integer(C_INT), value, intent(in) :: gin integer(C_INT), intent(inout) :: gout real(C_DOUBLE), intent(inout) :: mu @@ -77,11 +73,10 @@ module mgxs_interface real(C_DOUBLE), intent(inout) :: uvw(1:3) end subroutine sample_scatter_c - subroutine sample_fission_energy_c(i_mat, tid, gin, dg, gout) bind(C) + subroutine sample_fission_energy_c(i_mat, gin, dg, gout) bind(C) use ISO_C_BINDING implicit none integer(C_INT), value, intent(in) :: i_mat - integer(C_INT), value, intent(in) :: tid integer(C_INT), value, intent(in) :: gin integer(C_INT), intent(inout) :: dg integer(C_INT), intent(inout) :: gout @@ -102,12 +97,11 @@ module mgxs_interface real(C_DOUBLE) :: awr end function get_awr_c - function get_nuclide_xs_c(index, tid, xstype, gin, gout, mu, dg) result(val) & + function get_nuclide_xs_c(index, xstype, gin, gout, mu, dg) result(val) & bind(C) use ISO_C_BINDING implicit none integer(C_INT), value, intent(in) :: index - integer(C_INT), value, intent(in) :: tid integer(C_INT), value, intent(in) :: xstype integer(C_INT), value, intent(in) :: gin integer(C_INT), optional, intent(in) :: gout @@ -116,12 +110,11 @@ module mgxs_interface real(C_DOUBLE) :: val end function get_nuclide_xs_c - function get_macro_xs_c(index, tid, xstype, gin, gout, mu, dg) result(val) & + function get_macro_xs_c(index, xstype, gin, gout, mu, dg) result(val) & bind(C) use ISO_C_BINDING implicit none integer(C_INT), value, intent(in) :: index - integer(C_INT), value, intent(in) :: tid integer(C_INT), value, intent(in) :: xstype integer(C_INT), value, intent(in) :: gin integer(C_INT), optional, intent(in) :: gout @@ -130,27 +123,24 @@ module mgxs_interface real(C_DOUBLE) :: val end function get_macro_xs_c - subroutine set_nuclide_angle_index_c(index, tid, uvw) bind(C) + subroutine set_nuclide_angle_index_c(index, uvw) bind(C) use ISO_C_BINDING implicit none integer(C_INT), value, intent(in) :: index - integer(C_INT), value, intent(in) :: tid real(C_DOUBLE), intent(in) :: uvw(1:3) end subroutine set_nuclide_angle_index_c - subroutine set_macro_angle_index_c(index, tid, uvw) bind(C) + subroutine set_macro_angle_index_c(index, uvw) bind(C) use ISO_C_BINDING implicit none integer(C_INT), value, intent(in) :: index - integer(C_INT), value, intent(in) :: tid real(C_DOUBLE), intent(in) :: uvw(1:3) end subroutine set_macro_angle_index_c - subroutine set_nuclide_temperature_index_c(index, tid, sqrtkT) bind(C) + subroutine set_nuclide_temperature_index_c(index, sqrtkT) bind(C) use ISO_C_BINDING implicit none integer(C_INT), value, intent(in) :: index - integer(C_INT), value, intent(in) :: tid real(C_DOUBLE), value, intent(in) :: sqrtkT end subroutine set_nuclide_temperature_index_c diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 45234f454d..a96f530084 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -7,11 +7,10 @@ namespace openmc { //============================================================================== void -add_mgxs_c(hid_t file_id, char* name, const int energy_groups, - const int delayed_groups, const int n_temps, double temps[], int& method, - const double tolerance, const int max_order, - const bool legendre_to_tabular, const int legendre_to_tabular_points, - const int n_threads) +add_mgxs_c(hid_t file_id, const char* name, int energy_groups, + int delayed_groups, int n_temps, const double temps[], double tolerance, + int max_order, bool legendre_to_tabular, int legendre_to_tabular_points, + int& method) { //!! mgxs_data.F90 will be modified to just create the list of names //!! in the order needed @@ -30,10 +29,8 @@ add_mgxs_c(hid_t file_id, char* name, const int energy_groups, + "provided MGXS Library"); } - Mgxs mg; - mg.from_hdf5(xs_grp, energy_groups, delayed_groups, - temperature, method, tolerance, max_order, legendre_to_tabular, - legendre_to_tabular_points, n_threads); + Mgxs mg(xs_grp, energy_groups, delayed_groups, temperature, tolerance, + max_order, legendre_to_tabular, legendre_to_tabular_points, method); nuclides_MG.push_back(mg); } @@ -41,7 +38,7 @@ add_mgxs_c(hid_t file_id, char* name, const int energy_groups, //============================================================================== bool -query_fissionable_c(const int n_nuclides, const int i_nuclides[]) +query_fissionable_c(int n_nuclides, const int i_nuclides[]) { bool result = false; for (int n = 0; n < n_nuclides; n++) { @@ -53,12 +50,10 @@ query_fissionable_c(const int n_nuclides, const int i_nuclides[]) //============================================================================== void -create_macro_xs_c(char* mat_name, const int n_nuclides, - const int i_nuclides[], const int n_temps, const double temps[], - const double atom_densities[], int& method, const double tolerance, - const int n_threads) +create_macro_xs_c(const char* mat_name, int n_nuclides, const int i_nuclides[], + int n_temps, const double temps[], const double atom_densities[], + double tolerance, int& method) { - Mgxs macro; if (n_temps > 0) { // // Convert temps to a vector double_1dvec temperature; @@ -75,10 +70,14 @@ create_macro_xs_c(char* mat_name, const int n_nuclides, mgxs_ptr[n] = &nuclides_MG[i_nuclides[n] - 1]; } - macro.build_macro(mat_name, temperature, mgxs_ptr, atom_densities_vec, - method, tolerance, n_threads); + Mgxs macro(mat_name, temperature, mgxs_ptr, atom_densities_vec, + tolerance, method); + macro_xs.push_back(macro); + } else { + // Preserve the ordering of materials by including a blank entry + Mgxs macro; + macro_xs.push_back(macro); } - macro_xs.push_back(macro); } //============================================================================== @@ -86,22 +85,21 @@ create_macro_xs_c(char* mat_name, const int n_nuclides, //============================================================================== void -calculate_xs_c(const int i_mat, const int tid, const int gin, - const double sqrtkT, const double uvw[3], double& total_xs, double& abs_xs, - double& nu_fiss_xs) +calculate_xs_c(int i_mat, int gin, double sqrtkT, const double uvw[3], + double& total_xs, double& abs_xs, double& nu_fiss_xs) { - macro_xs[i_mat - 1].calculate_xs(tid, gin - 1, sqrtkT, uvw, total_xs, abs_xs, + macro_xs[i_mat - 1].calculate_xs(gin - 1, sqrtkT, uvw, total_xs, abs_xs, nu_fiss_xs); } //============================================================================== void -sample_scatter_c(const int i_mat, const int tid, const int gin, int& gout, - double& mu, double& wgt, double uvw[3]) +sample_scatter_c(int i_mat, int gin, int& gout, double& mu, double& wgt, + double uvw[3]) { int gout_c = gout - 1; - macro_xs[i_mat - 1].sample_scatter(tid, gin - 1, gout_c, mu, wgt); + macro_xs[i_mat - 1].sample_scatter(gin - 1, gout_c, mu, wgt); // adjust return value for fortran indexing gout = gout_c + 1; @@ -113,12 +111,11 @@ sample_scatter_c(const int i_mat, const int tid, const int gin, int& gout, //============================================================================== void -sample_fission_energy_c(const int i_mat, const int tid, const int gin, - int& dg, int& gout) +sample_fission_energy_c(int i_mat, int gin, int& dg, int& gout) { int dg_c = 0; int gout_c = 0; - macro_xs[i_mat - 1].sample_fission_energy(tid, gin - 1, dg_c, gout_c); + macro_xs[i_mat - 1].sample_fission_energy(gin - 1, dg_c, gout_c); // adjust return values for fortran indexing dg = dg_c + 1; @@ -128,8 +125,7 @@ sample_fission_energy_c(const int i_mat, const int tid, const int gin, //============================================================================== double -get_nuclide_xs_c(const int index, const int tid, const int xstype, - const int gin, int* gout, double* mu, int* dg) +get_nuclide_xs_c(int index, int xstype, int gin, int* gout, double* mu, int* dg) { int gout_c; int* gout_c_p; @@ -147,15 +143,13 @@ get_nuclide_xs_c(const int index, const int tid, const int xstype, } else { dg_c_p = dg; } - return nuclides_MG[index - 1].get_xs(tid, xstype, gin - 1, gout_c_p, mu, - dg_c_p); + return nuclides_MG[index - 1].get_xs(xstype, gin - 1, gout_c_p, mu, dg_c_p); } //============================================================================== double -get_macro_xs_c(const int index, const int tid, const int xstype, - const int gin, int* gout, double* mu, int* dg) +get_macro_xs_c(int index, int xstype, int gin, int* gout, double* mu, int* dg) { int gout_c; int* gout_c_p; @@ -173,38 +167,34 @@ get_macro_xs_c(const int index, const int tid, const int xstype, } else { dg_c_p = dg; } - return macro_xs[index - 1].get_xs(tid, xstype, gin - 1, gout_c_p, mu, - dg_c_p); + return macro_xs[index - 1].get_xs(xstype, gin - 1, gout_c_p, mu, dg_c_p); } //============================================================================== void -set_nuclide_angle_index_c(const int index, const int tid, - const double uvw[3]) +set_nuclide_angle_index_c(int index, const double uvw[3]) { // Update the values - nuclides_MG[index - 1].set_angle_index(tid, uvw); + nuclides_MG[index - 1].set_angle_index(uvw); } //============================================================================== void -set_macro_angle_index_c(const int index, const int tid, - const double uvw[3]) +set_macro_angle_index_c(int index, const double uvw[3]) { // Update the values - macro_xs[index - 1].set_angle_index(tid, uvw); + macro_xs[index - 1].set_angle_index(uvw); } //============================================================================== void -set_nuclide_temperature_index_c(const int index, const int tid, - const double sqrtkT) +set_nuclide_temperature_index_c(int index, double sqrtkT) { // Update the values - nuclides_MG[index - 1].set_temperature_index(tid, sqrtkT); + nuclides_MG[index - 1].set_temperature_index(sqrtkT); } //============================================================================== @@ -212,7 +202,7 @@ set_nuclide_temperature_index_c(const int index, const int tid, //============================================================================== void -get_name_c(const int index, int name_len, char* name) +get_name_c(int index, int name_len, char* name) { // First blank out our input string std::string str(name_len, ' '); @@ -229,7 +219,7 @@ get_name_c(const int index, int name_len, char* name) //============================================================================== double -get_awr_c(const int index) +get_awr_c(int index) { return nuclides_MG[index - 1].awr; } diff --git a/src/mgxs_interface.h b/src/mgxs_interface.h index 785f72b32f..2cdd2889a5 100644 --- a/src/mgxs_interface.h +++ b/src/mgxs_interface.h @@ -22,67 +22,58 @@ extern std::vector macro_xs; //============================================================================== extern "C" void -add_mgxs_c(hid_t file_id, char* name, const int energy_groups, - const int delayed_groups, const int n_temps, double temps[], int& method, - const double tolerance, const int max_order, - const bool legendre_to_tabular, const int legendre_to_tabular_points, - const int n_threads); +add_mgxs_c(hid_t file_id, const char* name, int energy_groups, + int delayed_groups, int n_temps, const double temps[], double tolerance, + int max_order, bool legendre_to_tabular, int legendre_to_tabular_points, + int& method); extern "C" bool -query_fissionable_c(const int n_nuclides, const int i_nuclides[]); +query_fissionable_c(int n_nuclides, const int i_nuclides[]); extern "C" void -create_macro_xs_c(char* mat_name, const int n_nuclides, - const int i_nuclides[], const int n_temps, const double temps[], - const double atom_densities[], int& method, const double tolerance, - const int n_threads); +create_macro_xs_c(const char* mat_name, int n_nuclides, const int i_nuclides[], + int n_temps, const double temps[], const double atom_densities[], + double tolerance, int& method); //============================================================================== // Mgxs tracking/transport/tallying interface methods //============================================================================== extern "C" void -calculate_xs_c(const int i_mat, const int tid, const int gin, - const double sqrtkT, const double uvw[3], double& total_xs, - double& abs_xs, double& nu_fiss_xs); +calculate_xs_c(int i_mat, int gin, double sqrtkT, const double uvw[3], + double& total_xs, double& abs_xs, double& nu_fiss_xs); extern "C" void -sample_scatter_c(const int i_mat, const int tid, const int gin, - int& gout, double& mu, double& wgt, double uvw[3]); +sample_scatter_c(int i_mat, int gin, int& gout, double& mu, double& wgt, + double uvw[3]); extern "C" void -sample_fission_energy_c(const int i_mat, const int tid, - const int gin, int& dg, int& gout); +sample_fission_energy_c(int i_mat, int gin, int& dg, int& gout); extern "C" double -get_nuclide_xs_c(const int index, const int tid, - const int xstype, const int gin, int* gout, double* mu, int* dg); +get_nuclide_xs_c(int index, int xstype, int gin, int* gout, double* mu, int* dg); extern "C" double -get_macro_xs_c(const int index, const int tid, - const int xstype, const int gin, int* gout, double* mu, int* dg); +get_macro_xs_c(int index, int xstype, int gin, int* gout, double* mu, int* dg); extern "C" void -set_nuclide_angle_index_c(const int index, const int tid, - const double uvw[3]); +set_nuclide_angle_index_c(int index, const double uvw[3]); extern "C" void -set_macro_angle_index_c(const int index, const int tid, - const double uvw[3]); +set_macro_angle_index_c(int index, const double uvw[3]); extern "C" void -set_nuclide_temperature_index_c(const int index, const int tid, - const double sqrtkT); +set_nuclide_temperature_index_c(int index, double sqrtkT); //============================================================================== // General Mgxs methods //============================================================================== extern "C" void -get_name_c(const int index, int name_len, char* name); +get_name_c(int index, int name_len, char* name); extern "C" double -get_awr_c(const int index); +get_awr_c(int index); } // namespace openmc #endif // MGXS_INTERFACE_H \ No newline at end of file diff --git a/src/physics_mg.F90 b/src/physics_mg.F90 index d04d4cb85d..a7a1832956 100644 --- a/src/physics_mg.F90 +++ b/src/physics_mg.F90 @@ -2,10 +2,6 @@ module physics_mg ! This module contains the multi-group specific physics routines so as to not ! hinder performance of the CE versions with multiple if-thens. -#ifdef _OPENMP - use omp_lib -#endif - use bank_header use constants use error, only: fatal_error, warning, write_message @@ -145,14 +141,8 @@ contains subroutine scatter(p) type(Particle), intent(inout) :: p - integer(C_INT) :: tid -#ifdef _OPENMP - tid = OMP_GET_THREAD_NUM() -#else - tid = 0 -#endif - call sample_scatter_c(p % material, tid, p % last_g, p % g, p % mu, & + call sample_scatter_c(p % material, p % last_g, p % g, p % mu, & p % wgt, p % coord(1) % uvw) ! Update energy value for downstream compatability (in tallying) @@ -183,12 +173,6 @@ contains real(8) :: mu ! fission neutron angular cosine real(8) :: phi ! fission neutron azimuthal angle real(8) :: weight ! weight adjustment for ufs method - integer(C_INT) :: tid -#ifdef _OPENMP - tid = OMP_GET_THREAD_NUM() -#else - tid = 0 -#endif ! TODO: Heat generation from fission @@ -268,7 +252,7 @@ contains ! Sample secondary energy distribution for fission reaction and set energy ! in fission bank - call sample_fission_energy_c(p % material, tid, p % g, dg, gout) + call sample_fission_energy_c(p % material, p % g, dg, gout) bank_array(i) % E = real(gout, 8) bank_array(i) % delayed_group = dg diff --git a/src/scattdata.cpp b/src/scattdata.cpp index 952c05f647..ad6ae21a63 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -7,8 +7,9 @@ namespace openmc { //============================================================================== void -ScattData::base_init(int order, int_1dvec& in_gmin, int_1dvec& in_gmax, - double_2dvec& in_energy, double_2dvec& in_mult) +ScattData::base_init(int order, const int_1dvec& in_gmin, + const int_1dvec& in_gmax, const double_2dvec& in_energy, + const double_2dvec& in_mult) { int groups = in_energy.size(); @@ -42,7 +43,7 @@ ScattData::base_init(int order, int_1dvec& in_gmin, int_1dvec& in_gmax, //============================================================================== void -ScattData::base_combine(const int max_order, +ScattData::base_combine(int max_order, const std::vector& those_scatts, const double_1dvec& scalars, int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& sparse_mult, double_3dvec& sparse_scatter) @@ -179,8 +180,7 @@ ScattData::sample_energy(int gin, int& gout, int& i_gout) //============================================================================== double -ScattData::get_xs(const int xstype, const int gin, const int* gout, - const double* mu) +ScattData::get_xs(int xstype, int gin, const int* gout, const double* mu) { // Set the outgoing group offset index as needed int i_gout = 0; @@ -239,8 +239,8 @@ ScattData::get_xs(const int xstype, const int gin, const int* gout, //============================================================================== void -ScattDataLegendre::init(int_1dvec& in_gmin, int_1dvec& in_gmax, - double_2dvec& in_mult, double_3dvec& coeffs) +ScattDataLegendre::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, + const double_2dvec& in_mult, const double_3dvec& coeffs) { int groups = coeffs.size(); int order = coeffs[0][0].size(); @@ -334,7 +334,7 @@ ScattDataLegendre::update_max_val() //============================================================================== double -ScattDataLegendre::calc_f(const int gin, const int gout, const double mu) +ScattDataLegendre::calc_f(int gin, int gout, double mu) { double f; if ((gout < gmin[gin]) || (gout > gmax[gin])) { @@ -350,7 +350,7 @@ ScattDataLegendre::calc_f(const int gin, const int gout, const double mu) //============================================================================== void -ScattDataLegendre::sample(const int gin, int& gout, double& mu, double& wgt) +ScattDataLegendre::sample(int gin, int& gout, double& mu, double& wgt) { // Sample the outgoing energy using the base-class method int i_gout; @@ -408,7 +408,7 @@ ScattDataLegendre::combine(const std::vector& those_scatts, // so we use a base class method to sum up xs and create new energy and mult // matrices ScattData::base_combine(max_order, those_scatts, scalars, in_gmin, in_gmax, - sparse_mult, sparse_scatter); + sparse_mult, sparse_scatter); // Got everything we need, store it. init(in_gmin, in_gmax, sparse_mult, sparse_scatter); @@ -417,7 +417,7 @@ ScattDataLegendre::combine(const std::vector& those_scatts, //============================================================================== double_3dvec -ScattDataLegendre::get_matrix(const int max_order) +ScattDataLegendre::get_matrix(int max_order) { // Get the sizes and initialize the data to 0 int groups = energy.size(); @@ -442,8 +442,8 @@ ScattDataLegendre::get_matrix(const int max_order) //============================================================================== void -ScattDataHistogram::init(int_1dvec& in_gmin, int_1dvec& in_gmax, - double_2dvec& in_mult, double_3dvec& coeffs) +ScattDataHistogram::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, + const double_2dvec& in_mult, const double_3dvec& coeffs) { int groups = coeffs.size(); int order = coeffs[0][0].size(); @@ -479,8 +479,7 @@ ScattDataHistogram::init(int_1dvec& in_gmin, int_1dvec& in_gmax, } // Initialize the base class attributes - ScattData::base_init(order, in_gmin, in_gmax, in_energy, - in_mult); + ScattData::base_init(order, in_gmin, in_gmax, in_energy, in_mult); // Build the angular distribution mu values mu = double_1dvec(order); @@ -522,7 +521,7 @@ ScattDataHistogram::init(int_1dvec& in_gmin, int_1dvec& in_gmax, //============================================================================== double -ScattDataHistogram::calc_f(const int gin, const int gout, const double mu) +ScattDataHistogram::calc_f(int gin, int gout, double mu) { double f; if ((gout < gmin[gin]) || (gout > gmax[gin])) { @@ -546,7 +545,7 @@ ScattDataHistogram::calc_f(const int gin, const int gout, const double mu) //============================================================================== void -ScattDataHistogram::sample(const int gin, int& gout, double& mu, double& wgt) +ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt) { // Sample the outgoing energy using the base-class method int i_gout; @@ -581,7 +580,7 @@ ScattDataHistogram::sample(const int gin, int& gout, double& mu, double& wgt) //============================================================================== double_3dvec -ScattDataHistogram::get_matrix(const int max_order) +ScattDataHistogram::get_matrix(int max_order) { // Get the sizes and initialize the data to 0 int groups = energy.size(); @@ -643,8 +642,8 @@ ScattDataHistogram::combine(const std::vector& those_scatts, //============================================================================== void -ScattDataTabular::init(int_1dvec& in_gmin, int_1dvec& in_gmax, - double_2dvec& in_mult, double_3dvec& coeffs) +ScattDataTabular::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, + const double_2dvec& in_mult, const double_3dvec& coeffs) { int groups = coeffs.size(); int order = coeffs[0][0].size(); @@ -732,7 +731,7 @@ ScattDataTabular::init(int_1dvec& in_gmin, int_1dvec& in_gmax, //============================================================================== double -ScattDataTabular::calc_f(const int gin, const int gout, const double mu) +ScattDataTabular::calc_f(int gin, int gout, double mu) { double f; if ((gout < gmin[gin]) || (gout > gmax[gin])) { @@ -757,7 +756,7 @@ ScattDataTabular::calc_f(const int gin, const int gout, const double mu) //============================================================================== void -ScattDataTabular::sample(const int gin, int& gout, double& mu, double& wgt) +ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt) { // Sample the outgoing energy using the base-class method int i_gout; @@ -805,7 +804,7 @@ ScattDataTabular::sample(const int gin, int& gout, double& mu, double& wgt) //============================================================================== double_3dvec -ScattDataTabular::get_matrix(const int max_order) +ScattDataTabular::get_matrix(int max_order) { // Get the sizes and initialize the data to 0 int groups = energy.size(); diff --git a/src/scattdata.h b/src/scattdata.h index 69ce9e2450..888f960521 100644 --- a/src/scattdata.h +++ b/src/scattdata.h @@ -29,18 +29,17 @@ class ScattData { protected: //! \brief Initializes the attributes of the base class. void - base_init(int order, int_1dvec& in_gmin, int_1dvec& in_gmax, - double_2dvec& in_energy, double_2dvec& in_mult); - + base_init(int order, const int_1dvec& in_gmin, const int_1dvec& in_gmax, + const double_2dvec& in_energy, const double_2dvec& in_mult); + //! \brief Combines microscopic ScattDatas into a macroscopic one. void - base_combine(const int max_order, - const std::vector& those_scatts, + base_combine(int max_order, const std::vector& those_scatts, const double_1dvec& scalars, int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& sparse_mult, double_3dvec& sparse_scatter); - + public: - + double_2dvec energy; // Normalized p0 matrix for sampling Eout double_2dvec mult; // nu-scatter multiplication (nu-scatt/scatt) double_3dvec dist; // Angular distribution @@ -51,15 +50,15 @@ class ScattData { //! \brief Calculates the value of normalized f(mu). //! //! The value of f(mu) is normalized as in the integral of f(mu)dmu across - //! [-1,1] is 1. + //! [-1,1] is 1. //! //! @param gin Incoming energy group of interest. //! @param gout Outgoing energy group of interest. //! @param mu Cosine of the change-in-angle of interest. //! @return The value of f(mu). virtual double - calc_f(const int gin, const int gout, const double mu) = 0; - + calc_f(int gin, int gout, double mu) = 0; + //! \brief Samples the outgoing energy and angle from the ScattData info. //! //! @param gin Incoming energy group. @@ -67,8 +66,8 @@ class ScattData { //! @param mu Sampled cosine of the change-in-angle. //! @param wgt Weight of the particle to be adjusted. virtual void - sample(const int gin, int& gout, double& mu, double& wgt) = 0; - + sample(int gin, int& gout, double& mu, double& wgt) = 0; + //! \brief Initializes the ScattData object from a given scatter and //! multiplicity matrix. //! @@ -77,9 +76,9 @@ class ScattData { //! @param in_mult Input sparse multiplicity matrix //! @param coeffs Input sparse scattering matrix virtual void - init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, - double_3dvec& coeffs) = 0; - + init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, + const double_2dvec& in_mult, const double_3dvec& coeffs) = 0; + //! \brief Combines the microscopic data. //! //! @param those_scatts Microscopic objects to combine. @@ -87,7 +86,7 @@ class ScattData { virtual void combine(const std::vector& those_scatts, const double_1dvec& scalars) = 0; - + //! \brief Getter for the dimensionality of the scattering order. //! //! If Legendre this is the "n" in "Pn"; for Tabular, this is the number @@ -96,14 +95,14 @@ class ScattData { //! @return The order. virtual int get_order() = 0; - + //! \brief Builds a dense scattering matrix from the constituent parts //! //! @param max_order If Legendre this is the maximum value of "n" in "Pn" //! requested; ignored otherwise. //! @return The dense scattering matrix. virtual double_3dvec - get_matrix(const int max_order) = 0; + get_matrix(int max_order) = 0; //! \brief Samples the outgoing energy from the ScattData info. //! @@ -124,7 +123,7 @@ class ScattData { //! use nullptr if irrelevant. //! @return Requested cross section value. double - get_xs(const int xstype, const int gin, const int* gout, const double* mu); + get_xs(int xstype, int gin, const int* gout, const double* mu); }; //============================================================================== @@ -132,44 +131,44 @@ class ScattData { //============================================================================== class ScattDataLegendre: public ScattData { - + protected: - + // Maximal value for rejection sampling from a rectangle double_2dvec max_val; // Friend convert_legendre_to_tabular so it has access to protected // parameters friend void - convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, - int n_mu); - + convert_legendre_to_tabular(ScattDataLegendre& leg, + ScattDataTabular& tab, int n_mu); + public: - + void - init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, - double_3dvec& coeffs); + init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, + const double_2dvec& in_mult, const double_3dvec& coeffs); void combine(const std::vector& those_scatts, - const double_1dvec& scalars); - + const double_1dvec& scalars); + //! \brief Find the maximal value of the angular distribution to use as a // bounding box with rejection sampling. void update_max_val(); - + double - calc_f(const int gin, const int gout, const double mu); - + calc_f(int gin, int gout, double mu); + void - sample(const int gin, int& gout, double& mu, double& wgt); - + sample(int gin, int& gout, double& mu, double& wgt); + int get_order() {return dist[0][0].size() - 1;}; - + double_3dvec - get_matrix(const int max_order); + get_matrix(int max_order); }; //============================================================================== @@ -180,32 +179,32 @@ class ScattDataLegendre: public ScattData { class ScattDataHistogram: public ScattData { protected: - + double_1dvec mu; // Angle distribution mu bin boundaries double dmu; // Quick storage of the spacing between the mu bin points double_3dvec fmu; // The angular distribution histogram - + public: - + void - init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, - double_3dvec& coeffs); - + init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, + const double_2dvec& in_mult, const double_3dvec& coeffs); + void combine(const std::vector& those_scatts, - const double_1dvec& scalars); + const double_1dvec& scalars); double - calc_f(const int gin, const int gout, const double mu); - + calc_f(int gin, int gout, double mu); + void - sample(const int gin, int& gout, double& mu, double& wgt); - + sample(int gin, int& gout, double& mu, double& wgt); + int get_order() {return dist[0][0].size();}; - + double_3dvec - get_matrix(const int max_order); + get_matrix(int max_order); }; //============================================================================== @@ -214,9 +213,9 @@ class ScattDataHistogram: public ScattData { //============================================================================== class ScattDataTabular: public ScattData { - + protected: - + double_1dvec mu; // Angle distribution mu grid points double dmu; // Quick storage of the spacing between the mu points double_3dvec fmu; // The angular distribution function @@ -224,29 +223,29 @@ class ScattDataTabular: public ScattData { // Friend convert_legendre_to_tabular so it has access to protected // parameters friend void - convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, - int n_mu); - + convert_legendre_to_tabular(ScattDataLegendre& leg, + ScattDataTabular& tab, int n_mu); + public: - + void - init(int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& in_mult, - double_3dvec& coeffs); + init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, + const double_2dvec& in_mult, const double_3dvec& coeffs); void combine(const std::vector& those_scatts, - const double_1dvec& scalars); - + const double_1dvec& scalars); + double - calc_f(const int gin, const int gout, const double mu); - + calc_f(int gin, int gout, double mu); + void - sample(const int gin, int& gout, double& mu, double& wgt); - + sample(int gin, int& gout, double& mu, double& wgt); + int get_order() {return dist[0][0].size();}; - - double_3dvec get_matrix(const int max_order); + + double_3dvec get_matrix(int max_order); }; //============================================================================== diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index f6839081d3..fa4a644d13 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -2,10 +2,6 @@ module tally use, intrinsic :: ISO_C_BINDING -#ifdef _OPENMP - use omp_lib -#endif - use algorithm, only: binary_search use constants use dict_header, only: EMPTY @@ -1233,12 +1229,6 @@ contains real(8) :: p_uvw(3) ! Particle's current uvw integer :: p_g ! Particle group to use for getting info ! to tally with. - integer(C_INT) :: tid -#ifdef _OPENMP - tid = OMP_GET_THREAD_NUM() -#else - tid = 0 -#endif ! Set the direction and group to use with get_xs if (t % estimator == ESTIMATOR_ANALOG .or. & @@ -1276,13 +1266,13 @@ contains ! To significantly reduce de-referencing, point matxs to the ! macroscopic Mgxs for the material of interest - call set_macro_angle_index_c(p % material, tid, p_uvw) + call set_macro_angle_index_c(p % material, p_uvw) ! Do same for nucxs, point it to the microscopic nuclide data of interest if (i_nuclide > 0) then ! And since we haven't calculated this temperature index yet, do so now - call set_nuclide_temperature_index_c(i_nuclide, tid, p % sqrtkT) - call set_nuclide_angle_index_c(i_nuclide, tid, p_uvw) + call set_nuclide_temperature_index_c(i_nuclide, p % sqrtkT) + call set_nuclide_angle_index_c(i_nuclide, p_uvw) end if i = 0 @@ -1337,13 +1327,13 @@ contains if (i_nuclide > 0) then score = score * flux * atom_density * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_TOTAL, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_TOTAL, p_g) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_TOTAL, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_TOTAL, p_g) end if else if (i_nuclide > 0) then - score = get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_TOTAL, p_g) * & + score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_TOTAL, p_g) * & atom_density * flux else score = material_xs % total * flux @@ -1366,22 +1356,22 @@ contains end if if (i_nuclide > 0) then - score = score * flux * get_nuclide_xs_c(i_nuclide, tid, & + score = score * flux * get_nuclide_xs_c(i_nuclide, & MG_GET_XS_INVERSE_VELOCITY, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) else - score = score * flux * get_macro_xs_c(p % material, tid, & + score = score * flux * get_macro_xs_c(p % material, & MG_GET_XS_INVERSE_VELOCITY, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if else if (i_nuclide > 0) then - score = flux * get_nuclide_xs_c(i_nuclide, tid, & + score = flux * get_nuclide_xs_c(i_nuclide, & MG_GET_XS_INVERSE_VELOCITY, p_g) else - score = flux * get_macro_xs_c(p % material, tid, & + score = flux * get_macro_xs_c(p % material, & MG_GET_XS_INVERSE_VELOCITY, p_g) end if end if @@ -1404,22 +1394,22 @@ contains ! adjust the score by the actual probability for that nuclide. if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_SCATTER_FMU_MULT, & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_SCATTER_FMU_MULT, & p % last_g, p % g, MU=p % mu) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_SCATTER_FMU_MULT, & + get_macro_xs_c(p % material, MG_GET_XS_SCATTER_FMU_MULT, & p % last_g, p % g, MU=p % mu) end if else if (i_nuclide > 0) then score = atom_density * flux * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_SCATTER_MULT, & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_SCATTER_MULT, & p_g, MU=p % mu) else ! Get the scattering x/s and take away ! the multiplication baked in to sigS score = flux * & - get_macro_xs_c(p % material, tid, MG_GET_XS_SCATTER_MULT, & + get_macro_xs_c(p % material, MG_GET_XS_SCATTER_MULT, & p_g, MU=p % mu) end if end if @@ -1442,20 +1432,20 @@ contains ! adjust the score by the actual probability for that nuclide. if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_SCATTER_FMU, & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_SCATTER_FMU, & p % last_g, p % g, MU=p % mu) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_SCATTER_FMU, & + get_macro_xs_c(p % material, MG_GET_XS_SCATTER_FMU, & p % last_g, p % g, MU=p % mu) end if else if (i_nuclide > 0) then score = atom_density * flux * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_SCATTER, p_g) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_SCATTER, p_g) else ! Get the scattering x/s, which includes multiplication score = flux * & - get_macro_xs_c(p % material, tid, MG_GET_XS_SCATTER, p_g) + get_macro_xs_c(p % material, MG_GET_XS_SCATTER, p_g) end if end if @@ -1475,13 +1465,13 @@ contains end if if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_ABSORPTION, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_ABSORPTION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if else if (i_nuclide > 0) then score = atom_density * flux * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_ABSORPTION, p_g) else score = material_xs % absorption * flux end if @@ -1506,19 +1496,19 @@ contains end if if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_FISSION, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) else score = score * & - get_macro_xs_c(p % material, tid, MG_GET_XS_FISSION, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if else if (i_nuclide > 0) then - score = get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_FISSION, p_g) * & + score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) * & atom_density * flux else - score = get_macro_xs_c(p % material, tid, MG_GET_XS_FISSION, p_g) * flux + score = get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) * flux end if end if @@ -1544,12 +1534,12 @@ contains score = p % absorb_wgt * flux if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_NU_FISSION, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) else score = score * & - get_macro_xs_c(p % material, tid, MG_GET_XS_NU_FISSION, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, MG_GET_XS_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if else ! Skip any non-fission events @@ -1562,17 +1552,17 @@ contains score = keff * p % wgt_bank * flux if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_FISSION, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_FISSION, p_g) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) end if end if else if (i_nuclide > 0) then - score = get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_NU_FISSION, p_g) * & + score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_NU_FISSION, p_g) * & atom_density * flux else - score = get_macro_xs_c(p % material, tid, MG_GET_XS_NU_FISSION, p_g) * flux + score = get_macro_xs_c(p % material, MG_GET_XS_NU_FISSION, p_g) * flux end if end if @@ -1598,12 +1588,12 @@ contains score = p % absorb_wgt * flux if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_PROMPT_NU_FISSION, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_PROMPT_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) else score = score * & - get_macro_xs_c(p % material, tid, MG_GET_XS_PROMPT_NU_FISSION, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, MG_GET_XS_PROMPT_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if else ! Skip any non-fission events @@ -1617,17 +1607,17 @@ contains / real(p % n_bank, 8)) * flux if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_FISSION, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_FISSION, p_g) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) end if end if else if (i_nuclide > 0) then - score = get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_PROMPT_NU_FISSION, p_g) * & + score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_PROMPT_NU_FISSION, p_g) * & atom_density * flux else - score = get_macro_xs_c(p % material, tid, MG_GET_XS_PROMPT_NU_FISSION, p_g) * flux + score = get_macro_xs_c(p % material, MG_GET_XS_PROMPT_NU_FISSION, p_g) * flux end if end if @@ -1653,7 +1643,7 @@ contains ! No fission events occur if survival biasing is on -- need to ! calculate fraction of absorptions that would have resulted in ! nu-fission - if (get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) > ZERO) then + if (get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) > ZERO) then if (dg_filter > 0) then select type(filt => filters(t % filter(dg_filter)) % obj) @@ -1669,12 +1659,12 @@ contains score = p % absorb_wgt * flux if (i_nuclide > 0) then score = score * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) else score = score * & - get_macro_xs_c(p % material, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if call score_fission_delayed_dg(t, d_bin, score, score_index) @@ -1685,12 +1675,12 @@ contains score = p % absorb_wgt * flux if (i_nuclide > 0) then score = score * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) else score = score * & - get_macro_xs_c(p % material, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if end if end if @@ -1720,8 +1710,8 @@ contains if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_FISSION, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_FISSION, p_g) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) end if call score_fission_delayed_dg(t, d_bin, score, score_index) @@ -1732,8 +1722,8 @@ contains score = keff * p % wgt_bank / p % n_bank * sum(p % n_delayed_bank) * flux if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_FISSION, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_FISSION, p_g) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) end if end if end if @@ -1753,10 +1743,10 @@ contains if (i_nuclide > 0) then score = atom_density * flux * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) else score = flux * & - get_macro_xs_c(p % material, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) + get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) end if call score_fission_delayed_dg(t, d_bin, score, score_index) @@ -1766,11 +1756,11 @@ contains else if (i_nuclide > 0) then score = atom_density * flux * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g) else score = flux * & - get_macro_xs_c(p % material, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g) + get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g) end if end if end if @@ -1785,7 +1775,7 @@ contains ! No fission events occur if survival biasing is on -- need to ! calculate fraction of absorptions that would have resulted in ! nu-fission - if (get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) > ZERO) then + if (get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) > ZERO) then if (dg_filter > 0) then select type(filt => filters(t % filter(dg_filter)) % obj) @@ -1801,14 +1791,14 @@ contains score = p % absorb_wgt * flux if (i_nuclide > 0) then score = score * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) else score = score * & - get_macro_xs_c(p % material, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_macro_xs_c(p % material, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if call score_fission_delayed_dg(t, d_bin, score, score_index) @@ -1826,14 +1816,14 @@ contains do d = 1, num_delayed_groups if (i_nuclide > 0) then score = score + p % absorb_wgt * flux * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) else score = score + p % absorb_wgt * flux * & - get_macro_xs_c(p % material, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_macro_xs_c(p % material, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if end do end if @@ -1862,13 +1852,13 @@ contains if (i_nuclide > 0) then score = score + keff * atom_density * & fission_bank(n_bank - p % n_bank + k) % wgt * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_FISSION, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_FISSION, p_g) * flux + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) * flux else score = score + keff * & fission_bank(n_bank - p % n_bank + k) % wgt * & - get_macro_xs_c(p % material, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * flux + get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * flux end if ! if the delayed group filter is present, tally to corresponding @@ -1921,12 +1911,12 @@ contains if (i_nuclide > 0) then score = atom_density * flux * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) else score = flux * & - get_macro_xs_c(p % material, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_macro_xs_c(p % material, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) + get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) end if call score_fission_delayed_dg(t, d_bin, score, score_index) @@ -1943,12 +1933,12 @@ contains do d = 1, num_delayed_groups if (i_nuclide > 0) then score = score + atom_density * flux * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) else score = score + flux * & - get_macro_xs_c(p % material, tid, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & - get_macro_xs_c(p % material, tid, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) + get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * & + get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) end if end do end if @@ -1973,20 +1963,20 @@ contains end if if (i_nuclide > 0) then score = score * atom_density * & - get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_KAPPA_FISSION, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_nuclide_xs_c(i_nuclide, MG_GET_XS_KAPPA_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) else score = score * & - get_macro_xs_c(p % material, tid, MG_GET_XS_KAPPA_FISSION, p_g) / & - get_macro_xs_c(p % material, tid, MG_GET_XS_ABSORPTION, p_g) + get_macro_xs_c(p % material, MG_GET_XS_KAPPA_FISSION, p_g) / & + get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) end if else if (i_nuclide > 0) then - score = get_nuclide_xs_c(i_nuclide, tid, MG_GET_XS_KAPPA_FISSION, p_g) * & + score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_KAPPA_FISSION, p_g) * & atom_density * flux else score = flux * & - get_macro_xs_c(p % material, tid, MG_GET_XS_KAPPA_FISSION, p_g) + get_macro_xs_c(p % material, MG_GET_XS_KAPPA_FISSION, p_g) end if end if diff --git a/src/tracking.F90 b/src/tracking.F90 index c926739848..8fe05e3c26 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -2,10 +2,6 @@ module tracking use, intrinsic :: ISO_C_BINDING -#ifdef _OPENMP - use omp_lib -#endif - use constants use error, only: warning, write_message use geometry_header, only: cells @@ -52,12 +48,6 @@ contains real(8) :: d_collision ! sampled distance to collision real(8) :: distance ! distance particle travels logical :: found_cell ! found cell which particle is in? - integer(C_INT) :: tid -#ifdef _OPENMP - tid = OMP_GET_THREAD_NUM() -#else - tid = 0 -#endif ! Display message if high verbosity or trace is on if (verbosity >= 9 .or. trace) then @@ -124,7 +114,7 @@ contains end if else ! Get the MG data - call calculate_xs_c(p % material, tid, p % g, p % sqrtkT, & + call calculate_xs_c(p % material, p % g, p % sqrtkT, & p % coord(p % n_coord) % uvw, material_xs % total, & material_xs % absorption, material_xs % nu_fission) diff --git a/src/xsdata.cpp b/src/xsdata.cpp index b447ee0ae5..98df2d67d1 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -6,9 +6,8 @@ namespace openmc { // XsData class methods //============================================================================== -XsData::XsData(const int energy_groups, const int num_delayed_groups, - const bool fissionable, const int scatter_format, - const int n_pol, const int n_azi) +XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable, + int scatter_format, int n_pol, int n_azi) { int n_ang = n_pol * n_azi; @@ -60,11 +59,9 @@ XsData::XsData(const int energy_groups, const int num_delayed_groups, //============================================================================== void -XsData::from_hdf5(const hid_t xsdata_grp, const bool fissionable, - const int scatter_format, const int final_scatter_format, - const int order_data, const int max_order, - const int legendre_to_tabular_points, const bool is_isotropic, - const int n_pol, const int n_azi) +XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, + int final_scatter_format, int order_data, int max_order, + int legendre_to_tabular_points, bool is_isotropic, int n_pol, int n_azi) { // Reconstruct the dimension information so it doesn't need to be passed int n_ang = n_pol * n_azi; @@ -83,8 +80,7 @@ XsData::from_hdf5(const hid_t xsdata_grp, const bool fissionable, // Get scattering data scatter_from_hdf5(xsdata_grp, n_pol, n_azi, energy_groups, scatter_format, - final_scatter_format, order_data, max_order, - legendre_to_tabular_points); + final_scatter_format, order_data, max_order, legendre_to_tabular_points); // Check absorption to ensure it is not 0 since it is often the // denominator in tally methods @@ -116,9 +112,8 @@ XsData::from_hdf5(const hid_t xsdata_grp, const bool fissionable, //============================================================================== void -XsData::fission_from_hdf5(const hid_t xsdata_grp, const int n_pol, - const int n_azi, const int energy_groups, const int delayed_groups, - const bool is_isotropic) +XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, + int energy_groups, int delayed_groups, bool is_isotropic) { int n_ang = n_pol * n_azi; // Get the fission and kappa_fission data xs; these are optional @@ -485,10 +480,9 @@ XsData::fission_from_hdf5(const hid_t xsdata_grp, const int n_pol, //============================================================================== void -XsData::scatter_from_hdf5(const hid_t xsdata_grp, const int n_pol, - const int n_azi, const int energy_groups, int scatter_format, - const int final_scatter_format, const int order_data, const int max_order, - const int legendre_to_tabular_points) +XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, + int energy_groups, int scatter_format, int final_scatter_format, + int order_data, int max_order, int legendre_to_tabular_points) { int n_ang = n_pol * n_azi; if (!object_exists(xsdata_grp, "scatter_data")) { diff --git a/src/xsdata.h b/src/xsdata.h index adf80cad2b..36aacc1784 100644 --- a/src/xsdata.h +++ b/src/xsdata.h @@ -27,19 +27,17 @@ class XsData { private: //! \brief Reads scattering data from the HDF5 file void - scatter_from_hdf5(const hid_t xsdata_grp, const int n_pol, const int n_azi, - const int energy_groups, int scatter_format, - const int final_scatter_format, const int order_data, - const int max_order, const int legendre_to_tabular_points); + scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, int energy_groups, + int scatter_format, int final_scatter_format, int order_data, + int max_order, int legendre_to_tabular_points); //! \brief Reads fission data from the HDF5 file void - fission_from_hdf5(const hid_t xsdata_grp, const int n_pol, const int n_azi, - const int energy_groups, const int delayed_groups, - const bool is_isotropic); + fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, int energy_groups, + int delayed_groups, bool is_isotropic); public: - + // The following quantities have the following dimensions: // [angle][incoming group] double_2dvec total; @@ -75,9 +73,8 @@ class XsData { //! @param scatter_format The scattering representation of the file. //! @param n_pol Number of polar angles. //! @param n_azi Number of azimuthal angles. - XsData(const int num_groups, const int num_delayed_groups, - const bool fissionable, const int scatter_format, const int n_pol, - const int n_azi); + XsData(int num_groups, int num_delayed_groups, bool fissionable, + int scatter_format, int n_pol, int n_azi); //! \brief Loads the XsData object from the HDF5 file //! @@ -99,11 +96,10 @@ class XsData { //! @param n_pol Number of polar angles. //! @param n_azi Number of azimuthal angles. void - from_hdf5(const hid_t xsdata_grp, const bool fissionable, - const int scatter_format, const int final_scatter_format, - const int order_data, const int max_order, - const int legendre_to_tabular_points, const bool is_isotropic, - const int n_pol, const int n_azi); + from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, + int final_scatter_format, int order_data, int max_order, + int legendre_to_tabular_points, bool is_isotropic, int n_pol, + int n_azi); //! \brief Combines the microscopic data to a macroscopic object. //! From 67b0ea38e40081205a7f53e3a79a15a3413aa0b8 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Tue, 26 Jun 2018 21:20:30 -0400 Subject: [PATCH 036/100] resolving style comments --- src/hdf5_interface.cpp | 28 +++++++------- src/mgxs.cpp | 87 +++++++++++++++++------------------------- src/mgxs.h | 12 ------ src/mgxs_interface.cpp | 22 ++++++----- src/mgxs_interface.h | 2 +- src/scattdata.cpp | 32 ++++++++-------- src/scattdata.h | 10 +---- src/xsdata.cpp | 58 ++++++++++++++++------------ src/xsdata.h | 9 +---- 9 files changed, 114 insertions(+), 146 deletions(-) diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index a81f26e231..7133ad51ac 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -452,7 +452,7 @@ read_nd_vector(hid_t obj_id, const char* name, std::vector& result, bool must_have) { if (object_exists(obj_id, name)) { - read_double(obj_id, name, &result[0], true); + read_double(obj_id, name, result.data(), true); } else if (must_have) { fatal_error(std::string("Must provide " + std::string(name) + "!")); } @@ -466,8 +466,8 @@ read_nd_vector(hid_t obj_id, const char* name, if (object_exists(obj_id, name)) { int dim1 = result.size(); int dim2 = result[0].size(); - std::vector temp_arr = std::vector(dim1 * dim2); - read_double(obj_id, name, &temp_arr[0], true); + double temp_arr[dim1 * dim2]; + read_double(obj_id, name, temp_arr, true); int temp_idx = 0; for (int i = 0; i < dim1; i++) { @@ -488,8 +488,8 @@ read_nd_vector(hid_t obj_id, const char* name, if (object_exists(obj_id, name)) { int dim1 = result.size(); int dim2 = result[0].size(); - std::vector temp_arr = std::vector(dim1 * dim2); - read_int(obj_id, name, &temp_arr[0], true); + int temp_arr[dim1 * dim2]; + read_int(obj_id, name, temp_arr, true); int temp_idx = 0; for (int i = 0; i < dim1; i++) { @@ -512,8 +512,8 @@ read_nd_vector(hid_t obj_id, const char* name, int dim1 = result.size(); int dim2 = result[0].size(); int dim3 = result[0][0].size(); - std::vector temp_arr = std::vector(dim1 * dim2 * dim3); - read_double(obj_id, name, &temp_arr[0], true); + double temp_arr[dim1 * dim2 * dim3]; + read_double(obj_id, name, temp_arr, true); int temp_idx = 0; for (int i = 0; i < dim1; i++) { @@ -537,8 +537,8 @@ read_nd_vector(hid_t obj_id, const char* name, int dim1 = result.size(); int dim2 = result[0].size(); int dim3 = result[0][0].size(); - std::vector temp_arr = std::vector(dim1 * dim2 * dim3); - read_int(obj_id, name, &temp_arr[0], true); + int temp_arr[dim1 * dim2 * dim3]; + read_int(obj_id, name, temp_arr, true); int temp_idx = 0; for (int i = 0; i < dim1; i++) { @@ -563,9 +563,8 @@ read_nd_vector(hid_t obj_id, const char* name, int dim2 = result[0].size(); int dim3 = result[0][0].size(); int dim4 = result[0][0][0].size(); - std::vector temp_arr = std::vector( - dim1 * dim2 * dim3 * dim4); - read_double(obj_id, name, &temp_arr[0], true); + double temp_arr[dim1 * dim2 * dim3 * dim4]; + read_double(obj_id, name, temp_arr, true); int temp_idx = 0; for (int i = 0; i < dim1; i++) { @@ -593,9 +592,8 @@ read_nd_vector(hid_t obj_id, const char* name, int dim3 = result[0][0].size(); int dim4 = result[0][0][0].size(); int dim5 = result[0][0][0][0].size(); - std::vector temp_arr = std::vector( - dim1 * dim2 * dim3 * dim4 * dim5); - read_double(obj_id, name, &temp_arr[0], true); + double temp_arr[dim1 * dim2 * dim3 * dim4 * dim5]; + read_double(obj_id, name, temp_arr, true); int temp_idx = 0; for (int i = 0; i < dim1; i++) { diff --git a/src/mgxs.cpp b/src/mgxs.cpp index 748e7e9498..3e84f63072 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -1,5 +1,19 @@ +#include +#include +#include +#include + + #ifdef _OPENMP + # include + #endif + +#include "error.h" +#include "math_functions.h" +#include "random_lcg.h" +#include "string_functions.h" #include "mgxs.h" + namespace openmc { // Storage for the MGXS data @@ -39,14 +53,7 @@ Mgxs::init(const std::string& in_name, double in_awr, int n_threads = 1; #endif cache.resize(n_threads); - for (int thread = 0; thread < n_threads; thread++) { - cache[thread].sqrtkT = 0.; - cache[thread].t = 0; - cache[thread].a = 0; - cache[thread].u = 0.; - cache[thread].v = 0.; - cache[thread].w = 0.; - } + // std::vector.resize() will value-initialize the members of cache[:] } //============================================================================== @@ -59,7 +66,7 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, // get name char char_name[MAX_WORD_LEN]; get_name(xs_id, char_name); - std::string in_name(char_name, std::strlen(char_name)); + std::string in_name {char_name}; // remove the leading '/' in_name = in_name.substr(1); @@ -85,6 +92,9 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, // convert eV to Kelvin available_temps[i] /= K_BOLTZMANN; + + // Done with dset_names, so delete it + delete[] dset_names[i]; } std::sort(available_temps.begin(), available_temps.end()); @@ -92,7 +102,7 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, // interpolation if ((num_temps == 1) && (method == TEMPERATURE_INTERPOLATION)) { warning("Cross sections for " + strtrim(name) + " are only available " + - "at one temperature. Reverying to the nearest temperature " + + "at one temperature. Reverting to the nearest temperature " + "method."); method = TEMPERATURE_NEAREST; } @@ -190,7 +200,7 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, if (attribute_exists(xs_id, "fissionable")) { int int_fiss; read_attr_int(xs_id, "fissionable", &int_fiss); - in_fissionable = (bool)int_fiss; + in_fissionable = int_fiss; } else { fatal_error("Fissionable element must be set!"); } @@ -208,7 +218,7 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, // moment). Adjust for that. Histogram and Tabular formats dont need this // adjustment. if (in_scatter_format == ANGLE_LEGENDRE) { - order_dim = order_dim + 1; + ++order_dim; } // Get the angular information @@ -220,7 +230,7 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, read_attr_string(xs_id, "representation", MAX_WORD_LEN, &temp_str[0]); to_lower(strtrim(temp_str)); if (temp_str.compare(0, 5, "angle") == 0) { - in_is_isotropic = false; + in_is_isotropic = false; } else if (temp_str.compare(0, 9, "isotropic") != 0) { fatal_error("Invalid Data Representation!"); } @@ -326,7 +336,7 @@ Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs, // Create the xs data for each temperature for (int t = 0; t < mat_kTs.size(); t++) { - xs[t]= XsData(in_num_groups, in_num_delayed_groups, in_fissionable, + xs[t] = XsData(in_num_groups, in_num_delayed_groups, in_fissionable, in_scatter_format, in_polar.size(), in_azimuthal.size()); // Find the right temperature index to use @@ -433,28 +443,16 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) val = xs_t->total[a][gin]; break; case MG_GET_XS_NU_FISSION: - if (fissionable) { - val = xs_t->nu_fission[a][gin]; - } else { - val = 0.; - } + val = fissionable ? xs_t->nu_fission[a][gin] : 0.; break; case MG_GET_XS_ABSORPTION: val = xs_t->absorption[a][gin]; break; case MG_GET_XS_FISSION: - if (fissionable) { - val = xs_t->fission[a][gin]; - } else { - val = 0.; - } + val = fissionable ? xs_t->fission[a][gin] : 0.; break; case MG_GET_XS_KAPPA_FISSION: - if (fissionable) { - val = xs_t->kappa_fission[a][gin]; - } else { - val = 0.; - } + val = fissionable ? xs_t->kappa_fission[a][gin] : 0.; break; case MG_GET_XS_SCATTER: case MG_GET_XS_SCATTER_MULT: @@ -463,11 +461,7 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) val = xs_t->scatter[a]->get_xs(xstype, gin, gout, mu); break; case MG_GET_XS_PROMPT_NU_FISSION: - if (fissionable) { - val = xs_t->prompt_nu_fission[a][gin]; - } else { - val = 0.; - } + val = fissionable ? xs_t->prompt_nu_fission[a][gin] : 0.; break; case MG_GET_XS_DELAYED_NU_FISSION: if (fissionable) { @@ -638,11 +632,7 @@ Mgxs::calculate_xs(int gin, double sqrtkT, const double uvw[3], total_xs = xs_t->total[cache[tid].a][gin]; abs_xs = xs_t->absorption[cache[tid].a][gin]; - if (fissionable) { - nu_fiss_xs = xs_t->nu_fission[cache[tid].a][gin]; - } else { - nu_fiss_xs = 0.; - } + nu_fiss_xs = fissionable ? xs_t->nu_fission[cache[tid].a][gin] : 0.; } //============================================================================== @@ -650,18 +640,13 @@ Mgxs::calculate_xs(int gin, double sqrtkT, const double uvw[3], bool Mgxs::equiv(const Mgxs& that) { - bool match = false; - - if ((num_delayed_groups == that.num_delayed_groups) && - (num_groups == that.num_groups) && - (n_pol == that.n_pol) && - (n_azi == that.n_azi) && - (std::equal(polar.begin(), polar.end(), that.polar.begin())) && - (std::equal(azimuthal.begin(), azimuthal.end(), that.azimuthal.begin())) && - (scatter_format == that.scatter_format)) { - match = true; - } - return match; + return ((num_delayed_groups == that.num_delayed_groups) && + (num_groups == that.num_groups) && + (n_pol == that.n_pol) && + (n_azi == that.n_azi) && + (std::equal(polar.begin(), polar.end(), that.polar.begin())) && + (std::equal(azimuthal.begin(), azimuthal.end(), that.azimuthal.begin())) && + (scatter_format == that.scatter_format)); } //============================================================================== diff --git a/src/mgxs.h b/src/mgxs.h index 8ef174269a..0434bd55d5 100644 --- a/src/mgxs.h +++ b/src/mgxs.h @@ -4,23 +4,11 @@ #ifndef MGXS_H #define MGXS_H -#include -#include -#include #include -#include #include - #ifdef _OPENMP - # include - #endif - #include "constants.h" #include "hdf5_interface.h" -#include "math_functions.h" -#include "random_lcg.h" -#include "scattdata.h" -#include "string_functions.h" #include "xsdata.h" diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index a96f530084..d875987791 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -1,5 +1,10 @@ +#include + +#include "error.h" +#include "math_functions.h" #include "mgxs_interface.h" + namespace openmc { //============================================================================== @@ -12,11 +17,8 @@ add_mgxs_c(hid_t file_id, const char* name, int energy_groups, int max_order, bool legendre_to_tabular, int legendre_to_tabular_points, int& method) { - //!! mgxs_data.F90 will be modified to just create the list of names - //!! in the order needed // Convert temps to a vector for the from_hdf5 function - double_1dvec temperature; - temperature.assign(temps, temps + n_temps); + double_1dvec temperature(temps, temps + n_temps); write_message("Loading " + std::string(name) + " data...", 6); @@ -33,6 +35,7 @@ add_mgxs_c(hid_t file_id, const char* name, int energy_groups, max_order, legendre_to_tabular, legendre_to_tabular_points, method); nuclides_MG.push_back(mg); + close_group(xs_grp); } //============================================================================== @@ -56,12 +59,11 @@ create_macro_xs_c(const char* mat_name, int n_nuclides, const int i_nuclides[], { if (n_temps > 0) { // // Convert temps to a vector - double_1dvec temperature; - temperature.assign(temps, temps + n_temps); + double_1dvec temperature(temps, temps + n_temps); // Convert atom_densities to a vector - double_1dvec atom_densities_vec; - atom_densities_vec.assign(atom_densities, atom_densities + n_nuclides); + double_1dvec atom_densities_vec(atom_densities, + atom_densities + n_nuclides); // Build array of pointers to nuclides_MG's Mgxs objects needed for this // material @@ -72,11 +74,11 @@ create_macro_xs_c(const char* mat_name, int n_nuclides, const int i_nuclides[], Mgxs macro(mat_name, temperature, mgxs_ptr, atom_densities_vec, tolerance, method); - macro_xs.push_back(macro); + macro_xs.emplace_back(macro); } else { // Preserve the ordering of materials by including a blank entry Mgxs macro; - macro_xs.push_back(macro); + macro_xs.emplace_back(macro); } } diff --git a/src/mgxs_interface.h b/src/mgxs_interface.h index 2cdd2889a5..65afd20f9c 100644 --- a/src/mgxs_interface.h +++ b/src/mgxs_interface.h @@ -4,7 +4,7 @@ #ifndef MGXS_INTERFACE_H #define MGXS_INTERFACE_H -#include "error.h" +#include "hdf5_interface.h" #include "mgxs.h" diff --git a/src/scattdata.cpp b/src/scattdata.cpp index ad6ae21a63..a316eba46d 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -1,3 +1,11 @@ +#include +#include +#include + +#include "constants.h" +#include "math_functions.h" +#include "random_lcg.h" +#include "error.h" #include "scattdata.h" namespace openmc { @@ -35,7 +43,6 @@ ScattData::base_init(int order, const int_1dvec& in_gmin, dist[gin].resize(in_gmax[gin] - in_gmin[gin] + 1); for (auto& v : dist[gin]) { v.resize(order); - for (auto& n : v) n = 0.; } } } @@ -193,27 +200,22 @@ ScattData::get_xs(int xstype, int gin, const int* gout, const double* mu) i_gout = *gout - gmin[gin]; } - double val = 0.; + double val = scattxs[gin]; switch(xstype) { case MG_GET_XS_SCATTER: - if (gout != nullptr) { - val = scattxs[gin] * energy[gin][i_gout]; - } else { - val = scattxs[gin]; - } + if (gout != nullptr) val *= energy[gin][i_gout]; break; case MG_GET_XS_SCATTER_MULT: if (gout != nullptr) { - val = scattxs[gin] * energy[gin][i_gout] / mult[gin][i_gout]; + val *= energy[gin][i_gout] / mult[gin][i_gout]; } else { - val = scattxs[gin] / - std::inner_product(mult[gin].begin(), mult[gin].end(), - energy[gin].begin(), 0.0); + val /= std::inner_product(mult[gin].begin(), mult[gin].end(), + energy[gin].begin(), 0.0); } break; case MG_GET_XS_SCATTER_FMU_MULT: if ((gout != nullptr) && (mu != nullptr)) { - val = scattxs[gin] * energy[gin][i_gout] * calc_f(gin, *gout, *mu); + val *= energy[gin][i_gout] * calc_f(gin, *gout, *mu); } else { // This is not an expected path (asking for f_mu without asking for a // group or mu is not useful @@ -222,8 +224,7 @@ ScattData::get_xs(int xstype, int gin, const int* gout, const double* mu) break; case MG_GET_XS_SCATTER_FMU: if ((gout != nullptr) && (mu != nullptr)) { - val = scattxs[gin] * energy[gin][i_gout] * calc_f(gin, *gout, *mu) / - mult[gin][i_gout]; + val *= energy[gin][i_gout] * calc_f(gin, *gout, *mu) / mult[gin][i_gout]; } else { // This is not an expected path (asking for f_mu without asking for a // group or mu is not useful @@ -674,8 +675,7 @@ ScattDataTabular::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, } // Build the energy transfer matrix from data in the variable matrix - double_2dvec in_energy; - in_energy.resize(groups); + double_2dvec in_energy(groups); for (int gin = 0; gin < groups; gin++) { int num_groups = in_gmax[gin] - in_gmin[gin] + 1; in_energy[gin].resize(num_groups); diff --git a/src/scattdata.h b/src/scattdata.h index 888f960521..72ebaf6771 100644 --- a/src/scattdata.h +++ b/src/scattdata.h @@ -4,19 +4,11 @@ #ifndef SCATTDATA_H #define SCATTDATA_H -#include -#include #include -#include - -#include "constants.h" -#include "math_functions.h" -#include "random_lcg.h" -#include "error.h" namespace openmc { -// temporary declaations so we can name our friend functions +// forward declarations so we can name our friend functions class ScattDataLegendre; class ScattDataTabular; diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 98df2d67d1..712fe7b0ff 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -1,5 +1,15 @@ +#include +#include +#include +#include + +#include "constants.h" +#include "error.h" +#include "math_functions.h" +#include "random_lcg.h" #include "xsdata.h" + namespace openmc { //============================================================================== @@ -44,14 +54,17 @@ XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable, double_2dvec(energy_groups, double_1dvec(num_delayed_groups, 0.)))); } - scatter.resize(n_ang); + for (int a = 0; a < n_ang; a++) { if (scatter_format == ANGLE_HISTOGRAM) { - scatter[a] = new ScattDataHistogram; + // scatter[a] = std::make_unique(ScattDataHistogram); + scatter.emplace_back(new ScattDataHistogram); } else if (scatter_format == ANGLE_TABULAR) { - scatter[a] = new ScattDataTabular; + // scatter[a] = std::make_unique(ScattDataTabular); + scatter.emplace_back(new ScattDataTabular); } else if (scatter_format == ANGLE_LEGENDRE) { - scatter[a] = new ScattDataLegendre; + // scatter[a] = std::make_unique(ScattDataLegendre); + scatter.emplace_back(new ScattDataLegendre); } } } @@ -131,7 +144,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (ndims == 3) { // Beta is input as [delayed group] - double_1dvec temp_arr = double_1dvec(n_pol * n_azi * delayed_groups); + double_1dvec temp_arr(n_pol * n_azi * delayed_groups); read_nd_vector(xsdata_grp, "beta", temp_arr); // Broadcast to all incoming groups @@ -155,7 +168,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // If chi is provided, set chi-prompt and chi-delayed if (object_exists(xsdata_grp, "chi")) { - double_2dvec temp_arr = double_2dvec(n_ang, double_1dvec(energy_groups)); + double_2dvec temp_arr(n_ang, double_1dvec(energy_groups)); read_nd_vector(xsdata_grp, "chi", temp_arr); for (int a = 0; a < n_ang; a++) { @@ -277,7 +290,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // If chi-prompt is provided, set chi-prompt if (object_exists(xsdata_grp, "chi-prompt")) { - double_2dvec temp_arr = double_2dvec(n_ang, double_1dvec(energy_groups)); + double_2dvec temp_arr(n_ang, double_1dvec(energy_groups)); read_nd_vector(xsdata_grp, "chi-prompt", temp_arr); for (int a = 0; a < n_ang; a++) { @@ -309,7 +322,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (ndims == 3) { // chi-delayed is a [in group] vector - double_2dvec temp_arr = double_2dvec(n_ang, double_1dvec(energy_groups)); + double_2dvec temp_arr(n_ang, double_1dvec(energy_groups)); read_nd_vector(xsdata_grp, "chi-delayed", temp_arr); for (int a = 0; a < n_ang; a++) { @@ -371,7 +384,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } else if (ndims == 4) { // prompt nu fission is a matrix, // so set prompt_nu_fiss & chi_prompt - double_3dvec temp_arr = double_3dvec(n_ang, double_2dvec(energy_groups, + double_3dvec temp_arr(n_ang, double_2dvec(energy_groups, double_1dvec(energy_groups))); read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_arr); @@ -414,7 +427,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, fatal_error("cannot set delayed-nu-fission with a 1D array if " "beta is not provided"); } - double_2dvec temp_arr = double_2dvec(n_ang, double_1dvec(energy_groups)); + double_2dvec temp_arr(n_ang, double_1dvec(energy_groups)); read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); for (int a = 0; a < n_ang; a++) { @@ -433,7 +446,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } else if (ndims == 5) { // This will contain delayed-nu-fision and chi-delayed data - double_4dvec temp_arr = double_4dvec(n_ang, double_3dvec(energy_groups, + double_4dvec temp_arr(n_ang, double_3dvec(energy_groups, double_2dvec(energy_groups, double_1dvec(delayed_groups)))); read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); @@ -491,9 +504,9 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, hid_t scatt_grp = open_group(xsdata_grp, "scatter_data"); // Get the outgoing group boundary indices - int_2dvec gmin = int_2dvec(n_ang, int_1dvec(energy_groups)); + int_2dvec gmin(n_ang, int_1dvec(energy_groups)); read_nd_vector(scatt_grp, "g_min", gmin, true); - int_2dvec gmax = int_2dvec(n_ang, int_1dvec(energy_groups)); + int_2dvec gmax(n_ang, int_1dvec(energy_groups)); read_nd_vector(scatt_grp, "g_max", gmax, true); // Make gmin and gmax start from 0 vice 1 as they do in the library @@ -512,7 +525,7 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, length += order_data * (gmax[a][gin] - gmin[a][gin] + 1); } } - double_1dvec temp_arr = double_1dvec(length); + double_1dvec temp_arr(length); read_nd_vector(scatt_grp, "scatter_matrix", temp_arr, true); // Compare the number of orders given with the max order of the problem; @@ -526,8 +539,7 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // convert the flattened temp_arr to a jagged array for passing to // scatt data - double_4dvec input_scatt = - double_4dvec(n_ang, double_3dvec(energy_groups)); + double_4dvec input_scatt(n_ang, double_3dvec(energy_groups)); int temp_idx = 0; for (int a = 0; a < n_ang; a++) { @@ -546,7 +558,7 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, temp_arr.clear(); // Get multiplication matrix - double_3dvec temp_mult = double_3dvec(n_ang, double_2dvec(energy_groups)); + double_3dvec temp_mult(n_ang, double_2dvec(energy_groups)); if (object_exists(scatt_grp, "multiplicity_matrix")) { temp_arr.resize(length / order_data); read_nd_vector(scatt_grp, "multiplicity_matrix", temp_arr); @@ -584,7 +596,7 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Now create a tabular version of legendre_scatt convert_legendre_to_tabular(legendre_scatt, - *static_cast(scatter[a]), + *static_cast(scatter[a].get()), legendre_to_tabular_points); scatter_format = final_scatter_format; @@ -676,7 +688,7 @@ XsData::combine(const std::vector& those_xs, // Build vector of the scattering objects to incorporate std::vector those_scatts(those_xs.size()); for (int i = 0; i < those_xs.size(); i++) { - those_scatts[i] = those_xs[i]->scatter[a]; + those_scatts[i] = those_xs[i]->scatter[a].get(); } // Now combine these guys @@ -689,12 +701,8 @@ XsData::combine(const std::vector& those_xs, bool XsData::equiv(const XsData& that) { - bool match = false; - if ((absorption.size() == that.absorption.size()) && - (absorption[0].size() == that.absorption[0].size())) { - match = true; - } - return match; + return ((absorption.size() == that.absorption.size()) && + (absorption[0].size() == that.absorption[0].size())); } } //namespace openmc diff --git a/src/xsdata.h b/src/xsdata.h index 36aacc1784..c855c67d89 100644 --- a/src/xsdata.h +++ b/src/xsdata.h @@ -4,15 +4,10 @@ #ifndef XSDATA_H #define XSDATA_H -#include -#include -#include +#include #include -#include "constants.h" #include "hdf5_interface.h" -#include "math_functions.h" -#include "random_lcg.h" #include "scattdata.h" @@ -61,7 +56,7 @@ class XsData { // [angle][incoming group][outgoing group][delayed group] double_4dvec chi_delayed; // scatter has the following dimensions: [angle] - std::vector scatter; + std::vector > scatter; XsData() = default; From 1fec0b3ac416c7812bd0c08309ffd9bbdd9fceca Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Tue, 26 Jun 2018 21:25:05 -0400 Subject: [PATCH 037/100] added comments explaining if (is_isotropic) line --- src/xsdata.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 712fe7b0ff..3482a316a2 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -140,6 +140,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, hid_t xsdata = open_dataset(xsdata_grp, "beta"); int ndims = dataset_ndims(xsdata); + // raise ndims to make the isotropic ndims the same as angular if (is_isotropic) ndims += 2; if (ndims == 3) { @@ -211,6 +212,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (object_exists(xsdata_grp, "nu-fission")) { hid_t xsdata = open_dataset(xsdata_grp, "nu-fission"); int ndims = dataset_ndims(xsdata); + // raise ndims to make the isotropic ndims the same as angular if (is_isotropic) ndims += 2; if (ndims == 3) { @@ -317,6 +319,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (object_exists(xsdata_grp, "chi-delayed")) { hid_t xsdata = open_dataset(xsdata_grp, "chi-delayed"); int ndims = dataset_ndims(xsdata); + // raise ndims to make the isotropic ndims the same as angular if (is_isotropic) ndims += 2; close_dataset(xsdata); @@ -374,6 +377,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (object_exists(xsdata_grp, "prompt-nu-fission")) { hid_t xsdata = open_dataset(xsdata_grp, "prompt-nu-fission"); int ndims = dataset_ndims(xsdata); + // raise ndims to make the isotropic ndims the same as angular if (is_isotropic) ndims += 2; close_dataset(xsdata); @@ -419,6 +423,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, hid_t xsdata = open_dataset(xsdata_grp, "delayed-nu-fission"); int ndims = dataset_ndims(xsdata); close_dataset(xsdata); + // raise ndims to make the isotropic ndims the same as angular if (is_isotropic) ndims += 2; if (ndims == 3) { From ca0f415de48b8b45888280307f8caec590ead949 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 20 Jun 2018 07:06:02 -0500 Subject: [PATCH 038/100] Update recognized thermal scattering names with Lib80x names --- openmc/data/thermal.py | 60 ++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/openmc/data/thermal.py b/openmc/data/thermal.py index a036a2680c..18ba56bc56 100644 --- a/openmc/data/thermal.py +++ b/openmc/data/thermal.py @@ -24,40 +24,44 @@ from openmc.stats import Discrete, Tabular _THERMAL_NAMES = { - 'c_Al27': ('al', 'al27'), - 'c_Be': ('be', 'be-metal'), - 'c_BeO': ('beo'), - 'c_Be_in_BeO': ('bebeo', 'be-o', 'be/o'), + 'c_Al27': ('al', 'al27', 'al-27'), + 'c_Be': ('be', 'be-metal', 'be-met'), + 'c_BeO': ('beo',), + 'c_Be_in_BeO': ('bebeo', 'be-beo', 'be-o', 'be/o'), 'c_C6H6': ('benz', 'c6h6'), - 'c_C_in_SiC': ('csic',), - 'c_Ca_in_CaH2': ('cah'), - 'c_D_in_D2O': ('dd2o', 'hwtr', 'hw'), - 'c_Fe56': ('fe', 'fe56'), + 'c_C_in_SiC': ('csic', 'c-sic'), + 'c_Ca_in_CaH2': ('cah',), + 'c_D_in_D2O': ('dd2o', 'd-d2o', 'hwtr', 'hw'), + 'c_Fe56': ('fe', 'fe56', 'fe-56'), 'c_Graphite': ('graph', 'grph', 'gr'), - 'c_H_in_CaH2': ('hcah2'), - 'c_H_in_CH2': ('hch2', 'poly', 'pol'), + 'c_Graphite_10p': ('grph10',), + 'c_Graphite_30p': ('grph30',), + 'c_H_in_CaH2': ('hcah2',), + 'c_H_in_CH2': ('hch2', 'poly', 'pol', 'h-poly'), 'c_H_in_CH4_liquid': ('lch4', 'lmeth'), 'c_H_in_CH4_solid': ('sch4', 'smeth'), - 'c_H_in_H2O': ('hh2o', 'lwtr', 'lw'), - 'c_H_in_H2O_solid': ('hice',), - 'c_H_in_C5O2H8': ('lucite', 'c5o2h8'), - 'c_H_in_YH2': ('hyh2'), - 'c_H_in_ZrH': ('hzrh', 'h-zr', 'h/zr', 'hzr'), + 'c_H_in_H2O': ('hh2o', 'h-h2o', 'lwtr', 'lw'), + 'c_H_in_H2O_solid': ('hice', 'h-ice'), + 'c_H_in_C5O2H8': ('lucite', 'c5o2h8', 'h-luci'), + 'c_H_in_YH2': ('hyh2', 'h-yh2'), + 'c_H_in_ZrH': ('hzrh', 'h-zrh', 'h-zr', 'h/zr', 'hzr'), 'c_Mg24': ('mg', 'mg24'), - 'c_O_in_BeO': ('obeo', 'o-be', 'o/be'), - 'c_O_in_D2O': ('od2o'), - 'c_O_in_H2O_ice': ('oice'), - 'c_O_in_UO2': ('ouo2', 'o2-u', 'o2/u'), - 'c_ortho_D': ('orthod', 'dortho'), - 'c_ortho_H': ('orthoh', 'hortho'), - 'c_Si_in_SiC': ('sisic'), + 'c_O_in_BeO': ('obeo', 'o-beo', 'o-be', 'o/be'), + 'c_O_in_D2O': ('od2o', 'o-d2o'), + 'c_O_in_H2O_ice': ('oice', 'o-ice'), + 'c_O_in_UO2': ('ouo2', 'o-uo2', 'o2-u', 'o2/u'), + 'c_N_in_UN': ('n-un',), + 'c_ortho_D': ('orthod', 'orthoD', 'dortho'), + 'c_ortho_H': ('orthoh', 'orthoH', 'hortho'), + 'c_Si_in_SiC': ('sisic', 'si-sic'), 'c_SiO2_alpha': ('sio2', 'sio2a'), - 'c_SiO2_beta': ('sio2b'), - 'c_para_D': ('parad', 'dpara'), - 'c_para_H': ('parah', 'hpara'), - 'c_U_in_UO2': ('uuo2', 'u-o2', 'u/o2'), - 'c_Y_in_YH2': ('yyh2'), - 'c_Zr_in_ZrH': ('zrzrh', 'zr-h', 'zr/h') + 'c_SiO2_beta': ('sio2b',), + 'c_para_D': ('parad', 'paraD', 'dpara'), + 'c_para_H': ('parah', 'paraH', 'hpara'), + 'c_U_in_UN': ('u-un',), + 'c_U_in_UO2': ('uuo2', 'u-uo2', 'u-o2', 'u/o2'), + 'c_Y_in_YH2': ('yyh2', 'y-yh2'), + 'c_Zr_in_ZrH': ('zrzrh', 'zr-zrh', 'zr-h', 'zr/h') } From 514d8350a2a6e33351f8bec5e0a5d5e85959e656 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 20 Jun 2018 07:27:59 -0500 Subject: [PATCH 039/100] Move Faddeeva source into vendor/ directory --- CMakeLists.txt | 4 ++-- {src => vendor}/faddeeva/Faddeeva.c | 0 {src => vendor}/faddeeva/Faddeeva.cc | 0 {src => vendor}/faddeeva/Faddeeva.h | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename {src => vendor}/faddeeva/Faddeeva.c (100%) rename {src => vendor}/faddeeva/Faddeeva.cc (100%) rename {src => vendor}/faddeeva/Faddeeva.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec77fa0e33..d154b1cf34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -320,7 +320,8 @@ endif() # Build faddeeva library #=============================================================================== -add_library(faddeeva STATIC src/faddeeva/Faddeeva.c) +add_library(faddeeva STATIC vendor/faddeeva/Faddeeva.c) +target_compile_options(faddeeva PRIVATE ${cflags}) #=============================================================================== # List source files. Define the libopenmc and the OpenMC executable @@ -469,7 +470,6 @@ target_include_directories(libopenmc PUBLIC include ${HDF5_INCLUDE_DIRS}) # The executable and the faddeeva package use only one language. They can be # set via target_compile_options which accepts a list. target_compile_options(${program} PUBLIC ${cxxflags}) -target_compile_options(faddeeva PRIVATE ${cflags}) # The libopenmc library has both F90 and C++ so the compile flags must be set # file-by-file via set_source_file_properties. The compile flags must first be diff --git a/src/faddeeva/Faddeeva.c b/vendor/faddeeva/Faddeeva.c similarity index 100% rename from src/faddeeva/Faddeeva.c rename to vendor/faddeeva/Faddeeva.c diff --git a/src/faddeeva/Faddeeva.cc b/vendor/faddeeva/Faddeeva.cc similarity index 100% rename from src/faddeeva/Faddeeva.cc rename to vendor/faddeeva/Faddeeva.cc diff --git a/src/faddeeva/Faddeeva.h b/vendor/faddeeva/Faddeeva.h similarity index 100% rename from src/faddeeva/Faddeeva.h rename to vendor/faddeeva/Faddeeva.h From 2a936aa3820c92a0a4b97af048c1d87ca72d38b9 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 20 Jun 2018 10:56:28 -0500 Subject: [PATCH 040/100] Move pugixml to vendor/ directory --- CMakeLists.txt | 14 +++++++------- src/cell.h | 4 ++-- src/lattice.h | 2 +- src/surface.h | 2 +- src/xml_interface.h | 2 +- {src => vendor}/pugixml/pugiconfig.hpp | 0 {src => vendor}/pugixml/pugixml.cpp | 0 {src => vendor}/pugixml/pugixml.hpp | 0 8 files changed, 12 insertions(+), 12 deletions(-) rename {src => vendor}/pugixml/pugiconfig.hpp (100%) rename {src => vendor}/pugixml/pugixml.cpp (100%) rename {src => vendor}/pugixml/pugixml.hpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d154b1cf34..047cb875b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -284,9 +284,8 @@ endif() # pugixml library #=============================================================================== -add_library(pugixml src/pugixml/pugixml_c.cpp src/pugixml/pugixml.cpp) -add_library(pugixml_fortran src/pugixml/pugixml_f.F90) -target_link_libraries(pugixml_fortran pugixml) +add_library(pugixml vendor/pugixml/pugixml.cpp) +target_include_directories(pugixml PUBLIC vendor/pugixml/) #=============================================================================== # RPATH information @@ -377,6 +376,7 @@ set(LIBOPENMC_FORTRAN_SRC src/plot_header.F90 src/product_header.F90 src/progress_header.F90 + src/pugixml/pugixml_f.F90 src/random_lcg.F90 src/reaction_header.F90 src/relaxng @@ -443,6 +443,7 @@ set(LIBOPENMC_CXX_SRC src/mgxs.cpp src/mgxs_interface.cpp src/plot.cpp + src/pugixml/pugixml_c.cpp src/random_lcg.cpp src/scattdata.cpp src/simulation.cpp @@ -450,8 +451,7 @@ set(LIBOPENMC_CXX_SRC src/string_functions.cpp src/surface.cpp src/xml_interface.cpp - src/xsdata.cpp - src/pugixml/pugixml.cpp) + src/xsdata.cpp) add_library(libopenmc SHARED ${LIBOPENMC_FORTRAN_SRC} ${LIBOPENMC_CXX_SRC}) set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc @@ -462,7 +462,7 @@ add_executable(${program} src/main.cpp) # Add compiler/linker flags #=============================================================================== -set_property(TARGET ${program} libopenmc pugixml_fortran +set_property(TARGET ${program} libopenmc PROPERTY LINKER_LANGUAGE Fortran) target_include_directories(libopenmc PUBLIC include ${HDF5_INCLUDE_DIRS}) @@ -488,7 +488,7 @@ endforeach() # target_link_libraries treats any arguments starting with - but not -l as # linker flags. Thus, we can pass both linker flags and libraries together. -target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml_fortran +target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml faddeeva) target_link_libraries(${program} ${ldflags} libopenmc) diff --git a/src/cell.h b/src/cell.h index a2f72c8337..24413b4fd4 100644 --- a/src/cell.h +++ b/src/cell.h @@ -7,7 +7,7 @@ #include #include "hdf5.h" -#include "pugixml/pugixml.hpp" +#include "pugixml.hpp" namespace openmc { @@ -50,7 +50,7 @@ public: //! A geometry primitive that links surfaces, universes, and materials //============================================================================== -class Cell +class Cell { public: int32_t id; //!< Unique ID diff --git a/src/lattice.h b/src/lattice.h index 19749ce4f0..bc706a5a3f 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -9,7 +9,7 @@ #include "constants.h" #include "hdf5.h" -#include "pugixml/pugixml.hpp" +#include "pugixml.hpp" namespace openmc { diff --git a/src/surface.h b/src/surface.h index 1d8cc6ac7b..666fc0dbae 100644 --- a/src/surface.h +++ b/src/surface.h @@ -6,7 +6,7 @@ #include #include "hdf5.h" -#include "pugixml/pugixml.hpp" +#include "pugixml.hpp" #include "constants.h" diff --git a/src/xml_interface.h b/src/xml_interface.h index b6f9e3246d..de89018efe 100644 --- a/src/xml_interface.h +++ b/src/xml_interface.h @@ -4,7 +4,7 @@ #include #include -#include "pugixml/pugixml.hpp" +#include "pugixml.hpp" namespace openmc { diff --git a/src/pugixml/pugiconfig.hpp b/vendor/pugixml/pugiconfig.hpp similarity index 100% rename from src/pugixml/pugiconfig.hpp rename to vendor/pugixml/pugiconfig.hpp diff --git a/src/pugixml/pugixml.cpp b/vendor/pugixml/pugixml.cpp similarity index 100% rename from src/pugixml/pugixml.cpp rename to vendor/pugixml/pugixml.cpp diff --git a/src/pugixml/pugixml.hpp b/vendor/pugixml/pugixml.hpp similarity index 100% rename from src/pugixml/pugixml.hpp rename to vendor/pugixml/pugixml.hpp From bd85855f122305c08f22a70d37c892b1a5f59d51 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 20 Jun 2018 12:01:51 -0500 Subject: [PATCH 041/100] Get rid of program variable in CMakeLists.txt --- CMakeLists.txt | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 047cb875b1..23728e3a76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -326,7 +326,6 @@ target_compile_options(faddeeva PRIVATE ${cflags}) # List source files. Define the libopenmc and the OpenMC executable #=============================================================================== -set(program "openmc") set(LIBOPENMC_FORTRAN_SRC src/algorithm.F90 src/angle_distribution.F90 @@ -456,20 +455,20 @@ add_library(libopenmc SHARED ${LIBOPENMC_FORTRAN_SRC} ${LIBOPENMC_CXX_SRC}) set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc PUBLIC_HEADER include/openmc.h) -add_executable(${program} src/main.cpp) +add_executable(openmc src/main.cpp) #=============================================================================== # Add compiler/linker flags #=============================================================================== -set_property(TARGET ${program} libopenmc +set_property(TARGET openmc libopenmc PROPERTY LINKER_LANGUAGE Fortran) target_include_directories(libopenmc PUBLIC include ${HDF5_INCLUDE_DIRS}) # The executable and the faddeeva package use only one language. They can be # set via target_compile_options which accepts a list. -target_compile_options(${program} PUBLIC ${cxxflags}) +target_compile_options(openmc PUBLIC ${cxxflags}) # The libopenmc library has both F90 and C++ so the compile flags must be set # file-by-file via set_source_file_properties. The compile flags must first be @@ -490,7 +489,7 @@ endforeach() # linker flags. Thus, we can pass both linker flags and libraries together. target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml faddeeva) -target_link_libraries(${program} ${ldflags} libopenmc) +target_link_libraries(openmc ${ldflags} libopenmc) #=============================================================================== # Python package @@ -506,7 +505,7 @@ add_custom_command(TARGET libopenmc POST_BUILD # Install executable, scripts, manpage, license #=============================================================================== -install(TARGETS ${program} libopenmc +install(TARGETS openmc libopenmc RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib @@ -514,4 +513,4 @@ install(TARGETS ${program} libopenmc ) install(DIRECTORY src/relaxng DESTINATION share/openmc) install(FILES man/man1/openmc.1 DESTINATION share/man/man1) -install(FILES LICENSE DESTINATION "share/doc/${program}" RENAME copyright) +install(FILES LICENSE DESTINATION "share/doc/openmc" RENAME copyright) From 3b806c8e4415d235e216c97c05b0eb0ad0d4d135 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 20 Jun 2018 12:22:48 -0500 Subject: [PATCH 042/100] Separate out setting properties for openmc executable --- CMakeLists.txt | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 23728e3a76..f0dac2c370 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -454,31 +454,23 @@ set(LIBOPENMC_CXX_SRC add_library(libopenmc SHARED ${LIBOPENMC_FORTRAN_SRC} ${LIBOPENMC_CXX_SRC}) set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc - PUBLIC_HEADER include/openmc.h) -add_executable(openmc src/main.cpp) + PUBLIC_HEADER include/openmc.h + LINKER_LANGUAGE Fortran) #=============================================================================== # Add compiler/linker flags #=============================================================================== -set_property(TARGET openmc libopenmc - PROPERTY LINKER_LANGUAGE Fortran) - target_include_directories(libopenmc PUBLIC include ${HDF5_INCLUDE_DIRS}) -# The executable and the faddeeva package use only one language. They can be -# set via target_compile_options which accepts a list. -target_compile_options(openmc PUBLIC ${cxxflags}) - # The libopenmc library has both F90 and C++ so the compile flags must be set -# file-by-file via set_source_file_properties. The compile flags must first be -# converted from lists to strings. -string(REPLACE ";" " " f90flags "${f90flags}") -string(REPLACE ";" " " cxxflags "${cxxflags}") -set_source_files_properties(${LIBOPENMC_FORTRAN_SRC} PROPERTIES COMPILE_FLAGS - ${f90flags}) -set_source_files_properties(${LIBOPENMC_CXX_SRC} PROPERTIES COMPILE_FLAGS - ${cxxflags}) +# file-by-file via set_source_file_properties. +set_property( + SOURCE ${LIBOPENMC_FORTRAN_SRC} + PROPERTY COMPILE_OPTIONS ${f90flags}) +set_property( + SOURCE ${LIBOPENMC_CXX_SRC} + PROPERTY COMPILE_OPTIONS ${cxxflags}) # Add HDF5 library directories to link line with -L foreach(LIBDIR ${HDF5_LIBRARY_DIRS}) @@ -489,7 +481,16 @@ endforeach() # linker flags. Thus, we can pass both linker flags and libraries together. target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml faddeeva) -target_link_libraries(openmc ${ldflags} libopenmc) + +#=============================================================================== +# openmc executable +#=============================================================================== + +add_executable(openmc src/main.cpp) +target_compile_options(openmc PUBLIC ${cxxflags}) +target_link_libraries(openmc libopenmc) +set_property(TARGET libopenmc + PROPERTY LINKER_LANGUAGE Fortran) #=============================================================================== # Python package From 18838b13edf83a49f1af745f3d0f4bbe53478252 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 20 Jun 2018 12:36:33 -0500 Subject: [PATCH 043/100] Make MPI, UNIX, MAX_COORD, and PHDF5 definitions specific to libopenmc --- CMakeLists.txt | 49 ++++++++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f0dac2c370..ca8658c5e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,14 +9,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # Set module path set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) -#=============================================================================== -# Architecture specific definitions -#=============================================================================== - -if (${UNIX}) - add_definitions(-DUNIX) -endif() - #=============================================================================== # Command line options #=============================================================================== @@ -27,10 +19,7 @@ option(debug "Compile with debug flags" OFF) option(optimize "Turn on all compiler optimization flags" OFF) option(coverage "Compile with coverage analysis flags" OFF) option(mpif08 "Use Fortran 2008 MPI interface" OFF) - -# Maximum number of nested coordinates levels set(maxcoord 10 CACHE STRING "Maximum number of nested coordinate levels") -add_definitions(-DMAX_COORD=${maxcoord}) #=============================================================================== # MPI for distributed-memory parallelism @@ -39,17 +28,12 @@ add_definitions(-DMAX_COORD=${maxcoord}) set(MPI_ENABLED FALSE) if($ENV{FC} MATCHES "(mpi[^/]*|ftn)$") message("-- Detected MPI wrapper: $ENV{FC}") - add_definitions(-DOPENMC_MPI) set(MPI_ENABLED TRUE) - - # Get directory containing MPI wrapper - get_filename_component(MPI_DIR $ENV{FC} DIRECTORY) endif() # Check for Fortran 2008 MPI interface if(MPI_ENABLED AND mpif08) message("-- Using Fortran 2008 MPI bindings") - add_definitions(-DOPENMC_MPIF08) endif() #=============================================================================== @@ -77,7 +61,6 @@ if(HDF5_IS_PARALLEL) if(NOT MPI_ENABLED) message(FATAL_ERROR "Parallel HDF5 must be used with MPI.") endif() - add_definitions(-DPHDF5) message("-- Using parallel HDF5") endif() @@ -316,14 +299,14 @@ if("${isSystemDir}" STREQUAL "-1") endif() #=============================================================================== -# Build faddeeva library +# faddeeva library #=============================================================================== add_library(faddeeva STATIC vendor/faddeeva/Faddeeva.c) target_compile_options(faddeeva PRIVATE ${cflags}) #=============================================================================== -# List source files. Define the libopenmc and the OpenMC executable +# libopenmc #=============================================================================== set(LIBOPENMC_FORTRAN_SRC @@ -457,11 +440,9 @@ set_target_properties(libopenmc PROPERTIES PUBLIC_HEADER include/openmc.h LINKER_LANGUAGE Fortran) -#=============================================================================== -# Add compiler/linker flags -#=============================================================================== - -target_include_directories(libopenmc PUBLIC include ${HDF5_INCLUDE_DIRS}) +target_include_directories(libopenmc + PUBLIC include + PRIVATE ${HDF5_INCLUDE_DIRS}) # The libopenmc library has both F90 and C++ so the compile flags must be set # file-by-file via set_source_file_properties. @@ -472,10 +453,20 @@ set_property( SOURCE ${LIBOPENMC_CXX_SRC} PROPERTY COMPILE_OPTIONS ${cxxflags}) -# Add HDF5 library directories to link line with -L -foreach(LIBDIR ${HDF5_LIBRARY_DIRS}) - list(APPEND ldflags "-L${LIBDIR}") -endforeach() +target_compile_definitions(libopenmc PRIVATE -DMAX_COORD=${maxcoord}) +if (UNIX) + # Used in progress_header.F90 for calling check_isatty + target_compile_definitions(libopenmc PRIVATE -DUNIX) +endif() +if (HDF5_IS_PARALLEL) + target_compile_definitions(libopenmc PRIVATE -DPHDF5) +endif() +if (MPI_ENABLED) + target_compile_definitions(libopenmc PUBLIC -DOPENMC_MPI) + if (mpif08) + target_compile_definitions(libopenmc PRIVATE -DOPENMC_MPIF08) + endif() +endif() # target_link_libraries treats any arguments starting with - but not -l as # linker flags. Thus, we can pass both linker flags and libraries together. @@ -487,7 +478,7 @@ target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml #=============================================================================== add_executable(openmc src/main.cpp) -target_compile_options(openmc PUBLIC ${cxxflags}) +target_compile_options(openmc PRIVATE ${cxxflags}) target_link_libraries(openmc libopenmc) set_property(TARGET libopenmc PROPERTY LINKER_LANGUAGE Fortran) From 695716de801176f7e43458a6e1df4b6f9e7e49dc Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 20 Jun 2018 13:08:05 -0500 Subject: [PATCH 044/100] Make GIT_SHA1 definition specific to libopenmc --- CMakeLists.txt | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ca8658c5e7..8aa2c6d915 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -250,19 +250,6 @@ message(STATUS "C flags: ${cflags}") message(STATUS "C++ flags: ${cxxflags}") message(STATUS "Linker flags: ${ldflags}") -#=============================================================================== -# git SHA1 hash -#=============================================================================== - -execute_process(COMMAND git rev-parse HEAD - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - RESULT_VARIABLE GIT_SHA1_SUCCESS - OUTPUT_VARIABLE GIT_SHA1 - ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) -if(GIT_SHA1_SUCCESS EQUAL 0) - add_definitions(-DGIT_SHA1="${GIT_SHA1}") -endif() - #=============================================================================== # pugixml library #=============================================================================== @@ -468,6 +455,16 @@ if (MPI_ENABLED) endif() endif() +# Set git SHA1 hash as a compile definition +execute_process(COMMAND git rev-parse HEAD + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + RESULT_VARIABLE GIT_SHA1_SUCCESS + OUTPUT_VARIABLE GIT_SHA1 + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) +if(GIT_SHA1_SUCCESS EQUAL 0) + target_compile_definitions(libopenmc PRIVATE -DGIT_SHA1="${GIT_SHA1}") +endif() + # target_link_libraries treats any arguments starting with - but not -l as # linker flags. Thus, we can pass both linker flags and libraries together. target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml From 08899b45d4e25fb7f7ee45a96c2a8242935d0205 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 20 Jun 2018 13:14:21 -0500 Subject: [PATCH 045/100] Use FindOpenMP to set flags. Bump required CMake version to 3.1 --- CMakeLists.txt | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8aa2c6d915..6b5806f26d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.0 FATAL_ERROR) +cmake_minimum_required(VERSION 3.1 FATAL_ERROR) project(openmc Fortran C CXX) # Setup output directories @@ -72,15 +72,14 @@ endif() # versions, we manually add the flags. However, at some point in time, the # manual logic can be removed in favor of the block below -#if(NOT (CMAKE_VERSION VERSION_LESS 3.1)) -# if(openmp) -# find_package(OpenMP) -# if(OPENMP_FOUND) -# list(APPEND f90flags ${OpenMP_Fortran_FLAGS}) -# list(APPEND ldflags ${OpenMP_Fortran_FLAGS}) -# endif() -# endif() -#endif() +if(openmp) + find_package(OpenMP) + if(OPENMP_FOUND) + list(APPEND f90flags ${OpenMP_Fortran_FLAGS}) + list(APPEND cxxflags ${OpenMP_CXX_FLAGS}) + list(APPEND ldflags ${OpenMP_Fortran_FLAGS}) + endif() +endif() set(CMAKE_POSITION_INDEPENDENT_CODE ON) @@ -108,10 +107,6 @@ if(CMAKE_Fortran_COMPILER_ID STREQUAL GNU) list(REMOVE_ITEM f90flags -O2) list(APPEND f90flags -O3) endif() - if(openmp) - list(APPEND f90flags -fopenmp) - list(APPEND ldflags -fopenmp) - endif() if(coverage) list(APPEND f90flags -coverage) list(APPEND ldflags -coverage) @@ -132,10 +127,6 @@ elseif(CMAKE_Fortran_COMPILER_ID STREQUAL Intel) if(optimize) list(APPEND f90flags -O3) endif() - if(openmp) - list(APPEND f90flags -qopenmp) - list(APPEND ldflags -qopenmp) - endif() elseif(CMAKE_Fortran_COMPILER_ID STREQUAL PGI) # PGI Fortran compiler options @@ -170,10 +161,6 @@ elseif(CMAKE_Fortran_COMPILER_ID STREQUAL XL) list(REMOVE_ITEM f90flags -O2) list(APPEND f90flags -O3) endif() - if(openmp) - list(APPEND f90flags -qsmp=omp) - list(APPEND ldflags -qsmp=omp) - endif() elseif(CMAKE_Fortran_COMPILER_ID STREQUAL Cray) # Cray Fortran compiler options @@ -240,9 +227,6 @@ if(optimize) list(REMOVE_ITEM cxxflags -O2) list(APPEND cxxflags -O3) endif() -if(openmp) - list(APPEND cxxflags -fopenmp) -endif() # Show flags being used message(STATUS "Fortran flags: ${f90flags}") From a4a87ee97d2f4ef80c3f2e8c7588efad22004117 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 20 Jun 2018 13:15:56 -0500 Subject: [PATCH 046/100] Two doc fixes --- docs/source/usersguide/tallies.rst | 2 +- openmc/filter_expansion.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/usersguide/tallies.rst b/docs/source/usersguide/tallies.rst index bbec016423..1210bc2820 100644 --- a/docs/source/usersguide/tallies.rst +++ b/docs/source/usersguide/tallies.rst @@ -213,7 +213,7 @@ The following tables show all valid scores: +----------------------+---------------------------------------------------+ |nu-fission |Total production of neutrons due to fission. | +----------------------+---------------------------------------------------+ - |nu-scatter, |This score is similar in functionality to the | + |nu-scatter |This score is similar in functionality to the | | |``scatter`` score except the total production of | | |neutrons due to scattering is scored vice simply | | |the scattering rate. This accounts for | diff --git a/openmc/filter_expansion.py b/openmc/filter_expansion.py index 5159cfd473..1970c07710 100644 --- a/openmc/filter_expansion.py +++ b/openmc/filter_expansion.py @@ -54,7 +54,7 @@ class LegendreFilter(ExpansionFilter): r"""Score Legendre expansion moments up to specified order. This filter allows scores to be multiplied by Legendre polynomials of the - change in particle angle ($\mu$) up to a user-specified order. + change in particle angle (:math:`\mu`) up to a user-specified order. Parameters ---------- From 573f612afe108ff607c056b315224e7c592e5d97 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 20 Jun 2018 15:48:14 -0500 Subject: [PATCH 047/100] Remove defunct from_ace routines --- src/endf_header.F90 | 56 --------------------------------------------- 1 file changed, 56 deletions(-) diff --git a/src/endf_header.F90 b/src/endf_header.F90 index 9443efe2be..d45fbe68f3 100644 --- a/src/endf_header.F90 +++ b/src/endf_header.F90 @@ -37,7 +37,6 @@ module endf_header contains procedure :: from_hdf5 => polynomial_from_hdf5 procedure :: evaluate => polynomial_evaluate - procedure :: from_ace => polynomial_from_ace end type Polynomial !=============================================================================== @@ -52,7 +51,6 @@ module endf_header real(8), allocatable :: x(:) ! values of abscissa real(8), allocatable :: y(:) ! values of ordinate contains - procedure :: from_ace => tabulated1d_from_ace procedure :: from_hdf5 => tabulated1d_from_hdf5 procedure :: evaluate => tabulated1d_evaluate end type Tabulated1D @@ -63,24 +61,6 @@ contains ! Polynomial implementation !=============================================================================== - subroutine polynomial_from_ace(this, xss, idx) - class(Polynomial), intent(inout) :: this - real(8), intent(in) :: xss(:) - integer, intent(in) :: idx - - integer :: nc ! number of coefficients (order - 1) - - ! Clear space - if (allocated(this % coef)) deallocate(this % coef) - - ! Determine number of coefficients - nc = nint(xss(idx)) - - ! Allocate space for and read coefficients - allocate(this % coef(nc)) - this % coef(:) = xss(idx + 1 : idx + nc) - end subroutine polynomial_from_ace - subroutine polynomial_from_hdf5(this, dset_id) class(Polynomial), intent(inout) :: this integer(HID_T), intent(in) :: dset_id @@ -111,42 +91,6 @@ contains ! Tabulated1D implementation !=============================================================================== - subroutine tabulated1d_from_ace(this, xss, idx) - class(Tabulated1D), intent(inout) :: this - real(8), intent(in) :: xss(:) - integer, intent(in) :: idx - - integer :: nr, ne - - ! Clear space - if (allocated(this % nbt)) deallocate(this % nbt) - if (allocated(this % int)) deallocate(this % int) - if (allocated(this % x)) deallocate(this % x) - if (allocated(this % y)) deallocate(this % y) - - ! Determine number of regions - nr = nint(xss(idx)) - this % n_regions = nr - - ! Read interpolation region data - if (nr > 0) then - allocate(this % nbt(nr)) - allocate(this % int(nr)) - this % nbt(:) = nint(xss(idx + 1 : idx + nr)) - this % int(:) = nint(xss(idx + nr + 1 : idx + 2*nr)) - end if - - ! Determine number of pairs - ne = int(XSS(idx + 2*nr + 1)) - this % n_pairs = ne - - ! Read (x,y) pairs - allocate(this % x(ne)) - allocate(this % y(ne)) - this % x(:) = xss(idx + 2*nr + 2 : idx + 2*nr + 1 + ne) - this % y(:) = xss(idx + 2*nr + 2 + ne : idx + 2*nr + 1 + 2*ne) - end subroutine tabulated1d_from_ace - subroutine tabulated1d_from_hdf5(this, dset_id) class(Tabulated1D), intent(inout) :: this integer(HID_T), intent(in) :: dset_id From 384982fa3667013bb79d0573c16b59ec3359dc19 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 20 Jun 2018 16:01:44 -0500 Subject: [PATCH 048/100] Get rid of SIGMA1 implementation that is not used/tested --- CMakeLists.txt | 1 - src/doppler.F90 | 216 ------------------------------------------------ 2 files changed, 217 deletions(-) delete mode 100644 src/doppler.F90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b5806f26d..61df522230 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -297,7 +297,6 @@ set(LIBOPENMC_FORTRAN_SRC src/dict_header.F90 src/distribution_multivariate.F90 src/distribution_univariate.F90 - src/doppler.F90 src/eigenvalue.F90 src/endf.F90 src/endf_header.F90 diff --git a/src/doppler.F90 b/src/doppler.F90 deleted file mode 100644 index 56c07c50eb..0000000000 --- a/src/doppler.F90 +++ /dev/null @@ -1,216 +0,0 @@ -module doppler - - use constants, only: ZERO, ONE, PI, K_BOLTZMANN - - implicit none - - real(8), parameter :: sqrt_pi_inv = ONE / sqrt(PI) - -contains - -!=============================================================================== -! BROADEN takes a microscopic cross section at a temperature T_1 and Doppler -! broadens it to a higher temperature T_2 based on a method originally developed -! by Cullen and Weisbin (see "Exact Doppler Broadening of Tabulated Cross -! Sections," Nucl. Sci. Eng. 60, 199-229 (1976)). The only difference here is -! the F functions are evaluated based on complementary error functions rather -! than error functions as is done in the BROADR module of NJOY. -!=============================================================================== - - subroutine broaden(energy, xs, A_target, T, sigmaNew) - - real(8), intent(in) :: energy(:) ! energy grid - real(8), intent(in) :: xs(:) ! unbroadened cross section - integer, intent(in) :: A_target ! mass number of target - real(8), intent(in) :: T ! temperature (difference) - real(8), intent(out) :: sigmaNew(:) ! broadened cross section - - integer :: i, k ! loop indices - integer :: n ! number of energy points - real(8) :: F_a(0:4) ! F(a) functions as per C&W - real(8) :: F_b(0:4) ! F(b) functions as per C&W - real(8) :: H(0:4) ! H functions as per C&W - real(8), allocatable :: x(:) ! proportional to relative velocity - real(8) :: y ! proportional to neutron velocity - real(8) :: y_sq ! y**2 - real(8) :: y_inv ! 1/y - real(8) :: y_inv_sq ! 1/y**2 - real(8) :: alpha ! constant equal to A/kT - real(8) :: slope ! slope of xs between adjacent points - real(8) :: Ak, Bk ! coefficients at each point - real(8) :: a, b ! values of x(k)-y and x(k+1)-y - real(8) :: sigma ! broadened cross section at one point - - ! Determine alpha parameter -- have to convert k to eV/K - alpha = A_target/(K_BOLTZMANN * T) - - ! Allocate memory for x and assign values - n = size(energy) - allocate(x(n)) - x = sqrt(alpha * energy) - - ! Loop over incoming neutron energies - ENERGY_NEUTRON: do i = 1, n - - sigma = ZERO - y = x(i) - y_sq = y*y - y_inv = ONE / y - y_inv_sq = y_inv / y - - ! ======================================================================= - ! EVALUATE FIRST TERM FROM x(k) - y = 0 to -4 - - k = i - a = ZERO - call calculate_F(F_a, a) - - do while (a >= -4.0 .and. k > 1) - ! Move to next point - F_b = F_a - k = k - 1 - a = x(k) - y - - ! Calculate F and H functions - call calculate_F(F_a, a) - H = F_a - F_b - - ! Calculate A(k), B(k), and slope terms - Ak = y_inv_sq*H(2) + 2.0*y_inv*H(1) + H(0) - Bk = y_inv_sq*H(4) + 4.0*y_inv*H(3) + 6.0*H(2) + 4.0*y*H(1) + y_sq*H(0) - slope = (xs(k+1) - xs(k)) / (x(k+1)**2 - x(k)**2) - - ! Add contribution to broadened cross section - sigma = sigma + Ak*(xs(k) - slope*x(k)**2) + slope*Bk - end do - - ! ======================================================================= - ! EXTEND CROSS SECTION TO 0 ASSUMING 1/V SHAPE - - if (k == 1 .and. a >= -4.0) then - ! Since x = 0, this implies that a = -y - F_b = F_a - a = -y - - ! Calculate F and H functions - call calculate_F(F_a, a) - H = F_a - F_b - - ! Add contribution to broadened cross section - sigma = sigma + xs(k)*x(k)*(y_inv_sq*H(1) + y_inv*H(0)) - end if - - ! ======================================================================= - ! EVALUATE FIRST TERM FROM x(k) - y = 0 to 4 - - k = i - b = ZERO - call calculate_F(F_b, b) - - do while (b <= 4.0 .and. k < n) - ! Move to next point - F_a = F_b - k = k + 1 - b = x(k) - y - - ! Calculate F and H functions - call calculate_F(F_b, b) - H = F_a - F_b - - ! Calculate A(k), B(k), and slope terms - Ak = y_inv_sq*H(2) + 2.0*y_inv*H(1) + H(0) - Bk = y_inv_sq*H(4) + 4.0*y_inv*H(3) + 6.0*H(2) + 4.0*y*H(1) + y_sq*H(0) - slope = (xs(k) - xs(k-1)) / (x(k)**2 - x(k-1)**2) - - ! Add contribution to broadened cross section - sigma = sigma + Ak*(xs(k) - slope*x(k)**2) + slope*Bk - end do - - ! ======================================================================= - ! EXTEND CROSS SECTION TO INFINITY ASSUMING CONSTANT SHAPE - - if (k == n .and. b <= 4.0) then - ! Calculate F function at last energy point - a = x(k) - y - call calculate_F(F_a, a) - - ! Add contribution to broadened cross section - sigma = sigma + xs(k) * (y_inv_sq*F_a(2) + 2.0*y_inv*F_a(1) + F_a(0)) - end if - - ! ======================================================================= - ! EVALUATE SECOND TERM FROM x(k) + y = 0 to +4 - - if (y <= 4.0) then - ! Swap signs on y - y = -y - y_inv = -y_inv - k = 1 - - ! Calculate a and b based on 0 and x(1) - a = -y - b = x(k) - y - - ! Calculate F and H functions - call calculate_F(F_a, a) - call calculate_F(F_b, b) - H = F_a - F_b - - ! Add contribution to broadened cross section - sigma = sigma - xs(k) * x(k) * (y_inv_sq*H(1) + y_inv*H(0)) - - ! Now progress forward doing the remainder of the second term - do while (b <= 4.0) - ! Move to next point - F_a = F_b - k = k + 1 - b = x(k) - y - - ! Calculate F and H functions - call calculate_F(F_b, b) - H = F_a - F_b - - ! Calculate A(k), B(k), and slope terms - Ak = y_inv_sq*H(2) + 2.0*y_inv*H(1) + H(0) - Bk = y_inv_sq*H(4) + 4.0*y_inv*H(3) + 6.0*H(2) + 4.0*y*H(1) & - + y_sq*H(0) - slope = (xs(k) - xs(k-1)) / (x(k)**2 - x(k-1)**2) - - ! Add contribution to broadened cross section - sigma = sigma - Ak*(xs(k) - slope*x(k)**2) - slope*Bk - end do - end if - - ! Set broadened cross section - sigmaNew(i) = sigma - - end do ENERGY_NEUTRON - - end subroutine broaden - -!=============================================================================== -! CALCULATE_F evaluates the function: -! -! F(n,a) = 1/sqrt(pi)*int(z^n*exp(-z^2), z = a to infinity) -! -! The five values returned in a vector correspond to the integral for n = 0 -! through 4. These functions are called over and over during the Doppler -! broadening routine. -!=============================================================================== - - subroutine calculate_F(F, a) - - real(8), intent(inout) :: F(0:4) - real(8), intent(in) :: a - -#ifndef NO_F2008 - F(0) = 0.5*erfc(a) -#endif - F(1) = 0.5*sqrt_pi_inv*exp(-a*a) - F(2) = 0.5*F(0) + a*F(1) - F(3) = F(1)*(1.0 + a*a) - F(4) = 0.75*F(0) + F(1)*a*(1.5 + a*a) - - end subroutine calculate_F - -end module doppler From 610fc5c9188405c6edacb30ef4b4c965cd3a1595 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 20 Jun 2018 16:09:24 -0500 Subject: [PATCH 049/100] Use generator expression to handle compile options for Fortran/C++ separately --- CMakeLists.txt | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 61df522230..adf2126826 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1 FATAL_ERROR) +cmake_minimum_required(VERSION 3.3 FATAL_ERROR) project(openmc Fortran C CXX) # Setup output directories @@ -68,11 +68,8 @@ endif() # Set compile/link flags based on which compiler is being used #=============================================================================== -# Support for Fortran in FindOpenMP was added in CMake 3.1. To support lower -# versions, we manually add the flags. However, at some point in time, the -# manual logic can be removed in favor of the block below - if(openmp) + # Requires CMake 3.1+ find_package(OpenMP) if(OPENMP_FOUND) list(APPEND f90flags ${OpenMP_Fortran_FLAGS}) @@ -248,7 +245,7 @@ target_include_directories(pugixml PUBLIC vendor/pugixml/) # This block of code ensures that dynamic libraries can be found via the RPATH # whether the executable is the original one from the build directory or the # installed one in CMAKE_INSTALL_PREFIX. Ref: -# https://cmake.org/Wiki/CMake_RPATH_handling#Always_full_RPATH +# https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/RPATH-handling # use, i.e. don't skip the full RPATH for the build tree set(CMAKE_SKIP_BUILD_RPATH FALSE) @@ -280,7 +277,7 @@ target_compile_options(faddeeva PRIVATE ${cflags}) # libopenmc #=============================================================================== -set(LIBOPENMC_FORTRAN_SRC +add_library(libopenmc SHARED src/algorithm.F90 src/angle_distribution.F90 src/angleenergy_header.F90 @@ -382,8 +379,6 @@ set(LIBOPENMC_FORTRAN_SRC src/tallies/tally_header.F90 src/tallies/trigger.F90 src/tallies/trigger_header.F90 -) -set(LIBOPENMC_CXX_SRC src/cell.cpp src/initialize.cpp src/finalize.cpp @@ -404,7 +399,6 @@ set(LIBOPENMC_CXX_SRC src/surface.cpp src/xml_interface.cpp src/xsdata.cpp) -add_library(libopenmc SHARED ${LIBOPENMC_FORTRAN_SRC} ${LIBOPENMC_CXX_SRC}) set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc PUBLIC_HEADER include/openmc.h @@ -415,13 +409,11 @@ target_include_directories(libopenmc PRIVATE ${HDF5_INCLUDE_DIRS}) # The libopenmc library has both F90 and C++ so the compile flags must be set -# file-by-file via set_source_file_properties. -set_property( - SOURCE ${LIBOPENMC_FORTRAN_SRC} - PROPERTY COMPILE_OPTIONS ${f90flags}) -set_property( - SOURCE ${LIBOPENMC_CXX_SRC} - PROPERTY COMPILE_OPTIONS ${cxxflags}) +# differently depending on the language. The $ generator +# expression was added in CMake 3.3 +target_compile_options(libopenmc PRIVATE + $<$:${f90flags}> + $<$:${cxxflags}>) target_compile_definitions(libopenmc PRIVATE -DMAX_COORD=${maxcoord}) if (UNIX) From 36db02bad3e354ffa6c61e8ed3ecb7bfe74d93b3 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 20 Jun 2018 16:25:45 -0500 Subject: [PATCH 050/100] Use C_STANDARD property on faddeeva library --- CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index adf2126826..1fd03c37b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,7 +171,7 @@ endif() if(CMAKE_C_COMPILER_ID STREQUAL GNU) # GCC compiler options - list(APPEND cflags -std=c99 -O2) + list(APPEND cflags -O2) if(debug) list(REMOVE_ITEM cflags -O2) list(APPEND cflags -g -Wall -pedantic -fbounds-check) @@ -189,7 +189,6 @@ if(CMAKE_C_COMPILER_ID STREQUAL GNU) elseif(CMAKE_C_COMPILER_ID STREQUAL Intel) # Intel compiler options - list(APPEND cflags -std=c99) if(debug) list(APPEND cflags -g -w3 -ftrapuv -fp-stack-check -O0) endif() @@ -202,7 +201,6 @@ elseif(CMAKE_C_COMPILER_ID STREQUAL Intel) elseif(CMAKE_C_COMPILER_ID MATCHES Clang) # Clang options - list(APPEND cflags -std=c99) if(debug) list(APPEND cflags -g -O0 -ftrapv) endif() @@ -272,6 +270,9 @@ endif() add_library(faddeeva STATIC vendor/faddeeva/Faddeeva.c) target_compile_options(faddeeva PRIVATE ${cflags}) +set_target_properties(faddeeva PROPERTIES + C_STANDARD 99 + C_STANDARD_REQUIRED ON) #=============================================================================== # libopenmc From 459fc8e12c1aa40d596c64c51bcce5fa52dc2143 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 21 Jun 2018 15:30:29 -0500 Subject: [PATCH 051/100] Dont modify linker_language for executable --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fd03c37b8..15c89142e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -453,8 +453,6 @@ target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml add_executable(openmc src/main.cpp) target_compile_options(openmc PRIVATE ${cxxflags}) target_link_libraries(openmc libopenmc) -set_property(TARGET libopenmc - PROPERTY LINKER_LANGUAGE Fortran) #=============================================================================== # Python package From 1145c918056d09fe6f71385242f77f9464ae06a5 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 28 Jun 2018 17:11:52 -0500 Subject: [PATCH 052/100] Add n_nuclides in openmc.h --- include/openmc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/openmc.h b/include/openmc.h index 2c0f10eae0..03597e5a10 100644 --- a/include/openmc.h +++ b/include/openmc.h @@ -134,6 +134,7 @@ extern "C" { extern int32_t n_lattices; extern int32_t n_materials; extern int32_t n_meshes; + extern int n_nuclides; extern int64_t n_particles; extern int32_t n_plots; extern int32_t n_realizations; From 3647306d5c7cf90d3189dc5146aa9833ac9ef95e Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 3 Jul 2018 16:29:44 -0500 Subject: [PATCH 053/100] Restructuring of classes, better handling of file 2 contribution --- openmc/data/neutron.py | 2 +- openmc/data/resonance_covariance.py | 563 ++++++++++++++-------------- 2 files changed, 278 insertions(+), 287 deletions(-) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index e35dd5ab36..7a9b41fd9b 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -803,7 +803,7 @@ class IncidentNeutron(EqualityMixin): data.resonances = res.Resonances.from_endf(ev) if (32, 151) in ev.section and get_covariance: - data.res_covariance = res_cov.ResonanceCovariance.from_endf(ev) + data.res_covariance = res_cov.ResonanceCovariances.from_endf(ev, data.resonances) # Read each reaction for mf, mt, nc, mod in ev.reaction_list: diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index b35c070949..d8c0236ff6 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -10,203 +10,54 @@ import pandas as pd from .data import NEUTRON_MASS from .endf import get_head_record, get_cont_record, get_tab1_record, get_list_record, get_intg_record import openmc.checkvalue as cv -from .resonance import ResonanceRange +from .resonance import Resonances -def res_subset(nuclide, parameter_str, bounds): - """Produce a subset of resonance paramaters and the covariance matrix - to an IncidentNeutron objecti - - Parameters - ---------- - nuclide: ResonanceCovariance object - parameter_str: paramater to be discriminated - (i.e. 'energy','captureWidth','fissionWidthA'...) - bounds: np.array [low numerical bound, high numerical bound] +def file2contributions(file32params, file2params): + """Function for aiding in adding resonance parameters from File 2 that are + not always present in file 32. + + Paramateers + ----------- + file2params: pandas.Dataframe + Resonance parameters from File 2. Ordered by energy. + file32params: pandas.Dataframe + Incomplete set of resonance parameters contained in File 32. Returns ------- - parameters_subset : Dataframe of a subset of parameters - (maintains indexing) - cov_subset: subset of covariance matrix (upper triangular) - + parameters: pandas.Dataframs + Complete set of parameters ordered by L-values and then energy """ - parameters = nuclide.parameters - cov = nuclide.covariance - mpar = nuclide.mpar - mask1 = parameters[parameter_str]>=bounds[0] - mask2 = parameters[parameter_str]<=bounds[1] - mask = mask1 & mask2 - parameters_subset=parameters[mask] - indices = parameters_subset.index.values - sub_cov_dim = len(indices)*mpar - oldvalues = [] - for index1 in indices: - for i in range(mpar): - for index2 in indices: - for j in range(mpar): - if index2*mpar+j >= index1*mpar+i: - oldvalues.append(cov[index1*mpar+i,index2*mpar+j]) + #Use l-values and competitiveWidth from File 2 data + #Re-sort File 2 by energy to match File 32 + file2params=file2params.sort_values(by=['energy']) + file2params=file2params.reset_index(drop=True) + #Sort File 32 parameters by energy as well (maintaining index) + file32params_sort = file32params.sort_values(by=['energy']) + #Add in values (.values converts to array first to ignore index) + file32params_sort['L'] = file2params['L'].values + if 'competiveWidth' in file32params_sort: + file32params_sort['competitiveWidth'] = file2params['competitiveWidth'].values + #Resort to File 32 order (by L then by E) for use with covariance + parameters = file32params_sort.sort_index() - cov_subset = np.zeros([sub_cov_dim,sub_cov_dim]) - tri_indices = np.triu_indices(sub_cov_dim) - cov_subset[tri_indices] = oldvalues - - nuclide.parameters_subset = parameters_subset - nuclide.cov_subset = cov_subset - -def sample_resonance_parameters(nuclide, n_samples, use_subset=False): - """Return a IncidentNeutron object with n_samples of xs - - Parameters - ---------- - nuclide: IncidentNeutron object with resonance covariance data - - Returns - ------- - ev : openmc.data.endf.Evaluation - - """ - if use_subset==False: - parameters = nuclide.parameters - cov = nuclide.covariance - else: - parameters = nuclide.parameters_subset - cov = nuclide.cov_subset - nparams,params = parameters.shape - cov = cov + cov.T - np.diag(cov.diagonal()) #symmetrizing covariance matrix - covsize = cov.shape[0] - formalism = nuclide.formalism - mpar = nuclide.mpar - samples = [] + return parameters - ### Handling MLBW Sampling ### - if formalism == 'mlbw' or formalism == 'slbw': - if mpar == 3: - param_list = ['energy','neutronWidth','captureWidth'] - mean_array = pd.DataFrame.as_matrix(parameters[param_list]) - spin = pd.DataFrame.as_matrix(parameters['J']) - gf = pd.DataFrame.as_matrix(parameters['fissionWidth']) - mean = mean_array.flatten() - for i in range(n_samples): - sample = np.random.multivariate_normal(mean,cov) - energy = sample[0::3] - gn = sample[1::3] - gg = sample[2::3] - gt = gn + gg + gf - records = [] - for j, E in enumerate(energy): - records.append([energy[j], spin[j], gt[j], gn[j], - gg[j], gf[j]]) - columns = ['energy', 'J', 'totalWidth', 'neutronWidth', - 'captureWidth', 'fissionWidth'] - sample_params = pd.DataFrame.from_records(records, columns=columns) - samples.append(sample_params) - - elif mpar == 4: - param_list = ['energy','neutronWidth','captureWidth','fissionWidth'] - mean_array = pd.DataFrame.as_matrix(parameters[param_list]) - spin = pd.DataFrame.as_matrix(parameters['J']) - mean = mean_array.flatten() - for i in range(n_samples): - sample = np.random.multivariate_normal(mean,cov) - energy = sample[0::4] - gn = sample[1::4] - gg = sample[2::4] - gf = sample[3::4] - gt = gn + gg + gf - records = [] - for j, E in enumerate(energy): - records.append([energy[j], spin[j], gt[j], gn[j], - gg[j], gf[j]]) - columns = ['energy', 'J', 'totalWidth', 'neutronWidth', - 'captureWidth', 'fissionWidth'] - sample_params = pd.DataFrame.from_records(records, columns=columns) - samples.append(sample_params) - - elif mpar == 5: - param_list = ['energy','neutronWidth','captureWidth','fissionWidth'] - mean_array = pd.DataFrame.as_matrix(parameters[param_list]) - spin = pd.DataFrame.as_matrix(parameters['J']) - mean = mean_array.flatten() - for i in range(n_samples): - sample = np.random.multivariate_normal(mean,cov) - energy = sample[0::4] - gn = sample[1::4] - gg = sample[2::4] - gf = sample[3::4] - gt = gn + gg + gf - records = [] - for j, E in enumerate(energy): - records.append([energy[j], spin[j], gt[j], gn[j], - gg[j], gf[j]]) - columns = ['energy', 'J', 'totalWidth', 'neutronWidth', - 'captureWidth', 'fissionWidth'] - sample_params = pd.DataFrame.from_records(records, columns=columns) - samples.append(sample_params) - ### Handling RM Sampling ### - if formalism == 'rm': - if mpar == 3: - param_list = ['energy','neutronWidth','captureWidth'] - mean_array = pd.DataFrame.as_matrix(parameters[param_list]) - spin = pd.DataFrame.as_matrix(parameters['J']) - gfa = pd.DataFrame.as_matrix(parameters['fissionWidthA']) - gfb = pd.DataFrame.as_matrix(parameters['fissionWidthB']) - mean = mean_array.flatten() - for i in range(n_samples): - sample = np.random.multivariate_normal(mean,cov) - energy = sample[0::3] - gn = sample[1::3] - gg = sample[2::3] - records = [] - for j, E in enumerate(energy): - records.append([energy[j], spin[j], gn[j], - gg[j], gfa[j], gfb[j]]) - columns = ['energy', 'J', 'neutronWidth', - 'captureWidth', 'fissionWidthA','fissionWidthB'] - sample_params = pd.DataFrame.from_records(records, columns=columns) - samples.append(sample_params) - - elif mpar == 5: - param_list = ['energy','neutronWidth','captureWidth','fissionWidthA','fissionWidthB'] - mean_array = pd.DataFrame.as_matrix(parameters[param_list]) - spin = pd.DataFrame.as_matrix(parameters['J']) - mean = mean_array.flatten() - for i in range(n_samples): - sample = np.random.multivariate_normal(mean,cov) - energy = sample[0::5] - gn = sample[1::5] - gg = sample[2::5] - gfa = sample[3::5] - gfb = sample[4::5] - records = [] - for j, E in enumerate(energy): - records.append([energy[j], spin[j], gn[j], - gg[j], gfa[j], gfb[j]]) - columns = ['energy', 'J', 'neutronWidth', - 'captureWidth', 'fissionWidthA','fissionWidthB'] - sample_params = pd.DataFrame.from_records(records, columns=columns) - samples.append(sample_params) - - nuclide.samples = samples - -class ResonanceCovariance(object): +class ResonanceCovariances(Resonances): """Resolved resonance covariance data Parameters ---------- - ranges : list of openmc.data.ResonanceRange + ranges : list of openmc.data.ResonanceCovarianceRange Distinct energy ranges for resonance data Attributes ---------- - ranges : list of openmc.data.ResonanceRange + ranges : list of openmc.data.ResonanceCovarianceRange Distinct energy ranges for resonance data - resolved : openmc.data.ResonanceRange or None + resolved : openmc.data.ResonanceCovariance or None Resolved resonance range - unresolved : openmc.data.Unresolved or None - Unresolved resonance range - """ def __init__(self, ranges): @@ -223,7 +74,7 @@ class ResonanceCovariance(object): @ranges.setter def ranges(self, ranges): cv.check_type('resonance ranges', ranges, MutableSequence) - self._ranges = cv.CheckedList(ResonanceRange, 'resonance ranges', + self._ranges = cv.CheckedList(ResonanceCovarianceRange, 'resonance range', ranges) @classmethod @@ -238,7 +89,7 @@ class ResonanceCovariance(object): Returns ------- - openmc.data.ResonanceCovariance + openmc.data.ResonanceCovariances Resonance covariance data """ @@ -257,7 +108,9 @@ class ResonanceCovariance(object): for j in range(n_ranges): items = get_cont_record(file_obj) - resonance_flag = items[2] # flag for resolved (1)/unresolved (2) + unresolved_flag = items[2] # 0: only scattering radius given + # 1: resolved parameters given + # 2: unresolved parameters given formalism = items[3] # resonance formalism # Throw error for unsupported formalisms @@ -265,11 +118,12 @@ class ResonanceCovariance(object): raise TypeError('LRF= ', formalism, 'covariance not supported for this formalism') - if resonance_flag in (0, 1): + if unresolved_flag in (0,1): # resolved resonance region - erange = _FORMALISMS[formalism].from_endf(ev, file_obj, items, resonances) - - elif resonance_flag == 2: + file2params = resonances.ranges[j].parameters + erange = _FORMALISMS[formalism].from_endf(ev, file_obj, + items, file2params) + elif unresolved_flag == 2: warnings.warn('Unresolved resonance not supported.' 'Covariance values for the' 'unresolved region not imported.') @@ -277,26 +131,9 @@ class ResonanceCovariance(object): return cls(ranges) -class MultiLevelBreitWignerCovariance(ResonanceRange): - """Multi-level Breit-Wigner resolved resonance formalism covariance data. - Multi-level Breit-Wigner resolved resonance data is identified by LRF=2 in - the ENDF-6 format. - - Parameters - ---------- - target_spin : float - Intrinsic spin, :math:`I`, of the target nuclide - energy_min : float - Minimum energy of the resolved resonance range in eV - energy_max : float - Maximum energy of the resolved resonance range in eV - channel : dict - Dictionary whose keys are l-values and values are channel radii as a - function of energy - scattering : dict - Dictionary whose keys are l-values and values are scattering radii as a - function of energy +class ResonanceCovarianceRange(object): + """Resonace covariance range Attributes ---------- @@ -306,17 +143,229 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): The covariance matrix contained within the ENDF evaluation lcomp : int Flag indicating the format of the covariance matrix + mpar : int + Number of parameters in covariance matrix for each individual resonance + """ + + + @classmethod + def res_subset(cls, parameter_str, bounds): + """Produce a subset of resonance parameters and the covariance matrix + to an IncidentNeutron object. + + Parameters + ---------- + parameter_str: parameter to be discriminated + (i.e. 'energy','captureWidth','fissionWidthA'...) + bounds: np.array [low numerical bound, high numerical bound] + + Returns + ------- + parameters_subset : Dataframe of a subset of parameters + (maintains indexing) + cov_subset: subset of covariance matrix (upper triangular) + + """ + parameters = cls.parameters + cov = cls.covariance + mpar = cls.mpar + mask1 = parameters[parameter_str]>=bounds[0] + mask2 = parameters[parameter_str]<=bounds[1] + mask = mask1 & mask2 + parameters_subset=parameters[mask] + indices = parameters_subset.index.values + sub_cov_dim = len(indices)*mpar + oldvalues = [] + for index1 in indices: + for i in range(mpar): + for index2 in indices: + for j in range(mpar): + if index2*mpar+j >= index1*mpar+i: + oldvalues.append(cov[index1*mpar+i,index2*mpar+j]) + + cov_subset = np.zeros([sub_cov_dim,sub_cov_dim]) + tri_indices = np.triu_indices(sub_cov_dim) + cov_subset[tri_indices] = oldvalues + + cls.parameters_subset = parameters_subset + cls.cov_subset = cov_subset + + @classmethod + def sample_resonance_parameters(cls, n_samples, use_subset=False): + """Return a IncidentNeutron object with n_samples of xs + + Parameters + ---------- + n_samples: int + The number of samples to produce + use_subset: bool, optional + Flag on whether to sample from an already produced subset + + Returns + ------- + + """ + print('Begin sampling') + print((cls)) + print(dir(cls)) + print(vars(cls)) + if use_subset==False: + parameters = cls.parameters + cov = cls.covariance + else: + if cls.parameters_subset is None: + raise ValueError('No subset of resonances defined') + parameters = cls.parameters_subset + cov = cls.cov_subset + + nparams,params = parameters.shape + cov = cov + cov.T - np.diag(cov.diagonal()) #symmetrizing covariance matrix + covsize = cov.shape[0] + formalism = cls.formalism + mpar = cls.mpar + samples = [] + + + ### Handling MLBW Sampling ### + if formalism == 'mlbw' or formalism == 'slbw': + if mpar == 3: + param_list = ['energy','neutronWidth','captureWidth'] + mean_array = pd.DataFrame.as_matrix(parameters[param_list]) + spin = pd.DataFrame.as_matrix(parameters['J']) + gf = pd.DataFrame.as_matrix(parameters['fissionWidth']) + mean = mean_array.flatten() + for i in range(n_samples): + sample = np.random.multivariate_normal(mean,cov) + energy = sample[0::3] + gn = sample[1::3] + gg = sample[2::3] + gt = gn + gg + gf + records = [] + for j, E in enumerate(energy): + records.append([energy[j], spin[j], gt[j], gn[j], + gg[j], gf[j]]) + columns = ['energy', 'J', 'totalWidth', 'neutronWidth', + 'captureWidth', 'fissionWidth'] + sample_params = pd.DataFrame.from_records(records, columns=columns) + samples.append(sample_params) + + elif mpar == 4: + param_list = ['energy','neutronWidth','captureWidth','fissionWidth'] + mean_array = pd.DataFrame.as_matrix(parameters[param_list]) + spin = pd.DataFrame.as_matrix(parameters['J']) + mean = mean_array.flatten() + for i in range(n_samples): + sample = np.random.multivariate_normal(mean,cov) + energy = sample[0::4] + gn = sample[1::4] + gg = sample[2::4] + gf = sample[3::4] + gt = gn + gg + gf + records = [] + for j, E in enumerate(energy): + records.append([energy[j], spin[j], gt[j], gn[j], + gg[j], gf[j]]) + columns = ['energy', 'J', 'totalWidth', 'neutronWidth', + 'captureWidth', 'fissionWidth'] + sample_params = pd.DataFrame.from_records(records, columns=columns) + samples.append(sample_params) + + elif mpar == 5: + param_list = ['energy','neutronWidth','captureWidth','fissionWidth'] + mean_array = pd.DataFrame.as_matrix(parameters[param_list]) + spin = pd.DataFrame.as_matrix(parameters['J']) + mean = mean_array.flatten() + for i in range(n_samples): + sample = np.random.multivariate_normal(mean,cov) + energy = sample[0::4] + gn = sample[1::4] + gg = sample[2::4] + gf = sample[3::4] + gt = gn + gg + gf + records = [] + for j, E in enumerate(energy): + records.append([energy[j], spin[j], gt[j], gn[j], + gg[j], gf[j]]) + columns = ['energy', 'J', 'totalWidth', 'neutronWidth', + 'captureWidth', 'fissionWidth'] + sample_params = pd.DataFrame.from_records(records, columns=columns) + samples.append(sample_params) + + ### Handling RM Sampling ### + if formalism == 'rm': + if mpar == 3: + param_list = ['energy','neutronWidth','captureWidth'] + mean_array = pd.DataFrame.as_matrix(parameters[param_list]) + spin = pd.DataFrame.as_matrix(parameters['J']) + gfa = pd.DataFrame.as_matrix(parameters['fissionWidthA']) + gfb = pd.DataFrame.as_matrix(parameters['fissionWidthB']) + mean = mean_array.flatten() + for i in range(n_samples): + sample = np.random.multivariate_normal(mean,cov) + energy = sample[0::3] + gn = sample[1::3] + gg = sample[2::3] + records = [] + for j, E in enumerate(energy): + records.append([energy[j], spin[j], gn[j], + gg[j], gfa[j], gfb[j]]) + columns = ['energy', 'J', 'neutronWidth', + 'captureWidth', 'fissionWidthA','fissionWidthB'] + sample_params = pd.DataFrame.from_records(records, columns=columns) + samples.append(sample_params) + + elif mpar == 5: + param_list = ['energy','neutronWidth','captureWidth','fissionWidthA','fissionWidthB'] + mean_array = pd.DataFrame.as_matrix(parameters[param_list]) + spin = pd.DataFrame.as_matrix(parameters['J']) + mean = mean_array.flatten() + for i in range(n_samples): + sample = np.random.multivariate_normal(mean,cov) + energy = sample[0::5] + gn = sample[1::5] + gg = sample[2::5] + gfa = sample[3::5] + gfb = sample[4::5] + records = [] + for j, E in enumerate(energy): + records.append([energy[j], spin[j], gn[j], + gg[j], gfa[j], gfb[j]]) + columns = ['energy', 'J', 'neutronWidth', + 'captureWidth', 'fissionWidthA','fissionWidthB'] + sample_params = pd.DataFrame.from_records(records, columns=columns) + samples.append(sample_params) + + cls.samples = samples + +class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): + """Multi-level Breit-Wigner resolved resonance formalism covariance data. + + Multi-level Breit-Wigner resolved resonance data is identified by LRF=2 in + the ENDF-6 format. + + Attributes + ---------- + cov_parameters: list + The parameters that are included in the covariance matrix + covariance_matrix : array + The covariance matrix contained within the ENDF evaluation + lcomp : int + Flag indicating the format of the covariance matrix + mpar : int + Number of parameters in covariance matrix for each individual resonance """ def __init__(self, energy_min, energy_max): self.parameters = None self.covariance = None + self.mpar = None + self.lcomp = None self.num_parameters = None self.formalism = 'mlbw' - + @classmethod - def from_endf(cls, ev, file_obj, items, resonances): + def from_endf(cls, ev, file_obj, items, file2params): """Create MLBW covariance data from an ENDF evaluation. Parameters @@ -325,11 +374,11 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): ENDF evaluation file_obj : file-like object ENDF file positioned at the second record of a resonance range - subsection in MF=2, MT=151 + subsection in MF=32, MT=151 items : list Items from the CONT record at the start of the resonance range subsection - resonances : Resonance object + resonances : openmc.data.IncidentNeutron.Resonance Returns ------- @@ -398,17 +447,8 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): covsize = cov.shape[0] mpar = int(covsize/nparams) - #Use l-values and competitiveWidth from File 2 data - #Resort File 2 by energy to match File 32 - file2parameters=resonances.ranges[0].parameters.sort_values(by=['energy']) - file2parameters=file2parameters.reset_index(drop=True) - #Sort File 32 parameters by energy as well (maintaining index) - parameters_sort = parameters.sort_values(by=['energy']) - #Add in values (.values converts to array first to ignore index) - parameters_sort['L'] = file2parameters['L'].values - parameters_sort['competitiveWidth'] = file2parameters['competitiveWidth'].values - #Resort to File 32 order (essential for use with covariance!) - parameters = parameters_sort.sort_index() + #Add parameters from File 2 + parameters = file2contributions(parameters, file2params) # Create instance of class mlbw = cls(energy_min, energy_max) @@ -463,18 +503,8 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): covsize = cov.shape[0] mpar = int(covsize/nparams) - #Use l-values and competitiveWidth from File 2 data - #Resort File 2 by energy to match File 32 - file2parameters=resonances.ranges[0].parameters.sort_values(by=['energy']) - file2parameters=file2parameters.reset_index(drop=True) - #Sort File 32 parameters by energy as well (maintaining index) - parameters_sort = parameters.sort_values(by=['energy']) - #Add in values (.values converts to array first to ignore index) - parameters_sort['L'] = file2parameters['L'].values - parameters_sort['competitiveWidth'] = file2parameters['competitiveWidth'].values - #Resort to File 32 order (essential for use with covariance!) - parameters = parameters_sort.sort_index() - + #Add parameters from File 2 + parameters = file2contributions(parameter, file2params) # Create instance of MultiLevelBreitWignerCovariance mlbw = cls(energy_min, energy_max) @@ -532,18 +562,8 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): covsize = cov.shape[0] mpar = int(covsize/nparams) - #Use l-values and competitiveWidth from File 2 data - #Resort File 2 by energy to match File 32 - file2parameters=resonances.ranges[0].parameters.sort_values(by=['energy']) - file2parameters=file2parameters.reset_index(drop=True) - #Sort File 32 parameters by energy as well (maintaining index) - parameters_sort = parameters.sort_values(by=['energy']) - #Add in values (.values converts to array first to ignore index) - parameters_sort['L'] = file2parameters['L'].values - parameters_sort['competitiveWidth'] = file2parameters['competitiveWidth'].values - #Resort to File 32 order (essential for use with covariance!) - parameters = parameters_sort.sort_index() - + #Add parameters from File 2 + parameters = file2contributions(parameter, file2params) # Create instance of class mlbw = cls(energy_min, energy_max) @@ -554,12 +574,6 @@ class MultiLevelBreitWignerCovariance(ResonanceRange): return mlbw - def subset(self, parameter_str, bounds): - res_subset(self, parameter_str, bounds) - - def sample(self, n_samples, use_subset=False): - sample_resonance_parameters(self,n_samples,use_subset) - class SingleLevelBreitWignerCovariance(MultiLevelBreitWignerCovariance): """Single-level Breit-Wigner resolved resonance formalism covariance data. @@ -612,7 +626,7 @@ class SingleLevelBreitWignerCovariance(MultiLevelBreitWignerCovariance): def __init__(self, energy_min, energy_max): self.formalism = 'slbw' -class ReichMooreCovariance(ResonanceRange): +class ReichMooreCovariance(ResonanceCovarianceRange): """Reich-Moore resolved resonance formalism covariance data. Reich-Moore resolved resonance data is identified by LRF=3 in the ENDF-6 @@ -654,7 +668,7 @@ class ReichMooreCovariance(ResonanceRange): self.formalism = 'rm' @classmethod - def from_endf(cls, ev, file_obj, items, resonances): + def from_endf(cls, ev, file_obj, items, file2params): """Create Reich-Moore resonance covariance data from an ENDF evaluation. Includes the resonance parameters contained separately in File 32. @@ -737,16 +751,8 @@ class ReichMooreCovariance(ResonanceRange): covsize = cov.shape[0] mpar = int(covsize/nparams) - #Use l-values and competitiveWidth from File 2 data - #Resort File 2 by energy to match File 32 - file2parameters=resonances.ranges[0].parameters.sort_values(by=['energy']) - file2parameters=file2parameters.reset_index(drop=True) - #Sort File 32 parameters by energy as well (maintaining index) - parameters_sort = parameters.sort_values(by=['energy']) - #Add in values (.values converts to array first to ignore index) - parameters_sort['L'] = file2parameters['L'].values - #Resort to File 32 order (essential for use with covariance!) - parameters = parameters_sort.sort_index() + #Add parameters from File 2 + parameters = file2contributions(parameter, file2params) # Create instance of ReichMooreCovariance rmc = cls(energy_min, energy_max) @@ -794,16 +800,8 @@ class ReichMooreCovariance(ResonanceRange): covsize = cov.shape[0] mpar = int(covsize/nparams) - #Use l-values and competitiveWidth from File 2 data - #Resort File 2 by energy to match File 32 - file2parameters=resonances.ranges[0].parameters.sort_values(by=['energy']) - file2parameters=file2parameters.reset_index(drop=True) - #Sort File 32 parameters by energy as well (maintaining index) - parameters_sort = parameters.sort_values(by=['energy']) - #Add in values (.values converts to array first to ignore index) - parameters_sort['L'] = file2parameters['L'].values - #Resort to File 32 order (essential for use with covariance!) - parameters = parameters_sort.sort_index() + #Add parameters from File 2 + parameters = file2contributions(parameter, file2params) # Create instance of ReichMooreCovariance rmc = cls(energy_min, energy_max) @@ -814,19 +812,12 @@ class ReichMooreCovariance(ResonanceRange): return rmc - def subset(self, parameter_str, bounds): - res_subset(self, parameter_str, bounds) - - def sample(self, n_samples, use_subset=False): - sample_resonance_parameters(self,n_samples,use_subset) - -# _FORMALISMS = {0: ResonanceRange, -# 1: SingleLevelBreitWigner, -# 2: MultiLevelBreitWigner, -# 3: ReichMoore, -# 7: RMatrixLimited} -_FORMALISMS = {1: SingleLevelBreitWignerCovariance, +_FORMALISMS = { + 0: ResonanceCovarianceRange, + 1: SingleLevelBreitWignerCovariance, 2: MultiLevelBreitWignerCovariance, - 3: ReichMooreCovariance} - + 3: ReichMooreCovariance + # 7: RMatrixLimitedCovariance + } + From a0182e12d6431d82ec9039be4f87473646565cee Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 3 Jul 2018 17:10:08 -0500 Subject: [PATCH 054/100] Sampling and subset functions working --- openmc/data/resonance_covariance.py | 38 ++++++++++++----------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index d8c0236ff6..a84e7aa537 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -147,9 +147,7 @@ class ResonanceCovarianceRange(object): Number of parameters in covariance matrix for each individual resonance """ - - @classmethod - def res_subset(cls, parameter_str, bounds): + def res_subset(self, parameter_str, bounds): """Produce a subset of resonance parameters and the covariance matrix to an IncidentNeutron object. @@ -166,9 +164,9 @@ class ResonanceCovarianceRange(object): cov_subset: subset of covariance matrix (upper triangular) """ - parameters = cls.parameters - cov = cls.covariance - mpar = cls.mpar + parameters = self.parameters + cov = self.covariance + mpar = self.mpar mask1 = parameters[parameter_str]>=bounds[0] mask2 = parameters[parameter_str]<=bounds[1] mask = mask1 & mask2 @@ -187,11 +185,10 @@ class ResonanceCovarianceRange(object): tri_indices = np.triu_indices(sub_cov_dim) cov_subset[tri_indices] = oldvalues - cls.parameters_subset = parameters_subset - cls.cov_subset = cov_subset + self.parameters_subset = parameters_subset + self.cov_subset = cov_subset - @classmethod - def sample_resonance_parameters(cls, n_samples, use_subset=False): + def sample_resonance_parameters(self, n_samples, use_subset=False): """Return a IncidentNeutron object with n_samples of xs Parameters @@ -205,24 +202,20 @@ class ResonanceCovarianceRange(object): ------- """ - print('Begin sampling') - print((cls)) - print(dir(cls)) - print(vars(cls)) if use_subset==False: - parameters = cls.parameters - cov = cls.covariance + parameters = self.parameters + cov = self.covariance else: - if cls.parameters_subset is None: + if self.parameters_subset is None: raise ValueError('No subset of resonances defined') - parameters = cls.parameters_subset - cov = cls.cov_subset + parameters = self.parameters_subset + cov = self.cov_subset nparams,params = parameters.shape cov = cov + cov.T - np.diag(cov.diagonal()) #symmetrizing covariance matrix covsize = cov.shape[0] - formalism = cls.formalism - mpar = cls.mpar + formalism = self.formalism + mpar = self.mpar samples = [] @@ -270,6 +263,7 @@ class ResonanceCovarianceRange(object): sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) + ###FIXME doesn't look any different from mpar == 4 elif mpar == 5: param_list = ['energy','neutronWidth','captureWidth','fissionWidth'] mean_array = pd.DataFrame.as_matrix(parameters[param_list]) @@ -335,7 +329,7 @@ class ResonanceCovarianceRange(object): sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) - cls.samples = samples + self.samples = samples class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): """Multi-level Breit-Wigner resolved resonance formalism covariance data. From 1845edb23365a49de30e2529123524bcfc70c5a5 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Thu, 5 Jul 2018 14:35:50 -0500 Subject: [PATCH 055/100] Fixed a lot of doc strings, jupyter example --- .../nuclear-data-resonance-covariance.ipynb | 278 ++++++++++++++++++ openmc/data/resonance_covariance.py | 218 +++++++------- 2 files changed, 383 insertions(+), 113 deletions(-) create mode 100644 examples/jupyter/nuclear-data-resonance-covariance.ipynb diff --git a/examples/jupyter/nuclear-data-resonance-covariance.ipynb b/examples/jupyter/nuclear-data-resonance-covariance.ipynb new file mode 100644 index 0000000000..d1def693c6 --- /dev/null +++ b/examples/jupyter/nuclear-data-resonance-covariance.ipynb @@ -0,0 +1,278 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "import os\n", + "from pprint import pprint\n", + "import shutil\n", + "import subprocess\n", + "import urllib.request\n", + "\n", + "import h5py\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib.cm\n", + "from matplotlib.patches import Rectangle\n", + "\n", + "import openmc.data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ENDF: Resonance Covariance Data\n", + "\n", + "We can also load the resonance covariance data contined within File 32 of ENDF. Let's download the ENDF/B-VII.1 evaluation for $^{157}$Gd and load it in:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Download ENDF file\n", + "url = 'https://t2.lanl.gov/nis/data/data/ENDFB-VII.1-neutron/Gd/157'\n", + "filename, headers = urllib.request.urlretrieve(url, 'gd157.endf')\n", + "\n", + "# Load into memory\n", + "gd157_endf = openmc.data.IncidentNeutron.from_endf(filename, get_covariance = True)\n", + "gd157_endf" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can access the parameters contained within File 32 in a similar manner to the File 2 parameters from before. " + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " energy J neutronWidth captureWidth fissionWidthA fissionWidthB L\n", + "0 0.0314 2.0 0.000474 0.1072 0.0 0.0 0\n", + "1 2.8250 2.0 0.000345 0.0970 0.0 0.0 0\n", + "2 16.2400 1.0 0.000400 0.0910 0.0 0.0 0\n", + "3 16.7700 2.0 0.012800 0.0805 0.0 0.0 0\n", + "4 20.5600 2.0 0.011360 0.0880 0.0 0.0 0\n" + ] + } + ], + "source": [ + "first_five = gd157_endf.res_covariance.ranges[0].parameters[:5]\n", + "print(first_five)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The newly created object will contain multiple resonance regions within 'gd157_endf.res_covariance.ranges'. We can access the full covariance matrix from File 32 for a given range by:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "covariance = gd157_endf.res_covariance.ranges[0].covariance" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This covariance matrix currently only stores the upper triangular portion as covariance matrix are symmetric. Plotting the covariance matrix:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.imshow(covariance)\n", + "plt.colorbar()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another capability of the covariance module is selecting a subset of the resonance parameters and the corresponding subset of the covariance matrix. We can do this by specifying the value we want to discriminate and the bounds within one energy region. Selecting only resonances with J=2:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " energy J neutronWidth captureWidth fissionWidthA fissionWidthB L\n", + "0 0.0314 2.0 0.000474 0.1072 0.0 0.0 0\n", + "1 2.8250 2.0 0.000345 0.0970 0.0 0.0 0\n", + "3 16.7700 2.0 0.012800 0.0805 0.0 0.0 0\n", + "4 20.5600 2.0 0.011360 0.0880 0.0 0.0 0\n", + "5 21.6500 2.0 0.000376 0.1140 0.0 0.0 0\n" + ] + } + ], + "source": [ + "lower_bound = 2; #inclusive\n", + "upper_bound = 2; #inclusive\n", + "gd157_endf.res_covariance.ranges[0].res_subset('J',[lower_bound,upper_bound])\n", + "subset_first_five = gd157_endf.res_covariance.ranges[0].parameters_subset[:5]\n", + "print(subset_first_five)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The subset method will also store the corresponding subset of the covariance matrix" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[ 2.82609600e-06 5.89537500e-09 -4.78638600e-06 -5.73895500e-08\n", + " -1.48636900e-09]\n", + " [ 0.00000000e+00 1.36218000e-11 -9.61975600e-09 -1.15354000e-10\n", + " -2.87250000e-12]\n", + " [ 0.00000000e+00 0.00000000e+00 8.20814700e-06 9.83537100e-08\n", + " 2.58111200e-09]\n", + " [ 0.00000000e+00 0.00000000e+00 0.00000000e+00 6.54205000e-06\n", + " -4.31977000e-10]\n", + " [ 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00\n", + " 1.76975000e-10]]\n" + ] + } + ], + "source": [ + "cov_subset = gd157_endf.res_covariance.ranges[0].cov_subset\n", + "print(cov_subset[:5,:5])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The final function of the covariance module is the ability to sample a new set of parameters using the covariance matrix. Currently the sampling uses np.multivariate_normal(). Because parameters are assumed to have a multivariate normal distribution this method doesn't not currently guarantee that sampled parameters will be positive. " + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Sample 1\n", + " energy J neutronWidth captureWidth fissionWidthA fissionWidthB\n", + "0 0.031860 2.0 0.000475 0.106353 0.0 0.0\n", + "1 2.823805 2.0 0.000326 0.103970 0.0 0.0\n", + "2 16.242208 1.0 0.000430 0.110773 0.0 0.0\n", + "3 16.770072 2.0 0.012445 0.083466 0.0 0.0\n", + "4 20.559242 2.0 0.011852 0.082108 0.0 0.0\n", + "Sample 2\n", + " energy J neutronWidth captureWidth fissionWidthA fissionWidthB\n", + "0 0.032548 2.0 0.000476 0.105254 0.0 0.0\n", + "1 2.829121 2.0 0.000375 0.086731 0.0 0.0\n", + "2 16.234402 1.0 0.000438 0.144065 0.0 0.0\n", + "3 16.771254 2.0 0.012171 0.088258 0.0 0.0\n", + "4 20.571634 2.0 0.011214 0.094332 0.0 0.0\n" + ] + } + ], + "source": [ + "n_samples = 5\n", + "gd157_endf.res_covariance.ranges[0].sample_resonance_parameters(n_samples)\n", + "samples = gd157_endf.res_covariance.ranges[0].samples\n", + "first_five_sample_1 = samples[0][:5]\n", + "first_five_sample_2 = samples[1][:5]\n", + "print('Sample 1')\n", + "print(first_five_sample_1)\n", + "print('Sample 2')\n", + "print(first_five_sample_2)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index a84e7aa537..e761a3756e 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -14,7 +14,7 @@ from .resonance import Resonances def file2contributions(file32params, file2params): """Function for aiding in adding resonance parameters from File 2 that are - not always present in file 32. + not always present in File 32. Uses already imported resonance data. Paramateers ----------- @@ -25,7 +25,7 @@ def file2contributions(file32params, file2params): Returns ------- - parameters: pandas.Dataframs + parameters: pandas.Dataframe Complete set of parameters ordered by L-values and then energy """ #Use l-values and competitiveWidth from File 2 data @@ -56,8 +56,6 @@ class ResonanceCovariances(Resonances): ---------- ranges : list of openmc.data.ResonanceCovarianceRange Distinct energy ranges for resonance data - resolved : openmc.data.ResonanceCovariance or None - Resolved resonance range """ def __init__(self, ranges): @@ -85,7 +83,7 @@ class ResonanceCovariances(Resonances): ---------- ev : openmc.data.endf.Evaluation ENDF evaluation - resonances : Resonance object + resonances : openmc.data.Resonance object Returns ------- @@ -133,35 +131,53 @@ class ResonanceCovariances(Resonances): class ResonanceCovarianceRange(object): - """Resonace covariance range + """Resonace covariance range. Base class for different formalisms. + Parameters + ---------- + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV Attributes ---------- - cov_parameters: list - The parameters that are included in the covariance matrix - covariance_matrix : array + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV + parameters: pandas.DataFrame + Resonance parameters + covariance : numpy.array The covariance matrix contained within the ENDF evaluation lcomp : int - Flag indicating the format of the covariance matrix + Flag indicating the format of the covariance matrix within the ENDF file mpar : int Number of parameters in covariance matrix for each individual resonance + formalism : str + String descriptor of formalism """ + def __init__(self, energy_min, energy_max): + self.energy_min = energy_min + self.energy_max = energy_max def res_subset(self, parameter_str, bounds): - """Produce a subset of resonance parameters and the covariance matrix - to an IncidentNeutron object. + """Produce a subset of resonance parameters and the corresponding + covariance matrix to an IncidentNeutron object. Parameters ---------- - parameter_str: parameter to be discriminated - (i.e. 'energy','captureWidth','fissionWidthA'...) - bounds: np.array [low numerical bound, high numerical bound] + parameter_str: str + parameter to be discriminated + (i.e. 'energy','captureWidth','fissionWidthA'...) + bounds: np.array + [low numerical bound, high numerical bound] Returns ------- - parameters_subset : Dataframe of a subset of parameters - (maintains indexing) - cov_subset: subset of covariance matrix (upper triangular) + parameters_subset : pandas.Dataframe + Subset of parameters (maintains indexing of original) + cov_subset: np.array + Subset of covariance matrix (upper triangular) """ parameters = self.parameters @@ -173,17 +189,17 @@ class ResonanceCovarianceRange(object): parameters_subset=parameters[mask] indices = parameters_subset.index.values sub_cov_dim = len(indices)*mpar - oldvalues = [] + cov_subset_vals = [] for index1 in indices: for i in range(mpar): for index2 in indices: for j in range(mpar): if index2*mpar+j >= index1*mpar+i: - oldvalues.append(cov[index1*mpar+i,index2*mpar+j]) + cov_subset_vals.append(cov[index1*mpar+i,index2*mpar+j]) cov_subset = np.zeros([sub_cov_dim,sub_cov_dim]) tri_indices = np.triu_indices(sub_cov_dim) - cov_subset[tri_indices] = oldvalues + cov_subset[tri_indices] = cov_subset_vals self.parameters_subset = parameters_subset self.cov_subset = cov_subset @@ -193,13 +209,15 @@ class ResonanceCovarianceRange(object): Parameters ---------- - n_samples: int + n_samples : int The number of samples to produce - use_subset: bool, optional + use_subset : bool, optional Flag on whether to sample from an already produced subset Returns ------- + samples : list of openmc.data.ResonanceCovarianceRange objects + List of samples size [n_samples] """ if use_subset==False: @@ -219,7 +237,7 @@ class ResonanceCovarianceRange(object): samples = [] - ### Handling MLBW Sampling ### + # Handling MLBW Sampling if formalism == 'mlbw' or formalism == 'slbw': if mpar == 3: param_list = ['energy','neutronWidth','captureWidth'] @@ -263,29 +281,30 @@ class ResonanceCovarianceRange(object): sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) - ###FIXME doesn't look any different from mpar == 4 elif mpar == 5: - param_list = ['energy','neutronWidth','captureWidth','fissionWidth'] + param_list = ['energy','neutronWidth','captureWidth', + 'fissionWidth', 'competitiveWidth'] mean_array = pd.DataFrame.as_matrix(parameters[param_list]) spin = pd.DataFrame.as_matrix(parameters['J']) mean = mean_array.flatten() for i in range(n_samples): sample = np.random.multivariate_normal(mean,cov) - energy = sample[0::4] - gn = sample[1::4] - gg = sample[2::4] - gf = sample[3::4] + energy = sample[0::5] + gn = sample[1::5] + gg = sample[2::5] + gf = sample[3::5] + gx = sample[4::5] gt = gn + gg + gf records = [] for j, E in enumerate(energy): records.append([energy[j], spin[j], gt[j], gn[j], - gg[j], gf[j]]) + gg[j], gf[j], gx[j]]) columns = ['energy', 'J', 'totalWidth', 'neutronWidth', - 'captureWidth', 'fissionWidth'] + 'captureWidth', 'fissionWidth', 'competitveWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) - ### Handling RM Sampling ### + # Handling RM Sampling if formalism == 'rm': if mpar == 3: param_list = ['energy','neutronWidth','captureWidth'] @@ -333,29 +352,37 @@ class ResonanceCovarianceRange(object): class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): """Multi-level Breit-Wigner resolved resonance formalism covariance data. - - Multi-level Breit-Wigner resolved resonance data is identified by LRF=2 in - the ENDF-6 format. + Parameters + ---------- + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV Attributes ---------- - cov_parameters: list - The parameters that are included in the covariance matrix - covariance_matrix : array + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV + parameters: pandas.DataFrame + Resonance parameters + covariance : numpy.array The covariance matrix contained within the ENDF evaluation lcomp : int - Flag indicating the format of the covariance matrix + Flag indicating the format of the covariance matrix within the ENDF file mpar : int Number of parameters in covariance matrix for each individual resonance - + formalism : str + String descriptor of formalism """ def __init__(self, energy_min, energy_max): + super().__init__(energy_min, energy_max) self.parameters = None self.covariance = None self.mpar = None self.lcomp = None - self.num_parameters = None self.formalism = 'mlbw' @classmethod @@ -372,7 +399,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): items : list Items from the CONT record at the start of the resonance range subsection - resonances : openmc.data.IncidentNeutron.Resonance + resonances : openmc.data.IncidentNeutron.Resonance object Returns ------- @@ -406,7 +433,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): records = [] for i in range(num_short_range): items, values = get_list_record(file_obj) - num_parameters = items[2] + mpar = items[2] num_res = items[5] num_par_vals = num_res*6 res_values = values[:num_par_vals] @@ -424,7 +451,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): gg[i], gf[i]]) #Build the upper-triangular covariance matrix - cov_dim = num_parameters*num_res + cov_dim = mpar*num_res cov = np.zeros([cov_dim,cov_dim]) indices = np.triu_indices(cov_dim) cov[indices] = cov_values @@ -435,12 +462,6 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): 'captureWidth', 'fissionWidth'] parameters = pd.DataFrame.from_records(records, columns=columns) - #Determine mpar (number of parameters for each resonance in - #covariance matrix) - nparams,params = parameters.shape - covsize = cov.shape[0] - mpar = int(covsize/nparams) - #Add parameters from File 2 parameters = file2contributions(parameters, file2params) @@ -450,7 +471,6 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): mlbw.covariance = cov mlbw.mpar = mpar mlbw.lcomp = LCOMP - mlbw.num_parameters = num_parameters return mlbw @@ -498,7 +518,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): mpar = int(covsize/nparams) #Add parameters from File 2 - parameters = file2contributions(parameter, file2params) + parameters = file2contributions(parameters, file2params) # Create instance of MultiLevelBreitWignerCovariance mlbw = cls(energy_min, energy_max) @@ -557,7 +577,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): mpar = int(covsize/nparams) #Add parameters from File 2 - parameters = file2contributions(parameter, file2params) + parameters = file2contributions(parameters, file2params) # Create instance of class mlbw = cls(energy_min, energy_max) @@ -571,53 +591,36 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): class SingleLevelBreitWignerCovariance(MultiLevelBreitWignerCovariance): """Single-level Breit-Wigner resolved resonance formalism covariance data. - Single-level Breit-Wigner resolved resonance data is is identified by LRF=1 in the ENDF-6 format. Parameters ---------- - target_spin : float - Intrinsic spin, :math:`I`, of the target nuclide energy_min : float Minimum energy of the resolved resonance range in eV energy_max : float Maximum energy of the resolved resonance range in eV - channel : dict - Dictionary whose keys are l-values and values are channel radii as a - function of energy - scattering : dict - Dictionary whose keys are l-values and values are scattering radii as a - function of energy Attributes ---------- - atomic_weight_ratio : float - Atomic weight ratio of the target nuclide given as a function of - l-value. Note that this may be different than the value for the - evaluation as a whole. - channel_radius : dict - Dictionary whose keys are l-values and values are channel radii as a - function of energy - energy_max : float - Maximum energy of the resolved resonance range in eV energy_min : float Minimum energy of the resolved resonance range in eV - parameters : pandas.DataFrame - Energies, spins, and resonances widths for each resonance - q_value : dict - Q-value to be added to incident particle's center-of-mass energy to - determine the channel energy for use in the penetrability factor. The - keys of the dictionary are l-values. - scattering_radius : dict - Dictionary whose keys are l-values and values are scattering radii as a - function of energy - target_spin : float - Intrinsic spin, :math:`I`, of the target nuclide - + energy_max : float + Maximum energy of the resolved resonance range in eV + parameters: pandas.DataFrame + Resonance parameters + covariance : numpy.array + The covariance matrix contained within the ENDF evaluation + lcomp : int + Flag indicating the format of the covariance matrix within the ENDF file + mpar : int + Number of parameters in covariance matrix for each individual resonance + formalism : str + String descriptor of formalism """ def __init__(self, energy_min, energy_max): + super().__init__(energy_min,energy_max) self.formalism = 'slbw' class ReichMooreCovariance(ResonanceCovarianceRange): @@ -626,39 +629,35 @@ class ReichMooreCovariance(ResonanceCovarianceRange): Reich-Moore resolved resonance data is identified by LRF=3 in the ENDF-6 format. - Parameters ---------- - target_spin : float - Intrinsic spin, :math:`I`, of the target nuclide energy_min : float Minimum energy of the resolved resonance range in eV energy_max : float Maximum energy of the resolved resonance range in eV - channel : dict - Dictionary whose keys are l-values and values are channel radii as a - function of energy - scattering : dict - Dictionary whose keys are l-values and values are scattering radii as a - function of energy Attributes ---------- - num_parameters: list - Number of parameters used in each subsection - cov_parameters: list - The parameters that are included in the covariance matrix - covariance_matrix : array + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV + parameters: pandas.DataFrame + Resonance parameters + covariance : numpy.array The covariance matrix contained within the ENDF evaluation - - + lcomp : int + Flag indicating the format of the covariance matrix within the ENDF file + mpar : int + Number of parameters in covariance matrix for each individual resonance + formalism : str + String descriptor of formalism """ def __init__(self, energy_min, energy_max): - self.num_parameters = None + super().__init__(energy_min, energy_max) self.parameters = None self.covariance = None - self.num_parameters = None self.formalism = 'rm' @classmethod @@ -711,7 +710,7 @@ class ReichMooreCovariance(ResonanceCovarianceRange): records = [] for i in range(num_short_range): items, values = get_list_record(file_obj) - num_parameters = items[2] + mpar = items[2] num_res = items[5] num_par_vals = num_res*6 res_values = values[:num_par_vals] @@ -729,7 +728,7 @@ class ReichMooreCovariance(ResonanceCovarianceRange): gfa[i], gfb[i]]) #Build the upper-triangular covariance matrix - cov_dim = num_parameters*num_res + cov_dim = mpar*num_res cov = np.zeros([cov_dim,cov_dim]) indices = np.triu_indices(cov_dim) cov[indices] = cov_values @@ -739,14 +738,8 @@ class ReichMooreCovariance(ResonanceCovarianceRange): 'fissionWidthA', 'fissionWidthB'] parameters = pd.DataFrame.from_records(records, columns=columns) - #Determine mpar (number of parameters for each resonance in - #covariance matrix) - nparams,params = parameters.shape - covsize = cov.shape[0] - mpar = int(covsize/nparams) - #Add parameters from File 2 - parameters = file2contributions(parameter, file2params) + parameters = file2contributions(parameters, file2params) # Create instance of ReichMooreCovariance rmc = cls(energy_min, energy_max) @@ -754,7 +747,6 @@ class ReichMooreCovariance(ResonanceCovarianceRange): rmc.covariance = cov rmc.mpar = mpar rmc.lcomp = LCOMP - rmc.num_parameters = num_parameters return rmc @@ -795,7 +787,7 @@ class ReichMooreCovariance(ResonanceCovarianceRange): mpar = int(covsize/nparams) #Add parameters from File 2 - parameters = file2contributions(parameter, file2params) + parameters = file2contributions(parameters, file2params) # Create instance of ReichMooreCovariance rmc = cls(energy_min, energy_max) From 84ef96cf8a40f6c14c36df6d1e909ffeacc5f381 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Fri, 6 Jul 2018 09:57:17 -0500 Subject: [PATCH 056/100] added reconstruction ability for resonance samples --- .../nuclear-data-resonance-covariance.ipynb | 106 +++++++++++++++--- openmc/data/resonance.py | 20 ++-- openmc/data/resonance_covariance.py | 66 ++++++++--- 3 files changed, 154 insertions(+), 38 deletions(-) diff --git a/examples/jupyter/nuclear-data-resonance-covariance.ipynb b/examples/jupyter/nuclear-data-resonance-covariance.ipynb index d1def693c6..88c421ce5f 100644 --- a/examples/jupyter/nuclear-data-resonance-covariance.ipynb +++ b/examples/jupyter/nuclear-data-resonance-covariance.ipynb @@ -118,7 +118,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 5, @@ -129,7 +129,7 @@ "data": { "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -212,7 +212,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The final function of the covariance module is the ability to sample a new set of parameters using the covariance matrix. Currently the sampling uses np.multivariate_normal(). Because parameters are assumed to have a multivariate normal distribution this method doesn't not currently guarantee that sampled parameters will be positive. " + "The covariance module also has the ability to sample a new set of parameters using the covariance matrix. Currently the sampling uses np.multivariate_normal(). Because parameters are assumed to have a multivariate normal distribution this method doesn't not currently guarantee that sampled parameters will be positive. " ] }, { @@ -225,19 +225,19 @@ "output_type": "stream", "text": [ "Sample 1\n", - " energy J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.031860 2.0 0.000475 0.106353 0.0 0.0\n", - "1 2.823805 2.0 0.000326 0.103970 0.0 0.0\n", - "2 16.242208 1.0 0.000430 0.110773 0.0 0.0\n", - "3 16.770072 2.0 0.012445 0.083466 0.0 0.0\n", - "4 20.559242 2.0 0.011852 0.082108 0.0 0.0\n", + " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", + "0 0.032744 0 2.0 0.000476 0.104726 0.0 0.0\n", + "1 2.824910 0 2.0 0.000367 0.093434 0.0 0.0\n", + "2 16.246703 0 1.0 0.000428 0.128670 0.0 0.0\n", + "3 16.772205 0 2.0 0.012712 0.087642 0.0 0.0\n", + "4 20.558978 0 2.0 0.011754 0.088571 0.0 0.0\n", "Sample 2\n", - " energy J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.032548 2.0 0.000476 0.105254 0.0 0.0\n", - "1 2.829121 2.0 0.000375 0.086731 0.0 0.0\n", - "2 16.234402 1.0 0.000438 0.144065 0.0 0.0\n", - "3 16.771254 2.0 0.012171 0.088258 0.0 0.0\n", - "4 20.571634 2.0 0.011214 0.094332 0.0 0.0\n" + " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", + "0 0.030677 0 2.0 0.000474 0.108886 0.0 0.0\n", + "1 2.822705 0 2.0 0.000357 0.099604 0.0 0.0\n", + "2 16.250280 0 1.0 0.000527 0.128495 0.0 0.0\n", + "3 16.770029 0 2.0 0.013519 0.076974 0.0 0.0\n", + "4 20.555458 0 2.0 0.011091 0.094415 0.0 0.0\n" ] } ], @@ -252,6 +252,82 @@ "print('Sample 2')\n", "print(first_five_sample_2)" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can reconstruct the cross section from the sampled parameters using the reconstruct method. This method also required the equivalent openmc.data.IncidentNeutron.resonance.ResonanceRange object. " + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[,\n", + " ]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gd157_endf.resonances.ranges" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Reconstructing in the ReichMoore region using our previously generated samples. " + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0,0.5,'Cross section (b)')" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "rm_resonance = gd157_endf.resonances.ranges[0]\n", + "energy_range = [rm_resonance.energy_min, rm_resonance.energy_max]\n", + "energies = np.logspace(np.log10(energy_range[0]),\n", + " np.log10(energy_range[1]), 10000)\n", + "for sample in range(n_samples):\n", + " xs = gd157_endf.res_covariance.ranges[0].reconstruct(energies, rm_resonance, sample)\n", + " elastic_xs = xs[2]\n", + " plt.loglog(energies, elastic_xs)\n", + "plt.xlabel('Energy (eV)')\n", + "plt.ylabel('Cross section (b)')\n", + "\n", + " " + ] } ], "metadata": { diff --git a/openmc/data/resonance.py b/openmc/data/resonance.py index d58f706eb9..95a145da56 100644 --- a/openmc/data/resonance.py +++ b/openmc/data/resonance.py @@ -202,7 +202,7 @@ class ResonanceRange(object): return cls(target_spin, energy_min, energy_max, {0: a}, {0: ap}) - def reconstruct(self, energies): + def reconstruct(self, energies, use_sample = False, sample_parameters = None): """Evaluate cross section at specified energies. Parameters @@ -221,8 +221,8 @@ class ResonanceRange(object): raise RuntimeError("Resonance reconstruction not available.") # Pre-calculate penetrations and shifts for resonances - if not self._prepared: - self._prepare_resonances() + if not self._prepared or use_sample: + self._prepare_resonances(use_sample, sample_parameters) if isinstance(energies, Iterable): elastic = np.zeros_like(energies) @@ -394,8 +394,11 @@ class MultiLevelBreitWigner(ResonanceRange): return mlbw - def _prepare_resonances(self): - df = self.parameters.copy() + def _prepare_resonances(self, use_sample = False, sample_parameters = None): + if use_sample == False: + df = self.parameters.copy() + else: + df = sample_parameters.copy() # Penetration and shift factors p = np.zeros(len(df)) @@ -653,8 +656,11 @@ class ReichMoore(ResonanceRange): return rm - def _prepare_resonances(self): - df = self.parameters.copy() + def _prepare_resonances(self, use_sample = False, sample_parameters = None): + if use_sample == False: + df = self.parameters.copy() + else: + df = sample_parameters.copy() # Penetration and shift factors p = np.zeros(len(df)) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index e761a3756e..6ed3db424e 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -113,7 +113,7 @@ class ResonanceCovariances(Resonances): # Throw error for unsupported formalisms if formalism in [0,7]: - raise TypeError('LRF= ', formalism, + raise NotImplementedError('LRF= ', formalism, 'covariance not supported for this formalism') if unresolved_flag in (0,1): @@ -122,14 +122,14 @@ class ResonanceCovariances(Resonances): erange = _FORMALISMS[formalism].from_endf(ev, file_obj, items, file2params) elif unresolved_flag == 2: - warnings.warn('Unresolved resonance not supported.' - 'Covariance values for the' - 'unresolved region not imported.') + warn_str = 'Unresolved resonance not supported.'\ + 'Covariance values for the unresolved region not imported.' + warnings.warn(warn_str) + ranges.append(erange) return cls(ranges) - class ResonanceCovarianceRange(object): """Resonace covariance range. Base class for different formalisms. Parameters @@ -243,6 +243,7 @@ class ResonanceCovarianceRange(object): param_list = ['energy','neutronWidth','captureWidth'] mean_array = pd.DataFrame.as_matrix(parameters[param_list]) spin = pd.DataFrame.as_matrix(parameters['J']) + l_value = pd.DataFrame.as_matrix(parameters['L']) gf = pd.DataFrame.as_matrix(parameters['fissionWidth']) mean = mean_array.flatten() for i in range(n_samples): @@ -253,9 +254,9 @@ class ResonanceCovarianceRange(object): gt = gn + gg + gf records = [] for j, E in enumerate(energy): - records.append([energy[j], spin[j], gt[j], gn[j], + records.append([energy[j], l_value[j], spin[j], gt[j], gn[j], gg[j], gf[j]]) - columns = ['energy', 'J', 'totalWidth', 'neutronWidth', + columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', 'captureWidth', 'fissionWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) @@ -264,6 +265,7 @@ class ResonanceCovarianceRange(object): param_list = ['energy','neutronWidth','captureWidth','fissionWidth'] mean_array = pd.DataFrame.as_matrix(parameters[param_list]) spin = pd.DataFrame.as_matrix(parameters['J']) + l_value = pd.DataFrame.as_matrix(parameters['L']) mean = mean_array.flatten() for i in range(n_samples): sample = np.random.multivariate_normal(mean,cov) @@ -274,9 +276,9 @@ class ResonanceCovarianceRange(object): gt = gn + gg + gf records = [] for j, E in enumerate(energy): - records.append([energy[j], spin[j], gt[j], gn[j], + records.append([energy[j], l_value[j], spin[j], gt[j], gn[j], gg[j], gf[j]]) - columns = ['energy', 'J', 'totalWidth', 'neutronWidth', + columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', 'captureWidth', 'fissionWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) @@ -286,6 +288,7 @@ class ResonanceCovarianceRange(object): 'fissionWidth', 'competitiveWidth'] mean_array = pd.DataFrame.as_matrix(parameters[param_list]) spin = pd.DataFrame.as_matrix(parameters['J']) + l_value = pd.DataFrame.as_matrix(parameters['L']) mean = mean_array.flatten() for i in range(n_samples): sample = np.random.multivariate_normal(mean,cov) @@ -297,9 +300,9 @@ class ResonanceCovarianceRange(object): gt = gn + gg + gf records = [] for j, E in enumerate(energy): - records.append([energy[j], spin[j], gt[j], gn[j], + records.append([energy[j], l_value[j], spin[j], gt[j], gn[j], gg[j], gf[j], gx[j]]) - columns = ['energy', 'J', 'totalWidth', 'neutronWidth', + columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', 'captureWidth', 'fissionWidth', 'competitveWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) @@ -310,6 +313,7 @@ class ResonanceCovarianceRange(object): param_list = ['energy','neutronWidth','captureWidth'] mean_array = pd.DataFrame.as_matrix(parameters[param_list]) spin = pd.DataFrame.as_matrix(parameters['J']) + l_value = pd.DataFrame.as_matrix(parameters['L']) gfa = pd.DataFrame.as_matrix(parameters['fissionWidthA']) gfb = pd.DataFrame.as_matrix(parameters['fissionWidthB']) mean = mean_array.flatten() @@ -320,17 +324,19 @@ class ResonanceCovarianceRange(object): gg = sample[2::3] records = [] for j, E in enumerate(energy): - records.append([energy[j], spin[j], gn[j], + records.append([energy[j], l_value[j], spin[j], gn[j], gg[j], gfa[j], gfb[j]]) - columns = ['energy', 'J', 'neutronWidth', + columns = ['energy', 'L', 'J', 'neutronWidth', 'captureWidth', 'fissionWidthA','fissionWidthB'] sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) elif mpar == 5: - param_list = ['energy','neutronWidth','captureWidth','fissionWidthA','fissionWidthB'] + param_list = ['energy','neutronWidth','captureWidth', + 'fissionWidthA','fissionWidthB'] mean_array = pd.DataFrame.as_matrix(parameters[param_list]) spin = pd.DataFrame.as_matrix(parameters['J']) + l_value = pd.DataFrame.as_matrix(parameters['L']) mean = mean_array.flatten() for i in range(n_samples): sample = np.random.multivariate_normal(mean,cov) @@ -341,15 +347,43 @@ class ResonanceCovarianceRange(object): gfb = sample[4::5] records = [] for j, E in enumerate(energy): - records.append([energy[j], spin[j], gn[j], + records.append([energy[j], l_value[j], spin[j], gn[j], gg[j], gfa[j], gfb[j]]) - columns = ['energy', 'J', 'neutronWidth', + columns = ['energy', 'L', 'J', 'neutronWidth', 'captureWidth', 'fissionWidthA','fissionWidthB'] sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) self.samples = samples + def reconstruct(self, energies, resonances, sampleN): + """Evaluate the cross section at specified energies for an already + sampled set of resonance parameters. + + Parameters + ---------- + energies : float or Iterable of float + Energies at which the cross section should be evaluated + resonances : openmc.data.Resonance object + Corresponding resonance range with File 2 data. Used for + reconstruction method + sampleN : int + Index of sample of resonance parameters to be used + + Returns + ------- + 3-tuple of float or numpy.ndarray + Elastic, capture, and fission cross sections at the specified + energies + + """ + if self.samples[sampleN] is None: + raise ValueError("Sample of resonance parameters has not been set.") + sample_parameters = self.samples[sampleN] + xs_array = resonances.reconstruct(energies, use_sample = True, + sample_parameters = sample_parameters) + return xs_array + class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): """Multi-level Breit-Wigner resolved resonance formalism covariance data. Parameters From e88f8cd3647d16f80ad17ed96a7c6d1450ff8502 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Fri, 6 Jul 2018 10:25:24 -0500 Subject: [PATCH 057/100] Small change to endf parser --- openmc/data/endf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openmc/data/endf.py b/openmc/data/endf.py index 0d558b5e41..5bda5c127f 100644 --- a/openmc/data/endf.py +++ b/openmc/data/endf.py @@ -69,9 +69,9 @@ def float_endf(s): """ try: - return float(ENDF_FLOAT_RE.sub(r'\1e\2', s)) + return float(_ENDF_FLOAT_RE.sub(r'\1e\2', s)) except: - if ENDF_FLOAT_RE.sub(r'\1e\2', s).isspace(): + if _ENDF_FLOAT_RE.sub(r'\1e\2', s).isspace(): return 0 else: raise TypeError('Expected float value or blank entry') From 6b836a199c526b135d1dcf5d85c4adf9ba8f2fcf Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Fri, 6 Jul 2018 12:45:27 -0500 Subject: [PATCH 058/100] Fixed MLBW sample reconstruction --- openmc/data/resonance_covariance.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index 6ed3db424e..24b3e1e9a8 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -36,7 +36,7 @@ def file2contributions(file32params, file2params): file32params_sort = file32params.sort_values(by=['energy']) #Add in values (.values converts to array first to ignore index) file32params_sort['L'] = file2params['L'].values - if 'competiveWidth' in file32params_sort: + if 'competitiveWidth' in file2params.columns: file32params_sort['competitiveWidth'] = file2params['competitiveWidth'].values #Resort to File 32 order (by L then by E) for use with covariance parameters = file32params_sort.sort_index() @@ -237,7 +237,7 @@ class ResonanceCovarianceRange(object): samples = [] - # Handling MLBW Sampling + # Handling MLBW sampling if formalism == 'mlbw' or formalism == 'slbw': if mpar == 3: param_list = ['energy','neutronWidth','captureWidth'] @@ -245,6 +245,7 @@ class ResonanceCovarianceRange(object): spin = pd.DataFrame.as_matrix(parameters['J']) l_value = pd.DataFrame.as_matrix(parameters['L']) gf = pd.DataFrame.as_matrix(parameters['fissionWidth']) + gx = pd.DataFrame.as_matrix(parameters['competitiveWidth']) mean = mean_array.flatten() for i in range(n_samples): sample = np.random.multivariate_normal(mean,cov) @@ -255,9 +256,9 @@ class ResonanceCovarianceRange(object): records = [] for j, E in enumerate(energy): records.append([energy[j], l_value[j], spin[j], gt[j], gn[j], - gg[j], gf[j]]) + gg[j], gf[j], gx[j]]) columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', - 'captureWidth', 'fissionWidth'] + 'captureWidth', 'fissionWidth', 'competitiveWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) @@ -266,6 +267,7 @@ class ResonanceCovarianceRange(object): mean_array = pd.DataFrame.as_matrix(parameters[param_list]) spin = pd.DataFrame.as_matrix(parameters['J']) l_value = pd.DataFrame.as_matrix(parameters['L']) + gx = pd.DataFrame.as_matrix(parameters['competitiveWidth']) mean = mean_array.flatten() for i in range(n_samples): sample = np.random.multivariate_normal(mean,cov) @@ -277,9 +279,9 @@ class ResonanceCovarianceRange(object): records = [] for j, E in enumerate(energy): records.append([energy[j], l_value[j], spin[j], gt[j], gn[j], - gg[j], gf[j]]) + gg[j], gf[j], gx[j]]) columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', - 'captureWidth', 'fissionWidth'] + 'captureWidth', 'fissionWidth', 'competitiveWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) From 27c9d3c772cbe5078c3aa6301d43fa6323222562 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Mon, 16 Jul 2018 17:03:25 -0500 Subject: [PATCH 059/100] MLBW test added --- tests/unit_tests/test_data_neutron.py | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/unit_tests/test_data_neutron.py b/tests/unit_tests/test_data_neutron.py index 03746430d9..a412f2024c 100644 --- a/tests/unit_tests/test_data_neutron.py +++ b/tests/unit_tests/test_data_neutron.py @@ -96,6 +96,18 @@ def am244(): endf_file = os.path.join(_ENDF_DATA, 'neutrons', 'n-095_Am_244.endf') return openmc.data.IncidentNeutron.from_njoy(endf_file) +@pytest.fixture(scope='module') +def gd154cov(): + """Gd154 ENDF data (contains Reich Moore resonance range)""" + filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-064_Gd_154.endf') + return openmc.data.IncidentNeutron.from_endf(filename, get_covariance=True) + +@pytest.fixture(scope='module') +def ti50(): + """Ti50 ENDF data (contains Multi-level Breit-Wigner resonance range)""" + filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-022_Ti_050.endf') + return openmc.data.IncidentNeutron.from_endf(filename, get_covariance=True) + def test_attributes(pu239): assert pu239.name == 'Pu239' @@ -243,6 +255,29 @@ def test_mlbw(sm150): assert sorted(xs.keys()) == [2, 18, 102] assert np.all(xs[18] == 0.0) +#FIXME +def test_mlbw_cov(ti50): + #Testing on first range + cov = ti50.res_covariance.ranges[0] + res = ti50.resonances.ranges[0] + assert cov.parameters['energy'][0] == pytest.approx(-21020.) + assert res.parameters['energy'][0] == cov.parameters['energy'][0] + assert isinstance(cov, openmc.data.resonance_covariance.MultiLevelBreitWignerCovariance) + assert cov.energy_min == pytest.approx(1e-5) + assert cov.energy_max == pytest.approx(587000.) + assert cov.covariance[0,0] == pytest.approx(1.410177e5) + + cov.res_subset('L',[1,1]) + subset = cov.parameters_subset + assert not subset.empty + assert cov.cov_subset is not None + assert (subset['L'] == 1).all() + cov.sample_resonance_parameters(1) + xs = cov.reconstruct([10., 100., 1000.], res, 0) + assert sorted(xs.keys()) == [2, 18, 102] + +#FIXME + def test_reichmoore(gd154): res = gd154.resonances From ebd66a456168f4068a9f51b4bc463fd2b3b88ac7 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 17 Jul 2018 13:00:08 -0500 Subject: [PATCH 060/100] Added tests for RM covariance --- tests/unit_tests/test_data_neutron.py | 73 ++++++++++++++++----------- 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/tests/unit_tests/test_data_neutron.py b/tests/unit_tests/test_data_neutron.py index a412f2024c..90d2799455 100644 --- a/tests/unit_tests/test_data_neutron.py +++ b/tests/unit_tests/test_data_neutron.py @@ -39,7 +39,7 @@ def sm150(): def gd154(): """Gd154 ENDF data (contains Reich Moore resonance range)""" filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-064_Gd_154.endf') - return openmc.data.IncidentNeutron.from_endf(filename) + return openmc.data.IncidentNeutron.from_endf(filename, get_covariance = True) @pytest.fixture(scope='module') @@ -96,12 +96,6 @@ def am244(): endf_file = os.path.join(_ENDF_DATA, 'neutrons', 'n-095_Am_244.endf') return openmc.data.IncidentNeutron.from_njoy(endf_file) -@pytest.fixture(scope='module') -def gd154cov(): - """Gd154 ENDF data (contains Reich Moore resonance range)""" - filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-064_Gd_154.endf') - return openmc.data.IncidentNeutron.from_endf(filename, get_covariance=True) - @pytest.fixture(scope='module') def ti50(): """Ti50 ENDF data (contains Multi-level Breit-Wigner resonance range)""" @@ -255,29 +249,6 @@ def test_mlbw(sm150): assert sorted(xs.keys()) == [2, 18, 102] assert np.all(xs[18] == 0.0) -#FIXME -def test_mlbw_cov(ti50): - #Testing on first range - cov = ti50.res_covariance.ranges[0] - res = ti50.resonances.ranges[0] - assert cov.parameters['energy'][0] == pytest.approx(-21020.) - assert res.parameters['energy'][0] == cov.parameters['energy'][0] - assert isinstance(cov, openmc.data.resonance_covariance.MultiLevelBreitWignerCovariance) - assert cov.energy_min == pytest.approx(1e-5) - assert cov.energy_max == pytest.approx(587000.) - assert cov.covariance[0,0] == pytest.approx(1.410177e5) - - cov.res_subset('L',[1,1]) - subset = cov.parameters_subset - assert not subset.empty - assert cov.cov_subset is not None - assert (subset['L'] == 1).all() - cov.sample_resonance_parameters(1) - xs = cov.reconstruct([10., 100., 1000.], res, 0) - assert sorted(xs.keys()) == [2, 18, 102] - -#FIXME - def test_reichmoore(gd154): res = gd154.resonances @@ -312,6 +283,48 @@ def test_rml(cl35): assert isinstance(group, openmc.data.SpinGroup) +def test_mlbw_cov(ti50): + #Testing on first range only + cov = ti50.res_covariance.ranges[0] + res = ti50.resonances.ranges[0] + assert cov.parameters['energy'][0] == pytest.approx(-21020.) + assert res.parameters['energy'][0] == cov.parameters['energy'][0] + assert isinstance(cov, openmc.data.resonance_covariance.MultiLevelBreitWignerCovariance) + assert cov.energy_min == pytest.approx(1e-5) + assert cov.energy_max == pytest.approx(587000.) + assert cov.covariance[0,0] == pytest.approx(1.410177e5) + + cov.res_subset('L',[1,1]) + subset = cov.parameters_subset + assert not subset.empty + assert cov.cov_subset is not None + assert (subset['L'] == 1).all() + cov.sample_resonance_parameters(1) + xs = cov.reconstruct([10., 100., 1000.], res, 0) + assert sorted(xs.keys()) == [2, 18, 102] + + +def test_rm_cov(gd154): + #Testing on first range only + cov = gd154.res_covariance.ranges[0] + res = gd154.resonances.ranges[0] + assert cov.parameters['energy'][0] == pytest.approx(-2.200001) + assert res.parameters['energy'][0] == cov.parameters['energy'][0] + assert isinstance(cov, openmc.data.resonance_covariance.ReichMooreCovariance) + assert cov.energy_min == pytest.approx(1e-5) + assert cov.energy_max == pytest.approx(2760.) + assert cov.covariance[0,0] == pytest.approx(0.8895997) + + cov.res_subset('energy',[0,100]) + subset = cov.parameters_subset + assert not subset.empty + assert cov.cov_subset is not None + assert (subset['energy'] < 100).all() + cov.sample_resonance_parameters(1) + xs = cov.reconstruct([10., 100., 1000.], res, 0) + assert sorted(xs.keys()) == [2, 18, 102] + + def test_madland_nix(am241): fission = am241.reactions[18] prompt_neutron = fission.products[0] From 447d85adefe7c8f34d68346a61d430fe44813caa Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 17 Jul 2018 13:13:29 -0500 Subject: [PATCH 061/100] some spelling --- .../nuclear-data-resonance-covariance.ipynb | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/examples/jupyter/nuclear-data-resonance-covariance.ipynb b/examples/jupyter/nuclear-data-resonance-covariance.ipynb index 88c421ce5f..c673dfea56 100644 --- a/examples/jupyter/nuclear-data-resonance-covariance.ipynb +++ b/examples/jupyter/nuclear-data-resonance-covariance.ipynb @@ -28,7 +28,7 @@ "source": [ "### ENDF: Resonance Covariance Data\n", "\n", - "We can also load the resonance covariance data contined within File 32 of ENDF. Let's download the ENDF/B-VII.1 evaluation for $^{157}$Gd and load it in:" + "We can also load the resonance covariance data contained within File 32 of ENDF. Let's download the ENDF/B-VII.1 evaluation for $^{157}$Gd and load it in:" ] }, { @@ -107,7 +107,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This covariance matrix currently only stores the upper triangular portion as covariance matrix are symmetric. Plotting the covariance matrix:" + "This covariance matrix currently only stores the upper triangular portion as covariance matrices are symmetric. Plotting the covariance matrix:" ] }, { @@ -118,7 +118,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 5, @@ -129,7 +129,7 @@ "data": { "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -226,18 +226,18 @@ "text": [ "Sample 1\n", " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.032744 0 2.0 0.000476 0.104726 0.0 0.0\n", - "1 2.824910 0 2.0 0.000367 0.093434 0.0 0.0\n", - "2 16.246703 0 1.0 0.000428 0.128670 0.0 0.0\n", - "3 16.772205 0 2.0 0.012712 0.087642 0.0 0.0\n", - "4 20.558978 0 2.0 0.011754 0.088571 0.0 0.0\n", + "0 0.035303 0 2.0 0.000482 0.100681 0.0 0.0\n", + "1 2.831054 0 2.0 0.000357 0.094362 0.0 0.0\n", + "2 16.244335 0 1.0 0.000400 0.049005 0.0 0.0\n", + "3 16.772396 0 2.0 0.012005 0.085736 0.0 0.0\n", + "4 20.560952 0 2.0 0.010648 0.098282 0.0 0.0\n", "Sample 2\n", " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.030677 0 2.0 0.000474 0.108886 0.0 0.0\n", - "1 2.822705 0 2.0 0.000357 0.099604 0.0 0.0\n", - "2 16.250280 0 1.0 0.000527 0.128495 0.0 0.0\n", - "3 16.770029 0 2.0 0.013519 0.076974 0.0 0.0\n", - "4 20.555458 0 2.0 0.011091 0.094415 0.0 0.0\n" + "0 0.032481 0 2.0 0.000477 0.105662 0.0 0.0\n", + "1 2.825417 0 2.0 0.000338 0.099793 0.0 0.0\n", + "2 16.248565 0 1.0 0.000465 0.118105 0.0 0.0\n", + "3 16.767121 0 2.0 0.012827 0.072236 0.0 0.0\n", + "4 20.559938 0 2.0 0.011424 0.085309 0.0 0.0\n" ] } ], @@ -268,8 +268,8 @@ { "data": { "text/plain": [ - "[,\n", - " ]" + "[,\n", + " ]" ] }, "execution_count": 9, @@ -305,9 +305,9 @@ }, { "data": { - "image/png": "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\n", + "image/png": "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\nJk0qPG8AAAAASUVORK5CYII=\n", "text/plain": [ - "" + "" ] }, "metadata": {}, From b197b2bba2832d2f9c2225c9f3251e7cd05ef8f9 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 17 Jul 2018 13:20:23 -0500 Subject: [PATCH 062/100] Some cleanup of dependencies --- openmc/data/resonance_covariance.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index 24b3e1e9a8..5894b8c314 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -3,11 +3,8 @@ import warnings import io import numpy as np -from numpy.polynomial import Polynomial -from scipy import sparse import pandas as pd -from .data import NEUTRON_MASS from .endf import get_head_record, get_cont_record, get_tab1_record, get_list_record, get_intg_record import openmc.checkvalue as cv from .resonance import Resonances @@ -453,7 +450,6 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): # Other scatter radius parameters items = get_cont_record(file_obj) target_spin = items[0] - ap = Polynomial((items[1],)) # energy-independent scattering-radius LCOMP = items[3] # Flag for compatibility 0,1,2 - 2 is compact form NLS = items[4] # number of l-values @@ -728,7 +724,6 @@ class ReichMooreCovariance(ResonanceCovarianceRange): # Other scatter radius parameters items = get_cont_record(file_obj) target_spin = items[0] - ap = Polynomial((items[1],)) LCOMP = items[3] # Flag for compatibility 0,1,2 - 2 is compact form NLS = items[4] # Number of l-values From 219ea89e8354b472794f662a402b166a6e67c37a Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 17 Jul 2018 13:43:59 -0500 Subject: [PATCH 063/100] style --- openmc/data/resonance_covariance.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index 5894b8c314..50fd09add3 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -129,6 +129,7 @@ class ResonanceCovariances(Resonances): class ResonanceCovarianceRange(object): """Resonace covariance range. Base class for different formalisms. + Parameters ---------- energy_min : float From f69ab27b3dd5ff32d8861def4229c051200d4ca4 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 17 Jul 2018 14:02:37 -0500 Subject: [PATCH 064/100] Added to sphinx autodocs --- docs/source/pythonapi/data.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/source/pythonapi/data.rst b/docs/source/pythonapi/data.rst index 7feaa8d608..500920edc2 100644 --- a/docs/source/pythonapi/data.rst +++ b/docs/source/pythonapi/data.rst @@ -78,7 +78,12 @@ Resonance Data openmc.data.SingleLevelBreitWigner openmc.data.MultiLevelBreitWigner openmc.data.ReichMoore + openmc.data.ResonaneCovariances openmc.data.RMatrixLimited + openmc.data.ResonanceCovarianceRange + openmc.data.SingleLevelBreitWignerCovariance + openmc.data.MultiLevelBreitWignerCovariance + openmc.data.ReichMooreCovariance openmc.data.ParticlePair openmc.data.SpinGroup openmc.data.Unresolved From 1963fbe60b9b91fc124c2c4608dca8a72ad5628a Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 17 Jul 2018 14:59:07 -0500 Subject: [PATCH 065/100] More docs work --- docs/source/conf.py | 2 +- docs/source/pythonapi/data.rst | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index eeecba23e4..03dde6b8bb 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -54,7 +54,7 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.viewcode', 'sphinx.ext.imgconverter', - 'sphinx_numfig', + 'sphinx.ext.numfig', 'notebook_sphinxext'] # Add any paths that contain templates here, relative to this directory. diff --git a/docs/source/pythonapi/data.rst b/docs/source/pythonapi/data.rst index 500920edc2..b3668dd1f5 100644 --- a/docs/source/pythonapi/data.rst +++ b/docs/source/pythonapi/data.rst @@ -78,12 +78,12 @@ Resonance Data openmc.data.SingleLevelBreitWigner openmc.data.MultiLevelBreitWigner openmc.data.ReichMoore - openmc.data.ResonaneCovariances openmc.data.RMatrixLimited - openmc.data.ResonanceCovarianceRange - openmc.data.SingleLevelBreitWignerCovariance - openmc.data.MultiLevelBreitWignerCovariance - openmc.data.ReichMooreCovariance + openmc.data.resonance_covariance.ResonanceCovariances + openmc.data.resonance_covariance.ResonanceCovarianceRange + openmc.data.resonance_covariance.SingleLevelBreitWignerCovariance + openmc.data.resonance_covariance.MultiLevelBreitWignerCovariance + openmc.data.resonance_covariance.ReichMooreCovariance openmc.data.ParticlePair openmc.data.SpinGroup openmc.data.Unresolved From 416a89c7852208c61b4e1e57a5e43af149f9c022 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 17 Jul 2018 15:14:50 -0500 Subject: [PATCH 066/100] added example notebook for covariance module --- docs/source/examples/index.rst | 1 + .../nuclear-data-resonance-covariance.rst | 13 ++ examples/jupyter/mgxs-part-i.ipynb | 160 ++---------------- 3 files changed, 24 insertions(+), 150 deletions(-) create mode 100644 docs/source/examples/nuclear-data-resonance-covariance.rst diff --git a/docs/source/examples/index.rst b/docs/source/examples/index.rst index 89a1f1fe0b..bcb1b1ad8f 100644 --- a/docs/source/examples/index.rst +++ b/docs/source/examples/index.rst @@ -24,6 +24,7 @@ Basic Usage triso candu nuclear-data + nuclear-data-resonance-covariance ------------------------------------ Multi-Group Cross Section Generation diff --git a/docs/source/examples/nuclear-data-resonance-covariance.rst b/docs/source/examples/nuclear-data-resonance-covariance.rst new file mode 100644 index 0000000000..4b505c9a58 --- /dev/null +++ b/docs/source/examples/nuclear-data-resonance-covariance.rst @@ -0,0 +1,13 @@ +.. _notebook_nuclear_data_resonance_covariance: + +================================== +Nuclear Data: Resonance Covariance +================================== + +.. only:: html + + .. notebook:: ../../../examples/jupyter/nuclear-data-resonance-covariance.ipynb + +.. only:: latex + + IPython notebooks must be viewed in the online HTML documentation. diff --git a/examples/jupyter/mgxs-part-i.ipynb b/examples/jupyter/mgxs-part-i.ipynb index 6f3ee8fe7a..d09aeaa464 100644 --- a/examples/jupyter/mgxs-part-i.ipynb +++ b/examples/jupyter/mgxs-part-i.ipynb @@ -28,7 +28,9 @@ { "cell_type": "code", "execution_count": 1, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [ { "data": { @@ -132,7 +134,9 @@ { "cell_type": "code", "execution_count": 2, - "metadata": {}, + "metadata": { + "collapsed": false + }, "outputs": [], "source": [ "%matplotlib inline\n", @@ -153,33 +157,11 @@ { "cell_type": "code", "execution_count": 3, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ -<<<<<<< HEAD - "# Instantiate some Nuclides\n", - "h1 = openmc.Nuclide('H1')\n", - "o16 = openmc.Nuclide('O16')\n", - "u235 = openmc.Nuclide('U235')\n", - "u238 = openmc.Nuclide('U238')\n", - "zr90 = openmc.Nuclide('Zr90')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the nuclides we defined, we will now create a material for the homogeneous medium." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ -======= ->>>>>>> upstream/develop "# Instantiate a Material and register the Nuclides\n", "inf_medium = openmc.Material(name='moderator')\n", "inf_medium.set_density('g/cc', 5.)\n", @@ -199,15 +181,10 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": 5, - "metadata": {}, -======= "execution_count": 4, "metadata": { "collapsed": true }, ->>>>>>> upstream/develop "outputs": [], "source": [ "# Instantiate a Materials collection and export to XML\n", @@ -224,15 +201,10 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": 6, - "metadata": {}, -======= "execution_count": 5, "metadata": { "collapsed": true }, ->>>>>>> upstream/develop "outputs": [], "source": [ "# Instantiate boundary Planes\n", @@ -251,15 +223,10 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": 7, - "metadata": {}, -======= "execution_count": 6, "metadata": { "collapsed": false }, ->>>>>>> upstream/develop "outputs": [], "source": [ "# Instantiate a Cell\n", @@ -281,15 +248,10 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": 8, - "metadata": {}, -======= "execution_count": 7, "metadata": { "collapsed": true }, ->>>>>>> upstream/develop "outputs": [], "source": [ "# Create root universe\n", @@ -305,15 +267,10 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": 9, - "metadata": {}, -======= "execution_count": 8, "metadata": { "collapsed": false }, ->>>>>>> upstream/develop "outputs": [], "source": [ "# Create Geometry and set root Universe\n", @@ -332,15 +289,10 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": 10, - "metadata": {}, -======= "execution_count": 9, "metadata": { "collapsed": true }, ->>>>>>> upstream/develop "outputs": [], "source": [ "# OpenMC simulation parameters\n", @@ -373,15 +325,10 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": 11, - "metadata": {}, -======= "execution_count": 10, "metadata": { "collapsed": false }, ->>>>>>> upstream/develop "outputs": [], "source": [ "# Instantiate a 2-group EnergyGroups object\n", @@ -417,15 +364,10 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": 12, - "metadata": {}, -======= "execution_count": 11, "metadata": { "collapsed": false }, ->>>>>>> upstream/develop "outputs": [], "source": [ "# Instantiate a few different sections\n", @@ -447,15 +389,10 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": 13, - "metadata": {}, -======= "execution_count": 12, "metadata": { "collapsed": false }, ->>>>>>> upstream/develop "outputs": [ { "data": { @@ -493,29 +430,18 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": 14, - "metadata": {}, -======= "execution_count": 13, "metadata": { "collapsed": false }, ->>>>>>> upstream/develop "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ -<<<<<<< HEAD - "/home/icmeyer/miniconda3/lib/python3.6/site-packages/openmc-0.9.0-py3.6-linux-x86_64.egg/openmc/mixin.py:61: IDWarning: Another CellFilter instance already exists with id=3.\n", - " warn(msg, IDWarning)\n", - "/home/icmeyer/miniconda3/lib/python3.6/site-packages/openmc-0.9.0-py3.6-linux-x86_64.egg/openmc/mixin.py:61: IDWarning: Another EnergyFilter instance already exists with id=4.\n", -======= "/home/romano/openmc/openmc/mixin.py:61: IDWarning: Another CellFilter instance already exists with id=3.\n", " warn(msg, IDWarning)\n", "/home/romano/openmc/openmc/mixin.py:61: IDWarning: Another EnergyFilter instance already exists with id=4.\n", ->>>>>>> upstream/develop " warn(msg, IDWarning)\n" ] } @@ -546,11 +472,6 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": null, - "metadata": {}, - "outputs": [], -======= "execution_count": 14, "metadata": { "collapsed": false @@ -702,7 +623,6 @@ "output_type": "execute_result" } ], ->>>>>>> upstream/develop "source": [ "# Run OpenMC\n", "openmc.run()" @@ -724,15 +644,10 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": null, - "metadata": {}, -======= "execution_count": 15, "metadata": { "collapsed": false }, ->>>>>>> upstream/develop "outputs": [], "source": [ "# Load the last statepoint file\n", @@ -755,15 +670,10 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": null, - "metadata": {}, -======= "execution_count": 16, "metadata": { "collapsed": false }, ->>>>>>> upstream/develop "outputs": [], "source": [ "# Load the tallies from the statepoint into each MGXS object\n", @@ -795,11 +705,6 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": null, - "metadata": {}, - "outputs": [], -======= "execution_count": 17, "metadata": { "collapsed": false @@ -822,7 +727,6 @@ ] } ], ->>>>>>> upstream/develop "source": [ "total.print_xs()" ] @@ -836,11 +740,6 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": null, - "metadata": {}, - "outputs": [], -======= "execution_count": 18, "metadata": { "collapsed": false @@ -893,7 +792,6 @@ "output_type": "execute_result" } ], ->>>>>>> upstream/develop "source": [ "df = scattering.get_pandas_dataframe()\n", "df.head(10)" @@ -908,15 +806,10 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": null, - "metadata": {}, -======= "execution_count": 19, "metadata": { "collapsed": false }, ->>>>>>> upstream/develop "outputs": [], "source": [ "absorption.export_xs_data(filename='absorption-xs', format='excel')" @@ -931,15 +824,10 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": null, - "metadata": {}, -======= "execution_count": 20, "metadata": { "collapsed": false }, ->>>>>>> upstream/develop "outputs": [], "source": [ "total.build_hdf5_store(filename='mgxs', append=True)\n", @@ -963,11 +851,6 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": null, - "metadata": {}, - "outputs": [], -======= "execution_count": 21, "metadata": { "collapsed": false @@ -1030,7 +913,6 @@ "output_type": "execute_result" } ], ->>>>>>> upstream/develop "source": [ "# Use tally arithmetic to compute the difference between the total, absorption and scattering\n", "difference = total.xs_tally - absorption.xs_tally - scattering.xs_tally\n", @@ -1048,11 +930,6 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": null, - "metadata": {}, - "outputs": [], -======= "execution_count": 22, "metadata": { "collapsed": false @@ -1115,7 +992,6 @@ "output_type": "execute_result" } ], ->>>>>>> upstream/develop "source": [ "# Use tally arithmetic to compute the absorption-to-total MGXS ratio\n", "absorption_to_total = absorption.xs_tally / total.xs_tally\n", @@ -1126,11 +1002,6 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": null, - "metadata": {}, - "outputs": [], -======= "execution_count": 23, "metadata": { "collapsed": false @@ -1193,7 +1064,6 @@ "output_type": "execute_result" } ], ->>>>>>> upstream/develop "source": [ "# Use tally arithmetic to compute the scattering-to-total MGXS ratio\n", "scattering_to_total = scattering.xs_tally / total.xs_tally\n", @@ -1211,11 +1081,6 @@ }, { "cell_type": "code", -<<<<<<< HEAD - "execution_count": null, - "metadata": {}, - "outputs": [], -======= "execution_count": 24, "metadata": { "collapsed": false @@ -1278,7 +1143,6 @@ "output_type": "execute_result" } ], ->>>>>>> upstream/develop "source": [ "# Use tally arithmetic to ensure that the absorption- and scattering-to-total MGXS ratios sum to unity\n", "sum_ratio = absorption_to_total + scattering_to_total\n", @@ -1304,13 +1168,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", -<<<<<<< HEAD - "version": "3.6.3" -======= "version": "3.6.0" ->>>>>>> upstream/develop } }, "nbformat": 4, - "nbformat_minor": 1 + "nbformat_minor": 0 } From be5b111de9f5e78381c929b0022e31a445825df3 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 17 Jul 2018 15:41:15 -0500 Subject: [PATCH 067/100] removed changes to reconstruction functions for pull request --- openmc/data/grid.py | 62 --------------------------------------------- 1 file changed, 62 deletions(-) diff --git a/openmc/data/grid.py b/openmc/data/grid.py index 9f40792040..e63919ac29 100644 --- a/openmc/data/grid.py +++ b/openmc/data/grid.py @@ -112,65 +112,3 @@ def thin(x, y, tolerance=0.001): y_out[i_remove] = np.nan return x_out[np.isfinite(x_out)], y_out[np.isfinite(y_out)] - -def linearizeIter(x, f, tolerance=0.001, unified=True): - """Return a tabulated representation of multiple functions of one - variable. - - Parameters - ---------- - x : Iterable of float - Initial x values at which the function should be evaluated - f : Callable - Function of a single variable that returns a dictionary - tolerance : float - Tolerance on the interpolation error - unified : boolean - Flag to indicate usage of a unified grid for all functions - if True, or independent grids if False - - Returns - ------- - numpy.ndarray - Tabulated values of the independent variable - dictionary of numpy.ndarray's - Tabulated values of the dependent variable - - """ - if unified==True: - # Initialize dictionary of output - y_dict = f(x[0]) - - for item in y_dict: - #Initialize output - x_out = [] - - #Initialize stacks - x_stack = [x[0]] - y_stack = [y_dict[item]] - for i in range(x.shape[0] - 1): - x_stack.insert(0, x[i + 1]) - y_stack.insert(0, f(x[i + 1])[item]) - - while True: - x_high, x_low = x_stack[-2:] - y_high, y_low = y_stack[-2:] - x_mid = 0.5*(x_low + x_high) - y_mid = f(x_mid)[item] - - y_interp = y_low + (y_high - y_low)/(x_high - x_low)*(x_mid - x_low) - error = abs((y_interp - y_mid)/y_mid) - if error > tolerance: - x_stack.insert(-1, x_mid) - y_stack.insert(-1, y_mid) - else: - x_out.append(x_stack.pop()) - y_stack.pop() - if len(x_stack) == 1: - break - - x_out.append(x_stack.pop()) - x=np.array(x_out) #Use x_out for initial x values in next item - - y_dict_out = f(np.array(x_out)) - return np.array(x_out), y_dict_out From 8956f2a58526e27d3a13163ec6b313716fbc5d08 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 17 Jul 2018 15:49:02 -0500 Subject: [PATCH 068/100] Some cleanup for pr --- openmc/data/neutron.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 8023ff5902..9482c5bb04 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -1,6 +1,6 @@ -from __future__ import division, unicode_literals import sys -from collections import OrderedDict, Iterable, Mapping, MutableMapping +from collections import OrderedDict +from collections.abc import Iterable, Mapping, MutableMappingimport sys from io import StringIO from itertools import chain from math import log10 @@ -10,7 +10,6 @@ import shutil import tempfile from warnings import warn -from six import string_types import numpy as np import h5py @@ -108,6 +107,7 @@ class IncidentNeutron(EqualityMixin): :meth:`IncidentNeutron.from_ace`. Parameters + ---------- name : str Name of the nuclide using the GND naming convention atomic_number : int @@ -887,10 +887,3 @@ class IncidentNeutron(EqualityMixin): data[2].xs['0K'] = xs return data -import sys -from collections import OrderedDict -from collections.abc import Iterable, Mapping, MutableMapping -from io import StringIO -from itertools import chain -from math import log10 -from numbers import Integral, Real From 9d3f4797cadba64186128140b3454fa5fe5c0213 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 17 Jul 2018 08:07:24 -0500 Subject: [PATCH 069/100] Expand style guide for C++ code --- docs/source/devguide/styleguide.rst | 103 +++++++++++++++++++++------- 1 file changed, 79 insertions(+), 24 deletions(-) diff --git a/docs/source/devguide/styleguide.rst b/docs/source/devguide/styleguide.rst index ccf6bf5217..e0e67a6d62 100644 --- a/docs/source/devguide/styleguide.rst +++ b/docs/source/devguide/styleguide.rst @@ -182,37 +182,83 @@ Always use C++-style comments (``//``) as opposed to C-style (``/**/``). (It is more difficult to comment out a large section of code that uses C-style comments.) -Header files should always use include guards with the following style (See -`SF.8 `_: - -.. code-block:: C++ - - #ifndef MODULE_NAME_H - #define MODULE_NAME_H - ... - content - ... - #endif // MODULE_NAME_H - Do not use C-style casting. Always use the C++-style casts ``static_cast``, ``const_cast``, or ``reinterpret_cast``. (See `ES.49 `_) +Source Files +------------ + +Use a ``.cpp`` suffix for code files and ``.h`` for header files. + +Header files should always use include guards with the following style (See +`SF.8 `_): + +.. code-block:: C++ + + #ifndef OPENMC_MODULE_NAME_H + #define OPENMC_MODULE_NAME_H + + namespace openmc { + ... + content + ... + } + + #endif // OPENMC_MODULE_NAME_H + +Avoid hidden dependencies by always including a related header file first, +followed by C/C++ library includes, other library includes, and then local +includes. For example: + +.. code-block:: C++ + + // foo.cpp + #include "foo.h" + + #include + #include + #include + + #include "hdf5.h" + #include "pugixml.hpp" + + #include "error.h" + #include "random_lcg.h" + Naming ------ -In general, write your code in lower-case. Having code in all caps does not -enhance code readability or otherwise. - Struct and class names should be CamelCase, e.g. ``HexLattice``. Functions (including member functions) should be lower-case with underscores, e.g. ``get_indices``. -Local variables, global variables, and struct/class attributes should be -lower-case with underscores (e.g. ``n_cells``) except for physics symbols that -are written differently by convention (e.g. ``E`` for energy). +Local variables, global variables, and struct/class member variables should be +lower-case with underscores (e.g., ``n_cells``) except for physics symbols that +are written differently by convention (e.g., ``E`` for energy). Data members of +classes (but not structs) additionally have trailing underscores (e.g., +``a_class_member_``). -Const variables should be in upper-case with underscores, e.g. ``SQRT_PI``. +Accessors and mutators (get and set functions) may be named like +variables. These often correspond to actual member variables, but this is not +required. For example, ``int count()`` and ``void set_count(int count)``. + +Variables declared constexpr or const that have static storage duration (exist +for the duration of the program) should be upper-case with underscores, +e.g., ``SQRT_PI``. + +Use C++-style declarator layout (see `NL.18 +`_): +pointer and reference operators in declarations should be placed adject to the +base type rather than the variable name. Avoid declaring multiple names in a +single declaration to avoid confusion: + +.. code-block:: C++ + + T* p; // good + T& p; // good + T *p; // bad + T* p, q; // misleading Curly braces ------------ @@ -280,6 +326,13 @@ the same line or omit the braces entirely. for (int i = 0; i < 5; i++) content(); +Documentation +------------- + +Classes, structs, and functions are to be annotated for the `Doxygen +`_ documentation generation tool. Use the +``\`` form of Doxygen commands, e.g., ``\brief`` instead of ``@brief``. + ------ Python ------ @@ -288,15 +341,17 @@ Style for Python code should follow PEP8_. Docstrings for functions and methods should follow numpydoc_ style. -Python code should work with both Python 2.7+ and Python 3.0+. +Python code should work with Python 3.4+. -Use of third-party Python packages should be limited to numpy_, scipy_, and -h5py_. Use of other third-party packages must be implemented as optional -dependencies rather than required dependencies. +Use of third-party Python packages should be limited to numpy_, scipy_, +matplotlib_, pandas_, and h5py_. Use of other third-party packages must be +implemented as optional dependencies rather than required dependencies. .. _C++ Core Guidelines: http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines .. _PEP8: https://www.python.org/dev/peps/pep-0008/ .. _numpydoc: https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt .. _numpy: http://www.numpy.org/ -.. _scipy: http://www.scipy.org/ +.. _scipy: https://www.scipy.org/ +.. _matplotlib: https://matplotlib.org/ +.. _pandas: https://pandas.pydata.org/ .. _h5py: http://www.h5py.org/ From b6f56865ddd21f007c9a532cabbf8b7f8d78614f Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 17 Jul 2018 08:43:53 -0500 Subject: [PATCH 070/100] Reformat README as a markdown file --- README.md | 58 +++++++++++++++++++++++++++++++++++++++ readme.rst | 80 ------------------------------------------------------ 2 files changed, 58 insertions(+), 80 deletions(-) create mode 100644 README.md delete mode 100644 readme.rst diff --git a/README.md b/README.md new file mode 100644 index 0000000000..ac5847cfad --- /dev/null +++ b/README.md @@ -0,0 +1,58 @@ +# OpenMC Monte Carlo Particle Transport Code + +[![License](https://img.shields.io/github/license/mit-crpg/openmc.svg)](http://openmc.readthedocs.io/en/latest/license.html) +[![Travis CI build status (Linux)](https://travis-ci.org/mit-crpg/openmc.svg?branch=develop)](https://travis-ci.org/mit-crpg/openmc) +[![Code Coverage](https://coveralls.io/repos/github/mit-crpg/openmc/badge.svg?branch=develop)](https://coveralls.io/github/mit-crpg/openmc?branch=develop) + +The OpenMC project aims to provide a fully-featured Monte Carlo particle +transport code based on modern methods. It is a constructive solid geometry, +continuous-energy transport code that uses HDF5 format cross sections. The +project started under the Computational Reactor Physics Group at MIT. + +Complete documentation on the usage of OpenMC is hosted on Read the Docs (both +for the [latest release](http://openmc.readthedocs.io/en/stable/) and +[developmental](http://openmc.readthedocs.io/en/latest/) version). If you are +interested in the project or would like to help and contribute, please send a +message to the OpenMC User's Group [mailing +list](https://groups.google.com/forum/?fromgroups=#!forum/openmc-users). + +## Installation + +Detailed [installation +instructions](http://openmc.readthedocs.io/en/stable/usersguide/install.html) +can be found in the User's Guide. + +## Citing + +If you use OpenMC in your research, please consider giving proper attribution by +citing the following publication: + +- Paul K. Romano, Nicholas E. Horelik, Bryan R. Herman, Adam G. Nelson, Benoit + Forget, and Kord Smith, "[OpenMC: A State-of-the-Art Monte Carlo Code for + Research and Development](https://doi.org/10.1016/j.anucene.2014.07.048)," + *Ann. Nucl. Energy*, **82**, 90--97 (2015). + +## Troubleshooting + +If you run into problems compiling, installing, or running OpenMC, first check +the [Troubleshooting +section](http://openmc.readthedocs.io/en/stable/usersguide/troubleshoot.html) in +the User's Guide. If you are not able to find a solution to your problem there, +please send a message to the User's Group [mailing +list](https://groups.google.com/forum/?fromgroups=#!forum/openmc-users). + +## Reporting Bugs + +OpenMC is hosted on GitHub and all bugs are reported and tracked through the +[Issues](https://github.com/mit-crpg/openmc/issues) feature on GitHub. However, +GitHub Issues should not be used for common troubleshooting purposes. If you are +having trouble installing the code or getting your model to run properly, you +should first send a message to the User's Group mailing list. If it turns out +your issue really is a bug in the code, an issue will then be created on +GitHub. If you want to request that a feature be added to the code, you may +create an Issue on github. + +## License + +OpenMC is distributed under the MIT/X +[license](http://openmc.readthedocs.io/en/stable/license.html). diff --git a/readme.rst b/readme.rst deleted file mode 100644 index 32cbb34e14..0000000000 --- a/readme.rst +++ /dev/null @@ -1,80 +0,0 @@ -========================================== -OpenMC Monte Carlo Particle Transport Code -========================================== - -|licensebadge| |travisbadge| |coverallsbadge| - -The OpenMC project aims to provide a fully-featured Monte Carlo particle -transport code based on modern methods. It is a constructive solid geometry, -continuous-energy transport code that uses HDF5 format cross sections. The -project started under the Computational Reactor Physics Group at MIT. - -Complete documentation on the usage of OpenMC is hosted on Read the Docs (both -for the `latest release`_ and developmental_ version). If you are interested in -the project or would like to help and contribute, please send a message to the -OpenMC User's Group `mailing list`_. - ------------- -Installation ------------- - -Detailed `installation instructions`_ can be found in the User's Guide. - ------- -Citing ------- - -If you use OpenMC in your research, please consider giving proper attribution by -citing the following publication: - -- Paul K. Romano, Nicholas E. Horelik, Bryan R. Herman, Adam G. Nelson, Benoit - Forget, and Kord Smith, "`OpenMC: A State-of-the-Art Monte Carlo Code for - Research and Development `_," - *Ann. Nucl. Energy*, **82**, 90--97 (2015). - ---------------- -Troubleshooting ---------------- - -If you run into problems compiling, installing, or running OpenMC, first check -the `Troubleshooting section`_ in the User's Guide. If you are not able to find -a solution to your problem there, please send a message to the User's Group -`mailing list`_. - --------------- -Reporting Bugs --------------- - -OpenMC is hosted on GitHub and all bugs are reported and tracked through the -Issues_ feature on GitHub. However, GitHub Issues should not be used for common -troubleshooting purposes. If you are having trouble installing the code or -getting your model to run properly, you should first send a message to the -User's Group `mailing list`_. If it turns out your issue really is a bug in the -code, an issue will then be created on GitHub. If you want to request that a -feature be added to the code, you may create an Issue on github. - -------- -License -------- - -OpenMC is distributed under the MIT/X license_. - -.. _latest release: http://openmc.readthedocs.io/en/stable/ -.. _developmental: http://openmc.readthedocs.io/en/latest/ -.. _mailing list: https://groups.google.com/forum/?fromgroups=#!forum/openmc-users -.. _installation instructions: http://openmc.readthedocs.io/en/stable/usersguide/install.html -.. _Troubleshooting section: http://openmc.readthedocs.io/en/stable/usersguide/troubleshoot.html -.. _Issues: https://github.com/mit-crpg/openmc/issues -.. _license: http://openmc.readthedocs.io/en/stable/license.html - -.. |licensebadge| image:: https://img.shields.io/github/license/mit-crpg/openmc.svg - :target: http://openmc.readthedocs.io/en/latest/license.html - :alt: License - -.. |travisbadge| image:: https://travis-ci.org/mit-crpg/openmc.svg?branch=develop - :target: https://travis-ci.org/mit-crpg/openmc - :alt: Travis CI build status (Linux) - -.. |coverallsbadge| image:: https://coveralls.io/repos/github/mit-crpg/openmc/badge.svg?branch=develop - :target: https://coveralls.io/github/mit-crpg/openmc?branch=develop - :alt: Code Coverage From ebbf855a7bf45c3c1a64facf0256d0dc9ba46c79 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 17 Jul 2018 15:42:59 -0500 Subject: [PATCH 071/100] Add CONTRIBUTING.md and code of conduct --- CODE_OF_CONDUCT.md | 73 ++++++++++++++++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 46 +++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..5aa0bcd34a --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,73 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at openmc@anl.gov. All complaints will +be reviewed and investigated and will result in a response that is deemed +necessary and appropriate to the circumstances. The project team is obligated to +maintain confidentiality with regard to the reporter of an incident. Further +details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..d02a543f87 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,46 @@ +# Contributing to OpenMC + +Welcome, and thank you for considering contributing to OpenMC! We look forward +to welcoming new members to the community and will do our best to help you get +up to speed. + +## Code of Conduct + +Participants in the OpenMC project are expected to follow and uphold the [Code +of Conduct](CODE_OF_CONDUCT.md). Please report any unacceptable behavior to +openmc@anl.gov. + +## Resources + +- [GitHub Repository](https://github.com/mit-crpg/openmc) +- [Documentation](http://openmc.readthedocs.io/en/latest) +- [User's Mailing List](openmc-users@googlegroups.com) +- [Developer's Mailing List](openmc-dev@googlegroups.com) +- [Slack Community](https://openmc.slack.com/signup) (If you don't see your + domain listed, contact openmc@anl.gov) + +## How to Report Bugs + +OpenMC is hosted on GitHub and all bugs are reported and tracked through the +[Issues](https://github.com/mit-crpg/openmc/issues) listed on GitHub. + +## How to Suggest Enhancements + +We welcome suggestions for new features or enhancements to the code and +encourage you to submit them as Issues on GitHub. However, it's important to +recognize that our development team is relatively small are does not have +unlimited time to devote to new feature suggestions. If you are interested in +working on the feature you are requesting, indicate so in the issue and the +development team will be happy to discuss it. + +## How to Submit Changes + +All changes to OpenMC happen through pull requests. For a full overview of the +process, see the developer's guide section on [Development +Workflow](http://openmc.readthedocs.io/en/latest/devguide/workflow.html). + +## Code Style + +Before you run off to make changes to the code, please have a look at our [style +guide](http://openmc.readthedocs.io/en/latest/devguide/styleguide.html), which +is used when reviewing new contributions. From 07e481b9a4184a974b00b5197664a05a000ca5d3 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Wed, 18 Jul 2018 12:53:52 -0500 Subject: [PATCH 072/100] Fixed docs by adding module to imports within [data] --- docs/source/conf.py | 1 + docs/source/pythonapi/data.rst | 10 +++++----- openmc/data/__init__.py | 1 + openmc/data/neutron.py | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 03dde6b8bb..e609aabe14 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -55,6 +55,7 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.imgconverter', 'sphinx.ext.numfig', + #'sphinx_numfig', 'notebook_sphinxext'] # Add any paths that contain templates here, relative to this directory. diff --git a/docs/source/pythonapi/data.rst b/docs/source/pythonapi/data.rst index b3668dd1f5..e7af5e273e 100644 --- a/docs/source/pythonapi/data.rst +++ b/docs/source/pythonapi/data.rst @@ -79,11 +79,11 @@ Resonance Data openmc.data.MultiLevelBreitWigner openmc.data.ReichMoore openmc.data.RMatrixLimited - openmc.data.resonance_covariance.ResonanceCovariances - openmc.data.resonance_covariance.ResonanceCovarianceRange - openmc.data.resonance_covariance.SingleLevelBreitWignerCovariance - openmc.data.resonance_covariance.MultiLevelBreitWignerCovariance - openmc.data.resonance_covariance.ReichMooreCovariance + openmc.data.ResonanceCovariances + openmc.data.ResonanceCovarianceRange + openmc.data.SingleLevelBreitWignerCovariance + openmc.data.MultiLevelBreitWignerCovariance + openmc.data.ReichMooreCovariance openmc.data.ParticlePair openmc.data.SpinGroup openmc.data.Unresolved diff --git a/openmc/data/__init__.py b/openmc/data/__init__.py index 7158e9fe3f..44c59628c9 100644 --- a/openmc/data/__init__.py +++ b/openmc/data/__init__.py @@ -27,5 +27,6 @@ from .urr import * from .library import * from .fission_energy import * from .resonance import * +from .resonance_covariance import * from .multipole import * from .grid import * diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 9482c5bb04..363a75e2eb 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -1,6 +1,6 @@ import sys from collections import OrderedDict -from collections.abc import Iterable, Mapping, MutableMappingimport sys +from collections.abc import Iterable, Mapping, MutableMapping from io import StringIO from itertools import chain from math import log10 From 35baf510eaa7ca6dc90df98548a143c6fc0d61d6 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Wed, 18 Jul 2018 15:44:45 -0500 Subject: [PATCH 073/100] changed to sphinx_numfig --- docs/source/conf.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index e609aabe14..eeecba23e4 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -54,8 +54,7 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.viewcode', 'sphinx.ext.imgconverter', - 'sphinx.ext.numfig', - #'sphinx_numfig', + 'sphinx_numfig', 'notebook_sphinxext'] # Add any paths that contain templates here, relative to this directory. From 76475730c7b849657692e28d0008f0c7acb8dcdc Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Wed, 18 Jul 2018 15:49:26 -0500 Subject: [PATCH 074/100] removed parsing of blanks in endf --- openmc/data/endf.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/openmc/data/endf.py b/openmc/data/endf.py index 5bda5c127f..6bf5fb4fb0 100644 --- a/openmc/data/endf.py +++ b/openmc/data/endf.py @@ -68,13 +68,7 @@ def float_endf(s): The number """ - try: - return float(_ENDF_FLOAT_RE.sub(r'\1e\2', s)) - except: - if _ENDF_FLOAT_RE.sub(r'\1e\2', s).isspace(): - return 0 - else: - raise TypeError('Expected float value or blank entry') + return float(_ENDF_FLOAT_RE.sub(r'\1e\2', s)) def int_endf(s): From 15ffa563e045dda7684a91468aee47d4ed0ea104 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Wed, 18 Jul 2018 16:59:41 -0500 Subject: [PATCH 075/100] Style --- openmc/data/endf.py | 29 +++++------ openmc/data/resonance_covariance.py | 76 ++++++++++++++--------------- 2 files changed, 53 insertions(+), 52 deletions(-) diff --git a/openmc/data/endf.py b/openmc/data/endf.py index 6bf5fb4fb0..cc930b442f 100644 --- a/openmc/data/endf.py +++ b/openmc/data/endf.py @@ -269,7 +269,8 @@ def get_tab2_record(file_obj): def get_intg_record(file_obj): """ - Return data from an INTG record in an ENDF-6 file. + Return data from an INTG record in an ENDF-6 file. Used to store the + covariance matrix in a compact format. Parameters ---------- @@ -278,32 +279,32 @@ def get_intg_record(file_obj): Returns ------- - array + numpy.ndarray The correlation matrix described in the INTG record """ # determine how many items are in list and NDIGIT items = get_cont_record(file_obj) - NDIGIT = int(items[2]) - NNN = int(items[3]) # Number of parameters - NM = int(items[4]) # Lines to read - NROW_RULES = {2: 18,3: 12,4: 11,5: 9,6: 8} - NROW = NROW_RULES[NDIGIT] + ndigit = int(items[2]) + npar = int(items[3]) # Number of parameters + nlines = int(items[4]) # Lines to read + NROW_RULES = {2: 18, 3: 12, 4: 11, 5: 9, 6: 8} + nrow = NROW_RULES[ndigit] # read lines and build correlation matrix - corr = np.identity(NNN) - for i in range(NM): + corr = np.identity(npar) + for i in range(nlines): line = file_obj.readline() ii = int_endf(line[:5]) - 1 #-1 to account for 0 indexing jj = int_endf(line[5:10]) - 1 - factor = 10**NDIGIT - for j in range(NROW): + factor = 10**ndigit + for j in range(nrow): if jj+j >= ii: break - element = int_endf(line[11+(NDIGIT+1)*j:11+(NDIGIT+1)*(j+1)]) + element = int_endf(line[11+(ndigit+1)*j:11+(ndigit+1)*(j+1)]) if element > 0: - corr[ii,jj] = (element+0.5)/factor + corr[ii, jj] = (element+0.5)/factor elif element < 0: - corr[ii,jj] = (element-0.5)/factor + corr[ii, jj] = (element-0.5)/factor #Symmetrize the correlation matrix corr = corr + corr.T - np.diag(corr.diagonal()) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index 50fd09add3..dbd4833304 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -109,11 +109,11 @@ class ResonanceCovariances(Resonances): formalism = items[3] # resonance formalism # Throw error for unsupported formalisms - if formalism in [0,7]: + if formalism in [0, 7]: raise NotImplementedError('LRF= ', formalism, 'covariance not supported for this formalism') - if unresolved_flag in (0,1): + if unresolved_flag in (0, 1): # resolved resonance region file2params = resonances.ranges[j].parameters erange = _FORMALISMS[formalism].from_endf(ev, file_obj, @@ -166,7 +166,7 @@ class ResonanceCovarianceRange(object): ---------- parameter_str: str parameter to be discriminated - (i.e. 'energy','captureWidth','fissionWidthA'...) + (i.e. 'energy', 'captureWidth', 'fissionWidthA'...) bounds: np.array [low numerical bound, high numerical bound] @@ -193,9 +193,9 @@ class ResonanceCovarianceRange(object): for index2 in indices: for j in range(mpar): if index2*mpar+j >= index1*mpar+i: - cov_subset_vals.append(cov[index1*mpar+i,index2*mpar+j]) + cov_subset_vals.append(cov[index1*mpar+i, index2*mpar+j]) - cov_subset = np.zeros([sub_cov_dim,sub_cov_dim]) + cov_subset = np.zeros([sub_cov_dim, sub_cov_dim]) tri_indices = np.triu_indices(sub_cov_dim) cov_subset[tri_indices] = cov_subset_vals @@ -218,7 +218,7 @@ class ResonanceCovarianceRange(object): List of samples size [n_samples] """ - if use_subset==False: + if not use_subset: parameters = self.parameters cov = self.covariance else: @@ -227,7 +227,7 @@ class ResonanceCovarianceRange(object): parameters = self.parameters_subset cov = self.cov_subset - nparams,params = parameters.shape + nparams, params = parameters.shape cov = cov + cov.T - np.diag(cov.diagonal()) #symmetrizing covariance matrix covsize = cov.shape[0] formalism = self.formalism @@ -238,7 +238,7 @@ class ResonanceCovarianceRange(object): # Handling MLBW sampling if formalism == 'mlbw' or formalism == 'slbw': if mpar == 3: - param_list = ['energy','neutronWidth','captureWidth'] + param_list = ['energy', 'neutronWidth', 'captureWidth'] mean_array = pd.DataFrame.as_matrix(parameters[param_list]) spin = pd.DataFrame.as_matrix(parameters['J']) l_value = pd.DataFrame.as_matrix(parameters['L']) @@ -246,7 +246,7 @@ class ResonanceCovarianceRange(object): gx = pd.DataFrame.as_matrix(parameters['competitiveWidth']) mean = mean_array.flatten() for i in range(n_samples): - sample = np.random.multivariate_normal(mean,cov) + sample = np.random.multivariate_normal(mean, cov) energy = sample[0::3] gn = sample[1::3] gg = sample[2::3] @@ -261,14 +261,14 @@ class ResonanceCovarianceRange(object): samples.append(sample_params) elif mpar == 4: - param_list = ['energy','neutronWidth','captureWidth','fissionWidth'] + param_list = ['energy', 'neutronWidth', 'captureWidth', 'fissionWidth'] mean_array = pd.DataFrame.as_matrix(parameters[param_list]) spin = pd.DataFrame.as_matrix(parameters['J']) l_value = pd.DataFrame.as_matrix(parameters['L']) gx = pd.DataFrame.as_matrix(parameters['competitiveWidth']) mean = mean_array.flatten() for i in range(n_samples): - sample = np.random.multivariate_normal(mean,cov) + sample = np.random.multivariate_normal(mean, cov) energy = sample[0::4] gn = sample[1::4] gg = sample[2::4] @@ -284,14 +284,14 @@ class ResonanceCovarianceRange(object): samples.append(sample_params) elif mpar == 5: - param_list = ['energy','neutronWidth','captureWidth', + param_list = ['energy', 'neutronWidth', 'captureWidth', 'fissionWidth', 'competitiveWidth'] mean_array = pd.DataFrame.as_matrix(parameters[param_list]) spin = pd.DataFrame.as_matrix(parameters['J']) l_value = pd.DataFrame.as_matrix(parameters['L']) mean = mean_array.flatten() for i in range(n_samples): - sample = np.random.multivariate_normal(mean,cov) + sample = np.random.multivariate_normal(mean, cov) energy = sample[0::5] gn = sample[1::5] gg = sample[2::5] @@ -310,7 +310,7 @@ class ResonanceCovarianceRange(object): # Handling RM Sampling if formalism == 'rm': if mpar == 3: - param_list = ['energy','neutronWidth','captureWidth'] + param_list = ['energy', 'neutronWidth', 'captureWidth'] mean_array = pd.DataFrame.as_matrix(parameters[param_list]) spin = pd.DataFrame.as_matrix(parameters['J']) l_value = pd.DataFrame.as_matrix(parameters['L']) @@ -318,7 +318,7 @@ class ResonanceCovarianceRange(object): gfb = pd.DataFrame.as_matrix(parameters['fissionWidthB']) mean = mean_array.flatten() for i in range(n_samples): - sample = np.random.multivariate_normal(mean,cov) + sample = np.random.multivariate_normal(mean, cov) energy = sample[0::3] gn = sample[1::3] gg = sample[2::3] @@ -327,19 +327,19 @@ class ResonanceCovarianceRange(object): records.append([energy[j], l_value[j], spin[j], gn[j], gg[j], gfa[j], gfb[j]]) columns = ['energy', 'L', 'J', 'neutronWidth', - 'captureWidth', 'fissionWidthA','fissionWidthB'] + 'captureWidth', 'fissionWidthA', 'fissionWidthB'] sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) elif mpar == 5: - param_list = ['energy','neutronWidth','captureWidth', - 'fissionWidthA','fissionWidthB'] + param_list = ['energy', 'neutronWidth', 'captureWidth', + 'fissionWidthA', 'fissionWidthB'] mean_array = pd.DataFrame.as_matrix(parameters[param_list]) spin = pd.DataFrame.as_matrix(parameters['J']) l_value = pd.DataFrame.as_matrix(parameters['L']) mean = mean_array.flatten() for i in range(n_samples): - sample = np.random.multivariate_normal(mean,cov) + sample = np.random.multivariate_normal(mean, cov) energy = sample[0::5] gn = sample[1::5] gg = sample[2::5] @@ -350,7 +350,7 @@ class ResonanceCovarianceRange(object): records.append([energy[j], l_value[j], spin[j], gn[j], gg[j], gfa[j], gfb[j]]) columns = ['energy', 'L', 'J', 'neutronWidth', - 'captureWidth', 'fissionWidthA','fissionWidthB'] + 'captureWidth', 'fissionWidthA', 'fissionWidthB'] sample_params = pd.DataFrame.from_records(records, columns=columns) samples.append(sample_params) @@ -451,7 +451,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): # Other scatter radius parameters items = get_cont_record(file_obj) target_spin = items[0] - LCOMP = items[3] # Flag for compatibility 0,1,2 - 2 is compact form + LCOMP = items[3] # Flag for compatibility 0, 1, 2 - 2 is compact form NLS = items[4] # number of l-values # Build covariance matrix for General Resolved Resonance Formats @@ -485,7 +485,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): #Build the upper-triangular covariance matrix cov_dim = mpar*num_res - cov = np.zeros([cov_dim,cov_dim]) + cov = np.zeros([cov_dim, cov_dim]) indices = np.triu_indices(cov_dim) cov[indices] = cov_values @@ -522,10 +522,10 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): for i in range(num_res): res_unc = values[i*12+6:i*12+12] #Delete 0 values (not provided, no fission width) - # DAJ/DGT always zero, DGF sometimes none zero [1,2,5] + # DAJ/DGT always zero, DGF sometimes none zero [1, 2, 5] res_unc_nonzero = [] for j in range(6): - if j in [1,2,5] and res_unc[j] != 0.0 : + if j in [1, 2, 5] and res_unc[j] != 0.0 : res_unc_nonzero.append(res_unc[j]) elif j in [0,3,4]: res_unc_nonzero.append(res_unc[j]) @@ -546,7 +546,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): #Determine mpar (number of parameters for each resonance in #covariance matrix) - nparams,params = parameters.shape + nparams, params = parameters.shape covsize = cov.shape[0] mpar = int(covsize/nparams) @@ -563,7 +563,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): return mlbw elif LCOMP == 0 : - cov = np.zeros([4,4]) + cov = np.zeros([4, 4]) records = [] cov_index = 0 for i in range(NLS): @@ -584,28 +584,28 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): #Populate the coviariance matrix for this resonance #There are no covariances between resonances in LCOMP=0 - cov[cov_index,cov_index]=cov_values[0] - cov[cov_index+1,cov_index+1:cov_index+2]=cov_values[1:2] - cov[cov_index+1,cov_index+3]=cov_values[4] - cov[cov_index+2,cov_index+2] = cov_values[3] - cov[cov_index+2,cov_index+3] = cov_values[5] - cov[cov_index+3,cov_index+3] = cov_values[6] + cov[cov_index, cov_index]=cov_values[0] + cov[cov_index+1, cov_index+1 : cov_index+2]=cov_values[1:2] + cov[cov_index+1, cov_index+3]=cov_values[4] + cov[cov_index+2, cov_index+2] = cov_values[3] + cov[cov_index+2, cov_index+3] = cov_values[5] + cov[cov_index+3, cov_index+3] = cov_values[6] cov_index += 4 if j < num_res-1: #Pad matrix for additional values - cov = np.pad(cov,((0,4),(0,4)),'constant', - constant_values=0) + cov = np.pad(cov, ((0, 4), (0, 4)), 'constant', + constant_values=0) #Create pandas DataFrame with resonance data, currently #redundant with data.IncidentNeutron.resonance - columns = ['energy', 'J', 'totalWidth','neutronWidth', + columns = ['energy', 'J', 'totalWidth', 'neutronWidth', 'captureWidth', 'fissionWidth'] parameters = pd.DataFrame.from_records(records, columns=columns) #Determine mpar (number of parameters for each resonance in #covariance matrix) - nparams,params = parameters.shape + nparams, params = parameters.shape covsize = cov.shape[0] mpar = int(covsize/nparams) @@ -653,7 +653,7 @@ class SingleLevelBreitWignerCovariance(MultiLevelBreitWignerCovariance): """ def __init__(self, energy_min, energy_max): - super().__init__(energy_min,energy_max) + super().__init__(energy_min, energy_max) self.formalism = 'slbw' class ReichMooreCovariance(ResonanceCovarianceRange): @@ -725,7 +725,7 @@ class ReichMooreCovariance(ResonanceCovarianceRange): # Other scatter radius parameters items = get_cont_record(file_obj) target_spin = items[0] - LCOMP = items[3] # Flag for compatibility 0,1,2 - 2 is compact form + LCOMP = items[3] # Flag for compatibility 0, 1, 2 - 2 is compact form NLS = items[4] # Number of l-values From 1beab30db638159846ef0d66edb36aae00c9f05f Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Thu, 19 Jul 2018 08:54:22 -0500 Subject: [PATCH 076/100] even more style --- openmc/data/neutron.py | 10 +- openmc/data/resonance.py | 11 +- openmc/data/resonance_covariance.py | 186 ++++++++++++++-------------- 3 files changed, 106 insertions(+), 101 deletions(-) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 363a75e2eb..10705985ab 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -298,7 +298,7 @@ class IncidentNeutron(EqualityMixin): @resonance_covariance.setter def resonance_covariance(self, resonance_covariance): - cv.check_type('resonances', resonances, res.ResonanceCovariance) + cv.check_type('resonances', resonances, res_cov.ResonanceCovariance) self._resonacne_covariance = resonance_covariance @summed_reactions.setter @@ -756,7 +756,7 @@ class IncidentNeutron(EqualityMixin): return data @classmethod - def from_endf(cls, ev_or_filename, get_covariance=False): + def from_endf(cls, ev_or_filename, covariance=False): """Generate incident neutron continuous-energy data from an ENDF evaluation Parameters @@ -765,7 +765,7 @@ class IncidentNeutron(EqualityMixin): ENDF evaluation to read from. If given as a string, it is assumed to be the filename for the ENDF file. - get_covariance : bool + covariance : bool Flag to indicate whether or not covariance data from File 32 should be retrieved @@ -800,8 +800,8 @@ class IncidentNeutron(EqualityMixin): if (2, 151) in ev.section: data.resonances = res.Resonances.from_endf(ev) - if (32, 151) in ev.section and get_covariance: - data.res_covariance = res_cov.ResonanceCovariances.from_endf(ev, data.resonances) + if (32, 151) in ev.section and covariance: + data.resonance_covariance = res_cov.ResonanceCovariances.from_endf(ev, data.resonances) # Read each reaction for mf, mt, nc, mod in ev.reaction_list: diff --git a/openmc/data/resonance.py b/openmc/data/resonance.py index 95a145da56..33d64e951f 100644 --- a/openmc/data/resonance.py +++ b/openmc/data/resonance.py @@ -16,6 +16,7 @@ except ImportError: _reconstruct = False import openmc.checkvalue as cv + class Resonances(object): """Resolved and unresolved resonance data @@ -202,7 +203,7 @@ class ResonanceRange(object): return cls(target_spin, energy_min, energy_max, {0: a}, {0: ap}) - def reconstruct(self, energies, use_sample = False, sample_parameters = None): + def reconstruct(self, energies, use_sample=False, sample_parameters=None): """Evaluate cross section at specified energies. Parameters @@ -394,8 +395,8 @@ class MultiLevelBreitWigner(ResonanceRange): return mlbw - def _prepare_resonances(self, use_sample = False, sample_parameters = None): - if use_sample == False: + def _prepare_resonances(self, use_sample=False, sample_parameters=None): + if not use_sample: df = self.parameters.copy() else: df = sample_parameters.copy() @@ -656,8 +657,8 @@ class ReichMoore(ResonanceRange): return rm - def _prepare_resonances(self, use_sample = False, sample_parameters = None): - if use_sample == False: + def _prepare_resonances(self, use_sample=False, sample_parameters=None): + if not use_sample: df = self.parameters.copy() else: df = sample_parameters.copy() diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index dbd4833304..abc6747764 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -5,40 +5,40 @@ import io import numpy as np import pandas as pd -from .endf import get_head_record, get_cont_record, get_tab1_record, get_list_record, get_intg_record +from . import endf import openmc.checkvalue as cv from .resonance import Resonances -def file2contributions(file32params, file2params): + +def _add_file2_contributions(file32params, file2params): """Function for aiding in adding resonance parameters from File 2 that are not always present in File 32. Uses already imported resonance data. - Paramateers - ----------- - file2params: pandas.Dataframe - Resonance parameters from File 2. Ordered by energy. - file32params: pandas.Dataframe + Paramaters + ---------- + file32params : pandas.Dataframe Incomplete set of resonance parameters contained in File 32. + file2params : pandas.Dataframe + Resonance parameters from File 2. Ordered by energy. Returns ------- - parameters: pandas.Dataframe + parameters : pandas.Dataframe Complete set of parameters ordered by L-values and then energy """ - #Use l-values and competitiveWidth from File 2 data - #Re-sort File 2 by energy to match File 32 - file2params=file2params.sort_values(by=['energy']) - file2params=file2params.reset_index(drop=True) - #Sort File 32 parameters by energy as well (maintaining index) - file32params_sort = file32params.sort_values(by=['energy']) - #Add in values (.values converts to array first to ignore index) - file32params_sort['L'] = file2params['L'].values + # Use l-values and competitiveWidth from File 2 data + # Re-sort File 2 by energy to match File 32 + file2params = file2params.sort_values(by=['energy']) + file2params.reset_index(drop=True, inplace=True) + # Sort File 32 parameters by energy as well (maintaining index) + file32params.sort_values(by=['energy'], inplace=True) + # Add in values (.values converts to array first to ignore index) + file32params['L'] = file2params['L'].values if 'competitiveWidth' in file2params.columns: - file32params_sort['competitiveWidth'] = file2params['competitiveWidth'].values - #Resort to File 32 order (by L then by E) for use with covariance - parameters = file32params_sort.sort_index() - - return parameters + file32params['competitiveWidth'] = file2params['competitiveWidth'].values + # Resort to File 32 order (by L then by E) for use with covariance + file32params.sort_index(inplace=True) + return file32params class ResonanceCovariances(Resonances): @@ -81,6 +81,7 @@ class ResonanceCovariances(Resonances): ev : openmc.data.endf.Evaluation ENDF evaluation resonances : openmc.data.Resonance object + Resonanance object generated from the same evaluation Returns ------- @@ -91,18 +92,18 @@ class ResonanceCovariances(Resonances): file_obj = io.StringIO(ev.section[32, 151]) # Determine whether discrete or continuous representation - items = get_head_record(file_obj) + items = endf.get_head_record(file_obj) n_isotope = items[4] # Number of isotopes ranges = [] for iso in range(n_isotope): - items = get_cont_record(file_obj) + items = endf.get_cont_record(file_obj) abundance = items[1] fission_widths = (items[3] == 1) # Flag for fission widths n_ranges = items[4] # number of resonance energy ranges for j in range(n_ranges): - items = get_cont_record(file_obj) + items = endf.get_cont_record(file_obj) unresolved_flag = items[2] # 0: only scattering radius given # 1: resolved parameters given # 2: unresolved parameters given @@ -127,7 +128,8 @@ class ResonanceCovariances(Resonances): return cls(ranges) -class ResonanceCovarianceRange(object): + +class ResonanceCovarianceRange: """Resonace covariance range. Base class for different formalisms. Parameters @@ -143,7 +145,7 @@ class ResonanceCovarianceRange(object): Minimum energy of the resolved resonance range in eV energy_max : float Maximum energy of the resolved resonance range in eV - parameters: pandas.DataFrame + parameters : pandas.DataFrame Resonance parameters covariance : numpy.array The covariance matrix contained within the ENDF evaluation @@ -164,27 +166,27 @@ class ResonanceCovarianceRange(object): Parameters ---------- - parameter_str: str + parameter_str : str parameter to be discriminated (i.e. 'energy', 'captureWidth', 'fissionWidthA'...) - bounds: np.array + bounds : np.array [low numerical bound, high numerical bound] Returns ------- parameters_subset : pandas.Dataframe Subset of parameters (maintains indexing of original) - cov_subset: np.array + cov_subset : np.array Subset of covariance matrix (upper triangular) """ parameters = self.parameters cov = self.covariance mpar = self.mpar - mask1 = parameters[parameter_str]>=bounds[0] - mask2 = parameters[parameter_str]<=bounds[1] + mask1 = parameters[parameter_str] >= bounds[0] + mask2 = parameters[parameter_str] <= bounds[1] mask = mask1 & mask2 - parameters_subset=parameters[mask] + parameters_subset = parameters[mask] indices = parameters_subset.index.values sub_cov_dim = len(indices)*mpar cov_subset_vals = [] @@ -228,7 +230,7 @@ class ResonanceCovarianceRange(object): cov = self.cov_subset nparams, params = parameters.shape - cov = cov + cov.T - np.diag(cov.diagonal()) #symmetrizing covariance matrix + cov = cov + cov.T - np.diag(cov.diagonal()) # symmetrizing covariance matrix covsize = cov.shape[0] formalism = self.formalism mpar = self.mpar @@ -384,6 +386,7 @@ class ResonanceCovarianceRange(object): sample_parameters = sample_parameters) return xs_array + class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): """Multi-level Breit-Wigner resolved resonance formalism covariance data. Parameters @@ -399,7 +402,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): Minimum energy of the resolved resonance range in eV energy_max : float Maximum energy of the resolved resonance range in eV - parameters: pandas.DataFrame + parameters : pandas.DataFrame Resonance parameters covariance : numpy.array The covariance matrix contained within the ENDF evaluation @@ -446,26 +449,26 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): energy_min, energy_max = items[0:2] nro, naps = items[4:6] if nro != 0: - params, ape = get_tab1_record(file_obj) + params, ape = endf.get_tab1_record(file_obj) # Other scatter radius parameters - items = get_cont_record(file_obj) + items = endf.get_cont_record(file_obj) target_spin = items[0] LCOMP = items[3] # Flag for compatibility 0, 1, 2 - 2 is compact form NLS = items[4] # number of l-values # Build covariance matrix for General Resolved Resonance Formats if LCOMP == 1: - items = get_cont_record(file_obj) - num_short_range = items[4] #Number of short range type resonance - #covariances - num_long_range = items[5] #Number of long range type resonance - #covariances + items = endf.get_cont_record(file_obj) + num_short_range = items[4] # Number of short range type resonance + # covariances + num_long_range = items[5] # Number of long range type resonance + # covariances # Read resonance widths, J values, etc records = [] for i in range(num_short_range): - items, values = get_list_record(file_obj) + items, values = endf.get_list_record(file_obj) mpar = items[2] num_res = items[5] num_par_vals = num_res*6 @@ -483,20 +486,20 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): records.append([energy[i], spin[i], gt[i], gn[i], gg[i], gf[i]]) - #Build the upper-triangular covariance matrix + # Build the upper-triangular covariance matrix cov_dim = mpar*num_res cov = np.zeros([cov_dim, cov_dim]) indices = np.triu_indices(cov_dim) cov[indices] = cov_values - #Create pandas DataFrame with resonance data, currently - #redundant with data.IncidentNeutron.resonance + # Create pandas DataFrame with resonance data, currently + # redundant with data.IncidentNeutron.resonance columns = ['energy', 'J', 'totalWidth', 'neutronWidth', 'captureWidth', 'fissionWidth'] parameters = pd.DataFrame.from_records(records, columns=columns) - #Add parameters from File 2 - parameters = file2contributions(parameters, file2params) + # Add parameters from File 2 + parameters = _add_file2_contributions(parameters, file2params) # Create instance of class mlbw = cls(energy_min, energy_max) @@ -507,9 +510,9 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): return mlbw - elif LCOMP == 2: #Compact format - Resonances and individual - #uncertainties followed by compact correlations - items, values = get_list_record(file_obj) + elif LCOMP == 2: # Compact format - Resonances and individual + # uncertainties followed by compact correlations + items, values = endf.get_list_record(file_obj) mean = items num_res = items[5] energy = values[0::12] @@ -521,7 +524,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): par_unc = [] for i in range(num_res): res_unc = values[i*12+6:i*12+12] - #Delete 0 values (not provided, no fission width) + # Delete 0 values (not provided, no fission width) # DAJ/DGT always zero, DGF sometimes none zero [1, 2, 5] res_unc_nonzero = [] for j in range(6): @@ -536,7 +539,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): records.append([energy[i], spin[i], gt[i], gn[i], gg[i], gf[i]]) - corr = get_intg_record(file_obj) + corr = endf.get_intg_record(file_obj) cov = np.diag(par_unc).dot(corr).dot(np.diag(par_unc)) # Create pandas DataFrame with resonacne data @@ -544,14 +547,14 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): 'captureWidth', 'fissionWidth'] parameters = pd.DataFrame.from_records(records, columns=columns) - #Determine mpar (number of parameters for each resonance in - #covariance matrix) + # Determine mpar (number of parameters for each resonance in + # covariance matrix) nparams, params = parameters.shape covsize = cov.shape[0] mpar = int(covsize/nparams) - #Add parameters from File 2 - parameters = file2contributions(parameters, file2params) + # Add parameters from File 2 + parameters = _add_file2_contributions(parameters, file2params) # Create instance of MultiLevelBreitWignerCovariance mlbw = cls(energy_min, energy_max) @@ -567,7 +570,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): records = [] cov_index = 0 for i in range(NLS): - items, values = get_list_record(file_obj) + items, values = endf.get_list_record(file_obj) num_res = items[5] for j in range(num_res): one_res = values[18*j:18*(j+1)] @@ -582,35 +585,35 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): gf = res_values[5] records.append([energy, spin, gt, gn, gg, gf]) - #Populate the coviariance matrix for this resonance - #There are no covariances between resonances in LCOMP=0 - cov[cov_index, cov_index]=cov_values[0] - cov[cov_index+1, cov_index+1 : cov_index+2]=cov_values[1:2] - cov[cov_index+1, cov_index+3]=cov_values[4] + # Populate the coviariance matrix for this resonance + # There are no covariances between resonances in LCOMP=0 + cov[cov_index, cov_index] = cov_values[0] + cov[cov_index+1, cov_index+1 : cov_index+2] = cov_values[1:2] + cov[cov_index+1, cov_index+3] = cov_values[4] cov[cov_index+2, cov_index+2] = cov_values[3] cov[cov_index+2, cov_index+3] = cov_values[5] cov[cov_index+3, cov_index+3] = cov_values[6] cov_index += 4 - if j < num_res-1: #Pad matrix for additional values + if j < num_res-1: # Pad matrix for additional values cov = np.pad(cov, ((0, 4), (0, 4)), 'constant', constant_values=0) - #Create pandas DataFrame with resonance data, currently - #redundant with data.IncidentNeutron.resonance + # Create pandas DataFrame with resonance data, currently + # redundant with data.IncidentNeutron.resonance columns = ['energy', 'J', 'totalWidth', 'neutronWidth', 'captureWidth', 'fissionWidth'] parameters = pd.DataFrame.from_records(records, columns=columns) - #Determine mpar (number of parameters for each resonance in - #covariance matrix) + # Determine mpar (number of parameters for each resonance in + # covariance matrix) nparams, params = parameters.shape covsize = cov.shape[0] mpar = int(covsize/nparams) - #Add parameters from File 2 - parameters = file2contributions(parameters, file2params) + # Add parameters from File 2 + parameters = _add_file2_contributions(parameters, file2params) # Create instance of class mlbw = cls(energy_min, energy_max) @@ -640,7 +643,7 @@ class SingleLevelBreitWignerCovariance(MultiLevelBreitWignerCovariance): Minimum energy of the resolved resonance range in eV energy_max : float Maximum energy of the resolved resonance range in eV - parameters: pandas.DataFrame + parameters : pandas.DataFrame Resonance parameters covariance : numpy.array The covariance matrix contained within the ENDF evaluation @@ -656,6 +659,7 @@ class SingleLevelBreitWignerCovariance(MultiLevelBreitWignerCovariance): super().__init__(energy_min, energy_max) self.formalism = 'slbw' + class ReichMooreCovariance(ResonanceCovarianceRange): """Reich-Moore resolved resonance formalism covariance data. @@ -675,7 +679,7 @@ class ReichMooreCovariance(ResonanceCovarianceRange): Minimum energy of the resolved resonance range in eV energy_max : float Maximum energy of the resolved resonance range in eV - parameters: pandas.DataFrame + parameters : pandas.DataFrame Resonance parameters covariance : numpy.array The covariance matrix contained within the ENDF evaluation @@ -720,10 +724,10 @@ class ReichMooreCovariance(ResonanceCovarianceRange): energy_min, energy_max = items[0:2] nro, naps = items[4:6] if nro != 0: - params, ape = get_tab1_record(file_obj) + params, ape = endf.get_tab1_record(file_obj) # Other scatter radius parameters - items = get_cont_record(file_obj) + items = endf.get_cont_record(file_obj) target_spin = items[0] LCOMP = items[3] # Flag for compatibility 0, 1, 2 - 2 is compact form NLS = items[4] # Number of l-values @@ -731,17 +735,17 @@ class ReichMooreCovariance(ResonanceCovarianceRange): # Build covariance matrix for General Resolved Resonance Formats if LCOMP == 1: - items = get_cont_record(file_obj) - num_short_range = items[4] #Number of short range type resonance - #covariances - num_long_range = items[5] #Number of long range type resonance - #covariances + items = endf.get_cont_record(file_obj) + num_short_range = items[4] # Number of short range type resonance + # covariances + num_long_range = items[5] # Number of long range type resonance + # covariances # Read resonance widths, J values, etc channel_radius = {} scattering_radius = {} records = [] for i in range(num_short_range): - items, values = get_list_record(file_obj) + items, values = endf.get_list_record(file_obj) mpar = items[2] num_res = items[5] num_par_vals = num_res*6 @@ -759,7 +763,7 @@ class ReichMooreCovariance(ResonanceCovarianceRange): records.append([energy[i], spin[i], gn[i], gg[i], gfa[i], gfb[i]]) - #Build the upper-triangular covariance matrix + # Build the upper-triangular covariance matrix cov_dim = mpar*num_res cov = np.zeros([cov_dim,cov_dim]) indices = np.triu_indices(cov_dim) @@ -770,8 +774,8 @@ class ReichMooreCovariance(ResonanceCovarianceRange): 'fissionWidthA', 'fissionWidthB'] parameters = pd.DataFrame.from_records(records, columns=columns) - #Add parameters from File 2 - parameters = file2contributions(parameters, file2params) + # Add parameters from File 2 + parameters = _add_file2_contributions(parameters, file2params) # Create instance of ReichMooreCovariance rmc = cls(energy_min, energy_max) @@ -782,9 +786,9 @@ class ReichMooreCovariance(ResonanceCovarianceRange): return rmc - elif LCOMP == 2: #Compact format - Resonances and individual - #uncertainties followed by compact correlations - items, values = get_list_record(file_obj) + elif LCOMP == 2: # Compact format - Resonances and individual + # uncertainties followed by compact correlations + items, values = endf.get_list_record(file_obj) num_res = items[5] energy = values[0::12] spin = values[1::12] @@ -795,7 +799,7 @@ class ReichMooreCovariance(ResonanceCovarianceRange): par_unc = [] for i in range(num_res): res_unc = values[i*12+6:i*12+12] - #Delete 0 values (not provided in evaluation) + # Delete 0 values (not provided in evaluation) res_unc = [x for x in res_unc if x != 0.0] par_unc.extend(res_unc) @@ -804,7 +808,7 @@ class ReichMooreCovariance(ResonanceCovarianceRange): records.append([energy[i], spin[i], gn[i], gg[i], gfa[i], gfb[i]]) - corr = get_intg_record(file_obj) + corr = endf.get_intg_record(file_obj) cov = np.diag(par_unc).dot(corr).dot(np.diag(par_unc)) # Create pandas DataFrame with resonacne data @@ -812,14 +816,14 @@ class ReichMooreCovariance(ResonanceCovarianceRange): 'fissionWidthA', 'fissionWidthB'] parameters = pd.DataFrame.from_records(records, columns=columns) - #Determine mpar (number of parameters for each resonance in - #covariance matrix) + # Determine mpar (number of parameters for each resonance in + # covariance matrix) nparams,params = parameters.shape covsize = cov.shape[0] mpar = int(covsize/nparams) - #Add parameters from File 2 - parameters = file2contributions(parameters, file2params) + # Add parameters from File 2 + parameters = _add_file2_contributions(parameters, file2params) # Create instance of ReichMooreCovariance rmc = cls(energy_min, energy_max) From c22b36e0c8049dd7823a4d976c40fb45c926859e Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Thu, 19 Jul 2018 13:10:37 -0500 Subject: [PATCH 077/100] Style and changed sampling to produce ResonanceRange objects --- .../nuclear-data-resonance-covariance.ipynb | 138 ++++++++++-------- openmc/data/neutron.py | 7 +- openmc/data/resonance_covariance.py | 74 ++++------ tests/unit_tests/test_data_neutron.py | 5 +- 4 files changed, 113 insertions(+), 111 deletions(-) diff --git a/examples/jupyter/nuclear-data-resonance-covariance.ipynb b/examples/jupyter/nuclear-data-resonance-covariance.ipynb index c673dfea56..74f774f410 100644 --- a/examples/jupyter/nuclear-data-resonance-covariance.ipynb +++ b/examples/jupyter/nuclear-data-resonance-covariance.ipynb @@ -53,7 +53,7 @@ "filename, headers = urllib.request.urlretrieve(url, 'gd157.endf')\n", "\n", "# Load into memory\n", - "gd157_endf = openmc.data.IncidentNeutron.from_endf(filename, get_covariance = True)\n", + "gd157_endf = openmc.data.IncidentNeutron.from_endf(filename, covariance = True)\n", "gd157_endf" ] }, @@ -83,7 +83,7 @@ } ], "source": [ - "first_five = gd157_endf.res_covariance.ranges[0].parameters[:5]\n", + "first_five = gd157_endf.resonance_covariance.ranges[0].parameters[:5]\n", "print(first_five)" ] }, @@ -100,7 +100,7 @@ "metadata": {}, "outputs": [], "source": [ - "covariance = gd157_endf.res_covariance.ranges[0].covariance" + "covariance = gd157_endf.resonance_covariance.ranges[0].covariance" ] }, { @@ -118,7 +118,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 5, @@ -129,7 +129,7 @@ "data": { "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -169,8 +169,8 @@ "source": [ "lower_bound = 2; #inclusive\n", "upper_bound = 2; #inclusive\n", - "gd157_endf.res_covariance.ranges[0].res_subset('J',[lower_bound,upper_bound])\n", - "subset_first_five = gd157_endf.res_covariance.ranges[0].parameters_subset[:5]\n", + "gd157_endf.resonance_covariance.ranges[0].res_subset('J',[lower_bound,upper_bound])\n", + "subset_first_five = gd157_endf.resonance_covariance.ranges[0].parameters_subset[:5]\n", "print(subset_first_five)" ] }, @@ -204,7 +204,7 @@ } ], "source": [ - "cov_subset = gd157_endf.res_covariance.ranges[0].cov_subset\n", + "cov_subset = gd157_endf.resonance_covariance.ranges[0].cov_subset\n", "print(cov_subset[:5,:5])" ] }, @@ -212,13 +212,44 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The covariance module also has the ability to sample a new set of parameters using the covariance matrix. Currently the sampling uses np.multivariate_normal(). Because parameters are assumed to have a multivariate normal distribution this method doesn't not currently guarantee that sampled parameters will be positive. " + "The covariance module also has the ability to sample a new set of parameters using the covariance matrix. Currently the sampling uses np.multivariate_normal(). Because parameters are assumed to have a multivariate normal distribution this method doesn't not currently guarantee that sampled parameters will be positive." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "openmc.data.resonance.ReichMoore" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rm_resonance = gd157_endf.resonances.ranges[0]\n", + "n_samples = 5\n", + "gd157_endf.resonance_covariance.ranges[0].sample_resonance_parameters(n_samples, rm_resonance)\n", + "samples = gd157_endf.resonance_covariance.ranges[0].samples\n", + "type(samples[0])\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The sampling routine requires the incorpotation of the `openmc.data.ResonanceRange` for the same resonance range object. This allows each sample itself to be its own `openmc.data.ResonanceRange` with a new set of parameters. Looking at some of the sampled parameters below:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -226,27 +257,24 @@ "text": [ "Sample 1\n", " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.035303 0 2.0 0.000482 0.100681 0.0 0.0\n", - "1 2.831054 0 2.0 0.000357 0.094362 0.0 0.0\n", - "2 16.244335 0 1.0 0.000400 0.049005 0.0 0.0\n", - "3 16.772396 0 2.0 0.012005 0.085736 0.0 0.0\n", - "4 20.560952 0 2.0 0.010648 0.098282 0.0 0.0\n", + "0 0.032307 0 2.0 0.000477 0.105887 0.0 0.0\n", + "1 2.827218 0 2.0 0.000349 0.094165 0.0 0.0\n", + "2 16.298283 0 1.0 0.000519 0.183407 0.0 0.0\n", + "3 16.771312 0 2.0 0.012540 0.078625 0.0 0.0\n", + "4 20.558190 0 2.0 0.011813 0.085244 0.0 0.0\n", "Sample 2\n", " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.032481 0 2.0 0.000477 0.105662 0.0 0.0\n", - "1 2.825417 0 2.0 0.000338 0.099793 0.0 0.0\n", - "2 16.248565 0 1.0 0.000465 0.118105 0.0 0.0\n", - "3 16.767121 0 2.0 0.012827 0.072236 0.0 0.0\n", - "4 20.559938 0 2.0 0.011424 0.085309 0.0 0.0\n" + "0 0.033027 0 2.0 0.000476 0.104104 0.0 0.0\n", + "1 2.825226 0 2.0 0.000344 0.098390 0.0 0.0\n", + "2 16.245609 0 1.0 0.000353 0.095063 0.0 0.0\n", + "3 16.764396 0 2.0 0.013475 0.075175 0.0 0.0\n", + "4 20.560505 0 2.0 0.011994 0.081186 0.0 0.0\n" ] } ], "source": [ - "n_samples = 5\n", - "gd157_endf.res_covariance.ranges[0].sample_resonance_parameters(n_samples)\n", - "samples = gd157_endf.res_covariance.ranges[0].samples\n", - "first_five_sample_1 = samples[0][:5]\n", - "first_five_sample_2 = samples[1][:5]\n", + "first_five_sample_1 = samples[0].parameters[:5]\n", + "first_five_sample_2 = samples[1].parameters[:5]\n", "print('Sample 1')\n", "print(first_five_sample_1)\n", "print('Sample 2')\n", @@ -257,35 +285,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We can reconstruct the cross section from the sampled parameters using the reconstruct method. This method also required the equivalent openmc.data.IncidentNeutron.resonance.ResonanceRange object. " - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[,\n", - " ]" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "gd157_endf.resonances.ranges" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Reconstructing in the ReichMoore region using our previously generated samples. " + "We can reconstruct the cross section from the sampled parameters using the reconstruct method of `openmc.data.ResonanceRange`. For more on reconstruction see the Nuclear Data example notebook. " ] }, { @@ -296,18 +296,39 @@ { "data": { "text/plain": [ - "Text(0,0.5,'Cross section (b)')" + "[,\n", + " ]" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" + } + ], + "source": [ + "gd157_endf.resonances.ranges" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0,0.5,'Cross section (b)')" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" }, { "data": { - "image/png": "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\nJk0qPG8AAAAASUVORK5CYII=\n", + "image/png": "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\nYBtKl8mxDQAAAABJRU5ErkJggg==\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -315,12 +336,11 @@ } ], "source": [ - "rm_resonance = gd157_endf.resonances.ranges[0]\n", "energy_range = [rm_resonance.energy_min, rm_resonance.energy_max]\n", "energies = np.logspace(np.log10(energy_range[0]),\n", " np.log10(energy_range[1]), 10000)\n", - "for sample in range(n_samples):\n", - " xs = gd157_endf.res_covariance.ranges[0].reconstruct(energies, rm_resonance, sample)\n", + "for sample in gd157_endf.resonance_covariance.ranges[0].samples:\n", + " xs = sample.reconstruct(energies)\n", " elastic_xs = xs[2]\n", " plt.loglog(energies, elastic_xs)\n", "plt.xlabel('Energy (eV)')\n", diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 10705985ab..3b98e00a21 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -233,7 +233,7 @@ class IncidentNeutron(EqualityMixin): @property def resonance_covariance(self): - return self._resoncance_covariance + return self._resonance_covariance @property def summed_reactions(self): @@ -298,8 +298,9 @@ class IncidentNeutron(EqualityMixin): @resonance_covariance.setter def resonance_covariance(self, resonance_covariance): - cv.check_type('resonances', resonances, res_cov.ResonanceCovariance) - self._resonacne_covariance = resonance_covariance + cv.check_type('resonance covariance', resonance_covariance, + res_cov.ResonanceCovariances) + self._resonance_covariance = resonance_covariance @summed_reactions.setter def summed_reactions(self, summed_reactions): diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index abc6747764..714d87234d 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -1,6 +1,7 @@ from collections import defaultdict, MutableSequence, Iterable import warnings import io +import copy import numpy as np import pandas as pd @@ -55,13 +56,6 @@ class ResonanceCovariances(Resonances): Distinct energy ranges for resonance data """ - def __init__(self, ranges): - self.ranges = ranges - - def __iter__(self): - for r in self.ranges: - yield r - @property def ranges(self): return self._ranges @@ -204,13 +198,16 @@ class ResonanceCovarianceRange: self.parameters_subset = parameters_subset self.cov_subset = cov_subset - def sample_resonance_parameters(self, n_samples, use_subset=False): - """Return a IncidentNeutron object with n_samples of xs + def sample_resonance_parameters(self, n_samples, resonances, use_subset=False): + """Return a list size 'n_samples' of openmc.data.ResonanceRange objects. + Each with an indepentenly sampled set of parameters Parameters ---------- n_samples : int The number of samples to produce + resonances : openmc.data.ResonanceRange object + Corresponding resonance range with File 2 data. use_subset : bool, optional Flag on whether to sample from an already produced subset @@ -236,7 +233,6 @@ class ResonanceCovarianceRange: mpar = self.mpar samples = [] - # Handling MLBW sampling if formalism == 'mlbw' or formalism == 'slbw': if mpar == 3: @@ -258,9 +254,11 @@ class ResonanceCovarianceRange: records.append([energy[j], l_value[j], spin[j], gt[j], gn[j], gg[j], gf[j], gx[j]]) columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', - 'captureWidth', 'fissionWidth', 'competitiveWidth'] + 'captureWidth', 'fissionWidth', 'competitiveWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) - samples.append(sample_params) + res_range = copy.copy(resonances) + res_range.parameters = sample_params + samples.append(res_range) elif mpar == 4: param_list = ['energy', 'neutronWidth', 'captureWidth', 'fissionWidth'] @@ -281,9 +279,11 @@ class ResonanceCovarianceRange: records.append([energy[j], l_value[j], spin[j], gt[j], gn[j], gg[j], gf[j], gx[j]]) columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', - 'captureWidth', 'fissionWidth', 'competitiveWidth'] + 'captureWidth', 'fissionWidth', 'competitiveWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) - samples.append(sample_params) + res_range = copy.copy(resonances) + res_range.parameters = sample_params + samples.append(res_range) elif mpar == 5: param_list = ['energy', 'neutronWidth', 'captureWidth', @@ -305,9 +305,11 @@ class ResonanceCovarianceRange: records.append([energy[j], l_value[j], spin[j], gt[j], gn[j], gg[j], gf[j], gx[j]]) columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', - 'captureWidth', 'fissionWidth', 'competitveWidth'] + 'captureWidth', 'fissionWidth', 'competitveWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) - samples.append(sample_params) + res_range = copy.copy(resonances) + res_range.parameters = sample_params + samples.append(res_range) # Handling RM Sampling if formalism == 'rm': @@ -331,7 +333,9 @@ class ResonanceCovarianceRange: columns = ['energy', 'L', 'J', 'neutronWidth', 'captureWidth', 'fissionWidthA', 'fissionWidthB'] sample_params = pd.DataFrame.from_records(records, columns=columns) - samples.append(sample_params) + res_range = copy.copy(resonances) + res_range.parameters = sample_params + samples.append(res_range) elif mpar == 5: param_list = ['energy', 'neutronWidth', 'captureWidth', @@ -354,38 +358,12 @@ class ResonanceCovarianceRange: columns = ['energy', 'L', 'J', 'neutronWidth', 'captureWidth', 'fissionWidthA', 'fissionWidthB'] sample_params = pd.DataFrame.from_records(records, columns=columns) - samples.append(sample_params) + res_range = copy.copy(resonances) + res_range.parameters = sample_params + samples.append(res_range) self.samples = samples - def reconstruct(self, energies, resonances, sampleN): - """Evaluate the cross section at specified energies for an already - sampled set of resonance parameters. - - Parameters - ---------- - energies : float or Iterable of float - Energies at which the cross section should be evaluated - resonances : openmc.data.Resonance object - Corresponding resonance range with File 2 data. Used for - reconstruction method - sampleN : int - Index of sample of resonance parameters to be used - - Returns - ------- - 3-tuple of float or numpy.ndarray - Elastic, capture, and fission cross sections at the specified - energies - - """ - if self.samples[sampleN] is None: - raise ValueError("Sample of resonance parameters has not been set.") - sample_parameters = self.samples[sampleN] - xs_array = resonances.reconstruct(energies, use_sample = True, - sample_parameters = sample_parameters) - return xs_array - class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): """Multi-level Breit-Wigner resolved resonance formalism covariance data. @@ -436,7 +414,9 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): items : list Items from the CONT record at the start of the resonance range subsection - resonances : openmc.data.IncidentNeutron.Resonance object + file2params : openmc.data.ResonanceRange object + Corresponding resonance range with File 2 data. Used for + reconstruction method Returns ------- diff --git a/tests/unit_tests/test_data_neutron.py b/tests/unit_tests/test_data_neutron.py index 90d2799455..54d815eb66 100644 --- a/tests/unit_tests/test_data_neutron.py +++ b/tests/unit_tests/test_data_neutron.py @@ -39,7 +39,7 @@ def sm150(): def gd154(): """Gd154 ENDF data (contains Reich Moore resonance range)""" filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-064_Gd_154.endf') - return openmc.data.IncidentNeutron.from_endf(filename, get_covariance = True) + return openmc.data.IncidentNeutron.from_endf(filename, covariance = True) @pytest.fixture(scope='module') @@ -96,11 +96,12 @@ def am244(): endf_file = os.path.join(_ENDF_DATA, 'neutrons', 'n-095_Am_244.endf') return openmc.data.IncidentNeutron.from_njoy(endf_file) + @pytest.fixture(scope='module') def ti50(): """Ti50 ENDF data (contains Multi-level Breit-Wigner resonance range)""" filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-022_Ti_050.endf') - return openmc.data.IncidentNeutron.from_endf(filename, get_covariance=True) + return openmc.data.IncidentNeutron.from_endf(filename, covariance=True) def test_attributes(pu239): From e48521184b2bc82a1c32f39668d7fd5fdafa44a6 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Thu, 19 Jul 2018 13:22:27 -0500 Subject: [PATCH 078/100] More reconstruction fixes --- .../nuclear-data-resonance-covariance.ipynb | 32 +++++++++---------- openmc/data/resonance.py | 20 ++++-------- openmc/data/resonance_covariance.py | 15 +++++++++ 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/examples/jupyter/nuclear-data-resonance-covariance.ipynb b/examples/jupyter/nuclear-data-resonance-covariance.ipynb index 74f774f410..bc83d48fc3 100644 --- a/examples/jupyter/nuclear-data-resonance-covariance.ipynb +++ b/examples/jupyter/nuclear-data-resonance-covariance.ipynb @@ -118,7 +118,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 5, @@ -129,7 +129,7 @@ "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAUkAAAD8CAYAAAD6+lbaAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4wLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvpW3flQAAIABJREFUeJzt3X2wXHWd5/H3JzeEJ+UxghCySxyi\nu4GaVcxEVmstxwgEnTVulc6EXceU4mTXAccZZ0th3RUXlyqYcWW1RLYiZATHIaQYXVJb0RhAtKZK\nIJFhxIAZIihciUAMMC5IHu797h/n18m5ndN9Tz/d233O55U6le7T53Sfcx++9/f4/SkiMDOzYnNm\n+wLMzIaZg6SZWRsOkmZmbThImpm14SBpZtaGg6SZWRsDC5KSVkjaIWmnpMsH9TlmZoOkQYyTlDQG\n/CNwPjAObAUujoiH+/5hZmYDNKiS5DJgZ0Q8FhH7gPXAygF9lpnZwMwd0PsuAJ7MPR8H3tTq4LFj\njo0jTjhpQJdiZgB7d43vjohXdXv+hb97bPxqz0SpY3/4o72bI2JFt581TAYVJFWwb0q9XtIaYA3A\n3ONP5Mw/+viALsXMAHZc9fGf93L+r/ZMcP/mf1bq2LHTHp3fy2cNk0FVt8eBhbnnZwBP5Q+IiLUR\nsTQilo4dc2y2T9k2k/r5me3ep/m1ft9n0fu1+ozGPQ/i693J+83099p6E8BkyX9VMqgguRVYLGmR\npHnAKmDjgD7LzGZAEOyPiVJbGdONgJF0pKTb0uv3SToz99oVaf8OSRfm9v+ZpO2SfizpVklH9Xrf\nAwmSEXEAuAzYDDwCbIiI7dOdp8i2mSxhND6zX+9V9rV+fWa792v1GY177ue9T/eZvR5rw6FfJck0\nAuZ64CJgCXCxpCVNh10CPBcRZwHXAdemc5eQFbzOBlYAX5Y0JmkB8CfA0og4BxhLx/VkUG2SRMQm\nYFM35/qXx2z4BMFE/4YMHhwBAyCpMQImP0xwJfCZ9Ph24EuSlPavj4i9wOOSdqb3e4Isph0taT9w\nDE3NfN0Y6hk3brMyGy6TRKmthKIRMAtaHZNqpy8AJ7c6NyJ+AXyOLFjuAl6IiO90cZtTDHWQVMDE\nkXGwg2HiqGjbGWFmgxPABFFqA+ZL2pbb1jS93bQjYNocU7hf0olkpcxFwOnAsZLe39FNFhhYdbtf\nxvYe+nrM2au27WxmNlglS4kAuyNiaZvXpx0BkztmXNJc4HhgT5tz3wE8HhHPAkj6BvBm4K/LXnSR\noS5JmtnwCGB/RKmthDIjYDYCq9Pj9wJ3RzaPeiOwKvV+LwIWA/eTVbPPk3RMartcTtZx3JOhL0nm\nvbxwP0c9eQQAanSgpYJmo7pdVKIMTd3f/Nz8NbHpxaGqdO/vFXFAUmMEzBiwLiK2S7oK2BYRG4Gb\ngK+ljpk9pJ7qdNwGsk6eA8ClETEB3CfpduCBtP/vgbW9XutIBcmjnzji0C9zU6vEbA6/qQJ/TWxa\nARN9/DkpGgETEZ/OPX4ZeF+Lc68Gri7YfyVwZf+ucsSCJPiX2Wy2ZDNu6mfkgmRDu+p14/XGa+2q\nktO9T1W5em2dExOFHcvVNrJB0sxmVtZx4yA5MppLic0lwnwpqZP2yrqo631b97Jxkg6SI6coKJrZ\nYEy6JDm66tq22C23SVqnXJIccQqIORw+sckKOUBapwIxUcP5J5UJkpAbYG5mA+HqtplZC4HYF2Oz\nfRkzruuys6SFkr4r6ZGUCfhjaf9JkrZIejT9f2L/Lre8dhmDzFmTrHPZYPI5pbYq6eVuDgB/HhH/\nEjgPuDRlDL4cuCsiFgN3peczbuxlR4F23CZp3ZhIA8qn26qk6+p2ROwiS2xJRPxa0iNkyTBXAm9L\nh90M3AN8sqer7JIDgVn/RIiJqFYpsYy+tEmmBXreANwHnJoCKBGxS9Ip/fiMXsQYqNzaRJUy3XRM\n/xGxTk1WrJRYRs9BUtIrgL8F/jQi/ilL41bqvCnrbg+SJuo5jtIzjayfso6b+vX19lR2lnQEWYD8\nekR8I+1+WtJp6fXTgGeKzi1ad9vMhpc7bjqUMv/eBDwSEZ/PvZTPJrwauKP7y+ufQSyfalY3E6FS\nW5X0UnZ+C/CHwEOSHkz7/gtwDbBB0iVk6dQLk2bOJrfH+WtgnfOMmw5FxN9RvGoZZGtLDK1G1qCi\n7EF1Ubf7tf6YdO92fTh7kFlnsgQXDpK10/jDOOrzvouqz2UyskN//1B0Uo13lX+0BGJ/Dacl1j5I\nmlk5EdRyMHn97riJJrOtUbIa1Y65ohLZdOMkB9Hj38n7uRQ5asRkya3Uu0krJO2QtFPSYdOX07ra\nt6XX70uTVhqvXZH275B0YW7/CZJul/STlFfiX/d61y5JJm6jNGsv6F9JUtIYcD1wPjAObJW0MSIe\nzh12CfBcRJwlaRVwLfAHKUfEKuBs4HTgTkmvTWtvfwH4dkS8V9I84Jher7X2Jclmo1qSLNLuXqp0\nnzZzJphTaithGbAzIh6LiH3AerK8D3kryfI/ANwOLE/js1cC6yNib0Q8DuwElkk6Dngr2fhtImJf\nRDzf6z07SDZpDAsa9eo3eFqi9VcgJqPcBsyXtC23rWl6uwXAk7nn42lf4TERcQB4ATi5zbmvAZ4F\n/krS30u6UVLP0/lc3TazUrIlZUuHjN0RsbTN60XFj+Y/3a2OabV/LnAu8NGIuE/SF8hSNf63Etfb\nkkuSBRodGh6iYpZXLpdkyXyS48DC3PMzgKdaHSNpLnA8sKfNuePAeETcl/bfThY0e+Ig2UZ+Rk7V\nDOq+qvr1spTgIuaU2krYCiyWtCh1sKwiy/uQl88D8V7g7oiItH9V6v1eBCwG7o+IXwJPSnpdOmc5\n8DA9cnV7GlWdwjioe6jC18Za61fW8Yg4IOkyYDMwBqyLiO2SrgK2RcRGsg6Yr0naSVaCXJXO3S5p\nA1kAPABcmnq2AT4KfD0F3seAD/Z6rQ6SJbjqbZZlJu/n3O2I2ARsatr36dzjl2mRICcirgauLtj/\nINCuLbRjDpIlVa0kOaig72mJ1ZV13HhaoplZC17jxqbRKPXk2yhHtSQ0DG2So/q1q6us46Z+PXMO\nkl3wFEarqzqmSuv5jiWNpdHt/zc9X5Qmoz+aJqfP6/0yh9Mo/1Ed5Wu32dHhjJvK6MefhY8Bj+Se\nXwtcFxGLgefIJqlXkiLLR9mYxpifzjjsXAq2bnghsA5JOgN4F3Bjei7g7WQj3SGbnP6eXj5j2OWT\n9TrwWJVFwP7JOaW2Kum1TfJ/AZ8AXpmenww8nyajQ/GkdWBm1902s95l1e1qBcAyellS9veAZyLi\nh/ndBYcWlq+qtO72wbnes/jzU1TNn41UaaPS3GDd6ePc7ZHR65Ky75b0TuAo4DiykuUJkuam0mTR\npPXK0mQKlMFhuUoGPVyom8zkM3UdVg11HQLUddknIq6IiDMi4kyyOZV3R8R/AL5LNhkdssnpd/R8\nlSPkYBtl08+Sg4eNPvUzwcXIGMTdfBL4eJqUfjIpS3DdTM7wCFRXt20m9HONm1HRl1/liLgHuCc9\nfowsNXutzTkwda63q9s26rLebc/dNjMr1BhMXjcOkgOUL1W5hGVVULWqdBkOkjMk5kwdeN739y+o\nzrer4g9DqjQbLXXt3XaQnCGanBpA+p1JyG2SNhOq1nNdhoPkDCpK3OugYqMiQhxwkDQza83VbRu4\ng9XtxswcypcmO21jnI32QbdJVldd2yTrV3YeEo1OnOZla9v9DHbaxjgbwcoBstr6mU9S0gpJOyTt\nlHR5wetHppy0O1OO2jNzr12R9u+QdGHTeVNy3PbKQXIWFXXcOMjYsOpn0l1JY8D1wEXAEuBiSUua\nDrsEeC4izgKuI8tVSzpuFXA2sAL4cnq/huYctz1xkJxljUDZKmnvdIl8G691My2xH0mCm9+jzGeW\nOdaGUx+nJS4DdkbEYxGxD1gPrGw6ZiVZTlrIctQuTzlrVwLrI2JvRDwO7Ezvd1iO235wm+QQaFXl\nbqRgm+7c/P9Fr7U7r1fN79PJZ7rUPFoi4ED/EuouAJ7MPR8H3tTqmIg4IOkFsnwQC4B7m85t5K1t\nznHbM5ckzay0Dqrb8yVty21rmt6qTO7ZVscU7m+R47ZnLkkOieZB5mbDpsO527sjYmmb18eBhbnn\nRblnG8eMS5oLHA/saXPuu2nKcSvpryPi/WUvuohLkkMm30bZrN2+2WqT7OQzeznWhkOESm0lbAUW\np9VV55F1xGxsOmYjWU5ayHLU3h0RkfavSr3fi4DFwP0tctz2FCDBJcmhdHApiBJteLPdJtnL+7rE\nPHr6leAitTFeBmwGxoB1EbFd0lXAtojYSJaL9mspN+0essBHOm4D8DBwALg0Iib6cmEFegqSkk4g\n60U6h+xX+kPADuA24EzgZ8DvR8RzPV1lDQ0yGYZZNyL6O5g8IjYBm5r2fTr3+GXgfS3OvRq4us17\n30PKcdurXqvbXwC+HRH/AvhXZGOTLgfuSutu35WeW5cm52ZbJ1XwMq+ZdU5MTM4ptVVJL6slHge8\nlbQ8Q0Tsi4jnmTq2qfLrbpvVSR/bJEdGLyH/NcCzwF+lKUA3SjoWODUidgGk/08pOlnSmsbwgImX\nXuzhMqptzoFsg8PHUzb2QXGp0W1+1k+Nudv9mpY4KnoJknOBc4EbIuINwIt0ULWu0rrbM2G63JMO\niDZwkbVLltmqpJcgOQ6MR8R96fntZEHzaUmnAaT/n+ntEq2heQpjw0y3V7b7bA8BqrY6rpbYy7rb\nvwSelPS6tGs5WZd8fmxT7dbdHrRO0qENaghQc0KObhN0uPQ7WqKmHTe9jpP8KPD1NBj0MeCDZIF3\ng6RLgCdo0YVvZqOnalXpMnoKkhHxIFA09Wh5L+9r7RVNYXSpzGZC1Xquy/CMmxHWPDNnGDKTW3Vl\nnTIOkjZiNHkoUOZTrHXKAdXKqNrwnjIcJCugebnag/unCXqd5K00A7dJ2ggrWq52utJh/rV2pdDm\n98k/n+4zOznWhlsgJivWc12Gg6SZlVbHv2kOkhXSKJVNHhHM2a9sMNbE9G2VIUBTMw+16zlvNy6y\nl2NtyLnjxqpizv7sB1kpw16ZdXIOy5vvAGZFavhzUb8Ghhp5+VVZlJwydbBROjwAc/ZlWwgmjp76\n099uqmE32dBrWACppDpmAXJJssKOenaMGANSNboxVKgxvjJyKxXP2Vf+B7ubbOgumY6+ACYnqxUA\ny3CQrDjl2yQncyW6OYcf1/I9HOAMsihZsVJiGQ6SZlZaHcdJuk2yBhqDxWMsV1WeyNollRL6Ts6L\n0u2JnaRK8/ISFRMltwpxkKwRTcCBo7NgOHFU8JvTJ/jN6RMo4Jhfakq+yrJDd6ZLlTYbKzbaoJTr\ntCnbcSNphaQdknZKOixhd1oy9rb0+n2Szsy9dkXav0PShWnfQknflfSIpO2SPtaPu3Z1u2bm/kZZ\nEJwQ85479Ddy3yuz/x24rK0+/XxIGgOuB84nS+C9VdLGiHg4d9glwHMRcZakVcC1wB9IWkK2vOzZ\nwOnAnZJeS7a87J9HxAOSXgn8UNKWpvfsmEuSNaSA/cdNsvdVE+x91QQEHPfzrAu8k0zjZYYAdTNc\nyIZUQEyq1FbCMmBnRDwWEfuA9WSLCOblFxW8HVguSWn/+ojYGxGPAzuBZRGxKyIeAIiIX5Ot3rqg\n19vuKUhK+rNUrP2xpFslHSVpUSoaP5qKyvN6vUjrv3nPz+F77/o833vX59EEHPc39xYe12nJ0tXt\nqlPJbVoLgCdzz8c5PKAdPCYiDgAvACeXOTdVzd8A3EePellSdgHwJ8DSiDgHGCMrAl8LXJfW3X6O\nrMhsZlVQvuNmfmM11LStaXqnokh62MSvFse0PVfSK4C/Bf40Iv5puluaTq9tknOBoyXtB44BdgFv\nB/59ev1m4DPADT1+jg3Aiq98AoA4An7+39/MnAPFGXpaZevxejY1VP77uDsiilYtaBgHFuaenwE8\n1eKYcUlzgeOBPe3OlXQEWYD8ekR8o/TVttHLQmC/AD5Hto7NLrKi8A+B51PRGIqL0DZkFPCTP/ry\ntO2PRe2LnQwB6mVlRRsCjcHkZbbpbQUWp+a5eWS10I1Nx+QXFXwvcHdERNq/KvV+LwIWA/en9sqb\ngEci4vO933Cml+r2iWQNqIvIepiOBS4qOLTwb4+kNY2i+MRLL3Z7GdYnS274Y6D4Z7wxzKdoOmIn\nQ4B6WVnRhkO/1t1OBanLgM1kHSwbImK7pKskvTsddhNwsqSdwMeBy9O524ENZKuzfhu4NCImgLcA\nfwi8XdKDaXtnr/fcS3X7HcDjEfEsgKRvAG8GTpA0N30RiorQAETEWmAtwFGnL/SvyxAoStxrNkUf\n525HxCZgU9O+T+cev0yL1VYj4mrg6qZ9f0fJXqNO9NK7/QRwnqRjUjG3se72d8mKxuB1t80qJV+r\naLdVSS9tkveRjV16AHgovdda4JPAx1MR+WSyIrONiINTGEuOj/S0xBop27NdsSDZ67rbVwJXNu1+\njGygqI2wRjq1okXGus1MXvQZNkpKd8pUiqclWkutVmG0Gqvhz4KDpLWVL1GW0UlQdQAeQSV/DqrE\nQdKmlU/W22iv7EcGcgfIEeOku2Zm7dXxD5uDpJUy3RRFq4kafu+dKs060mijbMVDgKxqXJK0jmly\n6vCgg/s7HEjsEunoqeP3zEHSulJ2eFAdf6kqK+jrtMRR4SBpXZtS9W5Rimw3F9ztmyOoht8vB0kz\nK62Of9QcJK0njUHmk3Oz5WmbB55rkoN5WZpLlXX8hRt5NfyeOUhaX8xJaZYPm5nT1LFjI66G30MP\nAbK+2n9sTO3xTsHTw31GX9k0aVX7Y+iSpPXVES/qYNUbYHIeLTt1bAS5d9usd42qN5RPjGGjoY5/\n7KatbktaJ+kZST/O7TtJ0pa0tvaWtN4NynxR0k5JP5J07iAv3sxmWA2T7pZpk/wqsKJp3+XAXWlt\n7bvSc8gWAluctjV4Kdna2/+KOJS9vIK/QLVS0zbJaYNkRHyfbK3bvJVka2qT/n9Pbv8tkbmXbFGw\n0/p1sTZ6jvh/gsagcTGAZZpsRrkkWdqpEbELIP1/Stq/AHgyd5zX3bbD5njb6NJkua3Ue0krJO1I\nzXOXF7x+pKTb0uv3SToz99oVaf8OSReWfc9u9HsIUNGvQuHfFa+7XS+NKYztMghZfUgaA64na6Jb\nAlwsaUnTYZcAz0XEWcB1wLXp3CXAKuBssqbAL0saK/meHev2R/bpRjU6/f9M2j8OLMwd13bd7YhY\nGhFLx445tsvLMLMZ1b/q9jJgZ0Q8FhH7gPVkzXV5+Wa924HlafnqlcD6iNgbEY8DO9P7lXnPjnUb\nJDeSrakNU9fW3gh8IPVynwe80KiWmzWqYo3SpKvgI6azjpv5jZpi2tY0vVuZprmDx0TEAeAFsmWq\nW507kOa+acdJSroVeBvZTY+TLSF7DbBB0iXAE8D70uGbgHeSRfaXgA/2eoFWPY02q6r1gtZC+e/Z\n7ohY2ub1Mk1zrY5ptb+o0NfzT9m0QTIiLm7x0vKCYwO4tNeLsnqIMdDEbF+FdaR/f9jKNM01jhmX\nNBc4nmykTbtzSzX3dcLN6DZrHCBHi+hr7/ZWYLGkRZLmkXXEbGw6Jt+s917g7lQQ2wisSr3fi8jG\nZd9f8j075mmJZlZOHweKR8QBSZcBm4ExYF1EbJd0FbAtIjYCNwFfk7STrAS5Kp27XdIG4GHgAHBp\nREwAFL1nr9fqIGlm5fWxHTkiNpH1Y+T3fTr3+GUO9Xc0n3s1cHWZ9+yVg6SZlVfDzjYHSTMrrY4j\nEhwkzaw8B0kzsxainvlBHSTNrDyXJM3MWnObpJlZOw6SZmYtVDChbhkOkmZWinB128ysLQdJM7N2\nHCTNzNqoYZDsdt3tv5T0k7S29jclnZB7rXCBHrN+a2Q2d4bzGeIlZVv6Koevu70FOCcifhv4R+AK\naL1AT9+u1iyn8ctYtV/KoeYlZQ9XtO52RHwnrTkBcC9ZBmBovUCP2cC4JDlz+rmk7KjoR2byDwHf\nSo+97rbNOEUWKF39Hrw6Vrd76riR9CmyzMBfb+wqOKzlutvAGoC5x5/Yy2WY2UyoYFW6jK6DpKTV\nwO8By9O6E9DhutvAWoCjTl9Ywy+99VO+9FK1ksxQqeHXtqvqtqQVwCeBd0fES7mXWi3QYzZjXN0e\njMaMG1e3m7RYd/sK4EhgiySAeyPiP7VboMdsplTtl3SYaLJ+X9xu192+qc3xhQv0mNmIm6E2SUkn\nAbcBZwI/A34/Ip4rOG418F/T0/8RETen/W8kG7p4NNmiYB+LiJD0l8C/BfYBPwU+GBHPT3c9Xnfb\nzEqboer25cBdEbEYuCs9n3odWSC9EngT2TDDKyU1eoBvIOsUXpy2xjjvwvHd03GQNLPyZmYw+Urg\n5vT4ZuA9BcdcCGyJiD2plLkFWCHpNOC4iPhB6lC+pXF+m/HdbXnutpmVNkPtvadGxC6AiNgl6ZSC\nY1qNyV6QHjfvb/Yhsir9tBwkzay88kFyvqRtuedr07A/ACTdCby64LxPlXz/VmOypx2rXTC+uy0H\nSTMrp7PVEndHxNKWbxXxjlavSXpa0mmpFHka8EzBYeNko24azgDuSfvPaNp/cKx2i/HdbblN0sxK\nmcFxkhuB1enxauCOgmM2AxdIOjF12FwAbE7V9F9LOk/Z+MQPNM5vM767LQdJMysvotzWm2uA8yU9\nCpyfniNpqaQbs8uIPcBnga1puyrtA/gIcCNZgp2fcii3xJeAV5KN735Q0v8uczGubptZaTPRcRMR\nvwKWF+zfBnw493wdsK7FcecU7D+rm+txkDSzcpzgwsysvarliizDQdLMSnOQNDNrJehHp8zIcZA0\ns9LqmGHJQdLMynOQNDMr1hhMXjddrbude+0/SwpJ89NzSfpiWnf7R5LOHcRFm9ksiECT5bYq6Xbd\nbSQtJBsN/0Ru90UcyuG2hiyvm9nI8lIQTbzu9uGK1t1OrgM+wdQvyUrglsjcC5yQJqibjaQ6Vi/b\nqeMaN90uBPZu4BcR8Q9NL3ndbbOqCmAyym0V0nHHjaRjyHK+XVD0csE+r7ttlRCqXimpYzW8/25K\nkr8FLAL+QdLPyPK1PSDp1XS47nZELI2IpWPHHNvFZZjNrNoHSOpZ3e64JBkRDwEH06mnQLk0InZL\n2ghcJmk92QI9LzTSsJvZ6Ktaz3UZZYYA3Qr8AHidpHFJl7Q5fBPwGFket68Af9yXqzSz2Ve2Z7ti\ncbTbdbfzr5+ZexzApb1flpkNm2wwecUiYAmecWNm5TkLkJlZay5Jmpm1UsH2xjIcJM36pGgKY7WG\nw1RvXnYZDpJmfdIcECs577uG1W0vKWvWZ6GqBshs+YYyWy8knSRpi6RH0/+FU/IkrU7HPCppdW7/\nGyU9lLKRfTGtv50/b0r2suk4SJpZeTOz7vblwF0RsRi4Kz2fQtJJwJVkk1aWAVfmgukNZFOeGxnJ\nVuTOK8pe1paDpFmfVXFq3kEzM5h8JXBzenwz8J6CYy4EtkTEnoh4DtgCrEhZx46LiB+kcdu3NJ1f\nlL2sLbdJmg1IFQOlJkvXpedL2pZ7vjYi1pY899TGdOaI2CXplIJjWmUcW5AeN++fkr2sqQbeloOk\n2YBVJntQ0Mlg8t0RsbTVi5LuBF5d8NKnSr5/q4xjhfunyV7WloOk2YBVIkACIvo2mDwi3tHyc6Sn\nJZ2WSpGnAc8UHDYOvC33/AzgnrT/jKb9TzE1e1lj/wOSlkXEL9tdq9skzay8mem42Qg0eqtXA3cU\nHLMZuEDSianD5gJgc6qm/1rSealX+wPAHRHxUEScEhFnpnwT48C50wVIcJA0s07MTJC8Bjhf0qNk\nPdHXAEhaKunG7DJiD/BZYGvarkr7AD4C3EiWjeynwLd6uRhXt82snM7aJLv/mIhfAcsL9m8DPpx7\nvg5Y1+K4c6b5jDPLXo+DpJmV1kHvdmU4SJpZSX2pSo+cMpnJ10l6RtKPm/Z/VNIOSdsl/UVu/xVp\nOtAOSRcO4qLNbBYEM9UmOVTKlCS/CnyJbOQ6AJJ+l2xU/G9HxN7GYE9JS4BVwNnA6cCdkl4bERP9\nvnAzmwX1q21PX5KMiO8De5p2fwS4JiL2pmMa45hWAusjYm9EPE7Wu7Ssj9drZrNIEaW2Kul2CNBr\ngX8j6T5J35P0O2l/q6lCh5G0RtI2SdsmXnqxy8swsxnl6nZH550InAf8DrBB0mtoPVXo8J3ZPM61\nAEedvrBaX1WzKoqAifrVt7sNkuPAN1KWjfslTQLz0/6FueMaU4LMrAoqVkoso9vq9v8B3g4g6bXA\nPGA32XSiVZKOlLSILJfb/f24UDMbAq5uH07SrWQTyedLGidLdLkOWJeGBe0DVqdS5XZJG4CHgQPA\npe7ZNquIALzGzeEi4uIWL72/xfFXA1f3clFmNowCwm2SZmbFAnfcmJm1VbH2xjIcJM2sPAdJM7NW\nqtdzXYaDpJmVE4BTpZmZteGSpJlZK56WaGbWWkB4nKSZWRs1nHHj1RLNrLwZmLst6SRJWyQ9mv4/\nscVxq9Mxj0pandv/RkkPpRUSvpiWlm28VriiQjsOkmZWTkTWu11m683lwF0RsRi4Kz2fQtJJZHkk\n3kSW2PvKXDC9AVhDlmBnMbAinZNfUeFs4HNlLsZB0szKm5ksQCuBm9Pjm4H3FBxzIbAlIvZExHPA\nFmCFpNOA4yLiBynpzi2581utqNCWg6SZlRTExESprUenRsQugPT/KQXHtFoFYUF63LwfWq+o0JY7\nbsysnM5Spc2XtC33fG1ajQAASXcCry4471Ml37/VKgjtVkcoXFEhlThbcpA0q6hI4UJx6HHvb1q6\nvXF3RCxt+TYR72j1mqSnJZ0WEbtS9bmoWjxOlue24QzgnrT/jKb9T+XOKVpR4dl2N+LqtpmVEkBM\nRqmtRxuBRm/1auCOgmM2AxdIOjF12FwAbE7V819LOi/1an8gd36rFRXacpA0qyhFtjUe9yxS0t0y\nW2+uAc6X9ChwfnqOpKWSbswuJfYAnwW2pu2qtA+yDpobyZa0/inwrbR/HfCatKLCeg6tqNCWq9tm\nNdCv6nYfOmWm/4yIXwHLC/ZMZZ8RAAAC5ElEQVRvAz6ce76OLPAVHXdOwf59tFhRoR2VCKQDJ+lZ\n4EVKFH0rZD71ul+o3z0P2/3+84h4VbcnS/o22T2VsTsiVnT7WcNkKIIkgKRt7Rp6q6Zu9wv1u+e6\n3W9VuU3SzKwNB0kzszaGKUiunf6QSqnb/UL97rlu91tJQ9MmaWY2jIapJGlmNnRmPUhKWpHyu+2U\ndFhKpKqQ9LOU4+7BxpzWsnnzRoGkdZKeSQN1G/sK70+ZL6bv+Y8knTt7V969Fvf8GUm/SN/nByW9\nM/faFemed0i6cHau2jo1q0FS0hhwPXARsAS4WNKS2bymAfvdiHh9bljItHnzRshXSXn7clrd30Uc\nyvW3hiz/3yj6KoffM8B16fv8+ojYBJB+rlcBZ6dzvpx+/m3IzXZJchmwMyIeS6Ph15PlkquLMnnz\nRkJEfB/Y07S71f2tBG6JzL3ACSmRwUhpcc+trATWR8TeiHicbMrcsoFdnPXNbAfJVjnhqiiA70j6\noaQ1aV+ZvHmjrNX9Vf37fllqRliXa0Kp+j1X1mwHyXa536rmLRFxLllV81JJb53tC5pFVf6+3wD8\nFvB6YBfwP9P+Kt9zpc12kBwHFuae53O/VUpEPJX+fwb4JllV6+lGNbNN3rxR1ur+Kvt9j4inI2Ii\nsrVXv8KhKnVl77nqZjtIbgUWS1okaR5Zw/bGWb6mvpN0rKRXNh6T5b77MeXy5o2yVve3EfhA6uU+\nD3ihUS0fdU1tq/+O7PsM2T2vknSkpEVknVb3z/T1WedmNVVaRByQdBlZAs0xYF1EbJ/NaxqQU4Fv\nppUt5wJ/ExHflrSVLIX8JcATwPtm8Rp7IulWskzR8yWNk61kdw3F97cJeCdZ58VLwAdn/IL7oMU9\nv03S68mq0j8D/iNARGyXtAF4GDgAXBoRg887Zj3zjBszszZmu7ptZjbUHCTNzNpwkDQza8NB0sys\nDQdJM7M2HCTNzNpwkDQza8NB0sysjf8PkgcWMPD86KAAAAAASUVORK5CYII=\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -257,18 +257,18 @@ "text": [ "Sample 1\n", " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.032307 0 2.0 0.000477 0.105887 0.0 0.0\n", - "1 2.827218 0 2.0 0.000349 0.094165 0.0 0.0\n", - "2 16.298283 0 1.0 0.000519 0.183407 0.0 0.0\n", - "3 16.771312 0 2.0 0.012540 0.078625 0.0 0.0\n", - "4 20.558190 0 2.0 0.011813 0.085244 0.0 0.0\n", + "0 0.032689 0 2.0 0.000477 0.105084 0.0 0.0\n", + "1 2.825536 0 2.0 0.000336 0.101927 0.0 0.0\n", + "2 16.224770 0 1.0 0.000287 0.025024 0.0 0.0\n", + "3 16.769618 0 2.0 0.012305 0.086891 0.0 0.0\n", + "4 20.554322 0 2.0 0.010908 0.090244 0.0 0.0\n", "Sample 2\n", " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.033027 0 2.0 0.000476 0.104104 0.0 0.0\n", - "1 2.825226 0 2.0 0.000344 0.098390 0.0 0.0\n", - "2 16.245609 0 1.0 0.000353 0.095063 0.0 0.0\n", - "3 16.764396 0 2.0 0.013475 0.075175 0.0 0.0\n", - "4 20.560505 0 2.0 0.011994 0.081186 0.0 0.0\n" + "0 0.027766 0 2.0 0.000465 0.113061 0.0 0.0\n", + "1 2.827059 0 2.0 0.000332 0.099581 0.0 0.0\n", + "2 16.210647 0 1.0 0.000456 0.062444 0.0 0.0\n", + "3 16.773836 0 2.0 0.013618 0.074771 0.0 0.0\n", + "4 20.558365 0 2.0 0.010902 0.088135 0.0 0.0\n" ] } ], @@ -296,8 +296,8 @@ { "data": { "text/plain": [ - "[,\n", - " ]" + "[,\n", + " ]" ] }, "execution_count": 10, @@ -326,9 +326,9 @@ }, { "data": { - "image/png": "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\nYBtKl8mxDQAAAABJRU5ErkJggg==\n", + "image/png": "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\nTLCDAAAAAElFTkSuQmCC\n", "text/plain": [ - "" + "" ] }, "metadata": {}, diff --git a/openmc/data/resonance.py b/openmc/data/resonance.py index 33d64e951f..e71073919b 100644 --- a/openmc/data/resonance.py +++ b/openmc/data/resonance.py @@ -203,7 +203,7 @@ class ResonanceRange(object): return cls(target_spin, energy_min, energy_max, {0: a}, {0: ap}) - def reconstruct(self, energies, use_sample=False, sample_parameters=None): + def reconstruct(self, energies): """Evaluate cross section at specified energies. Parameters @@ -222,8 +222,8 @@ class ResonanceRange(object): raise RuntimeError("Resonance reconstruction not available.") # Pre-calculate penetrations and shifts for resonances - if not self._prepared or use_sample: - self._prepare_resonances(use_sample, sample_parameters) + if not self._prepared: + self._prepare_resonances() if isinstance(energies, Iterable): elastic = np.zeros_like(energies) @@ -395,11 +395,8 @@ class MultiLevelBreitWigner(ResonanceRange): return mlbw - def _prepare_resonances(self, use_sample=False, sample_parameters=None): - if not use_sample: - df = self.parameters.copy() - else: - df = sample_parameters.copy() + def _prepare_resonances(self): + df = self.parameters.copy() # Penetration and shift factors p = np.zeros(len(df)) @@ -657,11 +654,8 @@ class ReichMoore(ResonanceRange): return rm - def _prepare_resonances(self, use_sample=False, sample_parameters=None): - if not use_sample: - df = self.parameters.copy() - else: - df = sample_parameters.copy() + def _prepare_resonances(self): + df = self.parameters.copy() # Penetration and shift factors p = np.zeros(len(df)) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index 714d87234d..ba62b4f4fa 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -257,6 +257,9 @@ class ResonanceCovarianceRange: 'captureWidth', 'fissionWidth', 'competitiveWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) res_range = copy.copy(resonances) + res_range._prepared = False # Set prepared to False to ensure + # the sampled parameters are used + # in reconstruction res_range.parameters = sample_params samples.append(res_range) @@ -282,6 +285,9 @@ class ResonanceCovarianceRange: 'captureWidth', 'fissionWidth', 'competitiveWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) res_range = copy.copy(resonances) + res_range._prepared = False # Set prepared to False to ensure + # the sampled parameters are used + # in reconstruction res_range.parameters = sample_params samples.append(res_range) @@ -308,6 +314,9 @@ class ResonanceCovarianceRange: 'captureWidth', 'fissionWidth', 'competitveWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) res_range = copy.copy(resonances) + res_range._prepared = False # Set prepared to False to ensure + # the sampled parameters are used + # in reconstruction res_range.parameters = sample_params samples.append(res_range) @@ -334,6 +343,9 @@ class ResonanceCovarianceRange: 'captureWidth', 'fissionWidthA', 'fissionWidthB'] sample_params = pd.DataFrame.from_records(records, columns=columns) res_range = copy.copy(resonances) + res_range._prepared = False # Set prepared to False to ensure + # the sampled parameters are used + # in reconstruction res_range.parameters = sample_params samples.append(res_range) @@ -359,6 +371,9 @@ class ResonanceCovarianceRange: 'captureWidth', 'fissionWidthA', 'fissionWidthB'] sample_params = pd.DataFrame.from_records(records, columns=columns) res_range = copy.copy(resonances) + res_range._prepared = False # Set prepared to False to ensure + # the sampled parameters are used + # in reconstruction res_range.parameters = sample_params samples.append(res_range) From 9ad8dabb9cc111ded69d381893df471e5b4a546d Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Thu, 19 Jul 2018 13:51:59 -0500 Subject: [PATCH 079/100] Fixes to tests --- .../nuclear-data-resonance-covariance.ipynb | 32 +++++++++---------- tests/unit_tests/test_data_neutron.py | 12 +++---- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/examples/jupyter/nuclear-data-resonance-covariance.ipynb b/examples/jupyter/nuclear-data-resonance-covariance.ipynb index bc83d48fc3..f830a2cacb 100644 --- a/examples/jupyter/nuclear-data-resonance-covariance.ipynb +++ b/examples/jupyter/nuclear-data-resonance-covariance.ipynb @@ -118,7 +118,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 5, @@ -129,7 +129,7 @@ "data": { "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -257,18 +257,18 @@ "text": [ "Sample 1\n", " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.032689 0 2.0 0.000477 0.105084 0.0 0.0\n", - "1 2.825536 0 2.0 0.000336 0.101927 0.0 0.0\n", - "2 16.224770 0 1.0 0.000287 0.025024 0.0 0.0\n", - "3 16.769618 0 2.0 0.012305 0.086891 0.0 0.0\n", - "4 20.554322 0 2.0 0.010908 0.090244 0.0 0.0\n", + "0 0.031837 0 2.0 0.000475 0.106547 0.0 0.0\n", + "1 2.824944 0 2.0 0.000310 0.101103 0.0 0.0\n", + "2 16.230854 0 1.0 0.000379 0.055465 0.0 0.0\n", + "3 16.764246 0 2.0 0.013214 0.075675 0.0 0.0\n", + "4 20.559124 0 2.0 0.011960 0.076114 0.0 0.0\n", "Sample 2\n", " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.027766 0 2.0 0.000465 0.113061 0.0 0.0\n", - "1 2.827059 0 2.0 0.000332 0.099581 0.0 0.0\n", - "2 16.210647 0 1.0 0.000456 0.062444 0.0 0.0\n", - "3 16.773836 0 2.0 0.013618 0.074771 0.0 0.0\n", - "4 20.558365 0 2.0 0.010902 0.088135 0.0 0.0\n" + "0 0.033447 0 2.0 0.000478 0.103629 0.0 0.0\n", + "1 2.821635 0 2.0 0.000334 0.093337 0.0 0.0\n", + "2 16.246838 0 1.0 0.000403 0.104026 0.0 0.0\n", + "3 16.766217 0 2.0 0.012486 0.079445 0.0 0.0\n", + "4 20.561842 0 2.0 0.011493 0.084187 0.0 0.0\n" ] } ], @@ -296,8 +296,8 @@ { "data": { "text/plain": [ - "[,\n", - " ]" + "[,\n", + " ]" ] }, "execution_count": 10, @@ -326,9 +326,9 @@ }, { "data": { - "image/png": "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\nTLCDAAAAAElFTkSuQmCC\n", + "image/png": "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\nEMYYY1L6/8Lpr4E7p68dAAAAAElFTkSuQmCC\n", "text/plain": [ - "" + "" ] }, "metadata": {}, diff --git a/tests/unit_tests/test_data_neutron.py b/tests/unit_tests/test_data_neutron.py index 54d815eb66..0ed3e92f77 100644 --- a/tests/unit_tests/test_data_neutron.py +++ b/tests/unit_tests/test_data_neutron.py @@ -286,7 +286,7 @@ def test_rml(cl35): def test_mlbw_cov(ti50): #Testing on first range only - cov = ti50.res_covariance.ranges[0] + cov = ti50.resonance_covariance.ranges[0] res = ti50.resonances.ranges[0] assert cov.parameters['energy'][0] == pytest.approx(-21020.) assert res.parameters['energy'][0] == cov.parameters['energy'][0] @@ -300,14 +300,14 @@ def test_mlbw_cov(ti50): assert not subset.empty assert cov.cov_subset is not None assert (subset['L'] == 1).all() - cov.sample_resonance_parameters(1) - xs = cov.reconstruct([10., 100., 1000.], res, 0) + cov.sample_resonance_parameters(1, res) + xs = cov.samples[0].reconstruct([10., 100., 1000.]) assert sorted(xs.keys()) == [2, 18, 102] def test_rm_cov(gd154): #Testing on first range only - cov = gd154.res_covariance.ranges[0] + cov = gd154.resonance_covariance.ranges[0] res = gd154.resonances.ranges[0] assert cov.parameters['energy'][0] == pytest.approx(-2.200001) assert res.parameters['energy'][0] == cov.parameters['energy'][0] @@ -321,8 +321,8 @@ def test_rm_cov(gd154): assert not subset.empty assert cov.cov_subset is not None assert (subset['energy'] < 100).all() - cov.sample_resonance_parameters(1) - xs = cov.reconstruct([10., 100., 1000.], res, 0) + cov.sample_resonance_parameters(1, res) + xs = cov.samples[0].reconstruct([10., 100., 1000.]) assert sorted(xs.keys()) == [2, 18, 102] From d148c2405619c4ece674d56e3d89f270b3facde5 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Thu, 19 Jul 2018 14:21:46 -0500 Subject: [PATCH 080/100] Take advantage of np.random.multivariate size option for multiple samples --- openmc/data/resonance_covariance.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index ba62b4f4fa..9a8163f3b2 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -243,8 +243,9 @@ class ResonanceCovarianceRange: gf = pd.DataFrame.as_matrix(parameters['fissionWidth']) gx = pd.DataFrame.as_matrix(parameters['competitiveWidth']) mean = mean_array.flatten() - for i in range(n_samples): - sample = np.random.multivariate_normal(mean, cov) + par_samples = np.random.multivariate_normal(mean, cov, + size=n_samples) + for sample in par_samples: energy = sample[0::3] gn = sample[1::3] gg = sample[2::3] @@ -270,8 +271,9 @@ class ResonanceCovarianceRange: l_value = pd.DataFrame.as_matrix(parameters['L']) gx = pd.DataFrame.as_matrix(parameters['competitiveWidth']) mean = mean_array.flatten() - for i in range(n_samples): - sample = np.random.multivariate_normal(mean, cov) + par_samples = np.random.multivariate_normal(mean, cov, + size=n_samples) + for sample in par_samples: energy = sample[0::4] gn = sample[1::4] gg = sample[2::4] @@ -298,8 +300,9 @@ class ResonanceCovarianceRange: spin = pd.DataFrame.as_matrix(parameters['J']) l_value = pd.DataFrame.as_matrix(parameters['L']) mean = mean_array.flatten() - for i in range(n_samples): - sample = np.random.multivariate_normal(mean, cov) + par_samples = np.random.multivariate_normal(mean, cov, + size=n_samples) + for sample in par_samples: energy = sample[0::5] gn = sample[1::5] gg = sample[2::5] @@ -330,8 +333,9 @@ class ResonanceCovarianceRange: gfa = pd.DataFrame.as_matrix(parameters['fissionWidthA']) gfb = pd.DataFrame.as_matrix(parameters['fissionWidthB']) mean = mean_array.flatten() - for i in range(n_samples): - sample = np.random.multivariate_normal(mean, cov) + par_samples = np.random.multivariate_normal(mean, cov, + size=n_samples) + for sample in par_samples: energy = sample[0::3] gn = sample[1::3] gg = sample[2::3] @@ -356,8 +360,9 @@ class ResonanceCovarianceRange: spin = pd.DataFrame.as_matrix(parameters['J']) l_value = pd.DataFrame.as_matrix(parameters['L']) mean = mean_array.flatten() - for i in range(n_samples): - sample = np.random.multivariate_normal(mean, cov) + par_samples = np.random.multivariate_normal(mean, cov, + size=n_samples) + for sample in par_samples: energy = sample[0::5] gn = sample[1::5] gg = sample[2::5] From fde13a913b94ed7dcb507a30201845bdade690af Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Thu, 19 Jul 2018 14:56:35 -0500 Subject: [PATCH 081/100] Style and change of __init__ methods --- .../nuclear-data-resonance-covariance.ipynb | 32 ++--- openmc/data/resonance_covariance.py | 128 ++++++------------ 2 files changed, 61 insertions(+), 99 deletions(-) diff --git a/examples/jupyter/nuclear-data-resonance-covariance.ipynb b/examples/jupyter/nuclear-data-resonance-covariance.ipynb index f830a2cacb..9e79175d88 100644 --- a/examples/jupyter/nuclear-data-resonance-covariance.ipynb +++ b/examples/jupyter/nuclear-data-resonance-covariance.ipynb @@ -118,7 +118,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 5, @@ -129,7 +129,7 @@ "data": { "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -257,18 +257,18 @@ "text": [ "Sample 1\n", " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.031837 0 2.0 0.000475 0.106547 0.0 0.0\n", - "1 2.824944 0 2.0 0.000310 0.101103 0.0 0.0\n", - "2 16.230854 0 1.0 0.000379 0.055465 0.0 0.0\n", - "3 16.764246 0 2.0 0.013214 0.075675 0.0 0.0\n", - "4 20.559124 0 2.0 0.011960 0.076114 0.0 0.0\n", + "0 0.030278 0 2.0 0.000472 0.109151 0.0 0.0\n", + "1 2.826910 0 2.0 0.000347 0.099239 0.0 0.0\n", + "2 16.199761 0 1.0 0.000258 0.082103 0.0 0.0\n", + "3 16.772474 0 2.0 0.012354 0.091428 0.0 0.0\n", + "4 20.553868 0 2.0 0.011185 0.089609 0.0 0.0\n", "Sample 2\n", " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.033447 0 2.0 0.000478 0.103629 0.0 0.0\n", - "1 2.821635 0 2.0 0.000334 0.093337 0.0 0.0\n", - "2 16.246838 0 1.0 0.000403 0.104026 0.0 0.0\n", - "3 16.766217 0 2.0 0.012486 0.079445 0.0 0.0\n", - "4 20.561842 0 2.0 0.011493 0.084187 0.0 0.0\n" + "0 0.033611 0 2.0 0.000479 0.103410 0.0 0.0\n", + "1 2.825707 0 2.0 0.000335 0.101266 0.0 0.0\n", + "2 16.270769 0 1.0 0.000360 0.071230 0.0 0.0\n", + "3 16.773850 0 2.0 0.013402 0.074592 0.0 0.0\n", + "4 20.563037 0 2.0 0.011916 0.086590 0.0 0.0\n" ] } ], @@ -296,8 +296,8 @@ { "data": { "text/plain": [ - "[,\n", - " ]" + "[,\n", + " ]" ] }, "execution_count": 10, @@ -326,9 +326,9 @@ }, { "data": { - "image/png": "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\nEMYYY1L6/8Lpr4E7p68dAAAAAElFTkSuQmCC\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYgAAAEOCAYAAACTqoDjAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4wLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvpW3flQAAIABJREFUeJzt3XecXHW5+PHPM21LtqT3hCQklAhK\nCSjFKyBSlCLloqBXUQT71ReI4oWLXUTF+xNFmjQR6SIEUYr0ToiAkICEhJCE9LrZMu08vz/mzM7s\nZGZ3ZmfOnJnd5/16DTtz5pRnJ8t55ttFVTHGGGNyBfwOwBhjTG2yBGGMMSYvSxDGGGPysgRhjDEm\nL0sQxhhj8rIEYYwxJi9LEMYYY/KyBGGMMSYvSxDGGGPysgRhjDEmr5DfAZRj7NixOmPGDL/DMMaY\nuvLiiy9uUNVxA+1X1wlixowZLFiwwO8wjDGmrojI8mL2q8sqJhE5VkSu2rp1q9+hGGPMkFWXCUJV\n56vqWe3t7X6HYowxQ1ZdJghjjDHeswRhjDEmr7pMENYGYYwx3qvLBGFtEMYY4726TBDGGFOvOnri\nrNjU5XcYRbEEYYwxVfTxy57igz9/xO8wimIJwhhjquit9Z1+h1C0ukwQ1khtjKlXjQ6MSYrfYRSl\nLhOENVIbY+rVl7bG+XxHo99hFKUuE4QxxtSrsLT5HULRLEEYY4zJyxKEMcaYvCxBGGOMycsShDHG\nmLzqMkFYN1djjPFeXSYI6+ZqjDHeq8sEYYwxxnuWIIwxxuRlCcIYM+T1JHpYunWp32HUHUsQxpgh\n73+e/B+O/8vxdMXrY5rtWmEJwhgz5D2/5nkAosmoz5HUF0sQxpghb5e3Y5x7RxJNJv0Opa5YgjDG\nDHlfvqWD/d5UdMViv0OpK5YgjDHDiPp7+e4t/l6/RHWZIGwktTGmnqgqF133F/RnM/wOpSR1mSBs\nJLUxphTx8Ag2jH6Pb9fviSdpe66NJzrO8C2GwQj5HYAxxnjt37t8ic7WWezc4/hyfU2mqrZe7TrC\nl+sPVl2WIIwxphQ9jeMB0Arkh0XvbuPul1YN6tiE5KxF3bkBVrzQ7zGO45BM+pPYrARhjBnyem/L\nWn4j9UcvfQKA4/eaUvQxGusBIJRUNOtrefQXH6ZryTpG/XF1wWOv+8Il9ET25atXHDa4gMtgCcIY\nMwykEkMF8gOiWQmnWMl4+ug+m5feEgNGMqqfQ3si+5Z6tYqxKiZjzLBRiU6uX+lZzzlbmwDoiHXw\n6IpHK3DW2mQJwhgzfFSgCNEcnd77/DuPnM3XH/46q7cXriKqZ5YgjDHDRqWHyW1dsoYj3vg8XRvf\nqvCZa4O1QRhjho1t3fGBdyrB+948jRE9E+jaEIedCu+XINULSQN9b7nLdjqKt3c6mt0rGlXlWIIw\nxgwbsXgCAE0kQAQJBss6X7pEEnf674aqBaq2ls08tqzre82qmIwxw0DfG/Tre+zJspNOrthpt3T2\nXzJRv+eAGqSaSRAisruIXCEid4jIl/2Oxxgz9DhZ9+no66+Xf8KS+7vWF08ThIhcKyLrROTVnO1H\nicgbIrJERM4DUNXFqvol4BRgnpdxGWOGqUoMhMgSdJeXUKc+SwgD8boN4nrgt8Af0htEJAhcBnwE\nWAm8ICL3qOoiETkOOM89xpiaoNFONr7yAO8ueJCtby/B2bwNTcRpCIVoGdvOjD3n0fIfJyOT94bc\nqRRMbUgnhgrfx9u3Q6wBAus39btfoHYqa0riaYJQ1cdFZEbO5v2BJaq6FEBEbgGOBxap6j3APSLy\nV+BPXsZmTCFOPME/H7+HxQ8+TWxNmHB3OwHaiUcOROVgQAjHt9MQ3Uzb0uV03/88/PLPBPaMsNdZ\n5xI64NOWKGpWhTOEm3iG6j+3H72YpgArsl6vBN4vIocAJwINwH2FDhaRs4CzAKZPn15oN2OK4iQd\n1qzs4JknF7B+4auwtRlHJqPBkcBHkUiCWHALTqiHWHMAp3kkGmmCKLA9QWMsVRsajK1il7f+wctf\n+Slth1/N7AtvQ9om+vq7mR05lZitL4+BqpjqtZHajwSRL9eqqj4KPDrQwap6FXAVwLx58+rzUze+\nSMSTrFvRwaLXNvDG4ndIrNhAKNYOEgaEQHIXWjpXIvoCybZO2vbanfefdCKTJ4wseM7tm3t49smV\nvPp4kMWRzxCOHsrej/yB55ceyn6/uZ3AlD2q9wuagsS9QTvuN/4NY/YgEuuo2vXr9UblR4JYCUzL\nej0VeNeHOMwQ5ThKx8Zu1r+7nTff3MKKZZvZvnobkS5B3LrgYKKLkR2baNn+MhpcQWBcF9M+uB97\nnvRlQq1tRV+rZVQjhx87mw8fszPPP76Cp+9Qnpv3bXZ/41aePeNkDrj2DmSyJYma4SaIV/ZMdZR8\nf5UuK8W0Qax+BZ7+DZxwBQTKG59RKX4kiBeAOSIyE1gFfBI4rZQTiMixwLGzZ8/2IDxTD2I9CTo2\n9dCxsYf1a7tY9W4HG1Z30rWhG9meIKCZgmowvoVJ21bSun0FLdtXkIysIDA1zrQPHcSM479MaMou\nZccjIrz/Q9PZc+8JXHvJC7wun2bW0jaePes/+cAfH0JGFj81tPGQb72Niqjauv2zsGkpHHIejNnZ\n+5CK4GmCEJGbgUOAsSKyEvieql4jIl8D7geCwLWq+lop51XV+cD8efPmnVnpmE31qSqJuEOsO0G8\nJ0lPZ5zu7XE6tkTZvLmbLZt62L4tRndHjOj2OM72BIGE5pwjSSC5kZbuNYzeupbW7WsZ0bWGYGIt\nPaM7CU0byaRD92PakWcTnDkPAt70Kmlua+DLFx7Itb9awFKOY/aSBC+eczzzrnoWgjZxgd+86o5a\nr1VIA/G6F9OpBbbfRz8N0QMZCiUIzel2p5k3cl6Ts1+h43LOm3t89qkcRR3FcRR1UitWqUPWttyf\n+d9TR0kmlGTCIRl3iMeSRKNJYrHMIx5LEos5JGLJVBKIJon3JEhEkzgxB+IOJBTp5/+wJHEcOgkk\ntxFObKO5ZxOt2zcxeusmmns20RDdTEN0K50jHKKjlNDEFsa8f2em7XcsDfOOQMbMqmo3k2AwwBnn\n7MeVP3uGJZxIZNEWVvzmi0z75jVVi8HkV2jKC68FXr0d2K2kY5JOkoD42z22Lr/SlFuC+PNNi3j3\nmbV5TlzwggW293ORnPeGaC+4ghyUJEkccXBIoiSABKpRhG4CTjcBp4ug00Mo0UU40U1jTzcjenpo\n7eqirbODcGw7kXgHQSc1jYEjStcIiLc40B6kYdYI2qdNZuJuH6Fpz/0J7rQ3tE2uiT6HgYBw1rkf\n4P8ueJjFu30aueNiJhzxKJG5h/gd2vDmUS+mgf7iwg/+L3B7Tij9x3Ld524l1rQAOKas2MpRlwmi\nXG++/XeceLf7rTX7Tu72aSZ7e9+forn7Zo7XPMfmX+rQ3b5D4sk9Z2+xICuuPDHluYaou+yVZu+n\niCoBVUSTiDqZh5Mk0Ps6ScBJPQ84DoH0z6zn4aRDKOEQiSdSj0SchlickJMg4MRT52FgsbASj0Ay\nojiNCs1CaHyYSGsjze2ttI7elZbxU4jMmEN45lxkzAxomwKhSBFn91cwHODM7xzEdRc8wtJZZ6Ln\nn82hdzxvVU2+SJfMa6eKqevZZ/u8dhJKbEuIRvd1tGkifiYHGKYJ4gOr/8b4x1b6HUZe6T9gzbm7\n5r4utL3Pa0mfM/PaCaT2UQECqW/lCKi7PfXcTS7uPgioaOqLeYBUlgwJ0ihIKEAgFCAYDhAIBZFw\nkGC4hVA4TKghTDjSQKihica2diJtIwm0jSTQNprAyNEE2sciTe3Q0ArNo6F5DIQaBv3Z1aL20U0c\ndPpePHfNIrZtOoZ3fn820794qd9hDVseFSAGRROJPq9XPxpn27/HM+fLmwgNh0Zqr5TbBvHBs3+E\n/udL6ZO5P926vkD6Dpt5Len3evd1f/Y2dPZ93XuPDuQe595txd0mec6NlPC60Hvk2RcIhECCqZ+B\nYOqR/VqCme29++bZL/3TFGW//Sfz/OP/ZqUcQsMdlzDtk2uR9gl+hzUsqWcZov8yxFuR8A7blm1d\nRnaP/+2rU7Ft2LiVWhliWZcJotw2iMCsD8CsD1Q4KmMK+8JXD+aKs+9l9aRP88IPv8D+l8z3O6Th\nyaturgOc9pwREzkuZ1tnvKvva4EmYGu0u2YSRH3OIGVMnWloCrHnKXvS1TyBtYt2IrHiX36HNCz5\nNevqJdckB9xnu3s33hrf6nE0xavLBCEix4rIVVu31s4HacxADjt0Z6LN61g15Wge/8m3/A5nmHHb\n9nTgG/WgDKLjXDTZN1k5EqKzuXDZIRGv7HKpxajLBKGq81X1rPb2dr9DMaYkx3zlIySDETauPYjo\n0pf8DmfY8WkYRF7vbu3u+3rqJ3hu//8l3lU7t+XaicSYYWCX2WOIjV3DuvEH8shPvud3OMOOFjPl\nxaBOXHrmkZxiR2dLqtNNMpFvb39YgjCmyk77xgmgcbZsPZDYypJmmTGDlR5SNMDgtFpQqEu7k/So\neqwfdZkgrA3C1LMJ41tIjl/NxjH78tBFP/Q7nGHFs0bqAUbvbx6Vb5qNQsf4PxNAWl0mCGuDMPXu\n1G+egmiULev3J7Fltd/hDBuVnoupd9YDR1l4/3K2b+7Ju196evFsG1YVmFa+dvJDfSYIY+rduLEt\nJEctY/PovXnwpxf6Hc4wkLmRV/asqbt5tDPMM3e9xX2Xv1L0sRs35c8EUqAWLOlWj/3+E+fxq69+\nt7RAB8kShDE+OeHs/0KcKJuX74zGo36HMyw4XnVz7UqVHHpW5ZkEtICG5IjSruGWfqKjjqAh+ZHS\njh0kSxDG+GTqhHacpkVsGbkvT/76B36HMyxUeqaN3iqmzRsAcDpLWMZUMtVRXfGurCk4a6cvriUI\nY3x0yFdOQBWWvxiqrU76Q0z6Rl5OI3Vi82bWXvSzPtvSZ4u5E++VdvbM3su2LRt0XF6qywRhvZjM\nULHHrrMI8AodLQfy+vwb/Q5n6CujCLHu4p+z6YYbKhZKa1ffkdHJUGvqScFurtUfIFGXCcJ6MZmh\nZOeT9sIJRnjhz4v8DmXIc8oopeVOz51NBlEtFMlaNje6rgsn2OReqHa6MQ2YIETkABG5TEReEZH1\nIvKOiNwnIl8VEbtDG1OmI478MOHov+gKHsjGpa/7Hc4QlZ6LyasFg0q/qWcnldiba7O2145+E4SI\n/A34AnA/cBQwCZgLXAA0AneLSO4stsaYEjXvJSTCLTxwybV+hzK0+TSba375U0GhRmrHh9gHKkH8\nl6qeoar3qOq7qppQ1e2qulBVL1HVQ4CnqxCnMUPaJ7/2FcLRlXRt35NkPOZ3OEOWZwsGlVkyeX7Z\npgoFUln9JghV3ZB+LiITReQ4t4F4Yr59jDGDEwqGYMy/6Wmawn2/vMTvcIaevsu7V1ynpsaxDHaU\nxStvLq9cMBVUVCO1iHwBeB44ETgZeFZEPu9lYAPEY72YzJBzzLfOIhTvYMPiJr9DGXrS67N7NFmf\n5vwsRnYFUwOZgZKv3buGWx69sxJhla3YXkznAnur6umq+llgX+A73oXVP+vFZIaiyROnE+AFupr2\n4F8PPeR3OENSOSWIuLPjgj2ValAO09j7XBv3YuMto3bYp5a7ua4EsocIdgArKh+OMcPbzie8B1Fl\nwa3P+R3K0KLl1zG9vmnxjqct4rjn7lmaP6Ss9DInceBgw/JUqL83ReRs9+kq4DkRuZvUZ3I8qSon\nY0wFHXbMqbx968X0NOzF1vWbaB832u+QhpRyurkmYp2DOm7BfW8XeKeWOrTmN1AJotV9vAX8hUzC\nvBuwOYqN8UBkziacUBP3/vJqv0MZcsoaB5EnQVTzFu841a9i6rcEoao2g5gxVXbiuRdw65m30Rmb\njjqKBGr/m2btSyeGwTdSe7bY0CB1dXbTPMLbDg0DDZS7SkT2KPDeCBH5vIh8ypvQjBmemptaoflF\n4pEJPPiHO/wOZ0gpZxhEVCMs2+moisVSbtrfuHplReLoz0BVTL8DLhSRxSJyu4j8TkSuFZEnSA2Q\nawXsL9iYCtv/rJOIRLey/Mn1focypJRTw7St9XiWzTw2/5vS50dxsZR4/R3WpPZq0F+WgaqYXgJO\nEZEWYB6pqTa6gcWq+obn0RkzTL1n3od5MXouHW1H89ZrS9n5PbP8DmloKGeyPolUMBCoh7lSi4rQ\nnV7jUVW9WVX/YsnBGO+N+kAEcRI8euXdfocyZFR0sj6f1+9Qr1bHy1L7KSwPG0lthoOjv/w92rYs\nJNq9Cz1dOw7SMqWrfEOz9vOq/tVlgrCR1GY4CIUjMG4xGmziL7+92e9w6pp4MRmTKtXs6Op4NE1I\nf+oyQRgzXHz4nLNp2fY2W96M1Fw3y3pU2fUgdIdn1eyQXI2/hmIn69tFRK4WkQdE5OH0w+vgjBnu\nJs16H0GeIhkcz1MPLPQ7nLpX3g083y25nNRQZjRVKFEUW4K4HVhIaqGgc7MexhiPzTh2NyKxbbx2\ntyWIcpWz5OgON3TVHeZ4Sp/9rX+u44Hfv1rGtXakydqtYkqo6uWq+ryqvph+eBqZMQaAAz9xDq1b\nnyThzOTdd7b4HU59q2gTROEb9t+vfJU3F6yr3MXwZ6qNYhPEfBH5iohMEpHR6YenkRljAAgEAoTn\nrEFU+dsVd/kdTl0rrw0ip8dS1rnST71sg6jlRurPkqpSehp40X0s8CooY0xfR3zrp4zetJDohvHE\nuq3La+kq0Yup7+0/6TiUVyQpLZ0kEzWaIFR1Zp6HDe00pkpax05Hm55HA03ce9PjfodTtyrZiSmZ\niJNJPH1+FKfE4kY1BsblKrYXU1hE/ltE7nAfXxORsNfBGWMy3vuZ42jdtpw1L2yocHfN4aRyVUzJ\nRKK882lpGaKWq5guJ7XM6O/cx77uNmNMlbznI5+lofsxVMbxz+dsQcfBqGRidbKqfKrSBpHTi6ka\nCaPYBLGfqn5WVR92H58D9vMyMGPMjtrfHyQc28bzNz/qdyj1qZK9mMpYW2IwHCd3Nlfvr1lsgkiK\nyM7pFyIyC6h4hZiIfNwdkHe3iBxR6fMbU+8O+/qvGLv+SZI9k9mwZnBLYA5vlburJpPJzBQegzp7\nieWN3ARRBcUmiHOBR0TkURF5DHgYOKeYA931I9aJyKs5248SkTdEZImInAfgzhR7JnA68Imifwtj\nhonIiHaSE15DVJl/7T/8DqeOuLfuCn7pd5JZvckGU3VVcn6o0TYIVf0HMAf4b/exq6o+UuQ1rgf6\nLMMkIkHgMuBoYC5wqojMzdrlAvd9Y0yOA7/yDcZt+Cddy4PEeqo/eKqeVbQNIklWYpCs/3ojdxT4\nDlVOHhhoydHD3J8nAh8DZgM7Ax9ztw1IVR8HNuVs3h9YoqpLVTUG3AIcLykXA39TVZtXwJg8puxz\nFMITIE38Y/4iv8OpK5Wstnc0kZURBnPm0tKJJhPEEtX9QtDvinLAh0hVJ+VbZ0+BPw/yulOA7G4Y\nK4H3A18HDgfaRWS2ql6Re6CInAWcBTB9+vRBXt6Y+jbhiDl0PbGcpQ9vQk/eE5FqziNah3QwAxX6\nl8xeAtTLBmN1QAIkk8rj8+8Exnl4sb4GWnL0e+7TH6rqsuz3RGRmGdfN99esqnopcOkAMV0FXAUw\nb9486wxuhqUDz7iIjfd8kY7Wz/D6S+vZfe/xfodUF7SMO3nuTctJOplJ+qpwJ3I0CZ3d/URUecU2\nUt+ZZ9sdZVx3JTAt6/VU4N0yzmfMsBIMN8DuawnHOnj0pif8Dqd+lDOuLed1MlnmVBtFH5ou/Tis\nWfz2YE4waAO1QewmIieRqvI5MetxOtBYxnVfAOaIyEwRiQCfBO4p9mBbctQYOOSbP2fcuidxOtqt\ny2uxKjkOwnEo71t8ccGIu9vSl5azdeN/lHG90g1UgtgVOAYYSaodIv3YBzizmAuIyM3AM8CuIrJS\nRM5Q1QTwNeB+YDFwm6q+VmzQtuSoMTBy2p7ExywAlHtueNLvcGqbex8vpyooNxVoMkn6Jl+od9Tq\n7asHf8Ecq/5V/TbXgdog7gbuFpEDVPWZwVxAVU8tsP0+4L7BnNMYk7L/WV/g+UteYj1zifUkiDQO\n1O9kuEpniMqdsZhupsu2Levn3WJLHwWCrkLDR7FtEF8SkZHpFyIySkSu9SimAVkVkzEpMw76FBJ4\nDKSJe+98xe9w6kAFx0FkTfft7eSJhRJE7czF9F5V7V3KSlU3A3t7E9LArIrJmIydjnkPLR3vsPqJ\nJTbLa0Hu55LUin1G2ZPlFSwL9Hup2v+3KjZBBERkVPqFu5qclWWNqQHzPv1jRnQ8Bozlmafe8Tuc\n2lbJkdTZs6kWOm1n+cuOio9Jv9gEcQnwtIj8SER+SGpluZ97F1b/rIrJmIxAKEzrvp1Eolt48bZB\nNRUOA5m5mJwKVc1o1kC5QuMr9K4vVuRa+VRjbqZi52L6A3ASsBZYD5yoqjd6GdgA8VgVkzFZDv3G\npYxb+zCB2HjeWLTB73BqT9aAtkqto5BMKvVQTVSOYksQAKOBTlX9DbC+zJHUxpgKioycCDPfIBTv\n4qHrbUnSHWXWpFanUm0QA0+18fLb11XgSjVexSQi3wO+A3zX3RQG/uhVUEXEY1VMxuT40Dk/YcLa\nx2BrG6ve2eZ3ODXGLUE4QrJCs6D2WSO6YE/UcsYT93/yQLB2pto4ATgO6ARQ1XeBVq+CGohVMRmz\no1Gz9ic57nkCToK7f/+Y3+HUmKwqpmRlZkTtWxLxbjbXQo3UTrJ2xkHENNU3TAFEZIR3IRljBuug\nr3+LCWufQdc2sHF9l9/h1AzJaqSmQm0Q6mTPxTSIb/N1MANvsQniNhG5EhgpImcCDwFXexeWMWYw\nJu5zLNryOCDcca1Nv5GRLkEIzqDbIHIX7MkkmsH0RNUqzMZarmJ7Mf2S1Oytd5Kan+lCt7HaGFNj\n9j3zvxi/biGJpUk6tkb9DqdGZO7gg+/F1PeGnuouW846E+UliGo0XRfbSD0CeFhVzyVVcmgSkbCn\nkfUfjzVSG1PAjEM/TzDwEBDmtuuf8zuc2tC7YJCglWqkLrcNoOgqpgJjLGpoLqbHgQYRmUKqeulz\npNaa9oU1UhvTv7mfOpzx6/9Jz6JOurbF/A7Hf+l7sQOaNVBOSyhN5A6Gc5wy14MoaZSBP4qNUFS1\nCzgR+I2qngDM9S4sY0w5djvh2wSTfwPC3P6HBX6HUwOy2iCyRiBrLEoinuTmHz7Hu29uLu2UxUy1\n0W9EwdIPqrKiE4SIHAB8Cviru83mYjKmVokw+7QPMn79Qrb/ayvbt1lbRIr0KTUkEj1sXt3Fpnc7\neeK2N0s6UzED5foPpbwShFaou25/io3wG6QGyd2lqq+JyCzgEe/CMsaU673/+T2Cyb8DYW677nm/\nw/FZej0IIdXXNSXe3UVHdxyAjdu78xxXWHZvqMHkBy0zQVRDsb2YHlfV41T1Yvf1UlX9b29DK8wa\nqY0pQiDAbp85lPHrF9K9aDsdW3v8jsh/KjiJTIKI9nTz8rolAGzsGWD1t5w2Zc3qxSSDSBE6hNog\naoo1UhtTnLknXkDIuR8Ic8s1w7lHk/T+TGqmaiba3U2ocxUAIUqrsnGcrJEMg+ntWnQJIv9ZJeh9\nLX9dJghjTJFEmHv6EUxYt4DYGz1sGrajqzNVTJrVSB2N9iA9qZJVQ6zEUoBm92uS7KsUd7iU10hd\nS20Qxpg6tevx3ybEXxGFW68cnutFaHaCyLqtx3t6CG1KTWzY1lnaOctdj6HoNohaXzBIRH4uIm0i\nEhaRf4jIBhH5tNfBGWMqQIQ9vngKk999HGeFsuLtLQMfM+Rkqpiyb+yxaLSEb/05N+oyR1IPmUZq\n4AhV3QYcA6wEdgHO9SwqY0xFzT7ya2jrIwSTUe66YjjO0ZQuQQT6jF9IRHsGP2lenhHZpbVBDJ1x\nEOlpNT4K3KyqmzyKxxjjBREOOve7TFn5AMEtzbzyz7V+R+QT6TNFRTwWKyE/5Iykzh5wp6W3QRQr\nGW7Jv72GpvueLyKvA/OAf4jIOMC3PnPWzdWY0o3f51iYvpCG6GYeuf6ZqszlUzuyqpiyvvkn4vGs\nb/ID3d5zPq8+JYih+VkWOw7iPOAAYJ6qxkktHHS8l4ENEI91czVmEA674DImrbqXULSNh+57y+9w\nqihTxZQ9wC0RjTHYm7s6yazxD6nz18MU3qUotpH6P4GEqiZF5AJSy41O9jQyY0zFjZj+XiL7rKZt\n29u8Pv91ou4o4qEvU4Lo0wYRSyC9jcUD3NxzB8o5SdKjsjX7/ENIsVVM/6uqHSJyMHAkcANwuXdh\nGWO8cuj5NzJyw20EaOZPV7/gdzjV0dvQEOyzVGgyEe1NEAOXI3Jnc80kiMxb1UsQDpVZGa8/xSaI\ndGXbx4DLVfVuIOJNSMYYL4VaxzHttLlMWv0MXa9tZ8Xy4dSWF3K7p6Y4sQTIIKuYktkJwr2VVrEA\nUY1LFZsgVrlLjp4C3CciDSUca4ypMXt95pcEw38lmIxz52+fGAYN1unbVbDPinKJWBSRYquH+n5G\nyXhWgnCqX8UkVbgFF3uFU4D7gaNUdQswGhsHYUz9CgQ48Pz/YeqKvxLuaObRB5f5HVFVKKE+bRDJ\naHzQ4yCcRBzpreZJV1NV73uzo5VZGa8/xfZi6gLeAo4Uka8B41X1AU8jM8Z4atzexxCe+watHct5\n9c+L6eoYuivPZRqRgzhZpaV33twXKfpbf98SRCKeRCW3BFE9TrJGEoSIfAO4CRjvPv4oIl/3MjBj\njPc+/IObGb3hJoJOhBsu9XaE9brl21i3fJun1ygsfQMP4TiZSe5UgxAo7uaeO6W3k0juUIIY9Kjs\nQYj3eD8Urdjy0BnA+1X1QlW9EPgAcKZ3YfXPBsoZUxmhtvHM+dKhTF35IM4KWPDsu55d6/aLFnD7\nRT4tf+reuFVCfXoxpd6SPvsUK5lIkpmLqfptEIke71cJLHrJUTI9mXCf+9bh1wbKGVM5u55wPjLl\nKZq71vL0DQuIdg3FsRHpJLDjGgqB3hJEae0HmnAyVUxa/TaIeLx2ShDXAc+JyPdF5PvAs8A1nkVl\njKmqI392M+PX3ETQaea6Xz/U+tJIAAAcAklEQVTldzgeSI90DvVdSxoIugvvDDgKOudtJ6GQThAE\n8+7jpUTU+0RebCP1r4DPAZuAzcDnVPX/eRmYMaZ6ImOmM+tzezNtxYMklzs89dhyz66VW8VTTfmq\nmIIht1Qx4PTbuZP1ZSeaIkdjV1Ai5n2nggHXrJPUMMNXVHUPYKHnERljfLH7J3/IW48dTEvH7iy8\nuZu5e45n1Oimil8n2h2ncUR1x9mmq340EHTXks5KBlJc9VBuWlNHs9otqp8gkvEaWFFOU5/myyIy\n3fNojDH+EeGon9/F6E3XE0wGueGihz35tt+zxb9lT1XCkPs79bYvl9Z+0HcyVzfJVLEX08bX3vb8\nGsV+IpOA19zV5O5JP7wMzBhTfaG28ez7v2ex0/I/E+5o4pbrK19psHW1D8vJZPViSjo537yLnEcp\nt5tr30RT7JThlRPdMsLzawxYxeT6gadRGGNqxuQDT2PJIXcxfsEC1j23Dwv3WM0++0+q2Pk3rVrD\nTvNmVex8xXETRCBILNEFNPS+kx44V+oSoJrUrORS/QQh6v21+v1ERGS2iBykqo9lP0h9LCs9j84Y\n44v/OO8WIi130ty1lqeuXcj6tZ0VO/em1d6NtSgsczON9+RUcanusE9+fUsQ2mcy1epXMVVj7YmB\nUub/AzrybO9y3zPGDEWBIB+99C7GbLyacEL4408fIh6rTKNox4bqVzFl37ij27b3ee+lv41y9xng\ndph7P85qg1CJFNjJO8VPETJ4AyWIGar6Su5GVV0AzPAkImNMTQiPnMxBF53HtOV/JBJt5aqfPlLW\nrK/BRDcA3R1+NFIL4qTGDfRsKTTdR2m9mFDNfIv3IUFUY0Ltga7Q2M97le//ZoypKWPedxSzvjCH\n6cvvgTVBbrzi+UGfK+DeoONdfkwKKASTqZHHPR3defcouXoomdlfpaGfHT2i/ieIF0RkhzmXROQM\n4EVvQjLG1JLdP/EDRh66hglrnqXj5U7m3714UOdJ34CTPuQHRQg4qbmLYl355zAauIoppw0imdnf\nCUTccwytEsRAvZi+CdwlIp8ikxDmkVpN7oRKBiIis4DzgXZVPbmS5zbGlOeD597M/Wd/mOi7o3nn\nvgRPjWnhoIOnlXSOdHWMkyi282QFiSBOqgQR7y7QliLB/NvTb+ducDK/hxNIlyCqNxfT6Pf3V8FT\nGf3+Nqq6VlUPJNXN9W338QNVPUBV1wx0chG5VkTWicirOduPEpE3RGSJiJznXmupqp4x2F/EGOMh\nEY785QO0Nv6Rls41vHTja7y0cMBbQM45UjdgdfxYrVgQTSUIp1KToDohMt1nw6mfVSxBfPwrX/P8\nGsXOxfSIqv7GfTxcwvmvB47K3iAiQeAy4GhgLnCqiMwt4ZzGGD8EQxxzxX20Ja6gqXszT165kNcW\nbSj68HQVjiMjvYqw32v3JojEYG/iOc3UGi4vqDrgaXlIVR8nNcFftv2BJW6JIQbcAhzvZRzGmMoI\nNLVx3DXzGd31OxqjXTzy62d4c8nmIo9O3ZgTofEkk84A+1aaIJJq/NBEqiQTDj1d9NFLPnw4o9bn\nNp7kKQm5SXDE9lWDirLWVK/CLGMKsCLr9UpgioiMEZErgL1F5LuFDhaRs0RkgYgsWL9+vdexGmNy\nBEeM4Zhrbmfs1t8SiSf5+y8eZ9nyLQMepxKkoWczGgix6KW3vQ+0z7UF3ARBMtV2EIoUv2RnfNUq\nItGcpKbhgp1ag87QWL7VjwSR7zNVVd2oql9S1Z1V9aJCB6vqVao6T1XnjRs3zsMwjTGFhNon8rFr\nb2L8xt8SSQS496JHeGdl4eVE1XFQEULxZQC8NL96S9r3jt0Qd/0EJ1U1FAwWN/BPVdnaNpNEKKdn\nv0QoOO6hjPEitcSPBLESyO7+MBUoaey9LTlqjP/Co6bw0WuvZcL6ywgnIvzlxw+yas32vPvGuntA\nAjiNG2jo2UT3yupVMSkKBNBgEnESoIUbyTs7diwJdcW7eHGfb7Fy6iE55y18nmSw2lVo3vAjQbwA\nzBGRmSISAT4JlDQzrC05akxtiIyZztG/v5yJay8nnGzmju/fx9r1O87b1BNzuw4Fg0Si/yQRmM36\nNflm8am8ZDLhVjFBMBkle6K+XK88+vcdtvVdGChDA407jq5OXzNoJYgBicjNwDPAriKyUkTOUNUE\n8DXgfmAxcJuqvuZlHMYY7zSMn8lRv/81k9ZeSdhp55YL57N+Y9/Ryj3dqek1JADNM5ajEuDOX95a\nlfg0mUxdWCDg9KDuBBGSp0vq0ude3WFbvv0AksH+ptu2BDEgVT1VVSepalhVp6rqNe72+1R1F7e9\n4SelnteqmIypLY0TdubIK3/BpNW/J5wczU3/excbt/T0vt/T7ZYqRDnm7B8wctNTJDt24rkn/+15\nbMn00O10ghB3gFmeG3/Pyjyli0T+m30i1EwgKQSSfQdWJJPJ3Kle65YfVUxlsyomY2pP06Q5HHXF\nj5m0+nrCyfHceP7txBOpG2W0K1OCaBy3MxMOWE5jzyYW3rCIf/97nadxJRPpxmhFNIoG3BIEcNJ3\n9u27b2APtmxY3WebFioNSAC0qXeOp7Rli14GvF8OtBrqMkEYY2pT05RdOfLyC5i0+k+Ek1O4+sc3\nARBLr8Hgfms//JtX0zLiBoJJ4aFfPMszT77lWUyayNysRaM4gfQUFcLEme2EY6lxHI09LxKPtHPv\nxf/X9/h+eiQpO1YzLXnhxUyPqTpXlwnCqpiMqV3NU+fywZ9/nlEbF6LvTmDhy28Ti6a+ZffOhxcI\ncsqvbmVkw+9oiPWw8MalXH3xvSTixY9NKFYikapiElGgh2TQ7a7qxhJwUtVfwbFbiETX0LN+bzat\nz6yHlq+ROj11uAZGANqnmmn9mysASxC+sSomY2rbuN0OZvx+Kwiow7NX3E08mmq0lkCm3l8aWznl\nN/cwdZdbGbXpZWLLmrnyq7fx5ONLKhpLPO7erAWEWG+W6m2C0FTpJhQUwtPeJto4gfkXXJo5QZ4S\nRDCZSiqJUEvq2ESmR1ZsnSBS2TaINrmroucrVl0mCGNM7TvsnF/Rtu0pSO7OujXuILpATsNwqIEj\nz7+Tg7/ayqgtV9EQi/Dyn97hN1+9ntdeW1uROBKJdIJQCGRGOPf2ThK3x1Uiycnf/RYNPa/TnfwQ\nrzw6H8jfBhFwUuM9EuHWPq8BiI+v+HKgLXP6zpwbjhUelFhJliCMMZ4IBIO0z+1GAyFWPrU0ta3A\nHWf6IV/ktD9cw6w972T0hr8Rjk3g0Uv/xWXfuJ63lpW3RKmTSCcFQQJZVT+9CSK1zYk7tDRFGPOR\nCTiBMAt//xqO4+QtQfRJCIBo6nUwvp1EuLRp0IuSs1ZFQ/vgF24qRV0mCGuDMKY+HP7f36GhZyPB\n7qmpDcF+1lyIjOCwc/7EyVd/nakTr2L0xkcIdE/i7xct4LJzrmfVu4P71pxIr6UtQDCrPSF99xN3\nm/vj46edSJhn6GzZn/kX/zB/G4TGs9odFMStpkpuIhFuAcfjGWurNMyiLhOEtUEYUx8aR40jHH+L\neEPqW3UgOHDVS3jUdI750V2c9LvPMHHUZYza9AzSMYW7v/80v/vOH1iXZ6R2f5Jx90YuEAhn2gYy\nA+BSCSA9dEFEOOjbnycU28SGxTvTsXnHbrgKBJKZUkQwEHUvsRGAeGR6/0ENYpzElv3uIxirTLVb\nseoyQRhj6oc0Z6qIpFAdUx6R8btywsX3cMJvTmJCy28ZuXkhumUyd5z/GFec/0c2b+4Z+CRAMpHV\n7hDJSlBugkg3KGvWGtNzZ08jMOXf9DRP4bGLb9rxd0IJaCZRjZuTmpdpwsytiJMgmTuxX+7xg5jM\n7/wzfkk4+XbJx5XDEoQxxlOtkzM3y0Co/2U982matAcn/epujv/V0Yxr+A3tWxaR3DiZW779AL+/\n9K9EB+gam0j3YgoIoYbMLa+3R1UgXYLoG9tpF5xLQ88iOoMfznNWBTIliKPOO4/3fTLCxy78AZHY\nwHOParlt2FbFVJi1QRhTP2bNe1/v80Bw8OtRj5i2N6dcejfHXnwQo4OX0ty1juiiJq7+6vW89lbh\nle2SUXccBBBuzkylkU4QGnDvtjl37RENYUbu0dm7nOgO3HYHgEBAOPiQgxERRFbn37/vwUXsk5GZ\nsrykw8pWlwnC2iCMqR+7fTDzDTwQLv+W0zbzAE697C8c/IUkbVtuJ6hTeOKiR7nnr6/k3d/p7eYq\nNLQ1Z70jWf8l77fyo776DcLRAivmhdzBfznVRYFIEW0kUh+33vqI0hhTtxpGZr7IBSOVW8d550O/\nyGnXXcTIxqsIJWDVX1Zw8x07dv9MJlINyBoQRozM9C6SdIN5oHB9TUtTI6Fk/mlAAhF3NLX0/Z1C\nrSX9GkVJN6hLlWeJtQRhjKmapobGgXcqQbBpJKdeeicTd7mHSKyTLfev44En+s4QG3ermAgIrWNG\nZ97oHQfhvi7QMCCRfCUIJeiuF5QI9f2dmsa1lPhbDCx3PqhqpQlLEMYYz4mTGoswotmTr9cc890b\nGDPzbgIOLL3+OVZvzrQPxKNuF9SAMGbKlMxhvaO607fbAgmiJd/tWJHGVKN2bhtF67hRBUNt27jj\ngkT5NHetKfBOur2kOimiLhOENVIbU1/CiVSPn7GTZ3pzARE+fuGNNHELyfAUbv3xDb1vxeOpEkQg\nKIydOi3rkEDvsUDBEkRkRP5qsVBj/u2jJ08uGGZ0XHHjH1rfsyLv9movQ1SXCcIaqY2pL9PaUwli\n/GyPEgRAIMDHf3IBrVtfoWHbTry4OPUtPBlNtRVIQBgxdkKf/VNvpDfkTxDBETuOaRBVQs35ly4d\nP3PngiGGcueiKiA182yGOqnXzXNSsUzaf8+izlOuwfc5M8aYIh3yvROZ88JSRu880dPrtE3cjdZd\nf0HHmvfy1BW3su+vv9E71UYgJARCmVte70DqAt1c0yLNO7abiAqNLfnbUyZMnwEUqCISYey651nb\n/k+CDV8s/IsU6OV06vlnE+tJEGmszq27LksQxpj60jiyhZ0/8t6qXOuos39Ky7ZFRLZPZcO2HhLu\ngkGSMw9UelR3ZsqNAgmiMZJna4im9vyN0Y1NzXm3p6/Q/JM5nHjpJf3+DrmroWZPk16t5ACWIIwx\nQ0xT2wQCba+SDI/i3jse6R1JnTuKOxBM3f6SkdT2RKhAFVOerrlKmJaRg5iQT+HY3U9iauvU/vfL\nrYryaYlrSxDGmCHnPR/bk4ATp+f5f5GMp+6uwdyZZNMjqWfsBkDHxPzVX6HIjiUIlRCt7YV7KxVS\nbOcjySlCFFwX22OWIIwxQ87eH/0STZ1LCEQnEk+3QURSVTOiqbmX0r2YDj36SAD2PebovOcK5qti\nkjCNbYMrQQzk2bbXkWrPqVFAXSYI6+ZqjOmPBINIcDnxyGS2u3PqRcKpBBFwx2SkezHNmTWKr15x\nGB86IH+1z/jJs3aYnlslTMvI0ksQxczSd9F3T4cipkWvhrpMENbN1RgzkOYpPSABkhtGABBySwIB\nx22TKHLq8clzduewx77eZ5tKmKZWb+4/U0c188FTT6N1ywLCsY6BD/BQXSYIY4wZyC4f2jv1JDEJ\ngHBzKlGImyBC/a1ul2XUuJGMemZBn20qQUY0F+6tlK2xK2vqjyKbEsaMm8hnbvk2wWR1FwjKZQnC\nGDMk7frBj9PQs4lEJDWyuaEtNc1Hug0i2FD8xIETR43o81olRKjItS0CkXcG3Kdxy30D7GGN1MYY\nUzGNI0YRimcW7xnR7k7U5yaISGP/q771RyW0Q0+jbJFYZv3sPjOwZj3tDtza+/z/HX3/QBcsOcZK\nsARhjBmyJJipomkZPT61zR1UEIgMPkE4gf5LD7vMvpvmzuXpKHq3a9aN/oyLzu99flJrgakzqjQp\nXyGWIIwxQ1akPbN4z+gxbq8jt0eSOv0vVdoflf5HM3/of67DCcR2fCPrfj+qfTrT/30B+7/wE75/\n4p8KXMd9IqUv1VoJliCMMUPW+F3H9j4fNTrVBtE4YSUAs9+7z6DPqwOUINy9AEiOzpMoXD/+1BbO\n+krhhui2jzXjOOs44LOnlRpiRdhkfcaYIWv3w4/k9VdTXUUDDalurqde9G22buli1NjS1qaY0Hw3\nHR270RXctbgD3Oqh1pGjkQ0P0h35yA5tCfevWk2P25axaEoHgU19lys95ZT/glNKCrOiLEEYY4as\nibvsy5RVPySY7EHkMCA1J1OpyQHg5F/+H04iyuX//QzhxIYB9w+4bR0hDaCh/FODjzzlJtiS6uV0\nyXnHEI37NOlSAXWZIETkWODY2bNn+x2KMaaGBQIB9tgvTrixrRInIxBpYu6BG5m53/sG3H3iznGW\nroa9PnI4j/z+3tTG3N5Iu32092ljOEhj2J+2hkLqMkGo6nxg/rx58870OxZjTG2bfeFPKnq+Qz/z\nn0Xtd/T3vgnJBARDPHLNvRWNoVqskdoYY7wSdL+D5y5/XSfqsgRhjDG1YATLi7znp/eqjUn4imUJ\nwhhjBun0Kz5X5J7a50e9sComY4zx2gDLmtYqSxDGGOM1qbOig8sShDHGVItPk+4NliUIY4zxWGbi\nV0sQxhhj8lBLEMYYY/qyNghjjDF5pKuYpM5KEDUzDkJERgC/A2LAo6p6k88hGWNMZbh5Qa2ROkNE\nrhWRdSLyas72o0TkDRFZIiLnuZtPBO5Q1TOB47yMyxhjqkndIoTUWVWT11VM1wNHZW8QkSBwGXA0\nMBc4VUTmAlOBFe5ug1/qyRhjakzHnJWMW/8SK2Y+5XcoJfE0Qajq48CmnM37A0tUdamqxoBbgOOB\nlaSShOdxGWNMNe00aTI/Ou46pk1u9juUkvhxI55CpqQAqcQwBfgzcJKIXA7ML3SwiJwlIgtEZMH6\n9eu9jdQYYyrguKO+ycPrAvzX8T/3O5SS+NFIna+VRlW1Exhw5itVvQq4CmDevHn1VaFnjBmWAi1j\nGXfuy36HUTI/ShArgWlZr6cC75ZyAhE5VkSu2rp1a0UDM8YYk+FHgngBmCMiM0UkAnwSuKeUE6jq\nfFU9q7293ZMAjTHGeN/N9WbgGWBXEVkpImeoagL4GnA/sBi4TVVf8zIOY4wxpfO0DUJVTy2w/T7g\nvsGeV0SOBY6dPXv2YE9hjDFmAHXZndSqmIwxxnt1mSCMMcZ4ry4ThPViMsYY79VlgrAqJmOM8Z6o\n1u9YMxFZDyx3X7YDW/t5nvtzLLChhMtln7PY93O3+RljqfHliyvfNj9jtH/n8uPLF1e+bfbvXFsx\nlhvfSFUdN2AEqjokHsBV/T3P83PBYM9f7Pu52/yMsdT48sVTazHav7P9O9u/8+DjK+ZRl1VMBcwf\n4Hnuz3LOX+z7udv8jLHU+ArFU0sx2r9zce/Zv3NxMQz0fi3FWIn4BlTXVUzlEJEFqjrP7zj6YzGW\nr9bjA4uxEmo9PqiPGHMNpRJEqa7yO4AiWIzlq/X4wGKshFqPD+ojxj6GbQnCGGNM/4ZzCcIYY0w/\nLEEYY4zJyxKEMcaYvCxB5CEih4jIEyJyhYgc4nc8hYjICBF5UUSO8TuWXCKyu/v53SEiX/Y7nnxE\n5OMicrWI3C0iR/gdTz4iMktErhGRO/yOJc39u7vB/ew+5Xc8+dTi55arHv7+hlyCEJFrRWSdiLya\ns/0oEXlDRJaIyHkDnEaB7UAjqRXwajFGgO8At9VifKq6WFW/BJwCVLxrX4Vi/IuqngmcDnyiRmNc\nqqpnVDq2XCXGeiJwh/vZHed1bIOJsVqfW5kxevr3VxGljOyrhwfwH8A+wKtZ24LAW8AsIAK8DMwF\n9gTuzXmMBwLucROAm2o0xsNJrcZ3OnBMrcXnHnMc8DRwWi1+hlnHXQLsU+Mx3lFD/998F9jL3edP\nXsY12Bir9blVKEZP/v4q8fB0wSA/qOrjIjIjZ/P+wBJVXQogIrcAx6vqRUB/1TObgYZajFFEDgVG\nkPoftltE7lNVp1bic89zD3CPiPwV+FMlYqtkjCIiwM+Av6nqwkrGV6kYq6WUWEmVqqcCL1HFWogS\nY1xUrbiylRKjiCzGw7+/ShhyVUwFTAFWZL1e6W7LS0ROFJErgRuB33ocW1pJMarq+ar6TVI33qsr\nlRwqFZ/bjnOp+zkOevXAEpUUI/B1UiWxk0XkS14GlqXUz3GMiFwB7C0i3/U6uByFYv0zcJKIXM7g\np5GolLwx+vy55Sr0Ofrx91eSIVeCKEDybCs4QlBV/0zqf4JqKinG3h1Ur698KHmV+hk+CjzqVTAF\nlBrjpcCl3oWTV6kxbgT8unnkjVVVO4HPVTuYAgrF6OfnlqtQjH78/ZVkuJQgVgLTsl5PBd71KZZC\naj3GWo8PLMZKq4dYLUYPDZcE8QIwR0RmikiEVOPuPT7HlKvWY6z1+MBirLR6iNVi9JLfreSVfgA3\nA6uBOKnMfYa7/aPAv0n1JjjfYqzf+CzG4RmrxVj9h03WZ4wxJq/hUsVkjDGmRJYgjDHG5GUJwhhj\nTF6WIIwxxuRlCcIYY0xeliCMMcbkZQnCDAsikhSRl7IexUynXhWSWjNjVj/vf19ELsrZtpc72Rsi\n8pCIjPI6TjP8WIIww0W3qu6V9fhZuScUkbLnMhOR9wBBdWf6LOBmdlwv4JNkZsi9EfhKubEYk8sS\nhBnWRORtEfmBiCwUkX+JyG7u9hHu4i8viMg/ReR4d/vpInK7iMwHHhCRgIj8TkReE5F7ReQ+ETlZ\nRD4sIndlXecjIpJvAshPAXdn7XeEiDzjxnO7iLSo6hvAFhF5f9ZxpwC3uM/vAU6t7CdjjCUIM3w0\n5VQxZX8j36Cq+wCXA99yt50PPKyq+wGHAr8QkRHuewcAn1XVw0itrjaD1II/X3DfA3gY2F1Exrmv\nPwdclyeug4AXAURkLHABcLgbzwLgbHe/m0mVGhCRDwAbVfVNAFXdDDSIyJhBfC7GFDRcpvs2pltV\n9yrwXvqb/YukbvgARwDHiUg6YTQC093nD6rqJvf5wcDtmlqPY42IPAKpuZxF5Ebg0yJyHanE8Zk8\n154ErHeff4DUAlBPpdYyIgI84753C/C0iJxDKlHcnHOedcBkYGOB39GYklmCMAai7s8kmf8nBDjJ\nrd7p5VbzdGZv6ue815FaUKeHVBJJ5Nmnm1TySZ/rQVXdobpIVVeIyNvAh4CTyJRU0hrdcxlTMVbF\nZEx+9wNfd5clRUT2LrDfk6RWVwuIyATgkPQbqvouqXn/LwCuL3D8YmC2+/xZ4CARme1es1lEdsna\n92bg/4C3VHVleqMb40Tg7RJ+P2MGZAnCDBe5bRAD9WL6ERAGXhGRV93X+dxJalrnV4ErgeeArVnv\n3wSsUNVCayT/FTepqOp64HTgZhF5hVTC2C1r39uB95BpnE7bF3i2QAnFmEGz6b6NKZPb02i720j8\nPHCQqq5x3/st8E9VvabAsU3AI+4xyUFe/9fAPar6j8H9BsbkZ20QxpTvXhEZSapR+UdZyeFFUu0V\n5xQ6UFW7ReR7pBaxf2eQ13/VkoPxgpUgjDHG5GVtEMYYY/KyBGGMMSYvSxDGGGPysgRhjDEmL0sQ\nxhhj8rIEYYwxJq//Dwyootmn+nKAAAAAAElFTkSuQmCC\n", "text/plain": [ - "" + "" ] }, "metadata": {}, diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index 9a8163f3b2..2de619c008 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -75,7 +75,8 @@ class ResonanceCovariances(Resonances): ev : openmc.data.endf.Evaluation ENDF evaluation resonances : openmc.data.Resonance object - Resonanance object generated from the same evaluation + openmc.data.Resonanance object generated from the same evaluation used + to import values not contained in File 32 Returns ------- @@ -214,7 +215,7 @@ class ResonanceCovarianceRange: Returns ------- samples : list of openmc.data.ResonanceCovarianceRange objects - List of samples size [n_samples] + List of samples size `n_samples` """ if not use_subset: @@ -412,12 +413,12 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): String descriptor of formalism """ - def __init__(self, energy_min, energy_max): + def __init__(self, energy_min, energy_max, parameters, covariance, mpar, lcomp): super().__init__(energy_min, energy_max) - self.parameters = None - self.covariance = None - self.mpar = None - self.lcomp = None + self.parameters = parameters + self.covariance = covariance + self.mpar = mpar + self.lcomp = lcomp self.formalism = 'mlbw' @classmethod @@ -454,11 +455,11 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): # Other scatter radius parameters items = endf.get_cont_record(file_obj) target_spin = items[0] - LCOMP = items[3] # Flag for compatibility 0, 1, 2 - 2 is compact form - NLS = items[4] # number of l-values + lcomp = items[3] # Flag for compatibility 0, 1, 2 - 2 is compact form + nls = items[4] # number of l-values # Build covariance matrix for General Resolved Resonance Formats - if LCOMP == 1: + if lcomp == 1: items = endf.get_cont_record(file_obj) num_short_range = items[4] # Number of short range type resonance # covariances @@ -501,16 +502,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): # Add parameters from File 2 parameters = _add_file2_contributions(parameters, file2params) - # Create instance of class - mlbw = cls(energy_min, energy_max) - mlbw.parameters = parameters - mlbw.covariance = cov - mlbw.mpar = mpar - mlbw.lcomp = LCOMP - - return mlbw - - elif LCOMP == 2: # Compact format - Resonances and individual + elif lcomp == 2: # Compact format - Resonances and individual # uncertainties followed by compact correlations items, values = endf.get_list_record(file_obj) mean = items @@ -523,7 +515,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): gf = values[5::12] par_unc = [] for i in range(num_res): - res_unc = values[i*12+6:i*12+12] + res_unc = values[i*12+6 : i*12+12] # Delete 0 values (not provided, no fission width) # DAJ/DGT always zero, DGF sometimes none zero [1, 2, 5] res_unc_nonzero = [] @@ -556,37 +548,21 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): # Add parameters from File 2 parameters = _add_file2_contributions(parameters, file2params) - # Create instance of MultiLevelBreitWignerCovariance - mlbw = cls(energy_min, energy_max) - mlbw.parameters = parameters - mlbw.covariance = cov - mlbw.mpar = mpar - mlbw.lcomp = LCOMP - - return mlbw - - elif LCOMP == 0 : + elif lcomp == 0 : cov = np.zeros([4, 4]) records = [] cov_index = 0 - for i in range(NLS): + for i in range(nls): items, values = endf.get_list_record(file_obj) num_res = items[5] for j in range(num_res): one_res = values[18*j:18*(j+1)] res_values = one_res[:6] cov_values = one_res[6:] - - energy = res_values[0] - spin = res_values[1] - gt = res_values[2] - gn = res_values[3] - gg = res_values[4] - gf = res_values[5] - records.append([energy, spin, gt, gn, gg, gf]) + records.append(list(res_values)) # Populate the coviariance matrix for this resonance - # There are no covariances between resonances in LCOMP=0 + # There are no covariances between resonances in lcomp=0 cov[cov_index, cov_index] = cov_values[0] cov[cov_index+1, cov_index+1 : cov_index+2] = cov_values[1:2] cov[cov_index+1, cov_index+3] = cov_values[4] @@ -615,14 +591,9 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): # Add parameters from File 2 parameters = _add_file2_contributions(parameters, file2params) - # Create instance of class - mlbw = cls(energy_min, energy_max) - mlbw.parameters = parameters - mlbw.covariance = cov - mlbw.mpar = mpar - mlbw.lcomp = LCOMP - - return mlbw + # Create instance of class + mlbw = cls(energy_min, energy_max, parameters, cov, mpar, lcomp) + return mlbw class SingleLevelBreitWignerCovariance(MultiLevelBreitWignerCovariance): @@ -655,8 +626,8 @@ class SingleLevelBreitWignerCovariance(MultiLevelBreitWignerCovariance): String descriptor of formalism """ - def __init__(self, energy_min, energy_max): - super().__init__(energy_min, energy_max) + def __init__(self, energy_min, energy_max, parameters, covariance, mpar, lcomp): + super().__init__(energy_min, energy_max, parameters, covariance, mpar, lcomp) self.formalism = 'slbw' @@ -691,10 +662,12 @@ class ReichMooreCovariance(ResonanceCovarianceRange): String descriptor of formalism """ - def __init__(self, energy_min, energy_max): + def __init__(self, energy_min, energy_max, parameters, covariance, mpar, lcomp): super().__init__(energy_min, energy_max) - self.parameters = None - self.covariance = None + self.parameters = parameters + self.covariance = covariance + self.mpar = mpar + self.lcomp = lcomp self.formalism = 'rm' @classmethod @@ -712,7 +685,9 @@ class ReichMooreCovariance(ResonanceCovarianceRange): items : list Items from the CONT record at the start of the resonance range subsection - resonances : Resonance object + resonances : openmc.data.Resonance object + openmc.data.Resonanance object generated from the same evaluation used + to import values not contained in File 32 Returns ------- @@ -729,12 +704,12 @@ class ReichMooreCovariance(ResonanceCovarianceRange): # Other scatter radius parameters items = endf.get_cont_record(file_obj) target_spin = items[0] - LCOMP = items[3] # Flag for compatibility 0, 1, 2 - 2 is compact form - NLS = items[4] # Number of l-values + lcomp = items[3] # Flag for compatibility 0, 1, 2 - 2 is compact form + nls = items[4] # Number of l-values # Build covariance matrix for General Resolved Resonance Formats - if LCOMP == 1: + if lcomp == 1: items = endf.get_cont_record(file_obj) num_short_range = items[4] # Number of short range type resonance # covariances @@ -777,16 +752,7 @@ class ReichMooreCovariance(ResonanceCovarianceRange): # Add parameters from File 2 parameters = _add_file2_contributions(parameters, file2params) - # Create instance of ReichMooreCovariance - rmc = cls(energy_min, energy_max) - rmc.parameters = parameters - rmc.covariance = cov - rmc.mpar = mpar - rmc.lcomp = LCOMP - - return rmc - - elif LCOMP == 2: # Compact format - Resonances and individual + elif lcomp == 2: # Compact format - Resonances and individual # uncertainties followed by compact correlations items, values = endf.get_list_record(file_obj) num_res = items[5] @@ -798,7 +764,7 @@ class ReichMooreCovariance(ResonanceCovarianceRange): gfb = values[5::12] par_unc = [] for i in range(num_res): - res_unc = values[i*12+6:i*12+12] + res_unc = values[i*12+6 : i*12+12] # Delete 0 values (not provided in evaluation) res_unc = [x for x in res_unc if x != 0.0] par_unc.extend(res_unc) @@ -825,21 +791,17 @@ class ReichMooreCovariance(ResonanceCovarianceRange): # Add parameters from File 2 parameters = _add_file2_contributions(parameters, file2params) - # Create instance of ReichMooreCovariance - rmc = cls(energy_min, energy_max) - rmc.parameters = parameters - rmc.covariance = cov - rmc.mpar = mpar - rmc.lcomp = LCOMP - - return rmc + # Create instance of ReichMooreCovariance + rmc = cls(energy_min, energy_max, parameters, cov, mpar, lcomp) + return rmc _FORMALISMS = { - 0: ResonanceCovarianceRange, - 1: SingleLevelBreitWignerCovariance, - 2: MultiLevelBreitWignerCovariance, - 3: ReichMooreCovariance - # 7: RMatrixLimitedCovariance - } + 0: ResonanceCovarianceRange, + 1: SingleLevelBreitWignerCovariance, + 2: MultiLevelBreitWignerCovariance, + 3: ReichMooreCovariance + # 7: RMatrixLimitedCovariance +} + From 81a15a9cb2505908182fbbc55fc73d9c549a29fd Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Fri, 20 Jul 2018 08:17:26 -0500 Subject: [PATCH 082/100] Stopped loop from erroneously adding range for unresolved paramaters as previous range --- openmc/data/resonance_covariance.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index 2de619c008..e1089b3571 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -114,12 +114,13 @@ class ResonanceCovariances(Resonances): file2params = resonances.ranges[j].parameters erange = _FORMALISMS[formalism].from_endf(ev, file_obj, items, file2params) + ranges.append(erange) + elif unresolved_flag == 2: - warn_str = 'Unresolved resonance not supported.'\ + warn_str = 'Unresolved resonance not supported. '\ 'Covariance values for the unresolved region not imported.' warnings.warn(warn_str) - ranges.append(erange) return cls(ranges) From 010acb8d1f96074e8554d668eeaae7304cc8a109 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Fri, 20 Jul 2018 09:14:03 -0500 Subject: [PATCH 083/100] added warning for sampling/reconstruction --- openmc/data/resonance_covariance.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index e1089b3571..960d55bc9e 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -219,6 +219,10 @@ class ResonanceCovarianceRange: List of samples size `n_samples` """ + warn_str = 'Sampling routine does not guarantee positive values for '\ + 'parameters. This can lead to undefined behavior in the '\ + 'reconstruction routine.' + warnings.warn(warn_str) if not use_subset: parameters = self.parameters cov = self.covariance From 5381ad46bc73c1cc45c2debd6507c15c5e1bf8da Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Mon, 23 Jul 2018 13:43:07 -0500 Subject: [PATCH 084/100] Style, changed sampling/subset methods to return new objects --- .../nuclear-data-resonance-covariance.ipynb | 776 +++++++++++++++--- openmc/data/endf.py | 22 +- openmc/data/neutron.py | 8 +- openmc/data/resonance_covariance.py | 281 ++++--- 4 files changed, 848 insertions(+), 239 deletions(-) diff --git a/examples/jupyter/nuclear-data-resonance-covariance.ipynb b/examples/jupyter/nuclear-data-resonance-covariance.ipynb index 9e79175d88..ab2694922d 100644 --- a/examples/jupyter/nuclear-data-resonance-covariance.ipynb +++ b/examples/jupyter/nuclear-data-resonance-covariance.ipynb @@ -1,5 +1,12 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this notebook we will explore features of the Python API that allow us to import and manipulate resonance covariance data. A full description of the ENDF-VI and ENDF-VII formats can be found in the [ENDF102 manual](https://www.oecd-nea.org/dbdata/data/manual-endf/endf102.pdf)." + ] + }, { "cell_type": "code", "execution_count": 1, @@ -16,8 +23,6 @@ "import h5py\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", - "import matplotlib.cm\n", - "from matplotlib.patches import Rectangle\n", "\n", "import openmc.data" ] @@ -28,7 +33,7 @@ "source": [ "### ENDF: Resonance Covariance Data\n", "\n", - "We can also load the resonance covariance data contained within File 32 of ENDF. Let's download the ENDF/B-VII.1 evaluation for $^{157}$Gd and load it in:" + "Let's download the ENDF/B-VII.1 evaluation for $^{157}$Gd and load it in:" ] }, { @@ -53,7 +58,7 @@ "filename, headers = urllib.request.urlretrieve(url, 'gd157.endf')\n", "\n", "# Load into memory\n", - "gd157_endf = openmc.data.IncidentNeutron.from_endf(filename, covariance = True)\n", + "gd157_endf = openmc.data.IncidentNeutron.from_endf(filename, covariance=True)\n", "gd157_endf" ] }, @@ -70,28 +75,113 @@ "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - " energy J neutronWidth captureWidth fissionWidthA fissionWidthB L\n", - "0 0.0314 2.0 0.000474 0.1072 0.0 0.0 0\n", - "1 2.8250 2.0 0.000345 0.0970 0.0 0.0 0\n", - "2 16.2400 1.0 0.000400 0.0910 0.0 0.0 0\n", - "3 16.7700 2.0 0.012800 0.0805 0.0 0.0 0\n", - "4 20.5600 2.0 0.011360 0.0880 0.0 0.0 0\n" - ] + "data": { + "text/html": [ + "
\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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
energyJneutronWidthcaptureWidthfissionWidthAfissionWidthBL
00.03142.00.0004740.10720.00.00
12.82502.00.0003450.09700.00.00
216.24001.00.0004000.09100.00.00
316.77002.00.0128000.08050.00.00
420.56002.00.0113600.08800.00.00
\n", + "
" + ], + "text/plain": [ + " energy J neutronWidth captureWidth fissionWidthA fissionWidthB L\n", + "0 0.0314 2.0 0.000474 0.1072 0.0 0.0 0\n", + "1 2.8250 2.0 0.000345 0.0970 0.0 0.0 0\n", + "2 16.2400 1.0 0.000400 0.0910 0.0 0.0 0\n", + "3 16.7700 2.0 0.012800 0.0805 0.0 0.0 0\n", + "4 20.5600 2.0 0.011360 0.0880 0.0 0.0 0" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "first_five = gd157_endf.resonance_covariance.ranges[0].parameters[:5]\n", - "print(first_five)" + "gd157_endf.resonance_covariance.ranges[0].parameters[:5]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The newly created object will contain multiple resonance regions within 'gd157_endf.res_covariance.ranges'. We can access the full covariance matrix from File 32 for a given range by:" + "The newly created object will contain multiple resonance regions within `gd157_endf.resonance_covariance.ranges`. We can access the full covariance matrix from File 32 for a given range by:" ] }, { @@ -118,7 +208,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 5, @@ -127,9 +217,9 @@ }, { "data": { - "image/png": "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\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAUIAAAD8CAYAAAACGq0tAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4wLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvpW3flQAAIABJREFUeJztnXvwZVV15z9fugWCTuTRQBBwIKGd\nDDqOml/QTDIJEXk5iW0mWkEzCTFYJCnIJDEphbFGDWoNZpKQODFW9WhHzEMkThw7Y4+kRYkzKUUa\nNGCrpDtotLWHh01ICIXQsuaPcy4cNnvvs8/j3t99rE/Vrd895+yz99rnd++667EfMjMcx3FWmUPW\nWwDHcZz1xhWh4zgrjytCx3FWHleEjuOsPK4IHcdZeVwROo6z8rgidBxnXZB0nqTbJe2VdFnk+mGS\n3l9fv1HSKfX5J0m6WtJtkr4g6fKhskxNEbZ10nGc1UXSBuAdwPnA6cArJJ0eFLsIuNfMTgOuAt5W\nn385cJiZ/Svge4CfmyjJvkxFERZ20nGc1eUMYK+Z3WFmDwHXAFuCMluAq+v3HwDOkiTAgCdL2gh8\nG/AQ8A9DhNk45OYMj3YSQNKkk5+PFd60aZOdcsopUxLFcRyAm2+++R4zO7bv/adJ9kBh2f2wG3iw\ncWqrmW1tHJ8IfLVxvA94flDNo2XM7KCk+4BjqJTilqoZjgB+xcwOFHckwrQUYWsnJV0MXAzw9Kc/\nnV2f/jSPBAbqITwC8Oj5Q3jkce8nPMIhTyi7XjRlnDcZcuch/+zayoT/m2k8g7De2Odh8lno0n6u\nfNu1SZu5suFndWwZSp+JNmz4u2glhTwA/Fxh2TfBg2a2limiyLlwvm+qzBnAt4CnAUcB/0fSRyeG\nVx+mpQhbO1n/OmwFWFtbM3j8BwZI/kOb1ybXYwpyPWjKOG8y5M5D/tm1lQn/N9N4BmG9sc/D5LPQ\npf1c+bZrkzZzZcPP6tgylD6ToYhRY2n7gJMbxycBX0+U2Ve7wU8FDgCvBD5iZg8Dd0n6K2AN6K0I\np2W6lHTScZwFQlSWU8mrgJuAzZJOlXQocAGwPSizHbiwfv8y4GNWrRLzFeCFqngy8ALgi707xvQU\nYUkns8QskLZftpQL8giHPPoKr6XazdXjrC6r/v8/pPDVhpkdBC4FrgO+AFxrZrslXSHpJXWxdwPH\nSNoLvAaYjD55B/AU4HNUuuYPzOzWIf2aimtcBzYnndwAbDOz3V3qmCi9lMsVugqhS9Q8bisbXksd\nr7fL66w/q/4ZGPNnwMx2ADuCc29ovH+QaqhMeN/9sfNDmFaMMNrJruSUUixGmIqVDCEVc1kU5iFm\n6SwHI8cI54qpKcJpklOCoSs7KdM81yXDnMrClZRfL0IZSrOaJXKvZ9Y4bH9RssYlZfvK0KwzPJ5G\n8soV4RzR9QMXux67lmuv5FzXepuMaW2mwglds8YxpdIna5yrp4slH7tWmjXO9b1NUZRkjZv1xBRR\nKuYdk2/IM1mgrPFcsZCK0HGc9WHDegswJRZLET74IBx+eLZIzE0Y2zXO3Tv013eMX+4xXeNcFj3V\nZqydtmx8SRvhta6ucV/3t6+7m5OhzTUudZtj7XQJ5XRBuCKcD2olGH5gYu5Q25c+dTxEcebcv1zZ\nmKwlrmTJl6XE/SqVeREo+QzMI4si52JI2Z3FUoQ1KcXR/NumMFIKMFRQzfJ9Y4qp+9rilW3ncvGy\nNlm7Xm+LYZbEImNlh15LxYTDvznGiMHl6knFWIfERrvK5zHCPAupCKH9i5pTYCkLMlV3qQKcR5r9\nHKIcx3wGY7WT+kGL1ZNTJl3a7PMcSu7p+0z6/OgOwRWh4zgrzWSK3TKyFAo+dGvDoQx9g/Hhcayu\nrnJ2aW9sFiUONQ9M+1kt6v+ibWrd5LVoLKLMT6A0s5eK1cTqSo37GuJilMQBx3bDu7qauWtjfXm7\n/BDlSD3P0nhrrs1cTK4rzR/nVP19n0npD+lYMcLS16KxFIoQyuJfYfwwJJYkCa/FjkuVROwLkaq3\ny/CPVD3hK2UhT8hdb3smbc+/TQnkAvttX+7U/yIlayrRVtJm3xhhqKDbZEj9GIf3x364uyj2rmwo\nfC0ay+ryA+lMcCyz1rwWO05da37A2zKnsexert6mfM2yKYsn98UJ64opppKMY9jvlOUcttv2bEva\njPUj1d+wzdT/JfW5iD3r1OcmPE71K1Zvl2fSpMvzi8nbB88aLxC5L0WzTKjEUvfnvuCpD2eJC11a\nbxfXOaeEwzIpZZCSIWXRlfwIpBRW137nlFpOobW12aZsYnWVKPYUqefXJl+sntIf7rFwReg4zkqz\nzFnjZe3Xo3SNtcXKtv1qzzM567ALi9TneSPlquYs4C51546H1v/EepaT3v2SdLKkj9cbLO+W9Ev1\n+aMl7ZS0p/571HjijkdTuYVJjFSCIXR5cx/usM6QWIA/F/xPJQRix7kvQ6qPubhSiXxtMcJUPal+\n9GkzjO+l2ojJlrqW+n+31ZOSPay35Jnk2sw9v5R8fZnECEtei8YQmQ8Cv2pm/5Jqz4BL6r2LLwOu\nN7PNwPU8trz2upBSCk3rrvkKzzWP2+oOYzS5WGHsS5yKRYX1tB2nlGIY72oqwJjlWBJniynR8EtX\n+lzb/gdtbTaVQK6NXF/Ca6lnWfJMuvzvc8clbbaVHQsfPhNgZvvN7Jb6/T9S7TtwIo/flPlq4KVD\nhRxKiRJLkbO8VoncF9vJE3tuY32O2pRj2/mujDl8RtJ5km6XtFfSEwwmSYdJen99/UZJpzSuPVvS\nJ2tv9DZJ+WWpWhjlv1EL+FzgRuB4M9sPlbIEjkvcc7GkXZJ23X333WOIUUzuQ9Hm0sbKz5Jce2Mq\n6nlU+POgiPs+l7YfknnoWxtj7mInaQPVJkznA6cDr6g9yiYXAfea2WnAVcDb6ns3An8E/LyZPRM4\nE3h4SN8Gf9olPQX4H8Avm9k/lN5nZlvNbM3M1o499tihYjiOM2VGjhGeAew1szvM7CHgGipvsknT\nu/wAcJYkAecAt5rZXwOY2TfM7Fu9O1YucxxJT6JSgn9sZn9Wn75T0gn19ROAu4a0MQ1yv+olsamw\n/CxpsyrGkieW8FhvK3G924d+/++YlxF7vn0oTYqM54qPpghPBL7aON5Xn4uWqbf/vA84BngGYJKu\nk3SLpNf2681jDMkai2rf0S+Y2W83LjU3Zb4Q+FB/8aZDGARvUpINXEU8RtifZYoRdlCEmyahr/p1\ncVBVLKdihWU2Aj8A/GT998ckndWnPxOGjCP8fuCngNskfbY+95+AK4FrJV1EtSP9qPuPjsVEGTaH\nMTTfN2lmgsPzsaxs7EOeuze0FNrqSX2JUpnj2L2hpRsOuwjliD2nVPmwnbA/ubpTfUz1LexPrB9N\nuWPPNpQjrDtWNlYu15+wfEqGsL+pz0Lsf5mTYwxF2HGK3T1mtpa5vg84uXF8EvD1RJl9dVzwqcCB\n+vxfmtk9AJJ2AM+jGqXSi96K0Mz+L+lM+SDtPCtyimFC7kOUGm5R8qErGRYx5Nc9ZYW0WScxuVLP\nqXmc++Klwgypcyn529psytr2TEv+x211pZRtqlxKlj4yNK/FjlPvhzLi0JibgM2STgW+BlwAvDIo\nM/EuPwm8DPiYmZmk64DXSjoCeAj4IapkSm+WfmZJGznFkPpVdhfRGcpYVtosEfCkkeoys4OSLgWu\noxpxs83Mdku6AthlZtupQm9/KGkvlSV4QX3vvZJ+m0qZGrDDzD48RJ6VV4SO45QzZoTczHYAO4Jz\nb2i8f5BEaM3M/ohqCM0orGbkP0HXX+n1SJxMcxxhLPY2DaaVKGg7PwarmiyD5Z5i5xZhg9KgdPPa\nrCmNnQ2te5p9G6vuXMxz3t3OeZcvxSIquRJcEQaUZHdLlNGysaz96kqf5zBmsiJW96zwhVlXlNgQ\nj9J7pi1T6pqzGEzrczLtcMGyfsJcETqOU8QyL8y6rAp+FNpcmjYLbBozUdrc8iG//NNMxHRpp5RF\nSZaUDLDvywJPsZsrllXBj0bXeOCsEg6lNF2wNnmGxD679HWsGGtuNkgu1jukzb4xwiFlulyb5o/D\nMscIl7VfoxObPhazkqYdp+tqtYWzF9ZDrlnSRxHMQvbwf9PlczMvzxaW1yJcRJnXhYkCTE2jijEN\n1ziHu8b582PgrvFyKkJ3jTuQmlMaKxO+H1uGUtw1Tpft0+aqu8bLqjCWtV+O40yBRdyPpIRFtGLX\nnZSF1WWKWmm8aGz3elpu2rzEsfr0ZZlihNPsixh3z5J5wi3CAeTihV1cyZx7M1RJhcmS3Go7Oaa1\n8k4oU5eBxtN2aWP0GQg97RhhSV1jxgiXkcH9krRB0mck/a/6+NR6x6k99Q5Uhw4Xcz4JxxnOKqHQ\nt54hX76hiZhcvbnj3LX1sEL7xgjD55fL7g+RZxbDZ5YxWTKGzL9EtZXnhLcBV9X7Gt9LtRPV0hJa\nb83scpOYaxQOw4kprS4uVdfhM7EseIm8MfoOTxniInZNrJS0MQ1y/9+hMnnWeBwGySzpJODfAe+q\njwW8kGrHKZiTfY1nRd+hH0NcvJgi7lJXaNX2rauvkhxC3y/3NIfXLDNjbuc5bwxV3r8DvBYe/WQd\nA/x9veMUxHemAtZ3X2PHcbrjrnEEST8C3GVmNzdPR4qGO1NVJ5dwX+OuY+1KrLm22FKTaQ7gnscY\n4ZB2ZklJjHBI3bnjtvPd21tORTh0F7uXSHoxcDjw7VQW4pGSNtZWYWxnqpVjEocLY0TNTGwqPhie\nS9XdZFJfW9wuN+g49UVNyd32vq3/zTZzZVP9DH9UYm3miMUf2+QO7+3SXq6eyfXmuZR8bW3E7h3C\nIiq5Enr3y8wuN7OTzOwUqk1VPmZmPwl8nGrHKZjTfY2nTZjoaI47bH5pY+9jVmIunphK1nS1TlN1\nxSzBmNxNhRQqp5L+tz2P2PlQcTeVRqx86pXqb9iXnOKNlS19dm2fgZx8uXrCz99QxnaNJZ0n6XZJ\neyVdFrl+WD3yZG89EuWU4PrTJd0v6dd6d6pmGgr+dcBr6p2njqHaiWrlCD+cuV//Lr/Y03J924h9\nqVeRPs8gpuBiFt4Y8qTqGet/N5YilLQBeAdwPnA68ApJpwfFLgLuNbPTqLbrfFtw/Srgf/fryeMZ\nJcFjZjcAN9Tv7wDOGKPeZSL2QYy5ol0/sH3rKHGNY1/cMb5Qfa2U0i992FZp2RL6yt4mx1iW25gW\nYMjIc43PAPbW+gJJ1wBbgM83ymwB3lS//wDwe5JU7238UuAO4J/GEGZZXX7HcaaApKIXsGkyKqR+\nXRxUdSLw1cZxbITJo2XqnMN9wDGSnkzlef76WP1axCE/C0n4S52L++VoixHG2iqpZ4hMXelbd8xK\n7dPPWZNK9IxVdxfLeBASbCxUGQ8/fI+ZreVqi5wLR5ikyvw61aSN+2ulOxhXhDOiqxuacndzH/xp\nxg/nQaHMA31d+mn9b2b+fylXhG0l9gEnN45jI0wmZfZJ2gg8FTgAPB94maTfAI4EHpH0oJn9Xplw\nT8QV4YyJDSsJz+fIKdRYYmZIzCg1fCQs0yZ3WE+p0m+jS7+aMpTeN1YSq6sS7CrjzJRhF4uwnZuA\nzZJOBb5GNfLklUGZ7VQjTz5JNRLlY2ZmwL99TCS9Cbh/iBIEV4QzJ6as2pRNSX3TJGfRlFiqoaLu\n006MPkqg67MtlWdMq29ure9DDoHDDy8r+4//mL1sZgclXQpcR7Vy1zYz2y3pCmCXmW2nGnHyh/UI\nlANUynIquCJ0HKeMcS1CzGwHsCM494bG+weBl7fU8aYxZHFFuE6UBv1zrnDI0KB8Lm45LboMiRki\nz3oOn4lZi2M93z5DigYxoiKcJ5azVwtELH7WJW7W9QsVKx+LnZUq6j5xtJJ4YtdrJW1PQ/Gsdz19\nMum9GdkinCeWs1cLRMxaGDrLIKechliIYRuls03asuJjzaooZRoKNTZTqOT/MbZ8U8UVoTNNcpnY\nLlnkti9cV6sul+To4rJ3qaeLa9xFYYw1RjLXx5TFm1KcKZmGJMtKQyy9cEXozJJUZjlG1+EzKStv\n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\nUQAAAABJRU5ErkJggg==\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -137,7 +227,7 @@ } ], "source": [ - "plt.imshow(covariance)\n", + "plt.imshow(covariance,cmap='seismic',vmin=-0.08, vmax=0.08)\n", "plt.colorbar()" ] }, @@ -145,7 +235,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Another capability of the covariance module is selecting a subset of the resonance parameters and the corresponding subset of the covariance matrix. We can do this by specifying the value we want to discriminate and the bounds within one energy region. Selecting only resonances with J=2:" + "The correlation matrix can be constructed using the covariance matrix and also give some insight into the relations among the parameters." ] }, { @@ -154,31 +244,47 @@ "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - " energy J neutronWidth captureWidth fissionWidthA fissionWidthB L\n", - "0 0.0314 2.0 0.000474 0.1072 0.0 0.0 0\n", - "1 2.8250 2.0 0.000345 0.0970 0.0 0.0 0\n", - "3 16.7700 2.0 0.012800 0.0805 0.0 0.0 0\n", - "4 20.5600 2.0 0.011360 0.0880 0.0 0.0 0\n", - "5 21.6500 2.0 0.000376 0.1140 0.0 0.0 0\n" - ] + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\nOEtDAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ - "lower_bound = 2; #inclusive\n", - "upper_bound = 2; #inclusive\n", - "gd157_endf.resonance_covariance.ranges[0].res_subset('J',[lower_bound,upper_bound])\n", - "subset_first_five = gd157_endf.resonance_covariance.ranges[0].parameters_subset[:5]\n", - "print(subset_first_five)" + "corr = np.zeros([len(covariance),len(covariance)])\n", + "for i in range(len(covariance)):\n", + " for j in range(len(covariance)):\n", + " corr[i, j]=covariance[i, j]/covariance[i, i]**(0.5)/covariance[j, j]**(0.5)\n", + "plt.imshow(corr, cmap='seismic',vmin=-1.0, vmax=1.0)\n", + "plt.colorbar()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The subset method will also store the corresponding subset of the covariance matrix" + "### Sampling and Reconstruction" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The covariance module also has the ability to sample a new set of parameters using the covariance matrix. Currently the sampling uses numpy.multivariate_normal(). Because parameters are assumed to have a multivariate normal distribution this method doesn't not currently guarantee that sampled parameters will be positive." ] }, { @@ -187,32 +293,36 @@ "metadata": {}, "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ - "[[ 2.82609600e-06 5.89537500e-09 -4.78638600e-06 -5.73895500e-08\n", - " -1.48636900e-09]\n", - " [ 0.00000000e+00 1.36218000e-11 -9.61975600e-09 -1.15354000e-10\n", - " -2.87250000e-12]\n", - " [ 0.00000000e+00 0.00000000e+00 8.20814700e-06 9.83537100e-08\n", - " 2.58111200e-09]\n", - " [ 0.00000000e+00 0.00000000e+00 0.00000000e+00 6.54205000e-06\n", - " -4.31977000e-10]\n", - " [ 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00\n", - " 1.76975000e-10]]\n" + "/home/icmeyer/miniconda3/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/data/resonance_covariance.py:239: UserWarning: Sampling routine does not guarantee positive values for parameters. This can lead to undefined behavior in the reconstruction routine.\n", + " warnings.warn(warn_str)\n" ] + }, + { + "data": { + "text/plain": [ + "openmc.data.resonance.ReichMoore" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "cov_subset = gd157_endf.resonance_covariance.ranges[0].cov_subset\n", - "print(cov_subset[:5,:5])" + "rm_resonance = gd157_endf.resonances.ranges[0]\n", + "n_samples = 5\n", + "samples = gd157_endf.resonance_covariance.ranges[0].sample_resonance_parameters(n_samples, rm_resonance)\n", + "type(samples[0])\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The covariance module also has the ability to sample a new set of parameters using the covariance matrix. Currently the sampling uses np.multivariate_normal(). Because parameters are assumed to have a multivariate normal distribution this method doesn't not currently guarantee that sampled parameters will be positive." + "The sampling routine requires the incorporation of the `openmc.data.ResonanceRange` for the same resonance range object. This allows each sample itself to be its own `openmc.data.ResonanceRange` with a new set of parameters. Looking at some of the sampled parameters below:" ] }, { @@ -220,10 +330,105 @@ "execution_count": 8, "metadata": {}, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Sample 1\n" + ] + }, { "data": { + "text/html": [ + "
\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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
energyLJneutronWidthcaptureWidthfissionWidthAfissionWidthB
00.02930902.00.0004680.1103270.00.0
12.82776102.00.0003590.0945390.00.0
216.20841801.00.0002830.0469950.00.0
316.76232202.00.0130440.0781280.00.0
420.55739402.00.0111030.0863090.00.0
\n", + "
" + ], "text/plain": [ - "openmc.data.resonance.ReichMoore" + " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", + "0 0.029309 0 2.0 0.000468 0.110327 0.0 0.0\n", + "1 2.827761 0 2.0 0.000359 0.094539 0.0 0.0\n", + "2 16.208418 0 1.0 0.000283 0.046995 0.0 0.0\n", + "3 16.762322 0 2.0 0.013044 0.078128 0.0 0.0\n", + "4 20.557394 0 2.0 0.011103 0.086309 0.0 0.0" ] }, "execution_count": 8, @@ -232,18 +437,8 @@ } ], "source": [ - "rm_resonance = gd157_endf.resonances.ranges[0]\n", - "n_samples = 5\n", - "gd157_endf.resonance_covariance.ranges[0].sample_resonance_parameters(n_samples, rm_resonance)\n", - "samples = gd157_endf.resonance_covariance.ranges[0].samples\n", - "type(samples[0])\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The sampling routine requires the incorpotation of the `openmc.data.ResonanceRange` for the same resonance range object. This allows each sample itself to be its own `openmc.data.ResonanceRange` with a new set of parameters. Looking at some of the sampled parameters below:" + "print('Sample 1')\n", + "samples[0].parameters[:5]" ] }, { @@ -255,30 +450,111 @@ "name": "stdout", "output_type": "stream", "text": [ - "Sample 1\n", - " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.030278 0 2.0 0.000472 0.109151 0.0 0.0\n", - "1 2.826910 0 2.0 0.000347 0.099239 0.0 0.0\n", - "2 16.199761 0 1.0 0.000258 0.082103 0.0 0.0\n", - "3 16.772474 0 2.0 0.012354 0.091428 0.0 0.0\n", - "4 20.553868 0 2.0 0.011185 0.089609 0.0 0.0\n", - "Sample 2\n", - " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.033611 0 2.0 0.000479 0.103410 0.0 0.0\n", - "1 2.825707 0 2.0 0.000335 0.101266 0.0 0.0\n", - "2 16.270769 0 1.0 0.000360 0.071230 0.0 0.0\n", - "3 16.773850 0 2.0 0.013402 0.074592 0.0 0.0\n", - "4 20.563037 0 2.0 0.011916 0.086590 0.0 0.0\n" + "Sample 2\n" ] + }, + { + "data": { + "text/html": [ + "
\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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
energyLJneutronWidthcaptureWidthfissionWidthAfissionWidthB
00.03134402.00.0004730.1071360.00.0
12.82702602.00.0003210.1029000.00.0
216.24279101.00.0004790.1198320.00.0
316.77214702.00.0133930.0702520.00.0
420.55632402.00.0122200.0771220.00.0
\n", + "
" + ], + "text/plain": [ + " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", + "0 0.031344 0 2.0 0.000473 0.107136 0.0 0.0\n", + "1 2.827026 0 2.0 0.000321 0.102900 0.0 0.0\n", + "2 16.242791 0 1.0 0.000479 0.119832 0.0 0.0\n", + "3 16.772147 0 2.0 0.013393 0.070252 0.0 0.0\n", + "4 20.556324 0 2.0 0.012220 0.077122 0.0 0.0" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "first_five_sample_1 = samples[0].parameters[:5]\n", - "first_five_sample_2 = samples[1].parameters[:5]\n", - "print('Sample 1')\n", - "print(first_five_sample_1)\n", "print('Sample 2')\n", - "print(first_five_sample_2)" + "samples[1].parameters[:5]" ] }, { @@ -296,8 +572,8 @@ { "data": { "text/plain": [ - "[,\n", - " ]" + "[,\n", + " ]" ] }, "execution_count": 10, @@ -312,7 +588,9 @@ { "cell_type": "code", "execution_count": 11, - "metadata": {}, + "metadata": { + "scrolled": false + }, "outputs": [ { "data": { @@ -326,9 +604,9 @@ }, { "data": { - "image/png": "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\n", + "image/png": "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\nSUVORK5CYII=\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -339,14 +617,326 @@ "energy_range = [rm_resonance.energy_min, rm_resonance.energy_max]\n", "energies = np.logspace(np.log10(energy_range[0]),\n", " np.log10(energy_range[1]), 10000)\n", - "for sample in gd157_endf.resonance_covariance.ranges[0].samples:\n", + "for sample in samples:\n", " xs = sample.reconstruct(energies)\n", " elastic_xs = xs[2]\n", " plt.loglog(energies, elastic_xs)\n", "plt.xlabel('Energy (eV)')\n", - "plt.ylabel('Cross section (b)')\n", - "\n", - " " + "plt.ylabel('Cross section (b)')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Subset Selection" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another capability of the covariance module is selecting a subset of the resonance parameters and the corresponding subset of the covariance matrix. We can do this by specifying the value we want to discriminate and the bounds within one energy region. Selecting only resonances with J=2:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
energyLJneutronWidthcaptureWidthfissionWidthAfissionWidthB
00.031402.00.0004740.10720.00.0
12.825002.00.0003450.09700.00.0
316.770002.00.0128000.08050.00.0
420.560002.00.0113600.08800.00.0
521.650002.00.0003760.11400.00.0
\n", + "
" + ], + "text/plain": [ + " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", + "0 0.0314 0 2.0 0.000474 0.1072 0.0 0.0\n", + "1 2.8250 0 2.0 0.000345 0.0970 0.0 0.0\n", + "3 16.7700 0 2.0 0.012800 0.0805 0.0 0.0\n", + "4 20.5600 0 2.0 0.011360 0.0880 0.0 0.0\n", + "5 21.6500 0 2.0 0.000376 0.1140 0.0 0.0" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lower_bound = 2; # inclusive\n", + "upper_bound = 2; # inclusive\n", + "rm_resonance_sub, rm_res_cov_sub = gd157_endf.resonance_covariance.ranges[0].res_subset('J',[lower_bound,upper_bound], rm_resonance)\n", + "rm_resonance_sub.parameters[:5]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The subset method will also store the corresponding subset of the covariance matrix" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(180, 180)" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rm_res_cov_sub.covariance\n", + "gd157_endf.resonance_covariance.ranges[0].covariance.shape\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Checking the size of the new covariance matrix to be sure it was sampled properly: " + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of parameters\n", + "Original: 60\n", + "Subet: 36\n", + "Covariance Size\n", + "Original: (180, 180)\n", + "Subset: (108, 108)\n" + ] + } + ], + "source": [ + "old_n_parameters = gd157_endf.resonance_covariance.ranges[0].parameters.shape[0]\n", + "old_shape = gd157_endf.resonance_covariance.ranges[0].covariance.shape\n", + "new_n_parameters = rm_resonance_sub.parameters.shape[0]\n", + "new_shape = rm_res_cov_sub.covariance.shape\n", + "print('Number of parameters\\nOriginal: '+str(old_n_parameters)+'\\nSubet: '+str(new_n_parameters)+'\\nCovariance Size\\nOriginal: '+str(old_shape)+'\\nSubset: '+str(new_shape))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And finally, we can sample from the subset as well" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/icmeyer/miniconda3/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/data/resonance_covariance.py:239: UserWarning: Sampling routine does not guarantee positive values for parameters. This can lead to undefined behavior in the reconstruction routine.\n", + " warnings.warn(warn_str)\n" + ] + }, + { + "data": { + "text/html": [ + "
\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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
energyLJneutronWidthcaptureWidthfissionWidthAfissionWidthB
00.03306102.00.0004770.1042860.00.0
12.82275802.00.0003450.1010870.00.0
216.77208402.00.0132770.0747350.00.0
320.55597702.00.0114170.0924370.00.0
421.66221302.00.0003800.1222820.00.0
\n", + "
" + ], + "text/plain": [ + " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", + "0 0.033061 0 2.0 0.000477 0.104286 0.0 0.0\n", + "1 2.822758 0 2.0 0.000345 0.101087 0.0 0.0\n", + "2 16.772084 0 2.0 0.013277 0.074735 0.0 0.0\n", + "3 20.555977 0 2.0 0.011417 0.092437 0.0 0.0\n", + "4 21.662213 0 2.0 0.000380 0.122282 0.0 0.0" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "samples_sub = rm_res_cov_sub.sample_resonance_parameters(n_samples, rm_resonance_sub)\n", + "samples_sub[0].parameters[:5]" ] } ], diff --git a/openmc/data/endf.py b/openmc/data/endf.py index cc930b442f..8a118f1695 100644 --- a/openmc/data/endf.py +++ b/openmc/data/endf.py @@ -71,8 +71,8 @@ def float_endf(s): return float(_ENDF_FLOAT_RE.sub(r'\1e\2', s)) -def int_endf(s): - """Conver string to int. Used for INTG records where blank entries +def _int_endf(s): + """Convert string to int. Used for INTG records where blank entries indicate a 0. Parameters @@ -267,10 +267,11 @@ def get_tab2_record(file_obj): return params, Tabulated2D(breakpoints, interpolation) + def get_intg_record(file_obj): """ - Return data from an INTG record in an ENDF-6 file. Used to store the - covariance matrix in a compact format. + Return data from an INTG record in an ENDF-6 file. Used to store the + covariance matrix in a compact format. Parameters ---------- @@ -285,8 +286,8 @@ def get_intg_record(file_obj): # determine how many items are in list and NDIGIT items = get_cont_record(file_obj) ndigit = int(items[2]) - npar = int(items[3]) # Number of parameters - nlines = int(items[4]) # Lines to read + npar = int(items[3]) # Number of parameters + nlines = int(items[4]) # Lines to read NROW_RULES = {2: 18, 3: 12, 4: 11, 5: 9, 6: 8} nrow = NROW_RULES[ndigit] @@ -294,24 +295,23 @@ def get_intg_record(file_obj): corr = np.identity(npar) for i in range(nlines): line = file_obj.readline() - ii = int_endf(line[:5]) - 1 #-1 to account for 0 indexing - jj = int_endf(line[5:10]) - 1 + ii = _int_endf(line[:5]) - 1 # -1 to account for 0 indexing + jj = _int_endf(line[5:10]) - 1 factor = 10**ndigit for j in range(nrow): if jj+j >= ii: break - element = int_endf(line[11+(ndigit+1)*j:11+(ndigit+1)*(j+1)]) + element = _int_endf(line[11+(ndigit+1)*j:11+(ndigit+1)*(j+1)]) if element > 0: corr[ii, jj] = (element+0.5)/factor elif element < 0: corr[ii, jj] = (element-0.5)/factor - #Symmetrize the correlation matrix + # Symmetrize the correlation matrix corr = corr + corr.T - np.diag(corr.diagonal()) return corr - def get_evaluations(filename): """Return a list of all evaluations within an ENDF file. diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 3b98e00a21..3917496b8e 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -299,7 +299,7 @@ class IncidentNeutron(EqualityMixin): @resonance_covariance.setter def resonance_covariance(self, resonance_covariance): cv.check_type('resonance covariance', resonance_covariance, - res_cov.ResonanceCovariances) + res_cov.ResonanceCovariances) self._resonance_covariance = resonance_covariance @summed_reactions.setter @@ -767,7 +767,7 @@ class IncidentNeutron(EqualityMixin): be the filename for the ENDF file. covariance : bool - Flag to indicate whether or not covariance data from File 32 should be + Flag to indicate whether or not covariance data from File 32 should be retrieved Returns @@ -802,7 +802,9 @@ class IncidentNeutron(EqualityMixin): data.resonances = res.Resonances.from_endf(ev) if (32, 151) in ev.section and covariance: - data.resonance_covariance = res_cov.ResonanceCovariances.from_endf(ev, data.resonances) + data.resonance_covariance = ( + res_cov.ResonanceCovariances.from_endf(ev, data.resonances) + ) # Read each reaction for mf, mt, nc, mod in ev.reaction_list: diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index 960d55bc9e..69e6776921 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -12,13 +12,13 @@ from .resonance import Resonances def _add_file2_contributions(file32params, file2params): - """Function for aiding in adding resonance parameters from File 2 that are + """Function for aiding in adding resonance parameters from File 2 that are not always present in File 32. Uses already imported resonance data. Paramaters ---------- file32params : pandas.Dataframe - Incomplete set of resonance parameters contained in File 32. + Incomplete set of resonance parameters contained in File 32. file2params : pandas.Dataframe Resonance parameters from File 2. Ordered by energy. @@ -26,6 +26,7 @@ def _add_file2_contributions(file32params, file2params): ------- parameters : pandas.Dataframe Complete set of parameters ordered by L-values and then energy + """ # Use l-values and competitiveWidth from File 2 data # Re-sort File 2 by energy to match File 32 @@ -54,6 +55,7 @@ class ResonanceCovariances(Resonances): ---------- ranges : list of openmc.data.ResonanceCovarianceRange Distinct energy ranges for resonance data + """ @property @@ -63,8 +65,8 @@ class ResonanceCovariances(Resonances): @ranges.setter def ranges(self, ranges): cv.check_type('resonance ranges', ranges, MutableSequence) - self._ranges = cv.CheckedList(ResonanceCovarianceRange, 'resonance range', - ranges) + self._ranges = cv.CheckedList(ResonanceCovarianceRange, + 'resonance range', ranges) @classmethod def from_endf(cls, ev, resonances): @@ -75,8 +77,8 @@ class ResonanceCovariances(Resonances): ev : openmc.data.endf.Evaluation ENDF evaluation resonances : openmc.data.Resonance object - openmc.data.Resonanance object generated from the same evaluation used - to import values not contained in File 32 + openmc.data.Resonanance object generated from the same evaluation + used to import values not contained in File 32 Returns ------- @@ -88,39 +90,40 @@ class ResonanceCovariances(Resonances): # Determine whether discrete or continuous representation items = endf.get_head_record(file_obj) - n_isotope = items[4] # Number of isotopes + n_isotope = items[4] # Number of isotopes ranges = [] for iso in range(n_isotope): items = endf.get_cont_record(file_obj) abundance = items[1] - fission_widths = (items[3] == 1) # Flag for fission widths - n_ranges = items[4] # number of resonance energy ranges + fission_widths = (items[3] == 1) # Flag for fission widths + n_ranges = items[4] # Number of resonance energy ranges for j in range(n_ranges): items = endf.get_cont_record(file_obj) - unresolved_flag = items[2] # 0: only scattering radius given - # 1: resolved parameters given - # 2: unresolved parameters given + # Unresolved flags - 0: only scattering radius given + # 1: resolved parameters given + # 2: unresolved parameters given + unresolved_flag = items[2] formalism = items[3] # resonance formalism # Throw error for unsupported formalisms if formalism in [0, 7]: - raise NotImplementedError('LRF= ', formalism, - 'covariance not supported for this formalism') + error = 'LRF = '+str(formalism)+'covariance not supported '\ + 'for this formalism' + raise NotImplementedError(error) if unresolved_flag in (0, 1): - # resolved resonance region + # Resolved resonance region file2params = resonances.ranges[j].parameters erange = _FORMALISMS[formalism].from_endf(ev, file_obj, items, file2params) ranges.append(erange) elif unresolved_flag == 2: - warn_str = 'Unresolved resonance not supported. '\ - 'Covariance values for the unresolved region not imported.' - warnings.warn(warn_str) - + warn = 'Unresolved resonance not supported. Covariance '\ + 'values for the unresolved region not imported.' + warnings.warn(warn) return cls(ranges) @@ -146,7 +149,7 @@ class ResonanceCovarianceRange: covariance : numpy.array The covariance matrix contained within the ENDF evaluation lcomp : int - Flag indicating the format of the covariance matrix within the ENDF file + Flag indicating format of the covariance matrix within the ENDF file mpar : int Number of parameters in covariance matrix for each individual resonance formalism : str @@ -155,35 +158,47 @@ class ResonanceCovarianceRange: def __init__(self, energy_min, energy_max): self.energy_min = energy_min self.energy_max = energy_max - - def res_subset(self, parameter_str, bounds): + + def res_subset(self, parameter_str, bounds, resonances): """Produce a subset of resonance parameters and the corresponding covariance matrix to an IncidentNeutron object. - + Parameters ---------- parameter_str : str parameter to be discriminated (i.e. 'energy', 'captureWidth', 'fissionWidthA'...) - bounds : np.array + bounds : np.array [low numerical bound, high numerical bound] - + resonances : openmc.data.ResonanceRange object + Corresponding resonance range with File 2 data. + Returns ------- - parameters_subset : pandas.Dataframe - Subset of parameters (maintains indexing of original) - cov_subset : np.array - Subset of covariance matrix (upper triangular) - + res_range : openmc.data.ResonanceRange + ResonanceRange object that contains a subset of parameters + (maintains indexing of original) + res_cov_range : openmc.data.ResonanceCovarianceRange + ResonanceCovarianceRange object that contains a subset of the + covariance matrix (upper triangular) as well as parameters + """ - parameters = self.parameters - cov = self.covariance - mpar = self.mpar + # Copy the objects + res_range = copy.copy(resonances) + res_cov_range = copy.copy(self) + + parameters = res_range.parameters + cov = res_cov_range.covariance + mpar = res_cov_range.mpar + # Create mask mask1 = parameters[parameter_str] >= bounds[0] mask2 = parameters[parameter_str] <= bounds[1] mask = mask1 & mask2 - parameters_subset = parameters[mask] - indices = parameters_subset.index.values + # Set the parameters for each object + res_range.parameters = parameters[mask] + res_cov_range.parameters = parameters[mask] + indices = res_cov_range.parameters.index.values + # Build subset of covariance sub_cov_dim = len(indices)*mpar cov_subset_vals = [] for index1 in indices: @@ -191,54 +206,48 @@ class ResonanceCovarianceRange: for index2 in indices: for j in range(mpar): if index2*mpar+j >= index1*mpar+i: - cov_subset_vals.append(cov[index1*mpar+i, index2*mpar+j]) - + cov_subset_vals.append(cov[index1*mpar+i, + index2*mpar+j]) + cov_subset = np.zeros([sub_cov_dim, sub_cov_dim]) tri_indices = np.triu_indices(sub_cov_dim) cov_subset[tri_indices] = cov_subset_vals - - self.parameters_subset = parameters_subset - self.cov_subset = cov_subset + res_cov_range.covariance = cov_subset + + return res_range, res_cov_range + + def sample_resonance_parameters(self, n_samples, resonances): + """Sample resonance parameters based on the covariances provided + within an ENDF evaluation. - def sample_resonance_parameters(self, n_samples, resonances, use_subset=False): - """Return a list size 'n_samples' of openmc.data.ResonanceRange objects. - Each with an indepentenly sampled set of parameters - Parameters ---------- n_samples : int The number of samples to produce resonances : openmc.data.ResonanceRange object Corresponding resonance range with File 2 data. - use_subset : bool, optional - Flag on whether to sample from an already produced subset - + Returns ------- - samples : list of openmc.data.ResonanceCovarianceRange objects + samples : list of openmc.data.ResonanceCovarianceRange objects List of samples size `n_samples` - + """ warn_str = 'Sampling routine does not guarantee positive values for '\ 'parameters. This can lead to undefined behavior in the '\ 'reconstruction routine.' warnings.warn(warn_str) - if not use_subset: - parameters = self.parameters - cov = self.covariance - else: - if self.parameters_subset is None: - raise ValueError('No subset of resonances defined') - parameters = self.parameters_subset - cov = self.cov_subset + parameters = self.parameters + cov = self.covariance nparams, params = parameters.shape - cov = cov + cov.T - np.diag(cov.diagonal()) # symmetrizing covariance matrix + # Symmetrizing covariance matrix + cov = cov + cov.T - np.diag(cov.diagonal()) covsize = cov.shape[0] formalism = self.formalism mpar = self.mpar samples = [] - + # Handling MLBW sampling if formalism == 'mlbw' or formalism == 'slbw': if mpar == 3: @@ -258,20 +267,22 @@ class ResonanceCovarianceRange: gt = gn + gg + gf records = [] for j, E in enumerate(energy): - records.append([energy[j], l_value[j], spin[j], gt[j], gn[j], - gg[j], gf[j], gx[j]]) + records.append([energy[j], l_value[j], spin[j], gt[j], + gn[j], gg[j], gf[j], gx[j]]) columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', 'captureWidth', 'fissionWidth', 'competitiveWidth'] - sample_params = pd.DataFrame.from_records(records, columns=columns) + sample_params = pd.DataFrame.from_records(records, + columns=columns) res_range = copy.copy(resonances) - res_range._prepared = False # Set prepared to False to ensure - # the sampled parameters are used - # in reconstruction + # Set _prepared to False to ensure sampled paramaters are + # used during construction routine + res_range._prepared = False res_range.parameters = sample_params samples.append(res_range) - + elif mpar == 4: - param_list = ['energy', 'neutronWidth', 'captureWidth', 'fissionWidth'] + param_list = ['energy', 'neutronWidth', 'captureWidth', + 'fissionWidth'] mean_array = pd.DataFrame.as_matrix(parameters[param_list]) spin = pd.DataFrame.as_matrix(parameters['J']) l_value = pd.DataFrame.as_matrix(parameters['L']) @@ -287,18 +298,19 @@ class ResonanceCovarianceRange: gt = gn + gg + gf records = [] for j, E in enumerate(energy): - records.append([energy[j], l_value[j], spin[j], gt[j], gn[j], - gg[j], gf[j], gx[j]]) + records.append([energy[j], l_value[j], spin[j], gt[j], + gn[j], gg[j], gf[j], gx[j]]) columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', 'captureWidth', 'fissionWidth', 'competitiveWidth'] - sample_params = pd.DataFrame.from_records(records, columns=columns) + sample_params = pd.DataFrame.from_records(records, + columns=columns) res_range = copy.copy(resonances) - res_range._prepared = False # Set prepared to False to ensure - # the sampled parameters are used - # in reconstruction + # Set _prepared to False to ensure sampled paramaters are + # used during construction routine + res_range._prepared = False res_range.parameters = sample_params samples.append(res_range) - + elif mpar == 5: param_list = ['energy', 'neutronWidth', 'captureWidth', 'fissionWidth', 'competitiveWidth'] @@ -317,15 +329,16 @@ class ResonanceCovarianceRange: gt = gn + gg + gf records = [] for j, E in enumerate(energy): - records.append([energy[j], l_value[j], spin[j], gt[j], gn[j], - gg[j], gf[j], gx[j]]) + records.append([energy[j], l_value[j], spin[j], gt[j], + gn[j], gg[j], gf[j], gx[j]]) columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', 'captureWidth', 'fissionWidth', 'competitveWidth'] - sample_params = pd.DataFrame.from_records(records, columns=columns) + sample_params = pd.DataFrame.from_records(records, + columns=columns) res_range = copy.copy(resonances) - res_range._prepared = False # Set prepared to False to ensure - # the sampled parameters are used - # in reconstruction + # Set _prepared to False to ensure sampled paramaters are + # used during construction routine + res_range._prepared = False res_range.parameters = sample_params samples.append(res_range) @@ -351,14 +364,15 @@ class ResonanceCovarianceRange: gg[j], gfa[j], gfb[j]]) columns = ['energy', 'L', 'J', 'neutronWidth', 'captureWidth', 'fissionWidthA', 'fissionWidthB'] - sample_params = pd.DataFrame.from_records(records, columns=columns) + sample_params = pd.DataFrame.from_records(records, + columns=columns) res_range = copy.copy(resonances) - res_range._prepared = False # Set prepared to False to ensure - # the sampled parameters are used - # in reconstruction + # Set _prepared to False to ensure sampled paramaters are + # used during construction routine + res_range._prepared = False res_range.parameters = sample_params samples.append(res_range) - + elif mpar == 5: param_list = ['energy', 'neutronWidth', 'captureWidth', 'fissionWidthA', 'fissionWidthB'] @@ -380,15 +394,16 @@ class ResonanceCovarianceRange: gg[j], gfa[j], gfb[j]]) columns = ['energy', 'L', 'J', 'neutronWidth', 'captureWidth', 'fissionWidthA', 'fissionWidthB'] - sample_params = pd.DataFrame.from_records(records, columns=columns) + sample_params = pd.DataFrame.from_records(records, + columns=columns) res_range = copy.copy(resonances) - res_range._prepared = False # Set prepared to False to ensure - # the sampled parameters are used - # in reconstruction + # Set _prepared to False to ensure sampled paramaters are + # used during construction routine + res_range._prepared = False res_range.parameters = sample_params samples.append(res_range) - - self.samples = samples + + return samples class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): @@ -411,7 +426,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): covariance : numpy.array The covariance matrix contained within the ENDF evaluation lcomp : int - Flag indicating the format of the covariance matrix within the ENDF file + Flag indicating format of the covariance matrix within the ENDF file mpar : int Number of parameters in covariance matrix for each individual resonance formalism : str @@ -425,7 +440,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): self.mpar = mpar self.lcomp = lcomp self.formalism = 'mlbw' - + @classmethod def from_endf(cls, ev, file_obj, items, file2params): """Create MLBW covariance data from an ENDF evaluation. @@ -460,16 +475,16 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): # Other scatter radius parameters items = endf.get_cont_record(file_obj) target_spin = items[0] - lcomp = items[3] # Flag for compatibility 0, 1, 2 - 2 is compact form + lcomp = items[3] # Flag for compatibility 0, 1, 2 - 2 is compact form nls = items[4] # number of l-values # Build covariance matrix for General Resolved Resonance Formats if lcomp == 1: items = endf.get_cont_record(file_obj) - num_short_range = items[4] # Number of short range type resonance - # covariances - num_long_range = items[5] # Number of long range type resonance - # covariances + # Number of short range type resonance covariances + num_short_range = items[4] + # Number of long range type resonance covariances + num_long_range = items[5] # Read resonance widths, J values, etc records = [] @@ -498,7 +513,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): indices = np.triu_indices(cov_dim) cov[indices] = cov_values - # Create pandas DataFrame with resonance data, currently + # Create pandas DataFrame with resonance data, currently # redundant with data.IncidentNeutron.resonance columns = ['energy', 'J', 'totalWidth', 'neutronWidth', 'captureWidth', 'fissionWidth'] @@ -507,11 +522,12 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): # Add parameters from File 2 parameters = _add_file2_contributions(parameters, file2params) - elif lcomp == 2: # Compact format - Resonances and individual - # uncertainties followed by compact correlations + # Compact format - Resonances and individual uncertainties followed by + # compact correlations + elif lcomp == 2: items, values = endf.get_list_record(file_obj) mean = items - num_res = items[5] + num_res = items[5] energy = values[0::12] spin = values[1::12] gt = values[2::12] @@ -525,9 +541,9 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): # DAJ/DGT always zero, DGF sometimes none zero [1, 2, 5] res_unc_nonzero = [] for j in range(6): - if j in [1, 2, 5] and res_unc[j] != 0.0 : + if j in [1, 2, 5] and res_unc[j] != 0.0: res_unc_nonzero.append(res_unc[j]) - elif j in [0,3,4]: + elif j in [0, 3, 4]: res_unc_nonzero.append(res_unc[j]) par_unc.extend(res_unc_nonzero) @@ -549,11 +565,11 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): nparams, params = parameters.shape covsize = cov.shape[0] mpar = int(covsize/nparams) - + # Add parameters from File 2 parameters = _add_file2_contributions(parameters, file2params) - elif lcomp == 0 : + elif lcomp == 0: cov = np.zeros([4, 4]) records = [] cov_index = 0 @@ -576,12 +592,11 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): cov[cov_index+3, cov_index+3] = cov_values[6] cov_index += 4 - if j < num_res-1: # Pad matrix for additional values + if j < num_res-1: # Pad matrix for additional values cov = np.pad(cov, ((0, 4), (0, 4)), 'constant', constant_values=0) - - # Create pandas DataFrame with resonance data, currently + # Create pandas DataFrame with resonance data, currently # redundant with data.IncidentNeutron.resonance columns = ['energy', 'J', 'totalWidth', 'neutronWidth', 'captureWidth', 'fissionWidth'] @@ -624,15 +639,17 @@ class SingleLevelBreitWignerCovariance(MultiLevelBreitWignerCovariance): covariance : numpy.array The covariance matrix contained within the ENDF evaluation lcomp : int - Flag indicating the format of the covariance matrix within the ENDF file + Flag indicating format of the covariance matrix within the ENDF file mpar : int Number of parameters in covariance matrix for each individual resonance formalism : str String descriptor of formalism """ - def __init__(self, energy_min, energy_max, parameters, covariance, mpar, lcomp): - super().__init__(energy_min, energy_max, parameters, covariance, mpar, lcomp) + def __init__(self, energy_min, energy_max, parameters, covariance, mpar, + lcomp): + super().__init__(energy_min, energy_max, parameters, covariance, mpar, + lcomp) self.formalism = 'slbw' @@ -660,14 +677,15 @@ class ReichMooreCovariance(ResonanceCovarianceRange): covariance : numpy.array The covariance matrix contained within the ENDF evaluation lcomp : int - Flag indicating the format of the covariance matrix within the ENDF file + Flag indicating format of the covariance matrix within the ENDF file mpar : int Number of parameters in covariance matrix for each individual resonance formalism : str String descriptor of formalism """ - def __init__(self, energy_min, energy_max, parameters, covariance, mpar, lcomp): + def __init__(self, energy_min, energy_max, parameters, covariance, mpar, + lcomp): super().__init__(energy_min, energy_max) self.parameters = parameters self.covariance = covariance @@ -677,8 +695,9 @@ class ReichMooreCovariance(ResonanceCovarianceRange): @classmethod def from_endf(cls, ev, file_obj, items, file2params): - """Create Reich-Moore resonance covariance data from an ENDF evaluation. - Includes the resonance parameters contained separately in File 32. + """Create Reich-Moore resonance covariance data from an ENDF + evaluation. Includes the resonance parameters contained separately in + File 32. Parameters ---------- @@ -691,8 +710,8 @@ class ReichMooreCovariance(ResonanceCovarianceRange): Items from the CONT record at the start of the resonance range subsection resonances : openmc.data.Resonance object - openmc.data.Resonanance object generated from the same evaluation used - to import values not contained in File 32 + openmc.data.Resonanance object generated from the same evaluation + used to import values not contained in File 32 Returns ------- @@ -712,14 +731,13 @@ class ReichMooreCovariance(ResonanceCovarianceRange): lcomp = items[3] # Flag for compatibility 0, 1, 2 - 2 is compact form nls = items[4] # Number of l-values - # Build covariance matrix for General Resolved Resonance Formats if lcomp == 1: items = endf.get_cont_record(file_obj) - num_short_range = items[4] # Number of short range type resonance - # covariances - num_long_range = items[5] # Number of long range type resonance - # covariances + # Number of short range type resonance covariances + num_short_range = items[4] + # Number of long range type resonance covariances + num_long_range = items[5] # Read resonance widths, J values, etc channel_radius = {} scattering_radius = {} @@ -731,7 +749,7 @@ class ReichMooreCovariance(ResonanceCovarianceRange): num_par_vals = num_res*6 res_values = values[:num_par_vals] cov_values = values[num_par_vals:] - + energy = res_values[0::6] spin = res_values[1::6] gn = res_values[2::6] @@ -745,7 +763,7 @@ class ReichMooreCovariance(ResonanceCovarianceRange): # Build the upper-triangular covariance matrix cov_dim = mpar*num_res - cov = np.zeros([cov_dim,cov_dim]) + cov = np.zeros([cov_dim, cov_dim]) indices = np.triu_indices(cov_dim) cov[indices] = cov_values @@ -757,10 +775,11 @@ class ReichMooreCovariance(ResonanceCovarianceRange): # Add parameters from File 2 parameters = _add_file2_contributions(parameters, file2params) - elif lcomp == 2: # Compact format - Resonances and individual - # uncertainties followed by compact correlations + # Compact format - Resonances and individual uncertainties followed by + # compact correlations + elif lcomp == 2: items, values = endf.get_list_record(file_obj) - num_res = items[5] + num_res = items[5] energy = values[0::12] spin = values[1::12] gn = values[2::12] @@ -789,7 +808,7 @@ class ReichMooreCovariance(ResonanceCovarianceRange): # Determine mpar (number of parameters for each resonance in # covariance matrix) - nparams,params = parameters.shape + nparams, params = parameters.shape covsize = cov.shape[0] mpar = int(covsize/nparams) @@ -800,6 +819,7 @@ class ReichMooreCovariance(ResonanceCovarianceRange): rmc = cls(energy_min, energy_max, parameters, cov, mpar, lcomp) return rmc + _FORMALISMS = { 0: ResonanceCovarianceRange, 1: SingleLevelBreitWignerCovariance, @@ -807,6 +827,3 @@ _FORMALISMS = { 3: ReichMooreCovariance # 7: RMatrixLimitedCovariance } - - - From e2a27f288be2dbe050e6b21da0558fd85675c9fd Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Mon, 23 Jul 2018 15:02:10 -0500 Subject: [PATCH 085/100] Restructured ResonanceCovarianceRange class to contain corresponding file2 data as an attribute --- .../nuclear-data-resonance-covariance.ipynb | 168 +++++++++--------- openmc/data/resonance_covariance.py | 121 ++++++------- 2 files changed, 141 insertions(+), 148 deletions(-) diff --git a/examples/jupyter/nuclear-data-resonance-covariance.ipynb b/examples/jupyter/nuclear-data-resonance-covariance.ipynb index ab2694922d..b8c1764cf5 100644 --- a/examples/jupyter/nuclear-data-resonance-covariance.ipynb +++ b/examples/jupyter/nuclear-data-resonance-covariance.ipynb @@ -208,7 +208,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 5, @@ -219,7 +219,7 @@ "data": { "image/png": "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\nIiq5Enr3y8wuN7OTzOwUqk1VPmZmPwl8nGrHKZjTfY2nTZjoaI47bH5pY+9jVmIunphK1nS1TlN1\nxSzBmNxNhRQqp5L+tz2P2PlQcTeVRqx86pXqb9iXnOKNlS19dm2fgZx8uXrCz99QxnaNJZ0n6XZJ\neyVdFrl+WD3yZG89EuWU4PrTJd0v6dd6d6pmGgr+dcBr6p2njqHaiWrlCD+cuV//Lr/Y03J924h9\nqVeRPs8gpuBiFt4Y8qTqGet/N5YilLQBeAdwPnA68ApJpwfFLgLuNbPTqLbrfFtw/Srgf/fryeMZ\nJcFjZjcAN9Tv7wDOGKPeZSL2QYy5ol0/sH3rKHGNY1/cMb5Qfa2U0i992FZp2RL6yt4mx1iW25gW\nYMjIc43PAPbW+gJJ1wBbgM83ymwB3lS//wDwe5JU7238UuAO4J/GEGZZXX7HcaaApKIXsGkyKqR+\nXRxUdSLw1cZxbITJo2XqnMN9wDGSnkzlef76WP1axCE/C0n4S52L++VoixHG2iqpZ4hMXelbd8xK\n7dPPWZNK9IxVdxfLeBASbCxUGQ8/fI+ZreVqi5wLR5ikyvw61aSN+2ulOxhXhDOiqxuacndzH/xp\nxg/nQaHMA31d+mn9b2b+fylXhG0l9gEnN45jI0wmZfZJ2gg8FTgAPB94maTfAI4EHpH0oJn9Xplw\nT8QV4YyJDSsJz+fIKdRYYmZIzCg1fCQs0yZ3WE+p0m+jS7+aMpTeN1YSq6sS7CrjzJRhF4uwnZuA\nzZJOBb5GNfLklUGZ7VQjTz5JNRLlY2ZmwL99TCS9Cbh/iBIEV4QzJ6as2pRNSX3TJGfRlFiqoaLu\n006MPkqg67MtlWdMq29ure9DDoHDDy8r+4//mL1sZgclXQpcR7Vy1zYz2y3pCmCXmW2nGnHyh/UI\nlANUynIquCJ0HKeMcS1CzGwHsCM494bG+weBl7fU8aYxZHFFuE6UBv1zrnDI0KB8Lm45LboMiRki\nz3oOn4lZi2M93z5DigYxoiKcJ5azVwtELH7WJW7W9QsVKx+LnZUq6j5xtJJ4YtdrJW1PQ/Gsdz19\nMum9GdkinCeWs1cLRMxaGDrLIKechliIYRuls03asuJjzaooZRoKNTZTqOT/MbZ8U8UVoTNNcpnY\nLlnkti9cV6sul+To4rJ3qaeLa9xFYYw1RjLXx5TFm1KcKZmGJMtKQyy9cEXozJJUZjlG1+EzKStv\n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\nUQAAAABJRU5ErkJggg==\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -246,7 +246,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 6, @@ -257,7 +257,7 @@ "data": { "image/png": "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\nOEtDAAAAAElFTkSuQmCC\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -296,7 +296,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/icmeyer/miniconda3/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/data/resonance_covariance.py:239: UserWarning: Sampling routine does not guarantee positive values for parameters. This can lead to undefined behavior in the reconstruction routine.\n", + "/home/icmeyer/miniconda3/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/data/resonance_covariance.py:235: UserWarning: Sampling routine does not guarantee positive values for parameters. This can lead to undefined behavior in the reconstruction routine.\n", " warnings.warn(warn_str)\n" ] }, @@ -314,7 +314,7 @@ "source": [ "rm_resonance = gd157_endf.resonances.ranges[0]\n", "n_samples = 5\n", - "samples = gd157_endf.resonance_covariance.ranges[0].sample_resonance_parameters(n_samples, rm_resonance)\n", + "samples = gd157_endf.resonance_covariance.ranges[0].sample_resonance_parameters(n_samples)\n", "type(samples[0])\n" ] }, @@ -370,51 +370,51 @@ " \n", " \n", " 0\n", - " 0.029309\n", + " 0.0314\n", " 0\n", " 2.0\n", - " 0.000468\n", - " 0.110327\n", + " 0.000474\n", + " 0.1072\n", " 0.0\n", " 0.0\n", " \n", " \n", " 1\n", - " 2.827761\n", + " 2.8250\n", " 0\n", " 2.0\n", - " 0.000359\n", - " 0.094539\n", + " 0.000345\n", + " 0.0970\n", " 0.0\n", " 0.0\n", " \n", " \n", " 2\n", - " 16.208418\n", + " 16.2400\n", " 0\n", " 1.0\n", - " 0.000283\n", - " 0.046995\n", + " 0.000400\n", + " 0.0910\n", " 0.0\n", " 0.0\n", " \n", " \n", " 3\n", - " 16.762322\n", + " 16.7700\n", " 0\n", " 2.0\n", - " 0.013044\n", - " 0.078128\n", + " 0.012800\n", + " 0.0805\n", " 0.0\n", " 0.0\n", " \n", " \n", " 4\n", - " 20.557394\n", + " 20.5600\n", " 0\n", " 2.0\n", - " 0.011103\n", - " 0.086309\n", + " 0.011360\n", + " 0.0880\n", " 0.0\n", " 0.0\n", " \n", @@ -423,12 +423,12 @@ "" ], "text/plain": [ - " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.029309 0 2.0 0.000468 0.110327 0.0 0.0\n", - "1 2.827761 0 2.0 0.000359 0.094539 0.0 0.0\n", - "2 16.208418 0 1.0 0.000283 0.046995 0.0 0.0\n", - "3 16.762322 0 2.0 0.013044 0.078128 0.0 0.0\n", - "4 20.557394 0 2.0 0.011103 0.086309 0.0 0.0" + " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", + "0 0.0314 0 2.0 0.000474 0.1072 0.0 0.0\n", + "1 2.8250 0 2.0 0.000345 0.0970 0.0 0.0\n", + "2 16.2400 0 1.0 0.000400 0.0910 0.0 0.0\n", + "3 16.7700 0 2.0 0.012800 0.0805 0.0 0.0\n", + "4 20.5600 0 2.0 0.011360 0.0880 0.0 0.0" ] }, "execution_count": 8, @@ -486,51 +486,51 @@ " \n", " \n", " 0\n", - " 0.031344\n", + " 0.0314\n", " 0\n", " 2.0\n", - " 0.000473\n", - " 0.107136\n", + " 0.000474\n", + " 0.1072\n", " 0.0\n", " 0.0\n", " \n", " \n", " 1\n", - " 2.827026\n", + " 2.8250\n", " 0\n", " 2.0\n", - " 0.000321\n", - " 0.102900\n", + " 0.000345\n", + " 0.0970\n", " 0.0\n", " 0.0\n", " \n", " \n", " 2\n", - " 16.242791\n", + " 16.2400\n", " 0\n", " 1.0\n", - " 0.000479\n", - " 0.119832\n", + " 0.000400\n", + " 0.0910\n", " 0.0\n", " 0.0\n", " \n", " \n", " 3\n", - " 16.772147\n", + " 16.7700\n", " 0\n", " 2.0\n", - " 0.013393\n", - " 0.070252\n", + " 0.012800\n", + " 0.0805\n", " 0.0\n", " 0.0\n", " \n", " \n", " 4\n", - " 20.556324\n", + " 20.5600\n", " 0\n", " 2.0\n", - " 0.012220\n", - " 0.077122\n", + " 0.011360\n", + " 0.0880\n", " 0.0\n", " 0.0\n", " \n", @@ -539,12 +539,12 @@ "" ], "text/plain": [ - " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.031344 0 2.0 0.000473 0.107136 0.0 0.0\n", - "1 2.827026 0 2.0 0.000321 0.102900 0.0 0.0\n", - "2 16.242791 0 1.0 0.000479 0.119832 0.0 0.0\n", - "3 16.772147 0 2.0 0.013393 0.070252 0.0 0.0\n", - "4 20.556324 0 2.0 0.012220 0.077122 0.0 0.0" + " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", + "0 0.0314 0 2.0 0.000474 0.1072 0.0 0.0\n", + "1 2.8250 0 2.0 0.000345 0.0970 0.0 0.0\n", + "2 16.2400 0 1.0 0.000400 0.0910 0.0 0.0\n", + "3 16.7700 0 2.0 0.012800 0.0805 0.0 0.0\n", + "4 20.5600 0 2.0 0.011360 0.0880 0.0 0.0" ] }, "execution_count": 9, @@ -572,8 +572,8 @@ { "data": { "text/plain": [ - "[,\n", - " ]" + "[,\n", + " ]" ] }, "execution_count": 10, @@ -604,9 +604,9 @@ }, { "data": { - "image/png": "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\nSUVORK5CYII=\n", + "image/png": "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\nBGGMMSar/wfYpbH87rh7KwAAAABJRU5ErkJggg==\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -746,8 +746,8 @@ "source": [ "lower_bound = 2; # inclusive\n", "upper_bound = 2; # inclusive\n", - "rm_resonance_sub, rm_res_cov_sub = gd157_endf.resonance_covariance.ranges[0].res_subset('J',[lower_bound,upper_bound], rm_resonance)\n", - "rm_resonance_sub.parameters[:5]" + "rm_res_cov_sub = gd157_endf.resonance_covariance.ranges[0].res_subset('J',[lower_bound,upper_bound])\n", + "rm_res_cov_sub.file2res.parameters[:5]" ] }, { @@ -808,7 +808,7 @@ "source": [ "old_n_parameters = gd157_endf.resonance_covariance.ranges[0].parameters.shape[0]\n", "old_shape = gd157_endf.resonance_covariance.ranges[0].covariance.shape\n", - "new_n_parameters = rm_resonance_sub.parameters.shape[0]\n", + "new_n_parameters = rm_res_cov_sub.file2res.parameters.shape[0]\n", "new_shape = rm_res_cov_sub.covariance.shape\n", "print('Number of parameters\\nOriginal: '+str(old_n_parameters)+'\\nSubet: '+str(new_n_parameters)+'\\nCovariance Size\\nOriginal: '+str(old_shape)+'\\nSubset: '+str(new_shape))\n" ] @@ -831,7 +831,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/icmeyer/miniconda3/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/data/resonance_covariance.py:239: UserWarning: Sampling routine does not guarantee positive values for parameters. This can lead to undefined behavior in the reconstruction routine.\n", + "/home/icmeyer/miniconda3/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/data/resonance_covariance.py:235: UserWarning: Sampling routine does not guarantee positive values for parameters. This can lead to undefined behavior in the reconstruction routine.\n", " warnings.warn(warn_str)\n" ] }, @@ -868,51 +868,51 @@ " \n", " \n", " 0\n", - " 0.033061\n", + " 0.0314\n", " 0\n", " 2.0\n", - " 0.000477\n", - " 0.104286\n", + " 0.000474\n", + " 0.1072\n", " 0.0\n", " 0.0\n", " \n", " \n", " 1\n", - " 2.822758\n", + " 2.8250\n", " 0\n", " 2.0\n", " 0.000345\n", - " 0.101087\n", - " 0.0\n", - " 0.0\n", - " \n", - " \n", - " 2\n", - " 16.772084\n", - " 0\n", - " 2.0\n", - " 0.013277\n", - " 0.074735\n", + " 0.0970\n", " 0.0\n", " 0.0\n", " \n", " \n", " 3\n", - " 20.555977\n", + " 16.7700\n", " 0\n", " 2.0\n", - " 0.011417\n", - " 0.092437\n", + " 0.012800\n", + " 0.0805\n", " 0.0\n", " 0.0\n", " \n", " \n", " 4\n", - " 21.662213\n", + " 20.5600\n", " 0\n", " 2.0\n", - " 0.000380\n", - " 0.122282\n", + " 0.011360\n", + " 0.0880\n", + " 0.0\n", + " 0.0\n", + " \n", + " \n", + " 5\n", + " 21.6500\n", + " 0\n", + " 2.0\n", + " 0.000376\n", + " 0.1140\n", " 0.0\n", " 0.0\n", " \n", @@ -921,12 +921,12 @@ "" ], "text/plain": [ - " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.033061 0 2.0 0.000477 0.104286 0.0 0.0\n", - "1 2.822758 0 2.0 0.000345 0.101087 0.0 0.0\n", - "2 16.772084 0 2.0 0.013277 0.074735 0.0 0.0\n", - "3 20.555977 0 2.0 0.011417 0.092437 0.0 0.0\n", - "4 21.662213 0 2.0 0.000380 0.122282 0.0 0.0" + " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", + "0 0.0314 0 2.0 0.000474 0.1072 0.0 0.0\n", + "1 2.8250 0 2.0 0.000345 0.0970 0.0 0.0\n", + "3 16.7700 0 2.0 0.012800 0.0805 0.0 0.0\n", + "4 20.5600 0 2.0 0.011360 0.0880 0.0 0.0\n", + "5 21.6500 0 2.0 0.000376 0.1140 0.0 0.0" ] }, "execution_count": 15, @@ -935,7 +935,7 @@ } ], "source": [ - "samples_sub = rm_res_cov_sub.sample_resonance_parameters(n_samples, rm_resonance_sub)\n", + "samples_sub = rm_res_cov_sub.sample_resonance_parameters(n_samples)\n", "samples_sub[0].parameters[:5]" ] } diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index 69e6776921..c78ce33f74 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -115,9 +115,9 @@ class ResonanceCovariances(Resonances): if unresolved_flag in (0, 1): # Resolved resonance region - file2params = resonances.ranges[j].parameters + resonance = resonances.ranges[j] erange = _FORMALISMS[formalism].from_endf(ev, file_obj, - items, file2params) + items, resonance) ranges.append(erange) elif unresolved_flag == 2: @@ -159,7 +159,7 @@ class ResonanceCovarianceRange: self.energy_min = energy_min self.energy_max = energy_max - def res_subset(self, parameter_str, bounds, resonances): + def res_subset(self, parameter_str, bounds): """Produce a subset of resonance parameters and the corresponding covariance matrix to an IncidentNeutron object. @@ -170,32 +170,25 @@ class ResonanceCovarianceRange: (i.e. 'energy', 'captureWidth', 'fissionWidthA'...) bounds : np.array [low numerical bound, high numerical bound] - resonances : openmc.data.ResonanceRange object - Corresponding resonance range with File 2 data. Returns ------- - res_range : openmc.data.ResonanceRange - ResonanceRange object that contains a subset of parameters - (maintains indexing of original) res_cov_range : openmc.data.ResonanceCovarianceRange ResonanceCovarianceRange object that contains a subset of the - covariance matrix (upper triangular) as well as parameters + covariance matrix (upper triangular) as well as a subset parameters + within self.file2params """ - # Copy the objects - res_range = copy.copy(resonances) - res_cov_range = copy.copy(self) + # Copy range and prevent change of original + res_cov_range = copy.deepcopy(self) - parameters = res_range.parameters + parameters = self.file2res.parameters cov = res_cov_range.covariance mpar = res_cov_range.mpar # Create mask mask1 = parameters[parameter_str] >= bounds[0] mask2 = parameters[parameter_str] <= bounds[1] mask = mask1 & mask2 - # Set the parameters for each object - res_range.parameters = parameters[mask] res_cov_range.parameters = parameters[mask] indices = res_cov_range.parameters.index.values # Build subset of covariance @@ -212,11 +205,16 @@ class ResonanceCovarianceRange: cov_subset = np.zeros([sub_cov_dim, sub_cov_dim]) tri_indices = np.triu_indices(sub_cov_dim) cov_subset[tri_indices] = cov_subset_vals + + res_cov_range.file2res.parameters = parameters[mask] res_cov_range.covariance = cov_subset + # Set _prepared to False to ensure parameter subset + # used during construction routine + res_cov_range.file2res._prepared = False - return res_range, res_cov_range + return res_cov_range - def sample_resonance_parameters(self, n_samples, resonances): + def sample_resonance_parameters(self, n_samples): """Sample resonance parameters based on the covariances provided within an ENDF evaluation. @@ -224,8 +222,6 @@ class ResonanceCovarianceRange: ---------- n_samples : int The number of samples to produce - resonances : openmc.data.ResonanceRange object - Corresponding resonance range with File 2 data. Returns ------- @@ -239,6 +235,11 @@ class ResonanceCovarianceRange: warnings.warn(warn_str) parameters = self.parameters cov = self.covariance + # Copy ResonanceRange object + res_range = copy.copy(self.file2res) + # Set _prepared to False to ensure sampled parameters are + # used during construction routine + res_range._prepared = False nparams, params = parameters.shape # Symmetrizing covariance matrix @@ -273,10 +274,6 @@ class ResonanceCovarianceRange: 'captureWidth', 'fissionWidth', 'competitiveWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) - res_range = copy.copy(resonances) - # Set _prepared to False to ensure sampled paramaters are - # used during construction routine - res_range._prepared = False res_range.parameters = sample_params samples.append(res_range) @@ -304,11 +301,6 @@ class ResonanceCovarianceRange: 'captureWidth', 'fissionWidth', 'competitiveWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) - res_range = copy.copy(resonances) - # Set _prepared to False to ensure sampled paramaters are - # used during construction routine - res_range._prepared = False - res_range.parameters = sample_params samples.append(res_range) elif mpar == 5: @@ -335,11 +327,6 @@ class ResonanceCovarianceRange: 'captureWidth', 'fissionWidth', 'competitveWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) - res_range = copy.copy(resonances) - # Set _prepared to False to ensure sampled paramaters are - # used during construction routine - res_range._prepared = False - res_range.parameters = sample_params samples.append(res_range) # Handling RM Sampling @@ -366,11 +353,6 @@ class ResonanceCovarianceRange: 'captureWidth', 'fissionWidthA', 'fissionWidthB'] sample_params = pd.DataFrame.from_records(records, columns=columns) - res_range = copy.copy(resonances) - # Set _prepared to False to ensure sampled paramaters are - # used during construction routine - res_range._prepared = False - res_range.parameters = sample_params samples.append(res_range) elif mpar == 5: @@ -396,11 +378,6 @@ class ResonanceCovarianceRange: 'captureWidth', 'fissionWidthA', 'fissionWidthB'] sample_params = pd.DataFrame.from_records(records, columns=columns) - res_range = copy.copy(resonances) - # Set _prepared to False to ensure sampled paramaters are - # used during construction routine - res_range._prepared = False - res_range.parameters = sample_params samples.append(res_range) return samples @@ -425,24 +402,29 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): Resonance parameters covariance : numpy.array The covariance matrix contained within the ENDF evaluation - lcomp : int - Flag indicating format of the covariance matrix within the ENDF file mpar : int Number of parameters in covariance matrix for each individual resonance + lcomp : int + Flag indicating format of the covariance matrix within the ENDF file + file2res : openmc.data.ResonanceRange object + Corresponding resonance range with File 2 data. formalism : str String descriptor of formalism + """ - def __init__(self, energy_min, energy_max, parameters, covariance, mpar, lcomp): + def __init__(self, energy_min, energy_max, parameters, covariance, mpar, + lcomp, file2res): super().__init__(energy_min, energy_max) self.parameters = parameters self.covariance = covariance self.mpar = mpar self.lcomp = lcomp + self.file2res = copy.copy(file2res) self.formalism = 'mlbw' @classmethod - def from_endf(cls, ev, file_obj, items, file2params): + def from_endf(cls, ev, file_obj, items, resonance): """Create MLBW covariance data from an ENDF evaluation. Parameters @@ -455,9 +437,8 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): items : list Items from the CONT record at the start of the resonance range subsection - file2params : openmc.data.ResonanceRange object - Corresponding resonance range with File 2 data. Used for - reconstruction method + resonance : openmc.data.ResonanceRange object + Corresponding resonance range with File 2 data. Returns ------- @@ -520,7 +501,8 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): parameters = pd.DataFrame.from_records(records, columns=columns) # Add parameters from File 2 - parameters = _add_file2_contributions(parameters, file2params) + parameters = _add_file2_contributions(parameters, + resonance.parameters) # Compact format - Resonances and individual uncertainties followed by # compact correlations @@ -567,7 +549,8 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): mpar = int(covsize/nparams) # Add parameters from File 2 - parameters = _add_file2_contributions(parameters, file2params) + parameters = _add_file2_contributions(parameters, + resonance.parameters) elif lcomp == 0: cov = np.zeros([4, 4]) @@ -609,10 +592,12 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): mpar = int(covsize/nparams) # Add parameters from File 2 - parameters = _add_file2_contributions(parameters, file2params) + parameters = _add_file2_contributions(parameters, + resonance.parameters) # Create instance of class - mlbw = cls(energy_min, energy_max, parameters, cov, mpar, lcomp) + mlbw = cls(energy_min, energy_max, parameters, cov, mpar, lcomp, + resonance) return mlbw @@ -638,18 +623,20 @@ class SingleLevelBreitWignerCovariance(MultiLevelBreitWignerCovariance): Resonance parameters covariance : numpy.array The covariance matrix contained within the ENDF evaluation - lcomp : int - Flag indicating format of the covariance matrix within the ENDF file mpar : int Number of parameters in covariance matrix for each individual resonance formalism : str String descriptor of formalism + lcomp : int + Flag indicating format of the covariance matrix within the ENDF file + file2res : openmc.data.ResonanceRange object + Corresponding resonance range with File 2 data. """ def __init__(self, energy_min, energy_max, parameters, covariance, mpar, - lcomp): + lcomp, file2res): super().__init__(energy_min, energy_max, parameters, covariance, mpar, - lcomp) + lcomp, file2res) self.formalism = 'slbw' @@ -680,21 +667,24 @@ class ReichMooreCovariance(ResonanceCovarianceRange): Flag indicating format of the covariance matrix within the ENDF file mpar : int Number of parameters in covariance matrix for each individual resonance + file2res : openmc.data.ResonanceRange object + Corresponding resonance range with File 2 data. formalism : str String descriptor of formalism """ def __init__(self, energy_min, energy_max, parameters, covariance, mpar, - lcomp): + lcomp, file2res): super().__init__(energy_min, energy_max) self.parameters = parameters self.covariance = covariance self.mpar = mpar self.lcomp = lcomp + self.file2res = copy.copy(file2res) self.formalism = 'rm' @classmethod - def from_endf(cls, ev, file_obj, items, file2params): + def from_endf(cls, ev, file_obj, items, resonance): """Create Reich-Moore resonance covariance data from an ENDF evaluation. Includes the resonance parameters contained separately in File 32. @@ -709,7 +699,7 @@ class ReichMooreCovariance(ResonanceCovarianceRange): items : list Items from the CONT record at the start of the resonance range subsection - resonances : openmc.data.Resonance object + resonance : openmc.data.Resonance object openmc.data.Resonanance object generated from the same evaluation used to import values not contained in File 32 @@ -773,7 +763,8 @@ class ReichMooreCovariance(ResonanceCovarianceRange): parameters = pd.DataFrame.from_records(records, columns=columns) # Add parameters from File 2 - parameters = _add_file2_contributions(parameters, file2params) + parameters = _add_file2_contributions(parameters, + resonance.parameters) # Compact format - Resonances and individual uncertainties followed by # compact correlations @@ -813,10 +804,12 @@ class ReichMooreCovariance(ResonanceCovarianceRange): mpar = int(covsize/nparams) # Add parameters from File 2 - parameters = _add_file2_contributions(parameters, file2params) + parameters = _add_file2_contributions(parameters, + resonance.parameters) # Create instance of ReichMooreCovariance - rmc = cls(energy_min, energy_max, parameters, cov, mpar, lcomp) + rmc = cls(energy_min, energy_max, parameters, cov, mpar, lcomp, + resonance) return rmc From 8c320cf1a4de39a43290cdfc388325475909c549 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Mon, 23 Jul 2018 17:10:49 -0500 Subject: [PATCH 086/100] Changed tests to reflect changes in module --- tests/unit_tests/test_data_neutron.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/tests/unit_tests/test_data_neutron.py b/tests/unit_tests/test_data_neutron.py index 0ed3e92f77..f793c2e12b 100644 --- a/tests/unit_tests/test_data_neutron.py +++ b/tests/unit_tests/test_data_neutron.py @@ -295,13 +295,11 @@ def test_mlbw_cov(ti50): assert cov.energy_max == pytest.approx(587000.) assert cov.covariance[0,0] == pytest.approx(1.410177e5) - cov.res_subset('L',[1,1]) - subset = cov.parameters_subset - assert not subset.empty - assert cov.cov_subset is not None - assert (subset['L'] == 1).all() - cov.sample_resonance_parameters(1, res) - xs = cov.samples[0].reconstruct([10., 100., 1000.]) + subset = cov.res_subset('L',[1,1]) + assert not subset.parameters.empty + assert (subset.file2res.parameters['L'] == 1).all() + samples = cov.sample_resonance_parameters(1) + xs = samples[0].reconstruct([10., 100., 1000.]) assert sorted(xs.keys()) == [2, 18, 102] @@ -316,13 +314,13 @@ def test_rm_cov(gd154): assert cov.energy_max == pytest.approx(2760.) assert cov.covariance[0,0] == pytest.approx(0.8895997) - cov.res_subset('energy',[0,100]) - subset = cov.parameters_subset - assert not subset.empty - assert cov.cov_subset is not None - assert (subset['energy'] < 100).all() - cov.sample_resonance_parameters(1, res) - xs = cov.samples[0].reconstruct([10., 100., 1000.]) + subset = cov.res_subset('energy',[0,100]) + assert not subset.parameters.empty + assert (subset.file2res.parameters['energy'] < 100).all() + samples = cov.sample_resonance_parameters(1) + print(samples) + print(samples[0]) + xs = samples[0].reconstruct([10., 100., 1000.]) assert sorted(xs.keys()) == [2, 18, 102] From 6b828523feed6100f7befdb00179405c01b934e9 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 24 Jul 2018 09:23:32 -0500 Subject: [PATCH 087/100] Removed print statements from test --- tests/unit_tests/test_data_neutron.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/unit_tests/test_data_neutron.py b/tests/unit_tests/test_data_neutron.py index f793c2e12b..66181c4eed 100644 --- a/tests/unit_tests/test_data_neutron.py +++ b/tests/unit_tests/test_data_neutron.py @@ -318,8 +318,6 @@ def test_rm_cov(gd154): assert not subset.parameters.empty assert (subset.file2res.parameters['energy'] < 100).all() samples = cov.sample_resonance_parameters(1) - print(samples) - print(samples[0]) xs = samples[0].reconstruct([10., 100., 1000.]) assert sorted(xs.keys()) == [2, 18, 102] From 8c70101849a66c644408cd624802bd5a51f692f7 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 25 Jul 2018 06:30:26 -0500 Subject: [PATCH 088/100] Clarify enforcement in code of conduct --- CODE_OF_CONDUCT.md | 7 +++++-- CONTRIBUTING.md | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 5aa0bcd34a..d29d42adc4 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -58,8 +58,11 @@ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at openmc@anl.gov. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to -maintain confidentiality with regard to the reporter of an incident. Further -details of specific enforcement policies may be posted separately. +maintain confidentiality with regard to the reporter of an incident. However, +note that some project team members may have a legal obligation to report +certain forms of harassment because of their affiliation (for example, staff and +faculty at universities in the United States). Further details of specific +enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d02a543f87..92f8d0870d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,7 +28,7 @@ OpenMC is hosted on GitHub and all bugs are reported and tracked through the We welcome suggestions for new features or enhancements to the code and encourage you to submit them as Issues on GitHub. However, it's important to -recognize that our development team is relatively small are does not have +recognize that our development team is relatively small and does not have unlimited time to devote to new feature suggestions. If you are interested in working on the feature you are requesting, indicate so in the issue and the development team will be happy to discuss it. From 78a411ebb7e4e87b090d8e1b29c80116d5e322fc Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Wed, 25 Jul 2018 09:41:54 -0500 Subject: [PATCH 089/100] Fix of sampling routine, change dataframe .as_matrix to .values --- .../nuclear-data-resonance-covariance.ipynb | 162 +++++++++--------- openmc/data/resonance.py | 4 +- openmc/data/resonance_covariance.py | 69 +++++--- 3 files changed, 132 insertions(+), 103 deletions(-) diff --git a/examples/jupyter/nuclear-data-resonance-covariance.ipynb b/examples/jupyter/nuclear-data-resonance-covariance.ipynb index b8c1764cf5..876cf4daba 100644 --- a/examples/jupyter/nuclear-data-resonance-covariance.ipynb +++ b/examples/jupyter/nuclear-data-resonance-covariance.ipynb @@ -208,7 +208,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 5, @@ -217,9 +217,9 @@ }, { "data": { - "image/png": "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\nIiq5Enr3y8wuN7OTzOwUqk1VPmZmPwl8nGrHKZjTfY2nTZjoaI47bH5pY+9jVmIunphK1nS1TlN1\nxSzBmNxNhRQqp5L+tz2P2PlQcTeVRqx86pXqb9iXnOKNlS19dm2fgZx8uXrCz99QxnaNJZ0n6XZJ\neyVdFrl+WD3yZG89EuWU4PrTJd0v6dd6d6pmGgr+dcBr6p2njqHaiWrlCD+cuV//Lr/Y03J924h9\nqVeRPs8gpuBiFt4Y8qTqGet/N5YilLQBeAdwPnA68ApJpwfFLgLuNbPTqLbrfFtw/Srgf/fryeMZ\nJcFjZjcAN9Tv7wDOGKPeZSL2QYy5ol0/sH3rKHGNY1/cMb5Qfa2U0i992FZp2RL6yt4mx1iW25gW\nYMjIc43PAPbW+gJJ1wBbgM83ymwB3lS//wDwe5JU7238UuAO4J/GEGZZXX7HcaaApKIXsGkyKqR+\nXRxUdSLw1cZxbITJo2XqnMN9wDGSnkzlef76WP1axCE/C0n4S52L++VoixHG2iqpZ4hMXelbd8xK\n7dPPWZNK9IxVdxfLeBASbCxUGQ8/fI+ZreVqi5wLR5ikyvw61aSN+2ulOxhXhDOiqxuacndzH/xp\nxg/nQaHMA31d+mn9b2b+fylXhG0l9gEnN45jI0wmZfZJ2gg8FTgAPB94maTfAI4EHpH0oJn9Xplw\nT8QV4YyJDSsJz+fIKdRYYmZIzCg1fCQs0yZ3WE+p0m+jS7+aMpTeN1YSq6sS7CrjzJRhF4uwnZuA\nzZJOBb5GNfLklUGZ7VQjTz5JNRLlY2ZmwL99TCS9Cbh/iBIEV4QzJ6as2pRNSX3TJGfRlFiqoaLu\n006MPkqg67MtlWdMq29ure9DDoHDDy8r+4//mL1sZgclXQpcR7Vy1zYz2y3pCmCXmW2nGnHyh/UI\nlANUynIquCJ0HKeMcS1CzGwHsCM494bG+weBl7fU8aYxZHFFuE6UBv1zrnDI0KB8Lm45LboMiRki\nz3oOn4lZi2M93z5DigYxoiKcJ5azVwtELH7WJW7W9QsVKx+LnZUq6j5xtJJ4YtdrJW1PQ/Gsdz19\nMum9GdkinCeWs1cLRMxaGDrLIKechliIYRuls03asuJjzaooZRoKNTZTqOT/MbZ8U8UVoTNNcpnY\nLlnkti9cV6sul+To4rJ3qaeLa9xFYYw1RjLXx5TFm1KcKZmGJMtKQyy9cEXozJJUZjlG1+EzKStv\n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\nUQAAAABJRU5ErkJggg==\n", + "image/png": "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\n", "text/plain": [ - "" + "
" ] }, "metadata": {}, @@ -246,7 +246,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 6, @@ -255,9 +255,9 @@ }, { "data": { - "image/png": "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\nOEtDAAAAAElFTkSuQmCC\n", + "image/png": "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\n", "text/plain": [ - "" + "
" ] }, "metadata": {}, @@ -370,51 +370,51 @@ " \n", " \n", " 0\n", - " 0.0314\n", + " 0.031892\n", " 0\n", " 2.0\n", - " 0.000474\n", - " 0.1072\n", + " 0.000477\n", + " 0.106883\n", " 0.0\n", " 0.0\n", " \n", " \n", " 1\n", - " 2.8250\n", + " 2.825068\n", " 0\n", " 2.0\n", - " 0.000345\n", - " 0.0970\n", + " 0.000333\n", + " 0.101242\n", " 0.0\n", " 0.0\n", " \n", " \n", " 2\n", - " 16.2400\n", + " 16.255167\n", " 0\n", " 1.0\n", - " 0.000400\n", - " 0.0910\n", + " 0.000433\n", + " 0.102033\n", " 0.0\n", " 0.0\n", " \n", " \n", " 3\n", - " 16.7700\n", + " 16.768821\n", " 0\n", " 2.0\n", - " 0.012800\n", - " 0.0805\n", + " 0.013301\n", + " 0.079907\n", " 0.0\n", " 0.0\n", " \n", " \n", " 4\n", - " 20.5600\n", + " 20.559310\n", " 0\n", " 2.0\n", - " 0.011360\n", - " 0.0880\n", + " 0.012069\n", + " 0.075562\n", " 0.0\n", " 0.0\n", " \n", @@ -423,12 +423,12 @@ "" ], "text/plain": [ - " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.0314 0 2.0 0.000474 0.1072 0.0 0.0\n", - "1 2.8250 0 2.0 0.000345 0.0970 0.0 0.0\n", - "2 16.2400 0 1.0 0.000400 0.0910 0.0 0.0\n", - "3 16.7700 0 2.0 0.012800 0.0805 0.0 0.0\n", - "4 20.5600 0 2.0 0.011360 0.0880 0.0 0.0" + " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", + "0 0.031892 0 2.0 0.000477 0.106883 0.0 0.0\n", + "1 2.825068 0 2.0 0.000333 0.101242 0.0 0.0\n", + "2 16.255167 0 1.0 0.000433 0.102033 0.0 0.0\n", + "3 16.768821 0 2.0 0.013301 0.079907 0.0 0.0\n", + "4 20.559310 0 2.0 0.012069 0.075562 0.0 0.0" ] }, "execution_count": 8, @@ -486,51 +486,51 @@ " \n", " \n", " 0\n", - " 0.0314\n", + " 0.033649\n", " 0\n", " 2.0\n", - " 0.000474\n", - " 0.1072\n", + " 0.000480\n", + " 0.103631\n", " 0.0\n", " 0.0\n", " \n", " \n", " 1\n", - " 2.8250\n", + " 2.829673\n", " 0\n", " 2.0\n", - " 0.000345\n", - " 0.0970\n", + " 0.000332\n", + " 0.099803\n", " 0.0\n", " 0.0\n", " \n", " \n", " 2\n", - " 16.2400\n", + " 16.222978\n", " 0\n", " 1.0\n", - " 0.000400\n", - " 0.0910\n", + " 0.000331\n", + " 0.071241\n", " 0.0\n", " 0.0\n", " \n", " \n", " 3\n", - " 16.7700\n", + " 16.765241\n", " 0\n", " 2.0\n", - " 0.012800\n", - " 0.0805\n", + " 0.012566\n", + " 0.080448\n", " 0.0\n", " 0.0\n", " \n", " \n", " 4\n", - " 20.5600\n", + " 20.566440\n", " 0\n", " 2.0\n", - " 0.011360\n", - " 0.0880\n", + " 0.011168\n", + " 0.088066\n", " 0.0\n", " 0.0\n", " \n", @@ -539,12 +539,12 @@ "" ], "text/plain": [ - " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.0314 0 2.0 0.000474 0.1072 0.0 0.0\n", - "1 2.8250 0 2.0 0.000345 0.0970 0.0 0.0\n", - "2 16.2400 0 1.0 0.000400 0.0910 0.0 0.0\n", - "3 16.7700 0 2.0 0.012800 0.0805 0.0 0.0\n", - "4 20.5600 0 2.0 0.011360 0.0880 0.0 0.0" + " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", + "0 0.033649 0 2.0 0.000480 0.103631 0.0 0.0\n", + "1 2.829673 0 2.0 0.000332 0.099803 0.0 0.0\n", + "2 16.222978 0 1.0 0.000331 0.071241 0.0 0.0\n", + "3 16.765241 0 2.0 0.012566 0.080448 0.0 0.0\n", + "4 20.566440 0 2.0 0.011168 0.088066 0.0 0.0" ] }, "execution_count": 9, @@ -572,8 +572,8 @@ { "data": { "text/plain": [ - "[,\n", - " ]" + "[,\n", + " ]" ] }, "execution_count": 10, @@ -604,9 +604,9 @@ }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYgAAAEOCAYAAACTqoDjAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4wLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvpW3flQAAIABJREFUeJzt3Xec23X9wPHXO+Mud920hUJbaKGL\nPSzQCihbEFqgIJYhG+THUpayZIkDBUUURZANFgFZFRSEsmS27EKFlgJtwdJBWzouySV5//7IN3e5\nXHKZ33yTu/fz8QiXfPMd70uP7zufLaqKMcYYk8nndQDGGGNqkyUIY4wxWVmCMMYYk5UlCGOMMVlZ\ngjDGGJOVJQhjjDFZWYIwxhiTlSUIY4wxWVmCMMYYk1VdJggRmSQiN4nIJK9jMcaY7krqeaqNQYMG\n6YgRI7wOwxhj6srrr7++TFUH59svUI1g3DJixAhmzZrldRjGGFNXROTTQvaryyomY4wx7rMEYYwx\nJqu6TBCpRupVq1Z5HYoxxnRbdZkgVHW6qp7Sr18/r0Mxxphuqy4ThDHGGPdZgjDGGJOVJQhjjKmi\nBR++z8vTH/I6jILUZYKwRmpjTL164udv8cZj9dF+WpcJwhqpjTH1Khoa4nUIBavLBGGMMcZ9liCM\nMcZkZQnCGGNMVpYgjDHGZGUJwhhjTFZ1mSCsm6sxxrivLhOEdXM1xhj31WWCMMYY4z5LEMYYY7Ky\nBGGMMSYrSxDGGGOysgRhjDEmK0sQxhhjsrIEYYwxJitLEMYYY7KqywRhI6mNMcZ9dZkgbCS1Mca4\nL+B1AMYY0xPcc+FP2PJb36SevpfXT6TGGFOiW0+7iBtOncGKpYs9uf6q5ctYuWIPZt6xzJPrl8oS\nhDGm24tGJgCwdOECT66fSMSScTSuX/Sxd553MX859pZKh1QQq2IyxpgatnrNXtDkzbWtBGGM6TES\nqmWf49Zjf8UNp86oQDS1zxKEMabbkwqeq6VpfMXO9dTdt3P7WRdW7HyVZgnCGGNKtGr5MmZMu7Pk\n4z/4z8asje5TwYgqyxKEMabH0Hisouf7+7k3Mee5Ybzz4jMVPW+tsARhjDElijMSgC8/+9zjSNxh\nCcIY02OI3zpuFsMShDGmx6h0FVNKIpHo8n2frz4TU80kCBHZXERuFJEHROT/vI7HGNOdJLu3tsbc\nSRDdlasJQkRuFZElIjI7Y/t+IvKBiMwTkQsAVHWOqp4KHA5Urh+ZMcakaNff9Evl83V9K02NpK43\nbpd7bgf+ALT1AxMRP3ADsA+wCJgpIo+q6vsiMhm4wDnGGE+tWr6MZ+6+i5XzlpJYE0LjA1DphUoj\nQgLRdYhvKYH1Wtj1hO+y6ZbbeB2yyUMTyZLE7WdcRON6DRxx5eUVOW++KqZ65WqCUNXnRWRExuad\ngHmqOh9ARO4FDgLeV9VHgUdF5DHgr9nOKSKnAKcAbLzxxi5FbnqixZ9+xAt//Rur57eg0aFEG0aQ\n8G8LgC8QIZhYguhqhBWgfpBeRP3b07K2iX/97n80Rh9j6yO3Zqd9D/T4NzG5aDx5I18b25u1Sypy\nxkqcpGZ50XIyFFiY9noRsLOI7A5MARqBx3MdrKo3ATcBjB8/vnv/6xhXzXt7FjP//g9aFkEivjHR\nxuGobwL4EjSyiMbYazSuH2PcnhPZ9ht7EwgGO50jGg7zxC1/ZunM1YQbduT1+5X3p1/E0b+5Iuv+\nxluV/6Zf2Bjtem2k9iLqbJ+oquqzwLPVDcX0JG89+xSz//ks0S9CJNiESGgo8A0k0Epj/FNCiRfo\nNSzIxKmHsvGYvQs6Z0MoxKTTfwDAK/98lPemLWCtf2/uOOk3HP6779Onf38XfyNTLNW41yHUFS8S\nxCJgeNrrYUBRo0xEZBIwadSoUZWMy3Qjs1/+D7P/PYN1C6NoZBDxwHBaGwYAe+ILhmmIfExT4r/0\nH9efbx55JAOHfKvsa07YfzI77BHm7jOvoqVpT+47604O++2R9Bs4qPxfyFREIlHpSofCzmeN1IWb\nCYwWkZHAZ8BU4MhiTqCq04Hp48ePP9mF+EydiIbDzH7peT56ZRZrPl+NrumF6iBi/g2INfQDdgU/\nNPgW44/PJ+hbweBtNmKPI79Hr77fdiWmhlCIE26+itvPvIi1zXvz93Nu5eg/n0VDKOTK9UyhkhUX\n6lIvpu7K1QQhItOA3YFBIrIIuExVbxGRM4AnAD9wq6q+52Ycpv4sX/wZ8999myUff8KaxcsJr2gh\nvsaPRptB+5Pwr0drsD/qCwLJxWD8gRYCrYsJJj6gQb6i76b92fGgA9l4zJ5Vj/+43/+cW0+5hJam\nPbn7rJ9ywk0/q3oMprNE3BJEMdzuxXREju2P00VDdD5WxVR7ouEwq75cyqrly1i7cgXrVq6iZe0a\nImvWEm1pIbqmheiaCPGWVuJR0KhAPACJIJpoBG0EaSbh603c34d4oAkIAePaL+JLEPR/hS++Al9i\nIaH4+/gaW+k1tA+jJ+zIVrvsW1MNw8fccBl3nHQdLaE9+Ps1v+LQ837kdUg9ntZRd9T7f/kLRk/Y\nES/HM9dl03q5VUwP/OqXfDV3bZYTp57k6JmgqR+Sfa8cx2vG67ZXmv06nfbP3M95qZrjvKnidNuO\nzlYR5xhf8pH+nPTnPhAfmv6e+AFf8pziR/GjvgAqQRK+gPNNPl0/55GDD3waxUcYH2EkEUa0BV9i\nIX5awBfB36QE+wZpHtiPQSOHs/Wue9RVfX4gGGTfSybzr5+9wfL3N+OT/85mxLitvA6rZ6t4G4R7\nlnyyM1/OXQ3BPp7FUJcJolxfzV1Li3+P7G92qqNM/kGJdnyd2TglnVaqyv660P1w9pO8+2WcP9d+\nbXHGgQRoAhEF4s7vnCCZUpznGmt/jrbtI5JwYosjxJx9nXP4E4hPEb8iAcHX4MMf9ONvCBBoaqR5\nQF/6Dh7MwGHD2GDjTRgweAjd3fDRYxmy05MseHtzZlz9MCfcZgnCS64NaKvASnXZxDxMDlCnCaLc\nKqZj/nhp2/NaqpIw3dOk087klhOuoKVxNx78za+Zcs75XofUYyneVDE9ds0fgOq3hZWrZibrK4aq\nTlfVU/r166IKowuBYLDtYUw1HHDZ0QQjy/ny7Q1oWZuletNUhcZdqmKSrgfMrVqVPznc9aNLuOHU\nGSxZ+GmloipbXSYIY+rNkE02o2n9t4k0DeO+S6xHk1cUlwbKVaCKKbw0Wf3435kvlX2uSrEEYUyV\nHHHVZTS2fExk1Xg+/3iu1+H0SFpHjdSZYq2tVb9mXSYIEZkkIjetWrXK61CMKVggGGTQ9qtobejP\nv35xu9fh9Ej1nCC8UJcJotw2CGO8cvAPzyG0bjbR+M4s+PB9r8PpMVJpoZam5Z4x7c78O3msLhOE\nMfVs/QlCPNibp665x+tQeh6XuqOWYsncT7Jur6VSjiUIY6ps0mlnElr3HtH4ziyc+4HX4fQotTSS\nWjoNte06MSTi1Z+Jti4ThLVBmHq3/s4J4sHe/Pva2q9m6E5qqAABvswEUdjaEtVUlwnC2iBMvZt0\n+g8IrZtDLPo1Vi1f5nU4PYYmamc9iFxDJ6RT4vBOXSYIY7qD3mNW0NrQn0d+9huvQ+kxtKaKEMUl\ngrhTxXTDqTO45djfuhFQJ5YgjPHIoT/+MY3hz4h+ubknfdx7olpqAJY8o6+7Em7atoKR5GYJwhiP\nBIJBggPmEAkN5cFfXe11OD2CWyUITSR4efpDrF65svCDck0aXUNJzBKEMR6afNFZBKKrWP3BAK9D\n6RHc6sW04rPFvPFYP+47+/clHb/gw/eJNq5f4ajKV5cJwnoxme5iwOAhNARnEW7enKfuvt3rcLo9\nt0oQkVXrAEjoZoUflFbF9O4zz+TdPRGv/rrWdZkgrBeT6U4mnjIZSbSy4KlFXofSfUlqTWqXqm9K\nOO/az1Zn3W69mIwxbcZ9bWcaI28RCe5g02+4reIJovTzxVcNrWAc7sibIERkoojcICLviMhSEVkg\nIo+LyOkiYl/hjamA9XduJuEP8fT1d3kdSrdW+RJE5b/t52qkTnjQeN1lghCRfwInAU8A+wEbAlsA\nl5BcUf4REZnsdpDGdHeTTjuTxpZPiK3Zyrq8uqiWegjVg3wliO+p6omq+qiqfq6qMVVdo6pvqOq1\nqro7UDurWxhTxxoGziMa2pCHrr3G61C6r05rzpd9wgqfr7Z0mSBUtW0OABEZIiKTnR5EQ7LtUy3W\ni8l0Rwf86HQCrWv4ak7I61C6rcqXICpfxTT7qSE8cdvNFT9vKQpqpBaRk4DXgCnAYcArInKCm4F1\nxXoxme5o4JChBHmdcGhrZv77ca/D6Za0Tr7xz3u1c3fZWu7mej6wvaoep6rHAl8DfuxeWMb0TJtP\n2R6Ad//2iseRdE/l1DC98OB93HJsbXyzr5ZCE8QiIL3T7mpgYeXDMaZnm3jAwYRa3qc1sYPN8uqG\nMnoxffjIp4SbcgyEK2NeJYDw6rVlHe+WfL2YzhGRc4DPgFdF5HIRuQx4BZhXjQCN6Wl6bbaSWENf\npv/qOq9D6X48GCh357kX5z188dzt8+6TSNReFVMf5/ER8DDtTfaPAP9zMS5jeqyDzjuXhsgyIouH\nex1KN+KMpHarDaKLEsTqtXvlOijtqb+y8VRIoKs3VfWKagVijElq6tULf+PbtLAXT99zO3sddZzX\nIXUbtbUeRHk+/3guG40c7eo18lUx3SQiW+V4r5eInCAiR7kTmjE918QTvo0kWvnkKWvqqyTXBspV\nIfFkrkkdj7m/vna+KqY/ApeKyBwRuV9E/igit4rICyQHyPUBHnA9SmN6mM132oXGyNu0+nfg84/n\neh1O99F9ChBVka+K6S3gcBHpDYwnOdVGCzBHVT+oQnzG9FgDt/Pz2QdNPHndbRz3u597HU63oGWN\npO4iu5TUi6m8nk+q7q+vXVA3V2d6jWdVdZqqPux1crCR1KYnOPCMs2gMLyK2cqzNz1QpZVUF1c40\n3NVSl9N920hq0xMEgkECfeYQaRrOYzf+wetwuoV6bqNOuLQaXlfqMkEY01PsddZx+GMtLJsV9TqU\n7qGsDFHH2aVEliCMqWHDR4+lIfYmkcbt+O/rr3odTv2r0j3+ttMu4ubj/urqNapRoih0sr4xInKz\niDwpIjNSD7eDM8bA8D03RH1BXv7LI16HUveqNQ5iXWJvoqEh+XcsgsarX8XUZS+mNPcDNwI3A+43\nnRtj2uxzzIksePomYr5tiYbDNIRsOvDSubTkaBUWIqrFqTZSYqr6J1V9TVVfTz1cjcwY06ZhyAKi\njYN56BpbTKgclS5AVLNfUy03Uk8XkdNEZEMRWS/1cDUyY0ybyT/6IYHWr1jzYR+vQ6lvFfymX+2u\nx9UYOZ2p0ARxLMk1IV4CXnces9wKyhjTUb+BgwjyBuGmLXntyX94HU7dquRkfcmpL9Q5r/uqMTAu\nU6ED5UZmeWzqdnDGmHZbHDYegNn3veZxJHWsgnfy1mik/UUVvtzXbBWTiARF5CwRecB5nCEiQbeD\nM8a0m7D/ZFtMqFwVbIRIJJT2jFONyfpqNEEAfyK5zOgfncfXnG3GmCrqNcoWEypHJRupy14jusj5\nmxKJjlVM1UgYhSaIHVX1WFWd4TyOB3Z0MzBjTGdTfvQjW0yoRpTd7bTYZJWo0TYIIC4ibYuxisim\nuDAeQkQOdgbkPSIi+1b6/MbUu4ZQiEDj24SbRvP0Pbd7HU79qWQVU5UbqWu5iul84BkReVZEngNm\nAOcWcqCzfsQSEZmdsX0/EflAROaJyAUAzkyxJwPHAd8t+LcwpgeZYIsJlcBZcrSMBJFZIdSh0bgK\nGSLhwUyDhfZiehoYDZzlPMaq6jMFXuN2YL/0DSLiB24A9ge2AI4QkS3SdrnEed8Yk2HznXYhZIsJ\nlaaMe2zmoRpPVHX+Ps1o88hsk3BDviVH93R+TgEOAEYBmwEHONvyUtXngS8zNu8EzFPV+aoaBe4F\nDpKkq4F/quobxf0qxvQc620fIB5ILiZkClfRRupEjLYqplJOXGgjtbPIUTyuzH/vneKvU4Z8JYhv\nOj8nZXkcWMZ1hwLp5eNFzrYzgb2Bw0Tk1GwHisgpIjJLRGYtXbq0jBCMqV8Hnn6mLSZUEneqmKSk\n0xbZi0njzH+zut+b8y05epnz9EpV/Tj9PREZWcZ1s30yqqrXA9fniekm4CaA8ePH97wJ2o3BWUyo\n7xzWRvfhsRv/wEFnnu11SPWhgkWI5NQX1Wikds5e1nKppSm0kfrvWbY9UMZ1FwHp/fSGAZ8XerAt\nOWoM7Hv2CbaYULEqeCcvf+qLwkoQ0pYflAXPfVTmNYuTrw1inIgcCvQTkSlpj+OAcuYcngmMFpGR\nItIATAUeLfRgW3LUGNho5GiC8TdsMaEiVPKbfvWmvkhGPeuWl2nx71GlayblK0GMJdnW0J+O7Q87\nACcXcgERmQa8DIwVkUUicqKqxoAzgCeAOcB9qvpeab+CMT3XJnsNt8WEPNKh7acKbRDh0MRSLlKW\nfG0QjwCPiMhEVX25lAuo6hE5tj8OPF7KOUVkEjBp1KhRpRxuTLex99HH8emTfybmt8WEClLJL/1p\n3Uy1hGnEteAEkePcXndzTXOqiPRPvRCRASJyq0sx5WVVTMa0a9hwoS0mVLBKjqRub6TurgpNENuo\n6srUC1VdAWzvTkjGmGLYYkKFq+g4CE2fzTW7l6c/1MW7hTZSe5eECk0QPhEZkHrhrCZX6HrWFWe9\nmIxp12/gIIKSXEzohQfv8zqcGuV0R63ginKZI5uzWfjO+128W80FS0tTaIK4FnhJRH4qIleSXFnu\nV+6F1TWrYjKmo/HH74FonLmPfuh1KDXKSQwVTBDxeNq5crZtdHW98hJEzUz3rap3AocCXwBLgSmq\nepebgRljCrfNLnvQGH2DSHC8dXnNIlVNo4nKrSWd0PbZXHNZ/WElOg3UfhUTwHrAWlX9PbC0zJHU\nxpgKG/mtoST8Dbx043SvQ6lByW/bFa3OL2Bkc7hphwpesPoKXXL0MuDHwIXOpiBwt1tBFRCPtUEY\nk2HPI44htG42rYkdWfq5TQXeQSozJFLrOJRwioxv8untGaVNI15eN1efv5jv96Up9AqHAJOBtQCq\n+jngWZcJa4MwJrv+W4eJBfvw2NW2InA6SZt1NV5igpCMG7rGE23nRUtpTyivF1PNtEEAUdX2Pl0i\n0su9kIwxpTroh2fT2PIprau2JhoOex1ODUmVICrXcyg51UYZdVa134mp4ARxn4j8GegvIicDTwE3\nuxeWMaYUgWCQ0JCPiIY24IGf/cLrcGpHqpEaSBTQPTXrKTKrmKo0WZ+XCu3FdA3J2Vv/TnJ+pkud\nxmpjTI055OLzaYgsY92CjW2tCIc4jdSikKhQV9cOVVVVmIvJC4U2UvcCZqjq+SRLDk0iEnQ1sq7j\nsUZqY3Lo1bcfwd5vEWkayUPX/NrrcGqKqpRcgsiUPtVGKflBC67AydEGUYUR1oVG+DzQKCJDSVYv\nHU9yrWlPWCO1MV2bdPHpBKMr+WrOel6HUiPaezFV7IzlTvdd6JKjHio0QYiqrgOmAL9X1UOALdwL\nyxhTjoFDhhIMzSLcPIaHfmuT+LVlBhVnLelKnDLtG3xJX+b9lYnDRQUnCBGZCBwFPOZs82wuJmNM\nfgdc+H0CrV/x5ZtNXofivbYbuHQYB1FOG00ikWgfX1FCgii8iinH8RWqKutKoRH+gOQguYdU9T0R\n2RR4xr2wjDHlWn/4JjQEZxJu3pzpN/zO63C8larNyRivEGlZV/Iptdz6qu5SxaSqz6vqZFW92nk9\nX1XPcje03KyR2pjC7H3uMfhb17Dk1dq/Gbkr+furSoelQsPr1rBq+TJuOebGopOoxrWsjkjajaqY\naoo1UhtTmOGjx9Lge41w81Y89ucbvA7HQ8k7uWhyBHRKayTMiw/eT7h5DF+8NiDXwcljJWMcBPEO\n4yuKD6m8Xkzid7+Wvy4ThDGmcHueOxV/6xoWv9i9Vz8rhOLr0EgdjUSQAqt6MudbSp+LSUppgyg4\nQeQ4vobaIIwxdWrEuK1obHiFcPMW/P3Xni3j4rFUCaJjMoiW0waRKLOKqdAEUesryonIr0Skr4gE\nReRpEVkmIke7HZwxpjIO/Mn/EYyuZOXsAT16dLXSsQ2iNRJpfzPfzT7j/Q69mEpS+9/PC41wX1X9\nCjgQWASMAc53LSpjTEUN3mg4Db1nEm7ajPuv+rnX4VSdppUg4rG0BNEaRXyp22DXGUIy2wLSk0MJ\ns7lqd+nFRHL9B4BvA9NU9UuX4jHGuOTQK39MQ2Qpaz8d2fNmenVuxop0mGQvFmktuA0is7E4fbrt\nkqbaKLCKKR7snX17vHam2pguIv8FxgNPi8hgwLO/MOvmakzx+vTvT+Ogd4iEhnHvJT/1OpwqSyWB\njre8aKT025gmypzNVbpJN1dVvQCYCIxX1VaSCwcd5GZgeeKxbq7GlGDqT39CY8sCwl/uwJKFn3od\nTtVJRhtEPNqK+ArsxZT5un2JnLReTLVfbVSMQhupvwPEVDUuIpeQXG50I1cjM8ZUXEMoxICtl9Da\nMIB/XNmTlnRJGyiXVjUUj0c77ZPzDJnjIBLtCaLAU9SdQquYfqKqq0VkV+BbwB2ArWloTB069Lwf\nEWp5kwi78PrT//Q6nCrreMvr2AaR5+7eqY1aSU0CqFrgOSooUfaCRfkVmiBSkRwA/ElVHwEa3AnJ\nGOO2LQ7bFBUfb9/5rtehVIWmtUEk0toO4q2tiK+0toDkpH/ts8Qmda8iRKEJ4jNnydHDgcdFpLGI\nY40xNWbipEMIxV+kpWk8j/7+Oq/DqQLnxq0BSEsQrZH2KqZ8fYJUMnsxeZsgfFVo5C70Jn848ASw\nn6quBNbDxkEYU9f2ueAogtGVLJnVn7VfdfMegW33bX/HNohotORJVeOtrSAdE4T2xBKEs1jQR8C3\nROQMYH1VfdLVyIwxrho+eizNg98k0rQx911wtdfhuCx14+44wV0s2ppln1xn6FiCiLfGaG+DcG6l\nVRz8Fo9F8+9UpkJ7Mf0AuAdY33ncLSJnuhmYMcZ9U6+6lNC69wi37srMfz/udTjuE3+HtZxjkda0\nkdTFSaQlCPGgiikWjeTfqUyFfjInAjur6qWqeikwATjZvbCMMdUQCAbZ4jvDAB/v3PWh1+G4JlX1\nowQ7zIKaiMZK/tafiCVoX+S6sOk6Kikarp0EIbT3ZMJ57lllm42kNqZyJk46hJD/BcLN23DPxZd5\nHY47Ukkgo2G3ZVn6bK7F3dISsTgiqSqm6o+KjkVqpIoJuA14VUQuF5HLgVeAW1yLKg8bSW1MZR32\ny/NpbFnEmsXbM+e1F125xkO/vYYHrv6FK+fOL1WCCHSYw2htdB8CDU67RL65kTIHysUTtPV9amuk\nrl7nznjM/Vl5C22k/g1wPPAlsAI4XlV7Qt84Y3qEPv37M3z3CHF/My/94VVXpgT//IMd+OLjnSt+\n3qKIv9MAM78/NaSr6xJEZjfYRDzR3osptXxoFRupOzawuyNvghARn4jMVtU3VPV6Vf2dqr7pemTG\nmKr61vEnE/I9R7h5O6ZdeLnX4VSY8w1fAqCJDu/4Asmbe7Hf/jVt2nC0+sPCYtEaqGJS1QTwtohs\n7Ho0xhhPHXHtRYRaPmLtyondchqOhGRZxzm1dGieb/+Z3Vw1fbptp3qqmuMgaiJBODYE3nNWk3s0\n9XAzMGNM9TX16sWYg/qh4uetOxa4MoDOi0F5qcV51BfosJZ0h32KLUGkn6dtHET1ShJLXnV/WZ5C\nf5srSK4mdyVwbdrDGNPN7DblcHr1+w/h5tH87ZzK/2/+2bwPKn7O/NqrmDSeyLFLkQmiQ1NGqhdT\n9UoQ1SitdPmJiMgoEdlFVZ9Lf5Bsr1nkenTGGE8cc83PCIVfpSWwO3+7srKLC3m5DoX6Ah3WgwDa\nXue/4Wab7jul+t1cxesEAVwHrM6yfZ3znjGmm5r00yNpDH/Gyk+3rego61WLl1TsXIVrv5lG1q7N\nsUu+bq4dX6YvSZ0aX1HNdaa1hHWwi5UvQYxQ1XcyN6rqLGCEKxEZY2rC+sM3YdP9IOEL8PbdS1j8\n6UcVOe+65d60QUgi2S10bcYAW03Np1Rs+0Gi/QatBJ1nVRw/XIWeU/muEOrivaZKBmKMqT17Tv0e\n/TeaSSQ0jMcufZhouPyl6KOrWyoQWfF88eTUFOtWrOywPbouFU8ZCUIKG0tRWd6XIGaKSKc5l0Tk\nROB1d0IyxtSSI664jGbfDMJN23P3mT8r+3yxde6vhNaZ4Esku4VG1iSn12iILANgznPDgPzVQ53W\npI772ud48jUWdI7K8r4E8UPgeBF5VkSudR7PAScBP6hkICKyqYjcIiIPVPK8xpjyfe/6Kwi1vEaL\nfw/uPO/iks7hc9Z/TrjffT8LwafJ0k/r2mRJQhIdm1fzVTFljoMg4Ut72ti2V7WIr/zSXD5dfiKq\n+oWqfp1kN9dPnMcVqjpRVRfnO7mI3CoiS0Rkdsb2/UTkAxGZJyIXONear6onlvqLGGPcEwgGmXLN\ncYRaPmTNV7tz7xVXFn0O0eQsqolIY549K08F0GRiiIVjTjxrOu6Ub4W2zEbqRPugu4Sv+lVMB155\nrOvXKHQupmdU9ffOY0YR578d2C99g4j4gRuA/YEtgCNEZIsizmmM8cCAwUPY5+Jv0BD5jBWLduLh\n635T5Bmcm2esb8VjK+Ta4iSIRMTp5upb18X+BZxRg23P1Zd8Xs0qpvWHb+L6NVytxFLV50lO8Jdu\nJ2CeU2KIAvcCB7kZhzGmMjYeswUTTh1FILaCxbPH8OQdfyn4WG3rCjrArfC6JskEobHkTVz85TWW\na1qCaL9G9edkcpMXv81QYGHa60XAUBEZKCI3AtuLyIW5DhaRU0RklojMWrp0qduxGmMybDVxV7Y6\nrAlfIsLHzw/m33cWNvN/qo4/FhzkymyxXRIfkGz80FgyUUljrIsDsslog9Bg2kpy3ZMXCSLbJ6qq\nulxVT1XVzVQ156TxqnqTqo5X1fGDBw92MUxjTC4TDziYcQdGEY0z/7lBPHX37XmPUfERiH5FPNDM\nK48/7H6QGUSSSUnjybYDX7kuh7mmAAAViElEQVRNIW1dWztLdamtd14kiEXA8LTXw4DPPYjDGFOG\nb0w5grHfDiMa56Nn+vP0Pbfn3DcaDoP4CMQ+BuDjF96qTpDQXlrxJ3+K07gsviK//Wc2UpM7QTRE\nu8dMRF4kiJnAaBEZKSINwFSgqJlhbclRY2rDNw87kjH7tYAq857uz4xpd2bdr2VtsseQNC4n0LqG\n1qXVa4doTU2L7YuDJlDNfWNfvXJl1u0PXP2LtpJHG+mqCJJ9xth642qCEJFpwMvAWBFZJCInqmoM\nOAN4ApgD3Keq7xVzXlty1JjasfvhRzF63zWAMvfffXjhwfs67RNZl5z/SPxKIP4ukYYtmf9ep1l8\nXJGIt7c1+OMRUOfGnqUA8fqTj2U9xxcf70y4YbcO2+K+5twX1RwzxtYZt3sxHaGqG6pqUFWHqeot\nzvbHVXWM095Q/tBMY4yn9pz6PUbttQrEz5zp0mmxoXCLM0GeKBvtOpCEv5Fnr7u/KrEl2hYEAl8i\n0uU3/0Vv/rfTtlwN6vFAry6GPVgJwjNWxWRM7dnrqOMYttNCEv5m3rhrBXNee7HtvWiLM+ZAYP+T\nTiXU8gZh2ZV/3XqT63G1lyAUSURQ2hPERmPf6LBv9H9dTT/XUXLxoYZODdLJhGIlCM9YFZMxtemA\n75/O+lu8Tyy4Hi/d8G7b6nGtEWd6C+eO8/XTJxKIrWXBCwN47cl/uBpTItFexSQaRn1NTizCIWef\n12HfVv9WrFjacZKIRLyLuaO0OVkqSTP3zdeAYrvQ1qa6TBDGmNo15Zzzae79POGmMfztnGsAiDoJ\nAklWvWy+0y4MnbCYhL+Jt6aFefzmP7kWT+oGLwJChITPKSU41UOB1mQDeij8KrFgH6b/8vcdjo93\nkSBUenXaNv+tt0EsQXjGqpiMqW3H/vbnNLXMIuzbjece+CuxaKoE0V5pf8AppzF8pwUgwqevjeS2\nMy6qyHTimdpWjHPmY4r7nRKEkyH88a8AaFh/LY0ti4h8uW2nUkQmfyzZpqK+XqDgi7fHveKjz4EK\nDwRUL2bArdMEYVVMxtS+8d/fGV+ilY+mf0407JQgMu44B5xyGhNOGkRDZB7rYntz1/fvrHhposMa\n1BJBfYEOsaRmdRWBvmMWEG0cxMOXXt92SHovqBR/PFnqiAV6AxCItU/8F13mR6SybRB9+z9X0fMV\nqi4ThDGm9m3z9W8STMwi3Lgtiz+cB2QfnLbN17/Jsbd8nz7NTxELDOHjWaO55dirK9Y2kWqDEEB8\n7XONp+bVE0mWBhJx5fCLLyG0bjaR1l14+4Xc85L6EsmEkPAnq6vSpw7X1vUrEne63kP6d3jd2LIw\nx56VZQnCGOOakftuivr8rHjH6cWU444TCAY55jc/Z59zRtAUe4FI43bMeiDIrSdczodvvFZWDKkq\nJkRB0qp+2jJEMoFoLNk+MubgISR8AWb9ZaZzfJYuq9qSNtZB26YOD7SuoTU4vG0hIbcE1/vA1fOn\n1GWCsDYIY+rDNw6dSkNkKXHGAeDLM73Fpltuwwm3XMEOh0RojLxJS3BXZvxxKbeecgmffzy3pBg6\njGPwt9flS2aCcN7abcrhhBIvEm7akYd/e23WKiZQAk47RPIcyQToj31JPNgbEv2zHFN/6jJBWBuE\nMfUhEAzi14+INg4CQPyFfbOesP9kTrzjAsbs8inB6FxafHsy/ar3uO2MC1m1fFlRMaQ3UkswvT2i\nbY/k+2ntwN/+ybEEoytY9tYgopFs04IrPqcdQlDwJ6uuRJcD0NowPMsx6YcX30ax2U7z2pZJrdY4\nvLpMEMaY+uHr096AK77ibjn7HHMiJ975Q4Zt+TaB2Besi+3DfefN4M7zLqZl7dr8JwASTiO10HEG\n17ZYfMnMoIn25DVkk81o3uAtIk3D+cdV2RvNfdp+/f6bJ3tG9RkbRhJx4oEupuFIXq2g2NPtd8Ip\n+BIfFX1cOSxBGGNc1X/TgW3PxV/aLeegM8/m2L+cwKBhLyGJdaxesxf3nP4g0y67Iu/aEolEe9HA\nH2pfVrRt8Tef820+3jG2qVdeSqjlQ8KtHedgateeIA49/0d85+LNOPzii2mI/C/v7yPllgCsBJGb\ntUEYUz9GbL9t2/NCq5iyCQSDfPeSSzjmz1Pp128GKkG+/GI37jjpOhZ8+H7uA9MSRLApbSbXtgyh\nHX6kX6/flitJ+LPM3SSKSMclS1NLgAr5E0SxS5Oqts8nVU11mSCsDcKY+rHFhF3bnvtKLEGkawiF\nOPrqq5j62/1oSswgHNqOJ37xLs8/OC3r/unTfDT2aa/6aW+kTmWGznffyWf9EH/rmk7bUcCffVEg\naciyf52qywRhjKkfDaH2CfB8AX8XexanT//+nHDTVWw07m0SvhBzHmviidtu7rRf2zQfPqWpf9/2\nN1I9qlJ3wSzLhzaEQgRb52cPwFmyNO7vOMGfv1cBo56LXLs6lcykyrPEWoIwxlRNQ3NTxc95yNnn\nMfZbaxCN8+kL6/HWs091eD81fYeI0HfQoLbt7TddR471paVxeZatSqrmKZGRIJoG52ugLl5bFVPb\n1avDEoQxxnWpuYtCfXu7cv7dDz+KjXddTtzfxOu3ze8wp1OsbUU5GDh0aNv2VIJQX+4qJgB/c5YS\ngSj+huy3z16Dcq+WF1r3bhe/RdrpE7km+0u1l1QnRdRlgrBGamPqS9BZo7mxV+W/Xafsd8IpNPf+\nD+GmUdxz3hVt22MRZ4yCX9hgk03bD/AVVoII9g123qjgD2XZDvQbknuqDV/vL3L/AmnWH/VG1u3V\nXoaoLhOENVIbU1/GnzyW5sBT7HLQd1y9zlG/uoLQug+ItkxoG3ndmjaTbL+B6VVMzhOnBJFreoxg\nU7ZeTBBoyr62dao3U1a+0m7x6kz30bhBsmS03ugNSjpPseoyQRhj6su2u+3J8X/4OYFg9m/dlRII\nBhn4tTCxYB/+9evbAEjEnPUgMrrYii/ZYN7Wm0mz3w6DzVlWmVMfjb2yt6dsuOmYnPGlrtUUeSn3\nLwFIjkbso6/+Kd/6v75MPvOHXR5fKZYgjDHdysE/OJtQy0fE121JrLW1rQ2i00yybSWI1MscJYhs\nCQI/Tf36ZN2/T/+u52E6/NLRHP2n87rcJzOU9NhHbTu+62MryBKEMabbCfT/mGhoQ/55843EnZHW\nmWMwUq/bChC52iAas1UlBWnuV/yEfKrK4I2Gd+j6m022adG9YAnCGNPt7HLCFNAES99cQiLmrAeR\nkSBS1TiN6zlrOjR0HBmdEmjM1gYRoM+g9YoPLEcS6nT6jJHWmm3K8SqwBGGM6XZGbTuexvCnJKIj\niEeTCcIXyLjdOTfhqZdeysAhL/Dda7NX+zQ0df62rwRp7p29iqlLBdznh459M2d1V7XVZYKwbq7G\nmHx8wU+JhDahZWVy6gt/g1NV5Mzrnb42xdTLL6NX3+y9Irf8+m5t4zjaSIDmHPuX6+Czz03rYuWt\nukwQ1s3VGJNP01A/iI+Wz5IJIeCMW/ClliAtsJ5/wOAhnPqXSR22qQTp1Tf3gLhcCq0oGvv1nYs+\ntxvqMkEYY0w+m++xCwDauhEAQadh2JdINlqLv/R5oVT8OUscmSRtNtkO03xr7jmbNt9pF06/cU9C\nLfNKDbEiLEEYY7ql7Xbfm0B0FZHGkQCEevdKvuHcmAMN2Qe6FUIJFDymI5R4Pu3A9lKLVGm6jHJY\ngjDGdFuB2GeoL3kjb2xOJghxEkT27quFUV8RpY+0mqz0lBCMdlw6tSn8Mkf/bJscFyz8cpVkCcIY\n021JoP0m3NQn2etIcEoQ5SQICXT5fmPLp9njSbvR73hc+5xN2+2/gu9cd3qHqUCSF/K2lGEJwhjT\nbQXWa1+OtDnVqUWTjdSpSfxKodJ1CeKkO44ntG5u5+PS7vfb7b532/NdDjo07whsL1iCMMZ0W4PH\nDW9/PnQYAD79DIDmMm7I6uu6BAG0VS1JY9rU3RkD5Tbf/TM2Gpt95lYAX+9kSWToVuOKjrESCvgt\njTGmPk046GDmz0quVz1wSHItiP0vP4QX772fiQdcVNS5AtFVxBqK6VqfLC70HtaXxJy5hJtGkznJ\n0p5Tv9flGb73uytY9NEHjBi3Z1GxVoqVIIwx3daAwUM6bdto5Gi+c2FxyQFg52P6dPltv5NUfVJC\nkYZFRV8PkrPTjhi3VUnHVkJdJggbSW2MKVSf3k/Tu/Gp/Dvmsd3ue3PI2ecRWvce/QY8U8ARieR/\nE4n2TbXfs7WDuqxiUtXpwPTx48ef7HUsxpjadsw1P6vo+U6888yC9tv66E1496+v8u0zzuD+869x\nttbGFBqFqssEYYwxtW6nfQ9kp30PTL5I9W+tsxJEXVYxGWNMPWlbc8JKEMYY0zPselRhk/6lerfW\nV3qwBGGMMSXbdrfCup+2JQarYjLGGNNB2xwb9VWGsARhjDEu0zptg7AEYYwxLkulBSlwTepaYQnC\nGGNMVpYgjDHGbc6d1qqYjDHGdGBVTMYYY7KTjJ91ombGQYhIL+CPQBR4VlXv8TgkY4ypkGQ3V7US\nRDsRuVVElojI7Izt+4nIByIyT0QucDZPAR5Q1ZOByW7GZYwxVeWMtq6v9OB+FdPtwH7pG0TED9wA\n7A9sARwhIlsAw4CFzm5xl+MyxpiqmXDMQTSEv2DTb4/wOpSiuFrFpKrPi8iIjM07AfNUdT6AiNwL\nHAQsIpkk3sLaRowx3ci4r+3MuNt39jqMonlxIx5Ke0kBkolhKPAgcKiI/AmYnutgETlFRGaJyKyl\nS5e6G6kxxvRgXjRSZ6uGU1VdCxyf72BVvQm4CWD8+PF1NvWVMcbUDy9KEIuA4WmvhwGfF3MCW3LU\nGGPc50WCmAmMFpGRItIATAUeLeYEqjpdVU/p16+fKwEaY4xxv5vrNOBlYKyILBKRE1U1BpwBPAHM\nAe5T1ffcjMMYY0zx3O7FdESO7Y8Dj5d6XhGZBEwaNWpUqacwxhiTR112J7UqJmOMcV9dJghjjDHu\nq5m5mIqRqmICvhKRuc7mfsCqLp5n/hwELCvisunnLPT9zG1exlhsfNniyrbNyxjt37n8+LLFlW2b\n/TvXVozlxrdJQRGoard4ADd19TzLz1mlnr/Q9zO3eRljsfFli6fWYrR/Z/t3tn/n0uMr5NGdqpim\n53me+bOc8xf6fuY2L2MsNr5c8dRSjPbvXNh79u9cWAz53q+lGCsRX17iZJQeR0Rmqep4r+PoisVY\nvlqPDyzGSqj1+KA+YszUnUoQxbrJ6wAKYDGWr9bjA4uxEmo9PqiPGDvosSUIY4wxXevJJQhjjDFd\nsARhjDEmK0sQxhhjsrIEkYWI7C4iL4jIjSKyu9fx5CIivUTkdRE50OtYMonI5s7n94CI/J/X8WQj\nIgeLyM0i8oiI7Ot1PNmIyKYicouIPOB1LCnO390dzmd3lNfxZFOLn1umevj763YJQkRuFZElIjI7\nY/t+IvKBiMwTkQvynEaBNUCI5PoVtRgjwI+B+2oxPlWdo6qnAocDFe/aV6EYH1bVk4HjgO/WaIzz\nVfXESseWqchYpwAPOJ/dZLdjKyXGan1uZcbo6t9fRRQzsq8eHsA3gB2A2Wnb/MBHwKZAA/A2sAWw\nNfCPjMf6gM85bgPgnhqNcW+Sa2kcBxxYa/E5x0wGXgKOrMXPMO24a4EdajzGB2ro/5sLge2cff7q\nZlylxlitz61CMbry91eJR13OxdQVVX1eREZkbN4JmKeq8wFE5F7gIFX9BdBV9cwKoLEWYxSRPYBe\nJP+HbRGRx1U1USvxOed5FHhURB4D/lqJ2CoZo4gI8Evgn6r6RiXjq1SM1VJMrCRL1cOAt6hiLUSR\nMb5frbjSFROjiMzBxb+/Suh2VUw5DAUWpr1e5GzLSkSmiMifgbuAP7gcW0pRMarqxar6Q5I33psr\nlRwqFZ/TjnO98zmWvPZHkYqKETiTZEnsMBE51c3A0hT7OQ4UkRuB7UXkQreDy5Ar1geBQ0XkT5Q+\njUSlZI3R488tU67P0Yu/v6J0uxJEDpJlW84Rgqr6IMn/CaqpqBjbdlC9vfKhZFXsZ/gs8KxbweRQ\nbIzXA9e7F05Wxca4HPDq5pE1VlVdCxxf7WByyBWjl59bplwxevH3V5SeUoJYBAxPez0M+NyjWHKp\n9RhrPT6wGCutHmK1GF3UUxLETGC0iIwUkQaSjbuPehxTplqPsdbjA4ux0uohVovRTV63klf6AUwD\n/ge0kszcJzrbvw18SLI3wcUWY/3GZzH2zFgtxuo/bLI+Y4wxWfWUKiZjjDFFsgRhjDEmK0sQxhhj\nsrIEYYwxJitLEMYYY7KyBGGMMSYrSxCmRxCRuIi8lfYoZDr1qpDkmhmbdvH+5SLyi4xt2zmTvSEi\nT4nIALfjND2PJQjTU7So6nZpj1+We0IRKXsuMxHZEvCrM9NnDtPovF7AVNpnyL0LOK3cWIzJZAnC\n9Ggi8omIXCEib4jIuyIyztney1n8ZaaIvCkiBznbjxOR+0VkOvCkiPhE5I8i8p6I/ENEHheRw0Rk\nLxF5KO06+4hItgkgjwIeSdtvXxF52YnnfhHpraofACtFZOe04w4H7nWePwocUdlPxhhLEKbnaMqo\nYkr/Rr5MVXcA/gSc52y7GJihqjsCewC/FpFeznsTgWNVdU+Sq6uNILngz0nOewAzgM1FZLDz+njg\ntixx7QK8DiAig4BLgL2deGYB5zj7TSNZakBEJgDLVXUugKquABpFZGAJn4sxOfWU6b6NaVHV7XK8\nl/pm/zrJGz7AvsBkEUkljBCwsfP836r6pfN8V+B+Ta7HsVhEnoHkXM4ichdwtIjcRjJxHJPl2hsC\nS53nE0guAPVici0jGoCXnffuBV4SkXNJJoppGedZAmwELM/xOxpTNEsQxkDE+Rmn/f8JAQ51qnfa\nONU8a9M3dXHe20guqBMmmURiWfZpIZl8Uuf6t6p2qi5S1YUi8gnwTeBQ2ksqKSHnXMZUjFUxGZPd\nE8CZzrKkiMj2Ofb7D8nV1XwisgGwe+oNVf2c5Lz/lwC35zh+DjDKef4KsIuIjHKu2SwiY9L2nQb8\nFvhIVRelNjoxDgE+KeL3MyYvSxCmp8hsg8jXi+mnQBB4R0RmO6+z+TvJaZ1nA38GXgVWpb1/D7BQ\nVXOtkfwYTlJR1aXAccA0EXmHZMIYl7bv/cCWtDdOp3wNeCVHCcWYktl038aUyelptMZpJH4N2EVV\nFzvv/QF4U1VvyXFsE/CMc0y8xOv/DnhUVZ8u7TcwJjtrgzCmfP8Qkf4kG5V/mpYcXifZXnFurgNV\ntUVELiO5iP2CEq8/25KDcYOVIIwxxmRlbRDGGGOysgRhjDEmK0sQxhhjsrIEYYwxJitLEMYYY7Ky\nBGGMMSar/wfYpbH87rh7KwAAAABJRU5ErkJggg==\n", + "image/png": "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\n", "text/plain": [ - "" + "
" ] }, "metadata": {}, @@ -868,51 +868,51 @@ " \n", " \n", " 0\n", - " 0.0314\n", + " 0.032823\n", " 0\n", " 2.0\n", - " 0.000474\n", - " 0.1072\n", + " 0.000477\n", + " 0.104828\n", " 0.0\n", " 0.0\n", " \n", " \n", " 1\n", - " 2.8250\n", + " 2.828013\n", " 0\n", " 2.0\n", - " 0.000345\n", - " 0.0970\n", + " 0.000350\n", + " 0.093018\n", + " 0.0\n", + " 0.0\n", + " \n", + " \n", + " 2\n", + " 16.765102\n", + " 0\n", + " 2.0\n", + " 0.013206\n", + " 0.080758\n", " 0.0\n", " 0.0\n", " \n", " \n", " 3\n", - " 16.7700\n", + " 20.557704\n", " 0\n", " 2.0\n", - " 0.012800\n", - " 0.0805\n", + " 0.011632\n", + " 0.082187\n", " 0.0\n", " 0.0\n", " \n", " \n", " 4\n", - " 20.5600\n", + " 21.655469\n", " 0\n", " 2.0\n", - " 0.011360\n", - " 0.0880\n", - " 0.0\n", - " 0.0\n", - " \n", - " \n", - " 5\n", - " 21.6500\n", - " 0\n", - " 2.0\n", - " 0.000376\n", - " 0.1140\n", + " 0.000347\n", + " 0.093798\n", " 0.0\n", " 0.0\n", " \n", @@ -921,12 +921,12 @@ "" ], "text/plain": [ - " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.0314 0 2.0 0.000474 0.1072 0.0 0.0\n", - "1 2.8250 0 2.0 0.000345 0.0970 0.0 0.0\n", - "3 16.7700 0 2.0 0.012800 0.0805 0.0 0.0\n", - "4 20.5600 0 2.0 0.011360 0.0880 0.0 0.0\n", - "5 21.6500 0 2.0 0.000376 0.1140 0.0 0.0" + " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", + "0 0.032823 0 2.0 0.000477 0.104828 0.0 0.0\n", + "1 2.828013 0 2.0 0.000350 0.093018 0.0 0.0\n", + "2 16.765102 0 2.0 0.013206 0.080758 0.0 0.0\n", + "3 20.557704 0 2.0 0.011632 0.082187 0.0 0.0\n", + "4 21.655469 0 2.0 0.000347 0.093798 0.0 0.0" ] }, "execution_count": 15, @@ -956,7 +956,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.3" + "version": "3.6.6" } }, "nbformat": 4, diff --git a/openmc/data/resonance.py b/openmc/data/resonance.py index e71073919b..07a34703b9 100644 --- a/openmc/data/resonance.py +++ b/openmc/data/resonance.py @@ -438,7 +438,7 @@ class MultiLevelBreitWigner(ResonanceRange): self._l_values = np.array(l_values) self._competitive = np.array(competitive) for l in l_values: - self._parameter_matrix[l] = df[df.L == l].as_matrix() + self._parameter_matrix[l] = df[df.L == l].values self._prepared = True @@ -683,7 +683,7 @@ class ReichMoore(ResonanceRange): self._l_values = np.array(l_values) for (l, J) in lj_values: self._parameter_matrix[l, J] = df[(df.L == l) & - (abs(df.J) == J)].as_matrix() + (abs(df.J) == J)].values self._prepared = True diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index c78ce33f74..7710512fa5 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -253,11 +253,11 @@ class ResonanceCovarianceRange: if formalism == 'mlbw' or formalism == 'slbw': if mpar == 3: param_list = ['energy', 'neutronWidth', 'captureWidth'] - mean_array = pd.DataFrame.as_matrix(parameters[param_list]) - spin = pd.DataFrame.as_matrix(parameters['J']) - l_value = pd.DataFrame.as_matrix(parameters['L']) - gf = pd.DataFrame.as_matrix(parameters['fissionWidth']) - gx = pd.DataFrame.as_matrix(parameters['competitiveWidth']) + mean_array = parameters[param_list].values + spin = parameters['J'].values + l_value = parameters['L'].values + gf = parameters['fissionWidth'].values + gx = parameters['competitiveWidth'].values mean = mean_array.flatten() par_samples = np.random.multivariate_normal(mean, cov, size=n_samples) @@ -274,16 +274,21 @@ class ResonanceCovarianceRange: 'captureWidth', 'fissionWidth', 'competitiveWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) + # Copy ResonanceRange object + res_range = copy.copy(self.file2res) + # Set _prepared to False to ensure sampled parameters are + # used during construction routine + res_range._prepared = False res_range.parameters = sample_params samples.append(res_range) elif mpar == 4: param_list = ['energy', 'neutronWidth', 'captureWidth', 'fissionWidth'] - mean_array = pd.DataFrame.as_matrix(parameters[param_list]) - spin = pd.DataFrame.as_matrix(parameters['J']) - l_value = pd.DataFrame.as_matrix(parameters['L']) - gx = pd.DataFrame.as_matrix(parameters['competitiveWidth']) + mean_array = parameters[param_list].values + spin = parameters['J'].values + l_value = parameters['L'].values + gx = parameters['competitiveWidth'].values mean = mean_array.flatten() par_samples = np.random.multivariate_normal(mean, cov, size=n_samples) @@ -301,14 +306,20 @@ class ResonanceCovarianceRange: 'captureWidth', 'fissionWidth', 'competitiveWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) + # Copy ResonanceRange object + res_range = copy.copy(self.file2res) + # Set _prepared to False to ensure sampled parameters are + # used during construction routine + res_range._prepared = False + res_range.parameters = sample_params samples.append(res_range) elif mpar == 5: param_list = ['energy', 'neutronWidth', 'captureWidth', 'fissionWidth', 'competitiveWidth'] - mean_array = pd.DataFrame.as_matrix(parameters[param_list]) - spin = pd.DataFrame.as_matrix(parameters['J']) - l_value = pd.DataFrame.as_matrix(parameters['L']) + mean_array = parameters[param_list].values + spin = parameters['J'].values + l_value = parameters['L'].values mean = mean_array.flatten() par_samples = np.random.multivariate_normal(mean, cov, size=n_samples) @@ -327,17 +338,23 @@ class ResonanceCovarianceRange: 'captureWidth', 'fissionWidth', 'competitveWidth'] sample_params = pd.DataFrame.from_records(records, columns=columns) + # Copy ResonanceRange object + res_range = copy.copy(self.file2res) + # Set _prepared to False to ensure sampled parameters are + # used during construction routine + res_range._prepared = False + res_range.parameters = sample_params samples.append(res_range) # Handling RM Sampling if formalism == 'rm': if mpar == 3: param_list = ['energy', 'neutronWidth', 'captureWidth'] - mean_array = pd.DataFrame.as_matrix(parameters[param_list]) - spin = pd.DataFrame.as_matrix(parameters['J']) - l_value = pd.DataFrame.as_matrix(parameters['L']) - gfa = pd.DataFrame.as_matrix(parameters['fissionWidthA']) - gfb = pd.DataFrame.as_matrix(parameters['fissionWidthB']) + mean_array = parameters[param_list].values + spin = parameters['J'].values + l_value = parameters['L'].values + gfa = parameters['fissionWidthA'].values + gfb = parameters['fissionWidthB'].values mean = mean_array.flatten() par_samples = np.random.multivariate_normal(mean, cov, size=n_samples) @@ -353,14 +370,20 @@ class ResonanceCovarianceRange: 'captureWidth', 'fissionWidthA', 'fissionWidthB'] sample_params = pd.DataFrame.from_records(records, columns=columns) + # Copy ResonanceRange object + res_range = copy.copy(self.file2res) + # Set _prepared to False to ensure sampled parameters are + # used during construction routine + res_range._prepared = False + res_range.parameters = sample_params samples.append(res_range) elif mpar == 5: param_list = ['energy', 'neutronWidth', 'captureWidth', 'fissionWidthA', 'fissionWidthB'] - mean_array = pd.DataFrame.as_matrix(parameters[param_list]) - spin = pd.DataFrame.as_matrix(parameters['J']) - l_value = pd.DataFrame.as_matrix(parameters['L']) + mean_array = parameters[param_list].values + spin = parameters['J'].values + l_value = parameters['L'].values mean = mean_array.flatten() par_samples = np.random.multivariate_normal(mean, cov, size=n_samples) @@ -378,6 +401,12 @@ class ResonanceCovarianceRange: 'captureWidth', 'fissionWidthA', 'fissionWidthB'] sample_params = pd.DataFrame.from_records(records, columns=columns) + # Copy ResonanceRange object + res_range = copy.copy(self.file2res) + # Set _prepared to False to ensure sampled parameters are + # used during construction routine + res_range._prepared = False + res_range.parameters = sample_params samples.append(res_range) return samples From 1bf5e7b2cbe821570037cbd9d039af94c0eca49e Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Wed, 25 Jul 2018 09:49:58 -0500 Subject: [PATCH 090/100] more changes to sampling --- openmc/data/resonance_covariance.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index 7710512fa5..bc63761265 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -235,11 +235,6 @@ class ResonanceCovarianceRange: warnings.warn(warn_str) parameters = self.parameters cov = self.covariance - # Copy ResonanceRange object - res_range = copy.copy(self.file2res) - # Set _prepared to False to ensure sampled parameters are - # used during construction routine - res_range._prepared = False nparams, params = parameters.shape # Symmetrizing covariance matrix From 3626d8ead7f46c2f83f6feae5e7285bb8b3feb84 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Fri, 27 Jul 2018 10:19:06 -0500 Subject: [PATCH 091/100] Condensed sampling method --- openmc/data/resonance_covariance.py | 219 ++++++++-------------------- 1 file changed, 63 insertions(+), 156 deletions(-) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index bc63761265..0a74170125 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -236,7 +236,6 @@ class ResonanceCovarianceRange: parameters = self.parameters cov = self.covariance - nparams, params = parameters.shape # Symmetrizing covariance matrix cov = cov + cov.T - np.diag(cov.diagonal()) covsize = cov.shape[0] @@ -244,165 +243,73 @@ class ResonanceCovarianceRange: mpar = self.mpar samples = [] - # Handling MLBW sampling + # Handling MLBW/SLBW sampling if formalism == 'mlbw' or formalism == 'slbw': - if mpar == 3: - param_list = ['energy', 'neutronWidth', 'captureWidth'] - mean_array = parameters[param_list].values - spin = parameters['J'].values - l_value = parameters['L'].values - gf = parameters['fissionWidth'].values - gx = parameters['competitiveWidth'].values - mean = mean_array.flatten() - par_samples = np.random.multivariate_normal(mean, cov, - size=n_samples) - for sample in par_samples: - energy = sample[0::3] - gn = sample[1::3] - gg = sample[2::3] - gt = gn + gg + gf - records = [] - for j, E in enumerate(energy): - records.append([energy[j], l_value[j], spin[j], gt[j], - gn[j], gg[j], gf[j], gx[j]]) - columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', - 'captureWidth', 'fissionWidth', 'competitiveWidth'] - sample_params = pd.DataFrame.from_records(records, - columns=columns) - # Copy ResonanceRange object - res_range = copy.copy(self.file2res) - # Set _prepared to False to ensure sampled parameters are - # used during construction routine - res_range._prepared = False - res_range.parameters = sample_params - samples.append(res_range) + params = ['energy', 'neutronWidth', 'captureWidth', 'fissionWidth', + 'competitiveWidth'] + param_list = params[:mpar] + mean_array = parameters[param_list].values + mean = mean_array.flatten() + par_samples = np.random.multivariate_normal(mean, cov, + size=n_samples) + spin = parameters['J'].values + l_value = parameters['L'].values + for sample in par_samples: + energy = sample[0::mpar] + gn = sample[1::mpar] + gg = sample[2::mpar] + gf = sample[3::mpar] if mpar > 3 else parameters['fissionWidth'].values + gx = sample[4::mpar] if mpar > 4 else parameters['competitiveWidth'].values + gt = gn + gg + gf + gx - elif mpar == 4: - param_list = ['energy', 'neutronWidth', 'captureWidth', - 'fissionWidth'] - mean_array = parameters[param_list].values - spin = parameters['J'].values - l_value = parameters['L'].values - gx = parameters['competitiveWidth'].values - mean = mean_array.flatten() - par_samples = np.random.multivariate_normal(mean, cov, - size=n_samples) - for sample in par_samples: - energy = sample[0::4] - gn = sample[1::4] - gg = sample[2::4] - gf = sample[3::4] - gt = gn + gg + gf - records = [] - for j, E in enumerate(energy): - records.append([energy[j], l_value[j], spin[j], gt[j], - gn[j], gg[j], gf[j], gx[j]]) - columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', - 'captureWidth', 'fissionWidth', 'competitiveWidth'] - sample_params = pd.DataFrame.from_records(records, - columns=columns) - # Copy ResonanceRange object - res_range = copy.copy(self.file2res) - # Set _prepared to False to ensure sampled parameters are - # used during construction routine - res_range._prepared = False - res_range.parameters = sample_params - samples.append(res_range) + records = [] + for j, E in enumerate(energy): + records.append([energy[j], l_value[j], spin[j], gt[j], gn[j], + gg[j], gf[j], gx[j]]) + columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', + 'captureWidth', 'fissionWidth', 'competitiveWidth'] + sample_params = pd.DataFrame.from_records(records, columns=columns) + # Copy ResonanceRange object + res_range = copy.copy(self.file2res) + # Set _prepared to False to ensure sampled parameters are + # used during construction routine + res_range._prepared = False + res_range.parameters = sample_params + samples.append(res_range) - elif mpar == 5: - param_list = ['energy', 'neutronWidth', 'captureWidth', - 'fissionWidth', 'competitiveWidth'] - mean_array = parameters[param_list].values - spin = parameters['J'].values - l_value = parameters['L'].values - mean = mean_array.flatten() - par_samples = np.random.multivariate_normal(mean, cov, - size=n_samples) - for sample in par_samples: - energy = sample[0::5] - gn = sample[1::5] - gg = sample[2::5] - gf = sample[3::5] - gx = sample[4::5] - gt = gn + gg + gf - records = [] - for j, E in enumerate(energy): - records.append([energy[j], l_value[j], spin[j], gt[j], - gn[j], gg[j], gf[j], gx[j]]) - columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', - 'captureWidth', 'fissionWidth', 'competitveWidth'] - sample_params = pd.DataFrame.from_records(records, - columns=columns) - # Copy ResonanceRange object - res_range = copy.copy(self.file2res) - # Set _prepared to False to ensure sampled parameters are - # used during construction routine - res_range._prepared = False - res_range.parameters = sample_params - samples.append(res_range) + # Handling RM sampling + elif formalism == 'rm': + params = ['energy', 'L', 'J', 'neutronWidth', 'captureWidth', + 'fissionWidthA', 'fissionWidthB'] + param_list = params[:mpar] + mean_array = parameters[param_list].values + mean = mean_array.flatten() + par_samples = np.random.multivariate_normal(mean, cov, + size=n_samples) + spin = parameters['J'] + l_value = parameters['L'].values + for sample in par_samples: + energy = sample[0::mpar] + gn = sample[1::mpar] + gg = sample[2::mpar] + gfa = sample[3::mpar] if mpar > 3 else parameters['fissionWidthA'].values + gfb = sample[3::mpar] if mpar > 3 else parameters['fissionWidthB'].values - # Handling RM Sampling - if formalism == 'rm': - if mpar == 3: - param_list = ['energy', 'neutronWidth', 'captureWidth'] - mean_array = parameters[param_list].values - spin = parameters['J'].values - l_value = parameters['L'].values - gfa = parameters['fissionWidthA'].values - gfb = parameters['fissionWidthB'].values - mean = mean_array.flatten() - par_samples = np.random.multivariate_normal(mean, cov, - size=n_samples) - for sample in par_samples: - energy = sample[0::3] - gn = sample[1::3] - gg = sample[2::3] - records = [] - for j, E in enumerate(energy): - records.append([energy[j], l_value[j], spin[j], gn[j], - gg[j], gfa[j], gfb[j]]) - columns = ['energy', 'L', 'J', 'neutronWidth', - 'captureWidth', 'fissionWidthA', 'fissionWidthB'] - sample_params = pd.DataFrame.from_records(records, - columns=columns) - # Copy ResonanceRange object - res_range = copy.copy(self.file2res) - # Set _prepared to False to ensure sampled parameters are - # used during construction routine - res_range._prepared = False - res_range.parameters = sample_params - samples.append(res_range) - - elif mpar == 5: - param_list = ['energy', 'neutronWidth', 'captureWidth', - 'fissionWidthA', 'fissionWidthB'] - mean_array = parameters[param_list].values - spin = parameters['J'].values - l_value = parameters['L'].values - mean = mean_array.flatten() - par_samples = np.random.multivariate_normal(mean, cov, - size=n_samples) - for sample in par_samples: - energy = sample[0::5] - gn = sample[1::5] - gg = sample[2::5] - gfa = sample[3::5] - gfb = sample[4::5] - records = [] - for j, E in enumerate(energy): - records.append([energy[j], l_value[j], spin[j], gn[j], - gg[j], gfa[j], gfb[j]]) - columns = ['energy', 'L', 'J', 'neutronWidth', - 'captureWidth', 'fissionWidthA', 'fissionWidthB'] - sample_params = pd.DataFrame.from_records(records, - columns=columns) - # Copy ResonanceRange object - res_range = copy.copy(self.file2res) - # Set _prepared to False to ensure sampled parameters are - # used during construction routine - res_range._prepared = False - res_range.parameters = sample_params - samples.append(res_range) + records = [] + for j, E in enumerate(energy): + records.append([energy[j], l_value[j], spin[j], gn[j], + gg[j], gfa[j], gfb[j]]) + columns = ['energy', 'L', 'J', 'neutronWidth', + 'captureWidth', 'fissionWidthA', 'fissionWidthB'] + sample_params = pd.DataFrame.from_records(records, + columns=columns) + # Copy ResonanceRange object + res_range = copy.copy(self.file2res) + # Set _prepared to False to ensure sampled parameters are + # used during construction routine + res_range._prepared = False + res_range.parameters = sample_params + samples.append(res_range) return samples From 28414ef2833d7360ebc094977d997e31e9e31f16 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Fri, 27 Jul 2018 11:00:03 -0500 Subject: [PATCH 092/100] Changed __copy__ method of ResonanceRange to mark parameters unprepared --- .../nuclear-data-resonance-covariance.ipynb | 134 +++++++++--------- openmc/data/resonance.py | 15 +- openmc/data/resonance_covariance.py | 21 +-- 3 files changed, 84 insertions(+), 86 deletions(-) diff --git a/examples/jupyter/nuclear-data-resonance-covariance.ipynb b/examples/jupyter/nuclear-data-resonance-covariance.ipynb index 876cf4daba..e60be13513 100644 --- a/examples/jupyter/nuclear-data-resonance-covariance.ipynb +++ b/examples/jupyter/nuclear-data-resonance-covariance.ipynb @@ -208,7 +208,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 5, @@ -246,7 +246,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 6, @@ -296,7 +296,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/icmeyer/miniconda3/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/data/resonance_covariance.py:235: UserWarning: Sampling routine does not guarantee positive values for parameters. This can lead to undefined behavior in the reconstruction routine.\n", + "/home/icmeyer/openmc/openmc/data/resonance_covariance.py:231: UserWarning: Sampling routine does not guarantee positive values for parameters. This can lead to undefined behavior in the reconstruction routine.\n", " warnings.warn(warn_str)\n" ] }, @@ -370,51 +370,51 @@ " \n", " \n", " 0\n", - " 0.031892\n", + " 0.033464\n", " 0\n", " 2.0\n", - " 0.000477\n", - " 0.106883\n", + " 0.000479\n", + " 0.103833\n", " 0.0\n", " 0.0\n", " \n", " \n", " 1\n", - " 2.825068\n", + " 2.824695\n", " 0\n", " 2.0\n", - " 0.000333\n", - " 0.101242\n", + " 0.000346\n", + " 0.090186\n", " 0.0\n", " 0.0\n", " \n", " \n", " 2\n", - " 16.255167\n", + " 16.271406\n", " 0\n", " 1.0\n", - " 0.000433\n", - " 0.102033\n", + " 0.000558\n", + " 0.170612\n", " 0.0\n", " 0.0\n", " \n", " \n", " 3\n", - " 16.768821\n", + " 16.771335\n", " 0\n", " 2.0\n", - " 0.013301\n", - " 0.079907\n", + " 0.011966\n", + " 0.080398\n", " 0.0\n", " 0.0\n", " \n", " \n", " 4\n", - " 20.559310\n", + " 20.554856\n", " 0\n", " 2.0\n", - " 0.012069\n", - " 0.075562\n", + " 0.011056\n", + " 0.090749\n", " 0.0\n", " 0.0\n", " \n", @@ -424,11 +424,11 @@ ], "text/plain": [ " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.031892 0 2.0 0.000477 0.106883 0.0 0.0\n", - "1 2.825068 0 2.0 0.000333 0.101242 0.0 0.0\n", - "2 16.255167 0 1.0 0.000433 0.102033 0.0 0.0\n", - "3 16.768821 0 2.0 0.013301 0.079907 0.0 0.0\n", - "4 20.559310 0 2.0 0.012069 0.075562 0.0 0.0" + "0 0.033464 0 2.0 0.000479 0.103833 0.0 0.0\n", + "1 2.824695 0 2.0 0.000346 0.090186 0.0 0.0\n", + "2 16.271406 0 1.0 0.000558 0.170612 0.0 0.0\n", + "3 16.771335 0 2.0 0.011966 0.080398 0.0 0.0\n", + "4 20.554856 0 2.0 0.011056 0.090749 0.0 0.0" ] }, "execution_count": 8, @@ -486,51 +486,51 @@ " \n", " \n", " 0\n", - " 0.033649\n", + " 0.029919\n", " 0\n", " 2.0\n", - " 0.000480\n", - " 0.103631\n", + " 0.000472\n", + " 0.109936\n", " 0.0\n", " 0.0\n", " \n", " \n", " 1\n", - " 2.829673\n", + " 2.823121\n", " 0\n", " 2.0\n", - " 0.000332\n", - " 0.099803\n", + " 0.000349\n", + " 0.097556\n", " 0.0\n", " 0.0\n", " \n", " \n", " 2\n", - " 16.222978\n", + " 16.236232\n", " 0\n", " 1.0\n", - " 0.000331\n", - " 0.071241\n", + " 0.000443\n", + " 0.096141\n", " 0.0\n", " 0.0\n", " \n", " \n", " 3\n", - " 16.765241\n", + " 16.770362\n", " 0\n", " 2.0\n", - " 0.012566\n", - " 0.080448\n", + " 0.012942\n", + " 0.079580\n", " 0.0\n", " 0.0\n", " \n", " \n", " 4\n", - " 20.566440\n", + " 20.560065\n", " 0\n", " 2.0\n", - " 0.011168\n", - " 0.088066\n", + " 0.011043\n", + " 0.094364\n", " 0.0\n", " 0.0\n", " \n", @@ -540,11 +540,11 @@ ], "text/plain": [ " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.033649 0 2.0 0.000480 0.103631 0.0 0.0\n", - "1 2.829673 0 2.0 0.000332 0.099803 0.0 0.0\n", - "2 16.222978 0 1.0 0.000331 0.071241 0.0 0.0\n", - "3 16.765241 0 2.0 0.012566 0.080448 0.0 0.0\n", - "4 20.566440 0 2.0 0.011168 0.088066 0.0 0.0" + "0 0.029919 0 2.0 0.000472 0.109936 0.0 0.0\n", + "1 2.823121 0 2.0 0.000349 0.097556 0.0 0.0\n", + "2 16.236232 0 1.0 0.000443 0.096141 0.0 0.0\n", + "3 16.770362 0 2.0 0.012942 0.079580 0.0 0.0\n", + "4 20.560065 0 2.0 0.011043 0.094364 0.0 0.0" ] }, "execution_count": 9, @@ -572,8 +572,8 @@ { "data": { "text/plain": [ - "[,\n", - " ]" + "[,\n", + " ]" ] }, "execution_count": 10, @@ -604,7 +604,7 @@ }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -831,7 +831,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/icmeyer/miniconda3/lib/python3.6/site-packages/openmc-0.10.0-py3.6-linux-x86_64.egg/openmc/data/resonance_covariance.py:235: UserWarning: Sampling routine does not guarantee positive values for parameters. This can lead to undefined behavior in the reconstruction routine.\n", + "/home/icmeyer/openmc/openmc/data/resonance_covariance.py:231: UserWarning: Sampling routine does not guarantee positive values for parameters. This can lead to undefined behavior in the reconstruction routine.\n", " warnings.warn(warn_str)\n" ] }, @@ -868,51 +868,51 @@ " \n", " \n", " 0\n", - " 0.032823\n", + " 0.029174\n", " 0\n", " 2.0\n", - " 0.000477\n", - " 0.104828\n", + " 0.000468\n", + " 0.110557\n", " 0.0\n", " 0.0\n", " \n", " \n", " 1\n", - " 2.828013\n", + " 2.826584\n", " 0\n", " 2.0\n", - " 0.000350\n", - " 0.093018\n", + " 0.000348\n", + " 0.090882\n", " 0.0\n", " 0.0\n", " \n", " \n", " 2\n", - " 16.765102\n", + " 16.768498\n", " 0\n", " 2.0\n", - " 0.013206\n", - " 0.080758\n", + " 0.013018\n", + " 0.076285\n", " 0.0\n", " 0.0\n", " \n", " \n", " 3\n", - " 20.557704\n", + " 20.561904\n", " 0\n", " 2.0\n", - " 0.011632\n", - " 0.082187\n", + " 0.010537\n", + " 0.096260\n", " 0.0\n", " 0.0\n", " \n", " \n", " 4\n", - " 21.655469\n", + " 21.652164\n", " 0\n", " 2.0\n", - " 0.000347\n", - " 0.093798\n", + " 0.000356\n", + " 0.159153\n", " 0.0\n", " 0.0\n", " \n", @@ -922,11 +922,11 @@ ], "text/plain": [ " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.032823 0 2.0 0.000477 0.104828 0.0 0.0\n", - "1 2.828013 0 2.0 0.000350 0.093018 0.0 0.0\n", - "2 16.765102 0 2.0 0.013206 0.080758 0.0 0.0\n", - "3 20.557704 0 2.0 0.011632 0.082187 0.0 0.0\n", - "4 21.655469 0 2.0 0.000347 0.093798 0.0 0.0" + "0 0.029174 0 2.0 0.000468 0.110557 0.0 0.0\n", + "1 2.826584 0 2.0 0.000348 0.090882 0.0 0.0\n", + "2 16.768498 0 2.0 0.013018 0.076285 0.0 0.0\n", + "3 20.561904 0 2.0 0.010537 0.096260 0.0 0.0\n", + "4 21.652164 0 2.0 0.000356 0.159153 0.0 0.0" ] }, "execution_count": 15, diff --git a/openmc/data/resonance.py b/openmc/data/resonance.py index 07a34703b9..5e4bd7129e 100644 --- a/openmc/data/resonance.py +++ b/openmc/data/resonance.py @@ -91,14 +91,14 @@ class Resonances(object): # Determine whether discrete or continuous representation items = get_head_record(file_obj) - n_isotope = items[4] # Number of isotopes + n_isotope = items[4] # Number of isotopes ranges = [] for iso in range(n_isotope): items = get_cont_record(file_obj) abundance = items[1] - fission_widths = (items[3] == 1) # fission widths are given? - n_ranges = items[4] # number of resonance energy ranges + fission_widths = (items[3] == 1) # fission widths are given? + n_ranges = items[4] # number of resonance energy ranges for j in range(n_ranges): items = get_cont_record(file_obj) @@ -113,7 +113,7 @@ class Resonances(object): # unresolved resonance region erange = Unresolved.from_endf(file_obj, items, fission_widths) - #erange.material = self + # erange.material = self ranges.append(erange) return cls(ranges) @@ -163,6 +163,13 @@ class ResonanceRange(object): self._prepared = False self._parameter_matrix = {} + def __copy__(self): + cls = type(self) + new_copy = cls.__new__(cls) + new_copy.__dict__.update(self.__dict__) + new_copy._prepared = False + return new_copy + @classmethod def from_endf(cls, ev, file_obj, items): """Create resonance range from an ENDF evaluation. diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index 0a74170125..ebc375fcb8 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -208,10 +208,6 @@ class ResonanceCovarianceRange: res_cov_range.file2res.parameters = parameters[mask] res_cov_range.covariance = cov_subset - # Set _prepared to False to ensure parameter subset - # used during construction routine - res_cov_range.file2res._prepared = False - return res_cov_range def sample_resonance_parameters(self, n_samples): @@ -264,29 +260,27 @@ class ResonanceCovarianceRange: records = [] for j, E in enumerate(energy): - records.append([energy[j], l_value[j], spin[j], gt[j], gn[j], - gg[j], gf[j], gx[j]]) + records.append([energy[j], l_value[j], spin[j], gt[j], + gn[j], gg[j], gf[j], gx[j]]) columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', 'captureWidth', 'fissionWidth', 'competitiveWidth'] - sample_params = pd.DataFrame.from_records(records, columns=columns) + sample_params = pd.DataFrame.from_records(records, + columns=columns) # Copy ResonanceRange object res_range = copy.copy(self.file2res) - # Set _prepared to False to ensure sampled parameters are - # used during construction routine - res_range._prepared = False res_range.parameters = sample_params samples.append(res_range) # Handling RM sampling elif formalism == 'rm': - params = ['energy', 'L', 'J', 'neutronWidth', 'captureWidth', + params = ['energy', 'neutronWidth', 'captureWidth', 'fissionWidthA', 'fissionWidthB'] param_list = params[:mpar] mean_array = parameters[param_list].values mean = mean_array.flatten() par_samples = np.random.multivariate_normal(mean, cov, size=n_samples) - spin = parameters['J'] + spin = parameters['J'].values l_value = parameters['L'].values for sample in par_samples: energy = sample[0::mpar] @@ -305,9 +299,6 @@ class ResonanceCovarianceRange: columns=columns) # Copy ResonanceRange object res_range = copy.copy(self.file2res) - # Set _prepared to False to ensure sampled parameters are - # used during construction routine - res_range._prepared = False res_range.parameters = sample_params samples.append(res_range) From 5918f5b4a4c341462dfd0bd2d20476a86a002d19 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Fri, 27 Jul 2018 11:15:07 -0500 Subject: [PATCH 093/100] remove unused variable --- openmc/data/resonance_covariance.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index ebc375fcb8..e2ed90a7d7 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -234,7 +234,6 @@ class ResonanceCovarianceRange: # Symmetrizing covariance matrix cov = cov + cov.T - np.diag(cov.diagonal()) - covsize = cov.shape[0] formalism = self.formalism mpar = self.mpar samples = [] From bd74e7a81d304e5a103be424f61a2e4a6417e3b3 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 29 Jul 2018 21:08:33 -0400 Subject: [PATCH 094/100] Fix indexing error with cell_set_temperature --- src/geometry_header.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 758fc54da7..2c943706d7 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -736,7 +736,7 @@ contains ! find which material is associated with this cell (material_index ! is the index into the materials array) if (present(instance)) then - material_index = cells(index) % material(instance) + material_index = cells(index) % material(instance + 1) else material_index = cells(index) % material(1) end if From c6c47e1e689cf88c7925d00f00e406ad86238274 Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 31 Jul 2018 08:29:59 -0500 Subject: [PATCH 095/100] Some name changes, removed redundandancies --- .../nuclear-data-resonance-covariance.ipynb | 140 +++++++++--------- openmc/data/resonance_covariance.py | 101 +++++-------- tests/unit_tests/test_data_neutron.py | 2 +- 3 files changed, 104 insertions(+), 139 deletions(-) diff --git a/examples/jupyter/nuclear-data-resonance-covariance.ipynb b/examples/jupyter/nuclear-data-resonance-covariance.ipynb index e60be13513..2c44b6f7fa 100644 --- a/examples/jupyter/nuclear-data-resonance-covariance.ipynb +++ b/examples/jupyter/nuclear-data-resonance-covariance.ipynb @@ -208,7 +208,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 5, @@ -246,7 +246,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 6, @@ -296,7 +296,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/icmeyer/openmc/openmc/data/resonance_covariance.py:231: UserWarning: Sampling routine does not guarantee positive values for parameters. This can lead to undefined behavior in the reconstruction routine.\n", + "/home/icmeyer/openmc/openmc/data/resonance_covariance.py:233: UserWarning: Sampling routine does not guarantee positive values for parameters. This can lead to undefined behavior in the reconstruction routine.\n", " warnings.warn(warn_str)\n" ] }, @@ -314,7 +314,7 @@ "source": [ "rm_resonance = gd157_endf.resonances.ranges[0]\n", "n_samples = 5\n", - "samples = gd157_endf.resonance_covariance.ranges[0].sample_resonance_parameters(n_samples)\n", + "samples = gd157_endf.resonance_covariance.ranges[0].sample(n_samples)\n", "type(samples[0])\n" ] }, @@ -370,51 +370,51 @@ " \n", " \n", " 0\n", - " 0.033464\n", + " 0.031151\n", " 0\n", " 2.0\n", - " 0.000479\n", - " 0.103833\n", + " 0.000471\n", + " 0.107045\n", " 0.0\n", " 0.0\n", " \n", " \n", " 1\n", - " 2.824695\n", + " 2.820921\n", " 0\n", " 2.0\n", - " 0.000346\n", - " 0.090186\n", + " 0.000334\n", + " 0.098885\n", " 0.0\n", " 0.0\n", " \n", " \n", " 2\n", - " 16.271406\n", + " 16.217408\n", " 0\n", " 1.0\n", - " 0.000558\n", - " 0.170612\n", + " 0.000453\n", + " 0.068385\n", " 0.0\n", " 0.0\n", " \n", " \n", " 3\n", - " 16.771335\n", + " 16.771021\n", " 0\n", " 2.0\n", - " 0.011966\n", - " 0.080398\n", + " 0.013670\n", + " 0.071278\n", " 0.0\n", " 0.0\n", " \n", " \n", " 4\n", - " 20.554856\n", + " 20.559685\n", " 0\n", " 2.0\n", - " 0.011056\n", - " 0.090749\n", + " 0.010609\n", + " 0.097546\n", " 0.0\n", " 0.0\n", " \n", @@ -424,11 +424,11 @@ ], "text/plain": [ " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.033464 0 2.0 0.000479 0.103833 0.0 0.0\n", - "1 2.824695 0 2.0 0.000346 0.090186 0.0 0.0\n", - "2 16.271406 0 1.0 0.000558 0.170612 0.0 0.0\n", - "3 16.771335 0 2.0 0.011966 0.080398 0.0 0.0\n", - "4 20.554856 0 2.0 0.011056 0.090749 0.0 0.0" + "0 0.031151 0 2.0 0.000471 0.107045 0.0 0.0\n", + "1 2.820921 0 2.0 0.000334 0.098885 0.0 0.0\n", + "2 16.217408 0 1.0 0.000453 0.068385 0.0 0.0\n", + "3 16.771021 0 2.0 0.013670 0.071278 0.0 0.0\n", + "4 20.559685 0 2.0 0.010609 0.097546 0.0 0.0" ] }, "execution_count": 8, @@ -486,51 +486,51 @@ " \n", " \n", " 0\n", - " 0.029919\n", + " 0.033838\n", " 0\n", " 2.0\n", - " 0.000472\n", - " 0.109936\n", + " 0.000480\n", + " 0.103325\n", " 0.0\n", " 0.0\n", " \n", " \n", " 1\n", - " 2.823121\n", + " 2.822370\n", " 0\n", " 2.0\n", - " 0.000349\n", - " 0.097556\n", + " 0.000367\n", + " 0.091599\n", " 0.0\n", " 0.0\n", " \n", " \n", " 2\n", - " 16.236232\n", + " 16.243968\n", " 0\n", " 1.0\n", - " 0.000443\n", - " 0.096141\n", + " 0.000311\n", + " 0.089655\n", " 0.0\n", " 0.0\n", " \n", " \n", " 3\n", - " 16.770362\n", + " 16.775993\n", " 0\n", " 2.0\n", - " 0.012942\n", - " 0.079580\n", + " 0.013050\n", + " 0.084476\n", " 0.0\n", " 0.0\n", " \n", " \n", " 4\n", - " 20.560065\n", + " 20.561690\n", " 0\n", " 2.0\n", - " 0.011043\n", - " 0.094364\n", + " 0.011163\n", + " 0.086802\n", " 0.0\n", " 0.0\n", " \n", @@ -540,11 +540,11 @@ ], "text/plain": [ " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.029919 0 2.0 0.000472 0.109936 0.0 0.0\n", - "1 2.823121 0 2.0 0.000349 0.097556 0.0 0.0\n", - "2 16.236232 0 1.0 0.000443 0.096141 0.0 0.0\n", - "3 16.770362 0 2.0 0.012942 0.079580 0.0 0.0\n", - "4 20.560065 0 2.0 0.011043 0.094364 0.0 0.0" + "0 0.033838 0 2.0 0.000480 0.103325 0.0 0.0\n", + "1 2.822370 0 2.0 0.000367 0.091599 0.0 0.0\n", + "2 16.243968 0 1.0 0.000311 0.089655 0.0 0.0\n", + "3 16.775993 0 2.0 0.013050 0.084476 0.0 0.0\n", + "4 20.561690 0 2.0 0.011163 0.086802 0.0 0.0" ] }, "execution_count": 9, @@ -572,8 +572,8 @@ { "data": { "text/plain": [ - "[,\n", - " ]" + "[,\n", + " ]" ] }, "execution_count": 10, @@ -604,7 +604,7 @@ }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYgAAAEOCAYAAACTqoDjAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJzt3XeYW+WV+PHvUZniGfdeMLYxMTbVYAg1lAVC6C10QicsJWSTEMgvbCCb7Gaz6SQBYgJhNwVCCyVAIIQOoRhTDRgb4wa4j8tUSfee3x+6mtHI0qhelZnzeR49M7q699WZ8fgevV1UFWOMMSZVoNIBGGOMqU6WIIwxxqRlCcIYY0xaliCMMcakZQnCGGNMWpYgjDHGpGUJwhhjTFqWIIwxxqRlCcIYY0xaliCMMcakFap0AMUYNWqUTpkypdJhGGNMTXnttdfWqerobOfVZIIQkWOAY6ZPn868efMqHY4xxtQUEVmWy3k12cSkqg+p6sVDhw6tdCjGGNNv1WSCMMYY4z9LEMYYY9KqyQQhIseIyNxNmzZVOhRjjOm3ajJBWB+EMcb4ryYThDHGGP9ZgjDGmHLq3AwtSysdRU4sQRhjTBmt/eUZLPzBFZUOIyc1OVHOGGNq1V0ffg2AGRWOIxc1WYOwUUzGGOO/mkwQNorJGGP8V5MJwhhjjP8sQRhjjEnLEoQxxpi0LEEYY4xJqyYThI1iMsYY/9VkgrBRTMaYWqOOw5qf/qzSYeSlJhOEMcbUmtann2b93LmVDiMvliCMMaYMNOZUOoS8WYIwxhiTliUIY4wxaVmCMMYYk5YlCGOMMWlZgjDG9HvRLodPFm2sdBg1xxKEMabfe+L2d/nLT+bTtqmr0qHUlJpMEDaT2hiTj0+XbgDiNYlKcB2H6J/Prch7F6MmE4TNpDbG5GNtx1oANkc2V+T9o9EuPg0NwZXauuXalqPGmH6vvssFQDvaK/L+kWiUZwI3MnaHVyry/oWqrXRmjDEFGNQZ/6orF1Xk/R033rS1ZvTsirx/oSxBGGNMoZY+D3MPhljEt7e49ZvXc9MF9/pWfl8sQRhjBgzVEhf40JXwyXzYuKzEBffo3Pw53PBw38rviyUIY8yAsakzWnQZrSsXsPbV+wq8Wop+/3KyBGGMGTAc1y26jObf7svoh88DQFFcKLhqsnF1Owtf+rTomPxio5iMMSYPixbswOqWKewP3BZ2+PnUyTwfbaWvQffqpJ9/8afvvoy6yoy9x/sSa7EsQRhjTB4eH/kDGAn7A3eHHEB4b91q9p7Qx0VegtBA71uuuqXuFCktSxDGmAGj1LfjQ1/djUY5n9iUvtd5khqbIJdQm1EbY0wBVIvvg0g2tOsoAKKrs0zAK/nwqfKomgQhIjNF5GYRuUdE/rXS8Rhj+h/16ZZXm7f/7HxNECJym4isEZF3Uo4fISILRWSxiFwDoKrvqeolwCnAHD/jMsYMVPEaxL0f3MtzK58rWamSpWKiNZpC/O6DuB34FfB/iQMiEgR+DRwGrAReFZEHVfVdETkWuMa7xpiq4brKsg3tLFy1mdVbWtncGWNQuIERTWFmjh/C9mMGEwzU1hj3Acm7T1//z+sBePuct0tTrvSdAGq1D8LXBKGqz4rIlJTDewGLVXUJgIjcCRwHvKuqDwIPisjDwJ/8jM2YTDQapXXpMp576hmWfbCUSGsIdZvRwDCgETcQIBqM8WnjJl6vb+G2uk5W103muJ324+LPTWf04PpK/wgmE59yuEr//HBQiVFME4EVSc9XAp8VkYOAE4F64JFMF4vIxcDFAJMnT/YvStOvqesSW72ayNKlRJYupWXhEj5avIaWjqF01G1Da/Mk3OBUYCp1bpT6zhbqu1qoi7aAurjBMJ31w2hrms7MQJjOYCuL2u/msDeHcuWBx3PuvlOQfnrTqGWJUaWTNs6gI9xa+oIzkBqbQZ1QiQSR7jelqvo08HS2i1V1LjAXYM6cObXZsGfKQlVxNmwgsmwZkY+Wxr8uXUrX0o9oWdPJxsbJbBo6jU1Dt6OjcR9oBpqiqLscCb9C0/BOdtxhMrvsdyDhsfujrotGIsTWriWyfDkdr89n8zN3s7qlgY8n7kd9bH+mh9t46KmbeG7xMdx4xr40hIOV/jUYgO5kHb9lHP3epSUqOLdbkPVB5G4lsE3S80nAJxWIw9Q4dV2c9euJrlpF9NNPia1aRfTT+PfRlSuJLFuGs2ULXfXD2TJ4MpsHb8PG4dPZPPZQdEITAJHAFjY3LqVzyDuMGN/M5/b9F/ba8fA+P/2HRo6kYYcdGHL44Yy9+hq2efddpt5yCx8/9xjvzjydf4kdwYLIU5z+21b+cP5hNNXbdKOqUeoP8jnWEi1B5O5VYHsRmQp8DJwGnJFPASJyDHDM9OnTfQjPlJuqol1duK2tuK2tOG1tuK1tuK1bcFpaiG1owVm/nljLBpwNLTgbNhBracFZtw6N9iy+Fg0Non3IBNpHTmRT8w5s3OUg2kOTQAYD4OKwsXE1mxvfZUtDG/XjJrH/nIM4fIcjGTooXHD8DbNmMfFnP2PEW28x/KqrWFC3N3Ag9bF5fPlPIW7/0r8QCtZmJ2W/U8XzERbNW83jv13AxTccSLiuOmqeviYIEbkDOAgYJSIrgetU9VYRuRx4DAgCt6nqgnzKVdWHgIfmzJlzUSFxuR0duJ2dyQWm/5r0vXa/1v1C39cmlaF5XrP1e2W/Nmt86a5xFVwnvk6M46COG38ec7zjLurEIHHcSZzrHXfdnmtjDhrpwu3qQrsiaCSCdnV5x7zvu7rQSAQ3EkE7OnDb2uLJoK0NYjH6Io0NyNChRIaOJjJoBG2TJ7N5u0FsDg2mNTCMLsYRcId0nx+TKBsbV7Op8X02hjeztm4QwydO55DtP8v+08ez3eimkvcRNO6yC9vdfz+N3/oWde89DByF++FLXP/QUL5//F4lfS9TGG9pvRIWWLqE8/Q97wBCy/otjBk/rGTlFsPvUUynZzj+CH10RPtt/S2/Zd2NN1bq7fs3EaS+HqmrI1Bfh9SFkXAYCYcIhENIOICEgrjDm9Fxo9BwPW4wjBMMEZUQbQTZomHatJ4ObaBLm4gwGHWGEHCber2Vi0tb3SZa6zfQWv8+m0OtrA8oq0NNjBgxid3H78gBkw9hl0nDmDaq9AkhnUBjIxN/+lPCP/xvYs8/ARzK/Ncf5PHtJ3P4juN8f3+TRalrEDn+Ta18d0vWc5x16yA0mjUrP2DM+Or4QFGTjaPFNjGFp42h6dQj45+xhfiHbZH4H48IqtrrZpLpT6rneLo/EgHRjOdo91HpXVbvvrT07y2AineuAtJTg8A7nvhZut8w8V0AV+NXqSqq3jki3QMxXI1PJ3IRnO7vFde71gEchZgGiGqAmBsgqkFiGsDRII6GcDSMo2FUw7gaRrUOdevBbUS0rudncb1HNPmQS1eojY5wKx3hLXSGPqUrtITOQBdbgjHWS4gW6ugMDGL84Al8ZsROzBg7kuljmtl+zGC2G91U0SYdCQQYc8232PO66+hc8AazOZAbH7iJ2ZP/nw2BrTDXp76AbGni2T8tz1pG0AEnBHTFd6e79Zw7GD78Y2D3ouMrVE0miGKbmB5cuIotq48qcVQDjyMOjkRxAjGcQPxrLPE86D0PtHnnODiBCLFAlFjAoUscOsWhU4ROCdClQpcE6CBMh1uPaDND6oYzonFbxjYPZ9KwJmYNb2TS8EYmDmtk4vBGxgxuqNrJaSLCuOuvZ89LL+fJjkkcsHInrr3vUX5zzvGVDm1gK3V+8LFPo7NxLJ92jvWt/FzUZIIo1rtjB7Ek8mhPzYGevxtN+myf7rhuVRNIPd7zXEV7/UFqd7nx71zvuXq1AFK+9pSd/jrQXlWP7tgl5XnK+zheSW4iTuK1Bdc7x0VQEVyvduEknaMawBVwNQCEQEOoG45/1RC4IcKBOuoCTdQF66kP1lMfqmNwQyNDG+porg8xvD5Ec0OIwd7X5vowwweFGdFUx8jmekY11zGkIUygSm/+uZJAgMk//hG7nHIBrzRcwMgF83lq4SoOnmFNTeWXUjUvsUJK3dC5Ie1xp4qWAK/JBFFsE9Mhs4+BxjVeWd2l9nqeOCzS0wy09Wu9b2A9r/dRlncw5W37vCbj6yllZXv/YFAIihAMxB+hgBAI9D7W67U0x4MihIIB6kMBGsIB6kNB6kPe13CAumCg5m/spRRsbmKXX/0Xn37lFpDDuPW+uez/zWsJ26imiih5J7WnkL/4BetSx+bEE0PLxr6XDi+nmkwQxTYxHb7jOOswNGVTP20anz1mCmtfXMec5dtz2/Nv8+UDd610WANSFY9y7SaREs7wLpJ9jDGmDMZcdBEzOp4grGP58G9309rV97BeU2qJod3+1CAKIS1LM7xQ1jD6VJMJQkSOEZG5mzZtqnQoxuREAgH2+tG3Gd7yHtuu/yy/eOTvlQ5pQFKnevogIh8uTHs808jZWNKk0HKpyQShqg+p6sVDh/a1Tbgx1aVu223ZebvVII3oM6+wubP8/+EHulLvKNddbgEdy12bm32IpLRqMkEYU6t2/PdvMXr9ywxv35vfPPBQpcMZOJJXD6gWmUKpnlYwSxDGlFOgsZE9jhyDIASfWUB7xPoiysmvGoQIxFpa8urj2KopKZHEMmQO13EKDa9gliCMKbNp517AiM2v0hDbi1seuL/S4Qwo6tMwpq4tm1i0z748+e0LCi8kdex7FajJBGGd1KaWSSDAXidMAQLwxLtEnSpqU+jvfGpi6ty0HoDQ86/lfM2S9vUpR6onMSTUZIKwTmpT66adeiZD214lrJ/lrocfrXQ4A0Bi1ePqScarPl2T/oUseeLRIy7jsa98q/QBpVGTCcKY/mCPE6ehEmTTQy/71vRhequm33PTlqTJkmve7/5WMoToeH0QS6acxOLIYX6G1s0ShDEVssNJp9HU/hYB3YunX869acIUzu9RTPmUHnQG9zyJdSR1UlcPSxDGVND2Bw7CCQ1i4e/urnQoA4JfNYh0e41lvyhTc1f1pIiaTBDWSW36i/0uvISGjg8JRubwwdIVlQ6n3/MrQbR7S6fksxJrcleD45J1FJPrlH9IdE0mCOukNv3JmJkbiNSP5Lmf3FDpUPq9ap0o99aqNVttJVANajJBGNOffOFrXyMcWY1snElbW0elw+mn/F+sb/Xo3XGCg3I+v6mtJ0Os6lpHtH6M96x6kljWBCEi+4jIr0XkLRFZKyLLReQREblMROwjvDFFCtWFqRv9Ph1NU3j0f/670uH0U4lhrv7cfJ3YIBbseAGfTD4n52uCbk+NwVnWmfX8StR++kwQIvIocCHwGHAEMB6YBVwLNAAPiMixfgdpTH937FVfJuC007GoqdKh9Gu+jXLVIACx8LA8LupJELIlhwSRb0wlkK0GcbaqXqCqD6rqJ6oaU9VWVZ2vqj9R1YOAF8sQpzH92ohRE5DwG2xpns2Lf/x9pcPpv6qpD6IG9JkgVHVd4nsRGScix3ojiMalO8cYU7jdz9oXDQRZ+nDqVpSmWInP6m6RM6mdaPrrA05XUeVKrGchvvcfVZYvXFpUeaWSUye1iFwIvAKcCJwMvCQi5/sZWJZ4bJir6Xf22vcQxHmPtvq9WPX2m5UOp38qoo1p0bzV3HzF02lfC2jKEFTXhazDUnuamIb+qWe5lVh4PA/9bMlWZ1fzMNergNmqeq6qngPsAVztX1h9s2Gupr8aOgci9cN4/qe3VjqUfqmYTuqP3uyrsSSl3L98Gb43Mv79xuVZyw53lX8p71zkmiBWAluSnm8BbFaPMSV26vkXI85aOjp3ItbSUulw+o9EYiiiD6I1uiXziymbO9z70cOcPX5s/MnN+2ctu1p7RrKNYvqaiHwN+Bh4WUSuF5HrgJeAxeUI0JiBJBQO44xfxOah03nqv35Y6XD6nUyb8eRi4fpFfRTcu9zrR4/kjYZ6AKLrW7MXnmkj6iSuW31NTIO9x4fA/fQkugeAT32My5gB67gvnw1uhA1LmtGY7ThXSsUMc21asaGg65b8bXSGV4qbOV2OlWlDWQL4ru8RGGN6mTxxW6L1d7JhxBwW/vEP7HDOuZUOqf8o4qba1BGhszHDi33UANxops/hSdcUENf6T1cwasLkvK/LR7YmprkislOG15pE5HwROdOf0IwZuKYfMxM3WMeCh2w0U2n4v9RGUXJoYkrVUYZlWbI1Md0IfEdE3hORu0XkRhG5TUSeIz5BbjBwj+9RGjPAHH34sbj6IRub9qbtrTcqHY4BJI/+i/0WuFx9V2lHJrlO+Uc6ZWtiegM4RUSagTnEl9roAN5T1YVliM+YgWvmZjrf345nfnoLR97+60pH0y+Ua0O5Kx/MpaaStBZToK6Ad/H/h8lpmKu3vMbTqnqHqt5f6eRgE+XMQHD2hReDu4mN7TNsyGupFDHM1c/luN/c5bK8rynH/to1udy3TZQzA8Gw5sG0j3yXluGzeONnP6t0ODWuFKu5Fnbt5sGZOpJ7Eo4bzF6DcCvQf1KTCcKYgWL/044AlGVvOWg0Wulwap5/Q0Mzlztvj0yLTlTfBkGpLEEYU8X22XUPOuveYd3IvVn1FxsPUizfEkQFpkKXY0RWrov1fUZEbhGRx0XkycTD7+CMMTB472HEwk289ufnKh1K7fPtRu5/hlCnd0IoR07KtQZxNzCf+EZBVyU9jDE+O/fUs3H4hPUNe9H+9luVDqcmSaLmUEQNoq8GocKKza+JqRqX2kiIqepNqvqKqr6WePgamTEGgLpQiLZtV9I6eDLzfn5zpcOpaaVsYkouS8rwcb6aO6kfEpFLRWS8iIxIPHyNzBjT7cSzzkS1g9Utk4mtX1/pcGpXETfy1EtdV7uPZiz24z4+R+c5e9qJVW+COId4k9KLwGveY55fQRljepuxzTZsHvI2a0ftzpKbb6x0ODUoy428AMkzmzOW25l5rla+sahW2UzqBFWd6ncgxpi+TTtsV9bfF2LhSy1sH40i4XClQ6o9JWxicmKRosrNd5Br1TYxiUhYRL4iIvd4j8tFxP46jSmjUw87go7QQlaP3I+Whx6odDg1qZR9EK7jJK3PlKHcPt4v35nZrlOlCQK4ifg2ozd6jz28Y8aYMhERorOidDUMZ/7//a3S4dSmErYxxRwnqUD/J725bu8mpnIkjFwTxJ6qeo6qPuk9zgP29DMwY8zWzj/jXBw2sKZ+D9rnv17pcGpPEQkiNQX0mqiWUu7iacfz5EHZFljMM6m45e+DyDVBOCKyXeKJiEwDSh6tiBzvTch7QEQOL3X5xtS6scOGsH7cQlqGz+D9X1lndb6KamJKuVZ7dVL3fm355MNyKLD/NDFdBTwlIk+LyDPAk8DXc7nQ2z9ijYi8k3L8CBFZKCKLReQaAG+l2IuAc4FTc/4pjBlA9j76SFSjLF87gejHH1c6nBpRfNuSpgxLdZKbmMoxDyIlQbnVspqrqv4D2B74iveYoapP5fgetwNHJB8QkSDwa+ALwCzgdBGZlXTKtd7rxpgUR+yxGxsGv8OqsXvxydzfVDqcGlH8jTz1877jlHdms6a+Xxk2t8i25egh3tcTgaOA6cB2wFHesaxU9VkgdbfvvYDFqrpEVSPAncBxEvdD4FFVnZ/fj2LMwCAiNM0egxNq5P2X1uC2tVU6pJpR3GrfKZ/gk/sE/Fxqw6spOI6y7NVnC3mjgmWrQRzofT0mzePoIt53IrAi6flK79gVwKHAySJySboLReRiEZknIvPWrl1bRAjG1K6LTjqVtvByPhlzAC13313pcGpHMRkipYnJdZzum3cfb1j4+6Vw1WHRwiUlKy8X2bYcvc779j9U9aPk10SkmMlz6VKnquoNwA1ZYpoLzAWYM2dOBRbZNabyhjTUsXnbNTRF5/DeHbew39lnI8FgpcOqfiW8Y7ixcu3PkWgec6HMzVq5dlLfm+ZYMYvTrwS2SXo+Cfgk14tty1Fj4LgTTiUmrXzSPIfWp5+udDjVrRR9ySkX9+o0LqRmkuNaTImFAJ9f9AQb/vJe/u9ThGx9EDuIyEnAUBE5MelxLtBQxPu+CmwvIlNFpA44DXgw14tty1FjYM/ttmX1qHdZO2oXls69tdLhVDXxYbRR72Gn6W/2fbZA5RxL/MRhj4xk7bijcr2oJLLVIGYQ72sYRu/+h92Bi3J5AxG5A/gnMENEVorIBaoaAy4HHgPeA+5S1QWF/QjGDFwzPrcHKrB0y7Z0vvtupcOpWj3LWpRuGFPyPIhMxa5cXvjbpWoZsVvpCstRtj6IB4AHRGQfVf1nIW+gqqdnOP4I8EghZYrIMcAx06dPL+RyY/qNs//lUK77+88JTdifVXPnMuXnP690SNUpcXMv4dQBxekpMFMTU1/5KOd5chkKKcPM6lz7IC4RkWGJJyIyXERu8ymmrKyJyZi4QEAI79yEE2pk4YIo0dWrKx1SdSvh5DIn5ibVS9Lf7d2+MkQNDLHJNUHsoqobE09UtQWY7U9Ixph8fOWks9nQuJgVEw9i3S02cS69+A28lKu5Ok72T/ArvlP8cihShglxmeSaIAIiMjzxxNtNLqe9JPxgo5iM6TFsUCNbpm2iq2Ek7z+5GGfjxuwXDTDdt1i38Jvt1jvKuT1H1f/VXCsh1wTxE+BFEfmeiPwH8Z3l/se/sPpmTUzG9HbBKefQFl7NivEHs+EPf6h0ONWriATRdyd1pnL7SBx5bjmaqmqW+1bV/wNOAlYDa4ETVfX3fgZmjMndjLFjWDVxMVsGb8uie5/G7eiodEjVxbsXq2rJmplct2fSWkG3+pzjqP4mJoARQJuq/hJYW+RMamNMiX3+mJOJBLawfOQBbLz3vkqHU2W8PakV3GJqEclc7Sk3Y4qogZ7oPuS65eh1wNXAt7xDYaBi9VjrgzBma5/fcSYrx7zF+lE7s/R3f0aj5VoKogYkPq27uXUu91mGp3cfRPpE8OauVxT2Xr3fOO3RIluocpJrDeIE4FigDUBVPwEG+xVUNtYHYUx6sw89EIcuPhq8D5v/ZtuSdvPWq1BXCu+HSLkja3I5PlYUMo1iKsfgplwTRETjDXcKICJN/oVkjCnUmfsdwPLR81k1dg7Lbr69pMM6a1ri96DgaGkmmLkaK89duoJyTRB3ichvgGEichHwBHCLf2EZYwohIkzed0dccfkwuCutTz5Z6ZCqRE+CcAttYkqpJqiTXIMopL0nny7gysh1FNOPia/eei/x9Zm+43VWV4T1QRiT2aWHH8uykfP5dNzeLP/FTVaLAHo6qQUt0RIVyRsGpe5JXQ6pW5D6IddO6ibgSVW9injNoVFEwr5G1gfrgzAms1AwwKg9p+EGhMXuDrT+4x+VDqkKJNUgUm+s0U64eX9Y9mJ+JdpEuW7PAvUiMpF489J5xPeaNsZUoa8edRLLR7zOxxP2Z8UNVotIvpG7saRP/qqwbiGsehse/WYuJfQ8L3qiWq5JpfrnQYiqtgMnAr9U1ROAWf6FZYwpRkM4RPOu43ADIT6MbW+1iG6Cm9RJ7SYv3pfnfbjXMNeCQuknfRCAiMg+wJnAw96xiq3FZIzJ7hvHn8HHw95i5cTPseIXN3pNIgOcSq+RR47r0B7rYpcp2/CPYH7zRnr9PgvKE8UlCC3D9qO5Rngl8Ulyf1HVBSIyDXjKv7D6Zp3UxmQ3qD7EoN1G4ATrWOzOZMuArkUkVnOVXjf2zs4OlrWvQkW4KdyZV4nJtY9C8oP2lxqEqj6rqseq6g+950tU9Sv+htZnPNZJbUwOvn7imSwbMd+rRdzce4G5ASWeIESl1+ijro4OFJjcMguJ1WUpI3WYa9KxAjJE0Qki4H+Cqf4UZowp2KC6MEPnTMAJCB8EdmHzX/9a6ZAqSgn0mgEdaW/no+VRjnz/y8xYclqf10pqgtBim3iCOZ6XaakNSxDGmCJ945jTWDpqHp+M35ePfnELbldXpUOqAO9Wl1qD6GrH7YzfgIe1ju67iNTlvnsWl9j6xRwUW4Oopj4IY0yNagiHGLf3TBxxWDxkf1r+9KdKh1R+iXWUVHrNg4h0dhBeswGAYZvzK7LYVWH7TR+EiPyPiAwRkbCI/ENE1onIWX4HZ4wpja9+4TiWjpnH6rFz+Oi2u3E253k37DcCaFLncjTSBQEveWSpBKTOlo6XU0wfRI5NTDWw5ejhqroZOBpYCXwGuMq3qIwxJRUOBtjx0H2JBDv4YPxRrJs70JZSS9zqeo9iinZ1JeWFvjNEah8ESWsxFXQLz7UGkWFdb8fxP3HkmiASy2ocCdyhqht8iicnNszVmPydf8DBfDjhVVpGzGTRgy8TXbWq0iGVUVITU3KC6OxECtxYQdWhmD6IXDmhyi2enWuCeEhE3gfmAP8QkdFAfoOGS8iGuRqTPxHh6BO+SGt4DYumHMeqH/x3pUOqgECvBOFEIkiBw0W1VDvTVbFc50FcA+wDzFHVKPGNg47zMzBjTOkdsePOLJuykPZB43n/7XbaX3ut0iGVSeITfqDXBLdoV2TrpqOMStsHUQty7aT+IhBTVUdEriW+3egEXyMzxvjiijP/lTXNi/hw2tGs+O5/DpDJcz1NTMmf/GOxSNJ8gvyaiVw36RL1v6lpq/cv0cZHfcm1bvXvqrpFRPYHPg/8L3CTf2EZY/wyc9wYOmZFiIUG8b67IxvvvqfSIZWB9HxNShBOJNrdB6F53tyTO7ul+/v+tex3rgkikaqOAm5S1QeAbPPSjTFV6rozL2HJqFdYOfFAFt/4R5yNGysdks8SNYggaHIfRLT7pey39tSlNpytXyqww7sQgVyHyRbzHjme97G35egpwCMiUp/HtcaYKtNUH+Yzh+1OV6iV9yYdz+of/ajSIfmr+8Yd6tU0E4tGEe9Wlm83ghuLAfFko5pUQ+lHcr3JnwI8BhyhqhuBEdg8CGNq2pc/93kWbTuPLUOmsOCfa2l/9dVKh+SjxI07iOuk1CByvKmndmY70SiJBIEmkkwZ+yDc/JYnL0Suo5jagQ+Bz4vI5cAYVX3c18iMMb4SES4961JWN3/Ah9OO5aN//16/XacpceNWCfXaXc+JOEnz1fK7uTsRBySRbArr6C5GrKtKEoSIXAkAqi27AAAdMElEQVT8ERjjPf4gIlf4GZgxxn87T5iAM1uIhsIsaDqQtTf6N/Zk+QUXsuzc83wrv2+JjoZQ73kQXdGC+w2cWJTu7lmvBlHOPohIl/9T0XJtYroA+KyqfkdVvwPsDVzkX1h9s5nUxpTO9adeyMIJz7N29Gzeu38enQs/8OV92l54gfaXXvKl7OwSI5VCvUYfvbDxTQLBXDfH7N3E5MZcUpuYylqDiPhf28t5y1F6RjLhfV+x3hibSW1M6YRDQb54xhmsb1zKwumn8NE3/x8aiVQ6rBLrqUEkL7o3fsOonjWRsq2NlHLHc2MOSKKsYPqTfBTr8v/fKNcE8TvgZRG5XkSuB14CbvUtKmNMWR04fSZbZrcSCdfzVng/1vzihkqHVFqJuQ4S7jVRbnDgRCSY6wiklGGuMZeez81eJ3UZm5icaJUkCFX9KXAesAFoAc5T1Z/7GZgxpry+f/plvD/xOdaN2pV3Hl5A+7x5JS2/q24IHQ0je3USl09SJ3VSExOABBMjkLLdDnvf/F3HRbqbmCpQg4j4v2FQ1sY3ic9Df0tVdwLm+x6RMaYi6sNBzj/nIh684W8Etj+Fkdd8n53v/wPB5uaSlP/CPv8JEmDX9naCTeVeoTR+43YDIW8V1qRXAjk2MW01US55ue8KJIhoFYxi0viKVG+KyGTfozHGVNQek7el4YBGOsNR3hh3Ih//v2tL94nfuwG3r/2kNOXlIXmYa+pOcIHu9fbyTBC9yvF/VnOqNS+t9v09cu2DGA8s8HaTezDx8DMwY0xlXHPs2by//Uu0NU9i/kfDafnjH0ta/rpli0paXi4CSTWI1B3aujut89wCVJ3kpqpEH0T5FphwNZz9pCLlOr7ru75GYYypGiLCf178bb73wx8Bn+PN397O3jvvTOOuu5ak/DUrVzC1JCXlRh2nZ4azBHA6u4D6pBMKW4k1vqRTzwztQsooRjneqc90JyLTRWQ/VX0m+UG8rrWyDPEZYypgVFMTJ3/pVNY2Lea9z5zBO1//HrGWlpKU3bJ6XUnKyZlqrwlskS299+OW9fGFCrN/+k/tg0h+Vv4mpp71n/yT7Tfyc2BLmuPt3mvGmH7qgOkzGX74YNrDW3hjm9NZfPm/lWR+RNvGthJEl5/kW3vnpt4r17q/eSh+TpYEkXo7jtcges+DKGcTU8/kPP9ke4cpqvpW6kFVnQdM8SUiY0zVuPLzp7Ny9gd01g9inrsfK79zXcGd1gEnnlwirf4Pz+xFFQgQcOIzjzs2b+kVzxu7fSURYd/FbHVAkjq/E7sflHP+cOVrEA19vNZYykCMMdXpJ+d9iwXTn2LT0O146YMRrL/ltwWVE4q1AxCrwG72KkLISxBdm9u9eNq2OicvydtBBOoLK6Mola9BvCoiW625JCIXACXdzFZEponIrSIyELa3MqZmBIMB/ufy77Jg0mOsGbMHzz+4gk1/eyz/cpx4ZtBO/0ff9OLVeFQ7AIi0x2sOAad363nWJqaUe786Pf0ObqCvz9L+0GDlZ1J/FThPRJ4WkZ94j2eAC4ErsxUuIreJyBoReSfl+BEislBEFovINQCqukRVLyj0BzHG+GdIQyNXXfo1Fo9+lo8nHcSLP3uEtrwX3vPusNHy30yRACrxGkSsMz48NaAp3av57tDm9gwCdQOJUVHl64M45vv+r4zb50+jqqtVdV/iw1yXeo/vquo+qroqh/JvB45IPiAiQeDXwBeAWcDpIjIr78iNMWU1dcRYzrr4bFYMfY0lU4/jxe/cTsfbb+d8vXo3YHUH+RVi+vclPlFONF6DcbriNQoh387ylF6I5AQRjPdBlLOJaeyEib6/R65rMT2lqr/0Hk/mWriqPkt8/aZkewGLvRpDBLgTOC7niI0xFbPHNttxxPmHsqr5HT6YdgovXHUjXR9+mPU613W7EwQM9jfITMRr4orGb3sS7CiywDBbdRSXcxRTGVTip5kIrEh6vhKYKCIjReRmYLaIfCvTxSJysYjME5F5a9eu9TtWY0yKg2bMZp8v7cqapgUsnPJFnrvix0RWftznNW4sigbiCaKrfixtn5RxGpVq/JO918SU6DsI1OXehv/p4o24gZRxOVqX/uR+pBIJIl0dTFV1vapeoqrbqeoPMl2sqnNVdY6qzhk9erSPYRpjMjlylwPZ/aydWN/4Lgu3OYnn/vW/iPXxgc1xot2dwNG6wbxy/53lCtUblhuAQHxxO3W8TvKG3Ifr3vfj+XQG9+5dLuE0Y1/7l0okiJXANknPJwHlX73LGFOU42YfzM5nz6Kl4QPen3ACz170XZyNG9OeG4104UqQgLsMgLWvflS2OFVdEBDxVj/11jBKLPNdMMlcg6jvKN/P56dKJIhXge1FZKqI1AGnAXkt/GdbjhpTHU7Y/RB2+tIObKr/gPfGHs8zF16H07p152+sqwuVAOHAp4jTitO6DRorz4Q5VY13UuMibqSnaShNh3LL2hVbHcs0MVCT13NKITgZX6slviYIEbkD+CcwQ0RWisgFqhoDLgceA94D7lLVBfmUa1uOGlM9jt/jEGacvT1bwot4b+QxPHvRd3C7eu+XHI11ohJExMFt/ICNw3bl9bm/Lkt88RpEAASCTspCfSle/Xua+R1uhgQR6Gs0Vv9oe/I1Qajq6ao6XlXDqjpJVW/1jj+iqp/x+hv+088YjDH+O2nPw9ju7Cm0hRbz7pAv8NxF30GTNrSJdLbH+yAE9jhjH9xgPUv+vjZtbaPUXDf+aV4URDtRb4GIdGvdfTx/yVbHMtUgYqGmdJUQ7yI3wwu1pSbHZFkTkzHV54uf/QKTzhxHZ2Ax7zQexvNX9nz2i3R2gAQQcdln7/3oGjSf1WMO4vELr0Qdf5tjuu/VoojbhUo8QYjAuLUv9zo3tm7E1tdnSBBusB7cMMFY7+GyHW1t8WzUD9RkgrAmJmOq0xn7Hs/oM4YT0494J7o3H9z6ZwAind4CTN4n7nOvPQ9HVrOs+QSeOO+ykqwSm0nyHtRCJ26wofvZCX/4KqFoKwDBWAex8E588P78lOv7SGA6CNHeW3+++9rLYH0QxhiztS8dcCqRw1eBtvP8sw6R9S1EvT4J8T5ZjxgxkoOvnEU02MrihhP462lfpTPLXIpCua7XGS4K2tUzn0Eg0NhIwIkniIbYS7jBOp7+5V96Xx/L3FzkStNW3Q0r3noHKO1+0UFvocNyq8kEYU1MxlS3b5x0LSsnPkxH4zge+85viXTFaxDJE413njmbw6/emc7QUpaPOZm//NufmX/j3NLtge1xkvpCVLpwQj1NTAAB16tBjFWaWt/CiezDm6+/0H2Ny9YJInHD1kAzQHctBGDjh2tASpsgRjffUNLyclWTCcKamIypbiLChVdcS7BzAZ90foboFq+dPuWOM2PaLC7+yRm0jnmGDcN35JX5k7jvi1ez/IVXShaL6+0dLdA9m9oL0jve01E++ZBmVEK89KvnuxNVuiamYCyeEGKh5l7PAZxN9YiWtonJYVhJy8tVTSYIY0z1mzpqKpvHv0ksPJiVjy8C0i9V1NQ4mKv/47tsf8YW2usWsmrUETx+ywruPetq1rzzQdFxuE5ivoV2z6aOB5P4Juadpxxy/oUM7nqWWHhP/vybX8aPx7a+2SdqHfH+DCXg9qwMq86EomNOFdpmTq/n9V35rqRbmJpMENbEZExt2PesUwhHNrN5U3xZnL7Wsjv8oJP5yq+uoHGveXSGN7Cq+fM88JO3ufeca1m7qPCZyV2JCXkCBHsm53UPUZV4AtBYvMZw8DdPoa5rPZtfHsHGLRtx085p6Oi1KbUQTxihyEYidRPREt9aJdC7vPDQ1gxnllZNJghrYjKmNuw36zAk+h7tg7YDQAJ9L4cdCoQ4//xvct4vT0N3epKu4HpWNR7C/f/1Ovedfx0ty/NflSfmxGsNAhBOqg0kMoQkahDxp5N23IXRI+YRrZ/AH6/9CW7aPhG3e0c6QSEQ72MJxdahwTqUsX3GJG5+s8gFIdz+Rl7XlEJNJghjTG0QEdyGT3ue53jHaWoYzOWXf5+zbjiJzh0eIRJYy6d1B3LvdS9y77/+J1vWpV/zKZ1EE5MISNJmdtKdILwahNOTvI794fcY3Po2gfZ9+efLz6UtN+gkfYoPxcsIEF+wsKtx2yxR5dcRryhH/vIs6jpezn5yCVmCMMb4KjA6qSkmzwXyhg0ayde/+mNO/vkxtE69n6hsZJXuw5+/8Rj3fuOntHdmnz8R7R7FpAQaet6/O0EEvE/zTs9rgVAdux45BBCW3bU8bbni9nRuH3Dx8QDs9+XDCUX9mR0+aeiYst+wLUEYY3w1ataU7u8Dee7qmTB28ASuvvoGjvzxgWwZdzeOdLKqdTfuuui3/PXOJ/q8Nub2NDGFBvVUIbqbuwLep/mU0ay7nnEeQyJPE6vfKUPJPTWI6Z/dhctuPoTP7LcndV3Lsv48UuxQ3jJN1K7JBGGd1MbUjhlz9uv+XkLF3XK2HbE911x/E5/7/o7E6h6ko35bVvwjym//7X/oiKQfWto9D0KEcHPPftjdLUyJA2kWZ9rppD0yRKJIIMPkteC67D9InrrnhvQEW/L3SKcmE4R1UhtTO7af3jNEMxQO9XFm7mZOnMOVN/ycyUcvJBRZSVfHHP50yQ9Zv6Vzq3OdRB8E0DhsSM8L3RkicbPdOkHseuwXaWxP08QkQMjbwjTlOqkrxwij8ux9XZMJwhhTO8Khuu5RO6FwOMvZ+Tnq+K9x+PfnEOp8kc66vfnLV35GW1fvEUJOYunxgNA8amT3cUlNEOmWdwWCZOiDCMdrJk6o97LfoSHZV3LVjMvApifdk/q8yXt5XV04SxDGGN81dsSbXcKDMu/FUKhtt5nNST8/h3Dn83TVf5bfX/XjXst1RCPeJ/2AMGz8+O7j3SOq+qhBAMigjjRHFakXr9zeSW/Q6CFpzt+q1BzOSXq37p+nvKvEWoIwxvhuwsoHCcY6aRre6Ev5o4Ztw5E/OJmG9vdxO2dz75+f7H7N7fI6qYMwemLP8NPE5LPuD/MZahChwelvk8H69Oc3jx6eMc66wHzvrfq+9TbyTJ+vU+L1qjKpyQRhndTG1JaG6Pt87vmvM2rcFN/eY9L4WWx7shJwY2x69P3upqZYZ08T07jRSTWIxFdJPdJbqCl9rSfYkL4/Zdj4cRljDAe9e1aWBDFkavpE6naPvCpwOFieajJBWCe1MbWl7vobeXXWnkzZc19f3+fQYy8jIE/S2TiT+266E0gaxRQU6sN1PScnlq/o7oNIfzusa9w6QSgQbqzb+mRg3NRpmQMM5PbJX1L6KNTb9vTgq44n7LzOcdd+LadyilWaIQXGGNOHfQ7dl30O9Tc5JOx76eG88Ks2Iq+vxXW1u4lJgymjjVLGuaaORkoINzWkORqioTn9ntRjt90emJ/2NYCuxhWM33sMG57qoz8mw0f37WbOYrtbZmW+rsRqsgZhjDGZ7DT78wScV+mq35EX5i3GiST6IHongECgd4KQDAkiWJ/uRh6mYUhz2vPrG/tq2VC+9rNzOP3UL/T1IyApTVDZ1rDyiyUIY0y/M2o30ECIRX++C43GJ9BJqHe7faKT2m2MD0vtqtt6DgVAuC5dggjSPCLDHg19DGHVDB3hyUKb79uqiEQTU7lZgjDG9DsHnncJ4UgLrGvE9fogNJRy1/U+lY/cv54lzXfQtceracsakq5GICEGDR+Rf2A53Odv3P+jPpNMOVmCMMb0OyOGTiAQW0w0NI329vgopkAoPl9BvLWZAl4zzrG7H8fFw//ClbO/mLascePGbHVMCTGoabAfofPKxQ9u1cRUKdURRZ5smKsxJpvAsDXEwkPoWBFfMylQHx91lJjV3d2uP2kOMy57ncCcc9OWM2b27lsflBBNgwvYBjT7JGvqQ0GGTij9rnSFqMkEYcNcjTHZjNktPh/B2dwEQKAh3pcg6nVaJ+/SNmybjM069YMHceFPD+h1TCXEoGG5zJjurVcLk2bOFgefchpjZ7xPfUf6ZT7KpSYThDHGZDP78KMR1yEWmAhAqCE+LFU0XoMIBHOfbFY/qPdyGkqIQc251SCatyQt/52UIaSPBAFw8r9dipB9vws/WYIwxvRLEybuQDiyio5BkwAID0okiPioplB9+oluudBAmHA4t2VDnEFLk5711FKSE8QO7/8hyxvmEVwJ2UQ5Y0y/JCKIfgrEaxB1zU3eK/Ebc7iu8JVlVUK9m6j6Pjvtt12jFxHesCMAT894mTe2+4hI/XAu45Ck8yuUGTxWgzDG9Fuxxg3d3zcMTow6iieIQPr9hXLiBvr+bH3S2dlrJ1/9ryu6v5/55dtZOmYdnwxdVHhQPrAEYYzpt2RMTzNOw5B4p3I4uj7+Wiya9prcCu771jluv/1paI/f7APJnd8ZJsqdsfueaY+rtztd47hJBQRZPEsQxph+a/iuU7u/Hzx0LAC77raR7RfdzZzPH5ZXWcFYun0h+hJPTsPqtmQ847XdNvHAhCUZX//CDy6Facs54szT83zv0rA+CGNMv7XHgYfyt7+vAGD08Pioo9lf/3f4NxfJYxQTwJhBd9H8TgeLPnNJTucn6grOxDFMfu4Rlk8+cqulNm675IQ+y5g4bjiXffPcvOIspZqsQdhEOWNMLqaO3I6YxGdSDx3kTZQTyTs5AJx4w/9y2BN30rxlORNX/D7r+YkxTts2jGDd+MR6TpXtdM5XTSYImyhnjMlFQAK8Mutxnpj6VxrCxW+yI4EAnzsrwCG/+XbWc/c5blvqIy3MOu1YuhNDDov1VRNrYjLG9Gu//fKPaY/ESlbe1C98Kafzppx0JBee5D3Jsq0pwB1H3cHSzUuLiq3ULEEYY/q1xrogjXXl2aIzk1walnYatRM7jdrJ91jyYQnCGGMKtN2Sf/cqBYf0eZ5IbfU9JFiCMMaYAh3x+As5nlmbfRA12UltjDE1Rbb6piZYgjDGGJOWJQhjjPFZTx+E1SCMMcYk0RyGuVYjSxDGGOMzqbEZ1AmWIIwxxm/eiq6pazFVO0sQxhjju9qsQVTNPAgRaQJuBCLA06r6xwqHZIwxJREMAA5IjX0m9zVaEblNRNaIyDspx48QkYUislhErvEOnwjco6oXAcf6GZcxxpRTg7fURzBgTUzJbgeOSD4gIkHg18AXgFnA6SIyC5gErPBOK2IzQGOMqS4TGlbFv7rzKxxJfnxNEKr6LLAh5fBewGJVXaKqEeBO4DhgJfEk4XtcxhhTTjMnbMchT1/GzkOaKh1KXipxI55IT00B4olhInAfcJKI3AQ8lOliEblYROaJyLy1a9f6G6kxxpTAkLMuo2GnmYz86nWVDiUvleikTtcIp6raBpyX7WJVnQvMBZgzZ05tDg0wxgwooeHDmXrPfZUOI2+VqEGsBLZJej4J+CSfAmzLUWOM8V8lEsSrwPYiMlVE6oDTgAfzKcC2HDXGGP/5Pcz1DuCfwAwRWSkiF6hqDLgceAx4D7hLVRf4GYcxxpj8+doHoaqnZzj+CPBIoeWKyDHAMdOnTy+0CGOMMVnU5HBSa2Iyxhj/1WSCMMYY47+aTBA2iskYY/xXkwnCmpiMMcZ/olq7c81EZC2wzHs6FNjUx/epX0cB6/J4u+Qyc3099VglY8w3vnRxpTtWyRjt37n4+NLFle6Y/TtXV4zFxjdMVUdnjUBV+8UDmNvX92m+ziu0/FxfTz1WyRjzjS9dPNUWo/0727+z/TsXHl8uj5psYsrgoSzfp34tpvxcX089VskY840vUzzVFKP9O+f2mv075xZDtterKcZSxJdVTTcxFUNE5qnqnErH0ReLsXjVHh9YjKVQ7fFBbcSYqj/VIPI1t9IB5MBiLF61xwcWYylUe3xQGzH2MmBrEMYYY/o2kGsQxhhj+mAJwhhjTFqWIIwxxqRlCSINETlIRJ4TkZtF5KBKx5OJiDSJyGsicnSlY0klIjO93989IvKvlY4nHRE5XkRuEZEHROTwSseTjohME5FbReSeSseS4P3d/a/3uzuz0vGkU42/t1S18PfX7xKEiNwmImtE5J2U40eIyEIRWSwi12QpRoFWoIH4DnjVGCPA1cBd1Rifqr6nqpcApwAlH9pXohjvV9WLgHOBU6s0xiWqekGpY0uVZ6wnAvd4v7tj/Y6tkBjL9XsrMkZf//5KIp+ZfbXwAD4H7A68k3QsCHwITAPqgDeBWcDOwF9THmOAgHfdWOCPVRrjocR34zsXOLra4vOuORZ4ETijGn+HSdf9BNi9ymO8p4r+33wL2M07509+xlVojOX6vZUoRl/+/krx8HXDoEpQ1WdFZErK4b2Axaq6BEBE7gSOU9UfAH01z7QA9dUYo4gcDDQR/w/bISKPqKpbLfF55TwIPCgiDwN/KkVspYxRRAT4b+BRVZ1fyvhKFWO55BMr8Vr1JOANytgKkWeM75YrrmT5xCgi7+Hj318p9LsmpgwmAiuSnq/0jqUlIieKyG+A3wO/8jm2hLxiVNVvq+pXid94bylVcihVfF4/zg3e77Hg3QPzlFeMwBXEa2Ini8glfgaWJN/f40gRuRmYLSLf8ju4FJlivQ84SURuovBlJEolbYwV/r2lyvR7rMTfX176XQ0iA0lzLOMMQVW9j/h/gnLKK8buE1RvL30oaeX7O3waeNqvYDLIN8YbgBv8CyetfGNcD1Tq5pE2VlVtA84rdzAZZIqxkr+3VJlirMTfX14GSg1iJbBN0vNJwCcViiWTao+x2uMDi7HUaiFWi9FHAyVBvApsLyJTRaSOeOfugxWOKVW1x1jt8YHFWGq1EKvF6KdK95KX+gHcAXwKRIln7gu840cCHxAfTfBti7F247MYB2asFmP5H7ZYnzHGmLQGShOTMcaYPFmCMMYYk5YlCGOMMWlZgjDGGJOWJQhjjDFpWYIwxhiTliUIMyCIiCMibyQ9cllOvSwkvmfGtD5ev15EfpBybDdvsTdE5AkRGe53nGbgsQRhBooOVd0t6fHfxRYoIkWvZSYiOwJB9Vb6zOAOtt4v4DR6Vsj9PXBpsbEYk8oShBnQRGSpiHxXROaLyNsisoN3vMnb/OVVEXldRI7zjp8rIneLyEPA4yISEJEbRWSBiPxVRB4RkZNF5F9E5C9J73OYiKRbAPJM4IGk8w4XkX968dwtIs2quhDYKCKfTbruFOBO7/sHgdNL+5sxxhKEGTgaU5qYkj+Rr1PV3YGbgG94x74NPKmqewIHAz8SkSbvtX2Ac1T1EOK7q00hvuHPhd5rAE8CM0VktPf8POB3aeLaD3gNQERGAdcCh3rxzAO+5p13B/FaAyKyN7BeVRcBqGoLUC8iIwv4vRiT0UBZ7tuYDlXdLcNriU/2rxG/4QMcDhwrIomE0QBM9r7/u6pu8L7fH7hb4/txrBKRpyC+lrOI/B44S0R+RzxxfCnNe48H1nrf7018A6gX4nsZUQf803vtTuBFEfk68URxR0o5a4AJwPoMP6MxebMEYQx0eV8dev5PCHCS17zTzWvmaUs+1Ee5vyO+oU4n8SQSS3NOB/Hkkyjr76q6VXORqq4QkaXAgcBJ9NRUEhq8sowpGWtiMia9x4ArvG1JEZHZGc57nvjuagERGQsclHhBVT8hvu7/tcDtGa5/D5juff8SsJ+ITPfec5CIfCbp3DuAnwEfqurKxEEvxnHA0jx+PmOysgRhBorUPohso5i+B4SBt0TkHe95OvcSX9b5HeA3wMvApqTX/wisUNVMeyQ/jJdUVHUtcC5wh4i8RTxh7JB07t3AjvR0TifsAbyUoYZiTMFsuW9jiuSNNGr1OolfAfZT1VXea78CXlfVWzNc2wg85V3jFPj+vwAeVNV/FPYTGJOe9UEYU7y/isgw4p3K30tKDq8R76/4eqYLVbVDRK4jvon98gLf/x1LDsYPVoMwxhiTlvVBGGOMScsShDHGmLQsQRhjjEnLEoQxxpi0LEEYY4xJyxKEMcaYtP4/I081NzD/ylsAAAAASUVORK5CYII=\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -746,7 +746,7 @@ "source": [ "lower_bound = 2; # inclusive\n", "upper_bound = 2; # inclusive\n", - "rm_res_cov_sub = gd157_endf.resonance_covariance.ranges[0].res_subset('J',[lower_bound,upper_bound])\n", + "rm_res_cov_sub = gd157_endf.resonance_covariance.ranges[0].subset('J',[lower_bound,upper_bound])\n", "rm_res_cov_sub.file2res.parameters[:5]" ] }, @@ -831,7 +831,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/icmeyer/openmc/openmc/data/resonance_covariance.py:231: UserWarning: Sampling routine does not guarantee positive values for parameters. This can lead to undefined behavior in the reconstruction routine.\n", + "/home/icmeyer/openmc/openmc/data/resonance_covariance.py:233: UserWarning: Sampling routine does not guarantee positive values for parameters. This can lead to undefined behavior in the reconstruction routine.\n", " warnings.warn(warn_str)\n" ] }, @@ -868,51 +868,51 @@ " \n", " \n", " 0\n", - " 0.029174\n", + " 0.031065\n", " 0\n", " 2.0\n", - " 0.000468\n", - " 0.110557\n", + " 0.000474\n", + " 0.107954\n", " 0.0\n", " 0.0\n", " \n", " \n", " 1\n", - " 2.826584\n", + " 2.823809\n", " 0\n", " 2.0\n", - " 0.000348\n", - " 0.090882\n", + " 0.000334\n", + " 0.098218\n", " 0.0\n", " 0.0\n", " \n", " \n", " 2\n", - " 16.768498\n", + " 16.769186\n", " 0\n", " 2.0\n", - " 0.013018\n", - " 0.076285\n", + " 0.013987\n", + " 0.072910\n", " 0.0\n", " 0.0\n", " \n", " \n", " 3\n", - " 20.561904\n", + " 20.556649\n", " 0\n", " 2.0\n", - " 0.010537\n", - " 0.096260\n", + " 0.010814\n", + " 0.098780\n", " 0.0\n", " 0.0\n", " \n", " \n", " 4\n", - " 21.652164\n", + " 21.654591\n", " 0\n", " 2.0\n", - " 0.000356\n", - " 0.159153\n", + " 0.000366\n", + " 0.117679\n", " 0.0\n", " 0.0\n", " \n", @@ -922,11 +922,11 @@ ], "text/plain": [ " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.029174 0 2.0 0.000468 0.110557 0.0 0.0\n", - "1 2.826584 0 2.0 0.000348 0.090882 0.0 0.0\n", - "2 16.768498 0 2.0 0.013018 0.076285 0.0 0.0\n", - "3 20.561904 0 2.0 0.010537 0.096260 0.0 0.0\n", - "4 21.652164 0 2.0 0.000356 0.159153 0.0 0.0" + "0 0.031065 0 2.0 0.000474 0.107954 0.0 0.0\n", + "1 2.823809 0 2.0 0.000334 0.098218 0.0 0.0\n", + "2 16.769186 0 2.0 0.013987 0.072910 0.0 0.0\n", + "3 20.556649 0 2.0 0.010814 0.098780 0.0 0.0\n", + "4 21.654591 0 2.0 0.000366 0.117679 0.0 0.0" ] }, "execution_count": 15, @@ -935,7 +935,7 @@ } ], "source": [ - "samples_sub = rm_res_cov_sub.sample_resonance_parameters(n_samples)\n", + "samples_sub = rm_res_cov_sub.sample(n_samples)\n", "samples_sub[0].parameters[:5]" ] } diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index e2ed90a7d7..4d8d502e42 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -1,4 +1,4 @@ -from collections import defaultdict, MutableSequence, Iterable +from collections import MutableSequence import warnings import io import copy @@ -109,7 +109,7 @@ class ResonanceCovariances(Resonances): # Throw error for unsupported formalisms if formalism in [0, 7]: - error = 'LRF = '+str(formalism)+'covariance not supported '\ + error = 'LRF='+str(formalism)+' covariance not supported '\ 'for this formalism' raise NotImplementedError(error) @@ -150,6 +150,8 @@ class ResonanceCovarianceRange: The covariance matrix contained within the ENDF evaluation lcomp : int Flag indicating format of the covariance matrix within the ENDF file + file2res : openmc.data.ResonanceRange object + Corresponding resonance range with File 2 data. mpar : int Number of parameters in covariance matrix for each individual resonance formalism : str @@ -159,7 +161,7 @@ class ResonanceCovarianceRange: self.energy_min = energy_min self.energy_max = energy_max - def res_subset(self, parameter_str, bounds): + def subset(self, parameter_str, bounds): """Produce a subset of resonance parameters and the corresponding covariance matrix to an IncidentNeutron object. @@ -210,7 +212,7 @@ class ResonanceCovarianceRange: res_cov_range.covariance = cov_subset return res_cov_range - def sample_resonance_parameters(self, n_samples): + def sample(self, n_samples): """Sample resonance parameters based on the covariances provided within an ENDF evaluation. @@ -286,7 +288,7 @@ class ResonanceCovarianceRange: gn = sample[1::mpar] gg = sample[2::mpar] gfa = sample[3::mpar] if mpar > 3 else parameters['fissionWidthA'].values - gfb = sample[3::mpar] if mpar > 3 else parameters['fissionWidthB'].values + gfb = sample[4::mpar] if mpar > 3 else parameters['fissionWidthB'].values records = [] for j, E in enumerate(energy): @@ -415,16 +417,6 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): indices = np.triu_indices(cov_dim) cov[indices] = cov_values - # Create pandas DataFrame with resonance data, currently - # redundant with data.IncidentNeutron.resonance - columns = ['energy', 'J', 'totalWidth', 'neutronWidth', - 'captureWidth', 'fissionWidth'] - parameters = pd.DataFrame.from_records(records, columns=columns) - - # Add parameters from File 2 - parameters = _add_file2_contributions(parameters, - resonance.parameters) - # Compact format - Resonances and individual uncertainties followed by # compact correlations elif lcomp == 2: @@ -458,21 +450,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): corr = endf.get_intg_record(file_obj) cov = np.diag(par_unc).dot(corr).dot(np.diag(par_unc)) - # Create pandas DataFrame with resonacne data - columns = ['energy', 'J', 'totalWidth', 'neutronWidth', - 'captureWidth', 'fissionWidth'] - parameters = pd.DataFrame.from_records(records, columns=columns) - - # Determine mpar (number of parameters for each resonance in - # covariance matrix) - nparams, params = parameters.shape - covsize = cov.shape[0] - mpar = int(covsize/nparams) - - # Add parameters from File 2 - parameters = _add_file2_contributions(parameters, - resonance.parameters) - + # Compatible resolved resonance format elif lcomp == 0: cov = np.zeros([4, 4]) records = [] @@ -500,22 +478,19 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): cov = np.pad(cov, ((0, 4), (0, 4)), 'constant', constant_values=0) - # Create pandas DataFrame with resonance data, currently - # redundant with data.IncidentNeutron.resonance - columns = ['energy', 'J', 'totalWidth', 'neutronWidth', - 'captureWidth', 'fissionWidth'] - parameters = pd.DataFrame.from_records(records, columns=columns) - - # Determine mpar (number of parameters for each resonance in - # covariance matrix) - nparams, params = parameters.shape - covsize = cov.shape[0] - mpar = int(covsize/nparams) - - # Add parameters from File 2 - parameters = _add_file2_contributions(parameters, - resonance.parameters) - + # Create pandas DataFrame with resonance data, currently + # redundant with data.IncidentNeutron.resonance + columns = ['energy', 'J', 'totalWidth', 'neutronWidth', + 'captureWidth', 'fissionWidth'] + parameters = pd.DataFrame.from_records(records, columns=columns) + # Determine mpar (number of parameters for each resonance in + # covariance matrix) + nparams, params = parameters.shape + covsize = cov.shape[0] + mpar = int(covsize/nparams) + # Add parameters from File 2 + parameters = _add_file2_contributions(parameters, + resonance.parameters) # Create instance of class mlbw = cls(energy_min, energy_max, parameters, cov, mpar, lcomp, resonance) @@ -678,15 +653,6 @@ class ReichMooreCovariance(ResonanceCovarianceRange): indices = np.triu_indices(cov_dim) cov[indices] = cov_values - # Create pandas DataFrame with resonance data - columns = ['energy', 'J', 'neutronWidth', 'captureWidth', - 'fissionWidthA', 'fissionWidthB'] - parameters = pd.DataFrame.from_records(records, columns=columns) - - # Add parameters from File 2 - parameters = _add_file2_contributions(parameters, - resonance.parameters) - # Compact format - Resonances and individual uncertainties followed by # compact correlations elif lcomp == 2: @@ -713,21 +679,20 @@ class ReichMooreCovariance(ResonanceCovarianceRange): corr = endf.get_intg_record(file_obj) cov = np.diag(par_unc).dot(corr).dot(np.diag(par_unc)) - # Create pandas DataFrame with resonacne data - columns = ['energy', 'J', 'neutronWidth', 'captureWidth', - 'fissionWidthA', 'fissionWidthB'] - parameters = pd.DataFrame.from_records(records, columns=columns) + # Create pandas DataFrame with resonacne data + columns = ['energy', 'J', 'neutronWidth', 'captureWidth', + 'fissionWidthA', 'fissionWidthB'] + parameters = pd.DataFrame.from_records(records, columns=columns) - # Determine mpar (number of parameters for each resonance in - # covariance matrix) - nparams, params = parameters.shape - covsize = cov.shape[0] - mpar = int(covsize/nparams) - - # Add parameters from File 2 - parameters = _add_file2_contributions(parameters, - resonance.parameters) + # Determine mpar (number of parameters for each resonance in + # covariance matrix) + nparams, params = parameters.shape + covsize = cov.shape[0] + mpar = int(covsize/nparams) + # Add parameters from File 2 + parameters = _add_file2_contributions(parameters, + resonance.parameters) # Create instance of ReichMooreCovariance rmc = cls(energy_min, energy_max, parameters, cov, mpar, lcomp, resonance) diff --git a/tests/unit_tests/test_data_neutron.py b/tests/unit_tests/test_data_neutron.py index 66181c4eed..2b67076da3 100644 --- a/tests/unit_tests/test_data_neutron.py +++ b/tests/unit_tests/test_data_neutron.py @@ -39,7 +39,7 @@ def sm150(): def gd154(): """Gd154 ENDF data (contains Reich Moore resonance range)""" filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-064_Gd_154.endf') - return openmc.data.IncidentNeutron.from_endf(filename, covariance = True) + return openmc.data.IncidentNeutron.from_endf(filename, covariance=True) @pytest.fixture(scope='module') From c4b28e480be4f69cba52102333c5d4fa3ad46bbe Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Tue, 31 Jul 2018 09:34:18 -0500 Subject: [PATCH 096/100] Fixed naming change in tests --- tests/unit_tests/test_data_neutron.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit_tests/test_data_neutron.py b/tests/unit_tests/test_data_neutron.py index 2b67076da3..277d6cb10b 100644 --- a/tests/unit_tests/test_data_neutron.py +++ b/tests/unit_tests/test_data_neutron.py @@ -295,10 +295,10 @@ def test_mlbw_cov(ti50): assert cov.energy_max == pytest.approx(587000.) assert cov.covariance[0,0] == pytest.approx(1.410177e5) - subset = cov.res_subset('L',[1,1]) + subset = cov.subset('L',[1,1]) assert not subset.parameters.empty assert (subset.file2res.parameters['L'] == 1).all() - samples = cov.sample_resonance_parameters(1) + samples = cov.sample(1) xs = samples[0].reconstruct([10., 100., 1000.]) assert sorted(xs.keys()) == [2, 18, 102] @@ -314,10 +314,10 @@ def test_rm_cov(gd154): assert cov.energy_max == pytest.approx(2760.) assert cov.covariance[0,0] == pytest.approx(0.8895997) - subset = cov.res_subset('energy',[0,100]) + subset = cov.subset('energy',[0,100]) assert not subset.parameters.empty assert (subset.file2res.parameters['energy'] < 100).all() - samples = cov.sample_resonance_parameters(1) + samples = cov.sample(1) xs = samples[0].reconstruct([10., 100., 1000.]) assert sorted(xs.keys()) == [2, 18, 102] From baabf2fc2b6f3ddca10db0f8bd1dca52e1c162eb Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 2 Aug 2018 10:49:40 -0500 Subject: [PATCH 097/100] change mit-crpg -> openmc-dev --- CONTRIBUTING.md | 4 ++-- README.md | 8 ++++---- docs/source/devguide/user-input.rst | 4 ++-- docs/source/devguide/workflow.rst | 12 ++++++------ docs/source/quickinstall.rst | 4 ++-- docs/source/releasenotes.rst | 16 ++++++++-------- docs/source/usersguide/beginners.rst | 4 ++-- docs/source/usersguide/install.rst | 4 ++-- man/man1/openmc.1 | 2 +- setup.py | 2 +- src/input_xml.F90 | 6 +++--- 11 files changed, 33 insertions(+), 33 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 92f8d0870d..b633bb9295 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ openmc@anl.gov. ## Resources -- [GitHub Repository](https://github.com/mit-crpg/openmc) +- [GitHub Repository](https://github.com/openmc-dev/openmc) - [Documentation](http://openmc.readthedocs.io/en/latest) - [User's Mailing List](openmc-users@googlegroups.com) - [Developer's Mailing List](openmc-dev@googlegroups.com) @@ -22,7 +22,7 @@ openmc@anl.gov. ## How to Report Bugs OpenMC is hosted on GitHub and all bugs are reported and tracked through the -[Issues](https://github.com/mit-crpg/openmc/issues) listed on GitHub. +[Issues](https://github.com/openmc-dev/openmc/issues) listed on GitHub. ## How to Suggest Enhancements diff --git a/README.md b/README.md index ac5847cfad..57197c363e 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # OpenMC Monte Carlo Particle Transport Code -[![License](https://img.shields.io/github/license/mit-crpg/openmc.svg)](http://openmc.readthedocs.io/en/latest/license.html) -[![Travis CI build status (Linux)](https://travis-ci.org/mit-crpg/openmc.svg?branch=develop)](https://travis-ci.org/mit-crpg/openmc) -[![Code Coverage](https://coveralls.io/repos/github/mit-crpg/openmc/badge.svg?branch=develop)](https://coveralls.io/github/mit-crpg/openmc?branch=develop) +[![License](https://img.shields.io/github/license/openmc-dev/openmc.svg)](http://openmc.readthedocs.io/en/latest/license.html) +[![Travis CI build status (Linux)](https://travis-ci.org/openmc-dev/openmc.svg?branch=develop)](https://travis-ci.org/openmc-dev/openmc) +[![Code Coverage](https://coveralls.io/repos/github/openmc-dev/openmc/badge.svg?branch=develop)](https://coveralls.io/github/openmc-dev/openmc?branch=develop) The OpenMC project aims to provide a fully-featured Monte Carlo particle transport code based on modern methods. It is a constructive solid geometry, @@ -44,7 +44,7 @@ list](https://groups.google.com/forum/?fromgroups=#!forum/openmc-users). ## Reporting Bugs OpenMC is hosted on GitHub and all bugs are reported and tracked through the -[Issues](https://github.com/mit-crpg/openmc/issues) feature on GitHub. However, +[Issues](https://github.com/openmc-dev/openmc/issues) feature on GitHub. However, GitHub Issues should not be used for common troubleshooting purposes. If you are having trouble installing the code or getting your model to run properly, you should first send a message to the User's Group mailing list. If it turns out diff --git a/docs/source/devguide/user-input.rst b/docs/source/devguide/user-input.rst index 3e1ea1c380..3c41e74fcf 100644 --- a/docs/source/devguide/user-input.rst +++ b/docs/source/devguide/user-input.rst @@ -65,8 +65,8 @@ developer or send a message to the `developers mailing list`_. .. _property attribute: https://docs.python.org/3.6/library/functions.html#property .. _XML Schema Part 2: http://www.w3.org/TR/xmlschema-2/ .. _boolean: http://www.w3.org/TR/xmlschema-2/#boolean -.. _xml_interface module: https://github.com/mit-crpg/openmc/blob/develop/src/xml_interface.F90 -.. _input_xml module: https://github.com/mit-crpg/openmc/blob/develop/src/input_xml.F90 +.. _xml_interface module: https://github.com/openmc-dev/openmc/blob/develop/src/xml_interface.F90 +.. _input_xml module: https://github.com/openmc-dev/openmc/blob/develop/src/input_xml.F90 .. _RELAX NG: http://relaxng.org/ .. _compact syntax: http://relaxng.org/compact-tutorial-20030326.html .. _trang: http://www.thaiopensource.com/relaxng/trang.html diff --git a/docs/source/devguide/workflow.rst b/docs/source/devguide/workflow.rst index 9b27fd655f..6201f429a0 100644 --- a/docs/source/devguide/workflow.rst +++ b/docs/source/devguide/workflow.rst @@ -55,7 +55,7 @@ Now that you understand the basic development workflow, let's discuss how an individual to contribute to development. Note that this would apply to both new features and bug fixes. The general steps for contributing are as follows: -1. Fork the main openmc repository from `mit-crpg/openmc`_. This will create a +1. Fork the main openmc repository from `openmc-dev/openmc`_. This will create a repository with the same name under your personal account. As such, you can commit to it as you please without disrupting other developers. @@ -74,7 +74,7 @@ features and bug fixes. The general steps for contributing are as follows: ensure that those changes are made on a different branch. 4. Issue a pull request from GitHub and select the *develop* branch of - mit-crpg/openmc as the target. + openmc-dev/openmc as the target. .. image:: ../_images/pullrequest.png @@ -87,7 +87,7 @@ features and bug fixes. The general steps for contributing are as follows: request page itself. 6. After the pull request has been thoroughly vetted, it is merged back into the - *develop* branch of mit-crpg/openmc. + *develop* branch of openmc-dev/openmc. Private Development ------------------- @@ -99,7 +99,7 @@ create a complete copy of the OpenMC repository (not a fork from GitHub). The private repository can then either be stored just locally or in conjunction with a private repository on Github (this requires a `paid plan`_). Alternatively, `Bitbucket`_ offers private repositories for free. If you want to merge some -changes you've made in your private repository back to mit-crpg/openmc +changes you've made in your private repository back to openmc-dev/openmc repository, simply follow the steps above with an extra step of pulling a branch from your private repository into a public fork. @@ -128,9 +128,9 @@ can interfere with virtual environments. .. _GitHub: https://github.com/ .. _git flow: http://nvie.com/git-model .. _valgrind: http://valgrind.org/ -.. _style guide: http://mit-crpg.github.io/openmc/devguide/styleguide.html +.. _style guide: http://openmc.readthedocs.io/en/latest/devguide/styleguide.html .. _pull request: https://help.github.com/articles/using-pull-requests -.. _mit-crpg/openmc: https://github.com/mit-crpg/openmc +.. _openmc-dev/openmc: https://github.com/openmc-dev/openmc .. _paid plan: https://github.com/plans .. _Bitbucket: https://bitbucket.org .. _ctest: http://www.cmake.org/cmake/help/v2.8.12/ctest.html diff --git a/docs/source/quickinstall.rst b/docs/source/quickinstall.rst index 7176b67be0..731bffde70 100644 --- a/docs/source/quickinstall.rst +++ b/docs/source/quickinstall.rst @@ -83,7 +83,7 @@ Installing from Source on Linux or Mac OS X ------------------------------------------- All OpenMC source code is hosted on `GitHub -`_. If you have `git +`_. If you have `git `_, the `gcc `_ compiler suite, `CMake `_, and `HDF5 `_ installed, you can download and install OpenMC be entering the following @@ -91,7 +91,7 @@ commands in a terminal: .. code-block:: sh - git clone https://github.com/mit-crpg/openmc.git + git clone https://github.com/openmc-dev/openmc.git cd openmc mkdir build && cd build cmake .. diff --git a/docs/source/releasenotes.rst b/docs/source/releasenotes.rst index 28af52f5f4..d5ea6c58cd 100644 --- a/docs/source/releasenotes.rst +++ b/docs/source/releasenotes.rst @@ -71,14 +71,14 @@ Bug Fixes - 0c6915_: Bugfix for generating thermal scattering data - 61ecb4_: Fix bugs in Python multipole objects -.. _937469: https://github.com/mit-crpg/openmc/commit/937469 -.. _a149ef: https://github.com/mit-crpg/openmc/commit/a149ef -.. _2c9b21: https://github.com/mit-crpg/openmc/commit/2c9b21 -.. _8047f6: https://github.com/mit-crpg/openmc/commit/8047f6 -.. _0beb4c: https://github.com/mit-crpg/openmc/commit/0beb4c -.. _f124be: https://github.com/mit-crpg/openmc/commit/f124be -.. _0c6915: https://github.com/mit-crpg/openmc/commit/0c6915 -.. _61ecb4: https://github.com/mit-crpg/openmc/commit/61ecb4 +.. _937469: https://github.com/openmc-dev/openmc/commit/937469 +.. _a149ef: https://github.com/openmc-dev/openmc/commit/a149ef +.. _2c9b21: https://github.com/openmc-dev/openmc/commit/2c9b21 +.. _8047f6: https://github.com/openmc-dev/openmc/commit/8047f6 +.. _0beb4c: https://github.com/openmc-dev/openmc/commit/0beb4c +.. _f124be: https://github.com/openmc-dev/openmc/commit/f124be +.. _0c6915: https://github.com/openmc-dev/openmc/commit/0c6915 +.. _61ecb4: https://github.com/openmc-dev/openmc/commit/61ecb4 ------------ Contributors diff --git a/docs/source/usersguide/beginners.rst b/docs/source/usersguide/beginners.rst index ec37d0825a..93d52429f9 100644 --- a/docs/source/usersguide/beginners.rst +++ b/docs/source/usersguide/beginners.rst @@ -153,9 +153,9 @@ and `Volume II`_. You may also find it helpful to review the following terms: .. _Reactor Concepts Manual: http://www.tayloredge.com/periodic/trivia/ReactorConcepts.pdf .. _Volume I: https://www.standards.doe.gov/standards-documents/1000/1019-bhdbk-1993-v1 .. _Volume II: https://www.standards.doe.gov/standards-documents/1000/1019-bhdbk-1993-v2 -.. _OpenMC source code: https://github.com/mit-crpg/openmc +.. _OpenMC source code: https://github.com/openmc-dev/openmc .. _GitHub: https://github.com/ -.. _bug reports: https://github.com/mit-crpg/openmc/issues +.. _bug reports: https://github.com/openmc-dev/openmc/issues .. _Neutron cross section: http://en.wikipedia.org/wiki/Neutron_cross_section .. _Effective multiplication factor: https://en.wikipedia.org/wiki/Nuclear_chain_reaction#Effective_neutron_multiplication_factor .. _Flux: http://en.wikipedia.org/wiki/Neutron_flux diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index f5b277a840..48dcd8c782 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -181,7 +181,7 @@ with GitHub since this involves setting up ssh_ keys. With git installed and setup, the following command will download the full source code from the GitHub repository:: - git clone https://github.com/mit-crpg/openmc.git + git clone https://github.com/openmc-dev/openmc.git By default, the cloned repository will be set to the development branch. To switch to the source of the latest stable release, run the following commands:: @@ -189,7 +189,7 @@ switch to the source of the latest stable release, run the following commands:: cd openmc git checkout master -.. _GitHub: https://github.com/mit-crpg/openmc +.. _GitHub: https://github.com/openmc-dev/openmc .. _git: https://git-scm.com .. _ssh: https://en.wikipedia.org/wiki/Secure_Shell diff --git a/man/man1/openmc.1 b/man/man1/openmc.1 index f49d80bad8..6263a02c5f 100644 --- a/man/man1/openmc.1 +++ b/man/man1/openmc.1 @@ -79,7 +79,7 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .SH REPORTING BUGS The OpenMC source code is hosted on GitHub at -https://github.com/mit-crpg/openmc. With a github account, you can submit issues +https://github.com/openmc-dev/openmc. With a github account, you can submit issues directly on the github repository that will then be reviewed by OpenMC developers. Alternatively, you can send a bug report to .I openmc-users@googlegroups.com\fP. diff --git a/setup.py b/setup.py index 2a42dd65dd..33987095d3 100755 --- a/setup.py +++ b/setup.py @@ -39,7 +39,7 @@ kwargs = { 'author': 'The OpenMC Development Team', 'author_email': 'openmc-dev@googlegroups.com', 'description': 'OpenMC', - 'url': 'https://github.com/mit-crpg/openmc', + 'url': 'https://github.com/openmc-dev/openmc', 'classifiers': [ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 6a9789b2e3..37ddee8956 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -228,7 +228,7 @@ contains ¬ exist! In order to run OpenMC, you first need a set of input & &files; at a minimum, this includes settings.xml, geometry.xml, & &and materials.xml. Please consult the user's guide at & - &http://mit-crpg.github.io/openmc for further information.") + &http://openmc.readthedocs.io for further information.") else ! The settings.xml file is optional if we just want to make a plot. return @@ -1369,7 +1369,7 @@ contains &materials.xml, settings.xml, or in the OPENMC_CROSS_SECTIONS& & environment variable. OpenMC needs such a file to identify & &where to find ACE cross section libraries. Please consult the& - & user's guide at http://mit-crpg.github.io/openmc for & + & user's guide at http://openmc.readthedocs.io for & &information on how to set up ACE cross section libraries.") else call warning("The CROSS_SECTIONS environment variable is & @@ -1387,7 +1387,7 @@ contains &materials.xml or in the OPENMC_MG_CROSS_SECTIONS environment & &variable. OpenMC needs such a file to identify where to & &find MG cross section libraries. Please consult the user's & - &guide at http://mit-crpg.github.io/openmc for information on & + &guide at http://openmc.readthedocs.io for information on & &how to set up MG cross section libraries.") else if (len_trim(env_variable) /= 0) then path_cross_sections = trim(env_variable) From 1615f205fb2a16f54be0a4cd6e2b9ba1067c5344 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 2 Aug 2018 13:32:24 -0500 Subject: [PATCH 098/100] Add 'contributors' to copyright --- LICENSE | 2 +- docs/source/conf.py | 4 ++-- docs/source/license.rst | 2 +- man/man1/openmc.1 | 3 ++- src/output.F90 | 4 ++-- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/LICENSE b/LICENSE index a11dc44a27..cfa34033c2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011-2018 Massachusetts Institute of Technology +Copyright (c) 2011-2018 Massachusetts Institute of Technology and OpenMC contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/docs/source/conf.py b/docs/source/conf.py index eeecba23e4..be7e3a8d13 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -71,7 +71,7 @@ master_doc = 'index' # General information about the project. project = u'OpenMC' -copyright = u'2011-2018, Massachusetts Institute of Technology' +copyright = u'2011-2018, Massachusetts Institute of Technology and OpenMC contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -208,7 +208,7 @@ htmlhelp_basename = 'openmcdoc' # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'openmc.tex', u'OpenMC Documentation', - u'Massachusetts Institute of Technology', 'manual'), + u'OpenMC contributors', 'manual'), ] latex_elements = { diff --git a/docs/source/license.rst b/docs/source/license.rst index e9cba3d8a8..c0728e1a8c 100644 --- a/docs/source/license.rst +++ b/docs/source/license.rst @@ -4,7 +4,7 @@ License Agreement ================= -Copyright © 2011-2018 Massachusetts Institute of Technology +Copyright © 2011-2018 Massachusetts Institute of Technology and OpenMC contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/man/man1/openmc.1 b/man/man1/openmc.1 index 6263a02c5f..eb5c857f71 100644 --- a/man/man1/openmc.1 +++ b/man/man1/openmc.1 @@ -59,7 +59,8 @@ Indicates the default path to a directory containing windowed multipole data if the user has not specified the tag in .I materials.xml\fP. .SH LICENSE -Copyright \(co 2011-2018 Massachusetts Institute of Technology. +Copyright \(co 2011-2018 Massachusetts Institute of Technology and OpenMC +contributors. .PP Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/src/output.F90 b/src/output.F90 index 6197cdc11c..0d50d54853 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -76,7 +76,7 @@ contains write(UNIT=OUTPUT_UNIT, FMT=*) & ' | The OpenMC Monte Carlo Code' write(UNIT=OUTPUT_UNIT, FMT=*) & - ' Copyright | 2011-2018 Massachusetts Institute of Technology' + ' Copyright | 2011-2018 MIT and OpenMC contributors' write(UNIT=OUTPUT_UNIT, FMT=*) & ' License | http://openmc.readthedocs.io/en/latest/license.html' write(UNIT=OUTPUT_UNIT, FMT='(11X,"Version | ",I1,".",I2,".",I1)') & @@ -171,7 +171,7 @@ contains write(UNIT=OUTPUT_UNIT, FMT='(1X,A,A)') "Git SHA1: ", GIT_SHA1 #endif write(UNIT=OUTPUT_UNIT, FMT=*) "Copyright (c) 2011-2018 & - &Massachusetts Institute of Technology" + &Massachusetts Institute of Technology and OpenMC contributors" write(UNIT=OUTPUT_UNIT, FMT=*) "MIT/X license at & &" end if From 7c6b6911a20955c8ef4a0f548efc3bae98c50359 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 2 Aug 2018 14:28:15 -0500 Subject: [PATCH 099/100] Try upgrading pip to avoid race condition breaking Python 3.4 builds --- tools/ci/travis-install.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/ci/travis-install.sh b/tools/ci/travis-install.sh index 2342cdadbc..67c8a4d96d 100755 --- a/tools/ci/travis-install.sh +++ b/tools/ci/travis-install.sh @@ -4,6 +4,9 @@ set -ex # Install NJOY 2016 ./tools/ci/travis-install-njoy.sh +# Upgrade pip before doing anything else +pip install --upgrade pip + # Running OpenMC's setup.py requires numpy/cython already. NumPy float # formatting changed in version 1.14, so stick with a lower version until we can # handle it in our test suite From 46e58ef4dd1b4a978a1f251c2538bb1f5f763dae Mon Sep 17 00:00:00 2001 From: Isaac Meyer Date: Thu, 2 Aug 2018 15:52:41 -0500 Subject: [PATCH 100/100] Added more tests for covariance module --- openmc/data/resonance_covariance.py | 2 +- tests/unit_tests/test_data_neutron.py | 96 ++++++++++++++++++++++++--- 2 files changed, 89 insertions(+), 9 deletions(-) diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index 4d8d502e42..300e6dbf60 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -433,7 +433,7 @@ class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange): for i in range(num_res): res_unc = values[i*12+6 : i*12+12] # Delete 0 values (not provided, no fission width) - # DAJ/DGT always zero, DGF sometimes none zero [1, 2, 5] + # DAJ/DGT always zero, DGF sometimes nonzero [1, 2, 5] res_unc_nonzero = [] for j in range(6): if j in [1, 2, 5] and res_unc[j] != 0.0: diff --git a/tests/unit_tests/test_data_neutron.py b/tests/unit_tests/test_data_neutron.py index 277d6cb10b..406ff0515f 100644 --- a/tests/unit_tests/test_data_neutron.py +++ b/tests/unit_tests/test_data_neutron.py @@ -37,7 +37,8 @@ def sm150(): @pytest.fixture(scope='module') def gd154(): - """Gd154 ENDF data (contains Reich Moore resonance range)""" + """Gd154 ENDF data (contains Reich Moore resonance range and reosnance + covariance with LCOMP=1).""" filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-064_Gd_154.endf') return openmc.data.IncidentNeutron.from_endf(filename, covariance=True) @@ -77,6 +78,13 @@ def na22(): return openmc.data.IncidentNeutron.from_endf(filename) +@pytest.fixture(scope='module') +def na23(): + """Na23 ENDF data (contains MLBW resonance covariance with LCOMP=0).""" + filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-011_Na_023.endf') + return openmc.data.IncidentNeutron.from_endf(filename, covariance=True) + + @pytest.fixture(scope='module') def be9(): """Be9 ENDF data (contains laboratory angle-energy distribution).""" @@ -99,11 +107,26 @@ def am244(): @pytest.fixture(scope='module') def ti50(): - """Ti50 ENDF data (contains Multi-level Breit-Wigner resonance range)""" + """Ti50 ENDF data (contains Multi-level Breit-Wigner resonance range and + resonance covariance with LCOMP=1).""" filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-022_Ti_050.endf') return openmc.data.IncidentNeutron.from_endf(filename, covariance=True) +@pytest.fixture(scope='module') +def cf252(): + """Cf252 ENDF data (contains RM resonance covariance with LCOMP=0).""" + filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-098_Cf_252.endf') + return openmc.data.IncidentNeutron.from_endf(filename, covariance=True) + + +@pytest.fixture(scope='module') +def th232(): + """Th232 ENDF data (contains RM resonance covariance with LCOMP=2).""" + filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-090_Th_232.endf') + return openmc.data.IncidentNeutron.from_endf(filename, covariance=True) + + def test_attributes(pu239): assert pu239.name == 'Pu239' assert pu239.mass_number == 239 @@ -284,8 +307,27 @@ def test_rml(cl35): assert isinstance(group, openmc.data.SpinGroup) -def test_mlbw_cov(ti50): - #Testing on first range only +def test_mlbw_cov_lcomp0(cf252): + # Testing on first range only + cov = cf252.resonance_covariance.ranges[0] + res = cf252.resonances.ranges[0] + assert cov.parameters['energy'][0] == pytest.approx(-3.5) + assert res.parameters['energy'][0] == cov.parameters['energy'][0] + assert isinstance(cov, openmc.data.resonance_covariance.MultiLevelBreitWignerCovariance) + assert cov.energy_min == pytest.approx(1e-5) + assert cov.energy_max == pytest.approx(1000.) + assert cov.covariance[0,0] == pytest.approx(1.225e-05) + + subset = cov.subset('energy', [0, 100]) + assert not subset.parameters.empty + assert (subset.file2res.parameters['energy'] < 100).all() + samples = cov.sample(1) + xs = samples[0].reconstruct([10., 100., 1000.]) + assert sorted(xs.keys()) == [2, 18, 102] + + +def test_mlbw_cov_lcomp1(ti50): + # Testing on first range only cov = ti50.resonance_covariance.ranges[0] res = ti50.resonances.ranges[0] assert cov.parameters['energy'][0] == pytest.approx(-21020.) @@ -295,7 +337,7 @@ def test_mlbw_cov(ti50): assert cov.energy_max == pytest.approx(587000.) assert cov.covariance[0,0] == pytest.approx(1.410177e5) - subset = cov.subset('L',[1,1]) + subset = cov.subset('L', [1, 1]) assert not subset.parameters.empty assert (subset.file2res.parameters['L'] == 1).all() samples = cov.sample(1) @@ -303,8 +345,27 @@ def test_mlbw_cov(ti50): assert sorted(xs.keys()) == [2, 18, 102] -def test_rm_cov(gd154): - #Testing on first range only +def test_mlbw_cov_lcomp2(na23): + # Testing on first range only + cov = na23.resonance_covariance.ranges[0] + res = na23.resonances.ranges[0] + assert cov.parameters['energy'][0] == pytest.approx(2810.) + assert res.parameters['energy'][0] == cov.parameters['energy'][0] + assert isinstance(cov, openmc.data.resonance_covariance.MultiLevelBreitWignerCovariance) + assert cov.energy_min == pytest.approx(600) + assert cov.energy_max == pytest.approx(500000.) + assert cov.covariance[0,0] == pytest.approx(16.1064163584) + + subset = cov.subset('L', [1, 1]) + assert not subset.parameters.empty + assert (subset.file2res.parameters['L'] == 1).all() + samples = cov.sample(1) + xs = samples[0].reconstruct([10., 100., 1000.]) + assert sorted(xs.keys()) == [2, 18, 102] + + +def test_rmcov_lcomp1(gd154): + # Testing on first range only cov = gd154.resonance_covariance.ranges[0] res = gd154.resonances.ranges[0] assert cov.parameters['energy'][0] == pytest.approx(-2.200001) @@ -314,7 +375,26 @@ def test_rm_cov(gd154): assert cov.energy_max == pytest.approx(2760.) assert cov.covariance[0,0] == pytest.approx(0.8895997) - subset = cov.subset('energy',[0,100]) + subset = cov.subset('energy', [0, 100]) + assert not subset.parameters.empty + assert (subset.file2res.parameters['energy'] < 100).all() + samples = cov.sample(1) + xs = samples[0].reconstruct([10., 100., 1000.]) + assert sorted(xs.keys()) == [2, 18, 102] + + +def test_rmcov_lcomp2(th232): + # Testing on first range only + cov = th232.resonance_covariance.ranges[0] + res = th232.resonances.ranges[0] + assert cov.parameters['energy'][0] == pytest.approx(-2000) + assert res.parameters['energy'][0] == cov.parameters['energy'][0] + assert isinstance(cov, openmc.data.resonance_covariance.ReichMooreCovariance) + assert cov.energy_min == pytest.approx(1e-5) + assert cov.energy_max == pytest.approx(4000.) + assert cov.covariance[0,0] == pytest.approx(246.6043092496) + + subset = cov.subset('energy', [0, 100]) assert not subset.parameters.empty assert (subset.file2res.parameters['energy'] < 100).all() samples = cov.sample(1)