Compare commits
2 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e806d33f6 | ||
|
|
8879d41751 |
2 changed files with 353 additions and 0 deletions
222
exasmr.md
Normal file
222
exasmr.md
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
---
|
||||
author: Steven Hamilton
|
||||
title: ExaSMR Project KPP-1 Verification
|
||||
---
|
||||
|
||||
# Science Challenge Problem Description
|
||||
|
||||
The ExaSMR challenge problem is the simulation of a representative NuScale SMR
|
||||
core by coupling continuous-energy Monte Carlo neutronics with CFD. Features
|
||||
of the problem include the following:
|
||||
|
||||
* representative model of the complete in-vessel coolant loop,
|
||||
* hybrid LES/RANS turbulence model or RANS plus an LES-informed momentum
|
||||
source for treatment of mixing vanes, and
|
||||
* pin-resolved spatial fission power and reaction rate tallies.
|
||||
|
||||
Details on the challenge problem specification are given in the table.
|
||||
|
||||
The simulation objective is to calculate reactor start-up conditions that
|
||||
demonstrate the initiation of natural coolant flow circulation through the
|
||||
reactor core and primary heat exchanger. The driver application, ENRICO,
|
||||
performs inline coupling of the Nek5000 CFD module with Monte Carlo through a
|
||||
common API that supports two Monte Carlo modules: Shift, which targets the
|
||||
Frontier architecture at ORNL, and OpenMC, which targets the Aurora system at
|
||||
ANL.
|
||||
|
||||
Minimum neutronics requirements for the coupled simulation are as
|
||||
follows:
|
||||
|
||||
* full-core representative SMR model containing 37 assemblies with $17\times
|
||||
17$ pins per assembly and 264 fuel pins per assembly item,
|
||||
* depleted fuel compositions containing $O(150)$ nuclides per material,
|
||||
* $10^{10}$ neutrons per eigenvalue iteration,
|
||||
* pin-resolved reaction rate with a single radial tally region and 20 axial
|
||||
levels, and
|
||||
* six macroscopic nuclide-independent reaction rate tallies.
|
||||
|
||||
|
||||
Minimum CFD requirements for the coupled simulation are as follows:
|
||||
|
||||
* assembly bundle mesh models with momentum sources from a resolved CFD
|
||||
calculation on a representative spacer grid and
|
||||
* full-core mesh $200\times 10^6$ elements and $70\times 10^9$ DOF.
|
||||
|
||||
Table: Challenge problem details
|
||||
|
||||
------------------------------------------------------------------------------------
|
||||
Functional requirement Minimum criteria
|
||||
------------------------- ---------------------------------------------------------
|
||||
Physical phenomena and Eigenvalue form of the linear
|
||||
associated models Boltzmann transport equation with quasistatic
|
||||
nuclide neutronics coupled to hybrid RANS/LES
|
||||
(or equivalent accuracy incompressible CFD with
|
||||
Boussinesq approximation, or low-Mach
|
||||
incompressible CFD with nonzero thermal divergence.
|
||||
|
||||
Numerical approach, The neutronics solver is an MC particle transport;
|
||||
and associated models the CFD solver is a spectral finite element on
|
||||
unstructured grids. Physics are coupled by using a
|
||||
quasistatic approximation.
|
||||
|
||||
Simulation details The neutronics model has a minimum of 200,000 tally
|
||||
bins and 10 billion particle histories per
|
||||
eigenvalue iteration. The CFD model has a minimum
|
||||
of 200 million elements and 70 billion DOF.
|
||||
|
||||
Demonstration calculation Run 30 eigenvalue cycles (10 inactive and 20 active)
|
||||
requirements to estimate the MC particle tracking rate and
|
||||
1000 time steps toward steady-state
|
||||
convergence in the CFD solve. Only one nonlinear
|
||||
(Picard) iteration is required. To facilitate
|
||||
comparison with the baseline measurement, the
|
||||
neutronics portion of this calculation requires six
|
||||
macroscopic reaction rates and one radial region
|
||||
per pin.
|
||||
------------------------------------------------------------------------------------
|
||||
|
||||
# Demonstration Calculation
|
||||
|
||||
## Facility Requirements
|
||||
|
||||
All workflow and runtime requirements use standard ECP and facility-supported
|
||||
libraries (e.g., Trilinos, HDF5).
|
||||
|
||||
## Input description and Execution
|
||||
|
||||
### Problem Inputs
|
||||
|
||||
To run ExaSMR coupled problems through the ENRICO driver, the following inputs
|
||||
are required:
|
||||
|
||||
* Monte Carlo driver input (XML)
|
||||
* Monte Carlo geometry input file (XML or HDF5)
|
||||
* Monte Carlo material compositions file (HDF5)
|
||||
* CFD parameter file (text)
|
||||
* CFD mesh file (binary)
|
||||
* CFD C++ user-defined functions (text)
|
||||
* CFD OCCA user-defined kernels (text)
|
||||
* CFD restart file (binary, optional)
|
||||
* ENRICO driver input (XML)
|
||||
* Batch submission script (text)
|
||||
|
||||
For the KPP-1 measurement case, the following inputs are used:
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
Component Filename Description
|
||||
------------ ------------------------------- --------------------------
|
||||
Monte Carlo singlerod_short.inp.xml Driver input
|
||||
|
||||
singlerod_short.rtk.xml Geometry input
|
||||
|
||||
singlerod_short_compositions.h5 Material definitions
|
||||
|
||||
CFD rod_short.udf User-defined C++ functions
|
||||
|
||||
rod_short.oudf User-defined OCCA kernels
|
||||
|
||||
rod_short.re2 Mesh file
|
||||
|
||||
rod_short.par Solver parmeters
|
||||
|
||||
Driver enrico.xml Coupled driver settings
|
||||
|
||||
Submission submit.lsf Batch submission script
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
### Resource Requirements
|
||||
|
||||
Estimated compute requirements for KPP-1 verification are two hours using the
|
||||
full Frontier or Aurora machines.
|
||||
|
||||
## Problem Artifacts
|
||||
|
||||
Standard artifacts for coupled simulations include:
|
||||
|
||||
* Screen output of submitted jobs
|
||||
* HDF5 output from Monte Carlo solver
|
||||
* NekRS state field output files (native binary format)
|
||||
|
||||
The NekRS files will be made available upon request; however, it is anticipated
|
||||
that these files will be very large (>1 TB). It is therefore not likely that
|
||||
the NekRS files will be useful for verification and we suggest that the other
|
||||
artifacts be used as the primary confirmation of execution.
|
||||
Because the run to be used for the FOM measurement will not be able to
|
||||
fully converge a coupled simulation, we cannot check the accuracy of computed
|
||||
results, but we can assess whether the simulation meets several sanity checks
|
||||
related to consistency of the numerical models and that computed quantities
|
||||
obey certain physical characteristics. These checks, all of which are printed
|
||||
to the screen output, include:
|
||||
|
||||
1. Verify consistency of the problem geometries. The ENRICO driver displays
|
||||
diagnostics related to volumetric mapping from the CFD mesh to the MC geometry,
|
||||
ensuring that the sum of the volume of the thermal/fluids elements matches the
|
||||
volume of the corresponding MC cell containing those elements.
|
||||
Exact agreement is not expected, but we anticipate the average volumetric error
|
||||
to be less than 1% and the maximum error for any element to be under 10% (some
|
||||
small regions may be slightly off due to modeling differences related to the
|
||||
gap between the fuel and clad in fuel pins). This check ensures that the physics
|
||||
models are geometrically equivalent and correctly aligned in space.
|
||||
2. The fuel temperature should be nonuniform, i.e., the minimum and maximum
|
||||
temperatures should be different. The minimum temperature should be greater than
|
||||
the coolant inlet temperature of 531.15K and the maximum temperature should be
|
||||
above this value. In a converged simulation, the fuel temperature is expected
|
||||
to reach a maximum of between 1000K and 1200K. For the FOM measurement, the
|
||||
actual temperature rise is expected to be much smaller, but the temperature
|
||||
should not exceed 1300K.
|
||||
3. The coolant/fluid temperature should be nonuniform, i.e., the minimum and
|
||||
maximum temperatures should be different. The minimum temperature should be
|
||||
approximately equal to the coolant inlet temperature of 531.15K and the maximum
|
||||
temperature should be above this value. In a converged simulation, the coolant
|
||||
temperature is expected to reach a maximum of around 590-610K. For the FOM
|
||||
measurement, the actual temperature rise is expected to be much smaller,
|
||||
but the coolant temperature should not exceed 620K.
|
||||
4. The eigenvalue (k-eff) computed by the MC solver should be approximately
|
||||
equal to 1. The actual value will depend on the temperature and coolant
|
||||
density distribution, but it is expected that it will likely be between 0.95
|
||||
and 1.05.
|
||||
|
||||
In addition, we will provide visualization artifacts in the form of 1D lineout
|
||||
and 2D slices of the temperature and heat generation rate at several locations
|
||||
in the problem. These artifacts can be examined to confirm that the simulations
|
||||
are behaving as expected. Because the KPP-1 verification simulation will not be
|
||||
fully converged, certain aspects of these visualizations will not necessarily
|
||||
satisfy all physical characteristics of a converged solution. For example,
|
||||
the small number of time steps executed in the CFD calculation may result in
|
||||
the fluid temperature not being monotonically increasing with respect to the
|
||||
axial height in the problem. Therefore, to aid in the evaluation of these
|
||||
visualization artifacts, we will provide a series of equivalent plots showing
|
||||
the progression towards convergence on a similar (but smaller) example problem.
|
||||
These plots are intended to provide a basis for evaluating whether the results
|
||||
of the KPP-1 verification simulation are showing the expected progress towards
|
||||
a converged solution, even though the results themselves will not be converged.
|
||||
|
||||
KPP-1 FOM measurement data can be obtained by running provided `python` script
|
||||
to extract performance data from above artifacts:
|
||||
```
|
||||
>>> python process_fom.py case_name
|
||||
```
|
||||
This script will extract timing data for each of the physics solvers and evaluate
|
||||
the ExaSMR FOM metric. The MC transport FOM uses the follow information:
|
||||
|
||||
* the number of particle histories per eigenvalue cycle,
|
||||
* the number of active cycles (the MC FOM is only taken over active cycles),
|
||||
* the total time spent in the active cycles.
|
||||
|
||||
All of these quantities are contained in the HDF5 output file.
|
||||
The FOM calculation for the CFD solver uses the following information:
|
||||
|
||||
* the number of degrees of freedom in the problem,
|
||||
* the number of time steps,
|
||||
* the time spent in the CFD solve.
|
||||
|
||||
This information is contained in the ENRICO screen output and will be parsed by
|
||||
the provided python script.
|
||||
|
||||
## Verification of KPP-1 Threshold
|
||||
|
||||
*Give evidence that*
|
||||
|
||||
1. *The FOM measurement met threshold ($>50$)*
|
||||
2. *The executed problem met challenge problem minimum criteria*
|
||||
|
||||
131
smr/build-core-fom.py
Normal file
131
smr/build-core-fom.py
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
from math import pi
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import openmc
|
||||
from tqdm import tqdm
|
||||
|
||||
from smr.materials import materials, clone
|
||||
from smr.surfaces import lattice_pitch, bottom_fuel_stack, top_active_core, \
|
||||
pellet_OR, active_fuel_length
|
||||
from smr.core import core_geometry
|
||||
from smr import inlet_temperature
|
||||
|
||||
|
||||
# Define command-line options
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--multipole', action='store_true',
|
||||
help='Use multipole cross sections')
|
||||
parser.add_argument('--no-multipole', dest='multipole', action='store_false',
|
||||
help='Do not use multipole cross sections')
|
||||
parser.add_argument('--clone', action='store_true',
|
||||
help='Clone materials for each cell instance')
|
||||
parser.add_argument('--no-clone', dest='clone', action='store_false',
|
||||
help='Do not clone materials for each cell instance')
|
||||
parser.add_argument('--depleted', action='store_true',
|
||||
help='Whether UO2 compositions should represent depleted fuel')
|
||||
parser.add_argument('--no-depleted', dest='depleted', action='store_false',
|
||||
help='Whether UO2 compositions should represent depleted fuel')
|
||||
parser.add_argument('-r', '--rings', type=int, default=1,
|
||||
help='Number of annular regions in fuel')
|
||||
parser.add_argument('-a', '--axial', type=int, default=20,
|
||||
help='Number of axial subdivisions in fuel')
|
||||
parser.add_argument('-o', '--output-dir', type=Path, default=None)
|
||||
parser.set_defaults(clone=True, multipole=True, depleted=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
# Make directory for inputs
|
||||
if args.output_dir is None:
|
||||
if args.depleted:
|
||||
directory = Path('core-fom-depleted')
|
||||
else:
|
||||
directory = Path('core-fom-fresh')
|
||||
else:
|
||||
directory = args.output_dir
|
||||
directory.mkdir(exist_ok=True)
|
||||
|
||||
if args.rings > 1:
|
||||
ring_radii = np.sqrt(np.arange(1, args.rings)*pellet_OR**2 / args.rings)
|
||||
else:
|
||||
ring_radii = None
|
||||
geometry = core_geometry(ring_radii, args.axial, args.depleted)
|
||||
|
||||
h = active_fuel_length / args.axial
|
||||
fuel_mats = {}
|
||||
|
||||
# Count the number of instances for each cell and material
|
||||
if args.clone:
|
||||
geometry.determine_paths(instances_only=True)
|
||||
|
||||
fuel_volume = pi * pellet_OR**2 * h / args.rings
|
||||
for cell in tqdm(geometry.get_all_cells().values(),
|
||||
desc='Differentiating materials / assigning volume'):
|
||||
if cell.fill in materials:
|
||||
# Determine if this material is fuel
|
||||
name = cell.fill.name
|
||||
is_fuel = 'UO2 Fuel' in name
|
||||
|
||||
# Determine volume of each fuel material
|
||||
if is_fuel:
|
||||
if args.clone:
|
||||
# Fill cell with list of "differentiated" materials if requested
|
||||
cell.fill = [clone(cell.fill) for i in range(cell.num_instances)]
|
||||
for mat in cell.fill:
|
||||
mat.volume = fuel_volume
|
||||
else:
|
||||
r_o = cell.region.bounding_box[1][0]
|
||||
if (name, r_o) not in fuel_mats:
|
||||
cell.fill = cell.fill.clone()
|
||||
cell.fill.volume = fuel_volume
|
||||
fuel_mats[name, r_o] = cell.fill
|
||||
else:
|
||||
cell.fill = fuel_mats[name, r_o]
|
||||
else:
|
||||
cell.fill.volume = 1.0
|
||||
|
||||
#### Create OpenMC "materials.xml" file
|
||||
all_materials = geometry.get_all_materials()
|
||||
materials = openmc.Materials(all_materials.values())
|
||||
materials.export_to_xml(directory)
|
||||
|
||||
|
||||
#### Create OpenMC "geometry.xml" file
|
||||
geometry.export_to_xml(directory)
|
||||
|
||||
|
||||
#### Create OpenMC "settings.xml" file
|
||||
|
||||
# Construct uniform initial source distribution over fissionable zones
|
||||
lower_left = [-7.*lattice_pitch/2., -7.*lattice_pitch/2., bottom_fuel_stack]
|
||||
upper_right = [+7.*lattice_pitch/2., +7.*lattice_pitch/2., top_active_core]
|
||||
source = openmc.source.Source(space=openmc.stats.Box(lower_left, upper_right))
|
||||
source.space.only_fissionable = True
|
||||
|
||||
settings = openmc.Settings()
|
||||
settings.batches = 200
|
||||
settings.inactive = 100
|
||||
settings.particles = 10000
|
||||
settings.output = {'tallies': False, 'summary': False}
|
||||
settings.source = source
|
||||
settings.sourcepoint = {'write': False}
|
||||
settings.temperature = {
|
||||
'default': inlet_temperature,
|
||||
'method': 'interpolation',
|
||||
'range': (300.0, 1500.0),
|
||||
}
|
||||
if args.multipole:
|
||||
settings.temperature['multipole'] = True
|
||||
settings.temperature['tolerance'] = 1000
|
||||
|
||||
settings.export_to_xml(directory)
|
||||
|
||||
tallies = openmc.Tallies()
|
||||
tally = openmc.Tally(name='depletion tally')
|
||||
fuel_mats = [mat for mat in materials if 'UO2 Fuel' in mat.name]
|
||||
tally.filters = [openmc.MaterialFilter(fuel_mats)]
|
||||
tally.scores = ['total', 'absorption', 'scatter', '(n,gamma)', 'fission', '(n,2n)']
|
||||
tallies.append(tally)
|
||||
tallies.export_to_xml(directory)
|
||||
Loading…
Add table
Add a link
Reference in a new issue