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]
  type = GeneratedMesh
  dim = 1
  nx = 100
  xmax = 1
  elem_type = EDGE3
[]

[Variables]
  [T]
    order = SECOND
    family = LAGRANGE
  []
[]

[Kernels]
  [diffusion]
    type = MatDiffusion
    variable = T
    diffusivity = k
  []
  [source]
    type = BodyForce
    variable = T
    value = 1.0
  []
[]

[Materials]
  [conductivity]
    type = GenericConstantMaterial
    prop_names = k
    prop_values = 2.0
  []
[]

[BCs]
  [right]
    type = DirichletBC
    variable = T
    boundary = right
    value = 300
  []
[]

[Executioner]
  type = Steady
  solve_type = PJFNK
  petsc_options_iname = '-pc_type -pc_hypre_type'
  petsc_options_value = 'hypre boomeramg'
[]

[Postprocessors]
  [avg]
    type = AverageNodalVariableValue
    variable = T
  []
  [max]
    type = NodalExtremeValue
    variable = T
    value_type = max
  []
[]

[Outputs]
[]
(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]
[]
(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]
  [grid]
    type = CartesianProduct
    execute_on = 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 = '1.45  0.9   10
                          9100  200   10
                          0.012 0.004 10
                          291   2     10'
  []
[]
(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]
  [sub]
    type = SamplerFullSolveMultiApp
    input_files = sub.i
    sampler = grid
  []
[]

[Controls]
  [cmdline]
    type = MultiAppSamplerControl
    multi_app = sub
    sampler = grid
    param_names = 'Materials/conductivity/prop_values Kernels/source/value Mesh/xmax BCs/right/value'
  []
[]
(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]
  [data]
    type = SamplerReporterTransfer
    from_multi_app = sub
    sampler = grid
    stochastic_reporter = results
    from_reporter = 'avg/value max/value'
  []
[]

[Reporters]
  [results]
    type = StochasticMatrix
    sampler = grid
    outputs = none
  []
[]
(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]
  [nearest_point_avg]
    type = NearestPointTrainer
    execute_on = timestep_end
    sampler = grid
    predictors = 'results/grid_0'
    predictor_cols = '1 2 3'
    response = results/data:avg:value
  []
  [nearest_point_max]
    type = NearestPointTrainer
    execute_on = timestep_end
    sampler = grid
    response = results/data:max:value
  []
[]
(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]
  [out]
    type = SurrogateTrainerOutput
    trainers = 'nearest_point_avg nearest_point_max'
    execute_on = FINAL
  []
[]
(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