mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-21 14:35:27 -04:00
Merge branch 'develop' into photon-new
This commit is contained in:
commit
970fc566a8
150 changed files with 11993 additions and 7991 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -95,3 +95,7 @@ examples/jupyter/plots
|
|||
*.c
|
||||
*.html
|
||||
*.so
|
||||
|
||||
.cache/
|
||||
.tox/
|
||||
.python-version
|
||||
|
|
|
|||
23
.travis.yml
23
.travis.yml
|
|
@ -28,21 +28,7 @@ matrix:
|
|||
env: OPENMC_CONFIG="check_source"
|
||||
|
||||
before_install:
|
||||
# ============== Handle Python third-party packages ==============
|
||||
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
|
||||
wget https://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh;
|
||||
else
|
||||
wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
|
||||
fi
|
||||
- bash miniconda.sh -b -p $HOME/miniconda
|
||||
- export PATH="$HOME/miniconda/bin:$PATH"
|
||||
- hash -r
|
||||
- conda config --set always_yes yes --set changeps1 no
|
||||
- conda update -q conda
|
||||
- conda info -a
|
||||
- if [[ $OPENMC_CONFIG != "check_source" ]]; then
|
||||
conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION six numpy scipy h5py=2.5 pandas;
|
||||
source activate test-environment;
|
||||
sudo add-apt-repository ppa:nschloe/hdf5-backports -y;
|
||||
sudo apt-get update -q;
|
||||
sudo apt-get install libhdf5-serial-dev libhdf5-mpich-dev -y;
|
||||
|
|
@ -52,7 +38,11 @@ before_install:
|
|||
export HDF5_DIR=/usr;
|
||||
fi
|
||||
|
||||
install: true
|
||||
install:
|
||||
- if [[ $OPENMC_CONFIG != "check_source" ]]; then
|
||||
pip install numpy cython;
|
||||
pip install -e .[test];
|
||||
fi
|
||||
|
||||
before_script:
|
||||
- if [[ $OPENMC_CONFIG != "check_source" ]]; then
|
||||
|
|
@ -71,6 +61,7 @@ script:
|
|||
- if [[ $OPENMC_CONFIG == "check_source" ]]; then
|
||||
./check_source.py;
|
||||
else
|
||||
./run_tests.py -C $OPENMC_CONFIG -j 2;
|
||||
./run_tests.py -C $OPENMC_CONFIG -j 2 &&
|
||||
pytest --cov=../openmc unit_tests/;
|
||||
fi
|
||||
- cd ..
|
||||
|
|
|
|||
|
|
@ -119,8 +119,8 @@ if(CMAKE_Fortran_COMPILER_ID STREQUAL GNU)
|
|||
list(APPEND f90flags -cpp -std=f2008ts -fbacktrace -O2)
|
||||
if(debug)
|
||||
list(REMOVE_ITEM f90flags -O2)
|
||||
list(APPEND f90flags -g -Wall -pedantic -fbounds-check
|
||||
-ffpe-trap=invalid,overflow,underflow)
|
||||
list(APPEND f90flags -g -Wall -Wno-unused-dummy-argument -pedantic
|
||||
-fbounds-check -ffpe-trap=invalid,overflow,underflow)
|
||||
list(APPEND ldflags -g)
|
||||
endif()
|
||||
if(profile)
|
||||
|
|
@ -320,10 +320,8 @@ set(LIBOPENMC_FORTRAN_SRC
|
|||
src/endf_header.F90
|
||||
src/energy_distribution.F90
|
||||
src/error.F90
|
||||
src/finalize.F90
|
||||
src/geometry.F90
|
||||
src/geometry_header.F90
|
||||
src/global.F90
|
||||
src/hdf5_interface.F90
|
||||
src/initialize.F90
|
||||
src/input_xml.F90
|
||||
|
|
@ -362,6 +360,8 @@ set(LIBOPENMC_FORTRAN_SRC
|
|||
src/secondary_nbody.F90
|
||||
src/secondary_uncorrelated.F90
|
||||
src/set_header.F90
|
||||
src/settings.F90
|
||||
src/simulation_header.F90
|
||||
src/simulation.F90
|
||||
src/source.F90
|
||||
src/source_header.F90
|
||||
|
|
@ -370,21 +370,37 @@ set(LIBOPENMC_FORTRAN_SRC
|
|||
src/string.F90
|
||||
src/summary.F90
|
||||
src/surface_header.F90
|
||||
src/tally.F90
|
||||
src/tally_filter.F90
|
||||
src/tally_filter_header.F90
|
||||
src/tally_header.F90
|
||||
src/tally_initialize.F90
|
||||
src/timer_header.F90
|
||||
src/tracking.F90
|
||||
src/track_output.F90
|
||||
src/trigger.F90
|
||||
src/trigger_header.F90
|
||||
src/urr_header.F90
|
||||
src/vector_header.F90
|
||||
src/volume_calc.F90
|
||||
src/volume_header.F90
|
||||
src/xml_interface.F90)
|
||||
src/xml_interface.F90
|
||||
src/tallies/tally.F90
|
||||
src/tallies/tally_derivative_header.F90
|
||||
src/tallies/tally_filter.F90
|
||||
src/tallies/tally_filter_header.F90
|
||||
src/tallies/tally_filter_azimuthal.F90
|
||||
src/tallies/tally_filter_cell.F90
|
||||
src/tallies/tally_filter_cellborn.F90
|
||||
src/tallies/tally_filter_cellfrom.F90
|
||||
src/tallies/tally_filter_delayedgroup.F90
|
||||
src/tallies/tally_filter_distribcell.F90
|
||||
src/tallies/tally_filter_energy.F90
|
||||
src/tallies/tally_filter_energyfunc.F90
|
||||
src/tallies/tally_filter_material.F90
|
||||
src/tallies/tally_filter_mesh.F90
|
||||
src/tallies/tally_filter_mu.F90
|
||||
src/tallies/tally_filter_particle.F90
|
||||
src/tallies/tally_filter_polar.F90
|
||||
src/tallies/tally_filter_surface.F90
|
||||
src/tallies/tally_filter_universe.F90
|
||||
src/tallies/tally_header.F90
|
||||
src/tallies/trigger.F90
|
||||
src/tallies/trigger_header.F90
|
||||
)
|
||||
add_library(libopenmc SHARED ${LIBOPENMC_FORTRAN_SRC})
|
||||
set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc)
|
||||
add_executable(${program} src/main.F90)
|
||||
|
|
@ -415,7 +431,7 @@ target_link_libraries(${program} ${ldflags} libopenmc)
|
|||
add_custom_command(TARGET libopenmc POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
$<TARGET_FILE:libopenmc>
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/openmc/_$<TARGET_FILE_NAME:libopenmc>
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/openmc/capi/$<TARGET_FILE_NAME:libopenmc>
|
||||
COMMENT "Copying libopenmc to Python module directory")
|
||||
|
||||
#===============================================================================
|
||||
|
|
@ -455,6 +471,11 @@ file(GLOB_RECURSE TESTS ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_*.py)
|
|||
|
||||
# Loop through all the tests
|
||||
foreach(test ${TESTS})
|
||||
# Remove unit tests
|
||||
if(test MATCHES ".*unit_tests.*")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
# Get test information
|
||||
get_filename_component(TEST_NAME ${test} NAME)
|
||||
get_filename_component(TEST_PATH ${test} PATH)
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
## This file should be placed in the root directory of your project.
|
||||
## Then modify the CMakeLists.txt file in the root directory of your
|
||||
## project to incorporate the testing dashboard.
|
||||
## # The following are required to uses Dart and the Cdash dashboard
|
||||
## ENABLE_TESTING()
|
||||
## INCLUDE(CTest)
|
||||
|
||||
# Generic information about CDASH site
|
||||
set(CTEST_PROJECT_NAME "OpenMC")
|
||||
set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC")
|
||||
set(CTEST_DROP_METHOD "http")
|
||||
set(CTEST_DROP_SITE "openmc.mit.edu")
|
||||
set(CTEST_DROP_LOCATION "/cdash/submit.php?project=OpenMC")
|
||||
set(CTEST_DROP_SITE_CDASH TRUE)
|
||||
|
||||
# Set file size larger to see more output
|
||||
set(CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE "20000")
|
||||
set(CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE "20000")
|
||||
|
||||
# User/password to CDASH site
|
||||
# Please contact Nick Horelik <nhorelik@mit.edu> or
|
||||
# Bryan Herman <bherman@mit.edu> if you want to push
|
||||
# test suite information to our CDASH site.
|
||||
set(CTEST_DROP_SITE_USER "")
|
||||
set(CTEST_DROP_SITE_PASSWORD "")
|
||||
35
MANIFEST.in
Normal file
35
MANIFEST.in
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
include CMakeLists.txt
|
||||
include LICENSE
|
||||
include schemas.xml
|
||||
include openmc/data/reconstruct.pyx
|
||||
include docs/source/_templates/layout.html
|
||||
include docs/sphinxext/LICENSE
|
||||
recursive-include . *.rst
|
||||
recursive-include cmake *.cmake
|
||||
recursive-include docs *.css
|
||||
recursive-include docs *.dia
|
||||
recursive-include docs *.png
|
||||
recursive-include docs *.py
|
||||
recursive-include docs *.svg
|
||||
recursive-include docs *.tex
|
||||
recursive-include docs *.txt
|
||||
recursive-include docs Makefile
|
||||
recursive-include examples *.h5
|
||||
recursive-include examples *.ipynb
|
||||
recursive-include examples *.png
|
||||
recursive-include examples *.py
|
||||
recursive-include examples *.xml
|
||||
recursive-include man *.1
|
||||
recursive-include src *.F90
|
||||
recursive-include src *.c
|
||||
recursive-include src *.cc
|
||||
recursive-include src *.cpp
|
||||
recursive-include src *.h
|
||||
recursive-include src *.hpp
|
||||
recursive-include src *.rnc
|
||||
recursive-include src *.rng
|
||||
recursive-include tests *.dat
|
||||
recursive-include tests *.h5
|
||||
recursive-include tests *.py
|
||||
recursive-include tests *.xml
|
||||
prune docs/build
|
||||
14
Makefile
14
Makefile
|
|
@ -1,14 +0,0 @@
|
|||
all:
|
||||
mkdir -p build
|
||||
cmake -H. -Bbuild
|
||||
make -s -C build
|
||||
clean:
|
||||
make -s -C build clean
|
||||
distclean:
|
||||
rm -fr build
|
||||
test:
|
||||
make -s -C build test
|
||||
install:
|
||||
make -s -C build install
|
||||
|
||||
.PHONY: all clean distclean test install
|
||||
|
|
@ -4,21 +4,32 @@
|
|||
C API
|
||||
=====
|
||||
|
||||
.. c:function:: void openmc_calculate_voumes()
|
||||
.. c:function:: void openmc_calculate_volumes()
|
||||
|
||||
Run a stochastic volume calculation
|
||||
|
||||
.. c:function:: int openmc_cell_set_temperature(int id, double T, int* instance)
|
||||
.. c:function:: int openmc_cell_get_id(int32_t index, int32_t* id)
|
||||
|
||||
Get the ID of a cell
|
||||
|
||||
:param index: Index in the cells array
|
||||
:type index: int32_t
|
||||
:param id: ID of the cell
|
||||
:type id: int32_t*
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_cell_set_temperature(index index, double T, int32_t* instance)
|
||||
|
||||
Set the temperature of a cell.
|
||||
|
||||
:param id: ID of the cell
|
||||
:type id: int
|
||||
:param index: Index in the cells array
|
||||
:type index: int32_t
|
||||
:param T: Temperature in Kelvin
|
||||
:type T: double
|
||||
:param instance: Which instance of the cell. To set the temperature for all
|
||||
instances, pass a null pointer.
|
||||
:type instance: int*
|
||||
:type instance: int32_t*
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
|
|
@ -26,7 +37,7 @@ C API
|
|||
|
||||
Finalize a simulation
|
||||
|
||||
.. c:function:: void openmc_find(double* xyz, int rtype, int* id, int* instance)
|
||||
.. c:function:: void openmc_find(double* xyz, int rtype, int32_t* id, int32_t* instance)
|
||||
|
||||
Determine the ID of the cell/material containing a given point
|
||||
|
||||
|
|
@ -36,10 +47,65 @@ C API
|
|||
:type rtype: int
|
||||
:param id: ID of the cell/material found. If a material is requested and the
|
||||
point is in a void, the ID is 0. If an error occurs, the ID is -1.
|
||||
:type id: int
|
||||
:type id: int32_t*
|
||||
:param instance: If a cell is repetaed in the geometry, the instance of the
|
||||
cell that was found and zero otherwise.
|
||||
:type instance: int
|
||||
:type instance: int32_t*
|
||||
|
||||
.. c:function:: int openmc_get_cell_index(int32_t id, int32_t* index)
|
||||
|
||||
Get the index in the cells array for a cell with a given ID
|
||||
|
||||
:param id: ID of the cell
|
||||
:type id: int32_t
|
||||
:param index: Index in the cells array
|
||||
:type index: int32_t*
|
||||
:return: Return status (negative if an error occurs)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_get_keff(double k_combined[])
|
||||
|
||||
:param k_combined: Combined estimate of k-effective
|
||||
:type k_combined: double[2]
|
||||
:return: Return status (negative if an error occurs)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_get_nuclide_index(char name[], int* index)
|
||||
|
||||
Get the index in the nuclides array for a nuclide with a given name
|
||||
|
||||
:param name: Name of the nuclide
|
||||
:type name: char[]
|
||||
:param index: Index in the nuclides array
|
||||
:type index: int*
|
||||
:return: Return status (negative if an error occurs)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_get_tally_index(int32_t id, int32_t* index)
|
||||
|
||||
Get the index in the tallies array for a tally with a given ID
|
||||
|
||||
:param id: ID of the tally
|
||||
:type id: int32_t
|
||||
:param index: Index in the tallies array
|
||||
:type index: int32_t*
|
||||
:return: Return status (negative if an error occurs)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_get_material_index(int32_t id, int32_t* index)
|
||||
|
||||
Get the index in the materials array for a material with a given ID
|
||||
|
||||
:param id: ID of the material
|
||||
:type id: int32_t
|
||||
:param index: Index in the materials array
|
||||
:type index: int32_t*
|
||||
:return: Return status (negative if an error occurs)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: void openmc_hard_reset()
|
||||
|
||||
Reset tallies, timers, and pseudo-random number generator state
|
||||
|
||||
.. c:function:: void openmc_init(int intracomm)
|
||||
|
||||
|
|
@ -57,13 +123,13 @@ C API
|
|||
:return: Return status (negative if an error occurs)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_material_add_nuclide(int id, char name[], double density)
|
||||
.. c:function:: int openmc_material_add_nuclide(int32_t index, char name[], double density)
|
||||
|
||||
Add a nuclide to an existing material. If the nuclide already exists, the
|
||||
density is overwritten.
|
||||
|
||||
:param id: ID of the material
|
||||
:type id: int
|
||||
:param index: Index in the materials array
|
||||
:type index: int32_t
|
||||
:param name: Name of the nuclide
|
||||
:type name: char[]
|
||||
:param density: Density in atom/b-cm
|
||||
|
|
@ -71,28 +137,67 @@ C API
|
|||
:return: Return status (negative if an error occurs)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_material_get_densities(int id, double* ptr)
|
||||
.. c:function:: int openmc_material_get_densities(int32_t index, int* nuclides[], double* densities[])
|
||||
|
||||
Get an array of nuclide densities for a material.
|
||||
Get density for each nuclide in a material.
|
||||
|
||||
:param id: ID of the material
|
||||
:type id: int
|
||||
:param ptr: Pointer to the array of densities
|
||||
:type ptr: double*
|
||||
:return: Length of the array
|
||||
:param index: Index in the materials array
|
||||
:type index: int32_t
|
||||
:param nuclides: Pointer to array of nuclide indices
|
||||
:type nuclides: int**
|
||||
:param densities: Pointer to the array of densities
|
||||
:type densities: double**
|
||||
:param n: Length of the array
|
||||
:type n: int
|
||||
:return: Return status (negative if an error occurs)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_material_set_density(int id, double density)
|
||||
.. c:function:: int openmc_material_get_id(int32_t index, int32_t* id)
|
||||
|
||||
Get the ID of a material
|
||||
|
||||
:param index: Index in the materials array
|
||||
:type index: int32_t
|
||||
:param id: ID of the material
|
||||
:type id: int32_t*
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_material_set_density(int32_t index, double density)
|
||||
|
||||
Set the density of a material.
|
||||
|
||||
:param id: ID of the material
|
||||
:type id: int
|
||||
:param index: Index in the materials array
|
||||
:type index: int32_t
|
||||
:param density: Density of the material in atom/b-cm
|
||||
:type density: double
|
||||
:return: Return status (negative if an error occurs)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_material_set_densities(int32_t, n, char* name[], double density[])
|
||||
|
||||
:param index: Index in the materials array
|
||||
:type index: int32_t
|
||||
:param n: Length of name/density
|
||||
:type n: int
|
||||
:param name: Array of nuclide names
|
||||
:type name: char**
|
||||
:param density: Array of densities
|
||||
:type density: double[]
|
||||
:return: Return status (negative if an error occurs)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_nuclide_name(int index, char* name[])
|
||||
|
||||
Get name of a nuclide
|
||||
|
||||
:param index: Index in the nuclides array
|
||||
:type index: int
|
||||
:param name: Name of the nuclide
|
||||
:type name: char**
|
||||
:return: Return status (negative if an error occurs)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: void openmc_plot_geometry()
|
||||
|
||||
Run plotting mode.
|
||||
|
|
@ -105,13 +210,52 @@ C API
|
|||
|
||||
Run a simulation
|
||||
|
||||
.. c:function:: void openmc_tally_results(int id, double** ptr, int shape_[3])
|
||||
.. c:function:: int openmc_tally_get_id(int32_t index, int32_t* id)
|
||||
|
||||
Get the ID of a tally
|
||||
|
||||
:param index: Index in the tallies array
|
||||
:type index: int32_t
|
||||
:param id: ID of the tally
|
||||
:type id: int32_t*
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_tally_get_nuclides(int32_t index, int* nuclides[], int* n)
|
||||
|
||||
Get nuclides specified in a tally
|
||||
|
||||
:param index: Index in the tallies array
|
||||
:type index: int32_t
|
||||
:param nuclides: Array of nuclide indices
|
||||
:type nuclides: int**
|
||||
:param n: Number of nuclides
|
||||
:type n: int*
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_tally_results(int32_t index, double** ptr, int shape_[3])
|
||||
|
||||
Get a pointer to tally results array.
|
||||
|
||||
:param id: ID of the tally
|
||||
:type id: int
|
||||
:param index: Index in the tallies array
|
||||
:type index: int32_t
|
||||
:param ptr: Pointer to the results array
|
||||
:type ptr: double**
|
||||
:param shape_: Shape of the results array
|
||||
:type shape_: int[3]
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
||||
.. c:function:: int openmc_tally_set_nuclides(int32_t index, int n, char* nuclides[])
|
||||
|
||||
Set the nuclides for a tally
|
||||
|
||||
:param index: Index in the tallies array
|
||||
:type index: int32_t
|
||||
:param n: Number of nuclides
|
||||
:type n: int
|
||||
:param nuclides: Array of nuclide names
|
||||
:type nuclides: char**
|
||||
:return: Return status (negative if an error occurred)
|
||||
:rtype: int
|
||||
|
|
|
|||
|
|
@ -123,9 +123,9 @@ to the scored values. The ``filter`` element has the following
|
|||
attributes/sub-elements:
|
||||
|
||||
:type:
|
||||
The type of the filter. Accepted options are "cell", "cellborn",
|
||||
"material", "universe", "energy", "energyout", "mu", "polar",
|
||||
"azimuthal", "mesh", "distribcell", "delayedgroup", and
|
||||
The type of the filter. Accepted options are "cell", "cellfrom",
|
||||
"cellborn", "surface", "material", "universe", "energy", "energyout", "mu",
|
||||
"polar", "azimuthal", "mesh", "distribcell", "delayedgroup", and
|
||||
"energyfunction".
|
||||
|
||||
:bins:
|
||||
|
|
@ -154,14 +154,31 @@ For each filter type, the following table describes what the ``bins`` attribute
|
|||
should be set to:
|
||||
|
||||
:cell:
|
||||
A list of unique IDs for cells in which the tally should be accumulated.
|
||||
A list of unique IDs for cells in which the tally should be
|
||||
accumulated.
|
||||
|
||||
:surface:
|
||||
This filter allows the tally to be scored when crossing a surface. A list of
|
||||
surface IDs should be given. By default, net currents are tallied, and to
|
||||
tally a partial current from one cell to another, this should be used in
|
||||
combination with a cell or cell_from filter that defines the other cell.
|
||||
This filter should not be used in combination with a meshfilter.
|
||||
|
||||
:cellfrom:
|
||||
This filter allows the tally to be scored when crossing a surface and the
|
||||
particle came from a specified cell. A list of cell IDs should be
|
||||
given.
|
||||
To tally a partial current from a cell to another, this filter should be
|
||||
used in combination with a cell filter, to define the other cell.
|
||||
This filter should not be used in combination with a meshfilter.
|
||||
|
||||
:cellborn:
|
||||
This filter allows the tally to be scored to only when particles were
|
||||
originally born in a specified cell. A list of cell IDs should be given.
|
||||
originally born in a specified cell. A list of cell IDs should be
|
||||
given.
|
||||
|
||||
:material:
|
||||
A list of unique IDs for matreials in which the tally should be accumulated.
|
||||
A list of unique IDs for materials in which the tally should be accumulated.
|
||||
|
||||
:universe:
|
||||
A list of unique IDs for universes in which the tally should be accumulated.
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ Constructing Tallies
|
|||
openmc.UniverseFilter
|
||||
openmc.MaterialFilter
|
||||
openmc.CellFilter
|
||||
openmc.CellFromFilter
|
||||
openmc.CellbornFilter
|
||||
openmc.SurfaceFilter
|
||||
openmc.MeshFilter
|
||||
|
|
|
|||
|
|
@ -2,16 +2,40 @@
|
|||
:data:`openmc.capi` -- Python bindings to the C API
|
||||
---------------------------------------------------
|
||||
|
||||
.. automodule:: openmc.capi
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. autosummary::
|
||||
:toctree: generated
|
||||
:nosignatures:
|
||||
:template: myfunction.rst
|
||||
|
||||
openmc.capi.lib_context
|
||||
openmc.capi.calculate_volumes
|
||||
openmc.capi.finalize
|
||||
openmc.capi.find_cell
|
||||
openmc.capi.find_material
|
||||
openmc.capi.hard_reset
|
||||
openmc.capi.init
|
||||
openmc.capi.keff
|
||||
openmc.capi.load_nuclide
|
||||
openmc.capi.plot_geometry
|
||||
openmc.capi.reset
|
||||
openmc.capi.run
|
||||
openmc.capi.run_in_memory
|
||||
|
||||
Classes
|
||||
-------
|
||||
|
||||
.. autosummary::
|
||||
:toctree: generated
|
||||
:nosignatures:
|
||||
:template: myclass.rst
|
||||
|
||||
openmc.capi.OpenMCLibrary
|
||||
openmc.capi.Cell
|
||||
openmc.capi.EnergyFilter
|
||||
openmc.capi.MaterialFilter
|
||||
openmc.capi.Material
|
||||
openmc.capi.Nuclide
|
||||
openmc.capi.Tally
|
||||
|
|
|
|||
|
|
@ -414,16 +414,19 @@ distributions.
|
|||
various HDF5 files, h5py is needed to provide access to data within these
|
||||
files from Python.
|
||||
|
||||
.. admonition:: Optional
|
||||
:class: note
|
||||
|
||||
`Matplotlib <http://matplotlib.org/>`_
|
||||
Matplotlib is used to providing plotting functionality in the API like the
|
||||
:meth:`Universe.plot` method and the :func:`openmc.plot_xs` function.
|
||||
|
||||
`uncertainties <https://pythonhosted.org/uncertainties/>`_
|
||||
Uncertainties are optionally used for decay data in the :mod:`openmc.data`
|
||||
module.
|
||||
Uncertainties are used for decay data in the :mod:`openmc.data` module.
|
||||
|
||||
`lxml <http://lxml.de/>`_
|
||||
lxml is used for the :ref:`scripts_validate` script and various other
|
||||
parts of the Python API.
|
||||
|
||||
.. admonition:: Optional
|
||||
:class: note
|
||||
|
||||
`Cython <http://cython.org/>`_
|
||||
Cython is used for resonance reconstruction for ENDF data converted to
|
||||
|
|
@ -437,8 +440,8 @@ distributions.
|
|||
The silomesh package is needed to convert voxel and track files to SILO
|
||||
format.
|
||||
|
||||
`lxml <http://lxml.de/>`_
|
||||
lxml is used for the :ref:`scripts_validate` script.
|
||||
`pytest <https://docs.pytest.org>`_
|
||||
The pytest framework is used for unit testing the Python API.
|
||||
|
||||
.. _usersguide_nxml:
|
||||
|
||||
|
|
|
|||
|
|
@ -261,12 +261,19 @@ The following tables show all valid scores:
|
|||
+----------------------+---------------------------------------------------+
|
||||
|Score | Description |
|
||||
+======================+===================================================+
|
||||
|current |Partial currents on the boundaries of each cell in |
|
||||
| |a mesh. Units are particles per source |
|
||||
| |particle. Note that this score can only be used if |
|
||||
| |a mesh filter has been specified. Furthermore, it |
|
||||
| |may not be used in conjunction with any other |
|
||||
| |score. |
|
||||
|current |Used in combination with a mesh filter: |
|
||||
| |Partial currents on the boundaries of each cell in |
|
||||
| |a mesh. It may not be used in conjunction with any |
|
||||
| |other score. Only energy and mesh filters may be |
|
||||
| |used. |
|
||||
| |Used in combination with a surface filter: |
|
||||
| |Net currents on any surface previously defined in |
|
||||
| |the geometry. It may be used along with any other |
|
||||
| |filter, except mesh filters. |
|
||||
| |Surfaces can alternatively be defined with cell |
|
||||
| |from and cell filters thereby resulting in tallying|
|
||||
| |partial currents. |
|
||||
| |Units are particles per source particle. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|events |Number of scoring events. Units are events per |
|
||||
| |source particle. |
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@
|
|||
"outputs": [],
|
||||
"source": [
|
||||
"# Instantiate a Materials collection\n",
|
||||
"materials_file = openmc.Materials((fuel, water, zircaloy))\n",
|
||||
"materials_file = openmc.Materials([fuel, water, zircaloy])\n",
|
||||
"\n",
|
||||
"# Export to \"materials.xml\"\n",
|
||||
"materials_file.export_to_xml()"
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@
|
|||
"outputs": [],
|
||||
"source": [
|
||||
"# Instantiate a Materials object\n",
|
||||
"materials_file = openmc.Materials((fuel, water, zircaloy))\n",
|
||||
"materials_file = openmc.Materials([fuel, water, zircaloy])\n",
|
||||
"\n",
|
||||
"# Export to \"materials.xml\"\n",
|
||||
"materials_file.export_to_xml()"
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -79,7 +79,7 @@
|
|||
"outputs": [],
|
||||
"source": [
|
||||
"# Instantiate a Materials collection\n",
|
||||
"materials_file = openmc.Materials((fuel, water, zircaloy))\n",
|
||||
"materials_file = openmc.Materials([fuel, water, zircaloy])\n",
|
||||
"\n",
|
||||
"# Export to \"materials.xml\"\n",
|
||||
"materials_file.export_to_xml()"
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@
|
|||
"outputs": [],
|
||||
"source": [
|
||||
"# Instantiate a Materials collection\n",
|
||||
"materials_file = openmc.Materials((fuel, water, zircaloy))\n",
|
||||
"materials_file = openmc.Materials([fuel, water, zircaloy])\n",
|
||||
"\n",
|
||||
"# Export to \"materials.xml\"\n",
|
||||
"materials_file.export_to_xml()"
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@
|
|||
" water.add_element('B', ppm_Boron * 1E-6)\n",
|
||||
" \n",
|
||||
" # Instantiate a Materials object\n",
|
||||
" materials = openmc.Materials((fuel, zircaloy, water))\n",
|
||||
" materials = openmc.Materials([fuel, zircaloy, water])\n",
|
||||
" \n",
|
||||
" # Create cylinders for the fuel and clad\n",
|
||||
" fuel_outer_radius = openmc.ZCylinder(R=0.39218)\n",
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
|
@ -19,7 +19,6 @@
|
|||
"\n",
|
||||
"from IPython.display import Image\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"import openmc"
|
||||
]
|
||||
},
|
||||
|
|
@ -65,7 +64,7 @@
|
|||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
|
@ -100,12 +99,12 @@
|
|||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Instantiate a Materials collection\n",
|
||||
"materials_file = openmc.Materials((fuel, water, zircaloy))\n",
|
||||
"materials_file = openmc.Materials([fuel, water, zircaloy])\n",
|
||||
"\n",
|
||||
"# Export to \"materials.xml\"\n",
|
||||
"materials_file.export_to_xml()"
|
||||
|
|
@ -122,7 +121,7 @@
|
|||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
|
@ -151,7 +150,7 @@
|
|||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
|
@ -188,7 +187,7 @@
|
|||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
|
@ -215,7 +214,7 @@
|
|||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
|
@ -228,7 +227,7 @@
|
|||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
|
@ -283,7 +282,7 @@
|
|||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
|
@ -310,9 +309,7 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
|
|
@ -333,13 +330,11 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX////pgJFyEhJNv8RV\nUZDeAAAAAWJLR0QAiAUdSAAAAAd0SU1FB+EEDRUZLksd2dYAAALKSURBVGje7dpLcqQwDAbgHHE2\nYeEj+D4cwQucBUfo+3CEXoSp8OhuhF70T4qpKXmdr21LogK2Pj7A8QmNP+HDhw8fPnz48Kf6VH9G\n+66vy+je8k19jnf8C5dXIPv86ms56lPdjvaYbyodx3ze+XLE76cXFiD4zPji99z0/AJ4n1lfvJ6f\nnl0A6x+578efMSg1wPr172/jPO5yFXM+Ef78gdblM+WPHyguP//t1/g6pA0wfln+ho/fwgYYn19C\n/xwDvwHGc9OvC+hs37DTrwuwfWanXxdQTC9Mvyygs3wjTL8uwPJpn/tNDbSGz7T0SBEWw4vLXzbQ\n6b6RoveIoO6TvPxlA63qs7z8ZQPF9F+SH22vbX8OQKf5Rtv+EgDNJ3X58wZaxWd1+fMGiuFvir8b\nvjp8J/tGy/6jAmRvhW8fwL3vVT+o3grfPoB7r/IpALI3tz8FoJN84/NV873hB8UnM3xzANtf8nb4\ndwmg3grfFEDJO8JPE0i9Ff4pAYL3pI8mkHor/HMCeO9JH00g9SafEsh7T/ppARBvp48UwJnelT5S\nACd7O31TAlnvKx9SQCd7B58KgPO+8iMFuPWe9E8F8BveWX7bAjzX9y4//Jve+fhsH6Ctv7n8PTzj\nvY/v9gEOHz58+PBX+6v/f/wPvnd54f3j6venE/yl769Xv7+j3x/o98/V32/o9+fl389Xnx+g5x/o\n+Qt6/oOeP6HnX+j5G3z+h54/ouefV5/foufP6Pk3ev4On/+j9w/o/Qd6/4Le/6D3T/D9V67Y/ZsV\nQBq+s+8f0ftP+P41axXguP9NWgDuu/Cdfv+N3r/D9/9TAID+A7T/Ae2/gPs/0P4TtP8F7r9J3AIO\n9P+g/Udw/9Oygbf7r9D+L7j/DO1/Q/vv4P4/tP8Q7n9E+y/h/k+0/xTuf4X7b+H+X7T/+BPuf3aM\n8OHDhw8fPnz4w/4vzcvgeY10sY0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTctMDQtMTNUMTc6MjU6\nNDUtMDQ6MDCJ1tNgAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE3LTA0LTEzVDE3OjI1OjQ1LTA0OjAw\n+Itr3AAAAABJRU5ErkJggg==\n",
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///9yEhLpgJFNv8Tq\nQYT7AAAAAWJLR0QAiAUdSAAAAAd0SU1FB+EKGA0jE/weoLoAAALKSURBVGje7dpLcqQwDAbgHHE2\nYeEj+D4cwQucBUfo+3CEXoSp8OhuhF70T4qpKXmdr21LogK2Pj7A8QmNP+HDhw8fPnz48Kf6VH9G\n+66vy+je8k19jnf8C5dXIPv86ms56lPdjvaYbyodx3ze+XLE76cXFiD4zPji99z0/AJ4n1lfvJ6f\nnl0A6x+578efMSg1wPr172/jPO5yFXM+Ef78gdblM+WPHyguP//t1/g6pA0wfln+ho/fwgYYn19C\n/xwDvwHGc9OvC+hs37DTrwuwfWanXxdQTC9Mvyygs3wjTL8uwPJpn/tNDbSGz7T0SBEWw4vLXzbQ\n6b6RoveIoO6TvPxlA63qs7z8ZQPF9F+SH22vbX8OQKf5Rtv+EgDNJ3X58wZaxWd1+fMGiuFvir8b\nvjp8J/tGy/6jAmRvhW8fwL3vVT+o3grfPoB7r/IpALI3tz8FoJN84/NV873hB8UnM3xzANtf8nb4\ndwmg3grfFEDJO8JPE0i9Ff4pAYL3pI8mkHor/HMCeO9JH00g9SafEsh7T/ppARBvp48UwJnelT5S\nACd7O31TAlnvKx9SQCd7B58KgPO+8iMFuPWe9E8F8BveWX7bAjzX9y4//Jve+fhsH6Ctv7n8PTzj\nvY/v9gEOHz58+PBX+6v/f/wPvnd54f3j6venE/yl769Xv7+j3x/o98/V32/o9+fl389Xnx+g5x/o\n+Qt6/oOeP6HnX+j5G3z+h54/ouefV5/foufP6Pk3ev4On/+j9w/o/Qd6/4Le/6D3T/D9V67Y/ZsV\nQBq+s+8f0ftP+P41axXguP9NWgDuu/Cdfv+N3r/D9/9TAID+A7T/Ae2/gPs/0P4TtP8F7r9J3AIO\n9P+g/Udw/9Oygbf7r9D+L7j/DO1/Q/vv4P4/tP8Q7n9E+y/h/k+0/xTuf4X7b+H+X7T/+BPuf3aM\n8OHDhw8fPnz4w/4vzcvgeY10sY0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTctMTAtMjRUMTM6MzU6\nMTktMDU6MDCdcfAWAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE3LTEwLTI0VDEzOjM1OjE5LTA1OjAw\n7CxIqgAAAABJRU5ErkJggg==\n",
|
||||
"text/plain": [
|
||||
"<IPython.core.display.Image object>"
|
||||
]
|
||||
|
|
@ -368,7 +363,7 @@
|
|||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
|
@ -380,7 +375,7 @@
|
|||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
|
@ -457,7 +452,7 @@
|
|||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
|
@ -472,7 +467,7 @@
|
|||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
|
@ -522,10 +517,25 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 21,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"/home/romano/openmc/openmc/mixin.py:61: IDWarning: Another EnergyFilter instance already exists with id=1.\n",
|
||||
" warn(msg, IDWarning)\n",
|
||||
"/home/romano/openmc/openmc/mixin.py:61: IDWarning: Another MeshFilter instance already exists with id=5.\n",
|
||||
" warn(msg, IDWarning)\n",
|
||||
"/home/romano/openmc/openmc/mixin.py:61: IDWarning: Another EnergyFilter instance already exists with id=6.\n",
|
||||
" warn(msg, IDWarning)\n",
|
||||
"/home/romano/openmc/openmc/mixin.py:61: IDWarning: Another CellFilter instance already exists with id=3.\n",
|
||||
" warn(msg, IDWarning)\n",
|
||||
"/home/romano/openmc/openmc/mixin.py:61: IDWarning: Another CellFilter instance already exists with id=2.\n",
|
||||
" warn(msg, IDWarning)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Export to \"tallies.xml\"\n",
|
||||
"tallies_file.export_to_xml()"
|
||||
|
|
@ -542,7 +552,6 @@
|
|||
"cell_type": "code",
|
||||
"execution_count": 22,
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [
|
||||
|
|
@ -578,25 +587,24 @@
|
|||
" | The OpenMC Monte Carlo Code\n",
|
||||
" Copyright | 2011-2017 Massachusetts Institute of Technology\n",
|
||||
" License | http://openmc.readthedocs.io/en/latest/license.html\n",
|
||||
" Version | 0.8.0\n",
|
||||
" Git SHA1 | bc4683be1c853fe6d0e31bccad416ef219e3efaf\n",
|
||||
" Date/Time | 2017-04-13 17:26:05\n",
|
||||
" MPI Processes | 1\n",
|
||||
" OpenMP Threads | 1\n",
|
||||
" Version | 0.9.0\n",
|
||||
" Git SHA1 | 5ca1d06b0c6ac3b56060ef289b7e5215210e7332\n",
|
||||
" Date/Time | 2017-10-24 13:35:19\n",
|
||||
" OpenMP Threads | 4\n",
|
||||
"\n",
|
||||
" Reading settings XML file...\n",
|
||||
" Reading geometry XML file...\n",
|
||||
" Reading materials XML file...\n",
|
||||
" Reading cross sections XML file...\n",
|
||||
" Reading U235 from /home/smharper/openmc/data/nndc_hdf5/U235.h5\n",
|
||||
" Reading U238 from /home/smharper/openmc/data/nndc_hdf5/U238.h5\n",
|
||||
" Reading O16 from /home/smharper/openmc/data/nndc_hdf5/O16.h5\n",
|
||||
" Reading H1 from /home/smharper/openmc/data/nndc_hdf5/H1.h5\n",
|
||||
" Reading B10 from /home/smharper/openmc/data/nndc_hdf5/B10.h5\n",
|
||||
" Reading Zr90 from /home/smharper/openmc/data/nndc_hdf5/Zr90.h5\n",
|
||||
" Reading geometry XML file...\n",
|
||||
" Building neighboring cells lists for each surface...\n",
|
||||
" Reading U235 from /home/romano/openmc/scripts/nndc_hdf5/U235.h5\n",
|
||||
" Reading U238 from /home/romano/openmc/scripts/nndc_hdf5/U238.h5\n",
|
||||
" Reading O16 from /home/romano/openmc/scripts/nndc_hdf5/O16.h5\n",
|
||||
" Reading H1 from /home/romano/openmc/scripts/nndc_hdf5/H1.h5\n",
|
||||
" Reading B10 from /home/romano/openmc/scripts/nndc_hdf5/B10.h5\n",
|
||||
" Reading Zr90 from /home/romano/openmc/scripts/nndc_hdf5/Zr90.h5\n",
|
||||
" Maximum neutron transport energy: 2.00000E+07 eV for U235\n",
|
||||
" Reading tallies XML file...\n",
|
||||
" Building neighboring cells lists for each surface...\n",
|
||||
" Initializing source particles...\n",
|
||||
"\n",
|
||||
" ====================> K EIGENVALUE SIMULATION <====================\n",
|
||||
|
|
@ -627,20 +635,20 @@
|
|||
"\n",
|
||||
" =======================> TIMING STATISTICS <=======================\n",
|
||||
"\n",
|
||||
" Total time for initialization = 2.2576E-01 seconds\n",
|
||||
" Reading cross sections = 1.8005E-01 seconds\n",
|
||||
" Total time in simulation = 9.6105E+00 seconds\n",
|
||||
" Time in transport only = 9.5952E+00 seconds\n",
|
||||
" Time in inactive batches = 1.4678E+00 seconds\n",
|
||||
" Time in active batches = 8.1427E+00 seconds\n",
|
||||
" Time synchronizing fission bank = 2.6325E-03 seconds\n",
|
||||
" Sampling source sites = 1.5038E-03 seconds\n",
|
||||
" SEND/RECV source sites = 8.8069E-04 seconds\n",
|
||||
" Time accumulating tallies = 2.0568E-04 seconds\n",
|
||||
" Total time for finalization = 1.5435E-03 seconds\n",
|
||||
" Total time elapsed = 9.8506E+00 seconds\n",
|
||||
" Calculation Rate (inactive) = 8516.30 neutrons/second\n",
|
||||
" Calculation Rate (active) = 4605.35 neutrons/second\n",
|
||||
" Total time for initialization = 4.1497E-01 seconds\n",
|
||||
" Reading cross sections = 3.6232E-01 seconds\n",
|
||||
" Total time in simulation = 3.6447E+00 seconds\n",
|
||||
" Time in transport only = 3.5939E+00 seconds\n",
|
||||
" Time in inactive batches = 4.4241E-01 seconds\n",
|
||||
" Time in active batches = 3.2022E+00 seconds\n",
|
||||
" Time synchronizing fission bank = 2.7734E-03 seconds\n",
|
||||
" Sampling source sites = 1.1981E-03 seconds\n",
|
||||
" SEND/RECV source sites = 1.5506E-03 seconds\n",
|
||||
" Time accumulating tallies = 1.2237E-04 seconds\n",
|
||||
" Total time for finalization = 1.4924E-03 seconds\n",
|
||||
" Total time elapsed = 4.0823E+00 seconds\n",
|
||||
" Calculation Rate (inactive) = 28254.0 neutrons/second\n",
|
||||
" Calculation Rate (active) = 11710.5 neutrons/second\n",
|
||||
"\n",
|
||||
" ============================> RESULTS <============================\n",
|
||||
"\n",
|
||||
|
|
@ -689,7 +697,7 @@
|
|||
"cell_type": "code",
|
||||
"execution_count": 23,
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"collapsed": true,
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -710,14 +718,25 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 24,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style>\n",
|
||||
" .dataframe thead tr:only-child th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: left;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
|
|
@ -777,14 +796,25 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 25,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style>\n",
|
||||
" .dataframe thead tr:only-child th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: left;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
|
|
@ -803,7 +833,7 @@
|
|||
" <td>0.0</td>\n",
|
||||
" <td>0.625</td>\n",
|
||||
" <td>total</td>\n",
|
||||
" <td>(absorption + current)</td>\n",
|
||||
" <td>((absorption + current) / (absorption + current))</td>\n",
|
||||
" <td>0.694368</td>\n",
|
||||
" <td>0.004606</td>\n",
|
||||
" </tr>\n",
|
||||
|
|
@ -812,11 +842,11 @@
|
|||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" energy low [eV] energy high [eV] nuclide score mean \\\n",
|
||||
"0 0.00e+00 6.25e-01 total (absorption + current) 6.94e-01 \n",
|
||||
" energy low [eV] energy high [eV] nuclide \\\n",
|
||||
"0 0.00e+00 6.25e-01 total \n",
|
||||
"\n",
|
||||
" std. dev. \n",
|
||||
"0 4.61e-03 "
|
||||
" score mean std. dev. \n",
|
||||
"0 ((absorption + current) / (absorption + current)) 6.94e-01 4.61e-03 "
|
||||
]
|
||||
},
|
||||
"execution_count": 25,
|
||||
|
|
@ -845,14 +875,25 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 26,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style>\n",
|
||||
" .dataframe thead tr:only-child th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: left;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
|
|
@ -871,7 +912,7 @@
|
|||
" <td>0.0</td>\n",
|
||||
" <td>0.625</td>\n",
|
||||
" <td>total</td>\n",
|
||||
" <td>nu-fission</td>\n",
|
||||
" <td>(nu-fission / nu-fission)</td>\n",
|
||||
" <td>1.203099</td>\n",
|
||||
" <td>0.009615</td>\n",
|
||||
" </tr>\n",
|
||||
|
|
@ -880,8 +921,11 @@
|
|||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" energy low [eV] energy high [eV] nuclide score mean std. dev.\n",
|
||||
"0 0.00e+00 6.25e-01 total nu-fission 1.20e+00 9.61e-03"
|
||||
" energy low [eV] energy high [eV] nuclide score \\\n",
|
||||
"0 0.00e+00 6.25e-01 total (nu-fission / nu-fission) \n",
|
||||
"\n",
|
||||
" mean std. dev. \n",
|
||||
"0 1.20e+00 9.61e-03 "
|
||||
]
|
||||
},
|
||||
"execution_count": 26,
|
||||
|
|
@ -908,14 +952,25 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 27,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style>\n",
|
||||
" .dataframe thead tr:only-child th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: left;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
|
|
@ -934,9 +989,9 @@
|
|||
" <th>0</th>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>0.625</td>\n",
|
||||
" <td>10000</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>total</td>\n",
|
||||
" <td>absorption</td>\n",
|
||||
" <td>(absorption / absorption)</td>\n",
|
||||
" <td>0.749423</td>\n",
|
||||
" <td>0.006089</td>\n",
|
||||
" </tr>\n",
|
||||
|
|
@ -945,11 +1000,11 @@
|
|||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" energy low [eV] energy high [eV] cell nuclide score mean \\\n",
|
||||
"0 0.00e+00 6.25e-01 10000 total absorption 7.49e-01 \n",
|
||||
" energy low [eV] energy high [eV] cell nuclide score \\\n",
|
||||
"0 0.00e+00 6.25e-01 1 total (absorption / absorption) \n",
|
||||
"\n",
|
||||
" std. dev. \n",
|
||||
"0 6.09e-03 "
|
||||
" mean std. dev. \n",
|
||||
"0 7.49e-01 6.09e-03 "
|
||||
]
|
||||
},
|
||||
"execution_count": 27,
|
||||
|
|
@ -974,14 +1029,25 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 28,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style>\n",
|
||||
" .dataframe thead tr:only-child th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: left;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
|
|
@ -1000,7 +1066,7 @@
|
|||
" <th>0</th>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>0.625</td>\n",
|
||||
" <td>10000</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>total</td>\n",
|
||||
" <td>(nu-fission / absorption)</td>\n",
|
||||
" <td>1.663727</td>\n",
|
||||
|
|
@ -1011,11 +1077,11 @@
|
|||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" energy low [eV] energy high [eV] cell nuclide \\\n",
|
||||
"0 0.00e+00 6.25e-01 10000 total \n",
|
||||
" energy low [eV] energy high [eV] cell nuclide score \\\n",
|
||||
"0 0.00e+00 6.25e-01 1 total (nu-fission / absorption) \n",
|
||||
"\n",
|
||||
" score mean std. dev. \n",
|
||||
"0 (nu-fission / absorption) 1.66e+00 1.44e-02 "
|
||||
" mean std. dev. \n",
|
||||
"0 1.66e+00 1.44e-02 "
|
||||
]
|
||||
},
|
||||
"execution_count": 28,
|
||||
|
|
@ -1039,14 +1105,25 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 29,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style>\n",
|
||||
" .dataframe thead tr:only-child th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: left;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
|
|
@ -1065,7 +1142,7 @@
|
|||
" <td>0.0</td>\n",
|
||||
" <td>0.625</td>\n",
|
||||
" <td>total</td>\n",
|
||||
" <td>(absorption + current)</td>\n",
|
||||
" <td>((absorption + current) / (absorption + current))</td>\n",
|
||||
" <td>0.984668</td>\n",
|
||||
" <td>0.005509</td>\n",
|
||||
" </tr>\n",
|
||||
|
|
@ -1074,11 +1151,11 @@
|
|||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" energy low [eV] energy high [eV] nuclide score mean \\\n",
|
||||
"0 0.00e+00 6.25e-01 total (absorption + current) 9.85e-01 \n",
|
||||
" energy low [eV] energy high [eV] nuclide \\\n",
|
||||
"0 0.00e+00 6.25e-01 total \n",
|
||||
"\n",
|
||||
" std. dev. \n",
|
||||
"0 5.51e-03 "
|
||||
" score mean std. dev. \n",
|
||||
"0 ((absorption + current) / (absorption + current)) 9.85e-01 5.51e-03 "
|
||||
]
|
||||
},
|
||||
"execution_count": 29,
|
||||
|
|
@ -1101,14 +1178,25 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 30,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style>\n",
|
||||
" .dataframe thead tr:only-child th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: left;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
|
|
@ -1163,14 +1251,25 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 31,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style>\n",
|
||||
" .dataframe thead tr:only-child th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: left;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
|
|
@ -1189,9 +1288,9 @@
|
|||
" <th>0</th>\n",
|
||||
" <td>0.0</td>\n",
|
||||
" <td>0.625</td>\n",
|
||||
" <td>10000</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>total</td>\n",
|
||||
" <td>((((((absorption + current) * nu-fission) * ab...</td>\n",
|
||||
" <td>(((((((absorption + current) / (absorption + c...</td>\n",
|
||||
" <td>1.023002</td>\n",
|
||||
" <td>0.018791</td>\n",
|
||||
" </tr>\n",
|
||||
|
|
@ -1200,11 +1299,11 @@
|
|||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" energy low [eV] energy high [eV] cell nuclide \\\n",
|
||||
"0 0.00e+00 6.25e-01 10000 total \n",
|
||||
" energy low [eV] energy high [eV] cell nuclide \\\n",
|
||||
"0 0.00e+00 6.25e-01 1 total \n",
|
||||
"\n",
|
||||
" score mean std. dev. \n",
|
||||
"0 ((((((absorption + current) * nu-fission) * ab... 1.02e+00 1.88e-02 "
|
||||
"0 (((((((absorption + current) / (absorption + c... 1.02e+00 1.88e-02 "
|
||||
]
|
||||
},
|
||||
"execution_count": 31,
|
||||
|
|
@ -1230,7 +1329,7 @@
|
|||
"cell_type": "code",
|
||||
"execution_count": 32,
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"collapsed": true,
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -1245,14 +1344,25 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 33,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style>\n",
|
||||
" .dataframe thead tr:only-child th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: left;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
|
|
@ -1269,7 +1379,7 @@
|
|||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>0</th>\n",
|
||||
" <td>10000</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>0.000</td>\n",
|
||||
" <td>6.250000e-01</td>\n",
|
||||
" <td>(U238 / total)</td>\n",
|
||||
|
|
@ -1279,7 +1389,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>1</th>\n",
|
||||
" <td>10000</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>0.000</td>\n",
|
||||
" <td>6.250000e-01</td>\n",
|
||||
" <td>(U238 / total)</td>\n",
|
||||
|
|
@ -1289,7 +1399,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2</th>\n",
|
||||
" <td>10000</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>0.000</td>\n",
|
||||
" <td>6.250000e-01</td>\n",
|
||||
" <td>(U235 / total)</td>\n",
|
||||
|
|
@ -1299,7 +1409,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>3</th>\n",
|
||||
" <td>10000</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>0.000</td>\n",
|
||||
" <td>6.250000e-01</td>\n",
|
||||
" <td>(U235 / total)</td>\n",
|
||||
|
|
@ -1309,7 +1419,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>4</th>\n",
|
||||
" <td>10000</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>0.625</td>\n",
|
||||
" <td>2.000000e+07</td>\n",
|
||||
" <td>(U238 / total)</td>\n",
|
||||
|
|
@ -1319,7 +1429,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>5</th>\n",
|
||||
" <td>10000</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>0.625</td>\n",
|
||||
" <td>2.000000e+07</td>\n",
|
||||
" <td>(U238 / total)</td>\n",
|
||||
|
|
@ -1329,7 +1439,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>6</th>\n",
|
||||
" <td>10000</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>0.625</td>\n",
|
||||
" <td>2.000000e+07</td>\n",
|
||||
" <td>(U235 / total)</td>\n",
|
||||
|
|
@ -1339,7 +1449,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>7</th>\n",
|
||||
" <td>10000</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>0.625</td>\n",
|
||||
" <td>2.000000e+07</td>\n",
|
||||
" <td>(U235 / total)</td>\n",
|
||||
|
|
@ -1352,15 +1462,15 @@
|
|||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" cell energy low [eV] energy high [eV] nuclide \\\n",
|
||||
"0 10000 0.00e+00 6.25e-01 (U238 / total) \n",
|
||||
"1 10000 0.00e+00 6.25e-01 (U238 / total) \n",
|
||||
"2 10000 0.00e+00 6.25e-01 (U235 / total) \n",
|
||||
"3 10000 0.00e+00 6.25e-01 (U235 / total) \n",
|
||||
"4 10000 6.25e-01 2.00e+07 (U238 / total) \n",
|
||||
"5 10000 6.25e-01 2.00e+07 (U238 / total) \n",
|
||||
"6 10000 6.25e-01 2.00e+07 (U235 / total) \n",
|
||||
"7 10000 6.25e-01 2.00e+07 (U235 / total) \n",
|
||||
" cell energy low [eV] energy high [eV] nuclide \\\n",
|
||||
"0 1 0.00e+00 6.25e-01 (U238 / total) \n",
|
||||
"1 1 0.00e+00 6.25e-01 (U238 / total) \n",
|
||||
"2 1 0.00e+00 6.25e-01 (U235 / total) \n",
|
||||
"3 1 0.00e+00 6.25e-01 (U235 / total) \n",
|
||||
"4 1 6.25e-01 2.00e+07 (U238 / total) \n",
|
||||
"5 1 6.25e-01 2.00e+07 (U238 / total) \n",
|
||||
"6 1 6.25e-01 2.00e+07 (U235 / total) \n",
|
||||
"7 1 6.25e-01 2.00e+07 (U235 / total) \n",
|
||||
"\n",
|
||||
" score mean std. dev. \n",
|
||||
"0 (nu-fission / flux) 6.66e-07 5.63e-09 \n",
|
||||
|
|
@ -1393,9 +1503,7 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 34,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
|
|
@ -1425,9 +1533,7 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 35,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
|
|
@ -1449,9 +1555,7 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 36,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
|
|
@ -1480,14 +1584,25 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 37,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style>\n",
|
||||
" .dataframe thead tr:only-child th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: left;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
|
|
@ -1504,7 +1619,7 @@
|
|||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>0</th>\n",
|
||||
" <td>10000</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>0.000</td>\n",
|
||||
" <td>6.250000e-01</td>\n",
|
||||
" <td>U238</td>\n",
|
||||
|
|
@ -1514,7 +1629,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>1</th>\n",
|
||||
" <td>10000</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>0.000</td>\n",
|
||||
" <td>6.250000e-01</td>\n",
|
||||
" <td>U235</td>\n",
|
||||
|
|
@ -1524,7 +1639,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2</th>\n",
|
||||
" <td>10000</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>0.625</td>\n",
|
||||
" <td>2.000000e+07</td>\n",
|
||||
" <td>U238</td>\n",
|
||||
|
|
@ -1534,7 +1649,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>3</th>\n",
|
||||
" <td>10000</td>\n",
|
||||
" <td>1</td>\n",
|
||||
" <td>0.625</td>\n",
|
||||
" <td>2.000000e+07</td>\n",
|
||||
" <td>U235</td>\n",
|
||||
|
|
@ -1547,11 +1662,11 @@
|
|||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" cell energy low [eV] energy high [eV] nuclide score mean \\\n",
|
||||
"0 10000 0.00e+00 6.25e-01 U238 nu-fission 1.60e-06 \n",
|
||||
"1 10000 0.00e+00 6.25e-01 U235 nu-fission 8.55e-01 \n",
|
||||
"2 10000 6.25e-01 2.00e+07 U238 nu-fission 8.30e-02 \n",
|
||||
"3 10000 6.25e-01 2.00e+07 U235 nu-fission 9.06e-02 \n",
|
||||
" cell energy low [eV] energy high [eV] nuclide score mean \\\n",
|
||||
"0 1 0.00e+00 6.25e-01 U238 nu-fission 1.60e-06 \n",
|
||||
"1 1 0.00e+00 6.25e-01 U235 nu-fission 8.55e-01 \n",
|
||||
"2 1 6.25e-01 2.00e+07 U238 nu-fission 8.30e-02 \n",
|
||||
"3 1 6.25e-01 2.00e+07 U235 nu-fission 9.06e-02 \n",
|
||||
"\n",
|
||||
" std. dev. \n",
|
||||
"0 9.68e-09 \n",
|
||||
|
|
@ -1574,14 +1689,25 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 38,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<style>\n",
|
||||
" .dataframe thead tr:only-child th {\n",
|
||||
" text-align: right;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe thead th {\n",
|
||||
" text-align: left;\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" .dataframe tbody tr th {\n",
|
||||
" vertical-align: top;\n",
|
||||
" }\n",
|
||||
"</style>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
|
|
@ -1598,7 +1724,7 @@
|
|||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>0</th>\n",
|
||||
" <td>10002</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" <td>1.000000e-02</td>\n",
|
||||
" <td>1.080060e-01</td>\n",
|
||||
" <td>H1</td>\n",
|
||||
|
|
@ -1608,7 +1734,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>1</th>\n",
|
||||
" <td>10002</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" <td>1.080060e-01</td>\n",
|
||||
" <td>1.166529e+00</td>\n",
|
||||
" <td>H1</td>\n",
|
||||
|
|
@ -1618,7 +1744,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>2</th>\n",
|
||||
" <td>10002</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" <td>1.166529e+00</td>\n",
|
||||
" <td>1.259921e+01</td>\n",
|
||||
" <td>H1</td>\n",
|
||||
|
|
@ -1628,7 +1754,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>3</th>\n",
|
||||
" <td>10002</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" <td>1.259921e+01</td>\n",
|
||||
" <td>1.360790e+02</td>\n",
|
||||
" <td>H1</td>\n",
|
||||
|
|
@ -1638,7 +1764,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>4</th>\n",
|
||||
" <td>10002</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" <td>1.360790e+02</td>\n",
|
||||
" <td>1.469734e+03</td>\n",
|
||||
" <td>H1</td>\n",
|
||||
|
|
@ -1648,7 +1774,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>5</th>\n",
|
||||
" <td>10002</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" <td>1.469734e+03</td>\n",
|
||||
" <td>1.587401e+04</td>\n",
|
||||
" <td>H1</td>\n",
|
||||
|
|
@ -1658,7 +1784,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>6</th>\n",
|
||||
" <td>10002</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" <td>1.587401e+04</td>\n",
|
||||
" <td>1.714488e+05</td>\n",
|
||||
" <td>H1</td>\n",
|
||||
|
|
@ -1668,7 +1794,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>7</th>\n",
|
||||
" <td>10002</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" <td>1.714488e+05</td>\n",
|
||||
" <td>1.851749e+06</td>\n",
|
||||
" <td>H1</td>\n",
|
||||
|
|
@ -1678,7 +1804,7 @@
|
|||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>8</th>\n",
|
||||
" <td>10002</td>\n",
|
||||
" <td>3</td>\n",
|
||||
" <td>1.851749e+06</td>\n",
|
||||
" <td>2.000000e+07</td>\n",
|
||||
" <td>H1</td>\n",
|
||||
|
|
@ -1691,16 +1817,16 @@
|
|||
"</div>"
|
||||
],
|
||||
"text/plain": [
|
||||
" cell energy low [eV] energy high [eV] nuclide score mean \\\n",
|
||||
"0 10002 1.00e-02 1.08e-01 H1 scatter 4.54e+00 \n",
|
||||
"1 10002 1.08e-01 1.17e+00 H1 scatter 2.00e+00 \n",
|
||||
"2 10002 1.17e+00 1.26e+01 H1 scatter 1.64e+00 \n",
|
||||
"3 10002 1.26e+01 1.36e+02 H1 scatter 1.82e+00 \n",
|
||||
"4 10002 1.36e+02 1.47e+03 H1 scatter 2.03e+00 \n",
|
||||
"5 10002 1.47e+03 1.59e+04 H1 scatter 2.12e+00 \n",
|
||||
"6 10002 1.59e+04 1.71e+05 H1 scatter 2.18e+00 \n",
|
||||
"7 10002 1.71e+05 1.85e+06 H1 scatter 2.01e+00 \n",
|
||||
"8 10002 1.85e+06 2.00e+07 H1 scatter 3.73e-01 \n",
|
||||
" cell energy low [eV] energy high [eV] nuclide score mean \\\n",
|
||||
"0 3 1.00e-02 1.08e-01 H1 scatter 4.54e+00 \n",
|
||||
"1 3 1.08e-01 1.17e+00 H1 scatter 2.00e+00 \n",
|
||||
"2 3 1.17e+00 1.26e+01 H1 scatter 1.64e+00 \n",
|
||||
"3 3 1.26e+01 1.36e+02 H1 scatter 1.82e+00 \n",
|
||||
"4 3 1.36e+02 1.47e+03 H1 scatter 2.03e+00 \n",
|
||||
"5 3 1.47e+03 1.59e+04 H1 scatter 2.12e+00 \n",
|
||||
"6 3 1.59e+04 1.71e+05 H1 scatter 2.18e+00 \n",
|
||||
"7 3 1.71e+05 1.85e+06 H1 scatter 2.01e+00 \n",
|
||||
"8 3 1.85e+06 2.00e+07 H1 scatter 3.73e-01 \n",
|
||||
"\n",
|
||||
" std. dev. \n",
|
||||
"0 2.52e-02 \n",
|
||||
|
|
@ -1744,9 +1870,9 @@
|
|||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.2"
|
||||
"version": "3.6.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
"nbformat_minor": 1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ settings_file.export_to_xml()
|
|||
###############################################################################
|
||||
|
||||
# Instantiate a tally mesh
|
||||
mesh = openmc.Mesh(mesh_id=1)
|
||||
mesh = openmc.Mesh()
|
||||
mesh.type = 'regular'
|
||||
mesh.dimension = [100, 100, 1]
|
||||
mesh.lower_left = [-0.62992, -0.62992, -1.e50]
|
||||
|
|
|
|||
|
|
@ -1,21 +1,30 @@
|
|||
<?xml version="1.0"?>
|
||||
<tallies>
|
||||
|
||||
<filter id="1" type="cell">
|
||||
<bins>100</bins>
|
||||
</filter>
|
||||
|
||||
<filter id="2" type="energy">
|
||||
<bins>0 20.0e6</bins>
|
||||
</filter>
|
||||
|
||||
<filter id="3" type="energyout">
|
||||
<bins>0 20.0e6</bins>
|
||||
</filter>
|
||||
|
||||
<tally id="1">
|
||||
<filter type="cell" bins="100" />
|
||||
<filters>1</filters>
|
||||
<scores>total scatter nu-scatter absorption fission nu-fission</scores>
|
||||
</tally>
|
||||
|
||||
<tally id="2">
|
||||
<filter type="cell" bins="100" />
|
||||
<filter type="energy" bins="0 20.0e6" />
|
||||
<filters>1 2</filters>
|
||||
<scores>total scatter nu-scatter absorption fission nu-fission</scores>
|
||||
</tally>
|
||||
|
||||
<tally id="3">
|
||||
<filter type="cell" bins="100" />
|
||||
<filter type="energy" bins="0 20.0e6" />
|
||||
<filter type="energyout" bins="0 20.0e6" />
|
||||
<filters>1 2 3</filters>
|
||||
<scores>scatter nu-scatter nu-fission</scores>
|
||||
</tally>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,12 @@
|
|||
<width>1.0 1.0</width>
|
||||
</mesh>
|
||||
|
||||
<filter id="1" type="mesh">
|
||||
<bins>1</bins>
|
||||
</filter>
|
||||
|
||||
<tally id="1">
|
||||
<filter type="mesh" bins="1" />
|
||||
<filters>1</filters>
|
||||
<scores>total</scores>
|
||||
</tally>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,12 @@
|
|||
<width>1.0 1.0</width>
|
||||
</mesh>
|
||||
|
||||
<filter id="1" type="mesh">
|
||||
<bins>1</bins>
|
||||
</filter>
|
||||
|
||||
<tally id="1">
|
||||
<filter type="mesh" bins="1" />
|
||||
<filters>1</filters>
|
||||
<scores>total</scores>
|
||||
</tally>
|
||||
|
||||
|
|
|
|||
|
|
@ -22,10 +22,11 @@
|
|||
<!-- To assess convergence of the source distribution, we need to define the
|
||||
bounds for a mesh over which the Shannon entropy should be
|
||||
calculated. The extent in the z direction is made arbitrarily large. -->
|
||||
<entropy>
|
||||
<mesh id="1">
|
||||
<lower_left>-0.39218 -0.39218 -1.e50</lower_left>
|
||||
<upper_right>0.39218 0.39218 1.e50</upper_right>
|
||||
<dimension>10 10 1</dimension>
|
||||
</entropy>
|
||||
</mesh>
|
||||
<entropy_mesh>1</entropy_mesh>
|
||||
|
||||
</settings>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,22 @@
|
|||
<?xml version="1.0"?>
|
||||
<tallies>
|
||||
|
||||
<mesh id="1" type="regular">
|
||||
<mesh id="2" type="regular">
|
||||
<dimension>100 100 1</dimension>
|
||||
<lower_left>-0.62992 -0.62992 -1.e50</lower_left>
|
||||
<upper_right>0.62992 0.62992 1.e50</upper_right>
|
||||
</mesh>
|
||||
|
||||
<filter id="1" type="mesh">
|
||||
<bins>1</bins>
|
||||
</filter>
|
||||
|
||||
<filter id="2" type="energy">
|
||||
<bins>0. 4. 20.0e6</bins>
|
||||
</filter>
|
||||
|
||||
<tally id="1">
|
||||
<filter type="mesh" bins="1" />
|
||||
<filter type="energy" bins="0. 4. 20.0e6" />
|
||||
<filters>1 2</filters>
|
||||
<scores>flux fission nu-fission</scores>
|
||||
</tally>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,14 @@
|
|||
<lower_left>-0.63 -0.63 -1e+50</lower_left>
|
||||
<upper_right>0.63 0.63 1e+50</upper_right>
|
||||
</mesh>
|
||||
<filter id="1" type="energy">
|
||||
<bins>1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0</bins>
|
||||
</filter>
|
||||
<filter id="2" type="mesh">
|
||||
<bins>1</bins>
|
||||
</filter>
|
||||
<tally id="1" name="tally 1">
|
||||
<filter bins="1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0" type="energy" />
|
||||
<filter bins="1" type="mesh" />
|
||||
<filters>1 2</filters>
|
||||
<scores>flux fission nu-fission</scores>
|
||||
</tally>
|
||||
</tallies>
|
||||
|
|
|
|||
|
|
@ -27,6 +27,5 @@ from openmc.particle_restart import *
|
|||
from openmc.mixin import *
|
||||
from openmc.plotter import *
|
||||
from openmc.search import *
|
||||
from openmc.capi import *
|
||||
|
||||
__version__ = '0.9.0'
|
||||
|
|
|
|||
|
|
@ -108,9 +108,9 @@ class CrossNuclide(object):
|
|||
|
||||
Parameters
|
||||
----------
|
||||
left_nuclide : Nuclide or CrossNuclide
|
||||
left_nuclide : openmc.Nuclide or CrossNuclide
|
||||
The left nuclide in the outer product
|
||||
right_nuclide : Nuclide or CrossNuclide
|
||||
right_nuclide : openmc.Nuclide or CrossNuclide
|
||||
The right nuclide in the outer product
|
||||
binary_op : str
|
||||
The tally arithmetic binary operator (e.g., '+', '-', etc.) used to
|
||||
|
|
@ -118,9 +118,9 @@ class CrossNuclide(object):
|
|||
|
||||
Attributes
|
||||
----------
|
||||
left_nuclide : Nuclide or CrossNuclide
|
||||
left_nuclide : openmc.Nuclide or CrossNuclide
|
||||
The left nuclide in the outer product
|
||||
right_nuclide : Nuclide or CrossNuclide
|
||||
right_nuclide : openmc.Nuclide or CrossNuclide
|
||||
The right nuclide in the outer product
|
||||
binary_op : str
|
||||
The tally arithmetic binary operator (e.g., '+', '-', etc.) used to
|
||||
|
|
@ -510,7 +510,7 @@ class AggregateNuclide(object):
|
|||
|
||||
Parameters
|
||||
----------
|
||||
nuclides : Iterable of str or Nuclide or CrossNuclide
|
||||
nuclides : Iterable of str or openmc.Nuclide or CrossNuclide
|
||||
The nuclides included in the aggregation
|
||||
aggregate_op : str
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
|
|
@ -518,7 +518,7 @@ class AggregateNuclide(object):
|
|||
|
||||
Attributes
|
||||
----------
|
||||
nuclides : Iterable of str or Nuclide or CrossNuclide
|
||||
nuclides : Iterable of str or openmc.Nuclide or CrossNuclide
|
||||
The nuclides included in the aggregation
|
||||
aggregate_op : str
|
||||
The tally aggregation operator (e.g., 'sum', 'avg', etc.) used
|
||||
|
|
|
|||
304
openmc/capi.py
304
openmc/capi.py
|
|
@ -1,304 +0,0 @@
|
|||
from contextlib import contextmanager
|
||||
from ctypes import CDLL, c_int, c_int32, c_double, c_char_p, POINTER
|
||||
import sys
|
||||
from warnings import warn
|
||||
|
||||
import numpy as np
|
||||
from numpy.ctypeslib import as_array
|
||||
|
||||
import pkg_resources
|
||||
|
||||
__all__ = ['OpenMCLibrary', 'lib', 'lib_context']
|
||||
|
||||
_int3 = c_int*3
|
||||
_double3 = c_double*3
|
||||
_double_array = POINTER(POINTER(c_double))
|
||||
|
||||
|
||||
class OpenMCLibrary(object):
|
||||
"""Provides bindings to C functions defined by OpenMC shared library.
|
||||
|
||||
This class is normally not directly instantiated. Instead, when the
|
||||
:mod:`openmc` package is imported, an instance is automatically created with
|
||||
the name :data:`openmc.lib`. Calls to the OpenMC can then be made using that
|
||||
instance, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
openmc.lib.init()
|
||||
openmc.lib.run()
|
||||
|
||||
"""
|
||||
def __init__(self, filename):
|
||||
self._dll = CDLL(filename)
|
||||
|
||||
# Set argument/return types
|
||||
self._dll.openmc_calculate_volumes.restype = None
|
||||
self._dll.openmc_cell_set_temperature.argtypes = [
|
||||
c_int32, c_double, c_int32]
|
||||
self._dll.openmc_cell_set_temperature.restype = c_int
|
||||
self._dll.openmc_finalize.restype = None
|
||||
self._dll.openmc_find.argtypes = [
|
||||
POINTER(_double3), c_int, POINTER(c_int32), POINTER(c_int32)]
|
||||
self._dll.openmc_find.restype = None
|
||||
self._dll.openmc_init.argtypes = [POINTER(c_int)]
|
||||
self._dll.openmc_init.restype = None
|
||||
self._dll.openmc_load_nuclide.argtypes = [c_char_p]
|
||||
self._dll.openmc_load_nuclide.restype = c_int
|
||||
self._dll.openmc_material_add_nuclide.argtypes = [
|
||||
c_int32, c_char_p, c_double]
|
||||
self._dll.openmc_material_add_nuclide.restype = c_int
|
||||
self._dll.openmc_material_get_densities.argtypes = [
|
||||
c_int32, _double_array]
|
||||
self._dll.openmc_material_get_densities.restype = c_int
|
||||
self._dll.openmc_material_set_density.argtypes = [c_int32, c_double]
|
||||
self._dll.openmc_material_set_density.restype = c_int
|
||||
self._dll.openmc_plot_geometry.restype = None
|
||||
self._dll.openmc_run.restype = None
|
||||
self._dll.openmc_reset.restype = None
|
||||
self._dll.openmc_tally_results.argtypes = [
|
||||
c_int32, _double_array, POINTER(_int3)]
|
||||
self._dll.openmc_tally_results.restype = None
|
||||
|
||||
def calculate_volumes(self):
|
||||
"""Run stochastic volume calculation"""
|
||||
return self._dll.openmc_calculate_volumes()
|
||||
|
||||
def cell_set_temperature(self, cell_id, T, instance=None):
|
||||
"""Set the temperature of a cell
|
||||
|
||||
Parameters
|
||||
----------
|
||||
cell_id : int
|
||||
ID of the cell
|
||||
T : float
|
||||
Temperature in K
|
||||
instance : int or None
|
||||
Which instance of the cell
|
||||
|
||||
"""
|
||||
if instance is not None:
|
||||
return self._dll.openmc_cell_set_temperature(
|
||||
cell_id, T, instance)
|
||||
else:
|
||||
return self._dll.openmc_cell_set_temperature(cell_id, T, None)
|
||||
|
||||
def finalize(self):
|
||||
"""Finalize simulation and free memory"""
|
||||
return self._dll.openmc_finalize()
|
||||
|
||||
def find(self, xyz, rtype='cell'):
|
||||
"""Find the cell or material at a given point
|
||||
|
||||
Parameters
|
||||
----------
|
||||
xyz : iterable of float
|
||||
Cartesian coordinates of position
|
||||
rtype : {'cell', 'material'}
|
||||
Whether to return the cell or material ID
|
||||
|
||||
Returns
|
||||
-------
|
||||
int or None
|
||||
ID of the cell or material. If 'material' is requested and no
|
||||
material exists at the given coordinate, None is returned.
|
||||
int
|
||||
If the cell at the given point is repeated in the geometry, this
|
||||
indicates which instance it is, i.e., 0 would be the first instance.
|
||||
|
||||
"""
|
||||
# Set second argument to openmc_find
|
||||
if rtype == 'cell':
|
||||
r_int = 1
|
||||
elif rtype == 'material':
|
||||
r_int = 2
|
||||
else:
|
||||
raise ValueError('Unknown return type: {}'.format(rtype))
|
||||
|
||||
# Call openmc_find
|
||||
uid = c_int32()
|
||||
instance = c_int32()
|
||||
self._dll.openmc_find(_double3(*xyz), r_int, uid, instance)
|
||||
return (uid.value if uid != 0 else None), instance.value
|
||||
|
||||
def init(self, intracomm=None):
|
||||
"""Initialize OpenMC
|
||||
|
||||
Parameters
|
||||
----------
|
||||
intracomm : mpi4py.MPI.Intracomm or None
|
||||
MPI intracommunicator
|
||||
|
||||
"""
|
||||
if intracomm is not None:
|
||||
# If an mpi4py communicator was passed, convert it to an integer to
|
||||
# be passed to openmc_init
|
||||
try:
|
||||
intracomm = intracomm.py2f()
|
||||
except AttributeError:
|
||||
pass
|
||||
return self._dll.openmc_init(c_int(intracomm))
|
||||
else:
|
||||
return self._dll.openmc_init(None)
|
||||
|
||||
def load_nuclide(self, name):
|
||||
"""Load cross section data for a nuclide.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Name of nuclide, e.g. 'U235'
|
||||
|
||||
Returns
|
||||
-------
|
||||
int
|
||||
Return status (negative if an error occurs).
|
||||
|
||||
"""
|
||||
return self._dll.openmc_load_nuclide(name.encode())
|
||||
|
||||
def material_add_nuclide(self, mat_id, name, density):
|
||||
"""Add a nuclide to a material.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mat_id : int
|
||||
ID of the material
|
||||
name : str
|
||||
Name of nuclide, e.g. 'U235'
|
||||
density : float
|
||||
Density in atom/b-cm
|
||||
|
||||
Returns
|
||||
-------
|
||||
int
|
||||
Return status (negative if an error occurs).
|
||||
|
||||
"""
|
||||
return self._dll.openmc_material_add_nuclide(
|
||||
mat_id, name.encode(), density)
|
||||
|
||||
def material_get_densities(self, mat_id):
|
||||
"""Get atom densities in a material.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mat_id : int
|
||||
ID of the material
|
||||
|
||||
Returns
|
||||
-------
|
||||
numpy.ndarray
|
||||
Array of densities in atom/b-cm
|
||||
|
||||
"""
|
||||
data = POINTER(c_double)()
|
||||
n = self._dll.openmc_material_get_densities(mat_id, data)
|
||||
if data:
|
||||
return as_array(data, (n,))
|
||||
else:
|
||||
return None
|
||||
|
||||
def material_set_density(self, mat_id, density):
|
||||
"""Set density of a material.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mat_id : int
|
||||
ID of the material
|
||||
density : float
|
||||
Density in atom/b-cm
|
||||
|
||||
Returns
|
||||
-------
|
||||
int
|
||||
Return status (negative if an error occurs).
|
||||
|
||||
"""
|
||||
return self._dll.openmc_material_set_density(mat_id, density)
|
||||
|
||||
def plot_geometry(self):
|
||||
"""Plot geometry"""
|
||||
return self._dll.openmc_plot_geometry()
|
||||
|
||||
def reset(self):
|
||||
"""Reset tallies"""
|
||||
return self._dll.openmc_reset()
|
||||
|
||||
def run(self):
|
||||
"""Run simulation"""
|
||||
return self._dll.openmc_run()
|
||||
|
||||
def tally_results(self, tally_id):
|
||||
"""Get tally results array
|
||||
|
||||
Parameters
|
||||
----------
|
||||
tally_id : int
|
||||
ID of tally
|
||||
|
||||
Returns
|
||||
-------
|
||||
numpy.ndarray
|
||||
Array that exposes the internal tally results array
|
||||
|
||||
"""
|
||||
data = POINTER(c_double)()
|
||||
shape = _int3()
|
||||
self._dll.openmc_tally_results(tally_id, data, shape)
|
||||
if data:
|
||||
return as_array(data, tuple(shape[::-1]))
|
||||
else:
|
||||
return None
|
||||
|
||||
def __getattr__(self, key):
|
||||
# Fall-back for other functions that may be available from library
|
||||
try:
|
||||
return getattr(self._dll, 'openmc_{}'.format(key))
|
||||
except AttributeError:
|
||||
raise AttributeError("OpenMC library doesn't have a '{}' function"
|
||||
.format(key))
|
||||
|
||||
|
||||
@contextmanager
|
||||
def lib_context(intracomm=None):
|
||||
"""Provides context manager for calling OpenMC shared library functions.
|
||||
|
||||
This function is intended to be used in a 'with' statement and ensures that
|
||||
OpenMC is properly initialized/finalized. At the completion of the 'with'
|
||||
block, all memory that was allocated during the block is freed. For
|
||||
example::
|
||||
|
||||
with openmc.lib_context() as lib:
|
||||
for i in range(n_iters):
|
||||
lib.reset()
|
||||
do_stuff()
|
||||
lib.run()
|
||||
|
||||
Parameters
|
||||
----------
|
||||
intracomm : mpi4py.MPI.Intracomm or None
|
||||
MPI intracommunicator
|
||||
|
||||
"""
|
||||
lib.init(comm)
|
||||
yield lib
|
||||
lib.finalize()
|
||||
|
||||
|
||||
# Determine shared-library suffix
|
||||
if sys.platform == 'darwin':
|
||||
suffix = 'dylib'
|
||||
else:
|
||||
suffix = 'so'
|
||||
|
||||
# Open shared library
|
||||
filename = pkg_resources.resource_filename(
|
||||
__name__, '_libopenmc.{}'.format(suffix))
|
||||
try:
|
||||
lib = OpenMCLibrary(filename)
|
||||
except OSError:
|
||||
warn("OpenMC shared library is not available from the Python API. This "
|
||||
"means you will not be able to use openmc.lib to make in-memory "
|
||||
"calls to OpenMC.")
|
||||
lib = None
|
||||
55
openmc/capi/__init__.py
Normal file
55
openmc/capi/__init__.py
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
"""
|
||||
This module provides bindings to C functions defined by OpenMC shared library.
|
||||
When the :mod:`openmc` package is imported, the OpenMC shared library is
|
||||
automatically loaded. Calls to the OpenMC library can then be via functions or
|
||||
objects in the :mod:`openmc.capi` subpackage, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
openmc.capi.init()
|
||||
openmc.capi.run()
|
||||
openmc.capi.finalize()
|
||||
|
||||
"""
|
||||
|
||||
from ctypes import CDLL
|
||||
import os
|
||||
import sys
|
||||
from warnings import warn
|
||||
|
||||
import pkg_resources
|
||||
|
||||
|
||||
# Determine shared-library suffix
|
||||
if sys.platform == 'darwin':
|
||||
_suffix = 'dylib'
|
||||
else:
|
||||
_suffix = 'so'
|
||||
|
||||
if os.environ.get('READTHEDOCS', None) != 'True':
|
||||
# Open shared library
|
||||
_filename = pkg_resources.resource_filename(
|
||||
__name__, 'libopenmc.{}'.format(_suffix))
|
||||
_dll = CDLL(_filename)
|
||||
else:
|
||||
# For documentation builds, we don't actually have the shared library
|
||||
# available. Instead, we create a mock object so that when the modules
|
||||
# within the openmc.capi package try to configure arguments and return
|
||||
# values for symbols, no errors occur
|
||||
try:
|
||||
from unittest.mock import Mock
|
||||
except ImportError:
|
||||
from mock import Mock
|
||||
_dll = Mock()
|
||||
|
||||
from .error import *
|
||||
from .core import *
|
||||
from .nuclide import *
|
||||
from .material import *
|
||||
from .cell import *
|
||||
from .filter import *
|
||||
from .tally import *
|
||||
from .settings import settings
|
||||
|
||||
warn("The Python bindings to OpenMC's C API are still unstable "
|
||||
"and may change substantially in future releases.", FutureWarning)
|
||||
128
openmc/capi/cell.py
Normal file
128
openmc/capi/cell.py
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
from collections import Mapping, Iterable
|
||||
from ctypes import c_int, c_int32, c_double, c_char_p, POINTER
|
||||
from weakref import WeakValueDictionary
|
||||
|
||||
import numpy as np
|
||||
from numpy.ctypeslib import as_array
|
||||
|
||||
from . import _dll
|
||||
from .core import _FortranObjectWithID
|
||||
from .error import _error_handler
|
||||
from .material import Material
|
||||
|
||||
__all__ = ['Cell', 'cells']
|
||||
|
||||
# Cell functions
|
||||
_dll.openmc_cell_get_id.argtypes = [c_int32, POINTER(c_int32)]
|
||||
_dll.openmc_cell_get_id.restype = c_int
|
||||
_dll.openmc_cell_get_id.errcheck = _error_handler
|
||||
_dll.openmc_cell_get_fill.argtypes = [
|
||||
c_int32, POINTER(c_int), POINTER(POINTER(c_int32)), POINTER(c_int32)]
|
||||
_dll.openmc_cell_set_fill.argtypes = [
|
||||
c_int32, c_int, c_int32, POINTER(c_int32)]
|
||||
_dll.openmc_cell_set_fill.restype = c_int
|
||||
_dll.openmc_cell_set_fill.errcheck = _error_handler
|
||||
_dll.openmc_cell_set_temperature.argtypes = [
|
||||
c_int32, c_double, POINTER(c_int32)]
|
||||
_dll.openmc_cell_set_temperature.restype = c_int
|
||||
_dll.openmc_cell_set_temperature.errcheck = _error_handler
|
||||
_dll.openmc_get_cell_index.argtypes = [c_int32, POINTER(c_int32)]
|
||||
_dll.openmc_get_cell_index.restype = c_int
|
||||
_dll.openmc_get_cell_index.errcheck = _error_handler
|
||||
|
||||
|
||||
class Cell(_FortranObjectWithID):
|
||||
"""Cell stored internally.
|
||||
|
||||
This class exposes a cell that is stored internally in the OpenMC
|
||||
library. To obtain a view of a cell with a given ID, use the
|
||||
:data:`openmc.capi.nuclides` mapping.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
index : int
|
||||
Index in the `cells` array.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
id : int
|
||||
ID of the cell
|
||||
|
||||
"""
|
||||
__instances = WeakValueDictionary()
|
||||
|
||||
def __new__(cls, *args):
|
||||
if args not in cls.__instances:
|
||||
instance = super(Cell, self).__new__(cls)
|
||||
cls.__instances[args] = instance
|
||||
return cls.__instances[args]
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
cell_id = c_int32()
|
||||
_dll.openmc_cell_get_id(self._index, cell_id)
|
||||
return cell_id.value
|
||||
|
||||
@property
|
||||
def fill(self):
|
||||
fill_type = c_int()
|
||||
indices = POINTER(c_int32)()
|
||||
n = c_int32()
|
||||
_dll.openmc_cell_get_fill(self._index, fill_type, indices, n)
|
||||
|
||||
if fill_type.value == 1:
|
||||
if n.value > 1:
|
||||
return [Material(index=i) for i in indices[:n.value]]
|
||||
else:
|
||||
return Material(index=indices[0])
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
@fill.setter
|
||||
def fill(self, fill):
|
||||
if isinstance(fill, Iterable):
|
||||
n = len(fill)
|
||||
indices = (c_int*n)(*(m._index for m in fill))
|
||||
_dll.openmc_cell_set_fill(self._index, 1, 1, indices)
|
||||
elif isinstance(fill, Material):
|
||||
materials = [fill]
|
||||
indices = (c_int*1)(fill._index)
|
||||
_dll.openmc_cell_set_fill(self._index, 1, 1, indices)
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
def set_temperature(self, T, instance=None):
|
||||
"""Set the temperature of a cell
|
||||
|
||||
Parameters
|
||||
----------
|
||||
T : float
|
||||
Temperature in K
|
||||
instance : int or None
|
||||
Which instance of the cell
|
||||
|
||||
"""
|
||||
_dll.openmc_cell_set_temperature(self._index, T, instance)
|
||||
|
||||
|
||||
class _CellMapping(Mapping):
|
||||
def __getitem__(self, key):
|
||||
index = c_int32()
|
||||
try:
|
||||
_dll.openmc_get_cell_index(key, index)
|
||||
except (AllocationError, InvalidIDError) as e:
|
||||
# __contains__ expects a KeyError to work correctly
|
||||
raise KeyError(str(e))
|
||||
return Cell(index.value)
|
||||
|
||||
def __iter__(self):
|
||||
for i in range(len(self)):
|
||||
yield Cell(i + 1).id
|
||||
|
||||
def __len__(self):
|
||||
return c_int32.in_dll(_dll, 'n_cells').value
|
||||
|
||||
def __repr__(self):
|
||||
return repr(dict(self))
|
||||
|
||||
cells = _CellMapping()
|
||||
186
openmc/capi/core.py
Normal file
186
openmc/capi/core.py
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
from contextlib import contextmanager
|
||||
from ctypes import CDLL, c_int, c_int32, c_double, POINTER
|
||||
from warnings import warn
|
||||
|
||||
from . import _dll
|
||||
from .error import _error_handler
|
||||
|
||||
|
||||
_dll.openmc_calculate_volumes.restype = None
|
||||
_dll.openmc_finalize.restype = None
|
||||
_dll.openmc_find.argtypes = [POINTER(c_double*3), c_int, POINTER(c_int32),
|
||||
POINTER(c_int32)]
|
||||
_dll.openmc_find.restype = c_int
|
||||
_dll.openmc_find.errcheck = _error_handler
|
||||
_dll.openmc_hard_reset.restype = None
|
||||
_dll.openmc_init.argtypes = [POINTER(c_int)]
|
||||
_dll.openmc_init.restype = None
|
||||
_dll.openmc_get_keff.argtypes = [POINTER(c_double*2)]
|
||||
_dll.openmc_get_keff.restype = c_int
|
||||
_dll.openmc_get_keff.errcheck = _error_handler
|
||||
_dll.openmc_plot_geometry.restype = None
|
||||
_dll.openmc_run.restype = None
|
||||
_dll.openmc_reset.restype = None
|
||||
|
||||
|
||||
def calculate_volumes():
|
||||
"""Run stochastic volume calculation"""
|
||||
_dll.openmc_calculate_volumes()
|
||||
|
||||
|
||||
def finalize():
|
||||
"""Finalize simulation and free memory"""
|
||||
_dll.openmc_finalize()
|
||||
|
||||
|
||||
def find_cell(xyz):
|
||||
"""Find the cell at a given point
|
||||
|
||||
Parameters
|
||||
----------
|
||||
xyz : iterable of float
|
||||
Cartesian coordinates of position
|
||||
|
||||
Returns
|
||||
-------
|
||||
int
|
||||
ID of the cell.
|
||||
int
|
||||
If the cell at the given point is repeated in the geometry, this
|
||||
indicates which instance it is, i.e., 0 would be the first instance.
|
||||
|
||||
"""
|
||||
uid = c_int32()
|
||||
instance = c_int32()
|
||||
_dll.openmc_find((c_double*3)(*xyz), 1, uid, instance)
|
||||
return uid.value, instance.value
|
||||
|
||||
|
||||
def find_material(xyz):
|
||||
"""Find the material at a given point
|
||||
|
||||
Parameters
|
||||
----------
|
||||
xyz : iterable of float
|
||||
Cartesian coordinates of position
|
||||
|
||||
Returns
|
||||
-------
|
||||
int or None
|
||||
ID of the material or None is no material is found
|
||||
|
||||
"""
|
||||
uid = c_int32()
|
||||
instance = c_int32()
|
||||
_dll.openmc_find((c_double*3)(*xyz), 2, uid, instance)
|
||||
return uid.value if uid != 0 else None
|
||||
|
||||
|
||||
def hard_reset():
|
||||
"""Reset tallies, timers, and pseudo-random number generator state."""
|
||||
_dll.openmc_hard_reset()
|
||||
|
||||
|
||||
def init(intracomm=None):
|
||||
"""Initialize OpenMC
|
||||
|
||||
Parameters
|
||||
----------
|
||||
intracomm : mpi4py.MPI.Intracomm or None
|
||||
MPI intracommunicator
|
||||
|
||||
"""
|
||||
if intracomm is not None:
|
||||
# If an mpi4py communicator was passed, convert it to an integer to
|
||||
# be passed to openmc_init
|
||||
try:
|
||||
intracomm = intracomm.py2f()
|
||||
except AttributeError:
|
||||
pass
|
||||
_dll.openmc_init(c_int(intracomm))
|
||||
else:
|
||||
_dll.openmc_init(None)
|
||||
|
||||
|
||||
def keff():
|
||||
"""Return the calculated k-eigenvalue and its standard deviation.
|
||||
|
||||
Returns
|
||||
-------
|
||||
tuple
|
||||
Mean k-eigenvalue and standard deviation of the mean
|
||||
|
||||
"""
|
||||
k = (c_double*2)()
|
||||
_dll.openmc_get_keff(k)
|
||||
return tuple(k)
|
||||
|
||||
|
||||
def plot_geometry():
|
||||
"""Plot geometry"""
|
||||
_dll.openmc_plot_geometry()
|
||||
|
||||
|
||||
def reset():
|
||||
"""Reset tallies and timers."""
|
||||
_dll.openmc_reset()
|
||||
|
||||
|
||||
def run():
|
||||
"""Run simulation"""
|
||||
_dll.openmc_run()
|
||||
|
||||
|
||||
@contextmanager
|
||||
def run_in_memory(intracomm=None):
|
||||
"""Provides context manager for calling OpenMC shared library functions.
|
||||
|
||||
This function is intended to be used in a 'with' statement and ensures that
|
||||
OpenMC is properly initialized/finalized. At the completion of the 'with'
|
||||
block, all memory that was allocated during the block is freed. For
|
||||
example::
|
||||
|
||||
with openmc.capi.run_in_memory():
|
||||
for i in range(n_iters):
|
||||
openmc.capi.reset()
|
||||
do_stuff()
|
||||
openmc.capi.run()
|
||||
|
||||
Parameters
|
||||
----------
|
||||
intracomm : mpi4py.MPI.Intracomm or None
|
||||
MPI intracommunicator
|
||||
|
||||
"""
|
||||
init(intracomm)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
finalize()
|
||||
|
||||
|
||||
class _DLLGlobal(object):
|
||||
"""Data descriptor that exposes global variables from libopenmc."""
|
||||
def __init__(self, ctype, name):
|
||||
self.ctype = ctype
|
||||
self.name = name
|
||||
|
||||
def __get__(self, instance, owner):
|
||||
return self.ctype.in_dll(_dll, self.name).value
|
||||
|
||||
def __set__(self, instance, value):
|
||||
self.ctype.in_dll(_dll, self.name).value = value
|
||||
|
||||
|
||||
class _FortranObject(object):
|
||||
def __repr__(self):
|
||||
return "{}[{}]".format(type(self).__name__, self._index)
|
||||
|
||||
|
||||
class _FortranObjectWithID(_FortranObject):
|
||||
def __init__(self, uid=None, new=True, index=None):
|
||||
# Creating the object has already been handled by __new__. In the
|
||||
# initializer, all we do is make sure that the object returned has an ID
|
||||
# assigned. If the array index of the object is out of bounds, an
|
||||
# OutOfBoundsError will be raised here by virtue of referencing self.id
|
||||
self.id
|
||||
73
openmc/capi/error.py
Normal file
73
openmc/capi/error.py
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
from ctypes import c_int, c_char
|
||||
|
||||
from . import _dll
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
"""Root exception class for OpenMC."""
|
||||
|
||||
|
||||
class GeometryError(Error):
|
||||
"""Geometry-related error"""
|
||||
|
||||
|
||||
class InvalidIDError(Error):
|
||||
"""Use of an ID that is invalid."""
|
||||
|
||||
|
||||
class AllocationError(Error):
|
||||
"""Error related to memory allocation."""
|
||||
|
||||
|
||||
class OutOfBoundsError(Error):
|
||||
"""Index in array out of bounds."""
|
||||
|
||||
|
||||
class DataError(Error):
|
||||
"""Error relating to nuclear data."""
|
||||
|
||||
|
||||
class PhysicsError(Error):
|
||||
"""Error relating to performing physics."""
|
||||
|
||||
|
||||
class InvalidArgumentError(Error):
|
||||
"""Argument passed was invalid."""
|
||||
|
||||
|
||||
class InvalidTypeError(Error):
|
||||
"""Tried to perform an operation on the wrong type."""
|
||||
|
||||
|
||||
def _error_handler(err, func, args):
|
||||
"""Raise exception according to error code."""
|
||||
|
||||
# Get error code corresponding to global constant.
|
||||
def errcode(s):
|
||||
return c_int.in_dll(_dll, s).value
|
||||
|
||||
# Get error message set by OpenMC library
|
||||
errmsg = (c_char*256).in_dll(_dll, 'openmc_err_msg')
|
||||
msg = errmsg.value.decode()
|
||||
|
||||
# Raise exception type corresponding to error code
|
||||
if err == errcode('e_allocate'):
|
||||
raise AllocationError(msg)
|
||||
elif err == errcode('e_out_of_bounds'):
|
||||
raise OutOfBoundsError(msg)
|
||||
elif err == errcode('e_invalid_argument'):
|
||||
raise InvalidArgumentError(msg)
|
||||
elif err == errcode('e_invalid_type'):
|
||||
raise InvalidTypeError(msg)
|
||||
if err == errcode('e_invalid_id'):
|
||||
raise InvalidIDError(msg)
|
||||
elif err == errcode('e_geometry'):
|
||||
raise GeometryError(msg)
|
||||
elif err == errcode('e_data'):
|
||||
raise DataError(msg)
|
||||
elif err == errcode('e_physics'):
|
||||
raise PhysicsError(msg)
|
||||
elif err == errcode('e_warning'):
|
||||
warn(msg)
|
||||
elif err < 0:
|
||||
raise Exception("Unknown error encountered (code {}).".format(err))
|
||||
256
openmc/capi/filter.py
Normal file
256
openmc/capi/filter.py
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
from collections import Mapping
|
||||
from ctypes import c_int, c_int32, c_double, c_char_p, POINTER, \
|
||||
create_string_buffer
|
||||
from weakref import WeakValueDictionary
|
||||
|
||||
import numpy as np
|
||||
from numpy.ctypeslib import as_array
|
||||
|
||||
from . import _dll
|
||||
from .core import _FortranObjectWithID
|
||||
from .error import _error_handler, AllocationError, InvalidIDError
|
||||
from .material import Material
|
||||
|
||||
|
||||
__all__ = ['Filter', 'AzimuthalFilter', 'CellFilter',
|
||||
'CellbornFilter', 'CellfromFilter', 'DistribcellFilter',
|
||||
'DelayedGroupFilter', 'EnergyFilter', 'EnergyoutFilter',
|
||||
'EnergyFunctionFilter', 'MaterialFilter', 'MeshFilter',
|
||||
'MuFilter', 'PolarFilter', 'SurfaceFilter',
|
||||
'UniverseFilter', 'filters']
|
||||
|
||||
# Tally functions
|
||||
_dll.openmc_energy_filter_get_bins.argtypes = [
|
||||
c_int32, POINTER(POINTER(c_double)), POINTER(c_int32)]
|
||||
_dll.openmc_energy_filter_get_bins.restype = c_int
|
||||
_dll.openmc_energy_filter_get_bins.errcheck = _error_handler
|
||||
_dll.openmc_energy_filter_set_bins.argtypes = [c_int32, c_int32, POINTER(c_double)]
|
||||
_dll.openmc_energy_filter_set_bins.restype = c_int
|
||||
_dll.openmc_energy_filter_set_bins.errcheck = _error_handler
|
||||
_dll.openmc_extend_filters.argtypes = [c_int32, POINTER(c_int32), POINTER(c_int32)]
|
||||
_dll.openmc_extend_filters.restype = c_int
|
||||
_dll.openmc_extend_filters.errcheck = _error_handler
|
||||
_dll.openmc_filter_get_id.argtypes = [c_int32, POINTER(c_int32)]
|
||||
_dll.openmc_filter_get_id.restype = c_int
|
||||
_dll.openmc_filter_get_id.errcheck = _error_handler
|
||||
_dll.openmc_filter_get_type.argtypes = [c_int32, c_char_p]
|
||||
_dll.openmc_filter_get_type.restype = c_int
|
||||
_dll.openmc_filter_get_type.errcheck = _error_handler
|
||||
_dll.openmc_filter_set_id.argtypes = [c_int32, c_int32]
|
||||
_dll.openmc_filter_set_id.restype = c_int
|
||||
_dll.openmc_filter_set_id.errcheck = _error_handler
|
||||
_dll.openmc_filter_set_type.argtypes = [c_int32, c_char_p]
|
||||
_dll.openmc_filter_set_type.restype = c_int
|
||||
_dll.openmc_filter_set_type.errcheck = _error_handler
|
||||
_dll.openmc_get_filter_index.argtypes = [c_int32, POINTER(c_int32)]
|
||||
_dll.openmc_get_filter_index.restype = c_int
|
||||
_dll.openmc_get_filter_index.errcheck = _error_handler
|
||||
_dll.openmc_material_filter_get_bins.argtypes = [
|
||||
c_int32, POINTER(POINTER(c_int32)), POINTER(c_int32)]
|
||||
_dll.openmc_material_filter_get_bins.restype = c_int
|
||||
_dll.openmc_material_filter_get_bins.errcheck = _error_handler
|
||||
_dll.openmc_material_filter_set_bins.argtypes = [c_int32, c_int32, POINTER(c_int32)]
|
||||
_dll.openmc_material_filter_set_bins.restype = c_int
|
||||
_dll.openmc_material_filter_set_bins.errcheck = _error_handler
|
||||
_dll.openmc_mesh_filter_set_mesh.argtypes = [c_int32, c_int32]
|
||||
_dll.openmc_mesh_filter_set_mesh.restype = c_int
|
||||
_dll.openmc_mesh_filter_set_mesh.errcheck = _error_handler
|
||||
|
||||
|
||||
class Filter(_FortranObjectWithID):
|
||||
__instances = WeakValueDictionary()
|
||||
|
||||
def __new__(cls, obj=None, uid=None, new=True, index=None):
|
||||
mapping = filters
|
||||
if index is None:
|
||||
if new:
|
||||
# Determine ID to assign
|
||||
if uid is None:
|
||||
try:
|
||||
uid = max(mapping) + 1
|
||||
except ValueError:
|
||||
uid = 1
|
||||
else:
|
||||
if uid in mapping:
|
||||
raise AllocationError('A filter with ID={} has already '
|
||||
'been allocated.'.format(uid))
|
||||
|
||||
# Resize internal array
|
||||
index = c_int32()
|
||||
_dll.openmc_extend_filters(1, index, None)
|
||||
|
||||
# Set the filter type -- note that the filter_type attribute
|
||||
# only exists on subclasses!
|
||||
_dll.openmc_filter_set_type(index, cls.filter_type.encode())
|
||||
index = index.value
|
||||
else:
|
||||
index = mapping[uid]._index
|
||||
|
||||
if index not in cls.__instances:
|
||||
instance = super(Filter, cls).__new__(cls)
|
||||
instance._index = index
|
||||
if uid is not None:
|
||||
instance.id = uid
|
||||
cls.__instances[index] = instance
|
||||
|
||||
return cls.__instances[index]
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
filter_id = c_int32()
|
||||
_dll.openmc_filter_get_id(self._index, filter_id)
|
||||
return filter_id.value
|
||||
|
||||
@id.setter
|
||||
def id(self, filter_id):
|
||||
_dll.openmc_filter_set_id(self._index, filter_id)
|
||||
|
||||
|
||||
class EnergyFilter(Filter):
|
||||
filter_type = 'energy'
|
||||
|
||||
def __init__(self, bins=None, uid=None, new=True, index=None):
|
||||
super(EnergyFilter, self).__init__(uid, new, index)
|
||||
if bins is not None:
|
||||
self.bins = bins
|
||||
|
||||
@property
|
||||
def bins(self):
|
||||
energies = POINTER(c_double)()
|
||||
n = c_int32()
|
||||
_dll.openmc_energy_filter_get_bins(self._index, energies, n)
|
||||
return as_array(energies, (n.value,))
|
||||
|
||||
@bins.setter
|
||||
def bins(self, bins):
|
||||
# Get numpy array as a double*
|
||||
energies = np.asarray(bins)
|
||||
energies_p = energies.ctypes.data_as(POINTER(c_double))
|
||||
|
||||
_dll.openmc_energy_filter_set_bins(
|
||||
self._index, len(energies), energies_p)
|
||||
|
||||
|
||||
class EnergyoutFilter(Filter):
|
||||
filter_type = 'energyout'
|
||||
|
||||
|
||||
class AzimuthalFilter(Filter):
|
||||
filter_type = 'azimuthal'
|
||||
|
||||
|
||||
class CellFilter(Filter):
|
||||
filter_type = 'cell'
|
||||
|
||||
|
||||
class CellbornFilter(Filter):
|
||||
filter_type = 'cellborn'
|
||||
|
||||
|
||||
class CellfromFilter(Filter):
|
||||
filter_type = 'cellfrom'
|
||||
|
||||
|
||||
class DelayedGroupFilter(Filter):
|
||||
filter_type = 'delayedgroup'
|
||||
|
||||
|
||||
class DistribcellFilter(Filter):
|
||||
filter_type = 'distribcell'
|
||||
|
||||
|
||||
class EnergyFunctionFilter(Filter):
|
||||
filter_type = 'energyfunction'
|
||||
|
||||
|
||||
class MaterialFilter(Filter):
|
||||
filter_type = 'material'
|
||||
|
||||
def __init__(self, bins=None, uid=None, new=True, index=None):
|
||||
super(MaterialFilter, self).__init__(uid, new, index)
|
||||
if bins is not None:
|
||||
self.bins = bins
|
||||
|
||||
@property
|
||||
def bins(self):
|
||||
materials = POINTER(c_int32)()
|
||||
n = c_int32()
|
||||
_dll.openmc_material_filter_get_bins(self._index, materials, n)
|
||||
return [Material(index=materials[i]) for i in range(n.value)]
|
||||
|
||||
@bins.setter
|
||||
def bins(self, materials):
|
||||
# Get material indices as int32_t[]
|
||||
n = len(materials)
|
||||
bins = (c_int32*n)(*(m._index for m in materials))
|
||||
|
||||
_dll.openmc_material_filter_set_bins(self._index, n, bins)
|
||||
|
||||
|
||||
class MeshFilter(Filter):
|
||||
filter_type = 'mesh'
|
||||
|
||||
|
||||
class MuFilter(Filter):
|
||||
filter_type = 'mu'
|
||||
|
||||
|
||||
class PolarFilter(Filter):
|
||||
filter_type = 'polar'
|
||||
|
||||
|
||||
class SurfaceFilter(Filter):
|
||||
filter_type = 'surface'
|
||||
|
||||
|
||||
class UniverseFilter(Filter):
|
||||
filter_type = 'universe'
|
||||
|
||||
|
||||
_FILTER_TYPE_MAP = {
|
||||
'azimuthal': AzimuthalFilter,
|
||||
'cell': CellFilter,
|
||||
'cellborn': CellbornFilter,
|
||||
'cellfrom': CellfromFilter,
|
||||
'delayedgroup': DelayedGroupFilter,
|
||||
'distribcell': DistribcellFilter,
|
||||
'energy': EnergyFilter,
|
||||
'energyout': EnergyoutFilter,
|
||||
'energyfunction': EnergyFunctionFilter,
|
||||
'material': MaterialFilter,
|
||||
'mesh': MeshFilter,
|
||||
'mu': MuFilter,
|
||||
'polar': PolarFilter,
|
||||
'surface': SurfaceFilter,
|
||||
'universe': UniverseFilter,
|
||||
}
|
||||
|
||||
|
||||
def _get_filter(index):
|
||||
filter_type = create_string_buffer(20)
|
||||
_dll.openmc_filter_get_type(index, filter_type)
|
||||
filter_type = filter_type.value.decode()
|
||||
return _FILTER_TYPE_MAP[filter_type](index=index)
|
||||
|
||||
|
||||
class _FilterMapping(Mapping):
|
||||
def __getitem__(self, key):
|
||||
index = c_int32()
|
||||
try:
|
||||
_dll.openmc_get_filter_index(key, index)
|
||||
except (AllocationError, InvalidIDError) as e:
|
||||
# __contains__ expects a KeyError to work correctly
|
||||
raise KeyError(str(e))
|
||||
return _get_filter(index.value)
|
||||
|
||||
def __iter__(self):
|
||||
for i in range(len(self)):
|
||||
yield _get_filter(i + 1).id
|
||||
|
||||
def __len__(self):
|
||||
return c_int32.in_dll(_dll, 'n_filters').value
|
||||
|
||||
def __repr__(self):
|
||||
return repr(dict(self))
|
||||
|
||||
filters = _FilterMapping()
|
||||
214
openmc/capi/material.py
Normal file
214
openmc/capi/material.py
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
from collections import Mapping
|
||||
from ctypes import c_int, c_int32, c_double, c_char_p, POINTER
|
||||
from weakref import WeakValueDictionary
|
||||
|
||||
import numpy as np
|
||||
from numpy.ctypeslib import as_array
|
||||
|
||||
from . import _dll, Nuclide
|
||||
from .core import _FortranObjectWithID
|
||||
from .error import _error_handler, AllocationError, InvalidIDError
|
||||
|
||||
|
||||
__all__ = ['Material', 'materials']
|
||||
|
||||
# Material functions
|
||||
_dll.openmc_extend_materials.argtypes = [c_int32, POINTER(c_int32), POINTER(c_int32)]
|
||||
_dll.openmc_extend_materials.restype = c_int
|
||||
_dll.openmc_extend_materials.errcheck = _error_handler
|
||||
_dll.openmc_get_material_index.argtypes = [c_int32, POINTER(c_int32)]
|
||||
_dll.openmc_get_material_index.restype = c_int
|
||||
_dll.openmc_get_material_index.errcheck = _error_handler
|
||||
_dll.openmc_material_add_nuclide.argtypes = [
|
||||
c_int32, c_char_p, c_double]
|
||||
_dll.openmc_material_add_nuclide.restype = c_int
|
||||
_dll.openmc_material_add_nuclide.errcheck = _error_handler
|
||||
_dll.openmc_material_get_id.argtypes = [c_int32, POINTER(c_int32)]
|
||||
_dll.openmc_material_get_id.restype = c_int
|
||||
_dll.openmc_material_get_id.errcheck = _error_handler
|
||||
_dll.openmc_material_get_densities.argtypes = [
|
||||
c_int32, POINTER(POINTER(c_int)), POINTER(POINTER(c_double)),
|
||||
POINTER(c_int)]
|
||||
_dll.openmc_material_get_densities.restype = c_int
|
||||
_dll.openmc_material_get_densities.errcheck = _error_handler
|
||||
_dll.openmc_material_set_density.argtypes = [c_int32, c_double]
|
||||
_dll.openmc_material_set_density.restype = c_int
|
||||
_dll.openmc_material_set_density.errcheck = _error_handler
|
||||
_dll.openmc_material_set_densities.argtypes = [
|
||||
c_int32, c_int, POINTER(c_char_p), POINTER(c_double)]
|
||||
_dll.openmc_material_set_densities.restype = c_int
|
||||
_dll.openmc_material_set_densities.errcheck = _error_handler
|
||||
_dll.openmc_material_set_id.argtypes = [c_int32, c_int32]
|
||||
_dll.openmc_material_set_id.restype = c_int
|
||||
_dll.openmc_material_set_id.errcheck = _error_handler
|
||||
|
||||
|
||||
class Material(_FortranObjectWithID):
|
||||
"""Material stored internally.
|
||||
|
||||
This class exposes a material that is stored internally in the OpenMC
|
||||
library. To obtain a view of a material with a given ID, use the
|
||||
:data:`openmc.capi.materials` mapping.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
uid : int or None
|
||||
Unique ID of the tally
|
||||
new : bool
|
||||
When `index` is None, this argument controls whether a new object is
|
||||
created or a view to an existing object is returned.
|
||||
index : int or None
|
||||
Index in the `materials` array.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
id : int
|
||||
ID of the material
|
||||
nuclides : list of str
|
||||
List of nuclides in the material
|
||||
densities : numpy.ndarray
|
||||
Array of densities in atom/b-cm
|
||||
|
||||
"""
|
||||
__instances = WeakValueDictionary()
|
||||
|
||||
def __new__(cls, uid=None, new=True, index=None):
|
||||
mapping = materials
|
||||
if index is None:
|
||||
if new:
|
||||
# Determine ID to assign
|
||||
if uid is None:
|
||||
try:
|
||||
uid = max(mapping) + 1
|
||||
except ValueError:
|
||||
uid = 1
|
||||
else:
|
||||
if uid in mapping:
|
||||
raise AllocationError('A material with ID={} has already '
|
||||
'been allocated.'.format(uid))
|
||||
|
||||
index = c_int32()
|
||||
_dll.openmc_extend_materials(1, index, None)
|
||||
index = index.value
|
||||
else:
|
||||
index = mapping[uid]._index
|
||||
|
||||
if index not in cls.__instances:
|
||||
instance = super(Material, cls).__new__(cls)
|
||||
instance._index = index
|
||||
if uid is not None:
|
||||
instance.id = uid
|
||||
cls.__instances[index] = instance
|
||||
|
||||
return cls.__instances[index]
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
mat_id = c_int32()
|
||||
_dll.openmc_material_get_id(self._index, mat_id)
|
||||
return mat_id.value
|
||||
|
||||
@id.setter
|
||||
def id(self, mat_id):
|
||||
_dll.openmc_material_set_id(self._index, mat_id)
|
||||
|
||||
@property
|
||||
def nuclides(self):
|
||||
return self._get_densities()[0]
|
||||
return nuclides
|
||||
|
||||
@property
|
||||
def densities(self):
|
||||
return self._get_densities()[1]
|
||||
|
||||
def _get_densities(self):
|
||||
"""Get atom densities in a material.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list of string
|
||||
List of nuclide names
|
||||
numpy.ndarray
|
||||
Array of densities in atom/b-cm
|
||||
|
||||
"""
|
||||
# Allocate memory for arguments that are written to
|
||||
nuclides = POINTER(c_int)()
|
||||
densities = POINTER(c_double)()
|
||||
n = c_int()
|
||||
|
||||
# Get nuclide names and densities
|
||||
_dll.openmc_material_get_densities(self._index, nuclides, densities, n)
|
||||
|
||||
# Convert to appropriate types and return
|
||||
nuclide_list = [Nuclide(nuclides[i]).name for i in range(n.value)]
|
||||
density_array = as_array(densities, (n.value,))
|
||||
return nuclide_list, density_array
|
||||
|
||||
def add_nuclide(self, name, density):
|
||||
"""Add a nuclide to a material.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Name of nuclide, e.g. 'U235'
|
||||
density : float
|
||||
Density in atom/b-cm
|
||||
|
||||
"""
|
||||
_dll.openmc_material_add_nuclide(self._index, name.encode(), density)
|
||||
|
||||
def set_density(self, density):
|
||||
"""Set density of a material.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
density : float
|
||||
Density in atom/b-cm
|
||||
|
||||
"""
|
||||
_dll.openmc_material_set_density(self._index, density)
|
||||
|
||||
def set_densities(self, nuclides, densities):
|
||||
"""Set the densities of a list of nuclides in a material
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nuclides : iterable of str
|
||||
Nuclide names
|
||||
densities : iterable of float
|
||||
Corresponding densities in atom/b-cm
|
||||
|
||||
"""
|
||||
# Convert strings to an array of char*
|
||||
nucs = (c_char_p * len(nuclides))()
|
||||
nucs[:] = [x.encode() for x in nuclides]
|
||||
|
||||
# Get numpy array as a double*
|
||||
d = np.asarray(densities)
|
||||
dp = d.ctypes.data_as(POINTER(c_double))
|
||||
|
||||
_dll.openmc_material_set_densities(self._index, len(nuclides), nucs, dp)
|
||||
|
||||
|
||||
class _MaterialMapping(Mapping):
|
||||
def __getitem__(self, key):
|
||||
index = c_int32()
|
||||
try:
|
||||
_dll.openmc_get_material_index(key, index)
|
||||
except (AllocationError, InvalidIDError) as e:
|
||||
# __contains__ expects a KeyError to work correctly
|
||||
raise KeyError(str(e))
|
||||
return Material(index=index.value)
|
||||
|
||||
def __iter__(self):
|
||||
for i in range(len(self)):
|
||||
yield Material(index=i + 1).id
|
||||
|
||||
def __len__(self):
|
||||
return c_int32.in_dll(_dll, 'n_materials').value
|
||||
|
||||
def __repr__(self):
|
||||
return repr(dict(self))
|
||||
|
||||
materials = _MaterialMapping()
|
||||
101
openmc/capi/nuclide.py
Normal file
101
openmc/capi/nuclide.py
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
from collections import Mapping
|
||||
from ctypes import c_int, c_char_p, POINTER
|
||||
from weakref import WeakValueDictionary
|
||||
|
||||
import numpy as np
|
||||
from numpy.ctypeslib import as_array
|
||||
|
||||
from . import _dll
|
||||
from .core import _FortranObject
|
||||
from .error import _error_handler, DataError, AllocationError
|
||||
|
||||
|
||||
__all__ = ['Nuclide', 'nuclides', 'load_nuclide']
|
||||
|
||||
# Nuclide functions
|
||||
_dll.openmc_get_nuclide_index.argtypes = [c_char_p, POINTER(c_int)]
|
||||
_dll.openmc_get_nuclide_index.restype = c_int
|
||||
_dll.openmc_get_nuclide_index.errcheck = _error_handler
|
||||
_dll.openmc_load_nuclide.argtypes = [c_char_p]
|
||||
_dll.openmc_load_nuclide.restype = c_int
|
||||
_dll.openmc_load_nuclide.errcheck = _error_handler
|
||||
_dll.openmc_nuclide_name.argtypes = [c_int, POINTER(c_char_p)]
|
||||
_dll.openmc_nuclide_name.restype = c_int
|
||||
_dll.openmc_nuclide_name.errcheck = _error_handler
|
||||
|
||||
|
||||
def load_nuclide(name):
|
||||
"""Load cross section data for a nuclide.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Name of the nuclide, e.g. 'U235'
|
||||
|
||||
"""
|
||||
_dll.openmc_load_nuclide(name.encode())
|
||||
|
||||
|
||||
class Nuclide(_FortranObject):
|
||||
"""Nuclide stored internally.
|
||||
|
||||
This class exposes a nuclide that is stored internally in the OpenMC
|
||||
solver. To obtain a view of a nuclide with a given name, use the
|
||||
:data:`openmc.capi.nuclides` mapping.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
index : int
|
||||
Index in the `nuclides` array.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
name : str
|
||||
Name of the nuclide, e.g. 'U235'
|
||||
|
||||
"""
|
||||
__instances = WeakValueDictionary()
|
||||
|
||||
def __new__(cls, *args):
|
||||
if args not in cls.__instances:
|
||||
instance = super(Nuclide, cls).__new__(cls)
|
||||
cls.__instances[args] = instance
|
||||
return cls.__instances[args]
|
||||
|
||||
def __init__(self, index):
|
||||
self._index = index
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
name = c_char_p()
|
||||
_dll.openmc_nuclide_name(self._index, name)
|
||||
|
||||
# Find blank in name
|
||||
i = 0
|
||||
while name.value[i:i+1] != b' ':
|
||||
i += 1
|
||||
return name.value[:i].decode()
|
||||
|
||||
|
||||
class _NuclideMapping(Mapping):
|
||||
"""Provide mapping from nuclide name to index in nuclides array."""
|
||||
def __getitem__(self, key):
|
||||
index = c_int()
|
||||
try:
|
||||
_dll.openmc_get_nuclide_index(key.encode(), index)
|
||||
except (DataError, AllocationError) as e:
|
||||
# __contains__ expects a KeyError to work correctly
|
||||
raise KeyError(str(e))
|
||||
return Nuclide(index.value)
|
||||
|
||||
def __iter__(self):
|
||||
for i in range(len(self)):
|
||||
yield Nuclide(i + 1).name
|
||||
|
||||
def __len__(self):
|
||||
return c_int.in_dll(_dll, 'n_nuclides').value
|
||||
|
||||
def __repr__(self):
|
||||
return repr(dict(self))
|
||||
|
||||
nuclides = _NuclideMapping()
|
||||
53
openmc/capi/settings.py
Normal file
53
openmc/capi/settings.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
from ctypes import c_int, c_int32, c_int64, c_double, c_char_p, POINTER
|
||||
|
||||
from . import _dll
|
||||
from .core import _DLLGlobal
|
||||
from .error import _error_handler
|
||||
|
||||
_RUN_MODES = {1: 'fixed source',
|
||||
2: 'eigenvalue',
|
||||
3: 'plot',
|
||||
4: 'particle restart',
|
||||
5: 'volume'}
|
||||
|
||||
_dll.openmc_set_seed.argtypes = [c_int64]
|
||||
_dll.openmc_set_seed.restype = c_int
|
||||
_dll.openmc_set_seed.errcheck = _error_handler
|
||||
|
||||
|
||||
class _Settings(object):
|
||||
# Attributes that are accessed through a descriptor
|
||||
batches = _DLLGlobal(c_int32, 'n_batches')
|
||||
generations_per_batch = _DLLGlobal(c_int32, 'gen_per_batch')
|
||||
inactive = _DLLGlobal(c_int32, 'n_inactive')
|
||||
particles = _DLLGlobal(c_int64, 'n_particles')
|
||||
verbosity = _DLLGlobal(c_int, 'verbosity')
|
||||
|
||||
@property
|
||||
def run_mode(self):
|
||||
i = c_int.in_dll(_dll, 'run_mode').value
|
||||
try:
|
||||
return _RUN_MODES[i]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
@run_mode.setter
|
||||
def run_mode(self, mode):
|
||||
current_idx = c_int.in_dll(_dll, 'run_mode')
|
||||
for idx, mode_value in _RUN_MODES.items():
|
||||
if mode_value == mode:
|
||||
current_idx.value = idx
|
||||
break
|
||||
else:
|
||||
raise ValueError('Invalid run mode: {}'.format(mode))
|
||||
|
||||
@property
|
||||
def seed(self):
|
||||
return c_int64.in_dll(_dll, 'seed').value
|
||||
|
||||
@seed.setter
|
||||
def seed(self, seed):
|
||||
_dll.openmc_set_seed(seed)
|
||||
|
||||
|
||||
settings = _Settings()
|
||||
209
openmc/capi/tally.py
Normal file
209
openmc/capi/tally.py
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
from collections import Mapping
|
||||
from ctypes import c_int, c_int32, c_double, c_char_p, POINTER
|
||||
from weakref import WeakValueDictionary
|
||||
|
||||
from numpy.ctypeslib import as_array
|
||||
|
||||
from . import _dll, Nuclide
|
||||
from .core import _FortranObjectWithID
|
||||
from .error import _error_handler, AllocationError, InvalidIDError
|
||||
from .filter import _get_filter
|
||||
|
||||
|
||||
__all__ = ['Tally', 'tallies']
|
||||
|
||||
# Tally functions
|
||||
_dll.openmc_get_tally_index.argtypes = [c_int32, POINTER(c_int32)]
|
||||
_dll.openmc_get_tally_index.restype = c_int
|
||||
_dll.openmc_get_tally_index.errcheck = _error_handler
|
||||
_dll.openmc_extend_tallies.argtypes = [c_int32, POINTER(c_int32), POINTER(c_int32)]
|
||||
_dll.openmc_extend_tallies.restype = c_int
|
||||
_dll.openmc_extend_tallies.errcheck = _error_handler
|
||||
_dll.openmc_tally_get_id.argtypes = [c_int32, POINTER(c_int32)]
|
||||
_dll.openmc_tally_get_id.restype = c_int
|
||||
_dll.openmc_tally_get_id.errcheck = _error_handler
|
||||
_dll.openmc_tally_get_filters.argtypes = [
|
||||
c_int32, POINTER(POINTER(c_int32)), POINTER(c_int)]
|
||||
_dll.openmc_tally_get_filters.restype = c_int
|
||||
_dll.openmc_tally_get_filters.errcheck = _error_handler
|
||||
_dll.openmc_tally_get_nuclides.argtypes = [
|
||||
c_int32, POINTER(POINTER(c_int)), POINTER(c_int)]
|
||||
_dll.openmc_tally_get_nuclides.restype = c_int
|
||||
_dll.openmc_tally_get_nuclides.errcheck = _error_handler
|
||||
_dll.openmc_tally_results.argtypes = [
|
||||
c_int32, POINTER(POINTER(c_double)), POINTER(c_int*3)]
|
||||
_dll.openmc_tally_results.restype = c_int
|
||||
_dll.openmc_tally_results.errcheck = _error_handler
|
||||
_dll.openmc_tally_set_filters.argtypes = [c_int32, c_int, POINTER(c_int32)]
|
||||
_dll.openmc_tally_set_filters.restype = c_int
|
||||
_dll.openmc_tally_set_filters.errcheck = _error_handler
|
||||
_dll.openmc_tally_set_id.argtypes = [c_int32, c_int32]
|
||||
_dll.openmc_tally_set_id.restype = c_int
|
||||
_dll.openmc_tally_set_id.errcheck = _error_handler
|
||||
_dll.openmc_tally_set_nuclides.argtypes = [c_int32, c_int, POINTER(c_char_p)]
|
||||
_dll.openmc_tally_set_nuclides.restype = c_int
|
||||
_dll.openmc_tally_set_nuclides.errcheck = _error_handler
|
||||
_dll.openmc_tally_set_scores.argtypes = [c_int32, c_int, POINTER(c_char_p)]
|
||||
_dll.openmc_tally_set_scores.restype = c_int
|
||||
_dll.openmc_tally_set_scores.errcheck = _error_handler
|
||||
_dll.openmc_tally_set_type.argtypes = [c_int32, c_char_p]
|
||||
_dll.openmc_tally_set_type.restype = c_int
|
||||
_dll.openmc_tally_set_type.errcheck = _error_handler
|
||||
|
||||
|
||||
class Tally(_FortranObjectWithID):
|
||||
"""Tally stored internally.
|
||||
|
||||
This class exposes a tally that is stored internally in the OpenMC
|
||||
library. To obtain a view of a tally with a given ID, use the
|
||||
:data:`openmc.capi.tallies` mapping.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
uid : int or None
|
||||
Unique ID of the tally
|
||||
new : bool
|
||||
When `index` is None, this argument controls whether a new object is
|
||||
created or a view of an existing object is returned.
|
||||
index : int or None
|
||||
Index in the `tallies` array.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
id : int
|
||||
ID of the tally
|
||||
filters : list
|
||||
List of tally filters
|
||||
nuclides : list of str
|
||||
List of nuclides to score results for
|
||||
results : numpy.ndarray
|
||||
Array of tally results
|
||||
|
||||
"""
|
||||
__instances = WeakValueDictionary()
|
||||
|
||||
def __new__(cls, uid=None, new=True, index=None):
|
||||
mapping = tallies
|
||||
if index is None:
|
||||
if new:
|
||||
# Determine ID to assign
|
||||
if uid is None:
|
||||
try:
|
||||
uid = max(mapping) + 1
|
||||
except ValueError:
|
||||
uid = 1
|
||||
else:
|
||||
if uid in mapping:
|
||||
raise AllocationError('A tally with ID={} has already '
|
||||
'been allocated.'.format(uid))
|
||||
|
||||
index = c_int32()
|
||||
_dll.openmc_extend_tallies(1, index, None)
|
||||
_dll.openmc_tally_set_type(index, b'generic')
|
||||
index = index.value
|
||||
else:
|
||||
index = mapping[uid]._index
|
||||
|
||||
if index not in cls.__instances:
|
||||
instance = super(Tally, cls).__new__(cls)
|
||||
instance._index = index
|
||||
if uid is not None:
|
||||
instance.id = uid
|
||||
cls.__instances[index] = instance
|
||||
|
||||
return cls.__instances[index]
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
tally_id = c_int32()
|
||||
_dll.openmc_tally_get_id(self._index, tally_id)
|
||||
return tally_id.value
|
||||
|
||||
@id.setter
|
||||
def id(self, tally_id):
|
||||
_dll.openmc_tally_set_id(self._index, tally_id)
|
||||
|
||||
@property
|
||||
def filters(self):
|
||||
filt_idx = POINTER(c_int32)()
|
||||
n = c_int()
|
||||
_dll.openmc_tally_get_filters(self._index, filt_idx, n)
|
||||
return [_get_filter(filt_idx[i]) for i in range(n.value)]
|
||||
|
||||
@property
|
||||
def nuclides(self):
|
||||
nucs = POINTER(c_int)()
|
||||
n = c_int()
|
||||
_dll.openmc_tally_get_nuclides(self._index, nucs, n)
|
||||
return [Nuclide(nucs[i]).name if nucs[i] > 0 else 'total'
|
||||
for i in range(n.value)]
|
||||
|
||||
@property
|
||||
def results(self):
|
||||
data = POINTER(c_double)()
|
||||
shape = (c_int*3)()
|
||||
_dll.openmc_tally_results(self._index, data, shape)
|
||||
return as_array(data, tuple(shape[::-1]))
|
||||
|
||||
@filters.setter
|
||||
def filters(self, filters):
|
||||
# Get filter indices as int32_t[]
|
||||
n = len(filters)
|
||||
indices = (c_int32*n)(*(f._index for f in filters))
|
||||
|
||||
_dll.openmc_tally_set_filters(self._index, n, indices)
|
||||
|
||||
@nuclides.setter
|
||||
def nuclides(self, nuclides):
|
||||
nucs = (c_char_p * len(nuclides))()
|
||||
nucs[:] = [x.encode() for x in nuclides]
|
||||
_dll.openmc_tally_set_nuclides(self._index, len(nuclides), nucs)
|
||||
|
||||
@property
|
||||
def scores(self):
|
||||
pass
|
||||
|
||||
@scores.setter
|
||||
def scores(self, scores):
|
||||
scores_ = (c_char_p * len(scores))()
|
||||
scores_[:] = [x.encode() for x in scores]
|
||||
_dll.openmc_tally_set_scores(self._index, len(scores), scores_)
|
||||
|
||||
@classmethod
|
||||
def new(cls, tally_id=None):
|
||||
# Determine ID to assign
|
||||
if tally_id is None:
|
||||
try:
|
||||
tally_id = max(tallies) + 1
|
||||
except ValueError:
|
||||
tally_id = 1
|
||||
|
||||
index = c_int32()
|
||||
_dll.openmc_extend_tallies(1, index, None)
|
||||
_dll.openmc_tally_set_type(index, b'generic')
|
||||
tally = cls(index.value)
|
||||
tally.id = tally_id
|
||||
return tally
|
||||
|
||||
|
||||
class _TallyMapping(Mapping):
|
||||
def __getitem__(self, key):
|
||||
index = c_int32()
|
||||
try:
|
||||
_dll.openmc_get_tally_index(key, index)
|
||||
except (AllocationError, InvalidIDError) as e:
|
||||
# __contains__ expects a KeyError to work correctly
|
||||
raise KeyError(str(e))
|
||||
return Tally(index=index.value)
|
||||
|
||||
def __iter__(self):
|
||||
for i in range(len(self)):
|
||||
yield Tally(index=i + 1).id
|
||||
|
||||
def __len__(self):
|
||||
return c_int32.in_dll(_dll, 'n_tallies').value
|
||||
|
||||
def __repr__(self):
|
||||
return repr(dict(self))
|
||||
|
||||
tallies = _TallyMapping()
|
||||
|
|
@ -867,12 +867,13 @@ class IncidentNeutron(EqualityMixin):
|
|||
data.fission_energy = FissionEnergyRelease.from_endf(ev, data)
|
||||
|
||||
# Add 0K elastic scattering cross section
|
||||
pendf = Evaluation(pendf_file)
|
||||
file_obj = StringIO(pendf.section[3, 2])
|
||||
get_head_record(file_obj)
|
||||
params, xs = get_tab1_record(file_obj)
|
||||
data.energy['0K'] = xs.x
|
||||
data[2].xs['0K'] = xs
|
||||
if '0K' not in data.energy:
|
||||
pendf = Evaluation(pendf_file)
|
||||
file_obj = StringIO(pendf.section[3, 2])
|
||||
get_head_record(file_obj)
|
||||
params, xs = get_tab1_record(file_obj)
|
||||
data.energy['0K'] = xs.x
|
||||
data[2].xs['0K'] = xs
|
||||
|
||||
finally:
|
||||
# Get rid of temporary files
|
||||
|
|
|
|||
|
|
@ -50,48 +50,45 @@ _THERMAL_DATA = {
|
|||
75: ThermalTuple('ouo2', [8016, 8017, 8018], 1),
|
||||
}
|
||||
|
||||
|
||||
_PENDF_TEMPLATE = """
|
||||
_TEMPLATE_RECONR = """
|
||||
reconr / %%%%%%%%%%%%%%%%%%% Reconstruct XS for neutrons %%%%%%%%%%%%%%%%%%%%%%%
|
||||
20 22
|
||||
{nendf} {npendf}
|
||||
'{library} PENDF for {zsymam}'/
|
||||
{mat} 2/
|
||||
0.001 0.0 0.003/ err tempr errmax
|
||||
{error}/ err
|
||||
'{library}: {zsymam}'/
|
||||
'Processed by NJOY'/
|
||||
0/
|
||||
stop
|
||||
"""
|
||||
|
||||
_ACE_TEMPLATE = """
|
||||
reconr / %%%%%%%%%%%%%%%%%%% Reconstruct XS for neutrons %%%%%%%%%%%%%%%%%%%%%%%
|
||||
20 21
|
||||
'{library} PENDF for {zsymam}'/
|
||||
{mat} 2/
|
||||
0.001 0.0 0.003/ err tempr errmax
|
||||
'{library}: {zsymam}'/
|
||||
'Processed by NJOY'/
|
||||
0/
|
||||
_TEMPLATE_BROADR = """
|
||||
broadr / %%%%%%%%%%%%%%%%%%%%%%% Doppler broaden XS %%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
20 21 22
|
||||
{nendf} {npendf} {nbroadr}
|
||||
{mat} {num_temp} 0 0 0. /
|
||||
0.001 1.0e6 0.003 /
|
||||
{error}/ errthn
|
||||
{temps}
|
||||
0/
|
||||
"""
|
||||
|
||||
_TEMPLATE_HEATR = """
|
||||
heatr / %%%%%%%%%%%%%%%%%%%%%%%%% Add heating kerma %%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
20 22 23 /
|
||||
{nendf} {nheatr_in} {nheatr} /
|
||||
{mat} 3 /
|
||||
302 318 402 /
|
||||
"""
|
||||
|
||||
_TEMPLATE_PURR = """
|
||||
purr / %%%%%%%%%%%%%%%%%%%%%%%% Add probability tables %%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
20 23 24
|
||||
{nendf} {npurr_in} {npurr} /
|
||||
{mat} {num_temp} 1 20 64 /
|
||||
{temps}
|
||||
1.e10
|
||||
0/
|
||||
"""
|
||||
|
||||
_ACE_TEMPLATE_ACER = """acer /
|
||||
20 24 0 {nace} {ndir}
|
||||
_TEMPLATE_ACER = """
|
||||
acer / %%%%%%%%%%%%%%%%%%%%%%%% Write out in ACE format %%%%%%%%%%%%%%%%%%%%%%%%
|
||||
{nendf} {nacer_in} 0 {nace} {ndir}
|
||||
1 0 1 .{ext} /
|
||||
'{library}: {zsymam} at {temperature}'/
|
||||
{mat} {temperature}
|
||||
|
|
@ -99,35 +96,22 @@ _ACE_TEMPLATE_ACER = """acer /
|
|||
/
|
||||
"""
|
||||
|
||||
_ACE_THERMAL_TEMPLATE = """
|
||||
reconr / %%%%%%%%%%%%%%%%%%% Reconstruct XS for neutrons %%%%%%%%%%%%%%%%%%%%%%%
|
||||
20 22
|
||||
'{library} PENDF for {zsymam}'/
|
||||
{mat} 2/
|
||||
0.001 0. 0.001/ err tempr errmax
|
||||
'{library}: PENDF for {zsymam}'/
|
||||
'Processed by NJOY'/
|
||||
0/
|
||||
broadr / %%%%%%%%%%%%%%%%%%%%%%% Doppler broaden XS %%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
20 22 23
|
||||
{mat} {num_temp} 0 0 0./
|
||||
0.001 2.0e+6 0.001/ errthn thnmax errmax
|
||||
{temps}
|
||||
0/
|
||||
_THERMAL_TEMPLATE_THERMR = """
|
||||
thermr / %%%%%%%%%%%%%%%% Add thermal scattering data (free gas) %%%%%%%%%%%%%%%
|
||||
0 23 62
|
||||
0 {nthermr1_in} {nthermr1}
|
||||
0 {mat} 12 {num_temp} 1 0 {iform} 1 221 1/
|
||||
{temps}
|
||||
0.001 {energy_max}
|
||||
{error} {energy_max}
|
||||
thermr / %%%%%%%%%%%%%%%% Add thermal scattering data (bound) %%%%%%%%%%%%%%%%%%
|
||||
60 62 27
|
||||
{nthermal_endf} {nthermr2_in} {nthermr2}
|
||||
{mat_thermal} {mat} 16 {num_temp} {inelastic} {elastic} {iform} {natom} 222 1/
|
||||
{temps}
|
||||
0.001 {energy_max}
|
||||
{error} {energy_max}
|
||||
"""
|
||||
|
||||
_ACE_THERMAL_TEMPLATE_ACER = """acer /
|
||||
20 27 0 {nace} {ndir}
|
||||
_THERMAL_TEMPLATE_ACER = """
|
||||
acer / %%%%%%%%%%%%%%%%%%%%%%%% Write out in ACE format %%%%%%%%%%%%%%%%%%%%%%%%
|
||||
{nendf} {nthermal_acer_in} 0 {nace} {ndir}
|
||||
2 0 1 .{ext}/
|
||||
'{library}: {zsymam_thermal} processed by NJOY'/
|
||||
{mat} {temperature} '{data.name}' /
|
||||
|
|
@ -136,7 +120,8 @@ _ACE_THERMAL_TEMPLATE_ACER = """acer /
|
|||
"""
|
||||
|
||||
|
||||
def run(commands, tapein, tapeout, stdout=False, njoy_exec='njoy'):
|
||||
def run(commands, tapein, tapeout, input_filename=None, stdout=False,
|
||||
njoy_exec='njoy'):
|
||||
"""Run NJOY with given commands
|
||||
|
||||
Parameters
|
||||
|
|
@ -147,6 +132,8 @@ def run(commands, tapein, tapeout, stdout=False, njoy_exec='njoy'):
|
|||
Dictionary mapping tape numbers to paths for any input files
|
||||
tapeout : dict
|
||||
Dictionary mapping tape numbers to paths for any output files
|
||||
input_filename : str, optional
|
||||
File name to write out NJOY input commands
|
||||
stdout : bool, optional
|
||||
Whether to display output when running NJOY
|
||||
njoy_exec : str, optional
|
||||
|
|
@ -159,6 +146,10 @@ def run(commands, tapein, tapeout, stdout=False, njoy_exec='njoy'):
|
|||
|
||||
"""
|
||||
|
||||
if input_filename is not None:
|
||||
with open(input_filename, 'w') as f:
|
||||
f.write(commands)
|
||||
|
||||
# Create temporary directory -- it would be preferable to use
|
||||
# TemporaryDirectory(), but it is only available in Python 3.2
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
|
|
@ -195,7 +186,7 @@ def run(commands, tapein, tapeout, stdout=False, njoy_exec='njoy'):
|
|||
return njoy.returncode
|
||||
|
||||
|
||||
def make_pendf(filename, pendf='pendf', stdout=False):
|
||||
def make_pendf(filename, pendf='pendf', error=0.001, stdout=False):
|
||||
"""Generate ACE file from an ENDF file
|
||||
|
||||
Parameters
|
||||
|
|
@ -204,6 +195,8 @@ def make_pendf(filename, pendf='pendf', stdout=False):
|
|||
Path to ENDF file
|
||||
pendf : str, optional
|
||||
Path of pointwise ENDF file to write
|
||||
error : float, optional
|
||||
Fractional error tolerance for NJOY processing
|
||||
stdout : bool
|
||||
Whether to display NJOY standard output
|
||||
|
||||
|
|
@ -213,21 +206,14 @@ def make_pendf(filename, pendf='pendf', stdout=False):
|
|||
Return code of NJOY process
|
||||
|
||||
"""
|
||||
ev = endf.Evaluation(filename)
|
||||
mat = ev.material
|
||||
zsymam = ev.target['zsymam']
|
||||
|
||||
# Determine name of library
|
||||
library = '{}-{}.{}'.format(*ev.info['library'])
|
||||
|
||||
commands = _PENDF_TEMPLATE.format(**locals())
|
||||
tapein = {20: filename}
|
||||
tapeout = {22: pendf}
|
||||
return run(commands, tapein, tapeout, stdout)
|
||||
return make_ace(filename, pendf=pendf, error=error, broadr=False,
|
||||
heatr=False, purr=False, acer=False, stdout=stdout)
|
||||
|
||||
|
||||
def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir',
|
||||
pendf=None, **kwargs):
|
||||
def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir', pendf=None,
|
||||
error=0.001, broadr=True, heatr=True, purr=True, acer=True,
|
||||
**kwargs):
|
||||
"""Generate incident neutron ACE file from an ENDF file
|
||||
|
||||
Parameters
|
||||
|
|
@ -243,6 +229,16 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir',
|
|||
Path of xsdir file to write
|
||||
pendf : str, optional
|
||||
Path of pendf file to write. If omitted, the pendf file is not saved.
|
||||
error : float, optional
|
||||
Fractional error tolerance for NJOY processing
|
||||
broadr : bool, optional
|
||||
Indicating whether to Doppler broaden XS when running NJOY
|
||||
heatr : bool, optional
|
||||
Indicating whether to add heating kerma when running NJOY
|
||||
purr : bool, optional
|
||||
Indicating whether to add probability table when running NJOY
|
||||
acer : bool, optional
|
||||
Indicating whether to generate ACE file when running NJOY
|
||||
**kwargs
|
||||
Keyword arguments passed to :func:`openmc.data.njoy.run`
|
||||
|
||||
|
|
@ -264,26 +260,59 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir',
|
|||
num_temp = len(temperatures)
|
||||
temps = ' '.join(str(i) for i in temperatures)
|
||||
|
||||
commands = _ACE_TEMPLATE.format(**locals())
|
||||
tapein = {20: filename}
|
||||
# Create njoy commands by modules
|
||||
commands = ""
|
||||
|
||||
nendf, npendf = 20, 21
|
||||
tapein = {nendf: filename}
|
||||
tapeout = {}
|
||||
if pendf is not None:
|
||||
tapeout[21] = pendf
|
||||
fname = '{}_{:.1f}'
|
||||
for i, temperature in enumerate(temperatures):
|
||||
# Extend input with an ACER run for each temperature
|
||||
nace = 25 + 2*i
|
||||
ndir = 25 + 2*i + 1
|
||||
ext = '{:02}'.format(i + 1)
|
||||
commands += _ACE_TEMPLATE_ACER.format(**locals())
|
||||
tapeout[npendf] = pendf
|
||||
|
||||
# Indicate tapes to save for each ACER run
|
||||
tapeout[nace] = fname.format(ace, temperature)
|
||||
tapeout[ndir] = fname.format(xsdir, temperature)
|
||||
# reconr
|
||||
commands += _TEMPLATE_RECONR
|
||||
nlast = npendf
|
||||
|
||||
# broadr
|
||||
if broadr:
|
||||
nbroadr = nlast + 1
|
||||
commands += _TEMPLATE_BROADR
|
||||
nlast = nbroadr
|
||||
|
||||
# heatr
|
||||
if heatr:
|
||||
nheatr_in = nlast
|
||||
nheatr = nheatr_in + 1
|
||||
commands += _TEMPLATE_HEATR
|
||||
nlast = nheatr
|
||||
|
||||
# purr
|
||||
if purr:
|
||||
npurr_in = nlast
|
||||
npurr = npurr_in + 1
|
||||
commands += _TEMPLATE_PURR
|
||||
nlast = npurr
|
||||
|
||||
commands = commands.format(**locals())
|
||||
|
||||
# acer
|
||||
if acer:
|
||||
nacer_in = nlast
|
||||
fname = '{}_{:.1f}'
|
||||
for i, temperature in enumerate(temperatures):
|
||||
# Extend input with an ACER run for each temperature
|
||||
nace = nacer_in + 1 + 2*i
|
||||
ndir = nace + 1
|
||||
ext = '{:02}'.format(i + 1)
|
||||
commands += _TEMPLATE_ACER.format(**locals())
|
||||
|
||||
# Indicate tapes to save for each ACER run
|
||||
tapeout[nace] = fname.format(ace, temperature)
|
||||
tapeout[ndir] = fname.format(xsdir, temperature)
|
||||
commands += 'stop\n'
|
||||
retcode = run(commands, tapein, tapeout, **kwargs)
|
||||
|
||||
if retcode == 0:
|
||||
if acer and retcode == 0:
|
||||
with open(ace, 'w') as ace_file, open(xsdir, 'w') as xsdir_file:
|
||||
for temperature in temperatures:
|
||||
# Get contents of ACE file
|
||||
|
|
@ -311,8 +340,8 @@ def make_ace(filename, temperatures=None, ace='ace', xsdir='xsdir',
|
|||
return retcode
|
||||
|
||||
|
||||
def make_ace_thermal(filename, filename_thermal, temperatures=None,
|
||||
ace='ace', xsdir='xsdir', **kwargs):
|
||||
def make_ace_thermal(filename, filename_thermal, temperatures=None,
|
||||
ace='ace', xsdir='xsdir', error=0.001, **kwargs):
|
||||
"""Generate thermal scattering ACE file from ENDF files
|
||||
|
||||
Parameters
|
||||
|
|
@ -328,6 +357,8 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None,
|
|||
Path of ACE file to write
|
||||
xsdir : str, optional
|
||||
Path of xsdir file to write
|
||||
error : float, optional
|
||||
Fractional error tolerance for NJOY processing
|
||||
**kwargs
|
||||
Keyword arguments passed to :func:`openmc.data.njoy.run`
|
||||
|
||||
|
|
@ -390,16 +421,41 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None,
|
|||
num_temp = len(temperatures)
|
||||
temps = ' '.join(str(i) for i in temperatures)
|
||||
|
||||
commands = _ACE_THERMAL_TEMPLATE.format(**locals())
|
||||
tapein = {20: filename, 60: filename_thermal}
|
||||
# Create njoy commands by modules
|
||||
commands = ""
|
||||
|
||||
nendf, nthermal_endf, npendf = 20, 21, 22
|
||||
tapein = {nendf: filename, nthermal_endf:filename_thermal}
|
||||
tapeout = {}
|
||||
|
||||
# reconr
|
||||
commands += _TEMPLATE_RECONR
|
||||
nlast = npendf
|
||||
|
||||
# broadr
|
||||
nbroadr = nlast + 1
|
||||
commands += _TEMPLATE_BROADR
|
||||
nlast = nbroadr
|
||||
|
||||
# thermr
|
||||
nthermr1_in = nlast
|
||||
nthermr1 = nthermr1_in + 1
|
||||
nthermr2_in = nthermr1
|
||||
nthermr2 = nthermr2_in + 1
|
||||
commands += _THERMAL_TEMPLATE_THERMR
|
||||
nlast = nthermr2
|
||||
|
||||
commands = commands.format(**locals())
|
||||
|
||||
# acer
|
||||
nthermal_acer_in = nlast
|
||||
fname = '{}_{:.1f}'
|
||||
for i, temperature in enumerate(temperatures):
|
||||
# Extend input with an ACER run for each temperature
|
||||
nace = 28 + 2*i
|
||||
ndir = 28 + 2*i + 1
|
||||
nace = nthermal_acer_in + 1 + 2*i
|
||||
ndir = nace + 1
|
||||
ext = '{:02}'.format(i + 1)
|
||||
commands += _ACE_THERMAL_TEMPLATE_ACER.format(**locals())
|
||||
commands += _THERMAL_TEMPLATE_ACER.format(**locals())
|
||||
|
||||
# Indicate tapes to save for each ACER run
|
||||
tapeout[nace] = fname.format(ace, temperature)
|
||||
|
|
|
|||
|
|
@ -124,6 +124,15 @@ class Element(object):
|
|||
is a tuple consisting of an openmc.Nuclide instance and the natural
|
||||
abundance of the isotope.
|
||||
|
||||
Notes
|
||||
-----
|
||||
When the `enrichment` argument is specified, a correlation from
|
||||
`ORNL/CSD/TM-244 <https://doi.org/10.2172/5561567>`_ is used to
|
||||
calculate the weight fractions of U234, U235, U236, and U238. Namely,
|
||||
the weight fraction of U234 and U236 are taken to be 0.89% and 0.46%,
|
||||
respectively, of the U235 weight fraction. The remainder of the isotopic
|
||||
weight is assigned to U238.
|
||||
|
||||
"""
|
||||
|
||||
# Get the nuclides present in nature
|
||||
|
|
@ -217,9 +226,10 @@ class Element(object):
|
|||
if enrichment is not None:
|
||||
|
||||
# Calculate the mass fractions of isotopes
|
||||
abundances['U234'] = 0.008 * enrichment
|
||||
abundances['U234'] = 0.0089 * enrichment
|
||||
abundances['U235'] = enrichment
|
||||
abundances['U238'] = 100.0 - 1.008 * enrichment
|
||||
abundances['U236'] = 0.0046 * enrichment
|
||||
abundances['U238'] = 100.0 - 1.0135 * enrichment
|
||||
|
||||
# Convert the mass fractions to mole fractions
|
||||
for nuclide in abundances.keys():
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ from .mixin import IDManagerMixin
|
|||
|
||||
_FILTER_TYPES = ['universe', 'material', 'cell', 'cellborn', 'surface',
|
||||
'mesh', 'energy', 'energyout', 'mu', 'polar', 'azimuthal',
|
||||
'distribcell', 'delayedgroup', 'energyfunction', 'particle']
|
||||
'distribcell', 'delayedgroup', 'energyfunction', 'cellfrom',
|
||||
'particle']
|
||||
|
||||
_CURRENT_NAMES = {1: 'x-min out', 2: 'x-min in',
|
||||
3: 'x-max out', 4: 'x-max in',
|
||||
|
|
@ -620,6 +621,39 @@ class CellFilter(WithIDFilter):
|
|||
self._smart_set_bins(bins, openmc.Cell)
|
||||
|
||||
|
||||
class CellFromFilter(WithIDFilter):
|
||||
"""Bins tally on which Cell the neutron came from.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
bins : openmc.Cell, Integral, or iterable thereof
|
||||
The Cell(s) to tally. Either openmc.Cell objects or their
|
||||
Integral ID numbers can be used.
|
||||
filter_id : int
|
||||
Unique identifier for the filter
|
||||
|
||||
Attributes
|
||||
----------
|
||||
bins : Integral or Iterable of Integral
|
||||
openmc.Cell IDs.
|
||||
id : int
|
||||
Unique identifier for the filter
|
||||
num_bins : Integral
|
||||
The number of filter bins
|
||||
stride : Integral
|
||||
The number of filter, nuclide and score bins within each of this
|
||||
filter's bins.
|
||||
|
||||
"""
|
||||
@property
|
||||
def bins(self):
|
||||
return self._bins
|
||||
|
||||
@bins.setter
|
||||
def bins(self, bins):
|
||||
self._smart_set_bins(bins, openmc.Cell)
|
||||
|
||||
|
||||
class CellbornFilter(WithIDFilter):
|
||||
"""Bins tally events based on which Cell the neutron was born in.
|
||||
|
||||
|
|
|
|||
|
|
@ -606,7 +606,7 @@ class Library(object):
|
|||
|
||||
Parameters
|
||||
----------
|
||||
domain : Material or Cell or Universe or Integral
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh or Integral
|
||||
The material, cell, or universe object of interest (or its ID)
|
||||
mgxs_type : {'total', 'transport', 'nu-transport', 'absorption', 'capture', 'fission', 'nu-fission', 'kappa-fission', 'scatter', 'nu-scatter', 'scatter matrix', 'nu-scatter matrix', 'multiplicity matrix', 'nu-fission matrix', chi', 'chi-prompt', 'inverse-velocity', 'prompt-nu-fission', 'prompt-nu-fission matrix', 'delayed-nu-fission', 'delayed-nu-fission matrix', 'chi-delayed', 'beta'}
|
||||
The type of multi-group cross section object to return
|
||||
|
|
@ -668,7 +668,7 @@ class Library(object):
|
|||
|
||||
Returns
|
||||
-------
|
||||
Library
|
||||
openmc.mgxs.Library
|
||||
A new multi-group cross section library condensed to the group
|
||||
structure of interest
|
||||
|
||||
|
|
@ -880,7 +880,7 @@ class Library(object):
|
|||
|
||||
Returns
|
||||
-------
|
||||
Library
|
||||
openmc.mgxs.Library
|
||||
A Library object loaded from the pickle binary file
|
||||
|
||||
See also
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ class MDGXS(MGXS):
|
|||
Reaction type (e.g., 'chi-delayed', 'beta', etc.)
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -948,7 +948,7 @@ class ChiDelayed(MDGXS):
|
|||
Reaction type (e.g., 'total', 'nu-fission', etc.)
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -1462,7 +1462,7 @@ class DelayedNuFissionXS(MDGXS):
|
|||
Reaction type (e.g., 'total', 'nu-fission', etc.)
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -1598,7 +1598,7 @@ class Beta(MDGXS):
|
|||
Reaction type (e.g., 'total', 'nu-fission', etc.)
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -1782,7 +1782,7 @@ class DecayRate(MDGXS):
|
|||
Reaction type (e.g., 'total', 'nu-fission', etc.)
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -1959,7 +1959,7 @@ class MatrixMDGXS(MDGXS):
|
|||
Reaction type (e.g., 'total', 'nu-fission', etc.)
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -2551,7 +2551,7 @@ class DelayedNuFissionMatrixXS(MatrixMDGXS):
|
|||
Reaction type (e.g., 'total', 'nu-fission', etc.)
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ class MGXS(object):
|
|||
Reaction type (e.g., 'total', 'nu-fission', etc.)
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -2018,7 +2018,7 @@ class MatrixMGXS(MGXS):
|
|||
Reaction type (e.g., 'total', 'nu-fission', etc.)
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -2512,7 +2512,7 @@ class TotalXS(MGXS):
|
|||
Reaction type (e.g., 'total', 'nu-fission', etc.)
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -2649,7 +2649,7 @@ class TransportXS(MGXS):
|
|||
If True, the cross section data will include neutron multiplication
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -2858,7 +2858,7 @@ class AbsorptionXS(MGXS):
|
|||
Reaction type (e.g., 'total', 'nu-fission', etc.)
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -2986,7 +2986,7 @@ class CaptureXS(MGXS):
|
|||
Reaction type (e.g., 'total', 'nu-fission', etc.)
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -3140,7 +3140,7 @@ class FissionXS(MGXS):
|
|||
If true, computes cross sections which only includes prompt neutrons
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -3309,7 +3309,7 @@ class KappaFissionXS(MGXS):
|
|||
Reaction type (e.g., 'total', 'nu-fission', etc.)
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -3441,7 +3441,7 @@ class ScatterXS(MGXS):
|
|||
If True, the cross section data will include neutron multiplication
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -3658,7 +3658,7 @@ class ScatterMatrixXS(MatrixMGXS):
|
|||
If True, the cross section data will include neutron multiplication
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -4020,7 +4020,7 @@ class ScatterMatrixXS(MatrixMGXS):
|
|||
# Override the nuclides for tally arithmetic
|
||||
correction.nuclides = scatter_p1.nuclides
|
||||
self._xs_tally -= correction
|
||||
|
||||
|
||||
self._compute_xs()
|
||||
|
||||
return self._xs_tally
|
||||
|
|
@ -4749,7 +4749,7 @@ class MultiplicityMatrixXS(MatrixMGXS):
|
|||
Reaction type (e.g., 'total', 'nu-fission', etc.)
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -4915,7 +4915,7 @@ class ScatterProbabilityMatrix(MatrixMGXS):
|
|||
Reaction type (e.g., 'total', 'nu-fission', etc.)
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -5088,7 +5088,7 @@ class NuFissionMatrixXS(MatrixMGXS):
|
|||
If true, computes cross sections which only includes prompt neutrons
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -5245,7 +5245,7 @@ class Chi(MGXS):
|
|||
If true, computes cross sections which only includes prompt neutrons
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
@ -5823,7 +5823,7 @@ class InverseVelocity(MGXS):
|
|||
Reaction type (e.g., 'total', 'nu-fission', etc.)
|
||||
by_nuclide : bool
|
||||
If true, computes cross sections for each nuclide in domain
|
||||
domain : Material or Cell or Universe or Mesh
|
||||
domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.Mesh
|
||||
Domain for spatial homogenization
|
||||
domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'}
|
||||
Domain type for spatial homogenization
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ class Nuclide(object):
|
|||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Name of the nuclide, e.g. U235
|
||||
Name of the nuclide, e.g. 'U235'
|
||||
|
||||
Attributes
|
||||
----------
|
||||
name : str
|
||||
Name of the nuclide, e.g. U235
|
||||
Name of the nuclide, e.g. 'U235'
|
||||
scattering : 'data' or 'iso-in-lab' or None
|
||||
The type of angular scattering distribution to use
|
||||
|
||||
|
|
|
|||
|
|
@ -968,20 +968,15 @@ class Settings(object):
|
|||
subelement = ET.SubElement(element, key)
|
||||
subelement.text = str(value)
|
||||
|
||||
def _create_entropy_subelement(self, root):
|
||||
if self._entropy_mesh is not None:
|
||||
element = ET.SubElement(root, "entropy")
|
||||
def _create_entropy_mesh_subelement(self, root):
|
||||
if self.entropy_mesh is not None:
|
||||
# See if a <mesh> element already exists -- if not, add it
|
||||
path = "./mesh[@id='{}']".format(self.entropy_mesh.id)
|
||||
if root.find(path) is None:
|
||||
root.append(self.entropy_mesh.to_xml_element())
|
||||
|
||||
if self._entropy_mesh.dimension is not None:
|
||||
subelement = ET.SubElement(element, "dimension")
|
||||
subelement.text = ' '.join(
|
||||
str(x) for x in self._entropy_mesh.dimension)
|
||||
subelement = ET.SubElement(element, "lower_left")
|
||||
subelement.text = ' '.join(
|
||||
str(x) for x in self._entropy_mesh.lower_left)
|
||||
subelement = ET.SubElement(element, "upper_right")
|
||||
subelement.text = ' '.join(
|
||||
str(x) for x in self._entropy_mesh.upper_right)
|
||||
subelement = ET.SubElement(root, "entropy_mesh")
|
||||
subelement.text = str(self.entropy_mesh.id)
|
||||
|
||||
def _create_trigger_subelement(self, root):
|
||||
if self._trigger_active is not None:
|
||||
|
|
@ -1038,18 +1033,15 @@ class Settings(object):
|
|||
element = ET.SubElement(root, "track")
|
||||
element.text = ' '.join(map(str, self._track))
|
||||
|
||||
def _create_ufs_subelement(self, root):
|
||||
if self._ufs_mesh is not None:
|
||||
element = ET.SubElement(root, "uniform_fs")
|
||||
subelement = ET.SubElement(element, "dimension")
|
||||
subelement.text = ' '.join(str(x) for x in
|
||||
self._ufs_mesh.dimension)
|
||||
subelement = ET.SubElement(element, "lower_left")
|
||||
subelement.text = ' '.join(str(x) for x in
|
||||
self._ufs_mesh.lower_left)
|
||||
subelement = ET.SubElement(element, "upper_right")
|
||||
subelement.text = ' '.join(str(x) for x in
|
||||
self._ufs_mesh.upper_right)
|
||||
def _create_ufs_mesh_subelement(self, root):
|
||||
if self.ufs_mesh is not None:
|
||||
# See if a <mesh> element already exists -- if not, add it
|
||||
path = "./mesh[@id='{}']".format(self.ufs_mesh.id)
|
||||
if root.find(path) is None:
|
||||
root.append(self.ufs_mesh.to_xml_element())
|
||||
|
||||
subelement = ET.SubElement(root, "ufs_mesh")
|
||||
subelement.text = str(self.ufs_mesh.id)
|
||||
|
||||
def _create_dd_subelement(self, root):
|
||||
if self._dd_mesh_lower_left is not None and \
|
||||
|
|
@ -1137,7 +1129,7 @@ class Settings(object):
|
|||
self._create_seed_subelement(root_element)
|
||||
self._create_survival_biasing_subelement(root_element)
|
||||
self._create_cutoff_subelement(root_element)
|
||||
self._create_entropy_subelement(root_element)
|
||||
self._create_entropy_mesh_subelement(root_element)
|
||||
self._create_trigger_subelement(root_element)
|
||||
self._create_no_reduce_subelement(root_element)
|
||||
self._create_threads_subelement(root_element)
|
||||
|
|
@ -1146,7 +1138,7 @@ class Settings(object):
|
|||
self._create_temperature_subelements(root_element)
|
||||
self._create_trace_subelement(root_element)
|
||||
self._create_track_subelement(root_element)
|
||||
self._create_ufs_subelement(root_element)
|
||||
self._create_ufs_mesh_subelement(root_element)
|
||||
self._create_dd_subelement(root_element)
|
||||
self._create_resonance_scattering_subelement(root_element)
|
||||
self._create_volume_calcs_subelement(root_element)
|
||||
|
|
|
|||
|
|
@ -402,14 +402,6 @@ class StatePoint(object):
|
|||
scores = group['score_bins'].value
|
||||
n_score_bins = group['n_score_bins'].value
|
||||
|
||||
# Compute and set the filter strides
|
||||
for i in range(n_filters):
|
||||
tally_filter = tally.filters[i]
|
||||
tally_filter.stride = n_score_bins * len(nuclide_names)
|
||||
|
||||
for j in range(i+1, n_filters):
|
||||
tally_filter.stride *= tally.filters[j].num_bins
|
||||
|
||||
# Read scattering moment order strings (e.g., P3, Y1,2, etc.)
|
||||
moments = group['moment_orders'].value
|
||||
|
||||
|
|
@ -423,6 +415,9 @@ class StatePoint(object):
|
|||
|
||||
tally.scores.append(score)
|
||||
|
||||
# Compute and set the filter strides
|
||||
tally._update_filter_strides()
|
||||
|
||||
# Add Tally to the global dictionary of all Tallies
|
||||
tally.sparse = self.sparse
|
||||
self._tallies[tally_id] = tally
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from collections import Iterable, MutableSequence
|
|||
import copy
|
||||
import re
|
||||
from functools import partial
|
||||
import itertools
|
||||
from itertools import product
|
||||
from numbers import Integral, Real
|
||||
import warnings
|
||||
from xml.etree import ElementTree as ET
|
||||
|
|
@ -502,7 +502,7 @@ class Tally(IDManagerMixin):
|
|||
|
||||
Parameters
|
||||
----------
|
||||
nuclide : str, Nuclide, CrossNuclide or AggregateNuclide
|
||||
nuclide : str, openmc.Nuclide, CrossNuclide or AggregateNuclide
|
||||
Nuclide to add to the tally. The nuclide should be a Nuclide object
|
||||
when a user is adding nuclides to a Tally for input file generation.
|
||||
The nuclide is a str when a Tally is created from a StatePoint file
|
||||
|
|
@ -1329,7 +1329,7 @@ class Tally(IDManagerMixin):
|
|||
if isinstance(self_filter, openmc.MeshFilter):
|
||||
dimension = self_filter.mesh.dimension
|
||||
xyz = [range(1, x+1) for x in dimension]
|
||||
bins = list(itertools.product(*xyz))
|
||||
bins = list(product(*xyz))
|
||||
|
||||
# Create list of 2-tuples for energy boundary bins
|
||||
elif isinstance(self_filter, (openmc.EnergyFilter,
|
||||
|
|
@ -1364,7 +1364,7 @@ class Tally(IDManagerMixin):
|
|||
indices *= self_filter.num_bins
|
||||
|
||||
# Apply outer product sum between all filter bin indices
|
||||
filter_indices = list(map(sum, itertools.product(*filter_indices)))
|
||||
filter_indices = list(map(sum, product(*filter_indices)))
|
||||
|
||||
# If user did not specify any specific Filters, use them all
|
||||
else:
|
||||
|
|
@ -1664,8 +1664,10 @@ class Tally(IDManagerMixin):
|
|||
new_column.extend(['']*delta_len)
|
||||
columns[i] = tuple(new_column)
|
||||
|
||||
# Create and set a MultiIndex for the DataFrame's columns
|
||||
df.columns = pd.MultiIndex.from_tuples(columns)
|
||||
# Create and set a MultiIndex for the DataFrame's columns, but only
|
||||
# if any column actually is multi-level (e.g., a mesh filter)
|
||||
if any(len(c) > 1 for c in columns):
|
||||
df.columns = pd.MultiIndex.from_tuples(columns)
|
||||
|
||||
# Modify the df.to_string method so that it prints formatted strings.
|
||||
# Credit to http://stackoverflow.com/users/3657742/chrisb for this trick
|
||||
|
|
@ -1880,7 +1882,7 @@ class Tally(IDManagerMixin):
|
|||
new_tally.filters.append(self_filter)
|
||||
else:
|
||||
all_filters = [self_copy.filters, other_copy.filters]
|
||||
for self_filter, other_filter in itertools.product(*all_filters):
|
||||
for self_filter, other_filter in product(*all_filters):
|
||||
new_filter = openmc.CrossFilter(self_filter, other_filter,
|
||||
binary_op)
|
||||
new_tally.filters.append(new_filter)
|
||||
|
|
@ -1891,20 +1893,31 @@ class Tally(IDManagerMixin):
|
|||
new_tally.nuclides.append(self_nuclide)
|
||||
else:
|
||||
all_nuclides = [self_copy.nuclides, other_copy.nuclides]
|
||||
for self_nuclide, other_nuclide in itertools.product(*all_nuclides):
|
||||
new_nuclide = \
|
||||
openmc.CrossNuclide(self_nuclide, other_nuclide, binary_op)
|
||||
for self_nuclide, other_nuclide in product(*all_nuclides):
|
||||
new_nuclide = openmc.CrossNuclide(self_nuclide, other_nuclide,
|
||||
binary_op)
|
||||
new_tally.nuclides.append(new_nuclide)
|
||||
|
||||
# Define helper function that handles score units appropriately
|
||||
# depending on the binary operator
|
||||
def cross_score(score1, score2, binary_op):
|
||||
if binary_op == '+' or binary_op == '-':
|
||||
if score1 == score2:
|
||||
return score1
|
||||
else:
|
||||
return openmc.CrossScore(score1, score2, binary_op)
|
||||
else:
|
||||
return openmc.CrossScore(score1, score2, binary_op)
|
||||
|
||||
# Add scores to the new tally
|
||||
if score_product == 'entrywise':
|
||||
for self_score in self_copy.scores:
|
||||
new_tally.scores.append(self_score)
|
||||
new_score = cross_score(self_score, self_score, binary_op)
|
||||
new_tally.scores.append(new_score)
|
||||
else:
|
||||
all_scores = [self_copy.scores, other_copy.scores]
|
||||
for self_score, other_score in itertools.product(*all_scores):
|
||||
new_score = openmc.CrossScore(self_score, other_score,
|
||||
binary_op)
|
||||
for self_score, other_score in product(*all_scores):
|
||||
new_score = cross_score(self_score, other_score, binary_op)
|
||||
new_tally.scores.append(new_score)
|
||||
|
||||
# Update the new tally's filter strides
|
||||
|
|
@ -2142,7 +2155,7 @@ class Tally(IDManagerMixin):
|
|||
std_dev = {}
|
||||
|
||||
# Store the data from the misaligned structure
|
||||
for i, (bin1, bin2) in enumerate(itertools.product(filter1_bins, filter2_bins)):
|
||||
for i, (bin1, bin2) in enumerate(product(filter1_bins, filter2_bins)):
|
||||
filter_bins = [(bin1,), (bin2,)]
|
||||
|
||||
if self.mean is not None:
|
||||
|
|
@ -2163,7 +2176,7 @@ class Tally(IDManagerMixin):
|
|||
self._update_filter_strides()
|
||||
|
||||
# Realign the data
|
||||
for i, (bin1, bin2) in enumerate(itertools.product(filter1_bins, filter2_bins)):
|
||||
for i, (bin1, bin2) in enumerate(product(filter1_bins, filter2_bins)):
|
||||
filter_bins = [(bin1,), (bin2,)]
|
||||
indices = self.get_filter_indices(filters, filter_bins)
|
||||
|
||||
|
|
@ -3503,7 +3516,7 @@ class Tallies(cv.CheckedList):
|
|||
if f not in already_written:
|
||||
root_element.append(f.to_xml_element())
|
||||
already_written[f] = f.id
|
||||
else:
|
||||
elif f.id != already_written[f]:
|
||||
# Set the IDs of identical filters with different
|
||||
# user-defined IDs to the same value
|
||||
f.id = already_written[f]
|
||||
|
|
|
|||
11
readme.rst
11
readme.rst
|
|
@ -2,8 +2,7 @@
|
|||
OpenMC Monte Carlo Particle Transport Code
|
||||
==========================================
|
||||
|
||||
.. image:: https://travis-ci.org/mit-crpg/openmc.svg?branch=develop
|
||||
:target: https://travis-ci.org/mit-crpg/openmc
|
||||
|licensebadge| |travisbadge|
|
||||
|
||||
The OpenMC project aims to provide a fully-featured Monte Carlo particle
|
||||
transport code based on modern methods. It is a constructive solid geometry,
|
||||
|
|
@ -55,3 +54,11 @@ OpenMC is distributed under the MIT/X license_.
|
|||
.. _Troubleshooting section: http://openmc.readthedocs.io/en/stable/usersguide/troubleshoot.html
|
||||
.. _Issues: https://github.com/mit-crpg/openmc/issues
|
||||
.. _license: http://openmc.readthedocs.io/en/stable/license.html
|
||||
|
||||
.. |licensebadge| image:: https://img.shields.io/github/license/mit-crpg/openmc.svg
|
||||
:target: http://openmc.readthedocs.io/en/latest/license.html
|
||||
:alt: License
|
||||
|
||||
.. |travisbadge| image:: https://travis-ci.org/mit-crpg/openmc.svg?branch=develop
|
||||
:target: https://travis-ci.org/mit-crpg/openmc
|
||||
:alt: Travis CI build status (Linux)
|
||||
|
|
|
|||
|
|
@ -247,6 +247,11 @@ def update_materials(root):
|
|||
if 'name' in nuclide.attrib:
|
||||
nucname = nuclide.attrib['name']
|
||||
nucname = nucname.replace('-', '')
|
||||
# If a nuclide name is in the ZAID notation (e.g., a number),
|
||||
# convert it to the proper nuclide name.
|
||||
if nucname.strip().isnumeric():
|
||||
nucname = \
|
||||
openmc.data.neutron._get_metadata(int(nucname))[0]
|
||||
nucname = nucname.replace('Nat', '0')
|
||||
if nucname.endswith('m'):
|
||||
nucname = nucname[:-1] + '_m1'
|
||||
|
|
|
|||
86
setup.py
86
setup.py
|
|
@ -3,13 +3,8 @@
|
|||
import glob
|
||||
import sys
|
||||
import numpy as np
|
||||
try:
|
||||
from setuptools import setup
|
||||
have_setuptools = True
|
||||
except ImportError:
|
||||
from distutils.core import setup
|
||||
have_setuptools = False
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
try:
|
||||
from Cython.Build import cythonize
|
||||
have_cython = True
|
||||
|
|
@ -28,46 +23,53 @@ else:
|
|||
with open('openmc/__init__.py', 'r') as f:
|
||||
version = f.readlines()[-1].split()[-1].strip("'")
|
||||
|
||||
kwargs = {'name': 'openmc',
|
||||
'version': version,
|
||||
'packages': ['openmc', 'openmc.data', 'openmc.mgxs', 'openmc.model',
|
||||
'openmc.stats'],
|
||||
'scripts': glob.glob('scripts/openmc-*'),
|
||||
kwargs = {
|
||||
'name': 'openmc',
|
||||
'version': version,
|
||||
'packages': find_packages(),
|
||||
'scripts': glob.glob('scripts/openmc-*'),
|
||||
|
||||
# Data files and librarries
|
||||
'package_data': {
|
||||
'openmc': ['_libopenmc.{}'.format(suffix)],
|
||||
'openmc.data': ['mass.mas12', '*.h5']
|
||||
},
|
||||
# Data files and librarries
|
||||
'package_data': {
|
||||
'openmc.capi': ['libopenmc.{}'.format(suffix)],
|
||||
'openmc.data': ['mass.mas12', '*.h5']
|
||||
},
|
||||
|
||||
# Metadata
|
||||
'author': 'Will Boyd',
|
||||
'author_email': 'wbinventor@gmail.com',
|
||||
'description': 'OpenMC Python API',
|
||||
'url': 'https://github.com/mit-crpg/openmc',
|
||||
'classifiers': [
|
||||
'Intended Audience :: Developers',
|
||||
'Intended Audience :: End Users/Desktop',
|
||||
'Intended Audience :: Science/Research',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Natural Language :: English',
|
||||
'Programming Language :: Python',
|
||||
'Topic :: Scientific/Engineering'
|
||||
]}
|
||||
# Metadata
|
||||
'author': 'The OpenMC Development Team',
|
||||
'author_email': 'openmc-dev@googlegroups.com',
|
||||
'description': 'OpenMC',
|
||||
'url': 'https://github.com/mit-crpg/openmc',
|
||||
'classifiers': [
|
||||
'Development Status :: 4 - Beta',
|
||||
'Intended Audience :: Developers',
|
||||
'Intended Audience :: End Users/Desktop',
|
||||
'Intended Audience :: Science/Research',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Natural Language :: English',
|
||||
'Topic :: Scientific/Engineering'
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.2',
|
||||
'Programming Language :: Python :: 3.3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
],
|
||||
|
||||
if have_setuptools:
|
||||
kwargs.update({
|
||||
# Required dependencies
|
||||
'install_requires': ['six', 'numpy>=1.9', 'h5py', 'scipy', 'pandas>=0.17.0'],
|
||||
# Required dependencies
|
||||
'install_requires': [
|
||||
'six', 'numpy>=1.9', 'h5py', 'scipy', 'ipython', 'matplotlib',
|
||||
'pandas', 'lxml', 'uncertainties'
|
||||
],
|
||||
|
||||
# Optional dependencies
|
||||
'extras_require': {
|
||||
'decay': ['uncertainties'],
|
||||
'plot': ['matplotlib', 'ipython'],
|
||||
'vtk': ['vtk', 'silomesh'],
|
||||
'validate': ['lxml']
|
||||
},
|
||||
})
|
||||
# Optional dependencies
|
||||
'extras_require': {
|
||||
'test': ['pytest', 'pytest-cov'],
|
||||
'vtk': ['vtk', 'silomesh'],
|
||||
},
|
||||
}
|
||||
|
||||
# If Cython is present, add resonance reconstruction capability
|
||||
if have_cython:
|
||||
|
|
|
|||
465
src/api.F90
465
src/api.F90
|
|
@ -2,82 +2,177 @@ module openmc_api
|
|||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use hdf5, only: HID_T
|
||||
use hdf5, only: HID_T, h5tclose_f, h5close_f
|
||||
|
||||
use constants, only: K_BOLTZMANN
|
||||
use eigenvalue, only: k_sum
|
||||
use finalize, only: openmc_finalize
|
||||
use eigenvalue, only: k_sum, openmc_get_keff
|
||||
use error
|
||||
use geometry, only: find_cell
|
||||
use global
|
||||
use geometry_header
|
||||
use hdf5_interface
|
||||
use message_passing, only: master
|
||||
use material_header
|
||||
use mesh_header
|
||||
use message_passing
|
||||
use nuclide_header
|
||||
use initialize, only: openmc_init
|
||||
use input_xml, only: assign_0K_elastic_scattering, check_data_version
|
||||
use particle_header, only: Particle
|
||||
use plot, only: openmc_plot_geometry
|
||||
use random_lcg, only: seed, openmc_set_seed
|
||||
use settings
|
||||
use simulation_header
|
||||
use tally_header
|
||||
use tally_filter_header
|
||||
use tally_filter
|
||||
use tally, only: openmc_tally_set_type
|
||||
use simulation, only: openmc_run
|
||||
use string, only: to_f_string
|
||||
use timer_header
|
||||
use volume_calc, only: openmc_calculate_volumes
|
||||
|
||||
implicit none
|
||||
|
||||
private
|
||||
public :: openmc_calculate_volumes
|
||||
public :: openmc_cell_get_id
|
||||
public :: openmc_cell_get_fill
|
||||
public :: openmc_cell_set_fill
|
||||
public :: openmc_cell_set_temperature
|
||||
public :: openmc_energy_filter_get_bins
|
||||
public :: openmc_energy_filter_set_bins
|
||||
public :: openmc_extend_filters
|
||||
public :: openmc_extend_materials
|
||||
public :: openmc_extend_tallies
|
||||
public :: openmc_filter_get_id
|
||||
public :: openmc_filter_get_type
|
||||
public :: openmc_filter_set_id
|
||||
public :: openmc_filter_set_type
|
||||
public :: openmc_finalize
|
||||
public :: openmc_find
|
||||
public :: openmc_get_cell_index
|
||||
public :: openmc_get_keff
|
||||
public :: openmc_get_filter_index
|
||||
public :: openmc_get_filter_next_id
|
||||
public :: openmc_get_material_index
|
||||
public :: openmc_get_nuclide_index
|
||||
public :: openmc_get_tally_index
|
||||
public :: openmc_hard_reset
|
||||
public :: openmc_init
|
||||
public :: openmc_load_nuclide
|
||||
public :: openmc_material_add_nuclide
|
||||
public :: openmc_material_get_id
|
||||
public :: openmc_material_get_densities
|
||||
public :: openmc_material_set_density
|
||||
public :: openmc_material_set_densities
|
||||
public :: openmc_material_set_id
|
||||
public :: openmc_material_filter_get_bins
|
||||
public :: openmc_material_filter_set_bins
|
||||
public :: openmc_mesh_filter_set_mesh
|
||||
public :: openmc_nuclide_name
|
||||
public :: openmc_plot_geometry
|
||||
public :: openmc_reset
|
||||
public :: openmc_run
|
||||
public :: openmc_tally_get_id
|
||||
public :: openmc_tally_get_filters
|
||||
public :: openmc_tally_get_nuclides
|
||||
public :: openmc_tally_results
|
||||
public :: openmc_tally_set_filters
|
||||
public :: openmc_tally_set_id
|
||||
public :: openmc_tally_set_nuclides
|
||||
public :: openmc_tally_set_scores
|
||||
public :: openmc_tally_set_type
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! OPENMC_CELL_SET_TEMPERATURE sets the temperature of a cell
|
||||
! OPENMC_FINALIZE frees up memory by deallocating arrays and resetting global
|
||||
! variables
|
||||
!===============================================================================
|
||||
|
||||
function openmc_cell_set_temperature(id, T, instance) result(err) bind(C)
|
||||
integer(C_INT32_T), value, intent(in) :: id ! id of cell
|
||||
real(C_DOUBLE), value, intent(in) :: T
|
||||
integer(C_INT32_T), optional, intent(in) :: instance
|
||||
integer(C_INT) :: err
|
||||
subroutine openmc_finalize() bind(C)
|
||||
|
||||
integer :: i, n
|
||||
integer :: err
|
||||
|
||||
err = -1
|
||||
if (allocated(cells)) then
|
||||
if (cell_dict % has_key(id)) then
|
||||
i = cell_dict % get_key(id)
|
||||
associate (c => cells(i))
|
||||
if (allocated(c % sqrtkT)) then
|
||||
n = size(c % sqrtkT)
|
||||
if (present(instance) .and. n > 1) then
|
||||
if (instance >= 0 .and. instance < n) then
|
||||
c % sqrtkT(instance + 1) = sqrt(K_BOLTZMANN * T)
|
||||
err = 0
|
||||
end if
|
||||
else
|
||||
c % sqrtkT(:) = sqrt(K_BOLTZMANN * T)
|
||||
err = 0
|
||||
end if
|
||||
end if
|
||||
end associate
|
||||
end if
|
||||
end if
|
||||
end function openmc_cell_set_temperature
|
||||
! Clear results
|
||||
call openmc_reset()
|
||||
|
||||
! Reset global variables
|
||||
assume_separate = .false.
|
||||
check_overlaps = .false.
|
||||
confidence_intervals = .false.
|
||||
create_fission_neutrons = .true.
|
||||
energy_cutoff = ZERO
|
||||
energy_max_neutron = INFINITY
|
||||
energy_min_neutron = ZERO
|
||||
entropy_on = .false.
|
||||
gen_per_batch = 1
|
||||
keff = ONE
|
||||
legendre_to_tabular = .true.
|
||||
legendre_to_tabular_points = 33
|
||||
n_batch_interval = 1
|
||||
n_particles = 0
|
||||
n_source_points = 0
|
||||
n_state_points = 0
|
||||
n_tallies = 0
|
||||
output_summary = .true.
|
||||
output_tallies = .true.
|
||||
particle_restart_run = .false.
|
||||
pred_batches = .false.
|
||||
reduce_tallies = .true.
|
||||
res_scat_on = .false.
|
||||
res_scat_method = RES_SCAT_ARES
|
||||
res_scat_energy_min = 0.01_8
|
||||
res_scat_energy_max = 1000.0_8
|
||||
restart_run = .false.
|
||||
root_universe = -1
|
||||
run_CE = .true.
|
||||
run_mode = NONE
|
||||
satisfy_triggers = .false.
|
||||
seed = 1_8
|
||||
source_latest = .false.
|
||||
source_separate = .false.
|
||||
source_write = .true.
|
||||
survival_biasing = .false.
|
||||
temperature_default = 293.6_8
|
||||
temperature_method = TEMPERATURE_NEAREST
|
||||
temperature_multipole = .false.
|
||||
temperature_range = [ZERO, ZERO]
|
||||
temperature_tolerance = 10.0_8
|
||||
total_gen = 0
|
||||
trigger_on = .false.
|
||||
ufs = .false.
|
||||
urr_ptables_on = .true.
|
||||
verbosity = 7
|
||||
weight_cutoff = 0.25_8
|
||||
weight_survive = ONE
|
||||
write_all_tracks = .false.
|
||||
write_initial_source = .false.
|
||||
|
||||
! Deallocate arrays
|
||||
call free_memory()
|
||||
|
||||
! Release compound datatypes
|
||||
call h5tclose_f(hdf5_bank_t, err)
|
||||
|
||||
! Close FORTRAN interface.
|
||||
call h5close_f(err)
|
||||
|
||||
#ifdef MPI
|
||||
! Free all MPI types
|
||||
call MPI_TYPE_FREE(MPI_BANK, err)
|
||||
#endif
|
||||
|
||||
end subroutine openmc_finalize
|
||||
|
||||
!===============================================================================
|
||||
! OPENMC_FIND determines the ID or a cell or material at a given point in space
|
||||
!===============================================================================
|
||||
|
||||
subroutine openmc_find(xyz, rtype, id, instance) bind(C)
|
||||
function openmc_find(xyz, rtype, id, instance) result(err) bind(C)
|
||||
real(C_DOUBLE), intent(in) :: xyz(3) ! Cartesian point
|
||||
integer(C_INT), intent(in), value :: rtype ! 1 for cell, 2 for material
|
||||
integer(C_INT32_T), intent(out) :: id
|
||||
integer(C_INT32_T), intent(out) :: instance
|
||||
integer(C_INT) :: err
|
||||
|
||||
logical :: found
|
||||
type(Particle) :: p
|
||||
|
|
@ -89,6 +184,8 @@ contains
|
|||
|
||||
id = -1
|
||||
instance = -1
|
||||
err = E_UNASSIGNED
|
||||
|
||||
if (found) then
|
||||
if (rtype == 1) then
|
||||
id = cells(p % coord(p % n_coord) % cell) % id
|
||||
|
|
@ -100,202 +197,53 @@ contains
|
|||
end if
|
||||
end if
|
||||
instance = p % cell_instance - 1
|
||||
end if
|
||||
end subroutine openmc_find
|
||||
|
||||
!===============================================================================
|
||||
! OPENMC_LOAD_NUCLIDE loads a nuclide from the cross section library
|
||||
!===============================================================================
|
||||
|
||||
function openmc_load_nuclide(name) result(err) bind(C)
|
||||
character(kind=C_CHAR) :: name(*)
|
||||
integer(C_INT) :: err
|
||||
|
||||
integer :: n
|
||||
integer(HID_T) :: file_id
|
||||
integer(HID_T) :: group_id
|
||||
character(:), allocatable :: name_
|
||||
real(8) :: minmax(2) = [ZERO, INFINITY]
|
||||
type(VectorReal) :: temperature
|
||||
type(Nuclide), allocatable :: new_nuclides(:)
|
||||
|
||||
! Copy array of C_CHARs to normal Fortran string
|
||||
name_ = to_f_string(name)
|
||||
|
||||
err = -1
|
||||
if (.not. nuclide_dict % has_key(to_lower(name_))) then
|
||||
if (library_dict % has_key(to_lower(name_))) then
|
||||
! allocate extra space in nuclides array
|
||||
n = n_nuclides_total
|
||||
allocate(new_nuclides(n + 1))
|
||||
new_nuclides(1:n) = nuclides(:)
|
||||
call move_alloc(FROM=new_nuclides, TO=nuclides)
|
||||
n = n + 1
|
||||
|
||||
i_library = library_dict % get_key(to_lower(name_))
|
||||
|
||||
! Open file and make sure version is sufficient
|
||||
file_id = file_open(libraries(i_library) % path, 'r')
|
||||
call check_data_version(file_id)
|
||||
|
||||
! Read nuclide data from HDF5
|
||||
group_id = open_group(file_id, name_)
|
||||
call nuclides(n) % from_hdf5(group_id, temperature, &
|
||||
temperature_method, temperature_tolerance, minmax, &
|
||||
master)
|
||||
call close_group(group_id)
|
||||
call file_close(file_id)
|
||||
|
||||
! Add entry to nuclide dictionary
|
||||
call nuclide_dict % add_key(to_lower(name_), n)
|
||||
n_nuclides_total = n
|
||||
|
||||
! Assign resonant scattering data
|
||||
if (res_scat_on) call assign_0K_elastic_scattering(nuclides(n))
|
||||
|
||||
! Initialize nuclide grid
|
||||
call nuclides(n) % init_grid(energy_min_neutron, &
|
||||
energy_max_neutron, n_log_bins)
|
||||
|
||||
err = 0
|
||||
else
|
||||
err = -2
|
||||
end if
|
||||
err = 0
|
||||
else
|
||||
err = E_GEOMETRY
|
||||
call set_errmsg("Could not find cell/material at position (" // &
|
||||
trim(to_str(xyz(1))) // "," // trim(to_str(xyz(2))) // "," // &
|
||||
trim(to_str(xyz(3))) // ").")
|
||||
end if
|
||||
|
||||
end function openmc_load_nuclide
|
||||
end function openmc_find
|
||||
|
||||
!===============================================================================
|
||||
! OPENMC_MATERIAL_ADD_NUCLIDE
|
||||
! OPENMC_HARD_RESET reset tallies and timers as well as the pseudorandom
|
||||
! generator state
|
||||
!===============================================================================
|
||||
|
||||
function openmc_material_add_nuclide(id, name, density) result(err) bind(C)
|
||||
integer(C_INT32_T), value, intent(in) :: id
|
||||
character(kind=C_CHAR) :: name(*)
|
||||
real(C_DOUBLE), value, intent(in) :: density
|
||||
integer(C_INT) :: err
|
||||
subroutine openmc_hard_reset() bind(C)
|
||||
integer :: err
|
||||
|
||||
integer :: i, j, k, n
|
||||
integer :: err2
|
||||
real(8) :: awr
|
||||
integer, allocatable :: new_nuclide(:)
|
||||
real(8), allocatable :: new_density(:)
|
||||
character(:), allocatable :: name_
|
||||
! Reset all tallies and timers
|
||||
call openmc_reset()
|
||||
|
||||
name_ = to_f_string(name)
|
||||
! Reset total generations and keff guess
|
||||
keff = ONE
|
||||
total_gen = 0
|
||||
|
||||
err = -1
|
||||
if (allocated(materials)) then
|
||||
if (material_dict % has_key(id)) then
|
||||
i = material_dict % get_key(id)
|
||||
associate (m => materials(i))
|
||||
! Check if nuclide is already in material
|
||||
do j = 1, size(m % nuclide)
|
||||
k = m % nuclide(j)
|
||||
if (nuclides(k) % name == name_) then
|
||||
awr = nuclides(k) % awr
|
||||
m % density = m % density + density - m % atom_density(j)
|
||||
m % density_gpcc = m % density_gpcc + (density - &
|
||||
m % atom_density(j)) * awr * MASS_NEUTRON / N_AVOGADRO
|
||||
m % atom_density(j) = density
|
||||
err = 0
|
||||
end if
|
||||
end do
|
||||
|
||||
! If nuclide wasn't found, extend nuclide/density arrays
|
||||
if (err /= 0) then
|
||||
! If nuclide hasn't been loaded, load it now
|
||||
err2 = openmc_load_nuclide(name)
|
||||
|
||||
if (err2 /= -2) then
|
||||
! Extend arrays
|
||||
n = size(m % nuclide)
|
||||
allocate(new_nuclide(n + 1))
|
||||
new_nuclide(1:n) = m % nuclide
|
||||
call move_alloc(FROM=new_nuclide, TO=m % nuclide)
|
||||
|
||||
allocate(new_density(n + 1))
|
||||
new_density(1:n) = m % atom_density
|
||||
call move_alloc(FROM=new_density, TO=m % atom_density)
|
||||
|
||||
! Append new nuclide/density
|
||||
k = nuclide_dict % get_key(to_lower(name_))
|
||||
m % nuclide(n + 1) = k
|
||||
m % atom_density(n + 1) = density
|
||||
m % density = m % density + density
|
||||
m % density_gpcc = m % density_gpcc + &
|
||||
density * nuclides(k) % awr * MASS_NEUTRON / N_AVOGADRO
|
||||
m % n_nuclides = n + 1
|
||||
|
||||
err = 0
|
||||
end if
|
||||
end if
|
||||
end associate
|
||||
end if
|
||||
end if
|
||||
|
||||
end function openmc_material_add_nuclide
|
||||
! Reset the random number generator state
|
||||
err = openmc_set_seed(1_8)
|
||||
end subroutine openmc_hard_reset
|
||||
|
||||
!===============================================================================
|
||||
! OPENMC_MATERIAL_GET_DENSITIES returns an array of nuclide densities in a
|
||||
! material
|
||||
!===============================================================================
|
||||
|
||||
function openmc_material_get_densities(id, ptr) result(n) bind(C)
|
||||
integer(C_INT32_T), intent(in), value :: id
|
||||
type(C_PTR), intent(out) :: ptr
|
||||
integer(C_INT) :: n
|
||||
|
||||
ptr = C_NULL_PTR
|
||||
n = 0
|
||||
if (allocated(materials)) then
|
||||
if (material_dict % has_key(id)) then
|
||||
i = material_dict % get_key(id)
|
||||
associate (m => materials(i))
|
||||
if (allocated(m % atom_density)) then
|
||||
ptr = C_LOC(m % atom_density(1))
|
||||
n = size(m % atom_density)
|
||||
end if
|
||||
end associate
|
||||
end if
|
||||
end if
|
||||
end function openmc_material_get_densities
|
||||
|
||||
!===============================================================================
|
||||
! OPENMC_MATERIAL_SET_DENSITY sets the total density of a material in atom/b-cm
|
||||
!===============================================================================
|
||||
|
||||
function openmc_material_set_density(id, density) result(err) bind(C)
|
||||
integer(C_INT32_T), value, intent(in) :: id
|
||||
real(C_DOUBLE), value, intent(in) :: density
|
||||
integer(C_INT) :: err
|
||||
|
||||
integer :: i
|
||||
|
||||
err = -1
|
||||
if (allocated(materials)) then
|
||||
if (material_dict % has_key(id)) then
|
||||
i = material_dict % get_key(id)
|
||||
associate (m => materials(i))
|
||||
err = m % set_density(density, nuclides)
|
||||
end associate
|
||||
end if
|
||||
end if
|
||||
end function openmc_material_set_density
|
||||
|
||||
!===============================================================================
|
||||
! OPENMC_RESET resets all tallies
|
||||
! OPENMC_RESET resets tallies and timers
|
||||
!===============================================================================
|
||||
|
||||
subroutine openmc_reset() bind(C)
|
||||
integer :: i
|
||||
|
||||
do i = 1, size(tallies)
|
||||
tallies(i) % n_realizations = 0
|
||||
if (allocated(tallies(i) % results)) then
|
||||
tallies(i) % results(:, :, :) = ZERO
|
||||
end if
|
||||
end do
|
||||
if (allocated(tallies)) then
|
||||
do i = 1, size(tallies)
|
||||
associate (t => tallies(i) % obj)
|
||||
t % active = .false.
|
||||
t % n_realizations = 0
|
||||
if (allocated(t % results)) then
|
||||
t % results(:, :, :) = ZERO
|
||||
end if
|
||||
end associate
|
||||
end do
|
||||
end if
|
||||
|
||||
! Reset global tallies
|
||||
n_realizations = 0
|
||||
|
|
@ -307,10 +255,6 @@ contains
|
|||
k_abs_tra = ZERO
|
||||
k_sum(:) = ZERO
|
||||
|
||||
! Turn off tally flags
|
||||
tallies_on = .false.
|
||||
active_batches = .false.
|
||||
|
||||
! Clear active tally lists
|
||||
call active_analog_tallies % clear()
|
||||
call active_tracklength_tallies % clear()
|
||||
|
|
@ -318,50 +262,61 @@ contains
|
|||
call active_collision_tallies % clear()
|
||||
call active_tallies % clear()
|
||||
|
||||
! Reset timers
|
||||
call time_total % reset()
|
||||
call time_total % reset()
|
||||
call time_initialize % reset()
|
||||
call time_read_xs % reset()
|
||||
call time_unionize % reset()
|
||||
call time_bank % reset()
|
||||
call time_bank_sample % reset()
|
||||
call time_bank_sendrecv % reset()
|
||||
call time_tallies % reset()
|
||||
call time_inactive % reset()
|
||||
call time_active % reset()
|
||||
call time_transport % reset()
|
||||
call time_finalize % reset()
|
||||
|
||||
end subroutine openmc_reset
|
||||
|
||||
!===============================================================================
|
||||
! OPENMC_TALLY_RESULTS returns a pointer to a tally results array along with its
|
||||
! shape. This allows a user to obtain in-memory tally results from Python
|
||||
! directly.
|
||||
! FREE_MEMORY deallocates and clears all global allocatable arrays in the
|
||||
! program
|
||||
!===============================================================================
|
||||
|
||||
subroutine openmc_tally_results(id, ptr, shape_) bind(C)
|
||||
integer(C_INT32_T), intent(in), value :: id
|
||||
type(C_PTR), intent(out) :: ptr
|
||||
integer(C_INT), intent(out) :: shape_(3)
|
||||
subroutine free_memory()
|
||||
|
||||
integer :: i
|
||||
use cmfd_header
|
||||
use mgxs_header
|
||||
use plot_header
|
||||
use sab_header
|
||||
use settings
|
||||
use source_header
|
||||
use surface_header
|
||||
use tally_derivative_header
|
||||
use trigger_header
|
||||
use volume_header
|
||||
|
||||
ptr = C_NULL_PTR
|
||||
if (allocated(tallies)) then
|
||||
if (tally_dict % has_key(id)) then
|
||||
i = tally_dict % get_key(id)
|
||||
if (allocated(tallies(i) % results)) then
|
||||
ptr = C_LOC(tallies(i) % results(1,1,1))
|
||||
shape_(:) = shape(tallies(i) % results)
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
end subroutine openmc_tally_results
|
||||
call free_memory_geometry()
|
||||
call free_memory_surfaces()
|
||||
call free_memory_material()
|
||||
call free_memory_plot()
|
||||
call free_memory_volume()
|
||||
call free_memory_simulation()
|
||||
call free_memory_nuclide()
|
||||
call free_memory_settings()
|
||||
call free_memory_mgxs()
|
||||
call free_memory_sab()
|
||||
call free_memory_source()
|
||||
call free_memory_mesh()
|
||||
call free_memory_tally()
|
||||
call free_memory_tally_filter()
|
||||
call free_memory_tally_derivative()
|
||||
call free_memory_bank()
|
||||
|
||||
function to_f_string(c_string) result(f_string)
|
||||
character(kind=C_CHAR), intent(in) :: c_string(*)
|
||||
character(:), allocatable :: f_string
|
||||
! Deallocate CMFD
|
||||
call deallocate_cmfd(cmfd)
|
||||
|
||||
integer :: i, n
|
||||
|
||||
! Determine length of original string
|
||||
n = 0
|
||||
do while (c_string(n + 1) /= C_NULL_CHAR)
|
||||
n = n + 1
|
||||
end do
|
||||
|
||||
! Copy C string character by character
|
||||
allocate(character(len=n) :: f_string)
|
||||
do i = 1, n
|
||||
f_string(i:i) = c_string(i)
|
||||
end do
|
||||
end function to_f_string
|
||||
end subroutine free_memory
|
||||
|
||||
end module openmc_api
|
||||
|
|
|
|||
|
|
@ -19,4 +19,34 @@ module bank_header
|
|||
integer(C_INT) :: particle ! particle type (neutron, photon, etc.)
|
||||
end type Bank
|
||||
|
||||
! Source and fission bank
|
||||
type(Bank), allocatable, target :: source_bank(:)
|
||||
type(Bank), allocatable, target :: fission_bank(:)
|
||||
#ifdef _OPENMP
|
||||
type(Bank), allocatable, target :: master_fission_bank(:)
|
||||
#endif
|
||||
|
||||
integer(8) :: n_bank ! # of sites in fission bank
|
||||
|
||||
!$omp threadprivate(fission_bank, n_bank)
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! FREE_MEMORY_BANK deallocates global arrays defined in this module
|
||||
!===============================================================================
|
||||
|
||||
subroutine free_memory_bank()
|
||||
|
||||
! Deallocate fission and source bank and entropy
|
||||
!$omp parallel
|
||||
if (allocated(fission_bank)) deallocate(fission_bank)
|
||||
!$omp end parallel
|
||||
#ifdef _OPENMP
|
||||
if (allocated(master_fission_bank)) deallocate(master_fission_bank)
|
||||
#endif
|
||||
if (allocated(source_bank)) deallocate(source_bank)
|
||||
|
||||
end subroutine free_memory_bank
|
||||
|
||||
end module bank_header
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ module cmfd_data
|
|||
! parameters for CMFD calculation.
|
||||
!==============================================================================
|
||||
|
||||
use cmfd_header, only: allocate_cmfd, cmfd, cmfd_coremap, &
|
||||
cmfd_downscatter, cmfd_tallies, dhat_reset
|
||||
use constants
|
||||
use tally_filter, only: MeshFilter
|
||||
use tally_filter_mesh, only: MeshFilter
|
||||
|
||||
implicit none
|
||||
private
|
||||
|
|
@ -20,9 +22,7 @@ contains
|
|||
|
||||
subroutine set_up_cmfd()
|
||||
|
||||
use cmfd_header, only: allocate_cmfd
|
||||
use constants, only: CMFD_NOACCEL
|
||||
use global, only: cmfd, cmfd_coremap, cmfd_downscatter
|
||||
|
||||
! Check for core map and set it up
|
||||
if ((cmfd_coremap) .and. (cmfd%mat_dim == CMFD_NOACCEL)) call set_coremap()
|
||||
|
|
@ -56,12 +56,9 @@ contains
|
|||
IN_BACK, IN_FRONT, IN_BOTTOM, IN_TOP, CMFD_NOACCEL, &
|
||||
ZERO, ONE, TINY_BIT
|
||||
use error, only: fatal_error
|
||||
use global, only: cmfd, n_cmfd_tallies, cmfd_tallies, meshes, &
|
||||
filters, filter_matches
|
||||
use mesh, only: mesh_indices_to_bin
|
||||
use mesh_header, only: RegularMesh
|
||||
use mesh_header, only: RegularMesh, meshes
|
||||
use string, only: to_str
|
||||
use tally_header, only: TallyObject
|
||||
use tally_filter_header, only: filters, filter_matches
|
||||
|
||||
integer :: nx ! number of mesh cells in x direction
|
||||
integer :: ny ! number of mesh cells in y direction
|
||||
|
|
@ -76,7 +73,6 @@ contains
|
|||
integer :: ital ! tally object index
|
||||
integer :: ijk(3) ! indices for mesh cell
|
||||
integer :: score_index ! index to pull from tally object
|
||||
integer :: i_mesh ! index in meshes array
|
||||
integer :: i_filt ! index in filters array
|
||||
integer :: i_filter_mesh ! index for mesh filter
|
||||
integer :: i_filter_ein ! index for incoming energy filter
|
||||
|
|
@ -85,7 +81,6 @@ contains
|
|||
integer :: stride_surf ! stride for surface filter
|
||||
logical :: energy_filters! energy filters present
|
||||
real(8) :: flux ! temp variable for flux
|
||||
type(TallyObject), pointer :: t ! pointer for tally object
|
||||
type(RegularMesh), pointer :: m ! pointer for mesh object
|
||||
|
||||
! Extract spatial and energy indices from object
|
||||
|
|
@ -99,13 +94,14 @@ contains
|
|||
cmfd % openmc_src = ZERO
|
||||
|
||||
! Associate tallies and mesh
|
||||
t => cmfd_tallies(1)
|
||||
i_filt = t % filter(t % find_filter(FILTER_MESH))
|
||||
associate (t => cmfd_tallies(1) % obj)
|
||||
i_filt = t % filter(t % find_filter(FILTER_MESH))
|
||||
end associate
|
||||
|
||||
select type(filt => filters(i_filt) % obj)
|
||||
type is (MeshFilter)
|
||||
i_mesh = filt % mesh
|
||||
m => meshes(filt % mesh)
|
||||
end select
|
||||
m => meshes(i_mesh)
|
||||
|
||||
! Set mesh widths
|
||||
cmfd % hxyz(1,:,:,:) = m % width(1) ! set x width
|
||||
|
|
@ -115,16 +111,15 @@ contains
|
|||
cmfd % keff_bal = ZERO
|
||||
|
||||
! Begin loop around tallies
|
||||
TAL: do ital = 1, n_cmfd_tallies
|
||||
TAL: do ital = 1, size(cmfd_tallies)
|
||||
|
||||
! Associate tallies and mesh
|
||||
t => cmfd_tallies(ital)
|
||||
associate (t => cmfd_tallies(ital) % obj)
|
||||
i_filt = t % filter(t % find_filter(FILTER_MESH))
|
||||
select type(filt => filters(i_filt) % obj)
|
||||
type is (MeshFilter)
|
||||
i_mesh = filt % mesh
|
||||
m => meshes(filt % mesh)
|
||||
end select
|
||||
m => meshes(i_mesh)
|
||||
|
||||
! Check for energy filters
|
||||
energy_filters = (t % find_filter(FILTER_ENERGYIN) > 0)
|
||||
|
|
@ -166,7 +161,7 @@ contains
|
|||
|
||||
! Get bin number for mesh indices
|
||||
filter_matches(i_filter_mesh) % bins % data(1) = &
|
||||
mesh_indices_to_bin(m,ijk)
|
||||
m % get_bin_from_indices(ijk)
|
||||
|
||||
! Apply energy in filter
|
||||
if (energy_filters) then
|
||||
|
|
@ -217,7 +212,7 @@ contains
|
|||
|
||||
! Get bin number for mesh indices
|
||||
filter_matches(i_filter_mesh) % bins % data(1) = &
|
||||
mesh_indices_to_bin(m,ijk)
|
||||
m % get_bin_from_indices(ijk)
|
||||
|
||||
if (energy_filters) then
|
||||
! Apply energy in filter
|
||||
|
|
@ -266,7 +261,7 @@ contains
|
|||
|
||||
! Get the bin for this mesh cell
|
||||
filter_matches(i_filter_mesh) % bins % data(1) = &
|
||||
mesh_indices_to_bin(m, (/ i, j, k /))
|
||||
m % get_bin_from_indices([ i, j, k ])
|
||||
|
||||
score_index = 1
|
||||
do l = 1, size(t % filter)
|
||||
|
|
@ -321,13 +316,13 @@ contains
|
|||
|
||||
end do ZLOOP
|
||||
|
||||
end associate
|
||||
end do TAL
|
||||
|
||||
! Normalize openmc source distribution
|
||||
cmfd % openmc_src = cmfd % openmc_src/sum(cmfd % openmc_src)*cmfd%norm
|
||||
|
||||
! Nullify all pointers
|
||||
if (associated(t)) nullify(t)
|
||||
if (associated(m)) nullify(m)
|
||||
|
||||
end subroutine compute_xs
|
||||
|
|
@ -339,7 +334,6 @@ contains
|
|||
subroutine set_coremap()
|
||||
|
||||
use constants, only: CMFD_NOACCEL
|
||||
use global, only: cmfd
|
||||
|
||||
integer :: counter=1 ! counter for unique fuel assemblies
|
||||
integer :: nx ! number of mesh cells in x direction
|
||||
|
|
@ -400,7 +394,7 @@ contains
|
|||
subroutine neutron_balance()
|
||||
|
||||
use constants, only: ONE, ZERO, CMFD_NOACCEL, CMFD_NORES
|
||||
use global, only: cmfd, keff, current_batch
|
||||
use simulation_header, only: keff, current_batch
|
||||
|
||||
integer :: nx ! number of mesh cells in x direction
|
||||
integer :: ny ! number of mesh cells in y direction
|
||||
|
|
@ -509,7 +503,6 @@ contains
|
|||
subroutine compute_dtilde()
|
||||
|
||||
use constants, only: CMFD_NOACCEL, ZERO_FLUX, TINY_BIT
|
||||
use global, only: cmfd, cmfd_coremap
|
||||
|
||||
integer :: nx ! maximum number of cells in x direction
|
||||
integer :: ny ! maximum number of cells in y direction
|
||||
|
|
@ -651,7 +644,6 @@ contains
|
|||
subroutine compute_dhat()
|
||||
|
||||
use constants, only: CMFD_NOACCEL, ZERO
|
||||
use global, only: cmfd, cmfd_coremap, dhat_reset
|
||||
use output, only: write_message
|
||||
use string, only: to_str
|
||||
|
||||
|
|
@ -801,7 +793,6 @@ contains
|
|||
function get_reflector_albedo(l, g, i, j, k)
|
||||
|
||||
use constants, only: ONE
|
||||
use global, only: cmfd
|
||||
|
||||
real(8) :: get_reflector_albedo ! reflector albedo
|
||||
integer, intent(in) :: i ! iteration counter for x
|
||||
|
|
@ -840,7 +831,6 @@ contains
|
|||
subroutine compute_effective_downscatter()
|
||||
|
||||
use constants, only: ZERO, CMFD_NOACCEL
|
||||
use global, only: cmfd
|
||||
|
||||
integer :: nx ! number of mesh cells in x direction
|
||||
integer :: ny ! number of mesh cells in y direction
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ module cmfd_execute
|
|||
! cross section generation, diffusion calculation, and source re-weighting
|
||||
!==============================================================================
|
||||
|
||||
use global
|
||||
use cmfd_header
|
||||
use settings
|
||||
use simulation_header
|
||||
|
||||
implicit none
|
||||
private
|
||||
|
|
@ -63,10 +65,6 @@ contains
|
|||
|
||||
subroutine cmfd_init_batch()
|
||||
|
||||
use global, only: cmfd_begin, cmfd_on, &
|
||||
cmfd_reset, cmfd_run, &
|
||||
current_batch
|
||||
|
||||
! Check to activate CMFD diffusion and possible feedback
|
||||
! this guarantees that when cmfd begins at least one batch of tallies are
|
||||
! accumulated
|
||||
|
|
@ -91,7 +89,6 @@ contains
|
|||
subroutine calc_fission_source()
|
||||
|
||||
use constants, only: CMFD_NOACCEL, ZERO, TWO
|
||||
use global, only: cmfd, cmfd_coremap, entropy_on, current_batch
|
||||
use message_passing
|
||||
use string, only: to_str
|
||||
|
||||
|
|
@ -108,6 +105,9 @@ contains
|
|||
real(8) :: hxyz(3) ! cell dimensions of current ijk cell
|
||||
real(8) :: vol ! volume of cell
|
||||
real(8),allocatable :: source(:,:,:,:) ! tmp source array for entropy
|
||||
#ifdef MPI
|
||||
integer :: mpi_err ! MPI error code
|
||||
#endif
|
||||
|
||||
! Get maximum of spatial and group indices
|
||||
nx = cmfd % indices(1)
|
||||
|
|
@ -211,11 +211,11 @@ contains
|
|||
subroutine cmfd_reweight(new_weights)
|
||||
|
||||
use algorithm, only: binary_search
|
||||
use bank_header, only: source_bank
|
||||
use constants, only: ZERO, ONE
|
||||
use error, only: warning, fatal_error
|
||||
use global, only: meshes, source_bank, work, n_user_meshes, cmfd
|
||||
use mesh_header, only: RegularMesh
|
||||
use mesh, only: count_bank_sites, get_mesh_indices
|
||||
use mesh, only: count_bank_sites
|
||||
use message_passing
|
||||
use string, only: to_str
|
||||
|
||||
|
|
@ -226,15 +226,17 @@ contains
|
|||
integer :: nz ! maximum number of cells in z direction
|
||||
integer :: ng ! maximum number of energy groups
|
||||
integer :: i ! iteration counter
|
||||
integer :: g ! index for group
|
||||
integer :: ijk(3) ! spatial bin location
|
||||
integer :: e_bin ! energy bin of source particle
|
||||
integer :: mesh_bin ! mesh bin of soruce particle
|
||||
integer :: n_groups ! number of energy groups
|
||||
real(8) :: norm ! normalization factor
|
||||
logical :: outside ! any source sites outside mesh
|
||||
logical :: in_mesh ! source site is inside mesh
|
||||
type(RegularMesh), pointer :: m ! point to mesh
|
||||
|
||||
! Associate pointer
|
||||
m => meshes(n_user_meshes + 1)
|
||||
#ifdef MPI
|
||||
integer :: mpi_err
|
||||
#endif
|
||||
|
||||
! Get maximum of spatial and group indices
|
||||
nx = cmfd % indices(1)
|
||||
|
|
@ -244,7 +246,7 @@ contains
|
|||
|
||||
! allocate arrays in cmfd object (can take out later extend to multigroup)
|
||||
if (.not.allocated(cmfd%sourcecounts)) then
|
||||
allocate(cmfd%sourcecounts(ng,nx,ny,nz))
|
||||
allocate(cmfd%sourcecounts(ng, nx*ny*nz))
|
||||
cmfd % sourcecounts = 0
|
||||
end if
|
||||
if (.not.allocated(cmfd % weightfactors)) then
|
||||
|
|
@ -259,9 +261,8 @@ contains
|
|||
cmfd%weightfactors = ONE
|
||||
|
||||
! Count bank sites in mesh and reverse due to egrid structure
|
||||
call count_bank_sites(m, source_bank, cmfd%sourcecounts, cmfd % egrid, &
|
||||
sites_outside=outside, size_bank=work)
|
||||
cmfd % sourcecounts = cmfd%sourcecounts(ng:1:-1,:,:,:)
|
||||
call count_bank_sites(cmfd_mesh, source_bank, cmfd%sourcecounts, &
|
||||
cmfd % egrid, sites_outside=outside, size_bank=work)
|
||||
|
||||
! Check for sites outside of the mesh
|
||||
if (master .and. outside) then
|
||||
|
|
@ -270,10 +271,21 @@ contains
|
|||
|
||||
! Have master compute weight factors (watch for 0s)
|
||||
if (master) then
|
||||
where(cmfd % cmfd_src > ZERO .and. cmfd % sourcecounts > ZERO)
|
||||
cmfd % weightfactors = cmfd % cmfd_src/sum(cmfd % cmfd_src)* &
|
||||
sum(cmfd % sourcecounts) / cmfd % sourcecounts
|
||||
end where
|
||||
! Calculate normalization factor
|
||||
norm = sum(cmfd % sourcecounts) / sum(cmfd % cmfd_src)
|
||||
|
||||
do mesh_bin = 1, nx*ny*nz
|
||||
call cmfd_mesh % get_indices_from_bin(mesh_bin, ijk)
|
||||
do g = 1, ng
|
||||
if (cmfd % sourcecounts(ng - g + 1, mesh_bin) > ZERO) then
|
||||
if (cmfd % cmfd_src(g,ijk(1),ijk(2),ijk(3)) > ZERO) then
|
||||
cmfd % weightfactors(g,ijk(1),ijk(2),ijk(3)) = &
|
||||
cmfd % cmfd_src(g,ijk(1),ijk(2),ijk(3)) * norm &
|
||||
/ cmfd % sourcecounts(ng - g + 1, mesh_bin)
|
||||
end if
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
end if
|
||||
|
||||
if (.not. cmfd_feedback) return
|
||||
|
|
@ -289,7 +301,7 @@ contains
|
|||
do i = 1, int(work,4)
|
||||
|
||||
! Determine spatial bin
|
||||
call get_mesh_indices(m, source_bank(i) % xyz, ijk, in_mesh)
|
||||
call cmfd_mesh % get_indices(source_bank(i) % xyz, ijk, in_mesh)
|
||||
|
||||
! Determine energy bin
|
||||
n_groups = size(cmfd % egrid) - 1
|
||||
|
|
@ -313,8 +325,7 @@ contains
|
|||
|
||||
! Reweight particle
|
||||
source_bank(i) % wgt = source_bank(i) % wgt * &
|
||||
cmfd % weightfactors(e_bin, ijk(1), ijk(2), ijk(3))
|
||||
|
||||
cmfd % weightfactors(e_bin, ijk(1), ijk(2), ijk(3))
|
||||
end do
|
||||
|
||||
end subroutine cmfd_reweight
|
||||
|
|
@ -325,8 +336,6 @@ contains
|
|||
|
||||
function get_matrix_idx(g, i, j, k, ng, nx, ny) result (matidx)
|
||||
|
||||
use global, only: cmfd, cmfd_coremap
|
||||
|
||||
integer :: matidx ! the index location in matrix
|
||||
integer, intent(in) :: i ! current x index
|
||||
integer, intent(in) :: j ! current y index
|
||||
|
|
@ -357,7 +366,6 @@ contains
|
|||
|
||||
subroutine cmfd_tally_reset()
|
||||
|
||||
use global, only: cmfd_tallies
|
||||
use output, only: write_message
|
||||
|
||||
integer :: i ! loop counter
|
||||
|
|
@ -367,8 +375,8 @@ contains
|
|||
|
||||
! Reset CMFD tallies
|
||||
do i = 1, size(cmfd_tallies)
|
||||
cmfd_tallies(i) % n_realizations = 0
|
||||
cmfd_tallies(i) % results(:,:,:) = ZERO
|
||||
cmfd_tallies(i) % obj % n_realizations = 0
|
||||
cmfd_tallies(i) % obj % results(:,:,:) = ZERO
|
||||
end do
|
||||
|
||||
end subroutine cmfd_tally_reset
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
module cmfd_header
|
||||
|
||||
use constants, only: CMFD_NOACCEL, ZERO, ONE
|
||||
use mesh_header, only: RegularMesh
|
||||
use set_header, only: SetInt
|
||||
use tally_header, only: TallyContainer
|
||||
use timer_header, only: Timer
|
||||
|
||||
implicit none
|
||||
private
|
||||
|
|
@ -49,7 +53,7 @@ module cmfd_header
|
|||
real(8), allocatable :: openmc_src(:,:,:,:)
|
||||
|
||||
! Source sites in each mesh box
|
||||
real(8), allocatable :: sourcecounts(:,:,:,:)
|
||||
real(8), allocatable :: sourcecounts(:,:)
|
||||
|
||||
! Weight adjustment factors
|
||||
real(8), allocatable :: weightfactors(:,:,:,:)
|
||||
|
|
@ -88,6 +92,67 @@ module cmfd_header
|
|||
|
||||
end type cmfd_type
|
||||
|
||||
! Main object
|
||||
type(cmfd_type), public :: cmfd
|
||||
|
||||
type(RegularMesh), public, pointer :: cmfd_mesh => null()
|
||||
|
||||
! Pointers for different tallies
|
||||
type(TallyContainer), public, pointer :: cmfd_tallies(:) => null()
|
||||
|
||||
! Timing objects
|
||||
type(Timer), public :: time_cmfd ! timer for whole cmfd calculation
|
||||
type(Timer), public :: time_cmfdbuild ! timer for matrix build
|
||||
type(Timer), public :: time_cmfdsolve ! timer for solver
|
||||
|
||||
! Flag for active core map
|
||||
logical, public :: cmfd_coremap = .false.
|
||||
|
||||
! Flag to reset dhats to zero
|
||||
logical, public :: dhat_reset = .false.
|
||||
|
||||
! Flag to activate neutronic feedback via source weights
|
||||
logical, public :: cmfd_feedback = .false.
|
||||
|
||||
! Adjoint method type
|
||||
character(len=10), public :: cmfd_adjoint_type = 'physical'
|
||||
|
||||
! Number of incomplete ilu factorization levels
|
||||
integer, public :: cmfd_ilu_levels = 1
|
||||
|
||||
! Batch to begin cmfd
|
||||
integer, public :: cmfd_begin = 1
|
||||
|
||||
! Tally reset list
|
||||
integer, public :: n_cmfd_resets
|
||||
type(SetInt), public :: cmfd_reset
|
||||
|
||||
! Compute effective downscatter cross section
|
||||
logical, public :: cmfd_downscatter = .false.
|
||||
|
||||
! Convergence monitoring
|
||||
logical, public :: cmfd_power_monitor = .false.
|
||||
|
||||
! Cmfd output
|
||||
logical, public :: cmfd_write_matrices = .false.
|
||||
|
||||
! Run an adjoint calculation (last batch only)
|
||||
logical, public :: cmfd_run_adjoint = .false.
|
||||
|
||||
! CMFD run logicals
|
||||
logical, public :: cmfd_on = .false.
|
||||
|
||||
! CMFD display info
|
||||
character(len=25), public :: cmfd_display = 'balance'
|
||||
|
||||
! Estimate of spectral radius of CMFD matrices and tolerances
|
||||
real(8), public :: cmfd_spectral = ZERO
|
||||
real(8), public :: cmfd_shift = 1.e6
|
||||
real(8), public :: cmfd_ktol = 1.e-8_8
|
||||
real(8), public :: cmfd_stol = 1.e-8_8
|
||||
real(8), public :: cmfd_atoli = 1.e-10_8
|
||||
real(8), public :: cmfd_rtoli = 1.e-5_8
|
||||
|
||||
contains
|
||||
|
||||
!==============================================================================
|
||||
|
|
@ -133,7 +198,7 @@ contains
|
|||
if (.not. allocated(this % openmc_src)) allocate(this % openmc_src(ng,nx,ny,nz))
|
||||
|
||||
! Allocate source weight modification vars
|
||||
if (.not. allocated(this % sourcecounts)) allocate(this % sourcecounts(ng,nx,ny,nz))
|
||||
if (.not. allocated(this % sourcecounts)) allocate(this % sourcecounts(ng,nx*ny*nz))
|
||||
if (.not. allocated(this % weightfactors)) allocate(this % weightfactors(ng,nx,ny,nz))
|
||||
|
||||
! Allocate batchwise parameters
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
module cmfd_input
|
||||
|
||||
use global
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use cmfd_header
|
||||
use mesh_header, only: mesh_dict
|
||||
use mgxs_header, only: energy_bins
|
||||
use tally
|
||||
use tally_header
|
||||
use timer_header
|
||||
|
||||
implicit none
|
||||
private
|
||||
|
|
@ -14,21 +21,9 @@ contains
|
|||
|
||||
subroutine configure_cmfd()
|
||||
|
||||
use cmfd_header, only: allocate_cmfd
|
||||
use message_passing, only: master
|
||||
|
||||
integer :: color ! color group of processor
|
||||
|
||||
! Read in cmfd input file
|
||||
call read_cmfd_xml()
|
||||
|
||||
! Assign color
|
||||
if (master) then
|
||||
color = 1
|
||||
else
|
||||
color = 2
|
||||
end if
|
||||
|
||||
! Initialize timers
|
||||
call time_cmfd % reset()
|
||||
call time_cmfdbuild % reset()
|
||||
|
|
@ -47,7 +42,6 @@ contains
|
|||
|
||||
use constants, only: ZERO, ONE
|
||||
use error, only: fatal_error, warning
|
||||
use global
|
||||
use output, only: write_message
|
||||
use string, only: to_lower
|
||||
use xml_interface
|
||||
|
|
@ -241,20 +235,19 @@ contains
|
|||
! There are 3 tally types:
|
||||
! 1: Only an energy in filter-> flux,total,p1 scatter
|
||||
! 2: Energy in and energy out filter-> nu-scatter,nu-fission
|
||||
! 3: Surface current
|
||||
! 3: Mesh current
|
||||
!===============================================================================
|
||||
|
||||
subroutine create_cmfd_tally(root)
|
||||
|
||||
use constants, only: MAX_LINE_LEN
|
||||
use error, only: fatal_error, warning
|
||||
use mesh_header, only: RegularMesh
|
||||
use mesh_header, only: RegularMesh, openmc_extend_meshes
|
||||
use string
|
||||
use tally, only: setup_active_cmfdtallies
|
||||
use tally_header, only: TallyObject
|
||||
use tally, only: openmc_tally_set_type
|
||||
use tally_header, only: openmc_extend_tallies
|
||||
use tally_filter_header
|
||||
use tally_filter
|
||||
use tally_initialize, only: add_tallies
|
||||
use xml_interface
|
||||
|
||||
type(XMLNode), intent(in) :: root ! XML root element
|
||||
|
|
@ -262,25 +255,28 @@ contains
|
|||
logical :: energy_filters
|
||||
integer :: i ! loop counter
|
||||
integer :: n ! size of arrays in mesh specification
|
||||
integer :: ng ! number of energy groups (default 1)
|
||||
integer(C_INT32_T) :: ng ! number of energy groups (default 1)
|
||||
integer :: n_filter ! number of filters
|
||||
integer :: i_filt ! index in filters array
|
||||
integer :: i_start, i_end
|
||||
integer :: i_filt_start, i_filt_end
|
||||
integer(C_INT32_T), allocatable :: filter_indices(:)
|
||||
integer(C_INT) :: err
|
||||
integer :: i_filt ! index in filters array
|
||||
integer :: filt_id
|
||||
integer :: iarray3(3) ! temp integer array
|
||||
real(8) :: rarray3(3) ! temp double array
|
||||
type(TallyObject), pointer :: t
|
||||
real(C_DOUBLE), allocatable :: energies(:)
|
||||
type(RegularMesh), pointer :: m
|
||||
type(XMLNode) :: node_mesh
|
||||
|
||||
! Set global variables if they are 0 (this can happen if there is no tally
|
||||
! file)
|
||||
if (n_meshes == 0) n_meshes = n_user_meshes + n_cmfd_meshes
|
||||
err = openmc_extend_meshes(1, i_start)
|
||||
|
||||
! Allocate mesh
|
||||
if (.not. allocated(meshes)) allocate(meshes(n_meshes))
|
||||
m => meshes(n_user_meshes+1)
|
||||
cmfd_mesh => meshes(i_start)
|
||||
m => meshes(i_start)
|
||||
|
||||
! Set mesh id
|
||||
m % id = n_user_meshes + 1
|
||||
m % id = i_start
|
||||
|
||||
! Set mesh type to rectangular
|
||||
m % type = LATTICE_RECT
|
||||
|
|
@ -374,71 +370,54 @@ contains
|
|||
m % volume_frac = ONE/real(product(m % dimension),8)
|
||||
|
||||
! Add mesh to dictionary
|
||||
call mesh_dict % add_key(m % id, n_user_meshes + 1)
|
||||
call mesh_dict % set(m % id, i_start)
|
||||
|
||||
! Determine number of filters
|
||||
energy_filters = check_for_node(node_mesh, "energy")
|
||||
n_cmfd_filters = merge(5, 3, energy_filters)
|
||||
n = merge(5, 3, energy_filters)
|
||||
|
||||
! Extend filters array so we can add CMFD filters
|
||||
call add_filters(n_cmfd_filters)
|
||||
err = openmc_extend_filters(n, i_filt_start, i_filt_end)
|
||||
|
||||
! Set up mesh filter
|
||||
i_filt = n_user_filters + 1
|
||||
allocate(MeshFilter :: filters(i_filt) % obj)
|
||||
select type (filt => filters(i_filt) % obj)
|
||||
type is (MeshFilter)
|
||||
filt % id = i_filt
|
||||
filt % n_bins = product(m % dimension)
|
||||
filt % mesh = n_user_meshes + 1
|
||||
! Add filter to dictionary
|
||||
call filter_dict % add_key(filt % id, i_filt)
|
||||
end select
|
||||
i_filt = i_filt_start
|
||||
err = openmc_filter_set_type(i_filt, C_CHAR_'mesh' // C_NULL_CHAR)
|
||||
call openmc_get_filter_next_id(filt_id)
|
||||
err = openmc_filter_set_id(i_filt, filt_id)
|
||||
err = openmc_mesh_filter_set_mesh(i_filt, i_start)
|
||||
|
||||
if (energy_filters) then
|
||||
! Read and set incoming energy mesh filter
|
||||
i_filt = i_filt + 1
|
||||
allocate(EnergyFilter :: filters(i_filt) % obj)
|
||||
select type (filt => filters(i_filt) % obj)
|
||||
type is (EnergyFilter)
|
||||
filt % id = i_filt
|
||||
ng = node_word_count(node_mesh, "energy")
|
||||
filt % n_bins = ng - 1
|
||||
allocate(filt % bins(ng))
|
||||
call get_node_array(node_mesh, "energy", filt % bins)
|
||||
! Add filter to dictionary
|
||||
call filter_dict % add_key(filt % id, i_filt)
|
||||
end select
|
||||
err = openmc_filter_set_type(i_filt, C_CHAR_'energy' // C_NULL_CHAR)
|
||||
call openmc_get_filter_next_id(filt_id)
|
||||
err = openmc_filter_set_id(i_filt, filt_id)
|
||||
|
||||
! Get energies and set bins
|
||||
ng = node_word_count(node_mesh, "energy")
|
||||
allocate(energies(ng))
|
||||
call get_node_array(node_mesh, "energy", energies)
|
||||
err = openmc_energy_filter_set_bins(i_filt, ng, energies)
|
||||
|
||||
! Read and set outgoing energy mesh filter
|
||||
i_filt = i_filt + 1
|
||||
allocate(EnergyoutFilter :: filters(i_filt) % obj)
|
||||
select type (filt => filters(i_filt) % obj)
|
||||
type is (EnergyoutFilter)
|
||||
filt % id = i_filt
|
||||
ng = node_word_count(node_mesh, "energy")
|
||||
filt % n_bins = ng - 1
|
||||
allocate(filt % bins(ng))
|
||||
call get_node_array(node_mesh, "energy", filt % bins)
|
||||
! Add filter to dictionary
|
||||
call filter_dict % add_key(filt % id, i_filt)
|
||||
end select
|
||||
err = openmc_filter_set_type(i_filt, C_CHAR_'energyout' // C_NULL_CHAR)
|
||||
call openmc_get_filter_next_id(filt_id)
|
||||
err = openmc_filter_set_id(i_filt, filt_id)
|
||||
err = openmc_energy_filter_set_bins(i_filt, ng, energies)
|
||||
end if
|
||||
|
||||
! Duplicate the mesh filter for the surface current tally since other
|
||||
! Duplicate the mesh filter for the mesh current tally since other
|
||||
! tallies use this filter and we need to change the dimension
|
||||
i_filt = i_filt + 1
|
||||
allocate(MeshFilter :: filters(i_filt) % obj)
|
||||
select type (filt => filters(i_filt) % obj)
|
||||
type is (MeshFilter)
|
||||
filt % id = i_filt
|
||||
! We need to increase the dimension by one since we also need
|
||||
! currents coming into and out of the boundary mesh cells.
|
||||
filt % n_bins = product(m % dimension + 1)
|
||||
filt % mesh = n_user_meshes + 1
|
||||
! Add filter to dictionary
|
||||
call filter_dict % add_key(filt % id, i_filt)
|
||||
end select
|
||||
err = openmc_filter_set_type(i_filt, C_CHAR_'mesh' // C_NULL_CHAR)
|
||||
call openmc_get_filter_next_id(filt_id)
|
||||
err = openmc_filter_set_id(i_filt, filt_id)
|
||||
err = openmc_mesh_filter_set_mesh(i_filt, i_start)
|
||||
|
||||
! We need to increase the dimension by one since we also need
|
||||
! currents coming into and out of the boundary mesh cells.
|
||||
filters(i_filt) % obj % n_bins = product(m % dimension + 1)
|
||||
|
||||
! Set up surface filter
|
||||
i_filt = i_filt + 1
|
||||
|
|
@ -458,32 +437,41 @@ contains
|
|||
end if
|
||||
filt % current = .true.
|
||||
! Add filter to dictionary
|
||||
call filter_dict % add_key(filt % id, i_filt)
|
||||
call filter_dict % set(filt % id, i_filt)
|
||||
end select
|
||||
|
||||
! Initialize filters
|
||||
do i = i_filt_start, i_filt_end
|
||||
select type (filt => filters(i) % obj)
|
||||
type is (SurfaceFilter)
|
||||
! Don't do anything
|
||||
class default
|
||||
call filt % initialize()
|
||||
end select
|
||||
end do
|
||||
|
||||
! Allocate tallies
|
||||
call add_tallies("cmfd", n_cmfd_tallies)
|
||||
err = openmc_extend_tallies(3, i_start, i_end)
|
||||
cmfd_tallies => tallies(i_start:i_end)
|
||||
|
||||
! Begin loop around tallies
|
||||
do i = 1, n_cmfd_tallies
|
||||
do i = 1, size(cmfd_tallies)
|
||||
! Allocate tally
|
||||
err = openmc_tally_set_type(i_start + i - 1, C_CHAR_'generic' // C_NULL_CHAR)
|
||||
|
||||
! Point t to tally variable
|
||||
t => cmfd_tallies(i)
|
||||
associate (t => cmfd_tallies(i) % obj)
|
||||
|
||||
! Set reset property
|
||||
if (check_for_node(root, "reset")) then
|
||||
call get_node_value(root, "reset", t % reset)
|
||||
end if
|
||||
|
||||
! Set the mesh filter index in the tally find_filter array
|
||||
n_filter = 1
|
||||
t % find_filter(FILTER_MESH) = n_filter
|
||||
|
||||
! Set the incoming energy mesh filter index in the tally find_filter
|
||||
! array
|
||||
n_filter = 1
|
||||
if (energy_filters) then
|
||||
n_filter = n_filter + 1
|
||||
t % find_filter(FILTER_ENERGYIN) = n_filter
|
||||
end if
|
||||
|
||||
! Set number of nucilde bins
|
||||
|
|
@ -492,7 +480,7 @@ contains
|
|||
t % n_nuclide_bins = 1
|
||||
|
||||
! Record tally id which is equivalent to loop number
|
||||
t % id = i_cmfd_tallies + i
|
||||
t % id = i_start + i - 1
|
||||
|
||||
if (i == 1) then
|
||||
|
||||
|
|
@ -506,11 +494,13 @@ contains
|
|||
t % type = TALLY_VOLUME
|
||||
|
||||
! Allocate and set filters
|
||||
allocate(t % filter(n_filter))
|
||||
t % filter(1) = n_user_filters + 1
|
||||
allocate(filter_indices(n_filter))
|
||||
filter_indices(1) = i_filt_start
|
||||
if (energy_filters) then
|
||||
t % filter(2) = n_user_filters + 2
|
||||
filter_indices(2) = i_filt_start + 1
|
||||
end if
|
||||
err = openmc_tally_set_filters(i_start + i - 1, n_filter, filter_indices)
|
||||
deallocate(filter_indices)
|
||||
|
||||
! Allocate scoring bins
|
||||
allocate(t % score_bins(3))
|
||||
|
|
@ -542,16 +532,17 @@ contains
|
|||
! array
|
||||
if (energy_filters) then
|
||||
n_filter = n_filter + 1
|
||||
t % find_filter(FILTER_ENERGYOUT) = n_filter
|
||||
end if
|
||||
|
||||
! Allocate and set indices in filters array
|
||||
allocate(t % filter(n_filter))
|
||||
t % filter(1) = n_user_filters + 1
|
||||
allocate(filter_indices(n_filter))
|
||||
filter_indices(1) = i_filt_start
|
||||
if (energy_filters) then
|
||||
t % filter(2) = n_user_filters + 2
|
||||
t % filter(3) = n_user_filters + 3
|
||||
filter_indices(2) = i_filt_start + 1
|
||||
filter_indices(3) = i_filt_start + 2
|
||||
end if
|
||||
err = openmc_tally_set_filters(i_start + i - 1, n_filter, filter_indices)
|
||||
deallocate(filter_indices)
|
||||
|
||||
! Allocate macro reactions
|
||||
allocate(t % score_bins(2))
|
||||
|
|
@ -576,15 +567,16 @@ contains
|
|||
|
||||
! Set the surface filter index in the tally find_filter array
|
||||
n_filter = n_filter + 1
|
||||
t % find_filter(FILTER_SURFACE) = n_filter
|
||||
|
||||
! Allocate and set filters
|
||||
allocate(t % filter(n_filter))
|
||||
t % filter(1) = n_user_filters + n_cmfd_filters - 1
|
||||
t % filter(n_filter) = n_user_filters + n_cmfd_filters
|
||||
allocate(filter_indices(n_filter))
|
||||
filter_indices(1) = i_filt_end - 1
|
||||
filter_indices(n_filter) = i_filt_end
|
||||
if (energy_filters) then
|
||||
t % filter(2) = n_user_filters + 2
|
||||
filter_indices(2) = i_filt_start + 1
|
||||
end if
|
||||
err = openmc_tally_set_filters(i_start + i - 1, n_filter, filter_indices)
|
||||
deallocate(filter_indices)
|
||||
|
||||
! Allocate macro reactions
|
||||
allocate(t % score_bins(1))
|
||||
|
|
@ -597,14 +589,14 @@ contains
|
|||
|
||||
! Set macro bins
|
||||
t % score_bins(1) = SCORE_CURRENT
|
||||
t % type = TALLY_SURFACE_CURRENT
|
||||
t % type = TALLY_MESH_CURRENT
|
||||
end if
|
||||
|
||||
end do
|
||||
! Make CMFD tallies active from the start
|
||||
t % active = .true.
|
||||
|
||||
! Put cmfd tallies into active tally array and turn tallies on
|
||||
call setup_active_cmfdtallies()
|
||||
tallies_on = .true.
|
||||
end associate
|
||||
end do
|
||||
|
||||
end subroutine create_cmfd_tally
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
module cmfd_loss_operator
|
||||
|
||||
use constants, only: CMFD_NOACCEL, ZERO
|
||||
use global, only: cmfd, cmfd_coremap
|
||||
use cmfd_header, only: cmfd, cmfd_coremap
|
||||
use matrix_header, only: Matrix
|
||||
|
||||
implicit none
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
module cmfd_prod_operator
|
||||
|
||||
use constants, only: CMFD_NOACCEL
|
||||
use global, only: cmfd, cmfd_coremap
|
||||
use cmfd_header, only: cmfd, cmfd_coremap
|
||||
use matrix_header, only: Matrix
|
||||
|
||||
implicit none
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ contains
|
|||
|
||||
subroutine cmfd_solver_execute(adjoint)
|
||||
|
||||
use global, only: cmfd_adjoint_type, time_cmfdbuild, time_cmfdsolve
|
||||
use cmfd_header, only: cmfd_adjoint_type, time_cmfdbuild, time_cmfdsolve
|
||||
|
||||
logical, optional, intent(in) :: adjoint ! adjoint calc
|
||||
|
||||
|
|
@ -100,8 +100,8 @@ contains
|
|||
subroutine init_data(adjoint)
|
||||
|
||||
use constants, only: ONE, ZERO
|
||||
use global, only: cmfd_shift, keff, cmfd_ktol, cmfd_stol, &
|
||||
cmfd_write_matrices
|
||||
use cmfd_header, only: cmfd_shift, cmfd_ktol, cmfd_stol, cmfd_write_matrices
|
||||
use simulation_header, only: keff
|
||||
|
||||
logical, intent(in) :: adjoint
|
||||
|
||||
|
|
@ -167,7 +167,7 @@ contains
|
|||
subroutine compute_adjoint()
|
||||
|
||||
use error, only: fatal_error
|
||||
use global, only: cmfd_write_matrices
|
||||
use cmfd_header, only: cmfd_write_matrices
|
||||
|
||||
! Transpose matrices
|
||||
loss = loss % transpose()
|
||||
|
|
@ -190,7 +190,7 @@ contains
|
|||
|
||||
use constants, only: ONE
|
||||
use error, only: fatal_error
|
||||
use global, only: cmfd, cmfd_atoli, cmfd_rtoli
|
||||
use cmfd_header, only: cmfd, cmfd_atoli, cmfd_rtoli
|
||||
|
||||
integer :: i ! iteration counter
|
||||
integer :: innerits ! # of inner iterations
|
||||
|
|
@ -304,7 +304,7 @@ contains
|
|||
use, intrinsic :: ISO_FORTRAN_ENV
|
||||
|
||||
use constants, only: ONE, ZERO
|
||||
use global, only: cmfd_power_monitor
|
||||
use cmfd_header, only: cmfd_power_monitor
|
||||
use message_passing, only: master
|
||||
|
||||
integer, intent(in) :: iter ! outer iteration number
|
||||
|
|
@ -346,7 +346,7 @@ contains
|
|||
|
||||
use constants, only: ONE, ZERO
|
||||
use error, only: fatal_error
|
||||
use global, only: cmfd, cmfd_spectral
|
||||
use cmfd_header, only: cmfd, cmfd_spectral
|
||||
|
||||
type(Matrix), intent(inout) :: A ! coefficient matrix
|
||||
type(Vector), intent(inout) :: b ! right hand side vector
|
||||
|
|
@ -452,7 +452,7 @@ contains
|
|||
|
||||
use constants, only: ONE, ZERO
|
||||
use error, only: fatal_error
|
||||
use global, only: cmfd, cmfd_spectral
|
||||
use cmfd_header, only: cmfd, cmfd_spectral
|
||||
|
||||
type(Matrix), intent(inout) :: A ! coefficient matrix
|
||||
type(Vector), intent(inout) :: b ! right hand side vector
|
||||
|
|
@ -597,7 +597,7 @@ contains
|
|||
|
||||
use constants, only: ONE, ZERO
|
||||
use error, only: fatal_error
|
||||
use global, only: cmfd, cmfd_spectral
|
||||
use cmfd_header, only: cmfd, cmfd_spectral
|
||||
|
||||
type(Matrix), intent(inout) :: A ! coefficient matrix
|
||||
type(Vector), intent(inout) :: b ! right hand side vector
|
||||
|
|
@ -693,7 +693,8 @@ contains
|
|||
|
||||
subroutine extract_results()
|
||||
|
||||
use global, only: cmfd, cmfd_write_matrices, current_batch
|
||||
use cmfd_header, only: cmfd, cmfd_write_matrices
|
||||
use simulation_header, only: current_batch
|
||||
|
||||
character(len=25) :: filename ! name of file to write data
|
||||
integer :: n ! problem size
|
||||
|
|
@ -750,7 +751,7 @@ contains
|
|||
|
||||
subroutine matrix_to_indices(irow, g, i, j, k, ng, nx, ny, nz)
|
||||
|
||||
use global, only: cmfd, cmfd_coremap
|
||||
use cmfd_header, only: cmfd, cmfd_coremap
|
||||
|
||||
integer, intent(out) :: i ! iteration counter for x
|
||||
integer, intent(out) :: j ! iteration counter for y
|
||||
|
|
|
|||
|
|
@ -302,7 +302,8 @@ module constants
|
|||
! Tally type
|
||||
integer, parameter :: &
|
||||
TALLY_VOLUME = 1, &
|
||||
TALLY_SURFACE_CURRENT = 2
|
||||
TALLY_MESH_CURRENT = 2, &
|
||||
TALLY_SURFACE = 3
|
||||
|
||||
! Tally estimator types
|
||||
integer, parameter :: &
|
||||
|
|
@ -332,7 +333,7 @@ module constants
|
|||
SCORE_FISSION = -10, & ! fission rate
|
||||
SCORE_NU_FISSION = -11, & ! neutron production rate
|
||||
SCORE_KAPPA_FISSION = -12, & ! fission energy production rate
|
||||
SCORE_CURRENT = -13, & ! partial current
|
||||
SCORE_CURRENT = -13, & ! current
|
||||
SCORE_FLUX_YN = -14, & ! angular moment of flux
|
||||
SCORE_TOTAL_YN = -15, & ! angular moment of total reaction rate
|
||||
SCORE_SCATTER_YN = -16, & ! angular flux-weighted scattering moment (0:N)
|
||||
|
|
@ -366,7 +367,7 @@ module constants
|
|||
integer, parameter :: NO_BIN_FOUND = -1
|
||||
|
||||
! Tally filter and map types
|
||||
integer, parameter :: N_FILTER_TYPES = 15
|
||||
integer, parameter :: N_FILTER_TYPES = 16
|
||||
integer, parameter :: &
|
||||
FILTER_UNIVERSE = 1, &
|
||||
FILTER_MATERIAL = 2, &
|
||||
|
|
@ -382,7 +383,8 @@ module constants
|
|||
FILTER_AZIMUTHAL = 12, &
|
||||
FILTER_DELAYEDGROUP = 13, &
|
||||
FILTER_ENERGYFUNCTION = 14, &
|
||||
FILTER_PARTICLE = 15
|
||||
FILTER_CELLFROM = 15, &
|
||||
FILTER_PARTICLE = 16
|
||||
|
||||
! Mesh types
|
||||
integer, parameter :: &
|
||||
|
|
|
|||
|
|
@ -3,17 +3,19 @@ module cross_section
|
|||
use algorithm, only: binary_search
|
||||
use constants
|
||||
use error, only: fatal_error
|
||||
use global
|
||||
use list_header, only: ListElemInt
|
||||
use material_header, only: Material
|
||||
use material_header, only: Material, materials
|
||||
use math, only: faddeeva, w_derivative, broaden_wmp_polynomials
|
||||
use multipole_header, only: FORM_RM, FORM_MLBW, MP_EA, RM_RT, RM_RA, RM_RF, &
|
||||
MLBW_RT, MLBW_RX, MLBW_RA, MLBW_RF, FIT_T, FIT_A,&
|
||||
FIT_F, MultipoleArray
|
||||
use nuclide_header
|
||||
use particle_header, only: Particle
|
||||
use photon_header, only: micro_photon_xs, elements
|
||||
use random_lcg, only: prn, future_prn, prn_set_stream
|
||||
use sab_header, only: SAlphaBeta
|
||||
use sab_header, only: SAlphaBeta, sab_tables
|
||||
use settings
|
||||
use simulation_header
|
||||
|
||||
implicit none
|
||||
|
||||
|
|
|
|||
|
|
@ -7,438 +7,535 @@ module dict_header
|
|||
! pairs. This data structure is used to provide lookup features, e.g. cells and
|
||||
! surfaces by name.
|
||||
!
|
||||
! The original version was roughly based on capabilities in the 'flibs' open
|
||||
! source package. However, it was rewritten from scratch so that it could be
|
||||
! used stand-alone without relying on the implementation of lists. As with
|
||||
! lists, it was considered writing a single dictionary used unlimited
|
||||
! polymorphism, but again compiler support is spotty and doesn't always prevent
|
||||
! duplication of code.
|
||||
! The implementation is based on Algorithm D from Knuth Vol. 3 Sec. 6.4 (open
|
||||
! addressing with double hashing). Hash table sizes M are chosen such that M
|
||||
! and M - 2 are twin primes, which helps reduce clustering. The sequence of
|
||||
! twin primes used for the table sizes comes from
|
||||
! https://github.com/anholt/hash_table/blob/master/hash_table.c. These values
|
||||
! were selected so that the table would grow by approximately a factor of two
|
||||
! each time the maximum load factor is exceeded. An upper limit is placed on
|
||||
! the load factor to prevent exponential performance degradation as the number
|
||||
! of entries approaches the number of buckets.
|
||||
!===============================================================================
|
||||
|
||||
implicit none
|
||||
|
||||
integer, parameter, private :: HASH_SIZE = 4993
|
||||
integer, parameter, private :: HASH_MULTIPLIER = 31
|
||||
integer, parameter, private :: DICT_NULL = -huge(0)
|
||||
integer, parameter :: DICT_KEY_LENGTH = 255
|
||||
integer, parameter :: EMPTY = -huge(0)
|
||||
integer, parameter, private :: DELETED = -huge(0) + 1
|
||||
integer, parameter, private :: KEY_CHAR_LENGTH = 255
|
||||
integer, parameter, private :: TABLE_SIZES(30) = &
|
||||
[5, 7, 13, 19, 43, 73, 151, 283, 571, 1153, 2269, 4519, 9013, 18043, &
|
||||
36109, 72091, 144409, 288361, 576883, 1153459, 2307163, 4613893, &
|
||||
9227641, 18455029, 36911011, 73819861, 147639589, 295279081, &
|
||||
590559793, 1181116273]
|
||||
real(8), parameter, private :: MAX_LOAD_FACTOR = 0.65
|
||||
|
||||
!===============================================================================
|
||||
! ELEMKEYVALUE* contains (key,value) pairs and a pointer to the next (key,value)
|
||||
! pair
|
||||
! DICTENTRY* contains (key,value) pairs.
|
||||
!===============================================================================
|
||||
|
||||
type ElemKeyValueCI
|
||||
type(ElemKeyValueCI), pointer :: next => null()
|
||||
character(len=DICT_KEY_LENGTH) :: key
|
||||
integer :: value
|
||||
end type ElemKeyValueCI
|
||||
type DictEntryII
|
||||
integer :: key = EMPTY
|
||||
integer :: value = EMPTY
|
||||
end type DictEntryII
|
||||
|
||||
type ElemKeyValueII
|
||||
type(ElemKeyValueII), pointer :: next => null()
|
||||
integer :: key
|
||||
integer :: value
|
||||
end type ElemKeyValueII
|
||||
type DictEntryCI
|
||||
character(len=KEY_CHAR_LENGTH) :: key
|
||||
integer :: value = EMPTY
|
||||
end type DictEntryCI
|
||||
|
||||
!===============================================================================
|
||||
! HASHLIST* types contain a single pointer to a linked list of (key,value)
|
||||
! pairs. This type is necesssary so that the Dict types can be dynamically
|
||||
! allocated.
|
||||
! BUCKET* contains an allocatable DictEntry object for storing a (key,value)
|
||||
! pair and the hash value for fast comparisons. Integer (key,value) pairs are
|
||||
! stored directly in the hash table since their memory requirement is small.
|
||||
!===============================================================================
|
||||
|
||||
type, private :: HashListCI
|
||||
type(ElemKeyValueCI), pointer :: list => null()
|
||||
end type HashListCI
|
||||
|
||||
type, private :: HashListII
|
||||
type(ElemKeyValueII), pointer :: list => null()
|
||||
end type HashListII
|
||||
type, private :: BucketCI
|
||||
type(DictEntryCI), allocatable :: entry
|
||||
integer :: hash = EMPTY
|
||||
end type BucketCI
|
||||
|
||||
!===============================================================================
|
||||
! DICT* is a dictionary of (key,value) pairs with convenience methods as
|
||||
! type-bound procedures. DictCharInt has character(*) keys and integer values,
|
||||
! and DictIntInt has integer keys and values.
|
||||
! type-bound procedures. DictIntInt has integer keys and values, and
|
||||
! DictCharInt has character(*) keys and integer values.
|
||||
!===============================================================================
|
||||
|
||||
type, public :: DictCharInt
|
||||
private
|
||||
type(HashListCI), pointer :: table(:) => null()
|
||||
contains
|
||||
procedure :: add_key => dict_add_key_ci
|
||||
procedure :: get_key => dict_get_key_ci
|
||||
procedure :: has_key => dict_has_key_ci
|
||||
procedure :: keys => dict_keys_ci
|
||||
procedure :: clear => dict_clear_ci
|
||||
procedure, private :: get_elem => dict_get_elem_ci
|
||||
end type DictCharInt
|
||||
|
||||
type, public :: DictIntInt
|
||||
private
|
||||
type(HashListII), pointer :: table(:) => null()
|
||||
integer, private :: entries = 0
|
||||
integer, private :: capacity = 0
|
||||
type(DictEntryII), allocatable, private :: table(:)
|
||||
contains
|
||||
procedure :: add_key => dict_add_key_ii
|
||||
procedure :: get_key => dict_get_key_ii
|
||||
procedure :: has_key => dict_has_key_ii
|
||||
procedure :: keys => dict_keys_ii
|
||||
procedure :: clear => dict_clear_ii
|
||||
procedure, private :: get_elem => dict_get_elem_ii
|
||||
procedure :: set => set_ii
|
||||
procedure :: get => get_ii
|
||||
procedure :: has => has_ii
|
||||
procedure :: remove => remove_ii
|
||||
procedure :: next_entry => next_entry_ii
|
||||
procedure :: clear => clear_ii
|
||||
procedure :: size => size_ii
|
||||
procedure, private :: get_entry => get_entry_ii
|
||||
procedure, private :: resize => resize_ii
|
||||
end type DictIntInt
|
||||
|
||||
type, public :: DictCharInt
|
||||
integer, private :: entries = 0
|
||||
integer, private :: capacity = 0
|
||||
type(BucketCI), allocatable, private :: table(:)
|
||||
contains
|
||||
procedure :: set => set_ci
|
||||
procedure :: get => get_ci
|
||||
procedure :: has => has_ci
|
||||
procedure :: remove => remove_ci
|
||||
procedure :: next_entry => next_entry_ci
|
||||
procedure :: clear => clear_ci
|
||||
procedure :: size => size_ci
|
||||
procedure, private :: get_entry => get_entry_ci
|
||||
procedure, private :: resize => resize_ci
|
||||
end type DictCharInt
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! DICT_ADD_KEY adds a (key,value) entry to a dictionary. If the key is already
|
||||
! in the dictionary, the value is replaced by the new specified value.
|
||||
! GET_ENTRY returns the index of the (key,value) pair in the table for a given
|
||||
! key. This method is private.
|
||||
!===============================================================================
|
||||
|
||||
subroutine dict_add_key_ci(this, key, value)
|
||||
function get_entry_ii(this, key) result(i)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
character(*), intent(in) :: key
|
||||
integer, intent(in) :: value
|
||||
class(DictIntInt) :: this
|
||||
integer, intent(in) :: key
|
||||
integer :: i
|
||||
|
||||
integer :: hash
|
||||
type(ElemKeyValueCI), pointer :: elem => null()
|
||||
type(ElemKeyValueCI), pointer :: new_elem => null()
|
||||
integer :: c
|
||||
|
||||
elem => this % get_elem(key)
|
||||
|
||||
if (associated(elem)) then
|
||||
elem % value = value
|
||||
else
|
||||
! Get hash
|
||||
hash = dict_hash_key_ci(key)
|
||||
|
||||
! Create new element
|
||||
allocate(new_elem)
|
||||
new_elem % key = key
|
||||
new_elem % value = value
|
||||
|
||||
! Add element to front of list
|
||||
new_elem % next => this % table(hash) % list
|
||||
this % table(hash) % list => new_elem
|
||||
if (.not. allocated(this % table)) then
|
||||
allocate(this % table(TABLE_SIZES(1)))
|
||||
this % capacity = TABLE_SIZES(1)
|
||||
end if
|
||||
|
||||
end subroutine dict_add_key_ci
|
||||
hash = hash_ii(key)
|
||||
i = 1 + mod(hash, this % capacity)
|
||||
c = 2 + mod(hash, this % capacity - 2)
|
||||
|
||||
subroutine dict_add_key_ii(this, key, value)
|
||||
do
|
||||
if (this % table(i) % key == key .or. &
|
||||
this % table(i) % key == EMPTY) exit
|
||||
|
||||
class(DictIntInt) :: this
|
||||
i = 1 + mod(i + c - 1, this % capacity)
|
||||
end do
|
||||
|
||||
end function get_entry_ii
|
||||
|
||||
function get_entry_ci(this, key) result(i)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
character(*), intent(in) :: key
|
||||
integer :: i
|
||||
|
||||
integer :: hash
|
||||
integer :: c
|
||||
|
||||
if (.not. allocated(this % table)) then
|
||||
allocate(this % table(TABLE_SIZES(1)))
|
||||
this % capacity = TABLE_SIZES(1)
|
||||
end if
|
||||
|
||||
hash = hash_ci(key)
|
||||
i = 1 + mod(hash, this % capacity)
|
||||
c = 2 + mod(hash, this % capacity - 2)
|
||||
|
||||
do
|
||||
if (this % table(i) % hash == hash) then
|
||||
if (allocated(this % table(i) % entry)) then
|
||||
if (this % table(i) % entry % key == key) exit
|
||||
end if
|
||||
end if
|
||||
|
||||
if (this % table(i) % hash == EMPTY) exit
|
||||
|
||||
i = 1 + mod(i + c - 1, this % capacity)
|
||||
end do
|
||||
|
||||
end function get_entry_ci
|
||||
|
||||
!===============================================================================
|
||||
! RESIZE allocates a new hash table to accomodate the number of entries and
|
||||
! reinserts all of the entries into the new table. This method is private.
|
||||
!===============================================================================
|
||||
|
||||
subroutine resize_ii(this)
|
||||
|
||||
class(DictIntInt) :: this
|
||||
|
||||
type(DictEntryII), allocatable :: table(:)
|
||||
integer :: new_size
|
||||
integer :: i
|
||||
|
||||
do i = 1, size(TABLE_SIZES)
|
||||
if (TABLE_SIZES(i) > this % capacity) exit
|
||||
end do
|
||||
new_size = TABLE_SIZES(i)
|
||||
|
||||
call move_alloc(this % table, table)
|
||||
allocate(this % table(new_size))
|
||||
this % capacity = new_size
|
||||
this % entries = 0
|
||||
|
||||
! Rehash each entry into the new table
|
||||
do i = 1, size(table)
|
||||
if (table(i) % key /= EMPTY .and. table(i) % key /= DELETED) then
|
||||
call this % set(table(i) % key, table(i) % value)
|
||||
end if
|
||||
end do
|
||||
|
||||
deallocate(table)
|
||||
|
||||
end subroutine resize_ii
|
||||
|
||||
subroutine resize_ci(this)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
|
||||
type(BucketCI), allocatable :: table(:)
|
||||
integer :: new_size
|
||||
integer :: i
|
||||
|
||||
do i = 1, size(TABLE_SIZES)
|
||||
if (TABLE_SIZES(i) > this % capacity) exit
|
||||
end do
|
||||
new_size = TABLE_SIZES(i)
|
||||
|
||||
call move_alloc(this % table, table)
|
||||
allocate(this % table(new_size))
|
||||
this % capacity = new_size
|
||||
this % entries = 0
|
||||
|
||||
! Rehash each entry into the new table
|
||||
do i = 1, size(table)
|
||||
if (table(i) % hash /= EMPTY .and. table(i) % hash /= DELETED) then
|
||||
call this % set(table(i) % entry % key, table(i) % entry % value)
|
||||
end if
|
||||
end do
|
||||
|
||||
deallocate(table)
|
||||
|
||||
end subroutine resize_ci
|
||||
|
||||
!===============================================================================
|
||||
! SET adds a (key,value) entry to a dictionary. If the key is already in the
|
||||
! dictionary, the value is replaced by the new specified value.
|
||||
!===============================================================================
|
||||
|
||||
subroutine set_ii(this, key, value)
|
||||
|
||||
class(DictIntInt) :: this
|
||||
integer, intent(in) :: key
|
||||
integer, intent(in) :: value
|
||||
|
||||
integer :: hash
|
||||
type(ElemKeyValueII), pointer :: elem => null()
|
||||
type(ElemKeyValueII), pointer :: new_elem => null()
|
||||
integer :: i
|
||||
integer :: c
|
||||
|
||||
elem => this % get_elem(key)
|
||||
|
||||
if (associated(elem)) then
|
||||
elem % value = value
|
||||
else
|
||||
! Get hash
|
||||
hash = dict_hash_key_ii(key)
|
||||
|
||||
! Create new element
|
||||
allocate(new_elem)
|
||||
new_elem % key = key
|
||||
new_elem % value = value
|
||||
|
||||
! Add element to front of list
|
||||
new_elem % next => this % table(hash) % list
|
||||
this % table(hash) % list => new_elem
|
||||
if (.not. allocated(this % table)) then
|
||||
allocate(this % table(TABLE_SIZES(1)))
|
||||
this % capacity = TABLE_SIZES(1)
|
||||
else if (real(this % entries + 1, 8) / this % capacity > MAX_LOAD_FACTOR) then
|
||||
call this % resize()
|
||||
end if
|
||||
|
||||
end subroutine dict_add_key_ii
|
||||
hash = hash_ii(key)
|
||||
i = 1 + mod(hash, this % capacity)
|
||||
c = 2 + mod(hash, this % capacity - 2)
|
||||
|
||||
!===============================================================================
|
||||
! DICT_GET_ELEM returns a pointer to the (key,value) pair for a given key. This
|
||||
! method is private.
|
||||
!===============================================================================
|
||||
do
|
||||
if (this % table(i) % key == EMPTY .or. &
|
||||
this % table(i) % key == DELETED) then
|
||||
this % table(i) % key = key
|
||||
this % table(i) % value = value
|
||||
this % entries = this % entries + 1
|
||||
exit
|
||||
else if (this % table(i) % key == key) then
|
||||
this % table(i) % value = value
|
||||
exit
|
||||
end if
|
||||
|
||||
function dict_get_elem_ci(this, key) result(elem)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
character(*), intent(in) :: key
|
||||
type(ElemKeyValueCI), pointer :: elem
|
||||
|
||||
integer :: hash
|
||||
|
||||
! Check for dictionary not being allocated
|
||||
if (.not. associated(this % table)) then
|
||||
allocate(this % table(HASH_SIZE))
|
||||
end if
|
||||
|
||||
hash = dict_hash_key_ci(key)
|
||||
elem => this % table(hash) % list
|
||||
do while (associated(elem))
|
||||
if (elem % key == key) exit
|
||||
elem => elem % next
|
||||
i = 1 + mod(i + c - 1, this % capacity)
|
||||
end do
|
||||
|
||||
end function dict_get_elem_ci
|
||||
end subroutine set_ii
|
||||
|
||||
function dict_get_elem_ii(this, key) result(elem)
|
||||
subroutine set_ci(this, key, value)
|
||||
|
||||
class(DictIntInt) :: this
|
||||
integer, intent(in) :: key
|
||||
type(ElemKeyValueII), pointer :: elem
|
||||
|
||||
integer :: hash
|
||||
|
||||
! Check for dictionary not being allocated
|
||||
if (.not. associated(this % table)) then
|
||||
allocate(this % table(HASH_SIZE))
|
||||
end if
|
||||
|
||||
hash = dict_hash_key_ii(key)
|
||||
elem => this % table(hash) % list
|
||||
do while (associated(elem))
|
||||
if (elem % key == key) exit
|
||||
elem => elem % next
|
||||
end do
|
||||
|
||||
end function dict_get_elem_ii
|
||||
|
||||
!===============================================================================
|
||||
! DICT_GET_KEY returns the value matching a given key. If the dictionary does
|
||||
! not contain the key, the value DICT_NULL is returned.
|
||||
!===============================================================================
|
||||
|
||||
function dict_get_key_ci(this, key) result(value)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
class(DictCharInt) :: this
|
||||
character(*), intent(in) :: key
|
||||
integer :: value
|
||||
integer, intent(in) :: value
|
||||
|
||||
type(ElemKeyValueCI), pointer :: elem
|
||||
integer :: hash
|
||||
integer :: i
|
||||
integer :: c
|
||||
|
||||
elem => this % get_elem(key)
|
||||
|
||||
if (associated(elem)) then
|
||||
value = elem % value
|
||||
else
|
||||
value = DICT_NULL
|
||||
if (.not. allocated(this % table)) then
|
||||
allocate(this % table(TABLE_SIZES(1)))
|
||||
this % capacity = TABLE_SIZES(1)
|
||||
else if (real(this % entries + 1, 8) / this % capacity > MAX_LOAD_FACTOR) then
|
||||
call this % resize()
|
||||
end if
|
||||
|
||||
end function dict_get_key_ci
|
||||
hash = hash_ci(key)
|
||||
i = 1 + mod(hash, this % capacity)
|
||||
c = 2 + mod(hash, this % capacity - 2)
|
||||
|
||||
function dict_get_key_ii(this, key) result(value)
|
||||
do
|
||||
if (this % table(i) % hash == EMPTY .or. &
|
||||
this % table(i) % hash == DELETED) then
|
||||
if (.not. allocated(this % table(i) % entry)) then
|
||||
allocate(this % table(i) % entry)
|
||||
end if
|
||||
this % table(i) % hash = hash
|
||||
this % table(i) % entry % key = key
|
||||
this % table(i) % entry % value = value
|
||||
this % entries = this % entries + 1
|
||||
exit
|
||||
else if (this % table(i) % hash == hash .and. &
|
||||
this % table(i) % entry % key == key) then
|
||||
this % table(i) % entry % value = value
|
||||
exit
|
||||
end if
|
||||
|
||||
i = 1 + mod(i + c - 1, this % capacity)
|
||||
end do
|
||||
|
||||
end subroutine set_ci
|
||||
|
||||
!===============================================================================
|
||||
! GET returns the value matching a given key. If the dictionary does not contain
|
||||
! the key, the value EMPTY is returned.
|
||||
!===============================================================================
|
||||
|
||||
function get_ii(this, key) result(value)
|
||||
|
||||
class(DictIntInt) :: this
|
||||
integer, intent(in) :: key
|
||||
integer :: value
|
||||
|
||||
type(ElemKeyValueII), pointer :: elem
|
||||
integer :: i
|
||||
|
||||
elem => this % get_elem(key)
|
||||
i = this % get_entry(key)
|
||||
value = this % table(i) % value
|
||||
|
||||
if (associated(elem)) then
|
||||
value = elem % value
|
||||
end function get_ii
|
||||
|
||||
function get_ci(this, key) result(value)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
character(*), intent(in) :: key
|
||||
integer :: value
|
||||
|
||||
integer :: i
|
||||
|
||||
i = this % get_entry(key)
|
||||
if (allocated(this % table(i) % entry)) then
|
||||
value = this % table(i) % entry % value
|
||||
else
|
||||
value = DICT_NULL
|
||||
value = EMPTY
|
||||
end if
|
||||
|
||||
end function dict_get_key_ii
|
||||
end function get_ci
|
||||
|
||||
!===============================================================================
|
||||
! DICT_HAS_KEY determines whether a dictionary has a (key,value) pair with a
|
||||
! given key.
|
||||
! HAS determines whether a dictionary has a (key,value) pair with a given key.
|
||||
!===============================================================================
|
||||
|
||||
function dict_has_key_ci(this, key) result(has)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
character(*), intent(in) :: key
|
||||
logical :: has
|
||||
|
||||
type(ElemKeyValueCI), pointer :: elem
|
||||
|
||||
elem => this % get_elem(key)
|
||||
has = associated(elem)
|
||||
|
||||
end function dict_has_key_ci
|
||||
|
||||
function dict_has_key_ii(this, key) result(has)
|
||||
function has_ii(this, key) result(has)
|
||||
|
||||
class(DictIntInt) :: this
|
||||
integer, intent(in) :: key
|
||||
logical :: has
|
||||
|
||||
type(ElemKeyValueII), pointer :: elem
|
||||
integer :: i
|
||||
|
||||
elem => this % get_elem(key)
|
||||
has = associated(elem)
|
||||
i = this % get_entry(key)
|
||||
has = (this % table(i) % key /= EMPTY)
|
||||
|
||||
end function dict_has_key_ii
|
||||
end function has_ii
|
||||
|
||||
!===============================================================================
|
||||
! DICT_HASH_KEY returns the hash value for a given key
|
||||
!===============================================================================
|
||||
|
||||
function dict_hash_key_ci(key) result(val)
|
||||
function has_ci(this, key) result(has)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
character(*), intent(in) :: key
|
||||
integer :: val
|
||||
logical :: has
|
||||
|
||||
integer :: i
|
||||
|
||||
val = 0
|
||||
i = this % get_entry(key)
|
||||
has = (this % table(i) % hash /= EMPTY)
|
||||
|
||||
do i = 1, len_trim(key)
|
||||
val = HASH_MULTIPLIER * val + ichar(key(i:i))
|
||||
end do
|
||||
end function has_ci
|
||||
|
||||
! Added the absolute val on val-1 since the sum in the do loop is
|
||||
! susceptible to integer overflow
|
||||
val = 1 + mod(abs(val-1), HASH_SIZE)
|
||||
!===============================================================================
|
||||
! REMOVE deletes a (key,value) entry from a dictionary.
|
||||
!===============================================================================
|
||||
|
||||
end function dict_hash_key_ci
|
||||
|
||||
function dict_hash_key_ii(key) result(val)
|
||||
subroutine remove_ii(this, key)
|
||||
|
||||
class(DictIntInt) :: this
|
||||
integer, intent(in) :: key
|
||||
integer :: val
|
||||
|
||||
val = 0
|
||||
|
||||
! Added the absolute val on val-1 since the sum in the do loop is
|
||||
! susceptible to integer overflow
|
||||
val = 1 + mod(abs(key-1), HASH_SIZE)
|
||||
|
||||
end function dict_hash_key_ii
|
||||
|
||||
!===============================================================================
|
||||
! DICT_KEYS returns a pointer to a linked list of all (key,value) pairs
|
||||
!===============================================================================
|
||||
|
||||
function dict_keys_ci(this) result(keys)
|
||||
class(DictCharInt) :: this
|
||||
type(ElemKeyValueCI), pointer :: keys
|
||||
|
||||
integer :: i
|
||||
type(ElemKeyValueCI), pointer :: current => null()
|
||||
type(ElemKeyValueCI), pointer :: elem => null()
|
||||
|
||||
keys => null()
|
||||
|
||||
do i = 1, size(this % table)
|
||||
! Get pointer to start of bucket i
|
||||
elem => this % table(i) % list
|
||||
|
||||
do while (associated(elem))
|
||||
! Allocate (key,value) pair
|
||||
if (.not. associated(keys)) then
|
||||
allocate(keys)
|
||||
current => keys
|
||||
else
|
||||
allocate(current % next)
|
||||
current => current % next
|
||||
end if
|
||||
|
||||
! Copy (key,value) pair
|
||||
current % key = elem % key
|
||||
current % value = elem % value
|
||||
|
||||
! Move to next element in bucket i
|
||||
elem => elem % next
|
||||
end do
|
||||
end do
|
||||
|
||||
end function dict_keys_ci
|
||||
|
||||
function dict_keys_ii(this) result(keys)
|
||||
class(DictIntInt) :: this
|
||||
type(ElemKeyValueII), pointer :: keys
|
||||
|
||||
integer :: i
|
||||
type(ElemKeyValueII), pointer :: current => null()
|
||||
type(ElemKeyValueII), pointer :: elem => null()
|
||||
|
||||
keys => null()
|
||||
|
||||
do i = 1, size(this % table)
|
||||
! Get pointer to start of bucket i
|
||||
elem => this % table(i) % list
|
||||
|
||||
do while (associated(elem))
|
||||
! Allocate (key,value) pair
|
||||
if (.not. associated(keys)) then
|
||||
allocate(keys)
|
||||
current => keys
|
||||
else
|
||||
allocate(current % next)
|
||||
current => current % next
|
||||
end if
|
||||
|
||||
! Copy (key,value) pair
|
||||
current % key = elem % key
|
||||
current % value = elem % value
|
||||
|
||||
! Move to next element in bucket i
|
||||
elem => elem % next
|
||||
end do
|
||||
end do
|
||||
|
||||
end function dict_keys_ii
|
||||
|
||||
!===============================================================================
|
||||
! DICT_CLEAR Deletes and deallocates the dictionary item
|
||||
!===============================================================================
|
||||
|
||||
subroutine dict_clear_ci(this)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
|
||||
integer :: i
|
||||
type(ElemKeyValueCI), pointer :: current
|
||||
type(ElemKeyValueCI), pointer :: next
|
||||
|
||||
if (associated(this % table)) then
|
||||
do i = 1, size(this % table)
|
||||
current => this % table(i) % list
|
||||
do while (associated(current))
|
||||
if (associated(current % next)) then
|
||||
next => current % next
|
||||
else
|
||||
nullify(next)
|
||||
end if
|
||||
deallocate(current)
|
||||
current => next
|
||||
end do
|
||||
if (associated(this % table(i) % list)) &
|
||||
nullify(this % table(i) % list)
|
||||
end do
|
||||
deallocate(this % table)
|
||||
i = this % get_entry(key)
|
||||
if (this % table(i) % key /= EMPTY) then
|
||||
this % table(i) % key = DELETED
|
||||
this % table(i) % value = EMPTY
|
||||
this % entries = this % entries - 1
|
||||
end if
|
||||
|
||||
end subroutine dict_clear_ci
|
||||
end subroutine remove_ii
|
||||
|
||||
subroutine dict_clear_ii(this)
|
||||
subroutine remove_ci(this, key)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
character(*), intent(in) :: key
|
||||
|
||||
integer :: i
|
||||
|
||||
i = this % get_entry(key)
|
||||
if (this % table(i) % hash /= EMPTY) then
|
||||
this % table(i) % hash = DELETED
|
||||
if (allocated(this % table(i) % entry)) then
|
||||
deallocate(this % table(i) % entry)
|
||||
end if
|
||||
this % entries = this % entries - 1
|
||||
end if
|
||||
|
||||
end subroutine remove_ci
|
||||
|
||||
!===============================================================================
|
||||
! NEXT_ENTRY finds the next (key,value) pair. The value of current_entry is
|
||||
! updated with the (key,value) pair, and the value of i is updated with the
|
||||
! index of the entry in the table. Passing in i = 0 will locate the first entry
|
||||
! in the dictionary. If there are no more entries, i will be set to 0.
|
||||
!===============================================================================
|
||||
|
||||
subroutine next_entry_ii(this, current_entry, i)
|
||||
|
||||
class(DictIntInt) :: this
|
||||
type(DictEntryII), intent(inout) :: current_entry
|
||||
integer, intent(inout) :: i
|
||||
|
||||
if (.not. allocated(this % table)) return
|
||||
|
||||
do
|
||||
i = i + 1
|
||||
if (i > size(this % table)) then
|
||||
i = 0
|
||||
exit
|
||||
else if (this % table(i) % key /= EMPTY .and. &
|
||||
this % table(i) % key /= DELETED) then
|
||||
current_entry = this % table(i)
|
||||
exit
|
||||
end if
|
||||
end do
|
||||
|
||||
end subroutine next_entry_ii
|
||||
|
||||
subroutine next_entry_ci(this, current_entry, i)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
type(DictEntryCI), intent(inout) :: current_entry
|
||||
integer, intent(inout) :: i
|
||||
|
||||
if (.not. allocated(this % table)) return
|
||||
|
||||
do
|
||||
i = i + 1
|
||||
if (i > size(this % table)) then
|
||||
i = 0
|
||||
exit
|
||||
else if (this % table(i) % hash /= EMPTY .and. &
|
||||
this % table(i) % hash /= DELETED) then
|
||||
current_entry = this % table(i) % entry
|
||||
exit
|
||||
end if
|
||||
end do
|
||||
|
||||
end subroutine next_entry_ci
|
||||
|
||||
!===============================================================================
|
||||
! CLEAR deletes and deallocates the dictionary item
|
||||
!===============================================================================
|
||||
|
||||
subroutine clear_ii(this)
|
||||
|
||||
class(DictIntInt) :: this
|
||||
|
||||
if (allocated(this % table)) deallocate(this % table)
|
||||
this % entries = 0
|
||||
this % capacity = 0
|
||||
|
||||
end subroutine clear_ii
|
||||
|
||||
subroutine clear_ci(this)
|
||||
|
||||
class(DictCharInt) :: this
|
||||
|
||||
if (allocated(this % table)) deallocate(this % table)
|
||||
this % entries = 0
|
||||
this % capacity = 0
|
||||
|
||||
end subroutine clear_ci
|
||||
|
||||
!===============================================================================
|
||||
! SIZE returns the number of entries in the dictionary
|
||||
!===============================================================================
|
||||
|
||||
pure function size_ii(this) result(size)
|
||||
|
||||
class(DictIntInt), intent(in) :: this
|
||||
integer :: size
|
||||
|
||||
size = this % entries
|
||||
|
||||
end function size_ii
|
||||
|
||||
pure function size_ci(this) result(size)
|
||||
|
||||
class(DictCharInt), intent(in) :: this
|
||||
integer :: size
|
||||
|
||||
size = this % entries
|
||||
|
||||
end function size_ci
|
||||
|
||||
!===============================================================================
|
||||
! HASH returns the hash value for a given key
|
||||
!===============================================================================
|
||||
|
||||
pure function hash_ii(key) result(hash)
|
||||
|
||||
integer, intent(in) :: key
|
||||
integer :: hash
|
||||
|
||||
hash = abs(key - 1)
|
||||
|
||||
end function hash_ii
|
||||
|
||||
pure function hash_ci(key) result(hash)
|
||||
|
||||
character(*), intent(in) :: key
|
||||
integer :: hash
|
||||
|
||||
integer :: i
|
||||
type(ElemKeyValueII), pointer :: current
|
||||
type(ElemKeyValueII), pointer :: next
|
||||
|
||||
if (associated(this % table)) then
|
||||
do i = 1, size(this % table)
|
||||
current => this % table(i) % list
|
||||
do while (associated(current))
|
||||
if (associated(current % next)) then
|
||||
next => current % next
|
||||
else
|
||||
nullify(next)
|
||||
end if
|
||||
deallocate(current)
|
||||
current => next
|
||||
end do
|
||||
if (associated(this % table(i) % list)) &
|
||||
nullify(this % table(i) % list)
|
||||
end do
|
||||
deallocate(this % table)
|
||||
end if
|
||||
hash = 0
|
||||
|
||||
end subroutine dict_clear_ii
|
||||
do i = 1, len_trim(key)
|
||||
hash = 31 * hash + ichar(key(i:i))
|
||||
end do
|
||||
|
||||
hash = abs(hash - 1)
|
||||
|
||||
end function hash_ci
|
||||
|
||||
end module dict_header
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
module distribution_multivariate
|
||||
|
||||
use constants, only: ONE, TWO, PI
|
||||
use distribution_univariate, only: Distribution
|
||||
use distribution_univariate
|
||||
use error, only: fatal_error
|
||||
use random_lcg, only: prn
|
||||
use math, only: rotate_angle
|
||||
use xml_interface
|
||||
|
||||
implicit none
|
||||
|
||||
|
|
@ -58,10 +60,17 @@ module distribution_multivariate
|
|||
|
||||
type, abstract :: SpatialDistribution
|
||||
contains
|
||||
procedure(spatial_distribution_from_xml_), deferred :: from_xml
|
||||
procedure(spatial_distribution_sample_), deferred :: sample
|
||||
end type SpatialDistribution
|
||||
|
||||
abstract interface
|
||||
subroutine spatial_distribution_from_xml_(this, node)
|
||||
import SpatialDistribution, XMLNode
|
||||
class(SpatialDistribution), intent(inout) :: this
|
||||
type(XMLNode), intent(in) :: node
|
||||
end subroutine spatial_distribution_from_xml_
|
||||
|
||||
function spatial_distribution_sample_(this) result(xyz)
|
||||
import SpatialDistribution
|
||||
class(SpatialDistribution), intent(in) :: this
|
||||
|
|
@ -74,6 +83,7 @@ module distribution_multivariate
|
|||
class(Distribution), allocatable :: y
|
||||
class(Distribution), allocatable :: z
|
||||
contains
|
||||
procedure :: from_xml => cartesian_independent_from_xml
|
||||
procedure :: sample => cartesian_independent_sample
|
||||
end type CartesianIndependent
|
||||
|
||||
|
|
@ -82,12 +92,14 @@ module distribution_multivariate
|
|||
real(8) :: upper_right(3)
|
||||
logical :: only_fissionable = .false.
|
||||
contains
|
||||
procedure :: from_xml => spatial_box_from_xml
|
||||
procedure :: sample => spatial_box_sample
|
||||
end type SpatialBox
|
||||
|
||||
type, extends(SpatialDistribution) :: SpatialPoint
|
||||
real(8) :: xyz(3)
|
||||
contains
|
||||
procedure :: from_xml => spatial_point_from_xml
|
||||
procedure :: sample => spatial_point_sample
|
||||
end type SpatialPoint
|
||||
|
||||
|
|
@ -132,6 +144,55 @@ contains
|
|||
uvw(:) = this % reference_uvw
|
||||
end function monodirectional_sample
|
||||
|
||||
subroutine cartesian_independent_from_xml(this, node)
|
||||
class(CartesianIndependent), intent(inout) :: this
|
||||
type(XMLNode), intent(in) :: node
|
||||
|
||||
type(XMLNode) :: node_dist
|
||||
|
||||
! Read distribution for x coordinate
|
||||
if (check_for_node(node, "x")) then
|
||||
node_dist = node % child("x")
|
||||
call distribution_from_xml(this % x, node_dist)
|
||||
else
|
||||
allocate(Discrete :: this % x)
|
||||
select type (dist => this % x)
|
||||
type is (Discrete)
|
||||
allocate(dist % x(1), dist % p(1))
|
||||
dist % x(1) = ZERO
|
||||
dist % p(1) = ONE
|
||||
end select
|
||||
end if
|
||||
|
||||
! Read distribution for y coordinate
|
||||
if (check_for_node(node, "y")) then
|
||||
node_dist = node % child("y")
|
||||
call distribution_from_xml(this % y, node_dist)
|
||||
else
|
||||
allocate(Discrete :: this % y)
|
||||
select type (dist => this % y)
|
||||
type is (Discrete)
|
||||
allocate(dist % x(1), dist % p(1))
|
||||
dist % x(1) = ZERO
|
||||
dist % p(1) = ONE
|
||||
end select
|
||||
end if
|
||||
|
||||
if (check_for_node(node, "z")) then
|
||||
node_dist = node % child("z")
|
||||
call distribution_from_xml(this % z, node_dist)
|
||||
else
|
||||
allocate(Discrete :: this % z)
|
||||
select type (dist => this % z)
|
||||
type is (Discrete)
|
||||
allocate(dist % x(1), dist % p(1))
|
||||
dist % x(1) = ZERO
|
||||
dist % p(1) = ONE
|
||||
end select
|
||||
end if
|
||||
|
||||
end subroutine cartesian_independent_from_xml
|
||||
|
||||
function cartesian_independent_sample(this) result(xyz)
|
||||
class(CartesianIndependent), intent(in) :: this
|
||||
real(8) :: xyz(3)
|
||||
|
|
@ -141,6 +202,26 @@ contains
|
|||
xyz(3) = this % z % sample()
|
||||
end function cartesian_independent_sample
|
||||
|
||||
subroutine spatial_box_from_xml(this, node)
|
||||
class(SpatialBox), intent(inout) :: this
|
||||
type(XMLNode), intent(in) :: node
|
||||
|
||||
real(8), allocatable :: temp_real(:)
|
||||
|
||||
! Make sure correct number of parameters are given
|
||||
if (node_word_count(node, "parameters") /= 6) then
|
||||
call fatal_error('Box/fission spatial source must have &
|
||||
&six parameters specified.')
|
||||
end if
|
||||
|
||||
! Read lower-right/upper-left coordinates
|
||||
allocate(temp_real(6))
|
||||
call get_node_array(node, "parameters", temp_real)
|
||||
this % lower_left(:) = temp_real(1:3)
|
||||
this % upper_right(:) = temp_real(4:6)
|
||||
deallocate(temp_real)
|
||||
end subroutine spatial_box_from_xml
|
||||
|
||||
function spatial_box_sample(this) result(xyz)
|
||||
class(SpatialBox), intent(in) :: this
|
||||
real(8) :: xyz(3)
|
||||
|
|
@ -152,6 +233,20 @@ contains
|
|||
xyz(:) = this % lower_left + r*(this % upper_right - this % lower_left)
|
||||
end function spatial_box_sample
|
||||
|
||||
subroutine spatial_point_from_xml(this, node)
|
||||
class(SpatialPoint), intent(inout) :: this
|
||||
type(XMLNode), intent(in) :: node
|
||||
|
||||
! Make sure correct number of parameters are given
|
||||
if (node_word_count(node, "parameters") /= 3) then
|
||||
call fatal_error('Point spatial source must have &
|
||||
&three parameters specified.')
|
||||
end if
|
||||
|
||||
! Read location of point source
|
||||
call get_node_array(node, "parameters", this % xyz)
|
||||
end subroutine spatial_point_from_xml
|
||||
|
||||
function spatial_point_sample(this) result(xyz)
|
||||
class(SpatialPoint), intent(in) :: this
|
||||
real(8) :: xyz(3)
|
||||
|
|
|
|||
|
|
@ -1,16 +1,20 @@
|
|||
module eigenvalue
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use algorithm, only: binary_search
|
||||
use constants, only: ZERO
|
||||
use error, only: fatal_error, warning
|
||||
use global
|
||||
use math, only: t_percentile
|
||||
use mesh, only: count_bank_sites
|
||||
use mesh_header, only: RegularMesh
|
||||
use mesh_header, only: RegularMesh, meshes
|
||||
use message_passing
|
||||
use random_lcg, only: prn, set_particle_seed, advance_prn_seed
|
||||
use settings
|
||||
use simulation_header
|
||||
use string, only: to_str
|
||||
use tally_header
|
||||
use timer_header
|
||||
|
||||
implicit none
|
||||
|
||||
|
|
@ -39,6 +43,7 @@ contains
|
|||
& temp_sites(:) ! local array of extra sites on each node
|
||||
|
||||
#ifdef MPI
|
||||
integer :: mpi_err ! MPI error code
|
||||
integer(8) :: n ! number of sites to send/recv
|
||||
integer :: neighbor ! processor to send/recv data from
|
||||
#ifdef MPIF08
|
||||
|
|
@ -297,69 +302,34 @@ contains
|
|||
subroutine shannon_entropy()
|
||||
|
||||
integer :: ent_idx ! entropy index
|
||||
integer :: i, j, k ! index for bank sites
|
||||
integer :: n ! # of boxes in each dimension
|
||||
integer :: i ! index for mesh elements
|
||||
logical :: sites_outside ! were there sites outside entropy box?
|
||||
type(RegularMesh), pointer :: m
|
||||
|
||||
! Get pointer to entropy mesh
|
||||
m => entropy_mesh
|
||||
|
||||
! On the first pass through this subroutine, we need to determine how big
|
||||
! the entropy mesh should be in each direction and then allocate a
|
||||
! three-dimensional array to store the fraction of source sites in each mesh
|
||||
! box
|
||||
|
||||
if (.not. allocated(entropy_p)) then
|
||||
if (.not. allocated(m % dimension)) then
|
||||
! 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)**(ONE/THREE))
|
||||
|
||||
! copy dimensions
|
||||
m % n_dimension = 3
|
||||
allocate(m % dimension(3))
|
||||
m % dimension = n
|
||||
|
||||
! determine width
|
||||
m % width = (m % upper_right - m % lower_left) / m % dimension
|
||||
associate (m => meshes(index_entropy_mesh))
|
||||
! count number of fission sites over mesh
|
||||
call count_bank_sites(m, fission_bank, entropy_p, &
|
||||
size_bank=n_bank, sites_outside=sites_outside)
|
||||
|
||||
! display warning message if there were sites outside entropy box
|
||||
if (sites_outside) then
|
||||
if (master) call warning("Fission source site(s) outside of entropy box.")
|
||||
end if
|
||||
|
||||
! allocate p
|
||||
allocate(entropy_p(1, m % dimension(1), m % dimension(2), &
|
||||
m % dimension(3)))
|
||||
end if
|
||||
! sum values to obtain shannon entropy
|
||||
if (master) then
|
||||
! Normalize to total weight of bank sites
|
||||
entropy_p = entropy_p / sum(entropy_p)
|
||||
|
||||
! count number of fission sites over mesh
|
||||
call count_bank_sites(m, fission_bank, entropy_p, &
|
||||
size_bank=n_bank, sites_outside=sites_outside)
|
||||
|
||||
! display warning message if there were sites outside entropy box
|
||||
if (sites_outside) then
|
||||
if (master) call warning("Fission source site(s) outside of entropy box.")
|
||||
end if
|
||||
|
||||
! sum values to obtain shannon entropy
|
||||
if (master) then
|
||||
! Normalize to total weight of bank sites
|
||||
entropy_p = entropy_p / sum(entropy_p)
|
||||
|
||||
ent_idx = current_gen + gen_per_batch*(current_batch - 1)
|
||||
entropy(ent_idx) = ZERO
|
||||
do i = 1, m % dimension(1)
|
||||
do j = 1, m % dimension(2)
|
||||
do k = 1, m % dimension(3)
|
||||
if (entropy_p(1,i,j,k) > ZERO) then
|
||||
entropy(ent_idx) = entropy(ent_idx) - &
|
||||
entropy_p(1,i,j,k) * log(entropy_p(1,i,j,k))/log(TWO)
|
||||
end if
|
||||
end do
|
||||
ent_idx = current_gen + gen_per_batch*(current_batch - 1)
|
||||
entropy(ent_idx) = ZERO
|
||||
do i = 1, size(entropy_p, 2)
|
||||
if (entropy_p(1,i) > ZERO) then
|
||||
entropy(ent_idx) = entropy(ent_idx) - &
|
||||
entropy_p(1,i) * log(entropy_p(1,i))/log(TWO)
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
end if
|
||||
|
||||
end if
|
||||
end associate
|
||||
end subroutine shannon_entropy
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -371,6 +341,9 @@ contains
|
|||
subroutine calculate_generation_keff()
|
||||
|
||||
integer :: i ! overall generation
|
||||
#ifdef MPI
|
||||
integer :: mpi_err ! MPI error code
|
||||
#endif
|
||||
|
||||
! Get keff for this generation by subtracting off the starting value
|
||||
keff_generation = global_tallies(RESULT_VALUE, K_TRACKLENGTH) - keff_generation
|
||||
|
|
@ -439,8 +412,8 @@ contains
|
|||
end subroutine calculate_average_keff
|
||||
|
||||
!===============================================================================
|
||||
! CALCULATE_COMBINED_KEFF calculates a minimum variance estimate of k-effective
|
||||
! based on a linear combination of the collision, absorption, and tracklength
|
||||
! OPENMC_GET_KEFF calculates a minimum variance estimate of k-effective based on
|
||||
! a linear combination of the collision, absorption, and tracklength
|
||||
! estimates. The theory behind this can be found in M. Halperin, "Almost
|
||||
! linearly-optimum combination of unbiased estimates," J. Am. Stat. Assoc., 56,
|
||||
! 36-43 (1961), doi:10.1080/01621459.1961.10482088. The implementation here
|
||||
|
|
@ -448,7 +421,9 @@ contains
|
|||
! of keff confidence intervals in MCNP," Nucl. Technol., 111, 169-182 (1995).
|
||||
!===============================================================================
|
||||
|
||||
subroutine calculate_combined_keff()
|
||||
function openmc_get_keff(k_combined) result(err) bind(C)
|
||||
real(C_DOUBLE), intent(out) :: k_combined(2)
|
||||
integer(C_INT) :: err
|
||||
|
||||
integer :: l ! loop index
|
||||
integer :: i, j, k ! indices referring to collision, absorption, or track
|
||||
|
|
@ -459,9 +434,14 @@ contains
|
|||
real(8) :: g ! sum of weighting factors
|
||||
real(8) :: S(3) ! sums used for variance calculation
|
||||
|
||||
k_combined = ZERO
|
||||
|
||||
! Make sure we have at least four realizations. Notice that at the end,
|
||||
! there is a N-3 term in a denominator.
|
||||
if (n_realizations <= 3) return
|
||||
if (n_realizations <= 3) then
|
||||
err = -1
|
||||
return
|
||||
end if
|
||||
|
||||
! Initialize variables
|
||||
n = real(n_realizations, 8)
|
||||
|
|
@ -523,7 +503,6 @@ contains
|
|||
! Initialize variables
|
||||
g = ZERO
|
||||
S = ZERO
|
||||
k_combined = ZERO
|
||||
|
||||
do l = 1, 3
|
||||
! Permutations of estimates
|
||||
|
|
@ -590,8 +569,9 @@ contains
|
|||
k_combined(2) = sqrt(k_combined(2))
|
||||
|
||||
end if
|
||||
err = 0
|
||||
|
||||
end subroutine calculate_combined_keff
|
||||
end function openmc_get_keff
|
||||
|
||||
!===============================================================================
|
||||
! COUNT_SOURCE_FOR_UFS determines the source fraction in each UFS mesh cell and
|
||||
|
|
@ -606,18 +586,21 @@ contains
|
|||
logical :: sites_outside ! were there sites outside the ufs mesh?
|
||||
#ifdef MPI
|
||||
integer :: n ! total number of ufs mesh cells
|
||||
integer :: mpi_err ! MPI error code
|
||||
#endif
|
||||
|
||||
associate (m => meshes(index_ufs_mesh))
|
||||
|
||||
if (current_batch == 1 .and. current_gen == 1) then
|
||||
! On the first generation, just assume that the source is already evenly
|
||||
! distributed so that effectively the production of fission sites is not
|
||||
! biased
|
||||
|
||||
source_frac = ufs_mesh % volume_frac
|
||||
source_frac = m % volume_frac
|
||||
|
||||
else
|
||||
! count number of source sites in each ufs mesh cell
|
||||
call count_bank_sites(ufs_mesh, source_bank, source_frac, &
|
||||
call count_bank_sites(m, source_bank, source_frac, &
|
||||
sites_outside=sites_outside, size_bank=work)
|
||||
|
||||
! Check for sites outside of the mesh
|
||||
|
|
@ -627,7 +610,7 @@ contains
|
|||
|
||||
#ifdef MPI
|
||||
! Send source fraction to all processors
|
||||
n = product(ufs_mesh % dimension)
|
||||
n = product(m % dimension)
|
||||
call MPI_BCAST(source_frac, n, MPI_REAL8, 0, mpi_intracomm, mpi_err)
|
||||
#endif
|
||||
|
||||
|
|
@ -641,6 +624,8 @@ contains
|
|||
source_bank % wgt = source_bank % wgt * n_particles / total
|
||||
end if
|
||||
|
||||
end associate
|
||||
|
||||
end subroutine count_source_for_ufs
|
||||
|
||||
#ifdef _OPENMP
|
||||
|
|
|
|||
|
|
@ -1,14 +1,57 @@
|
|||
module error
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
use, intrinsic :: ISO_FORTRAN_ENV
|
||||
use constants
|
||||
|
||||
use constants
|
||||
use message_passing
|
||||
|
||||
implicit none
|
||||
|
||||
private
|
||||
public :: fatal_error
|
||||
public :: warning
|
||||
|
||||
! Error codes
|
||||
integer(C_INT), public, bind(C) :: E_UNASSIGNED = -1
|
||||
integer(C_INT), public, bind(C) :: E_ALLOCATE = -2
|
||||
integer(C_INT), public, bind(C) :: E_OUT_OF_BOUNDS = -3
|
||||
integer(C_INT), public, bind(C) :: E_INVALID_SIZE = -4
|
||||
integer(C_INT), public, bind(C) :: E_INVALID_ARGUMENT = -5
|
||||
integer(C_INT), public, bind(C) :: E_INVALID_TYPE = -6
|
||||
integer(C_INT), public, bind(C) :: E_INVALID_ID = -7
|
||||
integer(C_INT), public, bind(C) :: E_GEOMETRY = -8
|
||||
integer(C_INT), public, bind(C) :: E_DATA = -9
|
||||
integer(C_INT), public, bind(C) :: E_PHYSICS = -10
|
||||
|
||||
! Warning codes
|
||||
integer(C_INT), public, bind(C) :: E_WARNING = 1
|
||||
|
||||
! Error message
|
||||
character(kind=C_CHAR), public, bind(C) :: openmc_err_msg(256)
|
||||
|
||||
public :: set_errmsg
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! SET_ERRMSG sets the 'openmc_err_msg' module variable that is exposed via the C
|
||||
! API
|
||||
!===============================================================================
|
||||
|
||||
subroutine set_errmsg(f_string)
|
||||
character(*), intent(in) :: f_string
|
||||
|
||||
integer :: i, n
|
||||
|
||||
! Copy Fortran string to null-terminated C char array
|
||||
n = len_trim(f_string)
|
||||
do i = 1, n
|
||||
openmc_err_msg(i) = f_string(i:i)
|
||||
end do
|
||||
openmc_err_msg(n + 1) = C_NULL_CHAR
|
||||
end subroutine set_errmsg
|
||||
|
||||
!===============================================================================
|
||||
! WARNING issues a warning to the user in the log file and the standard output
|
||||
! stream.
|
||||
|
|
|
|||
|
|
@ -1,40 +0,0 @@
|
|||
module finalize
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use hdf5, only: h5tclose_f, h5close_f
|
||||
|
||||
use global
|
||||
use hdf5_interface, only: hdf5_bank_t
|
||||
use message_passing
|
||||
|
||||
implicit none
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! FINALIZE_RUN does all post-simulation tasks such as calculating tally
|
||||
! statistics and writing out tallies
|
||||
!===============================================================================
|
||||
|
||||
subroutine openmc_finalize() bind(C)
|
||||
|
||||
integer :: hdf5_err
|
||||
|
||||
! Deallocate arrays
|
||||
call free_memory()
|
||||
|
||||
! Release compound datatypes
|
||||
call h5tclose_f(hdf5_bank_t, hdf5_err)
|
||||
|
||||
! Close FORTRAN interface.
|
||||
call h5close_f(hdf5_err)
|
||||
|
||||
#ifdef MPI
|
||||
! Free all MPI types
|
||||
call MPI_TYPE_FREE(MPI_BANK, mpi_err)
|
||||
#endif
|
||||
|
||||
end subroutine openmc_finalize
|
||||
|
||||
end module finalize
|
||||
|
|
@ -2,16 +2,17 @@ module geometry
|
|||
|
||||
use constants
|
||||
use error, only: fatal_error, warning
|
||||
use geometry_header, only: Cell, Universe, Lattice, &
|
||||
&RectLattice, HexLattice
|
||||
use global
|
||||
use geometry_header
|
||||
use output, only: write_message
|
||||
use particle_header, only: LocalCoord, Particle
|
||||
use particle_restart_write, only: write_particle_restart
|
||||
use simulation_header
|
||||
use settings
|
||||
use surface_header
|
||||
use stl_vector, only: VectorInt
|
||||
use string, only: to_str
|
||||
use tally, only: score_surface_current
|
||||
use tally_header
|
||||
|
||||
implicit none
|
||||
|
||||
|
|
@ -384,9 +385,8 @@ contains
|
|||
! the geometry, is reflected, or crosses into a new lattice or cell
|
||||
!===============================================================================
|
||||
|
||||
subroutine cross_surface(p, last_cell)
|
||||
subroutine cross_surface(p)
|
||||
type(Particle), intent(inout) :: p
|
||||
integer, intent(in) :: last_cell ! last cell particle was in
|
||||
|
||||
real(8) :: u ! x-component of direction
|
||||
real(8) :: v ! y-component of direction
|
||||
|
|
@ -425,9 +425,7 @@ contains
|
|||
end if
|
||||
|
||||
! Score to global leakage tally
|
||||
if (tallies_on) then
|
||||
global_tally_leakage = global_tally_leakage + p % wgt
|
||||
end if
|
||||
global_tally_leakage = global_tally_leakage + p % wgt
|
||||
|
||||
! Display message
|
||||
if (verbosity >= 10 .or. trace) then
|
||||
|
|
@ -469,7 +467,7 @@ contains
|
|||
p%coord(1)%uvw(:) = [u, v, w] / norm
|
||||
|
||||
! Reassign particle's cell and surface
|
||||
p % coord(1) % cell = last_cell
|
||||
p % coord(1) % cell = p % last_cell(p % last_n_coord)
|
||||
p % surface = -p % surface
|
||||
|
||||
! If a reflective surface is coincident with a lattice or universe
|
||||
|
|
@ -1251,8 +1249,8 @@ contains
|
|||
class(Lattice), pointer :: lat ! pointer to current lattice
|
||||
|
||||
! Don't research places already checked
|
||||
if (found(universe_dict % get_key(univ % id), map)) then
|
||||
count = counts(universe_dict % get_key(univ % id), map)
|
||||
if (found(universe_dict % get(univ % id), map)) then
|
||||
count = counts(universe_dict % get(univ % id), map)
|
||||
return
|
||||
end if
|
||||
|
||||
|
|
@ -1260,8 +1258,8 @@ contains
|
|||
! Count = 1, then quit
|
||||
if (univ % id == univ_id) then
|
||||
count = 1
|
||||
counts(universe_dict % get_key(univ % id), map) = 1
|
||||
found(universe_dict % get_key(univ % id), map) = .true.
|
||||
counts(universe_dict % get(univ % id), map) = 1
|
||||
found(universe_dict % get(univ % id), map) = .true.
|
||||
return
|
||||
end if
|
||||
|
||||
|
|
@ -1357,8 +1355,8 @@ contains
|
|||
end if
|
||||
end do
|
||||
|
||||
counts(universe_dict % get_key(univ % id), map) = count
|
||||
found(universe_dict % get_key(univ % id), map) = .true.
|
||||
counts(universe_dict % get(univ % id), map) = count
|
||||
found(universe_dict % get(univ % id), map) = .true.
|
||||
|
||||
end function count_target
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
module geometry_header
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use algorithm, only: find
|
||||
use constants, only: HALF, TWO, THREE, INFINITY, K_BOLTZMANN, &
|
||||
MATERIAL_VOID, NONE
|
||||
use dict_header, only: DictCharInt, DictIntInt
|
||||
use material_header, only: Material
|
||||
use material_header, only: Material, materials, material_dict, n_materials
|
||||
use nuclide_header
|
||||
use sab_header
|
||||
use stl_vector, only: VectorReal
|
||||
use string, only: to_lower
|
||||
|
||||
|
|
@ -155,6 +159,19 @@ module geometry_header
|
|||
! array index of the root universe
|
||||
integer :: root_universe = -1
|
||||
|
||||
integer(C_INT32_T), bind(C) :: n_cells ! # of cells
|
||||
integer(C_INT32_T), bind(C) :: n_universes ! # of universes
|
||||
integer(C_INT32_T), bind(C) :: n_lattices ! # of lattices
|
||||
|
||||
type(Cell), allocatable, target :: cells(:)
|
||||
type(Universe), allocatable, target :: universes(:)
|
||||
type(LatticeContainer), allocatable, target :: lattices(:)
|
||||
|
||||
! Dictionaries which map user IDs to indices in the global arrays
|
||||
type(DictIntInt) :: cell_dict
|
||||
type(DictIntInt) :: universe_dict
|
||||
type(DictIntInt) :: lattice_dict
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -330,16 +347,8 @@ contains
|
|||
! temperatures to read (which may be different if interpolation is used)
|
||||
!===============================================================================
|
||||
|
||||
subroutine get_temperatures(cells, materials, material_dict, nuclide_dict, &
|
||||
n_nucs, nuc_temps, sab_dict, n_sabs, sab_temps)
|
||||
type(Cell), allocatable, intent(in) :: cells(:)
|
||||
type(Material), allocatable, intent(in) :: materials(:)
|
||||
type(DictIntInt), intent(in) :: material_dict
|
||||
type(DictCharInt), intent(in) :: nuclide_dict
|
||||
integer, intent(in) :: n_nucs
|
||||
subroutine get_temperatures(nuc_temps, sab_temps)
|
||||
type(VectorReal), allocatable, intent(out) :: nuc_temps(:)
|
||||
type(DictCharInt), optional, intent(in) :: sab_dict
|
||||
integer, optional, intent(in) :: n_sabs
|
||||
type(VectorReal), optional, allocatable, intent(out) :: sab_temps(:)
|
||||
|
||||
integer :: i, j, k
|
||||
|
|
@ -348,8 +357,8 @@ contains
|
|||
integer :: i_material
|
||||
real(8) :: temperature ! temperature in Kelvin
|
||||
|
||||
allocate(nuc_temps(n_nucs))
|
||||
if (present(n_sabs) .and. present(sab_temps)) allocate(sab_temps(n_sabs))
|
||||
allocate(nuc_temps(n_nuclides))
|
||||
if (present(sab_temps)) allocate(sab_temps(n_sab_tables))
|
||||
|
||||
do i = 1, size(cells)
|
||||
do j = 1, size(cells(i) % material)
|
||||
|
|
@ -364,11 +373,12 @@ contains
|
|||
temperature = cells(i) % sqrtkT(1)**2 / K_BOLTZMANN
|
||||
end if
|
||||
|
||||
i_material = material_dict % get_key(cells(i) % material(j))
|
||||
i_material = cells(i) % material(j)
|
||||
|
||||
associate (mat => materials(i_material))
|
||||
NUC_NAMES_LOOP: do k = 1, size(mat % names)
|
||||
! Get index in nuc_temps array
|
||||
i_nuclide = nuclide_dict % get_key(to_lower(mat % names(k)))
|
||||
i_nuclide = nuclide_dict % get(to_lower(mat % names(k)))
|
||||
|
||||
! Add temperature if it hasn't already been added
|
||||
if (find(nuc_temps(i_nuclide), temperature) == -1) then
|
||||
|
|
@ -376,11 +386,10 @@ contains
|
|||
end if
|
||||
end do NUC_NAMES_LOOP
|
||||
|
||||
if (present(sab_temps) .and. present(sab_dict) .and. &
|
||||
mat % n_sab > 0) then
|
||||
if (present(sab_temps) .and. mat % n_sab > 0) then
|
||||
SAB_NAMES_LOOP: do k = 1, size(mat % sab_names)
|
||||
! Get index in nuc_temps array
|
||||
i_sab = sab_dict % get_key(to_lower(mat % sab_names(k)))
|
||||
i_sab = sab_dict % get(to_lower(mat % sab_names(k)))
|
||||
|
||||
! Add temperature if it hasn't already been added
|
||||
if (find(sab_temps(i_sab), temperature) == -1) then
|
||||
|
|
@ -394,4 +403,239 @@ contains
|
|||
|
||||
end subroutine get_temperatures
|
||||
|
||||
!===============================================================================
|
||||
! FREE_MEMORY_GEOMETRY deallocates global arrays defined in this module
|
||||
!===============================================================================
|
||||
|
||||
subroutine free_memory_geometry()
|
||||
|
||||
n_cells = 0
|
||||
n_universes = 0
|
||||
n_lattices = 0
|
||||
|
||||
if (allocated(cells)) deallocate(cells)
|
||||
if (allocated(universes)) deallocate(universes)
|
||||
if (allocated(lattices)) deallocate(lattices)
|
||||
|
||||
call cell_dict % clear()
|
||||
call universe_dict % clear()
|
||||
call lattice_dict % clear()
|
||||
|
||||
end subroutine free_memory_geometry
|
||||
|
||||
!===============================================================================
|
||||
! C API FUNCTIONS
|
||||
!===============================================================================
|
||||
|
||||
function openmc_get_cell_index(id, index) result(err) bind(C)
|
||||
! Return the index in the cells array of a cell with a given ID
|
||||
integer(C_INT32_T), value :: id
|
||||
integer(C_INT32_T), intent(out) :: index
|
||||
integer(C_INT) :: err
|
||||
|
||||
if (allocated(cells)) then
|
||||
if (cell_dict % has(id)) then
|
||||
index = cell_dict % get(id)
|
||||
err = 0
|
||||
else
|
||||
err = E_INVALID_ID
|
||||
call set_errmsg("No cell exists with ID=" // trim(to_str(id)) // ".")
|
||||
end if
|
||||
else
|
||||
err = E_ALLOCATE
|
||||
call set_errmsg("Memory has not been allocated for cells.")
|
||||
end if
|
||||
end function openmc_get_cell_index
|
||||
|
||||
|
||||
function openmc_cell_get_fill(index, type, indices, n) result(err) bind(C)
|
||||
integer(C_INT32_T), value, intent(in) :: index
|
||||
integer(C_INT), intent(out) :: type
|
||||
integer(C_INT32_T), intent(out) :: n
|
||||
type(C_PTR), intent(out) :: indices
|
||||
integer(C_INT) :: err
|
||||
|
||||
err = 0
|
||||
if (index >= 1 .and. index <= size(cells)) then
|
||||
associate (c => cells(index))
|
||||
type = c % type
|
||||
select case (type)
|
||||
case (FILL_MATERIAL)
|
||||
n = size(c % material)
|
||||
indices = C_LOC(c % material(1))
|
||||
case (FILL_UNIVERSE, FILL_LATTICE)
|
||||
n = 1
|
||||
indices = C_LOC(c % fill)
|
||||
end select
|
||||
end associate
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in cells array is out of bounds.")
|
||||
end if
|
||||
end function openmc_cell_get_fill
|
||||
|
||||
|
||||
function openmc_cell_get_id(index, id) result(err) bind(C)
|
||||
! Return the ID of a cell
|
||||
integer(C_INT32_T), value :: index
|
||||
integer(C_INT32_T), intent(out) :: id
|
||||
integer(C_INT) :: err
|
||||
|
||||
if (index >= 1 .and. index <= size(cells)) then
|
||||
id = cells(index) % id
|
||||
err = 0
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in cells array is out of bounds.")
|
||||
end if
|
||||
end function openmc_cell_get_id
|
||||
|
||||
|
||||
function openmc_cell_set_fill(index, type, n, indices) result(err) bind(C)
|
||||
! Set the fill for a fill
|
||||
integer(C_INT32_T), value, intent(in) :: index ! index in cells
|
||||
integer(C_INT), value, intent(in) :: type
|
||||
integer(c_INT32_T), value, intent(in) :: n
|
||||
integer(C_INT32_T), intent(in) :: indices(n)
|
||||
integer(C_INT) :: err
|
||||
|
||||
integer :: i, j
|
||||
|
||||
err = 0
|
||||
if (index >= 1 .and. index <= size(cells)) then
|
||||
associate (c => cells(index))
|
||||
select case (type)
|
||||
case (FILL_MATERIAL)
|
||||
if (allocated(c % material)) deallocate(c % material)
|
||||
allocate(c % material(n))
|
||||
|
||||
c % type = FILL_MATERIAL
|
||||
do i = 1, n
|
||||
j = indices(i)
|
||||
if (j == 0) then
|
||||
c % material(i) = MATERIAL_VOID
|
||||
else
|
||||
if (j >= 1 .and. j <= n_materials) then
|
||||
c % material(i) = j
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index " // trim(to_str(j)) // " in the &
|
||||
&materials array is out of bounds.")
|
||||
end if
|
||||
end if
|
||||
end do
|
||||
case (FILL_UNIVERSE)
|
||||
c % type = FILL_UNIVERSE
|
||||
case (FILL_LATTICE)
|
||||
c % type = FILL_LATTICE
|
||||
end select
|
||||
end associate
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in cells array is out of bounds.")
|
||||
end if
|
||||
|
||||
end function openmc_cell_set_fill
|
||||
|
||||
|
||||
function openmc_cell_set_temperature(index, T, instance) result(err) bind(C)
|
||||
! Set the temperature of a cell
|
||||
integer(C_INT32_T), value, intent(in) :: index ! index in cells
|
||||
real(C_DOUBLE), value, intent(in) :: T ! temperature
|
||||
integer(C_INT32_T), optional, intent(in) :: instance ! cell instance
|
||||
|
||||
integer(C_INT) :: err ! error code
|
||||
integer :: j ! looping variable
|
||||
integer :: n ! number of cell instances
|
||||
integer :: material_index ! material index in materials array
|
||||
integer :: num_nuclides ! num nuclides in material
|
||||
integer :: nuclide_index ! index of nuclide in nuclides array
|
||||
real(8) :: min_temp ! min common-denominator avail temp
|
||||
real(8) :: max_temp ! max common-denominator avail temp
|
||||
real(8) :: temp ! actual temp we'll assign
|
||||
logical :: outside_low ! lower than available data
|
||||
logical :: outside_high ! higher than available data
|
||||
|
||||
outside_low = .false.
|
||||
outside_high = .false.
|
||||
|
||||
err = E_UNASSIGNED
|
||||
|
||||
if (index >= 1 .and. index <= size(cells)) then
|
||||
|
||||
! error if the cell is filled with another universe
|
||||
if (cells(index) % fill /= NONE) then
|
||||
err = E_GEOMETRY
|
||||
call set_errmsg("Cannot set temperature on a cell filled &
|
||||
&with a universe.")
|
||||
else
|
||||
! find which material is associated with this cell (material_index
|
||||
! is the index into the materials array)
|
||||
if (present(instance)) then
|
||||
material_index = cells(index) % material(instance)
|
||||
else
|
||||
material_index = cells(index) % material(1)
|
||||
end if
|
||||
|
||||
! number of nuclides associated with this material
|
||||
num_nuclides = size(materials(material_index) % nuclide)
|
||||
|
||||
min_temp = ZERO
|
||||
max_temp = INFINITY
|
||||
|
||||
do j = 1, num_nuclides
|
||||
nuclide_index = materials(material_index) % nuclide(j)
|
||||
min_temp = max(min_temp, minval(nuclides(nuclide_index) % kTs))
|
||||
max_temp = min(max_temp, maxval(nuclides(nuclide_index) % kTs))
|
||||
end do
|
||||
|
||||
! adjust the temperature to be within bounds if necessary
|
||||
if (K_BOLTZMANN * T < min_temp) then
|
||||
outside_low = .true.
|
||||
temp = min_temp / K_BOLTZMANN
|
||||
else if (K_BOLTZMANN * T > max_temp) then
|
||||
outside_high = .true.
|
||||
temp = max_temp / K_BOLTZMANN
|
||||
else
|
||||
temp = T
|
||||
end if
|
||||
|
||||
associate (c => cells(index))
|
||||
if (allocated(c % sqrtkT)) then
|
||||
n = size(c % sqrtkT)
|
||||
if (present(instance) .and. n > 1) then
|
||||
if (instance >= 0 .and. instance < n) then
|
||||
c % sqrtkT(instance + 1) = sqrt(K_BOLTZMANN * temp)
|
||||
err = 0
|
||||
end if
|
||||
else
|
||||
c % sqrtkT(:) = sqrt(K_BOLTZMANN * temp)
|
||||
err = 0
|
||||
end if
|
||||
end if
|
||||
end associate
|
||||
|
||||
! Assign error codes for outside of temperature bounds provided the
|
||||
! temperature was changed correctly. This needs to be done after
|
||||
! changing the temperature based on the logical structure above.
|
||||
if (err == 0) then
|
||||
if (outside_low) then
|
||||
err = E_WARNING
|
||||
call set_errmsg("Nuclear data has not been loaded beyond lower &
|
||||
&bound of T=" // trim(to_str(T)) // " K.")
|
||||
else if (outside_high) then
|
||||
err = E_WARNING
|
||||
call set_errmsg("Nuclear data has not been loaded beyond upper &
|
||||
&bound of T=" // trim(to_str(T)) // " K.")
|
||||
end if
|
||||
end if
|
||||
|
||||
end if
|
||||
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in cells array is out of bounds.")
|
||||
end if
|
||||
end function openmc_cell_set_temperature
|
||||
|
||||
end module geometry_header
|
||||
|
|
|
|||
590
src/global.F90
590
src/global.F90
|
|
@ -1,590 +0,0 @@
|
|||
module global
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
#ifdef MPIF08
|
||||
use mpi_f08
|
||||
#endif
|
||||
|
||||
use bank_header, only: Bank
|
||||
use cmfd_header
|
||||
use constants
|
||||
use dict_header, only: DictCharInt, DictIntInt
|
||||
use geometry_header, only: Cell, Universe, Lattice, LatticeContainer
|
||||
use material_header, only: Material
|
||||
use mesh_header, only: RegularMesh
|
||||
use mgxs_header, only: Mgxs, MgxsContainer
|
||||
use nuclide_header
|
||||
use photon_header, only: PhotonInteraction, ElementMicroXS
|
||||
use plot_header, only: ObjectPlot
|
||||
use sab_header, only: SAlphaBeta
|
||||
use set_header, only: SetInt
|
||||
use stl_vector, only: VectorInt
|
||||
use surface_header, only: SurfaceContainer
|
||||
use source_header, only: SourceDistribution
|
||||
use tally_header, only: TallyObject, TallyDerivative
|
||||
use tally_filter_header, only: TallyFilterContainer, TallyFilterMatch
|
||||
use trigger_header, only: KTrigger
|
||||
use timer_header, only: Timer
|
||||
use volume_header, only: VolumeCalculation
|
||||
|
||||
implicit none
|
||||
|
||||
! ============================================================================
|
||||
! GEOMETRY-RELATED VARIABLES
|
||||
|
||||
! Main arrays
|
||||
type(Cell), allocatable, target :: cells(:)
|
||||
type(Universe), allocatable, target :: universes(:)
|
||||
type(LatticeContainer), allocatable, target :: lattices(:)
|
||||
type(SurfaceContainer), allocatable, target :: surfaces(:)
|
||||
type(Material), allocatable, target :: materials(:)
|
||||
type(ObjectPlot), allocatable, target :: plots(:)
|
||||
|
||||
type(VolumeCalculation), allocatable :: volume_calcs(:)
|
||||
|
||||
! Size of main arrays
|
||||
integer :: n_cells ! # of cells
|
||||
integer :: n_universes ! # of universes
|
||||
integer :: n_lattices ! # of lattices
|
||||
integer :: n_surfaces ! # of surfaces
|
||||
integer :: n_materials ! # of materials
|
||||
integer :: n_plots ! # of plots
|
||||
|
||||
! These dictionaries provide a fast lookup mechanism -- the key is the
|
||||
! user-specified identifier and the value is the index in the corresponding
|
||||
! array
|
||||
type(DictIntInt) :: cell_dict
|
||||
type(DictIntInt) :: universe_dict
|
||||
type(DictIntInt) :: lattice_dict
|
||||
type(DictIntInt) :: surface_dict
|
||||
type(DictIntInt) :: material_dict
|
||||
type(DictIntInt) :: mesh_dict
|
||||
type(DictIntInt) :: filter_dict
|
||||
type(DictIntInt) :: tally_dict
|
||||
type(DictIntInt) :: plot_dict
|
||||
|
||||
! Number of lost particles
|
||||
integer :: n_lost_particles
|
||||
|
||||
! ============================================================================
|
||||
! ENERGY TREATMENT RELATED VARIABLES
|
||||
logical :: run_CE = .true. ! Run in CE mode?
|
||||
|
||||
! ============================================================================
|
||||
! CROSS SECTION RELATED VARIABLES NEEDED REGARDLESS OF CE OR MG
|
||||
|
||||
integer :: n_nuclides_total ! Number of nuclide cross section tables
|
||||
integer :: n_elements ! Number of photon cross section tables
|
||||
|
||||
! Cross section caches
|
||||
type(NuclideMicroXS), allocatable :: micro_xs(:) ! Cache for each nuclide
|
||||
type(ElementMicroXS), allocatable :: micro_photon_xs(:) ! Cache for each element
|
||||
type(MaterialMacroXS) :: material_xs ! Cache for current material
|
||||
|
||||
! Dictionaries to look up cross sections and listings
|
||||
type(DictCharInt) :: nuclide_dict
|
||||
type(DictCharInt) :: element_dict
|
||||
type(DictCharInt) :: library_dict
|
||||
|
||||
! Cross section libraries
|
||||
type(Library), allocatable :: libraries(:)
|
||||
|
||||
! ============================================================================
|
||||
! CONTINUOUS-ENERGY CROSS SECTION RELATED VARIABLES
|
||||
|
||||
! Cross section arrays
|
||||
type(Nuclide), allocatable, target :: nuclides(:) ! Nuclide cross-sections
|
||||
type(PhotonInteraction), allocatable :: elements(:) ! Photon cross sections
|
||||
type(SAlphaBeta), allocatable, target :: sab_tables(:) ! S(a,b) tables
|
||||
|
||||
integer :: n_sab_tables ! Number of S(a,b) thermal scattering tables
|
||||
|
||||
! Minimum/maximum energies
|
||||
real(8) :: energy_min_neutron = ZERO
|
||||
real(8) :: energy_max_neutron = INFINITY
|
||||
|
||||
! Dictionaries to look up cross sections and listings
|
||||
type(DictCharInt) :: sab_dict
|
||||
|
||||
! Unreoslved resonance probablity tables
|
||||
logical :: urr_ptables_on = .true.
|
||||
|
||||
! Default temperature and method for choosing temperatures
|
||||
integer :: temperature_method = TEMPERATURE_NEAREST
|
||||
logical :: temperature_multipole = .false.
|
||||
real(8) :: temperature_tolerance = 10.0_8
|
||||
real(8) :: temperature_default = 293.6_8
|
||||
real(8) :: temperature_range(2) = [ZERO, ZERO]
|
||||
|
||||
integer :: n_log_bins ! number of bins for logarithmic grid
|
||||
real(8) :: log_spacing ! spacing on logarithmic grid
|
||||
|
||||
logical :: photon_transport = .false.
|
||||
integer :: electron_treatment = ELECTRON_LED
|
||||
|
||||
! ============================================================================
|
||||
! MULTI-GROUP CROSS SECTION RELATED VARIABLES
|
||||
|
||||
! Cross section arrays
|
||||
type(MgxsContainer), allocatable, target :: nuclides_MG(:)
|
||||
|
||||
! Cross section caches
|
||||
type(MgxsContainer), target, allocatable :: macro_xs(:)
|
||||
|
||||
! Number of energy groups
|
||||
integer :: num_energy_groups
|
||||
|
||||
! Number of delayed groups
|
||||
integer :: num_delayed_groups
|
||||
|
||||
! Energy group structure
|
||||
real(8), allocatable :: energy_bins(:)
|
||||
|
||||
! Midpoint of the energy group structure
|
||||
real(8), allocatable :: energy_bin_avg(:)
|
||||
|
||||
! Maximum Data Order
|
||||
integer :: max_order
|
||||
|
||||
! Whether or not to convert Legendres to tabulars
|
||||
logical :: legendre_to_tabular = .True.
|
||||
|
||||
! Number of points to use in the Legendre to tabular conversion
|
||||
integer :: legendre_to_tabular_points = 33
|
||||
|
||||
! ============================================================================
|
||||
! TALLY-RELATED VARIABLES
|
||||
|
||||
type(RegularMesh), allocatable, target :: meshes(:)
|
||||
type(TallyObject), allocatable, target :: tallies(:)
|
||||
type(TallyFilterContainer), allocatable, target :: filters(:)
|
||||
type(TallyFilterMatch), allocatable :: filter_matches(:)
|
||||
|
||||
! Pointers for different tallies
|
||||
type(TallyObject), pointer :: user_tallies(:) => null()
|
||||
type(TallyObject), pointer :: cmfd_tallies(:) => null()
|
||||
|
||||
! Starting index (minus 1) in tallies for each tally group
|
||||
integer :: i_user_tallies = -1
|
||||
integer :: i_cmfd_tallies = -1
|
||||
|
||||
! Active tally lists
|
||||
type(VectorInt) :: active_analog_tallies
|
||||
type(VectorInt) :: active_tracklength_tallies
|
||||
type(VectorInt) :: active_current_tallies
|
||||
type(VectorInt) :: active_collision_tallies
|
||||
type(VectorInt) :: active_tallies
|
||||
|
||||
! Global tallies
|
||||
! 1) collision estimate of k-eff
|
||||
! 2) absorption estimate of k-eff
|
||||
! 3) track-length estimate of k-eff
|
||||
! 4) leakage fraction
|
||||
|
||||
real(C_DOUBLE), 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)
|
||||
|
||||
integer :: n_meshes = 0 ! # of structured meshes
|
||||
integer :: n_user_meshes = 0 ! # of structured user meshes
|
||||
integer :: n_filters = 0 ! # of filters
|
||||
integer :: n_user_filters = 0 ! # of user filters
|
||||
integer :: n_tallies = 0 ! # of tallies
|
||||
integer :: n_user_tallies = 0 ! # of user tallies
|
||||
|
||||
! Tally derivatives
|
||||
type(TallyDerivative), allocatable :: tally_derivs(:)
|
||||
!$omp threadprivate(tally_derivs)
|
||||
|
||||
! Normalization for statistics
|
||||
integer :: n_realizations = 0 ! # of independent realizations
|
||||
real(8) :: total_weight ! total starting particle weight in realization
|
||||
|
||||
! Flag for turning tallies on
|
||||
logical :: tallies_on = .false.
|
||||
logical :: active_batches = .false.
|
||||
|
||||
! Assume all tallies are spatially distinct
|
||||
logical :: assume_separate = .false.
|
||||
|
||||
! Use confidence intervals for results instead of standard deviations
|
||||
logical :: confidence_intervals = .false.
|
||||
|
||||
! ============================================================================
|
||||
! EIGENVALUE SIMULATION VARIABLES
|
||||
|
||||
integer(8) :: n_particles = 0 ! # of particles per generation
|
||||
integer :: n_batches ! # of batches
|
||||
integer :: n_inactive ! # of inactive batches
|
||||
integer :: n_active ! # of active batches
|
||||
integer :: gen_per_batch = 1 ! # of generations per batch
|
||||
integer :: current_batch = 0 ! current batch
|
||||
integer :: current_gen = 0 ! current generation within a batch
|
||||
integer :: total_gen = 0 ! total number of generations simulated
|
||||
|
||||
! ============================================================================
|
||||
! TALLY PRECISION TRIGGER VARIABLES
|
||||
|
||||
integer :: n_max_batches ! max # of batches
|
||||
integer :: n_batch_interval = 1 ! batch interval for triggers
|
||||
logical :: pred_batches = .false. ! predict batches for triggers
|
||||
logical :: trigger_on = .false. ! flag for turning triggers on/off
|
||||
type(KTrigger) :: keff_trigger ! trigger for k-effective
|
||||
logical :: satisfy_triggers = .false. ! whether triggers are satisfied
|
||||
|
||||
! External source
|
||||
type(SourceDistribution), allocatable :: external_source(:)
|
||||
|
||||
! Source and fission bank
|
||||
type(Bank), allocatable, target :: source_bank(:)
|
||||
type(Bank), allocatable, target :: fission_bank(:)
|
||||
#ifdef _OPENMP
|
||||
type(Bank), allocatable, target :: master_fission_bank(:)
|
||||
#endif
|
||||
integer(8) :: n_bank ! # of sites in fission bank
|
||||
integer(8) :: work ! number of particles per processor
|
||||
integer(8), allocatable :: work_index(:) ! starting index in source bank for each process
|
||||
integer(8) :: current_work ! index in source bank of current history simulated
|
||||
|
||||
! Temporary k-effective values
|
||||
real(8), allocatable :: k_generation(:) ! single-generation estimates of k
|
||||
real(8) :: keff = ONE ! average k over active batches
|
||||
real(8) :: keff_std ! standard deviation of average k
|
||||
real(8) :: k_col_abs = ZERO ! sum over batches of k_collision * k_absorption
|
||||
real(8) :: k_col_tra = ZERO ! sum over batches of k_collision * k_tracklength
|
||||
real(8) :: k_abs_tra = ZERO ! sum over batches of k_absorption * k_tracklength
|
||||
real(8) :: k_combined(2) ! combined best estimate of k-effective
|
||||
|
||||
! Shannon entropy
|
||||
logical :: entropy_on = .false.
|
||||
real(8), allocatable :: entropy(:) ! shannon entropy at each generation
|
||||
real(8), allocatable :: entropy_p(:,:,:,:) ! % of source sites in each cell
|
||||
type(RegularMesh), pointer :: entropy_mesh
|
||||
|
||||
! Uniform fission source weighting
|
||||
logical :: ufs = .false.
|
||||
type(RegularMesh), pointer :: ufs_mesh => null()
|
||||
real(8), allocatable :: source_frac(:,:,:,:)
|
||||
|
||||
! Write source at end of simulation
|
||||
logical :: source_separate = .false.
|
||||
logical :: source_write = .true.
|
||||
logical :: source_latest = .false.
|
||||
|
||||
! ============================================================================
|
||||
! PARALLEL PROCESSING VARIABLES
|
||||
|
||||
#ifdef _OPENMP
|
||||
integer :: n_threads = NONE ! number of OpenMP threads
|
||||
integer :: thread_id ! ID of a given thread
|
||||
#endif
|
||||
|
||||
! No reduction at end of batch
|
||||
logical :: reduce_tallies = .true.
|
||||
|
||||
! ============================================================================
|
||||
! TIMING VARIABLES
|
||||
|
||||
type(Timer) :: time_total ! timer for total run
|
||||
type(Timer) :: time_initialize ! timer for initialization
|
||||
type(Timer) :: time_read_xs ! timer for reading cross sections
|
||||
type(Timer) :: time_unionize ! timer for material xs-energy grid union
|
||||
type(Timer) :: time_bank ! timer for fission bank synchronization
|
||||
type(Timer) :: time_bank_sample ! timer for fission bank sampling
|
||||
type(Timer) :: time_bank_sendrecv ! timer for fission bank SEND/RECV
|
||||
type(Timer) :: time_tallies ! timer for accumulate tallies
|
||||
type(Timer) :: time_inactive ! timer for inactive batches
|
||||
type(Timer) :: time_active ! timer for active batches
|
||||
type(Timer) :: time_transport ! timer for transport only
|
||||
type(Timer) :: time_finalize ! timer for finalization
|
||||
|
||||
! ===========================================================================
|
||||
! VARIANCE REDUCTION VARIABLES
|
||||
|
||||
logical :: survival_biasing = .false.
|
||||
real(8) :: weight_cutoff = 0.25_8
|
||||
real(8) :: energy_cutoff(4) = [ZERO, 1000.0_8, ZERO, ZERO]
|
||||
real(8) :: weight_survive = ONE
|
||||
|
||||
! ============================================================================
|
||||
! MISCELLANEOUS VARIABLES
|
||||
|
||||
! Mode to run in (fixed source, eigenvalue, plotting, etc)
|
||||
integer :: run_mode = NONE
|
||||
|
||||
! Restart run
|
||||
logical :: restart_run = .false.
|
||||
integer :: restart_batch
|
||||
|
||||
character(MAX_FILE_LEN) :: path_input ! Path to input file
|
||||
character(MAX_FILE_LEN) :: path_cross_sections = '' ! Path to cross_sections.xml
|
||||
character(MAX_FILE_LEN) :: path_multipole ! Path to wmp library
|
||||
character(MAX_FILE_LEN) :: path_source = '' ! Path to binary source
|
||||
character(MAX_FILE_LEN) :: path_state_point ! Path to binary state point
|
||||
character(MAX_FILE_LEN) :: path_source_point ! Path to binary source point
|
||||
character(MAX_FILE_LEN) :: path_particle_restart ! Path to particle restart
|
||||
character(MAX_FILE_LEN) :: path_output = '' ! Path to output directory
|
||||
|
||||
! The verbosity controls how much information will be printed to the
|
||||
! screen and in logs
|
||||
integer :: verbosity = 7
|
||||
|
||||
! Flag for enabling cell overlap checking during transport
|
||||
logical :: check_overlaps = .false.
|
||||
integer(8), allocatable :: overlap_check_cnt(:)
|
||||
|
||||
! Trace for single particle
|
||||
logical :: trace
|
||||
integer :: trace_batch
|
||||
integer :: trace_gen
|
||||
integer(8) :: trace_particle
|
||||
|
||||
! Particle tracks
|
||||
logical :: write_all_tracks = .false.
|
||||
integer, allocatable :: track_identifiers(:,:)
|
||||
|
||||
! Particle restart run
|
||||
logical :: particle_restart_run = .false.
|
||||
|
||||
! Number of distribcell maps
|
||||
integer :: n_maps
|
||||
|
||||
! Write out initial source
|
||||
logical :: write_initial_source = .false.
|
||||
|
||||
! Whether create fission neutrons or not. Only applied for MODE_FIXEDSOURCE
|
||||
logical :: create_fission_neutrons = .true.
|
||||
|
||||
! ============================================================================
|
||||
! CMFD VARIABLES
|
||||
|
||||
! Main object
|
||||
type(cmfd_type) :: cmfd
|
||||
|
||||
! Is CMFD active
|
||||
logical :: cmfd_run = .false.
|
||||
|
||||
! Timing objects
|
||||
type(Timer) :: time_cmfd ! timer for whole cmfd calculation
|
||||
type(Timer) :: time_cmfdbuild ! timer for matrix build
|
||||
type(Timer) :: time_cmfdsolve ! timer for solver
|
||||
|
||||
! Flag for active core map
|
||||
logical :: cmfd_coremap = .false.
|
||||
|
||||
! Flag to reset dhats to zero
|
||||
logical :: dhat_reset = .false.
|
||||
|
||||
! Flag to activate neutronic feedback via source weights
|
||||
logical :: cmfd_feedback = .false.
|
||||
|
||||
! User-defined tally information
|
||||
integer :: n_cmfd_meshes = 1 ! # of structured meshes
|
||||
integer :: n_cmfd_filters = 0 ! # of filters
|
||||
integer :: n_cmfd_tallies = 3 ! # of user-defined tallies
|
||||
|
||||
! Adjoint method type
|
||||
character(len=10) :: cmfd_adjoint_type = 'physical'
|
||||
|
||||
! Number of incomplete ilu factorization levels
|
||||
integer :: cmfd_ilu_levels = 1
|
||||
|
||||
! Batch to begin cmfd
|
||||
integer :: cmfd_begin = 1
|
||||
|
||||
! Tally reset list
|
||||
integer :: n_cmfd_resets
|
||||
type(SetInt) :: cmfd_reset
|
||||
|
||||
! Compute effective downscatter cross section
|
||||
logical :: cmfd_downscatter = .false.
|
||||
|
||||
! Convergence monitoring
|
||||
logical :: cmfd_power_monitor = .false.
|
||||
|
||||
! Cmfd output
|
||||
logical :: cmfd_write_matrices = .false.
|
||||
|
||||
! Run an adjoint calculation (last batch only)
|
||||
logical :: cmfd_run_adjoint = .false.
|
||||
|
||||
! CMFD run logicals
|
||||
logical :: cmfd_on = .false.
|
||||
|
||||
! CMFD display info
|
||||
character(len=25) :: cmfd_display = 'balance'
|
||||
|
||||
! Estimate of spectral radius of CMFD matrices and tolerances
|
||||
real(8) :: cmfd_spectral = ZERO
|
||||
real(8) :: cmfd_shift = 1.e6
|
||||
real(8) :: cmfd_ktol = 1.e-8_8
|
||||
real(8) :: cmfd_stol = 1.e-8_8
|
||||
real(8) :: cmfd_atoli = 1.e-10_8
|
||||
real(8) :: cmfd_rtoli = 1.e-5_8
|
||||
|
||||
! Information about state points to be written
|
||||
integer :: n_state_points = 0
|
||||
type(SetInt) :: statepoint_batch
|
||||
|
||||
! Information about source points to be written
|
||||
integer :: n_source_points = 0
|
||||
type(SetInt) :: sourcepoint_batch
|
||||
|
||||
! Various output options
|
||||
logical :: output_summary = .true.
|
||||
logical :: output_tallies = .true.
|
||||
|
||||
! ============================================================================
|
||||
! RESONANCE SCATTERING VARIABLES
|
||||
|
||||
logical :: res_scat_on = .false. ! is resonance scattering treated?
|
||||
integer :: res_scat_method = RES_SCAT_ARES ! resonance scattering method
|
||||
real(8) :: res_scat_energy_min = 0.01_8
|
||||
real(8) :: res_scat_energy_max = 1000.0_8
|
||||
character(10), allocatable :: res_scat_nuclides(:)
|
||||
|
||||
!$omp threadprivate(micro_xs, micro_photon_xs, material_xs, fission_bank, &
|
||||
!$omp& n_bank, trace, thread_id, current_work, filter_matches)
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! FREE_MEMORY deallocates and clears all global allocatable arrays in the
|
||||
! program
|
||||
!===============================================================================
|
||||
|
||||
subroutine free_memory()
|
||||
|
||||
integer :: i ! Loop Index
|
||||
|
||||
! Deallocate cells, surfaces, materials
|
||||
if (allocated(cells)) deallocate(cells)
|
||||
if (allocated(universes)) deallocate(universes)
|
||||
if (allocated(lattices)) deallocate(lattices)
|
||||
if (allocated(surfaces)) deallocate(surfaces)
|
||||
if (allocated(materials)) deallocate(materials)
|
||||
if (allocated(plots)) deallocate(plots)
|
||||
|
||||
! Deallocate geometry debugging information
|
||||
if (allocated(overlap_check_cnt)) deallocate(overlap_check_cnt)
|
||||
|
||||
! Deallocate cross section data, listings, and cache
|
||||
if (allocated(nuclides)) then
|
||||
! First call the clear routines
|
||||
do i = 1, size(nuclides)
|
||||
call nuclides(i) % clear()
|
||||
end do
|
||||
deallocate(nuclides)
|
||||
end if
|
||||
if (allocated(elements)) deallocate(elements)
|
||||
|
||||
if (allocated(res_scat_nuclides)) deallocate(res_scat_nuclides)
|
||||
|
||||
if (allocated(nuclides_MG)) deallocate(nuclides_MG)
|
||||
|
||||
if (allocated(macro_xs)) deallocate(macro_xs)
|
||||
|
||||
if (allocated(sab_tables)) deallocate(sab_tables)
|
||||
if (allocated(micro_xs)) deallocate(micro_xs)
|
||||
|
||||
! Deallocate external source
|
||||
if (allocated(external_source)) deallocate(external_source)
|
||||
|
||||
! Deallocate k and entropy
|
||||
if (allocated(k_generation)) deallocate(k_generation)
|
||||
if (allocated(entropy)) deallocate(entropy)
|
||||
if (allocated(entropy_p)) deallocate(entropy_p)
|
||||
|
||||
! Deallocate tally-related arrays
|
||||
if (allocated(global_tallies)) deallocate(global_tallies)
|
||||
if (allocated(meshes)) deallocate(meshes)
|
||||
if (allocated(filters)) deallocate(filters)
|
||||
if (allocated(tallies)) deallocate(tallies)
|
||||
if (allocated(filter_matches)) deallocate(filter_matches)
|
||||
|
||||
! Deallocate fission and source bank and entropy
|
||||
!$omp parallel
|
||||
if (allocated(fission_bank)) deallocate(fission_bank)
|
||||
!$omp end parallel
|
||||
#ifdef _OPENMP
|
||||
if (allocated(master_fission_bank)) deallocate(master_fission_bank)
|
||||
#endif
|
||||
if (allocated(source_bank)) deallocate(source_bank)
|
||||
if (allocated(entropy_p)) deallocate(entropy_p)
|
||||
|
||||
! Deallocate array of work indices
|
||||
if (allocated(work_index)) deallocate(work_index)
|
||||
|
||||
! Deallocate CMFD
|
||||
call deallocate_cmfd(cmfd)
|
||||
|
||||
! Deallocate tally node lists
|
||||
call active_analog_tallies % clear()
|
||||
call active_tracklength_tallies % clear()
|
||||
call active_current_tallies % clear()
|
||||
call active_collision_tallies % clear()
|
||||
call active_tallies % clear()
|
||||
|
||||
! Deallocate track_identifiers
|
||||
if (allocated(track_identifiers)) deallocate(track_identifiers)
|
||||
|
||||
! Deallocate dictionaries
|
||||
call cell_dict % clear()
|
||||
call universe_dict % clear()
|
||||
call lattice_dict % clear()
|
||||
call surface_dict % clear()
|
||||
call material_dict % clear()
|
||||
call mesh_dict % clear()
|
||||
call filter_dict % clear()
|
||||
call tally_dict % clear()
|
||||
call plot_dict % clear()
|
||||
call nuclide_dict % clear()
|
||||
call sab_dict % clear()
|
||||
|
||||
! Clear statepoint and sourcepoint batch set
|
||||
call statepoint_batch % clear()
|
||||
call sourcepoint_batch % clear()
|
||||
|
||||
! Deallocate entropy mesh
|
||||
if (associated(entropy_mesh)) then
|
||||
if (allocated(entropy_mesh % lower_left)) &
|
||||
deallocate(entropy_mesh % lower_left)
|
||||
if (allocated(entropy_mesh % upper_right)) &
|
||||
deallocate(entropy_mesh % upper_right)
|
||||
if (allocated(entropy_mesh % width)) deallocate(entropy_mesh % width)
|
||||
deallocate(entropy_mesh)
|
||||
end if
|
||||
|
||||
! Deallocate ufs
|
||||
if (allocated(source_frac)) deallocate(source_frac)
|
||||
if (associated(ufs_mesh)) then
|
||||
if (allocated(ufs_mesh % lower_left)) deallocate(ufs_mesh % lower_left)
|
||||
if (allocated(ufs_mesh % upper_right)) &
|
||||
deallocate(ufs_mesh % upper_right)
|
||||
if (allocated(ufs_mesh % width)) deallocate(ufs_mesh % width)
|
||||
deallocate(ufs_mesh)
|
||||
end if
|
||||
|
||||
end subroutine free_memory
|
||||
|
||||
!===============================================================================
|
||||
! OVERALL_GENERATION determines the overall generation number
|
||||
!===============================================================================
|
||||
|
||||
pure function overall_generation() result(gen)
|
||||
integer :: gen
|
||||
gen = gen_per_batch*(current_batch - 1) + current_gen
|
||||
end function overall_generation
|
||||
|
||||
end module global
|
||||
|
|
@ -9,30 +9,26 @@ module initialize
|
|||
|
||||
use bank_header, only: Bank
|
||||
use constants
|
||||
use dict_header, only: DictIntInt, ElemKeyValueII
|
||||
use set_header, only: SetInt
|
||||
use error, only: fatal_error, warning
|
||||
use geometry, only: neighbor_lists, count_instance, calc_offsets, &
|
||||
maximum_levels
|
||||
use geometry_header, only: Cell, Universe, Lattice, RectLattice, HexLattice,&
|
||||
root_universe
|
||||
use global
|
||||
use hdf5_interface, only: file_open, read_attribute, file_close, &
|
||||
hdf5_bank_t, hdf5_integer8_t
|
||||
use input_xml, only: read_input_xml, read_plots_xml
|
||||
use input_xml, only: read_input_xml
|
||||
use material_header, only: Material
|
||||
use message_passing
|
||||
use mgxs_data, only: read_mgxs, create_macro_xs
|
||||
use output, only: print_version, write_message, print_usage, &
|
||||
print_plot
|
||||
use random_lcg, only: initialize_prng
|
||||
use state_point, only: load_state_point
|
||||
use output, only: print_version, write_message, print_usage
|
||||
use random_lcg, only: openmc_set_seed, seed
|
||||
use settings
|
||||
#ifdef _OPENMP
|
||||
use simulation_header, only: n_threads
|
||||
#endif
|
||||
use string, only: to_str, starts_with, ends_with, str_to_int
|
||||
use summary, only: write_summary
|
||||
use tally_header, only: TallyObject
|
||||
use tally_initialize,only: configure_tallies
|
||||
use tally_filter
|
||||
use tally, only: init_tally_routines
|
||||
use timer_header
|
||||
|
||||
implicit none
|
||||
|
||||
|
|
@ -48,6 +44,8 @@ contains
|
|||
subroutine openmc_init(intracomm) bind(C)
|
||||
integer, intent(in), optional :: intracomm ! MPI intracommunicator
|
||||
|
||||
integer :: err
|
||||
|
||||
! Copy the communicator to a new variable. This is done to avoid changing
|
||||
! the signature of this subroutine. If MPI is being used but no communicator
|
||||
! was passed, assume MPI_COMM_WORLD.
|
||||
|
|
@ -84,75 +82,16 @@ contains
|
|||
! Read command line arguments
|
||||
call read_command_line()
|
||||
|
||||
! Initialize random number generator -- if the user specifies a seed, it
|
||||
! will be re-initialized later
|
||||
err = openmc_set_seed(seed)
|
||||
|
||||
! Read XML input files
|
||||
call read_input_xml()
|
||||
|
||||
! Initialize random number generator -- this has to be done after the input
|
||||
! files have been read in case the user specified a seed for the random
|
||||
! number generator
|
||||
|
||||
call initialize_prng()
|
||||
|
||||
! Read plots.xml if it exists -- this has to be done separate from the other
|
||||
! XML files because we need the PRNG to be initialized first
|
||||
if (run_mode == MODE_PLOTTING) call read_plots_xml()
|
||||
|
||||
! Use dictionaries to redefine index pointers
|
||||
call adjust_indices()
|
||||
|
||||
! 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(root_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
|
||||
! Allocate and setup tally stride, filter_matches, and tally maps
|
||||
call configure_tallies()
|
||||
|
||||
! Set up tally procedure pointers
|
||||
call init_tally_routines()
|
||||
|
||||
! Determine how much work each processor should do
|
||||
call calculate_work()
|
||||
|
||||
! Allocate source bank, and for eigenvalue simulations also allocate the
|
||||
! fission bank
|
||||
call allocate_banks()
|
||||
|
||||
! If this is a restart run, load the state point data and binary source
|
||||
! file
|
||||
if (restart_run) call load_state_point()
|
||||
end if
|
||||
|
||||
if (master) then
|
||||
if (run_mode == MODE_PLOTTING) then
|
||||
! Display plotting information
|
||||
if (verbosity >= 5) call print_plot()
|
||||
else
|
||||
! Write summary information
|
||||
if (output_summary) call write_summary()
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check for particle restart run
|
||||
if (particle_restart_run) run_mode = MODE_PARTICLE
|
||||
|
||||
! Warn if overlap checking is on
|
||||
if (master .and. check_overlaps .and. run_mode /= MODE_PLOTTING) then
|
||||
call warning("Cell overlap checking is ON.")
|
||||
end if
|
||||
|
||||
! Stop initialization timer
|
||||
call time_initialize%stop()
|
||||
|
||||
|
|
@ -172,6 +111,7 @@ contains
|
|||
integer, intent(in) :: intracomm ! MPI intracommunicator
|
||||
#endif
|
||||
|
||||
integer :: mpi_err ! MPI error code
|
||||
integer :: bank_blocks(6) ! Count for each datatype
|
||||
#ifdef MPIF08
|
||||
type(MPI_Datatype) :: bank_types(6)
|
||||
|
|
@ -427,450 +367,4 @@ contains
|
|||
|
||||
end subroutine read_command_line
|
||||
|
||||
!===============================================================================
|
||||
! ADJUST_INDICES changes the values for 'surfaces' for each cell and the
|
||||
! material index assigned to each to the indices in the surfaces and material
|
||||
! array rather than the unique IDs assigned to each surface and material. Also
|
||||
! assigns boundary conditions to surfaces based on those read into the bc_dict
|
||||
! dictionary
|
||||
!===============================================================================
|
||||
|
||||
subroutine adjust_indices()
|
||||
|
||||
integer :: i ! index for various purposes
|
||||
integer :: j ! index for various purposes
|
||||
integer :: k ! loop index for lattices
|
||||
integer :: m ! loop index for lattices
|
||||
integer :: lid ! lattice IDs
|
||||
integer :: i_array ! index in surfaces/materials array
|
||||
integer :: id ! user-specified id
|
||||
type(Cell), pointer :: c => null()
|
||||
class(Lattice), pointer :: lat => null()
|
||||
|
||||
do i = 1, n_cells
|
||||
! =======================================================================
|
||||
! ADJUST REGION SPECIFICATION FOR EACH CELL
|
||||
|
||||
c => cells(i)
|
||||
do j = 1, size(c%region)
|
||||
id = c%region(j)
|
||||
! Make sure that only regions are checked. Since OP_UNION is the
|
||||
! operator with the lowest integer value, anything below it must denote
|
||||
! a half-space
|
||||
if (id < OP_UNION) then
|
||||
if (surface_dict%has_key(abs(id))) then
|
||||
i_array = surface_dict%get_key(abs(id))
|
||||
c%region(j) = sign(i_array, id)
|
||||
else
|
||||
call fatal_error("Could not find surface " // trim(to_str(abs(id)))&
|
||||
&// " specified on cell " // trim(to_str(c%id)))
|
||||
end if
|
||||
end if
|
||||
end do
|
||||
|
||||
! Also adjust the indices in the reverse Polish notation
|
||||
do j = 1, size(c%rpn)
|
||||
id = c%rpn(j)
|
||||
! Again, make sure that only regions are checked
|
||||
if (id < OP_UNION) then
|
||||
i_array = surface_dict%get_key(abs(id))
|
||||
c%rpn(j) = sign(i_array, id)
|
||||
end if
|
||||
end do
|
||||
|
||||
! =======================================================================
|
||||
! ADJUST UNIVERSE INDEX FOR EACH CELL
|
||||
|
||||
id = c%universe
|
||||
if (universe_dict%has_key(id)) then
|
||||
c%universe = universe_dict%get_key(id)
|
||||
else
|
||||
call fatal_error("Could not find universe " // trim(to_str(id)) &
|
||||
&// " specified on cell " // trim(to_str(c%id)))
|
||||
end if
|
||||
|
||||
! =======================================================================
|
||||
! ADJUST MATERIAL/FILL POINTERS FOR EACH CELL
|
||||
|
||||
if (c % material(1) == NONE) then
|
||||
id = c % fill
|
||||
if (universe_dict % has_key(id)) then
|
||||
c % type = FILL_UNIVERSE
|
||||
c % fill = universe_dict % get_key(id)
|
||||
elseif (lattice_dict % has_key(id)) then
|
||||
lid = lattice_dict % get_key(id)
|
||||
c % type = FILL_LATTICE
|
||||
c % fill = lid
|
||||
else
|
||||
call fatal_error("Specified fill " // trim(to_str(id)) // " on cell "&
|
||||
// trim(to_str(c % id)) // " is neither a universe nor a &
|
||||
&lattice.")
|
||||
end if
|
||||
else
|
||||
do j = 1, size(c % material)
|
||||
id = c % material(j)
|
||||
if (id == MATERIAL_VOID) then
|
||||
c % type = FILL_MATERIAL
|
||||
else if (material_dict % has_key(id)) then
|
||||
c % type = FILL_MATERIAL
|
||||
c % material(j) = material_dict % get_key(id)
|
||||
else
|
||||
call fatal_error("Could not find material " // trim(to_str(id)) &
|
||||
// " specified on cell " // trim(to_str(c % id)))
|
||||
end if
|
||||
end do
|
||||
end if
|
||||
end do
|
||||
|
||||
! ==========================================================================
|
||||
! ADJUST UNIVERSE INDICES FOR EACH LATTICE
|
||||
|
||||
do i = 1, n_lattices
|
||||
lat => lattices(i)%obj
|
||||
select type (lat)
|
||||
|
||||
type is (RectLattice)
|
||||
do m = 1, lat%n_cells(3)
|
||||
do k = 1, lat%n_cells(2)
|
||||
do j = 1, lat%n_cells(1)
|
||||
id = lat%universes(j,k,m)
|
||||
if (universe_dict%has_key(id)) then
|
||||
lat%universes(j,k,m) = universe_dict%get_key(id)
|
||||
else
|
||||
call fatal_error("Invalid universe number " &
|
||||
&// trim(to_str(id)) // " specified on lattice " &
|
||||
&// trim(to_str(lat%id)))
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
end do
|
||||
|
||||
type is (HexLattice)
|
||||
do m = 1, lat%n_axial
|
||||
do k = 1, 2*lat%n_rings - 1
|
||||
do j = 1, 2*lat%n_rings - 1
|
||||
if (j + k < lat%n_rings + 1) then
|
||||
cycle
|
||||
else if (j + k > 3*lat%n_rings - 1) then
|
||||
cycle
|
||||
end if
|
||||
id = lat%universes(j, k, m)
|
||||
if (universe_dict%has_key(id)) then
|
||||
lat%universes(j, k, m) = universe_dict%get_key(id)
|
||||
else
|
||||
call fatal_error("Invalid universe number " &
|
||||
&// trim(to_str(id)) // " specified on lattice " &
|
||||
&// trim(to_str(lat%id)))
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
end do
|
||||
|
||||
end select
|
||||
|
||||
if (lat%outer /= NO_OUTER_UNIVERSE) then
|
||||
if (universe_dict%has_key(lat%outer)) then
|
||||
lat%outer = universe_dict%get_key(lat%outer)
|
||||
else
|
||||
call fatal_error("Invalid universe number " &
|
||||
&// trim(to_str(lat%outer)) &
|
||||
&// " specified on lattice " // trim(to_str(lat%id)))
|
||||
end if
|
||||
end if
|
||||
|
||||
end do
|
||||
|
||||
! =======================================================================
|
||||
! ADJUST INDICES FOR EACH TALLY FILTER
|
||||
|
||||
FILTER_LOOP: do i = 1, n_filters
|
||||
|
||||
select type(filt => filters(i) % obj)
|
||||
type is (SurfaceFilter)
|
||||
! Check if this is a surface filter only for surface currents
|
||||
if (.not. filt % current) call filt % initialize()
|
||||
class default
|
||||
call filt % initialize()
|
||||
end select
|
||||
|
||||
end do FILTER_LOOP
|
||||
|
||||
end subroutine adjust_indices
|
||||
|
||||
!===============================================================================
|
||||
! CALCULATE_WORK determines how many particles each processor should simulate
|
||||
!===============================================================================
|
||||
|
||||
subroutine calculate_work()
|
||||
|
||||
integer :: i ! loop index
|
||||
integer :: remainder ! Number of processors with one extra particle
|
||||
integer(8) :: i_bank ! Running count of number of particles
|
||||
integer(8) :: min_work ! Minimum number of particles on each proc
|
||||
integer(8) :: work_i ! Number of particles on rank i
|
||||
|
||||
allocate(work_index(0:n_procs))
|
||||
|
||||
! Determine minimum amount of particles to simulate on each processor
|
||||
min_work = n_particles/n_procs
|
||||
|
||||
! Determine number of processors that have one extra particle
|
||||
remainder = int(mod(n_particles, int(n_procs,8)), 4)
|
||||
|
||||
i_bank = 0
|
||||
work_index(0) = 0
|
||||
do i = 0, n_procs - 1
|
||||
! Number of particles for rank i
|
||||
if (i < remainder) then
|
||||
work_i = min_work + 1
|
||||
else
|
||||
work_i = min_work
|
||||
end if
|
||||
|
||||
! Set number of particles
|
||||
if (rank == i) work = work_i
|
||||
|
||||
! Set index into source bank for rank i
|
||||
i_bank = i_bank + work_i
|
||||
work_index(i+1) = i_bank
|
||||
end do
|
||||
|
||||
end subroutine calculate_work
|
||||
|
||||
!===============================================================================
|
||||
! ALLOCATE_BANKS allocates memory for the fission and source banks
|
||||
!===============================================================================
|
||||
|
||||
subroutine allocate_banks()
|
||||
|
||||
integer :: alloc_err ! allocation error code
|
||||
|
||||
! Allocate source bank
|
||||
allocate(source_bank(work), STAT=alloc_err)
|
||||
|
||||
! Check for allocation errors
|
||||
if (alloc_err /= 0) then
|
||||
call fatal_error("Failed to allocate source bank.")
|
||||
end if
|
||||
|
||||
if (run_mode == MODE_EIGENVALUE) then
|
||||
#ifdef _OPENMP
|
||||
! If OpenMP is being used, each thread needs its own private fission
|
||||
! bank. Since the private fission banks need to be combined at the end of
|
||||
! a generation, there is also a 'master_fission_bank' that is used to
|
||||
! collect the sites from each thread.
|
||||
|
||||
n_threads = omp_get_max_threads()
|
||||
|
||||
!$omp parallel
|
||||
thread_id = omp_get_thread_num()
|
||||
|
||||
if (thread_id == 0) then
|
||||
allocate(fission_bank(3*work))
|
||||
else
|
||||
allocate(fission_bank(3*work/n_threads))
|
||||
end if
|
||||
!$omp end parallel
|
||||
allocate(master_fission_bank(3*work), STAT=alloc_err)
|
||||
#else
|
||||
allocate(fission_bank(3*work), STAT=alloc_err)
|
||||
#endif
|
||||
|
||||
! Check for allocation errors
|
||||
if (alloc_err /= 0) then
|
||||
call fatal_error("Failed to allocate fission bank.")
|
||||
end if
|
||||
end if
|
||||
|
||||
end subroutine allocate_banks
|
||||
|
||||
!===============================================================================
|
||||
! PREPARE_DISTRIBCELL initializes any distribcell filters present and sets the
|
||||
! offsets for distribcells
|
||||
!===============================================================================
|
||||
|
||||
subroutine prepare_distribcell()
|
||||
|
||||
integer :: i, j ! Tally, filter loop counters
|
||||
logical :: distribcell_active ! Does simulation use distribcell?
|
||||
integer, allocatable :: univ_list(:) ! Target offsets
|
||||
integer, allocatable :: counts(:,:) ! Target count
|
||||
logical, allocatable :: found(:,:) ! Target found
|
||||
|
||||
! Assume distribcell is not needed until proven otherwise.
|
||||
distribcell_active = .false.
|
||||
|
||||
! We need distribcell if any tallies have distribcell filters.
|
||||
do i = 1, n_tallies
|
||||
do j = 1, size(tallies(i) % filter)
|
||||
select type(filt => filters(tallies(i) % filter(j)) % obj)
|
||||
type is (DistribcellFilter)
|
||||
distribcell_active = .true.
|
||||
end select
|
||||
end do
|
||||
end do
|
||||
|
||||
! We also need distribcell if any distributed materials or distributed
|
||||
! temperatues are present.
|
||||
if (.not. distribcell_active) then
|
||||
do i = 1, n_cells
|
||||
if (size(cells(i) % material) > 1 .or. size(cells(i) % sqrtkT) > 1) then
|
||||
distribcell_active = .true.
|
||||
exit
|
||||
end if
|
||||
end do
|
||||
end if
|
||||
|
||||
! If distribcell isn't used in this simulation then no more work left to do.
|
||||
if (.not. distribcell_active) return
|
||||
|
||||
! Count the number of instances of each cell.
|
||||
call count_instance(universes(root_universe))
|
||||
|
||||
! Set the number of bins in all distribcell filters.
|
||||
do i = 1, n_tallies
|
||||
do j = 1, size(tallies(i) % filter)
|
||||
select type(filt => filters(tallies(i) % filter(j)) % obj)
|
||||
type is (DistribcellFilter)
|
||||
! Set the number of bins to the number of instances of the cell.
|
||||
filt % n_bins = cells(filt % cell) % instances
|
||||
end select
|
||||
end do
|
||||
end do
|
||||
|
||||
! Make sure the number of materials and temperatures matches the number of
|
||||
! cell instances.
|
||||
do i = 1, n_cells
|
||||
associate (c => cells(i))
|
||||
if (size(c % material) > 1) then
|
||||
if (size(c % material) /= c % instances) then
|
||||
call fatal_error("Cell " // trim(to_str(c % id)) // " was &
|
||||
&specified with " // trim(to_str(size(c % material))) &
|
||||
// " materials but has " // trim(to_str(c % instances)) &
|
||||
// " distributed instances. The number of materials must &
|
||||
&equal one or the number of instances.")
|
||||
end if
|
||||
end if
|
||||
if (size(c % sqrtkT) > 1) then
|
||||
if (size(c % sqrtkT) /= c % instances) then
|
||||
call fatal_error("Cell " // trim(to_str(c % id)) // " was &
|
||||
&specified with " // trim(to_str(size(c % sqrtkT))) &
|
||||
// " temperatures but has " // trim(to_str(c % instances)) &
|
||||
// " distributed instances. The number of temperatures must &
|
||||
&equal one or the number of instances.")
|
||||
end if
|
||||
end if
|
||||
end associate
|
||||
end do
|
||||
|
||||
! Allocate offset maps at each level in the geometry
|
||||
call allocate_offsets(univ_list, counts, found)
|
||||
|
||||
! Calculate offsets for each target distribcell
|
||||
do i = 1, n_maps
|
||||
do j = 1, n_universes
|
||||
call calc_offsets(univ_list(i), i, universes(j), counts, found)
|
||||
end do
|
||||
end do
|
||||
|
||||
end subroutine prepare_distribcell
|
||||
|
||||
!===============================================================================
|
||||
! ALLOCATE_OFFSETS determines the number of maps needed and allocates required
|
||||
! memory for distribcell offset tables
|
||||
!===============================================================================
|
||||
|
||||
recursive subroutine allocate_offsets(univ_list, counts, found)
|
||||
|
||||
integer, intent(out), allocatable :: univ_list(:) ! Target offsets
|
||||
integer, intent(out), allocatable :: counts(:,:) ! Target count
|
||||
logical, intent(out), allocatable :: found(:,:) ! Target found
|
||||
|
||||
integer :: i, j, k ! Loop counters
|
||||
type(SetInt) :: cell_list ! distribells to track
|
||||
|
||||
! Begin gathering list of cells in distribcell tallies
|
||||
n_maps = 0
|
||||
|
||||
! List all cells referenced in distribcell filters.
|
||||
do i = 1, n_tallies
|
||||
do j = 1, size(tallies(i) % filter)
|
||||
select type(filt => filters(tallies(i) % filter(j)) % obj)
|
||||
type is (DistribcellFilter)
|
||||
call cell_list % add(filt % cell)
|
||||
end select
|
||||
end do
|
||||
end do
|
||||
|
||||
! List all cells with multiple (distributed) materials or temperatures.
|
||||
do i = 1, n_cells
|
||||
if (size(cells(i) % material) > 1 .or. size(cells(i) % sqrtkT) > 1) then
|
||||
call cell_list % add(i)
|
||||
end if
|
||||
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
|
||||
do j = 1, size(universes(i) % cells)
|
||||
if (cell_list % contains(universes(i) % cells(j))) then
|
||||
n_maps = n_maps + 1
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
|
||||
! Allocate the list of offset tables for each unique universe
|
||||
allocate(univ_list(n_maps))
|
||||
|
||||
! Allocate list to accumulate target distribcell counts in each universe
|
||||
allocate(counts(n_universes, n_maps))
|
||||
counts(:,:) = 0
|
||||
|
||||
! Allocate list to track if target distribcells are found in each universe
|
||||
allocate(found(n_universes, n_maps))
|
||||
found(:,:) = .false.
|
||||
|
||||
|
||||
! Search through universes for distributed cells and assign each one a
|
||||
! unique distribcell array index.
|
||||
k = 1
|
||||
do i = 1, n_universes
|
||||
do j = 1, size(universes(i) % cells)
|
||||
if (cell_list % contains(universes(i) % cells(j))) then
|
||||
cells(universes(i) % cells(j)) % distribcell_index = k
|
||||
univ_list(k) = universes(i) % id
|
||||
k = k + 1
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
|
||||
! Allocate the offset tables for lattices
|
||||
do i = 1, n_lattices
|
||||
associate(lat => lattices(i) % obj)
|
||||
select type(lat)
|
||||
|
||||
type is (RectLattice)
|
||||
allocate(lat % offset(n_maps, lat % n_cells(1), lat % n_cells(2), &
|
||||
lat % n_cells(3)))
|
||||
type is (HexLattice)
|
||||
allocate(lat % offset(n_maps, 2 * lat % n_rings - 1, &
|
||||
2 * lat % n_rings - 1, lat % n_axial))
|
||||
end select
|
||||
|
||||
lat % offset(:, :, :, :) = 0
|
||||
end associate
|
||||
end do
|
||||
|
||||
! Allocate offset table for fill cells
|
||||
do i = 1, n_cells
|
||||
if (cells(i) % type /= FILL_MATERIAL) then
|
||||
allocate(cells(i) % offset(n_maps))
|
||||
end if
|
||||
end do
|
||||
|
||||
! Free up memory
|
||||
call cell_list % clear()
|
||||
|
||||
end subroutine allocate_offsets
|
||||
|
||||
end module initialize
|
||||
|
|
|
|||
2656
src/input_xml.F90
2656
src/input_xml.F90
File diff suppressed because it is too large
Load diff
15
src/main.F90
15
src/main.F90
|
|
@ -1,17 +1,18 @@
|
|||
program main
|
||||
|
||||
use constants
|
||||
use finalize, only: openmc_finalize
|
||||
use global
|
||||
use initialize, only: openmc_init
|
||||
use message_passing
|
||||
use particle_restart, only: run_particle_restart
|
||||
use plot, only: openmc_plot_geometry
|
||||
use simulation, only: openmc_run
|
||||
use volume_calc, only: openmc_calculate_volumes
|
||||
use openmc_api, only: openmc_init, openmc_finalize, openmc_run, &
|
||||
openmc_plot_geometry, openmc_calculate_volumes
|
||||
use particle_restart, only: run_particle_restart
|
||||
use settings, only: run_mode
|
||||
|
||||
implicit none
|
||||
|
||||
#ifdef MPI
|
||||
integer :: mpi_err ! MPI error code
|
||||
#endif
|
||||
|
||||
! Initialize run -- when run with MPI, pass communicator
|
||||
#ifdef MPI
|
||||
#ifdef MPIF08
|
||||
|
|
|
|||
|
|
@ -1,18 +1,36 @@
|
|||
module material_header
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use constants
|
||||
use nuclide_header, only: Nuclide
|
||||
use dict_header, only: DictIntInt
|
||||
use error
|
||||
use nuclide_header
|
||||
use sab_header
|
||||
use stl_vector, only: VectorReal, VectorInt
|
||||
use string, only: to_str
|
||||
|
||||
implicit none
|
||||
|
||||
private
|
||||
public :: free_memory_material
|
||||
public :: openmc_extend_materials
|
||||
public :: openmc_get_material_index
|
||||
public :: openmc_material_add_nuclide
|
||||
public :: openmc_material_get_id
|
||||
public :: openmc_material_get_densities
|
||||
public :: openmc_material_set_density
|
||||
public :: openmc_material_set_densities
|
||||
public :: openmc_material_set_id
|
||||
|
||||
!===============================================================================
|
||||
! MATERIAL describes a material by its constituent nuclides
|
||||
!===============================================================================
|
||||
|
||||
type Material
|
||||
type, public :: Material
|
||||
integer :: id ! unique identifier
|
||||
character(len=104) :: name = "" ! User-defined name
|
||||
integer :: n_nuclides ! number of nuclides
|
||||
integer :: n_nuclides = 0 ! number of nuclides
|
||||
integer, allocatable :: nuclide(:) ! index in nuclides array
|
||||
integer, allocatable :: element(:) ! index in elements array
|
||||
real(8) :: density ! total atom density in atom/b-cm
|
||||
|
|
@ -45,25 +63,31 @@ module material_header
|
|||
|
||||
contains
|
||||
procedure :: set_density => material_set_density
|
||||
procedure :: assign_sab_tables => material_assign_sab_tables
|
||||
end type Material
|
||||
|
||||
integer(C_INT32_T), public, bind(C) :: n_materials ! # of materials
|
||||
|
||||
type(Material), public, allocatable, target :: materials(:)
|
||||
|
||||
! Dictionary that maps user IDs to indices in 'materials'
|
||||
type(DictIntInt), public :: material_dict
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! MATERIAL_SET_DENSITY sets the total density of a material in atom/b-cm.
|
||||
!===============================================================================
|
||||
|
||||
function material_set_density(m, density, nuclides) result(err)
|
||||
function material_set_density(m, density) result(err)
|
||||
class(Material), intent(inout) :: m
|
||||
real(8), intent(in) :: density
|
||||
type(Nuclide), intent(in) :: nuclides(:)
|
||||
integer :: err
|
||||
|
||||
integer :: i
|
||||
real(8) :: sum_percent
|
||||
real(8) :: awr
|
||||
|
||||
err = -1
|
||||
if (allocated(m % atom_density)) then
|
||||
! Set total density based on value provided
|
||||
m % density = density
|
||||
|
|
@ -83,7 +107,393 @@ contains
|
|||
+ m % atom_density(i) * awr * MASS_NEUTRON / N_AVOGADRO
|
||||
end do
|
||||
err = 0
|
||||
else
|
||||
err = E_ALLOCATE
|
||||
call set_errmsg("Material atom density array hasn't been allocated.")
|
||||
end if
|
||||
end function material_set_density
|
||||
|
||||
!===============================================================================
|
||||
! ASSIGN_SAB_TABLES assigns S(alpha,beta) tables to specific nuclides within
|
||||
! materials so the code knows when to apply bound thermal scattering data
|
||||
!===============================================================================
|
||||
|
||||
subroutine material_assign_sab_tables(this)
|
||||
class(Material), intent(inout) :: this
|
||||
|
||||
integer :: j ! index over nuclides in material
|
||||
integer :: k ! index over S(a,b) tables in material
|
||||
integer :: m ! position for sorting
|
||||
integer :: temp_nuclide ! temporary value for sorting
|
||||
integer :: temp_table ! temporary value for sorting
|
||||
real(8) :: temp_frac ! temporary value for sorting
|
||||
logical :: found
|
||||
type(VectorInt) :: i_sab_tables
|
||||
type(VectorInt) :: i_sab_nuclides
|
||||
type(VectorReal) :: sab_fracs
|
||||
|
||||
if (.not. allocated(this % i_sab_tables)) return
|
||||
|
||||
ASSIGN_SAB: do k = 1, size(this % i_sab_tables)
|
||||
! In order to know which nuclide the S(a,b) table applies to, we need
|
||||
! to search through the list of nuclides for one which has a matching
|
||||
! name
|
||||
found = .false.
|
||||
associate (sab => sab_tables(this % i_sab_tables(k)))
|
||||
FIND_NUCLIDE: do j = 1, size(this % nuclide)
|
||||
if (any(sab % nuclides == nuclides(this % nuclide(j)) % name)) then
|
||||
call i_sab_tables % push_back(this % i_sab_tables(k))
|
||||
call i_sab_nuclides % push_back(j)
|
||||
call sab_fracs % push_back(this % sab_fracs(k))
|
||||
found = .true.
|
||||
end if
|
||||
end do FIND_NUCLIDE
|
||||
end associate
|
||||
|
||||
! Check to make sure S(a,b) table matched a nuclide
|
||||
if (.not. found) then
|
||||
call fatal_error("S(a,b) table " // trim(this % &
|
||||
sab_names(k)) // " did not match any nuclide on material " &
|
||||
// trim(to_str(this % id)))
|
||||
end if
|
||||
end do ASSIGN_SAB
|
||||
|
||||
! Make sure each nuclide only appears in one table.
|
||||
do j = 1, i_sab_nuclides % size()
|
||||
do k = j+1, i_sab_nuclides % size()
|
||||
if (i_sab_nuclides % data(j) == i_sab_nuclides % data(k)) then
|
||||
call fatal_error(trim( &
|
||||
nuclides(this % nuclide(i_sab_nuclides % data(j))) % name) &
|
||||
// " in material " // trim(to_str(this % id)) // " was found &
|
||||
&in multiple S(a,b) tables. Each nuclide can only appear in &
|
||||
&one S(a,b) table per material.")
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
|
||||
! Update i_sab_tables and i_sab_nuclides
|
||||
deallocate(this % i_sab_tables)
|
||||
deallocate(this % sab_fracs)
|
||||
if (allocated(this % i_sab_nuclides)) deallocate(this % i_sab_nuclides)
|
||||
m = i_sab_tables % size()
|
||||
allocate(this % i_sab_tables(m))
|
||||
allocate(this % i_sab_nuclides(m))
|
||||
allocate(this % sab_fracs(m))
|
||||
this % i_sab_tables(:) = i_sab_tables % data(1:m)
|
||||
this % i_sab_nuclides(:) = i_sab_nuclides % data(1:m)
|
||||
this % sab_fracs(:) = sab_fracs % data(1:m)
|
||||
|
||||
! Clear entries in vectors for next material
|
||||
call i_sab_tables % clear()
|
||||
call i_sab_nuclides % clear()
|
||||
call sab_fracs % clear()
|
||||
|
||||
! If there are multiple S(a,b) tables, we need to make sure that the
|
||||
! entries in i_sab_nuclides are sorted or else they won't be applied
|
||||
! correctly in the cross_section module. The algorithm here is a simple
|
||||
! insertion sort -- don't need anything fancy!
|
||||
|
||||
if (size(this % i_sab_tables) > 1) then
|
||||
SORT_SAB: do k = 2, size(this % i_sab_tables)
|
||||
! Save value to move
|
||||
m = k
|
||||
temp_nuclide = this % i_sab_nuclides(k)
|
||||
temp_table = this % i_sab_tables(k)
|
||||
temp_frac = this % i_sab_tables(k)
|
||||
|
||||
MOVE_OVER: do
|
||||
! Check if insertion value is greater than (m-1)th value
|
||||
if (temp_nuclide >= this % i_sab_nuclides(m-1)) exit
|
||||
|
||||
! Move values over until hitting one that's not larger
|
||||
this % i_sab_nuclides(m) = this % i_sab_nuclides(m-1)
|
||||
this % i_sab_tables(m) = this % i_sab_tables(m-1)
|
||||
this % sab_fracs(m) = this % sab_fracs(m-1)
|
||||
m = m - 1
|
||||
|
||||
! Exit if we've reached the beginning of the list
|
||||
if (m == 1) exit
|
||||
end do MOVE_OVER
|
||||
|
||||
! Put the original value into its new position
|
||||
this % i_sab_nuclides(m) = temp_nuclide
|
||||
this % i_sab_tables(m) = temp_table
|
||||
this % sab_fracs(m) = temp_frac
|
||||
end do SORT_SAB
|
||||
end if
|
||||
|
||||
! Deallocate temporary arrays for names of nuclides and S(a,b) tables
|
||||
if (allocated(this % names)) deallocate(this % names)
|
||||
end subroutine material_assign_sab_tables
|
||||
|
||||
!===============================================================================
|
||||
! FREE_MEMORY_MATERIAL deallocates global arrays defined in this module
|
||||
!===============================================================================
|
||||
|
||||
subroutine free_memory_material()
|
||||
n_materials = 0
|
||||
if (allocated(materials)) deallocate(materials)
|
||||
call material_dict % clear()
|
||||
end subroutine free_memory_material
|
||||
|
||||
!===============================================================================
|
||||
! C API FUNCTIONS
|
||||
!===============================================================================
|
||||
|
||||
function openmc_extend_materials(n, index_start, index_end) result(err) bind(C)
|
||||
! Extend the materials array by n elements
|
||||
integer(C_INT32_T), value, intent(in) :: n
|
||||
integer(C_INT32_T), optional, intent(out) :: index_start
|
||||
integer(C_INT32_T), optional, intent(out) :: index_end
|
||||
integer(C_INT) :: err
|
||||
|
||||
type(Material), allocatable :: temp(:) ! temporary materials array
|
||||
|
||||
if (n_materials == 0) then
|
||||
! Allocate materials array
|
||||
allocate(materials(n))
|
||||
else
|
||||
! Allocate materials array with increased size
|
||||
allocate(temp(n_materials + n))
|
||||
|
||||
! Move original materials to temporary array
|
||||
temp(1:n_materials) = materials(:)
|
||||
|
||||
! Move allocation from temporary array
|
||||
call move_alloc(FROM=temp, TO=materials)
|
||||
end if
|
||||
|
||||
! Return indices in materials array
|
||||
if (present(index_start)) index_start = n_materials + 1
|
||||
if (present(index_end)) index_end = n_materials + n
|
||||
n_materials = n_materials + n
|
||||
|
||||
err = 0
|
||||
end function openmc_extend_materials
|
||||
|
||||
function openmc_get_material_index(id, index) result(err) bind(C)
|
||||
! Returns the index in the materials array of a material with a given ID
|
||||
integer(C_INT32_T), value :: id
|
||||
integer(C_INT32_T), intent(out) :: index
|
||||
integer(C_INT) :: err
|
||||
|
||||
if (allocated(materials)) then
|
||||
if (material_dict % has(id)) then
|
||||
index = material_dict % get(id)
|
||||
err = 0
|
||||
else
|
||||
err = E_INVALID_ID
|
||||
call set_errmsg("No material exists with ID=" // trim(to_str(id)) // ".")
|
||||
end if
|
||||
else
|
||||
err = E_ALLOCATE
|
||||
call set_errmsg("Memory has not been allocated for materials.")
|
||||
end if
|
||||
end function openmc_get_material_index
|
||||
|
||||
|
||||
function openmc_material_add_nuclide(index, name, density) result(err) bind(C)
|
||||
! Add a nuclide at a specified density in atom/b-cm to a material
|
||||
integer(C_INT32_T), value, intent(in) :: index
|
||||
character(kind=C_CHAR) :: name(*)
|
||||
real(C_DOUBLE), value, intent(in) :: density
|
||||
integer(C_INT) :: err
|
||||
|
||||
integer :: j, k, n
|
||||
real(8) :: awr
|
||||
integer, allocatable :: new_nuclide(:)
|
||||
real(8), allocatable :: new_density(:)
|
||||
logical, allocatable :: new_p0(:)
|
||||
character(:), allocatable :: name_
|
||||
|
||||
name_ = to_f_string(name)
|
||||
|
||||
err = E_UNASSIGNED
|
||||
if (index >= 1 .and. index <= size(materials)) then
|
||||
associate (m => materials(index))
|
||||
! Check if nuclide is already in material
|
||||
do j = 1, m % n_nuclides
|
||||
k = m % nuclide(j)
|
||||
if (nuclides(k) % name == name_) then
|
||||
awr = nuclides(k) % awr
|
||||
m % density = m % density + density - m % atom_density(j)
|
||||
m % density_gpcc = m % density_gpcc + (density - &
|
||||
m % atom_density(j)) * awr * MASS_NEUTRON / N_AVOGADRO
|
||||
m % atom_density(j) = density
|
||||
err = 0
|
||||
end if
|
||||
end do
|
||||
|
||||
! If nuclide wasn't found, extend nuclide/density arrays
|
||||
if (err /= 0) then
|
||||
! If nuclide hasn't been loaded, load it now
|
||||
err = openmc_load_nuclide(name)
|
||||
|
||||
if (err == 0) then
|
||||
! Extend arrays
|
||||
n = m % n_nuclides
|
||||
allocate(new_nuclide(n + 1))
|
||||
if (n > 0) new_nuclide(1:n) = m % nuclide
|
||||
call move_alloc(FROM=new_nuclide, TO=m % nuclide)
|
||||
|
||||
allocate(new_density(n + 1))
|
||||
if (n > 0) new_density(1:n) = m % atom_density
|
||||
call move_alloc(FROM=new_density, TO=m % atom_density)
|
||||
|
||||
allocate(new_p0(n + 1))
|
||||
if (n > 0) new_p0(1:n) = m % p0
|
||||
new_p0(n + 1) = .false.
|
||||
call move_alloc(FROM=new_p0, TO=m % p0)
|
||||
|
||||
! Append new nuclide/density
|
||||
k = nuclide_dict % get(to_lower(name_))
|
||||
m % nuclide(n + 1) = k
|
||||
m % atom_density(n + 1) = density
|
||||
m % density = m % density + density
|
||||
m % density_gpcc = m % density_gpcc + &
|
||||
density * nuclides(k) % awr * MASS_NEUTRON / N_AVOGADRO
|
||||
m % n_nuclides = n + 1
|
||||
end if
|
||||
end if
|
||||
end associate
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in materials array is out of bounds.")
|
||||
end if
|
||||
|
||||
end function openmc_material_add_nuclide
|
||||
|
||||
|
||||
function openmc_material_get_densities(index, nuclides, densities, n) &
|
||||
result(err) bind(C)
|
||||
! returns an array of nuclide densities in a material
|
||||
integer(C_INT32_T), value :: index
|
||||
type(C_PTR), intent(out) :: nuclides
|
||||
type(C_PTR), intent(out) :: densities
|
||||
integer(C_INT), intent(out) :: n
|
||||
integer(C_INT) :: err
|
||||
|
||||
if (index >= 1 .and. index <= size(materials)) then
|
||||
associate (m => materials(index))
|
||||
if (allocated(m % atom_density)) then
|
||||
nuclides = C_LOC(m % nuclide(1))
|
||||
densities = C_LOC(m % atom_density(1))
|
||||
n = size(m % atom_density)
|
||||
err = 0
|
||||
else
|
||||
err = E_ALLOCATE
|
||||
call set_errmsg("Material atom density array has not been allocated.")
|
||||
end if
|
||||
end associate
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in materials array is out of bounds.")
|
||||
end if
|
||||
end function openmc_material_get_densities
|
||||
|
||||
|
||||
function openmc_material_get_id(index, id) result(err) bind(C)
|
||||
! returns the ID of a material
|
||||
integer(C_INT32_T), value :: index
|
||||
integer(C_INT32_T), intent(out) :: id
|
||||
integer(C_INT) :: err
|
||||
|
||||
if (index >= 1 .and. index <= size(materials)) then
|
||||
id = materials(index) % id
|
||||
err = 0
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in materials array is out of bounds.")
|
||||
end if
|
||||
end function openmc_material_get_id
|
||||
|
||||
|
||||
function openmc_material_set_id(index, id) result(err) bind(C)
|
||||
! Set the ID of a material
|
||||
integer(C_INT32_T), value, intent(in) :: index
|
||||
integer(C_INT32_T), value, intent(in) :: id
|
||||
integer(C_INT) :: err
|
||||
|
||||
if (index >= 1 .and. index <= n_materials) then
|
||||
materials(index) % id = id
|
||||
call material_dict % set(id, index)
|
||||
err = 0
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in materials array is out of bounds.")
|
||||
end if
|
||||
end function openmc_material_set_id
|
||||
|
||||
|
||||
function openmc_material_set_density(index, density) result(err) bind(C)
|
||||
! Set the total density of a material in atom/b-cm
|
||||
integer(C_INT32_T), value, intent(in) :: index
|
||||
real(C_DOUBLE), value, intent(in) :: density
|
||||
integer(C_INT) :: err
|
||||
|
||||
err = E_UNASSIGNED
|
||||
if (index >= 1 .and. index <= size(materials)) then
|
||||
associate (m => materials(index))
|
||||
err = m % set_density(density)
|
||||
end associate
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in materials array is out of bounds.")
|
||||
end if
|
||||
end function openmc_material_set_density
|
||||
|
||||
|
||||
function openmc_material_set_densities(index, n, name, density) result(err) bind(C)
|
||||
! Sets the densities for a list of nuclides in a material. If the nuclides
|
||||
! don't already exist in the material, they will be added
|
||||
integer(C_INT32_T), value, intent(in) :: index
|
||||
integer(C_INT), value, intent(in) :: n
|
||||
type(C_PTR), intent(in) :: name(n)
|
||||
real(C_DOUBLE), intent(in) :: density(n)
|
||||
integer(C_INT) :: err
|
||||
|
||||
integer :: i
|
||||
integer :: stat
|
||||
character(C_CHAR), pointer :: string(:)
|
||||
character(len=:, kind=C_CHAR), allocatable :: name_
|
||||
|
||||
if (index >= 1 .and. index <= size(materials)) then
|
||||
associate (m => materials(index))
|
||||
! If nuclide/density arrays are not correct size, reallocate
|
||||
if (n /= m % n_nuclides) then
|
||||
deallocate(m % nuclide, m % atom_density, m % p0, STAT=stat)
|
||||
allocate(m % nuclide(n), m % atom_density(n), m % p0(n))
|
||||
end if
|
||||
|
||||
do i = 1, n
|
||||
! Convert C string to Fortran string
|
||||
call c_f_pointer(name(i), string, [10])
|
||||
name_ = to_lower(to_f_string(string))
|
||||
|
||||
if (.not. nuclide_dict % has(name_)) then
|
||||
err = openmc_load_nuclide(string)
|
||||
if (err < 0) return
|
||||
end if
|
||||
|
||||
m % nuclide(i) = nuclide_dict % get(name_)
|
||||
m % atom_density(i) = density(i)
|
||||
end do
|
||||
m % n_nuclides = n
|
||||
|
||||
! Set isotropic flags to flags
|
||||
m % p0(:) = .false.
|
||||
|
||||
! Set total density to the sum of the vector
|
||||
err = m % set_density(sum(density))
|
||||
|
||||
! Assign S(a,b) tables
|
||||
call m % assign_sab_tables()
|
||||
end associate
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in materials array is out of bounds.")
|
||||
end if
|
||||
|
||||
end function openmc_material_set_densities
|
||||
|
||||
end module material_header
|
||||
|
|
|
|||
386
src/mesh.F90
386
src/mesh.F90
|
|
@ -1,8 +1,8 @@
|
|||
module mesh
|
||||
|
||||
use algorithm, only: binary_search
|
||||
use bank_header, only: bank
|
||||
use constants
|
||||
use global
|
||||
use mesh_header
|
||||
use message_passing
|
||||
|
||||
|
|
@ -10,116 +10,6 @@ module mesh
|
|||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! GET_MESH_BIN determines the tally bin for a particle in a structured mesh
|
||||
!===============================================================================
|
||||
|
||||
pure subroutine get_mesh_bin(m, xyz, bin)
|
||||
type(RegularMesh), intent(in) :: m ! mesh pointer
|
||||
real(8), intent(in) :: xyz(:) ! coordinates
|
||||
integer, intent(out) :: bin ! tally bin
|
||||
|
||||
integer :: n ! size of mesh
|
||||
integer :: d ! mesh dimension index
|
||||
integer :: ijk(3) ! indices in mesh
|
||||
logical :: in_mesh ! was given coordinate in mesh at all?
|
||||
|
||||
! Get number of dimensions
|
||||
n = m % n_dimension
|
||||
|
||||
! Loop over the dimensions of the mesh
|
||||
do d = 1, n
|
||||
|
||||
! Check for cases where particle is outside of mesh
|
||||
if (xyz(d) < m % lower_left(d)) then
|
||||
bin = NO_BIN_FOUND
|
||||
return
|
||||
elseif (xyz(d) > m % upper_right(d)) then
|
||||
bin = NO_BIN_FOUND
|
||||
return
|
||||
end if
|
||||
end do
|
||||
|
||||
! Determine indices
|
||||
call get_mesh_indices(m, xyz, ijk, in_mesh)
|
||||
|
||||
! Convert indices to bin
|
||||
if (in_mesh) then
|
||||
bin = mesh_indices_to_bin(m, ijk)
|
||||
else
|
||||
bin = NO_BIN_FOUND
|
||||
end if
|
||||
|
||||
end subroutine get_mesh_bin
|
||||
|
||||
!===============================================================================
|
||||
! GET_MESH_INDICES determines the indices of a particle in a structured mesh
|
||||
!===============================================================================
|
||||
|
||||
pure subroutine get_mesh_indices(m, xyz, ijk, in_mesh)
|
||||
type(RegularMesh), intent(in) :: m
|
||||
real(8), intent(in) :: xyz(:) ! coordinates to check
|
||||
integer, intent(out) :: ijk(:) ! indices in mesh
|
||||
logical, intent(out) :: in_mesh ! were given coords in mesh?
|
||||
|
||||
! Find particle in mesh
|
||||
ijk(:m % n_dimension) = ceiling((xyz(:m % n_dimension) - m % lower_left)/m % width)
|
||||
|
||||
! Determine if particle is in mesh
|
||||
if (any(ijk(:m % n_dimension) < 1) .or. &
|
||||
any(ijk(:m % n_dimension) > m % dimension)) then
|
||||
in_mesh = .false.
|
||||
else
|
||||
in_mesh = .true.
|
||||
end if
|
||||
|
||||
end subroutine get_mesh_indices
|
||||
|
||||
!===============================================================================
|
||||
! MESH_INDICES_TO_BIN maps (i), (i,j), or (i,j,k) indices to a single bin number
|
||||
! for use in a TallyObject results array
|
||||
!===============================================================================
|
||||
|
||||
pure function mesh_indices_to_bin(m, ijk) result(bin)
|
||||
type(RegularMesh), intent(in) :: m
|
||||
integer, intent(in) :: ijk(:)
|
||||
integer :: bin
|
||||
|
||||
if (m % n_dimension == 1) then
|
||||
bin = ijk(1)
|
||||
elseif (m % n_dimension == 2) then
|
||||
bin = (ijk(2) - 1) * m % dimension(1) + ijk(1)
|
||||
elseif (m % n_dimension == 3) then
|
||||
bin = ((ijk(3) - 1) * m % dimension(2) + (ijk(2) - 1)) &
|
||||
* m % dimension(1) + ijk(1)
|
||||
end if
|
||||
|
||||
end function mesh_indices_to_bin
|
||||
|
||||
!===============================================================================
|
||||
! BIN_TO_MESH_INDICES maps a single mesh bin from a TallyObject results array to
|
||||
! (i), (i,j), or (i,j,k) indices
|
||||
!===============================================================================
|
||||
|
||||
pure subroutine bin_to_mesh_indices(m, bin, ijk)
|
||||
type(RegularMesh), intent(in) :: m
|
||||
integer, intent(in) :: bin
|
||||
integer, intent(out) :: ijk(:)
|
||||
|
||||
if (m % n_dimension == 1) then
|
||||
ijk(1) = bin
|
||||
else if (m % n_dimension == 2) then
|
||||
ijk(1) = mod(bin - 1, m % dimension(1)) + 1
|
||||
ijk(2) = (bin - 1)/m % dimension(1) + 1
|
||||
else if (m % n_dimension == 3) then
|
||||
ijk(1) = mod(bin - 1, m % dimension(1)) + 1
|
||||
ijk(2) = mod(bin - 1, m % dimension(1) * m % dimension(2)) &
|
||||
/ m % dimension(1) + 1
|
||||
ijk(3) = (bin - 1)/(m % dimension(1) * m % dimension(2)) + 1
|
||||
end if
|
||||
|
||||
end subroutine bin_to_mesh_indices
|
||||
|
||||
!===============================================================================
|
||||
! COUNT_BANK_SITES determines the number of fission bank sites in each cell of a
|
||||
! given mesh as well as an optional energy group structure. This can be used for
|
||||
|
|
@ -130,28 +20,28 @@ contains
|
|||
subroutine count_bank_sites(m, bank_array, cnt, energies, size_bank, &
|
||||
sites_outside)
|
||||
|
||||
type(RegularMesh), pointer :: m ! mesh to count sites
|
||||
type(RegularMesh), intent(in) :: m ! mesh to count sites
|
||||
type(Bank), intent(in) :: bank_array(:) ! fission or source bank
|
||||
real(8), intent(out) :: cnt(:,:,:,:) ! weight of sites in each
|
||||
real(8), intent(out) :: cnt(:,:) ! weight of sites in each
|
||||
! cell and energy group
|
||||
real(8), intent(in), optional :: energies(:) ! energy grid to search
|
||||
integer(8), intent(in), optional :: size_bank ! # of bank sites (on each proc)
|
||||
logical, intent(inout), optional :: sites_outside ! were there sites outside mesh?
|
||||
real(8), allocatable :: cnt_(:,:)
|
||||
|
||||
integer :: i ! loop index for local fission sites
|
||||
integer :: n_sites ! size of bank array
|
||||
integer :: ijk(3) ! indices on mesh
|
||||
integer :: n_groups ! number of groups in energies
|
||||
integer :: e_bin ! energy_bin
|
||||
logical :: in_mesh ! was single site outside mesh?
|
||||
logical :: outside ! was any site outside mesh?
|
||||
integer :: n ! number of energy groups / size
|
||||
integer :: mesh_bin ! mesh bin
|
||||
integer :: e_bin ! energy bin
|
||||
#ifdef MPI
|
||||
integer :: n ! total size of count variable
|
||||
real(8) :: dummy ! temporary receive buffer for non-root reductions
|
||||
integer :: mpi_err ! MPI error code
|
||||
#endif
|
||||
logical :: outside ! was any site outside mesh?
|
||||
|
||||
! initialize variables
|
||||
cnt = ZERO
|
||||
allocate(cnt_(size(cnt,1), size(cnt,2)))
|
||||
cnt_ = ZERO
|
||||
outside = .false.
|
||||
|
||||
! Set size of bank
|
||||
|
|
@ -163,18 +53,18 @@ contains
|
|||
|
||||
! Determine number of energies in group structure
|
||||
if (present(energies)) then
|
||||
n_groups = size(energies) - 1
|
||||
n = size(energies) - 1
|
||||
else
|
||||
n_groups = 1
|
||||
n = 1
|
||||
end if
|
||||
|
||||
! loop over fission sites and count how many are in each mesh box
|
||||
FISSION_SITES: do i = 1, n_sites
|
||||
! determine scoring bin for entropy mesh
|
||||
call get_mesh_indices(m, bank_array(i) % xyz, ijk, in_mesh)
|
||||
call m % get_bin(bank_array(i) % xyz, mesh_bin)
|
||||
|
||||
! if outside mesh, skip particle
|
||||
if (.not. in_mesh) then
|
||||
if (mesh_bin == NO_BIN_FOUND) then
|
||||
outside = .true.
|
||||
cycle
|
||||
end if
|
||||
|
|
@ -183,266 +73,34 @@ contains
|
|||
if (present(energies)) then
|
||||
if (bank_array(i) % E < energies(1)) then
|
||||
e_bin = 1
|
||||
elseif (bank_array(i) % E > energies(n_groups+1)) then
|
||||
e_bin = n_groups
|
||||
elseif (bank_array(i) % E > energies(n + 1)) then
|
||||
e_bin = n
|
||||
else
|
||||
e_bin = binary_search(energies, n_groups + 1, bank_array(i) % E)
|
||||
e_bin = binary_search(energies, n + 1, bank_array(i) % E)
|
||||
end if
|
||||
else
|
||||
e_bin = 1
|
||||
end if
|
||||
|
||||
! add to appropriate mesh box
|
||||
cnt(e_bin,ijk(1),ijk(2),ijk(3)) = cnt(e_bin,ijk(1),ijk(2),ijk(3)) + &
|
||||
bank_array(i) % wgt
|
||||
cnt_(e_bin, mesh_bin) = cnt_(e_bin, mesh_bin) + bank_array(i) % wgt
|
||||
end do FISSION_SITES
|
||||
|
||||
#ifdef MPI
|
||||
! determine total number of mesh cells
|
||||
n = n_groups * size(cnt,2) * size(cnt,3) * size(cnt,4)
|
||||
|
||||
! collect values from all processors
|
||||
if (master) then
|
||||
call MPI_REDUCE(MPI_IN_PLACE, cnt, n, MPI_REAL8, MPI_SUM, 0, &
|
||||
mpi_intracomm, mpi_err)
|
||||
else
|
||||
! Receive buffer not significant at other processors
|
||||
call MPI_REDUCE(cnt, dummy, n, MPI_REAL8, MPI_SUM, 0, &
|
||||
mpi_intracomm, mpi_err)
|
||||
end if
|
||||
n = size(cnt_)
|
||||
call MPI_REDUCE(cnt_, cnt, n, MPI_REAL8, MPI_SUM, 0, mpi_intracomm, mpi_err)
|
||||
|
||||
! Check if there were sites outside the mesh for any processor
|
||||
if (present(sites_outside)) then
|
||||
call MPI_REDUCE(outside, sites_outside, 1, MPI_LOGICAL, MPI_LOR, 0, &
|
||||
mpi_intracomm, mpi_err)
|
||||
end if
|
||||
|
||||
#else
|
||||
sites_outside = outside
|
||||
cnt = cnt_
|
||||
#endif
|
||||
|
||||
end subroutine count_bank_sites
|
||||
|
||||
!===============================================================================
|
||||
! MESH_INTERSECTS determines if a line between xyz0 and xyz1 intersects the
|
||||
! outer boundary of the given mesh. This is important for determining whether a
|
||||
! track will score to a mesh tally.
|
||||
!===============================================================================
|
||||
|
||||
pure function mesh_intersects_1d(m, xyz0, xyz1) result(intersects)
|
||||
type(RegularMesh), intent(in) :: m
|
||||
real(8), intent(in) :: xyz0(1)
|
||||
real(8), intent(in) :: xyz1(1)
|
||||
logical :: intersects
|
||||
|
||||
real(8) :: x0 ! track start point
|
||||
real(8) :: x1 ! track end point
|
||||
real(8) :: xm0 ! lower-left coordinates of mesh
|
||||
real(8) :: xm1 ! upper-right coordinates of mesh
|
||||
|
||||
! Copy coordinates of starting point
|
||||
x0 = xyz0(1)
|
||||
|
||||
! Copy coordinates of ending point
|
||||
x1 = xyz1(1)
|
||||
|
||||
! Copy coordinates of mesh lower_left
|
||||
xm0 = m % lower_left(1)
|
||||
|
||||
! Copy coordinates of mesh upper_right
|
||||
xm1 = m % upper_right(1)
|
||||
|
||||
! Set default value for intersects
|
||||
intersects = .false.
|
||||
|
||||
! Check if line intersects left surface
|
||||
if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
|
||||
! Check if line intersects right surface
|
||||
if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
|
||||
end function mesh_intersects_1d
|
||||
|
||||
pure function mesh_intersects_2d(m, xyz0, xyz1) result(intersects)
|
||||
type(RegularMesh), intent(in) :: m
|
||||
real(8), intent(in) :: xyz0(2)
|
||||
real(8), intent(in) :: xyz1(2)
|
||||
logical :: intersects
|
||||
|
||||
real(8) :: x0, y0 ! track start point
|
||||
real(8) :: x1, y1 ! track end point
|
||||
real(8) :: xi, yi ! track intersection point with mesh
|
||||
real(8) :: xm0, ym0 ! lower-left coordinates of mesh
|
||||
real(8) :: xm1, ym1 ! upper-right coordinates of mesh
|
||||
|
||||
! Copy coordinates of starting point
|
||||
x0 = xyz0(1)
|
||||
y0 = xyz0(2)
|
||||
|
||||
! Copy coordinates of ending point
|
||||
x1 = xyz1(1)
|
||||
y1 = xyz1(2)
|
||||
|
||||
! Copy coordinates of mesh lower_left
|
||||
xm0 = m % lower_left(1)
|
||||
ym0 = m % lower_left(2)
|
||||
|
||||
! Copy coordinates of mesh upper_right
|
||||
xm1 = m % upper_right(1)
|
||||
ym1 = m % upper_right(2)
|
||||
|
||||
! Set default value for intersects
|
||||
intersects = .false.
|
||||
|
||||
! Check if line intersects left surface -- calculate the intersection point
|
||||
! y
|
||||
if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then
|
||||
yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0)
|
||||
if (yi >= ym0 .and. yi < ym1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects back surface -- calculate the intersection point
|
||||
! x
|
||||
if ((y0 < ym0 .and. y1 > ym0) .or. (y0 > ym0 .and. y1 < ym0)) then
|
||||
xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0)
|
||||
if (xi >= xm0 .and. xi < xm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects right surface -- calculate the intersection
|
||||
! point y
|
||||
if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then
|
||||
yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0)
|
||||
if (yi >= ym0 .and. yi < ym1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects front surface -- calculate the intersection point
|
||||
! x
|
||||
if ((y0 < ym1 .and. y1 > ym1) .or. (y0 > ym1 .and. y1 < ym1)) then
|
||||
xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0)
|
||||
if (xi >= xm0 .and. xi < xm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
end function mesh_intersects_2d
|
||||
|
||||
pure function mesh_intersects_3d(m, xyz0, xyz1) result(intersects)
|
||||
type(RegularMesh), intent(in) :: m
|
||||
real(8), intent(in) :: xyz0(3)
|
||||
real(8), intent(in) :: xyz1(3)
|
||||
logical :: intersects
|
||||
|
||||
real(8) :: x0, y0, z0 ! track start point
|
||||
real(8) :: x1, y1, z1 ! track end point
|
||||
real(8) :: xi, yi, zi ! track intersection point with mesh
|
||||
real(8) :: xm0, ym0, zm0 ! lower-left coordinates of mesh
|
||||
real(8) :: xm1, ym1, zm1 ! upper-right coordinates of mesh
|
||||
|
||||
! Copy coordinates of starting point
|
||||
x0 = xyz0(1)
|
||||
y0 = xyz0(2)
|
||||
z0 = xyz0(3)
|
||||
|
||||
! Copy coordinates of ending point
|
||||
x1 = xyz1(1)
|
||||
y1 = xyz1(2)
|
||||
z1 = xyz1(3)
|
||||
|
||||
! Copy coordinates of mesh lower_left
|
||||
xm0 = m % lower_left(1)
|
||||
ym0 = m % lower_left(2)
|
||||
zm0 = m % lower_left(3)
|
||||
|
||||
! Copy coordinates of mesh upper_right
|
||||
xm1 = m % upper_right(1)
|
||||
ym1 = m % upper_right(2)
|
||||
zm1 = m % upper_right(3)
|
||||
|
||||
! Set default value for intersects
|
||||
intersects = .false.
|
||||
|
||||
! Check if line intersects left surface -- calculate the intersection point
|
||||
! (y,z)
|
||||
if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then
|
||||
yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0)
|
||||
zi = z0 + (xm0 - x0) * (z1 - z0) / (x1 - x0)
|
||||
if (yi >= ym0 .and. yi < ym1 .and. zi >= zm0 .and. zi < zm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects back surface -- calculate the intersection point
|
||||
! (x,z)
|
||||
if ((y0 < ym0 .and. y1 > ym0) .or. (y0 > ym0 .and. y1 < ym0)) then
|
||||
xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0)
|
||||
zi = z0 + (ym0 - y0) * (z1 - z0) / (y1 - y0)
|
||||
if (xi >= xm0 .and. xi < xm1 .and. zi >= zm0 .and. zi < zm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects bottom surface -- calculate the intersection
|
||||
! point (x,y)
|
||||
if ((z0 < zm0 .and. z1 > zm0) .or. (z0 > zm0 .and. z1 < zm0)) then
|
||||
xi = x0 + (zm0 - z0) * (x1 - x0) / (z1 - z0)
|
||||
yi = y0 + (zm0 - z0) * (y1 - y0) / (z1 - z0)
|
||||
if (xi >= xm0 .and. xi < xm1 .and. yi >= ym0 .and. yi < ym1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects right surface -- calculate the intersection point
|
||||
! (y,z)
|
||||
if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then
|
||||
yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0)
|
||||
zi = z0 + (xm1 - x0) * (z1 - z0) / (x1 - x0)
|
||||
if (yi >= ym0 .and. yi < ym1 .and. zi >= zm0 .and. zi < zm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects front surface -- calculate the intersection point
|
||||
! (x,z)
|
||||
if ((y0 < ym1 .and. y1 > ym1) .or. (y0 > ym1 .and. y1 < ym1)) then
|
||||
xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0)
|
||||
zi = z0 + (ym1 - y0) * (z1 - z0) / (y1 - y0)
|
||||
if (xi >= xm0 .and. xi < xm1 .and. zi >= zm0 .and. zi < zm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects top surface -- calculate the intersection point
|
||||
! (x,y)
|
||||
if ((z0 < zm1 .and. z1 > zm1) .or. (z0 > zm1 .and. z1 < zm1)) then
|
||||
xi = x0 + (zm1 - z0) * (x1 - x0) / (z1 - z0)
|
||||
yi = y0 + (zm1 - z0) * (y1 - y0) / (z1 - z0)
|
||||
if (xi >= xm0 .and. xi < xm1 .and. yi >= ym0 .and. yi < ym1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
end function mesh_intersects_3d
|
||||
|
||||
end module mesh
|
||||
|
|
|
|||
|
|
@ -1,14 +1,28 @@
|
|||
module mesh_header
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use hdf5
|
||||
|
||||
use constants
|
||||
use dict_header, only: DictIntInt
|
||||
use error, only: warning, fatal_error
|
||||
use hdf5_interface
|
||||
use string, only: to_str, to_lower
|
||||
use xml_interface
|
||||
|
||||
implicit none
|
||||
private
|
||||
public :: free_memory_mesh
|
||||
public :: openmc_extend_meshes
|
||||
|
||||
!===============================================================================
|
||||
! STRUCTUREDMESH represents a tessellation of n-dimensional Euclidean space by
|
||||
! congruent squares or cubes
|
||||
!===============================================================================
|
||||
|
||||
type RegularMesh
|
||||
integer :: id ! user-specified id
|
||||
type, public :: RegularMesh
|
||||
integer :: id = -1 ! user-specified id
|
||||
integer :: type ! rectangular, hexagonal
|
||||
integer :: n_dimension ! rank of mesh
|
||||
real(8) :: volume_frac ! volume fraction of each cell
|
||||
|
|
@ -16,6 +30,566 @@ module mesh_header
|
|||
real(8), allocatable :: lower_left(:) ! lower-left corner of mesh
|
||||
real(8), allocatable :: upper_right(:) ! upper-right corner of mesh
|
||||
real(8), allocatable :: width(:) ! width of each mesh cell
|
||||
contains
|
||||
procedure :: from_xml => regular_from_xml
|
||||
procedure :: get_bin => regular_get_bin
|
||||
procedure :: get_indices => regular_get_indices
|
||||
procedure :: get_bin_from_indices => regular_get_bin_from_indices
|
||||
procedure :: get_indices_from_bin => regular_get_indices_from_bin
|
||||
procedure :: intersects => regular_intersects
|
||||
procedure :: to_hdf5 => regular_to_hdf5
|
||||
end type RegularMesh
|
||||
|
||||
integer(C_INT32_T), public, bind(C) :: n_meshes = 0 ! # of structured meshes
|
||||
|
||||
type(RegularMesh), public, allocatable, target :: meshes(:)
|
||||
|
||||
! Dictionary that maps user IDs to indices in 'meshes'
|
||||
type(DictIntInt), public :: mesh_dict
|
||||
|
||||
contains
|
||||
|
||||
subroutine regular_from_xml(this, node)
|
||||
class(RegularMesh), intent(inout) :: this
|
||||
type(XMLNode), intent(in) :: node
|
||||
|
||||
integer :: n
|
||||
character(MAX_LINE_LEN) :: temp_str
|
||||
|
||||
! Copy mesh id
|
||||
if (check_for_node(node, "id")) then
|
||||
call get_node_value(node, "id", this % id)
|
||||
|
||||
! Check to make sure 'id' hasn't been used
|
||||
if (mesh_dict % has(this % id)) then
|
||||
call fatal_error("Two or more meshes use the same unique ID: " &
|
||||
// to_str(this % id))
|
||||
end if
|
||||
end if
|
||||
|
||||
! Read mesh type
|
||||
if (check_for_node(node, "type")) then
|
||||
call get_node_value(node, "type", temp_str)
|
||||
select case (to_lower(temp_str))
|
||||
case ('rect', 'rectangle', 'rectangular')
|
||||
call warning("Mesh type '" // trim(temp_str) // "' is deprecated. &
|
||||
&Please use 'regular' instead.")
|
||||
this % type = MESH_REGULAR
|
||||
case ('regular')
|
||||
this % type = MESH_REGULAR
|
||||
case default
|
||||
call fatal_error("Invalid mesh type: " // trim(temp_str))
|
||||
end select
|
||||
else
|
||||
this % type = MESH_REGULAR
|
||||
end if
|
||||
|
||||
! Determine number of dimensions for mesh
|
||||
if (check_for_node(node, "dimension")) then
|
||||
n = node_word_count(node, "dimension")
|
||||
if (n /= 1 .and. n /= 2 .and. n /= 3) then
|
||||
call fatal_error("Mesh must be one, two, or three dimensions.")
|
||||
end if
|
||||
this % n_dimension = n
|
||||
|
||||
! Allocate attribute arrays
|
||||
allocate(this % dimension(n))
|
||||
|
||||
! Check that dimensions are all greater than zero
|
||||
call get_node_array(node, "dimension", this % dimension)
|
||||
if (any(this % dimension <= 0)) then
|
||||
call fatal_error("All entries on the <dimension> element for a tally &
|
||||
&mesh must be positive.")
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check for lower-left coordinates
|
||||
if (check_for_node(node, "lower_left")) then
|
||||
n = node_word_count(node, "lower_left")
|
||||
allocate(this % lower_left(n))
|
||||
|
||||
! Read mesh lower-left corner location
|
||||
call get_node_array(node, "lower_left", this % lower_left)
|
||||
else
|
||||
call fatal_error("Must specify <lower_left> on a mesh.")
|
||||
end if
|
||||
|
||||
if (check_for_node(node, "width")) then
|
||||
! Make sure both upper-right or width were specified
|
||||
if (check_for_node(node, "upper_right")) then
|
||||
call fatal_error("Cannot specify both <upper_right> and <width> on a &
|
||||
&mesh.")
|
||||
end if
|
||||
|
||||
n = node_word_count(node, "width")
|
||||
allocate(this % width(n))
|
||||
allocate(this % upper_right(n))
|
||||
|
||||
! Check to ensure width has same dimensions
|
||||
if (n /= size(this % lower_left)) then
|
||||
call fatal_error("Number of entries on <width> must be the same as &
|
||||
&the number of entries on <lower_left>.")
|
||||
end if
|
||||
|
||||
! Check for negative widths
|
||||
call get_node_array(node, "width", this % width)
|
||||
if (any(this % width < ZERO)) then
|
||||
call fatal_error("Cannot have a negative <width> on a tally mesh.")
|
||||
end if
|
||||
|
||||
! Set width and upper right coordinate
|
||||
this % upper_right = this % lower_left + this % dimension * this % width
|
||||
|
||||
elseif (check_for_node(node, "upper_right")) then
|
||||
n = node_word_count(node, "upper_right")
|
||||
allocate(this % upper_right(n))
|
||||
allocate(this % width(n))
|
||||
|
||||
! Check to ensure width has same dimensions
|
||||
if (n /= size(this % lower_left)) then
|
||||
call fatal_error("Number of entries on <upper_right> must be the &
|
||||
&same as the number of entries on <lower_left>.")
|
||||
end if
|
||||
|
||||
! Check that upper-right is above lower-left
|
||||
call get_node_array(node, "upper_right", this % upper_right)
|
||||
if (any(this % upper_right < this % lower_left)) then
|
||||
call fatal_error("The <upper_right> coordinates must be greater than &
|
||||
&the <lower_left> coordinates on a tally mesh.")
|
||||
end if
|
||||
|
||||
! Set width and upper right coordinate
|
||||
this % width = (this % upper_right - this % lower_left) / this % dimension
|
||||
else
|
||||
call fatal_error("Must specify either <upper_right> and <width> on a &
|
||||
&mesh.")
|
||||
end if
|
||||
|
||||
if (allocated(this % dimension)) then
|
||||
if (size(this % dimension) /= size(this % lower_left)) then
|
||||
call fatal_error("Number of entries on <lower_left> must be the same &
|
||||
&as the number of entries on <dimension>.")
|
||||
end if
|
||||
|
||||
! Set volume fraction
|
||||
this % volume_frac = ONE/real(product(this % dimension),8)
|
||||
end if
|
||||
|
||||
end subroutine regular_from_xml
|
||||
|
||||
!===============================================================================
|
||||
! GET_MESH_BIN determines the tally bin for a particle in a structured mesh
|
||||
!===============================================================================
|
||||
|
||||
pure subroutine regular_get_bin(this, xyz, bin)
|
||||
class(RegularMesh), intent(in) :: this
|
||||
real(8), intent(in) :: xyz(:) ! coordinates
|
||||
integer, intent(out) :: bin ! tally bin
|
||||
|
||||
integer :: n ! size of mesh
|
||||
integer :: d ! mesh dimension index
|
||||
integer :: ijk(3) ! indices in mesh
|
||||
logical :: in_mesh ! was given coordinate in mesh at all?
|
||||
|
||||
! Get number of dimensions
|
||||
n = this % n_dimension
|
||||
|
||||
! Loop over the dimensions of the mesh
|
||||
do d = 1, n
|
||||
|
||||
! Check for cases where particle is outside of mesh
|
||||
if (xyz(d) < this % lower_left(d)) then
|
||||
bin = NO_BIN_FOUND
|
||||
return
|
||||
elseif (xyz(d) > this % upper_right(d)) then
|
||||
bin = NO_BIN_FOUND
|
||||
return
|
||||
end if
|
||||
end do
|
||||
|
||||
! Determine indices
|
||||
call this % get_indices(xyz, ijk, in_mesh)
|
||||
|
||||
! Convert indices to bin
|
||||
if (in_mesh) then
|
||||
bin = this % get_bin_from_indices(ijk)
|
||||
else
|
||||
bin = NO_BIN_FOUND
|
||||
end if
|
||||
|
||||
end subroutine regular_get_bin
|
||||
|
||||
!===============================================================================
|
||||
! GET_MESH_INDICES determines the indices of a particle in a structured mesh
|
||||
!===============================================================================
|
||||
|
||||
pure subroutine regular_get_indices(this, xyz, ijk, in_mesh)
|
||||
class(RegularMesh), intent(in) :: this
|
||||
real(8), intent(in) :: xyz(:) ! coordinates to check
|
||||
integer, intent(out) :: ijk(:) ! indices in mesh
|
||||
logical, intent(out) :: in_mesh ! were given coords in mesh?
|
||||
|
||||
! Find particle in mesh
|
||||
ijk(:this % n_dimension) = ceiling((xyz(:this % n_dimension) - &
|
||||
this % lower_left)/this % width)
|
||||
|
||||
! Determine if particle is in mesh
|
||||
if (any(ijk(:this % n_dimension) < 1) .or. &
|
||||
any(ijk(:this % n_dimension) > this % dimension)) then
|
||||
in_mesh = .false.
|
||||
else
|
||||
in_mesh = .true.
|
||||
end if
|
||||
|
||||
end subroutine regular_get_indices
|
||||
|
||||
!===============================================================================
|
||||
! MESH_INDICES_TO_BIN maps (i), (i,j), or (i,j,k) indices to a single bin number
|
||||
! for use in a TallyObject results array
|
||||
!===============================================================================
|
||||
|
||||
pure function regular_get_bin_from_indices(this, ijk) result(bin)
|
||||
class(RegularMesh), intent(in) :: this
|
||||
integer, intent(in) :: ijk(:)
|
||||
integer :: bin
|
||||
|
||||
if (this % n_dimension == 1) then
|
||||
bin = ijk(1)
|
||||
elseif (this % n_dimension == 2) then
|
||||
bin = (ijk(2) - 1) * this % dimension(1) + ijk(1)
|
||||
elseif (this % n_dimension == 3) then
|
||||
bin = ((ijk(3) - 1) * this % dimension(2) + (ijk(2) - 1)) &
|
||||
* this % dimension(1) + ijk(1)
|
||||
end if
|
||||
|
||||
end function regular_get_bin_from_indices
|
||||
|
||||
!===============================================================================
|
||||
! BIN_TO_MESH_INDICES maps a single mesh bin from a TallyObject results array to
|
||||
! (i), (i,j), or (i,j,k) indices
|
||||
!===============================================================================
|
||||
|
||||
pure subroutine regular_get_indices_from_bin(this, bin, ijk)
|
||||
class(RegularMesh), intent(in) :: this
|
||||
integer, intent(in) :: bin
|
||||
integer, intent(out) :: ijk(:)
|
||||
|
||||
if (this % n_dimension == 1) then
|
||||
ijk(1) = bin
|
||||
else if (this % n_dimension == 2) then
|
||||
ijk(1) = mod(bin - 1, this % dimension(1)) + 1
|
||||
ijk(2) = (bin - 1)/this % dimension(1) + 1
|
||||
else if (this % n_dimension == 3) then
|
||||
ijk(1) = mod(bin - 1, this % dimension(1)) + 1
|
||||
ijk(2) = mod(bin - 1, this % dimension(1) * this % dimension(2)) &
|
||||
/ this % dimension(1) + 1
|
||||
ijk(3) = (bin - 1)/(this % dimension(1) * this % dimension(2)) + 1
|
||||
end if
|
||||
|
||||
end subroutine regular_get_indices_from_bin
|
||||
|
||||
!===============================================================================
|
||||
! MESH_INTERSECTS determines if a line between xyz0 and xyz1 intersects the
|
||||
! outer boundary of the given mesh. This is important for determining whether a
|
||||
! track will score to a mesh tally.
|
||||
!===============================================================================
|
||||
|
||||
pure function regular_intersects(this, xyz0, xyz1) result(intersects)
|
||||
class(RegularMesh), intent(in) :: this
|
||||
real(8), intent(in) :: xyz0(:)
|
||||
real(8), intent(in) :: xyz1(:)
|
||||
logical :: intersects
|
||||
|
||||
select case(this % n_dimension)
|
||||
case (1)
|
||||
intersects = mesh_intersects_1d(this, xyz0, xyz1)
|
||||
case (2)
|
||||
intersects = mesh_intersects_2d(this, xyz0, xyz1)
|
||||
case (3)
|
||||
intersects = mesh_intersects_3d(this, xyz0, xyz1)
|
||||
end select
|
||||
end function regular_intersects
|
||||
|
||||
pure function mesh_intersects_1d(m, xyz0, xyz1) result(intersects)
|
||||
type(RegularMesh), intent(in) :: m
|
||||
real(8), intent(in) :: xyz0(:)
|
||||
real(8), intent(in) :: xyz1(:)
|
||||
logical :: intersects
|
||||
|
||||
real(8) :: x0 ! track start point
|
||||
real(8) :: x1 ! track end point
|
||||
real(8) :: xm0 ! lower-left coordinates of mesh
|
||||
real(8) :: xm1 ! upper-right coordinates of mesh
|
||||
|
||||
! Copy coordinates of starting point
|
||||
x0 = xyz0(1)
|
||||
|
||||
! Copy coordinates of ending point
|
||||
x1 = xyz1(1)
|
||||
|
||||
! Copy coordinates of mesh lower_left
|
||||
xm0 = m % lower_left(1)
|
||||
|
||||
! Copy coordinates of mesh upper_right
|
||||
xm1 = m % upper_right(1)
|
||||
|
||||
! Set default value for intersects
|
||||
intersects = .false.
|
||||
|
||||
! Check if line intersects left surface
|
||||
if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
|
||||
! Check if line intersects right surface
|
||||
if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
|
||||
end function mesh_intersects_1d
|
||||
|
||||
pure function mesh_intersects_2d(m, xyz0, xyz1) result(intersects)
|
||||
type(RegularMesh), intent(in) :: m
|
||||
real(8), intent(in) :: xyz0(:)
|
||||
real(8), intent(in) :: xyz1(:)
|
||||
logical :: intersects
|
||||
|
||||
real(8) :: x0, y0 ! track start point
|
||||
real(8) :: x1, y1 ! track end point
|
||||
real(8) :: xi, yi ! track intersection point with mesh
|
||||
real(8) :: xm0, ym0 ! lower-left coordinates of mesh
|
||||
real(8) :: xm1, ym1 ! upper-right coordinates of mesh
|
||||
|
||||
! Copy coordinates of starting point
|
||||
x0 = xyz0(1)
|
||||
y0 = xyz0(2)
|
||||
|
||||
! Copy coordinates of ending point
|
||||
x1 = xyz1(1)
|
||||
y1 = xyz1(2)
|
||||
|
||||
! Copy coordinates of mesh lower_left
|
||||
xm0 = m % lower_left(1)
|
||||
ym0 = m % lower_left(2)
|
||||
|
||||
! Copy coordinates of mesh upper_right
|
||||
xm1 = m % upper_right(1)
|
||||
ym1 = m % upper_right(2)
|
||||
|
||||
! Set default value for intersects
|
||||
intersects = .false.
|
||||
|
||||
! Check if line intersects left surface -- calculate the intersection point
|
||||
! y
|
||||
if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then
|
||||
yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0)
|
||||
if (yi >= ym0 .and. yi < ym1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects back surface -- calculate the intersection point
|
||||
! x
|
||||
if ((y0 < ym0 .and. y1 > ym0) .or. (y0 > ym0 .and. y1 < ym0)) then
|
||||
xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0)
|
||||
if (xi >= xm0 .and. xi < xm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects right surface -- calculate the intersection
|
||||
! point y
|
||||
if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then
|
||||
yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0)
|
||||
if (yi >= ym0 .and. yi < ym1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects front surface -- calculate the intersection point
|
||||
! x
|
||||
if ((y0 < ym1 .and. y1 > ym1) .or. (y0 > ym1 .and. y1 < ym1)) then
|
||||
xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0)
|
||||
if (xi >= xm0 .and. xi < xm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
end function mesh_intersects_2d
|
||||
|
||||
pure function mesh_intersects_3d(m, xyz0, xyz1) result(intersects)
|
||||
type(RegularMesh), intent(in) :: m
|
||||
real(8), intent(in) :: xyz0(:)
|
||||
real(8), intent(in) :: xyz1(:)
|
||||
logical :: intersects
|
||||
|
||||
real(8) :: x0, y0, z0 ! track start point
|
||||
real(8) :: x1, y1, z1 ! track end point
|
||||
real(8) :: xi, yi, zi ! track intersection point with mesh
|
||||
real(8) :: xm0, ym0, zm0 ! lower-left coordinates of mesh
|
||||
real(8) :: xm1, ym1, zm1 ! upper-right coordinates of mesh
|
||||
|
||||
! Copy coordinates of starting point
|
||||
x0 = xyz0(1)
|
||||
y0 = xyz0(2)
|
||||
z0 = xyz0(3)
|
||||
|
||||
! Copy coordinates of ending point
|
||||
x1 = xyz1(1)
|
||||
y1 = xyz1(2)
|
||||
z1 = xyz1(3)
|
||||
|
||||
! Copy coordinates of mesh lower_left
|
||||
xm0 = m % lower_left(1)
|
||||
ym0 = m % lower_left(2)
|
||||
zm0 = m % lower_left(3)
|
||||
|
||||
! Copy coordinates of mesh upper_right
|
||||
xm1 = m % upper_right(1)
|
||||
ym1 = m % upper_right(2)
|
||||
zm1 = m % upper_right(3)
|
||||
|
||||
! Set default value for intersects
|
||||
intersects = .false.
|
||||
|
||||
! Check if line intersects left surface -- calculate the intersection point
|
||||
! (y,z)
|
||||
if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then
|
||||
yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0)
|
||||
zi = z0 + (xm0 - x0) * (z1 - z0) / (x1 - x0)
|
||||
if (yi >= ym0 .and. yi < ym1 .and. zi >= zm0 .and. zi < zm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects back surface -- calculate the intersection point
|
||||
! (x,z)
|
||||
if ((y0 < ym0 .and. y1 > ym0) .or. (y0 > ym0 .and. y1 < ym0)) then
|
||||
xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0)
|
||||
zi = z0 + (ym0 - y0) * (z1 - z0) / (y1 - y0)
|
||||
if (xi >= xm0 .and. xi < xm1 .and. zi >= zm0 .and. zi < zm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects bottom surface -- calculate the intersection
|
||||
! point (x,y)
|
||||
if ((z0 < zm0 .and. z1 > zm0) .or. (z0 > zm0 .and. z1 < zm0)) then
|
||||
xi = x0 + (zm0 - z0) * (x1 - x0) / (z1 - z0)
|
||||
yi = y0 + (zm0 - z0) * (y1 - y0) / (z1 - z0)
|
||||
if (xi >= xm0 .and. xi < xm1 .and. yi >= ym0 .and. yi < ym1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects right surface -- calculate the intersection point
|
||||
! (y,z)
|
||||
if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then
|
||||
yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0)
|
||||
zi = z0 + (xm1 - x0) * (z1 - z0) / (x1 - x0)
|
||||
if (yi >= ym0 .and. yi < ym1 .and. zi >= zm0 .and. zi < zm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects front surface -- calculate the intersection point
|
||||
! (x,z)
|
||||
if ((y0 < ym1 .and. y1 > ym1) .or. (y0 > ym1 .and. y1 < ym1)) then
|
||||
xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0)
|
||||
zi = z0 + (ym1 - y0) * (z1 - z0) / (y1 - y0)
|
||||
if (xi >= xm0 .and. xi < xm1 .and. zi >= zm0 .and. zi < zm1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
! Check if line intersects top surface -- calculate the intersection point
|
||||
! (x,y)
|
||||
if ((z0 < zm1 .and. z1 > zm1) .or. (z0 > zm1 .and. z1 < zm1)) then
|
||||
xi = x0 + (zm1 - z0) * (x1 - x0) / (z1 - z0)
|
||||
yi = y0 + (zm1 - z0) * (y1 - y0) / (z1 - z0)
|
||||
if (xi >= xm0 .and. xi < xm1 .and. yi >= ym0 .and. yi < ym1) then
|
||||
intersects = .true.
|
||||
return
|
||||
end if
|
||||
end if
|
||||
|
||||
end function mesh_intersects_3d
|
||||
|
||||
!===============================================================================
|
||||
! TO_HDF5 writes the mesh data to an HDF5 group
|
||||
!===============================================================================
|
||||
|
||||
subroutine regular_to_hdf5(this, group)
|
||||
class(RegularMesh), intent(in) :: this
|
||||
integer(HID_T), intent(in) :: group
|
||||
|
||||
integer(HID_T) :: mesh_group
|
||||
|
||||
mesh_group = create_group(group, "mesh " // trim(to_str(this % id)))
|
||||
|
||||
call write_dataset(mesh_group, "type", "regular")
|
||||
call write_dataset(mesh_group, "dimension", this % dimension)
|
||||
call write_dataset(mesh_group, "lower_left", this % lower_left)
|
||||
call write_dataset(mesh_group, "upper_right", this % upper_right)
|
||||
call write_dataset(mesh_group, "width", this % width)
|
||||
|
||||
call close_group(mesh_group)
|
||||
end subroutine regular_to_hdf5
|
||||
|
||||
!===============================================================================
|
||||
! FREE_MEMORY_MESH deallocates global arrays defined in this module
|
||||
!===============================================================================
|
||||
|
||||
subroutine free_memory_mesh()
|
||||
n_meshes = 0
|
||||
if (allocated(meshes)) deallocate(meshes)
|
||||
call mesh_dict % clear()
|
||||
end subroutine free_memory_mesh
|
||||
|
||||
!===============================================================================
|
||||
! C API FUNCTIONS
|
||||
!===============================================================================
|
||||
|
||||
function openmc_extend_meshes(n, index_start, index_end) result(err) bind(C)
|
||||
! Extend the meshes array by n elements
|
||||
integer(C_INT32_T), value, intent(in) :: n
|
||||
integer(C_INT32_T), optional, intent(out) :: index_start
|
||||
integer(C_INT32_T), optional, intent(out) :: index_end
|
||||
integer(C_INT) :: err
|
||||
|
||||
type(RegularMesh), allocatable :: temp(:) ! temporary meshes array
|
||||
|
||||
if (n_meshes == 0) then
|
||||
! Allocate meshes array
|
||||
allocate(meshes(n))
|
||||
else
|
||||
! Allocate meshes array with increased size
|
||||
allocate(temp(n_meshes + n))
|
||||
|
||||
! Copy original meshes to temporary array
|
||||
temp(1:n_meshes) = meshes
|
||||
|
||||
! Move allocation from temporary array
|
||||
call move_alloc(FROM=temp, TO=meshes)
|
||||
end if
|
||||
|
||||
! Return indices in meshes array
|
||||
if (present(index_start)) index_start = n_meshes + 1
|
||||
if (present(index_end)) index_end = n_meshes + n
|
||||
n_meshes = n_meshes + n
|
||||
|
||||
err = 0
|
||||
end function openmc_extend_meshes
|
||||
|
||||
end module mesh_header
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ module message_passing
|
|||
integer :: rank = 0 ! rank of process
|
||||
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 ! MPI datatype for fission bank
|
||||
type(MPI_Comm) :: mpi_intracomm ! MPI intra-communicator
|
||||
|
|
|
|||
|
|
@ -2,14 +2,16 @@ module mgxs_data
|
|||
|
||||
use constants
|
||||
use algorithm, only: find
|
||||
use dict_header, only: DictCharInt
|
||||
use error, only: fatal_error
|
||||
use geometry_header, only: get_temperatures
|
||||
use global
|
||||
use geometry_header, only: get_temperatures, cells
|
||||
use hdf5_interface
|
||||
use material_header, only: Material
|
||||
use material_header, only: Material, materials, n_materials
|
||||
use mgxs_header
|
||||
use nuclide_header, only: n_nuclides
|
||||
use output, only: write_message
|
||||
use set_header, only: SetChar
|
||||
use settings
|
||||
use stl_vector, only: VectorReal
|
||||
use string, only: to_lower
|
||||
implicit none
|
||||
|
|
@ -24,7 +26,6 @@ contains
|
|||
subroutine read_mgxs()
|
||||
integer :: i ! index in materials array
|
||||
integer :: j ! index over nuclides in material
|
||||
integer :: i_xsdata ! index in <xsdata> list
|
||||
integer :: i_nuclide ! index in nuclides array
|
||||
character(20) :: name ! name of library to load
|
||||
integer :: representation ! Data representation
|
||||
|
|
@ -34,7 +35,6 @@ contains
|
|||
integer(HID_T) :: file_id
|
||||
integer(HID_T) :: xsdata_group
|
||||
logical :: file_exists
|
||||
type(DictCharInt) :: xsdata_dict
|
||||
type(VectorReal), allocatable :: temps(:)
|
||||
character(MAX_WORD_LEN) :: word
|
||||
integer, allocatable :: array(:)
|
||||
|
|
@ -51,8 +51,7 @@ contains
|
|||
call write_message("Loading cross section data...", 5)
|
||||
|
||||
! Get temperatures
|
||||
call get_temperatures(cells, materials, material_dict, nuclide_dict, &
|
||||
n_nuclides_total, temps)
|
||||
call get_temperatures(temps)
|
||||
|
||||
! Open file for reading
|
||||
file_id = file_open(path_cross_sections, 'r', parallel=.true.)
|
||||
|
|
@ -72,7 +71,7 @@ contains
|
|||
end if
|
||||
|
||||
! allocate arrays for MGXS storage and cross section cache
|
||||
allocate(nuclides_MG(n_nuclides_total))
|
||||
allocate(nuclides_MG(n_nuclides))
|
||||
|
||||
! ==========================================================================
|
||||
! READ ALL MGXS CROSS SECTION TABLES
|
||||
|
|
@ -85,7 +84,6 @@ contains
|
|||
name = mat % names(j)
|
||||
|
||||
if (.not. already_read % contains(name)) then
|
||||
i_xsdata = xsdata_dict % get_key(to_lower(name))
|
||||
i_nuclide = mat % nuclide(j)
|
||||
|
||||
call write_message("Loading " // trim(name) // " data...", 6)
|
||||
|
|
@ -234,7 +232,7 @@ contains
|
|||
kT = cells(i) % sqrtkT(1)**2
|
||||
end if
|
||||
|
||||
i_material = material_dict % get_key(cells(i) % material(j))
|
||||
i_material = cells(i) % material(j)
|
||||
|
||||
! Add temperature if it hasn't already been added
|
||||
if (find(kTs(i_material), kT) == -1) then
|
||||
|
|
|
|||
|
|
@ -209,7 +209,25 @@ module mgxs_header
|
|||
procedure :: calculate_xs => mgxsang_calculate_xs
|
||||
end type MgxsAngle
|
||||
|
||||
contains
|
||||
! Cross section arrays
|
||||
type(MgxsContainer), allocatable, target :: nuclides_MG(:)
|
||||
|
||||
! Cross section caches
|
||||
type(MgxsContainer), target, allocatable :: macro_xs(:)
|
||||
|
||||
! Number of energy groups
|
||||
integer :: num_energy_groups
|
||||
|
||||
! Number of delayed groups
|
||||
integer :: num_delayed_groups
|
||||
|
||||
! Energy group structure
|
||||
real(8), allocatable :: energy_bins(:)
|
||||
|
||||
! Midpoint of the energy group structure
|
||||
real(8), allocatable :: energy_bin_avg(:)
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! MGXS*_FROM_HDF5 reads in the data from the HDF5 Library. At the point of entry
|
||||
|
|
@ -3533,4 +3551,15 @@ module mgxs_header
|
|||
|
||||
end subroutine find_angle
|
||||
|
||||
!===============================================================================
|
||||
! FREE_MEMORY_MGXS deallocates global arrays defined in this module
|
||||
!===============================================================================
|
||||
|
||||
subroutine free_memory_mgxs()
|
||||
if (allocated(nuclides_MG)) deallocate(nuclides_MG)
|
||||
if (allocated(macro_xs)) deallocate(macro_xs)
|
||||
if (allocated(energy_bins)) deallocate(energy_bins)
|
||||
if (allocated(energy_bin_avg)) deallocate(energy_bin_avg)
|
||||
end subroutine free_memory_mgxs
|
||||
|
||||
end module mgxs_header
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@ module multipole
|
|||
use hdf5
|
||||
|
||||
use constants
|
||||
use global
|
||||
use error, only: fatal_error
|
||||
use hdf5_interface
|
||||
use multipole_header, only: MultipoleArray, FIT_T, FIT_A, FIT_F, &
|
||||
MP_FISS, FORM_MLBW, FORM_RM
|
||||
use nuclide_header, only: nuclides
|
||||
|
||||
implicit none
|
||||
|
||||
|
|
|
|||
|
|
@ -7,19 +7,19 @@ module nuclide_header
|
|||
|
||||
use algorithm, only: sort, find
|
||||
use constants
|
||||
use dict_header, only: DictIntInt
|
||||
use dict_header, only: DictIntInt, DictCharInt
|
||||
use endf, only: reaction_name, is_fission, is_disappearance
|
||||
use endf_header, only: Function1D, Polynomial, Tabulated1D
|
||||
use error, only: fatal_error, warning
|
||||
use hdf5_interface, only: read_attribute, open_group, close_group, &
|
||||
open_dataset, read_dataset, close_dataset, get_shape, get_datasets, &
|
||||
object_exists, get_name, get_groups
|
||||
use error
|
||||
use hdf5_interface
|
||||
use list_header, only: ListInt
|
||||
use math, only: evaluate_legendre
|
||||
use message_passing
|
||||
use multipole_header, only: MultipoleArray
|
||||
use product_header, only: AngleEnergyContainer
|
||||
use reaction_header, only: Reaction
|
||||
use secondary_uncorrelated, only: UncorrelatedAngleEnergy
|
||||
use settings
|
||||
use stl_vector, only: VectorInt, VectorReal
|
||||
use string
|
||||
use urr_header, only: UrrData
|
||||
|
|
@ -96,6 +96,7 @@ module nuclide_header
|
|||
class(Function1D), allocatable :: fission_q_recov ! fragments, neutrons, gammas, betas
|
||||
|
||||
contains
|
||||
procedure :: assign_0K_elastic_scattering
|
||||
procedure :: clear => nuclide_clear
|
||||
procedure :: from_hdf5 => nuclide_from_hdf5
|
||||
procedure :: init_grid => nuclide_init_grid
|
||||
|
|
@ -166,8 +167,80 @@ module nuclide_header
|
|||
character(MAX_FILE_LEN) :: path
|
||||
end type Library
|
||||
|
||||
! Cross section libraries
|
||||
type(Library), allocatable :: libraries(:)
|
||||
type(DictCharInt) :: library_dict
|
||||
|
||||
! Nuclear data for each nuclide
|
||||
type(Nuclide), allocatable, target :: nuclides(:)
|
||||
integer(C_INT), bind(C) :: n_nuclides
|
||||
type(DictCharInt) :: nuclide_dict
|
||||
|
||||
! Cross section caches
|
||||
type(NuclideMicroXS), allocatable :: micro_xs(:) ! Cache for each nuclide
|
||||
type(MaterialMacroXS) :: material_xs ! Cache for current material
|
||||
!$omp threadprivate(micro_xs, material_xs)
|
||||
|
||||
! Minimum/maximum energies
|
||||
real(8) :: energy_min_neutron = ZERO
|
||||
real(8) :: energy_max_neutron = INFINITY
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! ASSIGN_0K_ELASTIC_SCATTERING
|
||||
!===============================================================================
|
||||
|
||||
subroutine assign_0K_elastic_scattering(this)
|
||||
class(Nuclide), intent(inout) :: this
|
||||
|
||||
integer :: i
|
||||
real(8) :: xs_cdf_sum
|
||||
|
||||
this % resonant = .false.
|
||||
if (allocated(res_scat_nuclides)) then
|
||||
! If resonant nuclides were specified, check the list explicitly
|
||||
do i = 1, size(res_scat_nuclides)
|
||||
if (this % name == res_scat_nuclides(i)) then
|
||||
this % resonant = .true.
|
||||
|
||||
! Make sure nuclide has 0K data
|
||||
if (.not. allocated(this % energy_0K)) then
|
||||
call fatal_error("Cannot treat " // trim(this % name) // " as a &
|
||||
&resonant scatterer because 0 K elastic scattering data is &
|
||||
¬ present.")
|
||||
end if
|
||||
|
||||
exit
|
||||
end if
|
||||
end do
|
||||
else
|
||||
! Otherwise, assume that any that have 0 K elastic scattering data are
|
||||
! resonant
|
||||
this % resonant = allocated(this % energy_0K)
|
||||
end if
|
||||
|
||||
if (this % resonant) then
|
||||
! Build CDF for 0K elastic scattering
|
||||
xs_cdf_sum = ZERO
|
||||
allocate(this % xs_cdf(0:size(this % energy_0K)))
|
||||
this % xs_cdf(0) = ZERO
|
||||
|
||||
associate (E => this % energy_0K, xs => this % elastic_0K)
|
||||
do i = 1, size(E) - 1
|
||||
! Negative cross sections result in a CDF that is not monotonically
|
||||
! increasing. Set all negative xs values to zero.
|
||||
if (xs(i) < ZERO) xs(i) = ZERO
|
||||
|
||||
! build xs cdf
|
||||
xs_cdf_sum = xs_cdf_sum + (sqrt(E(i))*xs(i) + sqrt(E(i+1))*xs(i+1))&
|
||||
/ TWO * (E(i+1) - E(i))
|
||||
this % xs_cdf(i) = xs_cdf_sum
|
||||
end do
|
||||
end associate
|
||||
end if
|
||||
end subroutine assign_0K_elastic_scattering
|
||||
|
||||
!===============================================================================
|
||||
! NUCLIDE_CLEAR resets and deallocates data in Nuclide
|
||||
!===============================================================================
|
||||
|
|
@ -521,7 +594,7 @@ contains
|
|||
|
||||
do i = 1, size(this % reactions)
|
||||
call MTs % push_back(this % reactions(i) % MT)
|
||||
call this % reaction_index % add_key(this % reactions(i) % MT, i)
|
||||
call this % reaction_index % set(this % reactions(i) % MT, i)
|
||||
|
||||
associate (rx => this % reactions(i))
|
||||
! Skip total inelastic level scattering, gas production cross sections
|
||||
|
|
@ -745,4 +818,169 @@ contains
|
|||
|
||||
end subroutine nuclide_init_grid
|
||||
|
||||
!===============================================================================
|
||||
! CHECK_DATA_VERSION checks for the right version of nuclear data within HDF5
|
||||
! files
|
||||
!===============================================================================
|
||||
|
||||
subroutine check_data_version(file_id)
|
||||
integer(HID_T), intent(in) :: file_id
|
||||
|
||||
integer, allocatable :: version(:)
|
||||
|
||||
if (attribute_exists(file_id, 'version')) then
|
||||
call read_attribute(version, file_id, 'version')
|
||||
if (version(1) /= HDF5_VERSION(1)) then
|
||||
call fatal_error("HDF5 data format uses version " // trim(to_str(&
|
||||
version(1))) // "." // trim(to_str(version(2))) // " whereas &
|
||||
&your installation of OpenMC expects version " // trim(to_str(&
|
||||
HDF5_VERSION(1))) // ".x data.")
|
||||
end if
|
||||
else
|
||||
call fatal_error("HDF5 data does not indicate a version. Your &
|
||||
&installation of OpenMC expects version " // trim(to_str(&
|
||||
HDF5_VERSION(1))) // ".x data.")
|
||||
end if
|
||||
end subroutine check_data_version
|
||||
|
||||
!===============================================================================
|
||||
! FREE_MEMORY_NUCLIDE deallocates global arrays defined in this module
|
||||
!===============================================================================
|
||||
|
||||
subroutine free_memory_nuclide()
|
||||
integer :: i
|
||||
|
||||
! Deallocate cross section data, listings, and cache
|
||||
if (allocated(nuclides)) then
|
||||
! First call the clear routines
|
||||
do i = 1, size(nuclides)
|
||||
call nuclides(i) % clear()
|
||||
end do
|
||||
deallocate(nuclides)
|
||||
end if
|
||||
n_nuclides = 0
|
||||
|
||||
if (allocated(libraries)) deallocate(libraries)
|
||||
|
||||
call nuclide_dict % clear()
|
||||
call library_dict % clear()
|
||||
|
||||
end subroutine free_memory_nuclide
|
||||
|
||||
!===============================================================================
|
||||
! C API FUNCTIONS
|
||||
!===============================================================================
|
||||
|
||||
function openmc_get_nuclide_index(name, index) result(err) bind(C)
|
||||
! Return the index in the nuclides array of a nuclide with a given name
|
||||
character(kind=C_CHAR), intent(in) :: name(*)
|
||||
integer(C_INT), intent(out) :: index
|
||||
integer(C_INT) :: err
|
||||
|
||||
character(:), allocatable :: name_
|
||||
|
||||
! Copy array of C_CHARs to normal Fortran string
|
||||
name_ = to_f_string(name)
|
||||
|
||||
if (allocated(nuclides)) then
|
||||
if (nuclide_dict % has(to_lower(name_))) then
|
||||
index = nuclide_dict % get(to_lower(name_))
|
||||
err = 0
|
||||
else
|
||||
err = E_DATA
|
||||
call set_errmsg("No nuclide named '" // trim(name_) // &
|
||||
"' has been loaded.")
|
||||
end if
|
||||
else
|
||||
err = E_ALLOCATE
|
||||
call set_errmsg("Memory for nuclides has not been allocated.")
|
||||
end if
|
||||
end function openmc_get_nuclide_index
|
||||
|
||||
|
||||
function openmc_load_nuclide(name) result(err) bind(C)
|
||||
! Load a nuclide from the cross section library
|
||||
character(kind=C_CHAR), intent(in) :: name(*)
|
||||
integer(C_INT) :: err
|
||||
|
||||
integer :: i_library
|
||||
integer :: n
|
||||
integer(HID_T) :: file_id
|
||||
integer(HID_T) :: group_id
|
||||
character(:), allocatable :: name_
|
||||
real(8) :: minmax(2) = [ZERO, INFINITY]
|
||||
type(VectorReal) :: temperature
|
||||
type(Nuclide), allocatable :: new_nuclides(:)
|
||||
|
||||
! Copy array of C_CHARs to normal Fortran string
|
||||
name_ = to_f_string(name)
|
||||
|
||||
err = 0
|
||||
if (.not. nuclide_dict % has(to_lower(name_))) then
|
||||
if (library_dict % has(to_lower(name_))) then
|
||||
! allocate extra space in nuclides array
|
||||
n = n_nuclides
|
||||
allocate(new_nuclides(n + 1))
|
||||
new_nuclides(1:n) = nuclides(:)
|
||||
call move_alloc(FROM=new_nuclides, TO=nuclides)
|
||||
n = n + 1
|
||||
|
||||
i_library = library_dict % get(to_lower(name_))
|
||||
|
||||
! Open file and make sure version is sufficient
|
||||
file_id = file_open(libraries(i_library) % path, 'r')
|
||||
call check_data_version(file_id)
|
||||
|
||||
! Read nuclide data from HDF5
|
||||
group_id = open_group(file_id, name_)
|
||||
call nuclides(n) % from_hdf5(group_id, temperature, &
|
||||
temperature_method, temperature_tolerance, minmax, &
|
||||
master)
|
||||
call close_group(group_id)
|
||||
call file_close(file_id)
|
||||
|
||||
! Add entry to nuclide dictionary
|
||||
call nuclide_dict % set(to_lower(name_), n)
|
||||
n_nuclides = n
|
||||
|
||||
! Assign resonant scattering data
|
||||
if (res_scat_on) call nuclides(n) % assign_0K_elastic_scattering()
|
||||
|
||||
! Initialize nuclide grid
|
||||
call nuclides(n) % init_grid(energy_min_neutron, &
|
||||
energy_max_neutron, n_log_bins)
|
||||
else
|
||||
err = E_DATA
|
||||
call set_errmsg("Nuclide '" // trim(name_) // "' is not present &
|
||||
&in library.")
|
||||
end if
|
||||
end if
|
||||
|
||||
end function openmc_load_nuclide
|
||||
|
||||
|
||||
function openmc_nuclide_name(index, name) result(err) bind(C)
|
||||
! Return the name of a nuclide with a given index
|
||||
integer(C_INT), value, intent(in) :: index
|
||||
type(c_ptr), intent(out) :: name
|
||||
integer(C_INT) :: err
|
||||
|
||||
character(C_CHAR), pointer :: name_
|
||||
|
||||
err = E_UNASSIGNED
|
||||
if (allocated(nuclides)) then
|
||||
if (index >= 1 .and. index <= size(nuclides)) then
|
||||
name_ => nuclides(index) % name(1:1)
|
||||
name = C_LOC(name_)
|
||||
err = 0
|
||||
else
|
||||
err = E_OUT_OF_BOUNDS
|
||||
call set_errmsg("Index in nuclides array is out of bounds.")
|
||||
end if
|
||||
else
|
||||
err = E_ALLOCATE
|
||||
call set_errmsg("Memory for nuclides has not been allocated yet.")
|
||||
end if
|
||||
end function openmc_nuclide_name
|
||||
|
||||
end module nuclide_header
|
||||
|
|
|
|||
|
|
@ -1,24 +1,32 @@
|
|||
module output
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
use, intrinsic :: ISO_FORTRAN_ENV
|
||||
|
||||
use cmfd_header
|
||||
use constants
|
||||
use eigenvalue, only: openmc_get_keff
|
||||
use endf, only: reaction_name
|
||||
use error, only: fatal_error, warning
|
||||
use geometry_header, only: Cell, Universe, Lattice, RectLattice, &
|
||||
HexLattice
|
||||
use global
|
||||
use geometry_header
|
||||
use math, only: t_percentile
|
||||
use mesh_header, only: RegularMesh
|
||||
use mesh, only: mesh_indices_to_bin, bin_to_mesh_indices
|
||||
use mesh_header, only: RegularMesh, meshes
|
||||
use message_passing, only: master, n_procs
|
||||
use mgxs_header, only: nuclides_MG
|
||||
use nuclide_header
|
||||
use particle_header, only: LocalCoord, Particle
|
||||
use plot_header
|
||||
use sab_header, only: SAlphaBeta
|
||||
use settings
|
||||
use simulation_header
|
||||
use surface_header, only: surfaces
|
||||
use string, only: to_upper, to_str
|
||||
use tally_header, only: TallyObject
|
||||
use tally_header
|
||||
use tally_derivative_header
|
||||
use tally_filter
|
||||
use tally_filter_mesh, only: MeshFilter
|
||||
use tally_filter_header, only: TallyFilterMatch
|
||||
use timer_header
|
||||
|
||||
implicit none
|
||||
|
||||
|
|
@ -529,6 +537,7 @@ contains
|
|||
|
||||
subroutine print_runtime()
|
||||
|
||||
integer :: n_active
|
||||
real(8) :: speed_inactive ! # of neutrons/second in inactive batches
|
||||
real(8) :: speed_active ! # of neutrons/second in active batches
|
||||
character(15) :: string
|
||||
|
|
@ -561,6 +570,7 @@ contains
|
|||
write(ou,100) "Total time elapsed", time_total % elapsed
|
||||
|
||||
! Calculate particle rate in active/inactive batches
|
||||
n_active = n_batches - n_inactive
|
||||
if (restart_run) then
|
||||
if (restart_batch < n_inactive) then
|
||||
speed_inactive = real(n_particles * (n_inactive - restart_batch) * &
|
||||
|
|
@ -608,6 +618,8 @@ contains
|
|||
real(8) :: t_n1 ! t-value with N-1 degrees of freedom
|
||||
real(8) :: t_n3 ! t-value with N-3 degrees of freedom
|
||||
real(8) :: x(2) ! mean and standard deviation
|
||||
real(C_DOUBLE) :: k_combined(2)
|
||||
integer(C_INT) :: err
|
||||
|
||||
! display header block for results
|
||||
call header("Results", 4)
|
||||
|
|
@ -634,10 +646,13 @@ contains
|
|||
write(ou,102) "k-effective (Track-length)", x(1), t_n1 * x(2)
|
||||
x(:) = mean_stdev(r(:, K_ABSORPTION), n)
|
||||
write(ou,102) "k-effective (Absorption)", x(1), t_n1 * x(2)
|
||||
if (n > 3) write(ou,102) "Combined k-effective", k_combined(1), &
|
||||
t_n3 * k_combined(2)
|
||||
if (n > 3) then
|
||||
err = openmc_get_keff(k_combined)
|
||||
write(ou,102) "Combined k-effective", k_combined(1), &
|
||||
t_n3 * k_combined(2)
|
||||
end if
|
||||
end if
|
||||
x(:) = mean_stdev(global_tallies(:, LEAKAGE), n)
|
||||
x(:) = mean_stdev(r(:, LEAKAGE), n)
|
||||
write(ou,102) "Leakage Fraction", x(1), t_n1 * x(2)
|
||||
end associate
|
||||
else
|
||||
|
|
@ -722,11 +737,13 @@ contains
|
|||
character(36) :: score_names(N_SCORE_TYPES) ! names of scoring function
|
||||
character(36) :: score_name ! names of scoring function
|
||||
! to be applied at write-time
|
||||
type(TallyObject), pointer :: t
|
||||
type(TallyFilterMatch), allocatable :: matches(:)
|
||||
|
||||
! Skip if there are no tallies
|
||||
if (n_tallies == 0) return
|
||||
|
||||
allocate(matches(n_filters))
|
||||
|
||||
! Initialize names for scores
|
||||
score_names(abs(SCORE_FLUX)) = "Flux"
|
||||
score_names(abs(SCORE_TOTAL)) = "Total Reaction Rate"
|
||||
|
|
@ -751,6 +768,7 @@ contains
|
|||
score_names(abs(SCORE_INVERSE_VELOCITY)) = "Flux-Weighted Inverse Velocity"
|
||||
score_names(abs(SCORE_FISS_Q_PROMPT)) = "Prompt fission power"
|
||||
score_names(abs(SCORE_FISS_Q_RECOV)) = "Recoverable fission power"
|
||||
score_names(abs(SCORE_CURRENT)) = "Current"
|
||||
|
||||
! Create filename for tally output
|
||||
filename = trim(path_output) // "tallies.out"
|
||||
|
|
@ -767,7 +785,7 @@ contains
|
|||
end if
|
||||
|
||||
TALLY_LOOP: do i = 1, n_tallies
|
||||
t => tallies(i)
|
||||
associate (t => tallies(i) % obj)
|
||||
nr = t % n_realizations
|
||||
|
||||
if (confidence_intervals) then
|
||||
|
|
@ -809,7 +827,7 @@ contains
|
|||
end if
|
||||
|
||||
! Handle surface current tallies separately
|
||||
if (t % type == TALLY_SURFACE_CURRENT) then
|
||||
if (t % type == TALLY_MESH_CURRENT) then
|
||||
call write_surface_current(t, unit_tally)
|
||||
cycle
|
||||
end if
|
||||
|
|
@ -822,8 +840,8 @@ contains
|
|||
|
||||
! Initialize bins, filter level, and indentation
|
||||
do h = 1, size(t % filter)
|
||||
call filter_matches(t % filter(h)) % bins % clear()
|
||||
call filter_matches(t % filter(h)) % bins % push_back(0)
|
||||
call matches(t % filter(h)) % bins % clear()
|
||||
call matches(t % filter(h)) % bins % push_back(0)
|
||||
end do
|
||||
j = 1
|
||||
indent = 0
|
||||
|
|
@ -834,18 +852,18 @@ contains
|
|||
if (size(t % filter) == 0) exit find_bin
|
||||
|
||||
! Increment bin combination
|
||||
filter_matches(t % filter(j)) % bins % data(1) = &
|
||||
filter_matches(t % filter(j)) % bins % data(1) + 1
|
||||
matches(t % filter(j)) % bins % data(1) = &
|
||||
matches(t % filter(j)) % bins % data(1) + 1
|
||||
|
||||
! =================================================================
|
||||
! REACHED END OF BINS FOR THIS FILTER, MOVE TO NEXT FILTER
|
||||
|
||||
if (filter_matches(t % filter(j)) % bins % data(1) > &
|
||||
if (matches(t % filter(j)) % bins % data(1) > &
|
||||
filters(t % filter(j)) % obj % n_bins) then
|
||||
! If this is the first filter, then exit
|
||||
if (j == 1) exit print_bin
|
||||
|
||||
filter_matches(t % filter(j)) % bins % data(1) = 0
|
||||
matches(t % filter(j)) % bins % data(1) = 0
|
||||
j = j - 1
|
||||
indent = indent - 2
|
||||
|
||||
|
|
@ -859,7 +877,7 @@ contains
|
|||
! Print current filter information
|
||||
write(UNIT=unit_tally, FMT='(1X,2A)') repeat(" ", indent), &
|
||||
trim(filters(t % filter(j)) % obj % &
|
||||
text_label(filter_matches(t % filter(j)) % bins % data(1)))
|
||||
text_label(matches(t % filter(j)) % bins % data(1)))
|
||||
indent = indent + 2
|
||||
j = j + 1
|
||||
end if
|
||||
|
|
@ -870,7 +888,7 @@ contains
|
|||
if (size(t % filter) > 0) then
|
||||
write(UNIT=unit_tally, FMT='(1X,2A)') repeat(" ", indent), &
|
||||
trim(filters(t % filter(j)) % obj % &
|
||||
text_label(filter_matches(t % filter(j)) % bins % data(1)))
|
||||
text_label(matches(t % filter(j)) % bins % data(1)))
|
||||
end if
|
||||
|
||||
! Determine scoring index for this bin combination -- note that unlike
|
||||
|
|
@ -879,7 +897,7 @@ contains
|
|||
|
||||
filter_index = 1
|
||||
do h = 1, size(t % filter)
|
||||
filter_index = filter_index + (max(filter_matches(t % filter(h)) &
|
||||
filter_index = filter_index + (max(matches(t % filter(h)) &
|
||||
% bins % data(1),1) - 1) * t % stride(h)
|
||||
end do
|
||||
|
||||
|
|
@ -968,6 +986,7 @@ contains
|
|||
|
||||
end do print_bin
|
||||
|
||||
end associate
|
||||
end do TALLY_LOOP
|
||||
|
||||
close(UNIT=unit_tally)
|
||||
|
|
@ -1001,6 +1020,9 @@ contains
|
|||
logical :: energy_filters ! energy filters present
|
||||
character(MAX_LINE_LEN) :: string
|
||||
type(RegularMesh), pointer :: m
|
||||
type(TallyFilterMatch), allocatable :: matches(:)
|
||||
|
||||
allocate(matches(n_filters))
|
||||
|
||||
nr = t % n_realizations
|
||||
|
||||
|
|
@ -1017,8 +1039,8 @@ contains
|
|||
|
||||
! initialize bins array
|
||||
do j = 1, size(t % filter)
|
||||
call filter_matches(t % filter(j)) % bins % clear()
|
||||
call filter_matches(t % filter(j)) % bins % push_back(1)
|
||||
call matches(t % filter(j)) % bins % clear()
|
||||
call matches(t % filter(j)) % bins % push_back(1)
|
||||
end do
|
||||
|
||||
! determine how many energy in bins there are
|
||||
|
|
@ -1040,8 +1062,8 @@ contains
|
|||
do i = 1, n_cells
|
||||
|
||||
! Get the indices for this cell
|
||||
call bin_to_mesh_indices(m, i, ijk)
|
||||
filter_matches(i_filter_mesh) % bins % data(1) = i
|
||||
call m % get_indices_from_bin(i, ijk)
|
||||
matches(i_filter_mesh) % bins % data(1) = i
|
||||
|
||||
! Write the header for this cell
|
||||
if (n_dim == 1) then
|
||||
|
|
@ -1059,18 +1081,18 @@ contains
|
|||
do l = 1, n
|
||||
if (print_ebin) then
|
||||
! Set incoming energy bin
|
||||
filter_matches(i_filter_ein) % bins % data(1) = l
|
||||
matches(i_filter_ein) % bins % data(1) = l
|
||||
|
||||
! Write incoming energy bin
|
||||
write(UNIT=unit_tally, FMT='(3X,A)') &
|
||||
trim(filters(i_filter_ein) % obj % text_label( &
|
||||
filter_matches(i_filter_ein) % bins % data(1)))
|
||||
matches(i_filter_ein) % bins % data(1)))
|
||||
end if
|
||||
|
||||
filter_index = 1
|
||||
do j = 1, size(t % filter)
|
||||
if (t % filter(j) == i_filter_surf) cycle
|
||||
filter_index = filter_index + (filter_matches(t % filter(j)) &
|
||||
filter_index = filter_index + (matches(t % filter(j)) &
|
||||
% bins % data(1) - 1) * t % stride(j)
|
||||
end do
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ module particle_header
|
|||
!===============================================================================
|
||||
|
||||
type LocalCoord
|
||||
|
||||
! Indices in various arrays for this level
|
||||
integer :: cell = NONE
|
||||
integer :: universe = NONE
|
||||
|
|
@ -48,6 +49,10 @@ module particle_header
|
|||
integer :: cell_instance ! offset for distributed properties
|
||||
type(LocalCoord) :: coord(MAX_COORD) ! coordinates for all levels
|
||||
|
||||
! Particle coordinates before crossing a surface
|
||||
integer :: last_n_coord ! number of current coordinates
|
||||
integer :: last_cell(MAX_COORD) ! coordinates for all levels
|
||||
|
||||
! Energy Data
|
||||
real(8) :: E ! post-collision energy
|
||||
real(8) :: last_E ! pre-collision energy
|
||||
|
|
@ -142,11 +147,12 @@ contains
|
|||
this % fission = .false.
|
||||
this % delayed_group = 0
|
||||
this % n_delayed_bank(:) = 0
|
||||
this % g = 1
|
||||
this % g = NONE
|
||||
|
||||
! Set up base level coordinates
|
||||
this % coord(1) % universe = root_universe
|
||||
this % n_coord = 1
|
||||
this % last_n_coord = 1
|
||||
|
||||
end subroutine initialize_particle
|
||||
|
||||
|
|
@ -209,6 +215,7 @@ contains
|
|||
this % last_uvw = src % uvw
|
||||
if (run_CE) then
|
||||
this % E = src % E
|
||||
this % g = NONE
|
||||
else
|
||||
this % g = int(src % E)
|
||||
this % last_g = int(src % E)
|
||||
|
|
|
|||
|
|
@ -4,11 +4,15 @@ module particle_restart
|
|||
|
||||
use bank_header, only: Bank
|
||||
use constants
|
||||
use global
|
||||
use hdf5_interface, only: file_open, file_close, read_dataset
|
||||
use mgxs_header, only: energy_bin_avg
|
||||
use nuclide_header, only: micro_xs, n_nuclides
|
||||
use output, only: write_message, print_particle
|
||||
use particle_header, only: Particle
|
||||
use random_lcg, only: set_particle_seed
|
||||
use settings
|
||||
use simulation_header
|
||||
use tally_header, only: n_tallies
|
||||
use tracking, only: transport
|
||||
|
||||
use hdf5, only: HID_T
|
||||
|
|
@ -32,7 +36,7 @@ contains
|
|||
! Set verbosity high
|
||||
verbosity = 10
|
||||
|
||||
allocate(micro_xs(n_nuclides_total))
|
||||
allocate(micro_xs(n_nuclides))
|
||||
|
||||
! Initialize the particle to be tracked
|
||||
call p % initialize()
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
module particle_restart_write
|
||||
|
||||
use bank_header, only: Bank
|
||||
use global
|
||||
use bank_header, only: Bank, source_bank
|
||||
use hdf5_interface
|
||||
use particle_header, only: Particle
|
||||
use settings
|
||||
use simulation_header
|
||||
use string, only: to_str
|
||||
|
||||
use hdf5
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ module photon_header
|
|||
use hdf5, only: HID_T, HSIZE_T, SIZE_T
|
||||
|
||||
use constants, only: ZERO, HALF, SUBSHELLS
|
||||
use dict_header, only: DictIntInt
|
||||
use dict_header, only: DictIntInt, DictCharInt
|
||||
use endf_header, only: Tabulated1D
|
||||
use hdf5_interface
|
||||
|
||||
|
|
@ -57,6 +57,11 @@ module photon_header
|
|||
procedure :: from_hdf5 => photon_from_hdf5
|
||||
end type PhotonInteraction
|
||||
|
||||
type(PhotonInteraction), allocatable :: elements(:) ! Photon cross sections
|
||||
integer :: n_elements ! Number of photon cross section tables
|
||||
|
||||
type(DictCharInt) :: element_dict
|
||||
|
||||
!===============================================================================
|
||||
! ELEMENTMICROXS contains cached microscopic photon cross sections for a
|
||||
! particular element at the current energy
|
||||
|
|
@ -73,6 +78,9 @@ module photon_header
|
|||
real(8) :: pair_production ! microscopic pair production xs
|
||||
end type ElementMicroXS
|
||||
|
||||
type(ElementMicroXS), allocatable :: micro_photon_xs(:) ! Cache for each element
|
||||
!$omp threadprivate(micro_photon_xs)
|
||||
|
||||
contains
|
||||
|
||||
subroutine photon_from_hdf5(this, group_id)
|
||||
|
|
@ -167,7 +175,7 @@ contains
|
|||
! Create mapping from designator to index
|
||||
do j = 1, size(SUBSHELLS)
|
||||
if (designators(i) == SUBSHELLS(j)) then
|
||||
call this % shell_dict % add_key(j, i)
|
||||
call this % shell_dict % set(j, i)
|
||||
this % shells(i) % index_subshell = j
|
||||
exit
|
||||
end if
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ contains
|
|||
call p % create_secondary(uvw, E, ELECTRON, run_ce=.true.)
|
||||
|
||||
! Fill hole left by emitted auger electron
|
||||
i_hole = elm % shell_dict % get_key(secondary)
|
||||
i_hole = elm % shell_dict % get(secondary)
|
||||
call atomic_relaxation(p, elm, i_hole)
|
||||
else
|
||||
! Radiative transition -- get X-ray energy
|
||||
|
|
@ -363,7 +363,7 @@ contains
|
|||
end if
|
||||
|
||||
! Fill hole created by electron transitioning to the photoelectron hole
|
||||
i_hole = elm % shell_dict % get_key(primary)
|
||||
i_hole = elm % shell_dict % get(primary)
|
||||
call atomic_relaxation(p, elm, i_hole)
|
||||
|
||||
end subroutine atomic_relaxation
|
||||
|
|
|
|||
|
|
@ -5,22 +5,26 @@ module physics
|
|||
use cross_section, only: elastic_xs_0K
|
||||
use endf, only: reaction_name
|
||||
use error, only: fatal_error, warning
|
||||
use global
|
||||
use material_header, only: Material
|
||||
use material_header, only: Material, materials
|
||||
use math
|
||||
use mesh, only: get_mesh_indices
|
||||
use mesh_header, only: meshes
|
||||
use message_passing
|
||||
use nuclide_header
|
||||
use output, only: write_message
|
||||
use particle_header, only: Particle
|
||||
use particle_restart_write, only: write_particle_restart
|
||||
use photon_header
|
||||
use photon_physics, only: rayleigh_scatter, compton_scatter, &
|
||||
atomic_relaxation
|
||||
use physics_common
|
||||
use random_lcg, only: prn, advance_prn_seed, prn_set_stream
|
||||
use reaction_header, only: Reaction
|
||||
use sab_header, only: sab_tables
|
||||
use secondary_uncorrelated, only: UncorrelatedAngleEnergy
|
||||
use settings
|
||||
use simulation_header
|
||||
use string, only: to_str
|
||||
use tally_header
|
||||
|
||||
implicit none
|
||||
|
||||
|
|
@ -35,11 +39,6 @@ contains
|
|||
|
||||
type(Particle), intent(inout) :: p
|
||||
|
||||
! Store pre-collision particle properties
|
||||
p % last_wgt = p % wgt
|
||||
p % last_E = p % E
|
||||
p % last_uvw = p % coord(1) % uvw
|
||||
|
||||
! Add to collision counter for particle
|
||||
p % n_collision = p % n_collision + 1
|
||||
|
||||
|
|
@ -1399,10 +1398,9 @@ contains
|
|||
integer :: nu_d(MAX_DELAYED_GROUPS) ! number of delayed neutrons born
|
||||
integer :: i ! loop index
|
||||
integer :: nu ! actual number of neutrons produced
|
||||
integer :: ijk(3) ! indices in ufs mesh
|
||||
integer :: mesh_bin ! mesh bin for source site
|
||||
real(8) :: nu_t ! total nu
|
||||
real(8) :: weight ! weight adjustment for ufs method
|
||||
logical :: in_mesh ! source site in ufs mesh?
|
||||
type(Nuclide), pointer :: nuc
|
||||
|
||||
! Get pointers
|
||||
|
|
@ -1414,18 +1412,20 @@ contains
|
|||
! the expected number of fission sites produced
|
||||
|
||||
if (ufs) then
|
||||
! Determine indices on ufs mesh for current location
|
||||
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!")
|
||||
end if
|
||||
associate (m => meshes(index_ufs_mesh))
|
||||
! Determine indices on ufs mesh for current location
|
||||
call m % get_bin(p % coord(1) % xyz, mesh_bin)
|
||||
if (mesh_bin == NO_BIN_FOUND) then
|
||||
call write_particle_restart(p)
|
||||
call fatal_error("Source site outside UFS mesh!")
|
||||
end if
|
||||
|
||||
if (source_frac(1,ijk(1),ijk(2),ijk(3)) /= ZERO) then
|
||||
weight = ufs_mesh % volume_frac / source_frac(1,ijk(1),ijk(2),ijk(3))
|
||||
else
|
||||
weight = ONE
|
||||
end if
|
||||
if (source_frac(1, mesh_bin) /= ZERO) then
|
||||
weight = m % volume_frac / source_frac(1, mesh_bin)
|
||||
else
|
||||
weight = ONE
|
||||
end if
|
||||
end associate
|
||||
else
|
||||
weight = ONE
|
||||
end if
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
module physics_common
|
||||
|
||||
use constants
|
||||
use global, only: weight_cutoff, weight_survive
|
||||
use particle_header, only: Particle
|
||||
use random_lcg, only: prn
|
||||
use settings, only: weight_cutoff, weight_survive
|
||||
|
||||
implicit none
|
||||
|
||||
|
|
|
|||
|
|
@ -2,21 +2,25 @@ module physics_mg
|
|||
! This module contains the multi-group specific physics routines so as to not
|
||||
! hinder performance of the CE versions with multiple if-thens.
|
||||
|
||||
use bank_header
|
||||
use constants
|
||||
use error, only: fatal_error, warning
|
||||
use global
|
||||
use material_header, only: Material
|
||||
use material_header, only: Material, materials
|
||||
use math, only: rotate_angle
|
||||
use mgxs_header, only: Mgxs, MgxsContainer
|
||||
use mesh, only: get_mesh_indices
|
||||
use mesh_header, only: meshes
|
||||
use mgxs_header
|
||||
use message_passing
|
||||
use nuclide_header, only: material_xs
|
||||
use output, only: write_message
|
||||
use particle_header, only: Particle
|
||||
use particle_restart_write, only: write_particle_restart
|
||||
use physics_common
|
||||
use random_lcg, only: prn
|
||||
use scattdata_header
|
||||
use settings
|
||||
use simulation_header
|
||||
use string, only: to_str
|
||||
use tally_header
|
||||
|
||||
implicit none
|
||||
|
||||
|
|
@ -31,12 +35,6 @@ contains
|
|||
|
||||
type(Particle), intent(inout) :: p
|
||||
|
||||
! Store pre-collision particle properties
|
||||
p % last_wgt = p % wgt
|
||||
p % last_g = p % g
|
||||
p % last_E = p % E
|
||||
p % last_uvw = p % coord(1) % uvw
|
||||
|
||||
! Add to collision counter for particle
|
||||
p % n_collision = p % n_collision + 1
|
||||
|
||||
|
|
@ -177,12 +175,11 @@ contains
|
|||
integer :: dg ! delayed group
|
||||
integer :: gout ! group out
|
||||
integer :: nu ! actual number of neutrons produced
|
||||
integer :: ijk(3) ! indices in ufs mesh
|
||||
integer :: mesh_bin ! mesh bin for source site
|
||||
real(8) :: nu_t ! total nu
|
||||
real(8) :: mu ! fission neutron angular cosine
|
||||
real(8) :: phi ! fission neutron azimuthal angle
|
||||
real(8) :: weight ! weight adjustment for ufs method
|
||||
logical :: in_mesh ! source site in ufs mesh?
|
||||
class(Mgxs), pointer :: xs
|
||||
|
||||
! Get Pointers
|
||||
|
|
@ -194,20 +191,21 @@ contains
|
|||
! the expected number of fission sites produced
|
||||
|
||||
if (ufs) then
|
||||
associate (m => meshes(index_ufs_mesh))
|
||||
! Determine indices on ufs mesh for current location
|
||||
call m % get_bin(p % coord(1) % xyz, mesh_bin)
|
||||
|
||||
! Determine indices on ufs mesh for current location
|
||||
call get_mesh_indices(ufs_mesh, p % coord(1) % xyz, ijk, in_mesh)
|
||||
if (mesh_bin == NO_BIN_FOUND) then
|
||||
call write_particle_restart(p)
|
||||
call fatal_error("Source site outside UFS mesh!")
|
||||
end if
|
||||
|
||||
if (.not. in_mesh) then
|
||||
call write_particle_restart(p)
|
||||
call fatal_error("Source site outside UFS mesh!")
|
||||
end if
|
||||
|
||||
if (source_frac(1,ijk(1),ijk(2),ijk(3)) /= ZERO) then
|
||||
weight = ufs_mesh % volume_frac / source_frac(1,ijk(1),ijk(2),ijk(3))
|
||||
else
|
||||
weight = ONE
|
||||
end if
|
||||
if (source_frac(1, mesh_bin) /= ZERO) then
|
||||
weight = m % volume_frac / source_frac(1, mesh_bin)
|
||||
else
|
||||
weight = ONE
|
||||
end if
|
||||
end associate
|
||||
else
|
||||
weight = ONE
|
||||
end if
|
||||
|
|
|
|||
11
src/plot.F90
11
src/plot.F90
|
|
@ -7,15 +7,14 @@ module plot
|
|||
use constants
|
||||
use error, only: fatal_error
|
||||
use geometry, only: find_cell, check_cell_overlap
|
||||
use geometry_header, only: Cell, root_universe
|
||||
use global
|
||||
use geometry_header, only: Cell, root_universe, cells
|
||||
use hdf5_interface
|
||||
use mesh, only: get_mesh_indices
|
||||
use mesh_header, only: RegularMesh
|
||||
use output, only: write_message, time_stamp
|
||||
use material_header, only: materials
|
||||
use particle_header, only: LocalCoord, Particle
|
||||
use plot_header
|
||||
use progress_header, only: ProgressBar
|
||||
use settings, only: check_overlaps
|
||||
use string, only: to_str
|
||||
|
||||
implicit none
|
||||
|
|
@ -241,8 +240,8 @@ contains
|
|||
width = xyz_ur_plot - xyz_ll_plot
|
||||
|
||||
associate (m => pl % meshlines_mesh)
|
||||
call get_mesh_indices(m, xyz_ll_plot, ijk_ll(:m % n_dimension), in_mesh)
|
||||
call get_mesh_indices(m, xyz_ur_plot, ijk_ur(:m % n_dimension), in_mesh)
|
||||
call m % get_indices(xyz_ll_plot, ijk_ll(:m % n_dimension), in_mesh)
|
||||
call m % get_indices(xyz_ur_plot, ijk_ur(:m % n_dimension), in_mesh)
|
||||
|
||||
! sweep through all meshbins on this plane and draw borders
|
||||
do i = ijk_ll(outer), ijk_ur(outer)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
module plot_header
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use constants
|
||||
use mesh_header, only: RegularMesh
|
||||
use dict_header, only: DictIntInt
|
||||
use mesh_header, only: RegularMesh
|
||||
|
||||
implicit none
|
||||
|
||||
|
|
@ -50,4 +53,23 @@ module plot_header
|
|||
integer, parameter :: PLOT_COLOR_CELLS = 1
|
||||
integer, parameter :: PLOT_COLOR_MATS = 2
|
||||
|
||||
integer(C_INT32_T), bind(C) :: n_plots ! # of plots
|
||||
|
||||
type(ObjectPlot), allocatable, target :: plots(:)
|
||||
|
||||
! Dictionary that maps user IDs to indices in 'plots'
|
||||
type(DictIntInt) :: plot_dict
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! FREE_MEMORY_PLOT deallocates global arrays defined in this module
|
||||
!===============================================================================
|
||||
|
||||
subroutine free_memory_plot()
|
||||
n_plots = 0
|
||||
if (allocated(plots)) deallocate(plots)
|
||||
call plot_dict % clear()
|
||||
end subroutine free_memory_plot
|
||||
|
||||
end module plot_header
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
module random_lcg
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use constants
|
||||
|
||||
implicit none
|
||||
|
|
@ -7,28 +9,29 @@ module random_lcg
|
|||
private
|
||||
save
|
||||
|
||||
! Random number seed
|
||||
integer(8), public :: seed = 1_8
|
||||
! Starting seed
|
||||
integer(C_INT64_T), public, bind(C) :: seed = 1_8
|
||||
|
||||
integer(8) :: prn_seed0 ! original seed
|
||||
integer(8) :: prn_seed(N_STREAMS) ! current seed
|
||||
integer(8) :: prn_mult ! multiplication factor, g
|
||||
integer(8) :: prn_add ! additive factor, c
|
||||
integer :: prn_bits ! number of bits, M
|
||||
integer(8) :: prn_mod ! 2^M
|
||||
integer(8) :: prn_mask ! 2^M - 1
|
||||
integer(8) :: prn_stride ! stride between particles
|
||||
real(8) :: prn_norm ! 2^(-M)
|
||||
integer :: stream ! current RNG stream
|
||||
! LCG parameters
|
||||
integer(C_INT64_T), parameter :: prn_mult = 2806196910506780709_8 ! multiplication factor, g
|
||||
integer(C_INT64_T), parameter :: prn_add = 1_8 ! additive factor, c
|
||||
integer, parameter :: prn_bits = 63 ! number of bits, M
|
||||
integer(C_INT64_T), parameter :: prn_mod = ibset(0_8, prn_bits) ! 2^M
|
||||
integer(C_INT64_T), parameter :: prn_mask = not(prn_mod) ! 2^M - 1
|
||||
integer(C_INT64_T), parameter :: prn_stride = 152917_8 ! stride between particles
|
||||
real(C_DOUBLE), parameter :: prn_norm = 2._8**(-prn_bits) ! 2^(-M)
|
||||
|
||||
! Current PRNG state
|
||||
integer(C_INT64_T) :: prn_seed(N_STREAMS) ! current seed
|
||||
integer :: stream ! current RNG stream
|
||||
!$omp threadprivate(prn_seed, stream)
|
||||
|
||||
public :: prn
|
||||
public :: future_prn
|
||||
public :: initialize_prng
|
||||
public :: set_particle_seed
|
||||
public :: advance_prn_seed
|
||||
public :: prn_set_stream
|
||||
public :: openmc_set_seed
|
||||
|
||||
contains
|
||||
|
||||
|
|
@ -38,10 +41,10 @@ contains
|
|||
|
||||
function prn() result(pseudo_rn)
|
||||
|
||||
real(8) :: pseudo_rn
|
||||
real(C_DOUBLE) :: pseudo_rn
|
||||
|
||||
! This algorithm uses bit-masking to find the next integer(8) value to be
|
||||
! used to calculate the random number
|
||||
! This algorithm uses bit-masking to find the next integer(C_INT64_T) value
|
||||
! to be used to calculate the random number
|
||||
|
||||
prn_seed(stream) = iand(prn_mult*prn_seed(stream) + prn_add, prn_mask)
|
||||
|
||||
|
|
@ -59,40 +62,14 @@ contains
|
|||
|
||||
function future_prn(n) result(pseudo_rn)
|
||||
|
||||
integer(8), intent(in) :: n ! number of prns to skip
|
||||
integer(C_INT64_T), intent(in) :: n ! number of prns to skip
|
||||
|
||||
real(8) :: pseudo_rn
|
||||
real(C_DOUBLE) :: pseudo_rn
|
||||
|
||||
pseudo_rn = future_seed(n, prn_seed(stream)) * prn_norm
|
||||
|
||||
end function future_prn
|
||||
|
||||
!===============================================================================
|
||||
! INITIALIZE_PRNG sets up the random number generator, determining the seed and
|
||||
! values for g, c, and m.
|
||||
!===============================================================================
|
||||
|
||||
subroutine initialize_prng()
|
||||
|
||||
integer :: i
|
||||
|
||||
prn_seed0 = seed
|
||||
!$omp parallel
|
||||
do i = 1, N_STREAMS
|
||||
prn_seed(i) = prn_seed0 + i - 1
|
||||
end do
|
||||
stream = STREAM_TRACKING
|
||||
!$omp end parallel
|
||||
prn_mult = 2806196910506780709_8
|
||||
prn_add = 1_8
|
||||
prn_bits = 63
|
||||
prn_mod = ibset(0_8, prn_bits) ! clever way of calculating 2**bits
|
||||
prn_mask = prn_mod - 1_8
|
||||
prn_stride = 152917_8
|
||||
prn_norm = 2._8**(-prn_bits)
|
||||
|
||||
end subroutine initialize_prng
|
||||
|
||||
!===============================================================================
|
||||
! SET_PARTICLE_SEED sets the seed to a unique value based on the ID of the
|
||||
! particle
|
||||
|
|
@ -100,12 +77,12 @@ contains
|
|||
|
||||
subroutine set_particle_seed(id)
|
||||
|
||||
integer(8), intent(in) :: id
|
||||
integer(C_INT64_T), intent(in) :: id
|
||||
|
||||
integer :: i
|
||||
|
||||
do i = 1, N_STREAMS
|
||||
prn_seed(i) = future_seed(id*prn_stride, prn_seed0 + i - 1)
|
||||
prn_seed(i) = future_seed(id*prn_stride, seed + i - 1)
|
||||
end do
|
||||
|
||||
end subroutine set_particle_seed
|
||||
|
|
@ -117,7 +94,7 @@ contains
|
|||
|
||||
subroutine advance_prn_seed(n)
|
||||
|
||||
integer(8), intent(in) :: n ! number of seeds to skip
|
||||
integer(C_INT64_T), intent(in) :: n ! number of seeds to skip
|
||||
|
||||
prn_seed(stream) = future_seed(n, prn_seed(stream))
|
||||
|
||||
|
|
@ -132,15 +109,15 @@ contains
|
|||
|
||||
function future_seed(n, seed) result(new_seed)
|
||||
|
||||
integer(8), intent(in) :: n ! number of seeds to skip
|
||||
integer(8), intent(in) :: seed ! original seed
|
||||
integer(8) :: new_seed ! new seed
|
||||
integer(C_INT64_T), intent(in) :: n ! number of seeds to skip
|
||||
integer(C_INT64_T), intent(in) :: seed ! original seed
|
||||
integer(C_INT64_T) :: new_seed ! new seed
|
||||
|
||||
integer(8) :: nskip ! positive number of seeds to skip
|
||||
integer(8) :: g ! original multiplicative constant
|
||||
integer(8) :: c ! original additive constnat
|
||||
integer(8) :: g_new ! new effective multiplicative constant
|
||||
integer(8) :: c_new ! new effective additive constant
|
||||
integer(C_INT64_T) :: nskip ! positive number of seeds to skip
|
||||
integer(C_INT64_T) :: g ! original multiplicative constant
|
||||
integer(C_INT64_T) :: c ! original additive constnat
|
||||
integer(C_INT64_T) :: g_new ! new effective multiplicative constant
|
||||
integer(C_INT64_T) :: c_new ! new effective additive constant
|
||||
|
||||
! In cases where we want to skip backwards, we add the period of the random
|
||||
! number generator until the number of PRNs to skip is positive since
|
||||
|
|
@ -198,4 +175,26 @@ contains
|
|||
|
||||
end subroutine prn_set_stream
|
||||
|
||||
!===============================================================================
|
||||
! C API FUNCTIONS
|
||||
!===============================================================================
|
||||
|
||||
function openmc_set_seed(new_seed) result(err) bind(C)
|
||||
! Saves the starting seed and sets up the PRNG thread state
|
||||
integer(C_INT64_T), value, intent(in) :: new_seed
|
||||
integer(C_INT) :: err
|
||||
|
||||
integer :: i
|
||||
|
||||
err = 0
|
||||
seed = new_seed
|
||||
!$omp parallel
|
||||
do i = 1, N_STREAMS
|
||||
prn_seed(i) = seed + i - 1
|
||||
end do
|
||||
stream = STREAM_TRACKING
|
||||
!$omp end parallel
|
||||
|
||||
end function openmc_set_seed
|
||||
|
||||
end module random_lcg
|
||||
|
|
|
|||
|
|
@ -12,14 +12,7 @@ element settings {
|
|||
|
||||
element energy_mode { ( "continuous-energy" | "ce" | "CE" | "multi-group" | "mg" | "MG" ) }? &
|
||||
|
||||
element entropy {
|
||||
(element dimension { list { xsd:int+ } } |
|
||||
attribute dimension { list { xsd:int+ } })? &
|
||||
(element lower_left { list { xsd:double+ } } |
|
||||
attribute lower_left { list { xsd:double+ } }) &
|
||||
(element upper_right { list { xsd:double+ } } |
|
||||
attribute upper_right { list { xsd:double+ } })
|
||||
}? &
|
||||
element entropy_mesh { xsd:positiveInteger }? &
|
||||
|
||||
element generations_per_batch { xsd:positiveInteger }? &
|
||||
|
||||
|
|
@ -34,6 +27,22 @@ element settings {
|
|||
|
||||
element max_order { xsd:nonNegativeInteger }? &
|
||||
|
||||
element mesh {
|
||||
(element id { xsd:int } | attribute id { xsd:int }) &
|
||||
(element type { ( "regular" ) } |
|
||||
attribute type { ( "regular" ) })? &
|
||||
(element dimension { list { xsd:positiveInteger+ } } |
|
||||
attribute dimension { list { xsd:positiveInteger+ } }) &
|
||||
(element lower_left { list { xsd:double+ } } |
|
||||
attribute lower_left { list { xsd:double+ } }) &
|
||||
(
|
||||
(element upper_right { list { xsd:double+ } } |
|
||||
attribute upper_right { list { xsd:double+ } }) |
|
||||
(element width { list { xsd:double+ } } |
|
||||
attribute width { list { xsd:double+ } })
|
||||
)
|
||||
}* &
|
||||
|
||||
element no_reduce { xsd:boolean }? &
|
||||
|
||||
element output {
|
||||
|
|
@ -133,6 +142,8 @@ element settings {
|
|||
(element batch_interval { xsd:positiveInteger } | attribute batch_interval { xsd:positiveInteger })?
|
||||
}? &
|
||||
|
||||
element ufs_mesh { xsd:positiveInteger }? &
|
||||
|
||||
element verbosity { xsd:positiveInteger }? &
|
||||
|
||||
element volume_calc {
|
||||
|
|
@ -148,15 +159,6 @@ element settings {
|
|||
attribute upper_right { list { xsd:double+ } })
|
||||
}* &
|
||||
|
||||
element uniform_fs{
|
||||
(element dimension { list { xsd:positiveInteger+ } } |
|
||||
attribute dimension { list { xsd:positiveInteger+ } }) &
|
||||
(element lower_left { list { xsd:double+ } } |
|
||||
attribute lower_left { list { xsd:double+ } }) &
|
||||
(element upper_right { list { xsd:double+ } } |
|
||||
attribute upper_right { list { xsd:double+ } })
|
||||
}? &
|
||||
|
||||
element resonance_scattering {
|
||||
(element enable { xsd:boolean } | attribute enable { xsd:boolean })? &
|
||||
(element method { xsd:string } | attribute method { xsd:string })? &
|
||||
|
|
|
|||
|
|
@ -62,59 +62,8 @@
|
|||
</element>
|
||||
</optional>
|
||||
<optional>
|
||||
<element name="entropy">
|
||||
<interleave>
|
||||
<optional>
|
||||
<choice>
|
||||
<element name="dimension">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="int"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</element>
|
||||
<attribute name="dimension">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="int"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</attribute>
|
||||
</choice>
|
||||
</optional>
|
||||
<choice>
|
||||
<element name="lower_left">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="double"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</element>
|
||||
<attribute name="lower_left">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="double"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</attribute>
|
||||
</choice>
|
||||
<choice>
|
||||
<element name="upper_right">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="double"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</element>
|
||||
<attribute name="upper_right">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="double"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</attribute>
|
||||
</choice>
|
||||
</interleave>
|
||||
<element name="entropy_mesh">
|
||||
<data type="positiveInteger"/>
|
||||
</element>
|
||||
</optional>
|
||||
<optional>
|
||||
|
|
@ -159,6 +108,96 @@
|
|||
<data type="nonNegativeInteger"/>
|
||||
</element>
|
||||
</optional>
|
||||
<zeroOrMore>
|
||||
<element name="mesh">
|
||||
<interleave>
|
||||
<choice>
|
||||
<element name="id">
|
||||
<data type="int"/>
|
||||
</element>
|
||||
<attribute name="id">
|
||||
<data type="int"/>
|
||||
</attribute>
|
||||
</choice>
|
||||
<optional>
|
||||
<choice>
|
||||
<element name="type">
|
||||
<value>regular</value>
|
||||
</element>
|
||||
<attribute name="type">
|
||||
<value>regular</value>
|
||||
</attribute>
|
||||
</choice>
|
||||
</optional>
|
||||
<choice>
|
||||
<element name="dimension">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="positiveInteger"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</element>
|
||||
<attribute name="dimension">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="positiveInteger"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</attribute>
|
||||
</choice>
|
||||
<choice>
|
||||
<element name="lower_left">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="double"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</element>
|
||||
<attribute name="lower_left">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="double"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</attribute>
|
||||
</choice>
|
||||
<choice>
|
||||
<choice>
|
||||
<element name="upper_right">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="double"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</element>
|
||||
<attribute name="upper_right">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="double"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</attribute>
|
||||
</choice>
|
||||
<choice>
|
||||
<element name="width">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="double"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</element>
|
||||
<attribute name="width">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="double"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</attribute>
|
||||
</choice>
|
||||
</choice>
|
||||
</interleave>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
<optional>
|
||||
<element name="no_reduce">
|
||||
<data type="boolean"/>
|
||||
|
|
@ -595,6 +634,11 @@
|
|||
</interleave>
|
||||
</element>
|
||||
</optional>
|
||||
<optional>
|
||||
<element name="ufs_mesh">
|
||||
<data type="positiveInteger"/>
|
||||
</element>
|
||||
</optional>
|
||||
<optional>
|
||||
<element name="verbosity">
|
||||
<data type="positiveInteger"/>
|
||||
|
|
@ -670,60 +714,6 @@
|
|||
</interleave>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
<optional>
|
||||
<element name="uniform_fs">
|
||||
<interleave>
|
||||
<choice>
|
||||
<element name="dimension">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="positiveInteger"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</element>
|
||||
<attribute name="dimension">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="positiveInteger"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</attribute>
|
||||
</choice>
|
||||
<choice>
|
||||
<element name="lower_left">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="double"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</element>
|
||||
<attribute name="lower_left">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="double"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</attribute>
|
||||
</choice>
|
||||
<choice>
|
||||
<element name="upper_right">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="double"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</element>
|
||||
<attribute name="upper_right">
|
||||
<list>
|
||||
<oneOrMore>
|
||||
<data type="double"/>
|
||||
</oneOrMore>
|
||||
</list>
|
||||
</attribute>
|
||||
</choice>
|
||||
</interleave>
|
||||
</element>
|
||||
</optional>
|
||||
<optional>
|
||||
<element name="resonance_scattering">
|
||||
<interleave>
|
||||
|
|
|
|||
|
|
@ -35,12 +35,14 @@ element tallies {
|
|||
element filter {
|
||||
(element id { xsd:int } | attribute id { xsd:int }) &
|
||||
(
|
||||
( (element type { ( "cell" | "cellborn" | "material" | "universe" |
|
||||
"surface" | "distribcell" | "mesh" | "energy" | "energyout" | "mu" |
|
||||
"polar" | "azimuthal" | "delayedgroup" | "energyfunction") } |
|
||||
attribute type { ( "cell" | "cellborn" | "material" | "universe" |
|
||||
"surface" | "distribcell" | "mesh" | "energy" | "energyout" | "mu" |
|
||||
"polar" | "azimuthal" | "delayedgroup" | "energyfunction") }) &
|
||||
( (element type { ( "cell" | "cellfrom" | "cellborn" | "material" |
|
||||
"universe" | "surface" | "distribcell" | "mesh" | "energy" |
|
||||
"energyout" | "mu" | "polar" | "azimuthal" | "delayedgroup" |
|
||||
"energyfunction") } |
|
||||
attribute type { ( "cell" | "cellfrom" | "cellborn" | "material" |
|
||||
"universe" | "surface" | "distribcell" | "mesh" | "energy" |
|
||||
"energyout" | "mu" | "polar" | "azimuthal" | "delayedgroup" |
|
||||
"energyfunction") }) &
|
||||
(element bins { list { xsd:double+ } } |
|
||||
attribute bins { list { xsd:double+ } })
|
||||
) |
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@
|
|||
<element name="type">
|
||||
<choice>
|
||||
<value>cell</value>
|
||||
<value>cellfrom</value>
|
||||
<value>cellborn</value>
|
||||
<value>material</value>
|
||||
<value>universe</value>
|
||||
|
|
@ -186,6 +187,7 @@
|
|||
<attribute name="type">
|
||||
<choice>
|
||||
<value>cell</value>
|
||||
<value>cellfrom</value>
|
||||
<value>cellborn</value>
|
||||
<value>material</value>
|
||||
<value>universe</value>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
module sab_header
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
use, intrinsic :: ISO_FORTRAN_ENV
|
||||
|
||||
use algorithm, only: find, sort
|
||||
use constants
|
||||
use dict_header, only: DictIntInt
|
||||
use dict_header, only: DictIntInt, DictCharInt
|
||||
use distribution_univariate, only: Tabular
|
||||
use error, only: warning, fatal_error
|
||||
use hdf5, only: HID_T, HSIZE_T, SIZE_T
|
||||
|
|
@ -78,6 +79,11 @@ module sab_header
|
|||
procedure :: from_hdf5 => salphabeta_from_hdf5
|
||||
end type SAlphaBeta
|
||||
|
||||
! S(a,b) tables
|
||||
type(SAlphaBeta), allocatable, target :: sab_tables(:)
|
||||
integer(C_INT), bind(C) :: n_sab_tables
|
||||
type(DictCharInt) :: sab_dict
|
||||
|
||||
contains
|
||||
|
||||
subroutine salphabeta_from_hdf5(this, group_id, temperature, method, &
|
||||
|
|
@ -354,4 +360,14 @@ contains
|
|||
call close_group(kT_group)
|
||||
end subroutine salphabeta_from_hdf5
|
||||
|
||||
!===============================================================================
|
||||
! FREE_MEMORY_SAB deallocates global arrays defined in this module
|
||||
!===============================================================================
|
||||
|
||||
subroutine free_memory_sab()
|
||||
n_sab_tables = 0
|
||||
if (allocated(sab_tables)) deallocate(sab_tables)
|
||||
call sab_dict % clear()
|
||||
end subroutine free_memory_sab
|
||||
|
||||
end module sab_header
|
||||
|
|
|
|||
158
src/settings.F90
Normal file
158
src/settings.F90
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
module settings
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use constants
|
||||
use set_header, only: SetInt
|
||||
|
||||
implicit none
|
||||
|
||||
! ============================================================================
|
||||
! ENERGY TREATMENT RELATED VARIABLES
|
||||
logical :: run_CE = .true. ! Run in CE mode?
|
||||
|
||||
! ============================================================================
|
||||
! CONTINUOUS-ENERGY CROSS SECTION RELATED VARIABLES
|
||||
|
||||
! Unreoslved resonance probablity tables
|
||||
logical :: urr_ptables_on = .true.
|
||||
|
||||
! Default temperature and method for choosing temperatures
|
||||
integer :: temperature_method = TEMPERATURE_NEAREST
|
||||
logical :: temperature_multipole = .false.
|
||||
real(8) :: temperature_tolerance = 10.0_8
|
||||
real(8) :: temperature_default = 293.6_8
|
||||
real(8) :: temperature_range(2) = [ZERO, ZERO]
|
||||
|
||||
integer :: n_log_bins ! number of bins for logarithmic grid
|
||||
|
||||
logical :: photon_transport = .false.
|
||||
integer :: electron_treatment = ELECTRON_LED
|
||||
|
||||
! ============================================================================
|
||||
! MULTI-GROUP CROSS SECTION RELATED VARIABLES
|
||||
|
||||
! Maximum Data Order
|
||||
integer :: max_order
|
||||
|
||||
! Whether or not to convert Legendres to tabulars
|
||||
logical :: legendre_to_tabular = .true.
|
||||
|
||||
! Number of points to use in the Legendre to tabular conversion
|
||||
integer :: legendre_to_tabular_points = 33
|
||||
|
||||
! Assume all tallies are spatially distinct
|
||||
logical :: assume_separate = .false.
|
||||
|
||||
! Use confidence intervals for results instead of standard deviations
|
||||
logical :: confidence_intervals = .false.
|
||||
|
||||
! ============================================================================
|
||||
! SIMULATION VARIABLES
|
||||
|
||||
integer(C_INT64_T), bind(C) :: n_particles = 0 ! # of particles per generation
|
||||
integer(C_INT32_T), bind(C) :: n_batches ! # of batches
|
||||
integer(C_INT32_T), bind(C) :: n_inactive ! # of inactive batches
|
||||
integer(C_INT32_T), bind(C) :: gen_per_batch = 1 ! # of generations per batch
|
||||
|
||||
integer :: n_max_batches ! max # of batches
|
||||
integer :: n_batch_interval = 1 ! batch interval for triggers
|
||||
logical :: pred_batches = .false. ! predict batches for triggers
|
||||
logical :: trigger_on = .false. ! flag for turning triggers on/off
|
||||
|
||||
logical :: entropy_on = .false.
|
||||
integer :: index_entropy_mesh = -1
|
||||
|
||||
logical :: ufs = .false.
|
||||
integer :: index_ufs_mesh = -1
|
||||
|
||||
! Write source at end of simulation
|
||||
logical :: source_separate = .false.
|
||||
logical :: source_write = .true.
|
||||
logical :: source_latest = .false.
|
||||
|
||||
! Variance reduction settins
|
||||
logical :: survival_biasing = .false.
|
||||
real(8) :: weight_cutoff = 0.25_8
|
||||
real(8) :: energy_cutoff(4) = [ZERO, 1000.0_8, ZERO, ZERO]
|
||||
real(8) :: weight_survive = ONE
|
||||
|
||||
! Mode to run in (fixed source, eigenvalue, plotting, etc)
|
||||
integer(C_INT), bind(C) :: run_mode = NONE
|
||||
|
||||
! Restart run
|
||||
logical :: restart_run = .false.
|
||||
|
||||
! The verbosity controls how much information will be printed to the screen
|
||||
! and in logs
|
||||
integer(C_INT), bind(C) :: verbosity = 7
|
||||
|
||||
logical :: check_overlaps = .false.
|
||||
|
||||
! Trace for single particle
|
||||
integer :: trace_batch
|
||||
integer :: trace_gen
|
||||
integer(8) :: trace_particle
|
||||
|
||||
! Particle tracks
|
||||
logical :: write_all_tracks = .false.
|
||||
integer, allocatable :: track_identifiers(:,:)
|
||||
|
||||
! Particle restart run
|
||||
logical :: particle_restart_run = .false.
|
||||
|
||||
! Write out initial source
|
||||
logical :: write_initial_source = .false.
|
||||
|
||||
! Whether create fission neutrons or not. Only applied for MODE_FIXEDSOURCE
|
||||
logical :: create_fission_neutrons = .true.
|
||||
|
||||
! Information about state points to be written
|
||||
integer :: n_state_points = 0
|
||||
type(SetInt) :: statepoint_batch
|
||||
|
||||
! Information about source points to be written
|
||||
integer :: n_source_points = 0
|
||||
type(SetInt) :: sourcepoint_batch
|
||||
|
||||
character(MAX_FILE_LEN) :: path_input ! Path to input file
|
||||
character(MAX_FILE_LEN) :: path_cross_sections = '' ! Path to cross_sections.xml
|
||||
character(MAX_FILE_LEN) :: path_multipole ! Path to wmp library
|
||||
character(MAX_FILE_LEN) :: path_source = '' ! Path to binary source
|
||||
character(MAX_FILE_LEN) :: path_state_point ! Path to binary state point
|
||||
character(MAX_FILE_LEN) :: path_source_point ! Path to binary source point
|
||||
character(MAX_FILE_LEN) :: path_particle_restart ! Path to particle restart
|
||||
character(MAX_FILE_LEN) :: path_output = '' ! Path to output directory
|
||||
|
||||
! Various output options
|
||||
logical :: output_summary = .true.
|
||||
logical :: output_tallies = .true.
|
||||
|
||||
! Resonance scattering settings
|
||||
logical :: res_scat_on = .false. ! is resonance scattering treated?
|
||||
integer :: res_scat_method = RES_SCAT_ARES ! resonance scattering method
|
||||
real(8) :: res_scat_energy_min = 0.01_8
|
||||
real(8) :: res_scat_energy_max = 1000.0_8
|
||||
character(10), allocatable :: res_scat_nuclides(:)
|
||||
|
||||
! Is CMFD active
|
||||
logical :: cmfd_run = .false.
|
||||
|
||||
! No reduction at end of batch
|
||||
logical :: reduce_tallies = .true.
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! FREE_MEMORY_SETTINGS deallocates global arrays defined in this module
|
||||
!===============================================================================
|
||||
|
||||
subroutine free_memory_settings()
|
||||
if (allocated(res_scat_nuclides)) deallocate(res_scat_nuclides)
|
||||
if (allocated(track_identifiers)) deallocate(track_identifiers)
|
||||
|
||||
call statepoint_batch % clear()
|
||||
call sourcepoint_batch % clear()
|
||||
end subroutine free_memory_settings
|
||||
|
||||
end module settings
|
||||
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