mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-26 21:25:36 -04:00
Merge branch 'multipole' into diff_tally5
This commit is contained in:
commit
f303b3ed8d
131 changed files with 11847 additions and 9138 deletions
6
docs/source/_templates/myfunction.rst
Normal file
6
docs/source/_templates/myfunction.rst
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{{ fullname }}
|
||||
{{ underline }}
|
||||
|
||||
.. currentmodule:: {{ module }}
|
||||
|
||||
.. autofunction:: {{ objname }}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
92
docs/source/io_formats/data_wmp.rst
Normal file
92
docs/source/io_formats/data_wmp.rst
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
.. _usersguide_particle_restart:
|
||||
.. _io_particle_restart:
|
||||
|
||||
============================
|
||||
Particle Restart File Format
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
.. _usersguide_source:
|
||||
.. _io_source:
|
||||
|
||||
==================
|
||||
Source File Format
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
.. _usersguide_statepoint:
|
||||
.. _io_statepoint:
|
||||
|
||||
=======================
|
||||
State Point File Format
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
.. _usersguide_summary:
|
||||
.. _io_summary:
|
||||
|
||||
===================
|
||||
Summary File Format
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
.. _usersguide_track:
|
||||
.. _io_track:
|
||||
|
||||
=================
|
||||
Track File Format
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
.. _usersguide_voxel:
|
||||
.. _io_voxel:
|
||||
|
||||
======================
|
||||
Voxel Plot File Format
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
1461
docs/source/pythonapi/examples/mgxs-part-iv.ipynb
Normal file
1461
docs/source/pythonapi/examples/mgxs-part-iv.ipynb
Normal file
File diff suppressed because one or more lines are too long
13
docs/source/pythonapi/examples/mgxs-part-iv.rst
Normal file
13
docs/source/pythonapi/examples/mgxs-part-iv.rst
Normal 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
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -14,7 +14,5 @@ essential aspects of using OpenMC to perform simulations.
|
|||
beginners
|
||||
install
|
||||
input
|
||||
mgxs_library
|
||||
output/index
|
||||
processing
|
||||
troubleshoot
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
1
openmc/data/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
from .data import *
|
||||
101
openmc/data/data.py
Normal file
101
openmc/data/data.py
Normal 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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
208
openmc/filter.py
208
openmc/filter.py
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
1926
openmc/mgxs/mgxs.py
1926
openmc/mgxs/mgxs.py
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -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
|
||||
|
|
|
|||
18
src/ace.F90
18
src/ace.F90
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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 &
|
||||
|
|
|
|||
|
|
@ -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 &
|
||||
¬ 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
26
src/math.F90
26
src/math.F90
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
1929
src/mgxs_header.F90
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
module simulation
|
||||
|
||||
#ifdef MPI
|
||||
use mpi
|
||||
use message_passing
|
||||
#endif
|
||||
|
||||
use cmfd_execute, only: cmfd_init_batch, execute_cmfd
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
534
src/tally.F90
534
src/tally.F90
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
b9b4222c4beea80fe6083590f6b785303d174972d80671fb661bac8e030db6f4a61648240cfad6162799361fc0e08a23c61d31aff844d978528d6dad5b5fbc63
|
||||
9b859eb5501c05b6a652d299bd0cadc0a924ffae31117babbdc9f7f8ca87689322c275818eb0dde0ff5fa78317d8d8f1585b18dcc772e3ff4ed499de8a491dc3
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
401b8be1b296db7f21ccae089c7ac480044d953b7264ca0ae8e34bb79e24cbb57195bcb568deda6f2f7e07366bbfac408a92306351b9169edd04499723707e1b
|
||||
96c54eb4f1da175445bf2187449ee32c9ff435d8c60e9421a4a16497aae9f233e3e494f531892dd55f6ac1a06e0240799503ff19e14e2436a0b0f0d83ba56cb8
|
||||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
e0409e0660d58857a6a96ff5cb539ccc41c82f0e443e8081ee00bbee7b6c81b0ad43c870950ae37d4a18c329067b09479a27aa171c3a3f5771f53b384496fe61
|
||||
85faac9b8c725ec9242ebc3793b70dcd1c8e58aeb4296345aefd8031304263bd66eaad0c6f1c61a1c644b73f397699856ab3d76d2b397295176650b4069acc9e
|
||||
|
|
@ -1 +1 @@
|
|||
04b4a5099f0097bbe02983c67dea691d0d0d4ece7fb7c264b9b2c29955baa9e870b6fa999480da08ead1e5a0c078ae33ce1b0a5c8594ad465aedf9bf3933e104
|
||||
2fdba76bad058eec6e43657692ef759de79c934076067d4ec5c9f2bdb131877e001f67e16b16bb14889e5e0a1ba84c780979b9d6772573aa6f82d979774c2af8
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
k-combined:
|
||||
1.045320E+00 5.851680E-02
|
||||
1.033731E+00 4.974463E-02
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
abe20c626d613e73ccb1a3f8468ad1b9aecca528afa9e8131a411d754eb86b8ab64a6fb1fdc9c0b8b8158ff7c82f548de5912041bf035aa5a2d4532cfe0c9510
|
||||
60a35864ad71646309d7f1687ba0826d4d53a5b2e8babf73614362645205484bad3c0e7bf605ec0b11cadf58474b2e3d0a97bf2d9297f9118682c37ff0269afd
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
k-combined:
|
||||
1.083030E+00 1.855038E-02
|
||||
1.055274E+00 1.715904E-02
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
c9f9e7211bfb2af58130bedfd64592d093b7bfa424953eba433ecf08940595a96b8de7a892f12d1ab465cebd8e5dd784114c1b1299b534ed329df92752c9ed1f
|
||||
0efba3dd7882fdd38756d0a8f01ff00d7a1abdaab6430b3f090f3339e552448453bbb733852b6bd6ff09608d923c282f168320f942fc2eb3a45610873c588734
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
k-combined:
|
||||
1.380785E-01 5.556526E-03
|
||||
1.033731E+00 4.974463E-02
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
ca8490e0e4549fed727ddc75b6d92cfe5162e11b905218a0afaa3ce2ee0763e2ff38074de27aaa678818624f49c5823650475dfa8f66f502a98fc03145399c0d
|
||||
6c437c3f9281c52a80a9b166971aa0f5db7ff8b6cf65c79b6d7bf294fad30cc7044f6a665cd9059f8580441bcbb581f7152ff5bccbc21fbcc407847ea6fe3306
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue