mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 22:26:08 -04:00
Updating local branch with latest commits in develop.
Merge branch 'develop' of https://github.com/mit-crpg/openmc into fix-init-args-capi
This commit is contained in:
commit
cd0e9667f4
84 changed files with 6329 additions and 5295 deletions
184
CMakeLists.txt
184
CMakeLists.txt
|
|
@ -1,4 +1,4 @@
|
|||
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
|
||||
cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
|
||||
project(openmc Fortran C CXX)
|
||||
|
||||
# Setup output directories
|
||||
|
|
@ -9,14 +9,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
|||
# Set module path
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)
|
||||
|
||||
#===============================================================================
|
||||
# Architecture specific definitions
|
||||
#===============================================================================
|
||||
|
||||
if (${UNIX})
|
||||
add_definitions(-DUNIX)
|
||||
endif()
|
||||
|
||||
#===============================================================================
|
||||
# Command line options
|
||||
#===============================================================================
|
||||
|
|
@ -27,10 +19,7 @@ option(debug "Compile with debug flags" OFF)
|
|||
option(optimize "Turn on all compiler optimization flags" OFF)
|
||||
option(coverage "Compile with coverage analysis flags" OFF)
|
||||
option(mpif08 "Use Fortran 2008 MPI interface" OFF)
|
||||
|
||||
# Maximum number of nested coordinates levels
|
||||
set(maxcoord 10 CACHE STRING "Maximum number of nested coordinate levels")
|
||||
add_definitions(-DMAX_COORD=${maxcoord})
|
||||
|
||||
#===============================================================================
|
||||
# MPI for distributed-memory parallelism
|
||||
|
|
@ -39,17 +28,12 @@ add_definitions(-DMAX_COORD=${maxcoord})
|
|||
set(MPI_ENABLED FALSE)
|
||||
if($ENV{FC} MATCHES "(mpi[^/]*|ftn)$")
|
||||
message("-- Detected MPI wrapper: $ENV{FC}")
|
||||
add_definitions(-DOPENMC_MPI)
|
||||
set(MPI_ENABLED TRUE)
|
||||
|
||||
# Get directory containing MPI wrapper
|
||||
get_filename_component(MPI_DIR $ENV{FC} DIRECTORY)
|
||||
endif()
|
||||
|
||||
# Check for Fortran 2008 MPI interface
|
||||
if(MPI_ENABLED AND mpif08)
|
||||
message("-- Using Fortran 2008 MPI bindings")
|
||||
add_definitions(-DOPENMC_MPIF08)
|
||||
endif()
|
||||
|
||||
#===============================================================================
|
||||
|
|
@ -77,7 +61,6 @@ if(HDF5_IS_PARALLEL)
|
|||
if(NOT MPI_ENABLED)
|
||||
message(FATAL_ERROR "Parallel HDF5 must be used with MPI.")
|
||||
endif()
|
||||
add_definitions(-DPHDF5)
|
||||
message("-- Using parallel HDF5")
|
||||
endif()
|
||||
|
||||
|
|
@ -85,19 +68,15 @@ endif()
|
|||
# Set compile/link flags based on which compiler is being used
|
||||
#===============================================================================
|
||||
|
||||
# Support for Fortran in FindOpenMP was added in CMake 3.1. To support lower
|
||||
# versions, we manually add the flags. However, at some point in time, the
|
||||
# manual logic can be removed in favor of the block below
|
||||
|
||||
#if(NOT (CMAKE_VERSION VERSION_LESS 3.1))
|
||||
# if(openmp)
|
||||
# find_package(OpenMP)
|
||||
# if(OPENMP_FOUND)
|
||||
# list(APPEND f90flags ${OpenMP_Fortran_FLAGS})
|
||||
# list(APPEND ldflags ${OpenMP_Fortran_FLAGS})
|
||||
# endif()
|
||||
# endif()
|
||||
#endif()
|
||||
if(openmp)
|
||||
# Requires CMake 3.1+
|
||||
find_package(OpenMP)
|
||||
if(OPENMP_FOUND)
|
||||
list(APPEND f90flags ${OpenMP_Fortran_FLAGS})
|
||||
list(APPEND cxxflags ${OpenMP_CXX_FLAGS})
|
||||
list(APPEND ldflags ${OpenMP_Fortran_FLAGS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
|
|
@ -125,10 +104,6 @@ if(CMAKE_Fortran_COMPILER_ID STREQUAL GNU)
|
|||
list(REMOVE_ITEM f90flags -O2)
|
||||
list(APPEND f90flags -O3)
|
||||
endif()
|
||||
if(openmp)
|
||||
list(APPEND f90flags -fopenmp)
|
||||
list(APPEND ldflags -fopenmp)
|
||||
endif()
|
||||
if(coverage)
|
||||
list(APPEND f90flags -coverage)
|
||||
list(APPEND ldflags -coverage)
|
||||
|
|
@ -149,10 +124,6 @@ elseif(CMAKE_Fortran_COMPILER_ID STREQUAL Intel)
|
|||
if(optimize)
|
||||
list(APPEND f90flags -O3)
|
||||
endif()
|
||||
if(openmp)
|
||||
list(APPEND f90flags -qopenmp)
|
||||
list(APPEND ldflags -qopenmp)
|
||||
endif()
|
||||
|
||||
elseif(CMAKE_Fortran_COMPILER_ID STREQUAL PGI)
|
||||
# PGI Fortran compiler options
|
||||
|
|
@ -187,10 +158,6 @@ elseif(CMAKE_Fortran_COMPILER_ID STREQUAL XL)
|
|||
list(REMOVE_ITEM f90flags -O2)
|
||||
list(APPEND f90flags -O3)
|
||||
endif()
|
||||
if(openmp)
|
||||
list(APPEND f90flags -qsmp=omp)
|
||||
list(APPEND ldflags -qsmp=omp)
|
||||
endif()
|
||||
|
||||
elseif(CMAKE_Fortran_COMPILER_ID STREQUAL Cray)
|
||||
# Cray Fortran compiler options
|
||||
|
|
@ -204,7 +171,7 @@ endif()
|
|||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL GNU)
|
||||
# GCC compiler options
|
||||
list(APPEND cflags -std=c99 -O2)
|
||||
list(APPEND cflags -O2)
|
||||
if(debug)
|
||||
list(REMOVE_ITEM cflags -O2)
|
||||
list(APPEND cflags -g -Wall -pedantic -fbounds-check)
|
||||
|
|
@ -222,7 +189,6 @@ if(CMAKE_C_COMPILER_ID STREQUAL GNU)
|
|||
|
||||
elseif(CMAKE_C_COMPILER_ID STREQUAL Intel)
|
||||
# Intel compiler options
|
||||
list(APPEND cflags -std=c99)
|
||||
if(debug)
|
||||
list(APPEND cflags -g -w3 -ftrapuv -fp-stack-check -O0)
|
||||
endif()
|
||||
|
|
@ -235,7 +201,6 @@ elseif(CMAKE_C_COMPILER_ID STREQUAL Intel)
|
|||
|
||||
elseif(CMAKE_C_COMPILER_ID MATCHES Clang)
|
||||
# Clang options
|
||||
list(APPEND cflags -std=c99)
|
||||
if(debug)
|
||||
list(APPEND cflags -g -O0 -ftrapv)
|
||||
endif()
|
||||
|
|
@ -257,9 +222,6 @@ if(optimize)
|
|||
list(REMOVE_ITEM cxxflags -O2)
|
||||
list(APPEND cxxflags -O3)
|
||||
endif()
|
||||
if(openmp)
|
||||
list(APPEND cxxflags -fopenmp)
|
||||
endif()
|
||||
|
||||
# Show flags being used
|
||||
message(STATUS "Fortran flags: ${f90flags}")
|
||||
|
|
@ -267,26 +229,12 @@ message(STATUS "C flags: ${cflags}")
|
|||
message(STATUS "C++ flags: ${cxxflags}")
|
||||
message(STATUS "Linker flags: ${ldflags}")
|
||||
|
||||
#===============================================================================
|
||||
# git SHA1 hash
|
||||
#===============================================================================
|
||||
|
||||
execute_process(COMMAND git rev-parse HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
RESULT_VARIABLE GIT_SHA1_SUCCESS
|
||||
OUTPUT_VARIABLE GIT_SHA1
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(GIT_SHA1_SUCCESS EQUAL 0)
|
||||
add_definitions(-DGIT_SHA1="${GIT_SHA1}")
|
||||
endif()
|
||||
|
||||
#===============================================================================
|
||||
# pugixml library
|
||||
#===============================================================================
|
||||
|
||||
add_library(pugixml src/pugixml/pugixml_c.cpp src/pugixml/pugixml.cpp)
|
||||
add_library(pugixml_fortran src/pugixml/pugixml_f.F90)
|
||||
target_link_libraries(pugixml_fortran pugixml)
|
||||
add_library(pugixml vendor/pugixml/pugixml.cpp)
|
||||
target_include_directories(pugixml PUBLIC vendor/pugixml/)
|
||||
|
||||
#===============================================================================
|
||||
# RPATH information
|
||||
|
|
@ -295,7 +243,7 @@ target_link_libraries(pugixml_fortran pugixml)
|
|||
# This block of code ensures that dynamic libraries can be found via the RPATH
|
||||
# whether the executable is the original one from the build directory or the
|
||||
# installed one in CMAKE_INSTALL_PREFIX. Ref:
|
||||
# https://cmake.org/Wiki/CMake_RPATH_handling#Always_full_RPATH
|
||||
# https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/RPATH-handling
|
||||
|
||||
# use, i.e. don't skip the full RPATH for the build tree
|
||||
set(CMAKE_SKIP_BUILD_RPATH FALSE)
|
||||
|
|
@ -317,17 +265,20 @@ if("${isSystemDir}" STREQUAL "-1")
|
|||
endif()
|
||||
|
||||
#===============================================================================
|
||||
# Build faddeeva library
|
||||
# faddeeva library
|
||||
#===============================================================================
|
||||
|
||||
add_library(faddeeva STATIC src/faddeeva/Faddeeva.c)
|
||||
add_library(faddeeva STATIC vendor/faddeeva/Faddeeva.c)
|
||||
target_compile_options(faddeeva PRIVATE ${cflags})
|
||||
set_target_properties(faddeeva PROPERTIES
|
||||
C_STANDARD 99
|
||||
C_STANDARD_REQUIRED ON)
|
||||
|
||||
#===============================================================================
|
||||
# List source files. Define the libopenmc and the OpenMC executable
|
||||
# libopenmc
|
||||
#===============================================================================
|
||||
|
||||
set(program "openmc")
|
||||
set(LIBOPENMC_FORTRAN_SRC
|
||||
add_library(libopenmc SHARED
|
||||
src/algorithm.F90
|
||||
src/angle_distribution.F90
|
||||
src/angleenergy_header.F90
|
||||
|
|
@ -344,7 +295,6 @@ set(LIBOPENMC_FORTRAN_SRC
|
|||
src/dict_header.F90
|
||||
src/distribution_multivariate.F90
|
||||
src/distribution_univariate.F90
|
||||
src/doppler.F90
|
||||
src/eigenvalue.F90
|
||||
src/endf.F90
|
||||
src/endf_header.F90
|
||||
|
|
@ -363,7 +313,7 @@ set(LIBOPENMC_FORTRAN_SRC
|
|||
src/mesh_header.F90
|
||||
src/message_passing.F90
|
||||
src/mgxs_data.F90
|
||||
src/mgxs_header.F90
|
||||
src/mgxs_interface.F90
|
||||
src/multipole_header.F90
|
||||
src/nuclide_header.F90
|
||||
src/output.F90
|
||||
|
|
@ -376,11 +326,11 @@ set(LIBOPENMC_FORTRAN_SRC
|
|||
src/plot_header.F90
|
||||
src/product_header.F90
|
||||
src/progress_header.F90
|
||||
src/pugixml/pugixml_f.F90
|
||||
src/random_lcg.F90
|
||||
src/reaction_header.F90
|
||||
src/relaxng
|
||||
src/sab_header.F90
|
||||
src/scattdata_header.F90
|
||||
src/secondary_correlated.F90
|
||||
src/secondary_kalbach.F90
|
||||
src/secondary_nbody.F90
|
||||
|
|
@ -430,8 +380,6 @@ set(LIBOPENMC_FORTRAN_SRC
|
|||
src/tallies/tally_header.F90
|
||||
src/tallies/trigger.F90
|
||||
src/tallies/trigger_header.F90
|
||||
)
|
||||
set(LIBOPENMC_CXX_SRC
|
||||
src/cell.cpp
|
||||
src/initialize.cpp
|
||||
src/finalize.cpp
|
||||
|
|
@ -440,53 +388,71 @@ set(LIBOPENMC_CXX_SRC
|
|||
src/lattice.cpp
|
||||
src/math_functions.cpp
|
||||
src/message_passing.cpp
|
||||
src/mgxs.cpp
|
||||
src/mgxs_interface.cpp
|
||||
src/plot.cpp
|
||||
src/pugixml/pugixml_c.cpp
|
||||
src/random_lcg.cpp
|
||||
src/scattdata.cpp
|
||||
src/simulation.cpp
|
||||
src/state_point.cpp
|
||||
src/string_functions.cpp
|
||||
src/surface.cpp
|
||||
src/xml_interface.cpp
|
||||
src/pugixml/pugixml.cpp)
|
||||
add_library(libopenmc SHARED ${LIBOPENMC_FORTRAN_SRC} ${LIBOPENMC_CXX_SRC})
|
||||
src/xsdata.cpp)
|
||||
set_target_properties(libopenmc PROPERTIES
|
||||
OUTPUT_NAME openmc
|
||||
PUBLIC_HEADER include/openmc.h)
|
||||
add_executable(${program} src/main.cpp)
|
||||
PUBLIC_HEADER include/openmc.h
|
||||
LINKER_LANGUAGE Fortran)
|
||||
|
||||
#===============================================================================
|
||||
# Add compiler/linker flags
|
||||
#===============================================================================
|
||||
|
||||
set_property(TARGET ${program} libopenmc pugixml_fortran
|
||||
PROPERTY LINKER_LANGUAGE Fortran)
|
||||
|
||||
target_include_directories(libopenmc PUBLIC include ${HDF5_INCLUDE_DIRS})
|
||||
|
||||
# The executable and the faddeeva package use only one language. They can be
|
||||
# set via target_compile_options which accepts a list.
|
||||
target_compile_options(${program} PUBLIC ${cxxflags})
|
||||
target_compile_options(faddeeva PRIVATE ${cflags})
|
||||
target_include_directories(libopenmc
|
||||
PUBLIC include
|
||||
PRIVATE ${HDF5_INCLUDE_DIRS})
|
||||
|
||||
# The libopenmc library has both F90 and C++ so the compile flags must be set
|
||||
# file-by-file via set_source_file_properties. The compile flags must first be
|
||||
# converted from lists to strings.
|
||||
string(REPLACE ";" " " f90flags "${f90flags}")
|
||||
string(REPLACE ";" " " cxxflags "${cxxflags}")
|
||||
set_source_files_properties(${LIBOPENMC_FORTRAN_SRC} PROPERTIES COMPILE_FLAGS
|
||||
${f90flags})
|
||||
set_source_files_properties(${LIBOPENMC_CXX_SRC} PROPERTIES COMPILE_FLAGS
|
||||
${cxxflags})
|
||||
# differently depending on the language. The $<COMPILE_LANGUAGE> generator
|
||||
# expression was added in CMake 3.3
|
||||
target_compile_options(libopenmc PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:Fortran>:${f90flags}>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:${cxxflags}>)
|
||||
|
||||
# Add HDF5 library directories to link line with -L
|
||||
foreach(LIBDIR ${HDF5_LIBRARY_DIRS})
|
||||
list(APPEND ldflags "-L${LIBDIR}")
|
||||
endforeach()
|
||||
target_compile_definitions(libopenmc PRIVATE -DMAX_COORD=${maxcoord})
|
||||
if (UNIX)
|
||||
# Used in progress_header.F90 for calling check_isatty
|
||||
target_compile_definitions(libopenmc PRIVATE -DUNIX)
|
||||
endif()
|
||||
if (HDF5_IS_PARALLEL)
|
||||
target_compile_definitions(libopenmc PRIVATE -DPHDF5)
|
||||
endif()
|
||||
if (MPI_ENABLED)
|
||||
target_compile_definitions(libopenmc PUBLIC -DOPENMC_MPI)
|
||||
if (mpif08)
|
||||
target_compile_definitions(libopenmc PRIVATE -DOPENMC_MPIF08)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Set git SHA1 hash as a compile definition
|
||||
execute_process(COMMAND git rev-parse HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
RESULT_VARIABLE GIT_SHA1_SUCCESS
|
||||
OUTPUT_VARIABLE GIT_SHA1
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(GIT_SHA1_SUCCESS EQUAL 0)
|
||||
target_compile_definitions(libopenmc PRIVATE -DGIT_SHA1="${GIT_SHA1}")
|
||||
endif()
|
||||
|
||||
# target_link_libraries treats any arguments starting with - but not -l as
|
||||
# linker flags. Thus, we can pass both linker flags and libraries together.
|
||||
target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml_fortran
|
||||
target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml
|
||||
faddeeva)
|
||||
target_link_libraries(${program} ${ldflags} libopenmc)
|
||||
|
||||
#===============================================================================
|
||||
# openmc executable
|
||||
#===============================================================================
|
||||
|
||||
add_executable(openmc src/main.cpp)
|
||||
target_compile_options(openmc PRIVATE ${cxxflags})
|
||||
target_link_libraries(openmc libopenmc)
|
||||
|
||||
#===============================================================================
|
||||
# Python package
|
||||
|
|
@ -502,7 +468,7 @@ add_custom_command(TARGET libopenmc POST_BUILD
|
|||
# Install executable, scripts, manpage, license
|
||||
#===============================================================================
|
||||
|
||||
install(TARGETS ${program} libopenmc
|
||||
install(TARGETS openmc libopenmc
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
|
|
@ -510,4 +476,4 @@ install(TARGETS ${program} libopenmc
|
|||
)
|
||||
install(DIRECTORY src/relaxng DESTINATION share/openmc)
|
||||
install(FILES man/man1/openmc.1 DESTINATION share/man/man1)
|
||||
install(FILES LICENSE DESTINATION "share/doc/${program}" RENAME copyright)
|
||||
install(FILES LICENSE DESTINATION "share/doc/openmc" RENAME copyright)
|
||||
|
|
|
|||
76
CODE_OF_CONDUCT.md
Normal file
76
CODE_OF_CONDUCT.md
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at openmc@anl.gov. All complaints will
|
||||
be reviewed and investigated and will result in a response that is deemed
|
||||
necessary and appropriate to the circumstances. The project team is obligated to
|
||||
maintain confidentiality with regard to the reporter of an incident. However,
|
||||
note that some project team members may have a legal obligation to report
|
||||
certain forms of harassment because of their affiliation (for example, staff and
|
||||
faculty at universities in the United States). Further details of specific
|
||||
enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
46
CONTRIBUTING.md
Normal file
46
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# Contributing to OpenMC
|
||||
|
||||
Welcome, and thank you for considering contributing to OpenMC! We look forward
|
||||
to welcoming new members to the community and will do our best to help you get
|
||||
up to speed.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Participants in the OpenMC project are expected to follow and uphold the [Code
|
||||
of Conduct](CODE_OF_CONDUCT.md). Please report any unacceptable behavior to
|
||||
openmc@anl.gov.
|
||||
|
||||
## Resources
|
||||
|
||||
- [GitHub Repository](https://github.com/openmc-dev/openmc)
|
||||
- [Documentation](http://openmc.readthedocs.io/en/latest)
|
||||
- [User's Mailing List](openmc-users@googlegroups.com)
|
||||
- [Developer's Mailing List](openmc-dev@googlegroups.com)
|
||||
- [Slack Community](https://openmc.slack.com/signup) (If you don't see your
|
||||
domain listed, contact openmc@anl.gov)
|
||||
|
||||
## How to Report Bugs
|
||||
|
||||
OpenMC is hosted on GitHub and all bugs are reported and tracked through the
|
||||
[Issues](https://github.com/openmc-dev/openmc/issues) listed on GitHub.
|
||||
|
||||
## How to Suggest Enhancements
|
||||
|
||||
We welcome suggestions for new features or enhancements to the code and
|
||||
encourage you to submit them as Issues on GitHub. However, it's important to
|
||||
recognize that our development team is relatively small and does not have
|
||||
unlimited time to devote to new feature suggestions. If you are interested in
|
||||
working on the feature you are requesting, indicate so in the issue and the
|
||||
development team will be happy to discuss it.
|
||||
|
||||
## How to Submit Changes
|
||||
|
||||
All changes to OpenMC happen through pull requests. For a full overview of the
|
||||
process, see the developer's guide section on [Development
|
||||
Workflow](http://openmc.readthedocs.io/en/latest/devguide/workflow.html).
|
||||
|
||||
## Code Style
|
||||
|
||||
Before you run off to make changes to the code, please have a look at our [style
|
||||
guide](http://openmc.readthedocs.io/en/latest/devguide/styleguide.html), which
|
||||
is used when reviewing new contributions.
|
||||
2
LICENSE
2
LICENSE
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2011-2018 Massachusetts Institute of Technology
|
||||
Copyright (c) 2011-2018 Massachusetts Institute of Technology and OpenMC contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
|
|
|||
58
README.md
Normal file
58
README.md
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# OpenMC Monte Carlo Particle Transport Code
|
||||
|
||||
[](http://openmc.readthedocs.io/en/latest/license.html)
|
||||
[](https://travis-ci.org/openmc-dev/openmc)
|
||||
[](https://coveralls.io/github/openmc-dev/openmc?branch=develop)
|
||||
|
||||
The OpenMC project aims to provide a fully-featured Monte Carlo particle
|
||||
transport code based on modern methods. It is a constructive solid geometry,
|
||||
continuous-energy transport code that uses HDF5 format cross sections. The
|
||||
project started under the Computational Reactor Physics Group at MIT.
|
||||
|
||||
Complete documentation on the usage of OpenMC is hosted on Read the Docs (both
|
||||
for the [latest release](http://openmc.readthedocs.io/en/stable/) and
|
||||
[developmental](http://openmc.readthedocs.io/en/latest/) version). If you are
|
||||
interested in the project or would like to help and contribute, please send a
|
||||
message to the OpenMC User's Group [mailing
|
||||
list](https://groups.google.com/forum/?fromgroups=#!forum/openmc-users).
|
||||
|
||||
## Installation
|
||||
|
||||
Detailed [installation
|
||||
instructions](http://openmc.readthedocs.io/en/stable/usersguide/install.html)
|
||||
can be found in the User's Guide.
|
||||
|
||||
## Citing
|
||||
|
||||
If you use OpenMC in your research, please consider giving proper attribution by
|
||||
citing the following publication:
|
||||
|
||||
- Paul K. Romano, Nicholas E. Horelik, Bryan R. Herman, Adam G. Nelson, Benoit
|
||||
Forget, and Kord Smith, "[OpenMC: A State-of-the-Art Monte Carlo Code for
|
||||
Research and Development](https://doi.org/10.1016/j.anucene.2014.07.048),"
|
||||
*Ann. Nucl. Energy*, **82**, 90--97 (2015).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you run into problems compiling, installing, or running OpenMC, first check
|
||||
the [Troubleshooting
|
||||
section](http://openmc.readthedocs.io/en/stable/usersguide/troubleshoot.html) in
|
||||
the User's Guide. If you are not able to find a solution to your problem there,
|
||||
please send a message to the User's Group [mailing
|
||||
list](https://groups.google.com/forum/?fromgroups=#!forum/openmc-users).
|
||||
|
||||
## Reporting Bugs
|
||||
|
||||
OpenMC is hosted on GitHub and all bugs are reported and tracked through the
|
||||
[Issues](https://github.com/openmc-dev/openmc/issues) feature on GitHub. However,
|
||||
GitHub Issues should not be used for common troubleshooting purposes. If you are
|
||||
having trouble installing the code or getting your model to run properly, you
|
||||
should first send a message to the User's Group mailing list. If it turns out
|
||||
your issue really is a bug in the code, an issue will then be created on
|
||||
GitHub. If you want to request that a feature be added to the code, you may
|
||||
create an Issue on github.
|
||||
|
||||
## License
|
||||
|
||||
OpenMC is distributed under the MIT/X
|
||||
[license](http://openmc.readthedocs.io/en/stable/license.html).
|
||||
|
|
@ -71,7 +71,7 @@ master_doc = 'index'
|
|||
|
||||
# General information about the project.
|
||||
project = u'OpenMC'
|
||||
copyright = u'2011-2018, Massachusetts Institute of Technology'
|
||||
copyright = u'2011-2018, Massachusetts Institute of Technology and OpenMC contributors'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
|
|
@ -208,7 +208,7 @@ htmlhelp_basename = 'openmcdoc'
|
|||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'openmc.tex', u'OpenMC Documentation',
|
||||
u'Massachusetts Institute of Technology', 'manual'),
|
||||
u'OpenMC contributors', 'manual'),
|
||||
]
|
||||
|
||||
latex_elements = {
|
||||
|
|
|
|||
|
|
@ -182,37 +182,83 @@ Always use C++-style comments (``//``) as opposed to C-style (``/**/``). (It
|
|||
is more difficult to comment out a large section of code that uses C-style
|
||||
comments.)
|
||||
|
||||
Header files should always use include guards with the following style (See
|
||||
`SF.8 <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#sf8-use-include-guards-for-all-h-files>`_:
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
#ifndef MODULE_NAME_H
|
||||
#define MODULE_NAME_H
|
||||
...
|
||||
content
|
||||
...
|
||||
#endif // MODULE_NAME_H
|
||||
|
||||
Do not use C-style casting. Always use the C++-style casts ``static_cast``,
|
||||
``const_cast``, or ``reinterpret_cast``. (See `ES.49 <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es49-if-you-must-use-a-cast-use-a-named-cast>`_)
|
||||
|
||||
Source Files
|
||||
------------
|
||||
|
||||
Use a ``.cpp`` suffix for code files and ``.h`` for header files.
|
||||
|
||||
Header files should always use include guards with the following style (See
|
||||
`SF.8 <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#sf8-use-include-guards-for-all-h-files>`_):
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
#ifndef OPENMC_MODULE_NAME_H
|
||||
#define OPENMC_MODULE_NAME_H
|
||||
|
||||
namespace openmc {
|
||||
...
|
||||
content
|
||||
...
|
||||
}
|
||||
|
||||
#endif // OPENMC_MODULE_NAME_H
|
||||
|
||||
Avoid hidden dependencies by always including a related header file first,
|
||||
followed by C/C++ library includes, other library includes, and then local
|
||||
includes. For example:
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
// foo.cpp
|
||||
#include "foo.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "hdf5.h"
|
||||
#include "pugixml.hpp"
|
||||
|
||||
#include "error.h"
|
||||
#include "random_lcg.h"
|
||||
|
||||
Naming
|
||||
------
|
||||
|
||||
In general, write your code in lower-case. Having code in all caps does not
|
||||
enhance code readability or otherwise.
|
||||
|
||||
Struct and class names should be CamelCase, e.g. ``HexLattice``.
|
||||
|
||||
Functions (including member functions) should be lower-case with underscores,
|
||||
e.g. ``get_indices``.
|
||||
|
||||
Local variables, global variables, and struct/class attributes should be
|
||||
lower-case with underscores (e.g. ``n_cells``) except for physics symbols that
|
||||
are written differently by convention (e.g. ``E`` for energy).
|
||||
Local variables, global variables, and struct/class member variables should be
|
||||
lower-case with underscores (e.g., ``n_cells``) except for physics symbols that
|
||||
are written differently by convention (e.g., ``E`` for energy). Data members of
|
||||
classes (but not structs) additionally have trailing underscores (e.g.,
|
||||
``a_class_member_``).
|
||||
|
||||
Const variables should be in upper-case with underscores, e.g. ``SQRT_PI``.
|
||||
Accessors and mutators (get and set functions) may be named like
|
||||
variables. These often correspond to actual member variables, but this is not
|
||||
required. For example, ``int count()`` and ``void set_count(int count)``.
|
||||
|
||||
Variables declared constexpr or const that have static storage duration (exist
|
||||
for the duration of the program) should be upper-case with underscores,
|
||||
e.g., ``SQRT_PI``.
|
||||
|
||||
Use C++-style declarator layout (see `NL.18
|
||||
<http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#nl18-use-c-style-declarator-layout>`_):
|
||||
pointer and reference operators in declarations should be placed adject to the
|
||||
base type rather than the variable name. Avoid declaring multiple names in a
|
||||
single declaration to avoid confusion:
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
T* p; // good
|
||||
T& p; // good
|
||||
T *p; // bad
|
||||
T* p, q; // misleading
|
||||
|
||||
Curly braces
|
||||
------------
|
||||
|
|
@ -280,6 +326,13 @@ the same line or omit the braces entirely.
|
|||
|
||||
for (int i = 0; i < 5; i++) content();
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
Classes, structs, and functions are to be annotated for the `Doxygen
|
||||
<http://www.stack.nl/~dimitri/doxygen/>`_ documentation generation tool. Use the
|
||||
``\`` form of Doxygen commands, e.g., ``\brief`` instead of ``@brief``.
|
||||
|
||||
------
|
||||
Python
|
||||
------
|
||||
|
|
@ -288,15 +341,17 @@ Style for Python code should follow PEP8_.
|
|||
|
||||
Docstrings for functions and methods should follow numpydoc_ style.
|
||||
|
||||
Python code should work with both Python 2.7+ and Python 3.0+.
|
||||
Python code should work with Python 3.4+.
|
||||
|
||||
Use of third-party Python packages should be limited to numpy_, scipy_, and
|
||||
h5py_. Use of other third-party packages must be implemented as optional
|
||||
dependencies rather than required dependencies.
|
||||
Use of third-party Python packages should be limited to numpy_, scipy_,
|
||||
matplotlib_, pandas_, and h5py_. Use of other third-party packages must be
|
||||
implemented as optional dependencies rather than required dependencies.
|
||||
|
||||
.. _C++ Core Guidelines: http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines
|
||||
.. _PEP8: https://www.python.org/dev/peps/pep-0008/
|
||||
.. _numpydoc: https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
|
||||
.. _numpy: http://www.numpy.org/
|
||||
.. _scipy: http://www.scipy.org/
|
||||
.. _scipy: https://www.scipy.org/
|
||||
.. _matplotlib: https://matplotlib.org/
|
||||
.. _pandas: https://pandas.pydata.org/
|
||||
.. _h5py: http://www.h5py.org/
|
||||
|
|
|
|||
|
|
@ -65,8 +65,8 @@ developer or send a message to the `developers mailing list`_.
|
|||
.. _property attribute: https://docs.python.org/3.6/library/functions.html#property
|
||||
.. _XML Schema Part 2: http://www.w3.org/TR/xmlschema-2/
|
||||
.. _boolean: http://www.w3.org/TR/xmlschema-2/#boolean
|
||||
.. _xml_interface module: https://github.com/mit-crpg/openmc/blob/develop/src/xml_interface.F90
|
||||
.. _input_xml module: https://github.com/mit-crpg/openmc/blob/develop/src/input_xml.F90
|
||||
.. _xml_interface module: https://github.com/openmc-dev/openmc/blob/develop/src/xml_interface.F90
|
||||
.. _input_xml module: https://github.com/openmc-dev/openmc/blob/develop/src/input_xml.F90
|
||||
.. _RELAX NG: http://relaxng.org/
|
||||
.. _compact syntax: http://relaxng.org/compact-tutorial-20030326.html
|
||||
.. _trang: http://www.thaiopensource.com/relaxng/trang.html
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ Now that you understand the basic development workflow, let's discuss how an
|
|||
individual to contribute to development. Note that this would apply to both new
|
||||
features and bug fixes. The general steps for contributing are as follows:
|
||||
|
||||
1. Fork the main openmc repository from `mit-crpg/openmc`_. This will create a
|
||||
1. Fork the main openmc repository from `openmc-dev/openmc`_. This will create a
|
||||
repository with the same name under your personal account. As such, you can
|
||||
commit to it as you please without disrupting other developers.
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ features and bug fixes. The general steps for contributing are as follows:
|
|||
ensure that those changes are made on a different branch.
|
||||
|
||||
4. Issue a pull request from GitHub and select the *develop* branch of
|
||||
mit-crpg/openmc as the target.
|
||||
openmc-dev/openmc as the target.
|
||||
|
||||
.. image:: ../_images/pullrequest.png
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ features and bug fixes. The general steps for contributing are as follows:
|
|||
request page itself.
|
||||
|
||||
6. After the pull request has been thoroughly vetted, it is merged back into the
|
||||
*develop* branch of mit-crpg/openmc.
|
||||
*develop* branch of openmc-dev/openmc.
|
||||
|
||||
Private Development
|
||||
-------------------
|
||||
|
|
@ -99,7 +99,7 @@ create a complete copy of the OpenMC repository (not a fork from GitHub). The
|
|||
private repository can then either be stored just locally or in conjunction with
|
||||
a private repository on Github (this requires a `paid plan`_). Alternatively,
|
||||
`Bitbucket`_ offers private repositories for free. If you want to merge some
|
||||
changes you've made in your private repository back to mit-crpg/openmc
|
||||
changes you've made in your private repository back to openmc-dev/openmc
|
||||
repository, simply follow the steps above with an extra step of pulling a branch
|
||||
from your private repository into a public fork.
|
||||
|
||||
|
|
@ -128,9 +128,9 @@ can interfere with virtual environments.
|
|||
.. _GitHub: https://github.com/
|
||||
.. _git flow: http://nvie.com/git-model
|
||||
.. _valgrind: http://valgrind.org/
|
||||
.. _style guide: http://mit-crpg.github.io/openmc/devguide/styleguide.html
|
||||
.. _style guide: http://openmc.readthedocs.io/en/latest/devguide/styleguide.html
|
||||
.. _pull request: https://help.github.com/articles/using-pull-requests
|
||||
.. _mit-crpg/openmc: https://github.com/mit-crpg/openmc
|
||||
.. _openmc-dev/openmc: https://github.com/openmc-dev/openmc
|
||||
.. _paid plan: https://github.com/plans
|
||||
.. _Bitbucket: https://bitbucket.org
|
||||
.. _ctest: http://www.cmake.org/cmake/help/v2.8.12/ctest.html
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ Basic Usage
|
|||
triso
|
||||
candu
|
||||
nuclear-data
|
||||
nuclear-data-resonance-covariance
|
||||
|
||||
------------------------------------
|
||||
Multi-Group Cross Section Generation
|
||||
|
|
|
|||
13
docs/source/examples/nuclear-data-resonance-covariance.rst
Normal file
13
docs/source/examples/nuclear-data-resonance-covariance.rst
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
.. _notebook_nuclear_data_resonance_covariance:
|
||||
|
||||
==================================
|
||||
Nuclear Data: Resonance Covariance
|
||||
==================================
|
||||
|
||||
.. only:: html
|
||||
|
||||
.. notebook:: ../../../examples/jupyter/nuclear-data-resonance-covariance.ipynb
|
||||
|
||||
.. only:: latex
|
||||
|
||||
IPython notebooks must be viewed in the online HTML documentation.
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
License Agreement
|
||||
=================
|
||||
|
||||
Copyright © 2011-2018 Massachusetts Institute of Technology
|
||||
Copyright © 2011-2018 Massachusetts Institute of Technology and OpenMC contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
|
|
|||
|
|
@ -79,6 +79,11 @@ Resonance Data
|
|||
openmc.data.MultiLevelBreitWigner
|
||||
openmc.data.ReichMoore
|
||||
openmc.data.RMatrixLimited
|
||||
openmc.data.ResonanceCovariances
|
||||
openmc.data.ResonanceCovarianceRange
|
||||
openmc.data.SingleLevelBreitWignerCovariance
|
||||
openmc.data.MultiLevelBreitWignerCovariance
|
||||
openmc.data.ReichMooreCovariance
|
||||
openmc.data.ParticlePair
|
||||
openmc.data.SpinGroup
|
||||
openmc.data.Unresolved
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ Installing from Source on Linux or Mac OS X
|
|||
-------------------------------------------
|
||||
|
||||
All OpenMC source code is hosted on `GitHub
|
||||
<https://github.com/mit-crpg/openmc>`_. If you have `git
|
||||
<https://github.com/openmc-dev/openmc>`_. If you have `git
|
||||
<https://git-scm.com>`_, the `gcc <https://gcc.gnu.org/>`_ compiler suite,
|
||||
`CMake <http://www.cmake.org>`_, and `HDF5 <https://www.hdfgroup.org/HDF5/>`_
|
||||
installed, you can download and install OpenMC be entering the following
|
||||
|
|
@ -91,7 +91,7 @@ commands in a terminal:
|
|||
|
||||
.. code-block:: sh
|
||||
|
||||
git clone https://github.com/mit-crpg/openmc.git
|
||||
git clone https://github.com/openmc-dev/openmc.git
|
||||
cd openmc
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
|
|
|
|||
|
|
@ -71,14 +71,14 @@ Bug Fixes
|
|||
- 0c6915_: Bugfix for generating thermal scattering data
|
||||
- 61ecb4_: Fix bugs in Python multipole objects
|
||||
|
||||
.. _937469: https://github.com/mit-crpg/openmc/commit/937469
|
||||
.. _a149ef: https://github.com/mit-crpg/openmc/commit/a149ef
|
||||
.. _2c9b21: https://github.com/mit-crpg/openmc/commit/2c9b21
|
||||
.. _8047f6: https://github.com/mit-crpg/openmc/commit/8047f6
|
||||
.. _0beb4c: https://github.com/mit-crpg/openmc/commit/0beb4c
|
||||
.. _f124be: https://github.com/mit-crpg/openmc/commit/f124be
|
||||
.. _0c6915: https://github.com/mit-crpg/openmc/commit/0c6915
|
||||
.. _61ecb4: https://github.com/mit-crpg/openmc/commit/61ecb4
|
||||
.. _937469: https://github.com/openmc-dev/openmc/commit/937469
|
||||
.. _a149ef: https://github.com/openmc-dev/openmc/commit/a149ef
|
||||
.. _2c9b21: https://github.com/openmc-dev/openmc/commit/2c9b21
|
||||
.. _8047f6: https://github.com/openmc-dev/openmc/commit/8047f6
|
||||
.. _0beb4c: https://github.com/openmc-dev/openmc/commit/0beb4c
|
||||
.. _f124be: https://github.com/openmc-dev/openmc/commit/f124be
|
||||
.. _0c6915: https://github.com/openmc-dev/openmc/commit/0c6915
|
||||
.. _61ecb4: https://github.com/openmc-dev/openmc/commit/61ecb4
|
||||
|
||||
------------
|
||||
Contributors
|
||||
|
|
|
|||
|
|
@ -153,9 +153,9 @@ and `Volume II`_. You may also find it helpful to review the following terms:
|
|||
.. _Reactor Concepts Manual: http://www.tayloredge.com/periodic/trivia/ReactorConcepts.pdf
|
||||
.. _Volume I: https://www.standards.doe.gov/standards-documents/1000/1019-bhdbk-1993-v1
|
||||
.. _Volume II: https://www.standards.doe.gov/standards-documents/1000/1019-bhdbk-1993-v2
|
||||
.. _OpenMC source code: https://github.com/mit-crpg/openmc
|
||||
.. _OpenMC source code: https://github.com/openmc-dev/openmc
|
||||
.. _GitHub: https://github.com/
|
||||
.. _bug reports: https://github.com/mit-crpg/openmc/issues
|
||||
.. _bug reports: https://github.com/openmc-dev/openmc/issues
|
||||
.. _Neutron cross section: http://en.wikipedia.org/wiki/Neutron_cross_section
|
||||
.. _Effective multiplication factor: https://en.wikipedia.org/wiki/Nuclear_chain_reaction#Effective_neutron_multiplication_factor
|
||||
.. _Flux: http://en.wikipedia.org/wiki/Neutron_flux
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ with GitHub since this involves setting up ssh_ keys. With git installed and
|
|||
setup, the following command will download the full source code from the GitHub
|
||||
repository::
|
||||
|
||||
git clone https://github.com/mit-crpg/openmc.git
|
||||
git clone https://github.com/openmc-dev/openmc.git
|
||||
|
||||
By default, the cloned repository will be set to the development branch. To
|
||||
switch to the source of the latest stable release, run the following commands::
|
||||
|
|
@ -189,7 +189,7 @@ switch to the source of the latest stable release, run the following commands::
|
|||
cd openmc
|
||||
git checkout master
|
||||
|
||||
.. _GitHub: https://github.com/mit-crpg/openmc
|
||||
.. _GitHub: https://github.com/openmc-dev/openmc
|
||||
.. _git: https://git-scm.com
|
||||
.. _ssh: https://en.wikipedia.org/wiki/Secure_Shell
|
||||
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ The following tables show all valid scores:
|
|||
+----------------------+---------------------------------------------------+
|
||||
|nu-fission |Total production of neutrons due to fission. |
|
||||
+----------------------+---------------------------------------------------+
|
||||
|nu-scatter, |This score is similar in functionality to the |
|
||||
|nu-scatter |This score is similar in functionality to the |
|
||||
| |``scatter`` score except the total production of |
|
||||
| |neutrons due to scattering is scored vice simply |
|
||||
| |the scattering rate. This accounts for |
|
||||
|
|
|
|||
964
examples/jupyter/nuclear-data-resonance-covariance.ipynb
Normal file
964
examples/jupyter/nuclear-data-resonance-covariance.ipynb
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -134,6 +134,7 @@ extern "C" {
|
|||
extern int32_t n_lattices;
|
||||
extern int32_t n_materials;
|
||||
extern int32_t n_meshes;
|
||||
extern int n_nuclides;
|
||||
extern int64_t n_particles;
|
||||
extern int32_t n_plots;
|
||||
extern int32_t n_realizations;
|
||||
|
|
|
|||
|
|
@ -59,7 +59,8 @@ Indicates the default path to a directory containing windowed multipole data if
|
|||
the user has not specified the <multipole_library> tag in
|
||||
.I materials.xml\fP.
|
||||
.SH LICENSE
|
||||
Copyright \(co 2011-2018 Massachusetts Institute of Technology.
|
||||
Copyright \(co 2011-2018 Massachusetts Institute of Technology and OpenMC
|
||||
contributors.
|
||||
.PP
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
|
@ -79,7 +80,7 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
.SH REPORTING BUGS
|
||||
The OpenMC source code is hosted on GitHub at
|
||||
https://github.com/mit-crpg/openmc. With a github account, you can submit issues
|
||||
https://github.com/openmc-dev/openmc. With a github account, you can submit issues
|
||||
directly on the github repository that will then be reviewed by OpenMC
|
||||
developers. Alternatively, you can send a bug report to
|
||||
.I openmc-users@googlegroups.com\fP.
|
||||
|
|
|
|||
|
|
@ -27,5 +27,6 @@ from .urr import *
|
|||
from .library import *
|
||||
from .fission_energy import *
|
||||
from .resonance import *
|
||||
from .resonance_covariance import *
|
||||
from .multipole import *
|
||||
from .grid import *
|
||||
|
|
|
|||
|
|
@ -71,6 +71,24 @@ def float_endf(s):
|
|||
return float(_ENDF_FLOAT_RE.sub(r'\1e\2', s))
|
||||
|
||||
|
||||
def _int_endf(s):
|
||||
"""Convert string to int. Used for INTG records where blank entries
|
||||
indicate a 0.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
s : str
|
||||
Integer or spaces
|
||||
|
||||
Returns
|
||||
-------
|
||||
integer
|
||||
The number or 0
|
||||
"""
|
||||
s = s.strip()
|
||||
return int(s) if s else 0
|
||||
|
||||
|
||||
def get_text_record(file_obj):
|
||||
"""Return data from a TEXT record in an ENDF-6 file.
|
||||
|
||||
|
|
@ -250,6 +268,50 @@ def get_tab2_record(file_obj):
|
|||
return params, Tabulated2D(breakpoints, interpolation)
|
||||
|
||||
|
||||
def get_intg_record(file_obj):
|
||||
"""
|
||||
Return data from an INTG record in an ENDF-6 file. Used to store the
|
||||
covariance matrix in a compact format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
file_obj : file-like object
|
||||
ENDF-6 file to read from
|
||||
|
||||
Returns
|
||||
-------
|
||||
numpy.ndarray
|
||||
The correlation matrix described in the INTG record
|
||||
"""
|
||||
# determine how many items are in list and NDIGIT
|
||||
items = get_cont_record(file_obj)
|
||||
ndigit = int(items[2])
|
||||
npar = int(items[3]) # Number of parameters
|
||||
nlines = int(items[4]) # Lines to read
|
||||
NROW_RULES = {2: 18, 3: 12, 4: 11, 5: 9, 6: 8}
|
||||
nrow = NROW_RULES[ndigit]
|
||||
|
||||
# read lines and build correlation matrix
|
||||
corr = np.identity(npar)
|
||||
for i in range(nlines):
|
||||
line = file_obj.readline()
|
||||
ii = _int_endf(line[:5]) - 1 # -1 to account for 0 indexing
|
||||
jj = _int_endf(line[5:10]) - 1
|
||||
factor = 10**ndigit
|
||||
for j in range(nrow):
|
||||
if jj+j >= ii:
|
||||
break
|
||||
element = _int_endf(line[11+(ndigit+1)*j:11+(ndigit+1)*(j+1)])
|
||||
if element > 0:
|
||||
corr[ii, jj] = (element+0.5)/factor
|
||||
elif element < 0:
|
||||
corr[ii, jj] = (element-0.5)/factor
|
||||
|
||||
# Symmetrize the correlation matrix
|
||||
corr = corr + corr.T - np.diag(corr.diagonal())
|
||||
return corr
|
||||
|
||||
|
||||
def get_evaluations(filename):
|
||||
"""Return a list of all evaluations within an ENDF file.
|
||||
|
||||
|
|
@ -288,7 +350,7 @@ class Evaluation(object):
|
|||
Attributes
|
||||
----------
|
||||
info : dict
|
||||
Miscallaneous information about the evaluation.
|
||||
Miscellaneous information about the evaluation.
|
||||
target : dict
|
||||
Information about the target material, such as its mass, isomeric state,
|
||||
whether it's stable, and whether it's fissionable.
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ from .njoy import make_ace
|
|||
from .product import Product
|
||||
from .reaction import Reaction, _get_photon_products_ace
|
||||
from . import resonance as res
|
||||
from . import resonance_covariance as res_cov
|
||||
from .urr import ProbabilityTables
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.mixin import EqualityMixin
|
||||
|
|
@ -148,6 +149,8 @@ class IncidentNeutron(EqualityMixin):
|
|||
and the values are Reaction objects.
|
||||
resonances : openmc.data.Resonances or None
|
||||
Resonance parameters
|
||||
resonance_covariance : openmc.data.ResonanceCovariance or None
|
||||
Covariance for resonance parameters
|
||||
summed_reactions : collections.OrderedDict
|
||||
Contains summed cross sections, e.g., the total cross section. The keys
|
||||
are the MT values and the values are Reaction objects.
|
||||
|
|
@ -228,6 +231,10 @@ class IncidentNeutron(EqualityMixin):
|
|||
def resonances(self):
|
||||
return self._resonances
|
||||
|
||||
@property
|
||||
def resonance_covariance(self):
|
||||
return self._resonance_covariance
|
||||
|
||||
@property
|
||||
def summed_reactions(self):
|
||||
return self._summed_reactions
|
||||
|
|
@ -289,6 +296,12 @@ class IncidentNeutron(EqualityMixin):
|
|||
cv.check_type('resonances', resonances, res.Resonances)
|
||||
self._resonances = resonances
|
||||
|
||||
@resonance_covariance.setter
|
||||
def resonance_covariance(self, resonance_covariance):
|
||||
cv.check_type('resonance covariance', resonance_covariance,
|
||||
res_cov.ResonanceCovariances)
|
||||
self._resonance_covariance = resonance_covariance
|
||||
|
||||
@summed_reactions.setter
|
||||
def summed_reactions(self, summed_reactions):
|
||||
cv.check_type('summed reactions', summed_reactions, Mapping)
|
||||
|
|
@ -744,7 +757,7 @@ class IncidentNeutron(EqualityMixin):
|
|||
return data
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, ev_or_filename):
|
||||
def from_endf(cls, ev_or_filename, covariance=False):
|
||||
"""Generate incident neutron continuous-energy data from an ENDF evaluation
|
||||
|
||||
Parameters
|
||||
|
|
@ -753,6 +766,10 @@ class IncidentNeutron(EqualityMixin):
|
|||
ENDF evaluation to read from. If given as a string, it is assumed to
|
||||
be the filename for the ENDF file.
|
||||
|
||||
covariance : bool
|
||||
Flag to indicate whether or not covariance data from File 32 should be
|
||||
retrieved
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.IncidentNeutron
|
||||
|
|
@ -784,6 +801,11 @@ class IncidentNeutron(EqualityMixin):
|
|||
if (2, 151) in ev.section:
|
||||
data.resonances = res.Resonances.from_endf(ev)
|
||||
|
||||
if (32, 151) in ev.section and covariance:
|
||||
data.resonance_covariance = (
|
||||
res_cov.ResonanceCovariances.from_endf(ev, data.resonances)
|
||||
)
|
||||
|
||||
# Read each reaction
|
||||
for mf, mt, nc, mod in ev.reaction_list:
|
||||
if mf == 3:
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ except ImportError:
|
|||
_reconstruct = False
|
||||
import openmc.checkvalue as cv
|
||||
|
||||
|
||||
class Resonances(object):
|
||||
"""Resolved and unresolved resonance data
|
||||
|
||||
|
|
@ -90,14 +91,14 @@ class Resonances(object):
|
|||
|
||||
# Determine whether discrete or continuous representation
|
||||
items = get_head_record(file_obj)
|
||||
n_isotope = items[4] # Number of isotopes
|
||||
n_isotope = items[4] # Number of isotopes
|
||||
|
||||
ranges = []
|
||||
for iso in range(n_isotope):
|
||||
items = get_cont_record(file_obj)
|
||||
abundance = items[1]
|
||||
fission_widths = (items[3] == 1) # fission widths are given?
|
||||
n_ranges = items[4] # number of resonance energy ranges
|
||||
fission_widths = (items[3] == 1) # fission widths are given?
|
||||
n_ranges = items[4] # number of resonance energy ranges
|
||||
|
||||
for j in range(n_ranges):
|
||||
items = get_cont_record(file_obj)
|
||||
|
|
@ -112,7 +113,7 @@ class Resonances(object):
|
|||
# unresolved resonance region
|
||||
erange = Unresolved.from_endf(file_obj, items, fission_widths)
|
||||
|
||||
#erange.material = self
|
||||
# erange.material = self
|
||||
ranges.append(erange)
|
||||
|
||||
return cls(ranges)
|
||||
|
|
@ -162,6 +163,13 @@ class ResonanceRange(object):
|
|||
self._prepared = False
|
||||
self._parameter_matrix = {}
|
||||
|
||||
def __copy__(self):
|
||||
cls = type(self)
|
||||
new_copy = cls.__new__(cls)
|
||||
new_copy.__dict__.update(self.__dict__)
|
||||
new_copy._prepared = False
|
||||
return new_copy
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, ev, file_obj, items):
|
||||
"""Create resonance range from an ENDF evaluation.
|
||||
|
|
@ -437,7 +445,7 @@ class MultiLevelBreitWigner(ResonanceRange):
|
|||
self._l_values = np.array(l_values)
|
||||
self._competitive = np.array(competitive)
|
||||
for l in l_values:
|
||||
self._parameter_matrix[l] = df[df.L == l].as_matrix()
|
||||
self._parameter_matrix[l] = df[df.L == l].values
|
||||
|
||||
self._prepared = True
|
||||
|
||||
|
|
@ -682,7 +690,7 @@ class ReichMoore(ResonanceRange):
|
|||
self._l_values = np.array(l_values)
|
||||
for (l, J) in lj_values:
|
||||
self._parameter_matrix[l, J] = df[(df.L == l) &
|
||||
(abs(df.J) == J)].as_matrix()
|
||||
(abs(df.J) == J)].values
|
||||
|
||||
self._prepared = True
|
||||
|
||||
|
|
|
|||
708
openmc/data/resonance_covariance.py
Normal file
708
openmc/data/resonance_covariance.py
Normal file
|
|
@ -0,0 +1,708 @@
|
|||
from collections import MutableSequence
|
||||
import warnings
|
||||
import io
|
||||
import copy
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
from . import endf
|
||||
import openmc.checkvalue as cv
|
||||
from .resonance import Resonances
|
||||
|
||||
|
||||
def _add_file2_contributions(file32params, file2params):
|
||||
"""Function for aiding in adding resonance parameters from File 2 that are
|
||||
not always present in File 32. Uses already imported resonance data.
|
||||
|
||||
Paramaters
|
||||
----------
|
||||
file32params : pandas.Dataframe
|
||||
Incomplete set of resonance parameters contained in File 32.
|
||||
file2params : pandas.Dataframe
|
||||
Resonance parameters from File 2. Ordered by energy.
|
||||
|
||||
Returns
|
||||
-------
|
||||
parameters : pandas.Dataframe
|
||||
Complete set of parameters ordered by L-values and then energy
|
||||
|
||||
"""
|
||||
# Use l-values and competitiveWidth from File 2 data
|
||||
# Re-sort File 2 by energy to match File 32
|
||||
file2params = file2params.sort_values(by=['energy'])
|
||||
file2params.reset_index(drop=True, inplace=True)
|
||||
# Sort File 32 parameters by energy as well (maintaining index)
|
||||
file32params.sort_values(by=['energy'], inplace=True)
|
||||
# Add in values (.values converts to array first to ignore index)
|
||||
file32params['L'] = file2params['L'].values
|
||||
if 'competitiveWidth' in file2params.columns:
|
||||
file32params['competitiveWidth'] = file2params['competitiveWidth'].values
|
||||
# Resort to File 32 order (by L then by E) for use with covariance
|
||||
file32params.sort_index(inplace=True)
|
||||
return file32params
|
||||
|
||||
|
||||
class ResonanceCovariances(Resonances):
|
||||
"""Resolved resonance covariance data
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ranges : list of openmc.data.ResonanceCovarianceRange
|
||||
Distinct energy ranges for resonance data
|
||||
|
||||
Attributes
|
||||
----------
|
||||
ranges : list of openmc.data.ResonanceCovarianceRange
|
||||
Distinct energy ranges for resonance data
|
||||
|
||||
"""
|
||||
|
||||
@property
|
||||
def ranges(self):
|
||||
return self._ranges
|
||||
|
||||
@ranges.setter
|
||||
def ranges(self, ranges):
|
||||
cv.check_type('resonance ranges', ranges, MutableSequence)
|
||||
self._ranges = cv.CheckedList(ResonanceCovarianceRange,
|
||||
'resonance range', ranges)
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, ev, resonances):
|
||||
"""Generate resonance covariance data from an ENDF evaluation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ev : openmc.data.endf.Evaluation
|
||||
ENDF evaluation
|
||||
resonances : openmc.data.Resonance object
|
||||
openmc.data.Resonanance object generated from the same evaluation
|
||||
used to import values not contained in File 32
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.ResonanceCovariances
|
||||
Resonance covariance data
|
||||
|
||||
"""
|
||||
file_obj = io.StringIO(ev.section[32, 151])
|
||||
|
||||
# Determine whether discrete or continuous representation
|
||||
items = endf.get_head_record(file_obj)
|
||||
n_isotope = items[4] # Number of isotopes
|
||||
|
||||
ranges = []
|
||||
for iso in range(n_isotope):
|
||||
items = endf.get_cont_record(file_obj)
|
||||
abundance = items[1]
|
||||
fission_widths = (items[3] == 1) # Flag for fission widths
|
||||
n_ranges = items[4] # Number of resonance energy ranges
|
||||
|
||||
for j in range(n_ranges):
|
||||
items = endf.get_cont_record(file_obj)
|
||||
# Unresolved flags - 0: only scattering radius given
|
||||
# 1: resolved parameters given
|
||||
# 2: unresolved parameters given
|
||||
unresolved_flag = items[2]
|
||||
formalism = items[3] # resonance formalism
|
||||
|
||||
# Throw error for unsupported formalisms
|
||||
if formalism in [0, 7]:
|
||||
error = 'LRF='+str(formalism)+' covariance not supported '\
|
||||
'for this formalism'
|
||||
raise NotImplementedError(error)
|
||||
|
||||
if unresolved_flag in (0, 1):
|
||||
# Resolved resonance region
|
||||
resonance = resonances.ranges[j]
|
||||
erange = _FORMALISMS[formalism].from_endf(ev, file_obj,
|
||||
items, resonance)
|
||||
ranges.append(erange)
|
||||
|
||||
elif unresolved_flag == 2:
|
||||
warn = 'Unresolved resonance not supported. Covariance '\
|
||||
'values for the unresolved region not imported.'
|
||||
warnings.warn(warn)
|
||||
|
||||
return cls(ranges)
|
||||
|
||||
|
||||
class ResonanceCovarianceRange:
|
||||
"""Resonace covariance range. Base class for different formalisms.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
energy_min : float
|
||||
Minimum energy of the resolved resonance range in eV
|
||||
energy_max : float
|
||||
Maximum energy of the resolved resonance range in eV
|
||||
|
||||
Attributes
|
||||
----------
|
||||
energy_min : float
|
||||
Minimum energy of the resolved resonance range in eV
|
||||
energy_max : float
|
||||
Maximum energy of the resolved resonance range in eV
|
||||
parameters : pandas.DataFrame
|
||||
Resonance parameters
|
||||
covariance : numpy.array
|
||||
The covariance matrix contained within the ENDF evaluation
|
||||
lcomp : int
|
||||
Flag indicating format of the covariance matrix within the ENDF file
|
||||
file2res : openmc.data.ResonanceRange object
|
||||
Corresponding resonance range with File 2 data.
|
||||
mpar : int
|
||||
Number of parameters in covariance matrix for each individual resonance
|
||||
formalism : str
|
||||
String descriptor of formalism
|
||||
"""
|
||||
def __init__(self, energy_min, energy_max):
|
||||
self.energy_min = energy_min
|
||||
self.energy_max = energy_max
|
||||
|
||||
def subset(self, parameter_str, bounds):
|
||||
"""Produce a subset of resonance parameters and the corresponding
|
||||
covariance matrix to an IncidentNeutron object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
parameter_str : str
|
||||
parameter to be discriminated
|
||||
(i.e. 'energy', 'captureWidth', 'fissionWidthA'...)
|
||||
bounds : np.array
|
||||
[low numerical bound, high numerical bound]
|
||||
|
||||
Returns
|
||||
-------
|
||||
res_cov_range : openmc.data.ResonanceCovarianceRange
|
||||
ResonanceCovarianceRange object that contains a subset of the
|
||||
covariance matrix (upper triangular) as well as a subset parameters
|
||||
within self.file2params
|
||||
|
||||
"""
|
||||
# Copy range and prevent change of original
|
||||
res_cov_range = copy.deepcopy(self)
|
||||
|
||||
parameters = self.file2res.parameters
|
||||
cov = res_cov_range.covariance
|
||||
mpar = res_cov_range.mpar
|
||||
# Create mask
|
||||
mask1 = parameters[parameter_str] >= bounds[0]
|
||||
mask2 = parameters[parameter_str] <= bounds[1]
|
||||
mask = mask1 & mask2
|
||||
res_cov_range.parameters = parameters[mask]
|
||||
indices = res_cov_range.parameters.index.values
|
||||
# Build subset of covariance
|
||||
sub_cov_dim = len(indices)*mpar
|
||||
cov_subset_vals = []
|
||||
for index1 in indices:
|
||||
for i in range(mpar):
|
||||
for index2 in indices:
|
||||
for j in range(mpar):
|
||||
if index2*mpar+j >= index1*mpar+i:
|
||||
cov_subset_vals.append(cov[index1*mpar+i,
|
||||
index2*mpar+j])
|
||||
|
||||
cov_subset = np.zeros([sub_cov_dim, sub_cov_dim])
|
||||
tri_indices = np.triu_indices(sub_cov_dim)
|
||||
cov_subset[tri_indices] = cov_subset_vals
|
||||
|
||||
res_cov_range.file2res.parameters = parameters[mask]
|
||||
res_cov_range.covariance = cov_subset
|
||||
return res_cov_range
|
||||
|
||||
def sample(self, n_samples):
|
||||
"""Sample resonance parameters based on the covariances provided
|
||||
within an ENDF evaluation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
n_samples : int
|
||||
The number of samples to produce
|
||||
|
||||
Returns
|
||||
-------
|
||||
samples : list of openmc.data.ResonanceCovarianceRange objects
|
||||
List of samples size `n_samples`
|
||||
|
||||
"""
|
||||
warn_str = 'Sampling routine does not guarantee positive values for '\
|
||||
'parameters. This can lead to undefined behavior in the '\
|
||||
'reconstruction routine.'
|
||||
warnings.warn(warn_str)
|
||||
parameters = self.parameters
|
||||
cov = self.covariance
|
||||
|
||||
# Symmetrizing covariance matrix
|
||||
cov = cov + cov.T - np.diag(cov.diagonal())
|
||||
formalism = self.formalism
|
||||
mpar = self.mpar
|
||||
samples = []
|
||||
|
||||
# Handling MLBW/SLBW sampling
|
||||
if formalism == 'mlbw' or formalism == 'slbw':
|
||||
params = ['energy', 'neutronWidth', 'captureWidth', 'fissionWidth',
|
||||
'competitiveWidth']
|
||||
param_list = params[:mpar]
|
||||
mean_array = parameters[param_list].values
|
||||
mean = mean_array.flatten()
|
||||
par_samples = np.random.multivariate_normal(mean, cov,
|
||||
size=n_samples)
|
||||
spin = parameters['J'].values
|
||||
l_value = parameters['L'].values
|
||||
for sample in par_samples:
|
||||
energy = sample[0::mpar]
|
||||
gn = sample[1::mpar]
|
||||
gg = sample[2::mpar]
|
||||
gf = sample[3::mpar] if mpar > 3 else parameters['fissionWidth'].values
|
||||
gx = sample[4::mpar] if mpar > 4 else parameters['competitiveWidth'].values
|
||||
gt = gn + gg + gf + gx
|
||||
|
||||
records = []
|
||||
for j, E in enumerate(energy):
|
||||
records.append([energy[j], l_value[j], spin[j], gt[j],
|
||||
gn[j], gg[j], gf[j], gx[j]])
|
||||
columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth',
|
||||
'captureWidth', 'fissionWidth', 'competitiveWidth']
|
||||
sample_params = pd.DataFrame.from_records(records,
|
||||
columns=columns)
|
||||
# Copy ResonanceRange object
|
||||
res_range = copy.copy(self.file2res)
|
||||
res_range.parameters = sample_params
|
||||
samples.append(res_range)
|
||||
|
||||
# Handling RM sampling
|
||||
elif formalism == 'rm':
|
||||
params = ['energy', 'neutronWidth', 'captureWidth',
|
||||
'fissionWidthA', 'fissionWidthB']
|
||||
param_list = params[:mpar]
|
||||
mean_array = parameters[param_list].values
|
||||
mean = mean_array.flatten()
|
||||
par_samples = np.random.multivariate_normal(mean, cov,
|
||||
size=n_samples)
|
||||
spin = parameters['J'].values
|
||||
l_value = parameters['L'].values
|
||||
for sample in par_samples:
|
||||
energy = sample[0::mpar]
|
||||
gn = sample[1::mpar]
|
||||
gg = sample[2::mpar]
|
||||
gfa = sample[3::mpar] if mpar > 3 else parameters['fissionWidthA'].values
|
||||
gfb = sample[4::mpar] if mpar > 3 else parameters['fissionWidthB'].values
|
||||
|
||||
records = []
|
||||
for j, E in enumerate(energy):
|
||||
records.append([energy[j], l_value[j], spin[j], gn[j],
|
||||
gg[j], gfa[j], gfb[j]])
|
||||
columns = ['energy', 'L', 'J', 'neutronWidth',
|
||||
'captureWidth', 'fissionWidthA', 'fissionWidthB']
|
||||
sample_params = pd.DataFrame.from_records(records,
|
||||
columns=columns)
|
||||
# Copy ResonanceRange object
|
||||
res_range = copy.copy(self.file2res)
|
||||
res_range.parameters = sample_params
|
||||
samples.append(res_range)
|
||||
|
||||
return samples
|
||||
|
||||
|
||||
class MultiLevelBreitWignerCovariance(ResonanceCovarianceRange):
|
||||
"""Multi-level Breit-Wigner resolved resonance formalism covariance data.
|
||||
Parameters
|
||||
----------
|
||||
energy_min : float
|
||||
Minimum energy of the resolved resonance range in eV
|
||||
energy_max : float
|
||||
Maximum energy of the resolved resonance range in eV
|
||||
|
||||
Attributes
|
||||
----------
|
||||
energy_min : float
|
||||
Minimum energy of the resolved resonance range in eV
|
||||
energy_max : float
|
||||
Maximum energy of the resolved resonance range in eV
|
||||
parameters : pandas.DataFrame
|
||||
Resonance parameters
|
||||
covariance : numpy.array
|
||||
The covariance matrix contained within the ENDF evaluation
|
||||
mpar : int
|
||||
Number of parameters in covariance matrix for each individual resonance
|
||||
lcomp : int
|
||||
Flag indicating format of the covariance matrix within the ENDF file
|
||||
file2res : openmc.data.ResonanceRange object
|
||||
Corresponding resonance range with File 2 data.
|
||||
formalism : str
|
||||
String descriptor of formalism
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, energy_min, energy_max, parameters, covariance, mpar,
|
||||
lcomp, file2res):
|
||||
super().__init__(energy_min, energy_max)
|
||||
self.parameters = parameters
|
||||
self.covariance = covariance
|
||||
self.mpar = mpar
|
||||
self.lcomp = lcomp
|
||||
self.file2res = copy.copy(file2res)
|
||||
self.formalism = 'mlbw'
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, ev, file_obj, items, resonance):
|
||||
"""Create MLBW covariance data from an ENDF evaluation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ev : openmc.data.endf.Evaluation
|
||||
ENDF evaluation
|
||||
file_obj : file-like object
|
||||
ENDF file positioned at the second record of a resonance range
|
||||
subsection in MF=32, MT=151
|
||||
items : list
|
||||
Items from the CONT record at the start of the resonance range
|
||||
subsection
|
||||
resonance : openmc.data.ResonanceRange object
|
||||
Corresponding resonance range with File 2 data.
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.MultiLevelBreitWignerCovariance
|
||||
Multi-level Breit-Wigner resonance covariance parameters
|
||||
|
||||
"""
|
||||
|
||||
# Read energy-dependent scattering radius if present
|
||||
energy_min, energy_max = items[0:2]
|
||||
nro, naps = items[4:6]
|
||||
if nro != 0:
|
||||
params, ape = endf.get_tab1_record(file_obj)
|
||||
|
||||
# Other scatter radius parameters
|
||||
items = endf.get_cont_record(file_obj)
|
||||
target_spin = items[0]
|
||||
lcomp = items[3] # Flag for compatibility 0, 1, 2 - 2 is compact form
|
||||
nls = items[4] # number of l-values
|
||||
|
||||
# Build covariance matrix for General Resolved Resonance Formats
|
||||
if lcomp == 1:
|
||||
items = endf.get_cont_record(file_obj)
|
||||
# Number of short range type resonance covariances
|
||||
num_short_range = items[4]
|
||||
# Number of long range type resonance covariances
|
||||
num_long_range = items[5]
|
||||
|
||||
# Read resonance widths, J values, etc
|
||||
records = []
|
||||
for i in range(num_short_range):
|
||||
items, values = endf.get_list_record(file_obj)
|
||||
mpar = items[2]
|
||||
num_res = items[5]
|
||||
num_par_vals = num_res*6
|
||||
res_values = values[:num_par_vals]
|
||||
cov_values = values[num_par_vals:]
|
||||
|
||||
energy = res_values[0::6]
|
||||
spin = res_values[1::6]
|
||||
gt = res_values[2::6]
|
||||
gn = res_values[3::6]
|
||||
gg = res_values[4::6]
|
||||
gf = res_values[5::6]
|
||||
|
||||
for i, E in enumerate(energy):
|
||||
records.append([energy[i], spin[i], gt[i], gn[i],
|
||||
gg[i], gf[i]])
|
||||
|
||||
# Build the upper-triangular covariance matrix
|
||||
cov_dim = mpar*num_res
|
||||
cov = np.zeros([cov_dim, cov_dim])
|
||||
indices = np.triu_indices(cov_dim)
|
||||
cov[indices] = cov_values
|
||||
|
||||
# Compact format - Resonances and individual uncertainties followed by
|
||||
# compact correlations
|
||||
elif lcomp == 2:
|
||||
items, values = endf.get_list_record(file_obj)
|
||||
mean = items
|
||||
num_res = items[5]
|
||||
energy = values[0::12]
|
||||
spin = values[1::12]
|
||||
gt = values[2::12]
|
||||
gn = values[3::12]
|
||||
gg = values[4::12]
|
||||
gf = values[5::12]
|
||||
par_unc = []
|
||||
for i in range(num_res):
|
||||
res_unc = values[i*12+6 : i*12+12]
|
||||
# Delete 0 values (not provided, no fission width)
|
||||
# DAJ/DGT always zero, DGF sometimes nonzero [1, 2, 5]
|
||||
res_unc_nonzero = []
|
||||
for j in range(6):
|
||||
if j in [1, 2, 5] and res_unc[j] != 0.0:
|
||||
res_unc_nonzero.append(res_unc[j])
|
||||
elif j in [0, 3, 4]:
|
||||
res_unc_nonzero.append(res_unc[j])
|
||||
par_unc.extend(res_unc_nonzero)
|
||||
|
||||
records = []
|
||||
for i, E in enumerate(energy):
|
||||
records.append([energy[i], spin[i], gt[i], gn[i],
|
||||
gg[i], gf[i]])
|
||||
|
||||
corr = endf.get_intg_record(file_obj)
|
||||
cov = np.diag(par_unc).dot(corr).dot(np.diag(par_unc))
|
||||
|
||||
# Compatible resolved resonance format
|
||||
elif lcomp == 0:
|
||||
cov = np.zeros([4, 4])
|
||||
records = []
|
||||
cov_index = 0
|
||||
for i in range(nls):
|
||||
items, values = endf.get_list_record(file_obj)
|
||||
num_res = items[5]
|
||||
for j in range(num_res):
|
||||
one_res = values[18*j:18*(j+1)]
|
||||
res_values = one_res[:6]
|
||||
cov_values = one_res[6:]
|
||||
records.append(list(res_values))
|
||||
|
||||
# Populate the coviariance matrix for this resonance
|
||||
# There are no covariances between resonances in lcomp=0
|
||||
cov[cov_index, cov_index] = cov_values[0]
|
||||
cov[cov_index+1, cov_index+1 : cov_index+2] = cov_values[1:2]
|
||||
cov[cov_index+1, cov_index+3] = cov_values[4]
|
||||
cov[cov_index+2, cov_index+2] = cov_values[3]
|
||||
cov[cov_index+2, cov_index+3] = cov_values[5]
|
||||
cov[cov_index+3, cov_index+3] = cov_values[6]
|
||||
|
||||
cov_index += 4
|
||||
if j < num_res-1: # Pad matrix for additional values
|
||||
cov = np.pad(cov, ((0, 4), (0, 4)), 'constant',
|
||||
constant_values=0)
|
||||
|
||||
# Create pandas DataFrame with resonance data, currently
|
||||
# redundant with data.IncidentNeutron.resonance
|
||||
columns = ['energy', 'J', 'totalWidth', 'neutronWidth',
|
||||
'captureWidth', 'fissionWidth']
|
||||
parameters = pd.DataFrame.from_records(records, columns=columns)
|
||||
# Determine mpar (number of parameters for each resonance in
|
||||
# covariance matrix)
|
||||
nparams, params = parameters.shape
|
||||
covsize = cov.shape[0]
|
||||
mpar = int(covsize/nparams)
|
||||
# Add parameters from File 2
|
||||
parameters = _add_file2_contributions(parameters,
|
||||
resonance.parameters)
|
||||
# Create instance of class
|
||||
mlbw = cls(energy_min, energy_max, parameters, cov, mpar, lcomp,
|
||||
resonance)
|
||||
return mlbw
|
||||
|
||||
|
||||
class SingleLevelBreitWignerCovariance(MultiLevelBreitWignerCovariance):
|
||||
"""Single-level Breit-Wigner resolved resonance formalism covariance data.
|
||||
Single-level Breit-Wigner resolved resonance data is is identified by LRF=1
|
||||
in the ENDF-6 format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
energy_min : float
|
||||
Minimum energy of the resolved resonance range in eV
|
||||
energy_max : float
|
||||
Maximum energy of the resolved resonance range in eV
|
||||
|
||||
Attributes
|
||||
----------
|
||||
energy_min : float
|
||||
Minimum energy of the resolved resonance range in eV
|
||||
energy_max : float
|
||||
Maximum energy of the resolved resonance range in eV
|
||||
parameters : pandas.DataFrame
|
||||
Resonance parameters
|
||||
covariance : numpy.array
|
||||
The covariance matrix contained within the ENDF evaluation
|
||||
mpar : int
|
||||
Number of parameters in covariance matrix for each individual resonance
|
||||
formalism : str
|
||||
String descriptor of formalism
|
||||
lcomp : int
|
||||
Flag indicating format of the covariance matrix within the ENDF file
|
||||
file2res : openmc.data.ResonanceRange object
|
||||
Corresponding resonance range with File 2 data.
|
||||
"""
|
||||
|
||||
def __init__(self, energy_min, energy_max, parameters, covariance, mpar,
|
||||
lcomp, file2res):
|
||||
super().__init__(energy_min, energy_max, parameters, covariance, mpar,
|
||||
lcomp, file2res)
|
||||
self.formalism = 'slbw'
|
||||
|
||||
|
||||
class ReichMooreCovariance(ResonanceCovarianceRange):
|
||||
"""Reich-Moore resolved resonance formalism covariance data.
|
||||
|
||||
Reich-Moore resolved resonance data is identified by LRF=3 in the ENDF-6
|
||||
format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
energy_min : float
|
||||
Minimum energy of the resolved resonance range in eV
|
||||
energy_max : float
|
||||
Maximum energy of the resolved resonance range in eV
|
||||
|
||||
Attributes
|
||||
----------
|
||||
energy_min : float
|
||||
Minimum energy of the resolved resonance range in eV
|
||||
energy_max : float
|
||||
Maximum energy of the resolved resonance range in eV
|
||||
parameters : pandas.DataFrame
|
||||
Resonance parameters
|
||||
covariance : numpy.array
|
||||
The covariance matrix contained within the ENDF evaluation
|
||||
lcomp : int
|
||||
Flag indicating format of the covariance matrix within the ENDF file
|
||||
mpar : int
|
||||
Number of parameters in covariance matrix for each individual resonance
|
||||
file2res : openmc.data.ResonanceRange object
|
||||
Corresponding resonance range with File 2 data.
|
||||
formalism : str
|
||||
String descriptor of formalism
|
||||
"""
|
||||
|
||||
def __init__(self, energy_min, energy_max, parameters, covariance, mpar,
|
||||
lcomp, file2res):
|
||||
super().__init__(energy_min, energy_max)
|
||||
self.parameters = parameters
|
||||
self.covariance = covariance
|
||||
self.mpar = mpar
|
||||
self.lcomp = lcomp
|
||||
self.file2res = copy.copy(file2res)
|
||||
self.formalism = 'rm'
|
||||
|
||||
@classmethod
|
||||
def from_endf(cls, ev, file_obj, items, resonance):
|
||||
"""Create Reich-Moore resonance covariance data from an ENDF
|
||||
evaluation. Includes the resonance parameters contained separately in
|
||||
File 32.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ev : openmc.data.endf.Evaluation
|
||||
ENDF evaluation
|
||||
file_obj : file-like object
|
||||
ENDF file positioned at the second record of a resonance range
|
||||
subsection in MF=2, MT=151
|
||||
items : list
|
||||
Items from the CONT record at the start of the resonance range
|
||||
subsection
|
||||
resonance : openmc.data.Resonance object
|
||||
openmc.data.Resonanance object generated from the same evaluation
|
||||
used to import values not contained in File 32
|
||||
|
||||
Returns
|
||||
-------
|
||||
openmc.data.ReichMooreCovariance
|
||||
Reich-Moore resonance covariance parameters
|
||||
|
||||
"""
|
||||
# Read energy-dependent scattering radius if present
|
||||
energy_min, energy_max = items[0:2]
|
||||
nro, naps = items[4:6]
|
||||
if nro != 0:
|
||||
params, ape = endf.get_tab1_record(file_obj)
|
||||
|
||||
# Other scatter radius parameters
|
||||
items = endf.get_cont_record(file_obj)
|
||||
target_spin = items[0]
|
||||
lcomp = items[3] # Flag for compatibility 0, 1, 2 - 2 is compact form
|
||||
nls = items[4] # Number of l-values
|
||||
|
||||
# Build covariance matrix for General Resolved Resonance Formats
|
||||
if lcomp == 1:
|
||||
items = endf.get_cont_record(file_obj)
|
||||
# Number of short range type resonance covariances
|
||||
num_short_range = items[4]
|
||||
# Number of long range type resonance covariances
|
||||
num_long_range = items[5]
|
||||
# Read resonance widths, J values, etc
|
||||
channel_radius = {}
|
||||
scattering_radius = {}
|
||||
records = []
|
||||
for i in range(num_short_range):
|
||||
items, values = endf.get_list_record(file_obj)
|
||||
mpar = items[2]
|
||||
num_res = items[5]
|
||||
num_par_vals = num_res*6
|
||||
res_values = values[:num_par_vals]
|
||||
cov_values = values[num_par_vals:]
|
||||
|
||||
energy = res_values[0::6]
|
||||
spin = res_values[1::6]
|
||||
gn = res_values[2::6]
|
||||
gg = res_values[3::6]
|
||||
gfa = res_values[4::6]
|
||||
gfb = res_values[5::6]
|
||||
|
||||
for i, E in enumerate(energy):
|
||||
records.append([energy[i], spin[i], gn[i], gg[i],
|
||||
gfa[i], gfb[i]])
|
||||
|
||||
# Build the upper-triangular covariance matrix
|
||||
cov_dim = mpar*num_res
|
||||
cov = np.zeros([cov_dim, cov_dim])
|
||||
indices = np.triu_indices(cov_dim)
|
||||
cov[indices] = cov_values
|
||||
|
||||
# Compact format - Resonances and individual uncertainties followed by
|
||||
# compact correlations
|
||||
elif lcomp == 2:
|
||||
items, values = endf.get_list_record(file_obj)
|
||||
num_res = items[5]
|
||||
energy = values[0::12]
|
||||
spin = values[1::12]
|
||||
gn = values[2::12]
|
||||
gg = values[3::12]
|
||||
gfa = values[4::12]
|
||||
gfb = values[5::12]
|
||||
par_unc = []
|
||||
for i in range(num_res):
|
||||
res_unc = values[i*12+6 : i*12+12]
|
||||
# Delete 0 values (not provided in evaluation)
|
||||
res_unc = [x for x in res_unc if x != 0.0]
|
||||
par_unc.extend(res_unc)
|
||||
|
||||
records = []
|
||||
for i, E in enumerate(energy):
|
||||
records.append([energy[i], spin[i], gn[i], gg[i],
|
||||
gfa[i], gfb[i]])
|
||||
|
||||
corr = endf.get_intg_record(file_obj)
|
||||
cov = np.diag(par_unc).dot(corr).dot(np.diag(par_unc))
|
||||
|
||||
# Create pandas DataFrame with resonacne data
|
||||
columns = ['energy', 'J', 'neutronWidth', 'captureWidth',
|
||||
'fissionWidthA', 'fissionWidthB']
|
||||
parameters = pd.DataFrame.from_records(records, columns=columns)
|
||||
|
||||
# Determine mpar (number of parameters for each resonance in
|
||||
# covariance matrix)
|
||||
nparams, params = parameters.shape
|
||||
covsize = cov.shape[0]
|
||||
mpar = int(covsize/nparams)
|
||||
|
||||
# Add parameters from File 2
|
||||
parameters = _add_file2_contributions(parameters,
|
||||
resonance.parameters)
|
||||
# Create instance of ReichMooreCovariance
|
||||
rmc = cls(energy_min, energy_max, parameters, cov, mpar, lcomp,
|
||||
resonance)
|
||||
return rmc
|
||||
|
||||
|
||||
_FORMALISMS = {
|
||||
0: ResonanceCovarianceRange,
|
||||
1: SingleLevelBreitWignerCovariance,
|
||||
2: MultiLevelBreitWignerCovariance,
|
||||
3: ReichMooreCovariance
|
||||
# 7: RMatrixLimitedCovariance
|
||||
}
|
||||
|
|
@ -24,40 +24,44 @@ from openmc.stats import Discrete, Tabular
|
|||
|
||||
|
||||
_THERMAL_NAMES = {
|
||||
'c_Al27': ('al', 'al27'),
|
||||
'c_Be': ('be', 'be-metal'),
|
||||
'c_BeO': ('beo'),
|
||||
'c_Be_in_BeO': ('bebeo', 'be-o', 'be/o'),
|
||||
'c_Al27': ('al', 'al27', 'al-27'),
|
||||
'c_Be': ('be', 'be-metal', 'be-met'),
|
||||
'c_BeO': ('beo',),
|
||||
'c_Be_in_BeO': ('bebeo', 'be-beo', 'be-o', 'be/o'),
|
||||
'c_C6H6': ('benz', 'c6h6'),
|
||||
'c_C_in_SiC': ('csic',),
|
||||
'c_Ca_in_CaH2': ('cah'),
|
||||
'c_D_in_D2O': ('dd2o', 'hwtr', 'hw'),
|
||||
'c_Fe56': ('fe', 'fe56'),
|
||||
'c_C_in_SiC': ('csic', 'c-sic'),
|
||||
'c_Ca_in_CaH2': ('cah',),
|
||||
'c_D_in_D2O': ('dd2o', 'd-d2o', 'hwtr', 'hw'),
|
||||
'c_Fe56': ('fe', 'fe56', 'fe-56'),
|
||||
'c_Graphite': ('graph', 'grph', 'gr'),
|
||||
'c_H_in_CaH2': ('hcah2'),
|
||||
'c_H_in_CH2': ('hch2', 'poly', 'pol'),
|
||||
'c_Graphite_10p': ('grph10',),
|
||||
'c_Graphite_30p': ('grph30',),
|
||||
'c_H_in_CaH2': ('hcah2',),
|
||||
'c_H_in_CH2': ('hch2', 'poly', 'pol', 'h-poly'),
|
||||
'c_H_in_CH4_liquid': ('lch4', 'lmeth'),
|
||||
'c_H_in_CH4_solid': ('sch4', 'smeth'),
|
||||
'c_H_in_H2O': ('hh2o', 'lwtr', 'lw'),
|
||||
'c_H_in_H2O_solid': ('hice',),
|
||||
'c_H_in_C5O2H8': ('lucite', 'c5o2h8'),
|
||||
'c_H_in_YH2': ('hyh2'),
|
||||
'c_H_in_ZrH': ('hzrh', 'h-zr', 'h/zr', 'hzr'),
|
||||
'c_H_in_H2O': ('hh2o', 'h-h2o', 'lwtr', 'lw'),
|
||||
'c_H_in_H2O_solid': ('hice', 'h-ice'),
|
||||
'c_H_in_C5O2H8': ('lucite', 'c5o2h8', 'h-luci'),
|
||||
'c_H_in_YH2': ('hyh2', 'h-yh2'),
|
||||
'c_H_in_ZrH': ('hzrh', 'h-zrh', 'h-zr', 'h/zr', 'hzr'),
|
||||
'c_Mg24': ('mg', 'mg24'),
|
||||
'c_O_in_BeO': ('obeo', 'o-be', 'o/be'),
|
||||
'c_O_in_D2O': ('od2o'),
|
||||
'c_O_in_H2O_ice': ('oice'),
|
||||
'c_O_in_UO2': ('ouo2', 'o2-u', 'o2/u'),
|
||||
'c_ortho_D': ('orthod', 'dortho'),
|
||||
'c_ortho_H': ('orthoh', 'hortho'),
|
||||
'c_Si_in_SiC': ('sisic'),
|
||||
'c_O_in_BeO': ('obeo', 'o-beo', 'o-be', 'o/be'),
|
||||
'c_O_in_D2O': ('od2o', 'o-d2o'),
|
||||
'c_O_in_H2O_ice': ('oice', 'o-ice'),
|
||||
'c_O_in_UO2': ('ouo2', 'o-uo2', 'o2-u', 'o2/u'),
|
||||
'c_N_in_UN': ('n-un',),
|
||||
'c_ortho_D': ('orthod', 'orthoD', 'dortho'),
|
||||
'c_ortho_H': ('orthoh', 'orthoH', 'hortho'),
|
||||
'c_Si_in_SiC': ('sisic', 'si-sic'),
|
||||
'c_SiO2_alpha': ('sio2', 'sio2a'),
|
||||
'c_SiO2_beta': ('sio2b'),
|
||||
'c_para_D': ('parad', 'dpara'),
|
||||
'c_para_H': ('parah', 'hpara'),
|
||||
'c_U_in_UO2': ('uuo2', 'u-o2', 'u/o2'),
|
||||
'c_Y_in_YH2': ('yyh2'),
|
||||
'c_Zr_in_ZrH': ('zrzrh', 'zr-h', 'zr/h')
|
||||
'c_SiO2_beta': ('sio2b',),
|
||||
'c_para_D': ('parad', 'paraD', 'dpara'),
|
||||
'c_para_H': ('parah', 'paraH', 'hpara'),
|
||||
'c_U_in_UN': ('u-un',),
|
||||
'c_U_in_UO2': ('uuo2', 'u-uo2', 'u-o2', 'u/o2'),
|
||||
'c_Y_in_YH2': ('yyh2', 'y-yh2'),
|
||||
'c_Zr_in_ZrH': ('zrzrh', 'zr-zrh', 'zr-h', 'zr/h')
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ class LegendreFilter(ExpansionFilter):
|
|||
r"""Score Legendre expansion moments up to specified order.
|
||||
|
||||
This filter allows scores to be multiplied by Legendre polynomials of the
|
||||
change in particle angle ($\mu$) up to a user-specified order.
|
||||
change in particle angle (:math:`\mu`) up to a user-specified order.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
|
|
|||
|
|
@ -208,12 +208,12 @@ class Mesh(IDManagerMixin):
|
|||
|
||||
shape = np.array(lattice.shape)
|
||||
width = lattice.pitch*shape
|
||||
|
||||
|
||||
mesh = cls(mesh_id, name)
|
||||
mesh.lower_left = lattice.lower_left
|
||||
mesh.upper_right = lattice.lower_left + width
|
||||
mesh.dimension = shape*division
|
||||
|
||||
|
||||
return mesh
|
||||
|
||||
def to_xml_element(self):
|
||||
|
|
@ -333,14 +333,16 @@ class Mesh(IDManagerMixin):
|
|||
if n_dim == 1:
|
||||
universe_array = np.array([universes])
|
||||
elif n_dim == 2:
|
||||
universe_array = np.empty(self.dimension, dtype=openmc.Universe)
|
||||
universe_array = np.empty(self.dimension[::-1],
|
||||
dtype=openmc.Universe)
|
||||
i = 0
|
||||
for y in range(self.dimension[1] - 1, -1, -1):
|
||||
for x in range(self.dimension[0]):
|
||||
universe_array[y][x] = universes[i]
|
||||
i += 1
|
||||
else:
|
||||
universe_array = np.empty(self.dimension, dtype=openmc.Universe)
|
||||
universe_array = np.empty(self.dimension[::-1],
|
||||
dtype=openmc.Universe)
|
||||
i = 0
|
||||
for z in range(self.dimension[2]):
|
||||
for y in range(self.dimension[1] - 1, -1, -1):
|
||||
|
|
|
|||
80
readme.rst
80
readme.rst
|
|
@ -1,80 +0,0 @@
|
|||
==========================================
|
||||
OpenMC Monte Carlo Particle Transport Code
|
||||
==========================================
|
||||
|
||||
|licensebadge| |travisbadge| |coverallsbadge|
|
||||
|
||||
The OpenMC project aims to provide a fully-featured Monte Carlo particle
|
||||
transport code based on modern methods. It is a constructive solid geometry,
|
||||
continuous-energy transport code that uses HDF5 format cross sections. The
|
||||
project started under the Computational Reactor Physics Group at MIT.
|
||||
|
||||
Complete documentation on the usage of OpenMC is hosted on Read the Docs (both
|
||||
for the `latest release`_ and developmental_ version). If you are interested in
|
||||
the project or would like to help and contribute, please send a message to the
|
||||
OpenMC User's Group `mailing list`_.
|
||||
|
||||
------------
|
||||
Installation
|
||||
------------
|
||||
|
||||
Detailed `installation instructions`_ can be found in the User's Guide.
|
||||
|
||||
------
|
||||
Citing
|
||||
------
|
||||
|
||||
If you use OpenMC in your research, please consider giving proper attribution by
|
||||
citing the following publication:
|
||||
|
||||
- Paul K. Romano, Nicholas E. Horelik, Bryan R. Herman, Adam G. Nelson, Benoit
|
||||
Forget, and Kord Smith, "`OpenMC: A State-of-the-Art Monte Carlo Code for
|
||||
Research and Development <https://doi.org/10.1016/j.anucene.2014.07.048>`_,"
|
||||
*Ann. Nucl. Energy*, **82**, 90--97 (2015).
|
||||
|
||||
---------------
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
If you run into problems compiling, installing, or running OpenMC, first check
|
||||
the `Troubleshooting section`_ in the User's Guide. If you are not able to find
|
||||
a solution to your problem there, please send a message to the User's Group
|
||||
`mailing list`_.
|
||||
|
||||
--------------
|
||||
Reporting Bugs
|
||||
--------------
|
||||
|
||||
OpenMC is hosted on GitHub and all bugs are reported and tracked through the
|
||||
Issues_ feature on GitHub. However, GitHub Issues should not be used for common
|
||||
troubleshooting purposes. If you are having trouble installing the code or
|
||||
getting your model to run properly, you should first send a message to the
|
||||
User's Group `mailing list`_. If it turns out your issue really is a bug in the
|
||||
code, an issue will then be created on GitHub. If you want to request that a
|
||||
feature be added to the code, you may create an Issue on github.
|
||||
|
||||
-------
|
||||
License
|
||||
-------
|
||||
|
||||
OpenMC is distributed under the MIT/X license_.
|
||||
|
||||
.. _latest release: http://openmc.readthedocs.io/en/stable/
|
||||
.. _developmental: http://openmc.readthedocs.io/en/latest/
|
||||
.. _mailing list: https://groups.google.com/forum/?fromgroups=#!forum/openmc-users
|
||||
.. _installation instructions: http://openmc.readthedocs.io/en/stable/usersguide/install.html
|
||||
.. _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)
|
||||
|
||||
.. |coverallsbadge| image:: https://coveralls.io/repos/github/mit-crpg/openmc/badge.svg?branch=develop
|
||||
:target: https://coveralls.io/github/mit-crpg/openmc?branch=develop
|
||||
:alt: Code Coverage
|
||||
2
setup.py
2
setup.py
|
|
@ -39,7 +39,7 @@ kwargs = {
|
|||
'author': 'The OpenMC Development Team',
|
||||
'author_email': 'openmc-dev@googlegroups.com',
|
||||
'description': 'OpenMC',
|
||||
'url': 'https://github.com/mit-crpg/openmc',
|
||||
'url': 'https://github.com/openmc-dev/openmc',
|
||||
'classifiers': [
|
||||
'Development Status :: 4 - Beta',
|
||||
'Intended Audience :: Developers',
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ contains
|
|||
index_ufs_mesh = -1
|
||||
keff = ONE
|
||||
legendre_to_tabular = .true.
|
||||
legendre_to_tabular_points = 33
|
||||
legendre_to_tabular_points = C_NONE
|
||||
n_batch_interval = 1
|
||||
n_lost_particles = 0
|
||||
n_particles = 0
|
||||
|
|
@ -310,7 +310,6 @@ contains
|
|||
subroutine free_memory()
|
||||
|
||||
use cmfd_header
|
||||
use mgxs_header
|
||||
use plot_header
|
||||
use sab_header
|
||||
use settings
|
||||
|
|
@ -328,7 +327,6 @@ contains
|
|||
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()
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "hdf5.h"
|
||||
#include "pugixml/pugixml.hpp"
|
||||
#include "pugixml.hpp"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
|
@ -50,7 +50,7 @@ public:
|
|||
//! A geometry primitive that links surfaces, universes, and materials
|
||||
//==============================================================================
|
||||
|
||||
class Cell
|
||||
class Cell
|
||||
{
|
||||
public:
|
||||
int32_t id; //!< Unique ID
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ module cmfd_input
|
|||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use cmfd_header
|
||||
use mesh_header, only: mesh_dict
|
||||
use mgxs_header, only: energy_bins
|
||||
use mesh_header, only: mesh_dict
|
||||
use mgxs_interface, only: energy_bins, num_energy_groups
|
||||
use tally
|
||||
use tally_header
|
||||
use timer_header
|
||||
|
|
|
|||
|
|
@ -405,6 +405,25 @@ module constants
|
|||
DIFF_NUCLIDE_DENSITY = 2, &
|
||||
DIFF_TEMPERATURE = 3
|
||||
|
||||
|
||||
! Mgxs::get_xs enumerated types
|
||||
integer(C_INT), parameter :: &
|
||||
MG_GET_XS_TOTAL = 0, &
|
||||
MG_GET_XS_ABSORPTION = 1, &
|
||||
MG_GET_XS_INVERSE_VELOCITY = 2, &
|
||||
MG_GET_XS_DECAY_RATE = 3, &
|
||||
MG_GET_XS_SCATTER = 4, &
|
||||
MG_GET_XS_SCATTER_MULT = 5, &
|
||||
MG_GET_XS_SCATTER_FMU_MULT = 6, &
|
||||
MG_GET_XS_SCATTER_FMU = 7, &
|
||||
MG_GET_XS_FISSION = 8, &
|
||||
MG_GET_XS_KAPPA_FISSION = 9, &
|
||||
MG_GET_XS_PROMPT_NU_FISSION = 10, &
|
||||
MG_GET_XS_DELAYED_NU_FISSION = 11, &
|
||||
MG_GET_XS_NU_FISSION = 12, &
|
||||
MG_GET_XS_CHI_PROMPT = 13, &
|
||||
MG_GET_XS_CHI_DELAYED = 14
|
||||
|
||||
! ============================================================================
|
||||
! RANDOM NUMBER STREAM CONSTANTS
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,85 @@
|
|||
//! \file constants.h
|
||||
//! A collection of constants
|
||||
|
||||
#ifndef CONSTANTS_H
|
||||
#define CONSTANTS_H
|
||||
|
||||
#include <cmath>
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
namespace openmc {
|
||||
|
||||
namespace openmc{
|
||||
typedef std::vector<double> double_1dvec;
|
||||
typedef std::vector<std::vector<double> > double_2dvec;
|
||||
typedef std::vector<std::vector<std::vector<double> > > double_3dvec;
|
||||
typedef std::vector<std::vector<std::vector<std::vector<double> > > > double_4dvec;
|
||||
typedef std::vector<std::vector<std::vector<std::vector<std::vector<double> > > > > double_5dvec;
|
||||
typedef std::vector<std::vector<std::vector<std::vector<std::vector<std::vector<double> > > > > > double_6dvec;
|
||||
typedef std::vector<int> int_1dvec;
|
||||
typedef std::vector<std::vector<int> > int_2dvec;
|
||||
typedef std::vector<std::vector<std::vector<int> > > int_3dvec;
|
||||
|
||||
constexpr int MAX_SAMPLE {10000};
|
||||
|
||||
constexpr std::array<int, 3> VERSION {0, 10, 0};
|
||||
constexpr std::array<int, 2> VERSION_PARTICLE_RESTART {2, 0};
|
||||
|
||||
// Maximum number of words in a single line, length of line, and length of
|
||||
// single word
|
||||
constexpr int MAX_WORDS {500};
|
||||
constexpr int MAX_LINE_LEN {250};
|
||||
constexpr int MAX_WORD_LEN {150};
|
||||
constexpr int MAX_FILE_LEN {255};
|
||||
|
||||
// Physical Constants
|
||||
constexpr double K_BOLTZMANN {8.6173303e-5}; // Boltzmann constant in eV/K
|
||||
|
||||
// Angular distribution type
|
||||
constexpr int ANGLE_ISOTROPIC {1};
|
||||
constexpr int ANGLE_32_EQUI {2};
|
||||
constexpr int ANGLE_TABULAR {3};
|
||||
constexpr int ANGLE_LEGENDRE {4};
|
||||
constexpr int ANGLE_HISTOGRAM {5};
|
||||
|
||||
// MGXS Table Types
|
||||
constexpr int MGXS_ISOTROPIC {1}; // Isotroically weighted data
|
||||
constexpr int MGXS_ANGLE {2}; // Data by angular bins
|
||||
|
||||
// Flag to denote this was a macroscopic data object
|
||||
constexpr double MACROSCOPIC_AWR {-2.};
|
||||
|
||||
// Number of mu bins to use when converting Legendres to tabular type
|
||||
constexpr int DEFAULT_NMU {33};
|
||||
|
||||
// Temperature treatment method
|
||||
constexpr int TEMPERATURE_NEAREST {1};
|
||||
constexpr int TEMPERATURE_INTERPOLATION {2};
|
||||
|
||||
// TODO: cmath::M_PI has 3 more digits precision than the Fortran constant we
|
||||
// use so for now we will reuse the Fortran constant until we are OK with
|
||||
// modifying test results
|
||||
constexpr double PI {3.1415926535898};
|
||||
|
||||
const double SQRT_PI {std::sqrt(PI)};
|
||||
|
||||
// Mgxs::get_xs enumerated types
|
||||
constexpr int MG_GET_XS_TOTAL {0};
|
||||
constexpr int MG_GET_XS_ABSORPTION {1};
|
||||
constexpr int MG_GET_XS_INVERSE_VELOCITY {2};
|
||||
constexpr int MG_GET_XS_DECAY_RATE {3};
|
||||
constexpr int MG_GET_XS_SCATTER {4};
|
||||
constexpr int MG_GET_XS_SCATTER_MULT {5};
|
||||
constexpr int MG_GET_XS_SCATTER_FMU_MULT {6};
|
||||
constexpr int MG_GET_XS_SCATTER_FMU {7};
|
||||
constexpr int MG_GET_XS_FISSION {8};
|
||||
constexpr int MG_GET_XS_KAPPA_FISSION {9};
|
||||
constexpr int MG_GET_XS_PROMPT_NU_FISSION {10};
|
||||
constexpr int MG_GET_XS_DELAYED_NU_FISSION {11};
|
||||
constexpr int MG_GET_XS_NU_FISSION {12};
|
||||
constexpr int MG_GET_XS_CHI_PROMPT {13};
|
||||
constexpr int MG_GET_XS_CHI_DELAYED {14};
|
||||
|
||||
extern "C" double FP_COINCIDENT;
|
||||
extern "C" double FP_PRECISION;
|
||||
|
|
|
|||
216
src/doppler.F90
216
src/doppler.F90
|
|
@ -1,216 +0,0 @@
|
|||
module doppler
|
||||
|
||||
use constants, only: ZERO, ONE, PI, K_BOLTZMANN
|
||||
|
||||
implicit none
|
||||
|
||||
real(8), parameter :: sqrt_pi_inv = ONE / sqrt(PI)
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! BROADEN takes a microscopic cross section at a temperature T_1 and Doppler
|
||||
! broadens it to a higher temperature T_2 based on a method originally developed
|
||||
! by Cullen and Weisbin (see "Exact Doppler Broadening of Tabulated Cross
|
||||
! Sections," Nucl. Sci. Eng. 60, 199-229 (1976)). The only difference here is
|
||||
! the F functions are evaluated based on complementary error functions rather
|
||||
! than error functions as is done in the BROADR module of NJOY.
|
||||
!===============================================================================
|
||||
|
||||
subroutine broaden(energy, xs, A_target, T, sigmaNew)
|
||||
|
||||
real(8), intent(in) :: energy(:) ! energy grid
|
||||
real(8), intent(in) :: xs(:) ! unbroadened cross section
|
||||
integer, intent(in) :: A_target ! mass number of target
|
||||
real(8), intent(in) :: T ! temperature (difference)
|
||||
real(8), intent(out) :: sigmaNew(:) ! broadened cross section
|
||||
|
||||
integer :: i, k ! loop indices
|
||||
integer :: n ! number of energy points
|
||||
real(8) :: F_a(0:4) ! F(a) functions as per C&W
|
||||
real(8) :: F_b(0:4) ! F(b) functions as per C&W
|
||||
real(8) :: H(0:4) ! H functions as per C&W
|
||||
real(8), allocatable :: x(:) ! proportional to relative velocity
|
||||
real(8) :: y ! proportional to neutron velocity
|
||||
real(8) :: y_sq ! y**2
|
||||
real(8) :: y_inv ! 1/y
|
||||
real(8) :: y_inv_sq ! 1/y**2
|
||||
real(8) :: alpha ! constant equal to A/kT
|
||||
real(8) :: slope ! slope of xs between adjacent points
|
||||
real(8) :: Ak, Bk ! coefficients at each point
|
||||
real(8) :: a, b ! values of x(k)-y and x(k+1)-y
|
||||
real(8) :: sigma ! broadened cross section at one point
|
||||
|
||||
! Determine alpha parameter -- have to convert k to eV/K
|
||||
alpha = A_target/(K_BOLTZMANN * T)
|
||||
|
||||
! Allocate memory for x and assign values
|
||||
n = size(energy)
|
||||
allocate(x(n))
|
||||
x = sqrt(alpha * energy)
|
||||
|
||||
! Loop over incoming neutron energies
|
||||
ENERGY_NEUTRON: do i = 1, n
|
||||
|
||||
sigma = ZERO
|
||||
y = x(i)
|
||||
y_sq = y*y
|
||||
y_inv = ONE / y
|
||||
y_inv_sq = y_inv / y
|
||||
|
||||
! =======================================================================
|
||||
! EVALUATE FIRST TERM FROM x(k) - y = 0 to -4
|
||||
|
||||
k = i
|
||||
a = ZERO
|
||||
call calculate_F(F_a, a)
|
||||
|
||||
do while (a >= -4.0 .and. k > 1)
|
||||
! Move to next point
|
||||
F_b = F_a
|
||||
k = k - 1
|
||||
a = x(k) - y
|
||||
|
||||
! Calculate F and H functions
|
||||
call calculate_F(F_a, a)
|
||||
H = F_a - F_b
|
||||
|
||||
! Calculate A(k), B(k), and slope terms
|
||||
Ak = y_inv_sq*H(2) + 2.0*y_inv*H(1) + H(0)
|
||||
Bk = y_inv_sq*H(4) + 4.0*y_inv*H(3) + 6.0*H(2) + 4.0*y*H(1) + y_sq*H(0)
|
||||
slope = (xs(k+1) - xs(k)) / (x(k+1)**2 - x(k)**2)
|
||||
|
||||
! Add contribution to broadened cross section
|
||||
sigma = sigma + Ak*(xs(k) - slope*x(k)**2) + slope*Bk
|
||||
end do
|
||||
|
||||
! =======================================================================
|
||||
! EXTEND CROSS SECTION TO 0 ASSUMING 1/V SHAPE
|
||||
|
||||
if (k == 1 .and. a >= -4.0) then
|
||||
! Since x = 0, this implies that a = -y
|
||||
F_b = F_a
|
||||
a = -y
|
||||
|
||||
! Calculate F and H functions
|
||||
call calculate_F(F_a, a)
|
||||
H = F_a - F_b
|
||||
|
||||
! Add contribution to broadened cross section
|
||||
sigma = sigma + xs(k)*x(k)*(y_inv_sq*H(1) + y_inv*H(0))
|
||||
end if
|
||||
|
||||
! =======================================================================
|
||||
! EVALUATE FIRST TERM FROM x(k) - y = 0 to 4
|
||||
|
||||
k = i
|
||||
b = ZERO
|
||||
call calculate_F(F_b, b)
|
||||
|
||||
do while (b <= 4.0 .and. k < n)
|
||||
! Move to next point
|
||||
F_a = F_b
|
||||
k = k + 1
|
||||
b = x(k) - y
|
||||
|
||||
! Calculate F and H functions
|
||||
call calculate_F(F_b, b)
|
||||
H = F_a - F_b
|
||||
|
||||
! Calculate A(k), B(k), and slope terms
|
||||
Ak = y_inv_sq*H(2) + 2.0*y_inv*H(1) + H(0)
|
||||
Bk = y_inv_sq*H(4) + 4.0*y_inv*H(3) + 6.0*H(2) + 4.0*y*H(1) + y_sq*H(0)
|
||||
slope = (xs(k) - xs(k-1)) / (x(k)**2 - x(k-1)**2)
|
||||
|
||||
! Add contribution to broadened cross section
|
||||
sigma = sigma + Ak*(xs(k) - slope*x(k)**2) + slope*Bk
|
||||
end do
|
||||
|
||||
! =======================================================================
|
||||
! EXTEND CROSS SECTION TO INFINITY ASSUMING CONSTANT SHAPE
|
||||
|
||||
if (k == n .and. b <= 4.0) then
|
||||
! Calculate F function at last energy point
|
||||
a = x(k) - y
|
||||
call calculate_F(F_a, a)
|
||||
|
||||
! Add contribution to broadened cross section
|
||||
sigma = sigma + xs(k) * (y_inv_sq*F_a(2) + 2.0*y_inv*F_a(1) + F_a(0))
|
||||
end if
|
||||
|
||||
! =======================================================================
|
||||
! EVALUATE SECOND TERM FROM x(k) + y = 0 to +4
|
||||
|
||||
if (y <= 4.0) then
|
||||
! Swap signs on y
|
||||
y = -y
|
||||
y_inv = -y_inv
|
||||
k = 1
|
||||
|
||||
! Calculate a and b based on 0 and x(1)
|
||||
a = -y
|
||||
b = x(k) - y
|
||||
|
||||
! Calculate F and H functions
|
||||
call calculate_F(F_a, a)
|
||||
call calculate_F(F_b, b)
|
||||
H = F_a - F_b
|
||||
|
||||
! Add contribution to broadened cross section
|
||||
sigma = sigma - xs(k) * x(k) * (y_inv_sq*H(1) + y_inv*H(0))
|
||||
|
||||
! Now progress forward doing the remainder of the second term
|
||||
do while (b <= 4.0)
|
||||
! Move to next point
|
||||
F_a = F_b
|
||||
k = k + 1
|
||||
b = x(k) - y
|
||||
|
||||
! Calculate F and H functions
|
||||
call calculate_F(F_b, b)
|
||||
H = F_a - F_b
|
||||
|
||||
! Calculate A(k), B(k), and slope terms
|
||||
Ak = y_inv_sq*H(2) + 2.0*y_inv*H(1) + H(0)
|
||||
Bk = y_inv_sq*H(4) + 4.0*y_inv*H(3) + 6.0*H(2) + 4.0*y*H(1) &
|
||||
+ y_sq*H(0)
|
||||
slope = (xs(k) - xs(k-1)) / (x(k)**2 - x(k-1)**2)
|
||||
|
||||
! Add contribution to broadened cross section
|
||||
sigma = sigma - Ak*(xs(k) - slope*x(k)**2) - slope*Bk
|
||||
end do
|
||||
end if
|
||||
|
||||
! Set broadened cross section
|
||||
sigmaNew(i) = sigma
|
||||
|
||||
end do ENERGY_NEUTRON
|
||||
|
||||
end subroutine broaden
|
||||
|
||||
!===============================================================================
|
||||
! CALCULATE_F evaluates the function:
|
||||
!
|
||||
! F(n,a) = 1/sqrt(pi)*int(z^n*exp(-z^2), z = a to infinity)
|
||||
!
|
||||
! The five values returned in a vector correspond to the integral for n = 0
|
||||
! through 4. These functions are called over and over during the Doppler
|
||||
! broadening routine.
|
||||
!===============================================================================
|
||||
|
||||
subroutine calculate_F(F, a)
|
||||
|
||||
real(8), intent(inout) :: F(0:4)
|
||||
real(8), intent(in) :: a
|
||||
|
||||
#ifndef NO_F2008
|
||||
F(0) = 0.5*erfc(a)
|
||||
#endif
|
||||
F(1) = 0.5*sqrt_pi_inv*exp(-a*a)
|
||||
F(2) = 0.5*F(0) + a*F(1)
|
||||
F(3) = F(1)*(1.0 + a*a)
|
||||
F(4) = 0.75*F(0) + F(1)*a*(1.5 + a*a)
|
||||
|
||||
end subroutine calculate_F
|
||||
|
||||
end module doppler
|
||||
|
|
@ -37,7 +37,6 @@ module endf_header
|
|||
contains
|
||||
procedure :: from_hdf5 => polynomial_from_hdf5
|
||||
procedure :: evaluate => polynomial_evaluate
|
||||
procedure :: from_ace => polynomial_from_ace
|
||||
end type Polynomial
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -52,7 +51,6 @@ module endf_header
|
|||
real(8), allocatable :: x(:) ! values of abscissa
|
||||
real(8), allocatable :: y(:) ! values of ordinate
|
||||
contains
|
||||
procedure :: from_ace => tabulated1d_from_ace
|
||||
procedure :: from_hdf5 => tabulated1d_from_hdf5
|
||||
procedure :: evaluate => tabulated1d_evaluate
|
||||
end type Tabulated1D
|
||||
|
|
@ -63,24 +61,6 @@ contains
|
|||
! Polynomial implementation
|
||||
!===============================================================================
|
||||
|
||||
subroutine polynomial_from_ace(this, xss, idx)
|
||||
class(Polynomial), intent(inout) :: this
|
||||
real(8), intent(in) :: xss(:)
|
||||
integer, intent(in) :: idx
|
||||
|
||||
integer :: nc ! number of coefficients (order - 1)
|
||||
|
||||
! Clear space
|
||||
if (allocated(this % coef)) deallocate(this % coef)
|
||||
|
||||
! Determine number of coefficients
|
||||
nc = nint(xss(idx))
|
||||
|
||||
! Allocate space for and read coefficients
|
||||
allocate(this % coef(nc))
|
||||
this % coef(:) = xss(idx + 1 : idx + nc)
|
||||
end subroutine polynomial_from_ace
|
||||
|
||||
subroutine polynomial_from_hdf5(this, dset_id)
|
||||
class(Polynomial), intent(inout) :: this
|
||||
integer(HID_T), intent(in) :: dset_id
|
||||
|
|
@ -111,42 +91,6 @@ contains
|
|||
! Tabulated1D implementation
|
||||
!===============================================================================
|
||||
|
||||
subroutine tabulated1d_from_ace(this, xss, idx)
|
||||
class(Tabulated1D), intent(inout) :: this
|
||||
real(8), intent(in) :: xss(:)
|
||||
integer, intent(in) :: idx
|
||||
|
||||
integer :: nr, ne
|
||||
|
||||
! Clear space
|
||||
if (allocated(this % nbt)) deallocate(this % nbt)
|
||||
if (allocated(this % int)) deallocate(this % int)
|
||||
if (allocated(this % x)) deallocate(this % x)
|
||||
if (allocated(this % y)) deallocate(this % y)
|
||||
|
||||
! Determine number of regions
|
||||
nr = nint(xss(idx))
|
||||
this % n_regions = nr
|
||||
|
||||
! Read interpolation region data
|
||||
if (nr > 0) then
|
||||
allocate(this % nbt(nr))
|
||||
allocate(this % int(nr))
|
||||
this % nbt(:) = nint(xss(idx + 1 : idx + nr))
|
||||
this % int(:) = nint(xss(idx + nr + 1 : idx + 2*nr))
|
||||
end if
|
||||
|
||||
! Determine number of pairs
|
||||
ne = int(XSS(idx + 2*nr + 1))
|
||||
this % n_pairs = ne
|
||||
|
||||
! Read (x,y) pairs
|
||||
allocate(this % x(ne))
|
||||
allocate(this % y(ne))
|
||||
this % x(:) = xss(idx + 2*nr + 2 : idx + 2*nr + 1 + ne)
|
||||
this % y(:) = xss(idx + 2*nr + 2 + ne : idx + 2*nr + 1 + 2*ne)
|
||||
end subroutine tabulated1d_from_ace
|
||||
|
||||
subroutine tabulated1d_from_hdf5(this, dset_id)
|
||||
class(Tabulated1D), intent(inout) :: this
|
||||
integer(HID_T), intent(in) :: dset_id
|
||||
|
|
|
|||
|
|
@ -265,4 +265,13 @@ contains
|
|||
|
||||
end subroutine write_message
|
||||
|
||||
subroutine write_message_from_c(message, message_len, level) bind(C)
|
||||
integer(C_INT), intent(in), value :: message_len
|
||||
character(kind=C_CHAR), intent(in) :: message(message_len)
|
||||
integer(C_INT), intent(in), value :: level
|
||||
character(message_len+1) :: message_out
|
||||
write(message_out, *) message
|
||||
call write_message(message_out, level)
|
||||
end subroutine write_message_from_c
|
||||
|
||||
end module error
|
||||
|
|
|
|||
21
src/error.h
21
src/error.h
|
|
@ -11,7 +11,8 @@ namespace openmc {
|
|||
|
||||
extern "C" void fatal_error_from_c(const char* message, int message_len);
|
||||
extern "C" void warning_from_c(const char* message, int message_len);
|
||||
|
||||
extern "C" void write_message_from_c(const char* message, int message_len,
|
||||
int level);
|
||||
|
||||
inline
|
||||
void fatal_error(const char *message)
|
||||
|
|
@ -43,5 +44,23 @@ void warning(const std::stringstream& message)
|
|||
warning(message.str());
|
||||
}
|
||||
|
||||
inline
|
||||
void write_message(const char* message, int level)
|
||||
{
|
||||
write_message_from_c(message, strlen(message), level);
|
||||
}
|
||||
|
||||
inline
|
||||
void write_message(const std::string& message, int level)
|
||||
{
|
||||
write_message_from_c(message.c_str(), message.length(), level);
|
||||
}
|
||||
|
||||
inline
|
||||
void write_message(const std::stringstream& message, int level)
|
||||
{
|
||||
write_message(message.str(), level);
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
#endif // ERROR_H
|
||||
|
|
|
|||
|
|
@ -736,7 +736,7 @@ contains
|
|||
! 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)
|
||||
material_index = cells(index) % material(instance + 1)
|
||||
else
|
||||
material_index = cells(index) % material(1)
|
||||
end if
|
||||
|
|
|
|||
|
|
@ -447,6 +447,172 @@ read_complex(hid_t obj_id, const char* name, double _Complex* buffer, bool indep
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name, std::vector<double>& result,
|
||||
bool must_have)
|
||||
{
|
||||
if (object_exists(obj_id, name)) {
|
||||
read_double(obj_id, name, result.data(), true);
|
||||
} else if (must_have) {
|
||||
fatal_error(std::string("Must provide " + std::string(name) + "!"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<double> >& result, bool must_have)
|
||||
{
|
||||
if (object_exists(obj_id, name)) {
|
||||
int dim1 = result.size();
|
||||
int dim2 = result[0].size();
|
||||
double temp_arr[dim1 * dim2];
|
||||
read_double(obj_id, name, temp_arr, true);
|
||||
|
||||
int temp_idx = 0;
|
||||
for (int i = 0; i < dim1; i++) {
|
||||
for (int j = 0; j < dim2; j++) {
|
||||
result[i][j] = temp_arr[temp_idx++];
|
||||
}
|
||||
}
|
||||
} else if (must_have) {
|
||||
fatal_error(std::string("Must provide " + std::string(name) + "!"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<int> >& result, bool must_have)
|
||||
{
|
||||
if (object_exists(obj_id, name)) {
|
||||
int dim1 = result.size();
|
||||
int dim2 = result[0].size();
|
||||
int temp_arr[dim1 * dim2];
|
||||
read_int(obj_id, name, temp_arr, true);
|
||||
|
||||
int temp_idx = 0;
|
||||
for (int i = 0; i < dim1; i++) {
|
||||
for (int j = 0; j < dim2; j++) {
|
||||
result[i][j] = temp_arr[temp_idx++];
|
||||
}
|
||||
}
|
||||
} else if (must_have) {
|
||||
fatal_error(std::string("Must provide " + std::string(name) + "!"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<std::vector<double> > >& result,
|
||||
bool must_have)
|
||||
{
|
||||
if (object_exists(obj_id, name)) {
|
||||
int dim1 = result.size();
|
||||
int dim2 = result[0].size();
|
||||
int dim3 = result[0][0].size();
|
||||
double temp_arr[dim1 * dim2 * dim3];
|
||||
read_double(obj_id, name, temp_arr, true);
|
||||
|
||||
int temp_idx = 0;
|
||||
for (int i = 0; i < dim1; i++) {
|
||||
for (int j = 0; j < dim2; j++) {
|
||||
for (int k = 0; k < dim3; k++) {
|
||||
result[i][j][k] = temp_arr[temp_idx++];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (must_have) {
|
||||
fatal_error(std::string("Must provide " + std::string(name) + "!"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<std::vector<int> > >& result,
|
||||
bool must_have)
|
||||
{
|
||||
if (object_exists(obj_id, name)) {
|
||||
int dim1 = result.size();
|
||||
int dim2 = result[0].size();
|
||||
int dim3 = result[0][0].size();
|
||||
int temp_arr[dim1 * dim2 * dim3];
|
||||
read_int(obj_id, name, temp_arr, true);
|
||||
|
||||
int temp_idx = 0;
|
||||
for (int i = 0; i < dim1; i++) {
|
||||
for (int j = 0; j < dim2; j++) {
|
||||
for (int k = 0; k < dim3; k++) {
|
||||
result[i][j][k] = temp_arr[temp_idx++];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (must_have) {
|
||||
fatal_error(std::string("Must provide " + std::string(name) + "!"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<std::vector<std::vector<double> > > >& result,
|
||||
bool must_have)
|
||||
{
|
||||
if (object_exists(obj_id, name)) {
|
||||
int dim1 = result.size();
|
||||
int dim2 = result[0].size();
|
||||
int dim3 = result[0][0].size();
|
||||
int dim4 = result[0][0][0].size();
|
||||
double temp_arr[dim1 * dim2 * dim3 * dim4];
|
||||
read_double(obj_id, name, temp_arr, true);
|
||||
|
||||
int temp_idx = 0;
|
||||
for (int i = 0; i < dim1; i++) {
|
||||
for (int j = 0; j < dim2; j++) {
|
||||
for (int k = 0; k < dim3; k++) {
|
||||
for (int l = 0; l < dim4; l++) {
|
||||
result[i][j][k][l] = temp_arr[temp_idx++];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (must_have) {
|
||||
fatal_error(std::string("Must provide " + std::string(name) + "!"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<std::vector<std::vector<std::vector<double> > > > >& result,
|
||||
bool must_have)
|
||||
{
|
||||
if (object_exists(obj_id, name)) {
|
||||
int dim1 = result.size();
|
||||
int dim2 = result[0].size();
|
||||
int dim3 = result[0][0].size();
|
||||
int dim4 = result[0][0][0].size();
|
||||
int dim5 = result[0][0][0][0].size();
|
||||
double temp_arr[dim1 * dim2 * dim3 * dim4 * dim5];
|
||||
read_double(obj_id, name, temp_arr, true);
|
||||
|
||||
int temp_idx = 0;
|
||||
for (int i = 0; i < dim1; i++) {
|
||||
for (int j = 0; j < dim2; j++) {
|
||||
for (int k = 0; k < dim3; k++) {
|
||||
for (int l = 0; l < dim4; l++) {
|
||||
for (int m = 0; m < dim5; m++) {
|
||||
result[i][j][k][l][m] = temp_arr[temp_idx++];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (must_have) {
|
||||
fatal_error(std::string("Must provide " + std::string(name) + "!"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
read_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, double* results)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <array>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <complex.h>
|
||||
|
||||
|
||||
|
|
@ -55,6 +56,39 @@ extern "C" void read_string(hid_t obj_id, const char* name, size_t slen,
|
|||
extern "C" void read_complex(hid_t obj_id, const char* name,
|
||||
double _Complex* buffer, bool indep);
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name, std::vector<double>& result,
|
||||
bool must_have = false);
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<double> >& result,
|
||||
bool must_have = false);
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<int> >& result, bool must_have = false);
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<std::vector<double> > >& result,
|
||||
bool must_have = false);
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<std::vector<int> > >& result,
|
||||
bool must_have = false);
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<std::vector<std::vector<double> > > >& result,
|
||||
bool must_have = false);
|
||||
|
||||
void
|
||||
read_nd_vector(hid_t obj_id, const char* name,
|
||||
std::vector<std::vector<std::vector<std::vector<std::vector<double> > > > >& result,
|
||||
bool must_have = false);
|
||||
|
||||
extern "C" void read_tally_results(hid_t group_id, hsize_t n_filter,
|
||||
hsize_t n_score, double* results);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ module input_xml
|
|||
use mesh_header
|
||||
use message_passing
|
||||
use mgxs_data, only: create_macro_xs, read_mgxs
|
||||
use mgxs_header
|
||||
use mgxs_interface
|
||||
use nuclide_header
|
||||
use output, only: title, header, print_plot
|
||||
use plot_header
|
||||
|
|
@ -228,7 +228,7 @@ contains
|
|||
¬ exist! In order to run OpenMC, you first need a set of input &
|
||||
&files; at a minimum, this includes settings.xml, geometry.xml, &
|
||||
&and materials.xml. Please consult the user's guide at &
|
||||
&http://mit-crpg.github.io/openmc for further information.")
|
||||
&http://openmc.readthedocs.io for further information.")
|
||||
else
|
||||
! The settings.xml file is optional if we just want to make a plot.
|
||||
return
|
||||
|
|
@ -1369,7 +1369,7 @@ contains
|
|||
&materials.xml, settings.xml, or in the OPENMC_CROSS_SECTIONS&
|
||||
& environment variable. OpenMC needs such a file to identify &
|
||||
&where to find ACE cross section libraries. Please consult the&
|
||||
& user's guide at http://mit-crpg.github.io/openmc for &
|
||||
& user's guide at http://openmc.readthedocs.io for &
|
||||
&information on how to set up ACE cross section libraries.")
|
||||
else
|
||||
call warning("The CROSS_SECTIONS environment variable is &
|
||||
|
|
@ -1387,7 +1387,7 @@ contains
|
|||
&materials.xml or in the OPENMC_MG_CROSS_SECTIONS environment &
|
||||
&variable. OpenMC needs such a file to identify where to &
|
||||
&find MG cross section libraries. Please consult the user's &
|
||||
&guide at http://mit-crpg.github.io/openmc for information on &
|
||||
&guide at http://openmc.readthedocs.io for information on &
|
||||
&how to set up MG cross section libraries.")
|
||||
else if (len_trim(env_variable) /= 0) then
|
||||
path_cross_sections = trim(env_variable)
|
||||
|
|
@ -3458,7 +3458,7 @@ contains
|
|||
if (run_CE) then
|
||||
awr = nuclides(mat % nuclide(j)) % awr
|
||||
else
|
||||
awr = nuclides_MG(mat % nuclide(j)) % obj % awr
|
||||
awr = get_awr_c(mat % nuclide(j))
|
||||
end if
|
||||
|
||||
! if given weight percent, convert all values so that they are divided
|
||||
|
|
@ -3483,7 +3483,7 @@ contains
|
|||
if (run_CE) then
|
||||
awr = nuclides(mat % nuclide(j)) % awr
|
||||
else
|
||||
awr = nuclides_MG(mat % nuclide(j)) % obj % awr
|
||||
awr = get_awr_c(mat % nuclide(j))
|
||||
end if
|
||||
x = mat % atom_density(j)
|
||||
sum_percent = sum_percent + x*awr
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include "constants.h"
|
||||
#include "hdf5.h"
|
||||
#include "pugixml/pugixml.hpp"
|
||||
#include "pugixml.hpp"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ module material_header
|
|||
integer :: n_nuclides = 0 ! number of nuclides
|
||||
integer, allocatable :: nuclide(:) ! index in nuclides array
|
||||
real(8) :: density ! total atom density in atom/b-cm
|
||||
real(8), allocatable :: atom_density(:) ! nuclide atom density in atom/b-cm
|
||||
real(C_DOUBLE), allocatable :: atom_density(:) ! nuclide atom density in atom/b-cm
|
||||
real(8) :: density_gpcc ! total density in g/cm^3
|
||||
|
||||
! To improve performance of tallying, we store an array (direct address
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ void calc_pn_c(int n, double x, double pnx[]) {
|
|||
}
|
||||
|
||||
// Use recursion relation to build the higher orders
|
||||
for (int l = 1; l < n; l ++) {
|
||||
for (int l = 1; l < n; l++) {
|
||||
pnx[l + 1] = ((2 * l + 1) * x * pnx[l] - l * pnx[l - 1]) / (l + 1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,22 +7,12 @@
|
|||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "constants.h"
|
||||
#include "random_lcg.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// Module constants.
|
||||
//==============================================================================
|
||||
|
||||
// TODO: cmath::M_PI has 3 more digits precision than the Fortran constant we
|
||||
// use so for now we will reuse the Fortran constant until we are OK with
|
||||
// modifying test results
|
||||
extern "C" constexpr double PI {3.1415926535898};
|
||||
|
||||
extern "C" const double SQRT_PI {std::sqrt(PI)};
|
||||
|
||||
//==============================================================================
|
||||
//! Calculate the percentile of the standard normal distribution with a
|
||||
//! specified probability level.
|
||||
|
|
|
|||
712
src/mgxs.cpp
Normal file
712
src/mgxs.cpp
Normal file
|
|
@ -0,0 +1,712 @@
|
|||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <valarray>
|
||||
|
||||
#ifdef _OPENMP
|
||||
# include <omp.h>
|
||||
#endif
|
||||
|
||||
#include "error.h"
|
||||
#include "math_functions.h"
|
||||
#include "random_lcg.h"
|
||||
#include "string_functions.h"
|
||||
#include "mgxs.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
||||
// Storage for the MGXS data
|
||||
std::vector<Mgxs> nuclides_MG;
|
||||
std::vector<Mgxs> macro_xs;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
// Mgxs base-class methods
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
Mgxs::init(const std::string& in_name, double in_awr,
|
||||
const double_1dvec& in_kTs, bool in_fissionable, int in_scatter_format,
|
||||
int in_num_groups, int in_num_delayed_groups, bool in_is_isotropic,
|
||||
const double_1dvec& in_polar, const double_1dvec& in_azimuthal)
|
||||
{
|
||||
// Set the metadata
|
||||
name = in_name;
|
||||
awr = in_awr;
|
||||
kTs = in_kTs;
|
||||
fissionable = in_fissionable;
|
||||
scatter_format = in_scatter_format;
|
||||
num_groups = in_num_groups;
|
||||
num_delayed_groups = in_num_delayed_groups;
|
||||
xs.resize(in_kTs.size());
|
||||
is_isotropic = in_is_isotropic;
|
||||
n_pol = in_polar.size();
|
||||
n_azi = in_azimuthal.size();
|
||||
polar = in_polar;
|
||||
azimuthal = in_azimuthal;
|
||||
|
||||
// Set the cross section index cache
|
||||
#ifdef _OPENMP
|
||||
int n_threads = omp_get_max_threads();
|
||||
#else
|
||||
int n_threads = 1;
|
||||
#endif
|
||||
cache.resize(n_threads);
|
||||
// std::vector.resize() will value-initialize the members of cache[:]
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups,
|
||||
int in_num_delayed_groups, const double_1dvec& temperature,
|
||||
double tolerance, int_1dvec& temps_to_read, int& order_dim, int& method)
|
||||
{
|
||||
// get name
|
||||
char char_name[MAX_WORD_LEN];
|
||||
get_name(xs_id, char_name);
|
||||
std::string in_name {char_name};
|
||||
// remove the leading '/'
|
||||
in_name = in_name.substr(1);
|
||||
|
||||
// Get the AWR
|
||||
double in_awr;
|
||||
if (attribute_exists(xs_id, "atomic_weight_ratio")) {
|
||||
read_attr_double(xs_id, "atomic_weight_ratio", &in_awr);
|
||||
} else {
|
||||
in_awr = MACROSCOPIC_AWR;
|
||||
}
|
||||
|
||||
// Determine the available temperatures
|
||||
hid_t kT_group = open_group(xs_id, "kTs");
|
||||
int num_temps = get_num_datasets(kT_group);
|
||||
char* dset_names[num_temps];
|
||||
for (int i = 0; i < num_temps; i++) {
|
||||
dset_names[i] = new char[151];
|
||||
}
|
||||
get_datasets(kT_group, dset_names);
|
||||
double_1dvec available_temps(num_temps);
|
||||
for (int i = 0; i < num_temps; i++) {
|
||||
read_double(kT_group, dset_names[i], &available_temps[i], true);
|
||||
|
||||
// convert eV to Kelvin
|
||||
available_temps[i] /= K_BOLTZMANN;
|
||||
|
||||
// Done with dset_names, so delete it
|
||||
delete[] dset_names[i];
|
||||
}
|
||||
std::sort(available_temps.begin(), available_temps.end());
|
||||
|
||||
// If only one temperature is available, lets just use nearest temperature
|
||||
// interpolation
|
||||
if ((num_temps == 1) && (method == TEMPERATURE_INTERPOLATION)) {
|
||||
warning("Cross sections for " + strtrim(name) + " are only available " +
|
||||
"at one temperature. Reverting to the nearest temperature " +
|
||||
"method.");
|
||||
method = TEMPERATURE_NEAREST;
|
||||
}
|
||||
|
||||
switch(method) {
|
||||
case TEMPERATURE_NEAREST:
|
||||
// Find the minimum difference
|
||||
for (int i = 0; i < temperature.size(); i++) {
|
||||
std::valarray<double> temp_diff(available_temps.data(),
|
||||
available_temps.size());
|
||||
temp_diff = std::abs(temp_diff - temperature[i]);
|
||||
int i_closest = std::min_element(std::begin(temp_diff), std::end(temp_diff)) -
|
||||
std::begin(temp_diff);
|
||||
double temp_actual = available_temps[i_closest];
|
||||
|
||||
if (std::abs(temp_actual - temperature[i]) < tolerance) {
|
||||
if (std::find(temps_to_read.begin(), temps_to_read.end(),
|
||||
std::round(temp_actual)) == temps_to_read.end()) {
|
||||
temps_to_read.push_back(std::round(temp_actual));
|
||||
} else {
|
||||
fatal_error("MGXS Library does not contain cross section for " +
|
||||
in_name + " at or near " +
|
||||
std::to_string(std::round(temperature[i])) + " K.");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TEMPERATURE_INTERPOLATION:
|
||||
for (int i = 0; i < temperature.size(); i++) {
|
||||
for (int j = 0; j < num_temps - 1; j++) {
|
||||
if ((available_temps[j] <= temperature[i]) &&
|
||||
(temperature[i] < available_temps[j + 1])) {
|
||||
if (std::find(temps_to_read.begin(),
|
||||
temps_to_read.end(),
|
||||
std::round(available_temps[j])) == temps_to_read.end()) {
|
||||
temps_to_read.push_back(std::round((int)available_temps[j]));
|
||||
}
|
||||
|
||||
if (std::find(temps_to_read.begin(), temps_to_read.end(),
|
||||
std::round(available_temps[j + 1])) == temps_to_read.end()) {
|
||||
temps_to_read.push_back(std::round((int) available_temps[j + 1]));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
fatal_error("MGXS Library does not contain cross sections for " +
|
||||
in_name + " at temperatures that bound " +
|
||||
std::to_string(std::round(temperature[i])));
|
||||
}
|
||||
}
|
||||
std::sort(temps_to_read.begin(), temps_to_read.end());
|
||||
|
||||
// Get the library's temperatures
|
||||
int n_temperature = temps_to_read.size();
|
||||
double_1dvec in_kTs(n_temperature);
|
||||
for (int i = 0; i < n_temperature; i++) {
|
||||
std::string temp_str(std::to_string(temps_to_read[i]) + "K");
|
||||
|
||||
//read exact temperature value
|
||||
read_double(kT_group, temp_str.c_str(), &in_kTs[i], true);
|
||||
}
|
||||
close_group(kT_group);
|
||||
|
||||
// Load the remaining metadata
|
||||
int in_scatter_format;
|
||||
if (attribute_exists(xs_id, "scatter_format")) {
|
||||
std::string temp_str(MAX_WORD_LEN, ' ');
|
||||
read_attr_string(xs_id, "scatter_format", MAX_WORD_LEN, &temp_str[0]);
|
||||
to_lower(strtrim(temp_str));
|
||||
if (temp_str.compare(0, 8, "legendre") == 0) {
|
||||
in_scatter_format = ANGLE_LEGENDRE;
|
||||
} else if (temp_str.compare(0, 9, "histogram") == 0) {
|
||||
in_scatter_format = ANGLE_HISTOGRAM;
|
||||
} else if (temp_str.compare(0, 7, "tabular") == 0) {
|
||||
in_scatter_format = ANGLE_TABULAR;
|
||||
} else {
|
||||
fatal_error("Invalid scatter_format option!");
|
||||
}
|
||||
} else {
|
||||
in_scatter_format = ANGLE_LEGENDRE;
|
||||
}
|
||||
|
||||
if (attribute_exists(xs_id, "scatter_shape")) {
|
||||
std::string temp_str(MAX_WORD_LEN, ' ');
|
||||
read_attr_string(xs_id, "scatter_shape", MAX_WORD_LEN, &temp_str[0]);
|
||||
to_lower(strtrim(temp_str));
|
||||
if (temp_str.compare(0, 14, "[g][g\'][order]") != 0) {
|
||||
fatal_error("Invalid scatter_shape option!");
|
||||
}
|
||||
}
|
||||
|
||||
bool in_fissionable = false;
|
||||
if (attribute_exists(xs_id, "fissionable")) {
|
||||
int int_fiss;
|
||||
read_attr_int(xs_id, "fissionable", &int_fiss);
|
||||
in_fissionable = int_fiss;
|
||||
} else {
|
||||
fatal_error("Fissionable element must be set!");
|
||||
}
|
||||
|
||||
// Get the library's value for the order
|
||||
if (attribute_exists(xs_id, "order")) {
|
||||
read_attr_int(xs_id, "order", &order_dim);
|
||||
} else {
|
||||
fatal_error("Order must be provided!");
|
||||
}
|
||||
|
||||
// Store the dimensionality of the data in order_dim.
|
||||
// For Legendre data, we usually refer to it as Pn where n is the order.
|
||||
// However Pn has n+1 sets of points (since you need to count the P0
|
||||
// moment). Adjust for that. Histogram and Tabular formats dont need this
|
||||
// adjustment.
|
||||
if (in_scatter_format == ANGLE_LEGENDRE) {
|
||||
++order_dim;
|
||||
}
|
||||
|
||||
// Get the angular information
|
||||
int in_n_pol;
|
||||
int in_n_azi;
|
||||
bool in_is_isotropic = true;
|
||||
if (attribute_exists(xs_id, "representation")) {
|
||||
std::string temp_str(MAX_WORD_LEN, ' ');
|
||||
read_attr_string(xs_id, "representation", MAX_WORD_LEN, &temp_str[0]);
|
||||
to_lower(strtrim(temp_str));
|
||||
if (temp_str.compare(0, 5, "angle") == 0) {
|
||||
in_is_isotropic = false;
|
||||
} else if (temp_str.compare(0, 9, "isotropic") != 0) {
|
||||
fatal_error("Invalid Data Representation!");
|
||||
}
|
||||
}
|
||||
|
||||
if (!in_is_isotropic) {
|
||||
if (attribute_exists(xs_id, "num_polar")) {
|
||||
read_attr_int(xs_id, "num_polar", &in_n_pol);
|
||||
} else {
|
||||
fatal_error("num_polar must be provided!");
|
||||
}
|
||||
if (attribute_exists(xs_id, "num_azimuthal")) {
|
||||
read_attr_int(xs_id, "num_azimuthal", &in_n_azi);
|
||||
} else {
|
||||
fatal_error("num_azimuthal must be provided!");
|
||||
}
|
||||
} else {
|
||||
in_n_pol = 1;
|
||||
in_n_azi = 1;
|
||||
}
|
||||
|
||||
// Set the angular bins to use equally-spaced bins
|
||||
double_1dvec in_polar(in_n_pol);
|
||||
double dangle = PI / in_n_pol;
|
||||
for (int p = 0; p < in_n_pol; p++) {
|
||||
in_polar[p] = (p + 0.5) * dangle;
|
||||
}
|
||||
double_1dvec in_azimuthal(in_n_azi);
|
||||
dangle = 2. * PI / in_n_azi;
|
||||
for (int a = 0; a < in_n_azi; a++) {
|
||||
in_azimuthal[a] = (a + 0.5) * dangle - PI;
|
||||
}
|
||||
|
||||
// Finally use this data to initialize the MGXS Object
|
||||
init(in_name, in_awr, in_kTs, in_fissionable, in_scatter_format,
|
||||
in_num_groups, in_num_delayed_groups, in_is_isotropic, in_polar,
|
||||
in_azimuthal);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
Mgxs::Mgxs(hid_t xs_id, int energy_groups, int delayed_groups,
|
||||
const double_1dvec& temperature, double tolerance, int max_order,
|
||||
bool legendre_to_tabular, int legendre_to_tabular_points, int& method)
|
||||
{
|
||||
// Call generic data gathering routine (will populate the metadata)
|
||||
int order_data;
|
||||
int_1dvec temps_to_read;
|
||||
metadata_from_hdf5(xs_id, energy_groups, delayed_groups, temperature,
|
||||
tolerance, temps_to_read, order_data, method);
|
||||
|
||||
// Set number of energy and delayed groups
|
||||
int final_scatter_format = scatter_format;
|
||||
if (legendre_to_tabular) {
|
||||
if (scatter_format == ANGLE_LEGENDRE) final_scatter_format = ANGLE_TABULAR;
|
||||
}
|
||||
|
||||
// Load the more specific XsData information
|
||||
for (int t = 0; t < temps_to_read.size(); t++) {
|
||||
xs[t] = XsData(energy_groups, delayed_groups, fissionable,
|
||||
final_scatter_format, n_pol, n_azi);
|
||||
// Get the temperature as a string and then open the HDF5 group
|
||||
std::string temp_str = std::to_string(temps_to_read[t]) + "K";
|
||||
hid_t xsdata_grp = open_group(xs_id, temp_str.c_str());
|
||||
|
||||
xs[t].from_hdf5(xsdata_grp, fissionable, scatter_format,
|
||||
final_scatter_format, order_data, max_order,
|
||||
legendre_to_tabular_points, is_isotropic, n_pol, n_azi);
|
||||
close_group(xsdata_grp);
|
||||
|
||||
} // end temperature loop
|
||||
|
||||
// Make sure the scattering format is updated to the final case
|
||||
scatter_format = final_scatter_format;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs,
|
||||
const std::vector<Mgxs*>& micros, const double_1dvec& atom_densities,
|
||||
double tolerance, int& method)
|
||||
{
|
||||
// Get the minimum data needed to initialize:
|
||||
// Dont need awr, but lets just initialize it anyways
|
||||
double in_awr = -1.;
|
||||
// start with the assumption it is not fissionable
|
||||
bool in_fissionable = false;
|
||||
for (int m = 0; m < micros.size(); m++) {
|
||||
if (micros[m]->fissionable) in_fissionable = true;
|
||||
}
|
||||
// Force all of the following data to be the same; these will be verified
|
||||
// to be true later
|
||||
int in_scatter_format = micros[0]->scatter_format;
|
||||
int in_num_groups = micros[0]->num_groups;
|
||||
int in_num_delayed_groups = micros[0]->num_delayed_groups;
|
||||
bool in_is_isotropic = micros[0]->is_isotropic;
|
||||
double_1dvec in_polar = micros[0]->polar;
|
||||
double_1dvec in_azimuthal = micros[0]->azimuthal;
|
||||
|
||||
init(in_name, in_awr, mat_kTs, in_fissionable, in_scatter_format,
|
||||
in_num_groups, in_num_delayed_groups, in_is_isotropic, in_polar,
|
||||
in_azimuthal);
|
||||
|
||||
// Create the xs data for each temperature
|
||||
for (int t = 0; t < mat_kTs.size(); t++) {
|
||||
xs[t] = XsData(in_num_groups, in_num_delayed_groups, in_fissionable,
|
||||
in_scatter_format, in_polar.size(), in_azimuthal.size());
|
||||
|
||||
// Find the right temperature index to use
|
||||
double temp_desired = mat_kTs[t];
|
||||
|
||||
// Create the list of temperature indices and interpolation factors for
|
||||
// each microscopic data at the material temperature
|
||||
int_1dvec micro_t(micros.size(), 0);
|
||||
double_1dvec micro_t_interp(micros.size(), 0.);
|
||||
for (int m = 0; m < micros.size(); m++) {
|
||||
switch(method) {
|
||||
case TEMPERATURE_NEAREST:
|
||||
{
|
||||
// Find the nearest temperature
|
||||
std::valarray<double> temp_diff(micros[m]->kTs.data(),
|
||||
micros[m]->kTs.size());
|
||||
temp_diff = std::abs(temp_diff - temp_desired);
|
||||
micro_t[m] = std::min_element(std::begin(temp_diff),
|
||||
std::end(temp_diff)) -
|
||||
std::begin(temp_diff);
|
||||
double temp_actual = micros[m]->kTs[micro_t[m]];
|
||||
|
||||
if (std::abs(temp_actual - temp_desired) >= K_BOLTZMANN * tolerance) {
|
||||
fatal_error("MGXS Library does not contain cross section for " +
|
||||
name + " at or near " +
|
||||
std::to_string(std::round(temp_desired / K_BOLTZMANN))
|
||||
+ " K.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TEMPERATURE_INTERPOLATION:
|
||||
// Get a list of bounding temperatures for each actual temperature
|
||||
// present in the model
|
||||
for (int k = 0; k < micros[m]->kTs.size() - 1; k++) {
|
||||
if ((micros[m]->kTs[k] <= temp_desired) &&
|
||||
(temp_desired < micros[m]->kTs[k + 1])) {
|
||||
micro_t[m] = k;
|
||||
if (k == 0) {
|
||||
micro_t_interp[m] = (temp_desired - micros[m]->kTs[k]) /
|
||||
(micros[m]->kTs[k + 1] - micros[m]->kTs[k]);
|
||||
} else {
|
||||
micro_t_interp[m] = 1.;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end switch
|
||||
} // end microscopic temperature loop
|
||||
|
||||
// We are about to loop through each of the microscopic objects
|
||||
// and incorporate the contribution of each microscopic data at
|
||||
// one of the two temperature interpolants to this macroscopic quantity.
|
||||
// If we are doing nearest temperature interpolation, then we don't need
|
||||
// to do the 2nd temperature
|
||||
int num_interp_points = 2;
|
||||
if (method == TEMPERATURE_NEAREST) num_interp_points = 1;
|
||||
for (int interp_point = 0; interp_point < num_interp_points; interp_point++) {
|
||||
double_1dvec interp(micros.size());
|
||||
double_1dvec temp_indices(micros.size());
|
||||
for (int m = 0; m < micros.size(); m++) {
|
||||
interp[m] = (1. - micro_t_interp[m]) * atom_densities[m];
|
||||
temp_indices[m] = micro_t[m] + interp_point;
|
||||
}
|
||||
|
||||
combine(micros, interp, micro_t, t);
|
||||
} // end loop to sum all micros across the temperatures
|
||||
} // end temperature (t) loop
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
Mgxs::combine(const std::vector<Mgxs*>& micros, const double_1dvec& scalars,
|
||||
const int_1dvec& micro_ts, int this_t)
|
||||
{
|
||||
// Build the vector of pointers to the xs objects within micros
|
||||
std::vector<XsData*> those_xs(micros.size());
|
||||
for (int i = 0; i < micros.size(); i++) {
|
||||
if (!xs[this_t].equiv(micros[i]->xs[micro_ts[i]])) {
|
||||
fatal_error("Cannot combine the Mgxs objects!");
|
||||
}
|
||||
those_xs[i] = &(micros[i]->xs[micro_ts[i]]);
|
||||
}
|
||||
|
||||
xs[this_t].combine(those_xs, scalars);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
double
|
||||
Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg)
|
||||
{
|
||||
// This method assumes that the temperature and angle indices are set
|
||||
#ifdef _OPENMP
|
||||
int tid = omp_get_thread_num();
|
||||
XsData* xs_t = &xs[cache[tid].t];
|
||||
int a = cache[tid].a;
|
||||
#else
|
||||
XsData* xs_t = &xs[cache[0].t];
|
||||
int a = cache[0].a;
|
||||
#endif
|
||||
double val;
|
||||
switch(xstype) {
|
||||
case MG_GET_XS_TOTAL:
|
||||
val = xs_t->total[a][gin];
|
||||
break;
|
||||
case MG_GET_XS_NU_FISSION:
|
||||
val = fissionable ? xs_t->nu_fission[a][gin] : 0.;
|
||||
break;
|
||||
case MG_GET_XS_ABSORPTION:
|
||||
val = xs_t->absorption[a][gin];
|
||||
break;
|
||||
case MG_GET_XS_FISSION:
|
||||
val = fissionable ? xs_t->fission[a][gin] : 0.;
|
||||
break;
|
||||
case MG_GET_XS_KAPPA_FISSION:
|
||||
val = fissionable ? xs_t->kappa_fission[a][gin] : 0.;
|
||||
break;
|
||||
case MG_GET_XS_SCATTER:
|
||||
case MG_GET_XS_SCATTER_MULT:
|
||||
case MG_GET_XS_SCATTER_FMU_MULT:
|
||||
case MG_GET_XS_SCATTER_FMU:
|
||||
val = xs_t->scatter[a]->get_xs(xstype, gin, gout, mu);
|
||||
break;
|
||||
case MG_GET_XS_PROMPT_NU_FISSION:
|
||||
val = fissionable ? xs_t->prompt_nu_fission[a][gin] : 0.;
|
||||
break;
|
||||
case MG_GET_XS_DELAYED_NU_FISSION:
|
||||
if (fissionable) {
|
||||
if (dg != nullptr) {
|
||||
val = xs_t->delayed_nu_fission[a][gin][*dg];
|
||||
} else {
|
||||
val = 0.;
|
||||
for (auto& num : xs_t->delayed_nu_fission[a][gin]) {
|
||||
val += num;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val = 0.;
|
||||
}
|
||||
break;
|
||||
case MG_GET_XS_CHI_PROMPT:
|
||||
if (fissionable) {
|
||||
if (gout != nullptr) {
|
||||
val = xs_t->chi_prompt[a][gin][*gout];
|
||||
} else {
|
||||
// provide an outgoing group-wise sum
|
||||
val = 0.;
|
||||
for (auto& num : xs_t->chi_prompt[a][gin]) {
|
||||
val += num;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val = 0.;
|
||||
}
|
||||
break;
|
||||
case MG_GET_XS_CHI_DELAYED:
|
||||
if (fissionable) {
|
||||
if (gout != nullptr) {
|
||||
if (dg != nullptr) {
|
||||
val = xs_t->chi_delayed[a][gin][*gout][*dg];
|
||||
} else {
|
||||
val = xs_t->chi_delayed[a][gin][*gout][0];
|
||||
}
|
||||
} else {
|
||||
if (dg != nullptr) {
|
||||
val = 0.;
|
||||
for (int i = 0; i < xs_t->chi_delayed[a][gin].size(); i++) {
|
||||
val += xs_t->chi_delayed[a][gin][i][*dg];
|
||||
}
|
||||
} else {
|
||||
val = 0.;
|
||||
for (int i = 0; i < xs_t->chi_delayed[a][gin].size(); i++) {
|
||||
for (auto& num : xs_t->chi_delayed[a][gin][i]) {
|
||||
val += num;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val = 0.;
|
||||
}
|
||||
break;
|
||||
case MG_GET_XS_INVERSE_VELOCITY:
|
||||
val = xs_t->inverse_velocity[a][gin];
|
||||
break;
|
||||
case MG_GET_XS_DECAY_RATE:
|
||||
if (dg != nullptr) {
|
||||
val = xs_t->decay_rate[a][*dg + 1];
|
||||
} else {
|
||||
val = xs_t->decay_rate[a][0];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
val = 0.;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
Mgxs::sample_fission_energy(int gin, int& dg, int& gout)
|
||||
{
|
||||
// This method assumes that the temperature and angle indices are set
|
||||
#ifdef _OPENMP
|
||||
int tid = omp_get_thread_num();
|
||||
#else
|
||||
int tid = 0;
|
||||
#endif
|
||||
XsData* xs_t = &xs[cache[tid].t];
|
||||
double nu_fission = xs_t->nu_fission[cache[tid].a][gin];
|
||||
|
||||
// Find the probability of having a prompt neutron
|
||||
double prob_prompt =
|
||||
xs_t->prompt_nu_fission[cache[tid].a][gin];
|
||||
|
||||
// sample random numbers
|
||||
double xi_pd = prn() * nu_fission;
|
||||
double xi_gout = prn();
|
||||
|
||||
// Select whether the neutron is prompt or delayed
|
||||
if (xi_pd <= prob_prompt) {
|
||||
// the neutron is prompt
|
||||
|
||||
// set the delayed group for the particle to be -1, indicating prompt
|
||||
dg = -1;
|
||||
|
||||
// sample the outgoing energy group
|
||||
gout = 0;
|
||||
double prob_gout =
|
||||
xs_t->chi_prompt[cache[tid].a][gin][gout];
|
||||
while (prob_gout < xi_gout) {
|
||||
gout++;
|
||||
prob_gout += xs_t->chi_prompt[cache[tid].a][gin][gout];
|
||||
}
|
||||
|
||||
} else {
|
||||
// the neutron is delayed
|
||||
|
||||
// get the delayed group
|
||||
dg = 0;
|
||||
while (xi_pd >= prob_prompt) {
|
||||
dg++;
|
||||
prob_prompt +=
|
||||
xs_t->delayed_nu_fission[cache[tid].a][gin][dg];
|
||||
}
|
||||
|
||||
// adjust dg in case of round-off error
|
||||
dg = std::min(dg, num_delayed_groups - 1);
|
||||
|
||||
// sample the outgoing energy group
|
||||
gout = 0;
|
||||
double prob_gout =
|
||||
xs_t->chi_delayed[cache[tid].a][gin][gout][dg];
|
||||
while (prob_gout < xi_gout) {
|
||||
gout++;
|
||||
prob_gout +=
|
||||
xs_t->chi_delayed[cache[tid].a][gin][gout][dg];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
Mgxs::sample_scatter(int gin, int& gout, double& mu, double& wgt)
|
||||
{
|
||||
// This method assumes that the temperature and angle indices are set
|
||||
// Sample the data
|
||||
#ifdef _OPENMP
|
||||
int tid = omp_get_thread_num();
|
||||
#else
|
||||
int tid = 0;
|
||||
#endif
|
||||
xs[cache[tid].t].scatter[cache[tid].a]->sample(gin, gout, mu, wgt);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
Mgxs::calculate_xs(int gin, double sqrtkT, const double uvw[3],
|
||||
double& total_xs, double& abs_xs, double& nu_fiss_xs)
|
||||
{
|
||||
// Set our indices
|
||||
#ifdef _OPENMP
|
||||
int tid = omp_get_thread_num();
|
||||
#else
|
||||
int tid = 0;
|
||||
#endif
|
||||
set_temperature_index(sqrtkT);
|
||||
set_angle_index(uvw);
|
||||
XsData* xs_t = &xs[cache[tid].t];
|
||||
total_xs = xs_t->total[cache[tid].a][gin];
|
||||
abs_xs = xs_t->absorption[cache[tid].a][gin];
|
||||
|
||||
nu_fiss_xs = fissionable ? xs_t->nu_fission[cache[tid].a][gin] : 0.;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
bool
|
||||
Mgxs::equiv(const Mgxs& that)
|
||||
{
|
||||
return ((num_delayed_groups == that.num_delayed_groups) &&
|
||||
(num_groups == that.num_groups) &&
|
||||
(n_pol == that.n_pol) &&
|
||||
(n_azi == that.n_azi) &&
|
||||
(std::equal(polar.begin(), polar.end(), that.polar.begin())) &&
|
||||
(std::equal(azimuthal.begin(), azimuthal.end(), that.azimuthal.begin())) &&
|
||||
(scatter_format == that.scatter_format));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
Mgxs::set_temperature_index(double sqrtkT)
|
||||
{
|
||||
// See if we need to find the new index
|
||||
#ifdef _OPENMP
|
||||
int tid = omp_get_thread_num();
|
||||
#else
|
||||
int tid = 0;
|
||||
#endif
|
||||
if (sqrtkT != cache[tid].sqrtkT) {
|
||||
double kT = sqrtkT * sqrtkT;
|
||||
|
||||
// initialize vector for storage of the differences
|
||||
std::valarray<double> temp_diff(kTs.data(), kTs.size());
|
||||
|
||||
// Find the minimum difference of kT and kTs
|
||||
temp_diff = std::abs(temp_diff - kT);
|
||||
cache[tid].t = std::min_element(std::begin(temp_diff), std::end(temp_diff)) -
|
||||
std::begin(temp_diff);
|
||||
|
||||
// store this temperature as the last one used
|
||||
cache[tid].sqrtkT = sqrtkT;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
Mgxs::set_angle_index(const double uvw[3])
|
||||
{
|
||||
// See if we need to find the new index
|
||||
#ifdef _OPENMP
|
||||
int tid = omp_get_thread_num();
|
||||
#else
|
||||
int tid = 0;
|
||||
#endif
|
||||
if (!is_isotropic &&
|
||||
((uvw[0] != cache[tid].u) || (uvw[1] != cache[tid].v) ||
|
||||
(uvw[2] != cache[tid].w))) {
|
||||
// convert uvw to polar and azimuthal angles
|
||||
double my_pol = std::acos(uvw[2]);
|
||||
double my_azi = std::atan2(uvw[1], uvw[0]);
|
||||
|
||||
// Find the location, assuming equal-bin angles
|
||||
double delta_angle = PI / n_pol;
|
||||
int p = std::floor(my_pol / delta_angle);
|
||||
delta_angle = 2. * PI / n_azi;
|
||||
int a = std::floor((my_azi + PI) / delta_angle);
|
||||
|
||||
cache[tid].a = n_azi * p + a;
|
||||
|
||||
// store this direction as the last one used
|
||||
cache[tid].u = uvw[0];
|
||||
cache[tid].v = uvw[1];
|
||||
cache[tid].w = uvw[2];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
205
src/mgxs.h
Normal file
205
src/mgxs.h
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
//! \file mgxs.h
|
||||
//! A collection of classes for Multi-Group Cross Section data
|
||||
|
||||
#ifndef MGXS_H
|
||||
#define MGXS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "constants.h"
|
||||
#include "hdf5_interface.h"
|
||||
#include "xsdata.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// Cache contains the cached data for an MGXS object
|
||||
//==============================================================================
|
||||
|
||||
struct CacheData {
|
||||
double sqrtkT; // last temperature corresponding to t
|
||||
int t; // temperature index
|
||||
int a; // angle index
|
||||
// last angle that corresponds to a
|
||||
double u;
|
||||
double v;
|
||||
double w;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// MGXS contains the mgxs data for a nuclide/material
|
||||
//==============================================================================
|
||||
|
||||
class Mgxs {
|
||||
private:
|
||||
|
||||
double_1dvec kTs; // temperature in eV (k * T)
|
||||
int scatter_format; // flag for if this is legendre, histogram, or tabular
|
||||
int num_delayed_groups; // number of delayed neutron groups
|
||||
int num_groups; // number of energy groups
|
||||
std::vector<XsData> xs; // Cross section data
|
||||
// MGXS Incoming Flux Angular grid information
|
||||
bool is_isotropic; // used to skip search for angle indices if isotropic
|
||||
int n_pol;
|
||||
int n_azi;
|
||||
double_1dvec polar;
|
||||
double_1dvec azimuthal;
|
||||
|
||||
//! \brief Initializes the Mgxs object metadata
|
||||
//!
|
||||
//! @param in_name Name of the object.
|
||||
//! @param in_awr atomic-weight ratio.
|
||||
//! @param in_kTs temperatures (in units of eV) that data is available.
|
||||
//! @param in_fissionable Is this item fissionable or not.
|
||||
//! @param in_scatter_format Denotes whether Legendre, Tabular, or
|
||||
//! Histogram scattering is used.
|
||||
//! @param in_num_groups Number of energy groups.
|
||||
//! @param in_num_delayed_groups Number of delayed groups.
|
||||
//! @param in_is_isotropic Is this an isotropic or angular with respect to
|
||||
//! the incoming particle.
|
||||
//! @param in_polar Polar angle grid.
|
||||
//! @param in_azimuthal Azimuthal angle grid.
|
||||
void
|
||||
init(const std::string& in_name, double in_awr, const double_1dvec& in_kTs,
|
||||
bool in_fissionable, int in_scatter_format, int in_num_groups,
|
||||
int in_num_delayed_groups, bool in_is_isotropic,
|
||||
const double_1dvec& in_polar, const double_1dvec& in_azimuthal);
|
||||
|
||||
//! \brief Initializes the Mgxs object metadata from the HDF5 file
|
||||
//!
|
||||
//! @param xs_id HDF5 group id for the cross section data.
|
||||
//! @param in_num_groups Number of energy groups.
|
||||
//! @param in_num_delayed_groups Number of delayed groups.
|
||||
//! @param temperature Temperatures to read.
|
||||
//! @param tolerance Tolerance of temperature selection method.
|
||||
//! @param temps_to_read Resultant list of temperatures in the library
|
||||
//! to read which correspond to the requested temperatures.
|
||||
//! @param order_dim Resultant dimensionality of the scattering order.
|
||||
//! @param method Method of choosing nearest temperatures.
|
||||
void
|
||||
metadata_from_hdf5(hid_t xs_id, int in_num_groups,
|
||||
int in_num_delayed_groups, const double_1dvec& temperature,
|
||||
double tolerance, int_1dvec& temps_to_read, int& order_dim,
|
||||
int& method);
|
||||
|
||||
//! \brief Performs the actual act of combining the microscopic data for a
|
||||
//! single temperature.
|
||||
//!
|
||||
//! @param micros Microscopic objects to combine.
|
||||
//! @param scalars Scalars to multiply the microscopic data by.
|
||||
//! @param micro_ts The temperature index of the microscopic objects that
|
||||
//! corresponds to the temperature of interest.
|
||||
//! @param this_t The temperature index of the macroscopic object.
|
||||
void
|
||||
combine(const std::vector<Mgxs*>& micros, const double_1dvec& scalars,
|
||||
const int_1dvec& micro_ts, int this_t);
|
||||
|
||||
//! \brief Checks to see if this and that are able to be combined
|
||||
//!
|
||||
//! This comparison is used when building macroscopic cross sections
|
||||
//! from microscopic cross sections.
|
||||
//! @param that The other Mgxs to compare to this one.
|
||||
//! @return True if they can be combined, False otherwise.
|
||||
bool equiv(const Mgxs& that);
|
||||
|
||||
public:
|
||||
|
||||
std::string name; // name of dataset, e.g., UO2
|
||||
double awr; // atomic weight ratio
|
||||
bool fissionable; // Is this fissionable
|
||||
std::vector<CacheData> cache; // index and data cache
|
||||
|
||||
Mgxs() = default;
|
||||
|
||||
//! \brief Constructor that loads the Mgxs object from the HDF5 file
|
||||
//!
|
||||
//! @param xs_id HDF5 group id for the cross section data.
|
||||
//! @param energy_groups Number of energy groups.
|
||||
//! @param delayed_groups Number of delayed groups.
|
||||
//! @param temperature Temperatures to read.
|
||||
//! @param tolerance Tolerance of temperature selection method.
|
||||
//! @param max_order Maximum order requested by the user;
|
||||
//! this is only used for Legendre scattering.
|
||||
//! @param legendre_to_tabular Flag to denote if any Legendre provided
|
||||
//! should be converted to a Tabular representation.
|
||||
//! @param legendre_to_tabular_points If a conversion is requested, this
|
||||
//! provides the number of points to use in the tabular representation.
|
||||
//! @param method Method of choosing nearest temperatures.
|
||||
Mgxs(hid_t xs_id, int energy_groups,
|
||||
int delayed_groups, const double_1dvec& temperature, double tolerance,
|
||||
int max_order, bool legendre_to_tabular,
|
||||
int legendre_to_tabular_points, int& method);
|
||||
|
||||
//! \brief Constructor that initializes and populates all data to build a
|
||||
//! macroscopic cross section from microscopic cross section.
|
||||
//!
|
||||
//! @param in_name Name of the object.
|
||||
//! @param mat_kTs temperatures (in units of eV) that data is needed.
|
||||
//! @param micros Microscopic objects to combine.
|
||||
//! @param atom_densities Atom densities of those microscopic quantities.
|
||||
//! @param tolerance Tolerance of temperature selection method.
|
||||
//! @param method Method of choosing nearest temperatures.
|
||||
Mgxs(const std::string& in_name, const double_1dvec& mat_kTs,
|
||||
const std::vector<Mgxs*>& micros, const double_1dvec& atom_densities,
|
||||
double tolerance, int& method);
|
||||
|
||||
//! \brief Provides a cross section value given certain parameters
|
||||
//!
|
||||
//! @param xstype Type of cross section requested, according to the
|
||||
//! enumerated constants.
|
||||
//! @param gin Incoming energy group.
|
||||
//! @param gout Outgoing energy group; use nullptr if irrelevant, or if a
|
||||
//! sum is requested.
|
||||
//! @param mu Cosine of the change-in-angle, for scattering quantities;
|
||||
//! use nullptr if irrelevant.
|
||||
//! @param dg delayed group index; use nullptr if irrelevant.
|
||||
//! @return Requested cross section value.
|
||||
double
|
||||
get_xs(int xstype, int gin, int* gout, double* mu, int* dg);
|
||||
|
||||
//! \brief Samples the fission neutron energy and if prompt or delayed.
|
||||
//!
|
||||
//! @param gin Incoming energy group.
|
||||
//! @param dg Sampled delayed group index.
|
||||
//! @param gout Sampled outgoing energy group.
|
||||
void
|
||||
sample_fission_energy(int gin, int& dg, int& gout);
|
||||
|
||||
//! \brief Samples the outgoing energy and angle from a scatter event.
|
||||
//!
|
||||
//! @param gin Incoming energy group.
|
||||
//! @param gout Sampled outgoing energy group.
|
||||
//! @param mu Sampled cosine of the change-in-angle.
|
||||
//! @param wgt Weight of the particle to be adjusted.
|
||||
void
|
||||
sample_scatter(int gin, int& gout, double& mu, double& wgt);
|
||||
|
||||
//! \brief Calculates cross section quantities needed for tracking.
|
||||
//!
|
||||
//! @param gin Incoming energy group.
|
||||
//! @param sqrtkT Temperature of the material.
|
||||
//! @param uvw Incoming particle direction.
|
||||
//! @param total_xs Resultant total cross section.
|
||||
//! @param abs_xs Resultant absorption cross section.
|
||||
//! @param nu_fiss_xs Resultant nu-fission cross section.
|
||||
void
|
||||
calculate_xs(int gin, double sqrtkT, const double uvw[3],
|
||||
double& total_xs, double& abs_xs, double& nu_fiss_xs);
|
||||
|
||||
//! \brief Sets the temperature index in cache given a temperature
|
||||
//!
|
||||
//! @param sqrtkT Temperature of the material.
|
||||
void
|
||||
set_temperature_index(double sqrtkT);
|
||||
|
||||
//! \brief Sets the angle index in cache given a direction
|
||||
//!
|
||||
//! @param uvw Incoming particle direction.
|
||||
void
|
||||
set_angle_index(const double uvw[3]);
|
||||
};
|
||||
|
||||
} // namespace openmc
|
||||
#endif // MGXS_H
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
module mgxs_data
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use constants
|
||||
use algorithm, only: find
|
||||
use dict_header, only: DictCharInt
|
||||
|
|
@ -7,11 +9,11 @@ module mgxs_data
|
|||
use geometry_header, only: get_temperatures, cells
|
||||
use hdf5_interface
|
||||
use material_header, only: Material, materials, n_materials
|
||||
use mgxs_header
|
||||
use mgxs_interface
|
||||
use nuclide_header, only: n_nuclides
|
||||
use set_header, only: SetChar
|
||||
use settings
|
||||
use stl_vector, only: VectorReal
|
||||
use stl_vector, only: VectorReal, VectorChar
|
||||
use string, only: to_lower
|
||||
implicit none
|
||||
|
||||
|
|
@ -27,14 +29,11 @@ contains
|
|||
integer :: j ! index over nuclides in material
|
||||
integer :: i_nuclide ! index in nuclides array
|
||||
character(20) :: name ! name of library to load
|
||||
integer :: representation ! Data representation
|
||||
character(MAX_LINE_LEN) :: temp_str
|
||||
type(Material), pointer :: mat
|
||||
type(SetChar) :: already_read
|
||||
integer(HID_T) :: file_id
|
||||
integer(HID_T) :: xsdata_group
|
||||
logical :: file_exists
|
||||
type(VectorReal), allocatable :: temps(:)
|
||||
type(VectorReal), allocatable, target :: temps(:)
|
||||
character(MAX_WORD_LEN) :: word
|
||||
integer, allocatable :: array(:)
|
||||
|
||||
|
|
@ -69,9 +68,6 @@ contains
|
|||
&version supported by OpenMC.")
|
||||
end if
|
||||
|
||||
! allocate arrays for MGXS storage and cross section cache
|
||||
allocate(nuclides_MG(n_nuclides))
|
||||
|
||||
! ==========================================================================
|
||||
! READ ALL MGXS CROSS SECTION TABLES
|
||||
|
||||
|
|
@ -80,89 +76,29 @@ contains
|
|||
mat => materials(i)
|
||||
|
||||
NUCLIDE_LOOP: do j = 1, mat % n_nuclides
|
||||
name = mat % names(j)
|
||||
name = trim(mat % names(j)) // C_NULL_CHAR
|
||||
i_nuclide = mat % nuclide(j)
|
||||
|
||||
if (.not. already_read % contains(name)) then
|
||||
i_nuclide = mat % nuclide(j)
|
||||
call add_mgxs_c(file_id, name, num_energy_groups, num_delayed_groups, &
|
||||
temps(i_nuclide) % size(), temps(i_nuclide) % data, &
|
||||
temperature_tolerance, max_order, &
|
||||
logical(legendre_to_tabular, C_BOOL), &
|
||||
legendre_to_tabular_points, temperature_method)
|
||||
|
||||
call write_message("Loading " // trim(name) // " data...", 6)
|
||||
|
||||
! Check to make sure cross section set exists in the library
|
||||
if (object_exists(file_id, trim(name))) then
|
||||
xsdata_group = open_group(file_id, trim(name))
|
||||
else
|
||||
call fatal_error("Data for '" // trim(name) // "' does not exist in "&
|
||||
&// trim(path_cross_sections))
|
||||
end if
|
||||
|
||||
! First find out the data representation
|
||||
if (attribute_exists(xsdata_group, "representation")) then
|
||||
|
||||
call read_attribute(temp_str, xsdata_group, "representation")
|
||||
|
||||
if (trim(temp_str) == 'isotropic') then
|
||||
representation = MGXS_ISOTROPIC
|
||||
else if (trim(temp_str) == 'angle') then
|
||||
representation = MGXS_ANGLE
|
||||
else
|
||||
call fatal_error("Invalid Data Representation!")
|
||||
end if
|
||||
else
|
||||
! Default to isotropic representation
|
||||
representation = MGXS_ISOTROPIC
|
||||
end if
|
||||
|
||||
! Now allocate accordingly
|
||||
select case(representation)
|
||||
|
||||
case(MGXS_ISOTROPIC)
|
||||
allocate(MgxsIso :: nuclides_MG(i_nuclide) % obj)
|
||||
|
||||
case(MGXS_ANGLE)
|
||||
allocate(MgxsAngle :: nuclides_MG(i_nuclide) % obj)
|
||||
|
||||
end select
|
||||
|
||||
! Now read in the data specific to the type we just declared
|
||||
call nuclides_MG(i_nuclide) % obj % from_hdf5(xsdata_group, &
|
||||
num_energy_groups, num_delayed_groups, temps(i_nuclide), &
|
||||
temperature_method, temperature_tolerance, max_order, &
|
||||
legendre_to_tabular, legendre_to_tabular_points)
|
||||
|
||||
! Add name to dictionary
|
||||
call already_read % add(name)
|
||||
|
||||
call close_group(xsdata_group)
|
||||
|
||||
end if
|
||||
end do NUCLIDE_LOOP
|
||||
|
||||
mat % fissionable = query_fissionable_c(mat % n_nuclides, mat % nuclide)
|
||||
|
||||
end do MATERIAL_LOOP
|
||||
|
||||
call file_close(file_id)
|
||||
|
||||
! Avoid some valgrind leak errors
|
||||
call already_read % clear()
|
||||
|
||||
! Loop around material
|
||||
MATERIAL_LOOP3: do i = 1, n_materials
|
||||
|
||||
! Get material
|
||||
mat => materials(i)
|
||||
|
||||
! Loop around nuclides in material
|
||||
NUCLIDE_LOOP2: do j = 1, mat % n_nuclides
|
||||
|
||||
! Is this fissionable?
|
||||
if (nuclides_MG(mat % nuclide(j)) % obj % fissionable) then
|
||||
mat % fissionable = .true.
|
||||
end if
|
||||
if (mat % fissionable) then
|
||||
exit NUCLIDE_LOOP2
|
||||
end if
|
||||
|
||||
end do NUCLIDE_LOOP2
|
||||
end do MATERIAL_LOOP3
|
||||
|
||||
call file_close(file_id)
|
||||
|
||||
end subroutine read_mgxs
|
||||
|
||||
!===============================================================================
|
||||
|
|
@ -173,8 +109,7 @@ contains
|
|||
integer :: i_mat ! index in materials array
|
||||
type(Material), pointer :: mat ! current material
|
||||
type(VectorReal), allocatable :: kTs(:)
|
||||
|
||||
allocate(macro_xs(n_materials))
|
||||
character(MAX_WORD_LEN) :: name ! name of material
|
||||
|
||||
! Get temperatures to read for each material
|
||||
call get_mat_kTs(kTs)
|
||||
|
|
@ -188,19 +123,13 @@ contains
|
|||
! Get the material
|
||||
mat => materials(i_mat)
|
||||
|
||||
! Get the scattering type for the first nuclide
|
||||
select type(nuc => nuclides_MG(mat % nuclide(1)) % obj)
|
||||
type is (MgxsIso)
|
||||
allocate(MgxsIso :: macro_xs(i_mat) % obj)
|
||||
type is (MgxsAngle)
|
||||
allocate(MgxsAngle :: macro_xs(i_mat) % obj)
|
||||
end select
|
||||
name = trim(mat % name) // C_NULL_CHAR
|
||||
|
||||
! Do not read materials which we do not actually use in the problem to
|
||||
! reduce storage
|
||||
if (allocated(kTs(i_mat) % data)) then
|
||||
call macro_xs(i_mat) % obj % combine(kTs(i_mat), mat, nuclides_MG, &
|
||||
num_energy_groups, num_delayed_groups, max_order, &
|
||||
call create_macro_xs_c(name, mat % n_nuclides, mat % nuclide, &
|
||||
kTs(i_mat) % size(), kTs(i_mat) % data, mat % atom_density, &
|
||||
temperature_tolerance, temperature_method)
|
||||
end if
|
||||
end do
|
||||
|
|
|
|||
3593
src/mgxs_header.F90
3593
src/mgxs_header.F90
File diff suppressed because it is too large
Load diff
164
src/mgxs_interface.F90
Normal file
164
src/mgxs_interface.F90
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
module mgxs_interface
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use hdf5_interface
|
||||
|
||||
implicit none
|
||||
|
||||
interface
|
||||
|
||||
subroutine add_mgxs_c(file_id, name, energy_groups, delayed_groups, &
|
||||
n_temps, temps, tolerance, max_order, legendre_to_tabular, &
|
||||
legendre_to_tabular_points, method) bind(C)
|
||||
use ISO_C_BINDING
|
||||
import HID_T
|
||||
implicit none
|
||||
integer(HID_T), value, intent(in) :: file_id
|
||||
character(kind=C_CHAR),intent(in) :: name(*)
|
||||
integer(C_INT), value, intent(in) :: energy_groups
|
||||
integer(C_INT), value, intent(in) :: delayed_groups
|
||||
integer(C_INT), value, intent(in) :: n_temps
|
||||
real(C_DOUBLE), intent(in) :: temps(1:n_temps)
|
||||
real(C_DOUBLE), value, intent(in) :: tolerance
|
||||
integer(C_INT), value, intent(in) :: max_order
|
||||
logical(C_BOOL),value, intent(in) :: legendre_to_tabular
|
||||
integer(C_INT), value, intent(in) :: legendre_to_tabular_points
|
||||
integer(C_INT), intent(inout) :: method
|
||||
end subroutine add_mgxs_c
|
||||
|
||||
function query_fissionable_c(n_nuclides, i_nuclides) result(result) bind(C)
|
||||
use ISO_C_BINDING
|
||||
implicit none
|
||||
integer(C_INT), value, intent(in) :: n_nuclides
|
||||
integer(C_INT), intent(in) :: i_nuclides(1:n_nuclides)
|
||||
logical(C_BOOL) :: result
|
||||
end function query_fissionable_c
|
||||
|
||||
subroutine create_macro_xs_c(name, n_nuclides, i_nuclides, n_temps, temps, &
|
||||
atom_densities, tolerance, method) bind(C)
|
||||
use ISO_C_BINDING
|
||||
implicit none
|
||||
character(kind=C_CHAR),intent(in) :: name(*)
|
||||
integer(C_INT), value, intent(in) :: n_nuclides
|
||||
integer(C_INT), intent(in) :: i_nuclides(1:n_nuclides)
|
||||
integer(C_INT), value, intent(in) :: n_temps
|
||||
real(C_DOUBLE), intent(in) :: temps(1:n_temps)
|
||||
real(C_DOUBLE), intent(in) :: atom_densities(1:n_nuclides)
|
||||
real(C_DOUBLE), value, intent(in) :: tolerance
|
||||
integer(C_INT), intent(inout) :: method
|
||||
end subroutine create_macro_xs_c
|
||||
|
||||
subroutine calculate_xs_c(i_mat, gin, sqrtkT, uvw, total_xs, abs_xs, &
|
||||
nu_fiss_xs) bind(C)
|
||||
use ISO_C_BINDING
|
||||
implicit none
|
||||
integer(C_INT), value, intent(in) :: i_mat
|
||||
integer(C_INT), value, intent(in) :: gin
|
||||
real(C_DOUBLE), value, intent(in) :: sqrtkT
|
||||
real(C_DOUBLE), intent(in) :: uvw(1:3)
|
||||
real(C_DOUBLE), intent(inout) :: total_xs
|
||||
real(C_DOUBLE), intent(inout) :: abs_xs
|
||||
real(C_DOUBLE), intent(inout) :: nu_fiss_xs
|
||||
end subroutine calculate_xs_c
|
||||
|
||||
subroutine sample_scatter_c(i_mat, gin, gout, mu, wgt, uvw) bind(C)
|
||||
use ISO_C_BINDING
|
||||
implicit none
|
||||
integer(C_INT), value, intent(in) :: i_mat
|
||||
integer(C_INT), value, intent(in) :: gin
|
||||
integer(C_INT), intent(inout) :: gout
|
||||
real(C_DOUBLE), intent(inout) :: mu
|
||||
real(C_DOUBLE), intent(inout) :: wgt
|
||||
real(C_DOUBLE), intent(inout) :: uvw(1:3)
|
||||
end subroutine sample_scatter_c
|
||||
|
||||
subroutine sample_fission_energy_c(i_mat, gin, dg, gout) bind(C)
|
||||
use ISO_C_BINDING
|
||||
implicit none
|
||||
integer(C_INT), value, intent(in) :: i_mat
|
||||
integer(C_INT), value, intent(in) :: gin
|
||||
integer(C_INT), intent(inout) :: dg
|
||||
integer(C_INT), intent(inout) :: gout
|
||||
end subroutine sample_fission_energy_c
|
||||
|
||||
subroutine get_name_c(index, name_len, name) bind(C)
|
||||
use ISO_C_BINDING
|
||||
implicit none
|
||||
integer(C_INT), value, intent(in) :: index
|
||||
integer(C_INT), value, intent(in) :: name_len
|
||||
character(kind=C_CHAR), intent(inout) :: name(name_len)
|
||||
end subroutine get_name_c
|
||||
|
||||
function get_awr_c(index) result(awr) bind(C)
|
||||
use ISO_C_BINDING
|
||||
implicit none
|
||||
integer(C_INT), value, intent(in) :: index
|
||||
real(C_DOUBLE) :: awr
|
||||
end function get_awr_c
|
||||
|
||||
function get_nuclide_xs_c(index, xstype, gin, gout, mu, dg) result(val) &
|
||||
bind(C)
|
||||
use ISO_C_BINDING
|
||||
implicit none
|
||||
integer(C_INT), value, intent(in) :: index
|
||||
integer(C_INT), value, intent(in) :: xstype
|
||||
integer(C_INT), value, intent(in) :: gin
|
||||
integer(C_INT), optional, intent(in) :: gout
|
||||
real(C_DOUBLE), optional, intent(in) :: mu
|
||||
integer(C_INT), optional, intent(in) :: dg
|
||||
real(C_DOUBLE) :: val
|
||||
end function get_nuclide_xs_c
|
||||
|
||||
function get_macro_xs_c(index, xstype, gin, gout, mu, dg) result(val) &
|
||||
bind(C)
|
||||
use ISO_C_BINDING
|
||||
implicit none
|
||||
integer(C_INT), value, intent(in) :: index
|
||||
integer(C_INT), value, intent(in) :: xstype
|
||||
integer(C_INT), value, intent(in) :: gin
|
||||
integer(C_INT), optional, intent(in) :: gout
|
||||
real(C_DOUBLE), optional, intent(in) :: mu
|
||||
integer(C_INT), optional, intent(in) :: dg
|
||||
real(C_DOUBLE) :: val
|
||||
end function get_macro_xs_c
|
||||
|
||||
subroutine set_nuclide_angle_index_c(index, uvw) bind(C)
|
||||
use ISO_C_BINDING
|
||||
implicit none
|
||||
integer(C_INT), value, intent(in) :: index
|
||||
real(C_DOUBLE), intent(in) :: uvw(1:3)
|
||||
end subroutine set_nuclide_angle_index_c
|
||||
|
||||
subroutine set_macro_angle_index_c(index, uvw) bind(C)
|
||||
use ISO_C_BINDING
|
||||
implicit none
|
||||
integer(C_INT), value, intent(in) :: index
|
||||
real(C_DOUBLE), intent(in) :: uvw(1:3)
|
||||
end subroutine set_macro_angle_index_c
|
||||
|
||||
subroutine set_nuclide_temperature_index_c(index, sqrtkT) bind(C)
|
||||
use ISO_C_BINDING
|
||||
implicit none
|
||||
integer(C_INT), value, intent(in) :: index
|
||||
real(C_DOUBLE), value, intent(in) :: sqrtkT
|
||||
end subroutine set_nuclide_temperature_index_c
|
||||
|
||||
end interface
|
||||
|
||||
! Number of energy groups
|
||||
integer(C_INT) :: num_energy_groups
|
||||
|
||||
! Number of delayed groups
|
||||
integer(C_INT) :: num_delayed_groups
|
||||
|
||||
! Energy group structure with decreasing energy
|
||||
real(8), allocatable :: energy_bins(:)
|
||||
|
||||
! Midpoint of the energy group structure
|
||||
real(8), allocatable :: energy_bin_avg(:)
|
||||
|
||||
! Energy group structure with increasing energy
|
||||
real(8), allocatable :: rev_energy_bins(:)
|
||||
|
||||
end module mgxs_interface
|
||||
229
src/mgxs_interface.cpp
Normal file
229
src/mgxs_interface.cpp
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
#include <string>
|
||||
|
||||
#include "error.h"
|
||||
#include "math_functions.h"
|
||||
#include "mgxs_interface.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// Mgxs data loading interface methods
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
add_mgxs_c(hid_t file_id, const char* name, int energy_groups,
|
||||
int delayed_groups, int n_temps, const double temps[], double tolerance,
|
||||
int max_order, bool legendre_to_tabular, int legendre_to_tabular_points,
|
||||
int& method)
|
||||
{
|
||||
// Convert temps to a vector for the from_hdf5 function
|
||||
double_1dvec temperature(temps, temps + n_temps);
|
||||
|
||||
write_message("Loading " + std::string(name) + " data...", 6);
|
||||
|
||||
// Check to make sure cross section set exists in the library
|
||||
hid_t xs_grp;
|
||||
if (object_exists(file_id, name)) {
|
||||
xs_grp = open_group(file_id, name);
|
||||
} else {
|
||||
fatal_error("Data for " + std::string(name) + " does not exist in "
|
||||
+ "provided MGXS Library");
|
||||
}
|
||||
|
||||
Mgxs mg(xs_grp, energy_groups, delayed_groups, temperature, tolerance,
|
||||
max_order, legendre_to_tabular, legendre_to_tabular_points, method);
|
||||
|
||||
nuclides_MG.push_back(mg);
|
||||
close_group(xs_grp);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
bool
|
||||
query_fissionable_c(int n_nuclides, const int i_nuclides[])
|
||||
{
|
||||
bool result = false;
|
||||
for (int n = 0; n < n_nuclides; n++) {
|
||||
if (nuclides_MG[i_nuclides[n] - 1].fissionable) result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
create_macro_xs_c(const char* mat_name, int n_nuclides, const int i_nuclides[],
|
||||
int n_temps, const double temps[], const double atom_densities[],
|
||||
double tolerance, int& method)
|
||||
{
|
||||
if (n_temps > 0) {
|
||||
// // Convert temps to a vector
|
||||
double_1dvec temperature(temps, temps + n_temps);
|
||||
|
||||
// Convert atom_densities to a vector
|
||||
double_1dvec atom_densities_vec(atom_densities,
|
||||
atom_densities + n_nuclides);
|
||||
|
||||
// Build array of pointers to nuclides_MG's Mgxs objects needed for this
|
||||
// material
|
||||
std::vector<Mgxs*> mgxs_ptr(n_nuclides);
|
||||
for (int n = 0; n < n_nuclides; n++) {
|
||||
mgxs_ptr[n] = &nuclides_MG[i_nuclides[n] - 1];
|
||||
}
|
||||
|
||||
Mgxs macro(mat_name, temperature, mgxs_ptr, atom_densities_vec,
|
||||
tolerance, method);
|
||||
macro_xs.emplace_back(macro);
|
||||
} else {
|
||||
// Preserve the ordering of materials by including a blank entry
|
||||
Mgxs macro;
|
||||
macro_xs.emplace_back(macro);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Mgxs tracking/transport/tallying interface methods
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
calculate_xs_c(int i_mat, int gin, double sqrtkT, const double uvw[3],
|
||||
double& total_xs, double& abs_xs, double& nu_fiss_xs)
|
||||
{
|
||||
macro_xs[i_mat - 1].calculate_xs(gin - 1, sqrtkT, uvw, total_xs, abs_xs,
|
||||
nu_fiss_xs);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
sample_scatter_c(int i_mat, int gin, int& gout, double& mu, double& wgt,
|
||||
double uvw[3])
|
||||
{
|
||||
int gout_c = gout - 1;
|
||||
macro_xs[i_mat - 1].sample_scatter(gin - 1, gout_c, mu, wgt);
|
||||
|
||||
// adjust return value for fortran indexing
|
||||
gout = gout_c + 1;
|
||||
|
||||
// Rotate the angle
|
||||
rotate_angle_c(uvw, mu, nullptr);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
sample_fission_energy_c(int i_mat, int gin, int& dg, int& gout)
|
||||
{
|
||||
int dg_c = 0;
|
||||
int gout_c = 0;
|
||||
macro_xs[i_mat - 1].sample_fission_energy(gin - 1, dg_c, gout_c);
|
||||
|
||||
// adjust return values for fortran indexing
|
||||
dg = dg_c + 1;
|
||||
gout = gout_c + 1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
double
|
||||
get_nuclide_xs_c(int index, int xstype, int gin, int* gout, double* mu, int* dg)
|
||||
{
|
||||
int gout_c;
|
||||
int* gout_c_p;
|
||||
int dg_c;
|
||||
int* dg_c_p;
|
||||
if (gout != nullptr) {
|
||||
gout_c = *gout - 1;
|
||||
gout_c_p = &gout_c;
|
||||
} else {
|
||||
gout_c_p = gout;
|
||||
}
|
||||
if (dg != nullptr) {
|
||||
dg_c = *dg - 1;
|
||||
dg_c_p = &dg_c;
|
||||
} else {
|
||||
dg_c_p = dg;
|
||||
}
|
||||
return nuclides_MG[index - 1].get_xs(xstype, gin - 1, gout_c_p, mu, dg_c_p);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
double
|
||||
get_macro_xs_c(int index, int xstype, int gin, int* gout, double* mu, int* dg)
|
||||
{
|
||||
int gout_c;
|
||||
int* gout_c_p;
|
||||
int dg_c;
|
||||
int* dg_c_p;
|
||||
if (gout != nullptr) {
|
||||
gout_c = *gout - 1;
|
||||
gout_c_p = &gout_c;
|
||||
} else {
|
||||
gout_c_p = gout;
|
||||
}
|
||||
if (dg != nullptr) {
|
||||
dg_c = *dg - 1;
|
||||
dg_c_p = &dg_c;
|
||||
} else {
|
||||
dg_c_p = dg;
|
||||
}
|
||||
return macro_xs[index - 1].get_xs(xstype, gin - 1, gout_c_p, mu, dg_c_p);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
set_nuclide_angle_index_c(int index, const double uvw[3])
|
||||
{
|
||||
// Update the values
|
||||
nuclides_MG[index - 1].set_angle_index(uvw);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
set_macro_angle_index_c(int index, const double uvw[3])
|
||||
{
|
||||
// Update the values
|
||||
macro_xs[index - 1].set_angle_index(uvw);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
set_nuclide_temperature_index_c(int index, double sqrtkT)
|
||||
{
|
||||
// Update the values
|
||||
nuclides_MG[index - 1].set_temperature_index(sqrtkT);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// General Mgxs methods
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
get_name_c(int index, int name_len, char* name)
|
||||
{
|
||||
// First blank out our input string
|
||||
std::string str(name_len, ' ');
|
||||
std::strcpy(name, str.c_str());
|
||||
|
||||
// Now get the data and copy to the C-string
|
||||
str = nuclides_MG[index - 1].name;
|
||||
std::strcpy(name, str.c_str());
|
||||
|
||||
// Finally, remove the null terminator
|
||||
name[std::strlen(name)] = ' ';
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
double
|
||||
get_awr_c(int index)
|
||||
{
|
||||
return nuclides_MG[index - 1].awr;
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
79
src/mgxs_interface.h
Normal file
79
src/mgxs_interface.h
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
//! \file mgxs_interface.h
|
||||
//! A collection of C interfaces to the C++ Mgxs class
|
||||
|
||||
#ifndef MGXS_INTERFACE_H
|
||||
#define MGXS_INTERFACE_H
|
||||
|
||||
#include "hdf5_interface.h"
|
||||
#include "mgxs.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
extern std::vector<Mgxs> nuclides_MG;
|
||||
extern std::vector<Mgxs> macro_xs;
|
||||
|
||||
//==============================================================================
|
||||
// Mgxs data loading interface methods
|
||||
//==============================================================================
|
||||
|
||||
extern "C" void
|
||||
add_mgxs_c(hid_t file_id, const char* name, int energy_groups,
|
||||
int delayed_groups, int n_temps, const double temps[], double tolerance,
|
||||
int max_order, bool legendre_to_tabular, int legendre_to_tabular_points,
|
||||
int& method);
|
||||
|
||||
extern "C" bool
|
||||
query_fissionable_c(int n_nuclides, const int i_nuclides[]);
|
||||
|
||||
extern "C" void
|
||||
create_macro_xs_c(const char* mat_name, int n_nuclides, const int i_nuclides[],
|
||||
int n_temps, const double temps[], const double atom_densities[],
|
||||
double tolerance, int& method);
|
||||
|
||||
//==============================================================================
|
||||
// Mgxs tracking/transport/tallying interface methods
|
||||
//==============================================================================
|
||||
|
||||
extern "C" void
|
||||
calculate_xs_c(int i_mat, int gin, double sqrtkT, const double uvw[3],
|
||||
double& total_xs, double& abs_xs, double& nu_fiss_xs);
|
||||
|
||||
extern "C" void
|
||||
sample_scatter_c(int i_mat, int gin, int& gout, double& mu, double& wgt,
|
||||
double uvw[3]);
|
||||
|
||||
extern "C" void
|
||||
sample_fission_energy_c(int i_mat, int gin, int& dg, int& gout);
|
||||
|
||||
extern "C" double
|
||||
get_nuclide_xs_c(int index, int xstype, int gin, int* gout, double* mu, int* dg);
|
||||
|
||||
extern "C" double
|
||||
get_macro_xs_c(int index, int xstype, int gin, int* gout, double* mu, int* dg);
|
||||
|
||||
extern "C" void
|
||||
set_nuclide_angle_index_c(int index, const double uvw[3]);
|
||||
|
||||
extern "C" void
|
||||
set_macro_angle_index_c(int index, const double uvw[3]);
|
||||
|
||||
extern "C" void
|
||||
set_nuclide_temperature_index_c(int index, double sqrtkT);
|
||||
|
||||
//==============================================================================
|
||||
// General Mgxs methods
|
||||
//==============================================================================
|
||||
|
||||
extern "C" void
|
||||
get_name_c(int index, int name_len, char* name);
|
||||
|
||||
extern "C" double
|
||||
get_awr_c(int index);
|
||||
|
||||
} // namespace openmc
|
||||
#endif // MGXS_INTERFACE_H
|
||||
|
|
@ -165,10 +165,10 @@ module nuclide_header
|
|||
!===============================================================================
|
||||
|
||||
type MaterialMacroXS
|
||||
real(8) :: total ! macroscopic total xs
|
||||
real(8) :: absorption ! macroscopic absorption xs
|
||||
real(8) :: fission ! macroscopic fission xs
|
||||
real(8) :: nu_fission ! macroscopic production xs
|
||||
real(C_DOUBLE) :: total ! macroscopic total xs
|
||||
real(C_DOUBLE) :: absorption ! macroscopic absorption xs
|
||||
real(C_DOUBLE) :: fission ! macroscopic fission xs
|
||||
real(C_DOUBLE) :: nu_fission ! macroscopic production xs
|
||||
end type MaterialMacroXS
|
||||
|
||||
!===============================================================================
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ module output
|
|||
use math, only: t_percentile
|
||||
use mesh_header, only: RegularMesh, meshes
|
||||
use message_passing, only: master, n_procs
|
||||
use mgxs_header, only: nuclides_MG
|
||||
use mgxs_interface
|
||||
use nuclide_header
|
||||
use particle_header, only: LocalCoord, Particle
|
||||
use plot_header
|
||||
|
|
@ -76,7 +76,7 @@ contains
|
|||
write(UNIT=OUTPUT_UNIT, FMT=*) &
|
||||
' | The OpenMC Monte Carlo Code'
|
||||
write(UNIT=OUTPUT_UNIT, FMT=*) &
|
||||
' Copyright | 2011-2018 Massachusetts Institute of Technology'
|
||||
' Copyright | 2011-2018 MIT and OpenMC contributors'
|
||||
write(UNIT=OUTPUT_UNIT, FMT=*) &
|
||||
' License | http://openmc.readthedocs.io/en/latest/license.html'
|
||||
write(UNIT=OUTPUT_UNIT, FMT='(11X,"Version | ",I1,".",I2,".",I1)') &
|
||||
|
|
@ -171,7 +171,7 @@ contains
|
|||
write(UNIT=OUTPUT_UNIT, FMT='(1X,A,A)') "Git SHA1: ", GIT_SHA1
|
||||
#endif
|
||||
write(UNIT=OUTPUT_UNIT, FMT=*) "Copyright (c) 2011-2018 &
|
||||
&Massachusetts Institute of Technology"
|
||||
&Massachusetts Institute of Technology and OpenMC contributors"
|
||||
write(UNIT=OUTPUT_UNIT, FMT=*) "MIT/X license at &
|
||||
&<http://openmc.readthedocs.io/en/latest/license.html>"
|
||||
end if
|
||||
|
|
@ -680,6 +680,7 @@ contains
|
|||
character(36) :: score_name ! names of scoring function
|
||||
! to be applied at write-time
|
||||
type(TallyFilterMatch), allocatable :: matches(:)
|
||||
character(MAX_WORD_LEN) :: temp_name
|
||||
|
||||
! Skip if there are no tallies
|
||||
if (n_tallies == 0) return
|
||||
|
|
@ -843,8 +844,9 @@ contains
|
|||
write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), &
|
||||
trim(nuclides(i_nuclide) % name)
|
||||
else
|
||||
call get_name_c(i_nuclide, len(temp_name), temp_name)
|
||||
write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), &
|
||||
trim(nuclides_MG(i_nuclide) % obj % name)
|
||||
trim(temp_name)
|
||||
end if
|
||||
end if
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ module particle_restart
|
|||
use constants
|
||||
use error, only: write_message
|
||||
use hdf5_interface, only: file_open, file_close, read_dataset, HID_T
|
||||
use mgxs_header, only: energy_bin_avg
|
||||
use mgxs_interface, only: energy_bin_avg
|
||||
use nuclide_header, only: micro_xs, n_nuclides
|
||||
use output, only: print_particle
|
||||
use particle_header, only: Particle
|
||||
|
|
|
|||
|
|
@ -8,13 +8,12 @@ module physics_mg
|
|||
use material_header, only: Material, materials
|
||||
use math, only: rotate_angle
|
||||
use mesh_header, only: meshes
|
||||
use mgxs_header
|
||||
use mgxs_interface
|
||||
use message_passing
|
||||
use nuclide_header, only: material_xs
|
||||
use particle_header, only: Particle
|
||||
use physics_common
|
||||
use random_lcg, only: prn
|
||||
use scattdata_header
|
||||
use settings
|
||||
use simulation_header
|
||||
use string, only: to_str
|
||||
|
|
@ -143,16 +142,12 @@ contains
|
|||
|
||||
type(Particle), intent(inout) :: p
|
||||
|
||||
call macro_xs(p % material) % obj % sample_scatter(p % coord(1) % uvw, &
|
||||
p % last_g, p % g, &
|
||||
p % mu, p % wgt)
|
||||
call sample_scatter_c(p % material, p % last_g, p % g, p % mu, &
|
||||
p % wgt, p % coord(1) % uvw)
|
||||
|
||||
! Update energy value for downstream compatability (in tallying)
|
||||
p % E = energy_bin_avg(p % g)
|
||||
|
||||
! Convert change in angle (mu) to new direction
|
||||
p % coord(1) % uvw = rotate_angle(p % coord(1) % uvw, p % mu)
|
||||
|
||||
! Set event component
|
||||
p % event = EVENT_SCATTER
|
||||
|
||||
|
|
@ -178,10 +173,6 @@ contains
|
|||
real(8) :: mu ! fission neutron angular cosine
|
||||
real(8) :: phi ! fission neutron azimuthal angle
|
||||
real(8) :: weight ! weight adjustment for ufs method
|
||||
class(Mgxs), pointer :: xs
|
||||
|
||||
! Get Pointers
|
||||
xs => macro_xs(p % material) % obj
|
||||
|
||||
! TODO: Heat generation from fission
|
||||
|
||||
|
|
@ -261,7 +252,7 @@ contains
|
|||
|
||||
! Sample secondary energy distribution for fission reaction and set energy
|
||||
! in fission bank
|
||||
call xs % sample_fission_energy(p % g, bank_array(i) % uvw, dg, gout)
|
||||
call sample_fission_energy_c(p % material, p % g, dg, gout)
|
||||
|
||||
bank_array(i) % E = real(gout, 8)
|
||||
bank_array(i) % delayed_group = dg
|
||||
|
|
|
|||
936
src/scattdata.cpp
Normal file
936
src/scattdata.cpp
Normal file
|
|
@ -0,0 +1,936 @@
|
|||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <cmath>
|
||||
|
||||
#include "constants.h"
|
||||
#include "math_functions.h"
|
||||
#include "random_lcg.h"
|
||||
#include "error.h"
|
||||
#include "scattdata.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// ScattData base-class methods
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattData::base_init(int order, const int_1dvec& in_gmin,
|
||||
const int_1dvec& in_gmax, const double_2dvec& in_energy,
|
||||
const double_2dvec& in_mult)
|
||||
{
|
||||
int groups = in_energy.size();
|
||||
|
||||
gmin = in_gmin;
|
||||
gmax = in_gmax;
|
||||
energy.resize(groups);
|
||||
mult.resize(groups);
|
||||
dist.resize(groups);
|
||||
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
// Store the inputted data
|
||||
energy[gin] = in_energy[gin];
|
||||
mult[gin] = in_mult[gin];
|
||||
|
||||
// Make sure the energy is normalized
|
||||
double norm = std::accumulate(energy[gin].begin(), energy[gin].end(), 0.);
|
||||
|
||||
if (norm != 0.) {
|
||||
for (auto& n : energy[gin]) n /= norm;
|
||||
}
|
||||
|
||||
// Initialize the distribution data
|
||||
dist[gin].resize(in_gmax[gin] - in_gmin[gin] + 1);
|
||||
for (auto& v : dist[gin]) {
|
||||
v.resize(order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattData::base_combine(int max_order,
|
||||
const std::vector<ScattData*>& those_scatts, const double_1dvec& scalars,
|
||||
int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& sparse_mult,
|
||||
double_3dvec& sparse_scatter)
|
||||
{
|
||||
int groups = those_scatts[0] -> energy.size();
|
||||
|
||||
// Now allocate and zero our storage spaces
|
||||
double_3dvec this_matrix = double_3dvec(groups, double_2dvec(groups,
|
||||
double_1dvec(max_order, 0.)));
|
||||
double_2dvec mult_numer(groups, double_1dvec(groups, 0.));
|
||||
double_2dvec mult_denom(groups, double_1dvec(groups, 0.));
|
||||
|
||||
// Build the dense scattering and multiplicity matrices
|
||||
// Get the multiplicity_matrix
|
||||
// To combine from nuclidic data we need to use the final relationship
|
||||
// mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) /
|
||||
// sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'}))
|
||||
// Developed as follows:
|
||||
// mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'}
|
||||
// mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'})
|
||||
// mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) /
|
||||
// sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'}))
|
||||
// nuscatt_{i,g,g'} can be reconstructed from the energy and scattxs member
|
||||
// variables
|
||||
for (int i = 0; i < those_scatts.size(); i++) {
|
||||
ScattData* that = those_scatts[i];
|
||||
|
||||
// Build the dense matrix for that object
|
||||
double_3dvec that_matrix = that->get_matrix(max_order);
|
||||
|
||||
// Now add that to this for the scattering and multiplicity
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
// Only spend time adding that's gmin to gmax data since the rest will
|
||||
// be zeros
|
||||
int i_gout = 0;
|
||||
for (int gout = that->gmin[gin]; gout <= that->gmax[gin]; gout++) {
|
||||
// Do the scattering matrix
|
||||
for (int l = 0; l < max_order; l++) {
|
||||
this_matrix[gin][gout][l] += scalars[i] * that_matrix[gin][gout][l];
|
||||
}
|
||||
|
||||
// Incorporate that's contribution to the multiplicity matrix data
|
||||
double nuscatt = that->scattxs[gin] * that->energy[gin][i_gout];
|
||||
mult_numer[gin][gout] += scalars[i] * nuscatt;
|
||||
if (that->mult[gin][i_gout] > 0.) {
|
||||
mult_denom[gin][gout] += scalars[i] * nuscatt / that->mult[gin][i_gout];
|
||||
} else {
|
||||
mult_denom[gin][gout] += scalars[i];
|
||||
}
|
||||
i_gout++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Combine mult_numer and mult_denom into the combined multiplicity matrix
|
||||
double_2dvec this_mult(groups, double_1dvec(groups, 1.));
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
for (int gout = 0; gout < groups; gout++) {
|
||||
if (mult_denom[gin][gout] > 0.) {
|
||||
this_mult[gin][gout] = mult_numer[gin][gout] / mult_denom[gin][gout];
|
||||
}
|
||||
}
|
||||
}
|
||||
mult_numer.clear();
|
||||
mult_denom.clear();
|
||||
|
||||
// We have the data, now we need to convert to a jagged array and then use
|
||||
// the initialize function to store it on the object.
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
// Find the minimum and maximum group boundaries
|
||||
int gmin_;
|
||||
for (gmin_ = 0; gmin_ < groups; gmin_++) {
|
||||
bool non_zero = false;
|
||||
for (int l = 0; l < this_matrix[gin][gmin_].size(); l++) {
|
||||
if (this_matrix[gin][gmin_][l] != 0.) {
|
||||
non_zero = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (non_zero) break;
|
||||
}
|
||||
int gmax_;
|
||||
for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) {
|
||||
bool non_zero = false;
|
||||
for (int l = 0; l < this_matrix[gin][gmax_].size(); l++) {
|
||||
if (this_matrix[gin][gmax_][l] != 0.) {
|
||||
non_zero = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (non_zero) break;
|
||||
}
|
||||
|
||||
// treat the case of all values being 0
|
||||
if (gmin_ > gmax_) {
|
||||
gmin_ = gin;
|
||||
gmax_ = gin;
|
||||
}
|
||||
|
||||
// Store the group bounds
|
||||
in_gmin[gin] = gmin_;
|
||||
in_gmax[gin] = gmax_;
|
||||
|
||||
// Store the data in the compressed format
|
||||
sparse_scatter[gin].resize(gmax_ - gmin_ + 1);
|
||||
sparse_mult[gin].resize(gmax_ - gmin_ + 1);
|
||||
int i_gout = 0;
|
||||
for (int gout = gmin_; gout <= gmax_; gout++) {
|
||||
sparse_scatter[gin][i_gout] = this_matrix[gin][gout];
|
||||
sparse_mult[gin][i_gout] = this_mult[gin][gout];
|
||||
i_gout++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattData::sample_energy(int gin, int& gout, int& i_gout)
|
||||
{
|
||||
// Sample the outgoing group
|
||||
double xi = prn();
|
||||
|
||||
i_gout = 0;
|
||||
gout = gmin[gin];
|
||||
double prob = energy[gin][i_gout];
|
||||
while((prob < xi) && (gout < gmax[gin])) {
|
||||
gout++;
|
||||
i_gout++;
|
||||
prob += energy[gin][i_gout];
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
double
|
||||
ScattData::get_xs(int xstype, int gin, const int* gout, const double* mu)
|
||||
{
|
||||
// Set the outgoing group offset index as needed
|
||||
int i_gout = 0;
|
||||
if (gout != nullptr) {
|
||||
// short circuit the function if gout is from a zero portion of the
|
||||
// scattering matrix
|
||||
if ((*gout < gmin[gin]) || (*gout > gmax[gin])) { // > gmax?
|
||||
return 0.;
|
||||
}
|
||||
i_gout = *gout - gmin[gin];
|
||||
}
|
||||
|
||||
double val = scattxs[gin];
|
||||
switch(xstype) {
|
||||
case MG_GET_XS_SCATTER:
|
||||
if (gout != nullptr) val *= energy[gin][i_gout];
|
||||
break;
|
||||
case MG_GET_XS_SCATTER_MULT:
|
||||
if (gout != nullptr) {
|
||||
val *= energy[gin][i_gout] / mult[gin][i_gout];
|
||||
} else {
|
||||
val /= std::inner_product(mult[gin].begin(), mult[gin].end(),
|
||||
energy[gin].begin(), 0.0);
|
||||
}
|
||||
break;
|
||||
case MG_GET_XS_SCATTER_FMU_MULT:
|
||||
if ((gout != nullptr) && (mu != nullptr)) {
|
||||
val *= energy[gin][i_gout] * calc_f(gin, *gout, *mu);
|
||||
} else {
|
||||
// This is not an expected path (asking for f_mu without asking for a
|
||||
// group or mu is not useful
|
||||
fatal_error("Invalid call to get_xs");
|
||||
}
|
||||
break;
|
||||
case MG_GET_XS_SCATTER_FMU:
|
||||
if ((gout != nullptr) && (mu != nullptr)) {
|
||||
val *= energy[gin][i_gout] * calc_f(gin, *gout, *mu) / mult[gin][i_gout];
|
||||
} else {
|
||||
// This is not an expected path (asking for f_mu without asking for a
|
||||
// group or mu is not useful
|
||||
fatal_error("Invalid call to get_xs");
|
||||
}
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// ScattDataLegendre methods
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattDataLegendre::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
||||
const double_2dvec& in_mult, const double_3dvec& coeffs)
|
||||
{
|
||||
int groups = coeffs.size();
|
||||
int order = coeffs[0][0].size();
|
||||
|
||||
// make a copy of coeffs that we can use to both extract data and normalize
|
||||
double_3dvec matrix = coeffs;
|
||||
|
||||
// Get the scattering cross section value by summing the un-normalized P0
|
||||
// coefficient in the variable matrix over all outgoing groups.
|
||||
scattxs.resize(groups);
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
int num_groups = in_gmax[gin] - in_gmin[gin] + 1;
|
||||
scattxs[gin] = 0.;
|
||||
for (int i_gout = 0; i_gout < num_groups; i_gout++) {
|
||||
scattxs[gin] += matrix[gin][i_gout][0];
|
||||
}
|
||||
}
|
||||
|
||||
// Build the energy transfer matrix from data in the variable matrix while
|
||||
// also normalizing the variable matrix itself
|
||||
// (forcing the CDF of f(mu=1) == 1)
|
||||
double_2dvec in_energy;
|
||||
in_energy.resize(groups);
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
int num_groups = in_gmax[gin] - in_gmin[gin] + 1;
|
||||
in_energy[gin].resize(num_groups);
|
||||
for (int i_gout = 0; i_gout < num_groups; i_gout++) {
|
||||
double norm = matrix[gin][i_gout][0];
|
||||
in_energy[gin][i_gout] = norm;
|
||||
if (norm != 0.) {
|
||||
for (auto& n : matrix[gin][i_gout]) n /= norm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the base class attributes
|
||||
ScattData::base_init(order, in_gmin, in_gmax, in_energy, in_mult);
|
||||
|
||||
// Set the distribution (sdata.dist) values and initialize max_val
|
||||
max_val.resize(groups);
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
int num_groups = gmax[gin] - gmin[gin] + 1;
|
||||
for (int i_gout = 0; i_gout < num_groups; i_gout++) {
|
||||
dist[gin][i_gout] = matrix[gin][i_gout];
|
||||
}
|
||||
max_val[gin].resize(num_groups);
|
||||
for (auto& n : max_val[gin]) n = 0.;
|
||||
}
|
||||
|
||||
// Now update the maximum value
|
||||
update_max_val();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattDataLegendre::update_max_val()
|
||||
{
|
||||
int groups = max_val.size();
|
||||
// Step through the polynomial with fixed number of points to identify the
|
||||
// maximal value
|
||||
int Nmu = 1001;
|
||||
double dmu = 2. / (Nmu - 1);
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
int num_groups = gmax[gin] - gmin[gin] + 1;
|
||||
for (int i_gout = 0; i_gout < num_groups; i_gout++) {
|
||||
for (int imu = 0; imu < Nmu; imu++) {
|
||||
double mu;
|
||||
if (imu == 0) {
|
||||
mu = -1.;
|
||||
} else if (imu == (Nmu - 1)) {
|
||||
mu = 1.;
|
||||
} else {
|
||||
mu = -1. + (imu - 1) * dmu;
|
||||
}
|
||||
|
||||
// Calculate probability
|
||||
double f = evaluate_legendre_c(dist[gin][i_gout].size() - 1,
|
||||
dist[gin][i_gout].data(), mu);
|
||||
|
||||
// if this is a new maximum, store it
|
||||
if (f > max_val[gin][i_gout]) max_val[gin][i_gout] = f;
|
||||
} // end imu loop
|
||||
|
||||
// Since we may not have caught the true max, add 10% margin
|
||||
max_val[gin][i_gout] *= 1.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
double
|
||||
ScattDataLegendre::calc_f(int gin, int gout, double mu)
|
||||
{
|
||||
double f;
|
||||
if ((gout < gmin[gin]) || (gout > gmax[gin])) {
|
||||
f = 0.;
|
||||
} else {
|
||||
int i_gout = gout - gmin[gin];
|
||||
f = evaluate_legendre_c(dist[gin][i_gout].size() - 1,
|
||||
dist[gin][i_gout].data(), mu);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattDataLegendre::sample(int gin, int& gout, double& mu, double& wgt)
|
||||
{
|
||||
// Sample the outgoing energy using the base-class method
|
||||
int i_gout;
|
||||
sample_energy(gin, gout, i_gout);
|
||||
|
||||
// Now we can sample mu using the scattering kernel using rejection
|
||||
// sampling from a rectangular bounding box
|
||||
double M = max_val[gin][i_gout];
|
||||
int samples = 0;
|
||||
|
||||
while(true) {
|
||||
mu = 2. * prn() - 1.;
|
||||
double f = calc_f(gin, gout, mu);
|
||||
if (f > 0.) {
|
||||
double u = prn() * M;
|
||||
if (u <= f) break;
|
||||
}
|
||||
samples++;
|
||||
if (samples > MAX_SAMPLE) {
|
||||
fatal_error("Maximum number of Legendre expansion samples reached");
|
||||
}
|
||||
};
|
||||
|
||||
// Update the weight to reflect neutron multiplicity
|
||||
wgt *= mult[gin][i_gout];
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattDataLegendre::combine(const std::vector<ScattData*>& those_scatts,
|
||||
const double_1dvec& scalars)
|
||||
{
|
||||
// Find the max order in the data set and make sure we can combine the sets
|
||||
int max_order = 0;
|
||||
for (int i = 0; i < those_scatts.size(); i++) {
|
||||
// Lets also make sure these items are combineable
|
||||
ScattDataLegendre* that = dynamic_cast<ScattDataLegendre*>(those_scatts[i]);
|
||||
if (!that) {
|
||||
fatal_error("Cannot combine the ScattData objects!");
|
||||
}
|
||||
int that_order = that->get_order();
|
||||
if (that_order > max_order) max_order = that_order;
|
||||
}
|
||||
max_order++; // Add one since this is a Legendre
|
||||
|
||||
int groups = those_scatts[0] -> energy.size();
|
||||
|
||||
int_1dvec in_gmin(groups);
|
||||
int_1dvec in_gmax(groups);
|
||||
double_3dvec sparse_scatter(groups);
|
||||
double_2dvec sparse_mult(groups);
|
||||
|
||||
// The rest of the steps do not depend on the type of angular representation
|
||||
// so we use a base class method to sum up xs and create new energy and mult
|
||||
// matrices
|
||||
ScattData::base_combine(max_order, those_scatts, scalars, in_gmin, in_gmax,
|
||||
sparse_mult, sparse_scatter);
|
||||
|
||||
// Got everything we need, store it.
|
||||
init(in_gmin, in_gmax, sparse_mult, sparse_scatter);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
double_3dvec
|
||||
ScattDataLegendre::get_matrix(int max_order)
|
||||
{
|
||||
// Get the sizes and initialize the data to 0
|
||||
int groups = energy.size();
|
||||
int order_dim = max_order + 1;
|
||||
double_3dvec matrix = double_3dvec(groups, double_2dvec(groups,
|
||||
double_1dvec(order_dim, 0.)));
|
||||
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) {
|
||||
int gout = i_gout + gmin[gin];
|
||||
for (int l = 0; l < order_dim; l++) {
|
||||
matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] *
|
||||
dist[gin][i_gout][l];
|
||||
}
|
||||
}
|
||||
}
|
||||
return matrix;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// ScattDataHistogram methods
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattDataHistogram::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
||||
const double_2dvec& in_mult, const double_3dvec& coeffs)
|
||||
{
|
||||
int groups = coeffs.size();
|
||||
int order = coeffs[0][0].size();
|
||||
|
||||
// make a copy of coeffs that we can use to both extract data and normalize
|
||||
double_3dvec matrix = coeffs;
|
||||
|
||||
// Get the scattering cross section value by summing the distribution
|
||||
// over all the histogram bins in angle and outgoing energy groups
|
||||
scattxs.resize(groups);
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
scattxs[gin] = 0.;
|
||||
for (int i_gout = 0; i_gout < matrix[gin].size(); i_gout++) {
|
||||
scattxs[gin] += std::accumulate(matrix[gin][i_gout].begin(),
|
||||
matrix[gin][i_gout].end(), 0.);
|
||||
}
|
||||
}
|
||||
|
||||
// Build the energy transfer matrix from data in the variable matrix
|
||||
double_2dvec in_energy;
|
||||
in_energy.resize(groups);
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
int num_groups = in_gmax[gin] - in_gmin[gin] + 1;
|
||||
in_energy[gin].resize(num_groups);
|
||||
for (int i_gout = 0; i_gout < num_groups; i_gout++) {
|
||||
double norm = std::accumulate(matrix[gin][i_gout].begin(),
|
||||
matrix[gin][i_gout].end(), 0.);
|
||||
in_energy[gin][i_gout] = norm;
|
||||
if (norm != 0.) {
|
||||
for (auto& n : matrix[gin][i_gout]) n /= norm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the base class attributes
|
||||
ScattData::base_init(order, in_gmin, in_gmax, in_energy, in_mult);
|
||||
|
||||
// Build the angular distribution mu values
|
||||
mu = double_1dvec(order);
|
||||
dmu = 2. / order;
|
||||
mu[0] = -1.;
|
||||
for (int imu = 1; imu < order; imu++) {
|
||||
mu[imu] = -1. + imu * dmu;
|
||||
}
|
||||
|
||||
// Calculate f(mu) and integrate it so we can avoid rejection sampling
|
||||
fmu.resize(groups);
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
int num_groups = gmax[gin] - gmin[gin] + 1;
|
||||
fmu[gin].resize(num_groups);
|
||||
for (int i_gout = 0; i_gout < num_groups; i_gout++) {
|
||||
fmu[gin][i_gout].resize(order);
|
||||
// The variable matrix contains f(mu); so directly assign it
|
||||
fmu[gin][i_gout] = matrix[gin][i_gout];
|
||||
|
||||
// Integrate the histogram
|
||||
dist[gin][i_gout][0] = dmu * matrix[gin][i_gout][0];
|
||||
for (int imu = 1; imu < order; imu++) {
|
||||
dist[gin][i_gout][imu] = dmu * matrix[gin][i_gout][imu] +
|
||||
dist[gin][i_gout][imu - 1];
|
||||
}
|
||||
|
||||
// Now re-normalize for integral to unity
|
||||
double norm = dist[gin][i_gout][order - 1];
|
||||
if (norm > 0.) {
|
||||
for (int imu = 0; imu < order; imu++) {
|
||||
fmu[gin][i_gout][imu] /= norm;
|
||||
dist[gin][i_gout][imu] /= norm;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
double
|
||||
ScattDataHistogram::calc_f(int gin, int gout, double mu)
|
||||
{
|
||||
double f;
|
||||
if ((gout < gmin[gin]) || (gout > gmax[gin])) {
|
||||
f = 0.;
|
||||
} else {
|
||||
// Find mu bin
|
||||
int i_gout = gout - gmin[gin];
|
||||
int imu;
|
||||
if (mu == 1.) {
|
||||
// use size -2 to have the index one before the end
|
||||
imu = this->mu.size() - 2;
|
||||
} else {
|
||||
imu = std::floor((mu + 1.) / dmu + 1.) - 1;
|
||||
}
|
||||
|
||||
f = fmu[gin][i_gout][imu];
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt)
|
||||
{
|
||||
// Sample the outgoing energy using the base-class method
|
||||
int i_gout;
|
||||
sample_energy(gin, gout, i_gout);
|
||||
|
||||
// Determine the outgoing cosine bin
|
||||
double xi = prn();
|
||||
|
||||
int imu;
|
||||
if (xi < dist[gin][i_gout][0]) {
|
||||
imu = 0;
|
||||
} else {
|
||||
// TODO lower_bound? + 1?
|
||||
imu = std::upper_bound(dist[gin][i_gout].begin(),
|
||||
dist[gin][i_gout].end(), xi) -
|
||||
dist[gin][i_gout].begin();
|
||||
}
|
||||
|
||||
// Randomly select mu within the imu bin
|
||||
mu = prn() * dmu + this->mu[imu];
|
||||
|
||||
if (mu < -1.) {
|
||||
mu = -1.;
|
||||
} else if (mu > 1.) {
|
||||
mu = 1.;
|
||||
}
|
||||
|
||||
// Update the weight to reflect neutron multiplicity
|
||||
wgt *= mult[gin][i_gout];
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
double_3dvec
|
||||
ScattDataHistogram::get_matrix(int max_order)
|
||||
{
|
||||
// Get the sizes and initialize the data to 0
|
||||
int groups = energy.size();
|
||||
// We ignore the requested order for Histogram and Tabular representations
|
||||
int order_dim = get_order();
|
||||
double_3dvec matrix = double_3dvec(groups, double_2dvec(groups,
|
||||
double_1dvec(order_dim, 0.)));
|
||||
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) {
|
||||
int gout = i_gout + gmin[gin];
|
||||
for (int l = 0; l < order_dim; l++) {
|
||||
matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] *
|
||||
fmu[gin][i_gout][l];
|
||||
}
|
||||
}
|
||||
}
|
||||
return matrix;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattDataHistogram::combine(const std::vector<ScattData*>& those_scatts,
|
||||
const double_1dvec& scalars)
|
||||
{
|
||||
// Find the max order in the data set and make sure we can combine the sets
|
||||
int max_order = those_scatts[0]->get_order();
|
||||
for (int i = 0; i < those_scatts.size(); i++) {
|
||||
// Lets also make sure these items are combineable
|
||||
ScattDataHistogram* that = dynamic_cast<ScattDataHistogram*>(those_scatts[i]);
|
||||
if (!that) {
|
||||
fatal_error("Cannot combine the ScattData objects!");
|
||||
}
|
||||
if (max_order != that->get_order()) {
|
||||
fatal_error("Cannot combine the ScattData objects!");
|
||||
}
|
||||
}
|
||||
|
||||
int groups = those_scatts[0] -> energy.size();
|
||||
|
||||
int_1dvec in_gmin(groups);
|
||||
int_1dvec in_gmax(groups);
|
||||
double_3dvec sparse_scatter(groups);
|
||||
double_2dvec sparse_mult(groups);
|
||||
|
||||
// The rest of the steps do not depend on the type of angular representation
|
||||
// so we use a base class method to sum up xs and create new energy and mult
|
||||
// matrices
|
||||
ScattData::base_combine(max_order, those_scatts, scalars, in_gmin, in_gmax,
|
||||
sparse_mult, sparse_scatter);
|
||||
|
||||
// Got everything we need, store it.
|
||||
init(in_gmin, in_gmax, sparse_mult, sparse_scatter);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// ScattDataTabular methods
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattDataTabular::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
||||
const double_2dvec& in_mult, const double_3dvec& coeffs)
|
||||
{
|
||||
int groups = coeffs.size();
|
||||
int order = coeffs[0][0].size();
|
||||
|
||||
// make a copy of coeffs that we can use to both extract data and normalize
|
||||
double_3dvec matrix = coeffs;
|
||||
|
||||
// Build the angular distribution mu values
|
||||
mu = double_1dvec(order);
|
||||
dmu = 2. / (order - 1);
|
||||
mu[0] = -1.;
|
||||
for (int imu = 1; imu < order - 1; imu++) {
|
||||
mu[imu] = -1. + imu * dmu;
|
||||
}
|
||||
mu[order - 1] = 1.;
|
||||
|
||||
// Get the scattering cross section value by integrating the distribution
|
||||
// over all mu points and then combining over all outgoing groups
|
||||
scattxs.resize(groups);
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
scattxs[gin] = 0.;
|
||||
for (int i_gout = 0; i_gout < matrix[gin].size(); i_gout++) {
|
||||
for (int imu = 1; imu < order; imu++) {
|
||||
scattxs[gin] += 0.5 * dmu * (matrix[gin][i_gout][imu - 1] +
|
||||
matrix[gin][i_gout][imu]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build the energy transfer matrix from data in the variable matrix
|
||||
double_2dvec in_energy(groups);
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
int num_groups = in_gmax[gin] - in_gmin[gin] + 1;
|
||||
in_energy[gin].resize(num_groups);
|
||||
for (int i_gout = 0; i_gout < num_groups; i_gout++) {
|
||||
double norm = 0.;
|
||||
for (int imu = 1; imu < order; imu++) {
|
||||
norm += 0.5 * dmu * (matrix[gin][i_gout][imu - 1] +
|
||||
matrix[gin][i_gout][imu]);
|
||||
}
|
||||
in_energy[gin][i_gout] = norm;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the base class attributes
|
||||
ScattData::base_init(order, in_gmin, in_gmax, in_energy, in_mult);
|
||||
|
||||
// Calculate f(mu) and integrate it so we can avoid rejection sampling
|
||||
fmu.resize(groups);
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
int num_groups = gmax[gin] - gmin[gin] + 1;
|
||||
fmu[gin].resize(num_groups);
|
||||
for (int i_gout = 0; i_gout < num_groups; i_gout++) {
|
||||
fmu[gin][i_gout].resize(order);
|
||||
// The variable matrix contains f(mu); so directly assign it
|
||||
fmu[gin][i_gout] = matrix[gin][i_gout];
|
||||
|
||||
// Ensure positivity
|
||||
for (auto& val : fmu[gin][i_gout]) {
|
||||
if (val < 0.) val = 0.;
|
||||
}
|
||||
|
||||
// Now re-normalize for numerical integration issues and to take care of
|
||||
// the above negative fix-up. Also accrue the CDF
|
||||
double norm = 0.;
|
||||
for (int imu = 1; imu < order; imu++) {
|
||||
norm += 0.5 * dmu * (fmu[gin][i_gout][imu - 1] +
|
||||
fmu[gin][i_gout][imu]);
|
||||
// incorporate to the CDF
|
||||
dist[gin][i_gout][imu] = norm;
|
||||
}
|
||||
|
||||
// now do the normalization
|
||||
if (norm > 0.) {
|
||||
for (int imu = 0; imu < order; imu++) {
|
||||
fmu[gin][i_gout][imu] /= norm;
|
||||
dist[gin][i_gout][imu] /= norm;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
double
|
||||
ScattDataTabular::calc_f(int gin, int gout, double mu)
|
||||
{
|
||||
double f;
|
||||
if ((gout < gmin[gin]) || (gout > gmax[gin])) {
|
||||
f = 0.;
|
||||
} else {
|
||||
// Find mu bin
|
||||
int i_gout = gout - gmin[gin];
|
||||
int imu;
|
||||
if (mu == 1.) {
|
||||
// use size -2 to have the index one before the end
|
||||
imu = this->mu.size() - 2;
|
||||
} else {
|
||||
imu = std::floor((mu + 1.) / dmu + 1.) - 1;
|
||||
}
|
||||
|
||||
double r = (mu - this->mu[imu]) / (this->mu[imu + 1] - this->mu[imu]);
|
||||
f = (1. - r) * fmu[gin][i_gout][imu] + r * fmu[gin][i_gout][imu + 1];
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt)
|
||||
{
|
||||
// Sample the outgoing energy using the base-class method
|
||||
int i_gout;
|
||||
sample_energy(gin, gout, i_gout);
|
||||
|
||||
// Determine the outgoing cosine bin
|
||||
int NP = this->mu.size();
|
||||
double xi = prn();
|
||||
|
||||
double c_k = dist[gin][i_gout][0];
|
||||
int k;
|
||||
for (k = 0; k < NP - 1; k++) {
|
||||
double c_k1 = dist[gin][i_gout][k + 1];
|
||||
if (xi < c_k1) break;
|
||||
c_k = c_k1;
|
||||
}
|
||||
|
||||
// Check to make sure k is <= NP - 1
|
||||
k = std::min(k, NP - 2);
|
||||
|
||||
// Find the pdf values we want
|
||||
double p0 = fmu[gin][i_gout][k];
|
||||
double mu0 = this -> mu[k];
|
||||
double p1 = fmu[gin][i_gout][k + 1];
|
||||
double mu1 = this -> mu[k + 1];
|
||||
|
||||
if (p0 == p1) {
|
||||
mu = mu0 + (xi - c_k) / p0;
|
||||
} else {
|
||||
double frac = (p1 - p0) / (mu1 - mu0);
|
||||
mu = mu0 + (std::sqrt(std::max(0., p0 * p0 + 2. * frac * (xi - c_k)))
|
||||
- p0) / frac;
|
||||
}
|
||||
|
||||
if (mu < -1.) {
|
||||
mu = -1.;
|
||||
} else if (mu > 1.) {
|
||||
mu = 1.;
|
||||
}
|
||||
|
||||
// Update the weight to reflect neutron multiplicity
|
||||
wgt *= mult[gin][i_gout];
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
double_3dvec
|
||||
ScattDataTabular::get_matrix(int max_order)
|
||||
{
|
||||
// Get the sizes and initialize the data to 0
|
||||
int groups = energy.size();
|
||||
// We ignore the requested order for Histogram and Tabular representations
|
||||
int order_dim = get_order();
|
||||
double_3dvec matrix = double_3dvec(groups, double_2dvec(groups,
|
||||
double_1dvec(order_dim, 0.)));
|
||||
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) {
|
||||
int gout = i_gout + gmin[gin];
|
||||
for (int l = 0; l < order_dim; l++) {
|
||||
matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] *
|
||||
fmu[gin][i_gout][l];
|
||||
}
|
||||
}
|
||||
}
|
||||
return matrix;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
ScattDataTabular::combine(const std::vector<ScattData*>& those_scatts,
|
||||
const double_1dvec& scalars)
|
||||
{
|
||||
// Find the max order in the data set and make sure we can combine the sets
|
||||
int max_order = those_scatts[0]->get_order();
|
||||
for (int i = 0; i < those_scatts.size(); i++) {
|
||||
// Lets also make sure these items are combineable
|
||||
ScattDataTabular* that = dynamic_cast<ScattDataTabular*>(those_scatts[i]);
|
||||
if (!that) {
|
||||
fatal_error("Cannot combine the ScattData objects!");
|
||||
}
|
||||
if (max_order != that->get_order()) {
|
||||
fatal_error("Cannot combine the ScattData objects!");
|
||||
}
|
||||
}
|
||||
|
||||
int groups = those_scatts[0] -> energy.size();
|
||||
|
||||
int_1dvec in_gmin(groups);
|
||||
int_1dvec in_gmax(groups);
|
||||
double_3dvec sparse_scatter(groups);
|
||||
double_2dvec sparse_mult(groups);
|
||||
|
||||
// The rest of the steps do not depend on the type of angular representation
|
||||
// so we use a base class method to sum up xs and create new energy and mult
|
||||
// matrices
|
||||
ScattData::base_combine(max_order, those_scatts, scalars, in_gmin, in_gmax,
|
||||
sparse_mult, sparse_scatter);
|
||||
|
||||
// Got everything we need, store it.
|
||||
init(in_gmin, in_gmax, sparse_mult, sparse_scatter);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// module-level methods
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab,
|
||||
int n_mu)
|
||||
{
|
||||
// See if the user wants us to figure out how many points to use
|
||||
if (n_mu == C_NONE) {
|
||||
// then we will use 2 pts if its P0, or the default if a higher order
|
||||
// TODO use an error minimization algorithm that also picks n_mu
|
||||
if (leg.get_order() == 0) {
|
||||
n_mu = 2;
|
||||
} else {
|
||||
n_mu = DEFAULT_NMU;
|
||||
}
|
||||
}
|
||||
|
||||
tab.base_init(n_mu, leg.gmin, leg.gmax, leg.energy, leg.mult);
|
||||
tab.scattxs = leg.scattxs;
|
||||
|
||||
// Build mu and dmu
|
||||
tab.mu = double_1dvec(n_mu);
|
||||
tab.dmu = 2. / (n_mu - 1);
|
||||
tab.mu[0] = -1.;
|
||||
for (int imu = 1; imu < n_mu - 1; imu++) {
|
||||
tab.mu[imu] = -1. + imu * tab.dmu;
|
||||
}
|
||||
tab.mu[n_mu - 1] = 1.;
|
||||
|
||||
// Calculate f(mu) and integrate it so we can avoid rejection sampling
|
||||
int groups = tab.energy.size();
|
||||
tab.fmu.resize(groups);
|
||||
for (int gin = 0; gin < groups; gin++) {
|
||||
int num_groups = tab.gmax[gin] - tab.gmin[gin] + 1;
|
||||
tab.fmu[gin].resize(num_groups);
|
||||
for (int i_gout = 0; i_gout < num_groups; i_gout++) {
|
||||
tab.fmu[gin][i_gout].resize(n_mu);
|
||||
for (int imu = 0; imu < n_mu; imu++) {
|
||||
tab.fmu[gin][i_gout][imu] =
|
||||
evaluate_legendre_c(leg.dist[gin][i_gout].size() - 1,
|
||||
leg.dist[gin][i_gout].data(), tab.mu[imu]);
|
||||
}
|
||||
|
||||
// Ensure positivity
|
||||
for (auto& val : tab.fmu[gin][i_gout]) {
|
||||
if (val < 0.) val = 0.;
|
||||
}
|
||||
|
||||
// Now re-normalize for numerical integration issues and to take care of
|
||||
// the above negative fix-up. Also accrue the CDF
|
||||
double norm = 0.;
|
||||
tab.dist[gin][i_gout][0] = 0.;
|
||||
for (int imu = 1; imu < n_mu; imu++) {
|
||||
norm += 0.5 * tab.dmu * (tab.fmu[gin][i_gout][imu - 1] +
|
||||
tab.fmu[gin][i_gout][imu]);
|
||||
// incorporate to the CDF
|
||||
tab.dist[gin][i_gout][imu] = norm;
|
||||
}
|
||||
|
||||
// now do the normalization
|
||||
if (norm > 0.) {
|
||||
for (int imu = 0; imu < n_mu; imu++) {
|
||||
tab.fmu[gin][i_gout][imu] /= norm;
|
||||
tab.dist[gin][i_gout][imu] /= norm;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
258
src/scattdata.h
Normal file
258
src/scattdata.h
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
//! \file scattdata.h
|
||||
//! A collection of multi-group scattering data classes
|
||||
|
||||
#ifndef SCATTDATA_H
|
||||
#define SCATTDATA_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace openmc {
|
||||
|
||||
// forward declarations so we can name our friend functions
|
||||
class ScattDataLegendre;
|
||||
class ScattDataTabular;
|
||||
|
||||
//==============================================================================
|
||||
// SCATTDATA contains all the data needed to describe the scattering energy and
|
||||
// angular distribution data
|
||||
//==============================================================================
|
||||
|
||||
class ScattData {
|
||||
protected:
|
||||
//! \brief Initializes the attributes of the base class.
|
||||
void
|
||||
base_init(int order, const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
||||
const double_2dvec& in_energy, const double_2dvec& in_mult);
|
||||
|
||||
//! \brief Combines microscopic ScattDatas into a macroscopic one.
|
||||
void
|
||||
base_combine(int max_order, const std::vector<ScattData*>& those_scatts,
|
||||
const double_1dvec& scalars, int_1dvec& in_gmin, int_1dvec& in_gmax,
|
||||
double_2dvec& sparse_mult, double_3dvec& sparse_scatter);
|
||||
|
||||
public:
|
||||
|
||||
double_2dvec energy; // Normalized p0 matrix for sampling Eout
|
||||
double_2dvec mult; // nu-scatter multiplication (nu-scatt/scatt)
|
||||
double_3dvec dist; // Angular distribution
|
||||
int_1dvec gmin; // minimum outgoing group
|
||||
int_1dvec gmax; // maximum outgoing group
|
||||
double_1dvec scattxs; // Isotropic Sigma_{s,g_{in}}
|
||||
|
||||
//! \brief Calculates the value of normalized f(mu).
|
||||
//!
|
||||
//! The value of f(mu) is normalized as in the integral of f(mu)dmu across
|
||||
//! [-1,1] is 1.
|
||||
//!
|
||||
//! @param gin Incoming energy group of interest.
|
||||
//! @param gout Outgoing energy group of interest.
|
||||
//! @param mu Cosine of the change-in-angle of interest.
|
||||
//! @return The value of f(mu).
|
||||
virtual double
|
||||
calc_f(int gin, int gout, double mu) = 0;
|
||||
|
||||
//! \brief Samples the outgoing energy and angle from the ScattData info.
|
||||
//!
|
||||
//! @param gin Incoming energy group.
|
||||
//! @param gout Sampled outgoing energy group.
|
||||
//! @param mu Sampled cosine of the change-in-angle.
|
||||
//! @param wgt Weight of the particle to be adjusted.
|
||||
virtual void
|
||||
sample(int gin, int& gout, double& mu, double& wgt) = 0;
|
||||
|
||||
//! \brief Initializes the ScattData object from a given scatter and
|
||||
//! multiplicity matrix.
|
||||
//!
|
||||
//! @param in_gmin List of minimum outgoing groups for every incoming group
|
||||
//! @param in_gmax List of maximum outgoing groups for every incoming group
|
||||
//! @param in_mult Input sparse multiplicity matrix
|
||||
//! @param coeffs Input sparse scattering matrix
|
||||
virtual void
|
||||
init(const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
||||
const double_2dvec& in_mult, const double_3dvec& coeffs) = 0;
|
||||
|
||||
//! \brief Combines the microscopic data.
|
||||
//!
|
||||
//! @param those_scatts Microscopic objects to combine.
|
||||
//! @param scalars Scalars to multiply the microscopic data by.
|
||||
virtual void
|
||||
combine(const std::vector<ScattData*>& those_scatts,
|
||||
const double_1dvec& scalars) = 0;
|
||||
|
||||
//! \brief Getter for the dimensionality of the scattering order.
|
||||
//!
|
||||
//! If Legendre this is the "n" in "Pn"; for Tabular, this is the number
|
||||
//! of points, and for Histogram this is the number of bins.
|
||||
//!
|
||||
//! @return The order.
|
||||
virtual int
|
||||
get_order() = 0;
|
||||
|
||||
//! \brief Builds a dense scattering matrix from the constituent parts
|
||||
//!
|
||||
//! @param max_order If Legendre this is the maximum value of "n" in "Pn"
|
||||
//! requested; ignored otherwise.
|
||||
//! @return The dense scattering matrix.
|
||||
virtual double_3dvec
|
||||
get_matrix(int max_order) = 0;
|
||||
|
||||
//! \brief Samples the outgoing energy from the ScattData info.
|
||||
//!
|
||||
//! @param gin Incoming energy group.
|
||||
//! @param gout Sampled outgoing energy group.
|
||||
//! @param i_gout Sampled outgoing energy group index.
|
||||
void
|
||||
sample_energy(int gin, int& gout, int& i_gout);
|
||||
|
||||
//! \brief Provides a cross section value given certain parameters
|
||||
//!
|
||||
//! @param xstype Type of cross section requested, according to the
|
||||
//! enumerated constants.
|
||||
//! @param gin Incoming energy group.
|
||||
//! @param gout Outgoing energy group; use nullptr if irrelevant, or if a
|
||||
//! sum is requested.
|
||||
//! @param mu Cosine of the change-in-angle, for scattering quantities;
|
||||
//! use nullptr if irrelevant.
|
||||
//! @return Requested cross section value.
|
||||
double
|
||||
get_xs(int xstype, int gin, const int* gout, const double* mu);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// ScattDataLegendre represents the angular distributions as Legendre kernels
|
||||
//==============================================================================
|
||||
|
||||
class ScattDataLegendre: public ScattData {
|
||||
|
||||
protected:
|
||||
|
||||
// Maximal value for rejection sampling from a rectangle
|
||||
double_2dvec max_val;
|
||||
|
||||
// Friend convert_legendre_to_tabular so it has access to protected
|
||||
// parameters
|
||||
friend void
|
||||
convert_legendre_to_tabular(ScattDataLegendre& leg,
|
||||
ScattDataTabular& tab, int n_mu);
|
||||
|
||||
public:
|
||||
|
||||
void
|
||||
init(const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
||||
const double_2dvec& in_mult, const double_3dvec& coeffs);
|
||||
|
||||
void
|
||||
combine(const std::vector<ScattData*>& those_scatts,
|
||||
const double_1dvec& scalars);
|
||||
|
||||
//! \brief Find the maximal value of the angular distribution to use as a
|
||||
// bounding box with rejection sampling.
|
||||
void
|
||||
update_max_val();
|
||||
|
||||
double
|
||||
calc_f(int gin, int gout, double mu);
|
||||
|
||||
void
|
||||
sample(int gin, int& gout, double& mu, double& wgt);
|
||||
|
||||
int
|
||||
get_order() {return dist[0][0].size() - 1;};
|
||||
|
||||
double_3dvec
|
||||
get_matrix(int max_order);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// ScattDataHistogram represents the angular distributions as a histogram, as it
|
||||
// would be if it came from a "mu" tally in OpenMC
|
||||
//==============================================================================
|
||||
|
||||
class ScattDataHistogram: public ScattData {
|
||||
|
||||
protected:
|
||||
|
||||
double_1dvec mu; // Angle distribution mu bin boundaries
|
||||
double dmu; // Quick storage of the spacing between the mu bin points
|
||||
double_3dvec fmu; // The angular distribution histogram
|
||||
|
||||
public:
|
||||
|
||||
void
|
||||
init(const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
||||
const double_2dvec& in_mult, const double_3dvec& coeffs);
|
||||
|
||||
void
|
||||
combine(const std::vector<ScattData*>& those_scatts,
|
||||
const double_1dvec& scalars);
|
||||
|
||||
double
|
||||
calc_f(int gin, int gout, double mu);
|
||||
|
||||
void
|
||||
sample(int gin, int& gout, double& mu, double& wgt);
|
||||
|
||||
int
|
||||
get_order() {return dist[0][0].size();};
|
||||
|
||||
double_3dvec
|
||||
get_matrix(int max_order);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// ScattDataTabular represents the angular distributions as a table of mu and
|
||||
// f(mu)
|
||||
//==============================================================================
|
||||
|
||||
class ScattDataTabular: public ScattData {
|
||||
|
||||
protected:
|
||||
|
||||
double_1dvec mu; // Angle distribution mu grid points
|
||||
double dmu; // Quick storage of the spacing between the mu points
|
||||
double_3dvec fmu; // The angular distribution function
|
||||
|
||||
// Friend convert_legendre_to_tabular so it has access to protected
|
||||
// parameters
|
||||
friend void
|
||||
convert_legendre_to_tabular(ScattDataLegendre& leg,
|
||||
ScattDataTabular& tab, int n_mu);
|
||||
|
||||
public:
|
||||
|
||||
void
|
||||
init(const int_1dvec& in_gmin, const int_1dvec& in_gmax,
|
||||
const double_2dvec& in_mult, const double_3dvec& coeffs);
|
||||
|
||||
void
|
||||
combine(const std::vector<ScattData*>& those_scatts,
|
||||
const double_1dvec& scalars);
|
||||
|
||||
double
|
||||
calc_f(int gin, int gout, double mu);
|
||||
|
||||
void
|
||||
sample(int gin, int& gout, double& mu, double& wgt);
|
||||
|
||||
int
|
||||
get_order() {return dist[0][0].size();};
|
||||
|
||||
double_3dvec get_matrix(int max_order);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// Function to convert Legendre functions to tabular
|
||||
//==============================================================================
|
||||
|
||||
//! \brief Converts a ScattDatalegendre to a ScattDataHistogram
|
||||
//!
|
||||
//! @param leg The initial ScattDataLegendre object.
|
||||
//! @param leg The resultant ScattDataTabular object.
|
||||
//! @param n_mu The number of mu points to use when building the
|
||||
//! ScattDataTabular object.
|
||||
void
|
||||
convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab,
|
||||
int n_mu);
|
||||
|
||||
} // namespace openmc
|
||||
#endif // SCATTDATA_H
|
||||
|
|
@ -1,852 +0,0 @@
|
|||
module scattdata_header
|
||||
|
||||
use algorithm, only: binary_search
|
||||
use constants
|
||||
use error, only: fatal_error
|
||||
use math
|
||||
use random_lcg, only: prn
|
||||
|
||||
implicit none
|
||||
|
||||
|
||||
!===============================================================================
|
||||
! JAGGED1D and JAGGED2D is a type which allows for jagged 1-D or 2-D array.
|
||||
!===============================================================================
|
||||
|
||||
type :: Jagged2D
|
||||
real(8), allocatable :: data(:, :)
|
||||
end type Jagged2D
|
||||
|
||||
type :: Jagged1D
|
||||
real(8), allocatable :: data(:)
|
||||
end type Jagged1D
|
||||
|
||||
!===============================================================================
|
||||
! SCATTDATA contains all the data to describe the scattering energy and
|
||||
! angular distribution
|
||||
!===============================================================================
|
||||
|
||||
type, abstract :: ScattData
|
||||
! The data attribute of the energy, mult, and dist arrays
|
||||
! are not necessarily 1-indexed as they instead will be allocated
|
||||
! from a minimum outgoing group to an outgoing minimum group.
|
||||
! Normalized p0 matrix on its own for sampling energy
|
||||
type(Jagged1D), allocatable :: energy(:) ! (Gin % data(Gout))
|
||||
! Nu-scatter multiplication (i.e. nu-scatt/scatt)
|
||||
type(Jagged1D), allocatable :: mult(:) ! (Gin % data(Gout))
|
||||
! Angular distribution
|
||||
type(Jagged2D), allocatable :: dist(:) ! (Gin % data(Order/Nmu, Gout)
|
||||
integer, allocatable :: gmin(:) ! Minimum outgoing group
|
||||
integer, allocatable :: gmax(:) ! Maximum outgoing group
|
||||
real(8), allocatable :: scattxs(:) ! Isotropic Sigma_{s,g_{in}}
|
||||
|
||||
contains
|
||||
procedure(scattdata_init_), deferred :: init ! Initializes ScattData
|
||||
procedure(scattdata_calc_f_), deferred :: calc_f ! Calculates f, given mu
|
||||
procedure(scattdata_sample_), deferred :: sample ! sample the scatter event
|
||||
procedure :: get_matrix => scattdata_get_matrix ! Rebuild scattering matrix
|
||||
end type ScattData
|
||||
|
||||
abstract interface
|
||||
subroutine scattdata_init_(this, gmin, gmax, mult, coeffs)
|
||||
import ScattData, Jagged1D, Jagged2D
|
||||
class(ScattData), intent(inout) :: this ! Object to work with
|
||||
integer, intent(in) :: gmin(:) ! Min Gout
|
||||
integer, intent(in) :: gmax(:) ! Max Gout
|
||||
type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix
|
||||
type(Jagged2D), intent(in) :: coeffs(:) ! Coefficients to use
|
||||
end subroutine scattdata_init_
|
||||
|
||||
pure function scattdata_calc_f_(this, gin, gout, mu) result(f)
|
||||
import ScattData
|
||||
class(ScattData), intent(in) :: this ! Scattering Object to work with
|
||||
integer, intent(in) :: gin ! Incoming Energy Group
|
||||
integer, intent(in) :: gout ! Outgoing Energy Group
|
||||
real(8), intent(in) :: mu ! Angle of interest
|
||||
real(8) :: f ! Return value of f(mu)
|
||||
|
||||
end function scattdata_calc_f_
|
||||
|
||||
subroutine scattdata_sample_(this, gin, gout, mu, wgt)
|
||||
import ScattData
|
||||
class(ScattData), intent(in) :: this ! Scattering Object to work with
|
||||
integer, intent(in) :: gin ! Incoming neutron group
|
||||
integer, intent(out) :: gout ! Sampled outgoin group
|
||||
real(8), intent(out) :: mu ! Sampled change in angle
|
||||
real(8), intent(inout) :: wgt ! Particle weight
|
||||
end subroutine scattdata_sample_
|
||||
end interface
|
||||
|
||||
type, extends(ScattData) :: ScattDataLegendre
|
||||
! Maximal value for rejection sampling from rectangle
|
||||
type(Jagged1D), allocatable :: max_val(:) ! (Gin % data(Gout))
|
||||
contains
|
||||
procedure :: init => scattdatalegendre_init
|
||||
procedure :: calc_f => scattdatalegendre_calc_f
|
||||
procedure :: sample => scattdatalegendre_sample
|
||||
end type ScattDataLegendre
|
||||
|
||||
type, extends(ScattData) :: ScattDataHistogram
|
||||
real(8), allocatable :: mu(:) ! Mu bins
|
||||
real(8) :: dmu ! Mu spacing
|
||||
! Histogram of f(mu) (dist has CDF)
|
||||
type(Jagged2D), allocatable :: fmu(:) ! (Gin % data(Order/Nmu x Gout)
|
||||
contains
|
||||
procedure :: init => scattdatahistogram_init
|
||||
procedure :: calc_f => scattdatahistogram_calc_f
|
||||
procedure :: sample => scattdatahistogram_sample
|
||||
procedure :: get_matrix => scattdatahistogram_get_matrix
|
||||
end type ScattDataHistogram
|
||||
|
||||
type, extends(ScattData) :: ScattDataTabular
|
||||
real(8), allocatable :: mu(:) ! Mu bins
|
||||
real(8) :: dmu ! Mu spacing
|
||||
! PDF of f(mu) (dist has CDF)
|
||||
type(Jagged2D), allocatable :: fmu(:) ! (Gin % data(Order/Nmu x Gout)
|
||||
contains
|
||||
procedure :: init => scattdatatabular_init
|
||||
procedure :: calc_f => scattdatatabular_calc_f
|
||||
procedure :: sample => scattdatatabular_sample
|
||||
procedure :: get_matrix => scattdatatabular_get_matrix
|
||||
end type ScattDataTabular
|
||||
|
||||
!===============================================================================
|
||||
! SCATTDATACONTAINER allocatable array for storing ScattData Objects (for angle)
|
||||
!===============================================================================
|
||||
|
||||
type ScattDataContainer
|
||||
class(ScattData), allocatable :: obj
|
||||
end type ScattDataContainer
|
||||
|
||||
contains
|
||||
|
||||
!===============================================================================
|
||||
! SCATTDATA*_INIT builds the scattdata object
|
||||
!===============================================================================
|
||||
|
||||
subroutine scattdata_init(this, order, gmin, gmax, energy, mult)
|
||||
class(ScattData), intent(inout) :: this ! Object to work on
|
||||
integer, intent(in) :: order ! Data Order
|
||||
integer, intent(in) :: gmin(:) ! Min Gout
|
||||
integer, intent(in) :: gmax(:) ! Max Gout
|
||||
type(Jagged1D), intent(inout) :: energy(:) ! Energy Transfer Matrix
|
||||
type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix
|
||||
|
||||
integer :: groups, gin
|
||||
real(8) :: norm
|
||||
|
||||
groups = size(energy, dim=1)
|
||||
|
||||
allocate(this % gmin(groups))
|
||||
allocate(this % gmax(groups))
|
||||
allocate(this % energy(groups))
|
||||
allocate(this % mult(groups))
|
||||
allocate(this % dist(groups))
|
||||
|
||||
this % gmin = gmin
|
||||
this % gmax = gmax
|
||||
|
||||
! Set the outgoing energy PDF values
|
||||
do gin = 1, groups
|
||||
! Make sure energy is normalized (i.e., CDF is 1)
|
||||
norm = sum(energy(gin) % data(:))
|
||||
if (norm /= ZERO) energy(gin) % data(:) = energy(gin) % data(:) / norm
|
||||
! Set the values
|
||||
allocate(this % energy(gin) % data(gmin(gin):gmax(gin)))
|
||||
this % energy(gin) % data(:) = energy(gin) % data(:)
|
||||
allocate(this % mult(gin) % data(gmin(gin):gmax(gin)))
|
||||
this % mult(gin) % data(gmin(gin):gmax(gin)) = &
|
||||
mult(gin) % data(gmin(gin):gmax(gin))
|
||||
allocate(this % dist(gin) % data(order, gmin(gin):gmax(gin)))
|
||||
this % dist(gin) % data = ZERO
|
||||
end do
|
||||
end subroutine scattdata_init
|
||||
|
||||
subroutine scattdatalegendre_init(this, gmin, gmax, mult, coeffs)
|
||||
class(ScattDataLegendre), intent(inout) :: this ! Object to work on
|
||||
integer, intent(in) :: gmin(:) ! Min Gout
|
||||
integer, intent(in) :: gmax(:) ! Max Gout
|
||||
type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix
|
||||
type(Jagged2D), intent(in) :: coeffs(:) ! Coefficients to use
|
||||
|
||||
real(8) :: dmu, mu, f, norm
|
||||
integer :: imu, Nmu, gout, gin, groups, order
|
||||
type(Jagged1D), allocatable :: energy(:)
|
||||
type(Jagged2D), allocatable :: matrix(:)
|
||||
|
||||
groups = size(coeffs)
|
||||
order = size(coeffs(1) % data, dim=1)
|
||||
|
||||
! make a copy of coeffs that we can use to extract data and normalize
|
||||
allocate(matrix(groups))
|
||||
do gin = 1, groups
|
||||
allocate(matrix(gin) % data(order, gmin(gin):gmax(gin)))
|
||||
matrix(gin) % data = coeffs(gin) % data
|
||||
end do
|
||||
|
||||
! Get scattxs value
|
||||
allocate(this % scattxs(groups))
|
||||
! Get this by summing the un-normalized P0 coefficient in matrix
|
||||
! over all outgoing groups
|
||||
do gin = 1, groups
|
||||
this % scattxs(gin) = sum(matrix(gin) % data(1, :), dim=1)
|
||||
end do
|
||||
|
||||
allocate(energy(groups))
|
||||
! Build energy transfer probability matrix from data in matrix
|
||||
! while also normalizing matrix itself (making CDF of f(mu=1)=1)
|
||||
do gin = 1, groups
|
||||
allocate(energy(gin) % data(gmin(gin):gmax(gin)))
|
||||
energy(gin) % data = ZERO
|
||||
do gout = gmin(gin), gmax(gin)
|
||||
norm = matrix(gin) % data(1, gout)
|
||||
energy(gin) % data(gout) = norm
|
||||
if (norm /= ZERO) then
|
||||
matrix(gin) % data(:, gout) = matrix(gin) % data(:, gout) / norm
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
|
||||
call scattdata_init(this, order, gmin, gmax, energy, mult)
|
||||
|
||||
allocate(this % max_val(groups))
|
||||
! Set dist values from matrix and initialize max_val
|
||||
do gin = 1, groups
|
||||
do gout = gmin(gin), gmax(gin)
|
||||
this % dist(gin) % data(:, gout) = matrix(gin) % data(:, gout)
|
||||
end do
|
||||
allocate(this % max_val(gin) % data(gmin(gin):gmax(gin)))
|
||||
this % max_val(gin) % data(:) = ZERO
|
||||
end do
|
||||
|
||||
! Step through the polynomial with fixed number of points to identify
|
||||
! the maximal value.
|
||||
Nmu = 1001
|
||||
dmu = TWO / real(Nmu - 1, 8)
|
||||
do gin = 1, groups
|
||||
do gout = gmin(gin), gmax(gin)
|
||||
do imu = 1, Nmu
|
||||
! Update mu. Do first and last seperate to avoid float errors
|
||||
if (imu == 1) then
|
||||
mu = -ONE
|
||||
else if (imu == Nmu) then
|
||||
mu = ONE
|
||||
else
|
||||
mu = -ONE + real(imu - 1, 8) * dmu
|
||||
end if
|
||||
! Calculate probability
|
||||
f = this % calc_f(gin,gout,mu)
|
||||
! If this is a new max, store it.
|
||||
if (f > this % max_val(gin) % data(gout)) &
|
||||
this % max_val(gin) % data(gout) = f
|
||||
end do
|
||||
! Finally, since we may not have caught the exact max, add 10% margin
|
||||
this % max_val(gin) % data(gout) = &
|
||||
this % max_val(gin) % data(gout) * 1.1_8
|
||||
end do
|
||||
end do
|
||||
end subroutine scattdatalegendre_init
|
||||
|
||||
subroutine scattdatahistogram_init(this, gmin, gmax, mult, coeffs)
|
||||
class(ScattDataHistogram), intent(inout) :: this ! Object to work on
|
||||
integer, intent(in) :: gmin(:) ! Min Gout
|
||||
integer, intent(in) :: gmax(:) ! Max Gout
|
||||
type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix
|
||||
type(Jagged2D), intent(in) :: coeffs(:) ! Coefficients to use
|
||||
|
||||
integer :: imu, gin, gout, groups, order
|
||||
real(8) :: norm
|
||||
type(Jagged1D), allocatable :: energy(:)
|
||||
type(Jagged2D), allocatable :: matrix(:)
|
||||
|
||||
groups = size(coeffs)
|
||||
order = size(coeffs(1) % data, dim=1)
|
||||
|
||||
! make a copy of coeffs that we can use to extract data and normalize
|
||||
allocate(matrix(groups))
|
||||
do gin = 1, groups
|
||||
allocate(matrix(gin) % data(order, gmin(gin):gmax(gin)))
|
||||
matrix(gin) % data(:, :) = coeffs(gin) % data(:, :)
|
||||
end do
|
||||
|
||||
! Get scattxs value
|
||||
allocate(this % scattxs(groups))
|
||||
! Get this by summing the un-normalized angular distribution in matrix
|
||||
! over all outgoing groups
|
||||
do gin = 1, groups
|
||||
this % scattxs(gin) = sum(matrix(gin) % data(:, :))
|
||||
end do
|
||||
|
||||
allocate(energy(groups))
|
||||
! Build energy transfer probability matrix from data in matrix
|
||||
! while also normalizing matrix itself (making CDF of f(mu=1)=1)
|
||||
do gin = 1, groups
|
||||
allocate(energy(gin) % data(gmin(gin):gmax(gin)))
|
||||
do gout = gmin(gin), gmax(gin)
|
||||
norm = sum(matrix(gin) % data(:, gout))
|
||||
energy(gin) % data(gout) = norm
|
||||
if (norm /= ZERO) then
|
||||
matrix(gin) % data(:, gout) = matrix(gin) % data(:, gout) / norm
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
|
||||
call scattdata_init(this, order, gmin, gmax, energy, mult)
|
||||
|
||||
allocate(this % mu(order))
|
||||
this % dmu = TWO / real(order, 8)
|
||||
this % mu(1) = -ONE
|
||||
do imu = 2, order
|
||||
this % mu(imu) = -ONE + real(imu - 1, 8) * this % dmu
|
||||
end do
|
||||
|
||||
! Integrate this histogram so we can avoid rejection sampling while
|
||||
! also saving the original histogram in fmu
|
||||
allocate(this % fmu(groups))
|
||||
do gin = 1, groups
|
||||
allocate(this % fmu(gin) % data(order, gmin(gin):gmax(gin)))
|
||||
do gout = gmin(gin), gmax(gin)
|
||||
! Store the histogram
|
||||
this % fmu(gin) % data(:, gout) = matrix(gin) % data(:, gout)
|
||||
! Integrate the histogram
|
||||
this % dist(gin) % data(1, gout) = &
|
||||
this % dmu * matrix(gin) % data(1, gout)
|
||||
do imu = 2, order
|
||||
this % dist(gin) % data(imu, gout) = &
|
||||
this % dmu * matrix(gin) % data(imu, gout) + &
|
||||
this % dist(gin) % data(imu - 1, gout)
|
||||
end do
|
||||
|
||||
! Normalize the integral to unity
|
||||
norm = this % dist(gin) % data(order, gout)
|
||||
if (norm > ZERO) then
|
||||
this % fmu(gin) % data(:, gout) = &
|
||||
this % fmu(gin) % data(:, gout) / norm
|
||||
this % dist(gin) % data(:, gout) = &
|
||||
this % dist(gin) % data(:, gout) / norm
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
|
||||
end subroutine scattdatahistogram_init
|
||||
|
||||
subroutine scattdatatabular_init(this, gmin, gmax, mult, coeffs)
|
||||
class(ScattDataTabular), intent(inout) :: this ! Object to work on
|
||||
integer, intent(in) :: gmin(:) ! Min Gout
|
||||
integer, intent(in) :: gmax(:) ! Max Gout
|
||||
type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix
|
||||
type(Jagged2D), intent(in) :: coeffs(:) ! Coefficients to use
|
||||
|
||||
integer :: imu, gin, gout, groups, order
|
||||
real(8) :: norm
|
||||
type(Jagged1D), allocatable :: energy(:)
|
||||
type(Jagged2D), allocatable :: matrix(:)
|
||||
|
||||
groups = size(coeffs)
|
||||
order = size(coeffs(1) % data, dim=1)
|
||||
|
||||
! make a copy of coeffs that we can use to extract data and normalize
|
||||
allocate(matrix(groups))
|
||||
do gin = 1, groups
|
||||
allocate(matrix(gin) % data(order, gmin(gin):gmax(gin)))
|
||||
matrix(gin) % data = coeffs(gin) % data
|
||||
end do
|
||||
|
||||
! Build the angular distribution mu values
|
||||
allocate(this % mu(order))
|
||||
this % dmu = TWO / real(order - 1, 8)
|
||||
this % mu(1) = -ONE
|
||||
do imu = 2, order - 1
|
||||
this % mu(imu) = -ONE + real(imu - 1, 8) * this % dmu
|
||||
end do
|
||||
this % mu(order) = ONE
|
||||
|
||||
! Get scattxs
|
||||
allocate(this % scattxs(groups))
|
||||
! Get this by integrating the scattering distribution over all mu points
|
||||
! and then combining over all outgoing groups
|
||||
! over all outgoing groups
|
||||
do gin = 1, groups
|
||||
norm = ZERO
|
||||
do gout = gmin(gin), gmax(gin)
|
||||
do imu = 2, order
|
||||
norm = norm + HALF * this % dmu * &
|
||||
(matrix(gin) % data(imu - 1, gout) + &
|
||||
matrix(gin) % data(imu, gout))
|
||||
end do
|
||||
end do
|
||||
this % scattxs(gin) = norm
|
||||
end do
|
||||
|
||||
allocate(energy(groups))
|
||||
! Build energy transfer probability matrix from data in matrix
|
||||
do gin = 1, groups
|
||||
allocate(energy(gin) % data(gmin(gin):gmax(gin)))
|
||||
do gout = gmin(gin), gmax(gin)
|
||||
norm = ZERO
|
||||
do imu = 2, order
|
||||
norm = norm + HALF * this % dmu * &
|
||||
(matrix(gin) % data(imu - 1, gout) + &
|
||||
matrix(gin) % data(imu, gout))
|
||||
end do
|
||||
energy(gin) % data(gout) = norm
|
||||
end do
|
||||
end do
|
||||
call scattdata_init(this, order, gmin, gmax, energy, mult)
|
||||
|
||||
! Calculate f(mu) and integrate it so we can avoid rejection sampling
|
||||
allocate(this % fmu(groups))
|
||||
do gin = 1, groups
|
||||
allocate(this % fmu(gin) % data(order, gmin(gin):gmax(gin)))
|
||||
do gout = gmin(gin), gmax(gin)
|
||||
! Coeffs contain f(mu), put in f(mu) as that is where the
|
||||
! PDF lives
|
||||
this % fmu(gin) % data(:, gout) = matrix(gin) % data(:, gout)
|
||||
|
||||
! Force positivity
|
||||
do imu = 1, order
|
||||
if (this % fmu(gin) % data(imu, gout) < ZERO) then
|
||||
this % fmu(gin) % data(imu, gout) = ZERO
|
||||
end if
|
||||
end do
|
||||
|
||||
! Re-normalize fmu for numerical integration issues and in case
|
||||
! the negative fix-up introduced un-normalized data while
|
||||
! accruing the CDF
|
||||
norm = ZERO
|
||||
do imu = 2, order
|
||||
norm = norm + HALF * this % dmu * &
|
||||
(this % fmu(gin) % data(imu - 1, gout) + &
|
||||
this % fmu(gin) % data(imu, gout))
|
||||
this % dist(gin) % data(imu, gout) = norm
|
||||
end do
|
||||
if (norm > ZERO) then
|
||||
this % fmu(gin) % data(:, gout) = &
|
||||
this % fmu(gin) % data(:, gout) / norm
|
||||
this % dist(gin) % data(:, gout) = &
|
||||
this % dist(gin) % data(:, gout) / norm
|
||||
end if
|
||||
end do
|
||||
end do
|
||||
end subroutine scattdatatabular_init
|
||||
|
||||
!===============================================================================
|
||||
! SCATTDATA_*_CALC_F Calculates the value of f given mu (and gin,gout pair)
|
||||
!===============================================================================
|
||||
|
||||
pure function scattdatalegendre_calc_f(this, gin, gout, mu) result(f)
|
||||
class(ScattDataLegendre), intent(in) :: this ! The ScattData to evaluate
|
||||
integer, intent(in) :: gin ! Incoming Energy Group
|
||||
integer, intent(in) :: gout ! Outgoing Energy Group
|
||||
real(8), intent(in) :: mu ! Angle of interest
|
||||
real(8) :: f ! Return value of f(mu)
|
||||
|
||||
! Plug mu in to the legendre expansion and go from there
|
||||
if (gout < this % gmin(gin) .or. gout > this % gmax(gin)) then
|
||||
f = ZERO
|
||||
else
|
||||
f = evaluate_legendre(this % dist(gin) % data(:, gout), mu)
|
||||
end if
|
||||
|
||||
end function scattdatalegendre_calc_f
|
||||
|
||||
pure function scattdatahistogram_calc_f(this, gin, gout, mu) result(f)
|
||||
class(ScattDataHistogram), intent(in) :: this ! The ScattData to evaluate
|
||||
integer, intent(in) :: gin ! Incoming Energy Group
|
||||
integer, intent(in) :: gout ! Outgoing Energy Group
|
||||
real(8), intent(in) :: mu ! Angle of interest
|
||||
real(8) :: f ! Return value of f(mu)
|
||||
|
||||
integer :: imu
|
||||
|
||||
if (gout < this % gmin(gin) .or. gout > this % gmax(gin)) then
|
||||
f = ZERO
|
||||
else
|
||||
! Find mu bin
|
||||
if (mu == ONE) then
|
||||
imu = size(this % fmu(gin) % data, dim=1)
|
||||
else
|
||||
imu = floor((mu + ONE) / this % dmu + ONE)
|
||||
end if
|
||||
|
||||
f = this % fmu(gin) % data(imu, gout)
|
||||
end if
|
||||
|
||||
end function scattdatahistogram_calc_f
|
||||
|
||||
pure function scattdatatabular_calc_f(this, gin, gout, mu) result(f)
|
||||
class(ScattDataTabular), intent(in) :: this ! The ScattData to evaluate
|
||||
integer, intent(in) :: gin ! Incoming Energy Group
|
||||
integer, intent(in) :: gout ! Outgoing Energy Group
|
||||
real(8), intent(in) :: mu ! Angle of interest
|
||||
real(8) :: f ! Return value of f(mu)
|
||||
|
||||
integer :: imu
|
||||
real(8) :: r
|
||||
|
||||
if (gout < this % gmin(gin) .or. gout > this % gmax(gin)) then
|
||||
f = ZERO
|
||||
else
|
||||
! Find mu bin
|
||||
if (mu == ONE) then
|
||||
imu = size(this % fmu(gin) % data, dim=1) - 1
|
||||
else
|
||||
imu = floor((mu + ONE) / this % dmu + ONE)
|
||||
end if
|
||||
|
||||
! Now interpolate to find f(mu)
|
||||
r = (mu - this % mu(imu)) / (this % mu(imu + 1) - this % mu(imu))
|
||||
f = (ONE - r) * this % fmu(gin) % data(imu, gout) + &
|
||||
r * this % fmu(gin) % data(imu + 1, gout)
|
||||
end if
|
||||
|
||||
end function scattdatatabular_calc_f
|
||||
|
||||
!===============================================================================
|
||||
! SCATTDATA*_SCATTER Samples the outgoing energy and change in angle.
|
||||
!===============================================================================
|
||||
|
||||
subroutine scattdatalegendre_sample(this, gin, gout, mu, wgt)
|
||||
class(ScattDataLegendre), intent(in) :: this ! Scattering object to use
|
||||
integer, intent(in) :: gin ! Incoming neutron group
|
||||
integer, intent(out) :: gout ! Sampled outgoin group
|
||||
real(8), intent(out) :: mu ! Sampled change in angle
|
||||
real(8), intent(inout) :: wgt ! Particle weight
|
||||
|
||||
real(8) :: xi ! Our random number
|
||||
real(8) :: prob ! Running probability
|
||||
real(8) :: u, f, M
|
||||
integer :: samples
|
||||
|
||||
xi = prn()
|
||||
gout = this % gmin(gin)
|
||||
prob = this % energy(gin) % data(gout)
|
||||
|
||||
do while ((prob < xi) .and. (gout < this % gmax(gin)))
|
||||
gout = gout + 1
|
||||
prob = prob + this % energy(gin) % data(gout)
|
||||
end do
|
||||
|
||||
! Now we can sample mu using the legendre representation of the scattering
|
||||
! kernel in data(1:this % order)
|
||||
|
||||
! Do with rejection sampling from a rectangular bounding box
|
||||
! Set maximal value
|
||||
M = this % max_val(gin) % data(gout)
|
||||
samples = 0
|
||||
do
|
||||
mu = TWO * prn() - ONE
|
||||
f = this % calc_f(gin, gout, mu)
|
||||
if (f > ZERO) then
|
||||
u = prn() * M
|
||||
if (u <= f) then
|
||||
exit
|
||||
end if
|
||||
end if
|
||||
samples = samples + 1
|
||||
if (samples > MAX_SAMPLE) then
|
||||
call fatal_error("Maximum number of Legendre expansion samples reached!")
|
||||
end if
|
||||
end do
|
||||
|
||||
wgt = wgt * this % mult(gin) % data(gout)
|
||||
|
||||
end subroutine scattdatalegendre_sample
|
||||
|
||||
subroutine scattdatahistogram_sample(this, gin, gout, mu, wgt)
|
||||
class(ScattDataHistogram), intent(in) :: this ! Scattering object to use
|
||||
integer, intent(in) :: gin ! Incoming neutron group
|
||||
integer, intent(out) :: gout ! Sampled outgoin group
|
||||
real(8), intent(out) :: mu ! Sampled change in angle
|
||||
real(8), intent(inout) :: wgt ! Particle weight
|
||||
|
||||
real(8) :: xi ! Our random number
|
||||
real(8) :: prob ! Running probability
|
||||
integer :: imu
|
||||
|
||||
xi = prn()
|
||||
gout = this % gmin(gin)
|
||||
prob = this % energy(gin) % data(gout)
|
||||
|
||||
do while ((prob < xi) .and. (gout < this % gmax(gin)))
|
||||
gout = gout + 1
|
||||
prob = prob + this % energy(gin) % data(gout)
|
||||
end do
|
||||
|
||||
xi = prn()
|
||||
if (xi < this % dist(gin) % data(1, gout)) then
|
||||
imu = 1
|
||||
else
|
||||
imu = binary_search(this % dist(gin) % data(:, gout), &
|
||||
size(this % dist(gin) % data(:, gout)), xi) + 1
|
||||
end if
|
||||
|
||||
! Randomly select a mu in this bin.
|
||||
mu = prn() * this % dmu + this % mu(imu)
|
||||
|
||||
wgt = wgt * this % mult(gin) % data(gout)
|
||||
|
||||
end subroutine scattdatahistogram_sample
|
||||
|
||||
subroutine scattdatatabular_sample(this, gin, gout, mu, wgt)
|
||||
class(ScattDataTabular), intent(in) :: this ! Scattering object to use
|
||||
integer, intent(in) :: gin ! Incoming neutron group
|
||||
integer, intent(out) :: gout ! Sampled outgoin group
|
||||
real(8), intent(out) :: mu ! Sampled change in angle
|
||||
real(8), intent(inout) :: wgt ! Particle weight
|
||||
|
||||
real(8) :: xi ! Our random number
|
||||
real(8) :: prob ! Running probability
|
||||
real(8) :: mu0, frac, mu1
|
||||
real(8) :: c_k, c_k1, p0, p1
|
||||
integer :: k, NP
|
||||
|
||||
xi = prn()
|
||||
gout = this % gmin(gin)
|
||||
prob = this % energy(gin) % data(gout)
|
||||
|
||||
do while ((prob < xi) .and. (gout < this % gmax(gin)))
|
||||
gout = gout + 1
|
||||
prob = prob + this % energy(gin) % data(gout)
|
||||
end do
|
||||
|
||||
! determine outgoing cosine bin
|
||||
NP = size(this % dist(gin) % data(:, gout))
|
||||
xi = prn()
|
||||
|
||||
c_k = this % dist(gin) % data(1, gout)
|
||||
do k = 1, NP - 1
|
||||
c_k1 = this % dist(gin) % data(k + 1, gout)
|
||||
if (xi < c_k1) exit
|
||||
c_k = c_k1
|
||||
end do
|
||||
|
||||
! check to make sure k is <= NP - 1
|
||||
k = min(k, NP - 1)
|
||||
|
||||
p0 = this % fmu(gin) % data(k, gout)
|
||||
mu0 = this % mu(k)
|
||||
! Linear-linear interpolation to find mu value w/in bin.
|
||||
p1 = this % fmu(gin) % data(k + 1, gout)
|
||||
mu1 = this % mu(k + 1)
|
||||
|
||||
if (p0 == p1) then
|
||||
mu = mu0 + (xi - c_k) / p0
|
||||
else
|
||||
frac = (p1 - p0) / (mu1 - mu0)
|
||||
mu = mu0 + &
|
||||
(sqrt(max(ZERO, p0 * p0 + TWO * frac * (xi - c_k))) - p0) / frac
|
||||
end if
|
||||
|
||||
if (mu <= -ONE) then
|
||||
mu = -ONE
|
||||
else if (mu >= ONE) then
|
||||
mu = ONE
|
||||
end if
|
||||
|
||||
wgt = wgt * this % mult(gin) % data(gout)
|
||||
|
||||
end subroutine scattdatatabular_sample
|
||||
|
||||
!===============================================================================
|
||||
! SCATTDATA*_GET_MATRIX Reproduces the original scattering matrix (densely)
|
||||
! using ScattData's information of fmu/dist, energy, and scattxs
|
||||
!===============================================================================
|
||||
|
||||
subroutine scattdata_get_matrix(this, req_order, matrix)
|
||||
class(ScattData), intent(in) :: this ! Scattering Object to work with
|
||||
integer, intent(in) :: req_order ! Requested order of matrix
|
||||
type(Jagged2D), allocatable, intent(inout) :: matrix(:) ! Resultant matrix just built
|
||||
|
||||
integer :: order, groups, gin, gout
|
||||
|
||||
groups = size(this % energy)
|
||||
! Set gin and gout for getting the order
|
||||
order = min(req_order, size(this % dist(1) % data, dim=1))
|
||||
|
||||
if (allocated(matrix)) deallocate(matrix)
|
||||
allocate(matrix(groups))
|
||||
! Initialize to 0; this way the zero entries in the dense matrix dont
|
||||
! need to be explicitly set, requiring a significant increase in the
|
||||
! lines of code.
|
||||
do gin = 1, groups
|
||||
allocate(matrix(gin) % data(order, groups))
|
||||
do gout = this % gmin(gin), this % gmax(gin)
|
||||
matrix(gin) % data(:, gout) = this % scattxs(gin) * &
|
||||
this % energy(gin) % data(gout) * &
|
||||
this % dist(gin) % data(1:order, gout)
|
||||
end do
|
||||
end do
|
||||
end subroutine scattdata_get_matrix
|
||||
|
||||
subroutine scattdatahistogram_get_matrix(this, req_order, matrix)
|
||||
class(ScattDataHistogram), intent(in) :: this ! Scattering Object to work with
|
||||
integer, intent(in) :: req_order ! Requested order of matrix
|
||||
type(Jagged2D), allocatable, intent(inout) :: matrix(:) ! Resultant matrix just built
|
||||
|
||||
integer :: order, groups, gin, gout
|
||||
|
||||
groups = size(this % energy)
|
||||
order = min(req_order, size(this % dist(1) % data, dim=1))
|
||||
|
||||
if (allocated(matrix)) deallocate(matrix)
|
||||
allocate(matrix(groups))
|
||||
! Initialize to 0; this way the zero entries in the dense matrix dont
|
||||
! need to be explicitly set, requiring a significant increase in the
|
||||
! lines of code.
|
||||
do gin = 1, groups
|
||||
allocate(matrix(gin) % data(order, groups))
|
||||
do gout = this % gmin(gin), this % gmax(gin)
|
||||
matrix(gin) % data(:, gout) = this % scattxs(gin) * &
|
||||
this % energy(gin) % data(gout) * &
|
||||
this % fmu(gin) % data(1:order, gout)
|
||||
end do
|
||||
end do
|
||||
end subroutine scattdatahistogram_get_matrix
|
||||
|
||||
subroutine scattdatatabular_get_matrix(this, req_order, matrix)
|
||||
class(ScattDataTabular), intent(in) :: this ! Scattering Object to work with
|
||||
integer, intent(in) :: req_order ! Requested order of matrix
|
||||
type(Jagged2D), allocatable, intent(inout) :: matrix(:) ! Resultant matrix just built
|
||||
|
||||
integer :: order, groups, gin, gout
|
||||
|
||||
groups = size(this % energy)
|
||||
order = min(req_order, size(this % dist(1) % data, dim=1))
|
||||
|
||||
if (allocated(matrix)) deallocate(matrix)
|
||||
allocate(matrix(groups))
|
||||
! Initialize to 0; this way the zero entries in the dense matrix dont
|
||||
! need to be explicitly set, requiring a significant increase in the
|
||||
! lines of code.
|
||||
do gin = 1, groups
|
||||
allocate(matrix(gin) % data(order, groups))
|
||||
do gout = this % gmin(gin), this % gmax(gin)
|
||||
matrix(gin) % data(:, gout) = this % scattxs(gin) * &
|
||||
this % energy(gin) % data(gout) * &
|
||||
this % fmu(gin) % data(1:order, gout)
|
||||
end do
|
||||
end do
|
||||
end subroutine scattdatatabular_get_matrix
|
||||
|
||||
!===============================================================================
|
||||
! JAGGED_FROM_DENSE_*D Creates a jagged array from a sparse dense matrix.
|
||||
! The user can supply a key which indicates the values to remove, but the
|
||||
! default is ZERO
|
||||
!===============================================================================
|
||||
|
||||
subroutine jagged_from_dense_1D(dense, jagged, lo_bounds_, hi_bounds_, key_)
|
||||
real(8), intent(in) :: dense(:, :)
|
||||
type(Jagged1D), allocatable, intent(inout) :: jagged(:)
|
||||
real(8), intent(in), optional :: key_
|
||||
integer, intent(inout), allocatable, optional :: lo_bounds_(:)
|
||||
integer, intent(inout), allocatable, optional :: hi_bounds_(:)
|
||||
|
||||
real(8) :: key
|
||||
integer :: i, jmin, jmax
|
||||
integer, allocatable :: lo_bounds(:), hi_bounds(:)
|
||||
|
||||
if (present(key_)) then
|
||||
key = key_
|
||||
else
|
||||
key = ZERO
|
||||
end if
|
||||
|
||||
allocate(lo_bounds(size(dense, dim=2)))
|
||||
allocate(hi_bounds(size(dense, dim=2)))
|
||||
|
||||
if (allocated(jagged)) deallocate(jagged)
|
||||
allocate(jagged(size(dense, dim=2)))
|
||||
do i = 1, size(dense, dim=2)
|
||||
! Find the min and max j values
|
||||
do jmin = 1, size(dense, dim=1)
|
||||
if (dense(jmin, i) /= key) exit
|
||||
end do
|
||||
do jmax = size(dense, dim=1), 1, -1
|
||||
if (dense(jmax, i) /= key) exit
|
||||
end do
|
||||
! Treat the case of all values matching the key
|
||||
if (jmin > jmax) then
|
||||
jmin = i
|
||||
jmax = i
|
||||
end if
|
||||
|
||||
! Now store the jagged row
|
||||
allocate(jagged(i) % data(jmin:jmax))
|
||||
jagged(i) % data(jmin:jmax) = dense(jmin:jmax, i)
|
||||
|
||||
lo_bounds(i) = jmin
|
||||
hi_bounds(i) = jmax
|
||||
end do
|
||||
|
||||
if (present(lo_bounds_)) then
|
||||
if (allocated(lo_bounds_)) deallocate(lo_bounds_)
|
||||
allocate(lo_bounds_(size(dense, dim=2)))
|
||||
lo_bounds_ = lo_bounds
|
||||
end if
|
||||
if (present(hi_bounds_)) then
|
||||
if (allocated(hi_bounds_)) deallocate(hi_bounds_)
|
||||
allocate(hi_bounds_(size(dense, dim=2)))
|
||||
hi_bounds_ = hi_bounds
|
||||
end if
|
||||
|
||||
end subroutine jagged_from_dense_1D
|
||||
|
||||
subroutine jagged_from_dense_2D(dense, jagged, lo_bounds_, hi_bounds_, key_)
|
||||
real(8), intent(in) :: dense(:, :, :)
|
||||
type(Jagged2D), allocatable, intent(inout) :: jagged(:)
|
||||
real(8), intent(in), optional :: key_
|
||||
integer, intent(inout), allocatable, optional :: lo_bounds_(:)
|
||||
integer, intent(inout), allocatable, optional :: hi_bounds_(:)
|
||||
|
||||
real(8) :: key
|
||||
integer :: i, jmin, jmax
|
||||
integer, allocatable :: lo_bounds(:), hi_bounds(:)
|
||||
|
||||
if (present(key_)) then
|
||||
key = key_
|
||||
else
|
||||
key = ZERO
|
||||
end if
|
||||
|
||||
allocate(lo_bounds(size(dense, dim=3)))
|
||||
allocate(hi_bounds(size(dense, dim=3)))
|
||||
|
||||
if (allocated(jagged)) deallocate(jagged)
|
||||
allocate(jagged(size(dense, dim=3)))
|
||||
do i = 1, size(dense, dim=3)
|
||||
! Find the min and max j values
|
||||
do jmin = 1, size(dense, dim=2)
|
||||
if (any(dense(:, jmin, i) /= key)) exit
|
||||
end do
|
||||
do jmax = size(dense, dim=2), 1, -1
|
||||
if (any(dense(:, jmax, i) /= key)) exit
|
||||
end do
|
||||
! Treat the case of all values matching the key
|
||||
if (jmin > jmax) then
|
||||
jmin = i
|
||||
jmax = i
|
||||
end if
|
||||
|
||||
! Now store the jagged row
|
||||
allocate(jagged(i) % data(size(dense, dim=1), jmin:jmax))
|
||||
jagged(i) % data(:, jmin:jmax) = dense(:, jmin:jmax, i)
|
||||
|
||||
lo_bounds(i) = jmin
|
||||
hi_bounds(i) = jmax
|
||||
end do
|
||||
|
||||
if (present(lo_bounds_)) then
|
||||
if (allocated(lo_bounds_)) deallocate(lo_bounds_)
|
||||
allocate(lo_bounds_(size(dense, dim=3)))
|
||||
lo_bounds_ = lo_bounds
|
||||
end if
|
||||
if (present(hi_bounds_)) then
|
||||
if (allocated(hi_bounds_)) deallocate(hi_bounds_)
|
||||
allocate(hi_bounds_(size(dense, dim=3)))
|
||||
hi_bounds_ = hi_bounds
|
||||
end if
|
||||
|
||||
end subroutine jagged_from_dense_2D
|
||||
|
||||
end module scattdata_header
|
||||
|
|
@ -18,9 +18,9 @@ module settings
|
|||
logical :: urr_ptables_on = .true.
|
||||
|
||||
! Default temperature and method for choosing temperatures
|
||||
integer :: temperature_method = TEMPERATURE_NEAREST
|
||||
integer(C_INT) :: temperature_method = TEMPERATURE_NEAREST
|
||||
logical :: temperature_multipole = .false.
|
||||
real(8) :: temperature_tolerance = 10.0_8
|
||||
real(C_DOUBLE) :: temperature_tolerance = 10.0_8
|
||||
real(8) :: temperature_default = 293.6_8
|
||||
real(8) :: temperature_range(2) = [ZERO, ZERO]
|
||||
|
||||
|
|
@ -30,13 +30,16 @@ module settings
|
|||
! MULTI-GROUP CROSS SECTION RELATED VARIABLES
|
||||
|
||||
! Maximum Data Order
|
||||
integer :: max_order
|
||||
integer(C_INT) :: 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
|
||||
integer(C_INT) :: legendre_to_tabular_points = C_NONE
|
||||
|
||||
! ============================================================================
|
||||
! SIMULATION VARIABLES
|
||||
|
||||
! Assume all tallies are spatially distinct
|
||||
logical :: assume_separate = .false.
|
||||
|
|
@ -44,9 +47,6 @@ module settings
|
|||
! 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
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ module simulation
|
|||
use geometry_header, only: n_cells
|
||||
use material_header, only: n_materials, materials
|
||||
use message_passing
|
||||
use mgxs_header, only: energy_bins, energy_bin_avg
|
||||
use mgxs_interface, only: energy_bins, energy_bin_avg
|
||||
use nuclide_header, only: micro_xs, n_nuclides
|
||||
use output, only: header, print_columns, &
|
||||
print_batch_keff, print_generation, print_runtime, &
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ module source
|
|||
use hdf5_interface
|
||||
use math
|
||||
use message_passing, only: rank
|
||||
use mgxs_header, only: rev_energy_bins, num_energy_groups
|
||||
use mgxs_interface, only: rev_energy_bins, num_energy_groups
|
||||
use output, only: write_message
|
||||
use particle_header, only: Particle
|
||||
use random_lcg, only: prn, set_particle_seed, prn_set_stream
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ module state_point
|
|||
use hdf5_interface
|
||||
use mesh_header, only: RegularMesh, meshes, n_meshes
|
||||
use message_passing
|
||||
use mgxs_header, only: nuclides_MG
|
||||
use mgxs_interface
|
||||
use nuclide_header, only: nuclides
|
||||
use output, only: time_stamp
|
||||
use random_lcg, only: openmc_get_seed, openmc_set_seed
|
||||
|
|
@ -73,6 +73,7 @@ contains
|
|||
character(MAX_WORD_LEN), allocatable :: str_array(:)
|
||||
character(C_CHAR), pointer :: string(:)
|
||||
character(len=:, kind=C_CHAR), allocatable :: filename_
|
||||
character(MAX_WORD_LEN, kind=C_CHAR) :: temp_name
|
||||
|
||||
err = 0
|
||||
if (present(filename)) then
|
||||
|
|
@ -307,11 +308,13 @@ contains
|
|||
str_array(j) = nuclides(tally % nuclide_bins(j)) % name
|
||||
end if
|
||||
else
|
||||
i_xs = index(nuclides_MG(tally % nuclide_bins(j)) % obj % name, '.')
|
||||
call get_name_c(tally % nuclide_bins(j), len(temp_name), &
|
||||
temp_name)
|
||||
i_xs = index(temp_name, '.')
|
||||
if (i_xs > 0) then
|
||||
str_array(j) = nuclides_MG(tally % nuclide_bins(j)) % obj % name(1 : i_xs-1)
|
||||
str_array(j) = trim(temp_name(1 : i_xs-1))
|
||||
else
|
||||
str_array(j) = nuclides_MG(tally % nuclide_bins(j)) % obj % name
|
||||
str_array(j) = trim(temp_name)
|
||||
end if
|
||||
end if
|
||||
else
|
||||
|
|
|
|||
30
src/string_functions.cpp
Normal file
30
src/string_functions.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include "string_functions.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
std::string& strtrim(std::string& s)
|
||||
{
|
||||
const char* t = " \t\n\r\f\v";
|
||||
s.erase(s.find_last_not_of(t) + 1);
|
||||
s.erase(0, s.find_first_not_of(t));
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
char* strtrim(char* c_str)
|
||||
{
|
||||
std::string std_str;
|
||||
std_str.assign(c_str);
|
||||
strtrim(std_str);
|
||||
int length = std_str.copy(c_str, std_str.size());
|
||||
c_str[length] = '\0';
|
||||
return c_str;
|
||||
}
|
||||
|
||||
|
||||
void to_lower(std::string& str)
|
||||
{
|
||||
for (int i = 0; i < str.size(); i++) str[i] = std::tolower(str[i]);
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
18
src/string_functions.h
Normal file
18
src/string_functions.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
//! \file string_functions.h
|
||||
//! A collection of helper routines for C-strings and STL strings
|
||||
|
||||
#ifndef STRING_FUNCTIONS_H
|
||||
#define STRING_FUNCTIONS_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace openmc {
|
||||
|
||||
std::string& strtrim(std::string& s);
|
||||
|
||||
char* strtrim(char* c_str);
|
||||
|
||||
void to_lower(std::string& str);
|
||||
|
||||
} // namespace openmc
|
||||
#endif // STRING_FUNCTIONS_H
|
||||
|
|
@ -8,7 +8,7 @@ module summary
|
|||
use material_header, only: Material, n_materials
|
||||
use mesh_header, only: RegularMesh
|
||||
use message_passing
|
||||
use mgxs_header, only: nuclides_MG
|
||||
use mgxs_interface
|
||||
use nuclide_header
|
||||
use output, only: time_stamp
|
||||
use settings, only: run_CE
|
||||
|
|
@ -93,7 +93,7 @@ contains
|
|||
num_nuclides = 0
|
||||
num_macros = 0
|
||||
do i = 1, n_nuclides
|
||||
if (nuclides_MG(i) % obj % awr /= MACROSCOPIC_AWR) then
|
||||
if (get_awr_c(i) /= MACROSCOPIC_AWR) then
|
||||
num_nuclides = num_nuclides + 1
|
||||
else
|
||||
num_macros = num_macros + 1
|
||||
|
|
@ -118,12 +118,14 @@ contains
|
|||
nuc_names(i) = nuclides(i) % name
|
||||
awrs(i) = nuclides(i) % awr
|
||||
else
|
||||
if (nuclides_MG(i) % obj % awr /= MACROSCOPIC_AWR) then
|
||||
nuc_names(j) = nuclides_MG(i) % obj % name
|
||||
awrs(j) = nuclides_MG(i) % obj % awr
|
||||
if (get_awr_c(i) /= MACROSCOPIC_AWR) then
|
||||
call get_name_c(i, len(nuc_names(j)), nuc_names(j))
|
||||
nuc_names(j) = trim(nuc_names(j))
|
||||
awrs(j) = get_awr_c(i)
|
||||
j = j + 1
|
||||
else
|
||||
macro_names(k) = nuclides_MG(i) % obj % name
|
||||
call get_name_c(i, len(macro_names(k)), macro_names(k))
|
||||
macro_names(k) = trim(macro_names(k))
|
||||
k = k + 1
|
||||
end if
|
||||
end if
|
||||
|
|
@ -353,7 +355,7 @@ contains
|
|||
num_nuclides = 0
|
||||
num_macros = 0
|
||||
do j = 1, m % n_nuclides
|
||||
if (nuclides_MG(m % nuclide(j)) % obj % awr /= MACROSCOPIC_AWR) then
|
||||
if (get_awr_c(m % nuclide(j)) /= MACROSCOPIC_AWR) then
|
||||
num_nuclides = num_nuclides + 1
|
||||
else
|
||||
num_macros = num_macros + 1
|
||||
|
|
@ -379,12 +381,14 @@ contains
|
|||
k = 1
|
||||
n = 1
|
||||
do j = 1, m % n_nuclides
|
||||
if (nuclides_MG(m % nuclide(j)) % obj % awr /= MACROSCOPIC_AWR) then
|
||||
nuc_names(k) = nuclides_MG(m % nuclide(j)) % obj % name
|
||||
if (get_awr_c(m % nuclide(j)) /= MACROSCOPIC_AWR) then
|
||||
call get_name_c(m % nuclide(j), len(nuc_names(k)), nuc_names(k))
|
||||
nuc_names(k) = trim(nuc_names(k))
|
||||
nuc_densities(k) = m % atom_density(j)
|
||||
k = k + 1
|
||||
else
|
||||
macro_names(n) = nuclides_MG(m % nuclide(j)) % obj % name
|
||||
call get_name_c(m % nuclide(j), len(macro_names(n)), macro_names(n))
|
||||
macro_names(n) = trim(macro_names(n))
|
||||
n = n + 1
|
||||
end if
|
||||
end do
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "hdf5.h"
|
||||
#include "pugixml/pugixml.hpp"
|
||||
#include "pugixml.hpp"
|
||||
|
||||
#include "constants.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ module tally
|
|||
use math, only: t_percentile
|
||||
use mesh_header, only: RegularMesh, meshes
|
||||
use message_passing
|
||||
use mgxs_header
|
||||
use mgxs_interface
|
||||
use nuclide_header
|
||||
use output, only: header
|
||||
use particle_header, only: LocalCoord, Particle
|
||||
|
|
@ -1229,8 +1229,6 @@ contains
|
|||
real(8) :: p_uvw(3) ! Particle's current uvw
|
||||
integer :: p_g ! Particle group to use for getting info
|
||||
! to tally with.
|
||||
class(Mgxs), pointer :: matxs
|
||||
class(Mgxs), pointer :: nucxs
|
||||
|
||||
! Set the direction and group to use with get_xs
|
||||
if (t % estimator == ESTIMATOR_ANALOG .or. &
|
||||
|
|
@ -1268,13 +1266,13 @@ contains
|
|||
|
||||
! To significantly reduce de-referencing, point matxs to the
|
||||
! macroscopic Mgxs for the material of interest
|
||||
matxs => macro_xs(p % material) % obj
|
||||
call set_macro_angle_index_c(p % material, p_uvw)
|
||||
|
||||
! Do same for nucxs, point it to the microscopic nuclide data of interest
|
||||
if (i_nuclide > 0) then
|
||||
nucxs => nuclides_MG(i_nuclide) % obj
|
||||
! And since we haven't calculated this temperature index yet, do so now
|
||||
call nucxs % find_temperature(p % sqrtkT)
|
||||
call set_nuclide_temperature_index_c(i_nuclide, p % sqrtkT)
|
||||
call set_nuclide_angle_index_c(i_nuclide, p_uvw)
|
||||
end if
|
||||
|
||||
i = 0
|
||||
|
|
@ -1328,14 +1326,14 @@ contains
|
|||
end if
|
||||
|
||||
if (i_nuclide > 0) then
|
||||
score = score * atom_density * &
|
||||
nucxs % get_xs('total', p_g, UVW=p_uvw) / &
|
||||
matxs % get_xs('total', p_g, UVW=p_uvw) * flux
|
||||
score = score * flux * atom_density * &
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_TOTAL, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_TOTAL, p_g)
|
||||
end if
|
||||
|
||||
else
|
||||
if (i_nuclide > 0) then
|
||||
score = nucxs % get_xs('total', p_g, UVW=p_uvw) * &
|
||||
score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_TOTAL, p_g) * &
|
||||
atom_density * flux
|
||||
else
|
||||
score = material_xs % total * flux
|
||||
|
|
@ -1358,19 +1356,23 @@ contains
|
|||
end if
|
||||
|
||||
if (i_nuclide > 0) then
|
||||
score = score * nucxs % get_xs('inverse-velocity', p_g, UVW=p_uvw) &
|
||||
/ matxs % get_xs('absorption', p_g, UVW=p_uvw) * flux
|
||||
score = score * flux * get_nuclide_xs_c(i_nuclide, &
|
||||
MG_GET_XS_INVERSE_VELOCITY, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
else
|
||||
score = score * matxs % get_xs('inverse-velocity', p_g, UVW=p_uvw) &
|
||||
/ matxs % get_xs('absorption', p_g, UVW=p_uvw) * flux
|
||||
score = score * flux * get_macro_xs_c(p % material, &
|
||||
MG_GET_XS_INVERSE_VELOCITY, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
end if
|
||||
|
||||
else
|
||||
|
||||
if (i_nuclide > 0) then
|
||||
score = flux * nucxs % get_xs('inverse-velocity', p_g, UVW=p_uvw)
|
||||
score = flux * get_nuclide_xs_c(i_nuclide, &
|
||||
MG_GET_XS_INVERSE_VELOCITY, p_g)
|
||||
else
|
||||
score = flux * matxs % get_xs('inverse-velocity', p_g, UVW=p_uvw)
|
||||
score = flux * get_macro_xs_c(p % material, &
|
||||
MG_GET_XS_INVERSE_VELOCITY, p_g)
|
||||
end if
|
||||
end if
|
||||
|
||||
|
|
@ -1392,21 +1394,23 @@ contains
|
|||
! adjust the score by the actual probability for that nuclide.
|
||||
if (i_nuclide > 0) then
|
||||
score = score * atom_density * &
|
||||
nucxs % get_xs('scatter*f_mu/mult', p % last_g, p % g, &
|
||||
UVW=p_uvw, MU=p % mu) / &
|
||||
matxs % get_xs('scatter*f_mu/mult', p % last_g, p % g, &
|
||||
UVW=p_uvw, MU=p % mu)
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_SCATTER_FMU_MULT, &
|
||||
p % last_g, p % g, MU=p % mu) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_SCATTER_FMU_MULT, &
|
||||
p % last_g, p % g, MU=p % mu)
|
||||
end if
|
||||
|
||||
else
|
||||
if (i_nuclide > 0) then
|
||||
score = atom_density * flux * &
|
||||
nucxs % get_xs('scatter/mult', p_g, UVW=p_uvw)
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_SCATTER_MULT, &
|
||||
p_g, MU=p % mu)
|
||||
else
|
||||
! Get the scattering x/s and take away
|
||||
! the multiplication baked in to sigS
|
||||
score = flux * &
|
||||
matxs % get_xs('scatter/mult', p_g, UVW=p_uvw)
|
||||
get_macro_xs_c(p % material, MG_GET_XS_SCATTER_MULT, &
|
||||
p_g, MU=p % mu)
|
||||
end if
|
||||
end if
|
||||
|
||||
|
|
@ -1428,19 +1432,20 @@ contains
|
|||
! adjust the score by the actual probability for that nuclide.
|
||||
if (i_nuclide > 0) then
|
||||
score = score * atom_density * &
|
||||
nucxs % get_xs('scatter*f_mu', p % last_g, p % g, &
|
||||
UVW=p_uvw, MU=p % mu) / &
|
||||
matxs % get_xs('scatter*f_mu', p % last_g, p % g, &
|
||||
UVW=p_uvw, MU=p % mu)
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_SCATTER_FMU, &
|
||||
p % last_g, p % g, MU=p % mu) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_SCATTER_FMU, &
|
||||
p % last_g, p % g, MU=p % mu)
|
||||
end if
|
||||
|
||||
else
|
||||
if (i_nuclide > 0) then
|
||||
score = nucxs % get_xs('scatter', p_g, UVW=p_uvw) * &
|
||||
atom_density * flux
|
||||
score = atom_density * flux * &
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_SCATTER, p_g)
|
||||
else
|
||||
! Get the scattering x/s, which includes multiplication
|
||||
score = matxs % get_xs('scatter', p_g, UVW=p_uvw) * flux
|
||||
score = flux * &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_SCATTER, p_g)
|
||||
end if
|
||||
end if
|
||||
|
||||
|
|
@ -1460,13 +1465,13 @@ contains
|
|||
end if
|
||||
if (i_nuclide > 0) then
|
||||
score = score * atom_density * &
|
||||
nucxs % get_xs('absorption', p_g, UVW=p_uvw) / &
|
||||
matxs % get_xs('absorption', p_g, UVW=p_uvw)
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_ABSORPTION, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
end if
|
||||
else
|
||||
if (i_nuclide > 0) then
|
||||
score = nucxs % get_xs('absorption', p_g, UVW=p_uvw) * &
|
||||
atom_density * flux
|
||||
score = atom_density * flux * &
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_ABSORPTION, p_g)
|
||||
else
|
||||
score = material_xs % absorption * flux
|
||||
end if
|
||||
|
|
@ -1491,19 +1496,19 @@ contains
|
|||
end if
|
||||
if (i_nuclide > 0) then
|
||||
score = score * atom_density * &
|
||||
nucxs % get_xs('fission', p_g, UVW=p_uvw) / &
|
||||
matxs % get_xs('absorption', p_g, UVW=p_uvw)
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
else
|
||||
score = score * &
|
||||
matxs % get_xs('fission', p_g, UVW=p_uvw) / &
|
||||
matxs % get_xs('absorption', p_g, UVW=p_uvw)
|
||||
get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
end if
|
||||
else
|
||||
if (i_nuclide > 0) then
|
||||
score = nucxs % get_xs('fission', p_g, UVW=p_uvw) * &
|
||||
score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) * &
|
||||
atom_density * flux
|
||||
else
|
||||
score = matxs % get_xs('fission', p_g, UVW=p_uvw) * flux
|
||||
score = get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) * flux
|
||||
end if
|
||||
end if
|
||||
|
||||
|
|
@ -1529,12 +1534,12 @@ contains
|
|||
score = p % absorb_wgt * flux
|
||||
if (i_nuclide > 0) then
|
||||
score = score * atom_density * &
|
||||
nucxs % get_xs('nu-fission', p_g, UVW=p_uvw) / &
|
||||
matxs % get_xs('absorption', p_g, UVW=p_uvw)
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_NU_FISSION, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
else
|
||||
score = score * &
|
||||
matxs % get_xs('nu-fission', p_g, UVW=p_uvw) / &
|
||||
matxs % get_xs('absorption', p_g, UVW=p_uvw)
|
||||
get_macro_xs_c(p % material, MG_GET_XS_NU_FISSION, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
end if
|
||||
else
|
||||
! Skip any non-fission events
|
||||
|
|
@ -1547,17 +1552,17 @@ contains
|
|||
score = keff * p % wgt_bank * flux
|
||||
if (i_nuclide > 0) then
|
||||
score = score * atom_density * &
|
||||
nucxs % get_xs('fission', p_g, UVW=p_uvw) / &
|
||||
matxs % get_xs('fission', p_g, UVW=p_uvw)
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g)
|
||||
end if
|
||||
end if
|
||||
|
||||
else
|
||||
if (i_nuclide > 0) then
|
||||
score = nucxs % get_xs('nu-fission', p_g, UVW=p_uvw) * &
|
||||
score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_NU_FISSION, p_g) * &
|
||||
atom_density * flux
|
||||
else
|
||||
score = matxs % get_xs('nu-fission', p_g, UVW=p_uvw) * flux
|
||||
score = get_macro_xs_c(p % material, MG_GET_XS_NU_FISSION, p_g) * flux
|
||||
end if
|
||||
end if
|
||||
|
||||
|
|
@ -1583,12 +1588,12 @@ contains
|
|||
score = p % absorb_wgt * flux
|
||||
if (i_nuclide > 0) then
|
||||
score = score * atom_density * &
|
||||
nucxs % get_xs('prompt-nu-fission', p_g, UVW=p_uvw) / &
|
||||
matxs % get_xs('absorption', p_g, UVW=p_uvw)
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_PROMPT_NU_FISSION, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
else
|
||||
score = score * &
|
||||
matxs % get_xs('prompt-nu-fission', p_g, UVW=p_uvw) / &
|
||||
matxs % get_xs('absorption', p_g, UVW=p_uvw)
|
||||
get_macro_xs_c(p % material, MG_GET_XS_PROMPT_NU_FISSION, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
end if
|
||||
else
|
||||
! Skip any non-fission events
|
||||
|
|
@ -1602,17 +1607,17 @@ contains
|
|||
/ real(p % n_bank, 8)) * flux
|
||||
if (i_nuclide > 0) then
|
||||
score = score * atom_density * &
|
||||
nucxs % get_xs('fission', p_g, UVW=p_uvw) / &
|
||||
matxs % get_xs('fission', p_g, UVW=p_uvw)
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g)
|
||||
end if
|
||||
end if
|
||||
|
||||
else
|
||||
if (i_nuclide > 0) then
|
||||
score = nucxs % get_xs('prompt-nu-fission', p_g, UVW=p_uvw) * &
|
||||
score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_PROMPT_NU_FISSION, p_g) * &
|
||||
atom_density * flux
|
||||
else
|
||||
score = matxs % get_xs('prompt-nu-fission', p_g, UVW=p_uvw) * flux
|
||||
score = get_macro_xs_c(p % material, MG_GET_XS_PROMPT_NU_FISSION, p_g) * flux
|
||||
end if
|
||||
end if
|
||||
|
||||
|
|
@ -1638,7 +1643,7 @@ contains
|
|||
! No fission events occur if survival biasing is on -- need to
|
||||
! calculate fraction of absorptions that would have resulted in
|
||||
! nu-fission
|
||||
if (matxs % get_xs('absorption', p_g, UVW=p_uvw) > ZERO) then
|
||||
if (get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) > ZERO) then
|
||||
|
||||
if (dg_filter > 0) then
|
||||
select type(filt => filters(t % filter(dg_filter)) % obj)
|
||||
|
|
@ -1653,13 +1658,13 @@ contains
|
|||
|
||||
score = p % absorb_wgt * flux
|
||||
if (i_nuclide > 0) then
|
||||
score = score * nucxs % get_xs('delayed-nu-fission', &
|
||||
p_g, UVW=p_uvw, dg=d) / &
|
||||
matxs % get_xs('absorption', p_g, UVW=p_uvw)
|
||||
score = score * &
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
else
|
||||
score = score * matxs % get_xs('delayed-nu-fission', &
|
||||
p_g, UVW=p_uvw, dg=d) / &
|
||||
matxs % get_xs('absorption', p_g, UVW=p_uvw)
|
||||
score = score * &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
end if
|
||||
|
||||
call score_fission_delayed_dg(t, d_bin, score, score_index)
|
||||
|
|
@ -1669,11 +1674,13 @@ contains
|
|||
else
|
||||
score = p % absorb_wgt * flux
|
||||
if (i_nuclide > 0) then
|
||||
score = score * nucxs % get_xs('delayed-nu-fission', p_g, &
|
||||
UVW=p_uvw) / matxs % get_xs('absorption', p_g, UVW=p_uvw)
|
||||
score = score * &
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
else
|
||||
score = score * matxs % get_xs('delayed-nu-fission', p_g, &
|
||||
UVW=p_uvw) / matxs % get_xs('absorption', p_g, UVW=p_uvw)
|
||||
score = score * &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
|
|
@ -1703,8 +1710,8 @@ contains
|
|||
|
||||
if (i_nuclide > 0) then
|
||||
score = score * atom_density * &
|
||||
nucxs % get_xs('fission', p_g, UVW=p_uvw) / &
|
||||
matxs % get_xs('fission', p_g, UVW=p_uvw)
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g)
|
||||
end if
|
||||
|
||||
call score_fission_delayed_dg(t, d_bin, score, score_index)
|
||||
|
|
@ -1715,8 +1722,8 @@ contains
|
|||
score = keff * p % wgt_bank / p % n_bank * sum(p % n_delayed_bank) * flux
|
||||
if (i_nuclide > 0) then
|
||||
score = score * atom_density * &
|
||||
nucxs % get_xs('fission', p_g, UVW=p_uvw) / &
|
||||
matxs % get_xs('fission', p_g, UVW=p_uvw)
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g)
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
|
|
@ -1735,11 +1742,11 @@ contains
|
|||
d = filt % groups(d_bin)
|
||||
|
||||
if (i_nuclide > 0) then
|
||||
score = nucxs % get_xs('delayed-nu-fission', p_g, &
|
||||
UVW=p_uvw, dg=d) * atom_density * flux
|
||||
score = atom_density * flux * &
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d)
|
||||
else
|
||||
score = matxs % get_xs('delayed-nu-fission', p_g, &
|
||||
UVW=p_uvw, dg=d) * flux
|
||||
score = flux * &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d)
|
||||
end if
|
||||
|
||||
call score_fission_delayed_dg(t, d_bin, score, score_index)
|
||||
|
|
@ -1748,11 +1755,12 @@ contains
|
|||
end select
|
||||
else
|
||||
if (i_nuclide > 0) then
|
||||
score = nucxs % get_xs('delayed-nu-fission', p_g, UVW=p_uvw) &
|
||||
* atom_density * flux
|
||||
score = atom_density * flux * &
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g)
|
||||
|
||||
else
|
||||
score = matxs % get_xs('delayed-nu-fission', p_g, UVW=p_uvw) &
|
||||
* flux
|
||||
score = flux * &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g)
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
|
|
@ -1767,7 +1775,7 @@ contains
|
|||
! No fission events occur if survival biasing is on -- need to
|
||||
! calculate fraction of absorptions that would have resulted in
|
||||
! nu-fission
|
||||
if (matxs % get_xs('absorption', p_g, UVW=p_uvw) > ZERO) then
|
||||
if (get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g) > ZERO) then
|
||||
|
||||
if (dg_filter > 0) then
|
||||
select type(filt => filters(t % filter(dg_filter)) % obj)
|
||||
|
|
@ -1782,17 +1790,15 @@ contains
|
|||
|
||||
score = p % absorb_wgt * flux
|
||||
if (i_nuclide > 0) then
|
||||
score = score * nucxs % get_xs('decay rate', p_g, &
|
||||
UVW=p_uvw, dg=d) * &
|
||||
nucxs % get_xs('delayed-nu-fission', p_g, &
|
||||
UVW=p_uvw, dg=d) / matxs % get_xs('absorption', &
|
||||
p_g, UVW=p_uvw)
|
||||
score = score * &
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * &
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
else
|
||||
score = score * matxs % get_xs('decay rate', p_g, &
|
||||
UVW=p_uvw, dg=d) * &
|
||||
matxs % get_xs('delayed-nu-fission', p_g, &
|
||||
UVW=p_uvw, dg=d) / matxs % get_xs('absorption', &
|
||||
p_g, UVW=p_uvw)
|
||||
score = score * &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
end if
|
||||
|
||||
call score_fission_delayed_dg(t, d_bin, score, score_index)
|
||||
|
|
@ -1809,15 +1815,15 @@ contains
|
|||
! for all delayed groups.
|
||||
do d = 1, num_delayed_groups
|
||||
if (i_nuclide > 0) then
|
||||
score = score + p % absorb_wgt * &
|
||||
nucxs % get_xs('decay rate', p_g, UVW=p_uvw, dg=d) * &
|
||||
nucxs % get_xs('delayed-nu-fission', p_g, UVW=p_uvw, &
|
||||
dg=d) / matxs % get_xs('absorption', p_g, UVW=p_uvw) * flux
|
||||
score = score + p % absorb_wgt * flux * &
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * &
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
else
|
||||
score = score + p % absorb_wgt * &
|
||||
matxs % get_xs('decay rate', p_g, UVW=p_uvw, dg=d) * &
|
||||
matxs % get_xs('delayed-nu-fission', p_g, UVW=p_uvw, &
|
||||
dg=d) / matxs % get_xs('absorption', p_g, UVW=p_uvw) * flux
|
||||
score = score + p % absorb_wgt * flux * &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
end if
|
||||
end do
|
||||
end if
|
||||
|
|
@ -1846,13 +1852,13 @@ contains
|
|||
if (i_nuclide > 0) then
|
||||
score = score + keff * atom_density * &
|
||||
fission_bank(n_bank - p % n_bank + k) % wgt * &
|
||||
nucxs % get_xs('decay rate', p_g, UVW=p_uvw, dg=g) * &
|
||||
nucxs % get_xs('fission', p_g, UVW=p_uvw) / &
|
||||
matxs % get_xs('fission', p_g, UVW=p_uvw) * flux
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * &
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_FISSION, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_FISSION, p_g) * flux
|
||||
else
|
||||
score = score + keff * &
|
||||
fission_bank(n_bank - p % n_bank + k) % wgt * &
|
||||
matxs % get_xs('decay rate', p_g, UVW=p_uvw, dg=g) * flux
|
||||
get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * flux
|
||||
end if
|
||||
|
||||
! if the delayed group filter is present, tally to corresponding
|
||||
|
|
@ -1904,13 +1910,13 @@ contains
|
|||
d = filt % groups(d_bin)
|
||||
|
||||
if (i_nuclide > 0) then
|
||||
score = nucxs % get_xs('decay rate', p_g, UVW=p_uvw, dg=d) * &
|
||||
nucxs % get_xs('delayed-nu-fission', p_g, UVW=p_uvw, &
|
||||
dg=d) * atom_density * flux
|
||||
score = atom_density * flux * &
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * &
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d)
|
||||
else
|
||||
score = matxs % get_xs('decay rate', p_g, UVW=p_uvw, dg=d) * &
|
||||
matxs % get_xs('delayed-nu-fission', p_g, UVW=p_uvw, &
|
||||
dg=d) * flux
|
||||
score = flux * &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d)
|
||||
end if
|
||||
|
||||
call score_fission_delayed_dg(t, d_bin, score, score_index)
|
||||
|
|
@ -1927,12 +1933,12 @@ contains
|
|||
do d = 1, num_delayed_groups
|
||||
if (i_nuclide > 0) then
|
||||
score = score + atom_density * flux * &
|
||||
nucxs % get_xs('decay rate', p_g, UVW=p_uvw, dg=d) * &
|
||||
nucxs % get_xs('delayed-nu-fission', p_g, UVW=p_uvw, dg=d)
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, DG=d) * &
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d)
|
||||
else
|
||||
score = score + flux * &
|
||||
matxs % get_xs('decay rate', p_g, UVW=p_uvw, dg=d) * &
|
||||
matxs % get_xs('delayed-nu-fission', p_g, UVW=p_uvw, dg=d)
|
||||
get_macro_xs_c(p % material, MG_GET_XS_DECAY_RATE, p_g, DG=d) * &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_DELAYED_NU_FISSION, p_g, DG=d)
|
||||
end if
|
||||
end do
|
||||
end if
|
||||
|
|
@ -1957,19 +1963,20 @@ contains
|
|||
end if
|
||||
if (i_nuclide > 0) then
|
||||
score = score * atom_density * &
|
||||
nucxs % get_xs('kappa-fission', p_g, UVW=p_uvw) / &
|
||||
matxs % get_xs('absorption', p_g, UVW=p_uvw)
|
||||
get_nuclide_xs_c(i_nuclide, MG_GET_XS_KAPPA_FISSION, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
else
|
||||
score = score * &
|
||||
matxs % get_xs('kappa-fission', p_g, UVW=p_uvw) / &
|
||||
matxs % get_xs('absorption', p_g, UVW=p_uvw)
|
||||
get_macro_xs_c(p % material, MG_GET_XS_KAPPA_FISSION, p_g) / &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_ABSORPTION, p_g)
|
||||
end if
|
||||
else
|
||||
if (i_nuclide > 0) then
|
||||
score = nucxs % get_xs('kappa-fission', p_g, UVW=p_uvw) * &
|
||||
score = get_nuclide_xs_c(i_nuclide, MG_GET_XS_KAPPA_FISSION, p_g) * &
|
||||
atom_density * flux
|
||||
else
|
||||
score = matxs % get_xs('kappa-fission', p_g, UVW=p_uvw) * flux
|
||||
score = flux * &
|
||||
get_macro_xs_c(p % material, MG_GET_XS_KAPPA_FISSION, p_g)
|
||||
|
||||
end if
|
||||
end if
|
||||
|
|
@ -1988,8 +1995,6 @@ contains
|
|||
t % results(RESULT_VALUE, score_index, filter_index) + score
|
||||
|
||||
end do SCORE_LOOP
|
||||
|
||||
nullify(matxs, nucxs)
|
||||
end subroutine score_general_mg
|
||||
|
||||
!===============================================================================
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ module tally_filter_energy
|
|||
use constants
|
||||
use error
|
||||
use hdf5_interface
|
||||
use mgxs_header, only: num_energy_groups, rev_energy_bins
|
||||
use mgxs_interface, only: num_energy_groups, rev_energy_bins
|
||||
use particle_header, only: Particle
|
||||
use settings, only: run_CE
|
||||
use string, only: to_str
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
module tracking
|
||||
|
||||
use, intrinsic :: ISO_C_BINDING
|
||||
|
||||
use constants
|
||||
use error, only: warning, write_message
|
||||
use geometry_header, only: cells
|
||||
|
|
@ -7,7 +9,7 @@ module tracking
|
|||
check_cell_overlap
|
||||
use material_header, only: materials, Material
|
||||
use message_passing
|
||||
use mgxs_header
|
||||
use mgxs_interface
|
||||
use nuclide_header
|
||||
use particle_header, only: LocalCoord, Particle
|
||||
use physics, only: collision
|
||||
|
|
@ -112,8 +114,10 @@ contains
|
|||
end if
|
||||
else
|
||||
! Get the MG data
|
||||
call macro_xs(p % material) % obj % calculate_xs(p % g, p % sqrtkT, &
|
||||
p % coord(p % n_coord) % uvw, material_xs)
|
||||
call calculate_xs_c(p % material, p % g, p % sqrtkT, &
|
||||
p % coord(p % n_coord) % uvw, material_xs % total, &
|
||||
material_xs % absorption, material_xs % nu_fission)
|
||||
|
||||
|
||||
! Finally, update the particle group while we have already checked
|
||||
! for if multi-group
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "pugixml/pugixml.hpp"
|
||||
#include "pugixml.hpp"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
|
|
|||
713
src/xsdata.cpp
Normal file
713
src/xsdata.cpp
Normal file
|
|
@ -0,0 +1,713 @@
|
|||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
#include "constants.h"
|
||||
#include "error.h"
|
||||
#include "math_functions.h"
|
||||
#include "random_lcg.h"
|
||||
#include "xsdata.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// XsData class methods
|
||||
//==============================================================================
|
||||
|
||||
XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable,
|
||||
int scatter_format, int n_pol, int n_azi)
|
||||
{
|
||||
int n_ang = n_pol * n_azi;
|
||||
|
||||
// check to make sure scatter format is OK before we allocate
|
||||
if (scatter_format != ANGLE_HISTOGRAM && scatter_format != ANGLE_TABULAR &&
|
||||
scatter_format != ANGLE_LEGENDRE) {
|
||||
fatal_error("Invalid scatter_format!");
|
||||
}
|
||||
// allocate all [temperature][phi][theta][in group] quantities
|
||||
total = double_2dvec(n_ang, double_1dvec(energy_groups, 0.));
|
||||
absorption = double_2dvec(n_ang, double_1dvec(energy_groups, 0.));
|
||||
inverse_velocity = double_2dvec(n_ang, double_1dvec(energy_groups, 0.));
|
||||
if (fissionable) {
|
||||
fission = double_2dvec(n_ang, double_1dvec(energy_groups, 0.));
|
||||
nu_fission = double_2dvec(n_ang, double_1dvec(energy_groups, 0.));
|
||||
prompt_nu_fission = double_2dvec(n_ang, double_1dvec(energy_groups, 0.));
|
||||
kappa_fission = double_2dvec(n_ang, double_1dvec(energy_groups, 0.));
|
||||
}
|
||||
|
||||
// allocate decay_rate; [temperature][phi][theta][delayed group]
|
||||
decay_rate = double_2dvec(n_ang, double_1dvec(num_delayed_groups, 0.));
|
||||
|
||||
if (fissionable) {
|
||||
// allocate delayed_nu_fission; [temperature][phi][theta][in group][delay group]
|
||||
delayed_nu_fission = double_3dvec(n_ang, double_2dvec(energy_groups,
|
||||
double_1dvec(num_delayed_groups, 0.)));
|
||||
|
||||
// chi_prompt; [temperature][phi][theta][in group][delayed group]
|
||||
chi_prompt = double_3dvec(n_ang, double_2dvec(energy_groups,
|
||||
double_1dvec(energy_groups, 0.)));
|
||||
|
||||
// chi_delayed; [temperature][phi][theta][in group][out group][delay group]
|
||||
chi_delayed = double_4dvec(n_ang, double_3dvec(energy_groups,
|
||||
double_2dvec(energy_groups, double_1dvec(num_delayed_groups, 0.))));
|
||||
}
|
||||
|
||||
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
if (scatter_format == ANGLE_HISTOGRAM) {
|
||||
// scatter[a] = std::make_unique(ScattDataHistogram);
|
||||
scatter.emplace_back(new ScattDataHistogram);
|
||||
} else if (scatter_format == ANGLE_TABULAR) {
|
||||
// scatter[a] = std::make_unique(ScattDataTabular);
|
||||
scatter.emplace_back(new ScattDataTabular);
|
||||
} else if (scatter_format == ANGLE_LEGENDRE) {
|
||||
// scatter[a] = std::make_unique(ScattDataLegendre);
|
||||
scatter.emplace_back(new ScattDataLegendre);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format,
|
||||
int final_scatter_format, int order_data, int max_order,
|
||||
int legendre_to_tabular_points, bool is_isotropic, int n_pol, int n_azi)
|
||||
{
|
||||
// Reconstruct the dimension information so it doesn't need to be passed
|
||||
int n_ang = n_pol * n_azi;
|
||||
int energy_groups = total[0].size();
|
||||
int delayed_groups = decay_rate[0].size();
|
||||
|
||||
// Set the fissionable-specific data
|
||||
if (fissionable) {
|
||||
fission_from_hdf5(xsdata_grp, n_pol, n_azi, energy_groups, delayed_groups,
|
||||
is_isotropic);
|
||||
}
|
||||
// Get the non-fission-specific data
|
||||
read_nd_vector(xsdata_grp, "decay_rate", decay_rate);
|
||||
read_nd_vector(xsdata_grp, "absorption", absorption, true);
|
||||
read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity);
|
||||
|
||||
// Get scattering data
|
||||
scatter_from_hdf5(xsdata_grp, n_pol, n_azi, energy_groups, scatter_format,
|
||||
final_scatter_format, order_data, max_order, legendre_to_tabular_points);
|
||||
|
||||
// Check absorption to ensure it is not 0 since it is often the
|
||||
// denominator in tally methods
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
if (absorption[a][gin] == 0.) absorption[a][gin] = 1.e-10;
|
||||
}
|
||||
}
|
||||
|
||||
// Get or calculate the total x/s
|
||||
if (object_exists(xsdata_grp, "total")) {
|
||||
read_nd_vector(xsdata_grp, "total", total);
|
||||
} else {
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
total[a][gin] = absorption[a][gin] + scatter[a]->scattxs[gin];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fix if total is 0, since it is in the denominator when tallying
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
if (total[a][gin] == 0.) total[a][gin] = 1.e-10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi,
|
||||
int energy_groups, int delayed_groups, bool is_isotropic)
|
||||
{
|
||||
int n_ang = n_pol * n_azi;
|
||||
// Get the fission and kappa_fission data xs; these are optional
|
||||
read_nd_vector(xsdata_grp, "fission", fission);
|
||||
read_nd_vector(xsdata_grp, "kappa-fission", kappa_fission);
|
||||
|
||||
// Set/get beta
|
||||
double_3dvec temp_beta =double_3dvec(n_ang, double_2dvec(energy_groups,
|
||||
double_1dvec(delayed_groups, 0.)));
|
||||
if (object_exists(xsdata_grp, "beta")) {
|
||||
hid_t xsdata = open_dataset(xsdata_grp, "beta");
|
||||
int ndims = dataset_ndims(xsdata);
|
||||
|
||||
// raise ndims to make the isotropic ndims the same as angular
|
||||
if (is_isotropic) ndims += 2;
|
||||
|
||||
if (ndims == 3) {
|
||||
// Beta is input as [delayed group]
|
||||
double_1dvec temp_arr(n_pol * n_azi * delayed_groups);
|
||||
read_nd_vector(xsdata_grp, "beta", temp_arr);
|
||||
|
||||
// Broadcast to all incoming groups
|
||||
int temp_idx = 0;
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
for (int dg = 0; dg < delayed_groups; dg++) {
|
||||
// Set the first group index and copy the rest
|
||||
temp_beta[a][0][dg] = temp_arr[temp_idx++];
|
||||
for (int gin = 1; gin < energy_groups; gin++) {
|
||||
temp_beta[a][gin] = temp_beta[a][0];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (ndims == 4) {
|
||||
// Beta is input as [in group][delayed group]
|
||||
read_nd_vector(xsdata_grp, "beta", temp_beta);
|
||||
} else {
|
||||
fatal_error("beta must be provided as a 3D or 4D array!");
|
||||
}
|
||||
}
|
||||
|
||||
// If chi is provided, set chi-prompt and chi-delayed
|
||||
if (object_exists(xsdata_grp, "chi")) {
|
||||
double_2dvec temp_arr(n_ang, double_1dvec(energy_groups));
|
||||
read_nd_vector(xsdata_grp, "chi", temp_arr);
|
||||
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
// First set the first group
|
||||
for (int gout = 0; gout < energy_groups; gout++) {
|
||||
chi_prompt[a][0][gout] = temp_arr[a][gout];
|
||||
}
|
||||
|
||||
// Now normalize this data
|
||||
double chi_sum = std::accumulate(chi_prompt[a][0].begin(),
|
||||
chi_prompt[a][0].end(),
|
||||
0.);
|
||||
if (chi_sum <= 0.) {
|
||||
fatal_error("Encountered chi for a group that is <= 0!");
|
||||
}
|
||||
for (int gout = 0; gout < energy_groups; gout++) {
|
||||
chi_prompt[a][0][gout] /= chi_sum;
|
||||
}
|
||||
|
||||
// And extend to the remaining incoming groups
|
||||
for (int gin = 1; gin < energy_groups; gin++) {
|
||||
chi_prompt[a][gin] = chi_prompt[a][0];
|
||||
}
|
||||
|
||||
// Finally set chi-delayed equal to chi-prompt
|
||||
// Set chi-delayed to chi-prompt
|
||||
for(int gin = 0; gin < energy_groups; gin++) {
|
||||
for (int gout = 0; gout < energy_groups; gout++) {
|
||||
for (int dg = 0; dg < delayed_groups; dg++) {
|
||||
chi_delayed[a][gin][gout][dg] =
|
||||
chi_prompt[a][gin][gout];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If nu-fission is provided, set prompt- and delayed-nu-fission;
|
||||
// if nu-fission is a matrix, set chi-prompt and chi-delayed.
|
||||
if (object_exists(xsdata_grp, "nu-fission")) {
|
||||
hid_t xsdata = open_dataset(xsdata_grp, "nu-fission");
|
||||
int ndims = dataset_ndims(xsdata);
|
||||
// raise ndims to make the isotropic ndims the same as angular
|
||||
if (is_isotropic) ndims += 2;
|
||||
|
||||
if (ndims == 3) {
|
||||
// nu-fission is a 3-d array
|
||||
read_nd_vector(xsdata_grp, "nu-fission", prompt_nu_fission);
|
||||
|
||||
// set delayed-nu-fission and correct prompt-nu-fission with beta
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
for (int dg = 0; dg < delayed_groups; dg++) {
|
||||
delayed_nu_fission[a][gin][dg] =
|
||||
temp_beta[a][gin][dg] * prompt_nu_fission[a][gin];
|
||||
}
|
||||
|
||||
// Correct the prompt-nu-fission using the delayed neutron fraction
|
||||
if (delayed_groups > 0) {
|
||||
double beta_sum = std::accumulate(temp_beta[a][gin].begin(),
|
||||
temp_beta[a][gin].end(), 0.);
|
||||
prompt_nu_fission[a][gin] *= (1. - beta_sum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (ndims == 4) {
|
||||
// nu-fission is a matrix
|
||||
read_nd_vector(xsdata_grp, "nu-fission", chi_prompt);
|
||||
|
||||
// Normalize the chi info so the CDF is 1.
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
double chi_sum = std::accumulate(chi_prompt[a][gin].begin(),
|
||||
chi_prompt[a][gin].end(), 0.);
|
||||
// Set the vector nu-fission from the matrix nu-fission
|
||||
prompt_nu_fission[a][gin] = chi_sum;
|
||||
|
||||
if (chi_sum >= 0.) {
|
||||
for (int gout = 0; gout < energy_groups; gout++) {
|
||||
chi_prompt[a][gin][gout] /= chi_sum;
|
||||
}
|
||||
} else {
|
||||
fatal_error("Encountered chi for a group that is <= 0!");
|
||||
}
|
||||
}
|
||||
|
||||
// set chi-delayed to chi-prompt
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
for (int gout = 0; gout < energy_groups; gout++) {
|
||||
for (int dg = 0; dg < delayed_groups; dg++) {
|
||||
chi_delayed[a][gin][gout][dg] =
|
||||
chi_prompt[a][gin][gout];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the delayed-nu-fission and correct prompt-nu-fission with beta
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
for (int dg = 0; dg < delayed_groups; dg++) {
|
||||
delayed_nu_fission[a][gin][dg] =
|
||||
temp_beta[a][gin][dg] *
|
||||
prompt_nu_fission[a][gin];
|
||||
}
|
||||
|
||||
// Correct prompt-nu-fission using the delayed neutron fraction
|
||||
if (delayed_groups > 0) {
|
||||
double beta_sum = std::accumulate(temp_beta[a][gin].begin(),
|
||||
temp_beta[a][gin].end(), 0.);
|
||||
prompt_nu_fission[a][gin] *= (1. - beta_sum);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fatal_error("nu-fission must be provided as a 3D or 4D array!");
|
||||
}
|
||||
|
||||
close_dataset(xsdata);
|
||||
}
|
||||
|
||||
// If chi-prompt is provided, set chi-prompt
|
||||
if (object_exists(xsdata_grp, "chi-prompt")) {
|
||||
double_2dvec temp_arr(n_ang, double_1dvec(energy_groups));
|
||||
read_nd_vector(xsdata_grp, "chi-prompt", temp_arr);
|
||||
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
for (int gout = 0; gout < energy_groups; gout++) {
|
||||
chi_prompt[a][gin][gout] = temp_arr[a][gout];
|
||||
}
|
||||
|
||||
// Normalize chi so its CDF goes to 1
|
||||
double chi_sum = std::accumulate(chi_prompt[a][gin].begin(),
|
||||
chi_prompt[a][gin].end(), 0.);
|
||||
if (chi_sum >= 0.) {
|
||||
for (int gout = 0; gout < energy_groups; gout++) {
|
||||
chi_prompt[a][gin][gout] /= chi_sum;
|
||||
}
|
||||
} else {
|
||||
fatal_error("Encountered chi-prompt for a group that is <= 0.!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If chi-delayed is provided, set chi-delayed
|
||||
if (object_exists(xsdata_grp, "chi-delayed")) {
|
||||
hid_t xsdata = open_dataset(xsdata_grp, "chi-delayed");
|
||||
int ndims = dataset_ndims(xsdata);
|
||||
// raise ndims to make the isotropic ndims the same as angular
|
||||
if (is_isotropic) ndims += 2;
|
||||
close_dataset(xsdata);
|
||||
|
||||
if (ndims == 3) {
|
||||
// chi-delayed is a [in group] vector
|
||||
double_2dvec temp_arr(n_ang, double_1dvec(energy_groups));
|
||||
read_nd_vector(xsdata_grp, "chi-delayed", temp_arr);
|
||||
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
// normalize the chi CDF to 1
|
||||
double chi_sum = std::accumulate(temp_arr[a].begin(),
|
||||
temp_arr[a].end(), 0.);
|
||||
if (chi_sum <= 0.) {
|
||||
fatal_error("Encountered chi-delayed for a group that is <= 0!");
|
||||
}
|
||||
|
||||
// set chi-delayed
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
for (int gout = 0; gout < energy_groups; gout++) {
|
||||
for (int dg = 0; dg < delayed_groups; dg++) {
|
||||
chi_delayed[a][gin][gout][dg] = temp_arr[a][gout] / chi_sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (ndims == 4) {
|
||||
// chi_delayed is a matrix
|
||||
read_nd_vector(xsdata_grp, "chi-delayed", chi_delayed);
|
||||
|
||||
// Normalize the chi info so the CDF is 1.
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
for (int dg = 0; dg < delayed_groups; dg++) {
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
double chi_sum = 0.;
|
||||
for (int gout = 0; gout < energy_groups; gout++) {
|
||||
chi_sum += chi_delayed[a][gin][gout][dg];
|
||||
}
|
||||
|
||||
if (chi_sum > 0.) {
|
||||
for (int gout = 0; gout < energy_groups; gout++) {
|
||||
chi_delayed[a][gin][gout][dg] /= chi_sum;
|
||||
}
|
||||
} else {
|
||||
fatal_error("Encountered chi-delayed for a group that is <= 0!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fatal_error("chi-delayed must be provided as a 3D or 4D array!");
|
||||
}
|
||||
}
|
||||
|
||||
// Get prompt-nu-fission, if present
|
||||
if (object_exists(xsdata_grp, "prompt-nu-fission")) {
|
||||
hid_t xsdata = open_dataset(xsdata_grp, "prompt-nu-fission");
|
||||
int ndims = dataset_ndims(xsdata);
|
||||
// raise ndims to make the isotropic ndims the same as angular
|
||||
if (is_isotropic) ndims += 2;
|
||||
close_dataset(xsdata);
|
||||
|
||||
if (ndims == 3) {
|
||||
// prompt-nu-fission is a [in group] vector
|
||||
read_nd_vector(xsdata_grp, "prompt-nu-fission",
|
||||
prompt_nu_fission);
|
||||
} else if (ndims == 4) {
|
||||
// prompt nu fission is a matrix,
|
||||
// so set prompt_nu_fiss & chi_prompt
|
||||
double_3dvec temp_arr(n_ang, double_2dvec(energy_groups,
|
||||
double_1dvec(energy_groups)));
|
||||
read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_arr);
|
||||
|
||||
// The prompt_nu_fission vector from the matrix form
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
double prompt_sum = std::accumulate(temp_arr[a][gin].begin(),
|
||||
temp_arr[a][gin].end(), 0.);
|
||||
prompt_nu_fission[a][gin] = prompt_sum;
|
||||
}
|
||||
|
||||
// The chi_prompt data is just the normalized fission matrix
|
||||
for (int gin= 0; gin < energy_groups; gin++) {
|
||||
if (prompt_nu_fission[a][gin] > 0.) {
|
||||
for (int gout = 0; gout < energy_groups; gout++) {
|
||||
chi_prompt[a][gin][gout] =
|
||||
temp_arr[a][gin][gout] / prompt_nu_fission[a][gin];
|
||||
}
|
||||
} else {
|
||||
fatal_error("Encountered chi-prompt for a group that is <= 0!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
fatal_error("prompt-nu-fission must be provided as a 3D or 4D array!");
|
||||
}
|
||||
}
|
||||
|
||||
// Get delayed-nu-fission, if present
|
||||
if (object_exists(xsdata_grp, "delayed-nu-fission")) {
|
||||
hid_t xsdata = open_dataset(xsdata_grp, "delayed-nu-fission");
|
||||
int ndims = dataset_ndims(xsdata);
|
||||
close_dataset(xsdata);
|
||||
// raise ndims to make the isotropic ndims the same as angular
|
||||
if (is_isotropic) ndims += 2;
|
||||
|
||||
if (ndims == 3) {
|
||||
// delayed-nu-fission is an [in group] vector
|
||||
if (temp_beta[0][0][0] == 0.) {
|
||||
fatal_error("cannot set delayed-nu-fission with a 1D array if "
|
||||
"beta is not provided");
|
||||
}
|
||||
double_2dvec temp_arr(n_ang, double_1dvec(energy_groups));
|
||||
read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr);
|
||||
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
for (int dg = 0; dg < delayed_groups; dg++) {
|
||||
// Set delayed-nu-fission using beta
|
||||
delayed_nu_fission[a][gin][dg] =
|
||||
temp_beta[a][gin][dg] * temp_arr[a][gin];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (ndims == 4) {
|
||||
read_nd_vector(xsdata_grp, "delayed-nu-fission",
|
||||
delayed_nu_fission);
|
||||
|
||||
} else if (ndims == 5) {
|
||||
// This will contain delayed-nu-fision and chi-delayed data
|
||||
double_4dvec temp_arr(n_ang, double_3dvec(energy_groups,
|
||||
double_2dvec(energy_groups, double_1dvec(delayed_groups))));
|
||||
read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr);
|
||||
|
||||
// Set the 3D delayed-nu-fission matrix and 4D chi-delayed matrix
|
||||
// from the 4D delayed-nu-fission matrix
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
for (int dg = 0; dg < delayed_groups; dg++) {
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
double gout_sum = 0.;
|
||||
for (int gout = 0; gout < energy_groups; gout++) {
|
||||
gout_sum += temp_arr[a][gin][gout][dg];
|
||||
chi_delayed[a][gin][gout][dg] = temp_arr[a][gin][gout][dg];
|
||||
}
|
||||
delayed_nu_fission[a][gin][dg] = gout_sum;
|
||||
// Normalize chi-delayed
|
||||
if (gout_sum > 0.) {
|
||||
for (int gout = 0; gout < energy_groups; gout++) {
|
||||
chi_delayed[a][gin][gout][dg] /= gout_sum;
|
||||
}
|
||||
} else {
|
||||
fatal_error("Encountered chi-delayed for a group that is <= 0!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
fatal_error("prompt-nu-fission must be provided as a 3D, 4D, or 5D "
|
||||
"array!");
|
||||
}
|
||||
}
|
||||
|
||||
// Combine prompt_nu_fission and delayed_nu_fission into nu_fission
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
nu_fission[a][gin] =
|
||||
std::accumulate(delayed_nu_fission[a][gin].begin(),
|
||||
delayed_nu_fission[a][gin].end(),
|
||||
prompt_nu_fission[a][gin]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi,
|
||||
int energy_groups, int scatter_format, int final_scatter_format,
|
||||
int order_data, int max_order, int legendre_to_tabular_points)
|
||||
{
|
||||
int n_ang = n_pol * n_azi;
|
||||
if (!object_exists(xsdata_grp, "scatter_data")) {
|
||||
fatal_error("Must provide scatter_data group!");
|
||||
}
|
||||
hid_t scatt_grp = open_group(xsdata_grp, "scatter_data");
|
||||
|
||||
// Get the outgoing group boundary indices
|
||||
int_2dvec gmin(n_ang, int_1dvec(energy_groups));
|
||||
read_nd_vector(scatt_grp, "g_min", gmin, true);
|
||||
int_2dvec gmax(n_ang, int_1dvec(energy_groups));
|
||||
read_nd_vector(scatt_grp, "g_max", gmax, true);
|
||||
|
||||
// Make gmin and gmax start from 0 vice 1 as they do in the library
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
gmin[a][gin] -= 1;
|
||||
gmax[a][gin] -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Now use this info to find the length of a vector to hold the flattened
|
||||
// data.
|
||||
int length = 0;
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
length += order_data * (gmax[a][gin] - gmin[a][gin] + 1);
|
||||
}
|
||||
}
|
||||
double_1dvec temp_arr(length);
|
||||
read_nd_vector(scatt_grp, "scatter_matrix", temp_arr, true);
|
||||
|
||||
// Compare the number of orders given with the max order of the problem;
|
||||
// strip off the superfluous orders if needed
|
||||
int order_dim;
|
||||
if (scatter_format == ANGLE_LEGENDRE) {
|
||||
order_dim = std::min(order_data - 1, max_order) + 1;
|
||||
} else {
|
||||
order_dim = order_data;
|
||||
}
|
||||
|
||||
// convert the flattened temp_arr to a jagged array for passing to
|
||||
// scatt data
|
||||
double_4dvec input_scatt(n_ang, double_3dvec(energy_groups));
|
||||
|
||||
int temp_idx = 0;
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
input_scatt[a][gin].resize(gmax[a][gin] - gmin[a][gin] + 1);
|
||||
for (int i_gout = 0; i_gout < input_scatt[a][gin].size(); i_gout++) {
|
||||
input_scatt[a][gin][i_gout].resize(order_dim);
|
||||
for (int l = 0; l < order_dim; l++) {
|
||||
input_scatt[a][gin][i_gout][l] = temp_arr[temp_idx++];
|
||||
}
|
||||
// Adjust index for the orders we didnt take
|
||||
temp_idx += (order_data - order_dim);
|
||||
}
|
||||
}
|
||||
}
|
||||
temp_arr.clear();
|
||||
|
||||
// Get multiplication matrix
|
||||
double_3dvec temp_mult(n_ang, double_2dvec(energy_groups));
|
||||
if (object_exists(scatt_grp, "multiplicity_matrix")) {
|
||||
temp_arr.resize(length / order_data);
|
||||
read_nd_vector(scatt_grp, "multiplicity_matrix", temp_arr);
|
||||
|
||||
// convert the flat temp_arr to a jagged array for passing to scatt data
|
||||
int temp_idx = 0;
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
temp_mult[a][gin].resize(gmax[a][gin] - gmin[a][gin] + 1);
|
||||
for (int i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) {
|
||||
temp_mult[a][gin][i_gout] = temp_arr[temp_idx++];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Use a default: multiplicities are 1.0.
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
for (int gin = 0; gin < energy_groups; gin++) {
|
||||
temp_mult[a][gin].resize(gmax[a][gin] - gmin[a][gin] + 1);
|
||||
for (int i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) {
|
||||
temp_mult[a][gin][i_gout] = 1.;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
temp_arr.clear();
|
||||
close_group(scatt_grp);
|
||||
|
||||
// Finally, convert the Legendre data to tabular, if needed
|
||||
if (scatter_format == ANGLE_LEGENDRE &&
|
||||
final_scatter_format == ANGLE_TABULAR) {
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
ScattDataLegendre legendre_scatt;
|
||||
legendre_scatt.init(gmin[a], gmax[a], temp_mult[a], input_scatt[a]);
|
||||
|
||||
// Now create a tabular version of legendre_scatt
|
||||
convert_legendre_to_tabular(legendre_scatt,
|
||||
*static_cast<ScattDataTabular*>(scatter[a].get()),
|
||||
legendre_to_tabular_points);
|
||||
|
||||
scatter_format = final_scatter_format;
|
||||
}
|
||||
} else {
|
||||
// We are sticking with the current representation
|
||||
// Initialize the ScattData object with this data
|
||||
for (int a = 0; a < n_ang; a++) {
|
||||
scatter[a]->init(gmin[a], gmax[a], temp_mult[a], input_scatt[a]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void
|
||||
XsData::combine(const std::vector<XsData*>& those_xs,
|
||||
const double_1dvec& scalars)
|
||||
{
|
||||
// Combine the non-scattering data
|
||||
for (int i = 0; i < those_xs.size(); i++) {
|
||||
XsData* that = those_xs[i];
|
||||
if (!equiv(*that)) fatal_error("Cannot combine the XsData objects!");
|
||||
double scalar = scalars[i];
|
||||
for (int a = 0; a < total.size(); a++) {
|
||||
for (int gin = 0; gin < total[a].size(); gin++) {
|
||||
total[a][gin] += scalar * that->total[a][gin];
|
||||
absorption[a][gin] += scalar * that->absorption[a][gin];
|
||||
if (i == 0) {
|
||||
inverse_velocity[a][gin] = that->inverse_velocity[a][gin];
|
||||
}
|
||||
if (that->prompt_nu_fission.size() > 0) {
|
||||
nu_fission[a][gin] += scalar * that->nu_fission[a][gin];
|
||||
prompt_nu_fission[a][gin] +=
|
||||
scalar * that->prompt_nu_fission[a][gin];
|
||||
kappa_fission[a][gin] += scalar * that->kappa_fission[a][gin];
|
||||
fission[a][gin] += scalar * that->fission[a][gin];
|
||||
|
||||
for (int dg = 0; dg < delayed_nu_fission[a][gin].size(); dg++) {
|
||||
delayed_nu_fission[a][gin][dg] +=
|
||||
scalar * that->delayed_nu_fission[a][gin][dg];
|
||||
}
|
||||
|
||||
for (int gout = 0; gout < chi_prompt[a][gin].size(); gout++) {
|
||||
chi_prompt[a][gin][gout] +=
|
||||
scalar * that->chi_prompt[a][gin][gout];
|
||||
|
||||
for (int dg = 0; dg < chi_delayed[a][gin][gout].size(); dg++) {
|
||||
chi_delayed[a][gin][gout][dg] +=
|
||||
scalar * that->chi_delayed[a][gin][gout][dg];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int dg = 0; dg < decay_rate[a].size(); dg++) {
|
||||
decay_rate[a][dg] += scalar * that->decay_rate[a][dg];
|
||||
}
|
||||
|
||||
// Normalize chi
|
||||
if (chi_prompt.size() > 0) {
|
||||
for (int gin = 0; gin < chi_prompt[a].size(); gin++) {
|
||||
double norm = std::accumulate(chi_prompt[a][gin].begin(),
|
||||
chi_prompt[a][gin].end(), 0.);
|
||||
if (norm > 0.) {
|
||||
for (int gout = 0; gout < chi_prompt[a][gin].size(); gout++) {
|
||||
chi_prompt[a][gin][gout] /= norm;
|
||||
}
|
||||
}
|
||||
|
||||
for (int dg = 0; dg < chi_delayed[a][gin][0].size(); dg++) {
|
||||
norm = 0.;
|
||||
for (int gout = 0; gout < chi_delayed[a][gin].size(); gout++) {
|
||||
norm += chi_delayed[a][gin][gout][dg];
|
||||
}
|
||||
if (norm > 0.) {
|
||||
for (int gout = 0; gout < chi_delayed[a][gin].size(); gout++) {
|
||||
chi_delayed[a][gin][gout][dg] /= norm;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allow the ScattData object to combine itself
|
||||
for (int a = 0; a < total.size(); a++) {
|
||||
// Build vector of the scattering objects to incorporate
|
||||
std::vector<ScattData*> those_scatts(those_xs.size());
|
||||
for (int i = 0; i < those_xs.size(); i++) {
|
||||
those_scatts[i] = those_xs[i]->scatter[a].get();
|
||||
}
|
||||
|
||||
// Now combine these guys
|
||||
scatter[a]->combine(those_scatts, scalars);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
bool
|
||||
XsData::equiv(const XsData& that)
|
||||
{
|
||||
return ((absorption.size() == that.absorption.size()) &&
|
||||
(absorption[0].size() == that.absorption[0].size()));
|
||||
}
|
||||
|
||||
} //namespace openmc
|
||||
118
src/xsdata.h
Normal file
118
src/xsdata.h
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
//! \file xsdata.h
|
||||
//! A collection of classes for containing the Multi-Group Cross Section data
|
||||
|
||||
#ifndef XSDATA_H
|
||||
#define XSDATA_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "hdf5_interface.h"
|
||||
#include "scattdata.h"
|
||||
|
||||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// XSDATA contains the temperature-independent cross section data for an MGXS
|
||||
//==============================================================================
|
||||
|
||||
class XsData {
|
||||
|
||||
private:
|
||||
//! \brief Reads scattering data from the HDF5 file
|
||||
void
|
||||
scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, int energy_groups,
|
||||
int scatter_format, int final_scatter_format, int order_data,
|
||||
int max_order, int legendre_to_tabular_points);
|
||||
|
||||
//! \brief Reads fission data from the HDF5 file
|
||||
void
|
||||
fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, int energy_groups,
|
||||
int delayed_groups, bool is_isotropic);
|
||||
|
||||
public:
|
||||
|
||||
// The following quantities have the following dimensions:
|
||||
// [angle][incoming group]
|
||||
double_2dvec total;
|
||||
double_2dvec absorption;
|
||||
double_2dvec nu_fission;
|
||||
double_2dvec prompt_nu_fission;
|
||||
double_2dvec kappa_fission;
|
||||
double_2dvec fission;
|
||||
double_2dvec inverse_velocity;
|
||||
|
||||
// decay_rate has the following dimensions:
|
||||
// [angle][delayed group]
|
||||
double_2dvec decay_rate;
|
||||
// delayed_nu_fission has the following dimensions:
|
||||
// [angle][incoming group][delayed group]
|
||||
double_3dvec delayed_nu_fission;
|
||||
// chi_prompt has the following dimensions:
|
||||
// [angle][incoming group][outgoing group]
|
||||
double_3dvec chi_prompt;
|
||||
// chi_delayed has the following dimensions:
|
||||
// [angle][incoming group][outgoing group][delayed group]
|
||||
double_4dvec chi_delayed;
|
||||
// scatter has the following dimensions: [angle]
|
||||
std::vector<std::shared_ptr<ScattData> > scatter;
|
||||
|
||||
XsData() = default;
|
||||
|
||||
//! \brief Constructs the XsData object metadata.
|
||||
//!
|
||||
//! @param num_groups Number of energy groups.
|
||||
//! @param num_delayed_groups Number of delayed groups.
|
||||
//! @param fissionable Is this a fissionable data set or not.
|
||||
//! @param scatter_format The scattering representation of the file.
|
||||
//! @param n_pol Number of polar angles.
|
||||
//! @param n_azi Number of azimuthal angles.
|
||||
XsData(int num_groups, int num_delayed_groups, bool fissionable,
|
||||
int scatter_format, int n_pol, int n_azi);
|
||||
|
||||
//! \brief Loads the XsData object from the HDF5 file
|
||||
//!
|
||||
//! @param xs_id HDF5 group id for the cross section data.
|
||||
//! @param fissionable Is this a fissionable data set or not.
|
||||
//! @param scatter_format The scattering representation of the file.
|
||||
//! @param final_scatter_format The scattering representation after reading;
|
||||
//! this is different from scatter_format if converting a Legendre to
|
||||
//! a tabular representation.
|
||||
//! @param order_data The dimensionality of the scattering data in the file.
|
||||
//! @param max_order Maximum order requested by the user;
|
||||
//! this is only used for Legendre scattering.
|
||||
//! @param legendre_to_tabular Flag to denote if any Legendre provided
|
||||
//! should be converted to a Tabular representation.
|
||||
//! @param legendre_to_tabular_points If a conversion is requested, this
|
||||
//! provides the number of points to use in the tabular representation.
|
||||
//! @param is_isotropic Is this an isotropic or angular with respect to
|
||||
//! the incoming particle.
|
||||
//! @param n_pol Number of polar angles.
|
||||
//! @param n_azi Number of azimuthal angles.
|
||||
void
|
||||
from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format,
|
||||
int final_scatter_format, int order_data, int max_order,
|
||||
int legendre_to_tabular_points, bool is_isotropic, int n_pol,
|
||||
int n_azi);
|
||||
|
||||
//! \brief Combines the microscopic data to a macroscopic object.
|
||||
//!
|
||||
//! @param micros Microscopic objects to combine.
|
||||
//! @param scalars Scalars to multiply the microscopic data by.
|
||||
void
|
||||
combine(const std::vector<XsData*>& those_xs, const double_1dvec& scalars);
|
||||
|
||||
//! \brief Checks to see if this and that are able to be combined
|
||||
//!
|
||||
//! This comparison is used when building macroscopic cross sections
|
||||
//! from microscopic cross sections.
|
||||
//! @param that The other XsData to compare to this one.
|
||||
//! @return True if they can be combined.
|
||||
bool
|
||||
equiv(const XsData& that);
|
||||
};
|
||||
|
||||
|
||||
} //namespace openmc
|
||||
#endif // XSDATA_H
|
||||
|
|
@ -37,9 +37,10 @@ def sm150():
|
|||
|
||||
@pytest.fixture(scope='module')
|
||||
def gd154():
|
||||
"""Gd154 ENDF data (contains Reich Moore resonance range)"""
|
||||
"""Gd154 ENDF data (contains Reich Moore resonance range and reosnance
|
||||
covariance with LCOMP=1)."""
|
||||
filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-064_Gd_154.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename)
|
||||
return openmc.data.IncidentNeutron.from_endf(filename, covariance=True)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
|
|
@ -77,6 +78,13 @@ def na22():
|
|||
return openmc.data.IncidentNeutron.from_endf(filename)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def na23():
|
||||
"""Na23 ENDF data (contains MLBW resonance covariance with LCOMP=0)."""
|
||||
filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-011_Na_023.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename, covariance=True)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def be9():
|
||||
"""Be9 ENDF data (contains laboratory angle-energy distribution)."""
|
||||
|
|
@ -97,6 +105,28 @@ def am244():
|
|||
return openmc.data.IncidentNeutron.from_njoy(endf_file)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def ti50():
|
||||
"""Ti50 ENDF data (contains Multi-level Breit-Wigner resonance range and
|
||||
resonance covariance with LCOMP=1)."""
|
||||
filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-022_Ti_050.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename, covariance=True)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def cf252():
|
||||
"""Cf252 ENDF data (contains RM resonance covariance with LCOMP=0)."""
|
||||
filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-098_Cf_252.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename, covariance=True)
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def th232():
|
||||
"""Th232 ENDF data (contains RM resonance covariance with LCOMP=2)."""
|
||||
filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-090_Th_232.endf')
|
||||
return openmc.data.IncidentNeutron.from_endf(filename, covariance=True)
|
||||
|
||||
|
||||
def test_attributes(pu239):
|
||||
assert pu239.name == 'Pu239'
|
||||
assert pu239.mass_number == 239
|
||||
|
|
@ -277,6 +307,101 @@ def test_rml(cl35):
|
|||
assert isinstance(group, openmc.data.SpinGroup)
|
||||
|
||||
|
||||
def test_mlbw_cov_lcomp0(cf252):
|
||||
# Testing on first range only
|
||||
cov = cf252.resonance_covariance.ranges[0]
|
||||
res = cf252.resonances.ranges[0]
|
||||
assert cov.parameters['energy'][0] == pytest.approx(-3.5)
|
||||
assert res.parameters['energy'][0] == cov.parameters['energy'][0]
|
||||
assert isinstance(cov, openmc.data.resonance_covariance.MultiLevelBreitWignerCovariance)
|
||||
assert cov.energy_min == pytest.approx(1e-5)
|
||||
assert cov.energy_max == pytest.approx(1000.)
|
||||
assert cov.covariance[0,0] == pytest.approx(1.225e-05)
|
||||
|
||||
subset = cov.subset('energy', [0, 100])
|
||||
assert not subset.parameters.empty
|
||||
assert (subset.file2res.parameters['energy'] < 100).all()
|
||||
samples = cov.sample(1)
|
||||
xs = samples[0].reconstruct([10., 100., 1000.])
|
||||
assert sorted(xs.keys()) == [2, 18, 102]
|
||||
|
||||
|
||||
def test_mlbw_cov_lcomp1(ti50):
|
||||
# Testing on first range only
|
||||
cov = ti50.resonance_covariance.ranges[0]
|
||||
res = ti50.resonances.ranges[0]
|
||||
assert cov.parameters['energy'][0] == pytest.approx(-21020.)
|
||||
assert res.parameters['energy'][0] == cov.parameters['energy'][0]
|
||||
assert isinstance(cov, openmc.data.resonance_covariance.MultiLevelBreitWignerCovariance)
|
||||
assert cov.energy_min == pytest.approx(1e-5)
|
||||
assert cov.energy_max == pytest.approx(587000.)
|
||||
assert cov.covariance[0,0] == pytest.approx(1.410177e5)
|
||||
|
||||
subset = cov.subset('L', [1, 1])
|
||||
assert not subset.parameters.empty
|
||||
assert (subset.file2res.parameters['L'] == 1).all()
|
||||
samples = cov.sample(1)
|
||||
xs = samples[0].reconstruct([10., 100., 1000.])
|
||||
assert sorted(xs.keys()) == [2, 18, 102]
|
||||
|
||||
|
||||
def test_mlbw_cov_lcomp2(na23):
|
||||
# Testing on first range only
|
||||
cov = na23.resonance_covariance.ranges[0]
|
||||
res = na23.resonances.ranges[0]
|
||||
assert cov.parameters['energy'][0] == pytest.approx(2810.)
|
||||
assert res.parameters['energy'][0] == cov.parameters['energy'][0]
|
||||
assert isinstance(cov, openmc.data.resonance_covariance.MultiLevelBreitWignerCovariance)
|
||||
assert cov.energy_min == pytest.approx(600)
|
||||
assert cov.energy_max == pytest.approx(500000.)
|
||||
assert cov.covariance[0,0] == pytest.approx(16.1064163584)
|
||||
|
||||
subset = cov.subset('L', [1, 1])
|
||||
assert not subset.parameters.empty
|
||||
assert (subset.file2res.parameters['L'] == 1).all()
|
||||
samples = cov.sample(1)
|
||||
xs = samples[0].reconstruct([10., 100., 1000.])
|
||||
assert sorted(xs.keys()) == [2, 18, 102]
|
||||
|
||||
|
||||
def test_rmcov_lcomp1(gd154):
|
||||
# Testing on first range only
|
||||
cov = gd154.resonance_covariance.ranges[0]
|
||||
res = gd154.resonances.ranges[0]
|
||||
assert cov.parameters['energy'][0] == pytest.approx(-2.200001)
|
||||
assert res.parameters['energy'][0] == cov.parameters['energy'][0]
|
||||
assert isinstance(cov, openmc.data.resonance_covariance.ReichMooreCovariance)
|
||||
assert cov.energy_min == pytest.approx(1e-5)
|
||||
assert cov.energy_max == pytest.approx(2760.)
|
||||
assert cov.covariance[0,0] == pytest.approx(0.8895997)
|
||||
|
||||
subset = cov.subset('energy', [0, 100])
|
||||
assert not subset.parameters.empty
|
||||
assert (subset.file2res.parameters['energy'] < 100).all()
|
||||
samples = cov.sample(1)
|
||||
xs = samples[0].reconstruct([10., 100., 1000.])
|
||||
assert sorted(xs.keys()) == [2, 18, 102]
|
||||
|
||||
|
||||
def test_rmcov_lcomp2(th232):
|
||||
# Testing on first range only
|
||||
cov = th232.resonance_covariance.ranges[0]
|
||||
res = th232.resonances.ranges[0]
|
||||
assert cov.parameters['energy'][0] == pytest.approx(-2000)
|
||||
assert res.parameters['energy'][0] == cov.parameters['energy'][0]
|
||||
assert isinstance(cov, openmc.data.resonance_covariance.ReichMooreCovariance)
|
||||
assert cov.energy_min == pytest.approx(1e-5)
|
||||
assert cov.energy_max == pytest.approx(4000.)
|
||||
assert cov.covariance[0,0] == pytest.approx(246.6043092496)
|
||||
|
||||
subset = cov.subset('energy', [0, 100])
|
||||
assert not subset.parameters.empty
|
||||
assert (subset.file2res.parameters['energy'] < 100).all()
|
||||
samples = cov.sample(1)
|
||||
xs = samples[0].reconstruct([10., 100., 1000.])
|
||||
assert sorted(xs.keys()) == [2, 18, 102]
|
||||
|
||||
|
||||
def test_madland_nix(am241):
|
||||
fission = am241.reactions[18]
|
||||
prompt_neutron = fission.products[0]
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ set -ex
|
|||
# Install NJOY 2016
|
||||
./tools/ci/travis-install-njoy.sh
|
||||
|
||||
# Upgrade pip before doing anything else
|
||||
pip install --upgrade pip
|
||||
|
||||
# Running OpenMC's setup.py requires numpy/cython already. NumPy float
|
||||
# formatting changed in version 1.14, so stick with a lower version until we can
|
||||
# handle it in our test suite
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue