MAST
Multidisciplinary-design Adaptation and Sensitivity Toolkit (MAST)
first_order_newmark_transient_solver.cpp
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 // MAST includes
23 #include "base/elem_base.h"
25 #include "base/nonlinear_system.h"
26 
27 
28 // libMesh includes
29 #include "libmesh/numeric_vector.h"
30 
31 
32 MAST::FirstOrderNewmarkTransientSolver::FirstOrderNewmarkTransientSolver():
33 MAST::TransientSolverBase(1, 2),
34 beta(0.5)
35 { }
36 
37 
38 MAST::FirstOrderNewmarkTransientSolver::~FirstOrderNewmarkTransientSolver()
39 { }
40 
41 
42 
43 void
44 MAST::FirstOrderNewmarkTransientSolver::
45 set_element_data(const std::vector<libMesh::dof_id_type>& dof_indices,
46  const std::vector<libMesh::NumericVector<Real>*>& sols) {
47 
48  libmesh_assert_equal_to(sols.size(), 2);
49 
50  const unsigned int n_dofs = (unsigned int)dof_indices.size();
51 
52  // get the current state and velocity estimates
53  // also get the current discrete velocity replacement
55  sol = RealVectorX::Zero(n_dofs),
56  vel = RealVectorX::Zero(n_dofs);
57 
58 
59  const libMesh::NumericVector<Real>
60  &sol_global = *sols[0],
61  &vel_global = *sols[1];
62 
63  // get the references to current and previous sol and velocity
64 
65  for (unsigned int i=0; i<n_dofs; i++) {
66 
67  sol(i) = sol_global(dof_indices[i]);
68  vel(i) = vel_global(dof_indices[i]);
69  }
70 
71  _assembly_ops->set_elem_solution(sol);
72  _assembly_ops->set_elem_velocity(vel);
73 }
74 
75 
76 
77 void
78 MAST::FirstOrderNewmarkTransientSolver::
79 extract_element_sensitivity_data(const std::vector<libMesh::dof_id_type>& dof_indices,
80  const std::vector<libMesh::NumericVector<Real>*>& sols,
81  std::vector<RealVectorX>& local_sols) {
82 
83  libmesh_assert_equal_to(sols.size(), 2);
84 
85  const unsigned int n_dofs = (unsigned int)dof_indices.size();
86 
87  local_sols.resize(2);
88 
90  &sol = local_sols[0],
91  &vel = local_sols[1];
92 
93  sol = RealVectorX::Zero(n_dofs);
94  vel = RealVectorX::Zero(n_dofs);
95 
96  const libMesh::NumericVector<Real>
97  &sol_global = *sols[0],
98  &vel_global = *sols[1];
99 
100  // get the references to current and previous sol and velocity
101 
102  for (unsigned int i=0; i<n_dofs; i++) {
103 
104  sol(i) = sol_global(dof_indices[i]);
105  vel(i) = vel_global(dof_indices[i]);
106  }
107 
108 }
109 
110 
111 
112 void
113 MAST::FirstOrderNewmarkTransientSolver::
114 set_element_perturbed_data(const std::vector<libMesh::dof_id_type>& dof_indices,
115  const std::vector<libMesh::NumericVector<Real>*>& sols){
116 
117  libmesh_assert_equal_to(sols.size(), 2);
118 
119  const unsigned int n_dofs = (unsigned int)dof_indices.size();
120 
121  // get the current state and velocity estimates
122  // also get the current discrete velocity replacement
124  sol = RealVectorX::Zero(n_dofs),
125  vel = RealVectorX::Zero(n_dofs);
126 
127 
128  const libMesh::NumericVector<Real>
129  &sol_global = *sols[0],
130  &vel_global = *sols[1];
131 
132  // get the references to current and previous sol and velocity
133 
134  for (unsigned int i=0; i<n_dofs; i++) {
135 
136  sol(i) = sol_global(dof_indices[i]);
137  vel(i) = vel_global(dof_indices[i]);
138  }
139 
140  _assembly_ops->set_elem_perturbed_solution(sol);
141  _assembly_ops->set_elem_perturbed_velocity(vel);
142 }
143 
144 
145 
146 
147 
148 void
149 MAST::FirstOrderNewmarkTransientSolver::
150 update_velocity(libMesh::NumericVector<Real>& vec,
151  const libMesh::NumericVector<Real>& sol) {
152 
153  const libMesh::NumericVector<Real>
154  &prev_sol = this->solution(1),
155  &prev_vel = this->velocity(1);
156 
157  vec = sol;
158  vec.add(-1., prev_sol);
159  vec.scale(1./beta/dt);
160  vec.close();
161  vec.add(-(1.-beta)/beta, prev_vel);
162 
163  vec.close();
164 }
165 
166 
167 
168 void
169 MAST::FirstOrderNewmarkTransientSolver::
170 update_sensitivity_velocity(libMesh::NumericVector<Real>& vec,
171  const libMesh::NumericVector<Real>& sol) {
172 
173  const libMesh::NumericVector<Real>
174  &prev_sol = this->solution_sensitivity(1),
175  &prev_vel = this->velocity_sensitivity(1);
176 
177  vec = sol;
178  vec.add(-1., prev_sol);
179  vec.scale(1./beta/dt);
180  vec.close();
181  vec.add(-(1.-beta)/beta, prev_vel);
182 
183  vec.close();
184 }
185 
186 
187 
188 void
189 MAST::FirstOrderNewmarkTransientSolver::
190 update_delta_velocity(libMesh::NumericVector<Real>& vec,
191  const libMesh::NumericVector<Real>& sol) {
192 
193  vec = sol;
194  vec.scale( 1./beta/dt);
195  vec.close();
196 }
197 
198 
199 
200 
201 
202 void
203 MAST::FirstOrderNewmarkTransientSolver::
204 elem_calculations(bool if_jac,
205  RealVectorX& vec,
206  RealMatrixX& mat) {
207  // make sure that the assembly object is provided
208  libmesh_assert(_assembly_ops);
209  unsigned int n_dofs = (unsigned int)vec.size();
210 
212  f_x = RealVectorX::Zero(n_dofs),
213  f_m = RealVectorX::Zero(n_dofs);
214 
216  f_m_jac_xdot = RealMatrixX::Zero(n_dofs, n_dofs),
217  f_m_jac = RealMatrixX::Zero(n_dofs, n_dofs),
218  f_x_jac = RealMatrixX::Zero(n_dofs, n_dofs);
219 
220  // perform the element assembly
221  _assembly_ops->elem_calculations(if_jac,
222  f_m, // mass vector
223  f_x, // forcing vector
224  f_m_jac_xdot, // Jac of mass wrt x_dot
225  f_m_jac, // Jac of mass wrt x
226  f_x_jac); // Jac of forcing vector wrt x
227 
228  if (_if_highest_derivative_solution) {
229 
230  //
231  // The residual here is modeled as
232  // r(x, xdot) = f_m(x, xdot) + f_x(x, xdot)= 0
233  //
234  // then, given x = x0, the residual can be used to evaluate xdot0 at
235  // the same time step as
236  //
237  // r(x0, xdot) + dr/dxdot dxdot = 0
238  //
239 
240  // system residual
241  vec = (f_m + f_x);
242 
243  // system Jacobian
244  if (if_jac)
245  mat = f_m_jac_xdot;
246  }
247  else {
248  //
249  // The residual here is modeled as
250  // r = (f_m + f_x )= 0
251  // where, (for example)
252  // f_m = int_Omega phi u_dot [typical mass vector in conduction, for example]
253  // f_x = int_Omega phi_i u_i - int_Gamma phi q_n [typical conductance and heat flux combination, for example]
254  //
255  // This method assumes
256  // x = x0 + (1-beta) dt x0_dot + beta dt x_dot
257  // or, x_dot = (x-x0)/beta/dt - (1-beta)/beta x0_dot
258  //
259  // Both f_m and f_x can be functions of x_dot and x. Then, the
260  // Jacobian is
261  // dr/dx =[df_m/dx + df_x/dx +
262  // df_m/dx_dot dx_dot/dx + df_x/dx_dot dx_dot/dx]
263  // = [(df_m/dx + df_x/dx) +
264  // (df_m/dx_dot + df_x/dx_dot) (1/beta/dt)]
265  // = (df_m/dx + df_x/dx) +
266  // 1/(beta*dt)(df_m/dx_dot + df_x/dx_dot)
267  // Note that this form of equations makes it a good candidate for
268  // use as implicit solver, ie, for a nonzero beta.
269  //
270 
271 
272  // system residual
273  vec = (f_m + f_x);
274 
275  // system Jacobian
276  if (if_jac)
277  mat = (1./beta/dt)*f_m_jac_xdot + (f_m_jac + f_x_jac);
278  }
279 }
280 
281 
282 
283 void
286 
287  // make sure that the assembly object is provided
288  libmesh_assert(_assembly_ops);
289 
290  // perform the element assembly
291  _assembly_ops->linearized_jacobian_solution_product(vec);
292 }
293 
294 
295 
296 
297 void
300  RealVectorX& vec) {
301 
302  // make sure that the assembly object is provided
303  libmesh_assert(_assembly_ops);
304  unsigned int n_dofs = (unsigned int)vec.size();
305 
307  f_x = RealVectorX::Zero(n_dofs),
308  f_m = RealVectorX::Zero(n_dofs);
309 
310  // perform the element assembly
311  _assembly_ops->elem_sensitivity_calculations(f,
312  f_m, // mass vector
313  f_x); // forcing vector
314 
315  // sensitivity of system residual involving mass and internal force term
316  vec = (f_m + f_x);
317 }
318 
319 
320 
321 void
323 elem_sensitivity_contribution_previous_timestep(const std::vector<RealVectorX>& prev_sols,
324  RealVectorX& vec) {
325 
326  // nothing to be done for highest derivative term
327  if (_if_highest_derivative_solution) return;
328 
329  // make sure that the assembly object is provided
330  libmesh_assert(_assembly_ops);
331  libmesh_assert_equal_to(prev_sols.size(), 2);
332 
333  unsigned int n_dofs = (unsigned int)vec.size();
334 
335  const RealVectorX
336  &sol = prev_sols[0],
337  &vel = prev_sols[1];
339  dummy_vec = RealVectorX::Zero(n_dofs);
340 
342  f_m_jac_xdot = RealMatrixX::Zero(n_dofs, n_dofs),
343  dummy_mat = RealMatrixX::Zero(n_dofs, n_dofs);
344 
345  // perform the element assembly
346  _assembly_ops->elem_calculations(true,
347  dummy_vec, // mass vector
348  dummy_vec, // forcing vector
349  f_m_jac_xdot, // Jac of mass wrt x_dot
350  dummy_mat, // Jac of mass wrt x
351  dummy_mat); // Jac of forcing vector wrt x
352 
353  vec = -1.*(f_m_jac_xdot * ( (1./beta/dt)*sol + (1.-beta)/beta * vel));
354 }
355 
356 
357 
358 void
361  RealVectorX& vec) {
362 
363  libmesh_assert(false); // to be implemented
364 }
365 
366 
367 
368 void
371  RealVectorX& vec) {
372  libmesh_assert(false); // to be implemented
373 }
374 
375 
376 
377 void
381  RealVectorX& vec) {
382  libmesh_assert(false); // to be implemented
383 }
384 
385 
386 
virtual void elem_sensitivity_calculations(const MAST::FunctionBase &f, RealVectorX &vec)
performs the element sensitivity calculations over elem, and returns the element residual sensitivity...
virtual void elem_sensitivity_contribution_previous_timestep(const std::vector< RealVectorX > &prev_sols, RealVectorX &vec)
computes the contribution for this element from previous time step
virtual void elem_topology_sensitivity_calculations(const MAST::FunctionBase &f, RealVectorX &vec)
performs the element topology sensitivity calculations over elem, and returns the element residual se...
Matrix< Real, Dynamic, Dynamic > RealMatrixX
Matrix< Real, Dynamic, 1 > RealVectorX
virtual void elem_linearized_jacobian_solution_product(RealVectorX &vec)
This class implements the Newmark solver for solution of a first-order ODE.
virtual void elem_shape_sensitivity_calculations(const MAST::FunctionBase &f, RealVectorX &vec)
performs the element shape sensitivity calculations over elem, and returns the element residual sensi...