Smith  0.1
Smith is an implicit thermal structural mechanics simulation code.
explicit_dynamic_solve.hpp
Go to the documentation of this file.
1 // Copyright (c) Lawrence Livermore National Security, LLC and
2 // other Smith Project Developers. See the top-level LICENSE file for
3 // details.
4 //
5 // SPDX-License-Identifier: (BSD-3-Clause)
6 
11 #pragma once
12 
17 
18 namespace smith {
19 
25 inline FieldState computeLumpedMass(const WeakForm* mass_residual_eval, const FieldState& shape_u,
26  const FieldState& lumped_field, const FieldState& rho)
27 {
28  std::vector<gretl::StateBase> inputs{shape_u, rho, lumped_field};
29 
30  FieldState z = lumped_field.clone(inputs);
31 
32  z.set_eval([=](const gretl::UpstreamStates& upstreams, gretl::DownstreamState& downstream) {
33  const FEFieldPtr& ShapeDisp = upstreams[0].get<FEFieldPtr>();
34  const FEFieldPtr& Rho = upstreams[1].get<FEFieldPtr>();
35  const FEFieldPtr& LumpedOutputFieldForSizing = upstreams[2].get<FEFieldPtr>();
36 
37  FEFieldPtr Z = std::make_shared<FiniteElementState>(
38  LumpedOutputFieldForSizing->space(),
39  "diag_mass"); // create a pointer to a new FE space for our new values to live in
40 
41  auto m_diagonal = mass_residual_eval->residual(
42  TimeInfo(0.0, 0.0), ShapeDisp.get(),
43  getConstFieldPointers(Rho)); // diagonal of the diagonalized lumped mass matrix, in mfem vector format
44  *Z = m_diagonal;
45 
46  downstream.set<FEFieldPtr, FEDualPtr>(Z); // Set the output to our new values
47  });
48 
49  z.set_vjp([=](gretl::UpstreamStates& upstreams, const gretl::DownstreamState& downstream) {
50  const FEDualPtr& Z_dual = downstream.get_dual<FEDualPtr, FEFieldPtr>();
51  const FEFieldPtr& ShapeDisp = upstreams[0].get<FEFieldPtr>(); // shape disp tate
52  const FEFieldPtr& Rho = upstreams[1].get<FEFieldPtr>(); // density parameter state
53  FEDualPtr& Shape_dual = upstreams[0].get_dual<FEDualPtr, FEFieldPtr>(); // dual of shape parameter state
54  FEDualPtr& Rho_dual = upstreams[1].get_dual<FEDualPtr, FEFieldPtr>(); // dual of density parameter state
55 
56  FiniteElementState Z_dual_state(Z_dual->space(), Z_dual->name());
57  Z_dual_state = *Z_dual;
58 
59  mass_residual_eval->vjp(TimeInfo(0.0, 0.0), ShapeDisp.get(), getConstFieldPointers(Rho), {}, &Z_dual_state,
60  Shape_dual.get(), getFieldPointers(Rho_dual), {});
61  });
62 
63  return z.finalize();
64 }
65 
68 {
69  auto z = x.clone({x});
70  z.set_eval([](const gretl::UpstreamStates& upstreams, gretl::DownstreamState& downstream) {
71  const FEFieldPtr& X = upstreams[0].get<FEFieldPtr>();
72  FEFieldPtr Z = std::make_shared<FiniteElementState>(X->space(), "diag_inverse");
73  FiniteElementState& X_ = *upstreams[0].get<FEFieldPtr>();
74  auto Z_ = *Z;
75  int sz = X_.Size();
76  for (int index = 0; index < sz; index++) {
77  Z_[index] = 1 / X_[index];
78  }
79  *Z = Z_;
80  downstream.set<FEFieldPtr, FEDualPtr>(Z);
81  });
82 
83  z.set_vjp([](gretl::UpstreamStates& upstreams, const gretl::DownstreamState& downstream) {
84  FiniteElementDual& Z_dual = *downstream.get_dual<FEDualPtr, FEFieldPtr>();
85  FiniteElementDual& X_dual = *upstreams[0].get_dual<FEDualPtr, FEFieldPtr>();
86  FiniteElementState& X_ = *upstreams[0].get<FEFieldPtr>();
87  int sz = X_.Size();
88  for (int index = 0; index < sz; index++) {
89  X_dual[index] -= Z_dual[index] / (std::pow(X_[index], 2));
90  }
91  });
92 
93  return z.finalize();
94 }
95 
99 inline FieldState evalResidual(const WeakForm* residual_eval, FieldState shape_disp,
100  const std::vector<FieldState>& states, const std::vector<FieldState>& params,
101  TimeInfo time_info, size_t inertial_index)
102 {
103  std::vector<gretl::StateBase> allStateBases;
104  for (auto& s : states) allStateBases.push_back(s);
105  for (auto& p : params) allStateBases.push_back(p);
106  allStateBases.push_back(shape_disp);
107  auto z = states[inertial_index].clone(allStateBases);
108 
109  z.set_eval([=](const gretl::UpstreamStates& inputs, gretl::DownstreamState& output) {
111 
112  size_t num_fields = inputs.size() - 1; // get the number of non-shapedisp input fields
113  std::vector<ConstFieldPtr> fields(num_fields); // set up fields vector
114 
115  // Convert from gretl FieldState to FiniteElementState pointers, stored in the FEFieldPointer array corrected_fields
116  // Fields should be in the order shape_u, u, v, a
117  for (size_t field_index = 0; field_index < num_fields; ++field_index) {
118  fields[field_index] = inputs[field_index].get<FEFieldPtr>().get();
119  }
120 
121  FEFieldPtr R =
122  std::make_shared<FiniteElementState>(fields[inertial_index]->space(), "residual"); // set up output pointer
123 
124  // set the acceleration field equal to zero here, so that when we evaluate the residual, we get zero contribution
125  // from the acceleration and mass, because acceleration and mass are being accounted for elsewhere
126  FiniteElementState zero_accel(*fields[inertial_index]);
127  fields[inertial_index] = &zero_accel;
128 
129  // evaluate the residual with zero acceleration contribution
130  *R = residual_eval->residual(time_info, inputs[num_fields].get<FEFieldPtr>().get(), fields);
131 
132  output.set<FEFieldPtr, FEDualPtr>(R);
133  });
134 
135  z.set_vjp([=](gretl::UpstreamStates& inputs, const gretl::DownstreamState& output) {
137 
138  const FEFieldPtr Z = output.get<FEFieldPtr>();
139  const FEDualPtr Z_dual = output.get_dual<FEDualPtr, FEFieldPtr>();
140  FiniteElementState Z_dual_state(Z_dual->space(), Z_dual->name());
141  Z_dual_state = *Z_dual;
142 
143  // get the input values and store them in corrected_fields
144  size_t num_fields = inputs.size() - 1;
145  std::vector<ConstFieldPtr> fields(num_fields);
146  for (size_t field_index = 0; field_index < num_fields; ++field_index) {
147  fields[field_index] = inputs[field_index].get<FEFieldPtr>().get();
148  }
149 
150  // set the acceleration field equal to zero here, so that when we evaluate the residual, we get zero contribution
151  // from the acceleration and mass, because acceleration and mass are being accounted for elsewhere
152  FiniteElementState zero_accel(*fields[inertial_index]);
153  fields[inertial_index] = &zero_accel;
154 
155  std::vector<DualFieldPtr> field_sensitivities(num_fields);
156  for (size_t field_index = 0; field_index < num_fields; ++field_index) {
157  field_sensitivities[field_index] = inputs[field_index].get_dual<FEDualPtr, FEFieldPtr>().get();
158  }
159  // setting the field sensitivity to nullptr means if will not be computed in the vjp call
160  field_sensitivities[inertial_index] = nullptr;
161 
162  auto shape_disp_ptr = inputs[num_fields].get<FEFieldPtr>();
163  auto shape_disp_sensitivity_ptr = inputs[num_fields].get_dual<FEDualPtr, FEFieldPtr>();
164 
165  // set the dual fields for each input, using the call to residual that pulls the derivative
166  residual_eval->vjp(time_info, shape_disp_ptr.get(), fields, {}, &Z_dual_state, shape_disp_sensitivity_ptr.get(),
167  field_sensitivities, {});
168  });
169 
170  return z.finalize();
171 }
172 
176  const BoundaryConditionManager* bc_manager)
177 {
178  SLIC_ERROR_IF(x.get()->Size() != y.get()->Size(), "Trying to component wise multiple vectors with different sizes");
179  auto z = x.clone({x, y});
180 
181  z.set_eval([=](const gretl::UpstreamStates& upstreams, gretl::DownstreamState& downstream) {
182  const FEFieldPtr& X = upstreams[0].get<FEFieldPtr>();
183  FEFieldPtr Z = std::make_shared<FiniteElementState>(X->space(), "ComponentMult");
184  const FiniteElementState& X_ = *upstreams[0].get<FEFieldPtr>();
185  const FiniteElementState& Y_ = *upstreams[1].get<FEFieldPtr>();
186  auto Z_ = *Z;
187 
188  int sz = X_.Size();
189  for (int index = 0; index < sz; index++) {
190  Z_[index] = X_[index] * Y_[index];
191  }
192 
193  *Z = Z_;
194 
195  // enforce zero acceleration at fixed BCs
196  if (bc_manager) {
197  Z->SetSubVector(bc_manager->allEssentialTrueDofs(), 0.0);
198  }
199 
200  downstream.set<FEFieldPtr, FEDualPtr>(Z);
201  });
202 
203  z.set_vjp([=](gretl::UpstreamStates& upstreams, const gretl::DownstreamState& downstream) {
204  auto Z_dual = *downstream.get_dual<FEDualPtr, FEFieldPtr>();
205  const FiniteElementState& X = *upstreams[0].get<FEFieldPtr>();
206  const FiniteElementState& Y = *upstreams[1].get<FEFieldPtr>();
207  FiniteElementDual& X_dual = *upstreams[0].get_dual<FEDualPtr, FEFieldPtr>();
208  FiniteElementDual& Y_dual = *upstreams[1].get_dual<FEDualPtr, FEFieldPtr>();
209 
210  // enforce zero acceleration at fixed BCs
211  if (bc_manager) {
212  Z_dual.SetSubVector(bc_manager->allEssentialTrueDofs(), 0.0);
213  }
214 
215  int sz = X.Size();
216  for (int index = 0; index < sz; index++) {
217  X_dual[index] += Z_dual[index] * Y[index];
218  Y_dual[index] += Z_dual[index] * X[index];
219  }
220  });
221 
222  return z.finalize();
223 }
224 
230  const BoundaryConditionManager* bc_manager)
231 {
232  SLIC_ERROR_IF(x.get()->Size() != y.get()->Size(), "Trying to component wise multiple vectors with different sizes");
233  auto z = x.clone({x, y});
234 
235  z.set_eval([=](const gretl::UpstreamStates& upstreams, gretl::DownstreamState& downstream) {
236  const FEFieldPtr& X = upstreams[0].get<FEFieldPtr>();
237  FEFieldPtr Z = std::make_shared<FiniteElementState>(X->space(), "ComponentMult");
238  const FiniteElementState& X_ = *upstreams[0].get<FEFieldPtr>();
239  const FiniteElementState& Y_ = *upstreams[1].get<FEFieldPtr>();
240  auto Z_ = *Z;
241 
242  int sz = X_.Size();
243  for (int index = 0; index < sz; index++) {
244  Z_[index] = -X_[index] * Y_[index];
245  }
246 
247  *Z = Z_;
248 
249  // enforce zero acceleration at fixed BCs
250  if (bc_manager) {
251  Z->SetSubVector(bc_manager->allEssentialTrueDofs(), 0.0);
252  }
253 
254  downstream.set<FEFieldPtr, FEDualPtr>(Z);
255  });
256 
257  z.set_vjp([=](gretl::UpstreamStates& upstreams, const gretl::DownstreamState& downstream) {
258  auto Z_dual = *downstream.get_dual<FEDualPtr, FEFieldPtr>();
259  const FiniteElementState& X = *upstreams[0].get<FEFieldPtr>();
260  const FiniteElementState& Y = *upstreams[1].get<FEFieldPtr>();
261  FiniteElementDual& X_dual = *upstreams[0].get_dual<FEDualPtr, FEFieldPtr>();
262  FiniteElementDual& Y_dual = *upstreams[1].get_dual<FEDualPtr, FEFieldPtr>();
263 
264  // enforce zero acceleration at fixed BCs
265  if (bc_manager) {
266  Z_dual.SetSubVector(bc_manager->allEssentialTrueDofs(), 0.0);
267  }
268 
269  int sz = X.Size();
270  for (int index = 0; index < sz; index++) {
271  X_dual[index] -= Z_dual[index] * Y[index];
272  Y_dual[index] -= Z_dual[index] * X[index];
273  }
274  });
275 
276  return z.finalize();
277 }
278 
279 } // namespace smith
This file contains the declaration of the boundary condition manager class.
A container for the boundary condition information relating to a specific physics module.
const mfem::Array< int > & allEssentialTrueDofs() const
Returns all the true degrees of freedom associated with all the essential BCs.
Class for encapsulating the dual vector space of a finite element space (i.e. the space of linear for...
Class for encapsulating the critical MFEM components of a primal finite element field.
Abstract WeakForm class.
Definition: weak_form.hpp:36
virtual mfem::Vector residual(TimeInfo time_info, ConstFieldPtr shape_disp, const std::vector< ConstFieldPtr > &fields, const std::vector< ConstQuadratureFieldPtr > &quad_fields={}) const =0
Virtual interface for computing the residual vector of a weak form.
virtual void vjp(TimeInfo time_info, ConstFieldPtr shape_disp, const std::vector< ConstFieldPtr > &fields, const std::vector< ConstQuadratureFieldPtr > &quad_fields, ConstFieldPtr v_field, DualFieldPtr vjp_shape_disp_sensitivity, const std::vector< DualFieldPtr > &vjp_sensitivities, const std::vector< QuadratureFieldPtr > &vjp_quadrature_sensivities) const =0
Vector-Jacobian product, will += into existing values in vjpFields.
smith::functional implementation for evaluating nodal lumped masses, give an input density field
Accelerator functionality.
Definition: smith.cpp:36
FieldState diagInverse(const FieldState &x)
gretl-function implementation to compute invert the values for every entry in a FieldState.
FieldState evalResidual(const WeakForm *residual_eval, FieldState shape_disp, const std::vector< FieldState > &states, const std::vector< FieldState > &params, TimeInfo time_info, size_t inertial_index)
gretl-function implementation which evaluates the residual force (which is minus the mechanical force...
constexpr T & get(variant< T0, T1 > &v)
Returns the variant member of specified type.
Definition: variant.hpp:338
std::shared_ptr< FiniteElementState > FEFieldPtr
typedef
Definition: field_state.hpp:20
std::vector< FiniteElementState * > getFieldPointers(std::vector< FieldState > &states, std::vector< FieldState > params={})
Get a vector of FieldPtr or DualFieldPtr from a vector of FieldState.
gretl::State< FEFieldPtr, FEDualPtr > FieldState
typedef
Definition: field_state.hpp:22
FieldState componentWiseMult(const FieldState &x, const FieldState &y, const BoundaryConditionManager *bc_manager)
gretl-function implementation which multiplies x and y component-wise to create a new FieldState....
FieldState computeLumpedMass(const WeakForm *mass_residual_eval, const FieldState &shape_u, const FieldState &lumped_field, const FieldState &rho)
gretl-function implementation to compute lumped mass vectors from shape_displacements FieldState and ...
std::shared_ptr< FiniteElementDual > FEDualPtr
typedef
Definition: field_state.hpp:21
SMITH_HOST_DEVICE auto pow(dual< gradient_type > a, dual< gradient_type > b)
implementation of a (dual) raised to the b (dual) power
Definition: dual.hpp:405
std::vector< const FiniteElementState * > getConstFieldPointers(const std::vector< FieldState > &states, const std::vector< FieldState > &params={})
Get a vector of ConstFieldPtr or ConstDualFieldPtr from a vector of FieldState.
FieldState negativeComponentWiseMult(const FieldState &x, const FieldState &y, const BoundaryConditionManager *bc_manager)
gretl-function implementation which multiplies and then negates x and y component-wise to create a ne...
mfem::ParFiniteElementSpace & space(FieldState field)
Get the space from the primal field of a field states.
#define SMITH_MARK_FUNCTION
Definition: profiling.hpp:90
struct storing time and timestep information
Definition: common.hpp:18
Specifies interface for evaluating weak form residuals and their gradients.