Merge pull request #471 from wbinventor/mgxs

Multi-Group Cross Section Generation Module
This commit is contained in:
Paul Romano 2015-10-28 13:17:05 -05:00
commit 96e92e4306
48 changed files with 10809 additions and 1955 deletions

7
.gitignore vendored
View file

@ -64,3 +64,10 @@ data/nndc
# IPython notebook checkpoints
.ipynb_checkpoints
# Multi-group cross section IPython Notebook
docs/source/pythonapi/examples/*.xml
docs/source/pythonapi/examples/*.png
docs/source/pythonapi/examples/*.xls
docs/source/pythonapi/examples/mgxs
docs/source/pythonapi/examples/tracks

View file

@ -27,7 +27,7 @@ before_install:
- conda config --set always_yes yes --set changeps1 no
- conda update -q conda
- conda info -a
- conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION numpy scipy h5py
- conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION numpy scipy h5py pandas
- source activate test-environment
# Install GCC, MPICH, HDF5, PHDF5

View file

@ -27,6 +27,7 @@ sys.path.insert(0, os.path.abspath('../..'))
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.napoleon',
'sphinx.ext.pngmath',
'sphinx.ext.autosummary',
'sphinxcontrib.tikz',
'sphinx_numfig',
'notebook_sphinxext']

View file

@ -0,0 +1,8 @@
.. _pythonapi_energy_groups:
=============
Energy Groups
=============
.. automodule:: openmc.mgxs.groups
:members:

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,11 @@
====================================
Multi-Group Cross Section Generation
====================================
.. only:: html
.. notebook:: multi-group-cross-sections.ipynb
.. only:: latex
IPython notebooks must be viewed in the online HTML documentation.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -336,7 +336,18 @@
"metadata": {
"collapsed": false
},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Run openmc in plotting mode\n",
"executor = openmc.Executor()\n",
@ -352,7 +363,7 @@
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///9yEhLpgJFNv8Tq\nQYT7AAAAAWJLR0QAiAUdSAAAAAd0SU1FB98KAwI1HbUKyRQAAAPZSURBVGje7Zs7buMwEIZ9iey5\n0gyNjQpXKTYudIScgkdQYTfut1idwkdQkQNsYQO2Qj0sPiVK+mlQDmwgwIcgg8Cc4fCTSK5W4OeF\nkM8rHv+2I/rgxPZEPZgR7XtQxKdXYuUXJSUnBQ/9WCgo4vOSJ+WFUvF7E08mlia+rn7VcKXP8sRs\nzFX8b2MdX2y6v1Tw6MZUw4H4ojfIjD8mvn/qRL5p4+vvlMqvp2EhR8WBzfiz20hXORmP9fi/bM9E\neUFvV5H/0yRkeSbiGRfFJErxD9ENdz7Mbhig/h89fvtFdMiI/ePUIXV4lXju8K3DKv9NThOZ3q2K\nmUy6grxFES8rjeyic+FFQav+ncg3fXjH+Ts+/iibztFqOiZuZP/Z3OafPX40NGgST2r+uvQkXXp6\ncKvmr+r0e1Eef5um3+JHP3IFF1D/seNZJgaDmvY0Gav1s+2f1fqpIcublfKGt6apotG/NVx3SInW\ntLX+7Vg/Pv1YqOsnun6JSVdOXT/X7vk75f938QP+8OmSBs0fXtymMhJbf8qlPynYmpKCh7OB1fzN\nalOj1sl0ZAruHLiA+RM73pDe/VjMVP89+aTXwjyc/x5n+u991895/utrJTy8/06TXh0r/5JOa2Jm\nYmqi4r/vUm/H4wLmT+z4anhr05X+q6KUXhtzr/9qSff5L5uMT//V/NdU4YuBTPa/8P67l/6r44ds\n+hYuoP5jx9ciy6XTWlibBrmx8V/TdMfjkP+6pOsu/lvM9N90sf7r+f6m/65n+S8p/itN15v0UkW3\n/+48+PRfJX6S9Joo4g+G/1qYG9KroqP/WypcuvyXPf13wH89/hHef7MB6R3Cqn55U4rv4kfH3zaS\ngQuYP7HjVf89tXrbO+hfLdr+Ozv/SP1dgtQ/Ov8C+i/3+q/Zf2D/HWi6bjT6rym9I/v/03/b+LHS\n4cTg/utTsV7/net/Afzz4f0XGX84/2j9xZ4/sePR/of2X7D/o+vPo/sv6h9B/Bfxr9j1Hz2eN/hO\n8/wfff4A848+f/1A/530/I0+/8PvH9D3H9HnT+R49P0b+v4PfP/4E/wXfP8Mvf9G37/D/ovuP8Se\nP7Hj0f0vdP8tqP9O339cyv7p3P1fdP8Z3v9G999j13/seMax8x/o+ZN7+O+E8zdP/8XOf8Hnz9Dz\nb7HnT+x49PxlCp7/BM+fOv13wvnXBfivt2lMvD8TyH/Hnb+Gz3+j589jz5/Y8ej9h4D+W7qQmf57\nefqv239n3T+C7z+h969i13/seMax+3/o/cMcu/8Y2H9n3p+J6r98pv8m4fwXuH+M3n+OO3++AX9c\nlR+4PhbRAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTEwLTAzVDA5OjUxOjU5KzA3OjAwJPCZIQAA\nACV0RVh0ZGF0ZTptb2RpZnkAMjAxNS0xMC0wM1QwOTo1MTo1OSswNzowMFWtIZ0AAAAASUVORK5C\nYII=\n",
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAAAFzUkdC\nAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAxQTFRF\n////chIS6YCRTb/E6kGE+wAAAAFiS0dEAIgFHUgAAAAJcEhZcwAAAEgAAABIAEbJaz4AAALKSURB\nVGje7dpLcqQwDAbgHHE2YeEj+D4cwQucBUfo+3CEXoSp8OhuhF70T4qpKXmdr21LogK2Pj7A8QmN\nP+HDhw8fPnz48Kf6VH9G+66vy+je8k19jnf8C5dXIPv86ms56lPdjvaYbyodx3ze+XLE76cXFiD4\nzPji99z0/AJ4n1lfvJ6fnl0A6x+578efMSg1wPr172/jPO5yFXM+Ef78gdblM+WPHyguP//t1/g6\npA0wfln+ho/fwgYYn19C/xwDvwHGc9OvC+hs37DTrwuwfWanXxdQTC9Mvyygs3wjTL8uwPJpn/tN\nDbSGz7T0SBEWw4vLXzbQ6b6RoveIoO6TvPxlA63qs7z8ZQPF9F+SH22vbX8OQKf5Rtv+EgDNJ3X5\n8wZaxWd1+fMGiuFvir8bvjp8J/tGy/6jAmRvhW8fwL3vVT+o3grfPoB7r/IpALI3tz8FoJN84/NV\n873hB8UnM3xzANtf8nb4dwmg3grfFEDJO8JPE0i9Ff4pAYL3pI8mkHor/HMCeO9JH00g9SafEsh7\nT/ppARBvp48UwJnelT5SACd7O31TAlnvKx9SQCd7B58KgPO+8iMFuPWe9E8F8BveWX7bAjzX9y4/\n/Jve+fhsH6Ctv7n8PTzjvY/v9gEOHz58+PBX+6v/f/wPvnd54f3j6venE/yl769Xv7+j3x/o98/V\n32/o9+fl389Xnx+g5x/o+Qt6/oOeP6HnX+j5G3z+h54/ouefV5/foufP6Pk3ev4On/+j9w/o/Qd6\n/4Le/6D3T/D9V67Y/ZsVQBq+s+8f0ftP+P41axXguP9NWgDuu/Cdfv+N3r/D9/9TAID+A7T/Ae2/\ngPs/0P4TtP8F7r9J3AIO9P+g/Udw/9Oygbf7r9D+L7j/DO1/Q/vv4P4/tP8Q7n9E+y/h/k+0/xTu\nf4X7b+H+X7T/+BPuf3aM8OHDhw8fPnz4w/4vzcvgeY10sY0AAAAldEVYdGRhdGU6Y3JlYXRlADIw\nMTUtMTAtMTJUMjM6NTI6MDgtMDQ6MDAXQ5NYAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE1LTEwLTEy\nVDIzOjUyOjA4LTA0OjAwZh4r5AAAAABJRU5ErkJggg==\n",
"text/plain": [
"<IPython.core.display.Image object>"
]
@ -381,13 +392,12 @@
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": true
"collapsed": false
},
"outputs": [],
"source": [
"# Instantiate an empty TalliesFile\n",
"tallies_file = openmc.TalliesFile()\n",
"tallies_file.tallies = []"
"tallies_file = openmc.TalliesFile()"
]
},
{
@ -563,9 +573,9 @@
" Copyright: 2011-2015 Massachusetts Institute of Technology\n",
" License: http://mit-crpg.github.io/openmc/license.html\n",
" Version: 0.7.0\n",
" Git SHA1: 71dfde8d12942170a9a8d91796ab40a6e9becaaf\n",
" Date/Time: 2015-10-03 09:53:29\n",
" OpenMP Threads: 4\n",
" Git SHA1: 170155e8d7935b57fad57bfad6aff1034a80206e\n",
" Date/Time: 2015-10-12 23:52:08\n",
" MPI Processes: 1\n",
"\n",
" ===========================================================================\n",
" ========================> INITIALIZATION <=========================\n",
@ -577,11 +587,11 @@
" Reading materials XML file...\n",
" Reading tallies XML file...\n",
" Building neighboring cells lists for each surface...\n",
" Loading ACE cross section table: 92235.71c\n",
" Loading ACE cross section table: 92238.71c\n",
" Loading ACE cross section table: 8016.71c\n",
" Loading ACE cross section table: 92235.71c\n",
" Loading ACE cross section table: 5010.71c\n",
" Loading ACE cross section table: 1001.71c\n",
" Loading ACE cross section table: 5010.71c\n",
" Loading ACE cross section table: 40090.71c\n",
" Initializing source particles...\n",
"\n",
@ -591,26 +601,26 @@
"\n",
" Bat./Gen. k Average k \n",
" ========= ======== ==================== \n",
" 1/1 1.00279 \n",
" 2/1 1.03320 \n",
" 3/1 1.04467 \n",
" 4/1 1.09693 \n",
" 5/1 1.05008 \n",
" 6/1 1.08426 \n",
" 7/1 1.05363 1.06894 +/- 0.01531\n",
" 8/1 0.97961 1.03917 +/- 0.03106\n",
" 9/1 1.06444 1.04549 +/- 0.02285\n",
" 10/1 1.08345 1.05308 +/- 0.01926\n",
" 11/1 1.06871 1.05568 +/- 0.01594\n",
" 12/1 1.03183 1.05228 +/- 0.01390\n",
" 13/1 1.04486 1.05135 +/- 0.01207\n",
" 14/1 1.06468 1.05283 +/- 0.01075\n",
" 15/1 1.04185 1.05173 +/- 0.00968\n",
" 16/1 1.01268 1.04818 +/- 0.00944\n",
" 17/1 1.04129 1.04761 +/- 0.00864\n",
" 18/1 1.01127 1.04481 +/- 0.00843\n",
" 19/1 1.03738 1.04428 +/- 0.00782\n",
" 20/1 1.04410 1.04427 +/- 0.00728\n",
" 1/1 1.05992 \n",
" 2/1 1.05251 \n",
" 3/1 1.05204 \n",
" 4/1 1.02100 \n",
" 5/1 1.07784 \n",
" 6/1 1.04814 \n",
" 7/1 1.02335 1.03574 +/- 0.01239\n",
" 8/1 1.02415 1.03188 +/- 0.00813\n",
" 9/1 1.10331 1.04974 +/- 0.01876\n",
" 10/1 1.05452 1.05069 +/- 0.01456\n",
" 11/1 1.07867 1.05536 +/- 0.01277\n",
" 12/1 1.04203 1.05345 +/- 0.01096\n",
" 13/1 1.04482 1.05237 +/- 0.00955\n",
" 14/1 1.04117 1.05113 +/- 0.00852\n",
" 15/1 1.07581 1.05360 +/- 0.00801\n",
" 16/1 1.04235 1.05257 +/- 0.00731\n",
" 17/1 1.02710 1.05045 +/- 0.00701\n",
" 18/1 1.01970 1.04809 +/- 0.00687\n",
" 19/1 1.01022 1.04538 +/- 0.00691\n",
" 20/1 1.01449 1.04332 +/- 0.00675\n",
" Creating state point statepoint.20.h5...\n",
"\n",
" ===========================================================================\n",
@ -620,27 +630,27 @@
"\n",
" =======================> TIMING STATISTICS <=======================\n",
"\n",
" Total time for initialization = 3.7200E-01 seconds\n",
" Reading cross sections = 1.2400E-01 seconds\n",
" Total time in simulation = 4.7110E+00 seconds\n",
" Time in transport only = 4.6510E+00 seconds\n",
" Time in inactive batches = 6.1900E-01 seconds\n",
" Time in active batches = 4.0920E+00 seconds\n",
" Time synchronizing fission bank = 2.0000E-03 seconds\n",
" Sampling source sites = 2.0000E-03 seconds\n",
" Total time for initialization = 4.1300E-01 seconds\n",
" Reading cross sections = 9.6000E-02 seconds\n",
" Total time in simulation = 1.6248E+01 seconds\n",
" Time in transport only = 1.6236E+01 seconds\n",
" Time in inactive batches = 2.3150E+00 seconds\n",
" Time in active batches = 1.3933E+01 seconds\n",
" Time synchronizing fission bank = 0.0000E+00 seconds\n",
" Sampling source sites = 0.0000E+00 seconds\n",
" SEND/RECV source sites = 0.0000E+00 seconds\n",
" Time accumulating tallies = 0.0000E+00 seconds\n",
" Total time for finalization = 2.0000E-03 seconds\n",
" Total time elapsed = 5.0950E+00 seconds\n",
" Calculation Rate (inactive) = 20193.9 neutrons/second\n",
" Calculation Rate (active) = 9164.22 neutrons/second\n",
" Total time elapsed = 1.6672E+01 seconds\n",
" Calculation Rate (inactive) = 5399.57 neutrons/second\n",
" Calculation Rate (active) = 2691.45 neutrons/second\n",
"\n",
" ============================> RESULTS <============================\n",
"\n",
" k-effective (Collision) = 1.04044 +/- 0.00527\n",
" k-effective (Track-length) = 1.04427 +/- 0.00728\n",
" k-effective (Absorption) = 1.04794 +/- 0.00535\n",
" Combined k-effective = 1.04628 +/- 0.00467\n",
" k-effective (Collision) = 1.03935 +/- 0.00682\n",
" k-effective (Track-length) = 1.04332 +/- 0.00675\n",
" k-effective (Absorption) = 1.03845 +/- 0.00598\n",
" Combined k-effective = 1.04024 +/- 0.00523\n",
" Leakage Fraction = 0.00000 +/- 0.00000\n",
"\n"
]
@ -741,30 +751,22 @@
" <th>mean</th>\n",
" <th>std. dev.</th>\n",
" </tr>\n",
" <tr>\n",
" <th>bin</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>total</td>\n",
" <td>(nu-fission / absorption)</td>\n",
" <td>1.046353</td>\n",
" <td>0.00935</td>\n",
" <td>1.040166</td>\n",
" <td>0.009069</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" nuclide score mean std. dev.\n",
"bin \n",
"0 total (nu-fission / absorption) 1.046353 0.00935"
" nuclide score mean std. dev.\n",
"0 total (nu-fission / absorption) 1.040166 0.009069"
]
},
"execution_count": 26,
@ -804,35 +806,29 @@
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>energy [MeV]</th>\n",
" <th>nuclide</th>\n",
" <th>score</th>\n",
" <th>mean</th>\n",
" <th>std. dev.</th>\n",
" </tr>\n",
" <tr>\n",
" <th>bin</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>(0.0e+00 - 6.2e-01)</td>\n",
" <td>total</td>\n",
" <td>absorption</td>\n",
" <td>0.95873</td>\n",
" <td>0.00774</td>\n",
" <td>0.95938</td>\n",
" <td>0.008187</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" nuclide score mean std. dev.\n",
"bin \n",
"0 total absorption 0.95873 0.00774"
" energy [MeV] nuclide score mean std. dev.\n",
"0 (0.0e+00 - 6.2e-01) total absorption 0.95938 0.008187"
]
},
"execution_count": 27,
@ -875,30 +871,22 @@
" <th>mean</th>\n",
" <th>std. dev.</th>\n",
" </tr>\n",
" <tr>\n",
" <th>bin</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>total</td>\n",
" <td>nu-fission</td>\n",
" <td>1.091622</td>\n",
" <td>0.011163</td>\n",
" <td>1.090899</td>\n",
" <td>0.010602</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" nuclide score mean std. dev.\n",
"bin \n",
"0 total nu-fission 1.091622 0.011163"
" nuclide score mean std. dev.\n",
"0 total nu-fission 1.090899 0.010602"
]
},
"execution_count": 28,
@ -944,25 +932,16 @@
" <th>mean</th>\n",
" <th>std. dev.</th>\n",
" </tr>\n",
" <tr>\n",
" <th>bin</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0.0e+00 - 6.2e-01</td>\n",
" <td>(0.0e+00 - 6.2e-01)</td>\n",
" <td>10000</td>\n",
" <td>total</td>\n",
" <td>absorption</td>\n",
" <td>0.802012</td>\n",
" <td>0.006609</td>\n",
" <td>0.803413</td>\n",
" <td>0.007031</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
@ -970,8 +949,7 @@
],
"text/plain": [
" energy [MeV] cell nuclide score mean std. dev.\n",
"bin \n",
"0 0.0e+00 - 6.2e-01 10000 total absorption 0.802012 0.006609"
"0 (0.0e+00 - 6.2e-01) 10000 total absorption 0.803413 0.007031"
]
},
"execution_count": 29,
@ -1009,44 +987,28 @@
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>energy [MeV]</th>\n",
" <th>cell</th>\n",
" <th>nuclide</th>\n",
" <th>score</th>\n",
" <th>mean</th>\n",
" <th>std. dev.</th>\n",
" </tr>\n",
" <tr>\n",
" <th>bin</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0.0e+00 - 6.2e-01</td>\n",
" <td>10000</td>\n",
" <td>(0.0e+00 - 6.2e-01)</td>\n",
" <td>total</td>\n",
" <td>(nu-fission / absorption)</td>\n",
" <td>1.246604</td>\n",
" <td>0.011825</td>\n",
" <td>1.237053</td>\n",
" <td>0.011765</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" energy [MeV] cell nuclide score mean \\\n",
"bin \n",
"0 0.0e+00 - 6.2e-01 10000 total (nu-fission / absorption) 1.246604 \n",
"\n",
" std. dev. \n",
"bin \n",
"0 0.011825 "
" energy [MeV] nuclide score mean std. dev.\n",
"0 (0.0e+00 - 6.2e-01) total (nu-fission / absorption) 1.237053 0.011765"
]
},
"execution_count": 30,
@ -1082,39 +1044,32 @@
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>energy [MeV]</th>\n",
" <th>nuclide</th>\n",
" <th>score</th>\n",
" <th>mean</th>\n",
" <th>std. dev.</th>\n",
" </tr>\n",
" <tr>\n",
" <th>bin</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>(0.0e+00 - 6.2e-01)</td>\n",
" <td>total</td>\n",
" <td>(((absorption * nu-fission) * absorption) * (n...</td>\n",
" <td>1.046353</td>\n",
" <td>0.01894</td>\n",
" <td>1.040166</td>\n",
" <td>0.019018</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" nuclide score mean \\\n",
"bin \n",
"0 total (((absorption * nu-fission) * absorption) * (n... 1.046353 \n",
" energy [MeV] nuclide \\\n",
"0 (0.0e+00 - 6.2e-01) total \n",
"\n",
" std. dev. \n",
"bin \n",
"0 0.01894 "
" score mean std. dev. \n",
"0 (((absorption * nu-fission) * absorption) * (n... 1.040166 0.019018 "
]
},
"execution_count": 31,
@ -1174,115 +1129,104 @@
" <th>mean</th>\n",
" <th>std. dev.</th>\n",
" </tr>\n",
" <tr>\n",
" <th>bin</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>10000</td>\n",
" <td>0.0e+00 - 6.3e-07</td>\n",
" <td>(0.0e+00 - 6.3e-07)</td>\n",
" <td>(U-238 / total)</td>\n",
" <td>(nu-fission / flux)</td>\n",
" <td>0.000001</td>\n",
" <td>6.859257e-09</td>\n",
" <td>6.657029e-07</td>\n",
" <td>7.377419e-09</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>10000</td>\n",
" <td>0.0e+00 - 6.3e-07</td>\n",
" <td>(0.0e+00 - 6.3e-07)</td>\n",
" <td>(U-238 / total)</td>\n",
" <td>(scatter / flux)</td>\n",
" <td>0.209986</td>\n",
" <td>1.966887e-03</td>\n",
" <td>2.099891e-01</td>\n",
" <td>2.303838e-03</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>10000</td>\n",
" <td>0.0e+00 - 6.3e-07</td>\n",
" <td>(0.0e+00 - 6.3e-07)</td>\n",
" <td>(U-235 / total)</td>\n",
" <td>(nu-fission / flux)</td>\n",
" <td>0.355667</td>\n",
" <td>3.717881e-03</td>\n",
" <td>3.564204e-01</td>\n",
" <td>3.951669e-03</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>10000</td>\n",
" <td>0.0e+00 - 6.3e-07</td>\n",
" <td>(0.0e+00 - 6.3e-07)</td>\n",
" <td>(U-235 / total)</td>\n",
" <td>(scatter / flux)</td>\n",
" <td>0.005555</td>\n",
" <td>5.218094e-05</td>\n",
" <td>5.555330e-03</td>\n",
" <td>6.101004e-05</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>10000</td>\n",
" <td>6.3e-07 - 2.0e+01</td>\n",
" <td>(6.3e-07 - 2.0e+01)</td>\n",
" <td>(U-238 / total)</td>\n",
" <td>(nu-fission / flux)</td>\n",
" <td>0.007165</td>\n",
" <td>5.625590e-05</td>\n",
" <td>7.154887e-03</td>\n",
" <td>8.053460e-05</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>10000</td>\n",
" <td>6.3e-07 - 2.0e+01</td>\n",
" <td>(6.3e-07 - 2.0e+01)</td>\n",
" <td>(U-238 / total)</td>\n",
" <td>(scatter / flux)</td>\n",
" <td>0.227653</td>\n",
" <td>8.544314e-04</td>\n",
" <td>2.277701e-01</td>\n",
" <td>1.079289e-03</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>10000</td>\n",
" <td>6.3e-07 - 2.0e+01</td>\n",
" <td>(6.3e-07 - 2.0e+01)</td>\n",
" <td>(U-235 / total)</td>\n",
" <td>(nu-fission / flux)</td>\n",
" <td>0.008089</td>\n",
" <td>5.080374e-05</td>\n",
" <td>8.066738e-03</td>\n",
" <td>5.254797e-05</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>10000</td>\n",
" <td>6.3e-07 - 2.0e+01</td>\n",
" <td>(6.3e-07 - 2.0e+01)</td>\n",
" <td>(U-235 / total)</td>\n",
" <td>(scatter / flux)</td>\n",
" <td>0.003370</td>\n",
" <td>1.361116e-05</td>\n",
" <td>3.366802e-03</td>\n",
" <td>1.647058e-05</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" cell energy [MeV] nuclide score mean \\\n",
"bin \n",
"0 10000 0.0e+00 - 6.3e-07 (U-238 / total) (nu-fission / flux) 0.000001 \n",
"1 10000 0.0e+00 - 6.3e-07 (U-238 / total) (scatter / flux) 0.209986 \n",
"2 10000 0.0e+00 - 6.3e-07 (U-235 / total) (nu-fission / flux) 0.355667 \n",
"3 10000 0.0e+00 - 6.3e-07 (U-235 / total) (scatter / flux) 0.005555 \n",
"4 10000 6.3e-07 - 2.0e+01 (U-238 / total) (nu-fission / flux) 0.007165 \n",
"5 10000 6.3e-07 - 2.0e+01 (U-238 / total) (scatter / flux) 0.227653 \n",
"6 10000 6.3e-07 - 2.0e+01 (U-235 / total) (nu-fission / flux) 0.008089 \n",
"7 10000 6.3e-07 - 2.0e+01 (U-235 / total) (scatter / flux) 0.003370 \n",
" cell energy [MeV] nuclide score \\\n",
"0 10000 (0.0e+00 - 6.3e-07) (U-238 / total) (nu-fission / flux) \n",
"1 10000 (0.0e+00 - 6.3e-07) (U-238 / total) (scatter / flux) \n",
"2 10000 (0.0e+00 - 6.3e-07) (U-235 / total) (nu-fission / flux) \n",
"3 10000 (0.0e+00 - 6.3e-07) (U-235 / total) (scatter / flux) \n",
"4 10000 (6.3e-07 - 2.0e+01) (U-238 / total) (nu-fission / flux) \n",
"5 10000 (6.3e-07 - 2.0e+01) (U-238 / total) (scatter / flux) \n",
"6 10000 (6.3e-07 - 2.0e+01) (U-235 / total) (nu-fission / flux) \n",
"7 10000 (6.3e-07 - 2.0e+01) (U-235 / total) (scatter / flux) \n",
"\n",
" std. dev. \n",
"bin \n",
"0 6.859257e-09 \n",
"1 1.966887e-03 \n",
"2 3.717881e-03 \n",
"3 5.218094e-05 \n",
"4 5.625590e-05 \n",
"5 8.544314e-04 \n",
"6 5.080374e-05 \n",
"7 1.361116e-05 "
" mean std. dev. \n",
"0 6.657029e-07 7.377419e-09 \n",
"1 2.099891e-01 2.303838e-03 \n",
"2 3.564204e-01 3.951669e-03 \n",
"3 5.555330e-03 6.101004e-05 \n",
"4 7.154887e-03 8.053460e-05 \n",
"5 2.277701e-01 1.079289e-03 \n",
"6 8.066738e-03 5.254797e-05 \n",
"7 3.366802e-03 1.647058e-05 "
]
},
"execution_count": 33,
@ -1313,11 +1257,11 @@
"name": "stdout",
"output_type": "stream",
"text": [
"[[[ 6.64174599e-07]\n",
" [ 3.55666541e-01]]\n",
"[[[ 6.65702880e-07]\n",
" [ 3.56420449e-01]]\n",
"\n",
" [[ 7.16505734e-03]\n",
" [ 8.08949336e-03]]]\n"
" [[ 7.15488656e-03]\n",
" [ 8.06673774e-03]]]\n"
]
}
],
@ -1345,9 +1289,9 @@
"name": "stdout",
"output_type": "stream",
"text": [
"[[[ 0.00555465]]\n",
"[[[ 0.00555533]]\n",
"\n",
" [[ 0.00337011]]]\n"
" [[ 0.0033668 ]]]\n"
]
}
],
@ -1369,8 +1313,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
"[[[ 0.22765348]\n",
" [ 0.00337011]]]\n"
"[[[ 0.22777006]\n",
" [ 0.0033668 ]]]\n"
]
}
],
@ -1411,64 +1355,54 @@
" <th>mean</th>\n",
" <th>std. dev.</th>\n",
" </tr>\n",
" <tr>\n",
" <th>bin</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>10000</td>\n",
" <td>0.0e+00 - 6.3e-07</td>\n",
" <td>(0.0e+00 - 6.3e-07)</td>\n",
" <td>U-238</td>\n",
" <td>nu-fission</td>\n",
" <td>0.000002</td>\n",
" <td>1.284890e-08</td>\n",
" <td>1.283958e-08</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>10000</td>\n",
" <td>0.0e+00 - 6.3e-07</td>\n",
" <td>(0.0e+00 - 6.3e-07)</td>\n",
" <td>U-235</td>\n",
" <td>nu-fission</td>\n",
" <td>0.867982</td>\n",
" <td>7.022256e-03</td>\n",
" <td>0.868553</td>\n",
" <td>6.880390e-03</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>10000</td>\n",
" <td>6.3e-07 - 2.0e+01</td>\n",
" <td>(6.3e-07 - 2.0e+01)</td>\n",
" <td>U-238</td>\n",
" <td>nu-fission</td>\n",
" <td>0.082801</td>\n",
" <td>6.087096e-04</td>\n",
" <td>0.082149</td>\n",
" <td>8.837250e-04</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>10000</td>\n",
" <td>6.3e-07 - 2.0e+01</td>\n",
" <td>(6.3e-07 - 2.0e+01)</td>\n",
" <td>U-235</td>\n",
" <td>nu-fission</td>\n",
" <td>0.093484</td>\n",
" <td>5.275039e-04</td>\n",
" <td>0.092618</td>\n",
" <td>5.195308e-04</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" cell energy [MeV] nuclide score mean std. dev.\n",
"bin \n",
"0 10000 0.0e+00 - 6.3e-07 U-238 nu-fission 0.000002 1.284890e-08\n",
"1 10000 0.0e+00 - 6.3e-07 U-235 nu-fission 0.867982 7.022256e-03\n",
"2 10000 6.3e-07 - 2.0e+01 U-238 nu-fission 0.082801 6.087096e-04\n",
"3 10000 6.3e-07 - 2.0e+01 U-235 nu-fission 0.093484 5.275039e-04"
" cell energy [MeV] nuclide score mean std. dev.\n",
"0 10000 (0.0e+00 - 6.3e-07) U-238 nu-fission 0.000002 1.283958e-08\n",
"1 10000 (0.0e+00 - 6.3e-07) U-235 nu-fission 0.868553 6.880390e-03\n",
"2 10000 (6.3e-07 - 2.0e+01) U-238 nu-fission 0.082149 8.837250e-04\n",
"3 10000 (6.3e-07 - 2.0e+01) U-235 nu-fission 0.092618 5.195308e-04"
]
},
"execution_count": 37,
@ -1504,114 +1438,104 @@
" <th>mean</th>\n",
" <th>std. dev.</th>\n",
" </tr>\n",
" <tr>\n",
" <th>bin</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>10002</td>\n",
" <td>1.0e-08 - 1.1e-07</td>\n",
" <td>(1.0e-08 - 1.1e-07)</td>\n",
" <td>H-1</td>\n",
" <td>scatter</td>\n",
" <td>4.620525</td>\n",
" <td>0.038249</td>\n",
" <td>4.619398</td>\n",
" <td>0.040124</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>10002</td>\n",
" <td>1.1e-07 - 1.2e-06</td>\n",
" <td>(1.1e-07 - 1.2e-06)</td>\n",
" <td>H-1</td>\n",
" <td>scatter</td>\n",
" <td>2.036841</td>\n",
" <td>0.013203</td>\n",
" <td>2.030757</td>\n",
" <td>0.011239</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>10002</td>\n",
" <td>1.2e-06 - 1.3e-05</td>\n",
" <td>(1.2e-06 - 1.3e-05)</td>\n",
" <td>H-1</td>\n",
" <td>scatter</td>\n",
" <td>1.659916</td>\n",
" <td>0.010107</td>\n",
" <td>1.658488</td>\n",
" <td>0.009777</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>10002</td>\n",
" <td>1.3e-05 - 1.4e-04</td>\n",
" <td>(1.3e-05 - 1.4e-04)</td>\n",
" <td>H-1</td>\n",
" <td>scatter</td>\n",
" <td>1.861546</td>\n",
" <td>0.013328</td>\n",
" <td>1.853002</td>\n",
" <td>0.007378</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>10002</td>\n",
" <td>1.4e-04 - 1.5e-03</td>\n",
" <td>(1.4e-04 - 1.5e-03)</td>\n",
" <td>H-1</td>\n",
" <td>scatter</td>\n",
" <td>2.049664</td>\n",
" <td>0.008215</td>\n",
" <td>2.050773</td>\n",
" <td>0.012484</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>10002</td>\n",
" <td>1.5e-03 - 1.6e-02</td>\n",
" <td>(1.5e-03 - 1.6e-02)</td>\n",
" <td>H-1</td>\n",
" <td>scatter</td>\n",
" <td>2.162157</td>\n",
" <td>0.010245</td>\n",
" <td>2.131759</td>\n",
" <td>0.007821</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>10002</td>\n",
" <td>1.6e-02 - 1.7e-01</td>\n",
" <td>(1.6e-02 - 1.7e-01)</td>\n",
" <td>H-1</td>\n",
" <td>scatter</td>\n",
" <td>2.224496</td>\n",
" <td>0.013796</td>\n",
" <td>2.213710</td>\n",
" <td>0.015159</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>10002</td>\n",
" <td>1.7e-01 - 1.9e+00</td>\n",
" <td>(1.7e-01 - 1.9e+00)</td>\n",
" <td>H-1</td>\n",
" <td>scatter</td>\n",
" <td>1.997585</td>\n",
" <td>0.009161</td>\n",
" <td>2.011925</td>\n",
" <td>0.009406</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>10002</td>\n",
" <td>1.9e+00 - 2.0e+01</td>\n",
" <td>(1.9e+00 - 2.0e+01)</td>\n",
" <td>H-1</td>\n",
" <td>scatter</td>\n",
" <td>0.373472</td>\n",
" <td>0.003922</td>\n",
" <td>0.371280</td>\n",
" <td>0.003949</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" cell energy [MeV] nuclide score mean std. dev.\n",
"bin \n",
"0 10002 1.0e-08 - 1.1e-07 H-1 scatter 4.620525 0.038249\n",
"1 10002 1.1e-07 - 1.2e-06 H-1 scatter 2.036841 0.013203\n",
"2 10002 1.2e-06 - 1.3e-05 H-1 scatter 1.659916 0.010107\n",
"3 10002 1.3e-05 - 1.4e-04 H-1 scatter 1.861546 0.013328\n",
"4 10002 1.4e-04 - 1.5e-03 H-1 scatter 2.049664 0.008215\n",
"5 10002 1.5e-03 - 1.6e-02 H-1 scatter 2.162157 0.010245\n",
"6 10002 1.6e-02 - 1.7e-01 H-1 scatter 2.224496 0.013796\n",
"7 10002 1.7e-01 - 1.9e+00 H-1 scatter 1.997585 0.009161\n",
"8 10002 1.9e+00 - 2.0e+01 H-1 scatter 0.373472 0.003922"
" cell energy [MeV] nuclide score mean std. dev.\n",
"0 10002 (1.0e-08 - 1.1e-07) H-1 scatter 4.619398 0.040124\n",
"1 10002 (1.1e-07 - 1.2e-06) H-1 scatter 2.030757 0.011239\n",
"2 10002 (1.2e-06 - 1.3e-05) H-1 scatter 1.658488 0.009777\n",
"3 10002 (1.3e-05 - 1.4e-04) H-1 scatter 1.853002 0.007378\n",
"4 10002 (1.4e-04 - 1.5e-03) H-1 scatter 2.050773 0.012484\n",
"5 10002 (1.5e-03 - 1.6e-02) H-1 scatter 2.131759 0.007821\n",
"6 10002 (1.6e-02 - 1.7e-01) H-1 scatter 2.213710 0.015159\n",
"7 10002 (1.7e-01 - 1.9e+00) H-1 scatter 2.011925 0.009406\n",
"8 10002 (1.9e+00 - 2.0e+01) H-1 scatter 0.371280 0.003949"
]
},
"execution_count": 38,
@ -1644,7 +1568,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.9"
"version": "2.7.6"
}
},
"nbformat": 4,

View file

@ -57,6 +57,15 @@ on a given module or class.
summary
tallies
**Multi-Group Cross Section Generation**
.. toctree::
:maxdepth: 1
mgxs
energy_groups
mgxs_library
**Example Jupyter Notebooks:**
.. toctree::
@ -65,6 +74,7 @@ on a given module or class.
examples/post-processing
examples/pandas-dataframes
examples/tally-arithmetic
examples/multi-group-cross-sections
.. _Jupyter: https://jupyter.org/
.. _NumPy: http://www.numpy.org/

View file

@ -0,0 +1,66 @@
.. _pythonapi_mgxs:
==========================
Multi-Group Cross Sections
==========================
.. currentmodule:: openmc.mgxs.mgxs
----------------------------
Summary of Available Classes
----------------------------
.. autosummary::
MGXS
AbsorptionXS
CaptureXS
Chi
FissionXS
NuFissionXS
NuScatterXS
NuScatterMatrixXS
ScatterXS
ScatterMatrixXS
TotalXS
TransportXS
-------------------
Class Documentation
-------------------
.. autoclass:: MGXS
:members:
.. autoclass:: AbsorptionXS
:members:
.. autoclass:: CaptureXS
:members:
.. autoclass:: Chi
:members:
.. autoclass:: FissionXS
:members:
.. autoclass:: NuFissionXS
:members:
.. autoclass:: NuScatterXS
:members:
.. autoclass:: NuScatterMatrixXS
:members:
.. autoclass:: ScatterXS
:members:
.. autoclass:: ScatterMatrixXS
:members:
.. autoclass:: TotalXS
:members:
.. autoclass:: TransportXS
:members:

View file

@ -0,0 +1,8 @@
.. _pythonapi_mgxs_library:
============
MGXS Library
============
.. automodule:: openmc.mgxs.library
:members:

View file

@ -12,6 +12,8 @@ from openmc.trigger import *
from openmc.tallies import *
from openmc.cmfd import *
from openmc.executor import *
from openmc.statepoint import *
from openmc.summary import *
try:
from openmc.opencg_compatible import *

View file

@ -1,9 +1,20 @@
import sys
from openmc import Filter, Nuclide
from openmc.filter import _FILTER_TYPES
import openmc.checkvalue as cv
if sys.version_info[0] >= 3:
basestring = str
# Acceptable tally arithmetic binary operations
_TALLY_ARITHMETIC_OPS = ['+', '-', '*', '/', '^']
class CrossScore(object):
"""A special-purpose tally score used to encapsulate all combinations of two
tally's scores as a outer product for tally arithmetic.
tally's scores as an outer product for tally arithmetic.
Parameters
----------
@ -40,6 +51,38 @@ class CrossScore(object):
if binary_op is not None:
self.binary_op = binary_op
def __hash__(self):
return hash(str(self))
def __eq__(self, other):
return str(other) == str(self)
def __ne__(self, other):
return not self == other
def __deepcopy__(self, memo):
existing = memo.get(id(self))
# If this is the first time we have tried to copy this object, create a copy
if existing is None:
clone = type(self).__new__(type(self))
clone._left_score = self.left_score
clone._right_score = self.right_score
clone._binary_op = self.binary_op
memo[id(self)] = clone
return clone
# If this object has been copied before, return the first copy made
else:
return existing
def __repr__(self):
string = '({0} {1} {2})'.format(self.left_score,
self.binary_op, self.right_score)
return string
@property
def left_score(self):
return self._left_score
@ -54,28 +97,24 @@ class CrossScore(object):
@left_score.setter
def left_score(self, left_score):
cv.check_type('left_score', left_score, (basestring, CrossScore))
self._left_score = left_score
@right_score.setter
def right_score(self, right_score):
cv.check_type('right_score', right_score, (basestring, CrossScore))
self._right_score = right_score
@binary_op.setter
def binary_op(self, binary_op):
cv.check_type('binary_op', binary_op, (basestring, CrossScore))
cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS)
self._binary_op = binary_op
def __eq__(self, other):
return str(other) == str(self)
def __repr__(self):
string = '({0} {1} {2})'.format(self.left_score,
self.binary_op, self.right_score)
return string
class CrossNuclide(object):
"""A special-purpose nuclide used to encapsulate all combinations of two
tally's nuclides as a outer product for tally arithmetic.
tally's nuclides as an outer product for tally arithmetic.
Parameters
----------
@ -112,33 +151,33 @@ class CrossNuclide(object):
if binary_op is not None:
self.binary_op = binary_op
@property
def left_nuclide(self):
return self._left_nuclide
@property
def right_nuclide(self):
return self._right_nuclide
@property
def binary_op(self):
return self._binary_op
@left_nuclide.setter
def left_nuclide(self, left_nuclide):
self._left_nuclide = left_nuclide
@right_nuclide.setter
def right_nuclide(self, right_nuclide):
self._right_nuclide = right_nuclide
@binary_op.setter
def binary_op(self, binary_op):
self._binary_op = binary_op
def __hash__(self):
return hash(str(self))
def __eq__(self, other):
return str(other) == str(self)
def __ne__(self, other):
return not self == other
def __deepcopy__(self, memo):
existing = memo.get(id(self))
# If this is the first time we have tried to copy this object, create a copy
if existing is None:
clone = type(self).__new__(type(self))
clone._left_nuclide = self.left_nuclide
clone._right_nuclide = self.right_nuclide
clone._binary_op = self.binary_op
memo[id(self)] = clone
return clone
# If this object has been copied before, return the first copy made
else:
return existing
def __repr__(self):
string = ''
@ -161,10 +200,38 @@ class CrossNuclide(object):
return string
@property
def left_nuclide(self):
return self._left_nuclide
@property
def right_nuclide(self):
return self._right_nuclide
@property
def binary_op(self):
return self._binary_op
@left_nuclide.setter
def left_nuclide(self, left_nuclide):
cv.check_type('left_nuclide', left_nuclide, (Nuclide, CrossNuclide))
self._left_nuclide = left_nuclide
@right_nuclide.setter
def right_nuclide(self, right_nuclide):
cv.check_type('right_nuclide', right_nuclide, (Nuclide, CrossNuclide))
self._right_nuclide = right_nuclide
@binary_op.setter
def binary_op(self, binary_op):
cv.check_type('binary_op', binary_op, basestring)
cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS)
self._binary_op = binary_op
class CrossFilter(object):
"""A special-purpose filter used to encapsulate all combinations of two
tally's filter bins as a outer product for tally arithmetic.
tally's filter bins as an outer product for tally arithmetic.
Parameters
----------
@ -192,12 +259,10 @@ class CrossFilter(object):
left_type = left_filter.type
right_type = right_filter.type
self.type = '({0} {1} {2})'.format(left_type, binary_op, right_type)
self._type = '({0} {1} {2})'.format(left_type, binary_op, right_type)
self._bins = {}
self._bins['left'] = left_filter.bins
self._bins['right'] = right_filter.bins
self._num_bins = left_filter.num_bins * right_filter.num_bins
self._stride = None
self._left_filter = None
self._right_filter = None
@ -205,13 +270,34 @@ class CrossFilter(object):
if left_filter is not None:
self.left_filter = left_filter
self._bins['left'] = left_filter.bins
if right_filter is not None:
self.right_filter = right_filter
self._bins['right'] = right_filter.bins
if binary_op is not None:
self.binary_op = binary_op
def __hash__(self):
return hash((self.type, self.bins))
return hash((self.left_filter, self.right_filter))
def __eq__(self, other):
return str(other) == str(self)
def __ne__(self, other):
return not self == other
def __repr__(self):
string = 'CrossFilter\n'
filter_type = '({0} {1} {2})'.format(self.left_filter.type,
self.binary_op,
self.right_filter.type)
filter_bins = '({0} {1} {2})'.format(self.left_filter.bins,
self.binary_op,
self.right_filter.bins)
string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', filter_type)
string += '{0: <16}{1}{2}\n'.format('\tBins', '=\t', filter_bins)
return string
def __deepcopy__(self, memo):
existing = memo.get(id(self))
@ -221,9 +307,12 @@ class CrossFilter(object):
clone = type(self).__new__(type(self))
clone._left_filter = self.left_filter
clone._right_filter = self.right_filter
clone._binary_op = self.binary_op
clone._type = self.type
clone._bins = self.bins
clone._num_bins = self.num_bins
clone._stride = self.stride
memo[id(self)] = clone
return clone
@ -250,54 +339,49 @@ class CrossFilter(object):
@property
def bins(self):
return (self._bins['left'], self._bins['right'])
return self._bins['left'], self._bins['right']
@property
def num_bins(self):
return self._num_bins
if self.left_filter is not None and self.right_filter is not None:
return self.left_filter.num_bins * self.right_filter.num_bins
else:
return 0
@property
def stride(self):
return self.left_filter.stride * self.right_filter.stride
return self._stride
@type.setter
def type(self, filter_type):
if filter_type not in _FILTER_TYPES.values():
msg = 'Unable to set Filter type to "{0}" since it is not one ' \
'of the supported types'.format(type)
raise ValueError(msg)
self._type = filter_type
@left_filter.setter
def left_filter(self, left_filter):
cv.check_type('left_filter', left_filter, (Filter, CrossFilter))
self._left_filter = left_filter
self._bins['left'] = left_filter.bins
@right_filter.setter
def right_filter(self, right_filter):
cv.check_type('right_filter', right_filter, (Filter, CrossFilter))
self._right_filter = right_filter
self._bins['right'] = right_filter.bins
@binary_op.setter
def binary_op(self, binary_op):
cv.check_type('binary_op', binary_op, basestring)
cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS)
self._binary_op = binary_op
def __eq__(self, other):
return str(other) == str(self)
def split_filters(self):
split_filters = []
# If left Filter is not a CrossFilter, simply append to list
if isinstance(self.left_filter, Filter):
split_filters.append(self.left_filter)
# Recursively descend CrossFilter tree to collect all Filters
else:
split_filters.extend(self.left_filter.split_filters())
# If right Filter is not a CrossFilter, simply append to list
if isinstance(self.right_filter, Filter):
split_filters.append(self.right_filter)
# Recursively descend CrossFilter tree to collect all Filters
else:
split_filters.extend(self.right_filter.split_filters())
return split_filters
@stride.setter
def stride(self, stride):
self._stride = stride
def get_bin_index(self, filter_bin):
"""Returns the index in the CrossFilter for some bin.
@ -316,7 +400,7 @@ class CrossFilter(object):
Returns
-------
filter_index : int
filter_index : Integral
The index in the Tally data array for this filter bin.
"""
@ -326,15 +410,56 @@ class CrossFilter(object):
filter_index = left_index * self.right_filter.num_bins + right_index
return filter_index
def __repr__(self):
def get_pandas_dataframe(self, datasize, summary=None):
"""Builds a Pandas DataFrame for the CrossFilter's bins.
string = 'CrossFilter\n'
filter_type = '({0} {1} {2})'.format(self.left_filter.type,
self.binary_op,
self.right_filter.type)
filter_bins = '({0} {1} {2})'.format(self.left_filter.bins,
self.binary_op,
self.right_filter.bins)
string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', filter_type)
string += '{0: <16}{1}{2}\n'.format('\tBins', '=\t', filter_bins)
return string
This method constructs a Pandas DataFrame object for the CrossFilter
with columns annotated by filter bin information. This is a helper
method for the Tally.get_pandas_dataframe(...) method. This method
recursively builds and concatenates Pandas DataFrames for the left
and right filters and crossfilters.
This capability has been tested for Pandas >=0.13.1. However, it is
recommended to use v0.16 or newer versions of Pandas since this method
uses Pandas' Multi-index functionality.
Parameters
----------
datasize : Integral
The total number of bins in the tally corresponding to this filter
summary : None or Summary
An optional Summary object to be used to construct columns for
distribcell tally filters (default is None). The geometric
information in the Summary object is embedded into a Multi-index
column with a geometric "path" to each distribcell instance.
NOTE: This option requires the OpenCG Python package.
Returns
-------
pandas.DataFrame
A Pandas DataFrame with columns of strings that characterize the
crossfilter's bins. Each entry in the DataFrame will include one
or more binary operations used to construct the crossfilter's bins.
The number of rows in the DataFrame is the same as the total number
of bins in the corresponding tally, with the filter bins
appropriately tiled to map to the corresponding tally bins.
See also
--------
Tally.get_pandas_dataframe(), Filter.get_pandas_dataframe()
"""
# If left and right filters are identical, do not combine bins
if self.left_filter == self.right_filter:
df = self.left_filter.get_pandas_dataframe(datasize, summary)
# If left and right filters are different, combine their bins
else:
left_df = self.left_filter.get_pandas_dataframe(datasize, summary)
right_df = self.right_filter.get_pandas_dataframe(datasize, summary)
left_df = left_df.astype(str)
right_df = right_df.astype(str)
df = '(' + left_df + ' ' + self.binary_op + ' ' + right_df + ')'
return df

View file

@ -38,22 +38,30 @@ class Element(object):
if xs is not None:
self.xs = xs
def __eq__(self, element2):
# Check type
if not isinstance(element2, Element):
def __eq__(self, other):
if isinstance(other, Element):
if self._name != other._name:
return False
elif self._xs != other._xs:
return False
else:
return True
elif isinstance(other, basestring) and other == self.name:
return True
else:
return False
# Check name and xs
if self._name != element2._name:
return False
elif self._xs != element2._xs:
return False
else:
return True
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self._name, self._xs))
def __repr__(self):
string = 'Element - {0}\n'.format(self._name)
string += '{0: <16}{1}{2}\n'.format('\tXS', '=\t', self._xs)
return string
@property
def xs(self):
return self._xs
@ -70,9 +78,4 @@ class Element(object):
@name.setter
def name(self, name):
check_type('name', name, basestring)
self._name = name
def __repr__(self):
string = 'Element - {0}\n'.format(self._name)
string += '{0: <16}{1}{2}\n'.format('\tXS', '=\t', self._xs)
return string
self._name = name

View file

@ -30,14 +30,16 @@ class Executor(object):
stdout=subprocess.PIPE)
# Capture and re-print OpenMC output in real-time
while (True and output):
line = p.stdout.readline()
print(line, end='')
while True:
# If OpenMC is finished, break loop
line = p.stdout.readline()
if not line and p.poll() != None:
break
# If user requested output, print to screen
if output:
print(line, end='')
# Return the returncode (integer, zero if no problems encountered)
return p.returncode

View file

@ -1,20 +1,26 @@
from collections import Iterable
import copy
from numbers import Real, Integral
import sys
import numpy as np
from openmc import Mesh
from openmc.checkvalue import check_type, check_iterable_type, \
check_greater_than, _isinstance
from openmc.summary import Summary
import openmc.checkvalue as cv
if sys.version_info[0] >= 3:
basestring = str
_FILTER_TYPES = ['universe', 'material', 'cell', 'cellborn', 'surface',
'mesh', 'energy', 'energyout', 'mu', 'polar', 'azimuthal',
'distribcell', 'delayedgroup']
class Filter(object):
"""A filter used to constrain a tally to a specific criterion, e.g. only tally
events when the particle is in a certain cell and energy range.
"""A filter used to constrain a tally to a specific criterion, e.g. only
tally events when the particle is in a certain cell and energy range.
Parameters
----------
@ -22,46 +28,60 @@ class Filter(object):
The type of the tally filter. Acceptable values are "universe",
"material", "cell", "cellborn", "surface", "mesh", "energy",
"energyout", and "distribcell".
bins : int or Iterable of int or Iterable of float
bins : Integral or Iterable of Integral or Iterable of Real
The bins for the filter. This takes on different meaning for different
filters.
filters. See the OpenMC online documentation for more details.
Attributes
----------
type : str
The type of the tally filter.
bins : int or Iterable of int or Iterable of float
bins : Integral or Iterable of Integral or Iterable of Real
The bins for the filter
num_bins : Integral
The number of filter bins
mesh : Mesh or None
A Mesh object for 'mesh' type filters.
offset : Integral
A value used to index tally bins for 'distribcell' tallies.
stride : Integral
The number of filter, nuclide and score bins within each of this
filter's bins.
"""
# Initialize Filter class attributes
def __init__(self, type=None, bins=None):
self.type = type
self._type = None
self._num_bins = 0
self.bins = bins
self._bins = None
self._mesh = None
self._offset = -1
self._stride = None
def __eq__(self, filter2):
# Check type
if self.type != filter2.type:
return False
if type is not None:
self.type = type
if bins is not None:
self.bins = bins
# Check number of bins
elif len(self.bins) != len(filter2.bins):
def __eq__(self, other):
if not isinstance(other, Filter):
return False
# Check bin edges
elif not np.allclose(self.bins, filter2.bins):
elif self.type != other.type:
return False
elif len(self.bins) != len(other.bins):
return False
elif not np.allclose(self.bins, other.bins):
return False
else:
return True
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self._type, self._bins))
return hash((self.type, tuple(self.bins)))
def __deepcopy__(self, memo):
existing = memo.get(id(self))
@ -84,6 +104,13 @@ class Filter(object):
else:
return existing
def __repr__(self):
string = 'Filter\n'
string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self.type)
string += '{0: <16}{1}{2}\n'.format('\tBins', '=\t', self.bins)
string += '{0: <16}{1}{2}\n'.format('\tOffset', '=\t', self.offset)
return string
@property
def type(self):
return self._type
@ -94,7 +121,14 @@ class Filter(object):
@property
def num_bins(self):
return self._num_bins
if self.bins is None:
return 0
elif self.type in ['energy', 'energyout']:
return len(self.bins) - 1
elif self.type in ['cell', 'cellborn', 'surface', 'universe', 'material']:
return len(self.bins)
else:
return self._num_bins
@property
def mesh(self):
@ -121,15 +155,13 @@ class Filter(object):
@bins.setter
def bins(self, bins):
if bins is None:
self.num_bins = 0
elif self._type is None:
if self.type is None:
msg = 'Unable to set bins for Filter to "{0}" since ' \
'the Filter type has not yet been set'.format(bins)
raise ValueError(msg)
# If the bin edge is a single value, it is a Cell, Material, etc. ID
if not _isinstance(bins, Iterable):
if not isinstance(bins, Iterable):
bins = [bins]
# If the bins are in a collection, convert it to a list
@ -137,14 +169,14 @@ class Filter(object):
bins = list(bins)
if self.type in ['cell', 'cellborn', 'surface', 'material',
'universe', 'distribcell', 'delayedgroup']:
check_iterable_type('filter bins', bins, Integral)
'universe', 'distribcell', 'delayedgroup']:
cv.check_iterable_type('filter bins', bins, Integral)
for edge in bins:
check_greater_than('filter bin', edge, 0, equality=True)
cv.check_greater_than('filter bin', edge, 0, equality=True)
elif self._type in ['energy', 'energyout']:
elif self.type in ['energy', 'energyout']:
for edge in bins:
if not _isinstance(edge, Real):
if not cv._isinstance(edge, Real):
msg = 'Unable to add bin edge "{0}" to a "{1}" Filter ' \
'since it is a non-integer or floating point ' \
'value'.format(edge, self.type)
@ -163,12 +195,12 @@ class Filter(object):
raise ValueError(msg)
# mesh filters
elif self._type == 'mesh':
elif self.type == 'mesh':
if not len(bins) == 1:
msg = 'Unable to add bins "{0}" to a mesh Filter since ' \
'only a single mesh can be used per tally'.format(bins)
raise ValueError(msg)
elif not _isinstance(bins[0], Integral):
elif not isinstance(bins[0], Integral):
msg = 'Unable to add bin "{0}" to mesh Filter since it ' \
'is a non-integer'.format(bins[0])
raise ValueError(msg)
@ -180,16 +212,15 @@ class Filter(object):
# If all error checks passed, add bin edges
self._bins = np.array(bins)
# FIXME
@num_bins.setter
def num_bins(self, num_bins):
check_type('filter num_bins', num_bins, Integral)
check_greater_than('filter num_bins', num_bins, 0, equality=True)
cv.check_type('filter num_bins', num_bins, Integral)
cv.check_greater_than('filter num_bins', num_bins, 0, equality=True)
self._num_bins = num_bins
@mesh.setter
def mesh(self, mesh):
check_type('filter mesh', mesh, Mesh)
cv.check_type('filter mesh', mesh, Mesh)
self._mesh = mesh
self.type = 'mesh'
@ -197,12 +228,12 @@ class Filter(object):
@offset.setter
def offset(self, offset):
check_type('filter offset', offset, Integral)
cv.check_type('filter offset', offset, Integral)
self._offset = offset
@stride.setter
def stride(self, stride):
check_type('filter stride', stride, Integral)
cv.check_type('filter stride', stride, Integral)
if stride < 0:
msg = 'Unable to set stride "{0}" for a "{1}" Filter since it ' \
'is a negative value'.format(stride, self.type)
@ -277,25 +308,63 @@ class Filter(object):
return merged_filter
def is_subset(self, other):
"""Determine if another filter is a subset of this filter.
If all of the bins in the other filter are included as bins in this
filter, then it is a subset of this filter.
Parameters
----------
other : Filter
The filter to query as a subset of this filter
Returns
-------
bool
Whether or not the other filter is a subset of this filter
"""
if not isinstance(other, Filter):
return False
elif self.type != other.type:
return False
elif self.type in ['energy', 'energyout']:
if len(self.bins) != len(other.bins):
return False
else:
return np.allclose(self.bins, other.bins)
for bin in other.bins:
if bin not in self.bins:
return False
return True
def get_bin_index(self, filter_bin):
"""Returns the index in the Filter for some bin.
Parameters
----------
filter_bin : int or tuple
filter_bin : Integral or tuple
The bin is the integer ID for 'material', 'surface', 'cell',
'cellborn', and 'universe' Filters. The bin is an integer for the
cell instance ID for 'distribcell' Filters. The bin is a 2-tuple of
floats for 'energy' and 'energyout' filters corresponding to the
energy boundaries of the bin of interest. The bin is a (x,y,z)
3-tuple for 'mesh' filters corresponding to the mesh cell of
energy boundaries of the bin of interest. The bin is an (x,y,z)
3-tuple for 'mesh' filters corresponding to the mesh cell
interest.
Returns
-------
filter_index : int
filter_index : Integral
The index in the Tally data array for this filter bin.
See also
--------
Filter.get_bin()
"""
try:
@ -317,10 +386,14 @@ class Filter(object):
# Use lower energy bound to find index for energy Filters
elif self.type in ['energy', 'energyout']:
val = np.where(self.bins == filter_bin[0])[0][0]
filter_index = val
deltas = np.abs(self.bins - filter_bin[1]) / filter_bin[1]
min_delta = np.min(deltas)
if min_delta < 1E-3:
filter_index = deltas.argmin() - 1
else:
raise ValueError
# Filter bins for distribcell are the "IDs" of each unique placement
# Filter bins for distribcells are "IDs" of each unique placement
# of the Cell in the Geometry (integers starting at 0)
elif self.type == 'distribcell':
filter_index = filter_bin
@ -332,14 +405,355 @@ class Filter(object):
except ValueError:
msg = 'Unable to get the bin index for Filter since "{0}" ' \
'is not one of the bins'.format(filter_bin)
'is not one of the bins'.format(filter_bin)
raise ValueError(msg)
return filter_index
def __repr__(self):
string = 'Filter\n'
string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self.type)
string += '{0: <16}{1}{2}\n'.format('\tBins', '=\t', self.bins)
string += '{0: <16}{1}{2}\n'.format('\tOffset', '=\t', self.offset)
return string
def get_bin(self, bin_index):
"""Returns the filter bin for some filter bin index.
Parameters
----------
bin_index : Integral
The zero-based index into the filter's array of bins. The bin
index for 'material', 'surface', 'cell', 'cellborn', and 'universe'
filters corresponds to the ID in the filter's list of bins. For
'distribcell' tallies the bin index necessarily can only be zero
since only one cell can be tracked per tally. The bin index for
'energy' and 'energyout' filters corresponds to the energy range of
interest in the filter bins of energies. The bin index for 'mesh'
filters is the index into the flattened array of (x,y) or (x,y,z)
mesh cell bins.
Returns
-------
bin : 1-, 2-, or 3-tuple of Real
The bin in the Tally data array. The bin for 'material', surface',
'cell', 'cellborn', 'universe' and 'distribcell' filters is a
1-tuple of the ID corresponding to the appropriate filter bin.
The bin for 'energy' and 'energyout' filters is a 2-tuple of the
lower and upper energies bounding the energy interval for the filter
bin. The bin for 'mesh' tallies is a 2-tuple or 3-tuple of the x,y
or x,y,z mesh cell indices corresponding to the bin in a 2D/3D mesh.
See also
--------
Filter.get_bin_index()
"""
cv.check_type('bin_index', bin_index, Integral)
cv.check_greater_than('bin_index', bin_index, 0, equality=True)
cv.check_less_than('bin_index', bin_index, self.num_bins)
if self.type == 'mesh':
# Construct 3-tuple of x,y,z cell indices for a 3D mesh
if len(self.mesh.dimension) == 3:
nx, ny, nz = self.mesh.dimension
x = bin_index / (ny * nz)
y = (bin_index - (x * ny * nz)) / nz
z = bin_index - (x * ny * nz) - (y * nz)
filter_bin = (x, y, z)
# Construct 2-tuple of x,y cell indices for a 2D mesh
else:
nx, ny = self.mesh.dimension
x = bin_index / ny
y = bin_index - (x * ny)
filter_bin = (x, y)
# Construct 2-tuple of lower, upper energies for energy(out) filters
elif self.type in ['energy', 'energyout']:
filter_bin = (self.bins[bin_index], self.bins[bin_index+1])
# Construct 1-tuple of with the cell ID for distribcell filters
elif self.type == 'distribcell':
filter_bin = (self.bins[0],)
# Construct 1-tuple with domain ID (e.g., material) for other filters
else:
filter_bin = (self.bins[bin_index],)
return filter_bin
def get_pandas_dataframe(self, data_size, summary=None):
"""Builds a Pandas DataFrame for the Filter's bins.
This method constructs a Pandas DataFrame object for the filter with
columns annotated by filter bin information. This is a helper method
for the Tally.get_pandas_dataframe(...) method.
This capability has been tested for Pandas >=0.13.1. However, it is
recommended to use v0.16 or newer versions of Pandas since this method
uses Pandas' Multi-index functionality.
Parameters
----------
data_size : Integral
The total number of bins in the tally corresponding to this filter
summary : None or Summary
An optional Summary object to be used to construct columns for
distribcell tally filters (default is None). The geometric
information in the Summary object is embedded into a Multi-index
column with a geometric "path" to each distribcell instance.
NOTE: This option requires the OpenCG Python package.
Returns
-------
pandas.DataFrame
A Pandas DataFrame with columns of strings that characterize the
filter's bins. The number of rows in the DataFrame is the same as
the total number of bins in the corresponding tally, with the filter
bin appropriately tiled to map to the corresponding tally bins.
For 'cell', 'cellborn', 'surface', 'material', and 'universe'
filters, the DataFrame includes a single column with the cell,
surface, material or universe ID corresponding to each filter bin.
For 'distribcell' filters, the DataFrame either includes:
1. a single column with the cell instance IDs (without summary info)
2. separate columns for the cell IDs, universe IDs, and lattice IDs
and x,y,z cell indices corresponding to each (with summary info).
For 'energy' and 'energyout' filters, the DataFrame include a single
column with each element comprising a string with the lower, upper
energy bounds for each filter bin.
For 'mesh' filters, the DataFrame includes three columns for the
x,y,z mesh cell indices corresponding to each filter bin.
Raises
------
ImportError
When Pandas is not installed, or summary info is requested but
OpenCG is not installed.
See also
--------
Tally.get_pandas_dataframe(), CrossFilter.get_pandas_dataframe()
"""
# Attempt to import Pandas
try:
import pandas as pd
except ImportError:
msg = 'The Pandas Python package must be installed on your system'
raise ImportError(msg)
# Initialize Pandas DataFrame
df = pd.DataFrame()
# mesh filters
if self.type == 'mesh':
# Initialize dictionary to build Pandas Multi-index column
filter_dict = {}
# Append Mesh ID as outermost index of mult-index
mesh_key = 'mesh {0}'.format(self.mesh.id)
# Find mesh dimensions - use 3D indices for simplicity
if (len(self.mesh.dimension) == 3):
nx, ny, nz = self.mesh.dimension
else:
nx, ny = self.mesh.dimension
nz = 1
# Generate multi-index sub-column for x-axis
filter_bins = np.arange(1, nx+1)
repeat_factor = ny * nz * self.stride
filter_bins = np.repeat(filter_bins, repeat_factor)
tile_factor = data_size / len(filter_bins)
filter_bins = np.tile(filter_bins, tile_factor)
filter_dict[(mesh_key, 'x')] = filter_bins
# Generate multi-index sub-column for y-axis
filter_bins = np.arange(1, ny+1)
repeat_factor = nz * self.stride
filter_bins = np.repeat(filter_bins, repeat_factor)
tile_factor = data_size / len(filter_bins)
filter_bins = np.tile(filter_bins, tile_factor)
filter_dict[(mesh_key, 'y')] = filter_bins
# Generate multi-index sub-column for z-axis
filter_bins = np.arange(1, nz+1)
repeat_factor = self.stride
filter_bins = np.repeat(filter_bins, repeat_factor)
tile_factor = data_size / len(filter_bins)
filter_bins = np.tile(filter_bins, tile_factor)
filter_dict[(mesh_key, 'z')] = filter_bins
# Initialize a Pandas DataFrame from the mesh dictionary
df = pd.concat([df, pd.DataFrame(filter_dict)])
# distribcell filters
elif self.type == 'distribcell':
level_df = None
if isinstance(summary, Summary):
# Attempt to import the OpenCG package
try:
import opencg
except ImportError:
msg = 'The OpenCG package must be installed ' \
'to use a Summary for distribcell dataframes'
raise ImportError(msg)
# Create and extract the OpenCG geometry the Summary
summary.make_opencg_geometry()
opencg_geometry = summary.opencg_geometry
openmc_geometry = summary.openmc_geometry
# Use OpenCG to compute the number of regions
opencg_geometry.initialize_cell_offsets()
num_regions = opencg_geometry.num_regions
# Initialize a dictionary mapping OpenMC distribcell
# offsets to OpenCG LocalCoords linked lists
offsets_to_coords = {}
# Use OpenCG to compute LocalCoords linked list for
# each region and store in dictionary
for region in range(num_regions):
coords = opencg_geometry.find_region(region)
path = opencg.get_path(coords)
cell_id = path[-1]
# If this region is in Cell corresponding to the
# distribcell filter bin, store it in dictionary
if cell_id == self.bins[0]:
offset = openmc_geometry.get_offset(path, self.offset)
offsets_to_coords[offset] = coords
# Each distribcell offset is a DataFrame bin
# Unravel the paths into DataFrame columns
num_offsets = len(offsets_to_coords)
# Initialize termination condition for while loop
levels_remain = True
counter = 0
# Iterate over each level in the CSG tree hierarchy
while levels_remain:
levels_remain = False
# Initialize dictionary to build Pandas Multi-index
# column for this level in the CSG tree hierarchy
level_dict = {}
# Initialize prefix Multi-index keys
counter += 1
level_key = 'level {0}'.format(counter)
univ_key = (level_key, 'univ', 'id')
cell_key = (level_key, 'cell', 'id')
lat_id_key = (level_key, 'lat', 'id')
lat_x_key = (level_key, 'lat', 'x')
lat_y_key = (level_key, 'lat', 'y')
lat_z_key = (level_key, 'lat', 'z')
# Allocate NumPy arrays for each CSG level and
# each Multi-index column in the DataFrame
level_dict[univ_key] = np.empty(num_offsets)
level_dict[cell_key] = np.empty(num_offsets)
level_dict[lat_id_key] = np.empty(num_offsets)
level_dict[lat_x_key] = np.empty(num_offsets)
level_dict[lat_y_key] = np.empty(num_offsets)
level_dict[lat_z_key] = np.empty(num_offsets)
# Initialize Multi-index columns to NaN - this is
# necessary since some distribcell instances may
# have very different LocalCoords linked lists
level_dict[univ_key][:] = np.NAN
level_dict[cell_key][:] = np.NAN
level_dict[lat_id_key][:] = np.NAN
level_dict[lat_x_key][:] = np.NAN
level_dict[lat_y_key][:] = np.NAN
level_dict[lat_z_key][:] = np.NAN
# Iterate over all regions (distribcell instances)
for offset in range(num_offsets):
coords = offsets_to_coords[offset]
# If entire LocalCoords has been unraveled into
# Multi-index columns already, continue
if coords is None:
continue
# Assign entry to Universe Multi-index column
if coords._type == 'universe':
level_dict[univ_key][offset] = coords._universe._id
level_dict[cell_key][offset] = coords._cell._id
# Assign entry to Lattice Multi-index column
else:
level_dict[lat_id_key][offset] = coords._lattice._id
level_dict[lat_x_key][offset] = coords._lat_x
level_dict[lat_y_key][offset] = coords._lat_y
level_dict[lat_z_key][offset] = coords._lat_z
# Move to next node in LocalCoords linked list
if coords._next is None:
offsets_to_coords[offset] = None
else:
offsets_to_coords[offset] = coords._next
levels_remain = True
# Tile the Multi-index columns
for level_key, level_bins in level_dict.items():
level_bins = np.repeat(level_bins, self.stride)
tile_factor = data_size / len(level_bins)
level_bins = np.tile(level_bins, tile_factor)
level_dict[level_key] = level_bins
# Initialize a Pandas DataFrame from the level dictionary
if level_df is None:
level_df = pd.DataFrame(level_dict)
else:
level_df = pd.concat([level_df, pd.DataFrame(level_dict)], axis=1)
# Create DataFrame column for distribcell instances IDs
# NOTE: This is performed regardless of whether the user
# requests Summary geometric information
filter_bins = np.arange(self.num_bins)
filter_bins = np.repeat(filter_bins, self.stride)
tile_factor = data_size / len(filter_bins)
filter_bins = np.tile(filter_bins, tile_factor)
filter_bins = filter_bins
df = pd.DataFrame({self.type : filter_bins})
# If OpenCG level info DataFrame was created, concatenate
# with DataFrame of distribcell instance IDs
if level_df is not None:
level_df = level_df.dropna(axis=1, how='all')
level_df = level_df.astype(np.int)
df = pd.concat([level_df, df], axis=1)
# energy, energyout filters
elif 'energy' in self.type:
bins = self.bins
num_bins = self.num_bins
# Create strings for
template = '({0:.1e} - {1:.1e})'
filter_bins = []
for i in range(num_bins):
filter_bins.append(template.format(bins[i], bins[i+1]))
# Tile the energy bins into a DataFrame column
filter_bins = np.repeat(filter_bins, self.stride)
tile_factor = data_size / len(filter_bins)
filter_bins = np.tile(filter_bins, tile_factor)
filter_bins = filter_bins
df = pd.concat([df, pd.DataFrame({self.type + ' [MeV]' : filter_bins})])
# universe, material, surface, cell, and cellborn filters
else:
filter_bins = np.repeat(self.bins, self.stride)
tile_factor = data_size / len(filter_bins)
filter_bins = np.tile(filter_bins, tile_factor)
filter_bins = filter_bins
df = pd.concat([df, pd.DataFrame({self.type : filter_bins})])
return df

View file

@ -1,3 +1,4 @@
from collections import OrderedDict
from xml.etree import ElementTree as ET
import openmc
@ -110,7 +111,7 @@ class Geometry(object):
"""
nuclides = {}
nuclides = OrderedDict()
materials = self.get_all_materials()
for material in materials:
@ -134,7 +135,9 @@ class Geometry(object):
for cell in material_cells:
materials.add(cell._fill)
return list(materials)
materials = list(materials)
materials.sort(key=lambda x: x.id)
return materials
def get_all_material_cells(self):
all_cells = self.get_all_cells()
@ -144,7 +147,9 @@ class Geometry(object):
if cell._type == 'normal':
material_cells.add(cell)
return list(material_cells)
material_cells = list(material_cells)
material_cells.sort(key=lambda x: x.id)
return material_cells
def get_all_material_universes(self):
"""Return all universes composed of at least one non-fill cell
@ -165,7 +170,9 @@ class Geometry(object):
if cell._type == 'normal':
material_universes.add(universe)
return list(material_universes)
material_universes = list(material_universes)
material_universes.sort(key=lambda x: x.id)
return material_universes
class GeometryFile(object):
@ -198,7 +205,13 @@ class GeometryFile(object):
"""
root_universe = self._geometry._root_universe
# Clear OpenMC written IDs used to optimize XML generation
openmc.universe.WRITTEN_IDS = {}
# Reset xml element tree
self._geometry_file.clear()
root_universe = self.geometry.root_universe
root_universe.create_xml_subelement(self._geometry_file)
# Clean the indentation in the file to be user-readable

View file

@ -83,6 +83,38 @@ class Material(object):
# If specified, this file will be used instead of composition values
self._distrib_otf_file = None
def __repr__(self):
string = 'Material\n'
string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id)
string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name)
string += '{0: <16}{1}{2}'.format('\tDensity', '=\t', self._density)
string += ' [{0}]\n'.format(self._density_units)
string += '{0: <16}\n'.format('\tS(a,b) Tables')
for sab in self._sab:
string += '{0: <16}{1}[{2}{3}]\n'.format('\tS(a,b)', '=\t',
sab[0], sab[1])
string += '{0: <16}\n'.format('\tNuclides')
for nuclide in self._nuclides:
percent = self._nuclides[nuclide][1]
percent_type = self._nuclides[nuclide][2]
string += '{0: <16}'.format('\t{0}'.format(nuclide))
string += '=\t{0: <12} [{1}]\n'.format(percent, percent_type)
string += '{0: <16}\n'.format('\tElements')
for element in self._elements:
percent = self._nuclides[element][1]
percent_type = self._nuclides[element][2]
string += '{0: >16}'.format('\t{0}'.format(element))
string += '=\t{0: <12} [{1}]\n'.format(percent, percent_type)
return string
@property
def id(self):
return self._id
@ -125,7 +157,7 @@ class Material(object):
msg = 'Unable to set Material ID to "{0}" since a Material with ' \
'this ID was already initialized'.format(material_id)
raise ValueError(msg)
check_greater_than('material ID', material_id, 0)
check_greater_than('material ID', material_id, 0, equality=True)
self._id = material_id
MATERIAL_IDS.append(material_id)
@ -326,7 +358,7 @@ class Material(object):
"""
nuclides = {}
nuclides = OrderedDict()
for nuclide_name, nuclide_tuple in self._nuclides.items():
nuclide = nuclide_tuple[0]
@ -335,38 +367,6 @@ class Material(object):
return nuclides
def __repr__(self):
string = 'Material\n'
string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id)
string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name)
string += '{0: <16}{1}{2}'.format('\tDensity', '=\t', self._density)
string += ' [{0}]\n'.format(self._density_units)
string += '{0: <16}\n'.format('\tS(a,b) Tables')
for sab in self._sab:
string += '{0: <16}{1}[{2}{3}]\n'.format('\tS(a,b)', '=\t',
sab[0], sab[1])
string += '{0: <16}\n'.format('\tNuclides')
for nuclide in self._nuclides:
percent = self._nuclides[nuclide][1]
percent_type = self._nuclides[nuclide][2]
string += '{0: <16}'.format('\t{0}'.format(nuclide))
string += '=\t{0: <12} [{1}]\n'.format(percent, percent_type)
string += '{0: <16}\n'.format('\tElements')
for element in self._elements:
percent = self._nuclides[element][1]
percent_type = self._nuclides[element][2]
string += '{0: >16}'.format('\t{0}'.format(element))
string += '=\t{0: <12} [{1}]\n'.format(percent, percent_type)
return string
def _get_nuclide_xml(self, nuclide, distrib=False):
xml_element = ET.Element("nuclide")
xml_element.set("name", nuclide[0]._name)
@ -581,6 +581,9 @@ class MaterialsFile(object):
"""
# Reset xml element tree
self._materials_file.clear()
self._create_material_subelements()
# Clean the indentation in the file to be user-readable

View file

@ -4,8 +4,10 @@ from numbers import Real, Integral
from xml.etree import ElementTree as ET
import sys
from openmc.checkvalue import (check_type, check_length, check_value,
check_greater_than)
import numpy as np
import openmc.checkvalue as cv
if sys.version_info[0] >= 3:
basestring = str
@ -142,14 +144,14 @@ class Mesh(object):
self._id = AUTO_MESH_ID
AUTO_MESH_ID += 1
else:
check_type('mesh ID', mesh_id, Integral)
check_greater_than('mesh ID', mesh_id, 0)
cv.check_type('mesh ID', mesh_id, Integral)
cv.check_greater_than('mesh ID', mesh_id, 0, equality=True)
self._id = mesh_id
@name.setter
def name(self, name):
if name is not None:
check_type('name for mesh ID="{0}"'.format(self._id),
cv.check_type('name for mesh ID="{0}"'.format(self._id),
name, basestring)
self._name = name
else:
@ -157,34 +159,34 @@ class Mesh(object):
@type.setter
def type(self, meshtype):
check_type('type for mesh ID="{0}"'.format(self._id),
cv.check_type('type for mesh ID="{0}"'.format(self._id),
meshtype, basestring)
check_value('type for mesh ID="{0}"'.format(self._id),
cv.check_value('type for mesh ID="{0}"'.format(self._id),
meshtype, ['regular'])
self._type = meshtype
@dimension.setter
def dimension(self, dimension):
check_type('mesh dimension', dimension, Iterable, Integral)
check_length('mesh dimension', dimension, 2, 3)
cv.check_type('mesh dimension', dimension, Iterable, Integral)
cv.check_length('mesh dimension', dimension, 2, 3)
self._dimension = dimension
@lower_left.setter
def lower_left(self, lower_left):
check_type('mesh lower_left', lower_left, Iterable, Real)
check_length('mesh lower_left', lower_left, 2, 3)
cv.check_type('mesh lower_left', lower_left, Iterable, Real)
cv.check_length('mesh lower_left', lower_left, 2, 3)
self._lower_left = lower_left
@upper_right.setter
def upper_right(self, upper_right):
check_type('mesh upper_right', upper_right, Iterable, Real)
check_length('mesh upper_right', upper_right, 2, 3)
cv.check_type('mesh upper_right', upper_right, Iterable, Real)
cv.check_length('mesh upper_right', upper_right, 2, 3)
self._upper_right = upper_right
@width.setter
def width(self, width):
check_type('mesh width', width, Iterable, Real)
check_length('mesh width', width, 2, 3)
cv.check_type('mesh width', width, Iterable, Real)
cv.check_length('mesh width', width, 2, 3)
self._width = width
def __repr__(self):

3
openmc/mgxs/__init__.py Normal file
View file

@ -0,0 +1,3 @@
from openmc.mgxs.groups import EnergyGroups
from openmc.mgxs.library import Library
from openmc.mgxs.mgxs import *

238
openmc/mgxs/groups.py Normal file
View file

@ -0,0 +1,238 @@
from collections import Iterable
from numbers import Real
import copy
import sys
import numpy as np
import openmc.checkvalue as cv
if sys.version_info[0] >= 3:
basestring = str
class EnergyGroups(object):
"""An energy groups structure used for multi-group cross-sections.
Parameters
----------
group_edges : Iterable of Real
The energy group boundaries [MeV]
Attributes
----------
group_edges : Iterable of Real
The energy group boundaries [MeV]
num_group : Integral
The number of energy groups
"""
def __init__(self, group_edges=None):
self._group_edges = None
if group_edges is not None:
self.group_edges = group_edges
def __deepcopy__(self, memo):
existing = memo.get(id(self))
# If this is the first time we have tried to copy object, create copy
if existing is None:
clone = type(self).__new__(type(self))
clone._group_edges = copy.deepcopy(self.group_edges, memo)
memo[id(self)] = clone
return clone
# If this object has been copied before, return the first copy made
else:
return existing
def __eq__(self, other):
if not isinstance(other, EnergyGroups):
return False
elif self.group_edges != other.group_edges:
return False
else:
return True
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(tuple(self.group_edges))
@property
def group_edges(self):
return self._group_edges
@property
def num_groups(self):
return len(self.group_edges) - 1
@group_edges.setter
def group_edges(self, edges):
cv.check_type('group edges', edges, Iterable, Real)
cv.check_greater_than('number of group edges', len(edges), 1)
self._group_edges = np.array(edges)
def get_group(self, energy):
"""Returns the energy group in which the given energy resides.
Parameters
----------
energy : Real
The energy of interest in MeV
Returns
-------
Integral
The energy group index, starting at 1 for the highest energies
Raises
------
ValueError
If the group edges have not yet been set.
"""
if self.group_edges is None:
msg = 'Unable to get energy group for energy "{0}" MeV since ' \
'the group edges have not yet been set'.format(energy)
raise ValueError(msg)
index = np.where(self.group_edges > energy)[0][0]
group = self.num_groups - index + 1
return group
def get_group_bounds(self, group):
"""Returns the energy boundaries for the energy group of interest.
Parameters
----------
group : Integral
The energy group index, starting at 1 for the highest energies
Returns
-------
2-tuple
The low and high energy bounds for the group in MeV
Raises
------
ValueError
If the group edges have not yet been set.
"""
if self.group_edges is None:
msg = 'Unable to get energy group bounds for group "{0}" since ' \
'the group edges have not yet been set'.format(group)
raise ValueError(msg)
cv.check_greater_than('group', group, 0)
cv.check_less_than('group', group, self.num_groups, equality=True)
lower = self.group_edges[self.num_groups-group]
upper = self.group_edges[self.num_groups-group+1]
return lower, upper
def get_group_indices(self, groups='all'):
"""Returns the array indices for one or more energy groups.
Parameters
----------
groups : str, tuple
The energy groups of interest - a tuple of the energy group indices,
starting at 1 for the highest energies (default is 'all')
Returns
-------
ndarray
The ndarray array indices for each energy group of interest
Raises
------
ValueError
If the group edges have not yet been set, or if a group is requested
that is outside the bounds of the number of energy groups.
"""
if self.group_edges is None:
msg = 'Unable to get energy group indices for groups "{0}" since ' \
'the group edges have not yet been set'.format(groups)
raise ValueError(msg)
if groups == 'all':
return np.arange(self.num_groups)
else:
indices = np.zeros(len(groups), dtype=np.int)
for i, group in enumerate(groups):
cv.check_greater_than('group', group, 0)
cv.check_less_than('group', group, self.num_groups, equality=True)
indices[i] = group - 1
return indices
def get_condensed_groups(self, coarse_groups):
"""Return a coarsened version of this EnergyGroups object.
This method merges together energy groups in this object into wider
energy groups as defined by the list of groups specified by the user,
and returns a new, coarse EnergyGroups object.
Parameters
----------
coarse_groups : Iterable of 2-tuple
The energy groups of interest - a list of 2-tuples, each directly
corresponding to one of the new coarse groups. The values in the
2-tuples are upper/lower energy groups used to construct a new
coarse group. For example, if [(1,2), (3,4)] was used as the coarse
groups, fine groups 1 and 2 would be merged into coarse group 1
while fine groups 3 and 4 would be merged into coarse group 2.
Returns
-------
EnergyGroups
A coarsened version of this EnergyGroups object.
Raises
------
ValueError
If the group edges have not yet been set.
"""
cv.check_type('group edges', coarse_groups, Iterable)
for group in coarse_groups:
cv.check_type('group edges', group, Iterable)
cv.check_length('group edges', group, 2)
cv.check_greater_than('lower group', group[0], 1, True)
cv.check_less_than('lower group', group[0], self.num_groups, True)
cv.check_greater_than('upper group', group[0], 1, True)
cv.check_less_than('upper group', group[0], self.num_groups, True)
cv.check_less_than('lower group', group[0], group[1], False)
# Compute the group indices into the coarse group
group_bounds = [group[1] for group in coarse_groups]
group_bounds.insert(0, coarse_groups[0][0])
# Determine the indices mapping the fine-to-coarse energy groups
group_bounds = np.asarray(group_bounds)
group_indices = np.flipud(self.num_groups - group_bounds)
group_indices[-1] += 1
# Determine the edges between coarse energy groups and sort
# in increasing order in case the user passed in unordered groups
group_edges = self.group_edges[group_indices]
group_edges = np.sort(group_edges)
# Create a new condensed EnergyGroups object
condensed_groups = EnergyGroups()
condensed_groups.group_edges = group_edges
return condensed_groups

611
openmc/mgxs/library.py Normal file
View file

@ -0,0 +1,611 @@
import sys
import os
import copy
import pickle
from numbers import Integral
from collections import OrderedDict
import openmc
import openmc.mgxs
import openmc.checkvalue as cv
if sys.version_info[0] >= 3:
basestring = str
class Library(object):
"""A multi-group cross section library for some energy group structure.
This class can be used for both OpenMC input generation and tally data
post-processing to compute spatially-homogenized and energy-integrated
multi-group cross sections for deterministic neutronics calculations.
This class helps automate the generation of MGXS objects for some energy
group structure and domain type. The Library serves as a collection for
MGXS objects with routines to automate the initialization of tallies for
input files, the loading of tally data from statepoint files, data storage,
energy group condensation and more.
Parameters
----------
openmc_geometry : openmc.Geometry
An geometry which has been initialized with a root universe
by_nuclide : bool
If true, computes cross sections for each nuclide in each domain
mgxs_types : Iterable of str
The types of cross sections in the library (e.g., ['total', 'scatter'])
name : str, optional
Name of the multi-group cross section. library Used as a label to
identify tallies in OpenMC 'tallies.xml' file.
Attributes
----------
openmc_geometry : openmc.Geometry
An geometry which has been initialized with a root universe
by_nuclide : bool
If true, computes cross sections for each nuclide in each domain
mgxs_types : Iterable of str
The types of cross sections in the library (e.g., ['total', 'scatter'])
domain_type : {'material', 'cell', 'distribcell', 'universe'}
Domain type for spatial homogenization
correction : 'P0' or None
Apply the P0 correction to scattering matrices if set to 'P0'
energy_groups : EnergyGroups
Energy group structure for energy condensation
tally_trigger : Trigger
An (optional) tally precision trigger given to each tally used to
compute the cross section
all_mgxs : OrderedDict
MGXS objects keyed by domain ID and cross section type
statepoint : openmc.StatePoint
The statepoint with tally data used to the compute cross sections
name : str, optional
Name of the multi-group cross section library. Used as a label to
identify tallies in OpenMC 'tallies.xml' file.
"""
def __init__(self, openmc_geometry, by_nuclide=False,
mgxs_types=None, name=''):
self._name = ''
self._openmc_geometry = None
self._by_nuclide = None
self._mgxs_types = []
self._domain_type = None
self._correction = 'P0'
self._energy_groups = None
self._tally_trigger = None
self._all_mgxs = OrderedDict()
self._sp_filename = None
self.name = name
self.openmc_geometry = openmc_geometry
self.by_nuclide = by_nuclide
if mgxs_types is not None:
self.mgxs_types = mgxs_types
def __deepcopy__(self, memo):
existing = memo.get(id(self))
# If this is the first time we have tried to copy this object, copy it
if existing is None:
clone = type(self).__new__(type(self))
clone._name = self.name
clone._openmc_geometry = self.openmc_geometry
clone._by_nuclide = self.by_nuclide
clone._mgxs_types = self.mgxs_types
clone._domain_type = self.domain_type
clone._correction = self.correction
clone._energy_groups = copy.deepcopy(self.energy_groups, memo)
clone._tally_trigger = copy.deepcopy(self.tally_trigger, memo)
clone._all_mgxs = self.all_mgxs
clone._sp_filename = self._sp_filename
clone._all_mgxs = OrderedDict()
for domain in self.domains:
clone.all_mgxs[domain.id] = OrderedDict()
for mgxs_type in self.mgxs_types:
mgxs = copy.deepcopy(self.all_mgxs[domain.id][mgxs_type])
clone.all_mgxs[domain.id][mgxs_type] = mgxs
memo[id(self)] = clone
return clone
# If this object has been copied before, return the first copy made
else:
return existing
@property
def openmc_geometry(self):
return self._openmc_geometry
@property
def name(self):
return self._name
@property
def mgxs_types(self):
return self._mgxs_types
@property
def by_nuclide(self):
return self._by_nuclide
@property
def domains(self):
if self.domain_type is None:
raise ValueError('Unable to get all domains without a domain type')
if self.domain_type == 'material':
return self.openmc_geometry.get_all_materials()
elif self.domain_type == 'cell' or self.domain_type == 'distribcell':
return self.openmc_geometry.get_all_material_cells()
elif self.domain_type == 'universe':
return self.openmc_geometry.get_all_universes()
@property
def domain_type(self):
return self._domain_type
@property
def correction(self):
return self._correction
@property
def energy_groups(self):
return self._energy_groups
@property
def tally_trigger(self):
return self._tally_trigger
@property
def num_groups(self):
return self.energy_groups.num_groups
@property
def all_mgxs(self):
return self._all_mgxs
@property
def statepoint(self):
return self._sp_filename
@openmc_geometry.setter
def openmc_geometry(self, openmc_geometry):
cv.check_type('openmc_geometry', openmc_geometry, openmc.Geometry)
self._openmc_geometry = openmc_geometry
@name.setter
def name(self, name):
cv.check_type('name', name, basestring)
self._name = name
@mgxs_types.setter
def mgxs_types(self, mgxs_types):
if mgxs_types == 'all':
self._mgxs_types = openmc.mgxs.MGXS_TYPES
else:
cv.check_iterable_type('mgxs_types', mgxs_types, basestring)
for mgxs_type in mgxs_types:
cv.check_value('mgxs_type', mgxs_type, openmc.mgxs.MGXS_TYPES)
self._mgxs_types = mgxs_types
@by_nuclide.setter
def by_nuclide(self, by_nuclide):
cv.check_type('by_nuclide', by_nuclide, bool)
self._by_nuclide = by_nuclide
@domain_type.setter
def domain_type(self, domain_type):
cv.check_value('domain type', domain_type, tuple(openmc.mgxs.DOMAIN_TYPES))
self._domain_type = domain_type
@correction.setter
def correction(self, correction):
cv.check_value('correction', correction, ('P0', None))
self._correction = correction
@energy_groups.setter
def energy_groups(self, energy_groups):
cv.check_type('energy groups', energy_groups, openmc.mgxs.EnergyGroups)
self._energy_groups = energy_groups
@tally_trigger.setter
def tally_trigger(self, tally_trigger):
cv.check_type('tally trigger', tally_trigger, openmc.Trigger)
self._tally_trigger = tally_trigger
def build_library(self):
"""Initialize MGXS objects in each domain and for each reaction type
in the library.
This routine will populate the all_mgxs instance attribute dictionary
with MGXS subclass objects keyed by each domain ID (e.g., Material IDs)
and cross section type (e.g., 'nu-fission', 'total', etc.).
"""
# Initialize MGXS for each domain and mgxs type and store in dictionary
for domain in self.domains:
self.all_mgxs[domain.id] = OrderedDict()
for mgxs_type in self.mgxs_types:
mgxs = openmc.mgxs.MGXS.get_mgxs(mgxs_type, name=self.name)
mgxs.domain = domain
mgxs.domain_type = self.domain_type
mgxs.energy_groups = self.energy_groups
mgxs.by_nuclide = self.by_nuclide
# If a tally trigger was specified, add it to the MGXS
if self.tally_trigger:
mgxs.tally_trigger = self.tally_trigger
# Specify whether to use a transport ('P0') correction
if isinstance(mgxs, openmc.mgxs.ScatterMatrixXS):
mgxs.correction = self.correction
self.all_mgxs[domain.id][mgxs_type] = mgxs
def add_to_tallies_file(self, tallies_file, merge=True):
"""Add all tallies from all MGXS objects to a tallies file.
NOTE: This assumes that build_library() has been called
Parameters
----------
tallies_file : openmc.TalliesFile
A TalliesFile object to add each MGXS' tallies to generate a
"tallies.xml" input file for OpenMC
merge : bool
Indicate whether tallies should be merged when possible. Defaults
to True.
"""
cv.check_type('tallies_file', tallies_file, openmc.TalliesFile)
# Add tallies from each MGXS for each domain and mgxs type
for domain in self.domains:
for mgxs_type in self.mgxs_types:
mgxs = self.get_mgxs(domain, mgxs_type)
for tally_id, tally in mgxs.tallies.items():
tallies_file.add_tally(tally, merge=merge)
def load_from_statepoint(self, statepoint):
"""Extracts tallies in an OpenMC StatePoint with the data needed to
compute multi-group cross sections.
This method is needed to compute cross section data from tallies
in an OpenMC StatePoint object.
NOTE: The statepoint must first be linked with an OpenMC Summary object.
Parameters
----------
statepoint : openmc.StatePoint
An OpenMC StatePoint object with tally data
Raises
------
ValueError
When this method is called with a statepoint that has not been
linked with a summary object.
"""
cv.check_type('statepoint', statepoint, openmc.StatePoint)
if not statepoint.with_summary:
msg = 'Unable to load data from a statepoint which has not been ' \
'linked with a summary file'
raise ValueError(msg)
self._sp_filename = statepoint._f.filename
# Load tallies for each MGXS for each domain and mgxs type
for domain in self.domains:
for mgxs_type in self.mgxs_types:
mgxs = self.get_mgxs(domain, mgxs_type)
mgxs.load_from_statepoint(statepoint)
def get_mgxs(self, domain, mgxs_type):
"""Return the MGXS object for some domain and reaction rate type.
This routine searches the library for an MGXS object for the spatial
domain and reaction rate type requested by the user.
NOTE: This routine must be called after the build_library() routine.
Parameters
----------
domain : Material or Cell or Universe or Integral
The material, cell, or universe object of interest (or its ID)
mgxs_type : {'total', 'transport', 'absorption', 'capture', 'fission', 'nu-fission', 'scatter', 'nu-scatter', 'scatter matrix', 'nu-scatter matrix', 'chi'}
The type of multi-group cross section object to return
Returns
-------
openmc.mgxs.MGXS
The MGXS object for the requested domain and reaction rate type
Raises
------
ValueError
If no MGXS object can be found for the requested domain or
multi-group cross section type
"""
if self.domain_type == 'material':
cv.check_type('domain', domain, (openmc.Material, Integral))
elif self.domain_type == 'cell' or self.domain_type == 'distribcell':
cv.check_type('domain', domain, (openmc.Cell, Integral))
elif self.domain_type == 'universe':
cv.check_type('domain', domain, (openmc.Universe, Integral))
# Check that requested domain is included in library
if cv._isinstance(domain, Integral):
domain_id = domain
for domain in self.domains:
if domain_id == domain.id:
break
else:
msg = 'Unable to find MGXS for {0} "{1}" in ' \
'library'.format(self.domain_type, domain)
raise ValueError(msg)
else:
domain_id = domain.id
# Check that requested domain is included in library
if mgxs_type not in self.mgxs_types:
msg = 'Unable to find MGXS type "{0}"'.format(mgxs_type)
raise ValueError(msg)
return self.all_mgxs[domain_id][mgxs_type]
def get_condensed_library(self, coarse_groups):
"""Construct an energy-condensed version of this library.
This routine condenses each of the multi-group cross sections in the
library to a coarse energy group structure. NOTE: This routine must
be called after the load_from_statepoint(...) routine loads the tallies
from the statepoint into each of the cross sections.
Parameters
----------
coarse_groups : openmc.mgxs.EnergyGroups
The coarse energy group structure of interest
Returns
-------
Library
A new multi-group cross section library condensed to the group
structure of interest
Raises
------
ValueError
When this method is called before a statepoint has been loaded
See also
--------
MGXS.get_condensed_xs(coarse_groups)
"""
if self.statepoint is None:
msg = 'Unable to get a condensed coarse group cross section ' \
'library since the statepoint has not yet been loaded'
raise ValueError(msg)
cv.check_type('coarse_groups', coarse_groups, openmc.mgxs.EnergyGroups)
cv.check_less_than('coarse groups', coarse_groups.num_groups,
self.num_groups, equality=True)
cv.check_value('upper coarse energy', coarse_groups.group_edges[-1],
[self.energy_groups.group_edges[-1]])
cv.check_value('lower coarse energy', coarse_groups.group_edges[0],
[self.energy_groups.group_edges[0]])
# Clone this Library to initialize the condensed version
condensed_library = copy.deepcopy(self)
condensed_library.energy_groups = coarse_groups
# Condense the MGXS for each domain and mgxs type
for domain in self.domains:
for mgxs_type in self.mgxs_types:
mgxs = condensed_library.get_mgxs(domain, mgxs_type)
condensed_mgxs = mgxs.get_condensed_xs(coarse_groups)
condensed_library.all_mgxs[domain.id][mgxs_type] = condensed_mgxs
return condensed_library
def get_subdomain_avg_library(self):
"""Construct a subdomain-averaged version of this library.
This routine averages each multi-group cross section across distribcell
instances. The method performs spatial homogenization to compute the
scalar flux-weighted average cross section across the subdomains.
NOTE: This method is only relevant for distribcell domain types and
simplys returns a deep copy of the library for all other domains types.
Returns
-------
Library
A new multi-group cross section library averaged across subdomains
Raises
------
ValueError
When this method is called before a statepoint has been loaded
See also
--------
MGXS.get_subdomain_avg_xs(subdomains)
"""
if self.statepoint is None:
msg = 'Unable to get a subdomain-averaged cross section ' \
'library since the statepoint has not yet been loaded'
raise ValueError(msg)
# Clone this Library to initialize the subdomain-averaged version
subdomain_avg_library = copy.deepcopy(self)
if subdomain_avg_library.domain_type == 'distribcell':
subdomain_avg_library.domain_type = 'cell'
else:
return subdomain_avg_library
# Subdomain average the MGXS for each domain and mgxs type
for domain in self.domains:
for mgxs_type in self.mgxs_types:
mgxs = subdomain_avg_library.get_mgxs(domain, mgxs_type)
avg_mgxs = mgxs.get_subdomain_avg_xs()
subdomain_avg_library.all_mgxs[domain.id][mgxs_type] = avg_mgxs
return subdomain_avg_library
def build_hdf5_store(self, filename='mgxs.h5', directory='mgxs',
subdomains='all', nuclides='all', xs_type='macro'):
"""Export the multi-group cross section library to an HDF5 binary file.
This method constructs an HDF5 file which stores the library's
multi-group cross section data. The data is stored in a hierarchy of
HDF5 groups from the domain type, domain id, subdomain id (for
distribcell domains), nuclides and cross section types. Two datasets for
the mean and standard deviation are stored for each subdomain entry in
the HDF5 file. The number of groups is stored as a file attribute.
NOTE: This requires the h5py Python package.
Parameters
----------
filename : str
Filename for the HDF5 file. Defaults to 'mgxs.h5'.
directory : str
Directory for the HDF5 file. Defaults to 'mgxs'.
subdomains : {'all', 'avg'}
Report all subdomains or the average of all subdomain cross sections
in the report. Defaults to 'all'.
nuclides : {'all', 'sum'}
The nuclides of the cross-sections to include in the report. This
may be a list of nuclide name strings (e.g., ['U-235', 'U-238']).
The special string 'all' will report the cross sections for all
nuclides in the spatial domain. The special string 'sum' will report
the cross sections summed over all nuclides. Defaults to 'all'.
xs_type: {'macro', 'micro'}
Store the macro or micro cross section in units of cm^-1 or barns.
Defaults to 'macro'.
Raises
------
ValueError
When this method is called before a statepoint has been loaded
See also
--------
MGXS.build_hdf5_store(filename, directory, xs_type)
"""
if self.statepoint is None:
msg = 'Unable to get a condensed coarse group cross section ' \
'library since a statepoint has not yet been loaded'
raise ValueError(msg)
cv.check_type('filename', filename, basestring)
cv.check_type('directory', directory, basestring)
import h5py
# Make directory if it does not exist
if not os.path.exists(directory):
os.makedirs(directory)
# Add an attribute for the number of energy groups to the HDF5 file
full_filename = os.path.join(directory, filename)
full_filename = full_filename.replace(' ', '-')
f = h5py.File(full_filename, 'w')
f.attrs["# groups"] = self.num_groups
f.close()
# Export MGXS for each domain and mgxs type to an HDF5 file
for domain in self.domains:
for mgxs_type in self.mgxs_types:
mgxs = self.all_mgxs[domain.id][mgxs_type]
if subdomains == 'avg':
mgxs = mgxs.get_subdomain_avg_xs()
mgxs.build_hdf5_store(filename, directory,
xs_type=xs_type, nuclides=nuclides)
def dump_to_file(self, filename='mgxs', directory='mgxs'):
"""Store this Library object in a pickle binary file.
Parameters
----------
filename : str
Filename for the pickle file. Defaults to 'mgxs'.
directory : str
Directory for the pickle file. Defaults to 'mgxs'.
See also
--------
Library.load_from_file(filename, directory)
"""
cv.check_type('filename', filename, basestring)
cv.check_type('directory', directory, basestring)
# Make directory if it does not exist
if not os.path.exists(directory):
os.makedirs(directory)
full_filename = os.path.join(directory, filename + '.pkl')
full_filename = full_filename.replace(' ', '-')
# Load and return pickled Library object
pickle.dump(self, open(full_filename, 'wb'))
@staticmethod
def load_from_file(filename='mgxs', directory='mgxs'):
"""Load a Library object from a pickle binary file.
Parameters
----------
filename : str
Filename for the pickle file. Defaults to 'mgxs'.
directory : str
Directory for the pickle file. Defaults to 'mgxs'.
Returns
-------
Library
A Library object loaded from the pickle binary file
See also
--------
Library.dump_to_file(mgxs_lib, filename, directory)
"""
cv.check_type('filename', filename, basestring)
cv.check_type('directory', directory, basestring)
# Make directory if it does not exist
if not os.path.exists(directory):
os.makedirs(directory)
full_filename = os.path.join(directory, filename + '.pkl')
full_filename = full_filename.replace(' ', '-')
# Load and return pickled Library object
return pickle.load(open(full_filename, 'rb'))

2277
openmc/mgxs/mgxs.py Normal file

File diff suppressed because it is too large Load diff

View file

@ -41,25 +41,32 @@ class Nuclide(object):
if xs is not None:
self.xs = xs
def __eq__(self, nuclide2):
# Check type
if not isinstance(nuclide2, Nuclide):
return False
# Check name
elif self._name != nuclide2._name:
return False
# Check xs
elif self._xs != nuclide2._xs:
return False
else:
def __eq__(self, other):
if isinstance(other, Nuclide):
if self._name != other._name:
return False
elif self._xs != other._xs:
return False
else:
return True
elif isinstance(other, basestring) and other == self.name:
return True
else:
return False
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self._name, self._xs))
def __repr__(self):
string = 'Nuclide - {0}\n'.format(self._name)
string += '{0: <16}{1}{2}\n'.format('\tXS', '=\t', self._xs)
if self._zaid is not None:
string += '{0: <16}{1}{2}\n'.format('\tZAID', '=\t', self._zaid)
return string
@property
def name(self):
return self._name
@ -85,11 +92,4 @@ class Nuclide(object):
@zaid.setter
def zaid(self, zaid):
check_type('zaid', zaid, Integral)
self._zaid = zaid
def __repr__(self):
string = 'Nuclide - {0}\n'.format(self._name)
string += '{0: <16}{1}{2}\n'.format('\tXS', '=\t', self._xs)
if self._zaid is not None:
string += '{0: <16}{1}{2}\n'.format('\tZAID', '=\t', self._zaid)
return string
self._zaid = zaid

View file

@ -144,7 +144,7 @@ class Plot(object):
AUTO_PLOT_ID += 1
else:
check_type('plot ID', plot_id, Integral)
check_greater_than('plot ID', plot_id, 0)
check_greater_than('plot ID', plot_id, 0, equality=True)
self._id = plot_id
@name.setter
@ -363,6 +363,9 @@ class PlotsFile(object):
"""
# Reset xml element tree
self._plots_file.clear()
self._create_plot_subelements()
# Clean the indentation in the file to be user-readable

View file

@ -213,6 +213,9 @@ class Intersection(Region):
def __init__(self, *nodes):
self.nodes = list(nodes)
def __str__(self):
return '(' + ' '.join(map(str, self.nodes)) + ')'
@property
def nodes(self):
return self._nodes
@ -222,9 +225,6 @@ class Intersection(Region):
check_type('nodes', nodes, Iterable, Region)
self._nodes = nodes
def __str__(self):
return '(' + ' '.join(map(str, self.nodes)) + ')'
class Union(Region):
"""Union of two or more regions.
@ -252,6 +252,9 @@ class Union(Region):
def __init__(self, *nodes):
self.nodes = list(nodes)
def __str__(self):
return '(' + ' | '.join(map(str, self.nodes)) + ')'
@property
def nodes(self):
return self._nodes
@ -261,9 +264,6 @@ class Union(Region):
check_type('nodes', nodes, Iterable, Region)
self._nodes = nodes
def __str__(self):
return '(' + ' | '.join(map(str, self.nodes)) + ')'
class Complement(Region):
"""Complement of a region.
@ -295,6 +295,9 @@ class Complement(Region):
def __init__(self, node):
self.node = node
def __str__(self):
return '~' + str(self.node)
@property
def node(self):
return self._node
@ -303,6 +306,3 @@ class Complement(Region):
def node(self, node):
check_type('node', node, Region)
self._node = node
def __str__(self):
return '~' + str(self.node)

View file

@ -1178,6 +1178,13 @@ class SettingsFile(object):
"""
# Reset xml element tree
self._settings_file.clear()
self._source_subelement = None
self._trigger_subelement = None
self._eigenvalue_subelement = None
self._source_element = None
self._create_eigenvalue_subelement()
self._create_source_subelement()
self._create_output_subelement()

View file

@ -1,4 +1,3 @@
import copy
import sys
import re
import numpy as np
@ -33,42 +32,42 @@ class StatePoint(object):
each batch
cmfd_src : ndarray
CMFD fission source distribution over all mesh cells and energy groups.
current_batch : int
current_batch : Integral
Number of batches simulated
date_and_time : str
Date and time when simulation began
entropy : ndarray
Shannon entropy of fission source at each batch
gen_per_batch : int
gen_per_batch : Integral
Number of fission generations per batch
global_tallies : ndarray of compound datatype
Global tallies for k-effective estimates and leakage. The compound
datatype has fields 'name', 'sum', 'sum_sq', 'mean', and 'std_dev'.
k_combined : list
Combined estimator for k-effective and its uncertainty
k_col_abs : float
k_col_abs : Real
Cross-product of collision and absorption estimates of k-effective
k_col_tra : float
k_col_tra : Real
Cross-product of collision and tracklength estimates of k-effective
k_abs_tra : float
k_abs_tra : Real
Cross-product of absorption and tracklength estimates of k-effective
k_generation : ndarray
Estimate of k-effective for each batch/generation
meshes : dict
Dictionary whose keys are mesh IDs and whose values are Mesh objects
n_batches : int
n_batches : Integral
Number of batches
n_inactive : int
n_inactive : Integral
Number of inactive batches
n_particles : int
n_particles : Integral
Number of particles per generation
n_realizations : int
n_realizations : Integral
Number of tally realizations
path : str
Working directory for simulation
run_mode : str
Simulation run mode, e.g. 'k-eigenvalue'
seed : int
seed : Integral
Pseudorandom number generator seed
source : ndarray of compound datatype
Array of source sites. The compound datatype has fields 'wgt', 'xyz',
@ -80,10 +79,10 @@ class StatePoint(object):
Dictionary whose keys are tally IDs and whose values are Tally objects
tallies_present : bool
Indicate whether user-defined tallies are present
version: tuple of int
version: tuple of Integral
Version of OpenMC
with_summary : bool
Indicate whether statepoint data has been linked against a summary file
summary : None or openmc.summary.Summary
A summary object if the statepoint has been linked with a summary file
"""
@ -109,7 +108,7 @@ class StatePoint(object):
# Set flags for what data has been read
self._meshes_read = False
self._tallies_read = False
self._with_summary = False
self._summary = False
self._global_tallies = None
def close(self):
@ -121,31 +120,19 @@ class StatePoint(object):
@property
def cmfd_balance(self):
if self.cmfd_on:
return self._f['cmfd/cmfd_balance'].value
else:
return None
return self._f['cmfd/cmfd_balance'].value if self.cmfd_on else None
@property
def cmfd_dominance(self):
if self.cmfd_on:
return self._f['cmfd/cmfd_dominance'].value
else:
return None
return self._f['cmfd/cmfd_dominance'].value if self.cmfd_on else None
@property
def cmfd_entropy(self):
if self.cmfd_on:
return self._f['cmfd/cmfd_entropy'].value
else:
return None
return self._f['cmfd/cmfd_entropy'].value if self.cmfd_on else None
@property
def cmfd_indices(self):
if self.cmfd_on:
return self._f['cmfd/indices'].value
else:
return None
return self._f['cmfd/indices'].value if self.cmfd_on else None
@property
def cmfd_src(self):
@ -157,10 +144,7 @@ class StatePoint(object):
@property
def cmfd_srccmp(self):
if self.cmfd_on:
return self._f['cmfd/cmfd_srccmp'].value
else:
return None
return self._f['cmfd/cmfd_srccmp'].value if self.cmfd_on else None
@property
def current_batch(self):
@ -328,10 +312,7 @@ class StatePoint(object):
@property
def source(self):
if self.source_present:
return self._f['source_bank'].value
else:
return None
return self._f['source_bank'].value if self.source_present else None
@property
def source_present(self):
@ -459,16 +440,20 @@ class StatePoint(object):
self._f['version_minor'].value,
self._f['version_release'].value)
@property
def summary(self):
return self._summary
@property
def with_summary(self):
return self._with_summary
return False if self.summary is None else True
def get_tally(self, scores=[], filters=[], nuclides=[],
name=None, id=None, estimator=None):
"""Finds and returns a Tally object with certain properties.
This routine searches the list of Tallies and returns the first Tally
found it finds which satisfies all of the input parameters.
found which satisfies all of the input parameters.
NOTE: The input parameters do not need to match the complete Tally
specification and may only represent a subset of the Tally's properties.
@ -482,7 +467,7 @@ class StatePoint(object):
A list of Nuclide objects (default is []).
name : str, optional
The name specified for the Tally (default is None).
id : int, optional
id : Integral, optional
The id specified for the Tally (default is None).
estimator: str, optional
The type of estimator ('tracklength', 'analog'; default is None).
@ -536,8 +521,16 @@ class StatePoint(object):
# Iterate over the Filters requested by the user
for filter in filters:
if filter not in test_tally.filters:
contains_filters = False
contains_filters = False
# Test if requested filter is a subset of any of the test
# tally's filters and if so continue to next filter
for test_filter in test_tally.filters:
if test_filter.is_subset(filter):
contains_filters = True
break
if not contains_filters:
break
if not contains_filters:
@ -624,4 +617,4 @@ class StatePoint(object):
material_ids.append(summary.materials[bin].id)
filter.bins = material_ids
self._with_summary = True
self._summary = summary

View file

@ -83,9 +83,8 @@ class Summary(object):
name, xs = sab_table.decode().split('.')
material.add_s_alpha_beta(name, xs)
# Set the Material's density to g/cm3 - this is what is used in
# OpenMC
material.set_density(density=density, units='g/cm3')
# Set the Material's density to atom/b-cm as used by OpenMC
material.set_density(density=density, units='atom/b-cm')
# Add all nuclides to the Material
for fullname, density in zip(nuclides, nuc_densities):

View file

@ -75,6 +75,22 @@ class Surface(object):
def __pos__(self):
return Halfspace(self, '+')
def __repr__(self):
string = 'Surface\n'
string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id)
string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name)
string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._type)
string += '{0: <16}{1}{2}\n'.format('\tBoundary', '=\t', self._boundary_type)
coeffs = '{0: <16}'.format('\tCoefficients') + '\n'
for coeff in self._coeffs:
coeffs += '{0: <16}{1}{2}\n'.format(coeff, '=\t', self._coeffs[coeff])
string += coeffs
return string
@property
def id(self):
return self._id
@ -103,7 +119,7 @@ class Surface(object):
AUTO_SURFACE_ID += 1
else:
check_type('surface ID', surface_id, Integral)
check_greater_than('surface ID', surface_id, 0)
check_greater_than('surface ID', surface_id, 0, equality=True)
self._id = surface_id
@name.setter
@ -120,22 +136,6 @@ class Surface(object):
check_value('boundary type', boundary_type, _BC_TYPES)
self._boundary_type = boundary_type
def __repr__(self):
string = 'Surface\n'
string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id)
string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name)
string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._type)
string += '{0: <16}{1}{2}\n'.format('\tBoundary', '=\t', self._boundary_type)
coeffs = '{0: <16}'.format('\tCoefficients') + '\n'
for coeff in self._coeffs:
coeffs += '{0: <16}{1}{2}\n'.format(coeff, '=\t', self._coeffs[coeff])
string += coeffs
return string
def create_xml_subelement(self):
element = ET.Element("surface")
element.set("id", str(self._id))

File diff suppressed because it is too large Load diff

View file

@ -58,6 +58,22 @@ class Trigger(object):
else:
return existing
def __eq__(self, other):
if str(self) == str(other):
return True
else:
return False
def __ne__(self, other):
return not self == other
def __repr__(self):
string = 'Trigger\n'
string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._trigger_type)
string += '{0: <16}{1}{2}\n'.format('\tThreshold', '=\t', self._threshold)
string += '{0: <16}{1}{2}\n'.format('\tScores', '=\t', self._scores)
return string
@property
def trigger_type(self):
return self._trigger_type
@ -102,13 +118,6 @@ class Trigger(object):
else:
self._scores.append(score)
def __repr__(self):
string = 'Trigger\n'
string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._trigger_type)
string += '{0: <16}{1}{2}\n'.format('\tThreshold', '=\t', self._threshold)
string += '{0: <16}{1}{2}\n'.format('\tScores', '=\t', self._scores)
return string
def get_trigger_xml(self, element):
"""Return XML representation of the trigger

View file

@ -73,6 +73,30 @@ class Cell(object):
self._translation = None
self._offsets = None
def __repr__(self):
string = 'Cell\n'
string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id)
string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name)
if isinstance(self._fill, openmc.Material):
string += '{0: <16}{1}{2}\n'.format('\tMaterial', '=\t',
self._fill._id)
elif isinstance(self._fill, (Universe, Lattice)):
string += '{0: <16}{1}{2}\n'.format('\tFill', '=\t',
self._fill._id)
else:
string += '{0: <16}{1}{2}\n'.format('\tFill', '=\t', self._fill)
string += '{0: <16}{1}{2}\n'.format('\tRegion', '=\t', self._region)
string += '{0: <16}{1}{2}\n'.format('\tRotation', '=\t',
self._rotation)
string += '{0: <16}{1}{2}\n'.format('\tTranslation', '=\t',
self._translation)
string += '{0: <16}{1}{2}\n'.format('\tOffset', '=\t', self._offsets)
return string
@property
def id(self):
return self._id
@ -120,7 +144,7 @@ class Cell(object):
AUTO_CELL_ID += 1
else:
cv.check_type('cell ID', cell_id, Integral)
cv.check_greater_than('cell ID', cell_id, 0)
cv.check_greater_than('cell ID', cell_id, 0, equality=True)
self._id = cell_id
@name.setter
@ -251,7 +275,7 @@ class Cell(object):
"""
nuclides = {}
nuclides = OrderedDict()
if self._type != 'void':
nuclides.update(self._fill.get_all_nuclides())
@ -269,13 +293,34 @@ class Cell(object):
"""
cells = {}
cells = OrderedDict()
if self._type == 'fill' or self._type == 'lattice':
cells.update(self._fill.get_all_cells())
return cells
def get_all_materials(self):
"""Return all materials that are contained within the cell
Returns
-------
materials : dict
Dictionary whose keys are material IDs and values are Material instances
"""
materials = OrderedDict()
if self.fill_type == 'material':
materials[self.fill.id] = self.fill
# Append all Cells in each Cell in the Universe to the dictionary
cells = self.get_all_cells()
for cell_id, cell in cells.items():
materials.update(cell.get_all_materials())
return materials
def get_all_universes(self):
"""Return all universes that are contained within this one if any of
its cells are filled with a universe or lattice.
@ -288,7 +333,7 @@ class Cell(object):
"""
universes = {}
universes = OrderedDict()
if self._type == 'fill':
universes[self._fill._id] = self._fill
@ -298,30 +343,6 @@ class Cell(object):
return universes
def __repr__(self):
string = 'Cell\n'
string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id)
string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name)
if isinstance(self._fill, openmc.Material):
string += '{0: <16}{1}{2}\n'.format('\tMaterial', '=\t',
self._fill._id)
elif isinstance(self._fill, (Universe, Lattice)):
string += '{0: <16}{1}{2}\n'.format('\tFill', '=\t',
self._fill._id)
else:
string += '{0: <16}{1}{2}\n'.format('\tFill', '=\t', self._fill)
string += '{0: <16}{1}{2}\n'.format('\tRegion', '=\t', self._region)
string += '{0: <16}{1}{2}\n'.format('\tRotation', '=\t',
self._rotation)
string += '{0: <16}{1}{2}\n'.format('\tTranslation', '=\t',
self._translation)
string += '{0: <16}{1}{2}\n'.format('\tOffset', '=\t', self._offsets)
return string
def create_xml_subelement(self, xml_element):
element = ET.Element("cell")
element.set("id", str(self._id))
@ -415,7 +436,7 @@ class Universe(object):
# Keys - Cell IDs
# Values - Cells
self._cells = {}
self._cells = OrderedDict()
# Keys - Cell IDs
# Values - Offsets
@ -442,7 +463,7 @@ class Universe(object):
AUTO_UNIVERSE_ID += 1
else:
cv.check_type('universe ID', universe_id, Integral)
cv.check_greater_than('universe ID', universe_id, 0, True)
cv.check_greater_than('universe ID', universe_id, 0, equality=True)
self._id = universe_id
@name.setter
@ -541,7 +562,7 @@ class Universe(object):
"""
nuclides = {}
nuclides = OrderedDict()
# Append all Nuclides in each Cell in the Universe to the dictionary
for cell_id, cell in self._cells.items():
@ -559,7 +580,7 @@ class Universe(object):
"""
cells = {}
cells = OrderedDict()
# Add this Universe's cells to the dictionary
cells.update(self._cells)
@ -570,6 +591,25 @@ class Universe(object):
return cells
def get_all_materials(self):
"""Return all materials that are contained within the universe
Returns
-------
materials : dict
Dictionary whose keys are material IDs and values are Material instances
"""
materials = OrderedDict()
# Append all Cells in each Cell in the Universe to the dictionary
cells = self.get_all_cells()
for cell_id, cell in cells.items():
materials.update(cell.get_all_materials())
return materials
def get_all_universes(self):
"""Return all universes that are contained within this one.
@ -584,7 +624,7 @@ class Universe(object):
# Get all Cells in this Universe
cells = self.get_all_cells()
universes = {}
universes = OrderedDict()
# Append all Universes containing each Cell to the dictionary
for cell_id, cell in cells.items():
@ -603,6 +643,7 @@ class Universe(object):
return string
def create_xml_subelement(self, xml_element):
# Iterate over all Cells
for cell_id, cell in self._cells.items():
@ -684,7 +725,7 @@ class Lattice(object):
AUTO_UNIVERSE_ID += 1
else:
cv.check_type('lattice ID', lattice_id, Integral)
cv.check_greater_than('lattice ID', lattice_id, 0)
cv.check_greater_than('lattice ID', lattice_id, 0, equality=True)
self._id = lattice_id
@name.setter
@ -717,7 +758,7 @@ class Lattice(object):
"""
univs = dict()
univs = OrderedDict()
for k in range(len(self._universes)):
for j in range(len(self._universes[k])):
if isinstance(self._universes[k][j], Universe):
@ -745,7 +786,7 @@ class Lattice(object):
"""
nuclides = {}
nuclides = OrderedDict()
# Get all unique Universes contained in each of the lattice cells
unique_universes = self.get_unique_universes()
@ -766,7 +807,7 @@ class Lattice(object):
"""
cells = {}
cells = OrderedDict()
unique_universes = self.get_unique_universes()
for universe_id, universe in unique_universes.items():
@ -774,6 +815,25 @@ class Lattice(object):
return cells
def get_all_materials(self):
"""Return all materials that are contained within the lattice
Returns
-------
materials : dict
Dictionary whose keys are material IDs and values are Material instances
"""
materials = OrderedDict()
# Append all Cells in each Cell in the Universe to the dictionary
cells = self.get_all_cells()
for cell_id, cell in cells.items():
materials.update(cell.get_all_materials())
return materials
def get_all_universes(self):
"""Return all universes that are contained within the lattice
@ -787,7 +847,7 @@ class Lattice(object):
# Initialize a dictionary of all Universes contained by the Lattice
# in each nested Universe level
all_universes = {}
all_universes = OrderedDict()
# Get all unique Universes contained in each of the lattice cells
unique_universes = self.get_unique_universes()
@ -836,6 +896,50 @@ class RectLattice(Lattice):
self._lower_left = None
self._offsets = None
def __repr__(self):
string = 'RectLattice\n'
string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id)
string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name)
string += '{0: <16}{1}{2}\n'.format('\tDimension', '=\t',
self._dimension)
string += '{0: <16}{1}{2}\n'.format('\tLower Left', '=\t',
self._lower_left)
string += '{0: <16}{1}{2}\n'.format('\tPitch', '=\t', self._pitch)
if self._outer is not None:
string += '{0: <16}{1}{2}\n'.format('\tOuter', '=\t',
self._outer._id)
else:
string += '{0: <16}{1}{2}\n'.format('\tOuter', '=\t',
self._outer)
string += '{0: <16}\n'.format('\tUniverses')
# Lattice nested Universe IDs - column major for Fortran
for i, universe in enumerate(np.ravel(self._universes)):
string += '{0} '.format(universe._id)
# Add a newline character every time we reach end of row of cells
if (i+1) % self._dimension[-1] == 0:
string += '\n'
string = string.rstrip('\n')
if self._offsets is not None:
string += '{0: <16}\n'.format('\tOffsets')
# Lattice cell offsets
for i, offset in enumerate(np.ravel(self._offsets)):
string += '{0} '.format(offset)
# Add a newline character when we reach end of row of cells
if (i+1) % self._dimension[-1] == 0:
string += '\n'
string = string.rstrip('\n')
return string
@property
def dimension(self):
return self._dimension
@ -893,51 +997,8 @@ class RectLattice(Lattice):
return offset
def __repr__(self):
string = 'RectLattice\n'
string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id)
string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name)
string += '{0: <16}{1}{2}\n'.format('\tDimension', '=\t',
self._dimension)
string += '{0: <16}{1}{2}\n'.format('\tLower Left', '=\t',
self._lower_left)
string += '{0: <16}{1}{2}\n'.format('\tPitch', '=\t', self._pitch)
if self._outer is not None:
string += '{0: <16}{1}{2}\n'.format('\tOuter', '=\t',
self._outer._id)
else:
string += '{0: <16}{1}{2}\n'.format('\tOuter', '=\t',
self._outer)
string += '{0: <16}\n'.format('\tUniverses')
# Lattice nested Universe IDs - column major for Fortran
for i, universe in enumerate(np.ravel(self._universes)):
string += '{0} '.format(universe._id)
# Add a newline character every time we reach end of row of cells
if (i+1) % self._dimension[-1] == 0:
string += '\n'
string = string.rstrip('\n')
if self._offsets is not None:
string += '{0: <16}\n'.format('\tOffsets')
# Lattice cell offsets
for i, offset in enumerate(np.ravel(self._offsets)):
string += '{0} '.format(offset)
# Add a newline character when we reach end of row of cells
if (i+1) % self._dimension[-1] == 0:
string += '\n'
string = string.rstrip('\n')
return string
def create_xml_subelement(self, xml_element):
# Determine if XML element already contains subelement for this Lattice
path = './lattice[@id=\'{0}\']'.format(self._id)
test = xml_element.find(path)
@ -1052,6 +1113,34 @@ class HexLattice(Lattice):
self._num_axial = None
self._center = None
def __repr__(self):
string = 'HexLattice\n'
string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id)
string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name)
string += '{0: <16}{1}{2}\n'.format('\t# Rings', '=\t', self._num_rings)
string += '{0: <16}{1}{2}\n'.format('\t# Axial', '=\t', self._num_axial)
string += '{0: <16}{1}{2}\n'.format('\tCenter', '=\t',
self._center)
string += '{0: <16}{1}{2}\n'.format('\tPitch', '=\t', self._pitch)
if self._outer is not None:
string += '{0: <16}{1}{2}\n'.format('\tOuter', '=\t',
self._outer._id)
else:
string += '{0: <16}{1}{2}\n'.format('\tOuter', '=\t',
self._outer)
string += '{0: <16}\n'.format('\tUniverses')
if self._num_axial is not None:
slices = [self._repr_axial_slice(x) for x in self._universes]
string += '\n'.join(slices)
else:
string += self._repr_axial_slice(self._universes)
return string
@property
def num_rings(self):
return self._num_rings
@ -1172,34 +1261,6 @@ class HexLattice(Lattice):
6*(self._num_rings - 1 - r))
raise ValueError(msg)
def __repr__(self):
string = 'HexLattice\n'
string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id)
string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name)
string += '{0: <16}{1}{2}\n'.format('\t# Rings', '=\t', self._num_rings)
string += '{0: <16}{1}{2}\n'.format('\t# Axial', '=\t', self._num_axial)
string += '{0: <16}{1}{2}\n'.format('\tCenter', '=\t',
self._center)
string += '{0: <16}{1}{2}\n'.format('\tPitch', '=\t', self._pitch)
if self._outer is not None:
string += '{0: <16}{1}{2}\n'.format('\tOuter', '=\t',
self._outer._id)
else:
string += '{0: <16}{1}{2}\n'.format('\tOuter', '=\t',
self._outer)
string += '{0: <16}\n'.format('\tUniverses')
if self._num_axial is not None:
slices = [self._repr_axial_slice(x) for x in self._universes]
string += '\n'.join(slices)
else:
string += self._repr_axial_slice(self._universes)
return string
def create_xml_subelement(self, xml_element):
# Determine if XML element already contains subelement for this Lattice
path = './hex_lattice[@id=\'{0}\']'.format(self._id)

View file

@ -11,7 +11,7 @@ except ImportError:
kwargs = {'name': 'openmc',
'version': '0.7.0',
'packages': ['openmc'],
'packages': ['openmc', 'openmc.mgxs'],
'scripts': glob.glob('scripts/openmc-*'),
# Metadata

View file

@ -0,0 +1 @@
7e5c0de6e50c494abeea443d74606db809d74ce8bb2571eb4e1c98b3c9a33885b0aef2a4a82b6f95a1725b078d4a5ff01f68e1cc72addbd2d6bd0fb8251ad2e7

View file

@ -0,0 +1,49 @@
material group in nuclide mean std. dev.
0 1 1 total 0.419289 0.01638 material group in nuclide mean std. dev.
0 1 1 total 0.07774 0.003273 material group in group out nuclide mean std. dev.
0 1 1 1 total 0.352665 0.015654 material group out nuclide mean std. dev.
0 1 1 total 1 0.119622 material group in nuclide mean std. dev.
0 2 1 total 0.247316 0.009562 material group in nuclide mean std. dev.
0 2 1 total 0 0 material group in group out nuclide mean std. dev.
0 2 1 1 total 0.244838 0.009996 material group out nuclide mean std. dev.
0 2 1 total 0 0 material group in nuclide mean std. dev.
0 3 1 total 0.409938 0.042262 material group in nuclide mean std. dev.
0 3 1 total 0 0 material group in group out nuclide mean std. dev.
0 3 1 1 total 0.403354 0.041386 material group out nuclide mean std. dev.
0 3 1 total 0 0 material group in nuclide mean std. dev.
0 4 1 total 0.344007 0.05352 material group in nuclide mean std. dev.
0 4 1 total 0 0 material group in group out nuclide mean std. dev.
0 4 1 1 total 0.340438 0.052067 material group out nuclide mean std. dev.
0 4 1 total 0 0 material group in nuclide mean std. dev.
0 5 1 total 0 0 material group in nuclide mean std. dev.
0 5 1 total 0 0 material group in group out nuclide mean std. dev.
0 5 1 1 total 0 0 material group out nuclide mean std. dev.
0 5 1 total 0 0 material group in nuclide mean std. dev.
0 6 1 total 0 0 material group in nuclide mean std. dev.
0 6 1 total 0 0 material group in group out nuclide mean std. dev.
0 6 1 1 total 0 0 material group out nuclide mean std. dev.
0 6 1 total 0 0 material group in nuclide mean std. dev.
0 7 1 total 0 0 material group in nuclide mean std. dev.
0 7 1 total 0 0 material group in group out nuclide mean std. dev.
0 7 1 1 total 0 0 material group out nuclide mean std. dev.
0 7 1 total 0 0 material group in nuclide mean std. dev.
0 8 1 total 0 0 material group in nuclide mean std. dev.
0 8 1 total 0 0 material group in group out nuclide mean std. dev.
0 8 1 1 total 0 0 material group out nuclide mean std. dev.
0 8 1 total 0 0 material group in nuclide mean std. dev.
0 9 1 total 0.751873 0.559701 material group in nuclide mean std. dev.
0 9 1 total 0 0 material group in group out nuclide mean std. dev.
0 9 1 1 total 0.695491 0.50757 material group out nuclide mean std. dev.
0 9 1 total 0 0 material group in nuclide mean std. dev.
0 10 1 total 0 0 material group in nuclide mean std. dev.
0 10 1 total 0 0 material group in group out nuclide mean std. dev.
0 10 1 1 total 0 0 material group out nuclide mean std. dev.
0 10 1 total 0 0 material group in nuclide mean std. dev.
0 11 1 total 0.457329 0.403578 material group in nuclide mean std. dev.
0 11 1 total 0 0 material group in group out nuclide mean std. dev.
0 11 1 1 total 0.446737 0.392775 material group out nuclide mean std. dev.
0 11 1 total 0 0 material group in nuclide mean std. dev.
0 12 1 total 0.574978 0.38864 material group in nuclide mean std. dev.
0 12 1 total 0 0 material group in group out nuclide mean std. dev.
0 12 1 1 total 0.559478 0.377512 material group out nuclide mean std. dev.
0 12 1 total 0 0

View file

@ -0,0 +1,85 @@
#!/usr/bin/env python
import os
import sys
import glob
import hashlib
sys.path.insert(0, os.pardir)
from testing_harness import PyAPITestHarness
import openmc
import openmc.mgxs
class MGXSTestHarness(PyAPITestHarness):
def _build_inputs(self):
# The openmc.mgxs module needs a summary.h5 file
self._input_set.settings.output = {'summary': True}
# Generate inputs using parent class routine
super(MGXSTestHarness, self)._build_inputs()
# Initialize a two-group structure
energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625e-6, 20.])
# Initialize MGXS Library for a few cross section types
self.mgxs_lib = openmc.mgxs.Library(self._input_set.geometry.geometry)
self.mgxs_lib.by_nuclide = False
self.mgxs_lib.mgxs_types = ['transport', 'nu-fission',
'nu-scatter matrix', 'chi']
self.mgxs_lib.energy_groups = energy_groups
self.mgxs_lib.domain_type = 'material'
self.mgxs_lib.build_library()
# Initialize a tallies file
self._input_set.tallies = openmc.TalliesFile()
self.mgxs_lib.add_to_tallies_file(self._input_set.tallies, merge=False)
self._input_set.tallies.export_to_xml()
def _get_results(self, hash_output=False):
"""Digest info in the statepoint and return as a string."""
# Read the statepoint file.
statepoint = glob.glob(os.path.join(os.getcwd(), self._sp_name))[0]
sp = openmc.StatePoint(statepoint)
# Read the summary file.
summary = glob.glob(os.path.join(os.getcwd(), 'summary.h5'))[0]
su = openmc.Summary(summary)
sp.link_with_summary(su)
# Load the MGXS library from the statepoint
self.mgxs_lib.load_from_statepoint(sp)
# Build a condensed 1-group MGXS Library
one_group = openmc.mgxs.EnergyGroups([0., 20.])
condense_lib = self.mgxs_lib.get_condensed_library(one_group)
# Build a string from Pandas Dataframe for each 1-group MGXS
outstr = ''
for domain in condense_lib.domains:
for mgxs_type in condense_lib.mgxs_types:
mgxs = condense_lib.get_mgxs(domain, mgxs_type)
df = mgxs.get_pandas_dataframe()
outstr += df.to_string()
print(outstr)
# Hash the results if necessary
if hash_output:
sha512 = hashlib.sha512()
sha512.update(outstr.encode('utf-8'))
outstr = sha512.hexdigest()
return outstr
def _cleanup(self):
super(MGXSTestHarness, self)._cleanup()
f = os.path.join(os.getcwd(), 'tallies.xml')
if os.path.exists(f): os.remove(f)
if __name__ == '__main__':
harness = MGXSTestHarness('statepoint.10.*', True)
harness.main()

View file

@ -0,0 +1 @@
7e5c0de6e50c494abeea443d74606db809d74ce8bb2571eb4e1c98b3c9a33885b0aef2a4a82b6f95a1725b078d4a5ff01f68e1cc72addbd2d6bd0fb8251ad2e7

View file

@ -0,0 +1,168 @@
domain=1 type=transport
[ 0.38437891 0.81208747]
[ 0.01648997 0.07418959]
domain=1 type=nu-fission
[ 0.02127008 0.69604034]
[ 0.0008939 0.05345764]
domain=1 type=nu-scatter matrix
[[ 3.49923892e-01 1.73140769e-04]
[ 1.94810926e-03 3.79607212e-01]]
[[ 0.01664928 0.0001732 ]
[ 0.00195193 0.04007819]]
domain=1 type=chi
[ 1. 0.]
[ 0.11962178 0. ]
domain=2 type=transport
[ 0.24504295 0.26645769]
[ 0.00882749 0.05220872]
domain=2 type=nu-fission
[ 0. 0.]
[ 0. 0.]
domain=2 type=nu-scatter matrix
[[ 0.24365718 0. ]
[ 0. 0.25478661]]
[[ 0.00908307 0. ]
[ 0. 0.05556256]]
domain=2 type=chi
[ 0. 0.]
[ 0. 0.]
domain=3 type=transport
[ 0.28227749 1.42731974]
[ 0.03724175 0.24712746]
domain=3 type=nu-fission
[ 0. 0.]
[ 0. 0.]
domain=3 type=nu-scatter matrix
[[ 0.25396726 0.02727268]
[ 0. 1.37652669]]
[[ 0.03617307 0.00180698]
[ 0. 0.2402569 ]]
domain=3 type=chi
[ 0. 0.]
[ 0. 0.]
domain=4 type=transport
[ 0.25572316 1.17976682]
[ 0.05191655 0.22938034]
domain=4 type=nu-fission
[ 0. 0.]
[ 0. 0.]
domain=4 type=nu-scatter matrix
[[ 0.23297756 0.02228141]
[ 0. 1.14680862]]
[[ 0.04977114 0.00262525]
[ 0. 0.22219839]]
domain=4 type=chi
[ 0. 0.]
[ 0. 0.]
domain=5 type=transport
[ 0. 0.]
[ 0. 0.]
domain=5 type=nu-fission
[ 0. 0.]
[ 0. 0.]
domain=5 type=nu-scatter matrix
[[ 0. 0.]
[ 0. 0.]]
[[ 0. 0.]
[ 0. 0.]]
domain=5 type=chi
[ 0. 0.]
[ 0. 0.]
domain=6 type=transport
[ 0. 0.]
[ 0. 0.]
domain=6 type=nu-fission
[ 0. 0.]
[ 0. 0.]
domain=6 type=nu-scatter matrix
[[ 0. 0.]
[ 0. 0.]]
[[ 0. 0.]
[ 0. 0.]]
domain=6 type=chi
[ 0. 0.]
[ 0. 0.]
domain=7 type=transport
[ 0. 0.]
[ 0. 0.]
domain=7 type=nu-fission
[ 0. 0.]
[ 0. 0.]
domain=7 type=nu-scatter matrix
[[ 0. 0.]
[ 0. 0.]]
[[ 0. 0.]
[ 0. 0.]]
domain=7 type=chi
[ 0. 0.]
[ 0. 0.]
domain=8 type=transport
[ 0. 0.]
[ 0. 0.]
domain=8 type=nu-fission
[ 0. 0.]
[ 0. 0.]
domain=8 type=nu-scatter matrix
[[ 0. 0.]
[ 0. 0.]]
[[ 0. 0.]
[ 0. 0.]]
domain=8 type=chi
[ 0. 0.]
[ 0. 0.]
domain=9 type=transport
[ 0.50403601 1.68709544]
[ 0.37962374 2.53662237]
domain=9 type=nu-fission
[ 0. 0.]
[ 0. 0.]
domain=9 type=nu-scatter matrix
[[ 0.50403601 0. ]
[ 0. 1.41795483]]
[[ 0.37962374 0. ]
[ 0. 2.15802716]]
domain=9 type=chi
[ 0. 0.]
[ 0. 0.]
domain=10 type=transport
[ 0. 0.]
[ 0. 0.]
domain=10 type=nu-fission
[ 0. 0.]
[ 0. 0.]
domain=10 type=nu-scatter matrix
[[ 0. 0.]
[ 0. 0.]]
[[ 0. 0.]
[ 0. 0.]]
domain=10 type=chi
[ 0. 0.]
[ 0. 0.]
domain=11 type=transport
[ 0.30282618 1.00614519]
[ 0.40131081 1.09163785]
domain=11 type=nu-fission
[ 0. 0.]
[ 0. 0.]
domain=11 type=nu-scatter matrix
[[ 0.27567871 0.02714747]
[ 0. 0.95792921]]
[[ 0.38567601 0.02000859]
[ 0. 1.05195936]]
domain=11 type=chi
[ 0. 0.]
[ 0. 0.]
domain=12 type=transport
[ 0.25593293 1.11334475]
[ 0.26842571 0.98867569]
domain=12 type=nu-fission
[ 0. 0.]
[ 0. 0.]
domain=12 type=nu-scatter matrix
[[ 0.22631045 0.02962248]
[ 0. 1.07168976]]
[[ 0.25487194 0.0177599 ]
[ 0. 0.95829029]]
domain=12 type=chi
[ 0. 0.]
[ 0. 0.]

View file

@ -0,0 +1,93 @@
#!/usr/bin/env python
import os
import sys
import glob
import hashlib
import h5py
sys.path.insert(0, os.pardir)
from testing_harness import PyAPITestHarness
import openmc
import openmc.mgxs
class MGXSTestHarness(PyAPITestHarness):
def _build_inputs(self):
# The openmc.mgxs module needs a summary.h5 file
self._input_set.settings.output = {'summary': True}
# Generate inputs using parent class routine
super(MGXSTestHarness, self)._build_inputs()
# Initialize a two-group structure
energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625e-6, 20.])
# Initialize MGXS Library for a few cross section types
self.mgxs_lib = openmc.mgxs.Library(self._input_set.geometry.geometry)
self.mgxs_lib.by_nuclide = False
self.mgxs_lib.mgxs_types = ['transport', 'nu-fission',
'nu-scatter matrix', 'chi']
self.mgxs_lib.energy_groups = energy_groups
self.mgxs_lib.domain_type = 'material'
self.mgxs_lib.build_library()
# Initialize a tallies file
self._input_set.tallies = openmc.TalliesFile()
self.mgxs_lib.add_to_tallies_file(self._input_set.tallies, merge=False)
self._input_set.tallies.export_to_xml()
def _get_results(self, hash_output=False):
"""Digest info in the statepoint and return as a string."""
# Read the statepoint file.
statepoint = glob.glob(os.path.join(os.getcwd(), self._sp_name))[0]
sp = openmc.StatePoint(statepoint)
# Read the summary file.
summary = glob.glob(os.path.join(os.getcwd(), 'summary.h5'))[0]
su = openmc.Summary(summary)
sp.link_with_summary(su)
# Load the MGXS library from the statepoint
self.mgxs_lib.load_from_statepoint(sp)
# Export the MGXS Library to an HDF5 file
self.mgxs_lib.build_hdf5_store(directory='.')
# Open the MGXS HDF5 file
f = h5py.File('mgxs.h5', 'r')
# Build a string from the datasets in the HDF5 file
outstr = ''
for domain in self.mgxs_lib.domains:
for mgxs_type in self.mgxs_lib.mgxs_types:
outstr += 'domain={0} type={1}\n'.format(domain.id, mgxs_type)
key = 'material/{0}/{1}/average'.format(domain.id, mgxs_type)
outstr += str(f[key][...]) + '\n'
key = 'material/{0}/{1}/std. dev.'.format(domain.id, mgxs_type)
outstr += str(f[key][...]) + '\n'
# Close the MGXS HDF5 file
f.close()
# Hash the results if necessary
if hash_output:
sha512 = hashlib.sha512()
sha512.update(outstr.encode('utf-8'))
outstr = sha512.hexdigest()
return outstr
def _cleanup(self):
super(MGXSTestHarness, self)._cleanup()
f = os.path.join(os.getcwd(), 'tallies.xml')
if os.path.exists(f): os.remove(f)
f = os.path.join(os.getcwd(), 'mgxs.h5')
if os.path.exists(f): os.remove(f)
if __name__ == '__main__':
harness = MGXSTestHarness('statepoint.10.*', True)
harness.main()

View file

@ -0,0 +1 @@
7e5c0de6e50c494abeea443d74606db809d74ce8bb2571eb4e1c98b3c9a33885b0aef2a4a82b6f95a1725b078d4a5ff01f68e1cc72addbd2d6bd0fb8251ad2e7

View file

@ -0,0 +1,121 @@
material group in nuclide mean std. dev.
1 1 1 total 0.384379 0.01649
0 1 2 total 0.812087 0.07419 material group in nuclide mean std. dev.
1 1 1 total 0.02127 0.000894
0 1 2 total 0.69604 0.053458 material group in group out nuclide mean std. dev.
3 1 1 1 total 0.349924 0.016649
2 1 1 2 total 0.000173 0.000173
1 1 2 1 total 0.001948 0.001952
0 1 2 2 total 0.379607 0.040078 material group out nuclide mean std. dev.
1 1 1 total 1 0.119622
0 1 2 total 0 0.000000 material group in nuclide mean std. dev.
1 2 1 total 0.245043 0.008827
0 2 2 total 0.266458 0.052209 material group in nuclide mean std. dev.
1 2 1 total 0 0
0 2 2 total 0 0 material group in group out nuclide mean std. dev.
3 2 1 1 total 0.243657 0.009083
2 2 1 2 total 0.000000 0.000000
1 2 2 1 total 0.000000 0.000000
0 2 2 2 total 0.254787 0.055563 material group out nuclide mean std. dev.
1 2 1 total 0 0
0 2 2 total 0 0 material group in nuclide mean std. dev.
1 3 1 total 0.282277 0.037242
0 3 2 total 1.427320 0.247127 material group in nuclide mean std. dev.
1 3 1 total 0 0
0 3 2 total 0 0 material group in group out nuclide mean std. dev.
3 3 1 1 total 0.253967 0.036173
2 3 1 2 total 0.027273 0.001807
1 3 2 1 total 0.000000 0.000000
0 3 2 2 total 1.376527 0.240257 material group out nuclide mean std. dev.
1 3 1 total 0 0
0 3 2 total 0 0 material group in nuclide mean std. dev.
1 4 1 total 0.255723 0.051917
0 4 2 total 1.179767 0.229380 material group in nuclide mean std. dev.
1 4 1 total 0 0
0 4 2 total 0 0 material group in group out nuclide mean std. dev.
3 4 1 1 total 0.232978 0.049771
2 4 1 2 total 0.022281 0.002625
1 4 2 1 total 0.000000 0.000000
0 4 2 2 total 1.146809 0.222198 material group out nuclide mean std. dev.
1 4 1 total 0 0
0 4 2 total 0 0 material group in nuclide mean std. dev.
1 5 1 total 0 0
0 5 2 total 0 0 material group in nuclide mean std. dev.
1 5 1 total 0 0
0 5 2 total 0 0 material group in group out nuclide mean std. dev.
3 5 1 1 total 0 0
2 5 1 2 total 0 0
1 5 2 1 total 0 0
0 5 2 2 total 0 0 material group out nuclide mean std. dev.
1 5 1 total 0 0
0 5 2 total 0 0 material group in nuclide mean std. dev.
1 6 1 total 0 0
0 6 2 total 0 0 material group in nuclide mean std. dev.
1 6 1 total 0 0
0 6 2 total 0 0 material group in group out nuclide mean std. dev.
3 6 1 1 total 0 0
2 6 1 2 total 0 0
1 6 2 1 total 0 0
0 6 2 2 total 0 0 material group out nuclide mean std. dev.
1 6 1 total 0 0
0 6 2 total 0 0 material group in nuclide mean std. dev.
1 7 1 total 0 0
0 7 2 total 0 0 material group in nuclide mean std. dev.
1 7 1 total 0 0
0 7 2 total 0 0 material group in group out nuclide mean std. dev.
3 7 1 1 total 0 0
2 7 1 2 total 0 0
1 7 2 1 total 0 0
0 7 2 2 total 0 0 material group out nuclide mean std. dev.
1 7 1 total 0 0
0 7 2 total 0 0 material group in nuclide mean std. dev.
1 8 1 total 0 0
0 8 2 total 0 0 material group in nuclide mean std. dev.
1 8 1 total 0 0
0 8 2 total 0 0 material group in group out nuclide mean std. dev.
3 8 1 1 total 0 0
2 8 1 2 total 0 0
1 8 2 1 total 0 0
0 8 2 2 total 0 0 material group out nuclide mean std. dev.
1 8 1 total 0 0
0 8 2 total 0 0 material group in nuclide mean std. dev.
1 9 1 total 0.504036 0.379624
0 9 2 total 1.687095 2.536622 material group in nuclide mean std. dev.
1 9 1 total 0 0
0 9 2 total 0 0 material group in group out nuclide mean std. dev.
3 9 1 1 total 0.504036 0.379624
2 9 1 2 total 0.000000 0.000000
1 9 2 1 total 0.000000 0.000000
0 9 2 2 total 1.417955 2.158027 material group out nuclide mean std. dev.
1 9 1 total 0 0
0 9 2 total 0 0 material group in nuclide mean std. dev.
1 10 1 total 0 0
0 10 2 total 0 0 material group in nuclide mean std. dev.
1 10 1 total 0 0
0 10 2 total 0 0 material group in group out nuclide mean std. dev.
3 10 1 1 total 0 0
2 10 1 2 total 0 0
1 10 2 1 total 0 0
0 10 2 2 total 0 0 material group out nuclide mean std. dev.
1 10 1 total 0 0
0 10 2 total 0 0 material group in nuclide mean std. dev.
1 11 1 total 0.302826 0.401311
0 11 2 total 1.006145 1.091638 material group in nuclide mean std. dev.
1 11 1 total 0 0
0 11 2 total 0 0 material group in group out nuclide mean std. dev.
3 11 1 1 total 0.275679 0.385676
2 11 1 2 total 0.027147 0.020009
1 11 2 1 total 0.000000 0.000000
0 11 2 2 total 0.957929 1.051959 material group out nuclide mean std. dev.
1 11 1 total 0 0
0 11 2 total 0 0 material group in nuclide mean std. dev.
1 12 1 total 0.255933 0.268426
0 12 2 total 1.113345 0.988676 material group in nuclide mean std. dev.
1 12 1 total 0 0
0 12 2 total 0 0 material group in group out nuclide mean std. dev.
3 12 1 1 total 0.226310 0.254872
2 12 1 2 total 0.029622 0.017760
1 12 2 1 total 0.000000 0.000000
0 12 2 2 total 1.071690 0.958290 material group out nuclide mean std. dev.
1 12 1 total 0 0
0 12 2 total 0 0

View file

@ -0,0 +1,79 @@
#!/usr/bin/env python
import os
import sys
import glob
import hashlib
sys.path.insert(0, os.pardir)
from testing_harness import PyAPITestHarness
import openmc
import openmc.mgxs
class MGXSTestHarness(PyAPITestHarness):
def _build_inputs(self):
# The openmc.mgxs module needs a summary.h5 file
self._input_set.settings.output = {'summary': True}
# Generate inputs using parent class routine
super(MGXSTestHarness, self)._build_inputs()
# Initialize a two-group structure
energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625e-6, 20.])
# Initialize MGXS Library for a few cross section types
self.mgxs_lib = openmc.mgxs.Library(self._input_set.geometry.geometry)
self.mgxs_lib.by_nuclide = False
self.mgxs_lib.mgxs_types = ['transport', 'nu-fission',
'nu-scatter matrix', 'chi']
self.mgxs_lib.energy_groups = energy_groups
self.mgxs_lib.domain_type = 'material'
self.mgxs_lib.build_library()
# Initialize a tallies file
self._input_set.tallies = openmc.TalliesFile()
self.mgxs_lib.add_to_tallies_file(self._input_set.tallies, merge=False)
self._input_set.tallies.export_to_xml()
def _get_results(self, hash_output=False):
"""Digest info in the statepoint and return as a string."""
# Read the statepoint file.
statepoint = glob.glob(os.path.join(os.getcwd(), self._sp_name))[0]
sp = openmc.StatePoint(statepoint)
# Read the summary file.
summary = glob.glob(os.path.join(os.getcwd(), 'summary.h5'))[0]
su = openmc.Summary(summary)
sp.link_with_summary(su)
# Load the MGXS library from the statepoint
self.mgxs_lib.load_from_statepoint(sp)
# Build a string from Pandas Dataframe for each MGXS
outstr = ''
for domain in self.mgxs_lib.domains:
for mgxs_type in self.mgxs_lib.mgxs_types:
mgxs = self.mgxs_lib.get_mgxs(domain, mgxs_type)
df = mgxs.get_pandas_dataframe()
outstr += df.to_string()
# Hash the results if necessary
if hash_output:
sha512 = hashlib.sha512()
sha512.update(outstr.encode('utf-8'))
outstr = sha512.hexdigest()
return outstr
def _cleanup(self):
super(MGXSTestHarness, self)._cleanup()
f = os.path.join(os.getcwd(), 'tallies.xml')
if os.path.exists(f): os.remove(f)
if __name__ == '__main__':
harness = MGXSTestHarness('statepoint.10.*', True)
harness.main()

View file

@ -0,0 +1 @@
04dcfca7d68981d7ec19d428c541acd6345ec2d608c581d56ce21d23548f52977fe713b5cdd7434bebf62067444d6562ef322175736a6a63e3985e5e48718081

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,79 @@
#!/usr/bin/env python
import os
import sys
import glob
import hashlib
sys.path.insert(0, os.pardir)
from testing_harness import PyAPITestHarness
import openmc
import openmc.mgxs
class MGXSTestHarness(PyAPITestHarness):
def _build_inputs(self):
# The openmc.mgxs module needs a summary.h5 file
self._input_set.settings.output = {'summary': True}
# Generate inputs using parent class routine
super(MGXSTestHarness, self)._build_inputs()
# Initialize a two-group structure
energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625e-6, 20.])
# Initialize MGXS Library for a few cross section types
self.mgxs_lib = openmc.mgxs.Library(self._input_set.geometry.geometry)
self.mgxs_lib.by_nuclide = True
self.mgxs_lib.mgxs_types = ['transport', 'nu-fission',
'nu-scatter matrix', 'chi']
self.mgxs_lib.energy_groups = energy_groups
self.mgxs_lib.domain_type = 'material'
self.mgxs_lib.build_library()
# Initialize a tallies file
self._input_set.tallies = openmc.TalliesFile()
self.mgxs_lib.add_to_tallies_file(self._input_set.tallies, merge=False)
self._input_set.tallies.export_to_xml()
def _get_results(self, hash_output=False):
"""Digest info in the statepoint and return as a string."""
# Read the statepoint file.
statepoint = glob.glob(os.path.join(os.getcwd(), self._sp_name))[0]
sp = openmc.StatePoint(statepoint)
# Read the summary file.
summary = glob.glob(os.path.join(os.getcwd(), 'summary.h5'))[0]
su = openmc.Summary(summary)
sp.link_with_summary(su)
# Load the MGXS library from the statepoint
self.mgxs_lib.load_from_statepoint(sp)
# Build a string from Pandas Dataframe for each MGXS
outstr = ''
for domain in self.mgxs_lib.domains:
for mgxs_type in self.mgxs_lib.mgxs_types:
mgxs = self.mgxs_lib.get_mgxs(domain, mgxs_type)
df = mgxs.get_pandas_dataframe()
outstr += df.to_string()
# Hash the results if necessary
if hash_output:
sha512 = hashlib.sha512()
sha512.update(outstr.encode('utf-8'))
outstr = sha512.hexdigest()
return outstr
def _cleanup(self):
super(MGXSTestHarness, self)._cleanup()
f = os.path.join(os.getcwd(), 'tallies.xml')
if os.path.exists(f): os.remove(f)
if __name__ == '__main__':
harness = MGXSTestHarness('statepoint.10.*', True)
harness.main()

View file

@ -339,6 +339,9 @@ class PyAPITestHarness(TestHarness):
"""Make sure the current inputs agree with the _true standard."""
compare = filecmp.cmp('inputs_test.dat', 'inputs_true.dat')
if not compare:
f = open('inputs_test.dat')
for line in f.readlines(): print(line)
f.close()
os.rename('inputs_test.dat', 'inputs_error.dat')
assert compare, 'Input files are broken.'
@ -349,6 +352,7 @@ class PyAPITestHarness(TestHarness):
output.append(os.path.join(os.getcwd(), 'geometry.xml'))
output.append(os.path.join(os.getcwd(), 'settings.xml'))
output.append(os.path.join(os.getcwd(), 'inputs_test.dat'))
output.append(os.path.join(os.getcwd(), 'summary.h5'))
for f in output:
if os.path.exists(f):
os.remove(f)