Thermomechanical SIMP Optimization with Multi-Apps

In this example, we setup two different physics problems defined in the same domain. The first model is a mechanical small deformation problem with two loads using symmetric boundary conditions. Such a model yields the typical SIMP "bridge-like" structure. The problem is set up regularly with the mechanical compliance sensitivity computed and adequately filtered.

Listing 1: MBB User objects in structural subapp

[UserObjects<<<{"href": "../../../../syntax/UserObjects/index.html"}>>>]
  [rad_avg]
    type = RadialAverage<<<{"description": "Perform a radial average of a material property", "href": "../../../../source/userobjects/RadialAverage.html"}>>>
    radius<<<{"description": "Cut-off radius for the averaging"}>>> = 1.2
    weights<<<{"description": "Distance based weight function"}>>> = linear
    prop_name<<<{"description": "Name of the material property to average"}>>> = sensitivity
    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
    force_preaux<<<{"description": "Forces the UserObject to be executed in PREAUX"}>>> = true
  []
  [calc_sense]
    type = SensitivityFilter<<<{"description": "Computes the filtered sensitivity using a radial average user object.", "href": "../../../../source/userobjects/SensitivityFilter.html"}>>>
    density_sensitivity<<<{"description": "Name of the density_sensitivity variable."}>>> = Dc
    design_density<<<{"description": "Design density variable name."}>>> = mat_den
    filter_UO<<<{"description": "Radial Average user object"}>>> = rad_avg
    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
    force_postaux<<<{"description": "Forces the UserObject to be executed in POSTAUX"}>>> = true
  []
[]
(modules/combined/examples/optimization/thermomechanical/structural_sub.i)

The second model is a thermal, heat conduction problem with one heat generation boundary (on the left) with the rest of boundaries defined as insulating material; i.e. zero Neumann boundary condition on temperature. Such a model often generates a dendritic structure to maximize the reduction in the temperature gradients. In a way analogous to the structural problem, the thermal compliance sensitivities are generated and filtered in the subapp:

Listing 2: MBB User objects in thermal subapp

[UserObjects<<<{"href": "../../../../syntax/UserObjects/index.html"}>>>]
  [rad_avg]
    type = RadialAverage<<<{"description": "Perform a radial average of a material property", "href": "../../../../source/userobjects/RadialAverage.html"}>>>
    radius<<<{"description": "Cut-off radius for the averaging"}>>> = 0.1
    weights<<<{"description": "Distance based weight function"}>>> = linear
    prop_name<<<{"description": "Name of the material property to average"}>>> = sensitivity
    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
    force_preaux<<<{"description": "Forces the UserObject to be executed in PREAUX"}>>> = true
  []
  [rad_avg_cost]
    type = RadialAverage<<<{"description": "Perform a radial average of a material property", "href": "../../../../source/userobjects/RadialAverage.html"}>>>
    radius<<<{"description": "Cut-off radius for the averaging"}>>> = 0.1
    weights<<<{"description": "Distance based weight function"}>>> = linear
    prop_name<<<{"description": "Name of the material property to average"}>>> = cost_sensitivity
    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
    force_preaux<<<{"description": "Forces the UserObject to be executed in PREAUX"}>>> = true
  []
  [rad_avg_thermal]
    type = RadialAverage<<<{"description": "Perform a radial average of a material property", "href": "../../../../source/userobjects/RadialAverage.html"}>>>
    radius<<<{"description": "Cut-off radius for the averaging"}>>> = 0.1
    weights<<<{"description": "Distance based weight function"}>>> = linear
    prop_name<<<{"description": "Name of the material property to average"}>>> = thermal_sensitivity
    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
    force_preaux<<<{"description": "Forces the UserObject to be executed in PREAUX"}>>> = true
  []
  # Provides Dc
  [calc_sense]
    type = SensitivityFilter<<<{"description": "Computes the filtered sensitivity using a radial average user object.", "href": "../../../../source/userobjects/SensitivityFilter.html"}>>>
    density_sensitivity<<<{"description": "Name of the density_sensitivity variable."}>>> = Dc
    design_density<<<{"description": "Design density variable name."}>>> = mat_den
    filter_UO<<<{"description": "Radial Average user object"}>>> = rad_avg
    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
    force_postaux<<<{"description": "Forces the UserObject to be executed in POSTAUX"}>>> = true
  []
  # Provides Cc
  [calc_sense_cost]
    type = SensitivityFilter<<<{"description": "Computes the filtered sensitivity using a radial average user object.", "href": "../../../../source/userobjects/SensitivityFilter.html"}>>>
    density_sensitivity<<<{"description": "Name of the density_sensitivity variable."}>>> = Cc
    design_density<<<{"description": "Design density variable name."}>>> = mat_den
    filter_UO<<<{"description": "Radial Average user object"}>>> = rad_avg_cost
    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
    force_postaux<<<{"description": "Forces the UserObject to be executed in POSTAUX"}>>> = true
  []
  # Provides Tc
  [calc_sense_thermal]
    type = SensitivityFilter<<<{"description": "Computes the filtered sensitivity using a radial average user object.", "href": "../../../../source/userobjects/SensitivityFilter.html"}>>>
    density_sensitivity<<<{"description": "Name of the density_sensitivity variable."}>>> = Tc
    design_density<<<{"description": "Design density variable name."}>>> = mat_den
    filter_UO<<<{"description": "Radial Average user object"}>>> = rad_avg_thermal
    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
    force_postaux<<<{"description": "Forces the UserObject to be executed in POSTAUX"}>>> = true
  []
[]
(modules/combined/examples/optimization/thermomechanical/thermal_sub.i)

Finally, the main app obtain the sensitivities from the subapps and sends the computed pseudo-densities to the subapps. This process tends to reduce the objective function of both problems. The extent to which the one particular subapp drives the optimization process depends on the weights used to obtain a total or overall sensitivity, which is used in the density update process.

Listing 3: MBB Density update in main app

[UserObjects<<<{"href": "../../../../syntax/UserObjects/index.html"}>>>]
  # We do filtering in the subapps
  [update]
    type = DensityUpdate<<<{"description": "Compute updated densities based on sensitivities using an optimality criteria method to keep the volume constraint satisified.", "href": "../../../../source/userobjects/DensityUpdate.html"}>>>
    density_sensitivity<<<{"description": "Name of the density_sensitivity variable."}>>> = total_sensitivity
    design_density<<<{"description": "Design density variable name."}>>> = mat_den
    volume_fraction<<<{"description": "Volume Fraction"}>>> = ${vol_frac}
    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."}>>> = MULTIAPP_FIXED_POINT_BEGIN
  []
[]
(modules/combined/examples/optimization/thermomechanical/thermomechanical_main.i)

The result of the optimization, which heavily depends on the many simulation and optimization parameters, is shown in what follows: