Training a Surrogate Model

This example goes over how to train a surrogate model using the Trainers input syntax. For demonstrative purpose, this example uses the NearestPointTrainer, see Creating a surrogate model for information on how this model was created.

Overview

In general, a SurrogateTrainer object takes in input and output data from a full-order model to create reduced-order model that is later evaluated by a SurrogateModel object to quickly emulate the full-order model outputs. The advantage is that creating a reduced-order generally requires a minimal amount of samples, so taking a large set of samples for statistical quantities is much faster in the end when using the surrogate system. To demonstrate the training process, we use a heat conduction model as the full-order model with maximum and average temperatures as the quantities of interest. The reduced-order model uses NearestPointTrainer.

Model Problem

This example uses a one-dimensional heat conduction problem as the full-order model which has certain uncertain parameters. The model equation is as follows:

The quantities of interest are the average and maximum temperature:

Parameter Uncertainty

For demonstration, each of these parameters will have two types of probability distributions: Uniform () and Normal (). Where and are the max and minimum bounds of the uniform distribution, respectively. And and are the mean and standard deviation of the normal distribution, respectively.

The uncertain parameters for this model problem are:

ParameterSymbolUniformNormal
Conductivity
Volumetric Heat Source
Domain Size
Right Boundary Temperature

Analytical Solutions

This simple model problem has analytical descriptions for the field temperature, average temperature, and maximum temperature:

With the quadratic feature of the field temperature, using quadratic elements in the discretization will actually yield the exact solution.

Input File

Below is the input file used to solve the one-dimensional heat conduction model.

[Mesh<<<{"href": "../../../syntax/Mesh/index.html"}>>>]
  type = GeneratedMesh
  dim = 1
  nx = 100
  xmax = 1
  elem_type = EDGE3
[]

[Variables<<<{"href": "../../../syntax/Variables/index.html"}>>>]
  [T]
    order<<<{"description": "Specifies the order of the FE shape function to use for this variable (additional orders not listed are allowed)"}>>> = SECOND
    family<<<{"description": "Specifies the family of FE shape functions to use for this variable"}>>> = LAGRANGE
  []
[]

[Kernels<<<{"href": "../../../syntax/Kernels/index.html"}>>>]
  [diffusion]
    type = MatDiffusion<<<{"description": "Diffusion equation Kernel that takes an isotropic Diffusivity from a material property", "href": "../../../source/kernels/MatDiffusion.html"}>>>
    variable<<<{"description": "The name of the variable that this residual object operates on"}>>> = T
    diffusivity<<<{"description": "The diffusivity value or material property"}>>> = k
  []
  [source]
    type = BodyForce<<<{"description": "Demonstrates the multiple ways that scalar values can be introduced into kernels, e.g. (controllable) constants, functions, and postprocessors. Implements the weak form $(\\psi_i, -f)$.", "href": "../../../source/kernels/BodyForce.html"}>>>
    variable<<<{"description": "The name of the variable that this residual object operates on"}>>> = T
    value<<<{"description": "Coefficient to multiply by the body force term"}>>> = 1.0
  []
[]

[Materials<<<{"href": "../../../syntax/Materials/index.html"}>>>]
  [conductivity]
    type = GenericConstantMaterial<<<{"description": "Declares material properties based on names and values prescribed by input parameters.", "href": "../../../source/materials/GenericConstantMaterial.html"}>>>
    prop_names<<<{"description": "The names of the properties this material will have"}>>> = k
    prop_values<<<{"description": "The values associated with the named properties"}>>> = 2.0
  []
[]

[BCs<<<{"href": "../../../syntax/BCs/index.html"}>>>]
  [right]
    type = DirichletBC<<<{"description": "Imposes the essential boundary condition $u=g$, where $g$ is a constant, controllable value.", "href": "../../../source/bcs/DirichletBC.html"}>>>
    variable<<<{"description": "The name of the variable that this residual object operates on"}>>> = T
    boundary<<<{"description": "The list of boundary IDs from the mesh where this object applies"}>>> = right
    value<<<{"description": "Value of the BC"}>>> = 300
  []
[]

[Executioner<<<{"href": "../../../syntax/Executioner/index.html"}>>>]
  type = Steady
  solve_type = PJFNK
  petsc_options_iname = '-pc_type -pc_hypre_type'
  petsc_options_value = 'hypre boomeramg'
[]

[Postprocessors<<<{"href": "../../../syntax/Postprocessors/index.html"}>>>]
  [avg]
    type = AverageNodalVariableValue<<<{"description": "Computes the average value of a field by sampling all nodal solutions on the domain or within a subdomain", "href": "../../../source/postprocessors/AverageNodalVariableValue.html"}>>>
    variable<<<{"description": "The name of the variable that this postprocessor operates on"}>>> = T
  []
  [max]
    type = NodalExtremeValue<<<{"description": "Finds either the min or max elemental value of a variable over the domain.", "href": "../../../source/postprocessors/NodalExtremeValue.html"}>>>
    variable<<<{"description": "The name of the variable that this postprocessor operates on"}>>> = T
    value_type<<<{"description": "Type of extreme value to return. 'max' returns the maximum value. 'min' returns the minimum value. 'max_abs' returns the maximum of the absolute value."}>>> = max
  []
