mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-25 12:35:29 -04:00
Fixed merge conflicts with develop
This commit is contained in:
commit
4e6aca6028
331 changed files with 6506 additions and 222815 deletions
21
.travis.yml
21
.travis.yml
|
|
@ -1,11 +1,21 @@
|
|||
sudo: false
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
- "3.4"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gfortran
|
||||
- g++
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/mpich_install
|
||||
- $HOME/hdf5_install
|
||||
- $HOME/phdf5_install
|
||||
|
||||
before_install:
|
||||
# ============== Handle Python third-party packages ==============
|
||||
- sudo apt-get update
|
||||
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
|
||||
wget https://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh;
|
||||
else
|
||||
|
|
@ -20,13 +30,12 @@ before_install:
|
|||
- conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION numpy scipy h5py
|
||||
- source activate test-environment
|
||||
|
||||
# ============== Install GCC, MPICH, HDF5, PHDF5 ==============
|
||||
- sudo apt-get install -qq -y gfortran g++
|
||||
# Install GCC, MPICH, HDF5, PHDF5
|
||||
- ./tests/travis_install.sh
|
||||
- export FC=gfortran
|
||||
- export MPI_DIR=$PWD/mpich_install
|
||||
- export PHDF5_DIR=$PWD/phdf5_install
|
||||
- export HDF5_DIR=$PWD/hdf5_install
|
||||
- export MPI_DIR=$HOME/mpich_install
|
||||
- export PHDF5_DIR=$HOME/phdf5_install
|
||||
- export HDF5_DIR=$HOME/hdf5_install
|
||||
|
||||
install: true
|
||||
|
||||
|
|
|
|||
|
|
@ -24,12 +24,17 @@ option(profile "Compile with profiling flags" OFF)
|
|||
option(debug "Compile with debug flags" OFF)
|
||||
option(optimize "Turn on all compiler optimization flags" OFF)
|
||||
option(verbose "Create verbose Makefiles" OFF)
|
||||
option(coverage "Compile with flags" OFF)
|
||||
option(coverage "Compile with coverage analysis flags" OFF)
|
||||
option(mpif08 "Use Fortran 2008 MPI interface" OFF)
|
||||
|
||||
if (verbose)
|
||||
set(CMAKE_VERBOSE_MAKEFILE on)
|
||||
endif()
|
||||
|
||||
# Maximum number of nested coordinates levels
|
||||
set(maxcoord 10 CACHE STRING "Maximum number of nested coordinate levels")
|
||||
add_definitions(-DMAX_COORD=${maxcoord})
|
||||
|
||||
#===============================================================================
|
||||
# MPI for distributed-memory parallelism / HDF5 for binary output
|
||||
#===============================================================================
|
||||
|
|
@ -51,6 +56,12 @@ elseif($ENV{FC} MATCHES "h5pfc$")
|
|||
set(HDF5_ENABLED TRUE)
|
||||
endif()
|
||||
|
||||
# Check for Fortran 2008 MPI interface
|
||||
if(MPI_ENABLED AND mpif08)
|
||||
message("-- Using Fortran 2008 MPI bindings")
|
||||
add_definitions(-DMPIF08)
|
||||
endif()
|
||||
|
||||
#===============================================================================
|
||||
# Set compile/link flags based on which compiler is being used
|
||||
#===============================================================================
|
||||
|
|
|
|||
|
|
@ -17,13 +17,18 @@ import sys, os
|
|||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
sys.path.insert(0, os.path.abspath('../sphinxext'))
|
||||
sys.path.insert(0, os.path.abspath('../..'))
|
||||
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['sphinx.ext.pngmath', 'sphinxcontrib.tikz', 'sphinx_numfig']
|
||||
extensions = ['sphinx.ext.autodoc',
|
||||
'sphinx.ext.napoleon',
|
||||
'sphinx.ext.pngmath',
|
||||
'sphinxcontrib.tikz',
|
||||
'sphinx_numfig']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
|
|
|||
|
|
@ -18,9 +18,7 @@ from the git repository as such:
|
|||
|
||||
.. code-block:: sh
|
||||
|
||||
git clone https://bitbucket.org/philexander/tikz.git
|
||||
cd tikz
|
||||
sudo python setup.py install
|
||||
sudo pip install https://bitbucket.org/philexander/tikz/get/HEAD.tar.gz
|
||||
|
||||
The Numfig_ package can be installed directly with pip:
|
||||
|
||||
|
|
|
|||
|
|
@ -125,8 +125,16 @@ program, subroutine, function, if, associate, etc. Emacs users should set the
|
|||
variables f90-if-indent, f90-do-indent, f90-continuation-indent,
|
||||
f90-type-indent, f90-associate-indent, and f90-program indent to 2.
|
||||
|
||||
Continuation lines should be indented by an extra 5 spaces. This is the default
|
||||
value of f90-continuation-indent in Emacs.
|
||||
Continuation lines should be indented by at least 5 spaces. They may be indented
|
||||
more in order to make the content match the context. For example, either of
|
||||
these are valid continuation indentations:
|
||||
|
||||
.. code-block:: fortran
|
||||
|
||||
local_xyz(1) = xyz(1) - (this % lower_left(1) + &
|
||||
(i_xyz(1) - HALF)*this % pitch(1))
|
||||
call which_data(scatt_type, get_scatt, get_nuscatt, get_chi_t, get_chi_p, &
|
||||
get_chi_d, scatt_order)
|
||||
|
||||
Whitespace in Expressions
|
||||
-------------------------
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ free to send a message to the User's Group `mailing list`_.
|
|||
methods/index
|
||||
usersguide/index
|
||||
devguide/index
|
||||
pythonapi/index
|
||||
publications
|
||||
license
|
||||
developers
|
||||
|
|
|
|||
|
|
@ -10,9 +10,8 @@ Overviews
|
|||
|
||||
- Paul K. Romano, Nicholas E. Horelik, Bryan R. Herman, Adam G. Nelson, Benoit
|
||||
Forget, and Kord Smith, "OpenMC: A State-of-the-Art Monte Carlo Code for
|
||||
Research and Development," *Proc. Joint International Conference on
|
||||
Supercomputing in Nuclear Applications and Monte Carlo*, Paris, France,
|
||||
Oct. 27--31 (2013). `<http://dx.doi.org/10.1051/snamc/201406016>`_
|
||||
Research and Development," *Ann. Nucl. Energy*, **82**, 90--97
|
||||
(2015). `<http://dx.doi.org/10.1016/j.anucene.2014.07.048>`_
|
||||
|
||||
- Paul K. Romano, Bryan R. Herman, Nicholas E. Horelik, Benoit Forget, Kord
|
||||
Smith, and Andrew R. Siegel, "Progress and Status of the OpenMC Monte Carlo
|
||||
|
|
|
|||
8
docs/source/pythonapi/ace.rst
Normal file
8
docs/source/pythonapi/ace.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_ace:
|
||||
|
||||
==========
|
||||
ACE Format
|
||||
==========
|
||||
|
||||
.. automodule:: openmc.ace
|
||||
:members:
|
||||
8
docs/source/pythonapi/cmfd.rst
Normal file
8
docs/source/pythonapi/cmfd.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_cmfd:
|
||||
|
||||
====
|
||||
CMFD
|
||||
====
|
||||
|
||||
.. automodule:: openmc.cmfd
|
||||
:members:
|
||||
8
docs/source/pythonapi/element.rst
Normal file
8
docs/source/pythonapi/element.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_element:
|
||||
|
||||
=======
|
||||
Element
|
||||
=======
|
||||
|
||||
.. automodule:: openmc.element
|
||||
:members:
|
||||
8
docs/source/pythonapi/executor.rst
Normal file
8
docs/source/pythonapi/executor.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_executor:
|
||||
|
||||
========
|
||||
Executor
|
||||
========
|
||||
|
||||
.. automodule:: openmc.executor
|
||||
:members:
|
||||
8
docs/source/pythonapi/filter.rst
Normal file
8
docs/source/pythonapi/filter.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_filter:
|
||||
|
||||
======
|
||||
Filter
|
||||
======
|
||||
|
||||
.. automodule:: openmc.filter
|
||||
:members:
|
||||
8
docs/source/pythonapi/geometry.rst
Normal file
8
docs/source/pythonapi/geometry.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_geometry:
|
||||
|
||||
========
|
||||
Geometry
|
||||
========
|
||||
|
||||
.. automodule:: openmc.geometry
|
||||
:members:
|
||||
32
docs/source/pythonapi/index.rst
Normal file
32
docs/source/pythonapi/index.rst
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
.. _pythonapi:
|
||||
|
||||
==========
|
||||
Python API
|
||||
==========
|
||||
|
||||
--------
|
||||
Contents
|
||||
--------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
ace
|
||||
cmfd
|
||||
element
|
||||
executor
|
||||
filter
|
||||
geometry
|
||||
material
|
||||
mesh
|
||||
nuclide
|
||||
opencg_compatible
|
||||
particle_restart
|
||||
plots
|
||||
settings
|
||||
statepoint
|
||||
summary
|
||||
surface
|
||||
tallies
|
||||
trigger
|
||||
universe
|
||||
8
docs/source/pythonapi/material.rst
Normal file
8
docs/source/pythonapi/material.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_material:
|
||||
|
||||
=========
|
||||
Materials
|
||||
=========
|
||||
|
||||
.. automodule:: openmc.material
|
||||
:members:
|
||||
8
docs/source/pythonapi/mesh.rst
Normal file
8
docs/source/pythonapi/mesh.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_mesh:
|
||||
|
||||
====
|
||||
Mesh
|
||||
====
|
||||
|
||||
.. automodule:: openmc.mesh
|
||||
:members:
|
||||
8
docs/source/pythonapi/nuclide.rst
Normal file
8
docs/source/pythonapi/nuclide.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_nuclide:
|
||||
|
||||
=======
|
||||
Nuclide
|
||||
=======
|
||||
|
||||
.. automodule:: openmc.nuclide
|
||||
:members:
|
||||
8
docs/source/pythonapi/opencg_compatible.rst
Normal file
8
docs/source/pythonapi/opencg_compatible.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_opencg_compatible:
|
||||
|
||||
====================
|
||||
OpenCG Compatibility
|
||||
====================
|
||||
|
||||
.. automodule:: openmc.opencg_compatible
|
||||
:members:
|
||||
8
docs/source/pythonapi/particle_restart.rst
Normal file
8
docs/source/pythonapi/particle_restart.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_particle_restart:
|
||||
|
||||
================
|
||||
Particle Restart
|
||||
================
|
||||
|
||||
.. automodule:: openmc.particle_restart
|
||||
:members:
|
||||
8
docs/source/pythonapi/plots.rst
Normal file
8
docs/source/pythonapi/plots.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_plots:
|
||||
|
||||
=====
|
||||
Plots
|
||||
=====
|
||||
|
||||
.. automodule:: openmc.plots
|
||||
:members:
|
||||
8
docs/source/pythonapi/settings.rst
Normal file
8
docs/source/pythonapi/settings.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_settings:
|
||||
|
||||
========
|
||||
Settings
|
||||
========
|
||||
|
||||
.. automodule:: openmc.settings
|
||||
:members:
|
||||
8
docs/source/pythonapi/statepoint.rst
Normal file
8
docs/source/pythonapi/statepoint.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_statepoint:
|
||||
|
||||
==========
|
||||
Statepoint
|
||||
==========
|
||||
|
||||
.. automodule:: openmc.statepoint
|
||||
:members:
|
||||
8
docs/source/pythonapi/summary.rst
Normal file
8
docs/source/pythonapi/summary.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_summary:
|
||||
|
||||
=======
|
||||
Summary
|
||||
=======
|
||||
|
||||
.. automodule:: openmc.summary
|
||||
:members:
|
||||
8
docs/source/pythonapi/surface.rst
Normal file
8
docs/source/pythonapi/surface.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_surface:
|
||||
|
||||
=======
|
||||
Surface
|
||||
=======
|
||||
|
||||
.. automodule:: openmc.surface
|
||||
:members:
|
||||
8
docs/source/pythonapi/tallies.rst
Normal file
8
docs/source/pythonapi/tallies.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_tallies:
|
||||
|
||||
=======
|
||||
Tallies
|
||||
=======
|
||||
|
||||
.. automodule:: openmc.tallies
|
||||
:members:
|
||||
8
docs/source/pythonapi/trigger.rst
Normal file
8
docs/source/pythonapi/trigger.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_trigger:
|
||||
|
||||
=======
|
||||
Trigger
|
||||
=======
|
||||
|
||||
.. automodule:: openmc.trigger
|
||||
:members:
|
||||
8
docs/source/pythonapi/universe.rst
Normal file
8
docs/source/pythonapi/universe.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.. _pythonapi_universe:
|
||||
|
||||
========
|
||||
Universe
|
||||
========
|
||||
|
||||
.. automodule:: openmc.universe
|
||||
:members:
|
||||
|
|
@ -441,24 +441,22 @@ attributes/sub-elements:
|
|||
has the following attributes:
|
||||
|
||||
:type:
|
||||
The type of spatial distribution. Valid options are "box" and "point". A
|
||||
"box" spatial distribution has coordinates sampled uniformly in a
|
||||
parallelepiped. A "point" spatial distribution has coordinates specified
|
||||
by a triplet.
|
||||
|
||||
The type of spatial distribution. Valid options are "box", "fission", and
|
||||
"point". A "box" spatial distribution has coordinates sampled uniformly in
|
||||
a parallelepiped. A "fission" spatial distribution samples locations from
|
||||
a "box" distribution but only locations in fissionable materials are
|
||||
accepted. A "point" spatial distribution has coordinates specified by a
|
||||
triplet.
|
||||
|
||||
*Default*: None
|
||||
|
||||
:parameters:
|
||||
For a "box" spatial distribution, ``parameters`` should be given as six
|
||||
real numbers, the first three of which specify the lower-left corner of a
|
||||
parallelepiped and the last three of which specify the upper-right
|
||||
corner. Source sites are sampled uniformly through that parallelepiped.
|
||||
|
||||
To filter a "box" spatial distribution by fissionable material, specify
|
||||
"fission" tag instead of "box". The ``parameters`` should be given as six
|
||||
real numbers, the first three of which specify the lower-left corner of a
|
||||
parallelepiped and the last three of which specify the upper-right
|
||||
corner. Source sites are sampled uniformly through that parallelepiped.
|
||||
For a "box" or "fission" spatial distribution, ``parameters`` should be
|
||||
given as six real numbers, the first three of which specify the lower-left
|
||||
corner of a parallelepiped and the last three of which specify the
|
||||
upper-right corner. Source sites are sampled uniformly through that
|
||||
parallelepiped.
|
||||
|
||||
For a "point" spatial distribution, ``parameters`` should be given as
|
||||
three real numbers which specify the (x,y,z) location of an isotropic
|
||||
|
|
@ -481,7 +479,7 @@ attributes/sub-elements:
|
|||
|
||||
:parameters:
|
||||
For an "isotropic" angular distribution, ``parameters`` should not be
|
||||
specified
|
||||
specified.
|
||||
|
||||
For a "monodirectional" angular distribution, ``parameters`` should be
|
||||
given as three real numbers which specify the angular cosines with respect
|
||||
|
|
@ -499,7 +497,7 @@ attributes/sub-elements:
|
|||
"watt", and "maxwell". The "monoenergetic" option produces source sites at
|
||||
a single energy. The "watt" option produces source sites whose energy is
|
||||
sampled from a Watt fission spectrum. The "maxwell" option produce source
|
||||
sites whose energy is sampled from a Maxwell fission spectrum
|
||||
sites whose energy is sampled from a Maxwell fission spectrum.
|
||||
|
||||
*Default*: watt
|
||||
|
||||
|
|
@ -605,8 +603,6 @@ survival biasing, otherwise known as implicit capture or absorption.
|
|||
|
||||
*Default*: false
|
||||
|
||||
.. _trace:
|
||||
|
||||
``<threads>`` Element
|
||||
---------------------
|
||||
|
||||
|
|
@ -615,6 +611,8 @@ a simulation. It has no attributes and accepts a positive integer value.
|
|||
|
||||
*Default*: None (Determined by environment variable :envvar:`OMP_NUM_THREADS`)
|
||||
|
||||
.. _trace:
|
||||
|
||||
``<trace>`` Element
|
||||
-------------------
|
||||
|
||||
|
|
@ -631,9 +629,9 @@ integers: the batch number, generation number, and particle number.
|
|||
|
||||
The ``<track>`` element specifies particles for which OpenMC will output binary
|
||||
files describing particle position at every step of its transport. This element
|
||||
should be followed by triplets of integers. Each triplet describes one particle
|
||||
. The integers in each triplet specify the batch number, generation number, and
|
||||
particle number, respectively.
|
||||
should be followed by triplets of integers. Each triplet describes one
|
||||
particle. The integers in each triplet specify the batch number, generation
|
||||
number, and particle number, respectively.
|
||||
|
||||
*Default*: None
|
||||
|
||||
|
|
@ -1224,8 +1222,8 @@ The ``<tally>`` element accepts the following sub-elements:
|
|||
The ``filter`` element has the following attributes/sub-elements:
|
||||
|
||||
:type:
|
||||
The type of the filter. Accepted options are "cell", "cellborn",
|
||||
"material", "universe", "energy", "energyout", "mesh", and
|
||||
The type of the filter. Accepted options are "cell", "cellborn",
|
||||
"material", "universe", "energy", "energyout", "mesh", and
|
||||
"distribcell".
|
||||
|
||||
:bins:
|
||||
|
|
@ -1307,24 +1305,25 @@ The ``<tally>`` element accepts the following sub-elements:
|
|||
physical quantities:
|
||||
|
||||
:flux:
|
||||
Total flux
|
||||
Total flux in particle-cm per source particle.
|
||||
|
||||
:total:
|
||||
Total reaction rate
|
||||
Total reaction rate in reactions per source particle.
|
||||
|
||||
:scatter:
|
||||
Total scattering rate. Can also be identified with the ``scatter-0``
|
||||
response type.
|
||||
response type. Units are reactions per source particle.
|
||||
|
||||
:absorption:
|
||||
Total absorption rate. This accounts for all reactions which do not
|
||||
produce secondary neutrons.
|
||||
produce secondary neutrons. Units are reactions per source particle.
|
||||
|
||||
:fission:
|
||||
Total fission rate
|
||||
Total fission rate in reactions per source particle.
|
||||
|
||||
:nu-fission:
|
||||
Total production of neutrons due to fission
|
||||
Total production of neutrons due to fission. Units are neutrons produced
|
||||
per source neutron.
|
||||
|
||||
:kappa-fission:
|
||||
The recoverable energy production rate due to fission. The recoverable
|
||||
|
|
@ -1333,51 +1332,55 @@ The ``<tally>`` element accepts the following sub-elements:
|
|||
total energies, and the total energy released by the delayed :math:`\beta`
|
||||
particles. The neutrino energy does not contribute to this response. The
|
||||
prompt and delayed :math:`\gamma`-rays are assumed to deposit their energy
|
||||
locally.
|
||||
locally. Units are MeV per source particle.
|
||||
|
||||
:scatter-N:
|
||||
Tally the N\ :sup:`th` \ scattering moment, where N is the Legendre
|
||||
expansion order of the change in particle angle :math:`\left(\mu\right)`.
|
||||
N must be between 0 and 10. As an example, tallying the
|
||||
2\ :sup:`nd` \ scattering moment would be specified as
|
||||
``<scores> scatter-2 </scores>``.
|
||||
N must be between 0 and 10. As an example, tallying the 2\ :sup:`nd` \
|
||||
scattering moment would be specified as ``<scores> scatter-2
|
||||
</scores>``. Units are reactions per source particle.
|
||||
|
||||
:scatter-PN:
|
||||
Tally all of the scattering moments from order 0 to N, where N is the
|
||||
Legendre expansion order of the change in particle angle
|
||||
:math:`\left(\mu\right)`. That is, ``scatter-P1`` is equivalent to
|
||||
requesting tallies of ``scatter-0`` and ``scatter-1``. Like for
|
||||
``scatter-N``, N must be between 0 and 10. As an example, tallying up
|
||||
to the 2\ :sup:`nd` \ scattering moment would be specified as
|
||||
``<scores> scatter-P2 </scores>``.
|
||||
``scatter-N``, N must be between 0 and 10. As an example, tallying up to
|
||||
the 2\ :sup:`nd` \ scattering moment would be specified as ``<scores>
|
||||
scatter-P2 </scores>``. Units are reactions per source particle.
|
||||
|
||||
:scatter-YN:
|
||||
``scatter-YN`` is similar to ``scatter-PN`` except an additional
|
||||
expansion is performed for the incoming particle direction
|
||||
``scatter-YN`` is similar to ``scatter-PN`` except an additional expansion
|
||||
is performed for the incoming particle direction
|
||||
:math:`\left(\Omega\right)` using the real spherical harmonics. This is
|
||||
useful for performing angular flux moment weighting of the scattering
|
||||
moments. Like ``scatter-PN``, ``scatter-YN`` will tally all of the
|
||||
moments from order 0 to N; N again must be between 0 and 10.
|
||||
moments. Like ``scatter-PN``, ``scatter-YN`` will tally all of the moments
|
||||
from order 0 to N; N again must be between 0 and 10. Units are reactions
|
||||
per source particle.
|
||||
|
||||
:nu-scatter, nu-scatter-N, nu-scatter-PN, nu-scatter-YN:
|
||||
These scores are similar in functionality to their ``scatter*``
|
||||
equivalents except the total production of neutrons due to
|
||||
scattering is scored vice simply the scattering rate. This accounts for
|
||||
multiplicity from (n,2n), (n,3n), and (n,4n) reactions.
|
||||
equivalents except the total production of neutrons due to scattering is
|
||||
scored vice simply the scattering rate. This accounts for multiplicity
|
||||
from (n,2n), (n,3n), and (n,4n) reactions. Units are neutrons produced per
|
||||
source particle.
|
||||
|
||||
:flux-YN:
|
||||
Spherical harmonic expansion of the direction of motion
|
||||
:math:`\left(\Omega\right)` of the total flux. This score will tally
|
||||
all of the harmonic moments of order 0 to N. N must be between 0 and 10.
|
||||
:math:`\left(\Omega\right)` of the total flux. This score will tally all
|
||||
of the harmonic moments of order 0 to N. N must be between 0
|
||||
and 10. Units are particle-cm per source particle.
|
||||
|
||||
:total-YN:
|
||||
The total reaction rate expanded via spherical harmonics about the
|
||||
direction of motion of the neutron, :math:`\Omega`.
|
||||
This score will tally all of the harmonic moments of order 0 to N. N must
|
||||
be between 0 and 10.
|
||||
be between 0 and 10. Units are reactions per source particle.
|
||||
|
||||
:current:
|
||||
Partial currents on the boundaries of each cell in a mesh.
|
||||
Partial currents on the boundaries of each cell in a mesh. Units are
|
||||
particles per source particle.
|
||||
|
||||
.. note::
|
||||
This score can only be used if a mesh filter has been
|
||||
|
|
@ -1385,7 +1388,7 @@ The ``<tally>`` element accepts the following sub-elements:
|
|||
other score.
|
||||
|
||||
:events:
|
||||
Number of scoring events
|
||||
Number of scoring events. Units are events per source particle.
|
||||
|
||||
:trigger:
|
||||
Precision trigger applied to all filter bins and nuclides for this tally.
|
||||
|
|
@ -1675,6 +1678,15 @@ The ``<begin>`` element controls what batch CMFD calculations should begin.
|
|||
|
||||
*Default*: 1
|
||||
|
||||
``<dhat_reset>`` Element
|
||||
------------------------
|
||||
|
||||
The ``<dhat_reset>`` element controls whether :math:`\widehat{D}` nonlinear
|
||||
CMFD parameters should be reset to zero before solving CMFD eigenproblem.
|
||||
It can be turned on with "true" and off with "false".
|
||||
|
||||
*Default*: false
|
||||
|
||||
``<display>`` Element
|
||||
---------------------
|
||||
|
||||
|
|
@ -1691,15 +1703,6 @@ The ``<display>`` element sets one additional CMFD output column. Options are:
|
|||
|
||||
*Default*: balance
|
||||
|
||||
``<dhat_reset>`` Element
|
||||
------------------------
|
||||
|
||||
The ``<dhat_reset>`` element controls whether :math:`\widehat{D}` nonlinear
|
||||
CMFD parameters should be reset to zero before solving CMFD eigenproblem.
|
||||
It can be turned on with "true" and off with "false".
|
||||
|
||||
*Default*: false
|
||||
|
||||
``<downscatter>`` Element
|
||||
-------------------------
|
||||
|
||||
|
|
@ -1743,11 +1746,11 @@ The CMFD mesh is a structured Cartesian mesh. This element has the following
|
|||
attributes/sub-elements:
|
||||
|
||||
:lower_left:
|
||||
The lower-left corner of the structured mesh. If only two coordinate are
|
||||
The lower-left corner of the structured mesh. If only two coordinates are
|
||||
given, it is assumed that the mesh is an x-y mesh.
|
||||
|
||||
:upper_right:
|
||||
The upper-right corner of the structrued mesh. If only two coordinate are
|
||||
The upper-right corner of the structrued mesh. If only two coordinates are
|
||||
given, it is assumed that the mesh is an x-y mesh.
|
||||
|
||||
:dimension:
|
||||
|
|
@ -1770,7 +1773,7 @@ attributes/sub-elements:
|
|||
|
||||
:map:
|
||||
An optional acceleration map can be specified to overlay on the coarse
|
||||
mesh spatial grid. If this option is used a ``1`` is used for a
|
||||
mesh spatial grid. If this option is used, a ``1`` is used for a
|
||||
non-accelerated region and a ``2`` is used for an accelerated region.
|
||||
For a simple 4x4 coarse mesh with a 2x2 fuel lattice surrounded by
|
||||
reflector, the map is:
|
||||
|
|
|
|||
|
|
@ -160,6 +160,13 @@ openmp
|
|||
Enables shared-memory parallelism using the OpenMP API. The Fortran compiler
|
||||
being used must support OpenMP.
|
||||
|
||||
coverage
|
||||
Compile and link code instrumented for coverage analysis. This is typically
|
||||
used in conjunction with gcov_.
|
||||
|
||||
maxcoord
|
||||
Maximum number of nested coordinate levels in geometry. Defaults to 10.
|
||||
|
||||
To set any of these options (e.g. turning on debug mode), the following form
|
||||
should be used:
|
||||
|
||||
|
|
@ -167,6 +174,8 @@ should be used:
|
|||
|
||||
cmake -Ddebug=on /path/to/openmc
|
||||
|
||||
.. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html
|
||||
|
||||
Compiling with MPI
|
||||
++++++++++++++++++
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ energy_filter = openmc.Filter(type='energy', bins=[0., 20.])
|
|||
energyout_filter = openmc.Filter(type='energyout', bins=[0., 20.])
|
||||
|
||||
# Instantiate the first Tally
|
||||
first_tally = openmc.Tally(tally_id=1, label='first tally')
|
||||
first_tally = openmc.Tally(tally_id=1, name='first tally')
|
||||
first_tally.add_filter(cell_filter)
|
||||
scores = ['total', 'scatter', 'nu-scatter', \
|
||||
'absorption', 'fission', 'nu-fission']
|
||||
|
|
@ -116,7 +116,7 @@ for score in scores:
|
|||
first_tally.add_score(score)
|
||||
|
||||
# Instantiate the second Tally
|
||||
second_tally = openmc.Tally(tally_id=2, label='second tally')
|
||||
second_tally = openmc.Tally(tally_id=2, name='second tally')
|
||||
second_tally.add_filter(cell_filter)
|
||||
second_tally.add_filter(energy_filter)
|
||||
scores = ['total', 'scatter', 'nu-scatter', \
|
||||
|
|
@ -125,7 +125,7 @@ for score in scores:
|
|||
second_tally.add_score(score)
|
||||
|
||||
# Instantiate the third Tally
|
||||
third_tally = openmc.Tally(tally_id=3, label='third tally')
|
||||
third_tally = openmc.Tally(tally_id=3, name='third tally')
|
||||
third_tally.add_filter(cell_filter)
|
||||
third_tally.add_filter(energy_filter)
|
||||
third_tally.add_filter(energyout_filter)
|
||||
|
|
|
|||
|
|
@ -1,13 +1,137 @@
|
|||
import numpy as np
|
||||
def check_type(name, value, expected_type, expected_iter_type=None):
|
||||
"""Ensure that an object is of an expected type. Optionally, if the object is
|
||||
iterable, check that each element is of a particular type.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Description of value being checked
|
||||
value : object
|
||||
Object to check type of
|
||||
expected_type : type
|
||||
type to check object against
|
||||
expected_iter_type : type or None, optional
|
||||
Expected type of each element in value, assuming it is iterable. If
|
||||
None, no check will be performed.
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(value, expected_type):
|
||||
msg = 'Unable to set {0} to {1} which is not of type {2}'.format(
|
||||
name, value, expected_type.__name__)
|
||||
raise ValueError(msg)
|
||||
|
||||
if expected_iter_type:
|
||||
for item in value:
|
||||
if not isinstance(item, expected_iter_type):
|
||||
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)
|
||||
|
||||
|
||||
def is_integer(val):
|
||||
return isinstance(val, (int, np.int32, np.int64))
|
||||
def check_length(name, value, length_min, length_max=None):
|
||||
"""Ensure that a sized object has length within a given range.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Description of value being checked
|
||||
value : collections.Sized
|
||||
Object to check length of
|
||||
length_min : int
|
||||
Minimum length of object
|
||||
length_max : int or None, optional
|
||||
Maximum length of object. If None, it is assumed object must be of
|
||||
length length_min.
|
||||
|
||||
"""
|
||||
|
||||
if length_max is None:
|
||||
if len(value) != length_min:
|
||||
msg = 'Unable to set {0} to {1} since it must be of ' \
|
||||
'length {2}'.format(name, value, length_min)
|
||||
raise ValueError(msg)
|
||||
elif not length_min <= len(value) <= length_max:
|
||||
if length_min == length_max:
|
||||
msg = 'Unable to set {0} to {1} since it must be of ' \
|
||||
'length {2}'.format(name, value, length_min)
|
||||
else:
|
||||
msg = 'Unable to set {0} to {1} since it must have length ' \
|
||||
'between {2} and {3}'.format(name, value, length_min,
|
||||
length_max)
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
def is_float(val):
|
||||
return isinstance(val, (float, np.float32, np.float64))
|
||||
def check_value(name, value, accepted_values):
|
||||
"""Ensure that an object's value is contained in a set of acceptable values.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Description of value being checked
|
||||
value : collections.Iterable
|
||||
Object to check
|
||||
accepted_values : collections.Container
|
||||
Container of acceptable values
|
||||
|
||||
def is_string(val):
|
||||
return isinstance(val, (str, np.str))
|
||||
"""
|
||||
|
||||
if value not in accepted_values:
|
||||
msg = 'Unable to set {0} to {1} since it is not in {2}'.format(
|
||||
name, value, accepted_values)
|
||||
raise ValueError(msg)
|
||||
|
||||
def check_less_than(name, value, maximum, equality=False):
|
||||
"""Ensure that an object's value is less than a given value.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Description of the value being checked
|
||||
value : object
|
||||
Object to check
|
||||
maximum : object
|
||||
Maximum value to check against
|
||||
equality : bool, optional
|
||||
Whether equality is allowed. Defaluts to False.
|
||||
|
||||
"""
|
||||
|
||||
if equality:
|
||||
if value > maximum:
|
||||
msg = 'Unable to set {0} to {1} since it is greater than ' \
|
||||
'{2}'.format(name, value, maximum)
|
||||
raise ValueError(msg)
|
||||
else:
|
||||
if value >= maximum:
|
||||
msg = 'Unable to set {0} to {1} since it is greater than ' \
|
||||
'or equal to {2}'.format(name, value, maximum)
|
||||
raise ValueError(msg)
|
||||
|
||||
def check_greater_than(name, value, minimum, equality=False):
|
||||
"""Ensure that an object's value is less than a given value.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Description of the value being checked
|
||||
value : object
|
||||
Object to check
|
||||
minimum : object
|
||||
Minimum value to check against
|
||||
equality : bool, optional
|
||||
Whether equality is allowed. Defaluts to False.
|
||||
|
||||
"""
|
||||
|
||||
if equality:
|
||||
if value < minimum:
|
||||
msg = 'Unable to set {0} to {1} since it is less than ' \
|
||||
'{2}'.format(name, value, minimum)
|
||||
raise ValueError(msg)
|
||||
else:
|
||||
if value <= minimum:
|
||||
msg = 'Unable to set {0} to {1} since it is less than ' \
|
||||
'or equal to {2}'.format(name, value, minimum)
|
||||
raise ValueError(msg)
|
||||
|
|
|
|||
746
openmc/cmfd.py
746
openmc/cmfd.py
|
|
@ -1,15 +1,77 @@
|
|||
"""This module can be used to specify parameters used for coarse mesh finite
|
||||
difference (CMFD) acceleration in OpenMC. CMFD was first proposed by [Smith]_
|
||||
and is widely used in accelerating neutron transport problems.
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
.. [Smith] K. Smith, "Nodal method storage reduction by non-linear
|
||||
iteration", *Trans. Am. Nucl. Soc.*, **44**, 265 (1983).
|
||||
|
||||
"""
|
||||
|
||||
from collections import Iterable
|
||||
from numbers import Real, Integral
|
||||
from xml.etree import ElementTree as ET
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
|
||||
from openmc.checkvalue import *
|
||||
from openmc.clean_xml import *
|
||||
from openmc.checkvalue import (check_type, check_length, check_value,
|
||||
check_greater_than, check_less_than)
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
class CMFDMesh(object):
|
||||
"""A structured Cartesian mesh used for Coarse Mesh Finite Difference (CMFD)
|
||||
acceleration.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
lower_left : Iterable of float
|
||||
The lower-left corner of the structured mesh. If only two coordinates are
|
||||
given, it is assumed that the mesh is an x-y mesh.
|
||||
upper_right : Iterable of float
|
||||
The upper-right corner of the structrued mesh. If only two coordinates
|
||||
are given, it is assumed that the mesh is an x-y mesh.
|
||||
dimension : Iterable of int
|
||||
The number of mesh cells in each direction.
|
||||
width : Iterable of float
|
||||
The width of mesh cells in each direction.
|
||||
energy : Iterable of float
|
||||
Energy bins in MeV, listed in ascending order (e.g. [0.0, 0.625e-7,
|
||||
20.0]) for CMFD tallies and acceleration. If no energy bins are listed,
|
||||
OpenMC automatically assumes a one energy group calculation over the
|
||||
entire energy range.
|
||||
albedo : Iterable of float
|
||||
Surface ratio of incoming to outgoing partial currents on global
|
||||
boundary conditions. They are listed in the following order: -x +x -y +y
|
||||
-z +z.
|
||||
map : Iterable of int
|
||||
An optional acceleration map can be specified to overlay on the coarse
|
||||
mesh spatial grid. If this option is used, a ``1`` is used for a
|
||||
non-accelerated region and a ``2`` is used for an accelerated region.
|
||||
For a simple 4x4 coarse mesh with a 2x2 fuel lattice surrounded by
|
||||
reflector, the map is:
|
||||
|
||||
::
|
||||
|
||||
[1, 1, 1, 1,
|
||||
1, 2, 2, 1,
|
||||
1, 2, 2, 1,
|
||||
1, 1, 1, 1]
|
||||
|
||||
Therefore a 2x2 system of equations is solved rather than a 4x4. This is
|
||||
extremely important to use in reflectors as neutrons will not contribute
|
||||
to any tallies far away from fission source neutron regions. A ``2``
|
||||
must be used to identify any fission source region.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self._lower_left = None
|
||||
self._upper_right = None
|
||||
self._dimension = None
|
||||
|
|
@ -18,625 +80,441 @@ class CMFDMesh(object):
|
|||
self._albedo = None
|
||||
self._map = None
|
||||
|
||||
|
||||
@property
|
||||
def lower_left(self):
|
||||
return self._lower_left
|
||||
|
||||
|
||||
@property
|
||||
def upper_right(self):
|
||||
return self._upper_right
|
||||
|
||||
|
||||
@property
|
||||
def dimension(self):
|
||||
return self._dimension
|
||||
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
return self._width
|
||||
|
||||
|
||||
@property
|
||||
def energy(self):
|
||||
return self._energy
|
||||
|
||||
|
||||
@property
|
||||
def albedo(self):
|
||||
return self._albedo
|
||||
|
||||
|
||||
@property
|
||||
def map(self):
|
||||
return self._mape
|
||||
|
||||
return self._map
|
||||
|
||||
@lower_left.setter
|
||||
def lower_left(self, lower_left):
|
||||
|
||||
if not isinstance(lower_left, (tuple, list, np.ndarray)):
|
||||
msg = 'Unable to set CMFD Mesh with lower_left {0} which is ' \
|
||||
'not a Python list, tuple or NumPy array'.format(lower_left)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif len(lower_left) != 2 and len(lower_left) != 3:
|
||||
msg = 'Unable to set CMFD Mesh with lower_left {0} since it ' \
|
||||
'must include 2 or 3 dimensions'.format(lower_left)
|
||||
raise ValueError(msg)
|
||||
|
||||
for coord in lower_left:
|
||||
|
||||
if not is_integer(coord) and not is_float(coord):
|
||||
msg = 'Unable to set CMFD Mesh with lower_left {0} which is ' \
|
||||
'not an integer or a floating point value'.format(coord)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('CMFD mesh lower_left', lower_left, Iterable, Real)
|
||||
check_length('CMFD mesh lower_left', lower_left, 2, 3)
|
||||
self._lower_left = lower_left
|
||||
|
||||
|
||||
@upper_right.setter
|
||||
def upper_right(self, upper_right):
|
||||
|
||||
if not isinstance(upper_right, (tuple, list, np.ndarray)):
|
||||
msg = 'Unable to set CMFD Mesh with upper_right {0} which is ' \
|
||||
'not a Python list, tuple or NumPy array'.format(upper_right)
|
||||
raise ValueError(msg)
|
||||
|
||||
if len(upper_right) != 2 and len(upper_right) != 3:
|
||||
msg = 'Unable to set CMFD Mesh with upper_right {0} since it ' \
|
||||
'must include 2 or 3 dimensions'.format(upper_right)
|
||||
raise ValueError(msg)
|
||||
|
||||
for coord in upper_right:
|
||||
|
||||
if not is_integer(coord) and not is_float(coord):
|
||||
msg = 'Unable to set CMFD Mesh with upper_right {0} which ' \
|
||||
'is not an integer or floating point value'.format(coord)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('CMFD mesh upper_right', upper_right, Iterable, Real)
|
||||
check_length('CMFD mesh upper_right', upper_right, 2, 3)
|
||||
self._upper_right = upper_right
|
||||
|
||||
|
||||
@dimension.setter
|
||||
def dimension(self, dimension):
|
||||
|
||||
if not isinstance(dimension, (tuple, list, np.ndarray)):
|
||||
msg = 'Unable to set CMFD Mesh with dimension {0} which is ' \
|
||||
'not a Python list, tuple or NumPy array'.format(dimension)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif len(dimension) != 2 and len(dimension) != 3:
|
||||
msg = 'Unable to set CMFD Mesh with dimension {0} since it ' \
|
||||
'must include 2 or 3 dimensions'.format(dimension)
|
||||
raise ValueError(msg)
|
||||
|
||||
for dim in dimension:
|
||||
|
||||
if not is_integer(dim):
|
||||
msg = 'Unable to set CMFD Mesh with dimension {0} which ' \
|
||||
'is a non-integer'.format(dim)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('CMFD mesh dimension', dimension, Iterable, Integral)
|
||||
check_length('CMFD mesh dimension', dimension, 2, 3)
|
||||
self._dimension = dimension
|
||||
|
||||
|
||||
@width.setter
|
||||
def width(self, width):
|
||||
|
||||
if not width is None:
|
||||
|
||||
if not isinstance(width, (tuple, list, np.ndarray)):
|
||||
msg = 'Unable to set CMFD Mesh with width {0} which ' \
|
||||
'is not a Python list, tuple or NumPy array'.format(width)
|
||||
raise ValueError(msg)
|
||||
|
||||
if len(width) != 2 and len(width) != 3:
|
||||
msg = 'Unable to set CMFD Mesh with width {0} since it must ' \
|
||||
'include 2 or 3 dimensions'.format(width)
|
||||
raise ValueError(msg)
|
||||
|
||||
for dim in width:
|
||||
|
||||
if not is_integer(dim) and not is_float(dim):
|
||||
msg = 'Unable to set CMFD Mesh with width {0} which is ' \
|
||||
'not an integer or floating point value'.format(width)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('CMFD mesh width', width, Iterable, Real)
|
||||
check_length('CMFD mesh width', width, 2, 3)
|
||||
self._width = width
|
||||
|
||||
|
||||
@energy.setter
|
||||
def energy(self, energy):
|
||||
|
||||
if not isinstance(energy, (tuple, list, np.ndarray)):
|
||||
msg = 'Unable to set CMFD Mesh energy to {0} which is not ' \
|
||||
'a Python tuple/list or NumPy array'.format(energy)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('CMFD mesh energy', energy, Iterable, Real)
|
||||
for e in energy:
|
||||
|
||||
if not is_integer(e) and not is_float(e):
|
||||
msg = 'Unable to set CMFD Mesh energy to {0} which is not ' \
|
||||
'an integer or floating point value'.format(e)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif e < 0:
|
||||
msg = 'Unable to set CMFD Mesh energy to {0} which is ' \
|
||||
'is a negative integer'.format(e)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_greater_than('CMFD mesh energy', e, 0, True)
|
||||
self._energy = energy
|
||||
|
||||
|
||||
@albedo.setter
|
||||
def albedo(self, albedo):
|
||||
|
||||
if not isinstance(albedo, (tuple, list, np.ndarray)):
|
||||
msg = 'Unable to set CMFD Mesh albedo to {0} which is not ' \
|
||||
'a Python tuple/list or NumPy array'.format(albedo)
|
||||
raise ValueError(msg)
|
||||
|
||||
if not len(albedo) == 6:
|
||||
msg = 'Unable to set CMFD Mesh albedo to {0} which is not ' \
|
||||
'length 6 for +/-x,y,z'.format(albedo)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('CMFD mesh albedo', albedo, Iterable, Real)
|
||||
check_length('CMFD mesh albedo', albedo, 6)
|
||||
for a in albedo:
|
||||
|
||||
if not is_integer(a) and not is_float(a):
|
||||
msg = 'Unable to set CMFD Mesh albedo to {0} which is not ' \
|
||||
'an integer or floating point value'.format(a)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif a < 0 or a > 1:
|
||||
msg = 'Unable to set CMFD Mesh albedo to {0} which is ' \
|
||||
'is not in [0,1]'.format(a)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_greater_than('CMFD mesh albedo', a, 0, True)
|
||||
check_less_than('CMFD mesh albedo', a, 1, True)
|
||||
self._albedo = albedo
|
||||
|
||||
|
||||
@map.setter
|
||||
def map(self, map):
|
||||
|
||||
if not isinstance(map, (tuple, list, np.ndarray)):
|
||||
msg = 'Unable to set CMFD Mesh map to {0} which is not ' \
|
||||
'a Python tuple/list or NumPy array'.format(map)
|
||||
raise ValueError(msg)
|
||||
|
||||
for m in map:
|
||||
|
||||
if m != 1 and m != 2:
|
||||
msg = 'Unable to set CMFD Mesh map to {0} which is ' \
|
||||
'is not 1 or 2'.format(m)
|
||||
raise ValueError(msg)
|
||||
|
||||
self._map = map
|
||||
|
||||
|
||||
def get_mesh_xml(self):
|
||||
def map(self, meshmap):
|
||||
check_type('CMFD mesh map', meshmap, Iterable, Integral)
|
||||
for m in meshmap:
|
||||
check_value('CMFD mesh map', m, [1, 2])
|
||||
self._map = meshmap
|
||||
|
||||
def _get_xml_element(self):
|
||||
element = ET.Element("mesh")
|
||||
|
||||
if len(self._lower_left) == 2:
|
||||
subelement = ET.SubElement(element, "lower_left")
|
||||
subelement.text = '{0} {1}'.format(self._lower_left[0],
|
||||
self._lower_left[1])
|
||||
else:
|
||||
subelement = ET.SubElement(element, "lower_left")
|
||||
subelement.text = '{0} {1} {2}'.format(self._lower_left[0],
|
||||
self._lower_left[1],
|
||||
self._lower_left[2])
|
||||
subelement = ET.SubElement(element, "lower_left")
|
||||
subelement.text = ' '.join(map(str, self._lower_left))
|
||||
|
||||
if not self._upper_right is None:
|
||||
if len(self._upper_right) == 2:
|
||||
subelement = ET.SubElement(element, "upper_right")
|
||||
subelement.text = '{0} {1}'.format(self._upper_right[0],
|
||||
self._upper_right[1])
|
||||
else:
|
||||
subelement = ET.SubElement(element, "upper_right")
|
||||
subelement.text = '{0} {1} {2}'.format(self._upper_right[0],
|
||||
self._upper_right[1],
|
||||
self._upper_right[2])
|
||||
if self.upper_right is not None:
|
||||
subelement = ET.SubElement(element, "upper_right")
|
||||
subelement.text = ' '.join(map(str, self.upper_right))
|
||||
|
||||
if len(self._dimension) == 2:
|
||||
subelement = ET.SubElement(element, "dimension")
|
||||
subelement.text = '{0} {1}'.format(self._dimension[0],
|
||||
self._dimension[1])
|
||||
else:
|
||||
subelement = ET.SubElement(element, "dimension")
|
||||
subelement.text = '{0} {1} {2}'.format(self._dimension[0],
|
||||
self._dimension[1],
|
||||
self._dimension[2])
|
||||
subelement = ET.SubElement(element, "dimension")
|
||||
subelement.text = ' '.join(map(str, self.dimension))
|
||||
|
||||
if not self._width is None:
|
||||
if len(self._width) == 2:
|
||||
subelement = ET.SubElement(element, "width")
|
||||
subelement.text = '{0} {1}'.format(self._width[0],
|
||||
self._width[1])
|
||||
else:
|
||||
subelement = ET.SubElement(element, "width")
|
||||
subelement.text = '{0} {1} {2}'.format(self._width[0],
|
||||
self._width[1],
|
||||
self._width[2])
|
||||
|
||||
if not self._energy is None:
|
||||
if self.width is not None:
|
||||
subelement = ET.SubElement(element, "width")
|
||||
subelement.text = ' '.join(map(str, self.width))
|
||||
|
||||
if self.energy is not None:
|
||||
subelement = ET.SubElement(element, "energy")
|
||||
subelement.text = ' '.join(map(str, self.energy))
|
||||
|
||||
energy = ''
|
||||
for e in self._energy:
|
||||
energy += '{0} '.format(e)
|
||||
|
||||
subelement.set("energy", energy.rstrip(' '))
|
||||
|
||||
if not self._albedo is None:
|
||||
|
||||
if self.albedo is not None:
|
||||
subelement = ET.SubElement(element, "albedo")
|
||||
subelement.text = ' '.join(map(str, self.albedo))
|
||||
|
||||
albedo = ''
|
||||
for a in self._albedo:
|
||||
albedo += '{0} '.format(a)
|
||||
|
||||
subelement.set("albedo", albedo.rstrip(' '))
|
||||
|
||||
if not self._map is None:
|
||||
|
||||
if self.map is not None:
|
||||
subelement = ET.SubElement(element, "map")
|
||||
|
||||
map = ''
|
||||
for m in self._map:
|
||||
map += '{0} '.format(m)
|
||||
|
||||
subelement.set("map", map.rstrip(' '))
|
||||
subelement.text = ' '.join(map(str, self.map))
|
||||
|
||||
return element
|
||||
|
||||
|
||||
class CMFDFile(object):
|
||||
"""Parameters that control the use of coarse-mesh finite difference acceleration
|
||||
in OpenMC. This corresponds directly to the cmfd.xml input file.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
begin : int
|
||||
Batch number at which CMFD calculations should begin
|
||||
dhat_reset : bool
|
||||
Indicate whether :math:`\widehat{D}` nonlinear CMFD parameters should be
|
||||
reset to zero before solving CMFD eigenproblem.
|
||||
display : {'balance', 'dominance', 'entropy', 'source'}
|
||||
Set one additional CMFD output column. Options are:
|
||||
|
||||
* "balance" - prints the RMS [%] of the resdiual from the neutron balance
|
||||
equation on CMFD tallies.
|
||||
* "dominance" - prints the estimated dominance ratio from the CMFD
|
||||
iterations.
|
||||
* "entropy" - prints the *entropy* of the CMFD predicted fission source.
|
||||
* "source" - prints the RMS [%] between the OpenMC fission source and
|
||||
CMFD fission source.
|
||||
downscatter : bool
|
||||
Indicate whether an effective downscatter cross section should be used
|
||||
when using 2-group CMFD.
|
||||
feedback : bool
|
||||
Indicate or not the CMFD diffusion result is used to adjust the weight
|
||||
of fission source neutrons on the next OpenMC batch. Defaults to False.
|
||||
gauss_seidel_tolerance : Iterable of float
|
||||
Two parameters specifying the absolute inner tolerance and the relative
|
||||
inner tolerance for Gauss-Seidel iterations when performing CMFD.
|
||||
ktol : float
|
||||
Tolerance on the eigenvalue when performing CMFD power iteration
|
||||
cmfd_mesh : CMFDMesh
|
||||
Structured mesh to be used for acceleration
|
||||
norm : float
|
||||
Normalization factor applied to the CMFD fission source distribution
|
||||
power_monitor : bool
|
||||
View convergence of power iteration during CMFD acceleration
|
||||
run_adjoint : bool
|
||||
Perform adjoint calculation on the last batch
|
||||
shift : float
|
||||
Optional Wielandt shift parameter for accelerating power iterations. By
|
||||
default, it is very large so there is effectively no impact.
|
||||
spectral : float
|
||||
Optional spectral radius that can be used to accelerate the convergence
|
||||
of Gauss-Seidel iterations during CMFD power iteration.
|
||||
stol : float
|
||||
Tolerance on the fission source when performing CMFD power iteration
|
||||
tally_reset : list of int
|
||||
List of batch numbers at which CMFD tallies should be reset
|
||||
write_matrices : bool
|
||||
Write sparse matrices that are used during CMFD acceleration (loss,
|
||||
production) to file
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self._active_flush = None
|
||||
self._begin = None
|
||||
self._dhat_reset = None
|
||||
self._display = None
|
||||
self._downscatter = None
|
||||
self._feedback = None
|
||||
self._inactive = None
|
||||
self._inactive_flush = None
|
||||
self._gauss_seidel_tolerance = None
|
||||
self._ktol = None
|
||||
self._cmfd_mesh = None
|
||||
self._norm = None
|
||||
self._num_flushes = None
|
||||
self._power_monitor = None
|
||||
self._run_adjoint = None
|
||||
self._shift = None
|
||||
self._spectral = None
|
||||
self._stol = None
|
||||
self._tally_reset = None
|
||||
self._write_matrices = None
|
||||
|
||||
self._cmfd_file = ET.Element("cmfd")
|
||||
self._cmfd_mesh_element = None
|
||||
|
||||
|
||||
@property
|
||||
def active_flush(self):
|
||||
return self._active_flush
|
||||
|
||||
|
||||
@property
|
||||
def begin(self):
|
||||
return self._begin
|
||||
|
||||
@property
|
||||
def dhat_reset(self):
|
||||
return self._dhat_reset
|
||||
|
||||
@property
|
||||
def display(self):
|
||||
return self._display
|
||||
|
||||
@property
|
||||
def downscatter(self):
|
||||
return self._downscatter
|
||||
|
||||
@property
|
||||
def feedback(self):
|
||||
return self._feedback
|
||||
|
||||
@property
|
||||
def gauss_seidel_tolerance(self):
|
||||
return self._gauss_seidel_tolerance
|
||||
|
||||
@property
|
||||
def inactive(self):
|
||||
return self._inactive
|
||||
|
||||
|
||||
@property
|
||||
def inactive_flush(self):
|
||||
return self._inactive_flush
|
||||
|
||||
def ktol(self):
|
||||
return self._ktol
|
||||
|
||||
@property
|
||||
def cmfd_mesh(self):
|
||||
return self._cmfd_mesh
|
||||
|
||||
|
||||
@property
|
||||
def norm(self):
|
||||
return self._norm
|
||||
|
||||
|
||||
@property
|
||||
def num_flushes(self):
|
||||
return self._num_flushes
|
||||
|
||||
|
||||
@property
|
||||
def power_monitor(self):
|
||||
return self._power_monitor
|
||||
|
||||
|
||||
@property
|
||||
def run_adjoint(self):
|
||||
return self._run_adjoint
|
||||
|
||||
@property
|
||||
def shift(self):
|
||||
return self._shift
|
||||
|
||||
@property
|
||||
def solver(self):
|
||||
return self._solver
|
||||
def spectral(self):
|
||||
return self._spectral
|
||||
|
||||
@property
|
||||
def stol(self):
|
||||
return self._stol
|
||||
|
||||
@property
|
||||
def tally_reset(self):
|
||||
return self._tally_reset
|
||||
|
||||
@property
|
||||
def write_matrices(self):
|
||||
return self._write_matrices
|
||||
|
||||
|
||||
@active_flush.setter
|
||||
def active_flush(self, active_flush):
|
||||
|
||||
if not is_integer(active_flush):
|
||||
msg = 'Unable to set CMFD active flush batch to a non-integer ' \
|
||||
'value {0}'.format(active_flush)
|
||||
raise ValueError(msg)
|
||||
|
||||
if active_flush < 0:
|
||||
msg = 'Unable to set CMFD active flush batch to a negative ' \
|
||||
'value {0}'.format(active_flush)
|
||||
raise ValueError(msg)
|
||||
|
||||
self._active_flush = active_flush
|
||||
|
||||
|
||||
@begin.setter
|
||||
def begin(self, begin):
|
||||
|
||||
if not is_integer(begin):
|
||||
msg = 'Unable to set CMFD begin batch to a non-integer ' \
|
||||
'value {0}'.format(begin)
|
||||
raise ValueError(msg)
|
||||
|
||||
if begin <= 0:
|
||||
msg = 'Unable to set CMFD begin batch batch to a negative ' \
|
||||
'value {0}'.format(begin)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('CMFD begin batch', begin, Integral)
|
||||
check_greater_than('CMFD begin batch', begin, 0)
|
||||
self._begin = begin
|
||||
|
||||
@dhat_reset.setter
|
||||
def dhat_reset(self, dhat_reset):
|
||||
check_type('CMFD Dhat reset', dhat_reset, bool)
|
||||
self._dhat_reset = dhat_reset
|
||||
|
||||
@display.setter
|
||||
def display(self, display):
|
||||
|
||||
if not is_string(display):
|
||||
msg = 'Unable to set CMFD display to a non-string ' \
|
||||
'value'.format(display)
|
||||
raise ValueError(msg)
|
||||
|
||||
if display not in ['balance', 'dominance', 'entropy', 'source']:
|
||||
msg = 'Unable to set CMFD display to {0} which is ' \
|
||||
'not an accepted value'.format(display)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('CMFD display', display, basestring)
|
||||
check_value('CMFD display', display,
|
||||
['balance', 'dominance', 'entropy', 'source'])
|
||||
self._display = display
|
||||
|
||||
@downscatter.setter
|
||||
def downscatter(self, downscatter):
|
||||
check_type('CMFD downscatter', downscatter, bool)
|
||||
self._downscatter = downscatter
|
||||
|
||||
@feedback.setter
|
||||
def feedback(self, feedback):
|
||||
|
||||
if not isinstance(feedback, bool):
|
||||
msg = 'Unable to set CMFD feedback to {0} which is ' \
|
||||
'a non-boolean value'.format(feedback)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('CMFD feedback', feedback, bool)
|
||||
self._feedback = feedback
|
||||
|
||||
@gauss_seidel_tolerance.setter
|
||||
def gauss_seidel_tolerance(self, gauss_seidel_tolerance):
|
||||
check_type('CMFD Gauss-Seidel tolerance', gauss_seidel_tolerance,
|
||||
Iterable, Real)
|
||||
check_length('Gauss-Seidel tolerance', gauss_seidel_tolerance, 2)
|
||||
self._gauss_seidel_tolerance = gauss_seidel_tolerance
|
||||
|
||||
@inactive.setter
|
||||
def inactive(self, inactive):
|
||||
|
||||
if not isinstance(inactive, bool):
|
||||
msg = 'Unable to set CMFD inactive batch to {0} which is ' \
|
||||
' a non-boolean value'.format(inactive)
|
||||
raise ValueError(msg)
|
||||
|
||||
self._inactive = inactive
|
||||
|
||||
|
||||
@inactive_flush.setter
|
||||
def inactive_flush(self, inactive_flush):
|
||||
|
||||
if not is_integer(inactive_flush):
|
||||
msg = 'Unable to set CMFD inactive flush batch to {0} which is ' \
|
||||
'a non-integer value'.format(inactive_flush)
|
||||
raise ValueError(msg)
|
||||
|
||||
if inactive_flush <= 0:
|
||||
msg = 'Unable to set CMFD inactive flush batch to {0} which is ' \
|
||||
'a negative value {0}'.format(inactive_flush)
|
||||
raise ValueError(msg)
|
||||
|
||||
self._inactive_flush = inactive_flush
|
||||
|
||||
@ktol.setter
|
||||
def ktol(self, ktol):
|
||||
check_type('CMFD eigenvalue tolerance', ktol, Real)
|
||||
self._ktol = ktol
|
||||
|
||||
@cmfd_mesh.setter
|
||||
def cmfd_mesh(self, mesh):
|
||||
|
||||
if not isinstance(mesh, CMFDMesh):
|
||||
msg = 'Unable to set CMFD mesh to {0} which is not a ' \
|
||||
'CMFDMesh object'.format(mesh)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('CMFD mesh', mesh, CMFDMesh)
|
||||
self._mesh = mesh
|
||||
|
||||
|
||||
@norm.setter
|
||||
def norm(self, norm):
|
||||
|
||||
if not is_integer(norm) and not is_float(norm):
|
||||
msg = 'Unable to set the CMFD norm to {0} which is not ' \
|
||||
'an integer or floating point value'.format(norm)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('CMFD norm', norm, Real)
|
||||
self._norm = norm
|
||||
|
||||
|
||||
@num_flushes.setter
|
||||
def num_flushes(self, num_flushes):
|
||||
|
||||
if not is_integer(num_flushes):
|
||||
msg = 'Unable to set the CMFD number of flushes to {0} ' \
|
||||
'which is not an integer value'.format(num_flushes)
|
||||
raise ValueError(msg)
|
||||
|
||||
if num_flushes < 0:
|
||||
msg = 'Unable to set CMFD number of flushes to a negative ' \
|
||||
'value {0}'.format(num_flushes)
|
||||
raise ValueError(msg)
|
||||
|
||||
self._num_flushes = num_flushes
|
||||
|
||||
|
||||
@power_monitor.setter
|
||||
def power_monitor(self, power_monitor):
|
||||
|
||||
if not isinstance(power_monitor, bool):
|
||||
msg = 'Unable to set CMFD power monitor to {0} which is a ' \
|
||||
'non-boolean value'.format(power_monitor)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('CMFD power monitor', power_monitor, bool)
|
||||
self._power_monitor = power_monitor
|
||||
|
||||
|
||||
@run_adjoint.setter
|
||||
def run_adjoint(self, run_adjoint):
|
||||
|
||||
if not isinstance(run_adjoint, bool):
|
||||
msg = 'Unable to set CMFD run adjoint to {0} which is a ' \
|
||||
'non-boolean value'.format(run_adjoint)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('CMFD run adjoint', run_adjoint, bool)
|
||||
self._run_adjoint = run_adjoint
|
||||
|
||||
@shift.setter
|
||||
def shift(self, shift):
|
||||
check_type('CMFD Wielandt shift', shift, Real)
|
||||
self._shift = shift
|
||||
|
||||
@spectral.setter
|
||||
def spectral(self, spectral):
|
||||
check_type('CMFD spectral radius', spectral, Real)
|
||||
self._spectral = spectral
|
||||
|
||||
@stol.setter
|
||||
def stol(self, stol):
|
||||
check_type('CMFD fission source tolerance', stol, Real)
|
||||
self._stol = stol
|
||||
|
||||
@tally_reset.setter
|
||||
def tally_reset(self, tally_reset):
|
||||
check_type('tally reset batches', tally_reset, Iterable, Integral)
|
||||
self._tally_reset = tally_reset
|
||||
|
||||
@write_matrices.setter
|
||||
def write_matrices(self, write_matrices):
|
||||
|
||||
if not isinstance(write_matrices, bool):
|
||||
msg = 'Unable to set CMFD write matrices to {0} which is a ' \
|
||||
'non-boolean value'.format(write_matrices)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('CMFD write matrices', write_matrices, bool)
|
||||
self._write_matrices = write_matrices
|
||||
|
||||
|
||||
def create_active_flush_subelement(self):
|
||||
|
||||
if not self._active_flush is None:
|
||||
element = ET.SubElement(self._cmfd_file, "active_flush")
|
||||
element.text = '{0}'.format(str(self._active_flush))
|
||||
|
||||
|
||||
def create_begin_subelement(self):
|
||||
|
||||
if not self._begin is None:
|
||||
def _create_begin_subelement(self):
|
||||
if self._begin is not None:
|
||||
element = ET.SubElement(self._cmfd_file, "begin")
|
||||
element.text = '{0}'.format(str(self._begin))
|
||||
element.text = str(self._begin)
|
||||
|
||||
def _create_dhat_reset_subelement(self):
|
||||
if self._dhat_reset is not None:
|
||||
element = ET.SubElement(self._cmfd_file, "dhat_reset")
|
||||
element.text = str(self._dhat_reset).lower()
|
||||
|
||||
def create_display_subelement(self):
|
||||
|
||||
if not self._display is None:
|
||||
def _create_display_subelement(self):
|
||||
if self._display is not None:
|
||||
element = ET.SubElement(self._cmfd_file, "display")
|
||||
element.text = '{0}'.format(str(self._display))
|
||||
element.text = str(self._display)
|
||||
|
||||
def _create_downscatter_subelement(self):
|
||||
if self._downscatter is not None:
|
||||
element = ET.SubElement(self._cmfd_file, "downscatter")
|
||||
element.text = str(self._downscatter).lower()
|
||||
|
||||
def create_feedback_subelement(self):
|
||||
|
||||
if not self._feedback is None:
|
||||
def _create_feedback_subelement(self):
|
||||
if self._feedback is not None:
|
||||
element = ET.SubElement(self._cmfd_file, "feeback")
|
||||
element.text = '{0}'.format(str(self._feedback).lower())
|
||||
element.text = str(self._feedback).lower()
|
||||
|
||||
def _create_gauss_seidel_tolerance_subelement(self):
|
||||
if self._gauss_seidel_tolerance is not None:
|
||||
element = ET.SubElement(self._cmfd_file, "gauss_seidel_tolerance")
|
||||
element.text = ' '.join(map(str, self._gauss_seidel_tolerance))
|
||||
|
||||
def create_inactive_subelement(self):
|
||||
def _create_ktol_subelement(self):
|
||||
if self._ktol is not None:
|
||||
element = ET.SubElement(self._ktol, "ktol")
|
||||
element.text = str(self._ktol)
|
||||
|
||||
if not self._inactive is None:
|
||||
element = ET.SubElement(self._cmfd_file, "inactive")
|
||||
element.text = '{0}'.format(str(self._inactive).lower())
|
||||
|
||||
|
||||
def create_inactive_flush_subelement(self):
|
||||
|
||||
if not self._inactive_flush is None:
|
||||
element = ET.SubElement(self._cmfd_file, "inactive_flush")
|
||||
element.text = '{0}'.format(str(self._inactive_flush))
|
||||
|
||||
|
||||
def create_mesh_subelement(self):
|
||||
|
||||
if not self._mesh is None:
|
||||
xml_element = self._mesh.get_mesh_xml()
|
||||
def _create_mesh_subelement(self):
|
||||
if self._mesh is not None:
|
||||
xml_element = self._mesh._get_xml_element()
|
||||
self._cmfd_file.append(xml_element)
|
||||
|
||||
|
||||
def create_norm_subelement(self):
|
||||
|
||||
if not self._num_flushes is None:
|
||||
def _create_norm_subelement(self):
|
||||
if self._norm is not None:
|
||||
element = ET.SubElement(self._cmfd_file, "norm")
|
||||
element.text = '{0}'.format(str(self._norm))
|
||||
element.text = str(self._norm)
|
||||
|
||||
|
||||
def create_num_flushes_subelement(self):
|
||||
|
||||
if not self._num_flushes is None:
|
||||
element = ET.SubElement(self._cmfd_file, "num_flushes")
|
||||
element.text = '{0}'.format(str(self._num_flushes))
|
||||
|
||||
|
||||
def create_power_monitor_subelement(self):
|
||||
|
||||
if not self._power_monitor is None:
|
||||
def _create_power_monitor_subelement(self):
|
||||
if self._power_monitor is not None:
|
||||
element = ET.SubElement(self._cmfd_file, "power_monitor")
|
||||
element.text = '{0}'.format(str(self._power_monitor).lower())
|
||||
element.text = str(self._power_monitor).lower()
|
||||
|
||||
|
||||
def create_run_adjoint_subelement(self):
|
||||
|
||||
if not self._run_adjoint is None:
|
||||
def _create_run_adjoint_subelement(self):
|
||||
if self._run_adjoint is not None:
|
||||
element = ET.SubElement(self._cmfd_file, "run_adjoint")
|
||||
element.text = '{0}'.format(str(self._run_adjoint).lower())
|
||||
element.text = str(self._run_adjoint).lower()
|
||||
|
||||
def _create_shift_subelement(self):
|
||||
if self._shift is not None:
|
||||
element = ET.SubElement(self._shift, "shift")
|
||||
element.text = str(self._shift)
|
||||
|
||||
def create_write_matrices_subelement(self):
|
||||
def _create_spectral_subelement(self):
|
||||
if self._spectral is not None:
|
||||
element = ET.SubElement(self._spectral, "spectral")
|
||||
element.text = str(self._spectral)
|
||||
|
||||
if not self._write_matrices is None:
|
||||
def _create_stol_subelement(self):
|
||||
if self._stol is not None:
|
||||
element = ET.SubElement(self._stol, "stol")
|
||||
element.text = str(self._stol)
|
||||
|
||||
def _create_tally_reset_subelement(self):
|
||||
if self._tally_reset is not None:
|
||||
element = ET.SubElement(self._tally_reset, "tally_reset")
|
||||
element.text = ' '.join(map(str, self._tally_reset))
|
||||
|
||||
def _create_write_matrices_subelement(self):
|
||||
if self._write_matrices is not None:
|
||||
element = ET.SubElement(self._cmfd_file, "write_matrices")
|
||||
element.text = '{0}'.format(str(self._write_matrices).lower())
|
||||
|
||||
element.text = str(self._write_matrices).lower()
|
||||
|
||||
def export_to_xml(self):
|
||||
"""Create a cmfd.xml file using the class data that can be used for an OpenMC
|
||||
simulation.
|
||||
|
||||
self.create_active_flush_subelement()
|
||||
self.create_begin_subelement()
|
||||
self.create_display_subelement()
|
||||
self.create_feedback_subelement()
|
||||
self.create_inactive_subelement()
|
||||
self.create_inactive_flush_subelement()
|
||||
self.create_mesh_subelement()
|
||||
self.create_norm_subelement()
|
||||
self.create_num_flushes_subelement()
|
||||
self.create_power_monitor_subelement()
|
||||
self.create_run_adjoint_subelement()
|
||||
self.create_write_matrices_subelement()
|
||||
"""
|
||||
|
||||
self._create_begin_subelement()
|
||||
self._create_dhat_reset_subelement()
|
||||
self._create_display_subelement()
|
||||
self._create_downscatter_subelement()
|
||||
self._create_feedback_subelement()
|
||||
self._create_gauss_seidel_tolerance_subelement()
|
||||
self._create_ktol_subelement()
|
||||
self._create_mesh_subelement()
|
||||
self._create_norm_subelement()
|
||||
self._create_power_monitor_subelement()
|
||||
self._create_run_adjoint_subelement()
|
||||
self._create_shift_subelement()
|
||||
self._create_spectral_subelement()
|
||||
self._create_stol_subelement()
|
||||
self._create_tally_reset_subelement()
|
||||
self._create_write_matrices_subelement()
|
||||
|
||||
# Clean the indentation in the file to be user-readable
|
||||
clean_xml_indentation(self._cmfd_file)
|
||||
|
|
|
|||
|
|
@ -1,79 +1,78 @@
|
|||
from openmc.checkvalue import *
|
||||
import sys
|
||||
|
||||
from openmc.checkvalue import check_type
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
class Element(object):
|
||||
"""A natural element used in a material via <element>. Internally, OpenMC will
|
||||
expand the natural element into isotopes based on the known natural
|
||||
abundances.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Chemical symbol of the element, e.g. Pu
|
||||
xs : str
|
||||
Cross section identifier, e.g. 71c
|
||||
|
||||
Attributes
|
||||
----------
|
||||
name : str
|
||||
Chemical symbol of the element, e.g. Pu
|
||||
xs : str
|
||||
Cross section identifier, e.g. 71c
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, name='', xs=None):
|
||||
|
||||
# Initialize class attributes
|
||||
self._name = ''
|
||||
self._xs = None
|
||||
|
||||
# Set the Material class attributes
|
||||
# Set class attributes
|
||||
self.name = name
|
||||
|
||||
if not xs is None:
|
||||
if xs is not None:
|
||||
self.xs = xs
|
||||
|
||||
|
||||
def __eq__(self, element2):
|
||||
|
||||
# Check type
|
||||
if not isinstance(element2, Element):
|
||||
return False
|
||||
|
||||
# Check name
|
||||
# Check name and xs
|
||||
if self._name != element2._name:
|
||||
return False
|
||||
|
||||
# Check xs
|
||||
elif self._xs != element2._xs:
|
||||
return False
|
||||
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def __hash__(self):
|
||||
hashable = []
|
||||
hashable.append(self._name)
|
||||
hashable.append(self._xs)
|
||||
return hash(tuple(hashable))
|
||||
|
||||
return hash((self._name, self._xs))
|
||||
|
||||
@property
|
||||
def xs(self):
|
||||
return self._xs
|
||||
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
|
||||
@xs.setter
|
||||
def xs(self, xs):
|
||||
|
||||
if not is_string(xs):
|
||||
msg = 'Unable to set cross-section identifier xs for Element ' \
|
||||
'with a non-string value {0}'.format(xs)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('cross section identifier', xs, basestring)
|
||||
self._xs = xs
|
||||
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
|
||||
if not is_string(name):
|
||||
msg = 'Unable to set name for Element with a non-string ' \
|
||||
'value {0}'.format(name)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('name', name, basestring)
|
||||
self._name = name
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
string = 'Element - {0}\n'.format(self._name)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tXS', '=\t', self._xs)
|
||||
return string
|
||||
|
|
|
|||
|
|
@ -1,83 +1,128 @@
|
|||
from __future__ import print_function
|
||||
import subprocess
|
||||
from numbers import Integral
|
||||
import os
|
||||
import sys
|
||||
|
||||
from openmc.checkvalue import *
|
||||
from openmc.checkvalue import check_type
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
class Executor(object):
|
||||
"""Control execution of OpenMC
|
||||
|
||||
Attributes
|
||||
----------
|
||||
working_directory : str
|
||||
Path to working directory to run in
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._working_directory = '.'
|
||||
|
||||
|
||||
def _run_openmc(self, command, output):
|
||||
|
||||
# Launch a subprocess to run OpenMC
|
||||
p = subprocess.Popen(command, shell=True,
|
||||
p = subprocess.Popen(command, shell=True,
|
||||
cwd=self._working_directory,
|
||||
stdout=subprocess.PIPE)
|
||||
|
||||
# Capture and re-print OpenMC output in real-time
|
||||
while (True and output):
|
||||
line = p.stdout.readline()
|
||||
print(line),
|
||||
print(line, end='')
|
||||
|
||||
# If OpenMC is finished, break loop
|
||||
if line == '' and p.poll() != None:
|
||||
if not line and p.poll() != None:
|
||||
break
|
||||
|
||||
# Return the returncode (integer, zero if no problems encountered)
|
||||
return p.returncode
|
||||
|
||||
@property
|
||||
def working_directory(self):
|
||||
return self._working_directory
|
||||
|
||||
|
||||
@working_directory.setter
|
||||
def working_directory(self, working_directory):
|
||||
|
||||
if not is_string(working_directory):
|
||||
msg = 'Unable to set Executor\'s working directory to {0} ' \
|
||||
'since it is not a string'.format(working_directory)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif not os.path.isdir(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)
|
||||
|
||||
self._working_directory = working_directory
|
||||
|
||||
def plot_geometry(self, output=True, openmc_exec='openmc'):
|
||||
"""Run OpenMC in plotting mode"""
|
||||
|
||||
def plot_geometry(self, output=True):
|
||||
self._run_openmc('openmc -p', output)
|
||||
|
||||
return self._run_openmc(openmc_exec + ' -p', output)
|
||||
|
||||
def run_simulation(self, particles=None, threads=None,
|
||||
geometry_debug=False, restart_file=None,
|
||||
tracks=False, mpi_procs=1, output=True):
|
||||
tracks=False, mpi_procs=1, output=True,
|
||||
openmc_exec='openmc', mpi_exec=None):
|
||||
"""Run an OpenMC simulation.
|
||||
|
||||
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
|
||||
|
||||
"""
|
||||
|
||||
post_args = ' '
|
||||
pre_args = ''
|
||||
|
||||
if is_integer(particles) and particles > 0:
|
||||
if isinstance(particles, Integral) and particles > 0:
|
||||
post_args += '-n {0} '.format(particles)
|
||||
|
||||
if is_integer(threads) and threads > 0:
|
||||
if isinstance(threads, Integral) and threads > 0:
|
||||
post_args += '-s {0} '.format(threads)
|
||||
|
||||
if geometry_debug:
|
||||
post_args += '-g '
|
||||
|
||||
if is_string(restart_file):
|
||||
if isinstance(restart_file, basestring):
|
||||
post_args += '-r {0} '.format(restart_file)
|
||||
|
||||
if tracks:
|
||||
post_args += '-t'
|
||||
|
||||
if is_integer(mpi_procs) and mpi_procs > 1:
|
||||
pre_args += 'mpirun -n {0} '.format(mpi_procs)
|
||||
if isinstance(mpi_procs, Integral) and mpi_procs > 1:
|
||||
np_present = True
|
||||
else:
|
||||
np_present = False
|
||||
|
||||
command = pre_args + 'openmc ' + post_args
|
||||
if mpi_exec is not None and isinstance(mpi_exec, basestring):
|
||||
mpi_exec_present = True
|
||||
else:
|
||||
mpi_exec_present = False
|
||||
|
||||
self._run_openmc(command, output)
|
||||
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)
|
||||
|
|
|
|||
160
openmc/filter.py
160
openmc/filter.py
|
|
@ -1,15 +1,38 @@
|
|||
from collections import Iterable
|
||||
import copy
|
||||
from numbers import Real, Integral
|
||||
|
||||
import numpy as np
|
||||
|
||||
from openmc import Mesh
|
||||
from openmc.checkvalue import *
|
||||
from openmc.constants import *
|
||||
|
||||
from openmc.checkvalue import check_type
|
||||
|
||||
class Filter(object):
|
||||
"""A filter used to constrain a tally to a specific criterion, e.g. only tally
|
||||
events when the particle is in a certain cell and energy range.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
type : str
|
||||
The type of the tally filter. Acceptable values are "universe",
|
||||
"material", "cell", "cellborn", "surface", "mesh", "energy",
|
||||
"energyout", and "distribcell".
|
||||
bins : int or Iterable of int or Iterable of float
|
||||
The bins for the filter. This takes on different meaning for different
|
||||
filters.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
type : str
|
||||
The type of the tally filter.
|
||||
bins : int or Iterable of int or Iterable of float
|
||||
The bins for the filter
|
||||
|
||||
"""
|
||||
|
||||
# Initialize Filter class attributes
|
||||
def __init__(self, type=None, bins=None):
|
||||
|
||||
self.type = type
|
||||
self._num_bins = 0
|
||||
self.bins = bins
|
||||
|
|
@ -17,9 +40,7 @@ class Filter(object):
|
|||
self._offset = -1
|
||||
self._stride = None
|
||||
|
||||
|
||||
def __eq__(self, filter2):
|
||||
|
||||
# Check type
|
||||
if self._type != filter2._type:
|
||||
return False
|
||||
|
|
@ -35,21 +56,14 @@ class Filter(object):
|
|||
else:
|
||||
return True
|
||||
|
||||
|
||||
def __hash__(self):
|
||||
hashable = []
|
||||
hashable.append(self._type)
|
||||
hashable.append(self._bins)
|
||||
return hash(tuple(hashable))
|
||||
|
||||
return hash((self._type, self._bins))
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
|
||||
existing = memo.get(id(self))
|
||||
|
||||
# If this is the first time we have tried to copy this object, create a copy
|
||||
if existing is None:
|
||||
|
||||
clone = type(self).__new__(type(self))
|
||||
clone._type = self._type
|
||||
clone._bins = copy.deepcopy(self._bins, memo)
|
||||
|
|
@ -66,64 +80,52 @@ class Filter(object):
|
|||
else:
|
||||
return existing
|
||||
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self._type
|
||||
|
||||
|
||||
@property
|
||||
def bins(self):
|
||||
return self._bins
|
||||
|
||||
|
||||
@property
|
||||
def num_bins(self):
|
||||
return self._num_bins
|
||||
|
||||
|
||||
@property
|
||||
def mesh(self):
|
||||
return self._mesh
|
||||
|
||||
|
||||
@property
|
||||
def offset(self):
|
||||
return self._offset
|
||||
|
||||
|
||||
@property
|
||||
def stride(self):
|
||||
return self._stride
|
||||
|
||||
|
||||
@type.setter
|
||||
def type(self, type):
|
||||
|
||||
if type is None:
|
||||
self._type = type
|
||||
|
||||
elif not type in FILTER_TYPES.values():
|
||||
elif type not in FILTER_TYPES.values():
|
||||
msg = 'Unable to set Filter type to "{0}" since it is not one ' \
|
||||
'of the supported types'.format(type)
|
||||
raise ValueError(msg)
|
||||
|
||||
self._type = type
|
||||
|
||||
|
||||
@bins.setter
|
||||
def bins(self, bins):
|
||||
|
||||
if bins is None:
|
||||
self.num_bins = 0
|
||||
|
||||
elif self._type is None:
|
||||
msg = 'Unable to set bins for Filter to "{0}" since ' \
|
||||
'the Filter type has not yet been set'.format(bins)
|
||||
raise ValueError(msg)
|
||||
|
||||
# If the bin edge is a single value, it is a Cell, Material, etc. ID
|
||||
if not isinstance(bins, (tuple, list, np.ndarray)):
|
||||
if not isinstance(bins, Iterable):
|
||||
bins = [bins]
|
||||
|
||||
# If the bins are in a collection, convert it to a list
|
||||
|
|
@ -132,30 +134,23 @@ class Filter(object):
|
|||
|
||||
if self._type in ['cell', 'cellborn', 'surface', 'material',
|
||||
'universe', 'distribcell']:
|
||||
|
||||
for edge in bins:
|
||||
|
||||
if not is_integer(edge):
|
||||
if not isinstance(edge, Integral):
|
||||
msg = 'Unable to add bin "{0}" to a {1} Filter since ' \
|
||||
'it is a non-integer'.format(edge, self._type)
|
||||
'it is not an integer'.format(edge, self._type)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif edge < 0:
|
||||
msg = 'Unable to add bin "{0}" to a {1} Filter since ' \
|
||||
'it is a negative integer'.format(edge, self._type)
|
||||
'it is negative'.format(edge, self._type)
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
elif self._type in ['energy', 'energyout']:
|
||||
|
||||
for edge in bins:
|
||||
|
||||
if not is_integer(edge) and not is_float(edge):
|
||||
if not isinstance(edge, Real):
|
||||
msg = 'Unable to add bin edge "{0}" to a {1} Filter ' \
|
||||
'since it is a non-integer or floating point ' \
|
||||
'value'.format(edge, self._type)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif edge < 0.:
|
||||
msg = 'Unable to add bin edge "{0}" to a {1} Filter ' \
|
||||
'since it is a negative value'.format(edge, self._type)
|
||||
|
|
@ -163,27 +158,22 @@ class Filter(object):
|
|||
|
||||
# Check that bin edges are monotonically increasing
|
||||
for index in range(len(bins)):
|
||||
|
||||
if index > 0 and bins[index] < bins[index-1]:
|
||||
msg = 'Unable to add bin edges "{0}" to a {1} Filter ' \
|
||||
'since they are not monotonically ' \
|
||||
'increasing'.format(bins, self._type)
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
# mesh filters
|
||||
elif self._type == 'mesh':
|
||||
|
||||
if not len(bins) == 1:
|
||||
msg = 'Unable to add bins "{0}" to a mesh Filter since ' \
|
||||
'only a single mesh can be used per tally'.format(bins)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif not is_integer(bins[0]):
|
||||
elif not isinstance(bins[0], Integral):
|
||||
msg = 'Unable to add bin "{0}" to mesh Filter since it ' \
|
||||
'is a non-integer'.format(bins[0])
|
||||
raise ValueError(msg)
|
||||
|
||||
elif bins[0] < 0:
|
||||
msg = 'Unable to add bin "{0}" to mesh Filter since it ' \
|
||||
'is a negative integer'.format(bins[0])
|
||||
|
|
@ -192,12 +182,10 @@ class Filter(object):
|
|||
# If all error checks passed, add bin edges
|
||||
self._bins = bins
|
||||
|
||||
|
||||
# FIXME
|
||||
@num_bins.setter
|
||||
def num_bins(self, num_bins):
|
||||
|
||||
if not is_integer(num_bins) or num_bins < 0:
|
||||
if not isinstance(num_bins, Integral) or num_bins < 0:
|
||||
msg = 'Unable to set the number of bins "{0}" for a {1} Filter ' \
|
||||
'since it is not a positive ' \
|
||||
'integer'.format(num_bins, self._type)
|
||||
|
|
@ -205,39 +193,22 @@ class Filter(object):
|
|||
|
||||
self._num_bins = num_bins
|
||||
|
||||
|
||||
@mesh.setter
|
||||
def mesh(self, mesh):
|
||||
|
||||
if not isinstance(mesh, Mesh):
|
||||
msg = 'Unable to set Mesh to "{0}" for Filter since it is not a ' \
|
||||
'Mesh object'.format(mesh)
|
||||
raise ValueError(msg)
|
||||
check_type('filter mesh', mesh, Mesh)
|
||||
|
||||
self._mesh = mesh
|
||||
self.type = 'mesh'
|
||||
self.bins = self._mesh._id
|
||||
|
||||
|
||||
@offset.setter
|
||||
def offset(self, offset):
|
||||
|
||||
if not is_integer(offset):
|
||||
msg = 'Unable to set offset "{0}" for a {1} Filter since it is a ' \
|
||||
'non-integer value'.format(offset, self._type)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('filter offset', offset, Integral)
|
||||
self._offset = offset
|
||||
|
||||
|
||||
@stride.setter
|
||||
def stride(self, stride):
|
||||
|
||||
if not is_integer(stride):
|
||||
msg = 'Unable to set stride "{0}" for a {1} Filter since it is a ' \
|
||||
'non-integer value'.format(stride, self._type)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('filter stride', stride, Integral)
|
||||
if stride < 0:
|
||||
msg = 'Unable to set stride "{0}" for a {1} Filter since it is a ' \
|
||||
'negative value'.format(stride, self._type)
|
||||
|
|
@ -245,8 +216,20 @@ class Filter(object):
|
|||
|
||||
self._stride = stride
|
||||
|
||||
|
||||
def can_merge(self, filter):
|
||||
"""Determine if filter can be merged with another.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filter : Filter
|
||||
Filter to compare with
|
||||
|
||||
Returns
|
||||
-------
|
||||
bool
|
||||
Whether the filter can be merged
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(filter, Filter):
|
||||
return False
|
||||
|
|
@ -270,8 +253,20 @@ class Filter(object):
|
|||
else:
|
||||
return True
|
||||
|
||||
|
||||
def merge(self, filter):
|
||||
"""Merge this filter with another.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filter : Filter
|
||||
Filter to merge with
|
||||
|
||||
Returns
|
||||
-------
|
||||
merged_filter : Filter
|
||||
Filter resulting from the merge
|
||||
|
||||
"""
|
||||
|
||||
if not self.can_merge(filter):
|
||||
msg = 'Unable to merge {0} with {1} filters'.format(self._type, filter._type)
|
||||
|
|
@ -287,33 +282,30 @@ class Filter(object):
|
|||
|
||||
return merged_filter
|
||||
|
||||
|
||||
def get_bin_index(self, filter_bin):
|
||||
"""Returns the index in the Filter for some bin.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filter_bin : int, tuple
|
||||
The bin is the integer ID for 'material', 'surface', 'cell',
|
||||
'cellborn', and 'universe' Filters. The bin is an integer for
|
||||
the cell instance ID for 'distribcell' Filters. The bin is
|
||||
a 2-tuple of floats for 'energy' and 'energyout' filters
|
||||
corresponding to the energy boundaries of the bin of interest.
|
||||
The bin is a (x,y,z) 3-tuple for 'mesh' filters corresponding to
|
||||
the mesh cell of interest.
|
||||
|
||||
filter_bin : int or tuple
|
||||
The bin is the integer ID for 'material', 'surface', 'cell',
|
||||
'cellborn', and 'universe' Filters. The bin is an integer for the
|
||||
cell instance ID for 'distribcell' Filters. The bin is a 2-tuple of
|
||||
floats for 'energy' and 'energyout' filters corresponding to the
|
||||
energy boundaries of the bin of interest. The bin is a (x,y,z)
|
||||
3-tuple for 'mesh' filters corresponding to the mesh cell of
|
||||
interest.
|
||||
|
||||
Returns
|
||||
-------
|
||||
filter_index : int
|
||||
The index in the Tally data array for this filter bin.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
# FIXME: This does not work for distribcells!!!
|
||||
|
||||
try:
|
||||
# Filter bins for a mesh are an (x,y,z) tuple
|
||||
if self.type == 'mesh':
|
||||
|
||||
# Convert (x,y,z) to a single bin -- this is similar to
|
||||
# subroutine mesh_indices_to_bin in openmc/src/mesh.F90.
|
||||
if (len(self.mesh.dimension) == 3):
|
||||
|
|
@ -350,9 +342,7 @@ class Filter(object):
|
|||
|
||||
return filter_index
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
string = 'Filter\n'
|
||||
string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._type)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tBins', '=\t', self._bins)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from xml.etree import ElementTree as ET
|
|||
|
||||
import openmc
|
||||
from openmc.clean_xml import *
|
||||
|
||||
from openmc.checkvalue import check_type
|
||||
|
||||
def reset_auto_ids():
|
||||
openmc.reset_auto_material_id()
|
||||
|
|
@ -12,28 +12,28 @@ def reset_auto_ids():
|
|||
|
||||
|
||||
class Geometry(object):
|
||||
"""Geometry representing a collection of surfaces, cells, and universes.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
root_universe : openmc.universe.Universe
|
||||
Root universe which contains all others
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
# Initialize Geometry class attributes
|
||||
self._root_universe = None
|
||||
self._offsets = {}
|
||||
|
||||
|
||||
@property
|
||||
def root_universe(self):
|
||||
return self._root_universe
|
||||
|
||||
|
||||
@root_universe.setter
|
||||
def root_universe(self, root_universe):
|
||||
|
||||
if not isinstance(root_universe, openmc.Universe):
|
||||
msg = 'Unable to add root Universe {0} to Geometry since ' \
|
||||
'it is not a Universe'.format(root_universe)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif root_universe._id != 0:
|
||||
check_type('root universe', root_universe, openmc.Universe)
|
||||
if root_universe._id != 0:
|
||||
msg = 'Unable to add root Universe {0} to Geometry since ' \
|
||||
'it has ID={1} instead of ' \
|
||||
'ID=0'.format(root_universe, root_universe._id)
|
||||
|
|
@ -41,24 +41,26 @@ class Geometry(object):
|
|||
|
||||
self._root_universe = root_universe
|
||||
|
||||
|
||||
def get_offset(self, path, filter_offset):
|
||||
"""
|
||||
Returns the corresponding location in the results array for a given
|
||||
path and filter number.
|
||||
"""Returns the corresponding location in the results array for a given path and
|
||||
filter number. This is primarily intended to post-processing result when
|
||||
a distribcell filter is used.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : list
|
||||
A list of IDs that form the path to the target. It should begin
|
||||
with 0 for the base universe, and should cover every universe,
|
||||
cell, and lattice passed through. For the case of the lattice,
|
||||
a tuple should be provided to indicate which coordinates in the
|
||||
lattice should be entered. This should be in the
|
||||
form: (lat_id, i_x, i_y, i_z)
|
||||
|
||||
A list of IDs that form the path to the target. It should begin with
|
||||
0 for the base universe, and should cover every universe, cell, and
|
||||
lattice passed through. For the case of the lattice, a tuple should
|
||||
be provided to indicate which coordinates in the lattice should be
|
||||
entered. This should be in the form: (lat_id, i_x, i_y, i_z)
|
||||
filter_offset : int
|
||||
An integer that specifies which offset map the filter is using
|
||||
An integer that specifies which offset map the filter is using
|
||||
|
||||
Returns
|
||||
-------
|
||||
offset : int
|
||||
Location in the results array for the path and filter
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -74,16 +76,39 @@ class Geometry(object):
|
|||
# Return the final offset
|
||||
return offset
|
||||
|
||||
|
||||
def get_all_cells(self):
|
||||
"""Return all cells defined
|
||||
|
||||
Returns
|
||||
-------
|
||||
list of openmc.universe.Cell
|
||||
Cells in the geometry
|
||||
|
||||
"""
|
||||
|
||||
return self._root_universe.get_all_cells()
|
||||
|
||||
|
||||
def get_all_universes(self):
|
||||
"""Return all universes defined
|
||||
|
||||
Returns
|
||||
-------
|
||||
list of openmc.universe.Universe
|
||||
Universes in the geometry
|
||||
|
||||
"""
|
||||
|
||||
return self._root_universe.get_all_universes()
|
||||
|
||||
|
||||
def get_all_nuclides(self):
|
||||
"""Return all nuclides assigned to a material in the geometry
|
||||
|
||||
Returns
|
||||
-------
|
||||
list of openmc.nuclide.Nuclide
|
||||
Nuclides in the geometry
|
||||
|
||||
"""
|
||||
|
||||
nuclides = {}
|
||||
materials = self.get_all_materials()
|
||||
|
|
@ -93,8 +118,15 @@ class Geometry(object):
|
|||
|
||||
return nuclides
|
||||
|
||||
|
||||
def get_all_materials(self):
|
||||
"""Return all materials assigned to a cell
|
||||
|
||||
Returns
|
||||
-------
|
||||
list of openmc.material.Material
|
||||
Materials in the geometry
|
||||
|
||||
"""
|
||||
|
||||
material_cells = self.get_all_material_cells()
|
||||
materials = set()
|
||||
|
|
@ -104,9 +136,7 @@ class Geometry(object):
|
|||
|
||||
return list(materials)
|
||||
|
||||
|
||||
def get_all_material_cells(self):
|
||||
|
||||
all_cells = self.get_all_cells()
|
||||
material_cells = set()
|
||||
|
||||
|
|
@ -116,16 +146,21 @@ class Geometry(object):
|
|||
|
||||
return list(material_cells)
|
||||
|
||||
|
||||
def get_all_material_universes(self):
|
||||
"""Return all universes composed of at least one non-fill cell
|
||||
|
||||
Returns
|
||||
-------
|
||||
list of openmc.universe.Universe
|
||||
Universes with non-fill cells
|
||||
|
||||
"""
|
||||
|
||||
all_universes = self.get_all_universes()
|
||||
material_universes = set()
|
||||
|
||||
for universe_id, universe in all_universes.items():
|
||||
|
||||
cells = universe._cells
|
||||
|
||||
for cell_id, cell in cells.items():
|
||||
if cell._type == 'normal':
|
||||
material_universes.add(universe)
|
||||
|
|
@ -133,33 +168,35 @@ class Geometry(object):
|
|||
return list(material_universes)
|
||||
|
||||
|
||||
|
||||
class GeometryFile(object):
|
||||
"""Geometry file used for an OpenMC simulation. Corresponds directly to the
|
||||
geometry.xml input file.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
geometry : 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):
|
||||
|
||||
if not isinstance(geometry, Geometry):
|
||||
msg = 'Unable to set the Geometry to {0} for the GeometryFile ' \
|
||||
'since it is not a Geometry object'.format(geometry)
|
||||
raise ValueError(msg)
|
||||
|
||||
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.
|
||||
|
||||
"""
|
||||
|
||||
root_universe = self._geometry._root_universe
|
||||
root_universe.create_xml_subelement(self._geometry_file)
|
||||
|
|
@ -168,7 +205,7 @@ class GeometryFile(object):
|
|||
sort_xml_elements(self._geometry_file)
|
||||
clean_xml_indentation(self._geometry_file)
|
||||
|
||||
# Write the XML Tree to the materials.xml 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")
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
from collections import MappingView
|
||||
from collections import Iterable
|
||||
from copy import deepcopy
|
||||
from numbers import Real, Integral
|
||||
import warnings
|
||||
from xml.etree import ElementTree as ET
|
||||
import sys
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
import openmc
|
||||
from openmc.checkvalue import *
|
||||
from openmc.checkvalue import check_type, check_value, check_greater_than
|
||||
from openmc.clean_xml import *
|
||||
|
||||
|
||||
|
|
@ -14,6 +18,7 @@ MATERIAL_IDS = []
|
|||
# A static variable for auto-generated Material IDs
|
||||
AUTO_MATERIAL_ID = 10000
|
||||
|
||||
|
||||
def reset_auto_material_id():
|
||||
global AUTO_MATERIAL_ID, MATERIAL_IDS
|
||||
AUTO_MATERIAL_ID = 10000
|
||||
|
|
@ -23,20 +28,36 @@ def reset_auto_material_id():
|
|||
# Units for density supported by OpenMC
|
||||
DENSITY_UNITS = ['g/cm3', 'g/cc', 'kg/cm3', 'at/b-cm', 'at/cm3', 'sum']
|
||||
|
||||
# ENDF temperatures
|
||||
ENDF_TEMPS = np.array([300, 600, 700, 900, 1200, 1500])
|
||||
|
||||
# ENDF ZAIDs
|
||||
ENDF_ZAIDS = np.array(['70c', '71c', '72c', '73c', '74c'])
|
||||
|
||||
# Constant for density when not needed
|
||||
NO_DENSITY = 99999.
|
||||
|
||||
|
||||
class Material(object):
|
||||
"""A material composed of a collection of nuclides/elements that can be assigned
|
||||
to a region of space.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
material_id : int, optional
|
||||
Unique identifier for the material. If not specified, an identifier will
|
||||
automatically be assigned.
|
||||
name : str, optional
|
||||
Name of the material. If not specified, the name will be the empty
|
||||
string.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
id : int
|
||||
Unique identifier for the material
|
||||
density : float
|
||||
Density of the material (units defined separately)
|
||||
density_units : str
|
||||
Units used for `density`. Can be one of 'g/cm3', 'g/cc', 'kg/cm3',
|
||||
'atom/b-cm', 'atom/cm3', or 'sum'.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, material_id=None, name=''):
|
||||
|
||||
# Initialize class attributes
|
||||
self.id = material_id
|
||||
self.name = name
|
||||
|
|
@ -62,95 +83,75 @@ class Material(object):
|
|||
# If specified, this file will be used instead of composition values
|
||||
self._distrib_otf_file = None
|
||||
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self._id
|
||||
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
|
||||
@property
|
||||
def density(self):
|
||||
return self._density
|
||||
|
||||
|
||||
@property
|
||||
def density_units(self):
|
||||
return self._density_units
|
||||
|
||||
|
||||
@property
|
||||
def convert_to_distrib_comps(self):
|
||||
return self._convert_to_distrib_comps
|
||||
|
||||
|
||||
@property
|
||||
def distrib_otf_file(self):
|
||||
return self._distrib_otf_file
|
||||
|
||||
|
||||
@id.setter
|
||||
def id(self, material_id):
|
||||
|
||||
global AUTO_MATERIAL_ID, MATERIAL_IDS
|
||||
|
||||
# If the Material already has an ID, remove it from global list
|
||||
if hasattr(self, '_id') and not self._id is None:
|
||||
if hasattr(self, '_id') and self._id is not None:
|
||||
MATERIAL_IDS.remove(self._id)
|
||||
|
||||
if material_id is None:
|
||||
self._id = AUTO_MATERIAL_ID
|
||||
MATERIAL_IDS.append(AUTO_MATERIAL_ID)
|
||||
AUTO_MATERIAL_ID += 1
|
||||
|
||||
# Check that the ID is an integer and wasn't already used
|
||||
elif not is_integer(material_id):
|
||||
msg = 'Unable to set a non-integer Material ' \
|
||||
'ID {0}'.format(material_id)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif material_id in MATERIAL_IDS:
|
||||
msg = 'Unable to set Material ID to {0} since a Material with ' \
|
||||
'this ID was already initialized'.format(material_id)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif material_id < 0:
|
||||
msg = 'Unable to set Material ID to {0} since it must be a ' \
|
||||
'non-negative integer'.format(material_id)
|
||||
raise ValueError(msg)
|
||||
|
||||
else:
|
||||
check_type('material ID', material_id, Integral)
|
||||
if material_id in MATERIAL_IDS:
|
||||
msg = 'Unable to set Material ID to {0} since a Material with ' \
|
||||
'this ID was already initialized'.format(material_id)
|
||||
raise ValueError(msg)
|
||||
check_greater_than('material ID', material_id, 0)
|
||||
|
||||
self._id = material_id
|
||||
MATERIAL_IDS.append(material_id)
|
||||
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
|
||||
if not is_string(name):
|
||||
msg = 'Unable to set name for Material ID={0} with a non-string ' \
|
||||
'value {1}'.format(self._id, name)
|
||||
raise ValueError(msg)
|
||||
|
||||
else:
|
||||
self._name = name
|
||||
|
||||
check_type('name for Material ID={0}'.format(self._id),
|
||||
name, basestring)
|
||||
self._name = name
|
||||
|
||||
def set_density(self, units, density=NO_DENSITY):
|
||||
"""Set the density of the material
|
||||
|
||||
if not is_float(density):
|
||||
msg = 'Unable to set the density for Material ID={0} to a ' \
|
||||
'non-floating point value {1}'.format(self._id, density)
|
||||
raise ValueError(msg)
|
||||
Parameters
|
||||
----------
|
||||
units : str
|
||||
Physical units of density
|
||||
density : float, optional
|
||||
Value of the density. Must be specified unless units is given as
|
||||
'sum'.
|
||||
|
||||
elif not units in DENSITY_UNITS:
|
||||
msg = 'Unable to set the density for Material ID={0} with ' \
|
||||
'units {1}'.format(self._id, units)
|
||||
raise ValueError(msg)
|
||||
"""
|
||||
|
||||
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} ' \
|
||||
|
|
@ -161,45 +162,52 @@ class Material(object):
|
|||
self._density = density
|
||||
self._density_units = units
|
||||
|
||||
|
||||
@distrib_otf_file.setter
|
||||
def distrib_otf_file(self, filename):
|
||||
|
||||
# TODO: remove this when distributed materials are merged
|
||||
warnings.warn('This feature is not yet implemented in a release ' \
|
||||
warnings.warn('This feature is not yet implemented in a release '
|
||||
'version of openmc')
|
||||
|
||||
if not is_string(filename) and not filename is None:
|
||||
if not isinstance(filename, basestring) and filename is not None:
|
||||
msg = 'Unable to add OTF material file to Material ID={0} with a ' \
|
||||
'non-string name {1}'.format(self._id, filename)
|
||||
raise ValueError(msg)
|
||||
|
||||
self._distrib_otf_file = filename
|
||||
|
||||
|
||||
@convert_to_distrib_comps.setter
|
||||
def convert_to_distrib_comps(self):
|
||||
|
||||
# TODO: remove this when distributed materials are merged
|
||||
warnings.warn('This feature is not yet implemented in a release ' \
|
||||
warnings.warn('This feature is not yet implemented in a release '
|
||||
'version of openmc')
|
||||
|
||||
self._convert_to_distrib_comps = True
|
||||
|
||||
|
||||
def add_nuclide(self, nuclide, percent, percent_type='ao'):
|
||||
"""Add a nuclide to the material
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nuclide : str or openmc.nuclide.Nuclide
|
||||
Nuclide to add
|
||||
percent : float
|
||||
Atom or weight percent
|
||||
percent_type : str
|
||||
'ao' for atom percent and 'wo' for weight percent
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(nuclide, (openmc.Nuclide, str)):
|
||||
msg = 'Unable to add a Nuclide to Material ID={0} with a ' \
|
||||
'non-Nuclide value {1}'.format(self._id, nuclide)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif not is_float(percent):
|
||||
elif not isinstance(percent, Real):
|
||||
msg = 'Unable to add a Nuclide to Material ID={0} with a ' \
|
||||
'non-floating point value {1}'.format(self._id, percent)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif not percent_type in ['ao', 'wo', 'at/g-cm']:
|
||||
elif percent_type not in ['ao', 'wo', 'at/g-cm']:
|
||||
msg = 'Unable to add a Nuclide to Material ID={0} with a ' \
|
||||
'percent type {1}'.format(self._id, percent_type)
|
||||
raise ValueError(msg)
|
||||
|
|
@ -213,8 +221,15 @@ class Material(object):
|
|||
|
||||
self._nuclides[nuclide._name] = (nuclide, percent, percent_type)
|
||||
|
||||
|
||||
def remove_nuclide(self, nuclide):
|
||||
"""Remove a nuclide from the material
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nuclide : openmc.nuclide.Nuclide
|
||||
Nuclide to remove
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(nuclide, openmc.Nuclide):
|
||||
msg = 'Unable to remove a Nuclide {0} in Material ID={1} ' \
|
||||
|
|
@ -225,20 +240,31 @@ class Material(object):
|
|||
if nuclide._name in self._nuclides:
|
||||
del self._nuclides[nuclide._name]
|
||||
|
||||
|
||||
def add_element(self, element, percent, percent_type='ao'):
|
||||
"""Add a natural element to the material
|
||||
|
||||
Parameters
|
||||
----------
|
||||
element : openmc.element.Element
|
||||
Element to add
|
||||
percent : float
|
||||
Atom or weight percent
|
||||
percent_type : str
|
||||
'ao' for atom percent and 'wo' for weight percent
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(element, openmc.Element):
|
||||
msg = 'Unable to add an Element to Material ID={0} with a ' \
|
||||
'non-Element value {1}'.format(self._id, element)
|
||||
raise ValueError(msg)
|
||||
|
||||
if not is_float(percent):
|
||||
if not isinstance(percent, Real):
|
||||
msg = 'Unable to add an Element to Material ID={0} with a ' \
|
||||
'non-floating point value {1}'.format(self._id, percent)
|
||||
raise ValueError(msg)
|
||||
|
||||
if not percent_type in ['ao', 'wo']:
|
||||
if percent_type not in ['ao', 'wo']:
|
||||
msg = 'Unable to add an Element to Material ID={0} with a ' \
|
||||
'percent type {1}'.format(self._id, percent_type)
|
||||
raise ValueError(msg)
|
||||
|
|
@ -248,36 +274,58 @@ class Material(object):
|
|||
|
||||
self._elements[element._name] = (element, percent, percent_type)
|
||||
|
||||
|
||||
def remove_element(self, element):
|
||||
"""Remove a natural element from the material
|
||||
|
||||
Parameters
|
||||
----------
|
||||
element : openmc.element.Element
|
||||
Element to remove
|
||||
|
||||
"""
|
||||
|
||||
# If the Material contains the Element, delete it
|
||||
if element._name in self._elements:
|
||||
del self._elements[element._name]
|
||||
|
||||
|
||||
def add_s_alpha_beta(self, name, xs):
|
||||
r"""Add an :math:`S(\alpha,\beta)` table to the material
|
||||
|
||||
if not is_string(name):
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Name of the :math:`S(\alpha,\beta)` table
|
||||
xs : str
|
||||
Cross section identifier, e.g. '71t'
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(name, basestring):
|
||||
msg = 'Unable to add an S(a,b) table to Material ID={0} with a ' \
|
||||
'non-string table name {1}'.format(self._id, name)
|
||||
raise ValueError(msg)
|
||||
|
||||
if not is_string(xs):
|
||||
if not isinstance(xs, basestring):
|
||||
msg = 'Unable to add an S(a,b) table to Material ID={0} with a ' \
|
||||
'non-string cross-section identifier {1}'.format(self._id, xs)
|
||||
raise ValueError(msg)
|
||||
|
||||
self._sab.append((name, xs))
|
||||
|
||||
|
||||
def make_isotropic_in_lab(self):
|
||||
|
||||
for nuclide_name in self._nuclides:
|
||||
self._nuclides[nuclide_name][0].make_isotropic_in_lab()
|
||||
|
||||
|
||||
def get_all_nuclides(self):
|
||||
"""Returns all nuclides in the material
|
||||
|
||||
Returns
|
||||
-------
|
||||
nuclides : dict
|
||||
Dictionary whose keys are nuclide names and values are 2-tuples of
|
||||
(nuclide, density)
|
||||
|
||||
"""
|
||||
|
||||
nuclides = {}
|
||||
|
||||
|
|
@ -288,9 +336,7 @@ class Material(object):
|
|||
|
||||
return nuclides
|
||||
|
||||
|
||||
def _repr__(self):
|
||||
|
||||
string = 'Material\n'
|
||||
string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name)
|
||||
|
|
@ -322,9 +368,7 @@ class Material(object):
|
|||
|
||||
return string
|
||||
|
||||
|
||||
def get_nuclide_xml(self, nuclide, distrib=False):
|
||||
|
||||
def _get_nuclide_xml(self, nuclide, distrib=False):
|
||||
xml_element = ET.Element("nuclide")
|
||||
xml_element.set("name", nuclide[0]._name)
|
||||
|
||||
|
|
@ -334,7 +378,7 @@ class Material(object):
|
|||
else:
|
||||
xml_element.set("wo", str(nuclide[1]))
|
||||
|
||||
if not nuclide[0]._xs is None:
|
||||
if nuclide[0]._xs is not None:
|
||||
xml_element.set("xs", nuclide[0]._xs)
|
||||
|
||||
if not nuclide[0]._scattering is None:
|
||||
|
|
@ -342,9 +386,7 @@ class Material(object):
|
|||
|
||||
return xml_element
|
||||
|
||||
|
||||
def get_element_xml(self, element, distrib=False):
|
||||
|
||||
def _get_element_xml(self, element, distrib=False):
|
||||
xml_element = ET.Element("element")
|
||||
xml_element.set("name", str(element[0]._name))
|
||||
|
||||
|
|
@ -356,28 +398,31 @@ class Material(object):
|
|||
|
||||
return xml_element
|
||||
|
||||
|
||||
def get_nuclides_xml(self, nuclides, distrib=False):
|
||||
|
||||
def _get_nuclides_xml(self, nuclides, distrib=False):
|
||||
xml_elements = []
|
||||
|
||||
for nuclide in nuclides.values():
|
||||
xml_elements.append(self.get_nuclide_xml(nuclide, distrib))
|
||||
xml_elements.append(self._get_nuclide_xml(nuclide, distrib))
|
||||
|
||||
return xml_elements
|
||||
|
||||
|
||||
def get_elements_xml(self, elements, distrib=False):
|
||||
|
||||
def _get_elements_xml(self, elements, distrib=False):
|
||||
xml_elements = []
|
||||
|
||||
for element in elements.values():
|
||||
xml_elements.append(self.get_element_xml(element, distrib))
|
||||
xml_elements.append(self._get_element_xml(element, distrib))
|
||||
|
||||
return xml_elements
|
||||
|
||||
|
||||
def get_material_xml(self):
|
||||
"""Return XML representation of the material
|
||||
|
||||
Returns
|
||||
-------
|
||||
element : xml.etree.ElementTree.Element
|
||||
XML element containing material data
|
||||
|
||||
"""
|
||||
|
||||
# Create Material XML element
|
||||
element = ET.Element("material")
|
||||
|
|
@ -393,19 +438,17 @@ class Material(object):
|
|||
subelement.set("units", self._density_units)
|
||||
|
||||
if not self._convert_to_distrib_comps:
|
||||
|
||||
# Create nuclide XML subelements
|
||||
subelements = self.get_nuclides_xml(self._nuclides)
|
||||
subelements = self._get_nuclides_xml(self._nuclides)
|
||||
for subelement in subelements:
|
||||
element.append(subelement)
|
||||
|
||||
# Create element XML subelements
|
||||
subelements = self.get_elements_xml(self._elements)
|
||||
subelements = self._get_elements_xml(self._elements)
|
||||
for subelement in subelements:
|
||||
element.append(subelement)
|
||||
|
||||
else:
|
||||
|
||||
subelement = ET.SubElement(element, "compositions")
|
||||
|
||||
comps = []
|
||||
|
|
@ -418,29 +461,24 @@ class Material(object):
|
|||
raise ValueError(msg)
|
||||
comps.append(per)
|
||||
|
||||
|
||||
if self._distrib_otf_file is None:
|
||||
|
||||
# Create values and units subelements
|
||||
subsubelement = ET.SubElement(subelement, "values")
|
||||
subsubelement.text = ' '.join([str(c) for c in comps])
|
||||
subsubelement = ET.SubElement(subelement, "units")
|
||||
subsubelement.text = dist_per_type
|
||||
|
||||
else:
|
||||
|
||||
# Specify the materials file
|
||||
subsubelement = ET.SubElement(subelement, "otf_file_path")
|
||||
subsubelement.text = self._distrib_otf_file
|
||||
|
||||
|
||||
# Create nuclide XML subelements
|
||||
subelements = self.get_nuclides_xml(self._nuclides, distrib=True)
|
||||
for subelement_nuc in subelements:
|
||||
subelement.append(subelement_nuc)
|
||||
|
||||
# Create element XML subelements
|
||||
subelements = self.get_elements_xml(self._elements, distrib=True)
|
||||
subelements = self._get_elements_xml(self._elements, distrib=True)
|
||||
for subelement_ele in subelements:
|
||||
subelement.append(subelement_ele)
|
||||
|
||||
|
|
@ -454,31 +492,41 @@ class Material(object):
|
|||
|
||||
|
||||
class MaterialsFile(object):
|
||||
"""Materials file used for an OpenMC simulation. Corresponds directly to the
|
||||
materials.xml input file.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
default_xs : str
|
||||
The default cross section identifier applied to a nuclide when none is
|
||||
specified
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
# Initialize MaterialsFile class attributes
|
||||
self._materials = []
|
||||
self._default_xs = None
|
||||
self._materials_file = ET.Element("materials")
|
||||
|
||||
|
||||
@property
|
||||
def default_xs(self):
|
||||
return self._default_xs
|
||||
|
||||
|
||||
@default_xs.setter
|
||||
def default_xs(self, xs):
|
||||
|
||||
if not is_string(xs):
|
||||
msg = 'Unable to set default xs to a non-string value'.format(xs)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('default xs', xs, basestring)
|
||||
self._default_xs = xs
|
||||
|
||||
|
||||
def add_material(self, material):
|
||||
"""Add a material to the file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
material : Material
|
||||
Material to add
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(material, Material):
|
||||
msg = 'Unable to add a non-Material {0} to the ' \
|
||||
|
|
@ -487,19 +535,33 @@ class MaterialsFile(object):
|
|||
|
||||
self._materials.append(material)
|
||||
|
||||
|
||||
def add_materials(self, materials):
|
||||
"""Add multiple materials to the file.
|
||||
|
||||
if not isinstance(materials, (tuple, list, MappingView)):
|
||||
Parameters
|
||||
----------
|
||||
materials : tuple or list of Material
|
||||
Materials to add
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(materials, Iterable):
|
||||
msg = 'Unable to create OpenMC materials.xml file from {0} which ' \
|
||||
'is not a Python tuple/list'.format(materials)
|
||||
'is not iterable'.format(materials)
|
||||
raise ValueError(msg)
|
||||
|
||||
for material in materials:
|
||||
self.add_material(material)
|
||||
|
||||
def remove_material(self, material):
|
||||
"""Remove a material from the file
|
||||
|
||||
def remove_materials(self, material):
|
||||
Parameters
|
||||
----------
|
||||
material : Material
|
||||
Material to remove
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(material, Material):
|
||||
msg = 'Unable to remove a non-Material {0} from the ' \
|
||||
|
|
@ -509,26 +571,25 @@ class MaterialsFile(object):
|
|||
self._materials.remove(material)
|
||||
|
||||
def make_isotropic_in_lab(self):
|
||||
|
||||
for material in self._materials:
|
||||
materials.make_isotropic_in_lab()
|
||||
|
||||
|
||||
def create_material_subelements(self):
|
||||
|
||||
def _create_material_subelements(self):
|
||||
subelement = ET.SubElement(self._materials_file, "default_xs")
|
||||
|
||||
if not self._default_xs is None:
|
||||
if self._default_xs is not None:
|
||||
subelement.text = self._default_xs
|
||||
|
||||
for material in self._materials:
|
||||
xml_element = material.get_material_xml()
|
||||
self._materials_file.append(xml_element)
|
||||
|
||||
|
||||
def export_to_xml(self):
|
||||
"""Create a materials.xml file that can be used for a simulation.
|
||||
|
||||
self.create_material_subelements()
|
||||
"""
|
||||
|
||||
self._create_material_subelements()
|
||||
|
||||
# Clean the indentation in the file to be user-readable
|
||||
sort_xml_elements(self._materials_file)
|
||||
|
|
|
|||
252
openmc/mesh.py
252
openmc/mesh.py
|
|
@ -1,8 +1,14 @@
|
|||
from collections import Iterable
|
||||
import copy
|
||||
from numbers import Real, Integral
|
||||
from xml.etree import ElementTree as ET
|
||||
import sys
|
||||
|
||||
from openmc.checkvalue import *
|
||||
from openmc.checkvalue import (check_type, check_length, check_value,
|
||||
check_greater_than)
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
# "Static" variable for auto-generated and Mesh IDs
|
||||
AUTO_MESH_ID = 10000
|
||||
|
|
@ -14,9 +20,37 @@ def reset_auto_mesh_id():
|
|||
|
||||
|
||||
class Mesh(object):
|
||||
"""A structured Cartesian mesh in two or three dimensions
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mesh_id : int
|
||||
Unique identifier for the mesh
|
||||
name : str
|
||||
Name of the mesh
|
||||
|
||||
Attributes
|
||||
----------
|
||||
id : int
|
||||
Unique identifier for the mesh
|
||||
name : str
|
||||
Name of the mesh
|
||||
type : str
|
||||
Type of the mesh
|
||||
dimension : Iterable of int
|
||||
The number of mesh cells in each direction.
|
||||
lower_left : Iterable of float
|
||||
The lower-left corner of the structured mesh. If only two coordinate are
|
||||
given, it is assumed that the mesh is an x-y mesh.
|
||||
upper_right : Iterable of float
|
||||
The upper-right corner of the structrued mesh. If only two coordinate
|
||||
are given, it is assumed that the mesh is an x-y mesh.
|
||||
width : Iterable of float
|
||||
The width of mesh cells in each direction.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, mesh_id=None, name=''):
|
||||
|
||||
# Initialize Mesh class attributes
|
||||
self.id = mesh_id
|
||||
self.name = name
|
||||
|
|
@ -26,9 +60,7 @@ class Mesh(object):
|
|||
self._upper_right = None
|
||||
self._width = None
|
||||
|
||||
|
||||
def __eq__(self, mesh2):
|
||||
|
||||
# Check type
|
||||
if self._type != mesh2._type:
|
||||
return False
|
||||
|
|
@ -49,14 +81,11 @@ class Mesh(object):
|
|||
else:
|
||||
return True
|
||||
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
|
||||
existing = memo.get(id(self))
|
||||
|
||||
# If this is the first time we have tried to copy this object, create a copy
|
||||
if existing is None:
|
||||
|
||||
clone = type(self).__new__(type(self))
|
||||
clone._id = self._id
|
||||
clone._name = self._name
|
||||
|
|
@ -74,201 +103,87 @@ class Mesh(object):
|
|||
else:
|
||||
return existing
|
||||
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self._id
|
||||
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self._type
|
||||
|
||||
|
||||
@property
|
||||
def dimension(self):
|
||||
return self._dimension
|
||||
|
||||
|
||||
@property
|
||||
def lower_left(self):
|
||||
return self._lower_left
|
||||
|
||||
|
||||
@property
|
||||
def upper_right(self):
|
||||
return self._upper_right
|
||||
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
return self._width
|
||||
|
||||
|
||||
@property
|
||||
def num_mesh_cells(self):
|
||||
return np.prod(self._dimension)
|
||||
|
||||
|
||||
@id.setter
|
||||
def id(self, mesh_id):
|
||||
|
||||
if mesh_id is None:
|
||||
global AUTO_MESH_ID
|
||||
self._id = AUTO_MESH_ID
|
||||
AUTO_MESH_ID += 1
|
||||
|
||||
# Check that the ID is an integer and wasn't already used
|
||||
elif not is_integer(mesh_id):
|
||||
msg = 'Unable to set a non-integer Mesh ID {0}'.format(mesh_id)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif mesh_id < 0:
|
||||
msg = 'Unable to set Mesh ID to {0} since it must be a ' \
|
||||
'non-negative integer'.format(mesh_id)
|
||||
raise ValueError(msg)
|
||||
|
||||
else:
|
||||
check_type('mesh ID', mesh_id, Integral)
|
||||
check_greater_than('mesh ID', mesh_id, 0)
|
||||
self._id = mesh_id
|
||||
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
|
||||
if not is_string(name):
|
||||
msg = 'Unable to set name for Mesh ID={0} with a non-string ' \
|
||||
'value {1}'.format(self._id, name)
|
||||
raise ValueError(msg)
|
||||
|
||||
else:
|
||||
self._name = name
|
||||
|
||||
check_type('name for mesh ID={0}'.format(self._id), name, basestring)
|
||||
self._name = name
|
||||
|
||||
@type.setter
|
||||
def type(self, type):
|
||||
|
||||
if not is_string(type):
|
||||
msg = 'Unable to set Mesh ID={0} for type {1} which is not ' \
|
||||
'a string'.format(self._id, type)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif not type in ['rectangular', 'hexagonal']:
|
||||
msg = 'Unable to set Mesh ID={0} for type {1} which since ' \
|
||||
'only rectangular and hexagonal meshes are ' \
|
||||
'supported '.format(self._id, type)
|
||||
raise ValueError(msg)
|
||||
|
||||
self._type = type
|
||||
|
||||
def type(self, meshtype):
|
||||
check_type('type for mesh ID={0}'.format(self._id),
|
||||
meshtype, basestring)
|
||||
check_value('type for mesh ID={0}'.format(self._id),
|
||||
meshtype, ['rectangular', 'hexagonal'])
|
||||
self._type = meshtype
|
||||
|
||||
@dimension.setter
|
||||
def dimension(self, dimension):
|
||||
|
||||
if not isinstance(dimension, (tuple, list, np.ndarray)):
|
||||
msg = 'Unable to set Mesh ID={0} with dimension {1} which is ' \
|
||||
'not a Python list, tuple or NumPy ' \
|
||||
'array'.format(self._id, dimension)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif len(dimension) != 2 and len(dimension) != 3:
|
||||
msg = 'Unable to set Mesh ID={0} with dimension {1} since it ' \
|
||||
'must include 2 or 3 dimensions'.format(self._id, dimension)
|
||||
raise ValueError(msg)
|
||||
|
||||
for dim in dimension:
|
||||
|
||||
if not is_integer(dim):
|
||||
msg = 'Unable to set Mesh ID={0} with dimension {1} which ' \
|
||||
'is a non-integer'.format(self._id, dim)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('mesh dimension', dimension, Iterable, Integral)
|
||||
check_length('mesh dimension', dimension, 2, 3)
|
||||
self._dimension = dimension
|
||||
|
||||
|
||||
@lower_left.setter
|
||||
def lower_left(self, lower_left):
|
||||
|
||||
if not isinstance(lower_left, (tuple, list, np.ndarray)):
|
||||
msg = 'Unable to set Mesh ID={0} with lower_left {1} which is ' \
|
||||
'not a Python list, tuple or NumPy ' \
|
||||
'array'.format(self._id, lower_left)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif len(lower_left) != 2 and len(lower_left) != 3:
|
||||
msg = 'Unable to set Mesh ID={0} with lower_left {1} since it ' \
|
||||
'must include 2 or 3 dimensions'.format(self._id, lower_left)
|
||||
raise ValueError(msg)
|
||||
|
||||
for coord in lower_left:
|
||||
|
||||
if not is_integer(coord) and not is_float(coord):
|
||||
msg = 'Unable to set Mesh ID={0} with lower_left {1} which ' \
|
||||
'is neither neither an integer nor a floating point ' \
|
||||
'value'.format(self._id, coord)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('mesh lower_left', lower_left, Iterable, Real)
|
||||
check_length('mesh lower_left', lower_left, 2, 3)
|
||||
self._lower_left = lower_left
|
||||
|
||||
|
||||
@upper_right.setter
|
||||
def upper_right(self, upper_right):
|
||||
|
||||
if not isinstance(upper_right, (tuple, list, np.ndarray)):
|
||||
msg = 'Unable to set Mesh ID={0} with upper_right {1} which ' \
|
||||
'is not a Python list, tuple or NumPy ' \
|
||||
'array'.format(self._id, upper_right)
|
||||
raise ValueError(msg)
|
||||
|
||||
if len(upper_right) != 2 and len(upper_right) != 3:
|
||||
msg = 'Unable to set Mesh ID={0} with upper_right {1} since it ' \
|
||||
'must include 2 or 3 dimensions'.format(self._id, upper_right)
|
||||
raise ValueError(msg)
|
||||
|
||||
for coord in upper_right:
|
||||
|
||||
if not is_integer(coord) and not is_float(coord):
|
||||
msg = 'Unable to set Mesh ID={0} with upper_right {1} which ' \
|
||||
'is neither an integer nor a floating point ' \
|
||||
'value'.format(self._id, coord)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('mesh upper_right', upper_right, Iterable, Real)
|
||||
check_length('mesh upper_right', upper_right, 2, 3)
|
||||
self._upper_right = upper_right
|
||||
|
||||
|
||||
@width.setter
|
||||
def width(self, width):
|
||||
|
||||
if not width is None:
|
||||
|
||||
if not isinstance(width, (tuple, list, np.ndarray)):
|
||||
msg = 'Unable to set Mesh ID={0} with width {1} which ' \
|
||||
'is not a Python list, tuple or NumPy ' \
|
||||
'array'.format(self._id, width)
|
||||
raise ValueError(msg)
|
||||
|
||||
if len(width) != 2 and len(width) != 3:
|
||||
msg = 'Unable to set Mesh ID={0} with width {1} since it must ' \
|
||||
'include 2 or 3 dimensions'.format(self._id, width)
|
||||
raise ValueError(msg)
|
||||
|
||||
for dim in width:
|
||||
|
||||
if not is_integer(dim) and not is_float(dim):
|
||||
msg = 'Unable to set Mesh ID={0} with width {1} which is ' \
|
||||
'neither an integer nor a floating point ' \
|
||||
'value'.format(self._id, width)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('mesh width', width, Iterable, Real)
|
||||
check_length('mesh width', width, 2, 3)
|
||||
self._width = width
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
string = 'Mesh\n'
|
||||
string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name)
|
||||
|
|
@ -279,53 +194,32 @@ class Mesh(object):
|
|||
string += '{0: <16}{1}{2}\n'.format('\tPixels', '=\t', self._width)
|
||||
return string
|
||||
|
||||
|
||||
def get_mesh_xml(self):
|
||||
"""Return XML representation of the mesh
|
||||
|
||||
Returns
|
||||
-------
|
||||
element : xml.etree.ElementTree.Element
|
||||
XML element containing mesh data
|
||||
|
||||
"""
|
||||
|
||||
element = ET.Element("mesh")
|
||||
element.set("id", str(self._id))
|
||||
element.set("type", self._type)
|
||||
|
||||
if len(self._dimension) == 2:
|
||||
subelement = ET.SubElement(element, "dimension")
|
||||
subelement.text = '{0} {1}'.format(self._dimension[0],
|
||||
self._dimension[1])
|
||||
else:
|
||||
subelement = ET.SubElement(element, "dimension")
|
||||
subelement.text = '{0} {1} {2}'.format(self._dimension[0],
|
||||
self._dimension[1],
|
||||
self._dimension[2])
|
||||
subelement = ET.SubElement(element, "dimension")
|
||||
subelement.text = ' '.join(map(str, self._dimension))
|
||||
|
||||
if len(self._lower_left) == 2:
|
||||
subelement = ET.SubElement(element, "lower_left")
|
||||
subelement.text = '{0} {1}'.format(self._lower_left[0],
|
||||
self._lower_left[1])
|
||||
else:
|
||||
subelement = ET.SubElement(element, "lower_left")
|
||||
subelement.text = '{0} {1} {2}'.format(self._lower_left[0],
|
||||
self._lower_left[1],
|
||||
self._lower_left[2])
|
||||
subelement = ET.SubElement(element, "lower_left")
|
||||
subelement.text = ' '.join(map(str, self._lower_left))
|
||||
|
||||
if not self._upper_right is None:
|
||||
if len(self._upper_right) == 2:
|
||||
subelement = ET.SubElement(element, "upper_right")
|
||||
subelement.text = '{0} {1}'.format(self._upper_right[0],
|
||||
self._upper_right[1])
|
||||
else:
|
||||
subelement = ET.SubElement(element, "upper_right")
|
||||
subelement.text = '{0} {1} {2}'.format(self._upper_right[0],
|
||||
self._upper_right[1],
|
||||
self._upper_right[2])
|
||||
if self._upper_right is not None:
|
||||
subelement = ET.SubElement(element, "upper_right")
|
||||
subelement.text = ' '.join(map(str, self._upper_right))
|
||||
|
||||
if not self._width is None:
|
||||
if len(self._width) == 2:
|
||||
subelement = ET.SubElement(element, "width")
|
||||
subelement.text = '{0} {1}'.format(self._width[0],
|
||||
self._width[1])
|
||||
else:
|
||||
subelement = ET.SubElement(element, "width")
|
||||
subelement.text = '{0} {1} {2}'.format(self._width[0],
|
||||
self._width[1],
|
||||
self._width[2])
|
||||
if self._width is not None:
|
||||
subelement = ET.SubElement(element, "width")
|
||||
subelement.text = ' '.join(map(str, self._width))
|
||||
|
||||
return element
|
||||
return element
|
||||
|
|
|
|||
|
|
@ -1,10 +1,35 @@
|
|||
from openmc.checkvalue import *
|
||||
from numbers import Integral
|
||||
import sys
|
||||
|
||||
from openmc.checkvalue import check_type
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
class Nuclide(object):
|
||||
"""A nuclide that can be used in a material.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Name of the nuclide, e.g. U-235
|
||||
xs : str
|
||||
Cross section identifier, e.g. 71c
|
||||
|
||||
Attributes
|
||||
----------
|
||||
name : str
|
||||
Name of the nuclide, e.g. U-235
|
||||
xs : str
|
||||
Cross section identifier, e.g. 71c
|
||||
zaid : int
|
||||
1000*(atomic number) + mass number. As an example, the zaid of U-235
|
||||
would be 92235.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, name='', xs=None):
|
||||
|
||||
# Initialize class attributes
|
||||
self._name = ''
|
||||
self._xs = None
|
||||
|
|
@ -14,12 +39,10 @@ class Nuclide(object):
|
|||
# Set the Material class attributes
|
||||
self.name = name
|
||||
|
||||
if not xs is None:
|
||||
if xs is not None:
|
||||
self.xs = xs
|
||||
|
||||
|
||||
def __eq__(self, nuclide2):
|
||||
|
||||
# Check type
|
||||
if not isinstance(nuclide2, Nuclide):
|
||||
return False
|
||||
|
|
@ -35,63 +58,41 @@ class Nuclide(object):
|
|||
else:
|
||||
return True
|
||||
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self._name, self._xs))
|
||||
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
|
||||
@property
|
||||
def xs(self):
|
||||
return self._xs
|
||||
|
||||
|
||||
@property
|
||||
def zaid(self):
|
||||
return self._zaid
|
||||
|
||||
|
||||
@property
|
||||
def scattering(self):
|
||||
return self._scattering
|
||||
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
|
||||
if not is_string(name):
|
||||
msg = 'Unable to set name for Nuclide with a non-string ' \
|
||||
'value {0}'.format(name)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('name', name, basestring)
|
||||
self._name = name
|
||||
|
||||
|
||||
@xs.setter
|
||||
def xs(self, xs):
|
||||
|
||||
if not is_string(xs):
|
||||
msg = 'Unable to set cross-section identifier xs for Nuclide ' \
|
||||
'with a non-string value {0}'.format(xs)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('cross-section identifier', xs, basestring)
|
||||
self._xs = xs
|
||||
|
||||
|
||||
@zaid.setter
|
||||
def zaid(self, zaid):
|
||||
|
||||
if not is_integer(zaid):
|
||||
msg = 'Unable to set zaid for Nuclide ' \
|
||||
'with a non-integer {0}'.format(zaid)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('zaid', zaid, Integral)
|
||||
self._zaid = zaid
|
||||
|
||||
<<<<<<< HEAD
|
||||
|
||||
@scattering.setter
|
||||
def scattering(self, scattering):
|
||||
|
|
@ -104,13 +105,17 @@ class Nuclide(object):
|
|||
self._scattering = scattering
|
||||
|
||||
|
||||
=======
|
||||
>>>>>>> develop
|
||||
def __repr__(self):
|
||||
|
||||
string = 'Nuclide - {0}\n'.format(self._name)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tXS', '=\t', self._xs)
|
||||
if self._zaid is not None:
|
||||
string += '{0: <16}{1}{2}\n'.format('\tZAID', '=\t', self._zaid)
|
||||
<<<<<<< HEAD
|
||||
if self._scattering is not None:
|
||||
string += '{0: <16}{1}{2}\n'.format('\tscattering', '=\t',
|
||||
self._scattering)
|
||||
=======
|
||||
>>>>>>> develop
|
||||
return string
|
||||
|
|
|
|||
|
|
@ -62,8 +62,20 @@ OPENMC_LATTICES = {}
|
|||
OPENCG_LATTICES = {}
|
||||
|
||||
|
||||
|
||||
def get_opencg_material(openmc_material):
|
||||
"""Return an OpenCG material corresponding to an OpenMC material.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
openmc_material : openmc.material.Material
|
||||
OpenMC material
|
||||
|
||||
Returns
|
||||
-------
|
||||
opencg_material : opencg.Material
|
||||
Equivalent OpenCG material
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(openmc_material, openmc.Material):
|
||||
msg = 'Unable to create an OpenCG Material from {0} ' \
|
||||
|
|
@ -91,6 +103,19 @@ def get_opencg_material(openmc_material):
|
|||
|
||||
|
||||
def get_openmc_material(opencg_material):
|
||||
"""Return an OpenMC material corresponding to an OpenCG material.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
opencg_material : opencg.Material
|
||||
OpenCG material
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc_material : openmc.material.Material
|
||||
Equivalent OpenMC material
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(opencg_material, opencg.Material):
|
||||
msg = 'Unable to create an OpenMC Material from {0} ' \
|
||||
|
|
@ -118,6 +143,25 @@ def get_openmc_material(opencg_material):
|
|||
|
||||
|
||||
def is_opencg_surface_compatible(opencg_surface):
|
||||
"""Determine whether OpenCG surface is compatible with OpenMC geometry.
|
||||
|
||||
A surface is considered compatible if there is a one-to-one correspondence
|
||||
between OpenMC and OpenCG surface types. Note that some OpenCG surfaces,
|
||||
e.g. SquarePrism, do not have a one-to-one correspondence with OpenMC
|
||||
surfaces but can still be converted into an equivalent collection of OpenMC
|
||||
surfaces.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
opencg_surface : opencg.Surface
|
||||
OpenCG surface
|
||||
|
||||
Returns
|
||||
-------
|
||||
bool
|
||||
Whether OpenCG surface is compatible with OpenMC
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(opencg_surface, opencg.Surface):
|
||||
msg = 'Unable to check if OpenCG Surface is compatible' \
|
||||
|
|
@ -132,6 +176,19 @@ def is_opencg_surface_compatible(opencg_surface):
|
|||
|
||||
|
||||
def get_opencg_surface(openmc_surface):
|
||||
"""Return an OpenCG surface corresponding to an OpenMC surface.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
openmc_surface : openmc.surface.Surface
|
||||
OpenMC surface
|
||||
|
||||
Returns
|
||||
-------
|
||||
opencg_surface : opencg.Surface
|
||||
Equivalent OpenCG surface
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(openmc_surface, openmc.Surface):
|
||||
msg = 'Unable to create an OpenCG Surface from {0} ' \
|
||||
|
|
@ -205,6 +262,19 @@ def get_opencg_surface(openmc_surface):
|
|||
|
||||
|
||||
def get_openmc_surface(opencg_surface):
|
||||
"""Return an OpenMC surface corresponding to an OpenCG surface.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
opencg_surface : opencg.Surface
|
||||
OpenCG surface
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc_surface : openmc.surface.Surface
|
||||
Equivalent OpenMC surface
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(opencg_surface, opencg.Surface):
|
||||
msg = 'Unable to create an OpenMC Surface from {0} which ' \
|
||||
|
|
@ -269,7 +339,6 @@ def get_openmc_surface(opencg_surface):
|
|||
'Surface type in OpenMC'.format(opencg_surface._type)
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
# Add the OpenMC Surface to the global collection of all OpenMC Surfaces
|
||||
OPENMC_SURFACES[surface_id] = openmc_surface
|
||||
|
||||
|
|
@ -280,6 +349,23 @@ def get_openmc_surface(opencg_surface):
|
|||
|
||||
|
||||
def get_compatible_opencg_surfaces(opencg_surface):
|
||||
"""Generate OpenCG surfaces that are compatible with OpenMC equivalent to an
|
||||
OpenCG surface that is not compatible. For example, this method may be used
|
||||
to convert a ZSquarePrism OpenCG surface into a collection of equivalent
|
||||
XPlane and YPlane OpenCG surfaces.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
opencg_surface : opencg.Surface
|
||||
OpenCG surface that is incompatible with OpenMC
|
||||
|
||||
Returns
|
||||
-------
|
||||
surfaces : list of opencg.Surface
|
||||
Collection of surfaces equivalent to the original one but compatible
|
||||
with OpenMC
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(opencg_surface, opencg.Surface):
|
||||
msg = 'Unable to create an OpenMC Surface from {0} which ' \
|
||||
|
|
@ -349,6 +435,19 @@ def get_compatible_opencg_surfaces(opencg_surface):
|
|||
|
||||
|
||||
def get_opencg_cell(openmc_cell):
|
||||
"""Return an OpenCG cell corresponding to an OpenMC cell.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
openmc_cell : openmc.universe.Cell
|
||||
OpenMC cell
|
||||
|
||||
Returns
|
||||
-------
|
||||
opencg_cell : opencg.Cell
|
||||
Equivalent OpenCG cell
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(openmc_cell, openmc.Cell):
|
||||
msg = 'Unable to create an OpenCG Cell from {0} which ' \
|
||||
|
|
@ -398,7 +497,26 @@ def get_opencg_cell(openmc_cell):
|
|||
|
||||
|
||||
def get_compatible_opencg_cells(opencg_cell, opencg_surface, halfspace):
|
||||
"""Generate OpenCG cells that are compatible with OpenMC equivalent to an OpenCG
|
||||
cell that is not compatible.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
opencg_cell : opencg.Cell
|
||||
OpenCG cell
|
||||
opencg_surface : opencg.Surface
|
||||
OpenCG surface that causes the incompatibility, e.g. an instance of
|
||||
XSquarePrism
|
||||
halfspace : {-1, 1}
|
||||
Which halfspace defined by the surface is contained in the cell
|
||||
|
||||
Returns
|
||||
-------
|
||||
compatible_cells : list of opencg.Cell
|
||||
Collection of cells equivalent to the original one but compatible with
|
||||
OpenMC
|
||||
|
||||
"""
|
||||
if not isinstance(opencg_cell, opencg.Cell):
|
||||
msg = 'Unable to create compatible OpenMC Cell from {0} which ' \
|
||||
'is not an OpenCG Cell'.format(opencg_cell)
|
||||
|
|
@ -409,7 +527,7 @@ def get_compatible_opencg_cells(opencg_cell, opencg_surface, halfspace):
|
|||
'not an OpenCG Surface'.format(opencg_surface)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif not halfspace in [-1, +1]:
|
||||
elif halfspace not in [-1, +1]:
|
||||
msg = 'Unable to create compatible Cell since {0}' \
|
||||
'is not a +/-1 halfspace'.format(halfspace)
|
||||
raise ValueError(msg)
|
||||
|
|
@ -418,8 +536,8 @@ def get_compatible_opencg_cells(opencg_cell, opencg_surface, halfspace):
|
|||
compatible_cells = []
|
||||
|
||||
# SquarePrism Surfaces
|
||||
if opencg_surface._type in ['x-squareprism',
|
||||
'y-squareprism', 'z-squareprism']:
|
||||
if opencg_surface._type in ['x-squareprism', 'y-squareprism',
|
||||
'z-squareprism']:
|
||||
|
||||
# Get the compatible Surfaces (XPlanes and YPlanes)
|
||||
compatible_surfaces = get_compatible_opencg_surfaces(opencg_surface)
|
||||
|
|
@ -436,13 +554,11 @@ def get_compatible_opencg_cells(opencg_cell, opencg_surface, halfspace):
|
|||
|
||||
# If Cell is outside SquarePrism, add "outside" of Surface halfspaces
|
||||
else:
|
||||
|
||||
# Create 8 Cell clones to represent each of the disjoint planar
|
||||
# Surface halfspace intersections
|
||||
num_clones = 8
|
||||
|
||||
for clone_id in range(num_clones):
|
||||
|
||||
# Create a cloned OpenCG Cell with Surfaces compatible with OpenMC
|
||||
clone = opencg_cell.clone()
|
||||
compatible_cells.append(clone)
|
||||
|
|
@ -500,6 +616,14 @@ def get_compatible_opencg_cells(opencg_cell, opencg_surface, halfspace):
|
|||
|
||||
|
||||
def make_opencg_cells_compatible(opencg_universe):
|
||||
"""Make all cells in an OpenCG universe compatible with OpenMC.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
opencg_universe : opencg.Universe
|
||||
Universe to check
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(opencg_universe, opencg.Universe):
|
||||
msg = 'Unable to make compatible OpenCG Cells for {0} which ' \
|
||||
|
|
@ -545,8 +669,20 @@ def make_opencg_cells_compatible(opencg_universe):
|
|||
return
|
||||
|
||||
|
||||
|
||||
def get_openmc_cell(opencg_cell):
|
||||
"""Return an OpenMC cell corresponding to an OpenCG cell.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
opencg_cell : opencg.Cell
|
||||
OpenCG cell
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc_cell : openmc.universe.Cell
|
||||
Equivalent OpenMC cell
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(opencg_cell, opencg.Cell):
|
||||
msg = 'Unable to create an OpenMC Cell from {0} which ' \
|
||||
|
|
@ -597,8 +733,20 @@ def get_openmc_cell(opencg_cell):
|
|||
return openmc_cell
|
||||
|
||||
|
||||
|
||||
def get_opencg_universe(openmc_universe):
|
||||
"""Return an OpenCG universe corresponding to an OpenMC universe.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
openmc_universe : openmc.universe.Universe
|
||||
OpenMC universe
|
||||
|
||||
Returns
|
||||
-------
|
||||
opencg_universe : opencg.Universe
|
||||
Equivalent OpenCG universe
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(openmc_universe, openmc.Universe):
|
||||
msg = 'Unable to create an OpenCG Universe from {0} which ' \
|
||||
|
|
@ -633,6 +781,19 @@ def get_opencg_universe(openmc_universe):
|
|||
|
||||
|
||||
def get_openmc_universe(opencg_universe):
|
||||
"""Return an OpenMC universe corresponding to an OpenCG universe.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
opencg_universe : opencg.Universe
|
||||
OpenCG universe
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc_universe : openmc.universe.Universe
|
||||
Equivalent OpenMC universe
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(opencg_universe, opencg.Universe):
|
||||
msg = 'Unable to create an OpenMC Universe from {0} which ' \
|
||||
|
|
@ -670,6 +831,19 @@ def get_openmc_universe(opencg_universe):
|
|||
|
||||
|
||||
def get_opencg_lattice(openmc_lattice):
|
||||
"""Return an OpenCG lattice corresponding to an OpenMC lattice.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
openmc_lattice : openmc.universe.Lattice
|
||||
OpenMC lattice
|
||||
|
||||
Returns
|
||||
-------
|
||||
opencg_lattice : opencg.Lattice
|
||||
Equivalent OpenCG lattice
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(openmc_lattice, openmc.Lattice):
|
||||
msg = 'Unable to create an OpenCG Lattice from {0} which ' \
|
||||
|
|
@ -701,7 +875,7 @@ def get_opencg_lattice(openmc_lattice):
|
|||
lower_left = new_lower_left
|
||||
|
||||
# Initialize an empty array for the OpenCG nested Universes in this Lattice
|
||||
universe_array = np.ndarray(tuple(np.array(dimension)[::-1]), \
|
||||
universe_array = np.ndarray(tuple(np.array(dimension)[::-1]),
|
||||
dtype=opencg.Universe)
|
||||
|
||||
# Create OpenCG Universes for each unique nested Universe in this Lattice
|
||||
|
|
@ -723,8 +897,8 @@ def get_opencg_lattice(openmc_lattice):
|
|||
opencg_lattice.setUniverses(universe_array)
|
||||
|
||||
offset = np.array(lower_left, dtype=np.float64) - \
|
||||
((np.array(pitch, dtype=np.float64) * \
|
||||
np.array(dimension, dtype=np.float64))) / -2.0
|
||||
((np.array(pitch, dtype=np.float64) *
|
||||
np.array(dimension, dtype=np.float64))) / -2.0
|
||||
opencg_lattice.setOffset(offset)
|
||||
|
||||
# Add the OpenMC Lattice to the global collection of all OpenMC Lattices
|
||||
|
|
@ -737,6 +911,19 @@ def get_opencg_lattice(openmc_lattice):
|
|||
|
||||
|
||||
def get_openmc_lattice(opencg_lattice):
|
||||
"""Return an OpenMC lattice corresponding to an OpenCG lattice.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
opencg_lattice : opencg.Lattice
|
||||
OpenCG lattice
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc_lattice : openmc.universe.Lattice
|
||||
Equivalent OpenMC lattice
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(opencg_lattice, opencg.Lattice):
|
||||
msg = 'Unable to create an OpenMC Lattice from {0} which ' \
|
||||
|
|
@ -756,7 +943,7 @@ def get_openmc_lattice(opencg_lattice):
|
|||
universes = opencg_lattice._universes
|
||||
|
||||
# Initialize an empty array for the OpenMC nested Universes in this Lattice
|
||||
universe_array = np.ndarray(tuple(np.array(dimension)), \
|
||||
universe_array = np.ndarray(tuple(np.array(dimension)),
|
||||
dtype=openmc.Universe)
|
||||
|
||||
# Create OpenMC Universes for each unique nested Universe in this Lattice
|
||||
|
|
@ -773,11 +960,11 @@ def get_openmc_lattice(opencg_lattice):
|
|||
universe_array[x][y][z] = unique_universes[universe_id]
|
||||
|
||||
# Reverse y-dimension in array to match ordering in OpenCG
|
||||
universe_array = universe_array[:,::-1,:]
|
||||
universe_array = universe_array[:, ::-1, :]
|
||||
|
||||
lower_left = np.array(offset, dtype=np.float64) + \
|
||||
((np.array(width, dtype=np.float64) * \
|
||||
np.array(dimension, dtype=np.float64))) / -2.0
|
||||
((np.array(width, dtype=np.float64) *
|
||||
np.array(dimension, dtype=np.float64))) / -2.0
|
||||
|
||||
openmc_lattice = openmc.RectLattice(lattice_id=lattice_id)
|
||||
openmc_lattice.dimension = dimension
|
||||
|
|
@ -795,6 +982,19 @@ def get_openmc_lattice(opencg_lattice):
|
|||
|
||||
|
||||
def get_opencg_geometry(openmc_geometry):
|
||||
"""Return an OpenCG geometry corresponding to an OpenMC geometry.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
openmc_geometry : openmc.universe.Geometry
|
||||
OpenMC geometry
|
||||
|
||||
Returns
|
||||
-------
|
||||
opencg_geometry : opencg.Geometry
|
||||
Equivalent OpenCG geometry
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(openmc_geometry, openmc.Geometry):
|
||||
msg = 'Unable to get OpenCG geometry from {0} which is ' \
|
||||
|
|
@ -822,6 +1022,19 @@ def get_opencg_geometry(openmc_geometry):
|
|||
|
||||
|
||||
def get_openmc_geometry(opencg_geometry):
|
||||
"""Return an OpenMC geometry corresponding to an OpenCG geometry.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
opencg_geometry : opencg.Geometry
|
||||
OpenCG geometry
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc_geometry : openmc.universe.Geometry
|
||||
Equivalent OpenMC geometry
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(opencg_geometry, opencg.Geometry):
|
||||
msg = 'Unable to get OpenMC geometry from {0} which is ' \
|
||||
|
|
@ -849,8 +1062,8 @@ def get_openmc_geometry(opencg_geometry):
|
|||
# Make the entire geometry "compatible" before assigning auto IDs
|
||||
universes = opencg_geometry.getAllUniverses()
|
||||
for universe_id, universe in universes.items():
|
||||
if not isinstance(universe, opencg.Lattice):
|
||||
make_opencg_cells_compatible(universe)
|
||||
if not isinstance(universe, opencg.Lattice):
|
||||
make_opencg_cells_compatible(universe)
|
||||
|
||||
opencg_geometry.assignAutoIds()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,44 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import struct
|
||||
|
||||
|
||||
class Particle(object):
|
||||
"""Information used to restart a specific particle that caused a simulation to
|
||||
fail.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str
|
||||
Path to the particle restart file
|
||||
|
||||
Attributes
|
||||
----------
|
||||
filetype : int
|
||||
Integer indicating the file type
|
||||
revision : int
|
||||
Revision of the particle restart format
|
||||
current_batch : int
|
||||
The batch containing the particle
|
||||
gen_per_batch : int
|
||||
Number of generations per batch
|
||||
current_gen : int
|
||||
The generation containing the particle
|
||||
n_particles : int
|
||||
Number of particles per generation
|
||||
run_mode : int
|
||||
Type of simulation (criticality or fixed source)
|
||||
id : long
|
||||
Identifier of the particle
|
||||
weight : float
|
||||
Weight of the particle
|
||||
energy : float
|
||||
Energy of the particle in MeV
|
||||
xyz : list of float
|
||||
Position of the particle
|
||||
uvw : list of float
|
||||
Directional cosines of the particle
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, filename):
|
||||
if filename.endswith('.h5'):
|
||||
import h5py
|
||||
|
|
|
|||
409
openmc/plots.py
409
openmc/plots.py
|
|
@ -1,14 +1,21 @@
|
|||
from collections import Iterable
|
||||
from numbers import Real, Integral
|
||||
from xml.etree import ElementTree as ET
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
|
||||
from openmc.checkvalue import *
|
||||
from openmc.clean_xml import *
|
||||
from openmc.checkvalue import (check_type, check_value, check_length,
|
||||
check_greater_than, check_less_than)
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
# A static variable for auto-generated Plot IDs
|
||||
AUTO_PLOT_ID = 10000
|
||||
|
||||
|
||||
def reset_auto_plot_id():
|
||||
global AUTO_PLOT_ID
|
||||
AUTO_PLOT_ID = 10000
|
||||
|
|
@ -18,9 +25,50 @@ BASES = ['xy', 'xz', 'yz']
|
|||
|
||||
|
||||
class Plot(object):
|
||||
"""Definition of a finite region of space to be plotted, either as a slice plot
|
||||
in two dimensions or as a voxel plot in three dimensions.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
plot_id : int
|
||||
Unique identifier for the plot
|
||||
name : str
|
||||
Name of the plot
|
||||
|
||||
Attributes
|
||||
----------
|
||||
id : int
|
||||
Unique identifier
|
||||
name : str
|
||||
Name of the plot
|
||||
width : Iterable of float
|
||||
Width of the plot in each basis direction
|
||||
pixels : Iterable of int
|
||||
Number of pixels to use in each basis direction
|
||||
origin : tuple or list of ndarray
|
||||
Origin (center) of the plot
|
||||
filename :
|
||||
Path to write the plot to
|
||||
color : {'cell', 'mat'}
|
||||
Indicate whether the plot should be colored by cell or by material
|
||||
type : {'slice', 'voxel'}
|
||||
The type of the plot
|
||||
basis : {'xy', 'xz', 'yz'}
|
||||
The basis directions for the plot
|
||||
background : tuple or list of ndarray
|
||||
Color of the background defined by RGB
|
||||
mask_components : Iterable of int
|
||||
Unique id numbers of the cells or materials to plot
|
||||
mask_background : Iterable of int
|
||||
Color to apply to all cells/materials not listed in mask_components
|
||||
defined by RGB
|
||||
col_spec : dict
|
||||
Dictionary indicating that certain cells/materials (keys) should be
|
||||
colored with a specific RGB (values)
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, plot_id=None, name=''):
|
||||
|
||||
# Initialize Plot class attributes
|
||||
self.id = plot_id
|
||||
self.name = name
|
||||
|
|
@ -36,295 +84,139 @@ class Plot(object):
|
|||
self._mask_background = None
|
||||
self._col_spec = None
|
||||
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self._id
|
||||
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
return self._width
|
||||
|
||||
|
||||
@property
|
||||
def pixels(self):
|
||||
return self._pixels
|
||||
|
||||
|
||||
@property
|
||||
def origin(self):
|
||||
return self._origin
|
||||
|
||||
|
||||
@property
|
||||
def filename(self):
|
||||
return self._filename
|
||||
|
||||
|
||||
@property
|
||||
def color(self):
|
||||
return self._color
|
||||
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self._type
|
||||
|
||||
|
||||
@property
|
||||
def basis(self):
|
||||
return self._basis
|
||||
|
||||
|
||||
@property
|
||||
def background(self):
|
||||
return self._background
|
||||
|
||||
|
||||
@property
|
||||
def mask_componenets(self):
|
||||
return self._mask_components
|
||||
|
||||
|
||||
@property
|
||||
def mask_background(self):
|
||||
return self._mask_background
|
||||
|
||||
|
||||
@property
|
||||
def col_spec(self):
|
||||
return self._col_spec
|
||||
|
||||
|
||||
@id.setter
|
||||
def id(self, plot_id):
|
||||
|
||||
if plot_id is None:
|
||||
global AUTO_PLOT_ID
|
||||
self._id = AUTO_PLOT_ID
|
||||
AUTO_PLOT_ID += 1
|
||||
|
||||
# Check that the ID is an integer and wasn't already used
|
||||
elif not is_integer(plot_id):
|
||||
msg = 'Unable to set a non-integer Plot ID {0}'.format(plot_id)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif plot_id < 0:
|
||||
msg = 'Unable to set Plot ID to {0} since it must be a ' \
|
||||
'non-negative integer'.format(plot_id)
|
||||
raise ValueError(msg)
|
||||
|
||||
else:
|
||||
check_type('plot ID', plot_id, Integral)
|
||||
check_greater_than('plot ID', plot_id, 0)
|
||||
self._id = plot_id
|
||||
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
|
||||
if not is_string(name):
|
||||
msg = 'Unable to set name for Plot ID={0} with a non-string ' \
|
||||
'value {1}'.format(self._id, name)
|
||||
raise ValueError(msg)
|
||||
|
||||
else:
|
||||
self._name = name
|
||||
|
||||
check_type('plot name', name, basestring)
|
||||
self._name = name
|
||||
|
||||
@width.setter
|
||||
def width(self, width):
|
||||
|
||||
if not isinstance(width, (tuple, list, np.ndarray)):
|
||||
msg = 'Unable to create Plot ID={0} with width {1} which is not ' \
|
||||
'a Python tuple/list or NumPy array'.format(self._id, width)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif len(width) != 2 and len(width) != 3:
|
||||
msg = 'Unable to create Plot ID={0} with width {1} since only 2D ' \
|
||||
'and 3D plots are supported'.format(self._id, width)
|
||||
raise ValueError(msg)
|
||||
|
||||
for dim in width:
|
||||
if not is_integer(dim) and not is_float(dim):
|
||||
msg = 'Unable to create Plot ID={0} with width {1} since ' \
|
||||
'each element must be a floating point value or ' \
|
||||
'integer'.format(self._id, width)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('plot width', width, Iterable, Real)
|
||||
check_length('plot width', width, 2, 3)
|
||||
self._width = width
|
||||
|
||||
|
||||
@origin.setter
|
||||
def origin(self, origin):
|
||||
|
||||
if not isinstance(origin, (tuple, list, np.ndarray)):
|
||||
msg = 'Unable to create Plot ID={0} with origin {1} which is not ' \
|
||||
'a Python tuple/list or NumPy array'.format(self._id, origin)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif len(origin) != 3:
|
||||
msg = 'Unable to create Plot ID={0} with origin {1} since only ' \
|
||||
'a 3D coordinate must be input'.format(self._id, origin)
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
for dim in origin:
|
||||
if not is_integer(dim) and not is_float(dim):
|
||||
msg = 'Unable to create Plot ID={0} with origin {1} since ' \
|
||||
'each element must be a floating point value or ' \
|
||||
'integer'.format(self._id, origin)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('plot origin', origin, Iterable, Real)
|
||||
check_length('plot origin', origin, 3)
|
||||
self._origin = origin
|
||||
|
||||
|
||||
@pixels.setter
|
||||
def pixels(self, pixels):
|
||||
|
||||
if not isinstance(pixels, (tuple, list, np.ndarray)):
|
||||
msg = 'Unable to create Plot ID={0} with pixels {1} which is not ' \
|
||||
'a Python tuple/list or NumPy array'.format(self._id, pixels)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif len(pixels) != 2 and len(pixels) != 3:
|
||||
msg = 'Unable to create Plot ID={0} with pixels {1} since ' \
|
||||
'only 2D and 3D plots are supported'.format(self._id, pixels)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('plot pixels', pixels, Iterable, Integral)
|
||||
check_length('plot pixels', pixels, 2, 3)
|
||||
for dim in pixels:
|
||||
|
||||
if not is_integer(dim):
|
||||
msg = 'Unable to create Plot ID={0} with pixel value {1} ' \
|
||||
'which is not an integer'.format(self._id, dim)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif dim < 0:
|
||||
msg = 'Unable to create Plot ID={0} with pixel value {1} ' \
|
||||
'which is less than 0'.format(self._id, dim)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_greater_than('plot pixels', dim, 0)
|
||||
self._pixels = pixels
|
||||
|
||||
|
||||
@filename.setter
|
||||
def filename(self, filename):
|
||||
|
||||
if not is_string(filename):
|
||||
msg = 'Unable to create Plot ID={0} with filename {1} which is ' \
|
||||
'not a string'.format(self._id, filename)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('filename', filename, basestring)
|
||||
self._filename = filename
|
||||
|
||||
|
||||
@color.setter
|
||||
def color(self, color):
|
||||
|
||||
if not is_string(color):
|
||||
msg = 'Unable to create Plot ID={0} with color {1} which is not ' \
|
||||
'a string'.format(self._id, color)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif not color in ['cell', 'mat']:
|
||||
msg = 'Unable to create Plot ID={0} with color {1} which is not ' \
|
||||
'a cell or mat'.format(self._id, color)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('plot color', color, basestring)
|
||||
check_value('plot color', color, ['cell', 'mat'])
|
||||
self._color = color
|
||||
|
||||
|
||||
@type.setter
|
||||
def type(self, type):
|
||||
|
||||
if not is_string(type):
|
||||
msg = 'Unable to create Plot ID={0} with type {1} which is not ' \
|
||||
'a string'.format(self._id, type)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif not type in ['slice', 'voxel']:
|
||||
msg = 'Unable to create Plot ID={0} with type {1} which is not ' \
|
||||
'slice or voxel'.format(self._id, type)
|
||||
raise ValueError(msg)
|
||||
|
||||
self._type = type
|
||||
|
||||
def type(self, plottype):
|
||||
check_type('plot type', plottype, basestring)
|
||||
check_value('plot type', plottype, ['slice', 'voxel'])
|
||||
self._type = plottype
|
||||
|
||||
@basis.setter
|
||||
def basis(self, basis):
|
||||
|
||||
if not is_string(basis):
|
||||
msg = 'Unable to create Plot ID={0} with basis {1} which is not ' \
|
||||
'a string'.format(self._id, basis)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif not basis in ['xy', 'xz', 'yz']:
|
||||
msg = 'Unable to create Plot ID={0} with basis {1} which is not ' \
|
||||
'xy, xz, or yz'.format(self._id, basis)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('plot basis', basis, basestring)
|
||||
check_value('plot basis', basis, ['xy', 'xz', 'yz'])
|
||||
self._basis = basis
|
||||
|
||||
|
||||
@background.setter
|
||||
def background(self, background):
|
||||
|
||||
if not isinstance(background, (tuple, list, np.ndarray)):
|
||||
msg = 'Unable to create Plot ID={0} with background {1} ' \
|
||||
'which is not a Python tuple/list or NumPy ' \
|
||||
'array'.format(self._id, background)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif len(background) != 3:
|
||||
msg = 'Unable to create Plot ID={0} with background {1} ' \
|
||||
'which is not 3 integer RGB ' \
|
||||
'values'.format(self._id, background)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('plot background', background, Iterable, Integral)
|
||||
check_length('plot background', background, 3)
|
||||
for rgb in background:
|
||||
|
||||
if not is_integer(rgb):
|
||||
msg = 'Unable to create Plot ID={0} with background RGB ' \
|
||||
'value {1} which is not an integer'.format(self._id, rgb)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif rgb < 0 or rgb > 255:
|
||||
msg = 'Unable to create Plot ID={0} with background RGB value ' \
|
||||
'{1} which is not between 0 and 255'.format(self._id, rgb)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_greater_than('plot background',rgb, 0, True)
|
||||
check_less_than('plot background', rgb, 256)
|
||||
self._background = background
|
||||
|
||||
|
||||
@col_spec.setter
|
||||
def col_spec(self, col_spec):
|
||||
|
||||
if not isinstance(col_spec, dict):
|
||||
msg= 'Unable to create Plot ID={0} with col_spec parameter {1} ' \
|
||||
'which is not a Python dictionary of IDs to ' \
|
||||
'pixels'.format(self._id, col_spec)
|
||||
raise ValueError(msg)
|
||||
check_type('plot col_spec parameter', col_spec, dict, Integral)
|
||||
|
||||
for key in col_spec:
|
||||
|
||||
if not is_integer(key):
|
||||
msg = 'Unable to create Plot ID={0} with col_spec ID {1} ' \
|
||||
'which is not an integer'.format(self._id, key)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif key < 0:
|
||||
if key < 0:
|
||||
msg = 'Unable to create Plot ID={0} with col_spec ID {1} ' \
|
||||
'which is less than 0'.format(self._id, key)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif not isinstance(col_spec[key], (tuple, list, np.ndarray)):
|
||||
msg = 'Unable to create Plot ID={0} with col_spec RGB ' \
|
||||
'values {1} which is not a Python tuple/list or NumPy ' \
|
||||
'array'.format(self._id, col_spec[key])
|
||||
elif not isinstance(col_spec[key], Iterable):
|
||||
msg = 'Unable to create Plot ID={0} with col_spec RGB values' \
|
||||
' {1} which is not iterable'.format(self._id, col_spec[key])
|
||||
raise ValueError(msg)
|
||||
|
||||
elif len(col_spec[key]) != 3:
|
||||
|
|
@ -335,63 +227,23 @@ class Plot(object):
|
|||
|
||||
self._col_spec = col_spec
|
||||
|
||||
|
||||
@mask_componenets.setter
|
||||
def mask_components(self, mask_components):
|
||||
|
||||
if not isinstance(mask_components, (list, tuple, np.ndarray)):
|
||||
msg = 'Unable to create Plot ID={0} with mask components {1} ' \
|
||||
'which is not a Python tuple/list or NumPy ' \
|
||||
'array'.format(self._id, mask_components)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('plot mask_components', mask_components, Iterable, Integral)
|
||||
for component in mask_components:
|
||||
if not is_integer(component):
|
||||
msg = 'Unable to create Plot ID={0} with mask component {1} ' \
|
||||
'which is not an integer'.format(self._id, component)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif component < 0:
|
||||
msg = 'Unable to create Plot ID={0} with mask component {1} ' \
|
||||
'which is less than 0'.format(self._id, component)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_greater_than('plot mask_components', component, 0, True)
|
||||
self._mask_components = mask_components
|
||||
|
||||
|
||||
@mask_background.setter
|
||||
def mask_background(self, mask_background):
|
||||
|
||||
if not isinstance(mask_background, (list, tuple, np.ndarray)):
|
||||
msg = 'Unable to create Plot ID={0} with mask background {1} ' \
|
||||
'which is not a Python tuple/list or NumPy ' \
|
||||
'array'.format(self._id, mask_background)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif len(mask_background) != 3 and len(mask_background) != 0:
|
||||
msg = 'Unable to create Plot ID={0} with mask background ' \
|
||||
'{1} since 3 RGB values must be ' \
|
||||
'input'.format(self._id, mask_background)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('plot mask background', mask_background, Iterable, Integral)
|
||||
check_length('plot mask background', mask_background, 3)
|
||||
for rgb in mask_background:
|
||||
|
||||
if not is_integer(rgb):
|
||||
msg = 'Unable to create Plot ID={0} with mask background RGB ' \
|
||||
'value {1} which is not an integer'.format(self._id, rgb)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif rgb < 0 or rgb > 255:
|
||||
msg = 'Unable to create Plot ID={0} with mask bacground ' \
|
||||
'RGB value {1} which is not between 0 and ' \
|
||||
'255'.format(self._id, rgb)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_greater_than('plot mask background', rgb, 0, True)
|
||||
check_less_than('plot mask background', rgb, 256)
|
||||
self._mask_background = mask_background
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
string = 'Plot\n'
|
||||
string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name)
|
||||
|
|
@ -409,8 +261,15 @@ class Plot(object):
|
|||
string += '{0: <16}{1}{2}\n'.format('\tCol Spec', '=\t', self._col_spec)
|
||||
return string
|
||||
|
||||
|
||||
def get_plot_xml(self):
|
||||
"""Return XML representation of the plot
|
||||
|
||||
Returns
|
||||
-------
|
||||
element : xml.etree.ElementTree.Element
|
||||
XML element containing plot data
|
||||
|
||||
"""
|
||||
|
||||
element = ET.Element("plot")
|
||||
element.set("id", str(self._id))
|
||||
|
|
@ -422,64 +281,55 @@ class Plot(object):
|
|||
element.set("basis", self._basis)
|
||||
|
||||
subelement = ET.SubElement(element, "origin")
|
||||
text = ''
|
||||
for coord in self._origin:
|
||||
text += str(coord) + ' '
|
||||
subelement.text = text.rstrip(' ')
|
||||
subelement.text = ' '.join(map(str, self._origin))
|
||||
|
||||
subelement = ET.SubElement(element, "width")
|
||||
text = ''
|
||||
for dim in self._width:
|
||||
text += str(dim) + ' '
|
||||
subelement.text = text.rstrip(' ')
|
||||
subelement.text = ' '.join(map(str, self._width))
|
||||
|
||||
subelement = ET.SubElement(element, "pixels")
|
||||
text = ''
|
||||
for dim in self._pixels:
|
||||
text += str(dim) + ' '
|
||||
subelement.text = text.rstrip(' ')
|
||||
subelement.text = ' '.join(map(str, self._pixels))
|
||||
|
||||
if not self._mask_background is None:
|
||||
if self._mask_background is not None:
|
||||
subelement = ET.SubElement(element, "background")
|
||||
text = ''
|
||||
for rgb in self._background:
|
||||
text += str(rgb) + ' '
|
||||
subelement.text = text.rstrip(' ')
|
||||
|
||||
if not self._col_spec is None:
|
||||
subelement.text = ' '.join(map(str, self._background))
|
||||
|
||||
if self._col_spec is not None:
|
||||
for key in self._col_spec:
|
||||
subelement = ET.SubElement(element, "col_spec")
|
||||
subelement.set("id", '{0}'.format(key))
|
||||
value = self._col_spec[key]
|
||||
subelement.set("rgb",'{0} {1} {2}'.format(value[0],
|
||||
value[1], value[2]))
|
||||
subelement.set("id", str(key))
|
||||
subelement.set("rgb", ' '.join(map(
|
||||
str, self._col_spec[key])))
|
||||
|
||||
if not self._mask_components is None:
|
||||
if self._mask_components is not None:
|
||||
subelement = ET.SubElement(element, "mask")
|
||||
|
||||
text = ''
|
||||
for id in self._mask_components:
|
||||
text += str(id) + ' '
|
||||
subelement.set("components", text.rstrip(' '))
|
||||
|
||||
rgb = self._mask_background
|
||||
subelement.set("background", '{0} {1} {2}'.format(rgb[0],
|
||||
rgb[1], rgb[2]))
|
||||
subelement.set("components", ' '.join(map(
|
||||
str, self._mask_components)))
|
||||
subelement.set("background", ' '.join(map(
|
||||
str, self._mask_background)))
|
||||
|
||||
return element
|
||||
|
||||
|
||||
class PlotsFile(object):
|
||||
"""Plots file used for an OpenMC simulation. Corresponds directly to the
|
||||
plots.xml input file.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
# Initialize PlotsFile class attributes
|
||||
self._plots = []
|
||||
self._plots_file = ET.Element("plots")
|
||||
|
||||
|
||||
def add_plot(self, plot):
|
||||
"""Add a plot to the file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
plot : Plot
|
||||
Plot to add
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(plot, Plot):
|
||||
msg = 'Unable to add a non-Plot {0} to the PlotsFile'.format(plot)
|
||||
|
|
@ -487,15 +337,20 @@ class PlotsFile(object):
|
|||
|
||||
self._plots.append(plot)
|
||||
|
||||
|
||||
def remove_plot(self, plot):
|
||||
"""Remove a plot from the file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
plot : Plot
|
||||
Plot to remove
|
||||
|
||||
"""
|
||||
|
||||
self._plots.remove(plot)
|
||||
|
||||
|
||||
def create_plot_subelements(self):
|
||||
|
||||
def _create_plot_subelements(self):
|
||||
for plot in self._plots:
|
||||
|
||||
xml_element = plot.get_plot_xml()
|
||||
|
||||
if len(plot._name) > 0:
|
||||
|
|
@ -503,10 +358,12 @@ class PlotsFile(object):
|
|||
|
||||
self._plots_file.append(xml_element)
|
||||
|
||||
|
||||
def export_to_xml(self):
|
||||
"""Create a plots.xml file that can be used by OpenMC.
|
||||
|
||||
self.create_plot_subelements()
|
||||
"""
|
||||
|
||||
self._create_plot_subelements()
|
||||
|
||||
# Clean the indentation in the file to be user-readable
|
||||
clean_xml_indentation(self._plots_file)
|
||||
|
|
|
|||
1360
openmc/settings.py
1360
openmc/settings.py
File diff suppressed because it is too large
Load diff
|
|
@ -13,17 +13,28 @@ if sys.version > '3':
|
|||
|
||||
|
||||
class SourceSite(object):
|
||||
"""A single source site produced from fission.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
weight : float
|
||||
Weight of the particle arising from the site
|
||||
xyz : list of float
|
||||
Cartesian coordinates of the site
|
||||
uvw : list of float
|
||||
Directional cosines for particles emerging from the site
|
||||
E : float
|
||||
Energy of the emerging particle in MeV
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self._weight = None
|
||||
self._xyz = None
|
||||
self._uvw = None
|
||||
self._E = None
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
string = 'SourceSite\n'
|
||||
string += '{0: <16}{1}{2}\n'.format('\tweight', '=\t', self._weight)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tE', '=\t', self._E)
|
||||
|
|
@ -31,32 +42,56 @@ class SourceSite(object):
|
|||
string += '{0: <16}{1}{2}\n'.format('\t(u,v,w)', '=\t', self._uvw)
|
||||
return string
|
||||
|
||||
|
||||
@property
|
||||
def weight(self):
|
||||
return self._weight
|
||||
|
||||
|
||||
@property
|
||||
def xyz(self):
|
||||
return self._xyz
|
||||
|
||||
|
||||
@property
|
||||
def uvw(self):
|
||||
return self._uvw
|
||||
|
||||
|
||||
@property
|
||||
def E(self):
|
||||
return self._E
|
||||
|
||||
|
||||
|
||||
class StatePoint(object):
|
||||
"""State information on a simulation at a certain point in time (at the end of a
|
||||
given batch). Statepoints can be used to analyze tally results as well as
|
||||
restart a simulation.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
k_combined : list
|
||||
Combined estimator for k-effective and its uncertainty
|
||||
n_particles : int
|
||||
Number of particles per generation
|
||||
n_batches : int
|
||||
Number of batches
|
||||
current_batch :
|
||||
Number of batches simulated
|
||||
results : bool
|
||||
Indicate whether tally results have been read
|
||||
source : ndarray of SourceSite
|
||||
Array of source sites
|
||||
with_summary : bool
|
||||
Indicate whether statepoint data has been linked against a summary file
|
||||
tallies : dict
|
||||
Dictionary whose keys are tally IDs and whose values are Tally objects
|
||||
tallies_present : bool
|
||||
Indicate whether user-defined tallies are present
|
||||
global_tallies : ndarray
|
||||
Global tallies and their uncertainties
|
||||
n_realizations : int
|
||||
Number of tally realizations
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, filename):
|
||||
|
||||
if filename.endswith('.h5'):
|
||||
import h5py
|
||||
self._f = h5py.File(filename, 'r')
|
||||
|
|
@ -79,7 +114,6 @@ class StatePoint(object):
|
|||
# Read tally metadata
|
||||
self._read_tallies()
|
||||
|
||||
|
||||
def close(self):
|
||||
self._f.close()
|
||||
|
||||
|
|
@ -128,7 +162,6 @@ class StatePoint(object):
|
|||
return self._n_realizations
|
||||
|
||||
def _read_metadata(self):
|
||||
|
||||
# Read filetype
|
||||
self._filetype = self._get_int(path='filetype')[0]
|
||||
|
||||
|
|
@ -169,9 +202,7 @@ class StatePoint(object):
|
|||
if self._run_mode == 2:
|
||||
self._read_criticality()
|
||||
|
||||
|
||||
def _read_criticality(self):
|
||||
|
||||
# Read criticality information
|
||||
if self._run_mode == 2:
|
||||
|
||||
|
|
@ -191,9 +222,7 @@ class StatePoint(object):
|
|||
# Read CMFD information (if used)
|
||||
self._read_cmfd()
|
||||
|
||||
|
||||
def _read_cmfd(self):
|
||||
|
||||
base = 'cmfd'
|
||||
|
||||
# Read CMFD information
|
||||
|
|
@ -217,9 +246,7 @@ class StatePoint(object):
|
|||
self._cmfd_srccmp = self._get_double(self._current_batch,
|
||||
path='{0}/cmfd_srccmp'.format(base))
|
||||
|
||||
|
||||
def _read_meshes(self):
|
||||
|
||||
# Initialize dictionaries for the Meshes
|
||||
# Keys - Mesh IDs
|
||||
# Values - Mesh objects
|
||||
|
|
@ -282,9 +309,7 @@ class StatePoint(object):
|
|||
# Add mesh to the global dictionary of all Meshes
|
||||
self._meshes[mesh_id] = mesh
|
||||
|
||||
|
||||
def _read_tallies(self):
|
||||
|
||||
# Initialize dictionaries for the Tallies
|
||||
# Keys - Tally IDs
|
||||
# Values - Tally objects
|
||||
|
|
@ -423,7 +448,6 @@ class StatePoint(object):
|
|||
|
||||
# Add the scores to the Tally
|
||||
for j, score in enumerate(scores):
|
||||
|
||||
# If this is a scattering moment, insert the scattering order
|
||||
if '-n' in score:
|
||||
score = score.replace('-n', '-' + str(moments[j]))
|
||||
|
|
@ -437,10 +461,13 @@ class StatePoint(object):
|
|||
# Add Tally to the global dictionary of all Tallies
|
||||
self.tallies[tally_key] = tally
|
||||
|
||||
|
||||
def read_results(self):
|
||||
"""Read tally results and store them in the ``tallies`` attribute. No results
|
||||
are read when the statepoint is instantiated.
|
||||
|
||||
# Number of realizations for global Tallies
|
||||
"""
|
||||
|
||||
# Number of realizations for global Tallies
|
||||
self._n_realizations = self._get_int(path='n_realizations')[0]
|
||||
|
||||
# Read global Tallies
|
||||
|
|
@ -483,7 +510,8 @@ class StatePoint(object):
|
|||
sum_sq = results[1::2]
|
||||
|
||||
# Define a routine to convert 0 to 1
|
||||
nonzero = lambda val: 1 if not val else val
|
||||
def nonzero(val):
|
||||
return 1 if not val else val
|
||||
|
||||
# Reshape the results arrays
|
||||
new_shape = (nonzero(tally.num_filter_bins),
|
||||
|
|
@ -494,13 +522,17 @@ class StatePoint(object):
|
|||
sum_sq = np.reshape(sum_sq, new_shape)
|
||||
|
||||
# Set the data for this Tally
|
||||
tally.set_results(sum=sum, sum_sq=sum_sq)
|
||||
tally.sum = sum
|
||||
tally.sum_sq = sum_sq
|
||||
|
||||
# Indicate that Tally results have been read
|
||||
self._results = True
|
||||
|
||||
|
||||
def read_source(self):
|
||||
"""Read and store source sites from the statepoint file. By default, source
|
||||
sites are not loaded upon initialization.
|
||||
|
||||
"""
|
||||
|
||||
# Check whether Tally results have been read
|
||||
if not self._results:
|
||||
|
|
@ -520,7 +552,6 @@ class StatePoint(object):
|
|||
|
||||
# Initialize SourceSite object for each particle
|
||||
for i in range(self._n_particles):
|
||||
|
||||
# Initialize new source site
|
||||
site = SourceSite()
|
||||
|
||||
|
|
@ -536,9 +567,18 @@ class StatePoint(object):
|
|||
# Store the source site in the NumPy array
|
||||
self._source[i] = site
|
||||
|
||||
|
||||
def compute_ci(self, confidence=0.95):
|
||||
"""Computes confidence intervals for each Tally bin."""
|
||||
"""Computes confidence intervals for each Tally bin.
|
||||
|
||||
This method is equivalent to calling compute_stdev(...) when the
|
||||
confidence is known as opposed to its corresponding t value.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
confidence : float, optional
|
||||
Confidence level. Defaults to 0.95.
|
||||
|
||||
"""
|
||||
|
||||
# Determine significance level and percentile for two-sided CI
|
||||
alpha = 1 - confidence
|
||||
|
|
@ -548,11 +588,16 @@ class StatePoint(object):
|
|||
t_value = scipy.stats.t.ppf(percentile, self._n_realizations - 1)
|
||||
self.compute_stdev(t_value)
|
||||
|
||||
|
||||
def compute_stdev(self, t_value=1.0):
|
||||
"""
|
||||
Computes the sample mean and the standard deviation of the mean
|
||||
"""Computes the sample mean and the standard deviation of the mean
|
||||
for each Tally bin.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
t_value : float, optional
|
||||
Student's t-value applied to the uncertainty. Defaults to 1.0,
|
||||
meaning the reported value is the sample standard deviation.
|
||||
|
||||
"""
|
||||
|
||||
# Determine number of realizations
|
||||
|
|
@ -572,49 +617,45 @@ class StatePoint(object):
|
|||
if s != 0.0:
|
||||
self._global_tallies[i, 1] = t_value * np.sqrt((s2 / n - s**2) / (n-1))
|
||||
|
||||
|
||||
# Calculate sample mean and standard deviation for user-defined Tallies
|
||||
for tally_id, tally in self.tallies.items():
|
||||
tally.compute_std_dev(t_value)
|
||||
|
||||
|
||||
def get_tally(self, scores=[], filters=[], nuclides=[],
|
||||
name=None, id=None, estimator=None):
|
||||
"""Finds and returns a Tally object with certain properties.
|
||||
|
||||
This routine searches the list of Tallies and returns the first Tally
|
||||
found it finds which satisfieds all of the input parameters.
|
||||
found it finds which satisfies all of the input parameters.
|
||||
NOTE: The input parameters do not need to match the complete Tally
|
||||
specification and may only represent a subset of the Tallies properties.
|
||||
specification and may only represent a subset of the Tally's properties.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scores : list
|
||||
A list of one or more score strings (default is []).
|
||||
|
||||
filters : list
|
||||
A list of Filter objects (default is []).
|
||||
|
||||
nuclides : list
|
||||
A list of Nuclide objects (default is []).
|
||||
|
||||
name : str
|
||||
The name specified for the Tally (default is None).
|
||||
|
||||
id : int
|
||||
The id specified for the Tally (default is None).
|
||||
|
||||
estimator: str
|
||||
The type of estimator ('tracklength', 'analog'; default is None).
|
||||
scores : list, optional
|
||||
A list of one or more score strings (default is []).
|
||||
filters : list, optional
|
||||
A list of Filter objects (default is []).
|
||||
nuclides : list, optional
|
||||
A list of Nuclide objects (default is []).
|
||||
name : str, optional
|
||||
The name specified for the Tally (default is None).
|
||||
id : int, optional
|
||||
The id specified for the Tally (default is None).
|
||||
estimator: str, optional
|
||||
The type of estimator ('tracklength', 'analog'; default is None).
|
||||
|
||||
Returns
|
||||
-------
|
||||
A Tally object.
|
||||
tally : Tally
|
||||
A tally matching the specified criteria
|
||||
|
||||
Raises
|
||||
------
|
||||
LookupError : An error when a Tally meeting all of the input
|
||||
parameters cannot be found in the statepoint.
|
||||
LookupError
|
||||
If a Tally meeting all of the input parameters cannot be found in
|
||||
the statepoint.
|
||||
|
||||
"""
|
||||
|
||||
tally = None
|
||||
|
|
@ -640,7 +681,7 @@ class StatePoint(object):
|
|||
|
||||
# Iterate over the scores requested by the user
|
||||
for score in scores:
|
||||
if not score in test_tally.scores:
|
||||
if score not in test_tally.scores:
|
||||
contains_scores = False
|
||||
break
|
||||
|
||||
|
|
@ -653,7 +694,7 @@ class StatePoint(object):
|
|||
|
||||
# Iterate over the Filters requested by the user
|
||||
for filter in filters:
|
||||
if not filter in test_tally.filters:
|
||||
if filter not in test_tally.filters:
|
||||
contains_filters = False
|
||||
break
|
||||
|
||||
|
|
@ -666,7 +707,7 @@ class StatePoint(object):
|
|||
|
||||
# Iterate over the Nuclides requested by the user
|
||||
for nuclide in nuclides:
|
||||
if not nuclide in test_tally.nuclides:
|
||||
if nuclide not in test_tally.nuclides:
|
||||
contains_nuclides = False
|
||||
break
|
||||
|
||||
|
|
@ -683,14 +724,15 @@ class StatePoint(object):
|
|||
|
||||
return tally
|
||||
|
||||
|
||||
def link_with_summary(self, summary):
|
||||
"""Links Tallies and Filters with Summary model information.
|
||||
|
||||
This routine retrieves model information (materials, geometry) from a
|
||||
Summary object populated with an HDF5 'summary.h5' file and inserts
|
||||
it into the Tally objects. This can be helpful when viewing and
|
||||
manipulating large scale Tally data.
|
||||
Summary object populated with an HDF5 'summary.h5' file and inserts it
|
||||
into the Tally objects. This can be helpful when viewing and
|
||||
manipulating large scale Tally data. Note that it is necessary to link
|
||||
against a summary to populate the Tallies with any user-specified "name"
|
||||
XML tags.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
|
@ -699,8 +741,10 @@ class StatePoint(object):
|
|||
|
||||
Raises
|
||||
------
|
||||
ValueError : An error when the argument passed to the 'summary'
|
||||
parameter is not an openmc.Summary object.
|
||||
ValueError
|
||||
An error when the argument passed to the 'summary' parameter is not
|
||||
an openmc.Summary object.
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(summary, openmc.summary.Summary):
|
||||
|
|
@ -709,7 +753,6 @@ class StatePoint(object):
|
|||
raise ValueError(msg)
|
||||
|
||||
for tally_id, tally in self.tallies.items():
|
||||
|
||||
# Get the Tally name from the summary file
|
||||
tally.name = summary.tallies[tally_id].name
|
||||
tally.with_summary = True
|
||||
|
|
@ -717,7 +760,6 @@ class StatePoint(object):
|
|||
nuclide_zaids = copy.deepcopy(tally.nuclides)
|
||||
|
||||
for nuclide_zaid in nuclide_zaids:
|
||||
|
||||
tally.remove_nuclide(nuclide_zaid)
|
||||
if nuclide_zaid == -1:
|
||||
tally.add_nuclide(openmc.Nuclide('total'))
|
||||
|
|
@ -725,7 +767,6 @@ class StatePoint(object):
|
|||
tally.add_nuclide(summary.nuclides[nuclide_zaid])
|
||||
|
||||
for filter in tally.filters:
|
||||
|
||||
if filter.type == 'surface':
|
||||
surface_ids = []
|
||||
for bin in filter.bins:
|
||||
|
|
@ -749,12 +790,11 @@ class StatePoint(object):
|
|||
for bin in filter.bins:
|
||||
material_ids.append(summary.materials[bin].id)
|
||||
filter.bins = material_ids
|
||||
|
||||
|
||||
self._with_summary = True
|
||||
|
||||
|
||||
def _get_data(self, n, typeCode, size):
|
||||
return list(struct.unpack('={0}{1}'.format(n,typeCode),
|
||||
return list(struct.unpack('={0}{1}'.format(n, typeCode),
|
||||
self._f.read(n*size)))
|
||||
|
||||
def _get_int(self, n=1, path=None):
|
||||
|
|
|
|||
|
|
@ -2,16 +2,18 @@ import numpy as np
|
|||
|
||||
import openmc
|
||||
|
||||
try:
|
||||
import h5py
|
||||
except ImportError:
|
||||
msg = 'Unable to import h5py which is needed by openmc.summary'
|
||||
raise ImportError(msg)
|
||||
|
||||
|
||||
class Summary(object):
|
||||
"""Information summarizing the geometry, materials, and tallies used in a
|
||||
simulation.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, filename):
|
||||
# A user may not have h5py, but they can still use the rest of the
|
||||
# Python API so we'll only try to import h5py if the user actually inits
|
||||
# a Summary object.
|
||||
import h5py
|
||||
|
||||
openmc.reset_auto_ids()
|
||||
|
||||
|
|
@ -27,9 +29,7 @@ class Summary(object):
|
|||
self._read_geometry()
|
||||
self._read_tallies()
|
||||
|
||||
|
||||
def _read_metadata(self):
|
||||
|
||||
# Read OpenMC version
|
||||
self.version = [self._f['version_major'][0],
|
||||
self._f['version_minor'][0],
|
||||
|
|
@ -44,9 +44,7 @@ class Summary(object):
|
|||
self.gen_per_batch = self._f['gen_per_batch'][0]
|
||||
self.n_procs = self._f['n_procs'][0]
|
||||
|
||||
|
||||
def _read_geometry(self):
|
||||
|
||||
# Read in and initialize the Materials and Geometry
|
||||
self._read_nuclides()
|
||||
self._read_materials()
|
||||
|
|
@ -56,9 +54,7 @@ class Summary(object):
|
|||
self._read_lattices()
|
||||
self._finalize_geometry()
|
||||
|
||||
|
||||
def _read_nuclides(self):
|
||||
|
||||
self.n_nuclides = self._f['nuclides/n_nuclides'][0]
|
||||
|
||||
# Initialize dictionary for each Nuclide
|
||||
|
|
@ -67,7 +63,6 @@ class Summary(object):
|
|||
self.nuclides = {}
|
||||
|
||||
for key in self._f['nuclides'].keys():
|
||||
|
||||
if key == 'n_nuclides':
|
||||
continue
|
||||
|
||||
|
|
@ -88,9 +83,7 @@ class Summary(object):
|
|||
self.nuclides[zaid] = openmc.Nuclide(name=name, xs=xs)
|
||||
self.nuclides[zaid].zaid = zaid
|
||||
|
||||
|
||||
def _read_materials(self):
|
||||
|
||||
self.n_materials = self._f['materials/n_materials'][0]
|
||||
|
||||
# Initialize dictionary for each Material
|
||||
|
|
@ -99,7 +92,6 @@ class Summary(object):
|
|||
self.materials = {}
|
||||
|
||||
for key in self._f['materials'].keys():
|
||||
|
||||
if key == 'n_materials':
|
||||
continue
|
||||
|
||||
|
|
@ -116,7 +108,6 @@ class Summary(object):
|
|||
|
||||
# Read the names of the S(a,b) tables for this Material
|
||||
for i in range(1, n_sab+1):
|
||||
|
||||
sab_table = self._f['materials'][key]['sab_tables'][str(i)][0]
|
||||
|
||||
# Read the cross-section identifiers for each S(a,b) table
|
||||
|
|
@ -148,9 +139,7 @@ class Summary(object):
|
|||
# Add the Material to the global dictionary of all Materials
|
||||
self.materials[index] = material
|
||||
|
||||
|
||||
def _read_surfaces(self):
|
||||
|
||||
self.n_surfaces = self._f['geometry/n_surfaces'][0]
|
||||
|
||||
# Initialize dictionary for each Surface
|
||||
|
|
@ -159,7 +148,6 @@ class Summary(object):
|
|||
self.surfaces = {}
|
||||
|
||||
for key in self._f['geometry/surfaces'].keys():
|
||||
|
||||
if key == 'n_surfaces':
|
||||
continue
|
||||
|
||||
|
|
@ -171,7 +159,6 @@ class Summary(object):
|
|||
coeffs = self._f['geometry/surfaces'][key]['coefficients'][...]
|
||||
|
||||
# Create the Surface based on its type
|
||||
|
||||
if surf_type == 'X Plane':
|
||||
x0 = coeffs[0]
|
||||
surface = openmc.XPlane(surface_id, bc, x0, name)
|
||||
|
|
@ -232,9 +219,7 @@ class Summary(object):
|
|||
# Add Surface to global dictionary of all Surfaces
|
||||
self.surfaces[index] = surface
|
||||
|
||||
|
||||
def _read_cells(self):
|
||||
|
||||
self.n_cells = self._f['geometry/n_cells'][0]
|
||||
|
||||
# Initialize dictionary for each Cell
|
||||
|
|
@ -251,7 +236,6 @@ class Summary(object):
|
|||
self._cell_fills = {}
|
||||
|
||||
for key in self._f['geometry/cells'].keys():
|
||||
|
||||
if key == 'n_cells':
|
||||
continue
|
||||
|
||||
|
|
@ -310,9 +294,7 @@ class Summary(object):
|
|||
# Add the Cell to the global dictionary of all Cells
|
||||
self.cells[index] = cell
|
||||
|
||||
|
||||
def _read_universes(self):
|
||||
|
||||
self.n_universes = self._f['geometry/n_universes'][0]
|
||||
|
||||
# Initialize dictionary for each Universe
|
||||
|
|
@ -321,7 +303,6 @@ class Summary(object):
|
|||
self.universes = {}
|
||||
|
||||
for key in self._f['geometry/universes'].keys():
|
||||
|
||||
if key == 'n_universes':
|
||||
continue
|
||||
|
||||
|
|
@ -340,9 +321,7 @@ class Summary(object):
|
|||
# Add the Universe to the global list of Universes
|
||||
self.universes[index] = universe
|
||||
|
||||
|
||||
def _read_lattices(self):
|
||||
|
||||
self.n_lattices = self._f['geometry/n_lattices'][0]
|
||||
|
||||
# Initialize lattices for each Lattice
|
||||
|
|
@ -351,7 +330,6 @@ class Summary(object):
|
|||
self.lattices = {}
|
||||
|
||||
for key in self._f['geometry/lattices'].keys():
|
||||
|
||||
if key == 'n_lattices':
|
||||
continue
|
||||
|
||||
|
|
@ -383,7 +361,6 @@ class Summary(object):
|
|||
lattice.lower_left = lower_left
|
||||
lattice.pitch = pitch
|
||||
|
||||
|
||||
# If the Universe specified outer the Lattice is not void (-22)
|
||||
if outer != -22:
|
||||
lattice.outer = self.universes[outer]
|
||||
|
|
@ -395,14 +372,14 @@ class Summary(object):
|
|||
for x in range(universe_ids.shape[0]):
|
||||
for y in range(universe_ids.shape[1]):
|
||||
for z in range(universe_ids.shape[2]):
|
||||
universes[x,y,z] = \
|
||||
self.get_universe_by_id(universe_ids[x,y,z])
|
||||
universes[x, y, z] = \
|
||||
self.get_universe_by_id(universe_ids[x, y, z])
|
||||
|
||||
# Transpose, reverse y-dimension for appropriate ordering
|
||||
shape = universes.shape
|
||||
universes = np.transpose(universes, (1,0,2))
|
||||
universes = np.transpose(universes, (1, 0, 2))
|
||||
universes.shape = shape
|
||||
universes = universes[:,::-1,:]
|
||||
universes = universes[:, ::-1, :]
|
||||
lattice.universes = universes
|
||||
|
||||
if offset_size > 0:
|
||||
|
|
@ -420,8 +397,8 @@ class Summary(object):
|
|||
pitch = self._f['geometry/lattices'][key]['pitch'][...]
|
||||
outer = self._f['geometry/lattices'][key]['outer'][0]
|
||||
|
||||
universe_ids = \
|
||||
self._f['geometry/lattices'][key]['universes'][...]
|
||||
universe_ids = self._f[
|
||||
'geometry/lattices'][key]['universes'][...]
|
||||
|
||||
# Create the Lattice
|
||||
lattice = openmc.HexLattice(lattice_id=lattice_id, name=name)
|
||||
|
|
@ -441,9 +418,9 @@ class Summary(object):
|
|||
for i in range(universe_ids.shape[0]):
|
||||
for j in range(universe_ids.shape[1]):
|
||||
for k in range(universe_ids.shape[2]):
|
||||
if universe_ids[i,j,k] != -1:
|
||||
universes[i,j,k] = \
|
||||
self.get_universe_by_id(universe_ids[i,j,k])
|
||||
if universe_ids[i, j, k] != -1:
|
||||
universes[i, j, k] = self.get_universe_by_id(
|
||||
universe_ids[i, j, k])
|
||||
|
||||
if offset_size > 0:
|
||||
lattice.offsets = offsets
|
||||
|
|
@ -451,15 +428,12 @@ class Summary(object):
|
|||
# Add the Lattice to the global dictionary of all Lattices
|
||||
self.lattices[index] = lattice
|
||||
|
||||
|
||||
def _finalize_geometry(self):
|
||||
|
||||
# Initialize Geometry object
|
||||
self.openmc_geometry = openmc.Geometry()
|
||||
|
||||
# Iterate over all Cells and add fill Materials, Universes and Lattices
|
||||
for cell_key in self._cell_fills.keys():
|
||||
|
||||
# Determine fill type ('normal', 'universe', or 'lattice') and ID
|
||||
fill_type = self._cell_fills[cell_key][0]
|
||||
fill_id = self._cell_fills[cell_key][1]
|
||||
|
|
@ -482,16 +456,14 @@ class Summary(object):
|
|||
root_universe = self.get_universe_by_id(0)
|
||||
self.openmc_geometry.root_universe = root_universe
|
||||
|
||||
|
||||
def _read_tallies(self):
|
||||
|
||||
# Initialize dictionaries for the Tallies
|
||||
# Keys - Tally IDs
|
||||
# Values - Tally objects
|
||||
self.tallies = {}
|
||||
|
||||
# Read the number of tallies
|
||||
if not 'tallies' in self._f.keys():
|
||||
if 'tallies' not in self._f:
|
||||
self.n_tallies = 0
|
||||
return
|
||||
|
||||
|
|
@ -554,8 +526,11 @@ class Summary(object):
|
|||
# Add Tally to the global dictionary of all Tallies
|
||||
self.tallies[tally_id] = tally
|
||||
|
||||
|
||||
def make_opencg_geometry(self):
|
||||
"""Create OpenCG geometry based on the information contained in the summary
|
||||
file. The geometry is stored as the 'opencg_geometry' attribute.
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
from openmc.opencg_compatible import get_opencg_geometry
|
||||
|
|
@ -567,8 +542,22 @@ class Summary(object):
|
|||
if self.opencg_geometry is None:
|
||||
self.opencg_geometry = get_opencg_geometry(self.openmc_geometry)
|
||||
|
||||
|
||||
def get_nuclide_by_zaid(self, zaid):
|
||||
"""Return a Nuclide object given the 'zaid' identifier for the nuclide.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
zaid : int
|
||||
1000*Z + A, where Z is the atomic number of the nuclide and A is the
|
||||
mass number. For example, the zaid for U-235 is 92235.
|
||||
|
||||
Returns
|
||||
-------
|
||||
nuclide : openmc.nuclide.Nuclide or None
|
||||
Nuclide matching the specified zaid, or None if no matching object
|
||||
is found.
|
||||
|
||||
"""
|
||||
|
||||
for index, nuclide in self.nuclides.items():
|
||||
if nuclide._zaid == zaid:
|
||||
|
|
@ -576,8 +565,20 @@ class Summary(object):
|
|||
|
||||
return None
|
||||
|
||||
|
||||
def get_material_by_id(self, material_id):
|
||||
"""Return a Material object given the material id
|
||||
|
||||
Parameters
|
||||
----------
|
||||
id : int
|
||||
Unique identifier for the material
|
||||
|
||||
Returns
|
||||
-------
|
||||
material : openmc.material.Material
|
||||
Material with given id
|
||||
|
||||
"""
|
||||
|
||||
for index, material in self.materials.items():
|
||||
if material._id == material_id:
|
||||
|
|
@ -585,8 +586,20 @@ class Summary(object):
|
|||
|
||||
return None
|
||||
|
||||
|
||||
def get_surface_by_id(self, surface_id):
|
||||
"""Return a Surface object given the surface id
|
||||
|
||||
Parameters
|
||||
----------
|
||||
id : int
|
||||
Unique identifier for the surface
|
||||
|
||||
Returns
|
||||
-------
|
||||
surface : openmc.surface.Surface
|
||||
Surface with given id
|
||||
|
||||
"""
|
||||
|
||||
for index, surface in self.surfaces.items():
|
||||
if surface._id == surface_id:
|
||||
|
|
@ -594,8 +607,20 @@ class Summary(object):
|
|||
|
||||
return None
|
||||
|
||||
|
||||
def get_cell_by_id(self, cell_id):
|
||||
"""Return a Cell object given the cell id
|
||||
|
||||
Parameters
|
||||
----------
|
||||
id : int
|
||||
Unique identifier for the cell
|
||||
|
||||
Returns
|
||||
-------
|
||||
cell : openmc.universe.Cell
|
||||
Cell with given id
|
||||
|
||||
"""
|
||||
|
||||
for index, cell in self.cells.items():
|
||||
if cell._id == cell_id:
|
||||
|
|
@ -603,8 +628,20 @@ class Summary(object):
|
|||
|
||||
return None
|
||||
|
||||
|
||||
def get_universe_by_id(self, universe_id):
|
||||
"""Return a Universe object given the universe id
|
||||
|
||||
Parameters
|
||||
----------
|
||||
id : int
|
||||
Unique identifier for the universe
|
||||
|
||||
Returns
|
||||
-------
|
||||
universe : openmc.universe.Universe
|
||||
Universe with given id
|
||||
|
||||
"""
|
||||
|
||||
for index, universe in self.universes.items():
|
||||
if universe._id == universe_id:
|
||||
|
|
@ -612,8 +649,20 @@ class Summary(object):
|
|||
|
||||
return None
|
||||
|
||||
|
||||
def get_lattice_by_id(self, lattice_id):
|
||||
"""Return a Lattice object given the lattice id
|
||||
|
||||
Parameters
|
||||
----------
|
||||
id : int
|
||||
Unique identifier for the lattice
|
||||
|
||||
Returns
|
||||
-------
|
||||
lattice : openmc.universe.Lattice
|
||||
Lattice with given id
|
||||
|
||||
"""
|
||||
|
||||
for index, lattice in self.lattices.items():
|
||||
if lattice._id == lattice_id:
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,25 +1,47 @@
|
|||
from numbers import Real
|
||||
from xml.etree import ElementTree as ET
|
||||
import sys
|
||||
|
||||
from openmc.checkvalue import *
|
||||
from openmc.checkvalue import check_type, check_value
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
basestring = str
|
||||
|
||||
|
||||
class Trigger(object):
|
||||
"""A criterion for when to finish a simulation based on tally uncertainties.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
trigger_type : {'variance', 'std_dev', 'rel_err'}
|
||||
Determine whether to trigger on the variance, standard deviation, or
|
||||
relative error of scores.
|
||||
threshold : float
|
||||
The threshold for the trigger type.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
trigger_type : {'variance', 'std_dev', 'rel_err'}
|
||||
Determine whether to trigger on the variance, standard deviation, or
|
||||
relative error of scores.
|
||||
threshold : float
|
||||
The threshold for the trigger type.
|
||||
scores : list of str
|
||||
Scores which should be checked against the trigger
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, trigger_type, threshold):
|
||||
|
||||
# Initialize Mesh class attributes
|
||||
self.trigger_type = trigger_type
|
||||
self.threshold = threshold
|
||||
self._scores = []
|
||||
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
|
||||
existing = memo.get(id(self))
|
||||
|
||||
# If this is first time we have tried to copy this object, create a copy
|
||||
if existing is None:
|
||||
|
||||
clone = type(self).__new__(type(self))
|
||||
clone._trigger_type = self._trigger_type
|
||||
clone._threshold = self._threshold
|
||||
|
|
@ -36,47 +58,40 @@ class Trigger(object):
|
|||
else:
|
||||
return existing
|
||||
|
||||
|
||||
@property
|
||||
def trigger_type(self):
|
||||
return self._trigger_type
|
||||
|
||||
|
||||
@property
|
||||
def threshold(self):
|
||||
return self._threshold
|
||||
|
||||
|
||||
@property
|
||||
def scores(self):
|
||||
return self._scores
|
||||
|
||||
|
||||
@trigger_type.setter
|
||||
def trigger_type(self, trigger_type):
|
||||
|
||||
if not trigger_type in ['variance', 'std_dev', 'rel_err']:
|
||||
msg = 'Unable to create a tally trigger with ' \
|
||||
'type "{0}"'.format(trigger_type)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_value('tally trigger type', trigger_type,
|
||||
['variance', 'std_dev', 'rel_err'])
|
||||
self._trigger_type = trigger_type
|
||||
|
||||
|
||||
@threshold.setter
|
||||
def threshold(self, threshold):
|
||||
|
||||
if not is_float(threshold):
|
||||
msg = 'Unable to set a tally trigger threshold with ' \
|
||||
'threshold "{0}"'.format(threshold)
|
||||
raise ValueError(msg)
|
||||
|
||||
check_type('tally trigger threshold', threshold, Real)
|
||||
self._threshold = threshold
|
||||
|
||||
|
||||
def add_score(self, score):
|
||||
"""Add a score to the list of scores to be checked against the trigger.
|
||||
|
||||
if not is_string(score):
|
||||
Parameters
|
||||
----------
|
||||
score : str
|
||||
Score to append
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(score, basestring):
|
||||
msg = 'Unable to add score "{0}" to tally trigger since ' \
|
||||
'it is not a string'.format(score)
|
||||
raise ValueError(msg)
|
||||
|
|
@ -87,28 +102,25 @@ class Trigger(object):
|
|||
else:
|
||||
self._scores.append(score)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
string = 'Trigger\n'
|
||||
string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._trigger_type)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tThreshold', '=\t', self._threshold)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tScores', '=\t', self._scores)
|
||||
return string
|
||||
|
||||
|
||||
def get_trigger_xml(self, element):
|
||||
"""Return XML representation of the trigger
|
||||
|
||||
Returns
|
||||
-------
|
||||
element : xml.etree.ElementTree.Element
|
||||
XML element containing trigger data
|
||||
|
||||
"""
|
||||
|
||||
subelement = ET.SubElement(element, "trigger")
|
||||
subelement.set("type", self._trigger_type)
|
||||
subelement.set("threshold", str(self._threshold))
|
||||
|
||||
# Scores
|
||||
if len(self._scores) != 0:
|
||||
|
||||
scores = ''
|
||||
for score in self._scores:
|
||||
scores += '{0} '.format(score)
|
||||
|
||||
scores.rstrip(' ')
|
||||
subelement.set("scores", scores)
|
||||
subelement.set("scores", ' '.join(map(str, self._scores)))
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
|||
module ace_header
|
||||
|
||||
use constants, only: MAX_FILE_LEN
|
||||
use constants, only: MAX_FILE_LEN, ZERO
|
||||
use endf_header, only: Tab1
|
||||
use list_header, only: ListInt
|
||||
|
||||
|
|
@ -167,12 +167,12 @@ module ace_header
|
|||
|
||||
type Nuclide0K
|
||||
|
||||
character(10) :: nuclide ! name of nuclide, e.g. U-238
|
||||
character(16) :: scheme = 'ares' ! target velocity sampling scheme
|
||||
character(10) :: name ! name of nuclide, e.g. 92235.03c
|
||||
character(10) :: name_0K ! name of 0K nuclide, e.g. 92235.00c
|
||||
real(8) :: E_min = 0.01e-6 ! lower cutoff energy for res scattering
|
||||
real(8) :: E_max = 1000.0e-6 ! upper cutoff energy for res scattering
|
||||
character(10) :: nuclide ! name of nuclide, e.g. U-238
|
||||
character(16) :: scheme = 'ares' ! target velocity sampling scheme
|
||||
character(10) :: name ! name of nuclide, e.g. 92235.03c
|
||||
character(10) :: name_0K ! name of 0K nuclide, e.g. 92235.00c
|
||||
real(8) :: E_min = 0.01e-6_8 ! lower cutoff energy for res scattering
|
||||
real(8) :: E_max = 1000.0e-6_8 ! upper cutoff energy for res scattering
|
||||
|
||||
end type Nuclide0K
|
||||
|
||||
|
|
@ -204,7 +204,7 @@ module ace_header
|
|||
|
||||
! threshold for S(a,b) treatment (usually ~4 eV)
|
||||
real(8) :: threshold_inelastic
|
||||
real(8) :: threshold_elastic = 0.0
|
||||
real(8) :: threshold_elastic = ZERO
|
||||
|
||||
! Inelastic scattering data
|
||||
integer :: n_inelastic_e_in ! # of incoming E for inelastic
|
||||
|
|
@ -258,7 +258,7 @@ module ace_header
|
|||
type NuclideMicroXS
|
||||
integer :: index_grid ! index on nuclide energy grid
|
||||
integer :: index_temp ! temperature index for nuclide
|
||||
real(8) :: last_E = 0.0 ! last evaluated energy
|
||||
real(8) :: last_E = ZERO ! last evaluated energy
|
||||
real(8) :: interp_factor ! interpolation factor on nuc. energy grid
|
||||
real(8) :: total ! microscropic total xs
|
||||
real(8) :: elastic ! microscopic elastic scattering xs
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ contains
|
|||
|
||||
#ifdef MPI
|
||||
use global, only: mpi_err
|
||||
use mpi
|
||||
use message_passing
|
||||
#endif
|
||||
|
||||
integer :: nx ! maximum number of cells in x direction
|
||||
|
|
@ -224,7 +224,7 @@ contains
|
|||
|
||||
#ifdef MPI
|
||||
use global, only: mpi_err
|
||||
use mpi
|
||||
use message_passing
|
||||
#endif
|
||||
|
||||
logical, intent(in) :: new_weights ! calcualte new weights
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ contains
|
|||
|
||||
subroutine read_cmfd_xml()
|
||||
|
||||
use constants, only: ZERO, ONE
|
||||
use error, only: fatal_error, warning
|
||||
use global
|
||||
use output, only: write_message
|
||||
|
|
@ -103,7 +104,7 @@ contains
|
|||
cmfd % indices(4) = ng - 1 ! sets energy group dimension
|
||||
else
|
||||
if(.not.allocated(cmfd % egrid)) allocate(cmfd % egrid(2))
|
||||
cmfd % egrid = (/0.0_8,20.0_8/)
|
||||
cmfd % egrid = [ ZERO, 20.0_8 ]
|
||||
cmfd % indices(4) = 1 ! one energy group
|
||||
end if
|
||||
|
||||
|
|
@ -111,7 +112,7 @@ contains
|
|||
if (check_for_node(node_mesh, "albedo")) then
|
||||
call get_node_array(node_mesh, "albedo", cmfd % albedo)
|
||||
else
|
||||
cmfd % albedo = (/1.0, 1.0, 1.0, 1.0, 1.0, 1.0/)
|
||||
cmfd % albedo = [ ONE, ONE, ONE, ONE, ONE, ONE ]
|
||||
end if
|
||||
|
||||
! Get acceleration map
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ module constants
|
|||
! adjusted. Modifying constants in other sections may cause the code to fail.
|
||||
|
||||
! Monoatomic ideal-gas scattering treatment threshold
|
||||
real(8), parameter :: FREE_GAS_THRESHOLD = 400.0
|
||||
real(8), parameter :: FREE_GAS_THRESHOLD = 400.0_8
|
||||
|
||||
! Significance level for confidence intervals
|
||||
real(8), parameter :: CONFIDENCE_LEVEL = 0.95_8
|
||||
|
|
@ -63,15 +63,18 @@ module constants
|
|||
|
||||
real(8), parameter :: &
|
||||
PI = 3.1415926535898_8, & ! pi
|
||||
MASS_NEUTRON = 1.008664916, & ! mass of a neutron in amu
|
||||
MASS_PROTON = 1.007276466812, & ! mass of a proton in amu
|
||||
AMU = 1.660538921e-27, & ! 1 amu in kg
|
||||
N_AVOGADRO = 0.602214129, & ! Avogadro's number in 10^24/mol
|
||||
K_BOLTZMANN = 8.6173324e-11, & ! Boltzmann constant in MeV/K
|
||||
MASS_NEUTRON = 1.008664916_8, & ! mass of a neutron in amu
|
||||
MASS_PROTON = 1.007276466812_8, & ! mass of a proton in amu
|
||||
AMU = 1.660538921e-27_8, & ! 1 amu in kg
|
||||
N_AVOGADRO = 0.602214129_8, & ! Avogadro's number in 10^24/mol
|
||||
K_BOLTZMANN = 8.6173324e-11_8, & ! Boltzmann constant in MeV/K
|
||||
INFINITY = huge(0.0_8), & ! positive infinity
|
||||
ZERO = 0.0_8, &
|
||||
HALF = 0.5_8, &
|
||||
ONE = 1.0_8, &
|
||||
TWO = 2.0_8
|
||||
TWO = 2.0_8, &
|
||||
THREE = 3.0_8, &
|
||||
FOUR = 4.0_8
|
||||
|
||||
! ============================================================================
|
||||
! GEOMETRY-RELATED CONSTANTS
|
||||
|
|
@ -317,13 +320,13 @@ module constants
|
|||
OUT_FRONT = 4, &
|
||||
IN_TOP = 5, &
|
||||
OUT_TOP = 6
|
||||
|
||||
|
||||
! Tally trigger types and threshold
|
||||
integer, parameter :: &
|
||||
VARIANCE = 1, &
|
||||
RELATIVE_ERROR = 2, &
|
||||
STANDARD_DEVIATION = 3
|
||||
|
||||
STANDARD_DEVIATION = 3
|
||||
|
||||
! Global tallY parameters
|
||||
integer, parameter :: N_GLOBAL_TALLIES = 4
|
||||
integer, parameter :: &
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
module eigenvalue
|
||||
|
||||
#ifdef MPI
|
||||
use mpi
|
||||
use message_passing
|
||||
#endif
|
||||
|
||||
use cmfd_execute, only: cmfd_init_batch, execute_cmfd
|
||||
|
|
@ -96,7 +96,7 @@ contains
|
|||
end do GENERATION_LOOP
|
||||
|
||||
call finalize_batch()
|
||||
|
||||
|
||||
if (satisfy_triggers) exit BATCH_LOOP
|
||||
|
||||
end do BATCH_LOOP
|
||||
|
|
@ -171,6 +171,26 @@ contains
|
|||
|
||||
subroutine finalize_generation()
|
||||
|
||||
! Update global tallies with the omp private accumulation variables
|
||||
!$omp parallel
|
||||
!$omp critical
|
||||
global_tallies(K_TRACKLENGTH) % value = &
|
||||
global_tallies(K_TRACKLENGTH) % value + global_tally_tracklength
|
||||
global_tallies(K_COLLISION) % value = &
|
||||
global_tallies(K_COLLISION) % value + global_tally_collision
|
||||
global_tallies(LEAKAGE) % value = &
|
||||
global_tallies(LEAKAGE) % value + global_tally_leakage
|
||||
global_tallies(K_ABSORPTION) % value = &
|
||||
global_tallies(K_ABSORPTION) % value + global_tally_absorption
|
||||
!$omp end critical
|
||||
|
||||
! reset private tallies
|
||||
global_tally_tracklength = 0
|
||||
global_tally_collision = 0
|
||||
global_tally_leakage = 0
|
||||
global_tally_absorption = 0
|
||||
!$omp end parallel
|
||||
|
||||
#ifdef _OPENMP
|
||||
! Join the fission bank from each thread into one global fission bank
|
||||
call join_bank_from_threads()
|
||||
|
|
@ -220,12 +240,12 @@ contains
|
|||
|
||||
! Calculate combined estimate of k-effective
|
||||
if (master) call calculate_combined_keff()
|
||||
|
||||
|
||||
! Check_triggers
|
||||
if (master) call check_triggers()
|
||||
#ifdef MPI
|
||||
call MPI_BCAST(satisfy_triggers, 1, MPI_LOGICAL, 0, &
|
||||
MPI_COMM_WORLD, mpi_err)
|
||||
MPI_COMM_WORLD, mpi_err)
|
||||
#endif
|
||||
if (satisfy_triggers .or. &
|
||||
(trigger_on .and. current_batch == n_max_batches)) then
|
||||
|
|
@ -273,7 +293,11 @@ contains
|
|||
#ifdef MPI
|
||||
integer(8) :: n ! number of sites to send/recv
|
||||
integer :: neighbor ! processor to send/recv data from
|
||||
#ifdef MPIF08
|
||||
type(MPI_Request) :: request(20)
|
||||
#else
|
||||
integer :: request(20) ! communication request for send/recving sites
|
||||
#endif
|
||||
integer :: n_request ! number of communication requests
|
||||
integer(8) :: index_local ! index in local source bank
|
||||
integer(8), save, allocatable :: &
|
||||
|
|
@ -544,7 +568,7 @@ contains
|
|||
! If the user did not specify how many mesh cells are to be used in
|
||||
! each direction, we automatically determine an appropriate number of
|
||||
! cells
|
||||
n = ceiling((n_particles/20)**(1.0/3.0))
|
||||
n = ceiling((n_particles/20)**(ONE/THREE))
|
||||
|
||||
! copy dimensions
|
||||
m % n_dimension = 3
|
||||
|
|
|
|||
|
|
@ -92,15 +92,17 @@ contains
|
|||
! Determine corresponding indices in nuclide grid to energies on
|
||||
! equal-logarithmic grid
|
||||
j = 1
|
||||
do k = 0, M - 1
|
||||
do k = 0, M
|
||||
do while (log(nuc%energy(j + 1)/E_min) <= umesh(k))
|
||||
! Ensure that for isotopes where maxval(nuc % energy) << E_max
|
||||
! that there are no out-of-bounds issues.
|
||||
if (j + 1 == nuc % n_grid) then
|
||||
exit
|
||||
end if
|
||||
j = j + 1
|
||||
end do
|
||||
nuc % grid_index(k) = j
|
||||
end do
|
||||
|
||||
! Set the last point explicitly so that we don't have out-of-bounds issues
|
||||
nuc % grid_index(M) = size(nuc % energy) - 1
|
||||
end do
|
||||
|
||||
deallocate(umesh)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ module error
|
|||
use global
|
||||
|
||||
#ifdef MPI
|
||||
use mpi
|
||||
use message_passing
|
||||
#endif
|
||||
|
||||
implicit none
|
||||
|
|
@ -155,7 +155,7 @@ contains
|
|||
#ifdef NO_F2008
|
||||
stop
|
||||
#else
|
||||
error stop
|
||||
error stop
|
||||
#endif
|
||||
|
||||
end subroutine fatal_error
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ module finalize
|
|||
use tally, only: tally_statistics
|
||||
|
||||
#ifdef MPI
|
||||
use mpi
|
||||
use message_passing
|
||||
#endif
|
||||
|
||||
#ifdef HDF5
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
module fixed_source
|
||||
|
||||
#ifdef MPI
|
||||
use mpi
|
||||
use message_passing
|
||||
#endif
|
||||
|
||||
use constants, only: ZERO, MAX_LINE_LEN
|
||||
|
|
|
|||
421
src/geometry.F90
421
src/geometry.F90
|
|
@ -6,7 +6,7 @@ module geometry
|
|||
&RectLattice, HexLattice
|
||||
use global
|
||||
use output, only: write_message
|
||||
use particle_header, only: LocalCoord, deallocate_coord, Particle
|
||||
use particle_header, only: LocalCoord, Particle
|
||||
use particle_restart_write, only: write_particle_restart
|
||||
use string, only: to_str
|
||||
use tally, only: score_surface_current
|
||||
|
|
@ -76,20 +76,18 @@ contains
|
|||
type(Particle), intent(inout) :: p
|
||||
|
||||
integer :: i ! cell loop index on a level
|
||||
integer :: j ! coordinate level index
|
||||
integer :: n_coord ! saved number of coordinate levels
|
||||
integer :: n ! number of cells to search on a level
|
||||
integer :: index_cell ! index in cells array
|
||||
type(Cell), pointer :: c ! pointer to cell
|
||||
type(Universe), pointer :: univ ! universe to search in
|
||||
type(LocalCoord), pointer :: coord ! particle coordinate to search on
|
||||
|
||||
coord => p % coord0
|
||||
|
||||
! loop through each coordinate level
|
||||
do while (associated(coord))
|
||||
|
||||
p % coord => coord
|
||||
|
||||
univ => universes(coord % universe)
|
||||
n_coord = p % n_coord
|
||||
do j = 1, n_coord
|
||||
p % n_coord = j
|
||||
univ => universes(p % coord(j) % universe)
|
||||
n = univ % n_cells
|
||||
|
||||
! loop through each cell on this level
|
||||
|
|
@ -99,10 +97,10 @@ contains
|
|||
|
||||
if (simple_cell_contains(c, p)) then
|
||||
! the particle should only be contained in one cell per level
|
||||
if (index_cell /= coord % cell) then
|
||||
if (index_cell /= p % coord(j) % cell) then
|
||||
call fatal_error("Overlapping cells detected: " &
|
||||
&// trim(to_str(cells(index_cell) % id)) // ", " &
|
||||
&// trim(to_str(cells(coord % cell) % id)) &
|
||||
&// trim(to_str(cells(p % coord(j) % cell) % id)) &
|
||||
&// " on universe " // trim(to_str(univ % id)))
|
||||
end if
|
||||
|
||||
|
|
@ -111,9 +109,6 @@ contains
|
|||
end if
|
||||
|
||||
end do
|
||||
|
||||
coord => coord % next
|
||||
|
||||
end do
|
||||
|
||||
end subroutine check_cell_overlap
|
||||
|
|
@ -130,6 +125,7 @@ contains
|
|||
logical, intent(inout) :: found
|
||||
integer, optional :: search_cells(:)
|
||||
integer :: i ! index over cells
|
||||
integer :: j ! coordinate level index
|
||||
integer :: i_xyz(3) ! indices in lattice
|
||||
integer :: n ! number of cells to search
|
||||
integer :: index_cell ! index in cells array
|
||||
|
|
@ -138,8 +134,10 @@ contains
|
|||
class(Lattice), pointer :: lat ! pointer to lattice
|
||||
type(Universe), pointer :: univ ! universe to search in
|
||||
|
||||
! Remove coordinates for any lower levels
|
||||
call deallocate_coord(p % coord % next)
|
||||
do j = p % n_coord + 1, MAX_COORD
|
||||
call p % coord(j) % reset()
|
||||
end do
|
||||
j = p % n_coord
|
||||
|
||||
! set size of list to search
|
||||
if (present(search_cells)) then
|
||||
|
|
@ -147,7 +145,7 @@ contains
|
|||
n = size(search_cells)
|
||||
else
|
||||
use_search_cells = .false.
|
||||
univ => universes(p % coord % universe)
|
||||
univ => universes(p % coord(j) % universe)
|
||||
n = univ % n_cells
|
||||
end if
|
||||
|
||||
|
|
@ -157,7 +155,7 @@ contains
|
|||
if (use_search_cells) then
|
||||
index_cell = search_cells(i)
|
||||
! check to make sure search cell is in same universe
|
||||
if (cells(index_cell) % universe /= p % coord % universe) cycle
|
||||
if (cells(index_cell) % universe /= p % coord(j) % universe) cycle
|
||||
else
|
||||
index_cell = univ % cells(i)
|
||||
end if
|
||||
|
|
@ -169,7 +167,7 @@ contains
|
|||
if (.not. simple_cell_contains(c, p)) cycle
|
||||
|
||||
! Set cell on this level
|
||||
p % coord % cell = index_cell
|
||||
p % coord(j) % cell = index_cell
|
||||
|
||||
! Show cell information on trace
|
||||
if (verbosity >= 10 .or. trace) then
|
||||
|
|
@ -188,28 +186,29 @@ contains
|
|||
! ======================================================================
|
||||
! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL
|
||||
|
||||
! Create new level of coordinates
|
||||
allocate(p % coord % next)
|
||||
p % coord % next % xyz = p % coord % xyz
|
||||
p % coord % next % uvw = p % coord % uvw
|
||||
! Store lower level coordinates
|
||||
p % coord(j + 1) % xyz = p % coord(j) % xyz
|
||||
p % coord(j + 1) % uvw = p % coord(j) % uvw
|
||||
|
||||
! Move particle to next level and set universe
|
||||
p % coord => p % coord % next
|
||||
p % coord % universe = c % fill
|
||||
j = j + 1
|
||||
p % n_coord = j
|
||||
p % coord(j) % universe = c % fill
|
||||
|
||||
! Apply translation
|
||||
if (allocated(c % translation)) then
|
||||
p % coord % xyz = p % coord % xyz - c % translation
|
||||
p % coord(j) % xyz = p % coord(j) % xyz - c % translation
|
||||
end if
|
||||
|
||||
! Apply rotation
|
||||
if (allocated(c % rotation_matrix)) then
|
||||
p % coord % xyz = matmul(c % rotation_matrix, p % coord % xyz)
|
||||
p % coord % uvw = matmul(c % rotation_matrix, p % coord % uvw)
|
||||
p % coord % rotated = .true.
|
||||
p % coord(j) % xyz = matmul(c % rotation_matrix, p % coord(j) % xyz)
|
||||
p % coord(j) % uvw = matmul(c % rotation_matrix, p % coord(j) % uvw)
|
||||
p % coord(j) % rotated = .true.
|
||||
end if
|
||||
|
||||
call find_cell(p, found)
|
||||
j = p % n_coord
|
||||
if (.not. found) exit
|
||||
|
||||
elseif (c % type == CELL_LATTICE) then CELL_TYPE
|
||||
|
|
@ -220,40 +219,41 @@ contains
|
|||
lat => lattices(c % fill) % obj
|
||||
|
||||
! Determine lattice indices
|
||||
i_xyz = lat % get_indices(p % coord % xyz + TINY_BIT * p % coord % uvw)
|
||||
i_xyz = lat % get_indices(p % coord(j) % xyz + TINY_BIT * p % coord(j) % uvw)
|
||||
|
||||
! Create new level of coordinates
|
||||
allocate(p % coord % next)
|
||||
p % coord % next % xyz = lat % get_local_xyz(p % coord % xyz, i_xyz)
|
||||
p % coord % next % uvw = p % coord % uvw
|
||||
! Store lower level coordinates
|
||||
p % coord(j + 1) % xyz = lat % get_local_xyz(p % coord(j) % xyz, i_xyz)
|
||||
p % coord(j + 1) % uvw = p % coord(j) % uvw
|
||||
|
||||
! set particle lattice indices
|
||||
p % coord % next% lattice = c % fill
|
||||
p % coord % next% lattice_x = i_xyz(1)
|
||||
p % coord % next% lattice_y = i_xyz(2)
|
||||
p % coord % next% lattice_z = i_xyz(3)
|
||||
p % coord(j + 1) % lattice = c % fill
|
||||
p % coord(j + 1) % lattice_x = i_xyz(1)
|
||||
p % coord(j + 1) % lattice_y = i_xyz(2)
|
||||
p % coord(j + 1) % lattice_z = i_xyz(3)
|
||||
|
||||
! Set the next lowest coordinate level.
|
||||
if (lat % are_valid_indices(i_xyz)) then
|
||||
! Particle is inside the lattice.
|
||||
p % coord % next % universe = &
|
||||
&lat % universes(i_xyz(1), i_xyz(2), i_xyz(3))
|
||||
p % coord(j + 1) % universe = &
|
||||
lat % universes(i_xyz(1), i_xyz(2), i_xyz(3))
|
||||
|
||||
else
|
||||
! Particle is outside the lattice.
|
||||
if (lat % outer == NO_OUTER_UNIVERSE) then
|
||||
call fatal_error("A particle is outside latttice " &
|
||||
&// trim(to_str(lat % id)) // " but the lattice has no &
|
||||
// trim(to_str(lat % id)) // " but the lattice has no &
|
||||
&defined outer universe.")
|
||||
else
|
||||
p % coord % next % universe = lat % outer
|
||||
p % coord(j + 1) % universe = lat % outer
|
||||
end if
|
||||
end if
|
||||
|
||||
! Move particle to next level and search for the lower cells.
|
||||
p % coord => p % coord % next
|
||||
j = j + 1
|
||||
p % n_coord = j
|
||||
|
||||
call find_cell(p, found)
|
||||
j = p % n_coord
|
||||
if (.not. found) exit
|
||||
|
||||
end if CELL_TYPE
|
||||
|
|
@ -314,15 +314,13 @@ contains
|
|||
! TODO: Find a better solution to score surface currents than
|
||||
! physically moving the particle forward slightly
|
||||
|
||||
p % coord0 % xyz = p % coord0 % xyz + TINY_BIT * p % coord0 % uvw
|
||||
p % coord(1) % xyz = p % coord(1) % xyz + TINY_BIT * p % coord(1) % uvw
|
||||
call score_surface_current(p)
|
||||
end if
|
||||
|
||||
! Score to global leakage tally
|
||||
if (tallies_on) then
|
||||
!$omp atomic
|
||||
global_tallies(LEAKAGE) % value = &
|
||||
global_tallies(LEAKAGE) % value + p % wgt
|
||||
global_tally_leakage = global_tally_leakage + p % wgt
|
||||
end if
|
||||
|
||||
! Display message
|
||||
|
|
@ -337,7 +335,7 @@ contains
|
|||
! PARTICLE REFLECTS FROM SURFACE
|
||||
|
||||
! Do not handle reflective boundary conditions on lower universes
|
||||
if (.not. associated(p % coord, p % coord0)) then
|
||||
if (p % n_coord /= 1) then
|
||||
call handle_lost_particle(p, "Cannot reflect particle " &
|
||||
&// trim(to_str(p % id)) // " off surface in a lower universe.")
|
||||
return
|
||||
|
|
@ -348,15 +346,15 @@ contains
|
|||
! case the surface crossing in coincident with a mesh boundary
|
||||
|
||||
if (active_current_tallies % size() > 0) then
|
||||
p % coord0 % xyz = p % coord0 % xyz - TINY_BIT * p % coord0 % uvw
|
||||
p % coord(1) % xyz = p % coord(1) % xyz - TINY_BIT * p % coord(1) % uvw
|
||||
call score_surface_current(p)
|
||||
p % coord0 % xyz = p % coord0 % xyz + TINY_BIT * p % coord0 % uvw
|
||||
p % coord(1) % xyz = p % coord(1) % xyz + TINY_BIT * p % coord(1) % uvw
|
||||
end if
|
||||
|
||||
! Copy particle's direction cosines
|
||||
u = p % coord0 % uvw(1)
|
||||
v = p % coord0 % uvw(2)
|
||||
w = p % coord0 % uvw(3)
|
||||
u = p % coord(1) % uvw(1)
|
||||
v = p % coord(1) % uvw(2)
|
||||
w = p % coord(1) % uvw(3)
|
||||
|
||||
select case (surf%type)
|
||||
case (SURF_PX)
|
||||
|
|
@ -383,8 +381,8 @@ contains
|
|||
|
||||
case (SURF_CYL_X)
|
||||
! Find y-y0, z-z0 and dot product of direction and surface normal
|
||||
y = p % coord0 % xyz(2) - surf % coeffs(1)
|
||||
z = p % coord0 % xyz(3) - surf % coeffs(2)
|
||||
y = p % coord(1) % xyz(2) - surf % coeffs(1)
|
||||
z = p % coord(1) % xyz(3) - surf % coeffs(2)
|
||||
R = surf % coeffs(3)
|
||||
dot_prod = v*y + w*z
|
||||
|
||||
|
|
@ -394,8 +392,8 @@ contains
|
|||
|
||||
case (SURF_CYL_Y)
|
||||
! Find x-x0, z-z0 and dot product of direction and surface normal
|
||||
x = p % coord0 % xyz(1) - surf % coeffs(1)
|
||||
z = p % coord0 % xyz(3) - surf % coeffs(2)
|
||||
x = p % coord(1) % xyz(1) - surf % coeffs(1)
|
||||
z = p % coord(1) % xyz(3) - surf % coeffs(2)
|
||||
R = surf % coeffs(3)
|
||||
dot_prod = u*x + w*z
|
||||
|
||||
|
|
@ -405,8 +403,8 @@ contains
|
|||
|
||||
case (SURF_CYL_Z)
|
||||
! Find x-x0, y-y0 and dot product of direction and surface normal
|
||||
x = p % coord0 % xyz(1) - surf % coeffs(1)
|
||||
y = p % coord0 % xyz(2) - surf % coeffs(2)
|
||||
x = p % coord(1) % xyz(1) - surf % coeffs(1)
|
||||
y = p % coord(1) % xyz(2) - surf % coeffs(2)
|
||||
R = surf % coeffs(3)
|
||||
dot_prod = u*x + v*y
|
||||
|
||||
|
|
@ -417,9 +415,9 @@ contains
|
|||
case (SURF_SPHERE)
|
||||
! Find x-x0, y-y0, z-z0 and dot product of direction and surface
|
||||
! normal
|
||||
x = p % coord0 % xyz(1) - surf % coeffs(1)
|
||||
y = p % coord0 % xyz(2) - surf % coeffs(2)
|
||||
z = p % coord0 % xyz(3) - surf % coeffs(3)
|
||||
x = p % coord(1) % xyz(1) - surf % coeffs(1)
|
||||
y = p % coord(1) % xyz(2) - surf % coeffs(2)
|
||||
z = p % coord(1) % xyz(3) - surf % coeffs(3)
|
||||
R = surf % coeffs(4)
|
||||
dot_prod = u*x + v*y + w*z
|
||||
|
||||
|
|
@ -431,9 +429,9 @@ contains
|
|||
case (SURF_CONE_X)
|
||||
! Find x-x0, y-y0, z-z0 and dot product of direction and surface
|
||||
! normal
|
||||
x = p % coord0 % xyz(1) - surf % coeffs(1)
|
||||
y = p % coord0 % xyz(2) - surf % coeffs(2)
|
||||
z = p % coord0 % xyz(3) - surf % coeffs(3)
|
||||
x = p % coord(1) % xyz(1) - surf % coeffs(1)
|
||||
y = p % coord(1) % xyz(2) - surf % coeffs(2)
|
||||
z = p % coord(1) % xyz(3) - surf % coeffs(3)
|
||||
R = surf % coeffs(4)
|
||||
dot_prod = (v*y + w*z - R*u*x)/((R + ONE)*R*x*x)
|
||||
|
||||
|
|
@ -445,9 +443,9 @@ contains
|
|||
case (SURF_CONE_Y)
|
||||
! Find x-x0, y-y0, z-z0 and dot product of direction and surface
|
||||
! normal
|
||||
x = p % coord0 % xyz(1) - surf % coeffs(1)
|
||||
y = p % coord0 % xyz(2) - surf % coeffs(2)
|
||||
z = p % coord0 % xyz(3) - surf % coeffs(3)
|
||||
x = p % coord(1) % xyz(1) - surf % coeffs(1)
|
||||
y = p % coord(1) % xyz(2) - surf % coeffs(2)
|
||||
z = p % coord(1) % xyz(3) - surf % coeffs(3)
|
||||
R = surf % coeffs(4)
|
||||
dot_prod = (u*x + w*z - R*v*y)/((R + ONE)*R*y*y)
|
||||
|
||||
|
|
@ -459,9 +457,9 @@ contains
|
|||
case (SURF_CONE_Z)
|
||||
! Find x-x0, y-y0, z-z0 and dot product of direction and surface
|
||||
! normal
|
||||
x = p % coord0 % xyz(1) - surf % coeffs(1)
|
||||
y = p % coord0 % xyz(2) - surf % coeffs(2)
|
||||
z = p % coord0 % xyz(3) - surf % coeffs(3)
|
||||
x = p % coord(1) % xyz(1) - surf % coeffs(1)
|
||||
y = p % coord(1) % xyz(2) - surf % coeffs(2)
|
||||
z = p % coord(1) % xyz(3) - surf % coeffs(3)
|
||||
R = surf % coeffs(4)
|
||||
dot_prod = (u*x + v*y - R*w*z)/((R + ONE)*R*z*z)
|
||||
|
||||
|
|
@ -477,28 +475,26 @@ contains
|
|||
|
||||
! Set new particle direction
|
||||
norm = sqrt(u*u + v*v + w*w)
|
||||
p % coord0 % uvw = [u, v, w] / norm
|
||||
p % coord(1) % uvw = [u, v, w] / norm
|
||||
|
||||
! Reassign particle's cell and surface
|
||||
p % coord0 % cell = last_cell
|
||||
p % coord(1) % cell = last_cell
|
||||
p % surface = -p % surface
|
||||
|
||||
! If a reflective surface is coincident with a lattice or universe
|
||||
! boundary, it is necessary to redetermine the particle's coordinates in
|
||||
! the lower universes.
|
||||
|
||||
if (associated(p % coord0 % next)) then
|
||||
call deallocate_coord(p % coord0 % next)
|
||||
call find_cell(p, found)
|
||||
if (.not. found) then
|
||||
call handle_lost_particle(p, "Couldn't find particle after reflecting&
|
||||
& from surface.")
|
||||
return
|
||||
end if
|
||||
p % n_coord = 1
|
||||
call find_cell(p, found)
|
||||
if (.not. found) then
|
||||
call handle_lost_particle(p, "Couldn't find particle after reflecting&
|
||||
& from surface.")
|
||||
return
|
||||
end if
|
||||
|
||||
! Set previous coordinate going slightly past surface crossing
|
||||
p % last_xyz = p % coord0 % xyz + TINY_BIT * p % coord0 % uvw
|
||||
p % last_xyz = p % coord(1) % xyz + TINY_BIT * p % coord(1) % uvw
|
||||
|
||||
! Diagnostic message
|
||||
if (verbosity >= 10 .or. trace) then
|
||||
|
|
@ -532,8 +528,7 @@ contains
|
|||
|
||||
! Remove lower coordinate levels and assignment of surface
|
||||
p % surface = NONE
|
||||
p % coord => p % coord0
|
||||
call deallocate_coord(p % coord % next)
|
||||
p % n_coord = 1
|
||||
call find_cell(p, found)
|
||||
|
||||
if (run_mode /= MODE_PLOTTING .and. (.not. found)) then
|
||||
|
|
@ -542,9 +537,8 @@ contains
|
|||
! the particle is really traveling tangent to a surface, if we move it
|
||||
! forward a tiny bit it should fix the problem.
|
||||
|
||||
p % coord => p % coord0
|
||||
call deallocate_coord(p % coord % next)
|
||||
p % coord % xyz = p % coord % xyz + TINY_BIT * p % coord % uvw
|
||||
p % n_coord = 1
|
||||
p % coord(1) % xyz = p % coord(1) % xyz + TINY_BIT * p % coord(1) % uvw
|
||||
call find_cell(p, found)
|
||||
|
||||
! Couldn't find next cell anywhere! This probably means there is an actual
|
||||
|
|
@ -568,52 +562,46 @@ contains
|
|||
|
||||
type(Particle), intent(inout) :: p
|
||||
integer, intent(in) :: lattice_translation(3)
|
||||
integer :: j
|
||||
integer :: i_xyz(3) ! indices in lattice
|
||||
logical :: found ! particle found in cell?
|
||||
class(Lattice), pointer :: lat
|
||||
type(LocalCoord), pointer :: parent_coord
|
||||
|
||||
lat => lattices(p % coord % lattice) % obj
|
||||
j = p % n_coord
|
||||
lat => lattices(p % coord(j) % lattice) % obj
|
||||
|
||||
if (verbosity >= 10 .or. trace) then
|
||||
call write_message(" Crossing lattice " // trim(to_str(lat % id)) &
|
||||
&// ". Current position (" // trim(to_str(p % coord % lattice_x)) &
|
||||
&// "," // trim(to_str(p % coord % lattice_y)) // "," &
|
||||
&// trim(to_str(p % coord % lattice_z)) // ")")
|
||||
&// ". Current position (" // trim(to_str(p % coord(j) % lattice_x)) &
|
||||
&// "," // trim(to_str(p % coord(j) % lattice_y)) // "," &
|
||||
&// trim(to_str(p % coord(j) % lattice_z)) // ")")
|
||||
end if
|
||||
|
||||
! Find the coordiante level just above the current one.
|
||||
parent_coord => p % coord0
|
||||
do while(.not. associated(parent_coord % next, p % coord))
|
||||
parent_coord => parent_coord % next
|
||||
end do
|
||||
|
||||
! Set the lattice indices.
|
||||
p % coord % lattice_x = p % coord % lattice_x + lattice_translation(1)
|
||||
p % coord % lattice_y = p % coord % lattice_y + lattice_translation(2)
|
||||
p % coord % lattice_z = p % coord % lattice_z + lattice_translation(3)
|
||||
i_xyz(1) = p % coord % lattice_x
|
||||
i_xyz(2) = p % coord % lattice_y
|
||||
i_xyz(3) = p % coord % lattice_z
|
||||
p % coord(j) % lattice_x = p % coord(j) % lattice_x + lattice_translation(1)
|
||||
p % coord(j) % lattice_y = p % coord(j) % lattice_y + lattice_translation(2)
|
||||
p % coord(j) % lattice_z = p % coord(j) % lattice_z + lattice_translation(3)
|
||||
i_xyz(1) = p % coord(j) % lattice_x
|
||||
i_xyz(2) = p % coord(j) % lattice_y
|
||||
i_xyz(3) = p % coord(j) % lattice_z
|
||||
|
||||
! Set the new coordinate position.
|
||||
p % coord % xyz = lat % get_local_xyz(parent_coord % xyz, i_xyz)
|
||||
p % coord(j) % xyz = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz)
|
||||
|
||||
OUTSIDE_LAT: if (.not. lat % are_valid_indices(i_xyz)) then
|
||||
! The particle is outside the lattice. Search for it from coord0.
|
||||
call deallocate_coord(p % coord0 % next)
|
||||
p % coord => p % coord0
|
||||
! The particle is outside the lattice. Search for it from base coord
|
||||
p % n_coord = 1
|
||||
call find_cell(p, found)
|
||||
if (.not. found) then
|
||||
call handle_lost_particle(p, "Could not locate particle " &
|
||||
&// trim(to_str(p % id)) // " after crossing a lattice boundary.")
|
||||
// trim(to_str(p % id)) // " after crossing a lattice boundary.")
|
||||
return
|
||||
end if
|
||||
|
||||
else OUTSIDE_LAT
|
||||
|
||||
! Find cell in next lattice element
|
||||
p % coord % universe = lat % universes(i_xyz(1), i_xyz(2), i_xyz(3))
|
||||
p % coord(j) % universe = lat % universes(i_xyz(1), i_xyz(2), i_xyz(3))
|
||||
|
||||
call find_cell(p, found)
|
||||
if (.not. found) then
|
||||
|
|
@ -622,15 +610,14 @@ contains
|
|||
! off all lower-level coordinates and search from universe zero
|
||||
|
||||
! Remove lower coordinates
|
||||
call deallocate_coord(p % coord0 % next)
|
||||
p % coord => p % coord0
|
||||
p % n_coord = 1
|
||||
|
||||
! Search for particle
|
||||
call find_cell(p, found)
|
||||
if (.not. found) then
|
||||
call handle_lost_particle(p, "Could not locate particle " &
|
||||
&// trim(to_str(p % id)) &
|
||||
&// " after crossing a lattice boundary.")
|
||||
// trim(to_str(p % id)) &
|
||||
// " after crossing a lattice boundary.")
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
|
@ -644,14 +631,17 @@ contains
|
|||
! that has a parent cell, also include the surfaces of the edge of the universe.
|
||||
!===============================================================================
|
||||
|
||||
subroutine distance_to_boundary(p, dist, surface_crossed, lattice_translation)
|
||||
subroutine distance_to_boundary(p, dist, surface_crossed, lattice_translation, &
|
||||
next_level)
|
||||
|
||||
type(Particle), intent(inout) :: p
|
||||
real(8), intent(out) :: dist
|
||||
integer, intent(out) :: surface_crossed
|
||||
integer, intent(out) :: lattice_translation(3)
|
||||
integer, intent(out) :: next_level
|
||||
|
||||
integer :: i ! index for surface in cell
|
||||
integer :: j
|
||||
integer :: index_surf ! index in surfaces array (with sign)
|
||||
integer :: i_xyz(3) ! lattice indices
|
||||
integer :: level_surf_cross ! surface crossed on current level
|
||||
|
|
@ -675,30 +665,25 @@ contains
|
|||
type(Cell), pointer :: cl
|
||||
type(Surface), pointer :: surf
|
||||
class(Lattice), pointer :: lat
|
||||
type(LocalCoord), pointer :: coord
|
||||
type(LocalCoord), pointer :: final_coord
|
||||
type(LocalCoord), pointer :: parent_coord
|
||||
|
||||
! inialize distance to infinity (huge)
|
||||
dist = INFINITY
|
||||
d_lat = INFINITY
|
||||
d_surf = INFINITY
|
||||
lattice_translation(:) = [0, 0, 0]
|
||||
nullify(final_coord)
|
||||
|
||||
! Get pointer to top-level coordinates
|
||||
coord => p % coord0
|
||||
next_level = 0
|
||||
|
||||
! Loop over each universe level
|
||||
LEVEL_LOOP: do while(associated(coord))
|
||||
LEVEL_LOOP: do j = 1, p % n_coord
|
||||
|
||||
! get pointer to cell on this level
|
||||
cl => cells(coord % cell)
|
||||
cl => cells(p % coord(j) % cell)
|
||||
|
||||
! copy directional cosines
|
||||
u = coord % uvw(1)
|
||||
v = coord % uvw(2)
|
||||
w = coord % uvw(3)
|
||||
u = p % coord(j) % uvw(1)
|
||||
v = p % coord(j) % uvw(2)
|
||||
w = p % coord(j) % uvw(3)
|
||||
|
||||
! =======================================================================
|
||||
! FIND MINIMUM DISTANCE TO SURFACE IN THIS CELL
|
||||
|
|
@ -706,9 +691,9 @@ contains
|
|||
SURFACE_LOOP: do i = 1, cl % n_surfaces
|
||||
|
||||
! copy local coordinates of particle
|
||||
x = coord % xyz(1)
|
||||
y = coord % xyz(2)
|
||||
z = coord % xyz(3)
|
||||
x = p % coord(j) % xyz(1)
|
||||
y = p % coord(j) % xyz(2)
|
||||
z = p % coord(j) % xyz(3)
|
||||
|
||||
! check for coincident surface -- note that we can't skip the
|
||||
! calculation in general because a particle could be on one side of a
|
||||
|
|
@ -1129,20 +1114,20 @@ contains
|
|||
! =======================================================================
|
||||
! FIND MINIMUM DISTANCE TO LATTICE SURFACES
|
||||
|
||||
LAT_COORD: if (coord % lattice /= NONE) then
|
||||
lat => lattices(coord % lattice) % obj
|
||||
LAT_COORD: if (p % coord(j) % lattice /= NONE) then
|
||||
lat => lattices(p % coord(j) % lattice) % obj
|
||||
|
||||
LAT_TYPE: select type(lat)
|
||||
|
||||
type is (RectLattice)
|
||||
! copy local coordinates
|
||||
x = coord % xyz(1)
|
||||
y = coord % xyz(2)
|
||||
z = coord % xyz(3)
|
||||
x = p % coord(j) % xyz(1)
|
||||
y = p % coord(j) % xyz(2)
|
||||
z = p % coord(j) % xyz(3)
|
||||
|
||||
! determine oncoming edge
|
||||
x0 = sign(lat % pitch(1) * 0.5_8, u)
|
||||
y0 = sign(lat % pitch(2) * 0.5_8, v)
|
||||
x0 = sign(lat % pitch(1) * HALF, u)
|
||||
y0 = sign(lat % pitch(2) * HALF, v)
|
||||
|
||||
! left and right sides
|
||||
if (abs(x - x0) < FP_PRECISION) then
|
||||
|
|
@ -1179,7 +1164,7 @@ contains
|
|||
end if
|
||||
|
||||
if (lat % is_3d) then
|
||||
z0 = sign(lat % pitch(3) * 0.5_8, w)
|
||||
z0 = sign(lat % pitch(3) * HALF, w)
|
||||
|
||||
! top and bottom sides
|
||||
if (abs(z - z0) < FP_PRECISION) then
|
||||
|
|
@ -1202,18 +1187,14 @@ contains
|
|||
|
||||
type is (HexLattice) LAT_TYPE
|
||||
! Copy local coordinates.
|
||||
z = coord % xyz(3)
|
||||
i_xyz(1) = coord % lattice_x
|
||||
i_xyz(2) = coord % lattice_y
|
||||
i_xyz(3) = coord % lattice_z
|
||||
parent_coord => p % coord0
|
||||
do while(.not. associated(parent_coord % next, coord))
|
||||
parent_coord => parent_coord % next
|
||||
end do
|
||||
z = p % coord(j) % xyz(3)
|
||||
i_xyz(1) = p % coord(j) % lattice_x
|
||||
i_xyz(2) = p % coord(j) % lattice_y
|
||||
i_xyz(3) = p % coord(j) % lattice_z
|
||||
|
||||
! Compute velocities along the hexagonal axes.
|
||||
beta_dir = u*sqrt(3.0_8)/2.0_8 + v/2.0_8
|
||||
gama_dir = u*sqrt(3.0_8)/2.0_8 - v/2.0_8
|
||||
beta_dir = u*sqrt(THREE)/TWO + v/TWO
|
||||
gama_dir = u*sqrt(THREE)/TWO - v/TWO
|
||||
|
||||
! Note that hexagonal lattice distance calculations are performed
|
||||
! using the particle's coordinates relative to the neighbor lattice
|
||||
|
|
@ -1223,13 +1204,13 @@ contains
|
|||
! of hex lattices.
|
||||
|
||||
! Upper right and lower left sides.
|
||||
edge = -sign(lat % pitch(1)/2.0_8, beta_dir) ! Oncoming edge
|
||||
if (beta_dir > 0.0) then
|
||||
xyz_t = lat % get_local_xyz(parent_coord % xyz, i_xyz+[1, 0, 0])
|
||||
edge = -sign(lat % pitch(1)/TWO, beta_dir) ! Oncoming edge
|
||||
if (beta_dir > ZERO) then
|
||||
xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[1, 0, 0])
|
||||
else
|
||||
xyz_t = lat % get_local_xyz(parent_coord % xyz, i_xyz+[-1, 0, 0])
|
||||
xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[-1, 0, 0])
|
||||
end if
|
||||
beta = xyz_t(1)*sqrt(3.0_8)/2.0_8 + xyz_t(2)/2.0_8
|
||||
beta = xyz_t(1)*sqrt(THREE)/TWO + xyz_t(2)/TWO
|
||||
if (abs(beta - edge) < FP_PRECISION) then
|
||||
d = INFINITY
|
||||
else if (beta_dir == ZERO) then
|
||||
|
|
@ -1246,13 +1227,13 @@ contains
|
|||
end if
|
||||
|
||||
! Lower right and upper left sides.
|
||||
edge = -sign(lat % pitch(1)/2.0_8, gama_dir) ! Oncoming edge
|
||||
if (gama_dir > 0.0) then
|
||||
xyz_t = lat % get_local_xyz(parent_coord % xyz, i_xyz+[1, -1, 0])
|
||||
edge = -sign(lat % pitch(1)/TWO, gama_dir) ! Oncoming edge
|
||||
if (gama_dir > ZERO) then
|
||||
xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[1, -1, 0])
|
||||
else
|
||||
xyz_t = lat % get_local_xyz(parent_coord % xyz, i_xyz+[-1, 1, 0])
|
||||
xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[-1, 1, 0])
|
||||
end if
|
||||
gama = xyz_t(1)*sqrt(3.0_8)/2.0_8 - xyz_t(2)/2.0_8
|
||||
gama = xyz_t(1)*sqrt(THREE)/TWO - xyz_t(2)/TWO
|
||||
if (abs(gama - edge) < FP_PRECISION) then
|
||||
d = INFINITY
|
||||
else if (gama_dir == ZERO) then
|
||||
|
|
@ -1271,11 +1252,11 @@ contains
|
|||
end if
|
||||
|
||||
! Upper and lower sides.
|
||||
edge = -sign(lat % pitch(1)/2.0_8, v) ! Oncoming edge
|
||||
if (v > 0.0) then
|
||||
xyz_t = lat % get_local_xyz(parent_coord % xyz, i_xyz+[0, 1, 0])
|
||||
edge = -sign(lat % pitch(1)/TWO, v) ! Oncoming edge
|
||||
if (v > ZERO) then
|
||||
xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[0, 1, 0])
|
||||
else
|
||||
xyz_t = lat % get_local_xyz(parent_coord % xyz, i_xyz+[0, -1, 0])
|
||||
xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[0, -1, 0])
|
||||
end if
|
||||
if (abs(xyz_t(2) - edge) < FP_PRECISION) then
|
||||
d = INFINITY
|
||||
|
|
@ -1296,7 +1277,7 @@ contains
|
|||
|
||||
! Top and bottom sides.
|
||||
if (lat % is_3d) then
|
||||
z0 = sign(lat % pitch(2) * 0.5_8, w)
|
||||
z0 = sign(lat % pitch(2) * HALF, w)
|
||||
|
||||
if (abs(z - z0) < FP_PRECISION) then
|
||||
d = INFINITY
|
||||
|
|
@ -1317,10 +1298,10 @@ contains
|
|||
end if
|
||||
end select LAT_TYPE
|
||||
|
||||
if (d_lat < 0.0) then
|
||||
if (d_lat < ZERO) then
|
||||
call handle_lost_particle(p, "Particle " // trim(to_str(p % id)) &
|
||||
&//" had a negative distance to a lattice boundary. d = " &
|
||||
&//trim(to_str(d_lat)))
|
||||
//" had a negative distance to a lattice boundary. d = " &
|
||||
//trim(to_str(d_lat)))
|
||||
end if
|
||||
end if LAT_COORD
|
||||
|
||||
|
|
@ -1333,24 +1314,19 @@ contains
|
|||
dist = d_surf
|
||||
surface_crossed = level_surf_cross
|
||||
lattice_translation(:) = [0, 0, 0]
|
||||
final_coord => coord
|
||||
next_level = j
|
||||
end if
|
||||
else
|
||||
if ((dist - d_lat)/dist >= FP_REL_PRECISION) then
|
||||
dist = d_lat
|
||||
surface_crossed = None
|
||||
lattice_translation(:) = level_lat_trans
|
||||
final_coord => coord
|
||||
next_level = j
|
||||
end if
|
||||
end if
|
||||
|
||||
coord => coord % next
|
||||
|
||||
end do LEVEL_LOOP
|
||||
|
||||
! Move particle to appropriate coordinate level
|
||||
if (associated(final_coord)) p % coord => final_coord
|
||||
|
||||
end subroutine distance_to_boundary
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -1365,6 +1341,7 @@ contains
|
|||
type(Surface), pointer :: surf ! surface
|
||||
logical :: s ! sense of particle
|
||||
|
||||
integer :: j
|
||||
real(8) :: x,y,z ! coordinates of particle
|
||||
real(8) :: func ! surface function evaluated at point
|
||||
real(8) :: A ! coefficient on x for plane
|
||||
|
|
@ -1374,9 +1351,10 @@ contains
|
|||
real(8) :: x0,y0,z0 ! coefficients for quadratic surfaces / box
|
||||
real(8) :: r ! radius for quadratic surfaces
|
||||
|
||||
x = p % coord % xyz(1)
|
||||
y = p % coord % xyz(2)
|
||||
z = p % coord % xyz(3)
|
||||
j = p % n_coord
|
||||
x = p % coord(j) % xyz(1)
|
||||
y = p % coord(j) % xyz(2)
|
||||
z = p % coord(j) % xyz(3)
|
||||
|
||||
select case (surf % type)
|
||||
case (SURF_PX)
|
||||
|
|
@ -1468,7 +1446,7 @@ contains
|
|||
if (abs(func) < FP_COINCIDENT) then
|
||||
! Particle may be coincident with this surface. Artifically move the
|
||||
! particle forward a tiny bit.
|
||||
p % coord % xyz = p % coord % xyz + TINY_BIT * p % coord % uvw
|
||||
p % coord(j) % xyz = p % coord(j) % xyz + TINY_BIT * p % coord(j) % uvw
|
||||
s = sense(p, surf)
|
||||
elseif (func > 0) then
|
||||
s = .true.
|
||||
|
|
@ -1591,8 +1569,8 @@ contains
|
|||
|
||||
subroutine calc_offsets(goal, map, univ, counts, found)
|
||||
|
||||
integer, intent(inout) :: goal ! target universe ID
|
||||
integer, intent(inout) :: map ! map index in vector of maps
|
||||
integer, intent(in) :: goal ! target universe ID
|
||||
integer, intent(in) :: map ! map index in vector of maps
|
||||
type(Universe), intent(in) :: univ ! universe searching in
|
||||
integer, intent(inout) :: counts(:,:) ! target count
|
||||
logical, intent(inout) :: found(:,:) ! target found
|
||||
|
|
@ -1692,11 +1670,11 @@ contains
|
|||
|
||||
recursive function count_target(univ, counts, found, goal, map) result(count)
|
||||
|
||||
type(Universe), intent(inout) :: univ ! universe to search through
|
||||
integer, intent(inout) :: counts(:,:) ! target count
|
||||
logical, intent(inout) :: found(:,:) ! target found
|
||||
integer, intent(inout) :: goal ! target universe ID
|
||||
integer, intent(inout) :: map ! current map
|
||||
type(Universe), intent(in) :: univ ! universe to search through
|
||||
integer, intent(inout) :: counts(:,:) ! target count
|
||||
logical, intent(inout) :: found(:,:) ! target found
|
||||
integer, intent(in) :: goal ! target universe ID
|
||||
integer, intent(in) :: map ! current map
|
||||
|
||||
integer :: i ! index over cells
|
||||
integer :: j, k, m ! indices in lattice
|
||||
|
|
@ -1907,5 +1885,82 @@ contains
|
|||
|
||||
end subroutine count_instance
|
||||
|
||||
!===============================================================================
|
||||
! MAXIMUM_LEVELS determines the maximum number of nested coordinate levels in
|
||||
! the geometry
|
||||
!===============================================================================
|
||||
|
||||
recursive function maximum_levels(univ) result(levels)
|
||||
|
||||
type(Universe), intent(in) :: univ ! universe to search through
|
||||
integer :: levels ! maximum number of levels for this universe
|
||||
|
||||
integer :: i ! index over cells
|
||||
integer :: j, k, m ! indices in lattice
|
||||
integer :: levels_below ! max levels below this universe
|
||||
type(Cell), pointer :: c ! pointer to current cell
|
||||
type(Universe), pointer :: next_univ ! next universe to loop through
|
||||
class(Lattice), pointer :: lat ! pointer to current lattice
|
||||
|
||||
levels_below = 0
|
||||
do i = 1, univ % n_cells
|
||||
c => cells(univ % cells(i))
|
||||
|
||||
! ====================================================================
|
||||
! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL
|
||||
if (c % type == CELL_FILL) then
|
||||
|
||||
next_univ => universes(c % fill)
|
||||
levels_below = max(levels_below, maximum_levels(next_univ))
|
||||
|
||||
! ====================================================================
|
||||
! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL
|
||||
elseif (c % type == CELL_LATTICE) then
|
||||
|
||||
! Set current lattice
|
||||
lat => lattices(c % fill) % obj
|
||||
|
||||
select type (lat)
|
||||
|
||||
type is (RectLattice)
|
||||
|
||||
! Loop over lattice coordinates
|
||||
do j = 1, lat % n_cells(1)
|
||||
do k = 1, lat % n_cells(2)
|
||||
do m = 1, lat % n_cells(3)
|
||||
next_univ => universes(lat % universes(j, k, m))
|
||||
levels_below = max(levels_below, maximum_levels(next_univ))
|
||||
end do
|
||||
end do
|
||||
end do
|
||||
|
||||
type is (HexLattice)
|
||||
|
||||
! Loop over lattice coordinates
|
||||
do m = 1, lat % n_axial
|
||||
do k = 1, 2*lat % n_rings - 1
|
||||
do j = 1, 2*lat % n_rings - 1
|
||||
! This array location is never used
|
||||
if (j + k < lat % n_rings + 1) then
|
||||
cycle
|
||||
! This array location is never used
|
||||
else if (j + k > 3*lat % n_rings - 1) then
|
||||
cycle
|
||||
else
|
||||
next_univ => universes(lat % universes(j, k, m))
|
||||
levels_below = max(levels_below, maximum_levels(next_univ))
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
end do
|
||||
|
||||
end select
|
||||
|
||||
end if
|
||||
end do
|
||||
|
||||
levels = 1 + levels_below
|
||||
|
||||
end function maximum_levels
|
||||
|
||||
end module geometry
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
module geometry_header
|
||||
|
||||
use constants, only: HALF, TWO, THREE
|
||||
|
||||
implicit none
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -29,7 +31,7 @@ module geometry_header
|
|||
integer :: outer ! universe to tile outside the lat
|
||||
logical :: is_3d ! Lattice has cells on z axis
|
||||
integer, allocatable :: offset(:,:,:,:) ! Distribcell offsets
|
||||
|
||||
|
||||
contains
|
||||
|
||||
procedure(are_valid_indices_), deferred :: are_valid_indices
|
||||
|
|
@ -121,7 +123,7 @@ module geometry_header
|
|||
character(len=52) :: name = "" ! User-defined name
|
||||
integer :: type ! Type of surface
|
||||
real(8), allocatable :: coeffs(:) ! Definition of surface
|
||||
integer, allocatable :: &
|
||||
integer, allocatable :: &
|
||||
neighbor_pos(:), & ! List of cells on positive side
|
||||
neighbor_neg(:) ! List of cells on negative side
|
||||
integer :: bc ! Boundary condition
|
||||
|
|
@ -141,7 +143,7 @@ module geometry_header
|
|||
integer :: material ! Material within cell (0 for universe)
|
||||
integer :: n_surfaces ! Number of surfaces within
|
||||
integer, allocatable :: offset (:) ! Distribcell offset for tally counter
|
||||
integer, allocatable :: &
|
||||
integer, allocatable :: &
|
||||
& surfaces(:) ! List of surfaces bounding cell -- note that
|
||||
! parentheses, union, etc operators will be listed
|
||||
! here too
|
||||
|
|
@ -189,7 +191,7 @@ contains
|
|||
real(8), intent(in) :: global_xyz(3)
|
||||
integer :: i_xyz(3)
|
||||
|
||||
real(8) :: xyz(3) ! global_xyz alias
|
||||
real(8) :: xyz(3) ! global_xyz alias
|
||||
|
||||
xyz = global_xyz
|
||||
|
||||
|
|
@ -209,7 +211,7 @@ contains
|
|||
real(8), intent(in) :: global_xyz(3)
|
||||
integer :: i_xyz(3)
|
||||
|
||||
real(8) :: xyz(3) ! global_xyz alias
|
||||
real(8) :: xyz(3) ! global_xyz alias
|
||||
real(8) :: alpha ! Skewed coord axis
|
||||
real(8) :: xyz_t(3) ! Local xyz
|
||||
real(8) :: dists(4) ! Squared distances from cell centers
|
||||
|
|
@ -220,16 +222,16 @@ contains
|
|||
|
||||
! Index z direction.
|
||||
if (this % is_3d) then
|
||||
i_xyz(3) = ceiling((xyz(3) - this % center(3))/this % pitch(2) + 0.5_8)&
|
||||
&+ this % n_axial/2
|
||||
i_xyz(3) = ceiling((xyz(3) - this % center(3))/this % pitch(2) + HALF)&
|
||||
+ this % n_axial/2
|
||||
else
|
||||
i_xyz(3) = 1
|
||||
end if
|
||||
|
||||
! Convert coordinates into skewed bases. The (x, alpha) basis is used to
|
||||
! find the index of the global coordinates to within 4 cells.
|
||||
alpha = xyz(2) - xyz(1) / sqrt(3.0_8)
|
||||
i_xyz(1) = floor(xyz(1) / (sqrt(3.0_8) / 2.0_8 * this % pitch(1)))
|
||||
alpha = xyz(2) - xyz(1) / sqrt(THREE)
|
||||
i_xyz(1) = floor(xyz(1) / (sqrt(THREE) / TWO * this % pitch(1)))
|
||||
i_xyz(2) = floor(alpha / this % pitch(1))
|
||||
|
||||
! Add offset to indices (the center cell is (i_x, i_alpha) = (0, 0) but
|
||||
|
|
@ -279,12 +281,12 @@ contains
|
|||
xyz = global_xyz
|
||||
|
||||
local_xyz(1) = xyz(1) - (this % lower_left(1) + &
|
||||
&(i_xyz(1) - 0.5_8)*this % pitch(1))
|
||||
(i_xyz(1) - HALF)*this % pitch(1))
|
||||
local_xyz(2) = xyz(2) - (this % lower_left(2) + &
|
||||
&(i_xyz(2) - 0.5_8)*this % pitch(2))
|
||||
(i_xyz(2) - HALF)*this % pitch(2))
|
||||
if (this % is_3d) then
|
||||
local_xyz(3) = xyz(3) - (this % lower_left(3) + &
|
||||
&(i_xyz(3) - 0.5_8)*this % pitch(3))
|
||||
(i_xyz(3) - HALF)*this % pitch(3))
|
||||
else
|
||||
local_xyz(3) = xyz(3)
|
||||
end if
|
||||
|
|
@ -304,14 +306,14 @@ contains
|
|||
|
||||
! x_l = x_g - (center + pitch_x*cos(30)*index_x)
|
||||
local_xyz(1) = xyz(1) - (this % center(1) + &
|
||||
&sqrt(3.0_8) / 2.0_8 * (i_xyz(1) - this % n_rings) * this % pitch(1))
|
||||
sqrt(THREE) / TWO * (i_xyz(1) - this % n_rings) * this % pitch(1))
|
||||
! y_l = y_g - (center + pitch_x*index_x + pitch_y*sin(30)*index_y)
|
||||
local_xyz(2) = xyz(2) - (this % center(2) + &
|
||||
&(i_xyz(2) - this % n_rings) * this % pitch(1) + &
|
||||
&(i_xyz(1) - this % n_rings) * this % pitch(1) / 2.0_8)
|
||||
(i_xyz(2) - this % n_rings) * this % pitch(1) + &
|
||||
(i_xyz(1) - this % n_rings) * this % pitch(1) / TWO)
|
||||
if (this % is_3d) then
|
||||
local_xyz(3) = xyz(3) - this % center(3) &
|
||||
&+ (this % n_axial/2 - i_xyz(3) + 1) * this % pitch(2)
|
||||
+ (this % n_axial/2 - i_xyz(3) + 1) * this % pitch(2)
|
||||
else
|
||||
local_xyz(3) = xyz(3)
|
||||
end if
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ module global
|
|||
#ifdef HDF5
|
||||
use hdf5_interface, only: HID_T
|
||||
#endif
|
||||
#ifdef MPIF08
|
||||
use mpi_f08
|
||||
#endif
|
||||
|
||||
implicit none
|
||||
save
|
||||
|
|
@ -112,11 +115,24 @@ module global
|
|||
|
||||
! Global tallies
|
||||
! 1) collision estimate of k-eff
|
||||
! 2) track-length estimate of k-eff
|
||||
! 3) leakage fraction
|
||||
! 2) absorption estimate of k-eff
|
||||
! 3) track-length estimate of k-eff
|
||||
! 4) leakage fraction
|
||||
|
||||
type(TallyResult), allocatable, target :: global_tallies(:)
|
||||
|
||||
! It is possible to protect accumulate operations on global tallies by using
|
||||
! an atomic update. However, when multiple threads accumulate to the same
|
||||
! global tally, it can cause a higher cache miss rate due to
|
||||
! invalidation. Thus, we use threadprivate variables to accumulate global
|
||||
! tallies and then reduce at the end of a generation.
|
||||
real(8) :: global_tally_collision = ZERO
|
||||
real(8) :: global_tally_absorption = ZERO
|
||||
real(8) :: global_tally_tracklength = ZERO
|
||||
real(8) :: global_tally_leakage = ZERO
|
||||
!$omp threadprivate(global_tally_collision, global_tally_absorption, &
|
||||
!$omp& global_tally_tracklength, global_tally_leakage)
|
||||
|
||||
! Tally map structure
|
||||
type(TallyMap), allocatable :: tally_maps(:)
|
||||
|
||||
|
|
@ -212,8 +228,13 @@ module global
|
|||
logical :: master = .true. ! master process?
|
||||
logical :: mpi_enabled = .false. ! is MPI in use and initialized?
|
||||
integer :: mpi_err ! MPI error code
|
||||
#ifdef MPIF08
|
||||
type(MPI_Datatype) :: MPI_BANK
|
||||
type(MPI_Datatype) :: MPI_TALLYRESULT
|
||||
#else
|
||||
integer :: MPI_BANK ! MPI datatype for fission bank
|
||||
integer :: MPI_TALLYRESULT ! MPI datatype for TallyResult
|
||||
#endif
|
||||
|
||||
#ifdef _OPENMP
|
||||
integer :: n_threads = NONE ! number of OpenMP threads
|
||||
|
|
@ -243,8 +264,8 @@ module global
|
|||
! VARIANCE REDUCTION VARIABLES
|
||||
|
||||
logical :: survival_biasing = .false.
|
||||
real(8) :: weight_cutoff = 0.25
|
||||
real(8) :: weight_survive = 1.0
|
||||
real(8) :: weight_cutoff = 0.25_8
|
||||
real(8) :: weight_survive = ONE
|
||||
|
||||
! ============================================================================
|
||||
! HDF5 VARIABLES
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ module hdf5_interface
|
|||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
#ifdef MPI
|
||||
use mpi, only: MPI_COMM_WORLD, MPI_INFO_NULL
|
||||
use message_passing, only: MPI_COMM_WORLD, MPI_INFO_NULL
|
||||
#endif
|
||||
|
||||
implicit none
|
||||
|
|
@ -149,7 +149,12 @@ contains
|
|||
|
||||
! Setup file access property list with parallel I/O access
|
||||
call h5pcreate_f(H5P_FILE_ACCESS_F, plist, hdf5_err)
|
||||
#ifdef MPIF08
|
||||
call h5pset_fapl_mpio_f(plist, MPI_COMM_WORLD%MPI_VAL, &
|
||||
MPI_INFO_NULL%MPI_VAL, hdf5_err)
|
||||
#else
|
||||
call h5pset_fapl_mpio_f(plist, MPI_COMM_WORLD, MPI_INFO_NULL, hdf5_err)
|
||||
#endif
|
||||
|
||||
! Create the file collectively
|
||||
call h5fcreate_f(trim(filename), H5F_ACC_TRUNC_F, file_id, hdf5_err, &
|
||||
|
|
@ -174,7 +179,12 @@ contains
|
|||
|
||||
! Setup file access property list with parallel I/O access
|
||||
call h5pcreate_f(H5P_FILE_ACCESS_F, plist, hdf5_err)
|
||||
#ifdef MPIF08
|
||||
call h5pset_fapl_mpio_f(plist, MPI_COMM_WORLD%MPI_VAL, &
|
||||
MPI_INFO_NULL%MPI_VAL, hdf5_err)
|
||||
#else
|
||||
call h5pset_fapl_mpio_f(plist, MPI_COMM_WORLD, MPI_INFO_NULL, hdf5_err)
|
||||
#endif
|
||||
|
||||
! Determine access type
|
||||
open_mode = H5F_ACC_RDONLY_F
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ module initialize
|
|||
use set_header, only: SetInt
|
||||
use energy_grid, only: logarithmic_grid, grid_method, unionized_grid
|
||||
use error, only: fatal_error, warning
|
||||
use geometry, only: neighbor_lists, count_instance, calc_offsets
|
||||
use geometry, only: neighbor_lists, count_instance, calc_offsets, &
|
||||
maximum_levels
|
||||
use geometry_header, only: Cell, Universe, Lattice, RectLattice, HexLattice,&
|
||||
&BASE_UNIVERSE
|
||||
use global
|
||||
|
|
@ -26,7 +27,7 @@ module initialize
|
|||
use tally_initialize, only: configure_tallies
|
||||
|
||||
#ifdef MPI
|
||||
use mpi
|
||||
use message_passing
|
||||
#endif
|
||||
|
||||
#ifdef _OPENMP
|
||||
|
|
@ -95,11 +96,20 @@ contains
|
|||
|
||||
! Initialize distribcell_filters
|
||||
call prepare_distribcell()
|
||||
|
||||
|
||||
! After reading input and basic geometry setup is complete, build lists of
|
||||
! neighboring cells for efficient tracking
|
||||
call neighbor_lists()
|
||||
|
||||
! Check to make sure there are not too many nested coordinate levels in the
|
||||
! geometry since the coordinate list is statically allocated for performance
|
||||
! reasons
|
||||
if (maximum_levels(universes(BASE_UNIVERSE)) > MAX_COORD) then
|
||||
call fatal_error("Too many nested coordinate levels in the geometry. &
|
||||
&Try increasing the maximum number of coordinate levels by &
|
||||
&providing the CMake -Dmaxcoord= option.")
|
||||
end if
|
||||
|
||||
if (run_mode /= MODE_PLOTTING) then
|
||||
! With the AWRs from the xs_listings, change all material specifications
|
||||
! so that they contain atom percents summing to 1
|
||||
|
|
@ -185,11 +195,17 @@ contains
|
|||
subroutine initialize_mpi()
|
||||
|
||||
integer :: bank_blocks(4) ! Count for each datatype
|
||||
#ifdef MPIF08
|
||||
type(MPI_Datatype) :: bank_types(4)
|
||||
type(MPI_Datatype) :: result_types(1)
|
||||
type(MPI_Datatype) :: temp_type
|
||||
#else
|
||||
integer :: bank_types(4) ! Datatypes
|
||||
integer(MPI_ADDRESS_KIND) :: bank_disp(4) ! Displacements
|
||||
integer :: temp_type ! temporary derived type
|
||||
integer :: result_blocks(1) ! Count for each datatype
|
||||
integer :: result_types(1) ! Datatypes
|
||||
integer :: temp_type ! temporary derived type
|
||||
#endif
|
||||
integer(MPI_ADDRESS_KIND) :: bank_disp(4) ! Displacements
|
||||
integer :: result_blocks(1) ! Count for each datatype
|
||||
integer(MPI_ADDRESS_KIND) :: result_disp(1) ! Displacements
|
||||
integer(MPI_ADDRESS_KIND) :: result_base_disp ! Base displacement
|
||||
integer(MPI_ADDRESS_KIND) :: lower_bound ! Lower bound for TallyResult
|
||||
|
|
@ -936,7 +952,7 @@ contains
|
|||
|
||||
count_all = .false.
|
||||
|
||||
! Loop over tallies
|
||||
! Loop over tallies
|
||||
do i = 1, n_tallies
|
||||
|
||||
! Get pointer to tally
|
||||
|
|
@ -954,25 +970,25 @@ contains
|
|||
if (size(tally % filters(j) % int_bins) > 1) then
|
||||
call fatal_error("A distribcell filter was specified with &
|
||||
&multiple bins. This feature is not supported.")
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
|
||||
end do
|
||||
|
||||
end do
|
||||
|
||||
|
||||
if (count_all) then
|
||||
|
||||
|
||||
univ => universes(BASE_UNIVERSE)
|
||||
|
||||
! sum the number of occurrences of all cells
|
||||
call count_instance(univ)
|
||||
|
||||
! Loop over tallies
|
||||
do i = 1, n_tallies
|
||||
! Loop over tallies
|
||||
do i = 1, n_tallies
|
||||
|
||||
! Get pointer to tally
|
||||
tally => tallies(i)
|
||||
tally => tallies(i)
|
||||
|
||||
! Initialize the filters
|
||||
do j = 1, tally % n_filters
|
||||
|
|
@ -993,7 +1009,7 @@ contains
|
|||
|
||||
! Calculate offsets for each target distribcell
|
||||
do i = 1, n_maps
|
||||
do j = 1, n_universes
|
||||
do j = 1, n_universes
|
||||
univ => universes(j)
|
||||
call calc_offsets(univ_list(i), i, univ, counts, found)
|
||||
end do
|
||||
|
|
@ -1003,7 +1019,7 @@ contains
|
|||
deallocate(counts)
|
||||
deallocate(found)
|
||||
deallocate(univ_list)
|
||||
|
||||
|
||||
end subroutine prepare_distribcell
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -1018,31 +1034,31 @@ contains
|
|||
logical, intent(out), allocatable :: found(:,:) ! Target found
|
||||
|
||||
integer :: i, j, k, l, m ! Loop counters
|
||||
type(SetInt) :: cell_list ! distribells to track
|
||||
type(SetInt) :: cell_list ! distribells to track
|
||||
type(Universe), pointer :: univ ! pointer to universe
|
||||
class(Lattice), pointer :: lat ! pointer to lattice
|
||||
type(TallyObject), pointer :: tally ! pointer to tally
|
||||
type(TallyFilter), pointer :: filter ! pointer to filter
|
||||
|
||||
|
||||
! Begin gathering list of cells in distribcell tallies
|
||||
n_maps = 0
|
||||
|
||||
|
||||
! Populate list of distribcells to track
|
||||
do i = 1, n_tallies
|
||||
tally => tallies(i)
|
||||
|
||||
do j = 1, tally % n_filters
|
||||
filter => tally % filters(j)
|
||||
filter => tally % filters(j)
|
||||
|
||||
if (filter % type == FILTER_DISTRIBCELL) then
|
||||
if (.not. cell_list % contains(filter % int_bins(1))) then
|
||||
call cell_list % add(filter % int_bins(1))
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
|
||||
end do
|
||||
end do
|
||||
|
||||
|
||||
! Compute the number of unique universes containing these distribcells
|
||||
! to determine the number of offset tables to allocate
|
||||
do i = 1, n_universes
|
||||
|
|
@ -1053,7 +1069,7 @@ contains
|
|||
end if
|
||||
end do
|
||||
end do
|
||||
|
||||
|
||||
! Allocate the list of offset tables for each unique universe
|
||||
allocate(univ_list(n_maps))
|
||||
|
||||
|
|
@ -1071,34 +1087,34 @@ contains
|
|||
univ => universes(i)
|
||||
|
||||
do j = 1, univ % n_cells
|
||||
|
||||
|
||||
if (cell_list % contains(univ % cells(j))) then
|
||||
|
||||
! Loop over all tallies
|
||||
|
||||
! Loop over all tallies
|
||||
do l = 1, n_tallies
|
||||
tally => tallies(l)
|
||||
|
||||
|
||||
do m = 1, tally % n_filters
|
||||
filter => tally % filters(m)
|
||||
|
||||
|
||||
! Loop over only distribcell filters
|
||||
! If filter points to cell we just found, set offset index
|
||||
if (filter % type == FILTER_DISTRIBCELL) then
|
||||
if (filter % type == FILTER_DISTRIBCELL) then
|
||||
if (filter % int_bins(1) == univ % cells(j)) then
|
||||
filter % offset = k
|
||||
end if
|
||||
end if
|
||||
|
||||
end do
|
||||
end do
|
||||
|
||||
end do
|
||||
|
||||
univ_list(k) = univ % id
|
||||
k = k + 1
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
|
||||
! Allocate the offset tables for lattices
|
||||
|
||||
! Allocate the offset tables for lattices
|
||||
do i = 1, n_lattices
|
||||
lat => lattices(i) % obj
|
||||
|
||||
|
|
|
|||
|
|
@ -1797,11 +1797,11 @@ contains
|
|||
case ('g/cc', 'g/cm3')
|
||||
mat % density = -val
|
||||
case ('kg/m3')
|
||||
mat % density = -0.001 * val
|
||||
mat % density = -0.001_8 * val
|
||||
case ('atom/b-cm')
|
||||
mat % density = val
|
||||
case ('atom/cm3', 'atom/cc')
|
||||
mat % density = 1.0e-24 * val
|
||||
mat % density = 1.0e-24_8 * val
|
||||
case default
|
||||
call fatal_error("Unkwown units '" // trim(units) &
|
||||
&// "' specified on material " // trim(to_str(mat % id)))
|
||||
|
|
|
|||
96
src/math.F90
96
src/math.F90
|
|
@ -1,6 +1,6 @@
|
|||
module math
|
||||
|
||||
use constants, only: PI, ONE, TWO, ZERO
|
||||
use constants
|
||||
use random_lcg, only: prn
|
||||
|
||||
implicit none
|
||||
|
|
@ -41,27 +41,27 @@ contains
|
|||
|
||||
q = sqrt(-TWO*log(p))
|
||||
z = (((((c(1)*q + c(2))*q + c(3))*q + c(4))*q + c(5))*q + c(6)) / &
|
||||
((((d(1)*q + d(2))*q + d(3))*q + d(4))*q + 1.)
|
||||
((((d(1)*q + d(2))*q + d(3))*q + d(4))*q + ONE)
|
||||
|
||||
elseif (p <= 1. - p_low) then
|
||||
elseif (p <= ONE - p_low) then
|
||||
! Rational approximation for central region
|
||||
|
||||
q = p - 0.5
|
||||
q = p - HALF
|
||||
r = q*q
|
||||
z = (((((a(1)*r + a(2))*r + a(3))*r + a(4))*r + a(5))*r + a(6))*q / &
|
||||
(((((b(1)*r + b(2))*r + b(3))*r + b(4))*r + b(5))*r + 1.)
|
||||
(((((b(1)*r + b(2))*r + b(3))*r + b(4))*r + b(5))*r + ONE)
|
||||
|
||||
else
|
||||
! Rational approximation for upper region
|
||||
|
||||
q = sqrt(-2*log(1. - p))
|
||||
q = sqrt(-TWO*log(ONE - p))
|
||||
z = -(((((c(1)*q + c(2))*q + c(3))*q + c(4))*q + c(5))*q + c(6)) / &
|
||||
((((d(1)*q + d(2))*q + d(3))*q + d(4))*q + 1.)
|
||||
((((d(1)*q + d(2))*q + d(3))*q + d(4))*q + ONE)
|
||||
endif
|
||||
|
||||
! Refinement based on Newton's method
|
||||
#ifndef NO_F2008
|
||||
z = z - (0.5 * erfc(-z/sqrt(TWO)) - p) * sqrt(TWO*PI) * exp(0.5*z*z)
|
||||
z = z - (HALF * erfc(-z/sqrt(TWO)) - p) * sqrt(TWO*PI) * exp(HALF*z*z)
|
||||
#endif
|
||||
|
||||
end function normal_percentile
|
||||
|
|
@ -86,13 +86,13 @@ contains
|
|||
! For one degree of freedom, the t-distribution becomes a Cauchy
|
||||
! distribution whose cdf we can invert directly
|
||||
|
||||
t = tan(PI*(p - 0.5))
|
||||
t = tan(PI*(p - HALF))
|
||||
|
||||
elseif (df == 2) then
|
||||
! For two degrees of freedom, the cdf is given by 1/2 + x/(2*sqrt(x^2 +
|
||||
! 2)). This can be directly inverted to yield the solution below
|
||||
|
||||
t = TWO*sqrt(TWO)*(p - 0.5)/sqrt(ONE - 4.*(p - 0.5)**2)
|
||||
t = TWO*sqrt(TWO)*(p - HALF)/sqrt(ONE - FOUR*(p - HALF)**2)
|
||||
|
||||
else
|
||||
|
||||
|
|
@ -102,12 +102,12 @@ contains
|
|||
! 16 (4), pp. 1123-1132 (1987).
|
||||
|
||||
n = real(df,8)
|
||||
k = 1./(n - 2.)
|
||||
k = ONE/(n - TWO)
|
||||
z = normal_percentile(p)
|
||||
z2 = z * z
|
||||
t = sqrt(n*k) * (z + (z2 - 3.)*z*k/4. + ((5.*z2 - 56.)*z2 + &
|
||||
75.)*z*k*k/96. + (((z2 - 27.)*3.*z2 + 417.)*z2 - 315.) &
|
||||
*z*k*k*k/384.)
|
||||
t = sqrt(n*k) * (z + (z2 - THREE)*z*k/FOUR + ((5._8*z2 - 56._8)*z2 + &
|
||||
75._8)*z*k*k/96._8 + (((z2 - 27._8)*THREE*z2 + 417._8)*z2 - 315._8) &
|
||||
*z*k*k*k/384._8)
|
||||
|
||||
end if
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ contains
|
|||
case(1)
|
||||
pnx = x
|
||||
case(2)
|
||||
pnx = 1.5_8 * x * x - 0.5_8
|
||||
pnx = 1.5_8 * x * x - HALF
|
||||
case(3)
|
||||
pnx = 2.5_8 * x * x * x - 1.5_8 * x
|
||||
case(4)
|
||||
|
|
@ -199,37 +199,37 @@ contains
|
|||
rn(3) = ONE*sqrt(w2m1) * cos(phi)
|
||||
case (2)
|
||||
! l = 2, m = -2
|
||||
rn(1) = 0.288675134594813_8 * (-3.0_8 * w**2 + 3.0_8) * sin(TWO*phi)
|
||||
rn(1) = 0.288675134594813_8 * (-THREE * w**2 + THREE) * sin(TWO*phi)
|
||||
! l = 2, m = -1
|
||||
rn(2) = 1.73205080756888_8 * w*sqrt(w2m1) * sin(phi)
|
||||
! l = 2, m = 0
|
||||
rn(3) = 1.5_8 * w**2 - 0.5_8
|
||||
rn(3) = 1.5_8 * w**2 - HALF
|
||||
! l = 2, m = 1
|
||||
rn(4) = 1.73205080756888_8 * w*sqrt(w2m1) * cos(phi)
|
||||
! l = 2, m = 2
|
||||
rn(5) = 0.288675134594813_8 * (-3.0_8 * w**2 + 3.0_8) * cos(TWO*phi)
|
||||
rn(5) = 0.288675134594813_8 * (-THREE * w**2 + THREE) * cos(TWO*phi)
|
||||
case (3)
|
||||
! l = 3, m = -3
|
||||
rn(1) = 0.790569415042095_8 * (w2m1)**(3.0_8/TWO) * sin(3.0_8 * phi)
|
||||
rn(1) = 0.790569415042095_8 * (w2m1)**(THREE/TWO) * sin(THREE * phi)
|
||||
! l = 3, m = -2
|
||||
rn(2) = 1.93649167310371_8 * w*(w2m1) * sin(TWO*phi)
|
||||
! l = 3, m = -1
|
||||
rn(3) = 0.408248290463863_8*sqrt(w2m1)*((15.0_8/TWO)*w**2 - 3.0_8/TWO) * &
|
||||
rn(3) = 0.408248290463863_8*sqrt(w2m1)*((15.0_8/TWO)*w**2 - THREE/TWO) * &
|
||||
sin(phi)
|
||||
! l = 3, m = 0
|
||||
rn(4) = 2.5_8 * w**3 - 1.5_8 * w
|
||||
! l = 3, m = 1
|
||||
rn(5) = 0.408248290463863_8*sqrt(w2m1)*((15.0_8/TWO)*w**2 - 3.0_8/TWO) * &
|
||||
rn(5) = 0.408248290463863_8*sqrt(w2m1)*((15.0_8/TWO)*w**2 - THREE/TWO) * &
|
||||
cos(phi)
|
||||
! l = 3, m = 2
|
||||
rn(6) = 1.93649167310371_8 * w*(w2m1) * cos(TWO*phi)
|
||||
! l = 3, m = 3
|
||||
rn(7) = 0.790569415042095_8 * (w2m1)**(3.0_8/TWO) * cos(3.0_8* phi)
|
||||
rn(7) = 0.790569415042095_8 * (w2m1)**(THREE/TWO) * cos(THREE* phi)
|
||||
case (4)
|
||||
! l = 4, m = -4
|
||||
rn(1) = 0.739509972887452_8 * (w2m1)**2 * sin(4.0_8*phi)
|
||||
! l = 4, m = -3
|
||||
rn(2) = 2.09165006633519_8 * w*(w2m1)**(3.0_8/TWO) * sin(3.0_8* phi)
|
||||
rn(2) = 2.09165006633519_8 * w*(w2m1)**(THREE/TWO) * sin(THREE* phi)
|
||||
! l = 4, m = -2
|
||||
rn(3) = 0.074535599249993_8 * (w2m1)*((105.0_8/TWO)*w**2 - 15.0_8/TWO) * &
|
||||
sin(TWO*phi)
|
||||
|
|
@ -245,7 +245,7 @@ contains
|
|||
rn(7) = 0.074535599249993_8 * (w2m1)*((105.0_8/TWO)*w**2 - 15.0_8/TWO) * &
|
||||
cos(TWO*phi)
|
||||
! l = 4, m = 3
|
||||
rn(8) = 2.09165006633519_8 * w*(w2m1)**(3.0_8/TWO) * cos(3.0_8* phi)
|
||||
rn(8) = 2.09165006633519_8 * w*(w2m1)**(THREE/TWO) * cos(THREE* phi)
|
||||
! l = 4, m = 4
|
||||
rn(9) = 0.739509972887452_8 * (w2m1)**2 * cos(4.0_8*phi)
|
||||
case (5)
|
||||
|
|
@ -254,8 +254,8 @@ contains
|
|||
! l = 5, m = -4
|
||||
rn(2) = 2.21852991866236_8 * w*(w2m1)**2 * sin(4.0_8*phi)
|
||||
! l = 5, m = -3
|
||||
rn(3) = 0.00996023841111995_8 * (w2m1)**(3.0_8/TWO)* &
|
||||
((945.0_8 /TWO)*w**2 - 105.0_8/TWO) * sin(3.0_8*phi)
|
||||
rn(3) = 0.00996023841111995_8 * (w2m1)**(THREE/TWO)* &
|
||||
((945.0_8 /TWO)*w**2 - 105.0_8/TWO) * sin(THREE*phi)
|
||||
! l = 5, m = -2
|
||||
rn(4) = 0.0487950036474267_8 * (w2m1)*((315.0_8/TWO)*w**3 - 105.0_8/TWO*w) * &
|
||||
sin(TWO*phi)
|
||||
|
|
@ -271,8 +271,8 @@ contains
|
|||
rn(8) = 0.0487950036474267_8 * (w2m1)* &
|
||||
((315.0_8/TWO)*w**3 - 105.0_8/TWO*w) * cos(TWO*phi)
|
||||
! l = 5, m = 3
|
||||
rn(9) = 0.00996023841111995_8 * (w2m1)**(3.0_8/TWO)* &
|
||||
((945.0_8 /TWO)*w**2 - 105.0_8/TWO) * cos(3.0_8*phi)
|
||||
rn(9) = 0.00996023841111995_8 * (w2m1)**(THREE/TWO)* &
|
||||
((945.0_8 /TWO)*w**2 - 105.0_8/TWO) * cos(THREE*phi)
|
||||
! l = 5, m = 4
|
||||
rn(10) = 2.21852991866236_8 * w*(w2m1)**2 * cos(4.0_8*phi)
|
||||
! l = 5, m = 5
|
||||
|
|
@ -286,8 +286,8 @@ contains
|
|||
rn(3) = 0.00104990131391452_8 * (w2m1)**2 * &
|
||||
((10395.0_8/TWO)*w**2 - 945.0_8/TWO) * sin(4.0_8*phi)
|
||||
! l = 6, m = -3
|
||||
rn(4) = 0.00575054632785295_8 * (w2m1)**(3.0_8/TWO) * &
|
||||
((3465.0_8/TWO)*w**3 - 945.0_8/TWO*w) * sin(3.0_8*phi)
|
||||
rn(4) = 0.00575054632785295_8 * (w2m1)**(THREE/TWO) * &
|
||||
((3465.0_8/TWO)*w**3 - 945.0_8/TWO*w) * sin(THREE*phi)
|
||||
! l = 6, m = -2
|
||||
rn(5) = 0.0345032779671177_8 * (w2m1) * &
|
||||
((3465.0_8/8.0_8)*w**4 - 945.0_8/4.0_8 * w**2 + 105.0_8/8.0_8) * sin(TWO*phi)
|
||||
|
|
@ -303,8 +303,8 @@ contains
|
|||
rn(9) = 0.0345032779671177_8 * (w2m1) * &
|
||||
((3465.0_8/8.0_8)*w**4 -945.0_8/4.0_8 * w**2 + 105.0_8/8.0_8) * cos(TWO*phi)
|
||||
! l = 6, m = 3
|
||||
rn(10) = 0.00575054632785295_8 * (w2m1)**(3.0_8/TWO) * &
|
||||
((3465.0_8/TWO)*w**3 - 945.0_8/TWO*w) * cos(3.0_8*phi)
|
||||
rn(10) = 0.00575054632785295_8 * (w2m1)**(THREE/TWO) * &
|
||||
((3465.0_8/TWO)*w**3 - 945.0_8/TWO*w) * cos(THREE*phi)
|
||||
! l = 6, m = 4
|
||||
rn(11) = 0.00104990131391452_8 * (w2m1)**2 * &
|
||||
((10395.0_8/TWO)*w**2 - 945.0_8/TWO) * cos(4.0_8*phi)
|
||||
|
|
@ -324,9 +324,9 @@ contains
|
|||
rn(4) = 0.000548293079133141_8 * (w2m1)**2* &
|
||||
((45045.0_8/TWO)*w**3 - 10395.0_8/TWO*w) * sin(4.0_8*phi)
|
||||
! l = 7, m = -3
|
||||
rn(5) = 0.00363696483726654_8 * (w2m1)**(3.0_8/TWO)* &
|
||||
rn(5) = 0.00363696483726654_8 * (w2m1)**(THREE/TWO)* &
|
||||
((45045.0_8/8.0_8)*w**4 - 10395.0_8/4.0_8 * w**2 + 945.0_8/8.0_8)* &
|
||||
sin(3.0_8*phi)
|
||||
sin(THREE*phi)
|
||||
! l = 7, m = -2
|
||||
rn(6) = 0.025717224993682_8 * (w2m1)* &
|
||||
((9009.0_8/8.0_8)*w**5 -3465.0_8/4.0_8 * w**3 + (945.0_8/8.0_8)*w)* &
|
||||
|
|
@ -346,9 +346,9 @@ contains
|
|||
((9009.0_8/8.0_8)*w**5 -3465.0_8/4.0_8 * w**3 + (945.0_8/8.0_8)*w)* &
|
||||
cos(TWO*phi)
|
||||
! l = 7, m = 3
|
||||
rn(11) = 0.00363696483726654_8 * (w2m1)**(3.0_8/TWO)* &
|
||||
rn(11) = 0.00363696483726654_8 * (w2m1)**(THREE/TWO)* &
|
||||
((45045.0_8/8.0_8)*w**4 - 10395.0_8/4.0_8 * w**2 + 945.0_8/8.0_8)* &
|
||||
cos(3.0_8*phi)
|
||||
cos(THREE*phi)
|
||||
! l = 7, m = 4
|
||||
rn(12) = 0.000548293079133141_8 * (w2m1)**2 * &
|
||||
((45045.0_8/TWO)*w**3 - 10395.0_8/TWO*w) * cos(4.0_8*phi)
|
||||
|
|
@ -374,8 +374,8 @@ contains
|
|||
rn(5) = 0.000316557156832328_8 * (w2m1)**2* &
|
||||
((675675.0_8/8.0_8)*w**4 - 135135.0_8/4.0_8 * w**2 + 10395.0_8/8.0_8) * sin(4.0_8*phi)
|
||||
! l = 8, m = -3
|
||||
rn(6) = 0.00245204119306875_8 * (w2m1)**(3.0_8/TWO)* &
|
||||
((135135.0_8/8.0_8)*w**5 - 45045.0_8/4.0_8 * w**3 + (10395.0_8/8.0_8)*w) * sin(3.0_8*phi)
|
||||
rn(6) = 0.00245204119306875_8 * (w2m1)**(THREE/TWO)* &
|
||||
((135135.0_8/8.0_8)*w**5 - 45045.0_8/4.0_8 * w**3 + (10395.0_8/8.0_8)*w) * sin(THREE*phi)
|
||||
! l = 8, m = -2
|
||||
rn(7) = 0.0199204768222399_8 * (w2m1)* &
|
||||
((45045.0_8/16.0_8)*w**6- 45045.0_8/16.0_8 * w**4 + &
|
||||
|
|
@ -396,9 +396,9 @@ contains
|
|||
45045.0_8/16.0_8 * w**4 + (10395.0_8/16.0_8)*w**2 - &
|
||||
315.0_8/16.0_8) * cos(TWO*phi)
|
||||
! l = 8, m = 3
|
||||
rn(12) = 0.00245204119306875_8 * (w2m1)**(3.0_8/TWO)* &
|
||||
rn(12) = 0.00245204119306875_8 * (w2m1)**(THREE/TWO)* &
|
||||
((135135.0_8/8.0_8)*w**5 - 45045.0_8/4.0_8 * w**3 + &
|
||||
(10395.0_8/8.0_8)*w) * cos(3.0_8*phi)
|
||||
(10395.0_8/8.0_8)*w) * cos(THREE*phi)
|
||||
! l = 8, m = 4
|
||||
rn(13) = 0.000316557156832328_8 * (w2m1)**2*((675675.0_8/8.0_8)*w**4 - &
|
||||
135135.0_8/4.0_8 * w**2 + 10395.0_8/8.0_8) * cos(4.0_8*phi)
|
||||
|
|
@ -431,9 +431,9 @@ contains
|
|||
rn(6) = 0.000196320414650061_8 * (w2m1)**2*((2297295.0_8/8.0_8)*w**5 - &
|
||||
675675.0_8/4.0_8 * w**3 + (135135.0_8/8.0_8)*w) * sin(4.0_8*phi)
|
||||
! l = 9, m = -3
|
||||
rn(7) = 0.00173385495536766_8 * (w2m1)**(3.0_8/TWO)* &
|
||||
rn(7) = 0.00173385495536766_8 * (w2m1)**(THREE/TWO)* &
|
||||
((765765.0_8/16.0_8)*w**6 - 675675.0_8/16.0_8 * w**4 + &
|
||||
(135135.0_8/16.0_8)*w**2 - 3465.0_8/16.0_8) * sin(3.0_8*phi)
|
||||
(135135.0_8/16.0_8)*w**2 - 3465.0_8/16.0_8) * sin(THREE*phi)
|
||||
! l = 9, m = -2
|
||||
rn(8) = 0.0158910431540932_8 * (w2m1)*((109395.0_8/16.0_8)*w**7- &
|
||||
135135.0_8/16.0_8 * w**5 + (45045.0_8/16.0_8)*w**3 - 3465.0_8/16.0_8 * w)* &
|
||||
|
|
@ -452,9 +452,9 @@ contains
|
|||
135135.0_8/16.0_8 * w**5 + (45045.0_8/16.0_8)*w**3 - 3465.0_8/ 16.0_8 * w) * &
|
||||
cos(TWO*phi)
|
||||
! l = 9, m = 3
|
||||
rn(13) = 0.00173385495536766_8 * (w2m1)**(3.0_8/TWO)*((765765.0_8/16.0_8)*w**6 - &
|
||||
rn(13) = 0.00173385495536766_8 * (w2m1)**(THREE/TWO)*((765765.0_8/16.0_8)*w**6 - &
|
||||
675675.0_8/16.0_8 * w**4 + (135135.0_8/16.0_8)*w**2 - 3465.0_8/16.0_8)* &
|
||||
cos(3.0_8*phi)
|
||||
cos(THREE*phi)
|
||||
! l = 9, m = 4
|
||||
rn(14) = 0.000196320414650061_8 * (w2m1)**2*((2297295.0_8/8.0_8)*w**5 - &
|
||||
675675.0_8/4.0_8 * w**3 + (135135.0_8/8.0_8)*w) * cos(4.0_8*phi)
|
||||
|
|
@ -494,9 +494,9 @@ contains
|
|||
11486475.0_8/16.0_8 * w**4 + (2027025.0_8/16.0_8)*w**2 - &
|
||||
45045.0_8/16.0_8) * sin(4.0_8*phi)
|
||||
! l = 10, m = -3
|
||||
rn(8) = 0.00127230170115096_8 * (w2m1)**(3.0_8/TWO)* &
|
||||
rn(8) = 0.00127230170115096_8 * (w2m1)**(THREE/TWO)* &
|
||||
((2078505.0_8/16.0_8)*w**7 - 2297295.0_8/16.0_8 * w**5 + &
|
||||
(675675.0_8/16.0_8)*w**3 - 45045.0_8/16.0_8 * w) * sin(3.0_8*phi)
|
||||
(675675.0_8/16.0_8)*w**3 - 45045.0_8/16.0_8 * w) * sin(THREE*phi)
|
||||
! l = 10, m = -2
|
||||
rn(9) = 0.012974982402692_8 * (w2m1)*((2078505.0_8/128.0_8)*w**8 - &
|
||||
765765.0_8/32.0_8 * w**6 + (675675.0_8/64.0_8)*w**4 - &
|
||||
|
|
@ -517,9 +517,9 @@ contains
|
|||
765765.0_8/32.0_8 * w**6 + (675675.0_8/64.0_8)*w**4 -&
|
||||
45045.0_8/32.0_8 * w**2 + 3465.0_8/128.0_8) * cos(TWO*phi)
|
||||
! l = 10, m = 3
|
||||
rn(14) = 0.00127230170115096_8 * (w2m1)**(3.0_8/TWO)* &
|
||||
rn(14) = 0.00127230170115096_8 * (w2m1)**(THREE/TWO)* &
|
||||
((2078505.0_8/16.0_8)*w**7 - 2297295.0_8/16.0_8 * w**5 + &
|
||||
(675675.0_8/16.0_8)*w**3 - 45045.0_8/16.0_8 * w) * cos(3.0_8*phi)
|
||||
(675675.0_8/16.0_8)*w**3 - 45045.0_8/16.0_8 * w) * cos(THREE*phi)
|
||||
! l = 10, m = 4
|
||||
rn(15) = 0.000128521880085575_8 * (w2m1)**2*((14549535.0_8/16.0_8)*w**6 - &
|
||||
11486475.0_8/16.0_8 * w**4 + (2027025.0_8/16.0_8)*w**2 - &
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ module mesh
|
|||
use search, only: binary_search
|
||||
|
||||
#ifdef MPI
|
||||
use mpi
|
||||
use message_passing
|
||||
#endif
|
||||
|
||||
implicit none
|
||||
|
|
|
|||
11
src/message_passing.F90
Normal file
11
src/message_passing.F90
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
module message_passing
|
||||
|
||||
#ifdef MPI
|
||||
#ifdef MPIF08
|
||||
use mpi_f08
|
||||
#else
|
||||
use mpi
|
||||
#endif
|
||||
#endif
|
||||
|
||||
end module message_passing
|
||||
|
|
@ -1,10 +1,17 @@
|
|||
module mpiio_interface
|
||||
|
||||
#ifdef MPI
|
||||
use mpi
|
||||
#ifndef HDF5
|
||||
use message_passing
|
||||
|
||||
implicit none
|
||||
|
||||
#ifdef MPIF08
|
||||
#define FH_TYPE type(MPI_File)
|
||||
#else
|
||||
#define FH_TYPE integer
|
||||
#endif
|
||||
|
||||
integer :: mpiio_err ! MPI error code
|
||||
|
||||
! Generic HDF5 write procedure interface
|
||||
|
|
@ -48,11 +55,11 @@ contains
|
|||
subroutine mpi_create_file(filename, fh)
|
||||
|
||||
character(*), intent(in) :: filename ! name of file to create
|
||||
integer, intent(inout) :: fh ! file handle
|
||||
FH_TYPE, intent(inout) :: fh ! file handle
|
||||
|
||||
! Create the file
|
||||
call MPI_FILE_OPEN(MPI_COMM_WORLD, filename, MPI_MODE_CREATE + &
|
||||
MPI_MODE_WRONLY, MPI_INFO_NULL, fh, mpiio_err)
|
||||
MPI_MODE_WRONLY, MPI_INFO_NULL, fh, mpiio_err)
|
||||
|
||||
end subroutine mpi_create_file
|
||||
|
||||
|
|
@ -64,7 +71,7 @@ contains
|
|||
|
||||
character(*), intent(in) :: filename ! name of file to open
|
||||
character(*), intent(in) :: mode ! open 'r' read, 'w' write
|
||||
integer, intent(inout) :: fh ! file handle
|
||||
FH_TYPE, intent(inout) :: fh ! file handle
|
||||
|
||||
integer :: open_mode
|
||||
|
||||
|
|
@ -76,7 +83,7 @@ contains
|
|||
|
||||
! Create the file
|
||||
call MPI_FILE_OPEN(MPI_COMM_WORLD, filename, &
|
||||
open_mode, MPI_INFO_NULL, fh, mpiio_err)
|
||||
open_mode, MPI_INFO_NULL, fh, mpiio_err)
|
||||
|
||||
end subroutine mpi_open_file
|
||||
|
||||
|
|
@ -86,7 +93,7 @@ contains
|
|||
|
||||
subroutine mpi_close_file(fh)
|
||||
|
||||
integer, intent(inout) :: fh ! file handle
|
||||
FH_TYPE, intent(inout) :: fh ! file handle
|
||||
|
||||
call MPI_FILE_CLOSE(fh, mpiio_err)
|
||||
|
||||
|
|
@ -98,16 +105,16 @@ contains
|
|||
|
||||
subroutine mpi_write_integer(fh, buffer, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: buffer ! data to write
|
||||
logical, intent(in) :: collect ! collective I/O
|
||||
|
||||
if (collect) then
|
||||
call MPI_FILE_WRITE_ALL(fh, buffer, 1, MPI_INTEGER, &
|
||||
MPI_STATUS_IGNORE, mpiio_err)
|
||||
MPI_STATUS_IGNORE, mpiio_err)
|
||||
else
|
||||
call MPI_FILE_WRITE(fh, buffer, 1, MPI_INTEGER, &
|
||||
MPI_STATUS_IGNORE, mpiio_err)
|
||||
MPI_STATUS_IGNORE, mpiio_err)
|
||||
end if
|
||||
|
||||
end subroutine mpi_write_integer
|
||||
|
|
@ -118,7 +125,7 @@ contains
|
|||
|
||||
subroutine mpi_read_integer(fh, buffer, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(inout) :: buffer ! read data to here
|
||||
logical, intent(in) :: collect ! collective I/O
|
||||
|
||||
|
|
@ -138,7 +145,7 @@ contains
|
|||
|
||||
subroutine mpi_write_integer_1Darray(fh, buffer, length, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length ! length of array
|
||||
integer, intent(in) :: buffer(:) ! data to write
|
||||
logical, intent(in) :: collect ! collective I/O
|
||||
|
|
@ -159,7 +166,7 @@ contains
|
|||
|
||||
subroutine mpi_read_integer_1Darray(fh, buffer, length, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length ! length of array
|
||||
integer, intent(inout) :: buffer(:) ! read data to here
|
||||
logical, intent(in) :: collect ! collective I/O
|
||||
|
|
@ -180,7 +187,7 @@ contains
|
|||
|
||||
subroutine mpi_write_integer_2Darray(fh, buffer, length, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length(2) ! length of array
|
||||
integer, intent(in) :: buffer(length(1),length(2)) ! data to write
|
||||
logical, intent(in) :: collect ! collective I/O
|
||||
|
|
@ -201,7 +208,7 @@ contains
|
|||
|
||||
subroutine mpi_read_integer_2Darray(fh, buffer, length, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length(2) ! length of array
|
||||
integer, intent(inout) :: buffer(length(1),length(2)) ! read data to here
|
||||
logical, intent(in) :: collect ! collective I/O
|
||||
|
|
@ -222,7 +229,7 @@ contains
|
|||
|
||||
subroutine mpi_write_integer_3Darray(fh, buffer, length, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length(3) ! length of array
|
||||
integer, intent(in) :: buffer(length(1),length(2),&
|
||||
length(3)) ! data to write
|
||||
|
|
@ -244,7 +251,7 @@ contains
|
|||
|
||||
subroutine mpi_read_integer_3Darray(fh, buffer, length, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length(3) ! length of array
|
||||
integer, intent(inout) :: buffer(length(1),length(2), &
|
||||
length(3)) ! read data to here
|
||||
|
|
@ -266,7 +273,7 @@ contains
|
|||
|
||||
subroutine mpi_write_integer_4Darray(fh, buffer, length, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length(4) ! length of array
|
||||
integer, intent(in) :: buffer(length(1),length(2),&
|
||||
length(3),length(4)) ! data to write
|
||||
|
|
@ -288,7 +295,7 @@ contains
|
|||
|
||||
subroutine mpi_read_integer_4Darray(fh, buffer, length, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length(4) ! length of array
|
||||
integer, intent(inout) :: buffer(length(1),length(2), &
|
||||
length(3),length(4)) ! read data to here
|
||||
|
|
@ -310,16 +317,16 @@ contains
|
|||
|
||||
subroutine mpi_write_double(fh, buffer, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
real(8), intent(in) :: buffer ! data to write
|
||||
logical, intent(in) :: collect ! collective I/O
|
||||
|
||||
if (collect) then
|
||||
call MPI_FILE_WRITE_ALL(fh, buffer, 1, MPI_REAL8, &
|
||||
MPI_STATUS_IGNORE, mpiio_err)
|
||||
MPI_STATUS_IGNORE, mpiio_err)
|
||||
else
|
||||
call MPI_FILE_WRITE(fh, buffer, 1, MPI_REAL8, &
|
||||
MPI_STATUS_IGNORE, mpiio_err)
|
||||
MPI_STATUS_IGNORE, mpiio_err)
|
||||
end if
|
||||
|
||||
end subroutine mpi_write_double
|
||||
|
|
@ -330,7 +337,7 @@ contains
|
|||
|
||||
subroutine mpi_read_double(fh, buffer, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
real(8), intent(inout) :: buffer ! read data to here
|
||||
logical, intent(in) :: collect ! collective I/O
|
||||
|
||||
|
|
@ -350,7 +357,7 @@ contains
|
|||
|
||||
subroutine mpi_write_double_1Darray(fh, buffer, length, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length ! length of array
|
||||
real(8), intent(in) :: buffer(:) ! data to write
|
||||
logical, intent(in) :: collect ! collective I/O
|
||||
|
|
@ -371,7 +378,7 @@ contains
|
|||
|
||||
subroutine mpi_read_double_1Darray(fh, buffer, length, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length ! length of array
|
||||
real(8), intent(inout) :: buffer(:) ! read data to here
|
||||
logical, intent(in) :: collect ! collective I/O
|
||||
|
|
@ -392,7 +399,7 @@ contains
|
|||
|
||||
subroutine mpi_write_double_2Darray(fh, buffer, length, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length(2) ! length of array
|
||||
real(8), intent(in) :: buffer(length(1),length(2)) ! data to write
|
||||
logical, intent(in) :: collect ! collective I/O
|
||||
|
|
@ -413,7 +420,7 @@ contains
|
|||
|
||||
subroutine mpi_read_double_2Darray(fh, buffer, length, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length(2) ! length of array
|
||||
real(8), intent(inout) :: buffer(length(1),length(2)) ! read data to here
|
||||
logical, intent(in) :: collect ! collective I/O
|
||||
|
|
@ -434,7 +441,7 @@ contains
|
|||
|
||||
subroutine mpi_write_double_3Darray(fh, buffer, length, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length(3) ! length of array
|
||||
real(8), intent(in) :: buffer(length(1),length(2),&
|
||||
length(3)) ! data to write
|
||||
|
|
@ -456,7 +463,7 @@ contains
|
|||
|
||||
subroutine mpi_read_double_3Darray(fh, buffer, length, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length(3) ! length of array
|
||||
real(8), intent(inout) :: buffer(length(1),length(2), &
|
||||
length(3)) ! read data to here
|
||||
|
|
@ -478,7 +485,7 @@ contains
|
|||
|
||||
subroutine mpi_write_double_4Darray(fh, buffer, length, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length(4) ! length of array
|
||||
real(8), intent(in) :: buffer(length(1),length(2),&
|
||||
length(3),length(4)) ! data to write
|
||||
|
|
@ -500,7 +507,7 @@ contains
|
|||
|
||||
subroutine mpi_read_double_4Darray(fh, buffer, length, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length(4) ! length of array
|
||||
real(8), intent(inout) :: buffer(length(1),length(2), &
|
||||
length(3),length(4)) ! read data to here
|
||||
|
|
@ -522,7 +529,7 @@ contains
|
|||
|
||||
subroutine mpi_write_long(fh, buffer, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer(8), intent(in) :: buffer ! data to write
|
||||
logical, intent(in) :: collect ! collective I/O
|
||||
|
||||
|
|
@ -542,7 +549,7 @@ contains
|
|||
|
||||
subroutine mpi_read_long(fh, buffer, collect)
|
||||
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer(8), intent(inout) :: buffer ! read data to here
|
||||
logical, intent(in) :: collect ! collective I/O
|
||||
|
||||
|
|
@ -563,7 +570,7 @@ contains
|
|||
subroutine mpi_write_string(fh, buffer, length, collect)
|
||||
|
||||
character(*), intent(in) :: buffer ! data to write
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length ! length of data
|
||||
logical, intent(in) :: collect ! collective I/O
|
||||
|
||||
|
|
@ -584,7 +591,7 @@ contains
|
|||
subroutine mpi_read_string(fh, buffer, length, collect)
|
||||
|
||||
character(*), intent(inout) :: buffer ! read data to here
|
||||
integer, intent(in) :: fh ! file handle
|
||||
FH_TYPE, intent(in) :: fh ! file handle
|
||||
integer, intent(in) :: length ! length of string
|
||||
logical, intent(in) :: collect ! collective I/O
|
||||
|
||||
|
|
@ -598,5 +605,6 @@ contains
|
|||
|
||||
end subroutine mpi_read_string
|
||||
|
||||
#endif
|
||||
#endif
|
||||
end module mpiio_interface
|
||||
|
|
|
|||
|
|
@ -258,7 +258,6 @@ contains
|
|||
type(Surface), pointer :: s => null()
|
||||
type(Universe), pointer :: u => null()
|
||||
class(Lattice), pointer :: l => null()
|
||||
type(LocalCoord), pointer :: coord => null()
|
||||
|
||||
! display type of particle
|
||||
select case (p % type)
|
||||
|
|
@ -273,39 +272,34 @@ contains
|
|||
end select
|
||||
|
||||
! loop through each level of universes
|
||||
coord => p % coord0
|
||||
i = 0
|
||||
do while(associated(coord))
|
||||
do i = 1, p % n_coord
|
||||
! Print level
|
||||
write(ou,*) ' Level ' // trim(to_str(i))
|
||||
write(ou,*) ' Level ' // trim(to_str(i - 1))
|
||||
|
||||
! Print cell for this level
|
||||
if (coord % cell /= NONE) then
|
||||
c => cells(coord % cell)
|
||||
if (p % coord(i) % cell /= NONE) then
|
||||
c => cells(p % coord(i) % cell)
|
||||
write(ou,*) ' Cell = ' // trim(to_str(c % id))
|
||||
end if
|
||||
|
||||
! Print universe for this level
|
||||
if (coord % universe /= NONE) then
|
||||
u => universes(coord % universe)
|
||||
if (p % coord(i) % universe /= NONE) then
|
||||
u => universes(p % coord(i) % universe)
|
||||
write(ou,*) ' Universe = ' // trim(to_str(u % id))
|
||||
end if
|
||||
|
||||
! Print information on lattice
|
||||
if (coord % lattice /= NONE) then
|
||||
l => lattices(coord % lattice) % obj
|
||||
if (p % coord(i) % lattice /= NONE) then
|
||||
l => lattices(p % coord(i) % lattice) % obj
|
||||
write(ou,*) ' Lattice = ' // trim(to_str(l % id))
|
||||
write(ou,*) ' Lattice position = (' // trim(to_str(&
|
||||
p % coord % lattice_x)) // ',' // trim(to_str(&
|
||||
p % coord % lattice_y)) // ')'
|
||||
p % coord(i) % lattice_x)) // ',' // trim(to_str(&
|
||||
p % coord(i) % lattice_y)) // ')'
|
||||
end if
|
||||
|
||||
! Print local coordinates
|
||||
write(ou,'(1X,A,3ES12.4)') ' xyz = ', coord % xyz
|
||||
write(ou,'(1X,A,3ES12.4)') ' uvw = ', coord % uvw
|
||||
|
||||
coord => coord % next
|
||||
i = i + 1
|
||||
write(ou,'(1X,A,3ES12.4)') ' xyz = ', p % coord(i) % xyz
|
||||
write(ou,'(1X,A,3ES12.4)') ' uvw = ', p % coord(i) % uvw
|
||||
end do
|
||||
|
||||
! Print surface
|
||||
|
|
@ -2181,9 +2175,9 @@ contains
|
|||
end select
|
||||
|
||||
end function get_label
|
||||
|
||||
|
||||
!===============================================================================
|
||||
! FIND_OFFSET uses a given map number, a target cell ID, and a target offset
|
||||
! FIND_OFFSET uses a given map number, a target cell ID, and a target offset
|
||||
! to build a string which is the path from the base universe to the target cell
|
||||
! with the given offset
|
||||
!===============================================================================
|
||||
|
|
@ -2196,7 +2190,7 @@ contains
|
|||
integer, intent(in) :: final ! Target offset
|
||||
integer, intent(inout) :: offset ! Current offset
|
||||
character(100) :: path ! Path to offset
|
||||
|
||||
|
||||
integer :: i, j ! Index over cells
|
||||
integer :: k, l, m ! Indices in lattice
|
||||
integer :: old_k, old_l, old_m ! Previous indices in lattice
|
||||
|
|
@ -2212,7 +2206,7 @@ contains
|
|||
class(Lattice), pointer :: lat ! Pointer to current lattice
|
||||
|
||||
n = univ % n_cells
|
||||
|
||||
|
||||
! Write to the geometry stack
|
||||
if (univ%id == 0) then
|
||||
path = trim(path) // to_str(univ%id)
|
||||
|
|
@ -2223,31 +2217,31 @@ contains
|
|||
! Look through all cells in this universe
|
||||
do i = 1, n
|
||||
|
||||
cell_index = univ % cells(i)
|
||||
cell_index = univ % cells(i)
|
||||
c => cells(cell_index)
|
||||
|
||||
|
||||
! If the cell ID matches the goal and the offset matches final,
|
||||
! write to the geometry stack
|
||||
if (cell_dict % get_key(c % id) == goal .AND. offset == final) then
|
||||
path = trim(path) // "->" // to_str(c%id)
|
||||
return
|
||||
end if
|
||||
|
||||
|
||||
end do
|
||||
|
||||
|
||||
! Find the fill cell or lattice cell that we need to enter
|
||||
do i = 1, n
|
||||
|
||||
later_cell = .false.
|
||||
|
||||
cell_index = univ % cells(i)
|
||||
cell_index = univ % cells(i)
|
||||
c => cells(cell_index)
|
||||
|
||||
this_cell = .false.
|
||||
this_cell = .false.
|
||||
|
||||
! If we got here, we still think the target is in this universe
|
||||
! or further down, but it's not this exact cell.
|
||||
! Compare offset to next cell to see if we should enter this cell
|
||||
! or further down, but it's not this exact cell.
|
||||
! Compare offset to next cell to see if we should enter this cell
|
||||
if (i /= n) then
|
||||
|
||||
do j = i+1, n
|
||||
|
|
@ -2260,8 +2254,8 @@ contains
|
|||
cycle
|
||||
end if
|
||||
|
||||
! Break loop once we've found the next cell with an offset
|
||||
exit
|
||||
! Break loop once we've found the next cell with an offset
|
||||
exit
|
||||
end do
|
||||
|
||||
! Ensure we didn't just end the loop by iteration
|
||||
|
|
@ -2278,13 +2272,13 @@ contains
|
|||
else
|
||||
lat => lattices(c % fill) % obj
|
||||
temp_offset = lat % offset(map, 1, 1, 1)
|
||||
end if
|
||||
end if
|
||||
|
||||
! If the final offset is in the range of offset - temp_offset+offset
|
||||
! then the goal is in this cell
|
||||
if (final < temp_offset + offset) then
|
||||
this_cell = .true.
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
|
||||
|
|
@ -2341,7 +2335,7 @@ contains
|
|||
! Loop over lattice coordinates
|
||||
do k = 1, n_x
|
||||
do l = 1, n_y
|
||||
do m = 1, n_z
|
||||
do m = 1, n_z
|
||||
|
||||
if (final >= lat % offset(map, k, l, m) + offset) then
|
||||
if (k == n_x .and. l == n_y .and. m == n_z) then
|
||||
|
|
@ -2364,14 +2358,14 @@ contains
|
|||
! Target is at this lattice position
|
||||
lat_offset = lat % offset(map, old_k, old_l, old_m)
|
||||
offset = offset + lat_offset
|
||||
next_univ => universes(lat % universes(old_k, old_l, old_m))
|
||||
next_univ => universes(lat % universes(old_k, old_l, old_m))
|
||||
path = trim(path) // "(" // trim(to_str(old_k)) // &
|
||||
"," // trim(to_str(old_l)) // "," // &
|
||||
trim(to_str(old_m)) // ")"
|
||||
call find_offset(map, goal, next_univ, final, offset, path)
|
||||
return
|
||||
end if
|
||||
|
||||
|
||||
end do
|
||||
end do
|
||||
end do
|
||||
|
|
@ -2404,10 +2398,24 @@ contains
|
|||
end if
|
||||
|
||||
if (final >= lat % offset(map, k, l, m) + offset) then
|
||||
old_m = m
|
||||
old_l = l
|
||||
old_k = k
|
||||
cycle
|
||||
if (k == lat % n_rings .and. l == n_y .and. m == n_z) then
|
||||
! This is last lattice cell, so target must be here
|
||||
lat_offset = lat % offset(map, k, l, m)
|
||||
offset = offset + lat_offset
|
||||
next_univ => universes(lat % universes(k, l, m))
|
||||
path = trim(path) // "(" // &
|
||||
trim(to_str(k - lat % n_rings)) // "," // &
|
||||
trim(to_str(l - lat % n_rings)) // "," // &
|
||||
trim(to_str(m)) // ")"
|
||||
call find_offset(map, goal, next_univ, final, offset, &
|
||||
path)
|
||||
return
|
||||
else
|
||||
old_m = m
|
||||
old_l = l
|
||||
old_k = k
|
||||
cycle
|
||||
end if
|
||||
else
|
||||
! Target is at this lattice position
|
||||
lat_offset = lat % offset(map, old_k, old_l, old_m)
|
||||
|
|
@ -2429,7 +2437,7 @@ contains
|
|||
|
||||
end if
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
end subroutine find_offset
|
||||
|
||||
end module output
|
||||
|
|
|
|||
|
|
@ -7,9 +7,10 @@ module output_interface
|
|||
|
||||
#ifdef HDF5
|
||||
use hdf5_interface
|
||||
#endif
|
||||
#else
|
||||
#ifdef MPI
|
||||
use mpiio_interface
|
||||
#endif
|
||||
#endif
|
||||
|
||||
implicit none
|
||||
|
|
@ -22,8 +23,13 @@ module output_interface
|
|||
integer(HID_T) :: hdf5_fh
|
||||
integer(HID_T) :: hdf5_grp
|
||||
#else
|
||||
integer :: unit_fh
|
||||
# endif
|
||||
integer :: unit_fh
|
||||
#ifdef MPIF08
|
||||
type(MPI_File) :: mpi_fh
|
||||
#else
|
||||
integer :: mpi_fh
|
||||
#endif
|
||||
#endif
|
||||
logical :: serial ! Serial I/O when using MPI/PHDF5
|
||||
contains
|
||||
generic, public :: write_data => write_double, &
|
||||
|
|
@ -122,7 +128,7 @@ contains
|
|||
open(NEWUNIT=self % unit_fh, FILE=filename, ACTION="write", &
|
||||
STATUS='replace', ACCESS='stream')
|
||||
else
|
||||
call mpi_create_file(filename, self % unit_fh)
|
||||
call mpi_create_file(filename, self % mpi_fh)
|
||||
end if
|
||||
#else
|
||||
open(NEWUNIT=self % unit_fh, FILE=filename, ACTION="write", &
|
||||
|
|
@ -170,7 +176,7 @@ contains
|
|||
STATUS='old', ACCESS='stream')
|
||||
end if
|
||||
else
|
||||
call mpi_open_file(filename, self % unit_fh, mode)
|
||||
call mpi_open_file(filename, self % mpi_fh, mode)
|
||||
end if
|
||||
#else
|
||||
! Check for read/write mode to open, default is read only
|
||||
|
|
@ -203,7 +209,7 @@ contains
|
|||
if (self % serial) then
|
||||
close(UNIT=self % unit_fh)
|
||||
else
|
||||
call mpi_close_file(self % unit_fh)
|
||||
call mpi_close_file(self % mpi_fh)
|
||||
end if
|
||||
#else
|
||||
close(UNIT=self % unit_fh)
|
||||
|
|
@ -293,7 +299,7 @@ contains
|
|||
if (self % serial) then
|
||||
write(self % unit_fh) buffer
|
||||
else
|
||||
call mpi_write_double(self % unit_fh, buffer, collect_)
|
||||
call mpi_write_double(self % mpi_fh, buffer, collect_)
|
||||
end if
|
||||
#else
|
||||
write(self % unit_fh) buffer
|
||||
|
|
@ -354,7 +360,7 @@ contains
|
|||
if (self % serial) then
|
||||
read(self % unit_fh) buffer
|
||||
else
|
||||
call mpi_read_double(self % unit_fh, buffer, collect_)
|
||||
call mpi_read_double(self % mpi_fh, buffer, collect_)
|
||||
end if
|
||||
#else
|
||||
read(self % unit_fh) buffer
|
||||
|
|
@ -417,7 +423,7 @@ contains
|
|||
if (self % serial) then
|
||||
write(self % unit_fh) buffer(1:length)
|
||||
else
|
||||
call mpi_write_double_1Darray(self % unit_fh, buffer, length, collect_)
|
||||
call mpi_write_double_1Darray(self % mpi_fh, buffer, length, collect_)
|
||||
end if
|
||||
#else
|
||||
write(self % unit_fh) buffer(1:length)
|
||||
|
|
@ -480,7 +486,7 @@ contains
|
|||
if (self % serial) then
|
||||
read(self % unit_fh) buffer(1:length)
|
||||
else
|
||||
call mpi_read_double_1Darray(self % unit_fh, buffer, length, collect_)
|
||||
call mpi_read_double_1Darray(self % mpi_fh, buffer, length, collect_)
|
||||
end if
|
||||
#else
|
||||
read(self % unit_fh) buffer(1:length)
|
||||
|
|
@ -543,7 +549,7 @@ contains
|
|||
if (self % serial) then
|
||||
write(self % unit_fh) buffer(1:length(1),1:length(2))
|
||||
else
|
||||
call mpi_write_double_2Darray(self % unit_fh, buffer, length, collect_)
|
||||
call mpi_write_double_2Darray(self % mpi_fh, buffer, length, collect_)
|
||||
end if
|
||||
#else
|
||||
write(self % unit_fh) buffer(1:length(1),1:length(2))
|
||||
|
|
@ -606,7 +612,7 @@ contains
|
|||
if (self % serial) then
|
||||
read(self % unit_fh) buffer(1:length(1),1:length(2))
|
||||
else
|
||||
call mpi_read_double_2Darray(self % unit_fh, buffer, length, collect_)
|
||||
call mpi_read_double_2Darray(self % mpi_fh, buffer, length, collect_)
|
||||
end if
|
||||
#else
|
||||
read(self % unit_fh) buffer(1:length(1),1:length(2))
|
||||
|
|
@ -669,7 +675,7 @@ contains
|
|||
if (self % serial) then
|
||||
write(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3))
|
||||
else
|
||||
call mpi_write_double_3Darray(self % unit_fh, buffer, length, collect_)
|
||||
call mpi_write_double_3Darray(self % mpi_fh, buffer, length, collect_)
|
||||
end if
|
||||
#else
|
||||
write(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3))
|
||||
|
|
@ -732,7 +738,7 @@ contains
|
|||
if (self % serial) then
|
||||
read(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3))
|
||||
else
|
||||
call mpi_read_double_3Darray(self % unit_fh, buffer, length, collect_)
|
||||
call mpi_read_double_3Darray(self % mpi_fh, buffer, length, collect_)
|
||||
end if
|
||||
#else
|
||||
read(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3))
|
||||
|
|
@ -798,7 +804,7 @@ contains
|
|||
write(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3), &
|
||||
1:length(4))
|
||||
else
|
||||
call mpi_write_double_4Darray(self % unit_fh, buffer, length, collect_)
|
||||
call mpi_write_double_4Darray(self % mpi_fh, buffer, length, collect_)
|
||||
end if
|
||||
#else
|
||||
write(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3), &
|
||||
|
|
@ -864,7 +870,7 @@ contains
|
|||
read(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3), &
|
||||
1:length(4))
|
||||
else
|
||||
call mpi_read_double_4Darray(self % unit_fh, buffer, length, collect_)
|
||||
call mpi_read_double_4Darray(self % mpi_fh, buffer, length, collect_)
|
||||
end if
|
||||
#else
|
||||
read(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3), &
|
||||
|
|
@ -926,7 +932,7 @@ contains
|
|||
if (self % serial) then
|
||||
write(self % unit_fh) buffer
|
||||
else
|
||||
call mpi_write_integer(self % unit_fh, buffer, collect_)
|
||||
call mpi_write_integer(self % mpi_fh, buffer, collect_)
|
||||
end if
|
||||
#else
|
||||
write(self % unit_fh) buffer
|
||||
|
|
@ -987,7 +993,7 @@ contains
|
|||
if (self % serial) then
|
||||
read(self % unit_fh) buffer
|
||||
else
|
||||
call mpi_read_integer(self % unit_fh, buffer, collect_)
|
||||
call mpi_read_integer(self % mpi_fh, buffer, collect_)
|
||||
end if
|
||||
#else
|
||||
read(self % unit_fh) buffer
|
||||
|
|
@ -1050,7 +1056,7 @@ contains
|
|||
if (self % serial) then
|
||||
write(self % unit_fh) buffer(1:length)
|
||||
else
|
||||
call mpi_write_integer_1Darray(self % unit_fh, buffer, length, collect_)
|
||||
call mpi_write_integer_1Darray(self % mpi_fh, buffer, length, collect_)
|
||||
end if
|
||||
#else
|
||||
write(self % unit_fh) buffer(1:length)
|
||||
|
|
@ -1114,7 +1120,7 @@ contains
|
|||
if (self % serial) then
|
||||
read(self % unit_fh) buffer(1:length)
|
||||
else
|
||||
call mpi_read_integer_1Darray(self % unit_fh, buffer, length, collect_)
|
||||
call mpi_read_integer_1Darray(self % mpi_fh, buffer, length, collect_)
|
||||
end if
|
||||
#else
|
||||
read(self % unit_fh) buffer(1:length)
|
||||
|
|
@ -1177,7 +1183,7 @@ contains
|
|||
if (self % serial) then
|
||||
write(self % unit_fh) buffer(1:length(1),1:length(2))
|
||||
else
|
||||
call mpi_write_integer_2Darray(self % unit_fh, buffer, length, collect_)
|
||||
call mpi_write_integer_2Darray(self % mpi_fh, buffer, length, collect_)
|
||||
end if
|
||||
#else
|
||||
write(self % unit_fh) buffer(1:length(1),1:length(2))
|
||||
|
|
@ -1240,7 +1246,7 @@ contains
|
|||
if (self % serial) then
|
||||
read(self % unit_fh) buffer(1:length(1),1:length(2))
|
||||
else
|
||||
call mpi_read_integer_2Darray(self % unit_fh, buffer, length, collect_)
|
||||
call mpi_read_integer_2Darray(self % mpi_fh, buffer, length, collect_)
|
||||
end if
|
||||
#else
|
||||
read(self % unit_fh) buffer(1:length(1),1:length(2))
|
||||
|
|
@ -1303,7 +1309,7 @@ contains
|
|||
if (self % serial) then
|
||||
write(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3))
|
||||
else
|
||||
call mpi_write_integer_3Darray(self % unit_fh, buffer, length, collect_)
|
||||
call mpi_write_integer_3Darray(self % mpi_fh, buffer, length, collect_)
|
||||
end if
|
||||
#else
|
||||
write(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3))
|
||||
|
|
@ -1366,7 +1372,7 @@ contains
|
|||
if (self % serial) then
|
||||
read(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3))
|
||||
else
|
||||
call mpi_read_integer_3Darray(self % unit_fh, buffer, length, collect_)
|
||||
call mpi_read_integer_3Darray(self % mpi_fh, buffer, length, collect_)
|
||||
end if
|
||||
#else
|
||||
read(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3))
|
||||
|
|
@ -1431,7 +1437,7 @@ contains
|
|||
write(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3), &
|
||||
1:length(4))
|
||||
else
|
||||
call mpi_write_integer_4Darray(self % unit_fh, buffer, length, collect_)
|
||||
call mpi_write_integer_4Darray(self % mpi_fh, buffer, length, collect_)
|
||||
end if
|
||||
#else
|
||||
write(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3), &
|
||||
|
|
@ -1497,7 +1503,7 @@ contains
|
|||
read(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3), &
|
||||
1:length(4))
|
||||
else
|
||||
call mpi_read_integer_4Darray(self % unit_fh, buffer, length, collect_)
|
||||
call mpi_read_integer_4Darray(self % mpi_fh, buffer, length, collect_)
|
||||
end if
|
||||
#else
|
||||
read(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3), &
|
||||
|
|
@ -1560,7 +1566,7 @@ contains
|
|||
if (self % serial) then
|
||||
write(self % unit_fh) buffer
|
||||
else
|
||||
call mpi_write_long(self % unit_fh, buffer, collect_)
|
||||
call mpi_write_long(self % mpi_fh, buffer, collect_)
|
||||
end if
|
||||
#else
|
||||
write(self % unit_fh) buffer
|
||||
|
|
@ -1622,7 +1628,7 @@ contains
|
|||
if (self % serial) then
|
||||
read(self % unit_fh) buffer
|
||||
else
|
||||
call mpi_read_long(self % unit_fh, buffer, collect_)
|
||||
call mpi_read_long(self % mpi_fh, buffer, collect_)
|
||||
end if
|
||||
#else
|
||||
read(self % unit_fh) buffer
|
||||
|
|
@ -1688,7 +1694,7 @@ contains
|
|||
if (self % serial) then
|
||||
write(self % unit_fh) buffer
|
||||
else
|
||||
call mpi_write_string(self % unit_fh, buffer, n, collect_)
|
||||
call mpi_write_string(self % mpi_fh, buffer, n, collect_)
|
||||
end if
|
||||
#else
|
||||
write(self % unit_fh) buffer
|
||||
|
|
@ -1754,7 +1760,7 @@ contains
|
|||
if (self % serial) then
|
||||
read(self % unit_fh) buffer
|
||||
else
|
||||
call mpi_read_string(self % unit_fh, buffer, n, collect_)
|
||||
call mpi_read_string(self % mpi_fh, buffer, n, collect_)
|
||||
end if
|
||||
#else
|
||||
read(self % unit_fh) buffer
|
||||
|
|
@ -1914,7 +1920,7 @@ contains
|
|||
# elif MPI
|
||||
|
||||
! Write out tally buffer
|
||||
call MPI_FILE_READ(self % unit_fh, buffer, n1*n2, MPI_TALLYRESULT, &
|
||||
call MPI_FILE_READ(self % mpi_fh, buffer, n1*n2, MPI_TALLYRESULT, &
|
||||
MPI_STATUS_IGNORE, mpiio_err)
|
||||
|
||||
#else
|
||||
|
|
@ -1943,7 +1949,11 @@ contains
|
|||
# ifndef HDF5
|
||||
integer(MPI_OFFSET_KIND) :: offset ! offset of data
|
||||
integer :: size_bank ! size of bank to write
|
||||
#ifdef MPIF08
|
||||
type(MPI_Datatype) :: datatype
|
||||
#else
|
||||
integer :: datatype
|
||||
#endif
|
||||
# endif
|
||||
# ifdef HDF5
|
||||
integer(8) :: offset(1) ! source data offset
|
||||
|
|
@ -2023,7 +2033,7 @@ contains
|
|||
#elif MPI
|
||||
|
||||
! Get current offset for master
|
||||
if (master) call MPI_FILE_GET_POSITION(self % unit_fh, offset, mpiio_err)
|
||||
if (master) call MPI_FILE_GET_POSITION(self % mpi_fh, offset, mpiio_err)
|
||||
|
||||
! Determine offset on master process and broadcast to all processors
|
||||
call MPI_TYPE_MATCH_SIZE(MPI_TYPECLASS_INTEGER, MPI_OFFSET_KIND, &
|
||||
|
|
@ -2035,7 +2045,7 @@ contains
|
|||
offset = offset + size_bank*work_index(rank)
|
||||
|
||||
! Write all source sites
|
||||
call MPI_FILE_WRITE_AT(self % unit_fh, offset, source_bank(1), int(work), &
|
||||
call MPI_FILE_WRITE_AT(self % mpi_fh, offset, source_bank(1), int(work), &
|
||||
MPI_BANK, MPI_STATUS_IGNORE, mpiio_err)
|
||||
|
||||
#else
|
||||
|
|
@ -2124,11 +2134,11 @@ contains
|
|||
|
||||
! Go to the end of the file to set file pointer
|
||||
offset = 0
|
||||
call MPI_FILE_SEEK(self % unit_fh, offset, MPI_SEEK_END, &
|
||||
call MPI_FILE_SEEK(self % mpi_fh, offset, MPI_SEEK_END, &
|
||||
mpiio_err)
|
||||
|
||||
! Get current offset (will be at EOF)
|
||||
call MPI_FILE_GET_POSITION(self % unit_fh, offset, mpiio_err)
|
||||
call MPI_FILE_GET_POSITION(self % mpi_fh, offset, mpiio_err)
|
||||
|
||||
! Get the size of the source bank on all procs
|
||||
call MPI_TYPE_SIZE(MPI_BANK, size_bank, mpi_err)
|
||||
|
|
@ -2140,7 +2150,7 @@ contains
|
|||
offset = offset + size_bank*work_index(rank)
|
||||
|
||||
! Write all source sites
|
||||
call MPI_FILE_READ_AT(self % unit_fh, offset, source_bank(1), int(work), &
|
||||
call MPI_FILE_READ_AT(self % mpi_fh, offset, source_bank(1), int(work), &
|
||||
MPI_BANK, MPI_STATUS_IGNORE, mpiio_err)
|
||||
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -26,9 +26,8 @@ module particle_header
|
|||
|
||||
! Is this level rotated?
|
||||
logical :: rotated = .false.
|
||||
|
||||
! Pointer to next (more local) set of coordinates
|
||||
type(LocalCoord), pointer :: next => null()
|
||||
contains
|
||||
procedure :: reset => reset_coord
|
||||
end type LocalCoord
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -42,8 +41,8 @@ module particle_header
|
|||
integer :: type ! Particle type (n, p, e, etc)
|
||||
|
||||
! Particle coordinates
|
||||
type(LocalCoord), pointer :: coord0 => null() ! coordinates on universe 0
|
||||
type(LocalCoord), pointer :: coord => null() ! coordinates on lowest universe
|
||||
integer :: n_coord ! number of current coordinates
|
||||
type(LocalCoord) :: coord(MAX_COORD) ! coordinates for all levels
|
||||
|
||||
! Other physical data
|
||||
real(8) :: wgt ! particle weight
|
||||
|
|
@ -87,26 +86,6 @@ module particle_header
|
|||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! DEALLOCATE_COORD removes all levels of coordinates below a given level. This
|
||||
! is used in distance_to_boundary when the particle moves from a lower universe
|
||||
! to a higher universe since the data for the lower one is not needed anymore.
|
||||
!===============================================================================
|
||||
|
||||
recursive subroutine deallocate_coord(coord)
|
||||
|
||||
type(LocalCoord), pointer :: coord
|
||||
|
||||
if (associated(coord)) then
|
||||
! recursively deallocate lower coordinates
|
||||
if (associated(coord % next)) call deallocate_coord(coord%next)
|
||||
|
||||
! deallocate this coord
|
||||
deallocate(coord)
|
||||
end if
|
||||
|
||||
end subroutine deallocate_coord
|
||||
|
||||
!===============================================================================
|
||||
! INITIALIZE_PARTICLE sets default attributes for a particle from the source
|
||||
! bank
|
||||
|
|
@ -137,9 +116,8 @@ contains
|
|||
this % fission = .false.
|
||||
|
||||
! Set up base level coordinates
|
||||
allocate(this % coord0)
|
||||
this % coord0 % universe = BASE_UNIVERSE
|
||||
this % coord => this % coord0
|
||||
this % coord(1) % universe = BASE_UNIVERSE
|
||||
this % n_coord = 1
|
||||
|
||||
end subroutine initialize_particle
|
||||
|
||||
|
|
@ -150,13 +128,30 @@ contains
|
|||
subroutine clear_particle(this)
|
||||
|
||||
class(Particle) :: this
|
||||
integer :: i
|
||||
|
||||
! remove any coordinate levels
|
||||
call deallocate_coord(this % coord0)
|
||||
|
||||
! Make sure coord pointer is nullified
|
||||
nullify(this % coord)
|
||||
do i = 1, MAX_COORD
|
||||
call this % coord(i) % reset()
|
||||
end do
|
||||
|
||||
end subroutine clear_particle
|
||||
|
||||
!===============================================================================
|
||||
! RESET_COORD
|
||||
!===============================================================================
|
||||
|
||||
elemental subroutine reset_coord(this)
|
||||
class(LocalCoord), intent(inout) :: this
|
||||
|
||||
this % cell = NONE
|
||||
this % universe = NONE
|
||||
this % lattice = NONE
|
||||
this % lattice_x = NONE
|
||||
this % lattice_y = NONE
|
||||
this % lattice_z = NONE
|
||||
this % rotated = .false.
|
||||
|
||||
end subroutine reset_coord
|
||||
|
||||
end module particle_header
|
||||
|
|
|
|||
|
|
@ -89,13 +89,13 @@ contains
|
|||
call pr % read_data(p % id, 'id')
|
||||
call pr % read_data(p % wgt, 'weight')
|
||||
call pr % read_data(p % E, 'energy')
|
||||
call pr % read_data(p % coord % xyz, 'xyz', length=3)
|
||||
call pr % read_data(p % coord % uvw, 'uvw', length=3)
|
||||
call pr % read_data(p % coord(1) % xyz, 'xyz', length=3)
|
||||
call pr % read_data(p % coord(1) % uvw, 'uvw', length=3)
|
||||
|
||||
! Set particle last attributes
|
||||
p % last_wgt = p % wgt
|
||||
p % last_xyz = p % coord % xyz
|
||||
p % last_uvw = p % coord % uvw
|
||||
p % last_xyz = p % coord(1) % xyz
|
||||
p % last_uvw = p % coord(1) % uvw
|
||||
p % last_E = p % E
|
||||
|
||||
! Close hdf5 file
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ contains
|
|||
filename = trim(filename) // '.binary'
|
||||
#endif
|
||||
|
||||
!$omp critical
|
||||
!$omp critical (WriteParticleRestart)
|
||||
! Create file
|
||||
call pr % file_create(filename)
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ contains
|
|||
|
||||
! Close file
|
||||
call pr % file_close()
|
||||
!$omp end critical
|
||||
!$omp end critical (WriteParticleRestart)
|
||||
|
||||
end subroutine write_particle_restart
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ contains
|
|||
! Store pre-collision particle properties
|
||||
p % last_wgt = p % wgt
|
||||
p % last_E = p % E
|
||||
p % last_uvw = p % coord0 % uvw
|
||||
p % last_uvw = p % coord(1) % uvw
|
||||
|
||||
! Add to collision counter for particle
|
||||
p % n_collision = p % n_collision + 1
|
||||
|
|
@ -143,7 +143,7 @@ contains
|
|||
case ('total')
|
||||
cutoff = prn() * material_xs % total
|
||||
case ('scatter')
|
||||
cutoff = prn() * material_xs % total - material_xs % absorption
|
||||
cutoff = prn() * (material_xs % total - material_xs % absorption)
|
||||
case ('fission')
|
||||
cutoff = prn() * material_xs % fission
|
||||
end select
|
||||
|
|
@ -254,19 +254,19 @@ contains
|
|||
p % last_wgt = p % wgt
|
||||
|
||||
! Score implicit absorption estimate of keff
|
||||
!$omp atomic
|
||||
global_tallies(K_ABSORPTION) % value = &
|
||||
global_tallies(K_ABSORPTION) % value + p % absorb_wgt * &
|
||||
micro_xs(i_nuclide) % nu_fission / micro_xs(i_nuclide) % absorption
|
||||
if (run_mode == MODE_EIGENVALUE) then
|
||||
global_tally_absorption = global_tally_absorption + p % absorb_wgt * &
|
||||
micro_xs(i_nuclide) % nu_fission / micro_xs(i_nuclide) % absorption
|
||||
end if
|
||||
else
|
||||
! See if disappearance reaction happens
|
||||
if (micro_xs(i_nuclide) % absorption > &
|
||||
prn() * micro_xs(i_nuclide) % total) then
|
||||
! Score absorption estimate of keff
|
||||
!$omp atomic
|
||||
global_tallies(K_ABSORPTION) % value = &
|
||||
global_tallies(K_ABSORPTION) % value + p % wgt * &
|
||||
micro_xs(i_nuclide) % nu_fission / micro_xs(i_nuclide) % absorption
|
||||
if (run_mode == MODE_EIGENVALUE) then
|
||||
global_tally_absorption = global_tally_absorption + p % wgt * &
|
||||
micro_xs(i_nuclide) % nu_fission / micro_xs(i_nuclide) % absorption
|
||||
end if
|
||||
|
||||
p % alive = .false.
|
||||
p % event = EVENT_ABSORB
|
||||
|
|
@ -335,7 +335,7 @@ contains
|
|||
|
||||
! S(a,b) scattering
|
||||
call sab_scatter(i_nuclide, micro_xs(i_nuclide) % index_sab, &
|
||||
p % E, p % coord0 % uvw, p % mu, &
|
||||
p % E, p % coord(1) % uvw, p % mu, &
|
||||
materials(p % material) % p0(i_nuc_mat))
|
||||
|
||||
else
|
||||
|
|
@ -344,7 +344,7 @@ contains
|
|||
|
||||
! Perform collision physics for elastic scattering
|
||||
call elastic_scatter(i_nuclide, rxn, &
|
||||
p % E, p % coord0 % uvw, p % mu, p % wgt, &
|
||||
p % E, p % coord(1) % uvw, p % mu, p % wgt, &
|
||||
materials(p % material) % p0(i_nuc_mat))
|
||||
end if
|
||||
|
||||
|
|
@ -387,7 +387,7 @@ contains
|
|||
end do
|
||||
|
||||
! Perform collision physics for inelastic scattering
|
||||
call inelastic_scatter(nuc, rxn, p % E, p % coord0 % uvw, &
|
||||
call inelastic_scatter(nuc, rxn, p % E, p % coord(1) % uvw, &
|
||||
p % mu, p % wgt, materials(p % material) % p0(i_nuc_mat))
|
||||
p % event_MT = rxn % MT
|
||||
|
||||
|
|
@ -620,13 +620,13 @@ contains
|
|||
if (r > ONE) then
|
||||
! equally likely N-4 middle bins
|
||||
j = int(r) + 2
|
||||
elseif (r > 0.6) then
|
||||
elseif (r > 0.6_8) then
|
||||
! second to last bin has relative probability of 0.4
|
||||
j = n_energy_out - 1
|
||||
elseif (r > 0.5) then
|
||||
elseif (r > HALF) then
|
||||
! last bin has relative probability of 0.1
|
||||
j = n_energy_out
|
||||
elseif (r > 0.1) then
|
||||
elseif (r > 0.1_8) then
|
||||
! second bin has relative probability of 0.4
|
||||
j = 2
|
||||
else
|
||||
|
|
@ -852,8 +852,8 @@ contains
|
|||
|
||||
case ('dbrc')
|
||||
E_red = sqrt((awr * E) / kT)
|
||||
E_low = (((E_red - 4.0_8)**2) * kT) / awr
|
||||
E_up = (((E_red + 4.0_8)**2) * kT) / awr
|
||||
E_low = (((E_red - FOUR)**2) * kT) / awr
|
||||
E_up = (((E_red + FOUR)**2) * kT) / awr
|
||||
|
||||
! find lower and upper energy bound indices
|
||||
! lower index
|
||||
|
|
@ -906,8 +906,8 @@ contains
|
|||
|
||||
case ('ares')
|
||||
E_red = sqrt((awr * E) / kT)
|
||||
E_low = (((E_red - 4.0_8)**2) * kT) / awr
|
||||
E_up = (((E_red + 4.0_8)**2) * kT) / awr
|
||||
E_low = (((E_red - FOUR)**2) * kT) / awr
|
||||
E_up = (((E_red + FOUR)**2) * kT) / awr
|
||||
|
||||
! find lower and upper energy bound indices
|
||||
! lower index
|
||||
|
|
@ -1108,7 +1108,7 @@ contains
|
|||
|
||||
if (ufs) then
|
||||
! Determine indices on ufs mesh for current location
|
||||
call get_mesh_indices(ufs_mesh, p % coord0 % xyz, ijk, in_mesh)
|
||||
call get_mesh_indices(ufs_mesh, p % coord(1) % xyz, ijk, in_mesh)
|
||||
if (.not. in_mesh) then
|
||||
call write_particle_restart(p)
|
||||
call fatal_error("Source site outside UFS mesh!")
|
||||
|
|
@ -1146,7 +1146,7 @@ contains
|
|||
p % fission = .true. ! Fission neutrons will be banked
|
||||
do i = int(n_bank,4) + 1, int(min(n_bank + nu, int(size(fission_bank),8)),4)
|
||||
! Bank source neutrons by copying particle data
|
||||
fission_bank(i) % xyz = p % coord0 % xyz
|
||||
fission_bank(i) % xyz = p % coord(1) % xyz
|
||||
|
||||
! Set weight of fission bank site
|
||||
fission_bank(i) % wgt = ONE/weight
|
||||
|
|
|
|||
136
src/plot.F90
136
src/plot.F90
|
|
@ -7,7 +7,7 @@ module plot
|
|||
use global
|
||||
use mesh, only: get_mesh_indices
|
||||
use output, only: write_message
|
||||
use particle_header, only: deallocate_coord, Particle, LocalCoord
|
||||
use particle_header, only: Particle, LocalCoord
|
||||
use plot_header
|
||||
use ppmlib, only: Image, init_image, allocate_image, &
|
||||
deallocate_image, set_pixel
|
||||
|
|
@ -46,7 +46,7 @@ contains
|
|||
end subroutine run_plot
|
||||
|
||||
!===============================================================================
|
||||
! POSITION_RGB computes the red/green/blue values for a given plot with the
|
||||
! POSITION_RGB computes the red/green/blue values for a given plot with the
|
||||
! current particle's position
|
||||
!===============================================================================
|
||||
|
||||
|
|
@ -56,28 +56,20 @@ contains
|
|||
type(ObjectPlot), pointer, intent(in) :: pl
|
||||
integer, intent(out) :: rgb(3)
|
||||
integer, intent(out) :: id
|
||||
|
||||
|
||||
integer :: j
|
||||
logical :: found_cell
|
||||
integer :: level
|
||||
type(Cell), pointer :: c => null()
|
||||
type(LocalCoord), pointer :: coord => null()
|
||||
|
||||
call deallocate_coord(p % coord0 % next)
|
||||
p % coord => p % coord0
|
||||
type(Cell), pointer :: c
|
||||
|
||||
p % n_coord = 1
|
||||
|
||||
call find_cell(p, found_cell)
|
||||
j = p % n_coord
|
||||
if (check_overlaps) call check_cell_overlap(p)
|
||||
|
||||
! Loop through universes and stop on any specified level
|
||||
level = 0
|
||||
coord => p % coord0
|
||||
do
|
||||
if (level == pl % level) exit
|
||||
if (.not. associated(coord % next)) exit
|
||||
coord => coord % next
|
||||
level = level + 1
|
||||
end do
|
||||
|
||||
! Set coordinate level if specified
|
||||
if (pl % level >= 0) j = pl % level + 1
|
||||
|
||||
if (.not. found_cell) then
|
||||
! If no cell, revert to default color
|
||||
rgb = pl % not_found % rgb
|
||||
|
|
@ -85,7 +77,7 @@ contains
|
|||
else
|
||||
if (pl % color_by == PLOT_COLOR_MATS) then
|
||||
! Assign color based on material
|
||||
c => cells(coord % cell)
|
||||
c => cells(p % coord(j) % cell)
|
||||
if (c % material == MATERIAL_VOID) then
|
||||
! By default, color void cells white
|
||||
rgb = 255
|
||||
|
|
@ -100,14 +92,14 @@ contains
|
|||
end if
|
||||
else if (pl % color_by == PLOT_COLOR_CELLS) then
|
||||
! Assign color based on cell
|
||||
rgb = pl % colors(coord % cell) % rgb
|
||||
id = cells(coord % cell) % id
|
||||
rgb = pl % colors(p % coord(j) % cell) % rgb
|
||||
id = cells(p % coord(j) % cell) % id
|
||||
else
|
||||
rgb = 0
|
||||
id = -1
|
||||
end if
|
||||
end if
|
||||
|
||||
|
||||
end subroutine position_rgb
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -141,31 +133,31 @@ contains
|
|||
if (pl % basis == PLOT_BASIS_XY) then
|
||||
in_i = 1
|
||||
out_i = 2
|
||||
xyz(1) = pl % origin(1) - pl % width(1) / 2.0
|
||||
xyz(2) = pl % origin(2) + pl % width(2) / 2.0
|
||||
xyz(1) = pl % origin(1) - pl % width(1) / TWO
|
||||
xyz(2) = pl % origin(2) + pl % width(2) / TWO
|
||||
xyz(3) = pl % origin(3)
|
||||
else if (pl % basis == PLOT_BASIS_XZ) then
|
||||
in_i = 1
|
||||
out_i = 3
|
||||
xyz(1) = pl % origin(1) - pl % width(1) / 2.0
|
||||
xyz(1) = pl % origin(1) - pl % width(1) / TWO
|
||||
xyz(2) = pl % origin(2)
|
||||
xyz(3) = pl % origin(3) + pl % width(2) / 2.0
|
||||
xyz(3) = pl % origin(3) + pl % width(2) / TWO
|
||||
else if (pl % basis == PLOT_BASIS_YZ) then
|
||||
in_i = 2
|
||||
out_i = 3
|
||||
xyz(1) = pl % origin(1)
|
||||
xyz(2) = pl % origin(2) - pl % width(1) / 2.0
|
||||
xyz(3) = pl % origin(3) + pl % width(2) / 2.0
|
||||
xyz(2) = pl % origin(2) - pl % width(1) / TWO
|
||||
xyz(3) = pl % origin(3) + pl % width(2) / TWO
|
||||
end if
|
||||
|
||||
! allocate and initialize particle
|
||||
call p % initialize()
|
||||
p % coord % xyz = xyz
|
||||
p % coord % uvw = (/ 0.5, 0.5, 0.5 /)
|
||||
p % coord % universe = BASE_UNIVERSE
|
||||
p % coord(1) % xyz = xyz
|
||||
p % coord(1) % uvw = [ HALF, HALF, HALF ]
|
||||
p % coord(1) % universe = BASE_UNIVERSE
|
||||
|
||||
do y = 1, img % height
|
||||
call progress % set_value(dble(y)/dble(img % height)*100.)
|
||||
call progress % set_value(dble(y)/dble(img % height)*100)
|
||||
do x = 1, img % width
|
||||
|
||||
! get pixel color
|
||||
|
|
@ -175,12 +167,12 @@ contains
|
|||
call set_pixel(img, x-1, y-1, rgb(1), rgb(2), rgb(3))
|
||||
|
||||
! Advance pixel in first direction
|
||||
p % coord0 % xyz(in_i) = p % coord0 % xyz(in_i) + in_pixel
|
||||
p % coord(1) % xyz(in_i) = p % coord(1) % xyz(in_i) + in_pixel
|
||||
end do
|
||||
|
||||
! Advance pixel in second direction
|
||||
p % coord0 % xyz(in_i) = xyz(in_i)
|
||||
p % coord0 % xyz(out_i) = p % coord0 % xyz(out_i) - out_pixel
|
||||
p % coord(1) % xyz(in_i) = xyz(in_i)
|
||||
p % coord(1) % xyz(out_i) = p % coord(1) % xyz(out_i) - out_pixel
|
||||
end do
|
||||
|
||||
! Draw tally mesh boundaries on the image if requested
|
||||
|
|
@ -201,10 +193,10 @@ contains
|
|||
! DRAW_MESH_LINES draws mesh line boundaries on an image
|
||||
!===============================================================================
|
||||
subroutine draw_mesh_lines(pl, img)
|
||||
|
||||
|
||||
type(ObjectPlot), pointer, intent(in) :: pl
|
||||
type(Image), intent(inout) :: img
|
||||
|
||||
|
||||
logical :: in_mesh
|
||||
integer :: out_, in_ ! pixel location
|
||||
integer :: r, g, b ! RGB color for meshlines pixels
|
||||
|
|
@ -221,13 +213,13 @@ contains
|
|||
real(8) :: xyz_ll(3) ! lower left xyz
|
||||
real(8) :: xyz_ur(3) ! upper right xyz
|
||||
type(StructuredMesh), pointer :: m => null()
|
||||
|
||||
|
||||
m => pl % meshlines_mesh
|
||||
|
||||
|
||||
r = pl % meshlines_color % rgb(1)
|
||||
g = pl % meshlines_color % rgb(2)
|
||||
b = pl % meshlines_color % rgb(3)
|
||||
|
||||
|
||||
select case (pl % basis)
|
||||
case(PLOT_BASIS_XY)
|
||||
outer = 1
|
||||
|
|
@ -243,10 +235,10 @@ contains
|
|||
xyz_ll_plot = pl % origin
|
||||
xyz_ur_plot = pl % origin
|
||||
|
||||
xyz_ll_plot(outer) = pl % origin(1) - pl % width(1) / 2.0
|
||||
xyz_ll_plot(inner) = pl % origin(2) - pl % width(2) / 2.0
|
||||
xyz_ur_plot(outer) = pl % origin(1) + pl % width(1) / 2.0
|
||||
xyz_ur_plot(inner) = pl % origin(2) + pl % width(2) / 2.0
|
||||
xyz_ll_plot(outer) = pl % origin(1) - pl % width(1) / TWO
|
||||
xyz_ll_plot(inner) = pl % origin(2) - pl % width(2) / TWO
|
||||
xyz_ur_plot(outer) = pl % origin(1) + pl % width(1) / TWO
|
||||
xyz_ur_plot(inner) = pl % origin(2) + pl % width(2) / TWO
|
||||
|
||||
width = xyz_ur_plot - xyz_ll_plot
|
||||
|
||||
|
|
@ -259,24 +251,24 @@ contains
|
|||
! check if we're in the mesh for this ijk
|
||||
if (i > 0 .and. i <= m % dimension(outer) .and. &
|
||||
j > 0 .and. j <= m % dimension(inner)) then
|
||||
|
||||
|
||||
! get xyz's of lower left and upper right of this mesh cell
|
||||
xyz_ll(outer) = m % lower_left(outer) + m % width(outer) * (i - 1)
|
||||
xyz_ll(inner) = m % lower_left(inner) + m % width(inner) * (j - 1)
|
||||
xyz_ur(outer) = m % lower_left(outer) + m % width(outer) * i
|
||||
xyz_ur(inner) = m % lower_left(inner) + m % width(inner) * j
|
||||
|
||||
|
||||
! map the xyz ranges to pixel ranges
|
||||
|
||||
|
||||
frac = (xyz_ll(outer) - xyz_ll_plot(outer)) / width(outer)
|
||||
outrange(1) = int(frac * real(img % width, 8))
|
||||
frac = (xyz_ur(outer) - xyz_ll_plot(outer)) / width(outer)
|
||||
outrange(2) = int(frac * real(img % width, 8))
|
||||
|
||||
frac = (xyz_ur(inner) - xyz_ll_plot(inner)) / width(inner)
|
||||
inrange(1) = int((1. - frac) * real(img % height, 8))
|
||||
inrange(1) = int((ONE - frac) * real(img % height, 8))
|
||||
frac = (xyz_ll(inner) - xyz_ll_plot(inner)) / width(inner)
|
||||
inrange(2) = int((1. - frac) * real(img % height, 8))
|
||||
inrange(2) = int((ONE - frac) * real(img % height, 8))
|
||||
|
||||
! draw lines
|
||||
do out_ = outrange(1), outrange(2)
|
||||
|
|
@ -295,11 +287,11 @@ contains
|
|||
call set_pixel(img, outrange(2) - plus, in_, r, g, b)
|
||||
end do
|
||||
end do
|
||||
|
||||
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
|
||||
|
||||
end subroutine draw_mesh_lines
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -350,7 +342,7 @@ contains
|
|||
subroutine create_3d_dump(pl)
|
||||
|
||||
type(ObjectPlot), pointer :: pl
|
||||
|
||||
|
||||
integer :: x, y, z ! voxel location indices
|
||||
integer :: rgb(3) ! colors (red, green, blue) from 0-255
|
||||
integer :: id ! id of cell or material
|
||||
|
|
@ -361,15 +353,15 @@ contains
|
|||
|
||||
! compute voxel widths in each direction
|
||||
vox = pl % width/dble(pl % pixels)
|
||||
|
||||
|
||||
! initial particle position
|
||||
ll = pl % origin - pl % width / 2.0
|
||||
ll = pl % origin - pl % width / TWO
|
||||
|
||||
! allocate and initialize particle
|
||||
call p % initialize()
|
||||
p % coord0 % xyz = ll
|
||||
p % coord0 % uvw = (/ 0.5, 0.5, 0.5 /)
|
||||
p % coord0 % universe = BASE_UNIVERSE
|
||||
p % coord(1) % xyz = ll
|
||||
p % coord(1) % uvw = [ HALF, HALF, HALF ]
|
||||
p % coord(1) % universe = BASE_UNIVERSE
|
||||
|
||||
! Open binary plot file for writing
|
||||
open(UNIT=UNIT_PLOT, FILE=pl % path_plot, STATUS='replace', &
|
||||
|
|
@ -378,11 +370,11 @@ contains
|
|||
! write plot header info
|
||||
write(UNIT_PLOT) pl % pixels, vox, ll
|
||||
|
||||
! move to center of voxels
|
||||
ll = ll + vox / 2.0
|
||||
! move to center of voxels
|
||||
ll = ll + vox / TWO
|
||||
|
||||
do x = 1, pl % pixels(1)
|
||||
call progress % set_value(dble(x)/dble(pl % pixels(1))*100.)
|
||||
call progress % set_value(dble(x)/dble(pl % pixels(1))*100)
|
||||
do y = 1, pl % pixels(2)
|
||||
do z = 1, pl % pixels(3)
|
||||
|
||||
|
|
@ -393,21 +385,21 @@ contains
|
|||
write(UNIT_PLOT) id
|
||||
|
||||
! advance particle in z direction
|
||||
p % coord0 % xyz(3) = p % coord0 % xyz(3) + vox(3)
|
||||
|
||||
p % coord(1) % xyz(3) = p % coord(1) % xyz(3) + vox(3)
|
||||
|
||||
end do
|
||||
|
||||
|
||||
! advance particle in y direction
|
||||
p % coord0 % xyz(2) = p % coord0 % xyz(2) + vox(2)
|
||||
p % coord0 % xyz(3) = ll(3)
|
||||
|
||||
p % coord(1) % xyz(2) = p % coord(1) % xyz(2) + vox(2)
|
||||
p % coord(1) % xyz(3) = ll(3)
|
||||
|
||||
end do
|
||||
|
||||
|
||||
! advance particle in y direction
|
||||
p % coord0 % xyz(1) = p % coord0 % xyz(1) + vox(1)
|
||||
p % coord0 % xyz(2) = ll(2)
|
||||
p % coord0 % xyz(3) = ll(3)
|
||||
|
||||
p % coord(1) % xyz(1) = p % coord(1) % xyz(1) + vox(1)
|
||||
p % coord(1) % xyz(2) = ll(2)
|
||||
p % coord(1) % xyz(3) = ll(3)
|
||||
|
||||
end do
|
||||
|
||||
close(UNIT_PLOT)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ module source
|
|||
use string, only: to_str
|
||||
|
||||
#ifdef MPI
|
||||
use mpi
|
||||
use message_passing
|
||||
#endif
|
||||
|
||||
implicit none
|
||||
|
|
@ -132,8 +132,8 @@ contains
|
|||
site % xyz = p_min + r*(p_max - p_min)
|
||||
|
||||
! Fill p with needed data
|
||||
p % coord0 % xyz = site % xyz
|
||||
p % coord0 % uvw = [ ONE, ZERO, ZERO ]
|
||||
p % coord(1) % xyz = site % xyz
|
||||
p % coord(1) % uvw = [ ONE, ZERO, ZERO ]
|
||||
|
||||
! Now search to see if location exists in geometry
|
||||
call find_cell(p, found)
|
||||
|
|
@ -161,8 +161,8 @@ contains
|
|||
site % xyz = p_min + r*(p_max - p_min)
|
||||
|
||||
! Fill p with needed data
|
||||
p % coord0 % xyz = site % xyz
|
||||
p % coord0 % uvw = [ ONE, ZERO, ZERO ]
|
||||
p % coord(1) % xyz = site % xyz
|
||||
p % coord(1) % uvw = [ ONE, ZERO, ZERO ]
|
||||
|
||||
! Now search to see if location exists in geometry
|
||||
call find_cell(p, found)
|
||||
|
|
@ -306,8 +306,8 @@ contains
|
|||
! copy attributes from source bank site
|
||||
p % wgt = src % wgt
|
||||
p % last_wgt = src % wgt
|
||||
p % coord % xyz = src % xyz
|
||||
p % coord % uvw = src % uvw
|
||||
p % coord(1) % xyz = src % xyz
|
||||
p % coord(1) % uvw = src % uvw
|
||||
p % last_xyz = src % xyz
|
||||
p % last_uvw = src % uvw
|
||||
p % E = src % E
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ module state_point
|
|||
use dict_header, only: ElemKeyValueII, ElemKeyValueCI
|
||||
|
||||
#ifdef MPI
|
||||
use mpi
|
||||
use message_passing
|
||||
#endif
|
||||
|
||||
implicit none
|
||||
|
|
|
|||
108
src/tally.F90
108
src/tally.F90
|
|
@ -11,13 +11,13 @@ module tally
|
|||
mesh_intersects_2d, mesh_intersects_3d
|
||||
use mesh_header, only: StructuredMesh
|
||||
use output, only: header
|
||||
use particle_header, only: LocalCoord, Particle, deallocate_coord
|
||||
use particle_header, only: LocalCoord, Particle
|
||||
use search, only: binary_search
|
||||
use string, only: to_str
|
||||
use tally_header, only: TallyResult, TallyMapItem, TallyMapElement
|
||||
|
||||
#ifdef MPI
|
||||
use mpi
|
||||
use message_passing
|
||||
#endif
|
||||
|
||||
implicit none
|
||||
|
|
@ -140,7 +140,7 @@ contains
|
|||
end if
|
||||
|
||||
|
||||
case (SCORE_SCATTER_PN, SCORE_SCATTER_YN)
|
||||
case (SCORE_SCATTER_PN)
|
||||
! Only analog estimators are available.
|
||||
! Skip any event where the particle didn't scatter
|
||||
if (p % event /= EVENT_SCATTER) then
|
||||
|
|
@ -153,6 +153,19 @@ contains
|
|||
score = p % last_wgt
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
case (SCORE_NU_SCATTER, SCORE_NU_SCATTER_N)
|
||||
! Only analog estimators are available.
|
||||
! Skip any event where the particle didn't scatter
|
||||
|
|
@ -163,7 +176,7 @@ contains
|
|||
score = p % wgt
|
||||
|
||||
|
||||
case (SCORE_NU_SCATTER_PN, SCORE_NU_SCATTER_YN)
|
||||
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
|
||||
|
|
@ -176,6 +189,19 @@ contains
|
|||
score = p % wgt
|
||||
|
||||
|
||||
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 post-collision
|
||||
! weight as the estimate for the number of neutrons exiting a
|
||||
! reaction with neutrons in the exit channel
|
||||
score = p % wgt
|
||||
|
||||
|
||||
case (SCORE_TRANSPORT)
|
||||
! Only analog estimators are available.
|
||||
! Skip any event where the particle didn't scatter
|
||||
|
|
@ -444,13 +470,13 @@ contains
|
|||
num_nm = 2 * n + 1
|
||||
|
||||
! multiply score by the angular flux moments and store
|
||||
!$omp critical
|
||||
!$omp critical (score_general_scatt_yn)
|
||||
t % results(score_index: score_index + num_nm - 1, filter_index) &
|
||||
% value = t &
|
||||
% results(score_index: score_index + num_nm - 1, filter_index)&
|
||||
% value &
|
||||
+ score * calc_pn(n, p % mu) * calc_rn(n, p % last_uvw)
|
||||
!$omp end critical
|
||||
!$omp end critical (score_general_scatt_yn)
|
||||
end do
|
||||
i = i + (t % moment_order(i) + 1)**2 - 1
|
||||
|
||||
|
|
@ -461,7 +487,7 @@ contains
|
|||
if (t % estimator == ESTIMATOR_ANALOG) then
|
||||
uvw = p % last_uvw
|
||||
else if (t % estimator == ESTIMATOR_TRACKLENGTH) then
|
||||
uvw = p % coord0 % uvw
|
||||
uvw = p % coord(1) % uvw
|
||||
end if
|
||||
! Find the order for a collection of requested moments
|
||||
! and store the moment contribution of each
|
||||
|
|
@ -472,13 +498,13 @@ contains
|
|||
num_nm = 2 * n + 1
|
||||
|
||||
! multiply score by the angular flux moments and store
|
||||
!$omp critical
|
||||
!$omp critical (score_general_flux_tot_yn)
|
||||
t % results(score_index: score_index + num_nm - 1, filter_index) &
|
||||
% value = t &
|
||||
% results(score_index: score_index + num_nm - 1, filter_index)&
|
||||
% value &
|
||||
+ score * calc_rn(n, uvw)
|
||||
!$omp end critical
|
||||
!$omp end critical (score_general_flux_tot_yn)
|
||||
end do
|
||||
i = i + (t % moment_order(i) + 1)**2 - 1
|
||||
|
||||
|
|
@ -883,7 +909,6 @@ contains
|
|||
type(TallyObject), pointer :: t
|
||||
type(StructuredMesh), pointer :: m
|
||||
type(Material), pointer :: mat
|
||||
type(LocalCoord), pointer :: coord
|
||||
|
||||
t => tallies(i_tally)
|
||||
matching_bins(1:t%n_filters) = 1
|
||||
|
|
@ -892,8 +917,8 @@ contains
|
|||
! CHECK IF THIS TRACK INTERSECTS THE MESH
|
||||
|
||||
! Copy starting and ending location of particle
|
||||
xyz0 = p % coord0 % xyz - (d_track - TINY_BIT) * p % coord0 % uvw
|
||||
xyz1 = p % coord0 % xyz - TINY_BIT * p % coord0 % uvw
|
||||
xyz0 = p % coord(1) % xyz - (d_track - TINY_BIT) * p % coord(1) % uvw
|
||||
xyz1 = p % coord(1) % xyz - TINY_BIT * p % coord(1) % uvw
|
||||
|
||||
! Get index for mesh filter
|
||||
i_filter_mesh = t % find_filter(FILTER_MESH)
|
||||
|
|
@ -914,8 +939,8 @@ contains
|
|||
end if
|
||||
|
||||
! Reset starting and ending location
|
||||
xyz0 = p % coord0 % xyz - d_track * p % coord0 % uvw
|
||||
xyz1 = p % coord0 % xyz
|
||||
xyz0 = p % coord(1) % xyz - d_track * p % coord(1) % uvw
|
||||
xyz1 = p % coord(1) % xyz
|
||||
|
||||
! =========================================================================
|
||||
! CHECK FOR SCORING COMBINATION FOR FILTERS OTHER THAN MESH
|
||||
|
|
@ -927,7 +952,7 @@ contains
|
|||
! determine next universe bin
|
||||
! TODO: Account for multiple universes when performing this filter
|
||||
matching_bins(i) = get_next_bin(FILTER_UNIVERSE, &
|
||||
p % coord % universe, i_tally)
|
||||
p % coord(p % n_coord) % universe, i_tally)
|
||||
|
||||
case (FILTER_MATERIAL)
|
||||
matching_bins(i) = get_next_bin(FILTER_MATERIAL, &
|
||||
|
|
@ -935,15 +960,12 @@ contains
|
|||
|
||||
case (FILTER_CELL)
|
||||
! determine next cell bin
|
||||
coord => p % coord0
|
||||
do while(associated(coord))
|
||||
do j = 1, p % n_coord
|
||||
position(FILTER_CELL) = 0
|
||||
matching_bins(i) = get_next_bin(FILTER_CELL, &
|
||||
coord % cell, i_tally)
|
||||
p % coord(j) % cell, i_tally)
|
||||
if (matching_bins(i) /= NO_BIN_FOUND) exit
|
||||
coord => coord % next
|
||||
end do
|
||||
nullify(coord)
|
||||
|
||||
case (FILTER_CELLBORN)
|
||||
! determine next cellborn bin
|
||||
|
|
@ -983,7 +1005,7 @@ contains
|
|||
n_cross = sum(abs(ijk1(:m % n_dimension) - ijk0(:m % n_dimension))) + 1
|
||||
|
||||
! Copy particle's direction
|
||||
uvw = p % coord0 % uvw
|
||||
uvw = p % coord(1) % uvw
|
||||
|
||||
! Bounding coordinates
|
||||
do j = 1, m % n_dimension
|
||||
|
|
@ -1109,12 +1131,12 @@ contains
|
|||
logical, intent(out) :: found_bin
|
||||
|
||||
integer :: i ! loop index for filters
|
||||
integer :: j
|
||||
integer :: n ! number of bins for single filter
|
||||
integer :: offset ! offset for distribcell
|
||||
real(8) :: E ! particle energy
|
||||
type(TallyObject), pointer :: t
|
||||
type(StructuredMesh), pointer :: m
|
||||
type(LocalCoord), pointer :: coord
|
||||
|
||||
found_bin = .true.
|
||||
t => tallies(i_tally)
|
||||
|
|
@ -1128,13 +1150,13 @@ contains
|
|||
m => meshes(t % filters(i) % int_bins(1))
|
||||
|
||||
! Determine if we're in the mesh first
|
||||
call get_mesh_bin(m, p % coord0 % xyz, matching_bins(i))
|
||||
call get_mesh_bin(m, p % coord(1) % xyz, matching_bins(i))
|
||||
|
||||
case (FILTER_UNIVERSE)
|
||||
! determine next universe bin
|
||||
! TODO: Account for multiple universes when performing this filter
|
||||
matching_bins(i) = get_next_bin(FILTER_UNIVERSE, &
|
||||
p % coord % universe, i_tally)
|
||||
p % coord(p % n_coord) % universe, i_tally)
|
||||
|
||||
case (FILTER_MATERIAL)
|
||||
if (p % material /= MATERIAL_VOID) then
|
||||
|
|
@ -1144,37 +1166,39 @@ contains
|
|||
|
||||
case (FILTER_CELL)
|
||||
! determine next cell bin
|
||||
coord => p % coord0
|
||||
do while(associated(coord))
|
||||
do j = 1, p % n_coord
|
||||
position(FILTER_CELL) = 0
|
||||
matching_bins(i) = get_next_bin(FILTER_CELL, &
|
||||
coord % cell, i_tally)
|
||||
p % coord(j) % cell, i_tally)
|
||||
if (matching_bins(i) /= NO_BIN_FOUND) exit
|
||||
coord => coord % next
|
||||
end do
|
||||
nullify(coord)
|
||||
|
||||
case (FILTER_DISTRIBCELL)
|
||||
! determine next distribcell bin
|
||||
matching_bins(i) = NO_BIN_FOUND
|
||||
coord => p % coord0
|
||||
offset = 0
|
||||
do while(associated(coord))
|
||||
if (cells(coord % cell) % type == CELL_FILL) then
|
||||
offset = offset + cells(coord % cell) % &
|
||||
do j = 1, p % n_coord
|
||||
if (cells(p % coord(j) % cell) % type == CELL_FILL) then
|
||||
offset = offset + cells(p % coord(j) % cell) % &
|
||||
offset(t % filters(i) % offset)
|
||||
elseif(cells(coord % cell) % type == CELL_LATTICE) then
|
||||
offset = offset + lattices(coord % next % lattice) % obj % &
|
||||
offset(t % filters(i) % offset, coord % next % lattice_x, &
|
||||
coord % next % lattice_y, coord % next % lattice_z)
|
||||
elseif(cells(p % coord(j) % cell) % type == CELL_LATTICE) then
|
||||
if (lattices(p % coord(j + 1) % lattice) % obj &
|
||||
% are_valid_indices([&
|
||||
p % coord(j + 1) % lattice_x, &
|
||||
p % coord(j + 1) % lattice_y, &
|
||||
p % coord(j + 1) % lattice_z])) then
|
||||
offset = offset + lattices(p % coord(j + 1) % lattice) % obj % &
|
||||
offset(t % filters(i) % offset, &
|
||||
p % coord(j + 1) % lattice_x, &
|
||||
p % coord(j + 1) % lattice_y, &
|
||||
p % coord(j + 1) % lattice_z)
|
||||
end if
|
||||
end if
|
||||
if (t % filters(i) % int_bins(1) == coord % cell) then
|
||||
if (t % filters(i) % int_bins(1) == p % coord(j) % cell) then
|
||||
matching_bins(i) = offset + 1
|
||||
exit
|
||||
end if
|
||||
coord => coord % next
|
||||
end do
|
||||
nullify(coord)
|
||||
|
||||
case (FILTER_CELLBORN)
|
||||
! determine next cellborn bin
|
||||
|
|
@ -1270,7 +1294,7 @@ contains
|
|||
TALLY_LOOP: do i = 1, active_current_tallies % size()
|
||||
! Copy starting and ending location of particle
|
||||
xyz0 = p % last_xyz
|
||||
xyz1 = p % coord0 % xyz
|
||||
xyz1 = p % coord(1) % xyz
|
||||
|
||||
! Get pointer to tally
|
||||
i_tally = active_current_tallies % get_item(i)
|
||||
|
|
@ -1302,7 +1326,7 @@ contains
|
|||
end if
|
||||
|
||||
! Copy particle's direction
|
||||
uvw = p % coord0 % uvw
|
||||
uvw = p % coord(1) % uvw
|
||||
|
||||
! determine incoming energy bin
|
||||
j = t % find_filter(FILTER_ENERGYIN)
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ contains
|
|||
end if
|
||||
|
||||
! Write current coordinates into the newest column.
|
||||
coords(:, n_tracks) = p % coord0 % xyz
|
||||
coords(:, n_tracks) = p % coord(1) % xyz
|
||||
end subroutine write_particle_track
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -69,12 +69,12 @@ contains
|
|||
// '_' // trim(to_str(current_gen)) // '_' // trim(to_str(p % id)) &
|
||||
// '.binary'
|
||||
#endif
|
||||
!$omp critical
|
||||
!$omp critical (FinalizeParticleTrack)
|
||||
call binout % file_create(fname)
|
||||
length = [3, n_tracks]
|
||||
call binout % write_data(coords, 'coordinates', length=length)
|
||||
call binout % file_close()
|
||||
!$omp end critical
|
||||
!$omp end critical (FinalizeParticleTrack)
|
||||
deallocate(coords)
|
||||
end subroutine finalize_particle_track
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
module tracking
|
||||
|
||||
use constants, only: MODE_EIGENVALUE
|
||||
use cross_section, only: calculate_xs
|
||||
use error, only: fatal_error, warning
|
||||
use geometry, only: find_cell, distance_to_boundary, cross_surface, &
|
||||
|
|
@ -28,6 +29,8 @@ contains
|
|||
|
||||
type(Particle), intent(inout) :: p
|
||||
|
||||
integer :: j ! coordinate level
|
||||
integer :: next_level ! next coordinate level to check
|
||||
integer :: surface_crossed ! surface which particle is on
|
||||
integer :: lattice_translation(3) ! in-lattice translation vector
|
||||
integer :: last_cell ! most recent cell particle was in
|
||||
|
|
@ -36,7 +39,6 @@ contains
|
|||
real(8) :: d_collision ! sampled distance to collision
|
||||
real(8) :: distance ! distance particle travels
|
||||
logical :: found_cell ! found cell which particle is in?
|
||||
type(LocalCoord), pointer :: coord
|
||||
|
||||
! Display message if high verbosity or trace is on
|
||||
if (verbosity >= 9 .or. trace) then
|
||||
|
|
@ -45,7 +47,7 @@ contains
|
|||
|
||||
! If the cell hasn't been determined based on the particle's location,
|
||||
! initiate a search for the current cell
|
||||
if (p % coord % cell == NONE) then
|
||||
if (p % coord(p % n_coord) % cell == NONE) then
|
||||
call find_cell(p, found_cell)
|
||||
|
||||
! Particle couldn't be located
|
||||
|
|
@ -54,7 +56,7 @@ contains
|
|||
end if
|
||||
|
||||
! set birth cell attribute
|
||||
p % cell_born = p % coord % cell
|
||||
p % cell_born = p % coord(p % n_coord) % cell
|
||||
end if
|
||||
|
||||
! Initialize number of events to zero
|
||||
|
|
@ -87,7 +89,7 @@ contains
|
|||
|
||||
! Find the distance to the nearest boundary
|
||||
call distance_to_boundary(p, d_boundary, surface_crossed, &
|
||||
&lattice_translation)
|
||||
lattice_translation, next_level)
|
||||
|
||||
! Sample a distance to collision
|
||||
if (material_xs % total == ZERO) then
|
||||
|
|
@ -100,10 +102,8 @@ contains
|
|||
distance = min(d_boundary, d_collision)
|
||||
|
||||
! Advance particle
|
||||
coord => p % coord0
|
||||
do while (associated(coord))
|
||||
coord % xyz = coord % xyz + distance * coord % uvw
|
||||
coord => coord % next
|
||||
do j = 1, p % n_coord
|
||||
p % coord(j) % xyz = p % coord(j) % xyz + distance * p % coord(j) % uvw
|
||||
end do
|
||||
|
||||
! Score track-length tallies
|
||||
|
|
@ -111,17 +111,18 @@ contains
|
|||
call score_tracklength_tally(p, distance)
|
||||
|
||||
! Score track-length estimate of k-eff
|
||||
!$omp atomic
|
||||
global_tallies(K_TRACKLENGTH) % value = &
|
||||
global_tallies(K_TRACKLENGTH) % value + p % wgt * distance * &
|
||||
material_xs % nu_fission
|
||||
if (run_mode == MODE_EIGENVALUE) then
|
||||
global_tally_tracklength = global_tally_tracklength + p % wgt * &
|
||||
distance * material_xs % nu_fission
|
||||
end if
|
||||
|
||||
if (d_collision > d_boundary) then
|
||||
! ====================================================================
|
||||
! PARTICLE CROSSES SURFACE
|
||||
|
||||
last_cell = p % coord % cell
|
||||
p % coord % cell = NONE
|
||||
if (next_level > 0) p % n_coord = next_level
|
||||
last_cell = p % coord(p % n_coord) % cell
|
||||
p % coord(p % n_coord) % cell = NONE
|
||||
if (any(lattice_translation /= 0)) then
|
||||
! Particle crosses lattice boundary
|
||||
p % surface = NONE
|
||||
|
|
@ -138,10 +139,10 @@ contains
|
|||
! PARTICLE HAS COLLISION
|
||||
|
||||
! Score collision estimate of keff
|
||||
!$omp atomic
|
||||
global_tallies(K_COLLISION) % value = &
|
||||
global_tallies(K_COLLISION) % value + p % wgt * &
|
||||
material_xs % nu_fission / material_xs % total
|
||||
if (run_mode == MODE_EIGENVALUE) then
|
||||
global_tally_collision = global_tally_collision + p % wgt * &
|
||||
material_xs % nu_fission / material_xs % total
|
||||
end if
|
||||
|
||||
! score surface current tallies -- this has to be done before the collision
|
||||
! since the direction of the particle will change and we need to use the
|
||||
|
|
@ -168,7 +169,7 @@ contains
|
|||
p % fission = .false.
|
||||
|
||||
! Save coordinates for tallying purposes
|
||||
p % last_xyz = p % coord0 % xyz
|
||||
p % last_xyz = p % coord(1) % xyz
|
||||
|
||||
! Set last material to none since cross sections will need to be
|
||||
! re-evaluated
|
||||
|
|
@ -176,19 +177,15 @@ contains
|
|||
|
||||
! Set all uvws to base level -- right now, after a collision, only the
|
||||
! base level uvws are changed
|
||||
coord => p % coord0
|
||||
do while(associated(coord % next))
|
||||
if (coord % next % rotated) then
|
||||
do j = 1, p % n_coord - 1
|
||||
if (p % coord(j + 1) % rotated) then
|
||||
! If next level is rotated, apply rotation matrix
|
||||
coord % next % uvw = matmul(cells(coord % cell) % &
|
||||
rotation_matrix, coord % uvw)
|
||||
p % coord(j + 1) % uvw = matmul(cells(p % coord(j) % cell) % &
|
||||
rotation_matrix, p % coord(j) % uvw)
|
||||
else
|
||||
! Otherwise, copy this level's direction
|
||||
coord % next % uvw = coord % uvw
|
||||
p % coord(j + 1) % uvw = p % coord(j) % uvw
|
||||
end if
|
||||
|
||||
! Advance coordinate level
|
||||
coord => coord % next
|
||||
end do
|
||||
end if
|
||||
|
||||
|
|
|
|||
143
src/trigger.F90
143
src/trigger.F90
|
|
@ -1,9 +1,10 @@
|
|||
module trigger
|
||||
|
||||
#ifdef MPI
|
||||
use mpi
|
||||
use message_passing
|
||||
#endif
|
||||
|
||||
use constants
|
||||
use global
|
||||
use string, only: to_str
|
||||
use output, only: warning, write_message
|
||||
|
|
@ -30,7 +31,7 @@ contains
|
|||
character(len=52) :: name ! "eigenvalue" or tally score
|
||||
|
||||
integer :: n_pred_batches ! predicted # batches to satisfy all triggers
|
||||
|
||||
|
||||
! Checks if current_batch is one for which the triggers must be checked
|
||||
if (current_batch < n_batches .or. (.not. trigger_on)) return
|
||||
if (mod((current_batch - n_batches), n_batch_interval) /= 0 .and. &
|
||||
|
|
@ -39,24 +40,24 @@ contains
|
|||
! Check the trigger and output the result
|
||||
call check_tally_triggers(max_ratio, tally_id, name)
|
||||
|
||||
! When trigger threshold is reached, write information
|
||||
! When trigger threshold is reached, write information
|
||||
if (satisfy_triggers) then
|
||||
call write_message("Triggers satisfied for batch " // &
|
||||
trim(to_str(current_batch)))
|
||||
|
||||
|
||||
! When trigger is not reached write convergence info for user
|
||||
elseif (name == "eigenvalue") then
|
||||
call write_message("Triggers unsatisfied, max unc./thresh. is " // &
|
||||
trim(to_str(max_ratio)) // " for " // trim(name))
|
||||
else
|
||||
call write_message("Triggers unsatisfied, max unc./thresh. is " // &
|
||||
call write_message("Triggers unsatisfied, max unc./thresh. is " // &
|
||||
trim(to_str(max_ratio)) // " for " // trim(name) // &
|
||||
" in tally " // trim(to_str(tally_id)))
|
||||
end if
|
||||
end if
|
||||
|
||||
! If batch_interval is not set, estimate batches till triggers are satisfied
|
||||
if (pred_batches .and. .not. satisfy_triggers) then
|
||||
|
||||
|
||||
! Estimate the number of remaining batches to convergence
|
||||
! The prediction uses the fact that tally variances are proportional
|
||||
! to 1/N where N is the number of the batches/particles
|
||||
|
|
@ -65,9 +66,9 @@ contains
|
|||
n_pred_batches = n_batch_interval + n_batches
|
||||
|
||||
! Write the predicted number of batches for the user
|
||||
if (n_pred_batches > n_max_batches) then
|
||||
if (n_pred_batches > n_max_batches) then
|
||||
call warning("The estimated number of batches is " // &
|
||||
trim(to_str(n_pred_batches)) // &
|
||||
trim(to_str(n_pred_batches)) // &
|
||||
" -- greater than max batches. ")
|
||||
else
|
||||
call write_message("The estimated number of batches is " // &
|
||||
|
|
@ -98,8 +99,8 @@ contains
|
|||
integer :: n_order ! loop index for moment orders
|
||||
integer :: nm_order ! loop index for Ynm moment orders
|
||||
real(8) :: uncertainty ! trigger uncertainty
|
||||
real(8) :: std_dev = 0.0 ! trigger standard deviation
|
||||
real(8) :: rel_err = 0.0 ! trigger relative error
|
||||
real(8) :: std_dev = ZERO ! trigger standard deviation
|
||||
real(8) :: rel_err = ZERO ! trigger relative error
|
||||
real(8) :: ratio ! ratio of the uncertainty/trigger threshold
|
||||
type(TallyObject), pointer :: t ! tally pointer
|
||||
type(TriggerObject), pointer :: trigger ! tally trigger
|
||||
|
|
@ -115,8 +116,8 @@ contains
|
|||
! Check eigenvalue trigger
|
||||
if (run_mode == MODE_EIGENVALUE) then
|
||||
if (keff_trigger % trigger_type /= 0) then
|
||||
select case (keff_trigger % trigger_type)
|
||||
case(VARIANCE)
|
||||
select case (keff_trigger % trigger_type)
|
||||
case(VARIANCE)
|
||||
uncertainty = k_combined(2) ** 2
|
||||
case(STANDARD_DEVIATION)
|
||||
uncertainty = k_combined(2)
|
||||
|
|
@ -124,7 +125,7 @@ contains
|
|||
uncertainty = k_combined(2) / k_combined(1)
|
||||
end select
|
||||
|
||||
! If uncertainty is above threshold, store uncertainty ratio
|
||||
! If uncertainty is above threshold, store uncertainty ratio
|
||||
if (uncertainty > keff_trigger % threshold) then
|
||||
satisfy_triggers = .false.
|
||||
if (keff_trigger % trigger_type == VARIANCE) then
|
||||
|
|
@ -133,11 +134,11 @@ contains
|
|||
ratio = uncertainty / keff_trigger % threshold
|
||||
end if
|
||||
if (max_ratio < ratio) then
|
||||
max_ratio = ratio
|
||||
max_ratio = ratio
|
||||
name = "eigenvalue"
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
|
||||
! Compute uncertainties for all tallies, scores with triggers
|
||||
|
|
@ -153,10 +154,10 @@ contains
|
|||
trigger => t % triggers(s)
|
||||
|
||||
! Initialize trigger uncertainties to zero
|
||||
trigger % std_dev = 0.
|
||||
trigger % rel_err = 0.
|
||||
trigger % variance = 0.
|
||||
|
||||
trigger % std_dev = ZERO
|
||||
trigger % rel_err = ZERO
|
||||
trigger % variance = ZERO
|
||||
|
||||
! Surface current tally triggers require special treatment
|
||||
if (t % type == TALLY_SURFACE_CURRENT) then
|
||||
call compute_tally_current(t, trigger)
|
||||
|
|
@ -178,9 +179,9 @@ contains
|
|||
j = j - 1
|
||||
else
|
||||
if (j == t % n_filters) exit find_bin
|
||||
end if
|
||||
end if
|
||||
end do find_bin
|
||||
|
||||
|
||||
if (t % n_filters > 0) then
|
||||
filter_index = sum((max(matching_bins(1:t%n_filters),1) - 1) * &
|
||||
t % stride) + 1
|
||||
|
|
@ -193,13 +194,13 @@ contains
|
|||
|
||||
! Initialize score bin index
|
||||
NUCLIDE_LOOP: do n = 1, t % n_nuclide_bins
|
||||
|
||||
|
||||
select case(t % score_bins(trigger % score_index))
|
||||
|
||||
case (SCORE_SCATTER_PN, SCORE_NU_SCATTER_PN)
|
||||
|
||||
score_index = score_index - 1
|
||||
|
||||
|
||||
do n_order = 0, t % moment_order(trigger % score_index)
|
||||
score_index = score_index + 1
|
||||
|
||||
|
|
@ -207,17 +208,17 @@ contains
|
|||
score_index, filter_index, t)
|
||||
|
||||
if (trigger % variance < variance) then
|
||||
trigger % variance = std_dev ** 2
|
||||
trigger % variance = std_dev ** 2
|
||||
end if
|
||||
if (trigger % std_dev < std_dev) then
|
||||
if (trigger % std_dev < std_dev) then
|
||||
trigger % std_dev = std_dev
|
||||
end if
|
||||
if (trigger % rel_err < rel_err) then
|
||||
if (trigger % rel_err < rel_err) then
|
||||
trigger % rel_err = rel_err
|
||||
end if
|
||||
|
||||
end do
|
||||
|
||||
|
||||
case (SCORE_SCATTER_YN, SCORE_NU_SCATTER_YN, SCORE_FLUX_YN, &
|
||||
SCORE_TOTAL_YN)
|
||||
|
||||
|
|
@ -242,32 +243,32 @@ contains
|
|||
|
||||
end do
|
||||
end do
|
||||
|
||||
|
||||
case default
|
||||
call get_trigger_uncertainty(std_dev, rel_err, &
|
||||
score_index, filter_index, t)
|
||||
|
||||
if (trigger % variance < variance) then
|
||||
trigger % variance = std_dev ** 2
|
||||
trigger % variance = std_dev ** 2
|
||||
end if
|
||||
if (trigger % std_dev < std_dev) then
|
||||
if (trigger % std_dev < std_dev) then
|
||||
trigger % std_dev = std_dev
|
||||
end if
|
||||
if (trigger % rel_err < rel_err) then
|
||||
if (trigger % rel_err < rel_err) then
|
||||
trigger % rel_err = rel_err
|
||||
end if
|
||||
|
||||
end select
|
||||
|
||||
select case (t % triggers(s) % type)
|
||||
case(VARIANCE)
|
||||
|
||||
select case (t % triggers(s) % type)
|
||||
case(VARIANCE)
|
||||
uncertainty = trigger % variance
|
||||
case(STANDARD_DEVIATION)
|
||||
uncertainty = trigger % std_dev
|
||||
case default
|
||||
uncertainty = trigger % rel_err
|
||||
end select
|
||||
|
||||
|
||||
if (uncertainty > t % triggers(s) % threshold) then
|
||||
satisfy_triggers = .false.
|
||||
|
||||
|
|
@ -275,8 +276,8 @@ contains
|
|||
ratio = sqrt(uncertainty / t % triggers(s) % threshold)
|
||||
else
|
||||
ratio = uncertainty / t % triggers(s) % threshold
|
||||
end if
|
||||
|
||||
end if
|
||||
|
||||
if (max_ratio < ratio) then
|
||||
max_ratio = ratio
|
||||
name = t % triggers(s) % score_name
|
||||
|
|
@ -297,7 +298,7 @@ contains
|
|||
! COMPUTE_TALLY_CURRENT computes the current for a surface current tally with
|
||||
! precision trigger(s).
|
||||
!===============================================================================
|
||||
|
||||
|
||||
subroutine compute_tally_current(t, trigger)
|
||||
|
||||
integer :: i ! mesh index for x
|
||||
|
|
@ -310,8 +311,8 @@ contains
|
|||
integer :: n ! number of incoming energy bins
|
||||
integer :: filter_index ! index in results array for filters
|
||||
logical :: print_ebin ! should incoming energy bin be displayed?
|
||||
real(8) :: rel_err = 0.0 ! temporary relative error of result
|
||||
real(8) :: std_dev = 0.0 ! temporary standard deviration of result
|
||||
real(8) :: rel_err = ZERO ! temporary relative error of result
|
||||
real(8) :: std_dev = ZERO ! temporary standard deviration of result
|
||||
type(TallyObject), pointer :: t ! surface current tally
|
||||
type(TriggerObject) :: trigger ! surface current tally trigger
|
||||
type(StructuredMesh), pointer :: m ! surface current mesh
|
||||
|
|
@ -350,10 +351,10 @@ contains
|
|||
filter_index = &
|
||||
sum((matching_bins(1:t % n_filters) - 1) * t % stride) + 1
|
||||
call get_trigger_uncertainty(std_dev, rel_err, 1, filter_index, t)
|
||||
if (trigger % std_dev < std_dev) then
|
||||
if (trigger % std_dev < std_dev) then
|
||||
trigger % std_dev = std_dev
|
||||
end if
|
||||
if (trigger % rel_err < rel_err) then
|
||||
if (trigger % rel_err < rel_err) then
|
||||
trigger % rel_err = rel_err
|
||||
end if
|
||||
trigger % variance = std_dev**2
|
||||
|
|
@ -362,10 +363,10 @@ contains
|
|||
filter_index = &
|
||||
sum((matching_bins(1:t % n_filters) - 1) * t % stride) + 1
|
||||
call get_trigger_uncertainty(std_dev, rel_err, 1, filter_index, t)
|
||||
if (trigger % std_dev < std_dev) then
|
||||
if (trigger % std_dev < std_dev) then
|
||||
trigger % std_dev = std_dev
|
||||
end if
|
||||
if (trigger % rel_err < rel_err) then
|
||||
if (trigger % rel_err < rel_err) then
|
||||
trigger % rel_err = rel_err
|
||||
end if
|
||||
trigger % variance = trigger % std_dev**2
|
||||
|
|
@ -377,22 +378,22 @@ contains
|
|||
filter_index = &
|
||||
sum((matching_bins(1:t % n_filters) - 1) * t % stride) + 1
|
||||
call get_trigger_uncertainty(std_dev, rel_err, 1, filter_index, t)
|
||||
if (trigger % std_dev < std_dev) then
|
||||
if (trigger % std_dev < std_dev) then
|
||||
trigger % std_dev = std_dev
|
||||
end if
|
||||
if (trigger % rel_err < rel_err) then
|
||||
if (trigger % rel_err < rel_err) then
|
||||
trigger % rel_err = rel_err
|
||||
end if
|
||||
trigger % variance = trigger % std_dev**2
|
||||
|
||||
|
||||
matching_bins(i_filter_surf) = OUT_RIGHT
|
||||
filter_index = &
|
||||
sum((matching_bins(1:t % n_filters) - 1) * t % stride) + 1
|
||||
call get_trigger_uncertainty(std_dev, rel_err, 1, filter_index, t)
|
||||
if (trigger % std_dev < std_dev) then
|
||||
if (trigger % std_dev < std_dev) then
|
||||
trigger % std_dev = std_dev
|
||||
end if
|
||||
if (trigger % rel_err < rel_err) then
|
||||
if (trigger % rel_err < rel_err) then
|
||||
trigger % rel_err = rel_err
|
||||
end if
|
||||
trigger % variance = trigger % std_dev**2
|
||||
|
|
@ -404,10 +405,10 @@ contains
|
|||
filter_index = &
|
||||
sum((matching_bins(1:t % n_filters) - 1) * t % stride) + 1
|
||||
call get_trigger_uncertainty(std_dev, rel_err, 1, filter_index, t)
|
||||
if (trigger % std_dev < std_dev) then
|
||||
if (trigger % std_dev < std_dev) then
|
||||
trigger % std_dev = std_dev
|
||||
end if
|
||||
if (trigger % rel_err < rel_err) then
|
||||
if (trigger % rel_err < rel_err) then
|
||||
trigger % rel_err = rel_err
|
||||
end if
|
||||
trigger % variance = trigger % std_dev**2
|
||||
|
|
@ -417,10 +418,10 @@ contains
|
|||
filter_index = &
|
||||
sum((matching_bins(1:t % n_filters) - 1) * t % stride) + 1
|
||||
call get_trigger_uncertainty(std_dev, rel_err, 1, filter_index, t)
|
||||
if (trigger % std_dev < std_dev) then
|
||||
if (trigger % std_dev < std_dev) then
|
||||
trigger % std_dev = std_dev
|
||||
end if
|
||||
if (trigger % rel_err < rel_err) then
|
||||
if (trigger % rel_err < rel_err) then
|
||||
trigger % rel_err = rel_err
|
||||
end if
|
||||
trigger % variance = trigger % std_dev**2
|
||||
|
|
@ -432,10 +433,10 @@ contains
|
|||
filter_index = &
|
||||
sum((matching_bins(1:t % n_filters) - 1) * t % stride) + 1
|
||||
call get_trigger_uncertainty(std_dev, rel_err, 1, filter_index, t)
|
||||
if (trigger % std_dev < std_dev) then
|
||||
if (trigger % std_dev < std_dev) then
|
||||
trigger % std_dev = std_dev
|
||||
end if
|
||||
if (trigger % rel_err < rel_err) then
|
||||
if (trigger % rel_err < rel_err) then
|
||||
trigger % rel_err = rel_err
|
||||
end if
|
||||
trigger % variance = trigger % std_dev**2
|
||||
|
|
@ -444,10 +445,10 @@ contains
|
|||
filter_index = &
|
||||
sum((matching_bins(1:t % n_filters) - 1) * t % stride) + 1
|
||||
call get_trigger_uncertainty(std_dev, rel_err, 1, filter_index, t)
|
||||
if (trigger % std_dev < std_dev) then
|
||||
if (trigger % std_dev < std_dev) then
|
||||
trigger % std_dev = std_dev
|
||||
end if
|
||||
if (trigger % rel_err < rel_err) then
|
||||
if (trigger % rel_err < rel_err) then
|
||||
trigger % rel_err = rel_err
|
||||
end if
|
||||
trigger % variance = trigger % std_dev**2
|
||||
|
|
@ -459,10 +460,10 @@ contains
|
|||
filter_index = &
|
||||
sum((matching_bins(1:t % n_filters) - 1) * t % stride) + 1
|
||||
call get_trigger_uncertainty(std_dev, rel_err, 1, filter_index, t)
|
||||
if (trigger % std_dev < std_dev) then
|
||||
if (trigger % std_dev < std_dev) then
|
||||
trigger % std_dev = std_dev
|
||||
end if
|
||||
if (trigger % rel_err < rel_err) then
|
||||
if (trigger % rel_err < rel_err) then
|
||||
trigger % rel_err = rel_err
|
||||
end if
|
||||
trigger % variance = trigger % std_dev**2
|
||||
|
|
@ -471,10 +472,10 @@ contains
|
|||
filter_index = &
|
||||
sum((matching_bins(1:t % n_filters) - 1) * t % stride) + 1
|
||||
call get_trigger_uncertainty(std_dev, rel_err, 1, filter_index, t)
|
||||
if (trigger % std_dev < std_dev) then
|
||||
if (trigger % std_dev < std_dev) then
|
||||
trigger % std_dev = std_dev
|
||||
end if
|
||||
if (trigger % rel_err < rel_err) then
|
||||
if (trigger % rel_err < rel_err) then
|
||||
trigger % rel_err = rel_err
|
||||
end if
|
||||
trigger % variance = trigger % std_dev**2
|
||||
|
|
@ -486,10 +487,10 @@ contains
|
|||
filter_index = &
|
||||
sum((matching_bins(1:t % n_filters) - 1) * t % stride) + 1
|
||||
call get_trigger_uncertainty(std_dev, rel_err, 1, filter_index, t)
|
||||
if (trigger % std_dev < std_dev) then
|
||||
if (trigger % std_dev < std_dev) then
|
||||
trigger % std_dev = std_dev
|
||||
end if
|
||||
if (trigger % rel_err < rel_err) then
|
||||
if (trigger % rel_err < rel_err) then
|
||||
trigger % rel_err = rel_err
|
||||
end if
|
||||
trigger % variance = trigger % std_dev**2
|
||||
|
|
@ -498,10 +499,10 @@ contains
|
|||
filter_index = &
|
||||
sum((matching_bins(1:t % n_filters) - 1) * t % stride) + 1
|
||||
call get_trigger_uncertainty(std_dev, rel_err, 1, filter_index, t)
|
||||
if (trigger % std_dev < std_dev) then
|
||||
if (trigger % std_dev < std_dev) then
|
||||
trigger % std_dev = std_dev
|
||||
end if
|
||||
if (trigger % rel_err < rel_err) then
|
||||
if (trigger % rel_err < rel_err) then
|
||||
trigger % rel_err = rel_err
|
||||
end if
|
||||
trigger % variance = trigger % std_dev**2
|
||||
|
|
@ -539,11 +540,11 @@ contains
|
|||
std_dev = sqrt((tally_result % sum_sq / n - mean * mean) / (n - 1))
|
||||
|
||||
! Compute the relative error if the mean is non-zero
|
||||
if (mean == 0.) then
|
||||
rel_err = 0.
|
||||
if (mean == ZERO) then
|
||||
rel_err = ZERO
|
||||
else
|
||||
rel_err = std_dev / mean
|
||||
end if
|
||||
end if
|
||||
|
||||
end subroutine get_trigger_uncertainty
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, '../..')
|
||||
from openmc.statepoint import StatePoint
|
||||
|
||||
# read in statepoint file
|
||||
if len(sys.argv) > 1:
|
||||
sp = StatePoint(sys.argv[1])
|
||||
else:
|
||||
sp = StatePoint('statepoint.10.binary')
|
||||
sp.read_results()
|
||||
|
||||
# set up output string
|
||||
outstr = ''
|
||||
|
||||
# write out k-combined
|
||||
outstr += 'k-combined:\n'
|
||||
outstr += "{0:12.6E} {1:12.6E}\n".format(sp.k_combined[0], sp.k_combined[1])
|
||||
|
||||
# write results to file
|
||||
with open('results_test.dat','w') as fh:
|
||||
fh.write(outstr)
|
||||
58
tests/test_basic/test_basic.py
Normal file → Executable file
58
tests/test_basic/test_basic.py
Normal file → Executable file
|
|
@ -1,60 +1,10 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
from subprocess import Popen, STDOUT, PIPE, call
|
||||
import filecmp
|
||||
import glob
|
||||
from optparse import OptionParser
|
||||
sys.path.insert(0, '..')
|
||||
from testing_harness import TestHarness
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option('--mpi_exec', dest='mpi_exec', default='')
|
||||
parser.add_option('--mpi_np', dest='mpi_np', default='3')
|
||||
parser.add_option('--exe', dest='exe')
|
||||
(opts, args) = parser.parse_args()
|
||||
cwd = os.getcwd()
|
||||
|
||||
def test_run():
|
||||
if opts.mpi_exec != '':
|
||||
proc = Popen([opts.mpi_exec, '-np', opts.mpi_np, opts.exe, cwd],
|
||||
stderr=STDOUT, stdout=PIPE)
|
||||
else:
|
||||
proc = Popen([opts.exe, cwd], stderr=STDOUT, stdout=PIPE)
|
||||
print(proc.communicate()[0])
|
||||
returncode = proc.returncode
|
||||
assert returncode == 0, 'OpenMC did not exit successfully.'
|
||||
|
||||
def test_created_statepoint():
|
||||
statepoint = glob.glob(os.path.join(cwd, 'statepoint.10.*'))
|
||||
assert len(statepoint) == 1, 'Either multiple or no statepoint files exist.'
|
||||
assert statepoint[0].endswith('binary') or statepoint[0].endswith('h5'),\
|
||||
'Statepoint file is not a binary or hdf5 file.'
|
||||
|
||||
def test_results():
|
||||
statepoint = glob.glob(os.path.join(cwd, 'statepoint.10.*'))
|
||||
call([sys.executable, 'results.py', statepoint[0]])
|
||||
compare = filecmp.cmp('results_test.dat', 'results_true.dat')
|
||||
if not compare:
|
||||
os.rename('results_test.dat', 'results_error.dat')
|
||||
assert compare, 'Results do not agree.'
|
||||
|
||||
def teardown():
|
||||
output = glob.glob(os.path.join(cwd, 'statepoint.10.*'))
|
||||
output.append(os.path.join(cwd, 'results_test.dat'))
|
||||
for f in output:
|
||||
if os.path.exists(f):
|
||||
os.remove(f)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# test for openmc executable
|
||||
if opts.exe is None:
|
||||
raise Exception('Must specify OpenMC executable from command line with --exe.')
|
||||
|
||||
# run tests
|
||||
try:
|
||||
test_run()
|
||||
test_created_statepoint()
|
||||
test_results()
|
||||
finally:
|
||||
teardown()
|
||||
harness = TestHarness('statepoint.10.*')
|
||||
harness.main()
|
||||
|
|
|
|||
|
|
@ -1,92 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import numpy as np
|
||||
|
||||
sys.path.insert(0, '../..')
|
||||
import openmc
|
||||
from openmc.statepoint import StatePoint
|
||||
|
||||
# read in statepoint file
|
||||
if len(sys.argv) > 1:
|
||||
sp = StatePoint(sys.argv[1])
|
||||
else:
|
||||
sp = StatePoint('statepoint.20.binary')
|
||||
|
||||
sp.read_results()
|
||||
|
||||
# extract tally results and convert to vector
|
||||
tally1 = sp.get_tally(scores=['flux'], filters=[openmc.Filter('mesh', [1])], \
|
||||
estimator='tracklength')
|
||||
tally2 = sp.get_tally(scores=['flux'], filters=[openmc.Filter('mesh', [2])], \
|
||||
estimator='analog')
|
||||
tally3 = sp.get_tally(scores=['nu-fission'], \
|
||||
filters=[openmc.Filter('mesh', [2])], estimator='analog')
|
||||
tally4 = sp.get_tally(scores=['current'], filters=[openmc.Filter('mesh', [2]), \
|
||||
openmc.Filter('surface', [1,2,3,4,5,6])], \
|
||||
estimator='analog')
|
||||
|
||||
results1 = np.zeros((tally1.sum.size + tally1.sum.size, ))
|
||||
results1[0::2] = tally1.sum.ravel()
|
||||
results1[1::2] = tally1.sum_sq.ravel()
|
||||
|
||||
results2 = np.zeros((tally2.sum.size + tally2.sum.size, ))
|
||||
results2[0::2] = tally2.sum.ravel()
|
||||
results2[1::2] = tally2.sum_sq.ravel()
|
||||
|
||||
results3 = np.zeros((tally3.sum.size + tally3.sum.size, ))
|
||||
results3[0::2] = tally3.sum.ravel()
|
||||
results3[1::2] = tally3.sum_sq.ravel()
|
||||
|
||||
results4 = np.zeros((tally4.sum.size + tally4.sum.size, ))
|
||||
results4[0::2] = tally4.sum.ravel()
|
||||
results4[1::2] = tally4.sum_sq.ravel()
|
||||
|
||||
# set up output string
|
||||
outstr = ''
|
||||
|
||||
# write out k-combined
|
||||
outstr += 'k-combined:\n'
|
||||
outstr += "{0:12.6E} {1:12.6E}\n".format(sp.k_combined[0], sp.k_combined[1])
|
||||
|
||||
# write out tally results
|
||||
outstr += 'tally 1:\n'
|
||||
for item in results1:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
outstr += 'tally 2:\n'
|
||||
for item in results2:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
outstr += 'tally 3:\n'
|
||||
for item in results3:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
outstr += 'tally 4:\n'
|
||||
for item in results4:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
|
||||
# write out cmfd answers
|
||||
outstr += 'cmfd indices\n'
|
||||
for item in sp._cmfd_indices:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
outstr += 'k cmfd\n'
|
||||
for item in sp._k_cmfd:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
outstr += 'cmfd entropy\n'
|
||||
for item in sp._cmfd_entropy:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
outstr += 'cmfd balance\n'
|
||||
for item in sp._cmfd_balance:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
outstr += 'cmfd dominance ratio\n'
|
||||
for item in sp._cmfd_dominance:
|
||||
outstr += "{0:10.3E}\n".format(item)
|
||||
outstr += 'cmfd openmc source comparison\n'
|
||||
for item in sp._cmfd_srccmp:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
outstr += 'cmfd source\n'
|
||||
cmfdsrc = np.reshape(sp._cmfd_src, np.product(sp._cmfd_indices), order='F')
|
||||
for item in cmfdsrc:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
|
||||
# write results to file
|
||||
with open('results_test.dat', 'w') as fh:
|
||||
fh.write(outstr)
|
||||
|
|
@ -14,7 +14,7 @@ tally 1:
|
|||
3.894180E+01
|
||||
1.517824E+02
|
||||
3.528006E+01
|
||||
1.246309E+02
|
||||
1.246308E+02
|
||||
2.863448E+01
|
||||
8.222321E+01
|
||||
2.125384E+01
|
||||
|
|
|
|||
|
|
@ -1,68 +1,10 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
from subprocess import Popen, STDOUT, PIPE, call
|
||||
import filecmp
|
||||
import glob
|
||||
from optparse import OptionParser
|
||||
sys.path.insert(0, '..')
|
||||
from testing_harness import CMFDTestHarness
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option('--mpi_exec', dest='mpi_exec', default='')
|
||||
parser.add_option('--mpi_np', dest='mpi_np', default='3')
|
||||
parser.add_option('--exe', dest='exe')
|
||||
(opts, args) = parser.parse_args()
|
||||
cwd = os.getcwd()
|
||||
|
||||
def test_run():
|
||||
if opts.mpi_exec != '':
|
||||
proc = Popen([opts.mpi_exec, '-np', opts.mpi_np, opts.exe, cwd],
|
||||
stderr=STDOUT, stdout=PIPE)
|
||||
else:
|
||||
proc = Popen([opts.exe, cwd], stderr=STDOUT, stdout=PIPE)
|
||||
print(proc.communicate()[0])
|
||||
returncode = proc.returncode
|
||||
assert returncode == 0, 'OpenMC did not exit successfully.'
|
||||
|
||||
def test_created_statepoint():
|
||||
statepoint = glob.glob(os.path.join(cwd, 'statepoint.20.*'))
|
||||
assert len(statepoint) == 1, 'Either multiple or no statepoint files exist.'
|
||||
assert statepoint[0].endswith('binary') or statepoint[0].endswith('h5'),\
|
||||
'Statepoint file is not a binary or hdf5 file.'
|
||||
|
||||
|
||||
def test_output_exists():
|
||||
assert os.path.exists(os.path.join(cwd, 'tallies.out')), 'Tally output file does not exist.'
|
||||
|
||||
|
||||
def test_results():
|
||||
statepoint = glob.glob(os.path.join(cwd, 'statepoint.20.*'))
|
||||
call([sys.executable, 'results.py', statepoint[0]])
|
||||
compare = filecmp.cmp('results_test.dat', 'results_true.dat')
|
||||
if not compare:
|
||||
os.rename('results_test.dat', 'results_error.dat')
|
||||
assert compare, 'Results do not agree.'
|
||||
|
||||
|
||||
def teardown():
|
||||
output = glob.glob(os.path.join(cwd, 'statepoint.20.*'))
|
||||
output.append(os.path.join(cwd, 'tallies.out'))
|
||||
output.append(os.path.join(cwd, 'results_test.dat'))
|
||||
for f in output:
|
||||
if os.path.exists(f):
|
||||
os.remove(f)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# test for openmc executable
|
||||
if opts.exe is None:
|
||||
raise Exception('Must specify OpenMC executable from command line with --exe.')
|
||||
|
||||
# run tests
|
||||
try:
|
||||
test_run()
|
||||
test_created_statepoint()
|
||||
test_output_exists()
|
||||
test_results()
|
||||
finally:
|
||||
teardown()
|
||||
harness = CMFDTestHarness('statepoint.20.*', True)
|
||||
harness.main()
|
||||
|
|
|
|||
|
|
@ -1,92 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import numpy as np
|
||||
|
||||
sys.path.insert(0, '../..')
|
||||
import openmc
|
||||
from openmc.statepoint import StatePoint
|
||||
|
||||
# read in statepoint file
|
||||
if len(sys.argv) > 1:
|
||||
sp = StatePoint(sys.argv[1])
|
||||
else:
|
||||
sp = StatePoint('statepoint.20.binary')
|
||||
|
||||
sp.read_results()
|
||||
|
||||
# extract tally results and convert to vector
|
||||
tally1 = sp.get_tally(scores=['flux'], filters=[openmc.Filter('mesh', [1])], \
|
||||
estimator='tracklength')
|
||||
tally2 = sp.get_tally(scores=['flux'], filters=[openmc.Filter('mesh', [2])], \
|
||||
estimator='analog')
|
||||
tally3 = sp.get_tally(scores=['nu-fission'], \
|
||||
filters=[openmc.Filter('mesh', [2])], estimator='analog')
|
||||
tally4 = sp.get_tally(scores=['current'], filters=[openmc.Filter('mesh', [2]), \
|
||||
openmc.Filter('surface', [1,2,3,4,5,6])], \
|
||||
estimator='analog')
|
||||
|
||||
results1 = np.zeros((tally1.sum.size + tally1.sum.size, ))
|
||||
results1[0::2] = tally1.sum.ravel()
|
||||
results1[1::2] = tally1.sum_sq.ravel()
|
||||
|
||||
results2 = np.zeros((tally2.sum.size + tally2.sum.size, ))
|
||||
results2[0::2] = tally2.sum.ravel()
|
||||
results2[1::2] = tally2.sum_sq.ravel()
|
||||
|
||||
results3 = np.zeros((tally3.sum.size + tally3.sum.size, ))
|
||||
results3[0::2] = tally3.sum.ravel()
|
||||
results3[1::2] = tally3.sum_sq.ravel()
|
||||
|
||||
results4 = np.zeros((tally4.sum.size + tally4.sum.size, ))
|
||||
results4[0::2] = tally4.sum.ravel()
|
||||
results4[1::2] = tally4.sum_sq.ravel()
|
||||
|
||||
# set up output string
|
||||
outstr = ''
|
||||
|
||||
# write out k-combined
|
||||
outstr += 'k-combined:\n'
|
||||
outstr += "{0:12.6E} {1:12.6E}\n".format(sp._k_combined[0], sp._k_combined[1])
|
||||
|
||||
# write out tally results
|
||||
outstr += 'tally 1:\n'
|
||||
for item in results1:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
outstr += 'tally 2:\n'
|
||||
for item in results2:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
outstr += 'tally 3:\n'
|
||||
for item in results3:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
outstr += 'tally 4:\n'
|
||||
for item in results4:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
|
||||
# write out cmfd answers
|
||||
outstr += 'cmfd indices\n'
|
||||
for item in sp._cmfd_indices:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
outstr += 'k cmfd\n'
|
||||
for item in sp._k_cmfd:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
outstr += 'cmfd entropy\n'
|
||||
for item in sp._cmfd_entropy:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
outstr += 'cmfd balance\n'
|
||||
for item in sp._cmfd_balance:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
outstr += 'cmfd dominance ratio\n'
|
||||
for item in sp._cmfd_dominance:
|
||||
outstr += "{0:10.3E}\n".format(item)
|
||||
outstr += 'cmfd openmc source comparison\n'
|
||||
for item in sp._cmfd_srccmp:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
outstr += 'cmfd source\n'
|
||||
cmfdsrc = np.reshape(sp._cmfd_src, np.product(sp._cmfd_indices), order='F')
|
||||
for item in cmfdsrc:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
|
||||
# write results to file
|
||||
with open('results_test.dat', 'w') as fh:
|
||||
fh.write(outstr)
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
k-combined:
|
||||
1.170519E+00 8.422959E-03
|
||||
1.170519E+00 8.422960E-03
|
||||
tally 1:
|
||||
1.078122E+01
|
||||
1.170828E+01
|
||||
|
|
@ -47,7 +47,7 @@ tally 2:
|
|||
6.213554E+00
|
||||
1.946061E+00
|
||||
7.376629E+01
|
||||
2.729167E+02
|
||||
2.729166E+02
|
||||
5.253400E+01
|
||||
1.385018E+02
|
||||
6.438590E+00
|
||||
|
|
|
|||
|
|
@ -1,69 +1,10 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
from subprocess import Popen, STDOUT, PIPE, call
|
||||
import filecmp
|
||||
import glob
|
||||
from optparse import OptionParser
|
||||
sys.path.insert(0, '..')
|
||||
from testing_harness import CMFDTestHarness
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option('--mpi_exec', dest='mpi_exec', default='')
|
||||
parser.add_option('--mpi_np', dest='mpi_np', default='3')
|
||||
parser.add_option('--exe', dest='exe')
|
||||
(opts, args) = parser.parse_args()
|
||||
cwd = os.getcwd()
|
||||
|
||||
def test_run():
|
||||
if opts.mpi_exec != '':
|
||||
proc = Popen([opts.mpi_exec, '-np', opts.mpi_np, opts.exe, cwd],
|
||||
stderr=STDOUT, stdout=PIPE)
|
||||
else:
|
||||
proc = Popen([opts.exe, cwd], stderr=STDOUT, stdout=PIPE)
|
||||
print(proc.communicate()[0])
|
||||
returncode = proc.returncode
|
||||
assert returncode == 0, 'OpenMC did not exit successfully.'
|
||||
|
||||
|
||||
def test_created_statepoint():
|
||||
statepoint = glob.glob(os.path.join(cwd, 'statepoint.20.*'))
|
||||
assert len(statepoint) == 1, 'Either multiple or no statepoint files exist.'
|
||||
assert statepoint[0].endswith('binary') or statepoint[0].endswith('h5'),\
|
||||
'Statepoint file is not a binary or hdf5 file.'
|
||||
|
||||
|
||||
def test_output_exists():
|
||||
assert os.path.exists(os.path.join(cwd, 'tallies.out')), 'Tally output file does not exist.'
|
||||
|
||||
|
||||
def test_results():
|
||||
statepoint = glob.glob(os.path.join(cwd, 'statepoint.20.*'))
|
||||
call([sys.executable, 'results.py', statepoint[0]])
|
||||
compare = filecmp.cmp('results_test.dat', 'results_true.dat')
|
||||
if not compare:
|
||||
os.rename('results_test.dat', 'results_error.dat')
|
||||
assert compare, 'Results do not agree.'
|
||||
|
||||
|
||||
def teardown():
|
||||
output = glob.glob(os.path.join(cwd, 'statepoint.20.*'))
|
||||
output.append(os.path.join(cwd, 'tallies.out'))
|
||||
output.append(os.path.join(cwd, 'results_test.dat'))
|
||||
for f in output:
|
||||
if os.path.exists(f):
|
||||
os.remove(f)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# test for openmc executable
|
||||
if opts.exe is None:
|
||||
raise Exception('Must specify OpenMC executable from command line with --exe.')
|
||||
|
||||
# run tests
|
||||
try:
|
||||
test_run()
|
||||
test_created_statepoint()
|
||||
test_output_exists()
|
||||
test_results()
|
||||
finally:
|
||||
teardown()
|
||||
harness = CMFDTestHarness('statepoint.20.*', True)
|
||||
harness.main()
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import numpy as np
|
||||
|
||||
sys.path.insert(0, '../..')
|
||||
from openmc.statepoint import StatePoint
|
||||
|
||||
# read in statepoint file
|
||||
if len(sys.argv) > 1:
|
||||
sp = StatePoint(sys.argv[1])
|
||||
else:
|
||||
sp = StatePoint('statepoint.10.binary')
|
||||
|
||||
sp.read_results()
|
||||
|
||||
# extract tally results and convert to vector
|
||||
tally = sp._tallies[1]
|
||||
results = np.zeros((tally._sum.size + tally._sum.size, ))
|
||||
results[0::2] = tally._sum.ravel()
|
||||
results[1::2] = tally._sum_sq.ravel()
|
||||
|
||||
# set up output string
|
||||
outstr = ''
|
||||
|
||||
# write out k-combined
|
||||
outstr += 'k-combined:\n'
|
||||
outstr += "{0:12.6E} {1:12.6E}\n".format(sp._k_combined[0], sp._k_combined[1])
|
||||
|
||||
# write out tally results
|
||||
outstr += 'tallies:\n'
|
||||
for item in results:
|
||||
outstr += "{0:12.6E}\n".format(item)
|
||||
|
||||
# write results to file
|
||||
with open('results_test.dat','w') as fh:
|
||||
fh.write(outstr)
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
k-combined:
|
||||
2.913599E-01 6.738749E-03
|
||||
tallies:
|
||||
tally 1:
|
||||
6.420923E+01
|
||||
5.190738E+02
|
||||
|
|
|
|||
63
tests/test_confidence_intervals/test_confidence_intervals.py
Normal file → Executable file
63
tests/test_confidence_intervals/test_confidence_intervals.py
Normal file → Executable file
|
|
@ -1,65 +1,10 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
from subprocess import Popen, STDOUT, PIPE, call
|
||||
import filecmp
|
||||
import glob
|
||||
from optparse import OptionParser
|
||||
sys.path.insert(0, '..')
|
||||
from testing_harness import TestHarness
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option('--mpi_exec', dest='mpi_exec', default='')
|
||||
parser.add_option('--mpi_np', dest='mpi_np', default='3')
|
||||
parser.add_option('--exe', dest='exe')
|
||||
(opts, args) = parser.parse_args()
|
||||
cwd = os.getcwd()
|
||||
|
||||
def test_run():
|
||||
if opts.mpi_exec != '':
|
||||
proc = Popen([opts.mpi_exec, '-np', opts.mpi_np, opts.exe, cwd],
|
||||
stderr=STDOUT, stdout=PIPE)
|
||||
else:
|
||||
proc = Popen([opts.exe, cwd], stderr=STDOUT, stdout=PIPE)
|
||||
print(proc.communicate()[0])
|
||||
returncode = proc.returncode
|
||||
assert returncode == 0, 'OpenMC did not exit successfully.'
|
||||
|
||||
def test_created_statepoint():
|
||||
statepoint = glob.glob(os.path.join(cwd, 'statepoint.10.*'))
|
||||
assert len(statepoint) == 1, 'Either multiple or no statepoint files exist.'
|
||||
assert statepoint[0].endswith('binary') or statepoint[0].endswith('h5'),\
|
||||
'Statepoint file is not a binary or hdf5 file.'
|
||||
|
||||
def test_created_output():
|
||||
assert os.path.exists(os.path.join(cwd, 'tallies.out')), 'Tally output file does not exist.'
|
||||
|
||||
def test_results():
|
||||
statepoint = glob.glob(os.path.join(cwd, 'statepoint.10.*'))
|
||||
call([sys.executable, 'results.py', statepoint[0]])
|
||||
compare = filecmp.cmp('results_test.dat', 'results_true.dat')
|
||||
if not compare:
|
||||
os.rename('results_test.dat', 'results_error.dat')
|
||||
assert compare, 'Results do not agree.'
|
||||
|
||||
def teardown():
|
||||
output = glob.glob(os.path.join(cwd, 'statepoint.10.*'))
|
||||
output.append(os.path.join(cwd, 'results_test.dat'))
|
||||
output.append(os.path.join(cwd, 'tallies.out'))
|
||||
for f in output:
|
||||
if os.path.exists(f):
|
||||
os.remove(f)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# test for openmc executable
|
||||
if opts.exe is None:
|
||||
raise Exception('Must specify OpenMC executable from command line with --exe.')
|
||||
|
||||
# run tests
|
||||
try:
|
||||
test_run()
|
||||
test_created_statepoint()
|
||||
test_created_output()
|
||||
test_results()
|
||||
finally:
|
||||
teardown()
|
||||
harness = TestHarness('statepoint.10.*', True)
|
||||
harness.main()
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, '../..')
|
||||
from openmc.statepoint import StatePoint
|
||||
|
||||
# read in statepoint file
|
||||
if len(sys.argv) > 1:
|
||||
sp = StatePoint(sys.argv[1])
|
||||
else:
|
||||
sp = StatePoint('statepoint.10.binary')
|
||||
|
||||
sp.read_results()
|
||||
|
||||
# set up output string
|
||||
outstr = ''
|
||||
|
||||
# write out k-combined
|
||||
outstr += 'k-combined:\n'
|
||||
outstr += "{0:12.6E} {1:12.6E}\n".format(sp._k_combined[0], sp._k_combined[1])
|
||||
|
||||
# write results to file
|
||||
with open('results_test.dat','w') as fh:
|
||||
fh.write(outstr)
|
||||
|
|
@ -1,60 +1,10 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
from subprocess import Popen, STDOUT, PIPE, call
|
||||
import filecmp
|
||||
import glob
|
||||
from optparse import OptionParser
|
||||
sys.path.insert(0, '..')
|
||||
from testing_harness import TestHarness
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option('--mpi_exec', dest='mpi_exec', default='')
|
||||
parser.add_option('--mpi_np', dest='mpi_np', default='3')
|
||||
parser.add_option('--exe', dest='exe')
|
||||
(opts, args) = parser.parse_args()
|
||||
cwd = os.getcwd()
|
||||
|
||||
def test_run():
|
||||
if opts.mpi_exec != '':
|
||||
proc = Popen([opts.mpi_exec, '-np', opts.mpi_np, opts.exe, cwd],
|
||||
stderr=STDOUT, stdout=PIPE)
|
||||
else:
|
||||
proc = Popen([opts.exe, cwd], stderr=STDOUT, stdout=PIPE)
|
||||
print(proc.communicate()[0])
|
||||
returncode = proc.returncode
|
||||
assert returncode == 0, 'OpenMC did not exit successfully.'
|
||||
|
||||
def test_created_statepoint():
|
||||
statepoint = glob.glob(os.path.join(cwd, 'statepoint.10.*'))
|
||||
assert len(statepoint) == 1, 'Either multiple or no statepoint files exist.'
|
||||
assert statepoint[0].endswith('binary') or statepoint[0].endswith('h5'),\
|
||||
'Statepoint file is not a binary or hdf5 file.'
|
||||
|
||||
def test_results():
|
||||
statepoint = glob.glob(os.path.join(cwd, 'statepoint.10.*'))
|
||||
call([sys.executable, 'results.py', statepoint[0]])
|
||||
compare = filecmp.cmp('results_test.dat', 'results_true.dat')
|
||||
if not compare:
|
||||
os.rename('results_test.dat', 'results_error.dat')
|
||||
assert compare, 'Results do not agree.'
|
||||
|
||||
def teardown():
|
||||
output = glob.glob(os.path.join(cwd, 'statepoint.10.*'))
|
||||
output.append(os.path.join(cwd, 'results_test.dat'))
|
||||
for f in output:
|
||||
if os.path.exists(f):
|
||||
os.remove(f)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# test for openmc executable
|
||||
if opts.exe is None:
|
||||
raise Exception('Must specify OpenMC executable from command line with --exe.')
|
||||
|
||||
# run tests
|
||||
try:
|
||||
test_run()
|
||||
test_created_statepoint()
|
||||
test_results()
|
||||
finally:
|
||||
teardown()
|
||||
harness = TestHarness('statepoint.10.*')
|
||||
harness.main()
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, '../..')
|
||||
from openmc.statepoint import StatePoint
|
||||
|
||||
# read in statepoint file
|
||||
if len(sys.argv) > 1:
|
||||
sp = StatePoint(sys.argv[1])
|
||||
else:
|
||||
sp = StatePoint('statepoint.10.binary')
|
||||
|
||||
sp.read_results()
|
||||
|
||||
# set up output string
|
||||
outstr = ''
|
||||
|
||||
# write out k-combined
|
||||
outstr += 'k-combined:\n'
|
||||
outstr += "{0:12.6E} {1:12.6E}\n".format(sp._k_combined[0], sp._k_combined[1])
|
||||
|
||||
# write results to file
|
||||
with open('results_test.dat','w') as fh:
|
||||
fh.write(outstr)
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
k-combined:
|
||||
1.092203E+00 1.990175E-02
|
||||
1.092203E+00 1.990176E-02
|
||||
|
|
|
|||
|
|
@ -1,60 +1,10 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
from subprocess import Popen, STDOUT, PIPE, call
|
||||
import filecmp
|
||||
import glob
|
||||
from optparse import OptionParser
|
||||
sys.path.insert(0, '..')
|
||||
from testing_harness import TestHarness
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option('--mpi_exec', dest='mpi_exec', default='')
|
||||
parser.add_option('--mpi_np', dest='mpi_np', default='3')
|
||||
parser.add_option('--exe', dest='exe')
|
||||
(opts, args) = parser.parse_args()
|
||||
cwd = os.getcwd()
|
||||
|
||||
def test_run():
|
||||
if opts.mpi_exec != '':
|
||||
proc = Popen([opts.mpi_exec, '-np', opts.mpi_np, opts.exe, cwd],
|
||||
stderr=STDOUT, stdout=PIPE)
|
||||
else:
|
||||
proc = Popen([opts.exe, cwd], stderr=STDOUT, stdout=PIPE)
|
||||
print(proc.communicate()[0])
|
||||
returncode = proc.returncode
|
||||
assert returncode == 0, 'OpenMC did not exit successfully.'
|
||||
|
||||
def test_created_statepoint():
|
||||
statepoint = glob.glob(os.path.join(cwd, 'statepoint.10.*'))
|
||||
assert len(statepoint) == 1, 'Either multiple or no statepoint files exist.'
|
||||
assert statepoint[0].endswith('binary') or statepoint[0].endswith('h5'),\
|
||||
'Statepoint file is not a binary or hdf5 file.'
|
||||
|
||||
def test_results():
|
||||
statepoint = glob.glob(os.path.join(cwd, 'statepoint.10.*'))
|
||||
call([sys.executable, 'results.py', statepoint[0]])
|
||||
compare = filecmp.cmp('results_test.dat', 'results_true.dat')
|
||||
if not compare:
|
||||
os.rename('results_test.dat', 'results_error.dat')
|
||||
assert compare, 'Results do not agree.'
|
||||
|
||||
def teardown():
|
||||
output = glob.glob('statepoint.10.*')
|
||||
output.append(os.path.join(cwd, 'results_test.dat'))
|
||||
for f in output:
|
||||
if os.path.exists(f):
|
||||
os.remove(f)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# test for openmc executable
|
||||
if opts.exe is None:
|
||||
raise Exception('Must specify OpenMC executable from command line with --exe.')
|
||||
|
||||
# run tests
|
||||
try:
|
||||
test_run()
|
||||
test_created_statepoint()
|
||||
test_results()
|
||||
finally:
|
||||
teardown()
|
||||
harness = TestHarness('statepoint.10.*')
|
||||
harness.main()
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, '../..')
|
||||
from openmc.statepoint import StatePoint
|
||||
|
||||
# read in statepoint file
|
||||
if len(sys.argv) > 1:
|
||||
sp = StatePoint(sys.argv[1])
|
||||
else:
|
||||
sp = StatePoint('statepoint.10.binary')
|
||||
|
||||
sp.read_results()
|
||||
|
||||
# set up output string
|
||||
outstr = ''
|
||||
|
||||
# write out k-combined
|
||||
outstr += 'k-combined:\n'
|
||||
outstr += "{0:12.6E} {1:12.6E}\n".format(sp._k_combined[0], sp._k_combined[1])
|
||||
|
||||
# write results to file
|
||||
with open('results_test.dat','w') as fh:
|
||||
fh.write(outstr)
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
k-combined:
|
||||
8.085745E-01 9.674582E-03
|
||||
8.085745E-01 9.674599E-03
|
||||
|
|
|
|||
|
|
@ -1,60 +1,10 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
from subprocess import Popen, STDOUT, PIPE, call
|
||||
import filecmp
|
||||
import glob
|
||||
from optparse import OptionParser
|
||||
sys.path.insert(0, '..')
|
||||
from testing_harness import TestHarness
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option('--mpi_exec', dest='mpi_exec', default='')
|
||||
parser.add_option('--mpi_np', dest='mpi_np', default='3')
|
||||
parser.add_option('--exe', dest='exe')
|
||||
(opts, args) = parser.parse_args()
|
||||
cwd = os.getcwd()
|
||||
|
||||
def test_run():
|
||||
if opts.mpi_exec != '':
|
||||
proc = Popen([opts.mpi_exec, '-np', opts.mpi_np, opts.exe, cwd],
|
||||
stderr=STDOUT, stdout=PIPE)
|
||||
else:
|
||||
proc = Popen([opts.exe, cwd], stderr=STDOUT, stdout=PIPE)
|
||||
print(proc.communicate()[0])
|
||||
returncode = proc.returncode
|
||||
assert returncode == 0, 'OpenMC did not exit successfully.'
|
||||
|
||||
def test_created_statepoint():
|
||||
statepoint = glob.glob(os.path.join(cwd, 'statepoint.10.*'))
|
||||
assert len(statepoint) == 1, 'Either multiple or no statepoint files exist.'
|
||||
assert statepoint[0].endswith('binary') or statepoint[0].endswith('h5'),\
|
||||
'Statepoint file is not a binary or hdf5 file.'
|
||||
|
||||
def test_results():
|
||||
statepoint = glob.glob(os.path.join(cwd, 'statepoint.10.*'))
|
||||
call([sys.executable, 'results.py', statepoint[0]])
|
||||
compare = filecmp.cmp('results_test.dat', 'results_true.dat')
|
||||
if not compare:
|
||||
os.rename('results_test.dat', 'results_error.dat')
|
||||
assert compare, 'Results do not agree.'
|
||||
|
||||
def teardown():
|
||||
output = glob.glob(os.path.join(cwd, 'statepoint.10.*'))
|
||||
output.append(os.path.join(cwd, 'results_test.dat'))
|
||||
for f in output:
|
||||
if os.path.exists(f):
|
||||
os.remove(f)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# test for openmc executable
|
||||
if opts.exe is None:
|
||||
raise Exception('Must specify OpenMC executable from command line with --exe.')
|
||||
|
||||
# run tests
|
||||
try:
|
||||
test_run()
|
||||
test_created_statepoint()
|
||||
test_results()
|
||||
finally:
|
||||
teardown()
|
||||
harness = TestHarness('statepoint.10.*')
|
||||
harness.main()
|
||||
|
|
|
|||
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