diff --git a/CMakeLists.txt b/CMakeLists.txt index fd122a14c..36501c918 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,12 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/include) +# Set module path +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) + +# Make sure Fortran module directory is included when building +include_directories(${CMAKE_BINARY_DIR}/include) + #=============================================================================== # Architecture specific definitions #=============================================================================== @@ -23,37 +29,23 @@ option(openmp "Enable shared-memory parallelism with OpenMP" OFF) option(profile "Compile with profiling flags" OFF) option(debug "Compile with debug flags" OFF) option(optimize "Turn on all compiler optimization flags" OFF) -option(verbose "Create verbose Makefiles" OFF) option(coverage "Compile with coverage analysis flags" OFF) option(mpif08 "Use Fortran 2008 MPI interface" OFF) -if (verbose) - set(CMAKE_VERBOSE_MAKEFILE on) -endif() # Maximum number of nested coordinates levels set(maxcoord 10 CACHE STRING "Maximum number of nested coordinate levels") add_definitions(-DMAX_COORD=${maxcoord}) #=============================================================================== -# MPI for distributed-memory parallelism / HDF5 for binary output +# MPI for distributed-memory parallelism #=============================================================================== set(MPI_ENABLED FALSE) -set(HDF5_ENABLED FALSE) if($ENV{FC} MATCHES "mpi[^/]*$") message("-- Detected MPI wrapper: $ENV{FC}") add_definitions(-DMPI) set(MPI_ENABLED TRUE) -elseif($ENV{FC} MATCHES "h5fc$") - message("-- Detected HDF5 wrapper: $ENV{FC}") - add_definitions(-DHDF5) - set(HDF5_ENABLED TRUE) -elseif($ENV{FC} MATCHES "h5pfc$") - message("-- Detected parallel HDF5 wrapper: $ENV{FC}") - add_definitions(-DMPI -DHDF5) - set(MPI_ENABLED TRUE) - set(HDF5_ENABLED TRUE) endif() # Check for Fortran 2008 MPI interface @@ -62,11 +54,52 @@ if(MPI_ENABLED AND mpif08) add_definitions(-DMPIF08) endif() +#=============================================================================== +# HDF5 for binary output +#=============================================================================== + +# Unfortunately FindHDF5.cmake will always prefer a serial HDF5 installation +# over a parallel installation if both appear on the user's PATH. To get around +# this, we check for the environment variable HDF5_ROOT and if it exists, use it +# to check whether its a parallel version. + +if(DEFINED ENV{HDF5_ROOT} AND EXISTS $ENV{HDF5_ROOT}/bin/h5pcc) + set(HDF5_PREFER_PARALLEL TRUE) +else() + set(HDF5_PREFER_PARALLEL FALSE) +endif() + +find_package(HDF5 COMPONENTS Fortran_HL) +if(NOT HDF5_FOUND) + message(FATAL_ERROR "Could not find HDF5") +endif() +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() + #=============================================================================== # Set compile/link flags based on which compiler is being used #=============================================================================== -if(CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") +# 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(CMAKE_Fortran_COMPILER_ID STREQUAL GNU) # Make sure version is sufficient execute_process(COMMAND ${CMAKE_Fortran_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) @@ -75,88 +108,93 @@ if(CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") endif() # GNU Fortran compiler options - set(f90flags "-cpp -std=f2008 -fbacktrace") + list(APPEND f90flags -cpp -std=f2008 -fbacktrace) if(debug) - set(f90flags "-g -Wall -pedantic -fbounds-check -ffpe-trap=invalid,overflow,underflow ${f90flags}") - set(ldflags "-g") + if(NOT (GCC_VERSION VERSION_LESS 4.7)) + list(APPEND f90flags -Wall) + endif() + list(APPEND f90flags -g -pedantic -fbounds-check + -ffpe-trap=invalid,overflow,underflow) + list(APPEND ldflags -g) endif() if(profile) - set(f90flags "-pg ${f90flags}") - set(ldflags "-pg ${ldflags}") + list(APPEND f90flags -pg) + list(APPEND ldflags -pg) endif() if(optimize) - set(f90flags "-O3 ${f90flags}") + list(APPEND f90flags -O3) endif() if(openmp) - set(f90flags "-fopenmp ${f90flags}") - set(ldflags "-fopenmp ${ldflags}") + list(APPEND f90flags -fopenmp) + list(APPEND ldflags -fopenmp) endif() if(coverage) - set(f90flags "-coverage ${f90flags}") - set(ldflags "-coverage ${ldflags}") + list(APPEND f90flags -coverage) + list(APPEND ldflags -coverage) endif() -elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel") +elseif(CMAKE_Fortran_COMPILER_ID STREQUAL Intel) # Intel Fortran compiler options - set(f90flags "-fpp -std08 -assume byterecl -traceback") + list(APPEND f90flags -fpp -std08 -assume byterecl -traceback) if(debug) - set(f90flags "-g -warn -ftrapuv -fp-stack-check -check all -fpe0 ${f90flags}") - set(ldflags "-g") + list(APPEND f90flags -g -warn -ftrapuv -fp-stack-check + "-check all" -fpe0) + list(APPEND ldflags -g) endif() if(profile) - set(f90flags "-pg ${f90flags}") - set(ldflags "-pg ${ldflags}") + list(APPEND f90flags -pg) + list(APPEND ldflags -pg) endif() if(optimize) - set(f90flags "-O3 ${f90flags}") + list(APPEND f90flags -O3) endif() if(openmp) - set(f90flags "-openmp ${f90flags}") - set(ldflags "-openmp ${ldflags}") + list(APPEND f90flags -openmp) + list(APPEND ldflags -openmp) endif() -elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "PGI") +elseif(CMAKE_Fortran_COMPILER_ID STREQUAL PGI) # PGI Fortran compiler options - set(f90flags "-Mpreprocess -Minform=inform -traceback") + list(APPEND f90flags -Mpreprocess -Minform=inform -traceback) add_definitions(-DNO_F2008) if(debug) - set(f90flags "-g -Mbounds -Mchkptr -Mchkstk ${f90flags}") - set(ldflags "-g") + list(APPEND f90flags -g -Mbounds -Mchkptr -Mchkstk) + list(APPEND ldflags -g) endif() if(profile) - set(f90flags "-pg ${f90flags}") - set(ldflags "-pg ${ldflags}") + list(APPEND f90flags -pg) + list(APPEND ldflags -pg) endif() if(optimize) - set(f90flags "-fast -Mipa ${f90flags}") + list(APPEND f90flags -fast -Mipa) endif() -elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "XL") +elseif(CMAKE_Fortran_COMPILER_ID STREQUAL XL) # IBM XL compiler options - set(f90flags "-O2") + list(APPEND f90flags -O2) add_definitions(-DNO_F2008) if(debug) - set(f90flags "-g -C -qflag=i:i -u") - set(ldflags "-g") + list(APPEND f90flags -g -C -qflag=i:i -u) + list(APPEND ldflags -g) endif() if(profile) - set(f90flags "-p ${f90flags}") - set(ldflags "-p ${ldflags}") + list(APPEND f90flags -p) + list(APPEND ldflags -p) endif() if(optimize) - set(f90flags "-O3 ${f90flags}") + list(APPEND f90flags -O3) endif() if(openmp) - set(f90flags "-qsmp=omp ${f90flags}") - set(ldflags "-qsmp=omp ${ldflags}") + list(APPEND f90flags -qsmp=omp) + list(APPEND ldflags -qsmp=omp) endif() -elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Cray") +elseif(CMAKE_Fortran_COMPILER_ID STREQUAL Cray) # Cray Fortran compiler options - set(f90flags "-e Z -m 0") + list(APPEND f90flags -e Z -m 0) if(debug) - set(f90flags "-g -R abcnsp -O0 ${f90flags}") - set(ldflags "-g") + list(APPEND f90flags -g -R abcnsp -O0) + list(APPEND ldflags -g) endif() endif() @@ -204,10 +242,34 @@ add_subdirectory(src/xml/fox) set(program "openmc") file(GLOB source src/*.F90 src/xml/openmc_fox.F90) add_executable(${program} ${source}) -target_link_libraries(${program} ${libraries} fox_dom) -set_target_properties(${program} PROPERTIES - COMPILE_FLAGS "${f90flags}" - LINK_FLAGS "${ldflags}") + +# target_include_directories was added in CMake 2.8.11 and is the recommended +# way to set include directories. For lesser versions, we revert to set_property +if(CMAKE_VERSION VERSION_LESS 2.8.11) + include_directories(${HDF5_INCLUDE_DIRS}) +else() + target_include_directories(${program} PUBLIC ${HDF5_INCLUDE_DIRS}) +endif() + +# target_compile_options was added in CMake 2.8.12 and is the recommended way to +# set compile flags. Note that this sets the COMPILE_OPTIONS property (also +# available only in 2.8.12+) rather than the COMPILE_FLAGS property, which is +# deprecated. The former can handle lists whereas the latter cannot. +if(CMAKE_VERSION VERSION_LESS 4.8.12) + string(REPLACE ";" " " f90flags "${f90flags}") + set_property(TARGET ${program} PROPERTY COMPILE_FLAGS "${f90flags}") +else() + target_compile_options(${program} PUBLIC ${f90flags}) +endif() + +# Add HDF5 library directories to link line with -L +foreach(LIBDIR ${HDF5_LIBRARY_DIRS}) + list(APPEND ldflags "-L${LIBDIR}") +endforeach() + +# 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(${program} ${ldflags} ${HDF5_LIBRARIES} fox_dom) #=============================================================================== # Install executable, scripts, manpage, license @@ -306,38 +368,18 @@ foreach(test ${TESTS}) # If a restart test is encounted, need to run with -r and restart file(s) elseif(${test} MATCHES "restart") - # Set restart file names - if (${HDF5_ENABLED}) - - # Handle restart tests separately - if(${test} MATCHES "test_statepoint_restart") - set(RESTART_FILE statepoint.07.h5) - elseif(${test} MATCHES "test_sourcepoint_restart") - set(RESTART_FILE statepoint.07.h5 source.07.h5) - elseif(${test} MATCHES "test_particle_restart_eigval") - set(RESTART_FILE particle_9_555.h5) - elseif(${test} MATCHES "test_particle_restart_fixed") - set(RESTART_FILE particle_7_928.h5) - else(${test} MATCHES "test_statepoint_restart") - message(FATAL_ERROR "Restart test ${test} not recognized") - endif(${test} MATCHES "test_statepoint_restart") - - else(${HDF5_ENABLED}) - - # Handle restart tests separately - if(${test} MATCHES "test_statepoint_restart") - set(RESTART_FILE statepoint.07.binary) - elseif(${test} MATCHES "test_sourcepoint_restart") - set(RESTART_FILE statepoint.07.binary source.07.binary) - elseif(${test} MATCHES "test_particle_restart_eigval") - set(RESTART_FILE particle_9_555.binary) - elseif(${test} MATCHES "test_particle_restart_fixed") - set(RESTART_FILE particle_7_6144.binary) - else(${test} MATCHES "test_statepoint_restart") - message(FATAL_ERROR "Restart test ${test} not recognized") - endif(${test} MATCHES "test_statepoint_restart") - - endif(${HDF5_ENABLED}) + # Handle restart tests separately + if(${test} MATCHES "test_statepoint_restart") + set(RESTART_FILE statepoint.07.h5) + elseif(${test} MATCHES "test_sourcepoint_restart") + set(RESTART_FILE statepoint.07.h5 source.07.h5) + elseif(${test} MATCHES "test_particle_restart_eigval") + set(RESTART_FILE particle_9_555.h5) + elseif(${test} MATCHES "test_particle_restart_fixed") + set(RESTART_FILE particle_7_928.h5) + else(${test} MATCHES "test_statepoint_restart") + message(FATAL_ERROR "Restart test ${test} not recognized") + endif(${test} MATCHES "test_statepoint_restart") # Perform serial valgrind and coverage test add_test(NAME ${TEST_NAME} diff --git a/cmake/Modules/FindHDF5.cmake b/cmake/Modules/FindHDF5.cmake new file mode 100644 index 000000000..7492ea750 --- /dev/null +++ b/cmake/Modules/FindHDF5.cmake @@ -0,0 +1,399 @@ +#.rst: +# FindHDF5 +# -------- +# +# Find HDF5, a library for reading and writing self describing array data. +# +# +# +# This module invokes the HDF5 wrapper compiler that should be installed +# alongside HDF5. Depending upon the HDF5 Configuration, the wrapper +# compiler is called either h5cc or h5pcc. If this succeeds, the module +# will then call the compiler with the -show argument to see what flags +# are used when compiling an HDF5 client application. +# +# The module will optionally accept the COMPONENTS argument. If no +# COMPONENTS are specified, then the find module will default to finding +# only the HDF5 C library. If one or more COMPONENTS are specified, the +# module will attempt to find the language bindings for the specified +# components. The only valid components are C, CXX, Fortran, HL, and +# Fortran_HL. If the COMPONENTS argument is not given, the module will +# attempt to find only the C bindings. +# +# On UNIX systems, this module will read the variable +# HDF5_USE_STATIC_LIBRARIES to determine whether or not to prefer a +# static link to a dynamic link for HDF5 and all of it's dependencies. +# To use this feature, make sure that the HDF5_USE_STATIC_LIBRARIES +# variable is set before the call to find_package. +# +# To provide the module with a hint about where to find your HDF5 +# installation, you can set the environment variable HDF5_ROOT. The +# Find module will then look in this path when searching for HDF5 +# executables, paths, and libraries. +# +# In addition to finding the includes and libraries required to compile +# an HDF5 client application, this module also makes an effort to find +# tools that come with the HDF5 distribution that may be useful for +# regression testing. +# +# This module will define the following variables: +# +# :: +# +# HDF5_INCLUDE_DIRS - Location of the hdf5 includes +# HDF5_INCLUDE_DIR - Location of the hdf5 includes (deprecated) +# HDF5_DEFINITIONS - Required compiler definitions for HDF5 +# HDF5_C_LIBRARIES - Required libraries for the HDF5 C bindings. +# HDF5_CXX_LIBRARIES - Required libraries for the HDF5 C++ bindings +# HDF5_Fortran_LIBRARIES - Required libraries for the HDF5 Fortran bindings +# HDF5_HL_LIBRARIES - Required libraries for the HDF5 high level API +# HDF5_Fortran_HL_LIBRARIES - Required libraries for the high level Fortran +# bindings. +# HDF5_LIBRARIES - Required libraries for all requested bindings +# HDF5_FOUND - true if HDF5 was found on the system +# HDF5_VERSION - HDF5 version in format Major.Minor.Release +# HDF5_LIBRARY_DIRS - the full set of library directories +# HDF5_IS_PARALLEL - Whether or not HDF5 was found with parallel IO support +# HDF5_C_COMPILER_EXECUTABLE - the path to the HDF5 C wrapper compiler +# HDF5_CXX_COMPILER_EXECUTABLE - the path to the HDF5 C++ wrapper compiler +# HDF5_Fortran_COMPILER_EXECUTABLE - the path to the HDF5 Fortran wrapper compiler +# HDF5_DIFF_EXECUTABLE - the path to the HDF5 dataset comparison tool + +#============================================================================= +# Copyright 2015 Axel Huebl, Helmholtz-Zentrum Dresden - Rossendorf +# Copyright 2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# This module is maintained by Will Dicharry . + +include(SelectLibraryConfigurations) +include(FindPackageHandleStandardArgs) + +# List of the valid HDF5 components +set( HDF5_VALID_COMPONENTS + C + CXX + Fortran + HL + Fortran_HL +) + +# Validate the list of find components. +if( NOT HDF5_FIND_COMPONENTS ) + set( HDF5_LANGUAGE_BINDINGS "C" ) +else() + # add the extra specified components, ensuring that they are valid. + foreach( component ${HDF5_FIND_COMPONENTS} ) + list( FIND HDF5_VALID_COMPONENTS ${component} component_location ) + if( ${component_location} EQUAL -1 ) + message( FATAL_ERROR + "\"${component}\" is not a valid HDF5 component." ) + else() + list( APPEND HDF5_LANGUAGE_BINDINGS ${component} ) + endif() + endforeach() +endif() + +# Determine whether to search for serial or parallel executable first +if(HDF5_PREFER_PARALLEL) + set(HDF5_C_COMPILER_NAMES h5pcc h5cc) + set(HDF5_CXX_COMPILER_NAMES h5pc++ h5c++) + set(HDF5_Fortran_COMPILER_NAMES h5pfc h5fc) +else() + set(HDF5_C_COMPILER_NAMES h5cc h5pcc) + set(HDF5_CXX_COMPILER_NAMES h5c++ h5pc++) + set(HDF5_Fortran_COMPILER_NAMES h5fc h5pfc) +endif() + +# try to find the HDF5 wrapper compilers +find_program( HDF5_C_COMPILER_EXECUTABLE + NAMES ${HDF5_C_COMPILER_NAMES} + HINTS ENV HDF5_ROOT + PATH_SUFFIXES bin Bin + DOC "HDF5 Wrapper compiler. Used only to detect HDF5 compile flags." ) +mark_as_advanced( HDF5_C_COMPILER_EXECUTABLE ) + +find_program( HDF5_CXX_COMPILER_EXECUTABLE + NAMES ${HDF5_CXX_COMPILER_NAMES} + HINTS ENV HDF5_ROOT + PATH_SUFFIXES bin Bin + DOC "HDF5 C++ Wrapper compiler. Used only to detect HDF5 compile flags." ) +mark_as_advanced( HDF5_CXX_COMPILER_EXECUTABLE ) + +find_program( HDF5_Fortran_COMPILER_EXECUTABLE + NAMES ${HDF5_Fortran_COMPILER_NAMES} + HINTS ENV HDF5_ROOT + PATH_SUFFIXES bin Bin + DOC "HDF5 Fortran Wrapper compiler. Used only to detect HDF5 compile flags." ) +mark_as_advanced( HDF5_Fortran_COMPILER_EXECUTABLE ) + +unset(HDF5_C_COMPILER_NAMES) +unset(HDF5_CXX_COMPILER_NAMES) +unset(HDF5_Fortran_COMPILER_NAMES) + +find_program( HDF5_DIFF_EXECUTABLE + NAMES h5diff + HINTS ENV HDF5_ROOT + PATH_SUFFIXES bin Bin + DOC "HDF5 file differencing tool." ) +mark_as_advanced( HDF5_DIFF_EXECUTABLE ) + +# Invoke the HDF5 wrapper compiler. The compiler return value is stored to the +# return_value argument, the text output is stored to the output variable. +macro( _HDF5_invoke_compiler language output return_value ) + if( HDF5_${language}_COMPILER_EXECUTABLE ) + exec_program( ${HDF5_${language}_COMPILER_EXECUTABLE} + ARGS -show + OUTPUT_VARIABLE ${output} + RETURN_VALUE ${return_value} + ) + if( ${${return_value}} EQUAL 0 ) + # do nothing + else() + message( STATUS + "Unable to determine HDF5 ${language} flags from HDF5 wrapper." ) + endif() + endif() +endmacro() + +# Parse a compile line for definitions, includes, library paths, and libraries. +macro( _HDF5_parse_compile_line + compile_line_var + include_paths + definitions + library_paths + libraries ) + + # Match the include paths + string( REGEX MATCHALL "-I([^\" ]+)" include_path_flags + "${${compile_line_var}}" + ) + foreach( IPATH ${include_path_flags} ) + string( REGEX REPLACE "^-I" "" IPATH ${IPATH} ) + string( REPLACE "//" "/" IPATH ${IPATH} ) + list( APPEND ${include_paths} ${IPATH} ) + endforeach() + + # Match the definitions + string( REGEX MATCHALL "-D[^ ]*" definition_flags "${${compile_line_var}}" ) + foreach( DEF ${definition_flags} ) + list( APPEND ${definitions} ${DEF} ) + endforeach() + + # Match the library paths + string( REGEX MATCHALL "-L([^\" ]+|\"[^\"]+\")" library_path_flags + "${${compile_line_var}}" + ) + + foreach( LPATH ${library_path_flags} ) + string( REGEX REPLACE "^-L" "" LPATH ${LPATH} ) + string( REPLACE "//" "/" LPATH ${LPATH} ) + list( APPEND ${library_paths} ${LPATH} ) + endforeach() + + # now search for the library names specified in the compile line (match -l...) + # match only -l's preceded by a space or comma + # this is to exclude directory names like xxx-linux/ + string( REGEX MATCHALL "[, ]-l([^\", ]+)" library_name_flags + "${${compile_line_var}}" ) + # strip the -l from all of the library flags and add to the search list + foreach( LIB ${library_name_flags} ) + string( REGEX REPLACE "^[, ]-l" "" LIB ${LIB} ) + list( APPEND ${libraries} ${LIB} ) + endforeach() +endmacro() + +# Try to find HDF5 using an installed hdf5-config.cmake +if( NOT HDF5_FOUND ) + find_package( HDF5 QUIET NO_MODULE ) + if( HDF5_FOUND ) + set( HDF5_INCLUDE_DIRS ${HDF5_INCLUDE_DIR} ) + set( HDF5_LIBRARIES ) + set( HDF5_C_TARGET hdf5 ) + set( HDF5_CXX_TARGET hdf5_cpp ) + set( HDF5_HL_TARGET hdf5_hl ) + set( HDF5_Fortran_TARGET hdf5_fortran ) + set( HDF5_Fortran_HL_TARGET hdf5_hl_fortran ) + foreach( _component ${HDF5_LANGUAGE_BINDINGS} ) + list( FIND HDF5_VALID_COMPONENTS ${_component} _component_location ) + get_target_property( _comp_location ${HDF5_${_component}_TARGET} LOCATION ) + if( _comp_location ) + set( HDF5_${_component}_LIBRARY ${_comp_location} CACHE PATH + "HDF5 ${_component} library" ) + mark_as_advanced( HDF5_${_component}_LIBRARY ) + list( APPEND HDF5_LIBRARIES ${HDF5_${_component}_LIBRARY} ) + endif() + endforeach() + endif() +endif() + +if( NOT HDF5_FOUND ) + _HDF5_invoke_compiler( C HDF5_C_COMPILE_LINE HDF5_C_RETURN_VALUE ) + _HDF5_invoke_compiler( CXX HDF5_CXX_COMPILE_LINE HDF5_CXX_RETURN_VALUE ) + _HDF5_invoke_compiler( Fortran HDF5_Fortran_COMPILE_LINE HDF5_Fortran_RETURN_VALUE ) + set(HDF5_HL_COMPILE_LINE ${HDF5_C_COMPILE_LINE}) + set(HDF5_Fortran_HL_COMPILE_LINE ${HDF5_Fortran_COMPILE_LINE}) + + # seed the initial lists of libraries to find with items we know we need + set( HDF5_C_LIBRARY_NAMES_INIT hdf5 ) + set( HDF5_HL_LIBRARY_NAMES_INIT hdf5_hl ${HDF5_C_LIBRARY_NAMES_INIT} ) + set( HDF5_CXX_LIBRARY_NAMES_INIT hdf5_cpp ${HDF5_C_LIBRARY_NAMES_INIT} ) + set( HDF5_Fortran_LIBRARY_NAMES_INIT hdf5_fortran + ${HDF5_C_LIBRARY_NAMES_INIT} ) + set( HDF5_Fortran_HL_LIBRARY_NAMES_INIT hdf5hl_fortran hdf5_hl + ${HDF5_Fortran_LIBRARY_NAMES_INIT} ) + + foreach( LANGUAGE ${HDF5_LANGUAGE_BINDINGS} ) + if( HDF5_${LANGUAGE}_COMPILE_LINE ) + _HDF5_parse_compile_line( HDF5_${LANGUAGE}_COMPILE_LINE + HDF5_${LANGUAGE}_INCLUDE_FLAGS + HDF5_${LANGUAGE}_DEFINITIONS + HDF5_${LANGUAGE}_LIBRARY_DIRS + HDF5_${LANGUAGE}_LIBRARY_NAMES + ) + + # take a guess that the includes may be in the 'include' sibling + # directory of a library directory. + foreach( dir ${HDF5_${LANGUAGE}_LIBRARY_DIRS} ) + list( APPEND HDF5_${LANGUAGE}_INCLUDE_FLAGS ${dir}/../include ) + endforeach() + endif() + + # set the definitions for the language bindings. + list( APPEND HDF5_DEFINITIONS ${HDF5_${LANGUAGE}_DEFINITIONS} ) + + # find the HDF5 include directories + if(${LANGUAGE} MATCHES "Fortran") + set(HDF5_INCLUDE_FILENAME hdf5.mod) + else() + set(HDF5_INCLUDE_FILENAME hdf5.h) + endif() + + find_path( HDF5_${LANGUAGE}_INCLUDE_DIR ${HDF5_INCLUDE_FILENAME} + HINTS + ${HDF5_${LANGUAGE}_INCLUDE_FLAGS} + ENV + HDF5_ROOT + PATHS + $ENV{HOME}/.local/include + PATH_SUFFIXES + include + Include + ) + mark_as_advanced( HDF5_${LANGUAGE}_INCLUDE_DIR ) + list( APPEND HDF5_INCLUDE_DIRS ${HDF5_${LANGUAGE}_INCLUDE_DIR} ) + + # find the HDF5 libraries + foreach( LIB ${HDF5_${LANGUAGE}_LIBRARY_NAMES_INIT} ) + if( UNIX AND HDF5_USE_STATIC_LIBRARIES ) + # According to bug 1643 on the CMake bug tracker, this is the + # preferred method for searching for a static library. + # See http://www.cmake.org/Bug/view.php?id=1643. We search + # first for the full static library name, but fall back to a + # generic search on the name if the static search fails. + set( THIS_LIBRARY_SEARCH_DEBUG lib${LIB}d.a ${LIB}d ) + set( THIS_LIBRARY_SEARCH_RELEASE lib${LIB}.a ${LIB} ) + else() + set( THIS_LIBRARY_SEARCH_DEBUG ${LIB}d ) + set( THIS_LIBRARY_SEARCH_RELEASE ${LIB} ) + endif() + find_library( HDF5_${LIB}_LIBRARY_DEBUG + NAMES ${THIS_LIBRARY_SEARCH_DEBUG} + HINTS ${HDF5_${LANGUAGE}_LIBRARY_DIRS} + ENV HDF5_ROOT + PATH_SUFFIXES lib Lib ) + find_library( HDF5_${LIB}_LIBRARY_RELEASE + NAMES ${THIS_LIBRARY_SEARCH_RELEASE} + HINTS ${HDF5_${LANGUAGE}_LIBRARY_DIRS} + ENV HDF5_ROOT + PATH_SUFFIXES lib Lib ) + select_library_configurations( HDF5_${LIB} ) + list(APPEND HDF5_${LANGUAGE}_LIBRARIES ${HDF5_${LIB}_LIBRARY}) + endforeach() + list( APPEND HDF5_LIBRARY_DIRS ${HDF5_${LANGUAGE}_LIBRARY_DIRS} ) + + # When the wrapper lists a library with -l, e.g. -lz, simply use it as + # is. If find_library is called for these libraries, you end up with + # local libraries that will not be suitable when cross-compiling for the + # Intel Xeon Phi. + foreach(LIBNAME ${HDF5_${LANGUAGE}_LIBRARY_NAMES}) + list(APPEND HDF5_${LANGUAGE}_LIBRARIES "-l${LIBNAME}") + endforeach() + + # Append the libraries for this language binding to the list of all + # required libraries. + list(APPEND HDF5_LIBRARIES ${HDF5_${LANGUAGE}_LIBRARIES}) + endforeach() + + # We may have picked up some duplicates in various lists during the above + # process for the language bindings (both the C and C++ bindings depend on + # libz for example). Remove the duplicates. It appears that the default + # CMake behavior is to remove duplicates from the end of a list. However, + # for link lines, this is incorrect since unresolved symbols are searched + # for down the link line. Therefore, we reverse the list, remove the + # duplicates, and then reverse it again to get the duplicates removed from + # the beginning. + macro( _remove_duplicates_from_beginning _list_name ) + list( REVERSE ${_list_name} ) + list( REMOVE_DUPLICATES ${_list_name} ) + list( REVERSE ${_list_name} ) + endmacro() + + if( HDF5_INCLUDE_DIRS ) + _remove_duplicates_from_beginning( HDF5_INCLUDE_DIRS ) + endif() + if( HDF5_LIBRARY_DIRS ) + _remove_duplicates_from_beginning( HDF5_LIBRARY_DIRS ) + endif() + + # If the HDF5 include directory was found, open H5pubconf.h to determine if + # HDF5 was compiled with parallel IO support + set( HDF5_IS_PARALLEL FALSE ) + set( HDF5_VERSION "" ) + foreach( _dir IN LISTS HDF5_INCLUDE_DIRS ) + foreach(_hdr "${_dir}/H5pubconf.h" "${_dir}/H5pubconf-64.h" "${_dir}/H5pubconf-32.h") + if( EXISTS "${_hdr}" ) + file( STRINGS "${_hdr}" + HDF5_HAVE_PARALLEL_DEFINE + REGEX "HAVE_PARALLEL 1" ) + if( HDF5_HAVE_PARALLEL_DEFINE ) + set( HDF5_IS_PARALLEL TRUE ) + endif() + unset(HDF5_HAVE_PARALLEL_DEFINE) + + file( STRINGS "${_hdr}" + HDF5_VERSION_DEFINE + REGEX "^[ \t]*#[ \t]*define[ \t]+H5_VERSION[ \t]+" ) + if( "${HDF5_VERSION_DEFINE}" MATCHES + "H5_VERSION[ \t]+\"([0-9]+\\.[0-9]+\\.[0-9]+).*\"" ) + set( HDF5_VERSION "${CMAKE_MATCH_1}" ) + endif() + unset(HDF5_VERSION_DEFINE) + endif() + endforeach() + endforeach() + set( HDF5_IS_PARALLEL ${HDF5_IS_PARALLEL} CACHE BOOL + "HDF5 library compiled with parallel IO support" ) + mark_as_advanced( HDF5_IS_PARALLEL ) + + # For backwards compatibility we set HDF5_INCLUDE_DIR to the value of + # HDF5_INCLUDE_DIRS + if( HDF5_INCLUDE_DIRS ) + set( HDF5_INCLUDE_DIR "${HDF5_INCLUDE_DIRS}" ) + endif() + +endif() + +find_package_handle_standard_args( HDF5 + REQUIRED_VARS HDF5_LIBRARIES HDF5_INCLUDE_DIRS + VERSION_VAR HDF5_VERSION +) diff --git a/docs/source/devguide/index.rst b/docs/source/devguide/index.rst index 03838363c..37b17bc0f 100644 --- a/docs/source/devguide/index.rst +++ b/docs/source/devguide/index.rst @@ -16,6 +16,4 @@ as debugging. styleguide workflow xml-parsing - statepoint - voxel docbuild diff --git a/docs/source/devguide/statepoint.rst b/docs/source/devguide/statepoint.rst deleted file mode 100644 index 4a1db9478..000000000 --- a/docs/source/devguide/statepoint.rst +++ /dev/null @@ -1,291 +0,0 @@ -.. _devguide_statepoint: - -====================================== -State Point Binary File Specifications -====================================== - -The current revision of the statepoint binary file is 13. - -**integer(4) FILETYPE_STATEPOINT** - - Flags whether this file is a statepoint file or a particle restart file. - -**integer(4) REVISION_STATEPOINT** - - Revision of the binary state point file. Any time a change is made in the - format of the state-point file, this integer is incremented. - -**integer(4) VERSION_MAJOR** - - Major version number for OpenMC - -**integer(4) VERSION_MINOR** - - Minor version number for OpenMC - -**integer(4) VERSION_RELEASE** - - Release version number for OpenMC - -**character(19) time_stamp** - - Date and time the state point was written. - -**character(255) path** - - Absolute path to directory containing input files. - -**integer(8) seed** - - Pseudo-random number generator seed. - -**integer(4) run_mode** - - run mode used. The modes are described in constants.F90. - -**integer(8) n_particles** - - Number of particles used per generation. - -**integer(4) current_batch** - - The number of batches already simulated. - -if (run_mode == MODE_EIGENVALUE) - - **integer(4) n_inactive** - - Number of inactive batches - - **integer(4) gen_per_batch** - - Number of generations per batch for criticality calculations - - *do i = 1, current_batch \* gen_per_batch* - - **real(8) k_generation(i)** - - k-effective for the i-th total generation - - *do i = 1, current_batch \* gen_per_batch* - - **real(8) entropy(i)** - - Shannon entropy for the i-th total generation - - **real(8) k_col_abs** - - Sum of product of collision/absorption estimates of k-effective - - **real(8) k_col_tra** - - Sum of product of collision/track-length estimates of k-effective - - **real(8) k_abs_tra** - - Sum of product of absorption/track-length estimates of k-effective - - **real(8) k_combined(2)** - - Mean and standard deviation of a combined estimate of k-effective - - **integer(4) cmfd_on** - - Flag that cmfd is on - - if (cmfd_on) - - **integer(4) cmfd % indices** - - Indices for cmfd mesh (i,j,k,g) - - **real(8) cmfd % k_cmfd(1:current_batch)** - - CMFD eigenvalues - - **real(8) cmfd % src(1:G,1:I,1:J,1:K)** - - CMFD fission source - - **real(8) cmfd % entropy(1:current_batch)** - - CMFD estimate of Shannon entropy - - **real(8) cmfd % balance(1:current_batch)** - - RMS of the residual neutron balance equation on CMFD mesh - - **real(8) cmfd % dom(1:current_batch)** - - CMFD estimate of dominance ratio - - **real(8) cmfd % scr_cmp(1:current_batch)** - - RMS comparison of difference between OpenMC and CMFD fission source - -**integer(4) n_meshes** - - Number of meshes in tallies.xml file - -*do i = 1, n_meshes* - - **integer(4) meshes(i) % id** - - Unique ID of mesh. - - **integer(4) meshes(i) % type** - - Type of mesh. - - **integer(4) meshes(i) % n_dimension** - - Number of dimensions for mesh (2 or 3). - - **integer(4) meshes(i) % dimension(:)** - - Number of mesh cells in each dimension. - - **real(8) meshes(i) % lower_left(:)** - - Coordinates of lower-left corner of mesh. - - **real(8) meshes(i) % upper_right(:)** - - Coordinates of upper-right corner of mesh. - - **real(8) meshes(i) % width(:)** - - Width of each mesh cell in each dimension. - -**integer(4) n_tallies** - -*do i = 1, n_tallies* - - **integer(4) tallies(i) % id** - - Unique ID of tally. - - **integer(4) tallies(i) % n_realizations** - - Number of realizations for the i-th tally. - - **integer(4) size(tallies(i) % scores, 1)** - - Total number of score bins for the i-th tally - - **integer(4) size(tallies(i) % scores, 2)** - - Total number of filter bins for the i-th tally - - **integer(4) tallies(i) % n_filters** - - *do j = 1, tallies(i) % n_filters* - - **integer(4) tallies(i) % filter(j) % type** - - Type of tally filter. - - **integer(4) tallies(i) % filter(j) % n_bins** - - Number of bins for filter. - - **integer(4)/real(8) tallies(i) % filter(j) % bins(:)** - - Value for each filter bin of this type. - - **integer(4) tallies(i) % n_nuclide_bins** - - Number of nuclide bins. If none are specified, this is just one. - - *do j = 1, tallies(i) % n_nuclide_bins* - - **integer(4) tallies(i) % nuclide_bins(j)** - - Values of specified nuclide bins - - **integer(4) tallies(i) % n_score_bins** - - Number of scoring bins. - - *do j = 1, tallies(i) % n_score_bins* - - **integer(4) tallies(i) % score_bins(j)** - - Values of specified scoring bins (e.g. SCORE_FLUX). - - **integer(4) tallies(i) % n_score_bins** - - Number of scoring bins without accounting for those added by - the scatter-pn command. - - *do j = 1, tallies(i) % n_user_score_bins* - - **character(8) tallies(i) % moment_order(j)** - - Tallying moment order for Legendre and spherical - harmonic tally expansions (*e.g.*, 'P2', 'Y1,2', etc.). - -**integer(4) source_present** - - Flag indicated if source bank is present in the file - -**integer(4) n_realizations** - - Number of realizations for global tallies. - -**integer(4) N_GLOBAL_TALLIES** - - Number of global tally scores - -*do i = 1, N_GLOBAL_TALLIES* - - **real(8) global_tallies(i) % sum** - - Accumulated sum for the i-th global tally - - **real(8) global_tallies(i) % sum_sq** - - Accumulated sum of squares for the i-th global tally - -**integer(4) tallies_on** - - Flag indicated if tallies are present in the file. - -if (tallies_on > 0) - - *do i = 1, n_tallies* - - *do k = 1, size(tallies(i) % scores, 2)* - - *do j = 1, size(tallies(i) % scores, 1)* - - **real(8) tallies(i) % scores(j,k) % sum** - - Accumulated sum for the j-th score and k-th filter of the - i-th tally - - **real(8) tallies(i) % scores(j,k) % sum_sq** - - Accumulated sum of squares for the j-th score and k-th - filter of the i-th tally - -if (run_mode == MODE_EIGENVALUE and source_present) - - *do i = 1, n_particles* - - **real(8) source_bank(i) % wgt** - - Weight of the i-th source particle - - **real(8) source_bank(i) % xyz(1:3)** - - Coordinates of the i-th source particle. - - **real(8) source_bank(i) % uvw(1:3)** - - Direction of the i-th source particle - - **real(8) source_bank(i) % E** - - Energy of the i-th source particle. - diff --git a/docs/source/devguide/voxel.rst b/docs/source/devguide/voxel.rst deleted file mode 100644 index 98f5cb73b..000000000 --- a/docs/source/devguide/voxel.rst +++ /dev/null @@ -1,52 +0,0 @@ -.. _devguide_voxel: - -===================================== -Voxel Plot Binary File Specifications -===================================== - -The current revision of the voxel plot binary file is 1. - -**integer(4) n_voxels_x** - - Number of voxels in the x direction - -**integer(4) n_voxels_y** - - Number of voxels in the y direction - -**integer(4) n_voxels_z** - - Number of voxels in the z direction - -**real(8) width_voxel_x** - - Width of voxels in the x direction - -**real(8) width_voxel_y** - - Width of voxels in the y direction - -**real(8) width_voxel_z** - - Width of voxels in the z direction - -**real(8) lower_left_x** - - Lower left x point of the voxel grid - -**real(8) lower_left_y** - - Lower left y point of the voxel grid - -**real(8) lower_left_z** - - Lower left z point of the voxel grid - -*do x = 1, n_voxels_x* - *do y = 1, n_voxels_y* - *do z = 1, n_voxels_z* - - **integer(4) id** - - Cell or material id number at this voxel center. Set to -1 when - cell not_found. diff --git a/docs/source/methods/eigenvalue.rst b/docs/source/methods/eigenvalue.rst index fe99ba22e..41bf86549 100644 --- a/docs/source/methods/eigenvalue.rst +++ b/docs/source/methods/eigenvalue.rst @@ -142,7 +142,7 @@ than unity. By ensuring that the expected number of fission sites in each mesh cell is constant, the collision density across all cells, and hence the variance of tallies, is more uniform than it would be otherwise. -.. _Shannon entropy: https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/la-ur-06-3737_entropy.pdf +.. _Shannon entropy: https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/la-ur-06-3737.pdf .. [Lieberoth] J. Lieberoth, "A Monte Carlo Technique to Solve the Static Eigenvalue Problem of the Boltzmann Transport Equation," *Nukleonik*, **11**, diff --git a/docs/source/methods/physics.rst b/docs/source/methods/physics.rst index d0a6a2c99..e25057488 100644 --- a/docs/source/methods/physics.rst +++ b/docs/source/methods/physics.rst @@ -1027,14 +1027,19 @@ probability distribution function can be found by integrating equation Let us call the normalization factor in the denominator of equation :eq:`target-pdf-1` :math:`C`. -It is normally assumed that :math:`\sigma (v_r)` is constant over the range of + +Constant Cross Section Model +---------------------------- + +It is often assumed that :math:`\sigma (v_r)` is constant over the range of relative velocities of interest. This is a good assumption for almost all cases since the elastic scattering cross section varies slowly with velocity for light nuclei, and for heavy nuclei where large variations can occur due to resonance scattering, the moderating effect is rather small. Nonetheless, this assumption may cause incorrect answers in systems with low-lying resonances that can cause a significant amount of up-scatter that would be ignored by this assumption -(e.g. U-238 in commercial light-water reactors). Nevertheless, with this +(e.g. U-238 in commercial light-water reactors). We will revisit this assumption +later in :ref:`energy_dependent_xs_model`. For now, continuing with the assumption, we write :math:`\sigma (v_r) = \sigma_s` which simplifies :eq:`target-pdf-1` to @@ -1232,6 +1237,35 @@ If is not accepted, then we repeat the process and resample a target speed and cosine until a combination is found that satisfies equation :eq:`freegas-accept-2`. +.. _energy_dependent_xs_model: + +Energy-Dependent Cross Section Model +------------------------------------ + +As was noted earlier, assuming that the elastic scattering cross section is +constant in :eq:`reaction-rate` is not strictly correct, especially when +low-lying resonances are present in the cross sections for heavy nuclides. To +correctly account for energy dependence of the scattering cross section entails +performing another rejection step. The most common method is to sample +:math:`\mu` and :math:`v_T` as in the constant cross section approximation and +then perform a rejection on the ratio of the 0 K elastic scattering cross +section at the relative velocity to the maximum 0 K elastic scattering cross +section over the range of velocities considered: + +.. math:: + :label: dbrc + + p_{dbrc} = \frac{\sigma_s(v_r)}{\sigma_{s,max}} + +where it should be noted that the maximum is taken over the range :math:`[v_n - +4/\beta, 4_n + 4\beta]`. This method is known as Doppler broadening rejection +correction (DBRC) and was first introduced by `Becker et al.`_. OpenMC has an +implementation of DBRC as well as an accelerated sampling method that are +described fully in `Walsh et al.`_ + +.. _Becker et al.: http://dx.doi.org/10.1016/j.anucene.2008.12.001 +.. _Walsh et al.: http://dx.doi.org/10.1016/j.anucene.2014.01.017 + .. _sab_tables: ------------ diff --git a/docs/source/pythonapi/examples/pandas-dataframes.ipynb b/docs/source/pythonapi/examples/pandas-dataframes.ipynb index 24c5c00a0..cb63e2ac3 100644 --- a/docs/source/pythonapi/examples/pandas-dataframes.ipynb +++ b/docs/source/pythonapi/examples/pandas-dataframes.ipynb @@ -374,7 +374,7 @@ "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAAAFzUkdC\nAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAxQTFRF\n////chIS6YCRTb/E6kGE+wAAAAFiS0dEAIgFHUgAAAAJcEhZcwAAAEgAAABIAEbJaz4AAAPZSURB\nVGje7Zs7buMwEIZ9iey50gyNjQpXKTYudIScgkdQYTfut1idwkdQkQNsYQO2Qj0sPiVK+mlQDmwg\nwIcgg8Cc4fCTSK5W4OeFkM8rHv+2I/rgxPZEPZgR7XtQxKdXYuUXJSUnBQ/9WCgo4vOSJ+WFUvF7\nE08mlia+rn7VcKXP8sRszFX8b2MdX2y6v1Tw6MZUw4H4ojfIjD8mvn/qRL5p4+vvlMqvp2EhR8WB\nzfiz20hXORmP9fi/bM9EeUFvV5H/0yRkeSbiGRfFJErxD9ENdz7Mbhig/h89fvtFdMiI/ePUIXV4\nlXju8K3DKv9NThOZ3q2KmUy6grxFES8rjeyic+FFQav+ncg3fXjH+Ts+/iibztFqOiZuZP/Z3Oaf\nPX40NGgST2r+uvQkXXp6cKvmr+r0e1Eef5um3+JHP3IFF1D/seNZJgaDmvY0Gav1s+2f1fqpIcub\nlfKGt6apotG/NVx3SInWtLX+7Vg/Pv1YqOsnun6JSVdOXT/X7vk75f938QP+8OmSBs0fXtymMhJb\nf8qlPynYmpKCh7OB1fzNalOj1sl0ZAruHLiA+RM73pDe/VjMVP89+aTXwjyc/x5n+u991895/utr\nJTy8/06TXh0r/5JOa2JmYmqi4r/vUm/H4wLmT+z4anhr05X+q6KUXhtzr/9qSff5L5uMT//V/NdU\n4YuBTPa/8P67l/6r44ds+hYuoP5jx9ciy6XTWlibBrmx8V/TdMfjkP+6pOsu/lvM9N90sf7r+f6m\n/65n+S8p/itN15v0UkW3/+48+PRfJX6S9Joo4g+G/1qYG9KroqP/WypcuvyXPf13wH89/hHef7MB\n6R3Cqn55U4rv4kfH3zaSgQuYP7HjVf89tXrbO+hfLdr+Ozv/SP1dgtQ/Ov8C+i/3+q/Zf2D/HWi6\nbjT6rym9I/v/03/b+LHS4cTg/utTsV7/net/Afzz4f0XGX84/2j9xZ4/sePR/of2X7D/o+vPo/sv\n6h9B/Bfxr9j1Hz2eN/hO8/wfff4A848+f/1A/530/I0+/8PvH9D3H9HnT+R49P0b+v4PfP/4E/wX\nfP8Mvf9G37/D/ovuP8SeP7Hj0f0vdP8tqP9O339cyv7p3P1fdP8Z3v9G999j13/seMax8x/o+ZN7\n+O+E8zdP/8XOf8Hnz9Dzb7HnT+x49PxlCp7/BM+fOv13wvnXBfivt2lMvD8TyH/Hnb+Gz3+j589j\nz5/Y8ej9h4D+W7qQmf57efqv239n3T+C7z+h969i13/seMax+3/o/cMcu/8Y2H9n3p+J6r98pv8m\n4fwXuH+M3n+OO3++AX9clR+4PhbRAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTA4LTA4VDA5OjI2\nOjM4KzA3OjAwuRKYlgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNS0wOC0wOFQwOToyNjozOCswNzow\nMMhPICoAAAAASUVORK5CYII=\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///9yEhLpgJFNv8Tq\nQYT7AAAAAWJLR0QAiAUdSAAAAAd0SU1FB98JFQMbBgd4EXAAAALKSURBVGje7dpLcqQwDAbgHHE2\nYeEj+D4cwQucBUfo+3CEXoSp8OhuhF70T4qpKXmdr21LogK2Pj7A8QmNP+HDhw8fPnz48Kf6VH9G\n+66vy+je8k19jnf8C5dXIPv86ms56lPdjvaYbyodx3ze+XLE76cXFiD4zPji99z0/AJ4n1lfvJ6f\nnl0A6x+578efMSg1wPr172/jPO5yFXM+Ef78gdblM+WPHyguP//t1/g6pA0wfln+ho/fwgYYn19C\n/xwDvwHGc9OvC+hs37DTrwuwfWanXxdQTC9Mvyygs3wjTL8uwPJpn/tNDbSGz7T0SBEWw4vLXzbQ\n6b6RoveIoO6TvPxlA63qs7z8ZQPF9F+SH22vbX8OQKf5Rtv+EgDNJ3X58wZaxWd1+fMGiuFvir8b\nvjp8J/tGy/6jAmRvhW8fwL3vVT+o3grfPoB7r/IpALI3tz8FoJN84/NV873hB8UnM3xzANtf8nb4\ndwmg3grfFEDJO8JPE0i9Ff4pAYL3pI8mkHor/HMCeO9JH00g9SafEsh7T/ppARBvp48UwJnelT5S\nACd7O31TAlnvKx9SQCd7B58KgPO+8iMFuPWe9E8F8BveWX7bAjzX9y4//Jve+fhsH6Ctv7n8PTzj\nvY/v9gEOHz58+PBX+6v/f/wPvnd54f3j6venE/yl769Xv7+j3x/o98/V32/o9+fl389Xnx+g5x/o\n+Qt6/oOeP6HnX+j5G3z+h54/ouefV5/foufP6Pk3ev4On/+j9w/o/Qd6/4Le/6D3T/D9V67Y/ZsV\nQBq+s+8f0ftP+P41axXguP9NWgDuu/Cdfv+N3r/D9/9TAID+A7T/Ae2/gPs/0P4TtP8F7r9J3AIO\n9P+g/Udw/9Oygbf7r9D+L7j/DO1/Q/vv4P4/tP8Q7n9E+y/h/k+0/xTuf4X7b+H+X7T/+BPuf3aM\n8OHDhw8fPnz4w/4vzcvgeY10sY0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMDktMjFUMTA6MjU6\nMjYrMDc6MDAKj62JAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE1LTA5LTIxVDEwOjI1OjI2KzA3OjAw\ne9IVNQAAAABJRU5ErkJggg==\n", "text/plain": [ "" ] @@ -429,7 +429,7 @@ "source": [ "# Instantiate a tally Mesh\n", "mesh = openmc.Mesh(mesh_id=1)\n", - "mesh.type = 'rectangular'\n", + "mesh.type = 'regular'\n", "mesh.dimension = [17, 17]\n", "mesh.lower_left = [-10.71, -10.71]\n", "mesh.width = [1.26, 1.26]\n", @@ -562,9 +562,9 @@ "\n", " Copyright: 2011-2015 Massachusetts Institute of Technology\n", " License: http://mit-crpg.github.io/openmc/license.html\n", - " Version: 0.6.2\n", - " Date/Time: 2015-08-11 13:40:43\n", - " MPI Processes: 4\n", + " Version: 0.7.0\n", + " Git SHA1: b167d70c877c516deca785801b9fa6f53fb0985b\n", + " Date/Time: 2015-09-21 10:27:06\n", "\n", " ===========================================================================\n", " ========================> INITIALIZATION <=========================\n", @@ -590,38 +590,39 @@ "\n", " Bat./Gen. k Average k \n", " ========= ======== ==================== \n", - " 1/1 0.60069 \n", - " 2/1 0.62857 \n", - " 3/1 0.69431 \n", - " 4/1 0.65935 \n", - " 5/1 0.68092 \n", - " 6/1 0.64791 \n", - " 7/1 0.65859 0.65325 +/- 0.00534\n", - " 8/1 0.67381 0.66010 +/- 0.00752\n", - " 9/1 0.74149 0.68045 +/- 0.02103\n", - " 10/1 0.68244 0.68085 +/- 0.01629\n", - " 11/1 0.68068 0.68082 +/- 0.01330\n", - " 12/1 0.70394 0.68412 +/- 0.01172\n", - " 13/1 0.68624 0.68439 +/- 0.01015\n", - " 14/1 0.65667 0.68131 +/- 0.00947\n", - " 15/1 0.70080 0.68326 +/- 0.00869\n", - " 16/1 0.69639 0.68445 +/- 0.00795\n", - " 17/1 0.68786 0.68474 +/- 0.00726\n", - " 18/1 0.63698 0.68106 +/- 0.00762\n", - " 19/1 0.62785 0.67726 +/- 0.00802\n", - " 20/1 0.65759 0.67595 +/- 0.00758\n", - " Triggers unsatisfied, max unc./thresh. is 1.20713 for absorption in tally 10002\n", - " The estimated number of batches is 27\n", + " 1/1 0.59998 \n", + " 2/1 0.65473 \n", + " 3/1 0.67452 \n", + " 4/1 0.66458 \n", + " 5/1 0.70093 \n", + " 6/1 0.70726 \n", + " 7/1 0.65977 0.68351 +/- 0.02375\n", + " 8/1 0.68457 0.68387 +/- 0.01372\n", + " 9/1 0.70024 0.68796 +/- 0.01053\n", + " 10/1 0.64895 0.68016 +/- 0.01128\n", + " 11/1 0.68744 0.68137 +/- 0.00929\n", + " 12/1 0.68037 0.68123 +/- 0.00786\n", + " 13/1 0.64865 0.67715 +/- 0.00793\n", + " 14/1 0.71415 0.68127 +/- 0.00811\n", + " 15/1 0.65717 0.67886 +/- 0.00764\n", + " 16/1 0.71598 0.68223 +/- 0.00769\n", + " 17/1 0.67285 0.68145 +/- 0.00707\n", + " 18/1 0.69329 0.68236 +/- 0.00656\n", + " 19/1 0.65696 0.68055 +/- 0.00634\n", + " 20/1 0.65500 0.67884 +/- 0.00615\n", + " Triggers unsatisfied, max unc./thresh. is 1.21110 for absorption in tally 10002\n", + " The estimated number of batches is 28\n", " Creating state point statepoint.020.h5...\n", - " 21/1 0.68391 0.67645 +/- 0.00711\n", - " 22/1 0.69243 0.67739 +/- 0.00674\n", - " 23/1 0.65491 0.67614 +/- 0.00648\n", - " 24/1 0.64021 0.67425 +/- 0.00641\n", - " 25/1 0.72281 0.67668 +/- 0.00655\n", - " 26/1 0.71261 0.67839 +/- 0.00646\n", - " 27/1 0.69503 0.67914 +/- 0.00621\n", - " Triggers satisfied for batch 27\n", - " Creating state point statepoint.027.h5...\n", + " 21/1 0.67090 0.67835 +/- 0.00577\n", + " 22/1 0.69025 0.67905 +/- 0.00546\n", + " 23/1 0.66113 0.67805 +/- 0.00525\n", + " 24/1 0.67934 0.67812 +/- 0.00496\n", + " 25/1 0.67203 0.67781 +/- 0.00472\n", + " 26/1 0.66928 0.67741 +/- 0.00451\n", + " 27/1 0.70271 0.67856 +/- 0.00445\n", + " 28/1 0.70233 0.67959 +/- 0.00437\n", + " Triggers satisfied for batch 28\n", + " Creating state point statepoint.028.h5...\n", "\n", " ===========================================================================\n", " ======================> SIMULATION FINISHED <======================\n", @@ -630,28 +631,28 @@ "\n", " =======================> TIMING STATISTICS <=======================\n", "\n", - " Total time for initialization = 9.7300E-01 seconds\n", - " Reading cross sections = 3.0300E-01 seconds\n", - " Total time in simulation = 5.9130E+00 seconds\n", - " Time in transport only = 5.4000E+00 seconds\n", - " Time in inactive batches = 7.7300E-01 seconds\n", - " Time in active batches = 5.1400E+00 seconds\n", - " Time synchronizing fission bank = 4.4600E-01 seconds\n", - " Sampling source sites = 0.0000E+00 seconds\n", - " SEND/RECV source sites = 0.0000E+00 seconds\n", - " Time accumulating tallies = 9.0000E-03 seconds\n", + " Total time for initialization = 4.4100E-01 seconds\n", + " Reading cross sections = 1.7900E-01 seconds\n", + " Total time in simulation = 1.2656E+01 seconds\n", + " Time in transport only = 1.2642E+01 seconds\n", + " Time in inactive batches = 2.0300E+00 seconds\n", + " Time in active batches = 1.0626E+01 seconds\n", + " Time synchronizing fission bank = 4.0000E-03 seconds\n", + " Sampling source sites = 3.0000E-03 seconds\n", + " SEND/RECV source sites = 1.0000E-03 seconds\n", + " Time accumulating tallies = 0.0000E+00 seconds\n", " Total time for finalization = 0.0000E+00 seconds\n", - " Total time elapsed = 6.8870E+00 seconds\n", - " Calculation Rate (inactive) = 16170.8 neutrons/second\n", - " Calculation Rate (active) = 7295.72 neutrons/second\n", + " Total time elapsed = 1.3110E+01 seconds\n", + " Calculation Rate (inactive) = 6157.64 neutrons/second\n", + " Calculation Rate (active) = 3529.08 neutrons/second\n", "\n", " ============================> RESULTS <============================\n", "\n", - " k-effective (Collision) = 0.68117 +/- 0.00597\n", - " k-effective (Track-length) = 0.67914 +/- 0.00621\n", - " k-effective (Absorption) = 0.67898 +/- 0.00471\n", - " Combined k-effective = 0.67922 +/- 0.00479\n", - " Leakage Fraction = 0.34264 +/- 0.00301\n", + " k-effective (Collision) = 0.68196 +/- 0.00427\n", + " k-effective (Track-length) = 0.67959 +/- 0.00437\n", + " k-effective (Absorption) = 0.67957 +/- 0.00402\n", + " Combined k-effective = 0.67943 +/- 0.00295\n", + " Leakage Fraction = 0.34370 +/- 0.00201\n", "\n" ] }, @@ -671,7 +672,7 @@ "!rm statepoint.*\n", "\n", "# Run OpenMC with MPI!\n", - "executor.run_simulation(mpi_procs=4)" + "executor.run_simulation()" ] }, { @@ -694,9 +695,7 @@ "statepoints = glob.glob('statepoint.*.h5')\n", "\n", "# Load the last statepoint file\n", - "sp = StatePoint(statepoints[-1])\n", - "sp.read_results()\n", - "sp.compute_stdev()" + "sp = StatePoint(statepoints[-1])" ] }, { @@ -738,7 +737,7 @@ " \t\tmesh\t[1]\n", " \t\tenergy\t[ 0.00000000e+00 6.25000000e-07 2.00000000e+01]\n", "\tNuclides =\ttotal \n", - "\tScores =\t['fission', 'nu-fission']\n", + "\tScores =\t[u'fission', u'nu-fission']\n", "\tEstimator =\ttracklength\n", "\n" ] @@ -770,13 +769,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "[[[ 0.14583021]]\n", + "[[[ 0.15044911]]\n", "\n", - " [[ 0.07846909]]\n", + " [[ 0.09149973]]\n", "\n", - " [[ 0.33705448]]\n", + " [[ 0.27611475]]\n", "\n", - " [[ 0.15150059]]]\n" + " [[ 0.12476673]]]\n" ] } ], @@ -840,7 +839,7 @@ " 0.0e+00 - 6.3e-07\n", " fission\n", " 0.000236\n", - " 0.000034\n", + " 0.000035\n", " \n", " \n", " 1\n", @@ -849,8 +848,8 @@ " 1\n", " 0.0e+00 - 6.3e-07\n", " nu-fission\n", - " 0.000576\n", - " 0.000084\n", + " 0.000574\n", + " 0.000086\n", " \n", " \n", " 2\n", @@ -859,8 +858,8 @@ " 1\n", " 6.3e-07 - 2.0e+01\n", " fission\n", - " 0.000069\n", - " 0.000004\n", + " 0.000072\n", + " 0.000006\n", " \n", " \n", " 3\n", @@ -869,8 +868,8 @@ " 1\n", " 6.3e-07 - 2.0e+01\n", " nu-fission\n", - " 0.000183\n", - " 0.000011\n", + " 0.000190\n", + " 0.000014\n", " \n", " \n", " 4\n", @@ -879,8 +878,8 @@ " 1\n", " 0.0e+00 - 6.3e-07\n", " fission\n", - " 0.000366\n", - " 0.000052\n", + " 0.000451\n", + " 0.000058\n", " \n", " \n", " 5\n", @@ -889,8 +888,8 @@ " 1\n", " 0.0e+00 - 6.3e-07\n", " nu-fission\n", - " 0.000892\n", - " 0.000127\n", + " 0.001100\n", + " 0.000141\n", " \n", " \n", " 6\n", @@ -899,8 +898,8 @@ " 1\n", " 6.3e-07 - 2.0e+01\n", " fission\n", - " 0.000109\n", - " 0.000009\n", + " 0.000095\n", + " 0.000006\n", " \n", " \n", " 7\n", @@ -909,8 +908,8 @@ " 1\n", " 6.3e-07 - 2.0e+01\n", " nu-fission\n", - " 0.000284\n", - " 0.000021\n", + " 0.000250\n", + " 0.000016\n", " \n", " \n", " 8\n", @@ -919,8 +918,8 @@ " 1\n", " 0.0e+00 - 6.3e-07\n", " fission\n", - " 0.000540\n", - " 0.000058\n", + " 0.000575\n", + " 0.000080\n", " \n", " \n", " 9\n", @@ -929,8 +928,8 @@ " 1\n", " 0.0e+00 - 6.3e-07\n", " nu-fission\n", - " 0.001316\n", - " 0.000141\n", + " 0.001401\n", + " 0.000194\n", " \n", " \n", " 10\n", @@ -939,8 +938,8 @@ " 1\n", " 6.3e-07 - 2.0e+01\n", " fission\n", - " 0.000144\n", - " 0.000017\n", + " 0.000134\n", + " 0.000011\n", " \n", " \n", " 11\n", @@ -949,8 +948,8 @@ " 1\n", " 6.3e-07 - 2.0e+01\n", " nu-fission\n", - " 0.000376\n", - " 0.000041\n", + " 0.000353\n", + " 0.000028\n", " \n", " \n", " 12\n", @@ -959,8 +958,8 @@ " 1\n", " 0.0e+00 - 6.3e-07\n", " fission\n", - " 0.000830\n", - " 0.000085\n", + " 0.000655\n", + " 0.000071\n", " \n", " \n", " 13\n", @@ -969,8 +968,8 @@ " 1\n", " 0.0e+00 - 6.3e-07\n", " nu-fission\n", - " 0.002022\n", - " 0.000207\n", + " 0.001596\n", + " 0.000174\n", " \n", " \n", " 14\n", @@ -979,8 +978,8 @@ " 1\n", " 6.3e-07 - 2.0e+01\n", " fission\n", - " 0.000168\n", - " 0.000013\n", + " 0.000149\n", + " 0.000009\n", " \n", " \n", " 15\n", @@ -989,8 +988,8 @@ " 1\n", " 6.3e-07 - 2.0e+01\n", " nu-fission\n", - " 0.000434\n", - " 0.000034\n", + " 0.000391\n", + " 0.000023\n", " \n", " \n", " 16\n", @@ -999,8 +998,8 @@ " 1\n", " 0.0e+00 - 6.3e-07\n", " fission\n", - " 0.000738\n", - " 0.000043\n", + " 0.000781\n", + " 0.000078\n", " \n", " \n", " 17\n", @@ -1009,8 +1008,8 @@ " 1\n", " 0.0e+00 - 6.3e-07\n", " nu-fission\n", - " 0.001799\n", - " 0.000105\n", + " 0.001903\n", + " 0.000191\n", " \n", " \n", " 18\n", @@ -1019,8 +1018,8 @@ " 1\n", " 6.3e-07 - 2.0e+01\n", " fission\n", - " 0.000186\n", - " 0.000010\n", + " 0.000185\n", + " 0.000009\n", " \n", " \n", " 19\n", @@ -1029,8 +1028,8 @@ " 1\n", " 6.3e-07 - 2.0e+01\n", " nu-fission\n", - " 0.000486\n", - " 0.000026\n", + " 0.000484\n", + " 0.000024\n", " \n", " \n", "\n", @@ -1040,26 +1039,26 @@ " mesh 1 energy [MeV] score mean std. dev.\n", " x y z \n", "bin \n", - "0 1 1 1 0.0e+00 - 6.3e-07 fission 0.000236 0.000034\n", - "1 1 1 1 0.0e+00 - 6.3e-07 nu-fission 0.000576 0.000084\n", - "2 1 1 1 6.3e-07 - 2.0e+01 fission 0.000069 0.000004\n", - "3 1 1 1 6.3e-07 - 2.0e+01 nu-fission 0.000183 0.000011\n", - "4 1 2 1 0.0e+00 - 6.3e-07 fission 0.000366 0.000052\n", - "5 1 2 1 0.0e+00 - 6.3e-07 nu-fission 0.000892 0.000127\n", - "6 1 2 1 6.3e-07 - 2.0e+01 fission 0.000109 0.000009\n", - "7 1 2 1 6.3e-07 - 2.0e+01 nu-fission 0.000284 0.000021\n", - "8 1 3 1 0.0e+00 - 6.3e-07 fission 0.000540 0.000058\n", - "9 1 3 1 0.0e+00 - 6.3e-07 nu-fission 0.001316 0.000141\n", - "10 1 3 1 6.3e-07 - 2.0e+01 fission 0.000144 0.000017\n", - "11 1 3 1 6.3e-07 - 2.0e+01 nu-fission 0.000376 0.000041\n", - "12 1 4 1 0.0e+00 - 6.3e-07 fission 0.000830 0.000085\n", - "13 1 4 1 0.0e+00 - 6.3e-07 nu-fission 0.002022 0.000207\n", - "14 1 4 1 6.3e-07 - 2.0e+01 fission 0.000168 0.000013\n", - "15 1 4 1 6.3e-07 - 2.0e+01 nu-fission 0.000434 0.000034\n", - "16 1 5 1 0.0e+00 - 6.3e-07 fission 0.000738 0.000043\n", - "17 1 5 1 0.0e+00 - 6.3e-07 nu-fission 0.001799 0.000105\n", - "18 1 5 1 6.3e-07 - 2.0e+01 fission 0.000186 0.000010\n", - "19 1 5 1 6.3e-07 - 2.0e+01 nu-fission 0.000486 0.000026" + "0 1 1 1 0.0e+00 - 6.3e-07 fission 0.000236 0.000035\n", + "1 1 1 1 0.0e+00 - 6.3e-07 nu-fission 0.000574 0.000086\n", + "2 1 1 1 6.3e-07 - 2.0e+01 fission 0.000072 0.000006\n", + "3 1 1 1 6.3e-07 - 2.0e+01 nu-fission 0.000190 0.000014\n", + "4 1 2 1 0.0e+00 - 6.3e-07 fission 0.000451 0.000058\n", + "5 1 2 1 0.0e+00 - 6.3e-07 nu-fission 0.001100 0.000141\n", + "6 1 2 1 6.3e-07 - 2.0e+01 fission 0.000095 0.000006\n", + "7 1 2 1 6.3e-07 - 2.0e+01 nu-fission 0.000250 0.000016\n", + "8 1 3 1 0.0e+00 - 6.3e-07 fission 0.000575 0.000080\n", + "9 1 3 1 0.0e+00 - 6.3e-07 nu-fission 0.001401 0.000194\n", + "10 1 3 1 6.3e-07 - 2.0e+01 fission 0.000134 0.000011\n", + "11 1 3 1 6.3e-07 - 2.0e+01 nu-fission 0.000353 0.000028\n", + "12 1 4 1 0.0e+00 - 6.3e-07 fission 0.000655 0.000071\n", + "13 1 4 1 0.0e+00 - 6.3e-07 nu-fission 0.001596 0.000174\n", + "14 1 4 1 6.3e-07 - 2.0e+01 fission 0.000149 0.000009\n", + "15 1 4 1 6.3e-07 - 2.0e+01 nu-fission 0.000391 0.000023\n", + "16 1 5 1 0.0e+00 - 6.3e-07 fission 0.000781 0.000078\n", + "17 1 5 1 0.0e+00 - 6.3e-07 nu-fission 0.001903 0.000191\n", + "18 1 5 1 6.3e-07 - 2.0e+01 fission 0.000185 0.000009\n", + "19 1 5 1 6.3e-07 - 2.0e+01 nu-fission 0.000484 0.000024" ] }, "execution_count": 25, @@ -1084,9 +1083,9 @@ "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAY0AAAEaCAYAAADtxAsqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3X+UXWV97/H3hwAK/iBBLDHJQPgx2hmKGL2N6QUhFqVx\nrKQyCjexVFPvJZXOsl7FAloXYCv1RxdNQwRzrxSyKkMubQLSmjQgEnFNNSkQQ9qZYAIESVIDQqIY\nwPzge//Yzwwnh3PO3pPMnDNn5vNa66zZ+9nPd+9nz5w53/PsH89WRGBmZlbEYY1ugJmZNQ8nDTMz\nK8xJw8zMCnPSMDOzwpw0zMysMCcNMzMrzEnD6kbSfknrJP1Y0oOSfmeI1z9T0j/n1DlnqLdbD5K2\nSDq2QvmvGtEeG7sOb3QDbEx5PiKmAUg6D/hrYGad2/Bu4DnghwcTLEkAUf8bnKptb8TcaCXpsIh4\nqdHtsOHlnoY1yjHAs5B9EEv6mqQNkh6WdGEqXyDpC2n69yR9P9W9RdI3JP27pEckvb985ZKOlXSn\npPWSfijpdElTgfnA/049nrPKYt4o6R5J/yHp//Z/u5c0NW1nCbABaKnS3gN6OpIWSfpomt4i6Sup\n/hpJp5Rs858krU2v/57K3yDp7v62AKr2i5R0Xar3XUnHSTpF0oMly1tL50vKPynpP9Pv6LZU9lpJ\nN6d2rpf0wVQ+J5VtkPTlknX8StLfSPox8DuS/jDt37r0N/JnzGgTEX75VZcXsA9YB/QBu4BpqbwT\nuJvsg/E3gCeA44GjgP8g6x1sBE5K9W8BVqTpU4EngVeR9Vr+OZVfD3whTb8bWJemrwI+XaV9i4DL\n0/TvAS8BxwJTgf3A9BrtnVi6/ZI2/FGafhy4Mk1fXNLObuDMNH0C0JumFwJ/kaY7+ttSoc0vAXPS\n9BeA69P094Az0vS1wJ9WiN0GHJGmX59+fgW4rqTOeGBS2sc3AOOAe4HZJdv/UJpuA+4CxqX5G4CL\nG/2+82toX/4WYPX0QkRMi4g2YBbwD6n8LKA7Mk8B3yf7gH4B+F/APWQfho+n+gHcDhARm4HHgN8s\n29aZ/euPiPuAN0h6XVpW7Vv7mcDSFLMK2Fmy7ImIWFtSr7y9v03+oaLb0s+lQP95lfcAiyStA74N\nvE7Sa4B3Ad9KbVlR1pZSLwH/L01/i+x3CfBNYF76pn8hWXIq9zDQLekjZEkR4Fzg6/0VImJX2rf7\nIuKZiNgP3AqcnarsB5aVxL4DeCDtz+8CJ1X9bVhT8jkNa4iI+FE6lPJGsg/b0g9y8fIH8FuBp4HJ\nOausdCy96iGdGqrF7M6pF2Q9qdIvYkfV2E7//gl4Z0TsOWDl2amTwba/9Pe2nKxX9T3ggYiolHTe\nT/bh/wHg85JOL1lPeVur/X1ejIjSZLkkIj43yHZbE3FPwxpC0m+Svf9+DvwAuEjSYSmJvAtYK+lE\n4NPANOB9kqb3hwMfTuc3TgFOBh4p28QPgI+kbc0Eno6I58hOgr+OynrIvpX3n6ifUKVeeXvPBtYC\nPwXaJR0paTzZN+1SF5X8/Lc0fTfwyZLfyxlp8n5gbip7X422HAZ8OE3PTW0jIl4EVgE3AjeXB6UT\n+idExGrgCrJzTK8l69X9aUm98WnfzknnWcYB/4Osd1XuXuBD6XfSf17phCrttiblnobV01HpsAVk\nH/wfTd9S71B2Gex6sm+wn42IpyTdA3wmIn4m6ePALZL6DwP9lOzD7PXA/IjYIyl4+Rvw1cDfS1pP\n1kv4aCr/Z+CfJM0GuiKip6R91wC3SbqY7Oqqn5ElmdeXrJeIqNheAEm3k52HeRx4qGz/J6T2vAjM\nSWWfBL6eyg8n+zC+tKQtc8gSzBNVfqe7gemS/gLYwcuJCbJDUh8kS0zlxgH/IOkYsr/F30XELyT9\nVWrPBrJDT1dHxJ2SrgDuS3X/JSL6T/iX/l76UjvuTofF9qZ9+WmVtlsT0oE9S7ORT9LNZCeSlw/x\neo8E9kfE/pQUvh4Rbx+idT8OvCMinh2K9RXc5mXA6yLiqnpt00Y/9zTMXnYCcHv6lryH7CT8UKnr\ntzNJd5CdhC4/RGZ2SNzTMDOzwnwi3KyAdHPeZekGt+ck3STpeEkrJf1C2U2B41PdGZL+TdJOZUOm\nnFOynnmSeiX9UtKjki4pWTZT0lZJn5a0Q9J2SR9rwO6aVeWkYVZMABeQ3YvwFuD3gZVkVx79Btn/\n0iclTQb+BfhiREwALgOWSXpDWs8O4P0R8XpgHvC3kqaVbOd4shPvk4CPk52UPma4d86sKCcNs+Ku\nj4inI2I72aWtP4yI9RHxa+AOskuDP0J2t/q/AkTEd4EHyO6JICJW9N+kGBH3k13Z9K6SbewlSzj7\nI2Il8CuyJGU2IjhpmBW3o2T6hbL5F8nucziR7B6Snf0vsjvIJ0J2z4WkH0l6Ji3rIBueo98zceCg\nf8+n9ZqNCL56yuzgld4l3X9FyZPAP0TEJa+oLL2KbMiNPwS+nS7tvYPB3/lt1jDuaZgNjf4P/m8B\nH5B0nqRxkl6dTnBPBo5Mr58DL6U7vc9rUHvNDoqThtnBi7LpiIitwGzgc8BTZHdDf4bs8vbnyO4A\nv51sWPg5ZIMUVlun2YiTe5+GpFnAArJhB74ZEV+pUGch8D6y468fi4h1RWIlfQb4GnBcRDyr7HkH\nfWTDYEN2ovHSg947MzMbUjXPaaTByRaRDd+8Dfh3SXdFRF9JnQ7g1IholfROsgHSZuTFSmoB3ssr\nx9TZHOnpbmZmNrLkHZ6aTvYhviUi9pI9B2B2WZ3zgSUAEbEGGC9pYoHY64A/H4J9MDOzOslLGpPJ\nrgbpt5VXPtegWp1J1WLTCKNbI+LhCts8SdmjIler7HGcZmbWWHmX3BY9KVf4kkFJR5GdJHxvhfjt\nQEtE7JT0duBOSaelE4hmZtZgeUljG9BSMt9C1mOoVWdKqnNEldhTyJ65vD49nWwK8KCk6emZBHsA\nIuIhSY8CrZQ9lyA9N8HMzIZRRLyiQ5CXNB4AWtNVTdvJHvAyp6zOXUAXsFTSDGBXROyQ9Eyl2HQi\n/Pj+4NLnDEg6DtiZbno6mSxhPFZlZ3KaboPV2dnJsmXL8iuajRB+zw6f9KX+FWomjYjYJ6mL7LGR\n44Cb0tO55qfliyNihaQOSZvJniI2r1Zspc2UTJ8NfFHSXrJnPs9PD7Y3M7MRIHcYkTRo2sqyssVl\n811FYyvUOblkejkwpE9jMzOzoeM7wm1AW1tbo5tgNihHH93R6CaMOU4aNqC9vb3RTTAblOefn97o\nJow5ThpmZlaYh0Y3s6ayenX2Ali+/HSuvjqbnjkze9nwctIws6ZSmhy+973HuPrqk2tVtyHmw1Nm\n1rSeeGJCo5sw5jhpmFnT8k2+9efDU2bWVErPaTz55LE+p1Fn7mmYmVlhuU/uG4kkRTO2e6Tr7u5m\n7ty5jW6GWWEnnrjT5zWGiaSKAxa6p2FmZoU5aZhZ0zrxxJ2NbsKY4xPhZtZUSk+E/+AHJ/tEeJ05\naZhZUylNDhs2bODqq09vZHPGHB+eMrOm9fTTr2l0E8ac3KQhaZakjZI2Sbq8Sp2Fafl6SdOKxkr6\njKSXJB1bUnZlqr9R0nkHu2NmZjb0aiYNSeOARcAsoB2YI6mtrE4HcGpEtAKXADcWiZXUArwXeKKk\nrJ3ssbDtKe4GSe4NmVlFb3zj7kY3YczJO6cxHdgcEVsAJC0FZgOlj209H1gCEBFrJI2XNBE4KSf2\nOuDPgW+XrGs2cFtE7AW2pEfITgd+dLA7aGaji0e5bay8pDEZeLJkfivwzgJ1JgOTqsVKmg1sjYiH\nyx5ePokDE0T/uszMAJ8Ib7S8pFH0tutX3DVYtaJ0FPA5skNTReJ967eZ2QiRlzS2AS0l8y1k3/5r\n1ZmS6hxRJfYUYCqwPvUypgAPSnpnlXVtq9Swzs7Ogem2tjY/qnQI9PT0NLoJZoOyY8eRdHdvaHQz\nRoXe3l76+vpy69Uce0rS4cAjwLnAdmAtMCci+krqdABdEdEhaQawICJmFIlN8Y8D74iIZ9OJ8G6y\n8xiTge+SnWSPshiPPTUMPPaUNZuzz36M++/3Q5iGQ7Wxp2r2NCJin6QuYBUwDrgpIvokzU/LF0fE\nCkkd6aT1bmBerdhKmynZXq+k24FeYB9wqbODmVXj+zTqz6Pc2gD3NKwZlF49dc01cNVV2bSvnhpa\nHuXWzMwOmXsaNsA9DWs2Rx+9h+efP7LRzRiV3NMws1HniCP2N7oJY45HuTWzEe/Am4D/DPiDND0T\naXWavhP4uwPifERi6DlpmNmIV+3DX4KImWluJrCgTi0au3x4yszMCnPSMDOzwpw0zKxpXXCBhxCp\nNycNM2tanZ1OGvXmpGFmZoU5aZiZWWFOGmZmVpiThpmZFeakYWZNa9kyP+q13pw0zKxpLV/upFFv\nuUlD0ixJGyVtknR5lToL0/L1kqblxUr6y1T3x5LuldSSyqdKekHSuvS6YSh20szMhkbNpCFpHLAI\nmAW0A3MktZXV6SB7JGsrcAlwY4HYr0bEGRHxNrJRxq4qWeXmiJiWXpce8h6amdmQyetpTCf7EN8S\nEXuBpcDssjrnA0sAImINMF7SxFqxEfFcSfxrgZ8f8p6Ymdmwy0sak4EnS+a3prIidSbVipX0JUk/\nBT4KfLmk3knp0NRqSWcV2gszM6uLvKRRdDD6VzzdKU9EfD4iTgBuAf42FW8HWiJiGvBpoFvS6wa7\nbjMbGzz2VP3lPU9jG9BSMt9C1mOoVWdKqnNEgViAbmAFQETsAfak6YckPQq0Ag+VB3V2dg5Mt7W1\n0d7enrMrlqenp6fRTTAblIkTe+juPrPRzRgVent76evry62XlzQeAFolTSXrBVwEzCmrcxfQBSyV\nNAPYFRE7JD1TLVZSa0RsSvGzgXWp/DhgZ0Tsl3QyWcJ4rFLDli1blrtzNnh+Rrg1G79nh8eBT0t8\nWc2kERH7JHUBq4BxwE0R0Sdpflq+OCJWSOqQtBnYDcyrFZtW/deS3gLsBx4FPpHKzwa+KGkv8BIw\nPyJ2HfRem5nZkMp93GtErARWlpUtLpvvKhqbyj9Upf5yYHlem8zMrDF8R7iZmRXmpGFmTctjT9Wf\nk4aZNS2PPVV/ThpmZlaYk4aZmRXmpGFmZoU5aZiZWWFOGmbWtDz2VP05aZhZ0+rsdNKoNycNMzMr\nzEnDzMwKc9IwM7PCnDTMzKwwJw0za1oee6r+nDTMrGl57Kn6y00akmZJ2ihpk6TLq9RZmJavlzQt\nL1bSX6a6P5Z0r6SWkmVXpvobJZ13qDtoZmZDp2bSkDQOWATMAtqBOZLayup0AKdGRCtwCXBjgdiv\nRsQZEfE24E7gqhTTTvZY2PYUd4Mk94bMzEaIvA/k6cDmiNgSEXuBpWTP9C51PrAEICLWAOMlTawV\nGxHPlcS/Fvh5mp4N3BYReyNiC7A5rcfMzEaAvMe9TgaeLJnfCryzQJ3JwKRasZK+BFwMvMDLiWES\n8KMK6zIzsxEgr6cRBdejwW44Ij4fEScANwMLhqANZjbGeOyp+svraWwDWkrmW8i+/deqMyXVOaJA\nLEA3sKLGurZValhnZ+fAdFtbG+3t7dX2wQrq6elpdBPMBmXixB66u89sdDNGhd7eXvr6+nLr5SWN\nB4BWSVOB7WQnqeeU1bkL6AKWSpoB7IqIHZKeqRYrqTUiNqX42cC6knV1S7qO7LBUK7C2UsOWLVuW\nu3M2eHPnzm10E8wGxe/Z4SFVPoBUM2lExD5JXcAqYBxwU0T0SZqfli+OiBWSOiRtBnYD82rFplX/\ntaS3APuBR4FPpJheSbcDvcA+4NKI8OEpM7MRIq+nQUSsBFaWlS0um+8qGpvKP1Rje9cC1+a1y8zM\n6s/3QJiZWWFOGmbWtDz2VP05aZhZ0/LYU/XnpGFmZoU5aZiZWWFOGmZmVpiThpmZFeakYWZNy2NP\n1Z+Thpk1rc5OJ416c9IwM7PCnDTMzKwwJw0zMyvMScPMzApz0jCzpuWxp+rPScPMmpbHnqq/3KQh\naZakjZI2Sbq8Sp2Fafl6SdPyYiV9TVJfqr9c0jGpfKqkFyStS68bhmInzcxsaNRMGpLGAYuAWUA7\nMEdSW1mdDuDUiGgFLgFuLBB7N3BaRJwB/AS4smSVmyNiWnpdeqg7aGZmQyevpzGd7EN8S0TsBZaS\nPdO71PnAEoCIWAOMlzSxVmxE3BMRL6X4NcCUIdkbMzMbVnlJYzLwZMn81lRWpM6kArEAfwysKJk/\nKR2aWi3prJz2mZlZHeU9IzwKrkcHs3FJnwf2RER3KtoOtETETklvB+6UdFpEPHcw6zez0S0be8on\nw+spL2lsA1pK5lvIegy16kxJdY6oFSvpY0AHcG5/WUTsAfak6YckPQq0Ag+VN6yzs3Nguq2tjfb2\n9pxdsTw9PT2NboLZoEyc2EN395mNbsao0NvbS19fX269vKTxANAqaSpZL+AiYE5ZnbuALmCppBnA\nrojYIemZarGSZgGfBc6JiBf7VyTpOGBnROyXdDJZwnisUsOWLVuWu3M2eHPnzm10E8wGxe/Z4SFV\nPoBUM2lExD5JXcAqYBxwU0T0SZqfli+OiBWSOiRtBnYD82rFplVfDxwJ3JMa9sN0pdQ5wDWS9gIv\nAfMjYteh7LiZmQ2dvJ4GEbESWFlWtrhsvqtobCpvrVJ/GeAuhJnZCOU7ws3MrDAnDTNrWh57qv6c\nNMysaXnsqfpz0jAzs8KcNMzMrDAnDTMzK8xJw8zMCnPSMLOmlY09ZfXkpGFmTauz00mj3pw0zMys\nMCcNMzMrzEnDzMwKc9IwM7PCnDTMrGl57Kn6c9Iws6blsafqLzdpSJolaaOkTZIur1JnYVq+XtK0\nvFhJX5PUl+ovl3RMybIrU/2Nks471B00M7OhUzNpSBoHLAJmAe3AHEltZXU6gFPTg5UuAW4sEHs3\ncFpEnAH8BLgyxbSTPRa2PcXdIMm9ITOzESLvA3k6sDkitkTEXmApMLuszvnAEoCIWAOMlzSxVmxE\n3BMRL6X4NcCUND0buC0i9kbEFmBzWo+ZmY0AeUljMvBkyfzWVFakzqQCsQB/DKxI05NSvbwYMzNr\ngLykEQXXo4PZuKTPA3sionsI2mBmY4zHnqq/w3OWbwNaSuZbOLAnUKnOlFTniFqxkj4GdADn5qxr\nW6WGdXZ2Dky3tbXR3t5ec0csX09PT6ObYDYoEyf20N19ZqObMSr09vbS19eXWy8vaTwAtEqaCmwn\nO0k9p6zOXUAXsFTSDGBXROyQ9Ey1WEmzgM8C50TEi2Xr6pZ0HdlhqVZgbaWGLVu2LHfnbPDmzp3b\n6CaYDYrfs8NDqnwAqWbSiIh9krqAVcA44KaI6JM0Py1fHBErJHVI2gzsBubVik2rvh44ErgnNeyH\nEXFpRPRKuh3oBfYBl0aED0+ZmY0QeT0NImIlsLKsbHHZfFfR2FTeWmN71wLX5rXLzMzqz/dAmJlZ\nYU4aZta0PPZU/TlpmFnT8thT9eekYQN6e3+j0U0wsxHOScMG9PUd3+gmmNkI56RhAzZtekOjm2Bm\nI1zuJbc2uq1enb0ANmyYxNVXZ9MzZ2YvM7NSasZ75yT5nr9hcMwxL/CLXxzV6GbYGHXssbBz5/Bv\nZ8IEePbZ4d9Os5NERLzitnAfnhrjFix4uVfxy18eNTC9YEFj22Vjz86dEDG41623dg86ph6JaTTz\n4akx7lOfyl4Ar3nNr1m9+lWNbZCZjWhOGmNc6TmN559/lc9pmFlNPqdhAyZMeJ6dO49udDNsjJKy\nw0eD0d3dPehRbg9mO2NRtXMa7mmMcaU9jV27jnZPw8xqck/DBvjqKWsk9zRGFvc0rKLSnsYvf3mU\nexpmVlPuJbeSZknaKGmTpMur1FmYlq+XNC0vVtKHJf2npP2S3l5SPlXSC5LWpdcNh7qDZmY2dGr2\nNCSNAxYB7yF7Vve/S7qr5Al8SOoATo2IVknvBG4EZuTEbgA+CCzmlTZHxLQK5TZEqj3GEe7jmmve\nDcA117xyqQ8Jmlne4anpZB/iWwAkLQVmA6VPHz8fWAIQEWskjZc0ETipWmxEbExlQ7cnVli1D//s\nWK8Tg5lVl3d4ajLwZMn81lRWpM6kArGVnJQOTa2WdFaB+mZmVid5PY2iXzuHqsuwHWiJiJ3pXMed\nkk6LiOeGaP1mZnYI8pLGNqClZL6FrMdQq86UVOeIArEHiIg9wJ40/ZCkR4FW4KHyup2dnQPTbW1t\ntLe35+yK5ZtLd3d3oxthY9bg3389PT112c5Y0NvbS19fX269mvdpSDoceAQ4l6wXsBaYU+FEeFdE\ndEiaASyIiBkFY+8DLouIB9P8ccDOiNgv6WTgfuC3ImJXWbt8n8Yw6Ozc4GcuW8P4Po2R5aDu04iI\nfZK6gFXAOOCmiOiTND8tXxwRKyR1SNoM7Abm1YpNjfkgsBA4DviOpHUR8T7gHOAaSXuBl4D55QnD\nhk9n5wbAScPMqsu9uS8iVgIry8oWl813FY1N5XcAd1QoXwYsy2uTmZk1hp+nYWZmhTlpmJlZYU4a\nZmZWmJOGDfCVU2aWx0nDBixf7qRhZrU5aZiZWWFOGmZmVpiThpmZFeakYWZmhTlp2IALLtjQ6CaY\n2QjnpGEDsrGnzMyqc9IwM7PCnDTMzKwwJw0zMyvMScPMzArLTRqSZknaKGmTpMur1FmYlq+XNC0v\nVtKHJf2npP3pWeCl67oy1d8o6bxD2TkbHI89ZWZ5aiYNSeOARcAsoB2YI6mtrE4HcGpEtAKXADcW\niN0AfJDsca6l62oHLkr1ZwE3SHJvqE489pSZ5cn7QJ4ObI6ILRGxF1gKzC6rcz6wBCAi1gDjJU2s\nFRsRGyPiJxW2Nxu4LSL2RsQWYHNaj5mZjQB5SWMy8GTJ/NZUVqTOpAKx5SaleoOJMTOzOslLGlFw\nPTrUhgxBG8zMbJgdnrN8G9BSMt/CgT2BSnWmpDpHFIjN296UVPYKnZ2dA9NtbW20t7fnrNryzaW7\nu7vRjbAxa/Dvv56enrpsZyzo7e2lr68vt54iqn+Rl3Q48AhwLrAdWAvMiYi+kjodQFdEdEiaASyI\niBkFY+8DLouIB9N8O9BNdh5jMvBdspPsBzRSUnmRDYHOzg2+gsoaRoLB/lt3d3czd+7cYd/OWCSJ\niHjFUaSaPY2I2CepC1gFjANuiog+SfPT8sURsUJSh6TNwG5gXq3Y1JgPAguB44DvSFoXEe+LiF5J\ntwO9wD7gUmeH+snGnnLSMLPq8g5PERErgZVlZYvL5ruKxqbyO4A7qsRcC1yb1y4zM6s/3wNhZmaF\nOWmYmVlhThpmZlaYk4YN8JVTZpbHScMGeOwpM8vjpGFmZoU5aZiZWWFOGmZmVpiThpmZFVZz7KmR\nymNP5Tv2WNi5c/i3M2ECPPvs8G/HxgAN52DZZfz5kava2FPuaYxSO3dm/xeDed16a/egY+qRmGxs\nEIN880XQfeutg46Rn7ZwSJw0zMysMCcNMzMrzEnDzMwKc9IwM7PCcpOGpFmSNkraJOnyKnUWpuXr\nJU3Li5V0rKR7JP1E0t2SxqfyqZJekLQuvW4Yip00M7OhUTNpSBoHLAJmAe3AHEltZXU6yB7J2gpc\nAtxYIPYK4J6IeDNwb5rvtzkipqXXpYe6g2ZmNnTyehrTyT7Et0TEXmApMLuszvnAEoCIWAOMlzQx\nJ3YgJv38g0PeEzMzG3Z5SWMy8GTJ/NZUVqTOpBqxx0fEjjS9Azi+pN5J6dDUakln5e+CmZnVS94z\nwoveBVPkVk5VWl9EhKT+8u1AS0TslPR24E5Jp0XEcwXbYWZmwygvaWwDWkrmW8h6DLXqTEl1jqhQ\nvi1N75A0MSJ+JulNwFMAEbEH2JOmH5L0KNAKPFTesM7OzoHptrY22tvbc3ZlrJlLd3f3oCJ6enrq\nsh2zyvyebaTe3l76+vpy69Uce0rS4cAjwLlkvYC1wJyI6Cup0wF0RUSHpBnAgoiYUStW0leBZyLi\nK5KuAMZHxBWSjgN2RsR+SScD9wO/FRG7ytrlsadySIMfXqe7u5u5c+cO+3bMKvF7dmSpNvZUzZ5G\nROyT1AWsAsYBN6UP/flp+eKIWCGpQ9JmYDcwr1ZsWvWXgdslfRzYAlyYys8GvihpL/ASML88YZiZ\nWePkHZ4iIlYCK8vKFpfNdxWNTeXPAu+pUL4cWJ7XJjMzawzfEW5mZoXl9jTMzOpl8I/UmMtHPjK4\niAkTBrsNK+WkYWYjwsGcnPZJ7frz4SkzMyvMScPMzApz0jAzs8Jq3tw3UvnmvgIGf0bx4PlvYQ3i\ncxrDp9rNfe5pjFIisv+mQby6b7110DEqPDyZ2dC74IINjW7CmOOkYWZNq7PTSaPenDTMzKwwJw0z\nMyvMScPMzApz0jAzs8J8ye0oVa8rbidMgGefrc+2zMp1dm5g2bLTG92MUanaJbdOGjbA17xbs/F7\ndvgc9H0akmZJ2ihpk6TLq9RZmJavlzQtL1bSsZLukfQTSXdLGl+y7MpUf6Ok8wa/q2ZmNlxqJg1J\n44BFwCygHZgjqa2sTgdwakS0ApcANxaIvQK4JyLeDNyb5pHUDlyU6s8CbpDk8y5mZiNE3gfydGBz\nRGyJiL3AUmB2WZ3zgSUAEbEGGC9pYk7sQEz6+QdpejZwW0TsjYgtwOa0HjMzGwHyksZk4MmS+a2p\nrEidSTVij4+IHWl6B3B8mp6U6tXanpmNMZIqvqBy+cvLbajlJY2ip5iK/HVUaX3pjHat7fg01xDz\nP6A1m4io+LrggguqLvPFMsMj78l924CWkvkWDuwJVKozJdU5okL5tjS9Q9LEiPiZpDcBT9VY1zYq\n8IdY/fl3biOR35f1lZc0HgBaJU0FtpOdpJ5TVucuoAtYKmkGsCsidkh6pkbsXcBHga+kn3eWlHdL\nuo7ssFQrsLa8UZUuAzMzs+FXM2lExD5JXcAqYBxwU0T0SZqfli+OiBWSOiRtBnYD82rFplV/Gbhd\n0seBLcCFKaZX0u1AL7APuNQ3ZJiZjRxNeXOfmZk1hu+BGIUkfVJSr6RnJf35QcT3DEe7zA6GpN+U\n9GNJD0plAeUDAAAE0UlEQVQ6+WDen5KukXTucLRvrHFPYxSS1AecGxHbG90Ws0Ml6QpgXER8qdFt\nMfc0Rh1J3wBOBv5V0qckXZ/KPyxpQ/rG9v1UdpqkNZLWpSFgTknlv0o/JelrKe5hSRem8pmSVkv6\nR0l9kr7VmL21ZiBpanqf/B9J/yFplaRXp/fQO1Kd4yQ9XiG2A/gz4BOS7k1l/e/PN0m6P71/N0g6\nU9Jhkm4pec/+Wap7i6TONH2upIfS8pskHZnKt0i6OvVoHpb0lvr8hpqLk8YoExF/Qna12kxgJy/f\n5/IF4LyIeBvwgVQ2H/i7iJgGvIOXL2/uj7kAOAN4K/Ae4Gvpbn+At5H9M7cDJ0s6c7j2yUaFU4FF\nEfFbwC6gk+x9VvNQR0SsAL4BXBcR/YeX+mPmAv+a3r9vBdYD04BJEXF6RLwVuLkkJiS9OpVdmJYf\nDnyipM7TEfEOsuGQLjvEfR6VnDRGL5W8AHqAJZL+Jy9fNfdD4HPpvMfUiHixbB1nAd2ReQr4PvDb\nZP9cayNie7q67cfA1GHdG2t2j0fEw2n6QQb/fql0mf1aYJ6kq4C3RsSvgEfJvsQslPR7wHNl63hL\nasvmVLYEOLukzvL086GDaOOY4KQxug18i4uITwB/QXbz5IOSjo2I28h6HS8AKyS9u0J8+T9r/zp/\nXVK2n/x7fmxsq/R+2Ud2OT7Aq/sXSro5HXL6l1orjIgfAO8i6yHfIuniiNhF1jteDfwJ8M3ysLL5\n8pEq+tvp93QVThqj28AHvqRTImJtRFwFPA1MkXQSsCUirge+DZQ/zeYHwEXpOPEbyb6RraXytz6z\nwdpCdlgU4EP9hRExLyKmRcTv1wqWdALZ4aRvkiWHt0t6A9lJ8+Vkh2SnlYQE8Agwtf/8HXAxWQ/a\nCnImHZ2i7AXwVUmtZB/4342Ih5U94+RiSXuB/wK+VBJPRNwh6XfIjhUH8NmIeErZEPfl39h8GZ7V\nUun98jdkN/leAnynQp1q8f3T7wYuS+/f54A/IhtJ4ma9/EiFKw5YScSvJc0D/lHS4WRfgr5RZRt+\nT1fgS27NzKwwH54yM7PCnDTMzKwwJw0zMyvMScPMzApz0jAzs8KcNMzMrDAnDTMzK8xJw6yB0g1m\nZk3DScNskCS9RtJ30jDzGyRdKOm3Jf1bKluT6rw6jaP0cBqKe2aK/5iku9JQ3/dIOlrS36e4hySd\n39g9NKvO33LMBm8WsC0i3g8g6fXAOrLhth+U9FrgReBTwP6IeGt6NsPdkt6c1jENOD0idkm6Frg3\nIv5Y0nhgjaTvRsTzdd8zsxzuaZgN3sPAeyV9WdJZwInAf0XEgwAR8auI2A+cCXwrlT0CPAG8mWxM\no3vSiKwA5wFXSFoH3Ae8imw0YrMRxz0Ns0GKiE2SpgHvB/6K7IO+mmojAu8um78gIjYNRfvMhpN7\nGmaDJOlNwIsRcSvZSK3TgYmS/lta/jpJ48iGlv9IKnszcAKwkVcmklXAJ0vWPw2zEco9DbPBO53s\n0bcvAXvIHhd6GHC9pKOA58kej3sDcKOkh8keOPTRiNgrqXzY7b8EFqR6hwGPAT4ZbiOSh0Y3M7PC\nfHjKzMwKc9IwM7PCnDTMzKwwJw0zMyvMScPMzApz0jAzs8KcNMzMrDAnDTMzK+z/A6uJAXC4L148\nAAAAAElFTkSuQmCC\n", + "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -1109,7 +1108,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 27, @@ -1118,9 +1117,9 @@ }, { "data": { - "image/png": "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\nTkSuQmCC\n", + "image/png": "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\nEvx/rHWCrxSlro8AAAAASUVORK5CYII=\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -1166,7 +1165,7 @@ "\tFilters =\t\n", " \t\tcell\t[10000]\n", "\tNuclides =\tU-235 U-238 \n", - "\tScores =\t['scatter-Y0,0', 'scatter-Y1,-1', 'scatter-Y1,0', 'scatter-Y1,1', 'scatter-Y2,-2', 'scatter-Y2,-1', 'scatter-Y2,0', 'scatter-Y2,1', 'scatter-Y2,2']\n", + "\tScores =\t[u'scatter-Y0,0', u'scatter-Y1,-1', u'scatter-Y1,0', u'scatter-Y1,1', u'scatter-Y2,-2', u'scatter-Y2,-1', u'scatter-Y2,0', u'scatter-Y2,1', u'scatter-Y2,2']\n", "\tEstimator =\tanalog\n", "\n" ] @@ -1217,143 +1216,143 @@ " U-235\n", " scatter-Y0,0\n", " 0.036453\n", - " 0.000941\n", + " 0.001219\n", " \n", " \n", " 1\n", " 10000\n", " U-235\n", " scatter-Y1,-1\n", - " -0.000725\n", - " 0.000261\n", + " 0.000302\n", + " 0.000314\n", " \n", " \n", " 2\n", " 10000\n", " U-235\n", " scatter-Y1,0\n", - " -0.000088\n", - " 0.000408\n", + " -0.000006\n", + " 0.000347\n", " \n", " \n", " 3\n", " 10000\n", " U-235\n", " scatter-Y1,1\n", - " 0.000986\n", - " 0.000412\n", + " 0.000244\n", + " 0.000286\n", " \n", " \n", " 4\n", " 10000\n", " U-235\n", " scatter-Y2,-2\n", - " 0.000098\n", - " 0.000204\n", + " 0.000184\n", + " 0.000211\n", " \n", " \n", " 5\n", " 10000\n", " U-235\n", " scatter-Y2,-1\n", - " -0.000358\n", - " 0.000247\n", + " 0.000067\n", + " 0.000173\n", " \n", " \n", " 6\n", " 10000\n", " U-235\n", " scatter-Y2,0\n", - " 0.000197\n", - " 0.000140\n", + " 0.000353\n", + " 0.000210\n", " \n", " \n", " 7\n", " 10000\n", " U-235\n", " scatter-Y2,1\n", - " -0.000084\n", - " 0.000196\n", + " -0.000266\n", + " 0.000263\n", " \n", " \n", " 8\n", " 10000\n", " U-235\n", " scatter-Y2,2\n", - " 0.000052\n", - " 0.000168\n", + " -0.000246\n", + " 0.000153\n", " \n", " \n", " 9\n", " 10000\n", " U-238\n", " scatter-Y0,0\n", - " 2.325600\n", - " 0.015545\n", + " 2.315893\n", + " 0.008243\n", " \n", " \n", " 10\n", " 10000\n", " U-238\n", " scatter-Y1,-1\n", - " -0.030089\n", - " 0.002460\n", + " -0.022028\n", + " 0.002316\n", " \n", " \n", " 11\n", " 10000\n", " U-238\n", " scatter-Y1,0\n", - " -0.004451\n", - " 0.003663\n", + " -0.003426\n", + " 0.002651\n", " \n", " \n", " 12\n", " 10000\n", " U-238\n", " scatter-Y1,1\n", - " 0.020832\n", - " 0.002831\n", + " 0.026620\n", + " 0.002084\n", " \n", " \n", " 13\n", " 10000\n", " U-238\n", " scatter-Y2,-2\n", - " -0.004149\n", - " 0.001530\n", + " -0.001295\n", + " 0.001627\n", " \n", " \n", " 14\n", " 10000\n", " U-238\n", " scatter-Y2,-1\n", - " 0.000735\n", - " 0.001729\n", + " 0.000759\n", + " 0.001426\n", " \n", " \n", " 15\n", " 10000\n", " U-238\n", " scatter-Y2,0\n", - " 0.003431\n", - " 0.002098\n", + " 0.005513\n", + " 0.001983\n", " \n", " \n", " 16\n", " 10000\n", " U-238\n", " scatter-Y2,1\n", - " 0.000385\n", - " 0.001263\n", + " 0.000431\n", + " 0.001862\n", " \n", " \n", " 17\n", " 10000\n", " U-238\n", " scatter-Y2,2\n", - " 0.000002\n", - " 0.001718\n", + " -0.001962\n", + " 0.001222\n", " \n", " \n", "\n", @@ -1362,24 +1361,24 @@ "text/plain": [ " cell nuclide score mean std. dev.\n", "bin \n", - "0 10000 U-235 scatter-Y0,0 0.036453 0.000941\n", - "1 10000 U-235 scatter-Y1,-1 -0.000725 0.000261\n", - "2 10000 U-235 scatter-Y1,0 -0.000088 0.000408\n", - "3 10000 U-235 scatter-Y1,1 0.000986 0.000412\n", - "4 10000 U-235 scatter-Y2,-2 0.000098 0.000204\n", - "5 10000 U-235 scatter-Y2,-1 -0.000358 0.000247\n", - "6 10000 U-235 scatter-Y2,0 0.000197 0.000140\n", - "7 10000 U-235 scatter-Y2,1 -0.000084 0.000196\n", - "8 10000 U-235 scatter-Y2,2 0.000052 0.000168\n", - "9 10000 U-238 scatter-Y0,0 2.325600 0.015545\n", - "10 10000 U-238 scatter-Y1,-1 -0.030089 0.002460\n", - "11 10000 U-238 scatter-Y1,0 -0.004451 0.003663\n", - "12 10000 U-238 scatter-Y1,1 0.020832 0.002831\n", - "13 10000 U-238 scatter-Y2,-2 -0.004149 0.001530\n", - "14 10000 U-238 scatter-Y2,-1 0.000735 0.001729\n", - "15 10000 U-238 scatter-Y2,0 0.003431 0.002098\n", - "16 10000 U-238 scatter-Y2,1 0.000385 0.001263\n", - "17 10000 U-238 scatter-Y2,2 0.000002 0.001718" + "0 10000 U-235 scatter-Y0,0 0.036453 0.001219\n", + "1 10000 U-235 scatter-Y1,-1 0.000302 0.000314\n", + "2 10000 U-235 scatter-Y1,0 -0.000006 0.000347\n", + "3 10000 U-235 scatter-Y1,1 0.000244 0.000286\n", + "4 10000 U-235 scatter-Y2,-2 0.000184 0.000211\n", + "5 10000 U-235 scatter-Y2,-1 0.000067 0.000173\n", + "6 10000 U-235 scatter-Y2,0 0.000353 0.000210\n", + "7 10000 U-235 scatter-Y2,1 -0.000266 0.000263\n", + "8 10000 U-235 scatter-Y2,2 -0.000246 0.000153\n", + "9 10000 U-238 scatter-Y0,0 2.315893 0.008243\n", + "10 10000 U-238 scatter-Y1,-1 -0.022028 0.002316\n", + "11 10000 U-238 scatter-Y1,0 -0.003426 0.002651\n", + "12 10000 U-238 scatter-Y1,1 0.026620 0.002084\n", + "13 10000 U-238 scatter-Y2,-2 -0.001295 0.001627\n", + "14 10000 U-238 scatter-Y2,-1 0.000759 0.001426\n", + "15 10000 U-238 scatter-Y2,0 0.005513 0.001983\n", + "16 10000 U-238 scatter-Y2,1 0.000431 0.001862\n", + "17 10000 U-238 scatter-Y2,2 -0.001962 0.001222" ] }, "execution_count": 29, @@ -1413,8 +1412,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "[[[ 0.00171834 0.01554515]\n", - " [ 0.00016768 0.00094081]]]\n" + "[[[ 0.00122163 0.00824348]\n", + " [ 0.00015287 0.00121882]]]\n" ] } ], @@ -1450,7 +1449,7 @@ "\tFilters =\t\n", " \t\tdistribcell\t[10002]\n", "\tNuclides =\ttotal \n", - "\tScores =\t['absorption', 'scatter']\n", + "\tScores =\t[u'absorption', u'scatter']\n", "\tEstimator =\ttracklength\n", "\n" ] @@ -1482,25 +1481,25 @@ "name": "stdout", "output_type": "stream", "text": [ - "[[[ 0.04682759]]\n", + "[[[ 0.0400168 ]]\n", "\n", - " [[ 0.03205271]]\n", + " [[ 0.05233031]]\n", "\n", - " [[ 0.03592433]]\n", + " [[ 0.03819276]]\n", "\n", - " [[ 0.02417979]]\n", + " [[ 0.02900783]]\n", "\n", - " [[ 0.02524314]]\n", + " [[ 0.03176394]]\n", "\n", - " [[ 0.02390359]]\n", + " [[ 0.03046477]]\n", "\n", - " [[ 0.0274475 ]]\n", + " [[ 0.03864163]]\n", "\n", - " [[ 0.02827721]]\n", + " [[ 0.02455132]]\n", "\n", - " [[ 0.0231313 ]]\n", + " [[ 0.02282716]]\n", "\n", - " [[ 0.01898386]]]\n" + " [[ 0.02162945]]]\n" ] } ], @@ -1552,141 +1551,141 @@ " 558\n", " 279\n", " absorption\n", - " 0.000095\n", - " 0.000009\n", + " 0.000085\n", + " 0.000008\n", " \n", " \n", " 559\n", " 279\n", " scatter\n", - " 0.013611\n", - " 0.000544\n", + " 0.013429\n", + " 0.000449\n", " \n", " \n", " 560\n", " 280\n", " absorption\n", - " 0.000096\n", - " 0.000009\n", + " 0.000095\n", + " 0.000014\n", " \n", " \n", " 561\n", " 280\n", " scatter\n", - " 0.013999\n", - " 0.000568\n", + " 0.014770\n", + " 0.000783\n", " \n", " \n", " 562\n", " 281\n", " absorption\n", - " 0.000117\n", - " 0.000015\n", + " 0.000107\n", + " 0.000013\n", " \n", " \n", " 563\n", " 281\n", " scatter\n", - " 0.015951\n", - " 0.000682\n", + " 0.015044\n", + " 0.000605\n", " \n", " \n", " 564\n", " 282\n", " absorption\n", - " 0.000104\n", - " 0.000011\n", + " 0.000110\n", + " 0.000010\n", " \n", " \n", " 565\n", " 282\n", " scatter\n", - " 0.016057\n", - " 0.000574\n", + " 0.016090\n", + " 0.000795\n", " \n", " \n", " 566\n", " 283\n", " absorption\n", - " 0.000117\n", - " 0.000013\n", + " 0.000121\n", + " 0.000012\n", " \n", " \n", " 567\n", " 283\n", " scatter\n", - " 0.015997\n", - " 0.000706\n", + " 0.017010\n", + " 0.000793\n", " \n", " \n", " 568\n", " 284\n", " absorption\n", - " 0.000108\n", + " 0.000110\n", " 0.000007\n", " \n", " \n", " 569\n", " 284\n", " scatter\n", - " 0.016720\n", - " 0.000639\n", + " 0.017010\n", + " 0.000430\n", " \n", " \n", " 570\n", " 285\n", " absorption\n", - " 0.000116\n", - " 0.000008\n", + " 0.000112\n", + " 0.000007\n", " \n", " \n", " 571\n", " 285\n", " scatter\n", - " 0.017764\n", - " 0.000639\n", + " 0.017499\n", + " 0.000615\n", " \n", " \n", " 572\n", " 286\n", " absorption\n", - " 0.000111\n", - " 0.000014\n", + " 0.000127\n", + " 0.000016\n", " \n", " \n", " 573\n", " 286\n", " scatter\n", - " 0.018101\n", - " 0.000766\n", + " 0.017716\n", + " 0.000690\n", " \n", " \n", " 574\n", " 287\n", " absorption\n", - " 0.000115\n", - " 0.000012\n", + " 0.000119\n", + " 0.000013\n", " \n", " \n", " 575\n", " 287\n", " scatter\n", - " 0.018411\n", - " 0.000655\n", + " 0.018041\n", + " 0.000702\n", " \n", " \n", " 576\n", " 288\n", " absorption\n", - " 0.000138\n", - " 0.000014\n", + " 0.000125\n", + " 0.000013\n", " \n", " \n", " 577\n", " 288\n", " scatter\n", - " 0.019154\n", - " 0.000763\n", + " 0.018212\n", + " 0.000715\n", " \n", " \n", "\n", @@ -1695,26 +1694,26 @@ "text/plain": [ " distribcell score mean std. dev.\n", "bin \n", - "558 279 absorption 0.000095 0.000009\n", - "559 279 scatter 0.013611 0.000544\n", - "560 280 absorption 0.000096 0.000009\n", - "561 280 scatter 0.013999 0.000568\n", - "562 281 absorption 0.000117 0.000015\n", - "563 281 scatter 0.015951 0.000682\n", - "564 282 absorption 0.000104 0.000011\n", - "565 282 scatter 0.016057 0.000574\n", - "566 283 absorption 0.000117 0.000013\n", - "567 283 scatter 0.015997 0.000706\n", - "568 284 absorption 0.000108 0.000007\n", - "569 284 scatter 0.016720 0.000639\n", - "570 285 absorption 0.000116 0.000008\n", - "571 285 scatter 0.017764 0.000639\n", - "572 286 absorption 0.000111 0.000014\n", - "573 286 scatter 0.018101 0.000766\n", - "574 287 absorption 0.000115 0.000012\n", - "575 287 scatter 0.018411 0.000655\n", - "576 288 absorption 0.000138 0.000014\n", - "577 288 scatter 0.019154 0.000763" + "558 279 absorption 0.000085 0.000008\n", + "559 279 scatter 0.013429 0.000449\n", + "560 280 absorption 0.000095 0.000014\n", + "561 280 scatter 0.014770 0.000783\n", + "562 281 absorption 0.000107 0.000013\n", + "563 281 scatter 0.015044 0.000605\n", + "564 282 absorption 0.000110 0.000010\n", + "565 282 scatter 0.016090 0.000795\n", + "566 283 absorption 0.000121 0.000012\n", + "567 283 scatter 0.017010 0.000793\n", + "568 284 absorption 0.000110 0.000007\n", + "569 284 scatter 0.017010 0.000430\n", + "570 285 absorption 0.000112 0.000007\n", + "571 285 scatter 0.017499 0.000615\n", + "572 286 absorption 0.000127 0.000016\n", + "573 286 scatter 0.017716 0.000690\n", + "574 287 absorption 0.000119 0.000013\n", + "575 287 scatter 0.018041 0.000702\n", + "576 288 absorption 0.000125 0.000013\n", + "577 288 scatter 0.018212 0.000715" ] }, "execution_count": 33, @@ -1816,8 +1815,8 @@ " 10000\n", " 0\n", " absorption\n", - " 0.000122\n", - " 0.000010\n", + " 0.000136\n", + " 0.000017\n", " \n", " \n", " 1\n", @@ -1831,8 +1830,8 @@ " 10000\n", " 0\n", " scatter\n", - " 0.018596\n", - " 0.000871\n", + " 0.018504\n", + " 0.000740\n", " \n", " \n", " 2\n", @@ -1846,8 +1845,8 @@ " 10000\n", " 1\n", " absorption\n", - " 0.000206\n", - " 0.000014\n", + " 0.000231\n", + " 0.000031\n", " \n", " \n", " 3\n", @@ -1861,8 +1860,8 @@ " 10000\n", " 1\n", " scatter\n", - " 0.029733\n", - " 0.000953\n", + " 0.029149\n", + " 0.001525\n", " \n", " \n", " 4\n", @@ -1876,8 +1875,8 @@ " 10000\n", " 2\n", " absorption\n", - " 0.000280\n", - " 0.000018\n", + " 0.000306\n", + " 0.000032\n", " \n", " \n", " 5\n", @@ -1891,8 +1890,8 @@ " 10000\n", " 2\n", " scatter\n", - " 0.038494\n", - " 0.001383\n", + " 0.039770\n", + " 0.001519\n", " \n", " \n", " 6\n", @@ -1906,8 +1905,8 @@ " 10000\n", " 3\n", " absorption\n", - " 0.000384\n", - " 0.000026\n", + " 0.000339\n", + " 0.000028\n", " \n", " \n", " 7\n", @@ -1921,8 +1920,8 @@ " 10000\n", " 3\n", " scatter\n", - " 0.048839\n", - " 0.001181\n", + " 0.046708\n", + " 0.001355\n", " \n", " \n", " 8\n", @@ -1936,8 +1935,8 @@ " 10000\n", " 4\n", " absorption\n", - " 0.000457\n", - " 0.000023\n", + " 0.000433\n", + " 0.000031\n", " \n", " \n", " 9\n", @@ -1951,8 +1950,8 @@ " 10000\n", " 4\n", " scatter\n", - " 0.058061\n", - " 0.001466\n", + " 0.056359\n", + " 0.001790\n", " \n", " \n", " 10\n", @@ -1966,8 +1965,8 @@ " 10000\n", " 5\n", " absorption\n", - " 0.000494\n", - " 0.000026\n", + " 0.000538\n", + " 0.000028\n", " \n", " \n", " 11\n", @@ -1981,8 +1980,8 @@ " 10000\n", " 5\n", " scatter\n", - " 0.065874\n", - " 0.001575\n", + " 0.064943\n", + " 0.001978\n", " \n", " \n", " 12\n", @@ -1996,8 +1995,8 @@ " 10000\n", " 6\n", " absorption\n", - " 0.000490\n", - " 0.000032\n", + " 0.000588\n", + " 0.000028\n", " \n", " \n", " 13\n", @@ -2011,8 +2010,8 @@ " 10000\n", " 6\n", " scatter\n", - " 0.072420\n", - " 0.001988\n", + " 0.070231\n", + " 0.002714\n", " \n", " \n", " 14\n", @@ -2026,8 +2025,8 @@ " 10000\n", " 7\n", " absorption\n", - " 0.000605\n", - " 0.000042\n", + " 0.000670\n", + " 0.000041\n", " \n", " \n", " 15\n", @@ -2041,8 +2040,8 @@ " 10000\n", " 7\n", " scatter\n", - " 0.078802\n", - " 0.002228\n", + " 0.075852\n", + " 0.001862\n", " \n", " \n", " 16\n", @@ -2056,8 +2055,8 @@ " 10000\n", " 8\n", " absorption\n", - " 0.000627\n", - " 0.000037\n", + " 0.000745\n", + " 0.000039\n", " \n", " \n", " 17\n", @@ -2071,8 +2070,8 @@ " 10000\n", " 8\n", " scatter\n", - " 0.083684\n", - " 0.001936\n", + " 0.086234\n", + " 0.001968\n", " \n", " \n", " 18\n", @@ -2086,8 +2085,8 @@ " 10000\n", " 9\n", " absorption\n", - " 0.000711\n", - " 0.000040\n", + " 0.000731\n", + " 0.000039\n", " \n", " \n", " 19\n", @@ -2101,8 +2100,8 @@ " 10000\n", " 9\n", " scatter\n", - " 0.088989\n", - " 0.001689\n", + " 0.090448\n", + " 0.001956\n", " \n", " \n", "\n", @@ -2138,26 +2137,26 @@ " \n", " \n", "bin \n", - "0 0.000122 0.000010 \n", - "1 0.018596 0.000871 \n", - "2 0.000206 0.000014 \n", - "3 0.029733 0.000953 \n", - "4 0.000280 0.000018 \n", - "5 0.038494 0.001383 \n", - "6 0.000384 0.000026 \n", - "7 0.048839 0.001181 \n", - "8 0.000457 0.000023 \n", - "9 0.058061 0.001466 \n", - "10 0.000494 0.000026 \n", - "11 0.065874 0.001575 \n", - "12 0.000490 0.000032 \n", - "13 0.072420 0.001988 \n", - "14 0.000605 0.000042 \n", - "15 0.078802 0.002228 \n", - "16 0.000627 0.000037 \n", - "17 0.083684 0.001936 \n", - "18 0.000711 0.000040 \n", - "19 0.088989 0.001689 " + "0 0.000136 0.000017 \n", + "1 0.018504 0.000740 \n", + "2 0.000231 0.000031 \n", + "3 0.029149 0.001525 \n", + "4 0.000306 0.000032 \n", + "5 0.039770 0.001519 \n", + "6 0.000339 0.000028 \n", + "7 0.046708 0.001355 \n", + "8 0.000433 0.000031 \n", + "9 0.056359 0.001790 \n", + "10 0.000538 0.000028 \n", + "11 0.064943 0.001978 \n", + "12 0.000588 0.000028 \n", + "13 0.070231 0.002714 \n", + "14 0.000670 0.000041 \n", + "15 0.075852 0.001862 \n", + "16 0.000745 0.000039 \n", + "17 0.086234 0.001968 \n", + "18 0.000731 0.000039 \n", + "19 0.090448 0.001956 " ] }, "execution_count": 34, @@ -2210,38 +2209,38 @@ " \n", " \n", " mean\n", - " 0.000414\n", + " 0.000416\n", " 0.000025\n", " \n", " \n", " std\n", - " 0.000241\n", - " 0.000010\n", + " 0.000238\n", + " 0.000011\n", " \n", " \n", " min\n", - " 0.000013\n", - " 0.000003\n", + " 0.000023\n", + " 0.000004\n", " \n", " \n", " 25%\n", - " 0.000204\n", + " 0.000206\n", " 0.000017\n", " \n", " \n", " 50%\n", - " 0.000387\n", + " 0.000391\n", " 0.000024\n", " \n", " \n", " 75%\n", - " 0.000594\n", + " 0.000626\n", " 0.000031\n", " \n", " \n", " max\n", - " 0.000919\n", - " 0.000060\n", + " 0.000928\n", + " 0.000061\n", " \n", " \n", "\n", @@ -2252,13 +2251,13 @@ " \n", " \n", "count 289.000000 289.000000\n", - "mean 0.000414 0.000025\n", - "std 0.000241 0.000010\n", - "min 0.000013 0.000003\n", - "25% 0.000204 0.000017\n", - "50% 0.000387 0.000024\n", - "75% 0.000594 0.000031\n", - "max 0.000919 0.000060" + "mean 0.000416 0.000025\n", + "std 0.000238 0.000011\n", + "min 0.000023 0.000004\n", + "25% 0.000206 0.000017\n", + "50% 0.000391 0.000024\n", + "75% 0.000626 0.000031\n", + "max 0.000928 0.000061" ] }, "execution_count": 35, @@ -2293,7 +2292,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Mann-Whitney Test p-value: 0.378626583393\n" + "Mann-Whitney Test p-value: 0.474494586047\n" ] } ], @@ -2331,7 +2330,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Mann-Whitney Test p-value: 7.18782749267e-43\n" + "Mann-Whitney Test p-value: 1.364780046e-41\n" ] } ], @@ -2377,7 +2376,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 38, @@ -2386,9 +2385,9 @@ }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -2415,7 +2414,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 39, @@ -2424,9 +2423,9 @@ }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAEZCAYAAAB4hzlwAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3XmYFOW5/vHvM8OOw+YyLAIjriCioIKKUUPiliguaGQR\nd/QoLkGJJvH8FJccY456ohiMwQ3UARdccImyuCOKCwo4CLIJKDsy7AjM8/ujis4wMNAz093V3XN/\nrquv6a6ut/qu6Zl+ut6qesvcHREREYCcqAOIiEj6UFEQEZEYFQUREYlRURARkRgVBRERiVFREBGR\nGBUFkXKY2Z/MbGjUOURSSUVBUsrMjjezj81slZmtMLOPzOyoKi7zEjP7sMy0p8zsrqos193vcfd+\nVVlGecysxMzWmtkaM/vBzB4ysxpxth1kZk8nI5eIioKkjJk1AF4HHgQaAy2AO4BNUebaGTPLTcHL\ndHD3POAE4FzgyhS8psguqShIKh0EuLs/54GN7j7W3adum8HM+plZkZmtNrNvzKxjOP2PZjar1PSz\nw+ltgUeAY8Nv3T+ZWT+gN3BzOO3VcN7mZjbKzJaa2Rwzu67U6w4ysxfN7GkzKwYuKf2N3MwKwm/3\nF5nZ92a2zMz+XKp9XTMbZmYrw/w3m9mCeH4p7j4bmAC0K7W8B81svpkVm9nnZnZ8OP004E/ABeG6\nTQ6nNzSzx83sRzNbaGZ3mVlO+NwBZvZ+uHW2zMxGVvSNk+pDRUFSaQawNezaOc3MGpd+0szOB24H\n+rp7A6A7sCJ8ehZwfDj9DuAZM8t39+nAfwET3T3P3Ru7+1DgWeDecNpZ4Qfka8BkoDnwK+D3ZnZK\nqQjdgRfcvWHYfmdjwHQlKG6/Am4zs4PD6bcDrYD9gJOBC8tpv90qh+t9CPALYFKp5yYBhxNsURUC\nL5hZLXd/C/gfYGS4bh3D+Z8Cfgb2BzoCpwBXhM/dBbzl7o0Its4e2k0uqcZUFCRl3H0NcDzBh+VQ\nYKmZvWpm+4SzXEHwQf5FOP9sd58f3n/R3ReH958HvgO6hO2snJcsPf1oYC93v9vdt7j7XOAxoGep\neT5299Hha2wsZ7l3uPsmd58CfE3wwQ1wPvA/7l7s7j8QdJGVl2ubL81sLVAEvOjuw7c94e7PuvtP\n7l7i7g8AtYFtBchKL9vM8oHTgQHuvsHdlwF/L7VuPwMFZtbC3X929493k0uqMRUFSSl3/9bdL3X3\nlkB7gm/tfw+f3heYvbN2YbfN5LB76Kew7Z4VeOnWQPNt7cNl/AnYp9Q8C+NYzuJS99cDe4T3mwOl\nu4viWVZHd98DuAC4yMxab3vCzAaG3VCrwqwNgb3KWU5roCawqNS6/RPYO3z+ZoIiMsnMppnZpXFk\nk2oqrqMdRJLB3WeY2TD+s4N1AXBA2fnCD8t/Ad0Iuok87Evf9m15Z900ZafNB+a6+0HlxdlJm4oM\nIbwIaAl8Gz5uGW9Dd3/BzM4CBgGXmtkvgD8A3dz9GwAzW0n567uAYGf9nu5espPlLyH8HZtZV2Cc\nmb3v7nPizSjVh7YUJGXM7GAzu9HMWoSPWwK9gInhLI8BA82skwUOMLNWQH2CD8LlQE74Tbd9qUUv\nAfY1s5plprUp9XgSsCbcAVzXzHLNrL3953DYnXX17K77p7TngT+ZWaNw/a6lYkXlr0AvM9sXyAO2\nAMvNrJaZ3QY0KDXvYoLuIANw90XAGOABM8szsxwz29/MToBgX024XIBVYa4diocIqChIaq0h2A/w\nadiXPhGYAtwEwX4D4C8EO1ZXAy8Bjd29CLg/nH8xQUH4qNRyxwPfAIvNbGk47XGgXdid8lL4DfoM\n4AhgDrCMYOtj24dteVsKXuZxee4k6DKaS/AB/QJBX355tluWu08D3gFuBN4KbzOBecAGgi2dbV4I\nf64ws8/D+xcBtQj2T6wM52kaPncU8ImZrQFeBa5393m7yCbVmCXrIjvht8DhBH22DvzL3R8ysybA\ncwT9oPOA37n7qqSEEImImV1N8Lf9y6iziFREMrcUNhMcDXEocAzQ34Jjyv8IjA37dseHj0Uympk1\nNbOuYdfNwQTf+F+OOpdIRSWtKLj7Ynf/Kry/FphOcIx0d2BYONsw4OxkZRBJoVoER/ysJviy8wow\nJNJEIpWQtO6j7V7ErAB4n6AveL67Nw6nG7By22MREYlW0nc0m9kewCjghvDkpRgPKlLyq5KIiMQl\nqecphIcIjgKedvdXwslLzKypuy82s2bA0p20U6EQEakEd6/IodQ7SNqWQtg19DhQ5O5/L/XUaODi\n8P7FBH2vO3D3rL2de+65kWfIhPUL/xLK3KL/29D7l7m3bF4398R8l07mlkJXgkHBpmwbyZFgWIG/\nAs+b2eWEh6QmMYOIiFRA0oqCu39E+Vsiv07W64qISOXpjOYItG3bNuoISaX1y2zZvH7ZvG6JoqIQ\ngXbt2u1+pgym9cts2bx+2bxuiaJRUkVkp8Lx9rJOnz59oo6QEInasVyWioKIlCtZHzxSNcks2Oo+\nEhGRGBUFERGJUVEQEZEYFQUREYlRURCRjFJQUMD48eNjj0eOHEmTJk344IMPyMnJIS8vj7y8PJo2\nbcqZZ57JuHHjdmhfr1692Hx5eXlcf/31qV6NtKWiICIZxcxiR98MGzaMa6+9ljfffJNWrVoBUFxc\nzJo1a5gyZQonn3wy55xzDsOGDduu/euvv86aNWtit4ceeiiSdUlHKgoiknHcnUcffZSBAwcyZswY\njjnmmB3m2Weffbj++usZNGgQt9xySwQpM5OKgohknCFDhnD77bfzzjvv0KlTp13Oe84557B06VJm\nzJgRm6bzL8qnk9dEpFLsjsScQOW3V+wD2t0ZN24c3bp1o3379rudv3nz5gCsXLky1v7ss8+mRo3/\nfPzdd999XH755RXKka1UFESkUir6YZ4oZsY///lP7rrrLq644goef/zxXc7/ww8/ANCkSZNY+1df\nfZVu3bolPWsmUveRiGSc/Px8xo8fz4cffsg111yzy3lffvll8vPzOfjgg1OULrOpKIhIRmrWrBnj\nx4/nrbfe4sYbb4xN37a/YMmSJTz88MPceeed3HPPPdu11T6F8qn7SEQyVsuWLXnnnXc44YQTWLx4\nMQCNGjXC3alfvz5HH300L774Iqeccsp27c4880xyc3Njj0855RRGjRqV0uzpSkVBRDLK3Llzt3tc\nUFDA/PnzASgsLKxwe9meuo9ERCRGRUFERGJUFEREJEZFQUREYlQUREQkRkVBRERiVBRERCRGRUFE\nRGJUFEQkq7Rv354PPvgg6hgZS0VBROKy7YpnybzFo+zlOAGeeuopfvGLXwAwbdo0TjjhhF0uY968\neeTk5FBSUlK5X0YW0zAXIlIByRxILr6iUJECsjvJGhhv69at242tlEm0pSAiWaWgoIB33nkHgEmT\nJnHUUUfRsGFDmjZtysCBAwFiWxKNGjUiLy+PTz/9FHfn7rvvpqCggPz8fC6++GJWr14dW+7w4cNp\n3bo1e+21V2y+ba8zaNAgzjvvPPr27UvDhg0ZNmwYn332GcceeyyNGzemefPmXHfddWzevDm2vJyc\nHB555BEOPPBAGjRowG233cbs2bM59thjadSoET179txu/lRRURCRjLOrb/iltyJuuOEGBgwYQHFx\n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\n", + "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -2459,7 +2458,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", - "version": "2.7.8" + "version": "2.7.9" } }, "nbformat": 4, diff --git a/docs/source/pythonapi/examples/post-processing.ipynb b/docs/source/pythonapi/examples/post-processing.ipynb new file mode 100644 index 000000000..1bd7ee49a --- /dev/null +++ b/docs/source/pythonapi/examples/post-processing.ipynb @@ -0,0 +1,1121 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook demonstrates some basic post-processing tasks that can be performed with the Python API, such as plotting a 2D mesh tally and plotting neutron source sites from an eigenvalue calculation. The problem we will use is a simple reflected pin-cell." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from IPython.display import Image\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "import openmc\n", + "from openmc.statepoint import StatePoint\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generate Input Files" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we need to define materials that will be used in the problem. Before defining a material, we must create nuclides that are used in the material." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Instantiate some Nuclides\n", + "h1 = openmc.Nuclide('H-1')\n", + "b10 = openmc.Nuclide('B-10')\n", + "o16 = openmc.Nuclide('O-16')\n", + "u235 = openmc.Nuclide('U-235')\n", + "u238 = openmc.Nuclide('U-238')\n", + "zr90 = openmc.Nuclide('Zr-90')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With the nuclides we defined, we will now create three materials for the fuel, water, and cladding of the fuel pin." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# 1.6 enriched fuel\n", + "fuel = openmc.Material(name='1.6% Fuel')\n", + "fuel.set_density('g/cm3', 10.31341)\n", + "fuel.add_nuclide(u235, 3.7503e-4)\n", + "fuel.add_nuclide(u238, 2.2625e-2)\n", + "fuel.add_nuclide(o16, 4.6007e-2)\n", + "\n", + "# borated water\n", + "water = openmc.Material(name='Borated Water')\n", + "water.set_density('g/cm3', 0.740582)\n", + "water.add_nuclide(h1, 4.9457e-2)\n", + "water.add_nuclide(o16, 2.4732e-2)\n", + "water.add_nuclide(b10, 8.0042e-6)\n", + "\n", + "# zircaloy\n", + "zircaloy = openmc.Material(name='Zircaloy')\n", + "zircaloy.set_density('g/cm3', 6.55)\n", + "zircaloy.add_nuclide(zr90, 7.2758e-3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With our three materials, we can now create a materials file object that can be exported to an actual XML file." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Instantiate a MaterialsFile, add Materials\n", + "materials_file = openmc.MaterialsFile()\n", + "materials_file.add_material(fuel)\n", + "materials_file.add_material(water)\n", + "materials_file.add_material(zircaloy)\n", + "materials_file.default_xs = '71c'\n", + "\n", + "# Export to \"materials.xml\"\n", + "materials_file.export_to_xml()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's move on to the geometry. Our problem will have three regions for the fuel, the clad, and the surrounding coolant. The first step is to create the bounding surfaces -- in this case two cylinders and six reflective planes." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Create cylinders for the fuel and clad\n", + "fuel_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, R=0.39218)\n", + "clad_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, R=0.45720)\n", + "\n", + "# Create boundary planes to surround the geometry\n", + "# Use both reflective and vacuum boundaries to make life interesting\n", + "min_x = openmc.XPlane(x0=-0.63, boundary_type='reflective')\n", + "max_x = openmc.XPlane(x0=+0.63, boundary_type='reflective')\n", + "min_y = openmc.YPlane(y0=-0.63, boundary_type='reflective')\n", + "max_y = openmc.YPlane(y0=+0.63, boundary_type='reflective')\n", + "min_z = openmc.ZPlane(z0=-0.63, boundary_type='reflective')\n", + "max_z = openmc.ZPlane(z0=+0.63, boundary_type='reflective')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With the surfaces defined, we can now create cells that are defined by intersections of half-spaces created by the surfaces." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Create a Universe to encapsulate a fuel pin\n", + "pin_cell_universe = openmc.Universe(name='1.6% Fuel Pin')\n", + "\n", + "# Create fuel Cell\n", + "fuel_cell = openmc.Cell(name='1.6% Fuel')\n", + "fuel_cell.fill = fuel\n", + "fuel_cell.add_surface(fuel_outer_radius, halfspace=-1)\n", + "pin_cell_universe.add_cell(fuel_cell)\n", + "\n", + "# Create a clad Cell\n", + "clad_cell = openmc.Cell(name='1.6% Clad')\n", + "clad_cell.fill = zircaloy\n", + "clad_cell.add_surface(fuel_outer_radius, halfspace=+1)\n", + "clad_cell.add_surface(clad_outer_radius, halfspace=-1)\n", + "pin_cell_universe.add_cell(clad_cell)\n", + "\n", + "# Create a moderator Cell\n", + "moderator_cell = openmc.Cell(name='1.6% Moderator')\n", + "moderator_cell.fill = water\n", + "moderator_cell.add_surface(clad_outer_radius, halfspace=+1)\n", + "pin_cell_universe.add_cell(moderator_cell)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "OpenMC requires that there is a \"root\" universe. Let us create a root cell that is filled by the pin cell universe and then assign it to the root universe." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Create root Cell\n", + "root_cell = openmc.Cell(name='root cell')\n", + "root_cell.fill = pin_cell_universe\n", + "\n", + "# Add boundary planes\n", + "root_cell.add_surface(min_x, halfspace=+1)\n", + "root_cell.add_surface(max_x, halfspace=-1)\n", + "root_cell.add_surface(min_y, halfspace=+1)\n", + "root_cell.add_surface(max_y, halfspace=-1)\n", + "root_cell.add_surface(min_z, halfspace=+1)\n", + "root_cell.add_surface(max_z, halfspace=-1)\n", + "\n", + "# Create root Universe\n", + "root_universe = openmc.Universe(universe_id=0, name='root universe')\n", + "root_universe.add_cell(root_cell)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now must create a geometry that is assigned a root universe, put the geometry into a geometry file, and export it to XML." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Create Geometry and set root Universe\n", + "geometry = openmc.Geometry()\n", + "geometry.root_universe = root_universe" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Instantiate a GeometryFile\n", + "geometry_file = openmc.GeometryFile()\n", + "geometry_file.geometry = geometry\n", + "\n", + "# Export to \"geometry.xml\"\n", + "geometry_file.export_to_xml()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With the geometry and materials finished, we now just need to define simulation parameters. In this case, we will use 10 inactive batches and 90 active batches each with 5000 particles." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# OpenMC simulation parameters\n", + "batches = 100\n", + "inactive = 10\n", + "particles = 5000\n", + "\n", + "# Instantiate a SettingsFile\n", + "settings_file = openmc.SettingsFile()\n", + "settings_file.batches = batches\n", + "settings_file.inactive = inactive\n", + "settings_file.particles = particles\n", + "source_bounds = [-0.63, -0.63, -0.63, 0.63, 0.63, 0.63]\n", + "settings_file.set_source_space('box', source_bounds)\n", + "\n", + "# Export to \"settings.xml\"\n", + "settings_file.export_to_xml()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us also create a plot file that we can use to verify that our pin cell geometry was created successfully." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Instantiate a Plot\n", + "plot = openmc.Plot(plot_id=1)\n", + "plot.filename = 'materials-xy'\n", + "plot.origin = [0, 0, 0]\n", + "plot.width = [1.26, 1.26]\n", + "plot.pixels = [250, 250]\n", + "plot.color = 'mat'\n", + "\n", + "# Instantiate a PlotsFile, add Plot, and export to \"plots.xml\"\n", + "plot_file = openmc.PlotsFile()\n", + "plot_file.add_plot(plot)\n", + "plot_file.export_to_xml()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With the plots.xml file, we can now generate and view the plot. OpenMC outputs plots in .ppm format, which can be converted into a compressed format like .png with the convert utility." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Run openmc in plotting mode\n", + "executor = openmc.Executor()\n", + "executor.plot_geometry(output=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///9yEhLpgJFNv8Tq\nQYT7AAAAAWJLR0QAiAUdSAAAAAd0SU1FB98JEwAiCb5uYN4AAALKSURBVGje7dpLcqQwDAbgHHE2\nYeEj+D4cwQucBUfo+3CEXoSp8OhuhF70T4qpKXmdr21LogK2Pj7A8QmNP+HDhw8fPnz48Kf6VH9G\n+66vy+je8k19jnf8C5dXIPv86ms56lPdjvaYbyodx3ze+XLE76cXFiD4zPji99z0/AJ4n1lfvJ6f\nnl0A6x+578efMSg1wPr172/jPO5yFXM+Ef78gdblM+WPHyguP//t1/g6pA0wfln+ho/fwgYYn19C\n/xwDvwHGc9OvC+hs37DTrwuwfWanXxdQTC9Mvyygs3wjTL8uwPJpn/tNDbSGz7T0SBEWw4vLXzbQ\n6b6RoveIoO6TvPxlA63qs7z8ZQPF9F+SH22vbX8OQKf5Rtv+EgDNJ3X58wZaxWd1+fMGiuFvir8b\nvjp8J/tGy/6jAmRvhW8fwL3vVT+o3grfPoB7r/IpALI3tz8FoJN84/NV873hB8UnM3xzANtf8nb4\ndwmg3grfFEDJO8JPE0i9Ff4pAYL3pI8mkHor/HMCeO9JH00g9SafEsh7T/ppARBvp48UwJnelT5S\nACd7O31TAlnvKx9SQCd7B58KgPO+8iMFuPWe9E8F8BveWX7bAjzX9y4//Jve+fhsH6Ctv7n8PTzj\nvY/v9gEOHz58+PBX+6v/f/wPvnd54f3j6venE/yl769Xv7+j3x/o98/V32/o9+fl389Xnx+g5x/o\n+Qt6/oOeP6HnX+j5G3z+h54/ouefV5/foufP6Pk3ev4On/+j9w/o/Qd6/4Le/6D3T/D9V67Y/ZsV\nQBq+s+8f0ftP+P41axXguP9NWgDuu/Cdfv+N3r/D9/9TAID+A7T/Ae2/gPs/0P4TtP8F7r9J3AIO\n9P+g/Udw/9Oygbf7r9D+L7j/DO1/Q/vv4P4/tP8Q7n9E+y/h/k+0/xTuf4X7b+H+X7T/+BPuf3aM\n8OHDhw8fPnz4w/4vzcvgeY10sY0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMDktMThUMjE6MTc6\nMDErMDc6MDA/DItCAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE1LTA5LTE4VDIxOjE3OjAxKzA3OjAw\nTlEz/gAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Convert OpenMC's funky ppm to png\n", + "!convert materials-xy.ppm materials-xy.png\n", + "\n", + "# Display the materials plot inline\n", + "Image(filename='materials-xy.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As we can see from the plot, we have a nice pin cell with fuel, cladding, and water! Before we run our simulation, we need to tell the code what we want to tally. The following code shows how to create a 2D mesh tally." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Instantiate an empty TalliesFile\n", + "tallies_file = openmc.TalliesFile()\n", + "tallies_file.tallies = []" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Create mesh which will be used for tally\n", + "mesh = openmc.Mesh()\n", + "mesh.dimension = [100, 100]\n", + "mesh.lower_left = [-0.63, -0.63]\n", + "mesh.upper_right = [0.63, 0.63]\n", + "tallies_file.add_mesh(mesh)\n", + "\n", + "# Create mesh filter for tally\n", + "mesh_filter = openmc.Filter(type='mesh', bins=[1])\n", + "mesh_filter.mesh = mesh\n", + "\n", + "# Create mesh tally to score flux and fission rate\n", + "tally = openmc.Tally(name='flux')\n", + "tally.add_filter(mesh_filter)\n", + "tally.add_score('flux')\n", + "tally.add_score('fission')\n", + "tallies_file.add_tally(tally)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Export to \"tallies.xml\"\n", + "tallies_file.export_to_xml()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we a have a complete set of inputs, so we can go ahead and run our simulation." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": false, + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + " .d88888b. 888b d888 .d8888b.\n", + " d88P\" \"Y88b 8888b d8888 d88P Y88b\n", + " 888 888 88888b.d88888 888 888\n", + " 888 888 88888b. .d88b. 88888b. 888Y88888P888 888 \n", + " 888 888 888 \"88b d8P Y8b 888 \"88b 888 Y888P 888 888 \n", + " 888 888 888 888 88888888 888 888 888 Y8P 888 888 888\n", + " Y88b. .d88P 888 d88P Y8b. 888 888 888 \" 888 Y88b d88P\n", + " \"Y88888P\" 88888P\" \"Y8888 888 888 888 888 \"Y8888P\"\n", + "__________________888______________________________________________________\n", + " 888\n", + " 888\n", + "\n", + " Copyright: 2011-2015 Massachusetts Institute of Technology\n", + " License: http://mit-crpg.github.io/openmc/license.html\n", + " Version: 0.7.0\n", + " Git SHA1: 3df61825cc8c93656ed1458c34fca14000884e73\n", + " Date/Time: 2015-09-19 07:34:09\n", + " OpenMP Threads: 4\n", + "\n", + " ===========================================================================\n", + " ========================> INITIALIZATION <=========================\n", + " ===========================================================================\n", + "\n", + " Reading settings XML file...\n", + " Reading cross sections XML file...\n", + " Reading geometry XML file...\n", + " Reading materials XML file...\n", + " Reading tallies XML file...\n", + " Building neighboring cells lists for each surface...\n", + " Loading ACE cross section table: 92238.71c\n", + " Loading ACE cross section table: 8016.71c\n", + " Loading ACE cross section table: 92235.71c\n", + " Loading ACE cross section table: 5010.71c\n", + " Loading ACE cross section table: 1001.71c\n", + " Loading ACE cross section table: 40090.71c\n", + " Initializing source particles...\n", + "\n", + " ===========================================================================\n", + " ====================> K EIGENVALUE SIMULATION <====================\n", + " ===========================================================================\n", + "\n", + " Bat./Gen. k Average k \n", + " ========= ======== ==================== \n", + " 1/1 1.01593 \n", + " 2/1 1.05332 \n", + " 3/1 1.03858 \n", + " 4/1 1.03420 \n", + " 5/1 1.03004 \n", + " 6/1 1.03899 \n", + " 7/1 1.04639 \n", + " 8/1 1.03921 \n", + " 9/1 1.00410 \n", + " 10/1 1.06702 \n", + " 11/1 1.03401 \n", + " 12/1 1.05518 1.04460 +/- 0.01059\n", + " 13/1 1.03358 1.04092 +/- 0.00713\n", + " 14/1 1.00991 1.03317 +/- 0.00925\n", + " 15/1 1.04884 1.03631 +/- 0.00782\n", + " 16/1 1.03449 1.03600 +/- 0.00639\n", + " 17/1 1.04612 1.03745 +/- 0.00559\n", + " 18/1 1.07511 1.04216 +/- 0.00675\n", + " 19/1 1.01774 1.03944 +/- 0.00655\n", + " 20/1 1.04054 1.03955 +/- 0.00586\n", + " 21/1 1.01202 1.03705 +/- 0.00586\n", + " 22/1 1.04460 1.03768 +/- 0.00538\n", + " 23/1 1.04415 1.03818 +/- 0.00498\n", + " 24/1 1.04222 1.03846 +/- 0.00462\n", + " 25/1 1.04045 1.03860 +/- 0.00430\n", + " 26/1 1.04133 1.03877 +/- 0.00403\n", + " 27/1 1.03166 1.03835 +/- 0.00381\n", + " 28/1 1.00701 1.03661 +/- 0.00399\n", + " 29/1 1.04111 1.03685 +/- 0.00378\n", + " 30/1 1.05130 1.03757 +/- 0.00366\n", + " 31/1 1.02685 1.03706 +/- 0.00352\n", + " 32/1 1.03458 1.03695 +/- 0.00335\n", + " 33/1 1.05243 1.03762 +/- 0.00328\n", + " 34/1 1.05717 1.03843 +/- 0.00324\n", + " 35/1 1.07396 1.03985 +/- 0.00342\n", + " 36/1 1.01690 1.03897 +/- 0.00340\n", + " 37/1 1.03340 1.03877 +/- 0.00328\n", + " 38/1 1.04153 1.03886 +/- 0.00316\n", + " 39/1 1.01971 1.03820 +/- 0.00312\n", + " 40/1 1.01491 1.03743 +/- 0.00311\n", + " 41/1 1.02779 1.03712 +/- 0.00303\n", + " 42/1 1.03047 1.03691 +/- 0.00294\n", + " 43/1 1.02305 1.03649 +/- 0.00288\n", + " 44/1 1.07854 1.03773 +/- 0.00305\n", + " 45/1 1.04412 1.03791 +/- 0.00297\n", + " 46/1 1.05139 1.03828 +/- 0.00291\n", + " 47/1 1.05357 1.03870 +/- 0.00286\n", + " 48/1 1.06435 1.03937 +/- 0.00287\n", + " 49/1 1.02632 1.03904 +/- 0.00281\n", + " 50/1 1.05201 1.03936 +/- 0.00276\n", + " 51/1 1.04582 1.03952 +/- 0.00270\n", + " 52/1 1.02056 1.03907 +/- 0.00267\n", + " 53/1 1.06448 1.03966 +/- 0.00267\n", + " 54/1 1.03609 1.03958 +/- 0.00261\n", + " 55/1 1.02701 1.03930 +/- 0.00257\n", + " 56/1 1.04865 1.03950 +/- 0.00252\n", + " 57/1 1.06310 1.04000 +/- 0.00252\n", + " 58/1 1.02975 1.03979 +/- 0.00247\n", + " 59/1 1.03922 1.03978 +/- 0.00242\n", + " 60/1 1.07259 1.04043 +/- 0.00246\n", + " 61/1 1.04555 1.04053 +/- 0.00242\n", + " 62/1 1.01950 1.04013 +/- 0.00240\n", + " 63/1 1.04618 1.04024 +/- 0.00236\n", + " 64/1 1.02489 1.03996 +/- 0.00233\n", + " 65/1 1.06850 1.04048 +/- 0.00235\n", + " 66/1 1.03623 1.04040 +/- 0.00231\n", + " 67/1 0.99892 1.03967 +/- 0.00238\n", + " 68/1 1.05557 1.03995 +/- 0.00236\n", + " 69/1 1.01211 1.03948 +/- 0.00236\n", + " 70/1 1.04679 1.03960 +/- 0.00233\n", + " 71/1 1.03461 1.03952 +/- 0.00229\n", + " 72/1 1.01993 1.03920 +/- 0.00227\n", + " 73/1 1.04742 1.03933 +/- 0.00224\n", + " 74/1 1.05269 1.03954 +/- 0.00222\n", + " 75/1 1.05696 1.03981 +/- 0.00220\n", + " 76/1 1.05904 1.04010 +/- 0.00218\n", + " 77/1 1.05930 1.04039 +/- 0.00217\n", + " 78/1 1.03375 1.04029 +/- 0.00214\n", + " 79/1 1.07044 1.04073 +/- 0.00215\n", + " 80/1 1.04144 1.04074 +/- 0.00212\n", + " 81/1 1.06296 1.04105 +/- 0.00212\n", + " 82/1 1.04630 1.04112 +/- 0.00209\n", + " 83/1 1.03772 1.04108 +/- 0.00206\n", + " 84/1 1.03774 1.04103 +/- 0.00203\n", + " 85/1 1.03984 1.04101 +/- 0.00200\n", + " 86/1 1.03040 1.04087 +/- 0.00198\n", + " 87/1 1.03484 1.04080 +/- 0.00196\n", + " 88/1 1.03820 1.04076 +/- 0.00193\n", + " 89/1 1.04654 1.04084 +/- 0.00191\n", + " 90/1 1.03377 1.04075 +/- 0.00189\n", + " 91/1 1.03370 1.04066 +/- 0.00187\n", + " 92/1 1.04172 1.04067 +/- 0.00184\n", + " 93/1 1.04945 1.04078 +/- 0.00182\n", + " 94/1 1.03360 1.04069 +/- 0.00181\n", + " 95/1 1.06547 1.04099 +/- 0.00181\n", + " 96/1 1.04340 1.04101 +/- 0.00179\n", + " 97/1 1.07502 1.04140 +/- 0.00181\n", + " 98/1 1.05391 1.04155 +/- 0.00179\n", + " 99/1 1.05622 1.04171 +/- 0.00178\n", + " 100/1 1.01519 1.04142 +/- 0.00179\n", + " Creating state point statepoint.100.h5...\n", + "\n", + " ===========================================================================\n", + " ======================> SIMULATION FINISHED <======================\n", + " ===========================================================================\n", + "\n", + "\n", + " =======================> TIMING STATISTICS <=======================\n", + "\n", + " Total time for initialization = 3.6600E-01 seconds\n", + " Reading cross sections = 1.1500E-01 seconds\n", + " Total time in simulation = 8.1308E+01 seconds\n", + " Time in transport only = 8.1157E+01 seconds\n", + " Time in inactive batches = 2.1600E+00 seconds\n", + " Time in active batches = 7.9148E+01 seconds\n", + " Time synchronizing fission bank = 1.6000E-02 seconds\n", + " Sampling source sites = 9.0000E-03 seconds\n", + " SEND/RECV source sites = 7.0000E-03 seconds\n", + " Time accumulating tallies = 1.0000E-02 seconds\n", + " Total time for finalization = 1.6400E-01 seconds\n", + " Total time elapsed = 8.1856E+01 seconds\n", + " Calculation Rate (inactive) = 23148.1 neutrons/second\n", + " Calculation Rate (active) = 5685.55 neutrons/second\n", + "\n", + " ============================> RESULTS <============================\n", + "\n", + " k-effective (Collision) = 1.04100 +/- 0.00169\n", + " k-effective (Track-length) = 1.04142 +/- 0.00179\n", + " k-effective (Absorption) = 1.04380 +/- 0.00147\n", + " Combined k-effective = 1.04287 +/- 0.00130\n", + " Leakage Fraction = 0.00000 +/- 0.00000\n", + "\n" + ] + }, + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Run OpenMC!\n", + "executor.run_simulation()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tally Data Processing" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Our simulation ran successfully and created a statepoint file with all the tally data in it. We begin our analysis here loading the statepoint file and 'reading' the results. By default, data from the statepoint file is only read into memory when it is requested. This helps keep the memory use to a minimum even when a statepoint file may be huge." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": false, + "scrolled": true + }, + "outputs": [], + "source": [ + "# Load the statepoint file\n", + "sp = StatePoint('statepoint.100.h5')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next we need to get the tally, which can be done with the ``StatePoint.get_tally(...)`` method." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tally\n", + "\tID =\t10000\n", + "\tName =\t\n", + "\tFilters =\t\n", + " \t\tmesh\t[10000]\n", + "\tNuclides =\t-1 \n", + "\tScores =\t['flux', 'fission']\n", + "\tEstimator =\ttracklength\n", + "\n" + ] + } + ], + "source": [ + "tally = sp.get_tally(scores=['flux'])\n", + "print(tally)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The statepoint file actually stores the sum and sum-of-squares for each tally bin from which the mean and variance can be calculated as described [here](http://mit-crpg.github.io/openmc/methods/tallies.html#variance). The sum and sum-of-squares can be accessed using the ``sum`` and ``sum_sq`` properties:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[[ 0.41271426, 0. ]],\n", + "\n", + " [[ 0.40846766, 0. ]],\n", + "\n", + " [[ 0.4112029 , 0. ]],\n", + "\n", + " ..., \n", + " [[ 0.41437289, 0. ]],\n", + "\n", + " [[ 0.41376468, 0. ]],\n", + "\n", + " [[ 0.41312074, 0. ]]])" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tally.sum" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "However, the mean and standard deviation of the mean are usually what you are more interested in. The Tally class also has properties ``mean`` and ``std_dev`` which automatically calculate these statistics on-the-fly." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(10000, 1, 2)\n" + ] + }, + { + "data": { + "text/plain": [ + "(array([[[ 0.00458571, 0. ]],\n", + " \n", + " [[ 0.00453853, 0. ]],\n", + " \n", + " [[ 0.00456892, 0. ]],\n", + " \n", + " ..., \n", + " [[ 0.00460414, 0. ]],\n", + " \n", + " [[ 0.00459739, 0. ]],\n", + " \n", + " [[ 0.00459023, 0. ]]]),\n", + " array([[[ 2.02702426e-05, 0.00000000e+00]],\n", + " \n", + " [[ 1.77108625e-05, 0.00000000e+00]],\n", + " \n", + " [[ 1.79568064e-05, 0.00000000e+00]],\n", + " \n", + " ..., \n", + " [[ 1.83114148e-05, 0.00000000e+00]],\n", + " \n", + " [[ 1.69970626e-05, 0.00000000e+00]],\n", + " \n", + " [[ 1.92143217e-05, 0.00000000e+00]]]))" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(tally.mean.shape)\n", + "(tally.mean, tally.std_dev)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The tally data has three dimensions: one for filter combinations, one for nuclides, and one for scores. We see that there are 10000 filter combinations (corresponding to the 100 x 100 mesh bins), a single nuclide (since none was specified), and two scores. If we only want to look at a single score, we can use the ``get_slice(...)`` method as follows." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tally\n", + "\tID =\t10000\n", + "\tName =\t\n", + "\tFilters =\t\n", + " \t\tmesh\t[10000]\n", + "\tNuclides =\t-1 \n", + "\tScores =\t['flux']\n", + "\tEstimator =\ttracklength\n", + "\n" + ] + } + ], + "source": [ + "flux = tally.get_slice(scores=['flux'])\n", + "fission = tally.get_slice(scores=['fission'])\n", + "print(flux)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To get the bins into a form that we can plot, we can simply change the shape of the array since it is a numpy array." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "flux.std_dev.shape = (100, 100)\n", + "flux.mean.shape = (100, 100)\n", + "fission.std_dev.shape = (100, 100)\n", + "fission.mean.shape = (100, 100)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAWwAAAC4CAYAAADHR9Y0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzs3XnQJOdh3/dv3z0993289/3ufR8AFsQNAgQPSKIkymRk\nyVKiVGJJseOyEztOxZFdlbKiUnSVSkokUbZIkabEAyQBECSIa4EFdhfY+3333fe+37nvq7unO3+s\nUuXYKkslaAWwOJ//ZmrmfXqmfvV7e7qfflpwXZe+vr6+vg8/8YPegL6+vr6+v55+Yff19fX9gOgX\ndl9fX98PiH5h9/X19f2A6Bd2X19f3w+IfmH39fX1/YB4X4UtCMJTgiDcFgRhURCEf/a3tVF9fR+k\nfq77PqyEv+k8bEEQJGABeBzYBi4BP+W67vzf3ub19f3d6ue678Ps/exhnwaWXNddc13XAr4EfOpv\nZ7P6+j4w/Vz3fWi9n8IeADb/o8dbf/FcX98Psn6u+z605Pfx3r/yWIogCP3r3vvuKdd1hb/tP/lX\nvaCf676/C39Ztt9PYW8DQ//R4yHu7o38/0jHPk7y5d9Ak9p8THuep9UX+U37l9gV0sTcAjcunsQR\nBEYOLNGVNJqyl5ro5zPyl/C0Onxh+2fxJ8uoeodCIU29E8TtuaSVTarNCKVGAqHngCMQ0Kp8dN9z\n7L2X4Y1f+G1G/+9foat62FmZBAmElotQcPCereKq0LgZRo2YCKKLmdOYemAOr1Jn7g+OEHi0hPdM\nnfxChk7RoFeUYeMvPpQf8AIJIAVYwEvz8IdvgfBniP/jt5GGbZy8SCRVYOrpW0xJd1Acm3l7P03J\noGvrdIsG9XdDNG4E6NY0xh67w/hjd7A7CmlphwPKLR7tvEZL9PCOfIo/3vh5tp0BwpE8jk9kQN3i\nFJeYZIn19gi/8aMX+PXPD/NT+pdwvT3mpRle7jzO7+79MhFvnkHfGo2un63qECUzzOjQCk95XuQp\nvkOVIB10Oq7OnfoMFTcMGmDCyrdjvPpPZ4n/lognomD/c4PgPyly8NlrfJo/41/+2B0yX/l1FswZ\nDso3OSVdYtjeZDq7QqqcY2V8kFvefSwxRdgt46OOJPS4yBluLh1l5a0Zog/u4rpQfD3N0QcvERgv\ns+UMcFC8xaiwhoyN363joY0guOSI82vC//o+4vv+cg2zwE/ei/H/Gr78AY39wzbuBzn2v/pLn30/\nhX0ZmBIEYRTY4e6n+qn/9EWuLiB9W+AXH/8dPL4WrwoPMyavMswGdkdh6e397OYHWFw+gJMUUYa7\nGFNVVoQx0p49Hh96AVNVUEWTZPxF3mh8hPdunGD314foaSrCEQf54y2croJQdNFsE8+hJkLKJvsH\nNnYQ+LG7n1QyTHRfA/O3dewFDUYFxn58EXXEZN45zCntEpnEJms/OcoDqdc56L3Jy/ueYKkwSz6b\nAgNY5O4pqUGgBtwC1gDvCPzzMPxf38TjbxB/YJeG6SOiFhkR12lhkOukmd87TCK6y0njEp/TvsSF\nk2f5dvpp5l44guC4WC2NO1f2kY1nqMyGeVu/jwG2SLOLFO5izckUvp0h8/F1lAmLHTK08bDXy+D2\nLvKy8igBvcKPtJ+jqxkUezF6DZmt8ij5ZorevEQ3qyF4XOyf0mgO+NhmgOf5GBYKiU6OSy/dT85K\nwb67n7XTVODfGgweu8aJ0Luc+e1L3B6coUCUtzmDwi0eFl7FVFUMocmuleE7uU9gL6uEy2X2Z64S\n9eZJuDneMB/EFFXiSo4iMeySjHDdYeboAs4wvH0sjhlRqFsBsrU0lk9jV08zwDYlJ4LrChyX3iMn\nxN9HdN9/rvv6Pgh/48J2XdcWBOEfAt8BJOAP/rIz6ZLuIEgiI9I6bVGnSBRDaCHg0nB9OK6E3VNo\nmjIRT4Ggr4RPrLBTGiLfSROQ63TXNKJOgSPHrxLzZfEoLVp7IfyzNYypBhWCmKpLLwZZJYFgOHj9\nDTik0u76oQzsgRsTsU+p2GWN3qYMIjRzfszBDvJYh0IwgmBY6FMtSpUYy1tT2BkRwXGgzt3C7oKQ\nc1Dv6+CP1zBqLfK5FG3VQAxq6MEWw+PrlNph5IiFo8OWPYhXamJITY54rlK2Q7Q6BgP6JrHAGB6p\nhTDsEAsVGJeXyUeSND0GC+1p6rkQKc8u07F5po3bqKLNtdIparthXJ9ESY8TM3I0LT/YAg3HS0kO\nUXJC7IlJykqIYKSEZDp41BbWkEJBTFB3/HRkjRXGcBHIEUfDpCl5aaS8NG0Pkt9GTVloQybxcZv2\nboBsPUPxUJiSFGaXNHskqRFg2Z6kVI0TNio4isCWnKER9ePzReloAuFGBcoii/l9dHWNYirBpP8O\nsdgVhk5s4a4KVJphlPEO5WIUsdTDCQsUF2OYPR13v0BBiNFt6PSyKo2m/28a3b+VXPf1fRDezx42\nruu+ALzwX3qNcXAIY7aJ6xGxHBXLVbFFk4bgIyum6KY0JKOHOtolNbNFJJZHMh3mFw+TK6eQUz16\nr0qMdFbZP3kTb7TFQHyb7UMK0fs2Cd2Xp5E7TtcjYmZEloRJRpw1Bo4EqP6Mh8Z8GN4BLkEvo9Ab\nUMAwIWyCrVLbDeOpNAjvy7FqjLAtpfH76syvHOB64QTx2DZuRUDYdRGSDkggKj30I3Xi0zska3m6\ngo61piKsO2SOBxiaXmd+7hDDB5ZwdYEb1iFmhAUOqLc4mL7Jc5Vn2eiMsBnJ0JA8qHqX2FSBqfgS\nR/UrVA4EWeuOUqrGYFViLzxAO6rxOfVPSHjKXNVOk8+myatpiLgMh5cROg4M7EPrmFiOwpw0w0J7\nmkIvRihWIKNsk3ByVNIh5tcPUC17afc8zDcPsCaPM64sE3ZLgID3/gqi2MXv1hFTLo4tYcoqWy+M\nke2lyE7HqYl+2q4H1bGoTp/lhcYzlLcTxGJFookCir+N19PDoMmmPshCYT/NjSAsgRh0QZF4WHuF\nsfFlOsMaX//9n2B1dRJlsEP+ZhJBdPE+XsG646FbMahMhugoOtVqmAuXhxFK7ye57z/XcM/28P8a\nPqixf9jG/aDH/s+9r8L+6xg87uNjE18l49nitcajXKrez2fjf0xHV1kRJ+j5ReLBLLNHb1LwR1gr\njdOcD9L4YgCv3CDzLzbIHUqzl03zle3P8gnpazw48Du88D98jKVvNFn9ly20f5TCCQ/QLvnYvTmM\nlrJRZiaxcgbumgzrwCFgDBBd2L0NsgufPcTPHfk9Toy8w5IxQVCqYqHwLidojvmQBh1CnhLXB49Q\n9gbwhpuIUw5OTcSMqmxeG6U4lyZ5eAcj2WRjfpy2foJ1YRRBcjkjXCQgljivnSPXS6A7HfYp80S9\neQy3QUfU2M88E8oq4WiLrldmlxge2nyq+S3OVS+QnY6x4J/ijjiJJciUt0LwXcDH3Sx1BHKXMwiO\nCwf2c7l2hpXqFD6zQeWNENViEPMpFWnKxalI3P6V/RQWZRxtl/pDMZqzYYyxJuLsMlkzw8ruNJHR\nHMcCVzliX+Mbf/5pFrf24QyIdNY9KGmTbSeDaamYbR27pGMGTtOZj+LYErc4wmpvgpLuxzkvY815\nGfvpRbTkJr39Mr0xCZ9cJ+HL42gCt5mlLIUJfyLPyBWV5V+bprcrw7hD45iPyZNLDErb6J4Wd7rT\nFM04dAQis3kK9zq8/0U/jCXywzbuBz32f+6eF3ZczXHSt0CqkydsVfC5dZavTKGEu6Qnd9AmbNqm\nQb0VoHw7RqtroIYsRK2HR24z7FsjMFujkQyg+C1mmnc403ubvdkUuS8Ns3oxjbftwenIOFmZ9nUf\nNTOIxzKw31RhTbz7nQfBCDWIJvIUxx2kXo/M/fMcS11myneHOWEfDXy0LYN8NUVnXketmfARh47s\nQfI4BEMVLEOhJoWw8jqdgoIp9hhOrCDIDqrQovr9AHJWZ3/6Oues84xsrzNS22IzMUgz6GFJmCSX\nTyJ2XApDMQaUbRLKJqlYnj09yQ5xXCCp7HHc9y7rkQEqmp9bzj5uFI9S00McPvcexnQbIelgeRVW\nipOUuhEQoNBJUMgl7h5bvwA0gBjsrg9SzwfYu5mh2zQh0cbK66CpiLaLOaKCBrqng1dqYpkaq9Up\n8r0kLd2LHmky6V1AS7SpiAG6CCiCRVwtsbNm0dpVQbYpzwQpHwghDndxqxLCroxpqahaB0mz0MMt\nRNum1AmxMz8Auos62SExlMXfaiAuuexUh3AEGJJXCERr9FQBC4WgXCUt7rLbGsHvrX7Ahd3X93fv\nnhd2lCLjzhrhap0pfYnjgYu88PlPkRjY42OzX8dz8F2u7x7jKzc+i/Rij3CswPAvLbH6yAya2SGp\n7JEe2kEZtIgpefavzBHNVxjRNwj1jtLr3Uet7EeURaR8D2dVpBvUcZperJcVUIG/D8K6S9gpcnDk\nCreePIrqWJwaex1darLsTvCi9RSOKNFteVja2If9ZQVlo0vwYA5TNFArDoF4nUoxQmshiFsSwQ/u\nkR6mTwWvg+Gv0viyRmCtwaOffJGzq+9wZPUmT628zNJHhnktdo4/5B+wujxNuFhhKzGER2kjyC6V\naPDuPww8mKi0/Dolv589kqy7I9w297G+Mc3YwDLP/MrXCVNGpEcbg695Pk29cATrTQE6QBZ4HsgD\nmgsXHXbLA1AehBhw3AtDYfC4CD0HIetSb/iJh3LsH7xGB52Fyizz2SNwAHzBKsmZLe6zX0dzO7wj\nn8XpCXjUNofD12huVGi93gOzC08poEgQBXwCdkqioMSouT4kxyEqFqhbATbKwwjnZTLRbQ5OXiFJ\nFm2mS3pmm1f++KPYdYUHlDeZE/axwjg6HTLiDgFhkboZJWDX7nV0+/o+dO55YUv06EkSV8MHWJGG\nEZsOiGCKKmUirBJiO5wmemyHo5lruOsi7/3+SRrJAO5klS1xkOLrSQaLW3z2o18km0jwgvo0r914\nhOWtMRAMBLVHbDBLOFZhUxmjth1CeC2ObXhgAoSEiz7awButYQgtPnX8q5S7Yd4oPUw1EEQqu6y9\nOU1vSMaJivQcGf3HG3j1Gnq8w4SwSjBYZV0bxk24RIQstbej2KKEE3BYz03g1gV6FYmjmSv8xOmr\nTLHAanKIef805oSKL1qjSpAGXjz7a+hmnSV9nBHWUDE5zzkqhOii4SAiYdNG5xYHuF45ysbuFO2a\nQUbZ5UHe4BUeoUaAYTZ4yP8Kse0C35vr4cwATe6eJM0DnTbsbcBoFKbiMAK4IAgO4gmTYKJMqFdl\n+8Iwm3tjiG0HR5ZopwyYBjSIqCVOcYnbbx0k20lSO+thxLOOZ6PLpT99gErie0j/u0Xv6xqs1eHL\nXRw1DKsS8nqXWLdAq2hQKKTwDjUZ1Ve5P/Ym008tIqoOeyQxaNHGQ5UA1pxC/uUkLz3/DO4vOfQ+\nCjU3QO2dMMH1Oo889hKB4QrX7nV4+/o+ZO55Ybcx2BEy2LpMiTAdVePQoaskwjkG2GaXNKre5X79\nPEfi19iVBnnl6pP0ZAnB4yIKDqLaw9FFKkKIK8YRvld/lPmbR3DiAt4nO3SaGk5BxPbKuCEB8z0F\nburwqIQ0Y6GmO4hGD8WwCAsloskcrumi1TvkhCSuKKLqXaotL23LgDy4aYFeVKZzx0soVWEydYcO\nKrar0Or4cJcgPFIkHthla3cMy1QJ6mW0SBtSOjkSbBkDNAwfaswiRp5SL0LNDDIdXCAj75AlRa8k\nE+1UcOISutIh7uaZ6K7il5pckY9x0T7Noj1FEwPHK9A1FIpEyZKkQAwLBbuuYhb0uyVdA9XXJfRY\nicZ1P60dCXQZz/EO8okqzbAPzeoQEMskp3fQ4h0sSyG/nKCrelCw6OQN/ME6s8FbbC8PYc5rlN+O\nsbY2QS4eRz9do131Ye562dkcgqiM95N1XFWme8HG3JLgFRlsEUcVae34APDLNQQBPFKblL6Hk5Tw\nCw2O8x51/KwxSokIXVullfWyvjiOd6aGL1DFd6xKsZiiu+dj5NAa3bx2r6Pb1/ehc88Lu0iEG0ww\ny20sFKpGgE996s+YZAkViyV3kgA1Hue7+IQmFxMawqMONCW0bpeks0fqgT16gsRX+DQL7gzLjUm6\nt1TCDxfw3l9l78+HKexmKGQy0AJWbdi0IeygTnXwZ4pUs3EEWyThybHNIG3Vw7nI67QwaCR9aB9v\nszS3j84tD8xBd8tL1+PFXRewH7pBNFnkoHCTdjHA0s0D8CqMPLjOGf+bvFjw00h7yYyss7eW5Js8\niOtKxMiREXZJksNEo2hHqVcCnA28w0H5Jr/JL+GuK6T38kw/cIeAUmGqt8xwPcvL2sN83vc53m6f\noSSHUTN1zLbOqjbM1/gRagSoEOI2s+TWBmluBXC9XwQBfCM1Zn7yBqvfm6Z1bRSSkwTPbOGb2mIr\nN0bIW2A6MsdZ3qZMhKvyUaSHunhkk5BWJffyAAPeTR6bfpHn/+xZlp6bZm8hA4+D+skOqmqyvDFD\nN2/AfvC2TSJTReQpi+LRFObXE/BFYMLFfERlZW6aYc8qk6fmaAh+GvjYdId5tfIE90lv8X/qv8xt\nZtgjRZEY3QEdpoAdaL4YQKuaDP3qLWyvh3Vxgu9c+zj9A9h9P4zueWGLuKwwzh2mqePHRCVLkuX2\nFJcrZ1nLjuHWBW7bhxk5uEQvKHFw+gpbrQFqWS9v/fnD0BBwQ8BZB6IOnlab1ntB6r4QbUXF/mYR\npnwIkwG08SbObQkTCZ7rYtYEarU4VlVjKzHIt7yf4AH9TYx8h5ff+yjCQYteUqTR9pGJ7zJydpXt\n/Rm8ahPRguXYDDdKR6m+FGLkzBKWJYMDHIC1wATCvMB/2/49BqPrVDD4PYKsViZpbQbQAh0GgptY\nQQVFsMgoO/xa+B+zJE/yLT7OANvcGp1lOTbGO637OCe+hsfb5ZXAo1wRj1EWQnzO8yfobodsJ8kL\nL3+SWijM4jNTVBphuoKGYDiEx/JEozmae1l6D2eR/SaWrNBLSJABqtBsGuhCg6ORy5TtIEvVKTRf\nl5BUJdXIsvrVKSreMNYJL+aWzmZwiBeKz7DnpO6etPWD51N1pH02zRfD2OsK9ID90LnlIZ9LI/TA\nLHpAAR4Ftjbhqzugpyhc89DdPIz6YIt2wkNd8BMJ57AFga/zLG10GvgYYpP8sQHKjRhc5O7snge4\nOwe+B5SAJYif2iN/r8Pb1/chc88LG2CLQfzUsZHporHEFGs7E7x59WGi4QJpeYeIW6LgxlHVDgei\n1wn6S2xURtlYnkLUbJRgF9k1USwTty3itgWsrkJPVFFGSvSCKo7posS72AdVmBTBBx6nTdhtUtWC\ntGQPtzuzDJi7sCyx9u0JMsE19EQT01VwbBFBcWDEIaNvEbfyeJQOG+fHuHXrEHZMpKKFEWI27imB\nshKG4gTeUIMBYwsPAcK4KJToodHCwC1LjC+u0xg18MXrTOmL7JHCsFucrV9kSZ/gdf1Brm+cwCfW\n8ap1zu88RN3rJZ7IcVi5jkQPpycyoq2xZo2xvTNMI+vH6QjocgcxUEfTuqC56IkWiFDciNPuGkgh\nG8PfQA5Y6GKb08YFKp0wS91Jsk6Kai+M2rSxGjrWuo61rcMmNGd9rLvD2K7n7onKURCO9nB1sF7R\ncTvC3ROLfjDkJqFamd25QewFBbrADKC4YLugurSaXjorXryHy2iRDqpk0e04bNcHeaHzceSYie5r\nE1SqJKd3MYQWqdAeG4eHac16qMpBnBh4Rpp0uh48mebfRXT7+j5U7nlh9xDJEedJvkOZCOc5x2VO\nkp9PI/37Hgf+52s8c+o5fsz9Kr8r/gJbDHKAm0yrd7jtPcBOcBTPuRrBwyUMsUWukqLcjeKOycgz\nHdQHOngfUWhfk2nddhFsF+GkCx8T4JBBenidE/df4DpH2OoO0qj7+G7+adyrMr1vSsw+vED83C7X\n9cNsXx6hko/gTjscTVzneOA9Dk3e5HuvPcWr1x7nWvwk4kkT6UCb3pSMW1JoVT18ZfhZ3ovsJ0Ge\nDG8zEfwWi4EpNoRhTly+yn/3O/8PF372BNceOsBLPMkEyzzReplDKwv8Ufq/4g3/R3DLInPqfopS\niLmXj3Jk/AonH70MwB2muew5wdSPzqNudPn+5adwVwXYhkbBQ3MmDHEXdy5JsiAj6xarL8/QQ8YY\naDDwwBq2TyImFjjHeWKeAmvaKL9l/yI36kfpNL245yT4CvC/ATOgDJr4olVqgowZkeFxMEMaFFzc\nFjAJpIEKDApbHLbe4IU//xS1chDC3L10/9FheHYIIgIUwClAs+sl2K5yXH+Pb638KKuLEwg7LsKD\nHUamVngg+CZTmXkGU1s8de5FviB8lu/xOOu9YfRDHcJjOXLzg9gZ6V5Ht6/vQ+eeF3aumKT9bpr1\nmTG8vgYj7jpZM4l3X42JX1xiZGIVn1jHRuIUl4hRoEiMY7xHNFHk6uNHyaS2UJoWV5dP0hBDuLoM\nTwoMHNomLu+xkpuia3lxVYn2835cVUQwHfwHigwOrHNYusERrtPQfOyQ4dUrT7LlGcL3qyXWTwyy\n14vSkHwExkoMpdaZCi4w4Nliz05zuX6KyqkwY5k77LjDmA0VcV3AGG3iHSoQSlbRfB0QBBQsIhQ5\nJVxiVphngxGyqTT/8KnfQh7qoNBGo4uAy5ZngOdHnmHBmMKv1Dg+8TamR6GpGKQe3OKM/jYPti7w\nkvYYF8z7WWjuoxvwICdsjh17h73JFJV8hNZOABcQAz2ksS4N2Y/XaTJz7iaS6KB52ySNPVaqkyzu\nHeB3V38ZXerQ8PhYb03SDRnIyR6jQwu0T3jZfGIURsEaVmhUfNirDrRNUFSQHIKDFdI/eptkMIds\n2Oz1Uui5Cka6SernNqFu05Z0/AN1uraBa0sczlxBGevSahto8TZ+vcqWlCE4UiDmMSimY3wi802m\nPAs4iAwJG2SkXQRcbGRwXYJCleZckOaeDwYsqoTudXT7+j507nlhFyoJeqUwi9YU+7nJlLPI5eop\neqqMPttG9tlkuym+33oc0yNTIcx85yCTxjKy10KbahIRC0gVqNcCdFsesAWIgSQ4SDtgbhhYWQ32\nwFrX0QY7eLw1JkcWGA6v4aWFYDokyHNUv8qWNkZlJAD3W8iyhd9tEKJCJFYmSpEwZcKUKZlR5lv7\nGRtdYf/ETb53LUyxHAdHQp/oMBm+w37mqOFHxEGli0YHlS5tNw4uZCNJXrz/44xElhllhTS72Mg0\nFC/zsWmyJLFMGZ/Zwqs2wOfgzEgMmFtErDJtPPQcmVCvhuaa6N4WimFSbfqphkOQcCEr4PfUCCS3\naW6YdIpelCkLOWUi6xbdnE4776OQT/Be1YOqm2BBfSUMY6CNt/CFqrgHQXzGxpts4EQEmlsGSD0I\numA4+LQG0XCB5MAOoXYNn9NgxFim4NlmMBQm85FNOm0FpxRBXrIwiw4CAnq8jap06LkiWrlLsxkg\nq2Ug6OBxWgh1l4y+TVzNscQUEUqEKZMjgYBDWKhgCiqVkkor50Oc6NDOG/c6un19Hzr3vLBrjTDy\nkModbYZJFtnXu42247C0OUq5lkR+2GZJmebK0mm00QaOINLYDGOOq3hCDdbao3i1FobRxpnowasO\n3JDAA+sbE2z6RrFbyt1V9NaBYYhMFQjW1nk4WMZHgyVngu/XHme/MM//Ev1XzDxwi41OhqXqJM8G\nv8EZ4x1sJMJUKBPmG3yKh3iNWebR6HKMKzzsvMK7zfso9uIImosmdjnFJf4eX+BP+XvU8aNiYaLx\njnuGzzs/i+3IiKpDcmALSbSo48eghYlKhh2e4dt8h4/yevUhqm/EeXzqO3zkxPdZYIa64mVemWJM\nWCFp7OF4RFxBYJMhrrpHqe7EaLX9ELTBJ5HRd9inXGb9+TXee+MUN+8/hvCEBUMOwnWZnq2gR1tM\nPH6bqD+PW5K4vHo/piRixKrsCGnawx7kQIvh0BLmrsHipX1wUoGEAwmLVGCHuJajjYeF3EHS3T1+\nefxXWeQ6p2mwwjhVPUinZFD5n+JYBQ1m4a3eQ2C6uLcFhLALcQFSLuGjOey8gvO2wtXIcZYjY2wx\nRJIsXXSWuDuDaJo7XOUodkTGtQR6yHCjf//ovh8+9/6kY8lBUkxKz8V5PfAYq6Mz7MwP0StItEUP\n85X99JoStTeDeAIQHC4zM3yThHcPV4SgVqMsh+m6GrOReQZP7aCOWbwrnyC3m6a17YcGyPu6yA+b\nmKqONS5iXlWpiYG7P6sFGclrs8QEv+X8IjGlwFPiCyxIM9iqzBITpMjyLhO08fARXmNnbpALuQdJ\n7d8h5skRpch/v+83eNV+hIvaaZKePRa6M/x29xdRDYu4nMNHgyxJysIUguiSEHLYlsx2a4DSXgyX\nbQ5O3OJS9izfbT+NO9BjT0th+FrEj92mE1JZdid4yHmNieYqoXaNSLjEeetBvlt5GqcmUOsFKChx\nXMMlHtnFq9VpGAEkuUv9up92WMdVBezrCpNnlkimdjAlnbIbwWfU+Ezwi+yoGd7iHPaWhBy2UF2T\najmKSpdUbIWoWqDcjcO2AAJgiVCW6fgNCp0ElUKMih1ENkwuC6fYooOHSSZZYmdviNu7YewDCrFk\nlviZLNY+hUbPR3PMi1dv4PU08RpNZJ+JLcnEP5JDjXWoVCJsrY3x0uBT+Ds18pfT9BSJts9DPpzA\nlFRSo1s8FHmF28kD/Qtn+n7o3PPCFrYc2HBpLgRYysywmRyhZfnABKcnsbMziGj1UN0OQaFC0tgj\nHdghTg4bmYhaoliP0bENxoLLjM0so42a3M5PE3A9aLZFnQBCxkGeuTvTQNQdGm0/u3YaTe4SF3JE\nPXmWelP8WffH+bT6HxiT10CGhc4sW9YQk/oiN/OHcU2YSd3mSj3NzeohxvRFPGobBZOTQ2+z4ya4\n7u5HFbosFqd5LfcIHx1+kbgvRx0/m7ZKr7EPtyOhqja9kkJlLoohdhATLobb5HLnDNebR9GdOorT\nxSu38Q3WqSt316ZOuDkG7W1Us0fN8VHsxXincwZvo4XYc7BVCdnTxaO2CPor2F2ZTk8jRwLP/hYD\nhS32VtIfokIWAAAgAElEQVSMGascilyhGgmyUJvF6YqkxD12agNk8ynwuSg+E8F1sdoKg9oWpz0X\nqBCkIsbupkMFHAG2JGpqiAYBivNJ5MkOVkxkRRijwAprjDLKGkrXRpIdhh7fIDBQxjPcpJvXsAwJ\nphxOG+8wpG7ilRpYKOT1OKuRUSxHopP3oNVMVs0xzKZGZSWO4WuhxExsSQGfi6Z3yPR2ETJiv7D7\nfujc88J2bil0v+LDfVIkcmiHTHqTxeA+ajdDcFWAeQllxsT/35SYMW7jk+uUiOAi4KVJiArZpUHK\njQDyKZOqHsQuqax/a4rB2XXiDy9wdeU0jRt+lLke45+5SV0MsLYXZ6s1zGzgNg9ynmUmWDXHqVf9\nfC/0BBlphwQ57uT3U7DjrAyPUXkrhpAT+JPP/DShI2VmD96k6InQQaeLxiVOccM+TMUOYWsyrXwA\n54ZOPpwAn4vtyiy1N2msHaW3oZKND+HMiTi/pTL+z24x/sgd6rIfebhDxNlDUUwapo/dRpqd/Cij\nkWUGkltclE5TCkaJBQpsSEOU1BART5aZwdvobpeyE2b5+iyFfArzhEz1cgzJ7mE4KT722HscOXiF\nL93+aRL7coyzwg4Zbt05wp3dffzhR36OvTsDZG8P4P9MCTlj0hVVxECXQ/IVPsef8AU+Sztm3L0d\nrcTduc93oFqJQQXc10R8P98gfiBPTMxjc/fQ0zz7qA0ajCUXeKL3XW7dOsJrX3kM99vQm5JIfjLL\nPxj/AqcTF7ADLi4C3xWf4D35H1OxQgQCNR489TJ7SpJtzzDVczEGU2vEolnKUpi9y4Ns3xrjj0Z/\ngc8N/vG9jm5f34fOvT8kMiTgDouQgEYnwO6tIbrLHrghwDxwSsAuK7Qu+ikciSMkHcKUWbBnqPf8\nbPcGEGI2Hr1JfjVNORzF6Ym0Yx5qkQBSoAsDFmlpg0xrG2+kzqi0SiZ0Ho8WvnvJszPKdm6EcjuO\nI8sIjouJyi5ppgPznHYuEBTL3Jo9xGpigrXaJMaVFsqeReOcj3cHTtENqJSI4kgi48IKw8IGhXiC\n25P72HprhJ32ED1dpF6uEPUX2D85x83WUdppD9P/9RyZQ1sMq+uc650nKFWRdh1uf+0AgRM1YtNl\nVjZmCQpVBpLb7App9qQUAi49JJqCwYC4Ra0XIFcxqG2Haa37MLsKTjEGHgExYWO9q3CzdQSP0GHm\n0C22nCGe3/0kQtwi70tQ1wLMzR2h46jYYwIty4+QdXEkActUcAIyjkck20lSuO6HL5ThqBdpXEQ5\n3cYydXptBYBOwcvu+jCXFZXGboH8wqPU415ahoGhN6kJfiaG7+A91uD13UcphOI0FB8v+x5mw0jh\nkZrcz1sMCxvcxwX25CRemhyUbpJ79Wmoi5w++RYPh79PWC9ynnM4oxJy0MIItpi3993z6Pb1fdjc\n+8IeBmHYQQ126Voajc0M7hsibLkIkoMv1kBQXcw1FXNSo4eERpdFZ4pdO41pq/i1BnLLoriaxO06\niGEbYcqlFgrQsRQI2gTVIgkzi6j3yPS20aVNWkKbHdJcdM+wXh+jXgmCCyFvDa/RIE+c6cAdDnON\nGeEOzEKtE8DMeiksx2gue/Hvr9MOeMkKGXaFNKraZb86R5w8ggdWvONkX0nT2TVgFBDeJC1u89Hp\nb6Os21RCYSafmEcWbMJOmWn3Dk28lOoxmu+FCA8WkQ90KTgpVMsEG3qSyJo1xpo5TtCpElLKDHk2\nmXf3kW8n6Rb9mJaC1jaJrFewHhJQxjsIVxrstdIYdpuTQ2+TzWbYaIzQiihYUYWIVcTcVvCna2Qy\nm0i7AtVqmJISRXcsqlaEa81jlL0RxGKXwO0Gbe8gblhDnjURHAG76WLFVNoFL+1rXrLSAGL+Fjvl\no8i+DrrWRulZLNnTnIxf4v4zb7Ag7sO1wYg3eSn4KDf1GabERYJUCVDjAc5TI4SIQ5gSvRUVp6Vw\n4InrnNXfwk+dJSZpDRoYAw0Ex2V+ffaeR7ev78Pm3he2CHLOJunbxgzLlMQI9u8ZOAkB+ZfbHBi4\ngmzYbNrDHPNfRsVkjv14lDYj8jp110/xUpL6YhgnJuEaEqIHPCM17IZKcydEYLBIbi5N7UqMJz79\nAhvVUd64+Qn0/FmUtMm8aFHPeFCLHbovegn8eJ1opISFynu947Tx8KB8HnAJaiV+Kv27vPK5R7jW\nPcLZ0AU+ln+J5FyBfyL9Gon0DtMDd3iDB1lYOkDuhUHs8/Ldq/4mgTclQlcbHBm6xmh6gyIR8kLs\n7tKpooeXhcfoChr7J27y7L/+GjcCB7noO83guRU2rAyl+qP8tP/f0SiHeWVzGqntcDB1lcmpC1Sl\nIJ5kBzsoszEyxoC7xcfDz3HZewJTUtG5Qzz9OpJrMy3d4UcSX6PWC/BvhX/KaHCdMf8qu6NpxuVl\nDivXSfv3eMN9kOeETxKkxt75JL/9nX/E7M/c4IGnLlM6GuL2WxGKyz5acyEin87BqEtxKIW7J8Iy\nUAVPtEXy8DpBpYosWXQtnZvZY7g+iQPha8RP7TDlzpGS9njFeZiAVeNh7VXe4Qx+ajzonmeodZGu\noDHnm0I85+DaArYikyNBAx8WCgNsE+xVudC6j3rIe8+j29f3YXPPC9vrq5M+s0QvLGA3PTjbKq4r\nggtOSWGvPIDkdWhEA0TVEhG1SJEou1YG25UYUjcYGNpF8AgYoRbzuwdZWxzDUjx3lzetibT+1I+9\noNJsC1zLH0cOWGjpZfCBJnRJC7ukPHs0Bv1U7otyOvo2GbZZZIqm6MVDi9f5CCWiIMB19RCb+jCu\nJJHS94gFc/ipERP3GPatMcYqlzlJKFbEc6LDpjDIrHqHT4w+zxuba9w/PoSFwrXcMZacSZppHVuW\nGBS2OSxcx0KhqXtZHhrDRmKYdVw/pMxdfHYTWbTBcDASdTxWm8nAImd5m5IQoaUYIGoIdRdNMolP\nZDnDO5ioLNPghHqJHhLrjN4tUNlmxFkDAWqin5ieZ4hNUuzRk0UcBOSWRel8lE7RwH5Aoh710VB9\n7BkDtB0DVxdwhyXaphdBcGH8L9bdrgI74FUbxO08uWtpQgMlBjLbnPBfpaF5ueEeZs8eYJ+1yI/w\nHDGjgCyZmH8xa90hxKYwhKF2qBLkMifwZSpElvNc/93j5MNp5IzN+sgIktDDkUAO9xj0bnL7Xoe3\nr+9D5p4XtsfbJD6WI69HsXdV7F0dQqAbHbx7DXL1NIIXjJEmeqSL19Mk0G6w4Sg4ssCAuoM2buId\na5JWtrErMvmdBM09Hw5t2GjT/JofejLMwpX6SWaHbjIytkojWETrmqTaOSSvTXPQwDdYJ9PeYbC9\njesRiIpF6vh4i/sptSPU7QDf1p6hnEsQqDfozug0wh60cIsYu6TZIk4ew2kRT2fxpZtoJ5s8WfgO\n/yL/r/k3o0NMHzjKmjvKS6WnuFY9ilprokW6ELxM2ChjCQpVgrzNWYbZYMJdJtyr4ncaBKjRRkP1\ntxnyrxKgxqHuVU5XLnLDd4i67KeLRr6eQZe76HQ5zHV6SOzQ5nD1Bp2eh4uhM7RFD16nRbBVo6DG\nKKsRpuyLDDo76G6XJXWSghjD7ijsXBlGH2ox8OwaNfxUKlF2K8M4bQmCwGlolgN372AT4e7sERtI\nOxgbTWKtIqWlFH6twfTwAh+NfIdXeIS3rLMUGmk6LYOkmOc+79vk5Bh54qiY2MgsMoWrCezZKd5o\nPESgW8O72+DGS8eYHzyAe1BA9DhYPRVZtUgFN4kKxXsd3b6+D517vx6262Hxj/Yx9rk7uAGFylgc\nZmFkeIXTT7/FXG8fstRjSruD6LG5VT7E9+c+ysjUMkOpNbxCg6uFU9TMECcG3iZ2OMupgQu8s/MA\nzT/fg/N5OHoI9vvuLjgUFIg5RZJs0WCL5Z1pXrn+JMnTW/jSNSS3x+eXfp6wW+LYwYtMiMtMskiA\nGl9c/Psslg5gTULvlg4FkTeHH2BUXyVEhQoh6vhpOgarrVHqUoADnjl+1v+H3J+9iLMuke/GqXKK\nTWGQ6riB8maX9v8RpPOwy+JDs3z92LMMKZsoWMQokCDHRG+FJ2uv4cu2sFoSK7PDtL0eTDQUTAY3\nd0nNlTlx9grjiRUCYo0vH/kMimCRJItED4keGXaYeL1Oo+Zn9EfWqBpBtupDXL52ltHhFc4NvsZP\nlL7OQH0b01FoDPnQPB1Mr4LzlIDu7RCmTJkwgs/GO1ymbQSwGtrdZWu7QI27e9Y2EHIQDpk4ZYhH\nszz69MuEPBW8NJDoIeLgF2vUjCAvSI9xQ5ghLe8wwjqDbN69uQUSbTzskGG5PMWt28cQl1x8UpXp\nf3OThs+Haah4vS12S4OU6gl290YoeWP3Orp9fR8697ywA4EataAXQ24jBPJUx4M0bB/+WJl0fJss\ncTS6jLNMliSba8MU/ziOfl8bz6k2wYNVbI9Ite7n6qsn8U1WMWMqTkWEqh+j3GDmzBWGj+cwYi0u\nKSepOQGa5SnEbhzLK+MOuEx6FkmQvXvCL9QAVyAnJMkTw0TlOodphAx02nTMEFOJO6QjO+xpMRaY\nwaBJlCI9JOY4QLEXIy7kOcR1UvIeRBzyUyGMRotp5hh3lykbEfLRJK1MkKf1F3igep7huRXiYh7X\nC56hNillj7STZaC7g6T1aOo6MTnPANs08BInT9q/Q2kwiKMJBKkwJqzxmP97uAjE/mJh6P9v6iHe\nOkG3xrC4yRoiDcXPVGKB+7W3uM+6QF3zUiZIsFdl2lpGQCDhlvjGyLOoSodp7uClQVZKct13lNzR\nFGrHYiS1zqJ3moI/ihBxcTsyrgEEXFxZpGYHuV47xv3ieYLNKt997mluz0yhnjJhRyAnpuhEdO7n\nTY7zLmEqXOQ0XTSCVDFRqat+umEFq6VhCgpK0KTb0rC7IpYmE/XniekFCk6MJp57Hd2+vzENCAAJ\nwMvdn2MAJndvh5Tl7t02uh/I1v0g+ysLWxCEIeDfcffbd4Hfd133NwVBiABf5u5Np9aAn3Bdt/Kf\nvj8V24MzFcL+El6vQt3w0oslcTrQ2vPiKDKC2MV1Rfa8afL5OPobbXasASxDIbSviOy1ENs95r95\nEM/H6iipDnZIRBsIEJ3tcOj4JU5NXyQqFMn3wlwtnKBYOU6sO4IvUSOd2OAQ14g6JdZ6YwwObFEX\nfawyzirj9JB4nmdgABKRPdRij8OzV5kMLvA2Z9lmgB4iYco0LR8r3Ul6yAyKWxx0b2JbCtlwnG5C\nwbhT4Kx7gaSTY0mcYmdokMCnO/yM9nk+3foK7qvQCXjIjcWw0yIxJ0+wXaPoRLFiIlZAQMEkZWXB\nFpjQlhCTDneS41QJoNPGdiXOtc6jWDa4YHkVttQBdsiwNymRtPIk5BwdR0fXu0zuW+R0/j1S+Tyv\npM+RCu1wuHeDRKPMo+3XOSFfpeCLUJEDjLLGUa6yIQyTk5J0p1Qy7i6f9H6Dr7Z+FNvahy52/l/2\n3jtKsuu+7/y8VDmHrurqrs5peqZnehJmMBgEIpIEg0gFyrYkipJs7lnTWunQkne9x2e19rHX0tHq\nyGtZtLTiUaAoUhRFiqAoEBkYAINJmNzT0zOdQ3V35RxevbB/VBe6MIZWlKGxCFDfc96p1/fde+t1\n9e3v+9X3Fy7Nup161U4lZ6NZV1it9nNj5QDdbNLfWObpP32S4hNufPsy2LdULA6dWGCDh82X2M9l\nyrh5zTxJDTtuSmxUeijhxDZUwjgrUc/YSaT70FYU9KYAgsbByJt0+xLoNRNR91J7Fwv/3a7rH1wI\nIFvAakfxqDisVdyUECsGQtXErEHD8NDEC4QRCCPgxARaeloaSCFTwyIUER2AQ0B3ipRwU2s4UIsW\naNRAU2Fn5D+ghe/Fwm4Cv2ia5mVBEFzAm4IgPAd8BnjONM1fEwThXwH/687xNvR7lpge+0sO2C8x\nywQ3mMRAYvHNEZLfilMZdCI5dK6qR6g/ImGbrrL/SxdYlIeo+m3MyyPkVrvIzQbR12XkiobDUoEo\n9P70OqEnMpzefIA3cg+g2Jtsprspu53gNJAUDT85YiQ4xz3kqiE2U324unI4nSWcVNgmgomAhE4y\nFyPYyPGzoS+wao1zkwl+ij/iIod4lftxUSa3EaK47mfv5GW6rEmW9QEeWn2dqsXO2b4jLHCba4Ib\nXZxlQFjmp7x/yJHpN9nbnEM/C9UvwcV/uo+l6VFkq0p8ZoPqtpvfPvhZFEeDPdxgH9eJb20wvrGI\nMWlwzbOXsxxjkCU0ZF7VH+DDbzzL4PIG6LDwSD+rI31cJ8J3u/azx5ylJtm4t3wONIFvez7IF0//\nHKm5CMKn6wxElpgXR/A4ywyyyCCL/BPpS1xjigscwUmZTbpJa2Fy3+liX/M2P/roUxQ9PgY9S0wK\nN8g5A8yl9vD8H3yQrBCibgwj76shOVVkmgz9+i2umtOk0t0c3/s6exwz9NtXSMkhnuUJ8vg4p9+D\nIYhYUDn74n1sCD24PlSmueTEXqjTF19gs9pHZisM6zK3zXFWhX6qFzyMTMyRfHdr/12t6x9cWCE0\nirj3KL0/fpsTe1/nE7yA/7kSlldUGmfhek1mxbAAThQUZCQ0oFVsuQlUiKEyYtFwngD9IYX8B1x8\nk09weuYgS18Zx7hxDrbm+Qcr/O34GwnbNM0tYGvnvCwIwizQA3wMeHCn2x8CL/MOC7upKux3XyZA\nBi9FAs0chbkAxbN+CudkfCM5zF6TdDNAU5eJWWoMH7tNpWGnajroE1epJPw01uxggSYKjaYVQTao\n2R2kDJnE+ThVhwNh0ET2NBCDGlZnnai8iXVLZWuxF/tEGewmVnsNWdLe0n23iKIhI6PRb1kmLKRo\n2iXWz8YpJrwIj5qIXgObUeeEepZrwgFed/ahWJoYokjWDCA7VAJylS6SVHEwzwiCAMNLS3QbW4z1\nzmJf0BBqIE9DedhNVbIxdXURd7VCPWil27GBu1SmP79BWMzhb+RxOGpoyxKERJKxLgp4gFZ9D8Em\nkA6EeMNyD6pDJkMQKw3sNpMmMqv0UZVcBMwCB9TrzNoPcCl4kLi8QIRtqoKDnOwnmM5gzWrc7o2z\n4eilgos8fqw02M8VcnRRFZ2krQFMRcCuVLFTxUGVstWNZDGplW1QdBHsTZG0hLkpTGA/UMFTzFOv\nNBkILuC15EiZIea1YfJaa7eckuCmS0jioUgsnCAopIlLy7wUf5x80E/YvY3ZJ6K4GqiKharqwFpX\neTT0HIfd57n2Lhb+u13XPxiQweGA6X4mBxYJJVYZXTApVtZIZdeJzm4wUZ0hyCLOxRpyVsOqQ5RW\nCRqJ1uZDEq2nI4DYmhU/4DHAmQFjQUZ02RjnHM3lKpHcDWLqHL6+LbQnRJ69biMhTMHlFahWYYf+\nfxDxt9KwBUEYAA4CZ4GIaZrbO5e2gcg7jSlWfK1tnwgjYBJXV1m/NoR+04Kk6gT2JrE9VKWsOEmv\nxJDK4Avmidq2EDA5xEXSiRirm4MQA8MholVkdENiY6mP5kUb2usKhECwG1gmasi9KlysE5fWKawH\nuP7iXu4NvULvyDpdwSSSpGMgoCGzRRTdlAiZaQ5IV3AKFc5zlKWXhhHOCtw6Mo7qtbDXvMFn6l/i\nGfcmt/39yFITTVNoSFZqYQt9bHHcOMu3zAOs04tqWvjE/HcY1+bQ4gLqugUREeN/ERF6Jby5Egdf\nuk7tmIJ6ED7FV3BtNHAt1rEoKmq/SHnYiuUlEKugxhTOcAwnFY6L56iN21mZ6ON3Qj/DHmbpMlOM\nGTc5YFZBMHmN+3jF8SC9WoJfK//v3JzYz7mxY4TdLX28vQGyK1nFNqfxl/6PsuroJUaCGnbCRpJ7\njTNcHzpMQorybd8HuS0OUcGJgEkfq9j8NWwna1RPmYhZEVt3ndvaKDndT02043Xm8HmyuCmyTi+X\nOchqM07ZcCGJBsPKAn2sMSguEb13CzclBllk+egol6s+5KpOMJDCGq5SUVyk5rvpqW/yMw/8LhPy\nTX7lv3/dv+t1/f6FjChLWD0qVtVEdlpQH57g5MPLjJ+f5ZPfucL6qSaXsiBdahHwTVq7t0Hr5yYt\nIUOmRdzGzqu5cy4CGWCjCcpFEC5q6JQJ8F2O8132A/eJMHDAQu0XPSx/+QnKwjjW+QRN0aRuEVCL\nFgxN5weNvAXT/N40op2vja8A/840zb8QBCFnmqa/43rWNM3AHWPM4UNe/AMOknTh3BMnMBZhZmuK\n/FIAlkQsPQ08A3kCwym2K1E0U8ZryxMW0zjECgYiS98ZJbnQDXtgz/g1As4MVy4dxNLVwG6tkfxm\nlGbRCh4TIaYjjJqIpdcYeSiIXauhlqzUfVaqmpNKxoPiryM7VSxikyYyvVqCD9aexXu5QKni4tID\nB0iUujGqEmM9c7gsFaxmA7+eQzBMdFXCma6TcoTYDEQ4uvkmYSGNGrDwe2/uwXL/IXzk6CkliJpb\nBF0pcpUgec1P2eYiowRw5qrcf+Y06qhMacKBQpPtRoSi6mWEeRSLSkVxslmKkZBjbDu7qOIkSJoR\nFihq3lataDmHiI5Tq7FyapM993upK1ZULLzOCRqanZ+ufolZaYKbyhiD8iJ2sYaEhoMa9bqVXCPI\nujOGKisoaDSwUah5yebCZEshTBm8XWmctgoWpYmByCBL2LUaK5V+br+YpTL5GJZIDaWoIZVMDJuI\nPVDB5S/go4CMhomIYBhUcZA3/FQqHrqlBIdd54ixiUKDMi6+u/xRbm+MYU9XMd0iRkDEiIoIK1dx\nLF0kLq9Sx87cN+cwTVN4V/8A/53rurVZpmenJbxz/I/CGhC/S3NHcUZcjH58lYn5BaJnEix5XNid\nRXLVLSaKJs1Ky33Y+cF3ErK2cy7RImdh59WgReziHWPa0NgldCdgcQk0e0TO59x0ixGGSmU2j/cw\nOzTC7W/FqSZL7HxJuou4m591J1I7Rxs333Ftf08WtiAICvDnwJdM0/yLneZtQRCipmluCYLQDe8s\nKT7y+T1E/9GDfLf5IUTRICImSFX3oV+IU3omgJoCzZbFemyZIX+DcsPFxkqcoHUB0V6k5PTiFey4\nUyK2exrE4y7Euo7AIwwfnKE/tsCLSx8iuxEEH5h7DMwhARYEmvcfwx1K43JVyIl+6qUg+lYQuauK\n373FuDRHDTvTZZ1/tbaBw1UhpWuc/USJdMoGKZHeaANnoI7mFllhmqCeZSS7QPzbSTZ6JW4+EOTY\n6wai1cfCgUFi1l7GfqSPI9UMftFKWLTTI0jMWwPclMeZZYJBCoylbvPIkEhpzMH6eDfbROjCjYDB\nOCV8m0Wa21ZOjUxhcw0RxIuXAiPkmUTjDGNYUDnJq61Ii7zOpbUS+5+MUfC6GSyuMCWUyBkW/kkZ\nZn06sz6NHkSyxKlqTh7Mv0bS6uaye4gDKEjoKEAGL/PlUa5mDmFr+MgJPratfrptm6BVqeft6N3X\n8PrX2A9kjTTGvT9Eo2JBXVUwcxJ0gziaxT+4QY/jJr3SGl0kCZBlnginjAcQCl1YxDSyN87D/Cke\nirzBcZwzH0d/+R7KXwXGaMWBmzDw6dtMHrrCMc4xzwhzwme/53+Hv+t1Dcdp7RD894W/y/f244mK\njH4ggWfGgj9vMB43mM4WGTA2uJWEmgHngUlaRKuwS7adhNx2E7bb2mifGzuvEi3yUTva6jvjHDtt\netlEm9Mpk+cxMc8+GywE3LwZ17lltZDdH6I46ebWyz0Utwwg93f4mXTi7+Pv/H++Y+v3EiUiAF8E\nbpim+Zsdl54CPg386s7rX7zDcK6o0yzVT7BYH8JhqaI4m4RcaTRslBIBuGiS3/ZT6vfy0RNfRyjC\nyrNjzNgPYgREiMGBYxcYj80QELO8UTrBlcpBhP0y0Z5NRq23OD32UGsPwT4T6XgTMy1ivCizMDvO\n2nAfjsECQSWN01NC9GigQw8bPMyL5PERU7cxsiLV+6xYohXutZ7G+YyK40IT7oHN6RBz7mFWGGBF\nGiBrBHFcP013LUH4aAJXpclVZYqn3Y+iSbeZqs/wyeRTCLIJsoAhinQFMiTlLCYCe/XrHPVdQHqs\ngYGTsuriNeUkU8JV7uUcGYJIt02iZ7aI+rYpO5w4qDEsztNrrOPRiwxKSzRFhRIeJHSEiomRFNGK\nMpJi0LWc4yflPwUZTEMgZt2g6YSMHGReGKXQ9PPI+mv0ereouW3ohoRDqOERCgiYrLj66HOtcJtR\nZit7KSV9ZDIRzG2R5qxC9UE7m74Ik/oNFG8dTzhH+qUY5rYEMogug0reQy6jEpZfY9J2o7UZA0ma\nyKjio3T716hj4znzMe4TTtNlppjRp8hbfK3/5OsmOAUEw0S+otHVtU300DYFvDio/q2W/9/1un5f\nQBYQrBIWNUJ8GD7xf8wy+IVT2P/TDNv/pmW7JgE7rUC9Nsm2ibpNtPLOefuw0iJ0aFnNTVp/Tgtg\n22kXdw6tYz6JXd27bW1LO+MMAy5XQf+zm4z+2U2OA9UfmWTxsyf5k5+Z5nbGRLWUMOs66O/fyJLv\nxcK+D/gJ4KogCJd22v434D8CXxME4WfZCX96p8G3nt2D0jhC5SE7E703uZ9Xuc4+kpVuyJhYfq6G\nMKVjxgQc3goBb4bjP/Yqc41xko0oZl1h+Zlh0rkuLHGVrCuIHDBxDGXIBd3c0sapH7fDElibDfq9\nt6lqbtZlYA00LFRtXqwRFYejjM2sk70Z4SZTNCcVHhJexuqq8RcTH6Zo9yBYdPqEFfYdnmPAsY5w\nDW4EJ3ll6D4sqKQIM+8bYf0zcU5cP8OJL5xBOmrCIAiYrew9h4X5WD9uoUhDsLIu9JKyhMjhpY9V\neha38ecqyD064RsFjOwKm09cQ/ZpzDFBAQ/6pIInXOKweoW9K3OUrC5eCZ7k5eTDrM0MEj24jhDR\nyRLgh/gmU4EZ1ka7ORKpEsltIV3TwQvNuEx+wIlztsrYmWUSH6hQ8rlJWyrogwbLSh/Pa49xbfsg\n3emEAooAACAASURBVJYE94dfYh/XqWHnBpMImAxYlwhHUoT1NGlnmBd5nLAvjT3f4Nz1k9RyKWxV\nFWHWBDdYJhqEjyXoDa8RsOR5s3QPFc2F4m7ipIqdOoMssZ+rrKp9fKv6cX7f+RmsRY2F+THSza5W\nsN2nBChB0Jfi8L89y8MHnifOCpc5SA7/Oy23vw3e1bp+P0CZDuD8pb388O9/h6PnX6X+uTTVpQw6\nLemiTZ4ybydTds6FjqNNzCItAm5r2CJvt8bNnb5t56OFt1vonbKJwq6z0mTXStdpiQf6t9fwX3uW\nz9+8xNlH7+drP/Uhyv/3HOqFDLuPk/cXvpcokdd4+7ebTjz6N43PrYaw1gMMS7ME5Qwl3Dip0BXZ\npnLCg/iYijTYRNY1NJuILov0TSyxPtsDG8AWGDWJut1GyeqmXnVgNkVMl0hC6iXnCFIfULDYajhq\nZRy+CpqgIAR1TNXEyEloVQuyruGkjJ06yDIN08oqcSR0/JYs+aCXeYbIEqCBlUBPEY9UQi7qyIJG\nbGmb6Oo2m905FsYGyE95KM54UJ4xwAreYIGx2C3y6+uEFsMsj8UZziwhYtAIyFQFOxVc1LEhVARs\nmSbYQGo0cIoVbNRJEWKLKCoWmiELhk9g7/YtwlqKvOilgoMtMUpSCRMUt7DSREfiauMARcHHVuAs\nV5xxgpUstvAVPNUKuYKPlx33MmG/zZg5j1AyMDWZNGlyXi9bShc1zYYmSqTFILPsIUSaLEHShOhj\nlbi8hkNubW3WlGX8QoZezyo2rc4teS+yIKHYVIQhHWekSGB/hnjfEnud1/HVC1xbn2bN3UfW7SdF\nCBmNMW5hpYGNOr3iBiXcJHI+Vi8MYvYJSD0ayscaNE9ZEBQD+aSK5hOpYaeBlUzj3WnG73Zdv3fh\nAXo4secs3Xs2KNRUpppnGMicZ+n5t8sabStY5+16c5ukxY6jbQ3b7uh35972bQfknfO0HwA6u07L\ndnvnw6KtkZcBYb6EY75EnGVKTYXD9SiesXkSRQ9v3LoHWKeVlvv+wd2v1qeA65ESj8WeI2kN8h0+\nzAlOM3b4Js7DJWqCHSsNfOQp4qGOjQhJ5CvAazLClknkn20QeCxJUXCz/Uac3MUwpcUgpSkfTOmI\nTg3PdB6vM08JJxWbDWFABbuBaUpIkkFISBMhgVVQ6R1fp4adbSI4qBIjwTHzDAvCMLNMkCbEqqUH\npa+Os6/C3ls3ePDUafg65D/oYmMszFX2EyhkMGdBKEKPtsFjkymal2pM2Pt5afQ+RhZX6TLSCEd0\nDEkiSRfXmOKA4wamTYAc6ONQ67aScERZp5cGNiyoJOliSRokEM0SFpKkRQ86AkM9tznac4YwadyU\nsNDgt0q/wEvmo+wzFvhjfgJrV4N//eR/YOTlFTZSPfyu/ll+dP/XGB+ao2srQ3QjQ17w8OLkSYqK\nh0n5BtPRyywxyAx7CZGmgBcToZU6zwIBsjzDE6zZe4jFlxnmNpKpc/WefeiLdazddYSfUQk7Ewy7\nFugWNhlnDp9WwLFRxegSqcdtbNCDkyp7mOU5HqNicfIB5UUMRBYyYyyfH4MgyPtUfP1JiltBikkP\nF4WDZPATMxM4qJIsRu/60n3fQRAQ6EEwn+SfP/kN7nV+jWf+Z9CrsMQuMXYKCm2C1DteOy3dtmQB\nLTJROvrB27XsNgHDrkX+TpJIOwzQ3JnPQktmse+0qTvX2xLNDaD5/Gk+/sZpPvwv4HTgH3H21kcx\nhacwKcL3GFjxXsBdJ2zHwwWEHpU3LQc5yjl+Wfs1vrHxKW5fHqd+xYb9x0uMjN1iLzOtncrx8yZH\nGDtxg5HROep1G+vlOLnTYaYOX8I7WmLZOkzmWgStJMMtATMoUcn6aQpOBM1Ek2TMogVzTqS/f4np\n2AV8tgzdJOhnlbMcw4LKMc7SwwbkBJy3mvyw59scCl4nGfRzlnt4znyMh6SXGelepHJkk2gqTX7Y\nR0rvYn9+Fl8mTakODjfIDh27plI7qLDxwS4WhSHSw110mUn6xOXWBrV46SHBWneM7/oeRsBkwx6j\nbrFxtHGRk7yBLohIpoFYA6WmEde2SbqC3AhOIgBx1hlmnjkmqOBkD7OMum9iqzQZSF8nX5phyd3P\nBY6QnuzC0ajyWft/pSkqPOt6lOneq1iaKilCbNh7kNAYqC7TfzaB6ZU5c+g4t3YcmiPMs4cblA03\nv9P8LAkjRlW047DWWGQQQQBDFGkKCpKs84DvFbZu9XB96xDz8Rq1qItJ9zWmp86zrXTxtPohwnKK\nIXGJQRYJkCG3GOT5Nz6MGRaoOWzYf66AanMQI8GH+Bav7nuEW+VxDKvIanKI9VvDyKc0ivtdd3vp\nvr8gy3DyGMfJ8M/PfQb30+e4CoiNFiHK7JJsJ721CVfeORzsRn5o7FrRbTLV2NW72yTf7BjDTntb\nsLCya723nZUWdh8cnXJMY2esvtOn/X5tmUZswNVvgcc4ze8pn+a/3vdJzon3wqlzoL0/wv/uOmHb\n+uroikRaCGGnxgGucNp4kLTeRbMpEzPWiLGBgYhCk65mmv2VGaRok0afhS2irL4yQD7lp96w0xXY\nRlJ0ymU3+pobVgVkf5OgmMGn50kbIcrbHlgR8IQKuGM5ZGuDctYD8hbDgVbNkiIeAmSxoGIgohsy\nE+XbhJQsL/hPsinGWGKQAZYpu12s9vdy8sRZSmEn9aad7uU5nFqe+pRA44SMPipTE22sxYLoo5OU\ncVENONAR8NFyNroo4yeL3ValarGTtgTYEqI4SnWGZpfxBvNUe2xUTBfuZg1PrUJSDFHAi2iYpNQu\nuoQUfdY1NuhFwMRPjvuk09gklYxZZ8BcRkOkgpNq2IaXHBPCTV5IP8Yr1T2Uo06GPIvIaGiI+PMl\nhjZWiecSrNt7CZClju2t+42xyZZpkjZDZI2Wbhwwc5SE1i7xk8INNtmmy0xh0TTsWgOLrlIwfKya\ncTxylnB0m4zuZ0WbwEKTRK2HQilAvuhj+2qMhXNj+I5lkWJNMExwGviULIe5SHIwRq1pxa+k2DJ7\nSGox1JIFUW3+/y+8f8BbsAzYcUx7iTgzHNo8z2Hhz5mdM0lqbydj2CXTNnm2LeJ2Hxu7EkibgNty\nhUmrRli7r8SuhQ5v17zbc7eJ3GT3gSF3tLUll7bV3da52w8EgxZ5K4CpQWYWguIKh+RVDkl9FGOH\nSX40QOVikcZK/d1+lH/vuOuELTd0yik33u5b1CQ7q3I/T/Z/i/vjL5F5MsCkMssGPTzFx7BT40Tl\nLP9m6Vd5uf8ErweOk8NPw28jJwZ4RX2Ax7RnOei4yPzeYWpJO8KGiL2ryKHuMxwSL7U2Fvj6JKmL\nBvH/soi6V+KvCk+iX7Nz0nmKe4+f5hAXSRDjLMewU6PHt0HmHjehVQO1biFpRrBIKmFSlHBxk3Ea\nTitdx5I4hQpKUUW4YmJ1gvw/CWQecJDv8ZCWQpwXx/HzAEMsMsAyYVLYqDPMAk1king4WJnB3azw\ncuAEe6UZetMJPF+rUD/hYHO4izlznEFtjXF9gbOBQ3gseQ7ql/lC9udJKml+OPxnTHIDEYMI2+xt\n3KIg+viN8AD3u9OcoJV0NGrexkWZGWEvr954iFMrD7H6ZJwfC3yVB3iVCNv0L2wwdnEJ4ZhBpH+b\nI1wgTYg8PvL4sFJnRJrnMek5Xmp+gBx+osIWVRyESfEhnuZ11nCrXfzJ1qcZ6b3F/ftf4Ka4B4RW\nJmk3WwiSgVsqsY/rJLJ9fPXGj2LOCBjLIkLOZHh4DrMqcPE/HoPPNrEMVPEJOfaFLuMlTVDIcLHr\nMHW3hWx/CN28+2re+wWuh4MM/Oogj//sf6Dvldd41jCxmLtk3CbBdtJLk10rtlPuaDsC22PaxCrT\nspRhV+Joj+90/bUtZdh1TrYfu+2+nYHH7Xna7/FOaIcYtu9PBdIGrKgm+1/+fwh85D5e/OIvsfBL\nq6R+f/Nv+KS+/3HXV73FWmcsNMMHlaexUuMNjmOKIqYIomzQwIaKhR5zg6tbh/h6vZ/57hFW6WUj\n0UMmESGXCGFkJOozHi72HmdhoAB9AoNH5nGM1kg4I2CaSIJG2XBS89oxwgJpR5i4ssxH3N9G3mNg\nyCK/z2ew0kDFQpYAT9x8gZCaZ3Wyj0RYJ6cFSMmtCn52akTZIsoWiqARllL4Xy4gPSvgtNaY3zPE\ntaOTuMN56rKVFGF6WSfECq9xHzVsiBgMsEzPxha6JnO914OgmgTSOe5dvkCx10Eh5OE7P/o4SqSJ\ngzIeoYhHK6HXJQqml4viNAW8GD4Tq1jlGlMk6cJEIEGMEesCoe0cgzOr3PN7SVKeIG987B6KNjcG\nIm9yhNqYhX2xyww6F1lkmHXiNLCS7Q+RdQaoReysOPpYYJAJbnK0/iahcg6LRyVr8REjwVHpPDJN\n7uE8s+yhghMNiRx+ckocMaRiWg3qso0aNkrzUZIbveSnV7F7q4xyCxt1NEmmaW9lp+IzEPway7Uh\nJEHH/rkS2qiAIbWKAR2vneekcYaC08m2ECVv9fHxyLdIGl08dbcX73scNh9Mf9ZkwHuJrl/8c8KX\nZpB19a2klrY+rNEiOthNeLHTsqbb1mvbKm5ft/H27MbOZJm2Nt0m2s4wPY1dcu2MHIFWskzbOtc7\n2hXeLtm0522TezuWu9PhKQKmruK5NMPhX/hN+ieHWfnlMJd+R6DxHvZD3nXCjiurHHW/yGEucJtR\nrjFFEws26vjIo2JBxKCJgqYpbEpRFgJ9NFQLatFOo+DCzIiQFtAbFlYtQ8i2Jk7yxLoTBPvSlBoO\nSg0Py40hTEUkGtvEN7LKuHyVMXWWfe5rVO0OtmtRFjZHuKFNUbB5cITKiA0DuaGxZXZjddVRseCk\nQjcJFJoMsoyXAk69QriawZGpI+RFSvudpEYCbA6Guc0gDSyYiIistrRpehlkCd2QCTVzhBsZ9KJE\npJbCUalhr9QZUldYCcfY7I4wd2wUCY1Yc5Op1AxOtYwqyQRyOTbqvaw7vfTa1giKKbbMKDP5feR1\nPzZbg6btBfYJNxAbZbScTNH0smHEWBb6qOLkFmPYonWGmWOSGTIEWWiOkE/5WbEVWZgYwkCijhUD\nkRgJDlSvMrSxzvxWPxlfELNXYEBcRqk30bIWVJeVmsNGSXajUkOWBdyePA6hjI06IdIoDQOhLBJX\n11GMBpoooyNh2sEeKqNWbeiIEAK1YkVqaghuAxZlqgUnq0f6GDJX6TJSVMxh9LICqojfncUmv7s4\n7Pc7PP3Qe0jn4OgWfdeu4fjjs29Zy+36Hu2jbcXeGf3RJkqZtzsP77R423N0EirsatAKLVJtsKtx\nt2WV9mv7vjqv6R19ZFoPgvbcndZ+Z52S9qt1Z7xzNcnQHz9L9BeO4d23j/LDXaxfVMivvKsE2b83\n3HXCPsnrfIrXqWEnj48NejB2NtptYGWay+Tx8ZzwOMOxBSKsc1scQVdkKqKTtGjB3LSARYKHTLAI\naGmZ0reD5O7N43ioQrdtk410H7O5afb3vsn9E6eoTf8lvyj+IZZ8g3V3hAscYTJ5k8+f+y0+W/5d\nnut5GOFRnfykiwweCoqHYZKESRMkQx0bCk16WcNBDauqElguUzzgZOvRMEk5jNNS5QSn+ff8a/L4\nOMhlbjKBm/2ESREiQ0zdZKKwgNZlYjQE7v36BRSXDoNgTkM1ZKeGDT850oTYLMd4+NXXscZVClNO\nHnjzNB+wvUZ51MkznkfIiR6cRoWrc4e5Wj0IMZN4bA13pMTl/X6qP3KQgugjY/eTJkwJNxI6Nup4\nKbKPGTRk3OUKv/PK52jGZYZOzhFlix7WGWCZOKu4S0XEeYOh2VXy8QBP/9QQfcIqa+l+fu21T1Pf\nI9E3tETIlcHDAoPMkBEDdJNglHmGWEQaNwgOZnlEf5E31ON8xfYpLKhIbpWIdY1kKU51xYWwLDHw\n0ALmgsDMr0xj5kSy90W4MHUEu6NOkDTXhCmur+5nNr2XxT0DHPRevNtL9z2N4Sfhoc/V6f78q9hP\nLb1jVLJOK7uw05mosWsNw65s0baKO/XmzgJPbX1ZY1ebljrGdTod2+dtUm5b5m3ru23Rd4b4SR3z\ntiHdMWe7z52avAoI/+8l4g9m+PhvPM5z/8nHuS8ovBdx1wnbpxYIFES+5nqUNxL3kVzrITCZpCq5\nyOYiOMNVakkHm+f78B8v4O3NEiPByu1hymt+zKyC4DMIj2xybPAsgmSSDQa45R5jsHuR/uYyZzMn\nSBW7EXTwkWdEmSdp3eaFyCPM3xoj8UIPkYcTdHvfwDWeR7yqUU87yM5HuRHdR48jwdHyZfJWNwkl\nhp9ca8eUpkGoUKBitzNrneCNyEn6bCtMey5iQaWJTB0vXaSQMNCQGWSJe/grtomwxCDPKY8iuUz2\nFm/gMYusPBxm0T6I4RU5FjpLUM/SU9jmiusgXinHVPk63lMFrPEGgsuk1m1hyxNh1dmHQyqzku/j\nLzc/wYa/m8HuOU66X8diq3Nd2se8JYXuakkV60YPDWxoyOi6RFxcoyI6Oc0J/ORo2mT0SUgTpLGw\nn1V9mIA3xUpwkambs3huVWEB5EEdeUJDFAwMRPCZWKfLnAieZ8R6Gw2JJXWQXPkQE46byKLOQmGY\n1bNDRHs36Rtd5rdzn+PWlQlu3h4n8aFePAN5BuRlSo4gVdWFeVtkMxrHtJsYPwFBJYnSW+dq7QAe\npciY5RZuSoQj2yS9YQSXRkx+7+uRdwNyxELgp3uJOq/j/7Xnka8moKK+RW5tYmtLEu0oi/b1tsbc\ndvi1Ldx2xIdKy3q18XZS7CSSTqdje16DXYsYdq3g9rX2zyK8Vee87fxs1yjpjPWWO651PiDuTJd/\n65tERcVyZYvqr54iMvg4kV8eJfMHCbRkWwx6b+CuE7a1omJfFUkNdbG1GaN4LojTXkaVbKQ2umn2\nyFhyKraESr7qwzRM3GIRqWLgyNcJlTPUhiz0jq7wiPNZ6qKVNX8cW2+ZYC2HVDBRKgYOqlgcdXxi\nHg9F0hg8qz3O61sPUHrTx5OHvkm9x0JxxIEjW6Yvt0J3apumz8KmPUZMS7OuxCng4ggXqGKnZHoR\nVJmGojBnG+FPbD/OlHINt1mgR91ERqMsuThkXCYjBtFlAZUi/awQZYt81Y9qWElZgxSaXsp2J6fH\n72FF6sdJmWHm6M0nCddzFJxevOTx1nNUr2nQMJBqBo0+mVVvjPMcwlsvMpea5KWlx3AeyHGo6xw/\nIfwRc9IY19hHEgELPShmEw8lMjsb3YqmgWUnHeI2I4RIY7U26B5bp7TmIbXUjd21jGazUNS9WFI6\net7CkrMbdcpCdrhVcdFDEdVlYWjiNuPMElQzXEodZrWmkNZGmDKvs93sYiY1xdxrU/ROr5Dt9zGj\nT5NNBzFuCRgnwaZVcUslxIaJKOhIXo3MrTCGT4ABHctoHTNskjS6yBhBVCwEyHLAfxmvUWBV7qVX\nWL/bS/e9B78Xy4iHgX11YmeXsP/B5beRZ2eI3p0ZiW0y7ZRGzL/m6LSsDXbD9tpz3EnYbXRGn3Te\nR9vZ2Bln3fledPSROsa2JRPpjj6d0gjsxnMbG2XU379O7+fGyd8zysXhCJpahPx7R9S+64Qtpg2c\n52o8FH6FjVIfM0vTbAp9mKaAkRLJiBH6Jpc58pMvc0PZw2qzD4+1iG9PhomRGfYYs9yyjmFRGsTF\nNVbox0mVH+HPeWHrCV5K38eDoy9Qc1jJCCE8cp4yLraaUVbPDJHfDiEe0Sn7XSSlMGv2PvqPzTNa\nmOMnU3/KZWWSa/Ikpzz3UxUcRNhklFssMcibyhHmusaZEG8SaSQpLId42fcIxZiHf5v6d0wIcxgO\nkSl1joLVRcIX5leYQOceHuQVfm7jD+huJLFF6iwFejllPcFXpH/MJDMMskQeP36ljICBRWiwyCA1\nA6YqaSJ+Fc9+H2EzibdZoio6+M7WJ1hIjGIWQK9L+BolDmnXcDnLVBQ7JmEqONgjzPJTwh/xFB/n\nPEcZkeeJClu4KFHHRhUHDdHGw7YXcdYavLl9jM+M/S4jsVsA9MbWWege4Knoh9i2R+hRNvggT9NE\nYZU+CniZYS/L2WHWXxvEKH+ZoKfGitjH7cIeZhNTqCsWlruGSJZChEIphA+r1E9aORF5jYri5EL5\nKMUFL4qjgfOf5in/ZgD1WzaoSqQ+FcP+aIXgvhS9yjpRtjAR+Fj1O4hNgd/2/hxe6b3zT/Y/DAcn\nsR+KsO83Ps/g0rm3ane0a3u05QXYjXXWaDn72jU+GuwmpbTlEdglwk4ruC1nqLzd4u7Ux9vk7+zo\n2ybz9n20+7TvoX0fGm+3+Nu6dNtab19Td44au07Szt+hwtsTdcb/+Bm8r+WYe+A3qCibcOrM3/jR\nfr/grhP2t9MfJ3nfCD5bEt9wlns+8jplt4uq6UCvSxw0WkV1565PUhj2EQylOMZZbkljpKUgWdmP\ngEENO8/wBOvpfso1F5WokzWtj2Qjwg1zEp+URREaXKodZFbYQ1GQeXDkBe7rPUXB7mPSfw0/eS4I\nhzHtEDMSxGtrNGSRqmBlTYizV5uhi22uSVOsCXGyQoCq7CBJGEGGWNcaRbubmmBHsBpYsipiAnDW\nIWSQx4mO1NoMgRW8gSx2tYxDrGFVGvSrq/z08h/TwwYuZ5H1rl6y1hDIAlFxCx0Re7jC9s9PoQ7W\niMk1IutpRmrLfFh6Dp+zzPzACOlwiGZAJGpJsCbHOCXezxo9HOZ10sX7mNcnuOKdplvc5CFepiFY\nW3HZOIiyyXhxnnA1QyMoUer2kpP9qEGFmmzHp+cR3QY12caWL8IGPYjolHDjoUicNY5zhh7WuWQr\nsdgzQnPeQWEzSCHiY8g+z0D/Mls/GiXZHcZ0waPW51isDfOGfh8lwUNdsmLulGoTrCZiUEfoNloF\nvKoCmqGglyUkUWNLiNBFlH1c57K8n0rTzUe2vkvQ8y73m3lfwQPs5YHlNR6s/RnW+RnspfJ/I120\nLdjO6A47u9Z2OzyvLS20iRR2HYJyx3nb0XhnzLbCLqHeaZkrHXO0r3cWjmpDZDehpzM1vf2enRmY\nbU28Ldt0SiGd+nebzJV8mYGFG/wLy3/mueRxTnEvcJ3WPpPf37jrhP164yQXwj/MA9LzDPYt8ODA\n81zT9rNlRjEEiZPSy2zeivOtF38EV1eW8a5ZjnKeheooq0aMoDcDAlRw8goPsl3oRStaqITtbAsx\n6ti5oe+h31imW9ok0wxSFR1oYg9Hx8/SI6yzSUuXruBk0Rgi3MzQnd2EJZMeJUHVYWVd6uXB+qv4\n9Bxfc/8YuiARIIONOhI6qqLQE13FjQe7USPn8rJW6IGiSJeeQnQYWHQVl1kmTAofebSgQEFzYNRB\nF0X6qus8vnCKmsPGciTOpdB+ShYXFrlJN5v4jAKKWyP5w12IogWhUYOySPdqkmgmxeD0IrN9Y1zr\n3wdAVyVJNuVjw9qL4ZAYN+fwNpa4qh3gkucQD5ovM8U1LghHMHQJ3ZCpyk4ijSTT5Wuc8RzGHq7Q\nH15AUE3MmoTdaCCZBk3BQgl3S2pCZZsIOiI+o8C0doU+aRWXvcrqQD9rLyaIJRK4gyX22q8T6d/m\nVv8Y84xQwckQC+SrQRpbLla1AXAbiCIoLhVTAn1DIdSfpqlYyahBDK+ElVYcfFKPMFPfS3d+mzed\nBzF0mZ+c/QqFfufdXrrvGTisAgNdFh7LneWxxS9yhZaF2hnhodEib2HnWptEO+OqO2tXt4n9ThJu\nH3Z2rexOh2RnuGBn4kw7wqNNmm0ibpNvZwRIW2Lp1Ns7k2wEdtPTtY65OsMBO0MR259DW7bRAFdp\niyPnvggBkXTfMMvbEtXGnRW6v/9w1wk73LXN1nU7Z3zHiFo2eER5gVdKDzHXnMAm19h2RSjZ3Qjd\nJhaXiixpaMg0Nh0YTQtOV4WmrFDfqbEh2XVqhkJS7KIsuBBkA7u1TlV2UBZcfNL1DVRB4ZSUICf4\nUGgiYrBJNyEjzY81v4Z1y8D+UgPjtwxsn2/Q/ZEU064rRLMpArUsn3R8g5QYooQLGZ1NullmgGUG\nWhX5RJUz1ns4HT9OPWDn07N/wlBmke5Qij5jjShelhhqZXBKIjlHgA2hB5uuYtSWudE3xrWBSaqK\ngwI+ZDT2MsOIukRXIYu+IiPaDcQunUa/RHXWiutP6/Te2iL3YIAbj+kc4iLDt5bp+nKOgb4E21Mh\n/shw86T/KU6arzAjTtJrrBM31liWBzhevYClofF/+f4lkt8At8HvmP+MouZhgjme2HqR8eptFLOJ\nvVSnEnCyGe7m4/wFcdbI4+cqB4ipW3wo8zwpX4RueYsvCD/P02qOB0pPcdWYQEdEwCRGAisNknTx\nDE+woI/TzCksvzgKFjDGBHxTafSUTPnLPj7y2JfhuME3G5+knnTTZU3yuPAsL9ce4uWFh7nw/Ek+\nePIv+Ujw63ieLnLxof3A7bu9fN8TGIos8es//WWk88tcf7pFWu3Mwwa7RNjg7XWpO52Ib6V3s0t+\n7etixzg7u4TZJsI2ubcdmHcmv7QfBu1r7bTytruvTehGR3v7far8t/WyYdfS7qwqKO78jkbHvJ21\nSjpRolXf++h93+DI0Uv8yy/ez8yK76/p/f2Du07YmkWiZ88Kg+55aoKd541HiVi2KbLMarMP3ZQw\nDAGa4Ddz9AmrjHKLKf9lBorL/NDCU8xExrnsO8AGPfR41vDZC/ikDGuBPrat3cSsaziFMh6KiJKB\nnTo+obUDYjSfxJsqc6r7PnCCRVLxVqvYJBVzD6yEe0ko0VYFOLefhk0hL7ay/BJqjLn0Xnqdq0y7\nr3CgMYMmSmgWAUE0qVtt1GQ7F+LTFOsu9qev0aUlGWEeGzXKuNENmYiaQRYMlIKGtKQTkVMUbOtU\n4g7CSoqgkWWwsUZkNYNju0Y5ZKfhs2AICrZzDZKvaVy9ajJZVenp2uCeh86jSyKpUAjlhM5GzwL9\nkAAAIABJREFUoJurwf28ccPBnmaZQfsiTWTsQo2i6KEgeLmtDFPHzkqzH0MRaFgtxPQER7jAPq7j\ncJUxy+DeLqOFBQyPgc2sM5RZxUuBi6FDzNT2YdQlbsj7WK33YpVVHnG+gGKeZl/6Bu7ZAt8Jf5hz\nvqN0OzcoSm5ShPFQJORLUhjz4VXyNEWFcsSFP5rG5awilgUqfXb0sMigvoDFrhMjgSQaoAg0FDsF\nvYuL20dxWqqIJ0SuDU0C373by/f7HtYnYlgPuqgv/TnSauYtcoRd6ePODMO2067TEXln5bxO5x7s\nWqqdlm6nHCJ39G9HfnSWXe10OHbKJHTM35koI3W0dZZo7ezT/n3aD4B29mVnrZL22PY9d6a914Hq\ncgYhaMP6j+NYL7poPLPx133U3xe464RdqbqI920x7b7MphjlFf1BPm59ioCQJWsGsAp1ZE1DKJv0\nauuMcpseNhgILWAKMg/OvkrDrXDbN4KORI9rgQlutgrY+02afpE4K0RI4qWAhE6T1lZXDppEyin6\n1hK86H+IrCNA3XBglBoILhA+BomRKCvWXux6nZzXQ0F0kiZMmhDz2ijP5x7nh/gGB2zX6KluI2oa\nFdHKhq+HimKnLtk5Ez+OnNU4lLiK06gSIoWIQVoLozcVgmqeiJlCrBhIRejeSmKERFKxIHalSq+x\nQbSRQsiY5NNeyvusNHwWhJSA5+UKlStNZhWIawLdjTQuLc8b4nHW4zGIG8wwzsXSNOvP1MnUUuwV\nbzBZnaVmt7FgG2aLKBuSTNVwoOgNFs0hKpKLTylf5V7hDQaNJRKeHko5J/5GgUzQQzMo0WNuIBVN\n6jhQfVZm05PMaeM8G3wUteKgp7mBLVxBti6RN9NEEymyhDljOcE++2UqkoMadj7AS4R8aay+GpYJ\nlQYWKqYTS7NJzJ5g9InbXGcfZVyMiPP4wzkUTWWl0k9FdiI7NYQuuJg7SsLWS+4RL033nYU7f9Ag\nAVai0y66D2vMf1UksNwir06dt7MSXlvOaNehbofrdcZIt63r9nlnFEdnCrhEi/A6k17axNi5wUHn\nvbQfCncm2LSllDuTdzrvoU3YbYu5Lbm0LezOeG062ju/HfAOP6euQbEs0PPrVrKGk+VnHOyWmfr+\nw10n7Oqsk5U/G6H3hzboim7xJH/FR+tPc1sYZtMTJSptU8NNe8PdQf4/8t47SK70uvL8PZP50ntT\nJssXCgWg4IEGGm3RIJvNNlSToiTKBUWtViONQruzmpkYxUzETsyuNJpVhDRrZ2MkraRZylBkkGqK\nzVYbNtsB3TANDxQKVSjv0lZ6/8z+kXioV6WmhloSTczujchAZtZz+fDl+W6ee+755rjGPj5onKBh\ndzK8f44lZwIRnS6S2GmSJ0CSLtaNbuqGE0VssYtbHOYiAb3Ah8IRvkuIWTzEfDkGBtdwOmsojSbd\nG1lsN9VO6fgQhNwbKK0GA8U1Sh4XVZeDMBsEKOB2VBkYWuJQ6yq9pTR2o41wy8Axr8MzkO8OkSfA\nk9pb9NvW0MMiOSnMLXZ3aI7CbUJ6nlQoRLhWwBOuw6dgIdZLKhZht/0GdlrYJJWsx8/63i6KO/2M\n+6aINjZw5tvYC21G90D8i+AYE6kPSrQUGwPCIo27re/7uMYuxy3iwQI/I7QJLRbhssFrBz7B+Z0P\nkaSLZzLfYX/5Oqf7jvHtygvcLu+m2Buk4nDTNmwMZNdwSk2au+y8F3iMtBThhPA+r/WcItbM8iv5\nP+HWtQPMCWP4TpUp1uwE1DLHOcc3u7v530/9OPukqzhsJY4oZ0nLUTREYqQ69rWc4yRv8Uf6LxEU\nCjyjv8o3kl9Al+2c6nmTKBnW6KGOAwFIFnu5MHmCYsRLQ3SgxwS4DblsmL/tfYGh/jv3e+g+4OEB\nxnj+z17hhZdeJbmevkd/mGBsgqRJXTjvPux0aAezaGfNjrcbhG/3vXawCcTbgdVaoDTPby02qmxV\nf5iTi0mpWFepMcPKYZucuLbtdYNN7xLY+svCzPKt0r/G3deeu8/D62n+u3/9e7xU+jT/K58GpnlQ\nfbTvO2Dr8zKlS0Em2Usq0U3Ik4einWKfl8ohD2eaJyi7/CQmFpgt76C26kLsaTHb3EFNd/Fq8FP0\nih1pl8khq7rM7eZOJEljzDZDkA0AajhJCCvU0y4WF4Z5Y+EwhttGIrqGU6kRbBdRjBaVG0AOvN1g\nS7Rx6TWC5wvYxhu4onbsiyqVW1W82TR7RgT6u7M4gs17BJuui6SJc4X93NJ301NJsVe/wX7fNW4Y\n40jVXXxGfYV4K4erWkVI6mhRkULQQ83jQpR0uptpgskNMuEI6VAUp9xA8Op4KNPChtYSEVwaSyd7\n0F0C7vEqrVibedcgF4SjeOgUNxOssEICd6PGYO4afRs6BSPIzcQ4k95x1uhBRSZgFBnTZ9BEg6Sj\nB92QiEkpZFSquptAKYNxvUVmxs3cT/Qx3b8bvSbTcNvpa63Qf2uFXe5JsqEgXfIK0+5dRPUkPcIq\ngsPPgnuAOytjENRpOuys5/rQbCA4Ddo2G2Ehh1uroRYUKrIdwQs+V4EuaZ0EK0yxk41mhNniKIJb\noyT6KYa9NFIObJpK7+AqbbeNRkuhHlCoyc77PXQf6Aj2N9j7wjID56eRLswhsynJs+qVsbw2aQPY\n6k1tDWu2a+Wft3crWhtatqtETADeXoi06qO30xPWwqCZOVvd+qzXtd0karvPiXkOu2V/a+u8VQVj\nAFqzhXZrjr4jt3nihd1c+1ad/NJH3JwHIO6/5VkWmosK0yu7Eft0xEGNV7KfIXA0R+zQCjOtMbze\nMjsP3+TcG8fR1iTGu69T1EKUVR9vNU/yefvXiElpyngJk0Nt2ZhPDbPbd5NdoVtIqKSI0cSOV6iQ\nzcbZWI7y3vJJ3IM1jkdP428ViDUzoEHpNjAPnmGQenUkh9ZxjguLSIJB4HQV5W/KKHMw9jR4HwMm\nwJBA9cmU+71M1cZ5v/QIZ5yPUi6GOc4HfCHwZa6pPThrI/Q1/pCmrKA3RQJTJQpeN/luL3mCDBQ6\n3trMwOT4Hm6HRhhn6h6lU8GDU2piC7aZeXEQQ4Qe1vEIFW6yhz/hS4wzxQGu4KHCjD5GoFBGWX2f\netbFnb5hvjn6HKtSB6xdVGk7ZEq6F7dYZYdvCsGnMsgcCi2KBIiqRVqTBqvfcFF+xMF81whTpQme\ntn+bvtoy2rLI0CN30Po1xtu38buKiJKOgzoBQKuX+Nu5zxBNJAlKGxRyYeouO4KsUZT81CQnNl1F\nLSpUHU5W/b30RpboZZEaTjLEWGn0sZoaohETabtEbLE67ct2nNUG/cfmqO92UDACVFUP7Y+Em/+/\nhEyst87zX5rE01xm9sKmAsRUXHS22spLW4uIJohagXz7Ki9m0c4K2NsbWkxwti7hZXLWZsYLm1m2\ntSPRem1mA4zV+9pUgJj7m3SNwKajoPk5rUuPWXl181ymqkSwHMtswa8bMKmBc98Sz33xNOsXR8kv\nOe9exYMV9x+wfXToh8PgerSM53CRjZUYsXCK48JZWi47DqFBQC8w/9oYbcHGjlPTNPwOFgtD5Ka6\nuZPYSTnqRUXuWH8WQrS+46a4N8zSsX5ENGq4MRA6HiCDDR6ZeIelPcdQnFUkTWPfnVuEl/OQAXeO\nzm+hZeh6PUN7h0T9cyLfjn+K3HqEL839BWOJEoM7wTUOtMFYgNZ+gWRXhOu5fbz0lc9zbWCCxgsK\nekXk+up+Mtko1drLJP0xfs/766SFOIO+BX42+uc0fXbaSPgoochNDDsINrgiHuB9jnKAy6zRzW3G\nO8ZJTBIi3+HitSrd6joNu4Iodro6R5jFQYO3OMmJ6nn2FG7zVl3jXdcJ3go/wVVxH3FS7GSKGBmm\nfSNc8ByiYnNjp0mMNBI6ZbzUZDe+wRLVn3ew9MwQibE0Lzq/gRj7Og5bHU+8RPpUgI2AH3elxqnl\n9+jtXiMbCpEnSJgVjntfInI0y67labw3K/z7nTJL3gQ+W5G2KHOTPVRkL3J3jYhYxE6TQ1yigYP/\nwK9Rw8VD4nn+B/tv8VfKZ3kr+SR3vrULdUqhGVdJqnEMBGoNN8X1CCUpdN+H7oMbXSiT/fT86ldR\nV5cpsQmWJrdrzWIddKgQM7tusZWPtgKzla82QdlhOeZ2/w5r5mrK8UzANoHY6kdiNYqydi+aFItV\n4mfqsM33P8rlz+S0rSoUM7s2vUis2myTbhHp+KeYx64DyrdXsF0RsU2fAvx0tNkPVtx3wHYOVVGl\nNvGH1ogeTuIbzFP0p5BVjdXcABFviqA9T0JdweWvsdboZW5lDCMmMOSaI+bNYdgFlugnSoY4KSRF\nJ9nXQzyQxKXWmSrupqD4ETwaOgJ73TdIBC8SDF5GROeM8QgPuS6hKC38jTLOHsADQgAct5rYagKt\npyQUVwu7v4V+0MBbAsVlI7UzhLtVQzFaLHh6qPsVnFKF3uFllkM9FLR+DAFUt0xNdNFKOVlvJrjg\n7UjbglIeh9FCkjUW2/2cqT/KoLhEX2AZZbBFNeDETZUl+kkTY5EB1uimKAVYtvWzLsQZZBFR1LHr\nbXwU6RKT9xYEvshhElKShH+VdpfYWWBBsROgQD9LjDBLmBzfaT/NpfYhdss38UplDDr3tGs1Rdd6\nmvKYh9tDY1weOsRBLjPUmCRS3iDtiyArTcSoSlxMktfD3HEPEzcyhJs5Zu2DODbmGV5YZGZgB4Oe\neXpbSQ65LuJ2lDAQsKGyQZhlIUHd6aCU8XF99RDZeBf1gINFZx8PcY4e+wrpUIhcK4Lc1jmSOI/m\nlVAjIrrdIJeNUkkGaK46CXZnf8B10//LjcjuJjt2ZtFfS2PUaluyyu2KCnN5LdMxz8ymt/PP1izb\nBFgrfWKCrdkwY2a/23nre23gbKVThG0P2Jqpb28p357Ra5bn5mP7UmTWicSUJW7/1WAtxFoLsjKg\nr9XQimlGns5SLsgsvfV37/2POu47YHt3lajSZPjEbXqHV/BQoRlSuJ3fzXvpk0xIl/FIZRSxiXhc\nJ7Me553rcXYcvMmJxHt8bvQbvMSLXFP3MVKbY0SfxSa1yZ0M0ycuE2gUWU0NUHB7cUllKqIXr1zB\nj8Z+4SqzjPC68DTFfj8NyUGgUkLZ10Rq6mhjIuossAiOgsY+5QYVvwv5x5oYt6FecnJ77zDdzQzh\nSp5p1xgRIcW4Z4rnf/qvabdgsZpAEMHfn2ek9xbXJnWqRS91r5MntHc5VXmb7vUMrajITfsEf1T4\nVcaCN5kIX8UfLuGhzF79Oh+2jlKTnDRtDvJGL/PSMDapjdTUaIs2dtimcatVQnqeEXEWHZFVo5eb\nxh48zgpqH7TG1vHFW/SwRow0vawSJ4WbKo2qi3rVy0HnZWxSpxHmFrvwLtY5fP46U7FhpnzjXOQw\nD+tnGd5YIDqdx7ajhR4En15mQrzJLXk3b/Q9yeeKL9ObX2PSswshBY6bKq24A9Vlw61VOcKHOPQq\nGTGKjEobG4YhUdG9rKwMUjkTxH60iddWIOpcY1ibx5AF/pfoP2ZqYR9hZYNP/fhfYRPbFA0/M+IO\nSvMhatNejLxAV2yd3P0evA9kCAwcXuPo5/OUzrSQa5vt3bC1OcQEVStXbAKY1XfaBHhTaWFqtK00\nhwlqCpsFS2u2a2b2bcvxzOKeKbuzSve2+5VsV4eYxza9rk1w3t4R+dF3aBOct782j2dq1E3fbvvd\n13Vvi6O/cBVjtsTSW/bth/6Rx/cF2IIgSMCHwIphGC8IghAC/goYABaAnzQMo/BR+5biXvTDNlZC\nfRTwI+gGxXwY1ZCJ9aywku6nWA4w1buTZXcfFIDToERauBNVPFQ4wgX0BZkzX36CixvHESMG+WeD\nTAX24paruOJF2ssihctRxKDOtYFDBNjLMDqP8y5P6W/xtY0vMCPtZv1InKfS7xHXUmSeCtDaa8Mm\nton05OiaSSNsCDh7VMQ0NBt2VvQEOW+EHtcao9I0kXoeZ7NFjzdJXE7hs5XJLzip+xwUEz4O+y7w\neGSVFjL71m8Sv5xFfM3AflJn3+Eb/E7kn7Hq6KaG624XYZtcIcIb7z+LNiAwunuan6/9JXPyIN/W\nn2HpvRHqYS/eo2WCch4bbR7lNAottLZEphpl1j2Cy15DE5ZYEo6jIrOT2+QIs0ovAQqc9L3Ji65v\n4JHLnY5FCpzjGK/t+gTvdD/GeHQSF3X26jcYKK8QOFdG/E8G8Uc2MHYaKDGDscoi3UqOhwYv07WY\nxrHe4FT1Pb4pllEesvNjxsv4XyrgOF/hsS9+gD4h8V4kzAoJ9qnXeLL5LjP5XdTxYtvT5uG+03h9\nebJGiK+nf4oWCtVuO3XFQU1zsiAM8VztVfxaiYrHQ7p/lUZIodTwkfMHfihfgB9kbH/80dF6jJxZ\n4cmVJJdKjS2NI9bCnZUCqFm2UdjMuK16bTMbNgFUYRNIraoTa3ZrdfizNuhsNy61bm9OHqYM0ATR\nFpYioOU8ZnONdckxs0hpbWtvW7a1KlrMz2/y+uZk1rY8rE049kKDw//2HVrVCt/iCctdejDi+82w\n/1s6ixN7777+TeANwzB+VxCEf3H39W9+1I7hYJbo3usMu6cp42GZfrxSGVlqIbnbFMthJFmlLdjQ\nvQLh3ixj6i1ivjW8lKnjRKGF3WiSUrspl3x4bGV2SLeJ2DPYbC3WfVGaPgW/R+wAq22GFhlsdNPC\njiGoKFITJ3UCrSI2uU3GE+Hd3ofZ0X2H/vYyogqeWhW1YWfN3oUj3kAtCfROrpPrDzHbM4RT76Jf\nWCEkFbjGPuabI6hlO35fAbu/QUtQSNiXOCVP0q46GEouIVRhta+LgFDEVa0TT6yzIQco4EfH0/EI\nFxMsKf3YbQ2GucMoM4TIsi7GSHoSTMs7eKXxLDvsMxxoXuNI+RJVvwOvWEaUdIaEeSJkuSgkWK8d\nwqnX2Om+TUAo0MBBBTfd9nUi9jRZIUIVN3Wc9LNEyJsHm8RAZpW2Q8IbLVMWPaxno8TPrmHf10Bf\nh9p3wU0Zf7zcIfyyQA56K+u4qhKumkbYkQefgdol4XDViUkpBlmgSACXUEMQddy2Cg5XnTZ2fO48\nfnuequFEk3UabSfZfBfNtoMifq5V9zNoLDEmztAnrDCb2UF7zoaWkiglfjiA/YOM7Y89on7YsxP9\nlo5+YR17czNDhK2Z83alBnDPDMrkd62gu33txe26aBPQTAmdNRu2Zs+m7M7M9K0TiJnFm9dqArjE\nVj7d5MKtmbSV/7aubmOzvDavywzzuZW3NqkSq5zQnCwkQGqo6B+uofUehJN74cOrD5TFyH8WsAVB\nSADPAr8N/Mbdtz8DPHH3+X8C3uZ7DOrdnpscidc5zllusJfXxE+xKzCFitTpXEys4KVMwCiQC3bj\nPVbhpz7/ZfIEEQxYE3pYo4eNSBjxUzrSkkrEluHZkW/ykP8cAjq/zz+lOuymd3iZT/IdjvMBN7iB\nqP0E54RjFMQAewI3OVE7x9M33sKoC3zge4iXeJFfq/4BPZXsvX7YgsfNjb5xwkNZ+pZXeOxrH/Dh\n4YO82fM4V8QD7HNeY5/zGl83PsvV7BGaKQ87Jm5i83UWZPDqFXZWZ/BnqwhrkAmFmXpxhLH5eRpt\nB5c5RJYwVVy0UMgRZs3bg/hwE58tj0cs03YI7BGuEZSzrD7ay/v1E7xR+SR1n5Md5Xl6F1Lc2dGP\nGNSJ21I8z8vESPM+o2QLwzjVBlWnh4PSJVzUuMBRVoVe1o0eivjIEUZC4wXjW+xszRLOl5CuaSzH\nurkeG2fSO8aG4uSx5hreXaC2IPeHEO4Vce8GUdI7FRsZ8IF9WsNzpU77MRCeFWk/62TBl0CS2uzn\nGmW85KUgZ53HUBxVwqRJ1hKU8SLTwia0eSL6LqlSD3+0+o8RMKhLLq7kD1ENuTjqOc/TvI50AVJf\n7YMPQfrUD97Y8IOO7Y87pKEQ9l85TvK3/FxPbRo3meBjZp9mdqyySZfodLY3116s393GzSZlUWIr\nWJuFRlNN0QYqbIKxmUlbPUlMfxHYbC+HzUabBpvqEesCuqZIs8Fm27uZSZvnc9y9hjodHYOdTRdA\nq+rFzNpN8DcnEDNM0Bcs25rrV0p0FCPzu+I4f+kYjd98CeO/JMAG/j3wz+noPcyIG4aRuvs8BcS/\n184HucQnmUNDpGAEWDEStAUbgmDQROE4Z+ljCYfQpCuyQoEgF4UjzFZGaBkKg555CkKApkfh0d3f\npTTkpy44OOM6QYwU+7nKAIs4aBA3UjzWPI1LrHJHHWXxynMsuvrxj2/wE5WX2N+6gREQWO+Lkg97\n6RLXcd2sdT5BAloREbu/xr72dZyXWrgX6sj7dbRhGQmdcW4zwBI92hr/ovz7LNoGWRrsZZdjkpLh\nZUofJ7SYw/jTJvN/C3EP+AfK7E1PMbVvjPRAhCFpjsOti2i6zHVlDytCgoBY4KjjAkPiPIPCAhkp\ngiAY2GgzzBwD9kXGxGlUWSbsTzO3I8EV934UmvwrfpsoaVrYGWSBL4b+HR69iiy2+ICHSRMjRJ4j\njcv41Qpfdn2BDTFIQlslXC2REaJcCh3g8MQVZGcLL+XOQgUH7fj+FQh7QFYg9Eew6u9D1CRG1xYQ\n+/W7o7szMoQhsBkwbRvipn2cO+IIDRyoSGSJMMgio9osr+afp46L3qEFIq4MUdLoCJTwYbgMPpl4\nmT1MIgkq18UJYvYUYbJMM0ZWiHYGVRV2x65z/f/FgP9hju2PO/YFr/DLR17jQ99tYOsCtSbdYXXn\ns7aWm9tbjZWsvhwm0FsnAOuKL9bVYaydjFaJnJm5mtl2m61cOmw67pnHMLlw2fIay3nNazIliea+\n5kRk7bY0OXSTYjGPaeXQrQVI6AC+qaAxP5sT+ET0HU4e/FV+21VkkRgPSvy9gC0IwvNA2jCMy4Ig\nPPlR2xiGYQiC8D0dU175vVkufM2B0DJw7SoSP7DCit6HKsh4pRIprlFotkhWulkyPqBmd3HWm6PU\n2qDZcrCkt5GcKyhiE2+zgmjTkO1tdKqcY5lpNAq8SokYeV3iFbWIIQpc/KBNc/UdWjYnjUslPmxO\nk2xqNJpdVPxOSkqGCi/z2lyWixUvzAqUAm50h0BEy6EstxGLBlq/xJ3VDWaVW2hIbJBhWc/jbiTR\njCkUbBSMDco2D6rtJteuVfgzQ0G/qOJ3gXK7BRdyzD6xSnlngbC+QaBdQtAhJyUpy1Eqso8aGjbW\nqLPBMn24kfBTZpEPCDXzVJp3uOLajyypjBhVpoU0NaFMgAIaMja1RPXdVZLt22g2iQIBLhpRVnHT\nLeSpVtfpaqeZ9FzDLrbw6wv8TbuKKkoU5TRnNT+yqKLLaQp8SC5fppED7RtQ9ygUwn5Smg+pqjGy\n4kCoGki6jjLf5ExSoHleAtkgq1dYZ5mUq0VZctPGjp1byNoyTTVLs/nXqK1+SrrGnH+BgpLDSZ3m\n3fVHZE4zT51GxcnSWplaLMOqv0naiLPynT/Gdut3aOt2Vl/J/kAD/wcf22fpzFYA0buP+xkC6nSK\n2u9eJrlY4yxb/TS225CaGaXJGVtpDGtBzkp9bG9Rh60AfYWtk4Q1a9U/4rmVE7dOEtq2v1vpFWs7\nu/m3K5Zr2l50tEr7zEnGOnGY22A5j6nJNt+zUj7mtUUuzRH73TX0ZB+bxrT3MzJ3H39//Ocy7BPA\nZwRBeJbO5O0TBOHLQEoQhC7DMJKCIHQD39Oc+Gd/IcbYLx7gsYtn8YWmWNpZ5Jdrf0BKjnPcfZZj\nrHFreYI/v/TPoQGengLGI0sMijkaG25uTh5iePg2Tk+VW7P7Ge+6wRNdr/ILwp9yyTjEOT7NKWGK\ns/ox3jdOUBHH8QgV/PIUj/+MgEIBA5FhhtHYwSIDdFFkH2n6WaJOlAZ9tJG5yQQg8ijfJKpnkNAo\ni15iJPAyzjrdDLLAbpzUcDGUW+bA+k0MTaAUkljv2+BPxTjHBp0cs1+GFSBPp3lo7zLaCwJy20Bq\nGkhNQJ1jOmhw1R/lEgfZxRRjTHOBg4TYYIBF4nQzvNJi37yddyZ+hS7fOr+k/ve8Y/NwVjzOJQ4x\nyAKH82c5sniNvmePMxUdJYbAtP4cVeMwKanMWLLNU5W3udM3wXHhAz6tXeGc8hAxLc1Ae4mvKF9A\nkHQOcYk+lgjPFfCcBZZhui/Bqz/5FH4hQIgNjmCgI+IuN9ixuEjttMSpX/EiYuCfLSHmStzeo3Ld\nvYcMEZ7mDYYqy7SrTvSgg5fvHOfa+UOIpy4Q67tFP0uoyMioeCnzqvFprl48SOntMI+eeBvPqQzL\nzRPEfyrFQLLBza8cZPDodTZOPvx9fRXuz9g+Duz9Qc7/Dww73fO3ef4PzrOKwQiblIOpOzYzXg+b\nGmY/m9ro1r0jbQKiCQDy3f1M7rjFViA1gf4pNikQqybb6lVSp1OENGWA5vnM41l12NZjWDsRTVA1\npYjPswnwJmCbk8aG5bPBJuibGTls8unQKUJarWHNiaDOZoF2cNJgdFLjj4mzzKFtZ/g44t985Lt/\nL2AbhvEvgX8JIAjCE8A/Mwzj5wVB+F3gi8D/dPffl77XMaY8O7hp+zG+0ffjnFK+w3PGt/ivnX/I\nafFRrrOXbtZphW0kDs9R113YnQ3cQhUdkWZVwbgD61oC50CVUCJF7kaEV958kVt9+8nPBMmlwpw/\n9Ri57jB5V4Drgf3stE0RVbM8eX0OwWkwN9pPijgVPFTwkCFKjvA9gADIESbBCvF6hu5UjiV/P1cD\nE1ziEEPMc1T9EHepSbBewK1VyMSCeF0l8l0evil+howjTIA8K6yT2pDRroB4EoQRQIDpPWOcN47w\nbuUUP9v6S57W3gARVkiwSD/jTDHIAj5KjDHNKr2c5yEGWcAVqrCmRPC5i8yJQ/wb27/mgHCZLpKI\n6Iwwyw75DnOKTkn2cbO1l8vFIyycH8ZRafP4s6cZujlPbDrDl578Mhd7DvD7nt/goHAZ9awRAAAg\nAElEQVQRQTLIiSEUsQEYFPFxk2dwxFoMPbLIQG0Ru6vGPuE6OUKkifESn6WXVXqda5T6/DRTc9je\nhMnj4yjxFiGlQPdMhoVoncneGBc4ii7Y6RVTJOki3rvGLz5xASGsESZLL6u82niGKm72Oq6T/7/C\n1KZ8GI8JTLX3YL/UpOwMc7T7Ik/43+HXH/uP0KPxxX/4t+CHOrY/vhBg6DBFwc+Vha9R07d+cbc3\nprQ296LOZrZs7fqzZpZWtYiV/rCCmXk8k382OWbYWmC06qpNFYhpi2qlPazNNdvVJWY3pmz5LCaH\nbi1Qbm+i0S3bWhcJNq/XfG4WKs1s3bwPVlvWZWBNkqlER8BzGO58wIMQ/1Adtnl//h3wVUEQ/ivu\nSp++1w5tRSYvhDkvPExR9eGrlwm7c8TlFKd5lAoeBJdGl2sVFRkBA4UmpayfYjKI0RQpp/1obpHe\n7nlyyS5Wzw8wVd7TMbRdASYMekMr7HZNYqfDw/pJ4dfaaLqIj9K9pa0cNKjSMb/PEaaEjzpOknRx\nWLvEzuI0vptVNsbC3A7uZJYRQuRwUmPQWCaQLiFmDeoeO+2AzLotypS0gzvqDoSKwGL9fWYDwPBr\nqA+L1A84Kcp+prt2cEk6xBvSJ3isdJp6y8F6d5w1WzcFAthpUSAABsy3hzq6Y9nXcSZ0VVEdEodz\nl1moDVEznMTCWUQXlKWOuEGzieTdfkTFjWGIiIaBU60TUTMcN86i2kSm7aOMGndYKfcwUxvFCIuk\n7VHa9BIiRxOFZfq5wyiaRyTpiVPEg5sqG4Q63DZQviuoaMgKl/37qNZTOGfL2Po1aIKwYRDUSkT8\nOYJGHrumUhT8NBQXG2IQh7/GiP82IgYOGig0KRp+UsQJkaPa8IDDwPZQk9xiBP0DERo6nqeqJA4s\nMz4+S0v5obem/4PH9scWAniPepFlL2srAs3WVjWEGaYLn3XFc5PLtRoyWbNdM+OFrVTKdl20VYli\n1VCb21jB3QRrqxrFPIYogEkyWUHS8lHvqVfMYqKVJ7fy52ambr1Oq4LEvAfWhzWLNwHfCt7mowTU\nJAFphwNfwk1plvvPinwf8X0DtmEY7wDv3H2+AXzi+9lv2JiD9iVuLh/iVfEznFcf4Sftf05bFnFR\nxUkdA4EQG4TJoSGxTje5m12kV7owEiIUQUzqOHZ3rFipAWZ7ud0Av8bD0ff4fOCrTAk7GWCRpLzG\n5N4THa6cEnUc6IiE2MBAQMCggodpdpCkCw2Zw+0rdKXTSGcNmi4FaYfGcT7ASYMpeRwhpDN0zSBw\nqUJ5p498yEdDdNBFktu1PXw79SJ6RmXXIZD+x/+DWp+dpUAXVzjAitAptg7G7uC/lSeXC/HqzlPU\nnE5EDL7Ji+zkNn36Mn9S+RItu50JT6c11k0Vpd3i565+BduKBpqAcELlW4OfZsE5wBTjOB11ZgMt\nXE47+4XLPBl9k/eee4y64eKQfJG3HnmSqeO7+Efyf+Tx6+/yyOJZzj16iCuhg2SJ8NP8BSnivM8j\neCnRQOFDDpMmiorMHCPs5DbDzPEU32WQBfIEeZNTBJTz+OU1HrlxAc6AsG4g/ppOX3CZx40m47VZ\nbss7eNV7irrgRENglhGOcxYnjQ5n76hiF1rMM0TrF0VcWgFR0alNBWi+7YC3W1RdCrNHhrnun6BP\nWAYu/gOH+w93bH9sIRj0fmaRhDKP8U0dvfV3l9My28/NDNgEWCtXbQ2z2Gc6ZpjZq0l1WP2yzUYY\n2KpGsZ7Hyk+bGbBZ7LvnYSKAXQRBB8PYLEpaFygws3XzV4AJ/A62asCtK86YChKdjnpEoEPFNCzb\nmL9CrL8ubJbPboK3dfLy2jXih5M4Ds1x4ys8EHHfOx3LeHnKfp7LOw6zgylGXTOM2aYIkeNJ3iZG\nBrmpc7J8Grwai0of7/AEy/4R3EKVnsFFGm0HjbaT9cV+qv1u+IwKTglpoo1dquMbKzLgnqNLWOdl\nnqOFHYELvCs9zio9+CgTJY2LGlk9wsXvPoSitzj1idewi208VFFosmhLcDrxMF0/lkTrgS6SyKg4\nqeOiRlnwcW7nUTZCYUohNw4aeKhQwUOXc5UX419lNXSGoYEor0tP4nDVKYkeskSYWJniSPsKh/s/\nZNw2RbBW5IkP3kdXRNpOG8dil5gLDzDjGWHIPUeSbrKtKJ56A9EmkhS7cKtLOLQaCGDkocuf4RHn\nGSQ06jgJC1keql5EKag4Nhr0O5OUfR6MiIhLqhOXkrSRWe7roRgIkHFHCFCgh1UcNBitzvOF0tdJ\nhiIsKX0YiPgo01NM8umlN5nv66cWcJIjTA0XVdz4KWKvtxDmDKSqRmXISfVZJ8aowJIrwYLQj+aw\nkRXD+LQSP5f+Syp2NyuRLkCgjQ0ndQ4LF4mTYoFB7I4lYqQ4IbzPtWMHuSweYtoxTnigSJA8U8I4\n15t7gT++38P3gQgBOCV/h8O2KZqo9zoOTS8M609/a4HPSh2YQLS92GiqMUyJmwmK1kYaqxrExaZN\nqnkMjc3VbKwUQ4WtiwdoQPPuSazNPqYG3MxuTdC3asrNCcZUgMDWFnnd8tz87FZ+3UqHbG/OMbcx\nf4ls6rRVJsRrKLKfmww+CAn2/QfsdaEbVRaIdKWw0WaXcYOx1gw9xho+W5E8QURdoF9dI2MEabbs\nPFw+j+iVWAgOYPSq1CUn+UKElZvDSPEmod0ZgmqJpiKDU2dUuYNbrJKkixZ21mq9VIq7uJN9mCW5\nH6e9zuHGRYJyjprHxXxpmLiRwmeUGC3O0daXsQcapKQ4mVCEg6HLuBoNRqrzFJw+AsUigWqRWsxJ\nqifKfPcQkWYOT3qDUL5ALZckGkzhG6vwtjtJIjTCIgmC5KnjJE+QUOsSO9oz9BtzRJUCDnuD/toS\n9ZaTlm4n3kojVjTKuhfJoxLX0tgaOj61jLCuo68K95a4NqoCRcOHgM4ENxE1nUR9lUIuz47VFI5s\nG2ahazBNxhXiqrEbOy26SJKkCzVkoxjyUcFDr7bOsDZPSu5C1gyc7RYuvYaDOjIqIjpRLcOj9TPU\nNAfz9KMic4MJGoaDfmGJorNNKehGR+T2vhHWn4yTYJkSHqq4WbV3oSITVTMcaV8kJwap4iBHGBUZ\nFZk4KbyUcFLHLjaJk2Kc22RGo9yRRxHXBdyxGh4qNHAw2dxzv4fuAxMCBvuS1zmkTHJR1+4B0vbC\nn5WLtXLMsJUWgK28tVlQFLdtt72N3MxKYevSYdaOQyvQW7loAdCMzYKlOelY/UDM/c1iqGnmZM18\ntzf8mPuZ/5qALWx7WP1JrFy99Zzmtd4DdF1jIL9MdP0GMMiDEPcdsKcZ4y84Sg0XCk1m9DGeKpwm\naCtzJzTEVfZTcXjw2stMieMMZpb4R9f/hGd3vsK73Sf436RfBwRc1BFEg6A7z87wTR41zjArDLMq\n9PKk8DYbhPgrfoqjXGAytZdvz76IevEgWlCiGDZ4fbkbl7+M92AO+6fbDDDLsDTH8MwyvmaZ2kMy\n/7Ptn3CZg4TI8/jG+3RV0pwfOEDPZIrh6UXWno/SjNpxqzUeyZwndjWLcEan+qaE8SgIvyVy1ejF\nTxE/RRw0SNLV6WbsjxMijV8uojia1HsVFid6WHT0kxGiiJLO7pUZfn7tK7w6/hS9+jpHa5epBWxI\nLzUZ+f1pXL+lQg/ol0RuRUeZi/fhpczjrdPsWJ7jm9cbKF10KKMrUOzzsNjVyw1pAi9lPFQ5x3FE\ndLyUkWkTaWzQV0vx1/7PcsO7B90tcFC8jIrMMn0YCGQCYVYOxGnLnXpAF0ne1E9RxM/TwutcGFGZ\n+1wfLd3GV5Uf5zr7+FX+TyJkUWhSxY2TOk65TjbhJ48fMJhkNxmiiOgc4Aoj3GE/V/FRYpl+/oKf\n4TY7WRYGaNtsaJKIgE6QDZzqx121/xGGAb736vjkGoJqmG9tyURhqzTNLPJJbNIlVv2zlVIxaQdr\npgp/lxKxSuhMMDUzZVOzbbUwtWqeTaC0GkJJdJoITV21+RmszTum0sMEbOskZNIn1n3MTHr7Wo5W\nMLaaXZnXjOWemcVQVANlso0r33og+Gv4GADbT5HwXZueIHn6xCWyniBZKcAsg9xggngrwzOVN4l4\nN5A9bZKjEYLFAkebl/m5wT+jLrkQJQG3q8U1+26WxB4W6aeHNQ5zkRFmkQoG5CT6WsuUWyFawT72\nDF/nkHSFA/p15hL9rHnjZAhhc6pE6Mj2HJ4GqiJzS9iFhzJHWx9yrHiJuuRk2jXC6NQiUSmNbbxB\nbDWHM9UmbwswFxjk1q6d2N0tJiI3aA9IzNhHWRB8ZFufYqMe4tOuv8Vlq6Ej4l+vEFvL48g1sIVV\nqn126h4HXeczDNxZQxg3iN3K4r1T4dHjZ0mPRTnXcwTZ1iT6UIrEb6ygD9dBVRG6dXrtK6iGgIGI\nw1ZH8qgIPgOhi3s6p5LhZV2Ks0ovD7U+ZEy/Q8nupyZ2+spSxLljH8EQYEXqRRVEeqR1/BSRUbHR\nZsK4QY+wRtXuIk0MHZFBFjglfIcNwne/vG3cthqr9lEQOvWBb/McbqpIaDRRMAAPFU5IH2CjjUIT\nmTbFtSDLU4N0TaRwxTq/ktbVbnQkDshXiJJhObRE8okeZjdGyZ6J4ju4wZBrllv3e/A+KGFA/aJB\nQzQQ7yKXSUuYwKewCUAmKJkeIMbdbc1uPtP0yar+MAHMpDBMEDTB0pwYrFposzPQ3B82Ac8Ev+0T\ni5VysfLiqmUf0XJM87lJt1i7LM3Pu13xYblt9+6NyV9bJx/z3lmbeKymV6IKxTkoJB8QtOZjAOwo\nWRKsoND5mTsszFF328kQYZZR7uij+NQKO1szOPUKGVeY2YEBvJNx1A0bMU+Wut+JS66zMzBLxaGQ\nIkwLO15KDLJAF0lirQ1C5RLecoVLvnnCIQejA1M83H6P5wuvciM8zqRjnCnGKeHDTpsmdophHwUt\nyGnxUTyU2W1MEWnmuObbQ04KMjHzMspgndxIkMxcF2rVTsOpcKNnN/m4H+dgHddIHeywIA9QE1qo\nRoCVVh8rjgQx0ig0CWRLhCZLMAX5T/nYiPmwCSr+TIXQfBFHtIFtSUW8ZbArMcNyfx9vuE8ywiyt\nvTL2XW1cM2soeRXRbdBTTKG5RDKxKFJbo6koVOJ2lgaC6G4R13CNFV8vWSOK3ygS1jaI6hmGmSVD\nhLLhI9CyUxFdTLtGaCPRzToTXEdCw6dXGNPvsKd5E7vQZNXVg7PYQDJ0XP4qJ+pnyetB0u7OsVJ6\niBRdd/+fk5QNL+t0UxE8tLBTb7iwNdtE3Dl65DU0ZAxEqjUPKyv9VEa8VPCSJ8BV4wBhI8cp3qSf\nJQa9Cyzt6+ftNz7JlfnDHB17n2HP7P0eug9IdGAluyBibRUyM2ETrKx6aRMczW5AE6BM8FK27Ws9\nhgmI1qYYq1+JlVIxM1or+G8HbBP0rf7aVoWHCcjmOT6KZjHPa1IlJl1ibcAxgdvc1gq8djZb1K0G\nUuK211YfFBEQdShlQLt3FGuJ9EcT9x2wg2wQJE8vqwTJEyaLlwpZIswaI6y2e+mSUixEe6hKTmo4\nWaOb14c/xfXkAUoXwvgncgQGsvh7igiSQZQMT/I2cwzxHT7B5/g67bCNeXc/h7PXGXHMsM/bRLLF\nuS2P4VcKtCUZFzWGmeNDjpAlQgk/N0I+5o1h3hJP8hn+hoB9gze7HmNV7MWTqqJlJHJdYS74DvB/\n7/kiGSOKVyixy36LIBuoosxrPU8RIcsQ8+xhhWftSzhDdd4UT3GHUbpI4pTqndGQhkl1nLQtxMOt\ns2SfiLD6aBfDjjmCahmn0cY4Cqn+GDeYuEetNFpOIh+U8KZqEAMpBfIwEAPnepu66mImGqXUfZJG\n3MHOoWnmnYNgwE83v0JDUlhSehgU57HTYkNt8nzudVYd3ZwLHWKARRKssotbvMVJbOoaj1c/QEm3\nqCsK3sEyz954nUbbwfyjg4ysLOFsZLi1axcXZD9LjpN3lRuwy5jiE+obXBIP84r0LBuEKKaDFJYj\nnNnzGMOBGTxUOr7fXR6kJ+t4I0XiJAmTxSE3Ue6W14LkcdNxbbzmP8yN6n5OVx7lROns/R66D0go\nGPiYx06Ercb/pgrDmjmaqglre7q07T2zGcU0c7Jy2NaGGsmyvdmIYuq6nWwaKdXZyhFvB3zYWtw0\noa/BJgCbyg/Y+sugQefXgXmdZiOOGSadI929DlP5YfU8sYKw9TqsUkBzwnKyqRHX6ZiHVrADQTrr\nPDb4Ucb9z7D1DHu168yLQ8wLQ0zeXaD2dnOcK/VDlB1unPUG0WyekFAi4ijSHchxWTmMEq4THM2g\n+w1Kgo+6zclT2nd5svYOO4pz9HrWyLrDDNeXsa2oNDN29CEDydfCK5ZxCA3agkxJ9CKh4aZKhCx2\nWjRRyBDFLrXwUeR5XuZo6RIDlWX8zTrLoQGueA/w/rFZVqPdnGk+zOXpIxQFP8FgnuHYHN2OJIPG\nIkJZQJAMBF+nSGcT2nilMlkipIkxxDwXuw+QG4hw4uI5mpLCutTNu8ZjiIqOt1zBdlFHtOsUn3Jx\no38CzS3wDK8yygyxjRye1Tpro11c3bGXFW+CCf0GRgCK+FGbMk3dwbrcTd42Th0HbcXGSG0BZaPN\nn7e/SNibZsQ+Q5wUQ/VFEvUkirOO7uj8P1XxkCNMnmBn5XppjZZD4nT4CXJSCC8FxISArou0RAlD\nWUESNJqCQg4vYjvGZyvfIjSbx7lSZ0xZ4JzjMaY8e6nFXJTqAVSbDU24CwMGZFsRBo1FftnzxyBr\n91arXzQGcBgNQtIGUTIIGBQIcLT/LCF3jjfKTzPtHrvfQ/cBCT+wiyp+KnT4aBOIzAzapAvg7wKm\n1anO5JbNzFdiK8dsVYRYC5nW82x399tOnZgUg3n+jypetiz7mdehsJUyMcPKd1s7Iq2Oe+Z5rK36\nDss+Jkdt9TzZvlKNtXBpemab3iQqfmA3HSuC/68Ddi7H7mSanD/CDcdersp78VNiQwvTbtiIOdPE\n1DRS1sAh1gk5ijhaSxyJXcLwgjSuskqCJF2U8TKuT/Fk6x30sh23rULLKdHV2sCRbqIuSayPRSk4\nO14+OgJlzceS2k+fbRmvWEZCo58l8gSZZ4heVulniaNcINgs4ynXCVVv87brcZLxOO8eOsEyfdwo\n7iW/FqKme5HaAkZQIuZIc6B9hcB0jbQrws29Y+iIlO464i3RT44wBQJk/DGMXoljgx/icVRRmm0W\nxQFcRg2hCYX5ELa4SqtXZrHaR9jIccxzFkOBYKVEMFPl9f1Pcj58mDuMksWPlwobhFi0D6DpHf+Q\nbkNHQmdeGGJvawp3o84b2jMc1C4wos1gr7YJNspohsxsqJ9VWzcl/KyQoIgfhSbjTOGUasw4h7jq\n3EMZLyPMkhroLNPVwxqqS0ayG1QFN5WmA3fBQ19zlZ3zMyg3mhQiAZKeHlL+bhRbE8mtIUfaYDc6\nX1JNp3QnQLeR4amet3mLx1hgkAxRpvUxnNTpYQ0RHcEwuK3vZF/sGgnvCpfmjlAQf2j2qg94+IAx\nVLz3QMYEXatsDzbBzwqWH1VotAK2tUPR6smxfQKwArZ5XJNKsNIu5nmszTVYjmU9jwn8JuFg7tu2\nPDc/o9XzRKeTRZvHsBZZTaC1Lv9lZudWbtx6L8x7ZU4C2rZji/iAnXS69ExfsB9N3H9K5O0SQSc8\ndeQ0KwMDvBb+JA9xnm5HkpbNjkNu4Ag2eX3fSbpZpy+zysjkEo8p7zHhuYKTOh/wMO/xOGd4hILs\nJ+WNsursoyY5sUtNbD6VwN4i7VEb1wIT3GIXRfIU6GW9lqC54eafRn+Hhkvh2zyHjTZtbJTwkWAF\nN1XSxJgNjiJ4oUdfIWFf5BjnuMEENlrs8Vyn+aidVC6BURPQRAnR0FGqDcSXdKrdbpJ743i4Q5sE\n3+CzzDBKgSBF/Pw3mf/As8brKC80mRCmGFleQHNIXArs5WZoJ7MvjPDIpXMc+9qHfLr4JuKYhv6Q\nyMX+vTR9bnyDc6SdUVzUOMlbvM4nyRAjQpbZxGhH9XHhDC9q30RF5k/kL/GG9yQJ9yqfM/6SEekO\ng9UFopcLlOIe5kf7uSgdYpLdzLCDZb0Pn1CiKSjMM4SbKi5qPK6/ywCLSKLGDSZIEaeNDd0Qaesy\nq/RSTqu0Jgf51sFnMPbBQPcyrwx9gozTz1HpDAPKEmkxyh1GSdlieCjjqDdQ/8DB2+6nuP1PdiAZ\nKgEKJFjBKdUQMWjgQKFJRfPwbvVxig4//c4lEqPzPH3ndb59vwfvAxF2IIyEfQsQm2Bp6odhq7IC\ntmbNLTbB1qCT0ZrZtUlBwGb2CZtgafXmsPLZNsvfrBmwlWIw3fbqbPXCNoHTlOi5LH8zwbtNB5it\nckFr9m+GVScuWv5u0h9m96f53KRgamwCvZVyMfc174P5f7D51x9d3HfANqJQHVLwLlYYkhbYF75O\nmA0QoSx6aKKgyhVscosybha1BKnBOHm3H4Ua3axztHEJSRdZc/YiCTo5KURGult4NMoIhs60e5SL\nyhFObzyO4mgS4mV2cJbL4iHekZ/ib2vPYc+3mczvZqBvDpe/ShkvgUYJh9HmrOMYo+o8I415AloB\nb7tOghTj5VmUVhNR0tjVNUUy1k2l5qdidzPHMLsct4ge38CnF5mYuk2hXsVLmRhpjnOOIn5K+OjW\nU3iVMhsxH7TB1mgRbNSIqlm65ABKqMnGsJ8zxv9D3psGSXZeZ3rP3TLz5r5n1pq1di3dXb1g626g\nQewQSYgEhzstiSNp5LFlS1Z4rLDl8Q9P2PPDEyFb49BoZFsaWZTEkbhpGZIgCLIBEDsavaG6q6q7\n9r0yKyv3Pe/iH1kXdbsIW/RgGuiwT0RGVeW997tfZn35fiff855zzpCqrRAN5HGIbTxCDcduE3lG\nY9Czguru1Flx0STGLie5StXpwU0NjU2qYhcLeyPMz07QHnLg7S2RpNb54JYkpFdNvKN1EuEsE6E5\n9pQwc4xjCJ1vBitaitbiBCFHjrGBWYJ7ZWJCjmw0xPDmChGjwFZPgh1PnLruxi1UOS3e4GOVXSZ+\neJ1Y1x6VlJeL8fu4Pj1F/maE+gNeymkf5fkAoSfz7MUj7LS6yPVFOz0bPRIj0jzHK9c5vXON7yRM\nrsvHuLT7AFulFI09J9tb/URO5VHG24iqjhqr3umle5dYJ4woId6maIADgDqcLg4HMjs7GFseY33/\n78NJKfbaHhbva/dGBW73vC07rO+2xhUARdgHSPN2BYs1lh2ALc7ckgbKdIDcUrdYIGqBswXk9ufe\nbz72hCB7+zTR9rt9k7Pmb113oHw/zMx/+HbHATs7GWH2/i56frBLqJTjDG9SNzu1O3aEJCYCXWwR\nokAZHxtKL6vBAQSHSS/rnZ6E7Tq92hYJZ5qiGWBWm2S3HcfrqOBXSjjbLW5KY3xD/DxrxRFOaZeI\nmxmeqr6AW69xzTfFS9XHaGx7MG5KuFs1EqktpLCOs6XRMDxcc52gp7lLsFLG1W7jcTbpMnc5t/U2\nRlOk6PLSE1kn7w2Qc4V5OfcIZdNPwRnC/fEaodUCyUt7XM3KhAt5TgWv4qBFBS/r9OFwNVmVe9nw\nJhBFg0CjzGBmg0CzxHjhJl3CNm/33MdPhs5wDgO9LOGr1PDIVZRim9qimyOTtwgEC6zqKSbFWbxG\nhbOtN9jydCEqBg5jjU3hHl6vPcjO9R6OeG8S7spjiiJ6U0HPKzS2Hbj9DXoLW4R9GcqKh2UG0QUJ\n3ZRQ2w3WNpJ43HVCqTxqqQmmSN3roSedJmwWKXV7yLn9VPAREIqc9lzmP1W/R+NVF66zddanetmR\nEizPDLHzg14cvU2MtyWkb+uk+lfJuuLMNCfxnm+Q9G7T7dripHiVh+pvcHbrIsu+FGvOFO/u3sPV\ntXvRFhWYgVrIS2Xci4CJHvjoPzwfjnVIAgnjNkXG4aQY8dDvFhBZwUELKA972xbHawGbFcCzvGSL\n/rDTEdiuh9thzK6hZv/estCplW6Ndfi4db1dH23RIBZYK9yumbY2q8PJOtb1h5sEm7brrKCiPUvT\nSlm3bzYH8zFsV320dscB+4Xg47zh/QRTj1+nz7FO0CzwvP40bUHhiHSLNAlWGKRICA8Vdm718OrX\nHuGpL3+P1L0r3GKMV93nuWTewzZJ3sqdQ9wRaW8rfHroW0wNX0NCp0SAmuLmc/3/ll5pg5m2QP+V\nbc6632H1xPe46HqA5dIwpWaEW9+cpJ1ycOYfvcK0ZwLdlGkKLr7m+grfVD7DUfEGfrFMX2uDZyrP\nU3G7mQmN8qb6ACIGvcVNfu3P/4Tuxg6BsSK1czLNmhP3ahXn2xrRoTy9n98ABGLsMsgy7wZP8C3z\nWdaFXvyUGHYs8nDiFQam1xlbXMbhahGZKBI8UqSGm3fdR6k4fSSVbfRxiRtJN/fqVxlfXmSwvMED\n7stIFQPfahn3mTpGj8COlkcxCsSSuxz9B1d4Rvo+T1ZfoOUW8S7UUTZ00v9xFCGm4ww2EZwGwyzx\nJf6KGSaJt/c41prh7ZP3IjnaTIo3CPbsopSajCytUulS2fUFqYoeRrQF2obCgmOEgi/AtXsDzI5M\nMOW8TlJI8yCvkZnsIifFSQ0vUnnbz85qL9NvnUYXRaRugU8O/h0tp8yFyqN0u7eIBrM4TjYZUhd5\nWvgB4pjBnHqMjNYFmxBxZEmx2mnKcLN4p5fuXWINYBeR5nv8r6XMsIor2ZUSlpdpgZyHA5CyA65d\nHgcH9Tfg9qxCexp4ff9hb3QgcNAAAG6XyQGYZifD0QJba+OwxrQ3S7CnQr1fdqNou8aaszXvw/I9\ne5Er+OnMTpkOUNuTeSxu/DDFYv0PPuqAI3wIgH1j9zju/CmGA0u0FZmG7mJ9dwDNIRGPpDvJKzRw\nUyVNnO1AEnGqzWooRU1TMeoS284kWUeYpumg0IhTb3lxR8pcMe5B3W2Q872CLP0DfTUAACAASURB\nVLV5ov4jHnvrZfzhImmxSiYSoeZyMirOc61yGq3uAAmkoTakDKqim4wY2+ezfbiUBn65SEtSaCJT\nF52koxFuuka57pmkW98iY8S54ZhkZHQZd7qKu1YnayTRHG2CwRrVuIqelElVNzFnBDJijOunJmgr\nMiFyNHCyS5RVsZ+604VS0/DmazAEhlOijYKPCnVJpSp58FAh642y5u7lxN40nnYNr6MGSv49wrK7\nkMFwg6vd4lj6Bh6pQSYeYbw9g6dYJXariqYp1PtcOIYaFFU/WSGCgxYZYmSaCU7MX0d0mKz0pTC9\nJj6phJ8SDZeTeq1NvFbECAuE5QLDrWXiwi5VyU1cyFCUDUqBALWAi5rmQi61ePDSm5SFIPoJib29\nCA2PG+MxkVJXAARwV2r44iVcnhpHWrfwiyWKUoB3lNPslHrImWG6/Js0ulTCwh5Bd4FH/S8xuXOD\nm9ERCoHAnV66d4mVgVsYlG9LDLEAzZ5wYvciLarEThsotufthZ4sr/U2KoPbddGW2YHPkv7ZvXts\n97MnqNildVZw0AQcwv7z5gE9Y70m+wZlr6Ft3ct63S7bnOzvgTUXC7hNDnhr+zcVi7u2aCRr3gdz\n7vwP7obmjnccsDcX+knsRAi6i6DAmtFPK++mpUpkI1HiZIiSJcIeiwxR6VPp/eIKq0ofl8qnKSyE\nGInME4lkMb0CdaGB4IGeoVXmtse5uT5BY8LBOfFVzpXfJP5SDnFEJywKrA8cpSJ66TK3cRebSA0T\nJdCi974VIj0ZdkhCSwTTpO5QOSbeYJR5WjhQqeOTS2QjQWYZY8UY4DONv+Ed+R4ue09x45kxvEtl\nXLdWKCl+3K4GRjxL9aib5ikHQ7l1jHcEso44V6dOMibe5CRXGWWel/kYFbw0cKGbUme1DIAeERFM\nk7i+S0N00hYVBMxOvQ1BRvOIaLKA5ANBMkEEIQHhchHWQS7CxOYCg84V9JBB2plgXe+m//o2lSmV\n8lEVp9mkjsouMWQ05hlls9nLQ5cuspro52+OPEOEPca4SUcN7UQTXYgOGW+7Qm9lh25hp1NeVpYZ\nNefZblRx5Nz0yNu4pRpSVefolVmMIyLisMZfvvkLNBIq0q90sjRNXcQoiWSbMY6oc3xCeQ5ZaFPQ\ngkw3jnMxfw5EgYd9P6LLt0lS3WIgtcKp1WsMbS6jBUWmB4/d6aV7l1gJuIlE6T2gOxy0gwNNts7t\n/QntbbXshZjsUj57MwHruBX4s8sELZC3gNTqvm5PG7enx2u2ceH2Akvv6Z6Ffa/cvL2lmDUPe70P\nOyDbNx73/rEat3+DsOZg1Qo39s+xxraA3FLK2NUr9uskysDc/v/io7U7DthsGrQkB/OMssgQ63If\nvaklPGKVEDkEDDbpZpYJ0iTIFuMUFmMEB7N4bxYo/ncym4PdFB+O4PtcDl8sTyBc4kHlVa5U72c9\nnyKpbTPQWifiKPLmL95Hxhtl9vlFHr26TMBToHrcSS3+Z3QH1nhl+DyP+X+MlxJvcJYrt+5Daukc\nmbrBojzMBr2MsIBKHQORCWZ5kNc42bxGYmmPh4JvEOnb4yZj3OiaQAgYVP0q7vUG4k2TkF6kK1OB\nVaidcxKNbvNL4te4YD7G68I5RlhAoU0JP9/k8zjcJv3uLajAWP0WEWeGnmyat9X7eCH4JGtGP+PC\nLJ8QnkN1VqkpDjBE3JUWilOHfmANuAG8BG/cex+FcS/n+QlZI8pCeJQrT58k5t1FEyRe4ElGhXlO\ncYU0CY6Yt3jcvECXc5ua4uoEMfHgpUKEPXaJccV7gitDp/lK+ZucLFxDaoLeLeN0NDiq3WBpusHJ\ntV20ARlnvIkZgYXHBvFT4tnMd1GmNC44HuWychqXo0Gt6KXQivFy+glC+TK/7fgX/CR+luncFK+8\n9QTGlIm3v8SyMMjWZh/F7TBXKg/wsvgU4eAeIdK43gud/X/dmgjkOEKLSWCBA8/ZUjZY9MfhQKBd\nSWIPSFpUinW9ncu2gN7OX9tpA7t22p5paOeSreSWmu18K9hnT5E32A9GmgfJOg7buJaHb/WrtL4N\nmHS8aguQy9yuHLHmbm0Ads9csV1nvXfCoXOseytAGHDTpNM6SuOjtjsO2F2pDdyhXWqyGw0JXZA4\n73mFHjYRMHmF82zRQxMne6UYuekApe+AcMKDJBmI4wL1qIc2XvSbAt2pDQajS8TJMBW4Srid42Zx\nkpau0qtuUBlWcQtV/JQI+gp41AoIGgOuJdouiRhp/PvZg0/xAoueI1QdHuLCNrcYpUCQKFkSpImT\nYY1+QuQZEpZxS02aopNwO8/o1hJuVxU52iKabYApcmtsCPONDYRNk0w0jJJoQUDcrwEtIaHjpMnp\n/FWC+TLfKz/DVvN18AGzUJACbIR68TlqGLKAjzKqUKdAkMucZk3qJybtEjcyDG1t4NA19lJBPHoV\nda0Byy385SJtVSBHmC26WXQOUeryo5htNFNmVUgxxBIh8rRRSLbSDLTW2RjuYTXQh45EkAJ7rSjf\nqH2ZIc8CLrHBoLKK91YFYR7Ig+O4hjRq4Ai18DYNQlYkqwAFI8DGeDemKeErVjnDW/icJRKBLTIk\nyBKnZOTw6lW6m1ukyuso4ftpOF00owqmy6BU89HaGaGwHKVS9IHfYDuYxBcpMiCpqEbtTi/du8Q6\nvmV00CAiwK0VMIzbddEW5QAHAGwBleU9Wl6t5fEeVlLYtdT2VG07iNkpBMsLxRpf2J+p+dOlTO0p\n4PYEG0s9YgKCcBAkFPcnZk/usWvHsY1nryFieeT2RB3r3odT+LHNDQ6yP28LZYsQCENINWD97ig2\ndscBe+LsLGp0GrdUpYGLCHs8bv6YMeYoCz5eN89RIoDTbFDciVB60wX/Zpv80STC027kf1pH0ET0\ntEzlRhi/c47e6AYiBid732E4cot/tfBfUhNcjIRn+RR/x2n9EqZ4E3EyyJ4YoL6v8hxnjvO8wp+0\nf5kqXn5d+QN2B2Ns0Msa/eyQpI4bDZkUq6TMVb5jfJZBfRm/XqEU87Hh6mGz2cvDs2/gitYohVQi\nGxXW1F7e+eRJqj/ao5wRmT8/wJHSMvWml7ccDyAIJilWibDH0d1bjN5a4+trX2V3NE4l5EF5o82t\n4BHeOHo/DncLt1zhft6m31jjinCKPxN+kRB5jnKDh/TXSCwWaMktFqdSxINpYjt7mPUWJyrX2GsH\nmXONkanHKGk+9rwR1owUdUPlpHKFuJDGQZMkO0SaRcymzPWJSW65RiibfsaEWW7UTvBn27/CP+79\nfZ5xfpdna89hTItor8iIWzpqvoXRlmgcV9FDTbTTJoyBsSZSLbvZ1eOshPuRnTpfnPtr+lrrDAYW\n+aH+NJtqCdFj0MU2R3PXMNcFdESc8QZd8VU2d/vY24whbYkYaxKiQ0eequOK1FDdFTRZYkvrvtNL\n9+4xAZz3CDhkgea6iWEceLKHJXJ2wLZoEKuUad12np3+sOut7aBsaSMs7/WwOsVe/0PeB+y6+dMZ\nhHaP3AJ667gMiAKI+0hpmCCYt2cwYruPJVO0eHds59nnb3+N1oZmbUiHqwda75e9nooAmDJ4ByGY\nFDo9w+4Cu+OAPVme4/PzS9xMDXPZfZJNsxdHUycvRphVxvlK7RsMm6v8a+XXqC+q0HLBp3vghhNm\neS88HVL2OP3w2/gjhffqJwcp0HY48A/sMaUs8zQ/IMUqDrFFSfTTEh2kSTDHBFGySOhsmd1MXzlF\n0QzguK9JUkwToEiSHRKkkdE4zjQCJtPtKV7Y/TiNJZVYcZfu+9eJqWlS2irNLifb3gSX5CkeHnoV\nUWoRlbKUBjTSx/t4iUfwOmtEzV1OCNd4kUcomT4eMV+i0a2wHQwzdHyOq56j/J7069wXfoc+aYPx\n+VvErmRpDklwL3wt86ukHXF6opukSQAwJVzDHyriMDSOl+ZoeUTEgAl9IPtBbgMumPqTi5xaeB39\ndzxgKGhVB8VeD7vOCH/Hp/FS4Zj7BlPGdc5cf4cp73XKo25mlXGOV6f5N+u/wnPhx/mh5wkm3TdY\n+2Q/2jmZ3uYmHneDzUAv34l9inT/iyw9WKbtUdiLR8hoceo+J4Ms43FUuTB8nobspKT5eT3zMFWH\nm67oOjXc9PnWqQ3KJNVtxpmjgYvyYhizojAwtcTmW/2YuyLHn76E5GnTlFzkhRBhKcfKnV68d4sJ\nUHpIpeRwY/5tDbHdgbE2HdoBOmoQC2ic3K4IOVxoyeKiLWqiwUECi+Vh2ikEy7t1cKDIsMY16dAc\nmLcH7ayKepY6xF721fKOGxxK2tlXlNjnYFXZq3I7UNtbgVlBTntZWDt9YqW+C/v3tIDbUtu0OVDI\n2HtICrJA46hM7ZgDvsvtu9VHZHe+44zooy4LLDRGWDRGKRKgInooiH4u8Bj3C5dpCwqGIDIYXsBx\nXKd5zMFWo48SfoysguTW8UZKdPes45PLKLRZYBgJnbbk4KhvmkluMNmYIXlzl7rPSVaMou33b1xk\nGHW/IP+22UV2N86OmeSSeS+nuYyIgY5EppnAMETGnDcxBYFlIYwoG2yafSxpwxyTHahyBQGTmeQ4\naUeMBXGEaDCLiwYFAtTCKma3QZe5jarV8VAjZazQEh3UGx4i6QJNyUnSvcOTvT8gK8VoagqK2aZn\naYuulQyGDnnFjyjoOKQm/dIqp7jIKgNMNmbpKe2gCm3kgoHzpRbVI06aLgflKQ+lAYGCHGCVFEag\njTtWISTVGRA38Co1rgmTbJOkjtqpqyI1wWngcZcJtnOYO7AR78Vr1jivv8U7nEBHQJcE6ikn1UEP\nDhokr+6hLLYJtQrsShqNpEIdlYbPgYBOhD38lJAkjXn/KFt0kW3FWcsNUMeFacBU4CoeZ5WcEqSB\nEx9lJpkh4+0i5wpzJDZLfCJDPeZG8bTwyyUMyp1ON+JHHwD6sMxEYDp5DIdLwhQvAvptiTJ2jtle\nLc8ywfawZxLaPUy7wsMyy9t8P8WIneNu0gHa96NQ7LK9w8ksVoMDiwaxANvilA8HMA8nCNmB187V\nC7ZzD3Pv9vnZvfj3C26aosRquI/t7runWcYdB+yL3tM0ByZ5ae9xMpU4UWmPdDTGjiPB3/JprrhP\nIZgQMgucv/8V4kKaAgFe2HyG4kIQfdGF42QJZ6KCIrbpYZMmDr7DZynho5dNvsRfMsAKznKLnu+m\nWR5MkdVi6OYWmiCTIU4ZXyfNGS+GIGKaAnXcCIZJDZVZcZJr1ZPE2rukQqtsy10YisCpxFs0DQcb\nhQHG1FtMMEtEzvLjxMOUDD9SW+OKfApJ0NGQaKqz+DwFPmP8NZ56GwETwZlDFEyaJRfCtEJSyRFO\nFBn0LrEh9dBuOrl34128l6uYm6B9WaQ84KYhOTmX+AlJdrjHfIeCESJQquBbbXZcg1XgNfB8oknz\nrIv0AyE2jkqkSXCFUyz+wjAtHIywwCO8yCDLLDGIgcgo85wwr5HQ04iSzs6xGO6tFpHFIgFvGdVR\nh7DJUeU6oCPoJqpYp26qbJtdeF9v0TW9w6888Gf8YUHFSRQD6b36H02z0163JPjxUaJNimVjkHpZ\npVgKoecVvnT03zLsXGSTHlYYoIqHUW6xdbSLPSIMCsvEPv82OcJ8l2dw0SBOhhJ+/HdBxP7DMhO4\noD9GTuvlDFcR9nPv7GoLi9qwgn3w0/VGLO9WpVPNzqqEZ09Csbhwu67bniRjHDrP3B/HHrSz7mWv\n4WGnWuz1SFp0tNqSefsYVsDQnr2o2663VB1W+rpCRy1iL9xkNzsQW++JpXSxUtOt4wdlZ2WuGVOU\n9McxWeJusDsO2Ot7gxiZ+zjte4eMN8622cWOlGRL66bc8lJ3utAKLjZXBtgYWkEN1QhSwBFtwbvA\nH0LrcTfh81W+NPodVoJ9zKqjPM3z7BFGQ6GFgwJBZJeOdlJiYHWdibfTiI/4yPWHqaMioVPDzQ3h\nKF2n13lIe5nP1b5DYiODYcLRI7N0e7cpGgGm5eO82nqIOWOMc67XGQgtgtfgXsfbdLNFgSC3OMLi\n5VGk1+G/+PT/jCtV5QqnAIltoYvL4mmm/NcJUGRPCjEuzHEjcJTfPv3POSFdZdI1Q0DJ46eEz1mG\nnhbamEDTr3ItNAFKpytMBS9GQyFZyBNeruBo6uClU8RtlM6KG4NSKMC60McNwkjoTDDLIEvUUanQ\nqTW9ygC3GEPEQDIMvLUmXrNBUfbynPxx9IjMkGuZed8IEXMP92iVVW8fpgBzyjgNwYVabDCyuMrS\nPYMs35/iPvcVbr16hBLneZSX8FDF0W6RKOTYdiXY8SUoEUClzoiwwJpjhGI+hH5TYr23Hy0ssk0X\n6/TRRiFClpndKXRdxploMybOcQ+XGGeWIEV8lKmjMssEf3OnF+/dYqbAxt8NEpJ1TrXFn+KELUC0\nVBgNDjxKK4MPbveQrXRsyTaGpau2gN+eFQk/Dbr23D97VuFh/ttSeRz2ZC1wtNMkFqBar8/aGCyz\nvO3DKhj7xmTN267f/r+jUA4n2tiTbRotid3LCdKZQfj/C2Cr7QYT4iynXW+xKffwrjHFptRNUQ/S\nJ2ygI1MWvLREhYwQRy60UVeaNCMKrqEazYsqznYDSW6TE8LcXBtnqT3E2ZHXqIkeFpt9XNbuI+bM\nkHKu0DORJkIO6Z02FcFLDQ8m7Ne/9rNDErEBDq1FMrCDT6jQFmSC5DnueJfVVooXs4/zeuscFcnL\nY44Xccl1dEGgLPpYModYNVNsC0kcYosBcZ3R3CJepUTLVNkolxFrLrLuKDcdI7hoUsJPT2sbAYFb\nySO06g4MXaRIABcNZEmjGlAR+hoIoom8akBbR++WWaqO0G6rnOJdettbeIRax5WoQCESYL27hz7/\nJqYMIOAstYloOXo920yLk6yLfexKMXr1TZzGHhXZR6KdJlXZwL9dpeQNMNt1pFMBUI0w5xqjIngZ\nYJmEc4ctuhEw2BGSRIw9wvkCsek8O8EkpV4vlW43dZdKCT9F/AQbRTz1BqJhUhdcVPASJtdJJ5ck\nEtEt3JUqcTPDQHsFqaaRc4dJk6CQD7G0MkJejdKnrHN0aZax8AJH3POMa/M4im2UZgvBbdL2ffSF\neD40M6H0dpWWWKFbM1nhAFTsqeAWENmDe3Yu1+pKY2mzsY1jBersQbrDqekWqFmAbddyi7axsI1v\nnWuXFdqTc6zf7ZpruB3Q7UBqzcGuDLHXP7E/7Ofa36vDZVmtc+yvzw14dJP2fJPSVu2u4K/hZwRs\nQRCCwB8BR+lM/ZeBeeCvgBSwAnzBNM3C4Wsn1ev8064/oo6beUZRxTqb9OKQWzwmX+gkkYRVAqFd\n8kKA7WvdbP3FANEvbhH8ZJZMupfoYzs0zor8rvAbrF0YRrplMvDry1yXT/CT7GNQFuiLL3Oy7yLh\noT1ig1mWCzkG++JoSLhocIOjFAnQMJ2svDpG2QjR9x+t0je+hkKbNAl62SBULfG/zH6ZrBCjP7xC\nK+SgpPlYbab4XuCTlAUf23qSuJzh46ee4yuTf8nItTV8lytM6Tf5etqkJ2ew7U7wLifYI4KEzucr\nf8sx/QLhSJaJzAK+apW3xk6x54igCxJOuYkYyxGr5LnvW1dJnwxz+ZkTvLN1lhl3FX9Pnmfl7zHY\nXuu8sbuw5u7lGyc/wxfSf013a5sk29y3VaarvIuZgm+6vsAfO76KU2xwf/MKk9o8L3iqnKjc4Jn1\n5xHeNXll+CzPp57qcPhmggvG48TEDJKgs80yGeI4adLARaKdoTe3iTgDU/Mz1FIutv/7CGE5y3Gu\nkyZJV3EPTznDWl+SdWc3Jfzcw2XW6CctJxhNzRLuz3FCv8bHVy9Qznow+k0qeMisdLH1pwN4vlzg\naGya37rwB3hPVqDfRKjQ0ZpngD4IjH/wrLMPsq4/XDNh+RJhbnIGnevcztnCQfDOLl2zQNPydmUO\nuo4b+3/b08rtmmSrvoiVum6ZZjvHuudhLxgOuHJ7HRB79qO9cYHlIZvcvpkYtuvaHMjz7FmT1sZh\nBTEPy/OsDcrK6rS9o7ddawdxg05tvkFdw729CFx6n1f40djP6mH/S+D7pml+ThAEmU5Q+p8CL5im\n+S8EQfivgf9m/3Gbxd07GIhU8ZAnxB4RACZqN3mqcIGnxJeYVo/yE/855naOkcvGMVwi5ZYfQTEw\n4wJ7Swkqog9hVKNaCSA14YeVp9jzRRHUNg5fk6B3r1OelfX3CutL6Lip49brXFqeoiE56RlY49iD\ns/SZ6yTEHdbox0AkxSpJdsAjMDh+ixPCO5xyXOEh5VXWGymcTZ3jxnVW6CfXDvEJ6TkmxFk25R56\n4xkywRiX3SfIrb2Ex11hiCUkdNboZ50+yHYK9v8o9CT1uId7Slc4vjKLFhEoRnxc5xhvuAJ4YzWe\nnHiRoKvCxOYCXwx9nYrXjZ8SiqR1eOtZIAS+SJkjws3OMbOFhxrORpN0K86r7gdoOSXGmWOhMcz3\nxafZUHtoiE6cuQbCpgl+0P0SBiIxdhkQVnhG/C5XhRMUCPEDfg4Bg7Gtee6/fJXAZB6zC/RPQ+Ff\nmTTnWsRmckQqKiHyXOEk0cAeIXcWQxYwESgR4CUeoc9Y58nmj/i91X/CjPs4K30DzCfGGBNucg+X\naeKiLahsyQM09jwshkf55seeZSQyT9iTQ3PL4DTJN8K87b6fa97jwKsfdP3/e6/rD9/amPeYaL/u\nQ/vdAq2ZDqzZs/YsQDzcRssCMMtjbXCQpSjZrrPOOeyZWsksFgVipywsAP1ZatlZXqydKrGeb3I7\nbWFtPthei53+seZrf10WzWMds+ZpfcuwOHXrPEtlY1FI1sZRBcxHBQJfkZD+RwNWP/qEGcv+XsAW\nBCEAnDdN86sApmlqQFEQhE8BH9s/7U+Bl3ifhd10OLhmnmRL72JXjIMIUbJEzT1Uo06QAp5mDaOk\nMNBcJegtsX20m8K2jzpuzFSnG4peEYnq23T3pPEoNXC0aSoOGqITzXQgi21cNFCp4dYaBFoSIV3D\nkEQGWeFN/SH2tBj+Sol4cK/j0QoGDlqIGO8FsbxymacDzxOXd5gQZpmszxFt51HlBj3CJlVUXGID\nj1CljsqSOMhAeJ01qZ/nPU/g9a2z4Nb2AyoOPI0a4/lbeFtlmooDEYOqV6UsukmU98iYUdboY41+\nckoYX7BC8agXzRApmT6O+GYpqT4E02TBMYguy/Rr61SCbkohLxoydacTp+lCQ2bbk6RmeKgXVUZC\nC/hdRXq1dUxJJGuEGd+4SbK8Q8sroXllvMFyp5+mXKWvtUGylqbgC3FZiZAhTpIdQsU8/dc30WUT\ncwjMCTCmoLHuoEKCmqlRwUuOMFlXmF1XmD2iFAnSRsFpNGmbMmXTR04Ps9IcZKeaYLE8yp4jTNKz\nRVNzInp1Iscy1HweSi4fsz2j7IhRZF2npnkgBHtCmNe0hygoH6yWyAdd1x++GWSicX78sU+w98c/\npE36PdCzgPdwYSTLm7XAC9tz1jl2ELQ/sJ1v/bQnqVjesQXuh0ubHqZq7LSEXS1iV3rYxz9c59s+\nlp1Gsa63c9DYzrXMAnQr49Lirq3fLeWMuf/3ek+KyqOnqfyv9UMjfbT2s3jYg8CuIAh/Apyg8/3g\nt4CEaZpW+4U07IuED9ksE2TMJ1ltphiQVjjnep0hlmi5Rb6ufo6rnOJmYZLN9QH+We/vkOzZ4m9O\nPcvF/+Ec6zt++M8Ar0FIzfJw7GXue+oiA8YKLcXBq8JDvNR4lMWVCSqBAGWPjyJB+mqzjJfzDLV9\nxKQMEWmPN0bOslbq462N81wsn+O47xpfGv8a9wkXiZJll04Cjdpu8lv530f0tTEkE/9mA4+3ghot\no0gtvGIVl9zkJeERQuRJijv0+DdZYpBLwj0oygyCs58k22zSw3BuhV9750/RjhsU+318UfrLzjcO\n1c38iI9r4kkWGMZHmRi7JFxpGkcl5jjOFeEUcWEXCY2aoPId96c4MXqDf5j8c9b9XbzrnOR1zhIL\n7tLFNhnBycvDJ4lkCnzq2nPUj8hUB50orjZLwhCl3QBnX76MOlyhdM5FRfDS31hjsnyTnN+LM9/G\nuWqgjOv4gp35mPCeWyS/Q6do2eMQ/TJUpCjPxZ/i+vIqBsdo4qSOyjZdvMsJSvgJmEU+qX+PN4Qz\n/J76m+TG/UhljdxWgvxMAikiIJw3eLNxhkrcy9iXp9kw+/AIRfxikTc4y7XGaXLbCXQRTFFAqznp\nj33gINAHWtcfhU3nT/BfvfMMp0qf5hRpWhx4n1aqtuW9WvpnFx1v2qq3IdCJWR9WhFherp1fPpww\nY/d67Q1+LbPL9yw1ijUne5EqO5VzuMa3Bd52rbidq7arQqy52akOuxqmzgHFYqdRLK7fonwsesf6\n9mEAL+89yg+nf5da/b/lbjLBNP+f2XRBEO4F3gDOmaZ5URCE36OTvv+fm6YZsp2XM00zfOhaU546\ngdDVg9aWiRyNMnnGxEGTciXAVq6HMj6aigvNKTG4soLqqFGc9FJYDtNsulD6W9QbbiLmHo+Ef8xo\nZRFfq8JWKMnb1QeYqx7F6y7Ro67T7dzERCSgFcm8usjgwwkaoosa7o4Hq0WoNz1kajHicobHgj/m\nSHuBgFmk6PBSFbzohoS3XWWuNsGm1kO3c4uG04GuiIwJN6EssleJshAZRHCaRNgjQhYQKZteshcW\nGb4/wYavixwRPM0qR0sz5Lwh6qoLN51vFSo12sjIdRA0A90tokkdJi/KXidVnzBZomy2e9hs99By\nOEgKaY4ZMwxpy+TEIK84H2SIZeJkWH5th/CDR5BaBpPlWVpuhZqq0sSBT6uhNhvUiy5cnjoetYKy\na6AUNQQNtgfjOBtNAttVLgw8zJq/Fw0ZAZPRzBJPXr/AtdhxqlE3g+FlcoTZFLpZVlIsv5whcu8R\njrnfJSWuImJwgcfJEcJHhUeMF1mnj1fEh6maKqYm4WhpdFc3QTbJBULI7UDujQAAIABJREFUZidt\n3y1XWVscoFFUifl2KXqC6KpITNmlPL9BaXqTxp4bxd+gdeEHmKZpj3X97Av/A65r6KbTvgsgtv+4\nw+bzQl839659nY831kjvf1O3uGK43cO1AMpeo8Me7IOfTlO3zC4FtDzhK8Bp27HD6fCWp2tXnVgg\nbleD2PlnO6Vh0SIGt39ruAwc37+XPdvS+mm/j/24vXekNVeFAx7friCxxhaBuACzkZN8N/lzsPgq\n1OPcedvdf1g2975r+2fxsDeADdM0L+7//S3gd4AdQRCSpmnuCILQRScc9FMm/dJvIH3yi8QqnY7p\nppSjoiuky92s50dABsnXwhGus6ioRAMZTnz+Mjtigprpxik2yKfjhOt5hoMVTuWdhNp5ZlJHmN75\nDK29c/SMXeJxz484YW7yE+Eh/O0Sqt6g58tnaYsKDqNFXExCVSC0W+CqO0TAI/Apr8p4TUU1BNY8\nSTRBpoFKlijzO09Rq04g9M3ymPQG9xnvEJfzuLeblDM1vj7yAG2vzABtWkQQMHEaLZYLyzzyrMT1\nRJifNB+miZOgs4ca3Rh48JPngcpbpLRVMv4I46tLpLbWKSlu0r1RSt1+QrhwtlqUW3X+Sj1Drn0a\nZ6WfopYgrxbI+ad5qvJtyqaXN9TPEZCmOSJO4+cler4ywJ4ZwWsMkhDTIMA0xznRvM5Ya560FMOh\nNAi280TnSmg7Cnk9yMbZBP5WhcRKluzEJEpojCZOwuQ4vVvnEzMBshMPko2HuI8fscIAEqPoDLJW\n28b16cd4MrJFSqqwS4wLfIG8PoJmlPHKHgJCN6rxBI1iiKBcZMR3i4fZZD2X4i9Wf5EhdYlEcAdP\nsszu354juzZAJWVC0iTizJDKX6T++MeoKAGMVxT0SZg9/YP/d5+J/4DrGs5wACMfkpVlmFEZ6A/z\nyd4Ws5d2MZo6Dg6a81pgZXmnJgceeHP/HI9tSAtk4QAM7DU47FJAgJ+3/W2BsL2Li+Xx2pUhlt7a\n2jjslIe1eVgd2e08uSVLbANPcruXbG83Zve27cWerAxOa67We9HaP1azPW/RMYpTYvJEHLXay3ev\nR4EknZj0h23/7H2f/XsBe3/hrguCcMQ0zVvAE3Ti9TeArwL/0/7P95XFhuNp1OFVzpmvs/n9AV7/\n8/OYNQEj1Um9xg96VqHxoox5Xmf46C3+E/Ffc0F4jBlhkjYKnmidciXAH27+JgPhBQb6FvBKFbK+\nME1RZlEZ5knzh5w2L1MkQE85zUp+BndzEK+jxP2ti3zD+QU8a3W+9P1vs/xMD/W4kwBFSqqbGY7w\njnAPPWwio3OFU4zE5ngo+hI5Kcxk/SYTzQUqPgf5RICtaBJNkXDQxEGLLbqZ5jjviseJBX6fgWiD\nj/McL+Q/yQLDHEtMkxJWaeFgk15C60X6yttsTyXQNmXkCzqhK1Xan3XAL4CbGv5CDSUrspZKkXBn\n+CTf4w8v/SZZd4TsqSjf8DxLrh3hWuUE3Z4tWg4HbTrlWNeNPv609VV+XfkDTsjXuM4xso4oVVPl\n0d1XyXlDLAWHKBzLsz7RxyLD9DtXqZsqa5Ee1pVOMS4/JU5ylb7IKrNnhuiR1+hhHRdNpphmgFVm\nmWBbNeiOdGFK8A73MsMkNdzoTZF0I8Hz/qdpywrNtpPaYoAeb5qj4zfoY53czRiV/zPETPgEu/ck\nGfnsDM2wo5P6dkRHcGsUL7t57XfuxfwFN/2/sM0/fOb/YFXtZ/bf86PwH2JdfzSmARWWz/fx8udG\n8f7j7yNnDlqlWWDt4iC4Z+eWLVCqc9BV3A6CdhrkcGajPajnokN3NDgI5tm9W7tMr7l/jj1oaHm9\n9jlZhaosALfzzHbv3+7x23ly89B4cJD12eCnvW67jvu2AGhI5c3fOc+1pSH4JxXbaHeH/awqkd8A\n/kIQBAewSEf+JAHfEAThV9mXP73fheW9EK2NCEtdwzSPuQg9u0v++RjaggybwAlIHNlh7IkZZuVJ\n2hUXBYLUUSk3/Ozs9dAXWCXiyLLsGiLmTDMlX0MAqh4vTaeTliyzwgAXuZ8jrQXCSp4Zn4uUkiaq\n5Yg2ikzJ0xhxgcp5J0ZMQBFauKnxE+FhLnOK4n5yh58yRQIMSCvEyRAij0cpsycG2BC7cYhNEnqG\nJxZfou2WaXVL3OAoXio8ykvkxC28kkKBIJKvRd108hYP8FnjW0yVr1Pd8jNWX8TlbeIXSzhdTQQP\nCG2DVttBreEhvpxDzTYR9DJPdb1AxhOhoahEUhmqspOMEWdKfJd75Us8or5IUCrQxMkl7uF64Vma\nbScPBl5jRFhANeu4hAZDGyuczNwg6ClRdbtpCk4uOB4lXt/jTOMdNpUEV+UpNujjgY1LIJssdacY\nMFdoCC6+7fwsAiYpVhhgBQkdGQ2VOpPGEk+0sxgiuIROMwoPVXaUJBXBi08ss0OStiBjeCXSzgRv\n1s8wlz6GIUmc/cwrKK421ZCHhcwEZSPQ+ZRdFyEnoy+LaH0OKMtkb8R46cwj5DYjH3Ttf6B1/dGZ\nyerVLt6qD/DzlR9hUu3U8uD2BBTL07U+4FYnFTjwQuGA87ZL3OxKDfs5dqmcvZiSfTy7d31Yymel\nsYuHjts3CYvzttMZFp9t558Pc9d2jbX1sCgWu8yxaXstFk1kgbYTaJcdvPXnp7hWSMJdWK3mZwJs\n0zSvAfe9z6En/r5rpbqBUBEQdYPIyC7ueJXZsoP2j2XMOQnvRIlYLEPixDZLc6Pk0jHelh/AjAsE\nKHG9eooxzxxh5y7+wCh9rlWOcR0JHdFpgNMkTYISfmaaE9x76wpuX4WaR8WvlAjWizgKOhPNW1Qd\nLmoTLnJqCEXX6G9tsupIcU06iWAadAvbKGg4aeKrVYi191C8TUxFYElJMc8ozlaLrvIOg4V1miis\n0Y2bGiMsMMo8r5BGpJtFhgl4csTYYZcYbqNOb2uTQqGJGYBGyEG8nkXwGRQH/XhvVREdIJUMxBwI\neQFVqHNGf4MFhpmRJkn0btEyJTRT5phxnePiNKZLwDRg3jjCHlEqzTFiWpbHpAsMs4iuS/RIm/RU\ntwkVCxgBgbriZM+I8krjY9zfuMS51lsURS8Vl48laYhnK98j6MjTMBW6K9ssCUNc9p4m1e6IFCVF\nQ9E0BFOgKnvpau3waGGOOc8IFZeKqtTQUAgqBapKp0GwjsSSNIQ7UqElKsxrRyimo/Sq65x7+mWM\nvMRmrZ9SM0i75IBcx0+L7mRRtDbpB5PomkRlycvVkyfRyh88ceaDrOuP0rI3VObXY0gTUYytBu3t\n+nsBPcuDPVz3w04hWLytPfiG7XkrCGcBeJ3bu9HoHNAN1vn2DEi4XYli/W3d097dBQ4A2X7eYVC2\nANk6bj1nJ3ntnvj7JdjAgb7cztG/p07pdmN2xbj1QoyVkpe70e54puNU12WkI0P8qvLHCJhc8Z4k\n94Uw1X6V9gWVsc/ewEyIPD/389Q1N8KOyV/98Jf47c/+c04dv8Js/zjd8jq90gbrwT5kUaOFk9Nc\nwrGvulyjH4U2vnwZxx/pqBMtXIGODliry4hbBonCHoYoYEQFZkaOglMgmK6RjO3i8VaZN0dZYQC3\nUGOIJY6vzjCZu0X9lMSse5x3mWKJQabzp8hku/nK4Nfw+QoUCXCay/gpUsVLHZVlBikQZIQFUqyS\nJYokarwSPsd3Tn6WM+JbnK+/xvjqAmuhHjbu7eZU6QYJ9y6BdIn8uA9zG/wbVUTBpIttvFTYIUlI\nyDPACvfpF6ng5dvyZ/m89i0eNF/nChHqkSPodEDa16qAAfdIl8gORXm+71EeUN5iQR7kcvseZtan\nKHrCSJEm/2D93+F0a1R7PNwYPkK3sMWYeZPISom6uMsDR9/i06XvM2ouUIy4iJQKaLrKfGQEtfY6\n3o0tjitz/Kj7EV6PncFAJE+INgrDLFLCT1AqkAhnEDHQdJmmw0tV9rBqpFi9OEoLhdSjt9j87iCF\ndAR+3uTh6AUiepavr32VyjUfrmaDlLKKNiaRv9OL9661bdpHfez9y1M4/jcT/Y8X3pPWWbI0y8u0\nPuBWFTqJDhgfriFiAZd1rV3JoduOWVRC3TamxUVb4Gp55G46wG6vBmgvbWp1SLSSa+B2j9qiW1oc\nKEOsTcEu/7PuaWmwLeB27z9f4YA2safN28G7BjQ+0UPtH52m/Vur8Kb6/m/9R2x3vmt6K0bSabBJ\nDwYiOTGCO1zFN1Ym13LT7pNx+FsEhT0Es03L76DlF3m59hiO+QaVpIdruVNsGX2YKZGYtEsPm7ip\n08BFCT8+OhX0it4gzz3xJO54hbWlRe5HpOVRmOsbQoloVAQf254kPkcJXZT4fuApFh2DKEKbCWbR\nkFmnjwFWKEZ85I0godkc2a4E73ZP0cTJseoNenYv0NWzzp4jRI5OWrWIgYsGDVRWGGCeUYZZRMs6\neHf2JOXRAHpY5O3aORxujbZL4QfhnwO/SUTJ4j9Txi+WEVwm6m6duuRi50iCVXcvXsoEjBKbuynW\n5D5qETcPiq/RU9vmyeJL1P0qeSPM0M4ax9PfJusNk/VFyUpR2qJCBS9xs5NYZMrQ29zikdorlAJB\neiubnFyY5qr/BBWfyoQ+x+jCIgl5h0CqgLdRwSU3O5JD0iR307jf9bLTn2QrmeC4MM2cKjLTNUpc\nzHBTHuWNxln6HWt0i1v4KTHPKDoij/AiLanjGeuChLO7TV4KkTHj5HdCtPNOTD80FtROa5UdgeIv\nBnDeVyPu3sTlD+DTS4x45tmUe+700r2LTSOzpfLv/uw8T0xnOcbCe/1QrMCalTxjmeVFv1cnY/85\nqx+i3Xu2goT2WiV2L9wuybPGtgDRqj1i7zFplwlaG4pFz9g11PYA6PupVyzu2jpm32zsG5XlMdvL\nwlqv67CM0Po2kgKuv5vihT9/kN2tIrxHNN1ddscBu9b0EDd3uS4cey+5whBE1FgN58k6BEyc7hpJ\n9zraYi+S24X3qQqvvnKe1qIDbyhHNpegqgVwdZdoVFXKbT8boV4W5RG2jB6Ota9TEz1s+5JkPhXD\nS4W9xSKudgbDJXArNYSGwg5J5hnlce3HNHUn31C/QEny46BFt7DVSV3HRRUP6XiMHTlG9M08DdVD\noTtIkh0e5iec5W1uMkwThaBZoNFQ0eoO/K0sUsuJjkQLB3lClKpBFpbHEJIGaqCGXDWoOTzMe0e4\nlLiHhJjmmHSdrvFN4sYu3moNY0cmFwmyMZSkqAeRDB2fUWG3EmdL6cUbKdJsueiq7TBQ3ORF70Pk\n9RChyjSPbb3MjjfBy4mzbLm7KTu8iILBUW2O460ZNl1xglqJce0mt8JDDNVWObK3yP/e+8uIAY2H\nmq9xYu06fmeJYq8bU4W2LKMhUVdUmi0n8oLJTNc4m94kx3mXOSfshOK4xTIZLcZGu5f/i733jpLr\nvq88Py9VzrGrcw5o5EQQICkwSJRIiZIs2ZJpWR5JlsczHs94vD6za8/Zmd2zu7M+9uyxx3LQjCV7\nbCtYsqItUiQhRoAgcmw0Oofqrk7V1ZXjq/fe/tF4wgNkWeORYZOyv+fUQaPx6lXVw+/c9637u/d+\nI8omYTZp0dd5qfYoIWmLQ8o5Mo0oktjEqVTIuCKUSi7Wplto1BVUVSGzGEerStsKpyuwsLOHYpcb\np1BG6xZxCFVsa00aNscPXHs/yrW16OSlT/Uy0DrEnoE5pOQKWn275zU370yQNcHYKoezKjyshhTz\nmLsD/a15HVYX4d00hDUG1eS1zZuHVTFytyHHapyxAr1J81h/d3d2ipV7t1I0huUcVsmhWdKt99Kw\n2xA7W0kuD/LKuR5gkjtnuL956p4D9n3eN/j55jN8Wv55poUBCvho6jKyu0mnY4Ydyjg6ApPaENVP\nObAJKj3/eZ563YOhiRzwnmX3jmuoTYUvax/k86c/yon1Jxh93xU2glFkVeP4ymmueHZxNbqb9/CX\ntLLKSSNFVy5LQfZQCbq5xH5WaKWGg69L7yNdinN66Ti72i8TC66yQDc7GSPOOuvEUZHRXQLGCLT7\nlnmQkxzkPLQJnI3uJ+VqpYU1HmiewjdXwzlVQ1rWaNUaHOAE7+GvuMZukokuAk9mOeZ5nZiyznxL\nD16piCDodMpJioIXieZ2lkljjZBe4C+Hn6RpF+nQlzhaPo8gaSRdrXS1zzIojPMu/Vl2LE0hYVDs\ncdBpW6BpyMx22KmpTaI3Mzy+/DL1HoXV1jivO4+gOaHiUGiICmOuXZxzHOZ18Sh9rXNsRoPoLvBS\npinKGK0Ca7Y45517GO6bIikkuMFOutxJKoN2Cm0+XvU8wArbWSH2/Fc5PH0Zu7POQHiW3YFrdIhJ\nQCDVaGd5todx7y5uJEYpJkO0O5cYbhljfGwPy6c7Uc/JiB9q4HhHAbuvTtkI0Ig6wYCl1W5W/6AN\n3S6hDYuIdp2N59qp7ftHFP7019Z2uMoLHznK6sFh7v93v0FkIYWDOwHY5IkF7gRTk8KwHmtSKLLl\nOLgT6EzFh53bFAncvgGY8kITfEVuDw8wvwFYJ5PDbWC1uhWtjkoTmGuW96fc+nvV8jlMA5D5WeD2\nRqP5OVTLuc2b0WYiynP/6Ze4fi4Iv3mD22TNm6/uOWArcoOa6KCfGXREVmglLURxSRXa5BRuStio\ns0eokusL46XIO4XniPVkqDZd7LZfYkS6iaKryKrKidjjzNt68SmbdLPAsDSJw1uh2z7P2znBKOPU\ncJAlyEVHNy6pTJx1vBTp0RYYbMxy1naQot2LL5SlYPcQL8F7l54hFN+kEZLJ46OJTEnxkIt5KCou\nDFWkNZNGMVSchkpkKke4uEmnuorNpaFGZMo+B97pAm2kaN66tEHbFkfCbyChoTSbPFw9Sd7hISMF\nQRDwNioE1TweirTNruFLlRjtvUmxxYVo07ihDBOpZ0ik0/QE5rHbqrSpKdxjFeqKg5WBGJtEcFQb\n2IoryFMaymSTkJTDEEAJN9iy+7FJdWbp5Sz3YUgCXdICaSNCwJ5Fdwg4qSKiU5Lc1FtkspKPaXGA\nitNNES9eihQlL0vONgpOHxLbQwrs1Nl0uEiFEySUVSRHE4dUxUDAT56ItMnR0Eku5A6xMNaN21+m\n4PYwL3YTj60gjjaZt/VidIp0BpZ4R+A5Tux6J5P+HeglhV3CNfxSlsvyXrTEdkiW91gJW1f9h5L1\nvfVLA8qsXqsSllT6HzCQXLAxfudGItzmjq2KDHMKizld3ApicGfHbeZvWPltq/rDCpB3G3BMoDbf\nsTW8ybqhaKVErJ22VX5nnt88j9XwYn6DsHbg1k1R8/WtFnkNSOyC8H74xuUmq9drbCeJvHnrngN2\nWXQzISVoJYWIhqjr1MpO7M0GXqlMzeXEJVcYESe49PYj+CmyUxyj3menYPjoEJdwUSFmbHBQvYjY\nbvBs6xModpU+ZjkknUP1i7SJS3QxBwiMsZNl7Fxu9jCi3WSPfIUWeY2AVuSpxrNUqw5KihtvW551\nWvCkK3ww+XXyiodpTw8rSoKq4GJR6qTpFJkS+knXYggZkdZamkRzk/q0DXFFx1ZpwjFQRySKbQ5c\nyRLBbJ4VLUHZ60a0awwyyRX2UmwG2F2epCw5adjtiOgMNGcYqU0BAmJKRxjXecBxmk0hyFy9i1OO\nB2irrREvbBJ1p2naxG1jzEaDus3GhNFHQfCRqG3gyDew1XSaGxJVw4k9X8dbrbBDvUnaE2HKNcg5\nDnOAizzAKbxCkTrb70OmiYZERXDR8MroqoCek5hz9yLLGru0MdxSmYagoCGSYAVFU+muJknZbUy2\nJ7BRpo6CjkgVF3bqdCpJDrSdY3WzlenxEeKPzeAIVSjg43DfOQpdPooPOSkWg7Q3V3mSZ1jo7WYt\nEIeUjSPdp0jEl1gnSA0HTr1GcCiHS638Iwfs7ao9t0ptPIv/Yy1oWzWa41t38MxWp6MJaNaQKCut\nYc0bsfLKJgdsZkxb7d/wveB6Nw+tW44zfzbflwm05s3Equgwf291bsKdHDuW31nPLfK9Tse7b0x2\nAXy9IRr9caqfWaa6GOTNXvccsOvYSRMhRRtJukjWOsmcbEHfkpn1DxM/vEw0vs4qCXJhD1nBy2f5\nOAv1bmw00O0iy0I7vfl5Rq7N8c+Lf8xR73m+6X+CMWUnhaafT6b/O6pTZDw4ygqtLNNOrTHDg3/5\nBqPKBPL9KoV4gKrTRV5w8fiJE/Qxx6uPH0WUDFoCayweTpDIbzCwusBKWyvX5V28oh9nsxZGknX6\nlRlqcQV9FdSSwvTRbrwbZbonl6ECSlbFFyvhWmzQ+kyacK7AqccfYmJggL/kKVxUkWwaX4h8EFWS\n0RAQgKAjh81Ww0DAcaSKc3cV0aNjO19n15cn6dq7yunBI/xGx7+lyzZPE4mryl6iT2VoijIrQgtH\nOU3EtcFa1EA/BtmHA1z07WbIPUtXdonIqwVqB12EDm/xCC8RvWWBjbNOilaW6WCdOF6KSLqObV1n\neHGOSOrLnH7oEFJU44H8Wap+hZJjO+N6mgHknM79Vy4wnRUJIFHDgYGw/f+GyA1GmWCYcxxm0jaK\n5NGISmnirGCnTjvLNCQF0aEzJ/fSEES+zvuwO+o8FH0Fj7+C01EiR4BOkuQIkC+FGL+5B235ni/d\nt0gZzK938st//Jt8oPQFHuGzzLBNFZidsQlk9lsPkzYx6QYrIFqdklbO2gRkc1PRzZ1AaJ3NWLYc\nZ+3Yzdcwu3WTLoHbxhlrup71vf91ZR3CYJXomcBsUjsmLWRKCVXAJ8IBBb515n386ZUPMb82xnYy\nwZu77vmqXyfOdG2Q6Ylh1uU4eU+A+oYbbVmmqPtoqDLiqEF0KE3Uu0HGCHG1uZdeYRb3RpULV4+w\nf+cFlEiDlUgLM5VBJitDRPU0veV5vOkKz0y9h3q7TCHgZFIb2h4BJs6Q7/RRyTtpmS+yx3mNLbuf\n6/IorS0bBIwsPcICZVwIis5KMMECveTUIEmhlRAZHNQ4LR1loDjLw4VX8RcKCBvQrMqsjcbZ8jVQ\nRJXw2RzKagNXpoFc09BCdrJBP153nt7SPMPr0wQ8OSSHRgEfFaediuSkhIeb4jBj4ui2RDFo4ApW\nGWaCvsQ88YFNjLhB0e9i1RkjTBodkaLgJZ5Yx0kdJ1WipMkR4ATvoLetSDvLRNQtXJeriNcNbKtN\ngpECRmKJSDSDI1XHtVwjGC2Si4fYCEdxUaGNFG3CMpfce/FEK8SEDXSngF1qItg1QlMlNDHCtZE+\nvFKRdnmFiG8Tp+ylgY0zHGGGPkp4yCOzrLdTqPuZy/SjCnZaB5OMuq5/13izSYSa4KBFWCNti7Be\nTXBq/WESoWUcRo1Uup1VoRWns0I4uolXKhGQC3iDZRZTvfd66b5FyqBcNxhLNgn23oc2rBMaexal\nsH5H52vtME3wtEamWkOXrJuV388YY+W1rZGncCctYrW5m92zFXSsmmrzuVbttPmerZkfZodtjjiz\nboxajTNOy2cxs0rMLPCMJ85f7n6SE6tHGJu1blO+ueueA3aq2E5teRdLF3opO70Y3QI2pY6ETmPF\nRrYYJaanCQ5l6XPO4NJaWax3cch2AWe2wR8983M84DmJvyvP2ZH9/Hnlp5laH+bp6p9wSL2IfU3j\nF+c+RdMJPUyz0OwmLq5jt6mMPTwMMwb3Xb7EgepF5rRuXpKOs7E/hYcSITJkCJPTg3i0Cmf89zEr\n9hEky7v5Fj3iPBW7k7etv85TyW/T2LJRr9hp2iTSepRGTEZTRPq+nSS4mseWb4CiU97rJBltxSsV\naE2v8tDsGZwtVcSATkOwkZYCrNpipGjj2cYTXNAOEbRvoYoKTqo8ybdw7KjiGKkwLXSTEYK4qJI1\ngiiohIUMnSRxUMNBjShpJps7+IvqcVrlFZ4WvsCe1A2UV5uoVxXyu3y48lW6ZlMUPE6UGQ37WY3a\nqAOH3EALS3SQZJAp4uIafxH7cZohhQPdl6janSDrTAe6GHp5nmrdw8WhA7zL+DaD9mkawxLNmxJZ\ngrzCcTaIUsFFCS+baoRMPkp9ykM4tkHrzkWGuUk3i9RwMMkQVZz0MI+XEsm8k6kbO9FHReSmyo3X\n96LZZdoSSzzqfI6Ye4M2VwpjcAJKsHqvF+9bpgrAaU72HWVi/2Geri7QNVdGzpe+x51o1WPfTYGY\nMw7NyTTWTUATzuzc7oCt4VDqXcdZNdd3A7ZVC22ddG7lr61uybtlf+aNps5t56K1e9cs5zC/RZij\n01TA8LtJ9uzgC4f/DelLqzD7xt/2gv+D1T0H7OxfRamNd+P48RI4dBoZFzsPXqHc52FiYieIUEj4\nmKGfUW6wW7yGbhfJiQGEHvgP//p/x9ZS54a6k6/nP8BsepBK0suXmh/hjaFjBEa2sLWX8LprOIUq\nP2P7EzxCiVNsUWKQ51rfwTe9T/EO3/O45RIyGhc5gEyTPmaZZgBfpcT9qa8QjOWZC3Yhon932Os0\ng3TEUkx5u7mu7qKvukBPc5Ep7yBV7NTcDi789CHC9QzDjknKXx8nUCqwszjJROsIY8GdTB0YZJ/9\nMl65yATDCIqOfOuLWmEiRDrdive+Iv2eGdpIkSbKvNCLjyI1YVtrvmh0cr2+k04hyRH7Gc5xmDJu\nBAzclFnV2jFUgRWtjaSzi5HQHMqPNVl4opNPx36WRzOvcL96hrPSAfwHcwQG8rzuOYbkafJBvoKP\nAhvEOMWD7OMyXcvLdF9OkbwvQaY1yCZRvMfKiHqTB+WT9C0vYtQVbnQMsCLqKCRwUsVAvBUt4KJS\n8VLf8GCkJGp2J2lizDDAOnHSRCnhoYd5HuAUfcwS3soxfXGURVcvQlpD/x0DRnQ290c5UX6C+0dP\n0tMxQ4o2jP43V8bDm6IujVOpLXP+334I7UyI0d//6ndVFKZ6wwRwEzRLbHeipnHlbnOLWaayxARa\nkyYxp9aYx1hVKaZszrwRWDt36zFWDbfGnVy1WTp3GmNMQDYHMZjrndqFAAAgAElEQVTqE/Mc8q3P\nZj7XasGf+sg7uH74USr/9TzcfGsNc773KhGXSqR/HbVXRK3aMDZBD4M/usWga5yVzQ40zzb/6abM\nkD5NdyPJmG0HZa+TxEiKm4wwqQ5iKBBvXaVULZOa6mDDFcPdksftL+JUqtibNRLSKi6h8l1Fyqyr\njw1njHYhyR71GrvLN6g5nSTlDs5xGBGdsLRJ0emhs7lEuJJh3RnBJWzPcXtb8zVUReFFx8PINAmr\nXtabUSR7k03aWJbbyPRGcGg1rqk78XgK5D0bBOp5QuIWiq2dZLidtBrGYdSQFA2b0CCiZthRmOSw\ncB6Hv0afOEUHSZxUucR+sgSpCk7clPFSxEENj1hitHaTw/lLPOOPU7D7cFPmKnvYUOLYXVu0q1la\nWEfzGOgJAUelRpeUJBnsICUnuGLfyf3ZMxzJnEeMaVRcTrIE6dSXyBFgixD3b55juDCF111hQwri\n0iuEm1m0iIgh6vQwT9XmYEIcYFweYktcog2ZFtbYIsRKro3i2QAhf5aelkVWulupKC5yyTCFmI8W\nYZ1EbRzVJdEuL9Grz5ERwzRkG7hAtSvY4k1CxzaRuzWcvTX8oTxZIUilPkrJ5iFfCtzrpfvWq0yO\n+lSFmfF2Ii099Hx0N3xnHmFlm5u1WtbN4bzWh9X6bXam1ghVuNPwYjWsCJa/W5UY1gxqq3zPCtom\n9dG86xj43tQ/K2Bbc0Cw/Jv1363fFNQ2L+pj3SzFe5i+6aIxswrZN6fe+vvVPQfs0OEMwz83xqQy\niLYooikSG2Kc/tAkD/pe4o3x49QUG8qtjSpHs0FfKYnXW2BZSjBPLxc5wIrSyuHAGer77KQC7dQv\nOqikPJQ7/GScYWyeGoYHKrjQJZEiBpu0s27EKetuMkIYV7XGI5lTyNEmJbeHrwvv4wN8lX7nNFc6\nd3Bk9RL9G/MU2t0YMrToG/zr+u/yp8pP823pcT7Mn6OIdVJSjDhrzNDH6zyAhkS9aedU9QEedpxk\npsVJV3ORdmGRmm7jhjjKy43jaLrM+5RvUDfs1OsOBtfm8EUKHIq8QZ80CwYsC21c5AANw4Zg6MTE\nDTpYop85dgvXOFy+yP7UdW72D1OzbycOXmUPq84E/tC3OaydZ3/5CvWISLMo0LGS4l9VPs0fDH6S\nP+r9OBkxSP/4Aq0XNtjdco1TnmO8YhynT5vDLjSwG3XCyRxeoUL9sI2C24esaeyujTHuHKIoeomx\nwc34MFMMsmy0U9G38OglPOK2fd62qaJ93k7PQ9fYfegSp7vuZ2GuH3XSieZWGJGneNfmCZZbYqiC\njFCHMWMX445RxN0ajkgZbyRHYF8Ol1ImIm/Szwyns8e4mTlES3iNwsybf0f/H6Ka6w02fn2O1C+4\nWPu1R4ltPIOYq9GsqHeYYczNOj93AqR1Mou1MzU7bquEzuxsq9zO4zbB0Tyn6bq0ju6ybjzCnbI+\nuBPM704QtPLq1s9jvrZ5rHV4rwaoLoXq7hZKv/YIK//FzervL/4truqbp+45YLurJS6dOIJ+VMdQ\nRBRXky5xgT1c4YB4mfeEnmdcGuGrPMV1djEr9vPH9o/RJ00xwDQDTHOTEbYIIWCgIxKLb/CJj34a\nu6dB2hblK5Mfwhkrsd9/md35m8zaekjRym5SOIUqy0I7D+TPsL9wDaFisLM8gSZJ1J22W1NVBOKs\n4zpfQd8QqX3IwZY3SEEM4LGX2CtewkueDpK0zKaRFmD64BDBUJZHeZEaDiqKi4ZnOxb0JeERrss7\n+Wern2MHU2Rbg3zI8SVCxhajwg3+rPHTvMH9CB0G19f2UF318B9b/k/kQI2sK8gqCborS/RVligF\nHHQqizymnmD0/BTtjRWMhEBR8uGjwJN865bao40pruMLblFac+J5sYpkM2iGJIqDDh5pvEzb3Aon\nOh+mM7yE1iOx5QgTJMs+4QpJqZOcEEDUdASfwYYcZdw9gC4JiILGJddeXpKOU8LDPi5xnV1c13Yx\nW+/jQOk5dm5O8hfh93PDGKUZFvmZX/oMy2IX31z6INW4Qkd8kS7fIvPeLq4JOzjacopLjr2cyR3l\n0vxhls52UnE76H5yisxnYmRmWyjsiSDfX2NpoJ1ZuZfNswnqSS9rhxRCic17vXTf0jXzjEBtzcWx\nDxynczCM53e2eVqT1zVzpkvcBgGzs5a509xiDWaydscmyFst7NYNSnNWonU7zwRh81zm65jTcUxa\n5e4IVpN+sRpfzPdc4vaNwOqmtPLq9U/uI7VzF6//qpvUJavf8a1V9xyw29zL+J2LVEWFvKdGJe6l\nJtpoNG24pDJ7/ZcRBI1vGE+yuNFLWXdTCjlJNttI6xFkWxNZaNJGilZWuLG6i3LZw2N9J+iuLJLZ\njHLWeT9+V5YRaZyS5KYkeHBRpZ8Z6tiJCBki4ibKlgqXILwvS7ttlVbHCpogUcZNjHXW/DGkNYPY\ntzIs72+l0O2FDZG+2iJxI4NkU6mXnaw6Y5RFFxIaXoq4qKBvSmQXI9SqYVaEBKpgQ5abhI0Mw0xS\nlDy4KBMmg08oIisqBZubZlFCVyEltSIKDVYrrSyPd5FyrLAZi+Bdy9NVSRHPZ2id3MARqlPdYWdH\n8ybZqh/NKZFgBZkmSWpUHA5yhh/vXI2pwX4WW9pRW0TacyuMlm/QFAz6YgvohoDqUKiyrVapik50\nRJxilVzIR0HykFbChMnQRGZFbmWKQbYIIqGxRgtZPUSy2s1+QyAkZvBRIMQWiltF3NfEky8Q20oz\ns9BLp7zMU+6/4rRxBGwGN8QRXk09zKuFh7kh7iLs2cTlqqAaCg5fDR2ZwqUANNwIq34y0TjatA19\nTaHSrhCK/BNg/02VX4BaTsY90EauRSH2tJfYyavIS+t3TFspc9vGbnbAcCetYaUczE7ZpFCsKgyD\n29nTd1vhrfRI0/Kw0hzmJqZ547hbFmjVdVsHLJh0ign2VnNOpSNG6qE9ZOP9LM1GmXlRoJ7/n7mi\nb46654DdF59m8PgXuCbuIil0suGLs1DqxlWv0O+epdc7i45OSN/ixnQ3ZVzE4kvMZAdY1jtIh6P0\nCPMMM0GvMcf58aNMpUZQIzZaUmniq1l6Dk0R96/TwzxnAgfREenjAjt1O6KhU2KCmk9mOZvA+9Uy\nhk+g0WqjjIcyLhqGjVZSTD40hOLQ+OAv/BX8HKzF4tjHdbzrRSKNPATh1MgRXtz3EDoidexsEtne\n9Jtp48zXHqQj+hq7afBTfJ5QLI1Agz3CFZ7ncZZoJ8Im/fIMXor0CbP0t81SavNwjWF0RNIrcVJf\n7eLq7gon33s/j4+/TNvEKuKyDg6otihUYjLvXnuWycYgX3W+h7ZbpqQsIdaMAJ3aCm1qmhejx3mu\n+zEC5LgvepZD0fMc4Q0C8RJa0IbiarBqJLih72RAnCIqpPGKRZYjLcg0sdFApkkVJ3nDT12wkyfw\n3fxvT7OMVrZRtrloRAT2cxEfeSYY4iUe5r7AWX6K/85vvfDv6Kit81TiOXr2zzNn6+Zl9RGev/xu\n5pRu3A9sMbzzOo28kzPTD9H3/gl8e3OUfsuHcUJEPC8j7hagDoJTgwo0K8oPXnz/yKueg3O/rjPz\nib10f+r9HPvY/4NnZYuqpn6XVlC5rQwxU/PupiFMoNTYpj/M7tdpeZ5pAS9zW7pn5autihFzI9IE\nWlOPbe2QTSrl7g1I83ym8cYEb3PD0cz9tgGypLC5fweXPvUrzP3KApk/WvlhL+k/eN1zwD6zfpSr\nr32AxL4kicAa7UIKl7NC1gjyTPNJRqUbyEITn1Dkf4n/Z7xCkXmhjW/Of4DVRiuVgJuImIGGwKfz\nv4jU12Sk/xrPup8g1dFONJIm7/IjYDDBMEV8uCgjqxp9Z5JEchlUl4y+0yC308+3f+1RNrsjpAKt\nLAqdTNcGyJcCPJN7Hz8R+iIP9pxA/XWDtu5lAo4Mm3t8rNdD1HQHeZuPM96DTDPAA5yinxkqOPFT\nYMfQBN0fXUA7d5o4u/gcH+EXCv+VdtZY87XgEUr49AKt6hqhQoGU3s6VyC5USaKEh0vsp59ZBoLT\nvP/pL1MP2Bm3j5AfDXC4eJEH596AfiglPMwJncwF+5lkiAlGvqu2uI+zPLTcIFTJkX53gGrCRoAc\nhzhPglW2CDHNAN22RTrlJD4xz2OzL/PY/KsUDji5ERrlFY7zPr5BJ0lkmlRw4a2XGSwusNtzgyV7\nK4tCF69VHuLq5l7UWQeXywf4Df0pfGKB3VzlMb6Dig0NmXl3N8GjG7xROMTH9c/itBfIlkLMp/tZ\nibSxx3uVH3d8gW/PvYepyzswXhVYK8QR1nT0KZHRT1zlvsfP8LD9JNelHVy3j1L2ukk9036vl+6P\nTJVeyjD3c00KwU/y6PG9/KvXfptJzWBDvx23akr1TOA1O1yrdd26aWndfDSf07D8u1VlYh5jpUes\nvLhVX22lQaxZJeb7s0bB3p3FbWaMhAUYEAX+20O/yCu+g2z87CylS28tNcj3q3sO2LlcELeusZmN\n0SPPMeSZQFR0As08wVqewEqRLXsQtUtmIDLJQG2GgZUYS1ovl+0GggCbREgTY5oBYp51HPYKuiSy\n6Qth+LYH4dpoUMdOghX85ClSoiEoiOgkjFU2CLERi3Ahtg8zq3mDOFuESAsxlgQns/TRF5om/VgU\nVVMQawat9TUML2huAWEFossZRqQpOjqW8biKqMgoqERcGfoSc5xTltGa+3ij9gAPNd8gJG8hG1Xs\nwjajV8eGIBgIgkGOAAG2aGGNGGns1FGcKkd2naa24SI3FWSr089KXwvpbAj3UBl84EipyLpG2eFm\nxtZPphyljhO7cY5ZOlj1VAl3ruGRi3SzQAurVHCxQWzboFMXUGsKy7524sImfcIsp7gPFYXWW9dP\nQaWOnTJuQrU8/avzdEYWifm7yDkDqIJCCS+6JlE1HKRoY4VW/OQAtqNqK50YNZFIS5oFfw9XSu+i\nW5lBbdhYE9qo2VwYhoS65aCmOmlINrBBKe+DogFRAefuMon7ljlQO0sbi0TFNV61PchC+Z+MM/+j\n1Ziv0lhWyR3vI2Ic5iIfIDBwjoSYJD0FunanwcY00Jhd791JflZFSNPy593DAu62olgB1nqMyTk3\n7nq+NfjJmvFtNfNYbe+GDK2DYDQ7uTR7mEvGYSZWQvDqLDTN28Jbu+45YMerG3z4yOf51PgvE2zm\n6RmY5xL72aHf5Onyl1Be0Hkh8Bjprig3g/3EU6scvXiB5N5O7B1lUkIrpzlKzeagLbrA4nI/W5tR\n/mXPb+O3Z6ni5CDnaWDHQY2HeA0vRdIKjB05xqYW4P7mGyRtHUwzyDw9HOQCbspcZxdhxyYhxxa1\nkIPXhAe4wm52c41VKYGvUuT/OPX/EhlcQ+0Scb6kcXTlAjWXnbmfaKfgciOisEWItuw6x2fOcL7W\nzXKtk/WNNp6NvRPZXeUn9S+yYrSyJrYg2QfJ2MOsG3EagkI/s+xkjMOcZ4xR1khsOx3HF3GdbvDa\nTx2hNmJjYriXLmGRcDLHnvM32V2fQGgV+aPD/4yJ1QATwk7ixiIn2z9IJ0l+UfgUPcwTZhMNievs\nooiXT/KHDKQXyG6EeWHknbT3JlF7RL4hvpdBpvk3/JdbsyfbmGQImSZKWYcFsDV0DBTWHC3YnXUi\noTS1dh/dsws8KOZ4jnfyHO/8bme+mU5gbCi8Z/irNG0SS+42dEnA4a0Qty+zlurk0upBrqX30rtr\ngpaOZUojPoxFGdaBIqwNJrgh7eCyezeHty7hqtb5s+BHWB+I3+ul+6NVahNePM1ZdnBB/1P+5PGP\ncdSd5MXfhnJ1GwSdfG9sqY3bag6rCxHuDIOC26FQVhrk7p+tudSy5VymuM4EcAe3NzurbFuDHNw2\nzZjgLlqeb9hh94/B6dJRfv63P4v22reA06C/+R2M/6N1zwF7JDzOnO0xajGZRWcbJ/S3c728iwWh\nB/wC/Y/NMm4MM50ZYsPbwlhwlPP7DvNG6AjzQhcAdmpESLODm3SEUqzZWvna8k/QGlwiEUoBBmG2\nsBt1/lD7JJvJGMs3TvPvl+bpCy+SdkZZEjpYo4UqDio46WCJf8nv823exRYhHhROkqSDLcI0kZFp\nInh1bh7tJ+QL4LDX6N2dQtshsOX3UQ8p+DdKBFcLLPQ0cfrLVPskJuaGmF+6D+PbItd79hEYyDMw\nMs0Z4QhCFR7YOIc/WCLkyBLJ5mhdWoW6wNTeIdbcCcq4uc4u5kf6ICKwHEnQl55naGket6OMarex\ncCDKDW0nZ10HCMpZhlqm6WSJhjDP6jWd5Wo3U/sHGVVuECDHFWEvPczjocQ6cVYibaQ9cXDouIQK\ngmAQJIeHImDg1kr0NRaI1XOcdR8g6whCAlItLdQDEo8Lz7FKguvlvRiToJVl3FR4nOeZZIgFuvGT\npxZwkZGinKofY49whV92/hYpqY0tQuQJUNCiSF6dluFl3uZ/mUFxCl97ic/aP8FZ9/0wLzOgTBPY\nyvPZsX/Ol3xl1KjEippA84p/47r7p/prSjcwWKbJM/z+C+188+AnKf5eP49/7hsMvPQG89xpT2+y\nDZYVboOn2VHDnYl7Vp21OUvRuvFo/dmqOjFvBlZZoHWz0SwzPtXsqk2A9wjQL8LYo/fztQ+9lxdf\nnmHlYoAmz4Ke4s4e/61f9xywOzxLlCToDs2SqwY5s3SMpXIHZb+XUFuG2f4eNmpx2qor+Iw8mksk\n5WphdqqPhWoPrrYyXd4F2uyp7SnlSh3dBkm9i1zJz4YeR9Q04pV13GqFF0OPUKs58aoTlJsbLGR7\nmF7qpd6u4PRU6WUOEYMmMnHWGdYmUZE5Ip2hu7LAit5G3uWjKjopOTyM9YwwUJohXk5zoXMffimP\n215kwxHDWahjr2sEiwU8RhEtL5LWouQFHzvEMSqam61miAWhmwxh7IZKRougGQIeo0RAz2NXGzTq\nMna1QVjfwiVWyBBmIj5MOeRmYGWGlqU00bUtGu0ymUCAhbYOrrKTiubkneoJ2m3L+MQ854Q8DXWL\nrBoiaXQh600CRg63VEYVFOrYSdIJbqi6HdiooyKTJUgP88RIkyOI1yjiNOqE9QyKoVJ2ukm2tnE5\nuIuy00kvszTqdpoNhbAtTbnqZnkjynD4BptShKV6J/U1J4ZDgKDGfLaXI+JZHvN8hwscZKy5i3Q9\njstXQpHryO4matmOTy5w1P86J+VjTAsDZIsxwo4MjkqDc5NHKSpuhEAT2dtAL/1T+NP/XOWBPK9P\n+LB5e/A+NUy7fQ1nSKW5bwNlfgt5rvTd8VwmNw23O28rYN89tMBqHbdaza0qEWuYlHmDgDs7ZqtR\nxpolYp7LDah9PqrdYRauh7luP8IFz0GKEx4aNzPA2N/hNXvz1L3XYUtlusQbdHqSvLL0GM9efApd\nlmAgRb3VzlerH6BNSPEvwr9Lv7CtnuhnhvNfOcrqYifCT8LuHdeJxdJcZh+T5REqNTe7Oq+QSnXx\n+rWHoWIgLhkIOR317SLHel6lfedZLnUd4+qFA1z89n184sN/wIPDr9LKCuc5yBg7eYXj/GTjS+w2\nrpN1+hhMz6PVZMZ6h1gTW5hkCDt1BlbmCa6V+A97fomj1TN8eP0vmOoeIhMPkQis8a7FF2m7sUn1\npgPJodM/MMUjXS8zJ/YiShoN0UY7yxSdXr7Y9UH6xBmiQprx+A6GozcZak7xsPoKNdXOir2FkzzI\nFfayVknw8ROf48DWZfQWgWyrh9VEjCRdVHGyt3GNp/NfQdI1pux9fMfopWvvLC1Gik05zCvq2/Dr\nBf5v6d/zAu/gRR5lL1c4zFlGWWWVBGskEIBDnMdGgzl68MsF7FIN0QkOoUrB8PJyywO8IryNHAGG\nmGQsv48mNnYfv8jYhRDPXXkPtmM1Gm47Ut5g7sQwxpCO/XCZWtWPLBm4qBAmQ7nm4UL+EL0DM6g1\nB1OLo8xlh5j076C5W8LnyTMUneR8JUzTI6OWZYw68JKIsWhDjSiw762rpX1zlE7jcoatT5zhz+r3\nce7gYX76d5+n7Q9Oo/zOFMtsKz40trlsq1nFLBNQNcDHNvBWua21NtUgpknHlA9aZ0NaM0NM4DZf\nw5pxYuaAcOv9dAHZ93Rx/ece4lM/+wAzzxvUXzmDUbUy2z969QMBWxCEXwU+wvZVuA58jO0b3JfY\nvm4LwE8YhpH7655/ybmPOHtoCjK0aNx38HXeXniJHfZxfJs5VpxtLGg9fHHlZ2gLL+BwVCgbHqb2\nDKG3SuAFVVIolP3MJEdw+yoMBKfpVWbwRCoIGCwu9VGLOvGEi7wt+go2uc61+m5G9TxPdX+dh594\nCWe8jG4IxI11ZEGjIrjYIkRS6aCGnTeE+3hX4AV8jSJfMj5ETF/nJ8UvkiWIHoOCx0mfc4awkkY3\ndB6aP82cv5u1tijFFgeLSoK1rha6Li8Qkm5w3bmTmflhHEaVYHeWrBgktdXO/PUBzkpFOsOL7Ou/\nwLyth7pkZ0SawFcrE63k8HjLHJAv4mmU6ZhephjykDzSxnh4iEvNfVysHERyN1lVkuATGDXGkCWV\nuLDBk43nKBseTsr3E5YySJLGd3gMBZUneYZOkiRYwUuJh3mFHH4K+HmF47io0Elyu1MSAuTxc4GD\nZIQwXqFIAxthMvjJI6sqqmajoPggYlDptfNi+nHqaw7ymQDVipvj+gnul09xIvYOVpQ4f8zHWKWF\nycooatpJ0eujqShosoRWk5laHOZzr36cfK+PjDeCXpC4PHMQh1Cj3u/YRoUcIAnQqf11y+1vVT/s\n2n7LV1PHKOrUWGdhXuQr/1cU79gHCXTo9P3sDLuvX6PrmSmm61DSb8v2ZG5vSFolfKbJxuyIzVwS\n68R1gTu13Hd31KaM0OpSNACvAP0KLL57iOu7d/P8ZwdJvyyR2VBJzm1Sa2jQMCH9R7f+RsAWBKEb\n+CQwYhhGXRCELwEfBkaBE4Zh/IYgCP8r8L/denxPjWsjJFfuAwfYXHWiA6v0pObpURewqzUi3gzX\nm3t4uTDMoO8GiqPGit5GqSWI7FFxhctkcyGqFSdruQSdrnkcRpXquhuHu0pX6xwetULOH8Cu1DgW\nOcmy0M5lLUjMuMmB+AVs8Qbf4TGSRiedLFHGjY0GXSyyIUdJ0co0A9zvPItiU1minV5m2cEN5ugj\nEwhS89nYXb1Om7yMFhQYWJumXreRFNvIBbxsBfzM0Yt/apI461w0DjC32Y+sNvHHs8gOlWw9xNT6\nMI28nfVIgqHOcVTNRr3poOJ24hJqiE0DwxDoZY6d4g2CniyTiQFO9B1nU4ywWO9iSwvhNQrkFD8T\ncj8taoqIsYmNOiPlFaSGQcYI0SavUpftZAmxp3aVkeYEuguaokROD1CvOCnhZ01uZcI2TIu4Rhfb\nll0dkQY2luhgkS6cVPFsVOjQl/DH89hKDdSaTK4tgORX8bVnKa96KdU8lFQvmkPCXasSWdvCI5RZ\nlLqYqg/S9IjUBSdusURTkGg0bVAFQdHIqGFOTz5I1L2B2NQhA4u1boSgjrhLQ4xo6JsS1MDWXvuh\npu79XaztH53aIr8KZ77gAgYI9oeodgUJr+p4nRILHSHs/jTu/DT+NBhZ4w7O2lRzwJ3mFlNuZ3LW\npq7a6lzEcryVOnEBSlBA3yFSW40yI/bhXN9iNrKDS10HOW3fQ/ZqBq5OAf94TFQ/qMMusP1NxCUI\ngsb2dVwBfhV4261j/gR4he+zqDfXY8x+5xB0gbcnhy+R4ULzGEP2mxyNv0ZZdOJtFki7YvRLM8hG\ng5TeDosC7nqJ3oOTzD/bS2Y5Su1xiXmli+VUG8IFmbYdSXbsucaTvZ8hY4RJCW10y/ME2WLRUyKh\nbGAgkiHCNfaQFYJsCHHy+GlnmXfyHM/wJJtEeJQX6Wss4GuW+THv1yiKXq6wDw8lJhim3PDwi8lP\nE/OvUUkoFEadbAoB1omRI4iGxDot5FkjgBMfeRSpwXq1le9sPMF7o19lyD/JpQOHaLxoQ18UaTRt\nDGVm2JW/QWHQQdHlJO/0kxYjOKng9+aRfkzjin0vf9j4JG+3vcAD9lM8YXuWFaEVFxWGmWBnfpKC\n4WfN6CVf1tiVG+cj5S+hu0VKHjfz3jZa0+v4CiWu9u0g7Yiw2Ojmzxc/ypLRgTNQ4eHoCwzZt282\nbsooqLSRYpoBNokwRy/lNwLk6lMceP95xJSOVpApDbpxUmPUfp2ujiTzRg83cjtJFvp4If0uXjtx\nnKrooumREKMa4V1rBEMZ7P4VGrKNXFKGOQFxqAFtAlqfg0N9p3FU63zr5PvR9uoofTXs/jq1Gx7q\np9xQg8C7c2z8cGv/h17bP5q1QH4xyUu/0uD1+h4U99tofPhhnn74GYbO/keOPqOxdlJjljunlMPt\nzrvBNjViUiE2thUe5iaj2ZFbB/uaG4nmuXqBzl0i/L6d3/v8cZ4Rfw3bH76M+sUcta9Vqecu8aNM\nfXy/+hsB2zCMLUEQ/j8gyfb/wfOGYZwQBCFuGMb6rcPWge+rsbKLdRpOO1KwTrngRt1QcMdLVIJ2\nUlIrD/Eae+zXOBV6gEwySkaNUPH58fbmGbBP8YjjBM93vJtlpQt0ncZ1GXUJjKpERXWRbsZ4PvsE\nokPD68sh0yTBCq1iiZIQYJFONEPmsfLLOIw6AWWLTSWMWyrhpUAdO1JD50j+InFxnZzdT0HwkyG0\nHUZ1ayCnRy5yMbqXFvsqktDgsm0/JTxEyKAhMV0b4tnye3E004xQ4V3Cc4jtAhtqC13uRUqim0l1\nABUbyAKirGOjwWKggw1nlEW5nYCYxUOJAj6UZQ1Pqka23Y/fv8XjyvMcEs8jChpLQid+8nRXkuzK\nTBBeyeFu1BhdahDXShguDe9aicWOdiYd/VwVdjLin6THMU9DthFvbhDWssxEh0gIyxh2SEtRznOQ\nLEF2MI6CygYxNERGGGc/l2iMOCjO+PnGZ36cze4w/h2baLaKo/0AACAASURBVJJEPh0iPZ7gWP/r\nrNuiqF6Zlh0pcpMhtsbDMAckQPE2sGt1mgWF/GYYd2sB2d/APlhCq8toqzIkYb6lB9mrorWI6K+K\nyOd04h9fYzOVoH7TDa0QETI/FGD/XaztH81S0VWobEIFaVuk/fI0J+cEJlZGub7YSSmUINczSPSh\nFUY6b2yPm7teRbnWxLgBk3XI6bfchtw5T9KkRMJAlwLuYWjuUcgfcPEG9zG+uIOVVzo5tTiBf2EV\nfgcmxiAnTEOpCRURiuY4gn989YMokT7gl4ButreX/0IQhI9YjzEMwxAE4ftqZzb/7POIsbPIrjpG\ndAdFcR9K2yYb8Rz1UB6Zy4CBbqRYW+ihWAvg9zUJBTcIOuYQz1/GU1rFV7lA8aYfYxmEnI7k1ylW\n88yNl2nknUhSk6BrC1nJERU3WX89y0t0UMWBbjTZUbmGVy8ypTjIK5sYElxG5gIz6A2Z14qrKPYm\naTuclVepC1sYiFRwYquv4VSrzDhrxMQGXqPIRaGER12nvz7DlNPFgpZhvnIGz7UU4/IKXSwis0m0\nqdDamOUN6T4WmkPYK1fxLqk4tDVmv3aOMYeDHAEa1AhRw0eFImOUV5bZXBeo9epseW8iiGvMkaGI\nl0XqtLJCppplektDKriwNRqsTC7wZbefqpyAFYm1WIylsJcFBFqaQdr1Mk45S1xP49IqCEoTWWsh\n2wyybo8xJxpMUWCKGgIGaZo0mcRDiTZSyBjkbvbw0pefwPHIPMreBnXJQfXVm9xcEggOrJN0jlEQ\nC0TFDXwrXpozEao3nBgpEVGtoy8u01Bt5DIxmvE8uiKgVzxo63bYElAKTeY2VcSggS13mcYzNtRS\nk7K0jv7cEo6xBaRFjfXp6g+18H/4tX0GGL/1c/TW4++rlv7+XqoMnDzF9ZMAMi/hgIADoSETLduY\nLbjYIIC74kBWmzR1WDAkNpFwYENERkC8xU9vs9s16gTQaNc1nCroVYViwcllXMyU7aypEoZuh6QD\n/psGzAKf//v7zHfU39e1Tt96/M31gyiRg8BpwzAyAIIgfA24H1gTBKHFMIw1QRAS8P2bHeXhf0HP\nbx5ln3KZhVf7Of2Vt5G/piI/soH/6SRjvBcDgTp2jtZu0qEtE5RzdCiL9Knz7Cissc+xzjdVO19b\nfC8Nh4TDV8LrKmI4BTxKkYe0k8xs7uRGfje1rhN0u17FzYsMP51glj4W6SKoXUJFYULYiyooBIUt\nuhinjyEEAxLNGm6xhF8MkhYOoyNSxs0FDrJ1LUZ4Kccnj/0exzzTtDZXuWEL4p8pEr+Z4T8d+Tjt\nUZmP6i/z4pfg8NPdeAnTgZOWzQ0eHJ/nywP7OBnzktODjNRuMmgsEfHIvCw+SINefpJv4kCiQhs6\nIr56Dy01FzsbEyw5PJzx7vn/2XvzGEnS87zzF0dGZOR9H5VZ99ldfd/dM9PTc5FDcmYokUtRlExp\nvbbl3cVCEryAJViwgV3/syvLNrxeSytLwtqyJVGkKFLi8JrhHJyZnp6+7+q678qsvO8rIiNi/6iR\nvLCt5Rp0W2OxfkAigURWfkDgqSfy+/J934ckGSIU8X9oomvWON82PkGsn2fAXmHmK5fhr32eW8IF\nCnqMoKOC4DCxGWV+N0ypWeFnBn+bSWURp90jIg7wnZ1PcmP3YxyevEnMt4ubOAESWIi48VHHi4KO\nmzweWtS/NYb4G5+mI2r0UhJWUsRe/RK1i5/nyuAXEJIG0VCRp3kbuyeykUty/dtP0h10EHkmyzHl\nFrqtsGxM0lMUGmU/5koUEPF46yQTmxSFMLJkMKGusNqdJr+cpHhB5+TLVzmjXGFWfchrnU/wlaH3\n/v/+NzwGbZ8DDv8w6/+Q/GWtfQCaKvaaRbXs56F6iC2GkFoWQsvGNqBr+zCIIzLF3gbF++HftoAC\nFo+Q2UW16khbYJcFzNsSDbx0ui7smg29JHvfw//sfvmjdq3/l//oqz/IsOeBvy8IgsZeZc3zwDX2\nrvzPAv/7h89f/4s+oB9W0CWFha2DFOcS2PcEjB2FkakNXuKr3OE4ZYIEqVBz+pEwcdFijoMsSdNc\n06oU1SCCYjKVnGPbTlMXfDR7EjE5y7C6QUgqcdp3lSE2WaxM8Wr30xj9Huv2k9iCgJMusqSTrO4S\n3y5iqwJVv5+16ChuoYUg2NxwnGSMVTw0iZMjrWfo6i7e6z9N2rvF6bEbONUuYhe87Q7eYAMjKLM9\nniTrTqCKXRShR7q9w9lyGUkzEXo2/nIDf7VB3fCTlZLYkoDtsGniYonzrDNCEzfLTCBiUrf9lKww\nbkeLlLJDveOnL8l0cXKDU0ywzAt8jw5O1o1RXm98go97v8kh6QGa1WOdBPeMoxSKCT4ZeJVBxwZL\nTFKSQlgOiabgZk0YxUbggPGIiF6m2fMSsGvoi06W7h7k6JO3UJMd6nipECRIlQglujiRJ/tM/PIK\n1ZkIxpgTxdejGOxgpkx6YQlbd2BuxrndOsNs+B5HYnfJPJGm4fMQ07JMs0CmluZmOYQ7XmfEtUZo\n4A62LOB2NYkFMlzVz2IhcUS5i/9jdZaPTrPmnKAaCFAOBukjQeuHPr/8obX9o4kN/S40u+jNveON\nGr5/7z3OD58r/Lu8Gdh795/lwLjAlvaudov/122x/eFjn/8YP+gM+64gCL8L3GDvhP8W8C/Zu2V+\nWRCEv8GHpU9/0WeYkkS9GKSYG6BbdyEINlqkzYB/myP9e/QlB7tCgh4qt83jbJMGCVa2BijWw0iy\nSsCs4RZahFwFiuUo+aqHLgKjY6sMezdQ0Il7dkkJ27x/4yluqKeR2zvEjacZYIex7hodl4twZ4lD\nmQXwwG3xKN+PPslp8wZOu8v78nmSZIlSwEeNif4K/Y4TuyWRCmxzynsFZ62H3nNSswN0LSfb/jTr\njhF2qwm0bpvF0BT+1jUOlLepRX24Oy30qsrD3Vnm2gfYJcEoa1T6YYp6jLvdo1iagFPo8sHuOVze\nNoRg1RrDKXbJikl0l0K6v0OgU+emchJV1HGYfXKSn0I/Sr0ZpKV4aMkeOoabshmmZIRplPyEnBVG\nfOs46SGaJrZhY9oyeaJ00Thp3SQsF/F5agiSRTEfZ/72LMNH1nCFHex2k8haH7ejSYQiS/UpjKjK\n5P+8QlZoo6MQJ8f9UIFOsoLq7NFcC1JaTlAqJ/AfqZI+sonb08BERC30kXULve6k1gwxGNxg1L9C\n3JlDE9uEhDJxcrQVNx00DvAI1/kWdg8aJR81wc9Sf5IRaZ2Au/xDCf8/h7b3+Yvofvj40ane+C/F\nD6zDtm37V4Ff/fdeLrP3jeQHon/PSeegh5kzD6h8JszmyTEmovNshlL8/fo/5PPeLzPqWOMdLlJq\nh9FR0LwdNn+jQfn1HkLkIFJVQFQsOAbdmgZdAQZB+pSFY9jASZe7HONm/RS7X05guhUERSHYrNLs\n+Hlt8SVWD0+wEpmgfPZNbEnkoeMg88IMrzS/xbS1SNEfYVjcwE2LTYaQnRaWKdMtunioHSZcL/A/\nfe9foqcdvHX6SXyOGne2TvCle1+k8kEA11SD7k87eaH3DTYMH9/1PMtp13U2V0b51df/Ho1xjQMz\n9/l5/g9+v/IzvLrzY7RXXIRn87gcDQr/aIAjl+5w6CfvEJQrf555KGIxVltnNrfA7lCCmKNAoNVm\n0eMhqWX4+eSv8e32i9w0T+B1+egqMyhyD9dYnRXnCDYWcXYpriRgU8QVbqOpbSpCgCuO89Tibg6H\nb7KgTtE66iE+sk0lEmCzOMzi/EE+f/jfMhWdp0iEy9cuUtFDnHjhGj3Hv5vd0lcbtJUFHqwfo/09\nD1wGdLgtn2A1PEzhHyfpKypbR/qsbM5gTgp4Pl7hrOsKuqHwJ51Pc871ARFHkUG2+DRfR0fFRYsN\nhpEdBuej7/CoOUupGkMO9nlJ/Aa/9Z+u9/+s2t5nn//SPPZOx+hwnvOj32MitEAj4mUnOkjIX2Rt\nd4y526fIHU2AW2C+cojKVhSHU6d3RKUb89KdCUHKAyvS3u6qCDRBcfcIH8nTElzcun+W5WiN3WKC\n7FqSqcOPiMfylFdv4FfDrBfHKGci7E7GueU8yXZpGFsVaHs0RMVEV2RalkZb0MgRw7QkbhvHacg+\nQs4KidAOYVeBtL1DJFRi2TfGvDJNlAKbK8NkvpfCN1bB9Mms3JgmJh4hFI7zUJohLW2RU2LMOWbR\nxBrZtQG+9eorrBwdRxtpMdhfZ8S/iiL1uHLBg3u0wQAZBoUtbvZP8qh/gLSyTVTN0wxobIspNoUh\n3Gqbu9IhsnoSo6axZE9hqgIpyY1PbJMWtul4NEpCiFo1QPVhiMa9AD69jtQ3CVHGTxVBhA1hmAxJ\n6vgQvDaat0ORMIZLIZgsoTn3tqdNPFSCARp9D7LY5xwfEKWAhya64SNXG6BbdKENtPF/vELUzhOc\nKSGoFqVEko6qIcUNXL4m6aFNRnzLeKQmG+YwVTFAQ/CwrE+x0pgh5sniV6s4MGjgxRAdtEQ3orOP\n2+wgCBbqD1WFvc8+/3Xy2A175MwqF08uE6SCYuv0NYmiEKVV96KsmWQmUzQFHys7M7g2WriDNVS7\nh+PiMOLBBFZU2tusLrB3/OUEZbBH/OMZyrsRNldH8Yt19FUFZb3H6c9+wIHUQ+7//hw19znMnoxd\nhn5OYbU+wXubz+GI6sTiWWZ899jREtRMD6vdcRoOL21L4271GG3BzbiySiyS4YD0iEPGA9TZLiU1\nxLI5TlvUqOSCCA8tPD9Ww/AoFG8muOs4Qit0EqstklWTNH0epFkDU5RZmpvm4ZeOE4/uMHpxkamh\nBSZZAktk8bNTyHofqyQR9RcQWxa1eoBYLI/qabPhSbPeH2KHNBvuQQpEqbZCNCtBOl6ZhJRBpUuC\nXUJCmb4ks8YoK81hqrdj2BURX6xGVQgw0l0jbuToupy0Wy4WajMMxrfwSTVk+nRxEghUOOK/S5AS\nHdNJTk9gjEpIoo4lCpzgFiOsc5/D1Pt+su0UqtkjcLpIfGSHMWONASmD3RNYePowLdWNa7hOKrTB\nKeUaZ7jKDmlsBBLqLoII8+2DXM4/w1H5OuPqIgGqiIZNwKqxqowS0CoMsIObNrqp/gDl7bPPXz0e\nu2FPeea5xU/ipsV58wpP9t/jtnKCnZE1DoVvIwUN2nUNsW9x5MQt4uEMPVHBP1WiHXTSXA9im+Je\nW4MEaGCMOigoYdTxLsdTV/mc849YS4xy5+RRUpFtMqS4jpsgUQTdxi6J5L80gB0C4aBNPLTDQHQL\nj9DiDZ6n1IiSXRoiObSF5DBoPQgyt3GcLWUM70sVkoEsXVmlHtFY7I5zo3qaH/d9Dc9wA+tJicLa\nALZfwB4UaW54WalMUFuMMDy9hTLUJfTFHNU3w4hVi6lfm8M3UcVPDROJIhHaTS+5u2k2FyZ41DnM\n8OeW2SkM0n3kY+XSBN5YAwcGh6X7SFiUCHOUuyTcOZxDPS5L52nIXkxBwksDNy00OrTRyIdjKC82\nUdCx3Cbf9H+S6GKJAxsr/M75z3J19wKORZi9MMeIcxUXbWr4GbNWedZ8E03s8E7tEv/nxmeQ010i\nvhw9QaVAlCAVIhSJOl0og7cJxis0nW6qvSDvrz2NJ1jHGWxRC/kJu4sMhlbxynXi7HKEe4yzyriw\nwoxjng1hmJIZgzZk+wkEDAbZ5r/JfJ3J7jL3xmZoOjxodJlhnuHazuOW7j77fOR47IZtOyBPFIsE\nPqGOT6qzLIzTdLsJuMtEyRPTCiSSOdzROrW8n+WvT2M8paAEewgy2F6Qhw1c0Sa9pobgspFFExMH\nPdGFrOqYeYn6TpC6x8+uEidrabSNFHbIJn1ineLbcToLLoSSTXQkT2I0i5MuC+sHyVWTuL1NUC1s\nWcAbqzFkbzIlLTLoWNubKy2UqCk+sG3CQolNcZBMNAWHbeSAjsffwBeoIeV2mVDuI4REnEqHcj9I\nt+HCMJxYrj61cR8efx0VHRWdIFW0po55U6ZUjFJTAtRe9dF1a/RllTcuf5zN8WFCR4psCMPEjALP\n9t4h5Czgl6t4XE0ETEqEybJDo3GO5c4MqtWj43PjqzUovxvFCKrUw0Hq7wdZck5xJH4ft6OB31tF\nS7aIqAUUdKr4GWKLkFBmXRhlpzXIdf0MPZ+Di9objMortHDTwk2GAQwcuKQWPtc6ZVeYJBnG9RUW\nvQdoqxo9WUWLNxEkA9MSOW9dYZJl8mKcNi6qQgDDUjh+5x6H2484l7xGRo3RwI2Bg4hc4rD0kFC7\nxKJrnIojAIDk+KsxkH6fff5TeOyGXRSjtG03TcHNDekkW2KamhFER8Eh63jNFgeccwyPrPMeT/HO\n2jOs/PY0scQOnidaVH02BEGWDXzHy3RWPVATCIpl8vUB1isTXJfOsrIwycr1KSYGF2n5NEy7QV6P\nEkxWGE0uYhdE6u8FcNw0GHppkwF26KBhrjlwtA1mXniAW2liIaEe7nDx8Dtc4vuMsoqNQAsPFYIE\n1CrH1Vvc4iQ7vjS+iTruZJWob5dBdRP76grP+yuE/BUWjSnWt0ap3Iti+UUIOFgvjeOUukT8RUTJ\nIi1sI/dMwlsl2gE3Zkyi8M0k9ikBnrd57Uuf5Hb5BANH1uih8mnjm/wPjd9iU05Qk71YiEyzQNty\nYRs55qqDvFV5DrMjMzt8B3+uiv0VB1ZKxBwWEe7b5D8eZ+fpOLPaA/LuGLmBKJLQJ0+UTYY4zANa\ngptvSC9zrfUEXUFjdHyB53idEda5yUk6aKwxSgcNq7+E1uqyKo6TlnY4yU1cgTab8iBFIYoS6dHp\naEgNixfc38OpdHhbuMSukdgzbMHBSze/y0nzJuasxavqp7jKGTKk6AclDE0h2q2w4rCpOgJImARd\nFSD7uOW7zz4fKR67YWesJM3+AHE5hy6oLBgz5B8N0JNUxKTOUvkgz2pv8rfSv45Gh/CxPFP/5AEn\nxm/SE538sTqI2ZTQcyrF3SRT048YOb6KpBl0il7Wykleb3ySjseF+axMPhBjWFjjqHiHrPIMFSFI\nVkxy4sVrjJ5dI9XZITW+jY6DBaaJHN3FZdY5ID/6sCmlhp8aBaK8w0Uu88SHEV57haIODNJsUyXI\ncGADTdR57+7TbPlG6Z50MmX3aeHmA86xsDnLVnUY65CJ6mkhdqDz0MNWeYz2kJdSMsxB+SFHE3d5\n5ef+iJycoNiP8Z5wicagGzneQ590ISX6+KlzlLuMq4vcCh1CdXRYYZxv8DICNo2qn3vrCyj2IOFI\njuJqAtG0kEd0pF/qcsx3hxP+WygNnQtrH3D4jx9y/cVjxGM5nub7rAmjCFiMsUqMPNukWGeEvh+G\nWeYTfJt3eIq3uMQIG5QI00UlQJXV7Qkq332RiifIG7EXuSFfoHndTXdIxXO0zkv+P+FU6zYTxTUS\n2hYlKUTQrPDao0/iV2p8YebfILyoky9EGLidQzvQYyyxxgXeJ6PG+XXH36Rlu+lIKhYiWZIkO3n2\nftjYZ58fHR67YeeaCbrbMZyJHn1bplKKUFsMYVgyckPH49+m41dZZ2SvaSWU4/5ZixAllF6f8dAi\nrWE3hseBIThIxbaJK1kWbx2gkfOjtxQyWhq8oIa67EoJXDQxBYm4nMNLA5fQZii1zmBqgwhF6njp\noRKmRDq0RYnwn895jvRKzJUOse4dJuNIUs8GCFEhQgE5b2IKIl2Pk92BGLLDxEOblGebiNuBTA8T\nma3eENfr58hVUjQNDwRMkuEMAaNKp+Kl4g/SUlzsCnHucwSvs8GF8cvsignW9VGSF7KseYZZCY6R\nnR3ECoKBgw4aJSnMqjRCG40iEfzUqBAk146zWezie5TAG6oxHl4g5tpFcFoIQzAQyHAiuBeNNtNc\nIFCsU7ZDKOhM9pa4cfssgs9idHadHiouOswKD2jLLly0iJPj+61n2GyPUOgsUvP4kN0608oCfaVF\n3ytj2CpZI022ZMHrOqEny8RO7pIQdgkoFRwenbIcoi/IpIQMiksnJJY5pd+mNuClK6qIO2D3RWr4\nqeJnWZqkJvlJkkXCRPpw4OZ96TB79YP77POjw2M37Gbdj7SiUPEH6Rku6jthxKyF3LZwtGxOPn+d\ndGyDBxximgVClKnhp4mHpJrhaOwGtYifhu2lJbqJCDnYFHj42jGqRgBHSKcfcewNWBclcu0EbcUJ\n1gOO2TUmhCX81HGgU8NPCzd3OYpMn/P2FeJ2jo6gMS/McJKbdDsa//fqz9FLS8hundKDBIIAMn3M\nGxJ9wUE/LeJ8qoHlkVC6Nj9++MvEXFlq+Fky3czXZlnZmdmrFxeAtki6m2EisED/gsSaMErWGqDb\n1/iAc5iCxN81/hEuuUPPqfL5Q1/iqn2G3+t/kfKBELogU26HuKqcpSIFEAWL2xwnRJmX+QZXOEfe\nSCB0LGrXQmiJDke+cBm3p0m5HkUoyTgUE3ewhZ8axKBsBNmShnCZTVLNHbrfdNMfkejOOskTI0GW\nV/jTvexJVAwcdGsetndHWS9MIA7qJAa2STu28Q5UCT21gL6r0jY8mHkb60Gb5MF1DgTmMJGY88/w\nwHeQmJAnzTZRKc/w5AopfZdYq4zhdCCINrZfQFdUFpjmLZ7BgcEEy0yzQJ+9jk8nHa5op4H/63HL\nd599PlI8dsN+LvwaJ45u4PK0uGsf5cr0BVKxHbqmk7IaYiY6x1Hu4KPOmzxLliQv8w3yxMgwgEqP\n7dwI2W4SOdHDozYIRmuEPpdj1F5E63W5vXiajl9FTvTovOOh53NBKcn1wjlG3KvMeObZIk2cve3/\nB5xj2ZhgvjVDUw8Qlks8HXiDVXGMntvJywe/yvXGWZaq06SObXBJeZvj3GZtcpTL7Se5zxFORq9j\naA4yVopldYwtBuj1VdbWO/QXDiGPdDBzKnZbAgnm3j9K3h0ndjFDWt0mXinw9rUXGJ+4wYWJyzQV\nN1khwSJTLDLFfGOWB+XjtHp+eAQ7DzSkl3sIkzYeV4sEu3hpcI8j7JKkG1YQJw3sM32qjgDXemcZ\nUdZwudokJzaYd07ym/xtNDrQd9Au+9i4kmZ6Yo6j47eI/nQWl6tNjNyHg5+iNPBxzvEBPhoMscmx\n0A3aDpVHroNIfgOno4tLaBOgyrhyh+nYIgv2FMvyJNWf85M9MML9vo1LanPevMKYucbvOX6Kt8VL\nxMmxxiglOcJvuv4Gz66/zUh/ncpBN35PmTFW2WCYk9xkhHVauPDQxETibS4R4ofrdNxnn/8aeeyG\nrTtUdJfCAekhFSnAQ/UgiWCGSjVIvhCjYgXZIcUucW4ZJ9BReM7xBstMsNkZxlXo0TI8uJU2MWGH\ndt1L0wgQGiswIGdwtnpk9BSFQpTuHRWjrWK7BbAUZMFNVQyQtZOs1iYpNuL42m22zBF2lEF0v4Sl\nq1j23qCnBX0apW/wt5TfwVJkdElhOj5H0rGN3pVp11zIfoOgp4RZdeDptxgNLZPNpGkZHgQFnPZl\nhtwPIWAy1z9KoZUAA0qbEbpOBesJizTbJMRdpp2P8Mk1suUBtt8dZtU9ztLQJJWEn3x7gFIjtjf7\npgbGhoLw3T47mxbirMCgc4uYJ0fAV6aLE7erRTy6S3e6SL3rJ9NMQ18k5Crh8PXI21F2+kkGpW1y\nriTZUJqIWSIrJjE6p6hshuh6NNZCk/i0BoJss02aSXGREBXq+JhwLtKSXKzLQ/iUGmllmwF2aFIm\nJubJuAYQTBMx0kd7TmfAv8sQmxSIUhCipIVt1hmhgRcXbTQ6mKLIkjLGlGOJlqKxEJogJ8QpEMVH\njQhFwpSwEYhSpIafbQZpN70/UHv77PNXjcdu2O/0nuZe6SV+If5r6JKCgI0NdHY87H4wxPsvPMFN\n93GKdpRCO0qSLEV/hBZuStUoC7eSjB9eYDZ1h0PCA97a+BhL1UnOHn4Xj9zEdgsMnlpF/x0HtS+P\nwy/aSId1pO0uyeAOqqPHljlEcSvB+to093dOYXcFpMEe6nNNepZAQQrxhvU8hXaEw805Thl36YQ0\nZH+HQzzkA/sc/7r+18m/mSIymSN+JsO9a8eZiixwzv0e67dnyDaG0ZJtno3f4wsnbqPbCr8h/QIF\nO/HnoXWGoFA2QhSsKJFggU8886csMM2Xbv4US790kO6QC+EzJuKlHjhFJPvDGKwYMGFjfUmmFEtQ\n+ukEdxJnmBl+yCd8f4KESVQu0FeXqMVWWa5P0dnys22PUvTESQ5v0OsrOPp9plyLCGGLqtvHQf8d\nylaId9YuYvyqB2tE5t4vtxgYyOCXy5QIE8eHgUKOOCe4hSDbvOW7xIi4zqzwkAmWKVAB4Kp1jqye\noC/IBKYKPCN9j/Nc4bf5m3wgnaMnqdTxEabEQeYIUqGHilPoMjc2xRaDfJNP7U0rpM4oq2RJ/nmY\nQpptFHQELK4Wzj9u6e6zz0eOx27YSXWbscht7jkOodHhCS4zxiqNwYeMutbwROps1od5sHuS3m0V\nvAWUF3Vk0SAczDN+epl8OcGNGxdYUmZx+HocnrzFAXWOLAk2GMZJD3VWh5cBl4DPquFR88xKD7ER\nyFgp5JpJxJ1j6mNz1E0/AVeFo+5bvNF8kaXCNNk7Q4TH8nR9Kr9Q+Gd0NRnR30PGZD07Tmk5Tt9y\nUOmHaHdUuqMO1sxRmltezIM2Z5V3OOW8SW6rzQJHWGaCXRJ7V9gDHIH+gkTjf3RR/mKQtRfHuMcR\nqgSoEMBEwjVTx/+xMuFogbSUIRHKoaPgj9XwpJp8tfuTrPbGQQIhaFD1e7jDMSpmkFbXS61eZULv\n8aznDXzDTe6aR6nIAU5It5gvHWSlOsW7/ks0dS9mX6Pu8aMqPSYGlun+A42qHqXaCPPN4isM91dJ\n+zfIkSBKgSPco42LvBAlJJbwCzUMHMxxkGUUNqtn2L2bJpAqczh9jx+vfgPJabDqHsVJl0mWeJL3\n0Ogwzwxv8gyjrGMiscA0CjoVghjIpMiQJEuMHBGK2XCwSwAAGj9JREFUNPHwh/wEI2wQpMIM87Sd\nAeYft3j32ecjxuM3bDnLYdddmngJU2KUNYbYpOQL0/WpCNhksmma637IgyTYeGiSJAuSQN+l0tz1\nsbsaI7PkJn0+j+9YjVxhgM2NNJv5NMFIE0N1oD3ZpCeqoAtYDZnmkh/ZY6DEdQTVwu+pcmD8ASYy\nYUrM8pA7u2d5tKbSsFSSI9v0NYnXtWcZlVeY4SHCn83jlYEgdHQXnTUnNMHSREyXSGigREAtY/Vs\ndmtJ1MwESlJnJL6K3RPYejBCYKJMcLxA6OouVtXBdnEIIWgSkYrEg3mkjwm0T2lIYZOAq4ZrrQWr\nIMzY+GNVhkPrJJ/fprAZodH2I6p9moKbpcwMzaoH2xYRLAdhocS0Mk9UKZDtx2jZThRBJy3tYMkO\nykIAWeqjCRUqRhBNbuP2tRh9eo2d0iCVbJCMMICbOuMsYuCgSoAt0hgotPCQFLKk2Mb94XCmrYaO\nsX2Qju4iLW4Ql3eRMTA+rOsIUsaBQcUM0Sr56Do0+kEZhR7VbojFxgFoga2CO9lCsGxadQ+72w56\nfjdNn5vrzjOsd8dJWRl8vgpJ986+Ye/zI8djN+w4eY7SwEkXjQ5uWkQpUCVAhgFctOi2nLANpEEZ\n0QkLJY7SQWwJfHX1C3T7GlTq8C9W2CkPkFEvcaX9NPbvtrBf19m6OInvp2oEX85RqkSo7AaorA2R\n/fonSExuM/Zji5CycUodEuwyzCZeGhg44KENG8BTYLsFBM1CG20wLi1yhmsEqVBOhlj2jZN3pNA3\nnHBFgmUYOr/JufPvURJCrLQneK3wcaz5ryLfSPJ3Xvnf2Dw+yPu1p/jSP/kZxv7uEqc/eYXTz1/j\nSw9+hgdzR3jm9Hd5RnuT8GiJP/inP8n17Qvk1waIThW4860hNn5jHH4FDl26w7nBdwmez5PSNpj/\nzmHEvkmv5mRnPow9B4lYhrh3mUGth4vWn99o2rhYYpJTkZuci1zmA85hoGCaEnfrR7CECGnPNh/j\nNfzuGnMDM8Q8u4SVAiIWXhrskOKrfIaT3GKADCNscIBHmEjc5RiF7TrtuSHcz1fxBOqUxBD/MPTL\nnBeu8BTv0sbFNmnu6sf44N5FhgNrfOrU13HSZac2zPz8EViDWDTLgU/eYd0Y5f7aUXpf8cEREGZN\nhHiPXC7Fij7D0OwyR313Hrd099nnI8djN2wvdVREKgQpEcaBwQ4pRCwu2u/wtcrneGAcgzQwD2U9\nxLWjZwgIVTyuOs+PfJu72ZNs9uPQj2F/x4m9Y8K0jPt8H+3lBkbcwmw6qP5eDMPphLAELrBWRCqX\nNRa/E6L1GQXHiT4eWjxklhLhvbit9eG9sfUG5KwUhqwyFlghkxnkDytfRAn1kIIGCTVLK+3GKgdR\nRYNzn3oP53SLOeEALdz0FYmp8AK5ySI7Uyf4p5u/RGvNRbPuYeCXNqgfcXPVPsuSNclia4ZeQ6Fg\nRakSQLJMlluTFI0oPVNlIz/OwbMPeXHoW4SOVOiGFLJmnPXtCbLNQRgSMGsqomQiT7UxsyoNwYvV\nH2DePEBNChCkQlLK4rANCkKU642z9Jt7M0Di3gxD7lU+6f4Wa9YouW6cmJIn4ijScrm51zxOXk6S\n9GUwkKn0QpRrCW7Nn2W+3AZVwHlYJ5rOIdPnQvIyP3b6FoKnz5xwkAwD/ITwFY5wlxgFlpgkYw+w\nKQ8TPFggouRom27e37nI/JtDCF9Z4cAX8wwdzRMW8mz3BunJTswpEe9EDU+6hqq1qDyMYxVktMk2\nhvOxS3effT5yPHbV+6kh4SXDAIVKjG7ZheUXOOB+xHH1FqVehGwpuRfU2oKqHuR2+RTj3kWSaoaZ\n8EM2l0fY0geQL7qx1h2Y8zZoIEZFpKCMKdj0sgr6ioY23UIbbNP3lOmYXcyqSE+SsSoCzU0vq+uT\nPArPkFH3mlpqzRCS1EdVO7TbbtiB6G6OTH2QXH8At7fOuLVEiDwO20AQbGR3n9SxLWpRH2udcYJK\nCUfXgLJIJFBAihm8sfoxeAQ+f4X051ZpSy62jEEWetP4tBYRCmT7SR70D+Fv1di6M4ylCvgDVerd\nIPaYQPLcNoNskSPOuj5MMRej1gpCGKyeA4ep40sXqccie12NtT65dpIqQcLuIi6zg2RZiIpNwQrT\nNP0o6LisNmGhxLC6SbPrYa03Sk32Myhv8ZTwLnIbWpYbwbbZrQ6w2x1AxKbe81MphGlXPIwPLKGn\nZXQUvL42Q8O7+MUaK9Y4VctPStxGEiw2GKaBj3IjTLY+wHBknT4SS6VpMu0UfUskIW8wMbROKNWj\navqRBBPN36F7QOTA4APGgouIWNx3n6DZ9HLWuIHelx63dPfZ5yPHYzfsEBUEUqwwzs3Fs2y8OwHH\n4dmp10ilt9CdAsKSgf2PVPhFqE8GmF84gjrZwxVr46EFj0Du2Hj/mU7nLZXOOwrI0PxDP60lH3YM\nOCLgeFIn8dw2IwOrtOYesj5ewjwtMPS5Git3+6y+PsnWlWHMpySshIRdE7B9AtorLeKf3aaUjdOY\nC3L7+hmsoxKuM00mBuaJq1loihiLLoy6ihHts+kYpNoOUatGOB29TmPLxweXn+JE+7dJ9ueYax2H\nLpiaRBcNRdDR6FDr+Tk8dYeoWOBbzU+xK8VRCzq134swdHGd+Gcz3M+dZF6YoYnKCOu4aWHZAjSF\nvSCPDxOZ3I42Q64t1gZcBM0KE+0HZAuf4FHvKJ6xMt2WhtrXGQ8vMuhbR/X2iFEgJJTw0qCLk5bl\npmF4ece+yBNc5qx4lbPBq2RI8YF1jhsLF8gKSRKnN3GF23SSXla/NsVCf4oCATq4WOACWzzBU7zL\nbf0Yq/0xrrrOkhdirDPCMJt0Nj20HgbpXcqxbEyTXxngyQNvcfin8jQ/6yLlqlCwYrzTe5qIs0gq\nuUkmMMDLzq/zIt+mQog/OKFT6Mb5+fav853uC49buvvs85HjsRv2TU5gMkOeGC3DTbfhhDrcu36M\n7qtO8s8kUEZ19BcUgkeKEIPKdoSNy+PUHCHmpppsp4ewU2AFROwRAanfRxtqYAgqvS0XBIAEWCmR\nhtPDWm+MdnOchhLAut9j60GQzrQD0y1hTTg5ePgeykiXTX2I5o0AOgqlXgTCFs6JJt2cGxsRuyxg\npGQsQURs2NhvCyAK6KMqC187hDEiYR0zWZVGiMULvHj+G2gfrBPs5GAXqIPq6RG18+QWBqjUYpgx\nJzvONPWGn+6bHswBCalv0d92UHwnRltw0zuo0uspZKrD+FINVFePoFzmuenvsqOnWVIm8dBgRFvj\nuHCDd0cNMnfCzP+bAZpmmKGTG/y3wm+x6hqjYXk5L77PjpBiUZhig0GClJn68AfFnqJiiwJ1yccb\nnRe43T7NAe8DDEVmUZzEGBGQLJ2G4cHlaCPHdDgDRX+ERHebn1F/ly8LFj5hglkeIDpMrJ7MrQdn\nscIgxi0WiwcpE0YdbXPB+R6S22JuYpa+TyQhFXhBfIslYZSm4EFT2njEBi6hg9dVxxRFHnGQBxzi\nkXGAnunkffcZHEr3cUt3n30+cjx2w76XP4bVO4ThcODAgA9T67dzQ+ysD6LN1hEDwDGQNR16gAXF\nezGKegw0oA0OVw+wkQd0RKeNI6xjTjpg3ASxgxgUEIZEuqpKs+KjXUyB3w1Zgc7dKARV1Nku3nSd\n0UPLKOkuDVz0aw46NTd9U8ETquFR67QaBt2ehoiJgE2r6MFYVulnZYLJMj53jdyDJIYl4pxsInos\nfKEaI6E12nfruIw21MAR0AnEKowJaxSLA1CVmIov0dVdFEpxjHUnZknG0IE81LJBao0gRG1wC9Sa\nIYpqHC3awaW1GEmtIOs6W50Ug64Nhhxr+KkxEl2h6RC4t5LCvhdiMFwmnc7g99YwZJkDPKKaCVIt\nh1jzTZAI5tC9Ci7apOQdWrKb+xxm0xrikX6YHSOJ2O9T7oRp111YFYH2wwBuuYHm7TA2u4xfK3Gi\nfZsfL/8pN3uzuIV1plhCkKAgxrnWGkByG7isDpneMA23B0+4gSoYeJU66dQGDTwouk7IrNAyD1Ft\nBhEyIv2kA7PfQF3YZtk1yFZkmJWBMTJWCoets+gcJy1tP27p7rPPR47Hbtjbl4fofu48T0bepKe4\nWBOn4FXABHtSoFP17pV0FQVKlxMQAjshQJU989aBPwaxZ+E80kMabtFXVCqvRTEsBU724I/WkM8o\naJMBFK2LvSbtVX6MA0MaRFSIioQGdjh08jaa2vpwJkUX98kaqtXG56zjkRooTh3jzC65bgLDkgmq\nZXa/n2bt7UmMWYUnTn2f05Mf8BV+iq36EPIdkRfPvwaaxftcIMm7yIIGEnierZIaW+eofIfl2AE0\nf5f/PvHP+Xrus7xVeQFzTITb7CXq7AAdwAB2BQiCUVNYdsxQM/3URz20cZOtptlZG2VyaolqMMgf\n81lOcYNDUys8eCWIWXUz97VZ/s7gP+fzo/+WU/6rXOc0b73+PB+8+STGKQfXn7RoHXdzlqtYiPSR\niZHD7WrRUt2sd0ap5MMYay6s74rYNwXsVYGtfpTpZx/yhX/xdc66rzGbeUT87QreYpMIeVR6OOmQ\ncGe5eOINstIAGSlJMFVA0HWaHQ+/V/nZvci16BqHeEDV4eNXfP+ATWOI/FySxr8OUf3pIGJjm94v\nlrk7eZHAxwKM/ncLeL11PHaTmJhHR3nc0t1nn48cj92wxWELBJNHrx2idjmEfL9P8vktHKM9uhGN\nciiGLYP3+SpxMYfgtMn5YhiqQq/mpOvwYNcE+lsOGq8FUc+3sdttzO/OY4cTkAzDcBzTluguqRgJ\nFcsrIo91Cb+whdF2Um5EkBI6gXSJSfcix/p3afbddGSNhLaLizYRocgYq9iCwNvOSwzKm8TtHGGx\nzLWJc+SVGEPRTfzJMplAEvV4C/dSk+6mxrtbz2D1BTadg4j9ASw9CRVQ5B5VIcR3d15i2xrCdEh8\ns/4KbafG1MhDunEnpXaU+mZwL7d7BrgIRIE62NsChqRgR0VEw2b+4SF0U2EkvUzFGaCBG4B788ep\nZsNY6j04LRJwVjgVu8qWnWajlcbUJDa9w3RjGgTBpzVIsIuNwHp3lLu9Y7jdTU50bnO2eoMv+z/D\nzd4Zslt+oid20Q63sKsCpZZGfmiQy1zg5NJtktt5ZKXPoLTF2f73GWxm2VUH6HadPHrvMLUhH+JR\ngwl5iZ1emrneLL2uik+podFhkyGK1SgrG9O0rrnplTT6RxwYQQW8EXo/cYJuLkl/3on9O9A7odI7\nUGY1NM4R+e7jlu4++3zkeOyGLRn30aQLrF6bpPueC7XaJfkr22gXmtTMAM11H6JskRjeJsUOhu6g\n3nQjjvSRWn2cnR7tmAezKiNmoF9xYFoCdraMFNSQh/xIT7tQ4zpypYnhk7CDFnTv4D18hnbGhiUQ\nXCZhR5ET+h2e0t9lx0zxHfGTDDvXiTlyKOhMsEwfmRucIt7MMdjexnaKyG4DdaxD1Jej1XOzvZ3G\nl6zSbTjJbg6z3J5Ea3ZwCV1yc2X85xVS3m0UuUWxE+XBzklsWQAFvl1+iQPxewzFVgCBQiPJbi1F\nsRTBPiMgPGdjdBXsjLhXm+4Fe0vE6KnUNoOoiS6J1BYt3Cj0GGeF97cusZ0fRsj8PtJP6oRCBc7G\n3+P7nUvcNo7h12pUoyHEaRPneAdfoIaLFjX8FMwYxV6UpuIm0inxSv1V1gODVJQwfUXh1LlrBAeL\nNGQPpWaYXkOll9EwtxWoCqAJbK01ebrfY7sywo4/TU5PsLg6g+kSGGSNo9xFo8eifQBDB8HYqxHf\nIUW+m6ReCNB/JCNqFp6X6jgSbTRZx/fXofp+l9odlcy1IVyBFt7hBmvBUab/0ttmCj+Ca/+orfuX\nvfZ/yGM3bGt1Hk1oI8oWRECI2DhcBg76iLaF0LBxKy3SbJEjQb6YpHBzAOuKSNhX4PDPXWXhlVnq\nJT8zz96n4Iuwm4vBp0/hOtzBf3YHv1FnQN4hrBbJOeI0JQ/ziw8or8apfz0AfyBgvuJk4FKRz5x8\nFbfZ4lH7KNerTzA4to0S0bnBKW5xAgcGCjo3b53jTx4OY49Be8NNN69y5VQYe0NA22jz1N9+E9XX\npzIS48XJbzIRWsAhGvyrxXmmhucZ+dwq77susFid3jvesQEV8AnU+366aBziPmcOXKeSDvLHH/sM\nuk9B1XUKvzmAvuwEEUhD8bsxug81Tv+9K4jH+mwyyCwPOcAjDvCIDc8ku0oCu3oX71QRRWrTEl0E\nXBVS9g410U/fI6Mmu4xMLNMOKlzhPA76xLUczzle593uk1TkAELCZFRd5fTQVVKRTX7W+H2irQK3\n/YdIu7aJZYsEvt3CPm9RHAqSuFrk/YUQS/3/lc3GBLZmIUQM1L/WBHWva/VZ601CzjI3Aicp5FJU\nu35WGCdAlWh0F+m8Tn3Kjyr2SEV36MsSE8Iyn3F/jTciz/HumUus3Z9k7MASI6llOrKTDzgL/M7j\nlu//Bz+KJvKjtu5f9tr/IY/dsJ1Wl+J2EqOiEJveZeDEFuVqBGXNi2u4wUB8C6OksHp5mmo0SGNB\nRv9Xu6BFME9JWJqAPQw9SWV3OYU82iPkr5E7NIguO2iuSfQ9Tvq2SqkRp77ipZdR0JdUrKoD8ZSO\nU+6SOLKLPWbyqvtFTts3cKl1zjnf44h2B40WOg4ilHBgsMwEOw/i5L4Xgucd8KALtxs07+lQdSMJ\nKmqjh+roIeVMUge3mFXvE7DqfKtbYDCX4aveHydvxjB2FezL7M0TcQMOqC2H2EqP4D7Roq9t0ldk\nbM1mSFlnsrdM7tIAnaMuOpLGqneK5oAbfVAiPFrAdtmsWKOsZqeomBGWA5NMDCzgLdZ4syTRveZB\nitukJ3cY/n/aO5fYOq46Dn+/+/T1vbEd145fcWLLjfNo6tCoVQOUhpakChVkU6FS1KorxAKJwgJI\nu2eDhACpYsMCQQVRRUEhkRDEfQKtVOI2MUnsxEmTxnb8iONHYju27/X1n8VMRUBZsMjMeOrzSSN5\nzkjzm3P8+X+vz5k7N3WFLnrpZwfl5jRUi9mqSpKpZaq5QScD1CUmSabL1Ns492YuMaIGtpUHqEgW\nOVuzjRsLBa5c3szrv9/HI4+9Ta72FHW7pzi/aQuzhQLtXYMsZRdYziRZakjSnB9lU+pjKu5Z4AY1\nzJcL/OnmU1z6ZyuzbydYnhhlpT3L9KP1PHDfKRpqx1goVFCuSDFPnunUetZxk9zUIt0DB6hpm+Lp\nlsNkl6D56jA1H02xUJcjU7fEb4OW1+FYZQResLMrRSZGmmAG6vaM0/nVPt75636SlNnSPklj0zDj\n0y30vf8Zbw73zHU4OgwHcyxvSDGXKFCqSrOYrORKTwdtlRdYv2Oa683NLF7OsTSUg0YYW97o3Ur3\nOvDhCgxWkFg0Mo/fIvWlZTZlL1FMJniVp6hmknom2Msb7OQ0c+RJU6KVIVIs83e+wI3BPJwqwa4U\nXFmEnmnomYNUPXQU0JKhBUNDRn5xjnomaLYx1i/NcM/VGf7W9EXS+QWYSMAJoAnv9sMSzFkVKx0J\nkjtKlCrSZChSIk0LIzxY1cPEk/Ve8SrVMj7azPxKBYl8kXz1HGUSYOL86Hbmi3lIlnhpw4+49+ZF\nuq+luPVeFYmdCTa2D9ORukiRLFXMUtlwC2H8g8+TpcgWLvAEx0lS5rrq2Jk9Q5kEo9bIzrlzrFuZ\nZyazjo9y7fSMPcyR33wNNq+Q2b9E+tEi/Wxlgjrmu3KUs71syIyz2JBlG/108S9qmOZj2vmg/BCv\n3vwGk2/m4cdTwCA8VMtCqpXNTYPcX9vLCglyqQWGaOUd9tLCCJMzGzh84hm+VfkyB7ceY1d9P5l3\ni9ALdAJbgzbX4Vh9yMyCO7kU3MkdDsDMFHam89oRBndyO9CC7XA4HI67RyLqC3A4HA7H/4cr2A6H\nwxETXMF2OByOmBBYwZZ0QNI5SRck/TDAnFZJb0k6K+mMpO/47bWSuiUNSDouqSbAa0hKOinpWFjZ\nkmokvSapX1KfpIfD6rOkF/3xPi3pd5KyYY531KwVt6Pw2s+JxO04eB1IwZaUBF4GDgA7gGckbQ8i\nC+/pG98zs/uAPcC3/axDQLeZdQJv+PtB8QLQB598n1go2T8H/mxm24Eu4FwYuZLagG8Cu83sfiAJ\nfD2M7NXAGnM7Cq8hArdj47WZ3fUN+Czwl9v2DwGHgsi6Q/YRYB/eL7nBb2sEzgWUtxHv7u/HgGN+\nW6DZQDVw6Q7tgfcZqAXOA+vx7uM/BuwPa7yj3taK21F47Z83Erfj4nVQUyItwNBt+8N+W6D4r5IP\nAO/jDfK4f2gcaAgo9qfA9/Ee3/QJQWe3AxOSfiXpQ0m/lJQPIRczmwJ+AgwCI8CMmXWHkb1KWCtu\nR+E1ROR2XLwOqmCHfnO3pALwB+AFM5v9r4vxXh7v+jVJ+gpwzcxOAnf8AEdA2SlgN/ALM9sNzPM/\n/6oF2OcO4LtAG9AMFCQ9G0b2KuFT73aEXkNEbsfF66AK9lWg9bb9Vrx3IoEgKY0n9CtmdsRvHpfU\n6B9vAq4FEP054KCky8Bh4HFJr4SQPQwMm9kJf/81PMnHQujzg8B7ZjZpZsvAH/GmCcLIXg2sBbej\n8hqiczsWXgdVsHuALZLaJGWAp4GjQQRJEt5j2/rM7Ge3HToKPO///Dze/N9dxcxeMrNWM2vHW6B4\n08yeCzrbzMaAIUmdftM+4CzevFugfcab09sjKeeP/T68hakwslcDn3q3o/Laz47K7Xh4HdTkOPBl\nvEn8i8CLAeY8gjfPdgrv+1tO4q3g1+ItmgwAx4GaIBcDgL3AUfvPAkag2cAuvMdK9eK9G6gOq8/A\nD/D+iE4DvwbSYY93lNtacjtsr/2cSNyOg9fuWSIOh8MRE9wnHR0OhyMmuILtcDgcMcEVbIfD4YgJ\nrmA7HA5HTHAF2+FwOGKCK9gOh8MRE1zBdjgcjpjwb9rN8KSDkLULAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig = plt.subplot(121)\n", + "fig.imshow(flux.mean)\n", + "fig2 = plt.subplot(122)\n", + "fig2.imshow(fission.mean)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's say we want to look at the distribution of relative errors of our tally bins for flux. First we create a new variable called ``relative_error`` and set it to the ratio of the standard deviation and the mean, being careful not to divide by zero in case some bins were never scored to." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Determine relative error\n", + "relative_error = np.zeros_like(flux.std_dev)\n", + "nonzero = flux.mean > 0\n", + "relative_error[nonzero] = flux.std_dev[nonzero] / flux.mean[nonzero]\n", + "\n", + "# distribution of relative errors\n", + "ret = plt.hist(relative_error[nonzero], bins=50)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Source Sites" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Source sites can be accessed from the ``source`` property. As shown below, the source sites are represented as a numpy array with a structured datatype." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ (1.0, [0.08159183470384083, 0.37187405724079425, -0.4569273259677805], [-0.5991379733562734, 0.6213299732428319, -0.5049581697849825], 1.4308796774550836),\n", + " (1.0, [0.08159183470384083, 0.37187405724079425, -0.4569273259677805], [0.6943502674814661, -0.18996972225593808, 0.694110373553384], 1.8499326750790277),\n", + " (1.0, [-0.2283457014858208, -0.3149356437736135, -0.6287339985223156], [0.22841158666373973, -0.9428738529578353, 0.24252225565130936], 2.8993105331976654),\n", + " ...,\n", + " (1.0, [-0.20844939420957254, 0.043779246455180054, -0.22209004880139005], [0.871391386295745, 0.3866181159860615, 0.30199914615933615], 2.2329770939373517),\n", + " (1.0, [-0.20844939420957254, 0.043779246455180054, -0.22209004880139005], [-0.4649777417907873, 0.38973845929247963, 0.7949211489119309], 1.6836109244016622),\n", + " (1.0, [-0.20844939420957254, 0.043779246455180054, -0.22209004880139005], [-0.4649777417907873, 0.38973845929247963, 0.7949211489119309], 1.6836109244016622)], \n", + " dtype=[('wgt', '" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAY4AAAEUCAYAAAA8+dFZAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAGeRJREFUeJzt3X20ZFV55/Hvz8YXUBL6Jo4O0IojELtdOgENsGJmxBdc\npFVQOhFoEpUZBY0dXyaZMK6oMOOsTHSiImHJ4BIVDQ0qEAdHEF9BaR0UQVT6grAcMrysIcRu3yAq\nL8/8UXWhKG7VrXO7zq26t7+ftWp1nX32OfXUprof9tn77JOqQpKkUT1i0gFIkpYXE4ckqREThySp\nEROHJKkRE4ckqREThySpkVYTR5LDk1yf5MYkJ82z/2lJvpHkF0n+rMmxkqTJSFv3cSRZBdwAvBC4\nDfgWcGxVzfbUeTzwZOBlwPaqes+ox0qSJqPNHsdBwE1VdXNV3QOcBxzZW6Gq7qyqq4B7mh4rSZqM\nNhPHXsAtPdu3dsvaPlaS1KI2E8eOXANzHRRJmlK7tHju24A1Pdtr6PQcxnZsEhOMJC1CVWWxx7bZ\n47gK2C/JPkkeBRwNXDSgbv8XGPnYqmr9dfLJJ7d+3EJ1B+1vUt5f1r991FFHTW1bNjl2lHq25/ja\nc9j+UdptlLKlaMsdac+l+Lu+I+3Zv72jWutxVNW9STYBlwKrgLOqajbJid39ZyZ5Ip0ZU78G3J/k\nTcC6qvr5fMe2FetCDj300NaPW6juoP1NyvvLFvu9dsSOfOaox45Sz/YcX3sO2z9KuzUpa9s0/10f\ntG8Sv83WpuMuhSS1nOOfNhs2bOCCCy6YdBgrhu05PrbleCWhpvRSlZaZtWvXTjqEFcX2HB/bcrqY\nOPSAdevWTTqEFcX2HB/bcrqYOCRJjZg4JEmNmDgkSY2YOCRJjZg4JEmNmDgkSY2YOCRJjZg4JEmN\nmDgkSY2YOCRJjZg4JK14MzOQzP+amZl0dMtPmw9ykqSpsH07DFpIO4teI3bnZY9DktSIiUOS1IiJ\nQ5LUiIlDktSIiUPSsuHsqOngrCpJy4azo6aDPQ5JUiMmDklSIyYOSVIjJg5JUiMmDklSIyYOSZqH\nU38HczquJM3Dqb+D2eOQJDVi4pAkNWLikCQ1YuKQJDVi4pAkNWLikCQ1YuKQJDVi4pAkNWLikCQ1\n0mriSHJ4kuuT3JjkpAF1TuvuvzbJAT3lb01yXZLvJdmc5NFtxipJGk1riSPJKuB04HBgHXBskrV9\n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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Create log-spaced energy bins from 1 keV to 100 MeV\n", + "energy_bins = np.logspace(-3,1)\n", + "\n", + "# Calculate pdf for source energies\n", + "probability, bin_edges = np.histogram(sp.source['E'], energy_bins, density=True)\n", + "\n", + "# Make sure integrating the PDF gives us unity\n", + "print(sum(probability*np.diff(energy_bins)))\n", + "\n", + "# Plot source energy PDF\n", + "plt.semilogx(energy_bins[:-1], probability*np.diff(energy_bins), linestyle='steps')\n", + "plt.xlabel('Energy (MeV)')\n", + "plt.ylabel('Probability/MeV')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's also look at the spatial distribution of the sites. To make the plot a little more interesting, we can also include the direction of the particle emitted from the source and color each source by the logarithm of its energy." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(-0.5, 0.5)" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.quiver(sp.source['xyz'][:,0], sp.source['xyz'][:,1],\n", + " sp.source['uvw'][:,0], sp.source['uvw'][:,1],\n", + " np.log(sp.source['E']), cmap='jet', scale=20.0)\n", + "plt.colorbar()\n", + "plt.xlim((-0.5,0.5))\n", + "plt.ylim((-0.5,0.5))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.9" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/docs/source/pythonapi/examples/post-processing.rst b/docs/source/pythonapi/examples/post-processing.rst new file mode 100644 index 000000000..b488d15ff --- /dev/null +++ b/docs/source/pythonapi/examples/post-processing.rst @@ -0,0 +1,13 @@ +.. _notebook_post_processing: + +=============== +Post Processing +=============== + +.. only:: html + + .. notebook:: post-processing.ipynb + +.. only:: latex + + IPython notebooks must be viewed in the online HTML documentation. diff --git a/docs/source/pythonapi/examples/tally-arithmetic.ipynb b/docs/source/pythonapi/examples/tally-arithmetic.ipynb index 2b1205204..2f32f3d9a 100644 --- a/docs/source/pythonapi/examples/tally-arithmetic.ipynb +++ b/docs/source/pythonapi/examples/tally-arithmetic.ipynb @@ -358,7 +358,7 @@ "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAAAFzUkdC\nAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAxQTFRF\n////chIS6YCRTb/E6kGE+wAAAAFiS0dEAIgFHUgAAAAJcEhZcwAAAEgAAABIAEbJaz4AAALKSURB\nVGje7dpLcqQwDAbgHHE2YeEj+D4cwQucBUfo+3CEXoSp8OhuhF70T4qpKXmdr21LogK2Pj7A8QmN\nP+HDhw8fPnz48Kf6VH9G+66vy+je8k19jnf8C5dXIPv86ms56lPdjvaYbyodx3ze+XLE76cXFiD4\nzPji99z0/AJ4n1lfvJ6fnl0A6x+578efMSg1wPr172/jPO5yFXM+Ef78gdblM+WPHyguP//t1/g6\npA0wfln+ho/fwgYYn19C/xwDvwHGc9OvC+hs37DTrwuwfWanXxdQTC9Mvyygs3wjTL8uwPJpn/tN\nDbSGz7T0SBEWw4vLXzbQ6b6RoveIoO6TvPxlA63qs7z8ZQPF9F+SH22vbX8OQKf5Rtv+EgDNJ3X5\n8wZaxWd1+fMGiuFvir8bvjp8J/tGy/6jAmRvhW8fwL3vVT+o3grfPoB7r/IpALI3tz8FoJN84/NV\n873hB8UnM3xzANtf8nb4dwmg3grfFEDJO8JPE0i9Ff4pAYL3pI8mkHor/HMCeO9JH00g9SafEsh7\nT/ppARBvp48UwJnelT5SACd7O31TAlnvKx9SQCd7B58KgPO+8iMFuPWe9E8F8BveWX7bAjzX9y4/\n/Jve+fhsH6Ctv7n8PTzjvY/v9gEOHz58+PBX+6v/f/wPvnd54f3j6venE/yl769Xv7+j3x/o98/V\n32/o9+fl389Xnx+g5x/o+Qt6/oOeP6HnX+j5G3z+h54/ouefV5/foufP6Pk3ev4On/+j9w/o/Qd6\n/4Le/6D3T/D9V67Y/ZsVQBq+s+8f0ftP+P41axXguP9NWgDuu/Cdfv+N3r/D9/9TAID+A7T/Ae2/\ngPs/0P4TtP8F7r9J3AIO9P+g/Udw/9Oygbf7r9D+L7j/DO1/Q/vv4P4/tP8Q7n9E+y/h/k+0/xTu\nf4X7b+H+X7T/+BPuf3aM8OHDhw8fPnz4w/4vzcvgeY10sY0AAAAldEVYdGRhdGU6Y3JlYXRlADIw\nMTUtMDgtMDZUMTY6NDM6MTMrMDc6MDBtUQj+AAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE1LTA4LTA2\nVDE2OjQzOjEzKzA3OjAwHAywQgAAAABJRU5ErkJggg==\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///9yEhLpgJFNv8Tq\nQYT7AAAAAWJLR0QAiAUdSAAAAAd0SU1FB98JFQMZGiFPL70AAALKSURBVGje7dpLcqQwDAbgHHE2\nYeEj+D4cwQucBUfo+3CEXoSp8OhuhF70T4qpKXmdr21LogK2Pj7A8QmNP+HDhw8fPnz48Kf6VH9G\n+66vy+je8k19jnf8C5dXIPv86ms56lPdjvaYbyodx3ze+XLE76cXFiD4zPji99z0/AJ4n1lfvJ6f\nnl0A6x+578efMSg1wPr172/jPO5yFXM+Ef78gdblM+WPHyguP//t1/g6pA0wfln+ho/fwgYYn19C\n/xwDvwHGc9OvC+hs37DTrwuwfWanXxdQTC9Mvyygs3wjTL8uwPJpn/tNDbSGz7T0SBEWw4vLXzbQ\n6b6RoveIoO6TvPxlA63qs7z8ZQPF9F+SH22vbX8OQKf5Rtv+EgDNJ3X58wZaxWd1+fMGiuFvir8b\nvjp8J/tGy/6jAmRvhW8fwL3vVT+o3grfPoB7r/IpALI3tz8FoJN84/NV873hB8UnM3xzANtf8nb4\ndwmg3grfFEDJO8JPE0i9Ff4pAYL3pI8mkHor/HMCeO9JH00g9SafEsh7T/ppARBvp48UwJnelT5S\nACd7O31TAlnvKx9SQCd7B58KgPO+8iMFuPWe9E8F8BveWX7bAjzX9y4//Jve+fhsH6Ctv7n8PTzj\nvY/v9gEOHz58+PBX+6v/f/wPvnd54f3j6venE/yl769Xv7+j3x/o98/V32/o9+fl389Xnx+g5x/o\n+Qt6/oOeP6HnX+j5G3z+h54/ouefV5/foufP6Pk3ev4On/+j9w/o/Qd6/4Le/6D3T/D9V67Y/ZsV\nQBq+s+8f0ftP+P41axXguP9NWgDuu/Cdfv+N3r/D9/9TAID+A7T/Ae2/gPs/0P4TtP8F7r9J3AIO\n9P+g/Udw/9Oygbf7r9D+L7j/DO1/Q/vv4P4/tP8Q7n9E+y/h/k+0/xTuf4X7b+H+X7T/+BPuf3aM\n8OHDhw8fPnz4w/4vzcvgeY10sY0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMDktMjFUMTA6MDg6\nNTcrMDc6MDALr51VAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE1LTA5LTIxVDEwOjA4OjU3KzA3OjAw\nevIl6QAAAABJRU5ErkJggg==\n", "text/plain": [ "" ] @@ -569,7 +569,8 @@ " Copyright: 2011-2015 Massachusetts Institute of Technology\n", " License: http://mit-crpg.github.io/openmc/license.html\n", " Version: 0.7.0\n", - " Date/Time: 2015-08-15 10:52:49\n", + " Git SHA1: b167d70c877c516deca785801b9fa6f53fb0985b\n", + " Date/Time: 2015-09-21 10:25:26\n", "\n", " ===========================================================================\n", " ========================> INITIALIZATION <=========================\n", @@ -595,26 +596,26 @@ "\n", " Bat./Gen. k Average k \n", " ========= ======== ==================== \n", - " 1/1 1.00465 \n", - " 2/1 1.05814 \n", - " 3/1 1.05114 \n", - " 4/1 1.09189 \n", - " 5/1 1.03731 \n", - " 6/1 1.03510 \n", - " 7/1 1.09378 1.06444 +/- 0.02934\n", - " 8/1 1.04522 1.05803 +/- 0.01811\n", - " 9/1 1.06557 1.05992 +/- 0.01294\n", - " 10/1 1.05757 1.05945 +/- 0.01004\n", - " 11/1 1.04858 1.05764 +/- 0.00839\n", - " 12/1 1.01832 1.05202 +/- 0.00905\n", - " 13/1 1.05822 1.05279 +/- 0.00787\n", - " 14/1 1.07684 1.05547 +/- 0.00744\n", - " 15/1 1.00349 1.05027 +/- 0.00844\n", - " 16/1 1.06969 1.05203 +/- 0.00784\n", - " 17/1 1.06377 1.05301 +/- 0.00722\n", - " 18/1 1.02897 1.05116 +/- 0.00690\n", - " 19/1 1.00685 1.04800 +/- 0.00713\n", - " 20/1 1.02644 1.04656 +/- 0.00679\n", + " 1/1 1.00279 \n", + " 2/1 1.03320 \n", + " 3/1 1.04467 \n", + " 4/1 1.09693 \n", + " 5/1 1.05008 \n", + " 6/1 1.08426 \n", + " 7/1 1.05363 1.06894 +/- 0.01531\n", + " 8/1 0.97961 1.03917 +/- 0.03106\n", + " 9/1 1.06444 1.04549 +/- 0.02285\n", + " 10/1 1.08345 1.05308 +/- 0.01926\n", + " 11/1 1.06871 1.05568 +/- 0.01594\n", + " 12/1 1.03183 1.05228 +/- 0.01390\n", + " 13/1 1.04486 1.05135 +/- 0.01207\n", + " 14/1 1.06468 1.05283 +/- 0.01075\n", + " 15/1 1.04185 1.05173 +/- 0.00968\n", + " 16/1 1.01268 1.04818 +/- 0.00944\n", + " 17/1 1.04129 1.04761 +/- 0.00864\n", + " 18/1 1.01127 1.04481 +/- 0.00843\n", + " 19/1 1.03738 1.04428 +/- 0.00782\n", + " 20/1 1.04410 1.04427 +/- 0.00728\n", " Creating state point statepoint.20.h5...\n", "\n", " ===========================================================================\n", @@ -624,27 +625,27 @@ "\n", " =======================> TIMING STATISTICS <=======================\n", "\n", - " Total time for initialization = 4.4100E-01 seconds\n", - " Reading cross sections = 1.1300E-01 seconds\n", - " Total time in simulation = 1.8418E+01 seconds\n", - " Time in transport only = 1.8403E+01 seconds\n", - " Time in inactive batches = 2.1070E+00 seconds\n", - " Time in active batches = 1.6311E+01 seconds\n", - " Time synchronizing fission bank = 2.0000E-03 seconds\n", - " Sampling source sites = 2.0000E-03 seconds\n", + " Total time for initialization = 9.1800E-01 seconds\n", + " Reading cross sections = 6.5800E-01 seconds\n", + " Total time in simulation = 1.7037E+01 seconds\n", + " Time in transport only = 1.7024E+01 seconds\n", + " Time in inactive batches = 2.8600E+00 seconds\n", + " Time in active batches = 1.4177E+01 seconds\n", + " Time synchronizing fission bank = 4.0000E-03 seconds\n", + " Sampling source sites = 4.0000E-03 seconds\n", " SEND/RECV source sites = 0.0000E+00 seconds\n", " Time accumulating tallies = 0.0000E+00 seconds\n", " Total time for finalization = 1.0000E-03 seconds\n", - " Total time elapsed = 1.8861E+01 seconds\n", - " Calculation Rate (inactive) = 5932.61 neutrons/second\n", - " Calculation Rate (active) = 2299.06 neutrons/second\n", + " Total time elapsed = 1.7971E+01 seconds\n", + " Calculation Rate (inactive) = 4370.63 neutrons/second\n", + " Calculation Rate (active) = 2645.13 neutrons/second\n", "\n", " ============================> RESULTS <============================\n", "\n", - " k-effective (Collision) = 1.04599 +/- 0.00622\n", - " k-effective (Track-length) = 1.04656 +/- 0.00679\n", - " k-effective (Absorption) = 1.04614 +/- 0.00461\n", - " Combined k-effective = 1.04651 +/- 0.00368\n", + " k-effective (Collision) = 1.04044 +/- 0.00527\n", + " k-effective (Track-length) = 1.04427 +/- 0.00728\n", + " k-effective (Absorption) = 1.04794 +/- 0.00535\n", + " Combined k-effective = 1.04628 +/- 0.00467\n", " Leakage Fraction = 0.00000 +/- 0.00000\n", "\n" ] @@ -692,8 +693,7 @@ "outputs": [], "source": [ "# Load the statepoint file\n", - "sp = StatePoint('statepoint.20.h5')\n", - "sp.read_results()" + "sp = StatePoint('statepoint.20.h5')" ] }, { @@ -759,8 +759,8 @@ " 0\n", " total\n", " (nu-fission / absorption)\n", - " 1.042726\n", - " 0.008661\n", + " 1.046353\n", + " 0.00935\n", " \n", " \n", "\n", @@ -769,7 +769,7 @@ "text/plain": [ " nuclide score mean std. dev.\n", "bin \n", - "0 total (nu-fission / absorption) 1.042726 0.008661" + "0 total (nu-fission / absorption) 1.046353 0.00935" ] }, "execution_count": 26, @@ -827,17 +827,17 @@ " 0\n", " total\n", " absorption\n", - " 0.958874\n", - " 0.007146\n", + " 0.95873\n", + " 0.00774\n", " \n", " \n", "\n", "" ], "text/plain": [ - " nuclide score mean std. dev.\n", - "bin \n", - "0 total absorption 0.958874 0.007146" + " nuclide score mean std. dev.\n", + "bin \n", + "0 total absorption 0.95873 0.00774" ] }, "execution_count": 27, @@ -893,17 +893,17 @@ " 0\n", " total\n", " nu-fission\n", - " 1.09186\n", - " 0.010424\n", + " 1.091622\n", + " 0.011163\n", " \n", " \n", "\n", "" ], "text/plain": [ - " nuclide score mean std. dev.\n", - "bin \n", - "0 total nu-fission 1.09186 0.010424" + " nuclide score mean std. dev.\n", + "bin \n", + "0 total nu-fission 1.091622 0.011163" ] }, "execution_count": 28, @@ -966,8 +966,8 @@ " 10000\n", " total\n", " absorption\n", - " 0.802921\n", - " 0.006109\n", + " 0.802012\n", + " 0.006609\n", " \n", " \n", "\n", @@ -976,7 +976,7 @@ "text/plain": [ " energy [MeV] cell nuclide score mean std. dev.\n", "bin \n", - "0 0.0e+00 - 6.2e-01 10000 total absorption 0.802921 0.006109" + "0 0.0e+00 - 6.2e-01 10000 total absorption 0.802012 0.006609" ] }, "execution_count": 29, @@ -1037,8 +1037,8 @@ " 10000\n", " total\n", " (nu-fission / absorption)\n", - " 1.240421\n", - " 0.010978\n", + " 1.246604\n", + " 0.011825\n", " \n", " \n", "\n", @@ -1047,11 +1047,11 @@ "text/plain": [ " energy [MeV] cell nuclide score mean \\\n", "bin \n", - "0 0.0e+00 - 6.2e-01 10000 total (nu-fission / absorption) 1.240421 \n", + "0 0.0e+00 - 6.2e-01 10000 total (nu-fission / absorption) 1.246604 \n", "\n", " std. dev. \n", "bin \n", - "0 0.010978 " + "0 0.011825 " ] }, "execution_count": 30, @@ -1105,8 +1105,8 @@ " 0\n", " total\n", " (((absorption * nu-fission) * absorption) * (n...\n", - " 1.042726\n", - " 0.017538\n", + " 1.046353\n", + " 0.01894\n", " \n", " \n", "\n", @@ -1115,11 +1115,11 @@ "text/plain": [ " nuclide score mean \\\n", "bin \n", - "0 total (((absorption * nu-fission) * absorption) * (n... 1.042726 \n", + "0 total (((absorption * nu-fission) * absorption) * (n... 1.046353 \n", "\n", " std. dev. \n", "bin \n", - "0 0.017538 " + "0 0.01894 " ] }, "execution_count": 31, @@ -1197,7 +1197,7 @@ " (U-238 / total)\n", " (nu-fission / flux)\n", " 0.000001\n", - " 6.985151e-09\n", + " 6.859257e-09\n", " \n", " \n", " 1\n", @@ -1205,8 +1205,8 @@ " 0.0e+00 - 6.3e-07\n", " (U-238 / total)\n", " (scatter / flux)\n", - " 0.209988\n", - " 2.206753e-03\n", + " 0.209986\n", + " 1.966887e-03\n", " \n", " \n", " 2\n", @@ -1214,8 +1214,8 @@ " 0.0e+00 - 6.3e-07\n", " (U-235 / total)\n", " (nu-fission / flux)\n", - " 0.355276\n", - " 3.741612e-03\n", + " 0.355667\n", + " 3.717881e-03\n", " \n", " \n", " 3\n", @@ -1224,7 +1224,7 @@ " (U-235 / total)\n", " (scatter / flux)\n", " 0.005555\n", - " 5.842517e-05\n", + " 5.218094e-05\n", " \n", " \n", " 4\n", @@ -1232,8 +1232,8 @@ " 6.3e-07 - 2.0e+01\n", " (U-238 / total)\n", " (nu-fission / flux)\n", - " 0.007229\n", - " 5.951357e-05\n", + " 0.007165\n", + " 5.625590e-05\n", " \n", " \n", " 5\n", @@ -1241,8 +1241,8 @@ " 6.3e-07 - 2.0e+01\n", " (U-238 / total)\n", " (scatter / flux)\n", - " 0.227642\n", - " 9.496469e-04\n", + " 0.227653\n", + " 8.544314e-04\n", " \n", " \n", " 6\n", @@ -1250,8 +1250,8 @@ " 6.3e-07 - 2.0e+01\n", " (U-235 / total)\n", " (nu-fission / flux)\n", - " 0.008076\n", - " 5.699123e-05\n", + " 0.008089\n", + " 5.080374e-05\n", " \n", " \n", " 7\n", @@ -1259,8 +1259,8 @@ " 6.3e-07 - 2.0e+01\n", " (U-235 / total)\n", " (scatter / flux)\n", - " 0.003369\n", - " 1.369755e-05\n", + " 0.003370\n", + " 1.361116e-05\n", " \n", " \n", "\n", @@ -1270,24 +1270,24 @@ " cell energy [MeV] nuclide score mean \\\n", "bin \n", "0 10000 0.0e+00 - 6.3e-07 (U-238 / total) (nu-fission / flux) 0.000001 \n", - "1 10000 0.0e+00 - 6.3e-07 (U-238 / total) (scatter / flux) 0.209988 \n", - "2 10000 0.0e+00 - 6.3e-07 (U-235 / total) (nu-fission / flux) 0.355276 \n", + "1 10000 0.0e+00 - 6.3e-07 (U-238 / total) (scatter / flux) 0.209986 \n", + "2 10000 0.0e+00 - 6.3e-07 (U-235 / total) (nu-fission / flux) 0.355667 \n", "3 10000 0.0e+00 - 6.3e-07 (U-235 / total) (scatter / flux) 0.005555 \n", - "4 10000 6.3e-07 - 2.0e+01 (U-238 / total) (nu-fission / flux) 0.007229 \n", - "5 10000 6.3e-07 - 2.0e+01 (U-238 / total) (scatter / flux) 0.227642 \n", - "6 10000 6.3e-07 - 2.0e+01 (U-235 / total) (nu-fission / flux) 0.008076 \n", - "7 10000 6.3e-07 - 2.0e+01 (U-235 / total) (scatter / flux) 0.003369 \n", + "4 10000 6.3e-07 - 2.0e+01 (U-238 / total) (nu-fission / flux) 0.007165 \n", + "5 10000 6.3e-07 - 2.0e+01 (U-238 / total) (scatter / flux) 0.227653 \n", + "6 10000 6.3e-07 - 2.0e+01 (U-235 / total) (nu-fission / flux) 0.008089 \n", + "7 10000 6.3e-07 - 2.0e+01 (U-235 / total) (scatter / flux) 0.003370 \n", "\n", " std. dev. \n", "bin \n", - "0 6.985151e-09 \n", - "1 2.206753e-03 \n", - "2 3.741612e-03 \n", - "3 5.842517e-05 \n", - "4 5.951357e-05 \n", - "5 9.496469e-04 \n", - "6 5.699123e-05 \n", - "7 1.369755e-05 " + "0 6.859257e-09 \n", + "1 1.966887e-03 \n", + "2 3.717881e-03 \n", + "3 5.218094e-05 \n", + "4 5.625590e-05 \n", + "5 8.544314e-04 \n", + "6 5.080374e-05 \n", + "7 1.361116e-05 " ] }, "execution_count": 33, @@ -1318,11 +1318,11 @@ "name": "stdout", "output_type": "stream", "text": [ - "[[[ 6.63809296e-07]\n", - " [ 3.55275544e-01]]\n", + "[[[ 6.64174599e-07]\n", + " [ 3.55666541e-01]]\n", "\n", - " [[ 7.22895528e-03]\n", - " [ 8.07565148e-03]]]\n" + " [[ 7.16505734e-03]\n", + " [ 8.08949336e-03]]]\n" ] } ], @@ -1350,9 +1350,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "[[[ 0.00555505]]\n", + "[[[ 0.00555465]]\n", "\n", - " [[ 0.0033688 ]]]\n" + " [[ 0.00337011]]]\n" ] } ], @@ -1374,8 +1374,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "[[[ 0.2276418]\n", - " [ 0.0033688]]]\n" + "[[[ 0.22765348]\n", + " [ 0.00337011]]]\n" ] } ], @@ -1434,7 +1434,7 @@ " U-238\n", " nu-fission\n", " 0.000002\n", - " 1.211808e-08\n", + " 1.284890e-08\n", " \n", " \n", " 1\n", @@ -1442,8 +1442,8 @@ " 0.0e+00 - 6.3e-07\n", " U-235\n", " nu-fission\n", - " 0.870360\n", - " 6.496431e-03\n", + " 0.867982\n", + " 7.022256e-03\n", " \n", " \n", " 2\n", @@ -1451,8 +1451,8 @@ " 6.3e-07 - 2.0e+01\n", " U-238\n", " nu-fission\n", - " 0.083226\n", - " 6.367951e-04\n", + " 0.082801\n", + " 6.087096e-04\n", " \n", " \n", " 3\n", @@ -1460,8 +1460,8 @@ " 6.3e-07 - 2.0e+01\n", " U-235\n", " nu-fission\n", - " 0.092974\n", - " 5.921990e-04\n", + " 0.093484\n", + " 5.275039e-04\n", " \n", " \n", "\n", @@ -1470,10 +1470,10 @@ "text/plain": [ " cell energy [MeV] nuclide score mean std. dev.\n", "bin \n", - "0 10000 0.0e+00 - 6.3e-07 U-238 nu-fission 0.000002 1.211808e-08\n", - "1 10000 0.0e+00 - 6.3e-07 U-235 nu-fission 0.870360 6.496431e-03\n", - "2 10000 6.3e-07 - 2.0e+01 U-238 nu-fission 0.083226 6.367951e-04\n", - "3 10000 6.3e-07 - 2.0e+01 U-235 nu-fission 0.092974 5.921990e-04" + "0 10000 0.0e+00 - 6.3e-07 U-238 nu-fission 0.000002 1.284890e-08\n", + "1 10000 0.0e+00 - 6.3e-07 U-235 nu-fission 0.867982 7.022256e-03\n", + "2 10000 6.3e-07 - 2.0e+01 U-238 nu-fission 0.082801 6.087096e-04\n", + "3 10000 6.3e-07 - 2.0e+01 U-235 nu-fission 0.093484 5.275039e-04" ] }, "execution_count": 37, @@ -1526,8 +1526,8 @@ " 1.0e-08 - 1.1e-07\n", " H-1\n", " scatter\n", - " 4.638428\n", - " 0.034134\n", + " 4.620525\n", + " 0.038249\n", " \n", " \n", " 1\n", @@ -1535,8 +1535,8 @@ " 1.1e-07 - 1.2e-06\n", " H-1\n", " scatter\n", - " 2.050818\n", - " 0.010745\n", + " 2.036841\n", + " 0.013203\n", " \n", " \n", " 2\n", @@ -1544,8 +1544,8 @@ " 1.2e-06 - 1.3e-05\n", " H-1\n", " scatter\n", - " 1.656905\n", - " 0.009480\n", + " 1.659916\n", + " 0.010107\n", " \n", " \n", " 3\n", @@ -1553,8 +1553,8 @@ " 1.3e-05 - 1.4e-04\n", " H-1\n", " scatter\n", - " 1.870808\n", - " 0.011883\n", + " 1.861546\n", + " 0.013328\n", " \n", " \n", " 4\n", @@ -1562,8 +1562,8 @@ " 1.4e-04 - 1.5e-03\n", " H-1\n", " scatter\n", - " 2.045621\n", - " 0.011414\n", + " 2.049664\n", + " 0.008215\n", " \n", " \n", " 5\n", @@ -1571,8 +1571,8 @@ " 1.5e-03 - 1.6e-02\n", " H-1\n", " scatter\n", - " 2.163297\n", - " 0.008725\n", + " 2.162157\n", + " 0.010245\n", " \n", " \n", " 6\n", @@ -1580,8 +1580,8 @@ " 1.6e-02 - 1.7e-01\n", " H-1\n", " scatter\n", - " 2.202045\n", - " 0.013500\n", + " 2.224496\n", + " 0.013796\n", " \n", " \n", " 7\n", @@ -1589,8 +1589,8 @@ " 1.7e-01 - 1.9e+00\n", " H-1\n", " scatter\n", - " 1.996977\n", - " 0.010791\n", + " 1.997585\n", + " 0.009161\n", " \n", " \n", " 8\n", @@ -1598,8 +1598,8 @@ " 1.9e+00 - 2.0e+01\n", " H-1\n", " scatter\n", - " 0.370890\n", - " 0.003597\n", + " 0.373472\n", + " 0.003922\n", " \n", " \n", "\n", @@ -1608,15 +1608,15 @@ "text/plain": [ " cell energy [MeV] nuclide score mean std. dev.\n", "bin \n", - "0 10002 1.0e-08 - 1.1e-07 H-1 scatter 4.638428 0.034134\n", - "1 10002 1.1e-07 - 1.2e-06 H-1 scatter 2.050818 0.010745\n", - "2 10002 1.2e-06 - 1.3e-05 H-1 scatter 1.656905 0.009480\n", - "3 10002 1.3e-05 - 1.4e-04 H-1 scatter 1.870808 0.011883\n", - "4 10002 1.4e-04 - 1.5e-03 H-1 scatter 2.045621 0.011414\n", - "5 10002 1.5e-03 - 1.6e-02 H-1 scatter 2.163297 0.008725\n", - "6 10002 1.6e-02 - 1.7e-01 H-1 scatter 2.202045 0.013500\n", - "7 10002 1.7e-01 - 1.9e+00 H-1 scatter 1.996977 0.010791\n", - "8 10002 1.9e+00 - 2.0e+01 H-1 scatter 0.370890 0.003597" + "0 10002 1.0e-08 - 1.1e-07 H-1 scatter 4.620525 0.038249\n", + "1 10002 1.1e-07 - 1.2e-06 H-1 scatter 2.036841 0.013203\n", + "2 10002 1.2e-06 - 1.3e-05 H-1 scatter 1.659916 0.010107\n", + "3 10002 1.3e-05 - 1.4e-04 H-1 scatter 1.861546 0.013328\n", + "4 10002 1.4e-04 - 1.5e-03 H-1 scatter 2.049664 0.008215\n", + "5 10002 1.5e-03 - 1.6e-02 H-1 scatter 2.162157 0.010245\n", + "6 10002 1.6e-02 - 1.7e-01 H-1 scatter 2.224496 0.013796\n", + "7 10002 1.7e-01 - 1.9e+00 H-1 scatter 1.997585 0.009161\n", + "8 10002 1.9e+00 - 2.0e+01 H-1 scatter 0.373472 0.003922" ] }, "execution_count": 38, @@ -1649,7 +1649,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", - "version": "2.7.8" + "version": "2.7.9" } }, "nbformat": 4, diff --git a/docs/source/pythonapi/index.rst b/docs/source/pythonapi/index.rst index 8c42f2d7e..12baf937d 100644 --- a/docs/source/pythonapi/index.rst +++ b/docs/source/pythonapi/index.rst @@ -62,6 +62,7 @@ on a given module or class. .. toctree:: :maxdepth: 1 + examples/post-processing examples/pandas-dataframes examples/tally-arithmetic diff --git a/docs/source/quickinstall.rst b/docs/source/quickinstall.rst index b64dfebda..9ce752be7 100644 --- a/docs/source/quickinstall.rst +++ b/docs/source/quickinstall.rst @@ -35,8 +35,8 @@ Installing from Source on Linux or Mac OS X ------------------------------------------- All OpenMC source code is hosted on GitHub_. If you have git_, the gfortran_ -compiler, and CMake_ installed, you can download and install OpenMC be entering -the following commands in a terminal: +compiler, CMake_, and HDF5_ installed, you can download and install OpenMC be +entering the following commands in a terminal: .. code-block:: sh diff --git a/docs/source/usersguide/index.rst b/docs/source/usersguide/index.rst index 675ed4081..5a7e7addf 100644 --- a/docs/source/usersguide/index.rst +++ b/docs/source/usersguide/index.rst @@ -5,7 +5,7 @@ User's Guide ============ Welcome to the OpenMC User's Guide! This tutorial will guide you through the -essential aspects of using OpenMC to perform neutronic simulations. +essential aspects of using OpenMC to perform simulations. .. toctree:: :numbered: @@ -14,5 +14,6 @@ essential aspects of using OpenMC to perform neutronic simulations. beginners install input + output/index processing troubleshoot diff --git a/docs/source/usersguide/input.rst b/docs/source/usersguide/input.rst index 914540078..d912f20db 100644 --- a/docs/source/usersguide/input.rst +++ b/docs/source/usersguide/input.rst @@ -79,14 +79,13 @@ Message Description [VALID] XML file matches RelaxNG. ======================== =================================== -As an example, if OpenMC is installed in the directory -``/opt/openmc/0.6.2`` and the current working directory is where -OpenMC XML input files are located, they can be validated using -the following command: +As an example, if OpenMC is installed in the directory ``/opt/openmc/`` and the +current working directory is where OpenMC XML input files are located, they can +be validated using the following command: .. code-block:: bash - /opt/openmc/0.6.2/bin/xml_validate + /opt/openmc/bin/openmc-validate-xml -------------------------------------- Settings Specification -- settings.xml @@ -1287,14 +1286,16 @@ The ```` element accepts the following sub-elements: *Default*: total :estimator: - The estimator element is used to force the use of either ``analog`` or - ``tracklength`` tally estimation. ''analog'' is generally less efficient - though it can be used with every score type. ''tracklength'' is generally - the most efficient, though its usage is restricted to tallies that do not - score particle information which requires a collision to have occured, such - as a scattering tally which utilizes outgoing energy filters. + The estimator element is used to force the use of either ``analog``, + ``collision``, or ``tracklength`` tally estimation. ``analog`` is generally + the least efficient though it can be used with every score type. + ``tracklength`` is generally the most efficient, but neither ``tracklength`` + nor ``collision`` can be used to score a tally that requires post-collision + information. For example, a scattering tally with outgoing energy filters + cannot be used with ``tracklength`` or ``collision`` because the code will + not know the outgoing energy distribution. - *Default*: ``tracklength`` but will revert to analog if necessary. + *Default*: ``tracklength`` but will revert to ``analog`` if necessary. :scores: A space-separated list of the desired responses to be accumulated. Accepted @@ -1305,7 +1306,9 @@ The ```` element accepts the following sub-elements: physical quantities: :flux: - Total flux in particle-cm per source particle. + Total flux in particle-cm per source particle. Note: The ``analog`` + estimator is actually identical to the ``collision`` estimator for the + flux score. :total: Total reaction rate in reactions per source particle. @@ -1432,8 +1435,7 @@ a separate element with the tag name ````. This element has the following attributes/sub-elements: :type: - The type of structured mesh. Valid options include "rectangular" and - "hexagonal". + The type of structured mesh. The only valid option is "regular". :dimension: The number of mesh cells in each direction. @@ -1535,16 +1537,16 @@ sub-elements: *Default*: None - Required entry :type: - Keyword for type of plot to be produced. Currently only "slice" and - "voxel" plots are implemented. The "slice" plot type creates 2D pixel - maps saved in the PPM file format. PPM files can be displayed in most - viewers (e.g. the default Gnome viewer, IrfanView, etc.). The "voxel" - plot type produces a binary datafile containing voxel grid positioning and - the cell or material (specified by the ``color`` tag) at the center of each - voxel. These datafiles can be processed into 3D SILO files using the - ``voxel.py`` utility provided with the OpenMC source, and subsequently - viewed with a 3D viewer such as VISIT or Paraview. See the - :ref:`devguide_voxel` for information about the datafile structure. + Keyword for type of plot to be produced. Currently only "slice" and "voxel" + plots are implemented. The "slice" plot type creates 2D pixel maps saved in + the PPM file format. PPM files can be displayed in most viewers (e.g. the + default Gnome viewer, IrfanView, etc.). The "voxel" plot type produces a + binary datafile containing voxel grid positioning and the cell or material + (specified by the ``color`` tag) at the center of each voxel. These + datafiles can be processed into 3D SILO files using the + ``openmc-voxel-to-silovtk`` utility provided with the OpenMC source, and + subsequently viewed with a 3D viewer such as VISIT or Paraview. See the + :ref:`usersguide_voxel` for information about the datafile structure. .. note:: Since the PPM format is saved without any kind of compression, the resulting file sizes can be quite large. Saving the image in diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index 7d3cda173..dcf990bda 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -59,6 +59,31 @@ Prerequisites sudo apt-get install cmake + * HDF5_ Library for portable binary output format + + OpenMC uses HDF5 for binary output files. As such, you will need to have + HDF5 installed on your computer. The installed version will need to have + been compiled with the same compiler you intend to compile OpenMC with. If + you are using HDF5 in conjunction with MPI, we recommend that your HDF5 + installation be built with parallel I/O features. An example of + configuring HDF5_ is listed below:: + + FC=/opt/mpich/3.1/bin/mpif90 CC=/opt/mpich/3.1/bin/mpicc \ + ./configure --prefix=/opt/hdf5/1.8.12 --enable-fortran \ + --enable-fortran2003 --enable-parallel + + You may omit ``--enable-parallel`` if you want to compile HDF5_ in serial. + + On Debian derivatives, HDF5 and/or parallel HDF5 can be installed through + the APT package manager: + + .. code-block:: sh + + sudo apt-get install libhdf5-8 libhdf5-dev hdf5-helpers + + Note that the exact package names may vary depending on your particular + distribution and version. + .. admonition:: Optional * An MPI implementation for distributed-memory parallel runs @@ -72,20 +97,6 @@ Prerequisites sudo apt-get install mpich libmpich-dev sudo apt-get install openmpi-bin libopenmpi1.6 libopenmpi-dev - * HDF5_ Library for portable binary output format - - To compile with support for HDF5_ output (highly recommended), you will - need to have HDF5 installed on your computer. The installed version will - need to have been compiled with the same compiler you intend to compile - OpenMC with. HDF5_ must be built with parallel I/O features if you intend - to use HDF5_ with MPI. An example of configuring HDF5_ is listed below:: - - FC=/opt/mpich/3.1/bin/mpif90 CC=/opt/mpich/3.1/bin/mpicc \ - ./configure --prefix=/opt/hdf5/1.8.12 --enable-fortran \ - --enable-fortran2003 --enable-parallel - - You may omit ``--enable-parallel`` if you want to compile HDF5_ in serial. - * git_ version control software for obtaining source code .. _gfortran: http://gcc.gnu.org/wiki/GFortran @@ -194,27 +205,26 @@ command, i.e. FC=mpif90 cmake /path/to/openmc -Compiling with HDF5 -+++++++++++++++++++ - -To compile with MPI, set the :envvar:`FC` environment variable to the path to -the HDF5 Fortran wrapper. For example, in a bash shell: +Selecting HDF5 Installation ++++++++++++++++++++++++++++ +CMakeLists.txt searches for the ``h5fc`` or ``h5pfc`` HDF5 Fortran wrapper on +your PATH environment variable and subsequently uses it to determine library +locations and compile flags. If you have multiple installations of HDF5 or one +that does not appear on your PATH, you can set the HDF5_ROOT environment +variable to the root directory of the HDF5 installation, e.g. .. code-block:: sh - export FC=h5fc + export HDF5_ROOT=/opt/hdf5/1.8.15 cmake /path/to/openmc -As noted above, an environment variable can typically be set for a single -command, i.e. +This will cause CMake to search first in /opt/hdf5/1.8.15/bin for ``h5fc`` / +``h5pfc`` before it searches elsewhere. As noted above, an environment variable +can typically be set for a single command, i.e. .. code-block:: sh - FC=h5fc cmake /path/to/openmc - -To compile with support for both MPI and HDF5, use the parallel HDF5 wrapper -``h5pfc`` instead. Note that this requires that your HDF5 installation be -compiled with ``--enable-parallel``. + HDF5_ROOT=/opt/hdf5/1.8.15 cmake /path/to/openmc Compiling on Linux and Mac OS X ------------------------------- @@ -308,6 +318,25 @@ This will build an executable named ``openmc``. .. _MinGW: http://www.mingw.org .. _SourceForge: http://sourceforge.net/projects/mingw +Compiling for the Intel Xeon Phi +-------------------------------- + +In order to build OpenMC for the Intel Xeon Phi using the Intel Fortran +compiler, it is necessary to specify that all objects be compiled with the +``-mmic`` flag as follows: + +.. code-block:: sh + + mkdir build && cd build + FC=ifort FFLAGS=-mmic cmake -Dopenmp=on .. + make + +Note that unless an HDF5 build for the Intel Xeon Phi is already on your target +machine, you will need to cross-compile HDF5 for the Xeon Phi. An `example +script`_ to build zlib and HDF5 provides several necessary workarounds. + +.. _example script: https://github.com/paulromano/install-scripts/blob/master/install-hdf5-mic + Testing Build ------------- diff --git a/docs/source/usersguide/output/index.rst b/docs/source/usersguide/output/index.rst new file mode 100644 index 000000000..31bd1da91 --- /dev/null +++ b/docs/source/usersguide/output/index.rst @@ -0,0 +1,16 @@ +.. _usersguide_output: + +=================== +Output File Formats +=================== + +.. toctree:: + :numbered: + :maxdepth: 3 + + statepoint + source + summary + particle_restart + track + voxel diff --git a/docs/source/usersguide/output/particle_restart.rst b/docs/source/usersguide/output/particle_restart.rst new file mode 100644 index 000000000..e0d89a515 --- /dev/null +++ b/docs/source/usersguide/output/particle_restart.rst @@ -0,0 +1,57 @@ +.. _usersguide_particle_restart: + +============================ +Particle Restart File Format +============================ + +The current revision of the particle restart file format is 1. + +**/filetype** (*char[]*) + + String indicating the type of file. + +**/revision** (*int*) + + Revision of the particle restart file format. Any time a change is made in + the format, this integer is incremented. + +**/current_batch** (*int*) + + The number of batches already simulated. + +**/gen_per_batch** (*int*) + + Number of generations per batch. + +**/current_gen** (*int*) + + The number of generations already simulated. + +**/n_particles** (*int8_t*) + + Number of particles used per generation. + +**/run_mode** (*int*) + + Run mode used. A value of 1 indicates a fixed-source run and a value of 2 + indicates an eigenvalue run. + +**/id** (*int8_t*) + + Unique identifier of the particle. + +**/weight** (*double*) + + Weight of the particle. + +**/energy** (*double*) + + Energy of the particle in MeV. + +**/xyz** (*double[3]*) + + Position of the particle. + +**/uvw** (*double[3]*) + + Direction of the particle. diff --git a/docs/source/usersguide/output/source.rst b/docs/source/usersguide/output/source.rst new file mode 100644 index 000000000..2981b0f66 --- /dev/null +++ b/docs/source/usersguide/output/source.rst @@ -0,0 +1,19 @@ +.. _usersguide_source: + +================== +Source File Format +================== + +Normally, source data is stored in a state point file. However, it is possible +to request that the source be written separately, in which case the format used +is that documented here. + +**/filetype** (*char[]*) + + String indicating the type of file. + +**/source_bank** (Compound type) + + Source bank information for each particle. The compound type has fields + ``wgt``, ``xyz``, ``uvw``, and ``E`` which represent the weight, position, + direction, and energy of the source particle, respectively. diff --git a/docs/source/usersguide/output/statepoint.rst b/docs/source/usersguide/output/statepoint.rst new file mode 100644 index 000000000..d1ebc7231 --- /dev/null +++ b/docs/source/usersguide/output/statepoint.rst @@ -0,0 +1,259 @@ +.. _usersguide_statepoint: + +======================= +State Point File Format +======================= + +The current revision of the statepoint file format is 13. + +**/filetype** (*char[]*) + + String indicating the type of file. + +**/revision** (*int*) + + Revision of the state point file format. Any time a change is made in the + format, this integer is incremented. + +**/version_major** (*int*) + + Major version number for OpenMC + +**/version_minor** (*int*) + + Minor version number for OpenMC + +**/version_release** (*int*) + + Release version number for OpenMC + +**/date_and_time** (*char[]*) + + Date and time the state point was written. + +**/path** (*char[]*) + + Absolute path to directory containing input files. + +**/seed** (*int8_t*) + + Pseudo-random number generator seed. + +**/run_mode** (*char[]*) + + Run mode used. A value of 1 indicates a fixed-source run and a value of 2 + indicates an eigenvalue run. + +**/n_particles** (*int8_t*) + + Number of particles used per generation. + +**/n_batches** (*int*) + + Number of batches to simulate. + +**/current_batch** (*int*) + + The number of batches already simulated. + +if run_mode == 'k-eigenvalue': + + **/n_inactive** (*int*) + + Number of inactive batches. + + **/gen_per_batch** (*int*) + + Number of generations per batch. + + **/k_generation** (*double[]*) + + k-effective for each generation simulated. + + **/entropy** (*double[]*) + + Shannon entropy for each generation simulated + + **/k_col_abs** (*double*) + + Sum of product of collision/absorption estimates of k-effective + + **/k_col_tra** (*double*) + + Sum of product of collision/track-length estimates of k-effective + + **/k_abs_tra** (*double*) + + Sum of product of absorption/track-length estimates of k-effective + + **/k_combined** (*double[2]*) + + Mean and standard deviation of a combined estimate of k-effective + + **/cmfd_on** (*int*) + + Flag indicating whether CMFD is on (1) or off (0). + + if (cmfd_on) + + **/cmfd/indices** (*int[4]*) + + Indices for cmfd mesh (i,j,k,g) + + **/cmfd/k_cmfd** (*double[]*) + + CMFD eigenvalues + + **/cmfd/cmfd_src** (*double[][][][]*) + + CMFD fission source + + **/cmfd/cmfd_entropy** (*double[]*) + + CMFD estimate of Shannon entropy + + **/cmfd/cmfd_balance** (*double[]*) + + RMS of the residual neutron balance equation on CMFD mesh + + **/cmfd/cmfd_dominance** (*double[]*) + + CMFD estimate of dominance ratio + + **/cmfd/cmfd_srccmp** (*double[]*) + + RMS comparison of difference between OpenMC and CMFD fission source + +**/tallies/n_meshes** (*int*) + + Number of meshes in tallies.xml file + +**/tally/meshes/ids** (*int[]*) + + Internal unique ID of each mesh. + +**/tally/meshes/keys** (*int[]*) + + User-identified unique ID of each mesh. + +**/tallies/meshes/mesh /type** (*char[]*) + + Type of mesh. + +**/tallies/meshes/mesh /dimension** (*int*) + + Number of mesh cells in each dimension. + +**/tallies/meshes/mesh /lower_left** (*double[]*) + + Coordinates of lower-left corner of mesh. + +**/tallies/meshes/mesh /upper_right** (*double[]*) + + Coordinates of upper-right corner of mesh. + +**/tallies/meshes/mesh /width** (*double[]*) + + Width of each mesh cell in each dimension. + +**/tallies/n_tallies** (*int*) + + Number of user-defined tallies. + +**/tallies/ids** (*int[]*) + + Internal unique ID of each tally. + +**/tallies/keys** (*int[]*) + + User-identified unique ID of each tally. + +**/tallies/tally /estimator** (*char[]*) + + Type of tally estimator, either 'analog', 'tracklength', or 'collision'. + +**/tallies/tally /n_realizations** (*int*) + + Number of realizations. + +**/tallies/tally /n_filters** (*int*) + + Number of filters used. + +**/tallies/tally /filter /type** (*char[]*) + + Type of the j-th filter. Can be 'universe', 'material', 'cell', 'cellborn', + 'surface', 'mesh', 'energy', 'energyout', or 'distribcell'. + +**/tallies/tally /filter /offset** (*int*) + + Filter offset (used for distribcell filter). + +**/tallies/tally /filter /n_bins** (*int*) + + Number of bins for the j-th filter. + +**/tallies/tally /filter /bins** (*int[]* or *double[]*) + + Value for each filter bin of this type. + +**/tallies/tally /nuclides** (*char[][]*) + + Array of nuclides to tally. Note that if no nuclide is specified in the user + input, a single 'total' nuclide appears here. + +**/tallies/tally /n_score_bins** (*int*) + + Number of scoring bins for a single nuclide. In general, this can be greater + than the number of user-specified scores since each score might have + multiple scoring bins, e.g., scatter-PN. + +**/tallies/tally /score_bins** (*char[][]*) + + Values of specified scores. + +**/tallies/tally /n_user_scores** (*int*) + + Number of scores without accounting for those added by expansions, + e.g. scatter-PN. + +**/tallies/tally /moment_orders** (*char[][]*) + + Tallying moment orders for Legendre and spherical harmonic tally expansions + (*e.g.*, 'P2', 'Y1,2', etc.). + +**/tallies/tally /results** (Compound type) + + Accumulated sum and sum-of-squares for each bin of the i-th tally. This is a + two-dimensional array, the first dimension of which represents combinations + of filter bins and the second dimensions of which represents scoring + bins. Each element of the array has fields 'sum' and 'sum_sq'. + +**/source_present** (*int*) + + Flag indicated if source bank is present in the file + +**/n_realizations** (*int*) + + Number of realizations for global tallies. + +**/n_global_tallies** (*int*) + + Number of global tally scores. + +**/global_tallies** (Compound type) + + Accumulated sum and sum-of-squares for each global tally. The compound type + has fields named ``sum`` and ``sum_sq``. + +**tallies_present** (*int*) + + Flag indicated if tallies are present in the file. + +if (run_mode == 'k-eigenvalue' and source_present > 0) + + **/source_bank** (Compound type) + + Source bank information for each particle. The compound type has fields + ``wgt``, ``xyz``, ``uvw``, and ``E`` which represent the weight, + position, direction, and energy of the source particle, respectively. diff --git a/docs/source/usersguide/output/summary.rst b/docs/source/usersguide/output/summary.rst new file mode 100644 index 000000000..9ced8448a --- /dev/null +++ b/docs/source/usersguide/output/summary.rst @@ -0,0 +1,310 @@ +.. _usersguide_summary: + +=================== +Summary File Format +=================== + +The current revision of the summary file format is 1. + +**/filetype** (*char[]*) + + String indicating the type of file. + +**/revision** (*int*) + + Revision of the summary file format. Any time a change is made in the + format, this integer is incremented. + +**/version_major** (*int*) + + Major version number for OpenMC + +**/version_minor** (*int*) + + Minor version number for OpenMC + +**/version_release** (*int*) + + Release version number for OpenMC + +**/date_and_time** (*char[]*) + + Date and time the summary was written. + +**/n_procs** (*int*) + + Number of MPI processes used. + +**/n_particles** (*int8_t*) + + Number of particles used per generation. + +**/n_batches** (*int*) + + Number of batches to simulate. + +**/n_inactive** (*int*) + + Number of inactive batches. Only present if /run_mode is set to + 'k-eigenvalue'. + +**/n_active** (*int*) + + Number of active batches. Only present if /run_mode is set to + 'k-eigenvalue'. + +**/gen_per_batch** (*int*) + + Number of generations per batch. Only present if /run_mode is set to + 'k-eigenvalue'. + +**/geometry/n_cells** (*int*) + + Number of cells in the problem. + +**/geometry/n_surfaces** (*int*) + + Number of surfaces in the problem. + +**/geometry/n_universes** (*int*) + + Number of unique universes in the problem. + +**/geometry/n_lattices** (*int*) + + Number of lattices in the problem. + +**/geometry/cells/cell /index** (*int*) + + Index in cells array used internally in OpenMC. + +**/geometry/cells/cell /name** (*char[]*) + + Name of the cell. + +**/geometry/cells/cell /universe** (*int*) + + Universe assigned to the cell. If none is specified, the default + universe (0) is assigned. + +**/geometry/cells/cell /fill_type** (*char[]*) + + Type of fill for the cell. Can be 'normal', 'universe', or 'lattice'. + +**/geometry/cells/cell /material** (*int*) + + Unique ID of the material assigned to the cell. This dataset is present only + if fill_type is set to 'normal'. + +**/geometry/cells/cell /offset** (*int[]*) + + Offsets used for distribcell tally filter. This dataset is present only if + fill_type is set to 'universe'. + +**/geometry/cells/cell /translation** (*double[3]*) + + Translation applied to the fill universe. This dataset is present only if + fill_type is set to 'universe'. + +**/geometry/cells/cell /rotation** (*double[3]*) + + Angles in degrees about the x-, y-, and z-axes for which the fill universe + should be rotated. This dataset is present only if fill_type is set to + 'universe'. + +**/geometry/cells/cell /lattice** (*int*) + + Unique ID of the lattice which fills the cell. Only present if fill_type is + set to 'lattice'. + +**/geometry/cells/cell /surfaces** (*int[]*) + + Surface specification for the cell. + +**/geometry/surfaces/surface /index** (*int*) + + Index in surfaces array used internally in OpenMC. + +**/geometry/surfaces/surface /name** (*char[]*) + + Name of the surface. + +**/geometry/surfaces/surface /type** (*char[]*) + + Type of the surface. Can be 'x-plane', 'y-plane', 'z-plane', 'plane', + 'x-cylinder', 'y-cylinder', 'sphere', 'x-cone', 'y-cone', or 'z-cone'. + +**/geometry/surfaces/surface /coefficients** (*double[]*) + + Array of coefficients that define the surface. See :ref:`surface_element` + for what coefficients are defined for each surface type. + +**/geometry/surfaces/surface /boundary_condition** (*char[]*) + + Boundary condition applied to the surface. Can be 'transmission', 'vacuum', + 'reflective', or 'periodic'. + +**/geometry/universes/universe /index** (*int*) + + Index in the universes array used internally in OpenMC. + +**/geometry/universes/universe /cells** (*int[]*) + + Array of unique IDs of cells that appear in the universe. + +**/geometry/lattices/lattice /index** (*int*) + + Index in the lattices array used internally in OpenMC. + +**/geometry/lattices/lattice /name** (*char[]*) + + Name of the lattice. + +**/geometry/lattices/lattice /type** (*char[]*) + + Type of the lattice, either 'rectangular' or 'hexagonal'. + +**/geometry/lattices/lattice /pitch** (*double[]*) + + Pitch of the lattice. + +**/geometry/lattices/lattice /outer** (*int*) + + Outer universe assigned to lattice cells outside the defined range. + +**/geometry/lattices/lattice /offsets** (*int[]*) + + Offsets used for distribcell tally filter. + +**/geometry/lattices/lattice /universes** (*int[]*) + + Three-dimensional array of universes assigned to each cell of the lattice. + +**/geometry/lattices/lattice /dimension** (*int[]*) + + The number of lattice cells in each direction. This dataset is present only + when the 'type' dataset is set to 'rectangular'. + +**/geometry/lattices/lattice /lower_left** (*double[]*) + + The coordinates of the lower-left corner of the lattice. This dataset is + present only when the 'type' dataset is set to 'rectangular'. + +**/geometry/lattices/lattice /n_rings** (*int*) + + Number of radial ring positions in the xy-plane. This dataset is present + only when the 'type' dataset is set to 'hexagonal'. + +**/geometry/lattices/lattice /n_axial** (*int*) + + Number of lattice positions along the z-axis. This dataset is present only + when the 'type' dataset is set to 'hexagonal'. + +**/geometry/lattices/lattice /center** (*double[]*) + + Coordinates of the center of the lattice. This dataset is present only when + the 'type' dataset is set to 'hexagonal'. + +**/n_materials** (*int*) + + Number of materials in the problem. + +**/materials/material /index** (*int*) + + Index in materials array used internally in OpenMC. + +**/materials/material /name** (*char[]*) + + Name of the material. + +**/materials/material /atom_density** (*double[]*) + + Total atom density of the material in atom/b-cm. + +**/materials/material /nuclides** (*char[][]*) + + Array of nuclides present in the material, e.g., 'U-235.71c'. + +**/materials/material /nuclide_densities** (*double[]*) + + Atom density of each nuclide. + +**/materials/material /sab_names** (*char[][]*) + + Names of S(:math:`\alpha`,:math:`\beta`) tables assigned to the material. + +**/tallies/n_tallies** (*int*) + + Number of tallies in the problem. + +**/tallies/n_meshes** (*int*) + + Number of meshes in the problem. + +**/tallies/mesh /index** (*int*) + + Index in the meshes array used internally in OpenMC. + +**/tallies/mesh /type** (*char[]*) + + Type of the mesh. The only valid option is currently 'regular'. + +**/tallies/mesh /dimension** (*int[]*) + + Number of mesh cells in each direction. + +**/tallies/mesh /lower_left** (*double[]*) + + Coordinates of the lower-left corner of the mesh. + +**/tallies/mesh /upper_right** (*double[]*) + + Coordinates of the upper-right corner of the mesh. + +**/tallies/mesh /width** (*double[]*) + + Width of a single mesh cell in each direction. + +**/tallies/tally /index** (*int*) + + Index in tallies array used internally in OpenMC. + +**/tallies/tally /name** (*char[]*) + + Name of the tally. + +**/tallies/tally /n_filters** (*int*) + + Number of filters applied to the tally. + +**/tallies/tally /filter /type** (*char[]*) + + Type of the j-th filter. Can be 'universe', 'material', 'cell', 'cellborn', + 'surface', 'mesh', 'energy', 'energyout', or 'distribcell'. + +**/tallies/tally /filter /offset** (*int*) + + Filter offset (used for distribcell filter). + +**/tallies/tally /filter /n_bins** (*int*) + + Number of bins for the j-th filter. + +**/tallies/tally /filter /bins** (*int[]* or *double[]*) + + Value for each filter bin of this type. + +**/tallies/tally /nuclides** (*char[][]*) + + Array of nuclides to tally. Note that if no nuclide is specified in the user + input, a single 'total' nuclide appears here. + +**/tallies/tally /n_score_bins** (*int*) + + Number of scoring bins for a single nuclide. In general, this can be greater + than the number of user-specified scores since each score might have + multiple scoring bins, e.g., scatter-PN. + +**/tallies/tally /score_bins** (*char[][]*) + + Scoring bins for the tally. diff --git a/docs/source/usersguide/output/track.rst b/docs/source/usersguide/output/track.rst new file mode 100644 index 000000000..d3c7a27d8 --- /dev/null +++ b/docs/source/usersguide/output/track.rst @@ -0,0 +1,30 @@ +.. _usersguide_track: + +================= +Track File Format +================= + +The current revision of the particle track file format is 1. + +**/filetype** (*char[]*) + + String indicating the type of file. + +**/revision** (*int*) + + Revision of the track file format. Any time a change is made in the format, + this integer is incremented. + +**/n_particles** (*int*) + + Number of particles for which tracks are recorded. + +**/n_coords** (*int[]*) + + Number of coordinates for each particle. + +*do i = 1, n_particles* + + **/coordinates_i** (*double[][3]*) + + (x,y,z) coordinates for the *i*-th particle. diff --git a/docs/source/usersguide/output/voxel.rst b/docs/source/usersguide/output/voxel.rst new file mode 100644 index 000000000..1da501fb5 --- /dev/null +++ b/docs/source/usersguide/output/voxel.rst @@ -0,0 +1,25 @@ +.. _usersguide_voxel: + +====================== +Voxel Plot File Format +====================== + +**/filetype** (*char[]*) + + String indicating the type of file. + +**/num_voxels** (*int[3]*) + + Number of voxels in the x-, y-, and z- directions. + +**/voxel_width** (*double[3]*) + + Width of a voxel in centimeters. + +**/lower_left** (*double[3]*) + + Cartesian coordinates of the lower-left corner of the plot. + +**/data** (*int[][][]*) + + Data for each voxel that represents a material or cell ID. diff --git a/docs/source/usersguide/processing.rst b/docs/source/usersguide/processing.rst index e773cf156..b18569ec6 100644 --- a/docs/source/usersguide/processing.rst +++ b/docs/source/usersguide/processing.rst @@ -6,31 +6,34 @@ Data Processing and Visualization This section is intended to explain in detail the recommended procedures for carrying out common post-processing tasks with OpenMC. While several utilities -of varying complexity are provided to help automate the process, in many cases -it will be extremely beneficial to do some coding in Python to quickly obtain -results. In these cases, and for many of the provided utilities, it is necessary -for your Python installation to contain: +of varying complexity are provided to help automate the process, the most +powerful capabilities for post-processing derive from use of the :ref:`Python +API `. Both the provided scripts and the Python API rely on a number +third-party Python packages, including: -* [1]_ `Numpy `_ -* [1]_ `Scipy `_ -* [2]_ `h5py `_ -* [3]_ `Matplotlib `_ -* [3]_ `Silomesh `_ -* [3]_ `VTK `_ +* [1]_ `NumPy `_ +* [2]_ `h5py `_ +* [3]_ `pandas `_ +* [4]_ `matplotlib `_ +* [4]_ `Silomesh `_ +* [4]_ `VTK `_ +* [4]_ `lxml `_ -Most of these are easily obtainable in Ubuntu through the package manager, or -are easily installed with distutils. +Most of these are can easily be installed with `pip `_ +or alternatively obtaining through a package manager. -.. [1] Required for tally data extraction from statepoints with statepoint.py -.. [2] Required only if reading HDF5 statepoint files. -.. [3] Optional for plotting utilities +.. [1] Required for most post-processing tasks +.. [2] Required for reading HDF5 output files +.. [3] Optional dependency for advanced features in Python API +.. [4] Not used directly by the Python API, but are optional dependencies for a + number of scripts. ---------------------- Geometry Visualization ---------------------- Geometry plotting is carried out by creating a plots.xml, specifying plots, and -running OpenMC with the -plot or -p command-line option (See +running OpenMC with the --plot or -p command-line option (See :ref:`usersguide_plotting`). Plotting in 2D @@ -128,27 +131,26 @@ capabilities of 3D voxel plots. Voxel plots are built the same way 2D slice plots are, by determining the cell or material id of a particle at the center of each voxel. In this example, the space covered is the cube between the points (-5,-5,-5) and (5,5,5), with voxel -centers 10/500 = 0.02 cm apart. The binary VOXEL files that are produced do not +centers 10/500 = 0.02 cm apart. The HDF5 voxel files that are produced do not specify any color - instead containing only material or cell ids (material id in this example) - and thus the ``background``, ``col_spec``, and ``mask`` elements are not used. If no cell is found at a voxel center, an id of -1 is stored. -The binary VOXEL files output by OpenMC can not be viewed directly by any -existing viewers. In order to view them, they must be converted into a standard -mesh format that can be viewed in ParaView, Visit, etc. This typically will -compress the size of the file significantly. The provided utility voxel.py -accomplishes this for SILO: +The voxel plot data is written to an HDF5 file. The voxel file can subsequently +be converted into a standard mesh format that can be viewed in ParaView, Visit, +etc. This typically will compress the size of the file significantly. The +provided utility openmc-voxel-to-silovtk accomplishes this for SILO: .. code-block:: sh - /src/utils/voxel.py myplot.voxel -o output.silo + openmc-voxel-to-silovtk myplot.voxel -o output.silo and VTK file formats: .. code-block:: sh - /src/utils/voxel.py myplot.voxel --vtk -o output.vti + openmc-voxel-to-silovtk myplot.voxel --vtk -o output.vti To use this utility you need either @@ -156,11 +158,10 @@ To use this utility you need either or -* `VTK `_ with python bindings - On Ubuntu, these are - easily obtained with ``sudo apt-get install python-vtk`` +* `VTK `_ with python bindings. On debian derivatives, + these are easily obtained with ``sudo apt-get install python-vtk`` -Users can process the binary into any other format if desired by following the -example of voxel.py. For the binary file structure, see :ref:`devguide_voxel`. +For the HDF5 file structure, see :ref:`usersguide_voxel`. Once processed into a standard 3D file format, colors and masks can be defined using the stored id numbers to better explore the geometry. The process for @@ -183,150 +184,38 @@ doing this will depend on the 3D viewer, but should be straightforward. Tally Visualization ------------------- -Tally results are saved in both a text file (tallies.out) as well as a binary +Tally results are saved in both a text file (tallies.out) as well as an HDF5 statepoint file. While the tallies.out file may be fine for simple tallies, in -many cases the user requires more information about the tally or the run, or -has to deal with a large number of result values (e.g. for mesh tallies). In -these cases, extracting data from the statepoint file via Python scripting is -the preferred method of data analysis and visualization. +many cases the user requires more information about the tally or the run, or has +to deal with a large number of result values (e.g. for mesh tallies). In these +cases, extracting data from the statepoint file via the :ref:`pythonapi` is the +preferred method of data analysis and visualization. Data Extraction --------------- A great deal of information is available in statepoint files (See -:ref:`devguide_statepoint`), most of which is easily extracted by the provided -utility statepoint.py. This utility provides a Python class to load statepoints -and extract data - it is used in many of the provided plotting utilities, and -can be used in user-created scripts to carry out manipulations of the data. To -read tallies using this utility, make sure statepoint.py is in your PYTHONPATH, -and then import the class, instantiate it, and call read_results: +:ref:`usersguide_statepoint`), all of which is accessible through the Python +API. The ``openmc.statepoint`` module (see :ref:`pythonapi_statepoint`) provides +a class to load statepoints and access data as requested; it is used in many of +the provided plotting utilities, OpenMC's regression test suite, and can be used +in user-created scripts to carry out manipulations of the data. -.. code-block:: python - - from statepoint import StatePoint - sp = StatePoint('statepoint.100.binary') - sp.read_results() - -At this point the user can extract entire scores from tallies into a data -dictionary containing numpy arrays: - -.. code-block:: python - - tallyid = 1 - score = 'flux' - data = sp.extract_results(tallyid, score) - means = data['means'] - print data.keys() - -The results from this function contain all filter bins (all mesh points, all -energy groups, etc.), which can be reshaped with the bin ordering also contained -in the output dictionary. This is the best choice of output for easily -integrating ranges of data. - -Alternatively the user can extract specific values for a single score/filter -combination: - -.. code-block:: python - - tallyid = 1 - score = 'flux' - filters = [('mesh', (1, 1, 5)), ('energyin', 0)] - value, error = sp.get_value(tallyid, filters, score) - -In the future more documentation may become available here for statepoint.py and -the data extraction functions of StatePoint objects. However, for now it is up -to the user to explore the classes in statepoint.py to discover what data is -available in StatePoint objects (we highly recommend interactively exploring -with `IPython `_). Many examples can be found by looking -through the other utilities that use statepoint.py, and a few common -visualization tasks will be described here in the following sections. +An :ref:`example IPython notebook ` demonstrates how +to extract data from a statepoint using the Python API. Plotting in 2D -------------- +The :ref:`IPython notebook example ` also demonstrates +how to plot a mesh tally in two dimensions using the Python API. Note, however, +that there is also a script distributed with OpenMC, ``openmc-plot-mesh-tally``, +that provides an interactive GUI to explore and plot mesh tallies for any scores +and filter bins. + .. image:: ../_images/plotmeshtally.png :height: 200px -For simple viewing of 2D slices of a mesh plot, the utility plot_mesh_tally.py -is provided. This utility provides an interactive GUI to explore and plot -mesh tallies for any scores and filter bins. It requires statepoint.py. - -.. image:: ../_images/fluxplot.png - :height: 200px - -Alternatively, the user can write their own Python script to manipulate the data -appropriately. Consider a run where the first tally contains a 105x105x20 mesh -over a small core, with a flux score and two energyin filter bins. To explicitly -extract the data and create a plot with gnuplot, the following script can be -used. The script operates in several steps for clarity, and is not necessarily -the most efficient way to extract data from large mesh tallies. This creates the -two heatmaps in the previous figure. - -.. code-block:: python - - #!/usr/bin/env python - - import os - - import statepoint - - # load and parse the statepoint file - sp = statepoint.StatePoint('statepoint.300.binary') - sp.read_results() - - tallyid = 0 # This is tally 1 - score = 0 # This corresponds to flux (see tally.scores) - - # get mesh dimensions - meshid = sp.tallies[tallyid].filters['mesh'].bins[0] - for i,m in enumerate(sp.meshes): - if m.id == meshid: - mesh = m - break - nx,ny,nz = mesh.dimension - - # loop through mesh and extract values to python dictionaries - thermal = {} - fast = {} - for x in range(1,nx+1): - for y in range(1,ny+1): - for z in range(1,nz+1): - val,err = sp.get_value(tallyid, - [('mesh',(x,y,z)),('energyin',0)], - score) - thermal[(x,y,z)] = val - val,err = sp.get_value(tallyid, - [('mesh',(x,y,z)),('energyin',1)], - score) - fast[(x,y,z)] = val - - # sum up the axial values and write datafile for gnuplot - with open('meshdata.dat','w') as fh: - for x in range(1,nx+1): - for y in range(1,ny+1): - thermalval = 0. - fastval = 0. - for z in range(1,nz+1): - thermalval += thermal[(x,y,z)] - fastval += fast[(x,y,z)] - fh.write("{} {} {} {}\n".format(x,y,thermalval,fastval)) - - # write gnuplot file - with open('tmp.gnuplot','w') as fh: - fh.write(r"""set terminal png size 1000 400 - set output 'fluxplot.png' - set nokey - set autoscale fix - set multiplot layout 1,2 title "Pin Mesh Flux Tally" - set title "Thermal" - plot 'meshdata.dat' using 1:2:3 with image - set title "Fast" - plot 'meshdata.dat' using 1:2:4 with image - """) - - # make plot - os.system("gnuplot < tmp.gnuplot") - Plotting in 3D -------------- @@ -334,22 +223,23 @@ Plotting in 3D :height: 200px As with 3D plots of the geometry, meshtally data needs to be put into a standard -format for viewing. The utility statepoint_3d.py is provided to accomplish this -for both VTK and SILO. By default statepoint_3d.py processes a statepoint into a -3D file with all mesh tallies and filter/score combinations, +format for viewing. The utility ``openmc-statepoint-3d`` is provided to +accomplish this for both VTK and SILO. By default ``openmc-statepoint-3d`` +processes a statepoint into a 3D file with all mesh tallies and filter/score +combinations, .. code-block:: sh - /src/utils/statepoint_3d.py -o output.silo - /src/utils/statepoint_3d.py --vtk -o output.vtm + openmc-statepoint-3d -o output.silo + openmc-statepoint-3d --vtk -o output.vtm but it also provides several command-line options to selectively process only certain data arrays in order to keep file sizes down. .. code-block:: sh - statepoint_3d.py --tallies 2,4 --scores 4.1,4.3 -o output.silo - statepoint_3d.py --filters 2.energyin.1 --vtk -o output.vtm + openmc-statepoint-3d --tallies 2,4 --scores 4.1,4.3 -o output.silo + openmc-statepoint-3d --filters 2.energyin.1 --vtk -o output.vtm All available options for specifying a subset of tallies, scores, and filters can be listed with the ``--list`` or ``-l`` command line options. @@ -426,13 +316,11 @@ Getting Data into MATLAB ------------------------ There is currently no front-end utility to dump tally data to MATLAB files, but -the process is straightforward. First extract the data using a custom Python -script with statepoint.py, put the data into appropriately-shaped numpy arrays, -and then use the `Scipy MATLAB IO routines +the process is straightforward. First extract the data using the Python API via +``openmc.statepoint`` and then use the `Scipy MATLAB IO routines `_ to save to a MAT -file. Note that the data contained in the output from -``StatePoint.extract_result`` is already in a Numpy array that can be reshaped -and dumped to MATLAB in one step. +file. Note that all arrays that are accessible in a statepoint are already in +NumPy arrays that can be reshaped and dumped to MATLAB in one step. ---------------------------- Particle Track Visualization @@ -463,15 +351,15 @@ particle numbers, respectively. For example, to output the tracks for particles After running OpenMC, the directory should contain a file of the form -"track_(batch #)_(generation #)_(particle #).(binary or h5)" for each particle -tracked. These track files can be converted into VTK poly data files with the -"track.py" utility. The usage of track.py is of the form "track.py [-o OUT] IN" -where OUT is the optional output filename and IN is one or more filenames -describing track files. The default output name is "track.pvtp". A common -usage of track.py is "track.py track*.binary" which will use the data from all -binary track files in the directory to write a "track.pvtp" VTK output file. -The .pvtp file can then be read and plotted by 3d visualization programs such as -ParaView. +"track_(batch #)_(generation #)_(particle #).h5" for each particle tracked. +These track files can be converted into VTK poly data files with the +``openmc-track-to-vtk`` utility. The usage of ``openmc-track-to-vtk`` is of the +form "openmc-track-to-vtk [-o OUT] IN" where OUT is the optional output filename +and IN is one or more filenames describing track files. The default output name +is "track.pvtp". A common usage of track.py is "openmc-track-to-vtk track*.h5" +which will use the data from all binary track files in the directory to write a +"track.pvtp" VTK output file. The .pvtp file can then be read and plotted by 3d +visualization programs such as ParaView. ---------------------- Source Site Processing @@ -480,43 +368,6 @@ Source Site Processing For eigenvalue problems, OpenMC will store information on the fission source sites in the statepoint file by default. For each source site, the weight, position, sampled direction, and sampled energy are stored. To extract this data -from a statepoint file, the statepoint.py Python module can be used. Below is an -example of an interactive ipython session using the statepoint.py Python module: - -.. code-block:: python - - In [1]: import statepoint - - In [2]: sp = statepoint.StatePoint('statepoint.100.h5') - - In [3]: sp.read_source() - - In [4]: len(sp.source) - Out[4]: 1000 - - In [5]: sp.source[0:10] - Out[5]: - [, - , - , - , - , - , - , - , - , - ] - - In [6]: site = sp.source[0] - - In [7]: site.weight - Out[7]: 1.0 - - In [8]: site.xyz - Out[8]: array([ 2.21980946, -8.92686048, 87.93720485]) - - In [9]: site.uvw - Out[9]: array([ 0.06740523, 0.50612814, 0.85982024]) - - In [10]: site.E - Out[10]: 0.93292326356564159 +from a statepoint file, the ``openmc.statepoint`` module can be used. An +:ref:`example IPython notebook ` demontrates how to +analyze and plot source information. diff --git a/docs/source/usersguide/troubleshoot.rst b/docs/source/usersguide/troubleshoot.rst index 10ac12184..c5e4e7c1e 100644 --- a/docs/source/usersguide/troubleshoot.rst +++ b/docs/source/usersguide/troubleshoot.rst @@ -31,21 +31,6 @@ f951: error: unrecognized command line option "-fbacktrace" You are probably using a version of the gfortran compiler that is too old. Download and install the latest version of gfortran_. - -make[1]: ifort: Command not found -********************************* - -You tried compiling with the Intel Fortran compiler and it was not found on your -:envvar:`PATH`. If you have the Intel compiler installed, make sure the shell -can locate it (this can be tested with :program:`which ifort`). - -make[1]: pgf90: Command not found -********************************* - -You tried compiling with the PGI Fortran compiler and it was not found on your -:envvar:`PATH`. If you have the PGI compiler installed, make sure the shell can -locate it (this can be tested with :program:`which pgf90`). - ------------------------- Problems with Simulations ------------------------- @@ -56,13 +41,13 @@ Segmentation Fault A segmentation fault occurs when the program tries to access a variable in memory that was outside the memory allocated for the program. The best way to debug a segmentation fault is to re-compile OpenMC with debug options turned -on. First go to your ``openmc/src`` directory where OpenMC was compiled and type -the following commands: +on. Create a new build directory and type the following commands: .. code-block:: sh - make distclean - make DEBUG=yes + mkdir build-debug && cd build-debug + cmake -Ddebug=on /path/to/openmc + make Now when you re-run your problem, it should report exactly where the program failed. If after reading the debug output, you are still unsure why the program diff --git a/examples/python/lattice/nested/build-xml.py b/examples/python/lattice/nested/build-xml.py index ce6766542..24b5554c0 100644 --- a/examples/python/lattice/nested/build-xml.py +++ b/examples/python/lattice/nested/build-xml.py @@ -168,7 +168,7 @@ plot_file.export_to_xml() # Instantiate a tally mesh mesh = openmc.Mesh(mesh_id=1) -mesh.type = 'rectangular' +mesh.type = 'regular' mesh.dimension = [4, 4] mesh.lower_left = [-2, -2] mesh.width = [1, 1] diff --git a/examples/python/lattice/simple/build-xml.py b/examples/python/lattice/simple/build-xml.py index 675c7e08b..57e1f1729 100644 --- a/examples/python/lattice/simple/build-xml.py +++ b/examples/python/lattice/simple/build-xml.py @@ -157,7 +157,7 @@ plot_file.export_to_xml() # Instantiate a tally mesh mesh = openmc.Mesh(mesh_id=1) -mesh.type = 'rectangular' +mesh.type = 'regular' mesh.dimension = [4, 4] mesh.lower_left = [-2, -2] mesh.width = [1, 1] diff --git a/examples/python/pincell/build-xml.py b/examples/python/pincell/build-xml.py index 9338aff0e..fc9663b90 100644 --- a/examples/python/pincell/build-xml.py +++ b/examples/python/pincell/build-xml.py @@ -189,7 +189,7 @@ settings_file.export_to_xml() # Instantiate a tally mesh mesh = openmc.Mesh(mesh_id=1) -mesh.type = 'rectangular' +mesh.type = 'regular' mesh.dimension = [100, 100, 1] mesh.lower_left = [-0.62992, -0.62992, -1.e50] mesh.upper_right = [0.62992, 0.62992, 1.e50] diff --git a/examples/xml/lattice/nested/tallies.xml b/examples/xml/lattice/nested/tallies.xml index 5730e6b12..89c0774f1 100644 --- a/examples/xml/lattice/nested/tallies.xml +++ b/examples/xml/lattice/nested/tallies.xml @@ -2,7 +2,7 @@ - rectangular + regular 4 4 -2.0 -2.0 1.0 1.0 diff --git a/examples/xml/lattice/simple/tallies.xml b/examples/xml/lattice/simple/tallies.xml index 5730e6b12..89c0774f1 100644 --- a/examples/xml/lattice/simple/tallies.xml +++ b/examples/xml/lattice/simple/tallies.xml @@ -2,7 +2,7 @@ - rectangular + regular 4 4 -2.0 -2.0 1.0 1.0 diff --git a/examples/xml/pincell/tallies.xml b/examples/xml/pincell/tallies.xml index bbfd58836..73242b913 100644 --- a/examples/xml/pincell/tallies.xml +++ b/examples/xml/pincell/tallies.xml @@ -1,7 +1,7 @@ - + 100 100 1 -0.62992 -0.62992 -1.e50 0.62992 0.62992 1.e50 @@ -13,4 +13,4 @@ flux fission nu-fission - \ No newline at end of file + diff --git a/openmc/constants.py b/openmc/constants.py deleted file mode 100644 index a6b535e6d..000000000 --- a/openmc/constants.py +++ /dev/null @@ -1,123 +0,0 @@ -"""Dictionaries of integer-to-string mappings from openmc/src/constants.F90""" - -SURFACE_TYPES = {1: 'x-plane', - 2: 'y-plane', - 3: 'z-plane', - 4: 'plane', - 5: 'x-cylinder', - 6: 'y-cylinder', - 7: 'z-cylinder', - 8: 'sphere', - 9: 'x-cone', - 10: 'y-cone', - 11: 'z-cone'} - -BC_TYPES = {0: 'transmission', - 1: 'vacuum', - 2: 'reflective', - 3: 'periodic'} - -FILL_TYPES = {1: 'normal', - 2: 'fill', - 3: 'lattice'} - -LATTICE_TYPES = {1: 'rectangular', - 2: 'hexagonal'} - -ESTIMATOR_TYPES = {1: 'analog', - 2: 'tracklength'} - -FILTER_TYPES = {1: 'universe', - 2: 'material', - 3: 'cell', - 4: 'cellborn', - 5: 'surface', - 6: 'mesh', - 7: 'energy', - 8: 'energyout', - 9: 'distribcell'} - -SCORE_TYPES = {-1: 'flux', - -2: 'total', - -3: 'scatter', - -4: 'nu-scatter', - -5: 'scatter-n', - -6: 'scatter-pn', - -7: 'nu-scatter-n', - -8: 'nu-scatter-pn', - -9: 'transport', - -10: 'n1n', - -11: 'absorption', - -12: 'fission', - -13: 'nu-fission', - -14: 'kappa-fission', - -15: 'current', - -16: 'flux-yn', - -17: 'total-yn', - -18: 'scatter-yn', - -19: 'nu-scatter-yn', - -20: 'events', - 1: '(n,total)', - 2: '(n,elastic)', - 4: '(n,level)', - 11: '(n,2nd)', - 16: '(n,2n)', - 17: '(n,3n)', - 18: '(n,fission)', - 19: '(n,f)', - 20: '(n,nf)', - 21: '(n,2nf)', - 22: '(n,na)', - 23: '(n,n3a)', - 24: '(n,2na)', - 25: '(n,3na)', - 28: '(n,np)', - 29: '(n,n2a)', - 30: '(n,2n2a)', - 32: '(n,nd)', - 33: '(n,nt)', - 34: '(n,nHe-3)', - 35: '(n,nd2a)', - 36: '(n,nt2a)', - 37: '(n,4n)', - 38: '(n,3nf)', - 41: '(n,2np)', - 42: '(n,3np)', - 44: '(n,n2p)', - 45: '(n,npa)', - 91: '(n,nc)', - 101: '(n,disappear)', - 102: '(n,gamma)', - 103: '(n,p)', - 104: '(n,d)', - 105: '(n,t)', - 106: '(n,3He)', - 107: '(n,a)', - 108: '(n,2a)', - 109: '(n,3a)', - 111: '(n,2p)', - 112: '(n,pa)', - 113: '(n,t2a)', - 114: '(n,d2a)', - 115: '(n,pd)', - 116: '(n,pt)', - 117: '(n,da)', - 201: '(n,Xn)', - 202: '(n,Xgamma)', - 203: '(n,Xp)', - 204: '(n,Xd)', - 205: '(n,Xt)', - 206: '(n,X3He)', - 207: '(n,Xa)', - 444: '(damage)', - 649: '(n,pc)', - 699: '(n,dc)', - 749: '(n,tc)', - 799: '(n,3Hec)', - 849: '(n,tc)'} -SCORE_TYPES.update({MT: '(n,n' + str(MT-50) + ')' for MT in range(51,91)}) -SCORE_TYPES.update({MT: '(n,p' + str(MT-600) + ')' for MT in range(600,649)}) -SCORE_TYPES.update({MT: '(n,d' + str(MT-650) + ')' for MT in range(650,699)}) -SCORE_TYPES.update({MT: '(n,t' + str(MT-700) + ')' for MT in range(700,749)}) -SCORE_TYPES.update({MT: '(n,3He' + str(MT-750) + ')' for MT in range(750,649)}) -SCORE_TYPES.update({MT: '(n,a' + str(MT-800) + ')' for MT in range(800,849)}) diff --git a/openmc/filter.py b/openmc/filter.py index 5a8190676..6dd4bdaff 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -5,9 +5,11 @@ from numbers import Real, Integral import numpy as np from openmc import Mesh -from openmc.constants import * from openmc.checkvalue import check_type, check_iterable_type, \ - check_greater_than + check_greater_than, _isinstance + +_FILTER_TYPES = ['universe', 'material', 'cell', 'cellborn', 'surface', + 'mesh', 'energy', 'energyout', 'distribcell'] class Filter(object): """A filter used to constrain a tally to a specific criterion, e.g. only tally @@ -109,7 +111,7 @@ class Filter(object): def type(self, type): if type is None: self._type = type - elif type not in FILTER_TYPES.values(): + elif type not in _FILTER_TYPES: msg = 'Unable to set Filter type to "{0}" since it is not one ' \ 'of the supported types'.format(type) raise ValueError(msg) @@ -126,7 +128,7 @@ class Filter(object): raise ValueError(msg) # If the bin edge is a single value, it is a Cell, Material, etc. ID - if not isinstance(bins, Iterable): + if not _isinstance(bins, Iterable): bins = [bins] # If the bins are in a collection, convert it to a list @@ -141,7 +143,7 @@ class Filter(object): elif self._type in ['energy', 'energyout']: for edge in bins: - if not isinstance(edge, Real): + if not _isinstance(edge, Real): msg = 'Unable to add bin edge "{0}" to a "{1}" Filter ' \ 'since it is a non-integer or floating point ' \ 'value'.format(edge, self.type) @@ -165,7 +167,7 @@ class Filter(object): msg = 'Unable to add bins "{0}" to a mesh Filter since ' \ 'only a single mesh can be used per tally'.format(bins) raise ValueError(msg) - elif not isinstance(bins[0], Integral): + elif not _isinstance(bins[0], Integral): msg = 'Unable to add bin "{0}" to mesh Filter since it ' \ 'is a non-integer'.format(bins[0]) raise ValueError(msg) diff --git a/openmc/mesh.py b/openmc/mesh.py index 7e907aaa5..2fe873d2b 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -54,7 +54,7 @@ class Mesh(object): # Initialize Mesh class attributes self.id = mesh_id self.name = name - self._type = 'rectangular' + self._type = 'regular' self._dimension = None self._lower_left = None self._upper_right = None @@ -156,7 +156,7 @@ class Mesh(object): check_type('type for mesh ID="{0}"'.format(self._id), meshtype, basestring) check_value('type for mesh ID="{0}"'.format(self._id), - meshtype, ['rectangular', 'hexagonal']) + meshtype, ['regular']) self._type = meshtype @dimension.setter diff --git a/openmc/particle_restart.py b/openmc/particle_restart.py index d664de1ae..72bf3ac3d 100644 --- a/openmc/particle_restart.py +++ b/openmc/particle_restart.py @@ -12,10 +12,6 @@ class Particle(object): Attributes ---------- - filetype : int - Integer indicating the file type - revision : int - Revision of the particle restart format current_batch : int The batch containing the particle gen_per_batch : int @@ -40,70 +36,55 @@ class Particle(object): """ def __init__(self, filename): - if filename.endswith('.h5'): - import h5py - self._f = h5py.File(filename, 'r') - self._hdf5 = True - else: - self._f = open(filename, 'rb') - self._hdf5 = False + import h5py + self._f = h5py.File(filename, 'r') - # Read all metadata - self._read_data() + # Ensure filetype and revision are correct + if 'filetype' not in self._f or self._f[ + 'filetype'].value.decode() != 'particle restart': + raise IOError('{} is not a particle restart file.'.format(filename)) + if self._f['revision'].value != 1: + raise IOError('Particle restart file has a file revision of {} ' + 'which is not consistent with the revision this ' + 'version of OpenMC expects ({}).'.format( + self._f['revision'].value, 1)) - def _read_data(self): - # Read filetype - self.filetype = self._get_int(path='filetype')[0] + @property + def current_batch(self): + return self._f['current_batch'].value - # Read statepoint revision - self.revision = self._get_int(path='revision')[0] + @property + def current_gen(self): + return self._f['current_gen'].value - # Read current batch - self.current_batch = self._get_int(path='current_batch')[0] + @property + def energy(self): + return self._f['energy'].value - # Read run information - self.gen_per_batch = self._get_int(path='gen_per_batch')[0] - self.current_gen = self._get_int(path='current_gen')[0] - self.n_particles = self._get_long(path='n_particles')[0] - self.run_mode = self._get_int(path='run_mode')[0] + @property + def gen_per_batch(self): + return self._f['gen_per_batch'].value - # Read particle properties - self.id = self._get_long(path='id')[0] - self.weight = self._get_double(path='weight')[0] - self.energy = self._get_double(path='energy')[0] - self.xyz = self._get_double(3, path='xyz') - self.uvw = self._get_double(3, path='uvw') + @property + def id(self): + return self._f['id'].value - def _get_data(self, n, typeCode, size): - return list(struct.unpack('={0}{1}'.format(n, typeCode), - self._f.read(n*size))) + @property + def n_particles(self): + return self._f['n_particles'].value - def _get_int(self, n=1, path=None): - if self._hdf5: - return [int(v) for v in self._f[path].value] - else: - return [int(v) for v in self._get_data(n, 'i', 4)] + @property + def run_mode(self): + return self._f['run_mode'].value.decode() - def _get_long(self, n=1, path=None): - if self._hdf5: - return [int(v) for v in self._f[path].value] - else: - return [int(v) for v in self._get_data(n, 'q', 8)] + @property + def uvw(self): + return self._f['uvw'].value - def _get_float(self, n=1, path=None): - if self._hdf5: - return [float(v) for v in self._f[path].value] - else: - return [float(v) for v in self._get_data(n, 'f', 4)] + @property + def weight(self): + return self._f['weight'].value - def _get_double(self, n=1, path=None): - if self._hdf5: - return [float(v) for v in self._f[path].value] - else: - return [float(v) for v in self._get_data(n, 'd', 8)] - - def _get_string(self, n=1, path=None): - if self._hdf5: - return str(self._f[path].value) - else: - return str(self._get_data(n, 's', 1)[0]) + @property + def xyz(self): + return self._f['xyz'].value diff --git a/openmc/statepoint.py b/openmc/statepoint.py index 6a4713e91..133bd766c 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -1,64 +1,14 @@ import copy -import struct import sys import numpy as np -import scipy.stats import openmc -from openmc.constants import * if sys.version > '3': long = int -class SourceSite(object): - """A single source site produced from fission. - - Attributes - ---------- - weight : float - Weight of the particle arising from the site - xyz : list of float - Cartesian coordinates of the site - uvw : list of float - Directional cosines for particles emerging from the site - E : float - Energy of the emerging particle in MeV - - """ - - def __init__(self): - self._weight = None - self._xyz = None - self._uvw = None - self._E = None - - def __repr__(self): - string = 'SourceSite\n' - string += '{0: <16}{1}{2}\n'.format('\tweight', '=\t', self._weight) - string += '{0: <16}{1}{2}\n'.format('\tE', '=\t', self._E) - string += '{0: <16}{1}{2}\n'.format('\t(x,y,z)', '=\t', self._xyz) - string += '{0: <16}{1}{2}\n'.format('\t(u,v,w)', '=\t', self._uvw) - return string - - @property - def weight(self): - return self._weight - - @property - def xyz(self): - return self._xyz - - @property - def uvw(self): - return self._uvw - - @property - def E(self): - return self._E - - class StatePoint(object): """State information on a simulation at a certain point in time (at the end of a given batch). Statepoints can be used to analyze tally results as well as @@ -66,560 +16,450 @@ class StatePoint(object): Attributes ---------- + cmfd_on : bool + Indicate whether CMFD is active + cmfd_balance : ndarray + Residual neutron balance for each batch + cmfd_dominance + Dominance ratio for each batch + cmfd_entropy : ndarray + Shannon entropy of CMFD fission source for each batch + cmfd_indices : ndarray + Number of CMFD mesh cells and energy groups. The first three indices + correspond to the x-, y-, and z- spatial directions and the fourth index + is the number of energy groups. + cmfd_srccmp : ndarray + Root-mean-square difference between OpenMC and CMFD fission source for + each batch + cmfd_src : ndarray + CMFD fission source distribution over all mesh cells and energy groups. + current_batch : int + Number of batches simulated + date_and_time : str + Date and time when simulation began + entropy : ndarray + Shannon entropy of fission source at each batch + gen_per_batch : int + Number of fission generations per batch + global_tallies : ndarray of compound datatype + Global tallies for k-effective estimates and leakage. The compound + datatype has fields 'name', 'sum', 'sum_sq', 'mean', and 'std_dev'. k_combined : list Combined estimator for k-effective and its uncertainty - n_particles : int - Number of particles per generation + k_col_abs : float + Cross-product of collision and absorption estimates of k-effective + k_col_tra : float + Cross-product of collision and tracklength estimates of k-effective + k_abs_tra : float + Cross-product of absorption and tracklength estimates of k-effective + k_generation : ndarray + Estimate of k-effective for each batch/generation + meshes : dict + Dictionary whose keys are mesh IDs and whose values are Mesh objects n_batches : int Number of batches - current_batch : - Number of batches simulated - results : bool - Indicate whether tally results have been read - source : ndarray of SourceSite - Array of source sites - with_summary : bool - Indicate whether statepoint data has been linked against a summary file + n_inactive : int + Number of inactive batches + n_particles : int + Number of particles per generation + n_realizations : int + Number of tally realizations + path : str + Working directory for simulation + run_mode : str + Simulation run mode, e.g. 'k-eigenvalue' + seed : int + Pseudorandom number generator seed + source : ndarray of compound datatype + Array of source sites. The compound datatype has fields 'wgt', 'xyz', + 'uvw', and 'E' corresponding to the weight, position, direction, and + energy of the source site. + source_present : bool + Indicate whether source sites are present tallies : dict Dictionary whose keys are tally IDs and whose values are Tally objects tallies_present : bool Indicate whether user-defined tallies are present - global_tallies : ndarray - Global tallies and their uncertainties - n_realizations : int - Number of tally realizations + version: tuple of int + Version of OpenMC + with_summary : bool + Indicate whether statepoint data has been linked against a summary file """ def __init__(self, filename): - if filename.endswith('.h5'): - import h5py - self._f = h5py.File(filename, 'r') - self._hdf5 = True - else: - self._f = open(filename, 'rb') - self._hdf5 = False + import h5py + self._f = h5py.File(filename, 'r') + + # Ensure filetype and revision are correct + if 'filetype' not in self._f or self._f[ + 'filetype'].value.decode() != 'statepoint': + raise IOError('{} is not a statepoint file.'.format(filename)) + if self._f['revision'].value != 14: + raise IOError('Statepoint file has a file revision of {} ' + 'which is not consistent with the revision this ' + 'version of OpenMC expects ({}).'.format( + self._f['revision'].value, 14)) # Set flags for what data has been read - self._results = False - self._source = False + self._meshes_read = False + self._tallies_read = False self._with_summary = False - - # Read all metadata - self._read_metadata() - - # Read information about tally meshes - self._read_meshes() - - # Read tally metadata - self._read_tallies() + self._global_tallies = None def close(self): self._f.close() @property - def k_combined(self): - return self._k_combined + def cmfd_on(self): + return self._f['cmfd_on'].value > 0 @property - def n_particles(self): - return self._n_particles + def cmfd_balance(self): + if self.cmfd_on: + return self._f['cmfd/cmfd_balance'].value + else: + return None @property - def n_batches(self): - return self._n_batches + def cmfd_dominance(self): + if self.cmfd_on: + return self._f['cmfd/cmfd_dominance'].value + else: + return None + + @property + def cmfd_entropy(self): + if self.cmfd_on: + return self._f['cmfd/cmfd_entropy'].value + else: + return None + + @property + def cmfd_indices(self): + if self.cmfd_on: + return self._f['cmfd/indices'].value + else: + return None + + @property + def cmfd_src(self): + if self.cmfd_on: + data = self._f['cmfd/cmfd_src'].value + return np.reshape(data, tuple(self.cmfd_indices), order='F') + else: + return None + + @property + def cmfd_srccmp(self): + if self.cmfd_on: + return self._f['cmfd/cmfd_srccmp'].value + else: + return None @property def current_batch(self): - return self._current_batch + return self._f['current_batch'].value @property - def results(self): - return self._results + def date_and_time(self): + return self._f['date_and_time'].value.decode() + + @property + def entropy(self): + if self.run_mode == 'k-eigenvalue': + return self._f['entropy'].value + else: + return None + + @property + def gen_per_batch(self): + if self.run_mode == 'k-eigenvalue': + return self._f['gen_per_batch'].value + else: + return None + + @property + def global_tallies(self): + if self._global_tallies is None: + data = self._f['global_tallies'].value + gt = np.zeros_like(data, dtype=[ + ('name', 'a14'), ('sum', 'f8'), ('sum_sq', 'f8'), + ('mean', 'f8'), ('std_dev', 'f8')]) + gt['name'] = ['k-collision', 'k-absorption', 'k-tracklength', + 'leakage'] + gt['sum'] = data['sum'] + gt['sum_sq'] = data['sum_sq'] + + # Calculate mean and sample standard deviation of mean + n = self.n_realizations + gt['mean'] = gt['sum']/n + gt['std_dev'] = np.sqrt((gt['sum_sq']/n - gt['mean']**2)/(n - 1)) + + self._global_tallies = gt + + return self._global_tallies + + @property + def k_cmfd(self): + if self.cmfd_on: + return self._f['cmfd/k_cmfd'].value + else: + return None + + @property + def k_generation(self): + if self.run_mode == 'k-eigenvalue': + return self._f['k_generation'].value + else: + return None + + @property + def k_combined(self): + if self.run_mode == 'k-eigenvalue': + return self._f['k_combined'].value + else: + return None + + @property + def k_col_abs(self): + if self.run_mode == 'k-eigenvalue': + return self._f['k_col_abs'].value + else: + return None + + @property + def k_col_tra(self): + if self.run_mode == 'k-eigenvalue': + return self._f['k_col_tra'].value + else: + return None + + @property + def k_abs_tra(self): + if self.run_mode == 'k-eigenvalue': + return self._f['k_abs_tra'].value + else: + return None + + @property + def meshes(self): + if not self._meshes_read: + # Initialize dictionaries for the Meshes + # Keys - Mesh IDs + # Values - Mesh objects + self._meshes = {} + + # Read the number of Meshes + n_meshes = self._f['tallies/meshes/n_meshes'].value + + # Read a list of the IDs for each Mesh + if n_meshes > 0: + # User-defined Mesh IDs + mesh_keys = self._f['tallies/meshes/keys'].value + else: + mesh_keys = [] + + # Build dictionary of Meshes + base = 'tallies/meshes/mesh ' + + # Iterate over all Meshes + for mesh_key in mesh_keys: + # Read the mesh type + mesh_type = self._f['{0}{1}/type'.format(base, mesh_key)].value.decode() + + # Read the mesh dimensions, lower-left coordinates, + # upper-right coordinates, and width of each mesh cell + dimension = self._f['{0}{1}/dimension'.format(base, mesh_key)].value + lower_left = self._f['{0}{1}/lower_left'.format(base, mesh_key)].value + upper_right = self._f['{0}{1}/upper_right'.format(base, mesh_key)].value + width = self._f['{0}{1}/width'.format(base, mesh_key)].value + + # Create the Mesh and assign properties to it + mesh = openmc.Mesh(mesh_key) + mesh.dimension = dimension + mesh.width = width + mesh.lower_left = lower_left + mesh.upper_right = upper_right + mesh.type = mesh_type + + # Add mesh to the global dictionary of all Meshes + self._meshes[mesh_key] = mesh + + self._meshes_read = True + + return self._meshes + + @property + def n_batches(self): + return self._f['n_batches'].value + + @property + def n_inactive(self): + if self.run_mode == 'k-eigenvalue': + return self._f['n_inactive'].value + else: + return None + + @property + def n_particles(self): + return self._f['n_particles'].value + + @property + def n_realizations(self): + return self._f['n_realizations'].value + + @property + def path(self): + return self._f['path'].value.decode() + + @property + def run_mode(self): + return self._f['run_mode'].value.decode() + + @property + def seed(self): + return self._f['seed'].value @property def source(self): - return self._source + if self.source_present: + return self._f['source_bank'].value + else: + return None @property - def with_summary(self): - return self._with_summary + def source_present(self): + return self._f['source_present'].value > 0 @property def tallies(self): + if not self._tallies_read: + # Initialize dictionary for tallies + self._tallies = {} + + # Read the number of tallies + n_tallies = self._f['tallies/n_tallies'].value + + # Read a list of the IDs for each Tally + if n_tallies > 0: + # OpenMC Tally IDs (redefined internally from user definitions) + tally_keys = self._f['tallies/keys'].value + else: + tally_keys = [] + + base = 'tallies/tally ' + + # Iterate over all Tallies + for tally_key in tally_keys: + + # Read the Tally size specifications + n_realizations = self._f['{0}{1}/n_realizations'.format(base, tally_key)].value + + # Create Tally object and assign basic properties + tally = openmc.Tally(tally_id=tally_key) + tally._statepoint = self + tally.estimator = self._f['{0}{1}/estimator'.format( + base, tally_key)].value.decode() + tally.num_realizations = n_realizations + + # Read the number of Filters + n_filters = self._f['{0}{1}/n_filters'.format(base, tally_key)].value + + subbase = '{0}{1}/filter '.format(base, tally_key) + + # Initialize all Filters + for j in range(1, n_filters+1): + + # Read the Filter type + filter_type = self._f['{0}{1}/type'.format(subbase, j)].value.decode() + + # Read the Filter offset + offset = self._f['{0}{1}/offset'.format(subbase, j)].value + + n_bins = self._f['{0}{1}/n_bins'.format(subbase, j)].value + + # Read the bin values + bins = self._f['{0}{1}/bins'.format(subbase, j)].value + + # Create Filter object + filter = openmc.Filter(filter_type, bins) + filter.offset = offset + filter.num_bins = n_bins + + if filter_type == 'mesh': + mesh_ids = self._f['tallies/meshes/ids'].value + mesh_keys = self._f['tallies/meshes/keys'].value + + key = mesh_keys[mesh_ids == bins][0] + filter.mesh = self.meshes[key] + + # Add Filter to the Tally + tally.add_filter(filter) + + # Read Nuclide bins + nuclide_names = self._f['{0}{1}/nuclides'.format(base, tally_key)].value + + # Add all Nuclides to the Tally + for name in nuclide_names: + nuclide = openmc.Nuclide(name.decode().strip()) + tally.add_nuclide(nuclide) + + # Read score bins + n_score_bins = self._f['{0}{1}/n_score_bins'.format(base, tally_key)].value + + tally.num_score_bins = n_score_bins + + scores = self._f['{0}{1}/score_bins'.format( + base, tally_key)].value + n_user_scores = self._f['{0}{1}/n_user_score_bins' + .format(base, tally_key)].value + + # Compute and set the filter strides + for i in range(n_filters): + filter = tally.filters[i] + filter.stride = n_score_bins * len(nuclide_names) + + for j in range(i+1, n_filters): + filter.stride *= tally.filters[j].num_bins + + # Read scattering moment order strings (e.g., P3, Y-1,2, etc.) + moments = self._f['{0}{1}/moment_orders'.format( + base, tally_key)].value + + # Add the scores to the Tally + for j, score in enumerate(scores): + score = score.decode() + # If this is a scattering moment, insert the scattering order + if '-n' in score: + score = score.replace('-n', '-' + moments[j].decode()) + elif '-pn' in score: + score = score.replace('-pn', '-' + moments[j].decode()) + elif '-yn' in score: + score = score.replace('-yn', '-' + moments[j].decode()) + + tally.add_score(score) + + # Add Tally to the global dictionary of all Tallies + self._tallies[tally_key] = tally + + self._tallies_read = True + return self._tallies @property def tallies_present(self): - return self._tallies_present + return self._f['tallies/tallies_present'].value @property - def global_tallies(self): - return self._global_tallies + def version(self): + return (self._f['version_major'].value, + self._f['version_minor'].value, + self._f['version_release'].value) @property - def n_realizations(self): - return self._n_realizations - - def _read_metadata(self): - # Read filetype - self._filetype = self._get_int(path='filetype')[0] - - # Read statepoint revision - self._revision = self._get_int(path='revision')[0] - if self._revision != 13: - raise Exception('Statepoint Revision is not consistent.') - - # Read OpenMC version - if self._hdf5: - self._version = [self._get_int(path='version_major')[0], - self._get_int(path='version_minor')[0], - self._get_int(path='version_release')[0]] - else: - self._version = self._get_int(3) - - # Read date and time - self._date_and_time = self._get_string(19, path='date_and_time') - - # Read path - self._path = self._get_string(255, path='path').strip() - - # Read random number seed - self._seed = self._get_long(path='seed')[0] - - # Read run information - self._run_mode = self._get_int(path='run_mode')[0] - self._n_particles = self._get_long(path='n_particles')[0] - self._n_batches = self._get_int(path='n_batches')[0] - - # Read current batch - self._current_batch = self._get_int(path='current_batch')[0] - - # Read whether or not the source site distribution is present - self._source_present = self._get_int(path='source_present')[0] - - # Read criticality information - if self._run_mode == 2: - self._read_criticality() - - def _read_criticality(self): - # Read criticality information - if self._run_mode == 2: - - self._n_inactive = self._get_int(path='n_inactive')[0] - self._gen_per_batch = self._get_int(path='gen_per_batch')[0] - self._k_batch = self._get_double( - self._current_batch*self._gen_per_batch, - path='k_generation') - self._entropy = self._get_double( - self._current_batch*self._gen_per_batch, path='entropy') - - self._k_col_abs = self._get_double(path='k_col_abs')[0] - self._k_col_tra = self._get_double(path='k_col_tra')[0] - self._k_abs_tra = self._get_double(path='k_abs_tra')[0] - self._k_combined = self._get_double(2, path='k_combined') - - # Read CMFD information (if used) - self._read_cmfd() - - def _read_cmfd(self): - base = 'cmfd' - - # Read CMFD information - self._cmfd_on = self._get_int(path='cmfd_on')[0] - - if self._cmfd_on == 1: - - self._cmfd_indices = self._get_int(4, path='{0}/indices'.format(base)) - self._k_cmfd = self._get_double(self._current_batch, - path='{0}/k_cmfd'.format(base)) - self._cmfd_src = self._get_double_array(np.product(self._cmfd_indices), - path='{0}/cmfd_src'.format(base)) - self._cmfd_src = np.reshape(self._cmfd_src, tuple(self._cmfd_indices), - order='F') - self._cmfd_entropy = self._get_double(self._current_batch, - path='{0}/cmfd_entropy'.format(base)) - self._cmfd_balance = self._get_double(self._current_batch, - path='{0}/cmfd_balance'.format(base)) - self._cmfd_dominance = self._get_double(self._current_batch, - path='{0}/cmfd_dominance'.format(base)) - self._cmfd_srccmp = self._get_double(self._current_batch, - path='{0}/cmfd_srccmp'.format(base)) - - def _read_meshes(self): - # Initialize dictionaries for the Meshes - # Keys - Mesh IDs - # Values - Mesh objects - self._meshes = {} - - # Read the number of Meshes - self._n_meshes = self._get_int(path='tallies/meshes/n_meshes')[0] - - # Read a list of the IDs for each Mesh - if self._n_meshes > 0: - - # OpenMC Mesh IDs (redefined internally from user definitions) - self._mesh_ids = self._get_int(self._n_meshes, - path='tallies/meshes/ids') - - # User-defined Mesh IDs - self._mesh_keys = self._get_int(self._n_meshes, - path='tallies/meshes/keys') - - else: - self._mesh_keys = [] - self._mesh_ids = [] - - # Build dictionary of Meshes - base = 'tallies/meshes/mesh ' - - # Iterate over all Meshes - for mesh_key in self._mesh_keys: - - # Read the user-specified Mesh ID and type - mesh_id = self._get_int(path='{0}{1}/id'.format(base, mesh_key))[0] - mesh_type = self._get_int(path='{0}{1}/type'.format(base, mesh_key))[0] - - # Get the Mesh dimension - n_dimension = self._get_int( - path='{0}{1}/n_dimension'.format(base, mesh_key))[0] - - # Read the mesh dimensions, lower-left coordinates, - # upper-right coordinates, and width of each mesh cell - dimension = self._get_int( - n_dimension, path='{0}{1}/dimension'.format(base, mesh_key)) - lower_left = self._get_double( - n_dimension, path='{0}{1}/lower_left'.format(base, mesh_key)) - upper_right = self._get_double( - n_dimension, path='{0}{1}/upper_right'.format(base, mesh_key)) - width = self._get_double( - n_dimension, path='{0}{1}/width'.format(base, mesh_key)) - - # Create the Mesh and assign properties to it - mesh = openmc.Mesh(mesh_id) - - mesh.dimension = dimension - mesh.width = width - mesh.lower_left = lower_left - mesh.upper_right = upper_right - - #FIXME: Set the mesh type to 'rectangular' by default - mesh.type = 'rectangular' - - # Add mesh to the global dictionary of all Meshes - self._meshes[mesh_id] = mesh - - def _read_tallies(self): - # Initialize dictionaries for the Tallies - # Keys - Tally IDs - # Values - Tally objects - self._tallies = {} - - # Read the number of tallies - self._n_tallies = self._get_int(path='/tallies/n_tallies')[0] - - # Read a list of the IDs for each Tally - if self._n_tallies > 0: - - # OpenMC Tally IDs (redefined internally from user definitions) - self._tally_ids = self._get_int( - self._n_tallies, path='tallies/ids') - - # User-defined Tally IDs - self._tally_keys = self._get_int( - self._n_tallies, path='tallies/keys') - - else: - self._tally_keys = [] - self._tally_ids = [] - - base = 'tallies/tally ' - - # Iterate over all Tallies - for tally_key in self._tally_keys: - - # Read integer Tally estimator type code (analog or tracklength) - estimator_type = self._get_int( - path='{0}{1}/estimator'.format(base, tally_key))[0] - - # Read the Tally size specifications - n_realizations = self._get_int( - path='{0}{1}/n_realizations'.format(base, tally_key))[0] - - # Create Tally object and assign basic properties - tally = openmc.Tally(tally_key) - tally.estimator = ESTIMATOR_TYPES[estimator_type] - tally.num_realizations = n_realizations - - # Read the number of Filters - n_filters = self._get_int( - path='{0}{1}/n_filters'.format(base, tally_key))[0] - - subbase = '{0}{1}/filter '.format(base, tally_key) - - # Initialize all Filters - for j in range(1, n_filters+1): - - # Read the integer Filter type code - filter_type = self._get_int( - path='{0}{1}/type'.format(subbase, j))[0] - - # Read the Filter offset - offset = self._get_int( - path='{0}{1}/offset'.format(subbase, j))[0] - - n_bins = self._get_int( - path='{0}{1}/n_bins'.format(subbase, j))[0] - - if n_bins <= 0: - msg = 'Unable to create Filter "{0}" for Tally ID="{1}" ' \ - 'since no bins were specified'.format(j, tally_key) - raise ValueError(msg) - - # Read the bin values - if FILTER_TYPES[filter_type] in ['energy', 'energyout']: - bins = self._get_double( - n_bins+1, path='{0}{1}/bins'.format(subbase, j)) - - elif FILTER_TYPES[filter_type] in ['mesh', 'distribcell']: - bins = self._get_int( - path='{0}{1}/bins'.format(subbase, j))[0] - - else: - bins = self._get_int( - n_bins, path='{0}{1}/bins'.format(subbase, j)) - - # Create Filter object - filter = openmc.Filter(FILTER_TYPES[filter_type], bins) - filter.offset = offset - filter.num_bins = n_bins - - if FILTER_TYPES[filter_type] == 'mesh': - key = self._mesh_keys[self._mesh_ids.index(bins)] - filter.mesh = self._meshes[key] - - # Add Filter to the Tally - tally.add_filter(filter) - - # Read Nuclide bins - n_nuclides = self._get_int( - path='{0}{1}/n_nuclides'.format(base, tally_key))[0] - - nuclide_zaids = self._get_int( - n_nuclides, path='{0}{1}/nuclides'.format(base, tally_key)) - - # Add all Nuclides to the Tally - for nuclide_zaid in nuclide_zaids: - tally.add_nuclide(nuclide_zaid) - - # Read score bins - n_score_bins = self._get_int( - path='{0}{1}/n_score_bins'.format(base, tally_key))[0] - - tally.num_score_bins = n_score_bins - - scores = [SCORE_TYPES[j] for j in self._get_int( - n_score_bins, path='{0}{1}/score_bins'.format(base, tally_key))] - n_user_scores = self._get_int( - path='{0}{1}/n_user_score_bins'.format(base, tally_key))[0] - - # Compute and set the filter strides - for i in range(n_filters): - filter = tally.filters[i] - filter.stride = n_score_bins * n_nuclides - - for j in range(i+1, n_filters): - filter.stride *= tally.filters[j].num_bins - - # Read scattering moment order strings (e.g., P3, Y-1,2, etc.) - moments = [] - subbase = '{0}{1}/moments/'.format(base, tally_key) - - # Extract the moment order string for each score - for k in range(len(scores)): - moment = self._get_string(8, - path='{0}order{1}'.format(subbase, k+1)) - moment = moment.lstrip('[\'') - moment = moment.rstrip('\']') - - # Remove extra whitespace - moment.replace(" ", "") - moments.append(moment) - - # Add the scores to the Tally - for j, score in enumerate(scores): - # If this is a scattering moment, insert the scattering order - if '-n' in score: - score = score.replace('-n', '-' + str(moments[j])) - elif '-pn' in score: - score = score.replace('-pn', '-' + str(moments[j])) - elif '-yn' in score: - score = score.replace('-yn', '-' + str(moments[j])) - - tally.add_score(score) - - # Add Tally to the global dictionary of all Tallies - self.tallies[tally_key] = tally - - def read_results(self): - """Read tally results and store them in the ``tallies`` attribute. No results - are read when the statepoint is instantiated. - - """ - - # Number of realizations for global Tallies - self._n_realizations = self._get_int(path='n_realizations')[0] - - # Read global Tallies - n_global_tallies = self._get_int(path='n_global_tallies')[0] - - if self._hdf5: - data = self._f['global_tallies'].value - self._global_tallies = np.column_stack((data['sum'], data['sum_sq'])) - - else: - self._global_tallies = np.array(self._get_double(2*n_global_tallies)) - self._global_tallies.shape = (n_global_tallies, 2) - - # Flag indicating if Tallies are present - self._tallies_present = self._get_int(path='tallies/tallies_present')[0] - - base = 'tallies/tally ' - - # Read Tally results - if self._tallies_present: - - # Iterate over and extract the results for all Tallies - for tally_key in self._tally_keys: - - # Get this Tally - tally = self._tallies[tally_key] - - # Compute the total number of bins for this Tally - num_tot_bins = tally.num_bins - - # Extract Tally data from the file - if self._hdf5: - data = self._f['{0}{1}/results'.format(base, tally_key)].value - sum = data['sum'] - sum_sq = data['sum_sq'] - - else: - results = np.array(self._get_double(2*num_tot_bins)) - sum = results[0::2] - sum_sq = results[1::2] - - # Define a routine to convert 0 to 1 - def nonzero(val): - return 1 if not val else val - - # Reshape the results arrays - new_shape = (nonzero(tally.num_filter_bins), - nonzero(tally.num_nuclides), - nonzero(tally.num_score_bins)) - - sum = np.reshape(sum, new_shape) - sum_sq = np.reshape(sum_sq, new_shape) - - # Set the data for this Tally - tally.sum = sum - tally.sum_sq = sum_sq - - # Indicate that Tally results have been read - self._results = True - - def read_source(self): - """Read and store source sites from the statepoint file. By default, source - sites are not loaded upon initialization. - - """ - - # Check whether Tally results have been read - if not self._results: - self.read_results() - - # Check if source bank is in statepoint - if not self._source_present: - print('Unable to read source since it is not in statepoint file') - return - - # Initialize a NumPy array for the source sites - self._source = np.empty(self._n_particles, dtype=SourceSite) - - # For HDF5 state points, copy entire bank - if self._hdf5: - source_sites = self._f['source_bank'].value - - # Initialize SourceSite object for each particle - for i in range(self._n_particles): - # Initialize new source site - site = SourceSite() - - # Read position, angle, and energy - if self._hdf5: - site._weight, site._xyz, site._uvw, site._E = source_sites[i] - else: - site._weight = self._get_double()[0] - site._xyz = self._get_double(3) - site._uvw = self._get_double(3) - site._E = self._get_double()[0] - - # Store the source site in the NumPy array - self._source[i] = site - - def compute_ci(self, confidence=0.95): - """Computes confidence intervals for each Tally bin. - - This method is equivalent to calling compute_stdev(...) when the - confidence is known as opposed to its corresponding t value. - - Parameters - ---------- - confidence : float, optional - Confidence level. Defaults to 0.95. - - """ - - # Determine significance level and percentile for two-sided CI - alpha = 1 - confidence - percentile = 1 - alpha/2 - - # Calculate t-value - t_value = scipy.stats.t.ppf(percentile, self._n_realizations - 1) - self.compute_stdev(t_value) - - def compute_stdev(self, t_value=1.0): - """Computes the sample mean and the standard deviation of the mean - for each Tally bin. - - Parameters - ---------- - t_value : float, optional - Student's t-value applied to the uncertainty. Defaults to 1.0, - meaning the reported value is the sample standard deviation. - - """ - - # Determine number of realizations - n = self._n_realizations - - # Calculate the standard deviation for each global tally - for i in range(len(self._global_tallies)): - - # Get sum and sum of squares - s, s2 = self._global_tallies[i] - - # Calculate sample mean and replace value - s /= n - self._global_tallies[i, 0] = s - - # Calculate standard deviation - if s != 0.0: - self._global_tallies[i, 1] = t_value * np.sqrt((s2 / n - s**2) / (n-1)) - - # Calculate sample mean and standard deviation for user-defined Tallies - for tally_id, tally in self.tallies.items(): - tally.compute_std_dev(t_value) + def with_summary(self): + return self._with_summary def get_tally(self, scores=[], filters=[], nuclides=[], name=None, id=None, estimator=None): @@ -757,15 +597,6 @@ class StatePoint(object): tally.name = summary.tallies[tally_id].name tally.with_summary = True - nuclide_zaids = copy.deepcopy(tally.nuclides) - - for nuclide_zaid in nuclide_zaids: - tally.remove_nuclide(nuclide_zaid) - if nuclide_zaid == -1: - tally.add_nuclide(openmc.Nuclide('total')) - else: - tally.add_nuclide(summary.nuclides[nuclide_zaid]) - for filter in tally.filters: if filter.type == 'surface': surface_ids = [] @@ -792,43 +623,3 @@ class StatePoint(object): filter.bins = material_ids self._with_summary = True - - def _get_data(self, n, typeCode, size): - return list(struct.unpack('={0}{1}'.format(n, typeCode), - self._f.read(n*size))) - - def _get_int(self, n=1, path=None): - if self._hdf5: - return [int(v) for v in self._f[path].value] - else: - return [int(v) for v in self._get_data(n, 'i', 4)] - - def _get_long(self, n=1, path=None): - if self._hdf5: - return [long(v) for v in self._f[path].value] - else: - return [long(v) for v in self._get_data(n, 'q', 8)] - - def _get_float(self, n=1, path=None): - if self._hdf5: - return [float(v) for v in self._f[path].value] - else: - return [float(v) for v in self._get_data(n, 'f', 4)] - - def _get_double(self, n=1, path=None): - if self._hdf5: - return [float(v) for v in self._f[path].value] - else: - return [float(v) for v in self._get_data(n, 'd', 8)] - - def _get_double_array(self, n=1, path=None): - if self._hdf5: - return self._f[path].value - else: - return self._get_data(n, 'd', 8) - - def _get_string(self, n=1, path=None): - if self._hdf5: - return str(self._f[path].value) - else: - return str(self._get_data(n, 's', 1)[0]) diff --git a/openmc/summary.py b/openmc/summary.py index 7f9d5387e..2ae746484 100644 --- a/openmc/summary.py +++ b/openmc/summary.py @@ -31,22 +31,21 @@ class Summary(object): def _read_metadata(self): # Read OpenMC version - self.version = [self._f['version_major'][0], - self._f['version_minor'][0], - self._f['version_release'][0]] + self.version = [self._f['version_major'].value, + self._f['version_minor'].value, + self._f['version_release'].value] # Read date and time self.date_and_time = self._f['date_and_time'][...] - self.n_batches = self._f['n_batches'][0] - self.n_particles = self._f['n_particles'][0] - self.n_active = self._f['n_active'][0] - self.n_inactive = self._f['n_inactive'][0] - self.gen_per_batch = self._f['gen_per_batch'][0] - self.n_procs = self._f['n_procs'][0] + self.n_batches = self._f['n_batches'].value + self.n_particles = self._f['n_particles'].value + self.n_active = self._f['n_active'].value + self.n_inactive = self._f['n_inactive'].value + self.gen_per_batch = self._f['gen_per_batch'].value + self.n_procs = self._f['n_procs'].value def _read_geometry(self): # Read in and initialize the Materials and Geometry - self._read_nuclides() self._read_materials() self._read_surfaces() self._read_cells() @@ -54,37 +53,8 @@ class Summary(object): self._read_lattices() self._finalize_geometry() - def _read_nuclides(self): - self.n_nuclides = self._f['nuclides/n_nuclides'][0] - - # Initialize dictionary for each Nuclide - # Keys - Nuclide ZAIDs - # Values - Nuclide objects - self.nuclides = {} - - for key in self._f['nuclides'].keys(): - if key == 'n_nuclides': - continue - - index = self._f['nuclides'][key]['index'][0] - alias = self._f['nuclides'][key]['alias'][0] - zaid = self._f['nuclides'][key]['zaid'][0] - - # Read the Nuclide's name (e.g., 'H-1' or 'U-235') - name = alias.split('.')[0] - - # Read the Nuclide's cross-section identifier (e.g., '70c') - xs = alias.split('.')[1] - - # Initialize this Nuclide and add to global dictionary of Nuclides - if 'nat' in name: - self.nuclides[zaid] = openmc.Element(name=name, xs=xs) - else: - self.nuclides[zaid] = openmc.Nuclide(name=name, xs=xs) - self.nuclides[zaid].zaid = zaid - def _read_materials(self): - self.n_materials = self._f['materials/n_materials'][0] + self.n_materials = self._f['n_materials'].value # Initialize dictionary for each Material # Keys - Material keys @@ -96,23 +66,18 @@ class Summary(object): continue material_id = int(key.lstrip('material ')) - index = self._f['materials'][key]['index'][0] - name = self._f['materials'][key]['name'][0] - density = self._f['materials'][key]['atom_density'][0] + index = self._f['materials'][key]['index'].value + name = self._f['materials'][key]['name'].value.decode() + density = self._f['materials'][key]['atom_density'].value nuc_densities = self._f['materials'][key]['nuclide_densities'][...] - nuclides = self._f['materials'][key]['nuclides'][...] - n_sab = self._f['materials'][key]['n_sab'][0] + nuclides = self._f['materials'][key]['nuclides'].value - sab_names = [] - sab_xs = [] - - # Read the names of the S(a,b) tables for this Material - for i in range(1, n_sab+1): - sab_table = self._f['materials'][key]['sab_tables'][str(i)][0] - - # Read the cross-section identifiers for each S(a,b) table - sab_names.append(sab_table.split('.')[0]) - sab_xs.append(sab_table.split('.')[1]) + # Read the names of the S(a,b) tables for this Material and add them + if 'sab_names' in self._f['materials'][key]: + sab_tables = self._f['materials'][key]['sab_names'].value + for sab_table in sab_tables: + name, xs = sab_table.decode().split('.') + material.add_s_alpha_beta(name, xs) # Create the Material material = openmc.Material(material_id=material_id, name=name) @@ -120,27 +85,23 @@ class Summary(object): # Set the Material's density to g/cm3 - this is what is used in OpenMC material.set_density(density=density, units='g/cm3') - # Add all Nuclides to the Material - for i, zaid in enumerate(nuclides): - nuclide = self.get_nuclide_by_zaid(zaid) - density = nuc_densities[i] + # Add all nuclides to the Material + for fullname, density in zip(nuclides, nuc_densities): + fullname = fullname.decode().strip() + name, xs = fullname.split('.') - if isinstance(nuclide, openmc.Nuclide): - material.add_nuclide(nuclide, percent=density, percent_type='ao') - elif isinstance(nuclide, openmc.Element): - material.add_element(nuclide, percent=density, percent_type='ao') - - # Add S(a,b) table(s?) to the Material - for i in range(n_sab): - name = sab_names[i] - xs = sab_xs[i] - material.add_s_alpha_beta(name, xs) + if 'nat' in name: + material.add_element(openmc.Element(name=name, xs=xs), + percent=density, percent_type='ao') + else: + material.add_nuclide(openmc.Nuclide(name=name, xs=xs), + percent=density, percent_type='ao') # Add the Material to the global dictionary of all Materials self.materials[index] = material def _read_surfaces(self): - self.n_surfaces = self._f['geometry/n_surfaces'][0] + self.n_surfaces = self._f['geometry/n_surfaces'].value # Initialize dictionary for each Surface # Keys - Surface keys @@ -152,75 +113,75 @@ class Summary(object): continue surface_id = int(key.lstrip('surface ')) - index = self._f['geometry/surfaces'][key]['index'][0] - name = self._f['geometry/surfaces'][key]['name'][0] - surf_type = self._f['geometry/surfaces'][key]['type'][...][0] - bc = self._f['geometry/surfaces'][key]['boundary_condition'][...][0] + index = self._f['geometry/surfaces'][key]['index'].value + name = self._f['geometry/surfaces'][key]['name'].value.decode() + surf_type = self._f['geometry/surfaces'][key]['type'].value.decode() + bc = self._f['geometry/surfaces'][key]['boundary_condition'].value.decode() coeffs = self._f['geometry/surfaces'][key]['coefficients'][...] # Create the Surface based on its type - if surf_type == 'X Plane': + if surf_type == 'x-plane': x0 = coeffs[0] surface = openmc.XPlane(surface_id, bc, x0, name) - elif surf_type == 'Y Plane': + elif surf_type == 'y-plane': y0 = coeffs[0] surface = openmc.YPlane(surface_id, bc, y0, name) - elif surf_type == 'Z Plane': + elif surf_type == 'z-plane': z0 = coeffs[0] surface = openmc.ZPlane(surface_id, bc, z0, name) - elif surf_type == 'Plane': + elif surf_type == 'plane': A = coeffs[0] B = coeffs[1] C = coeffs[2] D = coeffs[3] surface = openmc.Plane(surface_id, bc, A, B, C, D, name) - elif surf_type == 'X Cylinder': + elif surf_type == 'x-cylinder': y0 = coeffs[0] z0 = coeffs[1] R = coeffs[2] surface = openmc.XCylinder(surface_id, bc, y0, z0, R, name) - elif surf_type == 'Y Cylinder': + elif surf_type == 'y-cylinder': x0 = coeffs[0] z0 = coeffs[1] R = coeffs[2] surface = openmc.YCylinder(surface_id, bc, x0, z0, R, name) - elif surf_type == 'Z Cylinder': + elif surf_type == 'z-cylinder': x0 = coeffs[0] y0 = coeffs[1] R = coeffs[2] surface = openmc.ZCylinder(surface_id, bc, x0, y0, R, name) - elif surf_type == 'Sphere': + elif surf_type == 'sphere': x0 = coeffs[0] y0 = coeffs[1] z0 = coeffs[2] R = coeffs[3] surface = openmc.Sphere(surface_id, bc, x0, y0, z0, R, name) - elif surf_type in ['X Cone', 'Y Cone', 'Z Cone']: + elif surf_type in ['x-cone', 'y-cone', 'z-cone']: x0 = coeffs[0] y0 = coeffs[1] z0 = coeffs[2] R2 = coeffs[3] - if surf_type == 'X Cone': + if surf_type == 'x-cone': surface = openmc.XCone(surface_id, bc, x0, y0, z0, R2, name) - if surf_type == 'Y Cone': + if surf_type == 'y-cone': surface = openmc.YCone(surface_id, bc, x0, y0, z0, R2, name) - if surf_type == 'Z Cone': + if surf_type == 'z-cone': surface = openmc.ZCone(surface_id, bc, x0, y0, z0, R2, name) # Add Surface to global dictionary of all Surfaces self.surfaces[index] = surface def _read_cells(self): - self.n_cells = self._f['geometry/n_cells'][0] + self.n_cells = self._f['geometry/n_cells'].value # Initialize dictionary for each Cell # Keys - Cell keys @@ -240,16 +201,16 @@ class Summary(object): continue cell_id = int(key.lstrip('cell ')) - index = self._f['geometry/cells'][key]['index'][0] - name = self._f['geometry/cells'][key]['name'][0] - fill_type = self._f['geometry/cells'][key]['fill_type'][...][0] + index = self._f['geometry/cells'][key]['index'].value + name = self._f['geometry/cells'][key]['name'].value.decode() + fill_type = self._f['geometry/cells'][key]['fill_type'].value.decode() if fill_type == 'normal': - fill = self._f['geometry/cells'][key]['material'][0] + fill = self._f['geometry/cells'][key]['material'].value elif fill_type == 'universe': - fill = self._f['geometry/cells'][key]['fill'][0] + fill = self._f['geometry/cells'][key]['fill'].value else: - fill = self._f['geometry/cells'][key]['lattice'][0] + fill = self._f['geometry/cells'][key]['lattice'].value if 'surfaces' in self._f['geometry/cells'][key].keys(): surfaces = self._f['geometry/cells'][key]['surfaces'][...] @@ -260,21 +221,17 @@ class Summary(object): cell = openmc.Cell(cell_id=cell_id, name=name) if fill_type == 'universe': - maps = self._f['geometry/cells'][key]['maps'][0] - - if maps > 0: + if 'offset' in self._f['geometry/cells'][key]: offset = self._f['geometry/cells'][key]['offset'][...] - cell.set_offset(offset) + cell.offsets = offset - translated = self._f['geometry/cells'][key]['translated'][0] - if translated: + if 'translation' in self._f['geometry/cells'][key]: translation = \ self._f['geometry/cells'][key]['translation'][...] translation = np.asarray(translation, dtype=np.float64) cell.translation = translation - rotated = self._f['geometry/cells'][key]['rotated'][0] - if rotated: + if 'rotation' in self._f['geometry/cells'][key]: rotation = \ self._f['geometry/cells'][key]['rotation'][...] rotation = np.asarray(rotation, dtype=np.int) @@ -287,15 +244,15 @@ class Summary(object): for surface_halfspace in surfaces: halfspace = np.sign(surface_halfspace) - surface_id = np.abs(surface_halfspace) - surface = self.surfaces[surface_id] + surface_id = abs(surface_halfspace) + surface = self.get_surface_by_id(surface_id) cell.add_surface(surface, halfspace) # Add the Cell to the global dictionary of all Cells self.cells[index] = cell def _read_universes(self): - self.n_universes = self._f['geometry/n_universes'][0] + self.n_universes = self._f['geometry/n_universes'].value # Initialize dictionary for each Universe # Keys - Universe keys @@ -307,7 +264,7 @@ class Summary(object): continue universe_id = int(key.lstrip('universe ')) - index = self._f['geometry/universes'][key]['index'][0] + index = self._f['geometry/universes'][key]['index'].value cells = self._f['geometry/universes'][key]['cells'][...] # Create this Universe @@ -322,7 +279,7 @@ class Summary(object): self.universes[index] = universe def _read_lattices(self): - self.n_lattices = self._f['geometry/n_lattices'][0] + self.n_lattices = self._f['geometry/n_lattices'].value # Initialize lattices for each Lattice # Keys - Lattice keys @@ -334,21 +291,21 @@ class Summary(object): continue lattice_id = int(key.lstrip('lattice ')) - index = self._f['geometry/lattices'][key]['index'][0] - name = self._f['geometry/lattices'][key]['name'][0] - lattice_type = self._f['geometry/lattices'][key]['type'][...][0] - maps = self._f['geometry/lattices'][key]['maps'][0] - offset_size = self._f['geometry/lattices'][key]['offset_size'][0] + index = self._f['geometry/lattices'][key]['index'].value + name = self._f['geometry/lattices'][key]['name'].value.decode() + lattice_type = self._f['geometry/lattices'][key]['type'].value.decode() - if offset_size > 0: + if 'offsets' in self._f['geometry/lattices'][key]: offsets = self._f['geometry/lattices'][key]['offsets'][...] + else: + offsets = None if lattice_type == 'rectangular': dimension = self._f['geometry/lattices'][key]['dimension'][...] lower_left = \ self._f['geometry/lattices'][key]['lower_left'][...] pitch = self._f['geometry/lattices'][key]['pitch'][...] - outer = self._f['geometry/lattices'][key]['outer'][0] + outer = self._f['geometry/lattices'][key]['outer'].value universe_ids = \ self._f['geometry/lattices'][key]['universes'][...] @@ -382,7 +339,7 @@ class Summary(object): universes = universes[:, ::-1, :] lattice.universes = universes - if offset_size > 0: + if offsets is not None: offsets = np.swapaxes(offsets, 0, 1) offsets = np.swapaxes(offsets, 1, 2) lattice.offsets = offsets @@ -476,7 +433,7 @@ class Summary(object): # Lattice is 2D; extract the only axial level lattice.universes = universes[0] - if offset_size > 0: + if offsets is not None: lattice.offsets = offsets # Add the Lattice to the global dictionary of all Lattices @@ -521,7 +478,7 @@ class Summary(object): self.n_tallies = 0 return - self.n_tallies = self._f['tallies/n_tallies'][0] + self.n_tallies = self._f['tallies/n_tallies'].value # OpenMC Tally keys all_keys = self._f['tallies/'].keys() @@ -531,43 +488,34 @@ class Summary(object): # Iterate over all Tallies for tally_key in tally_keys: - tally_id = int(tally_key.strip('tally ')) subbase = '{0}{1}'.format(base, tally_id) # Read Tally name metadata - name_size = self._f['{0}/name_size'.format(subbase)][0] - if (name_size > 0): - tally_name = self._f['{0}/name'.format(subbase)][0] - tally_name = tally_name.lstrip('[\'') - tally_name = tally_name.rstrip('\']') - else: - tally_name = '' + tally_name = self._f['{0}/name'.format(subbase)].value.decode() # Create Tally object and assign basic properties tally = openmc.Tally(tally_id, tally_name) # Read score metadata - score_bins = self._f['{0}/score_bins'.format(subbase)][...] - for score_bin in score_bins: - tally.add_score(openmc.SCORE_TYPES[score_bin]) + scores = self._f['{0}/score_bins'.format(subbase)].value + for score in scores: + tally.add_score(score.decode()) num_score_bins = self._f['{0}/n_score_bins'.format(subbase)][...] tally.num_score_bins = num_score_bins # Read filter metadata - num_filters = self._f['{0}/n_filters'.format(subbase)][0] + num_filters = self._f['{0}/n_filters'.format(subbase)].value # Initialize all Filters for j in range(1, num_filters+1): - subsubbase = '{0}/filter {1}'.format(subbase, j) # Read filter type (e.g., "cell", "energy", etc.) - filter_type_code = self._f['{0}/type'.format(subsubbase)][0] - filter_type = openmc.FILTER_TYPES[filter_type_code] + filter_type = self._f['{0}/type'.format(subsubbase)].value.decode() # Read the filter bins - num_bins = self._f['{0}/n_bins'.format(subsubbase)][0] + num_bins = self._f['{0}/n_bins'.format(subsubbase)].value bins = self._f['{0}/bins'.format(subsubbase)][...] # Create Filter object @@ -596,29 +544,6 @@ class Summary(object): if self.opencg_geometry is None: self.opencg_geometry = get_opencg_geometry(self.openmc_geometry) - def get_nuclide_by_zaid(self, zaid): - """Return a Nuclide object given the 'zaid' identifier for the nuclide. - - Parameters - ---------- - zaid : int - 1000*Z + A, where Z is the atomic number of the nuclide and A is the - mass number. For example, the zaid for U-235 is 92235. - - Returns - ------- - nuclide : openmc.nuclide.Nuclide or None - Nuclide matching the specified zaid, or None if no matching object - is found. - - """ - - for index, nuclide in self.nuclides.items(): - if nuclide._zaid == zaid: - return nuclide - - return None - def get_material_by_id(self, material_id): """Return a Material object given the material id diff --git a/openmc/surface.py b/openmc/surface.py index d5d258fa7..653754d30 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -4,7 +4,6 @@ from xml.etree import ElementTree as ET import sys from openmc.checkvalue import check_type, check_value, check_greater_than -from openmc.constants import BC_TYPES if sys.version_info[0] >= 3: basestring = str @@ -12,6 +11,8 @@ if sys.version_info[0] >= 3: # A static variable for auto-generated Surface IDs AUTO_SURFACE_ID = 10000 +_BC_TYPES = ['transmission', 'vacuum', 'reflective', 'periodic'] + def reset_auto_surface_id(): global AUTO_SURFACE_ID @@ -106,7 +107,7 @@ class Surface(object): @boundary_type.setter def boundary_type(self, boundary_type): check_type('boundary type', boundary_type, basestring) - check_value('boundary type', boundary_type, BC_TYPES.values()) + check_value('boundary type', boundary_type, _BC_TYPES) self._boundary_type = boundary_type def __repr__(self): @@ -134,7 +135,7 @@ class Surface(object): element.set("type", self._type) element.set("boundary", self._boundary_type) - element.set("coeffs", ' '.join([str(self._coeffs[key]) + element.set("coeffs", ' '.join([str(self._coeffs.setdefault(key, 0.0)) for key in self._coeff_keys])) return element diff --git a/openmc/tallies.py b/openmc/tallies.py index 003acd943..20a6af3f2 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -52,7 +52,7 @@ class Tally(object): List of nuclides to score results for scores : list of str List of defined scores, e.g. 'flux', 'fission', etc. - estimator : {'analog', 'tracklength'} + estimator : {'analog', 'tracklength', 'collision'} Type of estimator for the tally triggers : list of openmc.trigger.Trigger List of tally triggers @@ -103,6 +103,9 @@ class Tally(object): self._with_batch_statistics = False self._derived = False + self._statepoint = None + self._results_read = False + def __deepcopy__(self, memo): existing = memo.get(id(self)) @@ -121,6 +124,8 @@ class Tally(object): clone._with_summary = self.with_summary clone._with_batch_statistics = self.with_batch_statistics clone._derived = self.derived + clone._statepoint = self._statepoint + clone._results_read = self._results_read clone._filters = [] for filter in self.filters: @@ -259,24 +264,69 @@ class Tally(object): @property def sum(self): + if not self._statepoint: + return None + + if not self._results_read: + # Extract Tally data from the file + data = self._statepoint._f['tallies/tally {0}/results'.format( + self.id)].value + sum = data['sum'] + sum_sq = data['sum_sq'] + + # Define a routine to convert 0 to 1 + def nonzero(val): + return 1 if not val else val + + # Reshape the results arrays + new_shape = (nonzero(self.num_filter_bins), + nonzero(self.num_nuclides), + nonzero(self.num_score_bins)) + + sum = np.reshape(sum, new_shape) + sum_sq = np.reshape(sum_sq, new_shape) + + # Set the data for this Tally + self._sum = sum + self._sum_sq = sum_sq + + # Indicate that Tally results have been read + self._results_read = True + return self._sum @property def sum_sq(self): + if not self._statepoint: + return None + + if not self._results_read: + # Force reading of sum and sum_sq + self.sum + return self._sum_sq @property def mean(self): - # Compute the mean if needed if self._mean is None: - self.compute_mean() + if not self._statepoint: + return None + + self._mean = self.sum / self.num_realizations return self._mean @property def std_dev(self): - # Compute the standard deviation if needed if self._std_dev is None: - self.compute_std_dev() + if not self._statepoint: + return None + + n = self.num_realizations + nonzero = np.abs(self.mean) > 0 + self._std_dev = np.zeros_like(self.mean) + self._std_dev[nonzero] = np.sqrt((self.sum_sq[nonzero]/n - + self.mean[nonzero]**2)/(n - 1)) + self.with_batch_statistics = True return self._std_dev @property @@ -289,7 +339,8 @@ class Tally(object): @estimator.setter def estimator(self, estimator): - check_value('estimator', estimator, ['analog', 'tracklength']) + check_value('estimator', estimator, + ['analog', 'tracklength', 'collision']) self._estimator = estimator def add_trigger(self, trigger): @@ -456,30 +507,6 @@ class Tally(object): self._nuclides.remove(nuclide) - def compute_mean(self): - """Compute the sample mean for each bin in the tally""" - - # Calculate sample mean - self._mean = self.sum / self.num_realizations - - def compute_std_dev(self, t_value=1.0): - """Compute the sample standard deviation for each bin in the tally - - Parameters - ---------- - t_value : float, optional - Student's t-value applied to the uncertainty. Defaults to 1.0, - meaning the reported value is the sample standard deviation. - - """ - - # Calculate sample standard deviation - self.compute_mean() - self._std_dev = np.sqrt((self.sum_sq / self.num_realizations - - self.mean**2) / (self.num_realizations - 1)) - self._std_dev *= t_value - self.with_batch_statistics = True - def __repr__(self): string = 'Tally\n' string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self.id) diff --git a/scripts/openmc-plot-mesh-tally b/scripts/openmc-plot-mesh-tally index f925b413a..04f1f06c6 100755 --- a/scripts/openmc-plot-mesh-tally +++ b/scripts/openmc-plot-mesh-tally @@ -33,7 +33,7 @@ class MeshPlotter(tk.Frame): self.labels = {'cell': 'Cell:', 'cellborn': 'Cell born:', 'surface': 'Surface:', 'material': 'Material:', - 'universe': 'Universe:', 'energyin': 'Energy in:', + 'universe': 'Universe:', 'energy': 'Energy in:', 'energyout': 'Energy out:'} self.filterBoxes = {} @@ -180,9 +180,9 @@ class MeshPlotter(tk.Frame): self.filterBoxes[filterType] = combobox # Set combobox items - if filterType in ['energyin', 'energyout']: + if filterType in ['energy', 'energyout']: combobox['values'] = ['{0} to {1}'.format(*f.bins[i:i+2]) - for i in range(f.length)] + for i in range(len(f.bins) - 1)] else: combobox['values'] = [str(i) for i in f.bins] @@ -213,8 +213,13 @@ class MeshPlotter(tk.Frame): if f.type == 'mesh': mesh_filter = f continue - index = self.filterBoxes[f.type].current() - spec_list.append((f.type, (index,))) + elif f.type in ['energy', 'energyout']: + index = self.filterBoxes[f.type].current() + ebin = (f.bins[index], f.bins[index + 1]) + spec_list.append((f.type, (ebin,))) + else: + index = self.filterBoxes[f.type].current() + spec_list.append((f.type, (index,))) text = self.basisBox.get() if text == 'xy': @@ -268,8 +273,6 @@ class MeshPlotter(tk.Frame): def get_file_data(self, filename): # Create StatePoint object and read in data self.datafile = StatePoint(filename) - self.datafile.read_results() - self.datafile.compute_stdev() # Find which tallies are mesh tallies self.meshTallies = [] diff --git a/scripts/openmc-statepoint-histogram b/scripts/openmc-statepoint-histogram deleted file mode 100755 index 26e8bdae6..000000000 --- a/scripts/openmc-statepoint-histogram +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function -from sys import argv -from math import sqrt - -import numpy as np -import scipy.stats -import matplotlib.pyplot as plt - -from openmc.statepoint import StatePoint - -# Get filename -filename = argv[1] - -# Create StatePoint object -sp = StatePoint(filename) -sp.read_results() -sp.compute_ci() - -# Check if tallies are present -if not sp.tallies_present: - raise Exception("No tally data in state point!") - -# Loop over all tallies -for i, t in sp.tallies.items(): - # Determine relative error and fraction of bins with less than 1% half-width - # of CI - n_bins = t.mean.size - relative_error = t.std_dev[t.mean > 0.] / t.mean[t.mean > 0.] - fraction = float(sum(relative_error < 0.01))/n_bins - - # Display results - print("Tally " + str(i)) - print(" Fraction under 1% = {0}".format(fraction)) - print(" Min relative error = {0}".format(min(relative_error))) - print(" Max relative error = {0}".format(max(relative_error))) - print(" Non-scoring bins = {0}".format( - 1.0 - float(relative_error.size)/n_bins)) - - # Plot histogram - plt.hist(relative_error, 100) - plt.show() diff --git a/scripts/openmc-tally-convergence b/scripts/openmc-tally-convergence deleted file mode 100755 index 81f45fd71..000000000 --- a/scripts/openmc-tally-convergence +++ /dev/null @@ -1,375 +0,0 @@ -#!/usr/bin/env python - -# This program takes OpenMC statepoint binary files and creates a variety of -# outputs from them which should provide the user with an idea of the -# convergence behavior of all the tallies and filters defined by the user in -# tallies.xml. The program can directly plot the value and errors of each -# tally, filter, score combination; it can save these plots to a file; and -# it can also save the data used in these plots to a CSV file for importing in -# to other plotting packages such as Excel, gnuplot, MathGL, or Veusz. - -# To use the program, run this program from the working directory of the openMC -# problem to analyze. - -# The USER OPTIONS block below provides four options for the user to set: -# fileType, printxs, showImg, and savetoCSV. See the options block for more -# information. - -from __future__ import print_function -from math import sqrt, pow -from glob import glob - -import numpy as np -import scipy.stats -import matplotlib.pyplot as plt - -from openmc.statepoint import StatePoint - -##################################### USER OPTIONS - -# Set filetype (the file extension desired, without the period.) -# Options are backend dependent, but most backends support png, pdf, ps, eps -# and svg. Write "none" if no saved files are desired. -fileType = "none" - -# Set if cross-sections or reaction rates are desired printxs = True means X/S -printxs = False - -# Set if the figures should be displayed to screen or not (True means show) -showImg = False - -# Save to CSV for use in more advanced plotting programs like GNUPlot, MathGL -savetoCSV = True - -##################################### END USER OPTIONS - -## Find if tallies.xml exists. -#if glob('./tallies.xml') != None: -# # It exists -# tallyData = talliesXML('tallies.xml') -#else: -# # It does not exist. -# tallyData = None - -# Find all statepoints in this directory. -files = glob('./statepoint.*.binary') -fileNums = [] -begin = 13 -# Arrange the file list in increasing batch order -for i in range(len(files)): - end = files[i].find(".binary") - fileNums.append(int(files[i][begin:end])) -fileNums.sort() -# Re-make filenames -files = [] -for i in range(len(fileNums)): - files.append("./statepoint." + str(fileNums[i]) + ".binary") - -# Initialize arrays as needed -mean = [None for x in range(len(files))] -uncert = [None for x in range(len(files))] -scoreType = [None for x in range(len(files))] -active_batches = [None for x in range(len(files))] - -for i_batch in range(len(files)): - - # Get filename - batch_filename = files[i_batch] - - # Create StatePoint object - sp = StatePoint(batch_filename) - - # Read number of realizations for global tallies - sp.n_realizations = sp._get_int()[0] - - # Read global tallies - n_global_tallies = sp._get_int()[0] - sp.global_tallies = np.array(sp._get_double(2*n_global_tallies)) - sp.global_tallies.shape = (n_global_tallies, 2) - - # Flag indicating if tallies are present - tallies_present = sp._get_int()[0] - - # Check if tallies are present - if not tallies_present: - raise Exception("No tally data in state point!") - - # Increase the dimensionality of our main variables - mean[i_batch] = [None for x in range(len(sp.tallies))] - uncert[i_batch] = [None for x in range(len(sp.tallies))] - scoreType[i_batch] = [None for x in range(len(sp.tallies))] - - # Loop over all tallies - for i_tally, t in enumerate(sp.tallies): - # Calculate t-value for 95% two-sided CI - n = t.n_realizations - t_value = scipy.stats.t.ppf(0.975, n - 1) - - # Store the batch count - active_batches[i_batch] = n - - # Resize the 2nd dimension - mean[i_batch][i_tally] = [None for x in range(t.total_filter_bins)] - uncert[i_batch][i_tally] = [None for x in range(t.total_filter_bins)] - scoreType[i_batch][i_tally] = [None for x in range(t.total_filter_bins)] - - for i_filter in range(t.total_filter_bins): - # Resize the 3rd dimension - mean[i_batch][i_tally][i_filter] = [None for x in range(t.n_nuclides)] - uncert[i_batch][i_tally][i_filter] = [None for x in range(t.n_nuclides)] - scoreType[i_batch][i_tally][i_filter] = [None for x in range(t.n_nuclides)] - print(t.total_filter_bins,t.n_nuclides) - for i_nuclide in range(t.n_nuclides): - mean[i_batch][i_tally][i_filter][i_nuclide] = \ - [None for x in range(t.n_scores)] - uncert[i_batch][i_tally][i_filter][i_nuclide] = \ - [None for x in range(t.n_scores)] - scoreType[i_batch][i_tally][i_filter][i_nuclide] = \ - [None for x in range(t.n_scores)] - for i_score in range(t.n_scores): - scoreType[i_batch][i_tally][i_filter][i_nuclide][i_score] = \ - t.scores[i_score] - s, s2 = sp._get_double(2) - s /= n - mean[i_batch][i_tally][i_filter][i_nuclide][i_score] = s - if s != 0.0: - relative_error = t_value*sqrt((s2/n - s*s)/(n-1))/s - else: - relative_error = 0.0 - uncert[i_batch][i_tally][i_filter][i_nuclide][i_score] = relative_error - -# Reorder the data lists in to a list order more conducive for plotting: -# The indexing should be: [tally][filter][score][batch] -meanPlot = [None for x in range(len(mean[0]))] # Set to the number of tallies -uncertPlot = [None for x in range(len(mean[0]))] # Set to the number of tallies -absUncertPlot = [None for x in range(len(mean[0]))] # Set to number of tallies -filterLabel = [None for x in range(len(mean[0]))] #Set to the number of tallies -fluxLoc = [None for x in range(len(mean[0]))] # Set to the number of tallies -printxs = [False for x in range(len(mean[0]))] # Set to the number of tallies - -# Get and set the correct sizes for the rest of the dimensions -for i_tally in range(len(meanPlot)): - # Set 2nd (score) dimension - meanPlot[i_tally] = [None for x in range(len(mean[0][i_tally]))] - uncertPlot[i_tally] = [None for x in range(len(mean[0][i_tally]))] - absUncertPlot[i_tally] = [None for x in range(len(mean[0][i_tally]))] - filterLabel[i_tally] = [None for x in range(len(mean[0][i_tally]))] - - # Initialize flux location so it will be -1 if not found - fluxLoc[i_tally] = -1 - - for i_filter in range(len(meanPlot[i_tally])): - # Set 3rd (filter) dimension - meanPlot[i_tally][i_filter] = \ - [None for x in range(len(mean[0][i_tally][i_filter]))] - uncertPlot[i_tally][i_filter] = \ - [None for x in range(len(mean[0][i_tally][i_filter]))] - absUncertPlot[i_tally][i_filter] = \ - [None for x in range(len(mean[0][i_tally][i_filter]))] - filterLabel[i_tally][i_filter] = \ - [None for x in range(len(mean[0][i_tally][i_filter]))] - - for i_nuclide in range(len(meanPlot[i_tally][i_filter])): - # Set 4th (nuclide)) dimension - meanPlot[i_tally][i_filter][i_nuclide] = \ - [None for x in range(len(mean[0][i_tally][i_filter][i_nuclide]))] - uncertPlot[i_tally][i_filter][i_nuclide] = \ - [None for x in range(len(mean[0][i_tally][i_filter][i_nuclide]))] - absUncertPlot[i_tally][i_filter][i_nuclide] = \ - [None for x in range(len(mean[0][i_tally][i_filter][i_nuclide]))] - - for i_score in range(len(meanPlot[i_tally][i_filter][i_nuclide])): - # Set 5th (batch) dimension - meanPlot[i_tally][i_filter][i_nuclide][i_score] = \ - [None for x in range(len(mean))] - uncertPlot[i_tally][i_filter][i_nuclide][i_score] = \ - [None for x in range(len(mean))] - absUncertPlot[i_tally][i_filter][i_nuclide][i_score] = \ - [None for x in range(len(mean))] - - # Get filterLabel (this should be moved to its own function) - #??? How to do? - - # Set flux location if found - # all batches and all tallies will have the same score ordering, hence - # the 0's in the 1st, 3rd, and 4th dimensions. - if scoreType[0][i_tally][0][0][i_score] == 'flux': - fluxLoc[i_tally] = i_score - -# Set printxs array according to the printxs input -if printxs: - for i_tally in range(len(fluxLoc)): - if fluxLoc[i_tally] != -1: - printxs[i_tally] = True - -# Now rearrange the data as suitable, and perform xs conversion if necessary -for i_batch in range(len(mean)): - for i_tally in range(len(mean[i_batch])): - for i_filter in range(len(mean[i_batch][i_tally])): - for i_nuclide in range(len(mean[i_batch][i_tally][i_filter])): - for i_score in range(len(mean[i_batch][i_tally][i_filter][i_nuclide])): - if (printxs[i_tally] and \ - ((scoreType[0][i_tally][i_filter][i_nuclide][i_score] != 'flux') and \ - (scoreType[0][i_tally][i_filter][i_nuclide][i_score] != 'current'))): - - # Perform rate to xs conversion - # mean is mean/fluxmean - meanPlot[i_tally][i_filter][i_nuclide][i_score][i_batch] = \ - mean[i_batch][i_tally][i_filter][i_nuclide][i_score] / \ - mean[i_batch][i_tally][i_filter][i_nuclide][fluxLoc[i_tally]] - - # Update the relative uncertainty via error propagation - uncertPlot[i_tally][i_filter][i_nuclide][i_score][i_batch] = \ - sqrt(pow(uncert[i_batch][i_tally][i_filter][i_nuclide][i_score],2) \ - + pow(uncert[i_batch][i_tally][i_filter][i_nuclide][fluxLoc[i_tally]],2)) - else: - - # Do not perform rate to xs conversion - meanPlot[i_tally][i_filter][i_nuclide][i_score][i_batch] = \ - mean[i_batch][i_tally][i_filter][i_nuclide][i_score] - uncertPlot[i_tally][i_filter][i_nuclide][i_score][i_batch] = \ - uncert[i_batch][i_tally][i_filter][i_nuclide][i_score] - - # Both have the same absolute uncertainty calculation - absUncertPlot[i_tally][i_filter][i_nuclide][i_score][i_batch] = \ - uncert[i_batch][i_tally][i_filter][i_nuclide][i_score] * \ - mean[i_batch][i_tally][i_filter][i_nuclide][i_score] - -# Set plotting constants -xLabel = "Batches" -xLabel = xLabel.title() # not necessary for now, but is left in to handle if -# the previous line changes - -# Begin plotting -for i_tally in range(len(meanPlot)): - # Set tally string (placeholder until I put tally labels in statePoint) - tallyStr = "Tally " + str(i_tally + 1) - - for i_filter in range(len(meanPlot[i_tally])): - - # Set filter string - filterStr = "Filter " + str(i_filter + 1) - - for i_nuclide in range(len(meanPlot[i_tally][i_filter])): - - nuclideStr = "Nuclide " + str(i_nuclide + 1) - - for i_score in range(len(meanPlot[i_tally][i_filter][i_nuclide])): - - # Set score string - scoreStr = scoreType[i_batch][i_tally][i_filter][i_nuclide][i_score] - scoreStr = scoreStr.title() - if (printxs[i_tally] and ((scoreStr != 'Flux') and \ - (scoreStr != 'Current'))): - scoreStr = scoreStr + "-XS" - - # set Title - title = "Convergence of " + scoreStr + " in " + tallyStr + " for "\ - + filterStr + " and " + nuclideStr - - # set yLabel - yLabel = scoreStr - yLabel = yLabel.title() - - # Set saving filename - fileName = "tally_" + str(i_tally + 1) + "_" + scoreStr + \ - "_filter_" + str(i_filter+1) + "_nuclide_" + str(i_nuclide+1) \ - + "." + fileType - REfileName = "tally_" + str(i_tally + 1) + "_" + scoreStr + \ - "RE_filter_" + str(i_filter+1) + "_nuclide_" + str(i_nuclide+1) \ - + "." + fileType - - # Plot mean with absolute error bars - plt.errorbar(active_batches, \ - meanPlot[i_tally][i_filter][i_nuclide][i_score][:], \ - absUncertPlot[i_tally][i_filter][i_nuclide][i_score][:],fmt='o-',aa=True) - plt.xlabel(xLabel) - plt.ylabel(yLabel) - plt.title(title) - if (fileType != 'none'): - plt.savefig(fileName) - if showImg: - plt.show() - plt.clf() - - # Plot relative uncertainty - plt.plot(active_batches, \ - uncertPlot[i_tally][i_filter][i_nuclide][i_score][:],'o-',aa=True) - plt.xlabel(xLabel) - plt.ylabel("Relative Error of " + yLabel) - plt.title("Relative Error of " + title) - if (fileType != 'none'): - plt.savefig(REfileName) - if showImg: - plt.show() - plt.clf() - -if savetoCSV: - # This block loops through each tally, and for each tally: - # Creates a new file - # Writes the scores and filters for that tally in csv format. - # The columns will be: batches,then for each filter: all the scores - # The rows, of course, are the data points per batch. - - for i_tally in range(len(meanPlot)): - # Set tally string (placeholder until I put tally labels in statePoint) - tallyStr = "Tally " + str(i_tally + 1) - CSV_filename = "./tally" + str(i_tally+1)+".csv" - # Open the file - f = open(CSV_filename, 'w') - - # Write the header line - - lineText = "Batches" - - for i_filter in range(len(meanPlot[i_tally])): - - # Set filter string - filterStr = "Filter " + str(i_filter + 1) - - for i_nuclide in range(len(meanPlot[i_tally][i_filter])): - - nuclideStr = "Nuclide " + str(i_nuclide + 1) - - for i_score in range(len(meanPlot[i_tally][i_filter][i_nuclide])): - - # Set the title - scoreStr = scoreType[i_batch][i_tally][i_filter][i_nuclide][i_score] - scoreStr = scoreStr.title() - if (printxs[i_tally] and ((scoreStr != 'Flux') and \ - (scoreStr != 'Current'))): - scoreStr = scoreStr + "-XS" - - # set header - headerText = scoreStr + " for " + filterStr + " for " + nuclideStr - - lineText = lineText + "," + headerText + \ - ",Abs Unc of " + headerText + \ - ",Rel Unc of " + headerText - - f.write(lineText + "\n") - - # Write the data lines, each row is a different batch - - for i_batch in range(len(meanPlot[i_tally][0][0][0])): - - lineText = repr(active_batches[i_batch]) - - for i_filter in range(len(meanPlot[i_tally])): - - for i_nuclide in range(len(meanPlot[i_tally][i_filter])): - - for i_score in range(len(meanPlot[i_tally][i_filter][i_nuclide])): - - fieldText = \ - repr(meanPlot[i_tally][i_filter][i_nuclide][i_score][i_batch]) + \ - "," + \ - repr(absUncertPlot[i_tally][i_filter][i_nuclide][i_score][i_batch]) +\ - "," + \ - repr(uncertPlot[i_tally][i_filter][i_nuclide][i_score][i_batch]) - - lineText = lineText + "," + fieldText - - f.write(lineText + "\n") - - diff --git a/scripts/openmc-track-to-vtk b/scripts/openmc-track-to-vtk index f44b3871a..e22a22dea 100755 --- a/scripts/openmc-track-to-vtk +++ b/scripts/openmc-track-to-vtk @@ -18,6 +18,7 @@ Usage information can be obtained by running 'track.py --help': import os import argparse +import h5py import struct import vtk @@ -39,56 +40,26 @@ def main(): # Parse commandline arguments. args = _parse_args() - # Check input file extensions. - for fname in args.input: - if not (fname.endswith('.h5') or fname.endswith('.binary')): - raise ValueError("Input file names must either end with '.h5' or" - "'.binary'.") - # Make sure that the output filename ends with '.pvtp'. if not args.out: args.out = 'tracks.pvtp' elif not args.out.endswith('.pvtp'): args.out += '.pvtp' - # Import HDF library if HDF files are present - for fname in args.input: - if fname.endswith('.h5'): - import h5py - break - # Initialize data arrays and offset. points = vtk.vtkPoints() cells = vtk.vtkCellArray() point_offset = 0 for fname in args.input: # Write coordinate values to points array. - if fname.endswith('.binary'): - track = open(fname, 'rb') - - # Determine number of particles and tracks/particle - n_particles = struct.unpack('i', track.read(4))[0] - n_coords = struct.unpack('i'*n_particles, track.read(4*n_particles)) - - coords = [] - for i in range(n_particles): - # Read coordinates for each particle - coords.append([struct.unpack('ddd', track.read(24)) - for j in range(n_coords[i])]) - - # Add coordinates to points data - for triplet in coords[i]: - points.InsertNextPoint(triplet) - - else: - track = h5py.File(fname) - n_particles = track['n_particles'].value[0] - n_coords = track['n_coords'] - coords = [] - for i in range(n_particles): - coords.append(track['coordinates_' + str(i + 1)].value) - for j in range(n_coords[i]): - points.InsertNextPoint(coords[i][j,:]) + track = h5py.File(fname) + n_particles = track['n_particles'].value + n_coords = track['n_coords'] + coords = [] + for i in range(n_particles): + coords.append(track['coordinates_' + str(i + 1)].value) + for j in range(n_coords[i]): + points.InsertNextPoint(coords[i][j,:]) for i in range(n_particles): # Create VTK line and assign points to line. diff --git a/scripts/openmc-voxel-to-silovtk b/scripts/openmc-voxel-to-silovtk index eb052c75f..1329b6b6c 100755 --- a/scripts/openmc-voxel-to-silovtk +++ b/scripts/openmc-voxel-to-silovtk @@ -1,9 +1,11 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python from __future__ import division, print_function import struct import sys +import numpy as np +import h5py def parse_options(): """Process command line arguments""" @@ -22,14 +24,16 @@ def parse_options(): return parsed -def main(file_, o): - print(file_) - fh = open(file_, 'rb') - header = get_header(fh) - meshparms = (header['dimension'] + header['lower_left'] + - header['upper_right']) - nx, ny, nz = meshparms[:3] - ll = header['lower_left'] +def main(filename, o): + # Read data from voxel file + fh = h5py.File(filename, 'r') + dimension = fh['num_voxels'].value + width = fh['voxel_width'].value + lower_left = fh['lower_left'].value + voxel_data = fh['data'].value + + nx, ny, nz = dimension + upper_right = lower_left + width*dimension if o.vtk: try: @@ -40,13 +44,10 @@ def main(file_, o): 'See: http://www.vtk.org/') return - origin = [(l + w*n/2.) for n, l, w in - zip((nx, ny, nz), ll, header['width'])] - grid = vtk.vtkImageData() grid.SetDimensions(nx+1, ny+1, nz+1) - grid.SetOrigin(*ll) - grid.SetSpacing(*header['width']) + grid.SetOrigin(*lower_left) + grid.SetSpacing(*width) data = vtk.vtkDoubleArray() data.SetName("id") @@ -57,8 +58,7 @@ def main(file_, o): for y in range(ny): for z in range(nz): i = z*nx*ny + y*nx + x - id_ = get_int(fh)[0] - data.SetValue(i, id_) + data.SetValue(i, voxel_data[x,y,z]) grid.GetCellData().AddArray(data) writer = vtk.vtkXMLImageDataWriter() @@ -81,44 +81,23 @@ def main(file_, o): if not o.output.endswith(".silo"): o.output += ".silo" silomesh.init_silo(o.output) - silomesh.init_mesh('plot', *meshparms) + meshparams = list(map(int, dimension)) + list(map(float, lower_left)) + \ + list(map(float, upper_right)) + silomesh.init_mesh('plot', *meshparams) silomesh.init_var("id") - for x in range(1, nx+1): + for x in range(nx): sys.stdout.write(" {0}%\r".format(int(x/nx*100))) sys.stdout.flush() - for y in range(1, ny+1): - for z in range(1, nz+1): - id_ = get_int(fh)[0] - silomesh.set_value(float(id_), x, y, z) + for y in range(ny): + for z in range(nz): + silomesh.set_value(float(voxel_data[x,y,z]), + x + 1, y + 1, z + 1) print() silomesh.finalize_var() silomesh.finalize_mesh() silomesh.finalize_silo() -def get_header(file_): - nx, ny, nz = get_int(file_, 3) - wx, wy, wz = get_double(file_, 3) - lx, ly, lz = get_double(file_, 3) - header = {'dimension': [nx, ny, nz], 'width': [wx, wy, wz], - 'lower_left': [lx, ly, lz], - 'upper_right': [lx+wx*nx, ly+wy*ny, lz+wz*nz]} - return header - - -def get_data(file_, n, typeCode, size): - return list(struct.unpack('={0}{1}'.format(n, typeCode), - file_.read(n*size))) - - -def get_int(file_, n=1, path=None): - return get_data(file_, n, 'i', 4) - - -def get_double(file_, n=1, path=None): - return get_data(file_, n, 'd', 8) - - if __name__ == '__main__': (options, args) = parse_options() if args: diff --git a/setup.py b/setup.py index 655e38e3a..3273f1db7 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ kwargs = {'name': 'openmc', if have_setuptools: kwargs.update({ # Required dependencies - 'install_requires': ['numpy', 'scipy', 'h5py', 'matplotlib'], + 'install_requires': ['numpy', 'h5py', 'matplotlib'], # Optional dependencies 'extras_require': { diff --git a/src/ace.F90 b/src/ace.F90 index 0dd92ea2c..cccc57092 100644 --- a/src/ace.F90 +++ b/src/ace.F90 @@ -234,7 +234,7 @@ contains integer :: location ! location of ACE table integer :: entries ! number of entries on each record integer :: length ! length of ACE table - integer :: in = 7 ! file unit + integer :: unit_ace ! file unit integer :: zaids(16) ! list of ZAIDs (only used for S(a,b)) integer :: filetype ! filetype (ASCII or BINARY) real(8) :: kT ! temperature of table @@ -277,14 +277,14 @@ contains ! READ ACE TABLE IN ASCII FORMAT ! Find location of table - open(UNIT=in, FILE=filename, STATUS='old', ACTION='read') - rewind(UNIT=in) + open(NEWUNIT=unit_ace, FILE=filename, STATUS='old', ACTION='read') + rewind(UNIT=unit_ace) do i = 1, location - 1 - read(UNIT=in, FMT=*) + read(UNIT=unit_ace, FMT=*) end do ! Read first line of header - read(UNIT=in, FMT='(A10,2G12.0,1X,A10)') name, awr, kT, date_ + read(UNIT=unit_ace, FMT='(A10,2G12.0,1X,A10)') name, awr, kT, date_ ! Check that correct xs was found -- if cross_sections.xml is broken, the ! location of the table may be wrong @@ -294,7 +294,7 @@ contains end if ! Read more header and NXS and JXS - read(UNIT=in, FMT=100) comment, mat, & + read(UNIT=unit_ace, FMT=100) comment, mat, & (zaids(i), awrs(i), i=1,16), NXS, JXS 100 format(A70,A10/4(I7,F11.0)/4(I7,F11.0)/4(I7,F11.0)/4(I7,F11.0)/& ,8I9/8I9/8I9/8I9/8I9/8I9) @@ -304,21 +304,21 @@ contains allocate(XSS(length)) ! Read XSS array - read(UNIT=in, FMT='(4G20.0)') XSS + read(UNIT=unit_ace, FMT='(4G20.0)') XSS ! Close ACE file - close(UNIT=in) + close(UNIT=unit_ace) elseif (filetype == BINARY) then ! ======================================================================= ! READ ACE TABLE IN BINARY FORMAT ! Open ACE file - open(UNIT=in, FILE=filename, STATUS='old', ACTION='read', & + open(NEWUNIT=unit_ace, FILE=filename, STATUS='old', ACTION='read', & ACCESS='direct', RECL=record_length) ! Read all header information - read(UNIT=in, REC=location) name, awr, kT, date_, & + read(UNIT=unit_ace, REC=location) name, awr, kT, date_, & comment, mat, (zaids(i), awrs(i), i=1,16), NXS, JXS ! determine table length @@ -329,11 +329,11 @@ contains do i = 1, (length + entries - 1)/entries j1 = 1 + (i-1)*entries j2 = min(length, j1 + entries - 1) - read(UNIT=IN, REC=location + i) (XSS(j), j=j1,j2) + read(UNIT=UNIT_ACE, REC=location + i) (XSS(j), j=j1,j2) end do ! Close ACE file - close(UNIT=in) + close(UNIT=unit_ace) end if ! ========================================================================== diff --git a/src/ace_header.F90 b/src/ace_header.F90 index 209b752bf..467887c19 100644 --- a/src/ace_header.F90 +++ b/src/ace_header.F90 @@ -1,8 +1,8 @@ module ace_header - use constants, only: MAX_FILE_LEN, ZERO - use endf_header, only: Tab1 - use list_header, only: ListInt + use constants, only: MAX_FILE_LEN, ZERO + use endf_header, only: Tab1 + use list_header, only: ListInt implicit none diff --git a/src/bank_header.F90 b/src/bank_header.F90 index 1a91f86f7..499358120 100644 --- a/src/bank_header.F90 +++ b/src/bank_header.F90 @@ -1,5 +1,7 @@ module bank_header + use, intrinsic :: ISO_C_BINDING + implicit none !=============================================================================== @@ -8,16 +10,11 @@ module bank_header ! stored with less memory !=============================================================================== - type Bank - ! The 'sequence' attribute is used here to ensure that the data listed - ! appears in the given order. This is important for MPI purposes when bank - ! sites are sent from one processor to another. - sequence - - real(8) :: wgt ! weight of bank site - real(8) :: xyz(3) ! location of bank particle - real(8) :: uvw(3) ! diretional cosines - real(8) :: E ! energy + type, bind(C) :: Bank + real(C_DOUBLE) :: wgt ! weight of bank site + real(C_DOUBLE) :: xyz(3) ! location of bank particle + real(C_DOUBLE) :: uvw(3) ! diretional cosines + real(C_DOUBLE) :: E ! energy end type Bank end module bank_header diff --git a/src/cmfd_data.F90 b/src/cmfd_data.F90 index 2b1778419..19fe39572 100644 --- a/src/cmfd_data.F90 +++ b/src/cmfd_data.F90 @@ -57,7 +57,7 @@ contains use global, only: cmfd, n_cmfd_tallies, cmfd_tallies, meshes,& matching_bins use mesh, only: mesh_indices_to_bin - use mesh_header, only: StructuredMesh + use mesh_header, only: RegularMesh use string, only: to_str use tally_header, only: TallyObject @@ -79,8 +79,8 @@ contains integer :: i_filter_eout ! index for outgoing energy filter integer :: i_filter_surf ! index for surface filter real(8) :: flux ! temp variable for flux - type(TallyObject), pointer :: t => null() ! pointer for tally object - type(StructuredMesh), pointer :: m => null() ! pointer for mesh object + type(TallyObject), pointer :: t ! pointer for tally object + type(RegularMesh), pointer :: m ! pointer for mesh object ! Extract spatial and energy indices from object nx = cmfd % indices(1) diff --git a/src/cmfd_execute.F90 b/src/cmfd_execute.F90 index c55d206cb..4dfe99d77 100644 --- a/src/cmfd_execute.F90 +++ b/src/cmfd_execute.F90 @@ -217,7 +217,7 @@ contains use error, only: warning, fatal_error use global, only: meshes, source_bank, work, n_user_meshes, cmfd, & master - use mesh_header, only: StructuredMesh + use mesh_header, only: RegularMesh use mesh, only: count_bank_sites, get_mesh_indices use search, only: binary_search use string, only: to_str @@ -239,8 +239,7 @@ contains integer :: n_groups ! number of energy groups logical :: outside ! any source sites outside mesh logical :: in_mesh ! source site is inside mesh - - type(StructuredMesh), pointer :: m ! point to mesh + type(RegularMesh), pointer :: m ! point to mesh ! Associate pointer m => meshes(n_user_meshes + 1) diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index 2d44d3e9b..dac74c9c3 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -247,7 +247,7 @@ contains use constants, only: MAX_LINE_LEN use error, only: fatal_error, warning - use mesh_header, only: StructuredMesh + use mesh_header, only: RegularMesh use string use tally, only: setup_active_cmfdtallies use tally_header, only: TallyObject, TallyFilter @@ -264,10 +264,10 @@ contains integer :: i_filter_mesh ! index for mesh filter integer :: iarray3(3) ! temp integer array real(8) :: rarray3(3) ! temp double array - type(TallyObject), pointer :: t => null() - type(StructuredMesh), pointer :: m => null() + type(TallyObject), pointer :: t + type(RegularMesh), pointer :: m type(TallyFilter) :: filters(N_FILTER_TYPES) ! temporary filters - type(Node), pointer :: node_mesh => null() + type(Node), pointer :: node_mesh ! Set global variables if they are 0 (this can happen if there is no tally ! file) diff --git a/src/constants.F90 b/src/constants.F90 index 38bedf022..53891cdaa 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -11,14 +11,10 @@ module constants integer, parameter :: VERSION_RELEASE = 0 ! Revision numbers for binary files - integer, parameter :: REVISION_STATEPOINT = 13 + integer, parameter :: REVISION_STATEPOINT = 14 integer, parameter :: REVISION_PARTICLE_RESTART = 1 - - ! Binary file types - integer, parameter :: & - FILETYPE_STATEPOINT = -1, & - FILETYPE_PARTICLE_RESTART = -2, & - FILETYPE_SOURCE = -3 + integer, parameter :: REVISION_TRACK = 1 + integer, parameter :: REVISION_SUMMARY = 1 ! ============================================================================ ! ADJUSTABLE PARAMETERS @@ -249,7 +245,8 @@ module constants ! Tally estimator types integer, parameter :: & ESTIMATOR_ANALOG = 1, & - ESTIMATOR_TRACKLENGTH = 2 + ESTIMATOR_TRACKLENGTH = 2, & + ESTIMATOR_COLLISION = 3 ! Event types for tallies integer, parameter :: & @@ -315,6 +312,10 @@ module constants FILTER_ENERGYOUT = 8, & FILTER_DISTRIBCELL = 9 + ! Mesh types + integer, parameter :: & + MESH_REGULAR = 1 + ! Tally surface current directions integer, parameter :: & IN_RIGHT = 1, & @@ -330,7 +331,7 @@ module constants RELATIVE_ERROR = 2, & STANDARD_DEVIATION = 3 - ! Global tallY parameters + ! Global tally parameters integer, parameter :: N_GLOBAL_TALLIES = 4 integer, parameter :: & K_COLLISION = 1, & @@ -392,14 +393,6 @@ module constants MODE_PLOTTING = 3, & ! Plotting mode MODE_PARTICLE = 4 ! Particle restart mode - ! Unit numbers - integer, parameter :: UNIT_SUMMARY = 11 ! unit # for writing summary file - integer, parameter :: UNIT_TALLY = 12 ! unit # for writing tally file - integer, parameter :: UNIT_PLOT = 13 ! unit # for writing plot file - integer, parameter :: UNIT_XS = 14 ! unit # for writing xs summary file - integer, parameter :: UNIT_PARTICLE = 15 ! unit # for writing particle restart - integer, parameter :: UNIT_OUTPUT = 16 ! unit # for writing output - !============================================================================= ! CMFD CONSTANTS diff --git a/src/eigenvalue.F90 b/src/eigenvalue.F90 index 33d63b7cc..403347caa 100644 --- a/src/eigenvalue.F90 +++ b/src/eigenvalue.F90 @@ -9,7 +9,7 @@ module eigenvalue use global use math, only: t_percentile use mesh, only: count_bank_sites - use mesh_header, only: StructuredMesh + use mesh_header, only: RegularMesh use particle_header, only: Particle use random_lcg, only: prn, set_particle_seed, prn_skip use search, only: binary_search @@ -304,7 +304,7 @@ contains integer :: i, j, k ! index for bank sites integer :: n ! # of boxes in each dimension logical :: sites_outside ! were there sites outside entropy box? - type(StructuredMesh), pointer :: m => null() + type(RegularMesh), pointer :: m ! Get pointer to entropy mesh m => entropy_mesh diff --git a/src/finalize.F90 b/src/finalize.F90 index aa11f4769..86100d195 100644 --- a/src/finalize.F90 +++ b/src/finalize.F90 @@ -9,9 +9,8 @@ module finalize use message_passing #endif -#ifdef HDF5 - use hdf5_interface, only: h5tclose_f, h5close_f, hdf5_err -#endif + use hdf5_interface, only: hdf5_bank_t, hdf5_tallyresult_t + use hdf5, only: h5tclose_f, h5close_f implicit none @@ -24,8 +23,10 @@ contains subroutine finalize_run() + integer :: hdf5_err + ! Start finalization timer - call time_finalize % start() + call time_finalize%start() if (run_mode /= MODE_PLOTTING .and. run_mode /= MODE_PARTICLE) then ! Calculate statistics for tallies and write to tallies.out @@ -39,8 +40,8 @@ contains end if ! Stop timers and show timing statistics - call time_finalize % stop() - call time_total % stop() + call time_finalize%stop() + call time_total%stop() if (master .and. (run_mode /= MODE_PLOTTING .and. & run_mode /= MODE_PARTICLE)) then call print_runtime() @@ -51,14 +52,12 @@ contains ! Deallocate arrays call free_memory() -#ifdef HDF5 ! Release compound datatypes call h5tclose_f(hdf5_tallyresult_t, hdf5_err) call h5tclose_f(hdf5_bank_t, hdf5_err) ! Close FORTRAN interface. call h5close_f(hdf5_err) -#endif #ifdef MPI ! Free all MPI types diff --git a/src/global.F90 b/src/global.F90 index 564fcda84..398b72e14 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -8,7 +8,7 @@ module global use dict_header, only: DictCharInt, DictIntInt use geometry_header, only: Cell, Universe, Lattice, LatticeContainer, Surface use material_header, only: Material - use mesh_header, only: StructuredMesh + use mesh_header, only: RegularMesh use plot_header, only: ObjectPlot use set_header, only: SetInt use source_header, only: ExtSource @@ -16,9 +16,6 @@ module global use trigger_header, only: KTrigger use timer_header, only: Timer -#ifdef HDF5 - use hdf5_interface, only: HID_T -#endif #ifdef MPIF08 use mpi_f08 #endif @@ -93,7 +90,7 @@ module global ! ============================================================================ ! TALLY-RELATED VARIABLES - type(StructuredMesh), allocatable, target :: meshes(:) + type(RegularMesh), allocatable, target :: meshes(:) type(TallyObject), allocatable, target :: tallies(:) integer, allocatable :: matching_bins(:) @@ -109,9 +106,11 @@ module global type(SetInt) :: active_analog_tallies type(SetInt) :: active_tracklength_tallies type(SetInt) :: active_current_tallies + type(SetInt) :: active_collision_tallies type(SetInt) :: active_tallies !$omp threadprivate(active_analog_tallies, active_tracklength_tallies, & -!$omp& active_current_tallies, active_tallies) +!$omp& active_current_tallies, active_collision_tallies, & +!$omp& active_tallies) ! Global tallies ! 1) collision estimate of k-eff @@ -204,11 +203,11 @@ module global logical :: entropy_on = .false. real(8), allocatable :: entropy(:) ! shannon entropy at each generation real(8), allocatable :: entropy_p(:,:,:,:) ! % of source sites in each cell - type(StructuredMesh), pointer :: entropy_mesh + type(RegularMesh), pointer :: entropy_mesh ! Uniform fission source weighting logical :: ufs = .false. - type(StructuredMesh), pointer :: ufs_mesh => null() + type(RegularMesh), pointer :: ufs_mesh => null() real(8), allocatable :: source_frac(:,:,:,:) ! Write source at end of simulation @@ -267,16 +266,6 @@ module global real(8) :: weight_cutoff = 0.25_8 real(8) :: weight_survive = ONE - ! ============================================================================ - ! HDF5 VARIABLES - -#ifdef HDF5 - integer(HID_T) :: hdf5_output_file ! identifier for output file - integer(HID_T) :: hdf5_tallyresult_t ! Compound type for TallyResult - integer(HID_T) :: hdf5_bank_t ! Compound type for Bank - integer(HID_T) :: hdf5_integer8_t ! type for integer(8) -#endif - ! ============================================================================ ! MISCELLANEOUS VARIABLES @@ -500,6 +489,7 @@ contains call active_analog_tallies % clear() call active_tracklength_tallies % clear() call active_current_tallies % clear() + call active_collision_tallies % clear() call active_tallies % clear() ! Deallocate track_identifiers diff --git a/src/hdf5_interface.F90 b/src/hdf5_interface.F90 index 34b72196e..656039d19 100644 --- a/src/hdf5_interface.F90 +++ b/src/hdf5_interface.F90 @@ -1,1816 +1,1924 @@ module hdf5_interface -#ifdef HDF5 +!============================================================================== +! HDF5_INTERFACE -- This module provides the high-level procedures which greatly +! simplify writing/reading different types of data to HDF5 files. In order to +! get it to work with gfotran 4.6, all the write__ND subroutines had to be +! split into two procedures, one accepting an assumed-shape array and another +! one with an explicit-shape array since in gfortran 4.6 C_LOC does not work +! with an assumed-shape array. When we move to gfortran 4.9+, these procedures +! can be combined into one simply accepting an assumed-shape array. +!============================================================================== + + use error, only: fatal_error + use tally_header, only: TallyResult use hdf5 use h5lt use, intrinsic :: ISO_C_BINDING -#ifdef MPI +#ifdef PHDF5 use message_passing, only: MPI_COMM_WORLD, MPI_INFO_NULL #endif implicit none + private - integer :: hdf5_err ! HDF5 error code - integer :: hdf5_rank ! rank of data - integer(HID_T) :: dset ! data set handle - integer(HID_T) :: dspace ! data or file space handle - integer(HID_T) :: memspace ! data space handle for individual procs - integer(HID_T) :: plist ! property list handle - integer(HSIZE_T) :: dims1(1) ! dims type for 1-D array - integer(HSIZE_T) :: dims2(2) ! dims type for 2-D array - integer(HSIZE_T) :: dims3(3) ! dims type for 3-D array - integer(HSIZE_T) :: dims4(4) ! dims type for 4-D array - type(c_ptr) :: f_ptr ! pointer to data + integer(HID_T), public :: hdf5_tallyresult_t ! Compound type for TallyResult + integer(HID_T), public :: hdf5_bank_t ! Compound type for Bank + integer(HID_T), public :: hdf5_integer8_t ! type for integer(8) - ! Generic HDF5 write procedure interface - interface hdf5_write_data - module procedure hdf5_write_double - module procedure hdf5_write_double_1Darray - module procedure hdf5_write_double_2Darray - module procedure hdf5_write_double_3Darray - module procedure hdf5_write_double_4Darray - module procedure hdf5_write_integer - module procedure hdf5_write_integer_1Darray - module procedure hdf5_write_integer_2Darray - module procedure hdf5_write_integer_3Darray - module procedure hdf5_write_integer_4Darray - module procedure hdf5_write_long - module procedure hdf5_write_string -#ifdef MPI - module procedure hdf5_write_double_parallel - module procedure hdf5_write_double_1Darray_parallel - module procedure hdf5_write_double_2Darray_parallel - module procedure hdf5_write_double_3Darray_parallel - module procedure hdf5_write_double_4Darray_parallel - module procedure hdf5_write_integer_parallel - module procedure hdf5_write_integer_1Darray_parallel - module procedure hdf5_write_integer_2Darray_parallel - module procedure hdf5_write_integer_3Darray_parallel - module procedure hdf5_write_integer_4Darray_parallel - module procedure hdf5_write_long_parallel - module procedure hdf5_write_string_parallel -#endif - end interface hdf5_write_data + interface write_dataset + module procedure write_double + module procedure write_double_1D + module procedure write_double_2D + module procedure write_double_3D + module procedure write_double_4D + module procedure write_integer + module procedure write_integer_1D + module procedure write_integer_2D + module procedure write_integer_3D + module procedure write_integer_4D + module procedure write_long + module procedure write_string + module procedure write_string_1D + module procedure write_tally_result_1D + module procedure write_tally_result_2D + end interface write_dataset - ! Generic HDF5 read procedure interface - interface hdf5_read_data - module procedure hdf5_read_double - module procedure hdf5_read_double_1Darray - module procedure hdf5_read_double_2Darray - module procedure hdf5_read_double_3Darray - module procedure hdf5_read_double_4Darray - module procedure hdf5_read_integer - module procedure hdf5_read_integer_1Darray - module procedure hdf5_read_integer_2Darray - module procedure hdf5_read_integer_3Darray - module procedure hdf5_read_integer_4Darray - module procedure hdf5_read_long - module procedure hdf5_read_string -#ifdef MPI - module procedure hdf5_read_double_parallel - module procedure hdf5_read_double_1Darray_parallel - module procedure hdf5_read_double_2Darray_parallel - module procedure hdf5_read_double_3Darray_parallel - module procedure hdf5_read_double_4Darray_parallel - module procedure hdf5_read_integer_parallel - module procedure hdf5_read_integer_1Darray_parallel - module procedure hdf5_read_integer_2Darray_parallel - module procedure hdf5_read_integer_3Darray_parallel - module procedure hdf5_read_integer_4Darray_parallel - module procedure hdf5_read_long_parallel - module procedure hdf5_read_string_parallel -#endif - end interface hdf5_read_data + interface read_dataset + module procedure read_double + module procedure read_double_1D + module procedure read_double_2D + module procedure read_double_3D + module procedure read_double_4D + module procedure read_integer + module procedure read_integer_1D + module procedure read_integer_2D + module procedure read_integer_3D + module procedure read_integer_4D + module procedure read_long + module procedure read_string + module procedure read_string_1D + module procedure read_tally_result_1D + module procedure read_tally_result_2D + end interface read_dataset + + public :: write_dataset + public :: read_dataset + public :: file_create + public :: file_open + public :: file_close + public :: create_group + public :: open_group + public :: close_group + public :: write_attribute_string contains !=============================================================================== -! HDF5_FILE_CREATE creates HDF5 file +! FILE_CREATE creates HDF5 file !=============================================================================== - subroutine hdf5_file_create(filename, file_id) + function file_create(filename, parallel) result(file_id) + character(*), intent(in) :: filename ! name of file + logical, optional, intent(in) :: parallel ! whether to write in serial + integer(HID_T) :: file_id - character(*), intent(in) :: filename ! name of file - integer(HID_T), intent(inout) :: file_id ! file handle + integer(HID_T) :: plist ! property list handle + integer :: hdf5_err ! HDF5 error code + logical :: parallel_ - ! Create the file - call h5fcreate_f(trim(filename), H5F_ACC_TRUNC_F, file_id, hdf5_err) + ! Check for serial option + parallel_ = .false. +#ifdef PHDF5 + if (present(parallel)) parallel_ = parallel +#endif - end subroutine hdf5_file_create + if (parallel_) then + ! Setup file access property list with parallel I/O access + call h5pcreate_f(H5P_FILE_ACCESS_F, plist, hdf5_err) +#ifdef PHDF5 +#ifdef MPIF08 + call h5pset_fapl_mpio_f(plist, MPI_COMM_WORLD%MPI_VAL, & + MPI_INFO_NULL%MPI_VAL, hdf5_err) +#else + call h5pset_fapl_mpio_f(plist, MPI_COMM_WORLD, MPI_INFO_NULL, hdf5_err) +#endif +#endif + + ! Create the file collectively + call h5fcreate_f(trim(filename), H5F_ACC_TRUNC_F, file_id, hdf5_err, & + access_prp = plist) + + ! Close the property list + call h5pclose_f(plist, hdf5_err) + else + ! Create the file + call h5fcreate_f(trim(filename), H5F_ACC_TRUNC_F, file_id, hdf5_err) + end if + + end function file_create !=============================================================================== -! HDF5_FILE_OPEN opens HDF5 file +! FILE_OPEN opens HDF5 file !=============================================================================== - subroutine hdf5_file_open(filename, file_id, mode) + function file_open(filename, mode, parallel) result(file_id) + character(*), intent(in) :: filename ! name of file + character(*), intent(in) :: mode ! access mode to file + logical, optional, intent(in) :: parallel ! whether to write in serial + integer(HID_T) :: file_id - character(*), intent(in) :: filename ! name of file - character(*), intent(in) :: mode ! access mode to file - integer(HID_T), intent(inout) :: file_id ! file handle + logical :: parallel_ + integer(HID_T) :: plist ! property list handle + integer :: hdf5_err ! HDF5 error code + integer :: open_mode ! HDF5 open mode - integer :: open_mode ! HDF5 open mode + ! Check for serial option + parallel_ = .false. +#ifdef PHDF5 + if (present(parallel)) parallel_ = parallel +#endif ! Determine access type open_mode = H5F_ACC_RDONLY_F - if (trim(mode) == 'w') then - open_mode = H5F_ACC_RDWR_F - end if + if (mode == 'w') open_mode = H5F_ACC_RDWR_F - ! Open file - call h5fopen_f(trim(filename), open_mode, file_id, hdf5_err) - - end subroutine hdf5_file_open - -!=============================================================================== -! HDF5_FILE_CLOSE closes HDF5 file -!=============================================================================== - - subroutine hdf5_file_close(file_id) - - integer(HID_T), intent(inout) :: file_id ! file handle - - ! Close the file - call h5fclose_f(file_id, hdf5_err) - - end subroutine hdf5_file_close - -#ifdef MPI - -!=============================================================================== -! HDF5_FILE_CREATE_PARALLEL creates HDF5 file with parallel I/O -!=============================================================================== - - subroutine hdf5_file_create_parallel(filename, file_id) - - character(*), intent(in) :: filename ! name of file - integer(HID_T), intent(inout) :: file_id ! file handle - - ! Setup file access property list with parallel I/O access - call h5pcreate_f(H5P_FILE_ACCESS_F, plist, hdf5_err) + if (parallel_) then + ! Setup file access property list with parallel I/O access + call h5pcreate_f(H5P_FILE_ACCESS_F, plist, hdf5_err) +#ifdef PHDF5 #ifdef MPIF08 - call h5pset_fapl_mpio_f(plist, MPI_COMM_WORLD%MPI_VAL, & - MPI_INFO_NULL%MPI_VAL, hdf5_err) + call h5pset_fapl_mpio_f(plist, MPI_COMM_WORLD%MPI_VAL, & + MPI_INFO_NULL%MPI_VAL, hdf5_err) #else - call h5pset_fapl_mpio_f(plist, MPI_COMM_WORLD, MPI_INFO_NULL, hdf5_err) + call h5pset_fapl_mpio_f(plist, MPI_COMM_WORLD, MPI_INFO_NULL, hdf5_err) +#endif #endif - ! Create the file collectively - call h5fcreate_f(trim(filename), H5F_ACC_TRUNC_F, file_id, hdf5_err, & + ! Open the file collectively + call h5fopen_f(trim(filename), open_mode, file_id, hdf5_err, & access_prp = plist) - ! Close the property list - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_file_create_parallel - -!=============================================================================== -! HDF5_FILE_OPEN_PARALLEL opens HDF5 file with parallel I/O -!=============================================================================== - - subroutine hdf5_file_open_parallel(filename, file_id, mode) - - character(*), intent(in) :: filename ! name of file - character(*), intent(in) :: mode ! access mode - integer(HID_T), intent(inout) :: file_id ! file handle - - integer :: open_mode ! HDF5 access mode - - ! Setup file access property list with parallel I/O access - call h5pcreate_f(H5P_FILE_ACCESS_F, plist, hdf5_err) -#ifdef MPIF08 - call h5pset_fapl_mpio_f(plist, MPI_COMM_WORLD%MPI_VAL, & - MPI_INFO_NULL%MPI_VAL, hdf5_err) -#else - call h5pset_fapl_mpio_f(plist, MPI_COMM_WORLD, MPI_INFO_NULL, hdf5_err) -#endif - - ! Determine access type - open_mode = H5F_ACC_RDONLY_F - if (trim(mode) == 'w') then - open_mode = H5F_ACC_RDWR_F + ! Close the property list + call h5pclose_f(plist, hdf5_err) + else + ! Open file + call h5fopen_f(trim(filename), open_mode, file_id, hdf5_err) end if - ! Create the file collectively - call h5fopen_f(trim(filename), open_mode, file_id, hdf5_err, & - access_prp = plist) - - ! Close the property list - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_file_open_parallel - -#endif + end function file_open !=============================================================================== -! HDF5_OPEN_GROUP creates/opens HDF5 group to temp_group +! FILE_CLOSE closes HDF5 file !=============================================================================== - subroutine hdf5_open_group(hdf5_fh, group, hdf5_grp) + subroutine file_close(file_id) + integer(HID_T), intent(in) :: file_id - character(*), intent(in) :: group ! name of group - integer(HID_T), intent(in) :: hdf5_fh ! file handle of main output file - integer(HID_T), intent(inout) :: hdf5_grp ! handle for group + integer :: hdf5_err - logical :: status ! does the group exist + call h5fclose_f(file_id, hdf5_err) + end subroutine file_close + +!=============================================================================== +! OPEN_GROUP opens an existing HDF5 group +!=============================================================================== + + function open_group(group_id, name) result(newgroup_id) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of group + integer(HID_T) :: newgroup_id + + logical :: exists ! does the group exist + integer :: hdf5_err ! HDF5 error code ! Check if group exists - call h5ltpath_valid_f(hdf5_fh, trim(group), .true., status, hdf5_err) + call h5ltpath_valid_f(group_id, trim(name), .true., exists, hdf5_err) - ! Either create or open group - if (status) then - call h5gopen_f(hdf5_fh, trim(group), hdf5_grp, hdf5_err) + ! open group if it exists + if (exists) then + call h5gopen_f(group_id, trim(name), newgroup_id, hdf5_err) else - call h5gcreate_f(hdf5_fh, trim(group), hdf5_grp, hdf5_err) + call fatal_error("The group '" // trim(name) // "' does not exist.") end if - - end subroutine hdf5_open_group + end function open_group !=============================================================================== -! HDF5_CLOSE_GROUP closes HDF5 temp_group +! CREATE_GROUP creates a new HDF5 group !=============================================================================== - subroutine hdf5_close_group(hdf5_grp) + function create_group(group_id, name) result(newgroup_id) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of group + integer(HID_T) :: newgroup_id - integer(HID_T), intent(inout) :: hdf5_grp + integer :: hdf5_err ! HDF5 error code + logical :: exists ! does the group exist - ! Close the group - call h5gclose_f(hdf5_grp, hdf5_err) + ! Check if group exists + call h5ltpath_valid_f(group_id, trim(name), .true., exists, hdf5_err) - end subroutine hdf5_close_group + ! create group + if (exists) then + call fatal_error("The group '" // trim(name) // "' already exists.") + else + call h5gcreate_f(group_id, trim(name), newgroup_id, hdf5_err) + end if + end function create_group !=============================================================================== -! HDF5_WRITE_INTEGER writes integer scalar data +! CLOSE_GROUP closes HDF5 temp_group !=============================================================================== - subroutine hdf5_write_integer(group, name, buffer) + subroutine close_group(group_id) + integer(HID_T), intent(inout) :: group_id - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer, intent(in) :: buffer ! data to write + integer :: hdf5_err ! HDF5 error code - ! Set rank and dimensions - hdf5_rank = 1 - dims1(1) = 1 - - call h5ltmake_dataset_int_f(group, name, hdf5_rank, dims1, & - (/ buffer /), hdf5_err) - - end subroutine hdf5_write_integer + call h5gclose_f(group_id, hdf5_err) + if (hdf5_err < 0) then + call fatal_error("Unable to close HDF5 group.") + end if + end subroutine close_group !=============================================================================== -! HDF5_READ_INTEGER reads integer scalar data +! WRITE_DOUBLE writes double precision scalar data !=============================================================================== - subroutine hdf5_read_integer(group, name, buffer) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer, intent(inout) :: buffer ! read data to here - - integer :: buffer_copy(1) ! need an array for read - - ! Set up dimensions - dims1(1) = 1 - - ! Read data - call h5ltread_dataset_int_f(group, name, buffer_copy, dims1, hdf5_err) - buffer = buffer_copy(1) - - end subroutine hdf5_read_integer - -!=============================================================================== -! HDF5_WRITE_INTEGER_1DARRAY writes integer 1-D array -!=============================================================================== - - subroutine hdf5_write_integer_1Darray(group, name, buffer, len) - - integer, intent(in) :: len ! length of array to write - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer, intent(in) :: buffer(:) ! data to write - - ! Set rank and dimensions of data - hdf5_rank = 1 - dims1(1) = len - - ! Write data - call h5ltmake_dataset_int_f(group, name, hdf5_rank, dims1, & - buffer, hdf5_err) - - end subroutine hdf5_write_integer_1Darray - -!=============================================================================== -! HDF5_READ_INTEGER_1DARRAY reads integer 1-D array -!=============================================================================== - - subroutine hdf5_read_integer_1Darray(group, name, buffer, length) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer, intent(inout) :: buffer(:) ! read data to here - integer, intent(in) :: length ! length of array - - ! Set dimensions - dims1(1) = length - - ! Read data - call h5ltread_dataset_int_f(group, name, buffer, dims1, hdf5_err) - - end subroutine hdf5_read_integer_1Darray - -!=============================================================================== -! HDF5_WRITE_INTEGER_2DARRAY writes integer 2-D array -!=============================================================================== - - subroutine hdf5_write_integer_2Darray(group, name, buffer, length) - - integer, intent(in) :: length(2) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer, intent(in) :: buffer(length(1),length(2)) ! data to write - - ! Set rank and dimensions - hdf5_rank = 2 - dims2 = length - - ! Write data - call h5ltmake_dataset_int_f(group, name, hdf5_rank, dims2, & - buffer, hdf5_err) - - end subroutine hdf5_write_integer_2Darray - -!=============================================================================== -! HDF5_READ_INTEGER_2DARRAY reads integer 2-D array -!=============================================================================== - - subroutine hdf5_read_integer_2Darray(group, name, buffer, length) - - integer, intent(in) :: length(2) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer, intent(inout) :: buffer(length(1),length(2)) ! data to read - - ! Set rank and dimensions - dims2 = length - - ! Write data - call h5ltread_dataset_int_f(group, name, buffer, dims2, hdf5_err) - - end subroutine hdf5_read_integer_2Darray - -!=============================================================================== -! HDF5_WRITE_INTEGER_3DARRAY writes integer 3-D array -!=============================================================================== - - subroutine hdf5_write_integer_3Darray(group, name, buffer, length) - - integer, intent(in) :: length(3) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer, intent(in) :: buffer(length(1),length(2), & - length(3)) ! data to write - - ! Set rank and dimensions - hdf5_rank = 3 - dims3 = length - - ! Write data - call h5ltmake_dataset_int_f(group, name, hdf5_rank, dims3, & - buffer, hdf5_err) - - end subroutine hdf5_write_integer_3Darray - -!=============================================================================== -! HDF5_READ_INTEGER_3DARRAY reads integer 3-D array -!=============================================================================== - - subroutine hdf5_read_integer_3Darray(group, name, buffer, length) - - integer, intent(in) :: length(3) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer, intent(inout) :: buffer(length(1),length(2), & - length(3)) ! data to read - - ! Set rank and dimensions - dims3 = length - - ! Write data - call h5ltread_dataset_int_f(group, name, buffer, dims3, hdf5_err) - - end subroutine hdf5_read_integer_3Darray - -!=============================================================================== -! HDF5_WRITE_INTEGER_4DARRAY writes integer 4-D array -!=============================================================================== - - subroutine hdf5_write_integer_4Darray(group, name, buffer, length) - - integer, intent(in) :: length(4) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer, intent(in) :: buffer(length(1),length(2), & - length(3),length(4)) ! data to write - - ! Set rank and dimensions - hdf5_rank = 4 - dims4 = length - - ! Write data - call h5ltmake_dataset_int_f(group, name, hdf5_rank, dims4, & - buffer, hdf5_err) - - end subroutine hdf5_write_integer_4Darray - -!=============================================================================== -! HDF5_READ_INTEGER_4DARRAY reads integer 4-D array -!=============================================================================== - - subroutine hdf5_read_integer_4Darray(group, name, buffer, length) - - integer, intent(in) :: length(4) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer, intent(inout) :: buffer(length(1),length(2), & - length(3),length(4)) ! data to read - - ! Set rank and dimensions - dims4 = length - - ! Write data - call h5ltread_dataset_int_f(group, name, buffer, dims4, hdf5_err) - - end subroutine hdf5_read_integer_4Darray - -!=============================================================================== -! HDF5_WRITE_DOUBLE writes integer scalar data -!=============================================================================== - - subroutine hdf5_write_double(group, name, buffer) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8), intent(in) :: buffer ! data to write - - ! Set rank and dimensions - hdf5_rank = 1 - dims1(1) = 1 - - call h5ltmake_dataset_double_f(group, name, hdf5_rank, dims1, & - (/ buffer /), hdf5_err) - - end subroutine hdf5_write_double - -!=============================================================================== -! HDF5_READ_DOUBLE reads double scalar data -!=============================================================================== - - subroutine hdf5_read_double(group, name, buffer) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8), intent(inout) :: buffer ! read data to here - - real(8) :: buffer_copy(1) ! need an array for read - - ! Set up dimensions - dims1(1) = 1 - - ! Read data - call h5ltread_dataset_double_f(group, name, buffer_copy, dims1, hdf5_err) - buffer = buffer_copy(1) - - end subroutine hdf5_read_double - -!=============================================================================== -! HDF5_WRITE_DOUBLE_1DARRAY writes double 1-D array -!=============================================================================== - - subroutine hdf5_write_double_1Darray(group, name, buffer, length) - - integer, intent(in) :: length ! length of array to write - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8), intent(in) :: buffer(:) ! data to write - - ! Set rank and dimensions of data - hdf5_rank = 1 - dims1(1) = length - - ! Write data - call h5ltmake_dataset_double_f(group, name, hdf5_rank, dims1, & - buffer, hdf5_err) - - end subroutine hdf5_write_double_1Darray - -!=============================================================================== -! HDF5_READ_DOUBLE_1DARRAY reads double 1-D array -!=============================================================================== - - subroutine hdf5_read_double_1Darray(group, name, buffer, length) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8), intent(inout) :: buffer(:) ! read data to here - integer, intent(in) :: length ! length of array - - ! Set dimensions - dims1(1) = length - - ! Read data - call h5ltread_dataset_double_f(group, name, buffer, dims1, hdf5_err) - - end subroutine hdf5_read_double_1Darray - -!=============================================================================== -! HDF5_WRITE_DOUBLE_2DARRAY writes double 2-D array -!=============================================================================== - - subroutine hdf5_write_double_2Darray(group, name, buffer, length) - - integer, intent(in) :: length(2) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8), intent(in) :: buffer(length(1),length(2)) ! data to write - - ! Set rank and dimensions - hdf5_rank = 2 - dims2 = length - - ! Write data - call h5ltmake_dataset_double_f(group, name, hdf5_rank, dims2, & - buffer, hdf5_err) - - end subroutine hdf5_write_double_2Darray - -!=============================================================================== -! HDF5_READ_DOUBLE_2DARRAY reads double 2-D array -!=============================================================================== - - subroutine hdf5_read_double_2Darray(group, name, buffer, length) - - integer, intent(in) :: length(2) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8), intent(inout) :: buffer(length(1),length(2)) ! data to read - - ! Set rank and dimensions - dims2 = length - - ! Write data - call h5ltread_dataset_double_f(group, name, buffer, dims2, hdf5_err) - - end subroutine hdf5_read_double_2Darray - -!=============================================================================== -! HDF5_WRITE_DOUBLE_3DARRAY writes double 3-D array -!=============================================================================== - - subroutine hdf5_write_double_3Darray(group, name, buffer, length) - - integer, intent(in) :: length(3) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8), intent(in) :: buffer(length(1),length(2), & - length(3)) ! data to write - - ! Set rank and dimensions - hdf5_rank = 3 - dims3 = length - - ! Write data - call h5ltmake_dataset_double_f(group, name, hdf5_rank, dims3, & - buffer, hdf5_err) - - end subroutine hdf5_write_double_3Darray - -!=============================================================================== -! HDF5_READ_DOUBLE_3DARRAY reads double 3-D array -!=============================================================================== - - subroutine hdf5_read_double_3Darray(group, name, buffer, length) - - integer, intent(in) :: length(3) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8), intent(inout) :: buffer(length(1),length(2), & - length(3)) ! data to read - - ! Set rank and dimensions - dims3 = length - - ! Write data - call h5ltread_dataset_double_f(group, name, buffer, dims3, hdf5_err) - - end subroutine hdf5_read_double_3Darray - -!=============================================================================== -! HDF5_WRITE_DOUBLE_4DARRAY writes double 4-D array -!=============================================================================== - - subroutine hdf5_write_double_4Darray(group, name, buffer, length) - - integer, intent(in) :: length(4) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8), intent(in) :: buffer(length(1),length(2), & - length(3),length(4)) ! data to write - - ! Set rank and dimensions - hdf5_rank = 4 - dims4 = length - - ! Write data - call h5ltmake_dataset_double_f(group, name, hdf5_rank, dims4, & - buffer, hdf5_err) - - end subroutine hdf5_write_double_4Darray - -!=============================================================================== -! HDF5_READ_DOUBLE_4DARRAY reads double 4-D array -!=============================================================================== - - subroutine hdf5_read_double_4Darray(group, name, buffer, length) - - integer, intent(in) :: length(4) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8), intent(inout) :: buffer(length(1),length(2), & - length(3),length(4)) ! data to read - - ! Set rank and dimensions - dims4 = length - - ! Write data - call h5ltread_dataset_double_f(group, name, buffer, dims4, hdf5_err) - - end subroutine hdf5_read_double_4Darray - -!=============================================================================== -! HDF5_WRITE_LONG writes long integer scalar data -!=============================================================================== - - subroutine hdf5_write_long(group, name, buffer, long_type) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer(8), target, intent(in) :: buffer ! data to write - integer(HID_T), intent(in) :: long_type ! HDF5 long type - - ! Set up rank and dimensions - hdf5_rank = 1 - dims1(1) = 1 + subroutine write_double(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name for data + real(8), intent(in), target :: buffer ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + type(c_ptr) :: f_ptr + + ! Set up independentive vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if ! Create dataspace and dataset - call h5screate_simple_f(hdf5_rank, dims1, dspace, hdf5_err) - call h5dcreate_f(group, name, long_type, dspace, dset, hdf5_err) - - ! Write eight-byte integer - f_ptr = c_loc(buffer) - call h5dwrite_f(dset, long_type, f_ptr, hdf5_err) - - ! Close dataspace and dataset for long integer - call h5dclose_f(dset, hdf5_err) - call h5sclose_f(dspace, hdf5_err) - - end subroutine hdf5_write_long - -!=============================================================================== -! HDF5_READ_LONG read long integer scalar data -!=============================================================================== - - subroutine hdf5_read_long(group, name, buffer, long_type) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer(8), target, intent(out) :: buffer ! read data to here - integer(HID_T), intent(in) :: long_type ! long integer type - - ! Open dataset - call h5dopen_f(group, name, dset, hdf5_err) - - ! Get pointer to buffer + call h5screate_f(H5S_SCALAR_F, dspace, hdf5_err) + call h5dcreate_f(group_id, trim(name), H5T_NATIVE_DOUBLE, & + dspace, dset, hdf5_err) f_ptr = c_loc(buffer) - ! Read data from dataset - call h5dread_f(dset, long_type, f_ptr, hdf5_err) - - ! Close dataset - call h5dclose_f(dset, hdf5_err) - - end subroutine hdf5_read_long - -!=============================================================================== -! HDF5_WRITE_STRING writes string data -!=============================================================================== - - subroutine hdf5_write_string(group, name, buffer, length) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - character(*), intent(in) :: buffer ! data to write - integer, intent(in) :: length - - character(len=length), dimension(1) :: str_tmp - -! Fortran 2003 implementation not compatible with IBM compiler Feb 2013 -! type(c_ptr), dimension(1), target :: wdata -! character(len=length, kind=c_char), dimension(1), target :: c_str -! dims1(1) = 1 -! call h5screate_simple_f(1, dims1, dspace, hdf5_err) -! call h5dcreate_f(group, name, H5T_STRING, dspace, dset, hdf5_err) -! c_str(1) = buffer -! wdata(1) = c_loc(c_str(1)) -! f_ptr = c_loc(wdata(1)) - - ! Number of strings to write - dims1(1) = 1 - - ! Insert null character at end of string when writing - call h5tset_strpad_f(H5T_STRING, H5T_STR_NULLPAD_F, hdf5_err) - - ! Create the dataspace and dataset - call h5screate_simple_f(1, dims1, dspace, hdf5_err) - call h5dcreate_f(group, name, H5T_STRING, dspace, dset, hdf5_err) - - ! Set up dimesnions of string to write - dims2 = (/length, 1/) ! full array of strings to write - dims1(1) = length ! length of string - - ! Copy over string buffer to a rank 1 array - str_tmp(1) = buffer - - ! Write the variable dataset - call h5dwrite_vl_f(dset, H5T_STRING, str_tmp, dims2, dims1, hdf5_err, & - mem_space_id=dspace) - - ! Close all - call h5dclose_f(dset, hdf5_err) - call h5sclose_f(dspace, hdf5_err) - - end subroutine hdf5_write_string - -!=============================================================================== -! HDF5_READ_STRING reads string data -!=============================================================================== - - subroutine hdf5_read_string(group, name, buffer, length) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - character(*), intent(inout) :: buffer ! read data to here - integer, intent(in) :: length ! length of string to read - - character(len=length), dimension(1) :: str_tmp - - ! Fortran 2003 implementation not compatible with IBM Feb 2013 compiler -! type(c_ptr), dimension(1), target :: buf_ptr -! character(len=length, kind=c_char), pointer :: chr_ptr -! f_ptr = c_loc(buf_ptr(1)) -! call h5dread_f(dset, H5T_STRING, f_ptr, hdf5_err, xfer_prp=plist) -! call c_f_pointer(buf_ptr(1), chr_ptr) -! buffer = chr_ptr -! nullify(chr_ptr) - - ! Open dataset - call h5dopen_f(group, name, dset, hdf5_err) - - ! Get dataspace to read - call h5dget_space_f(dset, dspace, hdf5_err) - - ! Set dimensions - dims2 = (/length, 1/) - dims1(1) = length - - ! Read in the data - call h5dread_vl_f(dset, H5T_STRING, str_tmp, dims2, dims1, hdf5_err, & - mem_space_id=dspace, xfer_prp = plist) - - ! Copy over buffer - buffer = str_tmp(1) - - ! Close dataset - call h5dclose_f(dset, hdf5_err) - - end subroutine hdf5_read_string - -!=============================================================================== -! HDF5_WRITE_ATTRIBUTE_STRING writes a string attribute to a variables -!=============================================================================== - - subroutine hdf5_write_attribute_string(group, var, attr_type, attr_str) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: var ! name of varaible to set attr - character(*), intent(in) :: attr_type ! the attr type id - character(*), intent(in) :: attr_str ! attribute sting - - call h5ltset_attribute_string_f(group, var, attr_type, attr_str, hdf5_err) - - end subroutine hdf5_write_attribute_string - -# ifdef MPI - -!=============================================================================== -! HDF5_WRITE_INTEGER_PARALLEL writes integer scalar data in parallel -!=============================================================================== - - subroutine hdf5_write_integer_parallel(group, name, buffer, collect) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer,target, intent(in) :: buffer ! data to write - logical, intent(in) :: collect ! collect I/O - - ! Set rank and dimensions - hdf5_rank = 1 - dims1(1) = 1 - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Create dataspace - call h5screate_simple_f(hdf5_rank, dims1, dspace, hdf5_err) - - ! Create dataset - call h5dcreate_f(group, name, H5T_NATIVE_INTEGER, dspace, dset, hdf5_err) - - ! Write data - f_ptr = c_loc(buffer) - call h5dwrite_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close all - call h5dclose_f(dset, hdf5_err) - call h5sclose_f(dspace, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_write_integer_parallel - -!=============================================================================== -! HDF5_READ_INTEGER_PARALLEL reads integer scalar data -!=============================================================================== - - subroutine hdf5_read_integer_parallel(group, name, buffer, collect) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer, target, intent(inout) :: buffer ! read data to here - logical, intent(in) :: collect ! collective I/O - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Open dataset - call h5dopen_f(group, name, dset, hdf5_err) - - ! Read data - f_ptr = c_loc(buffer) - call h5dread_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close dataset and property list - call h5dclose_f(dset, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_read_integer_parallel - -!=============================================================================== -! HDF5_WRITE_INTEGER_1DARRAY_PARALLEL writes integer 1-D array in parallel -!=============================================================================== - - subroutine hdf5_write_integer_1Darray_parallel(group, name, buffer, length, & - collect) - - integer, intent(in) :: length ! length of array to write - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer,target, intent(in) :: buffer(length) ! data to write - logical, intent(in) :: collect ! collect I/O - - ! Set rank and dimensions of data - hdf5_rank = 1 - dims1(1) = length - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Create dataspace - call h5screate_simple_f(hdf5_rank, dims1, dspace, hdf5_err) - - ! Create dataset - call h5dcreate_f(group, name, H5T_NATIVE_INTEGER, dspace, dset, hdf5_err) - - ! Write data - f_ptr = c_loc(buffer) - call h5dwrite_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close all - call h5dclose_f(dset, hdf5_err) - call h5sclose_f(dspace, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_write_integer_1Darray_parallel - -!=============================================================================== -! HDF5_WRITE_INTEGER_1DARRAY_PARALLEL reads integer 1-D array in parallel -!=============================================================================== - - subroutine hdf5_read_integer_1Darray_parallel(group, name, buffer, length, & - collect) - - integer, intent(in) :: length ! length of array - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer, target, intent(inout) :: buffer(length) ! read data to here - logical, intent(in) :: collect ! collective I/O - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Open dataset - call h5dopen_f(group, name, dset, hdf5_err) - - ! Read data - f_ptr = c_loc(buffer) - call h5dread_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close dataset and property list - call h5dclose_f(dset, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_read_integer_1Darray_parallel - -!=============================================================================== -! HDF5_WRITE_INTEGER_2DARRAY_PARALLEL writes integer 2-D array in parallel -!=============================================================================== - - subroutine hdf5_write_integer_2Darray_parallel(group, name, buffer, length, & - collect) - - integer, intent(in) :: length(2) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer,target, intent(in) :: buffer(length(1),length(2)) ! data to write - logical, intent(in) :: collect ! collective I/O - - ! Set rank and dimensions - hdf5_rank = 2 - dims2 = length - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Create dataspace - call h5screate_simple_f(hdf5_rank, dims2, dspace, hdf5_err) - - ! Create dataset - call h5dcreate_f(group, name, H5T_NATIVE_INTEGER, dspace, dset, hdf5_err) - - ! Write data - f_ptr = c_loc(buffer) - call h5dwrite_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close all - call h5dclose_f(dset, hdf5_err) - call h5sclose_f(dspace, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_write_integer_2Darray_parallel - -!=============================================================================== -! HDF5_READ_INTEGER_2DARRAY_PARALLEL reads integer 2-D array in parallel -!=============================================================================== - - subroutine hdf5_read_integer_2Darray_parallel(group, name, buffer, length, & - collect) - - integer, intent(in) :: length(2) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer,target, intent(inout) :: buffer(length(1),length(2)) ! data to read - logical, intent(in) :: collect ! collect I/O - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Open dataset - call h5dopen_f(group, name, dset, hdf5_err) - - ! Read data - f_ptr = c_loc(buffer) - call h5dread_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close dataset and property list - call h5dclose_f(dset, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_read_integer_2Darray_parallel - -!=============================================================================== -! HDF5_WRITE_INTEGER_3DARRAY_PARALLEL writes integer 3-D array in parallel -!=============================================================================== - - subroutine hdf5_write_integer_3Darray_parallel(group, name, buffer, length, & - collect) - - integer, intent(in) :: length(3) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer,target, intent(in) :: buffer(length(1),length(2), & - length(3)) ! data to write - logical, intent(in) :: collect ! collective I/O - - ! Set rank and dimensions - hdf5_rank = 3 - dims3 = length - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Create dataspace - call h5screate_simple_f(hdf5_rank, dims3, dspace, hdf5_err) - - ! Create dataset - call h5dcreate_f(group, name, H5T_NATIVE_INTEGER, dspace, dset, hdf5_err) - - ! Write data - f_ptr = c_loc(buffer) - call h5dwrite_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close all - call h5dclose_f(dset, hdf5_err) - call h5sclose_f(dspace, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_write_integer_3Darray_parallel - -!=============================================================================== -! HDF5_READ_INTEGER_3DARRAY_PARALLEL reads integer 3-D array in parallel -!=============================================================================== - - subroutine hdf5_read_integer_3Darray_parallel(group, name, buffer, length, & - collect) - - integer, intent(in) :: length(3) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer,target, intent(inout) :: buffer(length(1),length(2), & - length(3)) ! data to read - logical, intent(in) :: collect ! collective I/O - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Open dataset - call h5dopen_f(group, name, dset, hdf5_err) - - ! Read data - f_ptr = c_loc(buffer) - call h5dread_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close dataset and property list - call h5dclose_f(dset, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_read_integer_3Darray_parallel - -!=============================================================================== -! HDF5_WRITE_INTEGER_4DARRAY_PARALLEL writes integer 4-D array in parallel -!=============================================================================== - - subroutine hdf5_write_integer_4Darray_parallel(group, name, buffer, length, & - collect) - - integer, intent(in) :: length(4) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer,target, intent(in) :: buffer(length(1),length(2), & - length(3),length(4)) ! data to write - logical, intent(in) :: collect ! collective I/O - - ! Set rank and dimensions - hdf5_rank = 4 - dims4 = length - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Create dataspace - call h5screate_simple_f(hdf5_rank, dims4, dspace, hdf5_err) - - ! Create dataset - call h5dcreate_f(group, name, H5T_NATIVE_INTEGER, dspace, dset, hdf5_err) - - ! Write data - f_ptr = c_loc(buffer) - call h5dwrite_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close all - call h5dclose_f(dset, hdf5_err) - call h5sclose_f(dspace, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_write_integer_4Darray_parallel - -!=============================================================================== -! HDF5_READ_INTEGER_4DARRAY_PARALLEL reads integer 4-D array in parallel -!=============================================================================== - - subroutine hdf5_read_integer_4Darray_parallel(group, name, buffer, length, & - collect) - - integer, intent(in) :: length(4) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer,target, intent(inout) :: buffer(length(1),length(2), & - length(3),length(4)) ! data to read - logical, intent(in) :: collect ! collective I/O - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Open dataset - call h5dopen_f(group, name, dset, hdf5_err) - - ! Read data - f_ptr = c_loc(buffer) - call h5dread_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close dataset and property list - call h5dclose_f(dset, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_read_integer_4Darray_parallel - -!=============================================================================== -! HDF5_WRITE_DOUBLE_PARALLEL writes double scalar data in parallel -!=============================================================================== - - subroutine hdf5_write_double_parallel(group, name, buffer, collect) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8),target, intent(in) :: buffer ! data to write - logical, intent(in) :: collect ! collect I/O - - ! Set rank and dimensions - hdf5_rank = 1 - dims1(1) = 1 - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Create dataspace - call h5screate_simple_f(hdf5_rank, dims1, dspace, hdf5_err) - - ! Create dataset - call h5dcreate_f(group, name, H5T_NATIVE_DOUBLE, dspace, dset, hdf5_err) - - ! Write data - f_ptr = c_loc(buffer) - call h5dwrite_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close all - call h5dclose_f(dset, hdf5_err) - call h5sclose_f(dspace, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_write_double_parallel - -!=============================================================================== -! HDF5_READ_DOUBLE_PARALLEL reads double scalar data -!=============================================================================== - - subroutine hdf5_read_double_parallel(group, name, buffer, collect) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8), target, intent(inout) :: buffer ! read data to here - logical, intent(in) :: collect ! collective I/O - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Open dataset - call h5dopen_f(group, name, dset, hdf5_err) - - ! Read data - f_ptr = c_loc(buffer) - call h5dread_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close dataset and property list - call h5dclose_f(dset, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_read_double_parallel - -!=============================================================================== -! HDF5_WRITE_DOUBLE_1DARRAY_PARALLEL writes double 1-D array in parallel -!=============================================================================== - - subroutine hdf5_write_double_1Darray_parallel(group, name, buffer, length, & - collect) - - integer, intent(in) :: length ! length of array to write - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8),target, intent(in) :: buffer(length) ! data to write - logical, intent(in) :: collect ! collect I/O - - ! Set rank and dimensions of data - hdf5_rank = 1 - dims1(1) = length - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Create dataspace - call h5screate_simple_f(hdf5_rank, dims1, dspace, hdf5_err) - - ! Create dataset - call h5dcreate_f(group, name, H5T_NATIVE_DOUBLE, dspace, dset, hdf5_err) - - ! Write data - f_ptr = c_loc(buffer) - call h5dwrite_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close all - call h5dclose_f(dset, hdf5_err) - call h5sclose_f(dspace, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_write_double_1Darray_parallel - -!=============================================================================== -! HDF5_WRITE_DOUBLE_1DARRAY_PARALLEL reads double 1-D array in parallel -!=============================================================================== - - subroutine hdf5_read_double_1Darray_parallel(group, name, buffer, length, & - collect) - - integer, intent(in) :: length ! length of array - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8),target, intent(inout) :: buffer(length) ! read data to here - logical, intent(in) :: collect ! collective I/O - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Open dataset - call h5dopen_f(group, name, dset, hdf5_err) - - ! Read data - f_ptr = c_loc(buffer) - call h5dread_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close dataset and property list - call h5dclose_f(dset, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_read_double_1Darray_parallel - -!=============================================================================== -! HDF5_WRITE_DOUBLE_2DARRAY_PARALLEL writes double 2-D array in parallel -!=============================================================================== - - subroutine hdf5_write_double_2Darray_parallel(group, name, buffer, length, & - collect) - - integer, intent(in) :: length(2) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8),target, intent(in) :: buffer(length(1),length(2)) ! data to write - logical, intent(in) :: collect ! collective I/O - - ! Set rank and dimensions - hdf5_rank = 2 - dims2 = length - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Create dataspace - call h5screate_simple_f(hdf5_rank, dims2, dspace, hdf5_err) - - ! Create dataset - call h5dcreate_f(group, name, H5T_NATIVE_DOUBLE, dspace, dset, hdf5_err) - - ! Write data - f_ptr = c_loc(buffer(1,1)) - call h5dwrite_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close all - call h5dclose_f(dset, hdf5_err) - call h5sclose_f(dspace, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_write_double_2Darray_parallel - -!=============================================================================== -! HDF5_READ_DOUBLE_2DARRAY_PARALLEL reads double 2-D array in parallel -!=============================================================================== - - subroutine hdf5_read_double_2Darray_parallel(group, name, buffer, length, & - collect) - - integer, intent(in) :: length(2) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8),target, intent(inout) :: buffer(length(1),length(2)) ! data to read - logical, intent(in) :: collect ! collect I/O - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Open dataset - call h5dopen_f(group, name, dset, hdf5_err) - - ! Read data - f_ptr = c_loc(buffer) - call h5dread_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close dataset and property list - call h5dclose_f(dset, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_read_double_2Darray_parallel - -!=============================================================================== -! HDF5_WRITE_DOUBLE_3DARRAY_PARALLEL writes double 3-D array in parallel -!=============================================================================== - - subroutine hdf5_write_double_3Darray_parallel(group, name, buffer, length, & - collect) - - integer, intent(in) :: length(3) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8),target, intent(in) :: buffer(length(1),length(2), & - length(3)) ! data to write - logical, intent(in) :: collect ! collective I/O - - ! Set rank and dimensions - hdf5_rank = 3 - dims3 = length - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Create dataspace - call h5screate_simple_f(hdf5_rank, dims3, dspace, hdf5_err) - - ! Create dataset - call h5dcreate_f(group, name, H5T_NATIVE_DOUBLE, dspace, dset, hdf5_err) - - ! Write data - f_ptr = c_loc(buffer) - call h5dwrite_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close all - call h5dclose_f(dset, hdf5_err) - call h5sclose_f(dspace, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_write_double_3Darray_parallel - -!=============================================================================== -! HDF5_READ_DOUBLE_3DARRAY_PARALLEL reads double 3-D array in parallel -!=============================================================================== - - subroutine hdf5_read_double_3Darray_parallel(group, name, buffer, length, & - collect) - - integer, intent(in) :: length(3) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8),target, intent(inout) :: buffer(length(1),length(2), & - length(3)) ! data to read - logical, intent(in) :: collect ! collective I/O - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Open dataset - call h5dopen_f(group, name, dset, hdf5_err) - - ! Read data - f_ptr = c_loc(buffer) - call h5dread_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close dataset and property list - call h5dclose_f(dset, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_read_double_3Darray_parallel - -!=============================================================================== -! HDF5_WRITE_DOUBLE_4DARRAY_PARALLEL writes double 4-D array in parallel -!=============================================================================== - - subroutine hdf5_write_double_4Darray_parallel(group, name, buffer, length, & - collect) - - integer, intent(in) :: length(4) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8),target, intent(in) :: buffer(length(1),length(2), & - length(3),length(4)) ! data to write - logical, intent(in) :: collect ! collective I/O - - ! Set rank and dimensions - hdf5_rank = 4 - dims4 = length - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Create dataspace - call h5screate_simple_f(hdf5_rank, dims4, dspace, hdf5_err) - - ! Create dataset - call h5dcreate_f(group, name, H5T_NATIVE_DOUBLE, dspace, dset, hdf5_err) - - ! Write data - f_ptr = c_loc(buffer) - call h5dwrite_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close all - call h5dclose_f(dset, hdf5_err) - call h5sclose_f(dspace, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_write_double_4Darray_parallel - -!=============================================================================== -! HDF5_READ_DOUBLE_4DARRAY_PARALLEL reads double 4-D array in parallel -!=============================================================================== - - subroutine hdf5_read_double_4Darray_parallel(group, name, buffer, length, & - collect) - - integer, intent(in) :: length(4) ! length of array dimensions - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - real(8),target, intent(inout) :: buffer(length(1),length(2), & - length(3),length(4)) ! data to read - logical, intent(in) :: collect ! collective I/O - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Open dataset - call h5dopen_f(group, name, dset, hdf5_err) - - ! Read data - f_ptr = c_loc(buffer) - call h5dread_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close dataset and property list - call h5dclose_f(dset, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_read_double_4Darray_parallel - -!=============================================================================== -! HDF5_WRITE_LONG_PARALLEL writes long integer scalar data in parallel -!=============================================================================== - - subroutine hdf5_write_long_parallel(group, name, buffer, long_type, collect) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer(8), target, intent(in) :: buffer ! data to write - integer(HID_T), intent(in) :: long_type ! HDF5 long type - logical, intent(in) :: collect ! collective I/O - - ! Set up rank and dimensions - hdf5_rank = 1 - dims1(1) = 1 - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Create dataspace - call h5screate_simple_f(hdf5_rank, dims1, dspace, hdf5_err) - - ! Create dataset - call h5dcreate_f(group, name, long_type, dspace, dset, hdf5_err) - - ! Write data - f_ptr = c_loc(buffer) - call h5dwrite_f(dset, long_type, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close all - call h5dclose_f(dset, hdf5_err) - call h5sclose_f(dspace, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_write_long_parallel - -!=============================================================================== -! HDF5_READ_LONG_PARALLEL read long integer scalar data in parallel -!=============================================================================== - - subroutine hdf5_read_long_parallel(group, name, buffer, long_type, collect) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - integer(8), target, intent(out) :: buffer ! read data to here - integer(HID_T), intent(in) :: long_type ! long integer type - logical, intent(in) :: collect ! collective I/O - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Open dataset - call h5dopen_f(group, name, dset, hdf5_err) - - ! Read data - f_ptr = c_loc(buffer) - call h5dread_f(dset, long_type, f_ptr, hdf5_err, xfer_prp=plist) - - ! Close dataset and property list - call h5dclose_f(dset, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_read_long_parallel - -!=============================================================================== -! HDF5_WRITE_STRING_PARALLEL writes string data in parallel -!=============================================================================== - - subroutine hdf5_write_string_parallel(group, name, buffer, length, collect) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - character(*), intent(in) :: buffer ! data to write - integer, intent(in) :: length ! length of string - logical, intent(in) :: collect ! collective I/O - - character(len=length), dimension(1) :: str_tmp - -! Fortran 2003 implementation not compatible with IBM compiler Feb 2013 -! type(c_ptr), dimension(1), target :: wdata -! character(len=length, kind=c_char), dimension(1), target :: c_str -! dims1(1) = 1 -! call h5screate_simple_f(1, dims1, dspace, hdf5_err) -! call h5dcreate_f(group, name, H5T_STRING, dspace, dset, hdf5_err) -! c_str(1) = buffer -! wdata(1) = c_loc(c_str(1)) -! f_ptr = c_loc(wdata(1)) - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Number of strings to write - dims1(1) = 1 - - ! Insert null character at end of string when writing - call h5tset_strpad_f(H5T_STRING, H5T_STR_NULLPAD_F, hdf5_err) - - ! Create the dataspace and dataset - call h5screate_simple_f(1, dims1, dspace, hdf5_err) - call h5dcreate_f(group, name, H5T_STRING, dspace, dset, hdf5_err) - - ! Set up dimesnions of string to write - dims2 = (/length, 1/) ! full array of strings to write - dims1(1) = length ! length of string - - ! Copy over string buffer to a rank 1 array - str_tmp(1) = buffer - - ! Write the variable dataset - call h5dwrite_vl_f(dset, H5T_STRING, str_tmp, dims2, dims1, hdf5_err, & - mem_space_id=dspace, xfer_prp=plist) - - ! Close all - call h5dclose_f(dset, hdf5_err) - call h5sclose_f(dspace, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_write_string_parallel - -!=============================================================================== -! HDF5_READ_STRING_PARALLEL reads string data in parallel -!=============================================================================== - - subroutine hdf5_read_string_parallel(group, name, buffer, length, collect) - - integer(HID_T), intent(in) :: group ! name of group - character(*), intent(in) :: name ! name of data - character(*), intent(inout) :: buffer ! read data to here - integer, intent(in) :: length ! length of string - logical, intent(in) :: collect ! collective I/O - - character(len=length), dimension(1) :: str_tmp - - ! Fortran 2003 implementation not compatible with IBM Feb 2013 compiler -! type(c_ptr), dimension(1), target :: buf_ptr -! character(len=length, kind=c_char), pointer :: chr_ptr -! f_ptr = c_loc(buf_ptr(1)) -! call h5dread_f(dset, H5T_STRING, f_ptr, hdf5_err, xfer_prp=plist) -! call c_f_pointer(buf_ptr(1), chr_ptr) -! buffer = chr_ptr -! nullify(chr_ptr) - - ! Create property list for independent or collective read - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - - ! Set independent or collective option - if (collect) then - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - else - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_INDEPENDENT_F, hdf5_err) - end if - - ! Open dataset - call h5dopen_f(group, name, dset, hdf5_err) - - ! Get dataspace to read - call h5dget_space_f(dset, dspace, hdf5_err) - - ! Set dimensions - dims2 = (/length, 1/) - dims1(1) = length - - ! Read in the data - call h5dread_vl_f(dset, H5T_STRING, str_tmp, dims2, dims1, hdf5_err, & - mem_space_id=dspace, xfer_prp = plist) - - ! Copy over buffer - buffer = str_tmp(1) - - ! Close dataset and property list - call h5dclose_f(dset, hdf5_err) - call h5pclose_f(plist, hdf5_err) - - end subroutine hdf5_read_string_parallel - -# endif - + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dwrite_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) #endif + else + call h5dwrite_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + end subroutine write_double + +!=============================================================================== +! READ_DOUBLE reads double precision scalar data +!=============================================================================== + + subroutine read_double(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name for data + real(8), intent(inout), target :: buffer ! read data to here + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5dopen_f(group_id, trim(name), dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dread_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dread_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + end subroutine read_double + +!=============================================================================== +! WRITE_DOUBLE_1D writes double precision 1-D array data +!=============================================================================== + + subroutine write_double_1D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + real(8), intent(in), target :: buffer(:) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(1) + + dims(:) = shape(buffer) + if (present(indep)) then + call write_double_1D_explicit(group_id, dims, name, buffer, indep) + else + call write_double_1D_explicit(group_id, dims, name, buffer) + end if + end subroutine write_double_1D + + subroutine write_double_1D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(1) + character(*), intent(in) :: name ! name of data + real(8), intent(in), target :: buffer(dims(1)) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5screate_simple_f(1, dims, dspace, hdf5_err) + call h5dcreate_f(group_id, trim(name), H5T_NATIVE_DOUBLE, & + dspace, dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dwrite_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dwrite_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + end subroutine write_double_1D_explicit + +!=============================================================================== +! READ_DOUBLE_1D reads double precision 1-D array data +!=============================================================================== + + subroutine read_double_1D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + real(8), intent(inout), target :: buffer(:) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(1) + + dims(:) = shape(buffer) + if (present(indep)) then + call read_double_1D_explicit(group_id, dims, name, buffer, indep) + else + call read_double_1D_explicit(group_id, dims, name, buffer) + end if + end subroutine read_double_1D + + subroutine read_double_1D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(1) + character(*), intent(in) :: name ! name of data + real(8), intent(inout), target :: buffer(dims(1)) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5dopen_f(group_id, trim(name), dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dread_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dread_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + end subroutine read_double_1D_explicit + +!=============================================================================== +! WRITE_DOUBLE_2D writes double precision 2-D array data +!=============================================================================== + + subroutine write_double_2D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + real(8), intent(in), target :: buffer(:,:) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(2) + + dims(:) = shape(buffer) + if (present(indep)) then + call write_double_2D_explicit(group_id, dims, name, buffer, indep) + else + call write_double_2D_explicit(group_id, dims, name, buffer) + end if + end subroutine write_double_2D + + subroutine write_double_2D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(2) + character(*), intent(in) :: name ! name of data + real(8), intent(in), target :: buffer(dims(1),dims(2)) + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5screate_simple_f(2, dims, dspace, hdf5_err) + call h5dcreate_f(group_id, trim(name), H5T_NATIVE_DOUBLE, & + dspace, dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dwrite_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dwrite_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + end subroutine write_double_2D_explicit + +!=============================================================================== +! READ_DOUBLE_2D reads double precision 2-D array data +!=============================================================================== + + subroutine read_double_2D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + real(8), intent(inout), target :: buffer(:,:) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(2) + + dims(:) = shape(buffer) + if (present(indep)) then + call read_double_2D_explicit(group_id, dims, name, buffer, indep) + else + call read_double_2D_explicit(group_id, dims, name, buffer) + end if + end subroutine read_double_2D + + subroutine read_double_2D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(2) + character(*), intent(in) :: name ! name of data + real(8), intent(inout), target :: buffer(dims(1),dims(2)) + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5dopen_f(group_id, trim(name), dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dread_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dread_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + end subroutine read_double_2D_explicit + +!=============================================================================== +! WRITE_DOUBLE_3D writes double precision 3-D array data +!=============================================================================== + + subroutine write_double_3D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + real(8), intent(in), target :: buffer(:,:,:) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(3) + + dims(:) = shape(buffer) + if (present(indep)) then + call write_double_3D_explicit(group_id, dims, name, buffer, indep) + else + call write_double_3D_explicit(group_id, dims, name, buffer) + end if + end subroutine write_double_3D + + subroutine write_double_3D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(3) + character(*), intent(in) :: name ! name of data + real(8), intent(in), target :: buffer(dims(1),dims(2),dims(3)) + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5screate_simple_f(3, dims, dspace, hdf5_err) + call h5dcreate_f(group_id, trim(name), H5T_NATIVE_DOUBLE, & + dspace, dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dwrite_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dwrite_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + end subroutine write_double_3D_explicit + +!=============================================================================== +! READ_DOUBLE_3D reads double precision 3-D array data +!=============================================================================== + + subroutine read_double_3D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + real(8), intent(inout), target :: buffer(:,:,:) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(3) + + dims(:) = shape(buffer) + if (present(indep)) then + call read_double_3D_explicit(group_id, dims, name, buffer, indep) + else + call read_double_3D_explicit(group_id, dims, name, buffer) + end if + end subroutine read_double_3D + + subroutine read_double_3D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(3) + character(*), intent(in) :: name ! name of data + real(8), intent(inout), target :: buffer(dims(1),dims(2),dims(3)) + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5dopen_f(group_id, trim(name), dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dread_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dread_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + end subroutine read_double_3D_explicit + +!=============================================================================== +! WRITE_DOUBLE_4D writes double precision 4-D array data +!=============================================================================== + + subroutine write_double_4D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + real(8), intent(in), target :: buffer(:,:,:,:) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(4) + + dims(:) = shape(buffer) + if (present(indep)) then + call write_double_4D_explicit(group_id, dims, name, buffer, indep) + else + call write_double_4D_explicit(group_id, dims, name, buffer) + end if + end subroutine write_double_4D + + subroutine write_double_4D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(4) + character(*), intent(in) :: name ! name of data + real(8), intent(in), target :: buffer(dims(1),dims(2),dims(3),dims(4)) + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5screate_simple_f(4, dims, dspace, hdf5_err) + call h5dcreate_f(group_id, trim(name), H5T_NATIVE_DOUBLE, & + dspace, dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dwrite_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dwrite_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + end subroutine write_double_4D_explicit + +!=============================================================================== +! READ_DOUBLE_4D reads double precision 4-D array data +!=============================================================================== + + subroutine read_double_4D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + real(8), intent(inout), target :: buffer(:,:,:,:) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(4) + + dims(:) = shape(buffer) + if (present(indep)) then + call read_double_4D_explicit(group_id, dims, name, buffer, indep) + else + call read_double_4D_explicit(group_id, dims, name, buffer) + end if + end subroutine read_double_4D + + subroutine read_double_4D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(4) + character(*), intent(in) :: name ! name of data + real(8), intent(inout), target :: buffer(dims(1),dims(2),dims(3),dims(4)) + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5dopen_f(group_id, trim(name), dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dread_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dread_f(dset, H5T_NATIVE_DOUBLE, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + end subroutine read_double_4D_explicit + +!=============================================================================== +! WRITE_INTEGER writes integer precision scalar data +!=============================================================================== + + subroutine write_integer(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name for data + integer, intent(in), target :: buffer ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + ! Create dataspace and dataset + call h5screate_f(H5S_SCALAR_F, dspace, hdf5_err) + call h5dcreate_f(group_id, trim(name), H5T_NATIVE_INTEGER, & + dspace, dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dwrite_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dwrite_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + end subroutine write_integer + +!=============================================================================== +! READ_INTEGER reads integer precision scalar data +!=============================================================================== + + subroutine read_integer(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name for data + integer, intent(inout), target :: buffer ! read data to here + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5dopen_f(group_id, trim(name), dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dread_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dread_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + end subroutine read_integer + +!=============================================================================== +! WRITE_INTEGER_1D writes integer precision 1-D array data +!=============================================================================== + + subroutine write_integer_1D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + integer, intent(in), target :: buffer(:) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(1) + + dims(:) = shape(buffer) + if (present(indep)) then + call write_integer_1D_explicit(group_id, dims, name, buffer, indep) + else + call write_integer_1D_explicit(group_id, dims, name, buffer) + end if + end subroutine write_integer_1D + + subroutine write_integer_1D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(1) + character(*), intent(in) :: name ! name of data + integer, intent(in), target :: buffer(dims(1)) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5screate_simple_f(1, dims, dspace, hdf5_err) + call h5dcreate_f(group_id, trim(name), H5T_NATIVE_INTEGER, & + dspace, dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dwrite_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dwrite_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + end subroutine write_integer_1D_explicit + +!=============================================================================== +! READ_INTEGER_1D reads integer precision 1-D array data +!=============================================================================== + + subroutine read_integer_1D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + integer, intent(inout), target :: buffer(:) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(1) + + dims(:) = shape(buffer) + if (present(indep)) then + call read_integer_1D_explicit(group_id, dims, name, buffer, indep) + else + call read_integer_1D_explicit(group_id, dims, name, buffer) + end if + end subroutine read_integer_1D + + subroutine read_integer_1D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(1) + character(*), intent(in) :: name ! name of data + integer, intent(inout), target :: buffer(dims(1)) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5dopen_f(group_id, trim(name), dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dread_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dread_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + end subroutine read_integer_1D_explicit + +!=============================================================================== +! WRITE_INTEGER_2D writes integer precision 2-D array data +!=============================================================================== + + subroutine write_integer_2D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + integer, intent(in), target :: buffer(:,:) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(2) + + dims(:) = shape(buffer) + if (present(indep)) then + call write_integer_2D_explicit(group_id, dims, name, buffer, indep) + else + call write_integer_2D_explicit(group_id, dims, name, buffer) + end if + end subroutine write_integer_2D + + subroutine write_integer_2D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(2) + character(*), intent(in) :: name ! name of data + integer, intent(in), target :: buffer(dims(1),dims(2)) + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5screate_simple_f(2, dims, dspace, hdf5_err) + call h5dcreate_f(group_id, trim(name), H5T_NATIVE_INTEGER, & + dspace, dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dwrite_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dwrite_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + end subroutine write_integer_2D_explicit + +!=============================================================================== +! READ_INTEGER_2D reads integer precision 2-D array data +!=============================================================================== + + subroutine read_integer_2D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + integer, intent(inout), target :: buffer(:,:) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(2) + + dims(:) = shape(buffer) + if (present(indep)) then + call read_integer_2D_explicit(group_id, dims, name, buffer, indep) + else + call read_integer_2D_explicit(group_id, dims, name, buffer) + end if + end subroutine read_integer_2D + + subroutine read_integer_2D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(2) + character(*), intent(in) :: name ! name of data + integer, intent(inout), target :: buffer(dims(1),dims(2)) + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5dopen_f(group_id, trim(name), dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dread_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dread_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + end subroutine read_integer_2D_explicit + +!=============================================================================== +! WRITE_INTEGER_3D writes integer precision 3-D array data +!=============================================================================== + + subroutine write_integer_3D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + integer, intent(in), target :: buffer(:,:,:) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(3) + + dims(:) = shape(buffer) + if (present(indep)) then + call write_integer_3D_explicit(group_id, dims, name, buffer, indep) + else + call write_integer_3D_explicit(group_id, dims, name, buffer) + end if + end subroutine write_integer_3D + + subroutine write_integer_3D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(3) + character(*), intent(in) :: name ! name of data + integer, intent(in), target :: buffer(dims(1),dims(2),dims(3)) + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5screate_simple_f(3, dims, dspace, hdf5_err) + call h5dcreate_f(group_id, trim(name), H5T_NATIVE_INTEGER, & + dspace, dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dwrite_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dwrite_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + end subroutine write_integer_3D_explicit + +!=============================================================================== +! READ_INTEGER_3D reads integer precision 3-D array data +!=============================================================================== + + subroutine read_integer_3D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + integer, intent(inout), target :: buffer(:,:,:) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(3) + + dims(:) = shape(buffer) + if (present(indep)) then + call read_integer_3D_explicit(group_id, dims, name, buffer, indep) + else + call read_integer_3D_explicit(group_id, dims, name, buffer) + end if + end subroutine read_integer_3D + + subroutine read_integer_3D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(3) + character(*), intent(in) :: name ! name of data + integer, intent(inout), target :: buffer(dims(1),dims(2),dims(3)) + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5dopen_f(group_id, trim(name), dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dread_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dread_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + end subroutine read_integer_3D_explicit + +!=============================================================================== +! WRITE_INTEGER_4D writes integer precision 4-D array data +!=============================================================================== + + subroutine write_integer_4D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + integer, intent(in), target :: buffer(:,:,:,:) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(4) + + dims(:) = shape(buffer) + if (present(indep)) then + call write_integer_4D_explicit(group_id, dims, name, buffer, indep) + else + call write_integer_4D_explicit(group_id, dims, name, buffer) + end if + end subroutine write_integer_4D + + subroutine write_integer_4D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(4) + character(*), intent(in) :: name ! name of data + integer, intent(in), target :: buffer(dims(1),dims(2),dims(3),dims(4)) + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5screate_simple_f(4, dims, dspace, hdf5_err) + call h5dcreate_f(group_id, trim(name), H5T_NATIVE_INTEGER, & + dspace, dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dwrite_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dwrite_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + end subroutine write_integer_4D_explicit + +!=============================================================================== +! READ_INTEGER_4D reads integer precision 4-D array data +!=============================================================================== + + subroutine read_integer_4D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + integer, intent(inout), target :: buffer(:,:,:,:) ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(4) + + dims(:) = shape(buffer) + if (present(indep)) then + call read_integer_4D_explicit(group_id, dims, name, buffer, indep) + else + call read_integer_4D_explicit(group_id, dims, name, buffer) + end if + end subroutine read_integer_4D + + subroutine read_integer_4D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(4) + character(*), intent(in) :: name ! name of data + integer, intent(inout), target :: buffer(dims(1),dims(2),dims(3),dims(4)) + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5dopen_f(group_id, trim(name), dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dread_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dread_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + end subroutine read_integer_4D_explicit + +!=============================================================================== +! WRITE_LONG writes long integer scalar data +!=============================================================================== + + subroutine write_long(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name for data + integer(8), intent(in), target :: buffer ! data to write + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + ! Create dataspace and dataset + call h5screate_f(H5S_SCALAR_F, dspace, hdf5_err) + call h5dcreate_f(group_id, trim(name), hdf5_integer8_t, & + dspace, dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dwrite_f(dset, hdf5_integer8_t, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dwrite_f(dset, hdf5_integer8_t, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + end subroutine write_long + +!=============================================================================== +! READ_LONG reads long integer scalar data +!=============================================================================== + + subroutine read_long(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name for data + integer(8), intent(inout), target :: buffer ! read data to here + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + call h5dopen_f(group_id, trim(name), dset, hdf5_err) + f_ptr = c_loc(buffer) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dread_f(dset, hdf5_integer8_t, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dread_f(dset, hdf5_integer8_t, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + end subroutine read_long + +!=============================================================================== +! WRITE_STRING writes string data +!=============================================================================== + + subroutine write_string(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name for data + character(*), intent(in), target :: buffer ! read data to here + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + integer(HID_T) :: filetype + integer(HID_T) :: memtype + integer(HSIZE_T) :: n + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + ! Create datatype for HDF5 file based on C char + n = len_trim(buffer) + call h5tcopy_f(H5T_C_S1, filetype, hdf5_err) + call h5tset_size_f(filetype, n + 1, hdf5_err) + + ! Create datatype in memory based on Fortran character + call h5tcopy_f(H5T_FORTRAN_S1, memtype, hdf5_err) + if (n > 0) call h5tset_size_f(memtype, n, hdf5_err) + + ! Create dataspace/dataset + call h5screate_f(H5S_SCALAR_F, dspace, hdf5_err) + call h5dcreate_f(group_id, trim(name), filetype, dspace, dset, hdf5_err) + + ! Get pointer to start of string + f_ptr = c_loc(buffer(1:1)) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + if (n > 0) call h5dwrite_f(dset, memtype, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + if (n > 0) call h5dwrite_f(dset, memtype, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + call h5tclose_f(memtype, hdf5_err) + call h5tclose_f(filetype, hdf5_err) + end subroutine write_string + +!=============================================================================== +! READ_STRING reads string data +!=============================================================================== + + subroutine read_string(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name for data + character(*), intent(inout), target :: buffer ! read data to here + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + integer(HID_T) :: filetype + integer(HID_T) :: memtype + integer(HSIZE_T) :: size + integer(HSIZE_T) :: n + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + ! Get dataset and dataspace + call h5dopen_f(group_id, trim(name), dset, hdf5_err) + call h5dget_space_f(dset, dspace, hdf5_err) + + ! Make sure buffer is large enough + call h5dget_type_f(dset, filetype, hdf5_err) + call h5tget_size_f(filetype, size, hdf5_err) + if (size > len(buffer) + 1) then + call fatal_error("Character buffer is not long enough to & + &read HDF5 string.") + end if + + ! Get datatype in memory based on Fortran character + n = len(buffer) + call h5tcopy_f(H5T_FORTRAN_S1, memtype, hdf5_err) + call h5tset_size_f(memtype, n, hdf5_err) + + ! Get pointer to start of string + f_ptr = c_loc(buffer(1:1)) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dread_f(dset, memtype, f_ptr, hdf5_err, mem_space_id=dspace, & + xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dread_f(dset, memtype, f_ptr, hdf5_err, mem_space_id=dspace) + end if + + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + call h5tclose_f(filetype, hdf5_err) + call h5tclose_f(memtype, hdf5_err) + end subroutine read_string + +!=============================================================================== +! WRITE_STRING_1D writes string 1-D array data +!=============================================================================== + + subroutine write_string_1D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name for data + character(*), intent(in), target :: buffer(:) ! read data to here + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(1) + + dims(:) = shape(buffer) + if (present(indep)) then + call write_string_1D_explicit(group_id, dims, name, buffer, indep) + else + call write_string_1D_explicit(group_id, dims, name, buffer) + end if + end subroutine write_string_1D + + subroutine write_string_1D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(1) + character(*), intent(in) :: name + character(*), intent(in), target :: buffer(dims(1)) + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + integer(HID_T) :: filetype + integer(HID_T) :: memtype + integer(HSIZE_T) :: n + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + ! Create datatype for HDF5 file based on C char + n = maxval(len_trim(buffer)) + call h5tcopy_f(H5T_C_S1, filetype, hdf5_err) + call h5tset_size_f(filetype, n + 1, hdf5_err) + + ! Create datatype in memory based on Fortran character + call h5tcopy_f(H5T_FORTRAN_S1, memtype, hdf5_err) + call h5tset_size_f(memtype, int(len(buffer(1)), HSIZE_T), hdf5_err) + + ! Create dataspace/dataset + call h5screate_simple_f(1, dims, dspace, hdf5_err) + call h5dcreate_f(group_id, trim(name), filetype, dspace, dset, hdf5_err) + + ! Get pointer to start of string + f_ptr = c_loc(buffer(1)(1:1)) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + if (n > 0) call h5dwrite_f(dset, memtype, f_ptr, hdf5_err, xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + if (n > 0) call h5dwrite_f(dset, memtype, f_ptr, hdf5_err) + end if + + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + call h5tclose_f(memtype, hdf5_err) + call h5tclose_f(filetype, hdf5_err) + end subroutine write_string_1D_explicit + +!=============================================================================== +! READ_STRING_1D reads string 1-D array data +!=============================================================================== + + subroutine read_string_1D(group_id, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name + character(*), intent(inout), target :: buffer(:) + logical, intent(in), optional :: indep ! independent I/O + + integer(HSIZE_T) :: dims(1) + + dims(:) = shape(buffer) + if (present(indep)) then + call read_string_1D_explicit(group_id, dims, name, buffer, indep) + else + call read_string_1D_explicit(group_id, dims, name, buffer) + end if + end subroutine read_string_1D + + subroutine read_string_1D_explicit(group_id, dims, name, buffer, indep) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(1) + character(*), intent(in) :: name + character(*), intent(inout), target :: buffer(dims(1)) + logical, intent(in), optional :: indep ! independent I/O + + integer :: hdf5_err + integer :: data_xfer_mode +#ifdef PHDF5 + integer(HID_T) :: plist ! property list +#endif + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + integer(HID_T) :: filetype + integer(HID_T) :: memtype + integer(HSIZE_T) :: size + integer(HSIZE_T) :: n + type(c_ptr) :: f_ptr + + ! Set up collective vs. independent I/O + data_xfer_mode = H5FD_MPIO_COLLECTIVE_F + if (present(indep)) then + if (indep) data_xfer_mode = H5FD_MPIO_INDEPENDENT_F + end if + + ! Get dataset and dataspace + call h5dopen_f(group_id, trim(name), dset, hdf5_err) + call h5dget_space_f(dset, dspace, hdf5_err) + + ! Make sure buffer is large enough + call h5dget_type_f(dset, filetype, hdf5_err) + call h5tget_size_f(filetype, size, hdf5_err) + if (size > len(buffer(1)) + 1) then + call fatal_error("Character buffer is not long enough to & + &read HDF5 string array.") + end if + + ! Get datatype in memory based on Fortran character + n = len(buffer(1)) + call h5tcopy_f(H5T_FORTRAN_S1, memtype, hdf5_err) + call h5tset_size_f(memtype, n, hdf5_err) + + ! Get pointer to start of string + f_ptr = c_loc(buffer(1)(1:1)) + + if (using_mpio_device(group_id)) then +#ifdef PHDF5 + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, data_xfer_mode, hdf5_err) + call h5dread_f(dset, memtype, f_ptr, hdf5_err, mem_space_id=dspace, & + xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#endif + else + call h5dread_f(dset, memtype, f_ptr, hdf5_err, mem_space_id=dspace) + end if + + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + call h5tclose_f(filetype, hdf5_err) + call h5tclose_f(memtype, hdf5_err) + end subroutine read_string_1D_explicit + +!=============================================================================== +! WRITE_ATTRIBUTE_STRING +!=============================================================================== + + subroutine write_attribute_string(group_id, var, attr_type, attr_str) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: var ! variable name for attr + character(*), intent(in) :: attr_type ! attr identifier type + character(*), intent(in) :: attr_str ! string for attr id type + + integer :: hdf5_err + + call h5ltset_attribute_string_f(group_id, var, attr_type, attr_str, hdf5_err) + end subroutine write_attribute_string + +!=============================================================================== +! WRITE_TALLY_RESULT writes an OpenMC TallyResult type +!=============================================================================== + + subroutine write_tally_result_1D(group_id, name, buffer) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + type(TallyResult), intent(in), target :: buffer(:) ! data to write + + integer(HSIZE_T) :: dims(1) + + dims(:) = shape(buffer) + call write_tally_result_1D_explicit(group_id, dims, name, buffer) + end subroutine write_tally_result_1D + + subroutine write_tally_result_1D_explicit(group_id, dims, name, buffer) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(1) + character(*), intent(in) :: name ! name of data + type(TallyResult), intent(in), target :: buffer(dims(1)) + + integer :: hdf5_err + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + type(c_ptr) :: f_ptr + + call h5screate_simple_f(1, dims, dspace, hdf5_err) + call h5dcreate_f(group_id, trim(name), hdf5_tallyresult_t, & + dspace, dset, hdf5_err) + f_ptr = c_loc(buffer) + call h5dwrite_f(dset, hdf5_tallyresult_t, f_ptr, hdf5_err) + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + end subroutine write_tally_result_1D_explicit + + subroutine write_tally_result_2D(group_id, name, buffer) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + type(TallyResult), intent(in), target :: buffer(:,:) ! data to write + + integer(HSIZE_T) :: dims(2) + + dims(:) = shape(buffer) + call write_tally_result_2D_explicit(group_id, dims, name, buffer) + end subroutine write_tally_result_2D + + subroutine write_tally_result_2D_explicit(group_id, dims, name, buffer) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(2) + character(*), intent(in) :: name ! name of data + type(TallyResult), intent(in), target :: buffer(dims(1),dims(2)) + + integer :: hdf5_err + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + type(c_ptr) :: f_ptr + + call h5screate_simple_f(2, dims, dspace, hdf5_err) + call h5dcreate_f(group_id, trim(name), hdf5_tallyresult_t, & + dspace, dset, hdf5_err) + f_ptr = c_loc(buffer) + call h5dwrite_f(dset, hdf5_tallyresult_t, f_ptr, hdf5_err) + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + end subroutine write_tally_result_2D_explicit + +!=============================================================================== +! READ_TALLY_RESULT reads OpenMC TallyResult data +!=============================================================================== + + subroutine read_tally_result_1D(group_id, name, buffer) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + type(TallyResult), intent(inout), target :: buffer(:) ! read data here + + integer(HSIZE_T) :: dims(1) + + dims(:) = shape(buffer) + call read_tally_result_1D_explicit(group_id, dims, name, buffer) + end subroutine read_tally_result_1D + + subroutine read_tally_result_1D_explicit(group_id, dims, name, buffer) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(1) + character(*), intent(in) :: name ! name of data + type(TallyResult), intent(inout), target :: buffer(dims(1)) + + integer :: hdf5_err + integer(HID_T) :: dset ! data set handle + type(c_ptr) :: f_ptr + + call h5dopen_f(group_id, trim(name), dset, hdf5_err) + f_ptr = c_loc(buffer) + call h5dread_f(dset, hdf5_tallyresult_t, f_ptr, hdf5_err) + call h5dclose_f(dset, hdf5_err) + end subroutine read_tally_result_1D_explicit + + subroutine read_tally_result_2D(group_id, name, buffer) + integer(HID_T), intent(in) :: group_id + character(*), intent(in) :: name ! name of data + type(TallyResult), intent(inout), target :: buffer(:,:) + + integer(HSIZE_T) :: dims(2) + + dims(:) = shape(buffer) + call read_tally_result_2D_explicit(group_id, dims, name, buffer) + end subroutine read_tally_result_2D + + subroutine read_tally_result_2D_explicit(group_id, dims, name, buffer) + integer(HID_T), intent(in) :: group_id + integer(HSIZE_T), intent(in) :: dims(2) + character(*), intent(in) :: name ! name of data + type(TallyResult), intent(inout), target :: buffer(dims(1),dims(2)) + + integer :: hdf5_err + integer(HID_T) :: dset ! data set handle + type(c_ptr) :: f_ptr + + call h5dopen_f(group_id, trim(name), dset, hdf5_err) + f_ptr = c_loc(buffer) + call h5dread_f(dset, hdf5_tallyresult_t, f_ptr, hdf5_err) + call h5dclose_f(dset, hdf5_err) + end subroutine read_tally_result_2D_explicit + + function using_mpio_device(obj_id) result(mpio) + integer(HID_T), intent(in) :: obj_id + logical :: mpio + + integer :: hdf5_err + integer :: driver + integer(HID_T) :: file_id + integer(HID_T) :: fapl_id + + ! Determine file that this object is part of + call h5iget_file_id_f(obj_id, file_id, hdf5_err) + + ! Get file access property list + call h5fget_access_plist_f(file_id, fapl_id, hdf5_err) + + ! Get low-level driver identifier + call h5pget_driver_f(fapl_id, driver, hdf5_err) + + ! Close file access property list access + call h5pclose_f(fapl_id, hdf5_err) + + ! Close file access -- note that this only decreases the reference count so + ! that the file is not actually closed + call h5fclose_f(file_id, hdf5_err) + + mpio = (driver == H5FD_MPIO_F) + end function using_mpio_device end module hdf5_interface diff --git a/src/hdf5_summary.F90 b/src/hdf5_summary.F90 deleted file mode 100644 index 375ab7460..000000000 --- a/src/hdf5_summary.F90 +++ /dev/null @@ -1,880 +0,0 @@ -module hdf5_summary - -#ifdef HDF5 - - use ace_header, only: Reaction, UrrData, Nuclide - use constants - use endf, only: reaction_name - use geometry_header, only: Cell, Surface, Universe, Lattice, RectLattice, & - &HexLattice - use global - use material_header, only: Material - use mesh_header, only: StructuredMesh - use output_interface - use output, only: time_stamp - use string, only: to_str - use tally_header, only: TallyObject - - implicit none - - type(BinaryOutput) :: su - -contains - -!=============================================================================== -! HDF5_WRITE_SUMMARY -!=============================================================================== - - subroutine hdf5_write_summary() - - character(MAX_FILE_LEN) :: filename = "summary.h5" - - ! Create a new file using default properties. - call su % file_create(filename) - - ! Write header information - call hdf5_write_header() - - ! Write eigenvalue information - if (run_mode == MODE_EIGENVALUE) then - - ! Write number of particles - call su % write_data(n_particles, "n_particles") - - ! Use H5LT interface to write n_batches, n_inactive, and n_active - call su % write_data(n_batches, "n_batches") - call su % write_data(n_inactive, "n_inactive") - call su % write_data(n_active, "n_active") - call su % write_data(gen_per_batch, "gen_per_batch") - - ! Add description of each variable - call su % write_attribute_string("n_particles", & - "description", "Number of particles per generation") - call su % write_attribute_string("n_batches", & - "description", "Total number of batches") - call su % write_attribute_string("n_inactive", & - "description", "Number of inactive batches") - call su % write_attribute_string("n_active", & - "description", "Number of active batches") - call su % write_attribute_string("gen_per_batch", & - "description", "Number of generations per batch") - end if - - call hdf5_write_geometry() - call hdf5_write_materials() - call hdf5_write_nuclides() - if (n_tallies > 0) then - call hdf5_write_tallies() - end if - - ! Terminate access to the file. - call su % file_close() - - end subroutine hdf5_write_summary - -!=============================================================================== -! HDF5_WRITE_HEADER -!=============================================================================== - - subroutine hdf5_write_header() - - ! Write version information - call su % write_data(VERSION_MAJOR, "version_major") - call su % write_data(VERSION_MINOR, "version_minor") - call su % write_data(VERSION_RELEASE, "version_release") - - ! Write current date and time - call su % write_data(time_stamp(), "date_and_time") - - ! Write MPI information - call su % write_data(n_procs, "n_procs") - call su % write_attribute_string("n_procs", "description", & - "Number of MPI processes") - - end subroutine hdf5_write_header - -!=============================================================================== -! HDF5_WRITE_GEOMETRY -!=============================================================================== - - subroutine hdf5_write_geometry() - - integer :: i, j, k, m - integer, allocatable :: lattice_universes(:,:,:) - type(Cell), pointer :: c => null() - type(Surface), pointer :: s => null() - type(Universe), pointer :: u => null() - class(Lattice), pointer :: lat => null() - - ! Use H5LT interface to write number of geometry objects - call su % write_data(n_cells, "n_cells", group="geometry") - call su % write_data(n_surfaces, "n_surfaces", group="geometry") - call su % write_data(n_universes, "n_universes", group="geometry") - call su % write_data(n_lattices, "n_lattices", group="geometry") - - ! ========================================================================== - ! WRITE INFORMATION ON CELLS - - ! Create a cell group (nothing directly written in this group) then close - call su % open_group("geometry/cells") - call su % close_group() - - ! Write information on each cell - CELL_LOOP: do i = 1, n_cells - c => cells(i) - - ! Write internal OpenMC index for this cell - call su % write_data(i, "index", & - group="geometry/cells/cell " // trim(to_str(c % id))) - - ! Write name for this cell - call su % write_data(c % name, "name", & - group="geometry/cells/cell " // trim(to_str(c % id))) - - ! Write universe for this cell - call su % write_data(universes(c % universe) % id, "universe", & - group="geometry/cells/cell " // trim(to_str(c % id))) - - ! Write information on what fills this cell - select case (c % type) - case (CELL_NORMAL) - call su % write_data("normal", "fill_type", & - group="geometry/cells/cell " // trim(to_str(c % id))) - if (c % material == MATERIAL_VOID) then - call su % write_data(-1, "material", & - group="geometry/cells/cell " // trim(to_str(c % id))) - else - call su % write_data(materials(c % material) % id, "material", & - group="geometry/cells/cell " // trim(to_str(c % id))) - end if - - case (CELL_FILL) - call su % write_data("universe", "fill_type", & - group="geometry/cells/cell " // trim(to_str(c % id))) - call su % write_data(universes(c % fill) % id, "fill", & - group="geometry/cells/cell " // trim(to_str(c % id))) - - call su % write_data(size(c % offset), "maps", & - group="geometry/cells/cell " // trim(to_str(c % id))) - if (size(c % offset) > 0) then - call su % write_data(c % offset, "offset", & - length=size(c % offset), & - group="geometry/cells/cell " // trim(to_str(c % id))) - end if - - if (allocated(c % translation)) then - call su % write_data(1, "translated", & - group="geometry/cells/cell " // trim(to_str(c % id))) - call su % write_data(c % translation, "translation", length=3, & - group="geometry/cells/cell " // trim(to_str(c % id))) - else - call su % write_data(0, "translated", & - group="geometry/cells/cell " // trim(to_str(c % id))) - end if - - if (allocated(c % rotation)) then - call su % write_data(1, "rotated", & - group="geometry/cells/cell " // trim(to_str(c % id))) - call su % write_data(c % rotation, "rotation", length=3, & - group="geometry/cells/cell " // trim(to_str(c % id))) - else - call su % write_data(0, "rotated", & - group="geometry/cells/cell " // trim(to_str(c % id))) - end if - - case (CELL_LATTICE) - call su % write_data("lattice", "fill_type", & - group="geometry/cells/cell " // trim(to_str(c % id))) - call su % write_data(lattices(c % fill) % obj % id, "lattice", & - group="geometry/cells/cell " // trim(to_str(c % id))) - end select - - ! Write list of bounding surfaces - if (c % n_surfaces > 0) then - call su % write_data(c % surfaces, "surfaces", length= c % n_surfaces, & - group="geometry/cells/cell " // trim(to_str(c % id))) - end if - - end do CELL_LOOP - - ! ========================================================================== - ! WRITE INFORMATION ON SURFACES - - ! Create surfaces group (nothing directly written here) then close - call su % open_group("geometry/surfaces") - call su % close_group() - - ! Write information on each surface - SURFACE_LOOP: do i = 1, n_surfaces - s => surfaces(i) - - ! Write internal OpenMC index for this surface - call su % write_data(i, "index", & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - - ! Write name for this surface - call su % write_data(s % name, "name", & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - - ! Write surface type - select case (s % type) - case (SURF_PX) - call su % write_data("X Plane", "type", & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - case (SURF_PY) - call su % write_data("Y Plane", "type", & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - case (SURF_PZ) - call su % write_data("Z Plane", "type", & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - case (SURF_PLANE) - call su % write_data("Plane", "type", & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - case (SURF_CYL_X) - call su % write_data("X Cylinder", "type", & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - case (SURF_CYL_Y) - call su % write_data("Y Cylinder", "type", & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - case (SURF_CYL_Z) - call su % write_data("Z Cylinder", "type", & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - case (SURF_SPHERE) - call su % write_data("Sphere", "type", & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - case (SURF_CONE_X) - call su % write_data("X Cone", "type", & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - case (SURF_CONE_Y) - call su % write_data("Y Cone", "type", & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - case (SURF_CONE_Z) - call su % write_data("Z Cone", "type", & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - end select - - ! Write coefficients for surface - call su % write_data(s % coeffs, "coefficients", length=size(s % coeffs), & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - - ! Write positive neighbors - if (allocated(s % neighbor_pos)) then - call su % write_data(s % neighbor_pos, "neighbors_positive", & - length=size(s % neighbor_pos), & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - end if - - ! Write negative neighbors - if (allocated(s % neighbor_neg)) then - call su % write_data(s % neighbor_neg, "neighbors_negative", & - length=size(s % neighbor_neg), & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - end if - - ! Write boundary condition - select case (s % bc) - case (BC_TRANSMIT) - call su % write_data("transmission", "boundary_condition", & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - case (BC_VACUUM) - call su % write_data("vacuum", "boundary_condition", & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - case (BC_REFLECT) - call su % write_data("reflective", "boundary_condition", & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - case (BC_PERIODIC) - call su % write_data("periodic", "boundary_condition", & - group="geometry/surfaces/surface " // trim(to_str(s % id))) - end select - - end do SURFACE_LOOP - - ! ========================================================================== - ! WRITE INFORMATION ON UNIVERSES - - ! Create universes group (nothing directly written here) then close - call su % open_group("geometry/universes") - call su % close_group() - - ! Write information on each universe - UNIVERSE_LOOP: do i = 1, n_universes - u => universes(i) - - ! Write internal OpenMC index for this universe - call su % write_data(i, "index", & - group="geometry/universes/universe " // trim(to_str(u % id))) - - ! Write list of cells in this universe - if (u % n_cells > 0) then - call su % write_data(u % cells, "cells", length=u % n_cells, & - group="geometry/universes/universe " // trim(to_str(u % id))) - end if - - end do UNIVERSE_LOOP - - ! ========================================================================== - ! WRITE INFORMATION ON LATTICES - - ! Create lattices group (nothing directly written here) then close - call su % open_group("geometry/lattices") - call su % close_group() - - ! Write information on each lattice - LATTICE_LOOP: do i = 1, n_lattices - lat => lattices(i) % obj - - ! Write internal OpenMC index for this lattice - call su % write_data(i, "index", & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - - ! Write name for this lattice - call su % write_data(lat % name, "name", & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - - ! Write lattice type - select type (lat) - type is (RectLattice) - ! Write lattice type. - call su % write_data("rectangular", "type", & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - - ! Write lattice dimensions, lower left corner, and pitch - call su % write_data(lat % n_cells, "dimension", length=3, & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - - if (lat % is_3d) then - call su % write_data(lat % lower_left, "lower_left", length=3, & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - else - call su % write_data(lat % lower_left, "lower_left", length=2, & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - end if - - if (lat % is_3d) then - call su % write_data(lat % pitch, "pitch", length=3, & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - else - call su % write_data(lat % pitch, "pitch", length=2, & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - end if - - call su % write_data(lat % outer, "outer", & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - call su % write_data(size(lat % offset), "offset_size", & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - call su % write_data(size(lat % offset,1), "maps", & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - - if (size(lat % offset) > 0) then - call su % write_data(lat % offset, "offsets", & - length=shape(lat % offset), & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - end if - - ! Write lattice universes. - allocate(lattice_universes(lat % n_cells(1), lat % n_cells(2), & - &lat % n_cells(3))) - do j = 1, lat % n_cells(1) - do k = 1, lat % n_cells(2) - do m = 1, lat % n_cells(3) - lattice_universes(j,k,m) = universes(lat % universes(j,k,m)) % id - end do - end do - end do - call su % write_data(lattice_universes, "universes", & - length=lat % n_cells, & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - deallocate(lattice_universes) - - type is (HexLattice) - ! Write lattice type. - call su % write_data("hexagonal", "type", & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - - ! Write number of lattice cells. - call su % write_data(lat % n_rings, "n_rings", & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - call su % write_data(lat % n_axial, "n_axial", & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - - ! Write lattice center, pitch and outer universe. - if (lat % is_3d) then - call su % write_data(lat % center, "center", length=3, & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - else - call su % write_data(lat % center, "center", length=2, & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - end if - - if (lat % is_3d) then - call su % write_data(lat % pitch, "pitch", length=2, & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - else - call su % write_data(lat % pitch, "pitch", length=1, & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - end if - - call su % write_data(lat % outer, "outer", & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - call su % write_data(size(lat % offset), "offset_size", & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - call su % write_data(size(lat % offset,1), "maps", & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - - if (size(lat % offset) > 0) then - call su % write_data(lat % offset, "offsets", & - length=shape(lat % offset), & - group="geometry/lattices/lattice " // trim(to_str(lat % id))) - end if - - ! Write lattice universes. - allocate(lattice_universes(2*lat % n_rings - 1, 2*lat % n_rings - 1, & - &lat % n_axial)) - do m = 1, lat % n_axial - do k = 1, 2*lat % n_rings - 1 - do j = 1, 2*lat % n_rings - 1 - if (j + k < lat % n_rings + 1) then - ! This array position is never used; put a -1 to indicate this - lattice_universes(j,k,m) = -1 - cycle - else if (j + k > 3*lat % n_rings - 1) then - ! This array position is never used; put a -1 to indicate this - lattice_universes(j,k,m) = -1 - cycle - end if - lattice_universes(j,k,m) = universes(lat % universes(j,k,m)) % id - end do - end do - end do - call su % write_data(lattice_universes, "universes", & - &length=(/2*lat % n_rings-1, 2*lat % n_rings-1, lat % n_axial/), & - &group="geometry/lattices/lattice " // trim(to_str(lat % id))) - deallocate(lattice_universes) - end select - end do LATTICE_LOOP - - end subroutine hdf5_write_geometry - -!=============================================================================== -! HDF5_WRITE_MATERIALS -!=============================================================================== - - subroutine hdf5_write_materials() - - integer :: i - integer :: j - integer, allocatable :: zaids(:) - type(Material), pointer :: m => null() - - ! Use H5LT interface to write number of materials - call su % write_data(n_materials, "n_materials", group="materials") - - ! Write information on each material - do i = 1, n_materials - m => materials(i) - - ! Write internal OpenMC index for this material - call su % write_data(i, "index", & - group="materials/material " // trim(to_str(m % id))) - - ! Write name for this material - call su % write_data(m % name, "name", & - group="materials/material " // trim(to_str(m % id))) - - ! Write atom density with units - call su % write_data(m % density, "atom_density", & - group="materials/material " // trim(to_str(m % id))) - call su % write_attribute_string("atom_density", "units", "atom/b-cm", & - group="materials/material " // trim(to_str(m % id))) - - ! Copy ZAID for each nuclide to temporary array - allocate(zaids(m % n_nuclides)) - do j = 1, m % n_nuclides - zaids(j) = nuclides(m % nuclide(j)) % zaid - end do - - ! Write temporary array to 'nuclides' - call su % write_data(zaids, "nuclides", length=m % n_nuclides, & - group="materials/material " // trim(to_str(m % id))) - - ! Deallocate temporary array - deallocate(zaids) - - ! Write atom densities - call su % write_data(m % atom_density, "nuclide_densities", & - length=m % n_nuclides, & - group="materials/material " // trim(to_str(m % id))) - - ! Write S(a,b) information if present - call su % write_data(m % n_sab, "n_sab", & - group="materials/material " // trim(to_str(m % id))) - - if (m % n_sab > 0) then - call su % write_data(m % i_sab_nuclides, "i_sab_nuclides", & - length=m % n_sab, & - group="materials/material " // trim(to_str(m % id))) - call su % write_data(m % i_sab_tables, "i_sab_tables", & - length=m % n_sab, & - group="materials/material " // trim(to_str(m % id))) - - do j = 1, m % n_sab - call su % write_data(m % sab_names(j), to_str(j), & - group="materials/material " // & - trim(to_str(m % id)) // "/sab_tables") - end do - end if - - end do - - end subroutine hdf5_write_materials - -!=============================================================================== -! HDF5_WRITE_TALLIES -!=============================================================================== - - subroutine hdf5_write_tallies() - - integer :: i, j - integer, allocatable :: temp_array(:) ! nuclide bin array - type(StructuredMesh), pointer :: m => null() - type(TallyObject), pointer :: t => null() - - ! Write total number of meshes - call su % write_data(n_meshes, "n_meshes", group="tallies") - - ! Write information for meshes - MESH_LOOP: do i = 1, n_meshes - m => meshes(i) - - ! Write type and number of dimensions - call su % write_data(m % type, "type", & - group="tallies/mesh " // trim(to_str(m % id))) - - call su % write_data(m % n_dimension, "n_dimension", & - group="tallies/mesh " // trim(to_str(m % id))) - - ! Write mesh information - call su % write_data(m % dimension, "dimension", & - length=m % n_dimension, & - group="tallies/mesh " // trim(to_str(m % id))) - call su % write_data(m % lower_left, "lower_left", & - length=m % n_dimension, & - group="tallies/mesh " // trim(to_str(m % id))) - call su % write_data(m % upper_right, "upper_right", & - length=m % n_dimension, & - group="tallies/mesh " // trim(to_str(m % id))) - call su % write_data(m % width, "width", & - length=m % n_dimension, & - group="tallies/mesh " // trim(to_str(m % id))) - - end do MESH_LOOP - - ! Write number of tallies - call su % write_data(n_tallies, "n_tallies", group="tallies") - - TALLY_METADATA: do i = 1, n_tallies - ! Get pointer to tally - t => tallies(i) - - ! Write the name for this tally - call su % write_data(len(t % name), "name_size", & - group="tallies/tally " // trim(to_str(t % id))) - if (len(t % name) > 0) then - call su % write_data(t % name, "name", & - group="tallies/tally " // trim(to_str(t % id))) - endif - - ! Write size of each tally - call su % write_data(t % total_score_bins, "total_score_bins", & - group="tallies/tally " // trim(to_str(t % id))) - call su % write_data(t % total_filter_bins, "total_filter_bins", & - group="tallies/tally " // trim(to_str(t % id))) - - ! Write number of filters - call su % write_data(t % n_filters, "n_filters", & - group="tallies/tally " // trim(to_str(t % id))) - - FILTER_LOOP: do j = 1, t % n_filters - ! Write type of filter - call su % write_data(t % filters(j) % type, "type", & - group="tallies/tally " // trim(to_str(t % id)) & - // "/filter " // trim(to_str(j))) - - ! Write number of bins for this filter - call su % write_data(t % filters(j) % n_bins, "n_bins", & - group="tallies/tally " // trim(to_str(t % id)) & - // "/filter " // trim(to_str(j))) - - ! Write filter bins - if (t % filters(j) % type == FILTER_ENERGYIN .or. & - t % filters(j) % type == FILTER_ENERGYOUT) then - call su % write_data(t % filters(j) % real_bins, "bins", & - length=size(t % filters(j) % real_bins), & - group="tallies/tally " // trim(to_str(t % id)) & - // "/filter " // trim(to_str(j))) - else - call su % write_data(t % filters(j) % int_bins, "bins", & - length=size(t % filters(j) % int_bins), & - group="tallies/tally " // trim(to_str(t % id)) & - // "/filter " // trim(to_str(j))) - end if - - ! Write name of type - select case (t % filters(j) % type) - case(FILTER_UNIVERSE) - call su % write_data("universe", "type_name", & - group="tallies/tally " // trim(to_str(t % id)) & - // "/filter " // trim(to_str(j))) - case(FILTER_MATERIAL) - call su % write_data("material", "type_name", & - group="tallies/tally " // trim(to_str(t % id)) & - // "/filter " // trim(to_str(j))) - case(FILTER_CELL) - call su % write_data("cell", "type_name", & - group="tallies/tally " // trim(to_str(t % id)) & - // "/filter " // trim(to_str(j))) - case(FILTER_CELLBORN) - call su % write_data("cellborn", "type_name", & - group="tallies/tally " // trim(to_str(t % id)) & - // "/filter " // trim(to_str(j))) - case(FILTER_SURFACE) - call su % write_data("surface", "type_name", & - group="tallies/tally " // trim(to_str(t % id)) & - // "/filter " // trim(to_str(j))) - case(FILTER_MESH) - call su % write_data("mesh", "type_name", & - group="tallies/tally " // trim(to_str(t % id)) & - // "/filter " // trim(to_str(j))) - case(FILTER_ENERGYIN) - call su % write_data("energy", "type_name", & - group="tallies/tally " // trim(to_str(t % id)) & - // "/filter " // trim(to_str(j))) - case(FILTER_ENERGYOUT) - call su % write_data("energyout", "type_name", & - group="tallies/tally " // trim(to_str(t % id)) & - // "/filter " // trim(to_str(j))) - end select - - end do FILTER_LOOP - - ! Write number of nuclide bins - call su % write_data(t % n_nuclide_bins, "n_nuclide_bins", & - group="tallies/tally " // trim(to_str(t % id))) - - ! Create temporary array for nuclide bins - allocate(temp_array(t % n_nuclide_bins)) - NUCLIDE_LOOP: do j = 1, t % n_nuclide_bins - if (t % nuclide_bins(j) > 0) then - temp_array(j) = nuclides(t % nuclide_bins(j)) % zaid - else - temp_array(j) = t % nuclide_bins(j) - end if - end do NUCLIDE_LOOP - - ! Write and deallocate nuclide bins - call su % write_data(temp_array, "nuclide_bins", length=t % n_nuclide_bins, & - group="tallies/tally " // trim(to_str(t % id))) - deallocate(temp_array) - - ! Write number of score bins - call su % write_data(t % n_score_bins, "n_score_bins", & - group="tallies/tally " // trim(to_str(t % id))) - call su % write_data(t % score_bins, "score_bins", length=t % n_score_bins, & - group="tallies/tally " // trim(to_str(t % id))) - - end do TALLY_METADATA - - end subroutine hdf5_write_tallies - -!=============================================================================== -! HDF5_WRITE_NUCLIDES -!=============================================================================== - - subroutine hdf5_write_nuclides() - - integer :: i, j - integer :: size_total - integer :: size_xs - integer :: size_angle - integer :: size_energy - type(Nuclide), pointer :: nuc => null() - type(Reaction), pointer :: rxn => null() - type(UrrData), pointer :: urr => null() - - ! Use H5LT interface to write number of nuclides - call su % write_data(n_nuclides_total, "n_nuclides", group="nuclides") - - ! Write information on each nuclide - NUCLIDE_LOOP: do i = 1, n_nuclides_total - nuc => nuclides(i) - - ! Write internal OpenMC index for this nuclide - call su % write_data(i, "index", & - group="nuclides/" // trim(nuc % name)) - - ! Determine size of cross-sections - size_xs = (5 + nuc % n_reaction) * nuc % n_grid * 8 - size_total = size_xs - - ! Write some basic attributes - call su % write_data(nuc % zaid, "zaid", & - group="nuclides/" // trim(nuc % name)) - call su % write_data(xs_listings(nuc % listing) % alias, "alias", & - group="nuclides/" // trim(nuc % name)) - call su % write_data(nuc % awr, "awr", & - group="nuclides/" // trim(nuc % name)) - call su % write_data(nuc % kT, "kT", & - group="nuclides/" // trim(nuc % name)) - call su % write_data(nuc % n_grid, "n_grid", & - group="nuclides/" // trim(nuc % name)) - call su % write_data(nuc % n_reaction, "n_reactions", & - group="nuclides/" // trim(nuc % name)) - call su % write_data(nuc % n_fission, "n_fission", & - group="nuclides/" // trim(nuc % name)) - call su % write_data(size_xs, "size_xs", & - group="nuclides/" // trim(nuc % name)) - - ! ======================================================================= - ! WRITE INFORMATION ON EACH REACTION - - ! Create overall group for reactions and close it - call su % open_group("nuclides/" // trim(nuc % name) // "/reactions") - call su % close_group() - - RXN_LOOP: do j = 1, nuc % n_reaction - ! Information on each reaction - rxn => nuc % reactions(j) - - ! Determine size of angle distribution - if (rxn % has_angle_dist) then - size_angle = rxn % adist % n_energy * 16 + size(rxn % adist % data) * 8 - else - size_angle = 0 - end if - - ! Determine size of energy distribution - if (rxn % has_energy_dist) then - size_energy = size(rxn % edist % data) * 8 - else - size_energy = 0 - end if - - ! Write information on reaction - call su % write_data(rxn % Q_value, "Q_value", & - group="nuclides/" // trim(nuc % name) // "/reactions/" // & - trim(reaction_name(rxn % MT))) - call su % write_data(rxn % multiplicity, "multiplicity", & - group="nuclides/" // trim(nuc % name) // "/reactions/" // & - trim(reaction_name(rxn % MT))) - call su % write_data(rxn % threshold, "threshold", & - group="nuclides/" // trim(nuc % name) // "/reactions/" // & - trim(reaction_name(rxn % MT))) - call su % write_data(size_angle, "size_angle", & - group="nuclides/" // trim(nuc % name) // "/reactions/" // & - trim(reaction_name(rxn % MT))) - call su % write_data(size_energy, "size_energy", & - group="nuclides/" // trim(nuc % name) // "/reactions/" // & - trim(reaction_name(rxn % MT))) - - ! Accumulate data size - size_total = size_total + size_angle + size_energy - end do RXN_LOOP - - ! ======================================================================= - ! WRITE INFORMATION ON URR PROBABILITY TABLES - - if (nuc % urr_present) then - urr => nuc % urr_data - call su % write_data(urr % n_energy, "urr_n_energy", & - group="nuclides/" // trim(nuc % name)) - call su % write_data(urr % n_prob, "urr_n_prob", & - group="nuclides/" // trim(nuc % name)) - call su % write_data(urr % interp, "urr_interp", & - group="nuclides/" // trim(nuc % name)) - call su % write_data(urr % inelastic_flag, "urr_inelastic", & - group="nuclides/" // trim(nuc % name)) - call su % write_data(urr % absorption_flag, "urr_absorption", & - group="nuclides/" // trim(nuc % name)) - call su % write_data(urr % energy(1), "urr_min_E", & - group="nuclides/" // trim(nuc % name)) - call su % write_data(urr % energy(urr % n_energy), "urr_max_E", & - group="nuclides/" // trim(nuc % name)) - end if - - ! Write total memory used - call su % write_data(size_total, "size_total", & - group="nuclides/" // trim(nuc % name)) - - end do NUCLIDE_LOOP - - end subroutine hdf5_write_nuclides - -!=============================================================================== -! HDF5_WRITE_TIMING -!=============================================================================== - - subroutine hdf5_write_timing() - - integer(8) :: total_particles - real(8) :: speed - - ! Write timing data - call su % write_data(time_initialize % elapsed, "time_initialize", & - group="timing") - call su % write_data(time_read_xs % elapsed, "time_read_xs", & - group="timing") - call su % write_data(time_transport % elapsed, "time_transport", & - group="timing") - call su % write_data(time_bank % elapsed, "time_bank", & - group="timing") - call su % write_data(time_bank_sample % elapsed, "time_bank_sample", & - group="timing") - call su % write_data(time_bank_sendrecv % elapsed, "time_bank_sendrecv", & - group="timing") - call su % write_data(time_tallies % elapsed, "time_tallies", & - group="timing") - call su % write_data(time_inactive % elapsed, "time_inactive", & - group="timing") - call su % write_data(time_active % elapsed, "time_active", & - group="timing") - call su % write_data(time_finalize % elapsed, "time_finalize", & - group="timing") - call su % write_data(time_total % elapsed, "time_total", & - group="timing") - - ! Add descriptions to timing data - call su % write_attribute_string("time_initialize", "description", & - "Total time elapsed for initialization (s)", group="timing") - call su % write_attribute_string("time_read_xs", "description", & - "Time reading cross-section libraries (s)", group="timing") - call su % write_attribute_string("time_transport", "description", & - "Time in transport only (s)", group="timing") - call su % write_attribute_string("time_bank", "description", & - "Total time synchronizing fission bank (s)", group="timing") - call su % write_attribute_string("time_bank_sample", "description", & - "Time between generations sampling source sites (s)", group="timing") - call su % write_attribute_string("time_bank_sendrecv", "description", & - "Time between generations SEND/RECVing source sites (s)", & - group="timing") - call su % write_attribute_string("time_tallies", "description", & - "Time between batches accumulating tallies (s)", group="timing") - call su % write_attribute_string("time_inactive", "description", & - "Total time in inactive batches (s)", group="timing") - call su % write_attribute_string("time_active", "description", & - "Total time in active batches (s)", group="timing") - call su % write_attribute_string("time_finalize", "description", & - "Total time for finalization (s)", group="timing") - call su % write_attribute_string("time_total", "description", & - "Total time elapsed (s)", group="timing") - - ! Write calculation rate - total_particles = n_particles * n_batches * gen_per_batch - speed = real(total_particles) / (time_inactive % elapsed + & - time_active % elapsed) - call su % write_data(speed, "neutrons_per_second", group="timing") - - end subroutine hdf5_write_timing - -#endif - -end module hdf5_summary diff --git a/src/initialize.F90 b/src/initialize.F90 index b944b6677..86242c753 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -12,16 +12,17 @@ module initialize use geometry_header, only: Cell, Universe, Lattice, RectLattice, HexLattice,& &BASE_UNIVERSE use global + use hdf5_interface, only: file_open, read_dataset, file_close, hdf5_bank_t,& + hdf5_tallyresult_t, hdf5_integer8_t use input_xml, only: read_input_xml, read_cross_sections_xml, & cells_in_univ_dict, read_plots_xml use material_header, only: Material - use output, only: title, header, write_summary, print_version, & - print_usage, write_xs_summary, print_plot, & - write_message - use output_interface + use output, only: title, header, print_version, write_message, & + print_usage, write_xs_summary, print_plot use random_lcg, only: initialize_prng use state_point, only: load_state_point use string, only: to_str, str_to_int, starts_with, ends_with + use summary, only: write_summary use tally_header, only: TallyObject, TallyResult, TallyFilter use tally_initialize, only: configure_tallies @@ -33,10 +34,9 @@ module initialize use omp_lib #endif -#ifdef HDF5 - use hdf5_interface - use hdf5_summary, only: hdf5_write_summary -#endif + use hdf5 + + use, intrinsic :: ISO_C_BINDING, only: c_loc implicit none @@ -52,18 +52,16 @@ contains subroutine initialize_run() ! Start total and initialization timer - call time_total % start() - call time_initialize % start() + call time_total%start() + call time_initialize%start() #ifdef MPI ! Setup MPI call initialize_mpi() #endif -#ifdef HDF5 ! Initialize HDF5 interface call hdf5_initialize() -#endif ! Read command line arguments call read_command_line() @@ -115,9 +113,9 @@ contains call normalize_ao() ! Read ACE-format cross sections - call time_read_xs % start() + call time_read_xs%start() call read_xs() - call time_read_xs % stop() + call time_read_xs%stop() ! Create linked lists for multiple instances of the same nuclide call same_nuclide_list() @@ -127,9 +125,9 @@ contains case (GRID_NUCLIDE) continue case (GRID_MAT_UNION) - call time_unionize % start() + call time_unionize%start() call unionized_grid() - call time_unionize % stop() + call time_unionize%stop() case (GRID_LOGARITHM) call logarithmic_grid() end select @@ -155,11 +153,7 @@ contains call print_plot() else ! Write summary information -#ifdef HDF5 - if (output_summary) call hdf5_write_summary() -#else if (output_summary) call write_summary() -#endif ! Write cross section information if (output_xs) call write_xs_summary() @@ -176,7 +170,7 @@ contains end if ! Stop initialization timer - call time_initialize % stop() + call time_initialize%stop() end subroutine initialize_run @@ -229,10 +223,10 @@ contains ! CREATE MPI_BANK TYPE ! Determine displacements for MPI_BANK type - call MPI_GET_ADDRESS(b % wgt, bank_disp(1), mpi_err) - call MPI_GET_ADDRESS(b % xyz, bank_disp(2), mpi_err) - call MPI_GET_ADDRESS(b % uvw, bank_disp(3), mpi_err) - call MPI_GET_ADDRESS(b % E, bank_disp(4), mpi_err) + call MPI_GET_ADDRESS(b%wgt, bank_disp(1), mpi_err) + call MPI_GET_ADDRESS(b%xyz, bank_disp(2), mpi_err) + call MPI_GET_ADDRESS(b%uvw, bank_disp(3), mpi_err) + call MPI_GET_ADDRESS(b%E, bank_disp(4), mpi_err) ! Adjust displacements bank_disp = bank_disp - bank_disp(1) @@ -248,8 +242,8 @@ contains ! CREATE MPI_TALLYRESULT TYPE ! Determine displacements for MPI_BANK type - call MPI_GET_ADDRESS(tr % value, result_base_disp, mpi_err) - call MPI_GET_ADDRESS(tr % sum, result_disp(1), mpi_err) + call MPI_GET_ADDRESS(tr%value, result_base_disp, mpi_err) + call MPI_GET_ADDRESS(tr%sum, result_disp(1), mpi_err) ! Adjust displacements result_disp = result_disp - result_base_disp @@ -275,8 +269,6 @@ contains end subroutine initialize_mpi #endif -#ifdef HDF5 - !=============================================================================== ! HDF5_INITIALIZE !=============================================================================== @@ -285,6 +277,7 @@ contains type(TallyResult), target :: tmp(2) ! temporary TallyResult type(Bank), target :: tmpb(2) ! temporary Bank + integer :: hdf5_err integer(HID_T) :: coordinates_t ! HDF5 type for 3 reals integer(HSIZE_T) :: dims(1) = (/3/) ! size of coordinates @@ -319,8 +312,6 @@ contains end subroutine hdf5_initialize -#endif - !=============================================================================== ! READ_COMMAND_LINE reads all parameters from the command line !=============================================================================== @@ -330,9 +321,9 @@ contains integer :: i ! loop index integer :: argc ! number of command line arguments integer :: last_flag ! index of last flag - integer :: filetype + character(MAX_WORD_LEN) :: filetype + integer(HID_T) :: file_id character(MAX_WORD_LEN), allocatable :: argv(:) ! command line arguments - type(BinaryOutput) :: sp ! Check number of command line arguments and allocate argv argc = COMMAND_ARGUMENT_COUNT() @@ -369,16 +360,16 @@ contains i = i + 1 ! Check what type of file this is - call sp % file_open(argv(i), 'r', serial = .false.) - call sp % read_data(filetype, 'filetype') - call sp % file_close() + file_id = file_open(argv(i), 'r', parallel=.true.) + call read_dataset(file_id, 'filetype', filetype) + call file_close(file_id) ! Set path and flag for type of run select case (filetype) - case (FILETYPE_STATEPOINT) + case ('statepoint') path_state_point = argv(i) restart_run = .true. - case (FILETYPE_PARTICLE_RESTART) + case ('particle restart') path_particle_restart = argv(i) particle_restart_run = .true. case default @@ -392,14 +383,13 @@ contains i = i + 1 ! Check if it has extension we can read - if ((ends_with(argv(i), '.binary') .or. & - ends_with(argv(i), '.h5'))) then + if (ends_with(argv(i), '.h5')) then ! Check file type is a source file - call sp % file_open(argv(i), 'r', serial = .false.) - call sp % read_data(filetype, 'filetype') - call sp % file_close() - if (filetype /= FILETYPE_SOURCE) then + file_id = file_open(argv(i), 'r', parallel=.true.) + call read_dataset(file_id, 'filetype', filetype) + call file_close(file_id) + if (filetype /= 'source') then call fatal_error("Second file after restart flag must be a & &source file") end if @@ -507,26 +497,26 @@ contains ! pairs are the id of the universe and the index in the array. In ! cells_in_univ_dict, it's the id of the universe and the number of cells. - pair_list => universe_dict % keys() + pair_list => universe_dict%keys() current => pair_list do while (associated(current)) ! Find index of universe in universes array - i_univ = current % value + i_univ = current%value univ => universes(i_univ) - univ % id = current % key + univ%id = current%key ! Check for lowest level universe - if (univ % id == 0) BASE_UNIVERSE = i_univ + if (univ%id == 0) BASE_UNIVERSE = i_univ ! Find cell count for this universe - n_cells_in_univ = cells_in_univ_dict % get_key(univ % id) + n_cells_in_univ = cells_in_univ_dict%get_key(univ%id) ! Allocate cell list for universe - allocate(univ % cells(n_cells_in_univ)) - univ % n_cells = n_cells_in_univ + allocate(univ%cells(n_cells_in_univ)) + univ%n_cells = n_cells_in_univ ! Move to next universe - next => current % next + next => current%next deallocate(current) current => next end do @@ -541,17 +531,17 @@ contains c => cells(i) ! Get pointer to corresponding universe - i_univ = universe_dict % get_key(c % universe) + i_univ = universe_dict%get_key(c%universe) univ => universes(i_univ) ! Increment the index for the cells array within the Universe object and ! then store the index of the Cell object in that array index_cell_in_univ(i_univ) = index_cell_in_univ(i_univ) + 1 - univ % cells(index_cell_in_univ(i_univ)) = i + univ%cells(index_cell_in_univ(i_univ)) = i end do ! Clear dictionary - call cells_in_univ_dict % clear() + call cells_in_univ_dict%clear() end subroutine prepare_universes @@ -581,15 +571,15 @@ contains ! ADJUST SURFACE LIST FOR EACH CELL c => cells(i) - do j = 1, c % n_surfaces - id = c % surfaces(j) + do j = 1, c%n_surfaces + id = c%surfaces(j) if (id < OP_DIFFERENCE) then - if (surface_dict % has_key(abs(id))) then - i_array = surface_dict % get_key(abs(id)) - c % surfaces(j) = sign(i_array, id) + if (surface_dict%has_key(abs(id))) then + i_array = surface_dict%get_key(abs(id)) + c%surfaces(j) = sign(i_array, id) else call fatal_error("Could not find surface " // trim(to_str(abs(id)))& - &// " specified on cell " // trim(to_str(c % id))) + &// " specified on cell " // trim(to_str(c%id))) end if end if end do @@ -597,40 +587,40 @@ contains ! ======================================================================= ! ADJUST UNIVERSE INDEX FOR EACH CELL - id = c % universe - if (universe_dict % has_key(id)) then - c % universe = universe_dict % get_key(id) + id = c%universe + if (universe_dict%has_key(id)) then + c%universe = universe_dict%get_key(id) else call fatal_error("Could not find universe " // trim(to_str(id)) & - &// " specified on cell " // trim(to_str(c % id))) + &// " specified on cell " // trim(to_str(c%id))) end if ! ======================================================================= ! ADJUST MATERIAL/FILL POINTERS FOR EACH CELL - id = c % material + id = c%material if (id == MATERIAL_VOID) then - c % type = CELL_NORMAL + c%type = CELL_NORMAL elseif (id /= 0) then - if (material_dict % has_key(id)) then - c % type = CELL_NORMAL - c % material = material_dict % get_key(id) + if (material_dict%has_key(id)) then + c%type = CELL_NORMAL + c%material = material_dict%get_key(id) else call fatal_error("Could not find material " // trim(to_str(id)) & - &// " specified on cell " // trim(to_str(c % id))) + &// " specified on cell " // trim(to_str(c%id))) end if else - id = c % fill - if (universe_dict % has_key(id)) then - c % type = CELL_FILL - c % fill = universe_dict % get_key(id) - elseif (lattice_dict % has_key(id)) then - lid = lattice_dict % get_key(id) - c % type = CELL_LATTICE - c % fill = lid + id = c%fill + if (universe_dict%has_key(id)) then + c%type = CELL_FILL + c%fill = universe_dict%get_key(id) + elseif (lattice_dict%has_key(id)) then + lid = lattice_dict%get_key(id) + c%type = CELL_LATTICE + c%fill = lid else call fatal_error("Specified fill " // trim(to_str(id)) // " on cell "& - &// trim(to_str(c % id)) // " is neither a universe nor a & + &// trim(to_str(c%id)) // " is neither a universe nor a & &lattice.") end if end if @@ -640,41 +630,41 @@ contains ! ADJUST UNIVERSE INDICES FOR EACH LATTICE do i = 1, n_lattices - lat => lattices(i) % obj + lat => lattices(i)%obj select type (lat) type is (RectLattice) - do m = 1, lat % n_cells(3) - do k = 1, lat % n_cells(2) - do j = 1, lat % n_cells(1) - id = lat % universes(j,k,m) - if (universe_dict % has_key(id)) then - lat % universes(j,k,m) = universe_dict % get_key(id) + do m = 1, lat%n_cells(3) + do k = 1, lat%n_cells(2) + do j = 1, lat%n_cells(1) + id = lat%universes(j,k,m) + if (universe_dict%has_key(id)) then + lat%universes(j,k,m) = universe_dict%get_key(id) else call fatal_error("Invalid universe number " & &// trim(to_str(id)) // " specified on lattice " & - &// trim(to_str(lat % id))) + &// trim(to_str(lat%id))) end if end do end do end do type is (HexLattice) - do m = 1, lat % n_axial - do k = 1, 2*lat % n_rings - 1 - do j = 1, 2*lat % n_rings - 1 - if (j + k < lat % n_rings + 1) then + do m = 1, lat%n_axial + do k = 1, 2*lat%n_rings - 1 + do j = 1, 2*lat%n_rings - 1 + if (j + k < lat%n_rings + 1) then cycle - else if (j + k > 3*lat % n_rings - 1) then + else if (j + k > 3*lat%n_rings - 1) then cycle end if - id = lat % universes(j, k, m) - if (universe_dict % has_key(id)) then - lat % universes(j, k, m) = universe_dict % get_key(id) + id = lat%universes(j, k, m) + if (universe_dict%has_key(id)) then + lat%universes(j, k, m) = universe_dict%get_key(id) else call fatal_error("Invalid universe number " & &// trim(to_str(id)) // " specified on lattice " & - &// trim(to_str(lat % id))) + &// trim(to_str(lat%id))) end if end do end do @@ -682,13 +672,13 @@ contains end select - if (lat % outer /= NO_OUTER_UNIVERSE) then - if (universe_dict % has_key(lat % outer)) then - lat % outer = universe_dict % get_key(lat % outer) + if (lat%outer /= NO_OUTER_UNIVERSE) then + if (universe_dict%has_key(lat%outer)) then + lat%outer = universe_dict%get_key(lat%outer) else call fatal_error("Invalid universe number " & - &// trim(to_str(lat % outer)) & - &// " specified on lattice " // trim(to_str(lat % id))) + &// trim(to_str(lat%outer)) & + &// " specified on lattice " // trim(to_str(lat%id))) end if end if @@ -700,68 +690,68 @@ contains ! ======================================================================= ! ADJUST INDICES FOR EACH TALLY FILTER - FILTER_LOOP: do j = 1, t % n_filters + FILTER_LOOP: do j = 1, t%n_filters - select case (t % filters(j) % type) + select case (t%filters(j)%type) case (FILTER_DISTRIBCELL) - do k = 1, size(t % filters(j) % int_bins) - id = t % filters(j) % int_bins(k) - if (cell_dict % has_key(id)) then - t % filters(j) % int_bins(k) = cell_dict % get_key(id) + do k = 1, size(t%filters(j)%int_bins) + id = t%filters(j)%int_bins(k) + if (cell_dict%has_key(id)) then + t%filters(j)%int_bins(k) = cell_dict%get_key(id) else call fatal_error("Could not find cell " // trim(to_str(id)) // & - " specified on tally " // trim(to_str(t % id))) + " specified on tally " // trim(to_str(t%id))) end if end do case (FILTER_CELL, FILTER_CELLBORN) - do k = 1, t % filters(j) % n_bins - id = t % filters(j) % int_bins(k) - if (cell_dict % has_key(id)) then - t % filters(j) % int_bins(k) = cell_dict % get_key(id) + do k = 1, t%filters(j)%n_bins + id = t%filters(j)%int_bins(k) + if (cell_dict%has_key(id)) then + t%filters(j)%int_bins(k) = cell_dict%get_key(id) else call fatal_error("Could not find cell " // trim(to_str(id)) & - &// " specified on tally " // trim(to_str(t % id))) + &// " specified on tally " // trim(to_str(t%id))) end if end do case (FILTER_SURFACE) ! Check if this is a surface filter only for surface currents - if (any(t % score_bins == SCORE_CURRENT)) cycle FILTER_LOOP + if (any(t%score_bins == SCORE_CURRENT)) cycle FILTER_LOOP - do k = 1, t % filters(j) % n_bins - id = t % filters(j) % int_bins(k) - if (surface_dict % has_key(id)) then - t % filters(j) % int_bins(k) = surface_dict % get_key(id) + do k = 1, t%filters(j)%n_bins + id = t%filters(j)%int_bins(k) + if (surface_dict%has_key(id)) then + t%filters(j)%int_bins(k) = surface_dict%get_key(id) else call fatal_error("Could not find surface " // trim(to_str(id)) & - &// " specified on tally " // trim(to_str(t % id))) + &// " specified on tally " // trim(to_str(t%id))) end if end do case (FILTER_UNIVERSE) - do k = 1, t % filters(j) % n_bins - id = t % filters(j) % int_bins(k) - if (universe_dict % has_key(id)) then - t % filters(j) % int_bins(k) = universe_dict % get_key(id) + do k = 1, t%filters(j)%n_bins + id = t%filters(j)%int_bins(k) + if (universe_dict%has_key(id)) then + t%filters(j)%int_bins(k) = universe_dict%get_key(id) else call fatal_error("Could not find universe " // trim(to_str(id)) & - &// " specified on tally " // trim(to_str(t % id))) + &// " specified on tally " // trim(to_str(t%id))) end if end do case (FILTER_MATERIAL) - do k = 1, t % filters(j) % n_bins - id = t % filters(j) % int_bins(k) - if (material_dict % has_key(id)) then - t % filters(j) % int_bins(k) = material_dict % get_key(id) + do k = 1, t%filters(j)%n_bins + id = t%filters(j)%int_bins(k) + if (material_dict%has_key(id)) then + t%filters(j)%int_bins(k) = material_dict%get_key(id) else call fatal_error("Could not find material " // trim(to_str(id)) & - &// " specified on tally " // trim(to_str(t % id))) + &// " specified on tally " // trim(to_str(t%id))) end if end do @@ -799,46 +789,46 @@ contains do i = 1, n_materials mat => materials(i) - percent_in_atom = (mat % atom_density(1) > ZERO) - density_in_atom = (mat % density > ZERO) + percent_in_atom = (mat%atom_density(1) > ZERO) + density_in_atom = (mat%density > ZERO) sum_percent = ZERO - do j = 1, mat % n_nuclides + do j = 1, mat%n_nuclides ! determine atomic weight ratio - index_list = xs_listing_dict % get_key(mat % names(j)) - awr = xs_listings(index_list) % awr + index_list = xs_listing_dict%get_key(mat%names(j)) + awr = xs_listings(index_list)%awr ! if given weight percent, convert all values so that they are divided ! by awr. thus, when a sum is done over the values, it's actually ! sum(w/awr) if (.not. percent_in_atom) then - mat % atom_density(j) = -mat % atom_density(j) / awr + mat%atom_density(j) = -mat%atom_density(j) / awr end if end do ! determine normalized atom percents. if given atom percents, this is ! straightforward. if given weight percents, the value is w/awr and is ! divided by sum(w/awr) - sum_percent = sum(mat % atom_density) - mat % atom_density = mat % atom_density / sum_percent + sum_percent = sum(mat%atom_density) + mat%atom_density = mat%atom_density / sum_percent ! Change density in g/cm^3 to atom/b-cm. Since all values are now in atom ! percent, the sum needs to be re-evaluated as 1/sum(x*awr) if (.not. density_in_atom) then sum_percent = ZERO - do j = 1, mat % n_nuclides - index_list = xs_listing_dict % get_key(mat % names(j)) - awr = xs_listings(index_list) % awr - x = mat % atom_density(j) + do j = 1, mat%n_nuclides + index_list = xs_listing_dict%get_key(mat%names(j)) + awr = xs_listings(index_list)%awr + x = mat%atom_density(j) sum_percent = sum_percent + x*awr end do sum_percent = ONE / sum_percent - mat % density = -mat % density * N_AVOGADRO & + mat%density = -mat%density * N_AVOGADRO & / MASS_NEUTRON * sum_percent end if ! Calculate nuclide atom densities - mat % atom_density = mat % density * mat % atom_density + mat%atom_density = mat%density * mat%atom_density end do end subroutine normalize_ao @@ -940,7 +930,7 @@ contains integer :: i, j ! Tally, filter loop counters integer :: n_filt ! Number of filters originally in tally logical :: count_all ! Count all cells - type(TallyObject), pointer :: tally ! Current tally + type(TallyObject), pointer :: t ! Current tally type(Universe), pointer :: univ ! Pointer to universe type(Cell), pointer :: c ! Pointer to cell integer, allocatable :: univ_list(:) ! Target offsets @@ -953,18 +943,18 @@ contains do i = 1, n_tallies ! Get pointer to tally - tally => tallies(i) + t => tallies(i) - n_filt = tally % n_filters + n_filt = t%n_filters ! Loop over the filters to determine how many additional filters ! need to be added to this tally - do j = 1, tally % n_filters + do j = 1, t%n_filters ! Determine type of filter - if (tally % filters(j) % type == FILTER_DISTRIBCELL) then + if (t%filters(j)%type == FILTER_DISTRIBCELL) then count_all = .true. - if (size(tally % filters(j) % int_bins) > 1) then + if (size(t%filters(j)%int_bins) > 1) then call fatal_error("A distribcell filter was specified with & &multiple bins. This feature is not supported.") end if @@ -985,15 +975,15 @@ contains do i = 1, n_tallies ! Get pointer to tally - tally => tallies(i) + t => tallies(i) ! Initialize the filters - do j = 1, tally % n_filters + do j = 1, t%n_filters ! Set the number of bins to the number of instances of the cell - if (tally % filters(j) % type == FILTER_DISTRIBCELL) then - c => cells(tally % filters(j) % int_bins(1)) - tally % filters(j) % n_bins = c % instances + if (t%filters(j)%type == FILTER_DISTRIBCELL) then + c => cells(t%filters(j)%int_bins(1)) + t%filters(j)%n_bins = c%instances end if end do @@ -1034,7 +1024,7 @@ contains type(SetInt) :: cell_list ! distribells to track type(Universe), pointer :: univ ! pointer to universe class(Lattice), pointer :: lat ! pointer to lattice - type(TallyObject), pointer :: tally ! pointer to tally + type(TallyObject), pointer :: t ! pointer to tally type(TallyFilter), pointer :: filter ! pointer to filter ! Begin gathering list of cells in distribcell tallies @@ -1042,14 +1032,14 @@ contains ! Populate list of distribcells to track do i = 1, n_tallies - tally => tallies(i) + t => tallies(i) - do j = 1, tally % n_filters - filter => tally % filters(j) + do j = 1, t%n_filters + filter => t%filters(j) - if (filter % type == FILTER_DISTRIBCELL) then - if (.not. cell_list % contains(filter % int_bins(1))) then - call cell_list % add(filter % int_bins(1)) + if (filter%type == FILTER_DISTRIBCELL) then + if (.not. cell_list%contains(filter%int_bins(1))) then + call cell_list%add(filter%int_bins(1)) end if end if @@ -1060,8 +1050,8 @@ contains ! to determine the number of offset tables to allocate do i = 1, n_universes univ => universes(i) - do j = 1, univ % n_cells - if (cell_list % contains(univ % cells(j))) then + do j = 1, univ%n_cells + if (cell_list%contains(univ%cells(j))) then n_maps = n_maps + 1 end if end do @@ -1083,29 +1073,29 @@ contains do i = 1, n_universes univ => universes(i) - do j = 1, univ % n_cells + do j = 1, univ%n_cells - if (cell_list % contains(univ % cells(j))) then + if (cell_list%contains(univ%cells(j))) then ! Loop over all tallies do l = 1, n_tallies - tally => tallies(l) + t => tallies(l) - do m = 1, tally % n_filters - filter => tally % filters(m) + do m = 1, t%n_filters + filter => t%filters(m) ! Loop over only distribcell filters ! If filter points to cell we just found, set offset index - if (filter % type == FILTER_DISTRIBCELL) then - if (filter % int_bins(1) == univ % cells(j)) then - filter % offset = k + if (filter%type == FILTER_DISTRIBCELL) then + if (filter%int_bins(1) == univ%cells(j)) then + filter%offset = k end if end if end do end do - univ_list(k) = univ % id + univ_list(k) = univ%id k = k + 1 end if end do @@ -1113,26 +1103,26 @@ contains ! Allocate the offset tables for lattices do i = 1, n_lattices - lat => lattices(i) % obj + lat => lattices(i)%obj select type(lat) type is (RectLattice) - allocate(lat % offset(n_maps, lat % n_cells(1), lat % n_cells(2), & - lat % n_cells(3))) + allocate(lat%offset(n_maps, lat%n_cells(1), lat%n_cells(2), & + lat%n_cells(3))) type is (HexLattice) - allocate(lat % offset(n_maps, 2 * lat % n_rings - 1, & - 2 * lat % n_rings - 1, lat % n_axial)) + allocate(lat%offset(n_maps, 2 * lat%n_rings - 1, & + 2 * lat%n_rings - 1, lat%n_axial)) end select - lat % offset(:, :, :, :) = 0 + lat%offset(:, :, :, :) = 0 end do ! Allocate offset table for fill cells do i = 1, n_cells - if (cells(i) % material == NONE) then - allocate(cells(i) % offset(n_maps)) + if (cells(i)%material == NONE) then + allocate(cells(i)%offset(n_maps)) end if end do diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 8f02267d8..b3354c073 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -8,7 +8,7 @@ module input_xml use geometry_header, only: Cell, Surface, Lattice, RectLattice, HexLattice use global use list_header, only: ListChar, ListInt, ListReal - use mesh_header, only: StructuredMesh + use mesh_header, only: RegularMesh use output, only: write_message use plot_header use random_lcg, only: prn @@ -2117,9 +2117,9 @@ contains character(MAX_WORD_LEN) :: temp_str character(MAX_WORD_LEN), allocatable :: sarray(:) type(DictCharInt) :: trigger_scores - type(ElemKeyValueCI), pointer :: pair_list => null() - type(TallyObject), pointer :: t => null() - type(StructuredMesh), pointer :: m => null() + type(ElemKeyValueCI), pointer :: pair_list + type(TallyObject), pointer :: t + type(RegularMesh), pointer :: m type(TallyFilter), allocatable :: filters(:) ! temporary filters type(Node), pointer :: doc => null() type(Node), pointer :: node_mesh => null() @@ -2214,9 +2214,11 @@ contains call get_node_value(node_mesh, "type", temp_str) select case (to_lower(temp_str)) case ('rect', 'rectangle', 'rectangular') - m % type = LATTICE_RECT - case ('hex', 'hexagon', 'hexagonal') - m % type = LATTICE_HEX + call warning("Mesh type '" // trim(temp_str) // "' is deprecated. & + &Please use 'regular' instead.") + m % type = MESH_REGULAR + case ('regular') + m % type = MESH_REGULAR case default call fatal_error("Invalid mesh type: " // trim(temp_str)) end select @@ -2756,7 +2758,7 @@ contains t % moment_order(j : j + n_bins - 1) = n_order j = j + n_bins - 1 - case ('total') + case ('total', '(n,total)') t % score_bins(j) = SCORE_TOTAL if (t % find_filter(FILTER_ENERGYOUT) > 0) then call fatal_error("Cannot tally total reaction rate with an & @@ -2842,13 +2844,13 @@ contains ! Set tally estimator to analog t % estimator = ESTIMATOR_ANALOG - case ('n2n') + case ('n2n', '(n,2n)') t % score_bins(j) = N_2N - case ('n3n') + case ('n3n', '(n,3n)') t % score_bins(j) = N_3N - case ('n4n') + case ('n4n', '(n,4n)') t % score_bins(j) = N_4N case ('absorption') @@ -2929,6 +2931,79 @@ contains case ('events') t % score_bins(j) = SCORE_EVENTS + case ('elastic', '(n,elastic)') + t % score_bins(j) = ELASTIC + case ('(n,2nd)') + t % score_bins(j) = N_2ND + case ('(n,na)') + t % score_bins(j) = N_2NA + case ('(n,n3a)') + t % score_bins(j) = N_N3A + case ('(n,2na)') + t % score_bins(j) = N_2NA + case ('(n,3na)') + t % score_bins(j) = N_3NA + case ('(n,np)') + t % score_bins(j) = N_NP + case ('(n,n2a)') + t % score_bins(j) = N_N2A + case ('(n,2n2a)') + t % score_bins(j) = N_2N2A + case ('(n,nd)') + t % score_bins(j) = N_ND + case ('(n,nt)') + t % score_bins(j) = N_NT + case ('(n,nHe-3)') + t % score_bins(j) = N_N3HE + case ('(n,nd2a)') + t % score_bins(j) = N_ND2A + case ('(n,nt2a)') + t % score_bins(j) = N_NT2A + case ('(n,3nf)') + t % score_bins(j) = N_3NF + case ('(n,2np)') + t % score_bins(j) = N_2NP + case ('(n,3np)') + t % score_bins(j) = N_3NP + case ('(n,n2p)') + t % score_bins(j) = N_N2P + case ('(n,npa)') + t % score_bins(j) = N_NPA + case ('(n,n1)') + t % score_bins(j) = N_N1 + case ('(n,nc)') + t % score_bins(j) = N_NC + case ('(n,gamma)') + t % score_bins(j) = N_GAMMA + case ('(n,p)') + t % score_bins(j) = N_P + case ('(n,d)') + t % score_bins(j) = N_D + case ('(n,t)') + t % score_bins(j) = N_T + case ('(n,3He)') + t % score_bins(j) = N_3HE + case ('(n,a)') + t % score_bins(j) = N_A + case ('(n,2a)') + t % score_bins(j) = N_2A + case ('(n,3a)') + t % score_bins(j) = N_3A + case ('(n,2p)') + t % score_bins(j) = N_2P + case ('(n,pa)') + t % score_bins(j) = N_PA + case ('(n,t2a)') + t % score_bins(j) = N_T2A + case ('(n,d2a)') + t % score_bins(j) = N_D2A + case ('(n,pd)') + t % score_bins(j) = N_PD + case ('(n,pt)') + t % score_bins(j) = N_PT + case ('(n,da)') + t % score_bins(j) = N_DA + case default ! Assume that user has specified an MT number MT = int(str_to_int(score_name)) @@ -3158,15 +3233,26 @@ contains ! tally needs post-collision information if (t % estimator == ESTIMATOR_ANALOG) then call fatal_error("Cannot use track-length estimator for tally " & - &// to_str(t % id)) + // to_str(t % id)) end if ! Set estimator to track-length estimator t % estimator = ESTIMATOR_TRACKLENGTH + case ('collision') + ! If the estimator was set to an analog estimator, this means the + ! tally needs post-collision information + if (t % estimator == ESTIMATOR_ANALOG) then + call fatal_error("Cannot use collision estimator for tally " & + // to_str(t % id)) + end if + + ! Set estimator to collision estimator + t % estimator = ESTIMATOR_COLLISION + case default call fatal_error("Invalid estimator '" // trim(temp_str) & - &// "' on tally " // to_str(t % id)) + // "' on tally " // to_str(t % id)) end select end if diff --git a/src/mesh.F90 b/src/mesh.F90 index b9d85f439..3d0235d18 100644 --- a/src/mesh.F90 +++ b/src/mesh.F90 @@ -20,7 +20,7 @@ contains subroutine get_mesh_bin(m, xyz, bin) - type(StructuredMesh), pointer :: m ! mesh pointer + type(RegularMesh), pointer :: m ! mesh pointer real(8), intent(in) :: xyz(:) ! coordinates integer, intent(out) :: bin ! tally bin @@ -73,7 +73,7 @@ contains subroutine get_mesh_indices(m, xyz, ijk, in_mesh) - type(StructuredMesh), pointer :: m + type(RegularMesh), pointer :: m real(8), intent(in) :: xyz(:) ! coordinates to check integer, intent(out) :: ijk(:) ! indices in mesh logical, intent(out) :: in_mesh ! were given coords in mesh? @@ -98,7 +98,7 @@ contains function mesh_indices_to_bin(m, ijk, surface_current) result(bin) - type(StructuredMesh), pointer :: m + type(RegularMesh), pointer :: m integer, intent(in) :: ijk(:) logical, optional :: surface_current integer :: bin @@ -132,7 +132,7 @@ contains subroutine bin_to_mesh_indices(m, bin, ijk) - type(StructuredMesh), pointer :: m + type(RegularMesh), pointer :: m integer, intent(in) :: bin integer, intent(out) :: ijk(:) @@ -163,7 +163,7 @@ contains subroutine count_bank_sites(m, bank_array, cnt, energies, size_bank, & sites_outside) - type(StructuredMesh), pointer :: m ! mesh to count sites + type(RegularMesh), pointer :: m ! mesh to count sites type(Bank), intent(in) :: bank_array(:) ! fission or source bank real(8), intent(out) :: cnt(:,:,:,:) ! weight of sites in each ! cell and energy group @@ -264,7 +264,7 @@ contains function mesh_intersects_2d(m, xyz0, xyz1) result(intersects) - type(StructuredMesh), pointer :: m + type(RegularMesh), pointer :: m real(8), intent(in) :: xyz0(2) real(8), intent(in) :: xyz1(2) logical :: intersects @@ -330,7 +330,7 @@ contains function mesh_intersects_3d(m, xyz0, xyz1) result(intersects) - type(StructuredMesh), pointer :: m + type(RegularMesh), pointer :: m real(8), intent(in) :: xyz0(3) real(8), intent(in) :: xyz1(3) logical :: intersects diff --git a/src/mesh_header.F90 b/src/mesh_header.F90 index 9aa57df90..9da06f813 100644 --- a/src/mesh_header.F90 +++ b/src/mesh_header.F90 @@ -7,7 +7,7 @@ module mesh_header ! congruent squares or cubes !=============================================================================== - type StructuredMesh + type RegularMesh integer :: id ! user-specified id integer :: type ! rectangular, hexagonal integer :: n_dimension ! rank of mesh @@ -16,6 +16,6 @@ module mesh_header real(8), allocatable :: lower_left(:) ! lower-left corner of mesh real(8), allocatable :: upper_right(:) ! upper-right corner of mesh real(8), allocatable :: width(:) ! width of each mesh cell - end type StructuredMesh + end type RegularMesh end module mesh_header diff --git a/src/mpiio_interface.F90 b/src/mpiio_interface.F90 deleted file mode 100644 index b9652c8ae..000000000 --- a/src/mpiio_interface.F90 +++ /dev/null @@ -1,610 +0,0 @@ -module mpiio_interface - -#ifdef MPI -#ifndef HDF5 - use message_passing - - implicit none - -#ifdef MPIF08 -#define FH_TYPE type(MPI_File) -#else -#define FH_TYPE integer -#endif - - integer :: mpiio_err ! MPI error code - - ! Generic HDF5 write procedure interface - interface mpi_write_data - module procedure mpi_write_double - module procedure mpi_write_double_1Darray - module procedure mpi_write_double_2Darray - module procedure mpi_write_double_3Darray - module procedure mpi_write_double_4Darray - module procedure mpi_write_integer - module procedure mpi_write_integer_1Darray - module procedure mpi_write_integer_2Darray - module procedure mpi_write_integer_3Darray - module procedure mpi_write_integer_4Darray - module procedure mpi_write_long - module procedure mpi_write_string - end interface mpi_write_data - - ! Generic HDF5 read procedure interface - interface mpi_read_data - module procedure mpi_read_double - module procedure mpi_read_double_1Darray - module procedure mpi_read_double_2Darray - module procedure mpi_read_double_3Darray - module procedure mpi_read_double_4Darray - module procedure mpi_read_integer - module procedure mpi_read_integer_1Darray - module procedure mpi_read_integer_2Darray - module procedure mpi_read_integer_3Darray - module procedure mpi_read_integer_4Darray - module procedure mpi_read_long - module procedure mpi_read_string - end interface mpi_read_data - -contains - -!=============================================================================== -! MPI_CREATE_FILE creates a file using MPI file I/O -!=============================================================================== - - subroutine mpi_create_file(filename, fh) - - character(*), intent(in) :: filename ! name of file to create - FH_TYPE, intent(inout) :: fh ! file handle - - ! Create the file - call MPI_FILE_OPEN(MPI_COMM_WORLD, filename, MPI_MODE_CREATE + & - MPI_MODE_WRONLY, MPI_INFO_NULL, fh, mpiio_err) - - end subroutine mpi_create_file - -!=============================================================================== -! MPI_OPEN_FILE opens a file using MPI file I/O -!=============================================================================== - - subroutine mpi_open_file(filename, fh, mode) - - character(*), intent(in) :: filename ! name of file to open - character(*), intent(in) :: mode ! open 'r' read, 'w' write - FH_TYPE, intent(inout) :: fh ! file handle - - integer :: open_mode - - ! Determine access mode - open_mode = MPI_MODE_RDONLY - if (mode == 'w') then - open_mode = ior(MPI_MODE_APPEND, MPI_MODE_WRONLY) - end if - - ! Create the file - call MPI_FILE_OPEN(MPI_COMM_WORLD, filename, & - open_mode, MPI_INFO_NULL, fh, mpiio_err) - - end subroutine mpi_open_file - -!=============================================================================== -! MPI_CLOSE_FILE closes a file using MPI file I/O -!=============================================================================== - - subroutine mpi_close_file(fh) - - FH_TYPE, intent(inout) :: fh ! file handle - - call MPI_FILE_CLOSE(fh, mpiio_err) - - end subroutine mpi_close_file - -!=============================================================================== -! MPI_WRITE_INTEGER writes integer scalar data using MPI File I/O -!=============================================================================== - - subroutine mpi_write_integer(fh, buffer, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: buffer ! data to write - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_WRITE_ALL(fh, buffer, 1, MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_WRITE(fh, buffer, 1, MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_write_integer - -!=============================================================================== -! MPI_READ_INTEGER reads integer scalar data using MPI file I/O -!=============================================================================== - - subroutine mpi_read_integer(fh, buffer, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(inout) :: buffer ! read data to here - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_READ_ALL(fh, buffer, 1, MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_READ(fh, buffer, 1, MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_read_integer - -!=============================================================================== -! MPI_WRITE_INTEGER_1DARRAY writes integer 1-D array data using MPI File I/O -!=============================================================================== - - subroutine mpi_write_integer_1Darray(fh, buffer, length, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length ! length of array - integer, intent(in) :: buffer(:) ! data to write - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_WRITE_ALL(fh, buffer, length, MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_WRITE(fh, buffer, length, MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_write_integer_1Darray - -!=============================================================================== -! MPI_READ_INTEGER_1DARRAY reads integer 1-D array using MPI file I/O -!=============================================================================== - - subroutine mpi_read_integer_1Darray(fh, buffer, length, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length ! length of array - integer, intent(inout) :: buffer(:) ! read data to here - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_READ_ALL(fh, buffer, length, MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_READ(fh, buffer, length, MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_read_integer_1Darray - -!=============================================================================== -! MPI_WRITE_INTEGER_2DARRAY writes integer 2-D array data using MPI File I/O -!=============================================================================== - - subroutine mpi_write_integer_2Darray(fh, buffer, length, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length(2) ! length of array - integer, intent(in) :: buffer(length(1),length(2)) ! data to write - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_WRITE_ALL(fh, buffer, product(length), MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_WRITE(fh, buffer, product(length), MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_write_integer_2Darray - -!=============================================================================== -! MPI_READ_INTEGER_2DARRAY reads integer 2-D array using MPI file I/O -!=============================================================================== - - subroutine mpi_read_integer_2Darray(fh, buffer, length, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length(2) ! length of array - integer, intent(inout) :: buffer(length(1),length(2)) ! read data to here - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_READ_ALL(fh, buffer, product(length), MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_READ(fh, buffer, product(length), MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_read_integer_2Darray - -!=============================================================================== -! MPI_WRITE_INTEGER_3DARRAY writes integer 3-D array data using MPI File I/O -!=============================================================================== - - subroutine mpi_write_integer_3Darray(fh, buffer, length, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length(3) ! length of array - integer, intent(in) :: buffer(length(1),length(2),& - length(3)) ! data to write - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_WRITE_ALL(fh, buffer, product(length), MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_WRITE(fh, buffer, product(length), MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_write_integer_3Darray - -!=============================================================================== -! MPI_READ_INTEGER_3DARRAY reads integer 3-D array using MPI file I/O -!=============================================================================== - - subroutine mpi_read_integer_3Darray(fh, buffer, length, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length(3) ! length of array - integer, intent(inout) :: buffer(length(1),length(2), & - length(3)) ! read data to here - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_READ_ALL(fh, buffer, product(length), MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_READ(fh, buffer, product(length), MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_read_integer_3Darray - -!=============================================================================== -! MPI_WRITE_INTEGER_4DARRAY writes integer 4-D array data using MPI File I/O -!=============================================================================== - - subroutine mpi_write_integer_4Darray(fh, buffer, length, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length(4) ! length of array - integer, intent(in) :: buffer(length(1),length(2),& - length(3),length(4)) ! data to write - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_WRITE_ALL(fh, buffer, product(length), MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_WRITE(fh, buffer, product(length), MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_write_integer_4Darray - -!=============================================================================== -! MPI_READ_INTEGER_4DARRAY reads integer 4-D array using MPI file I/O -!=============================================================================== - - subroutine mpi_read_integer_4Darray(fh, buffer, length, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length(4) ! length of array - integer, intent(inout) :: buffer(length(1),length(2), & - length(3),length(4)) ! read data to here - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_READ_ALL(fh, buffer, product(length), MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_READ(fh, buffer, product(length), MPI_INTEGER, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_read_integer_4Darray - -!=============================================================================== -! MPI_WRITE_DOUBLE writes integer scalar data using MPI File I/O -!=============================================================================== - - subroutine mpi_write_double(fh, buffer, collect) - - FH_TYPE, intent(in) :: fh ! file handle - real(8), intent(in) :: buffer ! data to write - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_WRITE_ALL(fh, buffer, 1, MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_WRITE(fh, buffer, 1, MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_write_double - -!=============================================================================== -! MPI_READ_DOUBLE reads integer scalar data using MPI file I/O -!=============================================================================== - - subroutine mpi_read_double(fh, buffer, collect) - - FH_TYPE, intent(in) :: fh ! file handle - real(8), intent(inout) :: buffer ! read data to here - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_READ_ALL(fh, buffer, 1, MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_READ(fh, buffer, 1, MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_read_double - -!=============================================================================== -! MPI_WRITE_DOUBLE_1DARRAY writes integer 1-D array data using MPI File I/O -!=============================================================================== - - subroutine mpi_write_double_1Darray(fh, buffer, length, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length ! length of array - real(8), intent(in) :: buffer(:) ! data to write - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_WRITE_ALL(fh, buffer, length, MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_WRITE(fh, buffer, length, MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_write_double_1Darray - -!=============================================================================== -! MPI_READ_DOUBLE_1DARRAY reads integer 1-D array using MPI file I/O -!=============================================================================== - - subroutine mpi_read_double_1Darray(fh, buffer, length, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length ! length of array - real(8), intent(inout) :: buffer(:) ! read data to here - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_READ_ALL(fh, buffer, length, MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_READ(fh, buffer, length, MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_read_double_1Darray - -!=============================================================================== -! MPI_WRITE_DOUBLE_2DARRAY writes integer 2-D array data using MPI File I/O -!=============================================================================== - - subroutine mpi_write_double_2Darray(fh, buffer, length, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length(2) ! length of array - real(8), intent(in) :: buffer(length(1),length(2)) ! data to write - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_WRITE_ALL(fh, buffer, product(length), MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_WRITE(fh, buffer, product(length), MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_write_double_2Darray - -!=============================================================================== -! MPI_READ_DOUBLE_2DARRAY reads integer 2-D array using MPI file I/O -!=============================================================================== - - subroutine mpi_read_double_2Darray(fh, buffer, length, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length(2) ! length of array - real(8), intent(inout) :: buffer(length(1),length(2)) ! read data to here - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_READ_ALL(fh, buffer, product(length), MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_READ(fh, buffer, product(length), MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_read_double_2Darray - -!=============================================================================== -! MPI_WRITE_DOUBLE_3DARRAY writes integer 3-D array data using MPI File I/O -!=============================================================================== - - subroutine mpi_write_double_3Darray(fh, buffer, length, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length(3) ! length of array - real(8), intent(in) :: buffer(length(1),length(2),& - length(3)) ! data to write - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_WRITE_ALL(fh, buffer, product(length), MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_WRITE(fh, buffer, product(length), MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_write_double_3Darray - -!=============================================================================== -! MPI_READ_DOUBLE_3DARRAY reads integer 3-D array using MPI file I/O -!=============================================================================== - - subroutine mpi_read_double_3Darray(fh, buffer, length, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length(3) ! length of array - real(8), intent(inout) :: buffer(length(1),length(2), & - length(3)) ! read data to here - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_READ_ALL(fh, buffer, product(length), MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_READ(fh, buffer, product(length), MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_read_double_3Darray - -!=============================================================================== -! MPI_WRITE_DOUBLE_4DARRAY writes integer 4-D array data using MPI File I/O -!=============================================================================== - - subroutine mpi_write_double_4Darray(fh, buffer, length, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length(4) ! length of array - real(8), intent(in) :: buffer(length(1),length(2),& - length(3),length(4)) ! data to write - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_WRITE_ALL(fh, buffer, product(length), MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_WRITE(fh, buffer, product(length), MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_write_double_4Darray - -!=============================================================================== -! MPI_READ_DOUBLE_4DARRAY reads integer 4-D array using MPI file I/O -!=============================================================================== - - subroutine mpi_read_double_4Darray(fh, buffer, length, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length(4) ! length of array - real(8), intent(inout) :: buffer(length(1),length(2), & - length(3),length(4)) ! read data to here - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_READ_ALL(fh, buffer, product(length), MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_READ(fh, buffer, product(length), MPI_REAL8, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_read_double_4Darray - -!=============================================================================== -! MPI_WRITE_LONG writes long integer scalar data using MPI file I/O -!=============================================================================== - - subroutine mpi_write_long(fh, buffer, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer(8), intent(in) :: buffer ! data to write - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_WRITE_ALL(fh, buffer, 1, MPI_INTEGER8, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_WRITE(fh, buffer, 1, MPI_INTEGER8, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_write_long - -!=============================================================================== -! MPI_READ_LONG reads long integer scalar data using MPI file I/O -!=============================================================================== - - subroutine mpi_read_long(fh, buffer, collect) - - FH_TYPE, intent(in) :: fh ! file handle - integer(8), intent(inout) :: buffer ! read data to here - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_READ_ALL(fh, buffer, 1, MPI_INTEGER8, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_READ(fh, buffer, 1, MPI_INTEGER8, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_read_long - -!=============================================================================== -! MPI_WRITE_STRING writes string data using MPI file I/O -!=============================================================================== - - subroutine mpi_write_string(fh, buffer, length, collect) - - character(*), intent(in) :: buffer ! data to write - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length ! length of data - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_WRITE_ALL(fh, buffer, length, MPI_CHARACTER, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_WRITE(fh, buffer, length, MPI_CHARACTER, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_write_string - -!=============================================================================== -! MPI_READ_STRING reads string data using MPI file I/O -!=============================================================================== - - subroutine mpi_read_string(fh, buffer, length, collect) - - character(*), intent(inout) :: buffer ! read data to here - FH_TYPE, intent(in) :: fh ! file handle - integer, intent(in) :: length ! length of string - logical, intent(in) :: collect ! collective I/O - - if (collect) then - call MPI_FILE_READ_ALL(fh, buffer, length, MPI_CHARACTER, & - MPI_STATUS_IGNORE, mpiio_err) - else - call MPI_FILE_READ(fh, buffer, length, MPI_CHARACTER, & - MPI_STATUS_IGNORE, mpiio_err) - end if - - end subroutine mpi_read_string - -#endif -#endif -end module mpiio_interface diff --git a/src/output.F90 b/src/output.F90 index d1d4ec72a..1a841a777 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -10,7 +10,7 @@ module output HexLattice, BASE_UNIVERSE use global use math, only: t_percentile - use mesh_header, only: StructuredMesh + use mesh_header, only: RegularMesh use mesh, only: mesh_indices_to_bin, bin_to_mesh_indices use particle_header, only: LocalCoord, Particle use plot_header @@ -315,694 +315,6 @@ contains end subroutine print_particle -!=============================================================================== -! PRINT_REACTION displays the attributes of a reaction -!=============================================================================== - - subroutine print_reaction(rxn) - - type(Reaction), pointer :: rxn - - write(ou,*) 'Reaction ' // reaction_name(rxn % MT) - write(ou,*) ' MT = ' // to_str(rxn % MT) - write(ou,*) ' Q-value = ' // to_str(rxn % Q_value) - write(ou,*) ' Multiplicity = ' // to_str(rxn % multiplicity) - write(ou,*) ' Threshold = ' // to_str(rxn % threshold) - if (rxn % has_energy_dist) then - write(ou,*) ' Energy: Law ' // to_str(rxn % edist % law) - end if - write(ou,*) - - end subroutine print_reaction - -!=============================================================================== -! PRINT_CELL displays the attributes of a cell -!=============================================================================== - - subroutine print_cell(c, unit) - - type(Cell), pointer :: c - integer, optional :: unit ! specified unit to write to - - integer :: index_cell ! index in cells array - integer :: i ! loop index for surfaces - integer :: index_surf ! index in surfaces array - integer :: unit_ ! unit to write to - character(MAX_LINE_LEN) :: string - type(Universe), pointer :: u => null() - class(Lattice), pointer :: l => null() - type(Material), pointer :: m => null() - - ! Set unit to stdout if not already set - if (present(unit)) then - unit_ = unit - else - unit_ = OUTPUT_UNIT - end if - - ! Write user-specified id for cell - write(unit_,*) 'Cell ' // to_str(c % id) - - ! Write user-specified name for cell - write(unit_,*) ' Name = ' // c % name - - ! Find index in cells array and write - index_cell = cell_dict % get_key(c % id) - write(unit_,*) ' Array Index = ' // to_str(index_cell) - - ! Write what universe this cell is in - u => universes(c % universe) - write(unit_,*) ' Universe = ' // to_str(u % id) - - ! Write information on fill for cell - select case (c % type) - case (CELL_NORMAL) - write(unit_,*) ' Fill = NONE' - case (CELL_FILL) - u => universes(c % fill) - write(unit_,*) ' Fill = Universe ' // to_str(u % id) - case (CELL_LATTICE) - l => lattices(c % fill) % obj - write(unit_,*) ' Fill = Lattice ' // to_str(l % id) - end select - - ! Write information on material - if (c % material == 0) then - write(unit_,*) ' Material = NONE' - elseif (c % material == MATERIAL_VOID) then - write(unit_,*) ' Material = Void' - else - m => materials(c % material) - write(unit_,*) ' Material = ' // to_str(m % id) - end if - - ! Write surface specification - string = "" - do i = 1, c % n_surfaces - select case (c % surfaces(i)) - case (OP_LEFT_PAREN) - string = trim(string) // ' (' - case (OP_RIGHT_PAREN) - string = trim(string) // ' )' - case (OP_UNION) - string = trim(string) // ' :' - case (OP_DIFFERENCE) - string = trim(string) // ' !' - case default - index_surf = abs(c % surfaces(i)) - string = trim(string) // ' ' // to_str(sign(& - surfaces(index_surf) % id, c % surfaces(i))) - end select - end do - write(unit_,*) ' Surface Specification:' // trim(string) - write(unit_,*) - - end subroutine print_cell - -!=============================================================================== -! PRINT_UNIVERSE displays the attributes of a universe -!=============================================================================== - - subroutine print_universe(univ, unit) - - type(Universe), pointer :: univ - integer, optional :: unit - - integer :: i ! loop index for cells in this universe - integer :: unit_ ! unit to write to - character(MAX_LINE_LEN) :: string - type(Cell), pointer :: c => null() - type(Universe), pointer :: base_u => null() - - ! Set default unit to stdout if not specified - if (present(unit)) then - unit_ = unit - else - unit_ = OUTPUT_UNIT - end if - - ! Get a pointer to the base universe - base_u => universes(BASE_UNIVERSE) - - ! Write user-specified id for this universe - write(unit_,*) 'Universe ' // to_str(univ % id) - - ! If this is the base universe, indicate so - if (associated(univ, base_u)) then - write(unit_,*) ' Base Universe' - end if - - ! Write list of cells in this universe - string = "" - do i = 1, univ % n_cells - c => cells(univ % cells(i)) - string = trim(string) // ' ' // to_str(c % id) - end do - write(unit_,*) ' Cells =' // trim(string) - write(unit_,*) - - end subroutine print_universe - -!=============================================================================== -! PRINT_LATTICE displays the attributes of a lattice -!=============================================================================== - - subroutine print_lattice(lat, unit) - - class(Lattice), pointer :: lat - integer, optional :: unit - - integer :: unit_ ! unit to write to - - ! set default unit if not specified - if (present(unit)) then - unit_ = unit - else - unit_ = OUTPUT_UNIT - end if - - ! Write information about lattice - write(unit_,*) 'Lattice ' // to_str(lat % id) - - ! Write user-specified name for lattice - write(unit_,*) ' Name = ' // lat % name - - select type(lat) - type is (RectLattice) - ! Write dimension of lattice. - if (lat % is_3d) then - write(unit_, *) ' Dimension = ' // to_str(lat % n_cells(1)) & - &// ' ' // to_str(lat % n_cells(2)) // ' ' & - &// to_str(lat % n_cells(3)) - else - write(unit_, *) ' Dimension = ' // to_str(lat % n_cells(1)) & - &// ' ' // to_str(lat % n_cells(2)) - end if - - ! Write lower-left coordinates of lattice. - if (lat % is_3d) then - write(unit_, *) ' Lower-left = ' // to_str(lat % lower_left(1)) & - &// ' ' // to_str(lat % lower_left(2)) // ' ' & - &// to_str(lat % lower_left(3)) - else - write(unit_, *) ' Lower-left = ' // to_str(lat % lower_left(1)) & - &// ' ' // to_str(lat % lower_left(2)) - end if - - ! Write lattice pitch along each axis. - if (lat % is_3d) then - write(unit_, *) ' Pitch = ' // to_str(lat % pitch(1)) & - &// ' ' // to_str(lat % pitch(2)) // ' ' & - &// to_str(lat % pitch(3)) - else - write(unit_, *) ' Pitch = ' // to_str(lat % pitch(1)) & - &// ' ' // to_str(lat % pitch(2)) - end if - write(unit_,*) - - type is (HexLattice) - ! Write dimension of lattice. - write(unit_,*) ' N-rings = ' // to_str(lat % n_rings) - if (lat % is_3d) write(unit_,*) ' N-axial = ' // to_str(lat % n_axial) - - ! Write center coordinates of lattice. - if (lat % is_3d) then - write(unit_, *) ' Center = ' // to_str(lat % center(1)) & - &// ' ' // to_str(lat % center(2)) // ' ' & - &// to_str(lat % center(3)) - else - write(unit_, *) ' Center = ' // to_str(lat % center(1)) & - &// ' ' // to_str(lat % center(2)) - end if - - ! Write lattice pitch along each axis. - if (lat % is_3d) then - write(unit_, *) ' Pitch = ' // to_str(lat % pitch(1)) & - &// ' ' // to_str(lat % pitch(2)) - else - write(unit_, *) ' Pitch = ' // to_str(lat % pitch(1)) - end if - write(unit_,*) - end select - - - end subroutine print_lattice - -!=============================================================================== -! PRINT_SURFACE displays the attributes of a surface -!=============================================================================== - - subroutine print_surface(surf, unit) - - type(Surface), pointer :: surf - integer, optional :: unit ! specified unit to write to - - integer :: i ! loop index for coefficients - integer :: unit_ ! unit to write to - character(MAX_LINE_LEN) :: string - type(Cell), pointer :: c => null() - - ! set default unit if not specified - if (present(unit)) then - unit_ = unit - else - unit_ = OUTPUT_UNIT - end if - - ! Write user-specified id of surface - write(unit_,*) 'Surface ' // to_str(surf % id) - - ! Write user-specified name for surface - write(unit_,*) ' Name = ' // surf % name - - ! Write type of surface - select case (surf % type) - case (SURF_PX) - string = "X Plane" - case (SURF_PY) - string = "Y Plane" - case (SURF_PZ) - string = "Z Plane" - case (SURF_PLANE) - string = "Plane" - case (SURF_CYL_X) - string = "X Cylinder" - case (SURF_CYL_Y) - string = "Y Cylinder" - case (SURF_CYL_Z) - string = "Z Cylinder" - case (SURF_SPHERE) - string = "Sphere" - case (SURF_CONE_X) - string = "X Cone" - case (SURF_CONE_Y) - string = "Y Cone" - case (SURF_CONE_Z) - string = "Z Cone" - end select - write(unit_,*) ' Type = ' // trim(string) - - ! Write coefficients for this surface - string = "" - do i = 1, size(surf % coeffs) - string = trim(string) // ' ' // to_str(surf % coeffs(i), 4) - end do - write(unit_,*) ' Coefficients = ' // trim(string) - - ! Write neighboring cells on positive side of this surface - string = "" - if (allocated(surf % neighbor_pos)) then - do i = 1, size(surf % neighbor_pos) - c => cells(abs(surf % neighbor_pos(i))) - string = trim(string) // ' ' // to_str(& - sign(c % id, surf % neighbor_pos(i))) - end do - end if - write(unit_,*) ' Positive Neighbors = ' // trim(string) - - ! Write neighboring cells on negative side of this surface - string = "" - if (allocated(surf % neighbor_neg)) then - do i = 1, size(surf % neighbor_neg) - c => cells(abs(surf % neighbor_neg(i))) - string = trim(string) // ' ' // to_str(& - sign(c % id, surf % neighbor_neg(i))) - end do - end if - write(unit_,*) ' Negative Neighbors =' // trim(string) - - ! Write boundary condition for this surface - select case (surf % bc) - case (BC_TRANSMIT) - write(unit_,*) ' Boundary Condition = Transmission' - case (BC_VACUUM) - write(unit_,*) ' Boundary Condition = Vacuum' - case (BC_REFLECT) - write(unit_,*) ' Boundary Condition = Reflective' - case (BC_PERIODIC) - write(unit_,*) ' Boundary Condition = Periodic' - end select - write(unit_,*) - - end subroutine print_surface - -!=============================================================================== -! PRINT_MATERIAL displays the attributes of a material -!=============================================================================== - - subroutine print_material(mat, unit) - - type(Material), pointer :: mat - integer, optional :: unit - - integer :: i ! loop index for nuclides - integer :: unit_ ! unit to write to - real(8) :: density ! density in atom/b-cm - character(MAX_LINE_LEN) :: string - type(Nuclide), pointer :: nuc => null() - - ! set default unit to stdout if not specified - if (present(unit)) then - unit_ = unit - else - unit_ = OUTPUT_UNIT - end if - - ! Write identifier for material - write(unit_,*) 'Material ' // to_str(mat % id) - - ! Write user-specified name for material - write(unit_,*) ' Name = ' // mat % name - - ! Write total atom density in atom/b-cm - write(unit_,*) ' Atom Density = ' // trim(to_str(mat % density)) & - // ' atom/b-cm' - - ! Write atom density for each nuclide in material - write(unit_,*) ' Nuclides:' - do i = 1, mat % n_nuclides - nuc => nuclides(mat % nuclide(i)) - density = mat % atom_density(i) - string = ' ' // trim(nuc % name) // ' = ' // & - trim(to_str(density)) // ' atom/b-cm' - write(unit_,*) trim(string) - end do - - ! Write information on S(a,b) table - if (mat % n_sab > 0) then - write(unit_,*) ' S(a,b) tables:' - do i = 1, mat % n_sab - write(unit_,*) ' ' // trim(& - sab_tables(mat % i_sab_tables(i)) % name) - end do - end if - write(unit_,*) - - end subroutine print_material - -!=============================================================================== -! PRINT_TALLY displays the attributes of a tally -!=============================================================================== - - subroutine print_tally(t, unit) - - type(TallyObject), pointer :: t - integer, optional :: unit - - integer :: i ! index for filter or score bins - integer :: j ! index in filters array - integer :: id ! user-specified id - integer :: unit_ ! unit to write to - integer :: n ! moment order to include in name - character(MAX_LINE_LEN) :: string - character(MAX_WORD_LEN) :: pn_string - type(Cell), pointer :: c => null() - type(Surface), pointer :: s => null() - type(Universe), pointer :: u => null() - type(Material), pointer :: m => null() - type(StructuredMesh), pointer :: sm => null() - - ! set default unit to stdout if not specified - if (present(unit)) then - unit_ = unit - else - unit_ = OUTPUT_UNIT - end if - - ! Write user-specified id of tally - write(unit_,*) 'Tally ' // to_str(t % id) - - ! Write the type of tally - select case(t % type) - case (TALLY_VOLUME) - write(unit_,*) ' Type: Volume' - case (TALLY_SURFACE_CURRENT) - write(unit_,*) ' Type: Surface Current' - end select - - ! Write the estimator used - select case(t % estimator) - case(ESTIMATOR_ANALOG) - write(unit_,*) ' Estimator: Analog' - case(ESTIMATOR_TRACKLENGTH) - write(unit_,*) ' Estimator: Track-length' - end select - - ! Write any cells bins if present - j = t % find_filter(FILTER_DISTRIBCELL) - if (j > 0) then - string = "" - id = t % filters(j) % int_bins(1) - c => cells(id) - string = trim(string) // ' ' // trim(to_str(c % id)) - write(unit_, *) ' Distribcell Bins:' // trim(string) - end if - - ! Write any cells bins if present - j = t % find_filter(FILTER_CELL) - if (j > 0) then - string = "" - do i = 1, t % filters(j) % n_bins - id = t % filters(j) % int_bins(i) - c => cells(id) - string = trim(string) // ' ' // trim(to_str(c % id)) - end do - write(unit_, *) ' Cell Bins:' // trim(string) - end if - - ! Write any surface bins if present - j = t % find_filter(FILTER_SURFACE) - if (j > 0) then - string = "" - do i = 1, t % filters(j) % n_bins - id = t % filters(j) % int_bins(i) - s => surfaces(id) - string = trim(string) // ' ' // trim(to_str(s % id)) - end do - write(unit_, *) ' Surface Bins:' // trim(string) - end if - - ! Write any universe bins if present - j = t % find_filter(FILTER_UNIVERSE) - if (j > 0) then - string = "" - do i = 1, t % filters(j) % n_bins - id = t % filters(j) % int_bins(i) - u => universes(id) - string = trim(string) // ' ' // trim(to_str(u % id)) - end do - write(unit_, *) ' Universe Bins:' // trim(string) - end if - - ! Write any material bins if present - j = t % find_filter(FILTER_MATERIAL) - if (j > 0) then - string = "" - do i = 1, t % filters(j) % n_bins - id = t % filters(j) % int_bins(i) - m => materials(id) - string = trim(string) // ' ' // trim(to_str(m % id)) - end do - write(unit_, *) ' Material Bins:' // trim(string) - end if - - ! Write any mesh bins if present - j = t % find_filter(FILTER_MESH) - if (j > 0) then - string = "" - id = t % filters(j) % int_bins(1) - sm => meshes(id) - string = trim(string) // ' ' // trim(to_str(sm % dimension(1))) - do i = 2, sm % n_dimension - string = trim(string) // ' x ' // trim(to_str(sm % dimension(i))) - end do - write(unit_, *) ' Mesh Bins:' // trim(string) - end if - - ! Write any birth region bins if present - j = t % find_filter(FILTER_CELLBORN) - if (j > 0) then - string = "" - do i = 1, t % filters(j) % n_bins - id = t % filters(j) % int_bins(i) - c => cells(id) - string = trim(string) // ' ' // trim(to_str(c % id)) - end do - write(unit_, *) ' Birth Region Bins:' // trim(string) - end if - - ! Write any incoming energy bins if present - j = t % find_filter(FILTER_ENERGYIN) - if (j > 0) then - string = "" - do i = 1, t % filters(j) % n_bins + 1 - string = trim(string) // ' ' // trim(to_str(& - t % filters(j) % real_bins(i))) - end do - write(unit_,*) ' Incoming Energy Bins:' // trim(string) - end if - - ! Write any outgoing energy bins if present - j = t % find_filter(FILTER_ENERGYOUT) - if (j > 0) then - string = "" - do i = 1, t % filters(j) % n_bins + 1 - string = trim(string) // ' ' // trim(to_str(& - t % filters(j) % real_bins(i))) - end do - write(unit_,*) ' Outgoing Energy Bins:' // trim(string) - end if - - ! Write nuclides bins - write(unit_,fmt='(1X,A)',advance='no') ' Nuclide Bins:' - do i = 1, t % n_nuclide_bins - if (t % nuclide_bins(i) == -1) then - write(unit_,fmt='(A)',advance='no') ' total' - else - write(unit_,fmt='(A)',advance='no') ' ' // trim(adjustl(& - nuclides(t % nuclide_bins(i)) % name)) - end if - if (mod(i,4) == 0 .and. i /= t % n_nuclide_bins) & - write(unit_,'(/18X)',advance='no') - end do - write(unit_,*) - - ! Write score bins - string = "" - j = 0 - do i = 1, t % n_user_score_bins - j = j + 1 - select case (t % score_bins(j)) - case (SCORE_FLUX) - string = trim(string) // ' flux' - case (SCORE_FLUX_YN) - pn_string = ' flux' - string = trim(string) // pn_string - do n = 1, t % moment_order(j) - pn_string = ' flux-y' // trim(to_str(n)) - string = trim(string) // pn_string - end do - j = j + n - 1 - case (SCORE_TOTAL) - string = trim(string) // ' total' - case (SCORE_TOTAL_YN) - pn_string = ' total' - string = trim(string) // pn_string - do n = 1, t % moment_order(j) - pn_string = ' total-y' // trim(to_str(n)) - string = trim(string) // pn_string - end do - j = j + n - 1 - case (SCORE_SCATTER) - string = trim(string) // ' scatter' - case (SCORE_NU_SCATTER) - string = trim(string) // ' nu-scatter' - case (SCORE_SCATTER_N) - pn_string = ' scatter-' // trim(to_str(t % moment_order(j))) - string = trim(string) // pn_string - case (SCORE_SCATTER_PN) - pn_string = ' scatter' - string = trim(string) // pn_string - do n = 1, t % moment_order(j) - pn_string = ' scatter-p' // trim(to_str(n)) - string = trim(string) // pn_string - end do - j = j + n - 1 - case (SCORE_NU_SCATTER_N) - pn_string = ' nu-scatter-' // trim(to_str(t % moment_order(j))) - string = trim(string) // pn_string - case (SCORE_NU_SCATTER_PN) - pn_string = ' nu-scatter' - string = trim(string) // pn_string - do n = 1, t % moment_order(j) - pn_string = ' nu-scatter-p' // trim(to_str(n)) - string = trim(string) // pn_string - end do - j = j + n - 1 - case (SCORE_SCATTER_YN) - pn_string = ' scatter' - string = trim(string) // pn_string - do n = 1, t % moment_order(j) - pn_string = ' scatter-y' // trim(to_str(n)) - string = trim(string) // pn_string - end do - j = j + n - 1 - case (SCORE_NU_SCATTER_YN) - pn_string = ' nu-scatter' - string = trim(string) // pn_string - do n = 1, t % moment_order(j) - pn_string = ' nu-scatter-y' // trim(to_str(n)) - string = trim(string) // pn_string - end do - j = j + n - 1 - case (SCORE_TRANSPORT) - string = trim(string) // ' transport' - case (SCORE_N_1N) - string = trim(string) // ' n1n' - case (SCORE_ABSORPTION) - string = trim(string) // ' absorption' - case (SCORE_FISSION) - string = trim(string) // ' fission' - case (SCORE_NU_FISSION) - string = trim(string) // ' nu-fission' - case (SCORE_KAPPA_FISSION) - string = trim(string) // ' kappa-fission' - case (SCORE_CURRENT) - string = trim(string) // ' current' - case default - string = trim(string) // ' ' // reaction_name(t % score_bins(j)) - end select - end do - write(unit_,*) ' Scores:' // trim(string) - write(unit_,*) - - end subroutine print_tally - -!=============================================================================== -! PRINT_GEOMETRY displays the attributes of all cells, surfaces, universes, -! surfaces, and lattices read in the input files. -!=============================================================================== - - subroutine print_geometry() - - integer :: i ! loop index for various arrays - type(Surface), pointer :: s => null() - type(Cell), pointer :: c => null() - type(Universe), pointer :: u => null() - class(Lattice), pointer :: l => null() - - ! print summary of surfaces - call header("SURFACE SUMMARY", unit=UNIT_SUMMARY) - do i = 1, n_surfaces - s => surfaces(i) - call print_surface(s, unit=UNIT_SUMMARY) - end do - - ! print summary of cells - call header("CELL SUMMARY", unit=UNIT_SUMMARY) - do i = 1, n_cells - c => cells(i) - call print_cell(c, unit=UNIT_SUMMARY) - end do - - ! print summary of universes - call header("UNIVERSE SUMMARY", unit=UNIT_SUMMARY) - do i = 1, n_universes - u => universes(i) - call print_universe(u, unit=UNIT_SUMMARY) - end do - - ! print summary of lattices - if (n_lattices > 0) then - call header("LATTICE SUMMARY", unit=UNIT_SUMMARY) - do i = 1, n_lattices - l => lattices(i) % obj - call print_lattice(l, unit=UNIT_SUMMARY) - end do - end if - - end subroutine print_geometry - !=============================================================================== ! PRINT_NUCLIDE displays information about a continuous-energy neutron ! cross_section table and its reactions and secondary angle/energy distributions @@ -1203,98 +515,6 @@ contains end subroutine print_sab_table -!=============================================================================== -! WRITE_SUMMARY displays summary information about the problem about to be run -! after reading all input files -!=============================================================================== - - subroutine write_summary() - - integer :: i ! loop index - character(MAX_FILE_LEN) :: path ! path of summary file - type(Material), pointer :: m => null() - type(TallyObject), pointer :: t => null() - - ! Create filename for log file - path = trim(path_output) // "summary.out" - - ! Open log file for writing - open(UNIT=UNIT_SUMMARY, FILE=path, STATUS='replace', ACTION='write') - - call header("OpenMC Monte Carlo Code", unit=UNIT_SUMMARY, level=1) - write(UNIT=UNIT_SUMMARY, FMT=*) & - "Copyright: 2011-2015 Massachusetts Institute of Technology" - write(UNIT=UNIT_SUMMARY, FMT='(1X,A,7X,2(I1,"."),I1)') & - "Version:", VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE -#ifdef GIT_SHA1 - write(UNIT=UNIT_SUMMARY, FMT='(1X,"Git SHA1:",6X,A)') GIT_SHA1 -#endif - write(UNIT=UNIT_SUMMARY, FMT='(1X,"Date/Time:",5X,A)') & - time_stamp() - - ! Write information on number of processors -#ifdef MPI - write(UNIT=UNIT_SUMMARY, FMT='(1X,"MPI Processes:",1X,A)') & - trim(to_str(n_procs)) -#endif - - ! Display problem summary - call header("PROBLEM SUMMARY", unit=UNIT_SUMMARY) - select case(run_mode) - case (MODE_EIGENVALUE) - write(UNIT_SUMMARY,100) 'Problem type:', 'k eigenvalue' - write(UNIT_SUMMARY,101) 'Number of Batches:', n_batches - write(UNIT_SUMMARY,101) 'Number of Inactive Batches:', n_inactive - write(UNIT_SUMMARY,101) 'Generations per Batch:', gen_per_batch - case (MODE_FIXEDSOURCE) - write(UNIT_SUMMARY,100) 'Problem type:', 'fixed source' - end select - write(UNIT_SUMMARY,101) 'Number of Particles:', n_particles - - ! Display geometry summary - call header("GEOMETRY SUMMARY", unit=UNIT_SUMMARY) - write(UNIT_SUMMARY,101) 'Number of Cells:', n_cells - write(UNIT_SUMMARY,101) 'Number of Surfaces:', n_surfaces - write(UNIT_SUMMARY,101) 'Number of Materials:', n_materials - - ! print summary of all geometry - call print_geometry() - - ! print summary of materials - call header("MATERIAL SUMMARY", unit=UNIT_SUMMARY) - do i = 1, n_materials - m => materials(i) - call print_material(m, unit=UNIT_SUMMARY) - end do - - ! print summary of tallies - if (n_tallies > 0) then - call header("TALLY SUMMARY", unit=UNIT_SUMMARY) - do i = 1, n_tallies - t=> tallies(i) - call print_tally(t, unit=UNIT_SUMMARY) - end do - end if - - ! print summary of variance reduction - call header("VARIANCE REDUCTION", unit=UNIT_SUMMARY) - if (survival_biasing) then - write(UNIT_SUMMARY,100) "Survival Biasing:", "on" - else - write(UNIT_SUMMARY,100) "Survival Biasing:", "off" - end if - write(UNIT_SUMMARY,100) "Weight Cutoff:", trim(to_str(weight_cutoff)) - write(UNIT_SUMMARY,100) "Survival weight:", trim(to_str(weight_survive)) - - ! Close summary file - close(UNIT_SUMMARY) - - ! Format descriptor for columns -100 format (1X,A,T35,A) -101 format (1X,A,T35,I11) - - end subroutine write_summary - !=============================================================================== ! WRITE_XS_SUMMARY writes information about each nuclide and S(a,b) table to a ! file called cross_sections.out. This file shows the list of reactions as well @@ -1304,7 +524,8 @@ contains subroutine write_xs_summary() - integer :: i ! loop index + integer :: i ! loop index + integer :: unit_xs ! cross_sections.out file unit character(MAX_FILE_LEN) :: path ! path of summary file type(Nuclide), pointer :: nuc => null() type(SAlphaBeta), pointer :: sab => null() @@ -1313,17 +534,17 @@ contains path = trim(path_output) // "cross_sections.out" ! Open log file for writing - open(UNIT=UNIT_XS, FILE=path, STATUS='replace', ACTION='write') + open(NEWUNIT=unit_xs, FILE=path, STATUS='replace', ACTION='write') ! Write header - call header("CROSS SECTION TABLES", unit=UNIT_XS) + call header("CROSS SECTION TABLES", unit=unit_xs) NUCLIDE_LOOP: do i = 1, n_nuclides_total ! Get pointer to nuclide nuc => nuclides(i) ! Print information about nuclide - call print_nuclide(nuc, unit=UNIT_XS) + call print_nuclide(nuc, unit=unit_xs) end do NUCLIDE_LOOP SAB_TABLES_LOOP: do i = 1, n_sab_tables @@ -1331,11 +552,11 @@ contains sab => sab_tables(i) ! Print information about S(a,b) table - call print_sab_table(sab, unit=UNIT_XS) + call print_sab_table(sab, unit=unit_xs) end do SAB_TABLES_LOOP ! Close cross section summary file - close(UNIT_XS) + close(unit_xs) end subroutine write_xs_summary @@ -1716,6 +937,7 @@ contains integer :: i_listing ! index in xs_listings array integer :: n_order ! loop index for moment orders integer :: nm_order ! loop index for Ynm moment orders + integer :: unit_tally ! tallies.out file unit real(8) :: t_value ! t-values for confidence intervals real(8) :: alpha ! significance level for CI character(MAX_FILE_LEN) :: filename ! name of output file @@ -1764,7 +986,7 @@ contains filename = trim(path_output) // "tallies.out" ! Open tally file for writing - open(FILE=filename, UNIT=UNIT_TALLY, STATUS='replace', ACTION='write') + open(FILE=filename, NEWUNIT=unit_tally, STATUS='replace', ACTION='write') ! Calculate t-value for confidence intervals if (confidence_intervals) then @@ -1788,16 +1010,16 @@ contains ! Write header block if (t % name == "") then - call header("TALLY " // trim(to_str(t % id)), unit=UNIT_TALLY, & + call header("TALLY " // trim(to_str(t % id)), unit=unit_tally, & level=3) else call header("TALLY " // trim(to_str(t % id)) // ": " & - // trim(t % name), unit=UNIT_TALLY, level=3) + // trim(t % name), unit=unit_tally, level=3) endif ! Handle surface current tallies separately if (t % type == TALLY_SURFACE_CURRENT) then - call write_surface_current(t) + call write_surface_current(t, unit_tally) cycle end if @@ -1840,7 +1062,7 @@ contains ! Print current filter information type = t % filters(j) % type - write(UNIT=UNIT_TALLY, FMT='(1X,2A,1X,A)') repeat(" ", indent), & + write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), & trim(filter_name(type)), trim(get_label(t, j)) indent = indent + 2 j = j + 1 @@ -1851,7 +1073,7 @@ contains ! Print filter information if (t % n_filters > 0) then type = t % filters(j) % type - write(UNIT=UNIT_TALLY, FMT='(1X,2A,1X,A)') repeat(" ", indent), & + write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), & trim(filter_name(type)), trim(get_label(t, j)) end if @@ -1872,11 +1094,11 @@ contains ! Write label for nuclide i_nuclide = t % nuclide_bins(n) if (i_nuclide == -1) then - write(UNIT=UNIT_TALLY, FMT='(1X,2A,1X,A)') repeat(" ", indent), & + write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), & "Total Material" else i_listing = nuclides(i_nuclide) % listing - write(UNIT=UNIT_TALLY, FMT='(1X,2A,1X,A)') repeat(" ", indent), & + write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), & trim(xs_listings(i_listing) % alias) end if @@ -1889,7 +1111,7 @@ contains case (SCORE_SCATTER_N, SCORE_NU_SCATTER_N) score_name = 'P' // trim(to_str(t % moment_order(k))) // " " // & score_names(abs(t % score_bins(k))) - write(UNIT=UNIT_TALLY, FMT='(1X,2A,1X,A,"+/- ",A)') & + write(UNIT=unit_tally, FMT='(1X,2A,1X,A,"+/- ",A)') & repeat(" ", indent), score_name, & to_str(t % results(score_index,filter_index) % sum), & trim(to_str(t % results(score_index,filter_index) % sum_sq)) @@ -1899,7 +1121,7 @@ contains score_index = score_index + 1 score_name = 'P' // trim(to_str(n_order)) // " " //& score_names(abs(t % score_bins(k))) - write(UNIT=UNIT_TALLY, FMT='(1X,2A,1X,A,"+/- ",A)') & + write(UNIT=unit_tally, FMT='(1X,2A,1X,A,"+/- ",A)') & repeat(" ", indent), score_name, & to_str(t % results(score_index,filter_index) % sum), & trim(to_str(t % results(score_index,filter_index) & @@ -1915,7 +1137,7 @@ contains score_name = 'Y' // trim(to_str(n_order)) // ',' // & trim(to_str(nm_order)) // " " & // score_names(abs(t % score_bins(k))) - write(UNIT=UNIT_TALLY, FMT='(1X,2A,1X,A,"+/- ",A)') & + write(UNIT=unit_tally, FMT='(1X,2A,1X,A,"+/- ",A)') & repeat(" ", indent), score_name, & to_str(t % results(score_index,filter_index) % sum), & trim(to_str(t % results(score_index,filter_index)& @@ -1929,7 +1151,7 @@ contains else score_name = score_names(abs(t % score_bins(k))) end if - write(UNIT=UNIT_TALLY, FMT='(1X,2A,1X,A,"+/- ",A)') & + write(UNIT=unit_tally, FMT='(1X,2A,1X,A,"+/- ",A)') & repeat(" ", indent), score_name, & to_str(t % results(score_index,filter_index) % sum), & trim(to_str(t % results(score_index,filter_index) % sum_sq)) @@ -1946,7 +1168,7 @@ contains end do TALLY_LOOP - close(UNIT=UNIT_TALLY) + close(UNIT=unit_tally) end subroutine write_tallies @@ -1955,9 +1177,9 @@ contains ! tallies.out file. !=============================================================================== - subroutine write_surface_current(t) - + subroutine write_surface_current(t, unit_tally) type(TallyObject), pointer :: t + integer, intent(in) :: unit_tally integer :: i ! mesh index for x integer :: j ! mesh index for y @@ -1972,7 +1194,7 @@ contains integer :: filter_index ! index in results array for filters logical :: print_ebin ! should incoming energy bin be displayed? character(MAX_LINE_LEN) :: string - type(StructuredMesh), pointer :: m => null() + type(RegularMesh), pointer :: m ! Get pointer to mesh i_filter_mesh = t % find_filter(FILTER_MESH) @@ -2001,7 +1223,7 @@ contains do k = 1, m % dimension(3) ! Write mesh cell index string = string(1:len2+1) // trim(to_str(k)) // ")" - write(UNIT=UNIT_TALLY, FMT='(1X,A)') trim(string) + write(UNIT=unit_tally, FMT='(1X,A)') trim(string) do l = 1, n if (print_ebin) then @@ -2009,7 +1231,7 @@ contains matching_bins(i_filter_ein) = l ! Write incoming energy bin - write(UNIT=UNIT_TALLY, FMT='(3X,A,1X,A)') & + write(UNIT=unit_tally, FMT='(3X,A,1X,A)') & "Incoming Energy", trim(get_label(t, i_filter_ein)) end if @@ -2018,14 +1240,14 @@ contains mesh_indices_to_bin(m, (/ i-1, j, k /) + 1, .true.) matching_bins(i_filter_surf) = IN_RIGHT filter_index = sum((matching_bins(1:t%n_filters) - 1) * t % stride) + 1 - write(UNIT=UNIT_TALLY, FMT='(5X,A,T35,A,"+/- ",A)') & + write(UNIT=unit_tally, FMT='(5X,A,T35,A,"+/- ",A)') & "Outgoing Current to Left", & to_str(t % results(1,filter_index) % sum), & trim(to_str(t % results(1,filter_index) % sum_sq)) matching_bins(i_filter_surf) = OUT_RIGHT filter_index = sum((matching_bins(1:t%n_filters) - 1) * t % stride) + 1 - write(UNIT=UNIT_TALLY, FMT='(5X,A,T35,A,"+/- ",A)') & + write(UNIT=unit_tally, FMT='(5X,A,T35,A,"+/- ",A)') & "Incoming Current from Left", & to_str(t % results(1,filter_index) % sum), & trim(to_str(t % results(1,filter_index) % sum_sq)) @@ -2035,14 +1257,14 @@ contains mesh_indices_to_bin(m, (/ i, j, k /) + 1, .true.) matching_bins(i_filter_surf) = IN_RIGHT filter_index = sum((matching_bins(1:t%n_filters) - 1) * t % stride) + 1 - write(UNIT=UNIT_TALLY, FMT='(5X,A,T35,A,"+/- ",A)') & + write(UNIT=unit_tally, FMT='(5X,A,T35,A,"+/- ",A)') & "Incoming Current from Right", & to_str(t % results(1,filter_index) % sum), & trim(to_str(t % results(1,filter_index) % sum_sq)) matching_bins(i_filter_surf) = OUT_RIGHT filter_index = sum((matching_bins(1:t%n_filters) - 1) * t % stride) + 1 - write(UNIT=UNIT_TALLY, FMT='(5X,A,T35,A,"+/- ",A)') & + write(UNIT=unit_tally, FMT='(5X,A,T35,A,"+/- ",A)') & "Outgoing Current to Right", & to_str(t % results(1,filter_index) % sum), & trim(to_str(t % results(1,filter_index) % sum_sq)) @@ -2052,14 +1274,14 @@ contains mesh_indices_to_bin(m, (/ i, j-1, k /) + 1, .true.) matching_bins(i_filter_surf) = IN_FRONT filter_index = sum((matching_bins(1:t%n_filters) - 1) * t % stride) + 1 - write(UNIT=UNIT_TALLY, FMT='(5X,A,T35,A,"+/- ",A)') & + write(UNIT=unit_tally, FMT='(5X,A,T35,A,"+/- ",A)') & "Outgoing Current to Back", & to_str(t % results(1,filter_index) % sum), & trim(to_str(t % results(1,filter_index) % sum_sq)) matching_bins(i_filter_surf) = OUT_FRONT filter_index = sum((matching_bins(1:t%n_filters) - 1) * t % stride) + 1 - write(UNIT=UNIT_TALLY, FMT='(5X,A,T35,A,"+/- ",A)') & + write(UNIT=unit_tally, FMT='(5X,A,T35,A,"+/- ",A)') & "Incoming Current from Back", & to_str(t % results(1,filter_index) % sum), & trim(to_str(t % results(1,filter_index) % sum_sq)) @@ -2069,14 +1291,14 @@ contains mesh_indices_to_bin(m, (/ i, j, k /) + 1, .true.) matching_bins(i_filter_surf) = IN_FRONT filter_index = sum((matching_bins(1:t%n_filters) - 1) * t % stride) + 1 - write(UNIT=UNIT_TALLY, FMT='(5X,A,T35,A,"+/- ",A)') & + write(UNIT=unit_tally, FMT='(5X,A,T35,A,"+/- ",A)') & "Incoming Current from Front", & to_str(t % results(1,filter_index) % sum), & trim(to_str(t % results(1,filter_index) % sum_sq)) matching_bins(i_filter_surf) = OUT_FRONT filter_index = sum((matching_bins(1:t%n_filters) - 1) * t % stride) + 1 - write(UNIT=UNIT_TALLY, FMT='(5X,A,T35,A,"+/- ",A)') & + write(UNIT=unit_tally, FMT='(5X,A,T35,A,"+/- ",A)') & "Outgoing Current to Front", & to_str(t % results(1,filter_index) % sum), & trim(to_str(t % results(1,filter_index) % sum_sq)) @@ -2086,14 +1308,14 @@ contains mesh_indices_to_bin(m, (/ i, j, k-1 /) + 1, .true.) matching_bins(i_filter_surf) = IN_TOP filter_index = sum((matching_bins(1:t%n_filters) - 1) * t % stride) + 1 - write(UNIT=UNIT_TALLY, FMT='(5X,A,T35,A,"+/- ",A)') & + write(UNIT=unit_tally, FMT='(5X,A,T35,A,"+/- ",A)') & "Outgoing Current to Bottom", & to_str(t % results(1,filter_index) % sum), & trim(to_str(t % results(1,filter_index) % sum_sq)) matching_bins(i_filter_surf) = OUT_TOP filter_index = sum((matching_bins(1:t%n_filters) - 1) * t % stride) + 1 - write(UNIT=UNIT_TALLY, FMT='(5X,A,T35,A,"+/- ",A)') & + write(UNIT=unit_tally, FMT='(5X,A,T35,A,"+/- ",A)') & "Incoming Current from Bottom", & to_str(t % results(1,filter_index) % sum), & trim(to_str(t % results(1,filter_index) % sum_sq)) @@ -2103,14 +1325,14 @@ contains mesh_indices_to_bin(m, (/ i, j, k /) + 1, .true.) matching_bins(i_filter_surf) = IN_TOP filter_index = sum((matching_bins(1:t%n_filters) - 1) * t % stride) + 1 - write(UNIT=UNIT_TALLY, FMT='(5X,A,T35,A,"+/- ",A)') & + write(UNIT=unit_tally, FMT='(5X,A,T35,A,"+/- ",A)') & "Incoming Current from Top", & to_str(t % results(1,filter_index) % sum), & trim(to_str(t % results(1,filter_index) % sum_sq)) matching_bins(i_filter_surf) = OUT_TOP filter_index = sum((matching_bins(1:t%n_filters) - 1) * t % stride) + 1 - write(UNIT=UNIT_TALLY, FMT='(5X,A,T35,A,"+/- ",A)') & + write(UNIT=unit_tally, FMT='(5X,A,T35,A,"+/- ",A)') & "Outgoing Current to Top", & to_str(t % results(1,filter_index) % sum), & trim(to_str(t % results(1,filter_index) % sum_sq)) @@ -2139,8 +1361,8 @@ contains integer, allocatable :: ijk(:) ! indices in mesh real(8) :: E0 ! lower bound for energy bin real(8) :: E1 ! upper bound for energy bin - type(StructuredMesh), pointer :: m => null() - type(Universe), pointer :: univ => null() + type(RegularMesh), pointer :: m + type(Universe), pointer :: univ bin = matching_bins(i_filter) diff --git a/src/output_interface.F90 b/src/output_interface.F90 deleted file mode 100644 index 05fcd0010..000000000 --- a/src/output_interface.F90 +++ /dev/null @@ -1,2165 +0,0 @@ -module output_interface - - use constants - use error, only: warning, fatal_error - use global - use tally_header, only: TallyResult - -#ifdef HDF5 - use hdf5_interface -#else -#ifdef MPI - use mpiio_interface -#endif -#endif - - implicit none - private - - type, public :: BinaryOutput - private - ! Compilation specific data -#ifdef HDF5 - integer(HID_T) :: hdf5_fh - integer(HID_T) :: hdf5_grp -#else - integer :: unit_fh -#ifdef MPIF08 - type(MPI_File) :: mpi_fh -#else - integer :: mpi_fh -#endif -#endif - logical :: serial ! Serial I/O when using MPI/PHDF5 - contains - generic, public :: write_data => write_double, & - write_double_1Darray, & - write_double_2Darray, & - write_double_3Darray, & - write_double_4Darray, & - write_integer, & - write_integer_1Darray, & - write_integer_2Darray, & - write_integer_3Darray, & - write_integer_4Darray, & - write_long, & - write_string - generic, public :: read_data => read_double, & - read_double_1Darray, & - read_double_2Darray, & - read_double_3Darray, & - read_double_4Darray, & - read_integer, & - read_integer_1Darray, & - read_integer_2Darray, & - read_integer_3Darray, & - read_integer_4Darray, & - read_long, & - read_string - procedure :: write_double => write_double - procedure :: write_double_1Darray => write_double_1Darray - procedure :: write_double_2Darray => write_double_2Darray - procedure :: write_double_3Darray => write_double_3Darray - procedure :: write_double_4Darray => write_double_4Darray - procedure :: write_integer => write_integer - procedure :: write_integer_1Darray => write_integer_1Darray - procedure :: write_integer_2Darray => write_integer_2Darray - procedure :: write_integer_3Darray => write_integer_3Darray - procedure :: write_integer_4Darray => write_integer_4Darray - procedure :: write_long => write_long - procedure :: write_string => write_string - procedure :: read_double => read_double - procedure :: read_double_1Darray => read_double_1Darray - procedure :: read_double_2Darray => read_double_2Darray - procedure :: read_double_3Darray => read_double_3Darray - procedure :: read_double_4Darray => read_double_4Darray - procedure :: read_integer => read_integer - procedure :: read_integer_1Darray => read_integer_1Darray - procedure :: read_integer_2Darray => read_integer_2Darray - procedure :: read_integer_3Darray => read_integer_3Darray - procedure :: read_integer_4Darray => read_integer_4Darray - procedure :: read_long => read_long - procedure :: read_string => read_string - procedure, public :: file_create => file_create - procedure, public :: file_open => file_open - procedure, public :: file_close => file_close - procedure, public :: write_tally_result => write_tally_result - procedure, public :: read_tally_result => read_tally_result - procedure, public :: write_source_bank => write_source_bank - procedure, public :: read_source_bank => read_source_bank -#ifdef HDF5 - procedure, public :: write_attribute_string => write_attribute_string - procedure, public :: open_group => open_group - procedure, public :: close_group => close_group -#endif - end type BinaryOutput - -contains - -!=============================================================================== -! FILE_CREATE creates a new file to write data to -!=============================================================================== - - subroutine file_create(self, filename, serial) - - character(*), intent(in) :: filename ! name of file to be created - logical, optional, intent(in) :: serial ! processor rank to write from - class(BinaryOutput) :: self - - ! Check for serial option - if (present(serial)) then - self % serial = serial - else - self % serial = .true. - end if - -#ifdef HDF5 -# ifdef MPI - if (self % serial) then - call hdf5_file_create(filename, self % hdf5_fh) - else - call hdf5_file_create_parallel(filename, self % hdf5_fh) - endif -# else - call hdf5_file_create(filename, self % hdf5_fh) -# endif -#elif MPI - if (self % serial) then - open(NEWUNIT=self % unit_fh, FILE=filename, ACTION="write", & - STATUS='replace', ACCESS='stream') - else - call mpi_create_file(filename, self % mpi_fh) - end if -#else - open(NEWUNIT=self % unit_fh, FILE=filename, ACTION="write", & - STATUS='replace', ACCESS='stream') -#endif - - end subroutine file_create - -!=============================================================================== -! FILE_OPEN opens an existing file for reading or read/writing -!=============================================================================== - - subroutine file_open(self, filename, mode, serial) - - character(*), intent(in) :: filename ! name of file to be opened - character(*), intent(in) :: mode ! file access mode - logical, optional, intent(in) :: serial ! processor rank to write from - class(BinaryOutput) :: self - - ! Check for serial option - if (present(serial)) then - self % serial = serial - else - self % serial = .true. - end if - -#ifdef HDF5 -# ifdef MPI - if (self % serial) then - call hdf5_file_open(filename, self % hdf5_fh, mode) - else - call hdf5_file_open_parallel(filename, self % hdf5_fh, mode) - endif -# else - call hdf5_file_open(filename, self % hdf5_fh, mode) -# endif -#elif MPI - if (self % serial) then - ! Check for read/write mode to open, default is read only - if (mode == 'w') then - open(NEWUNIT=self % unit_fh, FILE=filename, ACTION='write', & - STATUS='old', ACCESS='stream', POSITION='append') - else - open(NEWUNIT=self % unit_fh, FILE=filename, ACTION='read', & - STATUS='old', ACCESS='stream') - end if - else - call mpi_open_file(filename, self % mpi_fh, mode) - end if -#else - ! Check for read/write mode to open, default is read only - if (mode == 'w') then - open(NEWUNIT=self % unit_fh, FILE=filename, ACTION='write', & - STATUS='old', ACCESS='stream', POSITION='append') - else - open(NEWUNIT=self % unit_fh, FILE=filename, ACTION='read', & - STATUS='old', ACCESS='stream') - end if -#endif - - end subroutine file_open - -!=============================================================================== -! FILE_CLOSE closes a file -!=============================================================================== - - subroutine file_close(self) - - class(BinaryOutput) :: self - -#ifdef HDF5 -# ifdef MPI - call hdf5_file_close(self % hdf5_fh) -# else - call hdf5_file_close(self % hdf5_fh) -# endif -#elif MPI - if (self % serial) then - close(UNIT=self % unit_fh) - else - call mpi_close_file(self % mpi_fh) - end if -#else - close(UNIT=self % unit_fh) -#endif - - end subroutine file_close - -!=============================================================================== -! OPEN_GROUP call hdf5 routine to open a group within binary output context -!=============================================================================== - -#ifdef HDF5 - subroutine open_group(self, group) - - character(*), intent(in) :: group ! HDF5 group name - class(BinaryOutput) :: self - - call hdf5_open_group(self % hdf5_fh, group, self % hdf5_grp) - - end subroutine open_group -#endif - -!=============================================================================== -! CLOSE_GROUP call hdf5 routine to close a group within binary output context -!=============================================================================== - -#ifdef HDF5 - subroutine close_group(self) - - class(BinaryOutput) :: self - - call hdf5_close_group(self % hdf5_grp) - - end subroutine close_group -#endif - -!=============================================================================== -! WRITE_DOUBLE writes double precision scalar data -!=============================================================================== - - subroutine write_double(self, buffer, name, group, collect) - - real(8), intent(in) :: buffer ! data to write - character(*), intent(in) :: name ! name for data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_write_double(self % hdf5_grp, name_, buffer) - else - call hdf5_write_double_parallel(self % hdf5_grp, name_, buffer, collect_) - end if -# else - call hdf5_write_double(self % hdf5_grp, name_, buffer) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - write(self % unit_fh) buffer - else - call mpi_write_double(self % mpi_fh, buffer, collect_) - end if -#else - write(self % unit_fh) buffer -#endif - - end subroutine write_double - -!=============================================================================== -! READ_DOUBLE reads double precision scalar data -!=============================================================================== - - subroutine read_double(self, buffer, name, group, collect) - - real(8), intent(inout) :: buffer ! read data to here - character(*), intent(in) :: name ! name for data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_read_double(self % hdf5_grp, name_, buffer) - else - call hdf5_read_double_parallel(self % hdf5_grp, name_, buffer, collect_) - end if -# else - call hdf5_read_double(self % hdf5_grp, name_, buffer) -# endif - ! Check if HDf5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - read(self % unit_fh) buffer - else - call mpi_read_double(self % mpi_fh, buffer, collect_) - end if -#else - read(self % unit_fh) buffer -#endif - - end subroutine read_double - -!=============================================================================== -! WRITE_DOUBLE_1DARRAY writes double precision 1-D array data -!=============================================================================== - - subroutine write_double_1Darray(self, buffer, name, group, length, collect) - - integer, intent(in) :: length ! length of array to write - real(8), intent(in) :: buffer(:) ! data to write - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_write_double_1Darray(self % hdf5_grp, name_, buffer, length) - else - call hdf5_write_double_1Darray_parallel(self % hdf5_grp, name_, buffer, length, & - collect_) - end if -# else - call hdf5_write_double_1Darray(self % hdf5_grp, name_, buffer, length) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - write(self % unit_fh) buffer(1:length) - else - call mpi_write_double_1Darray(self % mpi_fh, buffer, length, collect_) - end if -#else - write(self % unit_fh) buffer(1:length) -#endif - - end subroutine write_double_1Darray - -!=============================================================================== -! READ_DOUBLE_1DARRAY reads double precision 1-D array data -!=============================================================================== - - subroutine read_double_1Darray(self, buffer, name, group, length, collect) - - integer, intent(in) :: length ! length of array to read - real(8), intent(inout) :: buffer(:) ! read data to here - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_read_double_1Darray(self % hdf5_grp, name_, buffer, length) - else - call hdf5_read_double_1Darray_parallel(self % hdf5_grp, name_, buffer, & - length, collect_) - end if -# else - call hdf5_read_double_1Darray(self % hdf5_grp, name_, buffer, length) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - read(self % unit_fh) buffer(1:length) - else - call mpi_read_double_1Darray(self % mpi_fh, buffer, length, collect_) - end if -#else - read(self % unit_fh) buffer(1:length) -#endif - - end subroutine read_double_1Darray - -!=============================================================================== -! WRITE_DOUBLE_2DARRAY writes double precision 2-D array data -!=============================================================================== - - subroutine write_double_2Darray(self, buffer, name, group, length, collect) - - integer, intent(in) :: length(2) ! dimension of array - real(8), intent(in) :: buffer(length(1),length(2)) ! the data - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_write_double_2Darray(self % hdf5_grp, name_, buffer, length) - else - call hdf5_write_double_2Darray_parallel(self % hdf5_grp, name_, buffer, length, & - collect_) - end if -# else - call hdf5_write_double_2Darray(self % hdf5_grp, name_, buffer, length) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - write(self % unit_fh) buffer(1:length(1),1:length(2)) - else - call mpi_write_double_2Darray(self % mpi_fh, buffer, length, collect_) - end if -#else - write(self % unit_fh) buffer(1:length(1),1:length(2)) -#endif - - end subroutine write_double_2Darray - -!=============================================================================== -! READ_DOUBLE_2DARRAY reads double precision 2-D array data -!=============================================================================== - - subroutine read_double_2Darray(self, buffer, name, group, length, collect) - - integer, intent(in) :: length(2) ! dimension of array - real(8), intent(inout) :: buffer(length(1),length(2)) ! the data - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_read_double_2Darray(self % hdf5_grp, name_, buffer, length) - else - call hdf5_read_double_2Darray_parallel(self % hdf5_grp, name_, buffer, length, & - collect_) - end if -# else - call hdf5_read_double_2Darray(self % hdf5_grp, name_, buffer, length) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - read(self % unit_fh) buffer(1:length(1),1:length(2)) - else - call mpi_read_double_2Darray(self % mpi_fh, buffer, length, collect_) - end if -#else - read(self % unit_fh) buffer(1:length(1),1:length(2)) -#endif - - end subroutine read_double_2Darray - -!=============================================================================== -! WRITE_DOUBLE_3DARRAY writes double precision 3-D array data -!=============================================================================== - - subroutine write_double_3Darray(self, buffer, name, group, length, collect) - - integer, intent(in) :: length(3) ! length of each dimension - real(8), intent(in) :: buffer(length(1),length(2),length(3)) - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_write_double_3Darray(self % hdf5_grp, name_, buffer, length) - else - call hdf5_write_double_3Darray_parallel(self % hdf5_grp, name_, buffer, & - length, collect_) - end if -# else - call hdf5_write_double_3Darray(self % hdf5_grp, name_, buffer, length) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - write(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3)) - else - call mpi_write_double_3Darray(self % mpi_fh, buffer, length, collect_) - end if -#else - write(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3)) -#endif - - end subroutine write_double_3Darray - -!=============================================================================== -! READ_DOUBLE_3DARRAY reads double precision 3-D array data -!=============================================================================== - - subroutine read_double_3Darray(self, buffer, name, group, length, collect) - - integer, intent(in) :: length(3) ! length of each dimension - real(8), intent(inout) :: buffer(length(1),length(2),length(3)) - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_read_double_3Darray(self % hdf5_grp, name_, buffer, length) - else - call hdf5_read_double_3Darray_parallel(self % hdf5_grp, name_, buffer, length, & - collect_) - end if -# else - call hdf5_read_double_3Darray(self % hdf5_grp, name_, buffer, length) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - read(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3)) - else - call mpi_read_double_3Darray(self % mpi_fh, buffer, length, collect_) - end if -#else - read(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3)) -#endif - - end subroutine read_double_3Darray - -!=============================================================================== -! WRITE_DOUBLE_4DARRAY writes double precision 4-D array data -!=============================================================================== - - subroutine write_double_4Darray(self, buffer, name, group, length, collect) - - integer, intent(in) :: length(4) ! length of each dimension - real(8), intent(in) :: buffer(length(1),length(2),& - length(3),length(4)) - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_write_double_4Darray(self % hdf5_grp, name_, buffer, length) - else - call hdf5_write_double_4Darray_parallel(self % hdf5_grp, name_, buffer, length, & - collect_) - end if -# else - ! Write the data in serial - call hdf5_write_double_4Darray(self % hdf5_grp, name_, buffer, length) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - write(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3), & - 1:length(4)) - else - call mpi_write_double_4Darray(self % mpi_fh, buffer, length, collect_) - end if -#else - write(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3), & - 1:length(4)) -#endif - - end subroutine write_double_4Darray - -!=============================================================================== -! READ_DOUBLE_4DARRAY reads double precision 4-D array data -!=============================================================================== - - subroutine read_double_4Darray(self, buffer, name, group, length, collect) - - integer, intent(in) :: length(4) ! length of each dimension - real(8), intent(inout) :: buffer(length(1),length(2),& - length(3),length(4)) - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_read_double_4Darray(self % hdf5_grp, name_, buffer, length) - else - call hdf5_read_double_4Darray_parallel(self % hdf5_grp, name_, buffer, length, & - collect_) - end if -# else - call hdf5_read_double_4Darray(self % hdf5_grp, name_, buffer, length) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - read(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3), & - 1:length(4)) - else - call mpi_read_double_4Darray(self % mpi_fh, buffer, length, collect_) - end if -#else - read(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3), & - 1:length(4)) -#endif - - end subroutine read_double_4Darray - -!=============================================================================== -! WRITE_INTEGER writes integer precision scalar data -!=============================================================================== - - subroutine write_integer(self, buffer, name, group, collect) - - integer, intent(in) :: buffer ! data to write - character(*), intent(in) :: name ! name for data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_write_integer(self % hdf5_grp, name_, buffer) - else - call hdf5_write_integer_parallel(self % hdf5_grp, name_, buffer, collect_) - end if -# else - call hdf5_write_integer(self % hdf5_grp, name_, buffer) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - write(self % unit_fh) buffer - else - call mpi_write_integer(self % mpi_fh, buffer, collect_) - end if -#else - write(self % unit_fh) buffer -#endif - - end subroutine write_integer - -!=============================================================================== -! READ_INTEGER reads integer precision scalar data -!=============================================================================== - - subroutine read_integer(self, buffer, name, group, collect) - - integer, intent(inout) :: buffer ! read data to here - character(*), intent(in) :: name ! name for data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_read_integer(self % hdf5_grp, name_, buffer) - else - call hdf5_read_integer_parallel(self % hdf5_grp, name_, buffer, collect_) - end if -# else - call hdf5_read_integer(self % hdf5_grp, name_, buffer) -# endif - ! Check if HDf5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - read(self % unit_fh) buffer - else - call mpi_read_integer(self % mpi_fh, buffer, collect_) - end if -#else - read(self % unit_fh) buffer -#endif - - end subroutine read_integer - -!=============================================================================== -! WRITE_INTEGER_1DARRAY writes integer precision 1-D array data -!=============================================================================== - - subroutine write_integer_1Darray(self, buffer, name, group, length, collect) - - integer, intent(in) :: length ! length of array to write - integer, intent(in) :: buffer(:) ! data to write - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_write_integer_1Darray(self % hdf5_grp, name_, buffer, length) - else - call hdf5_write_integer_1Darray_parallel(self % hdf5_grp, name_, buffer, length, & - collect_) - end if -# else - call hdf5_write_integer_1Darray(self % hdf5_grp, name_, buffer, length) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - write(self % unit_fh) buffer(1:length) - else - call mpi_write_integer_1Darray(self % mpi_fh, buffer, length, collect_) - end if -#else - write(self % unit_fh) buffer(1:length) -#endif - - end subroutine write_integer_1Darray - -!=============================================================================== -! READ_INTEGER_1DARRAY reads integer precision 1-D array data -!=============================================================================== - - subroutine read_integer_1Darray(self, buffer, name, group, length, collect) - - integer, intent(in) :: length ! length of array to read - integer, intent(inout) :: buffer(:) ! read data to here - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_read_integer_1Darray(self % hdf5_grp, name_, buffer, length) - else - call hdf5_read_integer_1Darray_parallel(self % hdf5_grp, name_, buffer, & - length, collect_) - end if -# else - ! Read the data in serial - call hdf5_read_integer_1Darray(self % hdf5_grp, name_, buffer, length) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - read(self % unit_fh) buffer(1:length) - else - call mpi_read_integer_1Darray(self % mpi_fh, buffer, length, collect_) - end if -#else - read(self % unit_fh) buffer(1:length) -#endif - - end subroutine read_integer_1Darray - -!=============================================================================== -! WRITE_INTEGER_2DARRAY writes integer precision 2-D array data -!=============================================================================== - - subroutine write_integer_2Darray(self, buffer, name, group, length, collect) - - integer, intent(in) :: length(2) ! dimension of array - integer, intent(in) :: buffer(length(1),length(2)) ! the data - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_write_integer_2Darray(self % hdf5_grp, name_, buffer, length) - else - call hdf5_write_integer_2Darray_parallel(self % hdf5_grp, name_, buffer, length, & - collect_) - end if -# else - call hdf5_write_integer_2Darray(self % hdf5_grp, name_, buffer, length) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - write(self % unit_fh) buffer(1:length(1),1:length(2)) - else - call mpi_write_integer_2Darray(self % mpi_fh, buffer, length, collect_) - end if -#else - write(self % unit_fh) buffer(1:length(1),1:length(2)) -#endif - - end subroutine write_integer_2Darray - -!=============================================================================== -! READ_INTEGER_2DARRAY reads integer precision 2-D array data -!=============================================================================== - - subroutine read_integer_2Darray(self, buffer, name, group, length, collect) - - integer, intent(in) :: length(2) ! dimension of array - integer, intent(inout) :: buffer(length(1),length(2)) ! the data - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_read_integer_2Darray(self % hdf5_grp, name_, buffer, length) - else - call hdf5_read_integer_2Darray_parallel(self % hdf5_grp, name_, buffer, length, & - collect_) - end if -# else - call hdf5_read_integer_2Darray(self % hdf5_grp, name_, buffer, length) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - read(self % unit_fh) buffer(1:length(1),1:length(2)) - else - call mpi_read_integer_2Darray(self % mpi_fh, buffer, length, collect_) - end if -#else - read(self % unit_fh) buffer(1:length(1),1:length(2)) -#endif - - end subroutine read_integer_2Darray - -!=============================================================================== -! WRITE_INTEGER_3DARRAY writes integer precision 3-D array data -!=============================================================================== - - subroutine write_integer_3Darray(self, buffer, name, group, length, collect) - - integer, intent(in) :: length(3) ! length of each dimension - integer, intent(in) :: buffer(length(1),length(2),length(3)) - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_write_integer_3Darray(self % hdf5_grp, name_, buffer, length) - else - call hdf5_write_integer_3Darray_parallel(self % hdf5_grp, name_, buffer, length, & - collect_) - end if -# else - call hdf5_write_integer_3Darray(self % hdf5_grp, name_, buffer, length) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - write(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3)) - else - call mpi_write_integer_3Darray(self % mpi_fh, buffer, length, collect_) - end if -#else - write(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3)) -#endif - - end subroutine write_integer_3Darray - -!=============================================================================== -! READ_INTEGER_3DARRAY reads integer precision 3-D array data -!=============================================================================== - - subroutine read_integer_3Darray(self, buffer, name, group, length, collect) - - integer, intent(in) :: length(3) ! length of each dimension - integer, intent(inout) :: buffer(length(1),length(2),length(3)) - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_read_integer_3Darray(self % hdf5_grp, name_, buffer, length) - else - call hdf5_read_integer_3Darray_parallel(self % hdf5_grp, name_, buffer, length, & - collect_) - end if -# else - call hdf5_read_integer_3Darray(self % hdf5_grp, name_, buffer, length) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - read(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3)) - else - call mpi_read_integer_3Darray(self % mpi_fh, buffer, length, collect_) - end if -#else - read(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3)) -#endif - - end subroutine read_integer_3Darray - -!=============================================================================== -! WRITE_INTEGER_4DARRAY writes integer precision 4-D array data -!=============================================================================== - - subroutine write_integer_4Darray(self, buffer, name, group, length, collect) - - integer, intent(in) :: length(4) ! length of each dimension - integer, intent(in) :: buffer(length(1),length(2),& - length(3),length(4)) - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_write_integer_4Darray(self % hdf5_grp, name_, buffer, length) - else - call hdf5_write_integer_4Darray_parallel(self % hdf5_grp, name_, buffer, length, & - collect_) - end if -# else - call hdf5_write_integer_4Darray(self % hdf5_grp, name_, buffer, length) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - write(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3), & - 1:length(4)) - else - call mpi_write_integer_4Darray(self % mpi_fh, buffer, length, collect_) - end if -#else - write(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3), & - 1:length(4)) -#endif - - end subroutine write_integer_4Darray - -!=============================================================================== -! READ_INTEGER_4DARRAY reads integer precision 4-D array data -!=============================================================================== - - subroutine read_integer_4Darray(self, buffer, name, group, length, collect) - - integer, intent(in) :: length(4) ! length of each dimension - integer, intent(inout) :: buffer(length(1),length(2),& - length(3),length(4)) - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_read_integer_4Darray(self % hdf5_grp, name_, buffer, length) - else - call hdf5_read_integer_4Darray_parallel(self % hdf5_grp, name_, buffer, length, & - collect_) - end if -# else - call hdf5_read_integer_4Darray(self % hdf5_grp, name_, buffer, length) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - read(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3), & - 1:length(4)) - else - call mpi_read_integer_4Darray(self % mpi_fh, buffer, length, collect_) - end if -#else - read(self % unit_fh) buffer(1:length(1),1:length(2),1:length(3), & - 1:length(4)) -#endif - - end subroutine read_integer_4Darray - -!=============================================================================== -! WRITE_LONG writes long integer scalar data -!=============================================================================== - - subroutine write_long(self, buffer, name, group, collect) - - integer(8), intent(in) :: buffer ! data to write - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_write_long(self % hdf5_grp, name_, buffer, hdf5_integer8_t) - else - call hdf5_write_long_parallel(self % hdf5_grp, name_, buffer, & - hdf5_integer8_t, collect_) - end if -# else - call hdf5_write_long(self % hdf5_grp, name_, buffer, hdf5_integer8_t) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - write(self % unit_fh) buffer - else - call mpi_write_long(self % mpi_fh, buffer, collect_) - end if -#else - write(self % unit_fh) buffer -#endif - - end subroutine write_long - -!=============================================================================== -! READ_LONG reads long integer scalar data -!=============================================================================== - - subroutine read_long(self, buffer, name, group, collect) - - integer(8), intent(inout) :: buffer ! data to write - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - logical :: collect_ - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_read_long(self % hdf5_grp, name_, buffer, hdf5_integer8_t) - else - call hdf5_read_long_parallel(self % hdf5_grp, name_, buffer, & - hdf5_integer8_t, collect_) - end if -# else - call hdf5_read_long(self % hdf5_grp, name_, buffer, hdf5_integer8_t) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - read(self % unit_fh) buffer - else - call mpi_read_long(self % mpi_fh, buffer, collect_) - end if -#else - read(self % unit_fh) buffer -#endif - - end subroutine read_long - -!=============================================================================== -! WRITE_STRING writes string data -!=============================================================================== - - subroutine write_string(self, buffer, name, group, collect) - - character(*), intent(in) :: buffer ! data to write - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - integer :: n - logical :: collect_ - - ! Get string length - n = len_trim(buffer) - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_write_string(self % hdf5_grp, name_, buffer, n) - else - call hdf5_write_string_parallel(self % hdf5_grp, name_, buffer, n, collect_) - end if -# else - ! Write the data - call hdf5_write_string(self % hdf5_grp, name_, buffer, n) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - write(self % unit_fh) buffer - else - call mpi_write_string(self % mpi_fh, buffer, n, collect_) - end if -#else - write(self % unit_fh) buffer -#endif - - end subroutine write_string - -!=============================================================================== -! READ_STRING reads string data -!=============================================================================== - - subroutine read_string(self, buffer, name, group, collect) - - character(*), intent(inout) :: buffer ! data to write - character(*), intent(in) :: name ! name of data - character(*), intent(in), optional :: group ! HDF5 group name - logical, intent(in), optional :: collect ! collective I/O - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - integer :: n - logical :: collect_ - - ! Get string length - n = len(buffer) - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - - ! Set up collective vs. independent I/O - if (present(collect)) then - collect_ = collect - else - collect_ = .true. - end if - - -#ifdef HDF5 - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif -# ifdef MPI - if (self % serial) then - call hdf5_read_string(self % hdf5_grp, name_, buffer, n) - else - call hdf5_read_string_parallel(self % hdf5_grp, name_, buffer, n, collect_) - end if -# else - call hdf5_read_string(self % hdf5_grp, name_, buffer, n) -# endif - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) -#elif MPI - if (self % serial) then - read(self % unit_fh) buffer - else - call mpi_read_string(self % mpi_fh, buffer, n, collect_) - end if -#else - read(self % unit_fh) buffer -#endif - - end subroutine read_string - -!=============================================================================== -! WRITE_ATTRIBUTE_STRING -!=============================================================================== - -#ifdef HDF5 - subroutine write_attribute_string(self, var, attr_type, attr_str, group) - - character(*), intent(in) :: var ! variable name for attr - character(*), intent(in) :: attr_type ! attr identifier type - character(*), intent(in) :: attr_str ! string for attr id type - character(*), intent(in), optional :: group ! HDF5 group name - class(BinaryOutput) :: self - - ! Check if HDF5 group should be created/opened - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - endif - - ! Write the attribute string - call hdf5_write_attribute_string(self % hdf5_grp, var, attr_type, attr_str) - - ! Check if HDF5 group should be closed - if (present(group)) call hdf5_close_group(self % hdf5_grp) - - end subroutine write_attribute_string -#endif - -!=============================================================================== -! WRITE_TALLY_RESULT writes an OpenMC TallyResult type -!=============================================================================== - - subroutine write_tally_result(self, buffer, name, group, n1, n2) - - character(*), intent(in), optional :: group ! HDF5 group name - character(*), intent(in) :: name ! name of data - integer, intent(in) :: n1, n2 ! TallyResult dims - type(TallyResult), intent(in), target :: buffer(n1, n2) ! data to write - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - -#ifndef HDF5 - integer :: j,k ! iteration counters -#endif - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - -#ifdef HDF5 - - ! Open up sub-group if present - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - end if - - ! Set overall size of vector to write - dims1(1) = n1*n2 - - ! Create up a dataspace for size - call h5screate_simple_f(1, dims1, dspace, hdf5_err) - - ! Create the dataset - call h5dcreate_f(self % hdf5_grp, name_, hdf5_tallyresult_t, dspace, dset, & - hdf5_err) - - ! Set pointer to first value and write - f_ptr = c_loc(buffer(1,1)) - call h5dwrite_f(dset, hdf5_tallyresult_t, f_ptr, hdf5_err) - - ! Close ids - call h5dclose_f(dset, hdf5_err) - call h5sclose_f(dspace, hdf5_err) - if (present(group)) then - call hdf5_close_group(self % hdf5_grp) - end if - -#else - - ! Write out tally buffer - do k = 1, n2 - do j = 1, n1 - write(self % unit_fh) buffer(j,k) % sum - write(self % unit_fh) buffer(j,k) % sum_sq - end do - end do - -#endif - - end subroutine write_tally_result - -!=============================================================================== -! READ_TALLY_RESULT reads OpenMC TallyResult data -!=============================================================================== - - subroutine read_tally_result(self, buffer, name, group, n1, n2) - - character(*), intent(in), optional :: group ! HDF5 group name - character(*), intent(in) :: name ! name of data - integer, intent(in) :: n1, n2 ! TallyResult dims - type(TallyResult), intent(inout), target :: buffer(n1, n2) ! read data here - class(BinaryOutput) :: self - - character(len=MAX_WORD_LEN) :: name_ ! HDF5 dataset name - character(len=MAX_WORD_LEN) :: group_ ! HDF5 group name - -#ifndef HDF5 -# ifndef MPI - integer :: j,k ! iteration counters -# endif -#endif - - ! Set name - name_ = trim(name) - - ! Set group - if (present(group)) then - group_ = trim(group) - end if - -#ifdef HDF5 - - ! Open up sub-group if present - if (present(group)) then - call hdf5_open_group(self % hdf5_fh, group_, self % hdf5_grp) - else - self % hdf5_grp = self % hdf5_fh - end if - - ! Open the dataset - call h5dopen_f(self % hdf5_grp, name, dset, hdf5_err) - - ! Set pointer to first value and write - f_ptr = c_loc(buffer(1,1)) - call h5dread_f(dset, hdf5_tallyresult_t, f_ptr, hdf5_err) - - ! Close ids - call h5dclose_f(dset, hdf5_err) - if (present(group)) call hdf5_close_group(self % hdf5_grp) - -# elif MPI - - ! Write out tally buffer - call MPI_FILE_READ(self % mpi_fh, buffer, n1*n2, MPI_TALLYRESULT, & - MPI_STATUS_IGNORE, mpiio_err) - -#else - - ! Read tally result - do k = 1, n2 - do j = 1, n1 - read(self % unit_fh) buffer(j,k) % sum - read(self % unit_fh) buffer(j,k) % sum_sq - end do - end do - -#endif - - end subroutine read_tally_result - -!=============================================================================== -! WRITE_SOURCE_BANK writes OpenMC source_bank data -!=============================================================================== - - subroutine write_source_bank(self) - - class(BinaryOutput) :: self - -#ifdef MPI -# ifndef HDF5 - integer(MPI_OFFSET_KIND) :: offset ! offset of data - integer :: size_bank ! size of bank to write -#ifdef MPIF08 - type(MPI_Datatype) :: datatype -#else - integer :: datatype -#endif -# endif -# ifdef HDF5 - integer(8) :: offset(1) ! source data offset -# endif -#endif - -#ifdef HDF5 -#ifdef MPI - - ! Set size of total dataspace for all procs and rank - dims1(1) = n_particles - hdf5_rank = 1 - - ! Create that dataspace - call h5screate_simple_f(hdf5_rank, dims1, dspace, hdf5_err) - - ! Create the dataset for that dataspace - call h5dcreate_f(self % hdf5_fh, "source_bank", hdf5_bank_t, dspace, dset, hdf5_err) - - ! Close the dataspace - call h5sclose_f(dspace, hdf5_err) - - ! Create another data space but for each proc individually - dims1(1) = work - call h5screate_simple_f(hdf5_rank, dims1, memspace, hdf5_err) - - ! Get the individual local proc dataspace - call h5dget_space_f(dset, dspace, hdf5_err) - - ! Select hyperslab for this dataspace - offset(1) = work_index(rank) - call h5sselect_hyperslab_f(dspace, H5S_SELECT_SET_F, offset, dims1, hdf5_err) - - ! Set up the property list for parallel writing - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - - ! Set up pointer to data - f_ptr = c_loc(source_bank(1)) - - ! Write data to file in parallel - call h5dwrite_f(dset, hdf5_bank_t, f_ptr, hdf5_err, & - file_space_id = dspace, mem_space_id = memspace, & - xfer_prp = plist) - - ! Close all ids - call h5sclose_f(dspace, hdf5_err) - call h5sclose_f(memspace, hdf5_err) - call h5dclose_f(dset, hdf5_err) - call h5pclose_f(plist, hdf5_err) - -# else - - ! Set size - dims1(1) = work - hdf5_rank = 1 - - ! Create dataspace - call h5screate_simple_f(hdf5_rank, dims1, dspace, hdf5_err) - - ! Create dataset - call h5dcreate_f(self % hdf5_fh, "source_bank", hdf5_bank_t, & - dspace, dset, hdf5_err) - - ! Set up pointer to data - f_ptr = c_loc(source_bank(1)) - - ! Write dataset to file - call h5dwrite_f(dset, hdf5_bank_t, f_ptr, hdf5_err) - - ! Close all ids - call h5dclose_f(dset, hdf5_err) - call h5sclose_f(dspace, hdf5_err) - -# endif - -#elif MPI - - ! Get current offset for master - if (master) call MPI_FILE_GET_POSITION(self % mpi_fh, offset, mpiio_err) - - ! Determine offset on master process and broadcast to all processors - call MPI_TYPE_MATCH_SIZE(MPI_TYPECLASS_INTEGER, MPI_OFFSET_KIND, & - datatype, mpi_err) - call MPI_BCAST(offset, 1, datatype, 0, MPI_COMM_WORLD, mpi_err) - - ! Set the proper offset for source data on this processor - call MPI_TYPE_SIZE(MPI_BANK, size_bank, mpi_err) - offset = offset + size_bank*work_index(rank) - - ! Write all source sites - call MPI_FILE_WRITE_AT(self % mpi_fh, offset, source_bank(1), int(work), & - MPI_BANK, MPI_STATUS_IGNORE, mpiio_err) - -#else - - ! Write out source sites - write(self % unit_fh) source_bank - -#endif - - end subroutine write_source_bank - -!=============================================================================== -! READ_SOURCE_BANK reads OpenMC source_bank data -!=============================================================================== - - subroutine read_source_bank(self) - - class(BinaryOutput) :: self - -#ifdef MPI -# ifndef HDF5 - integer(MPI_OFFSET_KIND) :: offset ! offset of data - integer :: size_bank ! size of bank to read -# endif -# ifdef HDF5 - integer(8) :: offset(1) ! offset of data -# endif -#endif - -#ifdef HDF5 -# ifdef MPI - - ! Set size of total dataspace for all procs and rank - dims1(1) = n_particles - hdf5_rank = 1 - - ! Open the dataset - call h5dopen_f(self % hdf5_fh, "source_bank", dset, hdf5_err) - - ! Create another data space but for each proc individually - dims1(1) = work - call h5screate_simple_f(hdf5_rank, dims1, memspace, hdf5_err) - - ! Get the individual local proc dataspace - call h5dget_space_f(dset, dspace, hdf5_err) - - ! Select hyperslab for this dataspace - offset(1) = work_index(rank) - call h5sselect_hyperslab_f(dspace, H5S_SELECT_SET_F, offset, dims1, hdf5_err) - - ! Set up the property list for parallel writing - call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) - call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) - - ! Set up pointer to data - f_ptr = c_loc(source_bank(1)) - - ! Read data from file in parallel - call h5dread_f(dset, hdf5_bank_t, f_ptr, hdf5_err, & - file_space_id = dspace, mem_space_id = memspace, & - xfer_prp = plist) - - ! Close all ids - call h5sclose_f(dspace, hdf5_err) - call h5sclose_f(memspace, hdf5_err) - call h5dclose_f(dset, hdf5_err) - call h5pclose_f(plist, hdf5_err) - -# else - - ! Open dataset - call h5dopen_f(self % hdf5_fh, "source_bank", dset, hdf5_err) - - ! Set up pointer to data - f_ptr = c_loc(source_bank(1)) - - ! Read dataset from file - call h5dread_f(dset, hdf5_bank_t, f_ptr, hdf5_err) - - ! Close all ids - call h5dclose_f(dset, hdf5_err) - -# endif - -#elif MPI - - ! Go to the end of the file to set file pointer - offset = 0 - call MPI_FILE_SEEK(self % mpi_fh, offset, MPI_SEEK_END, & - mpiio_err) - - ! Get current offset (will be at EOF) - call MPI_FILE_GET_POSITION(self % mpi_fh, offset, mpiio_err) - - ! Get the size of the source bank on all procs - call MPI_TYPE_SIZE(MPI_BANK, size_bank, mpi_err) - - ! Calculate offset where the source bank will begin - offset = offset - n_particles*size_bank - - ! Set the proper offset for source data on this processor - offset = offset + size_bank*work_index(rank) - - ! Write all source sites - call MPI_FILE_READ_AT(self % mpi_fh, offset, source_bank(1), int(work), & - MPI_BANK, MPI_STATUS_IGNORE, mpiio_err) - -#else - - ! Write out source sites - read(self % unit_fh) source_bank - -#endif - - end subroutine read_source_bank - -end module output_interface diff --git a/src/particle_restart.F90 b/src/particle_restart.F90 index 0ed25fdc8..2e0523d48 100644 --- a/src/particle_restart.F90 +++ b/src/particle_restart.F90 @@ -6,18 +6,18 @@ module particle_restart use constants use geometry_header, only: BASE_UNIVERSE use global + use hdf5_interface, only: file_open, file_close, read_dataset use output, only: write_message, print_particle - use output_interface, only: BinaryOutput use particle_header, only: Particle use random_lcg, only: set_particle_seed use tracking, only: transport + use hdf5, only: HID_T + implicit none private public :: run_particle_restart - type(BinaryOutput) :: pr ! Binary file - contains !=============================================================================== @@ -34,7 +34,7 @@ contains verbosity = 10 ! Initialize the particle to be tracked - call p % initialize() + call p%initialize() ! Read in the restart information call read_particle_restart(p, previous_run_mode) @@ -46,9 +46,9 @@ contains select case (previous_run_mode) case (MODE_EIGENVALUE) particle_seed = ((current_batch - 1)*gen_per_batch + & - current_gen - 1)*n_particles + p % id + current_gen - 1)*n_particles + p%id case (MODE_FIXEDSOURCE) - particle_seed = p % id + particle_seed = p%id end select call set_particle_seed(particle_seed) @@ -66,40 +66,48 @@ contains !=============================================================================== subroutine read_particle_restart(p, previous_run_mode) + type(Particle), intent(inout) :: p + integer, intent(inout) :: previous_run_mode integer :: int_scalar - integer, intent(inout) :: previous_run_mode - type(Particle), intent(inout) :: p + integer(HID_T) :: file_id + character(MAX_WORD_LEN) :: mode ! Write meessage call write_message("Loading particle restart file " & &// trim(path_particle_restart) // "...", 1) ! Open file - call pr % file_open(path_particle_restart, 'r') + file_id = file_open(path_particle_restart, 'r') ! Read data from file - call pr % read_data(int_scalar, 'filetype') - call pr % read_data(int_scalar, 'revision') - call pr % read_data(current_batch, 'current_batch') - call pr % read_data(gen_per_batch, 'gen_per_batch') - call pr % read_data(current_gen, 'current_gen') - call pr % read_data(n_particles, 'n_particles') - call pr % read_data(previous_run_mode, 'run_mode') - call pr % read_data(p % id, 'id') - call pr % read_data(p % wgt, 'weight') - call pr % read_data(p % E, 'energy') - call pr % read_data(p % coord(1) % xyz, 'xyz', length=3) - call pr % read_data(p % coord(1) % uvw, 'uvw', length=3) + call read_dataset(file_id, 'filetype', int_scalar) + call read_dataset(file_id, 'revision', int_scalar) + call read_dataset(file_id, 'current_batch', current_batch) + call read_dataset(file_id, 'gen_per_batch', gen_per_batch) + call read_dataset(file_id, 'current_gen', current_gen) + call read_dataset(file_id, 'n_particles', n_particles) + call read_dataset(file_id, 'run_mode', mode) + select case (mode) + case ('k-eigenvalue') + previous_run_mode = MODE_EIGENVALUE + case ('fixed source') + previous_run_mode = MODE_FIXEDSOURCE + end select + call read_dataset(file_id, 'id', p%id) + call read_dataset(file_id, 'weight', p%wgt) + call read_dataset(file_id, 'energy', p%E) + call read_dataset(file_id, 'xyz', p%coord(1)%xyz) + call read_dataset(file_id, 'uvw', p%coord(1)%uvw) ! Set particle last attributes - p % last_wgt = p % wgt - p % last_xyz = p % coord(1) % xyz - p % last_uvw = p % coord(1) % uvw - p % last_E = p % E + p%last_wgt = p%wgt + p%last_xyz = p%coord(1)%xyz + p%last_uvw = p%coord(1)%uvw + p%last_E = p%E ! Close hdf5 file - call pr % file_close() + call file_close(file_id) end subroutine read_particle_restart diff --git a/src/particle_restart_write.F90 b/src/particle_restart_write.F90 index f138a6740..edd779df0 100644 --- a/src/particle_restart_write.F90 +++ b/src/particle_restart_write.F90 @@ -2,17 +2,16 @@ module particle_restart_write use bank_header, only: Bank use global - use output_interface, only: BinaryOutput + use hdf5_interface use particle_header, only: Particle use string, only: to_str + use hdf5 + implicit none private public :: write_particle_restart - ! Binary output file - type(BinaryOutput) :: pr - contains !=============================================================================== @@ -20,47 +19,49 @@ contains !=============================================================================== subroutine write_particle_restart(p) - type(Particle), intent(in) :: p + integer(HID_T) :: file_id character(MAX_FILE_LEN) :: filename - type(Bank), pointer :: src => null() + type(Bank), pointer :: src ! Dont write another restart file if in particle restart mode if (run_mode == MODE_PARTICLE) return ! Set up file name filename = trim(path_output) // 'particle_' // trim(to_str(current_batch)) & - // '_' // trim(to_str(p % id)) -#ifdef HDF5 - filename = trim(filename) // '.h5' -#else - filename = trim(filename) // '.binary' -#endif + // '_' // trim(to_str(p%id)) // '.h5' !$omp critical (WriteParticleRestart) ! Create file - call pr % file_create(filename) + file_id = file_create(filename) ! Get information about source particle src => source_bank(current_work) ! Write data to file - call pr % write_data(FILETYPE_PARTICLE_RESTART, 'filetype') - call pr % write_data(REVISION_PARTICLE_RESTART, 'revision') - call pr % write_data(current_batch, 'current_batch') - call pr % write_data(gen_per_batch, 'gen_per_batch') - call pr % write_data(current_gen, 'current_gen') - call pr % write_data(n_particles, 'n_particles') - call pr % write_data(run_mode, 'run_mode') - call pr % write_data(p % id, 'id') - call pr % write_data(src % wgt, 'weight') - call pr % write_data(src % E, 'energy') - call pr % write_data(src % xyz, 'xyz', length = 3) - call pr % write_data(src % uvw, 'uvw', length = 3) + call write_dataset(file_id, 'filetype', 'particle restart') + call write_dataset(file_id, 'revision', REVISION_PARTICLE_RESTART) + call write_dataset(file_id, 'current_batch', current_batch) + call write_dataset(file_id, 'gen_per_batch', gen_per_batch) + call write_dataset(file_id, 'current_gen', current_gen) + call write_dataset(file_id, 'n_particles', n_particles) + select case(run_mode) + case (MODE_FIXEDSOURCE) + call write_dataset(file_id, 'run_mode', 'fixed source') + case (MODE_EIGENVALUE) + call write_dataset(file_id, 'run_mode', 'k-eigenvalue') + case (MODE_PARTICLE) + call write_dataset(file_id, 'run_mode', 'particle restart') + end select + call write_dataset(file_id, 'id', p%id) + call write_dataset(file_id, 'weight', src%wgt) + call write_dataset(file_id, 'energy', src%E) + call write_dataset(file_id, 'xyz', src%xyz) + call write_dataset(file_id, 'uvw', src%uvw) ! Close file - call pr % file_close() + call file_close(file_id) !$omp end critical (WriteParticleRestart) end subroutine write_particle_restart diff --git a/src/plot.F90 b/src/plot.F90 index e507b6093..a5497bc20 100644 --- a/src/plot.F90 +++ b/src/plot.F90 @@ -5,7 +5,9 @@ module plot use geometry, only: find_cell, check_cell_overlap use geometry_header, only: Cell, BASE_UNIVERSE use global + use hdf5_interface use mesh, only: get_mesh_indices + use mesh_header, only: RegularMesh use output, only: write_message use particle_header, only: Particle, LocalCoord use plot_header @@ -14,6 +16,8 @@ module plot use progress_header, only: ProgressBar use string, only: to_str + use hdf5 + implicit none contains @@ -212,7 +216,7 @@ contains real(8) :: xyz_ur_plot(3) ! upper right xyz of plot image real(8) :: xyz_ll(3) ! lower left xyz real(8) :: xyz_ur(3) ! upper right xyz - type(StructuredMesh), pointer :: m => null() + type(RegularMesh), pointer :: m m => pl % meshlines_mesh @@ -305,25 +309,26 @@ contains integer :: i ! loop index for height integer :: j ! loop index for width + integer :: unit_plot ! Open PPM file for writing - open(UNIT=UNIT_PLOT, FILE=pl % path_plot) + open(NEWUNIT=unit_plot, FILE=pl % path_plot) ! Write header - write(UNIT_PLOT, '(A2)') 'P6' - write(UNIT_PLOT, '(I0,'' '',I0)') img%width, img%height - write(UNIT_PLOT, '(A)') '255' + write(unit_plot, '(A2)') 'P6' + write(unit_plot, '(I0,'' '',I0)') img%width, img%height + write(unit_plot, '(A)') '255' ! Write color for each pixel do j = 1, img % height do i = 1, img % width - write(UNIT_PLOT, '(3A1)', advance='no') achar(img%red(i,j)), & + write(unit_plot, '(3A1)', advance='no') achar(img%red(i,j)), & achar(img%green(i,j)), achar(img%blue(i,j)) end do end do ! Close plot file - close(UNIT=UNIT_PLOT) + close(UNIT=unit_plot) end subroutine output_ppm @@ -346,10 +351,20 @@ contains integer :: x, y, z ! voxel location indices integer :: rgb(3) ! colors (red, green, blue) from 0-255 integer :: id ! id of cell or material + integer :: hdf5_err + integer, target :: data(pl%pixels(3),pl%pixels(2)) + integer(HID_T) :: file_id + integer(HID_T) :: dspace + integeR(HID_T) :: memspace + integer(HID_T) :: dset + integer(HSIZE_T) :: dims(3) + integer(HSIZE_T) :: dims_slab(3) + integer(HSIZE_T) :: offset(3) real(8) :: vox(3) ! x, y, and z voxel widths real(8) :: ll(3) ! lower left starting point for each sweep direction type(Particle) :: p type(ProgressBar) :: progress + type(c_ptr) :: f_ptr ! compute voxel widths in each direction vox = pl % width/dble(pl % pixels) @@ -364,11 +379,30 @@ contains p % coord(1) % universe = BASE_UNIVERSE ! Open binary plot file for writing - open(UNIT=UNIT_PLOT, FILE=pl % path_plot, STATUS='replace', & - ACCESS='stream') + file_id = file_create(pl%path_plot) ! write plot header info - write(UNIT_PLOT) pl % pixels, vox, ll + call write_dataset(file_id, "filetype", 'voxel') + call write_dataset(file_id, "num_voxels", pl%pixels) + call write_dataset(file_id, "voxel_width", vox) + call write_dataset(file_id, "lower_left", ll) + + ! Create dataset for voxel data -- note that the dimensions are reversed + ! since we want the order in the file to be z, y, x + dims(:) = [pl%pixels(3), pl%pixels(2), pl%pixels(1)] + call h5screate_simple_f(3, dims, dspace, hdf5_err) + call h5dcreate_f(file_id, "data", H5T_NATIVE_INTEGER, dspace, dset, hdf5_err) + + ! Create another dataspace for 2D array in memory + dims_slab(1) = pl%pixels(3) + dims_slab(2) = pl%pixels(2) + dims_slab(3) = 1 + call h5screate_simple_f(2, dims_slab(1:2), memspace, hdf5_err) + + ! Initialize offset and get pointer to data + offset(:) = 0 + call h5sselect_hyperslab_f(dspace, H5S_SELECT_SET_F, offset, dims_slab, hdf5_err) + f_ptr = c_loc(data) ! move to center of voxels ll = ll + vox / TWO @@ -377,22 +411,19 @@ contains call progress % set_value(dble(x)/dble(pl % pixels(1))*100) do y = 1, pl % pixels(2) do z = 1, pl % pixels(3) - ! get voxel color call position_rgb(p, pl, rgb, id) ! write to plot file - write(UNIT_PLOT) id + data(z,y) = id ! advance particle in z direction p % coord(1) % xyz(3) = p % coord(1) % xyz(3) + vox(3) - end do ! advance particle in y direction p % coord(1) % xyz(2) = p % coord(1) % xyz(2) + vox(2) p % coord(1) % xyz(3) = ll(3) - end do ! advance particle in y direction @@ -400,9 +431,17 @@ contains p % coord(1) % xyz(2) = ll(2) p % coord(1) % xyz(3) = ll(3) + ! Write to HDF5 dataset + offset(3) = x - 1 + call h5soffset_simple_f(dspace, offset, hdf5_err) + call h5dwrite_f(dset, H5T_NATIVE_INTEGER, f_ptr, hdf5_err, & + mem_space_id=memspace, file_space_id=dspace) end do - close(UNIT_PLOT) + call h5dclose_f(dset, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + call h5sclose_f(memspace, hdf5_err) + call file_close(file_id) end subroutine create_3d_dump diff --git a/src/plot_header.F90 b/src/plot_header.F90 index 8dc725d9d..a6ea9a580 100644 --- a/src/plot_header.F90 +++ b/src/plot_header.F90 @@ -1,7 +1,7 @@ module plot_header use constants - use mesh_header, only: StructuredMesh + use mesh_header, only: RegularMesh implicit none @@ -28,7 +28,7 @@ module plot_header integer :: pixels(3) ! pixel width/height of plot slice integer :: meshlines_width ! pixel width of meshlines integer :: level ! universe depth to plot the cells of - type(StructuredMesh), pointer :: meshlines_mesh => null() ! mesh to plot + type(RegularMesh), pointer :: meshlines_mesh => null() ! mesh to plot type(ObjectColor) :: meshlines_color ! Color for meshlines type(ObjectColor) :: not_found ! color for positions where no cell found type(ObjectColor), allocatable :: colors(:) ! colors of cells/mats diff --git a/src/relaxng/geometry.rnc b/src/relaxng/geometry.rnc index cebbc5b6a..82f1f15b3 100644 --- a/src/relaxng/geometry.rnc +++ b/src/relaxng/geometry.rnc @@ -6,7 +6,7 @@ element geometry { (element universe { xsd:int } | attribute universe { xsd:int })? & ( (element fill { xsd:int } | attribute fill { xsd:int }) | - (element material { ( xsd:int | "void" ) } | + (element material { ( xsd:int | "void" ) } | attribute material { ( xsd:int | "void" ) }) ) & (element surfaces { list { xsd:int* } } | attribute surfaces { list { xsd:int* } })? & @@ -18,7 +18,7 @@ element geometry { (element id { xsd:int } | attribute id { xsd:int }) & (element name { xsd:string { maxLength="52" } } | attribute name { xsd:string { maxLength="52" } })? & - (element type { xsd:string { maxLength = "15" } } | + (element type { xsd:string { maxLength = "15" } } | attribute type { xsd:string { maxLength = "15" } }) & (element coeffs { list { xsd:double+ } } | attribute coeffs { list { xsd:double+ } }) & (element boundary { ( "transmit" | "reflective" | "vacuum" ) } | @@ -29,12 +29,12 @@ element geometry { (element id { xsd:int } | attribute id { xsd:int }) & (element name { xsd:string { maxLength="52" } } | attribute name { xsd:string { maxLength="52" } })? & - (element dimension { list { xsd:positiveInteger+ } } | + (element dimension { list { xsd:positiveInteger+ } } | attribute dimension { list { xsd:positiveInteger+ } }) & (element lower_left { list { xsd:double+ } } | attribute lower_left { list { xsd:double+ } }) & (element pitch { list { xsd:double+ } } | attribute pitch { list { xsd:double+ } }) & (element universes { list { xsd:int+ } } | attribute universes { list { xsd:int+ } }) & - (element outside { xsd:int } | attribute outside { xsd:int })? + (element outer { xsd:int } | attribute outer { xsd:int })? }* & element hex_lattice { diff --git a/src/relaxng/geometry.rng b/src/relaxng/geometry.rng index fdbf74cbd..9bd573b34 100644 --- a/src/relaxng/geometry.rng +++ b/src/relaxng/geometry.rng @@ -282,10 +282,10 @@ - + - + diff --git a/src/relaxng/tallies.rnc b/src/relaxng/tallies.rnc index c2e0860b8..ee93d273c 100644 --- a/src/relaxng/tallies.rnc +++ b/src/relaxng/tallies.rnc @@ -1,8 +1,8 @@ element tallies { element mesh { (element id { xsd:int } | attribute id { xsd:int }) & - (element type { ( "rectangular" | "hexagonal" ) } | - attribute type { ( "rectangular" | "hexagonal" ) }) & + (element type { ( "regular" ) } | + attribute type { ( "regular" ) }) & (element dimension { list { xsd:positiveInteger+ } } | attribute dimension { list { xsd:positiveInteger+ } }) & (element lower_left { list { xsd:double+ } } | @@ -32,7 +32,7 @@ element tallies { element nuclides { list { xsd:string { maxLength = "12" }+ } }? & - element scores { + element scores { list { xsd:string { maxLength = "20" }+ } } & element trigger { diff --git a/src/relaxng/tallies.rng b/src/relaxng/tallies.rng index 9ea941fea..76973e855 100644 --- a/src/relaxng/tallies.rng +++ b/src/relaxng/tallies.rng @@ -14,16 +14,10 @@ - - rectangular - hexagonal - + regular - - rectangular - hexagonal - + regular diff --git a/src/source.F90 b/src/source.F90 index e82482915..c46174947 100644 --- a/src/source.F90 +++ b/src/source.F90 @@ -6,17 +6,20 @@ module source use geometry, only: find_cell use geometry_header, only: BASE_UNIVERSE use global + use hdf5_interface, only: file_create, file_open, file_close, read_dataset use math, only: maxwell_spectrum, watt_spectrum use output, only: write_message - use output_interface, only: BinaryOutput use particle_header, only: Particle use random_lcg, only: prn, set_particle_seed, prn_set_stream + use state_point, only: read_source_bank, write_source_bank use string, only: to_str #ifdef MPI use message_passing #endif + use hdf5, only: HID_T + implicit none contains @@ -27,12 +30,12 @@ contains subroutine initialize_source() - character(MAX_FILE_LEN) :: filename integer(8) :: i ! loop index over bank sites integer(8) :: id ! particle id - integer(4) :: itmp ! temporary integer - type(Bank), pointer :: src => null() ! source bank site - type(BinaryOutput) :: sp ! statepoint/source binary file + integer(HID_T) :: file_id + character(MAX_WORD_LEN) :: filetype + character(MAX_FILE_LEN) :: filename + type(Bank), pointer :: src ! source bank site call write_message("Initializing source particles...", 6) @@ -44,22 +47,22 @@ contains &// '...', 6) ! Open the binary file - call sp % file_open(path_source, 'r', serial = .false.) + file_id = file_open(path_source, 'r', parallel=.true.) ! Read the file type - call sp % read_data(itmp, "filetype") + call read_dataset(file_id, "filetype", filetype) ! Check to make sure this is a source file - if (itmp /= FILETYPE_SOURCE) then + if (filetype /= 'source') then call fatal_error("Specified starting source file not a source file & &type.") end if ! Read in the source bank - call sp % read_source_bank() + call read_source_bank(file_id) ! Close file - call sp % file_close() + call file_close(file_id) else ! Generation source sites from specified distribution in user input @@ -79,14 +82,10 @@ contains ! Write out initial source if (write_initial_source) then call write_message('Writing out initial source...', 1) -#ifdef HDF5 filename = trim(path_output) // 'initial_source.h5' -#else - filename = trim(path_output) // 'initial_source.binary' -#endif - call sp % file_create(filename, serial = .false.) - call sp % write_source_bank() - call sp % file_close() + file_id = file_create(filename, parallel=.true.) + call write_source_bank(file_id) + call file_close(file_id) end if end subroutine initialize_source @@ -113,28 +112,28 @@ contains integer, save :: num_resamples = 0 ! Number of resamples encountered ! Set weight to one by default - site % wgt = ONE + site%wgt = ONE ! Set the random number generator to the source stream. call prn_set_stream(STREAM_SOURCE) ! Sample position - select case (external_source % type_space) + select case (external_source%type_space) case (SRC_SPACE_BOX) ! Set particle defaults - call p % initialize() + call p%initialize() ! Repeat sampling source location until a good site has been found found = .false. do while (.not.found) ! Coordinates sampled uniformly over a box - p_min = external_source % params_space(1:3) - p_max = external_source % params_space(4:6) + p_min = external_source%params_space(1:3) + p_max = external_source%params_space(4:6) r = (/ (prn(), i = 1,3) /) - site % xyz = p_min + r*(p_max - p_min) + site%xyz = p_min + r*(p_max - p_min) ! Fill p with needed data - p % coord(1) % xyz = site % xyz - p % coord(1) % uvw = [ ONE, ZERO, ZERO ] + p%coord(1)%xyz = site%xyz + p%coord(1)%uvw = [ ONE, ZERO, ZERO ] ! Now search to see if location exists in geometry call find_cell(p, found) @@ -146,24 +145,24 @@ contains end if end if end do - call p % clear() + call p%clear() case (SRC_SPACE_FISSION) ! Repeat sampling source location until a good site has been found found = .false. do while (.not.found) ! Set particle defaults - call p % initialize() + call p%initialize() ! Coordinates sampled uniformly over a box - p_min = external_source % params_space(1:3) - p_max = external_source % params_space(4:6) + p_min = external_source%params_space(1:3) + p_max = external_source%params_space(4:6) r = (/ (prn(), i = 1,3) /) - site % xyz = p_min + r*(p_max - p_min) + site%xyz = p_min + r*(p_max - p_min) ! Fill p with needed data - p % coord(1) % xyz = site % xyz - p % coord(1) % uvw = [ ONE, ZERO, ZERO ] + p%coord(1)%xyz = site%xyz + p%coord(1)%uvw = [ ONE, ZERO, ZERO ] ! Now search to see if location exists in geometry call find_cell(p, found) @@ -175,66 +174,66 @@ contains end if cycle end if - if (p % material == MATERIAL_VOID) then + if (p%material == MATERIAL_VOID) then found = .false. cycle end if - if (.not. materials(p % material) % fissionable) found = .false. + if (.not. materials(p%material)%fissionable) found = .false. end do - call p % clear() + call p%clear() case (SRC_SPACE_POINT) ! Point source - site % xyz = external_source % params_space + site%xyz = external_source%params_space end select ! Sample angle - select case (external_source % type_angle) + select case (external_source%type_angle) case (SRC_ANGLE_ISOTROPIC) ! Sample isotropic distribution phi = TWO*PI*prn() mu = TWO*prn() - ONE - site % uvw(1) = mu - site % uvw(2) = sqrt(ONE - mu*mu) * cos(phi) - site % uvw(3) = sqrt(ONE - mu*mu) * sin(phi) + site%uvw(1) = mu + site%uvw(2) = sqrt(ONE - mu*mu) * cos(phi) + site%uvw(3) = sqrt(ONE - mu*mu) * sin(phi) case (SRC_ANGLE_MONO) ! Monodirectional source - site % uvw = external_source % params_angle + site%uvw = external_source%params_angle case default call fatal_error("No angle distribution specified for external source!") end select ! Sample energy distribution - select case (external_source % type_energy) + select case (external_source%type_energy) case (SRC_ENERGY_MONO) ! Monoenergtic source - site % E = external_source % params_energy(1) - if (site % E >= 20) then + site%E = external_source%params_energy(1) + if (site%E >= 20) then call fatal_error("Source energies above 20 MeV not allowed.") end if case (SRC_ENERGY_MAXWELL) - a = external_source % params_energy(1) + a = external_source%params_energy(1) do ! Sample Maxwellian fission spectrum - site % E = maxwell_spectrum(a) + site%E = maxwell_spectrum(a) ! resample if energy is >= 20 MeV - if (site % E < 20) exit + if (site%E < 20) exit end do case (SRC_ENERGY_WATT) - a = external_source % params_energy(1) - b = external_source % params_energy(2) + a = external_source%params_energy(1) + b = external_source%params_energy(2) do ! Sample Watt fission spectrum - site % E = watt_spectrum(a, b) + site%E = watt_spectrum(a, b) ! resample if energy is >= 20 MeV - if (site % E < 20) exit + if (site%E < 20) exit end do case default diff --git a/src/state_point.F90 b/src/state_point.F90 index 6b983231f..64ba7ef55 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -13,22 +13,25 @@ module state_point use constants + use endf, only: reaction_name use error, only: fatal_error, warning use global + use hdf5_interface use output, only: write_message, time_stamp use string, only: to_str, zero_padded, count_digits - use output_interface use tally_header, only: TallyObject - use mesh_header, only: StructuredMesh + use mesh_header, only: RegularMesh use dict_header, only: ElemKeyValueII, ElemKeyValueCI #ifdef MPI use message_passing #endif - implicit none + use hdf5 - type(BinaryOutput) :: sp ! Statepoint/source output file + use, intrinsic :: ISO_C_BINDING, only: c_loc, c_ptr + + implicit none contains @@ -38,177 +41,160 @@ contains subroutine write_state_point() - character(MAX_FILE_LEN) :: filename - integer :: i, j, k - integer, allocatable :: id_array(:) - integer, allocatable :: key_array(:) - type(StructuredMesh), pointer :: mesh + integer :: i, j, k + integer :: i_list, i_xs + integer :: n_order ! loop index for moment orders + integer :: nm_order ! loop index for Ynm moment orders + integer, allocatable :: id_array(:) + integer, allocatable :: key_array(:) + integer(HID_T) :: file_id + integer(HID_T) :: cmfd_group + integer(HID_T) :: tallies_group, tally_group + integer(HID_T) :: meshes_group, mesh_group + integer(HID_T) :: filter_group + character(20), allocatable :: str_array(:) + character(MAX_FILE_LEN) :: filename + type(RegularMesh), pointer :: meshp type(TallyObject), pointer :: tally type(ElemKeyValueII), pointer :: current type(ElemKeyValueII), pointer :: next - character(8) :: moment_name ! name of moment (e.g, P3) - integer :: n_order ! loop index for moment orders - integer :: nm_order ! loop index for Ynm moment orders ! Set filename for state point filename = trim(path_output) // 'statepoint.' // & & zero_padded(current_batch, count_digits(n_max_batches)) - - ! Append appropriate extension -#ifdef HDF5 filename = trim(filename) // '.h5' -#else - filename = trim(filename) // '.binary' -#endif ! Write message call write_message("Creating state point " // trim(filename) // "...", 1) if (master) then ! Create statepoint file - call sp % file_create(filename) + file_id = file_create(filename) ! Write file type - call sp % write_data(FILETYPE_STATEPOINT, "filetype") + call write_dataset(file_id, "filetype", 'statepoint') ! Write revision number for state point file - call sp % write_data(REVISION_STATEPOINT, "revision") + call write_dataset(file_id, "revision", REVISION_STATEPOINT) ! Write OpenMC version - call sp % write_data(VERSION_MAJOR, "version_major") - call sp % write_data(VERSION_MINOR, "version_minor") - call sp % write_data(VERSION_RELEASE, "version_release") + call write_dataset(file_id, "version_major", VERSION_MAJOR) + call write_dataset(file_id, "version_minor", VERSION_MINOR) + call write_dataset(file_id, "version_release", VERSION_RELEASE) ! Write current date and time - call sp % write_data(time_stamp(), "date_and_time") + call write_dataset(file_id, "date_and_time", time_stamp()) ! Write path to input - call sp % write_data(path_input, "path") + call write_dataset(file_id, "path", path_input) ! Write out random number seed - call sp % write_data(seed, "seed") + call write_dataset(file_id, "seed", seed) ! Write run information - call sp % write_data(run_mode, "run_mode") - call sp % write_data(n_particles, "n_particles") - call sp % write_data(n_batches, "n_batches") + select case(run_mode) + case (MODE_FIXEDSOURCE) + call write_dataset(file_id, "run_mode", "fixed source") + case (MODE_EIGENVALUE) + call write_dataset(file_id, "run_mode", "k-eigenvalue") + end select + call write_dataset(file_id, "n_particles", n_particles) + call write_dataset(file_id, "n_batches", n_batches) ! Write out current batch number - call sp % write_data(current_batch, "current_batch") + call write_dataset(file_id, "current_batch", current_batch) ! Indicate whether source bank is stored in statepoint if (source_separate) then - call sp % write_data(0, "source_present") + call write_dataset(file_id, "source_present", 0) else - call sp % write_data(1, "source_present") + call write_dataset(file_id, "source_present", 1) end if ! Write out information for eigenvalue run if (run_mode == MODE_EIGENVALUE) then - call sp % write_data(n_inactive, "n_inactive") - call sp % write_data(gen_per_batch, "gen_per_batch") - call sp % write_data(k_generation, "k_generation", & - length=current_batch*gen_per_batch) - call sp % write_data(entropy, "entropy", & - length=current_batch*gen_per_batch) - call sp % write_data(k_col_abs, "k_col_abs") - call sp % write_data(k_col_tra, "k_col_tra") - call sp % write_data(k_abs_tra, "k_abs_tra") - call sp % write_data(k_combined, "k_combined", length=2) + call write_dataset(file_id, "n_inactive", n_inactive) + call write_dataset(file_id, "gen_per_batch", gen_per_batch) + call write_dataset(file_id, "k_generation", k_generation) + call write_dataset(file_id, "entropy", entropy) + call write_dataset(file_id, "k_col_abs", k_col_abs) + call write_dataset(file_id, "k_col_tra", k_col_tra) + call write_dataset(file_id, "k_abs_tra", k_abs_tra) + call write_dataset(file_id, "k_combined", k_combined) ! Write out CMFD info if (cmfd_on) then -#ifdef HDF5 - call sp % open_group("cmfd") - call sp % close_group() -#endif - call sp % write_data(1, "cmfd_on") - call sp % write_data(cmfd % indices, "indices", length=4, group="cmfd") - call sp % write_data(cmfd % k_cmfd, "k_cmfd", length=current_batch, & - group="cmfd") - call sp % write_data(cmfd % cmfd_src, "cmfd_src", & - length=(/cmfd % indices(4), cmfd % indices(1), & - cmfd % indices(2), cmfd % indices(3)/), & - group="cmfd") - call sp % write_data(cmfd % entropy, "cmfd_entropy", & - length=current_batch, group="cmfd") - call sp % write_data(cmfd % balance, "cmfd_balance", & - length=current_batch, group="cmfd") - call sp % write_data(cmfd % dom, "cmfd_dominance", & - length = current_batch, group="cmfd") - call sp % write_data(cmfd % src_cmp, "cmfd_srccmp", & - length = current_batch, group="cmfd") + call write_dataset(file_id, "cmfd_on", 1) + + cmfd_group = create_group(file_id, "cmfd") + call write_dataset(cmfd_group, "indices", cmfd%indices) + call write_dataset(cmfd_group, "k_cmfd", cmfd%k_cmfd) + call write_dataset(cmfd_group, "cmfd_src", cmfd%cmfd_src) + call write_dataset(cmfd_group, "cmfd_entropy", cmfd%entropy) + call write_dataset(cmfd_group, "cmfd_balance", cmfd%balance) + call write_dataset(cmfd_group, "cmfd_dominance", cmfd%dom) + call write_dataset(cmfd_group, "cmfd_srccmp", cmfd%src_cmp) + call close_group(cmfd_group) else - call sp % write_data(0, "cmfd_on") + call write_dataset(file_id, "cmfd_on", 0) end if end if -#ifdef HDF5 - call sp % open_group("tallies") - call sp % close_group() -#endif + tallies_group = create_group(file_id, "tallies") ! Write number of meshes - call sp % write_data(n_meshes, "n_meshes", group="tallies/meshes") + meshes_group = create_group(tallies_group, "meshes") + call write_dataset(meshes_group, "n_meshes", n_meshes) if (n_meshes > 0) then ! Print list of mesh IDs - current => mesh_dict % keys() + current => mesh_dict%keys() allocate(id_array(n_meshes)) allocate(key_array(n_meshes)) i = 1 do while (associated(current)) - key_array(i) = current % key - id_array(i) = current % value + key_array(i) = current%key + id_array(i) = current%value ! Move to next mesh - next => current % next + next => current%next deallocate(current) current => next i = i + 1 end do - call sp % write_data(id_array, "ids", & - group="tallies/meshes", length=n_meshes) - call sp % write_data(key_array, "keys", & - group="tallies/meshes", length=n_meshes) + call write_dataset(meshes_group, "ids", id_array) + call write_dataset(meshes_group, "keys", key_array) deallocate(key_array) ! Write information for meshes MESH_LOOP: do i = 1, n_meshes + meshp => meshes(id_array(i)) + mesh_group = create_group(meshes_group, "mesh " // trim(to_str(meshp%id))) - mesh => meshes(id_array(i)) + select case (meshp%type) + case (MESH_REGULAR) + call write_dataset(mesh_group, "type", "regular") + end select + call write_dataset(mesh_group, "dimension", meshp%dimension) + call write_dataset(mesh_group, "lower_left", meshp%lower_left) + call write_dataset(mesh_group, "upper_right", meshp%upper_right) + call write_dataset(mesh_group, "width", meshp%width) - call sp % write_data(mesh % id, "id", & - group="tallies/meshes/mesh " // trim(to_str(mesh % id))) - call sp % write_data(mesh % type, "type", & - group="tallies/meshes/mesh " // trim(to_str(mesh % id))) - call sp % write_data(mesh % n_dimension, "n_dimension", & - group="tallies/meshes/mesh " // trim(to_str(mesh % id))) - call sp % write_data(mesh % dimension, "dimension", & - group="tallies/meshes/mesh " // trim(to_str(mesh % id)), & - length=mesh % n_dimension) - call sp % write_data(mesh % lower_left, "lower_left", & - group="tallies/meshes/mesh " // trim(to_str(mesh % id)), & - length=mesh % n_dimension) - call sp % write_data(mesh % upper_right, "upper_right", & - group="tallies/meshes/mesh " // trim(to_str(mesh % id)), & - length=mesh % n_dimension) - call sp % write_data(mesh % width, "width", & - group="tallies/meshes/mesh " // trim(to_str(mesh % id)), & - length=mesh % n_dimension) + call close_group(mesh_group) end do MESH_LOOP deallocate(id_array) - end if + call close_group(meshes_group) + ! Write number of tallies - call sp % write_data(n_tallies, "n_tallies", group="tallies") + call write_dataset(tallies_group, "n_tallies", n_tallies) if (n_tallies > 0) then @@ -219,14 +205,12 @@ contains ! Write all tally information except results do i = 1, n_tallies tally => tallies(i) - key_array(i) = tally % id + key_array(i) = tally%id id_array(i) = i end do - call sp % write_data(id_array, "ids", & - group="tallies", length=n_tallies) - call sp % write_data(key_array, "keys", & - group="tallies", length=n_tallies) + call write_dataset(tallies_group, "ids", id_array) + call write_dataset(tallies_group, "keys", key_array) deallocate(key_array) @@ -235,110 +219,173 @@ contains ! Get pointer to tally tally => tallies(i) + tally_group = create_group(tallies_group, "tally " // & + trim(to_str(tally%id))) - call sp % write_data(tally % estimator, "estimator", & - group="tallies/tally " // trim(to_str(tally % id))) - call sp % write_data(tally % n_realizations, "n_realizations", & - group="tallies/tally " // trim(to_str(tally % id))) - call sp % write_data(tally % n_filters, "n_filters", & - group="tallies/tally " // trim(to_str(tally % id))) + select case(tally%estimator) + case (ESTIMATOR_ANALOG) + call write_dataset(tally_group, "estimator", "analog") + case (ESTIMATOR_TRACKLENGTH) + call write_dataset(tally_group, "estimator", "tracklength") + case (ESTIMATOR_COLLISION) + call write_dataset(tally_group, "estimator", "collision") + end select + call write_dataset(tally_group, "n_realizations", tally%n_realizations) + call write_dataset(tally_group, "n_filters", tally%n_filters) ! Write filter information - FILTER_LOOP: do j = 1, tally % n_filters + FILTER_LOOP: do j = 1, tally%n_filters + filter_group = create_group(tally_group, "filter " // & + trim(to_str(j))) - call sp % write_data(tally % filters(j) % type, "type", & - group="tallies/tally " // trim(to_str(tally % id)) // & - "/filter " // to_str(j)) - call sp % write_data(tally % filters(j) % offset, "offset", & - group="tallies/tally " // trim(to_str(tally % id)) // & - "/filter " // to_str(j)) - call sp % write_data(tally % filters(j) % n_bins, "n_bins", & - group="tallies/tally " // trim(to_str(tally % id)) // & - "/filter " // to_str(j)) - if (tally % filters(j) % type == FILTER_ENERGYIN .or. & - tally % filters(j) % type == FILTER_ENERGYOUT) then - call sp % write_data(tally % filters(j) % real_bins, "bins", & - group="tallies/tally " // trim(to_str(tally % id)) // & - "/filter " // to_str(j), & - length=size(tally % filters(j) % real_bins)) + ! Write name of type + select case (tally%filters(j)%type) + case(FILTER_UNIVERSE) + call write_dataset(filter_group, "type", "universe") + case(FILTER_MATERIAL) + call write_dataset(filter_group, "type", "material") + case(FILTER_CELL) + call write_dataset(filter_group, "type", "cell") + case(FILTER_CELLBORN) + call write_dataset(filter_group, "type", "cellborn") + case(FILTER_SURFACE) + call write_dataset(filter_group, "type", "surface") + case(FILTER_MESH) + call write_dataset(filter_group, "type", "mesh") + case(FILTER_ENERGYIN) + call write_dataset(filter_group, "type", "energy") + case(FILTER_ENERGYOUT) + call write_dataset(filter_group, "type", "energyout") + case(FILTER_DISTRIBCELL) + call write_dataset(filter_group, "type", "distribcell") + end select + + call write_dataset(filter_group, "offset", tally%filters(j)%offset) + call write_dataset(filter_group, "n_bins", tally%filters(j)%n_bins) + if (tally%filters(j)%type == FILTER_ENERGYIN .or. & + tally%filters(j)%type == FILTER_ENERGYOUT) then + call write_dataset(filter_group, "bins", & + tally%filters(j)%real_bins) else - call sp % write_data(tally % filters(j) % int_bins, "bins", & - group="tallies/tally " // trim(to_str(tally % id)) // & - "/filter " // to_str(j), & - length=size(tally % filters(j) % int_bins)) + call write_dataset(filter_group, "bins", & + tally%filters(j)%int_bins) end if + call close_group(filter_group) end do FILTER_LOOP - call sp % write_data(tally % n_nuclide_bins, "n_nuclides", & - group="tallies/tally " // trim(to_str(tally % id))) - ! Set up nuclide bin array and then write - allocate(key_array(tally % n_nuclide_bins)) - NUCLIDE_LOOP: do j = 1, tally % n_nuclide_bins - if (tally % nuclide_bins(j) > 0) then - key_array(j) = nuclides(tally % nuclide_bins(j)) % zaid + allocate(str_array(tally%n_nuclide_bins)) + NUCLIDE_LOOP: do j = 1, tally%n_nuclide_bins + if (tally%nuclide_bins(j) > 0) then + ! Get index in cross section listings for this nuclide + i_list = nuclides(tally%nuclide_bins(j))%listing + + ! Determine position of . in alias string (e.g. "U-235.71c"). If + ! no . is found, just use the entire string. + i_xs = index(xs_listings(i_list)%alias, '.') + if (i_xs > 0) then + str_array(j) = xs_listings(i_list)%alias(1:i_xs - 1) + else + str_array(j) = xs_listings(i_list)%alias + end if else - key_array(j) = tally % nuclide_bins(j) + str_array(j) = 'total' end if end do NUCLIDE_LOOP - call sp % write_data(key_array, "nuclides", & - group="tallies/tally " // trim(to_str(tally % id)), & - length=tally % n_nuclide_bins) - deallocate(key_array) + call write_dataset(tally_group, "nuclides", str_array) + deallocate(str_array) - call sp % write_data(tally % n_score_bins, "n_score_bins", & - group="tallies/tally " // trim(to_str(tally % id))) - call sp % write_data(tally % score_bins, "score_bins", & - group="tallies/tally " // trim(to_str(tally % id)), & - length=tally % n_score_bins) - call sp % write_data(tally % n_user_score_bins, "n_user_score_bins", & - group="tallies/tally " // to_str(tally % id)) + call write_dataset(tally_group, "n_score_bins", tally%n_score_bins) + allocate(str_array(size(tally%score_bins))) + do j = 1, size(tally%score_bins) + select case(tally%score_bins(j)) + case (SCORE_FLUX) + str_array(j) = "flux" + case (SCORE_TOTAL) + str_array(j) = "total" + case (SCORE_SCATTER) + str_array(j) = "scatter" + case (SCORE_NU_SCATTER) + str_array(j) = "nu-scatter" + case (SCORE_SCATTER_N) + str_array(j) = "scatter-n" + case (SCORE_SCATTER_PN) + str_array(j) = "scatter-pn" + case (SCORE_NU_SCATTER_N) + str_array(j) = "nu-scatter-n" + case (SCORE_NU_SCATTER_PN) + str_array(j) = "nu-scatter-pn" + case (SCORE_TRANSPORT) + str_array(j) = "transport" + case (SCORE_N_1N) + str_array(j) = "n1n" + case (SCORE_ABSORPTION) + str_array(j) = "absorption" + case (SCORE_FISSION) + str_array(j) = "fission" + case (SCORE_NU_FISSION) + str_array(j) = "nu-fission" + case (SCORE_KAPPA_FISSION) + str_array(j) = "kappa-fission" + case (SCORE_CURRENT) + str_array(j) = "current" + case (SCORE_FLUX_YN) + str_array(j) = "flux-yn" + case (SCORE_TOTAL_YN) + str_array(j) = "total-yn" + case (SCORE_SCATTER_YN) + str_array(j) = "scatter-yn" + case (SCORE_NU_SCATTER_YN) + str_array(j) = "nu-scatter-yn" + case (SCORE_EVENTS) + str_array(j) = "events" + case default + str_array(j) = reaction_name(tally%score_bins(j)) + end select + end do + call write_dataset(tally_group, "score_bins", str_array) + call write_dataset(tally_group, "n_user_score_bins", tally%n_user_score_bins) + + deallocate(str_array) ! Write explicit moment order strings for each score bin k = 1 - MOMENT_LOOP: do j = 1, tally % n_user_score_bins - select case(tally % score_bins(k)) + allocate(str_array(tally%n_score_bins)) + MOMENT_LOOP: do j = 1, tally%n_user_score_bins + select case(tally%score_bins(k)) case (SCORE_SCATTER_N, SCORE_NU_SCATTER_N) - moment_name = 'P' // trim(to_str(tally % moment_order(k))) - call sp % write_data(moment_name, "order" // trim(to_str(k)), & - group="tallies/tally " // trim(to_str(tally % id)) // & - "/moments") + str_array(k) = 'P' // trim(to_str(tally%moment_order(k))) k = k + 1 case (SCORE_SCATTER_PN, SCORE_NU_SCATTER_PN) - do n_order = 0, tally % moment_order(k) - moment_name = 'P' // trim(to_str(n_order)) - call sp % write_data(moment_name, "order" // trim(to_str(k)), & - group="tallies/tally " // trim(to_str(tally % id)) // & - "/moments") + do n_order = 0, tally%moment_order(k) + str_array(k) = 'P' // trim(to_str(n_order)) k = k + 1 end do case (SCORE_SCATTER_YN, SCORE_NU_SCATTER_YN, SCORE_FLUX_YN, & - SCORE_TOTAL_YN) - do n_order = 0, tally % moment_order(k) + SCORE_TOTAL_YN) + do n_order = 0, tally%moment_order(k) do nm_order = -n_order, n_order - moment_name = 'Y' // trim(to_str(n_order)) // ',' // & + str_array(k) = 'Y' // trim(to_str(n_order)) // ',' // & trim(to_str(nm_order)) - call sp % write_data(moment_name, "order" // & - trim(to_str(k)), & - group="tallies/tally " // trim(to_str(tally % id)) // & - "/moments") - k = k + 1 + k = k + 1 end do end do case default - moment_name = '' - call sp % write_data(moment_name, "order" // trim(to_str(k)), & - group="tallies/tally " // trim(to_str(tally % id)) // & - "/moments") + str_array(k) = '' k = k + 1 end select - end do MOMENT_LOOP + call write_dataset(tally_group, "moment_orders", str_array) + deallocate(str_array) + + call close_group(tally_group) end do TALLY_METADATA end if + + call close_group(tallies_group) end if ! Check for the no-tally-reduction method @@ -346,47 +393,41 @@ contains ! If using the no-tally-reduction method, we need to collect tally ! results before writing them to the state point file. - call write_tally_results_nr() + call write_tally_results_nr(file_id) elseif (master) then ! Write number of global realizations - call sp % write_data(n_realizations, "n_realizations") + call write_dataset(file_id, "n_realizations", n_realizations) ! Write global tallies - call sp % write_data(N_GLOBAL_TALLIES, "n_global_tallies") - call sp % write_tally_result(global_tallies, "global_tallies", & - n1=N_GLOBAL_TALLIES, n2=1) + call write_dataset(file_id, "n_global_tallies", N_GLOBAL_TALLIES) + call write_dataset(file_id, "global_tallies", global_tallies) ! Write tallies + tallies_group = open_group(file_id, "tallies") if (tallies_on) then - ! Indicate that tallies are on - call sp % write_data(1, "tallies_present", group="tallies") + call write_dataset(tallies_group, "tallies_present", 1) ! Write all tally results TALLY_RESULTS: do i = 1, n_tallies - ! Set point to current tally tally => tallies(i) ! Write sum and sum_sq for each bin - call sp % write_tally_result(tally % results, "results", & - group="tallies/tally " // trim(to_str(tally % id)), & - n1=size(tally % results, 1), n2=size(tally % results, 2)) - + tally_group = open_group(tallies_group, "tally " // to_str(tally%id)) + call write_dataset(tally_group, "results", tally%results) + call close_group(tally_group) end do TALLY_RESULTS else - ! Indicate tallies are off - call sp % write_data(0, "tallies_present", group="tallies") - + call write_dataset(tallies_group, "tallies_present", 0) end if - ! Close the file for serial writing - call sp % file_close() - + call close_group(tallies_group) + call file_close(file_id) end if if (master .and. n_tallies > 0) then @@ -401,85 +442,60 @@ contains subroutine write_source_point() - type(BinaryOutput) :: sp + logical :: parallel + integer(HID_T) :: file_id character(MAX_FILE_LEN) :: filename + ! When using parallel HDF5, the file is written to collectively by all + ! processes. With MPI-only, the file is opened and written by the master + ! (note that the call to write_source_bank is by all processes since slave + ! processes need to send source bank data to the master. +#ifdef PHDF5 + parallel = .true. +#else + parallel = .false. +#endif + ! Check to write out source for a specified batch - if (sourcepoint_batch % contains(current_batch)) then - - ! Create or open up file + if (sourcepoint_batch%contains(current_batch)) then if (source_separate) then - - ! Set filename filename = trim(path_output) // 'source.' // & & zero_padded(current_batch, count_digits(n_max_batches)) - -#ifdef HDF5 filename = trim(filename) // '.h5' -#else - filename = trim(filename) // '.binary' -#endif - - ! Write message for new file creation - call write_message("Creating source file " // trim(filename) // "...", & - &1) + call write_message("Creating source file " // trim(filename) & + // "...", 1) ! Create separate source file - call sp % file_create(filename, serial = .false.) - - ! Write file type - call sp % write_data(FILETYPE_SOURCE, "filetype") - + if (master .or. parallel) then + file_id = file_create(filename, parallel=.true.) + call write_dataset(file_id, "filetype", 'source') + end if else - - ! Set filename for state point filename = trim(path_output) // 'statepoint.' // & - & zero_padded(current_batch, count_digits(n_max_batches)) -#ifdef HDF5 + zero_padded(current_batch, count_digits(n_max_batches)) filename = trim(filename) // '.h5' -#else - filename = trim(filename) // '.binary' -#endif - - ! Reopen statepoint file in parallel - call sp % file_open(filename, 'w', serial = .false.) + if (master .or. parallel) then + file_id = file_open(filename, 'w', parallel=.true.) + end if end if - ! Write out source - call sp % write_source_bank() - - ! Close file - call sp % file_close() - + call write_source_bank(file_id) + if (master .or. parallel) call file_close(file_id) end if ! Also check to write source separately in overwritten file if (source_latest) then - - ! Set filename - filename = trim(path_output) // 'source' -#ifdef HDF5 - filename = trim(filename) // '.h5' -#else - filename = trim(filename) // '.binary' -#endif - - ! Write message for new file creation + filename = trim(path_output) // 'source' // '.h5' call write_message("Creating source file " // trim(filename) // "...", 1) + if (master .or. parallel) then + file_id = file_create(filename, parallel=.true.) + call write_dataset(file_id, "filetype", 'source') + end if - ! Always create this file because it will be overwritten - call sp % file_create(filename, serial = .false.) - - ! Write file type - call sp % write_data(FILETYPE_SOURCE, "filetype") - - ! Write out source - call sp % write_source_bank() - - ! Close file - call sp % file_close() + call write_source_bank(file_id) + if (master .or. parallel) call file_close(file_id) end if end subroutine write_source_point @@ -488,12 +504,14 @@ contains ! WRITE_TALLY_RESULTS_NR !=============================================================================== - subroutine write_tally_results_nr() + subroutine write_tally_results_nr(file_id) + integer(HID_T), intent(in) :: file_id integer :: i ! loop index integer :: n ! number of filter bins integer :: m ! number of score bins integer :: n_bins ! total number of bins + integer(HID_T) :: tallies_group, tally_group real(8), allocatable :: tally_temp(:,:,:) ! contiguous array of results real(8), target :: global_temp(2,N_GLOBAL_TALLIES) #ifdef MPI @@ -510,16 +528,18 @@ contains if (master) then ! Write number of realizations - call sp % write_data(n_realizations, "n_realizations") + call write_dataset(file_id, "n_realizations", n_realizations) ! Write number of global tallies - call sp % write_data(N_GLOBAL_TALLIES, "n_global_tallies") + call write_dataset(file_id, "n_global_tallies", N_GLOBAL_TALLIES) + + tallies_group = open_group(file_id, "tallies") end if ! Copy global tallies into temporary array for reducing n_bins = 2 * N_GLOBAL_TALLIES - global_temp(1,:) = global_tallies(:) % sum - global_temp(2,:) = global_tallies(:) % sum_sq + global_temp(1,:) = global_tallies(:)%sum + global_temp(2,:) = global_tallies(:)%sum_sq if (master) then ! The MPI_IN_PLACE specifier allows the master to copy values into a @@ -531,19 +551,17 @@ contains ! Transfer values to value on master if (current_batch == n_max_batches .or. satisfy_triggers) then - global_tallies(:) % sum = global_temp(1,:) - global_tallies(:) % sum_sq = global_temp(2,:) + global_tallies(:)%sum = global_temp(1,:) + global_tallies(:)%sum_sq = global_temp(2,:) end if ! Put reduced value in temporary tally result allocate(tallyresult_temp(N_GLOBAL_TALLIES, 1)) - tallyresult_temp(:,1) % sum = global_temp(1,:) - tallyresult_temp(:,1) % sum_sq = global_temp(2,:) - + tallyresult_temp(:,1)%sum = global_temp(1,:) + tallyresult_temp(:,1)%sum_sq = global_temp(2,:) ! Write out global tallies sum and sum_sq - call sp % write_tally_result(tallyresult_temp, "global_tallies", & - n1=N_GLOBAL_TALLIES, n2=1) + call write_dataset(file_id, "global_tallies", tallyresult_temp) ! Deallocate temporary tally result deallocate(tallyresult_temp) @@ -558,17 +576,17 @@ contains if (tallies_on) then ! Indicate that tallies are on if (master) then - call sp % write_data(1, "tallies_present", group="tallies") + call write_dataset(tallies_group, "tallies_present", 1) ! Build list of tally IDs - current => tally_dict % keys() + current => tally_dict%keys() allocate(id_array(n_tallies)) i = 1 do while (associated(current)) - id_array(i) = current % value + id_array(i) = current%value ! Move to next tally - next => current % next + next => current%next deallocate(current) current => next i = i + 1 @@ -582,17 +600,20 @@ contains tally => tallies(i) ! Determine size of tally results array - m = size(tally % results, 1) - n = size(tally % results, 2) + m = size(tally%results, 1) + n = size(tally%results, 2) n_bins = m*n*2 ! Allocate array for storing sums and sums of squares, but ! contiguously in memory for each allocate(tally_temp(2,m,n)) - tally_temp(1,:,:) = tally % results(:,:) % sum - tally_temp(2,:,:) = tally % results(:,:) % sum_sq + tally_temp(1,:,:) = tally%results(:,:)%sum + tally_temp(2,:,:) = tally%results(:,:)%sum_sq if (master) then + tally_group = open_group(tallies_group, "tally " // & + trim(to_str(tally%id))) + ! The MPI_IN_PLACE specifier allows the master to copy values into ! a receive buffer without having a temporary variable #ifdef MPI @@ -603,18 +624,17 @@ contains ! At the end of the simulation, store the results back in the ! regular TallyResults array if (current_batch == n_max_batches .or. satisfy_triggers) then - tally % results(:,:) % sum = tally_temp(1,:,:) - tally % results(:,:) % sum_sq = tally_temp(2,:,:) + tally%results(:,:)%sum = tally_temp(1,:,:) + tally%results(:,:)%sum_sq = tally_temp(2,:,:) end if ! Put in temporary tally result allocate(tallyresult_temp(m,n)) - tallyresult_temp(:,:) % sum = tally_temp(1,:,:) - tallyresult_temp(:,:) % sum_sq = tally_temp(2,:,:) + tallyresult_temp(:,:)%sum = tally_temp(1,:,:) + tallyresult_temp(:,:)%sum_sq = tally_temp(2,:,:) ! Write reduced tally results to file - call sp % write_tally_result(tally % results, "results", & - group="tallies/tally " // trim(to_str(tally % id)), n1=m, n2=n) + call write_dataset(tally_group, "results", tally%results) ! Deallocate temporary tally result deallocate(tallyresult_temp) @@ -628,6 +648,8 @@ contains ! Deallocate temporary copy of tally results deallocate(tally_temp) + + if (master) call close_group(tally_group) end do TALLY_RESULTS deallocate(id_array) @@ -635,10 +657,12 @@ contains else if (master) then ! Indicate that tallies are off - call sp % write_data(0, "tallies_present", group="tallies") + call write_dataset(tallies_group, "tallies_present", 0) end if end if + if (master) call close_group(tallies_group) + end subroutine write_tally_results_nr !=============================================================================== @@ -647,73 +671,57 @@ contains subroutine load_state_point() - character(MAX_FILE_LEN) :: path_temp - character(19) :: current_time - integer :: i, j, k - integer :: length(4) - integer :: int_array(3) - integer, allocatable :: id_array(:) - integer, allocatable :: key_array(:) - integer :: curr_key - integer, allocatable :: temp_array(:) - logical :: source_present - real(8) :: real_array(3) - type(StructuredMesh), pointer :: mesh + integer :: i + integer :: int_array(3) + integer(HID_T) :: file_id + integer(HID_T) :: cmfd_group + integer(HID_T) :: tallies_group + integer(HID_T) :: tally_group + real(8) :: real_array(3) + logical :: source_present + character(MAX_WORD_LEN) :: word type(TallyObject), pointer :: tally - integer :: n_order ! loop index for moment orders - integer :: nm_order ! loop index for Ynm moment orders - character(8) :: moment_name ! name of moment (e.g, P3, Y-1,1) ! Write message call write_message("Loading state point " // trim(path_state_point) & - &// "...", 1) + // "...", 1) ! Open file for reading - call sp % file_open(path_state_point, 'r', serial = .false.) + file_id = file_open(path_state_point, 'r', parallel=.true.) ! Read filetype - call sp % read_data(int_array(1), "filetype") + call read_dataset(file_id, "filetype", int_array(1)) ! Read revision number for state point file and make sure it matches with ! current version - call sp % read_data(int_array(1), "revision") + call read_dataset(file_id, "revision", int_array(1)) if (int_array(1) /= REVISION_STATEPOINT) then call fatal_error("State point version does not match current version & &in OpenMC.") end if - ! Read OpenMC version - call sp % read_data(int_array(1), "version_major") - call sp % read_data(int_array(2), "version_minor") - call sp % read_data(int_array(3), "version_release") - if (int_array(1) /= VERSION_MAJOR .or. int_array(2) /= VERSION_MINOR & - .or. int_array(3) /= VERSION_RELEASE) then - if (master) call warning("State point file was created with a different & - &version of OpenMC.") - end if - - ! Read date and time - call sp % read_data(current_time, "date_and_time") - - ! Read path to input - call sp % read_data(path_temp, "path") - ! Read and overwrite random number seed - call sp % read_data(seed, "seed") + call read_dataset(file_id, "seed", seed) ! Read and overwrite run information except number of batches - call sp % read_data(run_mode, "run_mode") - call sp % read_data(n_particles, "n_particles") - call sp % read_data(int_array(1), "n_batches") + call read_dataset(file_id, "run_mode", word) + select case(word) + case ('fixed source') + run_mode = MODE_FIXEDSOURCE + case ('k-eigenvalue') + run_mode = MODE_EIGENVALUE + end select + call read_dataset(file_id, "n_particles", n_particles) + call read_dataset(file_id, "n_batches", int_array(1)) ! Take maximum of statepoint n_batches and input n_batches n_batches = max(n_batches, int_array(1)) ! Read batch number to restart at - call sp % read_data(restart_batch, "current_batch") + call read_dataset(file_id, "current_batch", restart_batch) ! Check for source in statepoint if needed - call sp % read_data(int_array(1), "source_present") + call read_dataset(file_id, "source_present", int_array(1)) if (int_array(1) == 1) then source_present = .true. else @@ -727,198 +735,41 @@ contains ! Read information specific to eigenvalue run if (run_mode == MODE_EIGENVALUE) then - call sp % read_data(int_array(1), "n_inactive") - call sp % read_data(gen_per_batch, "gen_per_batch") - call sp % read_data(k_generation, "k_generation", & - length=restart_batch*gen_per_batch) - call sp % read_data(entropy, "entropy", length=restart_batch*gen_per_batch) - call sp % read_data(k_col_abs, "k_col_abs") - call sp % read_data(k_col_tra, "k_col_tra") - call sp % read_data(k_abs_tra, "k_abs_tra") - call sp % read_data(real_array(1:2), "k_combined", length=2) + call read_dataset(file_id, "n_inactive", int_array(1)) + call read_dataset(file_id, "gen_per_batch", gen_per_batch) + call read_dataset(file_id, "k_generation", & + k_generation(1:restart_batch*gen_per_batch)) + call read_dataset(file_id, "entropy", & + entropy(1:restart_batch*gen_per_batch)) + call read_dataset(file_id, "k_col_abs", k_col_abs) + call read_dataset(file_id, "k_col_tra", k_col_tra) + call read_dataset(file_id, "k_abs_tra", k_abs_tra) + call read_dataset(file_id, "k_combined", real_array(1:2)) ! Take maximum of statepoint n_inactive and input n_inactive n_inactive = max(n_inactive, int_array(1)) ! Read in to see if CMFD was on - call sp % read_data(int_array(1), "cmfd_on") + call read_dataset(file_id, "cmfd_on", int_array(1)) ! Read in CMFD info if (int_array(1) == 1) then - call sp % read_data(cmfd % indices, "indices", length=4, group="cmfd") - call sp % read_data(cmfd % k_cmfd, "k_cmfd", length=restart_batch, & - group="cmfd") - length = cmfd % indices([4,1,2,3]) - call sp % read_data(cmfd % cmfd_src, "cmfd_src", & - length=length, group="cmfd") - call sp % read_data(cmfd % entropy, "cmfd_entropy", & - length=restart_batch, group="cmfd") - call sp % read_data(cmfd % balance, "cmfd_balance", & - length=restart_batch, group="cmfd") - call sp % read_data(cmfd % dom, "cmfd_dominance", & - length = restart_batch, group="cmfd") - call sp % read_data(cmfd % src_cmp, "cmfd_srccmp", & - length = restart_batch, group="cmfd") + cmfd_group = open_group(file_id, "cmfd") + call read_dataset(cmfd_group, "indices", cmfd%indices) + call read_dataset(cmfd_group, "k_cmfd", cmfd%k_cmfd(1:restart_batch)) + call read_dataset(cmfd_group, "cmfd_src", cmfd%cmfd_src) + call read_dataset(cmfd_group, "cmfd_entropy", & + cmfd%entropy(1:restart_batch)) + call read_dataset(cmfd_group, "cmfd_balance", & + cmfd%balance(1:restart_batch)) + call read_dataset(cmfd_group, "cmfd_dominance", & + cmfd%dom(1:restart_batch)) + call read_dataset(cmfd_group, "cmfd_srccmp", & + cmfd%src_cmp(1:restart_batch)) + call close_group(cmfd_group) end if end if - ! Read number of meshes - call sp % read_data(n_meshes, "n_meshes", group="tallies/meshes") - - if (n_meshes > 0) then - - ! Read list of mesh keys-> IDs - allocate(id_array(n_meshes)) - allocate(key_array(n_meshes)) - - call sp % read_data(id_array, "ids", & - group="tallies/meshes", length=n_meshes) - call sp % read_data(key_array, "keys", & - group="tallies/meshes", length=n_meshes) - - ! Read and overwrite mesh information - MESH_LOOP: do i = 1, n_meshes - - mesh => meshes(id_array(i)) - curr_key = key_array(id_array(i)) - - call sp % read_data(mesh % id, "id", & - group="tallies/meshes/mesh " // trim(to_str(curr_key))) - call sp % read_data(mesh % type, "type", & - group="tallies/meshes/mesh " // trim(to_str(curr_key))) - call sp % read_data(mesh % n_dimension, "n_dimension", & - group="tallies/meshes/mesh " // trim(to_str(meshes(i) % id))) - call sp % read_data(mesh % dimension, "dimension", & - group="tallies/meshes/mesh " // trim(to_str(curr_key)), & - length=mesh % n_dimension) - call sp % read_data(mesh % lower_left, "lower_left", & - group="tallies/meshes/mesh " // trim(to_str(curr_key)), & - length=mesh % n_dimension) - call sp % read_data(mesh % upper_right, "upper_right", & - group="tallies/meshes/mesh " // trim(to_str(curr_key)), & - length=mesh % n_dimension) - call sp % read_data(mesh % width, "width", & - group="tallies/meshes/mesh " // trim(to_str(curr_key)), & - length=meshes(i) % n_dimension) - - end do MESH_LOOP - - deallocate(id_array) - deallocate(key_array) - - end if - - ! Read and overwrite number of tallies - call sp % read_data(n_tallies, "n_tallies", group="tallies") - - ! Read list of tally keys-> IDs - allocate(id_array(n_tallies)) - allocate(key_array(n_tallies)) - - call sp % read_data(id_array, "ids", group="tallies", length=n_tallies) - call sp % read_data(key_array, "keys", group="tallies", length=n_tallies) - - ! Read in tally metadata - TALLY_METADATA: do i = 1, n_tallies - - ! Get pointer to tally - tally => tallies(i) - curr_key = key_array(id_array(i)) - - call sp % read_data(tally % estimator, "estimator", & - group="tallies/tally " // trim(to_str(curr_key))) - call sp % read_data(tally % n_realizations, "n_realizations", & - group="tallies/tally " // trim(to_str(curr_key))) - call sp % read_data(tally % n_filters, "n_filters", & - group="tallies/tally " // trim(to_str(curr_key))) - - FILTER_LOOP: do j = 1, tally % n_filters - call sp % read_data(tally % filters(j) % type, "type", & - group="tallies/tally " // trim(to_str(curr_key)) // & - "/filter " // to_str(j)) - call sp % read_data(tally % filters(j) % offset, "offset", & - group="tallies/tally " // trim(to_str(curr_key)) // & - "/filter " // to_str(j)) - call sp % read_data(tally % filters(j) % n_bins, "n_bins", & - group="tallies/tally " // trim(to_str(curr_key)) // & - "/filter " // to_str(j)) - if (tally % filters(j) % type == FILTER_ENERGYIN .or. & - tally % filters(j) % type == FILTER_ENERGYOUT) then - call sp % read_data(tally % filters(j) % real_bins, "bins", & - group="tallies/tally " // trim(to_str(curr_key)) // & - "/filter " // to_str(j), & - length=size(tally % filters(j) % real_bins)) - else - call sp % read_data(tally % filters(j) % int_bins, "bins", & - group="tallies/tally " // trim(to_str(curr_key)) // & - "/filter " // to_str(j), & - length=size(tally % filters(j) % int_bins)) - end if - - end do FILTER_LOOP - - call sp % read_data(tally % n_nuclide_bins, "n_nuclides", & - group="tallies/tally " // trim(to_str(curr_key))) - - ! Set up nuclide bin array and then read - allocate(temp_array(tally % n_nuclide_bins)) - call sp % read_data(temp_array, "nuclides", & - group="tallies/tally " // trim(to_str(curr_key)), & - length=tally % n_nuclide_bins) - - NUCLIDE_LOOP: do j = 1, tally % n_nuclide_bins - if (temp_array(j) > 0) then - tally % nuclide_bins(j) = temp_array(j) - else - tally % nuclide_bins(j) = temp_array(j) - end if - end do NUCLIDE_LOOP - - deallocate(temp_array) - - ! Write number of score bins, score bins, user score bins - call sp % read_data(tally % n_score_bins, "n_score_bins", & - group="tallies/tally " // trim(to_str(curr_key))) - call sp % read_data(tally % score_bins, "score_bins", & - group="tallies/tally " // trim(to_str(curr_key)), & - length=tally % n_score_bins) - call sp % read_data(tally % n_user_score_bins, "n_user_score_bins", & - group="tallies/tally " // trim(to_str(curr_key))) - - ! Read explicit moment order strings for each score bin - k = 1 - MOMENT_LOOP: do j = 1, tally % n_user_score_bins - select case(tally % score_bins(k)) - case (SCORE_SCATTER_N, SCORE_NU_SCATTER_N) - call sp % read_data(moment_name, "order" // trim(to_str(k)), & - group="tallies/tally " // trim(to_str(curr_key)) // "/moments") - k = k + 1 - case (SCORE_SCATTER_PN, SCORE_NU_SCATTER_PN) - do n_order = 0, tally % moment_order(k) - call sp % read_data(moment_name, "order" // trim(to_str(k)), & - group="tallies/tally " // trim(to_str(curr_key)) // "/moments") - k = k + 1 - end do - case (SCORE_SCATTER_YN, SCORE_NU_SCATTER_YN, SCORE_FLUX_YN, & - SCORE_TOTAL_YN) - do n_order = 0, tally % moment_order(k) - do nm_order = -n_order, n_order - call sp % read_data(moment_name, "order" // trim(to_str(k)), & - group="tallies/tally " // trim(to_str(curr_key)) // & - "/moments") - k = k + 1 - end do - end do - case default - call sp % read_data(moment_name, "order" // trim(to_str(k)), & - group="tallies/tally " // trim(to_str(curr_key)) // "/moments") - k = k + 1 - end select - - end do MOMENT_LOOP - - end do TALLY_METADATA - ! Check to make sure source bank is present if (path_source_point == path_state_point .and. .not. source_present) then call fatal_error("Source bank must be contained in statepoint restart & @@ -929,43 +780,32 @@ contains if (master) then ! Read number of realizations for global tallies - call sp % read_data(n_realizations, "n_realizations", collect=.false.) - - ! Read number of global tallies - call sp % read_data(int_array(1), "n_global_tallies", collect=.false.) - if (int_array(1) /= N_GLOBAL_TALLIES) then - call fatal_error("Number of global tallies does not match in state & - &point.") - end if + call read_dataset(file_id, "n_realizations", n_realizations, indep=.true.) ! Read global tally data - call sp % read_tally_result(global_tallies, "global_tallies", & - n1=N_GLOBAL_TALLIES, n2=1) + call read_dataset(file_id, "global_tallies", global_tallies) ! Check if tally results are present - call sp % read_data(int_array(1), "tallies_present", & - group="tallies", collect=.false.) + tallies_group = open_group(file_id, "tallies") + call read_dataset(file_id, "tallies_present", int_array(1), indep=.true.) ! Read in sum and sum squared if (int_array(1) == 1) then TALLY_RESULTS: do i = 1, n_tallies - ! Set pointer to tally tally => tallies(i) - curr_key = key_array(id_array(i)) ! Read sum and sum_sq for each bin - call sp % read_tally_result(tally % results, "results", & - group="tallies/tally " // trim(to_str(curr_key)), & - n1=size(tally % results, 1), n2=size(tally % results, 2)) - + tally_group = open_group(tallies_group, "tally " // & + trim(to_str(tally%id))) + call read_dataset(tally_group, "results", tally%results) + call close_group(tally_group) end do TALLY_RESULTS - end if + + call close_group(tallies_group) end if - deallocate(id_array) - deallocate(key_array) ! Read source if in eigenvalue mode if (run_mode == MODE_EIGENVALUE) then @@ -974,32 +814,203 @@ contains if (.not. source_present) then ! Close statepoint file - call sp % file_close() + call file_close(file_id) ! Write message call write_message("Loading source file " // trim(path_source_point) & - &// "...", 1) + // "...", 1) ! Open source file - call sp % file_open(path_source_point, 'r', serial = .false.) + file_id = file_open(path_source_point, 'r', parallel=.true.) ! Read file type - call sp % read_data(int_array(1), "filetype") + call read_dataset(file_id, "filetype", int_array(1)) end if ! Write out source - call sp % read_source_bank() + call read_source_bank(file_id) end if ! Close file - call sp % file_close() + call file_close(file_id) end subroutine load_state_point - subroutine read_source -! TODO write this routine -! TODO what if n_particles does not match source bank - end subroutine read_source +!=============================================================================== +! WRITE_SOURCE_BANK writes OpenMC source_bank data +!=============================================================================== + + subroutine write_source_bank(group_id) + use bank_header, only: Bank + + integer(HID_T), intent(in) :: group_id + + integer :: hdf5_err + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data or file space handle + integer(HID_T) :: memspace ! memory space handle + integer(HSIZE_T) :: offset(1) ! source data offset + integer(HSIZE_T) :: dims(1) + type(c_ptr) :: f_ptr +#ifdef PHDF5 + integer :: data_xfer_mode + integer(HID_T) :: plist ! property list +#else + integer :: i +#ifdef MPI + type(Bank), allocatable, target :: temp_source(:) +#endif +#endif + +#ifdef PHDF5 + ! Set size of total dataspace for all procs and rank + dims(1) = n_particles + call h5screate_simple_f(1, dims, dspace, hdf5_err) + call h5dcreate_f(group_id, "source_bank", hdf5_bank_t, dspace, dset, hdf5_err) + + ! Create another data space but for each proc individually + dims(1) = work + call h5screate_simple_f(1, dims, memspace, hdf5_err) + + ! Select hyperslab for this dataspace + offset(1) = work_index(rank) + call h5sselect_hyperslab_f(dspace, H5S_SELECT_SET_F, offset, dims, hdf5_err) + + ! Set up the property list for parallel writing + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) + + ! Set up pointer to data + f_ptr = c_loc(source_bank) + + ! Write data to file in parallel + call h5dwrite_f(dset, hdf5_bank_t, f_ptr, hdf5_err, & + file_space_id=dspace, mem_space_id=memspace, & + xfer_prp=plist) + + ! Close all ids + call h5sclose_f(dspace, hdf5_err) + call h5sclose_f(memspace, hdf5_err) + call h5dclose_f(dset, hdf5_err) + call h5pclose_f(plist, hdf5_err) + +#else + + if (master) then + ! Create dataset big enough to hold all source sites + dims(1) = n_particles + call h5screate_simple_f(1, dims, dspace, hdf5_err) + call h5dcreate_f(group_id, "source_bank", hdf5_bank_t, & + dspace, dset, hdf5_err) + + ! Save source bank sites since the souce_bank array is overwritten below +#ifdef MPI + allocate(temp_source(work)) + temp_source(:) = source_bank(:) +#endif + + do i = 0, n_procs - 1 + ! Create memory space + dims(1) = work_index(i+1) - work_index(i) + call h5screate_simple_f(1, dims, memspace, hdf5_err) + +#ifdef MPI + ! Receive source sites from other processes + if (i > 0) then + call MPI_RECV(source_bank, int(dims(1)), MPI_BANK, i, i, & + MPI_COMM_WORLD, MPI_STATUS_IGNORE, mpi_err) + end if +#endif + + ! Select hyperslab for this dataspace + call h5dget_space_f(dset, dspace, hdf5_err) + offset(1) = work_index(i) + call h5sselect_hyperslab_f(dspace, H5S_SELECT_SET_F, offset, dims, hdf5_err) + + ! Set up pointer to data and write data to hyperslab + f_ptr = c_loc(source_bank) + call h5dwrite_f(dset, hdf5_bank_t, f_ptr, hdf5_err, & + file_space_id=dspace, mem_space_id=memspace) + + call h5sclose_f(memspace, hdf5_err) + call h5sclose_f(dspace, hdf5_err) + end do + + ! Close all ids + call h5dclose_f(dset, hdf5_err) + + ! Restore state of source bank +#ifdef MPI + source_bank(:) = temp_source(:) + deallocate(temp_source) +#endif + else +#ifdef MPI + call MPI_SEND(source_bank, int(work), MPI_BANK, 0, rank, & + MPI_COMM_WORLD, mpi_err) +#endif + end if + +#endif + + end subroutine write_source_bank + +!=============================================================================== +! READ_SOURCE_BANK reads OpenMC source_bank data +!=============================================================================== + + subroutine read_source_bank(group_id) + use bank_header, only: Bank + + integer(HID_T), intent(in) :: group_id + + integer :: hdf5_err + integer(HID_T) :: dset ! data set handle + integer(HID_T) :: dspace ! data space handle + integer(HID_T) :: memspace ! memory space handle + integer(HSIZE_T) :: dims(1) + integer(HSIZE_T) :: offset(1) ! offset of data + type(c_ptr) :: f_ptr +#ifdef PHDF5 + integer :: data_xfer_mode + integer(HID_T) :: plist ! property list +#endif + + ! Open the dataset + call h5dopen_f(group_id, "source_bank", dset, hdf5_err) + + ! Create another data space but for each proc individually + dims(1) = work + call h5screate_simple_f(1, dims, memspace, hdf5_err) + + ! Select hyperslab for each process + call h5dget_space_f(dset, dspace, hdf5_err) + offset(1) = work_index(rank) + call h5sselect_hyperslab_f(dspace, H5S_SELECT_SET_F, offset, dims, hdf5_err) + + ! Set up pointer to data + f_ptr = c_loc(source_bank) + +#ifdef PHDF5 + ! Read data in parallel + call h5pcreate_f(H5P_DATASET_XFER_F, plist, hdf5_err) + call h5pset_dxpl_mpio_f(plist, H5FD_MPIO_COLLECTIVE_F, hdf5_err) + call h5dread_f(dset, hdf5_bank_t, f_ptr, hdf5_err, & + file_space_id=dspace, mem_space_id=memspace, & + xfer_prp=plist) + call h5pclose_f(plist, hdf5_err) +#else + call h5dread_f(dset, hdf5_bank_t, f_ptr, hdf5_err, & + file_space_id=dspace, mem_space_id=memspace) +#endif + + ! Close all ids + call h5sclose_f(dspace, hdf5_err) + call h5sclose_f(memspace, hdf5_err) + call h5dclose_f(dset, hdf5_err) + + end subroutine read_source_bank + end module state_point diff --git a/src/summary.F90 b/src/summary.F90 new file mode 100644 index 000000000..b93bf120c --- /dev/null +++ b/src/summary.F90 @@ -0,0 +1,669 @@ +module summary + + use ace_header, only: Reaction, UrrData, Nuclide + use constants + use endf, only: reaction_name + use geometry_header, only: Cell, Surface, Universe, Lattice, RectLattice, & + &HexLattice + use global + use hdf5_interface + use material_header, only: Material + use mesh_header, only: RegularMesh + use output, only: time_stamp + use string, only: to_str + use tally_header, only: TallyObject + + use hdf5 + + implicit none + private + + public :: write_summary + +contains + +!=============================================================================== +! WRITE_SUMMARY +!=============================================================================== + + subroutine write_summary() + + integer(HID_T) :: file_id + + ! Create a new file using default properties. + file_id = file_create("summary.h5") + + ! Write header information + call write_header(file_id) + + ! Write number of particles + call write_dataset(file_id, "n_particles", n_particles) + call write_dataset(file_id, "n_batches", n_batches) + call write_attribute_string(file_id, "n_particles", & + "description", "Number of particles per generation") + call write_attribute_string(file_id, "n_batches", & + "description", "Total number of batches") + + ! Write eigenvalue information + if (run_mode == MODE_EIGENVALUE) then + ! write number of inactive/active batches and generations/batch + call write_dataset(file_id, "n_inactive", n_inactive) + call write_dataset(file_id, "n_active", n_active) + call write_dataset(file_id, "gen_per_batch", gen_per_batch) + + ! Add description of each variable + call write_attribute_string(file_id, "n_inactive", & + "description", "Number of inactive batches") + call write_attribute_string(file_id, "n_active", & + "description", "Number of active batches") + call write_attribute_string(file_id, "gen_per_batch", & + "description", "Number of generations per batch") + end if + + call write_geometry(file_id) + call write_materials(file_id) + if (n_tallies > 0) then + call write_tallies(file_id) + end if + + ! Terminate access to the file. + call file_close(file_id) + + end subroutine write_summary + +!=============================================================================== +! WRITE_HEADER +!=============================================================================== + + subroutine write_header(file_id) + integer(HID_T), intent(in) :: file_id + + ! Write filetype and revision + call write_dataset(file_id, "filetype", "summary") + call write_dataset(file_id, "revision", REVISION_SUMMARY) + + ! Write version information + call write_dataset(file_id, "version_major", VERSION_MAJOR) + call write_dataset(file_id, "version_minor", VERSION_MINOR) + call write_dataset(file_id, "version_release", VERSION_RELEASE) + + ! Write current date and time + call write_dataset(file_id, "date_and_time", time_stamp()) + + ! Write MPI information + call write_dataset(file_id, "n_procs", n_procs) + call write_attribute_string(file_id, "n_procs", "description", & + "Number of MPI processes") + + end subroutine write_header + +!=============================================================================== +! WRITE_GEOMETRY +!=============================================================================== + + subroutine write_geometry(file_id) + integer(HID_T), intent(in) :: file_id + + integer :: i, j, k, m + integer, allocatable :: lattice_universes(:,:,:) + integer, allocatable :: surface_ids(:) + integer(HID_T) :: geom_group + integer(HID_T) :: cells_group, cell_group + integer(HID_T) :: surfaces_group, surface_group + integer(HID_T) :: universes_group, univ_group + integer(HID_T) :: lattices_group, lattice_group + type(Cell), pointer :: c + type(Surface), pointer :: s + type(Universe), pointer :: u + class(Lattice), pointer :: lat + + ! Use H5LT interface to write number of geometry objects + geom_group = create_group(file_id, "geometry") + call write_dataset(geom_group, "n_cells", n_cells) + call write_dataset(geom_group, "n_surfaces", n_surfaces) + call write_dataset(geom_group, "n_universes", n_universes) + call write_dataset(geom_group, "n_lattices", n_lattices) + + ! ========================================================================== + ! WRITE INFORMATION ON CELLS + + ! Create a cell group (nothing directly written in this group) then close + cells_group = create_group(geom_group, "cells") + + ! Write information on each cell + CELL_LOOP: do i = 1, n_cells + c => cells(i) + cell_group = create_group(cells_group, "cell " // trim(to_str(c%id))) + + ! Write internal OpenMC index for this cell + call write_dataset(cell_group, "index", i) + + ! Write name for this cell + call write_dataset(cell_group, "name", c%name) + + ! Write universe for this cell + call write_dataset(cell_group, "universe", universes(c%universe)%id) + + ! Write information on what fills this cell + select case (c%type) + case (CELL_NORMAL) + call write_dataset(cell_group, "fill_type", "normal") + if (c%material == MATERIAL_VOID) then + call write_dataset(cell_group, "material", -1) + else + call write_dataset(cell_group, "material", materials(c%material)%id) + end if + + case (CELL_FILL) + call write_dataset(cell_group, "fill_type", "universe") + call write_dataset(cell_group, "fill", universes(c%fill)%id) + if (size(c%offset) > 0) then + call write_dataset(cell_group, "offset", c%offset) + end if + + if (allocated(c%translation)) then + call write_dataset(cell_group, "translation", c%translation) + end if + if (allocated(c%rotation)) then + call write_dataset(cell_group, "rotation", c%rotation) + end if + + case (CELL_LATTICE) + call write_dataset(cell_group, "fill_type", "lattice") + call write_dataset(cell_group, "lattice", lattices(c%fill)%obj%id) + end select + + ! Write list of bounding surfaces + if (c%n_surfaces > 0) then + allocate(surface_ids(c%n_surfaces)) + do j = 1, c%n_surfaces + k = c%surfaces(j) + surface_ids(j) = sign(surfaces(abs(k))%id, k) + end do + call write_dataset(cell_group, "surfaces", surface_ids) + deallocate(surface_ids) + end if + + call close_group(cell_group) + end do CELL_LOOP + + call close_group(cells_group) + + ! ========================================================================== + ! WRITE INFORMATION ON SURFACES + + ! Create surfaces group + surfaces_group = create_group(geom_group, "surfaces") + + ! Write information on each surface + SURFACE_LOOP: do i = 1, n_surfaces + s => surfaces(i) + surface_group = create_group(surfaces_group, "surface " // & + trim(to_str(s%id))) + + ! Write internal OpenMC index for this surface + call write_dataset(surface_group, "index", i) + + ! Write name for this surface + call write_dataset(surface_group, "name", s%name) + + ! Write surface type + select case (s%type) + case (SURF_PX) + call write_dataset(surface_group, "type", "x-plane") + case (SURF_PY) + call write_dataset(surface_group, "type", "y-plane") + case (SURF_PZ) + call write_dataset(surface_group, "type", "z-plane") + case (SURF_PLANE) + call write_dataset(surface_group, "type", "plane") + case (SURF_CYL_X) + call write_dataset(surface_group, "type", "x-cylinder") + case (SURF_CYL_Y) + call write_dataset(surface_group, "type", "y-cylinder") + case (SURF_CYL_Z) + call write_dataset(surface_group, "type", "z-cylinder") + case (SURF_SPHERE) + call write_dataset(surface_group, "type", "sphere") + case (SURF_CONE_X) + call write_dataset(surface_group, "type", "x-cone") + case (SURF_CONE_Y) + call write_dataset(surface_group, "type", "y-cone") + case (SURF_CONE_Z) + call write_dataset(surface_group, "type", "z-cone") + end select + + ! Write coefficients for surface + call write_dataset(surface_group, "coefficients", s%coeffs) + + ! Write boundary condition + select case (s%bc) + case (BC_TRANSMIT) + call write_dataset(surface_group, "boundary_condition", "transmission") + case (BC_VACUUM) + call write_dataset(surface_group, "boundary_condition", "vacuum") + case (BC_REFLECT) + call write_dataset(surface_group, "boundary_condition", "reflective") + case (BC_PERIODIC) + call write_dataset(surface_group, "boundary_condition", "periodic") + end select + + call close_group(surface_group) + end do SURFACE_LOOP + + call close_group(surfaces_group) + + ! ========================================================================== + ! WRITE INFORMATION ON UNIVERSES + + ! Create universes group (nothing directly written here) then close + universes_group = create_group(geom_group, "universes") + + ! Write information on each universe + UNIVERSE_LOOP: do i = 1, n_universes + u => universes(i) + univ_group = create_group(universes_group, "universe " // & + trim(to_str(u%id))) + + ! Write internal OpenMC index for this universe + call write_dataset(univ_group, "index", i) + + ! Write list of cells in this universe + if (u%n_cells > 0) call write_dataset(univ_group, "cells", u%cells) + + call close_group(univ_group) + end do UNIVERSE_LOOP + + call close_group(universes_group) + + ! ========================================================================== + ! WRITE INFORMATION ON LATTICES + + ! Create lattices group (nothing directly written here) then close + lattices_group = create_group(geom_group, "lattices") + + ! Write information on each lattice + LATTICE_LOOP: do i = 1, n_lattices + lat => lattices(i)%obj + lattice_group = create_group(lattices_group, "lattice " // trim(to_str(lat%id))) + + ! Write internal OpenMC index for this lattice + call write_dataset(lattice_group, "index", i) + + ! Write name, pitch, and outer universe + call write_dataset(lattice_group, "name", lat%name) + call write_dataset(lattice_group, "pitch", lat%pitch) + call write_dataset(lattice_group, "outer", lat%outer) + + ! Write distribcell offsets if present + if (size(lat%offset) > 0) then + call write_dataset(lattice_group, "offsets", lat%offset) + end if + + select type (lat) + type is (RectLattice) + ! Write lattice type. + call write_dataset(lattice_group, "type", "rectangular") + + ! Write lattice dimensions, lower left corner, and pitch + call write_dataset(lattice_group, "dimension", lat%n_cells) + call write_dataset(lattice_group, "lower_left", lat%lower_left) + + ! Write lattice universes. + allocate(lattice_universes(lat%n_cells(1), lat%n_cells(2), & + &lat%n_cells(3))) + do j = 1, lat%n_cells(1) + do k = 1, lat%n_cells(2) + do m = 1, lat%n_cells(3) + lattice_universes(j,k,m) = universes(lat%universes(j,k,m))%id + end do + end do + end do + + type is (HexLattice) + ! Write lattice type. + call write_dataset(lattice_group, "type", "hexagonal") + + ! Write number of lattice cells. + call write_dataset(lattice_group, "n_rings", lat%n_rings) + call write_dataset(lattice_group, "n_axial", lat%n_axial) + + ! Write lattice center + call write_dataset(lattice_group, "center", lat%center) + + ! Write lattice universes. + allocate(lattice_universes(2*lat%n_rings - 1, 2*lat%n_rings - 1, & + &lat%n_axial)) + do m = 1, lat%n_axial + do k = 1, 2*lat%n_rings - 1 + do j = 1, 2*lat%n_rings - 1 + if (j + k < lat%n_rings + 1) then + ! This array position is never used; put a -1 to indicate this + lattice_universes(j,k,m) = -1 + cycle + else if (j + k > 3*lat%n_rings - 1) then + ! This array position is never used; put a -1 to indicate this + lattice_universes(j,k,m) = -1 + cycle + end if + lattice_universes(j,k,m) = universes(lat%universes(j,k,m))%id + end do + end do + end do + end select + + ! Write lattice universes + call write_dataset(lattice_group, "universes", lattice_universes) + deallocate(lattice_universes) + + call close_group(lattice_group) + end do LATTICE_LOOP + + call close_group(lattices_group) + call close_group(geom_group) + + end subroutine write_geometry + +!=============================================================================== +! WRITE_MATERIALS +!=============================================================================== + + subroutine write_materials(file_id) + integer(HID_T), intent(in) :: file_id + + integer :: i + integer :: j + integer :: i_list + character(12), allocatable :: nucnames(:) + integer(HID_T) :: materials_group + integer(HID_T) :: material_group + type(Material), pointer :: m + + materials_group = create_group(file_id, "materials") + + ! write number of materials + call write_dataset(file_id, "n_materials", n_materials) + + ! Write information on each material + do i = 1, n_materials + m => materials(i) + material_group = create_group(materials_group, "material " // & + trim(to_str(m%id))) + + ! Write internal OpenMC index for this material + call write_dataset(material_group, "index", i) + + ! Write name for this material + call write_dataset(material_group, "name", m%name) + + ! Write atom density with units + call write_dataset(material_group, "atom_density", m%density) + call write_attribute_string(material_group, "atom_density", "units", & + "atom/b-cm") + + ! Copy ZAID for each nuclide to temporary array + allocate(nucnames(m%n_nuclides)) + do j = 1, m%n_nuclides + i_list = nuclides(m%nuclide(j))%listing + nucnames(j) = xs_listings(i_list)%alias + end do + + ! Write temporary array to 'nuclides' + call write_dataset(material_group, "nuclides", nucnames) + + ! Deallocate temporary array + deallocate(nucnames) + + ! Write atom densities + call write_dataset(material_group, "nuclide_densities", m%atom_density) + + if (m%n_sab > 0) then + call write_dataset(material_group, "sab_names", m%sab_names) + end if + + call close_group(material_group) + end do + + call close_group(materials_group) + + end subroutine write_materials + +!=============================================================================== +! WRITE_TALLIES +!=============================================================================== + + subroutine write_tallies(file_id) + integer(HID_T), intent(in) :: file_id + + integer :: i, j + integer :: i_list, i_xs + integer(HID_T) :: tallies_group + integer(HID_T) :: mesh_group + integer(HID_T) :: tally_group + integer(HID_T) :: filter_group + character(20), allocatable :: str_array(:) + type(RegularMesh), pointer :: m + type(TallyObject), pointer :: t + + tallies_group = create_group(file_id, "tallies") + + ! Write total number of meshes + call write_dataset(tallies_group, "n_meshes", n_meshes) + + ! Write information for meshes + MESH_LOOP: do i = 1, n_meshes + m => meshes(i) + mesh_group = create_group(tallies_group, "mesh " // trim(to_str(m%id))) + + ! Write internal OpenMC index for this mesh + call write_dataset(mesh_group, "index", i) + + ! Write type and number of dimensions + call write_dataset(mesh_group, "type", "regular") + + ! Write mesh information + call write_dataset(mesh_group, "dimension", m%dimension) + call write_dataset(mesh_group, "lower_left", m%lower_left) + call write_dataset(mesh_group, "upper_right", m%upper_right) + call write_dataset(mesh_group, "width", m%width) + + call close_group(mesh_group) + end do MESH_LOOP + + ! Write number of tallies + call write_dataset(tallies_group, "n_tallies", n_tallies) + + TALLY_METADATA: do i = 1, n_tallies + ! Get pointer to tally + t => tallies(i) + tally_group = create_group(tallies_group, "tally " // trim(to_str(t%id))) + + ! Write internal OpenMC index for this tally + call write_dataset(tally_group, "index", i) + + ! Write the name for this tally + call write_dataset(tally_group, "name", t%name) + + ! Write number of filters + call write_dataset(tally_group, "n_filters", t%n_filters) + + FILTER_LOOP: do j = 1, t%n_filters + filter_group = create_group(tally_group, "filter " // trim(to_str(j))) + + ! Write number of bins for this filter + call write_dataset(filter_group, "offset", t%filters(j)%offset) + call write_dataset(filter_group, "n_bins", t%filters(j)%n_bins) + + ! Write filter bins + if (t%filters(j)%type == FILTER_ENERGYIN .or. & + t%filters(j)%type == FILTER_ENERGYOUT) then + call write_dataset(filter_group, "bins", t%filters(j)%real_bins) + else + call write_dataset(filter_group, "bins", t%filters(j)%int_bins) + end if + + ! Write name of type + select case (t%filters(j)%type) + case(FILTER_UNIVERSE) + call write_dataset(filter_group, "type", "universe") + case(FILTER_MATERIAL) + call write_dataset(filter_group, "type", "material") + case(FILTER_CELL) + call write_dataset(filter_group, "type", "cell") + case(FILTER_CELLBORN) + call write_dataset(filter_group, "type", "cellborn") + case(FILTER_SURFACE) + call write_dataset(filter_group, "type", "surface") + case(FILTER_MESH) + call write_dataset(filter_group, "type", "mesh") + case(FILTER_ENERGYIN) + call write_dataset(filter_group, "type", "energy") + case(FILTER_ENERGYOUT) + call write_dataset(filter_group, "type", "energyout") + case(FILTER_DISTRIBCELL) + call write_dataset(filter_group, "type", "distribcell") + end select + + call close_group(filter_group) + end do FILTER_LOOP + + ! Create temporary array for nuclide bins + allocate(str_array(t%n_nuclide_bins)) + NUCLIDE_LOOP: do j = 1, t%n_nuclide_bins + if (t%nuclide_bins(j) > 0) then + i_list = nuclides(t%nuclide_bins(j))%listing + i_xs = index(xs_listings(i_list)%alias, '.') + if (i_xs > 0) then + str_array(j) = xs_listings(i_list)%alias(1:i_xs - 1) + else + str_array(j) = xs_listings(i_list)%alias + end if + else + str_array(j) = 'total' + end if + end do NUCLIDE_LOOP + + ! Write and deallocate nuclide bins + call write_dataset(tally_group, "nuclides", str_array) + deallocate(str_array) + + ! Write number of score bins + call write_dataset(tally_group, "n_score_bins", t%n_score_bins) + allocate(str_array(size(t%score_bins))) + do j = 1, size(t%score_bins) + select case(t%score_bins(j)) + case (SCORE_FLUX) + str_array(j) = "flux" + case (SCORE_TOTAL) + str_array(j) = "total" + case (SCORE_SCATTER) + str_array(j) = "scatter" + case (SCORE_NU_SCATTER) + str_array(j) = "nu-scatter" + case (SCORE_SCATTER_N) + str_array(j) = "scatter-n" + case (SCORE_SCATTER_PN) + str_array(j) = "scatter-pn" + case (SCORE_NU_SCATTER_N) + str_array(j) = "nu-scatter-n" + case (SCORE_NU_SCATTER_PN) + str_array(j) = "nu-scatter-pn" + case (SCORE_TRANSPORT) + str_array(j) = "transport" + case (SCORE_N_1N) + str_array(j) = "n1n" + case (SCORE_ABSORPTION) + str_array(j) = "absorption" + case (SCORE_FISSION) + str_array(j) = "fission" + case (SCORE_NU_FISSION) + str_array(j) = "nu-fission" + case (SCORE_KAPPA_FISSION) + str_array(j) = "kappa-fission" + case (SCORE_CURRENT) + str_array(j) = "current" + case (SCORE_FLUX_YN) + str_array(j) = "flux-yn" + case (SCORE_TOTAL_YN) + str_array(j) = "total-yn" + case (SCORE_SCATTER_YN) + str_array(j) = "scatter-yn" + case (SCORE_NU_SCATTER_YN) + str_array(j) = "nu-scatter-yn" + case (SCORE_EVENTS) + str_array(j) = "events" + case default + str_array(j) = reaction_name(t%score_bins(j)) + end select + end do + call write_dataset(tally_group, "score_bins", str_array) + + deallocate(str_array) + + call close_group(tally_group) + end do TALLY_METADATA + + call close_group(tallies_group) + + end subroutine write_tallies + +!=============================================================================== +! WRITE_TIMING +!=============================================================================== + + subroutine write_timing(file_id) + integer(HID_T), intent(in) :: file_id + + integer(8) :: total_particles + integer(HID_T) :: time_group + real(8) :: speed + + time_group = create_group(file_id, "timing") + + ! Write timing data + call write_dataset(time_group, "time_initialize", time_initialize%elapsed) + call write_dataset(time_group, "time_read_xs", time_read_xs%elapsed) + call write_dataset(time_group, "time_transport", time_transport%elapsed) + call write_dataset(time_group, "time_bank", time_bank%elapsed) + call write_dataset(time_group, "time_bank_sample", time_bank_sample%elapsed) + call write_dataset(time_group, "time_bank_sendrecv", time_bank_sendrecv%elapsed) + call write_dataset(time_group, "time_tallies", time_tallies%elapsed) + call write_dataset(time_group, "time_inactive", time_inactive%elapsed) + call write_dataset(time_group, "time_active", time_active%elapsed) + call write_dataset(time_group, "time_finalize", time_finalize%elapsed) + call write_dataset(time_group, "time_total", time_total%elapsed) + + ! Add descriptions to timing data + call write_attribute_string(time_group, "time_initialize", "description", & + "Total time elapsed for initialization (s)") + call write_attribute_string(time_group, "time_read_xs", "description", & + "Time reading cross-section libraries (s)") + call write_attribute_string(time_group, "time_transport", "description", & + "Time in transport only (s)") + call write_attribute_string(time_group, "time_bank", "description", & + "Total time synchronizing fission bank (s)") + call write_attribute_string(time_group, "time_bank_sample", "description", & + "Time between generations sampling source sites (s)") + call write_attribute_string(time_group, "time_bank_sendrecv", "description", & + "Time between generations SEND/RECVing source sites (s)") + call write_attribute_string(time_group, "time_tallies", "description", & + "Time between batches accumulating tallies (s)") + call write_attribute_string(time_group, "time_inactive", "description", & + "Total time in inactive batches (s)") + call write_attribute_string(time_group, "time_active", "description", & + "Total time in active batches (s)") + call write_attribute_string(time_group, "time_finalize", "description", & + "Total time for finalization (s)") + call write_attribute_string(time_group, "time_total", "description", & + "Total time elapsed (s)") + + ! Write calculation rate + total_particles = n_particles * n_batches * gen_per_batch + speed = real(total_particles) / (time_inactive%elapsed + & + time_active%elapsed) + call write_dataset(time_group, "neutrons_per_second", speed) + + call close_group(time_group) + end subroutine write_timing + +end module summary diff --git a/src/tally.F90 b/src/tally.F90 index e78e58f28..d8ecf4db5 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -9,7 +9,7 @@ module tally use mesh, only: get_mesh_bin, bin_to_mesh_indices, & get_mesh_indices, mesh_indices_to_bin, & mesh_intersects_2d, mesh_intersects_3d - use mesh_header, only: StructuredMesh + use mesh_header, only: RegularMesh use output, only: header use particle_header, only: LocalCoord, Particle use search, only: binary_search @@ -81,8 +81,8 @@ contains case (SCORE_FLUX, SCORE_FLUX_YN) if (t % estimator == ESTIMATOR_ANALOG) then ! All events score to a flux bin. We actually use a collision - ! estimator since there is no way to count 'events' exactly for - ! the flux + ! estimator in place of an analog one since there is no way to count + ! 'events' exactly for the flux if (survival_biasing) then ! We need to account for the fact that some weight was already ! absorbed @@ -92,7 +92,7 @@ contains end if score = score / material_xs % total - else if (t % estimator == ESTIMATOR_TRACKLENGTH) then + else ! For flux, we need no cross section score = flux end if @@ -111,7 +111,7 @@ contains score = p % last_wgt end if - else if (t % estimator == ESTIMATOR_TRACKLENGTH) then + else if (i_nuclide > 0) then score = micro_xs(i_nuclide) % total * atom_density * flux else @@ -129,8 +129,8 @@ contains ! reaction rate score = p % last_wgt - else if (t % estimator == ESTIMATOR_TRACKLENGTH) then - ! Note SCORE_SCATTER_N not available for tracklength. + else + ! Note SCORE_SCATTER_N not available for tracklength/collision. if (i_nuclide > 0) then score = (micro_xs(i_nuclide) % total & - micro_xs(i_nuclide) % absorption) * atom_density * flux @@ -170,10 +170,34 @@ contains ! Only analog estimators are available. ! Skip any event where the particle didn't scatter if (p % event /= EVENT_SCATTER) cycle SCORE_LOOP - ! For scattering production, we need to use the post-collision - ! weight as the estimate for the number of neutrons exiting a - ! reaction with neutrons in the exit channel - score = p % wgt + ! For scattering production, we need to use the pre-collision + ! weight times the multiplicity as the estimate for the number of + ! neutrons exiting a reaction with neutrons in the exit channel + if (p % event_MT == ELASTIC .or. p % event_MT == N_LEVEL .or. & + (p % event_MT >= N_N1 .and. p % event_MT <= N_NC)) then + ! Don't waste time on very common reactions we know have multiplicities + ! of one. + score = p % last_wgt + else + do m = 1, nuclides(p % event_nuclide) % n_reaction + ! Check if this is the desired MT + if (p % event_MT == nuclides(p % event_nuclide) % reactions(m) % MT) then + ! Found the reaction, set our pointer and move on with life + rxn => nuclides(p % event_nuclide) % reactions(m) + exit + end if + end do + + ! Get multiplicity and apply to score + if (rxn % multiplicity_with_E) then + ! Then the multiplicity was already incorporated in to p % wgt + ! per the scattering routine, + score = p % wgt + else + ! Grab the multiplicity from the rxn + score = p % last_wgt * rxn % multiplicity + end if + end if case (SCORE_NU_SCATTER_PN) @@ -183,10 +207,34 @@ contains i = i + t % moment_order(i) cycle SCORE_LOOP end if - ! For scattering production, we need to use the post-collision - ! weight as the estimate for the number of neutrons exiting a - ! reaction with neutrons in the exit channel - score = p % wgt + ! For scattering production, we need to use the pre-collision + ! weight times the multiplicity as the estimate for the number of + ! neutrons exiting a reaction with neutrons in the exit channel + if (p % event_MT == ELASTIC .or. p % event_MT == N_LEVEL .or. & + (p % event_MT >= N_N1 .and. p % event_MT <= N_NC)) then + ! Don't waste time on very common reactions we know have multiplicities + ! of one. + score = p % last_wgt + else + do m = 1, nuclides(p % event_nuclide) % n_reaction + ! Check if this is the desired MT + if (p % event_MT == nuclides(p % event_nuclide) % reactions(m) % MT) then + ! Found the reaction, set our pointer and move on with life + rxn => nuclides(p % event_nuclide) % reactions(m) + exit + end if + end do + + ! Get multiplicity and apply to score + if (rxn % multiplicity_with_E) then + ! Then the multiplicity was already incorporated in to p % wgt + ! per the scattering routine, + score = p % wgt + else + ! Grab the multiplicity from the rxn + score = p % last_wgt * rxn % multiplicity + end if + end if case (SCORE_NU_SCATTER_YN) @@ -196,10 +244,34 @@ contains i = i + (t % moment_order(i) + 1)**2 - 1 cycle SCORE_LOOP end if - ! For scattering production, we need to use the post-collision - ! weight as the estimate for the number of neutrons exiting a - ! reaction with neutrons in the exit channel - score = p % wgt + ! For scattering production, we need to use the pre-collision + ! weight times the multiplicity as the estimate for the number of + ! neutrons exiting a reaction with neutrons in the exit channel + if (p % event_MT == ELASTIC .or. p % event_MT == N_LEVEL .or. & + (p % event_MT >= N_N1 .and. p % event_MT <= N_NC)) then + ! Don't waste time on very common reactions we know have multiplicities + ! of one. + score = p % last_wgt + else + do m = 1, nuclides(p % event_nuclide) % n_reaction + ! Check if this is the desired MT + if (p % event_MT == nuclides(p % event_nuclide) % reactions(m) % MT) then + ! Found the reaction, set our pointer and move on with life + rxn => nuclides(p % event_nuclide) % reactions(m) + exit + end if + end do + + ! Get multiplicity and apply to score + if (rxn % multiplicity_with_E) then + ! Then the multiplicity was already incorporated in to p % wgt + ! per the scattering routine, + score = p % wgt + else + ! Grab the multiplicity from the rxn + score = p % last_wgt * rxn % multiplicity + end if + end if case (SCORE_TRANSPORT) @@ -240,7 +312,7 @@ contains score = p % last_wgt end if - else if (t % estimator == ESTIMATOR_TRACKLENGTH) then + else if (i_nuclide > 0) then score = micro_xs(i_nuclide) % absorption * atom_density * flux else @@ -271,7 +343,7 @@ contains / micro_xs(p % event_nuclide) % absorption end if - else if (t % estimator == ESTIMATOR_TRACKLENGTH) then + else if (i_nuclide > 0) then score = micro_xs(i_nuclide) % fission * atom_density * flux else @@ -314,7 +386,7 @@ contains score = keff * p % wgt_bank end if - else if (t % estimator == ESTIMATOR_TRACKLENGTH) then + else if (i_nuclide > 0) then score = micro_xs(i_nuclide) % nu_fission * atom_density * flux else @@ -347,7 +419,7 @@ contains micro_xs(p % event_nuclide) % absorption end if - else if (t % estimator == ESTIMATOR_TRACKLENGTH) then + else if (i_nuclide > 0) then score = micro_xs(i_nuclide) % kappa_fission * atom_density * flux else @@ -360,6 +432,19 @@ contains ! Simply count number of scoring events score = ONE + case (ELASTIC) + if (t % estimator == ESTIMATOR_ANALOG) then + ! Check if event MT matches + if (p % event_MT /= ELASTIC) cycle SCORE_LOOP + score = p % last_wgt + + else + if (i_nuclide > 0) then + score = micro_xs(i_nuclide) % elastic * atom_density * flux + else + score = material_xs % elastic * flux + end if + end if case default if (t % estimator == ESTIMATOR_ANALOG) then @@ -368,7 +453,7 @@ contains if (p % event_MT /= score_bin) cycle SCORE_LOOP score = p % last_wgt - else if (t % estimator == ESTIMATOR_TRACKLENGTH) then + else ! Any other cross section has to be calculated on-the-fly. For ! cross sections that are used often (e.g. n2n, ngamma, etc. for ! depletion), it might make sense to optimize this section or @@ -484,7 +569,8 @@ contains case(SCORE_FLUX_YN, SCORE_TOTAL_YN) score_index = score_index - 1 num_nm = 1 - if (t % estimator == ESTIMATOR_ANALOG) then + if (t % estimator == ESTIMATOR_ANALOG .or. & + t % estimator == ESTIMATOR_COLLISION) then uvw = p % last_uvw else if (t % estimator == ESTIMATOR_TRACKLENGTH) then uvw = p % coord(1) % uvw @@ -536,6 +622,59 @@ contains end do SCORE_LOOP end subroutine score_general +!=============================================================================== +! SCORE_ALL_NUCLIDES tallies individual nuclide reaction rates specifically when +! the user requests all. +!=============================================================================== + + subroutine score_all_nuclides(p, i_tally, flux, filter_index) + + type(Particle), intent(in) :: p + integer, intent(in) :: i_tally + real(8), intent(in) :: flux + integer, intent(in) :: filter_index + + integer :: i ! loop index for nuclides in material + integer :: i_nuclide ! index in nuclides array + real(8) :: atom_density ! atom density of single nuclide in atom/b-cm + type(TallyObject), pointer :: t + type(Material), pointer :: mat + + ! Get pointer to tally + t => tallies(i_tally) + + ! Get pointer to current material. We need this in order to determine what + ! nuclides are in the material + mat => materials(p % material) + + ! ========================================================================== + ! SCORE ALL INDIVIDUAL NUCLIDE REACTION RATES + + NUCLIDE_LOOP: do i = 1, mat % n_nuclides + + ! Determine index in nuclides array and atom density for i-th nuclide in + ! current material + i_nuclide = mat % nuclide(i) + atom_density = mat % atom_density(i) + + ! Determine score for each bin + call score_general(p, t, (i_nuclide-1)*t % n_score_bins, filter_index, & + i_nuclide, atom_density, flux) + + end do NUCLIDE_LOOP + + ! ========================================================================== + ! SCORE TOTAL MATERIAL REACTION RATES + + i_nuclide = -1 + atom_density = ZERO + + ! Determine score for each bin + call score_general(p, t, n_nuclides_total*t % n_score_bins, filter_index, & + i_nuclide, atom_density, flux) + + end subroutine score_all_nuclides + !=============================================================================== ! SCORE_ANALOG_TALLY keeps track of how many events occur in a specified cell, ! energy range, etc. Note that since these are "analog" tallies, they are only @@ -819,59 +958,6 @@ contains end subroutine score_tracklength_tally -!=============================================================================== -! SCORE_ALL_NUCLIDES tallies individual nuclide reaction rates specifically when -! the user requests all. -!=============================================================================== - - subroutine score_all_nuclides(p, i_tally, flux, filter_index) - - type(Particle), intent(in) :: p - integer, intent(in) :: i_tally - real(8), intent(in) :: flux - integer, intent(in) :: filter_index - - integer :: i ! loop index for nuclides in material - integer :: i_nuclide ! index in nuclides array - real(8) :: atom_density ! atom density of single nuclide in atom/b-cm - type(TallyObject), pointer :: t - type(Material), pointer :: mat - - ! Get pointer to tally - t => tallies(i_tally) - - ! Get pointer to current material. We need this in order to determine what - ! nuclides are in the material - mat => materials(p % material) - - ! ========================================================================== - ! SCORE ALL INDIVIDUAL NUCLIDE REACTION RATES - - NUCLIDE_LOOP: do i = 1, mat % n_nuclides - - ! Determine index in nuclides array and atom density for i-th nuclide in - ! current material - i_nuclide = mat % nuclide(i) - atom_density = mat % atom_density(i) - - ! Determine score for each bin - call score_general(p, t, (i_nuclide-1)*t % n_score_bins, filter_index, & - i_nuclide, atom_density, flux) - - end do NUCLIDE_LOOP - - ! ========================================================================== - ! SCORE TOTAL MATERIAL REACTION RATES - - i_nuclide = -1 - atom_density = ZERO - - ! Determine score for each bin - call score_general(p, t, n_nuclides_total*t % n_score_bins, filter_index, & - i_nuclide, atom_density, flux) - - end subroutine score_all_nuclides - !=============================================================================== ! SCORE_TL_ON_MESH calculate fluxes and reaction rates based on the track-length ! estimate of the flux specifically for tallies that have mesh filters. For @@ -907,7 +993,7 @@ contains logical :: start_in_mesh ! starting coordinates inside mesh? logical :: end_in_mesh ! ending coordinates inside mesh? type(TallyObject), pointer :: t - type(StructuredMesh), pointer :: m + type(RegularMesh), pointer :: m type(Material), pointer :: mat t => tallies(i_tally) @@ -1119,6 +1205,118 @@ contains end subroutine score_tl_on_mesh +!=============================================================================== +! SCORE_COLLISION_TALLY calculates fluxes and reaction rates based on the +! 1/Sigma_t estimate of the flux. This is triggered after every collision. It +! is invalid for tallies that require post-collison information because it can +! score reactions that didn't actually occur, and we don't a priori know what +! the outcome will be for reactions that we didn't sample. +!=============================================================================== + + subroutine score_collision_tally(p) + + type(Particle), intent(in) :: p + + integer :: i + integer :: i_tally + integer :: j ! loop index for scoring bins + integer :: k ! loop index for nuclide bins + integer :: filter_index ! single index for single bin + integer :: i_nuclide ! index in nuclides array (from bins) + real(8) :: flux ! collision estimate of flux + real(8) :: atom_density ! atom density of single nuclide + ! in atom/b-cm + logical :: found_bin ! scoring bin found? + type(TallyObject), pointer :: t + type(Material), pointer :: mat + + ! Determine collision estimate of flux + if (survival_biasing) then + ! We need to account for the fact that some weight was already absorbed + flux = (p % last_wgt + p % absorb_wgt) / material_xs % total + else + flux = p % last_wgt / material_xs % total + end if + + ! A loop over all tallies is necessary because we need to simultaneously + ! determine different filter bins for the same tally in order to score to it + + TALLY_LOOP: do i = 1, active_collision_tallies % size() + ! Get index of tally and pointer to tally + i_tally = active_collision_tallies % get_item(i) + t => tallies(i_tally) + + ! ======================================================================= + ! DETERMINE SCORING BIN COMBINATION + + call get_scoring_bins(p, i_tally, found_bin) + if (.not. found_bin) cycle + + ! ======================================================================= + ! CALCULATE RESULTS AND ACCUMULATE TALLY + + ! If we have made it here, we have a scoring combination of bins for this + ! tally -- now we need to determine where in the results array we should + ! be accumulating the tally values + + ! Determine scoring index for this filter combination + filter_index = sum((matching_bins(1:t%n_filters) - 1) * t % stride) + 1 + + if (t % all_nuclides) then + if (p % material /= MATERIAL_VOID) then + call score_all_nuclides(p, i_tally, flux, filter_index) + end if + else + + NUCLIDE_BIN_LOOP: do k = 1, t % n_nuclide_bins + ! Get index of nuclide in nuclides array + i_nuclide = t % nuclide_bins(k) + + if (i_nuclide > 0) then + if (p % material /= MATERIAL_VOID) then + ! Get pointer to current material + mat => materials(p % material) + + ! Determine if nuclide is actually in material + NUCLIDE_MAT_LOOP: do j = 1, mat % n_nuclides + ! If index of nuclide matches the j-th nuclide listed in the + ! material, break out of the loop + if (i_nuclide == mat % nuclide(j)) exit + + ! If we've reached the last nuclide in the material, it means + ! the specified nuclide to be tallied is not in this material + if (j == mat % n_nuclides) then + cycle NUCLIDE_BIN_LOOP + end if + end do NUCLIDE_MAT_LOOP + + atom_density = mat % atom_density(j) + else + atom_density = ZERO + end if + end if + + ! Determine score for each bin + call score_general(p, t, (k-1)*t % n_score_bins, filter_index, & + i_nuclide, atom_density, flux) + + end do NUCLIDE_BIN_LOOP + end if + + ! If the user has specified that we can assume all tallies are spatially + ! separate, this implies that once a tally has been scored to, we needn't + ! check the others. This cuts down on overhead when there are many + ! tallies specified + + if (assume_separate) exit TALLY_LOOP + + end do TALLY_LOOP + + ! Reset tally map positioning + position = 0 + + end subroutine score_collision_tally + !=============================================================================== ! GET_SCORING_BINS determines a combination of filter bins that should be scored ! for a tally based on the particle's current attributes. @@ -1136,7 +1334,7 @@ contains integer :: offset ! offset for distribcell real(8) :: E ! particle energy type(TallyObject), pointer :: t - type(StructuredMesh), pointer :: m + type(RegularMesh), pointer :: m found_bin = .true. t => tallies(i_tally) @@ -1289,7 +1487,7 @@ contains logical :: y_same ! same starting/ending y index (j) logical :: z_same ! same starting/ending z index (k) type(TallyObject), pointer :: t - type(StructuredMesh), pointer :: m + type(RegularMesh), pointer :: m TALLY_LOOP: do i = 1, active_current_tallies % size() ! Copy starting and ending location of particle @@ -1873,6 +2071,8 @@ contains call active_analog_tallies % add(i_user_tallies + i) elseif (user_tallies(i) % estimator == ESTIMATOR_TRACKLENGTH) then call active_tracklength_tallies % add(i_user_tallies + i) + elseif (user_tallies(i) % estimator == ESTIMATOR_COLLISION) then + call active_collision_tallies % add(i_user_tallies + i) end if elseif (user_tallies(i) % type == TALLY_SURFACE_CURRENT) then call active_current_tallies % add(i_user_tallies + i) diff --git a/src/tally_header.F90 b/src/tally_header.F90 index d20c3fea2..ca4e25fd8 100644 --- a/src/tally_header.F90 +++ b/src/tally_header.F90 @@ -2,6 +2,7 @@ module tally_header use constants, only: NONE, N_FILTER_TYPES use trigger_header, only: TriggerObject + use, intrinsic :: ISO_C_BINDING implicit none @@ -39,10 +40,10 @@ module tally_header ! TALLYRESULT provides accumulation of results in a particular tally bin !=============================================================================== - type TallyResult - real(8) :: value = 0. - real(8) :: sum = 0. - real(8) :: sum_sq = 0. + type, bind(C) :: TallyResult + real(C_DOUBLE) :: value = 0. + real(C_DOUBLE) :: sum = 0. + real(C_DOUBLE) :: sum_sq = 0. end type TallyResult !=============================================================================== diff --git a/src/track_output.F90 b/src/track_output.F90 index 6ab514cdb..1665ac25e 100644 --- a/src/track_output.F90 +++ b/src/track_output.F90 @@ -6,19 +6,27 @@ module track_output use global - use output_interface, only: BinaryOutput + use hdf5_interface use particle_header, only: Particle use string, only: to_str - implicit none + use hdf5 - type, private :: TrackCoordinates + implicit none + private + + type TrackCoordinates real(8), allocatable :: coords(:,:) end type TrackCoordinates - type(TrackCoordinates), private, allocatable :: tracks(:) + type(TrackCoordinates), allocatable :: tracks(:) !$omp threadprivate(tracks) + public :: initialize_particle_track + public :: write_particle_track + public :: add_particle_track + public :: finalize_particle_track + contains !=============================================================================== @@ -43,19 +51,19 @@ contains ! Add another column to coords i = size(tracks) - if (allocated(tracks(i) % coords)) then - n_tracks = size(tracks(i) % coords, 2) + if (allocated(tracks(i)%coords)) then + n_tracks = size(tracks(i)%coords, 2) allocate(new_coords(3, n_tracks + 1)) - new_coords(:, 1:n_tracks) = tracks(i) % coords - call move_alloc(FROM=new_coords, TO=tracks(i) % coords) + new_coords(:, 1:n_tracks) = tracks(i)%coords + call move_alloc(FROM=new_coords, TO=tracks(i)%coords) else n_tracks = 0 - allocate(tracks(i) % coords(3, 1)) + allocate(tracks(i)%coords(3, 1)) end if ! Write current coordinates into the newest column. n_tracks = n_tracks + 1 - tracks(i) % coords(:, n_tracks) = p % coord(1) % xyz + tracks(i)%coords(:, n_tracks) = p%coord(1)%xyz end subroutine write_particle_track !=============================================================================== @@ -87,41 +95,34 @@ contains subroutine finalize_particle_track(p) type(Particle), intent(in) :: p - integer :: length(2) - character(MAX_FILE_LEN) :: fname - type(BinaryOutput) :: binout - integer :: i - integer, allocatable :: n_coords(:) integer :: n_particle_tracks + integer(HID_T) :: file_id + character(MAX_FILE_LEN) :: fname + integer, allocatable :: n_coords(:) -#ifdef HDF5 fname = trim(path_output) // 'track_' // trim(to_str(current_batch)) & - // '_' // trim(to_str(current_gen)) // '_' // trim(to_str(p % id)) & + // '_' // trim(to_str(current_gen)) // '_' // trim(to_str(p%id)) & // '.h5' -#else - fname = trim(path_output) // 'track_' // trim(to_str(current_batch)) & - // '_' // trim(to_str(current_gen)) // '_' // trim(to_str(p % id)) & - // '.binary' -#endif ! Determine total number of particles and number of coordinates for each n_particle_tracks = size(tracks) allocate(n_coords(n_particle_tracks)) do i = 1, n_particle_tracks - n_coords(i) = size(tracks(i) % coords, 2) + n_coords(i) = size(tracks(i)%coords, 2) end do !$omp critical (FinalizeParticleTrack) - call binout % file_create(fname) - call binout % write_data(n_particle_tracks, 'n_particles') - call binout % write_data(n_coords, 'n_coords', length=n_particle_tracks) + file_id = file_create(fname) + call write_dataset(file_id, 'filetype', 'track') + call write_dataset(file_id, 'revision', REVISION_TRACK) + call write_dataset(file_id, 'n_particles', n_particle_tracks) + call write_dataset(file_id, 'n_coords', n_coords) do i = 1, n_particle_tracks - length(:) = [3, n_coords(i)] - call binout % write_data(tracks(i) % coords, 'coordinates_' // & - trim(to_str(i)), length=length) + call write_dataset(file_id, 'coordinates_' // trim(to_str(i)), & + tracks(i)%coords) end do - call binout % file_close() + call file_close(file_id) !$omp end critical (FinalizeParticleTrack) deallocate(tracks) end subroutine finalize_particle_track diff --git a/src/tracking.F90 b/src/tracking.F90 index 173babd2f..81f01b411 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -13,7 +13,7 @@ module tracking use random_lcg, only: prn use string, only: to_str use tally, only: score_analog_tally, score_tracklength_tally, & - score_surface_current + score_collision_tally, score_surface_current use track_output, only: initialize_particle_track, write_particle_track, & add_particle_track, finalize_particle_track @@ -157,6 +157,7 @@ contains ! has occurred rather than before because we need information on the ! outgoing energy for any tallies with an outgoing energy filter + if (active_collision_tallies % size() > 0) call score_collision_tally(p) if (active_analog_tallies % size() > 0) call score_analog_tally(p) ! Reset banked weight during collision diff --git a/src/trigger.F90 b/src/trigger.F90 index 4a16cd5ca..a74a64be0 100644 --- a/src/trigger.F90 +++ b/src/trigger.F90 @@ -9,6 +9,7 @@ module trigger use string, only: to_str use output, only: warning, write_message use mesh, only: mesh_indices_to_bin + use mesh_header, only: RegularMesh use trigger_header, only: TriggerObject use tally, only: TallyObject @@ -315,7 +316,7 @@ contains real(8) :: std_dev = ZERO ! temporary standard deviration of result type(TallyObject), pointer :: t ! surface current tally type(TriggerObject) :: trigger ! surface current tally trigger - type(StructuredMesh), pointer :: m ! surface current mesh + type(RegularMesh), pointer :: m ! surface current mesh ! Get pointer to mesh i_filter_mesh = t % find_filter(FILTER_MESH) diff --git a/tests/cleanup b/tests/cleanup index 7b81d2d9d..3369c797e 100755 --- a/tests/cleanup +++ b/tests/cleanup @@ -5,6 +5,6 @@ # folders. This can occur if a previous error # occurred and the test suite was rerun without # deleting left over binary files. This will -# cause an assertion error in some of the +# cause an assertion error in some of the # tests. -find . \( -name "*.binary" -o -name "*.h5" -o -name "*.ppm" \) -exec rm -f {} \; +find . \( -name "*.h5" -o -name "*.ppm" \) -exec rm -f {} \; diff --git a/tests/run_tests.py b/tests/run_tests.py index 3550ad7cb..d3b79aa3b 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -107,13 +107,13 @@ tests = OrderedDict() class Test(object): def __init__(self, name, debug=False, optimize=False, mpi=False, openmp=False, - hdf5=False, valgrind=False, coverage=False): + phdf5=False, valgrind=False, coverage=False): self.name = name self.debug = debug self.optimize = optimize self.mpi = mpi self.openmp = openmp - self.hdf5 = hdf5 + self.phdf5 = phdf5 self.valgrind = valgrind self.coverage = coverage self.success = True @@ -124,13 +124,9 @@ class Test(object): self.cmake = ['cmake', '-H..', '-Bbuild', '-DPYTHON_EXECUTABLE=' + sys.executable] - # Check for MPI/HDF5 - if self.mpi and not self.hdf5: - self.fc = MPI_DIR+'/bin/mpif90' - elif not self.mpi and self.hdf5: - self.fc = HDF5_DIR+'/bin/h5fc' - elif self.mpi and self.hdf5: - self.fc = PHDF5_DIR+'/bin/h5pfc' + # Check for MPI + if self.mpi: + self.fc = os.path.join(MPI_DIR, 'bin', 'mpifort') else: self.fc = FC @@ -164,6 +160,10 @@ class Test(object): os.environ['FC'] = self.fc if self.mpi: os.environ['MPI_DIR'] = MPI_DIR + if self.phdf5: + os.environ['HDF5_ROOT'] = PHDF5_DIR + else: + os.environ['HDF5_ROOT'] = HDF5_DIR rc = call(['ctest', '-S', 'ctestscript.run','-V']) if rc != 0: self.success = False @@ -174,6 +174,10 @@ class Test(object): os.environ['FC'] = self.fc if self.mpi: os.environ['MPI_DIR'] = MPI_DIR + if self.phdf5: + os.environ['HDF5_ROOT'] = PHDF5_DIR + else: + os.environ['HDF5_ROOT'] = HDF5_DIR build_opts = self.build_opts.split() self.cmake += build_opts rc = call(self.cmake) @@ -263,41 +267,29 @@ class Test(object): # Simple function to add a test to the global tests dictionary def add_test(name, debug=False, optimize=False, mpi=False, openmp=False,\ - hdf5=False, valgrind=False, coverage=False): - tests.update({name: Test(name, debug, optimize, mpi, openmp, hdf5, + phdf5=False, valgrind=False, coverage=False): + tests.update({name: Test(name, debug, optimize, mpi, openmp, phdf5, valgrind, coverage)}) # List of all tests that may be run. User can add -C to command line to specify # a subset of these configurations -add_test('basic-normal') -add_test('basic-debug', debug=True) -add_test('basic-optimize', optimize=True) -add_test('omp-normal', openmp=True) -add_test('omp-debug', openmp=True, debug=True) -add_test('omp-optimize', openmp=True, optimize=True) -add_test('hdf5-normal', hdf5=True) -add_test('hdf5-debug', hdf5=True, debug=True) -add_test('hdf5-optimize', hdf5=True, optimize=True) -add_test('omp-hdf5-normal', openmp=True, hdf5=True) -add_test('omp-hdf5-debug', openmp=True, hdf5=True, debug=True) -add_test('omp-hdf5-optimize', openmp=True, hdf5=True, optimize=True) -add_test('mpi-normal', mpi=True) -add_test('mpi-debug', mpi=True, debug=True) -add_test('mpi-optimize', mpi=True, optimize=True) -add_test('mpi-omp-normal', mpi=True, openmp=True) -add_test('mpi-omp-debug', mpi=True, openmp=True, debug=True) -add_test('mpi-omp-optimize', mpi=True, openmp=True, optimize=True) -add_test('phdf5-normal', mpi=True, hdf5=True) -add_test('phdf5-debug', mpi=True, hdf5=True, debug=True) -add_test('phdf5-optimize', mpi=True, hdf5=True, optimize=True) -add_test('phdf5-omp-normal', mpi=True, hdf5=True, openmp=True) -add_test('phdf5-omp-debug', mpi=True, hdf5=True, openmp=True, debug=True) -add_test('phdf5-omp-optimize', mpi=True, hdf5=True, openmp=True, optimize=True) -add_test('basic-debug_valgrind', debug=True, valgrind=True) -add_test('hdf5-debug_valgrind', hdf5=True, debug=True, valgrind=True) -add_test('basic-debug_coverage', debug=True, coverage=True) -add_test('hdf5-debug_coverage', debug=True, hdf5=True, coverage=True) -add_test('mpi-debug_coverage', debug=True, mpi=True, coverage=True) +add_test('hdf5-normal') +add_test('hdf5-debug', debug=True) +add_test('hdf5-optimize', optimize=True) +add_test('omp-hdf5-normal', openmp=True) +add_test('omp-hdf5-debug', openmp=True, debug=True) +add_test('omp-hdf5-optimize', openmp=True, optimize=True) +add_test('mpi-hdf5-normal', mpi=True) +add_test('mpi-hdf5-debug', mpi=True, debug=True) +add_test('mpi-hdf5-optimize', mpi=True, optimize=True) +add_test('phdf5-normal', mpi=True, phdf5=True) +add_test('phdf5-debug', mpi=True, phdf5=True, debug=True) +add_test('phdf5-optimize', mpi=True, phdf5=True, optimize=True) +add_test('phdf5-omp-normal', mpi=True, phdf5=True, openmp=True) +add_test('phdf5-omp-debug', mpi=True, phdf5=True, openmp=True, debug=True) +add_test('phdf5-omp-optimize', mpi=True, phdf5=True, openmp=True, optimize=True) +add_test('hdf5-debug_valgrind', debug=True, valgrind=True) +add_test('hdf5-debug_coverage', debug=True, coverage=True) # Check to see if we should just print build configuration information to user if options.list_build_configs: @@ -305,7 +297,6 @@ if options.list_build_configs: print('Configuration Name: {0}'.format(key)) print(' Debug Flags:..........{0}'.format(tests[key].debug)) print(' Optimization Flags:...{0}'.format(tests[key].optimize)) - print(' HDF5 Active:..........{0}'.format(tests[key].hdf5)) print(' MPI Active:...........{0}'.format(tests[key].mpi)) print(' OpenMP Active:........{0}'.format(tests[key].openmp)) print(' Valgrind Test:........{0}'.format(tests[key].valgrind)) diff --git a/tests/test_cmfd_feed/results_true.dat b/tests/test_cmfd_feed/results_true.dat index 26380d403..9c109db6a 100644 --- a/tests/test_cmfd_feed/results_true.dat +++ b/tests/test_cmfd_feed/results_true.dat @@ -1,128 +1,128 @@ k-combined: -1.172666E+00 8.502438E-03 +1.168349E+00 1.145333E-02 tally 1: -1.170812E+01 -1.376785E+01 -2.179886E+01 -4.765478E+01 -2.945614E+01 -8.709999E+01 -3.527293E+01 -1.245879E+02 -3.829349E+01 -1.470691E+02 -3.709040E+01 -1.379455E+02 -3.380335E+01 -1.145311E+02 -2.801351E+01 -7.871047E+01 -2.029625E+01 -4.131602E+01 -1.084302E+01 -1.180329E+01 +1.167844E+01 +1.366808E+01 +2.141846E+01 +4.598143E+01 +2.928738E+01 +8.615095E+01 +3.513015E+01 +1.241914E+02 +3.715164E+01 +1.384553E+02 +3.639309E+01 +1.327919E+02 +3.370872E+01 +1.138391E+02 +2.875251E+01 +8.292323E+01 +2.117740E+01 +4.512961E+01 +1.130554E+01 +1.289872E+01 tally 2: -2.270565E+01 -2.599927E+01 -1.590852E+01 -1.276260E+01 -2.252857E+00 -2.614120E-01 -4.313167E+01 -9.326539E+01 -3.044479E+01 -4.648169E+01 -4.023051E+00 -8.172006E-01 -5.859113E+01 -1.725665E+02 -4.171599E+01 -8.755981E+01 -5.512216E+00 -1.531207E+00 -6.892516E+01 -2.383198E+02 -4.904413E+01 -1.207096E+02 -6.542718E+00 -2.155749E+00 -7.421495E+01 -2.764539E+02 -5.288881E+01 -1.405388E+02 -6.811354E+00 -2.358827E+00 -7.278191E+01 -2.661597E+02 -5.169924E+01 -1.343999E+02 -6.516967E+00 -2.148745E+00 -6.655238E+01 -2.222812E+02 -4.729758E+01 -1.123214E+02 -6.102046E+00 -1.890147E+00 -5.708495E+01 -1.636585E+02 -4.068603E+01 -8.317681E+01 -5.394757E+00 -1.465413E+00 -4.136562E+01 -8.598520E+01 -2.958591E+01 -4.402226E+01 -3.765802E+00 -7.200302E-01 -2.275517E+01 -2.614738E+01 -1.589295E+01 -1.276624E+01 -2.232715E+00 -2.558645E-01 +2.339531E+01 +2.755922E+01 +1.646762E+01 +1.365289E+01 +2.146174E+00 +2.369613E-01 +4.309769E+01 +9.312913E+01 +3.054873E+01 +4.681242E+01 +4.076365E+00 +8.462370E-01 +5.840647E+01 +1.715260E+02 +4.161366E+01 +8.713062E+01 +5.382541E+00 +1.473814E+00 +6.927641E+01 +2.411359E+02 +4.943841E+01 +1.228850E+02 +6.282202E+00 +1.990021E+00 +7.308593E+01 +2.678848E+02 +5.202069E+01 +1.357621E+02 +6.826145E+00 +2.353974E+00 +7.117026E+01 +2.543546E+02 +5.068896E+01 +1.290261E+02 +6.342979E+00 +2.033850E+00 +6.615720E+01 +2.193712E+02 +4.725156E+01 +1.119514E+02 +6.024815E+00 +1.833752E+00 +5.738164E+01 +1.651944E+02 +4.081217E+01 +8.360122E+01 +5.326191E+00 +1.435896E+00 +4.208669E+01 +8.911740E+01 +2.994944E+01 +4.517409E+01 +3.905846E+00 +7.855247E-01 +2.273578E+01 +2.615080E+01 +1.603853E+01 +1.303560E+01 +2.160924E+00 +2.473278E-01 tally 3: -1.529144E+01 -1.179942E+01 -1.023883E+00 -5.386625E-02 -2.936854E+01 -4.326483E+01 -1.881629E+00 -1.788063E-01 -4.015056E+01 -8.114284E+01 -2.594958E+00 -3.407980E-01 -4.720593E+01 -1.118311E+02 -3.161769E+00 -5.053887E-01 -5.095790E+01 -1.304930E+02 -3.308202E+00 -5.528151E-01 -4.979520E+01 -1.246892E+02 -3.163884E+00 -5.062497E-01 -4.554330E+01 -1.041770E+02 -3.019145E+00 -4.618487E-01 -3.921119E+01 -7.727273E+01 -2.472070E+00 -3.099171E-01 -2.843166E+01 -4.067093E+01 -1.823607E+00 -1.688171E-01 -1.530477E+01 -1.184246E+01 -1.047996E+00 -5.549017E-02 +1.584939E+01 +1.265206E+01 +1.096930E+00 +6.173135E-02 +2.940258E+01 +4.337818E+01 +1.932931E+00 +1.884749E-01 +4.008186E+01 +8.086427E+01 +2.512704E+00 +3.189987E-01 +4.759648E+01 +1.139252E+02 +3.041630E+00 +4.683237E-01 +5.006181E+01 +1.257467E+02 +3.137042E+00 +4.981005E-01 +4.883211E+01 +1.197646E+02 +3.130686E+00 +4.987337E-01 +4.550029E+01 +1.038199E+02 +2.853740E+00 +4.127265E-01 +3.937822E+01 +7.785807E+01 +2.488983E+00 +3.156421E-01 +2.884912E+01 +4.192640E+01 +1.855316E+00 +1.745109E-01 +1.543635E+01 +1.208459E+01 +1.025635E+00 +5.351565E-02 tally 4: 0.000000E+00 0.000000E+00 @@ -160,8 +160,8 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -3.111592E+00 -4.883699E-01 +3.119914E+00 +4.908283E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -208,10 +208,10 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.536088E+00 -1.540676E+00 -2.727975E+00 -3.757452E-01 +5.567786E+00 +1.556825E+00 +2.766088E+00 +3.864023E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -256,10 +256,10 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.518115E+00 -2.840502E+00 -5.271874E+00 -1.398895E+00 +7.491891E+00 +2.819491E+00 +5.235154E+00 +1.377898E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -304,10 +304,10 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.764240E+00 -3.855378E+00 -7.176540E+00 -2.591613E+00 +8.810357E+00 +3.898704E+00 +7.233068E+00 +2.630659E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -352,10 +352,10 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.381092E+00 -4.414024E+00 -8.597689E+00 -3.710217E+00 +9.374583E+00 +4.414420E+00 +8.565683E+00 +3.687428E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -400,10 +400,10 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.158655E+00 -4.215178E+00 -9.188880E+00 -4.244766E+00 +9.001252E+00 +4.073267E+00 +8.974821E+00 +4.050120E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -448,10 +448,10 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.362511E+00 -3.509173E+00 -9.159213E+00 -4.209143E+00 +8.236452E+00 +3.401934E+00 +9.042286E+00 +4.102906E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -496,10 +496,10 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.029505E+00 -2.479106E+00 -8.613258E+00 -3.719199E+00 +7.028546E+00 +2.482380E+00 +8.577643E+00 +3.691947E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -544,10 +544,10 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.119892E+00 -1.320586E+00 -7.401001E+00 -2.749355E+00 +5.159585E+00 +1.342512E+00 +7.389236E+00 +2.745028E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -592,10 +592,10 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.765680E+00 -3.903229E-01 -5.461998E+00 -1.501206E+00 +2.762685E+00 +3.914181E-01 +5.471849E+00 +1.509910E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -642,8 +642,8 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -3.044921E+00 -4.656739E-01 +3.038522E+00 +4.643520E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -662,114 +662,114 @@ k cmfd 0.000000E+00 0.000000E+00 0.000000E+00 -1.177990E+00 -1.160010E+00 -1.155990E+00 -1.160167E+00 -1.162166E+00 -1.161566E+00 -1.164454E+00 -1.166269E+00 -1.168529E+00 -1.168622E+00 -1.170296E+00 -1.168644E+00 -1.172975E+00 -1.176543E+00 -1.173389E+00 -1.178422E+00 +1.180802E+00 +1.162698E+00 +1.162794E+00 +1.159752E+00 +1.152596E+00 +1.151652E+00 +1.148131E+00 +1.151875E+00 +1.151434E+00 +1.158833E+00 +1.160751E+00 +1.155305E+00 +1.155356E+00 +1.158866E+00 +1.161574E+00 +1.154691E+00 cmfd entropy 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.214145E+00 -3.225292E+00 -3.229509E+00 -3.228530E+00 -3.224203E+00 -3.225547E+00 -3.224720E+00 -3.224546E+00 -3.224527E+00 -3.223579E+00 -3.224380E+00 -3.223483E+00 -3.222819E+00 -3.223067E+00 -3.224007E+00 -3.220616E+00 +3.214195E+00 +3.225164E+00 +3.227316E+00 +3.225663E+00 +3.226390E+00 +3.225832E+00 +3.226707E+00 +3.227866E+00 +3.229948E+00 +3.229269E+00 +3.230044E+00 +3.231568E+00 +3.234694E+00 +3.234771E+00 +3.234915E+00 +3.235876E+00 cmfd balance 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -4.801684E-03 -2.802571E-03 -1.828029E-03 -2.220542E-03 -1.709900E-03 -2.008246E-03 -2.578373E-03 -2.000076E-03 -1.645365E-03 -1.462882E-03 -1.208273E-03 -1.146126E-03 -1.214196E-03 -1.082376E-03 -8.967163E-04 -1.154433E-03 +4.742525E-03 +2.646417E-03 +1.981783E-03 +1.856593E-03 +1.797685E-03 +2.122587E-03 +1.200823E-03 +2.177249E-03 +1.442840E-03 +1.477754E-03 +1.236325E-03 +1.048988E-03 +8.395164E-04 +7.380254E-04 +7.742837E-04 +8.235911E-04 cmfd dominance ratio 0.000E+00 0.000E+00 0.000E+00 0.000E+00 - 5.472E-01 - 5.521E-01 - 5.445E-01 - 5.527E-01 + 5.467E-01 + 5.518E-01 + 5.535E-01 + 5.500E-01 + 5.481E-01 + 5.478E-01 + 5.467E-01 + 5.465E-01 + 5.493E-01 5.488E-01 - 5.078E-01 - 5.474E-01 - 5.475E-01 - 5.473E-01 - 5.469E-01 - 5.461E-01 - 5.455E-01 - 5.454E-01 - 5.459E-01 - 5.460E-01 - 5.432E-01 + 5.491E-01 + 5.503E-01 + 5.529E-01 + 5.531E-01 + 5.534E-01 + 5.552E-01 cmfd openmc source comparison 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -9.186654E-03 -6.033650E-03 -3.920380E-03 -4.218939E-03 -4.591972E-03 -4.042772E-03 -4.100500E-03 -3.664495E-03 -3.266803E-03 -3.164213E-03 -3.310474E-03 -3.165822E-03 -3.849586E-03 -2.718170E-03 -2.431480E-03 -3.322902E-03 +9.168094E-03 +5.978693E-03 +4.369223E-03 +4.546309E-03 +4.222522E-03 +4.221686E-03 +4.604208E-03 +3.950286E-03 +2.939283E-03 +3.667020E-03 +2.592899E-03 +2.272158E-03 +1.229170E-03 +1.114150E-03 +1.060490E-03 +1.714222E-03 cmfd source -4.296288E-02 -7.964357E-02 -1.107722E-01 -1.359821E-01 -1.425321E-01 -1.356719E-01 -1.285829E-01 -1.040603E-01 -7.630230E-02 -4.348975E-02 +4.724285E-02 +8.305825E-02 +1.081058E-01 +1.314542E-01 +1.357299E-01 +1.359417E-01 +1.240918E-01 +1.087580E-01 +8.111239E-02 +4.450518E-02 diff --git a/tests/test_cmfd_feed/tallies.xml b/tests/test_cmfd_feed/tallies.xml index b20c0ad61..37edcecc2 100644 --- a/tests/test_cmfd_feed/tallies.xml +++ b/tests/test_cmfd_feed/tallies.xml @@ -2,7 +2,7 @@ - rectangular + regular -10 -1 -1 10 1 1 10 1 1 diff --git a/tests/test_cmfd_nofeed/results_true.dat b/tests/test_cmfd_nofeed/results_true.dat index e70287bf7..308dd7d82 100644 --- a/tests/test_cmfd_nofeed/results_true.dat +++ b/tests/test_cmfd_nofeed/results_true.dat @@ -83,44 +83,44 @@ tally 2: 2.336090E+00 2.851840E-01 tally 3: -1.523800E+01 -1.170551E+01 +1.524100E+01 +1.171023E+01 1.071050E+00 5.839198E-02 -2.862100E+01 -4.111143E+01 +2.862800E+01 +4.113148E+01 1.892774E+00 1.812712E-01 -3.804200E+01 -7.314552E+01 +3.804600E+01 +7.316097E+01 2.423654E+00 2.968521E-01 -4.433500E+01 -9.878201E+01 +4.434600E+01 +9.882906E+01 2.823929E+00 4.033633E-01 -4.954300E+01 -1.229796E+02 +4.955300E+01 +1.230293E+02 3.226029E+00 5.265680E-01 -4.999000E+01 -1.256279E+02 +4.999400E+01 +1.256474E+02 3.232464E+00 5.286388E-01 -4.723500E+01 -1.120638E+02 +4.724300E+01 +1.121029E+02 3.015553E+00 4.606928E-01 -4.050800E+01 -8.237529E+01 +4.051300E+01 +8.239672E+01 2.592073E+00 3.412174E-01 -2.911800E+01 -4.263022E+01 +2.912700E+01 +4.265700E+01 1.875109E+00 1.785438E-01 -1.592800E+01 -1.279461E+01 +1.593500E+01 +1.280638E+01 1.038638E+00 5.538157E-02 tally 4: @@ -662,114 +662,114 @@ k cmfd 0.000000E+00 0.000000E+00 0.000000E+00 -1.177990E+00 -1.160491E+00 -1.145875E+00 -1.148719E+00 -1.140676E+00 -1.141509E+00 -1.143597E+00 -1.141954E+00 -1.150311E+00 -1.155088E+00 -1.155464E+00 -1.152786E+00 -1.156950E+00 -1.159040E+00 -1.160571E+00 -1.161251E+00 +1.180802E+00 +1.163440E+00 +1.148572E+00 +1.151423E+00 +1.143374E+00 +1.144091E+00 +1.146212E+00 +1.144900E+00 +1.153511E+00 +1.158766E+00 +1.159179E+00 +1.156627E+00 +1.160647E+00 +1.162860E+00 +1.164312E+00 +1.164928E+00 cmfd entropy 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.214145E+00 -3.222082E+00 -3.225870E+00 -3.230292E+00 -3.228784E+00 -3.228863E+00 -3.228331E+00 -3.230222E+00 -3.231212E+00 -3.230979E+00 -3.229831E+00 -3.229258E+00 -3.228559E+00 -3.227915E+00 -3.227427E+00 -3.229561E+00 +3.214195E+00 +3.222259E+00 +3.225989E+00 +3.230436E+00 +3.228875E+00 +3.229003E+00 +3.228502E+00 +3.230397E+00 +3.231417E+00 +3.231192E+00 +3.229995E+00 +3.229396E+00 +3.228730E+00 +3.228091E+00 +3.227600E+00 +3.229723E+00 cmfd balance 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -4.801684E-03 -3.228380E-03 -2.568997E-03 -2.195796E-03 -2.248884E-03 -3.405416E-03 -2.332198E-03 -2.576061E-03 -2.326651E-03 -2.324425E-03 -2.205364E-03 -2.112702E-03 -1.864656E-03 -1.804877E-03 -1.557106E-03 -1.312058E-03 +4.742525E-03 +3.110598E-03 +2.490108E-03 +2.114137E-03 +2.190200E-03 +3.281877E-03 +2.219193E-03 +2.458372E-03 +2.200863E-03 +2.181858E-03 +2.064212E-03 +1.961178E-03 +1.713250E-03 +1.665361E-03 +1.436016E-03 +1.193462E-03 cmfd dominance ratio 0.000E+00 0.000E+00 0.000E+00 0.000E+00 - 5.472E-01 - 5.510E-01 - 5.519E-01 - 5.535E-01 - 5.535E-01 + 5.467E-01 5.505E-01 - 5.488E-01 - 5.505E-01 - 5.510E-01 - 5.513E-01 - 5.510E-01 + 5.514E-01 + 5.531E-01 + 5.529E-01 + 5.501E-01 + 5.484E-01 + 5.500E-01 + 5.506E-01 5.508E-01 - 5.487E-01 - 5.489E-01 - 5.481E-01 - 5.499E-01 + 5.504E-01 + 5.500E-01 + 5.480E-01 + 5.482E-01 + 5.475E-01 + 5.493E-01 cmfd openmc source comparison 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -9.186654E-03 -5.964812E-03 -4.465905E-03 -4.119425E-03 -4.973577E-03 -4.092492E-03 -4.063342E-03 -2.804589E-03 -3.632667E-03 -5.005042E-03 -3.428575E-03 -3.007070E-03 -3.091465E-03 -3.030625E-03 -2.751739E-03 -1.762364E-03 +9.168094E-03 +5.976241E-03 +4.426550E-03 +4.107499E-03 +4.957716E-03 +4.026213E-03 +3.986000E-03 +2.702714E-03 +3.619345E-03 +4.909616E-03 +3.355042E-03 +2.945724E-03 +3.010811E-03 +2.965662E-03 +2.673073E-03 +1.669634E-03 cmfd source -4.538792E-02 -8.103354E-02 -1.045198E-01 -1.221411E-01 -1.398214E-01 -1.401011E-01 -1.305055E-01 -1.120110E-01 -8.032924E-02 -4.414939E-02 +4.539734E-02 +8.104913E-02 +1.045143E-01 +1.221516E-01 +1.398002E-01 +1.400323E-01 +1.304628E-01 +1.120006E-01 +8.038230E-02 +4.420934E-02 diff --git a/tests/test_cmfd_nofeed/tallies.xml b/tests/test_cmfd_nofeed/tallies.xml index b20c0ad61..37edcecc2 100644 --- a/tests/test_cmfd_nofeed/tallies.xml +++ b/tests/test_cmfd_nofeed/tallies.xml @@ -2,7 +2,7 @@ - rectangular + regular -10 -1 -1 10 1 1 10 1 1 diff --git a/tests/test_entropy/test_entropy.py b/tests/test_entropy/test_entropy.py index 4657101ad..43c17da14 100644 --- a/tests/test_entropy/test_entropy.py +++ b/tests/test_entropy/test_entropy.py @@ -1,6 +1,9 @@ #!/usr/bin/env python +import glob +import os import sys + sys.path.insert(0, '..') from testing_harness import * @@ -11,7 +14,6 @@ class EntropyTestHarness(TestHarness): # Read the statepoint file. statepoint = glob.glob(os.path.join(os.getcwd(), self._sp_name))[0] sp = StatePoint(statepoint) - sp.read_results() # Write out k-combined. outstr = 'k-combined:\n' @@ -20,7 +22,7 @@ class EntropyTestHarness(TestHarness): # Write out entropy data. outstr += 'entropy:\n' - results = ['{0:12.6E}'.format(x) for x in sp._entropy] + results = ['{0:12.6E}'.format(x) for x in sp.entropy] outstr += '\n'.join(results) + '\n' return outstr diff --git a/tests/test_filter_distribcell/test_filter_distribcell.py b/tests/test_filter_distribcell/test_filter_distribcell.py index 492f03dae..541d6b6af 100644 --- a/tests/test_filter_distribcell/test_filter_distribcell.py +++ b/tests/test_filter_distribcell/test_filter_distribcell.py @@ -1,6 +1,8 @@ #!/usr/bin/env python +import glob import hashlib +import os import sys sys.path.insert(0, '..') @@ -67,9 +69,8 @@ class DistribcellTestHarness(TestHarness): statepoint = glob.glob(os.path.join(os.getcwd(), self._sp_name)) assert len(statepoint) == 1, 'Either multiple or no statepoint files ' \ 'exist.' - assert statepoint[0].endswith('binary') \ - or statepoint[0].endswith('h5'), \ - 'Statepoint file is not a binary or hdf5 file.' + assert statepoint[0].endswith('h5'), \ + 'Statepoint file is not a HDF5 file.' if tallies_out_present: assert os.path.exists(os.path.join(os.getcwd(), 'tallies.out')), \ 'Tally output file does not exist.' diff --git a/tests/test_filter_mesh_2d/tallies.xml b/tests/test_filter_mesh_2d/tallies.xml index e046549de..de3fa6553 100644 --- a/tests/test_filter_mesh_2d/tallies.xml +++ b/tests/test_filter_mesh_2d/tallies.xml @@ -2,7 +2,7 @@ - rectangular + regular -182.07 -182.07 182.07 182.07 17 17 @@ -13,4 +13,4 @@ total - \ No newline at end of file + diff --git a/tests/test_filter_mesh_3d/tallies.xml b/tests/test_filter_mesh_3d/tallies.xml index b2be27279..cd7f925e8 100644 --- a/tests/test_filter_mesh_3d/tallies.xml +++ b/tests/test_filter_mesh_3d/tallies.xml @@ -2,7 +2,7 @@ - rectangular + regular -182.07 -182.07 -183.00 182.07 182.07 183.00 17 17 17 @@ -13,4 +13,4 @@ total - \ No newline at end of file + diff --git a/tests/test_fixed_source/test_fixed_source.py b/tests/test_fixed_source/test_fixed_source.py index e96a3ad8f..c3bd34856 100644 --- a/tests/test_fixed_source/test_fixed_source.py +++ b/tests/test_fixed_source/test_fixed_source.py @@ -1,6 +1,9 @@ #!/usr/bin/env python +import glob +import os import sys + sys.path.insert(0, '..') from testing_harness import * @@ -11,26 +14,26 @@ class FixedSourceTestHarness(TestHarness): # Read the statepoint file. statepoint = glob.glob(os.path.join(os.getcwd(), self._sp_name))[0] sp = StatePoint(statepoint) - sp.read_results() # Write out tally data. outstr = '' if self._tallies: tally_num = 1 - for tally_ind in sp._tallies: - tally = sp._tallies[tally_ind] - results = np.zeros((tally._sum.size*2, )) - results[0::2] = tally._sum.ravel() - results[1::2] = tally._sum_sq.ravel() + for tally_ind in sp.tallies: + tally = sp.tallies[tally_ind] + results = np.zeros((tally.sum.size*2, )) + results[0::2] = tally.sum.ravel() + results[1::2] = tally.sum_sq.ravel() results = ['{0:12.6E}'.format(x) for x in results] outstr += 'tally ' + str(tally_num) + ':\n' outstr += '\n'.join(results) + '\n' tally_num += 1 + gt = sp.global_tallies outstr += 'leakage:\n' - outstr += '{0:12.6E}'.format(sp._global_tallies[3][0]) + '\n' - outstr += '{0:12.6E}'.format(sp._global_tallies[3][1]) + '\n' + outstr += '{0:12.6E}'.format(gt[gt['name'] == b'leakage'][0]['sum']) + '\n' + outstr += '{0:12.6E}'.format(gt[gt['name'] == b'leakage'][0]['sum_sq']) + '\n' return outstr diff --git a/tests/test_many_scores/results_true.dat b/tests/test_many_scores/results_true.dat index ab1c43254..bb151ae0e 100644 --- a/tests/test_many_scores/results_true.dat +++ b/tests/test_many_scores/results_true.dat @@ -7,16 +7,8 @@ tally 1: 3.427342E+01 8.628000E+00 2.481430E+01 -8.628000E+00 -2.481430E+01 -5.102293E-01 -8.710841E-02 -8.628000E+00 -2.481430E+01 -9.329009E-01 -2.902534E-01 -5.102293E-01 -8.710841E-02 +8.632000E+00 +2.483728E+01 5.102293E-01 8.710841E-02 8.628000E+00 @@ -25,6 +17,14 @@ tally 1: 2.902534E-01 5.102293E-01 8.710841E-02 +5.087118E-01 +8.657086E-02 +8.632000E+00 +2.483728E+01 +9.328366E-01 +2.902108E-01 +5.087118E-01 +8.657086E-02 9.212024E+00 2.829472E+01 8.628000E+00 @@ -89,23 +89,23 @@ tally 1: 1.459209E-04 4.629047E-02 7.823267E-04 -8.628000E+00 -2.481430E+01 --4.712248E-02 -1.140942E-03 --6.431930E-02 -4.290580E-03 --9.251642E-02 -8.134201E-03 -1.020119E-04 -1.154184E-04 --2.994164E-02 -3.079076E-04 -2.128844E-02 -2.046549E-04 -1.637972E-02 -1.459209E-04 -4.629047E-02 -7.823267E-04 +8.632000E+00 +2.483728E+01 +-4.651997E-02 +1.133839E-03 +-6.416955E-02 +4.279418E-03 +-9.280565E-02 +8.095106E-03 +-2.078094E-04 +1.151292E-04 +-3.005568E-02 +3.104764E-04 +2.199519E-02 +2.179172E-04 +1.660645E-02 +1.451345E-04 +4.607553E-02 +7.673412E-04 1.014000E+01 3.427342E+01 diff --git a/tests/test_output/test_output.py b/tests/test_output/test_output.py index 1f51742ba..b37b7d07b 100644 --- a/tests/test_output/test_output.py +++ b/tests/test_output/test_output.py @@ -1,6 +1,9 @@ #!/usr/bin/env python +import glob +import os import sys + sys.path.insert(0, '..') from testing_harness import * @@ -14,8 +17,8 @@ class OutputTestHarness(TestHarness): # Check for the summary. summary = glob.glob(os.path.join(os.getcwd(), 'summary.*')) assert len(summary) == 1, 'Either multiple or no summary file exists.' - assert summary[0].endswith('out') or summary[0].endswith('h5'),\ - 'Summary file is not a binary or hdf5 file.' + assert summary[0].endswith('h5'),\ + 'Summary file is not a HDF5 file.' # Check for the cross sections. assert os.path.exists(os.path.join(os.getcwd(), 'cross_sections.out')),\ diff --git a/tests/test_particle_restart_eigval/results_true.dat b/tests/test_particle_restart_eigval/results_true.dat index bbc23fb6e..f34397853 100644 --- a/tests/test_particle_restart_eigval/results_true.dat +++ b/tests/test_particle_restart_eigval/results_true.dat @@ -5,7 +5,7 @@ current gen: particle id: 5.550000E+02 run mode: -2.000000E+00 +k-eigenvalue particle weight: 1.000000E+00 particle energy: diff --git a/tests/test_particle_restart_fixed/results_true.dat b/tests/test_particle_restart_fixed/results_true.dat index 701c3e133..de42a0c68 100644 --- a/tests/test_particle_restart_fixed/results_true.dat +++ b/tests/test_particle_restart_fixed/results_true.dat @@ -5,7 +5,7 @@ current gen: particle id: 9.280000E+02 run mode: -1.000000E+00 +fixed source particle weight: 1.000000E+00 particle energy: diff --git a/tests/test_score_MT/results_true.dat b/tests/test_score_MT/results_true.dat index 248f6657d..4b1c1af26 100644 --- a/tests/test_score_MT/results_true.dat +++ b/tests/test_score_MT/results_true.dat @@ -33,3 +33,69 @@ tally 1: 2.080857E-09 6.101318E-02 8.452067E-04 +tally 2: +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.000000E-01 +2.440000E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.000000E-02 +6.000000E-04 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +tally 3: +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.724026E-03 +1.684945E-05 +5.724026E-03 +1.684945E-05 +3.250298E-01 +2.370870E-02 +1.083784E+00 +2.568556E-01 +4.449887E-05 +1.980149E-09 +4.449887E-05 +1.980149E-09 +3.526275E-02 +2.863085E-04 +1.417358E-02 +4.375519E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.106469E-05 +8.605176E-10 +6.204277E-02 +8.555398E-04 diff --git a/tests/test_score_MT/tallies.xml b/tests/test_score_MT/tallies.xml index ef7ff8dd8..5e66ae929 100644 --- a/tests/test_score_MT/tallies.xml +++ b/tests/test_score_MT/tallies.xml @@ -6,4 +6,16 @@ n2n 16 51 102 - \ No newline at end of file + + + n2n 16 51 102 + analog + + + + + n2n 16 51 102 + collision + + + diff --git a/tests/test_score_absorption/results_true.dat b/tests/test_score_absorption/results_true.dat index bacbf26a3..9370a146f 100644 --- a/tests/test_score_absorption/results_true.dat +++ b/tests/test_score_absorption/results_true.dat @@ -18,3 +18,12 @@ tally 2: 0.000000E+00 4.000000E-01 4.240000E-02 +tally 3: +0.000000E+00 +0.000000E+00 +1.990713E+00 +8.557870E-01 +1.427399E-02 +4.420707E-05 +2.968053E-01 +1.960663E-02 diff --git a/tests/test_score_absorption/tallies.xml b/tests/test_score_absorption/tallies.xml index 8cbcef251..8b2dc2931 100644 --- a/tests/test_score_absorption/tallies.xml +++ b/tests/test_score_absorption/tallies.xml @@ -12,4 +12,10 @@ absorption - \ No newline at end of file + + + collision + absorption + + + diff --git a/tests/test_score_current/tallies.xml b/tests/test_score_current/tallies.xml index a740949fa..3f496d43a 100644 --- a/tests/test_score_current/tallies.xml +++ b/tests/test_score_current/tallies.xml @@ -2,7 +2,7 @@ - rectangular + regular -182.07 -182.07 -183.00 182.07 182.07 183.00 17 17 17 @@ -19,4 +19,4 @@ current - \ No newline at end of file + diff --git a/tests/test_score_fission/results_true.dat b/tests/test_score_fission/results_true.dat index 904c0d889..86b31aaaf 100644 --- a/tests/test_score_fission/results_true.dat +++ b/tests/test_score_fission/results_true.dat @@ -18,3 +18,12 @@ tally 2: 0.000000E+00 9.923196E-01 2.067216E-01 +tally 3: +9.036254E-01 +1.746552E-01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.912744E-01 +2.192705E-01 diff --git a/tests/test_score_fission/tallies.xml b/tests/test_score_fission/tallies.xml index d56614bdf..a8b57f911 100644 --- a/tests/test_score_fission/tallies.xml +++ b/tests/test_score_fission/tallies.xml @@ -12,4 +12,10 @@ fission - \ No newline at end of file + + + collision + fission + + + diff --git a/tests/test_score_flux/results_true.dat b/tests/test_score_flux/results_true.dat index 31e1d9292..31ca238d4 100644 --- a/tests/test_score_flux/results_true.dat +++ b/tests/test_score_flux/results_true.dat @@ -13,3 +13,29 @@ tally 1: 2.880575E+01 5.605671E+01 6.804062E+02 +tally 2: +3.077754E+01 +2.017424E+02 +1.172238E+01 +3.139127E+01 +5.231699E+01 +5.870469E+02 +3.259142E+01 +2.336719E+02 +1.040924E+01 +2.432332E+01 +5.709679E+01 +6.978668E+02 +tally 3: +3.077754E+01 +2.017424E+02 +1.172238E+01 +3.139127E+01 +5.231699E+01 +5.870469E+02 +3.259142E+01 +2.336719E+02 +1.040924E+01 +2.432332E+01 +5.709679E+01 +6.978668E+02 diff --git a/tests/test_score_flux/tallies.xml b/tests/test_score_flux/tallies.xml index 30bef7174..bcde40c75 100644 --- a/tests/test_score_flux/tallies.xml +++ b/tests/test_score_flux/tallies.xml @@ -6,4 +6,16 @@ flux - \ No newline at end of file + + + flux + analog + + + + + flux + collision + + + diff --git a/tests/test_score_flux_yn/results_true.dat b/tests/test_score_flux_yn/results_true.dat index 2e5df97cf..937f810ea 100644 --- a/tests/test_score_flux_yn/results_true.dat +++ b/tests/test_score_flux_yn/results_true.dat @@ -446,3 +446,869 @@ tally 2: 1.093913E-01 2.235961E-01 5.449263E-02 +tally 3: +3.077754E+01 +2.017424E+02 +-4.040800E-01 +5.606719E-01 +-5.238239E-01 +4.460714E-01 +1.155164E-01 +1.686786E-01 +-1.972294E-01 +2.912851E-01 +4.908524E-01 +1.374195E-01 +-1.467088E-02 +1.080839E-01 +6.749037E-02 +1.397361E-01 +4.136479E-03 +9.237632E-02 +-3.742305E-01 +9.917374E-02 +5.374208E-01 +2.530961E-01 +2.270996E-01 +9.415721E-02 +-4.568867E-02 +1.277446E-01 +1.581716E-01 +6.217155E-02 +4.667840E-01 +1.143380E-01 +9.684270E-02 +7.302998E-02 +8.366629E-01 +1.797483E-01 +-5.657893E-01 +2.553910E-01 +-2.351441E-02 +4.395513E-02 +7.843306E-01 +1.466478E-01 +4.617856E-02 +1.154681E-02 +1.431343E-01 +3.531062E-02 +4.625825E-01 +6.235642E-02 +-8.837342E-02 +6.231694E-02 +-3.766755E-01 +6.412261E-02 +1.995226E-01 +1.743990E-01 +-2.498625E-02 +8.897536E-02 +-1.039315E-01 +1.868672E-01 +6.712910E-01 +2.084042E-01 +5.805639E-02 +4.049580E-02 +1.603677E-01 +4.280033E-02 +3.909878E-01 +7.726018E-02 +9.878354E-02 +4.630595E-02 +-2.389983E-01 +3.528604E-02 +1.641046E-01 +1.669859E-01 +-2.351986E-02 +1.048794E-02 +1.172238E+01 +3.139127E+01 +-1.057733E+00 +2.820672E-01 +5.708838E-02 +6.224675E-02 +2.492981E-02 +1.827498E-01 +-1.339268E-01 +1.968929E-02 +2.363867E-01 +3.028587E-02 +-2.867841E-01 +2.680318E-02 +-2.352784E-01 +1.895006E-02 +4.365572E-01 +1.883240E-01 +-3.388837E-01 +7.209932E-02 +3.488374E-01 +6.640137E-02 +-3.343893E-01 +4.149634E-02 +-4.575314E-01 +7.461614E-02 +4.436881E-01 +1.325092E-01 +3.394853E-01 +2.987173E-02 +-2.633936E-02 +6.171428E-02 +9.994191E-02 +6.447641E-02 +-1.618840E-01 +3.497845E-02 +-1.290678E-01 +3.735394E-02 +9.852126E-03 +2.963925E-02 +-1.656539E-01 +4.190396E-02 +-2.292763E-01 +7.045480E-02 +-4.616824E-03 +1.926690E-02 +-1.960839E-01 +1.396042E-02 +-2.133526E-02 +5.189823E-02 +2.933136E-01 +5.721356E-02 +-1.084914E-01 +2.448532E-02 +-4.778583E-01 +7.644033E-02 +1.736901E-01 +6.630467E-02 +-5.460801E-02 +1.510381E-02 +1.106093E-01 +1.590306E-02 +1.659501E-01 +5.983218E-02 +1.343781E-02 +2.751294E-02 +2.052693E-01 +3.478581E-02 +-1.006298E-01 +1.815313E-02 +-2.563766E-01 +3.045246E-02 +5.231699E+01 +5.870469E+02 +-6.102587E-01 +5.930968E-01 +1.184182E+00 +1.364433E+00 +-6.362263E-02 +8.852514E-01 +-4.844978E-01 +1.751923E-01 +8.223413E-01 +2.436206E-01 +-9.656506E-01 +3.513566E-01 +2.710494E-01 +7.170772E-01 +4.792482E-01 +2.551569E-01 +-1.266077E-01 +2.824778E-01 +6.389964E-01 +2.501483E-01 +8.915816E-01 +3.557431E-01 +-1.007448E+00 +5.743018E-01 +3.528444E-01 +2.428078E-01 +-5.833000E-01 +3.733648E-01 +-4.660289E-01 +6.567263E-02 +5.856088E-01 +2.336146E-01 +3.836351E-02 +7.665403E-02 +-6.721211E-01 +2.651780E-01 +5.725993E-01 +2.101026E-01 +-2.130594E-01 +1.855350E-02 +2.607168E-01 +1.564288E-01 +-3.399382E-02 +3.067656E-02 +-1.228976E+00 +6.554836E-01 +-2.962235E-01 +1.808511E-01 +5.521675E-01 +1.722073E-01 +-1.658751E-01 +1.994119E-02 +-2.671896E-01 +1.343320E-01 +-2.325282E-01 +4.677656E-02 +-3.380310E-01 +1.703532E-01 +-3.571853E-01 +1.140525E-01 +3.836770E-02 +8.586429E-02 +7.328263E-01 +1.567227E-01 +4.840110E-02 +2.718471E-02 +5.654783E-01 +3.645579E-01 +-3.027585E-01 +1.407867E-01 +3.259142E+01 +2.336719E+02 +3.053294E-01 +2.086257E-01 +-7.563597E-01 +2.816768E-01 +-3.039288E-01 +2.855043E-01 +-2.648323E-01 +1.883784E-01 +2.665933E-01 +1.782353E-01 +1.978960E-01 +1.419567E-01 +1.228712E-01 +1.913946E-01 +-9.152681E-03 +1.324681E-01 +-5.707326E-01 +1.092067E-01 +2.326858E-01 +6.731743E-02 +-5.170241E-01 +1.353439E-01 +-4.064026E-01 +9.715030E-02 +-1.142031E-01 +7.748788E-02 +2.928039E-01 +2.716157E-01 +-1.721186E-01 +1.447738E-01 +6.452116E-01 +1.821975E-01 +-5.697276E-01 +1.047333E-01 +-9.640967E-02 +1.139327E-01 +-4.509832E-01 +2.079493E-01 +-2.134684E-02 +2.907667E-01 +-2.434868E-01 +1.235397E-01 +2.550330E-01 +2.979627E-01 +9.598615E-01 +3.140885E-01 +1.218430E-01 +6.283872E-02 +2.412915E-01 +1.907292E-02 +-2.236667E-01 +4.379414E-02 +2.844474E-01 +2.965692E-02 +1.618860E-01 +8.293785E-03 +-1.265583E-01 +4.515449E-02 +6.356127E-02 +1.358134E-02 +-3.844886E-01 +8.600010E-02 +-1.942739E-01 +7.516022E-02 +1.765511E-01 +3.522611E-02 +-3.433188E-01 +3.456066E-02 +-1.501983E-01 +5.633844E-02 +1.040924E+01 +2.432332E+01 +-4.138270E-01 +1.309129E-01 +-3.151106E-01 +1.286964E-01 +9.213222E-02 +6.189454E-02 +-2.746107E-01 +8.103949E-02 +-9.781742E-02 +3.783736E-02 +-1.178371E-01 +3.242332E-02 +-5.837932E-01 +2.059491E-01 +-7.338223E-03 +8.012203E-02 +5.628994E-02 +2.190669E-02 +8.155585E-02 +1.039007E-01 +6.052048E-02 +4.339463E-02 +-1.157646E-02 +1.839000E-02 +-2.641673E-01 +4.737589E-02 +-8.531135E-02 +5.432766E-02 +6.036555E-01 +1.190329E-01 +-3.149976E-01 +5.735264E-02 +-8.456340E-02 +4.563143E-03 +2.224065E-01 +6.600030E-02 +9.562392E-03 +1.843524E-02 +-2.400599E-01 +3.182217E-02 +-6.534941E-01 +1.180315E-01 +4.371157E-01 +9.076666E-02 +3.257455E-02 +2.936184E-02 +-8.788428E-02 +1.923293E-02 +-2.604776E-01 +3.660313E-02 +-6.315350E-02 +1.503534E-02 +5.609294E-01 +8.783528E-02 +-7.363672E-01 +1.789210E-01 +2.883575E-01 +6.478578E-02 +-3.302954E-02 +1.517946E-02 +-3.234157E-01 +4.418920E-02 +2.846318E-01 +2.712085E-02 +-3.227536E-01 +5.062832E-02 +4.391474E-01 +5.548002E-02 +1.322988E-01 +2.995854E-02 +5.709679E+01 +6.978668E+02 +2.859201E-02 +1.094507E+00 +6.058587E-01 +6.079927E-01 +7.553798E-02 +1.131607E+00 +-5.851206E-01 +1.215663E+00 +8.266012E-02 +9.031287E-01 +-7.088368E-01 +3.984608E-01 +-4.414986E-01 +1.502417E-01 +2.241998E-01 +3.228823E-01 +-7.328574E-01 +2.430448E-01 +-8.070160E-01 +1.767265E-01 +-1.154449E-01 +8.739303E-03 +-3.787161E-01 +4.728756E-01 +-1.743577E-01 +1.091245E-01 +2.878137E-01 +2.724285E-01 +2.128994E-01 +4.440539E-01 +9.495567E-01 +3.622719E-01 +1.422950E-01 +5.309223E-02 +1.323659E-01 +1.911979E-01 +-1.303752E-01 +5.710728E-01 +-4.611294E-02 +4.086632E-02 +5.937879E-01 +1.006156E-01 +-3.558925E-01 +2.998983E-01 +1.175971E+00 +5.323321E-01 +2.426485E-01 +1.497265E-01 +7.805090E-02 +5.060214E-02 +-2.914577E-01 +2.233355E-01 +1.053098E-01 +6.693123E-02 +4.541315E-01 +1.328340E-01 +-6.290732E-02 +8.910616E-02 +7.371592E-01 +1.980732E-01 +5.804701E-01 +1.711949E-01 +-6.642202E-01 +1.131866E-01 +1.779818E-01 +6.530190E-02 +-5.224739E-01 +2.534102E-01 +-1.824905E-01 +2.910309E-02 +tally 4: +3.077754E+01 +2.017424E+02 +-4.040800E-01 +5.606719E-01 +-5.238239E-01 +4.460714E-01 +1.155164E-01 +1.686786E-01 +-1.972294E-01 +2.912851E-01 +4.908524E-01 +1.374195E-01 +-1.467088E-02 +1.080839E-01 +6.749037E-02 +1.397361E-01 +4.136479E-03 +9.237632E-02 +-3.742305E-01 +9.917374E-02 +5.374208E-01 +2.530961E-01 +2.270996E-01 +9.415721E-02 +-4.568867E-02 +1.277446E-01 +1.581716E-01 +6.217155E-02 +4.667840E-01 +1.143380E-01 +9.684270E-02 +7.302998E-02 +8.366629E-01 +1.797483E-01 +-5.657893E-01 +2.553910E-01 +-2.351441E-02 +4.395513E-02 +7.843306E-01 +1.466478E-01 +4.617856E-02 +1.154681E-02 +1.431343E-01 +3.531062E-02 +4.625825E-01 +6.235642E-02 +-8.837342E-02 +6.231694E-02 +-3.766755E-01 +6.412261E-02 +1.995226E-01 +1.743990E-01 +-2.498625E-02 +8.897536E-02 +-1.039315E-01 +1.868672E-01 +6.712910E-01 +2.084042E-01 +5.805639E-02 +4.049580E-02 +1.603677E-01 +4.280033E-02 +3.909878E-01 +7.726018E-02 +9.878354E-02 +4.630595E-02 +-2.389983E-01 +3.528604E-02 +1.641046E-01 +1.669859E-01 +-2.351986E-02 +1.048794E-02 +1.172238E+01 +3.139127E+01 +-1.057733E+00 +2.820672E-01 +5.708838E-02 +6.224675E-02 +2.492981E-02 +1.827498E-01 +-1.339268E-01 +1.968929E-02 +2.363867E-01 +3.028587E-02 +-2.867841E-01 +2.680318E-02 +-2.352784E-01 +1.895006E-02 +4.365572E-01 +1.883240E-01 +-3.388837E-01 +7.209932E-02 +3.488374E-01 +6.640137E-02 +-3.343893E-01 +4.149634E-02 +-4.575314E-01 +7.461614E-02 +4.436881E-01 +1.325092E-01 +3.394853E-01 +2.987173E-02 +-2.633936E-02 +6.171428E-02 +9.994191E-02 +6.447641E-02 +-1.618840E-01 +3.497845E-02 +-1.290678E-01 +3.735394E-02 +9.852126E-03 +2.963925E-02 +-1.656539E-01 +4.190396E-02 +-2.292763E-01 +7.045480E-02 +-4.616824E-03 +1.926690E-02 +-1.960839E-01 +1.396042E-02 +-2.133526E-02 +5.189823E-02 +2.933136E-01 +5.721356E-02 +-1.084914E-01 +2.448532E-02 +-4.778583E-01 +7.644033E-02 +1.736901E-01 +6.630467E-02 +-5.460801E-02 +1.510381E-02 +1.106093E-01 +1.590306E-02 +1.659501E-01 +5.983218E-02 +1.343781E-02 +2.751294E-02 +2.052693E-01 +3.478581E-02 +-1.006298E-01 +1.815313E-02 +-2.563766E-01 +3.045246E-02 +5.231699E+01 +5.870469E+02 +-6.102587E-01 +5.930968E-01 +1.184182E+00 +1.364433E+00 +-6.362263E-02 +8.852514E-01 +-4.844978E-01 +1.751923E-01 +8.223413E-01 +2.436206E-01 +-9.656506E-01 +3.513566E-01 +2.710494E-01 +7.170772E-01 +4.792482E-01 +2.551569E-01 +-1.266077E-01 +2.824778E-01 +6.389964E-01 +2.501483E-01 +8.915816E-01 +3.557431E-01 +-1.007448E+00 +5.743018E-01 +3.528444E-01 +2.428078E-01 +-5.833000E-01 +3.733648E-01 +-4.660289E-01 +6.567263E-02 +5.856088E-01 +2.336146E-01 +3.836351E-02 +7.665403E-02 +-6.721211E-01 +2.651780E-01 +5.725993E-01 +2.101026E-01 +-2.130594E-01 +1.855350E-02 +2.607168E-01 +1.564288E-01 +-3.399382E-02 +3.067656E-02 +-1.228976E+00 +6.554836E-01 +-2.962235E-01 +1.808511E-01 +5.521675E-01 +1.722073E-01 +-1.658751E-01 +1.994119E-02 +-2.671896E-01 +1.343320E-01 +-2.325282E-01 +4.677656E-02 +-3.380310E-01 +1.703532E-01 +-3.571853E-01 +1.140525E-01 +3.836770E-02 +8.586429E-02 +7.328263E-01 +1.567227E-01 +4.840110E-02 +2.718471E-02 +5.654783E-01 +3.645579E-01 +-3.027585E-01 +1.407867E-01 +3.259142E+01 +2.336719E+02 +3.053294E-01 +2.086257E-01 +-7.563597E-01 +2.816768E-01 +-3.039288E-01 +2.855043E-01 +-2.648323E-01 +1.883784E-01 +2.665933E-01 +1.782353E-01 +1.978960E-01 +1.419567E-01 +1.228712E-01 +1.913946E-01 +-9.152681E-03 +1.324681E-01 +-5.707326E-01 +1.092067E-01 +2.326858E-01 +6.731743E-02 +-5.170241E-01 +1.353439E-01 +-4.064026E-01 +9.715030E-02 +-1.142031E-01 +7.748788E-02 +2.928039E-01 +2.716157E-01 +-1.721186E-01 +1.447738E-01 +6.452116E-01 +1.821975E-01 +-5.697276E-01 +1.047333E-01 +-9.640967E-02 +1.139327E-01 +-4.509832E-01 +2.079493E-01 +-2.134684E-02 +2.907667E-01 +-2.434868E-01 +1.235397E-01 +2.550330E-01 +2.979627E-01 +9.598615E-01 +3.140885E-01 +1.218430E-01 +6.283872E-02 +2.412915E-01 +1.907292E-02 +-2.236667E-01 +4.379414E-02 +2.844474E-01 +2.965692E-02 +1.618860E-01 +8.293785E-03 +-1.265583E-01 +4.515449E-02 +6.356127E-02 +1.358134E-02 +-3.844886E-01 +8.600010E-02 +-1.942739E-01 +7.516022E-02 +1.765511E-01 +3.522611E-02 +-3.433188E-01 +3.456066E-02 +-1.501983E-01 +5.633844E-02 +1.040924E+01 +2.432332E+01 +-4.138270E-01 +1.309129E-01 +-3.151106E-01 +1.286964E-01 +9.213222E-02 +6.189454E-02 +-2.746107E-01 +8.103949E-02 +-9.781742E-02 +3.783736E-02 +-1.178371E-01 +3.242332E-02 +-5.837932E-01 +2.059491E-01 +-7.338223E-03 +8.012203E-02 +5.628994E-02 +2.190669E-02 +8.155585E-02 +1.039007E-01 +6.052048E-02 +4.339463E-02 +-1.157646E-02 +1.839000E-02 +-2.641673E-01 +4.737589E-02 +-8.531135E-02 +5.432766E-02 +6.036555E-01 +1.190329E-01 +-3.149976E-01 +5.735264E-02 +-8.456340E-02 +4.563143E-03 +2.224065E-01 +6.600030E-02 +9.562392E-03 +1.843524E-02 +-2.400599E-01 +3.182217E-02 +-6.534941E-01 +1.180315E-01 +4.371157E-01 +9.076666E-02 +3.257455E-02 +2.936184E-02 +-8.788428E-02 +1.923293E-02 +-2.604776E-01 +3.660313E-02 +-6.315350E-02 +1.503534E-02 +5.609294E-01 +8.783528E-02 +-7.363672E-01 +1.789210E-01 +2.883575E-01 +6.478578E-02 +-3.302954E-02 +1.517946E-02 +-3.234157E-01 +4.418920E-02 +2.846318E-01 +2.712085E-02 +-3.227536E-01 +5.062832E-02 +4.391474E-01 +5.548002E-02 +1.322988E-01 +2.995854E-02 +5.709679E+01 +6.978668E+02 +2.859201E-02 +1.094507E+00 +6.058587E-01 +6.079927E-01 +7.553798E-02 +1.131607E+00 +-5.851206E-01 +1.215663E+00 +8.266012E-02 +9.031287E-01 +-7.088368E-01 +3.984608E-01 +-4.414986E-01 +1.502417E-01 +2.241998E-01 +3.228823E-01 +-7.328574E-01 +2.430448E-01 +-8.070160E-01 +1.767265E-01 +-1.154449E-01 +8.739303E-03 +-3.787161E-01 +4.728756E-01 +-1.743577E-01 +1.091245E-01 +2.878137E-01 +2.724285E-01 +2.128994E-01 +4.440539E-01 +9.495567E-01 +3.622719E-01 +1.422950E-01 +5.309223E-02 +1.323659E-01 +1.911979E-01 +-1.303752E-01 +5.710728E-01 +-4.611294E-02 +4.086632E-02 +5.937879E-01 +1.006156E-01 +-3.558925E-01 +2.998983E-01 +1.175971E+00 +5.323321E-01 +2.426485E-01 +1.497265E-01 +7.805090E-02 +5.060214E-02 +-2.914577E-01 +2.233355E-01 +1.053098E-01 +6.693123E-02 +4.541315E-01 +1.328340E-01 +-6.290732E-02 +8.910616E-02 +7.371592E-01 +1.980732E-01 +5.804701E-01 +1.711949E-01 +-6.642202E-01 +1.131866E-01 +1.779818E-01 +6.530190E-02 +-5.224739E-01 +2.534102E-01 +-1.824905E-01 +2.910309E-02 diff --git a/tests/test_score_flux_yn/tallies.xml b/tests/test_score_flux_yn/tallies.xml index 71301d0e7..e9f08bd4e 100644 --- a/tests/test_score_flux_yn/tallies.xml +++ b/tests/test_score_flux_yn/tallies.xml @@ -10,5 +10,17 @@ flux-y5 + + + + flux-y5 + analog + + + + + flux-y5 + collision + diff --git a/tests/test_score_kappafission/results_true.dat b/tests/test_score_kappafission/results_true.dat index dadcdd281..e992b4b68 100644 --- a/tests/test_score_kappafission/results_true.dat +++ b/tests/test_score_kappafission/results_true.dat @@ -9,3 +9,21 @@ tally 1: 0.000000E+00 2.035912E+02 8.999693E+03 +tally 2: +1.765331E+02 +6.974050E+03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.938441E+02 +7.888708E+03 +tally 3: +1.770125E+02 +6.702714E+03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.942246E+02 +8.416720E+03 diff --git a/tests/test_score_kappafission/tallies.xml b/tests/test_score_kappafission/tallies.xml index 1b63fdeeb..8fe5d5c84 100644 --- a/tests/test_score_kappafission/tallies.xml +++ b/tests/test_score_kappafission/tallies.xml @@ -6,4 +6,16 @@ kappa-fission - \ No newline at end of file + + + kappa-fission + analog + + + + + kappa-fission + collision + + + diff --git a/tests/test_score_nufission/results_true.dat b/tests/test_score_nufission/results_true.dat index 5d0b44662..33c4ff9fb 100644 --- a/tests/test_score_nufission/results_true.dat +++ b/tests/test_score_nufission/results_true.dat @@ -9,3 +9,21 @@ tally 1: 0.000000E+00 2.733038E+00 1.616903E+00 +tally 2: +2.296157E+00 +1.167084E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.679940E+00 +1.498454E+00 +tally 3: +2.381373E+00 +1.213497E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.607077E+00 +1.513932E+00 diff --git a/tests/test_score_nufission/tallies.xml b/tests/test_score_nufission/tallies.xml index d3e6963f3..2812a00b5 100644 --- a/tests/test_score_nufission/tallies.xml +++ b/tests/test_score_nufission/tallies.xml @@ -6,4 +6,16 @@ nu-fission - \ No newline at end of file + + + nu-fission + analog + + + + + nu-fission + collision + + + diff --git a/tests/test_score_nuscatter/results_true.dat b/tests/test_score_nuscatter/results_true.dat index df695d8a8..66e0c0a03 100644 --- a/tests/test_score_nuscatter/results_true.dat +++ b/tests/test_score_nuscatter/results_true.dat @@ -1,11 +1,11 @@ k-combined: -1.005983E+00 2.248579E-02 +9.870214E-01 2.095925E-02 tally 1: 0.000000E+00 0.000000E+00 -1.169000E+01 -2.915330E+01 -3.200000E+00 -2.342600E+00 -4.064000E+01 -3.595168E+02 +3.353000E+01 +1.133379E+02 +8.150000E+00 +6.793700E+00 +1.098500E+02 +1.221333E+03 diff --git a/tests/test_score_nuscatter/settings.xml b/tests/test_score_nuscatter/settings.xml index 517637a59..ce632aae3 100644 --- a/tests/test_score_nuscatter/settings.xml +++ b/tests/test_score_nuscatter/settings.xml @@ -3,7 +3,7 @@ 10 - 5 + 0 100 diff --git a/tests/test_score_nuscatter_n/results_true.dat b/tests/test_score_nuscatter_n/results_true.dat index b46a1e184..5dbc7f8ab 100644 --- a/tests/test_score_nuscatter_n/results_true.dat +++ b/tests/test_score_nuscatter_n/results_true.dat @@ -1,33 +1,33 @@ k-combined: -1.005983E+00 2.248579E-02 +9.870214E-01 2.095925E-02 tally 1: -1.169000E+01 -2.915330E+01 -1.247253E+00 -3.767436E-01 -5.330812E-01 -1.385083E-01 -2.987823E-01 -5.699361E-02 -2.645512E-01 -2.905381E-02 -3.200000E+00 -2.342600E+00 -3.809941E-01 -2.965326E-02 -4.319242E-01 -3.738822E-02 -9.261909E-02 -6.711328E-03 --6.052442E-02 -7.087230E-03 -4.064000E+01 -3.595168E+02 -2.096700E+01 -9.516606E+01 -7.560566E+00 -1.248694E+01 -2.093348E-01 -4.278510E-02 --1.449929E+00 -4.356371E-01 +3.353000E+01 +1.133379E+02 +3.491100E+00 +1.265776E+00 +1.948509E+00 +4.761101E-01 +9.177045E-01 +1.251750E-01 +5.654249E-01 +5.567043E-02 +8.150000E+00 +6.793700E+00 +1.223263E+00 +1.678053E-01 +7.833173E-01 +8.407682E-02 +1.350170E-01 +7.393546E-03 +2.164837E-01 +1.367122E-02 +1.098500E+02 +1.221333E+03 +5.598624E+01 +3.183267E+02 +2.048716E+01 +4.301097E+01 +1.399456E+00 +4.458904E-01 +-2.183180E+00 +6.628474E-01 diff --git a/tests/test_score_nuscatter_n/settings.xml b/tests/test_score_nuscatter_n/settings.xml index 517637a59..ce632aae3 100644 --- a/tests/test_score_nuscatter_n/settings.xml +++ b/tests/test_score_nuscatter_n/settings.xml @@ -3,7 +3,7 @@ 10 - 5 + 0 100 diff --git a/tests/test_score_nuscatter_pn/results_true.dat b/tests/test_score_nuscatter_pn/results_true.dat index 3c34895d9..41bc17f8b 100644 --- a/tests/test_score_nuscatter_pn/results_true.dat +++ b/tests/test_score_nuscatter_pn/results_true.dat @@ -1,24 +1,24 @@ k-combined: -1.005983E+00 2.248579E-02 +9.870214E-01 2.095925E-02 tally 1: -1.169000E+01 -2.915330E+01 -1.247253E+00 -3.767436E-01 -5.330812E-01 -1.385083E-01 -2.987823E-01 -5.699361E-02 -2.645512E-01 -2.905381E-02 +3.353000E+01 +1.133379E+02 +3.491100E+00 +1.265776E+00 +1.948509E+00 +4.761101E-01 +9.177045E-01 +1.251750E-01 +5.654249E-01 +5.567043E-02 tally 2: -1.169000E+01 -2.915330E+01 -1.247253E+00 -3.767436E-01 -5.330812E-01 -1.385083E-01 -2.987823E-01 -5.699361E-02 -2.645512E-01 -2.905381E-02 +3.353000E+01 +1.133379E+02 +3.491100E+00 +1.265776E+00 +1.948509E+00 +4.761101E-01 +9.177045E-01 +1.251750E-01 +5.654249E-01 +5.567043E-02 diff --git a/tests/test_score_nuscatter_pn/settings.xml b/tests/test_score_nuscatter_pn/settings.xml index 517637a59..ce632aae3 100644 --- a/tests/test_score_nuscatter_pn/settings.xml +++ b/tests/test_score_nuscatter_pn/settings.xml @@ -3,7 +3,7 @@ 10 - 5 + 0 100 diff --git a/tests/test_score_nuscatter_yn/results_true.dat b/tests/test_score_nuscatter_yn/results_true.dat index 1e8e143ef..cdf051ee7 100644 --- a/tests/test_score_nuscatter_yn/results_true.dat +++ b/tests/test_score_nuscatter_yn/results_true.dat @@ -1,38 +1,38 @@ k-combined: -1.005983E+00 2.248579E-02 +9.870214E-01 2.095925E-02 tally 1: -1.169000E+01 -2.915330E+01 +3.353000E+01 +1.133379E+02 tally 2: -1.169000E+01 -2.915330E+01 --2.198379E-01 -2.828670E-02 --1.317276E-01 -9.568596E-03 -8.309792E-02 -1.155410E-02 --2.288506E-02 -3.710542E-03 --2.720674E-02 -1.789163E-03 --1.323964E-02 -1.819112E-04 -8.941597E-02 -4.265616E-03 -1.516805E-01 -1.332526E-02 --1.832782E-02 -6.611171E-03 -1.311371E-02 -2.840648E-03 -3.728365E-02 -2.866806E-03 --5.100587E-02 -2.957146E-03 -3.388028E-02 -2.481570E-03 --7.766921E-02 -3.129377E-03 -1.666131E-02 -3.828290E-03 +3.353000E+01 +1.133379E+02 +4.293226E-01 +6.259462E-02 +-2.011041E-02 +5.388144E-02 +3.900136E-01 +5.873137E-02 +6.150213E-02 +9.043796E-03 +5.518583E-02 +1.739087E-02 +-2.047987E-01 +1.993679E-02 +6.710345E-02 +1.652573E-02 +-3.619254E-02 +1.598186E-02 +3.551558E-02 +9.077346E-03 +1.044669E-01 +2.082961E-03 +-3.782063E-02 +1.681459E-02 +1.752386E-01 +1.411429E-02 +-3.289649E-02 +9.534958E-03 +5.252770E-02 +7.518445E-03 +2.688056E-02 +3.397824E-03 diff --git a/tests/test_score_nuscatter_yn/settings.xml b/tests/test_score_nuscatter_yn/settings.xml index 517637a59..ce632aae3 100644 --- a/tests/test_score_nuscatter_yn/settings.xml +++ b/tests/test_score_nuscatter_yn/settings.xml @@ -3,7 +3,7 @@ 10 - 5 + 0 100 diff --git a/tests/test_score_scatter/results_true.dat b/tests/test_score_scatter/results_true.dat index 5f0ae8b1d..21d7d83c2 100644 --- a/tests/test_score_scatter/results_true.dat +++ b/tests/test_score_scatter/results_true.dat @@ -9,3 +9,21 @@ tally 1: 1.814004E+00 4.059013E+01 3.609499E+02 +tally 2: +0.000000E+00 +0.000000E+00 +1.169000E+01 +2.915330E+01 +3.200000E+00 +2.342600E+00 +4.064000E+01 +3.595168E+02 +tally 3: +0.000000E+00 +0.000000E+00 +1.172929E+01 +2.935812E+01 +3.185726E+00 +2.323517E+00 +4.074319E+01 +3.614902E+02 diff --git a/tests/test_score_scatter/tallies.xml b/tests/test_score_scatter/tallies.xml index a4425c0f2..b6eb73b50 100644 --- a/tests/test_score_scatter/tallies.xml +++ b/tests/test_score_scatter/tallies.xml @@ -6,4 +6,16 @@ scatter - \ No newline at end of file + + + scatter + analog + + + + + scatter + collision + + + diff --git a/tests/test_score_total/results_true.dat b/tests/test_score_total/results_true.dat index f3aa5d89b..e782fd9d0 100644 --- a/tests/test_score_total/results_true.dat +++ b/tests/test_score_total/results_true.dat @@ -9,3 +9,21 @@ tally 1: 1.831649E+00 4.088282E+01 3.662539E+02 +tally 2: +0.000000E+00 +0.000000E+00 +1.372000E+01 +4.018980E+01 +3.200000E+00 +2.342600E+00 +4.104000E+01 +3.668254E+02 +tally 3: +0.000000E+00 +0.000000E+00 +1.372000E+01 +4.018980E+01 +3.200000E+00 +2.342600E+00 +4.104000E+01 +3.668254E+02 diff --git a/tests/test_score_total/tallies.xml b/tests/test_score_total/tallies.xml index 815b84c14..02286f96c 100644 --- a/tests/test_score_total/tallies.xml +++ b/tests/test_score_total/tallies.xml @@ -6,4 +6,16 @@ total - \ No newline at end of file + + + total + analog + + + + + total + collision + + + diff --git a/tests/test_score_total_yn/results_true.dat b/tests/test_score_total_yn/results_true.dat index bcfdb9080..28a4b1627 100644 --- a/tests/test_score_total_yn/results_true.dat +++ b/tests/test_score_total_yn/results_true.dat @@ -410,3 +410,805 @@ tally 2: 3.130205E-02 -3.695818E-01 4.703480E-02 +tally 3: +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +7.200000E-01 +1.152000E-01 +-9.800486E-03 +5.637123E-04 +-2.018554E-02 +4.617738E-04 +-6.271657E-03 +8.252833E-04 +-8.231683E-03 +3.035447E-03 +-2.566508E-02 +1.108829E-03 +2.748466E-03 +1.641191E-03 +6.833190E-03 +5.993876E-04 +3.392213E-02 +2.143714E-03 +3.105616E-02 +1.012625E-03 +-5.473567E-02 +1.615531E-03 +-1.435523E-02 +1.095690E-03 +4.579564E-03 +6.451444E-04 +-1.570409E-02 +3.833387E-04 +1.633422E-02 +2.144997E-03 +-7.438775E-03 +6.441846E-04 +5.440025E-04 +1.290719E-04 +-1.687899E-02 +1.606230E-03 +3.315902E-02 +1.061759E-03 +-1.184684E-02 +4.312573E-04 +-4.732586E-02 +1.387994E-03 +-1.563538E-02 +3.316015E-04 +3.681927E-02 +5.403320E-04 +2.928507E-03 +5.761742E-04 +-3.519362E-02 +6.725185E-04 +1.372000E+01 +4.018980E+01 +-2.015212E-01 +1.072884E-01 +-2.606953E-01 +4.894468E-02 +7.537153E-02 +2.216346E-02 +-3.818524E-02 +6.301675E-02 +2.386335E-01 +1.931104E-02 +-1.872805E-02 +1.265896E-02 +3.732943E-02 +2.347696E-02 +-8.857050E-02 +1.636275E-02 +-1.718450E-01 +1.043488E-02 +1.526226E-01 +2.435399E-02 +7.344765E-02 +1.541644E-02 +-9.819186E-03 +1.473467E-02 +-8.215914E-03 +1.463085E-02 +2.197504E-01 +2.244815E-02 +2.521002E-02 +8.206540E-03 +3.677974E-01 +3.982027E-02 +-1.934606E-01 +3.440019E-02 +1.050141E-01 +2.346980E-02 +2.458487E-01 +1.861429E-02 +4.226131E-02 +2.690841E-03 +3.174234E-02 +1.867018E-02 +2.284995E-01 +1.190246E-02 +-7.894573E-03 +3.715471E-03 +-1.593928E-01 +1.391828E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.200000E+00 +2.342600E+00 +-2.991985E-01 +1.868406E-02 +4.460301E-02 +4.132113E-03 +-2.190630E-02 +1.023889E-02 +-3.265764E-02 +2.060374E-03 +3.491521E-02 +4.785957E-04 +-3.623623E-02 +5.929111E-04 +-4.962268E-02 +1.814245E-03 +1.406439E-01 +1.174445E-02 +-9.433277E-02 +5.036897E-03 +9.058176E-02 +3.871598E-03 +-1.409089E-01 +6.665385E-03 +-1.062337E-01 +4.771650E-03 +1.155280E-01 +8.020320E-03 +8.348336E-02 +1.633941E-03 +1.475434E-02 +3.411046E-03 +4.474425E-03 +6.049348E-03 +6.716359E-03 +2.898000E-03 +-3.674047E-02 +2.971797E-03 +-2.368070E-02 +9.474965E-04 +-6.109826E-02 +4.846201E-03 +-5.076118E-02 +8.354393E-03 +-1.763594E-02 +1.017310E-03 +-2.941064E-02 +1.044916E-03 +-5.631429E-03 +3.915186E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.104000E+01 +3.668254E+02 +-7.832373E-01 +3.913941E-01 +2.281642E-01 +2.669856E-01 +-3.731272E-01 +6.152809E-01 +-3.232973E-01 +7.526283E-02 +3.686513E-01 +9.047618E-02 +-6.018185E-01 +9.140623E-02 +3.848843E-01 +3.431711E-01 +3.397425E-03 +8.879103E-02 +-2.471531E-02 +5.561795E-02 +1.373897E-01 +7.288680E-02 +1.816888E-01 +5.419638E-02 +-3.504404E-01 +1.461853E-01 +1.225356E-01 +3.443595E-02 +-3.109887E-01 +5.492397E-02 +-3.542105E-01 +6.530224E-02 +2.104218E-01 +4.093872E-02 +2.661467E-02 +3.058847E-02 +-3.744331E-01 +6.755739E-02 +1.391218E-01 +4.432842E-02 +1.622041E-01 +6.843992E-03 +4.149973E-02 +1.782398E-02 +2.551752E-01 +2.626972E-02 +-4.706697E-01 +9.193926E-02 +-1.287882E-01 +3.489982E-02 +tally 4: +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +7.652157E-01 +1.242826E-01 +-1.008373E-02 +5.281691E-04 +-1.014715E-02 +2.749212E-04 +-2.506414E-02 +2.613512E-04 +4.320187E-03 +4.316562E-04 +1.439246E-02 +9.138575E-05 +-1.532539E-02 +2.360878E-04 +9.963404E-03 +1.511695E-04 +-6.314554E-03 +2.742799E-05 +7.969329E-03 +1.380329E-04 +-1.298431E-03 +3.287236E-04 +1.441639E-02 +1.409552E-04 +6.516689E-03 +2.511011E-04 +1.294596E-02 +2.249729E-04 +6.983038E-03 +6.334969E-05 +-1.086161E-02 +1.140033E-04 +2.217006E-02 +4.221807E-04 +-6.503276E-03 +2.028281E-04 +2.915180E-02 +3.659182E-04 +-9.080091E-03 +1.503808E-04 +-6.476980E-04 +1.927326E-04 +-1.549603E-02 +3.445843E-04 +2.957508E-02 +1.835035E-04 +6.982790E-03 +1.237342E-04 +-2.653281E-02 +2.606704E-04 +1.372000E+01 +4.018980E+01 +-2.015212E-01 +1.072884E-01 +-2.606953E-01 +4.894468E-02 +7.537153E-02 +2.216346E-02 +-3.818524E-02 +6.301675E-02 +2.386335E-01 +1.931104E-02 +-1.872805E-02 +1.265896E-02 +3.732943E-02 +2.347696E-02 +-8.857050E-02 +1.636275E-02 +-1.718450E-01 +1.043488E-02 +1.526226E-01 +2.435399E-02 +7.344765E-02 +1.541644E-02 +-9.819186E-03 +1.473467E-02 +-8.215914E-03 +1.463085E-02 +2.197504E-01 +2.244815E-02 +2.521002E-02 +8.206540E-03 +3.677974E-01 +3.982027E-02 +-1.934606E-01 +3.440019E-02 +1.050141E-01 +2.346980E-02 +2.458487E-01 +1.861429E-02 +4.226131E-02 +2.690841E-03 +3.174234E-02 +1.867018E-02 +2.284995E-01 +1.190246E-02 +-7.894573E-03 +3.715471E-03 +-1.593928E-01 +1.391828E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.200000E+00 +2.342600E+00 +-2.991985E-01 +1.868406E-02 +4.460301E-02 +4.132113E-03 +-2.190630E-02 +1.023889E-02 +-3.265764E-02 +2.060374E-03 +3.491521E-02 +4.785957E-04 +-3.623623E-02 +5.929111E-04 +-4.962268E-02 +1.814245E-03 +1.406439E-01 +1.174445E-02 +-9.433277E-02 +5.036897E-03 +9.058176E-02 +3.871598E-03 +-1.409089E-01 +6.665385E-03 +-1.062337E-01 +4.771650E-03 +1.155280E-01 +8.020320E-03 +8.348336E-02 +1.633941E-03 +1.475434E-02 +3.411046E-03 +4.474425E-03 +6.049348E-03 +6.716359E-03 +2.898000E-03 +-3.674047E-02 +2.971797E-03 +-2.368070E-02 +9.474965E-04 +-6.109826E-02 +4.846201E-03 +-5.076118E-02 +8.354393E-03 +-1.763594E-02 +1.017310E-03 +-2.941064E-02 +1.044916E-03 +-5.631429E-03 +3.915186E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.104000E+01 +3.668254E+02 +-7.832373E-01 +3.913941E-01 +2.281642E-01 +2.669856E-01 +-3.731272E-01 +6.152809E-01 +-3.232973E-01 +7.526283E-02 +3.686513E-01 +9.047618E-02 +-6.018185E-01 +9.140623E-02 +3.848843E-01 +3.431711E-01 +3.397425E-03 +8.879103E-02 +-2.471531E-02 +5.561795E-02 +1.373897E-01 +7.288680E-02 +1.816888E-01 +5.419638E-02 +-3.504404E-01 +1.461853E-01 +1.225356E-01 +3.443595E-02 +-3.109887E-01 +5.492397E-02 +-3.542105E-01 +6.530224E-02 +2.104218E-01 +4.093872E-02 +2.661467E-02 +3.058847E-02 +-3.744331E-01 +6.755739E-02 +1.391218E-01 +4.432842E-02 +1.622041E-01 +6.843992E-03 +4.149973E-02 +1.782398E-02 +2.551752E-01 +2.626972E-02 +-4.706697E-01 +9.193926E-02 +-1.287882E-01 +3.489982E-02 diff --git a/tests/test_score_total_yn/tallies.xml b/tests/test_score_total_yn/tallies.xml index ca5dcd2dc..51cb79c39 100644 --- a/tests/test_score_total_yn/tallies.xml +++ b/tests/test_score_total_yn/tallies.xml @@ -11,5 +11,19 @@ total-y4 U-235 total + + + + total-y4 + U-235 total + analog + + + + + total-y4 + U-235 total + collision + diff --git a/tests/test_source_file/test_source_file.py b/tests/test_source_file/test_source_file.py index d9aaa9a0f..fae6b2a72 100644 --- a/tests/test_source_file/test_source_file.py +++ b/tests/test_source_file/test_source_file.py @@ -1,6 +1,9 @@ #!/usr/bin/env python +import glob +import os import sys + sys.path.insert(0, '..') from testing_harness import * @@ -66,15 +69,13 @@ class SourceFileTestHarness(TestHarness): statepoint = glob.glob(os.path.join(os.getcwd(), self._sp_name)) assert len(statepoint) == 1, 'Either multiple or no statepoint files ' \ 'exist.' - assert statepoint[0].endswith('binary') \ - or statepoint[0].endswith('h5'), \ - 'Statepoint file is not a binary or hdf5 file.' + assert statepoint[0].endswith('h5'), \ + 'Statepoint file is not a HDF5 file.' source = glob.glob(os.path.join(os.getcwd(), 'source.10.*')) assert len(source) == 1, 'Either multiple or no source files exist.' - assert source[0].endswith('binary') \ - or source[0].endswith('h5'), \ - 'Source file is not a binary or hdf5 file.' + assert source[0].endswith('h5'), \ + 'Source file is not a HDF5 file.' def _run_openmc_restart(self): # Get the name of the source file. diff --git a/tests/test_sourcepoint_batch/test_sourcepoint_batch.py b/tests/test_sourcepoint_batch/test_sourcepoint_batch.py index 8cafb4108..a306b9aa7 100644 --- a/tests/test_sourcepoint_batch/test_sourcepoint_batch.py +++ b/tests/test_sourcepoint_batch/test_sourcepoint_batch.py @@ -1,6 +1,9 @@ #!/usr/bin/env python +import glob +import os import sys + sys.path.insert(0, '..') from testing_harness import * @@ -9,24 +12,21 @@ class SourcepointTestHarness(TestHarness): def _test_output_created(self): """Make sure statepoint.* files have been created.""" statepoint = glob.glob(os.path.join(os.getcwd(), 'statepoint.*')) - assert len(statepoint) == 5, '5 statepoint files must exist.' - assert statepoint[0].endswith('binary') \ - or statepoint[0].endswith('h5'), \ - 'Statepoint file is not a binary or hdf5 file.' + assert len(statepoint) == 5, '5 statepoint files must exist.' + assert statepoint[0].endswith('h5'), \ + 'Statepoint file is not a HDF5 file.' def _get_results(self): """Digest info in the statepoint and return as a string.""" # Read the statepoint file. statepoint = glob.glob(os.path.join(os.getcwd(), self._sp_name))[0] sp = StatePoint(statepoint) - sp.read_results() - sp.read_source() # Get the eigenvalue information. outstr = TestHarness._get_results(self) # Add the source information. - xyz = sp._source[0]._xyz + xyz = sp.source[0]['xyz'] outstr += ' '.join(['{0:12.6E}'.format(x) for x in xyz]) outstr += "\n" diff --git a/tests/test_sourcepoint_interval/test_sourcepoint_interval.py b/tests/test_sourcepoint_interval/test_sourcepoint_interval.py index 8cafb4108..a306b9aa7 100644 --- a/tests/test_sourcepoint_interval/test_sourcepoint_interval.py +++ b/tests/test_sourcepoint_interval/test_sourcepoint_interval.py @@ -1,6 +1,9 @@ #!/usr/bin/env python +import glob +import os import sys + sys.path.insert(0, '..') from testing_harness import * @@ -9,24 +12,21 @@ class SourcepointTestHarness(TestHarness): def _test_output_created(self): """Make sure statepoint.* files have been created.""" statepoint = glob.glob(os.path.join(os.getcwd(), 'statepoint.*')) - assert len(statepoint) == 5, '5 statepoint files must exist.' - assert statepoint[0].endswith('binary') \ - or statepoint[0].endswith('h5'), \ - 'Statepoint file is not a binary or hdf5 file.' + assert len(statepoint) == 5, '5 statepoint files must exist.' + assert statepoint[0].endswith('h5'), \ + 'Statepoint file is not a HDF5 file.' def _get_results(self): """Digest info in the statepoint and return as a string.""" # Read the statepoint file. statepoint = glob.glob(os.path.join(os.getcwd(), self._sp_name))[0] sp = StatePoint(statepoint) - sp.read_results() - sp.read_source() # Get the eigenvalue information. outstr = TestHarness._get_results(self) # Add the source information. - xyz = sp._source[0]._xyz + xyz = sp.source[0]['xyz'] outstr += ' '.join(['{0:12.6E}'.format(x) for x in xyz]) outstr += "\n" diff --git a/tests/test_sourcepoint_latest/test_sourcepoint_latest.py b/tests/test_sourcepoint_latest/test_sourcepoint_latest.py index 5ae398462..7d0af89b9 100644 --- a/tests/test_sourcepoint_latest/test_sourcepoint_latest.py +++ b/tests/test_sourcepoint_latest/test_sourcepoint_latest.py @@ -1,6 +1,9 @@ #!/usr/bin/env python +import glob +import os import sys + sys.path.insert(0, '..') from testing_harness import * @@ -12,9 +15,8 @@ class SourcepointTestHarness(TestHarness): source = glob.glob(os.path.join(os.getcwd(), 'source.*')) assert len(source) == 1, 'Either multiple or no source files ' \ 'exist.' - assert source[0].endswith('binary') \ - or source[0].endswith('h5'), \ - 'Source file is not a binary or hdf5 file.' + assert source[0].endswith('h5'), \ + 'Source file is not a HDF5 file.' if __name__ == '__main__': diff --git a/tests/test_sourcepoint_restart/tallies.xml b/tests/test_sourcepoint_restart/tallies.xml index 1704f56e1..67a1b50a9 100644 --- a/tests/test_sourcepoint_restart/tallies.xml +++ b/tests/test_sourcepoint_restart/tallies.xml @@ -2,7 +2,7 @@ - rectangular + regular 5 3 4 -10. -5. 0. 10. 4. 9. @@ -20,4 +20,4 @@ fission absorption total flux - \ No newline at end of file + diff --git a/tests/test_statepoint_restart/tallies.xml b/tests/test_statepoint_restart/tallies.xml index 1704f56e1..67a1b50a9 100644 --- a/tests/test_statepoint_restart/tallies.xml +++ b/tests/test_statepoint_restart/tallies.xml @@ -2,7 +2,7 @@ - rectangular + regular 5 3 4 -10. -5. 0. 10. 4. 9. @@ -20,4 +20,4 @@ fission absorption total flux - \ No newline at end of file + diff --git a/tests/test_statepoint_restart/test_statepoint_restart.py b/tests/test_statepoint_restart/test_statepoint_restart.py index 0420dbddf..dd42dc8ff 100644 --- a/tests/test_statepoint_restart/test_statepoint_restart.py +++ b/tests/test_statepoint_restart/test_statepoint_restart.py @@ -1,6 +1,9 @@ #!/usr/bin/env python +import glob +import os import sys + sys.path.insert(0, '..') from testing_harness import * diff --git a/tests/test_statepoint_sourcesep/test_statepoint_sourcesep.py b/tests/test_statepoint_sourcesep/test_statepoint_sourcesep.py index 861a04f18..c7221c90c 100644 --- a/tests/test_statepoint_sourcesep/test_statepoint_sourcesep.py +++ b/tests/test_statepoint_sourcesep/test_statepoint_sourcesep.py @@ -1,6 +1,9 @@ #!/usr/bin/env python +import glob +import os import sys + sys.path.insert(0, '..') from testing_harness import * @@ -12,9 +15,15 @@ class SourcepointTestHarness(TestHarness): source = glob.glob(os.path.join(os.getcwd(), 'source.*')) assert len(source) == 1, 'Either multiple or no source files ' \ 'exist.' - assert source[0].endswith('binary') \ - or source[0].endswith('h5'), \ - 'Source file is not a binary or hdf5 file.' + assert source[0].endswith('h5'), \ + 'Source file is not a HDF5 file.' + + def _cleanup(self): + TestHarness._cleanup(self) + output = glob.glob(os.path.join(os.getcwd(), 'source.*')) + for f in output: + if os.path.exists(f): + os.remove(f) if __name__ == '__main__': diff --git a/tests/test_track_output/test_track_output.py b/tests/test_track_output/test_track_output.py index 31d29b742..dc0eb1a69 100644 --- a/tests/test_track_output/test_track_output.py +++ b/tests/test_track_output/test_track_output.py @@ -1,5 +1,7 @@ #!/usr/bin/env python +import glob +import os import shutil import sys @@ -16,8 +18,8 @@ class TrackTestHarness(TestHarness): outputs.append(glob.glob(''.join((os.getcwd(), '/track_1_1_2.*')))) for files in outputs: assert len(files) == 1, 'Multiple or no track files detected.' - assert files[0].endswith('binary') or files[0].endswith('h5'),\ - 'Track files are not binary or hdf5 files' + assert files[0].endswith('h5'),\ + 'Track files are not HDF5 files' def _get_results(self): """Digest info in the statepoint and return as a string.""" diff --git a/tests/testing_harness.py b/tests/testing_harness.py index 9405db845..3dcbee667 100644 --- a/tests/testing_harness.py +++ b/tests/testing_harness.py @@ -82,9 +82,8 @@ class TestHarness(object): statepoint = glob.glob(os.path.join(os.getcwd(), self._sp_name)) assert len(statepoint) == 1, 'Either multiple or no statepoint files ' \ 'exist.' - assert statepoint[0].endswith('binary') \ - or statepoint[0].endswith('h5'), \ - 'Statepoint file is not a binary or hdf5 file.' + assert statepoint[0].endswith('h5'), \ + 'Statepoint file is not a HDF5 file.' if self._tallies: assert os.path.exists(os.path.join(os.getcwd(), 'tallies.out')), \ 'Tally output file does not exist.' @@ -94,7 +93,6 @@ class TestHarness(object): # Read the statepoint file. statepoint = glob.glob(os.path.join(os.getcwd(), self._sp_name))[0] sp = StatePoint(statepoint) - sp.read_results() # Write out k-combined. outstr = 'k-combined:\n' @@ -104,11 +102,11 @@ class TestHarness(object): # Write out tally data. if self._tallies: tally_num = 1 - for tally_ind in sp._tallies: - tally = sp._tallies[tally_ind] - results = np.zeros((tally._sum.size*2, )) - results[0::2] = tally._sum.ravel() - results[1::2] = tally._sum_sq.ravel() + for tally_ind in sp.tallies: + tally = sp.tallies[tally_ind] + results = np.zeros((tally.sum.size*2, )) + results[0::2] = tally.sum.ravel() + results[1::2] = tally.sum_sq.ravel() results = ['{0:12.6E}'.format(x) for x in results] outstr += 'tally ' + str(tally_num) + ':\n' @@ -155,7 +153,7 @@ class HashedTestHarness(TestHarness): class PlotTestHarness(TestHarness): - """Specialized TestHarness for running OpenMC plotting tests.""" + """Specialized TestHarness for running OpenMC plotting tests.""" def __init__(self, plot_names): self._plot_names = plot_names self._opts = None @@ -199,32 +197,31 @@ class PlotTestHarness(TestHarness): class CMFDTestHarness(TestHarness): - """Specialized TestHarness for running OpenMC CMFD tests.""" + """Specialized TestHarness for running OpenMC CMFD tests.""" def _get_results(self): """Digest info in the statepoint and return as a string.""" # Read the statepoint file. statepoint = glob.glob(os.path.join(os.getcwd(), self._sp_name))[0] sp = StatePoint(statepoint) - sp.read_results() # Write out the eigenvalue and tallies. outstr = TestHarness._get_results(self) # Write out CMFD data. outstr += 'cmfd indices\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in sp._cmfd_indices]) + outstr += '\n'.join(['{0:12.6E}'.format(x) for x in sp.cmfd_indices]) outstr += '\nk cmfd\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in sp._k_cmfd]) + outstr += '\n'.join(['{0:12.6E}'.format(x) for x in sp.k_cmfd]) outstr += '\ncmfd entropy\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in sp._cmfd_entropy]) + outstr += '\n'.join(['{0:12.6E}'.format(x) for x in sp.cmfd_entropy]) outstr += '\ncmfd balance\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in sp._cmfd_balance]) + outstr += '\n'.join(['{0:12.6E}'.format(x) for x in sp.cmfd_balance]) outstr += '\ncmfd dominance ratio\n' - outstr += '\n'.join(['{0:10.3E}'.format(x) for x in sp._cmfd_dominance]) + outstr += '\n'.join(['{0:10.3E}'.format(x) for x in sp.cmfd_dominance]) outstr += '\ncmfd openmc source comparison\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in sp._cmfd_srccmp]) + outstr += '\n'.join(['{0:12.6E}'.format(x) for x in sp.cmfd_srccmp]) outstr += '\ncmfd source\n' - cmfdsrc = np.reshape(sp._cmfd_src, np.product(sp._cmfd_indices), + cmfdsrc = np.reshape(sp.cmfd_src, np.product(sp.cmfd_indices), order='F') outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfdsrc]) outstr += '\n' @@ -233,15 +230,14 @@ class CMFDTestHarness(TestHarness): class ParticleRestartTestHarness(TestHarness): - """Specialized TestHarness for running OpenMC particle restart tests.""" + """Specialized TestHarness for running OpenMC particle restart tests.""" def _test_output_created(self): """Make sure the restart file has been created.""" particle = glob.glob(os.path.join(os.getcwd(), self._sp_name)) assert len(particle) == 1, 'Either multiple or no particle restart ' \ 'files exist.' - assert particle[0].endswith('binary') \ - or particle[0].endswith('h5'), \ - 'Particle restart file is not a binary or hdf5 file.' + assert particle[0].endswith('h5'), \ + 'Particle restart file is not a HDF5 file.' def _get_results(self): """Digest info in the statepoint and return as a string.""" @@ -258,7 +254,7 @@ class ParticleRestartTestHarness(TestHarness): outstr += 'particle id:\n' outstr += "{0:12.6E}\n".format(p.id) outstr += 'run mode:\n' - outstr += "{0:12.6E}\n".format(p.run_mode) + outstr += "{0}\n".format(p.run_mode) outstr += 'particle weight:\n' outstr += "{0:12.6E}\n".format(p.weight) outstr += 'particle energy:\n' diff --git a/tests/travis.sh b/tests/travis.sh index fac8d793a..443e951cc 100755 --- a/tests/travis.sh +++ b/tests/travis.sh @@ -5,7 +5,7 @@ set -ev # Run all debug tests ./check_source.py if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then - ./run_tests.py -C "^basic-debug$|^hdf5-debug$|^mpi-omp-debug$|^phdf5-omp-debug$" -j 2 -s + ./run_tests.py -C "^hdf5-debug$|^omp-hdf5-debug|^mpi-hdf5-debug|^phdf5-debug$|^phdf5-omp-debug$" -j 2 -s else - ./run_tests.py -C "^basic-debug$" -j 2 + ./run_tests.py -C "^hdf5-debug$" -j 2 fi