MAST3
Multidisciplinary-design Adaptation and Sensitivity Toolkit (MAST)
assemble_output_sensitivity.hpp
Go to the documentation of this file.
1 /*
2 * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit
3 * Copyright (C) 2013-2020 Manav Bhatia and MAST authors
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19 
20 #ifndef __mast_optimization_topology_simp_libmesh_output_sensitivity_h__
21 #define __mast_optimization_topology_simp_libmesh_output_sensitivity_h__
22 
23 // MAST includes
25 #include <mast/base/exceptions.hpp>
31 
32 // libMesh includes
33 #include <libmesh/nonlinear_implicit_system.h>
34 #include <libmesh/dof_map.h>
35 
36 
37 namespace MAST {
38 namespace Optimization {
39 namespace Topology {
40 namespace SIMP {
41 namespace libMeshWrapper {
42 
43 template <typename ScalarType,
44  typename ResidualElemOpsType,
45  typename OutputElemOpsType>
47 
48 public:
49 
50  static_assert(std::is_same<ScalarType,
51  typename ResidualElemOpsType::scalar_t>::value,
52  "Scalar type of assembly and element operations must be same");
53  static_assert(std::is_same<ScalarType,
54  typename OutputElemOpsType::scalar_t>::value,
55  "Scalar type of assembly and element operations must be same");
56 
57 
59  _e_ops (nullptr),
60  _output_e_ops (nullptr)
61  { }
62 
64 
65  inline void set_elem_ops(ResidualElemOpsType &e_ops,
66  OutputElemOpsType &output_ops) {
67 
68  _e_ops = &e_ops;
69  _output_e_ops = &output_ops;
70  }
71 
76  template <typename Vec1Type,
77  typename Vec2Type,
78  typename ContextType,
79  typename FilterType>
80  inline void assemble(ContextType &c,
81  const Vec1Type &X,
82  const Vec2Type &density,
83  const Vec1Type &X_adj,
84  const FilterType &filter,
86  std::vector<ScalarType> &sens) {
87 
88  Assert0(_e_ops && _output_e_ops, "Elem Operation objects not initialized");
89  Assert2(density.size() == c.rho_sys->n_dofs(),
90  density.size(), c.rho_sys->n_dofs(),
91  "Density coefficients must be provided for whole mesh");
92  Assert2(dvs.size() == sens.size(),
93  dvs.size(), sens.size(),
94  "DV and sensitivity vectors must have same size");
95 
96  uint_t
97  n_density_dofs = c.rho_sys->n_dofs(),
98  n_nodes = 0;
99 
101 
102  std::unique_ptr<Vec2Type>
103  v (MAST::Numerics::Utility::build<Vec2Type>(*c.rho_sys).release()),
104  v_filtered (MAST::Numerics::Utility::build<Vec2Type>(*c.rho_sys).release());
105 
106  // iterate over each element, initialize it and get the relevant
107  // analysis quantities
109  sol_accessor (*c.sys, X),
110  adj_accessor (*c.sys, X_adj);
111 
113  density_accessor (*c.rho_sys, density);
114 
115  using elem_vector_t = typename ResidualElemOpsType::vector_t;
116  using elem_matrix_t = typename ResidualElemOpsType::matrix_t;
117 
118  elem_vector_t
119  dres_e,
120  drho;
121 
122  uint_t
123  idx = 0;
124 
125  libMesh::MeshBase::const_element_iterator
126  el = c.mesh->active_local_elements_begin(),
127  end_el = c.mesh->active_local_elements_end();
128 
129  // first compute the sensitivity information assuming unfiltered
130  // density variables.
131  for ( ; el != end_el; ++el) {
132 
133  // set element in the context, which will be used for
134  // the initialization routines
135  c.elem = *el;
136 
137  sol_accessor.init(*c.elem);
138  density_accessor.init(*c.elem);
139  adj_accessor.init(*c.elem);
140 
141  const std::vector<libMesh::dof_id_type>
142  &density_dof_ids = density_accessor.dof_indices();
143 
145 
146  for (uint_t i=0; i<n_nodes; i++) {
147 
148  if (!dvs.is_design_parameter_dof_id(density_dof_ids[i]))
149  continue;
150 
151  // this assumes that if the DV (which is associated with a node)
152  // is connected to this element, then the dof_indices for this
153  // element will contain this index. If not, then the contribution
154  // of this element to the sensitivity is zero.
155 
156  idx = dvs.get_dv_id_for_topology_dof(density_dof_ids[i]);
158  &dv = dvs[idx];
159 
160  // set a unit value of density sensitivity
161  // for this dof
162  drho.setZero(density_dof_ids.size());
163  drho(i) = 1.;
164 
165  dres_e.setZero(sol_accessor.n_dofs());
166 
167  // first we compute the partial derivative of the
168  // residual wrt the parameter.
169  _e_ops->derivative(c,
170  dv,
171  sol_accessor,
172  density_accessor,
173  drho,
174  dres_e,
175  nullptr);
176 
177  // next, we compute the partial derivative derivative of
178  // the output functional and add it to the sensitivity result
180  (*v,
181  density_dof_ids[i],
182  _output_e_ops->derivative(c, // partial derivative of output
183  dv,
184  sol_accessor,
185  density_accessor,
186  drho)
187  + adj_accessor.dot(dres_e)); // the adjoint vector combined w/ res sens
188  }
189  }
190 
192 
193  // Now, combine the sensitivty with the filtering data
194  filter.compute_reverse_filtered_values(*v, *v_filtered);
195 
196  // copy the results back to sens
197  for (uint_t i=dvs.local_begin(); i<dvs.local_end(); i++) {
198 
199  idx = dvs.get_data_for_parameter(dvs[i]).template get<int>("dof_id");
200  sens[i] = MAST::Numerics::Utility::get(*v_filtered, idx);
201  }
202 
203  MAST::Numerics::Utility::comm_sum(c.rho_sys->comm(), sens);
204  }
205 
206 private:
207 
208  ResidualElemOpsType *_e_ops;
209  OutputElemOpsType *_output_e_ops;
210 };
211 
212 } // namespace libMeshWrapper
213 } // namespace SIMP
214 } // namespace Topology
215 } // namespace Optimization
216 } // namespace MAST
217 
218 
219 #endif // __mast_optimization_topology_simp_libmesh_output_sensitivity_h__
ScalarType get(const std::vector< ScalarType > &v, uint_t i)
Definition: utility.hpp:232
void init(const libMesh::Elem &e)
Definition: accessor.hpp:69
void setZero(ValType &m)
Definition: utility.hpp:44
void finalize(ValType &m)
Definition: utility.hpp:252
const std::vector< libMesh::dof_id_type > & dof_indices() const
Definition: accessor.hpp:55
std::enable_if< Dim< 3, ScalarType >::typesource_load_multiplier(const SourceLoadFieldType *f, const SectionAreaType *s, ContextType &c) { Assert0(f, "Invalid pointer");Assert0(s, "Invalid pointer");return f-> value(c) *s -> value(c)
void set_elem_ops(ResidualElemOpsType &e_ops, OutputElemOpsType &output_ops)
void assemble(ContextType &c, const Vec1Type &X, const Vec2Type &density, const Vec1Type &X_adj, const FilterType &filter, const MAST::Optimization::DesignParameterVector< ScalarType > &dvs, std::vector< ScalarType > &sens)
output derivative is defined as a
const MAST::Base::ParameterData & get_data_for_parameter(const MAST::Optimization::DesignParameter< ScalarType > &p) const
#define Assert0(cond, msg)
Definition: exceptions.hpp:134
uint_t n_linear_basis_nodes_on_elem(const libMesh::Elem &e)
identifies number of ndoes on element
Definition: utility.hpp:39
unsigned int uint_t
void add(std::vector< ScalarType > &v, uint_t i, ScalarType s)
Definition: utility.hpp:188
#define Assert2(cond, v1, v2, msg)
Definition: exceptions.hpp:152
void comm_sum(const libMesh::Parallel::Communicator &comm, real_t &v)
Definition: utility.hpp:328
uint_t get_dv_id_for_topology_dof(const uint_t id) const