diff --git a/.github/workflows/run-unit-tests.yml b/.github/workflows/run-unit-tests.yml new file mode 100644 index 0000000..350b758 --- /dev/null +++ b/.github/workflows/run-unit-tests.yml @@ -0,0 +1,58 @@ +name: MOOSE Tests + +on: + push: + branches: + - main + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + + steps: + + - name: Install Apptainer + uses: eWaterCycle/setup-apptainer@v2 + with: + apptainer-version: 1.3.6 + + - name: Restore Apptainer library + run: | + apptainer remote add --no-login SylabsCloud cloud.sycloud.io + apptainer remote use SylabsCloud + + + - name: Checkout repository + uses: actions/checkout@v4 + with: + path: Fizzy + + - name: Pull Apptainer image + run: | + apptainer pull library://billellis.07/fizzy/fizzy_cont_202112 + + - name: Build application + run: | + apptainer cache clean --force + df -h + apptainer overlay create --size 1024 overlay.img + apptainer exec \ + --bind ${{ github.workspace }}:/workspace \ + --overlay overlay.img \ + fizzy_cont_202112_latest.sif \ + bash -c " + . /opt/intel/oneapi/setvars.sh && + cd /workspace/Fizzy/unit && + make -j$(nproc) + " + + - name: Run tests + run: | + apptainer exec \ + --bind ${{ github.workspace }}:/workspace \ + fizzy_cont_202112_latest.sif \ + bash -c " + cd /workspace/Fizzy/unit && + ./fizzy-unit-opt -j$(nproc) + " diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..37f64e3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "FizzyCompiledSource"] + path = FizzyCompiledSource + url = https://github.com/TheBEllis/FizzyCompiledSource diff --git a/FizzyCompiledSource b/FizzyCompiledSource new file mode 160000 index 0000000..e2633a9 --- /dev/null +++ b/FizzyCompiledSource @@ -0,0 +1 @@ +Subproject commit e2633a93d717b54691574fa9e49c78285f145f6c diff --git a/Makefile b/Makefile index d15b0c9..7f99a75 100644 --- a/Makefile +++ b/Makefile @@ -86,9 +86,9 @@ export LDFLAGS := $(libmesh_LDFLAGS) export LIBS := $(libmesh_LIBS) FISPACT_DIR ?= ${MOOSE_DIR}/../FISPACT/ubuntu/20.10 +FISPACT_DIR ?= ${MOOSE_DIR} FISPACT_INCLUDES ?= -I ${FISPACT_DIR}/include/c -I ${FISPACT_DIR}/include/cpp -FISPACT_LIB_DIR ?= ${FISPACT_DIR}/lib/ -# FISPACT_LIB ?= +FISPACT_LIB_DIR ?= ${FISPACT_DIR}/lib/linux PUGIXML_DIR ?= $(MOOSE_DIR)/../pugixml/ PUGIXML_INCLUDES ?= -I $(PUGIXML_DIR)/src/ @@ -96,8 +96,13 @@ PUGIXML_LIB_DIR ?= ${PUGIXML_DIR}/build/ HDF5_DIR ?= /usr/lib/x86_64-linux-gnu/hdf5/openmpi/lib/ -ADDITIONAL_LIBS := -L$(FISPACT_LIB_DIR) -ljsonfortran -lmonitor -lfispact -lfispactapi -lfmt -L$(PUGIXML_LIB_DIR) -lpugixml -L$(HDF5_DIR) -lhdf5 -lhdf5_cpp -ADDITIONAL_LIBS += $(CC_LINKER_SLFLAG)$(FISPACT_LIB_DIR) +ADDITIONAL_LIBS := -L$(FISPACT_LIB_DIR) -ljsonfortran -lmonitor -lfispact -lfispactapi -L$(PUGIXML_LIB_DIR) -lpugixml -L$(HDF5_DIR) -lhdf5 -lspdlog +# ADDITIONAL_LIBS += $(CC_LINKER_SLFLAG)$(FISPACT_LIB_DIR) ADDITIONAL_CPPFLAGS += $(FISPACT_INCLUDES) ${PUGIXML_INCLUDES} +FIZZY_EXTERNAL_FLAGS = ${ADDITIONAL_LIBS} ${ADDITIONAL_CPPFLAGS} + +$(app_LIB): EXTERNAL_FLAGS := $(FIZZY_EXTERNAL_FLAGS) +$(app_test_LIB): EXTERNAL_FLAGS := $(FIZZY_EXTERNAL_FLAGS) +$(app_EXEC): EXTERNAL_FLAGS := $(FIZZY_EXTERNAL_FLAGS) diff --git a/README.md b/README.md index 1d82523..396f78c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,69 @@ -Fizzy -===== +# Fizzy + +Fizzy is a MOOSE application wrapping the nuclear inventory, source term and multi-physics code, FISPACT-II. + +## Dependencies +- [FISPACT-II](https://www.ukaea.org/service/fispact/)(5.0+) binaries. +- A working [MOOSE](https://mooseframework.inl.gov/) build. + - Being a MOOSE based application, Fizzy also has the same [minimum requirements](https://mooseframework.inl.gov/sqa/minimum_requirements.html) as MOOSE. +- PugiXML + - PugiXML can be installed easily from most package managers + - `sudo apt install libpugixml` + +## Obtaining Fizzy + +To obtain Fizzy, simply clone this repository. + +```language=bash +git clone https://github.com/TheBEllis/Fizzy.git +cd Fizzy +``` + +## Install + +> [!WARNING] +> Fizzy has only been tested on Ubuntu 24.04 (so far). Other Linux distros, MacOS and Windows have not been tested. If users trying to run Fizzy on these platforms +experience issues with installation and/or running, please report the issue on Fizzy's [github issues](https://github.com/TheBEllis/Fizzy/issues) page. + +To install Fizzy, users must specify the directory containg their FISPACT-II binaries. This can be done using the environment variable `FISPACT_DIR`. The exact directory will differe depending on the version of FISPACT-II being used. + +Users must also make sure that the relevent FISPACT-II libraries are present in their `LD_LIBRARY_PATH`. + +#### For FISPACT-II V5.1 + +```language=bash +export FISPACT_DIR=/path/to/FISPACT/api/ +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:path/to/FISPACT/api/lib/linux +``` + +#### For FISPACT-II V5.0 + +```language=bash +export FISPACT_DIR=/path/to/FISPACT/ubuntu/20.10 +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:path/to/FISPACT/ubuntu/20.10/lib +``` + +> [!IMPORTANT] +> The exact directories that need to be set may differ depending on users directory structure. By setting `FISPACT_DIR`, Fizzy will automatically look for FISPACT libraries and includes at `${FISPACT_DIR}/lib/linux` and `${FISPACT_DIR}/includes/cpp`. Users can manually set the locations of libraries and includes by settings the environment variables `FISPACT_LIB_DIR` and `FISPACT_INCLUDE_DIR`. + +The final step is to run `make` in the Fizzy root directory. After a successful install, an executable called `Fizzy-opt` should be found in the application root directory. + +```language=bash +cd /path/to/Fizzy +make -j 4 +``` + +## Building docs +Due to Fizzy currently being private, the only way to access documentation is by building it locally. Users can do this by running. + +``` +cd /path/to/Fizzy/doc +./moosedocs.py build --destination ./build_folder +``` + +This will populate the specified `build_folder` with html files. To access the documentation after building, `cd` into the build folder and open `index.html` from your chosen web browser. + +## References + -Fork "Fizzy" to create a new MOOSE-based application. -For more information see: [https://mooseframework.inl.gov/getting_started/new_users.html#create-an-app](https://mooseframework.inl.gov/getting_started/new_users.html#create-an-app) diff --git a/doc/config.yml b/doc/config.yml index cf01956..cff4c24 100644 --- a/doc/config.yml +++ b/doc/config.yml @@ -3,18 +3,80 @@ Content: root_dir: ${ROOT_DIR}/doc/content moose: root_dir: ${MOOSE_DIR}/framework/doc/content + fluid_properties: + root_dir: ${MOOSE_DIR}/modules/fluid_properties/doc/content + heat_transfer: + root_dir: ${MOOSE_DIR}/modules/heat_transfer/doc/content + navier_stokes: + root_dir: ${MOOSE_DIR}/modules/navier_stokes/doc/content + ray_tracing: + root_dir: ${MOOSE_DIR}/modules/ray_tracing/doc/content + reactor: + root_dir: ${MOOSE_DIR}/modules/reactor/doc/content + solid_mechanics: + root_dir: ${MOOSE_DIR}/modules/solid_mechanics/doc/content + solid_properties: + root_dir: ${MOOSE_DIR}/modules/solid_properties/doc/content + stochastic_tools: + root_dir: ${MOOSE_DIR}/modules/stochastic_tools/doc/content + subchannel: + root_dir: ${MOOSE_DIR}/modules/subchannel/doc/content + thermal_hydraulics: + root_dir: ${MOOSE_DIR}/modules/thermal_hydraulics/doc/content + modules: + root_dir: ${MOOSE_DIR}/modules/doc/content content: - - js/* - - css/* - - contrib/** - - media/** + - help/development/VSCode.md + - help/development/analyze_jacobian.md + - help/finite_element_concepts/nodal_patch_recovery.md + - application_development/performance_benchmarking.md + - application_usage/restart_recover.md + - application_usage/command_line_usage.md + python: + root_dir: ${MOOSE_DIR}/python/doc/content + content: + - python/mms.md + - python/MooseDocs/** + - python/moosesqa/index.md + - python/source/moosetree/Node.md + - python/testers/** + - python/CSVDiff.md + - python/TestHarness.md + Renderer: type: MooseDocs.base.MaterializeRenderer + Extensions: MooseDocs.extensions.navigation: name: Fizzy + repo: https://github.com/TheBEllis/Fizzy + menu: + Getting Started: + Installation: start.md + Documentation: + Tutorials: /tutorials/index.md + Input Syntax: /source/index.md + + MooseDocs.extensions.common: + shortcuts: + !include ${MOOSE_DIR}/framework/doc/globals.yml + MooseDocs.extensions.appsyntax: executable: ${ROOT_DIR} - remove: !include ${MOOSE_DIR}/framework/doc/remove.yml - includes: - - include + app_name: Fizzy + # remove: + # framework: !include ${MOOSE_DIR}/framework/doc/remove.yml + # unregister: + # framework: !include ${MOOSE_DIR}/framework/doc/unregister.yml + + MooseDocs.extensions.acronym: + acronyms: !include ${MOOSE_DIR}/framework/doc/acronyms.yml + + MooseDocs.extensions.template: + active: True + +globals: + type: MooseDocs.extensions.common + shortcuts: + + diff --git a/doc/content/index.md b/doc/content/index.md index 5d0f0d9..d76b165 100644 --- a/doc/content/index.md +++ b/doc/content/index.md @@ -1,3 +1,11 @@ !config navigation breadcrumbs=False scrollspy=False -# FizzyApp +# Fizzy class=center style=font-weight:200;font-size:400% + +!style halign=center fontsize=120% +Enabling FISPACT-II solves on unstructured meshes + +Fizzy utilises [FISPACT-II](https://www.ukaea.org/service/fispact/) APIs to enable easier usage of the nuclear inventory and source term code on unstructured meshes. + +It is primarily designed for use when the user has tallied neutron transport results on an unstructured mesh. + diff --git a/doc/content/media/FizzyDocsFlow.drawio b/doc/content/media/FizzyDocsFlow.drawio new file mode 100644 index 0000000..9913486 --- /dev/null +++ b/doc/content/media/FizzyDocsFlow.drawio @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/content/media/FizzyDocsFlow.png b/doc/content/media/FizzyDocsFlow.png new file mode 100644 index 0000000..dceffe9 Binary files /dev/null and b/doc/content/media/FizzyDocsFlow.png differ diff --git a/doc/content/media/FizzyFlow.png b/doc/content/media/FizzyFlow.png new file mode 100644 index 0000000..82e7290 Binary files /dev/null and b/doc/content/media/FizzyFlow.png differ diff --git a/doc/content/media/FizzyFlowNoneutrons.png b/doc/content/media/FizzyFlowNoneutrons.png new file mode 100644 index 0000000..cb745dd Binary files /dev/null and b/doc/content/media/FizzyFlowNoneutrons.png differ diff --git a/doc/content/media/Nb93.mp4 b/doc/content/media/Nb93.mp4 new file mode 100644 index 0000000..4c0b644 Binary files /dev/null and b/doc/content/media/Nb93.mp4 differ diff --git a/doc/content/source/actions/AddPhotonSpectraVectorPPAllBlocks.md b/doc/content/source/actions/AddPhotonSpectraVectorPPAllBlocks.md new file mode 100644 index 0000000..b393bed --- /dev/null +++ b/doc/content/source/actions/AddPhotonSpectraVectorPPAllBlocks.md @@ -0,0 +1,21 @@ +# AddPhotonSpectraVectorPPAllBlocks + +!alert construction title=Undocumented Action Class +The AddPhotonSpectraVectorPPAllBlocks has not been documented. The content listed below should be used as a starting point for +documenting the class, which includes the typical automatic documentation associated with an Action; +however, what is contained is ultimately determined by what is necessary to make the documentation +clear for users. + +!syntax description /VectorPostprocessors/PhotonEmissionAllBlocks/AddPhotonSpectraVectorPPAllBlocks + +## Overview + +!! Replace these lines with information regarding the AddPhotonSpectraVectorPPAllBlocks action. + +## Example Input File Syntax + +!! Describe and include an example of how to use the AddPhotonSpectraVectorPPAllBlocks action. + +!syntax description /VectorPostprocessors/PhotonEmissionAllBlocks/AddPhotonSpectraVectorPPAllBlocks + +!syntax parameters /VectorPostprocessors/PhotonEmissionAllBlocks/AddPhotonSpectraVectorPPAllBlocks diff --git a/doc/content/source/auxkernels/FispactElementKernel.md b/doc/content/source/auxkernels/FispactElementKernel.md new file mode 100644 index 0000000..27e003a --- /dev/null +++ b/doc/content/source/auxkernels/FispactElementKernel.md @@ -0,0 +1,23 @@ +# FispactElementKernel + +!alert construction title=Undocumented Class +The FispactElementKernel has not been documented. The content listed below should be used as a starting point for +documenting the class, which includes the typical automatic documentation associated with a +MooseObject; however, what is contained is ultimately determined by what is necessary to make the +documentation clear for users. + +!syntax description /AuxVariables/AuxKernel/FispactElementKernel + +## Overview + +!! Replace these lines with information regarding the FispactElementKernel object. + +## Example Input File Syntax + +!! Describe and include an example of how to use the FispactElementKernel object. + +!syntax parameters /AuxVariables/AuxKernel/FispactElementKernel + +!syntax inputs /AuxVariables/AuxKernel/FispactElementKernel + +!syntax children /AuxVariables/AuxKernel/FispactElementKernel diff --git a/doc/content/source/auxkernels/FispactNuclideKernel.md b/doc/content/source/auxkernels/FispactNuclideKernel.md new file mode 100644 index 0000000..6a4958e --- /dev/null +++ b/doc/content/source/auxkernels/FispactNuclideKernel.md @@ -0,0 +1,23 @@ +# FispactNuclideKernel + +!alert construction title=Undocumented Class +The FispactNuclideKernel has not been documented. The content listed below should be used as a starting point for +documenting the class, which includes the typical automatic documentation associated with a +MooseObject; however, what is contained is ultimately determined by what is necessary to make the +documentation clear for users. + +!syntax description /AuxVariables/AuxKernel/FispactNuclideKernel + +## Overview + +!! Replace these lines with information regarding the FispactNuclideKernel object. + +## Example Input File Syntax + +!! Describe and include an example of how to use the FispactNuclideKernel object. + +!syntax parameters /AuxVariables/AuxKernel/FispactNuclideKernel + +!syntax inputs /AuxVariables/AuxKernel/FispactNuclideKernel + +!syntax children /AuxVariables/AuxKernel/FispactNuclideKernel diff --git a/doc/content/source/index.md b/doc/content/source/index.md new file mode 100644 index 0000000..f2c5f29 --- /dev/null +++ b/doc/content/source/index.md @@ -0,0 +1,4 @@ +!config navigation collapsible-sections=[None, 'open', 'open', 'open', 'open', 'open'] + +!content location=source + diff --git a/doc/content/source/postprocessors/ElementPhotonEmission.md b/doc/content/source/postprocessors/ElementPhotonEmission.md new file mode 100644 index 0000000..85cb907 --- /dev/null +++ b/doc/content/source/postprocessors/ElementPhotonEmission.md @@ -0,0 +1,23 @@ +# ElementPhotonEmission + +!alert construction title=Undocumented Class +The ElementPhotonEmission has not been documented. The content listed below should be used as a starting point for +documenting the class, which includes the typical automatic documentation associated with a +MooseObject; however, what is contained is ultimately determined by what is necessary to make the +documentation clear for users. + +!syntax description /UserObjects/ElementPhotonEmission + +## Overview + +!! Replace these lines with information regarding the ElementPhotonEmission object. + +## Example Input File Syntax + +!! Describe and include an example of how to use the ElementPhotonEmission object. + +!syntax parameters /UserObjects/ElementPhotonEmission + +!syntax inputs /UserObjects/ElementPhotonEmission + +!syntax children /UserObjects/ElementPhotonEmission diff --git a/doc/content/source/postprocessors/NuclideMetric.md b/doc/content/source/postprocessors/NuclideMetric.md new file mode 100644 index 0000000..fbaedc5 --- /dev/null +++ b/doc/content/source/postprocessors/NuclideMetric.md @@ -0,0 +1,23 @@ +# NuclideMetric + +!alert construction title=Undocumented Class +The NuclideMetric has not been documented. The content listed below should be used as a starting point for +documenting the class, which includes the typical automatic documentation associated with a +MooseObject; however, what is contained is ultimately determined by what is necessary to make the +documentation clear for users. + +!syntax description /UserObjects/NuclideMetric + +## Overview + +!! Replace these lines with information regarding the NuclideMetric object. + +## Example Input File Syntax + +!! Describe and include an example of how to use the NuclideMetric object. + +!syntax parameters /UserObjects/NuclideMetric + +!syntax inputs /UserObjects/NuclideMetric + +!syntax children /UserObjects/NuclideMetric diff --git a/doc/content/source/postprocessors/SubdomainPhotonEmission.md b/doc/content/source/postprocessors/SubdomainPhotonEmission.md new file mode 100644 index 0000000..271b1ca --- /dev/null +++ b/doc/content/source/postprocessors/SubdomainPhotonEmission.md @@ -0,0 +1,23 @@ +# SubdomainPhotonEmission + +!alert construction title=Undocumented Class +The SubdomainPhotonEmission has not been documented. The content listed below should be used as a starting point for +documenting the class, which includes the typical automatic documentation associated with a +MooseObject; however, what is contained is ultimately determined by what is necessary to make the +documentation clear for users. + +!syntax description /UserObjects/SubdomainPhotonEmission + +## Overview + +!! Replace these lines with information regarding the SubdomainPhotonEmission object. + +## Example Input File Syntax + +!! Describe and include an example of how to use the SubdomainPhotonEmission object. + +!syntax parameters /UserObjects/SubdomainPhotonEmission + +!syntax inputs /UserObjects/SubdomainPhotonEmission + +!syntax children /UserObjects/SubdomainPhotonEmission diff --git a/doc/content/source/problems/FispactProblem.md b/doc/content/source/problems/FispactProblem.md new file mode 100644 index 0000000..d76f734 --- /dev/null +++ b/doc/content/source/problems/FispactProblem.md @@ -0,0 +1,53 @@ +# FispactProblem + +!alert construction title=Undocumented Class +The FispactProblem has not been documented. The content listed below should be used as a starting point for +documenting the class, which includes the typical automatic documentation associated with a +MooseObject; however, what is contained is ultimately determined by what is necessary to make the +documentation clear for users. + +!syntax description /Problem/FispactProblem + +## Overview + +The FispactProblem does most of the heavy lifiting for interfacing FISPACT-II's API with MOOSE's existing framework. + +## Example Input File Syntax + +!listing /tutorials/tutorial_1/input.i + id=simple-input + caption=A simple Fizzy input file. + +## Logic Flow + +[Figure 1](#fizzyflow) shows the logic within the +externalSolve+ method. The logic here is fairly simple. Each MPI rank loops over its local elements, and reads in the flux spectra corresponding to the current element from a given results file. Using user provided material properties and the read in flux, FISPACT-II input data is set, and then a calculation is run. + +!media media/FizzyDocsFlow.png + id=fizzyflow + style=width:100%;float:centre + prefix=Figure + caption=Logic flow in Fizzy externalSolve method + + Given these flux spectra often have on the order of 1000 energy bins, they can be a real memory hog. By reading in the flux spectra corresponding to the current loop iteration within the scope of the loop, we reduce maximum memory utilisation. Only one flux spectra is ever in scope for each MPI rank. + +Another potential memory hoarder is the nuclear inventory data generated by FISPACT-II. FISPACT-II provides users various quantities relating to all of the nuclides within the nuclear inventory. Once again we keep the output inventory data within the scope of the main solve loop, so that only one output object existson any one MPI rank at any time. However, we may want to do further operations on some of these nuclear inventory statistics later in the simulation, for example within an AuxKernel. Therefore, we need a system to extract requested inventory metrics for later retrieval, before the output data goes out of scope. For this we use the [Inventory Management system](#invmanage). + +## Inventory Management id=invmanage + +FISPACT-II produces a wealth of inventory data. Therefore it is infeasible to keep all data on all nuclides from every element in memory, especially when a high fidelity mesh is being used. To get around this, we only keep the data requested from other objects in the simulation. To manage these requests, we have implemented the [FispactInventoryManager](source/userobjects/FispactInventoryManager.md) object. This object stores the quantities requested by AuxKernels/PostProcessors, and extracts them from the FISPACT output objects. + +## Time Stepping + +### Steady + +For [Steady](source/executioners/Steady.md) simulations, the user can choose which time in the provided FispactSchedule they would like to use as their output, using the +output_inventory_time+ parameter. By default, values from the last entry in the irradiation schedule will be used in the output. + +### Transient + +The way FISPACT-II handles timestepping and the way MOOSE handles timestepping are, in short, not immediately compatible. FISPACT-II calculates nuclear inventories for all times defined in the irradiation [schedule](source/userobjects/FispactSchedule.md) in one API call. MOOSE on the other hand expects to run the +externalSolve+ method once every timestep. To get around this, we do all of the FISPACT calculations on the first MOOSE timestep i.e. the first time +externalSolve()+ is called. Data for all timesteps is then extracted from the output object.Later MOOSE timesteps query the stored data, but do not actually do any solving. + +!syntax parameters /Problem/FispactProblem + +!syntax inputs /Problem/FispactProblem + +!! !syntax children /Problem/FispactProblem diff --git a/doc/content/source/userobjects/FispactInventoryManager.md b/doc/content/source/userobjects/FispactInventoryManager.md new file mode 100644 index 0000000..1fa5bd9 --- /dev/null +++ b/doc/content/source/userobjects/FispactInventoryManager.md @@ -0,0 +1,26 @@ +# FispactInventoryManager + +!alert construction title=Undocumented Class +The FispactInventoryManager has not been documented. The content listed below should be used as a starting point for +documenting the class, which includes the typical automatic documentation associated with a +MooseObject; however, what is contained is ultimately determined by what is necessary to make the +documentation clear for users. + +!syntax description /UserObjects/FispactInventoryManager + +## Overview + + + + +!! Replace these lines with information regarding the FispactInventoryManager object. + +## Example Input File Syntax + +!! Describe and include an example of how to use the FispactInventoryManager object. + +!syntax parameters /UserObjects/FispactInventoryManager + +!syntax inputs /UserObjects/FispactInventoryManager + +!syntax children /UserObjects/FispactInventoryManager diff --git a/doc/content/source/userobjects/FispactMaterial.md b/doc/content/source/userobjects/FispactMaterial.md new file mode 100644 index 0000000..41dbd92 --- /dev/null +++ b/doc/content/source/userobjects/FispactMaterial.md @@ -0,0 +1,23 @@ +# FispactMaterial + +!alert construction title=Undocumented Class +The FispactMaterial has not been documented. The content listed below should be used as a starting point for +documenting the class, which includes the typical automatic documentation associated with a +MooseObject; however, what is contained is ultimately determined by what is necessary to make the +documentation clear for users. + +!syntax description /UserObjects/FispactMaterial + +## Overview + +!! Replace these lines with information regarding the FispactMaterial object. + +## Example Input File Syntax + +!! Describe and include an example of how to use the FispactMaterial object. + +!syntax parameters /UserObjects/FispactMaterial + +!syntax inputs /UserObjects/FispactMaterial + +!syntax children /UserObjects/FispactMaterial diff --git a/doc/content/source/userobjects/FispactNuclearDataPaths.md b/doc/content/source/userobjects/FispactNuclearDataPaths.md new file mode 100644 index 0000000..676a3b9 --- /dev/null +++ b/doc/content/source/userobjects/FispactNuclearDataPaths.md @@ -0,0 +1,23 @@ +# FispactNuclearDataPaths + +!alert construction title=Undocumented Class +The FispactNuclearDataPaths has not been documented. The content listed below should be used as a starting point for +documenting the class, which includes the typical automatic documentation associated with a +MooseObject; however, what is contained is ultimately determined by what is necessary to make the +documentation clear for users. + +!syntax description /UserObjects/FispactNuclearDataPaths + +## Overview + +!! Replace these lines with information regarding the FispactNuclearDataPaths object. + +## Example Input File Syntax + +!! Describe and include an example of how to use the FispactNuclearDataPaths object. + +!syntax parameters /UserObjects/FispactNuclearDataPaths + +!syntax inputs /UserObjects/FispactNuclearDataPaths + +!syntax children /UserObjects/FispactNuclearDataPaths diff --git a/doc/content/source/userobjects/FispactSchedule.md b/doc/content/source/userobjects/FispactSchedule.md new file mode 100644 index 0000000..f3c393b --- /dev/null +++ b/doc/content/source/userobjects/FispactSchedule.md @@ -0,0 +1,23 @@ +# FispactSchedule + +!alert construction title=Undocumented Class +The FispactSchedule has not been documented. The content listed below should be used as a starting point for +documenting the class, which includes the typical automatic documentation associated with a +MooseObject; however, what is contained is ultimately determined by what is necessary to make the +documentation clear for users. + +!syntax description /UserObjects/FispactSchedule + +## Overview + +!! Replace these lines with information regarding the FispactSchedule object. + +## Example Input File Syntax + +!! Describe and include an example of how to use the FispactSchedule object. + +!syntax parameters /UserObjects/FispactSchedule + +!syntax inputs /UserObjects/FispactSchedule + +!syntax children /UserObjects/FispactSchedule diff --git a/doc/content/source/userobjects/OpenMCFluxInput.md b/doc/content/source/userobjects/OpenMCFluxInput.md new file mode 100644 index 0000000..1b9500e --- /dev/null +++ b/doc/content/source/userobjects/OpenMCFluxInput.md @@ -0,0 +1,23 @@ +# OpenMCFluxInput + +!alert construction title=Undocumented Class +The OpenMCFluxInput has not been documented. The content listed below should be used as a starting point for +documenting the class, which includes the typical automatic documentation associated with a +MooseObject; however, what is contained is ultimately determined by what is necessary to make the +documentation clear for users. + +!syntax description /UserObjects/OpenMCFluxInput + +## Overview + +!! Replace these lines with information regarding the OpenMCFluxInput object. + +## Example Input File Syntax + +!! Describe and include an example of how to use the OpenMCFluxInput object. + +!syntax parameters /UserObjects/OpenMCFluxInput + +!syntax inputs /UserObjects/OpenMCFluxInput + +!syntax children /UserObjects/OpenMCFluxInput diff --git a/doc/content/source/vectorpostprocessors/SubdomainPhotonEmissionSpectraPostprocessor.md b/doc/content/source/vectorpostprocessors/SubdomainPhotonEmissionSpectraPostprocessor.md new file mode 100644 index 0000000..543eb2c --- /dev/null +++ b/doc/content/source/vectorpostprocessors/SubdomainPhotonEmissionSpectraPostprocessor.md @@ -0,0 +1,23 @@ +# SubdomainPhotonEmissionSpectraPostprocessor + +!alert construction title=Undocumented Class +The SubdomainPhotonEmissionSpectraPostprocessor has not been documented. The content listed below should be used as a starting point for +documenting the class, which includes the typical automatic documentation associated with a +MooseObject; however, what is contained is ultimately determined by what is necessary to make the +documentation clear for users. + +!syntax description /VectorPostprocessors/SubdomainPhotonEmissionSpectraPostprocessor + +## Overview + +!! Replace these lines with information regarding the SubdomainPhotonEmissionSpectraPostprocessor object. + +## Example Input File Syntax + +!! Describe and include an example of how to use the SubdomainPhotonEmissionSpectraPostprocessor object. + +!syntax parameters /VectorPostprocessors/SubdomainPhotonEmissionSpectraPostprocessor + +!syntax inputs /VectorPostprocessors/SubdomainPhotonEmissionSpectraPostprocessor + +!syntax children /VectorPostprocessors/SubdomainPhotonEmissionSpectraPostprocessor diff --git a/doc/content/start.md b/doc/content/start.md new file mode 100644 index 0000000..1882b17 --- /dev/null +++ b/doc/content/start.md @@ -0,0 +1,106 @@ +# Installation + +## Prerequisites + +- A working +MOOSE+ build Currently Fizzy has not been tested using MOOSE's conda environment, only MOOSE builds from source. Being a MOOSE based app, Fizzy shared MOOSE's [minimum requirements](http://mooseframework.inl.gov/sqa/minimum_requirements.html) +- Access to FISPACT-II binaries (5.0+) + + - FISPACT-II licenses can be purchase from [this](https://www.ukaea.org/service/fispact/) link. + +- [PugiXML](https://pugixml.org/) (1.14+) + + - PugiXML can be easily installed from most package managers. + + ``` + sudo apt install libpugixml-dev + ``` + +- [BOOST](https://www.boost.org/doc/user-guide/getting-started.html) Libraries + - This application makes use of `boost::interprocess`. Most users should be able to install BOOST libraries via their package manager. For Debian/Ubuntu users, this would look like: + + ``` + sudo apt install sudo apt install libboost-all-dev + ``` + +- [spdlog](https://github.com/gabime/spdlog) Libraries + - FISPACT-II's internal monitoring depends on libspdlog being available on the system + + ``` + sudo apt install libspdlog-dev + ``` + +!alert! note title=Recommended +> To use all of Fizzy's capabilities, users will also need a valid [Cardinal](https://cardinal.cels.anl.gov/) installation. Instructions on how to install Cardinal can be found [here](https://cardinal.cels.anl.gov/start.html). +> Using Fizzy and Cardinal together, users can perform particle transport using a source term generated by Fizzy. This may be used to perform shutdown dose rate calculations, for example. +!alert-end! + +[Tutorial 4](/) demonstrates how Fizzy and Cardinal can be used together. + +## Access + +To access Fizzy, clone the repository and cd into the directory + +```language=bash +git clone https://github.com/TheBEllis/Fizzy.git +cd Fizzy +``` + +## Installing + +!alert warning +Fizzy has only been tested on Ubuntu 24.04 (so far). Other Linux distros, MacOS and Windows have not been tested. If users trying to run Fizzy on these platforms +experience issues with installation and/or running, please report the issue on Fizzy's [github issues](https://github.com/TheBEllis/Fizzy/issues) page. + +To install Fizzy, users must specify the directory of their FISPACT-II binaries by setting the environment variable `FISPACT_DIR`. The exact directory will differ depending on the version of FISPACT-II the user has available. + +Users must also make sure that the relevent FISPACT-II libraries are present in their `LD_LIBRARY_PATH`. + + +#### FISPACT-II V5.1 + +```language=bash +export FISPACT_DIR=/path/to/FISPACT/api/ +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:path/to/FISPACT/api/lib/linux +``` + +#### FISPACT-II V5.0 + +```language=bash +export FISPACT_DIR=/path/to/FISPACT/ubuntu/20.10 +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:path/to/FISPACT/ubuntu/20.10/lib +``` + +!alert warning +The exact directories that need to be set may differ depending on users directory structure. By setting `FISPACT_DIR`, Fizzy will automatically look for FISPACT libraries and includes at `${FISPACT_DIR}/lib/linux` and `${FISPACT_DIR}/includes/cpp`. Users can manually set the locations of libraries and includes by settings the environment variables `FISPACT_LIB_DIR` and `FISPACT_INCLUDE_DIR`. + +The final step is to run `make` in the Fizzy root directory. After a successful install, an executable called `Fizzy-opt` should be found in the application root directory. + +```language=bash +make -j 4 +``` + +## Verifying installation. + +To verify Fizzy has been installed correctly, users can run example problems found in `/Fizzy/tutorials`. However, to run these tutorials, users need access to a suitable nuclear data set. The FISPACT-II nuclear data repository can be found [here](https://git.oecd-nea.org/fispact/nuclear_data/). The tutorials all make use of ENDFB80 nuclear data, so it is recommended that first time users download this nuclear data set. + +By default the `base_path` parameter in Tutorial 1's input file points to `/Projects/FispactNuclearData`. Users must change this directory to the directory on their local machine containing the downloaded nuclear data in their local filesystem. + +!listing /tutorials/tutorial_1/input.i + block=UserObjects/endf_nuclear_data + id=nd-block + caption=The user defined +Nuclear Data+ + +Then they are ready to run the input file. + +```language=bash +./Fizzy-opt -i tutorials/tutorial_1/input.i +``` + + +## Tutorials + +Click the link to access Fizzy tutorials that take you through the available functionality. + +!content pagination use_title=True + next=tutorials/index.md + diff --git a/doc/content/tutorials/index.md b/doc/content/tutorials/index.md new file mode 100644 index 0000000..3347f32 --- /dev/null +++ b/doc/content/tutorials/index.md @@ -0,0 +1,20 @@ +# Tutorials + +Fizzy is designed to work similarly to other MOOSE applications, in terms of its interoperability with other MOOSE applications. Any quantity that can be mapped to an auxiliary variable can be used within the existing MOOSE [Transfers](Transfers/index.md) system to communicate it's values with other MOOSE apps. + + +## Tutorial 1: Just FISPACT + +[Tutorial 1](tutorials/tutorial_1/index.md) will take you through how to set up a simple Fizzy application. This tutorial details the bare essentials of a Fizzy input file + +## Tutorial 2: Adding AuxVariables, AuxKernels and Postprocessors + +[Tutorial 2](tutorials/tutorial_2/index.md) will take you through how to add AuxVariables and AuxKernels to an input file in order to capture nuclear inventory quantities. + +## Tutorial 3: Transient Simulations + +[Tutorial 3](tutorials/tutorial_3/index.md) will take you through how to set up a transient Fizzy application, allowing the user to visualise how the inventory develops over time. + +## Tutorial 4: Coupling with Cardinal/OpenMC + +[Tutorial 4](tutorials/tutorial_4/index.md) will take you through how to set up a Fizzy application that couples to Cardinal/OpenMC to perform dose rate analysis. diff --git a/doc/content/tutorials/tutorial_1/index.md b/doc/content/tutorials/tutorial_1/index.md new file mode 100644 index 0000000..0d499d8 --- /dev/null +++ b/doc/content/tutorials/tutorial_1/index.md @@ -0,0 +1,100 @@ +# Fizzy tutorial 1: Just FISPACT + +This tutorial will focus on getting a base level input file prepared for a FISPACT solve using Fizzy. + +There are +6 necessary components+ to a Fizzy input file, + +1. [#mesh-section] +2. [#problem-section] +3. [#schedule] +4. [#input-flux] +5. [#materials] +6. [#nd] +7. [#exec] + +## The Mesh id=mesh-section + +!listing /tutorials/tutorial_1/input.i + block=Mesh + id=mesh-block + caption=The +Mesh+ block + +A Fizzy input file defines the mesh just like a standard [MOOSE](https://mooseframework.inl.gov/syntax/Mesh/) input file. There are no special requirements for a mesh using exclusively Fizzy, however restrictions do exist when coupling with [Cardinal], these are discussed in latter [tutorials](tutorials/tutorial_2/index.md). + +## The Problem id=problem-section + +!listing /tutorials/tutorial_1/input.i + block=Problem + id=problem-block + caption=User defined +irradiation schedule+" + + +The problem block represents the first significant departure from a standard MOOSE input. Here, a problem of type [FispactProblem](source/problems/FispactProblem.md) must be used. The required parameters are listed in [Table 1](#fp-params). + +!table id=fp-params caption=Necessary input parameters for a FispactProblem +| Parameter | Description | +| - | - | +| +molar_mass_data+ | Path to an HDF5 file containing molar mass data for relevant nuclides. | +| +fispact_schedule_uo+ | The name of the fispact schedule UserObject the user whishes to use in this simulation. | +| +fispact_nuclear_data_uo+ | The name of the fispact nuclear data UserObject the user whishes to use in this simulation. | +| +fispact_input_flux_uo+ | The name of the UserObject defining the input flux. | +| +output_inventory_time+ | If this is a Steady simulation, this parameter determines which FISPACT-II inventory step is used for output. | + + +## Irradiation Schedule id=schedule + +!listing /tutorials/tutorial_1/input.i + block=UserObjects/Schedule + id=schedule-block + caption=The +irradiation schedule+ block + +This block defines the irradiation schedule of your simulation. + +| Parameter | Description | +| - | - | +| +times+ | The times in seconds used for the irradiation schedule. | +| +flux_amplitude+ | Energy integrated projectile flux values in particles per second per cm^2 | + +## Input Flux id=input-flux + +!listing /tutorials/tutorial_1/input.i + block=UserObjects/InputFlux + id=input-flux-block + caption=The +input-flux+ block + +!alert warning +Currently only OpenMC statepoint files are supported as inputs. + +This block defines the input flux spectra for your FISPACT-II simulation. Here we are using mesh tallied flux spectra from an OpenMC simulation. The provided results data file must be compatible with the input mesh, i.e. it must have the correct dimensions. + +## FISPACT material definitions id=materials + +!listing /tutorials/tutorial_1/input.i + block=UserObjects/steel + id=materials-block + caption=A FISPACT material definition + +This block defines the materials in the simulation. Each block within the mesh must have +one and only one+ FispactMaterial assigned to it. Users can define materials by explicitly stating the concentrations of each isotope, or by defining elements, and letting FISPACT automatically decide the abundancies of each isotope. + +## Nuclear Data id=nd + +!listing /tutorials/tutorial_1/input.i + block=UserObjects/endf_nuclear_data + id=nd-block + caption=The user defined +Nuclear Data+ + +Here the user sets the necessary paths to their chosen nuclear data set. The [FispactNuclearData](source/userobjects/FispactNuclearDataPaths.md) UserObject will check whether the paths handed to it are valid, but currently it cannot check the validity of the nuclear data itself. + +FISPACT-II uses multi-group cross sections. The input flux spectra are required to be binned into the same energy groups as the passed in nuclear data. If the user passes in flux spectra binned into different energy groups, a conversion is automatically performed. The FispactProblem block has a parameter **conversion_type**, which can be set to either ENERGY or LETHARGY depending on how the user would like the energy groups to be converted. + +## Executioner id=exec + +!listing /tutorials/tutorial_1/input.i + block=Executioner + id=executioner-block + caption=The +Executioner+ block + +For [Steady](source/executioners/Steady.md) simulations, the executioner block looks just like a standard MOOSE input file. + +!content pagination use_title=True + next=tutorials/tutorial_2/index.md diff --git a/doc/content/tutorials/tutorial_2/index.md b/doc/content/tutorials/tutorial_2/index.md new file mode 100644 index 0000000..4c58618 --- /dev/null +++ b/doc/content/tutorials/tutorial_2/index.md @@ -0,0 +1,57 @@ +# Fizzy tutorial 2: Adding AuxVariables, AuxKernels, and PostProcessors + +In this tutorial, the input file from [Tutorial 1](tutorials/tutorial_1/index.md) will be developed to add AuxVariables, AuxKernels and PostProcessors to help extract data from the calculated nuclear inventories. + +1. [#auxvars] +2. [#postprocessors] +3. [#outputs] + +## Adding AuxVars and AuxKernels id=auxvars + +!listing /tutorials/tutorial_2/input.i + block=AuxVariables + id=aux-block + +Firstly, we add AuxVariables into the input file. Anyone who has used MOOSE before will be familiar with this syntax. We just define a block called `AuxVariables`, which lets MOOSE know we wish to define AuxVariables here. Then we define sub-blocks that represent our actual variables. Variables used in Fizzy AuxKernels must be CONSTANT order MONOMIALS. + + +!listing /tutorials/tutorial_2/input.i + block=AuxKernels + id=auxkern-block + +Secondly, we add AuxKernel blocks, to which we assign AuxVariables. Here we add two slightly different AuxKernels, a [FispactNuclideKernel](source/auxkernels/FispactNuclideKernel.md), and a [FispactElementKernel](source/auxkernels/FispactElementKernel.md). + +The FispactNuclideKernel is used for extracting metrics regarding particular nuclides from the nuclear inventory. In this example, we extract the number of Niobium-93 atoms. Because we are using AuxVariables, this value will be evaluated for each element. + +The FispactElementKernel is used for getting quantities representitive of the entire nuclear inventory, not just individual nuclides. Here we are modelling the total number of atoms in the entire inventory. + +To get a list of possible values of the `metric`, parameter, see the individual documentation pages for both [FispactNuclideKernel](source/auxkernels/FispactNuclideKernel.md), and [FispactElementKernel](source/auxkernels/FispactElementKernel.md). + + +## Adding PostProcessors id=postprocessors + +!listing /tutorials/tutorial_2/input.i + block=Postprocessors + id=post-block + +To calculate scalar quantities over the entire domain, or subsections of the domain, users can use PostProcessors. + +This example includes two postprocessors. Firstly, there is an [ElementPhotonEmission](ElementPhotonEmission.md) PostProcessor. This will return the total gamma emission rate summed over the elements defined by the element_ids parameter. If the user wishes to obtain the total gamma emission rate over a subdomain, they can use the [SubdomainPhotonEmission](SubdomainPhotonEmission.md) PostProcessor. + +A [NuclideMetric](NuclideMetric.md) is included to track domain wide metrics from particular nuclides. In this example, the nuclide_contribution postprocessor outputs the total slab dose rate contributed by Cr51. + +!alert warning +When providing nuclide names to AuxKernels or PostProcessors, make sure they are formatted correctly, using the correct case. + +## Output id=outputs + +!listing /tutorials/tutorial_2/input.i + block=Outputs + id=outputs-block + caption=The +Outputas+ block + +Now that some variables exist on the mesh, we may want to visualise the results.To do this we will need to add an exodus output block, or in this case, use the syntactical shortcut for one. + +!content pagination use_title=True + previous=tutorials/tutorial_1/index.md + next=tutorials/tutorial_3/index.md diff --git a/doc/content/tutorials/tutorial_3/index.md b/doc/content/tutorials/tutorial_3/index.md new file mode 100644 index 0000000..1620df1 --- /dev/null +++ b/doc/content/tutorials/tutorial_3/index.md @@ -0,0 +1,38 @@ +# Fizzy tutorial 3: Transient Simulations + +In this tutorial, the input file from [Tutorial 2](tutorials/tutorial_2/index.md) will be developed into a transient simulation, allowing users to visualise how tracked inventory metrics develop over time. + +1. [#times] +2. [#exec] + +## Getting Times from the FispactSchedule + +!listing /tutorials/tutorial_3/input.i + block=Times + id=times-block + +To run a transient simulation, we need to get our timesteps. FISPACT is different from standard MOOSE, in that the timestepping system is not dynamic. The user sets the times they would like to be solved for in the irradiation schedule, and then FISPACT solves for those times. We need a way of turning the times defined in the schedule into something that can be passed into MOOSE's Transient executioner. For this we use the [FispactScheduleTimes](FispactScheduleTimes.md) object. The only parameter we pass to this is the name of our previously defined FispactSchedule UserObject. + +## Adding PostProcessors id=postprocessors + +!listing /tutorials/tutorial_3/input.i + block=Executioner + id=exec-block + +To perform a transient solve firstly we must set our executioner type to Transient. Then we must use use a [TimeSequenceFromTimes](TimeSequenceFromTimes.md) timestepper, and pass in our previously defined FizzyTimes. + + +## Output id=output + +Now that the simulation is transient, we can visualise the number of Nb93 atoms over time. + +!media media/Nb93.mp4 + id=Nb93 + style=width:50%;margin-left:auto;margin-right:auto; + prefix=Figure + caption=Evolution of Nb93 atom count over time. + loop=true + +!content pagination use_title=True + previous=tutorials/tutorial_2/index.md + next=tutorials/tutorial_4/index.md diff --git a/doc/content/tutorials/tutorial_4/index.md b/doc/content/tutorials/tutorial_4/index.md new file mode 100644 index 0000000..511dbc3 --- /dev/null +++ b/doc/content/tutorials/tutorial_4/index.md @@ -0,0 +1,94 @@ +# Fizzy tutorial 4: Distributed Sampling with Cardinal + +In this tutorial, we will set up a MOOSE multiapp using Cardinal, to perform a photon transport solve. The source of the transport solve will be defined by the photon emission spectra calculated by FISPACT-II. The source will also be distributed over MPI ranks, so that different MPI ranks are responsible for sampling from subsections of the domain. + +## Prerequisites + +1. An MPI compatible MOOSE build +2. A valid Cardinal installation w/ OpenMC & DAGMC +3. A build of FizzyCompiledSource + +The next section will explain how to install the latter. For instructions on how to install Cardinal, please visit Cardinal's own [installation instructions](https://cardinal.cels.anl.gov/start.html). + +## Background + +!media media/FizzyFlowNoneutrons.png + id=fizzyflow + style=width:50%;margin-left:auto;margin-right:auto; + prefix=Figure + caption=Flow of data in a Fizzy & Cardinal multiapp. + +Figure 1 shows the flow of data used when performing distributed sampling with Fizzy. To perform distributed sampling, a custom OpenMC source is used, defined in FizzyCompiledSource. FizzyCompiledSource derived from OpenMC's [CompiledSource](https://docs.openmc.org/en/stable/pythonapi/generated/openmc.CompiledSource.html) functionality, which allows a source term to be defined by a compiled library. We utilise the CompiledSource functionality in order to have granular control over the weighting of sampled particles. This is necessary to perform distributed sampling, as the source terms for different MPI ranks may be of different strengths. + +Once Fizzy has completed its solve, the calculated photon emission spectra need to be communicated directly to the CompiledSource. There is not currently a way to do this using MOOSE's Transfers system. Therefore, we utilise an interprocess memory segment to store the photon emission spectra calculated by Fizzy, which we can then read into the CompiledSource at run time. + +## Installing FizzyCompiledSource + +FizzyCompiledSource is included as a submodule of Fizzy. To build it, first initialise the submodules in the repository. + +```language=bash +git submodule git submodule update --init +``` + +Then change directory into FizzyCompiledSource from the main Fizzy directory, and create a build folder. + +```language=bash +cd Fizzy +cd FizzyCompiledSource +mkdir build && cd build +``` + +Run CMake from the build folder, specifying the directory of your Cardinal build. + +```language=bash +cmake -DCARDINAL_DIR=/path/to/cardinal ../ +make -j +``` + +The built library can be found in the build folder at libCompiledSource.so. + +## OpenMC inputs id=openmc_inputs + +Within the OpenMC Python API, users can set parameters for their OpenMC run. This tutorial won't go over the fundamentals of setting up an OpenMC solve, or installing the OpenMC python module, but for more information, the OpenMC team have extensively documented the Python API, as well as all other parts of [OpenMC](https://docs.openmc.org/en/stable/pythonapi/index.html). + +To make use of distributed sampling, users must set the library they compiled in the previous step as their desired source in OpenMC. Below is an example OpenMC python file that shows users how to set the source, and that can be used a base for their own simulations. + +!listing /tutorials/tutorial_4/openmc_photon.py + +## Fizzy Inputs + +To prepare the Fizzy input for communicating with Cardinal/OpenMC, the com_photon_flux parameter must be set to True. This prompts Fizzy to put the necessary photon emission rate data into an interprocess memory segment. + +!listing /tutorials/tutorial_4/input.i + block=Problem + id=newblocks + +The other requisite addition to the Fizzy input file in the MultiApps block, within which we define a Cardinal multi-app that runs after Fizzy's solve is completed. + +!listing /tutorials/tutorial_4/input.i + block=MultiApps + id=multiapps + +The next additions are not required for the simulation to run, but might still be useful. Here we define a variable transfer from Cardinal to OpenMC. The tallies photon flux on each element will be transferred to the Auxiliary Variable photon_flux in Fizzy. + +!listing /tutorials/tutorial_4/input.i + block=AuxVariables Transfers + id=newblocks + +## Cardinal Inputs + +Listing 5 shows the example Cardinal input file. This input defines the mesh we wish to tally on, quantities we wish to tally, and the OpenMC xml files we wish to use as input. + + +!alert warning +The mesh used in Fizzy and Cardinal must be the same for distributed sampling to work. + + +!listing /tutorials/tutorial_4/photons_input.i + id=cardinal + +!alert warning +To make use of distributed sampling, OpenMC must be aware of the mesh used in the Fizzy calculation. For OpenMC to be aware of the mesh, at least one mesh tally must exist on the mesh. + +!content pagination use_title=True + previous=tutorials/tutorial_3/index.md diff --git a/doc/globals.yml b/doc/globals.yml new file mode 100644 index 0000000..8781ad4 --- /dev/null +++ b/doc/globals.yml @@ -0,0 +1 @@ +Cardinal: inal.cels.anl.gov diff --git a/doc/sqa_reports.yml b/doc/sqa_reports.yml index b81f567..44b7d77 100644 --- a/doc/sqa_reports.yml +++ b/doc/sqa_reports.yml @@ -1,5 +1,5 @@ Applications: - fizzy: + Fizzy: app_types: - FizzyApp content_directory: ${ROOT_DIR}/doc/content diff --git a/geometry/cube.e b/geometry/cube.e new file mode 100644 index 0000000..5f40eb5 Binary files /dev/null and b/geometry/cube.e differ diff --git a/geometry/cube_dag.h5m b/geometry/cube_dag.h5m new file mode 100644 index 0000000..e18deee Binary files /dev/null and b/geometry/cube_dag.h5m differ diff --git a/include/actions/AddInventoryManager.h b/include/actions/AddInventoryManager.h new file mode 100644 index 0000000..bdf6f5c --- /dev/null +++ b/include/actions/AddInventoryManager.h @@ -0,0 +1,12 @@ +#pragma once +#include "Action.h" +#include "InputParameters.h" + +class AddInventoryManager : public Action { +public: + static InputParameters validParams(); + + AddInventoryManager(const InputParameters ¶ms); + + virtual void act() override; +}; diff --git a/include/actions/AddPhotonSpectraVectorPPAllBlocks.h b/include/actions/AddPhotonSpectraVectorPPAllBlocks.h new file mode 100644 index 0000000..e5c1f40 --- /dev/null +++ b/include/actions/AddPhotonSpectraVectorPPAllBlocks.h @@ -0,0 +1,12 @@ +#pragma once +#include "Action.h" +#include "InputParameters.h" + +class AddPhotonSpectraVectorPPAllBlocks : public Action { +public: + static InputParameters validParams(); + + AddPhotonSpectraVectorPPAllBlocks(const InputParameters ¶ms); + + virtual void act() override; +}; diff --git a/include/auxkernels/FispactAuxKernel.h b/include/auxkernels/FispactAuxKernel.h new file mode 100644 index 0000000..25367c7 --- /dev/null +++ b/include/auxkernels/FispactAuxKernel.h @@ -0,0 +1,25 @@ +#pragma once +#include "AuxKernel.h" +#include "FispactInventoryManager.h" +#include "FizzyEnums.h" + +class FispactAuxKernel : public AuxKernel { + +public: + static InputParameters validParams() { + InputParameters params = AuxKernel::validParams(); + return params; + } + + FispactAuxKernel(const InputParameters ¶ms) : AuxKernel(params) { + if (mooseVariableBase()->feType() != libMesh::FEType(CONSTANT, MONOMIAL)) + paramError("variable", "Must be of type CONSTANT MONOMIAL"); + } + +protected: + virtual Real computeValue() override = 0; + + const FispactInventoryManager &getInventoryManager() { + return getUserObject("InvManager"); + } +}; diff --git a/include/auxkernels/FispactElementKernel.h b/include/auxkernels/FispactElementKernel.h new file mode 100644 index 0000000..da04924 --- /dev/null +++ b/include/auxkernels/FispactElementKernel.h @@ -0,0 +1,18 @@ +#include "FispactAuxKernel.h" +#include "FizzyEnums.h" +#include "InputParameters.h" + +class FispactElementKernel : public FispactAuxKernel { + +public: + static InputParameters validParams(); + + FispactElementKernel(const InputParameters ¶ms); + +protected: + virtual Real computeValue() override; + + std::string _nuclide; + + inventory_outputs::InventoryOutputsEnum _metric; +}; diff --git a/include/auxkernels/FispactNuclideKernel.h b/include/auxkernels/FispactNuclideKernel.h new file mode 100644 index 0000000..bdbe8f4 --- /dev/null +++ b/include/auxkernels/FispactNuclideKernel.h @@ -0,0 +1,17 @@ +#include "FispactAuxKernel.h" +#include "InputParameters.h" + +class FispactNuclideKernel : public FispactAuxKernel { + +public: + static InputParameters validParams(); + + FispactNuclideKernel(const InputParameters ¶ms); + +protected: + virtual Real computeValue() override; + + std::string _nuclide; + + nuclide_quantities::NuclideQuantitiesEnum _metric; +}; diff --git a/include/base/FizzyApp.h b/include/base/FizzyApp.h index b9ed312..9138f91 100644 --- a/include/base/FizzyApp.h +++ b/include/base/FizzyApp.h @@ -11,8 +11,7 @@ #include "MooseApp.h" -class FizzyApp : public MooseApp -{ +class FizzyApp : public MooseApp { public: static InputParameters validParams(); @@ -20,5 +19,7 @@ class FizzyApp : public MooseApp virtual ~FizzyApp(); static void registerApps(); - static void registerAll(Factory & f, ActionFactory & af, Syntax & s); + static void registerAll(Factory &f, ActionFactory &af, Syntax &s); + static void associateSyntaxInner(Syntax &syntax, + ActionFactory &action_factory); }; diff --git a/include/base/FizzyEnums.h b/include/base/FizzyEnums.h new file mode 100644 index 0000000..d7d53b6 --- /dev/null +++ b/include/base/FizzyEnums.h @@ -0,0 +1,46 @@ +#pragma once + +#include "MooseEnum.h" +#include "MultiMooseEnum.h" + +MooseEnum getInventoryMetricsEnum(); +MooseEnum getNuclideMetricsEnum(); + +namespace inventory_outputs { + +enum InventoryOutputsEnum { + INVENTORY_IRRAD_TIME, + INVENTORY_COOL_TIME, + INVENTORY_TOTAL_ACTIVITY, + INVENTORY_ALPHA_ACTIVITY, + INVENTORY_BETA_ACTIVITY, + INVENTORY_GAMMA_ACTIVITY, + INVENTORY_TOTAL_HEAT, + INVENTORY_ALPHA_HEAT, + INVENTORY_BETA_HEAT, + INVENTORY_GAMMA_HEAT, + INVENTORY_TOTAL_MASS, + INVENTORY_TOTAL_ATOMS, + INVENTORY_INGESTION, + INVENTORY_INHALATION, + INVENTORY_FLUX_AMP, + INVENTORY_DOSE_RATE +}; +}; + +namespace nuclide_quantities { + +enum NuclideQuantitiesEnum { + ATOMS, + GRAMS, + ACTIVITY, + ALPHA_ACTIVITY, + BETA_ACTIVITY, + GAMMA_ACTIVITY, + TOTAL_HEAT, + ALPHA_HEAT, + BETA_HEAT, + GAMMA_HEAT, + DOSE +}; +}; diff --git a/include/fispact/adapter/FispactContext.h b/include/fispact/adapter/FispactContext.h new file mode 100644 index 0000000..982cc7c --- /dev/null +++ b/include/fispact/adapter/FispactContext.h @@ -0,0 +1,478 @@ +#pragma once +#include "FispactContextBase.h" + +#include +#include +#include +/// Fispact includes +#include "FizzyEnums.h" +#include "fispactcompute.hpp" +#include "fispactelementaldata.hpp" +#include "fispactgroupconvert.hpp" +#include "fispactgroupstructures.hpp" +#include "fispactinputdata.hpp" +#include "fispactmonitor.hpp" +#include "fispactnucleardata.hpp" +#include "fispactoutputdata.hpp" +#include "fispactoutputdataapi.h" +#include "fispactutil.hpp" + +inline int +convertFispactEnum(inventory_outputs::InventoryOutputsEnum output_enum) { + switch (output_enum) { + case (inventory_outputs::INVENTORY_IRRAD_TIME): + return FISPACT_OUTPUT_DATA_INVENTORY_IRRAD_TIME; + case (inventory_outputs::INVENTORY_COOL_TIME): + return FISPACT_OUTPUT_DATA_INVENTORY_COOL_TIME; + case (inventory_outputs::INVENTORY_TOTAL_ACTIVITY): + return FISPACT_OUTPUT_DATA_INVENTORY_TOTAL_ACTIVITY; + case (inventory_outputs::INVENTORY_ALPHA_ACTIVITY): + return FISPACT_OUTPUT_DATA_INVENTORY_ALPHA_ACTIVITY; + case (inventory_outputs::INVENTORY_BETA_ACTIVITY): + return FISPACT_OUTPUT_DATA_INVENTORY_BETA_ACTIVITY; + case (inventory_outputs::INVENTORY_GAMMA_ACTIVITY): + return FISPACT_OUTPUT_DATA_INVENTORY_GAMMA_ACTIVITY; + case (inventory_outputs::INVENTORY_TOTAL_HEAT): + return FISPACT_OUTPUT_DATA_INVENTORY_TOTAL_HEAT; + case (inventory_outputs::INVENTORY_ALPHA_HEAT): + return FISPACT_OUTPUT_DATA_INVENTORY_ALPHA_HEAT; + case (inventory_outputs::INVENTORY_BETA_HEAT): + return FISPACT_OUTPUT_DATA_INVENTORY_BETA_HEAT; + case (inventory_outputs::INVENTORY_GAMMA_HEAT): + return FISPACT_OUTPUT_DATA_INVENTORY_GAMMA_HEAT; + case (inventory_outputs::INVENTORY_TOTAL_MASS): + return FISPACT_OUTPUT_DATA_INVENTORY_TOTAL_MASS; + case (inventory_outputs::INVENTORY_TOTAL_ATOMS): + return FISPACT_OUTPUT_DATA_INVENTORY_TOTAL_ATOMS; + case (inventory_outputs::INVENTORY_FLUX_AMP): + return FISPACT_OUTPUT_DATA_INVENTORY_FLUX_AMP; + default: + return -1; + } +} + +class FispactOutputNuclideData : public FispactOutputNuclideDataBase { +public: + explicit FispactOutputNuclideData(fispact::OutputNuclideData &nuclide_data) + : _nuclide_data(std::move(nuclide_data)) {} + + virtual ~FispactOutputNuclideData() = default; + + virtual std::string getElement() const { return _nuclide_data.getElement(); } + + virtual std::string getState() const { return _nuclide_data.getState(); } + + virtual int getIsotope() const { return _nuclide_data.getIsotope(); } + + virtual int getZAI() const { return _nuclide_data.getZAI(); } + + virtual double getHalfLife() const { return _nuclide_data.getHalfLife(); } + // The number of atoms + virtual double getAtoms() const { return _nuclide_data.getAtoms(); } + // The grams (g) + virtual double getGrams() const { return _nuclide_data.getGrams(); } + // The activity (Bq) + virtual double getActivity() const { return _nuclide_data.getActivity(); } + // The alpha fraction of the activity (Bq) + virtual double getAlphaActivity() const { + return _nuclide_data.getAlphaActivity(); + } + // The beta fraction of the activity (Bq) + virtual double getBetaActivity() const { + return _nuclide_data.getBetaActivity(); + } + // The gamma fraction of the activity (Bq) + virtual double getGammaActivity() const { + return _nuclide_data.getGammaActivity(); + } + // The total heat (kW) + virtual double getTotalHeat() const { return _nuclide_data.getTotalHeat(); } + // The alpha heat (kW) + virtual double getAlphaHeat() const { return _nuclide_data.getAlphaHeat(); } + // The beta heat (kW) + virtual double getBetaHeat() const { return _nuclide_data.getBetaHeat(); } + // The gamma heat (kW) + virtual double getGammaHeat() const { return _nuclide_data.getGammaHeat(); } + // The dose rate (Sv/hr) + virtual double getDoseRate() const { return _nuclide_data.getDoseRate(); } + // The ingestion (Sv) + virtual double getIngestion() const { return _nuclide_data.getIngestion(); } + // The inhalation (Sv) + virtual double getInhalation() const { return _nuclide_data.getInhalation(); } + + // virtual double + // getQuantity(nuclide_quantities::NuclideQuantitiesEnum quantity) const { + // switch (quantity) { + // case (nuclide_quantities::ATOMS): + // return getAtoms(); + // case (nuclide_quantities::GRAMS): + // return getGrams(); + // case (nuclide_quantities::ACTIVITY): + // return getActivity(); + // case (nuclide_quantities::ALPHA_ACTIVITY): + // return getAlphaActivity(); + // case (nuclide_quantities::BETA_ACTIVITY): + // return getBetaActivity(); + // case (nuclide_quantities::GAMMA_ACTIVITY): + // return getGammaActivity(); + // case (nuclide_quantities::TOTAL_HEAT): + // return getTotalHeat(); + // case (nuclide_quantities::ALPHA_HEAT): + // return getAlphaHeat(); + // case (nuclide_quantities::BETA_HEAT): + // return getBetaHeat(); + // case (nuclide_quantities::GAMMA_HEAT): + // return getGammaHeat(); + // case (nuclide_quantities::DOSE): + // return getDoseRate(); + // default: + // throw std::invalid_argument( + // "Invalid quantity requested from FISPACT nuclide inventory"); + // } + // } + +private: + fispact::OutputNuclideData _nuclide_data; +}; + +// IFispactInputData +class IFispactInputData : public IFispactInputDataBase { + +public: + IFispactInputData(fispact::FispactMonitor &monitor) + : IFispactInputDataBase(), _monitor(monitor), _input(_monitor) {} + + virtual void setFlux(const std::vector &flux_energy_groups, + const std::vector &flux) { + _input.setFlux(flux_energy_groups, flux); + } + + virtual void setFluxWallLoading(double wall_loading) { + _input.setFluxWallLoading(wall_loading); + } + + virtual void setFluxName(std::string flux_name) { + _input.setFluxName(flux_name); + } + + virtual void setExcludeXrays(bool enable) { _input.setExcludeXrays(enable); } + + virtual void setDensity(double density) { _input.setDensity(density); } + + virtual void setMassTotal(double total_mass) { + _input.setMassTotal(total_mass); + } + + virtual void setMass(const std::vector &atomicnumbers, + const std::vector &percentages) { + _input.setMass(atomicnumbers, percentages); + } + + virtual void setFuel(const std::vector &zais, + const std::vector &values) { + _input.setFuel(zais, values); + } + + virtual void setSchedule(const std::vector &deltatime, + const std::vector &fluxamp) { + _input.setSchedule(deltatime, fluxamp); + } + + virtual std::pair, std::vector> getSchedule() { + return _input.getSchedule(); + } + + virtual void setAtomsThreshold(double threshold) { + _input.setAtomsThreshold(threshold); + } + + virtual void setSolverTolerance(double rtol, double atol) { + _input.setSolverTolerance(rtol, atol); + } + + fispact::InputData &getInput() { return _input; }; + +private: + fispact::FispactMonitor &_monitor; + fispact::InputData _input; +}; +//~IFispactInputData + +// IFispactOutputData +class IFispactOutputData : public IFispactOutputDataBase { + +public: + IFispactOutputData(fispact::FispactMonitor &monitor) + : IFispactOutputDataBase(), _monitor(monitor), _output(_monitor) {} + + virtual std::vector getGammaSpectrumBins(int inv_index) { + return _output.getGammaSpectrumBins(inv_index); + }; + + virtual std::vector getGammaSpectrumBoundaries(int inv_index) { + return _output.getGammaSpectrumBoundaries(inv_index); + }; + + virtual std::vector> + getInventoryNuclides(int inventory_index) { + + std::vector fispact_nuclide_data = + _output.getInventoryNuclides(inventory_index); + + std::vector> nuclide_data; + nuclide_data.reserve(fispact_nuclide_data.size()); + + for (fispact::OutputNuclideData &nuclide : fispact_nuclide_data) { + nuclide_data.push_back( + std::make_unique(nuclide)); + } + return nuclide_data; + } + + fispact::OutputData &getOutput() { return _output; }; + + virtual std::pair, std::vector> + getSortedInventory(int inv_index, + inventory_outputs::InventoryOutputsEnum key) const { + + return _output.getSortedInventory(inv_index, convertFispactEnum(key)); + } + + virtual double + getInventoryValue(int inv_index, + inventory_outputs::InventoryOutputsEnum key) { + + if (key != inventory_outputs::INVENTORY_DOSE_RATE) { + return _output.getInventoryValue(inv_index, convertFispactEnum(key)); + } + return _output.getInventoryDoseRate(inv_index).getDose(); + } + + virtual int findInventoryIndex(int inv_index, int zai) { + return _output.findInventoryIndex(inv_index, zai); + } + + virtual bool findInventoryExists(int inv_index, int zai) { + return _output.findInventoryExists(inv_index, zai); + } + +private: + fispact::FispactMonitor &_monitor; + fispact::OutputData _output; +}; +//~IFispactOutputData + +class IFispactUtils : public IFispactUtilsBase { + +public: + IFispactUtils(fispact::FispactMonitor &monitor) + : IFispactUtilsBase(), _monitor(monitor) { + + _neutron_energy_groups_map[709] = fispact::groups::G709(); + _neutron_energy_groups_map[1102] = fispact::groups::G1102(); + + _photon_energy_groups_map[22] = {0.0, 1.0e4, 1.0e5, 2.0e5, 4.0e5, 1.0e6, + 1.5e6, 2.0e6, 2.5e6, 3.0e6, 3.5e6, 4.0e6, + 4.5e6, 5.0e6, 5.5e6, 6.0e6, 6.5e6, 7.0e6, + 7.5e6, 8.0e6, 1.0e7, 1.2e7, 1.4e7}; + _photon_energy_groups_map[24] = { + 1.000e-11, 1.000e+4, 2.000e+4, 5.000e+4, 1.000e+5, 2.000e+5, 3.000e+5, + 4.000e+5, 6.000e+5, 8.000e+5, 1.000e+6, 1.220e+6, 1.440e+6, 1.660e+6, + 2.000e+6, 2.500e+6, 3.000e+6, 4.000e+6, 5.000e+6, 6.500e+6, 8.000e+6, + 1.000e+7, 1.200e+7, 1.400e+7, 2.000e+7}; + } + + virtual int GetZai(std::string nuclidename) { + return fispact::util::GetZai(_monitor, nuclidename); + } + + virtual std::string getNuclideName(int zai) { + return fispact::util::GetNuclideName(_monitor, zai); + } + + virtual int GetAtomicNumberFromElementName(std::string elementname) { + return fispact::util::GetAtomicNumberFromElementName(_monitor, elementname); + } + + virtual std::vector getNeutronEnergyBounds(size_t n_bins) { + return _neutron_energy_groups_map[n_bins]; + } + + virtual std::vector getPhotonEnergyBounds(size_t n_bins) { + return _photon_energy_groups_map[n_bins]; + } + + virtual std::vector + GroupConvertByEnergy(const std::vector &inbounds, + const std::vector &invals, + const std::vector &outbounds) { + return fispact::groupconvert::GroupConvertByEnergy(_monitor, inbounds, + invals, outbounds); + } + + virtual std::vector + GroupConvertByLethargy(const std::vector &inbounds, + const std::vector &invals, + const std::vector &outbounds) { + return fispact::groupconvert::GroupConvertByLethargy(_monitor, inbounds, + invals, outbounds); + } + +private: + fispact::FispactMonitor &_monitor; + std::unordered_map> _neutron_energy_groups_map; + std::unordered_map> _photon_energy_groups_map; +}; + +class FispactContext : public FispactContextBase { +public: + FispactContext() : FispactContextBase(), _monitor("log_name"), _nd(_monitor) { + + _i_input_data = std::make_unique(_monitor); + _i_output_data = std::make_unique(_monitor); + _i_utils = std::make_unique(_monitor); + } + + virtual void globalInitialise() { fispact::GlobalInitialise(_monitor); } + + virtual void globalFinalise() { fispact::GlobalFinalise(_monitor); } + + virtual void process() { + auto *real_input = dynamic_cast(_i_input_data.get()); + auto *real_output = + dynamic_cast(_i_output_data.get()); + fispact::InputData &input = real_input->getInput(); + fispact::OutputData &output = real_output->getOutput(); + fispact::Process(input, _nd, output, _monitor, process_callback); + } + + virtual size_t getNuclearDataCrossSections() { + return _nd.getReactionXS(0, 0).size(); + } + virtual void setNuclearData( + std::unordered_map nuclear_data_paths) { + + fispact::io::NuclearDataReader nd_reader(_monitor); + + for (auto &[data, path] : nuclear_data_paths) { + if (data == "ND_IND_NUC_KEY") { + nd_reader.setPath(FISPACT_ND_IND_NUC_KEY, path); + continue; + } + + if (data == "ND_HAZARDS_KEY") { + nd_reader.setPath(FISPACT_ND_HAZARDS_KEY, path); + continue; + } + + if (data == "ND_ABSORP_KEY") { + + nd_reader.setPath(FISPACT_ND_ABSORP_KEY, path); + continue; + } + + if (data == "ND_CLEAR_KEY") { + + nd_reader.setPath(FISPACT_ND_CLEAR_KEY, path); + continue; + } + + if (data == "ND_A2DATA_KEY") { + nd_reader.setPath(FISPACT_ND_A2DATA_KEY, path); + continue; + } + + if (data == "ND_ENBINS_KEY") { + nd_reader.setPath(FISPACT_ND_ENBINS_KEY, path); + continue; + } + + if (data == "ND_DECAY_KEY") { + nd_reader.setPath(FISPACT_ND_DECAY_KEY, path); + continue; + } + + if (data == "ND_DK_ENDF_KEY") { + nd_reader.setPath(FISPACT_ND_DK_ENDF_KEY, path); + continue; + } + + if (data == "ND_PROB_TAB_KEY") { + nd_reader.setPath(FISPACT_ND_PROB_TAB_KEY, path); + continue; + } + + if (data == "ND_ASSCFY_KEY") { + nd_reader.setPath(FISPACT_ND_ASSCFY_KEY, path); + continue; + } + + if (data == "ND_FISSYLD_KEY") { + nd_reader.setPath(FISPACT_ND_FISSYLD_KEY, path); + continue; + } + + if (data == "ND_FY_ENDF_KEY") { + nd_reader.setPath(FISPACT_ND_FY_ENDF_KEY, path); + continue; + } + + if (data == "ND_SF_ENDF_KEY") { + nd_reader.setPath(FISPACT_ND_SF_ENDF_KEY, path); + continue; + } + + if (data == "ND_SP_ENDF_KEY") { + nd_reader.setPath(FISPACT_ND_SP_ENDF_KEY, path); + continue; + } + + if (data == "ND_XS_EXTRA_KEY") { + nd_reader.setPath(FISPACT_ND_XS_EXTRA_KEY, path); + continue; + } + + if (data == "ND_CROSSEC_KEY") { + nd_reader.setPath(FISPACT_ND_CROSSEC_KEY, path); + continue; + } + + if (data == "ND_CROSSUNC_KEY") { + nd_reader.setPath(FISPACT_ND_CROSSUNC_KEY, path); + continue; + } + + if (data == "ND_XS_ENDF_KEY") { + nd_reader.setPath(FISPACT_ND_XS_ENDF_KEY, path); + continue; + } + + if (data == "ND_XS_ENDFB_KEY") { + nd_reader.setUseXSBinary(true); + nd_reader.setPath(FISPACT_ND_XS_ENDFB_KEY, path); + continue; + } + } + // Load the nuclear data + nd_reader.load(_nd, load_callback); + } + + static void load_callback(std::string key, std::string path, int i, int t) { + std::cout << "\33[2K\r" << key << ": " << path << " [" << i << "/" << t + << "]" << std::flush; + } + + /** + * + * + * + */ + static void process_callback(std::string process_name, int i, int t) { + std::cout << "\33[2K\r [" << i << "/" << t << "] " << process_name + << std::flush; + } + +private: + fispact::FispactMonitor _monitor; + fispact::NuclearData _nd; +}; diff --git a/include/fispact/factory/FispactFactory.h b/include/fispact/factory/FispactFactory.h new file mode 100644 index 0000000..03171d6 --- /dev/null +++ b/include/fispact/factory/FispactFactory.h @@ -0,0 +1,5 @@ +#pragma once +#include "FispactContextBase.h" +#include + +std::unique_ptr createFispactContext(); diff --git a/include/fispact/interface/FispactContextBase.h b/include/fispact/interface/FispactContextBase.h new file mode 100644 index 0000000..9b61865 --- /dev/null +++ b/include/fispact/interface/FispactContextBase.h @@ -0,0 +1,178 @@ +#pragma once +#include "FizzyEnums.h" +#include +#include +#include + +class FispactOutputNuclideDataBase { +public: + virtual ~FispactOutputNuclideDataBase() = default; + + virtual std::string getElement() const = 0; + + virtual std::string getState() const = 0; + + virtual int getIsotope() const = 0; + + virtual int getZAI() const = 0; + + // The half life (s) + virtual double getHalfLife() const = 0; + // The number of atoms + virtual double getAtoms() const = 0; + // The grams (g) + virtual double getGrams() const = 0; + // The activity (Bq) + virtual double getActivity() const = 0; + // The alpha fraction of the activity (Bq) + virtual double getAlphaActivity() const = 0; + // The beta fraction of the activity (Bq) + virtual double getBetaActivity() const = 0; + // The gamma fraction of the activity (Bq) + virtual double getGammaActivity() const = 0; + // The total heat (kW) + virtual double getTotalHeat() const = 0; + // The alpha heat (kW) + virtual double getAlphaHeat() const = 0; + // The beta heat (kW) + virtual double getBetaHeat() const = 0; + // The gamma heat (kW) + virtual double getGammaHeat() const = 0; + // The dose rate (Sv/hr) + virtual double getDoseRate() const = 0; + // The ingestion (Sv) + virtual double getIngestion() const = 0; + // The inhalation (Sv) + virtual double getInhalation() const = 0; + + virtual double + getQuantity(nuclide_quantities::NuclideQuantitiesEnum quantity) const { + + switch (quantity) { + case (nuclide_quantities::ATOMS): + return getAtoms(); + case (nuclide_quantities::GRAMS): + return getGrams(); + case (nuclide_quantities::ACTIVITY): + return getActivity(); + case (nuclide_quantities::ALPHA_ACTIVITY): + return getAlphaActivity(); + case (nuclide_quantities::BETA_ACTIVITY): + return getBetaActivity(); + case (nuclide_quantities::GAMMA_ACTIVITY): + return getGammaActivity(); + case (nuclide_quantities::TOTAL_HEAT): + return getTotalHeat(); + case (nuclide_quantities::ALPHA_HEAT): + return getAlphaHeat(); + case (nuclide_quantities::BETA_HEAT): + return getBetaHeat(); + case (nuclide_quantities::GAMMA_HEAT): + return getGammaHeat(); + case (nuclide_quantities::DOSE): + return getDoseRate(); + default: + throw std::invalid_argument( + "Invalid quantity requested from FISPACT nuclide inventory"); + } + } + +private: +}; + +class IFispactInputDataBase { +public: + virtual void setFlux(const std::vector &flux_energy_groups, + const std::vector &flux) = 0; + + virtual void setFluxWallLoading(double wall_loading) = 0; + + virtual void setExcludeXrays(bool enable) = 0; + + virtual void setFluxName(std::string flux_name) = 0; + + virtual void setDensity(double density) = 0; + + virtual void setMassTotal(double total_mass) = 0; + + virtual void setMass(const std::vector &atomicnumbers, + const std::vector &percentages) = 0; + + virtual void setFuel(const std::vector &zais, + const std::vector &values) = 0; + + virtual void setSchedule(const std::vector &deltatime, + const std::vector &fluxamp) = 0; + + virtual std::pair, std::vector> getSchedule() = 0; + + virtual void setAtomsThreshold(double threshold) = 0; + + virtual void setSolverTolerance(double rtol, double atol) = 0; +}; + +class IFispactOutputDataBase { +public: + virtual std::vector getGammaSpectrumBins(int inv_index) = 0; + + virtual std::vector getGammaSpectrumBoundaries(int inv_index) = 0; + + virtual std::vector> + getInventoryNuclides(int inventory_index) = 0; + + virtual std::pair, std::vector> + getSortedInventory(int inv_index, + inventory_outputs::InventoryOutputsEnum key) const = 0; + + virtual double + getInventoryValue(int inv_index, + inventory_outputs::InventoryOutputsEnum key) = 0; + + virtual int findInventoryIndex(int inv_index, int zai) = 0; + + virtual bool findInventoryExists(int inv_index, int zai) = 0; +}; + +class IFispactUtilsBase { +public: + virtual int GetZai(std::string nuclidename) = 0; + + virtual std::string getNuclideName(int zai) = 0; + + virtual int GetAtomicNumberFromElementName(std::string elementname) = 0; + + virtual std::vector getNeutronEnergyBounds(size_t n_groups) = 0; + + virtual std::vector getPhotonEnergyBounds(size_t n_groups) = 0; + + virtual std::vector + GroupConvertByEnergy(const std::vector &inbounds, + const std::vector &invals, + const std::vector &outbounds) = 0; + + virtual std::vector + GroupConvertByLethargy(const std::vector &inbounds, + const std::vector &invals, + const std::vector &outbounds) = 0; +}; + +class FispactContextBase { +public: + virtual void globalInitialise() = 0; + virtual void globalFinalise() = 0; + virtual void process() = 0; + // virtual void hasFatal() = 0; + + virtual void setNuclearData( + std::unordered_map nuclear_data_paths) = 0; + + virtual size_t getNuclearDataCrossSections() = 0; + virtual IFispactInputDataBase &getInput() { return *_i_input_data; } + virtual IFispactOutputDataBase &getOutput() { return *_i_output_data; } + virtual IFispactUtilsBase &getUtils() { return *_i_utils; } + +protected: + std::unique_ptr _i_input_data; + std::unique_ptr _i_output_data; + std::unique_ptr _i_utils; +}; diff --git a/include/postprocessors/ElementPhotonEmission.h b/include/postprocessors/ElementPhotonEmission.h new file mode 100644 index 0000000..e64ed3d --- /dev/null +++ b/include/postprocessors/ElementPhotonEmission.h @@ -0,0 +1,20 @@ +#pragma once +#include "FispactPostprocessor.h" + +class ElementPhotonEmission : public FispactPostprocessor { + +public: + static InputParameters validParams(); + + ElementPhotonEmission(const InputParameters ¶ms); + + virtual void initialize(); + virtual void execute(); + virtual void finalize(); + + virtual PostprocessorValue getValue() const; + + std::vector _element_ids; + + Real _sum; +}; diff --git a/include/postprocessors/FispactElementPostprocessor.h b/include/postprocessors/FispactElementPostprocessor.h new file mode 100644 index 0000000..bf26144 --- /dev/null +++ b/include/postprocessors/FispactElementPostprocessor.h @@ -0,0 +1,30 @@ +#pragma once +#include "ElementPostprocessor.h" +#include "InputParameters.h" +#include "UserObject.h" + +// Forward dec +class FispactProblem; + +class FispactElementPostprocessor : public ElementPostprocessor { + +public: + static InputParameters validParams() { + InputParameters params = ElementPostprocessor::validParams(); + return params; + }; + + FispactElementPostprocessor(const InputParameters ¶ms); + + virtual void initialize() = 0; + virtual void execute() = 0; + virtual void finalize() = 0; + virtual void threadJoin(const UserObject &y) = 0; + + virtual PostprocessorValue getValue() const = 0; + + FispactProblem &getFispactProblem(); + +protected: + FispactProblem &_fispact_problem; +}; diff --git a/include/postprocessors/FispactInventoryMetric.h b/include/postprocessors/FispactInventoryMetric.h new file mode 100644 index 0000000..32d7c91 --- /dev/null +++ b/include/postprocessors/FispactInventoryMetric.h @@ -0,0 +1,31 @@ +#pragma once +#include "FispactElementPostprocessor.h" +#include "FizzyEnums.h" +#include "UserObject.h" + +class FispactInventoryMetric : public FispactElementPostprocessor { + +public: + static InputParameters validParams(); + + FispactInventoryMetric(const InputParameters ¶ms); + + virtual void initialize(); + virtual void execute(); + virtual void finalize(); + + virtual void threadJoin(const UserObject &y); + + virtual PostprocessorValue getValue() const; + + Real _sum; + + inventory_outputs::InventoryOutputsEnum _metric; + + /** + * Because sieverts is a specific quantity, if we want the total dose rate of + * a set of elements spanning multiple materials, we need to track the + * total_mass + */ + double _total_mass; +}; diff --git a/include/postprocessors/FispactNuclideMetric.h b/include/postprocessors/FispactNuclideMetric.h new file mode 100644 index 0000000..ac0d4e7 --- /dev/null +++ b/include/postprocessors/FispactNuclideMetric.h @@ -0,0 +1,33 @@ +#pragma once +#include "FispactElementPostprocessor.h" +#include "FizzyEnums.h" +#include "UserObject.h" + +class FispactNuclideMetric : public FispactElementPostprocessor { + +public: + static InputParameters validParams(); + + FispactNuclideMetric(const InputParameters ¶ms); + + virtual void initialize(); + virtual void execute(); + virtual void finalize(); + + virtual void threadJoin(const UserObject &y); + + virtual PostprocessorValue getValue() const; + + Real _sum; + + std::vector _nuclides; + + nuclide_quantities::NuclideQuantitiesEnum _metric; + + /** + * Because sieverts is a specific quantity, if we want the total dose rate of + * a set of elements spanning multiple materials, we need to track the + * total_mass + */ + double _total_mass; +}; diff --git a/include/postprocessors/FispactPostprocessor.h b/include/postprocessors/FispactPostprocessor.h new file mode 100644 index 0000000..66b9bea --- /dev/null +++ b/include/postprocessors/FispactPostprocessor.h @@ -0,0 +1,28 @@ +#pragma once +#include "GeneralPostprocessor.h" +#include "InputParameters.h" + +// Forward dec +class FispactProblem; + +class FispactPostprocessor : public GeneralPostprocessor { + +public: + static InputParameters validParams() { + InputParameters params = GeneralPostprocessor::validParams(); + return params; + }; + + FispactPostprocessor(const InputParameters ¶ms); + + virtual void initialize() = 0; + virtual void execute() = 0; + virtual void finalize() = 0; + + virtual PostprocessorValue getValue() const = 0; + + FispactProblem &getFispactProblem(); + +protected: + FispactProblem &_fispact_problem; +}; diff --git a/include/postprocessors/SubdomainPhotonEmission.h b/include/postprocessors/SubdomainPhotonEmission.h new file mode 100644 index 0000000..1e11aa7 --- /dev/null +++ b/include/postprocessors/SubdomainPhotonEmission.h @@ -0,0 +1,20 @@ +#pragma once +#include "BlockRestrictable.h" +#include "FispactPostprocessor.h" + +class SubdomainPhotonEmission : public FispactPostprocessor, + public BlockRestrictable { + +public: + static InputParameters validParams(); + + SubdomainPhotonEmission(const InputParameters ¶ms); + + virtual void initialize(); + virtual void execute(); + virtual void finalize(); + + virtual PostprocessorValue getValue() const; + + Real _sum; +}; diff --git a/include/problems/FispactProblem.h b/include/problems/FispactProblem.h index 124da28..ca3b75a 100644 --- a/include/problems/FispactProblem.h +++ b/include/problems/FispactProblem.h @@ -1,74 +1,163 @@ #pragma once + #include "ExternalProblem.h" -#include "fispactcompute.hpp" -#include "fispactelementaldata.hpp" -#include "fispactgroupconvert.hpp" -#include "fispactgroupstructures.hpp" -#include "fispactinputdata.hpp" -#include "fispactnucleardata.hpp" -#include "fispactoutputdata.hpp" -#include "fispactutil.hpp" -#include +#include "FispactContextBase.h" +#include "FispactFactory.h" +#include "FispactFluxInput.h" +#include "FispactMaterial.h" +#include "FispactNuclearDataPaths.h" +#include "FispactSchedule.h" +#include "PhotonSpectra.h" + +// Include for interprocess communication data structure +#include "HDF5Utils.h" +#include "PhotonSharingData.h" +#include #include +#include +#include -// Use fp as short for fispact -namespace fp = fispact; +#ifdef LIBMESH_HAVE_BOOST +namespace bi = boost::interprocess; +#endif class FispactProblem : public ExternalProblem { - /// Struct to store Material definitions - struct MaterialDefinition { - std::string _mat_name; - std::vector> _mat_atomic_composition; - double _mat_density; - }; public: - // Constructor for FispactProblem FispactProblem(const InputParameters ¶ms); + ~FispactProblem(); + static InputParameters validParams(); - // virtual void initialSetup() override; + virtual void initialSetup() override; + virtual void externalSolve() override; virtual void syncSolutions(ExternalProblem::Direction direction) override; virtual bool converged(unsigned int) override { return true; } -private: - static void load_callback(std::string key, std::string path, int i, int t) { - std::cout << "\33[2K\r" << key << ": " << path << " [" << i << "/" << t - << "]" << std::flush; + void timestepSetup() override; + + /** + * + * Calculates the total strength of one elements photon source term + * @param[in] element a ptr to the libmesh element whose strength we are + * calculating + * @param[in] element_flux the vector representing the energy binned photon + * flux for the relevent mesh element + * @return the total strength of the photon source term for this element + * + */ + double calculateElementStrength(const std::vector element_flux); + /** + * + */ + bool isFlux(const std::vector &flux) const; + + /// + const FispactMaterial &getElementMaterial(const dof_id_type &elem_id); + + void setPhotonBins(const std::vector &photon_bins); + + /** + * Converts FISPACT gamma spectra outputs from MeV s^-1 to cm^-3 s^-1 + * @param[in] photon_energy_spectra_ev Photon energy spectra as output by + * FISPACT + * @param[out] photon_energy_spectra_per_cc_s Photon energy spectra in + * photons/cc-s + */ + void + convertGammaEvToCount(const std::vector &photon_energy_spectra_ev, + std::vector &photon_energy_spectra_per_cc_s); + + std::unordered_map &getLocalElemIndexMap() { + return _local_elem_index; } - static void process_callback(std::string process_name, int i, int t) { - std::cout << "\33[2K\r [" << i << "/" << t << "] " << process_name - << std::flush; + PhotonSpectra *getPhotonSpectra() const { + return _photon_energy_spectra.get(); } - void setNuclearData(std::string nd_base_path); + const FispactSchedule &getSchedule() const { + if (hasUserObject(_fp_schedule_uo_name)) { + return getUserObject(_fp_schedule_uo_name); + } + mooseError("FispactSchedule UserObject has not been instantiated."); + } - /// Read a neutron flux spectra from a hdf5 file - std::vector readNeutronFluxFromHDF5(const std::string &filename); + size_t getFispactInventoryIndexFromTime(); - /// Write output photon flux to HDF5 - void writePhotonFluxToHDF5(const std::string &filename, - fp::OutputData &fispact_output); + const double getOutputInventoryTime() const { return _output_inventory_time; } - void writePhotonFluxBins(hid_t file_id, fp::OutputData &fispact_output); + const std::unordered_map &getMolarMassMap() { + return _molar_mass_map; + } - void setFispactInputData(fp::FispactMonitor &monitor, fp::InputData &input, - MaterialDefinition &material, - std::vector &neutron_flux, - const std::vector &bins, double volume); + const double avogadroNumber() const; - /// Generate a log file name for the fispact logs - std::string fispactLogName(); + const FispactContextBase *getFpContext() const { return _fp_ctxt.get(); } + + /** + * Load in molar mass data from HDF5 file set using input params + */ + void loadMolarMasses(); - // Initialise FISPACT monitor object - void initFispactMonitor(std::string); + void callFispactFactory(); - void readNeutronFluxFromHDF5(std::string filename, std::string tally_dir); + /** + * Set the nuclear data for FISPACT + * @param[in] nd_base_path The directory containing the various nuclear data + * resources required for fispact + * + */ + void setNuclearData(); + /** + * Method to write calculated photon flux to a HDF5 file, primarily for + * debugging purposes. + * @param[in] filename the name of the resulting HDF5 file containing the + * photon flux + * + */ + void writePhotonFlux(const std::string &filename, + const std::vector &inventory_times); + + /** + * Method used within @ref writePhotonFlux to write the photon energy bins + * used by FISPACT to the same HDF5 file + * @param[in] file_id the HDF5 file identifier for the file we are writing to + * @param[in] photon_bins a vector of doubles containing the photon energy + * bins used + * @param[in] parallel indicates whether or not to use the parallel HDF5 + * driver + */ + void writePhotonFluxBins(const hid_t &file_id, const bool parallel); + + /** + * + * Method used to set input parameters for a FISPACT activation calculation + * @param[in] monitor the FISPACT monitor object required by all FISPACT + * methods + * @param[in] material the material definition for the FISPACT calculation + * @param[in] neutron_flux the energy binned neutron flux + * @param[in] bins the energy bin boundaries for neutron flux + * @param[in] volume the volume in m^3 for the mesh element this FISPACT + * calculation corresponds to + * @param[out] input the now correctly setup FISPACT input object + */ + void setFispactInputData(const FispactMaterial &material, + const std::vector &neutron_flux, + const double &volume, + IFispactInputDataBase &input) const; + + /// Generate a log file name for the fispact logs + std::string fispactLogName(); + + /** + * + * + */ void read_material_xml_data(); /** @@ -77,74 +166,208 @@ class FispactProblem : public ExternalProblem { * start as opposed to running into a subdomain lacking a material half way * through the solve. */ - void checkMaterialsExist(); + void checkMaterialsExist() const; /** * Retrieve Fispact radiation schedule from FispactSchedule UserObject */ - void setFispactSchedule(fp::InputData &input); + void setFispactSchedule(IFispactInputDataBase &input, const double &volume, + const double &neutron_flux_sum) const; - void convertGammaEvToCount(fp::InputData &input, - const std::vector &photon_spectra, - const std::vector &photon_flux_bins, - std::vector &photons_per_cc_per_s); + /** + * + */ + void insertElementStrength(const int inv_index, const libMesh::Elem *element, + const std::vector element_flux); - void printInventoryByHeat(fp::OutputData &output, int timestep_index, - std::ostream &stream = std::cout); + /** + * + */ + void calculateLocalDomainStrength(); - void printInventoryByMass(fp::OutputData &output, int timestep_index, - std::ostream &stream); + /** + * + */ + void getTotalDomainStrength(); - void printInvData(fp::OutputData &output, std::ostream &stream); + /** + * + */ + void resolveFispactUserObjects(); - double extractHalflifeFromNuc(fp::NuclearData &nuclear_data, int zai); + /** + * Check if neutron group structure is consistent between the passed in flux + * data and the read in nuclear data + */ + void checkForEnergyGroupConsistency(); - bool isFlux(int elem_id); + /** + * + */ + std::vector &getNeutronBins() { + if (_flux_energy_groups.empty()) { + mooseError("_flux_energy_groups not set, so could not be gotten"); + } + return _flux_energy_groups; + } - /// FISPACT monitor - fp::FispactMonitor _fp_monitor; + /** + * Return a vector populated with the number of atoms of each isotope in a + * given material + */ + std::vector getMaterialAtoms(const FispactMaterial &material); - /// FISPACT nuclear data - fp::NuclearData _fp_nuclear_data; + /** + * Method to calculate the number of atoms in a given mass of substance + */ + double getNumAtoms(const double &mass, const double &molar_mass, + const double &avogadro) const; + + /** + * + */ + std::vector &getPhotonBins() { + if (_photon_bins.empty()) { + mooseError("_photon_bins not set, so could not be gotten"); + } + return _photon_bins; + } + + size_t photonEnergySpectraIdx(size_t inv_idx, dof_id_type elem_id) { + return ((inv_idx * (_mesh.nActiveLocalElem() * _n_photon_bins)) + + (_local_elem_index[elem_id] * _n_photon_bins)); + } + + /** + * + */ + int calculateMemorySize(); + + void convertFluxEnergyGroups(std::vector &flux, + const std::vector &input_energy_groups); + /** + * Method to generate name of the interprocess memory segment generated by + * this MPI rank + * @param[out] ipc_name Reference to the string we want to populate + */ + const std::string generateInterprocessName(); + +protected: + /// -- Interprocess bits -- +#ifdef LIBMESH_HAVE_BOOST + bi::managed_shared_memory _segment; + + PhotonSharingData *_photon_sharing_instance; +#endif + + std::unique_ptr _fp_ctxt; /// FISPACT neutron flux std::unordered_map> _neutron_fluxes; - // FISPACT Photon fluxes - std::unordered_map> _photon_fluxes; + /// FISPACT Photon fluxes + /// Indexed by time major, element id minor + // std::vector _photon_energy_spectra; - /// hdf5 filename for neutron flux - std::string _neutron_flux_filename; + std::unique_ptr _photon_energy_spectra; - /// path to neutron flux array in hdf5 file - std::string _neutron_flux_hdf5_path; + /// Vector to store all local element strengths over all inventory times + /// Indexed by time major, element id minor + std::vector _element_strengths; /// hdf5 filename for photon flux std::string _photon_flux_filename; - /// bool _materials_from_xml; - /// Boolean to determine whether a rank is still running FISPACT calculations - bool _calculating = true; - /// Filename of xml file to read materials from std::string _materials_xml_file; - /// Mappings from material name to material definitions - std::unordered_map _mat_definitions; - - MaterialDefinition &getElementMaterial(int &elem_id); + /// + // const size_t _input_neutron_bin_structure; - std::string _neutron_bin_type; + /// + std::vector _flux_energy_groups; - std::vector _neutron_bins; + /// + // std::vector _input_neutron_bins; + /// std::vector _photon_bins; - int _num_neutron_bins; + /// + // uint64_t _n_input_neutron_bins; + + /// + uint64_t _n_photon_bins; + + /// Number of FISPACT inventories + const size_t *_n_inventories; + + /// Number of FISPACT solution inventories(ignoring initial conditions) + const size_t *_n_solution_inventories; + + double _output_inventory_time; + + /// + UserObjectName _fp_schedule_uo_name; + + /// + UserObjectName _fp_flux_uo_name = NULL; + + /// Fispact nuclear data path + UserObjectName _fp_nuclear_data_uo_name; + + FispactSchedule *_fp_schedule_uo = nullptr; + + FispactNuclearDataPaths *_fp_nuclear_data_uo; + + FispactFluxInput *_fp_flux_input_uo = nullptr; + + std::vector _fp_fispact_materials; + + /// Vector to store local domain strength over all inventory times + std::vector _local_domain_strength; + + /// Vector to store local domain strength over all inventory times + std::vector _total_domain_strength; + + /// + bool _write_photon_flux; + + /// + bool _comm_photon_flux; + + /// + bool _solved; + + /// + + /// + bool _convert_energy_groups = false; + + bool _uniform; + + /// name given to the interprocess memory segment generated by this rank + const std::string _interprocess_segment_name; + + const std::string &_molar_mass_data_filename; + + /// Map from element ZAI to molar mass (g/mol) + std::unordered_map _molar_mass_map; + + /// Map from global element id to "local element id" + std::unordered_map _local_elem_index; - std::string _schedule_uo_name; + /// Absolute tolerance for FISPACT solver + double _atol; + /// Relative tolerance for FISPACT solver + double _rtol; - void setNeutronBins(); + // std::unordered_map> _neutron_group_map = { + // {100, fp::groups::G100()}, + // {709, fp::groups::G709()}, + // {1102, fp::groups::G1102()}}; + // + bool _exclude_xrays; }; diff --git a/include/times/FispactScheduleTimes.h b/include/times/FispactScheduleTimes.h new file mode 100644 index 0000000..e48c3eb --- /dev/null +++ b/include/times/FispactScheduleTimes.h @@ -0,0 +1,21 @@ +#pragma once +// Moose includes +#include "FispactSchedule.h" +#include "Times.h" + +/** + * Simple times from an input parameter + */ +class FispactScheduleTimes : public Times { +public: + static InputParameters validParams(); + FispactScheduleTimes(const InputParameters ¶meters); + virtual ~FispactScheduleTimes() = default; + +protected: + virtual void initialize() override {} + + const FispactSchedule &_schedule; + + std::vector _fispact_times; +}; diff --git a/include/userobjects/FISPACTMaterial.h b/include/userobjects/FISPACTMaterial.h deleted file mode 100644 index e774ba9..0000000 --- a/include/userobjects/FISPACTMaterial.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "GeneralUserObject.h" - -class FISPACTMaterial : public GeneralUserObject -{ -public: - static InputParameters validParams(); - - FISPACTMaterial(const InputParameters & params); - - virtual void initialize() {} - virtual void finalize() {} - virtual void execute() {} - -protected: - - // Nuclide names - std::vector _nuclides; - - // List of nuclide proportions corresponding to each nuclide in the nuclide list - std::vector _nuclide_proportion; - - // Density of the fispact material - double _density; -}; diff --git a/include/userobjects/FispactFluxInput.h b/include/userobjects/FispactFluxInput.h new file mode 100644 index 0000000..3da9f1f --- /dev/null +++ b/include/userobjects/FispactFluxInput.h @@ -0,0 +1,44 @@ +#pragma once + +#include "GeneralUserObject.h" +#include "InputParameters.h" +#include "UserObject.h" +#include "libmesh/id_types.h" + +class FispactFluxInput : public GeneralUserObject { + +public: + static InputParameters validParams() { + + InputParameters params = GeneralUserObject::validParams(); + + params.addRequiredParam("wall_loading", ""); + + return params; + } + + FispactFluxInput(const InputParameters ¶meters) + : GeneralUserObject(parameters), + _wall_loading(getParam("wall_loading")) {} + + virtual void initialize() {} + virtual void finalize() {} + virtual void execute() {} + + virtual std::vector getElemFlux(dof_id_type elem_id) = 0; + + virtual const std::vector &getFluxEnergyGroups() { + return _flux_energy_groups; + }; + + const size_t &getNumEnergyGroups() { return _n_bins; }; + + const double &getWallLoading() { return _wall_loading; }; + +protected: + std::vector _flux_energy_groups; + + size_t _n_bins; + + double _wall_loading; +}; diff --git a/include/userobjects/FispactInventoryManager.h b/include/userobjects/FispactInventoryManager.h new file mode 100644 index 0000000..53c0351 --- /dev/null +++ b/include/userobjects/FispactInventoryManager.h @@ -0,0 +1,228 @@ +#pragma once + +#include "FispactContextBase.h" +#include "FispactUserObject.h" +#include "FizzyEnums.h" +#include "InputParameters.h" +#include "UserObject.h" +#include "libmesh/id_types.h" +#include +#include + +class FispactInventoryManager : public FispactUserObject { +public: + /// Forward declaration + class ElementInventory; + + static InputParameters validParams(); + + FispactInventoryManager(const InputParameters ¶meters); + + virtual void initialize() {} + virtual void finalize() {} + virtual void execute() {} + + void registerNuclideMetricRequest( + const std::string &nuclide, + const nuclide_quantities::NuclideQuantitiesEnum metric, + const std::set &blocks); + + void registerElementMetricRequest( + const inventory_outputs::InventoryOutputsEnum metric, + const std::set &blocks); + + void extractInventoryData(FispactContextBase &fp_context, size_t elem_id); + + double + getNuclideMetric(libMesh::dof_id_type elem_id, std::string &nuclide, + int inv_index, + nuclide_quantities::NuclideQuantitiesEnum metric) const; + + double getElementMetric(libMesh::dof_id_type elem_id, int inv_index, + inventory_outputs::InventoryOutputsEnum metric) const; + + void initialiseNuclearInventory(); + + ElementInventory &getElementInventory(size_t elem_id); + + const ElementInventory &getElementInventory(size_t elem_id) const; + +protected: + /// Mapping from nuclide names to a vector containing the quantities to be + /// stored for that nuclide + + std::unordered_map _nuclide_ids; + + std::unordered_map _nuclide_names; + + std::vector _element_inventories; + + size_t _n_fispact_inventories; + + size_t _max_nuclide_id = 0; + +public: + class NuclideInventory { + public: + NuclideInventory( + const std::string &nuclide_name, size_t n_inventories, + const std::vector + &quantities) + : _nuclide_name(nuclide_name), _n_inventories(n_inventories) { + for (auto &quantity : quantities) { + _metric_data[quantity] = std::vector(n_inventories, 0.0); + } + + _n_metrics = _metric_data.size(); + }; + + void addQuantity(nuclide_quantities::NuclideQuantitiesEnum quantity) { + // _quantities.push_back(quantity); + // _data.resize(_quantities.size() * _n_inventories); + _metric_data[quantity] = std::vector(_n_inventories, 0.0); + } + + std::vector getQuantities() { + std::vector quantities; + + for (auto &[quantity, value] : _metric_data) { + quantities.push_back(quantity); + } + return quantities; + } + + double &getQuantity(nuclide_quantities::NuclideQuantitiesEnum quantity, + size_t inv_index) { + + return _metric_data.at(quantity)[inv_index]; + + // return _data[(_quantities.size() * inv_index) + + // findQuantity(quantity)]; + } + + const double & + getQuantity(nuclide_quantities::NuclideQuantitiesEnum quantity, + size_t inv_index) const { + + return _metric_data.at(quantity)[inv_index]; + // return _data[(_quantities.size() * inv_index) + + // findQuantity(quantity)]; + } + + void setQuantity(nuclide_quantities::NuclideQuantitiesEnum quantity, + size_t inv_index, const double &value) { + + _metric_data.at(quantity)[inv_index] = value; + // _data[(_quantities.size() * inv_index) + findQuantity(quantity)] = + // value; + } + + size_t + findQuantity(nuclide_quantities::NuclideQuantitiesEnum quantity) const { + for (int i = 0; i < _quantities.size(); i++) { + if (quantity == _quantities[i]) { + return i; + } + } + throw std::runtime_error( + "Searching for nuclide quantity that is not stored."); + } + + // double &operator()(size_t inv_index, + // nuclide_quantities::NuclideQuantitiesEnum quantity) { + // size_t quantity_id = findQuantity(quantity); + // return _data[(inv_index * _n_metrics) + quantity_id]; + // } + + protected: + std::string _nuclide_name; + size_t _n_inventories; + size_t _n_metrics; + + std::vector _quantities; + std::vector _data; + + std::unordered_map> + _metric_data; + }; + + /// + class ElementInventory { + public: + ElementInventory(size_t elem_id) : _elem_id(elem_id) {} + + void registerNuclideMetricRequest( + const std::string &name, const size_t id, const size_t n_inventories, + const nuclide_quantities::NuclideQuantitiesEnum metric) { + + if (std::find(_nuclides.begin(), _nuclides.end(), id) == + _nuclides.end()) { + + _nuclides.push_back(id); + _nuclide_data.emplace_back( + name, n_inventories, + std::vector(metric)); + _nuclide_data.back().addQuantity(metric); + } else { + getNuclide(id).addQuantity(metric); + } + } + + void registerElementMetricRequest( + const size_t n_inventories, + const inventory_outputs::InventoryOutputsEnum metric) { + + _inventory_metrics[metric] = std::vector(n_inventories, 0.0); + } + + bool has_nuclide(size_t nuclide_id) const { + if (find_nuclide(nuclide_id == -1)) { + return false; + } + return true; + } + + int find_nuclide(size_t nuclide_id) const { + for (size_t i = 0; i < _nuclides.size(); ++i) + if (_nuclides[i] == nuclide_id) + return i; + return -1; + } + + NuclideInventory &getNuclide(size_t n) { + return _nuclide_data[find_nuclide(n)]; + } + + const NuclideInventory &getNuclide(size_t n) const { + return _nuclide_data[find_nuclide(n)]; + } + + size_t getElemID() { return _elem_id; } + + std::vector &getNuclides() { return _nuclides; } + + std::unordered_map> & + getInventoryMetricMap() { + return _inventory_metrics; + } + + const double + getElementMetric(inventory_outputs::InventoryOutputsEnum metric, + int inv_index) const { + return _inventory_metrics.at(metric)[inv_index]; + } + + protected: + std::vector _nuclide_data; + std::vector _nuclides; + libMesh::dof_id_type _elem_id; + + size_t _n_element_metrics; + + std::unordered_map> + _inventory_metrics; + }; +}; diff --git a/include/userobjects/FispactMaterial.h b/include/userobjects/FispactMaterial.h new file mode 100644 index 0000000..1701609 --- /dev/null +++ b/include/userobjects/FispactMaterial.h @@ -0,0 +1,70 @@ +#pragma once + +#include "BlockRestrictable.h" +#include "FispactUserObject.h" +#include + +class FispactMaterial : public FispactUserObject, public BlockRestrictable { +public: + static InputParameters validParams(); + + FispactMaterial(const InputParameters ¶ms); + + virtual void initialize() {} + virtual void finalize() {} + virtual void execute() {} + + FispactProblem &getFispactProblem() const; + + /** + * Return a vector of Z or Zai numbers, depending on whether we are using + * setMass or setFuel, corresponding to the nuclides in _nuclides. + */ + // std::vector getZsorZais(const fispact::FispactMonitor &monitor) const; + + /* + * Getter for _nuclides + */ + const std::vector getNuclides() const; + + /* + * Getter for _nuclide_fraction + */ + const std::vector getNuclideFractions() const; + + const std::unordered_map &getNuclideFractionMap() const { + return _nuclide_fraction_map; + } + /* + * Getter for _nuclide_fraction + */ + const double &getDensity() const { return _density; } + + /* + * Getter for _material_type + */ + const std::string &getMaterialType() const { return _material_type; } + + double getAverageMolarMass(const std::vector &nuclide_names, + const std::vector &nuclide_fractions, + const std::string &fraction_type) const; + + void + convertFromAtomToMassFraction(const std::vector &nuclide_names, + std::vector &nuclide_fractions, + const double average_molar_mass); + +protected: + // + std::unordered_map _nuclide_fraction_map; + + const std::unordered_map &_molar_mass_map; + + // Density of the fispact material + double _density; + + // + const std::string _material_type; + + const double _avogadro; +}; diff --git a/include/userobjects/FispactNuclearDataPaths.h b/include/userobjects/FispactNuclearDataPaths.h new file mode 100644 index 0000000..4030683 --- /dev/null +++ b/include/userobjects/FispactNuclearDataPaths.h @@ -0,0 +1,24 @@ +#pragma once + +#include "GeneralUserObject.h" +#include + +class FispactNuclearDataPaths : public GeneralUserObject { +public: + static InputParameters validParams(); + + FispactNuclearDataPaths(const InputParameters ¶ms); + + virtual void initialize() {} + virtual void finalize() {} + virtual void execute() {} + + void loadNuclearDataPaths(); + + std::unordered_map &getNuclearDataPathMap(); + +protected: + /// Nuclear data strings + const std::string _base_path; + std::unordered_map _datatype_to_path_map; +}; diff --git a/include/userobjects/FispactSchedule.h b/include/userobjects/FispactSchedule.h index bdfbc69..ffa9d90 100644 --- a/include/userobjects/FispactSchedule.h +++ b/include/userobjects/FispactSchedule.h @@ -12,13 +12,26 @@ class FispactSchedule : public GeneralUserObject { virtual void finalize() {} virtual void execute() {} - const std::vector &getFluxSchedule(); - const std::vector &getTimes(); + const std::vector &getFluxAmplitude() const; + std::vector getFluxAmplitude(); + const std::vector &getTimes() const; + const std::vector &getCumulativeTimes() const; + const size_t &getNumInventories() const; + const size_t &getNumSolutionInventories() const; protected: /// Vector of flux amplitudes - const std::vector _flux_schedule; + const std::vector _flux_amplitude; /// List of times corresponding to the list of flux amplitudes on or off const std::vector _times; + + /// Cumulative version of _times + std::vector _cumulative_times; + + /// Total number of solution inventories (ignoring initial) + const size_t _n_solution_inventories; + + /// Total number of FISPACT inventories including initial inventory + const size_t _n_inventories; }; diff --git a/include/userobjects/FispactUserObject.h b/include/userobjects/FispactUserObject.h new file mode 100644 index 0000000..687cd6e --- /dev/null +++ b/include/userobjects/FispactUserObject.h @@ -0,0 +1,25 @@ +#pragma once + +#include "GeneralUserObject.h" +#include + +class FispactProblem; + +class FispactUserObject : public GeneralUserObject { +public: + static InputParameters validParams() { + InputParameters params = GeneralUserObject::validParams(); + return params; + }; + + FispactUserObject(const InputParameters ¶ms); + + virtual void initialize() {}; + virtual void finalize() {}; + virtual void execute() {}; + + FispactProblem &getFispactProblem() const { return _fispact_problem; } + +protected: + FispactProblem &_fispact_problem; +}; diff --git a/include/userobjects/OpenMCFluxInput.h b/include/userobjects/OpenMCFluxInput.h new file mode 100644 index 0000000..a4cd7c3 --- /dev/null +++ b/include/userobjects/OpenMCFluxInput.h @@ -0,0 +1,24 @@ +#include "FispactFluxInput.h" +#include "InputParameters.h" +#include "libMeshReducedNamespace.h" +#include "libmesh/id_types.h" + +class OpenMCFluxInput : public FispactFluxInput { + +public: + static InputParameters validParams(); + + OpenMCFluxInput(const InputParameters ¶ms); + + virtual std::vector getElemFlux(dof_id_type elem_id); + + void readEnergyFilterBins(); + void readNumEnergyBins(); + +protected: + size_t _flux_tally_id; + + size_t _energy_filter_id; + + std::string _statepoint_filename; +}; diff --git a/include/utils/EnergyGroups.h b/include/utils/EnergyGroups.h new file mode 100644 index 0000000..a110f00 --- /dev/null +++ b/include/utils/EnergyGroups.h @@ -0,0 +1,364 @@ +#include +#include +#include + +namespace utils { +namespace energy_groups { + +inline std::unordered_map> gamma_groups = { + {24, {1.000e-11, 1.000e+4, 2.000e+4, 5.000e+4, 1.000e+5, 2.000e+5, 3.000e+5, + 4.000e+5, 6.000e+5, 8.000e+5, 1.000e+6, 1.220e+6, 1.440e+6, 1.660e+6, + 2.000e+6, 2.500e+6, 3.000e+6, 4.000e+6, 5.000e+6, 6.500e+6, 8.000e+6, + 1.000e+7, 1.200e+7, 1.400e+7, 2.000e+7}}, + {22, {0.0, 1.0e4, 1.0e5, 2.0e5, 4.0e5, 1.0e6, 1.5e6, 2.0e6, + 2.5e6, 3.0e6, 3.5e6, 4.0e6, 4.5e6, 5.0e6, 5.5e6, 6.0e6, + 6.5e6, 7.0e6, 7.5e6, 8.0e6, 1.0e7, 1.2e7, 1.4e7}}}; + +inline std::unordered_map> neutron_groups = { + {1102, + {1.000000E-05, 1.047129E-05, 1.096478E-05, 1.148154E-05, 1.202264E-05, + 1.258925E-05, 1.318257E-05, 1.380384E-05, 1.445440E-05, 1.513561E-05, + 1.584893E-05, 1.659587E-05, 1.737801E-05, 1.819701E-05, 1.905461E-05, + 1.995262E-05, 2.089296E-05, 2.187762E-05, 2.290868E-05, 2.398833E-05, + 2.511886E-05, 2.630268E-05, 2.754229E-05, 2.884032E-05, 3.019952E-05, + 3.162278E-05, 3.311311E-05, 3.467369E-05, 3.630781E-05, 3.801894E-05, + 3.981072E-05, 4.168694E-05, 4.365158E-05, 4.570882E-05, 4.786301E-05, + 5.011872E-05, 5.248075E-05, 5.495409E-05, 5.754399E-05, 6.025596E-05, + 6.309573E-05, 6.606934E-05, 6.918310E-05, 7.244360E-05, 7.585776E-05, + 7.943282E-05, 8.317638E-05, 8.709636E-05, 9.120108E-05, 9.549926E-05, + 1.000000E-04, 1.047129E-04, 1.096478E-04, 1.148154E-04, 1.202264E-04, + 1.258925E-04, 1.318257E-04, 1.380384E-04, 1.445440E-04, 1.513561E-04, + 1.584893E-04, 1.659587E-04, 1.737801E-04, 1.819701E-04, 1.905461E-04, + 1.995262E-04, 2.089296E-04, 2.187762E-04, 2.290868E-04, 2.398833E-04, + 2.511886E-04, 2.630268E-04, 2.754229E-04, 2.884032E-04, 3.019952E-04, + 3.162278E-04, 3.311311E-04, 3.467369E-04, 3.630781E-04, 3.801894E-04, + 3.981072E-04, 4.168694E-04, 4.365158E-04, 4.570882E-04, 4.786301E-04, + 5.011872E-04, 5.248075E-04, 5.495409E-04, 5.754399E-04, 6.025596E-04, + 6.309573E-04, 6.606934E-04, 6.918310E-04, 7.244360E-04, 7.585776E-04, + 7.943282E-04, 8.317638E-04, 8.709636E-04, 9.120108E-04, 9.549926E-04, + 1.000000E-03, 1.047129E-03, 1.096478E-03, 1.148154E-03, 1.202264E-03, + 1.258925E-03, 1.318257E-03, 1.380384E-03, 1.445440E-03, 1.513561E-03, + 1.584893E-03, 1.659587E-03, 1.737801E-03, 1.819701E-03, 1.905461E-03, + 1.995262E-03, 2.089296E-03, 2.187762E-03, 2.290868E-03, 2.398833E-03, + 2.511886E-03, 2.630268E-03, 2.754229E-03, 2.884032E-03, 3.019952E-03, + 3.162278E-03, 3.311311E-03, 3.467369E-03, 3.630781E-03, 3.801894E-03, + 3.981072E-03, 4.168694E-03, 4.365158E-03, 4.570882E-03, 4.786301E-03, + 5.011872E-03, 5.248075E-03, 5.495409E-03, 5.754399E-03, 6.025596E-03, + 6.309573E-03, 6.606934E-03, 6.918310E-03, 7.244360E-03, 7.585776E-03, + 7.943282E-03, 8.317638E-03, 8.709636E-03, 9.120108E-03, 9.549926E-03, + 1.000000E-02, 1.047129E-02, 1.096478E-02, 1.148154E-02, 1.202264E-02, + 1.258925E-02, 1.318257E-02, 1.380384E-02, 1.445440E-02, 1.513561E-02, + 1.584893E-02, 1.659587E-02, 1.737801E-02, 1.819701E-02, 1.905461E-02, + 1.995262E-02, 2.089296E-02, 2.187762E-02, 2.290868E-02, 2.398833E-02, + 2.511886E-02, 2.630268E-02, 2.754229E-02, 2.884032E-02, 3.019952E-02, + 3.162278E-02, 3.311311E-02, 3.467369E-02, 3.630781E-02, 3.801894E-02, + 3.981072E-02, 4.168694E-02, 4.365158E-02, 4.570882E-02, 4.786301E-02, + 5.011872E-02, 5.248075E-02, 5.495409E-02, 5.754399E-02, 6.025596E-02, + 6.309573E-02, 6.606934E-02, 6.918310E-02, 7.244360E-02, 7.585776E-02, + 7.943282E-02, 8.317638E-02, 8.709636E-02, 9.120108E-02, 9.549926E-02, + 1.000000E-01, 1.047129E-01, 1.096478E-01, 1.148154E-01, 1.202264E-01, + 1.258925E-01, 1.318257E-01, 1.380384E-01, 1.445440E-01, 1.513561E-01, + 1.584893E-01, 1.659587E-01, 1.737801E-01, 1.819701E-01, 1.905461E-01, + 1.995262E-01, 2.089296E-01, 2.187762E-01, 2.290868E-01, 2.398833E-01, + 2.511886E-01, 2.630268E-01, 2.754229E-01, 2.884032E-01, 3.019952E-01, + 3.162278E-01, 3.311311E-01, 3.467369E-01, 3.630781E-01, 3.801894E-01, + 3.981072E-01, 4.168694E-01, 4.365158E-01, 4.570882E-01, 4.786301E-01, + 5.011872E-01, 5.248075E-01, 5.500000E-01, 5.750000E-01, 6.000000E-01, + 6.250000E-01, 6.500000E-01, 6.750000E-01, 7.000000E-01, 7.250000E-01, + 7.500000E-01, 7.750000E-01, 8.000000E-01, 8.250000E-01, 8.500000E-01, + 8.750000E-01, 9.000000E-01, 9.250000E-01, 9.500000E-01, 9.750000E-01, + 1.000000E+00, 1.025000E+00, 1.050000E+00, 1.075000E+00, 1.100000E+00, + 1.125000E+00, 1.150000E+00, 1.175000E+00, 1.200000E+00, 1.225000E+00, + 1.250000E+00, 1.275000E+00, 1.300000E+00, 1.325000E+00, 1.350000E+00, + 1.375000E+00, 1.400000E+00, 1.425000E+00, 1.450000E+00, 1.475000E+00, + 1.500000E+00, 1.525000E+00, 1.550000E+00, 1.575000E+00, 1.600000E+00, + 1.625000E+00, 1.650000E+00, 1.675000E+00, 1.700000E+00, 1.725000E+00, + 1.750000E+00, 1.775000E+00, 1.800000E+00, 1.825000E+00, 1.850000E+00, + 1.875000E+00, 1.900000E+00, 1.925000E+00, 1.950000E+00, 1.975000E+00, + 2.000000E+00, 2.025000E+00, 2.050000E+00, 2.075000E+00, 2.100000E+00, + 2.125000E+00, 2.150000E+00, 2.175000E+00, 2.200000E+00, 2.225000E+00, + 2.250000E+00, 2.275000E+00, 2.300000E+00, 2.325000E+00, 2.350000E+00, + 2.375000E+00, 2.400000E+00, 2.425000E+00, 2.450000E+00, 2.475000E+00, + 2.500000E+00, 2.525000E+00, 2.550000E+00, 2.575000E+00, 2.600000E+00, + 2.625000E+00, 2.650000E+00, 2.675000E+00, 2.700000E+00, 2.725000E+00, + 2.750000E+00, 2.775000E+00, 2.800000E+00, 2.825000E+00, 2.850000E+00, + 2.875000E+00, 2.900000E+00, 2.925000E+00, 2.950000E+00, 2.975000E+00, + 3.000000E+00, 3.025000E+00, 3.050000E+00, 3.075000E+00, 3.100000E+00, + 3.125000E+00, 3.150000E+00, 3.175000E+00, 3.200000E+00, 3.225000E+00, + 3.250000E+00, 3.275000E+00, 3.300000E+00, 3.325000E+00, 3.350000E+00, + 3.375000E+00, 3.400000E+00, 3.425000E+00, 3.450000E+00, 3.475000E+00, + 3.500000E+00, 3.525000E+00, 3.550000E+00, 3.575000E+00, 3.600000E+00, + 3.625000E+00, 3.650000E+00, 3.675000E+00, 3.700000E+00, 3.725000E+00, + 3.750000E+00, 3.775000E+00, 3.800000E+00, 3.825000E+00, 3.850000E+00, + 3.875000E+00, 3.900000E+00, 3.925000E+00, 3.950000E+00, 3.975000E+00, + 4.000000E+00, 4.025000E+00, 4.050000E+00, 4.075000E+00, 4.100000E+00, + 4.125000E+00, 4.150000E+00, 4.175000E+00, 4.200000E+00, 4.225000E+00, + 4.250000E+00, 4.275000E+00, 4.300000E+00, 4.325000E+00, 4.350000E+00, + 4.375000E+00, 4.400000E+00, 4.425000E+00, 4.450000E+00, 4.475000E+00, + 4.500000E+00, 4.525000E+00, 4.550000E+00, 4.575000E+00, 4.600000E+00, + 4.625000E+00, 4.650000E+00, 4.675000E+00, 4.700000E+00, 4.725000E+00, + 4.750000E+00, 4.775000E+00, 4.800000E+00, 4.825000E+00, 4.850000E+00, + 4.875000E+00, 4.900000E+00, 4.925000E+00, 4.950000E+00, 4.975000E+00, + 5.000000E+00, 5.025000E+00, 5.050000E+00, 5.075000E+00, 5.100000E+00, + 5.125000E+00, 5.150000E+00, 5.175000E+00, 5.200000E+00, 5.225000E+00, + 5.250000E+00, 5.275000E+00, 5.300000E+00, 5.325000E+00, 5.350000E+00, + 5.375000E+00, 5.400000E+00, 5.425000E+00, 5.450000E+00, 5.475000E+00, + 5.500000E+00, 5.525000E+00, 5.550000E+00, 5.575000E+00, 5.600000E+00, + 5.625000E+00, 5.650000E+00, 5.675000E+00, 5.700000E+00, 5.725000E+00, + 5.750000E+00, 5.775000E+00, 5.800000E+00, 5.825000E+00, 5.850000E+00, + 5.875000E+00, 5.900000E+00, 5.925000E+00, 5.950000E+00, 5.975000E+00, + 6.000000E+00, 6.025000E+00, 6.050000E+00, 6.075000E+00, 6.100000E+00, + 6.125000E+00, 6.150000E+00, 6.175000E+00, 6.200000E+00, 6.225000E+00, + 6.250000E+00, 6.275000E+00, 6.300000E+00, 6.325000E+00, 6.350000E+00, + 6.375000E+00, 6.400000E+00, 6.425000E+00, 6.450000E+00, 6.475000E+00, + 6.500000E+00, 6.525000E+00, 6.550000E+00, 6.575000E+00, 6.600000E+00, + 6.625000E+00, 6.650000E+00, 6.675000E+00, 6.700000E+00, 6.725000E+00, + 6.750000E+00, 6.775000E+00, 6.800000E+00, 6.825000E+00, 6.850000E+00, + 6.875000E+00, 6.900000E+00, 6.925000E+00, 6.950000E+00, 6.975000E+00, + 7.000000E+00, 7.025000E+00, 7.050000E+00, 7.075000E+00, 7.100000E+00, + 7.125000E+00, 7.150000E+00, 7.175000E+00, 7.200000E+00, 7.225000E+00, + 7.250000E+00, 7.275000E+00, 7.300000E+00, 7.325000E+00, 7.350000E+00, + 7.375000E+00, 7.400000E+00, 7.425000E+00, 7.450000E+00, 7.475000E+00, + 7.500000E+00, 7.525000E+00, 7.550000E+00, 7.575000E+00, 7.600000E+00, + 7.625000E+00, 7.650000E+00, 7.675000E+00, 7.700000E+00, 7.725000E+00, + 7.750000E+00, 7.775000E+00, 7.800000E+00, 7.825000E+00, 7.850000E+00, + 7.875000E+00, 7.900000E+00, 7.925000E+00, 7.950000E+00, 7.975000E+00, + 8.000000E+00, 8.025000E+00, 8.050000E+00, 8.075000E+00, 8.100000E+00, + 8.125000E+00, 8.150000E+00, 8.175000E+00, 8.200000E+00, 8.225000E+00, + 8.250000E+00, 8.275000E+00, 8.300000E+00, 8.325000E+00, 8.350000E+00, + 8.375000E+00, 8.400000E+00, 8.425000E+00, 8.450000E+00, 8.475000E+00, + 8.500000E+00, 8.525000E+00, 8.550000E+00, 8.575000E+00, 8.600000E+00, + 8.625000E+00, 8.650000E+00, 8.675000E+00, 8.700000E+00, 8.725000E+00, + 8.750000E+00, 8.775000E+00, 8.800000E+00, 8.825000E+00, 8.850000E+00, + 8.875000E+00, 8.900000E+00, 8.925000E+00, 8.950000E+00, 8.975000E+00, + 9.000000E+00, 9.025000E+00, 9.050000E+00, 9.075000E+00, 9.100000E+00, + 9.125000E+00, 9.150000E+00, 9.175000E+00, 9.200000E+00, 9.225000E+00, + 9.250000E+00, 9.275000E+00, 9.300000E+00, 9.325000E+00, 9.350000E+00, + 9.375000E+00, 9.400000E+00, 9.425000E+00, 9.450000E+00, 9.475000E+00, + 9.500000E+00, 9.525000E+00, 9.550000E+00, 9.575000E+00, 9.600000E+00, + 9.625000E+00, 9.650000E+00, 9.675000E+00, 9.700000E+00, 9.725000E+00, + 9.750000E+00, 9.775000E+00, 9.800000E+00, 9.825000E+00, 9.850000E+00, + 9.875000E+00, 9.900000E+00, 9.925000E+00, 9.950000E+00, 9.975000E+00, + 1.000000E+01, 1.047129E+01, 1.096478E+01, 1.148154E+01, 1.202264E+01, + 1.258925E+01, 1.318257E+01, 1.380384E+01, 1.445440E+01, 1.513561E+01, + 1.584893E+01, 1.659587E+01, 1.737801E+01, 1.819701E+01, 1.905461E+01, + 1.995262E+01, 2.089296E+01, 2.187762E+01, 2.290868E+01, 2.398833E+01, + 2.511886E+01, 2.630268E+01, 2.754229E+01, 2.884032E+01, 3.019952E+01, + 3.162278E+01, 3.311311E+01, 3.467369E+01, 3.630781E+01, 3.801894E+01, + 3.981072E+01, 4.168694E+01, 4.365158E+01, 4.570882E+01, 4.786301E+01, + 5.011872E+01, 5.248075E+01, 5.495409E+01, 5.754399E+01, 6.025596E+01, + 6.309573E+01, 6.606934E+01, 6.918310E+01, 7.244360E+01, 7.585776E+01, + 7.943282E+01, 8.317638E+01, 8.709636E+01, 9.120108E+01, 9.549926E+01, + 1.000000E+02, 1.047129E+02, 1.096478E+02, 1.148154E+02, 1.202264E+02, + 1.258925E+02, 1.318257E+02, 1.380384E+02, 1.445440E+02, 1.513561E+02, + 1.584893E+02, 1.659587E+02, 1.737801E+02, 1.819701E+02, 1.905461E+02, + 1.995262E+02, 2.089296E+02, 2.187762E+02, 2.290868E+02, 2.398833E+02, + 2.511886E+02, 2.630268E+02, 2.754229E+02, 2.884032E+02, 3.019952E+02, + 3.162278E+02, 3.311311E+02, 3.467369E+02, 3.630781E+02, 3.801894E+02, + 3.981072E+02, 4.168694E+02, 4.365158E+02, 4.570882E+02, 4.786301E+02, + 5.011872E+02, 5.248075E+02, 5.495409E+02, 5.754399E+02, 6.025596E+02, + 6.309573E+02, 6.606934E+02, 6.918310E+02, 7.244360E+02, 7.585776E+02, + 7.943282E+02, 8.317638E+02, 8.709636E+02, 9.120108E+02, 9.549926E+02, + 1.000000E+03, 1.047129E+03, 1.096478E+03, 1.148154E+03, 1.202264E+03, + 1.258925E+03, 1.318257E+03, 1.380384E+03, 1.445440E+03, 1.513561E+03, + 1.584893E+03, 1.659587E+03, 1.737801E+03, 1.819701E+03, 1.905461E+03, + 1.995262E+03, 2.089296E+03, 2.187762E+03, 2.290868E+03, 2.398833E+03, + 2.511886E+03, 2.630268E+03, 2.754229E+03, 2.884032E+03, 3.019952E+03, + 3.162278E+03, 3.311311E+03, 3.467369E+03, 3.630781E+03, 3.801894E+03, + 3.981072E+03, 4.168694E+03, 4.365158E+03, 4.570882E+03, 4.786301E+03, + 5.011872E+03, 5.248075E+03, 5.495409E+03, 5.754399E+03, 6.025596E+03, + 6.309573E+03, 6.606934E+03, 6.918310E+03, 7.244360E+03, 7.585776E+03, + 7.943282E+03, 8.317638E+03, 8.709636E+03, 9.120108E+03, 9.549926E+03, + 1.000000E+04, 1.047129E+04, 1.096478E+04, 1.148154E+04, 1.202264E+04, + 1.258925E+04, 1.318257E+04, 1.380384E+04, 1.445440E+04, 1.513561E+04, + 1.584893E+04, 1.659587E+04, 1.737801E+04, 1.819701E+04, 1.905461E+04, + 1.995262E+04, 2.089296E+04, 2.187762E+04, 2.290868E+04, 2.398833E+04, + 2.511886E+04, 2.630268E+04, 2.754229E+04, 2.884032E+04, 3.019952E+04, + 3.162278E+04, 3.311311E+04, 3.467369E+04, 3.630781E+04, 3.801894E+04, + 3.981072E+04, 4.168694E+04, 4.365158E+04, 4.570882E+04, 4.786301E+04, + 5.011872E+04, 5.248075E+04, 5.495409E+04, 5.754399E+04, 6.025596E+04, + 6.309573E+04, 6.606934E+04, 6.918310E+04, 7.244360E+04, 7.585776E+04, + 7.943282E+04, 8.317638E+04, 8.709636E+04, 9.120108E+04, 9.549926E+04, + 1.000000E+05, 1.047129E+05, 1.096478E+05, 1.148154E+05, 1.202264E+05, + 1.258925E+05, 1.318257E+05, 1.380384E+05, 1.445440E+05, 1.513561E+05, + 1.584893E+05, 1.659587E+05, 1.737801E+05, 1.819701E+05, 1.905461E+05, + 1.995262E+05, 2.089296E+05, 2.187762E+05, 2.290868E+05, 2.398833E+05, + 2.511886E+05, 2.630268E+05, 2.754229E+05, 2.884032E+05, 3.019952E+05, + 3.162278E+05, 3.311311E+05, 3.467369E+05, 3.630781E+05, 3.801894E+05, + 3.981072E+05, 4.168694E+05, 4.365158E+05, 4.570882E+05, 4.786301E+05, + 5.011872E+05, 5.248075E+05, 5.495409E+05, 5.754399E+05, 6.025596E+05, + 6.309573E+05, 6.606934E+05, 6.918310E+05, 7.244360E+05, 7.585776E+05, + 7.943282E+05, 8.317638E+05, 8.709636E+05, 9.120108E+05, 9.549926E+05, + 1.000000E+06, 1.047129E+06, 1.096478E+06, 1.148154E+06, 1.202264E+06, + 1.258925E+06, 1.318257E+06, 1.380384E+06, 1.445440E+06, 1.513561E+06, + 1.584893E+06, 1.659587E+06, 1.737801E+06, 1.819701E+06, 1.905461E+06, + 1.995262E+06, 2.089296E+06, 2.187762E+06, 2.290868E+06, 2.398833E+06, + 2.511886E+06, 2.630268E+06, 2.754229E+06, 2.884032E+06, 3.019952E+06, + 3.162278E+06, 3.311311E+06, 3.467369E+06, 3.630781E+06, 3.801894E+06, + 3.981072E+06, 4.168694E+06, 4.365158E+06, 4.570882E+06, 4.786301E+06, + 5.000000E+06, 5.200000E+06, 5.400000E+06, 5.600000E+06, 5.800000E+06, + 6.000000E+06, 6.200000E+06, 6.400000E+06, 6.600000E+06, 6.800000E+06, + 7.000000E+06, 7.200000E+06, 7.400000E+06, 7.600000E+06, 7.800000E+06, + 8.000000E+06, 8.200000E+06, 8.400000E+06, 8.600000E+06, 8.800000E+06, + 9.000000E+06, 9.200000E+06, 9.400000E+06, 9.600000E+06, 9.800000E+06, + 1.000000E+07, 1.020000E+07, 1.040000E+07, 1.060000E+07, 1.080000E+07, + 1.100000E+07, 1.120000E+07, 1.140000E+07, 1.160000E+07, 1.180000E+07, + 1.200000E+07, 1.220000E+07, 1.240000E+07, 1.260000E+07, 1.280000E+07, + 1.300000E+07, 1.320000E+07, 1.340000E+07, 1.360000E+07, 1.380000E+07, + 1.400000E+07, 1.420000E+07, 1.440000E+07, 1.460000E+07, 1.480000E+07, + 1.500000E+07, 1.520000E+07, 1.540000E+07, 1.560000E+07, 1.580000E+07, + 1.600000E+07, 1.620000E+07, 1.640000E+07, 1.660000E+07, 1.680000E+07, + 1.700000E+07, 1.720000E+07, 1.740000E+07, 1.760000E+07, 1.780000E+07, + 1.800000E+07, 1.820000E+07, 1.840000E+07, 1.860000E+07, 1.880000E+07, + 1.900000E+07, 1.920000E+07, 1.940000E+07, 1.960000E+07, 1.980000E+07, + 2.000000E+07, 2.020000E+07, 2.040000E+07, 2.060000E+07, 2.080000E+07, + 2.100000E+07, 2.120000E+07, 2.140000E+07, 2.160000E+07, 2.180000E+07, + 2.200000E+07, 2.220000E+07, 2.240000E+07, 2.260000E+07, 2.280000E+07, + 2.300000E+07, 2.320000E+07, 2.340000E+07, 2.360000E+07, 2.380000E+07, + 2.400000E+07, 2.420000E+07, 2.440000E+07, 2.460000E+07, 2.480000E+07, + 2.500000E+07, 2.520000E+07, 2.540000E+07, 2.560000E+07, 2.580000E+07, + 2.600000E+07, 2.620000E+07, 2.640000E+07, 2.660000E+07, 2.680000E+07, + 2.700000E+07, 2.720000E+07, 2.740000E+07, 2.760000E+07, 2.780000E+07, + 2.800000E+07, 2.820000E+07, 2.840000E+07, 2.860000E+07, 2.880000E+07, + 2.900000E+07, 2.920000E+07, 2.940000E+07, 2.960000E+07, 2.980000E+07, + 3.000000E+07, 3.019952E+07, 3.162278E+07, 3.311311E+07, 3.467369E+07, + 3.630781E+07, 3.801894E+07, 3.981072E+07, 4.168694E+07, 4.365158E+07, + 4.570882E+07, 4.786301E+07, 5.011872E+07, 5.248075E+07, 5.495409E+07, + 5.754399E+07, 6.025596E+07, 6.309573E+07, 6.606934E+07, 6.918310E+07, + 7.244360E+07, 7.585776E+07, 7.943282E+07, 8.317638E+07, 8.709636E+07, + 9.120108E+07, 9.549926E+07, 1.000000E+08, 1.047129E+08, 1.096478E+08, + 1.148154E+08, 1.202264E+08, 1.258925E+08, 1.318257E+08, 1.380384E+08, + 1.445440E+08, 1.513561E+08, 1.584893E+08, 1.659587E+08, 1.737801E+08, + 1.819701E+08, 1.905461E+08, 1.995262E+08, 2.089296E+08, 2.187762E+08, + 2.290868E+08, 2.398833E+08, 2.511886E+08, 2.630268E+08, 2.754229E+08, + 2.884032E+08, 3.019952E+08, 3.162278E+08, 3.311311E+08, 3.467369E+08, + 3.630781E+08, 3.801894E+08, 3.981072E+08, 4.168694E+08, 4.365158E+08, + 4.570882E+08, 4.786301E+08, 5.011872E+08, 5.248075E+08, 5.495409E+08, + 5.754399E+08, 6.025596E+08, 6.309573E+08, 6.606934E+08, 6.918310E+08, + 7.244360E+08, 7.585776E+08, 7.943282E+08, 8.317638E+08, 8.709636E+08, + 9.120108E+08, 9.549926E+08, 1.000000E+09}}, + + {709, {1.0000E-5, 1.0471E-5, 1.0965E-5, 1.1482E-5, 1.2023E-5, 1.2589E-5, + 1.3183E-5, 1.3804E-5, 1.4454E-5, 1.5136E-5, 1.5849E-5, 1.6596E-5, + 1.7378E-5, 1.8197E-5, 1.9055E-5, 1.9953E-5, 2.0893E-5, 2.1878E-5, + 2.2909E-5, 2.3988E-5, 2.5119E-5, 2.6303E-5, 2.7542E-5, 2.8840E-5, + 3.0200E-5, 3.1623E-5, 3.3113E-5, 3.4674E-5, 3.6308E-5, 3.8019E-5, + 3.9811E-5, 4.1687E-5, 4.3652E-5, 4.5709E-5, 4.7863E-5, 5.0119E-5, + 5.2481E-5, 5.4954E-5, 5.7544E-5, 6.0256E-5, 6.3096E-5, 6.6069E-5, + 6.9183E-5, 7.2444E-5, 7.5858E-5, 7.9433E-5, 8.3176E-5, 8.7096E-5, + 9.1201E-5, 9.5499E-5, 1.0000E-4, 1.0471E-4, 1.0965E-4, 1.1482E-4, + 1.2023E-4, 1.2589E-4, 1.3183E-4, 1.3804E-4, 1.4454E-4, 1.5136E-4, + 1.5849E-4, 1.6596E-4, 1.7378E-4, 1.8197E-4, 1.9055E-4, 1.9953E-4, + 2.0893E-4, 2.1878E-4, 2.2909E-4, 2.3988E-4, 2.5119E-4, 2.6303E-4, + 2.7542E-4, 2.8840E-4, 3.0200E-4, 3.1623E-4, 3.3113E-4, 3.4674E-4, + 3.6308E-4, 3.8019E-4, 3.9811E-4, 4.1687E-4, 4.3652E-4, 4.5709E-4, + 4.7863E-4, 5.0119E-4, 5.2481E-4, 5.4954E-4, 5.7544E-4, 6.0256E-4, + 6.3096E-4, 6.6069E-4, 6.9183E-4, 7.2444E-4, 7.5858E-4, 7.9433E-4, + 8.3176E-4, 8.7096E-4, 9.1201E-4, 9.5499E-4, 1.0000E-3, 1.0471E-3, + 1.0965E-3, 1.1482E-3, 1.2023E-3, 1.2589E-3, 1.3183E-3, 1.3804E-3, + 1.4454E-3, 1.5136E-3, 1.5849E-3, 1.6596E-3, 1.7378E-3, 1.8197E-3, + 1.9055E-3, 1.9953E-3, 2.0893E-3, 2.1878E-3, 2.2909E-3, 2.3988E-3, + 2.5119E-3, 2.6303E-3, 2.7542E-3, 2.8840E-3, 3.0200E-3, 3.1623E-3, + 3.3113E-3, 3.4674E-3, 3.6308E-3, 3.8019E-3, 3.9811E-3, 4.1687E-3, + 4.3652E-3, 4.5709E-3, 4.7863E-3, 5.0119E-3, 5.2481E-3, 5.4954E-3, + 5.7544E-3, 6.0256E-3, 6.3096E-3, 6.6069E-3, 6.9183E-3, 7.2444E-3, + 7.5858E-3, 7.9433E-3, 8.3176E-3, 8.7096E-3, 9.1201E-3, 9.5499E-3, + 1.0000E-2, 1.0471E-2, 1.0965E-2, 1.1482E-2, 1.2023E-2, 1.2589E-2, + 1.3183E-2, 1.3804E-2, 1.4454E-2, 1.5136E-2, 1.5849E-2, 1.6596E-2, + 1.7378E-2, 1.8197E-2, 1.9055E-2, 1.9953E-2, 2.0893E-2, 2.1878E-2, + 2.2909E-2, 2.3988E-2, 2.5119E-2, 2.6303E-2, 2.7542E-2, 2.8840E-2, + 3.0200E-2, 3.1623E-2, 3.3113E-2, 3.4674E-2, 3.6308E-2, 3.8019E-2, + 3.9811E-2, 4.1687E-2, 4.3652E-2, 4.5709E-2, 4.7863E-2, 5.0119E-2, + 5.2481E-2, 5.4954E-2, 5.7544E-2, 6.0256E-2, 6.3096E-2, 6.6069E-2, + 6.9183E-2, 7.2444E-2, 7.5858E-2, 7.9433E-2, 8.3176E-2, 8.7096E-2, + 9.1201E-2, 9.5499E-2, 1.0000E-1, 1.0471E-1, 1.0965E-1, 1.1482E-1, + 1.2023E-1, 1.2589E-1, 1.3183E-1, 1.3804E-1, 1.4454E-1, 1.5136E-1, + 1.5849E-1, 1.6596E-1, 1.7378E-1, 1.8197E-1, 1.9055E-1, 1.9953E-1, + 2.0893E-1, 2.1878E-1, 2.2909E-1, 2.3988E-1, 2.5119E-1, 2.6303E-1, + 2.7542E-1, 2.8840E-1, 3.0200E-1, 3.1623E-1, 3.3113E-1, 3.4674E-1, + 3.6308E-1, 3.8019E-1, 3.9811E-1, 4.1687E-1, 4.3652E-1, 4.5709E-1, + 4.7863E-1, 5.0119E-1, 5.2481E-1, 5.4954E-1, 5.7544E-1, 6.0256E-1, + 6.3096E-1, 6.6069E-1, 6.9183E-1, 7.2444E-1, 7.5858E-1, 7.9433E-1, + 8.3176E-1, 8.7096E-1, 9.1201E-1, 9.5499E-1, 1.0000E+0, 1.0471E+0, + 1.0965E+0, 1.1482E+0, 1.2023E+0, 1.2589E+0, 1.3183E+0, 1.3804E+0, + 1.4454E+0, 1.5136E+0, 1.5849E+0, 1.6596E+0, 1.7378E+0, 1.8197E+0, + 1.9055E+0, 1.9953E+0, 2.0893E+0, 2.1878E+0, 2.2909E+0, 2.3988E+0, + 2.5119E+0, 2.6303E+0, 2.7542E+0, 2.8840E+0, 3.0200E+0, 3.1623E+0, + 3.3113E+0, 3.4674E+0, 3.6308E+0, 3.8019E+0, 3.9811E+0, 4.1687E+0, + 4.3652E+0, 4.5709E+0, 4.7863E+0, 5.0119E+0, 5.2481E+0, 5.4954E+0, + 5.7544E+0, 6.0256E+0, 6.3096E+0, 6.6069E+0, 6.9183E+0, 7.2444E+0, + 7.5858E+0, 7.9433E+0, 8.3176E+0, 8.7096E+0, 9.1201E+0, 9.5499E+0, + 1.0000E+1, 1.0471E+1, 1.0965E+1, 1.1482E+1, 1.2023E+1, 1.2589E+1, + 1.3183E+1, 1.3804E+1, 1.4454E+1, 1.5136E+1, 1.5849E+1, 1.6596E+1, + 1.7378E+1, 1.8197E+1, 1.9055E+1, 1.9953E+1, 2.0893E+1, 2.1878E+1, + 2.2909E+1, 2.3988E+1, 2.5119E+1, 2.6303E+1, 2.7542E+1, 2.8840E+1, + 3.0200E+1, 3.1623E+1, 3.3113E+1, 3.4674E+1, 3.6308E+1, 3.8019E+1, + 3.9811E+1, 4.1687E+1, 4.3652E+1, 4.5709E+1, 4.7863E+1, 5.0119E+1, + 5.2481E+1, 5.4954E+1, 5.7544E+1, 6.0256E+1, 6.3096E+1, 6.6069E+1, + 6.9183E+1, 7.2444E+1, 7.5858E+1, 7.9433E+1, 8.3176E+1, 8.7096E+1, + 9.1201E+1, 9.5499E+1, 1.0000E+2, 1.0471E+2, 1.0965E+2, 1.1482E+2, + 1.2023E+2, 1.2589E+2, 1.3183E+2, 1.3804E+2, 1.4454E+2, 1.5136E+2, + 1.5849E+2, 1.6596E+2, 1.7378E+2, 1.8197E+2, 1.9055E+2, 1.9953E+2, + 2.0893E+2, 2.1878E+2, 2.2909E+2, 2.3988E+2, 2.5119E+2, 2.6303E+2, + 2.7542E+2, 2.8840E+2, 3.0200E+2, 3.1623E+2, 3.3113E+2, 3.4674E+2, + 3.6308E+2, 3.8019E+2, 3.9811E+2, 4.1687E+2, 4.3652E+2, 4.5709E+2, + 4.7863E+2, 5.0119E+2, 5.2481E+2, 5.4954E+2, 5.7544E+2, 6.0256E+2, + 6.3096E+2, 6.6069E+2, 6.9183E+2, 7.2444E+2, 7.5858E+2, 7.9433E+2, + 8.3176E+2, 8.7096E+2, 9.1201E+2, 9.5499E+2, 1.0000E+3, 1.0471E+3, + 1.0965E+3, 1.1482E+3, 1.2023E+3, 1.2589E+3, 1.3183E+3, 1.3804E+3, + 1.4454E+3, 1.5136E+3, 1.5849E+3, 1.6596E+3, 1.7378E+3, 1.8197E+3, + 1.9055E+3, 1.9953E+3, 2.0893E+3, 2.1878E+3, 2.2909E+3, 2.3988E+3, + 2.5119E+3, 2.6303E+3, 2.7542E+3, 2.8840E+3, 3.0200E+3, 3.1623E+3, + 3.3113E+3, 3.4674E+3, 3.6308E+3, 3.8019E+3, 3.9811E+3, 4.1687E+3, + 4.3652E+3, 4.5709E+3, 4.7863E+3, 5.0119E+3, 5.2481E+3, 5.4954E+3, + 5.7544E+3, 6.0256E+3, 6.3096E+3, 6.6069E+3, 6.9183E+3, 7.2444E+3, + 7.5858E+3, 7.9433E+3, 8.3176E+3, 8.7096E+3, 9.1201E+3, 9.5499E+3, + 1.0000E+4, 1.0471E+4, 1.0965E+4, 1.1482E+4, 1.2023E+4, 1.2589E+4, + 1.3183E+4, 1.3804E+4, 1.4454E+4, 1.5136E+4, 1.5849E+4, 1.6596E+4, + 1.7378E+4, 1.8197E+4, 1.9055E+4, 1.9953E+4, 2.0893E+4, 2.1878E+4, + 2.2909E+4, 2.3988E+4, 2.5119E+4, 2.6303E+4, 2.7542E+4, 2.8840E+4, + 3.0200E+4, 3.1623E+4, 3.3113E+4, 3.4674E+4, 3.6308E+4, 3.8019E+4, + 3.9811E+4, 4.1687E+4, 4.3652E+4, 4.5709E+4, 4.7863E+4, 5.0119E+4, + 5.2481E+4, 5.4954E+4, 5.7544E+4, 6.0256E+4, 6.3096E+4, 6.6069E+4, + 6.9183E+4, 7.2444E+4, 7.5858E+4, 7.9433E+4, 8.3176E+4, 8.7096E+4, + 9.1201E+4, 9.5499E+4, 1.0000E+5, 1.0471E+5, 1.0965E+5, 1.1482E+5, + 1.2023E+5, 1.2589E+5, 1.3183E+5, 1.3804E+5, 1.4454E+5, 1.5136E+5, + 1.5849E+5, 1.6596E+5, 1.7378E+5, 1.8197E+5, 1.9055E+5, 1.9953E+5, + 2.0893E+5, 2.1878E+5, 2.2909E+5, 2.3988E+5, 2.5119E+5, 2.6303E+5, + 2.7542E+5, 2.8840E+5, 3.0200E+5, 3.1623E+5, 3.3113E+5, 3.4674E+5, + 3.6308E+5, 3.8019E+5, 3.9811E+5, 4.1687E+5, 4.3652E+5, 4.5709E+5, + 4.7863E+5, 5.0119E+5, 5.2481E+5, 5.4954E+5, 5.7544E+5, 6.0256E+5, + 6.3096E+5, 6.6069E+5, 6.9183E+5, 7.2444E+5, 7.5858E+5, 7.9433E+5, + 8.3176E+5, 8.7096E+5, 9.1201E+5, 9.5499E+5, 1.0000E+6, 1.0471E+6, + 1.0965E+6, 1.1482E+6, 1.2023E+6, 1.2589E+6, 1.3183E+6, 1.3804E+6, + 1.4454E+6, 1.5136E+6, 1.5849E+6, 1.6596E+6, 1.7378E+6, 1.8197E+6, + 1.9055E+6, 1.9953E+6, 2.0893E+6, 2.1878E+6, 2.2909E+6, 2.3988E+6, + 2.5119E+6, 2.6303E+6, 2.7542E+6, 2.8840E+6, 3.0200E+6, 3.1623E+6, + 3.3113E+6, 3.4674E+6, 3.6308E+6, 3.8019E+6, 3.9811E+6, 4.1687E+6, + 4.3652E+6, 4.5709E+6, 4.7863E+6, 5.0119E+6, 5.2481E+6, 5.4954E+6, + 5.7544E+6, 6.0256E+6, 6.3096E+6, 6.6069E+6, 6.9183E+6, 7.2444E+6, + 7.5858E+6, 7.9433E+6, 8.3176E+6, 8.7096E+6, 9.1201E+6, 9.5499E+6, + 1.0000E+7, 1.0200E+7, 1.0400E+7, 1.0600E+7, 1.0800E+7, 1.1000E+7, + 1.1200E+7, 1.1400E+7, 1.1600E+7, 1.1800E+7, 1.2000E+7, 1.2200E+7, + 1.2400E+7, 1.2600E+7, 1.2800E+7, 1.3000E+7, 1.3200E+7, 1.3400E+7, + 1.3600E+7, 1.3800E+7, 1.4000E+7, 1.4200E+7, 1.4400E+7, 1.4600E+7, + 1.4800E+7, 1.5000E+7, 1.5200E+7, 1.5400E+7, 1.5600E+7, 1.5800E+7, + 1.6000E+7, 1.6200E+7, 1.6400E+7, 1.6600E+7, 1.6800E+7, 1.7000E+7, + 1.7200E+7, 1.7400E+7, 1.7600E+7, 1.7800E+7, 1.8000E+7, 1.8200E+7, + 1.8400E+7, 1.8600E+7, 1.8800E+7, 1.9000E+7, 1.9200E+7, 1.9400E+7, + 1.9600E+7, 1.9800E+7, 2.0000E+7, 2.1000E+7, 2.2000E+7, 2.3000E+7, + 2.4000E+7, 2.5000E+7, 2.6000E+7, 2.7000E+7, 2.8000E+7, 2.9000E+7, + 3.0000E+7, 3.2000E+7, 3.4000E+7, 3.6000E+7, 3.8000E+7, 4.0000E+7, + 4.2000E+7, 4.4000E+7, 4.6000E+7, 4.8000E+7, 5.0000E+7, 5.2000E+7, + 5.4000E+7, 5.6000E+7, 5.8000E+7, 6.0000E+7, 6.5000E+7, 7.0000E+7, + 7.5000E+7, 8.0000E+7, 9.0000E+7, 1.0000E+8, 1.1000E+8, 1.2000E+8, + 1.3000E+8, 1.4000E+8, 1.5000E+8, 1.6000E+8, 1.8000E+8, 2.0000E+8, + 2.4000E+8, 2.8000E+8, 3.2000E+8, 3.6000E+8, 4.0000E+8, 4.4000E+8, + 4.8000E+8, 5.2000E+8, 5.6000E+8, 6.0000E+8, 6.4000E+8, 6.8000E+8, + 7.2000E+8, 7.6000E+8, 8.0000E+8, 8.4000E+8, 8.8000E+8, 9.2000E+8, + 9.6000E+8, 1.0000E+9}}}; + +}; // namespace energy_groups +}; // namespace utils +// +// diff --git a/include/utils/HDF5Utils.h b/include/utils/HDF5Utils.h new file mode 100644 index 0000000..e3c74eb --- /dev/null +++ b/include/utils/HDF5Utils.h @@ -0,0 +1,98 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MooseError.h" + +#include "hdf5.h" +#include "hdf5_hl.h" + +namespace hdf5_utils { + +/* + *Check an attribute exists for a given object, using the object id and the + *name of the attribute + * + * + **/ +bool attribute_exists(hid_t obj_id, const char *name); +/***/ +bool object_exists(hid_t object_id, const char *name); + +/* + * Get the shape of an object + * + * + **/ +void get_shape(hid_t obj_id, hsize_t *dims); + +std::string object_name(hid_t obj_id); +/***/ +void ensure_exists(hid_t obj_id, const char *name, bool attribute = false); + +/***/ +hid_t file_open(const char *filename, char mode, bool parallel, + const MPI_Comm &comm); + +/***/ +void file_close(hid_t file_id); + +/***/ + +hid_t open_dataset(hid_t group_id, const char *name); + +void close_dataset(hid_t dataset_id); + +hid_t open_group(hid_t group_id, const char *name); + +hid_t open_group(hid_t group_id, const std::string &name); + +void close_group(hid_t group_id); + +void read_dataset_lowlevel(hid_t obj_id, const char *name, hid_t mem_type_id, + hid_t mem_space_id, void *buffer, bool parallel, + bool indep = true, hid_t file_space_id = H5S_ALL); + +void write_dataset_lowlevel(hid_t obj_id, const char *name, int ndim, + const hsize_t *dims, hid_t mem_type_id, + void *buffer, bool parallel, bool indep = true, + hid_t file_space_id = H5S_ALL); + +void read_double(hid_t obj_id, const char *name, double *buffer, bool parallel, + bool indep = true); + +void read_int(hid_t obj_id, const char *name, int *buffer, bool parallel, + bool indep = true); + +void read_string(hid_t obj_id, const char *name, + std::vector &buffer, int slen, bool parallel, + bool indep = true); + +bool using_mpio_device(hid_t obj_id); + +void read_double_hyperslab(hid_t group_id, const char *name, hsize_t rank, + hsize_t dims[], hsize_t start[], hsize_t count[], + double *results, bool parallel = true, + bool indep = true); + +void write_double_hyperslab(hid_t obj_id, const char *name, hsize_t ndim, + hsize_t dims[3], hsize_t start[], hsize_t count[], + double *results, bool parallel = true, + bool indep = true); +} // namespace hdf5_utils diff --git a/include/utils/PhotonSharingData.h b/include/utils/PhotonSharingData.h new file mode 100644 index 0000000..6996b9f --- /dev/null +++ b/include/utils/PhotonSharingData.h @@ -0,0 +1,150 @@ +#ifndef PHOTON_SHARING_DATA_H +#define PHOTON_SHARING_DATA_H + +#include "boost/interprocess/containers/map.hpp" +#include "boost/interprocess/containers/vector.hpp" +#include "boost/interprocess/managed_shared_memory.hpp" +#include "boost/interprocess/shared_memory_object.hpp" + +#include +#include +#include +#include +#include +#include +#include + +namespace bi = boost::interprocess; + +/// Allocator for vector of doubles +typedef boost::interprocess::allocator< + double, boost::interprocess::managed_shared_memory::segment_manager> + ShmemVecAllocator; + +typedef boost::interprocess::vector BoostIpVector; + +typedef boost::interprocess::allocator< + std::pair, + bi::managed_shared_memory::segment_manager> + ShmemIntIntMapAllocator; + +typedef bi::map, + ShmemIntIntMapAllocator> + BoostIpIntIntMap; + +typedef boost::interprocess::allocator< + std::pair, bi::managed_shared_memory::segment_manager> + ShmemIntDoubMapAllocator; + +typedef bi::map, ShmemIntDoubMapAllocator> + BoostIpIntDoubMap; + +class PhotonSharingData { +public: + // PhotonSharingData( + // bi::managed_shared_memory &segment, std::vector &photon_flux, + // std::vector &elem_strengths, uint64_t num_photon_bins, + // uint64_t num_local_elems, double total_domain_strength, + // double local_domain_strength, std::vector &photon_bins, + // std::unordered_map &local_element_idx_map) + // : _num_photon_bins(num_photon_bins), _num_local_elems(num_local_elems), + // _local_domain_strength(local_domain_strength), + // _total_domain_strength(total_domain_strength), _is_setup(false), + // _vec_alloc(segment.get_segment_manager()), + // _int_int_map_alloc(segment.get_segment_manager()), + // _int_doub_map_alloc(segment.get_segment_manager()), + // _photon_fluxes(_vec_alloc), _elem_strength(_vec_alloc), + // _photon_bins(_vec_alloc), _local_elem_idx_map(_int_int_map_alloc) { + // + // // Initialise shared memory _photon_flux with values from + // // FispactProblem's _photon_fluxes + // _photon_fluxes = + // BoostIpVector(photon_flux.begin(), photon_flux.end(), _vec_alloc); + // + // _elem_strength = + // BoostIpVector(elem_strengths.begin(), elem_strengths.end(), + // _vec_alloc); + // + // _photon_bins = + // BoostIpVector(photon_bins.begin(), photon_bins.end(), _vec_alloc); + // + // for (auto &[global_elem_id, local_elem_id] : local_element_idx_map) { + // + // _local_elem_idx_map.insert( + // std::pair(global_elem_id, local_elem_id)); + // } + // } + + PhotonSharingData(bi::managed_shared_memory &segment) + : _is_setup(false), _vec_alloc(segment.get_segment_manager()), + _int_int_map_alloc(segment.get_segment_manager()), + _int_doub_map_alloc(segment.get_segment_manager()), + _photon_fluxes(_vec_alloc), _elem_strength(_vec_alloc), + _photon_bins(_vec_alloc), _local_elem_idx_map(_int_int_map_alloc) {} + + void setPhotonSpectra(const std::vector::iterator spectra_begin, + const std::vector::iterator spectra_end) { + + _photon_fluxes.assign(spectra_begin, spectra_end); + } + + void + setElementStrengths(const std::vector::iterator elem_strength_begin, + const std::vector::iterator elem_strength_end) { + _elem_strength.assign(elem_strength_begin, elem_strength_end); + } + + void setPhotonBins(const std::vector &photon_bins) { + _photon_bins.assign(photon_bins.begin(), photon_bins.end()); + } + + void setNumPhotonBins(const size_t &n_photon_bins) { + _num_photon_bins = n_photon_bins; + } + + void setNumLocalElems(const size_t &n_local_elems) { + _num_local_elems = n_local_elems; + } + + void setLocalDomainStrength(const double &local_domain_strength) { + _local_domain_strength = local_domain_strength; + } + + void setTotalDomainStrength(const double &total_domain_strength) { + _total_domain_strength = total_domain_strength; + } + + void setLocalElemIdMap( + std::unordered_map &local_element_idx_map) { + + for (auto &[global_elem_id, local_elem_id] : local_element_idx_map) { + + _local_elem_idx_map.insert( + std::pair(global_elem_id, local_elem_id)); + } + } + + void setSamplingMethod(bool uniform = false) { _uniform = uniform; } + + size_t _num_photon_bins; + size_t _num_local_elems; + double _local_domain_strength; + double _total_domain_strength; + + bool _is_setup; + bool _uniform; + + /// Allocators + ShmemVecAllocator _vec_alloc; + ShmemIntIntMapAllocator _int_int_map_alloc; + ShmemIntDoubMapAllocator _int_doub_map_alloc; + + /// Data structures + BoostIpVector _photon_fluxes; + BoostIpVector _elem_strength; + BoostIpVector _photon_bins; + + BoostIpIntIntMap _local_elem_idx_map; +}; + +#endif diff --git a/include/utils/PhotonSpectra.h b/include/utils/PhotonSpectra.h new file mode 100644 index 0000000..7c98cf0 --- /dev/null +++ b/include/utils/PhotonSpectra.h @@ -0,0 +1,52 @@ +#include +#include + +class PhotonSpectra { +public: + PhotonSpectra(size_t nt, size_t ne, size_t nb) + : _nt(nt), _ne(ne), _nb(nb), _data(_nt * _ne * _nb, 0) {} + + /// Accessors + // Scalar data accessor + double &at(size_t t, size_t e, size_t b) { return _data.at(idx(t, e, b)); } + + const double &at(size_t t, size_t e, size_t b) const { + return _data.at(idx(t, e, b)); + } + + // Single element spectrum at time + std::vector::iterator spectrum_begin(size_t t, size_t e) { + return _data.begin() + idx(t, e, 0); + } + + std::vector::iterator spectrum_end(size_t t, size_t e) { + return spectrum_begin(t, e) + _nb; + } + + // Entire spectrum at time + std::vector::iterator time_begin(size_t t) { + return _data.begin() + idx(t, 0, 0); + } + std::vector::iterator time_end(size_t t) { + return time_begin(t) + (_ne * _nb); + } + + // Data accessors for debugging + std::vector &data() { return _data; }; + double *data_buffer() { return _data.data(); } + +private: + size_t idx(size_t t, size_t e, size_t b) const { + + // dbg checks + assert(t < _nt); + assert(e < _ne); + assert(b < _nb); + + return (t * _nb * _ne) + (e * _nb) + b; + } + + /// Number of timesteps, number of elements, number of bins + size_t _nt, _ne, _nb; + std::vector _data; +}; diff --git a/include/vectorpostprocessors/FispactVectorPostprocessor.h b/include/vectorpostprocessors/FispactVectorPostprocessor.h new file mode 100644 index 0000000..2189599 --- /dev/null +++ b/include/vectorpostprocessors/FispactVectorPostprocessor.h @@ -0,0 +1,24 @@ +#pragma once +#include "FispactProblem.h" +#include "GeneralVectorPostprocessor.h" + +class FispactVectorPostprocessor : public GeneralVectorPostprocessor { + +public: + static InputParameters validParams() { + InputParameters params = GeneralVectorPostprocessor::validParams(); + return params; + }; + + FispactVectorPostprocessor(const InputParameters ¶ms); + + virtual void initialize() = 0; + virtual void execute() = 0; + virtual void finalize() = 0; + + FispactProblem &getFispactProblem() { return _fispact_problem; } + + size_t getFispactInventoryIdx(); + + FispactProblem &_fispact_problem; +}; diff --git a/include/vectorpostprocessors/SubdomainPhotonEmissionSpectraPostprocessor.h b/include/vectorpostprocessors/SubdomainPhotonEmissionSpectraPostprocessor.h new file mode 100644 index 0000000..0648d08 --- /dev/null +++ b/include/vectorpostprocessors/SubdomainPhotonEmissionSpectraPostprocessor.h @@ -0,0 +1,21 @@ +#pragma once +#include "BlockRestrictable.h" +#include "FispactVectorPostprocessor.h" +#include "InputParameters.h" +#include "MooseTypes.h" + +class SubdomainPhotonEmissionSpectraPostprocessor + : public FispactVectorPostprocessor, + public BlockRestrictable { +public: + static InputParameters validParams(); + + SubdomainPhotonEmissionSpectraPostprocessor(const InputParameters ¶ms); + + virtual void initialize(); + virtual void execute(); + virtual void finalize(); + +protected: + VectorPostprocessorValue &_photon_emission_spectra; +}; diff --git a/inputs/cardinal_multiapp/fispact_cardinal.i b/inputs/cardinal_multiapp/fispact_cardinal.i new file mode 100644 index 0000000..6a50ade --- /dev/null +++ b/inputs/cardinal_multiapp/fispact_cardinal.i @@ -0,0 +1,67 @@ +[Mesh] + [fmg] + type = FileMeshGenerator + file = "../../example_geom/cube.e" + [] +[] + +[AuxVariables] + [Photon_flux] + family = MONOMIAL + order = CONSTANT + [] +[] + + +[Problem] + type = FispactProblem + fispact_nuclear_data_path = '/home/bill/Projects/FISPACT/nuclear_data/' + + neutron_flux_file = '/home/bill/Projects/PyFIS/cube_example/neutron_cube/statepoint.2.h5' + neutron_flux_tally_id = 1 + neutron_bin_type = 'G1102' + write_photon_flux = True + photon_flux_filename = 'photon_spectra_out' + comm_photon_flux = True + + fispact_schedule_uo = 'Schedule' + + read_materials_from_xml = True + materials_xml_file = '/home/bill/Projects/fizzy/materials.xml' +[] + +[UserObjects] + [Schedule] + type = FispactSchedule + times = '300 30 30 30 30 30' + flux_schedule = '1e10 0 0 0 0 0' + [] +[] + +[MultiApps] + [Cardinal] + type = FullSolveMultiApp + execute_on = timestep_end + app_type = 'CardinalApp' + input_files = '/home/bill/Projects/cardinal-fispact/inputs/compiled_source/card_input.i' + library_path = '/home/bill/Projects/cardinal-fispact/lib/' + library_name = 'libcardinal-opt.la' + [] +[] + +[Transfers] + [Photon_flux_from_cardinal] + type = MultiAppCopyTransfer + source_variable = 'photon_flux_photon' + variable = Photon_flux + from_multi_app='Cardinal' + [../] +[] + +[Executioner] + type = Steady +[] + +[Outputs] + exodus = True +[] diff --git a/inputs/fispact_in.i b/inputs/fispact_in.i index d82f071..67ac5ec 100644 --- a/inputs/fispact_in.i +++ b/inputs/fispact_in.i @@ -1,18 +1,29 @@ [Mesh] [fmg] type = FileMeshGenerator - file = "../librti-tets-scaled.e" + file = "../example_geom/cube.e" [] [] +[AuxVariables] + [Photon_flux] + family = MONOMIAL + order = CONSTANT + [] +[] + + [Problem] type = FispactProblem fispact_nuclear_data_path = '/home/bill/Projects/FISPACT/nuclear_data/' - neutron_flux_file = '/home/bill/Projects/PyFIS/statepoint.3.h5' - neutron_flux_hdf5_path = 'tallies/tally 1/results' + neutron_flux_file = '/home/bill/Projects/PyFIS/cube_example/neutron_cube/statepoint.2.h5' + neutron_flux_tally_id = 1 neutron_bin_type = 'G1102' - + write_photon_flux = True + photon_flux_filename = 'photon_spectra_test.h5' + comm_photon_flux = True + fispact_schedule_uo = 'Schedule' read_materials_from_xml = True @@ -31,3 +42,7 @@ [Executioner] type = Steady [] + +[Outputs] + exodus = True +[] diff --git a/inputs/material_tests/fispact_fuel.i b/inputs/material_tests/fispact_fuel.i new file mode 100644 index 0000000..9d9fb9e --- /dev/null +++ b/inputs/material_tests/fispact_fuel.i @@ -0,0 +1,164 @@ +[Mesh] + [fmg] + type = FileMeshGenerator + file = "../../geometry/cube.e" + [] +[] + +[Problem] + type = FispactProblem + + write_photon_flux = True + photon_flux_filename = 'photon_spectra_out' + + molar_mass_data = '../../molar_masses.h5' + + output_inventory_time = 1e5 + + fispact_schedule_uo = 'Schedule' + fispact_nuclear_data_uo = 'endf_nuclear_data' + fispact_input_flux_uo = 'InputFlux' + + atol = 1e-1 + rtol = 1e-1 +[] + +[AuxVariables] + [B10_atoms] + family = MONOMIAL + order = CONSTANT + [] + [Nb93_atoms] + family = MONOMIAL + order = CONSTANT + [] + [atoms] + family = MONOMIAL + order = CONSTANT + [] +[] + +[AuxKernels] + [B10_atoms_kernel] + type = FispactNuclideKernel + variable = B10_atoms + nuclide = "B10" + metric = "ATOMS" + [] + [B12_atoms_kernel] + type = FispactNuclideKernel + variable = Nb93_atoms + nuclide = "Nb93" + metric = "ATOMS" + [] + [atoms_kernel] + type = FispactElementKernel + variable = atoms + metric = "INVENTORY_TOTAL_ATOMS" + [] +[] + +[UserObjects] + [InputFlux] + type = OpenMCFluxInput + statepoint_filename = './statepoint_neutrons.10.h5' + energy_filter_id = 2 + flux_tally_id = 2 + wall_loading = 10 + [] + + [Schedule] + type = FispactSchedule + times = '1e5 1e4 1e4 2e5 2e5 2e5 5e5 5e5 2e5' + flux_amplitude = '1e10 0 0 0 0 0 0 0 0' + [] + + [steel] + type = FispactMaterial + material_type = FUEL + nuclides = "B10 B11 C12 C13 Si28 V50 V51 Cr50 Cr52 Cr53 Cr54 Mn55 Fe54 Fe56 Fe57 Fe58 Co59 Ni58 Ni60 Ni61 Ni62 Ni64 Mo92 Mo94 Mo95 Mo96 Mo97 Mo98 Mo100 Cu63 Cu65" + nuclide_fraction = "0.00000693 0.0000281 0.000395203 0.00000479726 0.0047 0.00000392193 0.00159608 0.0073 0.1407 0.016 0.004 0.0114 0.0395 0.6251 0.0146 0.002 0.0014 0.0731 0.0279 0.0012 0.0038 0.001 0.00297476 0.00190616 0.00332850 0.00353305 0.00205165 0.00525492 0.00215096 0.0006 0.0003" + fraction_type = 'wo' + density_units = 'g/cm3' + block = 1 + density = 8 + [] + + [endf_nuclear_data] + type = FispactNuclearDataPaths + base_path = "/home/bill/Projects/FispactNuclearData/" + ND_IND_NUC_KEY = "ENDFB80data/endfb80_index" + #ND_XS_ENDF_KEY = "ENDFB80data/endfb80-n/gxs-709" + ND_XS_ENDFB_KEY = "endfb80-n.bin" + ND_FY_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80nfy" + ND_SF_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80sfy" + ND_DK_ENDF_KEY = "ENDFB80data/decay" + ND_ABSORP_KEY = "decay/abs_2012" + [] + + + + [cendl_nuclear_data] + type = FispactNuclearDataPaths + base_path = "/home/bill/Projects/FispactNuclearData/" + ND_IND_NUC_KEY = "decay_2020_index.txt" + ND_XS_ENDF_KEY = "CENDL32data/gendf-1102" + #ND_XS_ENDFB_KEY = "CENDL-n.bin" + ND_FY_ENDF_KEY = "GEFY61data/gefy61_nfy" + ND_SF_ENDF_KEY = "GEFY61data/gefy61_sfy" + ND_PROB_TAB_KEY = "CENDL32data/tp-1102-294" + ND_DK_ENDF_KEY = "decay_2020" + ND_ABSORP_KEY = "decay/abs_2012" + [] +[] + +[Postprocessors] + [photon_emission] + type = ElementPhotonEmission + element_ids = '0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47' + [] + + [nuclide_contribution] + type = NuclideMetric + nuclides = "Cr51" + metric = "DOSE" + [] + +[] + +[VectorPostprocessors] + [PhotonEmissionAllBlocks] + [] +[] + +[Times] + [FizzyTimes] + type = FispactScheduleTimes + FispactScheduleName = Schedule +# FispactScheduleTimeIndices = '0 1' + + [] +[] + +[Executioner] + #type = Steady + + type = Transient + + [TimeStepper] + type = TimeSequenceFromTimes + times = FizzyTimes + use_last_t_for_end_time = True + [] +[] + +[Outputs] + [CSV] + type = CSV + [] + exodus = true +[] + + + + diff --git a/inputs/material_tests/fispact_mass.i b/inputs/material_tests/fispact_mass.i new file mode 100644 index 0000000..f11757a --- /dev/null +++ b/inputs/material_tests/fispact_mass.i @@ -0,0 +1,54 @@ +[Mesh] + [fmg] + type = FileMeshGenerator + file = "../../geometry/cube.e" + [] +[] + +[Problem] + type = FispactProblem + + neutron_flux_file = './statepoint_neutrons.10.h5' + neutron_flux_tally_id = 2 + neutron_bin_structure = 1102 + + write_photon_flux = True + photon_flux_filename = 'photon_spectra_out' + + molar_mass_data = '../../molar_masses.h5' + + fispact_schedule_uo = 'Schedule' + fispact_nuclear_data_uo = 'endf_nuclear_data' +[] + +[UserObjects] + [Schedule] + type = FispactSchedule + times = '300 30 30 30 30 30' + flux_amplitude = '1e10 0 0 0 0 0' + [] + + [steel] + type = FispactMaterial + material_type = MASS + nuclides = 'Fe Mo' + nuclide_fraction = '0.7 0.3' + block = 'steel' + density = 5 + [] + [endf_nuclear_data] + type = FispactNuclearDataPaths + base_path = "/Projects/FispactNuclearData/" + ND_IND_NUC_KEY = "ENDFB80data/endfb80_index" + #ND_XS_ENDF_KEY = "ENDFB80data/endfb80-n/gxs-709" + ND_XS_ENDFB_KEY = "endfb80-n.bin" + ND_FY_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80nfy" + ND_SF_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80sfy" + ND_DK_ENDF_KEY = "ENDFB80data/decay" + ND_ABSORP_KEY = "decay/abs_2012" + [] +[] + +[Executioner] + type = Steady +[] diff --git a/inputs/material_tests/photon_spectra_out b/inputs/material_tests/photon_spectra_out new file mode 100644 index 0000000..fddb5c1 Binary files /dev/null and b/inputs/material_tests/photon_spectra_out differ diff --git a/inputs/material_tests/statepoint_neutrons.10.h5 b/inputs/material_tests/statepoint_neutrons.10.h5 new file mode 100644 index 0000000..193fd89 Binary files /dev/null and b/inputs/material_tests/statepoint_neutrons.10.h5 differ diff --git a/inputs/r2s_multiapp/fispact_r2s.i b/inputs/r2s_multiapp/fispact_r2s.i new file mode 100644 index 0000000..0357570 --- /dev/null +++ b/inputs/r2s_multiapp/fispact_r2s.i @@ -0,0 +1,101 @@ +[Mesh] + [fmg] + type = FileMeshGenerator + file = "../../geometry/cube.e" + [] +[] + +[AuxVariables] + [Photon_flux] + family = MONOMIAL + order = CONSTANT + [] +[] + + +[Problem] + type = FispactProblem + output_inventory_time = 450 + + write_photon_flux = True + photon_flux_filename = 'photon_spectra_out' + + comm_photon_flux = True + + molar_mass_data = '../../molar_masses.h5' + + fispact_schedule_uo = 'Schedule' + fispact_nuclear_data_uo = 'endf_nuclear_data' + fispact_input_flux_uo = 'InputFlux' +[] + +[UserObjects] + [InputFlux] + type = OpenMCFluxInput + statepoint_filename = './statepoint_neutrons.10.h5' + energy_filter_id = 2 + flux_tally_id = 2 + wall_loading = 1 + [] + + [Schedule] + type = FispactSchedule + times = '300 30 30 30 30 30' + flux_amplitude = '1e10 0 0 0 0 0' + [] + + [steel] + type = FispactMaterial + material_type = FUEL + nuclides = "B10 B11 C12 C13 Si28 V50 V51 Cr50 Cr52 Cr53 Cr54 Mn55 Fe54 Fe56 Fe57 Fe58 Co59 Ni58 Ni60 Ni61 Ni62 Ni64 Mo92 Mo94 Mo95 Mo96 Mo97 Mo98 Mo100 Cu63 Cu65" + nuclide_fraction = "0.000693 0.002807 0.039520273803427465 0.000479726196572539 0.47 0.0003921925373160739 0.15960780746268394 0.73 14.07 1.6 0.4 1.14 3.95 62.51 1.46 0.2 0.14 7.31 2.79 0.12 0.38 0.1 0.2974760972643644 0.1906159496693566 0.33284984504744625 0.3533051306488447 0.20516502475964524 0.5254922939545649 0.21509565865577795 0.06 0.03" + block = 1 + density = 8 + [] + + [endf_nuclear_data] + type = FispactNuclearDataPaths + base_path = "/Projects/FispactNuclearData/" + ND_IND_NUC_KEY = "ENDFB80data/endfb80_index" + #ND_XS_ENDF_KEY = "ENDFB80data/endfb80-n/gxs-709" + ND_XS_ENDFB_KEY = "endfb80-n.bin" + ND_FY_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80nfy" + ND_SF_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80sfy" + ND_DK_ENDF_KEY = "ENDFB80data/decay" + ND_ABSORP_KEY = "decay/abs_2012" + [] +[] + +[MultiApps] + [photons] + type = FullSolveMultiApp + execute_on = timestep_end + app_type = 'CardinalApp' + input_files = '/Projects/Fizzy/inputs/r2s_multiapp/photons_input.i' + library_path = '/Projects/cardinal/lib/' + library_name = 'libcardinal-opt.la' + [] +[] + +[Transfers] + [Photon_flux_from_cardinal] + type = MultiAppCopyTransfer + source_variable = 'photon_flux_photon' + variable = Photon_flux + from_multi_app='photons' + [../] +[] + +[Executioner] + type = Steady +[] + +[Outputs] + exodus = True +[] + + + + + + diff --git a/inputs/r2s_multiapp/geometry/cube_hex.e b/inputs/r2s_multiapp/geometry/cube_hex.e new file mode 100644 index 0000000..52d148f Binary files /dev/null and b/inputs/r2s_multiapp/geometry/cube_hex.e differ diff --git a/inputs/r2s_multiapp/geometry/cube_hex_dag.h5m b/inputs/r2s_multiapp/geometry/cube_hex_dag.h5m new file mode 100644 index 0000000..472afae Binary files /dev/null and b/inputs/r2s_multiapp/geometry/cube_hex_dag.h5m differ diff --git a/inputs/r2s_multiapp/neutrons_input.i b/inputs/r2s_multiapp/neutrons_input.i new file mode 100644 index 0000000..024de30 --- /dev/null +++ b/inputs/r2s_multiapp/neutrons_input.i @@ -0,0 +1,38 @@ +[Mesh] + type = FileMesh + file = "../../geometry/cube.e" +[] + +[Problem] + type = OpenMCCellAverageProblem + cell_level = 0 + source_strength = 1 + xml_directory = './neutrons_xml' + [Tallies] + [neutron_flux] + type = MeshTally + filters = 'neutron_filter energy_filter' + name = 'neutron_flux' + score = 'flux' + [] + [] + + [Filters] + [neutron_filter] + type = ParticleFilter + particles = 'neutron' + [] + [energy_filter] + type = EnergyFilter + group_structure = UKAEA_1102 + [] + [] +[] + +[Executioner] + type = Steady +[] + +[Outputs] + exodus = True +[] diff --git a/inputs/r2s_multiapp/neutrons_xml/geometry.xml b/inputs/r2s_multiapp/neutrons_xml/geometry.xml new file mode 100644 index 0000000..e0fd09d --- /dev/null +++ b/inputs/r2s_multiapp/neutrons_xml/geometry.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/inputs/r2s_multiapp/neutrons_xml/materials.xml b/inputs/r2s_multiapp/neutrons_xml/materials.xml new file mode 100644 index 0000000..3f15a45 --- /dev/null +++ b/inputs/r2s_multiapp/neutrons_xml/materials.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputs/r2s_multiapp/neutrons_xml/settings.xml b/inputs/r2s_multiapp/neutrons_xml/settings.xml new file mode 100644 index 0000000..c9972be --- /dev/null +++ b/inputs/r2s_multiapp/neutrons_xml/settings.xml @@ -0,0 +1,26 @@ + + + fixed source + 500000 + 10 + 0 + + + + -50.0 50.0 0.0 1.0 + + + + + + 14080000.0 1.0 + + + + false + false + + ttb + continuous-energy + 1000 + diff --git a/inputs/r2s_multiapp/photons_input.i b/inputs/r2s_multiapp/photons_input.i new file mode 100644 index 0000000..8c86c72 --- /dev/null +++ b/inputs/r2s_multiapp/photons_input.i @@ -0,0 +1,31 @@ +[Mesh] + type = FileMesh + file = "../..//geometry/cube.e" +[] + +[Problem] + type = OpenMCCellAverageProblem + cell_level = 0 + source_strength = 1 + xml_directory = './photons_xml/' + [Tallies] + [photon_flux] + type = MeshTally + filters = 'Photon' + name = 'photon_flux' + score = 'flux' + [] + [] + + [Filters] + [Photon] + type = ParticleFilter + particles = 'photon' + [] + [] +[] + +[Executioner] + type = Steady +[] + diff --git a/inputs/r2s_multiapp/photons_xml/geometry.xml b/inputs/r2s_multiapp/photons_xml/geometry.xml new file mode 100644 index 0000000..e0fd09d --- /dev/null +++ b/inputs/r2s_multiapp/photons_xml/geometry.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/inputs/r2s_multiapp/photons_xml/materials.xml b/inputs/r2s_multiapp/photons_xml/materials.xml new file mode 100644 index 0000000..3f15a45 --- /dev/null +++ b/inputs/r2s_multiapp/photons_xml/materials.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputs/r2s_multiapp/photons_xml/settings.xml b/inputs/r2s_multiapp/photons_xml/settings.xml new file mode 100644 index 0000000..0bc98f1 --- /dev/null +++ b/inputs/r2s_multiapp/photons_xml/settings.xml @@ -0,0 +1,16 @@ + + + fixed source + 500000 + 5 + 0 + + + false + false + + ttb + continuous-energy + true + 10000 + diff --git a/inputs/r2s_multiapp/statepoint_neutrons.10.h5 b/inputs/r2s_multiapp/statepoint_neutrons.10.h5 new file mode 100644 index 0000000..193fd89 Binary files /dev/null and b/inputs/r2s_multiapp/statepoint_neutrons.10.h5 differ diff --git a/inputs/r2s_time/fispact_r2s_time.i b/inputs/r2s_time/fispact_r2s_time.i new file mode 100644 index 0000000..7ab08d9 --- /dev/null +++ b/inputs/r2s_time/fispact_r2s_time.i @@ -0,0 +1,141 @@ +[Mesh] + [fmg] + type = FileMeshGenerator + file = "../../geometry/cube.e" + [] +[] + +[AuxVariables] + [Photon_flux] + family = MONOMIAL + order = CONSTANT + [] +[] + + +[Problem] + type = FispactProblem + + write_photon_flux = True + photon_flux_filename = 'photon_spectra_out' + + comm_photon_flux = True + + molar_mass_data = '../../molar_masses.h5' + + fispact_schedule_uo = 'Schedule' + fispact_nuclear_data_uo = 'endf_nuclear_data' + fispact_input_flux_uo = 'InputFlux' +[] + +[UserObjects] + [InputFlux] + type = OpenMCFluxInput + statepoint_filename = './statepoint_neutrons.10.h5' + energy_filter_id = 2 + flux_tally_id = 2 + wall_loading = 1 + [] + + [Schedule] + type = FispactSchedule + times = '300 30 30 30 30 30' + flux_amplitude = '1e10 0 0 0 0 0' + [] + + [steel] + type = FispactMaterial + material_type = FUEL + nuclides = "B10 B11 C12 C13 Si28 V50 V51 Cr50 Cr52 Cr53 Cr54 Mn55 Fe54 Fe56 Fe57 Fe58 Co59 Ni58 Ni60 Ni61 Ni62 Ni64 Mo92 Mo94 Mo95 Mo96 Mo97 Mo98 Mo100 Cu63 Cu65" + nuclide_fraction = "0.000693 0.002807 0.039520273803427465 0.000479726196572539 0.47 0.0003921925373160739 0.15960780746268394 0.73 14.07 1.6 0.4 1.14 3.95 62.51 1.46 0.2 0.14 7.31 2.79 0.12 0.38 0.1 0.2974760972643644 0.1906159496693566 0.33284984504744625 0.3533051306488447 0.20516502475964524 0.5254922939545649 0.21509565865577795 0.06 0.03" + block = 1 + density = 8 + [] + + [endf_nuclear_data] + type = FispactNuclearDataPaths + base_path = "/Projects/FispactNuclearData/" + ND_IND_NUC_KEY = "ENDFB80data/endfb80_index" + #ND_XS_ENDF_KEY = "ENDFB80data/endfb80-n/gxs-709" + ND_XS_ENDFB_KEY = "endfb80-n.bin" + ND_FY_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80nfy" + ND_SF_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80sfy" + ND_DK_ENDF_KEY = "ENDFB80data/decay" + ND_ABSORP_KEY = "decay/abs_2012" + [] + + [cendl_nuclear_data] + type = FispactNuclearDataPaths + base_path = "/Projects/FispactNuclearData/" + ND_IND_NUC_KEY = "decay2020/decay_2020_index.txt" + #ND_XS_ENDF_KEY = "CENDL32data/gendf-1102" + ND_XS_ENDFB_KEY = "CENDL-n.bin" + ND_FY_ENDF_KEY = "GEFY61data/gefy61_nfy" + ND_SF_ENDF_KEY = "GEFY61data/gefy61_sfy" + ND_PROB_TAB_KEY = "CENDL32data/tp-1102-294" + ND_DK_ENDF_KEY = "decay2020/decay_2020" + ND_ABSORP_KEY = "decay/abs_2012" + [] + [tendl_nuclear_data] + type = FispactNuclearDataPaths + base_path = "/home/Projects/FispactNuclearData/" + ND_IND_NUC_KEY = "TENDL2017data/tendl17_decay12_index" + #ND_XS_ENDF_KEY = "TENDL2017data/tal2017-n/gxs-709" + ND_XS_ENDFB_KEY = "TENDL-n.bin" + ND_FY_ENDF_KEY = "GEFY61data/gefy61_nfy" + ND_SF_ENDF_KEY = "GEFY61data/gefy61_sfy" + ND_PROB_TAB_KEY = "TENDL2017data/tal2017-n/tp-709-294" + ND_DK_ENDF_KEY = "decay2020/decay_2020" + ND_ABSORP_KEY = "decay/abs_2012" + [] +[] + +[MultiApps] + [photons] + type = TransientMultiApp + execute_on = timestep_end + app_type = 'CardinalApp' + input_files = '/Projects/Fizzy/inputs/r2s_time/photons_input.i' + library_path = '/Projects/cardinal/lib/' + library_name = 'libcardinal-opt.la' + [] +[] + +[Transfers] + [Photon_flux_from_cardinal] + type = MultiAppCopyTransfer + source_variable = 'photon_flux_photon' + variable = Photon_flux + from_multi_app='photons' + [../] +[] + +[Times] + [FizzyTimes] + type = FispactScheduleTimes + FispactScheduleName = Schedule +# FispactScheduleTimeIndices = '0 1' + + [] +[] + +[Executioner] + + type = Transient + + [TimeStepper] + type = TimeSequenceFromTimes + times = FizzyTimes + use_last_t_for_end_time = True + [] +[] + +[Outputs] + exodus = True +[] + + + + + + diff --git a/inputs/r2s_time/neutrons_input.i b/inputs/r2s_time/neutrons_input.i new file mode 100644 index 0000000..024de30 --- /dev/null +++ b/inputs/r2s_time/neutrons_input.i @@ -0,0 +1,38 @@ +[Mesh] + type = FileMesh + file = "../../geometry/cube.e" +[] + +[Problem] + type = OpenMCCellAverageProblem + cell_level = 0 + source_strength = 1 + xml_directory = './neutrons_xml' + [Tallies] + [neutron_flux] + type = MeshTally + filters = 'neutron_filter energy_filter' + name = 'neutron_flux' + score = 'flux' + [] + [] + + [Filters] + [neutron_filter] + type = ParticleFilter + particles = 'neutron' + [] + [energy_filter] + type = EnergyFilter + group_structure = UKAEA_1102 + [] + [] +[] + +[Executioner] + type = Steady +[] + +[Outputs] + exodus = True +[] diff --git a/inputs/r2s_time/neutrons_xml/geometry.xml b/inputs/r2s_time/neutrons_xml/geometry.xml new file mode 100644 index 0000000..e0fd09d --- /dev/null +++ b/inputs/r2s_time/neutrons_xml/geometry.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/inputs/r2s_time/neutrons_xml/materials.xml b/inputs/r2s_time/neutrons_xml/materials.xml new file mode 100644 index 0000000..3f15a45 --- /dev/null +++ b/inputs/r2s_time/neutrons_xml/materials.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputs/r2s_time/neutrons_xml/settings.xml b/inputs/r2s_time/neutrons_xml/settings.xml new file mode 100644 index 0000000..c9972be --- /dev/null +++ b/inputs/r2s_time/neutrons_xml/settings.xml @@ -0,0 +1,26 @@ + + + fixed source + 500000 + 10 + 0 + + + + -50.0 50.0 0.0 1.0 + + + + + + 14080000.0 1.0 + + + + false + false + + ttb + continuous-energy + 1000 + diff --git a/inputs/r2s_time/photons_input.i b/inputs/r2s_time/photons_input.i new file mode 100644 index 0000000..8ec2b43 --- /dev/null +++ b/inputs/r2s_time/photons_input.i @@ -0,0 +1,32 @@ +[Mesh] + type = FileMesh + file = "../../geometry/cube.e" +[] + +[Problem] + type = OpenMCCellAverageProblem + cell_level = 0 + source_strength = 1 + xml_directory = './photons_xml/' + [Tallies] + [photon_flux] + type = MeshTally + filters = 'Photon' + name = 'photon_flux' + score = 'flux' + [] + [] + + [Filters] + [Photon] + type = ParticleFilter + particles = 'photon' + [] + [] +[] + +[Executioner] + type = Transient + dt = 1e7 +[] + diff --git a/inputs/r2s_time/photons_xml/geometry.xml b/inputs/r2s_time/photons_xml/geometry.xml new file mode 100644 index 0000000..e0fd09d --- /dev/null +++ b/inputs/r2s_time/photons_xml/geometry.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/inputs/r2s_time/photons_xml/materials.xml b/inputs/r2s_time/photons_xml/materials.xml new file mode 100644 index 0000000..3f15a45 --- /dev/null +++ b/inputs/r2s_time/photons_xml/materials.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputs/r2s_time/photons_xml/settings.xml b/inputs/r2s_time/photons_xml/settings.xml new file mode 100644 index 0000000..5732359 --- /dev/null +++ b/inputs/r2s_time/photons_xml/settings.xml @@ -0,0 +1,16 @@ + + + fixed source + 100000 + 5 + 0 + + + false + false + + ttb + continuous-energy + true + 10000 + diff --git a/inputs/r2s_time/statepoint_neutrons.10.h5 b/inputs/r2s_time/statepoint_neutrons.10.h5 new file mode 100644 index 0000000..7669729 Binary files /dev/null and b/inputs/r2s_time/statepoint_neutrons.10.h5 differ diff --git a/inputs/statepoint_neutrons.10.h5 b/inputs/statepoint_neutrons.10.h5 new file mode 100644 index 0000000..151e510 Binary files /dev/null and b/inputs/statepoint_neutrons.10.h5 differ diff --git a/inputs/time_dependent/transient_fispact.i b/inputs/time_dependent/transient_fispact.i new file mode 100644 index 0000000..4991908 --- /dev/null +++ b/inputs/time_dependent/transient_fispact.i @@ -0,0 +1,68 @@ +[Mesh] + [fmg] + type = FileMeshGenerator + file = "../../geometry/cube.e" + [] +[] + +[Problem] + type = FispactProblem + + neutron_flux_file = './../statepoint_neutrons.10.h5' + neutron_flux_tally_id = 1 + neutron_bin_type = 'G1102' + + write_photon_flux = True + photon_flux_filename = 'photon_spectra_out' + + molar_mass_data = '../../molar_masses.h5' + + fispact_schedule_uo = 'Schedule' + fispact_nuclear_data_uo = 'endf_nuclear_data' +[] + +[UserObjects] + [Schedule] + type = FispactSchedule + times = '300 30 30 30 30 30' + flux_schedule = '1e10 0 0 0 0 0' + [] + + [steel] + type = FISPACTMaterial + material_type = FUEL + nuclides = "C13 C12 Mn55 P31 S34 S32 S33 S36 Si28 Si29 Si30 Cr53 Cr50 Cr52 Cr54 Ni62 Ni60 Ni64 Ni58 Ni61 Fe56 Fe58 Fe57 Fe54" + nuclide_fraction = "1.5132548e-05 0.00135086745 0.01991 0.000795 2.14834688e-05 0.000486608589 3.8332928e-06 7.46496e-08 0.0179598856 0.000911951747 0.000601162667 0.0189874635 0.00868335215 0.167449803 0.00472638155 0.0033866271 0.0244346846 0.00086247408 0.0634340554 0.00106215882 0.610087944 0.00187506594 0.0140895912 0.0388643986" + block = 1 + density = 8 + [] + + [endf_nuclear_data] + type = FispactNuclearDataPaths + base_path = "/home/bill/Projects/FispactNuclearData/" + ND_IND_NUC_KEY = "ENDFB80data/endfb80_index" + ND_XS_ENDF_KEY = "ENDFB80data/endfb80-n/gxs-709" + ND_FY_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80nfy" + ND_SF_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80sfy" + ND_DK_ENDF_KEY = "ENDFB80data/decay" + ND_ABSORP_KEY = "decay/abs_2012" + [] +[] + +[Times] + [FizzyTimes] + type = FispactScheduleTimes + FispactScheduleName = Schedule + [] +[] + +[Executioner] + type = Transient + + [TimeStepper] + type = TimeSequenceFromTimes + times = FizzyTimes + use_last_t_for_end_time = True + [] + +[] diff --git a/inputs/xml_material_test/materials.xml b/inputs/xml_material_test/materials.xml new file mode 100644 index 0000000..3f15a45 --- /dev/null +++ b/inputs/xml_material_test/materials.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inputs/xml_material_test/statepoint_neutrons.10.h5 b/inputs/xml_material_test/statepoint_neutrons.10.h5 new file mode 100644 index 0000000..193fd89 Binary files /dev/null and b/inputs/xml_material_test/statepoint_neutrons.10.h5 differ diff --git a/inputs/xml_material_test/xml_materials.i b/inputs/xml_material_test/xml_materials.i new file mode 100644 index 0000000..3d9248f --- /dev/null +++ b/inputs/xml_material_test/xml_materials.i @@ -0,0 +1,66 @@ +[Mesh] + [fmg] + type = FileMeshGenerator + file = "../../geometry/cube.e" + [] +[] + +[AuxVariables] + [Photon_flux] + family = MONOMIAL + order = CONSTANT + [] +[] + + +[Problem] + type = FispactProblem + neutron_flux_file = './statepoint_neutrons.10.h5' + neutron_flux_tally_id = 2 + neutron_bin_structure = 1102 + output_inventory_time = 450 + + read_materials_from_xml = True + materials_xml_file = "materials.xml" + + write_photon_flux = True + photon_flux_filename = 'photon_spectra_out' + + comm_photon_flux = True + + molar_mass_data = '../../molar_masses.h5' + + fispact_schedule_uo = 'Schedule' + fispact_nuclear_data_uo = 'endf_nuclear_data' +[] + +[UserObjects] + [Schedule] + type = FispactSchedule + times = '300 30 30 30 30 30' + flux_amplitude = '1e10 0 0 0 0 0' + [] + + [endf_nuclear_data] + type = FispactNuclearDataPaths + base_path = "/Projects/FispactNuclearData/" + ND_IND_NUC_KEY = "ENDFB80data/endfb80_index" + #ND_XS_ENDF_KEY = "ENDFB80data/endfb80-n/gxs-709" + ND_XS_ENDFB_KEY = "endfb80-n.bin" + ND_FY_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80nfy" + ND_SF_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80sfy" + ND_DK_ENDF_KEY = "ENDFB80data/decay" + ND_ABSORP_KEY = "decay/abs_2012" + [] +[] + +[Executioner] + type = Steady +[] + + + + + + + diff --git a/molar_masses.h5 b/molar_masses.h5 new file mode 100644 index 0000000..1901a72 Binary files /dev/null and b/molar_masses.h5 differ diff --git a/src/actions/AddInventoryManager.C b/src/actions/AddInventoryManager.C new file mode 100644 index 0000000..499b4a1 --- /dev/null +++ b/src/actions/AddInventoryManager.C @@ -0,0 +1,180 @@ +#include "ActionWarehouse.h" +#include "AddInventoryManager.h" +#include "AddKernelAction.h" +#include "Attributes.h" +#include "AuxKernel.h" +#include "AuxiliarySystem.h" +#include "FispactInventoryManager.h" +#include "FispactInventoryMetric.h" +#include "FispactNuclideMetric.h" +#include "FizzyEnums.h" +#include "InputParameters.h" +#include "MooseMeshUtils.h" +#include "MooseTypes.h" +#include "Registry.h" +#include + +registerMooseAction("FizzyApp", AddInventoryManager, "add_inventory_manager"); + +typedef std::pair> + NuclideMetricsBlocksPair; + +InputParameters AddInventoryManager::validParams() { + InputParameters params = Action::validParams(); + params.addClassDescription( + "A MOOSE action automating the inclusion of a FispactInventoryManager " + "when aux kernels and postprocessors requiring inventory quantities are " + "included in the input file."); + return params; +} + +AddInventoryManager::AddInventoryManager(const InputParameters ¶ms) + : Action(params) {} + +void AddInventoryManager::act() { + std::unordered_map> + nuclide_metrics; + + std::unordered_map> + element_metrics; + + // Get all aux kernels in simulation + const std::vector> aux_kernels = + _problem->getAuxiliarySystem().elemAuxWarehouse().getObjects(); + + // Get all postprocessors in simulation + std::vector postprocessors; + _problem->theWarehouse() + .query() + .condition(Interfaces::Postprocessor) + .queryInto(postprocessors); + + /// Add all auxiliary kernel requests for nuclide/inventory metrics + for (auto &aux_kernel : aux_kernels) { + const InputParameters ¶ms = aux_kernel->parameters(); + + std::set block_ids_set; + + if (aux_kernel->blocks().empty()) { + block_ids_set = _mesh->meshSubdomains(); + } else { + + std::vector block_names = aux_kernel->blocks(); + + std::vector block_ids = + MooseMeshUtils::getSubdomainIDs(*_mesh, block_names); + + block_ids_set = std::set(block_ids.begin(), block_ids.end()); + } + + if (params.get("_type") == "FispactNuclideKernel") { + + const nuclide_quantities::NuclideQuantitiesEnum &metric = + params.get("metric") + .getEnum(); + + const std::string &nuclide = params.get("nuclide"); + + nuclide_metrics[nuclide].push_back( + NuclideMetricsBlocksPair(metric, block_ids_set)); + } + + if (params.get("_type") == "FispactElementKernel") { + + const inventory_outputs::InventoryOutputsEnum &metric = + params.get("metric") + .getEnum(); + + element_metrics[metric] = block_ids_set; + } + } + + for (Postprocessor *postprocessor : postprocessors) { + + if (FispactNuclideMetric *fispact_postprocessor = + dynamic_cast(postprocessor)) { + + const InputParameters ¶ms = fispact_postprocessor->parameters(); + + std::set block_ids_set; + + if (fispact_postprocessor->blocks().empty()) { + block_ids_set = _mesh->meshSubdomains(); + } else { + std::vector block_names = + fispact_postprocessor->blocks(); + + std::vector block_ids = + MooseMeshUtils::getSubdomainIDs(*_mesh, block_names); + + block_ids_set = + std::set(block_ids.begin(), block_ids.end()); + } + + const nuclide_quantities::NuclideQuantitiesEnum &metric = + params.get("metric") + .getEnum(); + + const std::vector &nuclides = + params.get>("nuclides"); + + for (const std::string &nuclide : nuclides) { + + nuclide_metrics[nuclide].push_back( + NuclideMetricsBlocksPair(metric, block_ids_set)); + } + } + + if (FispactInventoryMetric *fispact_postprocessor = + dynamic_cast(postprocessor)) { + + const InputParameters ¶ms = fispact_postprocessor->parameters(); + + std::set block_ids_set; + + if (fispact_postprocessor->blocks().empty()) { + block_ids_set = _mesh->meshSubdomains(); + } else { + std::vector block_names = + fispact_postprocessor->blocks(); + + std::vector block_ids = + MooseMeshUtils::getSubdomainIDs(*_mesh, block_names); + + block_ids_set = + std::set(block_ids.begin(), block_ids.end()); + } + + const inventory_outputs::InventoryOutputsEnum &metric = + params.get("metric") + .getEnum(); + + element_metrics[metric] = block_ids_set; + } + } + + if (!(nuclide_metrics.empty() && element_metrics.empty())) { + InputParameters inventory_params = + _app.getFactory().getValidParams("FispactInventoryManager"); + _problem->addUserObject("FispactInventoryManager", "inv_manager", + inventory_params); + + FispactInventoryManager &inv_manager = + _problem->getUserObject("inv_manager"); + + for (auto &[nuclide, metric_block_pairs] : nuclide_metrics) { + for (NuclideMetricsBlocksPair &metric_block_pair : metric_block_pairs) { + + inv_manager.registerNuclideMetricRequest( + nuclide, metric_block_pair.first, metric_block_pair.second); + } + } + + for (auto &[metric, blocks] : element_metrics) { + + inv_manager.registerElementMetricRequest(metric, blocks); + } + } +} diff --git a/src/actions/AddPhotonSpectraVectorPPAllBlocks.C b/src/actions/AddPhotonSpectraVectorPPAllBlocks.C new file mode 100644 index 0000000..47bd618 --- /dev/null +++ b/src/actions/AddPhotonSpectraVectorPPAllBlocks.C @@ -0,0 +1,37 @@ +#include "AddPhotonSpectraVectorPPAllBlocks.h" +#include "InputParameters.h" +#include "MooseTypes.h" +#include "Registry.h" +#include "SubdomainPhotonEmissionSpectraPostprocessor.h" + +registerMooseAction("FizzyApp", AddPhotonSpectraVectorPPAllBlocks, + "add_vector_postprocessor"); + +InputParameters AddPhotonSpectraVectorPPAllBlocks::validParams() { + InputParameters params = Action::validParams(); + params.addClassDescription( + "A MOOSE action that adds a SubdomainPhotonEmissionSpectraPostprocessor " + "for all subdomains on the mesh. Useful when there are many subdomains, " + "for example you have a block representing each cell in a CSG geometry."); + return params; +} + +AddPhotonSpectraVectorPPAllBlocks::AddPhotonSpectraVectorPPAllBlocks( + const InputParameters ¶ms) + : Action(params) {} + +void AddPhotonSpectraVectorPPAllBlocks::act() { + for (SubdomainID block_id : _mesh->meshSubdomains()) { + const std::string &subdomain_name = _mesh->getSubdomainName(block_id); + + InputParameters vpp_params = + _factory.getValidParams("SubdomainPhotonEmissionSpectraPostprocessor"); + + vpp_params.set>("block") = {subdomain_name}; + + std::string vpp_name = subdomain_name + "_photon_emission_vpp"; + + _problem->addVectorPostprocessor( + "SubdomainPhotonEmissionSpectraPostprocessor", vpp_name, vpp_params); + } +} diff --git a/src/auxkernels/FispactElementKernel.C b/src/auxkernels/FispactElementKernel.C new file mode 100644 index 0000000..98b9ce4 --- /dev/null +++ b/src/auxkernels/FispactElementKernel.C @@ -0,0 +1,36 @@ +#include "FispactElementKernel.h" +#include "FispactProblem.h" +#include "FizzyEnums.h" +#include "InputParameters.h" +#include "Registry.h" + +registerMooseObject("FizzyApp", FispactElementKernel); + +InputParameters FispactElementKernel::validParams() { + InputParameters params = FispactAuxKernel::validParams(); + + params.addClassDescription("AuxKernel to calculate user defined inventory " + "metrics, for all nuclides in the inventory."); + + params.addRequiredParam("metric", getInventoryMetricsEnum(), + "Which metric should be tracked."); + + return params; +} + +FispactElementKernel::FispactElementKernel(const InputParameters ¶ms) + : FispactAuxKernel(params), + _metric(getParam("metric") + .getEnum()) {} + +Real FispactElementKernel::computeValue() { + const FispactInventoryManager &inv_manager = + getUserObjectByName("inv_manager"); + + FispactProblem &fis_problem = static_cast(_c_fe_problem); + + size_t inventory_idx = fis_problem.getFispactInventoryIndexFromTime(); + + return inv_manager.getElementMetric(_current_elem->id(), inventory_idx, + _metric); +} diff --git a/src/auxkernels/FispactNuclideKernel.C b/src/auxkernels/FispactNuclideKernel.C new file mode 100644 index 0000000..2d5acc1 --- /dev/null +++ b/src/auxkernels/FispactNuclideKernel.C @@ -0,0 +1,38 @@ +#include "FispactNuclideKernel.h" +#include "FispactProblem.h" +#include "InputParameters.h" +#include "Registry.h" + +registerMooseObject("FizzyApp", FispactNuclideKernel); + +InputParameters FispactNuclideKernel::validParams() { + InputParameters params = FispactAuxKernel::validParams(); + + params.addClassDescription( + "AuxKernel to calculate user defined nuclide inventory metrics."); + + params.addRequiredParam( + "nuclide", "Which nuclide should this kernel track."); + + params.addRequiredParam("metric", getNuclideMetricsEnum(), + "Which metric should be tracked."); + + return params; +} + +FispactNuclideKernel::FispactNuclideKernel(const InputParameters ¶ms) + : FispactAuxKernel(params), _nuclide(getParam("nuclide")), + _metric(getParam("metric") + .getEnum()) {} + +Real FispactNuclideKernel::computeValue() { + const FispactInventoryManager &inv_manager = + getUserObjectByName("inv_manager"); + + FispactProblem &fis_problem = static_cast(_c_fe_problem); + + size_t inventory_idx = fis_problem.getFispactInventoryIndexFromTime(); + + return inv_manager.getNuclideMetric(_current_elem->id(), _nuclide, + inventory_idx, _metric); +} diff --git a/src/base/FizzyApp.C b/src/base/FizzyApp.C index fc15f9f..32a16d8 100644 --- a/src/base/FizzyApp.C +++ b/src/base/FizzyApp.C @@ -1,51 +1,52 @@ -#include "FizzyApp.h" -#include "Moose.h" +#include "ActionFactory.h" #include "AppFactory.h" +#include "FizzyApp.h" #include "ModulesApp.h" +#include "Moose.h" #include "MooseSyntax.h" +#include "Registry.h" -InputParameters -FizzyApp::validParams() -{ +InputParameters FizzyApp::validParams() { InputParameters params = MooseApp::validParams(); params.set("use_legacy_material_output") = false; params.set("use_legacy_initial_residual_evaluation_behavior") = false; return params; } -FizzyApp::FizzyApp(InputParameters parameters) : MooseApp(parameters) -{ +FizzyApp::FizzyApp(InputParameters parameters) : MooseApp(parameters) { FizzyApp::registerAll(_factory, _action_factory, _syntax); } FizzyApp::~FizzyApp() {} -void -FizzyApp::registerAll(Factory & f, ActionFactory & af, Syntax & syntax) -{ +void FizzyApp::registerAll(Factory &f, ActionFactory &af, Syntax &syntax) { ModulesApp::registerAllObjects(f, af, syntax); Registry::registerObjectsTo(f, {"FizzyApp"}); Registry::registerActionsTo(af, {"FizzyApp"}); /* register custom execute flags, action syntax, etc. here */ + + registerTask("add_inventory_manager", true); + addTaskDependency("add_inventory_manager", "add_aux_kernel"); + addTaskDependency("add_inventory_manager", "add_user_object"); + + associateSyntaxInner(syntax, af); } -void -FizzyApp::registerApps() -{ - registerApp(FizzyApp); +void FizzyApp::associateSyntaxInner(Syntax &syntax, + ActionFactory &action_factory) { + registerSyntax("AddPhotonSpectraVectorPPAllBlocks", + "VectorPostprocessors/PhotonEmissionAllBlocks"); } +void FizzyApp::registerApps() { registerApp(FizzyApp); } + /*************************************************************************************************** - *********************** Dynamic Library Entry Points - DO NOT MODIFY ****************************** + *********************** Dynamic Library Entry Points - DO NOT MODIFY + ******************************* **************************************************************************************************/ -extern "C" void -FizzyApp__registerAll(Factory & f, ActionFactory & af, Syntax & s) -{ +extern "C" void FizzyApp__registerAll(Factory &f, ActionFactory &af, + Syntax &s) { FizzyApp::registerAll(f, af, s); } -extern "C" void -FizzyApp__registerApps() -{ - FizzyApp::registerApps(); -} +extern "C" void FizzyApp__registerApps() { FizzyApp::registerApps(); } diff --git a/src/base/FizzyEnums.C b/src/base/FizzyEnums.C new file mode 100644 index 0000000..20a83f5 --- /dev/null +++ b/src/base/FizzyEnums.C @@ -0,0 +1,17 @@ +#include "FizzyEnums.h" + +MooseEnum getInventoryMetricsEnum() { + return MooseEnum( + "INVENTORY_IRRAD_TIME INVENTORY_COOL_TIME INVENTORY_TOTAL_ACTIVITY " + "INVENTORY_ALPHA_ACTIVITY INVENTORY_BETA_ACTIVITY " + "INVENTORY_GAMMA_ACTIVITY INVENTORY_TOTAL_HEAT INVENTORY_ALPHA_HEAT " + "INVENTORY_BETA_HEAT INVENTORY_GAMMA_HEAT INVENTORY_TOTAL_MASS " + "INVENTORY_TOTAL_ATOMS INVENTORY_INGESTION INVENTORY_INHALATION " + "INVENTORY_FLUX_AMP INVENTORY_DOSE_RATE"); +} + +MooseEnum getNuclideMetricsEnum() { + return MooseEnum( + "ATOMS GRAMS ACTIVITY ALPHA_ACTIVITY BETA_ACTIVITY GAMMA_ACTIVITY " + "TOTAL_HEAT ALPHA_HEAT BETA_HEAT GAMMA_HEAT DOSE"); +} diff --git a/src/fispact/factory/FispactFactory.C b/src/fispact/factory/FispactFactory.C new file mode 100644 index 0000000..073507c --- /dev/null +++ b/src/fispact/factory/FispactFactory.C @@ -0,0 +1,15 @@ +#ifdef FIZZY_UNIT_TEST +#include "FispactContextMock.h" +#else +#include "FispactContext.h" +#endif + +#include "FispactFactory.h" + +std::unique_ptr createFispactContext() { +#ifdef FIZZY_UNIT_TEST + return std::make_unique(); +#else + return std::make_unique(); +#endif +} diff --git a/src/main.C b/src/main.C index 7ec4933..bf32fb2 100644 --- a/src/main.C +++ b/src/main.C @@ -7,12 +7,12 @@ //* Licensed under LGPL 2.1, please see LICENSE for details //* https://www.gnu.org/licenses/lgpl-2.1.html +#include "ActionFactory.h" #include "FizzyTestApp.h" #include "MooseMain.h" // Begin the main program. -int -main(int argc, char * argv[]) -{ +int main(int argc, char *argv[]) { + return Moose::main(argc, argv); } diff --git a/src/postprocessors/ElementPhotonEmission.C b/src/postprocessors/ElementPhotonEmission.C new file mode 100644 index 0000000..1380ec9 --- /dev/null +++ b/src/postprocessors/ElementPhotonEmission.C @@ -0,0 +1,54 @@ +#include "ElementPhotonEmission.h" +#include "FispactProblem.h" +#include + +registerMooseObject("FizzyApp", ElementPhotonEmission); + +InputParameters ElementPhotonEmission::validParams() { + + InputParameters params = GeneralPostprocessor::validParams(); + + params.addClassDescription("Postprocessor used to get the total photon " + "emission rate in photons/s from a " + "given set of elements."); + + params.addRequiredParam>( + "element_ids", + "Global ID's off all the elements to sum photon emission over."); + return params; +} + +ElementPhotonEmission::ElementPhotonEmission(const InputParameters ¶ms) + : FispactPostprocessor(params), + _element_ids(getParam>("element_ids")) {} + +void ElementPhotonEmission::initialize() { _sum = 0; } + +void ElementPhotonEmission::execute() { + + PhotonSpectra *spectra = getFispactProblem().getPhotonSpectra(); + + std::unordered_map &local_element_index = + getFispactProblem().getLocalElemIndexMap(); + + size_t inventory_index = + getFispactProblem().getFispactInventoryIndexFromTime() - 1; + + for (auto &elem_id : _element_ids) { + + if (getFispactProblem().mesh().elemPtr(elem_id)->processor_id() == + processor_id()) { + + std::vector::iterator begin = spectra->spectrum_begin( + inventory_index, local_element_index[elem_id]); + std::vector::iterator end = + spectra->spectrum_end(inventory_index, local_element_index[elem_id]); + + _sum += std::accumulate(begin, end, 0.0); + } + } +} + +void ElementPhotonEmission::finalize() { comm().sum(_sum); } + +PostprocessorValue ElementPhotonEmission::getValue() const { return _sum; } diff --git a/src/postprocessors/FispactElementPostprocessor.C b/src/postprocessors/FispactElementPostprocessor.C new file mode 100644 index 0000000..126a69d --- /dev/null +++ b/src/postprocessors/FispactElementPostprocessor.C @@ -0,0 +1,12 @@ +#include "ElementPostprocessor.h" +#include "FispactElementPostprocessor.h" +#include "FispactProblem.h" + +FispactElementPostprocessor::FispactElementPostprocessor( + const InputParameters ¶ms) + : ElementPostprocessor(params), + _fispact_problem(static_cast(_fe_problem)) {} + +FispactProblem &FispactElementPostprocessor::getFispactProblem() { + return _fispact_problem; +} diff --git a/src/postprocessors/FispactInventoryMetric.C b/src/postprocessors/FispactInventoryMetric.C new file mode 100644 index 0000000..83095a0 --- /dev/null +++ b/src/postprocessors/FispactInventoryMetric.C @@ -0,0 +1,73 @@ +#include "FispactElementPostprocessor.h" +#include "FispactInventoryManager.h" +#include "FispactInventoryMetric.h" +#include "FispactProblem.h" +#include "FizzyEnums.h" +#include "UserObject.h" +#include + +registerMooseObject("FizzyApp", FispactInventoryMetric); + +InputParameters FispactInventoryMetric::validParams() { + + InputParameters params = FispactElementPostprocessor::validParams(); + + params.addClassDescription( + "Postprocessor to calculate a user defined inventory " + "metric, for all nuclides in the inventory, over the entire " + "domain (or specified subdomains)."); + + params.addRequiredParam("metric", getInventoryMetricsEnum(), + "Which metric should be tracked"); + return params; +} + +FispactInventoryMetric::FispactInventoryMetric(const InputParameters ¶ms) + : FispactElementPostprocessor(params), + _metric(getParam("metric") + .getEnum()) {} + +void FispactInventoryMetric::initialize() { + _sum = 0; + _total_mass = 0; +} + +void FispactInventoryMetric::threadJoin(const UserObject &y) {}; + +void FispactInventoryMetric::execute() { + + size_t inv_index = getFispactProblem().getFispactInventoryIndexFromTime(); + + const FispactInventoryManager &inv_manager = + getUserObjectByName("inv_manager"); + + double metric_value = + inv_manager.getElementMetric(_current_elem->id(), inv_index, _metric); + + if (_metric == inventory_outputs::INVENTORY_DOSE_RATE) { + + double element_volume = _current_elem->volume(); + double element_mat_density = getFispactProblem() + .getElementMaterial(_current_elem->id()) + .getDensity(); + + double element_mass = element_volume * element_mat_density; + metric_value *= element_mass; + _total_mass += element_mass; + } + + _sum += metric_value; +} + +void FispactInventoryMetric::finalize() { + + if (_metric == inventory_outputs::INVENTORY_DOSE_RATE) { + comm().sum(_total_mass); + + // This changes our dose values back to sieverts + _sum /= _total_mass; + } + comm().sum(_sum); +} + +PostprocessorValue FispactInventoryMetric::getValue() const { return _sum; } diff --git a/src/postprocessors/FispactNuclideMetric.C b/src/postprocessors/FispactNuclideMetric.C new file mode 100644 index 0000000..6308d76 --- /dev/null +++ b/src/postprocessors/FispactNuclideMetric.C @@ -0,0 +1,79 @@ +#include "FispactElementPostprocessor.h" +#include "FispactInventoryManager.h" +#include "FispactNuclideMetric.h" +#include "FispactProblem.h" +#include "FizzyEnums.h" +#include "UserObject.h" +#include + +registerMooseObject("FizzyApp", FispactNuclideMetric); + +InputParameters FispactNuclideMetric::validParams() { + + InputParameters params = FispactElementPostprocessor::validParams(); + + params.addClassDescription( + "Postprocessor to calculate a user defined inventory " + "metric, for a given nuclide(s) in the inventory, over the entire " + "domain."); + + params.addRequiredParam>( + "nuclides", "Which nuclide should this kernel track"); + + params.addRequiredParam("metric", getNuclideMetricsEnum(), + "Which metric should be tracked"); + return params; +} + +FispactNuclideMetric::FispactNuclideMetric(const InputParameters ¶ms) + : FispactElementPostprocessor(params), + _nuclides(getParam>("nuclides")), + _metric(getParam("metric") + .getEnum()) {} + +void FispactNuclideMetric::initialize() { + _sum = 0; + _total_mass = 0; +} + +void FispactNuclideMetric::threadJoin(const UserObject &y) {}; + +void FispactNuclideMetric::execute() { + + size_t inv_index = getFispactProblem().getFispactInventoryIndexFromTime(); + + const FispactInventoryManager &inv_manager = + getUserObjectByName("inv_manager"); + + for (std::string &nuclide : _nuclides) { + + double metric_value = inv_manager.getNuclideMetric( + _current_elem->id(), nuclide, inv_index, _metric); + + if (_metric == nuclide_quantities::DOSE) { + double element_volume = _current_elem->volume(); + double element_mat_density = getFispactProblem() + .getElementMaterial(_current_elem->id()) + .getDensity(); + + double element_mass = element_volume * element_mat_density; + metric_value *= element_mass; + _total_mass += element_mass; + } + + _sum += metric_value; + } +} + +void FispactNuclideMetric::finalize() { + + if (_metric == nuclide_quantities::DOSE) { + comm().sum(_total_mass); + + // This changes our dose values back to sieverts + _sum /= _total_mass; + } + comm().sum(_sum); +} + +PostprocessorValue FispactNuclideMetric::getValue() const { return _sum; } diff --git a/src/postprocessors/FispactPostprocessor.C b/src/postprocessors/FispactPostprocessor.C new file mode 100644 index 0000000..8ea44a1 --- /dev/null +++ b/src/postprocessors/FispactPostprocessor.C @@ -0,0 +1,10 @@ +#include "FispactPostprocessor.h" +#include "FispactProblem.h" + +FispactPostprocessor::FispactPostprocessor(const InputParameters ¶ms) + : GeneralPostprocessor(params), + _fispact_problem(static_cast(_fe_problem)) {} + +FispactProblem &FispactPostprocessor::getFispactProblem() { + return _fispact_problem; +} diff --git a/src/postprocessors/SubdomainPhotonEmission.C b/src/postprocessors/SubdomainPhotonEmission.C new file mode 100644 index 0000000..7120658 --- /dev/null +++ b/src/postprocessors/SubdomainPhotonEmission.C @@ -0,0 +1,56 @@ +#include "FispactProblem.h" +#include "SubdomainPhotonEmission.h" +#include + +registerMooseObject("FizzyApp", SubdomainPhotonEmission); + +InputParameters SubdomainPhotonEmission::validParams() { + + InputParameters params = FispactPostprocessor::validParams(); + + params.addClassDescription("Postprocessor used to get the total photon " + "emission rate in photons/s from a " + "given subdomain(s)."); + + params += BlockRestrictable::validParams(); + + return params; +} + +SubdomainPhotonEmission::SubdomainPhotonEmission(const InputParameters ¶ms) + : FispactPostprocessor(params), BlockRestrictable(this) {} + +void SubdomainPhotonEmission::initialize() { _sum = 0; } + +void SubdomainPhotonEmission::execute() { + + PhotonSpectra *spectra = getFispactProblem().getPhotonSpectra(); + + std::unordered_map &local_element_index = + getFispactProblem().getLocalElemIndexMap(); + + size_t inventory_index = + getFispactProblem().getFispactInventoryIndexFromTime() - 1; + + for (auto &block_id : blockIDs()) { + for (libMesh::Elem *elem : + getFispactProblem() + .mesh() + .getMesh() + .active_subdomain_elements_ptr_range(block_id)) { + + if (elem->processor_id() == processor_id()) { + std::vector::iterator begin = spectra->spectrum_begin( + inventory_index, local_element_index[elem->id()]); + std::vector::iterator end = spectra->spectrum_end( + inventory_index, local_element_index[elem->id()]); + + _sum += std::accumulate(begin, end, 0.0); + } + } + } +} + +void SubdomainPhotonEmission::finalize() { comm().sum(_sum); } + +PostprocessorValue SubdomainPhotonEmission::getValue() const { return _sum; } diff --git a/src/problems/FispactProblem.C b/src/problems/FispactProblem.C index 5ab610a..be94f7c 100644 --- a/src/problems/FispactProblem.C +++ b/src/problems/FispactProblem.C @@ -1,47 +1,43 @@ -#include "ExternalProblem.h" +#include "EnergyGroups.h" +#include "FispactInventoryManager.h" #include "FispactProblem.h" - -#include "FispactSchedule.h" -/// HDF5 include -#include "H5Cpp.h" - -/// PugiXML include -#include "MooseError.h" -#include "MooseTypes.h" -#include "fispactcompute.hpp" -#include "fispactconstantsapi.h" -#include "fispactgroupstructures.hpp" -#include "fispactinputdata.hpp" -#include "fispactnucleardata.hpp" -#include "fispactoutputdata.hpp" -#include "fispactoutputdataapi.h" -#include "fispactutil.hpp" -#include "mpi.h" +//// PugiXML include +#include "FizzyEnums.h" #include "pugixml.hpp" + +/// Cpp includes #include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #include +#include +#include #include +#include #include +#include #include #include +#include + +// Avogadro's number +constexpr double AVOGADRO = 6.02214076e+23; + +#define MOLAR_MASS_DATASET_DIMS 1 + registerMooseObject("FizzyApp", FispactProblem); InputParameters FispactProblem::validParams() { InputParameters params = ExternalProblem::validParams(); - // Suppress parameters we are not using + params.addClassDescription( + "Run a FISPACT-II solve using MOOSE input syntax, and obtain inventory " + "quantities as aux variables."); + + /// Suppress parameters we are not using params.suppressParameter("allow_invalid_solution"); params.suppressParameter("boundary_restricted_elem_integrity_check"); params.suppressParameter("boundary_restricted_node_integrity_check"); @@ -62,631 +58,938 @@ InputParameters FispactProblem::validParams() { params.suppressParameter("identify_variable_groups_in_nl"); params.suppressParameter>("linear_sys_names"); - // New parameters we need for FISPACT - params.addRequiredParam("neutron_flux_file", - "HDF5 file storing neutron flux"); - params.addRequiredParam( - "neutron_flux_hdf5_path", - "Path within HDF5 file for the vector storing neutron flux"); - - params.addRequiredParam("fispact_nuclear_data_path", - "Path to FISPACT nuclear data"); + /// New parameters we need for FISPACT - params.addRequiredParam("fispact_nuclear_data_path", - "Path to FISPACT nuclear data"); + params.addRequiredParam( + "fispact_nuclear_data_uo", "Name of the FispactNuclearDataPaths objects " + "to use for setting nuclear data"); - params.addRequiredParam("neutron_bin_type", - "neutron binning scheme for FISPACT"); - - params.addRequiredParam( + params.addRequiredParam( "fispact_schedule_uo", "Name of the FispactSchedule user object defining " "the FISPACT flux schedule"); - params.addRequiredParam( - "photon_spectra_filename", - "Filename for the h5 file containing the output photon spectra"); + params.addRequiredParam( + "fispact_input_flux_uo", + "Name of the FispactFluxInput user object defining " + "the input flux spectra"); + params.addParam("mock_fispact", false, + "Parameter exclusively for unit testing when we don't " + "wish to use the actual FISPACT library"); params.addParam( "read_materials_from_xml", false, "Parameter determining whether user wishes to read materaial nuclide " "compositions from openMC XML file"); - params.addParam( + + params.addParam( "materials_xml_file", "materials.xml", "Path and name of material xml file user wishes to use."); + params.addParam( + "write_photon_flux", false, + "Boolean value used to determine whether to wite photon spectra to hdf5 " + "after Fizzy has finished running."); + + params.addParam("exclude_xrays", false, + "Boolean value used to determine whether to exclude " + "xrays from output gamma spectrum."); + + params.addParam( + "photon_flux_filename", "photon_flux.h5", + "Filename for the h5 file containing the output photon spectra"); + + params.addParam( + "num_photon_bins", 24, + "The number of bins to sort the output photon flux into"); + + params.addParam( + "comm_photon_flux", false, + "Boolean value used to indicate whether to use boost::interprocess to " + "communicate photon spectra through IPC."); + + params.addRequiredParam("molar_mass_data", + "Filename for HDF5 file containing molar " + "mass data in g/mol for all isotopes"); + + params.addParam( + "conversion_type", MooseEnum("LETHARGY ENERGY", "LETHARGY"), + "Setting to determine whether to convert by lethargy or energy"); + + params.addParam("output_inventory_time", + "When using the Steady executioner, which inventory " + "step should be placed in interprocess data"); + + params.addParam("rtol", 2e-3, "Relative FISPACT solver tolerance."); + params.addParam("atol", 1e4, "Absolute FISPACT solver tolerance."); + + params.addParam( + "uniform_sampling", false, + "When using distributed sampling, this forced all elements to be sampled " + "uniformly, with their weighting changed to account for their emission " + "strengths."); return params; } FispactProblem::FispactProblem(const InputParameters ¶ms) - : ExternalProblem(params), _fp_monitor(fispactLogName()), - _fp_nuclear_data(_fp_monitor), - _neutron_flux_filename(getParam("neutron_flux_file")), - _neutron_flux_hdf5_path(getParam("neutron_flux_hdf5_path")), - _photon_flux_filename(getParam("photon_spectra_filename")), + : ExternalProblem(params), + _photon_flux_filename(getParam("photon_flux_filename")), _materials_from_xml(getParam("read_materials_from_xml")), - _neutron_bin_type(getParam("neutron_bin_type")), - _schedule_uo_name(getParam("fispact_schedule_uo")) { - _console << "Constructor" << std::endl; + _materials_xml_file(getParam("materials_xml_file")), + _n_photon_bins(getParam("num_photon_bins")), + _fp_schedule_uo_name(getParam("fispact_schedule_uo")), + _fp_flux_uo_name(getParam("fispact_input_flux_uo")), + _fp_nuclear_data_uo_name( + getParam("fispact_nuclear_data_uo")), + _local_domain_strength(0), _total_domain_strength(0), + _write_photon_flux(getParam("write_photon_flux")), + _comm_photon_flux(getParam("comm_photon_flux")), _solved(false), + _uniform(getParam("uniform_sampling")), + _interprocess_segment_name(generateInterprocessName()), + _molar_mass_data_filename(getParam("molar_mass_data")), + _atol(getParam("atol")), _rtol(getParam("rtol")), + _exclude_xrays(getParam("exclude_xrays")) { + + /** + * If write_photon_flux was set to true then check that user input a + * filename, if not use default + */ + if (_write_photon_flux && !isParamSetByUser("photon_flux_filename")) { + paramWarning("write_photon_flux", + "write_photon_flux is set to true but photon_flux_filename is " + "not set! Photon flux filename defaulting to " + + _photon_flux_filename); + } + + /// Set up local element index map + int local_elem_idx = 0; + for (const libMesh::Elem *element : *_mesh.getActiveLocalElementRange()) { + _local_elem_index.insert( + std::pair(element->id(), local_elem_idx++)); + } + + if (_comm_photon_flux) { + +#ifdef LIBMESH_HAVE_BOOST + + /// Remove any potentially left over shared memory segments + bi::shared_memory_object::remove(_interprocess_segment_name.c_str()); + comm().barrier(); + + /// Calculate space needed for shared mem region + unsigned long shared_memory_size = calculateMemorySize(); + + /// Create shared memory region + _segment = bi::managed_shared_memory(bi::create_only, + _interprocess_segment_name.c_str(), + shared_memory_size); +#else + mooseError("_comm_photon_flux is set to true but libmesh was not built " + "with BOOST. No communication occuring."); +#endif + } + + /// Need to load molar masses here, as FispactMaterial will need molar mass + /// data in its constructor + loadMolarMasses(); +} + +FispactProblem::~FispactProblem() { + /// Remove any shared memory region with a similar name just in case + // bi::shared_memory_object::remove(_interprocess_segment_name.c_str()); +} + +void FispactProblem::initialSetup() { + ExternalProblem::initialSetup(); + + callFispactFactory(); + + if (!_fp_ctxt) { + mooseError("Fispact context could not be initialised! Maybe user has asked " + "to use mock fispact outside of unit tests?"); + } + // Init FISPACT + _fp_ctxt->globalInitialise(); + + resolveFispactUserObjects(); + + setNuclearData(); + + checkForEnergyGroupConsistency(); + + setPhotonBins(_fp_ctxt->getUtils().getPhotonEnergyBounds(_n_photon_bins)); + + _n_inventories = &(_fp_schedule_uo->getNumInventories()); + + _n_solution_inventories = &(_fp_schedule_uo->getNumSolutionInventories()); + /// + + /// Reserve space in our solution vector + // _photon_energy_spectra.resize( + // _mesh.nActiveLocalElem() * *_n_solution_inventories * _n_photon_bins, + // 0); + + _photon_energy_spectra = std::make_unique( + *_n_solution_inventories, _mesh.nActiveLocalElem(), _n_photon_bins); + + /// Reserve space for element strengths vector + _element_strengths.resize( + _mesh.nActiveLocalElem() * (*_n_solution_inventories), 0); + + _local_domain_strength.resize(*_n_solution_inventories, 0); + + _total_domain_strength.reserve(*_n_solution_inventories); + + /// Check user has passed output_inventory_time, if problem is Steady and + /// they wish to use distributed sampling + if (_comm_photon_flux) { + if (!isParamSetByUser("output_inventory_time") && !isTransient()) { + paramError("output_inventory_time", + "Parameter not set! When using a Steady executioner and " + "comm_photon_flux, user " + "must provide the inventory time to be communicated."); + } else if (isParamSetByUser("output_inventory_time") && isTransient()) { + paramWarning("output_inventory_time", + "Parameter is set, but executioner is Transient. Ignoring " + "parameter."); + } + } - // Load materials from xml file + /** + * Load materials from xml file if read_materials_from_xml is set to true, + * and a materials xml filename has been passed + */ if (_materials_from_xml) { - // Set file to get materials from - _materials_xml_file = getParam("materials_xml_file"); - // Populate _mat_definitions with materials from openmc xml + if (!isParamSetByUser("materials_xml_file")) { + paramWarning("materials_xml_file", + "read_materials_from_xml is set to true, but " + "materials_xml_file is not set! Defaulting to " + + _materials_xml_file); + } + /// Populate _mat_definitions with materials from openmc xml read_material_xml_data(); + } + /// Check a corresponding material exists for all mesh blocks + // checkMaterialsExist(); + // + if (isParamSetByUser("output_inventory_time")) { + _output_inventory_time = (getParam("output_inventory_time")); } else { - if (isParamSetByUser("materials_xml_file")) { - mooseError("materials_xml_file is set by user, but " - "read_materials_from_xml is false!"); - } + _output_inventory_time = _fp_schedule_uo->getCumulativeTimes().back(); } +} - // Check a corresponding material exists for all mesh blocks - checkMaterialsExist(); - - // Initialise FISPACT - fp::GlobalInitialise(_fp_monitor); +void FispactProblem::resolveFispactUserObjects() { - // Get the path to our nuclear data - std::string fp_nuclear_data_path = - getParam("fispact_nuclear_data_path"); + _fp_nuclear_data_uo = + &getUserObject(_fp_nuclear_data_uo_name); + _fp_schedule_uo = &getUserObject(_fp_schedule_uo_name); + _fp_flux_input_uo = &getUserObject(_fp_flux_uo_name); - // Set nuclear data paths - setNuclearData(fp_nuclear_data_path); + TheWarehouse::Query uo_query = + theWarehouse().query().condition("UserObject"); + std::vector userobjs; + uo_query.queryInto(userobjs); - // Set neutron bin type - setNeutronBins(); + for (const auto u : userobjs) { + if (u->type() == "FispactMaterial") { - // Read neutron flux from h5 file - readNeutronFluxFromHDF5(_neutron_flux_filename, _neutron_flux_hdf5_path); - _console << _neutron_fluxes.size() << std::endl; + _fp_fispact_materials.push_back(dynamic_cast(u)); + } + } } -void FispactProblem::syncSolutions(ExternalProblem::Direction direction) {} +void FispactProblem::timestepSetup() { + + ExternalProblem::timestepSetup(); + + // if (_comm_photon_flux) { + // if (timeStep() > 1) { + // + // _segment.destroy("photon_sharing_instance"); + // } + // } +} void FispactProblem::externalSolve() { - // Set up fispact input data - fp::InputData fispact_input(_fp_monitor); - fp::OutputData fispact_output(_fp_monitor); - int counter = 1; - for (auto element_iter : *_mesh.getActiveLocalElementRange()) { + if (!_solved) { + + const auto &subdomain_names = getParam>("block"); + auto mesh_subdomains_vec = + MooseMeshUtils::getSubdomainIDs(_mesh, subdomain_names); + std::set mesh_subdomains(mesh_subdomains_vec.begin(), + mesh_subdomains_vec.end()); + int counter = 1; + for (const libMesh::Elem *element : *_mesh.getActiveLocalElementRange()) { + + /// Get element id + dof_id_type global_elem_id = element->id(); + + std::vector input_flux = + _fp_flux_input_uo->getElemFlux(global_elem_id); + + /// Output how many elements have been checked + _console << std::endl + << "Elem ID: " << std::to_string(global_elem_id) << std::endl; + _console << counter++ << "/" << _mesh.getMesh().n_active_local_elem() + << std::endl; + + // If the energy groups of our nuclear data and input flux do not match, + // convert input flux to energy grouping of loaded nuclear data + if (_convert_energy_groups) { + convertFluxEnergyGroups(input_flux, + _fp_flux_input_uo->getFluxEnergyGroups()); + } + + const FispactMaterial &input_material = + getElementMaterial(global_elem_id); + + setFispactInputData(input_material, input_flux, element->volume(), + _fp_ctxt->getInput()); - _console << "starting " + std::to_string(counter) << std::endl; + if (mesh_subdomains.count(element->subdomain_id())) { - // Get element id - int elem_id = (element_iter)->id(); - _console << "Elem ID" << std::to_string(elem_id) << std::endl; - std::vector photon_spectra(24, 0); + /// Run FISPACT + _fp_ctxt->process(); - // Check if there is any neutron flux in current element - bool is_flux = isFlux(elem_id); + /// Loop over number of inventories to get all data for current + /// element + for (int inv_index = 0; inv_index < *_n_solution_inventories; + inv_index++) { - // If there is flux in the element, run FISPACT - if (is_flux) { - // Here we are assuming the input mesh is in centremeters - double element_volume = (element_iter)->volume(); + /// Vector to store photon energy spectra in photons/cc-s + std::vector element_photon_energy_spectrum; - // Get element material definition - MaterialDefinition &el_mat = getElementMaterial(elem_id); + /// Calculated Fispact inventories start at index 1, 0 is reserved + /// for initial concentrations + convertGammaEvToCount( + _fp_ctxt->getOutput().getGammaSpectrumBins(inv_index + 1), + element_photon_energy_spectrum); - setFispactInputData(_fp_monitor, fispact_input, el_mat, - _neutron_fluxes[elem_id], _neutron_bins, - element_volume); - // Run FISPACT - fp::Process(fispact_input, _fp_nuclear_data, fispact_output, _fp_monitor, - process_callback); + std::copy(element_photon_energy_spectrum.begin(), + element_photon_energy_spectrum.end(), + _photon_energy_spectra->spectrum_begin( + inv_index, _local_elem_index[global_elem_id])); - convertGammaEvToCount( - fispact_input, fispact_output.getGammaSpectrumBins(1), - fispact_output.getGammaSpectrumBoundaries(0), photon_spectra); + insertElementStrength(inv_index, element, + element_photon_energy_spectrum); + } - for (auto &ev : fispact_input.getGammaEnergyBounds()) { - _console << std::to_string(ev) << " "; + // if inventory manager exists, store requested nuclide metrics + if (hasUserObject("inv_manager")) { + FispactInventoryManager &inv_manager = + getUserObject("inv_manager"); + inv_manager.extractInventoryData(*_fp_ctxt, global_elem_id); + } } } + calculateLocalDomainStrength(); - _photon_fluxes.insert( - std::pair>(elem_id, photon_spectra)); + if (_write_photon_flux) { - // Output how many elements have been checked - _console << counter++ << "/" << _mesh.getMesh().n_active_local_elem() - << std::endl; - } + const std::vector &inv_times = + _fp_schedule_uo->getCumulativeTimes(); + writePhotonFlux(_photon_flux_filename, inv_times); + } - writePhotonFluxToHDF5(_photon_flux_filename, fispact_output); - fp::GlobalFinalise(_fp_monitor); - _console << "Externally Solved" << std::endl; + _fp_ctxt->globalFinalise(); + + _solved = true; + } } -std::string FispactProblem::fispactLogName() { - std::string log_name = - "FISPACT_app_" + std::to_string(processor_id()) + ".log"; - return log_name; +size_t FispactProblem::getFispactInventoryIndexFromTime() { + const std::vector &schedule_times = + _fp_schedule_uo->getCumulativeTimes(); + + double inventory_time = + isTransient() ? time() : getParam("output_inventory_time"); + + auto schedule_iterator = + std::find(schedule_times.begin(), schedule_times.end(), inventory_time); + + if (schedule_iterator == schedule_times.end()) { + mooseError("Current time " + std::to_string(inventory_time)); + } + + size_t inventory_idx = + std::distance(schedule_times.begin(), schedule_iterator); + + // Fispact Inventory index "0" is the initial inventory + return inventory_idx + 1; } -void FispactProblem::setNuclearData(std::string nd_base_path) { - fp::io::NuclearDataReader nd_reader(_fp_monitor); +void FispactProblem::syncSolutions(ExternalProblem::Direction direction) { + if (direction == ExternalProblem::Direction::FROM_EXTERNAL_APP) { + + if (_comm_photon_flux) { +#ifdef LIBMESH_HAVE_BOOST + + /// Find the the inventory index associated with current time + /// -1 required due to indexing differences between the stored photon + /// spectra, and FISPACTs own indexing scheme + size_t photon_spectra_idx = getFispactInventoryIndexFromTime() - 1; + + /// Calculate TotalDomainStrength + getTotalDomainStrength(); + + /// Create a shared instantiation of the photon sharing class, the init + /// data that are common across all timesteps + if (timeStep() == 1) { + _photon_sharing_instance = _segment.construct( + "photon_sharing_instance")(_segment); + _photon_sharing_instance->setPhotonBins(_photon_bins); + _photon_sharing_instance->setNumPhotonBins(_n_photon_bins); + _photon_sharing_instance->setNumLocalElems(_mesh.nActiveLocalElem()); + _photon_sharing_instance->setLocalElemIdMap(_local_elem_index); + } - nd_reader.setPath(FISPACT_ND_IND_NUC_KEY, - nd_base_path + "decay2020/decay_2020_index.txt"); + // Setup data that varies per timestep + _photon_sharing_instance->_is_setup = false; - nd_reader.setPath(FISPACT_ND_XS_ENDF_KEY, - nd_base_path + "TENDL2021data/gendf-1102"); - nd_reader.setPath(FISPACT_ND_PROB_TAB_KEY, - nd_base_path + "TENDL2021data/tp-1102-294"); + _photon_sharing_instance->setPhotonSpectra( + _photon_energy_spectra->time_begin(photon_spectra_idx), + _photon_energy_spectra->time_end(photon_spectra_idx)); - nd_reader.setPath(FISPACT_ND_FY_ENDF_KEY, - nd_base_path + "GEFY61data/gefy61_nfy"); - nd_reader.setPath(FISPACT_ND_SF_ENDF_KEY, - nd_base_path + "GEFY61data/gefy61_sfy"); + _photon_sharing_instance->setElementStrengths( + _element_strengths.begin() + + (photon_spectra_idx * _mesh.nActiveLocalElem()), + _element_strengths.begin() + + (photon_spectra_idx * _mesh.nActiveLocalElem()) + + _mesh.nActiveLocalElem()); - nd_reader.setPath(FISPACT_ND_DK_ENDF_KEY, - nd_base_path + "decay2020/decay_2020"); - nd_reader.setPath(FISPACT_ND_ABSORP_KEY, nd_base_path + "decay/abs_2012"); + _photon_sharing_instance->setLocalDomainStrength( + _local_domain_strength[photon_spectra_idx]); + _photon_sharing_instance->setTotalDomainStrength( + _total_domain_strength[photon_spectra_idx]); - nd_reader.setPath(FISPACT_ND_HAZARDS_KEY, - nd_base_path + "/decay/hazards_2012"); - nd_reader.setPath(FISPACT_ND_CLEAR_KEY, nd_base_path + "/decay/clear_2012"); - nd_reader.setPath(FISPACT_ND_A2DATA_KEY, nd_base_path + "/decay/a2_2012"); + _photon_sharing_instance->setSamplingMethod(_uniform); - nd_reader.load(_fp_nuclear_data, &FispactProblem::load_callback); +#else + mooseError("_comm_photon_flux is set to true but libmesh was not + built with BOOST. No communication occuring."); +#endif + } + } + + if (direction == ExternalProblem::Direction::TO_EXTERNAL_APP) { + } } -void FispactProblem::writePhotonFluxToHDF5(const std::string &filename, - fp::OutputData &fispact_output) { - MPI_Comm comm = MPI_COMM_WORLD; - MPI_Info info = MPI_INFO_NULL; - _console << "Writing..." << std::endl; - hid_t plist_id = H5Pcreate(H5P_FILE_ACCESS); - H5Pset_all_coll_metadata_ops(plist_id, true); - H5Pset_coll_metadata_write(plist_id, true); - // Set HDF5 driver - H5Pset_fapl_mpio(plist_id, comm, info); - - // Create HDF5 file - auto file_id = - H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, plist_id); - H5Pclose(plist_id); - - // Loop over all MPI ranks - std::string dataset_name = "photon_data"; - hsize_t dataspace_dims[2]; - - // Set up dimensions for photon flux dataspace - dataspace_dims[0] = _mesh.getMesh().n_active_elem(); - dataspace_dims[1] = 24; - - hid_t filespace = H5Screate_simple(2, dataspace_dims, NULL); - hid_t h5_dataset = - H5Dcreate(file_id, dataset_name.c_str(), H5T_NATIVE_DOUBLE, filespace, - H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); - H5Sclose(filespace); - - // Get dataspace corresponding to the hdf5 dataset - filespace = H5Dget_space(h5_dataset); - - for (auto &element_flux_pair : _photon_fluxes) { - - // CONTEXT: A hyperslab is a section of a hdf5 dataspace, don't be put off - // by the fancy name - - // Create hdf5 dataspace to be our memory space for writing - hsize_t memory_dspace_dims[2] = {1, 24}; - hid_t memspace = H5Screate_simple(2, memory_dspace_dims, NULL); - - // Retrieve element id from _photon_fluxes map - hsize_t element_id = (hsize_t)element_flux_pair.first; - - // offset and count are used to select our hyperslab. - // Given the dimensions of the dataspace are num_elems * 24, our offset - // selection should be the element_id who's flux we wish to write - hsize_t offset[2] = {element_id, 0}; - - // count specifies the number of entries we wish to write in each dimension - hsize_t count[2] = {1, 24}; - - // Select the hyperslab of the dataspace that we wish to write to - H5Sselect_hyperslab(filespace, H5S_SELECT_SET, offset, NULL, count, NULL); - - // Set data transfer mode - plist_id = H5Pcreate(H5P_DATASET_XFER); - H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_INDEPENDENT); - - // Write the data - H5Dwrite(h5_dataset, H5T_NATIVE_DOUBLE, memspace, filespace, plist_id, - element_flux_pair.second.data()); - H5Sclose(memspace); +void FispactProblem::convertFluxEnergyGroups( + std::vector &flux, const std::vector &input_energy_groups) { + switch (getParam("conversion_type")) { + case 0: // LETHARGY + flux = _fp_ctxt->getUtils().GroupConvertByLethargy( + input_energy_groups, flux, _flux_energy_groups); + + case 1: // ENERGY + flux = _fp_ctxt->getUtils().GroupConvertByEnergy(input_energy_groups, flux, + _flux_energy_groups); } - writePhotonFluxBins(file_id, fispact_output); - // Close all the HDF5 bits and pieces - H5Sclose(filespace); - H5Dclose(h5_dataset); - H5Pclose(plist_id); - H5Fclose(file_id); } -void FispactProblem::writePhotonFluxBins(hid_t file_id, - fp::OutputData &fispact_output) { +/** + * TODO: Break up this function into setFispactInputFlux and + * setFispactInputMaterial + */ +void FispactProblem::setFispactInputData(const FispactMaterial &material, + const std::vector &flux, + const double &volume, + IFispactInputDataBase &input) const { + input.setFlux(_flux_energy_groups, flux); + input.setFluxWallLoading(1.0); + input.setFluxName("neutrons"); - // Get gamma bins from the FISPACT output data - std::vector photon_bins = - fispact_output.getGammaSpectrumBoundaries(0); + input.setSolverTolerance(_rtol, _atol); - // Set up hsize_t object to hold dataset dimensions - hsize_t bin_dataset_dims[1]; - bin_dataset_dims[0] = photon_bins.size(); + input.setExcludeXrays(_exclude_xrays); - std::string dataset_name = "photon_bins"; + /// Get density from mat density, in g/cm^3! + double density = material.getDensity(); + input.setDensity(density); - // Create a dataspace for the photon bins - hid_t filespace_photon_bins = H5Screate_simple(1, bin_dataset_dims, NULL); + /// Set atoms threshold + input.setAtomsThreshold(1.0e1); - // Create a dataset for the photon bins using the dataspace - hid_t h5_dataset_photon_bins = - H5Dcreate(file_id, dataset_name.c_str(), H5T_NATIVE_DOUBLE, - filespace_photon_bins, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + double total_mass_grams = density * volume; + + if (material.getMaterialType() == "MASS") { + + std::vector atomic_numbers; + std::vector percent; + + /// Set total mass, in kg! + input.setMassTotal(total_mass_grams * 1e-3); + + const std::unordered_map &nuclideFractionMap = + material.getNuclideFractionMap(); + + atomic_numbers.reserve(nuclideFractionMap.size()); + + for (auto &[element_name, mass_fraction] : nuclideFractionMap) { + + atomic_numbers.push_back( + _fp_ctxt->getUtils().GetAtomicNumberFromElementName(element_name)); + } + + input.setMass(atomic_numbers, material.getNuclideFractions()); + + } else if (material.getMaterialType() == "FUEL") { - // Set up transfer properties - hid_t plist_id = H5Pcreate(H5P_DATASET_XFER); - H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_INDEPENDENT); + /// Get material map, that maps from map[nuclide_name] -> mass_fraction + const std::unordered_map &nuclideFractionMap = + material.getNuclideFractionMap(); - // Only write the photon bins out on rank 0, we don't need to write it from - // all of them - if (ExternalProblem::comm().rank() == 0) { - H5Dwrite(h5_dataset_photon_bins, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, - plist_id, photon_bins.data()); + std::vector zais; + zais.reserve(nuclideFractionMap.size()); + std::vector atoms; + atoms.reserve(nuclideFractionMap.size()); + + /// For all key (isotope name) value (mass_fraction) pairs in map, + /// calculate the number of atoms pertaining to each isotope and append to + /// input fuel + for (const auto &[isotope_name, mass_fraction] : nuclideFractionMap) { + + double zai_mass = total_mass_grams * (mass_fraction); + + zais.push_back(_fp_ctxt->getUtils().GetZai(isotope_name)); + + atoms.push_back( + getNumAtoms(zai_mass, _molar_mass_map.at(isotope_name), AVOGADRO)); + } + input.setFuel(zais, atoms); } - H5Sclose(filespace_photon_bins); - H5Dclose(h5_dataset_photon_bins); - H5Pclose(plist_id); + + double flux_sum = std::accumulate(flux.begin(), flux.end(), 0.0); + + setFispactSchedule(input, volume, flux_sum); } -void FispactProblem::readNeutronFluxFromHDF5(std::string filename, - std::string tally_dir) { - - MPI_Comm comm = MPI_COMM_WORLD; - MPI_Info info = MPI_INFO_NULL; - // Set access properties - hid_t plist_id = H5Pcreate(H5P_FILE_ACCESS); - - H5Pset_all_coll_metadata_ops(plist_id, true); - H5Pset_coll_metadata_write(plist_id, true); - // Set HDF5 driver - H5Pset_fapl_mpio(plist_id, comm, info); - // Open statepoint file as H5File - hid_t file_id = H5Fopen(filename.c_str(), H5F_ACC_RDONLY, plist_id); - H5Pclose(plist_id); - // Create dataset and dataspace for the tally results - hid_t dataset_tally_id = H5Dopen(file_id, tally_dir.c_str(), H5P_DEFAULT); - hid_t space_tally_id = H5Dget_space(dataset_tally_id); - - // Read in dimensions of tally results array - hsize_t tally_array_dims[3]; - H5Sget_simple_extent_dims(space_tally_id, tally_array_dims, NULL); - - // Check that the neutron flux we are reading is suitable for this mesh - if (tally_array_dims[0] != _mesh.nElem() * _num_neutron_bins) { - mooseError("Neutron flux file is incorrect dimension"); +void FispactProblem::setFispactSchedule(IFispactInputDataBase &input, + const double &element_volume, + const double &neutron_flux_sum) const { + + std::vector flux_schedule = _fp_schedule_uo->getFluxAmplitude(); + const std::vector × = _fp_schedule_uo->getTimes(); + + /// Need to scale input flux amplitude by the total neutron flux in this + /// element/ volume + for (auto &flux_amplitude : flux_schedule) { + flux_amplitude *= neutron_flux_sum / element_volume; } + input.setSchedule(times, flux_schedule); +} + +const FispactMaterial & +FispactProblem::getElementMaterial(const dof_id_type &elem_id) { - // Read in number of realizations to calculate mean - // Set up dataset and dataspace for reading realization count - int n_realizations; - hid_t dataset_realizations_id = - H5Dopen(file_id, "n_realizations", H5P_DEFAULT); - hid_t space_realizations_id = H5Dget_space(dataset_realizations_id); - - // Set up memory space for reading realization (batch) count - hsize_t memspace_dimensions_realizations[3] = {1, 1, 1}; - hid_t memspace_realizations_id = - H5Screate_simple(1, memspace_dimensions_realizations, nullptr); - - H5Dread(dataset_realizations_id, H5T_STD_I32LE, memspace_realizations_id, - space_realizations_id, H5P_DEFAULT, &n_realizations); - - // Close realizations hdf5 structures - H5Sclose(space_realizations_id); - H5Sclose(memspace_realizations_id); - H5Dclose(dataset_realizations_id); - - // Set up vector of vectors to store neutron fluxes - std::vector> neutron_fluxes( - tally_array_dims[0] / _num_neutron_bins, - std::vector(_num_neutron_bins, 0)); - - for (int i = 0; i < neutron_fluxes.size(); i++) { - // Set up std::vector to store neutron flux data - std::vector neutron_flux_data(_num_neutron_bins, 0.0); - - // Set up counts and offsets for selecting hyperslab of tally array - hsize_t data_count[3] = {static_cast(_num_neutron_bins), 1, 1}; - hsize_t data_offset[3] = {static_cast((_num_neutron_bins * i)), 0, - 0}; - - // Set up memory space for reading tally results - hsize_t arr_len[3] = {static_cast(_num_neutron_bins), 1, 1}; - hid_t memspace_tally_id = H5Screate_simple(1, arr_len, NULL); - H5Sselect_hyperslab(space_tally_id, H5S_SELECT_SET, data_offset, NULL, - data_count, NULL); - - plist_id = H5Pcreate(H5P_DATASET_XFER); - H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_INDEPENDENT); - // Read in neutron flux tally results - H5Dread(dataset_tally_id, H5T_IEEE_F64LE, memspace_tally_id, space_tally_id, - H5P_DEFAULT, neutron_flux_data.data()); - - for (auto &neutron_flux : neutron_flux_data) { - neutron_flux = neutron_flux / n_realizations; + libMesh::Elem *elem = _mesh.elemPtr(elem_id); + + // Query the warehouse to see if a FispactMaterial exists on the block this + // element is assigned to + std::vector objs; + theWarehouse() + .query() + .condition("UserObject") + .condition(elem->subdomain_id()) + .queryInto(objs); + + // Remove extraneous user objects that are not FispactMaterials. Having done + // this, only one object should remain in the vector, and it should be the + for (auto it = objs.begin(); it != objs.end();) { + if ((*it)->type() != "FispactMaterial") { + it = objs.erase(it); + } else { + ++it; } - // Add neutron flux data to map - neutron_fluxes[i] = neutron_flux_data; + } - // Close memspace dataspace - H5Sclose(memspace_tally_id); - H5Pclose(plist_id); + // FISPACT material pertaining to this block. If there ismore than one + // object, then two FispactMaterials are assigned to this block, and that + // makes no blimmin sense does it + if (objs.empty()) { + mooseError("Unable to find FispactMaterial object on block " + + std::to_string(elem->subdomain_id())); + } else if (objs.size() > 1) { + mooseError("More than 1 FispactMaterial definition exists on block " + + std::to_string(elem->subdomain_id())); } - // for now, only keep neutron fluxes for local elements - for (MeshBase::element_iterator it = _mesh.activeLocalElementsBegin(); - it != _mesh.activeLocalElementsEnd(); it++) { - int elem_id = (*it)->id(); - _neutron_fluxes.insert(std::make_pair(elem_id, neutron_fluxes[elem_id])); + /// Return the FispactMaterial + return *(static_cast(objs[0])); +} + +bool FispactProblem::isFlux(const std::vector &flux) const { + /** + * return true if there is flux, false if there isn't, as the function name + * implies + */ + bool is_zero_flux = + std::all_of(flux.begin(), flux.end(), [](double j) { return j == 0; }); + + return !is_zero_flux; +} + +void FispactProblem::convertGammaEvToCount( + const std::vector &photon_energy_spectra_ev, + std::vector &photon_energy_spectra_per_s) { + + /// Reserve memory for photons per cc per s vector + photon_energy_spectra_per_s.resize(photon_energy_spectra_ev.size(), 0); + + /// Assert in case, somehow, the spectra output by FISPACT has different bin + /// structure to _photon_bins?? + mooseAssert( + _photon_bins.size() == photon_energy_spectra_ev.size() + 1, + "_photon_bins size should be one less that input photon spectra!"); + + /// Convert from MeV/s to per cc per s for each bin + for (int i = 0; i < photon_energy_spectra_ev.size(); i++) { + double bin_energy = + _photon_bins[i] + ((_photon_bins[i + 1] - _photon_bins[i]) / 2); + + /** + * per_cc_per_s = MeV/s * (inventory_density/(inventory_mass * + * energy_bin_midpoint)) + */ + /// _photon_bins are in eV, but Photon Spectra is returned in by FISPACT in + /// MeV, so need 1e6 + photon_energy_spectra_per_s[i] = + photon_energy_spectra_ev[i] * (1e6 / bin_energy); } - H5Dclose(dataset_tally_id); - H5Sclose(space_tally_id); - H5Fclose(file_id); } -// To do: Break up this function into setFispactInputFlux and -// setFispactInputMaterial -void FispactProblem::setFispactInputData(fp::FispactMonitor &monitor, - fp::InputData &input, - MaterialDefinition &material, - std::vector &neutron_flux, - const std::vector &bins, - double volume) { - // Set neutron flux - input.setFlux(bins, neutron_flux); +void FispactProblem::setPhotonBins(const std::vector &photon_bins) { + _photon_bins = photon_bins; +} - input.setFluxWallLoading(1.0); +double FispactProblem::calculateElementStrength( + const std::vector element_flux) { + double element_strength = 0; - input.setFluxName("neutrons"); + for (double flux_bin : element_flux) { + element_strength += flux_bin; + } + + return element_strength; +} + +void FispactProblem::insertElementStrength( + const int inv_index, const libMesh::Elem *element, + const std::vector element_flux) { + double elem_strength = calculateElementStrength(element_flux); + + int idx = + (inv_index * _mesh.nActiveLocalElem()) + _local_elem_index[element->id()]; + + _element_strengths[idx] = elem_strength; +} - // get density from mat density - input.setDensity(material._mat_density); - input.setAtomsThreshold(1.0e3); - - // Volume read in is in cm ^ 3, so we need to scale by 1e-6, as mass is in - // kg - double total_mass = material._mat_density * volume * 1e-6; - input.setMassTotal(total_mass); - - std::vector atomic_numbers; - std::vector percent; - for (auto &element_name_ao_pair : material._mat_atomic_composition) { - std::string element_name = element_name_ao_pair.first; - - /** Remove numbers from element name, isotope doesn't matter here as we're - obtaining the atomic number, not the atomic mass **/ - element_name.erase( - std::remove_if(element_name.begin(), element_name.end(), - [](unsigned char c) { return std::isdigit(c); }), - element_name.end()); - - atomic_numbers.push_back( - fp::util::GetAtomicNumberFromElementName(monitor, element_name)); - percent.push_back(element_name_ao_pair.second); +void FispactProblem::calculateLocalDomainStrength() { + + for (int inv_index = 0; inv_index < *_n_solution_inventories; inv_index++) { + for (const libMesh::Elem *element : *_mesh.getActiveLocalElementRange()) { + + double element_strength; + + // Attempt to retrieve element strength from vector + int idx = (inv_index * _mesh.nActiveLocalElem()) + + _local_elem_index[element->id()]; + + element_strength = _element_strengths.at(idx); + + _local_domain_strength[inv_index] += element_strength; + } } +} + +void FispactProblem::getTotalDomainStrength() { - input.setMass(atomic_numbers, percent); - setFispactSchedule(input); + _total_domain_strength = _local_domain_strength; + comm().sum(_total_domain_strength); } -void FispactProblem::setFispactSchedule(fp::InputData &input) { - FispactSchedule &schedule = getUserObject(_schedule_uo_name); +int FispactProblem::calculateMemorySize() { + /// Get number of active local elements + dof_id_type n_local_elem = _mesh.getMesh().n_active_local_elem(); - const std::vector &flux_schedule = schedule.getFluxSchedule(); - const std::vector × = schedule.getTimes(); - input.setSchedule(times, flux_schedule); + size_t photon_flux_map_size = + ((_n_photon_bins * sizeof(double)) + sizeof(int)) * n_local_elem; + + size_t element_strengths_map_size = + (sizeof(int) + sizeof(double)) * n_local_elem; + + size_t memory_size = photon_flux_map_size + element_strengths_map_size + + (sizeof(int) * 2) + (sizeof(double) * 2); + /** + * Really naive way of doing this, but currently giving a 20% buffer to + * account for the memory space required by Boost allocators and such + */ + return memory_size * 2; } -FispactProblem::MaterialDefinition & -FispactProblem::getElementMaterial(int &elem_id) { - libMesh::Elem *elem = _mesh.elemPtr(elem_id); +std::string FispactProblem::fispactLogName() { + // std::string log_name = "FISPACT_app_" + + // this->getMooseApp().getInputFileNames()[0] + + // std::to_string(processor_id()) + ".log"; - const std::string &subdomain_name = - _mesh.getSubdomainName(elem->subdomain_id()); + std::string log_name = + "FISPACT_app_" + std::to_string(processor_id()) + ".log"; + return log_name; +} - // Return material definition if it exists, otherwise throw error - if (_mat_definitions.find(subdomain_name) != _mat_definitions.end()) { - return _mat_definitions.at(subdomain_name); +void FispactProblem::setNuclearData() { + _fp_ctxt->setNuclearData(_fp_nuclear_data_uo->getNuclearDataPathMap()); +} - } else { - mooseError("No FISPACT material named " + subdomain_name + " was found."); +const std::string FispactProblem::generateInterprocessName() { + char mpi_proc_name[MPI_MAX_PROCESSOR_NAME]; + int len = 0; + int err = MPI_Get_processor_name(mpi_proc_name, &len); + + MPI_Comm node_comm; + int local_rank; + MPI_Comm_split_type(comm().get(), MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, + &node_comm); + MPI_Comm_rank(node_comm, &local_rank); + + std::string ipc_name = std::string(mpi_proc_name); + ipc_name += "_" + std::to_string(local_rank); + + return ipc_name; +} + +double FispactProblem::getNumAtoms(const double &mass, const double &molar_mass, + const double &avogadro) const { + return (mass / molar_mass) * avogadro; +} + +void FispactProblem::loadMolarMasses() { + + hid_t molar_mass_file = hdf5_utils::file_open( + _molar_mass_data_filename.c_str(), 'r', false, comm().get()); + + hid_t molar_mass_dataset = + hdf5_utils::open_dataset(molar_mass_file, "MolarMass"); + + hid_t element_symbols_dataset = + hdf5_utils::open_dataset(molar_mass_file, "symbol"); + + hsize_t molar_mass_dims[MOLAR_MASS_DATASET_DIMS]; + + hdf5_utils::get_shape(molar_mass_dataset, molar_mass_dims); + + // Vectors to store molar masses and respective element symbols + std::vector molar_masses(molar_mass_dims[0]); + std::vector element_symbols(molar_mass_dims[0]); + + hdf5_utils::read_double(molar_mass_dataset, nullptr, molar_masses.data(), + false); + + hdf5_utils::read_string(element_symbols_dataset, nullptr, element_symbols, 8, + false); + + for (int i = 0; i < molar_masses.size(); i++) { + + std::pair key_value = + std::pair(element_symbols[i], molar_masses[i]); + _molar_mass_map.insert(key_value); } } -bool FispactProblem::isFlux(int elem_id) { - // Check if there is any neutron flux in current element - bool is_zero_flux = std::all_of(_neutron_fluxes.at(elem_id).begin(), - _neutron_fluxes.at(elem_id).end(), - [](double j) { return j == 0; }); - // return true if there is flux, false if there isn't, as the function name - // implies - return !is_zero_flux; +void FispactProblem::checkForEnergyGroupConsistency() { + size_t n_nd_energy_groups = _fp_ctxt->getNuclearDataCrossSections(); + + if (_fp_flux_input_uo->getNumEnergyGroups() != n_nd_energy_groups) { + _flux_energy_groups = + _fp_ctxt->getUtils().getNeutronEnergyBounds(n_nd_energy_groups); + _convert_energy_groups = true; + + std::string conversion_type = getParam("conversion_type"); + mooseWarning("Input neutron flux group structure does not match that of " + "input nuclear data, converting using " + + conversion_type); + } else { + _flux_energy_groups = _fp_flux_input_uo->getFluxEnergyGroups(); + } } +// TO DO: Move most of this functionality to FispactMaterial, allow +// FispactMaterial to take in a wider range of inputs eg density units, and do +// the hard work there void FispactProblem::read_material_xml_data() { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file(_materials_xml_file.c_str()); if (!result) { - // mooseError(); mooseError("No file called " + _materials_xml_file + " could be found, exiting."); } + for (pugi::xml_node material : doc.child("materials").children()) { - // Get material name + InputParameters params = + _app.getFactory().getValidParams("FispactMaterial"); + + /// Get material name std::string material_name = material.attribute("name").value(); - // Get material density + + /// Get material density double density = std::stod(material.child("density").attribute("value").value()); - // Get atomic composition of material - std::vector> atomic_comp; + std::string density_units = + material.child("density").attribute("units").value(); + + std::vector nuclides; + std::vector nuclide_fractions; for (pugi::xml_node nuclide : material.children("nuclide")) { - std::pair nuclide_symbol_and_percentage = - std::make_pair(std::string(nuclide.attribute("name").value()), - std::stod(nuclide.attribute("ao").value())); - atomic_comp.push_back(nuclide_symbol_and_percentage); + nuclides.push_back(std::string(nuclide.attribute("name").value())); + + if (nuclide.attribute("wo")) { + nuclide_fractions.push_back(std::stod(nuclide.attribute("wo").value()) / + 100); + } else if (nuclide.attribute("ao")) { + + nuclide_fractions.push_back( + -std::stod(nuclide.attribute("ao").value())); + } } - // Create material definition - MaterialDefinition material_def{material_name, atomic_comp, density}; - // Insert material definition into material map - _mat_definitions.insert(std::make_pair(material_name, material_def)); - } -} + bool all_wo = + std::all_of(nuclide_fractions.begin(), nuclide_fractions.end(), + [](double x) { return x >= 0.0; }); + bool all_ao = + std::all_of(nuclide_fractions.begin(), nuclide_fractions.end(), + [](double x) { return x <= 0.0; }); -void FispactProblem::setNeutronBins() { - if (_neutron_bin_type == "G1102") { - _neutron_bins = fp::groups::G1102(); - _num_neutron_bins = 1102; - } -} + if (!(all_wo || all_ao)) { + mooseError("Cannot mix atom and weight percents in material. Error when " + "parsing material xml"); + } -void FispactProblem::checkMaterialsExist() { + std::string fraction_type; + if (all_ao) { + fraction_type = "ao"; + for (auto &fraction : nuclide_fractions) { + fraction = -fraction; + } + } + if (all_wo) { + fraction_type = "wo"; + } - // Fetch all subdomain ID's from libmesh - std::vector subdomain_ids; - for (auto &subdomain_id : _mesh.meshSubdomains()) { - subdomain_ids.push_back(subdomain_id); - } + params.set("density") = density; + params.set("material_type") = "FUEL"; + params.set("fraction_type") = fraction_type; + params.set("density_units") = density_units; + params.set>("block") = {material_name}; + params.set>("nuclides") = nuclides; + params.set>("nuclide_fraction") = nuclide_fractions; - // Fetch all subdomain names using libmesh - std::vector subdomain_names = - _mesh.getSubdomainNames(subdomain_ids); + addUserObject("FispactMaterial", material_name, params); + } +} - // Check that for all subdomain names there is an associated material - for (auto &subdomain_name : subdomain_names) { - if (_mat_definitions.find(subdomain_name) == _mat_definitions.end()) { - mooseError("Block " + subdomain_name + - " does not have a corresponding FISPACT material defined"); +void FispactProblem::writePhotonFlux( + const std::string &filename, const std::vector &inventory_times) { +/** + * Do use MPI HDF5 driver, as we are calling H5Dcreate on each rank the same + * number of times + */ +#ifdef H5_HAVE_PARALLEL + bool parallel = true; +#else + bool parallel = false; + mooseWarning( + "Writing photon flux requires HDF5 compiled with MPI. " + "Simulation continuing, but photon spectra will not be written."); + return; +#endif + /// Open OpenMC statepoint file with Neutron Flux + hid_t file_id = + hdf5_utils::file_open(filename.c_str(), 'w', parallel, comm().get()); + + for (int inv_id = 0; inv_id < *_n_solution_inventories; inv_id++) { + + std::string dataset_name = + "photon_flux_" + std::to_string(inventory_times[inv_id]); + + int ndim = 2; + unsigned long x_dim = _mesh.getMesh().n_active_elem(); + int y_dim = _n_photon_bins; + /// Set up dimensions for photon flux dataspace + hsize_t dataspace_dims[ndim]; + dataspace_dims[0] = x_dim; + dataspace_dims[1] = y_dim; + + // Create filespace + hid_t dataspace = H5Screate_simple(ndim, dataspace_dims, NULL); + hid_t h5_dataset = + H5Dcreate(file_id, dataset_name.c_str(), H5T_NATIVE_DOUBLE, dataspace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + H5Sclose(dataspace); + + for (const libMesh::Elem *element : *_mesh.getActiveLocalElementRange()) { + + /// Create hdf5 dataspace to be our memory space for writing + hsize_t hyperslab_dims[2] = {1, static_cast(y_dim)}; + + /** + * offset and count are used to select our hyperslab. + * Given the dimensions of the dataspace are num_elems * 24, our offset + * selection should be the element_id who's flux we wish to write + */ + hsize_t start[2] = {element->id(), 0}; + + /// count specifies the number of entries we wish to write in each + /// dimension + hsize_t count[2] = {1, _n_photon_bins}; + + hdf5_utils::write_double_hyperslab( + h5_dataset, nullptr, ndim, hyperslab_dims, start, count, + &*_photon_energy_spectra->spectrum_begin( + inv_id, _local_elem_index[element->id()]), + parallel); } + /// Close all the HDF5 bits and pieces + H5Dclose(h5_dataset); } + + /// Write bins to hdf5 file as well + writePhotonFluxBins(file_id, parallel); + + H5Fclose(file_id); } -void FispactProblem::convertGammaEvToCount( - fp::InputData &input, const std::vector &photon_spectra, - const std::vector &photon_flux_bins, - std::vector &photons_per_cc_per_s) { +void FispactProblem::writePhotonFluxBins(const hid_t &file_id, + const bool parallel) { + /// Check _photon_bins are actually set + std::vector &photon_bins = getPhotonBins(); - // Reserve memory for photons per cc per s vector - photons_per_cc_per_s.resize(photon_spectra.size()); + /// Set up hsize_t object to hold dataset dimensions + int ndim = 1; + hsize_t bin_dataset_dims[ndim]; + bin_dataset_dims[0] = photon_bins.size(); - // Get inventory density and mass - double inv_density = input.getDensity(); - double inv_mass = input.getMassTotal(); + std::string dataset_name = "photon_bins"; - // Convert from MeV/s to per cc per s for each bin - for (int i = 0; i < photon_spectra.size(); i++) { - double bin_energy = photon_flux_bins[i] + - ((photon_flux_bins[i + 1] - photon_flux_bins[i]) / 2); + /// Create a dataspace for the photon bins + hid_t filespace_photon_bins = H5Screate_simple(1, bin_dataset_dims, NULL); - // per_cc_per_s = MeV/s * (inventory_density/(inventory_mass * - // energy_bin_midpoint)) - double per_cc_per_s = - photon_spectra[i] * (inv_density / (inv_mass * bin_energy)); + /// Create a dataset for the photon bins using the dataspace + hid_t h5_dataset_photon_bins = + H5Dcreate(file_id, dataset_name.c_str(), H5T_NATIVE_DOUBLE, + filespace_photon_bins, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + H5Dclose(h5_dataset_photon_bins); - photons_per_cc_per_s[i] = per_cc_per_s; - } + hdf5_utils::write_dataset_lowlevel(file_id, dataset_name.c_str(), ndim, + bin_dataset_dims, H5T_NATIVE_DOUBLE, + photon_bins.data(), parallel); } -// double FispactProblem::extractHalflifeFromNuc(fp::NuclearData -// &nuclear_data, -// int zai) { -// int num_zais = nuclear_data.getDecayDataSize(); -// -// std::vector decay_zais = nuclear_data.getDecayZais(); -// for (int i = 0; i < num_zais + 1; i++) { -// if (decay_zais[i] == zai) { -// double halflife = nuclear_data.getDecayHalfLife(i); -// return halflife; -// } -// } -// return -1.0; -// } -// -// void FispactProblem::printInventoryByHeat(fp::OutputData &output, -// int timestep_index, -// std::ostream &stream) { -// double mass = output.getInventoryValue( -// timestep_index, FISPACT_OUTPUT_DATA_INVENTORY_TOTAL_MASS); -// -// std::pair, std::vector> dom_sort = -// output.getSortedInventory(timestep_index, -// FISPACT_OUTPUT_DATA_INVENTORY_TOTAL_HEAT); -// -// std::vector dom_zai = std::get<0>(dom_sort); -// std::vector dom_heat = std::get<1>(dom_sort); -// -// int num_nuclides = dom_zai.size(); -// for (int i = (num_nuclides - 8); i < num_nuclides; i++) { -// double heating = dom_heat[i] / mass; -// double halflife = extractHalflifeFromNuc(_fp_nuclear_data, dom_zai[i]); -// if (halflife != -1.0) { -// std::string nuclide_name = -// fp::util::GetNuclideName(_fp_monitor, dom_zai[i]); -// -// // stream << std::setw(15) << halflife / FISPACT_YEAR_TO_SEC << -// // std::setw(15) -// // << heating << std::setw(15) << nuclide_name << "\n"; -// stream << heating << "," << nuclide_name << "\n"; -// } -// } -// } -// -// void FispactProblem::printInvData(fp::OutputData &output, -// std::ostream &stream) { -// double mass = -// output.getInventoryValue(0, -// FISPACT_OUTPUT_DATA_INVENTORY_TOTAL_MASS); -// -// std::pair, std::vector> dom_sort = -// output.getSortedInventory(1, -// FISPACT_OUTPUT_DATA_INVENTORY_TOTAL_HEAT); -// -// std::vector dom_zai = std::get<0>(dom_sort); -// std::vector dom_heat = std::get<1>(dom_sort); -// -// std::vector chosen_zai(dom_zai.end() - 8, dom_zai.end()); -// -// for (auto zai : chosen_zai) { -// std::string nuclide_name = fp::util::GetNuclideName(_fp_monitor, zai); -// stream << nuclide_name << ","; -// } -// -// stream << std::endl; -// -// for (int time = 1; time < 6; time++) { -// -// std::pair, std::vector> timestep_sort = -// output.getSortedInventory(time, -// FISPACT_OUTPUT_DATA_INVENTORY_TOTAL_HEAT); -// std::vector time_zai = std::get<0>(timestep_sort); -// std::vector time_heat = std::get<1>(timestep_sort); -// -// for (int j = 0; j < time_zai.size(); j++) { -// int zai = time_zai[j]; -// if (std::find(chosen_zai.begin(), chosen_zai.end(), zai) != -// chosen_zai.end()) { -// std::string nuclide_name = fp::util::GetNuclideName(_fp_monitor, -// zai); double heating = time_heat[j] / mass; -// // std::cout << heating << std::endl; -// stream << heating << ","; -// } -// } -// stream << std::endl; +const double FispactProblem::avogadroNumber() const { return AVOGADRO; } + +void FispactProblem::callFispactFactory() { _fp_ctxt = createFispactContext(); } diff --git a/src/times/FispactScheduleTimes.C b/src/times/FispactScheduleTimes.C new file mode 100644 index 0000000..6c4398e --- /dev/null +++ b/src/times/FispactScheduleTimes.C @@ -0,0 +1,57 @@ +#include "FispactScheduleTimes.h" +#include "MooseError.h" +#include + +registerMooseObject("MooseApp", FispactScheduleTimes); + +InputParameters FispactScheduleTimes::validParams() { + InputParameters params = Times::validParams(); + + params.addClassDescription( + "Times set from a FispactSchedule UserObject defined in the input file"); + + params.addRequiredParam( + "FispactScheduleName", + "Name of the FispactSchedule UserObject used to set times"); + + params.addParam>( + "FispactScheduleTimeIndices", + "The indices of the values within the schedule times the user wishes to " + "give to the executioner. This is useful if the user wishes to only " + "store data and/or run multiapps at a subset of the times defined within " + "the FispactSchedule"); + + // Times are known for all processes already + params.set("auto_broadcast") = false; + params.set("dynamic_time_sequence") = false; + + return params; +} + +FispactScheduleTimes::FispactScheduleTimes(const InputParameters ¶meters) + : Times(parameters), + _schedule(getUserObject("FispactScheduleName")), + _fispact_times(_schedule.getCumulativeTimes()) { + + if (isParamValid("FispactScheduleTimeIndices")) { + + const std::vector &indices = + getParam>("FispactScheduleTimeIndices"); + + std::vector mask(_fispact_times.size(), false); + + for (auto index : indices) { + mask[index] = true; + } + + auto mask_it = mask.begin(); + _fispact_times.erase( + std::remove_if(_fispact_times.begin(), _fispact_times.end(), + [&](double const &) { return !*mask_it++; }), + _fispact_times.end()); + + _times = _fispact_times; + } else { + _times = _fispact_times; + } +} diff --git a/src/userobjects/FISPACTMaterial.C b/src/userobjects/FISPACTMaterial.C deleted file mode 100644 index 36a7fbd..0000000 --- a/src/userobjects/FISPACTMaterial.C +++ /dev/null @@ -1,27 +0,0 @@ -#include "FISPACTMaterial.h" - -registerMooseObject("fizzyApp", FISPACTMaterial); - -InputParameters -FISPACTMaterial::validParams() -{ - InputParameters params = GeneralUserObject::validParams(); - - params.addRequiredParam>("nuclides", - "a list of nuclides present in the material"); - - params.addRequiredParam>("nuclide_proportions", - "List of percentages dictating the proportion of the nuclides in the material."); - params.addRequiredParam("density", - "Total material density in g/cm^3"); - - return params; -} - -FISPACTMaterial::FISPACTMaterial(const InputParameters & parameters) - : GeneralUserObject(parameters), - _nuclides(getParam>("nuclides")), - _nuclide_proportion(getParam>("nuclide_proportions")), - _density(getParam("density")) -{ -} diff --git a/src/userobjects/FispactInventoryManager.C b/src/userobjects/FispactInventoryManager.C new file mode 100644 index 0000000..ef4e88b --- /dev/null +++ b/src/userobjects/FispactInventoryManager.C @@ -0,0 +1,148 @@ +#include "FispactContextBase.h" +#include "FispactInventoryManager.h" +#include "FispactProblem.h" +#include "FizzyEnums.h" +#include +#include +#include +registerMooseObject("FizzyApp", FispactInventoryManager); + +FispactInventoryManager::FispactInventoryManager( + const InputParameters ¶meters) + : FispactUserObject(parameters), + _n_fispact_inventories( + getFispactProblem().getSchedule().getNumInventories()) { + + initialiseNuclearInventory(); +} + +InputParameters FispactInventoryManager::validParams() { + + InputParameters params = FispactUserObject::validParams(); + + params.addClassDescription( + "A UserObject designed to recieve requests from postprocessors and " + "auxkernels regarding which nuclear inventory quantities they require to " + "compute their values. The inventory manager stores these requests and " + "retrieves the necessary data from the FISPACT output object generated " + "after each FISPACT solve."); + + return params; +} + +void FispactInventoryManager::registerNuclideMetricRequest( + const std::string &nuclide, + const nuclide_quantities::NuclideQuantitiesEnum metric, + const std::set &blocks) { + + if (_nuclide_ids.find(nuclide) == _nuclide_ids.end()) { + + _nuclide_ids[nuclide] = ++_max_nuclide_id; + + _nuclide_names[_nuclide_ids[nuclide]] = nuclide; + } + + for (const libMesh::Elem *elem : + *getSubProblem().mesh().getActiveLocalElementRange()) { + if (blocks.count(elem->subdomain_id())) { + getElementInventory(elem->id()) + .registerNuclideMetricRequest(nuclide, _nuclide_ids[nuclide], + _n_fispact_inventories, metric); + } + } +} + +void FispactInventoryManager::registerElementMetricRequest( + const inventory_outputs::InventoryOutputsEnum metric, + const std::set &blocks) { + + for (const libMesh::Elem *elem : + *getSubProblem().mesh().getActiveLocalElementRange()) { + if (blocks.count(elem->subdomain_id())) { + getElementInventory(elem->id()) + .registerElementMetricRequest(_n_fispact_inventories, metric); + } + } +} + +void FispactInventoryManager::extractInventoryData( + FispactContextBase &fp_context, size_t elem_id) { + + for (size_t inv_index = 0; inv_index < _n_fispact_inventories; inv_index++) { + + std::vector> + fispact_inventory_nuclides = + fp_context.getOutput().getInventoryNuclides(inv_index); + + ElementInventory &elem_inv = getElementInventory(elem_id); + + for (auto &[metric, values] : elem_inv.getInventoryMetricMap()) { + values[inv_index] = + fp_context.getOutput().getInventoryValue(inv_index, metric); + } + + for (size_t &nuclide : elem_inv.getNuclides()) { + + NuclideInventory &nuclide_inv = elem_inv.getNuclide(nuclide); + + int zai = fp_context.getUtils().GetZai(_nuclide_names[nuclide]); + // Check nuclide data exists for this inventory step + int fispact_nuclide_index = + fp_context.getOutput().findInventoryExists(inv_index, zai) + ? + + fp_context.getOutput().findInventoryIndex(inv_index, zai) + : -1; + + // If the FISPACT inventory does not contain this nuclide, set the + // quantity value to 0 + if (fispact_nuclide_index != -1) { + + for (nuclide_quantities::NuclideQuantitiesEnum quantity : + elem_inv.getNuclide(nuclide).getQuantities()) { + + nuclide_inv.setQuantity( + quantity, inv_index, + fispact_inventory_nuclides[fispact_nuclide_index]->getQuantity( + quantity)); + } + } + } + } +} + +double FispactInventoryManager::getNuclideMetric( + libMesh::dof_id_type elem_id, std::string &nuclide, int inv_index, + nuclide_quantities::NuclideQuantitiesEnum metric) const { + return getElementInventory(elem_id) + .getNuclide(_nuclide_ids.at(nuclide)) + .getQuantity(metric, inv_index); +} + +double FispactInventoryManager::getElementMetric( + libMesh::dof_id_type elem_id, int inv_index, + inventory_outputs::InventoryOutputsEnum metric) const { + return getElementInventory(elem_id).getElementMetric(metric, inv_index); +} + +void FispactInventoryManager::initialiseNuclearInventory() { + for (const libMesh::Elem *elem : + *getSubProblem().mesh().getActiveLocalElementRange()) { + + _element_inventories.emplace_back(elem->id()); + } +} + +FispactInventoryManager::ElementInventory & +FispactInventoryManager::getElementInventory(size_t elem_id) { + + size_t index = _fispact_problem.getLocalElemIndexMap()[elem_id]; + return _element_inventories[index]; +} + +const FispactInventoryManager::ElementInventory & +FispactInventoryManager::getElementInventory(size_t elem_id) const { + + size_t index = _fispact_problem.getLocalElemIndexMap()[elem_id]; + return _element_inventories[index]; +} diff --git a/src/userobjects/FispactMaterial.C b/src/userobjects/FispactMaterial.C new file mode 100644 index 0000000..46ad5e1 --- /dev/null +++ b/src/userobjects/FispactMaterial.C @@ -0,0 +1,205 @@ +#include "FispactFactory.h" +#include "FispactMaterial.h" + +#include +#include +#include + +registerMooseObject("FizzyApp", FispactMaterial); + +InputParameters FispactMaterial::validParams() { + InputParameters params = FispactUserObject::validParams(); + params += BlockRestrictable::validParams(); + + params.addClassDescription( + "A class designed to hold material definitions for FISPACT-II solves."); + + params.addRequiredParam>( + "nuclides", "a list of nuclides present in the material"); + + params.addRequiredParam>( + "nuclide_fraction", + "List of decimal fractions dictating the proportions of " + "the nuclides in the material."); + + params.addRequiredParam( + "fraction_type", MooseEnum("wo ao"), + "Determines whether supplied material fractions are mass fractions " + "or atomic fractions."); + + params.addRequiredParam("density", "Total material density"); + + params.addRequiredParam( + "density_units", MooseEnum("g/cm3 kg/m3 atom/b-cm atom/cm3"), + "Material density units"); + + // Enum to determine whether we are using FISPACT::setMass or + // FISPACT::setFUEL + MooseEnum material_type_enum{"MASS FUEL"}; + params.addRequiredParam( + "material_type", material_type_enum, + "Setting to determine if this is a FISPACT Mass or Fuel material"); + return params; +} + +FispactMaterial::FispactMaterial(const InputParameters ¶meters) + : FispactUserObject(parameters), BlockRestrictable(this), + _molar_mass_map(getFispactProblem().getMolarMassMap()), + _density(getParam("density")), + _material_type(getParam("material_type")), + _avogadro(getFispactProblem().avogadroNumber()) { + + std::vector nuclide_names = + getParam>("nuclides"); + std::vector nuclide_fractions = + getParam>("nuclide_fraction"); + + // Check _nuclides and _nuclide_fractions are of equal length + if (nuclide_names.size() != nuclide_fractions.size()) { + mooseError("Nuclides list length does not match nuclide fraction list " + "length in material " + + name()); + } + + // Check that nuclide fractions sum to equal to or less than 1 + if (!(std::accumulate(nuclide_fractions.begin(), nuclide_fractions.end(), + 0) <= 1)) { + mooseError("FispactMaterial " + name() + + " has nuclide fractions summing to more than 1."); + } + + // Check that the user has either: NOT set isotope numbers if the material + // type is set to MASS OR: HAS provided isotope number if material type is set + // to FUEL + for (auto &nuclide : nuclide_names) { + if (std::any_of(nuclide.begin(), nuclide.end(), + [](unsigned char c) { return std::isdigit(c); })) { + + if (_material_type == "MASS") { + mooseError("Material type is set to MASS, but the provided nuclides " + "have isotope numbers specified. Please provide only " + "nuclide symbols, not isotope numbers."); + } + } else if (_material_type == "FUEL") { + mooseError("Material set to FUEL, but provided nuclides do not have " + "isotope numbers defined. Please define nuclide isotopes"); + } + } + + std::string fraction_type = getParam("fraction_type"); + std::string density_units = getParam("density_units"); + + if ((_material_type == "MASS") && (fraction_type != "wo")) { + + mooseError("Fispact MASS material only supports mass fractions!"); + } + + if ((_material_type == "MASS") && + !((density_units == "g/cm3") || (density_units == "kg/cm3"))) { + mooseError( + "Fispact MASS material only supports density units of g/cm3 or kg/cm3"); + } + + /// If using a FUEL material, calculate mean molar mass for the material as + /// we'll probably need it + double average_molar_mass = 0; + if (_material_type == "FUEL") { + + average_molar_mass = + getAverageMolarMass(nuclide_names, nuclide_fractions, fraction_type); + + if (fraction_type == "ao") { + convertFromAtomToMassFraction(nuclide_names, nuclide_fractions, + average_molar_mass); + } + } + + /// If density is not given in g/cm3, we have some conversions to do + if (density_units == "g/cm3") { + + } else if (density_units == "kg/m3") { + _density /= 1000; + + } else if (density_units == "atom/cm3") { + _density *= average_molar_mass / _avogadro; + } + + else if (density_units == "atom/b-cm") { + _density *= average_molar_mass * 1e24 / _avogadro; + } + + // Actually initialise map now we've checked all the data makes sense + for (int i = 0; i < nuclide_names.size(); i++) { + auto [it, inserted] = _nuclide_fraction_map.try_emplace( + nuclide_names[i], nuclide_fractions[i]); + + // If we attempt to give the same isotope two mass fraction values, freak + // out + if (!inserted) { + throw std::runtime_error( + "Duplicate element in material definition for material " + name()); + } + } +} + +const std::vector FispactMaterial::getNuclides() const { + + std::vector nuclides; + + for (auto &pair : _nuclide_fraction_map) { + nuclides.push_back(pair.first); + } + return nuclides; +} + +const std::vector FispactMaterial::getNuclideFractions() const { + + std::vector nuclide_fractions; + + for (auto &pair : _nuclide_fraction_map) { + nuclide_fractions.push_back(pair.second); + } + return nuclide_fractions; +} + +double FispactMaterial::getAverageMolarMass( + const std::vector &nuclide_names, + const std::vector &nuclide_fractions, + const std::string &fraction_type) const { + double average_molar_mass = 0; + if (fraction_type == "wo") { + double sum_mass_frac_over_molar_mass = 0; + for (int i = 0; i < nuclide_names.size(); i++) { + + sum_mass_frac_over_molar_mass += + nuclide_fractions[i] / _molar_mass_map.at(nuclide_names[i]); + } + average_molar_mass = 1 / sum_mass_frac_over_molar_mass; + + } else if (fraction_type == "ao") { + for (int i = 0; i < nuclide_names.size(); i++) { + + average_molar_mass += + nuclide_fractions[i] * _molar_mass_map.at(nuclide_names[i]); + } + } + return average_molar_mass; +} + +void FispactMaterial::convertFromAtomToMassFraction( + const std::vector &nuclide_names, + std::vector &nuclide_fractions, const double average_molar_mass) { + + /// While we're here, now that we have the average molar mass, convert to + /// mass fraction + for (int i = 0; i < nuclide_names.size(); i++) { + + nuclide_fractions[i] = + (nuclide_fractions[i] * _molar_mass_map.at(nuclide_names[i])) / + average_molar_mass; + } +} + +FispactProblem &FispactMaterial::getFispactProblem() const { + return _fispact_problem; +} diff --git a/src/userobjects/FispactNuclearDataPaths.C b/src/userobjects/FispactNuclearDataPaths.C new file mode 100644 index 0000000..57f30fd --- /dev/null +++ b/src/userobjects/FispactNuclearDataPaths.C @@ -0,0 +1,89 @@ +#include "FispactNuclearDataPaths.h" +#include "MooseError.h" + +#include +#include +#include +#include +#include + +registerMooseObject("FizzyApp", FispactNuclearDataPaths); + +InputParameters FispactNuclearDataPaths::validParams() { + InputParameters params = GeneralUserObject::validParams(); + + params.addClassDescription("A UserObject to store paths to nuclear data, and " + "to check those paths exist."); + + params.addParam("base_path", "", ""); + params.addParam("ND_IND_NUC_KEY", ""); + params.addParam("ND_HAZARDS_KEY", ""); + params.addParam("ND_ABSORP_KEY", ""); + params.addParam("ND_CLEAR_KEY", ""); + params.addParam("ND_A2DATA_KEY", ""); + params.addParam("ND_ENBINS_KEY", ""); + params.addParam("ND_DECAY_KEY", ""); + params.addParam("ND_DK_ENDF_KEY", ""); + params.addParam("ND_PROB_TAB_KEY", ""); + params.addParam("ND_ASSCFY_KEY", ""); + params.addParam("ND_FISSYLD_KEY", ""); + params.addParam("ND_FY_ENDF_KEY", ""); + params.addParam("ND_SF_ENDF_KEY", ""); + params.addParam("ND_SP_ENDF_KEY", ""); + params.addParam("ND_XS_EXTRA_KEY", ""); + params.addParam("ND_CROSSEC_KEY", ""); + params.addParam("ND_CROSSUNC_KEY", ""); + params.addParam("ND_XS_ENDF_KEY", ""); + params.addParam("ND_XS_ENDFB_KEY", ""); + + return params; +} + +FispactNuclearDataPaths::FispactNuclearDataPaths( + const InputParameters ¶meters) + : GeneralUserObject(parameters), + _base_path(getParam("base_path")) { + loadNuclearDataPaths(); +} + +std::unordered_map &getNuclearDataPathMap(); + +std::unordered_map & +FispactNuclearDataPaths::getNuclearDataPathMap() { + return _datatype_to_path_map; +} + +void FispactNuclearDataPaths::loadNuclearDataPaths() { + + std::vector nuclear_data{ + "ND_IND_NUC_KEY", "ND_HAZARDS_KEY", "ND_ABSORP_KEY", "ND_CLEAR_KEY", + "ND_A2DATA_KEY", "ND_ENBINS_KEY", "ND_DECAY_KEY", "ND_DK_ENDF_KEY", + "ND_PROB_TAB_KEY", "ND_ASSCFY_KEY", "ND_FISSYLD_KEY", "ND_FY_ENDF_KEY", + "ND_SF_ENDF_KEY", "ND_SP_ENDF_KEY", "ND_XS_EXTRA_KEY", "ND_CROSSEC_KEY", + "ND_CROSSUNC_KEY", "ND_XS_ENDF_KEY", "ND_XS_ENDFB_KEY"}; + for (auto &data : nuclear_data) { + if (isParamValid(data)) { + /// check path exists + std::string path = _base_path + getParam(data); + + if (!(std::filesystem::exists(path))) { + paramError(data, path + " is not a valid path! Could not set "); + } + + if (data == ("ND_XS_ENDF_KEY")) { + if (isParamSetByUser("ND_XS_ENDFB_KEY")) { + paramWarning( + "ND_XS_ENDF_KEY", + "User has provided both compressed xs and uncompressed xs, " + "preferring compressed option."); + + /// If the user has set binary and non-binary cross sections, skip + /// setting the non-binary ones + + continue; + } + } + _datatype_to_path_map[data] = path; + } + } +} diff --git a/src/userobjects/FispactSchedule.C b/src/userobjects/FispactSchedule.C index f96c661..6d1ef5f 100644 --- a/src/userobjects/FispactSchedule.C +++ b/src/userobjects/FispactSchedule.C @@ -1,32 +1,56 @@ #include "FispactSchedule.h" +#include "MooseError.h" registerMooseObject("FizzyApp", FispactSchedule); InputParameters FispactSchedule::validParams() { InputParameters params = GeneralUserObject::validParams(); + params.addClassDescription( + "A UserObject used to set the FISPACT-II irradiation schedule."); + params.addRequiredParam>("times", "a list of times with each "); params.addRequiredParam>( - "flux_schedule", - "List of 1s and 0s of length one less than the list of times. \ - List represents whether heating or cooling should occur."); + "flux_amplitude", "Vector of flux amplitudes for each time."); return params; } FispactSchedule::FispactSchedule(const InputParameters ¶meters) : GeneralUserObject(parameters), - _flux_schedule(getParam>("flux_schedule")), - _times(getParam>("times")) { + _flux_amplitude(getParam>("flux_amplitude")), + _times(getParam>("times")), + _n_solution_inventories(_times.size()), + _n_inventories(_n_solution_inventories + 1) { // Check vectors passed in are the right size - mooseAssert(_times.size() == _flux_schedule.size(), - "The length of the flux_schdule and times must be equal"); + if (_times.size() != _flux_amplitude.size()) { + mooseError("The length of the flux_schdule and times must be equal"); + } + + _cumulative_times.resize(_times.size()); + std::inclusive_scan(_times.begin(), _times.end(), _cumulative_times.begin()); +} + +const std::vector &FispactSchedule::getFluxAmplitude() const { + return _flux_amplitude; +} + +std::vector FispactSchedule::getFluxAmplitude() { + return _flux_amplitude; } -const std::vector &FispactSchedule::getFluxSchedule() { - return _flux_schedule; +const std::vector &FispactSchedule::getTimes() const { return _times; } + +const std::vector &FispactSchedule::getCumulativeTimes() const { + return _cumulative_times; } -const std::vector &FispactSchedule::getTimes() { return _times; } +const size_t &FispactSchedule::getNumInventories() const { + return _n_inventories; +} + +const size_t &FispactSchedule::getNumSolutionInventories() const { + return _n_solution_inventories; +} diff --git a/src/userobjects/FispactUserObject.C b/src/userobjects/FispactUserObject.C new file mode 100644 index 0000000..fb3c267 --- /dev/null +++ b/src/userobjects/FispactUserObject.C @@ -0,0 +1,6 @@ +#include "FispactProblem.h" +#include "FispactUserObject.h" + +FispactUserObject::FispactUserObject(const InputParameters ¶ms) + : GeneralUserObject(params), + _fispact_problem(static_cast(_fe_problem)) {} diff --git a/src/userobjects/OpenMCFluxInput.C b/src/userobjects/OpenMCFluxInput.C new file mode 100644 index 0000000..eef5ba3 --- /dev/null +++ b/src/userobjects/OpenMCFluxInput.C @@ -0,0 +1,166 @@ +#include "HDF5Utils.h" +#include "InputParameters.h" +#include "OpenMCFluxInput.h" +#include "Problem.h" + +registerMooseObject("FizzyApp", OpenMCFluxInput); + +InputParameters OpenMCFluxInput::validParams() { + InputParameters params = FispactFluxInput::validParams(); + + params.addClassDescription( + "A UserObject used to read tallied flux from an OpenMC statepoint file."); + + params.addRequiredParam( + "flux_tally_id", "OpenMC tally ID of the tallies neutron flux"); + + params.addRequiredParam( + "energy_filter_id", + "OpenMC filter ID of the filter specifying the flux energy bins"); + + params.addRequiredParam( + "statepoint_filename", + "Filename of the statepoint file containing flux data"); + + return params; +} + +OpenMCFluxInput::OpenMCFluxInput(const InputParameters ¶meters) + : FispactFluxInput(parameters), + _flux_tally_id(getParam("flux_tally_id")), + _energy_filter_id(getParam("energy_filter_id")), + _statepoint_filename(getParam("statepoint_filename")) { + + readEnergyFilterBins(); + readNumEnergyBins(); +} + +std::vector OpenMCFluxInput::getElemFlux(dof_id_type elem_id) { + /** + * Don't do this with HDF5 MPI driver, as we are going to call H5Dopen a + * different number of times on each rank! + */ + bool parallel = false; + + hid_t hdf5_file = hdf5_utils::file_open(_statepoint_filename.c_str(), 'r', + parallel, comm().get()); + + hid_t tallies_group = hdf5_utils::open_group(hdf5_file, "tallies"); + + /// Open up the neutron flux tally group within the tallies group + std::string tally_group_name = "tally " + std::to_string(_flux_tally_id); + hid_t neutron_flux_tally_group = + hdf5_utils::open_group(tallies_group, tally_group_name); + + /// Define size of selection of flux + hsize_t dataset_dims[3]; + hsize_t hyperslab_dims[3]{_n_bins, 1, 1}; + hsize_t start[]{elem_id * _n_bins, 0, 0}; + hsize_t count[]{_n_bins, 1, 1}; + + /// Number of dimensions of hyperslab to read + hsize_t rank = 3; + + // Check this statepoint file is of + hid_t flux_dataset = + hdf5_utils::open_dataset(neutron_flux_tally_group, "results"); + hdf5_utils::get_shape(flux_dataset, dataset_dims); + + if (dataset_dims[0] != _n_bins * getSubProblem().mesh().getMesh().n_elem()) { + mooseError("Provided tally dimensions do not conform to this mesh and " + "neutron bin structure. Tally dimensions are (" + + std::to_string(dataset_dims[0]) + "," + + std::to_string(dataset_dims[1]) + "," + + std::to_string(dataset_dims[2]) + ")"); + } + + std::vector neutron_flux_results(_n_bins, 0); + + hdf5_utils::read_double_hyperslab(neutron_flux_tally_group, "results", rank, + hyperslab_dims, start, count, + neutron_flux_results.data(), parallel); + + /// Get number of tally realizations + int n_realizations; + hdf5_utils::read_int(neutron_flux_tally_group, "n_realizations", + &n_realizations, parallel, true); + + hdf5_utils::close_dataset(flux_dataset); + hdf5_utils::close_group(tallies_group); + hdf5_utils::close_group(neutron_flux_tally_group); + + hdf5_utils::file_close(hdf5_file); + + /** + * Divide every value in neutron flux results vector by n_realizations to + * get the mean value + */ + for (auto &bin : neutron_flux_results) { + bin /= n_realizations; + } + + return neutron_flux_results; +} + +void OpenMCFluxInput::readEnergyFilterBins() { + /** + * Don't do this with HDF5 MPI driver, as we are going to call H5Dopen a + * different number of times on each rank! + */ + bool parallel = false; + + hid_t hdf5_file = hdf5_utils::file_open(_statepoint_filename.c_str(), 'r', + parallel, comm().get()); + + hid_t filter_group = hdf5_utils::open_group(hdf5_file, "tallies/filters"); + + /// Open up the neutron flux tally group within the tallies group + std::string filter_name = "filter " + std::to_string(_energy_filter_id); + hid_t energy_filter_group = hdf5_utils::open_group(filter_group, filter_name); + + // Check this statepoint file is of + hid_t energy_bins_dataset = + hdf5_utils::open_dataset(energy_filter_group, "bins"); + + hsize_t energy_bins_dataset_dims[3]; + hdf5_utils::get_shape(energy_bins_dataset, energy_bins_dataset_dims); + + _flux_energy_groups.resize(energy_bins_dataset_dims[0]); + + hdf5_utils::read_double(energy_bins_dataset, nullptr, + _flux_energy_groups.data(), parallel); + + hdf5_utils::close_group(energy_filter_group); + hdf5_utils::close_group(filter_group); + hdf5_utils::close_dataset(energy_bins_dataset); + + hdf5_utils::file_close(hdf5_file); +} + +void OpenMCFluxInput::readNumEnergyBins() { + /** + * Don't do this with HDF5 MPI driver, as we are going to call H5Dopen a + * different number of times on each rank! + */ + bool parallel = false; + + hid_t hdf5_file = hdf5_utils::file_open(_statepoint_filename.c_str(), 'r', + parallel, comm().get()); + + hid_t filter_group = hdf5_utils::open_group(hdf5_file, "tallies/filters"); + + /// Open up the neutron flux tally group within the tallies group + std::string filter_name = "filter " + std::to_string(_energy_filter_id); + hid_t energy_filter_group = hdf5_utils::open_group(filter_group, filter_name); + + // Check this statepoint file is of + int n_bins; + hdf5_utils::read_int(energy_filter_group, "n_bins", &n_bins, parallel); + + hdf5_utils::close_group(energy_filter_group); + hdf5_utils::close_group(filter_group); + + hdf5_utils::file_close(hdf5_file); + + _n_bins = n_bins; +} diff --git a/src/utils/HDF5Utils.C b/src/utils/HDF5Utils.C new file mode 100644 index 0000000..2adaf68 --- /dev/null +++ b/src/utils/HDF5Utils.C @@ -0,0 +1,334 @@ +#include "HDF5Utils.h" +#include "MooseError.h" +#include "mpi.h" +#include + +namespace hdf5_utils { + +bool attribute_exists(hid_t obj_id, const char *name) { + + htri_t out = H5Aexists_by_name(obj_id, ".", name, H5P_DEFAULT); + // If the attribute exists out will be 1 + return out > 0; +} + +bool object_exists(hid_t object_id, const char *name) { + htri_t out = H5LTpath_valid(object_id, name, true); + if (out < 0) { + std::string error = + "Failed to check if object " + std::string(name) + " exists."; + mooseError(error); + } + return (out > 0); +} + +void get_shape(hid_t obj_id, hsize_t *dims) { + + auto type = H5Iget_type(obj_id); + hid_t dspace; + if (type == H5I_DATASET) { + dspace = H5Dget_space(obj_id); + } else if (type == H5I_ATTR) { + dspace = H5Aget_space(obj_id); + } else { + throw std::runtime_error{ + "Expected dataset or attribute in call to get_shape."}; + } + H5Sget_simple_extent_dims(dspace, dims, nullptr); + H5Sclose(dspace); +} + +std::string object_name(hid_t obj_id) { + // Determine size and create buffer + size_t size = 1 + H5Iget_name(obj_id, nullptr, 0); + char *buffer = new char[size]; + + // Read and return name + H5Iget_name(obj_id, buffer, size); + std::string str = buffer; + delete[] buffer; + return str; +} + +void ensure_exists(hid_t obj_id, const char *name, bool attribute) { + if (attribute) { + if (!attribute_exists(obj_id, name)) { + + std::string error_msg = "Attribute " + std::string(name) + + " does not exist in object " + + object_name(obj_id); + + mooseError(error_msg); + } + } else { + if (!object_exists(obj_id, name)) { + + std::string error_msg = "Object " + std::string(name) + + " does not exist in object " + + std::string(object_name(obj_id)); + + mooseError(error_msg); + } + } +} + +hid_t file_open(const char *filename, char mode, bool parallel, + const MPI_Comm &comm) { + bool create; + unsigned int flags; + switch (mode) { + case 'r': + case 'a': + create = false; + flags = (mode == 'r' ? H5F_ACC_RDONLY : H5F_ACC_RDWR); + break; + case 'w': + case 'x': + create = true; + flags = (mode == 'x' ? H5F_ACC_EXCL : H5F_ACC_TRUNC); + break; + default: + std::string error_msg = "Invalid file mode: " + std::to_string(mode); + mooseError(error_msg); + } + + hid_t plist = H5P_DEFAULT; +#ifdef H5_HAVE_PARALLEL + if (parallel) { + // Setup file access property list with parallel I/O access + plist = H5Pcreate(H5P_FILE_ACCESS); + H5Pset_all_coll_metadata_ops(plist, true); + H5Pset_fapl_mpio(plist, comm, MPI_INFO_NULL); + } +#endif + + // Open the file collectively + hid_t file_id; + if (create) { + file_id = H5Fcreate(filename, flags, H5P_DEFAULT, plist); + } else { + file_id = H5Fopen(filename, flags, plist); + } + if (file_id < 0) { + std::string error_msg = "Failed to open HDF5 file with mode " + + std::to_string(mode) + ": " + filename; + mooseError(error_msg); + } + +#ifdef H5_HAVE_PARALLEL + // Close the property list + if (parallel) + H5Pclose(plist); +#endif + + return file_id; +} + +void file_close(hid_t file_id) { H5Fclose(file_id); } + +hid_t open_group(hid_t group_id, const char *name) { + ensure_exists(group_id, name); + return H5Gopen(group_id, name, H5P_DEFAULT); +} + +hid_t open_group(hid_t group_id, const std::string &name) { + return open_group(group_id, name.c_str()); +} + +void close_group(hid_t group_id) { + if (H5Gclose(group_id) < 0) + mooseError("Failed to close group"); +} + +hid_t open_dataset(hid_t group_id, const char *name) { + ensure_exists(group_id, name); + return H5Dopen(group_id, name, H5P_DEFAULT); +} + +void close_dataset(hid_t dataset_id) { + if (H5Dclose(dataset_id) < 0) + mooseError("Failed to close dataset"); +} + +bool using_mpio_device(hid_t obj_id) { + + // Determine file that this object is part of + hid_t file_id = H5Iget_file_id(obj_id); + + // Get file access property list + hid_t fapl_id = H5Fget_access_plist(file_id); + + // Get low-level driver identifier + hid_t driver = H5Pget_driver(fapl_id); + + // Free resources + H5Pclose(fapl_id); + H5Fclose(file_id); + + return driver == H5FD_MPIO; +} + +void write_dataset_lowlevel(hid_t obj_id, const char *name, int ndim, + const hsize_t *dims, hid_t mem_type_id, + void *buffer, bool parallel, bool indep, + hid_t file_space_id) { + + hid_t dataset = obj_id; + if (name) { + dataset = open_dataset(obj_id, name); + } + // If array is given, create a simple dataspace. Otherwise, create a + // scalar datascape. + hid_t mem_space = H5Screate_simple(ndim, dims, NULL); + + if (parallel) { +#ifdef H5_HAVE_PARALLEL + // Set up collective vs independent I/O + auto data_xfer_mode = indep ? H5FD_MPIO_INDEPENDENT : H5FD_MPIO_COLLECTIVE; + + // Create dataset transfer property list + hid_t plist = H5Pcreate(H5P_DATASET_XFER); + H5Pset_dxpl_mpio(plist, data_xfer_mode); + + // Write data + H5Dwrite(dataset, mem_type_id, mem_space, file_space_id, plist, buffer); + H5Pclose(plist); +#endif + } else { + H5Dwrite(dataset, mem_type_id, mem_space, file_space_id, H5P_DEFAULT, + buffer); + } + + // Free resources + H5Sclose(mem_space); + if (name) { + H5Dclose(dataset); + } +} + +void read_dataset_lowlevel(hid_t obj_id, const char *name, hid_t mem_type_id, + hid_t mem_space_id, void *buffer, bool parallel, + bool indep, hid_t file_space_id) { + + hid_t dataset = obj_id; + if (name) { + dataset = open_dataset(obj_id, name); + } + + if (parallel) { +#ifdef H5_HAVE_PARALLEL + // Set up collective vs independent I/O + auto data_xfer_mode = indep ? H5FD_MPIO_INDEPENDENT : H5FD_MPIO_COLLECTIVE; + + // Create dataset transfer property list + hid_t plist = H5Pcreate(H5P_DATASET_XFER); + H5Pset_dxpl_mpio(plist, data_xfer_mode); + + // Read data + H5Dread(dataset, mem_type_id, mem_space_id, file_space_id, plist, buffer); + H5Pclose(plist); +#endif + } else { + H5Dread(dataset, mem_type_id, mem_space_id, file_space_id, H5P_DEFAULT, + buffer); + } + + if (name) { + H5Dclose(dataset); + } +} + +void read_double(hid_t obj_id, const char *name, double *buffer, bool parallel, + bool indep) { + read_dataset_lowlevel(obj_id, name, H5T_NATIVE_DOUBLE, H5S_ALL, buffer, + parallel, indep); +} + +void read_int(hid_t obj_id, const char *name, int *buffer, bool parallel, + bool indep) { + read_dataset_lowlevel(obj_id, name, H5T_NATIVE_INT, H5S_ALL, buffer, parallel, + indep); +} + +void read_string(hid_t obj_id, const char *name, + std::vector &buffer, int slen, bool parallel, + bool indep) { + + /// Currently easier to read into a char buffer and then use the predefined + /// string length to seperate the char buffer into strings + std::vector char_buff(slen * buffer.size()); + + /// Create datatype for "string" + hid_t datatype = H5Tcopy(H5T_C_S1); + H5Tset_size(datatype, slen); + + H5Tset_strpad(datatype, H5T_STR_NULLPAD); + + /// Read strings into char buffer + read_dataset_lowlevel(obj_id, name, datatype, H5S_ALL, char_buff.data(), + parallel, indep); + + /// Split vector of chars into strings of length slen + for (size_t i = 0; i < buffer.size(); i++) { + std::string s(char_buff.data() + i * slen, slen); + + auto pos = s.find_last_not_of(std::string("\0 ", 2)); + if (pos != std::string::npos) + s.erase(pos + 1); + else + s.clear(); + buffer[i] = std::move(s); + } + + /// Free memory allocated to datatype + H5Tclose(datatype); +} + +void read_double_hyperslab(hid_t obj_id, const char *name, hsize_t ndim, + hsize_t dims[], hsize_t start[], hsize_t count[], + double *results, bool parallel, bool indep) { + hid_t dataset = obj_id; + if (name) { + dataset = open_dataset(obj_id, name); + } + hid_t mem_space_id = H5Screate_simple(ndim, dims, nullptr); + + hid_t file_space_id = H5Dget_space(dataset); + + H5Sselect_hyperslab(file_space_id, H5S_SELECT_SET, start, nullptr, count, + nullptr); + + read_dataset_lowlevel(obj_id, name, H5T_NATIVE_DOUBLE, mem_space_id, results, + parallel, indep, file_space_id); + + H5Sclose(mem_space_id); + H5Sclose(file_space_id); + + if (name) { + H5Dclose(dataset); + } +} + +void write_double_hyperslab(hid_t obj_id, const char *name, hsize_t ndim, + hsize_t dims[], hsize_t start[], hsize_t count[], + double *results, bool parallel, bool indep) { + + hid_t dataset = obj_id; + if (name) { + dataset = open_dataset(obj_id, name); + } + hid_t file_space_id = H5Dget_space(dataset); + + H5Sselect_hyperslab(file_space_id, H5S_SELECT_SET, start, nullptr, count, + nullptr); + + write_dataset_lowlevel(obj_id, name, ndim, dims, H5T_NATIVE_DOUBLE, results, + parallel, indep, file_space_id); + + H5Sclose(file_space_id); + if (name) { + H5Dclose(dataset); + } +} + +} // namespace hdf5_utils diff --git a/src/vectorpostprocessors/FispactVectorPostprocessor.C b/src/vectorpostprocessors/FispactVectorPostprocessor.C new file mode 100644 index 0000000..a341ac9 --- /dev/null +++ b/src/vectorpostprocessors/FispactVectorPostprocessor.C @@ -0,0 +1,34 @@ +#include "FispactVectorPostprocessor.h" + +FispactVectorPostprocessor::FispactVectorPostprocessor( + const InputParameters ¶ms) + : GeneralVectorPostprocessor(params), + _fispact_problem(static_cast(_fe_problem)) {} + +size_t FispactVectorPostprocessor::getFispactInventoryIdx() { + + const FispactSchedule &schedule = getFispactProblem().getSchedule(); + + const std::vector &schedule_times = schedule.getCumulativeTimes(); + + double inventory_time; + if (!_is_transient) { + inventory_time = getFispactProblem().getOutputInventoryTime(); + + } else { + inventory_time = _t; + } + + auto schedule_iterator = + std::find(schedule_times.begin(), schedule_times.end(), inventory_time); + + if (schedule_iterator == schedule_times.end()) { + mooseError("Current time " + std::to_string(inventory_time) + + " does not match any entry in the FISPACT schedule. Cannot " + "do interprocess communication"); + } + size_t inventory_idx = + std::distance(schedule_times.begin(), schedule_iterator); + + return inventory_idx; +} diff --git a/src/vectorpostprocessors/SubdomainPhotonEmissionSpectraPostprocessor.C b/src/vectorpostprocessors/SubdomainPhotonEmissionSpectraPostprocessor.C new file mode 100644 index 0000000..336fad7 --- /dev/null +++ b/src/vectorpostprocessors/SubdomainPhotonEmissionSpectraPostprocessor.C @@ -0,0 +1,61 @@ +#include "SubdomainPhotonEmissionSpectraPostprocessor.h" +#include + +registerMooseObject("FizzyApp", SubdomainPhotonEmissionSpectraPostprocessor); + +InputParameters SubdomainPhotonEmissionSpectraPostprocessor::validParams() { + + InputParameters params = FispactVectorPostprocessor::validParams(); + params += BlockRestrictable::validParams(); + + params.addClassDescription("Postprocessor used to get the photon emission " + "spectra for a given subdomain(s)."); + + return params; +} + +SubdomainPhotonEmissionSpectraPostprocessor:: + SubdomainPhotonEmissionSpectraPostprocessor(const InputParameters ¶ms) + : FispactVectorPostprocessor(params), BlockRestrictable(this), + _photon_emission_spectra(declareVector("photon_emission_spectra")) { + + _photon_emission_spectra.resize(24); +} + +void SubdomainPhotonEmissionSpectraPostprocessor::initialize() { + std::fill(_photon_emission_spectra.begin(), _photon_emission_spectra.end(), + 0.0); +} + +void SubdomainPhotonEmissionSpectraPostprocessor::execute() { + PhotonSpectra *spectra = getFispactProblem().getPhotonSpectra(); + + std::unordered_map &local_element_index = + getFispactProblem().getLocalElemIndexMap(); + + size_t inventory_index = getFispactInventoryIdx(); + for (auto &block_id : blockIDs()) { + for (libMesh::Elem *elem : + getFispactProblem() + .mesh() + .getMesh() + .active_subdomain_elements_ptr_range(block_id)) { + + if (elem->processor_id() == processor_id()) { + std::vector::iterator begin = spectra->spectrum_begin( + inventory_index, local_element_index[elem->id()]); + + std::vector::iterator end = spectra->spectrum_end( + inventory_index, local_element_index[elem->id()]); + + std::transform(begin, end, _photon_emission_spectra.begin(), + _photon_emission_spectra.begin(), std::plus()); + } + } + } +} + +void SubdomainPhotonEmissionSpectraPostprocessor::finalize() { + + _communicator.sum(_photon_emission_spectra); +} diff --git a/tutorials/geometry/cube.cub5 b/tutorials/geometry/cube.cub5 new file mode 100644 index 0000000..19ea5e7 Binary files /dev/null and b/tutorials/geometry/cube.cub5 differ diff --git a/tutorials/geometry/cube.e b/tutorials/geometry/cube.e new file mode 100644 index 0000000..5f40eb5 Binary files /dev/null and b/tutorials/geometry/cube.e differ diff --git a/tutorials/geometry/cube_dag.h5m b/tutorials/geometry/cube_dag.h5m new file mode 100644 index 0000000..e18deee Binary files /dev/null and b/tutorials/geometry/cube_dag.h5m differ diff --git a/tutorials/statepoint_neutrons.10.h5 b/tutorials/statepoint_neutrons.10.h5 new file mode 100644 index 0000000..193fd89 Binary files /dev/null and b/tutorials/statepoint_neutrons.10.h5 differ diff --git a/tutorials/tutorial_1/input.i b/tutorials/tutorial_1/input.i new file mode 100644 index 0000000..6a57494 --- /dev/null +++ b/tutorials/tutorial_1/input.i @@ -0,0 +1,67 @@ +[Mesh] + [fmg] + type = FileMeshGenerator + file = "../geometry/cube.e" + [] +[] + +[Problem] + type = FispactProblem + + molar_mass_data = '../../molar_masses.h5' + + output_inventory_time = 1e5 + + fispact_schedule_uo = 'Schedule' + fispact_nuclear_data_uo = 'endf_nuclear_data' + fispact_input_flux_uo = 'InputFlux' +[] + + +[UserObjects] + [InputFlux] + type = OpenMCFluxInput + statepoint_filename = '../statepoint_neutrons.10.h5' + energy_filter_id = 2 + flux_tally_id = 2 + wall_loading = 10 + [] + + [Schedule] + type = FispactSchedule + times = '1e5 1e4 1e4 2e5 2e5 2e5 5e5 5e5 2e5' + flux_amplitude = '1e10 0 0 0 0 0 0 0 0' + [] + + [steel] + type = FispactMaterial + material_type = FUEL + nuclides = "B10 B11 C12 C13 Si28 V50 V51 Cr50 Cr52 Cr53 Cr54 Mn55 Fe54 Fe56 Fe57 Fe58 Co59 Ni58 Ni60 Ni61 Ni62 Ni64 Mo92 Mo94 Mo95 Mo96 Mo97 Mo98 Mo100 Cu63 Cu65" + nuclide_fraction = "0.00000693 0.0000281 0.000395203 0.00000479726 0.0047 0.00000392193 0.00159608 0.0073 0.1407 0.016 0.004 0.0114 0.0395 0.6251 0.0146 0.002 0.0014 0.0731 0.0279 0.0012 0.0038 0.001 0.00297476 0.00190616 0.00332850 0.00353305 0.00205165 0.00525492 0.00215096 0.0006 0.0003" + fraction_type = 'wo' + density_units = 'g/cm3' + block = 1 + density = 8 + [] + + [endf_nuclear_data] + type = FispactNuclearDataPaths + base_path = "/Projects/FispactNuclearData/" + ND_IND_NUC_KEY = "ENDFB80data/endfb80_index" + ND_XS_ENDF_KEY = "ENDFB80data/endfb80-n/gxs-709" + ND_FY_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80nfy" + ND_SF_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80sfy" + ND_DK_ENDF_KEY = "ENDFB80data/decay" + ND_ABSORP_KEY = "decay/abs_2012" + [] +[] + + +[Executioner] + type = Steady +[] + + + + + diff --git a/tutorials/tutorial_2/input.i b/tutorials/tutorial_2/input.i new file mode 100644 index 0000000..84661fe --- /dev/null +++ b/tutorials/tutorial_2/input.i @@ -0,0 +1,112 @@ +[Mesh] + [fmg] + type = FileMeshGenerator + file = "../geometry/cube.e" + [] +[] + +[Problem] + type = FispactProblem + + molar_mass_data = '../../molar_masses.h5' + + output_inventory_time = 1e5 + + fispact_schedule_uo = 'Schedule' + fispact_nuclear_data_uo = 'endf_nuclear_data' + fispact_input_flux_uo = 'InputFlux' +[] + +[AuxVariables] + [Nb93_atoms] + family = MONOMIAL + order = CONSTANT + [] + [atoms] + family = MONOMIAL + order = CONSTANT + [] +[] + +[AuxKernels] + [Nb93_atoms] + type = FispactNuclideKernel + variable = Nb93_atoms + nuclide = "Nb93" + metric = "ATOMS" + [] + [atoms_kernel] + type = FispactElementKernel + variable = atoms + metric = "INVENTORY_TOTAL_ATOMS" + [] +[] + +[UserObjects] + [InputFlux] + type = OpenMCFluxInput + statepoint_filename = '../statepoint_neutrons.10.h5' + energy_filter_id = 2 + flux_tally_id = 2 + wall_loading = 10 + [] + + [Schedule] + type = FispactSchedule + times = '1e5 1e4 1e4 2e5 2e5 2e5 5e5 5e5 2e5' + flux_amplitude = '1e10 0 0 0 0 0 0 0 0' + [] + + [steel] + type = FispactMaterial + material_type = FUEL + nuclides = "B10 B11 C12 C13 Si28 V50 V51 Cr50 Cr52 Cr53 Cr54 Mn55 Fe54 Fe56 Fe57 Fe58 Co59 Ni58 Ni60 Ni61 Ni62 Ni64 Mo92 Mo94 Mo95 Mo96 Mo97 Mo98 Mo100 Cu63 Cu65" + nuclide_fraction = "0.00000693 0.0000281 0.000395203 0.00000479726 0.0047 0.00000392193 0.00159608 0.0073 0.1407 0.016 0.004 0.0114 0.0395 0.6251 0.0146 0.002 0.0014 0.0731 0.0279 0.0012 0.0038 0.001 0.00297476 0.00190616 0.00332850 0.00353305 0.00205165 0.00525492 0.00215096 0.0006 0.0003" + fraction_type = 'wo' + density_units = 'g/cm3' + block = 1 + density = 8 + [] + + [endf_nuclear_data] + type = FispactNuclearDataPaths + base_path = "/home/bill/Projects/FispactNuclearData/" + ND_IND_NUC_KEY = "ENDFB80data/endfb80_index" + ND_XS_ENDF_KEY = "ENDFB80data/endfb80-n/gxs-709" + ND_FY_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80nfy" + ND_SF_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80sfy" + ND_DK_ENDF_KEY = "ENDFB80data/decay" + ND_ABSORP_KEY = "decay/abs_2012" + [] +[] + + +[Postprocessors] + [photon_emission] + type = ElementPhotonEmission + element_ids = '14 15' + [] + + [nuclide_contribution] + type = FispactNuclideMetric + nuclides = "Cr51" + metric = "DOSE" + [] + + + [inv_dose] + type = FispactInventoryMetric + metric = "INVENTORY_DOSE_RATE" + [] +[] + +[Executioner] + type = Steady +[] + +[Outputs] + exodus = true +[] + + + diff --git a/tutorials/tutorial_2/input_out.e b/tutorials/tutorial_2/input_out.e new file mode 100644 index 0000000..02ac40a Binary files /dev/null and b/tutorials/tutorial_2/input_out.e differ diff --git a/tutorials/tutorial_3/input.i b/tutorials/tutorial_3/input.i new file mode 100644 index 0000000..ebf5a65 --- /dev/null +++ b/tutorials/tutorial_3/input.i @@ -0,0 +1,122 @@ +[Mesh] + [fmg] + type = FileMeshGenerator + file = "../../geometry/cube.e" + [] +[] + +[Problem] + type = FispactProblem + + molar_mass_data = '../../molar_masses.h5' + + output_inventory_time = 1e5 + + fispact_schedule_uo = 'Schedule' + fispact_nuclear_data_uo = 'endf_nuclear_data' + fispact_input_flux_uo = 'InputFlux' +[] + +[AuxVariables] + [Nb93_atoms] + family = MONOMIAL + order = CONSTANT + [] + [atoms] + family = MONOMIAL + order = CONSTANT + [] +[] + +[AuxKernels] + [Nb93_atoms] + type = FispactNuclideKernel + variable = Nb93_atoms + nuclide = "Nb93" + metric = "ATOMS" + [] + [atoms_kernel] + type = FispactElementKernel + variable = atoms + metric = "INVENTORY_TOTAL_ATOMS" + [] +[] + +[UserObjects] + [InputFlux] + type = OpenMCFluxInput + statepoint_filename = '../statepoint_neutrons.10.h5' + energy_filter_id = 2 + flux_tally_id = 2 + wall_loading = 10 + [] + + [Schedule] + type = FispactSchedule + times = '1e5 1e4 1e4 2e5 2e5 2e5 5e5 5e5 2e5' + flux_amplitude = '1e10 0 0 0 0 0 0 0 0' + [] + + [steel] + type = FispactMaterial + material_type = FUEL + nuclides = "B10 B11 C12 C13 Si28 V50 V51 Cr50 Cr52 Cr53 Cr54 Mn55 Fe54 Fe56 Fe57 Fe58 Co59 Ni58 Ni60 Ni61 Ni62 Ni64 Mo92 Mo94 Mo95 Mo96 Mo97 Mo98 Mo100 Cu63 Cu65" + nuclide_fraction = "0.00000693 0.0000281 0.000395203 0.00000479726 0.0047 0.00000392193 0.00159608 0.0073 0.1407 0.016 0.004 0.0114 0.0395 0.6251 0.0146 0.002 0.0014 0.0731 0.0279 0.0012 0.0038 0.001 0.00297476 0.00190616 0.00332850 0.00353305 0.00205165 0.00525492 0.00215096 0.0006 0.0003" + fraction_type = 'wo' + density_units = 'g/cm3' + block = 1 + density = 8 + [] + + [endf_nuclear_data] + type = FispactNuclearDataPaths + base_path = "/home/bill/Projects/FispactNuclearData/" + ND_IND_NUC_KEY = "ENDFB80data/endfb80_index" + ND_XS_ENDF_KEY = "ENDFB80data/endfb80-n/gxs-709" + ND_FY_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80nfy" + ND_SF_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80sfy" + ND_DK_ENDF_KEY = "ENDFB80data/decay" + ND_ABSORP_KEY = "decay/abs_2012" + [] +[] + + +[Postprocessors] + [photon_emission] + type = ElementPhotonEmission + element_ids = '14 15' + [] + + [nuclide_contribution] + type = FispactNuclideMetric + nuclides = "Cr51" + metric = "DOSE" + [] +[] + + +[Times] + [FizzyTimes] + type = FispactScheduleTimes + FispactScheduleName = Schedule + [] +[] + + +[Executioner] + type = Transient + + [TimeStepper] + type = TimeSequenceFromTimes + times = FizzyTimes + use_last_t_for_end_time = True + [] +[] + + +[Outputs] + exodus = true +[] + + + diff --git a/tutorials/tutorial_3/input_out.e b/tutorials/tutorial_3/input_out.e new file mode 100644 index 0000000..bd0166e Binary files /dev/null and b/tutorials/tutorial_3/input_out.e differ diff --git a/tutorials/tutorial_4/input.i b/tutorials/tutorial_4/input.i new file mode 100644 index 0000000..78b0fcf --- /dev/null +++ b/tutorials/tutorial_4/input.i @@ -0,0 +1,143 @@ +[Mesh] + [fmg] + type = FileMeshGenerator + file = "../geometry/cube.e" + [] +[] + +[Problem] + type = FispactProblem + + molar_mass_data = '../../molar_masses.h5' + comm_photon_flux = True + + output_inventory_time = 1e5 + + fispact_schedule_uo = 'Schedule' + fispact_nuclear_data_uo = 'endf_nuclear_data' + fispact_input_flux_uo = 'InputFlux' +[] + +[AuxVariables] + [Nb93_atoms] + family = MONOMIAL + order = CONSTANT + [] + [atoms] + family = MONOMIAL + order = CONSTANT + [] + [Photon_flux] + family = MONOMIAL + order = CONSTANT + [] +[] + +[AuxKernels] + [Nb93_atoms] + type = FispactNuclideKernel + variable = Nb93_atoms + nuclide = "Nb93" + metric = "ATOMS" + [] + [atoms_kernel] + type = FispactElementKernel + variable = atoms + metric = "INVENTORY_TOTAL_ATOMS" + [] +[] + +[UserObjects] + [InputFlux] + type = OpenMCFluxInput + statepoint_filename = '../statepoint_neutrons.10.h5' + energy_filter_id = 2 + flux_tally_id = 2 + wall_loading = 10 + [] + + [Schedule] + type = FispactSchedule + times = '1e5 1e4 1e4 2e5 2e5 2e5 5e5 5e5 2e5' + flux_amplitude = '1e10 0 0 0 0 0 0 0 0' + [] + + [steel] + type = FispactMaterial + material_type = FUEL + nuclides = "B10 B11 C12 C13 Si28 V50 V51 Cr50 Cr52 Cr53 Cr54 Mn55 Fe54 Fe56 Fe57 Fe58 Co59 Ni58 Ni60 Ni61 Ni62 Ni64 Mo92 Mo94 Mo95 Mo96 Mo97 Mo98 Mo100 Cu63 Cu65" + nuclide_fraction = "0.00000693 0.0000281 0.000395203 0.00000479726 0.0047 0.00000392193 0.00159608 0.0073 0.1407 0.016 0.004 0.0114 0.0395 0.6251 0.0146 0.002 0.0014 0.0731 0.0279 0.0012 0.0038 0.001 0.00297476 0.00190616 0.00332850 0.00353305 0.00205165 0.00525492 0.00215096 0.0006 0.0003" + fraction_type = 'wo' + density_units = 'g/cm3' + block = 1 + density = 8 + [] + + [endf_nuclear_data] + type = FispactNuclearDataPaths + base_path = "/Projects/FispactNuclearData/" + ND_IND_NUC_KEY = "ENDFB80data/endfb80_index" + ND_XS_ENDF_KEY = "ENDFB80data/endfb80-n/gxs-709" + ND_FY_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80nfy" + ND_SF_ENDF_KEY = "ENDFB80data/endfb80-n/endfb80sfy" + ND_DK_ENDF_KEY = "ENDFB80data/decay" + ND_ABSORP_KEY = "decay/abs_2012" + [] +[] + + +[Postprocessors] + [photon_emission] + type = ElementPhotonEmission + element_ids = '14 15' + [] + + [nuclide_contribution] + type = FispactNuclideMetric + nuclides = "Cr51" + metric = "DOSE" + [] +[] + +[Transfers] + [Photon_flux_from_cardinal] + type = MultiAppCopyTransfer + source_variable = 'photon_flux_photon' + variable = Photon_flux + from_multi_app='photons' + [../] +[] + +[MultiApps] + [photons] + type = TransientMultiApp + execute_on = timestep_end + app_type = 'CardinalApp' + input_files = '/Projects/Fizzy/inputs/r2s_time/photons_input.i' + library_path = '/Projects/cardinal/lib/' + library_name = 'libcardinal-opt.la' + [] +[] + +[Times] + [FizzyTimes] + type = FispactScheduleTimes + FispactScheduleName = Schedule + [] +[] + +[Executioner] + type = Transient + [TimeStepper] + type = TimeSequenceFromTimes + times = FizzyTimes + use_last_t_for_end_time = True + [] +[] + +[Outputs] + exodus = true +[] + + + diff --git a/tutorials/tutorial_4/openmc_inputs.xml/geometry.xml b/tutorials/tutorial_4/openmc_inputs.xml/geometry.xml new file mode 100644 index 0000000..53bd1c3 --- /dev/null +++ b/tutorials/tutorial_4/openmc_inputs.xml/geometry.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/tutorials/tutorial_4/openmc_inputs.xml/materials.xml b/tutorials/tutorial_4/openmc_inputs.xml/materials.xml new file mode 100644 index 0000000..8abd77f --- /dev/null +++ b/tutorials/tutorial_4/openmc_inputs.xml/materials.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tutorials/tutorial_4/openmc_inputs.xml/settings.xml b/tutorials/tutorial_4/openmc_inputs.xml/settings.xml new file mode 100644 index 0000000..6d006c0 --- /dev/null +++ b/tutorials/tutorial_4/openmc_inputs.xml/settings.xml @@ -0,0 +1,16 @@ + + + fixed source + 50000 + 10 + 0 + + + false + false + + ttb + continuous-energy + true + 10000 + diff --git a/tutorials/tutorial_4/openmc_inputs.xml/tallies.xml b/tutorials/tutorial_4/openmc_inputs.xml/tallies.xml new file mode 100644 index 0000000..360edf5 --- /dev/null +++ b/tutorials/tutorial_4/openmc_inputs.xml/tallies.xml @@ -0,0 +1,17 @@ + + + + /Projects/Fizzy/geometry/cube.e + + + 1 + + + photon + + + 1 2 + flux + collision + + diff --git a/tutorials/tutorial_4/openmc_photon.py b/tutorials/tutorial_4/openmc_photon.py new file mode 100644 index 0000000..dc90236 --- /dev/null +++ b/tutorials/tutorial_4/openmc_photon.py @@ -0,0 +1,96 @@ +#!/usr/env/python3 + +import openmc +import openmc.lib +import os +import sys +import csv +import h5py + + +def make_model(compiled_source, mesh_id, temperature=296): + + model = openmc.Model() + model.settings.dagmc = True + # steel + steel = openmc.Material(name="steel", temperature=temperature) + + steel.set_density("g/cm3", 8.0) + steel.add_nuclide("B10", 0.000693, "wo") + steel.add_nuclide("B11", 0.002807, "wo") + steel.add_nuclide("C12", 0.039520273803427465, "wo") + steel.add_nuclide("C13", 0.000479726196572539, "wo") + steel.add_nuclide("Si28", 0.47, "wo") + steel.add_nuclide("V50", 0.0003921925373160739, "wo") + steel.add_nuclide("V51", 0.15960780746268394, "wo") + steel.add_nuclide("Cr50", 0.73, "wo") + steel.add_nuclide("Cr52", 14.07, "wo") + steel.add_nuclide("Cr53", 1.6, "wo") + steel.add_nuclide("Cr54", 0.4, "wo") + steel.add_nuclide("Mn55", 1.14, "wo") + steel.add_nuclide("Fe54", 3.95, "wo") + steel.add_nuclide("Fe56", 62.51, "wo") + steel.add_nuclide("Fe57", 1.46, "wo") + steel.add_nuclide("Fe58", 0.2, "wo") + steel.add_nuclide("Co59", 0.14, "wo") + steel.add_nuclide("Ni58", 7.31, "wo") + steel.add_nuclide("Ni60", 2.79, "wo") + steel.add_nuclide("Ni61", 0.12, "wo") + steel.add_nuclide("Ni62", 0.38, "wo") + steel.add_nuclide("Ni64", 0.1, "wo") + steel.add_nuclide("Mo92", 0.2974760972643644, "wo") + steel.add_nuclide("Mo94", 0.1906159496693566, "wo") + steel.add_nuclide("Mo95", 0.33284984504744625, "wo") + steel.add_nuclide("Mo96", 0.3533051306488447, "wo") + steel.add_nuclide("Mo97", 0.20516502475964524, "wo") + steel.add_nuclide("Mo98", 0.5254922939545649, "wo") + steel.add_nuclide("Mo100", 0.21509565865577795, "wo") + steel.add_nuclide("Cu63", 0.06, "wo") + steel.add_nuclide("Cu65", 0.03, "wo") + + materials = openmc.Materials() + materials.append(steel) + + model.materials = materials + + surf = openmc.Sphere(r=250, surface_id=99999, boundary_type="vacuum") + dag = openmc.DAGMCUniverse("/Projects/Fizzy/geometry/cube_dag.h5m", name='daguni', universe_id=42) + + cell = openmc.Cell(fill=dag, region=-surf, cell_id=99999) + + mesh = openmc.UnstructuredMesh( + filename='/Projects/Fizzy/geometry/cube.e', library='libmesh', mesh_id=1) + + mesh_filter = openmc.MeshFilter(mesh) + photon_filter = openmc.ParticleFilter("photon") + + photon_flux_tally = openmc.Tally(name="photon_flux") + photon_flux_tally.filters = [mesh_filter, photon_filter] + photon_flux_tally.scores = ['flux'] + photon_flux_tally.estimator = 'collision' + + model.tallies = [photon_flux_tally] + + model.geometry = openmc.Geometry([cell]) + model.settings.batches = 10 + model.settings.inactive = 0 + model.settings.output = {"summary": False, + "tallies": False} + # 1e10 histories per batch + model.settings.particles = 50000 + model.settings.photon_transport = True + model.settings.electron_treatment = 'ttb' + model.settings.run_mode = 'fixed source' + model.settings.energy_mode = 'continuous-energy' + # model.settings.sourcepoint = sourcepoint + model.settings.max_tracks = 10000 + + model.settings.source = openmc.CompiledSource( + compiled_source, mesh_id) + return model + + +model = make_model( + '/Projects/FizzyCompiledSource/build/libCompiledSource.so', '1') + +model.export_to_xml("./openmc_inputs.xml") diff --git a/tutorials/tutorial_4/photons_input.i b/tutorials/tutorial_4/photons_input.i new file mode 100644 index 0000000..9c4be51 --- /dev/null +++ b/tutorials/tutorial_4/photons_input.i @@ -0,0 +1,32 @@ +[Mesh] + type = FileMesh + file = "../geometry/cube.e" +[] + +[Problem] + type = OpenMCCellAverageProblem + cell_level = 0 + source_strength = 1 + xml_directory = './openmc_inputs.xml' + [Tallies] + [photon_flux] + type = MeshTally + filters = 'Photon' + name = 'photon_flux' + score = 'flux' + [] + [] + + [Filters] + [Photon] + type = ParticleFilter + particles = 'photon' + [] + [] +[] + +[Executioner] + type = Transient + dt = 1e7 +[] + diff --git a/unit/Makefile b/unit/Makefile index d3caace..847afe4 100644 --- a/unit/Makefile +++ b/unit/Makefile @@ -48,10 +48,30 @@ include $(MOOSE_DIR)/modules/modules.mk ADDITIONAL_INCLUDES := -I$(FRAMEWORK_DIR)/contrib/gtest ADDITIONAL_LIBS := $(FRAMEWORK_DIR)/contrib/gtest/libgtest.la +PUGIXML_DIR ?= $(MOOSE_DIR)/../pugixml/ +PUGIXML_INCLUDES ?= -I $(PUGIXML_DIR)/src/ +PUGIXML_LIB_DIR ?= ${PUGIXML_DIR}/build/ + +HDF5_DIR ?= /usr/lib/x86_64-linux-gnu/hdf5/openmpi/lib/ + +ADDITIONAL_LIBS += -L$(PUGIXML_LIB_DIR) -lpugixml -L$(HDF5_DIR) -lhdf5 -lspdlog +ADDITIONAL_CPPFLAGS += $(FISPACT_INCLUDES) ${PUGIXML_INCLUDES} -DFIZZY_UNIT_TEST # dep apps CURRENT_DIR := $(shell pwd) APPLICATION_DIR := $(CURRENT_DIR)/.. APPLICATION_NAME := fizzy + +FISPACT_STUB_DIR := $(CURRENT_DIR)/stubs +FISPACT_STUB_LIB := $(FISPACT_STUB_DIR)/libfispact_stub.a + +$(FISPACT_STUB_LIB): $(FISPACT_STUB_DIR)/fispact_stub.C + $(libmesh_CXX) $(libmesh_CXXFLAGS) -c $< -o $(FISPACT_STUB_DIR)/fispact_stub.o + ar rcs $@ $(FISPACT_STUB_DIR)/fispact_stub.o + +ADDITIONAL_LIBS += $(FISPACT_STUB_LIB) + +all: $(FISPACT_STUB_LIB) + include $(FRAMEWORK_DIR)/app.mk APPLICATION_DIR := $(CURRENT_DIR) diff --git a/unit/include/FispactMaterialTest.h b/unit/include/FispactMaterialTest.h new file mode 100644 index 0000000..28199a4 --- /dev/null +++ b/unit/include/FispactMaterialTest.h @@ -0,0 +1,29 @@ +#include "FizzyObjectUnitTest.h" + +class FispactMaterialTests : public FizzyObjectUnitTest { +public: + FispactMaterialTests() : FizzyObjectUnitTest("FizzyApp") { buildObjects(); } + +protected: + void buildObjects() { + + InputParameters pars_mat1 = _factory.getValidParams("FispactMaterial"); + + pars_mat1.set("material_type") = "FUEL"; + pars_mat1.set>("nuclides") = {"H1"}; + pars_mat1.set>("nuclide_fraction") = {1}; + pars_mat1.set("density") = 1; + pars_mat1.set("density_units") = "g/cm3"; + pars_mat1.set("fraction_type") = "wo"; + pars_mat1.set>("block") = {"1"}; + + _fe_problem->addObject("FispactMaterial", "test_mat_1", + pars_mat1); + + _mat1 = &_fe_problem->getUserObject("test_mat_1"); + } + + FispactMaterial *_mat1; + // const FispactFluxInput *; + // const FispactNuclearDataPaths *; +}; diff --git a/unit/include/FizzyObjectUnitTest.h b/unit/include/FizzyObjectUnitTest.h new file mode 100644 index 0000000..3e338b1 --- /dev/null +++ b/unit/include/FizzyObjectUnitTest.h @@ -0,0 +1,134 @@ +//* This file is part of the MOOSE framework +//* https://mooseframework.inl.gov +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#pragma once + +#include "gtest/gtest.h" +#include + +#include "AppFactory.h" +#include "FEProblem.h" +#include "FileMesh.h" +#include "FileMeshGenerator.h" +#include "FispactProblem.h" +#include "MooseMain.h" +#include "MooseMesh.h" + +/** + * Base class for building basic unit tests for MOOSE objects that can live + * alone (like user objects, etc.) + * + * This class builds the basic objects that are needed in order to test a MOOSE + * object. Those are a mesh and an FEProblem. To build a unit test, inherit + * from this class and build your test using the following template: + * + * In your .h file: + * + * class MyUnitTest : public MooseObjectUnitTest + * { + * public: + * MyUnitTest() : MooseObjectUnitTest("MyAppUnitApp") + * { + * // if you are using the old registration system, you want to register + * your objects using this + * // call. Otherwise, you do not need it. + * registerObjects(_factory); + * buildObjects(); + * } + * + * protected: + * void registerObjects(Factory & factory) + * { + * // register your objects as usual, we have to be in a method like this so + * that the register + * // macros work + * registerUserObject(MyObjectThatIAmTesting); + * } + * + * void buildObjects() + * { + * // build your object like so + * InputParameters pars = _factory.getValidParams("MyObjectThatIAmTesting"); + * _fe_problem->addUserObject("MyObjectThatIAmTesting", "fp", uo_pars); + * _obj = &_fe_problem->getUserObject("fp"); + * } + * + * // member variable used later in the actual tests + * const MyObjectThatIAmTesting * _obj; + * }; + * + * In your .C file + * + * TEST_F(MyObjectThatIAmTesting, test) + * { + * EXPECT_EQ("testing", _obj->method(par1, par2)); + * } + * + * NOTE: Testing mesh-bound objects like Kernels, BCs, etc. is not possible with + * this class. + */ +class FizzyObjectUnitTest : public ::testing::Test { +public: + /** + * @param app_name The name of client's application + */ + FizzyObjectUnitTest(const std::string &app_name) + : _app(Moose::createMooseApp(app_name, 0, nullptr)), + _factory(_app->getFactory()) { + buildObjects(); + } + +protected: + void buildObjects() { + + InputParameters mesh_params = _factory.getValidParams("FileMesh"); + mesh_params.set("file") = "../geometry/cube.e"; + + _mesh = _factory.createUnique("FileMesh", "name1", mesh_params); + _mesh->setMeshBase(_mesh->buildMeshBaseObject()); + _mesh->buildMesh(); + _mesh->init(); + _mesh->prepare(&_mesh->getMesh()); + + InputParameters problem_params = _factory.getValidParams("FispactProblem"); + problem_params.set("mesh") = _mesh.get(); + problem_params.set(MooseBase::name_param) = "name2"; + problem_params.set("fispact_schedule_uo") = "name2"; + problem_params.set("fispact_nuclear_data_uo") = "name2"; + problem_params.set("fispact_input_flux_uo") = "name2"; + problem_params.set("molar_mass_data") = "molar_mass_mock.h5"; + _fe_problem = _factory.create("FispactProblem", "problem", + problem_params); + + _fe_problem->createQRules(libMesh::QGAUSS, libMesh::FIRST, libMesh::FIRST, + libMesh::FIRST); + + _fe_problem->callFispactFactory(); + + _app->actionWarehouse().problemBase() = _fe_problem; + } + + template + T &addObject(const std::string &type, const std::string &name, + InputParameters ¶ms); + + std::unique_ptr _mesh; + std::shared_ptr _app; + Factory &_factory; + std::shared_ptr _fe_problem; +}; + +template +T &FizzyObjectUnitTest::addObject(const std::string &type, + const std::string &name, + InputParameters ¶ms) { + auto objects = _fe_problem->addObject(type, name, params); + mooseAssert(objects.size() == 1, "Doesn't work with threading"); + return *objects[0]; +} diff --git a/unit/include/FizzyProblemUnitTest.h b/unit/include/FizzyProblemUnitTest.h new file mode 100644 index 0000000..e69de29 diff --git a/unit/include/fispact/mock/FispactContextMock.h b/unit/include/fispact/mock/FispactContextMock.h new file mode 100644 index 0000000..af3c869 --- /dev/null +++ b/unit/include/fispact/mock/FispactContextMock.h @@ -0,0 +1,240 @@ + +#pragma once +#include "FispactContextBase.h" + +#include +#include + +class IMockFispactOutputNuclideData : public FispactOutputNuclideDataBase { + +public: + IMockFispactOutputNuclideData( + const std::string &name, const std::string &state, const int &isotope, + const int &zai, const double &hl, const double &atoms, + const double &grams, const double &activity, const double &a_act, + const double &b_act, const double &g_act, const double &total_heat, + const double &a_heat, const double &b_heat, const double &c_heat, + const double &g_heat, const double &ingestion, const double &inhalation) + : FispactOutputNuclideDataBase(), _name(name), _state(state), _zai(zai), + _isotope(isotope), _hl(hl), _atoms(atoms), _grams(grams), + _activity(activity), _a_act(a_act), _b_act(b_act), _g_act(g_act), + _total_heat(total_heat), _a_heat(a_heat), _b_heat(b_heat), + _g_heat(g_heat), _ingestion(ingestion), _inhalation(inhalation) {} + + virtual std::string getElement() const { return _name; } + + virtual std::string getState() { return "state"; } + + virtual int getIsotope() const { return _isotope; } + + virtual int getZAI() const { return _zai; } + + // The half life (s) + virtual double getHalfLife() const { return _hl; } + // The number of atoms + virtual double getAtoms() const { return _atoms; } + // The grams (g) + virtual double getGrams() const { return _grams; } + // The activity (Bq) + virtual double getActivity() const { return _activity; } + // The alpha fraction of the activity (Bq) + virtual double getAlphaActivity() const { return _a_act; } + // The beta fraction of the activity (Bq) + virtual double getBetaActivity() const { return _b_act; } + // The gamma fraction of the activity (Bq) + virtual double getGammaActivity() const { return _g_act; } + // The total heat (kW) + virtual double getTotalHeat() const { return _total_heat; } + // The alpha heat (kW) + virtual double getAlphaHeat() const { return _a_heat; } + // The beta heat (kW) + virtual double getBetaHeat() const { return _b_heat; } + // The gamma heat (kW) + virtual double getGammaHeat() const { return _g_heat; } + // The dose rate (Sv/hr) + virtual double getDoseRate() const { return _dose; } + // The ingestion (Sv) + virtual double getIngestion() const { return _ingestion; } + // The inhalation (Sv) + virtual double getInhalation() const { return _inhalation; } + +protected: + std::string _name; + std::string _state; + int _zai; + int _isotope; + double _hl, _atoms, _grams, _activity, _a_act, _b_act, _g_act, _total_heat, + _a_heat, _b_heat, _g_heat, _dose, _ingestion, _inhalation; +}; + +// IFispactInputData +class IMockFispactInputData : public IFispactInputDataBase { + +public: + IMockFispactInputData() : IFispactInputDataBase() {} + + virtual void setFlux(const std::vector &flux_energy_groups, + const std::vector &flux) {} + + virtual void setFluxWallLoading(double wall_loading) {} + + virtual void setExcludeXrays(bool enable) {} + + virtual void setFluxName(std::string flux_name) {} + + virtual void setDensity(double density) {} + + virtual void setMassTotal(double total_mass) {} + + virtual void setMass(const std::vector &atomicnumbers, + const std::vector &percentages) {} + + virtual void setFuel(const std::vector &zais, + const std::vector &values) {} + + virtual void setSchedule(const std::vector &deltatime, + const std::vector &fluxamp) {} + + virtual std::pair, std::vector> getSchedule() { + return schedule; + } + + virtual void setSolverTolerance(double rtol, double atol) { + this->rtol = rtol; + this->atol = atol; + } + + virtual void setAtomsThreshold(double threshold) {} + +private: + double rtol, atol; + std::pair, std::vector> schedule; +}; +//~IFispactInputData + +// IFispactOutputData +class IMockFispactOutputData : public IFispactOutputDataBase { + +public: + IMockFispactOutputData() : IFispactOutputDataBase() {} + + virtual std::vector getGammaSpectrumBins(int inv_index) { + std::vector vec = {1, 1, 1}; + return vec; + }; + + virtual std::vector getGammaSpectrumBoundaries(int inv_index) { + std::vector vec = {1, 1, 1}; + return vec; + }; + + virtual std::vector> + getInventoryNuclides(int inventory_index) { + + std::vector> nuclide_data; + nuclide_data.reserve(1); + + // nuclide_data.push_back(std::make_unique("H1", + // "liquid", 1, 1, 0.4, 0, 100, 1, 1, 1, 1,1,1)); + + return nuclide_data; + } + + virtual std::pair, std::vector> + getSortedInventory(int, inventory_outputs::InventoryOutputsEnum) const { + std::vector zais = {1, 2, 3}; + std::vector value = {1, 2, 3}; + + return std::pair, std::vector>(zais, value); + } + + virtual double getInventoryValue(int, + inventory_outputs::InventoryOutputsEnum) { + return 1.0; + } + + virtual int findInventoryIndex(int, int) { return 1; }; + + virtual bool findInventoryExists(int inv_index, int zai) { return true; } + +private: +}; +//~IFispactOutputData + +class IMockFispactUtils : public IFispactUtilsBase { + +public: + IMockFispactUtils() : IFispactUtilsBase() {} + + virtual int GetZai(std::string nuclidename) { + if (nuclidename == "H1") { + return 4; + } + + else if (nuclidename == "H2") { + return 5; + } + + else if (nuclidename == "He3") { + return 6; + } + return -1; + } + + virtual int GetAtomicNumberFromElementName(std::string elementname) const { + return 1; + } + + virtual std::vector + GroupConvertByEnergy(const std::vector &inbounds, + const std::vector &invals, + const std::vector &outbounds) { + return invals; + } + + virtual std::vector + GroupConvertByLethargy(const std::vector &inbounds, + const std::vector &invals, + const std::vector &outbounds) { + return invals; + } + + virtual std::string getNuclideName(int zai) { return "zai"; }; + + virtual int GetAtomicNumberFromElementName(std::string elementname) { + return 1; + } + + virtual std::vector getNeutronEnergyBounds(size_t n_groups) { + return {1, 2, 3}; + } + + virtual std::vector getPhotonEnergyBounds(size_t n_groups) { + return {1, 2, 3}; + }; + +private: +}; + +class FispactContextMock : public FispactContextBase { +public: + FispactContextMock() : FispactContextBase() { + + _i_input_data = std::make_unique(); + _i_output_data = std::make_unique(); + _i_utils = std::make_unique(); + } + + virtual void globalInitialise() {} + + virtual void globalFinalise() {} + + virtual void process() {} + + virtual size_t getNuclearDataCrossSections() { return 709; } + + virtual void setNuclearData( + std::unordered_map nuclear_data_paths) {} + +private: +}; diff --git a/unit/molar_mass_mock.h5 b/unit/molar_mass_mock.h5 new file mode 100644 index 0000000..f3a131e Binary files /dev/null and b/unit/molar_mass_mock.h5 differ diff --git a/unit/src/FispactMaterialTests.C b/unit/src/FispactMaterialTests.C new file mode 100644 index 0000000..86f8335 --- /dev/null +++ b/unit/src/FispactMaterialTests.C @@ -0,0 +1,50 @@ +#include "FispactMaterialTest.h" +#include "gtest/gtest.h" + +TEST_F(FispactMaterialTests, get_average_molar_mass) { + + std::vector nuclide_names = {"H1", "He3"}; + std::vector nuclide_fractions = {0.5, 0.5}; + std::string fraction_type = "wo"; + + EXPECT_DOUBLE_EQ(_mat1->getAverageMolarMass(nuclide_names, nuclide_fractions, + fraction_type), + 1.5); + + fraction_type = "ao"; + + EXPECT_DOUBLE_EQ(_mat1->getAverageMolarMass(nuclide_names, nuclide_fractions, + fraction_type), + 2); + + nuclide_names = {"H1", "H2", "He3"}; + nuclide_fractions = {0.1, 0.4, 0.6}; + fraction_type = "wo"; + + EXPECT_DOUBLE_EQ(_mat1->getAverageMolarMass(nuclide_names, nuclide_fractions, + fraction_type), + 2); + + fraction_type = "ao"; + + EXPECT_DOUBLE_EQ(_mat1->getAverageMolarMass(nuclide_names, nuclide_fractions, + fraction_type), + 2.7); +} + +TEST_F(FispactMaterialTests, convertAtomToMassFraction) { + + std::vector nuclide_names = {"H1", "He3"}; + std::vector nuclide_fractions = {0.5, 0.5}; + std::string fraction_type = "ao"; + + double average_molar_mass = _mat1->getAverageMolarMass( + nuclide_names, nuclide_fractions, fraction_type); + + _mat1->convertFromAtomToMassFraction(nuclide_names, nuclide_fractions, + average_molar_mass); + + std::vector expected_mass_frac = {0.25, 0.75}; + + EXPECT_EQ(nuclide_fractions, expected_mass_frac); +} diff --git a/unit/src/FispactProblemTests.C b/unit/src/FispactProblemTests.C new file mode 100644 index 0000000..14c2820 --- /dev/null +++ b/unit/src/FispactProblemTests.C @@ -0,0 +1,117 @@ +#include "AverageElementSize.h" +#include "FizzyObjectUnitTest.h" +#include "gtest/gtest.h" +#include + +class FispactProblemTest : public FizzyObjectUnitTest { +public: + FispactProblemTest() : FizzyObjectUnitTest("FizzyApp") {} +}; + +TEST_F(FispactProblemTest, isFlux) { + + std::vector no_flux({0, 0, 0, 0}); + std::vector flux({1, 0, 0, 0}); + EXPECT_TRUE(_fe_problem->isFlux(flux)); + EXPECT_FALSE(_fe_problem->isFlux(no_flux)); +} + +TEST_F(FispactProblemTest, convertGammaEvToCount) { + _fe_problem->setPhotonBins({0, 2, 6, 10}); + std::vector input = {1, 2, 3}; + std::vector output; + _fe_problem->convertGammaEvToCount(input, output); + EXPECT_EQ(output, std::vector({1e6, 5e5, 3.75e5})); +} + +TEST_F(FispactProblemTest, loadMolarMasses) { + + const std::unordered_map &molar_masses = + _fe_problem->getMolarMassMap(); + + std::vector zais; + + std::vector masses; + + EXPECT_EQ(molar_masses.at("H1"), 1); + EXPECT_EQ(molar_masses.at("H2"), 2); + EXPECT_EQ(molar_masses.at("He3"), 3); + + EXPECT_NE(molar_masses.at("H1"), 4); + + EXPECT_THROW(molar_masses.at("H33"), std::out_of_range); +} + +// class FispactProblemTestUserObjects : public FizzyObjectUnitTest { +// public: +// FispactProblemTestUserObjects() : FizzyObjectUnitTest("FizzyApp") { +// buildObjects(); +// } +// +// protected: +// void buildObjects() { +// +// InputParameters pars_mat1 = _factory.getValidParams("FispactMaterial"); +// +// pars_mat1.set("material_type") = "FUEL"; +// pars_mat1.set>("nuclides") = {"H1"}; +// pars_mat1.set>("nuclide_fraction") = {100}; +// pars_mat1.set("density") = 1; +// pars_mat1.set("density_units") = "g/cm3"; +// pars_mat1.set("fraction_type") = "wo"; +// pars_mat1.set>("block") = {"1"}; +// _fe_problem->addObject("FispactMaterial", "Hydrogen", +// pars_mat1); +// _mat1 = &_fe_problem->getUserObject("Hydrogen"); +// } +// +// const FispactMaterial *_mat1; +// const FispactSchedule *_schedule; +// // const FispactFluxInput *; +// // const FispactNuclearDataPaths *; +// }; + +/// Test fixture to make sure getElementMaterial throws if two materials are +/// defined on the same block +class FispactProblemTestThrowMaterials : public FizzyObjectUnitTest { +public: + FispactProblemTestThrowMaterials() : FizzyObjectUnitTest("FizzyApp") { + buildObjects(); + } + +protected: + void buildObjects() { + + InputParameters pars_mat1 = _factory.getValidParams("FispactMaterial"); + InputParameters pars_mat2 = _factory.getValidParams("FispactMaterial"); + + pars_mat1.set("material_type") = "FUEL"; + pars_mat1.set>("nuclides") = {"H1"}; + pars_mat1.set>("nuclide_fraction") = {1}; + pars_mat1.set("density") = 1; + pars_mat1.set("density_units") = "g/cm3"; + pars_mat1.set("fraction_type") = "wo"; + pars_mat1.set>("block") = {"1"}; + _fe_problem->addObject("FispactMaterial", "Hydrogen", + pars_mat1); + _mat1 = &_fe_problem->getUserObject("Hydrogen"); + + pars_mat2.set("material_type") = "FUEL"; + pars_mat2.set>("nuclides") = {"He3"}; + pars_mat2.set>("nuclide_fraction") = {1}; + pars_mat2.set("density") = 3; + pars_mat2.set("density_units") = "g/cm3"; + pars_mat2.set("fraction_type") = "wo"; + pars_mat2.set>("block") = {"1"}; + _fe_problem->addUserObject("FispactMaterial", "Helium", pars_mat2); + _mat2 = &_fe_problem->getUserObject("Helium"); + } + + const FispactMaterial *_mat1; + const FispactMaterial *_mat2; +}; + +TEST_F(FispactProblemTestThrowMaterials, getElementMaterial) { + dof_id_type elem_id = _fe_problem->mesh().elemPtr(0)->id(); + EXPECT_THROW(_fe_problem->getElementMaterial(elem_id), std::runtime_error); +} diff --git a/unit/stubs/fispact_stub.C b/unit/stubs/fispact_stub.C new file mode 100644 index 0000000..a17a41b --- /dev/null +++ b/unit/stubs/fispact_stub.C @@ -0,0 +1,117 @@ +extern "C" { + +void FispactElementalDataGetAtomicDisplacementEnergy() {} +void FispactElementalDataGetNaturalIsotopeAbundances() {} +void FispactElementalDataGetNrOfNaturalIsotopes() {} +void FispactElementalDataGetRelativeAtomicMass() {} +void FispactElementalDataGetStandardDensity() {} +void FispactElementalDataReset() {} +void FispactElementalDataSetAtomicDisplacementEnergy() {} +void FispactElementalDataSetNaturalIsotopeAbundances() {} +void FispactElementalDataSetRelativeAtomicMass() {} +void FispactElementalDataSetStandardDensity() {} +void FispactFinalise() {} +void FispactGetAtomicNumberFromElementName() {} +void FispactGetNuclideName() {} +void FispactGetZai() {} +void FispactGroupConvertByEnergy() {} +void FispactGroupConvertByLethargy() {} +void FispactInitialise() {} +void FispactInputDataCreate() {} +void FispactInputDataGetSchedule() {} +void FispactInputDataGetScheduleNrOfEntries() {} +void FispactInputDataRead() {} +void FispactInputDataSetAtomsThreshold() {} +void FispactInputDataSetDensity() {} +void FispactInputDataSetFlux() {} +void FispactInputDataSetFluxName() {} +void FispactInputDataSetFluxWallLoading() {} +void FispactInputDataSetFuel() {} +void FispactInputDataSetMass() {} +void FispactInputDataSetMassTotal() {} +void FispactInputDataSetSchedule() {} +void FispactInputDataSetSolverTolerance() {} +void FispactInputDataWrite() {} +void FispactNuclearDataCreate() {} +void FispactNuclearDataDestroy() {} +void FispactNuclearDataGetReactionXS() {} +void FispactNuclearDataGetReactionXSNrOfBins() {} +void FispactNuclearDataReaderCreate() {} +void FispactNuclearDataReaderDestroy() {} +void FispactNuclearDataReaderGetKeyName() {} +void FispactNuclearDataReaderLoad() {} +void FispactNuclearDataReaderRead() {} +void FispactNuclearDataReaderSetPath() {} +void FispactNuclearDataReaderSetUseXSBinary() {} +void FispactNuclearDataReaderWrite() {} +void FispactNuclearDataWriteBinary() {} +void FispactOutputDataCreate() {} +void FispactOutputDataFindInventoryNuclideExists() {} +void FispactOutputDataFindInventoryNuclideIndex() {} +void FispactOutputDataGetInventoryDoseRate() {} +void FispactOutputDataGetInventoryGammaSpectrum() {} +void FispactOutputDataGetInventoryGammaSpectrumNrOfBins() {} +void FispactOutputDataGetInventoryNrOfNuclides() {} +void FispactOutputDataGetInventoryNuclideAtIndex() {} +void FispactOutputDataGetInventorySortedByKey() {} +void FispactOutputDataGetInventoryValueByKey() {} +void FispactOutputDataWrite() {} +void FispactProcess() {} +void FispactFilesDataReadKeys() {} +void FispactInputDataSetExcludeXrays() {} + +void MonitorCreate() {} +void MonitorDestroy() {} +void MonitorWriteToFile() {} + +int FISPACT_GROUP_100 = 0; +int FISPACT_GROUP_1102 = 0; +int FISPACT_GROUP_142 = 0; +int FISPACT_GROUP_162 = 0; +int FISPACT_GROUP_172 = 0; +int FISPACT_GROUP_175 = 0; +int FISPACT_GROUP_211 = 0; +int FISPACT_GROUP_315 = 0; +int FISPACT_GROUP_351 = 0; +int FISPACT_GROUP_586 = 0; +int FISPACT_GROUP_616 = 0; +int FISPACT_GROUP_66 = 0; +int FISPACT_GROUP_689 = 0; +int FISPACT_GROUP_69 = 0; +int FISPACT_GROUP_709 = 0; +int FISPACT_MAX_KEY_LENGTH = 0; +int FISPACT_ND_A2DATA_KEY = 0; +int FISPACT_ND_ABSORP_KEY = 0; +int FISPACT_ND_ASSCFY_KEY = 0; +int FISPACT_ND_CLEAR_KEY = 0; +int FISPACT_ND_CROSSEC_KEY = 0; +int FISPACT_ND_CROSSUNC_KEY = 0; +int FISPACT_ND_DECAY_KEY = 0; +int FISPACT_ND_DK_ENDF_KEY = 0; +int FISPACT_ND_ENBINS_KEY = 0; +int FISPACT_ND_FISSYLD_KEY = 0; +int FISPACT_ND_FY_ENDF_KEY = 0; +int FISPACT_ND_HAZARDS_KEY = 0; +int FISPACT_ND_IND_NUC_KEY = 0; +int FISPACT_ND_PROB_TAB_KEY = 0; +int FISPACT_ND_SF_ENDF_KEY = 0; +int FISPACT_ND_SP_ENDF_KEY = 0; +int FISPACT_ND_XS_ENDFB_KEY = 0; +int FISPACT_ND_XS_ENDF_KEY = 0; +int FISPACT_ND_XS_EXTRA_KEY = 0; +int FISPACT_NUCLIDE_NAME_LENGTH = 0; +int FISPACT_OUTPUT_DATA_INVENTORY_ALPHA_ACTIVITY = 0; +int FISPACT_OUTPUT_DATA_INVENTORY_ALPHA_HEAT = 0; +int FISPACT_OUTPUT_DATA_INVENTORY_BETA_ACTIVITY = 0; +int FISPACT_OUTPUT_DATA_INVENTORY_BETA_HEAT = 0; +int FISPACT_OUTPUT_DATA_INVENTORY_COOL_TIME = 0; +int FISPACT_OUTPUT_DATA_INVENTORY_FLUX_AMP = 0; +int FISPACT_OUTPUT_DATA_INVENTORY_GAMMA_ACTIVITY = 0; +int FISPACT_OUTPUT_DATA_INVENTORY_GAMMA_HEAT = 0; +int FISPACT_OUTPUT_DATA_INVENTORY_IRRAD_TIME = 0; +int FISPACT_OUTPUT_DATA_INVENTORY_TOTAL_ACTIVITY = 0; +int FISPACT_OUTPUT_DATA_INVENTORY_TOTAL_ATOMS = 0; +int FISPACT_OUTPUT_DATA_INVENTORY_TOTAL_HEAT = 0; +int FISPACT_OUTPUT_DATA_INVENTORY_TOTAL_MASS = 0; +int FISPACT_VALID_GROUPS = 0; +}