Merge branch 'multipole' into diff_tally5

This commit is contained in:
Sterling Harper 2016-05-19 21:39:06 -04:00
commit f303b3ed8d
131 changed files with 11847 additions and 9138 deletions

View file

@ -0,0 +1,6 @@
{{ fullname }}
{{ underline }}
.. currentmodule:: {{ module }}
.. autofunction:: {{ objname }}

View file

@ -13,11 +13,14 @@ OpenMC was originally developed by members of the `Computational Reactor Physics
Group`_ at the `Massachusetts Institute of Technology`_ starting
in 2011. Various universities, laboratories, and other organizations now
contribute to the development of OpenMC. For more information on OpenMC, feel
free to send a message to the User's Group `mailing list`_.
free to send a message to the User's Group `mailing list`_. Documentation for
the latest developmental version of the develop branch can be found on
`Read the Docs`_.
.. _Computational Reactor Physics Group: http://crpg.mit.edu
.. _Massachusetts Institute of Technology: http://web.mit.edu
.. _mailing list: https://groups.google.com/forum/?fromgroups=#!forum/openmc-users
.. _Read the Docs: http://openmc.readthedocs.io/en/latest/
.. only:: html
@ -34,6 +37,7 @@ free to send a message to the User's Group `mailing list`_.
usersguide/index
devguide/index
pythonapi/index
io_formats/index
publications
license
developers

View file

@ -0,0 +1,92 @@
.. _io_data_wmp:
==========================================
The Windowed Multipole Library Format v0.2
==========================================
**/nuclide/**
- **broaden_poly** (*int[]*)
If 1, Doppler broaden curve fit for window with corresponding index.
If 0, do not.
- **curvefit** (*double[][][]*)
Curve fit coefficients. Indexed by (reaction type, coefficient index,
window index).
- **data** (*complex[][]*)
Complex poles and residues. Each pole has a corresponding set of
residues. For example, the `i`th pole and corresponding residues are
stored as `data[:,i] = [pole, residue_1, residue_2, ...]`. The
residues are in the order: total, competitive if present, absorption,
fission. Complex numbers are stored by forming a type with `"r"` and
`"i"` identifiers, similar to how `h5py` does it.
- **start_E** (*double*)
Lowest energy the windowed multipole part of the library is valid for.
- **end_E** (*double*)
Highest energy the windowed multipole part of the library is valid for.
- **energy_points** (*double[]*)
Energy grid for the pointwise library in the reaction group.
- **fissionable** (*int*)
1 if this nuclide has fission data. 0 if it does not.
- **fit_order** (*int*)
The order of the curve fit.
- **formalism** (*int*)
The formalism of the underlying data. Uses the `ENDF-6`_ format
formalism numbers.
.. table:: Table of supported formalisms.
+-------------+------------------+
| Formalism | Formalism number |
+=============+==================+
| MLBW | 2 |
+-------------+------------------+
| Reich-Moore | 3 |
+-------------+------------------+
- **l_value** (*int[]*)
The index for a corresponding pole. Equivalent to the :math:`l` quantum
number of the resonance the pole comes from :math:`+1`.
- **length** (*int*)
Total count of poles in `data`.
- **max_w** (*int*)
Maximum number of poles in a window.
- **MT_count** (*int*)
Number of pointwise tables in the library.
- **MT_list** (*int[]*)
A list of available MT identifiers. See `ENDF-6`_ for meaning.
- **n_grid** (*int*)
Total length of the pointwise data.
- **num_l** (*int*)
Number of possible :math:`l` quantum states for this nuclide.
- **pseudo_K0RS** (*double[]*)
:math:`l` dependent value of
.. math::
\sqrt{\frac{2 m_n}{\hbar}}\frac{AWR}{AWR + 1} r_{s,l}
Where :math:`m_n` is mass of neutron, :math:`AWR` is the atomic weight
ratio of the target to the neutron, and :math:`r_{s,l}` is the
scattering radius for a given :math:`l`.
- **spacing** (*double*)
.. math::
\frac{\sqrt{E_{max}}- \sqrt{E_{min}}}{n_w}
Where :math:`E_{max}` is the maximum energy the windows go up to. This
is not equivalent to the maximum energy for which the windowed multipole
data is valid for. It is slightly higher to ensure an integer number of
windows. :math:`E_{min}` is the minimum energy and equivalent to
`start_E`, and :math:`n_w` is the number of windows, given by `windows`.
- **sqrtAWR** (*double*)
Square root of the atomic weight ratio.
- **w_start** (*int[]*)
The pole to start from for each window.
- **w_end** (*int[]*)
The pole to end at for each window.
- **windows** (*int*)
Number of windows.
**/nuclide/reactions/MT<i>**
- **MT_sigma** (*double[]*) -- Cross section value for this reaction.
- **Q_value** (*double*) -- Energy released in this reaction, in eV.
- **threshold** (*int*) -- The first non-zero entry in `MT_sigma`.
.. _ENDF-6: https://www.oecd-nea.org/dbdata/data/manual-endf/endf102.pdf

View file

@ -1,13 +1,15 @@
.. _usersguide_output:
.. _io_file_formats:
===================
Output File Formats
===================
===============
IO File Formats
===============
.. toctree::
:numbered:
:maxdepth: 3
data_wmp
mgxs_library
statepoint
source
summary

View file

@ -1,4 +1,4 @@
.. _usersguide_mgxs_library:
.. _io_mgxs_library:
========================================
Multi-Group Cross Section Library Format
@ -8,10 +8,10 @@ OpenMC can be run in continuous-energy mode or multi-group mode, provided the
nuclear data is available. In continuous-energy mode, the
``cross_sections.xml`` file contains necessary meta-data for each data set,
including the name and a file system location where the complete library
can be found. In multi-group mode, this ``cross_sections.xml`` file contains
can be found. In multi-group mode, this ``mgxs.xml`` file contains
this same meta-data describing the nuclide or material, but also contains the
group-wise nuclear data. This portion of the manual describes the format of
the multi-group data library required to be used in the ``cross_sections.xml``
the multi-group data library required to be used in the ``mgxs.xml``
file.
Similar to the other input file types, the multi-group library is provided in
@ -22,9 +22,9 @@ materials.
.. _XML: http://www.w3.org/XML/
------------------------------------------------
MGXS Library Specification -- cross_sections.xml
------------------------------------------------
--------------------------------------
MGXS Library Specification -- mgxs.xml
--------------------------------------
The multi-group library meta-data is contained within the groups_,
group_structure_, and inverse_velocities_ elements.
@ -33,7 +33,7 @@ The actual multi-group data itself is contained within the xsdata_ element.
.. _groups:
``<groups>`` Element
----------------------------------
--------------------
The ``<groups>`` element has no attributes and simply provides the number of
energy groups contained within the library.

View file

@ -1,4 +1,4 @@
.. _usersguide_particle_restart:
.. _io_particle_restart:
============================
Particle Restart File Format

View file

@ -1,4 +1,4 @@
.. _usersguide_source:
.. _io_source:
==================
Source File Format

View file

@ -1,4 +1,4 @@
.. _usersguide_statepoint:
.. _io_statepoint:
=======================
State Point File Format

View file

@ -1,4 +1,4 @@
.. _usersguide_summary:
.. _io_summary:
===================
Summary File Format

View file

@ -1,4 +1,4 @@
.. _usersguide_track:
.. _io_track:
=================
Track File Format

View file

@ -1,4 +1,4 @@
.. _usersguide_voxel:
.. _io_voxel:
======================
Voxel Plot File Format

View file

@ -4,7 +4,7 @@
License Agreement
=================
Copyright © 2011-2015 Massachusetts Institute of Technology
Copyright © 2011-2016 Massachusetts Institute of Technology
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

View file

@ -136,6 +136,9 @@ Note that the implementation of WMP in OpenMC currently assumes that inelastic
scattering does not occur in the resolved resonance region. This is usually,
but not always the case. Future library versions may eliminate this issue.
The data format used by OpenMC to represent windowed multipole data is specified
in :ref:`io_data_wmp`
.. only:: html
.. rubric:: References

View file

@ -201,7 +201,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"With our material, we can now create a `MaterialsFile` object that can be exported to an actual XML file."
"With our material, we can now create a `Materials` object that can be exported to an actual XML file."
]
},
{
@ -212,10 +212,9 @@
},
"outputs": [],
"source": [
"# Instantiate a MaterialsFile, register all Materials, and export to XML\n",
"materials_file = openmc.MaterialsFile()\n",
"# Instantiate a Materials collection and export to XML\n",
"materials_file = openmc.Materials([inf_medium])\n",
"materials_file.default_xs = '71c'\n",
"materials_file.add_material(inf_medium)\n",
"materials_file.export_to_xml()"
]
},
@ -290,7 +289,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"We now must create a geometry that is assigned a root universe, put the geometry into a `GeometryFile` object, and export it to XML."
"We now must create a geometry that is assigned a root universe and export it to XML."
]
},
{
@ -305,12 +304,8 @@
"openmc_geometry = openmc.Geometry()\n",
"openmc_geometry.root_universe = root_universe\n",
"\n",
"# Instantiate a GeometryFile\n",
"geometry_file = openmc.GeometryFile()\n",
"geometry_file.geometry = openmc_geometry\n",
"\n",
"# Export to \"geometry.xml\"\n",
"geometry_file.export_to_xml()"
"openmc_geometry.export_to_xml()"
]
},
{
@ -333,8 +328,8 @@
"inactive = 10\n",
"particles = 2500\n",
"\n",
"# Instantiate a SettingsFile\n",
"settings_file = openmc.SettingsFile()\n",
"# Instantiate a Settings object\n",
"settings_file = openmc.Settings()\n",
"settings_file.batches = batches\n",
"settings_file.inactive = inactive\n",
"settings_file.particles = particles\n",
@ -377,10 +372,12 @@
"\n",
"* `TotalXS`\n",
"* `TransportXS`\n",
"* `NuTransportXS`\n",
"* `AbsorptionXS`\n",
"* `CaptureXS`\n",
"* `FissionXS`\n",
"* `NuFissionXS`\n",
"* `KappaFissionXS`\n",
"* `ScatterXS`\n",
"* `NuScatterXS`\n",
"* `ScatterMatrixXS`\n",
@ -399,9 +396,9 @@
"outputs": [],
"source": [
"# Instantiate a few different sections\n",
"total = mgxs.TotalXS(domain=cell, domain_type='cell', groups=groups)\n",
"absorption = mgxs.AbsorptionXS(domain=cell, domain_type='cell', groups=groups)\n",
"scattering = mgxs.ScatterXS(domain=cell, domain_type='cell', groups=groups)"
"total = mgxs.TotalXS(domain=cell, groups=groups)\n",
"absorption = mgxs.AbsorptionXS(domain=cell, groups=groups)\n",
"scattering = mgxs.ScatterXS(domain=cell, groups=groups)"
]
},
{
@ -455,7 +452,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"The `Absorption` object includes tracklength tallies for the 'absorption' and 'flux' scores in the 2-group structure in cell 1. Now that each `MGXS` object contains the tallies that it needs, we must add these tallies to a `TalliesFile` object to generate the \"tallies.xml\" input file for OpenMC."
"The `Absorption` object includes tracklength tallies for the 'absorption' and 'flux' scores in the 2-group structure in cell 1. Now that each `MGXS` object contains the tallies that it needs, we must add these tallies to a `Tallies` object to generate the \"tallies.xml\" input file for OpenMC."
]
},
{
@ -466,21 +463,18 @@
},
"outputs": [],
"source": [
"# Instantiate an empty TalliesFile\n",
"tallies_file = openmc.TalliesFile()\n",
"# Instantiate an empty Tallies object\n",
"tallies_file = openmc.Tallies()\n",
"\n",
"# Add total tallies to the tallies file\n",
"for tally in total.tallies.values():\n",
" tallies_file.add_tally(tally)\n",
"tallies_file += total.tallies.values()\n",
"\n",
"# Add absorption tallies to the tallies file\n",
"for tally in absorption.tallies.values():\n",
" tallies_file.add_tally(tally)\n",
"tallies_file += absorption.tallies.values()\n",
"\n",
"# Add scattering tallies to the tallies file\n",
"for tally in scattering.tallies.values():\n",
" tallies_file.add_tally(tally)\n",
" \n",
"tallies_file += scattering.tallies.values()\n",
"\n",
"# Export to \"tallies.xml\"\n",
"tallies_file.export_to_xml()"
]
@ -516,11 +510,11 @@
" 888\n",
" 888\n",
"\n",
" Copyright: 2011-2015 Massachusetts Institute of Technology\n",
" License: http://mit-crpg.github.io/openmc/license.html\n",
" Copyright: 2011-2016 Massachusetts Institute of Technology\n",
" License: http://openmc.readthedocs.io/en/latest/license.html\n",
" Version: 0.7.1\n",
" Git SHA1: eeb5091ca3a34cc85df73a3318cae2b6c7097413\n",
" Date/Time: 2016-04-13 11:24:09\n",
" Git SHA1: 19feb55e6d5e8350398627f39fb55ee8e2e63011\n",
" Date/Time: 2016-05-13 10:19:16\n",
" MPI Processes: 1\n",
"\n",
" ===========================================================================\n",
@ -606,20 +600,20 @@
"\n",
" =======================> TIMING STATISTICS <=======================\n",
"\n",
" Total time for initialization = 4.6300E-01 seconds\n",
" Reading cross sections = 1.2100E-01 seconds\n",
" Total time in simulation = 1.6504E+01 seconds\n",
" Time in transport only = 1.6479E+01 seconds\n",
" Time in inactive batches = 1.9620E+00 seconds\n",
" Time in active batches = 1.4542E+01 seconds\n",
" Time synchronizing fission bank = 1.0000E-02 seconds\n",
" Sampling source sites = 4.0000E-03 seconds\n",
" SEND/RECV source sites = 3.0000E-03 seconds\n",
" Total time for initialization = 4.2300E-01 seconds\n",
" Reading cross sections = 9.3000E-02 seconds\n",
" Total time in simulation = 1.6549E+01 seconds\n",
" Time in transport only = 1.6535E+01 seconds\n",
" Time in inactive batches = 2.3650E+00 seconds\n",
" Time in active batches = 1.4184E+01 seconds\n",
" Time synchronizing fission bank = 5.0000E-03 seconds\n",
" Sampling source sites = 3.0000E-03 seconds\n",
" SEND/RECV source sites = 0.0000E+00 seconds\n",
" Time accumulating tallies = 0.0000E+00 seconds\n",
" Total time for finalization = 0.0000E+00 seconds\n",
" Total time elapsed = 1.6977E+01 seconds\n",
" Calculation Rate (inactive) = 12742.1 neutrons/second\n",
" Calculation Rate (active) = 6876.63 neutrons/second\n",
" Total time elapsed = 1.6981E+01 seconds\n",
" Calculation Rate (inactive) = 10570.8 neutrons/second\n",
" Calculation Rate (active) = 7050.20 neutrons/second\n",
"\n",
" ============================> RESULTS <============================\n",
"\n",
@ -644,8 +638,7 @@
],
"source": [
"# Run OpenMC\n",
"executor = openmc.Executor()\n",
"executor.run_simulation()"
"openmc.run()"
]
},
{
@ -678,20 +671,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"In addition to the statepoint file, our simulation also created a summary file which encapsulates information about the materials and geometry. This is necessary for the `openmc.mgxs` module to properly process the tally data. We first create a `Summary` object and link it with the statepoint."
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# Load the summary file and link it with the statepoint\n",
"su = openmc.Summary('summary.h5')\n",
"sp.link_with_summary(su)"
"In addition to the statepoint file, our simulation also created a summary file which encapsulates information about the materials and geometry. By default, a `Summary` object is automatically linked when a `StatePoint` is loaded. This is necessary for the `openmc.mgxs` module to properly process the tally data."
]
},
{
@ -703,7 +683,7 @@
},
{
"cell_type": "code",
"execution_count": 18,
"execution_count": 17,
"metadata": {
"collapsed": false
},
@ -738,7 +718,7 @@
},
{
"cell_type": "code",
"execution_count": 19,
"execution_count": 18,
"metadata": {
"collapsed": false
},
@ -773,7 +753,7 @@
},
{
"cell_type": "code",
"execution_count": 20,
"execution_count": 19,
"metadata": {
"collapsed": false
},
@ -820,7 +800,7 @@
"0 1 2 total 1.292013 0.007642"
]
},
"execution_count": 20,
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
@ -839,7 +819,7 @@
},
{
"cell_type": "code",
"execution_count": 21,
"execution_count": 20,
"metadata": {
"collapsed": true
},
@ -857,7 +837,7 @@
},
{
"cell_type": "code",
"execution_count": 22,
"execution_count": 21,
"metadata": {
"collapsed": false
},
@ -884,7 +864,7 @@
},
{
"cell_type": "code",
"execution_count": 23,
"execution_count": 22,
"metadata": {
"collapsed": false
},
@ -941,7 +921,7 @@
"1 (((total / flux) - (absorption / flux)) - (sca... 1.44e-15 2.57e-03 "
]
},
"execution_count": 23,
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
@ -963,7 +943,7 @@
},
{
"cell_type": "code",
"execution_count": 24,
"execution_count": 23,
"metadata": {
"collapsed": false
},
@ -1020,7 +1000,7 @@
"1 ((absorption / flux) / (total / flux)) 1.93e-02 9.46e-05 "
]
},
"execution_count": 24,
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
@ -1035,7 +1015,7 @@
},
{
"cell_type": "code",
"execution_count": 25,
"execution_count": 24,
"metadata": {
"collapsed": false
},
@ -1092,7 +1072,7 @@
"1 ((scatter / flux) / (total / flux)) 9.81e-01 3.74e-03 "
]
},
"execution_count": 25,
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
@ -1114,7 +1094,7 @@
},
{
"cell_type": "code",
"execution_count": 26,
"execution_count": 25,
"metadata": {
"collapsed": false
},
@ -1144,7 +1124,7 @@
" <td>6.250000e-07</td>\n",
" <td>total</td>\n",
" <td>(((absorption / flux) / (total / flux)) + ((sc...</td>\n",
" <td>1</td>\n",
" <td>1.0</td>\n",
" <td>0.007763</td>\n",
" </tr>\n",
" <tr>\n",
@ -1154,7 +1134,7 @@
" <td>2.000000e+01</td>\n",
" <td>total</td>\n",
" <td>(((absorption / flux) / (total / flux)) + ((sc...</td>\n",
" <td>1</td>\n",
" <td>1.0</td>\n",
" <td>0.003739</td>\n",
" </tr>\n",
" </tbody>\n",
@ -1171,7 +1151,7 @@
"1 (((absorption / flux) / (total / flux)) + ((sc... 1.00e+00 3.74e-03 "
]
},
"execution_count": 26,
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,13 @@
.. _notebook_mgxs_part_iv:
====================================================
MGXS Part IV: Multi-Group Mode Cross-Section Library
====================================================
.. only:: html
.. notebook:: mgxs-part-iv.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

@ -4,9 +4,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"This notebook shows the how tallies can be combined (added, subtracted, multiplied, etc.) using the Python API in order to create derived tallies. Since no covariance information is obtained, it is assumed that tallies are completely independent of one another when propagating uncertainties. The target problem is a simple pin cell.\n",
"\n",
"**Note:** that this Notebook was created using the latest Pandas v0.16.1. Everything in the Notebook will wun with older versions of Pandas, but the multi-indexing option in >v0.15.0 makes the tables look prettier."
"This notebook shows the how tallies can be combined (added, subtracted, multiplied, etc.) using the Python API in order to create derived tallies. Since no covariance information is obtained, it is assumed that tallies are completely independent of one another when propagating uncertainties. The target problem is a simple pin cell."
]
},
{
@ -15,27 +13,6 @@
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The autoreload extension is already loaded. To reload it, use:\n",
" %reload_ext autoreload\n"
]
}
],
"source": [
"%load_ext autoreload\n",
"%autoreload 2"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import glob\n",
@ -61,7 +38,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 2,
"metadata": {
"collapsed": true
},
@ -85,7 +62,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 3,
"metadata": {
"collapsed": false
},
@ -120,17 +97,14 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# Instantiate a MaterialsFile, add Materials\n",
"materials_file = openmc.MaterialsFile()\n",
"materials_file.add_material(fuel)\n",
"materials_file.add_material(water)\n",
"materials_file.add_material(zircaloy)\n",
"# Instantiate a Materials collection\n",
"materials_file = openmc.Materials((fuel, water, zircaloy))\n",
"materials_file.default_xs = '71c'\n",
"\n",
"# Export to \"materials.xml\"\n",
@ -146,7 +120,7 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 5,
"metadata": {
"collapsed": false
},
@ -175,7 +149,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 6,
"metadata": {
"collapsed": false
},
@ -212,7 +186,7 @@
},
{
"cell_type": "code",
"execution_count": 8,
"execution_count": 7,
"metadata": {
"collapsed": false
},
@ -239,7 +213,7 @@
},
{
"cell_type": "code",
"execution_count": 9,
"execution_count": 8,
"metadata": {
"collapsed": false
},
@ -252,18 +226,14 @@
},
{
"cell_type": "code",
"execution_count": 10,
"execution_count": 9,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# Instantiate a GeometryFile\n",
"geometry_file = openmc.GeometryFile()\n",
"geometry_file.geometry = geometry\n",
"\n",
"# Export to \"geometry.xml\"\n",
"geometry_file.export_to_xml()"
"geometry.export_to_xml()"
]
},
{
@ -275,7 +245,7 @@
},
{
"cell_type": "code",
"execution_count": 11,
"execution_count": 10,
"metadata": {
"collapsed": true
},
@ -286,8 +256,8 @@
"inactive = 5\n",
"particles = 2500\n",
"\n",
"# Instantiate a SettingsFile\n",
"settings_file = openmc.SettingsFile()\n",
"# Instantiate a Settings object\n",
"settings_file = openmc.Settings()\n",
"settings_file.batches = batches\n",
"settings_file.inactive = inactive\n",
"settings_file.particles = particles\n",
@ -311,7 +281,7 @@
},
{
"cell_type": "code",
"execution_count": 12,
"execution_count": 11,
"metadata": {
"collapsed": false
},
@ -325,9 +295,8 @@
"plot.pixels = [250, 250]\n",
"plot.color = 'mat'\n",
"\n",
"# Instantiate a PlotsFile, add Plot, and export to \"plots.xml\"\n",
"plot_file = openmc.PlotsFile()\n",
"plot_file.add_plot(plot)\n",
"# Instantiate a Plots collection and export to \"plots.xml\"\n",
"plot_file = openmc.Plots([plot])\n",
"plot_file.export_to_xml()"
]
},
@ -340,7 +309,7 @@
},
{
"cell_type": "code",
"execution_count": 13,
"execution_count": 12,
"metadata": {
"collapsed": false
},
@ -351,32 +320,31 @@
"0"
]
},
"execution_count": 13,
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Run openmc in plotting mode\n",
"executor = openmc.Executor()\n",
"executor.plot_geometry(output=False)"
"openmc.plot_geometry(output=False)"
]
},
{
"cell_type": "code",
"execution_count": 14,
"execution_count": 13,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"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\nMTYtMDQtMTNUMTE6Mzk6MTQtMDQ6MDALPlLjAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE2LTA0LTEz\nVDExOjM5OjE0LTA0OjAwemPqXwAAAABJRU5ErkJggg==\n",
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///9yEhLpgJFNv8Tq\nQYT7AAAAAWJLR0QAiAUdSAAAAAd0SU1FB+AFBRQzLY81/IkAAALKSURBVGje7dpLcqQwDAbgHHE2\nYeEj+D4cwQucBUfo+3CEXoSp8OhuhF70T4qpKXmdr21LogK2Pj7A8QmNP+HDhw8fPnz48Kf6VH9G\n+66vy+je8k19jnf8C5dXIPv86ms56lPdjvaYbyodx3ze+XLE76cXFiD4zPji99z0/AJ4n1lfvJ6f\nnl0A6x+578efMSg1wPr172/jPO5yFXM+Ef78gdblM+WPHyguP//t1/g6pA0wfln+ho/fwgYYn19C\n/xwDvwHGc9OvC+hs37DTrwuwfWanXxdQTC9Mvyygs3wjTL8uwPJpn/tNDbSGz7T0SBEWw4vLXzbQ\n6b6RoveIoO6TvPxlA63qs7z8ZQPF9F+SH22vbX8OQKf5Rtv+EgDNJ3X58wZaxWd1+fMGiuFvir8b\nvjp8J/tGy/6jAmRvhW8fwL3vVT+o3grfPoB7r/IpALI3tz8FoJN84/NV873hB8UnM3xzANtf8nb4\ndwmg3grfFEDJO8JPE0i9Ff4pAYL3pI8mkHor/HMCeO9JH00g9SafEsh7T/ppARBvp48UwJnelT5S\nACd7O31TAlnvKx9SQCd7B58KgPO+8iMFuPWe9E8F8BveWX7bAjzX9y4//Jve+fhsH6Ctv7n8PTzj\nvY/v9gEOHz58+PBX+6v/f/wPvnd54f3j6venE/yl769Xv7+j3x/o98/V32/o9+fl389Xnx+g5x/o\n+Qt6/oOeP6HnX+j5G3z+h54/ouefV5/foufP6Pk3ev4On/+j9w/o/Qd6/4Le/6D3T/D9V67Y/ZsV\nQBq+s+8f0ftP+P41axXguP9NWgDuu/Cdfv+N3r/D9/9TAID+A7T/Ae2/gPs/0P4TtP8F7r9J3AIO\n9P+g/Udw/9Oygbf7r9D+L7j/DO1/Q/vv4P4/tP8Q7n9E+y/h/k+0/xTuf4X7b+H+X7T/+BPuf3aM\n8OHDhw8fPnz4w/4vzcvgeY10sY0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTYtMDUtMDVUMTQ6NTE6\nNDUtMDY6MDCqOITjAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE2LTA1LTA1VDE0OjUxOjQ1LTA2OjAw\n22U8XwAAAABJRU5ErkJggg==\n",
"text/plain": [
"<IPython.core.display.Image object>"
]
},
"execution_count": 14,
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
@ -398,19 +366,19 @@
},
{
"cell_type": "code",
"execution_count": 15,
"execution_count": 14,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# Instantiate an empty TalliesFile\n",
"tallies_file = openmc.TalliesFile()"
"# Instantiate an empty Tallies object\n",
"tallies_file = openmc.Tallies()"
]
},
{
"cell_type": "code",
"execution_count": 16,
"execution_count": 15,
"metadata": {
"collapsed": false
},
@ -426,7 +394,7 @@
"tally.filters = [openmc.Filter(type='cell', bins=[fuel_cell.id, moderator_cell.id])]\n",
"tally.filters.append(energy_filter)\n",
"tally.scores = ['flux']\n",
"tallies_file.add_tally(tally)\n",
"tallies_file.append(tally)\n",
"\n",
"# Instantiate reaction rate Tally in fuel\n",
"tally = openmc.Tally(name='fuel rxn rates')\n",
@ -434,7 +402,7 @@
"tally.filters.append(energy_filter)\n",
"tally.scores = ['nu-fission', 'scatter']\n",
"tally.nuclides = [u238, u235]\n",
"tallies_file.add_tally(tally)\n",
"tallies_file.append(tally)\n",
"\n",
"# Instantiate reaction rate Tally in moderator\n",
"tally = openmc.Tally(name='moderator rxn rates')\n",
@ -442,12 +410,12 @@
"tally.filters.append(energy_filter)\n",
"tally.scores = ['absorption', 'total']\n",
"tally.nuclides = [o16, h1]\n",
"tallies_file.add_tally(tally)"
"tallies_file.append(tally)"
]
},
{
"cell_type": "code",
"execution_count": 17,
"execution_count": 16,
"metadata": {
"collapsed": true
},
@ -458,8 +426,22 @@
"abs_rate = openmc.Tally(name='abs. rate')\n",
"fiss_rate.scores = ['nu-fission']\n",
"abs_rate.scores = ['absorption']\n",
"tallies_file.add_tally(fiss_rate)\n",
"tallies_file.add_tally(abs_rate)"
"tallies_file += (fiss_rate, abs_rate)"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# Resonance Escape Probability tallies\n",
"therm_abs_rate = openmc.Tally(name='therm. abs. rate')\n",
"therm_abs_rate.scores = ['absorption']\n",
"therm_abs_rate.filters = [openmc.Filter(type='energy', bins=[0., 0.625e-6])]\n",
"tallies_file.append(therm_abs_rate)"
]
},
{
@ -469,33 +451,18 @@
"collapsed": false
},
"outputs": [],
"source": [
"# Resonance Escape Probability tallies\n",
"therm_abs_rate = openmc.Tally(name='therm. abs. rate')\n",
"therm_abs_rate.scores = ['absorption']\n",
"therm_abs_rate.filters = [openmc.Filter(type='energy', bins=[0., 0.625e-6])]\n",
"tallies_file.add_tally(therm_abs_rate)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# Thermal Flux Utilization tallies\n",
"fuel_therm_abs_rate = openmc.Tally(name='fuel therm. abs. rate')\n",
"fuel_therm_abs_rate.scores = ['absorption']\n",
"fuel_therm_abs_rate.filters = [openmc.Filter(type='energy', bins=[0., 0.625e-6]),\n",
" openmc.Filter(type='cell', bins=[fuel_cell.id])]\n",
"tallies_file.add_tally(fuel_therm_abs_rate)"
"tallies_file.append(fuel_therm_abs_rate)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"execution_count": 19,
"metadata": {
"collapsed": true
},
@ -505,12 +472,12 @@
"therm_fiss_rate = openmc.Tally(name='therm. fiss. rate')\n",
"therm_fiss_rate.scores = ['nu-fission']\n",
"therm_fiss_rate.filters = [openmc.Filter(type='energy', bins=[0., 0.625e-6])]\n",
"tallies_file.add_tally(therm_fiss_rate)"
"tallies_file.append(therm_fiss_rate)"
]
},
{
"cell_type": "code",
"execution_count": 21,
"execution_count": 20,
"metadata": {
"collapsed": true
},
@ -525,12 +492,12 @@
"tally.filters.append(energy_filter)\n",
"tally.scores = ['nu-fission', 'scatter']\n",
"tally.nuclides = [h1, u238]\n",
"tallies_file.add_tally(tally)"
"tallies_file.append(tally)"
]
},
{
"cell_type": "code",
"execution_count": 22,
"execution_count": 21,
"metadata": {
"collapsed": false
},
@ -549,7 +516,7 @@
},
{
"cell_type": "code",
"execution_count": 23,
"execution_count": 22,
"metadata": {
"collapsed": false,
"scrolled": true
@ -572,12 +539,11 @@
" 888\n",
" 888\n",
"\n",
" Copyright: 2011-2015 Massachusetts Institute of Technology\n",
" License: http://mit-crpg.github.io/openmc/license.html\n",
" Copyright: 2011-2016 Massachusetts Institute of Technology\n",
" License: http://openmc.readthedocs.org/en/latest/license.html\n",
" Version: 0.7.1\n",
" Git SHA1: eeb5091ca3a34cc85df73a3318cae2b6c7097413\n",
" Date/Time: 2016-04-13 11:39:14\n",
" MPI Processes: 1\n",
" Git SHA1: df280b60eb1c6d7b7f842e05ede734a4883a0fc8\n",
" Date/Time: 2016-05-05 14:51:45\n",
"\n",
" ===========================================================================\n",
" ========================> INITIALIZATION <=========================\n",
@ -633,20 +599,20 @@
"\n",
" =======================> TIMING STATISTICS <=======================\n",
"\n",
" Total time for initialization = 4.0300E-01 seconds\n",
" Reading cross sections = 8.6000E-02 seconds\n",
" Total time in simulation = 1.4439E+01 seconds\n",
" Time in transport only = 1.4430E+01 seconds\n",
" Time in inactive batches = 2.2790E+00 seconds\n",
" Time in active batches = 1.2160E+01 seconds\n",
" Time synchronizing fission bank = 2.0000E-03 seconds\n",
" Sampling source sites = 1.0000E-03 seconds\n",
" SEND/RECV source sites = 1.0000E-03 seconds\n",
" Time accumulating tallies = 0.0000E+00 seconds\n",
" Total time for finalization = 1.0000E-03 seconds\n",
" Total time elapsed = 1.4856E+01 seconds\n",
" Calculation Rate (inactive) = 5484.86 neutrons/second\n",
" Calculation Rate (active) = 3083.88 neutrons/second\n",
" Total time for initialization = 7.2500E-01 seconds\n",
" Reading cross sections = 4.4400E-01 seconds\n",
" Total time in simulation = 1.5547E+01 seconds\n",
" Time in transport only = 1.5527E+01 seconds\n",
" Time in inactive batches = 2.2880E+00 seconds\n",
" Time in active batches = 1.3259E+01 seconds\n",
" Time synchronizing fission bank = 1.0000E-03 seconds\n",
" Sampling source sites = 0.0000E+00 seconds\n",
" SEND/RECV source sites = 0.0000E+00 seconds\n",
" Time accumulating tallies = 1.0000E-03 seconds\n",
" Total time for finalization = 2.0000E-03 seconds\n",
" Total time elapsed = 1.6291E+01 seconds\n",
" Calculation Rate (inactive) = 5463.29 neutrons/second\n",
" Calculation Rate (active) = 2828.27 neutrons/second\n",
"\n",
" ============================> RESULTS <============================\n",
"\n",
@ -664,7 +630,7 @@
"0"
]
},
"execution_count": 23,
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
@ -673,8 +639,8 @@
"# Remove old HDF5 (summary, statepoint) files\n",
"!rm statepoint.*\n",
"\n",
"# Run OpenMC with MPI!\n",
"executor.run_simulation()"
"# Run OpenMC!\n",
"openmc.run()"
]
},
{
@ -693,7 +659,7 @@
},
{
"cell_type": "code",
"execution_count": 24,
"execution_count": 23,
"metadata": {
"collapsed": false,
"scrolled": true
@ -704,27 +670,6 @@
"sp = openmc.StatePoint('statepoint.20.h5')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You may have also noticed we instructed OpenMC to create a summary file with lots of geometry information in it. This can help to produce more sensible output from the Python API, so we will use the summary file to link against."
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": false,
"scrolled": true
},
"outputs": [],
"source": [
"# Load the summary file and link with statepoint\n",
"su = openmc.Summary('summary.h5')\n",
"sp.link_with_summary(su)"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -736,7 +681,7 @@
},
{
"cell_type": "code",
"execution_count": 26,
"execution_count": 24,
"metadata": {
"collapsed": false
},
@ -772,7 +717,7 @@
"0 total (nu-fission / absorption) 1.04e+00 6.14e-03"
]
},
"execution_count": 26,
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
@ -796,7 +741,7 @@
},
{
"cell_type": "code",
"execution_count": 27,
"execution_count": 25,
"metadata": {
"collapsed": false
},
@ -820,7 +765,7 @@
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>6.250000e-07</td>\n",
" <td>total</td>\n",
" <td>absorption</td>\n",
@ -836,7 +781,7 @@
"0 0.00e+00 6.25e-07 total absorption 6.93e-01 4.11e-03"
]
},
"execution_count": 27,
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
@ -858,7 +803,7 @@
},
{
"cell_type": "code",
"execution_count": 28,
"execution_count": 26,
"metadata": {
"collapsed": false
},
@ -882,7 +827,7 @@
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>6.250000e-07</td>\n",
" <td>total</td>\n",
" <td>nu-fission</td>\n",
@ -898,7 +843,7 @@
"0 0.00e+00 6.25e-07 total nu-fission 1.20e+00 7.60e-03"
]
},
"execution_count": 28,
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
@ -919,6 +864,137 @@
"where the superscript $F$ denotes fuel."
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>energy low [MeV]</th>\n",
" <th>energy high [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",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0.0</td>\n",
" <td>6.250000e-07</td>\n",
" <td>10000</td>\n",
" <td>total</td>\n",
" <td>absorption</td>\n",
" <td>0.748413</td>\n",
" <td>0.004723</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" energy low [MeV] energy high [MeV] cell nuclide score mean \\\n",
"0 0.00e+00 6.25e-07 10000 total absorption 7.48e-01 \n",
"\n",
" std. dev. \n",
"0 4.72e-03 "
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Compute thermal flux utilization factor using tally arithmetic\n",
"fuel_therm_abs_rate = sp.get_tally(name='fuel therm. abs. rate')\n",
"therm_util = fuel_therm_abs_rate / therm_abs_rate\n",
"therm_util.get_pandas_dataframe()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The final factor is the number of fission neutrons produced per absorption in fuel, calculated as $$\\eta = \\frac{\\langle \\nu\\Sigma_f\\phi \\rangle_T}{\\langle \\Sigma_a \\phi \\rangle^F_T}$$"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>energy low [MeV]</th>\n",
" <th>energy high [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",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0.0</td>\n",
" <td>6.250000e-07</td>\n",
" <td>10000</td>\n",
" <td>total</td>\n",
" <td>(nu-fission / absorption)</td>\n",
" <td>1.663385</td>\n",
" <td>0.011253</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" energy low [MeV] energy high [MeV] cell nuclide \\\n",
"0 0.00e+00 6.25e-07 10000 total \n",
"\n",
" score mean std. dev. \n",
"0 (nu-fission / absorption) 1.66e+00 1.13e-02 "
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Compute neutrons produced per absorption (eta) using tally arithmetic\n",
"eta = therm_fiss_rate / fuel_therm_abs_rate\n",
"eta.get_pandas_dataframe()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we can calculate $k_\\infty$ using the product of the factors form the four-factor formula."
]
},
{
"cell_type": "code",
"execution_count": 29,
@ -946,138 +1022,7 @@
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0</td>\n",
" <td>6.250000e-07</td>\n",
" <td>10000</td>\n",
" <td>total</td>\n",
" <td>absorption</td>\n",
" <td>0.748413</td>\n",
" <td>0.004723</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" energy low [MeV] energy high [MeV] cell nuclide score mean \\\n",
"0 0.00e+00 6.25e-07 10000 total absorption 7.48e-01 \n",
"\n",
" std. dev. \n",
"0 4.72e-03 "
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Compute thermal flux utilization factor using tally arithmetic\n",
"fuel_therm_abs_rate = sp.get_tally(name='fuel therm. abs. rate')\n",
"therm_util = fuel_therm_abs_rate / therm_abs_rate\n",
"therm_util.get_pandas_dataframe()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The final factor is the number of fission neutrons produced per absorption in fuel, calculated as $$\\eta = \\frac{\\langle \\nu\\Sigma_f\\phi \\rangle_T}{\\langle \\Sigma_a \\phi \\rangle^F_T}$$"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>energy low [MeV]</th>\n",
" <th>energy high [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",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0</td>\n",
" <td>6.250000e-07</td>\n",
" <td>10000</td>\n",
" <td>total</td>\n",
" <td>(nu-fission / absorption)</td>\n",
" <td>1.663385</td>\n",
" <td>0.011253</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" energy low [MeV] energy high [MeV] cell nuclide \\\n",
"0 0.00e+00 6.25e-07 10000 total \n",
"\n",
" score mean std. dev. \n",
"0 (nu-fission / absorption) 1.66e+00 1.13e-02 "
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Compute neutrons produced per absorption (eta) using tally arithmetic\n",
"eta = therm_fiss_rate / fuel_therm_abs_rate\n",
"eta.get_pandas_dataframe()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we can calculate $k_\\infty$ using the product of the factors form the four-factor formula."
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>energy low [MeV]</th>\n",
" <th>energy high [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",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>6.250000e-07</td>\n",
" <td>10000</td>\n",
" <td>total</td>\n",
@ -1097,7 +1042,7 @@
"0 (((absorption * nu-fission) * absorption) * (n... 1.04e+00 1.32e-02 "
]
},
"execution_count": 31,
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
@ -1118,7 +1063,7 @@
},
{
"cell_type": "code",
"execution_count": 32,
"execution_count": 30,
"metadata": {
"collapsed": false,
"scrolled": true
@ -1134,7 +1079,7 @@
},
{
"cell_type": "code",
"execution_count": 33,
"execution_count": 31,
"metadata": {
"collapsed": false
},
@ -1263,7 +1208,7 @@
"7 (scatter / flux) 3.37e-03 1.44e-05 "
]
},
"execution_count": 33,
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
@ -1282,7 +1227,7 @@
},
{
"cell_type": "code",
"execution_count": 34,
"execution_count": 32,
"metadata": {
"collapsed": false
},
@ -1314,7 +1259,7 @@
},
{
"cell_type": "code",
"execution_count": 35,
"execution_count": 33,
"metadata": {
"collapsed": false
},
@ -1338,7 +1283,7 @@
},
{
"cell_type": "code",
"execution_count": 36,
"execution_count": 34,
"metadata": {
"collapsed": false
},
@ -1369,7 +1314,7 @@
},
{
"cell_type": "code",
"execution_count": 37,
"execution_count": 35,
"metadata": {
"collapsed": false
},
@ -1450,7 +1395,7 @@
"3 7.32e-04 "
]
},
"execution_count": 37,
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
@ -1463,7 +1408,7 @@
},
{
"cell_type": "code",
"execution_count": 38,
"execution_count": 36,
"metadata": {
"collapsed": false
},
@ -1604,7 +1549,7 @@
"8 3.20e-03 "
]
},
"execution_count": 38,
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
@ -1620,21 +1565,21 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"display_name": "Python 3",
"language": "python",
"name": "python2"
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
"pygments_lexer": "ipython3",
"version": "3.5.1"
}
},
"nbformat": 4,

View file

@ -13,6 +13,21 @@ online. We recommend going through the modules from Codecademy_ and/or the
`Scipy lectures`_. The full API documentation serves to provide more information
on a given module or class.
-------------------------
Example Jupyter Notebooks
-------------------------
.. toctree::
:maxdepth: 1
examples/post-processing
examples/pandas-dataframes
examples/tally-arithmetic
examples/mgxs-part-i
examples/mgxs-part-ii
examples/mgxs-part-iii
examples/mgxs-part-iv
------------------------------------
:mod:`openmc` -- Basic Functionality
------------------------------------
@ -29,7 +44,7 @@ Classes
:template: myclass.rst
openmc.XSdata
openmc.MGXSLibraryFile
openmc.MGXSLibrary
Functions
+++++++++
@ -50,7 +65,7 @@ Simulation Settings
openmc.Source
openmc.ResonanceScattering
openmc.SettingsFile
openmc.Settings
Material Specification
----------------------
@ -64,7 +79,7 @@ Material Specification
openmc.Element
openmc.Macroscopic
openmc.Material
openmc.MaterialsFile
openmc.Materials
Building geometry
-----------------
@ -96,7 +111,6 @@ Building geometry
openmc.RectLattice
openmc.HexLattice
openmc.Geometry
openmc.GeometryFile
Many of the above classes are derived from several abstract classes:
@ -109,6 +123,16 @@ Many of the above classes are derived from several abstract classes:
openmc.Region
openmc.Lattice
One function is also available to create a hexagonal region defined by the
intersection of six surface half-spaces.
.. autosummary::
:toctree: generated
:nosignatures:
:template: myfunction.rst
openmc.make_hexagon_region
Constructing Tallies
--------------------
@ -121,7 +145,7 @@ Constructing Tallies
openmc.Mesh
openmc.Trigger
openmc.Tally
openmc.TalliesFile
openmc.Tallies
Coarse Mesh Finite Difference Acceleration
------------------------------------------
@ -132,7 +156,7 @@ Coarse Mesh Finite Difference Acceleration
:template: myclass.rst
openmc.CMFDMesh
openmc.CMFDFile
openmc.CMFD
Plotting
--------
@ -143,7 +167,7 @@ Plotting
:template: myclass.rst
openmc.Plot
openmc.PlotsFile
openmc.Plots
Running OpenMC
--------------
@ -151,9 +175,10 @@ Running OpenMC
.. autosummary::
:toctree: generated
:nosignatures:
:template: myclass.rst
:template: myfunction.rst
openmc.Executor
openmc.run
openmc.plot_geometry
Post-processing
---------------
@ -271,20 +296,6 @@ Multi-group Cross Section Libraries
openmc.mgxs.Library
-------------------------
Example Jupyter Notebooks
-------------------------
.. toctree::
:maxdepth: 1
examples/post-processing
examples/pandas-dataframes
examples/tally-arithmetic
examples/mgxs-part-i
examples/mgxs-part-ii
examples/mgxs-part-iii
.. _Jupyter: https://jupyter.org/
.. _NumPy: http://www.numpy.org/
.. _Codecademy: https://www.codecademy.com/tracks/python

View file

@ -14,7 +14,5 @@ essential aspects of using OpenMC to perform simulations.
beginners
install
input
mgxs_library
output/index
processing
troubleshoot

View file

@ -1066,6 +1066,20 @@ Each ``<cell>`` element can have the following attributes or sub-elements:
<cell fill="..." rotation="0 0 90" />
The rotation applied is an intrinsic rotation whose Tait-Bryan angles are
given as those specified about the x, y, and z axes respectively. That is to
say, if the angles are :math:`(\phi, \theta, \psi)`, then the rotation
matrix applied is :math:`R_z(\psi) R_y(\theta) R_x(\phi)` or
.. math::
\left [ \begin{array}{ccc} \cos\theta \cos\psi & -\cos\theta \sin\psi +
\sin\phi \sin\theta \cos\psi & \sin\phi \sin\psi + \cos\phi \sin\theta
\cos\psi \\ \cos\theta \sin\psi & \cos\phi \cos\psi + \sin\phi \sin\theta
\sin\psi & -\sin\phi \cos\psi + \cos\phi \sin\theta \sin\psi \\
-\sin\theta & \sin\phi \cos\theta & \cos\phi \cos\theta \end{array}
\right ]
*Default*: None
:translation:
@ -1248,11 +1262,10 @@ Each ``material`` element can have the following attributes or sub-elements:
An element with attributes/sub-elements called ``value`` and ``units``. The
``value`` attribute is the numeric value of the density while the ``units``
can be "g/cm3", "kg/m3", "atom/b-cm", "atom/cm3", or "sum". The "sum" unit
indicates that values appearing in ``ao`` attributes for ``<nuclide>`` and
``<element>`` sub-elements are to be interpreted as nuclide/element
densities in atom/b-cm, and the total density of the material is taken as
the sum of all nuclides/elements. The "sum" option cannot be used in
conjunction with weight percents. The "macro" unit is used with
indicates that values appearing in ``ao`` or ``wo`` attributes for ``<nuclide>``
and ``<element>`` sub-elements are to be interpreted as absolute nuclide/element
densities in atom/b-cm or g/cm3, and the total density of the material is
taken as the sum of all nuclides/elements. The "macro" unit is used with
a ``macroscopic`` quantity to indicate that the density is already included
in the library and thus not needed here. However, if a value is provided
for the ``value``, then this is treated as a number density multiplier on
@ -1976,7 +1989,7 @@ sub-elements:
datafiles can be processed into 3D SILO files using the
``openmc-voxel-to-silovtk`` utility provided with the OpenMC source, and
subsequently viewed with a 3D viewer such as VISIT or Paraview. See the
:ref:`usersguide_voxel` for information about the datafile structure.
:ref:`io_voxel` for information about the datafile structure.
.. note:: Since the PPM format is saved without any kind of compression,
the resulting file sizes can be quite large. Saving the image in

View file

@ -161,7 +161,7 @@ or
* `VTK <http://www.vtk.org/>`_ with python bindings. On debian derivatives,
these are easily obtained with ``sudo apt-get install python-vtk``
For the HDF5 file structure, see :ref:`usersguide_voxel`.
For the HDF5 file structure, see :ref:`io_voxel`.
Once processed into a standard 3D file format, colors and masks can be defined
using the stored id numbers to better explore the geometry. The process for
@ -195,7 +195,7 @@ Data Extraction
---------------
A great deal of information is available in statepoint files (See
:ref:`usersguide_statepoint`), all of which is accessible through the Python
:ref:`io_statepoint`), all of which is accessible through the Python
API. The :class:`openmc.StatePoint` class can load statepoints and access data
as requested; it is used in many of the provided plotting utilities, OpenMC's
regression test suite, and can be used in user-created scripts to carry out

View file

@ -12,7 +12,7 @@ particles = 10000
###############################################################################
# Exporting to OpenMC materials.xml File
# Exporting to OpenMC materials.xml file
###############################################################################
# Instantiate some Nuclides
@ -31,15 +31,14 @@ fuel = openmc.Material(material_id=40, name='fuel')
fuel.set_density('g/cc', 4.5)
fuel.add_nuclide(u235, 1.)
# Instantiate a MaterialsFile, register all Materials, and export to XML
materials_file = openmc.MaterialsFile()
# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials([moderator, fuel])
materials_file.default_xs = '71c'
materials_file.add_materials([moderator, fuel])
materials_file.export_to_xml()
###############################################################################
# Exporting to OpenMC geometry.xml File
# Exporting to OpenMC geometry.xml file
###############################################################################
# Instantiate ZCylinder surfaces
@ -74,22 +73,18 @@ cell1.fill = universe1
universe1.add_cells([cell2, cell3])
root.add_cells([cell1, cell4])
# Instantiate a Geometry and register the root Universe
# Instantiate a Geometry, register the root Universe, and export to XML
geometry = openmc.Geometry()
geometry.root_universe = root
# Instantiate a GeometryFile, register Geometry, and export to XML
geometry_file = openmc.GeometryFile()
geometry_file.geometry = geometry
geometry_file.export_to_xml()
geometry.export_to_xml()
###############################################################################
# Exporting to OpenMC settings.xml File
# Exporting to OpenMC settings.xml file
###############################################################################
# Instantiate a SettingsFile, set all runtime parameters, and export to XML
settings_file = openmc.SettingsFile()
# Instantiate a Settings object, set all runtime parameters, and export to XML
settings_file = openmc.Settings()
settings_file.batches = batches
settings_file.inactive = inactive
settings_file.particles = particles
@ -103,7 +98,7 @@ settings_file.export_to_xml()
###############################################################################
# Exporting to OpenMC tallies.xml File
# Exporting to OpenMC tallies.xml file
###############################################################################
# Instantiate some tally Filters
@ -128,9 +123,6 @@ third_tally = openmc.Tally(tally_id=3, name='third tally')
third_tally.filters = [cell_filter, energy_filter, energyout_filter]
third_tally.scores = ['scatter', 'nu-scatter', 'nu-fission']
# Instantiate a TalliesFile, register all Tallies, and export to XML
tallies_file = openmc.TalliesFile()
tallies_file.add_tally(first_tally)
tallies_file.add_tally(second_tally)
tallies_file.add_tally(third_tally)
# Instantiate a Tallies collection and export to XML
tallies_file = openmc.Tallies((first_tally, second_tally, third_tally))
tallies_file.export_to_xml()

View file

@ -36,15 +36,14 @@ moderator.add_nuclide(h1, 2.)
moderator.add_nuclide(o16, 1.)
moderator.add_s_alpha_beta('HH2O', '71t')
# Instantiate a MaterialsFile, register all Materials, and export to XML
materials_file = openmc.MaterialsFile()
# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials([fuel1, fuel2, moderator])
materials_file.default_xs = '71c'
materials_file.add_materials([fuel1, fuel2, moderator])
materials_file.export_to_xml()
###############################################################################
# Exporting to OpenMC geometry.xml File
# Exporting to OpenMC geometry.xml file
###############################################################################
# Instantiate planar surfaces
@ -97,22 +96,18 @@ outer_box.fill = moderator
root = openmc.Universe(universe_id=0, name='root universe')
root.add_cells([inner_box, middle_box, outer_box])
# Instantiate a Geometry and register the root Universe
# Instantiate a Geometry, register the root Universe, and export to XML
geometry = openmc.Geometry()
geometry.root_universe = root
# Instantiate a GeometryFile, register Geometry, and export to XML
geometry_file = openmc.GeometryFile()
geometry_file.geometry = geometry
geometry_file.export_to_xml()
geometry.export_to_xml()
###############################################################################
# Exporting to OpenMC settings.xml File
###############################################################################
# Instantiate a SettingsFile, set all runtime parameters, and export to XML
settings_file = openmc.SettingsFile()
# Instantiate a Settings object, set all runtime parameters, and export to XML
settings_file = openmc.Settings()
settings_file.batches = batches
settings_file.inactive = inactive
settings_file.particles = particles
@ -133,7 +128,6 @@ plot.width = [20, 20]
plot.pixels = [200, 200]
plot.color = 'cell'
# Instantiate a PlotsFile, add Plot, and export to XML
plot_file = openmc.PlotsFile()
plot_file.add_plot(plot)
# Instantiate a Plots collection and export to XML
plot_file = openmc.Plots([plot])
plot_file.export_to_xml()

View file

@ -35,15 +35,14 @@ iron = openmc.Material(material_id=3, name='iron')
iron.set_density('g/cc', 7.9)
iron.add_nuclide(fe56, 1.)
# Instantiate a MaterialsFile, register all Materials, and export to XML
materials_file = openmc.MaterialsFile()
# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials([moderator, fuel, iron])
materials_file.default_xs = '71c'
materials_file.add_materials([moderator, fuel, iron])
materials_file.export_to_xml()
###############################################################################
# Exporting to OpenMC geometry.xml File
# Exporting to OpenMC geometry.xml file
###############################################################################
# Instantiate Surfaces
@ -105,22 +104,18 @@ lattice.outer = univ2
# Fill Cell with the Lattice
cell1.fill = lattice
# Instantiate a Geometry and register the root Universe
# Instantiate a Geometry, register the root Universe, and export to XML
geometry = openmc.Geometry()
geometry.root_universe = root
# Instantiate a GeometryFile, register Geometry, and export to XML
geometry_file = openmc.GeometryFile()
geometry_file.geometry = geometry
geometry_file.export_to_xml()
geometry.export_to_xml()
###############################################################################
# Exporting to OpenMC settings.xml File
# Exporting to OpenMC settings.xml file
###############################################################################
# Instantiate a SettingsFile, set all runtime parameters, and export to XML
settings_file = openmc.SettingsFile()
# Instantiate a Settings object, set all runtime parameters, and export to XML
settings_file = openmc.Settings()
settings_file.batches = batches
settings_file.inactive = inactive
settings_file.particles = particles
@ -137,7 +132,7 @@ settings_file.export_to_xml()
###############################################################################
# Exporting to OpenMC plots.xml File
# Exporting to OpenMC plots.xml file
###############################################################################
plot_xy = openmc.Plot(plot_id=1)
@ -155,10 +150,8 @@ plot_yz.width = [8, 8]
plot_yz.pixels = [400, 400]
plot_yz.color = 'mat'
# Instantiate a PlotsFile, add Plot, and export to XML
plot_file = openmc.PlotsFile()
plot_file.add_plot(plot_xy)
plot_file.add_plot(plot_yz)
# Instantiate a Plots collection, add plots, and export to XML
plot_file = openmc.Plots((plot_xy, plot_yz))
plot_file.export_to_xml()
@ -171,7 +164,6 @@ tally = openmc.Tally(tally_id=1)
tally.filters = [openmc.Filter(type='distribcell', bins=[cell2.id])]
tally.scores = ['total']
# Instantiate a TalliesFile, register Tally/Mesh, and export to XML
tallies_file = openmc.TalliesFile()
tallies_file.add_tally(tally)
# Instantiate a Tallies collection and export to XML
tallies_file = openmc.Tallies([tally])
tallies_file.export_to_xml()

View file

@ -11,7 +11,7 @@ particles = 10000
###############################################################################
# Exporting to OpenMC materials.xml File
# Exporting to OpenMC materials.xml file
###############################################################################
# Instantiate some Nuclides
@ -30,15 +30,14 @@ moderator.add_nuclide(h1, 2.)
moderator.add_nuclide(o16, 1.)
moderator.add_s_alpha_beta('HH2O', '71t')
# Instantiate a MaterialsFile, register all Materials, and export to XML
materials_file = openmc.MaterialsFile()
# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials((moderator, fuel))
materials_file.default_xs = '71c'
materials_file.add_materials([moderator, fuel])
materials_file.export_to_xml()
###############################################################################
# Exporting to OpenMC geometry.xml File
# Exporting to OpenMC geometry.xml file
###############################################################################
# Instantiate Surfaces
@ -116,22 +115,18 @@ lattice2.universes = [[univ4, univ4],
cell1.fill = lattice2
cell2.fill = lattice1
# Instantiate a Geometry and register the root Universe
# Instantiate a Geometry, register the root Universe, and export to XML
geometry = openmc.Geometry()
geometry.root_universe = root
# Instantiate a GeometryFile, register Geometry, and export to XML
geometry_file = openmc.GeometryFile()
geometry_file.geometry = geometry
geometry_file.export_to_xml()
geometry.export_to_xml()
###############################################################################
# Exporting to OpenMC settings.xml File
# Exporting to OpenMC settings.xml file
###############################################################################
# Instantiate a SettingsFile, set all runtime parameters, and export to XML
settings_file = openmc.SettingsFile()
# Instantiate a Settings object, set all runtime parameters, and export to XML
settings_file = openmc.Settings()
settings_file.batches = batches
settings_file.inactive = inactive
settings_file.particles = particles
@ -145,7 +140,7 @@ settings_file.export_to_xml()
###############################################################################
# Exporting to OpenMC plots.xml File
# Exporting to OpenMC plots.xml file
###############################################################################
plot = openmc.Plot(plot_id=1)
@ -154,14 +149,13 @@ plot.width = [4, 4]
plot.pixels = [400, 400]
plot.color = 'mat'
# Instantiate a PlotsFile, add Plot, and export to XML
plot_file = openmc.PlotsFile()
plot_file.add_plot(plot)
# Instantiate a Plots object and export to XML
plot_file = openmc.Plots([plot])
plot_file.export_to_xml()
###############################################################################
# Exporting to OpenMC tallies.xml File
# Exporting to OpenMC tallies.xml file
###############################################################################
# Instantiate a tally mesh
@ -180,8 +174,6 @@ tally = openmc.Tally(tally_id=1)
tally.filters = [mesh_filter]
tally.scores = ['total']
# Instantiate a TalliesFile, register Tally/Mesh, and export to XML
tallies_file = openmc.TalliesFile()
tallies_file.add_mesh(mesh)
tallies_file.add_tally(tally)
# Instantiate a Tallies collection, register Tally/Mesh, and export to XML
tallies_file = openmc.Tallies([tally])
tallies_file.export_to_xml()

View file

@ -11,7 +11,7 @@ particles = 10000
###############################################################################
# Exporting to OpenMC materials.xml File
# Exporting to OpenMC materials.xml file
###############################################################################
# Instantiate some Nuclides
@ -30,15 +30,14 @@ moderator.add_nuclide(h1, 2.)
moderator.add_nuclide(o16, 1.)
moderator.add_s_alpha_beta('HH2O', '71t')
# Instantiate a MaterialsFile, register all Materials, and export to XML
materials_file = openmc.MaterialsFile()
# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials([moderator, fuel])
materials_file.default_xs = '71c'
materials_file.add_materials([moderator, fuel])
materials_file.export_to_xml()
###############################################################################
# Exporting to OpenMC geometry.xml File
# Exporting to OpenMC geometry.xml file
###############################################################################
# Instantiate Surfaces
@ -106,22 +105,18 @@ lattice.universes = [[univ1, univ2, univ1, univ2],
# Fill Cell with the Lattice
cell1.fill = lattice
# Instantiate a Geometry and register the root Universe
# Instantiate a Geometry, register the root Universe, and export to XML
geometry = openmc.Geometry()
geometry.root_universe = root
# Instantiate a GeometryFile, register Geometry, and export to XML
geometry_file = openmc.GeometryFile()
geometry_file.geometry = geometry
geometry_file.export_to_xml()
geometry.export_to_xml()
###############################################################################
# Exporting to OpenMC settings.xml File
# Exporting to OpenMC settings.xml file
###############################################################################
# Instantiate a SettingsFile, set all runtime parameters, and export to XML
settings_file = openmc.SettingsFile()
# Instantiate a Settings object, set all runtime parameters, and export to XML
settings_file = openmc.Settings()
settings_file.batches = batches
settings_file.inactive = inactive
settings_file.particles = particles
@ -137,7 +132,7 @@ settings_file.export_to_xml()
###############################################################################
# Exporting to OpenMC plots.xml File
# Exporting to OpenMC plots.xml file
###############################################################################
plot = openmc.Plot(plot_id=1)
@ -146,14 +141,13 @@ plot.width = [4, 4]
plot.pixels = [400, 400]
plot.color = 'mat'
# Instantiate a PlotsFile, add Plot, and export to XML
plot_file = openmc.PlotsFile()
plot_file.add_plot(plot)
# Instantiate a Plots collection and export to XML
plot_file = openmc.Plots([plot])
plot_file.export_to_xml()
###############################################################################
# Exporting to OpenMC tallies.xml File
# Exporting to OpenMC tallies.xml file
###############################################################################
# Instantiate a tally mesh
@ -177,8 +171,6 @@ tally.filters = [mesh_filter]
tally.scores = ['total']
tally.triggers = [trigger]
# Instantiate a TalliesFile, register Tally/Mesh, and export to XML
tallies_file = openmc.TalliesFile()
tallies_file.add_mesh(mesh)
tallies_file.add_tally(tally)
# Instantiate a Tallies collection and export to XML
tallies_file = openmc.Tallies([tally])
tallies_file.export_to_xml()

View file

@ -11,7 +11,7 @@ particles = 1000
###############################################################################
# Exporting to OpenMC materials.xml File
# Exporting to OpenMC materials.xml file
###############################################################################
# Instantiate some Nuclides
@ -100,15 +100,14 @@ borated_water.add_nuclide(o16, 2.4672e-2)
borated_water.add_nuclide(o17, 6.0099e-5)
borated_water.add_s_alpha_beta('HH2O', '71t')
# Instantiate a MaterialsFile, register all Materials, and export to XML
materials_file = openmc.MaterialsFile()
# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials([uo2, helium, zircaloy, borated_water])
materials_file.default_xs = '71c'
materials_file.add_materials([uo2, helium, zircaloy, borated_water])
materials_file.export_to_xml()
###############################################################################
# Exporting to OpenMC geometry.xml File
# Exporting to OpenMC geometry.xml file
###############################################################################
# Instantiate ZCylinder surfaces
@ -149,22 +148,18 @@ root = openmc.Universe(universe_id=0, name='root universe')
# Register Cells with Universe
root.add_cells([fuel, gap, clad, water])
# Instantiate a Geometry and register the root Universe
# Instantiate a Geometry, register the root Universe, and export to XML
geometry = openmc.Geometry()
geometry.root_universe = root
# Instantiate a GeometryFile, register Geometry, and export to XML
geometry_file = openmc.GeometryFile()
geometry_file.geometry = geometry
geometry_file.export_to_xml()
geometry.export_to_xml()
###############################################################################
# Exporting to OpenMC settings.xml File
# Exporting to OpenMC settings.xml file
###############################################################################
# Instantiate a SettingsFile, set all runtime parameters, and export to XML
settings_file = openmc.SettingsFile()
# Instantiate a Settings object, set all runtime parameters, and export to XML
settings_file = openmc.Settings()
settings_file.batches = batches
settings_file.inactive = inactive
settings_file.particles = particles
@ -181,7 +176,7 @@ settings_file.export_to_xml()
###############################################################################
# Exporting to OpenMC tallies.xml File
# Exporting to OpenMC tallies.xml file
###############################################################################
# Instantiate a tally mesh
@ -201,8 +196,6 @@ tally = openmc.Tally(tally_id=1, name='tally 1')
tally.filters = [energy_filter, mesh_filter]
tally.scores = ['flux', 'fission', 'nu-fission']
# Instantiate a TalliesFile, register all Tallies, and export to XML
tallies_file = openmc.TalliesFile()
tallies_file.add_mesh(mesh)
tallies_file.add_tally(tally)
# Instantiate a Tallies collection and export to XML
tallies_file = openmc.Tallies([tally])
tallies_file.export_to_xml()

View file

@ -1,4 +1,3 @@
import numpy as np
import openmc
import openmc.mgxs
@ -12,7 +11,7 @@ inactive = 10
particles = 1000
###############################################################################
# Exporting to OpenMC mg_cross_sections.xml File
# Exporting to OpenMC mgxs.xml file
###############################################################################
# Instantiate the energy group data
@ -22,50 +21,48 @@ groups = openmc.mgxs.EnergyGroups(group_edges=[1E-11, 0.0635E-6, 10.0E-6,
# Instantiate the 7-group (C5G7) cross section data
uo2_xsdata = openmc.XSdata('UO2.300K', groups)
uo2_xsdata.order = 0
uo2_xsdata.total = np.array([0.1779492, 0.3298048, 0.4803882, 0.5543674,
0.3118013, 0.3951678, 0.5644058])
uo2_xsdata.absorption = np.array([8.0248E-03, 3.7174E-03, 2.6769E-02, 9.6236E-02,
3.0020E-02, 1.1126E-01, 2.8278E-01])
scatter = [[[0.1275370, 0.0423780, 0.0000094, 0.0000000, 0.0000000, 0.0000000, 0.0000000],
[0.0000000, 0.3244560, 0.0016314, 0.0000000, 0.0000000, 0.0000000, 0.0000000],
[0.0000000, 0.0000000, 0.4509400, 0.0026792, 0.0000000, 0.0000000, 0.0000000],
[0.0000000, 0.0000000, 0.0000000, 0.4525650, 0.0055664, 0.0000000, 0.0000000],
[0.0000000, 0.0000000, 0.0000000, 0.0001253, 0.2714010, 0.0102550, 0.0000000],
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0012968, 0.2658020, 0.0168090],
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0085458, 0.2730800]]]
uo2_xsdata.scatter = np.array(scatter[:][:])
uo2_xsdata.fission = np.array([7.21206E-03, 8.19301E-04, 6.45320E-03,
1.85648E-02, 1.78084E-02, 8.30348E-02,
2.16004E-01])
uo2_xsdata.nu_fission = np.array([2.005998E-02, 2.027303E-03, 1.570599E-02,
4.518301E-02, 4.334208E-02, 2.020901E-01,
5.257105E-01])
uo2_xsdata.chi = np.array([5.8791E-01, 4.1176E-01, 3.3906E-04, 1.1761E-07,
0.0000E+00, 0.0000E+00, 0.0000E+00])
uo2_xsdata.total = [0.1779492, 0.3298048, 0.4803882, 0.5543674,
0.3118013, 0.3951678, 0.5644058]
uo2_xsdata.absorption = [8.0248E-03, 3.7174E-03, 2.6769E-02, 9.6236E-02,
3.0020E-02, 1.1126E-01, 2.8278E-01]
uo2_xsdata.scatter = [[[0.1275370, 0.0423780, 0.0000094, 0.0000000, 0.0000000, 0.0000000, 0.0000000],
[0.0000000, 0.3244560, 0.0016314, 0.0000000, 0.0000000, 0.0000000, 0.0000000],
[0.0000000, 0.0000000, 0.4509400, 0.0026792, 0.0000000, 0.0000000, 0.0000000],
[0.0000000, 0.0000000, 0.0000000, 0.4525650, 0.0055664, 0.0000000, 0.0000000],
[0.0000000, 0.0000000, 0.0000000, 0.0001253, 0.2714010, 0.0102550, 0.0000000],
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0012968, 0.2658020, 0.0168090],
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0085458, 0.2730800]]]
uo2_xsdata.fission = [7.21206E-03, 8.19301E-04, 6.45320E-03,
1.85648E-02, 1.78084E-02, 8.30348E-02,
2.16004E-01]
uo2_xsdata.nu_fission = [2.005998E-02, 2.027303E-03, 1.570599E-02,
4.518301E-02, 4.334208E-02, 2.020901E-01,
5.257105E-01]
uo2_xsdata.chi = [5.8791E-01, 4.1176E-01, 3.3906E-04, 1.1761E-07,
0.0000E+00, 0.0000E+00, 0.0000E+00]
h2o_xsdata = openmc.XSdata('LWTR.300K', groups)
h2o_xsdata.order = 0
h2o_xsdata.total = np.array([0.15920605, 0.412969593, 0.59030986, 0.58435,
0.718, 1.2544497, 2.650379])
h2o_xsdata.absorption = np.array([6.0105E-04, 1.5793E-05, 3.3716E-04,
1.9406E-03, 5.7416E-03, 1.5001E-02,
3.7239E-02])
scatter = [[[0.0444777, 0.1134000, 0.0007235, 0.0000037, 0.0000001, 0.0000000, 0.0000000],
[0.0000000, 0.2823340, 0.1299400, 0.0006234, 0.0000480, 0.0000074, 0.0000010],
[0.0000000, 0.0000000, 0.3452560, 0.2245700, 0.0169990, 0.0026443, 0.0005034],
[0.0000000, 0.0000000, 0.0000000, 0.0910284, 0.4155100, 0.0637320, 0.0121390],
[0.0000000, 0.0000000, 0.0000000, 0.0000714, 0.1391380, 0.5118200, 0.0612290],
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0022157, 0.6999130, 0.5373200],
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.1324400, 2.4807000]]]
h2o_xsdata.scatter = np.array(scatter)
h2o_xsdata.total = [0.15920605, 0.412969593, 0.59030986, 0.58435,
0.718, 1.2544497, 2.650379]
h2o_xsdata.absorption = [6.0105E-04, 1.5793E-05, 3.3716E-04,
1.9406E-03, 5.7416E-03, 1.5001E-02,
3.7239E-02]
h2o_xsdata.scatter = [[[0.0444777, 0.1134000, 0.0007235, 0.0000037, 0.0000001, 0.0000000, 0.0000000],
[0.0000000, 0.2823340, 0.1299400, 0.0006234, 0.0000480, 0.0000074, 0.0000010],
[0.0000000, 0.0000000, 0.3452560, 0.2245700, 0.0169990, 0.0026443, 0.0005034],
[0.0000000, 0.0000000, 0.0000000, 0.0910284, 0.4155100, 0.0637320, 0.0121390],
[0.0000000, 0.0000000, 0.0000000, 0.0000714, 0.1391380, 0.5118200, 0.0612290],
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0022157, 0.6999130, 0.5373200],
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.1324400, 2.4807000]]]
mg_cross_sections_file = openmc.MGXSLibraryFile(groups)
mg_cross_sections_file.add_xsdatas([uo2_xsdata,h2o_xsdata])
mg_cross_sections_file = openmc.MGXSLibrary(groups)
mg_cross_sections_file.add_xsdatas([uo2_xsdata, h2o_xsdata])
mg_cross_sections_file.export_to_xml()
###############################################################################
# Exporting to OpenMC materials.xml File
# Exporting to OpenMC materials.xml file
###############################################################################
# Instantiate some Macroscopic Data
@ -81,15 +78,14 @@ water = openmc.Material(material_id=2, name='Water')
water.set_density('macro', 1.0)
water.add_macroscopic(h2o_data)
# Instantiate a MaterialsFile, register all Materials, and export to XML
materials_file = openmc.MaterialsFile()
# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials([uo2, water])
materials_file.default_xs = '300K'
materials_file.add_materials([uo2, water])
materials_file.export_to_xml()
###############################################################################
# Exporting to OpenMC geometry.xml File
# Exporting to OpenMC geometry.xml file
###############################################################################
# Instantiate ZCylinder surfaces
@ -122,24 +118,20 @@ root = openmc.Universe(universe_id=0, name='root universe')
# Register Cells with Universe
root.add_cells([fuel, moderator])
# Instantiate a Geometry and register the root Universe
# Instantiate a Geometry, register the root Universe, and export to XML
geometry = openmc.Geometry()
geometry.root_universe = root
# Instantiate a GeometryFile, register Geometry, and export to XML
geometry_file = openmc.GeometryFile()
geometry_file.geometry = geometry
geometry_file.export_to_xml()
geometry.export_to_xml()
###############################################################################
# Exporting to OpenMC settings.xml File
# Exporting to OpenMC settings.xml file
###############################################################################
# Instantiate a SettingsFile, set all runtime parameters, and export to XML
settings_file = openmc.SettingsFile()
# Instantiate a Settings object, set all runtime parameters, and export to XML
settings_file = openmc.Settings()
settings_file.energy_mode = "multi-group"
settings_file.cross_sections = "./mg_cross_sections.xml"
settings_file.cross_sections = "./mgxs.xml"
settings_file.batches = batches
settings_file.inactive = inactive
settings_file.particles = particles
@ -152,7 +144,7 @@ settings_file.source = openmc.source.Source(space=uniform_dist)
settings_file.export_to_xml()
###############################################################################
# Exporting to OpenMC tallies.xml File
# Exporting to OpenMC tallies.xml file
###############################################################################
# Instantiate a tally mesh
@ -171,14 +163,9 @@ mesh_filter.mesh = mesh
# Instantiate the Tally
tally = openmc.Tally(tally_id=1, name='tally 1')
tally.add_filter(energy_filter)
tally.add_filter(mesh_filter)
tally.add_score('flux')
tally.add_score('fission')
tally.add_score('nu-fission')
tally.filters = [energy_filter, mesh_filter]
tally.scores = ['flux', 'fission', 'nu-fission']
# Instantiate a TalliesFile, register all Tallies, and export to XML
tallies_file = openmc.TalliesFile()
tallies_file.add_mesh(mesh)
tallies_file.add_tally(tally)
# Instantiate a Tallies collection, register all Tallies, and export to XML
tallies_file = openmc.Tallies([tally])
tallies_file.export_to_xml()

View file

@ -12,7 +12,7 @@ particles = 10000
###############################################################################
# Exporting to OpenMC materials.xml File
# Exporting to OpenMC materials.xml file
###############################################################################
# Instantiate a Nuclides
@ -23,15 +23,14 @@ fuel = openmc.Material(material_id=1, name='fuel')
fuel.set_density('g/cc', 4.5)
fuel.add_nuclide(u235, 1.)
# Instantiate a MaterialsFile, register Material, and export to XML
materials_file = openmc.MaterialsFile()
# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials([fuel])
materials_file.default_xs = '71c'
materials_file.add_material(fuel)
materials_file.export_to_xml()
###############################################################################
# Exporting to OpenMC geometry.xml File
# Exporting to OpenMC geometry.xml file
###############################################################################
# Instantiate Surfaces
@ -64,22 +63,18 @@ root = openmc.Universe(universe_id=0, name='root universe')
# Register Cell with Universe
root.add_cell(cell)
# Instantiate a Geometry and register the root Universe
# Instantiate a Geometry, register the root Universe, and export to XML
geometry = openmc.Geometry()
geometry.root_universe = root
# Instantiate a GeometryFile, register Geometry, and export to XML
geometry_file = openmc.GeometryFile()
geometry_file.geometry = geometry
geometry_file.export_to_xml()
geometry.export_to_xml()
###############################################################################
# Exporting to OpenMC settings.xml File
# Exporting to OpenMC settings.xml file
###############################################################################
# Instantiate a SettingsFile, set all runtime parameters, and export to XML
settings_file = openmc.SettingsFile()
# Instantiate a Settings object, set all runtime parameters, and export to XML
settings_file = openmc.Settings()
settings_file.batches = batches
settings_file.inactive = inactive
settings_file.particles = particles

View file

@ -23,7 +23,7 @@ def reset_auto_cell_id():
class Cell(object):
"""A region of space defined as the intersection of half-space created by
r"""A region of space defined as the intersection of half-space created by
quadric surfaces.
Parameters
@ -33,6 +33,10 @@ class Cell(object):
automatically be assigned.
name : str, optional
Name of the cell. If not specified, the name is the empty string.
fill : openmc.Material or openmc.Universe or openmc.Lattice or 'void' or iterable of openmc.Material, optional
Indicates what the region of space is filled with
region : openmc.Region, optional
Region of space that is assigned to the cell.
Attributes
----------
@ -44,14 +48,25 @@ class Cell(object):
Indicates what the region of space is filled with
region : openmc.Region
Region of space that is assigned to the cell.
rotation : numpy.ndarray
rotation : Iterable of float
If the cell is filled with a universe, this array specifies the angles
in degrees about the x, y, and z axes that the filled universe should be
rotated.
Tait-Bryan angles. That is to say, if the angles are :math:`(\phi,
\theta, \psi)`, then the rotation matrix applied is :math:`R_z(\psi)
R_y(\theta) R_x(\phi)` or
.. math::
\left [ \begin{array}{ccc} \cos\theta \cos\psi & -\cos\theta \sin\psi
+ \sin\phi \sin\theta \cos\psi & \sin\phi \sin\psi + \cos\phi
\sin\theta \cos\psi \\ \cos\theta \sin\psi & \cos\phi \cos\psi +
\sin\phi \sin\theta \sin\psi & -\sin\phi \cos\psi + \cos\phi
\sin\theta \sin\psi \\ -\sin\theta & \sin\phi \cos\theta & \cos\phi
\cos\theta \end{array} \right ]
temperature : float or iterable of float
Temperature of the cell in Kelvin. Multiple temperatures can be given
to give each distributed cell instance a unique temperature.
translation : numpy.ndarray
translation : Iterable of float
If the cell is filled with a universe, this array specifies a vector
that is used to translate (shift) the universe.
offsets : ndarray
@ -61,7 +76,7 @@ class Cell(object):
"""
def __init__(self, cell_id=None, name=''):
def __init__(self, cell_id=None, name='', fill=None, region=None):
# Initialize Cell class attributes
self.id = cell_id
self.name = name
@ -74,6 +89,11 @@ class Cell(object):
self._offsets = None
self._distribcell_index = None
if fill is not None:
self.fill = fill
if region is not None:
self.region = region
def __eq__(self, other):
if not isinstance(other, Cell):
return False
@ -234,6 +254,10 @@ class Cell(object):
@rotation.setter
def rotation(self, rotation):
if not isinstance(self.fill, openmc.Universe):
raise RuntimeError('Cell rotation can only be applied if the cell '
'is filled with a Universe')
cv.check_type('cell rotation', rotation, Iterable, Real)
cv.check_length('cell rotation', rotation, 3)
self._rotation = rotation

View file

@ -1,3 +1,4 @@
import copy
from collections import Iterable
from numbers import Integral, Real
@ -57,7 +58,7 @@ def check_type(name, value, expected_type, expected_iter_type=None):
else:
msg = 'Unable to set "{0}" to "{1}" which is not of type "{2}"'.format(
name, value, expected_type.__name__)
raise ValueError(msg)
raise TypeError(msg)
if expected_iter_type:
for item in value:
@ -71,7 +72,7 @@ def check_type(name, value, expected_type, expected_iter_type=None):
msg = 'Unable to set "{0}" to "{1}" since each item must be ' \
'of type "{2}"'.format(name, value,
expected_iter_type.__name__)
raise ValueError(msg)
raise TypeError(msg)
def check_iterable_type(name, value, expected_type, min_depth=1, max_depth=1):
@ -122,7 +123,7 @@ def check_iterable_type(name, value, expected_type, min_depth=1, max_depth=1):
if len(tree) < min_depth:
msg = 'Error setting "{0}": The item at {1} does not meet the '\
'minimum depth of {2}'.format(name, ind_str, min_depth)
raise ValueError(msg)
raise TypeError(msg)
# This item is okay. Move on to the next item.
index[-1] += 1
@ -140,7 +141,7 @@ def check_iterable_type(name, value, expected_type, min_depth=1, max_depth=1):
msg = 'Error setting {0}: Found an iterable at {1}, items '\
'in that iterable exceed the maximum depth of {2}' \
.format(name, ind_str, max_depth)
raise ValueError(msg)
raise TypeError(msg)
else:
# This item is completely unexpected.
@ -148,7 +149,7 @@ def check_iterable_type(name, value, expected_type, min_depth=1, max_depth=1):
"item at {2} is of type '{3}'"\
.format(name, expected_type.__name__, ind_str,
type(current_item).__name__)
raise ValueError(msg)
raise TypeError(msg)
def check_length(name, value, length_min, length_max=None):
@ -278,6 +279,21 @@ class CheckedList(list):
for item in items:
self.append(item)
def __add__(self, other):
new_instance = copy.copy(self)
new_instance += other
return new_instance
def __radd__(self, other):
return self + other
def __iadd__(self, other):
check_type('CheckedList add operand', other, Iterable,
self.expected_type)
for item in other:
self.append(item)
return self
def append(self, item):
"""Append item to list

View file

@ -187,7 +187,7 @@ class CMFDMesh(object):
return element
class CMFDFile(object):
class CMFD(object):
"""Parameters that control the use of coarse-mesh finite difference acceleration
in OpenMC. This corresponds directly to the cmfd.xml input file.

1
openmc/data/__init__.py Normal file
View file

@ -0,0 +1 @@
from .data import *

101
openmc/data/data.py Normal file
View file

@ -0,0 +1,101 @@
# Isotopic abundances from M. Berglund and M. E. Wieser, "Isotopic compositions
# of the elements 2009 (IUPAC Technical Report)", Pure. Appl. Chem. 83 (2),
# pp. 397--410 (2011).
natural_abundance = {
'H-1': 0.999885, 'H-2': 0.000115, 'He-3': 1.34e-06,
'He-4': 0.99999866, 'Li-6': 0.0759, 'Li-7': 0.9241,
'Be-9': 1.0, 'B-10': 0.199, 'B-11': 0.801,
'C-12': 0.9893, 'C-13': 0.0107, 'N-14': 0.99636,
'N-15': 0.00364, 'O-16': 0.99757, 'O-17': 0.00038,
'O-18': 0.00205, 'F-19': 1.0, 'Ne-20': 0.9048,
'Ne-21': 0.0027, 'Ne-22': 0.0925, 'Na-23': 1.0,
'Mg-24': 0.7899, 'Mg-25': 0.1, 'Mg-26': 0.1101,
'Al-27': 1.0, 'Si-28': 0.92223, 'Si-29': 0.04685,
'Si-30': 0.03092, 'P-31': 1.0, 'S-32': 0.9499,
'S-33': 0.0075, 'S-34': 0.0425, 'S-36': 0.0001,
'Cl-35': 0.7576, 'Cl-37': 0.2424, 'Ar-36': 0.003336,
'Ar-38': 0.000629, 'Ar-40': 0.996035, 'K-39': 0.932581,
'K-40': 0.000117, 'K-41': 0.067302, 'Ca-40': 0.96941,
'Ca-42': 0.00647, 'Ca-43': 0.00135, 'Ca-44': 0.02086,
'Ca-46': 4e-05, 'Ca-48': 0.00187, 'Sc-45': 1.0,
'Ti-46': 0.0825, 'Ti-47': 0.0744, 'Ti-48': 0.7372,
'Ti-49': 0.0541, 'Ti-50': 0.0518, 'V-50': 0.0025,
'V-51': 0.9975, 'Cr-50': 0.04345, 'Cr-52': 0.83789,
'Cr-53': 0.09501, 'Cr-54': 0.02365, 'Mn-55': 1.0,
'Fe-54': 0.05845, 'Fe-56': 0.91754, 'Fe-57': 0.02119,
'Fe-58': 0.00282, 'Co-59': 1.0, 'Ni-58': 0.68077,
'Ni-60': 0.26223, 'Ni-61': 0.011399, 'Ni-62': 0.036346,
'Ni-64': 0.009255, 'Cu-63': 0.6915, 'Cu-65': 0.3085,
'Zn-64': 0.4917, 'Zn-66': 0.2773, 'Zn-67': 0.0404,
'Zn-68': 0.1845, 'Zn-70': 0.0061, 'Ga-69': 0.60108,
'Ga-71': 0.39892, 'Ge-70': 0.2057, 'Ge-72': 0.2745,
'Ge-73': 0.0775, 'Ge-74': 0.365, 'Ge-76': 0.0773,
'As-75': 1.0, 'Se-74': 0.0089, 'Se-76': 0.0937,
'Se-77': 0.0763, 'Se-78': 0.2377, 'Se-80': 0.4961,
'Se-82': 0.0873, 'Br-79': 0.5069, 'Br-81': 0.4931,
'Kr-78': 0.00355, 'Kr-80': 0.02286, 'Kr-82': 0.11593,
'Kr-83': 0.115, 'Kr-84': 0.56987, 'Kr-86': 0.17279,
'Rb-85': 0.7217, 'Rb-87': 0.2783, 'Sr-84': 0.0056,
'Sr-86': 0.0986, 'Sr-87': 0.07, 'Sr-88': 0.8258,
'Y-89': 1.0, 'Zr-90': 0.5145, 'Zr-91': 0.1122,
'Zr-92': 0.1715, 'Zr-94': 0.1738, 'Zr-96': 0.028,
'Nb-93': 1.0, 'Mo-92': 0.1453, 'Mo-94': 0.0915,
'Mo-95': 0.1584, 'Mo-96': 0.1667, 'Mo-97': 0.096,
'Mo-98': 0.2439, 'Mo-100': 0.0982, 'Ru-96': 0.0554,
'Ru-98': 0.0187, 'Ru-99': 0.1276, 'Ru-100': 0.126,
'Ru-101': 0.1706, 'Ru-102': 0.3155, 'Ru-104': 0.1862,
'Rh-103': 1.0, 'Pd-102': 0.0102, 'Pd-104': 0.1114,
'Pd-105': 0.2233, 'Pd-106': 0.2733, 'Pd-108': 0.2646,
'Pd-110': 0.1172, 'Ag-107': 0.51839, 'Ag-109': 0.48161,
'Cd-106': 0.0125, 'Cd-108': 0.0089, 'Cd-110': 0.1249,
'Cd-111': 0.128, 'Cd-112': 0.2413, 'Cd-113': 0.1222,
'Cd-114': 0.2873, 'Cd-116': 0.0749, 'In-113': 0.0429,
'In-115': 0.9571, 'Sn-112': 0.0097, 'Sn-114': 0.0066,
'Sn-115': 0.0034, 'Sn-116': 0.1454, 'Sn-117': 0.0768,
'Sn-118': 0.2422, 'Sn-119': 0.0859, 'Sn-120': 0.3258,
'Sn-122': 0.0463, 'Sn-124': 0.0579, 'Sb-121': 0.5721,
'Sb-123': 0.4279, 'Te-120': 0.0009, 'Te-122': 0.0255,
'Te-123': 0.0089, 'Te-124': 0.0474, 'Te-125': 0.0707,
'Te-126': 0.1884, 'Te-128': 0.3174, 'Te-130': 0.3408,
'I-127': 1.0, 'Xe-124': 0.000952, 'Xe-126': 0.00089,
'Xe-128': 0.019102, 'Xe-129': 0.264006, 'Xe-130': 0.04071,
'Xe-131': 0.212324, 'Xe-132': 0.269086, 'Xe-134': 0.104357,
'Xe-136': 0.088573, 'Cs-133': 1.0, 'Ba-130': 0.00106,
'Ba-132': 0.00101, 'Ba-134': 0.02417, 'Ba-135': 0.06592,
'Ba-136': 0.07854, 'Ba-137': 0.11232, 'Ba-138': 0.71698,
'La-138': 0.0008881, 'La-139': 0.9991119, 'Ce-136': 0.00185,
'Ce-138': 0.00251, 'Ce-140': 0.8845, 'Ce-142': 0.11114,
'Pr-141': 1.0, 'Nd-142': 0.27152, 'Nd-143': 0.12174,
'Nd-144': 0.23798, 'Nd-145': 0.08293, 'Nd-146': 0.17189,
'Nd-148': 0.05756, 'Nd-150': 0.05638, 'Sm-144': 0.0307,
'Sm-147': 0.1499, 'Sm-148': 0.1124, 'Sm-149': 0.1382,
'Sm-150': 0.0738, 'Sm-152': 0.2675, 'Sm-154': 0.2275,
'Eu-151': 0.4781, 'Eu-153': 0.5219, 'Gd-152': 0.002,
'Gd-154': 0.0218, 'Gd-155': 0.148, 'Gd-156': 0.2047,
'Gd-157': 0.1565, 'Gd-158': 0.2484, 'Gd-160': 0.2186,
'Tb-159': 1.0, 'Dy-156': 0.00056, 'Dy-158': 0.00095,
'Dy-160': 0.02329, 'Dy-161': 0.18889, 'Dy-162': 0.25475,
'Dy-163': 0.24896, 'Dy-164': 0.2826, 'Ho-165': 1.0,
'Er-162': 0.00139, 'Er-164': 0.01601, 'Er-166': 0.33503,
'Er-167': 0.22869, 'Er-168': 0.26978, 'Er-170': 0.1491,
'Tm-169': 1.0, 'Yb-168': 0.00123, 'Yb-170': 0.02982,
'Yb-171': 0.1409, 'Yb-172': 0.2168, 'Yb-173': 0.16103,
'Yb-174': 0.32026, 'Yb-176': 0.12996, 'Lu-175': 0.97401,
'Lu-176': 0.02599, 'Hf-174': 0.0016, 'Hf-176': 0.0526,
'Hf-177': 0.186, 'Hf-178': 0.2728, 'Hf-179': 0.1362,
'Hf-180': 0.3508, 'Ta-180': 0.0001201, 'Ta-181': 0.9998799,
'W-180': 0.0012, 'W-182': 0.265, 'W-183': 0.1431,
'W-184': 0.3064, 'W-186': 0.2843, 'Re-185': 0.374,
'Re-187': 0.626, 'Os-184': 0.0002, 'Os-186': 0.0159,
'Os-187': 0.0196, 'Os-188': 0.1324, 'Os-189': 0.1615,
'Os-190': 0.2626, 'Os-192': 0.4078, 'Ir-191': 0.373,
'Ir-193': 0.627, 'Pt-190': 0.00012, 'Pt-192': 0.00782,
'Pt-194': 0.3286, 'Pt-195': 0.3378, 'Pt-196': 0.2521,
'Pt-198': 0.07356, 'Au-197': 1.0, 'Hg-196': 0.0015,
'Hg-198': 0.0997, 'Hg-199': 0.1687, 'Hg-200': 0.231,
'Hg-201': 0.1318, 'Hg-202': 0.2986, 'Hg-204': 0.0687,
'Tl-203': 0.2952, 'Tl-205': 0.7048, 'Pb-204': 0.014,
'Pb-206': 0.241, 'Pb-207': 0.221, 'Pb-208': 0.524,
'Bi-209': 1.0, 'Th-232': 1.0, 'Pa-231': 1.0,
'U-234': 5.4e-05, 'U-235': 0.007204, 'U-238': 0.992742
}

View file

@ -1,6 +1,8 @@
import sys
from openmc.checkvalue import check_type
import openmc
from openmc.checkvalue import check_type, check_length
from openmc.data import natural_abundance
if sys.version_info[0] >= 3:
basestring = str
@ -97,7 +99,8 @@ class Element(object):
@name.setter
def name(self, name):
check_type('name', name, basestring)
check_type('element name', name, basestring)
check_length('element name', name, 1, 2)
self._name = name
@scattering.setter
@ -109,3 +112,22 @@ class Element(object):
raise ValueError(msg)
self._scattering = scattering
def expand(self):
"""Expand natural element into its naturally-occurring isotopes.
Returns
-------
isotopes : list
Naturally-occurring isotopes of the element. Each item of the list
is a tuple consisting of an openmc.Nuclide instance and the natural
abundance of the isotope.
"""
isotopes = []
for isotope, abundance in natural_abundance.items():
if isotope.startswith(self.name):
nuc = openmc.Nuclide(isotope, self.xs)
isotopes.append((nuc, abundance))
return isotopes

View file

@ -1,131 +1,103 @@
from __future__ import print_function
import subprocess
from numbers import Integral
import os
import sys
from openmc.checkvalue import check_type
if sys.version_info[0] >= 3:
basestring = str
class Executor(object):
"""Control execution of OpenMC
def _run(command, output, cwd):
# Launch a subprocess
p = subprocess.Popen(command, shell=True, cwd=cwd, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, universal_newlines=True)
Attributes
# Capture and re-print OpenMC output in real-time
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
def plot_geometry(output=True, openmc_exec='openmc', cwd='.'):
"""Run OpenMC in plotting mode
Parameters
----------
working_directory : str
Path to working directory to run in
output : bool
Capture OpenMC output from standard out
openmc_exec : str
Path to OpenMC executable
cwd : str, optional
Path to working directory to run in. Defaults to the current working directory.
"""
def __init__(self):
self._working_directory = '.'
return _run(openmc_exec + ' -p', output, cwd)
def _run_openmc(self, command, output):
# Launch a subprocess to run OpenMC
p = subprocess.Popen(command, shell=True,
cwd=self._working_directory,
stdout=subprocess.PIPE,
universal_newlines=True)
# Capture and re-print OpenMC output in real-time
while True:
# If OpenMC is finished, break loop
line = p.stdout.readline()
if not line and p.poll() != None:
break
def run(particles=None, threads=None, geometry_debug=False,
restart_file=None, tracks=False, mpi_procs=1, output=True,
openmc_exec='openmc', mpi_exec='mpiexec', cwd='.'):
"""Run an OpenMC simulation.
# If user requested output, print to screen
if output:
print(line, end='')
Parameters
----------
particles : int, optional
Number of particles to simulate per generation.
threads : int, optional
Number of OpenMP threads. If OpenMC is compiled with OpenMP threading
enabled, the default is implementation-dependent but is usually equal to
the number of hardware threads available (or a value set by the
OMP_NUM_THREADS environment variable).
geometry_debug : bool, optional
Turn on geometry debugging during simulation. Defaults to False.
restart_file : str, optional
Path to restart file to use
tracks : bool, optional
Write tracks for all particles. Defaults to False.
mpi_procs : int, optional
Number of MPI processes.
output : bool, optional
Capture OpenMC output from standard out. Defaults to True.
openmc_exec : str, optional
Path to OpenMC executable. Defaults to 'openmc'.
mpi_exec : str, optional
MPI execute command. Defaults to 'mpiexec'.
cwd : str, optional
Path to working directory to run in. Defaults to the current working directory.
# Return the returncode (integer, zero if no problems encountered)
return p.returncode
"""
@property
def working_directory(self):
return self._working_directory
post_args = ' '
pre_args = ''
@working_directory.setter
def working_directory(self, working_directory):
check_type("Executor's working directory", working_directory,
basestring)
if not os.path.isdir(working_directory):
msg = 'Unable to set Executor\'s working directory to "{0}" ' \
'which does not exist'.format(working_directory)
raise ValueError(msg)
if isinstance(particles, Integral) and particles > 0:
post_args += '-n {0} '.format(particles)
self._working_directory = working_directory
if isinstance(threads, Integral) and threads > 0:
post_args += '-s {0} '.format(threads)
def plot_geometry(self, output=True, openmc_exec='openmc'):
"""Run OpenMC in plotting mode"""
if geometry_debug:
post_args += '-g '
return self._run_openmc(openmc_exec + ' -p', output)
if isinstance(restart_file, basestring):
post_args += '-r {0} '.format(restart_file)
def run_simulation(self, particles=None, threads=None,
geometry_debug=False, restart_file=None,
tracks=False, mpi_procs=1, output=True,
openmc_exec='openmc', mpi_exec=None):
"""Run an OpenMC simulation.
if tracks:
post_args += '-t'
Parameters
----------
particles : int
Number of particles to simulate per generation
threads : int
Number of OpenMP threads
geometry_debug : bool
Turn on geometry debugging during simulation
restart_file : str
Path to restart file to use
tracks : bool
Write tracks for all particles
mpi_procs : int
Number of MPI processes
output : bool
Capture OpenMC output from standard out
openmc_exec : str
Path to OpenMC executable
if isinstance(mpi_procs, Integral) and mpi_procs > 1:
pre_args += '{} -n {} '.format(mpi_exec, mpi_procs)
"""
command = pre_args + openmc_exec + ' ' + post_args
post_args = ' '
pre_args = ''
if isinstance(particles, Integral) and particles > 0:
post_args += '-n {0} '.format(particles)
if isinstance(threads, Integral) and threads > 0:
post_args += '-s {0} '.format(threads)
if geometry_debug:
post_args += '-g '
if isinstance(restart_file, basestring):
post_args += '-r {0} '.format(restart_file)
if tracks:
post_args += '-t'
if isinstance(mpi_procs, Integral) and mpi_procs > 1:
np_present = True
else:
np_present = False
if mpi_exec is not None and isinstance(mpi_exec, basestring):
mpi_exec_present = True
else:
mpi_exec_present = False
if np_present or mpi_exec_present:
if mpi_exec_present:
pre_args += mpi_exec + ' '
else:
pre_args += 'mpirun '
pre_args += '-n {0} '.format(mpi_procs)
command = pre_args + openmc_exec + ' ' + post_args
return self._run_openmc(command, output)
return _run(command, output, cwd)

View file

@ -1,4 +1,4 @@
from collections import Iterable
from collections import Iterable, OrderedDict
import copy
from numbers import Real, Integral
import sys
@ -27,7 +27,8 @@ class Filter(object):
type : str
The type of the tally filter. Acceptable values are "universe",
"material", "cell", "cellborn", "surface", "mesh", "energy",
"energyout", and "distribcell".
"energyout", "distribcell", "mu", "polar", "azimuthal", and
"delayedgroup".
bins : Integral or Iterable of Integral or Iterable of Real
The bins for the filter. This takes on different meaning for different
filters. See the OpenMC online documentation for more details.
@ -515,7 +516,7 @@ class Filter(object):
return filter_bin
def get_pandas_dataframe(self, data_size, summary=None):
def get_pandas_dataframe(self, data_size, distribcell_paths=True):
"""Builds a Pandas DataFrame for the Filter's bins.
This method constructs a Pandas DataFrame object for the filter with
@ -530,12 +531,13 @@ class Filter(object):
----------
data_size : Integral
The total number of bins in the tally corresponding to this filter
summary : None or openmc.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.
distribcell_paths : bool, optional
Construct columns for distribcell tally filters (default is True).
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 assumes that all distribcell paths are
of the same length and do not have the same universes and cells but
different lattice cell indices.
Returns
-------
@ -553,7 +555,7 @@ class Filter(object):
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).
and x,y,z cell indices corresponding to each (distribcell paths).
For 'energy' and 'energyout' filters, the DataFrame includes one
column for the lower energy bound and one column for the upper
@ -565,8 +567,7 @@ class Filter(object):
Raises
------
ImportError
When Pandas is not installed, or summary info is requested but
OpenCG is not installed.
When Pandas is not installed
See also
--------
@ -625,106 +626,117 @@ class Filter(object):
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 Pandas Multi-index columns for each level in CSG tree
if distribcell_paths:
# Extract the OpenCG geometry from the Summary
opencg_geometry = summary.opencg_geometry
openmc_geometry = summary.openmc_geometry
# Distribcell paths require linked metadata from the Summary
if self.distribcell_paths is None:
msg = 'Unable to construct distribcell paths since ' \
'the Summary is not linked to the StatePoint'
raise ValueError(msg)
# Use OpenCG to compute the number of regions
opencg_geometry.initialize_cell_offsets()
num_regions = opencg_geometry.num_regions
# Make copy of array of distribcell paths to use in
# Pandas Multi-index column construction
distribcell_paths = copy.deepcopy(self.distribcell_paths)
num_offsets = len(distribcell_paths)
# Initialize a dictionary mapping OpenMC distribcell
# offsets to OpenCG LocalCoords linked lists
offsets_to_coords = {}
for offset, path in enumerate(self.distribcell_paths):
region = opencg_geometry.get_region_from_path(path)
coords = opencg_geometry.find_region(region)
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
# Loop over CSG levels in the distribcell paths
level_counter = 0
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 = {}
# Use level key as first index in Pandas Multi-index column
level_counter += 1
level_key = 'level {}'.format(level_counter)
# 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')
# Use the first distribcell path to determine if level
# is a universe/cell or lattice level
first_path = distribcell_paths[0]
next_index = first_path.index('-')
level = first_path[:next_index]
# 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)
# Trim universe/lattice info from path
first_path = first_path[next_index+2:]
# 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
# Create a dictionary for this level for Pandas Multi-index
level_dict = OrderedDict()
# Iterate over all regions (distribcell instances)
for offset in range(num_offsets):
coords = offsets_to_coords[offset]
# This level is a lattice (e.g., ID(x,y,z))
if '(' in level:
level_type = 'lattice'
# If entire LocalCoords has been unraveled into
# Multi-index columns already, continue
if coords is None:
continue
# Initialize prefix Multi-index keys
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')
# 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
# Allocate NumPy arrays for each CSG level and
# each Multi-index column in the DataFrame
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)
# This level is a universe / cell (e.g., ID->ID)
else:
level_type = 'universe'
# Initialize prefix Multi-index keys
univ_key = (level_key, 'univ', 'id')
cell_key = (level_key, 'cell', 'id')
# 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)
# Determine any levels remain in path
if '-' not in first_path:
levels_remain = False
# Populate Multi-index arrays with all distribcell paths
for i, path in enumerate(distribcell_paths):
if level_type == 'lattice':
# Extract lattice ID, indices from path
next_index = path.index('-')
lat_id_indices = path[:next_index]
# Trim lattice info from distribcell path
distribcell_paths[i] = path[next_index+2:]
# Extract the lattice cell indices from the path
i1 = lat_id_indices.index('(')
i2 = lat_id_indices.index(')')
i3 = lat_id_indices[i1+1:i2]
# Assign entry to Lattice Multi-index column
level_dict[lat_id_key][i] = path[:i1]
level_dict[lat_x_key][i] = int(i3.split(',')[0]) - 1
level_dict[lat_y_key][i] = int(i3.split(',')[1]) - 1
level_dict[lat_z_key][i] = int(i3.split(',')[2]) - 1
# Assign entry to Lattice Multi-index column
else:
# Reverse y index per lattice ordering in OpenCG
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._lattice.dimension[1] - coords._lat_y - 1
level_dict[lat_z_key][offset] = coords._lat_z
# Extract universe ID from path
next_index = path.index('-')
universe_id = int(path[:next_index])
# 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
# Trim universe info from distribcell path
path = path[next_index+2:]
# Extract cell ID from path
if '-' in path:
next_index = path.index('-')
cell_id = int(path[:next_index])
distribcell_paths[i] = path[next_index+2:]
else:
cell_id = int(path)
distribcell_paths[i] = ''
# Assign entry to Universe, Cell Multi-index columns
level_dict[univ_key][i] = universe_id
level_dict[cell_key][i] = cell_id
# Tile the Multi-index columns
for level_key, level_bins in level_dict.items():
@ -739,7 +751,7 @@ class Filter(object):
else:
level_df = pd.concat([level_df, pd.DataFrame(level_dict)], axis=1)
# Create DataFrame column for distribcell instances IDs
# Create DataFrame column for distribcell instance IDs
# NOTE: This is performed regardless of whether the user
# requests Summary geometric information
filter_bins = np.arange(self.num_bins)

View file

@ -23,7 +23,6 @@ class Geometry(object):
"""
def __init__(self):
# Initialize Geometry class attributes
self._root_universe = None
self._offsets = {}
@ -42,6 +41,27 @@ class Geometry(object):
self._root_universe = root_universe
def export_to_xml(self):
"""Create a geometry.xml file that can be used for a simulation.
"""
# Clear OpenMC written IDs used to optimize XML generation
openmc.universe.WRITTEN_IDS = {}
# Create XML representation
geometry_file = ET.Element("geometry")
self.root_universe.create_xml_subelement(geometry_file)
# Clean the indentation in the file to be user-readable
sort_xml_elements(geometry_file)
clean_xml_indentation(geometry_file)
# Write the XML Tree to the geometry.xml file
tree = ET.ElementTree(geometry_file)
tree.write("geometry.xml", xml_declaration=True, encoding='utf-8',
method="xml")
def get_cell_instance(self, path):
"""Return the instance number for the final cell in a geometry path.
@ -436,52 +456,3 @@ class Geometry(object):
lattices = list(lattices)
lattices.sort(key=lambda x: x.id)
return lattices
class GeometryFile(object):
"""Geometry file used for an OpenMC simulation. Corresponds directly to the
geometry.xml input file.
Attributes
----------
geometry : openmc.Geometry
The geometry to be used
"""
def __init__(self):
# Initialize GeometryFile class attributes
self._geometry = None
self._geometry_file = ET.Element("geometry")
@property
def geometry(self):
return self._geometry
@geometry.setter
def geometry(self, geometry):
check_type('the geometry', geometry, Geometry)
self._geometry = geometry
def export_to_xml(self):
"""Create a geometry.xml file that can be used for a simulation.
"""
# 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
sort_xml_elements(self._geometry_file)
clean_xml_indentation(self._geometry_file)
# Write the XML Tree to the geometry.xml file
tree = ET.ElementTree(self._geometry_file)
tree.write("geometry.xml", xml_declaration=True,
encoding='utf-8', method="xml")

View file

@ -7,7 +7,7 @@ import sys
import numpy as np
import openmc.checkvalue as cv
from openmc.universe import Universe, AUTO_UNIVERSE_ID
import openmc
if sys.version_info[0] >= 3:
basestring = str
@ -30,13 +30,13 @@ class Lattice(object):
Unique identifier for the lattice
name : str
Name of the lattice
pitch : float
Pitch of the lattice in cm
outer : int
The unique identifier of a universe to fill all space outside the
lattice
universes : numpy.ndarray of openmc.Universe
An array of universes filling each element of the lattice
pitch : Iterable of float
Pitch of the lattice in each direction in cm
outer : openmc.Universe
A universe to fill all space outside the lattice
universes : Iterable of Iterable of openmc.Universe
A two- or three-dimensional list/array of universes filling each element
of the lattice
"""
@ -93,9 +93,8 @@ class Lattice(object):
@id.setter
def id(self, lattice_id):
if lattice_id is None:
global AUTO_UNIVERSE_ID
self._id = AUTO_UNIVERSE_ID
AUTO_UNIVERSE_ID += 1
self._id = openmc.universe.AUTO_UNIVERSE_ID
openmc.universe.AUTO_UNIVERSE_ID += 1
else:
cv.check_type('lattice ID', lattice_id, Integral)
cv.check_greater_than('lattice ID', lattice_id, 0, equality=True)
@ -111,12 +110,12 @@ class Lattice(object):
@outer.setter
def outer(self, outer):
cv.check_type('outer universe', outer, Universe)
cv.check_type('outer universe', outer, openmc.Universe)
self._outer = outer
@universes.setter
def universes(self, universes):
cv.check_iterable_type('lattice universes', universes, Universe,
cv.check_iterable_type('lattice universes', universes, openmc.Universe,
min_depth=2, max_depth=3)
self._universes = np.asarray(universes)
@ -127,20 +126,20 @@ class Lattice(object):
-------
universes : collections.OrderedDict
Dictionary whose keys are universe IDs and values are
:class:`Universe` instances
:class:`openmc.Universe` instances
"""
univs = OrderedDict()
for k in range(len(self._universes)):
for j in range(len(self._universes[k])):
if isinstance(self._universes[k][j], Universe):
if isinstance(self._universes[k][j], openmc.Universe):
u = self._universes[k][j]
univs[u._id] = u
else:
for i in range(len(self._universes[k][j])):
u = self._universes[k][j][i]
assert isinstance(u, Universe)
assert isinstance(u, openmc.Universe)
univs[u._id] = u
if self.outer is not None:
@ -260,6 +259,14 @@ class RectLattice(Lattice):
lower_left : Iterable of float
The coordinates of the lower-left corner of the lattice. If the lattice
is two-dimensional, only the x- and y-coordinates are specified.
pitch : Iterable of float
Pitch of the lattice in the x, y, and (if applicable) z directions in
cm.
outer : openmc.Universe
A universe to fill all space outside the lattice
universes : Iterable of Iterable of openmc.Universe
A two- or three-dimensional list/array of universes filling each element
of the lattice
"""
@ -506,6 +513,19 @@ class HexLattice(Lattice):
center : Iterable of float
Coordinates of the center of the lattice. If the lattice does not have
axial sections then only the x- and y-coordinates are specified
pitch : Iterable of float
Pitch of the lattice in cm. The first item in the iterable specifies the
pitch in the radial direction and, if the lattice is 3D, the second item
in the iterable specifies the pitch in the axial direction.
outer : openmc.Universe
A universe to fill all space outside the lattice
universes : Iterable of Iterable of openmc.Universe
A two- or three-dimensional list/array of universes filling each element
of the lattice. Each sub-list corresponds to one ring of universes and
should be ordered from outermost ring to innermost ring. The universes
within each sub-list are ordered from the "top" and proceed in a
clockwise fashion. The :meth:`HexLattice.show_indices` method can be
used to help figure out indices for this property.
"""
@ -615,10 +635,10 @@ class HexLattice(Lattice):
# clockwise fashion.
# Check to see if the given universes look like a 2D or a 3D array.
if isinstance(self._universes[0][0], Universe):
if isinstance(self._universes[0][0], openmc.Universe):
n_dims = 2
elif isinstance(self._universes[0][0][0], Universe):
elif isinstance(self._universes[0][0][0], openmc.Universe):
n_dims = 3
else:
@ -636,7 +656,7 @@ class HexLattice(Lattice):
# Set the number of rings and make sure this number is consistent for
# all axial positions.
if n_dims == 3:
self.num_rings = len(self._universes)
self.num_rings = len(self._universes[0])
for rings in self._universes:
if len(rings) != self._num_rings:
msg = 'HexLattice ID={0:d} has an inconsistent number of ' \
@ -869,3 +889,107 @@ class HexLattice(Lattice):
# Join the rows together and return the string.
universe_ids = '\n'.join(rows)
return universe_ids
@staticmethod
def show_indices(num_rings):
"""Return a diagram of the hexagonal lattice layout with indices.
This method can be used to show the proper indices to be used when
setting the :attr:`HexLattice.universes` property. For example, running
this method with num_rings=3 will return the following diagram::
(0, 0)
(0,11) (0, 1)
(0,10) (1, 0) (0, 2)
(1, 5) (1, 1)
(0, 9) (2, 0) (0, 3)
(1, 4) (1, 2)
(0, 8) (1, 3) (0, 4)
(0, 7) (0, 5)
(0, 6)
Parameters
----------
num_rings : int
Number of rings in the hexagonal lattice
Returns
-------
str
Diagram of the hexagonal lattice showing indices
"""
# Find the largest string and count the number of digits so we can
# properly pad the output string later
largest_index = 6*(num_rings - 1)
n_digits_index = len(str(largest_index))
n_digits_ring = len(str(num_rings - 1))
str_form = '({{:{}}},{{:{}}})'.format(n_digits_ring, n_digits_index)
pad = ' '*(n_digits_index + n_digits_ring + 3)
# Initialize the list for each row.
rows = [[] for i in range(1 + 4 * (num_rings-1))]
middle = 2 * (num_rings - 1)
# Start with the degenerate first ring.
rows[middle] = [str_form.format(num_rings - 1, 0)]
# Add universes one ring at a time.
for r in range(1, num_rings):
# r_prime increments down while r increments up.
r_prime = num_rings - 1 - r
theta = 0
y = middle + 2*r
for i in range(r):
# Climb down the top-right.
rows[y].append(str_form.format(r_prime, theta))
y -= 1
theta += 1
for i in range(r):
# Climb down the right.
rows[y].append(str_form.format(r_prime, theta))
y -= 2
theta += 1
for i in range(r):
# Climb down the bottom-right.
rows[y].append(str_form.format(r_prime, theta))
y -= 1
theta += 1
for i in range(r):
# Climb up the bottom-left.
rows[y].insert(0, str_form.format(r_prime, theta))
y += 1
theta += 1
for i in range(r):
# Climb up the left.
rows[y].insert(0, str_form.format(r_prime, theta))
y += 2
theta += 1
for i in range(r):
# Climb up the top-left.
rows[y].insert(0, str_form.format(r_prime, theta))
y += 1
theta += 1
# Flip the rows and join each row into a single string.
rows = [pad.join(x) for x in rows[::-1]]
# Pad the beginning of the rows so they line up properly.
for y in range(num_rings - 1):
rows[y] = (num_rings - 1 - y)*pad + rows[y]
rows[-1 - y] = (num_rings - 1 - y)*pad + rows[-1 - y]
for y in range(num_rings % 2, num_rings, 2):
rows[middle + y] = pad + rows[middle + y]
if y != 0:
rows[middle - y] = pad + rows[middle - y]
# Join the rows together and return the string.
return '\n'.join(rows)

View file

@ -8,8 +8,9 @@ if sys.version_info[0] >= 3:
basestring = str
import openmc
from openmc.checkvalue import check_type, check_value, check_greater_than
import openmc.checkvalue as cv
from openmc.clean_xml import *
from openmc.data import natural_abundance
# A static variable for auto-generated Material IDs
@ -25,9 +26,6 @@ def reset_auto_material_id():
DENSITY_UNITS = ['g/cm3', 'g/cc', 'kg/cm3', 'atom/b-cm', 'atom/cm3', 'sum',
'macro']
# Constant for density when not needed
NO_DENSITY = 99999.
class Material(object):
"""A material composed of a collection of nuclides/elements that can be
@ -52,6 +50,14 @@ class Material(object):
Units used for `density`. Can be one of 'g/cm3', 'g/cc', 'kg/cm3',
'atom/b-cm', 'atom/cm3', 'sum', or 'macro'. The 'macro' unit only
applies in the case of a multi-group calculation.
elements : collections.OrderedDict
Dictionary whose keys are element names and values are 3-tuples
consisting of an :class:`openmc.Element` instance, the percent density,
and the percent type (atom or weight fraction).
nuclides : collections.OrderedDict
Dictionary whose keys are nuclide names and values are 3-tuples
consisting of an :class:`openmc.Nuclide` instance, the percent density,
and the percent type (atom or weight fraction).
"""
@ -141,9 +147,9 @@ class Material(object):
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))
percent = self._elements[element][1]
percent_type = self._elements[element][2]
string += '{0: <16}'.format('\t{0}'.format(element))
string += '=\t{0: <12} [{1}]\n'.format(percent, percent_type)
return string
@ -189,6 +195,14 @@ class Material(object):
def density_units(self):
return self._density_units
@property
def elements(self):
return self._elements
@property
def nuclides(self):
return self._nuclides
@property
def convert_to_distrib_comps(self):
return self._convert_to_distrib_comps
@ -205,45 +219,51 @@ class Material(object):
self._id = AUTO_MATERIAL_ID
AUTO_MATERIAL_ID += 1
else:
check_type('material ID', material_id, Integral)
check_greater_than('material ID', material_id, 0, equality=True)
cv.check_type('material ID', material_id, Integral)
cv.check_greater_than('material ID', material_id, 0, equality=True)
self._id = material_id
@name.setter
def name(self, name):
if name is not None:
check_type('name for Material ID="{0}"'.format(self._id),
name, basestring)
cv.check_type('name for Material ID="{0}"'.format(self._id),
name, basestring)
self._name = name
else:
self._name = ''
def set_density(self, units, density=NO_DENSITY):
def set_density(self, units, density=None):
"""Set the density of the material
Parameters
----------
units : str
Physical units of density
units : {'g/cm3', 'g/cc', 'km/cm3', 'atom/b-cm', 'atom/cm3', 'sum', 'macro'}
Physical units of density.
density : float, optional
Value of the density. Must be specified unless units is given as
'sum'.
"""
check_type('the density for Material ID="{0}"'.format(self._id),
density, Real)
check_value('density units', units, DENSITY_UNITS)
if density == NO_DENSITY and units is not 'sum':
msg = 'Unable to set the density Material ID="{0}" ' \
'because a density must be set when not using ' \
'sum unit'.format(self._id)
raise ValueError(msg)
self._density = density
cv.check_value('density units', units, DENSITY_UNITS)
self._density_units = units
if units is 'sum':
if density is not None:
msg = 'Density "{0}" for Material ID="{1}" is ignored ' \
'because the unit is "sum"'.format(density, self.id)
warnings.warn(msg)
else:
if density is None:
msg = 'Unable to set the density for Material ID="{0}" ' \
'because a density value must be given when not using ' \
'"sum" unit'.format(self.id)
raise ValueError(msg)
cv.check_type('the density for Material ID="{0}"'.format(self.id),
density, Real)
self._density = density
@distrib_otf_file.setter
def distrib_otf_file(self, filename):
# TODO: remove this when distributed materials are merged
@ -274,7 +294,7 @@ class Material(object):
Nuclide to add
percent : float
Atom or weight percent
percent_type : str
percent_type : {'ao', 'wo'}
'ao' for atom percent and 'wo' for weight percent
"""
@ -284,7 +304,7 @@ class Material(object):
'macroscopic data-set has already been added'.format(self._id)
raise ValueError(msg)
if not isinstance(nuclide, (openmc.Nuclide, str)):
if not isinstance(nuclide, (openmc.Nuclide, basestring)):
msg = 'Unable to add a Nuclide to Material ID="{0}" with a ' \
'non-Nuclide value "{1}"'.format(self._id, nuclide)
raise ValueError(msg)
@ -328,7 +348,9 @@ class Material(object):
del self._nuclides[nuclide._name]
def add_macroscopic(self, macroscopic):
"""Add a macroscopic to the material
"""Add a macroscopic to the material. This will also set the
density of the material to 1.0, unless it has been otherwise set,
as a default for Macroscopic cross sections.
Parameters
----------
@ -366,6 +388,14 @@ class Material(object):
'Material!'.format(self._id, macroscopic)
raise ValueError(msg)
# Generally speaking, the density for a macroscopic object will
# be 1.0. Therefore, lets set density to 1.0 so that the user
# doesnt need to set it unless its needed.
# Of course, if the user has already set a value of density,
# then we will not override it.
if self._density is None:
self.set_density('macro', 1.0)
def remove_macroscopic(self, macroscopic):
"""Remove a macroscopic from the material
@ -385,17 +415,21 @@ class Material(object):
if macroscopic._name == self._macroscopic.name:
self._macroscopic = None
def add_element(self, element, percent, percent_type='ao'):
def add_element(self, element, percent, percent_type='ao', expand=False):
"""Add a natural element to the material
Parameters
----------
element : openmc.Element
element : openmc.Element or str
Element to add
percent : float
Atom or weight percent
percent_type : str
'ao' for atom percent and 'wo' for weight percent
percent_type : {'ao', 'wo'}, optional
'ao' for atom percent and 'wo' for weight percent. Defaults to atom
percent.
expand : bool, optional
Whether to expand the natural element into its naturally-occurring
isotopes. Defaults to False.
"""
@ -404,7 +438,7 @@ class Material(object):
'macroscopic data-set has already been added'.format(self._id)
raise ValueError(msg)
if not isinstance(element, openmc.Element):
if not isinstance(element, (openmc.Element, basestring)):
msg = 'Unable to add an Element to Material ID="{0}" with a ' \
'non-Element value "{1}"'.format(self._id, element)
raise ValueError(msg)
@ -420,9 +454,20 @@ class Material(object):
raise ValueError(msg)
# Copy this Element to separate it from same Element in other Materials
element = deepcopy(element)
if isinstance(element, openmc.Element):
element = deepcopy(element)
else:
element = openmc.Element(element)
self._elements[element._name] = (element, percent, percent_type)
if expand:
if percent_type == 'wo':
raise NotImplementedError('Expanding natural element based on '
'weight percent is not yet supported.')
for isotope, abundance in element.expand():
self._nuclides[isotope.name] = (
isotope, percent*abundance, percent_type)
else:
self._elements[element.name] = (element, percent, percent_type)
def remove_element(self, element):
"""Remove a natural element from the material
@ -471,7 +516,7 @@ class Material(object):
for nuclide_name in self._nuclides:
self._nuclides[nuclide_name][0].scattering = 'iso-in-lab'
for element_name in self._elements:
self._element[element_name][0].scattering = 'iso-in-lab'
self._elements[element_name][0].scattering = 'iso-in-lab'
def get_all_nuclides(self):
"""Returns all nuclides in the material
@ -491,6 +536,14 @@ class Material(object):
density = nuclide_tuple[1]
nuclides[nuclide._name] = (nuclide, density)
for element_name, element_tuple in self._elements.items():
element = element_tuple[0]
density = element_tuple[1]
# Expand natural element into isotopes
for isotope, abundance in element.expand():
nuclides[isotope.name] = (isotope, density*abundance)
return nuclides
def _get_nuclide_xml(self, nuclide, distrib=False):
@ -498,7 +551,7 @@ class Material(object):
xml_element.set("name", nuclide[0]._name)
if not distrib:
if nuclide[2] is 'ao':
if nuclide[2] == 'ao':
xml_element.set("ao", str(nuclide[1]))
else:
xml_element.set("wo", str(nuclide[1]))
@ -525,11 +578,14 @@ class Material(object):
xml_element.set("name", str(element[0]._name))
if not distrib:
if element[2] is 'ao':
if element[2] == 'ao':
xml_element.set("ao", str(element[1]))
else:
xml_element.set("wo", str(element[1]))
if element[0].xs is not None:
xml_element.set("xs", element[0].xs)
if not element[0].scattering is None:
xml_element.set("scattering", element[0].scattering)
@ -639,9 +695,25 @@ class Material(object):
return element
class MaterialsFile(object):
"""Materials file used for an OpenMC simulation. Corresponds directly to the
materials.xml input file.
class Materials(cv.CheckedList):
"""Collection of Materials used for an OpenMC simulation.
This class corresponds directly to the materials.xml input file. It can be
thought of as a normal Python list where each member is a
:class:`Material`. It behaves like a list as the following example
demonstrates:
>>> fuel = openmc.Material()
>>> clad = openmc.Material()
>>> water = openmc.Material()
>>> m = openmc.Materials([fuel])
>>> m.append(water)
>>> m += [clad]
Parameters
----------
materials : Iterable of openmc.Material
Materials to add to the collection
Attributes
----------
@ -651,11 +723,12 @@ class MaterialsFile(object):
"""
def __init__(self):
# Initialize MaterialsFile class attributes
self._materials = []
def __init__(self, materials=None):
super(Materials, self).__init__(Material, 'materials collection')
self._default_xs = None
self._materials_file = ET.Element("materials")
if materials is not None:
self += materials
@property
def default_xs(self):
@ -663,11 +736,14 @@ class MaterialsFile(object):
@default_xs.setter
def default_xs(self, xs):
check_type('default xs', xs, basestring)
cv.check_type('default xs', xs, basestring)
self._default_xs = xs
def add_material(self, material):
"""Add a material to the file.
"""Append material to collection
.. deprecated:: 0.8
Use :meth:`Materials.append` instead.
Parameters
----------
@ -675,51 +751,72 @@ class MaterialsFile(object):
Material to add
"""
if not isinstance(material, Material):
msg = 'Unable to add a non-Material "{0}" to the ' \
'MaterialsFile'.format(material)
raise ValueError(msg)
self._materials.append(material)
warnings.warn("Materials.add_material(...) has been deprecated and may be "
"removed in a future version. Use Material.append(...) "
"instead.", DeprecationWarning)
self.append(material)
def add_materials(self, materials):
"""Add multiple materials to the file.
"""Add multiple materials to the collection
.. deprecated:: 0.8
Use compound assignment instead.
Parameters
----------
materials : tuple or list of openmc.Material
materials : Iterable of openmc.Material
Materials to add
"""
if not isinstance(materials, Iterable):
msg = 'Unable to create OpenMC materials.xml file from "{0}" which ' \
'is not iterable'.format(materials)
raise ValueError(msg)
warnings.warn("Materials.add_materials(...) has been deprecated and may be "
"removed in a future version. Use compound assignment "
"instead.", DeprecationWarning)
for material in materials:
self.add_material(material)
self.append(material)
def append(self, material):
"""Append material to collection
Parameters
----------
material : openmc.Material
Material to append
"""
super(Materials, self).append(material)
def insert(self, index, material):
"""Insert material before index
Parameters
----------
index : int
Index in list
material : openmc.Material
Material to insert
"""
super(Materials, self).insert(index, material)
def remove_material(self, material):
"""Remove a material from the file
.. deprecated:: 0.8
Use :meth:`Materials.remove` instead.
Parameters
----------
material : openmc.Material
Material to remove
"""
if not isinstance(material, Material):
msg = 'Unable to remove a non-Material "{0}" from the ' \
'MaterialsFile'.format(material)
raise ValueError(msg)
self._materials.remove(material)
warnings.warn("Materials.remove_material(...) has been deprecated and "
"may be removed in a future version. Use "
"Materials.remove(...) instead.", DeprecationWarning)
self.remove(material)
def make_isotropic_in_lab(self):
for material in self._materials:
for material in self:
material.make_isotropic_in_lab()
def _create_material_subelements(self):
@ -727,7 +824,7 @@ class MaterialsFile(object):
subelement = ET.SubElement(self._materials_file, "default_xs")
subelement.text = self._default_xs
for material in self._materials:
for material in self:
xml_element = material.get_material_xml()
self._materials_file.append(xml_element)

View file

@ -2,8 +2,12 @@ import sys
import os
import copy
import pickle
import warnings
from numbers import Integral
from collections import OrderedDict
from warnings import warn
import numpy as np
import openmc
import openmc.mgxs
@ -57,6 +61,8 @@ class Library(object):
The spatial domain(s) for which MGXS in the Library are computed
correction : {'P0', None}
Apply the P0 correction to scattering matrices if set to 'P0'
legendre_order : int
The highest legendre moment in the scattering matrices (default is 0)
energy_groups : openmc.mgxs.EnergyGroups
Energy group structure for energy condensation
tally_trigger : openmc.Trigger
@ -89,8 +95,9 @@ class Library(object):
self._mgxs_types = []
self._domain_type = None
self._domains = 'all'
self._correction = 'P0'
self._energy_groups = None
self._correction = 'P0'
self._legendre_order = 0
self._tally_trigger = None
self._all_mgxs = OrderedDict()
self._sp_filename = None
@ -118,6 +125,7 @@ class Library(object):
clone._domain_type = self.domain_type
clone._domains = copy.deepcopy(self.domains)
clone._correction = self.correction
clone._legendre_order = self.legendre_order
clone._energy_groups = copy.deepcopy(self.energy_groups, memo)
clone._tally_trigger = copy.deepcopy(self.tally_trigger, memo)
clone._all_mgxs = copy.deepcopy(self.all_mgxs)
@ -185,13 +193,17 @@ class Library(object):
else:
return self._domains
@property
def energy_groups(self):
return self._energy_groups
@property
def correction(self):
return self._correction
@property
def energy_groups(self):
return self._energy_groups
def legendre_order(self):
return self._legendre_order
@property
def tally_trigger(self):
@ -245,7 +257,7 @@ class Library(object):
@domain_type.setter
def domain_type(self, domain_type):
cv.check_value('domain type', domain_type, tuple(openmc.mgxs.DOMAIN_TYPES))
cv.check_value('domain type', domain_type, openmc.mgxs.DOMAIN_TYPES)
self._domain_type = domain_type
@domains.setter
@ -280,16 +292,36 @@ class Library(object):
self._domains = domains
@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
@correction.setter
def correction(self, correction):
cv.check_value('correction', correction, ('P0', None))
if correction == 'P0' and self.legendre_order > 0:
msg = 'The P0 correction will be ignored since the scattering ' \
'order {} is greater than zero'.format(self.legendre_order)
warnings.warn(msg)
self._correction = correction
@legendre_order.setter
def legendre_order(self, legendre_order):
cv.check_type('legendre_order', legendre_order, Integral)
cv.check_greater_than('legendre_order', legendre_order, 0, equality=True)
cv.check_less_than('legendre_order', legendre_order, 10, equality=True)
if self.correction == 'P0' and legendre_order > 0:
msg = 'The P0 correction will be ignored since the scattering ' \
'order {} is greater than zero'.format(self.legendre_order)
warnings.warn(msg, RuntimeWarning)
self.correction = None
self._legendre_order = legendre_order
@tally_trigger.setter
def tally_trigger(self, tally_trigger):
cv.check_type('tally trigger', tally_trigger, openmc.Trigger)
@ -344,6 +376,7 @@ class Library(object):
# Specify whether to use a transport ('P0') correction
if isinstance(mgxs, openmc.mgxs.ScatterMatrixXS):
mgxs.correction = self.correction
mgxs.legendre_order = self.legendre_order
self.all_mgxs[domain.id][mgxs_type] = mgxs
@ -354,23 +387,23 @@ class Library(object):
Parameters
----------
tallies_file : openmc.TalliesFile
A TalliesFile object to add each MGXS' tallies to generate a
"tallies.xml" input file for OpenMC
tallies_file : openmc.Tallies
A Tallies collection 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)
cv.check_type('tallies_file', tallies_file, openmc.Tallies)
# 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)
tallies_file.append(tally, merge=merge)
def load_from_statepoint(self, statepoint):
"""Extracts tallies in an OpenMC StatePoint with the data needed to
@ -403,6 +436,7 @@ class Library(object):
self._sp_filename = statepoint._f.filename
self._openmc_geometry = statepoint.summary.openmc_geometry
self._nuclides = statepoint.summary.nuclides
if statepoint.run_mode == 'k-eigenvalue':
self._keff = statepoint.k_combined[0]
@ -426,7 +460,7 @@ class Library(object):
----------
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', 'kappa-fission', 'scatter', 'nu-scatter', 'scatter matrix', 'nu-scatter matrix', 'chi'}
mgxs_type : {'total', 'transport', 'nu-transport', 'absorption', 'capture', 'fission', 'nu-fission', 'kappa-fission', 'scatter', 'nu-scatter', 'scatter matrix', 'nu-scatter matrix', 'chi'}
The type of multi-group cross section object to return
Returns
@ -456,7 +490,7 @@ class Library(object):
if domain_id == domain.id:
break
else:
msg = 'Unable to find MGXS for {0} "{1}" in ' \
msg = 'Unable to find MGXS for "{0}" "{1}" in ' \
'library'.format(self.domain_type, domain_id)
raise ValueError(msg)
else:
@ -575,7 +609,8 @@ class Library(object):
return subdomain_avg_library
def build_hdf5_store(self, filename='mgxs.h5', directory='mgxs',
subdomains='all', nuclides='all', xs_type='macro'):
subdomains='all', nuclides='all', xs_type='macro',
row_column='inout'):
"""Export the multi-group cross section library to an HDF5 binary file.
This method constructs an HDF5 file which stores the library's
@ -605,6 +640,10 @@ class Library(object):
xs_type: {'macro', 'micro'}
Store the macro or micro cross section in units of cm^-1 or barns.
Defaults to 'macro'.
row_column: {'inout', 'outin'}
Store scattering matrices indexed first by incoming group and
second by outgoing group ('inout'), or vice versa ('outin').
Defaults to 'inout'.
Raises
------
@ -635,7 +674,7 @@ class Library(object):
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.attrs['# groups'] = self.num_groups
f.close()
# Export MGXS for each domain and mgxs type to an HDF5 file
@ -646,8 +685,8 @@ class Library(object):
if subdomains == 'avg':
mgxs = mgxs.get_subdomain_avg_xs()
mgxs.build_hdf5_store(filename, directory,
xs_type=xs_type, nuclides=nuclides)
mgxs.build_hdf5_store(filename, directory, xs_type=xs_type,
nuclides=nuclides, row_column=row_column)
def dump_to_file(self, filename='mgxs', directory='mgxs'):
"""Store this Library object in a pickle binary file.
@ -712,3 +751,395 @@ class Library(object):
# Load and return pickled Library object
return pickle.load(open(full_filename, 'rb'))
def get_xsdata(self, domain, xsdata_name, nuclide='total', xs_type='macro',
xs_id='1m', order=None):
"""Generates an openmc.XSdata object describing a multi-group cross section
data set for eventual combination in to an openmc.MGXSLibrary object
(i.e., the library).
Parameters
----------
domain : openmc.Material or openmc.Cell or openmc.Universe
The domain for spatial homogenization
xsdata_name : str
Name to apply to the "xsdata" entry produced by this method
nuclide : str
A nuclide name string (e.g., 'U-235'). Defaults to 'total' to
obtain a material-wise macroscopic cross section.
xs_type: {'macro', 'micro'}
Provide the macro or micro cross section in units of cm^-1 or
barns. Defaults to 'macro'. If the Library object is not tallied by
nuclide this will be set to 'macro' regardless.
xs_ids : str
Cross section set identifier. Defaults to '1m'.
order : Scattering order for this data entry. Default is None,
which will set the XSdata object to use the order of the
Library.
Returns
-------
xsdata : openmc.XSdata
Multi-Group Cross Section data set object.
Raises
------
ValueError
When the Library object is initialized with insufficient types of
cross sections for the Library.
See also
--------
Library.create_mg_library()
"""
cv.check_type('domain', domain, (openmc.Material, openmc.Cell,
openmc.Cell))
cv.check_type('xsdata_name', xsdata_name, basestring)
cv.check_type('nuclide', nuclide, basestring)
cv.check_value('xs_type', xs_type, ['macro', 'micro'])
cv.check_type('xs_id', xs_id, basestring)
cv.check_type('order', order, (type(None), Integral))
if order is not None:
cv.check_greater_than('order', order, 0, equality=True)
cv.check_less_than('order', order, 10, equality=True)
# Make sure statepoint has been loaded
if self._sp_filename is None:
msg = 'A StatePoint must be loaded before calling ' \
'the create_mg_library() function'
raise ValueError(msg)
# If gathering material-specific data, set the xs_type to macro
if not self.by_nuclide:
xs_type = 'macro'
# Build & add metadata to XSdata object
name = xsdata_name
if nuclide is not 'total':
name += '_' + nuclide
name += '.' + xs_id
xsdata = openmc.XSdata(name, self.energy_groups)
if order is None:
# Set the order to the Library's order (the defualt behavior)
xsdata.order = self.legendre_order
else:
# Set the order of the xsdata object to the minimum of
# the provided order or the Library's order.
xsdata.order = min(order, self.legendre_order)
if nuclide is not 'total':
xsdata.zaid = self._nuclides[nuclide][0]
xsdata.awr = self._nuclides[nuclide][1]
# Now get xs data itself
if 'nu-transport' in self.mgxs_types and self.correction == 'P0':
mymgxs = self.get_mgxs(domain, 'nu-transport')
xsdata.set_total_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide])
elif 'total' in self.mgxs_types:
mymgxs = self.get_mgxs(domain, 'total')
xsdata.set_total_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide])
if 'absorption' in self.mgxs_types:
mymgxs = self.get_mgxs(domain, 'absorption')
xsdata.set_absorption_mgxs(mymgxs, xs_type=xs_type,
nuclide=[nuclide])
if 'fission' in self.mgxs_types:
mymgxs = self.get_mgxs(domain, 'fission')
xsdata.set_fission_mgxs(mymgxs, xs_type=xs_type,
nuclide=[nuclide])
if 'kappa-fission' in self.mgxs_types:
mymgxs = self.get_mgxs(domain, 'kappa-fission')
xsdata.set_kappa_fission_mgxs(mymgxs, xs_type=xs_type,
nuclide=[nuclide])
if 'chi' in self.mgxs_types:
mymgxs = self.get_mgxs(domain, 'chi')
xsdata.set_chi_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide])
if 'nu-fission' in self.mgxs_types:
mymgxs = self.get_mgxs(domain, 'nu-fission')
xsdata.set_nu_fission_mgxs(mymgxs, xs_type=xs_type,
nuclide=[nuclide])
# multiplicity requires scatter and nu-scatter
if ((('scatter matrix' in self.mgxs_types) and
('nu-scatter matrix' in self.mgxs_types))):
scatt_mgxs = self.get_mgxs(domain, 'scatter matrix')
nuscatt_mgxs = self.get_mgxs(domain, 'nu-scatter matrix')
xsdata.set_multiplicity_mgxs(nuscatt_mgxs, scatt_mgxs,
xs_type=xs_type, nuclide=[nuclide])
using_multiplicity = True
else:
using_multiplicity = False
if using_multiplicity:
nuscatt_mgxs = self.get_mgxs(domain, 'nu-scatter matrix')
xsdata.set_scatter_mgxs(nuscatt_mgxs, xs_type=xs_type,
nuclide=[nuclide])
else:
if 'nu-scatter matrix' in self.mgxs_types:
nuscatt_mgxs = self.get_mgxs(domain, 'nu-scatter matrix')
xsdata.set_scatter_mgxs(nuscatt_mgxs, xs_type=xs_type,
nuclide=[nuclide])
# Since we are not using multiplicity, then
# scattering multiplication (nu-scatter) must be
# accounted for approximately by using an adjusted
# absorption cross section.
if 'total' in self.mgxs_types:
xsdata._absorption = \
np.subtract(xsdata.total,
np.sum(xsdata.scatter[0, :, :], axis=1))
return xsdata
def create_mg_library(self, xs_type='macro', xsdata_names=None,
xs_ids=None):
"""Creates an openmc.MGXSLibrary object to contain the MGXS data for the
Multi-Group mode of OpenMC.
Parameters
----------
xs_type: {'macro', 'micro'}
Provide the macro or micro cross section in units of cm^-1 or
barns. Defaults to 'macro'. If the Library object is not tallied by
nuclide this will be set to 'macro' regardless.
xsdata_names : Iterable of str
List of names to apply to the "xsdata" entries in the
resultant mgxs data file. Defaults to 'set1', 'set2', ...
xs_ids : str or Iterable of str
Cross section set identifier (i.e., '71c') for all
data sets (if only str) or for each individual one
(if iterable of str). Defaults to '1m'.
Returns
-------
mgxs_file : openmc.MGXSLibrary
Multi-Group Cross Section File that is ready to be printed to the
file of choice by the user.
Raises
------
ValueError
When the Library object is initialized with insufficient types of
cross sections for the Library.
See also
--------
Library.dump_to_file()
"""
# Check to ensure the Library contains the correct
# multi-group cross section types
self.check_library_for_openmc_mgxs()
cv.check_value('xs_type', xs_type, ['macro', 'micro'])
if xsdata_names is not None:
cv.check_iterable_type('xsdata_names', xsdata_names, basestring)
if xs_ids is not None:
if isinstance(xs_ids, basestring):
# If we only have a string lets convert it now to a list
# of strings.
xs_ids = [xs_ids for i in range(len(self.domains))]
else:
cv.check_iterable_type('xs_ids', xs_ids, basestring)
else:
xs_ids = ['1m' for i in range(len(self.domains))]
# If gathering material-specific data, set the xs_type to macro
if not self.by_nuclide:
xs_type = 'macro'
# Initialize file
mgxs_file = openmc.MGXSLibrary(self.energy_groups)
# Create the xsdata object and add it to the mgxs_file
for i, domain in enumerate(self.domains):
if self.by_nuclide:
nuclides = list(domain.get_all_nuclides().keys())
else:
nuclides = ['total']
for nuclide in nuclides:
# Build & add metadata to XSdata object
if xsdata_names is None:
xsdata_name = 'set' + str(i + 1)
else:
xsdata_name = xsdata_names[i]
if nuclide is not 'total':
xsdata_name += '_' + nuclide
xsdata = self.get_xsdata(domain, xsdata_name, nuclide=nuclide,
xs_type=xs_type, xs_id=xs_ids[i])
mgxs_file.add_xsdata(xsdata)
return mgxs_file
def create_mg_library_and_materials(self, xsdata_names=None, xs_ids=None,
material_ids=None):
"""Creates an openmc.MGXSLibrary object to contain the MGXS data for the
Multi-Group mode of OpenMC as well as the associated openmc.Materials
objects. This method cannot be used for Library objects with
`Library.by_nuclide == True` since the materials to output would be
problem dependent and thus any Materials object produced by this method
would not be useful.
Parameters
----------
xsdata_names : Iterable of str
List of names to apply to the "xsdata" entries in the
resultant mgxs data file. Defaults to 'set1', 'set2', ...
xs_ids : str or Iterable of str
Cross section set identifier (i.e., '71c') for all
data sets (if only str) or for each individual one
(if iterable of str). Defaults to '1m'.
material_ids : None or Iterable of Integral
An optional list of material IDs to pass to the materials in
materials_file. Defaults to `None` implying the materials will be
given an ID number which matches the index of the domain in
`self.domains`
Returns
-------
mgxs_file : openmc.MGXSLibrary
Multi-Group Cross Section File that is ready to be printed to the
file of choice by the user.
materials_file : openmc.Materials
Materials file ready to be printed with all the macroscopic data
present within this Library.
Raises
------
ValueError
When the Library object is initialized with insufficient types of
cross sections for the Library.
See also
--------
Library.create_mg_library()
Library.dump_to_file()
"""
# Check to ensure the Library contains the correct
# multi-group cross section types
self.check_library_for_openmc_mgxs()
if xsdata_names is not None:
cv.check_iterable_type('xsdata_names', xsdata_names, basestring)
if xs_ids is not None:
if isinstance(xs_ids, basestring):
# If we only have a string lets convert it now to a list
# of strings.
xs_ids = [xs_ids for i in range(len(self.domains))]
else:
cv.check_iterable_type('xs_ids', xs_ids, basestring)
else:
xs_ids = ['1m' for i in range(len(self.domains))]
if material_ids is not None:
cv.check_iterable_type('material_ids', material_ids, Integral)
xs_type = 'macro'
# Initialize files
mgxs_file = openmc.MGXSLibrary(self.energy_groups)
materials = []
macroscopics = []
nuclide = 'total'
# Create the xsdata object and add it to the mgxs_file
for i, domain in enumerate(self.domains):
# Build & add metadata to XSdata object
if xsdata_names is None:
xsdata_name = 'set' + str(i + 1)
else:
xsdata_name = xsdata_names[i]
xsdata = self.get_xsdata(domain, xsdata_name, nuclide=nuclide,
xs_type=xs_type, xs_id=xs_ids[i])
mgxs_file.add_xsdata(xsdata)
macroscopics.append(openmc.Macroscopic(name=xsdata_name,
xs=xs_ids[i]))
if material_ids is not None:
mat_id = material_ids[i]
else:
mat_id = i
materials.append(openmc.Material(name=xsdata_name + '.' +
xs_ids[i], material_id=mat_id))
materials[-1].add_macroscopic(macroscopics[-1])
materials_file = openmc.Materials(materials)
return (mgxs_file, materials_file)
def check_library_for_openmc_mgxs(self):
"""This routine will check the MGXS Types within a Library
to ensure the MGXS types provided can be used to create
a MGXS Library for OpenMC's Multi-Group mode.
The rules to check include:
- Either total or transport should be present.
- Both can be available if one wants, but we should
use whatever corresponds to Library.correction (if P0: transport)
- Absorption and total (or transport) are required.
- A nu-fission cross section and chi values are not required as a
fixed source problem could be the target.
- Fission and kappa-fission are not required as they are only
needed to support tallies the user may wish to request.
- A nu-scatter matrix is required.
- Having both nu-scatter (of any order) and scatter
(at least isotropic) matrices is preferred
- If only nu-scatter, need total (not transport), to
be used in adjusting absorption
(i.e., reduced_abs = tot - nuscatt)
See also
--------
Library.create_mg_library()
"""
error_flag = False
# Ensure absorption is present
if 'absorption' not in self.mgxs_types:
error_flag = True
msg = '"absorption" MGXS type is required but not provided.'
warn(msg)
# Ensure nu-scattering matrix is required
if 'nu-scatter matrix' not in self.mgxs_types:
error_flag = True
msg = '"nu-scatter matrix" MGXS type is required but not provided.'
warn(msg)
else:
# Ok, now see the status of scatter
if 'scatter matrix' not in self.mgxs_types:
# We dont have both nu-scatter and scatter, therefore
# we need total, and not transport.
if 'total' not in self.mgxs_types:
error_flag = True
msg = '"total" MGXS type is required if a ' \
'scattering matrix is not provided.'
warn(msg)
# Total or transport can be present, but if using
# self.correction=="P0", then we should use transport.
if (((self.correction is "P0") and
('nu-transport' not in self.mgxs_types))):
error_flag = True
msg = 'A "nu-transport" MGXS type is required since a "P0" ' \
'correction is applied, but a "nu-transport" MGXS is ' \
'not provided.'
warn(msg)
elif (((self.correction is None) and
('total' not in self.mgxs_types))):
error_flag = True
msg = '"total" MGXS type is required, but not provided.'
warn(msg)
if error_flag:
msg = 'Invalid MGXS configuration encountered.'
raise ValueError(msg)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -393,9 +393,9 @@ def get_compatible_opencg_surfaces(opencg_surface):
surfaces = [left, right, bottom, top]
elif opencg_surface.type == 'z-squareprism':
x0 = opencg_surface.x0['x0']
y0 = opencg_surface.y0['y0']
R = opencg_surface.r['R']
x0 = opencg_surface.x0
y0 = opencg_surface.y0
R = opencg_surface.r
# Create a list of the four planes we need
left = opencg.XPlane(name=name, boundary=boundary, x0=x0-R)
@ -528,7 +528,7 @@ def get_compatible_opencg_cells(opencg_cell, opencg_surface, halfspace):
# Get the compatible Surfaces (XPlanes and YPlanes)
compatible_surfaces = get_compatible_opencg_surfaces(opencg_surface)
opencg_cell.removeSurface(opencg_surface)
opencg_cell.remove_surface(opencg_surface)
# If Cell is inside SquarePrism, add "inside" of Surface halfspaces
if halfspace == -1:
@ -595,7 +595,7 @@ def get_compatible_opencg_cells(opencg_cell, opencg_surface, halfspace):
# Remove redundant Surfaces from the Cells
for cell in compatible_cells:
cell.removeRedundantSurfaces()
cell.remove_redundant_surfaces()
# Return the list of OpenMC compatible OpenCG Cells
return compatible_cells
@ -639,7 +639,7 @@ def make_opencg_cells_compatible(opencg_universe):
surface, halfspace)
# Remove the non-compatible OpenCG Cell from the Universe
opencg_universe.removeCell(opencg_cell)
opencg_universe.remove_cell(opencg_cell)
# Add the compatible OpenCG Cells to the Universe
opencg_universe.add_cells(cells)

View file

@ -2,6 +2,7 @@ from collections import Iterable
from numbers import Real, Integral
from xml.etree import ElementTree as ET
import sys
import warnings
import numpy as np
@ -125,7 +126,7 @@ class Plot(object):
return self._background
@property
def mask_componenets(self):
def mask_components(self):
return self._mask_components
@property
@ -227,7 +228,7 @@ class Plot(object):
self._col_spec = col_spec
@mask_componenets.setter
@mask_components.setter
def mask_components(self, mask_components):
cv.check_type('plot mask_components', mask_components, Iterable, Integral)
for component in mask_components:
@ -401,44 +402,90 @@ class Plot(object):
return element
class PlotsFile(object):
"""Plots file used for an OpenMC simulation. Corresponds directly to the
plots.xml input file.
class Plots(cv.CheckedList):
"""Collection of Plots used for an OpenMC simulation.
This class corresponds directly to the plots.xml input file. It can be
thought of as a normal Python list where each member is a :class:`Plot`. It
behaves like a list as the following example demonstrates:
>>> xz_plot = openmc.Plot()
>>> big_plot = openmc.Plot()
>>> small_plot = openmc.Plot()
>>> p = openmc.Plots((xz_plot, big_plot))
>>> p.append(small_plot)
>>> small_plot = p.pop()
Parameters
----------
plots : Iterable of openmc.Plot
Plots to add to the collection
"""
def __init__(self):
# Initialize PlotsFile class attributes
self._plots = []
def __init__(self, plots=None):
super(Plots, self).__init__(Plot, 'plots collection')
self._plots_file = ET.Element("plots")
if plots is not None:
self += plots
def add_plot(self, plot):
"""Add a plot to the file.
.. deprecated:: 0.8
Use :meth:`Plots.append` instead.
Parameters
----------
plot : openmc.Plot
Plot to add
"""
warnings.warn("Plots.add_plot(...) has been deprecated and may be "
"removed in a future version. Use Plots.append(...) "
"instead.", DeprecationWarning)
self.append(plot)
if not isinstance(plot, Plot):
msg = 'Unable to add a non-Plot "{0}" to the PlotsFile'.format(plot)
raise ValueError(msg)
def append(self, plot):
"""Append plot to collection
self._plots.append(plot)
Parameters
----------
plot : openmc.Plot
Plot to append
"""
super(Plots, self).append(plot)
def insert(self, index, plot):
"""Insert plot before index
Parameters
----------
index : int
Index in list
plot : openmc.Plot
Plot to insert
"""
super(Plots, self).insert(index, plot)
def remove_plot(self, plot):
"""Remove a plot from the file.
.. deprecated:: 0.8
Use :meth:`Plots.remove` instead.
Parameters
----------
plot : openmc.Plot
Plot to remove
"""
self._plots.remove(plot)
warnings.warn("Plots.remove_plot(...) has been deprecated and may be "
"removed in a future version. Use Plots.remove(...) "
"instead.", DeprecationWarning)
self.remove(plot)
def colorize(self, geometry, seed=1):
"""Generate a consistent color scheme for each domain in each plot.
@ -456,7 +503,7 @@ class PlotsFile(object):
"""
for plot in self._plots:
for plot in self:
plot.colorize(geometry, seed)
@ -482,11 +529,11 @@ class PlotsFile(object):
"""
for plot in self._plots:
for plot in self:
plot.highlight_domains(geometry, domains, seed, alpha, background)
def _create_plot_subelements(self):
for plot in self._plots:
for plot in self:
xml_element = plot.get_plot_xml()
if len(plot._name) > 0:

View file

@ -16,7 +16,7 @@ if sys.version_info[0] >= 3:
basestring = str
class SettingsFile(object):
class Settings(object):
"""Settings file used for an OpenMC simulation. Corresponds directly to the
settings.xml input file.
@ -70,9 +70,10 @@ class SettingsFile(object):
deviation.
cross_sections : str
Indicates the path to an XML cross section listing file (usually named
cross_sections.xml). If it is not set, the :envvar:`CROSS_SECTIONS`
environment variable will be used for continuous-energy calculations
and :envvar:`MG_CROSS_SECTIONS` will be used for multi-group
cross_sections.xml). If it is not set, the
:envvar:`OPENMC_CROSS_SECTIONS` environment variable will be used for
continuous-energy calculations and
:envvar:`OPENMC_MG_CROSS_SECTIONS` will be used for multi-group
calculations to find the path to the XML cross section file.
multipole_library : str
Indicates the path to a directory containing a windowed multipole

View file

@ -1,5 +1,8 @@
import sys
import re
import os
import warnings
import numpy as np
import openmc
@ -14,6 +17,14 @@ class StatePoint(object):
of a given batch). Statepoints can be used to analyze tally results as well
as restart a simulation.
Parameters
----------
filename : str
Path to file to load
autolink : bool, optional
Whether to automatically link in metadata from a summary.h5
file. Defaults to True.
Attributes
----------
cmfd_on : bool
@ -96,7 +107,7 @@ class StatePoint(object):
"""
def __init__(self, filename):
def __init__(self, filename, autolink=True):
import h5py
self._f = h5py.File(filename, 'r')
@ -119,11 +130,18 @@ class StatePoint(object):
# Set flags for what data has been read
self._meshes_read = False
self._tallies_read = False
self._summary = False
self._summary = None
self._global_tallies = None
self._sparse = False
self._derivs_read = False
# Automatically link in a summary file if one exists
if autolink:
path_summary = os.path.join(os.path.dirname(filename), 'summary.h5')
if os.path.exists(path_summary):
su = openmc.Summary(path_summary)
self.link_with_summary(su)
def close(self):
self._f.close()
@ -659,6 +677,11 @@ class StatePoint(object):
"""
if self.summary is not None:
warnings.warn('A Summary object has already been linked.',
RuntimeWarning)
return
if not isinstance(summary, openmc.summary.Summary):
msg = 'Unable to link statepoint with "{0}" which ' \
'is not a Summary object'.format(summary)

View file

@ -328,8 +328,8 @@ class Point(Spatial):
Parameters
----------
xyz : Iterable of float
Cartesian coordinates of location
xyz : Iterable of float, optional
Cartesian coordinates of location. Defaults to (0., 0., 0.).
Attributes
----------
@ -338,7 +338,7 @@ class Point(Spatial):
"""
def __init__(self, xyz):
def __init__(self, xyz=(0., 0., 0.)):
super(Point, self).__init__()
self.xyz = xyz

View file

@ -38,8 +38,10 @@ class Summary(object):
self._opencg_geometry = None
self._read_metadata()
self._read_nuclides()
self._read_geometry()
self._read_tallies()
self._f.close()
@property
def openmc_geometry(self):
@ -55,8 +57,8 @@ class Summary(object):
def _read_metadata(self):
# Read OpenMC version
self.version = [self._f['version_major'].value,
self._f['version_minor'].value,
self._f['version_release'].value]
self._f['version_minor'].value,
self._f['version_release'].value]
# Read date and time
self.date_and_time = self._f['date_and_time'][...]
@ -65,11 +67,23 @@ class Summary(object):
self.n_batches = self._f['n_batches'].value
self.n_particles = self._f['n_particles'].value
self.n_active = self._f['n_active'].value
self.n_inactive = self._f['n_inactive'].value
self.gen_per_batch = self._f['gen_per_batch'].value
if 'n_inactive' in self._f:
self.n_active = self._f['n_active'].value
self.n_inactive = self._f['n_inactive'].value
self.gen_per_batch = self._f['gen_per_batch'].value
self.n_procs = self._f['n_procs'].value
def _read_nuclides(self):
self.nuclides = {}
n_nuclides = self._f['nuclides/n_nuclides_total'].value
names = self._f['nuclides/names'].value
awrs = self._f['nuclides/awrs'].value
zaids = self._f['nuclides/zaids'].value
for n in range(n_nuclides):
name = names[n].decode()
name = name[:name.find('.')]
self.nuclides[name] = (zaids[n], awrs[n])
def _read_geometry(self):
# Read in and initialize the Materials and Geometry
self._read_materials()
@ -266,7 +280,8 @@ class Summary(object):
rotation = \
self._f['geometry/cells'][key]['rotation'][...]
rotation = np.asarray(rotation, dtype=np.int)
cell.rotation = rotation
cell._rotation = rotation
elif fill_type == 'normal':
cell.temperature = \
self._f['geometry/cells'][key]['temperature'][...]
@ -381,11 +396,11 @@ class Summary(object):
self.lattices[index] = lattice
if lattice_type == 'hexagonal':
n_rings = self._f['geometry/lattices'][key]['n_rings'][0]
n_axial = self._f['geometry/lattices'][key]['n_axial'][0]
n_rings = self._f['geometry/lattices'][key]['n_rings'].value
n_axial = self._f['geometry/lattices'][key]['n_axial'].value
center = self._f['geometry/lattices'][key]['center'][...]
pitch = self._f['geometry/lattices'][key]['pitch'][...]
outer = self._f['geometry/lattices'][key]['outer'][0]
outer = self._f['geometry/lattices'][key]['outer'].value
universe_ids = self._f[
'geometry/lattices'][key]['universes'][...]

File diff suppressed because it is too large Load diff

View file

@ -1566,7 +1566,7 @@ class Tally(object):
return data
def get_pandas_dataframe(self, filters=True, nuclides=True, scores=True,
derivative=True, summary=None,
derivative=True, distribcell_paths=True,
float_format='{:.2e}'):
"""Build a Pandas DataFrame for the Tally data.
@ -1587,12 +1587,11 @@ class Tally(object):
Include columns with score bin information (default is True).
derivative : bool
Include columns with differential tally info (default is True).
summary : None or openmc.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 intance.
NOTE: This option requires the OpenCG Python package.
distribcell_paths : bool, optional
Construct columns for distribcell tally filters (default is True).
The geometric information in the Summary object is embedded into a
Multi-index column with a geometric "path" to each distribcell
instance.
float_format : str
All floats in the DataFrame will be formatted using the given
format string before printing.
@ -1618,14 +1617,6 @@ class Tally(object):
msg = 'The Tally ID="{0}" has no data to return'.format(self.id)
raise KeyError(msg)
# If using Summary, ensure StatePoint.link_with_summary(...) was called
if summary and not self.with_summary:
msg = 'The Tally ID="{0}" has not been linked with the Summary. ' \
'Call the StatePoint.link_with_summary(...) method ' \
'before using Tally.get_pandas_dataframe(...) with ' \
'Summary info'.format(self.id)
raise KeyError(msg)
# Initialize a pandas dataframe for the tally data
import pandas as pd
df = pd.DataFrame()
@ -1638,7 +1629,8 @@ class Tally(object):
# Append each Filter's DataFrame to the overall DataFrame
for self_filter in self.filters:
filter_df = self_filter.get_pandas_dataframe(data_size, summary)
filter_df = self_filter.get_pandas_dataframe(
data_size, distribcell_paths)
df = pd.concat([df, filter_df], axis=1)
# Include DataFrame column for nuclides if user requested it
@ -1667,7 +1659,7 @@ class Tally(object):
for score in self.scores:
if isinstance(score, (basestring, CrossScore)):
scores.append(score)
scores.append(str(score))
elif isinstance(score, AggregateScore):
scores.append(score.name)
column_name = '{0}(score)'.format(score.aggregate_op)
@ -3457,66 +3449,108 @@ class Tally(object):
return new_tally
class TalliesFile(object):
"""Tallies file used for an OpenMC simulation. Corresponds directly to the
tallies.xml input file.
class Tallies(cv.CheckedList):
"""Collection of Tallies used for an OpenMC simulation.
This class corresponds directly to the tallies.xml input file. It can be
thought of as a normal Python list where each member is a :class:`Tally`. It
behaves like a list as the following example demonstrates:
>>> t1 = openmc.Tally()
>>> t2 = openmc.Tally()
>>> t3 = openmc.Tally()
>>> tallies = openmc.Tallies([t1])
>>> tallies.append(t2)
>>> tallies += [t3]
Parameters
----------
tallies : Iterable of openmc.Tally
Tallies to add to the collection
"""
def __init__(self):
# Initialize TalliesFile class attributes
self._tallies = []
self._meshes = []
def __init__(self, tallies=None):
super(Tallies, self).__init__(Tally, 'tallies collection')
self._tallies_file = ET.Element("tallies")
@property
def tallies(self):
return self._tallies
@property
def meshes(self):
return self._meshes
if tallies is not None:
self += tallies
def add_tally(self, tally, merge=False):
"""Add a tally to the file
"""Append tally to collection
.. deprecated:: 0.8
Use :meth:`Tallies.append` instead.
Parameters
----------
tally : openmc.Tally
Tally to add to file
Tally to add
merge : bool
Indicate whether the tally should be merged with an existing tally,
if possible. Defaults to False.
"""
warnings.warn("Tallies.add_tally(...) has been deprecated and may be "
"removed in a future version. Use Tallies.append(...) "
"instead.", DeprecationWarning)
self.append(tally, merge)
def append(self, tally, merge=False):
"""Append tally to collection
Parameters
----------
tally : openmc.Tally
Tally to append
merge : bool
Indicate whether the tally should be merged with an existing tally,
if possible. Defaults to False.
"""
if not isinstance(tally, Tally):
msg = 'Unable to add a non-Tally "{0}" to the TalliesFile'.format(tally)
raise ValueError(msg)
msg = 'Unable to add a non-Tally "{0}" to the Tallies instance'.format(tally)
raise TypeError(msg)
if merge:
merged = False
# Look for a tally to merge with this one
for i, tally2 in enumerate(self._tallies):
for i, tally2 in enumerate(self):
# If a mergeable tally is found
if tally2.can_merge(tally):
# Replace tally 2 with the merged tally
merged_tally = tally2.merge(tally)
self._tallies[i] = merged_tally
self[i] = merged_tally
merged = True
break
# If not mergeable tally was found, simply add this tally
if not merged:
self._tallies.append(tally)
super(Tallies, self).append(tally)
else:
self._tallies.append(tally)
super(Tallies, self).append(tally)
def insert(self, index, item):
"""Insert tally before index
Parameters
----------
index : int
Index in list
item : openmc.Tally
Tally to insert
"""
super(Tallies, self).insert(index, item)
def remove_tally(self, tally):
"""Remove a tally from the file
"""Remove a tally from the collection
.. deprecated:: 0.8
Use :meth:`Tallies.remove` instead.
Parameters
----------
@ -3524,8 +3558,11 @@ class TalliesFile(object):
Tally to remove
"""
warnings.warn("Tallies.remove_tally(...) has been deprecated and may "
"be removed in a future version. Use Tallies.remove(...) "
"instead.", DeprecationWarning)
self._tallies.remove(tally)
self.remove(tally)
def merge_tallies(self):
"""Merge any mergeable tallies together. Note that n-way merges are
@ -3533,8 +3570,8 @@ class TalliesFile(object):
"""
for i, tally1 in enumerate(self._tallies):
for j, tally2 in enumerate(self._tallies):
for i, tally1 in enumerate(self):
for j, tally2 in enumerate(self):
# Do not merge the same tally with itself
if i == j:
continue
@ -3543,10 +3580,10 @@ class TalliesFile(object):
if tally1.can_merge(tally2):
# Replace tally 1 with the merged tally
merged_tally = tally1.merge(tally2)
self._tallies[i] = merged_tally
self[i] = merged_tally
# Remove tally 2 since it is no longer needed
self._tallies.pop(j)
self.pop(j)
# Continue iterating from the first loop
break
@ -3554,6 +3591,10 @@ class TalliesFile(object):
def add_mesh(self, mesh):
"""Add a mesh to the file
.. deprecated:: 0.8
Meshes that appear in a tally are automatically added to the
collection.
Parameters
----------
mesh : openmc.Mesh
@ -3561,41 +3602,48 @@ class TalliesFile(object):
"""
if not isinstance(mesh, Mesh):
msg = 'Unable to add a non-Mesh "{0}" to the TalliesFile'.format(mesh)
raise ValueError(msg)
self._meshes.append(mesh)
warnings.warn("Tallies.add_mesh(...) has been deprecated and may be "
"removed in a future version. Meshes that appear in a "
"tally are automatically added to the collection.",
DeprecationWarning)
def remove_mesh(self, mesh):
"""Remove a mesh from the file
.. deprecated:: 0.8
Meshes do not need to be managed explicitly.
Parameters
----------
mesh : openmc.Mesh
Mesh to remove from the file
"""
self._meshes.remove(mesh)
warnings.warn("Tallies.remove_mesh(...) has been deprecated and may be "
"removed in a future version. Meshes do not need to be "
"managed explicitly.", DeprecationWarning)
def _create_tally_subelements(self):
for tally in self._tallies:
for tally in self:
xml_element = tally.get_tally_xml()
self._tallies_file.append(xml_element)
def _create_mesh_subelements(self):
for mesh in self._meshes:
if len(mesh._name) > 0:
self._tallies_file.append(ET.Comment(mesh._name))
already_written = set()
for tally in self:
for f in tally.filters:
if f.type == 'mesh' and f.mesh not in already_written:
if len(f.mesh.name) > 0:
self._tallies_file.append(ET.Comment(f.mesh.name))
xml_element = mesh.get_mesh_xml()
self._tallies_file.append(xml_element)
xml_element = f.mesh.get_mesh_xml()
self._tallies_file.append(xml_element)
already_written.add(f.mesh)
def _create_derivative_subelements(self):
# Get a list of all derivatives referenced in a tally.
derivs = []
for tally in self._tallies:
for tally in self:
deriv = tally.derivative
if deriv is not None and deriv not in derivs:
derivs.append(deriv)

View file

@ -36,6 +36,8 @@ class Universe(object):
automatically be assigned
name : str, optional
Name of the universe. If not specified, the name is the empty string.
cells : Iterable of openmc.Cell, optional
Cells to add to the universe. By default no cells are added.
Attributes
----------
@ -49,7 +51,7 @@ class Universe(object):
"""
def __init__(self, universe_id=None, name=''):
def __init__(self, universe_id=None, name='', cells=None):
# Initialize Cell class attributes
self.id = universe_id
self.name = name
@ -61,7 +63,9 @@ class Universe(object):
# Keys - Cell IDs
# Values - Offsets
self._cell_offsets = OrderedDict()
self._num_regions = 0
if cells is not None:
self.add_cells(cells)
def __eq__(self, other):
if not isinstance(other, Universe):
@ -87,8 +91,6 @@ class Universe(object):
string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name)
string += '{0: <16}{1}{2}\n'.format('\tCells', '=\t',
list(self._cells.keys()))
string += '{0: <16}{1}{2}\n'.format('\t# Regions', '=\t',
self._num_regions)
return string
@property

View file

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

View file

@ -57,7 +57,7 @@ contains
character(12) :: alias ! alias of nuclide, e.g. U-235.03c
logical :: mp_found ! if windowed multipole libraries were found
type(Material), pointer :: mat
type(NuclideCE), pointer :: nuc
type(Nuclide), pointer :: nuc
type(SAlphaBeta), pointer :: sab
type(SetChar) :: already_read
@ -286,7 +286,7 @@ contains
character(10) :: mat ! material identifier
character(70) :: comment ! comment for ACE table
character(MAX_FILE_LEN) :: filename ! path to ACE cross section library
type(NuclideCE), pointer :: nuc
type(Nuclide), pointer :: nuc
type(SAlphaBeta), pointer :: sab
type(XsListing), pointer :: listing
@ -492,7 +492,7 @@ contains
!===============================================================================
subroutine read_esz(nuc, data_0K)
type(NuclideCE), intent(inout) :: nuc
type(Nuclide), intent(inout) :: nuc
logical, intent(in) :: data_0K ! are we reading 0K data?
integer :: NE ! number of energy points for total and elastic cross sections
@ -580,7 +580,7 @@ contains
!===============================================================================
subroutine read_nu_data(nuc)
type(NuclideCE), intent(inout) :: nuc
type(Nuclide), intent(inout) :: nuc
integer :: i, j ! loop index
integer :: idx ! index in XSS
@ -795,7 +795,7 @@ contains
!===============================================================================
subroutine read_reactions(nuc)
type(NuclideCE), intent(inout) :: nuc
type(Nuclide), intent(inout) :: nuc
integer :: i ! loop indices
integer :: i_fission ! index in nuc % index_fission
@ -971,7 +971,7 @@ contains
!===============================================================================
subroutine read_angular_dist(nuc)
type(NuclideCE), intent(inout) :: nuc
type(Nuclide), intent(inout) :: nuc
integer :: LOCB ! location of angular distribution for given MT
integer :: NE ! number of incoming energies
@ -1075,7 +1075,7 @@ contains
!===============================================================================
subroutine read_energy_dist(nuc)
type(NuclideCE), intent(inout) :: nuc
type(Nuclide), intent(inout) :: nuc
integer :: i ! loop index
integer :: n
@ -1464,7 +1464,7 @@ contains
!===============================================================================
subroutine read_unr_res(nuc)
type(NuclideCE), intent(inout) :: nuc
type(Nuclide), intent(inout) :: nuc
integer :: JXS23 ! location of URR data
integer :: lc ! locator
@ -1551,7 +1551,7 @@ contains
!===============================================================================
subroutine generate_nu_fission(nuc)
type(NuclideCE), intent(inout) :: nuc
type(Nuclide), intent(inout) :: nuc
integer :: i ! index on nuclide energy grid

View file

@ -37,7 +37,7 @@ module constants
real(8), parameter :: FP_COINCIDENT = 1e-12_8
! Maximum number of collisions/crossings
integer, parameter :: MAX_EVENTS = 10000
integer, parameter :: MAX_EVENTS = 1000000
integer, parameter :: MAX_SAMPLE = 100000
! Maximum number of secondary particles created

View file

@ -156,8 +156,8 @@ contains
integer :: i_high ! upper logarithmic mapping index
real(8) :: f ! interp factor on nuclide energy grid
real(8) :: sigT, sigA, sigF ! Intermediate multipole variables
type(NuclideCE), pointer :: nuc
type(Material), pointer :: mat
type(Nuclide), pointer :: nuc
type(Material), pointer :: mat
! Set pointer to nuclide and material
nuc => nuclides(i_nuclide)
@ -845,9 +845,9 @@ contains
!===============================================================================
pure function elastic_xs_0K(E, nuc) result(xs_out)
real(8), intent(in) :: E ! trial energy
type(NuclideCE), intent(in) :: nuc ! target nuclide at temperature
real(8) :: xs_out ! 0K xs at trial energy
real(8), intent(in) :: E ! trial energy
type(Nuclide), intent(in) :: nuc ! target nuclide at temperature
real(8) :: xs_out ! 0K xs at trial energy
integer :: i_grid ! index on nuclide energy grid
real(8) :: f ! interp factor on nuclide energy grid

View file

@ -27,7 +27,7 @@ contains
integer :: i ! index in nuclides array
integer :: j ! index in materials array
type(ListReal) :: list
type(NuclideCE), pointer :: nuc
type(Nuclide), pointer :: nuc
type(Material), pointer :: mat
call write_message("Creating unionized energy grid...", 5)
@ -70,7 +70,7 @@ contains
real(8) :: E_max ! Maximum energy in MeV
real(8) :: E_min ! Minimum energy in MeV
real(8), allocatable :: umesh(:) ! Equally log-spaced energy grid
type(NuclideCE), pointer :: nuc
type(Nuclide), pointer :: nuc
! Set minimum/maximum energies
E_max = energy_max_neutron
@ -179,7 +179,7 @@ contains
integer :: index_e ! index on union energy grid
real(8) :: union_energy ! energy on union grid
real(8) :: energy ! energy on nuclide grid
type(NuclideCE), pointer :: nuc
type(Nuclide), pointer :: nuc
type(Material), pointer :: mat
do k = 1, n_materials

View file

@ -5,9 +5,9 @@ module global
use constants
use dict_header, only: DictCharInt, DictIntInt
use geometry_header, only: Cell, Universe, Lattice, LatticeContainer
use macroxs_header, only: MacroXSContainer
use material_header, only: Material
use mesh_header, only: RegularMesh
use mgxs_header, only: Mgxs, MgxsContainer
use nuclide_header
use plot_header, only: ObjectPlot
use sab_header, only: SAlphaBeta
@ -87,7 +87,7 @@ module global
! CONTINUOUS-ENERGY CROSS SECTION RELATED VARIABLES
! Cross section arrays
type(NuclideCE), allocatable, target :: nuclides(:) ! Nuclide cross-sections
type(Nuclide), allocatable, target :: nuclides(:) ! Nuclide cross-sections
type(SAlphaBeta), allocatable, target :: sab_tables(:) ! S(a,b) tables
integer :: n_sab_tables ! Number of S(a,b) thermal scattering tables
@ -116,10 +116,10 @@ module global
! MULTI-GROUP CROSS SECTION RELATED VARIABLES
! Cross section arrays
type(NuclideMGContainer), allocatable, target :: nuclides_MG(:)
type(MgxsContainer), allocatable, target :: nuclides_MG(:)
! Cross section caches
type(MacroXSContainer), target, allocatable :: macro_xs(:)
type(MgxsContainer), target, allocatable :: macro_xs(:)
! Number of energy groups
integer :: energy_groups

File diff suppressed because it is too large Load diff

View file

@ -378,7 +378,7 @@ contains
! Check what type of file this is
file_id = file_open(argv(i), 'r', parallel=.true.)
call read_dataset(file_id, 'filetype', filetype)
call read_dataset(filetype, file_id, 'filetype')
call file_close(file_id)
! Set path and flag for type of run
@ -404,7 +404,7 @@ contains
! Check file type is a source file
file_id = file_open(argv(i), 'r', parallel=.true.)
call read_dataset(file_id, 'filetype', filetype)
call read_dataset(filetype, file_id, 'filetype')
call file_close(file_id)
if (filetype /= 'source') then
call fatal_error("Second file after restart flag must be a &

View file

@ -92,18 +92,22 @@ contains
type(NodeList), pointer :: node_scat_list => null()
type(NodeList), pointer :: node_source_list => null()
! Display output message
call write_message("Reading settings XML file...", 5)
! Check if settings.xml exists
filename = trim(path_input) // "settings.xml"
inquire(FILE=filename, EXIST=file_exists)
if (.not. file_exists) then
call fatal_error("Settings XML file '" // trim(filename) // "' does not &
&exist! In order to run OpenMC, you first need a set of input files;&
& at a minimum, this includes settings.xml, geometry.xml, and &
&materials.xml. Please consult the user's guide at &
&http://mit-crpg.github.io/openmc for further information.")
if (run_mode /= MODE_PLOTTING) then
call fatal_error("Settings XML file '" // trim(filename) // "' does &
&not exist! In order to run OpenMC, you first need a set of input &
&files; at a minimum, this includes settings.xml, geometry.xml, &
&and materials.xml. Please consult the user's guide at &
&http://mit-crpg.github.io/openmc for further information.")
else
! The settings.xml file is optional if we just want to make a plot.
return
end if
else
call write_message("Reading settings XML file...", 5)
end if
! Parse settings.xml file
@ -150,7 +154,7 @@ contains
call get_environment_variable("OPENMC_MG_CROSS_SECTIONS", &
env_variable)
if (len_trim(env_variable) == 0) then
call fatal_error("No cross_sections.xml file was specified in &
call fatal_error("No mgxs.xml file was specified in &
&settings.xml or in the OPENMC_MG_CROSS_SECTIONS environment &
&variable. OpenMC needs such a file to identify where to &
&find the cross section libraries. Please consult the user's &
@ -184,9 +188,12 @@ contains
if (check_for_node(doc, "max_order")) then
call get_node_value(doc, "max_order", max_order)
else
! Set to default of largest int, which means to use whatever is
! contained in library
max_order = huge(0)
! Set to default of largest int - 1, which means to use whatever is
! contained in library.
! This is largest int - 1 because for legendre scattering, a value of
! 1 is added to the order; adding 1 to huge(0) gets you the largest
! negative integer, which is not what we want.
max_order = huge(0) - 1
end if
else
max_order = 0
@ -3011,11 +3018,15 @@ contains
allocate(t % filters(j) % real_bins(n_words))
call get_node_array(node_filt, "bins", t % filters(j) % real_bins)
! We can save tallying time if we know that the tally bins
! match the energy group structure. In that case, the matching bin
! index is simply the group (after flipping for the different
! ordering of the library and tallying systems).
if (.not. run_CE) then
if (n_words /= energy_groups + 1) then
t % energy_matches_groups = .false.
else if (all(t % filters(j) % real_bins == energy_bins)) then
t % energy_matches_groups = .false.
if (n_words == energy_groups + 1) then
if (all(t % filters(j) % real_bins == &
energy_bins(energy_groups + 1:1:-1))) &
t % energy_matches_groups = .true.
end if
end if
@ -3030,11 +3041,15 @@ contains
allocate(t % filters(j) % real_bins(n_words))
call get_node_array(node_filt, "bins", t % filters(j) % real_bins)
! We can save tallying time if we know that the tally bins
! match the energy group structure. In that case, the matching bin
! index is simply the group (after flipping for the different
! ordering of the library and tallying systems).
if (.not. run_CE) then
if (n_words /= energy_groups + 1) then
t % energy_matches_groups = .false.
else if (all(t % filters(j) % real_bins == energy_bins)) then
t % energy_matches_groups = .false.
if (n_words == energy_groups + 1) then
if (all(t % filters(j) % real_bins == &
energy_bins(energy_groups + 1:1:-1))) &
t % energyout_matches_groups = .true.
end if
end if
@ -3494,27 +3509,22 @@ contains
case ('nu-scatter')
t % score_bins(j) = SCORE_NU_SCATTER
! Set tally estimator to analog
t % estimator = ESTIMATOR_ANALOG
case ('scatter-n')
if (n_order == 0) then
t % score_bins(j) = SCORE_SCATTER
else
t % score_bins(j) = SCORE_SCATTER_N
! Set tally estimator to analog
! Set tally estimator to analog for CE mode
! (MG mode has all data available without a collision being
! necessary)
if (run_CE) then
t % estimator = ESTIMATOR_ANALOG
end if
case ('scatter-n')
t % score_bins(j) = SCORE_SCATTER_N
t % moment_order(j) = n_order
t % estimator = ESTIMATOR_ANALOG
case ('nu-scatter-n')
! Set tally estimator to analog
t % estimator = ESTIMATOR_ANALOG
if (n_order == 0) then
t % score_bins(j) = SCORE_NU_SCATTER
else
t % score_bins(j) = SCORE_NU_SCATTER_N
end if
t % score_bins(j) = SCORE_NU_SCATTER_N
t % moment_order(j) = n_order
t % estimator = ESTIMATOR_ANALOG
case ('scatter-pn')
t % estimator = ESTIMATOR_ANALOG
@ -3553,10 +3563,14 @@ contains
call fatal_error("Diffusion score no longer supported for tallies, &
&please remove")
case ('n1n')
t % score_bins(j) = SCORE_N_1N
if (run_CE) then
t % score_bins(j) = SCORE_N_1N
! Set tally estimator to analog
t % estimator = ESTIMATOR_ANALOG
! Set tally estimator to analog
t % estimator = ESTIMATOR_ANALOG
else
call fatal_error("Cannot tally n1n rate in multi-group mode!")
end if
case ('n2n', '(n,2n)')
t % score_bins(j) = N_2N
@ -4690,23 +4704,24 @@ contains
subroutine read_mg_cross_sections_xml()
integer :: i ! loop index
logical :: file_exists ! does cross_sections.xml exist?
logical :: file_exists ! does mgxs.xml exist?
type(XsListing), pointer :: listing => null()
type(Node), pointer :: doc => null()
type(Node), pointer :: node_xsdata => null()
type(NodeList), pointer :: node_xsdata_list => null()
real(8), allocatable :: rev_energy_bins(:)
! Check if cross_sections.xml exists
! Check if mgxs.xml exists
inquire(FILE=path_cross_sections, EXIST=file_exists)
if (.not. file_exists) then
! Could not find cross_sections.xml file
! Could not find mgxs.xml file
call fatal_error("Cross sections XML file '" &
// trim(path_cross_sections) // "' does not exist!")
end if
call write_message("Reading cross sections XML file...", 5)
! Parse cross_sections.xml file
! Parse mgxs.xml file
call open_xmldoc(doc, path_cross_sections)
if (check_for_node(doc, "groups")) then
@ -4716,6 +4731,7 @@ contains
call fatal_error("groups element must exist!")
end if
allocate(rev_energy_bins(energy_groups + 1))
allocate(energy_bins(energy_groups + 1))
if (check_for_node(doc, "group_structure")) then
! Get neutron group structure
@ -4724,6 +4740,9 @@ contains
call fatal_error("group_structures element must exist!")
end if
! First reverse the order of energy_groups
energy_bins = energy_bins(energy_groups + 1:1:-1)
allocate(energy_bin_avg(energy_groups))
do i = 1, energy_groups
energy_bin_avg(i) = HALF * (energy_bins(i) + energy_bins(i + 1))
@ -4737,7 +4756,7 @@ contains
! If not given, estimate them by using average energy in group which is
! assumed to be the midpoint
do i = 1, energy_groups
inverse_velocities(i) = &
inverse_velocities(i) = ONE / &
(sqrt(TWO * energy_bin_avg(i) / (MASS_NEUTRON_MEV)) * &
C_LIGHT * 100.0_8)
end do
@ -4750,7 +4769,7 @@ contains
! Allocate xs_listings array
if (n_listings == 0) then
call fatal_error("At least one <xsdata> element must be present in &
&cross_sections.xml file!")
&mgxs.xml file!")
else
allocate(xs_listings(n_listings))
end if

View file

@ -1,860 +0,0 @@
module macroxs_header
use constants, only: MAX_FILE_LEN, ZERO, ONE, TWO, PI
use list_header, only: ListInt
use material_header, only: material
use math, only: calc_pn, calc_rn, expand_harmonic, find_angle
use nuclide_header
use random_lcg, only: prn
use scattdata_header
implicit none
!===============================================================================
! MACROXS_* contains cached macroscopic cross sections for the material a
! particle is traveling through
!===============================================================================
type, abstract :: MacroXS
! Data Order
integer :: order
contains
procedure(macroxs_init_), deferred :: init ! initializes object
procedure(macroxs_get_xs_), deferred :: get_xs ! Return xs
! Sample the outgoing energy from a fission event
procedure(macroxs_sample_fission_), deferred :: sample_fission_energy
! Sample the outgoing energy and angle from a scatter event
procedure(macroxs_sample_scatter_), deferred :: sample_scatter
! Calculate the material specific MGXS data from the nuclides
procedure(macroxs_calculate_xs_), deferred :: calculate_xs
end type MacroXS
abstract interface
subroutine macroxs_init_(this, mat, nuclides, groups, get_kfiss, get_fiss, &
max_order, scatt_type, legendre_mu_points, &
error_code, error_text)
import MacroXS, Material, NuclideMGContainer, MAX_LINE_LEN
class(MacroXS), intent(inout) :: this ! The MacroXS to initialize
type(Material), pointer, intent(in) :: mat ! base material
type(NuclideMGContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from
integer, intent(in) :: groups ! Number of E groups
logical, intent(in) :: get_kfiss ! Should we get kfiss data?
logical, intent(in) :: get_fiss ! Should we get fiss data?
integer, intent(in) :: max_order ! Maximum requested order
integer, intent(in) :: scatt_type ! Legendre or Tabular Scatt?
integer, intent(in) :: legendre_mu_points ! Treat as Leg or Tabular?
integer, intent(inout) :: error_code ! Code signifying error
character(MAX_LINE_LEN), intent(inout) :: error_text ! Error message to print
end subroutine macroxs_init_
function macroxs_get_xs_(this, g, xstype, gout, uvw) result(xs)
import MacroXS
class(MacroXS), intent(in) :: this ! The MacroXS to initialize
integer, intent(in) :: g ! Incoming Energy group
character(*) , intent(in) :: xstype ! Cross Section Type
integer, optional, intent(in) :: gout ! Outgoing Energy group
real(8), optional, intent(in) :: uvw(3) ! Requested Angle
real(8) :: xs ! Resultant xs
end function macroxs_get_xs_
function macroxs_sample_fission_(this, gin, uvw) result(gout)
import MacroXS
class(MacroXS), intent(in) :: this ! Data to work with
integer, intent(in) :: gin ! Incoming energy group
real(8), intent(in) :: uvw(3) ! Particle Direction
integer :: gout ! Sampled outgoing group
end function macroxs_sample_fission_
subroutine macroxs_sample_scatter_(this, uvw, gin, gout, mu, wgt)
import MacroXS
class(MacroXS), intent(in) :: this
real(8), intent(in) :: uvw(3) ! Incoming neutron direction
integer, intent(in) :: gin ! Incoming neutron group
integer, intent(out) :: gout ! Sampled outgoin group
real(8), intent(out) :: mu ! Sampled change in angle
real(8), intent(inout) :: wgt ! Particle weight
end subroutine macroxs_sample_scatter_
subroutine macroxs_calculate_xs_(this, gin, uvw, xs)
import MacroXS, MaterialMacroXS
class(MacroXS), intent(in) :: this
integer, intent(in) :: gin ! Incoming neutron group
real(8), intent(in) :: uvw(3) ! Incoming neutron direction
type(MaterialMacroXS), intent(inout) :: xs
end subroutine macroxs_calculate_xs_
end interface
type, extends(MacroXS) :: MacroXSIso
! Microscopic cross sections
real(8), allocatable :: total(:) ! total cross section
real(8), allocatable :: absorption(:) ! absorption cross section
class(ScattData), allocatable :: scatter ! scattering information
real(8), allocatable :: nu_fission(:) ! nu-fission
real(8), allocatable :: k_fission(:) ! kappa-fission
real(8), allocatable :: fission(:) ! fission x/s
real(8), allocatable :: scattxs(:) ! scattering xs
real(8), allocatable :: chi(:,:) ! fission spectra
contains
procedure :: init => macroxsiso_init ! inits object
procedure :: get_xs => macroxsiso_get_xs ! Returns xs
procedure :: sample_fission_energy => macroxsiso_sample_fission_energy
procedure :: sample_scatter => macroxsiso_sample_scatter
procedure :: calculate_xs => macroxsiso_calculate_xs
end type MacroXSIso
type, extends(MacroXS) :: MacroXSAngle
! Macroscopic cross sections
real(8), allocatable :: total(:,:,:) ! total cross section
real(8), allocatable :: absorption(:,:,:) ! absorption cross section
type(ScattDataContainer), allocatable :: scatter(:,:) ! scattering information
real(8), allocatable :: nu_fission(:,:,:) ! nu-fission
real(8), allocatable :: k_fission(:,:,:) ! kappa-fission
real(8), allocatable :: fission(:,:,:) ! fission x/s
real(8), allocatable :: chi(:,:,:,:) ! fission spectra
real(8), allocatable :: scattxs(:,:,:) ! scattering xs
real(8), allocatable :: polar(:) ! polar angles
real(8), allocatable :: azimuthal(:) ! azimuthal angles
contains
procedure :: init => macroxsangle_init ! inits object
procedure :: get_xs => macroxsangle_get_xs ! Returns xs
procedure :: sample_fission_energy => macroxsangle_sample_fission_energy
procedure :: sample_scatter => macroxsangle_sample_scatter
procedure :: calculate_xs => macroxsangle_calculate_xs
end type MacroXSAngle
!===============================================================================
! MACROXSCONTAINER pointer array for storing MacroXS objects.
!===============================================================================
type MacroXSContainer
class(MacroXS), allocatable :: obj
end type MacroXSContainer
contains
!===============================================================================
! MACROXS*_INIT sets the MacroXS Data
!===============================================================================
subroutine macroxsiso_init(this, mat, nuclides, groups, get_kfiss, get_fiss, &
max_order, scatt_type, legendre_mu_points, error_code, error_text)
class(MacroXSIso), intent(inout) :: this ! The MacroXS to initialize
type(Material), pointer, intent(in) :: mat ! base material
type(NuclideMGContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from
integer, intent(in) :: groups ! Number of E groups
logical, intent(in) :: get_kfiss ! Should we get kfiss data?
logical, intent(in) :: get_fiss ! Should we get fiss data?
integer, intent(in) :: max_order ! Maximum requested order
integer, intent(in) :: scatt_type ! How is data presented
integer, intent(in) :: legendre_mu_points ! Treat as Leg or Tabular?
integer, intent(inout) :: error_code ! Code signifying error
character(MAX_LINE_LEN), intent(inout) :: error_text ! Error message to print
integer :: i ! loop index over nuclides
integer :: gin, gout ! group indices
real(8) :: atom_density ! atom density of a nuclide
integer :: imu
real(8) :: norm
integer :: mat_max_order, order, l
real(8), allocatable :: temp_mult(:,:)
real(8), allocatable :: temp_energy(:,:)
real(8), allocatable :: scatt_coeffs(:,:,:)
! Initialize error data
error_code = 0
error_text = ''
! If we have tabular only data, then make sure all datasets have same size
if (scatt_type == ANGLE_HISTOGRAM) then
! Check all scattering data of same size
order = nuclides(mat % nuclide(1)) % obj % order
do i = 2, mat % n_nuclides
if (order /= nuclides(mat % nuclide(i)) % obj % order) then
error_code = 1
error_text = "All Histogram Scattering Entries Must Be Same Length!"
return
end if
end do
! Ok, got our order, store it
this % order = order
! Allocate stuff for later
allocate(scatt_coeffs(order, groups, groups))
scatt_coeffs = ZERO
allocate(ScattDataHistogram :: this % scatter)
else if (scatt_type == ANGLE_TABULAR) then
! Check all scattering data of same size
order = nuclides(mat % nuclide(1)) % obj % order
do i = 2, mat % n_nuclides
if (order /= nuclides(mat % nuclide(i)) % obj % order) then
error_code = 1
error_text = "All Tabular Scattering Entries Must Be Same Length!"
return
end if
end do
! Ok, got our order, store it
this % order = order
! Allocate stuff for later
allocate(scatt_coeffs(order, groups, groups))
scatt_coeffs = ZERO
allocate(ScattDataTabular :: this % scatter)
else if (scatt_type == ANGLE_LEGENDRE) then
! Otherwise find the maximum scattering order
! Need to determine the maximum scattering order of all data in this material
mat_max_order = 0
do i = 1, mat % n_nuclides
if (nuclides(mat % nuclide(i)) % obj % order > mat_max_order) then
mat_max_order = nuclides(mat % nuclide(i)) % obj % order
end if
end do
! Now need to compare this material maximum scattering order with
! the problem wide max scatt order and use whichever is lower
order = min(mat_max_order, max_order)
this % order = order + 1
! Now we can allocate our scatt_coeffs object accordingly
allocate(scatt_coeffs(order + 1, groups, groups))
scatt_coeffs = ZERO
if (legendre_mu_points == 1) then
allocate(ScattDataLegendre :: this % scatter)
else
allocate(ScattDataTabular :: this % scatter)
end if
end if
! Allocate and initialize data within macro_xs(i_mat) object
allocate(this % total(groups))
this % total = ZERO
allocate(this % absorption(groups))
this % absorption = ZERO
if (get_fiss) then
allocate(this % fission(groups))
this % fission = ZERO
end if
if (get_kfiss) then
allocate(this % k_fission(groups))
this % k_fission = ZERO
end if
allocate(this % nu_fission(groups))
this % nu_fission = ZERO
allocate(this % chi(groups, groups))
this % chi = ZERO
allocate(temp_energy(groups, groups))
temp_energy = ZERO
allocate(temp_mult(groups, groups))
temp_mult = ZERO
allocate(this % scattxs(groups))
! Add contribution from each nuclide in material
do i = 1, mat % n_nuclides
! Copy atom density of nuclide in material
atom_density = mat % atom_density(i)
! Perform our operations which depend upon the type
select type(nuc => nuclides(mat % nuclide(i)) % obj)
type is (NuclideIso)
! Add contributions to total, absorption, and fission data (if necessary)
this % total = this % total + atom_density * nuc % total
this % absorption = this % absorption + &
atom_density * nuc % absorption
if (nuc % fissionable) then
if (allocated(nuc % chi)) then
do gin = 1, groups
do gout = 1, groups
this % chi(gout,gin) = this % chi(gout,gin) + atom_density * &
nuc % chi(gout) * nuc % nu_fission(gin,1)
end do
end do
this % nu_fission = this % nu_fission + atom_density * &
nuc % nu_fission(:,1)
else
this % chi = this % chi + atom_density * nuc % nu_fission
do gin = 1, groups
this % nu_fission(gin) = this % nu_fission(gin) + atom_density * &
sum(nuc % nu_fission(:,gin))
end do
end if
if (get_fiss) then
this % fission = this % fission + atom_density * nuc % fission
end if
if (get_kfiss) then
this % k_fission = this % k_fission + atom_density * nuc % k_fission
end if
end if
! Now time to do the scattering
do gin = 1, groups
do gout = 1, groups
if (scatt_type == ANGLE_HISTOGRAM .or. scatt_type == ANGLE_TABULAR) then
! Transfer matrix
temp_energy(gout,gin) = temp_energy(gout,gin) + atom_density * &
sum(nuc % scatter(gout,gin,:))
! Determine the angular distribution
do imu = 1, order
scatt_coeffs(imu, gout, gin) = scatt_coeffs(imu, gout, gin) + &
nuc % scatter(gout,gin,imu) * &
atom_density
end do
else if (scatt_type == ANGLE_LEGENDRE) then
! Transfer matrix
temp_energy(gout,gin) = temp_energy(gout,gin) + atom_density * &
nuc % scatter(gout,gin,1)
! Determine the angular distribution coefficients so we can later
! expand do the complete distribution
do l = 1, min(nuc % order, order) + 1
scatt_coeffs(l, gout, gin) = scatt_coeffs(l, gout, gin) + &
nuc % scatter(gout,gin,l) * &
atom_density
end do
end if
! Multiplicity matrix
temp_mult(gout,gin) = temp_mult(gout,gin) + atom_density * &
nuc % mult(gout,gin)
end do
end do
type is (NuclideAngle)
error_code = 1
error_text = "Invalid Passing of NuclideAngle to MacroXSIso Object"
return
end select
end do
! Store the scattering xs
if (scatt_type == ANGLE_HISTOGRAM .or. scatt_type == ANGLE_TABULAR) then
this % scattxs(:) = sum(sum(scatt_coeffs(:,:,:),dim=1),dim=1)
else if (scatt_type == ANGLE_LEGENDRE) then
this % scattxs(:) = sum(scatt_coeffs(1,:,:),dim=1)
end if
! Normalize the scatt_coeffs
do gin = 1, groups
do gout = 1, groups
if (scatt_type == ANGLE_HISTOGRAM .or. scatt_type == ANGLE_TABULAR) then
norm = sum(scatt_coeffs(:,gout,gin))
else if (scatt_type == ANGLE_LEGENDRE) then
norm = scatt_coeffs(1,gout,gin)
end if
if (norm /= ZERO) then
scatt_coeffs(:, gout, gin) = scatt_coeffs(:, gout,gin) / norm
end if
end do
! Now normalize temp_energy (outgoing scattering energy probabilities)
norm = sum(temp_energy(:,gin))
if (norm > ZERO) then
temp_energy(:,gin) = temp_energy(:,gin) / norm
end if
end do
if (scatt_type == ANGLE_LEGENDRE .and. legendre_mu_points /= 1) then
call this % scatter % init(legendre_mu_points, temp_energy, temp_mult, &
scatt_coeffs)
else
call this % scatter % init(this % order, temp_energy, temp_mult, &
scatt_coeffs)
end if
! Now normalize chi
if (mat % fissionable) then
do gin = 1, groups
! Normalize Chi
norm = sum(this % chi(:,gin))
if (norm > ZERO) then
this % chi(:,gin) = this % chi(:,gin) / norm
end if
end do
end if
! Deallocate temporaries for the next material
deallocate(scatt_coeffs, temp_energy, temp_mult)
end subroutine macroxsiso_init
subroutine macroxsangle_init(this, mat, nuclides, groups, get_kfiss, get_fiss, &
max_order, scatt_type, legendre_mu_points, error_code, error_text)
class(MacroXSAngle), intent(inout) :: this ! The MacroXS to initialize
type(Material), pointer, intent(in) :: mat ! base material
type(NuclideMGContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from
integer, intent(in) :: groups ! Number of E groups
logical, intent(in) :: get_kfiss ! Should we get kfiss data?
logical, intent(in) :: get_fiss ! Should we get fiss data?
integer, intent(in) :: max_order ! Maximum requested order
integer, intent(in) :: scatt_type ! Legendre or Tabular Scatt?
integer, intent(in) :: legendre_mu_points ! Treat as Leg or Tabular?
integer, intent(inout) :: error_code ! Code signifying error
character(MAX_LINE_LEN), intent(inout) :: error_text ! Error message to print
integer :: i ! loop index over nuclides
integer :: gin, gout ! group indices
real(8) :: atom_density ! atom density of a nuclide
integer :: ipol, iazi, npol, nazi
integer :: imu
real(8) :: norm
integer :: mat_max_order, order, l
real(8), allocatable :: temp_mult(:,:,:,:)
real(8), allocatable :: temp_energy(:,:,:,:)
real(8), allocatable :: scatt_coeffs(:,:,:,:,:)
! Initialize error data
error_code = 0
error_text = ''
! Get the number of each polar and azi angles and make sure all the
! NuclideAngle types have the same number of these angles
npol = -1
nazi = -1
do i = 1, mat % n_nuclides
select type(nuc => nuclides(mat % nuclide(i)) % obj)
type is (NuclideAngle)
if (npol == -1) then
npol = nuc % n_pol
nazi = nuc % n_azi
allocate(this % polar(npol))
this % polar = nuc % polar
allocate(this % azimuthal(nazi))
this % azimuthal = nuc % azimuthal
else
if ((npol /= nuc % n_pol) .or. (nazi /= nuc % n_azi)) then
error_code = 1
error_text = "All Angular Data Must Be Same Length!"
end if
end if
end select
end do
! If we have tabular only data, then make sure all datasets have same size
if (scatt_type == ANGLE_HISTOGRAM) then
! Check all scattering data of same size
order = nuclides(mat % nuclide(1)) % obj % order
do i = 2, mat % n_nuclides
if (order /= nuclides(mat % nuclide(i)) % obj % order) then
error_code = 1
error_text = "All Histogram Scattering Entries Must Be Same Length!"
return
end if
end do
! Ok, got our order, store it
this % order = order
! Allocate stuff for later
allocate(scatt_coeffs(order, groups, groups, nazi, npol))
scatt_coeffs = ZERO
allocate(this % scatter(nazi, npol))
do ipol = 1, npol
do iazi = 1, nazi
allocate(ScattDataHistogram :: this % scatter(iazi, ipol) % obj)
end do
end do
else if (scatt_type == ANGLE_TABULAR) then
! Check all scattering data of same size
order = nuclides(mat % nuclide(1)) % obj % order
do i = 2, mat % n_nuclides
if (order /= nuclides(mat % nuclide(i)) % obj % order) then
error_code = 1
error_text = "All Tabular Scattering Entries Must Be Same Length!"
return
end if
end do
! Ok, got our order, store it
this % order = order
! Allocate stuff for later
allocate(scatt_coeffs(order, groups, groups, nazi, npol))
scatt_coeffs = ZERO
allocate(this % scatter(nazi, npol))
do ipol = 1, npol
do iazi = 1, nazi
allocate(ScattDataTabular :: this % scatter(iazi, ipol) % obj)
end do
end do
else if (scatt_type == ANGLE_LEGENDRE) then
! Otherwise find the maximum scattering order
! Need to determine the maximum scattering order of all data in this material
mat_max_order = 0
do i = 1, mat % n_nuclides
if (nuclides(mat % nuclide(i)) % obj % order > mat_max_order) then
mat_max_order = nuclides(mat % nuclide(i)) % obj % order
end if
end do
! Now need to compare this material maximum scattering order with
! the problem wide max scatt order and use whichever is lower
order = min(mat_max_order, max_order)
this % order = order + 1
! Now we can allocate our scatt_coeffs object accordingly
allocate(scatt_coeffs(order + 1, groups, groups, nazi, npol))
scatt_coeffs = ZERO
allocate(this % scatter(nazi, npol))
do ipol = 1, npol
do iazi = 1, nazi
if (legendre_mu_points == 1) then
allocate(ScattDataLegendre :: this % scatter(iazi, ipol) % obj)
else
allocate(ScattDataTabular :: this % scatter(iazi, ipol) % obj)
end if
end do
end do
end if
! Allocate and initialize data within macro_xs(i_mat) object
allocate(this % total(groups,nazi,npol))
this % total = ZERO
allocate(this % absorption(groups,nazi,npol))
this % absorption = ZERO
if (get_fiss) then
allocate(this % fission(groups,nazi,npol))
this % fission = ZERO
end if
if (get_kfiss) then
allocate(this % k_fission(groups,nazi,npol))
this % k_fission = ZERO
end if
allocate(this % nu_fission(groups,nazi,npol))
this % nu_fission = ZERO
allocate(this % chi(groups, groups, nazi, npol))
this % chi = ZERO
allocate(temp_energy(groups,groups,nazi,npol))
temp_energy = ZERO
allocate(temp_mult(groups,groups,nazi,npol))
temp_mult = ZERO
allocate(this % scattxs(groups,nazi,npol))
! Add contribution from each nuclide in material
do i = 1, mat % n_nuclides
! Copy atom density of nuclide in material
atom_density = mat % atom_density(i)
! Perform our operations which depend upon the type
select type(nuc => nuclides(mat % nuclide(i)) % obj)
type is (NuclideIso)
error_code = 1
error_text = "Invalid Passing of NuclideIso to MacroXSAngle Object"
return
type is (NuclideAngle)
! Add contributions to total, absorption, and fission data (if necessary)
this % total = this % total + atom_density * nuc % total
this % absorption = this % absorption + &
atom_density * nuc % absorption
if (nuc % fissionable) then
if (allocated(nuc % chi)) then
do gin = 1, groups
do gout = 1, groups
this % chi(gout,gin,:,:) = this % chi(gout,gin,:,:) + atom_density * &
nuc % chi(gout,:,:) * nuc % nu_fission(gin,1,:,:)
end do
end do
this % nu_fission = this % nu_fission + atom_density * &
nuc % nu_fission(:,1,:,:)
else
this % chi = this % chi + atom_density * nuc % nu_fission
do gin = 1, groups
this % nu_fission(gin,:,:) = this % nu_fission(gin,:,:) + atom_density * &
sum(nuc % nu_fission(:,gin,:,:),dim=1)
end do
end if
if (get_fiss) then
this % fission = this % fission + atom_density * nuc % fission
end if
if (get_kfiss) then
this % k_fission = this % k_fission + atom_density * nuc % k_fission
end if
end if
! Now time to do the scattering
do gin = 1, groups
do gout = 1, groups
if (scatt_type == ANGLE_HISTOGRAM .or. scatt_type == ANGLE_TABULAR) then
! Transfer matrix
temp_energy(gout,gin,:,:) = temp_energy(gout,gin,:,:) + atom_density * &
sum(nuc % scatter(gout,gin,:,:,:),dim=1)
! Determine the angular distribution
do imu = 1, order
scatt_coeffs(imu,gout,gin,:,:) = scatt_coeffs(imu,gout,gin,:,:) + &
nuc % scatter(gout,gin,imu,:,:) * &
atom_density
end do
else if (scatt_type == ANGLE_LEGENDRE) then
! Transfer matrix
temp_energy(gout,gin,:,:) = temp_energy(gout,gin,:,:) + atom_density * &
nuc % scatter(gout,gin,1,:,:)
! Determine the angular distribution coefficients so we can later
! expand do the complete distribution
do l = 1, min(nuc % order, order) + 1
scatt_coeffs(l, gout, gin,:,:) = scatt_coeffs(l, gout, gin,:,:) + &
nuc % scatter(gout,gin,l,:,:) * &
atom_density
end do
end if
! Multiplicity matrix
temp_mult(gout,gin,:,:) = temp_mult(gout,gin,:,:) + atom_density * &
nuc % mult(gout,gin,:,:)
end do
end do
end select
end do
! Store the scattering xs
if (scatt_type == ANGLE_HISTOGRAM .or. scatt_type == ANGLE_TABULAR) then
this % scattxs(:,:,:) = sum(sum(scatt_coeffs(:,:,:,:,:),dim=1),dim=1)
else if (scatt_type == ANGLE_LEGENDRE) then
this % scattxs(:,:,:) = sum(scatt_coeffs(1,:,:,:,:),dim=1)
end if
! Normalize the scatt_coeffs
do ipol = 1, npol
do iazi = 1, nazi
do gin = 1, groups
do gout = 1, groups
if (scatt_type == ANGLE_HISTOGRAM .or. scatt_type == ANGLE_TABULAR) then
norm = sum(scatt_coeffs(:,gout,gin,iazi,ipol))
else if (scatt_type == ANGLE_LEGENDRE) then
norm = scatt_coeffs(1,gout,gin,iazi,ipol)
end if
if (norm /= ZERO) then
scatt_coeffs(:,gout,gin,iazi,ipol) = &
scatt_coeffs(:,gout,gin,iazi,ipol) / norm
end if
end do
! Now normalize temp_energy (outgoing scattering energy probabilities)
norm = sum(temp_energy(:,gin,iazi,ipol))
if (norm > ZERO) then
temp_energy(:,gin,iazi,ipol) = temp_energy(:,gin,iazi,ipol) / norm
end if
end do
if (scatt_type == ANGLE_LEGENDRE .and. legendre_mu_points /= 1) then
call this % scatter(iazi, ipol) % obj % init(legendre_mu_points, &
temp_energy(:,:,iazi,ipol), temp_mult(:,:,iazi,ipol), &
scatt_coeffs(:,:,:,iazi,ipol))
else
call this % scatter(iazi, ipol) % obj % init(this % order, &
temp_energy(:,:,iazi,ipol), temp_mult(:,:,iazi,ipol), &
scatt_coeffs(:,:,:,iazi,ipol))
end if
end do
end do
! Now go through and normalize chi
if (mat % fissionable) then
do ipol = 1, npol
do iazi = 1, nazi
do gin = 1, groups
! Normalize Chi
norm = sum(this % chi(:,gin,iazi,ipol))
if (norm > ZERO) then
this % chi(:,gin,iazi,ipol) = this % chi(:,gin,iazi,ipol) / norm
end if
end do
end do
end do
end if
! Deallocate temporaries for the next material
deallocate(scatt_coeffs, temp_energy, temp_mult)
end subroutine macroxsangle_init
!===============================================================================
! MACROXS_*_GET_XS returns the requested data type
!===============================================================================
function macroxsiso_get_xs(this, g, xstype, gout, uvw) result(xs)
class(MacroXSIso), intent(in) :: this ! The MacroXS to initialize
integer, intent(in) :: g ! Incoming Energy group
character(*) , intent(in) :: xstype ! Type of xs requested
integer, optional, intent(in) :: gout ! Outgoing Energy group
real(8), optional, intent(in) :: uvw(3) ! Requested Angle
real(8) :: xs ! Requested x/s
select case(xstype)
case('total')
xs = this % total(g)
case('absorption')
xs = this % absorption(g)
case('fission')
xs = this % fission(g)
case('k_fission')
xs = this % k_fission(g)
case('nu_fission')
xs = this % nu_fission(g)
case('scatter')
xs = this % scattxs(g)
case('mult')
if (present(gout)) then
xs = this % scatter % mult(gout,g)
else
xs = sum(this % scatter % mult(:,g))
end if
end select
end function macroxsiso_get_xs
function macroxsangle_get_xs(this, g, xstype, gout,uvw) result(xs)
class(MacroXSAngle), intent(in) :: this ! The MacroXS to initialize
integer, intent(in) :: g ! Incoming Energy group
character(*) , intent(in) :: xstype ! Type of xs requested
integer, optional, intent(in) :: gout ! Outgoing Energy group
real(8), optional, intent(in) :: uvw(3) ! Requested Angle
real(8) :: xs ! Requested x/s
integer :: iazi, ipol
if (present(uvw)) then
call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol)
select case(xstype)
case('total')
xs = this % total(g,iazi,ipol)
case('absorption')
xs = this % absorption(g,iazi,ipol)
case('fission')
xs = this % fission(g,iazi,ipol)
case('k_fission')
xs = this % k_fission(g,iazi,ipol)
case('nu_fission')
xs = this % nu_fission(g,iazi,ipol)
case('scatter')
xs = this % scattxs(g,iazi,ipol)
case('mult')
if (present(gout)) then
xs = this % scatter(iazi,ipol) % obj % mult(gout,g)
else
xs = sum(this % scatter(iazi,ipol) % obj % mult(:,g))
end if
end select
end if
end function macroxsangle_get_xs
!===============================================================================
! MACROXS_*_SAMPLE_FISSION_ENERGY samples the outgoing energy from a fission
! event
!===============================================================================
function macroxsiso_sample_fission_energy(this, gin, uvw) result(gout)
class(MacroXSIso), intent(in) :: this ! Data to work with
integer, intent(in) :: gin ! Incoming energy group
real(8), intent(in) :: uvw(3) ! Particle Direction
integer :: gout ! Sampled outgoing group
real(8) :: xi ! Our random number
real(8) :: prob ! Running probability
xi = prn()
prob = ZERO
gout = 0
do while (prob < xi)
gout = gout + 1
prob = prob + this % chi(gout,gin)
end do
end function macroxsiso_sample_fission_energy
function macroxsangle_sample_fission_energy(this, gin, uvw) result(gout)
class(MacroXSAngle), intent(in) :: this ! Data to work with
integer, intent(in) :: gin ! Incoming energy group
real(8), intent(in) :: uvw(3) ! Particle Direction
integer :: gout ! Sampled outgoing group
real(8) :: xi ! Our random number
real(8) :: prob ! Running probability
integer :: iazi, ipol
call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol)
xi = prn()
prob = ZERO
gout = 0
do while (prob < xi)
gout = gout + 1
prob = prob + this % chi(gout,gin,iazi,ipol)
end do
end function macroxsangle_sample_fission_energy
!===============================================================================
! MACROXS*_SAMPLE_SCATTER Selects outgoing energy and angle after a scatter
! event
!===============================================================================
subroutine macroxsiso_sample_scatter(this, uvw, gin, gout, mu, wgt)
class(MacroXSIso), intent(in) :: this
real(8), intent(in) :: uvw(3) ! Incoming neutron direction
integer, intent(in) :: gin ! Incoming neutron group
integer, intent(out) :: gout ! Sampled outgoin group
real(8), intent(out) :: mu ! Sampled change in angle
real(8), intent(inout) :: wgt ! Particle weight
call this % scatter % sample(gin, gout, mu, wgt)
end subroutine macroxsiso_sample_scatter
subroutine macroxsangle_sample_scatter(this, uvw, gin, gout, mu, wgt)
class(MacroXSAngle), intent(in) :: this
real(8), intent(in) :: uvw(3) ! Incoming neutron direction
integer, intent(in) :: gin ! Incoming neutron group
integer, intent(out) :: gout ! Sampled outgoin group
real(8), intent(out) :: mu ! Sampled change in angle
real(8), intent(inout) :: wgt ! Particle weight
integer :: iazi, ipol ! Angular indices
call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol)
call this % scatter(iazi,ipol) % obj % sample(gin,gout,mu,wgt)
end subroutine macroxsangle_sample_scatter
!===============================================================================
! MACROXS*_CALCULATE_XS determines the multi-group macroscopic cross sections
! for the material the particle is currently traveling through.
!===============================================================================
subroutine macroxsiso_calculate_xs(this, gin, uvw, xs)
class(MacroXSIso), intent(in) :: this
integer, intent(in) :: gin ! Incoming neutron group
real(8), intent(in) :: uvw(3) ! Incoming neutron direction
type(MaterialMacroXS), intent(inout) :: xs ! Resultant MacroXS Data
xs % total = this % total(gin)
xs % elastic = this % scattxs(gin)
xs % absorption = this % absorption(gin)
xs % nu_fission = this % nu_fission(gin)
end subroutine macroxsiso_calculate_xs
subroutine macroxsangle_calculate_xs(this, gin, uvw, xs)
class(MacroXSAngle), intent(in) :: this
integer, intent(in) :: gin ! Incoming neutron group
real(8), intent(in) :: uvw(3) ! Incoming neutron direction
type(MaterialMacroXS), intent(inout) :: xs ! Resultant MacroXS Data
integer :: iazi, ipol
call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol)
xs % total = this % total(gin, iazi, ipol)
xs % elastic = this % scattxs(gin, iazi, ipol)
xs % absorption = this % absorption(gin, iazi, ipol)
xs % nu_fission = this % nu_fission(gin, iazi, ipol)
end subroutine macroxsangle_calculate_xs
end module macroxs_header

View file

@ -826,30 +826,4 @@ contains
end do
end subroutine broaden_wmp_polynomials
!===============================================================================
! find_angle finds the closest angle on the data grid and returns that index
!===============================================================================
pure subroutine find_angle(polar, azimuthal, uvw, i_azi, i_pol)
real(8), intent(in) :: polar(:) ! Polar angles [0,pi]
real(8), intent(in) :: azimuthal(:) ! Azi. angles [-pi,pi]
real(8), intent(in) :: uvw(3) ! Direction of motion
integer, intent(inout) :: i_pol ! Closest polar bin
integer, intent(inout) :: i_azi ! Closest azi bin
real(8) :: my_pol, my_azi, dangle
! Convert uvw to polar and azi
my_pol = acos(uvw(3))
my_azi = atan2(uvw(2), uvw(1))
! Search for equi-binned angles
dangle = PI / real(size(polar),8)
i_pol = floor(my_pol / dangle + ONE)
dangle = TWO * PI / real(size(azimuthal),8)
i_azi = floor((my_azi + PI) / dangle + ONE)
end subroutine find_angle
end module math

View file

@ -3,9 +3,8 @@ module mgxs_data
use constants
use error, only: fatal_error
use global
use macroxs_header
use material_header, only: Material
use nuclide_header
use mgxs_header
use output, only: write_message
use set_header, only: SetChar
use string, only: to_lower
@ -71,7 +70,8 @@ contains
if (tallies(i) % score_bins(l) == SCORE_KAPPA_FISSION) then
get_kfiss = .true.
end if
if (tallies(i) % score_bins(l) == SCORE_FISSION) then
if (tallies(i) % score_bins(l) == SCORE_FISSION .or. &
tallies(i) % score_bins(l) == SCORE_NU_FISSION) then
get_fiss = .true.
end if
end do
@ -118,17 +118,14 @@ contains
! Now allocate accordingly
select case(representation)
case(MGXS_ISOTROPIC)
allocate(NuclideIso :: nuclides_MG(i_nuclide) % obj)
allocate(MgxsIso :: nuclides_MG(i_nuclide) % obj)
case(MGXS_ANGLE)
allocate(NuclideAngle :: nuclides_MG(i_nuclide) % obj)
allocate(MgxsAngle :: nuclides_MG(i_nuclide) % obj)
end select
! Now read in the data specific to the type we just declared
call nuclides_MG(i_nuclide) % obj % init(node_xsdata, energy_groups, &
get_kfiss, get_fiss)
! Keep track of what listing is associated with this nuclide
nuclides_MG(i_nuclide) % obj % listing = i_listing
call nuclides_MG(i_nuclide) % obj % init_file(node_xsdata, &
energy_groups, get_kfiss, get_fiss, max_order, i_listing)
! Add name and alias to dictionary
call already_read % add(name)
@ -167,31 +164,8 @@ contains
subroutine create_macro_xs()
integer :: i_mat ! index in materials array
integer :: i ! loop index over nuclides
integer :: l ! Loop over score bins
type(Material), pointer :: mat ! current material
logical :: get_kfiss, get_fiss
integer :: error_code
character(MAX_LINE_LEN) :: error_text
integer :: scatt_type
integer :: legendre_mu_points
! Find out if we need fission & kappa fission
! (i.e., are there any SCORE_FISSION or SCORE_KAPPA_FISSION tallies?)
get_kfiss = .false.
get_fiss = .false.
do i = 1, n_tallies
do l = 1, tallies(i) % n_score_bins
if (tallies(i) % score_bins(l) == SCORE_KAPPA_FISSION) then
get_kfiss = .true.
end if
if (tallies(i) % score_bins(l) == SCORE_FISSION) then
get_fiss = .true.
end if
end do
if (get_kfiss .and. get_fiss) &
exit
end do
allocate(macro_xs(n_materials))
@ -203,21 +177,15 @@ contains
! Therefore type(nuclides(mat % nuclide(1)) % obj) dictates type(macroxs)
! At the same time, we will find the scattering type, as that will dictate
! how we allocate the scatter object within macroxs
legendre_mu_points = nuclides_MG(mat % nuclide(1)) % obj % legendre_mu_points
scatt_type = nuclides_MG(mat % nuclide(1)) % obj % scatt_type
select type(nuc => nuclides_MG(mat % nuclide(1)) % obj)
type is (NuclideIso)
allocate(MacroXSIso :: macro_xs(i_mat) % obj)
type is (NuclideAngle)
allocate(MacroXSAngle :: macro_xs(i_mat) % obj)
type is (MgxsIso)
allocate(MgxsIso :: macro_xs(i_mat) % obj)
type is (MgxsAngle)
allocate(MgxsAngle :: macro_xs(i_mat) % obj)
end select
call macro_xs(i_mat) % obj % init(mat, nuclides_MG, energy_groups, &
get_kfiss, get_fiss, max_order, &
scatt_type, legendre_mu_points, &
error_code, error_text)
! Handle any errors
if (error_code /= 0) call fatal_error(trim(error_text))
call macro_xs(i_mat) % obj % combine(mat, nuclides_MG, energy_groups, &
max_order, scatt_type, i_mat)
end do
end subroutine create_macro_xs

1929
src/mgxs_header.F90 Normal file

File diff suppressed because it is too large Load diff

View file

@ -6,6 +6,7 @@ module multipole
use hdf5_interface
use multipole_header, only: MultipoleArray, FIT_T, FIT_A, FIT_F, &
MP_FISS, FORM_MLBW, FORM_RM
use search, only: binary_search
implicit none
@ -23,163 +24,191 @@ contains
type(MultipoleArray), intent(out), target :: multipole ! The object to fill
integer, intent(in) :: i_table ! index in nuclides/
! sab_tables
integer(HID_T) :: file_id
integer(HID_T) :: group_id
! Intermediate loading components
integer :: NMT
integer :: i, j
integer, allocatable :: MT(:)
logical :: accumulated_fission
character(len=24) :: MT_n ! Takes the form '/nuclide/reactions/MT???'
integer :: is_fissionable
real(8) :: insert_pts(4) ! New points in the energy grid
integer :: cut1, cut2 ! Old indices just outside MP region
integer :: new_n_grid ! Number of points in new E grid
real(8), allocatable :: new_energy(:) ! New energy grid
real(8) :: f1, f2 ! Interpolation near cut1 & cut2
real(8), allocatable :: new_xs(:) ! New cross sections
integer :: i
integer :: IE ! Reaction threshold
associate (nuc => nuclides(i_table))
! Open file for reading and move into the /isotope group
!=========================================================================
! Copy in data from the file.
! Open file for reading and move into the /isotope group.
file_id = file_open(filename, 'r', parallel=.true.)
group_id = open_group(file_id, "/nuclide")
! Load in all the array size scalars
call read_dataset(group_id, "length", multipole % length)
call read_dataset(group_id, "windows", multipole % windows)
call read_dataset(group_id, "num_l", multipole % num_l)
call read_dataset(group_id, "fit_order", multipole % fit_order)
call read_dataset(group_id, "max_w", multipole % max_w)
call read_dataset(group_id, "fissionable", is_fissionable)
! Load in all the array size scalars.
call read_dataset(multipole % length, group_id, "length")
call read_dataset(multipole % windows, group_id, "windows")
call read_dataset(multipole % num_l, group_id, "num_l")
call read_dataset(multipole % fit_order, group_id, "fit_order")
call read_dataset(multipole % max_w, group_id, "max_w")
call read_dataset(is_fissionable, group_id, "fissionable")
if (is_fissionable == MP_FISS) then
multipole % fissionable = .true.
else
multipole % fissionable = .false.
end if
call read_dataset(group_id, "formalism", multipole % formalism)
call read_dataset(multipole % formalism, group_id, "formalism")
call read_dataset(group_id, "spacing", multipole % spacing)
call read_dataset(group_id, "sqrtAWR", multipole % sqrtAWR)
call read_dataset(group_id, "start_E", multipole % start_E)
call read_dataset(group_id, "end_E", multipole % end_E)
call read_dataset(multipole % spacing, group_id, "spacing")
call read_dataset(multipole % sqrtAWR, group_id, "sqrtAWR")
call read_dataset(multipole % start_E, group_id, "start_E")
call read_dataset(multipole % end_E, group_id, "end_E")
! Allocate the multipole array components
! Allocate the multipole array components.
call multipole % allocate()
! Read in arrays
call read_dataset(group_id, "data", multipole % data)
call read_dataset(group_id, "pseudo_K0RS", multipole % pseudo_k0RS)
call read_dataset(group_id, "l_value", multipole % l_value)
call read_dataset(group_id, "w_start", multipole % w_start)
call read_dataset(group_id, "w_end", multipole % w_end)
call read_dataset(group_id, "broaden_poly", multipole % broaden_poly)
! Read in arrays.
call read_dataset(multipole % data, group_id, "data")
call read_dataset(multipole % pseudo_k0RS, group_id, "pseudo_K0RS")
call read_dataset(multipole % l_value, group_id, "l_value")
call read_dataset(multipole % w_start, group_id, "w_start")
call read_dataset(multipole % w_end, group_id, "w_end")
call read_dataset(multipole % broaden_poly, group_id, "broaden_poly")
call read_dataset(group_id, "curvefit", multipole % curvefit)
! Delete ACE pointwise data
call read_dataset(group_id, "n_grid", nuc % n_grid)
deallocate(nuc % energy)
deallocate(nuc % total)
deallocate(nuc % elastic)
deallocate(nuc % fission)
deallocate(nuc % nu_fission)
deallocate(nuc % absorption)
allocate(nuc % energy(nuc % n_grid))
allocate(nuc % total(nuc % n_grid))
allocate(nuc % elastic(nuc % n_grid))
allocate(nuc % fission(nuc % n_grid))
allocate(nuc % nu_fission(nuc % n_grid))
allocate(nuc % absorption(nuc % n_grid))
nuc % total(:) = ZERO
nuc % absorption(:) = ZERO
nuc % fission(:) = ZERO
! Read in new energy axis (converting eV to MeV)
call read_dataset(group_id, "energy_points", nuc % energy)
nuc % energy = nuc % energy / 1.0e6_8
! Get count and list of MT tables
call read_dataset(group_id, "MT_count", NMT)
allocate(MT(NMT))
call read_dataset(group_id, "MT_list", MT)
call read_dataset(multipole % curvefit, group_id, "curvefit")
! Close the file.
call close_group(group_id)
call file_close(file_id)
accumulated_fission = .false.
!=========================================================================
! Remove the uneeded/inconsitent pointwise data. This step enforces the
! assumption that no inelastic scattering reactions can occur in the
! multipole region. The energy grid is replaced with one that removes all
! energies covered by multiple and adds four new points. Two new points
! mark the edges of the multipole region and cross sections will be
! interpolated to these points. The other two points are used to zero the
! cross sections inside the multipole region.
! Loop over each MT entry and load it into a reaction.
do i = 1, NMT
write(MT_n, '(A, I3.3)') '/nuclide/reactions/MT', MT(i)
! Define the four new inserted points.
insert_pts(:) = [multipole % start_E / 1e6_8, &
multipole % start_E / 1e6_8 + 1e-12_8, &
multipole % end_E / 1e6_8 - 1e-12_8, &
multipole % end_E / 1e6_8]
group_id = open_group(file_id, MT_n)
! Find the points just outside the multipole region.
cut1 = binary_search(nuc % energy, nuc % n_grid, insert_pts(1))
cut2 = binary_search(nuc % energy, nuc % n_grid, insert_pts(4)) + 1
if (nuc % energy(cut1) == insert_pts(1)) cut1 = cut1 - 1
if (nuc % energy(cut2) == insert_pts(4)) cut2 = cut2 + 1
! Each MT needs to be treated slightly differently.
select case (MT(i))
case(ELASTIC)
call read_dataset(group_id, "MT_sigma", nuc % elastic)
nuc % total(:) = nuc % total + nuc % elastic
case(N_FISSION)
call read_dataset(group_id, "MT_sigma", nuc % fission)
nuc % total(:) = nuc % total + nuc % fission
nuc % absorption(:) = nuc % absorption + nuc % fission
accumulated_fission = .true.
case default
! Search through all of our secondary reactions
do j = 1, nuc % n_reaction
if (nuc % reactions(j) % MT == MT(i)) then
! Match found
! Generate the new energy grid.
new_n_grid = nuc % n_grid - (cut2 - cut1 - 1) + 4
allocate(new_energy(new_n_grid))
new_energy(1:cut1) = nuc % energy(1:cut1)
new_energy(cut1+1:cut1+4) = insert_pts(:)
new_energy(cut1+5:new_n_grid) = nuc % energy(cut2:nuc % n_grid)
! Individual Fission components exist, so remove the combined
! fission cross section.
if ( (MT(i) == N_F .or. MT(i) == N_NF .or. MT(i) == N_2NF &
.or. MT(i) == N_3NF) .and. accumulated_fission) then
nuc % total(:) = nuc % total - nuc % fission
nuc % absorption(:) = nuc % absorption - nuc % fission
nuc % fission(:) = ZERO
accumulated_fission = .false.
end if
! Compute interpolation factors for the new energy points.
f1 = (insert_pts(1) - nuc % energy(cut1)) &
/ (nuc % energy(cut1+1) - nuc % energy(cut1))
f2 = (insert_pts(4) - nuc % energy(cut2-1)) &
/ (nuc % energy(cut2) - nuc % energy(cut2-1))
deallocate(nuc % reactions(j) % sigma)
allocate(nuc % reactions(j) % sigma(nuc % n_grid))
! Adjust the total cross section.
allocate(new_xs(new_n_grid))
new_xs(1:cut1) = nuc % total(1:cut1)
new_xs(cut1+1) = (ONE - f1) * nuc % total(cut1) &
+ f1 * nuc % total(cut1+1)
new_xs(cut1+2:cut1+3) = ZERO
new_xs(cut1+4) = (ONE - f2) * nuc % total(cut2-1) &
+ f2 * nuc % total(cut2)
new_xs(cut1+5:new_n_grid) = nuc % total(cut2:nuc % n_grid)
call move_alloc(new_xs, nuc % total)
call read_dataset(group_id, "MT_sigma", &
nuc % reactions(j) % sigma)
call read_dataset(group_id, "Q_value", &
nuc % reactions(j) % Q_value)
call read_dataset(group_id, "threshold", &
nuc % reactions(j) % threshold)
nuc % reactions(j) % threshold = 1 ! TODO: reconsider implications.
nuc % reactions(j) % Q_value = nuc % reactions(j) % Q_value &
/ 1.0e6_8
! Adjust the elastic cross section.
allocate(new_xs(new_n_grid))
new_xs(1:cut1) = nuc % elastic(1:cut1)
new_xs(cut1+1) = (ONE - f1) * nuc % elastic(cut1) &
+ f1 * nuc % elastic(cut1+1)
new_xs(cut1+2:cut1+3) = ZERO
new_xs(cut1+4) = (ONE - f2) * nuc % elastic(cut2-1) &
+ f2 * nuc % elastic(cut2)
new_xs(cut1+5:new_n_grid) = nuc % elastic(cut2:nuc % n_grid)
call move_alloc(new_xs, nuc % elastic)
! Accumulate total
if (MT(i) /= N_LEVEL .and. MT(i) <= N_DA) then
nuc % total(:) = nuc % total + nuc % reactions(j) % sigma
end if
! Adjust the fission cross section.
allocate(new_xs(new_n_grid))
new_xs(1:cut1) = nuc % fission(1:cut1)
new_xs(cut1+1) = (ONE - f1) * nuc % fission(cut1) &
+ f1 * nuc % fission(cut1+1)
new_xs(cut1+2:cut1+3) = ZERO
new_xs(cut1+4) = (ONE - f2) * nuc % fission(cut2-1) &
+ f2 * nuc % fission(cut2)
new_xs(cut1+5:new_n_grid) = nuc % fission(cut2:nuc % n_grid)
call move_alloc(new_xs, nuc % fission)
! Accumulate absorption
if (MT(i) >= N_GAMMA .and. MT(i) <= N_DA) then
nuc % absorption(:) = nuc % absorption &
+ nuc % reactions(j) % sigma
end if
! Adjust the nu-fission cross section.
allocate(new_xs(new_n_grid))
new_xs(1:cut1) = nuc % nu_fission(1:cut1)
new_xs(cut1+1) = (ONE - f1) * nuc % nu_fission(cut1) &
+ f1 * nuc % nu_fission(cut1+1)
new_xs(cut1+2:cut1+3) = ZERO
new_xs(cut1+4) = (ONE - f2) * nuc % nu_fission(cut2-1) &
+ f2 * nuc % nu_fission(cut2)
new_xs(cut1+5:new_n_grid) = nuc % nu_fission(cut2:nuc % n_grid)
call move_alloc(new_xs, nuc % nu_fission)
! Accumulate fission (if needed)
if ( (MT(i) == N_F .or. MT(i) == N_NF .or. MT(i) == N_2NF &
.or. MT(i) == N_3NF) ) then
nuc % fission(:) = nuc % fission + nuc % reactions(j) % sigma
nuc % absorption(:) = nuc % absorption &
+ nuc % reactions(j) % sigma
end if
end if
end do
end select
! Adjust the absorption cross section.
allocate(new_xs(new_n_grid))
new_xs(1:cut1) = nuc % absorption(1:cut1)
new_xs(cut1+1) = (ONE - f1) * nuc % absorption(cut1) &
+ f1 * nuc % absorption(cut1+1)
new_xs(cut1+2:cut1+3) = ZERO
new_xs(cut1+4) = (ONE - f2) * nuc % absorption(cut2-1) &
+ f2 * nuc % absorption(cut2)
new_xs(cut1+5:new_n_grid) = nuc % absorption(cut2:nuc % n_grid)
call move_alloc(new_xs, nuc % absorption)
call close_group(group_id)
! Adjust other cross sections.
do i = 1, nuc % n_reaction
associate (rxn => nuc % reactions(i))
if (.not. allocated(rxn % sigma)) cycle ! Skip unallocated reactions
IE = rxn % threshold
if (rxn % threshold >= cut2) then
! The threshold is above the multipole range. All we need to do
! is adjust the threshold index to match the new grid.
rxn % threshold = rxn % threshold - (cut2 - cut1 - 1) + 4
else if (rxn % threshold <= cut1) then
! The threhold is below the multipole range. Remove the multipole
! region just like we did with the other reactions.
! The new grid removed (cut2 - cut1 - 1) points and added 4.
allocate(new_xs(size(rxn % sigma) - (cut2 - cut1 - 1) + 4))
new_xs(1:cut1-IE+1) = rxn % sigma(1:cut1-IE+1)
new_xs(cut1-IE+2) = (ONE - f1) * rxn % sigma(cut1-IE+1) &
+ f1 * rxn % sigma(cut1-IE+2)
new_xs(cut1-IE+3:cut1-IE+4) = ZERO
new_xs(cut1-IE+5) = (ONE - f2) * rxn % sigma(cut2-IE) &
+ f2 * rxn % sigma(cut2-IE+1)
new_xs(cut1-IE+6:size(new_xs)) = &
rxn % sigma(cut2-IE+1:size(rxn % sigma))
call move_alloc(new_xs, rxn % sigma)
else
! The threshold lies within the multipole range. Remove the first
! cut2-IE points and add an interpolated point
allocate(new_xs(size(rxn % sigma) - (cut2-IE) + 1))
new_xs(1) = (ONE - f2) * rxn % sigma(cut2-IE) &
+ f2 * rxn % sigma(cut2-IE+1)
new_xs(2:size(new_xs)) = rxn % sigma(cut2-IE+1:size(rxn % sigma))
call move_alloc(new_xs, rxn % sigma)
rxn % threshold = cut1 + 4
end if
end associate
end do
! Close file
call file_close(file_id)
! Apply the new energy grid.
nuc % n_grid = new_n_grid
call move_alloc(new_energy, nuc % energy)
end associate

View file

@ -8,7 +8,7 @@ module nuclide_header
use endf_header, only: Function1D
use error, only: fatal_error, warning
use list_header, only: ListInt
use math, only: evaluate_legendre, find_angle
use math, only: evaluate_legendre
use multipole_header, only: MultipoleArray
use product_header, only: AngleEnergyContainer
use reaction_header, only: Reaction
@ -20,12 +20,12 @@ module nuclide_header
implicit none
!===============================================================================
! Nuclide contains the base nuclidic data for a nuclide, which does not depend
! upon how the nuclear data is represented (i.e., CE, or any variant of MG).
! The extended types, NuclideCE and NuclideMG deal with the rest
! Nuclide contains the base nuclidic data for a nuclide described as needed
! for continuous-energy neutron transport.
!===============================================================================
type, abstract :: Nuclide
type :: Nuclide
! Nuclide meta-data
character(12) :: name ! name of nuclide, e.g. 92235.03c
integer :: zaid ! Z and A identifier, e.g. 92235
real(8) :: awr ! Atomic Weight Ratio
@ -33,21 +33,8 @@ module nuclide_header
real(8) :: kT ! temperature in MeV (k*T)
! Fission information
logical :: fissionable ! nuclide is fissionable?
logical :: fissionable ! nuclide is fissionable?
contains
procedure(nuclide_print_), deferred :: print ! Writes nuclide info
end type Nuclide
abstract interface
subroutine nuclide_print_(this, unit)
import Nuclide
class(Nuclide),intent(in) :: this
integer, optional, intent(in) :: unit
end subroutine nuclide_print_
end interface
type, extends(Nuclide) :: NuclideCE
! Energy grid information
integer :: n_grid ! # of nuclide grid points
integer, allocatable :: grid_index(:) ! log grid mapping indices
@ -95,129 +82,14 @@ module nuclide_header
! array; used at tally-time
contains
procedure :: clear => nuclidece_clear
procedure :: print => nuclidece_print
procedure :: nu => nuclidece_nu
end type NuclideCE
type, abstract, extends(Nuclide) :: NuclideMG
! Scattering Order Information
integer :: order ! Order of data (Scattering for NuclideIso,
! Number of angles for all in NuclideAngle)
integer :: scatt_type ! either legendre, histogram, or tabular.
integer :: legendre_mu_points ! Number of tabular points to use to represent
! Legendre distribs, -1 if sample with the
! Legendres themselves
contains
procedure(nuclidemg_init_), deferred :: init ! Initialize the data
procedure(nuclidemg_get_xs_), deferred :: get_xs ! Get the requested xs
procedure(nuclidemg_calc_f_), deferred :: calc_f ! Calculates f, given mu
end type NuclideMG
abstract interface
subroutine nuclidemg_init_(this, node_xsdata, groups, get_kfiss, get_fiss)
import NuclideMG, Node
class(NuclideMG), intent(inout) :: this ! Working Object
type(Node), pointer, intent(in) :: node_xsdata ! Data from MGXS xml
integer, intent(in) :: groups ! Number of Energy groups
logical, intent(in) :: get_kfiss ! Need Kappa-Fission?
logical, intent(in) :: get_fiss ! Should we get fiss data?
end subroutine nuclidemg_init_
function nuclidemg_get_xs_(this, g, xstype, gout, uvw, mu, i_azi, i_pol) &
result(xs)
import NuclideMG
class(NuclideMG), intent(in) :: this
integer, intent(in) :: g ! Incoming Energy group
character(*), intent(in) :: xstype ! Cross Section Type
integer, optional, intent(in) :: gout ! Outgoing Group
real(8), optional, intent(in) :: uvw(3) ! Requested Angle
real(8), optional, intent(in) :: mu ! Change in angle
integer, optional, intent(in) :: i_azi ! Azimuthal Index
integer, optional, intent(in) :: i_pol ! Polar Index
real(8) :: xs ! Resultant xs
end function nuclidemg_get_xs_
pure function nuclidemg_calc_f_(this, gin, gout, mu, uvw, i_azi, i_pol) result(f)
import NuclideMG
class(NuclideMG), intent(in) :: this
integer, intent(in) :: gin ! Incoming Energy Group
integer, intent(in) :: gout ! Outgoing Energy Group
real(8), intent(in) :: mu ! Angle of interest
real(8), intent(in), optional :: uvw(3) ! Direction vector
integer, intent(in), optional :: i_azi ! Incoming Energy Group
integer, intent(in), optional :: i_pol ! Outgoing Energy Group
real(8) :: f ! Return value of f(mu)
end function nuclidemg_calc_f_
end interface
!===============================================================================
! NuclideIso contains the base MGXS data for a nuclide specifically for
! isotropically weighted MGXS
!===============================================================================
type, extends(NuclideMG) :: NuclideIso
! Microscopic cross sections
real(8), allocatable :: total(:) ! total cross section
real(8), allocatable :: absorption(:) ! absorption cross section
real(8), allocatable :: scatter(:,:,:) ! scattering information
real(8), allocatable :: nu_fission(:,:) ! fission matrix (Gout x Gin)
real(8), allocatable :: k_fission(:) ! kappa-fission
real(8), allocatable :: fission(:) ! neutron production
real(8), allocatable :: chi(:) ! Fission Spectra
real(8), allocatable :: mult(:,:) ! Scatter multiplicity (Gout x Gin)
contains
procedure :: init => nuclideiso_init ! Initialize Nuclidic MGXS Data
procedure :: print => nuclideiso_print ! Writes nuclide info
procedure :: get_xs => nuclideiso_get_xs ! Gets Size of Data w/in Object
procedure :: calc_f => nuclideiso_calc_f ! Calcs f given mu
end type NuclideIso
!===============================================================================
! NuclideAngle contains the base MGXS data for a nuclide specifically for
! explicit angle-dependent weighted MGXS
!===============================================================================
type, extends(NuclideMG) :: NuclideAngle
! Microscopic cross sections. Dimensions are: (n_pol, n_azi, Nl, Ng, Ng)
real(8), allocatable :: total(:,:,:) ! total cross section
real(8), allocatable :: absorption(:,:,:) ! absorption cross section
real(8), allocatable :: scatter(:,:,:,:,:) ! scattering information
real(8), allocatable :: nu_fission(:,:,:,:) ! fission matrix (Gout x Gin)
real(8), allocatable :: k_fission(:,:,:) ! kappa-fission
real(8), allocatable :: fission(:,:,:) ! neutron production
real(8), allocatable :: chi(:,:,:) ! Fission Spectra
real(8), allocatable :: mult(:,:,:,:) ! Scatter multiplicity (Gout x Gin)
! In all cases, right-most indices are theta, phi
integer :: n_pol ! Number of polar angles
integer :: n_azi ! Number of azimuthal angles
real(8), allocatable :: polar(:) ! polar angles
real(8), allocatable :: azimuthal(:) ! azimuthal angles
contains
procedure :: init => nuclideangle_init ! Initialize Nuclidic MGXS Data
procedure :: print => nuclideangle_print ! Gets Size of Data w/in Object
procedure :: get_xs => nuclideangle_get_xs ! Gets Size of Data w/in Object
procedure :: calc_f => nuclideangle_calc_f ! Calcs f given mu
end type NuclideAngle
!===============================================================================
! NUCLIDEMGCONTAINER pointer array for storing Nuclides
!===============================================================================
type NuclideMGContainer
class(NuclideMG), pointer :: obj
end type NuclideMGContainer
procedure :: clear => nuclide_clear
procedure :: print => nuclide_print
procedure :: nu => nuclide_nu
end type Nuclide
!===============================================================================
! NUCLIDE0K temporarily contains all 0K cross section data and other parameters
! needed to treat resonance scattering before transferring them to NuclideCE
! needed to treat resonance scattering before transferring them to Nuclide
!===============================================================================
type Nuclide0K
@ -294,397 +166,11 @@ module nuclide_header
contains
!===============================================================================
! NUCLIDE_*_INIT reads in the data from the XML file, as already accessed
! NUCLIDE_CLEAR resets and deallocates data in Nuclide
!===============================================================================
subroutine nuclidemg_init(this, node_xsdata)
class(NuclideMG), intent(inout) :: this ! Working Object
type(Node), pointer, intent(in) :: node_xsdata ! Data from MGXS xml
type(Node), pointer :: node_legendre_mu
character(MAX_LINE_LEN) :: temp_str
logical :: enable_leg_mu
! Load the data
call get_node_value(node_xsdata, "name", this % name)
this % name = to_lower(this % name)
if (check_for_node(node_xsdata, "kT")) then
call get_node_value(node_xsdata, "kT", this % kT)
else
this % kT = ZERO
end if
if (check_for_node(node_xsdata, "zaid")) then
call get_node_value(node_xsdata, "zaid", this % zaid)
else
this % zaid = -1
end if
if (check_for_node(node_xsdata, "scatt_type")) then
call get_node_value(node_xsdata, "scatt_type", temp_str)
temp_str = trim(to_lower(temp_str))
if (temp_str == 'legendre') then
this % scatt_type = ANGLE_LEGENDRE
else if (temp_str == 'histogram') then
this % scatt_type = ANGLE_HISTOGRAM
else if (temp_str == 'tabular') then
this % scatt_type = ANGLE_TABULAR
else
call fatal_error("Invalid Scatt Type Option!")
end if
else
this % scatt_type = ANGLE_LEGENDRE
end if
if (check_for_node(node_xsdata, "order")) then
call get_node_value(node_xsdata, "order", this % order)
else
call fatal_error("Order Must Be Provided!")
end if
! Get scattering treatment
if (check_for_node(node_xsdata, "tabular_legendre")) then
call get_node_ptr(node_xsdata, "tabular_legendre", node_legendre_mu)
if (check_for_node(node_legendre_mu, "enable")) then
call get_node_value(node_legendre_mu, "enable", temp_str)
temp_str = trim(to_lower(temp_str))
if (temp_str == 'true' .or. temp_str == '1') then
enable_leg_mu = .true.
elseif (temp_str == 'false' .or. temp_str == '0') then
enable_leg_mu = .false.
this % legendre_mu_points = 1
else
call fatal_error("Unrecognized tabular_legendre/enable: " // temp_str)
end if
else
enable_leg_mu = .true.
this % legendre_mu_points = 33
end if
if (enable_leg_mu .and. &
check_for_node(node_legendre_mu, "num_points")) then
call get_node_value(node_legendre_mu, "num_points", &
this % legendre_mu_points)
if (this % legendre_mu_points <= 0) then
call fatal_error("num_points element must be positive and non-zero!")
end if
this % legendre_mu_points = -1 * this % legendre_mu_points
end if
else
this % legendre_mu_points = 1
end if
if (check_for_node(node_xsdata, "fissionable")) then
call get_node_value(node_xsdata, "fissionable", temp_str)
temp_str = to_lower(temp_str)
if (trim(temp_str) == 'true' .or. trim(temp_str) == '1') then
this % fissionable = .true.
else
this % fissionable = .false.
end if
else
call fatal_error("Fissionable element must be set!")
end if
end subroutine nuclidemg_init
subroutine nuclideiso_init(this, node_xsdata, groups, get_kfiss, get_fiss)
class(NuclideIso), intent(inout) :: this ! Working Object
type(Node), pointer, intent(in) :: node_xsdata ! Data from MGXS xml
integer, intent(in) :: groups ! Number of Energy groups
logical, intent(in) :: get_kfiss ! Need Kappa-Fission?
logical, intent(in) :: get_fiss ! Need fiss data?
real(8), allocatable :: temp_arr(:)
integer :: arr_len
integer :: order_dim
! Call generic data gathering routine
call nuclidemg_init(this, node_xsdata)
! Load the more specific data
if (this % fissionable) then
if (check_for_node(node_xsdata, "chi")) then
! Get chi
allocate(this % chi(groups))
call get_node_array(node_xsdata, "chi", this % chi)
! Get nu_fission (as a vector)
if (check_for_node(node_xsdata, "nu_fission")) then
allocate(temp_arr(groups * 1))
call get_node_array(node_xsdata, "nu_fission", temp_arr)
allocate(this % nu_fission(groups, 1))
this % nu_fission = reshape(temp_arr, (/groups, 1/))
deallocate(temp_arr)
else
call fatal_error("If fissionable, must provide nu_fission!")
end if
else
! Get nu_fission (as a matrix)
if (check_for_node(node_xsdata, "nu_fission")) then
allocate(temp_arr(groups*groups))
call get_node_array(node_xsdata, "nu_fission", temp_arr)
allocate(this % nu_fission(groups, groups))
this % nu_fission = reshape(temp_arr, (/groups, groups/))
deallocate(temp_arr)
else
call fatal_error("If fissionable, must provide nu_fission!")
end if
end if
if (get_fiss) then
allocate(this % fission(groups))
if (check_for_node(node_xsdata, "fission")) then
call get_node_array(node_xsdata, "fission", this % fission)
else
call fatal_error("Fission data missing, required due to fission&
& tallies in tallies.xml file!")
end if
end if
if (get_kfiss) then
allocate(this % k_fission(groups))
if (check_for_node(node_xsdata, "kappa_fission")) then
call get_node_array(node_xsdata, "kappa_fission", this % k_fission)
else
call fatal_error("kappa_fission data missing, required due to &
&kappa-fission tallies in tallies.xml file!")
end if
end if
end if
allocate(this % absorption(groups))
if (check_for_node(node_xsdata, "absorption")) then
call get_node_array(node_xsdata, "absorption", this % absorption)
else
call fatal_error("Must provide absorption!")
end if
if (this % scatt_type == ANGLE_LEGENDRE) then
order_dim = this % order + 1
else if (this % scatt_type == ANGLE_HISTOGRAM) then
order_dim = this % order
else if (this % scatt_type == ANGLE_TABULAR) then
order_dim = this % order
end if
allocate(this % scatter(groups, groups, order_dim))
if (check_for_node(node_xsdata, "scatter")) then
allocate(temp_arr(groups * groups * order_dim))
call get_node_array(node_xsdata, "scatter", temp_arr)
this % scatter = reshape(temp_arr, (/groups, groups, order_dim/))
deallocate(temp_arr)
else
call fatal_error("Must provide scatter!")
return
end if
allocate(this % total(groups))
if (check_for_node(node_xsdata, "total")) then
call get_node_array(node_xsdata, "total", this % total)
else
this % total = this % absorption + sum(this%scatter(:,:,1),dim=1)
end if
! Get Mult Data
allocate(this % mult(groups, groups))
if (check_for_node(node_xsdata, "multiplicity")) then
arr_len = get_arraysize_double(node_xsdata, "multiplicity")
if (arr_len == groups * groups) then
allocate(temp_arr(arr_len))
call get_node_array(node_xsdata, "multiplicity", temp_arr)
this % mult = reshape(temp_arr, (/groups, groups/))
deallocate(temp_arr)
else
call fatal_error("Multiplicity length not same as number of groups&
& squared!")
return
end if
else
this % mult = ONE
end if
end subroutine nuclideiso_init
subroutine nuclideangle_init(this, node_xsdata, groups, get_kfiss, get_fiss)
class(NuclideAngle), intent(inout) :: this ! Working Object
type(Node), pointer, intent(in) :: node_xsdata ! Data from MGXS xml
integer, intent(in) :: groups ! Number of Energy groups
logical, intent(in) :: get_kfiss ! Need Kappa-Fission?
logical, intent(in) :: get_fiss ! Should we get fiss data?
real(8), allocatable :: temp_arr(:)
integer :: arr_len
real(8) :: dangle
integer :: iangle
integer :: order_dim
! Call generic data gathering routine
call nuclidemg_init(this, node_xsdata)
if (this % scatt_type == ANGLE_LEGENDRE) then
order_dim = this % order + 1
else if (this % scatt_type == ANGLE_HISTOGRAM) then
order_dim = this % order
else if (this % scatt_type == ANGLE_TABULAR) then
order_dim = this % order
end if
if (check_for_node(node_xsdata, "num_polar")) then
call get_node_value(node_xsdata, "num_polar", this % n_pol)
else
call fatal_error("num_polar Must Be Provided!")
end if
if (check_for_node(node_xsdata, "num_azimuthal")) then
call get_node_value(node_xsdata, "num_azimuthal", this % n_azi)
else
call fatal_error("num_azimuthal Must Be Provided!")
end if
! Load angle data, if present (else equally spaced)
allocate(this % polar(this % n_pol))
allocate(this % azimuthal(this % n_azi))
if (check_for_node(node_xsdata, "polar")) then
call fatal_error("User-Specified polar angle bins not yet supported!")
! When this feature is supported, this line will be activated
call get_node_array(node_xsdata, "polar", this % polar)
else
dangle = PI / real(this % n_pol,8)
do iangle = 1, this % n_pol
this % polar(iangle) = (real(iangle,8) - HALF) * dangle
end do
end if
if (check_for_node(node_xsdata, "azimuthal")) then
call fatal_error("User-Specified azimuthal angle bins not yet supported!")
! When this feature is supported, this line will be activated
call get_node_array(node_xsdata, "azimuthal", this % azimuthal)
else
dangle = TWO * PI / real(this % n_azi,8)
do iangle = 1, this % n_azi
this % azimuthal(iangle) = -PI + (real(iangle,8) - HALF) * dangle
end do
end if
! Load the more specific data
if (this % fissionable) then
if (check_for_node(node_xsdata, "chi")) then
! Get chi
allocate(temp_arr(groups * this % n_azi * this % n_pol))
call get_node_array(node_xsdata, "chi", temp_arr)
allocate(this % chi(groups, this % n_azi, this % n_pol))
this % chi = reshape(temp_arr, (/groups, this % n_azi, this % n_pol/))
deallocate(temp_arr)
! Get nu_fission (as a vector)
if (check_for_node(node_xsdata, "nu_fission")) then
allocate(temp_arr(groups * this % n_azi * this % n_pol))
call get_node_array(node_xsdata, "nu_fission", temp_arr)
allocate(this % nu_fission(groups, 1, this % n_azi, this % n_pol))
this % nu_fission = reshape(temp_arr, (/groups, 1, this % n_azi, &
this % n_pol/))
deallocate(temp_arr)
else
call fatal_error("If fissionable, must provide nu_fission!")
end if
else
! Get nu_fission (as a matrix)
if (check_for_node(node_xsdata, "nu_fission")) then
allocate(temp_arr(groups * this % n_azi * this % n_pol))
call get_node_array(node_xsdata, "nu_fission", temp_arr)
allocate(this % nu_fission(groups, groups, this % n_azi, this % n_pol))
this % nu_fission = reshape(temp_arr, (/groups, groups, &
this % n_azi, this % n_pol/))
deallocate(temp_arr)
else
call fatal_error("If fissionable, must provide nu_fission!")
end if
end if
if (get_fiss) then
if (check_for_node(node_xsdata, "fission")) then
allocate(temp_arr(groups * this % n_azi * this % n_pol))
call get_node_array(node_xsdata, "fission", temp_arr)
allocate(this % fission(groups, this % n_azi, this % n_pol))
this % fission = reshape(temp_arr, (/groups, this % n_azi, this % n_pol/))
deallocate(temp_arr)
else
call fatal_error("Fission data missing, required due to fission&
& tallies in tallies.xml file!")
end if
end if
if (get_kfiss) then
if (check_for_node(node_xsdata, "kappa_fission")) then
allocate(temp_arr(groups * this % n_azi * this % n_pol))
call get_node_array(node_xsdata, "kappa_fission", temp_arr)
allocate(this % k_fission(groups, this % n_azi, this % n_pol))
this % k_fission = reshape(temp_arr, (/groups, this % n_azi, this % n_pol/))
deallocate(temp_arr)
else
call fatal_error("kappa_fission data missing, required due to &
&kappa-fission tallies in tallies.xml file!")
end if
end if
end if
if (check_for_node(node_xsdata, "absorption")) then
allocate(temp_arr(groups * this % n_azi * this % n_pol))
call get_node_array(node_xsdata, "absorption", temp_arr)
allocate(this % absorption(groups, this % n_azi, this % n_pol))
this % absorption = reshape(temp_arr, (/groups, this % n_azi, this % n_pol/))
deallocate(temp_arr)
else
call fatal_error("Must provide absorption!")
end if
allocate(this % scatter(groups, groups, order_dim, this % n_azi, this % n_pol))
if (check_for_node(node_xsdata, "scatter")) then
allocate(temp_arr(groups * groups * order_dim * this % n_azi * this%n_pol))
call get_node_array(node_xsdata, "scatter", temp_arr)
this % scatter = reshape(temp_arr, (/groups, groups, order_dim, &
this%n_azi,this%n_pol/))
deallocate(temp_arr)
else
call fatal_error("Must provide scatter!")
end if
if (check_for_node(node_xsdata, "total")) then
allocate(temp_arr(groups * this % n_azi * this % n_pol))
call get_node_array(node_xsdata, "total", temp_arr)
allocate(this % total(groups, this % n_azi, this % n_pol))
this % total = reshape(temp_arr, (/groups, this % n_azi, this % n_pol/))
deallocate(temp_arr)
else
this % total = this % absorption + sum(this%scatter(:,:,1,:,:),dim=1)
end if
! Get Mult Data
allocate(this % mult(groups, groups, this % n_azi, this % n_pol))
if (check_for_node(node_xsdata, "multiplicity")) then
arr_len = get_arraysize_double(node_xsdata, "multiplicity")
if (arr_len == groups * groups * this % n_azi * this % n_pol) then
allocate(temp_arr(arr_len))
call get_node_array(node_xsdata, "multiplicity", temp_arr)
this % mult = reshape(temp_arr, (/groups, groups, this % n_azi, this % n_pol/))
deallocate(temp_arr)
else
call fatal_error("Multiplicity Length Does Not Match!")
end if
else
this % mult = ONE
end if
end subroutine nuclideangle_init
!===============================================================================
! NUCLIDECE_CLEAR resets and deallocates data in Nuclide, NuclideIso
! or NuclideAngle
!===============================================================================
subroutine nuclidece_clear(this)
class(NuclideCE), intent(inout) :: this ! The Nuclide object to clear
subroutine nuclide_clear(this)
class(Nuclide), intent(inout) :: this ! The Nuclide object to clear
if (associated(this % urr_data)) deallocate(this % urr_data)
@ -692,10 +178,14 @@ module nuclide_header
if (associated(this % multipole)) deallocate(this % multipole)
end subroutine nuclidece_clear
end subroutine nuclide_clear
function nuclidece_nu(this, E, emission_mode, group) result(nu)
class(NuclideCE), intent(in) :: this
!===============================================================================
! NUCLIDE_NU is an interface to the number of fission neutrons produced
!===============================================================================
function nuclide_nu(this, E, emission_mode, group) result(nu)
class(Nuclide), intent(in) :: this
real(8), intent(in) :: E
integer, intent(in) :: emission_mode
integer, optional, intent(in) :: group
@ -753,15 +243,16 @@ module nuclide_header
end if
end select
end function nuclidece_nu
end function nuclide_nu
!===============================================================================
! NUCLIDE*_PRINT displays information about a continuous-energy neutron
! cross_section table and its reactions and secondary angle/energy distributions
!===============================================================================
subroutine nuclidece_print(this, unit)
class(NuclideCE), intent(in) :: this
subroutine nuclide_print(this, unit)
class(Nuclide), intent(in) :: this
integer, intent(in), optional :: unit
integer :: i ! loop index over nuclides
@ -834,346 +325,6 @@ module nuclide_header
! Blank line at end of nuclide
write(unit_,*)
end subroutine nuclidece_print
subroutine nuclidemg_print(this, unit_)
class(NuclideMG), intent(in) :: this
integer, intent(in) :: unit_
character(MAX_LINE_LEN) :: temp_str
! Basic nuclide information
write(unit_,*) 'Nuclide ' // trim(this % name)
if (this % zaid > 0) then
! Dont print if data was macroscopic and thus zaid & AWR would be nonsense
write(unit_,*) ' zaid = ' // trim(to_str(this % zaid))
write(unit_,*) ' awr = ' // trim(to_str(this % awr))
end if
write(unit_,*) ' kT = ' // trim(to_str(this % kT))
if (this % scatt_type == ANGLE_LEGENDRE) then
temp_str = "Legendre"
write(unit_,*) ' Scattering Type = ' // trim(temp_str)
write(unit_,*) ' # of Scatter Moments = ' // &
trim(to_str(this % order))
else if (this % scatt_type == ANGLE_HISTOGRAM) then
temp_str = "Histogram"
write(unit_,*) ' Scattering Type = ' // trim(temp_str)
write(unit_,*) ' # of Scatter Bins = ' // &
trim(to_str(this % order))
else if (this % scatt_type == ANGLE_TABULAR) then
temp_str = "Tabular"
write(unit_,*) ' Scattering Type = ' // trim(temp_str)
write(unit_,*) ' # of Scatter Points = ' // trim(to_str(this % order))
end if
write(unit_,*) ' Fissionable = ', this % fissionable
end subroutine nuclidemg_print
subroutine nuclideiso_print(this, unit)
class(NuclideIso), intent(in) :: this
integer, optional, intent(in) :: unit
integer :: unit_ ! unit to write to
integer :: size_total, size_scattmat, size_mgxs
! set default unit for writing information
if (present(unit)) then
unit_ = unit
else
unit_ = OUTPUT_UNIT
end if
! Write Basic Nuclide Information
call nuclidemg_print(this, unit_)
! Determine size of mgxs and scattering matrices
size_scattmat = (size(this % scatter) + size(this % mult)) * 8
size_mgxs = size(this % total) + size(this % absorption) + &
size(this % nu_fission) + size(this % k_fission) + &
size(this % fission) + size(this % chi)
size_mgxs = size_mgxs * 8
! Calculate total memory
size_total = size_scattmat + size_mgxs
! Write memory used
write(unit_,*) ' Memory Requirements'
write(unit_,*) ' Cross sections = ' // trim(to_str(size_mgxs)) // ' bytes'
write(unit_,*) ' Scattering Matrices = ' // &
trim(to_str(size_scattmat)) // ' bytes'
write(unit_,*) ' Total = ' // trim(to_str(size_total)) // ' bytes'
! Blank line at end of nuclide
write(unit_,*)
end subroutine nuclideiso_print
subroutine nuclideangle_print(this, unit)
class(NuclideAngle), intent(in) :: this
integer, optional, intent(in) :: unit
integer :: unit_ ! unit to write to
integer :: size_total, size_scattmat, size_mgxs
! set default unit for writing information
if (present(unit)) then
unit_ = unit
else
unit_ = OUTPUT_UNIT
end if
! Write Basic Nuclide Information
call nuclidemg_print(this, unit_)
write(unit_,*) ' # of Polar Angles = ' // trim(to_str(this % n_pol))
write(unit_,*) ' # of Azimuthal Angles = ' // trim(to_str(this % n_azi))
! Determine size of mgxs and scattering matrices
size_scattmat = (size(this % scatter) + size(this % mult)) * 8
size_mgxs = size(this % total) + size(this % absorption) + &
size(this % nu_fission) + size(this % k_fission) + &
size(this % fission) + size(this % chi)
size_mgxs = size_mgxs * 8
! Calculate total memory
size_total = size_scattmat + size_mgxs
! Write memory used
write(unit_,*) ' Memory Requirements'
write(unit_,*) ' Cross sections = ' // trim(to_str(size_mgxs)) // ' bytes'
write(unit_,*) ' Scattering Matrices = ' // &
trim(to_str(size_scattmat)) // ' bytes'
write(unit_,*) ' Total = ' // trim(to_str(size_total)) // ' bytes'
! Blank line at end of nuclide
write(unit_,*)
end subroutine nuclideangle_print
!===============================================================================
! NUCLIDE*_GET_XS Returns the requested data type
!===============================================================================
function nuclideiso_get_xs(this, g, xstype, gout, uvw, mu, i_azi, i_pol) &
result(xs)
class(NuclideIso), intent(in) :: this
integer, intent(in) :: g ! Incoming Energy group
character(*), intent(in) :: xstype ! Cross Section Type
integer, optional, intent(in) :: gout ! Outgoing Group
real(8), optional, intent(in) :: uvw(3) ! Requested Angle
real(8), optional, intent(in) :: mu ! Change in angle
integer, optional, intent(in) :: i_azi ! Azimuthal Index
integer, optional, intent(in) :: i_pol ! Polar Index
real(8) :: xs ! Resultant xs
xs = ZERO
if ((xstype == 'nu_fission' .or. xstype == 'fission' .or. xstype =='chi' &
.or. xstype =='k_fission') .and. (.not. this % fissionable)) then
return
end if
if (present(gout)) then
select case(xstype)
case('mult')
xs = this % mult(gout,g)
case('nu_fission')
xs = this % nu_fission(gout,g)
case('f_mu', 'f_mu/mult')
xs = this % calc_f(g, gout, mu)
if (xstype == 'f_mu/mult') then
xs = xs / this % mult(gout,g)
end if
end select
else
select case(xstype)
case('total')
xs = this % total(g)
case('absorption')
xs = this % absorption(g)
case('fission')
xs = this % fission(g)
case('k_fission')
if (allocated(this % k_fission)) then
xs = this % k_fission(g)
end if
case('chi')
xs = this % chi(g)
case('scatter')
xs = this % total(g) - this % absorption(g)
end select
end if
end function nuclideiso_get_xs
function nuclideangle_get_xs(this, g, xstype, gout, uvw, mu, i_azi, i_pol) &
result(xs)
class(NuclideAngle), intent(in) :: this
integer, intent(in) :: g ! Incoming Energy group
character(*), intent(in) :: xstype ! Cross Section Type
integer, optional, intent(in) :: gout ! Outgoing Group
real(8), optional, intent(in) :: mu ! Change in angle
real(8), optional, intent(in) :: uvw(3) ! Requested Angle
integer, optional, intent(in) :: i_azi ! Azimuthal Index
integer, optional, intent(in) :: i_pol ! Polar Index
real(8) :: xs ! Resultant xs
integer :: i_azi_, i_pol_
xs = ZERO
if ((xstype == 'nu_fission' .or. xstype == 'fission' .or. xstype =='chi' &
.or. xstype =='k_fission') .and. (.not. this % fissionable)) then
return
end if
if (present(i_azi) .and. present(i_pol)) then
i_azi_ = i_azi
i_pol_ = i_pol
else
call find_angle(this % polar, this % azimuthal, uvw, i_azi_, i_pol_)
end if
if (present(gout)) then
select case(xstype)
case('mult')
xs = this % mult(gout,g,i_azi_,i_pol_)
case('nu_fission')
xs = this % nu_fission(gout,g,i_azi_,i_pol_)
case('chi')
xs = this % chi(gout,i_azi_,i_pol_)
case('f_mu', 'f_mu/mult')
xs = this % calc_f(g, gout, mu, I_AZI=i_azi_, I_POL=i_pol_)
if (xstype == 'f_mu/mult') then
xs = xs / this % mult(gout,g,i_azi_,i_pol_)
end if
end select
else
select case(xstype)
case('total')
xs = this % total(g,i_azi_,i_pol_)
case('absorption')
xs = this % absorption(g,i_azi_,i_pol_)
case('fission')
xs = this % fission(g,i_azi_,i_pol_)
case('k_fission')
if (allocated(this % k_fission)) then
xs = this % k_fission(g,i_azi_,i_pol_)
end if
case('chi')
xs = this % chi(g,i_azi_,i_pol_)
case('scatter')
xs = this % total(g,i_azi_,i_pol_) - this % absorption(g,i_azi_,i_pol_)
end select
end if
end function nuclideangle_get_xs
!===============================================================================
! NUCLIDE*_CALC_F Finds the value of f(mu), the scattering angle probability,
! given mu
!===============================================================================
pure function nuclideiso_calc_f(this, gin, gout, mu, uvw, i_azi, i_pol) &
result(f)
class(NuclideIso), intent(in) :: this
integer, intent(in) :: gin ! Incoming Energy Group
integer, intent(in) :: gout ! Outgoing Energy Group
real(8), intent(in) :: mu ! Angle of interest
real(8), intent(in), optional :: uvw(3) ! Direction vector
integer, intent(in), optional :: i_azi ! Incoming Energy Group
integer, intent(in), optional :: i_pol ! Outgoing Energy Group
real(8) :: f ! Return value of f(mu)
real(8) :: dmu, r
integer :: imu
if (this % scatt_type == ANGLE_LEGENDRE) then
f = evaluate_legendre(this % scatter(gout,gin,:), mu)
else if (this % scatt_type == ANGLE_TABULAR) then
dmu = TWO / real(this % order - 1,8)
! Find mu bin algebraically, knowing that the spacing is equal
f = (mu + ONE) / dmu + ONE
imu = floor(f)
! But save the amount that mu is past the previous index
! so we can use interpolation later.
f = f - real(imu,8)
! Adjust so interpolation works on the last bin if necessary
if (imu == size(this % scatter, dim=3)) then
imu = imu - 1
end if
! Now intepolate to find f(mu)
r = f / dmu
f = (ONE - r) * this % scatter(gout,gin,imu) + &
r * this % scatter(gout,gin,imu+1)
else ! (ANGLE_HISTOGRAM)
dmu = TWO / real(this % order,8)
! Find mu bin algebraically, knowing that the spacing is equal
imu = floor((mu + ONE) / dmu + ONE)
! Adjust so interpolation works on the last bin if necessary
if (imu == size(this % scatter, dim=3)) then
imu = imu - 1
end if
f = this % scatter(gout, gin, imu)
end if
end function nuclideiso_calc_f
pure function nuclideangle_calc_f(this, gin, gout, mu, uvw, i_azi, &
i_pol) result(f)
class(NuclideAngle), intent(in) :: this
integer, intent(in) :: gin ! Incoming Energy Group
integer, intent(in) :: gout ! Outgoing Energy Group
real(8), intent(in) :: mu ! Angle of interest
real(8), intent(in), optional :: uvw(3) ! Direction vector
integer, intent(in), optional :: i_azi ! Incoming Energy Group
integer, intent(in), optional :: i_pol ! Outgoing Energy Group
real(8) :: f ! Return value of f(mu)
real(8) :: dmu, r
integer :: imu
integer :: i_azi_, i_pol_
if (present(i_azi) .and. present(i_pol)) then
i_azi_ = i_azi
i_pol_ = i_pol
else if (present(uvw)) then
call find_angle(this % polar, this % azimuthal, uvw, i_azi_, i_pol_)
end if
if (this % scatt_type == ANGLE_LEGENDRE) then
f = evaluate_legendre(this % scatter(gout,gin,:,i_azi_,i_pol_), mu)
else if (this % scatt_type == ANGLE_TABULAR) then
dmu = TWO / real(this % order - 1,8)
! Find mu bin algebraically, knowing that the spacing is equal
f = (mu + ONE) / dmu + ONE
imu = floor(f)
! But save the amount that mu is past the previous index
! so we can use interpolation later.
f = f - real(imu,8)
! Adjust so interpolation works on the last bin if necessary
if (imu == size(this % scatter, dim=3)) then
imu = imu - 1
end if
! Now intepolate to find f(mu)
r = f / dmu
f = (ONE - r) * this % scatter(gout,gin,imu,i_azi_,i_pol_) + &
r * this % scatter(gout,gin,imu+1,i_azi_,i_pol_)
else ! (ANGLE_HISTOGRAM)
dmu = TWO / real(this % order,8)
! Find mu bin algebraically, knowing that the spacing is equal
imu = floor((mu + ONE) / dmu + ONE)
! Adjust so interpolation works on the last bin if necessary
if (imu == size(this % scatter, dim=3)) then
imu = imu - 1
end if
f = this % scatter(gout, gin, imu,i_azi_,i_pol_)
end if
end function nuclideangle_calc_f
end subroutine nuclide_print
end module nuclide_header

View file

@ -52,9 +52,9 @@ contains
! Write version information
write(UNIT=OUTPUT_UNIT, FMT=*) &
' Copyright: 2011-2015 Massachusetts Institute of Technology'
' Copyright: 2011-2016 Massachusetts Institute of Technology'
write(UNIT=OUTPUT_UNIT, FMT=*) &
' License: http://mit-crpg.github.io/openmc/license.html'
' License: http://openmc.readthedocs.io/en/latest/license.html'
write(UNIT=OUTPUT_UNIT, FMT='(6X,"Version:",8X,I1,".",I1,".",I1)') &
VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE
#ifdef GIT_SHA1
@ -335,10 +335,10 @@ contains
! Open log file for writing
open(NEWUNIT=unit_xs, FILE=path, STATUS='replace', ACTION='write')
! Write header
call header("CROSS SECTION TABLES", unit=unit_xs)
if (run_CE) then
! Write header
call header("CROSS SECTION TABLES", unit=unit_xs)
NUCLIDE_LOOP: do i = 1, n_nuclides_total
! Print information about nuclide
call nuclides(i) % print(unit=unit_xs)
@ -349,10 +349,17 @@ contains
call sab_tables(i) % print(unit=unit_xs)
end do SAB_TABLES_LOOP
else
! Write header
call header("MGXS LIBRARY TABLES", unit=unit_xs)
NuclideMG_LOOP: do i = 1, n_nuclides_total
! Print information about nuclide
call nuclides_mg(i) % obj % print(unit=unit_xs)
end do NuclideMG_LOOP
call header("MATERIAL MGXS TABLES", unit=unit_xs)
MATERIAL_LOOP: do i = 1, n_materials
! Print information about Materials
call macro_xs(i) % obj % print(unit=unit_xs)
end do MATERIAL_LOOP
end if
! Close cross section summary file
@ -920,7 +927,11 @@ contains
write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), &
"Total Material"
else
i_listing = nuclides(i_nuclide) % listing
if (run_CE) then
i_listing = nuclides(i_nuclide) % listing
else
i_listing = nuclides_MG(i_nuclide) % obj % listing
end if
write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), &
trim(xs_listings(i_listing) % alias)
end if

View file

@ -206,7 +206,7 @@ contains
this % last_g = int(src % E)
this % E = energy_bin_avg(this % g)
end if
this % last_E = src % E
this % last_E = this % E
end subroutine initialize_from_source

View file

@ -34,7 +34,7 @@ contains
verbosity = 10
! Initialize the particle to be tracked
call p%initialize()
call p % initialize()
! Read in the restart information
call read_particle_restart(p, previous_run_mode)
@ -46,9 +46,9 @@ contains
select case (previous_run_mode)
case (MODE_EIGENVALUE)
particle_seed = ((current_batch - 1)*gen_per_batch + &
current_gen - 1)*n_particles + p%id
current_gen - 1)*n_particles + p % id
case (MODE_FIXEDSOURCE)
particle_seed = p%id
particle_seed = p % id
end select
call set_particle_seed(particle_seed)
@ -71,7 +71,7 @@ contains
integer :: int_scalar
integer(HID_T) :: file_id
character(MAX_WORD_LEN) :: mode
character(MAX_WORD_LEN) :: tempstr
! Write meessage
call write_message("Loading particle restart file " &
@ -81,32 +81,32 @@ contains
file_id = file_open(path_particle_restart, 'r')
! Read data from file
call read_dataset(file_id, 'filetype', int_scalar)
call read_dataset(file_id, 'revision', int_scalar)
call read_dataset(file_id, 'current_batch', current_batch)
call read_dataset(file_id, 'gen_per_batch', gen_per_batch)
call read_dataset(file_id, 'current_gen', current_gen)
call read_dataset(file_id, 'n_particles', n_particles)
call read_dataset(file_id, 'run_mode', mode)
select case (mode)
call read_dataset(tempstr, file_id, 'filetype')
call read_dataset(int_scalar, file_id, 'revision')
call read_dataset(current_batch, file_id, 'current_batch')
call read_dataset(gen_per_batch, file_id, 'gen_per_batch')
call read_dataset(current_gen, file_id, 'current_gen')
call read_dataset(n_particles, file_id, 'n_particles')
call read_dataset(tempstr, file_id, 'run_mode')
select case (tempstr)
case ('k-eigenvalue')
previous_run_mode = MODE_EIGENVALUE
case ('fixed source')
previous_run_mode = MODE_FIXEDSOURCE
end select
call read_dataset(file_id, 'id', p%id)
call read_dataset(file_id, 'weight', p%wgt)
call read_dataset(file_id, 'energy', p%E)
call read_dataset(file_id, 'energy_group', p%g)
call read_dataset(file_id, 'xyz', p%coord(1)%xyz)
call read_dataset(file_id, 'uvw', p%coord(1)%uvw)
call read_dataset(p % id, file_id, 'id')
call read_dataset(p % wgt, file_id, 'weight')
call read_dataset(p % E, file_id, 'energy')
call read_dataset(p % g, file_id, 'energy_group')
call read_dataset(p % coord(1) % xyz, file_id, 'xyz')
call read_dataset(p % coord(1) % uvw, file_id, 'uvw')
! Set particle last attributes
p%last_wgt = p%wgt
p%last_xyz = p%coord(1)%xyz
p%last_uvw = p%coord(1)%uvw
p%last_E = p%E
p%last_g = p%g
p % last_wgt = p % wgt
p % last_xyz = p % coord(1)%xyz
p % last_uvw = p % coord(1)%uvw
p % last_E = p % E
p % last_g = p % g
! Close hdf5 file
call file_close(file_id)

View file

@ -80,7 +80,7 @@ contains
integer :: i_nuclide ! index in nuclides array
integer :: i_nuc_mat ! index in material's nuclides array
integer :: i_reaction ! index in nuc % reactions array
type(NuclideCE), pointer :: nuc
type(Nuclide), pointer :: nuc
call sample_nuclide(p, 'total ', i_nuclide, i_nuc_mat)
@ -203,7 +203,7 @@ contains
real(8) :: f
real(8) :: prob
real(8) :: cutoff
type(NuclideCE), pointer :: nuc
type(Nuclide), pointer :: nuc
! Get pointer to nuclide
nuc => nuclides(i_nuclide)
@ -301,7 +301,7 @@ contains
real(8) :: uvw_new(3) ! outgoing uvw for iso-in-lab scattering
real(8) :: uvw_old(3) ! incoming uvw for iso-in-lab scattering
real(8) :: phi ! azimuthal angle for iso-in-lab scattering
type(NuclideCE), pointer :: nuc
type(Nuclide), pointer :: nuc
! copy incoming direction
uvw_old(:) = p % coord(1) % uvw
@ -416,7 +416,7 @@ contains
real(8) :: v_cm(3) ! velocity of center-of-mass
real(8) :: v_t(3) ! velocity of target nucleus
real(8) :: uvw_cm(3) ! directional cosines in center-of-mass
type(NuclideCE), pointer :: nuc
type(Nuclide), pointer :: nuc
! get pointer to nuclide
nuc => nuclides(i_nuclide)
@ -742,7 +742,7 @@ contains
!===============================================================================
subroutine sample_target_velocity(nuc, v_target, E, uvw, v_neut, wgt, xs_eff)
type(NuclideCE), intent(in) :: nuc ! target nuclide at temperature T
type(Nuclide), intent(in) :: nuc ! target nuclide at temperature T
real(8), intent(out) :: v_target(3) ! target velocity
real(8), intent(in) :: v_neut(3) ! neutron velocity
real(8), intent(in) :: E ! particle energy
@ -987,7 +987,7 @@ contains
!===============================================================================
subroutine sample_cxs_target_velocity(nuc, v_target, E, uvw)
type(NuclideCE), intent(in) :: nuc ! target nuclide at temperature
type(Nuclide), intent(in) :: nuc ! target nuclide at temperature
real(8), intent(out) :: v_target(3)
real(8), intent(in) :: E
real(8), intent(in) :: uvw(3)
@ -1073,7 +1073,7 @@ contains
real(8) :: nu_t ! total nu
real(8) :: weight ! weight adjustment for ufs method
logical :: in_mesh ! source site in ufs mesh?
type(NuclideCE), pointer :: nuc
type(Nuclide), pointer :: nuc
! Get pointers
nuc => nuclides(i_nuclide)
@ -1169,10 +1169,10 @@ contains
!===============================================================================
subroutine sample_fission_neutron(nuc, rxn, E_in, site)
type(NuclideCE), intent(in) :: nuc
type(Reaction), intent(in) :: rxn
real(8), intent(in) :: E_in
type(Bank), intent(inout) :: site
type(Nuclide), intent(in) :: nuc
type(Reaction), intent(in) :: rxn
real(8), intent(in) :: E_in
type(Bank), intent(inout) :: site
integer :: group ! index on nu energy grid / precursor group
integer :: n_sample ! number of resamples
@ -1278,7 +1278,7 @@ contains
!===============================================================================
subroutine inelastic_scatter(nuc, rxn, p)
type(NuclideCE), intent(in) :: nuc
type(Nuclide), intent(in) :: nuc
type(Reaction), intent(in) :: rxn
type(Particle), intent(inout) :: p

View file

@ -5,9 +5,9 @@ module physics_mg
use constants
use error, only: fatal_error, warning
use global
use macroxs_header, only: MacroXS, MacroXSContainer
use material_header, only: Material
use math, only: rotate_angle
use mgxs_header, only: Mgxs, MgxsContainer
use mesh, only: get_mesh_indices
use output, only: write_message
use particle_header, only: Particle
@ -77,6 +77,7 @@ contains
call create_fission_sites(p, p % secondary_bank, p % n_secondary)
end if
end if
! If survival biasing is being used, the following subroutine adjusts the
! weight of the particle. Otherwise, it checks to see if absorption occurs
@ -178,7 +179,7 @@ contains
real(8) :: phi ! fission neutron azimuthal angle
real(8) :: weight ! weight adjustment for ufs method
logical :: in_mesh ! source site in ufs mesh?
class(MacroXS), pointer :: xs
class(Mgxs), pointer :: xs
! Get Pointers
xs => macro_xs(p % material) % obj
@ -241,14 +242,12 @@ contains
! Set weight of fission bank site
bank_array(i) % wgt = ONE/weight
! Sample cosine of angle -- fission neutrons are always emitted
! isotropically. Sometimes in ACE data, fission reactions actually have
! an angular distribution listed, but for those that do, it's simply just
! a uniform distribution in mu
! Sample cosine of angle -- fission neutrons are treated as being emitted
! isotropically.
mu = TWO * prn() - ONE
! Sample azimuthal angle uniformly in [0,2*pi)
phi = TWO*PI*prn()
phi = TWO * PI * prn()
bank_array(i) % uvw(1) = mu
bank_array(i) % uvw(2) = sqrt(ONE - mu*mu) * cos(phi)
bank_array(i) % uvw(3) = sqrt(ONE - mu*mu) * sin(phi)
@ -256,7 +255,7 @@ contains
! Sample secondary energy distribution for fission reaction and set energy
! in fission bank
bank_array(i) % E = &
real(xs % sample_fission_energy(p % g, fission_bank(i) % uvw), 8)
real(xs % sample_fission_energy(p % g, bank_array(i) % uvw), 8)
end do
! increment number of bank sites

View file

@ -8,36 +8,56 @@ module scattdata_header
implicit none
!===============================================================================
! JAGGED1D and JAGGED2D is a type which allows for jagged 1-D or 2-D array.
!===============================================================================
type :: Jagged2D
real(8), allocatable :: data(:, :)
end type Jagged2D
type :: Jagged1D
real(8), allocatable :: data(:)
end type Jagged1D
!===============================================================================
! SCATTDATA contains all the data to describe the scattering energy and
! angular distribution
!===============================================================================
type, abstract :: ScattData
! p0 matrix on its own for sampling energy
real(8), allocatable :: energy(:,:) ! (Gout x Gin)
real(8), allocatable :: mult(:,:) ! (Gout x Gin)
real(8), allocatable :: data(:,:,:) ! (Order/Nmu x Gout x Gin)
! The data attribute of the energy, mult, and dist arrays
! are not necessarily 1-indexed as they instead will be allocated
! from a minimum outgoing group to an outgoing minimum group.
! Normalized p0 matrix on its own for sampling energy
type(Jagged1D), allocatable :: energy(:) ! (Gin % data(Gout))
! Nu-scatter multiplication (i.e. nu-scatt/scatt)
type(Jagged1D), allocatable :: mult(:) ! (Gin % data(Gout))
! Angular distribution
type(Jagged2D), allocatable :: dist(:) ! (Gin % data(Order/Nmu, Gout)
integer, allocatable :: gmin(:) ! Minimum outgoing group
integer, allocatable :: gmax(:) ! Maximum outgoing group
real(8), allocatable :: scattxs(:) ! Isotropic Sigma_{s,g_{in}}
contains
procedure(scattdata_init_), deferred :: init ! Initializes ScattData
procedure(scattdata_calc_f_), deferred :: calc_f ! Calculates f, given mu
procedure(scattdata_sample_), deferred :: sample ! sample the scatter event
procedure :: get_matrix => scattdata_get_matrix ! Rebuild scattering matrix
end type ScattData
abstract interface
subroutine scattdata_init_(this, order, energy, mult, coeffs)
subroutine scattdata_init_(this, mult, coeffs)
import ScattData
class(ScattData), intent(inout) :: this ! Object to work on
integer, intent(in) :: order ! Data Order
real(8), intent(in) :: energy(:,:) ! Energy Transfer Matrix
real(8), intent(in) :: mult(:,:) ! Scatter Prod'n Matrix
real(8), intent(in) :: coeffs(:,:,:) ! Coefficients to use
class(ScattData), intent(inout) :: this ! Object to work with
real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix
real(8), intent(in) :: coeffs(:, :, :) ! Coefficients to use
end subroutine scattdata_init_
pure function scattdata_calc_f_(this, gin, gout, mu) result(f)
import ScattData
class(ScattData), intent(in) :: this ! The ScattData to evaluate
class(ScattData), intent(in) :: this ! Scattering Object to work with
integer, intent(in) :: gin ! Incoming Energy Group
integer, intent(in) :: gout ! Outgoing Energy Group
real(8), intent(in) :: mu ! Angle of interest
@ -47,7 +67,7 @@ module scattdata_header
subroutine scattdata_sample_(this, gin, gout, mu, wgt)
import ScattData
class(ScattData), intent(in) :: this ! Scattering Object to Use
class(ScattData), intent(in) :: this ! Scattering Object to work with
integer, intent(in) :: gin ! Incoming neutron group
integer, intent(out) :: gout ! Sampled outgoin group
real(8), intent(out) :: mu ! Sampled change in angle
@ -57,30 +77,35 @@ module scattdata_header
type, extends(ScattData) :: ScattDataLegendre
! Maximal value for rejection sampling from rectangle
real(8), allocatable :: max_val(:,:)
type(Jagged1D), allocatable :: max_val(:) ! (Gin % data(Gout))
contains
procedure :: init => scattdatalegendre_init
procedure :: calc_f => scattdatalegendre_calc_f
procedure :: sample => scattdatalegendre_sample
procedure :: init => scattdatalegendre_init
procedure :: calc_f => scattdatalegendre_calc_f
procedure :: sample => scattdatalegendre_sample
end type ScattDataLegendre
type, extends(ScattData) :: ScattDataHistogram
real(8), allocatable :: mu(:) ! Mu bins
real(8) :: dmu ! Mu spacing
type, extends(ScattData) :: ScattDataHistogram
real(8), allocatable :: mu(:) ! Mu bins
real(8) :: dmu ! Mu spacing
! Histogram of f(mu) (dist has CDF)
type(Jagged2D), allocatable :: fmu(:) ! (Gin % data(Order/Nmu x Gout)
contains
procedure :: init => scattdatahistogram_init
procedure :: calc_f => scattdatahistogram_calc_f
procedure :: sample => scattdatahistogram_sample
procedure :: init => scattdatahistogram_init
procedure :: calc_f => scattdatahistogram_calc_f
procedure :: sample => scattdatahistogram_sample
procedure :: get_matrix => scattdatahistogram_get_matrix
end type ScattDataHistogram
type, extends(ScattData) :: ScattDataTabular
real(8), allocatable :: mu(:) ! Mu bins
real(8) :: dmu ! Mu spacing
real(8), allocatable :: fmu(:,:,:) ! PDF of f(mu)
type, extends(ScattData) :: ScattDataTabular
real(8), allocatable :: mu(:) ! Mu bins
real(8) :: dmu ! Mu spacing
! PDF of f(mu) (dist has CDF)
type(Jagged2D), allocatable :: fmu(:) ! (Gin % data(Order/Nmu x Gout)
contains
procedure :: init => scattdatatabular_init
procedure :: calc_f => scattdatatabular_calc_f
procedure :: sample => scattdatatabular_sample
procedure :: init => scattdatatabular_init
procedure :: calc_f => scattdatatabular_calc_f
procedure :: sample => scattdatatabular_sample
procedure :: get_matrix => scattdatatabular_get_matrix
end type ScattDataTabular
!===============================================================================
@ -94,189 +119,313 @@ module scattdata_header
contains
!===============================================================================
! SCATTDATA_INIT builds the scattdata object
! SCATTDATA*_INIT builds the scattdata object
!===============================================================================
subroutine scattdata_init(this, order, energy, mult)
class(ScattData), intent(inout) :: this ! Object to work on
integer, intent(in) :: order ! Data Order
real(8), intent(in) :: energy(:,:) ! Energy Transfer Matrix
real(8), intent(in) :: mult(:,:) ! Scatter Prod'n Matrix
class(ScattData), intent(inout) :: this ! Object to work on
integer, intent(in) :: order ! Data Order
real(8), intent(inout) :: energy(:, :) ! Energy Transfer Matrix
real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix
integer :: groups
integer :: groups, gmin, gmax, gin
real(8) :: norm
groups = size(energy, dim=1)
allocate(this % energy(groups, groups))
this % energy = energy
allocate(this % mult(groups, groups))
this % mult = mult
allocate(this % data(order, groups, groups))
this % data = ZERO
allocate(this % gmin(groups))
allocate(this % gmax(groups))
allocate(this % energy(groups))
allocate(this % mult(groups))
allocate(this % dist(groups))
! Use energy to find the gmin and gmax values
! Also set energy values when doing it
do gin = 1, groups
! Make sure energy is normalized (i.e., CDF is 1)
norm = sum(energy(:, gin))
if (norm /= ZERO) energy(:, gin) = energy(:, gin) / norm
! Find gmin by checking the P0 moment
do gmin = 1, groups
if (energy(gmin, gin) > ZERO) exit
end do
! Find gmax by checking the P0 moment
do gmax = groups, 1, -1
if (energy(gmax, gin) > ZERO) exit
end do
! Treat the case of all zeros
if (gmin > gmax) then
gmin = gin
gmax = gin
! By not changing energy(gin) here we are leaving it as zero
end if
allocate(this % energy(gin) % data(gmin:gmax))
this % energy(gin) % data(gmin:gmax) = energy(gmin:gmax, gin)
allocate(this % mult(gin) % data(gmin:gmax))
this % mult(gin) % data(gmin:gmax) = mult(gmin:gmax, gin)
allocate(this % dist(gin) % data(order, gmin:gmax))
this % dist(gin) % data = ZERO
this % gmin(gin) = gmin
this % gmax(gin) = gmax
end do
end subroutine scattdata_init
subroutine scattdatalegendre_init(this, order, energy, mult, coeffs)
class(ScattDataLegendre), intent(inout) :: this ! Object to work on
integer, intent(in) :: order ! Data Order
real(8), intent(in) :: energy(:,:) ! Energy Transfer Matrix
real(8), intent(in) :: mult(:,:) ! Scatter Prod'n Matrix
real(8), intent(in) :: coeffs(:,:,:) ! Coefficients to use
subroutine scattdatalegendre_init(this, mult, coeffs)
class(ScattDataLegendre), intent(inout) :: this ! Object to work on
real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix
real(8), intent(in) :: coeffs(:, :, :) ! Coefficients to use
real(8) :: dmu, mu, f
integer :: imu, Nmu, gout, gin, groups
real(8) :: dmu, mu, f, norm
integer :: imu, Nmu, gout, gin, groups, order
real(8), allocatable :: energy(:, :)
real(8), allocatable :: matrix(:, :, :)
call scattdata_init(this, order, energy, mult)
groups = size(coeffs, dim=3)
order = size(coeffs, dim=1)
this % data = coeffs
! make a copy of coeffs that we can use to extract data and normalize
allocate(matrix(order, groups, groups))
matrix (:, :, :)= coeffs
groups = size(this % energy,dim=1)
! Get scattxs value
allocate(this % scattxs(groups))
! Get this by summing the un-normalized P0 coefficient in matrix
! over all outgoing groups
this % scattxs(:) = sum(matrix(1, :, :), dim=1)
allocate(this % max_val(groups, groups))
this % max_val = ZERO
! Step through the polynomial with fixed number of points to identify
! the maximal value.
Nmu = 1001
dmu = TWO / real(Nmu,8)
do imu = 1, Nmu
! Update mu. Do first and last seperate to avoid float errors
if (imu == 1) then
mu = -ONE
else if (imu == Nmu) then
mu = ONE
end if
mu = -ONE + real(imu - 1,8) * dmu
do gin = 1, groups
do gout = 1, groups
! Calculate probability
f = this % calc_f(gin,gout,mu)
! If this is a new max, store it.
if (f > this % max_val(gout,gin)) this % max_val(gout,gin) = f
end do
allocate(energy(groups, groups))
energy(:, :) = ZERO
! Build energy transfer probability matrix from data in matrix
! while also normalizing matrix itself (making CDF of f(mu=1)=1)
do gin = 1, groups
do gout = 1, groups
norm = matrix(1, gout, gin)
energy(gout, gin) = norm
if (norm /= ZERO) then
matrix(:, gout, gin) = matrix(:, gout, gin) / norm
end if
end do
end do
! Finally, since we may not have caught the exact max, add 10% margin
this % max_val = this % max_val * 1.1_8
call scattdata_init(this, order, energy, mult)
allocate(this % max_val(groups))
! Set dist values from matrix and initialize max_val
do gin = 1, groups
do gout = this % gmin(gin), this % gmax(gin)
this % dist(gin) % data(:, gout) = matrix(:, gout, gin)
end do
allocate(this % max_val(gin) % data(this % gmin(gin):this % gmax(gin)))
this % max_val(gin) % data(:) = ZERO
end do
! Step through the polynomial with fixed number of points to identify
! the maximal value.
Nmu = 1001
dmu = TWO / real(Nmu - 1, 8)
do gin = 1, groups
do gout = this % gmin(gin), this % gmax(gin)
do imu = 1, Nmu
! Update mu. Do first and last seperate to avoid float errors
if (imu == 1) then
mu = -ONE
else if (imu == Nmu) then
mu = ONE
else
mu = -ONE + real(imu - 1, 8) * dmu
end if
! Calculate probability
f = this % calc_f(gin,gout,mu)
! If this is a new max, store it.
if (f > this % max_val(gin) % data(gout)) &
this % max_val(gin) % data(gout) = f
end do
! Finally, since we may not have caught the exact max, add 10% margin
this % max_val(gin) % data(gout) = &
this % max_val(gin) % data(gout) * 1.1_8
end do
end do
end subroutine scattdatalegendre_init
subroutine scattdatahistogram_init(this, order, energy, mult, coeffs)
subroutine scattdatahistogram_init(this, mult, coeffs)
class(ScattDataHistogram), intent(inout) :: this ! Object to work on
integer, intent(in) :: order ! Data Order
real(8), intent(in) :: energy(:,:) ! Energy Transfer Matrix
real(8), intent(in) :: mult(:,:) ! Scatter Prod'n Matrix
real(8), intent(in) :: coeffs(:,:,:) ! Coefficients to use
real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix
real(8), intent(in) :: coeffs(:, :, :) ! Coefficients to use
integer :: imu, gin, gout, groups
integer :: imu, gin, gout, groups, order
real(8) :: norm
real(8), allocatable :: energy(:, :)
real(8), allocatable :: matrix(:, :, :)
groups = size(energy,dim=1)
groups = size(coeffs, dim=3)
order = size(coeffs, dim=1)
! make a copy of coeffs that we can use to extract data and normalize
allocate(matrix(order, groups, groups))
matrix(:, :, :) = coeffs
! Get scattxs value
allocate(this % scattxs(groups))
! Get this by summing the un-normalized P0 coefficient in matrix
! over all outgoing groups
this % scattxs(:) = sum(sum(matrix(:, :, :), dim=1), dim=1)
allocate(energy(groups, groups))
energy(:, :) = ZERO
! Build energy transfer probability matrix from data in matrix
! while also normalizing matrix itself (making CDF of f(mu=1)=1)
do gin = 1, groups
do gout = 1, groups
norm = sum(matrix(:, gout, gin))
energy(gout, gin) = norm
if (norm /= ZERO) then
matrix(:, gout, gin) = matrix(:, gout, gin) / norm
end if
end do
end do
call scattdata_init(this, order, energy, mult)
allocate(this % mu(order))
this % dmu = TWO / real(order,8)
this % dmu = TWO / real(order, 8)
this % mu(1) = -ONE
do imu = 2, order
this % mu(imu) = -ONE + real(imu - 1,8) * this % dmu
this % mu(imu) = -ONE + real(imu - 1, 8) * this % dmu
end do
! Best to integrate this histogram so we can avoid rejection sampling
! Integrate this histogram so we can avoid rejection sampling while
! also saving the original histogram in fmu
allocate(this % fmu(groups))
do gin = 1, groups
do gout = 1, groups
if (energy(gout,gin) > ZERO) then
! Integrate the histogram
this % data(1,gout,gin) = this % dmu * coeffs(1,gout,gin)
do imu = 2, order
this % data(imu,gout,gin) = this % dmu * coeffs(imu,gout,gin) + &
this % data(imu-1,gout,gin)
end do
! Now make sure integral norms to zero
norm = this % data(order,gout,gin)
if (norm > ZERO) then
this % data(:,gout,gin) = this % data(:,gout,gin) / norm
end if
allocate(this % fmu(gin) % data(order, &
this % gmin(gin):this % gmax(gin)))
do gout = this % gmin(gin), this % gmax(gin)
! Store the histogram
this % fmu(gin) % data(:, gout) = matrix(:, gout, gin)
! Integrate the histogram
this % dist(gin) % data(1, gout) = &
this % dmu * matrix(1, gout, gin)
do imu = 2, order
this % dist(gin) % data(imu, gout) = &
this % dmu * matrix(imu, gout, gin) + &
this % dist(gin) % data(imu - 1, gout)
end do
! Now make sure integral norms to zero
norm = this % dist(gin) % data(order, gout)
if (norm > ZERO) then
this % fmu(gin) % data(:, gout) = &
this % fmu(gin) % data(:, gout) / norm
this % dist(gin) % data(:, gout) = &
this % dist(gin) % data(:, gout) / norm
end if
end do
end do
end subroutine scattdatahistogram_init
subroutine scattdatatabular_init(this, order, energy, mult, coeffs)
subroutine scattdatatabular_init(this, mult, coeffs)
class(ScattDataTabular), intent(inout) :: this ! Object to work on
integer, intent(in) :: order ! Data Order
real(8), intent(in) :: energy(:,:) ! Energy Transfer Matrix
real(8), intent(in) :: mult(:,:) ! Scatter Prod'n Matrix
real(8), intent(in) :: coeffs(:,:,:) ! Coefficients to use
real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix
real(8), intent(in) :: coeffs(:, :, :) ! Coefficients to use
integer :: imu, gin, gout, groups
integer :: imu, gin, gout, groups, order
real(8) :: norm
logical :: legendre_flag
integer :: this_order
real(8), allocatable :: energy(:, :)
real(8), allocatable :: matrix(:, :, :)
if (order < 0) then
legendre_flag = .true.
this_order = -1 * order
else
legendre_flag = .false.
this_order = order
end if
groups = size(coeffs, dim=3)
order = size(coeffs, dim=1)
groups = size(energy,dim=1)
! make a copy of coeffs that we can use to extract data and normalize
allocate(matrix(order, groups, groups))
matrix(:, :, :) = coeffs
call scattdata_init(this, this_order, energy, mult)
allocate(this % mu(this_order))
this % dmu = TWO / real(this_order - 1)
do imu = 1, this_order - 1
this % mu(imu) = -ONE + real(imu - 1) * this % dmu
! Build the angular distribution mu values
allocate(this % mu(order))
this % dmu = TWO / real(order - 1, 8)
this % mu(1) = -ONE
do imu = 2, order - 1
this % mu(imu) = -ONE + real(imu - 1, 8) * this % dmu
end do
this % mu(this_order) = ONE
this % mu(order) = ONE
! Best to integrate this histogram so we can avoid rejection sampling
allocate(this % fmu(this_order,groups,groups))
! Get scattxs
allocate(this % scattxs(groups))
! Get this by integrating the scattering distribution over all mu points
! and then combining over all outgoing groups
! over all outgoing groups
do gin = 1, groups
norm = ZERO
do gout = 1, groups
do imu = 2, order
norm = norm + HALF * this % dmu * (matrix(imu - 1, gout, gin) + &
matrix(imu, gout, gin))
end do
end do
this % scattxs(gin) = norm
end do
allocate(energy(groups, groups))
energy(:, :) = ZERO
! Build energy transfer probability matrix from data in matrix
do gin = 1, groups
do gout = 1, groups
if (energy(gout,gin) > ZERO) then
if (legendre_flag) then
! Coeffs are legendre coeffs. Need to build f(mu) then integrate
! and store the integral in this % data
! Ensure the coeffs are normalized
norm = ONE / coeffs(1,gout,gin)
do imu = 1, this_order
this % fmu(imu,gout,gin) = evaluate_legendre(norm * coeffs(:,gout,gin), this % mu(imu))
! Force positivity
if (this % fmu(imu,gout,gin) < ZERO) then
this % fmu(imu,gout,gin) = ZERO
end if
end do
else
! Coeffs contain f(mu), put in f(mu) to save duplicate.
this % fmu(:,gout,gin) = this % data(:,gout,gin)
end if
norm = ZERO
do imu = 2, order
norm = norm + HALF * this % dmu * &
(matrix(imu - 1, gout, gin) + matrix(imu, gout, gin))
end do
energy(gout, gin) = norm
end do
end do
call scattdata_init(this, order, energy, mult)
! Re-normalize fmu for numerical integration issues and in case
! the negative fix-up introduced un-normalized data
norm = ZERO
do imu = 2, this_order
norm = norm + HALF * this % dmu * (this % fmu(imu-1,gout,gin) + this % fmu(imu,gout,gin))
end do
if (norm > ZERO) then
this % fmu(:,gout,gin) = this % fmu(:,gout,gin) / norm
end if
! Calculate f(mu) and integrate it so we can avoid rejection sampling
allocate(this % fmu(groups))
do gin = 1, groups
allocate(this % fmu(gin) % data(order, &
this % gmin(gin):this % gmax(gin)))
do gout = this % gmin(gin), this % gmax(gin)
! Coeffs contain f(mu), put in f(mu) as that is where the
! PDF lives
this % fmu(gin) % data(:, gout) = matrix(:, gout, gin)
! Now create CDF from fmu with trapezoidal rule
this % data(1,gout,gin) = ZERO
do imu = 2, this_order - 1
this % data(imu,gout,gin) = this % data(imu-1,gout,gin) + &
HALF * this % dmu * (this % fmu(imu-1,gout,gin) + this % fmu(imu,gout,gin))
end do
this % data(this_order,gout,gin) = ONE
! Force positivity
do imu = 1, order
if (this % fmu(gin) % data(imu, gout) < ZERO) then
this % fmu(gin) % data(imu, gout) = ZERO
end if
end do
! Re-normalize fmu for numerical integration issues and in case
! the negative fix-up introduced un-normalized data
norm = ZERO
do imu = 2, order
norm = norm + HALF * this % dmu * &
(this % fmu(gin) % data(imu - 1, gout) + &
this % fmu(gin) % data(imu, gout))
end do
if (norm > ZERO) then
this % fmu(gin) % data(:, gout) = &
this % fmu(gin) % data(:, gout) / norm
end if
! Now create CDF from fmu with trapezoidal rule
this % dist(gin) % data(1, gout) = ZERO
do imu = 2, order
this % dist(gin) % data(imu, gout) = &
this % dist(gin) % data(imu - 1, gout) + &
HALF * this % dmu * (this % fmu(gin) % data(imu - 1, gout) + &
this % fmu(gin) % data(imu, gout))
end do
! Ensure we normalize to 1 still
norm = this % dist(gin) % data(order, gout)
if (norm > ZERO) then
this % dist(gin) % data(:, gout) = &
this % dist(gin) % data(:, gout) / norm
end if
end do
end do
end subroutine scattdatatabular_init
!===============================================================================
@ -285,58 +434,69 @@ contains
pure function scattdatalegendre_calc_f(this, gin, gout, mu) result(f)
class(ScattDataLegendre), intent(in) :: this ! The ScattData to evaluate
integer, intent(in) :: gin ! Incoming Energy Group
integer, intent(in) :: gout ! Outgoing Energy Group
real(8), intent(in) :: mu ! Angle of interest
real(8) :: f ! Return value of f(mu)
! Plug mu in to the legendre expansion and go from there
f = evaluate_legendre(this % data(:, gout, gin), mu)
end function scattdatalegendre_calc_f
pure function scattdatahistogram_calc_f(this, gin, gout, mu) result(f)
class(ScattDataHistogram), intent(in) :: this ! The ScattData to evaluate
integer, intent(in) :: gin ! Incoming Energy Group
integer, intent(in) :: gout ! Outgoing Energy Group
real(8), intent(in) :: mu ! Angle of interest
real(8) :: f ! Return value of f(mu)
integer :: imu
! Find mu bin
imu = floor((mu + ONE)/ this % dmu + ONE)
! Adjust so interpolation works on the last bin if necessary
if (imu == size(this % data, dim=1)) then
imu = imu - 1
end if
! Use histogram interpolation to find f(mu)
f = this % data(imu, gout, gin)
end function scattdatahistogram_calc_f
pure function scattdatatabular_calc_f(this, gin, gout, mu) result(f)
class(ScattDataTabular), intent(in) :: this ! The ScattData to evaluate
integer, intent(in) :: gin ! Incoming Energy Group
integer, intent(in) :: gout ! Outgoing Energy Group
real(8), intent(in) :: mu ! Angle of interest
real(8) :: f ! Return value of f(mu)
! Plug mu in to the legendre expansion and go from there
if (gout < this % gmin(gin) .or. gout > this % gmax(gin)) then
f = ZERO
else
f = evaluate_legendre(this % dist(gin) % data(:, gout), mu)
end if
end function scattdatalegendre_calc_f
pure function scattdatahistogram_calc_f(this, gin, gout, mu) result(f)
class(ScattDataHistogram), intent(in) :: this ! The ScattData to evaluate
integer, intent(in) :: gin ! Incoming Energy Group
integer, intent(in) :: gout ! Outgoing Energy Group
real(8), intent(in) :: mu ! Angle of interest
real(8) :: f ! Return value of f(mu)
integer :: imu
if (gout < this % gmin(gin) .or. gout > this % gmax(gin)) then
f = ZERO
else
! Find mu bin
if (mu == ONE) then
imu = size(this % fmu(gin) % data, dim=1)
else
imu = floor((mu + ONE) / this % dmu + ONE)
end if
f = this % fmu(gin) % data(imu, gout)
end if
end function scattdatahistogram_calc_f
pure function scattdatatabular_calc_f(this, gin, gout, mu) result(f)
class(ScattDataTabular), intent(in) :: this ! The ScattData to evaluate
integer, intent(in) :: gin ! Incoming Energy Group
integer, intent(in) :: gout ! Outgoing Energy Group
real(8), intent(in) :: mu ! Angle of interest
real(8) :: f ! Return value of f(mu)
integer :: imu
real(8) :: r
! Find mu bin
imu = floor((mu + ONE)/ this % dmu + ONE)
! Adjust so interpolation works on the last bin if necessary
if (imu == size(this % data, dim=1)) then
imu = imu - 1
end if
if (gout < this % gmin(gin) .or. gout > this % gmax(gin)) then
f = ZERO
else
! Find mu bin
if (mu == ONE) then
imu = size(this % fmu(gin) % data, dim=1) - 1
else
imu = floor((mu + ONE) / this % dmu + ONE)
end if
! ! Now interpolate to find f(mu)
r = (mu - this % mu(imu)) / (this % mu(imu + 1) - this % mu(imu))
f = (ONE - r) * this % data(imu, gout, gin) + &
r * this % data(imu + 1, gout, gin)
! Now interpolate to find f(mu)
r = (mu - this % mu(imu)) / (this % mu(imu + 1) - this % mu(imu))
f = (ONE - r) * this % fmu(gin) % data(imu, gout) + &
r * this % fmu(gin) % data(imu + 1, gout)
end if
end function scattdatatabular_calc_f
@ -357,24 +517,24 @@ contains
integer :: samples
xi = prn()
prob = ZERO
gout = 0
gout = this % gmin(gin)
prob = this % energy(gin) % data(gout)
do while (prob < xi)
gout = gout + 1
prob = prob + this % energy(gout,gin)
prob = prob + this % energy(gin) % data(gout)
end do
! Now we can sample mu using the legendre representation of the thisering
! Now we can sample mu using the legendre representation of the scattering
! kernel in data(1:this % order)
! Do with rejection sampling
! Do with rejection sampling from a rectangular bounding box
! Set maximal value
M = this % max_val(gout,gin)
M = this % max_val(gin) % data(gout)
samples = 0
do
mu = TWO * prn() - ONE
f = this % calc_f(gin,gout,mu)
f = this % calc_f(gin, gout, mu)
if (f > ZERO) then
u = prn() * M
if (u <= f) then
@ -387,7 +547,7 @@ contains
end if
end do
wgt = wgt * this % mult(gout,gin)
wgt = wgt * this % mult(gin) % data(gout)
end subroutine scattdatalegendre_sample
@ -403,26 +563,26 @@ contains
integer :: imu
xi = prn()
prob = ZERO
gout = 0
gout = this % gmin(gin)
prob = this % energy(gin) % data(gout)
do while (prob < xi)
gout = gout + 1
prob = prob + this % energy(gout,gin)
prob = prob + this % energy(gin) % data(gout)
end do
xi = prn()
if (xi < this % data(1,gout,gin)) then
if (xi < this % dist(gin) % data(1, gout)) then
imu = 1
else
imu = binary_search(this % data(:,gout,gin), &
size(this % data(:,gout,gin)), xi)
imu = binary_search(this % dist(gin) % data(:, gout), &
size(this % dist(gin) % data(:, gout)), xi)
end if
! Randomly select a mu in this bin.
mu = prn() * this % dmu + this % mu(imu)
wgt = wgt * this % mult(gout,gin)
wgt = wgt * this % mult(gin) % data(gout)
end subroutine scattdatahistogram_sample
@ -440,21 +600,21 @@ contains
integer :: k, NP
xi = prn()
prob = ZERO
gout = 0
gout = this % gmin(gin)
prob = this % energy(gin) % data(gout)
do while (prob < xi)
gout = gout + 1
prob = prob + this % energy(gout,gin)
prob = prob + this % energy(gin) % data(gout)
end do
! determine outgoing cosine bin
NP = size(this % data(:,gout,gin))
NP = size(this % dist(gin) % data(:, gout))
xi = prn()
c_k = this % data(1,gout,gin)
c_k = this % dist(gin) % data(1, gout)
do k = 1, NP - 1
c_k1 = this % data(k+1,gout,gin)
c_k1 = this % dist(gin) % data(k + 1, gout)
if (xi < c_k1) exit
c_k = c_k1
end do
@ -462,18 +622,19 @@ contains
! check to make sure k is <= NP - 1
k = min(k, NP - 1)
p0 = this % fmu(k,gout,gin)
p0 = this % fmu(gin) % data(k, gout)
mu0 = this % mu(k)
! Linear-linear interpolation to find mu value w/in bin.
p1 = this % fmu(k+1,gout,gin)
mu1 = this % mu(k+1)
p1 = this % fmu(gin) % data(k + 1, gout)
mu1 = this % mu(k + 1)
frac = (p1 - p0)/(mu1 - mu0)
frac = (p1 - p0) / (mu1 - mu0)
if (frac == ZERO) then
mu = mu0 + (xi - c_k)/p0
mu = mu0 + (xi - c_k) / p0
else
mu = mu0 + (sqrt(max(ZERO, p0*p0 + TWO*frac*(xi - c_k))) - p0)/frac
mu = mu0 + &
(sqrt(max(ZERO, p0 * p0 + TWO * frac * (xi - c_k))) - p0) / frac
end if
if (mu <= -ONE) then
@ -482,8 +643,86 @@ contains
mu = ONE
end if
wgt = wgt * this % mult(gout,gin)
wgt = wgt * this % mult(gin) % data(gout)
end subroutine scattdatatabular_sample
!===============================================================================
! SCATTDATA*_GET_MATRIX Reproduces the original scattering matrix (densely)
! using ScattData's information of fmu/dist, energy, and scattxs
!===============================================================================
pure function scattdata_get_matrix(this, req_order) result(matrix)
class(ScattData), intent(in) :: this ! Scattering Object to work with
integer, intent(in) :: req_order ! Requested order of matrix
real(8), allocatable :: matrix(:, :, :) ! Resultant matrix just built
integer :: order, groups, gin, gout
groups = size(this % energy)
! Set gin and gout for getting the order
order = min(req_order, size(this % dist(1) % data, dim=1))
allocate(matrix(order, groups, groups))
! Initialize to 0; this way the zero entries in the dense matrix dont
! need to be explicitly set, requiring a significant increase in the
! lines of code.
matrix(:, :, :) = ZERO
do gin = 1, groups
do gout = this % gmin(gin), this % gmax(gin)
matrix(:, gout, gin) = this % scattxs(gin) * &
this % energy(gin) % data(gout) * &
this % dist(gin) % data(1:order, gout)
end do
end do
end function scattdata_get_matrix
pure function scattdatahistogram_get_matrix(this, req_order) result(matrix)
class(ScattDataHistogram), intent(in) :: this ! Scattering Object to work with
integer, intent(in) :: req_order ! Requested order of matrix
real(8), allocatable :: matrix(:, :, :) ! Resultant matrix just built
integer :: order, groups, gin, gout
groups = size(this % energy)
order = min(req_order, size(this % dist(1) % data, dim=1))
allocate(matrix(order, groups, groups))
! Initialize to 0; this way the zero entries in the dense matrix dont
! need to be explicitly set, requiring a significant increase in the
! lines of code.
matrix(:, :, :) = ZERO
do gin = 1, groups
do gout = this % gmin(gin), this % gmax(gin)
matrix(:, gout, gin) = this % scattxs(gin) * &
this % energy(gin) % data(gout) * &
this % fmu(gin) % data(1:order, gout)
end do
end do
end function scattdatahistogram_get_matrix
pure function scattdatatabular_get_matrix(this, req_order) result(matrix)
class(ScattDataTabular), intent(in) :: this ! Scattering Object to work with
integer, intent(in) :: req_order ! Requested order of matrix
real(8), allocatable :: matrix(:, :, :) ! Resultant matrix just built
integer :: order, groups, gin, gout
groups = size(this % energy)
order = min(req_order, size(this % dist(1) % data, dim=1))
allocate(matrix(order, groups, groups))
! Initialize to 0; this way the zero entries in the dense matrix dont
! need to be explicitly set, requiring a significant increase in the
! lines of code.
matrix(:, :, :) = ZERO
do gin = 1, groups
do gout = this % gmin(gin), this % gmax(gin)
matrix(:, gout, gin) = this % scattxs(gin) * &
this % energy(gin) % data(gout) * &
this % fmu(gin) % data(1:order, gout)
end do
end do
end function scattdatatabular_get_matrix
end module scattdata_header

View file

@ -1,7 +1,7 @@
module simulation
#ifdef MPI
use mpi
use message_passing
#endif
use cmfd_execute, only: cmfd_init_batch, execute_cmfd

View file

@ -53,7 +53,7 @@ contains
file_id = file_open(path_source, 'r', parallel=.true.)
! Read the file type
call read_dataset(file_id, "filetype", filetype)
call read_dataset(filetype, file_id, "filetype")
! Check to make sure this is a source file
if (filetype /= 'source') then

View file

@ -330,7 +330,11 @@ contains
NUCLIDE_LOOP: do j = 1, tally % n_nuclide_bins
if (tally % nuclide_bins(j) > 0) then
! Get index in cross section listings for this nuclide
i_list = nuclides(tally % nuclide_bins(j)) % listing
if (run_CE) then
i_list = nuclides(tally % nuclide_bins(j)) % listing
else
i_list = nuclides_MG(tally % nuclide_bins(j)) % obj % listing
end if
! Determine position of . in alias string (e.g. "U-235.71c"). If
! no . is found, just use the entire string.
@ -371,11 +375,11 @@ contains
MOMENT_LOOP: do j = 1, tally % n_user_score_bins
select case(tally % score_bins(k))
case (SCORE_SCATTER_N, SCORE_NU_SCATTER_N)
str_array(k) = 'P' // trim(to_str(tally % moment_order(k)))
str_array(k) = trim(to_str(tally % moment_order(k)))
k = k + 1
case (SCORE_SCATTER_PN, SCORE_NU_SCATTER_PN)
do n_order = 0, tally % moment_order(k)
str_array(k) = 'P' // trim(to_str(n_order))
str_array(k) = trim(to_str(n_order))
k = k + 1
end do
case (SCORE_SCATTER_YN, SCORE_NU_SCATTER_YN, SCORE_FLUX_YN, &
@ -740,25 +744,25 @@ contains
file_id = file_open(path_state_point, 'r', parallel=.true.)
! Read filetype
call read_dataset(file_id, "filetype", word)
call read_dataset(word, file_id, "filetype")
if (word /= 'statepoint') then
call fatal_error("OpenMC tried to restart from a non-statepoint file.")
end if
! Read revision number for state point file and make sure it matches with
! current version
call read_dataset(file_id, "revision", int_array(1))
call read_dataset(int_array(1), file_id, "revision")
if (int_array(1) /= REVISION_STATEPOINT) then
call fatal_error("State point version does not match current version &
&in OpenMC.")
end if
! Read and overwrite random number seed
call read_dataset(file_id, "seed", seed)
call read_dataset(seed, file_id, "seed")
! It is not impossible for a state point to be generated from a CE run but
! to be loaded in to an MG run (or vice versa), check to prevent that.
call read_dataset(file_id, "run_CE", sp_run_CE)
call read_dataset(sp_run_CE, file_id, "run_CE")
if (sp_run_CE == 0 .and. run_CE) then
call fatal_error("State point file is from multi-group run but &
& current run is continous-energy!")
@ -768,24 +772,24 @@ contains
end if
! Read and overwrite run information except number of batches
call read_dataset(file_id, "run_mode", word)
call read_dataset(word, file_id, "run_mode")
select case(word)
case ('fixed source')
run_mode = MODE_FIXEDSOURCE
case ('k-eigenvalue')
run_mode = MODE_EIGENVALUE
end select
call read_dataset(file_id, "n_particles", n_particles)
call read_dataset(file_id, "n_batches", int_array(1))
call read_dataset(n_particles, file_id, "n_particles")
call read_dataset(int_array(1), file_id, "n_batches")
! Take maximum of statepoint n_batches and input n_batches
n_batches = max(n_batches, int_array(1))
! Read batch number to restart at
call read_dataset(file_id, "current_batch", restart_batch)
call read_dataset(restart_batch, file_id, "current_batch")
! Check for source in statepoint if needed
call read_dataset(file_id, "source_present", int_array(1))
call read_dataset(int_array(1), file_id, "source_present")
if (int_array(1) == 1) then
source_present = .true.
else
@ -799,37 +803,37 @@ contains
! Read information specific to eigenvalue run
if (run_mode == MODE_EIGENVALUE) then
call read_dataset(file_id, "n_inactive", int_array(1))
call read_dataset(file_id, "gen_per_batch", gen_per_batch)
call read_dataset(file_id, "k_generation", &
k_generation(1:restart_batch*gen_per_batch))
call read_dataset(file_id, "entropy", &
entropy(1:restart_batch*gen_per_batch))
call read_dataset(file_id, "k_col_abs", k_col_abs)
call read_dataset(file_id, "k_col_tra", k_col_tra)
call read_dataset(file_id, "k_abs_tra", k_abs_tra)
call read_dataset(file_id, "k_combined", real_array(1:2))
call read_dataset(int_array(1), file_id, "n_inactive")
call read_dataset(gen_per_batch, file_id, "gen_per_batch")
call read_dataset(k_generation(1:restart_batch*gen_per_batch), &
file_id, "k_generation")
call read_dataset(entropy(1:restart_batch*gen_per_batch), &
file_id, "entropy")
call read_dataset(k_col_abs, file_id, "k_col_abs")
call read_dataset(k_col_tra, file_id, "k_col_tra")
call read_dataset(k_abs_tra, file_id, "k_abs_tra")
call read_dataset(real_array(1:2), file_id, "k_combined")
! Take maximum of statepoint n_inactive and input n_inactive
n_inactive = max(n_inactive, int_array(1))
! Read in to see if CMFD was on
call read_dataset(file_id, "cmfd_on", int_array(1))
call read_dataset(int_array(1), file_id, "cmfd_on")
! Read in CMFD info
if (int_array(1) == 1) then
cmfd_group = open_group(file_id, "cmfd")
call read_dataset(cmfd_group, "indices", cmfd%indices)
call read_dataset(cmfd_group, "k_cmfd", cmfd%k_cmfd(1:restart_batch))
call read_dataset(cmfd_group, "cmfd_src", cmfd%cmfd_src)
call read_dataset(cmfd_group, "cmfd_entropy", &
cmfd%entropy(1:restart_batch))
call read_dataset(cmfd_group, "cmfd_balance", &
cmfd%balance(1:restart_batch))
call read_dataset(cmfd_group, "cmfd_dominance", &
cmfd%dom(1:restart_batch))
call read_dataset(cmfd_group, "cmfd_srccmp", &
cmfd%src_cmp(1:restart_batch))
call read_dataset(cmfd % indices, cmfd_group, "indices")
call read_dataset(cmfd % k_cmfd(1:restart_batch), cmfd_group, "k_cmfd")
call read_dataset(cmfd % cmfd_src, cmfd_group, "cmfd_src")
call read_dataset(cmfd % entropy(1:restart_batch), cmfd_group, &
"cmfd_entropy")
call read_dataset(cmfd % balance(1:restart_batch), cmfd_group, &
"cmfd_balance")
call read_dataset(cmfd % dom(1:restart_batch), cmfd_group, &
"cmfd_dominance")
call read_dataset(cmfd % src_cmp(1:restart_batch), cmfd_group, &
"cmfd_srccmp")
call close_group(cmfd_group)
end if
end if
@ -849,14 +853,14 @@ contains
#endif
! Read number of realizations for global tallies
call read_dataset(file_id, "n_realizations", n_realizations, indep=.true.)
call read_dataset(n_realizations, file_id, "n_realizations", indep=.true.)
! Read global tally data
call read_dataset(file_id, "global_tallies", global_tallies)
! Check if tally results are present
tallies_group = open_group(file_id, "tallies")
call read_dataset(tallies_group, "tallies_present", int_array(1), &
call read_dataset(int_array(1), tallies_group, "tallies_present", &
indep=.true.)
! Read in sum and sum squared
@ -869,8 +873,8 @@ contains
tally_group = open_group(tallies_group, "tally " // &
trim(to_str(tally % id)))
call read_dataset(tally_group, "results", tally % results)
call read_dataset(tally_group, "n_realizations", &
tally % n_realizations)
call read_dataset(tally % n_realizations, tally_group, &
"n_realizations")
call close_group(tally_group)
end do TALLY_RESULTS
end if
@ -896,7 +900,7 @@ contains
file_id = file_open(path_source_point, 'r', parallel=.true.)
! Read file type
call read_dataset(file_id, "filetype", int_array(1))
call read_dataset(int_array(1), file_id, "filetype")
end if

View file

@ -68,6 +68,7 @@ contains
"description", "Number of generations per batch")
end if
call write_nuclides(file_id)
call write_geometry(file_id)
call write_materials(file_id)
if (n_tallies > 0) then
@ -105,6 +106,49 @@ contains
end subroutine write_header
!===============================================================================
! WRITE_NUCLIDES
!===============================================================================
subroutine write_nuclides(file_id)
integer(HID_T), intent(in) :: file_id
integer(HID_T) :: nuclide_group
integer :: i
character(12), allocatable :: nucnames(:)
real(8), allocatable :: awrs(:)
integer, allocatable :: zaids(:)
! Write useful data from nuclide objects
nuclide_group = create_group(file_id, "nuclides")
call write_dataset(nuclide_group, "n_nuclides_total", n_nuclides_total)
! Build array of nuclide names, awrs, and zaids
allocate(nucnames(n_nuclides_total))
allocate(awrs(n_nuclides_total))
allocate(zaids(n_nuclides_total))
do i = 1, n_nuclides_total
if (run_CE) then
nucnames(i) = xs_listings(nuclides(i) % listing) % alias
awrs(i) = nuclides(i) % awr
zaids(i) = nuclides(i) % zaid
else
nucnames(i) = xs_listings(nuclides_MG(i) % obj % listing) % alias
awrs(i) = nuclides_MG(i) % obj % awr
zaids(i) = nuclides_MG(i) % obj % zaid
end if
end do
! Write nuclide names, awrs and zaids
call write_dataset(nuclide_group, "names", nucnames)
call write_dataset(nuclide_group, "awrs", awrs)
call write_dataset(nuclide_group, "zaids", zaids)
call close_group(nuclide_group)
deallocate(nucnames, awrs, zaids)
end subroutine write_nuclides
!===============================================================================
! WRITE_GEOMETRY
!===============================================================================
@ -661,7 +705,11 @@ contains
allocate(str_array(t%n_nuclide_bins))
NUCLIDE_LOOP: do j = 1, t%n_nuclide_bins
if (t%nuclide_bins(j) > 0) then
i_list = nuclides(t%nuclide_bins(j))%listing
if (run_CE) then
i_list = nuclides(t % nuclide_bins(j)) % listing
else
i_list = nuclides_MG(t % nuclide_bins(j)) % obj % listing
end if
i_xs = index(xs_listings(i_list)%alias, '.')
if (i_xs > 0) then
str_array(j) = xs_listings(i_list)%alias(1:i_xs - 1)

View file

@ -27,8 +27,9 @@ module tally
!$omp threadprivate(position)
procedure(score_general_), pointer :: score_general => null()
procedure(get_scoring_bins_), pointer :: get_scoring_bins => null()
procedure(score_general_), pointer :: score_general => null()
procedure(score_analog_tally_), pointer :: score_analog_tally => null()
procedure(get_scoring_bins_), pointer :: get_scoring_bins => null()
abstract interface
subroutine score_general_(p, t, start_index, filter_index, i_nuclide, &
@ -44,6 +45,11 @@ module tally
real(8), intent(in) :: atom_density ! atom/b-cm
end subroutine score_general_
subroutine score_analog_tally_(p)
import Particle
type(Particle), intent(in) :: p
end subroutine score_analog_tally_
subroutine get_scoring_bins_(p, i_tally, found_bin)
import Particle
type(Particle), intent(in) :: p
@ -61,11 +67,13 @@ contains
subroutine init_tally_routines()
if (run_CE) then
score_general => score_general_ce
get_scoring_bins => get_scoring_bins_ce
score_general => score_general_ce
score_analog_tally => score_analog_tally_ce
get_scoring_bins => get_scoring_bins_ce
else
score_general => score_general_mg
get_scoring_bins => get_scoring_bins_mg
score_general => score_general_mg
score_analog_tally => score_analog_tally_mg
get_scoring_bins => get_scoring_bins_mg
end if
end subroutine init_tally_routines
@ -810,16 +818,48 @@ contains
integer :: score_bin ! scoring bin, e.g. SCORE_FLUX
integer :: score_index ! scoring bin index
real(8) :: score ! analog tally score
real(8) :: macro_total ! material macro total xs
real(8) :: macro_scatt ! material macro scatt xs
real(8) :: micro_abs ! nuclidic microscopic abs
real(8) :: p_uvw(3) ! Particle's current uvw
integer :: p_g ! Particle group to use for getting info
! to tally with.
class(Mgxs), pointer :: matxs
class(Mgxs), pointer :: nucxs
! Set the direction, if needed for nuclidic data, so that nuc % get_xs
! knows wihch direction it should be using for direction-dependent
! mgxs
if (i_nuclide > 0) then
! Set the direction and group to use with get_xs
! this only depends on if we
if (t % estimator == ESTIMATOR_ANALOG .or. &
t % estimator == ESTIMATOR_COLLISION) then
if (survival_biasing) then
! Then we either are alive and had a scatter (and so g changed),
! or are dead and g did not change
if (p % alive) then
p_uvw = p % last_uvw
p_g = p % last_g
else
p_uvw = p % coord(p % n_coord) % uvw
p_g = p % g
end if
else if (p % event == EVENT_SCATTER) then
! Then the energy group has been changed by the scattering routine
! meaning gin is now in p % last_g
p_uvw = p % last_uvw
p_g = p % last_g
else
! No scatter, no change in g.
p_uvw = p % coord(p % n_coord) % uvw
p_g = p % g
end if
else
! No actual collision so g has not changed.
p_uvw = p % coord(p % n_coord) % uvw
p_g = p % g
end if
! To significantly reduce de-referencing, point matxs to the
! macroscopic Mgxs for the material of interest
matxs => macro_xs(p % material) % obj
! Do same for nucxs, point it to the microscopic nuclide data of interest
if (i_nuclide > 0) then
nucxs => nuclides_MG(i_nuclide) % obj
end if
i = 0
@ -870,13 +910,16 @@ contains
else
score = p % last_wgt
end if
if (i_nuclide > 0) then
score = score * atom_density * &
nucxs % get_xs('total', p_g, UVW=p_uvw) / &
matxs % get_xs('total', p_g, UVW=p_uvw)
end if
else
if (i_nuclide > 0) then
associate (nuc => nuclides_MG(i_nuclide) % obj)
score = nuc % get_xs(p % g, 'total', UVW=p_uvw) * &
atom_density * flux
end associate
score = nucxs % get_xs('total', p_g, UVW=p_uvw) * &
atom_density * flux
else
score = material_xs % total * flux
end if
@ -884,7 +927,8 @@ contains
case (SCORE_INVERSE_VELOCITY)
if (t % estimator == ESTIMATOR_ANALOG) then
if (t % estimator == ESTIMATOR_ANALOG .or. &
t % estimator == ESTIMATOR_COLLISION) then
! All events score to an inverse velocity bin. We actually use a
! collision estimator in place of an analog one since there is no way
! to count 'events' exactly for the inverse velocity
@ -895,150 +939,94 @@ contains
else
score = p % last_wgt
end if
score = score * inverse_velocities(p % last_g)
score = score * inverse_velocities(p_g) / material_xs % total
else
! For inverse velocity, we need no cross section
score = score * inverse_velocities(p % g)
score = flux * inverse_velocities(p_g)
end if
case (SCORE_SCATTER, SCORE_SCATTER_N)
case (SCORE_SCATTER, SCORE_SCATTER_N, SCORE_SCATTER_PN, SCORE_SCATTER_YN)
if (t % estimator == ESTIMATOR_ANALOG) then
! Skip any event where the particle didn't scatter
if (p % event /= EVENT_SCATTER) cycle SCORE_LOOP
if (p % event /= EVENT_SCATTER) then
if (score_bin == SCORE_SCATTER_PN) then
i = i + t % moment_order(i)
else if (score_bin == SCORE_SCATTER_YN) then
i = i + (t % moment_order(i) + 1)**2 - 1
end if
cycle SCORE_LOOP
end if
! Since only scattering events make it here, again we can use
! the weight entering the collision as the estimator for the
! reaction rate
score = p % last_wgt
else
! Note SCORE_SCATTER_N not available for tracklength/collision.
! Since we transport based on material data, the angle selected
! was not selected from the f(mu) for the nuclide. Therefore
! adjust the score by the actual probability for that nuclide.
if (i_nuclide > 0) then
associate (nuc => nuclides_MG(i_nuclide) % obj)
score = nuc % get_xs(p % g, 'scatter', UVW=p_uvw) * &
atom_density * flux
end associate
score = score * atom_density * &
nucxs % get_xs('scatter*f_mu/mult', p % last_g, p % g, &
UVW=p_uvw, MU=p % mu) / &
matxs % get_xs('scatter*f_mu/mult', p % last_g, p % g, &
UVW=p_uvw, MU=p % mu)
end if
else
! Note SCORE_SCATTER_*N not available for tracklength/collision.
if (i_nuclide > 0) then
score = atom_density * flux * &
nucxs % get_xs('scatter/mult', p_g, UVW=p_uvw)
else
! Get the scattering x/s (stored in % elastic)
score = material_xs % elastic * flux
! Get the scattering x/s and take away
! the multiplication baked in to sigS
score = flux * &
matxs % get_xs('scatter/mult', p_g, UVW=p_uvw)
end if
end if
if (i_nuclide > 0) then
associate (nuc => nuclides_MG(i_nuclide) % obj)
score = score * nuc % get_xs(p % g, 'f_mu/mult', p % last_g, &
p % last_uvw, p % mu)
end associate
case (SCORE_NU_SCATTER, SCORE_NU_SCATTER_N, SCORE_NU_SCATTER_PN, &
SCORE_NU_SCATTER_YN)
if (t % estimator == ESTIMATOR_ANALOG) then
! Skip any event where the particle didn't scatter
if (p % event /= EVENT_SCATTER) then
if (score_bin == SCORE_NU_SCATTER_PN) then
i = i + t % moment_order(i)
else if (score_bin == SCORE_NU_SCATTER_YN) then
i = i + (t % moment_order(i) + 1)**2 - 1
end if
cycle SCORE_LOOP
end if
! For scattering production, we need to use the pre-collision
! weight times the multiplicity as the estimate for the number of
! neutrons exiting a reaction with neutrons in the exit channel
score = p % wgt
! Since we transport based on material data, the angle selected
! was not selected from the f(mu) for the nuclide. Therefore
! adjust the score by the actual probability for that nuclide.
if (i_nuclide > 0) then
score = score * atom_density * &
nucxs % get_xs('scatter*f_mu', p % last_g, p % g, &
UVW=p_uvw, MU=p % mu) / &
matxs % get_xs('scatter*f_mu', p % last_g, p % g, &
UVW=p_uvw, MU=p % mu)
end if
else
score = score / &
macro_xs(p % material) % obj % get_xs(p % g, 'mult', &
p % last_g, &
p % last_uvw)
end if
case (SCORE_SCATTER_PN)
! Only analog estimators are available.
! Skip any event where the particle didn't scatter
if (p % event /= EVENT_SCATTER) then
i = i + t % moment_order(i)
cycle SCORE_LOOP
end if
! Since only scattering events make it here, again we can use
! the weight entering the collision as the estimator for the
! reaction rate
score = p % last_wgt
if (i_nuclide > 0) then
associate (nuc => nuclides_MG(i_nuclide) % obj)
score = score * nuc % get_xs(p % g, 'f_mu/mult', p % last_g, &
p % last_uvw, p % mu)
end associate
else
score = score / &
macro_xs(p % material) % obj % get_xs(p % g, 'mult', &
p % last_g, &
p % last_uvw)
end if
case (SCORE_SCATTER_YN)
! Only analog estimators are available.
! Skip any event where the particle didn't scatter
if (p % event /= EVENT_SCATTER) then
i = i + (t % moment_order(i) + 1)**2 - 1
cycle SCORE_LOOP
end if
! Since only scattering events make it here, again we can use
! the weight entering the collision as the estimator for the
! reaction rate
score = p % last_wgt
if (i_nuclide > 0) then
associate (nuc => nuclides_MG(i_nuclide) % obj)
score = score * nuc % get_xs(p % g, 'f_mu/mult', p % last_g, &
p % last_uvw, p % mu)
end associate
else
score = score / &
macro_xs(p % material) % obj % get_xs(p % g, 'mult', &
p % last_g, &
p % last_uvw)
end if
case (SCORE_NU_SCATTER, SCORE_NU_SCATTER_N)
! Only analog estimators are available.
! Skip any event where the particle didn't scatter
if (p % event /= EVENT_SCATTER) cycle SCORE_LOOP
! For scattering production, we need to use the pre-collision
! weight times the multiplicity as the estimate for the number of
! neutrons exiting a reaction with neutrons in the exit channel
score = p % wgt
if (i_nuclide > 0) then
associate (nuc => nuclides_MG(i_nuclide) % obj)
score = score * nuc % get_xs(p % g, 'f_mu', p % last_g, &
p % last_uvw, p % mu)
end associate
end if
case (SCORE_NU_SCATTER_PN)
! Only analog estimators are available.
! Skip any event where the particle didn't scatter
if (p % event /= EVENT_SCATTER) then
i = i + t % moment_order(i)
cycle SCORE_LOOP
end if
! For scattering production, we need to use the pre-collision
! weight times the multiplicity as the estimate for the number of
! neutrons exiting a reaction with neutrons in the exit channel
score = p % wgt
if (i_nuclide > 0) then
associate (nuc => nuclides_MG(i_nuclide) % obj)
score = score * nuc % get_xs(p % g, 'f_mu', p % last_g, &
p % last_uvw, p % mu)
end associate
end if
case (SCORE_NU_SCATTER_YN)
! Only analog estimators are available.
! Skip any event where the particle didn't scatter
if (p % event /= EVENT_SCATTER) then
i = i + (t % moment_order(i) + 1)**2 - 1
cycle SCORE_LOOP
end if
! For scattering production, we need to use the pre-collision
! weight times the multiplicity as the estimate for the number of
! neutrons exiting a reaction with neutrons in the exit channel
score = p % wgt
if (i_nuclide > 0) then
associate (nuc => nuclides_MG(i_nuclide) % obj)
score = score * nuc % get_xs(p % g, 'f_mu', p % last_g, &
p % last_uvw, p % mu)
end associate
! Note SCORE_NU_SCATTER_*N not available for tracklength/collision.
if (i_nuclide > 0) then
score = nucxs % get_xs('scatter', p_g, UVW=p_uvw) * &
atom_density * flux
else
! Get the scattering x/s, which includes multiplication
score = matxs % get_xs('scatter', p_g, UVW=p_uvw) * flux
end if
end if
@ -1046,24 +1034,14 @@ contains
! Only analog estimators are available.
! Skip any event where the particle didn't scatter
if (p % event /= EVENT_SCATTER) cycle SCORE_LOOP
! get material macros
macro_total = material_xs % total
macro_scatt = material_xs % elastic
! Score total rate - p1 scatter rate Note estimator needs to be
! adjusted since tallying is only occuring when a scatter has
! happened. Effectively this means multiplying the estimator by
! total/scatter macro
score = (macro_total - p % mu * macro_scatt) * (ONE / macro_scatt)
case (SCORE_N_1N)
! Only analog estimators are available.
! Skip any event where the particle didn't scatter
if (p % event /= EVENT_SCATTER) cycle SCORE_LOOP
! Skip any events where weight of particle changed
if (p % wgt /= p % last_wgt) cycle SCORE_LOOP
! All events that reach this point are (n,1n) reactions
score = p % last_wgt
score = (material_xs % total - p % mu * material_xs % elastic)
if (material_xs % elastic /= ZERO) then
score = score / material_xs % elastic
end if
case (SCORE_ABSORPTION)
@ -1079,13 +1057,15 @@ contains
! can just use the particle's weight entering the collision
score = p % last_wgt
end if
if (i_nuclide > 0) then
score = score * atom_density * &
nucxs % get_xs('absorption', p_g, UVW=p_uvw) / &
matxs % get_xs('absorption', p_g, UVW=p_uvw)
end if
else
if (i_nuclide > 0) then
associate (nuc => nuclides_MG(i_nuclide) % obj)
score = nuc % get_xs(p % g, 'absorption', UVW=p_uvw) &
* atom_density * flux
end associate
score = nucxs % get_xs('absorption', p_g, UVW=p_uvw) * &
atom_density * flux
else
score = material_xs % absorption * flux
end if
@ -1098,38 +1078,30 @@ contains
! No fission events occur if survival biasing is on -- need to
! calculate fraction of absorptions that would have resulted in
! fission
associate (nuc => nuclides_MG(i_nuclide) % obj)
micro_abs = nuc % get_xs(p % g, 'absorption', UVW=p_uvw)
if (micro_abs > ZERO) then
score = p % absorb_wgt * &
nuc % get_xs(p % g, 'fission', UVW=p_uvw) &
/ micro_abs
else
score = ZERO
end if
end associate
score = p % absorb_wgt
else
! Skip any non-absorption events
if (p % event == EVENT_SCATTER) cycle SCORE_LOOP
! All fission events will contribute, so again we can use
! particle's weight entering the collision as the estimate for the
! fission reaction rate
associate (nuc => nuclides_MG(i_nuclide) % obj)
score = p % last_wgt &
* nuc % get_xs(p % g, 'fission', UVW=p_uvw) &
/ nuc % get_xs(p % g, 'absorption', UVW=p_uvw)
end associate
score = p % last_wgt
end if
if (i_nuclide > 0) then
score = score * atom_density * &
nucxs % get_xs('fission', p_g, UVW=p_uvw) / &
matxs % get_xs('absorption', p_g, UVW=p_uvw)
else
score = score * &
matxs % get_xs('fission', p_g, UVW=p_uvw) / &
matxs % get_xs('absorption', p_g, UVW=p_uvw)
end if
else
if (i_nuclide > 0) then
associate (nuc => nuclides_MG(i_nuclide) % obj)
score = nuc % get_xs(p % g, 'fission', UVW=p_uvw) * &
atom_density * flux
end associate
score = nucxs % get_xs('fission', p_g, UVW=p_uvw) * &
atom_density * flux
else
score = flux * macro_xs(p % material) % obj % get_xs(p % g, &
'fission', UVW=p_uvw)
score = flux * material_xs % fission
end if
end if
@ -1144,7 +1116,8 @@ contains
! neutrons were emitted with different energies, multiple
! outgoing energy bins may have been scored to. The following
! logic treats this special case and results to multiple bins
call score_fission_eout_mg(p, t, score_index)
call score_fission_eout_mg(p, t, score_index, i_nuclide, &
atom_density)
cycle SCORE_LOOP
end if
end if
@ -1152,16 +1125,16 @@ contains
! No fission events occur if survival biasing is on -- need to
! calculate fraction of absorptions that would have resulted in
! nu-fission
associate (nuc => nuclides_MG(i_nuclide) % obj)
micro_abs = nuc % get_xs(p % g, 'absorption', UVW=p_uvw)
if (micro_abs > ZERO) then
score = p % absorb_wgt * &
nuc % get_xs(p % g, 'fission', UVW=p_uvw) / &
micro_abs
else
score = ZERO
end if
end associate
score = p % absorb_wgt
if (i_nuclide > 0) then
score = score * atom_density * &
nucxs % get_xs('nu_fission', p_g, UVW=p_uvw) / &
matxs % get_xs('absorption', p_g, UVW=p_uvw)
else
score = score * &
matxs % get_xs('nu_fission', p_g, UVW=p_uvw) / &
matxs % get_xs('absorption', p_g, UVW=p_uvw)
end if
else
! Skip any non-fission events
if (.not. p % fission) cycle SCORE_LOOP
@ -1171,14 +1144,17 @@ contains
! bank. Since this was weighted by 1/keff, we multiply by keff
! to get the proper score.
score = keff * p % wgt_bank
if (i_nuclide > 0) then
score = score * atom_density * &
nucxs % get_xs('fission', p_g, UVW=p_uvw) / &
matxs % get_xs('fission', p_g, UVW=p_uvw)
end if
end if
else
if (i_nuclide > 0) then
associate (nuc => nuclides_MG(i_nuclide) % obj)
score = nuc % get_xs(p % g, 'nu_fission', UVW=p_uvw) &
* atom_density * flux
end associate
score = nucxs % get_xs('nu_fission', p_g, UVW=p_uvw) * &
atom_density * flux
else
score = material_xs % nu_fission * flux
end if
@ -1186,43 +1162,36 @@ contains
case (SCORE_KAPPA_FISSION)
! Determine kappa-fission cross section
score = ZERO
if (t % estimator == ESTIMATOR_ANALOG) then
if (survival_biasing) then
! No fission events occur if survival biasing is on -- need to
! calculate fraction of absorptions that would have resulted in
! fission scale by kappa-fission
associate (nuc => nuclides_MG(i_nuclide) % obj)
micro_abs = nuc % get_xs(p % g, 'absorption', UVW=p_uvw)
if (micro_abs > ZERO) then
score = p % absorb_wgt * &
nuc % get_xs(p % g, 'k_fission', UVW=p_uvw) / &
micro_abs
end if
end associate
! fission
score = p % absorb_wgt
else
! Skip any non-absorption events
if (p % event == EVENT_SCATTER) cycle SCORE_LOOP
! All fission events will contribute, so again we can use
! particle's weight entering the collision as the estimate for
! the fission energy production rate
associate (nuc => nuclides_MG(i_nuclide) % obj)
score = p % last_wgt * &
nuc % get_xs(p % g, 'k_fission', UVW=p_uvw) / &
nuc % get_xs(p % g, 'absorption', UVW=p_uvw)
end associate
! particle's weight entering the collision as the estimate for the
! fission reaction rate
score = p % last_wgt
end if
if (i_nuclide > 0) then
score = score * atom_density * &
nucxs % get_xs('kappa_fission', p_g, UVW=p_uvw) / &
matxs % get_xs('absorption', p_g, UVW=p_uvw)
else
score = score * &
matxs % get_xs('kappa_fission', p_g, UVW=p_uvw) / &
matxs % get_xs('absorption', p_g, UVW=p_uvw)
end if
else
if (i_nuclide > 0) then
associate (nuc => nuclides_MG(i_nuclide) % obj)
score = nuc % get_xs(p % g, 'k_fission', UVW=p_uvw) &
* atom_density * flux
end associate
score = flux * atom_density * &
nucxs % get_xs('kappa_fission', p_g, UVW=p_uvw)
else
score = flux * macro_xs(p % material) % obj % get_xs(p % g, &
'k_fission', UVW=p_uvw)
score = flux * matxs % get_xs('kappa_fission', p_g, UVW=p_uvw)
end if
end if
@ -1239,6 +1208,8 @@ contains
score, i)
end do SCORE_LOOP
nullify(matxs,nucxs)
end subroutine score_general_mg
!===============================================================================
@ -1413,7 +1384,7 @@ contains
! triggered at every collision, not every event
!===============================================================================
subroutine score_analog_tally(p)
subroutine score_analog_tally_ce(p)
type(Particle), intent(in) :: p
@ -1423,17 +1394,9 @@ contains
! position during the loop
integer :: filter_index ! single index for single bin
integer :: i_nuclide ! index in nuclides array
real(8) :: last_wgt ! pre-collision particle weight
real(8) :: wgt ! post-collision particle weight
real(8) :: mu ! cosine of angle of collision
logical :: found_bin ! scoring bin found?
type(TallyObject), pointer :: t
! Copy particle's pre- and post-collision weight and angle
last_wgt = p % last_wgt
wgt = p % wgt
mu = p % mu
! A loop over all tallies is necessary because we need to simultaneously
! determine different filter bins for the same tally in order to score to it
@ -1512,7 +1475,87 @@ contains
! Reset tally map positioning
position = 0
end subroutine score_analog_tally
end subroutine score_analog_tally_ce
subroutine score_analog_tally_mg(p)
type(Particle), intent(in) :: p
integer :: i, m
integer :: i_tally
integer :: k ! loop index for nuclide bins
! position during the loop
integer :: filter_index ! single index for single bin
integer :: i_nuclide ! index in nuclides array
logical :: found_bin ! scoring bin found?
type(TallyObject), pointer :: t
type(Material), pointer :: mat
real(8) :: atom_density
! A loop over all tallies is necessary because we need to simultaneously
! determine different filter bins for the same tally in order to score to it
TALLY_LOOP: do i = 1, active_analog_tallies % size()
! Get index of tally and pointer to tally
i_tally = active_analog_tallies % get_item(i)
t => tallies(i_tally)
! Get pointer to current material. We need this in order to determine what
! nuclides are in the material
mat => materials(p % material)
! =======================================================================
! DETERMINE SCORING BIN COMBINATION
call get_scoring_bins(p, i_tally, found_bin)
if (.not. found_bin) cycle
! =======================================================================
! CALCULATE RESULTS AND ACCUMULATE TALLY
! If we have made it here, we have a scoring combination of bins for this
! tally -- now we need to determine where in the results array we should
! be accumulating the tally values
! Determine scoring index for this filter combination
filter_index = sum((matching_bins(1:t%n_filters) - 1) * t % stride) + 1
! Check for nuclide bins
k = 0
NUCLIDE_LOOP: do while (k < t % n_nuclide_bins)
! Increment the index in the list of nuclide bins
k = k + 1
i_nuclide = t % nuclide_bins(k)
! Check to see if this nuclide was in the material of our collision.
do m = 1, mat % n_nuclides
if (mat % nuclide(m) == i_nuclide) then
atom_density = mat % atom_density(m)
exit
end if
end do
! Determine score for each bin
call score_general(p, t, (k-1)*t % n_score_bins, filter_index, &
i_nuclide, atom_density, ZERO)
end do NUCLIDE_LOOP
! If the user has specified that we can assume all tallies are spatially
! separate, this implies that once a tally has been scored to, we needn't
! check the others. This cuts down on overhead when there are many
! tallies specified
if (assume_separate) exit TALLY_LOOP
end do TALLY_LOOP
! Reset tally map positioning
position = 0
end subroutine score_analog_tally_mg
!===============================================================================
! SCORE_FISSION_EOUT handles a special case where we need to store neutron
@ -1582,10 +1625,12 @@ contains
end subroutine score_fission_eout_ce
subroutine score_fission_eout_mg(p, t, i_score)
subroutine score_fission_eout_mg(p, t, i_score, i_nuclide, atom_density)
type(Particle), intent(in) :: p
type(TallyObject), intent(inout) :: t
integer, intent(in) :: i_score ! index for score
integer, intent(in) :: i_score ! index for score
integer, intent(in) :: i_nuclide ! index for nuclide
real(8), intent(in) :: atom_density
integer :: i ! index of outgoing energy filter
integer :: n ! number of energies on filter
@ -1594,6 +1639,7 @@ contains
integer :: i_filter ! index for matching filter bin combination
real(8) :: score ! actual score
integer :: gout ! energy group of fission bank site
integer :: gin ! energy group of incident particle
real(8) :: E_out
! save original outgoing energy bin and score index
@ -1612,6 +1658,18 @@ contains
do k = 1, p % n_bank
! determine score based on bank site weight and keff
score = keff * fission_bank(n_bank - p % n_bank + k) % wgt
if (i_nuclide > 0) then
if (survival_biasing) then
gin = p % g
else
gin = p % last_g
end if
score = score * atom_density * &
nuclides_MG(i_nuclide) % obj % get_xs('fission', gin, &
UVW=p % last_uvw) / &
macro_xs(p % material) % obj % get_xs('fission', gin, &
UVW=p % last_uvw)
end if
if (t % energyout_matches_groups) then
! determine outgoing energy from fission bank
@ -1621,7 +1679,7 @@ contains
matching_bins(i) = gout
else
! determine outgoing energy from fission bank
E_out = fission_bank(n_bank - p % n_bank + k) % E
E_out = energy_bin_avg(int(fission_bank(n_bank - p % n_bank + k) % E))
! check if outgoing energy is within specified range on filter
if (E_out < t % filters(i) % real_bins(1) .or. &
@ -2617,7 +2675,6 @@ contains
end if
end if
case (FILTER_ENERGYOUT)
if (t % energyout_matches_groups) then
! Since all groups are filters, the filter bin is the group
@ -2641,7 +2698,6 @@ contains
end if
end if
case (FILTER_MU)
! determine mu bin
n = t % filters(i) % n_bins

View file

@ -7,7 +7,6 @@ module tracking
cross_lattice, check_cell_overlap
use geometry_header, only: Universe, BASE_UNIVERSE
use global
use macroxs_header, only: MacroXS
use output, only: write_message
use particle_header, only: LocalCoord, Particle
use physics, only: collision
@ -103,6 +102,7 @@ contains
material_xs % total = ZERO
material_xs % elastic = ZERO
material_xs % absorption = ZERO
material_xs % fission = ZERO
material_xs % nu_fission = ZERO
end if
end if

View file

@ -5,9 +5,9 @@ from openmc.stats import Box
class InputSet(object):
def __init__(self):
self.settings = openmc.SettingsFile()
self.materials = openmc.MaterialsFile()
self.geometry = openmc.GeometryFile()
self.settings = openmc.Settings()
self.materials = openmc.Materials()
self.geometry = openmc.Geometry()
self.tallies = None
self.plots = None
@ -267,9 +267,9 @@ class InputSet(object):
# Define the materials file.
self.materials.default_xs = '71c'
self.materials.add_materials((fuel, clad, cold_water, hot_water,
rpv_steel, lower_rad_ref, upper_rad_ref, bot_plate, bot_nozzle,
top_nozzle, top_fa, bot_fa))
self.materials += (fuel, clad, cold_water, hot_water, rpv_steel,
lower_rad_ref, upper_rad_ref, bot_plate,
bot_nozzle, top_nozzle, top_fa, bot_fa)
# Define surfaces.
s1 = openmc.ZCylinder(R=0.41, surface_id=1)
@ -550,11 +550,8 @@ class InputSet(object):
root.add_cells((c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12))
# Define the geometry file.
geometry = openmc.Geometry()
geometry.root_universe = root
self.geometry.geometry = geometry
# Assign root universe to geometry
self.geometry.root_universe = root
def build_default_settings(self):
self.settings.batches = 10
@ -593,7 +590,7 @@ class MGInputSet(InputSet):
# Define the materials file.
self.materials.default_xs = '71c'
self.materials.add_materials((uo2, clad, water))
self.materials += (uo2, clad, water)
# Define surfaces.
@ -630,12 +627,8 @@ class MGInputSet(InputSet):
root.add_cells((c1,c2,c3))
# Define the geometry file.
geometry = openmc.Geometry()
geometry.root_universe = root
self.geometry.geometry = geometry
# Assign root universe to geometry
self.geometry.root_universe = root
def build_default_settings(self):
self.settings.batches = 10
@ -656,8 +649,3 @@ class MGInputSet(InputSet):
plot.color = 'mat'
self.plots.add_plot(plot)

View file

@ -1 +1 @@
b9b4222c4beea80fe6083590f6b785303d174972d80671fb661bac8e030db6f4a61648240cfad6162799361fc0e08a23c61d31aff844d978528d6dad5b5fbc63
9b859eb5501c05b6a652d299bd0cadc0a924ffae31117babbdc9f7f8ca87689322c275818eb0dde0ff5fa78317d8d8f1585b18dcc772e3ff4ed499de8a491dc3

View file

@ -7,8 +7,6 @@ import hashlib
sys.path.insert(0, os.pardir)
from testing_harness import PyAPITestHarness
import openmc
from openmc.source import Source
from openmc.stats import Box
class AsymmetricLatticeTestHarness(PyAPITestHarness):
@ -20,7 +18,7 @@ class AsymmetricLatticeTestHarness(PyAPITestHarness):
self._input_set.build_default_materials_and_geometry()
# Extract universes encapsulating fuel and water assemblies
geometry = self._input_set.geometry.geometry
geometry = self._input_set.geometry
water = geometry.get_universes_by_name('water assembly (hot)')[0]
fuel = geometry.get_universes_by_name('fuel assembly (hot)')[0]
@ -49,19 +47,18 @@ class AsymmetricLatticeTestHarness(PyAPITestHarness):
root_univ.add_cell(root_cell)
# Over-ride geometry in the input set with this 3x3 lattice
self._input_set.geometry.geometry.root_universe = root_univ
self._input_set.geometry.root_universe = root_univ
# Initialize a "distribcell" filter for the fuel pin cell
distrib_filter = openmc.Filter(type='distribcell', bins=[27])
# Initialize the tallies
tally = openmc.Tally(name='distribcell tally', tally_id=27)
tally.add_filter(distrib_filter)
tally.add_score('nu-fission')
tally.filters.append(distrib_filter)
tally.scores.append('nu-fission')
# Initialize the tallies file
tallies_file = openmc.TalliesFile()
tallies_file.add_tally(tally)
tallies_file = openmc.Tallies([tally])
# Assign the tallies file to the input set
self._input_set.tallies = tallies_file
@ -70,7 +67,7 @@ class AsymmetricLatticeTestHarness(PyAPITestHarness):
self._input_set.build_default_settings()
# Specify summary output and correct source sampling box
source = Source(space=Box([-32, -32, 0], [32, 32, 32]))
source = openmc.Source(space=openmc.stats.Box([-32, -32, 0], [32, 32, 32]))
source.space.only_fissionable = True
self._input_set.settings.source = source
self._input_set.settings.output = {'summary': True}
@ -85,11 +82,6 @@ class AsymmetricLatticeTestHarness(PyAPITestHarness):
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)
# Extract the tally of interest
tally = sp.get_tally(name='distribcell tally')
@ -99,8 +91,8 @@ class AsymmetricLatticeTestHarness(PyAPITestHarness):
outstr += ', '.join(map(str, tally.std_dev.flatten())) + '\n'
# Extract fuel assembly lattices from the summary
core = su.get_cell_by_id(1)
fuel = su.get_cell_by_id(80)
core = sp.summary.get_cell_by_id(1)
fuel = sp.summary.get_cell_by_id(80)
fuel = fuel.fill
core = core.fill

View file

@ -1 +1 @@
401b8be1b296db7f21ccae089c7ac480044d953b7264ca0ae8e34bb79e24cbb57195bcb568deda6f2f7e07366bbfac408a92306351b9169edd04499723707e1b
96c54eb4f1da175445bf2187449ee32c9ff435d8c60e9421a4a16497aae9f233e3e494f531892dd55f6ac1a06e0240799503ff19e14e2436a0b0f0d83ba56cb8

View file

@ -28,9 +28,8 @@ class DistribmatTestHarness(PyAPITestHarness):
light_fuel.set_density('g/cc', 2.0)
light_fuel.add_nuclide('U-235', 1.0)
mats_file = openmc.MaterialsFile()
mats_file = openmc.Materials([moderator, dense_fuel, light_fuel])
mats_file.default_xs = '71c'
mats_file.add_materials([moderator, dense_fuel, light_fuel])
mats_file.export_to_xml()
@ -74,16 +73,14 @@ class DistribmatTestHarness(PyAPITestHarness):
geometry = openmc.Geometry()
geometry.root_universe = root_univ
geo_file = openmc.GeometryFile()
geo_file.geometry = geometry
geo_file.export_to_xml()
geometry.export_to_xml()
####################
# Settings
####################
sets_file = openmc.SettingsFile()
sets_file = openmc.Settings()
sets_file.batches = 5
sets_file.inactive = 0
sets_file.particles = 1000
@ -96,7 +93,7 @@ class DistribmatTestHarness(PyAPITestHarness):
# Plots
####################
plots_file = openmc.PlotsFile()
plots_file = openmc.Plots()
plot = openmc.Plot(plot_id=1)
plot.basis = 'xy'

View file

@ -1 +1 @@
e0409e0660d58857a6a96ff5cb539ccc41c82f0e443e8081ee00bbee7b6c81b0ad43c870950ae37d4a18c329067b09479a27aa171c3a3f5771f53b384496fe61
85faac9b8c725ec9242ebc3793b70dcd1c8e58aeb4296345aefd8031304263bd66eaad0c6f1c61a1c644b73f397699856ab3d76d2b397295176650b4069acc9e

View file

@ -1 +1 @@
04b4a5099f0097bbe02983c67dea691d0d0d4ece7fb7c264b9b2c29955baa9e870b6fa999480da08ead1e5a0c078ae33ce1b0a5c8594ad465aedf9bf3933e104
2fdba76bad058eec6e43657692ef759de79c934076067d4ec5c9f2bdb131877e001f67e16b16bb14889e5e0a1ba84c780979b9d6772573aa6f82d979774c2af8

View file

@ -1,2 +1,2 @@
k-combined:
1.045320E+00 5.851680E-02
1.033731E+00 4.974463E-02

View file

@ -1 +1 @@
abe20c626d613e73ccb1a3f8468ad1b9aecca528afa9e8131a411d754eb86b8ab64a6fb1fdc9c0b8b8158ff7c82f548de5912041bf035aa5a2d4532cfe0c9510
60a35864ad71646309d7f1687ba0826d4d53a5b2e8babf73614362645205484bad3c0e7bf605ec0b11cadf58474b2e3d0a97bf2d9297f9118682c37ff0269afd

View file

@ -1,2 +1,2 @@
k-combined:
1.083030E+00 1.855038E-02
1.055274E+00 1.715904E-02

View file

@ -27,7 +27,7 @@ class MGNuclideInputSet(MGInputSet):
# Define the materials file.
self.materials.default_xs = '71c'
self.materials.add_materials((uo2, clad, water))
self.materials += (uo2, clad, water)
# Define surfaces.
@ -68,7 +68,7 @@ class MGNuclideInputSet(MGInputSet):
geometry = openmc.Geometry()
geometry.root_universe = root
self.geometry.geometry = geometry
self.geometry = geometry
class MGMaxOrderTestHarness(PyAPITestHarness):
def __init__(self, statepoint_name, tallies_present, mg=False):
@ -76,9 +76,10 @@ class MGMaxOrderTestHarness(PyAPITestHarness):
self._input_set = MGNuclideInputSet()
def _build_inputs(self):
super(MGMaxOrderTestHarness, self)._build_inputs()
# Set P1 scattering
self._input_set.settings.max_order = 1
# Call standard input build
super(MGMaxOrderTestHarness, self)._build_inputs()
if __name__ == '__main__':
harness = MGMaxOrderTestHarness('statepoint.10.*', False, mg=True)

View file

@ -1 +1 @@
c9f9e7211bfb2af58130bedfd64592d093b7bfa424953eba433ecf08940595a96b8de7a892f12d1ab465cebd8e5dd784114c1b1299b534ed329df92752c9ed1f
0efba3dd7882fdd38756d0a8f01ff00d7a1abdaab6430b3f090f3339e552448453bbb733852b6bd6ff09608d923c282f168320f942fc2eb3a45610873c588734

View file

@ -1,2 +1,2 @@
k-combined:
1.380785E-01 5.556526E-03
1.033731E+00 4.974463E-02

View file

@ -12,21 +12,21 @@ class MGNuclideInputSet(MGInputSet):
# Define materials needed for 1D/1G slab problem
# This time do using nuclide, not macroscopic
uo2 = openmc.Material(name='UO2', material_id=1)
uo2.set_density('g/cm3', 1.0)
uo2.set_density('sum', 1.0)
uo2.add_nuclide("uo2_iso", 1.0)
clad = openmc.Material(name='Clad', material_id=2)
clad.set_density('g/cm3', 1.0)
clad.set_density('sum', 1.0)
clad.add_nuclide("clad_ang_mu", 1.0)
water_data = openmc.Nuclide('lwtr_iso_mu', '71c')
# water_data = openmc.Nuclide('lwtr_iso_mu', '71c')
water = openmc.Material(name='LWTR', material_id=3)
water.set_density('g/cm3', 1.0)
water.set_density('sum', 1.0)
water.add_nuclide("lwtr_iso_mu", 1.0)
# Define the materials file.
self.materials.default_xs = '71c'
self.materials.add_materials((uo2, clad, water))
self.materials += (uo2, clad, water)
# Define surfaces.
@ -67,7 +67,7 @@ class MGNuclideInputSet(MGInputSet):
geometry = openmc.Geometry()
geometry.root_universe = root
self.geometry.geometry = geometry
self.geometry = geometry
class MGNuclideTestHarness(PyAPITestHarness):
def __init__(self, statepoint_name, tallies_present, mg=False):

View file

@ -1 +1 @@
ca8490e0e4549fed727ddc75b6d92cfe5162e11b905218a0afaa3ce2ee0763e2ff38074de27aaa678818624f49c5823650475dfa8f66f502a98fc03145399c0d
6c437c3f9281c52a80a9b166971aa0f5db7ff8b6cf65c79b6d7bf294fad30cc7044f6a665cd9059f8580441bcbb581f7152ff5bccbc21fbcc407847ea6fe3306

File diff suppressed because it is too large Load diff

View file

@ -27,24 +27,15 @@ class MGTalliesTestHarness(PyAPITestHarness):
mat_filter = openmc.Filter(type='material', bins=[1,2,3])
tally1 = openmc.Tally(tally_id=1)
tally1.add_filter(mesh_filter)
tally1.add_score('total')
tally1.add_score('absorption')
tally1.add_score('flux')
tally1.add_score('fission')
tally1.add_score('nu-fission')
tally1.filters = [mesh_filter]
tally1.scores = ['total', 'absorption', 'flux',
'fission', 'nu-fission']
tally2 = openmc.Tally(tally_id=2)
tally2.add_filter(mat_filter)
tally2.add_filter(energy_filter)
tally2.add_filter(energyout_filter)
tally2.add_score('scatter')
tally2.add_score('nu-scatter')
tally2.filters = [mat_filter, energy_filter, energyout_filter]
tally2.scores = ['scatter', 'nu-scatter']
self._input_set.tallies = openmc.TalliesFile()
self._input_set.tallies.add_mesh(mesh)
self._input_set.tallies.add_tally(tally1)
self._input_set.tallies.add_tally(tally2)
self._input_set.tallies = openmc.Tallies([tally1, tally2])
super(MGTalliesTestHarness, self)._build_inputs()

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