Material Inversion Example: Convective Boundary Condition
Background
The MOOSE optimization module provides a flexible framework for solving inverse optimization problems in MOOSE. This page is part of a set of examples for different types of inverse optimization problems.
Example: Convective Boundary Condition
In this example, the convective coefficient from this equation Inverse Optimization, Eq. (12) is fit to experimental data. This is a nonlinear optimization problem but is limited to a boundary condition and will be easier to solve than material property inversion presented in Example 2: Constant Thermal Conductivity. This problem consists of a rectangular domain where the convective BC is applied to on the left. The top and bottom BCs are Dirichlet and the right BC is Neumann. This is a nonlinear optimization problem where the design parameters show up in the derivative of the PDE, see this section from the theory page. Getting a nonlinear optimization problem to converge is dependent on the initial guess and bounds for the design parameters. Convergence is limited to local minima and doesn't guarantee a global minimum. All of this makes material inversion problems more difficult to solve than the linear optimization problems for force inversion.
Main-App Optimization Executioner
The main input file containing the optimization reporter, executioner and transfers is shown in Listing 1. The adjoint problem will need the simulation temperature from the forward problem to evaluate Inverse Optimization, Eq. (31) for the convective BC. This requires us to transfer the forward simulation temperature field to the adjoint-app.
Listing 1:
[Optimization]
[]
[Mesh]
[gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 10
ny = 20
xmax = 1
ymax = 2
[]
[]
[OptimizationReporter]
type = GeneralOptimization
objective_name = objective_value
parameter_names = 'p1'
num_values = '1'
initial_condition = '9'
upper_bounds = '10'
lower_bounds = '1'
[]
[Reporters]
[main]
type = OptimizationData
measurement_points = '0.1 0 0
0.1 0.1 0
0.1 0.2 0
0.1 0.3 0
0.1 0.4 0
0.1 0.5 0
0.1 0.6 0
0.1 0.7 0
0.1 0.8 0
0.1 0.9 0
0.1 1 0
0.1 1.1 0
0.1 1.2 0
0.1 1.3 0
0.1 1.4 0
0.1 1.5 0
0.1 1.6 0
0.1 1.7 0
0.1 1.8 0
0.1 1.9 0
0.1 2 0'
measurement_values = '500
472.9398111
450.8117197
434.9560747
423.3061045
414.9454912
409.3219399
406.1027006
405.0865428
406.1604905
409.2772668
414.4449772
421.7253934
431.2401042
443.1862012
457.8664824
475.7450186
497.5582912
524.4966003
559.1876637
600'
[]
[]
[Executioner]
type = Optimize
tao_solver = taoblmvm #taolmvm#taonm #taolmvm
petsc_options_iname = '-tao_gatol' # -tao_fd_gradient -tao_fd_delta'
petsc_options_value = '1e-4' #1e-1 '#true 1e-4'
[]
[MultiApps]
[forward]
type = FullSolveMultiApp
input_files = forward.i
execute_on = "FORWARD"
clone_parent_mesh = true
[]
[adjoint]
type = FullSolveMultiApp
input_files = adjoint.i
execute_on = "ADJOINT"
clone_parent_mesh = true
[]
[]
[Transfers]
#these are usually the same for all input files.
[toForward]
type = MultiAppReporterTransfer
to_multi_app = forward
from_reporters = 'main/measurement_xcoord
main/measurement_ycoord
main/measurement_zcoord
main/measurement_time
main/measurement_values
OptimizationReporter/p1'
to_reporters = 'measure_data/measurement_xcoord
measure_data/measurement_ycoord
measure_data/measurement_zcoord
measure_data/measurement_time
measure_data/measurement_values
params/vals'
[]
[fromForward]
type = MultiAppReporterTransfer
from_multi_app = forward
from_reporters = 'measure_data/misfit_values measure_data/objective_value'
to_reporters = 'main/misfit_values OptimizationReporter/objective_value'
[]
[toAdjoint]
type = MultiAppReporterTransfer
to_multi_app = adjoint
from_reporters = 'main/measurement_xcoord
main/measurement_ycoord
main/measurement_zcoord
main/measurement_time
main/misfit_values
OptimizationReporter/p1'
to_reporters = 'misfit/measurement_xcoord
misfit/measurement_ycoord
misfit/measurement_zcoord
misfit/measurement_time
misfit/misfit_values
params/vals'
[]
[fromAdjoint]
type = MultiAppReporterTransfer
from_multi_app = adjoint
from_reporters = 'adjoint_pt/inner_product'
to_reporters = 'OptimizationReporter/grad_p1'
[]
# these are transferring data from subapp to subapp because the adjoint problem
# needs the forward solution to compute the gradient. Maybe this step could be
# done on the main app. The adjoint only passes the adjoint variable (whole mesh)
# to the main app and the main app computes the gradient from this.
[fromForwardtoAdjoint_temp]
type = MultiAppCopyTransfer
from_multi_app = forward
to_multi_app = adjoint
source_variable = 'temperature'
variable = 'temperature_forward'
[]
[]
[Outputs]
csv = true
[]
(modules/combined/test/tests/optimization/invOpt_bc_convective/main.i)Forward Problem Sub-App
The forward input file containing the solution to the PDE of interest is shown in Listing 2. The optimization executioner is controlling the coefficient
in [ConvectiveFluxFunction]
boundary condition. The coefficient is controlled by transferring data from the main-app into a chain of objects on the forward-app. The main-app first transfers the convection coefficient into a [ConstantValuePostprocessor]
on the forward-app, which is then transferred into a function that can finally be transferred into the ConvectiveFluxFunction
BC.
Listing 2:
[Mesh]
[gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 10
ny = 20
xmax = 1
ymax = 2
[]
[]
[Variables]
[temperature]
[]
[]
[Kernels]
[heat_conduction]
type = ADHeatConduction
variable = temperature
[]
[]
[BCs]
[left]
type = ConvectiveFluxFunction
variable = temperature
boundary = 'left'
T_infinity = 100.0
coefficient = function1
[]
[right]
type = NeumannBC
variable = temperature
boundary = right
value = -100
[]
[bottom]
type = DirichletBC
variable = temperature
boundary = bottom
value = 500
[]
[top]
type = DirichletBC
variable = temperature
boundary = top
value = 600
[]
[]
[Materials]
[steel]
type = ADGenericConstantMaterial
prop_names = thermal_conductivity
prop_values = 5
[]
[]
[Executioner]
type = Steady
solve_type = PJFNK
nl_abs_tol = 1e-6
nl_rel_tol = 1e-8
petsc_options_iname = '-pc_type'
petsc_options_value = 'lu'
[]
[Functions]
[function1]
type = ParsedOptimizationFunction
expression = 'a'
param_symbol_names = 'a'
param_vector_name = 'params/vals'
[]
[]
[VectorPostprocessors]
[vertical]
type = LineValueSampler
variable = 'temperature'
start_point = '0.1 0.0 0.0'
end_point = '0.1 2.0 0.0'
num_points = 21
sort_by = id
[]
[]
[Reporters]
[measure_data]
type = OptimizationData
objective_name = objective_value
variable = temperature
[]
[params]
type = ConstantReporter
real_vector_names = 'vals'
real_vector_values = '0' # Dummy value
[]
[]
[Outputs]
csv = true
exodus = false
console = false
file_base = 'forward'
[]
(modules/combined/test/tests/optimization/invOpt_bc_convective/forward.i)Adjoint Problem Sub-App
The adjoint input file shown in Listing 3 computes the adjoint of the forward PDE. The adjoint problem uses a Controls
block to allow the main app to transfer the material property used in the forward problem to the adjoint problem. The temperature field computed in the forward problem was transferred back to the main app and is finally transferred from the main app into the adjoint problem using a MultiAppCopyTransfer
. The gradient given by Inverse Optimization, Eq. (31) is computed on the left boundary using the SideIntegralVariablePostprocessor postprocessor.
Listing 3:
[Mesh]
[gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 10
ny = 20
xmax = 1
ymax = 2
[]
[]
[AuxVariables]
[temperature_forward]
[]
[T2]
[]
[]
[AuxKernels]
[TT]
type = ParsedAux
args = 'temperature temperature_forward'
variable = T2
function = 'temperature*(100-temperature_forward)'
[]
[]
[Variables]
[temperature]
[]
[]
[Kernels]
[heat_conduction]
type = ADHeatConduction
variable = temperature
[]
[]
[DiracKernels]
[pt]
type = ReporterPointSource
variable = temperature
x_coord_name = misfit/measurement_xcoord
y_coord_name = misfit/measurement_ycoord
z_coord_name = misfit/measurement_zcoord
value_name = misfit/misfit_values
[]
[]
[Reporters]
[misfit]
type = OptimizationData
[]
[params]
type = ConstantReporter
real_vector_names = 'vals'
real_vector_values = '0' # Dummy value
[]
[]
[BCs]
[left]
type = ConvectiveFluxFunction
variable = temperature
boundary = 'left'
T_infinity = 0.0
coefficient = function1
[]
[right]
type = NeumannBC
variable = temperature
boundary = right
value = 0
[]
[bottom]
type = DirichletBC
variable = temperature
boundary = bottom
value = 0
[]
[top]
type = DirichletBC
variable = temperature
boundary = top
value = 0
[]
[]
[Materials]
[steel]
type = ADGenericConstantMaterial
prop_names = thermal_conductivity
prop_values = 5
[]
[]
[Executioner]
type = Steady
solve_type = PJFNK
nl_abs_tol = 1e-6
nl_rel_tol = 1e-8
petsc_options_iname = '-pc_type'
petsc_options_value = 'lu'
[]
[Functions]
[function1]
type = ParsedOptimizationFunction
expression = 'a'
param_symbol_names = 'a'
param_vector_name = 'params/vals'
[]
[]
[VectorPostprocessors]
[adjoint_pt]
type = SideOptimizationNeumannFunctionInnerProduct
variable = T2
function = function1
boundary = left
[]
[]
[Outputs]
console = false
exodus = false
file_base = 'adjoint'
[]
(modules/combined/test/tests/optimization/invOpt_bc_convective/adjoint.i)