[]

[Outputs<<<{"href": "../../../syntax/Outputs/index.html"}>>>]
[]
(moose/modules/stochastic_tools/examples/surrogates/sub.i)

With this input the uncertain parameters are defined as:

  1. Materials/conductivity/prop_values

  2. Kernels/source/value

  3. Mesh/xmax

  4. BCs/right/value

These values in the sub.i file are arbitrary since the stochastic master app will be modifying them.

Training

This section describes how to set up an input file to train a surrogate and output the training data. This file will act as the master app and use the MultiApps and Transfers systems to communicate and run the sub app.

Omitting Solve

Any input file in MOOSE needs to include a Mesh, Variables, and Executioner block. However, the stochastic master app does not actually create or solve a system. So the StochasticToolsAction builds a minimal model to satisfy these requirements:

[StochasticTools<<<{"href": "../../../syntax/StochasticTools/index.html"}>>>]
[]
(moose/modules/stochastic_tools/examples/surrogates/nearest_point_training.i)

Training Sampler

First, a sampler needs to be created, which defines the training points for which the full-order model will be run. In this example, the training points are defined by the CartesianProductSampler:

[Samplers<<<{"href": "../../../syntax/Samplers/index.html"}>>>]
  [grid]
    type = CartesianProduct<<<{"description": "Provides complete Cartesian product for the supplied variables.", "href": "../../../source/samplers/CartesianProductSampler.html"}>>>
    execute_on<<<{"description": "The list of flag(s) indicating when this object should be executed. For a description of each flag, see https://mooseframework.inl.gov/source/interfaces/SetupInterface.html."}>>> = PRE_MULTIAPP_SETUP
    # Grid spacing:
    # k:    1.45  2.35  3.25  4.15  5.05  5.95  6.85  7.75  8.65  9.55
    # q:    9100  9300  9500  9700  9900  10100 10300 10500 10700 10900
    # L:    0.012 0.016 0.020 0.024 0.028 0.032 0.036 0.040 0.044 0.048
    # Tinf: 291   293   295   297   299   301   303   305   307   309
    linear_space_items<<<{"description": "A list of triplets, each item should include the min, step size, and number of steps."}>>> = '1.45  0.9   10
                          9100  200   10
                          0.012 0.004 10
                          291   2     10'
  []
[]
(moose/modules/stochastic_tools/examples/surrogates/nearest_point_training.i)

The "linear_space_items" parameter defines a uniform grid of points. Having 10 points for each parameter results in 10,000 training points. "execute_on" needs to be set to PRE_MULTIAPP_SETUP for this example since we will be using MultiAppSamplerControl to perturb the parameters.

MultiApp and Control

SamplerFullSolveMultiApp is used to setup the communication between the master and sub app with the ability to loop over samples. MultiAppSamplerControl defines which parameters to perturb, which must correspond with the dimensionality defined in the Sampler.

[MultiApps<<<{"href": "../../../syntax/MultiApps/index.html"}>>>]
  [sub]
    type = SamplerFullSolveMultiApp<<<{"description": "Creates a full-solve type sub-application for each row of each Sampler matrix.", "href": "../../../source/multiapps/SamplerFullSolveMultiApp.html"}>>>
    input_files<<<{"description": "The input file for each App.  If this parameter only contains one input file it will be used for all of the Apps.  When using 'positions_from_file' it is also admissable to provide one input_file per file."}>>> = sub.i
    sampler<<<{"description": "The Sampler object to utilize for creating MultiApps."}>>> = grid
  []
[]

[Controls<<<{"href": "../../../syntax/Controls/index.html"}>>>]
  [cmdline]
    type = MultiAppSamplerControl<<<{"description": "Control for modifying the command line arguments of MultiApps.", "href": "../../../source/controls/MultiAppSamplerControl.html"}>>>
    multi_app<<<{"description": "The name of the MultiApp to control."}>>> = sub
    sampler<<<{"description": "The Sampler object to utilize for altering the command line options of the MultiApp."}>>> = grid
    param_names<<<{"description": "The names of the command line parameters to set via the sampled data."}>>> = 'Materials/conductivity/prop_values Kernels/source/value Mesh/xmax BCs/right/value'
  []
[]
(moose/modules/stochastic_tools/examples/surrogates/nearest_point_training.i)

MultiAppSamplerControl is not the only method to perturb sub app input parameters. If all the parameters are controllable, then SamplerParameterTransfer can be used. See the Monte Carlo Example for more details.

Transferring Results

After each perturbed simulation of the sub app is finished, the results are transferred to the master app. SamplerReporterTransfer is used to transfer postprocessors, vectorpostprocessors, or reporter values from the sub app to a StochasticReporter in the master app.

