Converting CSG to CAD Geometry for Multiphysics
In this tutorial, you will learn how to:
Convert OpenMC CSG-based models to DAGMC using the Coreform Cubit CSG-to-CAD converter
Perform multiphysics feedback on a portion of the OpenMC model by coupling to finite element heat conduction
Run hybrid CSG + DAGMC OpenMC models with Cardinal
To access this tutorial,
cd cardinal/tutorials/csg_to_cad
This tutorial also requires you to download some mesh files from Box. Please download the files from the csg_to_cad
folder here and place these files within tutorials/csg_to_cad
.
To run this tutorial, you need to have built Cardinal with DAGMC support enabled, by setting export ENABLE_DAGMC=true
.
Geometry and Computational Models
This model consists of a simplified version of the KRUSTY reactor. The neutronics model contains the fuel, heat pipes, and several layers of radial insulation and reflector materials. Simplified material compositions have been used, and many ex-core components have been removed for the sake of a simpler tutorial.
A conceptual image of the (i) fully-detailed KRUSTY model (background transparent image) and the simplified CSG models used in this tutorial (foreground) is shown below.
Converting CSG to CAD using Coreform Cubit
The OpenMC CAD adapter provides the capability to convert OpenMC cells to CAD parts in the form of a Cubit journal file that can be imported into Cubit. These CAD models can then be exported to various other CAD formats supported by Cubit (ACIS, IGES, STEP, etc.) or parts can be meshed for use in other simulations – as is the case in this tutorial.
OpenMC provides a plotting utility, which is useful for exploring CSG models, but it is limited to axis-aligned slices of the geometry. CAD and meshing utilities commonly support interactive rendering of parts, which is useful for debugging geometry problems as well as verifying the shape and/or placement of neutronics cells.
To generate a journal file of the KRUSTY model provided here with the CAD adapter, run the following command:
openmc_to_cad model.xml -w 1000 1000 1000 -c 1
This will produce two files, openmc.jou
and openmc_cell1.jou
, that contain the entire KRUSTY model and cell 1, the fuel region, respectively. It is interesting to view the full model in CAD, but we will only need the first cell for the purposes of this tutorial.
To open and import the full model in to Cubit, select the "Play journal file" button
Cubit> playback "openmc.jou"
The quotes around the file name in the block above are meaningful in Cubit's console and should not be omitted.
The model should then appear in Cubit.
The model can then be examined for accuracy, with the material assignments appering as groups in the model tree.
The ability to interactively explore the model as CAD is extremely useful for visualization and debugging of a CSG model, which can be difficult to keep track of when relying on a mental model supported by 2D slices from native plotting utilities.
However, for this example we only need a single volume to couple heating in the center fuel volume (contained in the group labeled "mat:U-7.65Mo Fuel"). Let's instead import that single cell into Cubit.
Cubit> reset
Cubit> playback "openmc_cell1.jou"
Next we'll create 2 meshes:
A surface mesh of triangle for the DAGMC geometry. This will represent the geometry boundaries for particle transport
A volumetric mesh for a heating tally and decomposition based on the temperature field produced by heat conduction in MOOSE.
Generate the DAGMC Surface Mesh
For the DAGMC mesh, we'll apply Cubit's trimesh scheme to all the surfaes of the fuel volume. This will produce a watertight mesh for particle transport. Normally the coarse mesh settings would be used to build the DAGMC mesh, but in this case we'll disable that setting to obtain triangles with a better aspect ratio for the tetrahedral mesh we'll create later.
Cubit> set trimesher coarse off
Cubit> set trimesher split overconstrained edges on
Cubit> surface all scheme trimesh
Cubit> mesh surface all
Now that this is complete, we'll want to make sure the metadata converted from the OpenMC model is handled appropriately. To do this we'll use some capabilites from the DAGMC toolbar which can be added to Cubit. One of the capabilities is the conversion of group-based metadata to blocks and materials. We'll perform this conversion by clicking the button with the tooltip "Materials to Block Assignments".
Note: that this conversion can also be accomplished based on instructions found in previous Coreform Cubit webinars on modern DAGMC workflows.
This mesh can now be exported to the .h5m
format supported by DAGMC.
Cubit> export dagmc "krusty_fuel.h5m"
Note: This can also be accomplished in Cubit's export GUI.
Generate the Cardinal Mesh
When generating the Cardinal mesh, we want to ensure that the triangles of the DAGMC mesh correspond to the triangles used in the DAGMC mesh. Generating both meshes in Cubit allows us to guarantee that the boundaries of the two meshes are conformal. This mesh will be used to both tally heating in OpenMC and evaluate heat conductioon in MOOSE.
Cubit> set duplicate block elements on
Cubit> tetmesh tri all make block
Next, the mesh sideset "heat_pipes" can be added. Cardinal will expect to find on this sideset on the mesh.
Cubit> sideset 1 add surface 233 to 240
Cubit> sideset 1 name "heat_pipes"
This mesh can now be exported for use in multiphysics copuling.
Cubit> export mesh "/Users/pshriwise/krusty.e"
Multiphysics Coupling
We have built a hybrid Computer Aided Design (CAD) and CSG model of the KRUSTY reactor in OpenMC, along with a volume mesh for tallying and solving heat conduction. In this section, we briefly describe the input files used to couple heat conduction to neutronics.
MOOSE Heat Conduction
We solve for the fuel temperature using the finite element method using MOOSE. We will solve using the volume mesh produced from Cubit. This mesh is identical to the mesh which OpenMC will use for tallying, but does not striclty need to be (it can be entirely different, and most other tutorials demonstrate this feature). But in this case, we will for simplicity use an identical mesh.
[Mesh]
[fuel]
type = FileMeshGenerator
file = krusty_fuel.e
[]
[]
(tutorials/csg_to_cad/fuel.i)We will solve for temperature, with a variable T
. The power density will be supplied by OpenMC, so we create a variable named power
in this file in order to receive that field. The OpenMC tally will be a constant value in every mesh element, so we define this variable to match this basis.
[Variables]
[T]
[]
[]
[AuxVariables]
[power]
family = MONOMIAL
order = CONSTANT
[]
[]
(tutorials/csg_to_cad/fuel.i)Next, we specify the governing equation and boundary conditions. We will solve for the steady-state temperature distribution
We use the HeatConduction and CoupledForce kernels to define the Laplacian kernel and the coupled power term, respectively. For boundary conditions, we apply a constant temperature of 800 on the surface of the heat pipes.
[Kernels]
[heat_conduction]
type = HeatConduction
variable = T
[]
[power]
type = CoupledForce
variable = T
v = power
[]
[]
[BCs]
[surface]
type = DirichletBC
variable = T
boundary = 'heat_pipes'
value = 800
[]
[]
[Materials]
[k]
type = GenericConstantMaterial
prop_names = 'thermal_conductivity'
prop_values = '0.1'
[]
[]
(tutorials/csg_to_cad/fuel.i)Lastly, we need to specify a value for the thermal conductivity. We will set this to a constant value, for simplicity.
[Materials]
[k]
type = GenericConstantMaterial
prop_names = 'thermal_conductivity'
prop_values = '0.1'
[]
[]
(tutorials/csg_to_cad/fuel.i)Finally, we need to specify how to solve this equation. We will use a transient executioner, which will allow us to solve the equation multiple times. We also indicate the output file format (exodus). For the sake of normalizing the power we receive from OpenMC, we also add a postprocessor to compute the total integral of power - while we don't strictly need this because our meshes are identical between OpenMC and MOOSE for this problem, having this block here would be necessary if OpenMC and MOOSE were using different meshes, to guarantee power conservation.
[Postprocessors]
[tally_integral]
type = ElementIntegralVariablePostprocessor
variable = power
execute_on = transfer
[]
[]
[Executioner]
type = Transient
[]
[Outputs]
exodus = true
[]
(tutorials/csg_to_cad/fuel.i)OpenMC Neutron Transport
Our input file to run OpenMC within a MOOSE simulation will look similar to the previous input file syntax. First, we now have a problem block to inform MOOSE to replace it's typical finite element solver with calls to OpenMC -eigenvalue runs. We will have temperature feedback to OpenMC on block 1, and we add two mesh tallies. This will tally the kappa_fission
local power deposition and the flux
from OpenMC and map them to the mesh used in the mesh block. Other settings in the problem block refer to how to normalize the tallies from OpenMC into meaningful engineering units (W/volume for heating terms, and neutrons/area/time for flux).
power = 3000
[Problem]
type = OpenMCCellAverageProblem
power = ${power}
temperature_blocks = '1'
cell_level = 1
skinner = skinner
normalize_by_global_tally = false
source_rate_normalization = 'kappa_fission'
[Tallies]
[mesh]
type = MeshTally
score = 'kappa_fission flux'
[]
[]
[]
[Mesh]
[fuel]
type = FileMeshGenerator
file = krusty_fuel.e
[]
[]
(tutorials/csg_to_cad/openmc.i)We will dynamically modify the OpenMC geometry by "skinning" with the MoabSkinner object. For simplicity, we will lump elements into new cells by contouring into 4 intervals between temperatures of 800 K and 1000 K.
[UserObjects]
[skinner]
type = MoabSkinner
temperature = temp
n_temperature_bins = 4
temperature_min = 800
temperature_max = 1000
build_graveyard = true
[]
[]
(tutorials/csg_to_cad/openmc.i)Next, we specify how to pass data between OpenMC and the finite element heat conduction solver in the fuel.i
input file. We will run the heat conduction solver as a sub-application. On every time step, we will pass temperature (into OpenMC) and the heating tally (out of OpenMC) as listed in the transfers block. The other details listed in this section are optimizations for faster transfers (search_value_conflicts = false
) and details on the source/receiver variable names in each file and which postprocessors to use to ensure power conservation.
[MultiApps]
[conduction]
type = TransientMultiApp
input_files = 'fuel.i'
execute_on = timestep_end
[]
[]
[Transfers]
[heat_source_from_openmc]
type = MultiAppGeneralFieldShapeEvaluationTransfer
to_multi_app = conduction
source_variable = kappa_fission
variable = power
from_postprocessors_to_be_preserved = tally_integral
to_postprocessors_to_be_preserved = tally_integral
search_value_conflicts = false
[]
[temp_to_openmc]
type = MultiAppGeneralFieldShapeEvaluationTransfer
from_multi_app = conduction
variable = temp
source_variable = T
search_value_conflicts = false
[]
[]
(tutorials/csg_to_cad/openmc.i)Next, we set some initial conditions, since OpenMC will run first. We set a constant initial temperature of 800 K. We also add an auxiliary variable, CellTemperatureAux, so that we can see the temperature field actually applied to OpenMC (this will hold the cell temperatures). Lastly, we indicate the run settings - we will run OpenMC three times, and output all results to Exodus.
[ICs]
[temp]
type = ConstantIC
variable = temp
value = 800
[]
[power]
type = ConstantIC
variable = kappa_fission
value = ${fparse power/1.865e+03}
[]
[]
[AuxVariables]
[cell_temperature]
family = MONOMIAL
order = CONSTANT
[]
[]
[AuxKernels]
[cell_temperature]
type = CellTemperatureAux
variable = cell_temperature
[]
[]
[Postprocessors]
[tally_integral]
type = ElementIntegralVariablePostprocessor
variable = kappa_fission
execute_on = 'initial transfer timestep_end'
[]
[]
[Executioner]
type = Transient
num_steps = 3
[]
[Outputs]
exodus = true
[]
(tutorials/csg_to_cad/openmc.i)Execution and Postprocessing
To run the coupled calculation,
mpiexec -np 2 cardinal-opt -i openmc.i --n-threads=2
This will run both MOOSE and OpenMC with 2 MPI processes and 2 OpenMP threads per rank. To run the simulation faster, you can increase the parallel processes/threads, or simply decrease the number of particles used in OpenMC. When the simulation has completed, you will have created a number of different output files:
openmc_out.e
: Exodus output file with all variables in theopenmc.i
fileopenmc_out_conduction0.e
: Exodus output file with all variables in thefuel.i
file