https://mooseframework.inl.gov
DensityUpdate.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #include "DensityUpdate.h"
11 #include <algorithm>
12 
13 registerMooseObject("OptimizationApp", DensityUpdate);
14 
17 {
19  params.addClassDescription(
20  "Compute updated densities based on sensitivities using an optimality criteria method to "
21  "keep the volume constraint satisified.");
22  params.addRequiredCoupledVar("design_density", "Design density variable name.");
23  params.addRequiredParam<VariableName>("density_sensitivity",
24  "Name of the density_sensitivity variable.");
25  params.addRequiredParam<Real>("volume_fraction", "Volume Fraction");
26  params.addParam<Real>("bisection_lower_bound", 0, "Lower bound for the bisection algorithm.");
27  params.addParam<Real>("bisection_upper_bound", 1e16, "Upper bound for the bisection algorithm.");
28  return params;
29 }
30 
32  : ElementUserObject(parameters),
33  _mesh(_subproblem.mesh()),
34  _density_sensitivity_name(getParam<VariableName>("density_sensitivity")),
35  _design_density(&writableVariable("design_density")),
36  _density_sensitivity(&_subproblem.getStandardVariable(_tid, _density_sensitivity_name)),
37  _volume_fraction(getParam<Real>("volume_fraction")),
38  _lower_bound(getParam<Real>("bisection_lower_bound")),
39  _upper_bound(getParam<Real>("bisection_upper_bound"))
40 {
41  if (!dynamic_cast<MooseVariableFE<Real> *>(_design_density))
42  paramError("design_density", "Design density must be a finite element variable");
43 }
44 
45 void
47 {
50 }
51 
52 void
54 {
55  // Grab the element data for each id
56  auto elem_data_iter = _elem_data_map.find(_current_elem->id());
57 
58  // Check if the element data is not null
59  if (elem_data_iter != _elem_data_map.end())
60  {
61  ElementData & elem_data = elem_data_iter->second;
62  dynamic_cast<MooseVariableFE<Real> *>(_design_density)->setNodalValue(elem_data.new_density);
63  }
64  else
65  {
66  mooseError("Element data not found for the current element id.");
67  }
68 }
69 
70 void
72 {
73  _elem_data_map.clear();
75 
76  for (const auto & sub_id : blockIDs())
77  for (const auto & elem : _mesh.getMesh().active_local_subdomain_elements_ptr_range(sub_id))
78  {
79  dof_id_type elem_id = elem->id();
80  ElementData data = ElementData(
81  dynamic_cast<MooseVariableFE<Real> *>(_design_density)->getElementalValue(elem),
82  dynamic_cast<const MooseVariableFE<Real> *>(_density_sensitivity)
83  ->getElementalValue(elem),
84  elem->volume(),
85  0);
86  _elem_data_map[elem_id] = data;
87  _total_allowable_volume += elem->volume();
88  }
89 
92 }
93 
94 void
96 {
97  // Initialize the lower and upper bounds for the bisection method
98  Real l1 = _lower_bound;
99  Real l2 = _upper_bound;
100  bool perform_loop = true;
101  // Loop until the relative difference between l1 and l2 is less than a small tolerance
102  while (perform_loop)
103  {
104  // Compute the midpoint between l1 and l2
105  Real lmid = 0.5 * (l2 + l1);
106 
107  // Initialize the current total volume
108  Real curr_total_volume = 0;
109  // Loop over all elements
110  for (auto && [id, elem_data] : _elem_data_map)
111  {
112  // Compute the updated density for the current element
113  Real new_density = computeUpdatedDensity(elem_data.old_density, elem_data.sensitivity, lmid);
114  // Update the current filtered density for the current element
115  elem_data.new_density = new_density;
116  // Update the current total volume
117  curr_total_volume += new_density * elem_data.volume;
118  }
119 
120  // Sum the current total volume across all processors
121  _communicator.sum(curr_total_volume);
122 
123  // Update l1 or l2 based on whether the current total volume is greater than the total
124  // allowable volume
125  if (curr_total_volume > _total_allowable_volume)
126  l1 = lmid;
127  else
128  l2 = lmid;
129 
130  // Determine whether to continue the loop based on the relative difference between l1 and l2
131  perform_loop = (l2 - l1) / (l1 + l2) > 1e-3;
132  }
133 }
134 
135 // Method to compute the updated density for an element
136 Real
137 DensityUpdate::computeUpdatedDensity(Real current_density, Real dc, Real lmid)
138 {
139  // Define the maximum allowable change in density
140  Real move = 0.5;
141  // Compute the updated density based on the current density, the sensitivity, and the midpoint
142  // value
143  Real updated_density = std::max(
144  0.0,
145  std::min(1.0,
146  std::min(current_density + move,
147  std::max(current_density - move,
148  std::max(1e-5, current_density) * std::sqrt(-dc / lmid)))));
149  // Return the updated density
150  return updated_density;
151 }
const Real _upper_bound
Upper bound for bisection algorithm.
Definition: DensityUpdate.h:81
Real computeUpdatedDensity(Real current_density, Real dc, Real lmid)
Real _total_allowable_volume
Total volume allowed for volume contraint.
Definition: DensityUpdate.h:73
const Real _volume_fraction
The volume fraction to be enforced.
Definition: DensityUpdate.h:44
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
static InputParameters validParams()
Element user object that performs SIMP optimization using a bisection algorithm using a volume constr...
Definition: DensityUpdate.h:19
const Real _lower_bound
Lower bound for bisection algorithm.
Definition: DensityUpdate.h:79
void gatherElementData()
Gathers element date necessary to perform the bisection algorithm for optimization.
Definition: DensityUpdate.C:71
MooseWritableVariable * _design_density
The pseudo-density variable.
Definition: DensityUpdate.h:40
virtual void execute() override
Definition: DensityUpdate.C:53
MeshBase & mesh
const MooseWritableVariable * _density_sensitivity
The filtered density sensitivity variable.
Definition: DensityUpdate.h:42
const Parallel::Communicator & _communicator
virtual const std::set< SubdomainID > & blockIDs() const
void addRequiredParam(const std::string &name, const std::string &doc_string)
registerMooseObject("OptimizationApp", DensityUpdate)
MeshBase & getMesh()
static InputParameters validParams()
Definition: DensityUpdate.C:16
void paramError(const std::string &param, Args... args) const
virtual void timestepSetup() override
Definition: DensityUpdate.C:46
void performOptimCritLoop()
Performs the optimality criterion loop (bisection)
Definition: DensityUpdate.C:95
void addRequiredCoupledVar(const std::string &name, const std::string &doc_string)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const Elem *const & _current_elem
DensityUpdate(const InputParameters &parameters)
Definition: DensityUpdate.C:31
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
std::map< dof_id_type, ElementData > _elem_data_map
Data structure to hold old density, sensitivity, volume, current density.
Definition: DensityUpdate.h:76
const MooseMesh & _mesh
The system mesh.
Definition: DensityUpdate.h:30
uint8_t dof_id_type