[Transfers<<<{"href": "../../../syntax/Transfers/index.html"}>>>]
  [data]
    type = SamplerReporterTransfer<<<{"description": "Transfers data from Reporters on the sub-application to a StochasticReporter on the main application.", "href": "../../../source/transfers/SamplerReporterTransfer.html"}>>>
    from_multi_app<<<{"description": "The name of the MultiApp to receive data from"}>>> = sub
    sampler<<<{"description": "A the Sampler object that Transfer is associated.."}>>> = grid
    stochastic_reporter<<<{"description": "The name of the StochasticReporter object to transfer values to."}>>> = results
    from_reporter<<<{"description": "The name(s) of the Reporter(s) on the sub-app to transfer from."}>>> = 'avg/value max/value'
  []
[]

[Reporters<<<{"href": "../../../syntax/Reporters/index.html"}>>>]
  [results]
    type = StochasticMatrix<<<{"description": "Tool for extracting Sampler object data and storing data from stochastic simulations.", "href": "../../../source/reporters/StochasticMatrix.html"}>>>
    sampler<<<{"description": "The sample from which to extract distribution data."}>>> = grid
    outputs<<<{"description": "Vector of output names where you would like to restrict the output of variables(s) associated with this object"}>>> = none
  []
[]
(moose/modules/stochastic_tools/examples/surrogates/nearest_point_training.i)

Here, there are two transfers that transfer the sub app postprocessors computing and to two different master app reporters. The "outputs" parameter is set to none so it doesn't output the unnecessary results to a CSV file. The trainer will directly grab the data from the reporters.

Training Object

Training objects take in sampler and results data to train the surrogate model. The sampler points are taken directly from the sampler by defining "sampler". The results are taken directly from a reporter or vector postprocessor, the object is defined by "response" and "predictors".

[Trainers<<<{"href": "../../../syntax/Trainers/index.html"}>>>]
  [nearest_point_avg]
    type = NearestPointTrainer<<<{"description": "Loops over and saves sample values for [NearestPointSurrogate.md].", "href": "../../../source/trainers/NearestPointTrainer.html"}>>>
    execute_on<<<{"description": "The list of flag(s) indicating when this object should be executed. For a description of each flag, see https://mooseframework.inl.gov/source/interfaces/SetupInterface.html."}>>> = timestep_end
    sampler<<<{"description": "Sampler used to create predictor and response data."}>>> = grid
    predictors<<<{"description": "Reporter values used as the independent random variables, If 'predictors' and 'predictor_cols' are both empty, all sampler columns are used."}>>> = 'results/grid_0'
    predictor_cols<<<{"description": "Sampler columns used as the independent random variables, If 'predictors' and 'predictor_cols' are both empty, all sampler columns are used."}>>> = '1 2 3'
    response<<<{"description": "Reporter value of response results, can be vpp with <vpp_name>/<vector_name> or sampler column with 'sampler/col_<index>'."}>>> = results/data:avg:value
  []
  [nearest_point_max]
    type = NearestPointTrainer<<<{"description": "Loops over and saves sample values for [NearestPointSurrogate.md].", "href": "../../../source/trainers/NearestPointTrainer.html"}>>>
    execute_on<<<{"description": "The list of flag(s) indicating when this object should be executed. For a description of each flag, see https://mooseframework.inl.gov/source/interfaces/SetupInterface.html."}>>> = timestep_end
    sampler<<<{"description": "Sampler used to create predictor and response data."}>>> = grid
    response<<<{"description": "Reporter value of response results, can be vpp with <vpp_name>/<vector_name> or sampler column with 'sampler/col_<index>'."}>>> = results/data:max:value
  []
[]
(moose/modules/stochastic_tools/examples/surrogates/nearest_point_training.i)

In the nearest_point_avg trainer, we see that the predictor values are from a VPP and sampler columns. In the nearest_point_max trainer, the predictor names were not specified, which indicates that all the sampler columns are used as predictors. StochasticReporter defines the reporter name by the name of the transfer executing the transfer, which is why we know that the values names are data in this example.

Outputting Training Data

All training objects create variables that surrogates can use for evaluation. Saving this data will allow the surrogate to be run separately in another input. SurrogateTrainerOutput is used to output training data.

[Outputs<<<{"href": "../../../syntax/Outputs/index.html"}>>>]
  [out]
    type = SurrogateTrainerOutput<<<{"description": "Output for trained surrogate model data.", "href": "../../../source/outputs/SurrogateTrainerOutput.html"}>>>
    trainers<<<{"description": "A list of SurrogateTrainer objects to output."}>>> = 'nearest_point_avg nearest_point_max'
    execute_on<<<{"description": "The list of flag(s) indicating when this object should be executed. For a description of each flag, see https://mooseframework.inl.gov/source/interfaces/SetupInterface.html."}>>> = FINAL
  []
[]
(moose/modules/stochastic_tools/examples/surrogates/nearest_point_training.i)

The outputted file will be named: <file_base>_<surrogate name>.rd. For this example, the two outputted files are:

  • nearest_point_training_out_nearest_point_avg.rd

  • nearest_point_training_out_nearest_point_max.rd