MAST
structural_system.cpp
Go to the documentation of this file.
1 /*
2  * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit
3  * Copyright (C) 2013-2019 Manav Bhatia
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 // C++ includes
21 #include <vector>
22 
23 // MAST includes
25 #include "base/parameter.h"
26 
27 // libMesh includes
28 #include "libmesh/numeric_vector.h"
29 #include "libmesh/equation_systems.h"
30 #include "libmesh/sparse_matrix.h"
31 #include "libmesh/eigen_solver.h"
32 #include "libmesh/dof_map.h"
33 
34 
35 MAST::StructuralSystem::StructuralSystem(libMesh::EquationSystems& es,
36  const std::string& name,
37  const unsigned int number):
38 MAST::NonlinearSystem(es, name, number),
39 _iter(0),
40 _beta(0.),
41 _dl(0.),
42 _load_param(nullptr),
43 _min_p(0.),
44 _max_p(0.) {
45 
46 }
47 
48 
49 
51 
52 }
53 
54 
55 
56 void
58  Real min_p,
59  Real max_p) {
60 
61  // make sure that it has not already been set
62  libmesh_assert(!_load_param);
63 
64  _load_param = &param;
65  _min_p = min_p;
66  _max_p = max_p;
67 }
68 
69 
70 
71 void
73 
74  _load_param = nullptr;
75  _beta = 0.;
76  _dl = 0.;
77 
78 
80 }
81 
82 
83 
84 void
86  MAST::AssemblyBase& assembly) {
87 
88  // the system solves for both the structural displacement and
89  // load update using a constraint definition
90  //
91  // the governing equations are
92  // r = 0 (structural residual)
93  // g = 0 (constraint equation)
94  //
95  // the displacement and load steps are termed delta_x and delta_p. The
96  // Newton updates to these two quantities are termed dx and dp. Hence,
97  // each load increment seeks to solve for both delta_x and delta_p, while
98  // this nonlinear solution finds the incremental updates dx and dp so that
99  // the above two equations are satisfied.
100  //
101  // for j as the load step and k as the N-R iterate,
102  // x_j = x_(j-1) + delta_x_k
103  // p_j = p_(j-1) + delta_p_k
104  //
105  // delta_x_k = delta_x_(k-1) + dx_k
106  // delta_p_k = delta_p_(k-1) + dp_k
107  //
108  // the linearized form is (where dx and dp are k_th N-R updates for j_th
109  // load step).
110  // dr/dx dx + dr/dp dp = -r
111  // (dg/dx)^T dx + dg/dp dp = -g
112  //
113  //
114  // the system is solved as follows:
115  // dx1 = - inv(dr/dx) r
116  // dx2 = - inv(dr/dx) dr/dp
117  // so that
118  // dx = dx1 + dp dx2, and
119  // delta_x = delta_x_(k-1) + dx
120  //
121  // we use a quadratic constraint equation:
122  // g = delta_x^T delta_x + dl^2 = 0
123  //
124  // we solve this in the following way:
125  // 1. calculate dx1, dx2
126  // 2. solve for dp as the solution of the quadratic constraint eq.
127  //
128  // there is another way to solve this, by including the constraint in the
129  // N-R solution as follows. However, this will provide dp depending on
130  // the initial starting point for dp. Hence, we choose to analytically
131  // solve the quadratic equation.
132  //
133  // (dg/dx)^T (dx1 + dp dx2) + dg/dp dp = -g
134  // or, ((dg/dx)^T dx2 + dg/dp) dp = -g - (dg/dx)^T dx1
135  // or, dp = - (g + (dg/dx)^T dx1) / ((dg/dx)^T dx2 + dg/dp)
136 
137  START_LOG("solve()", "StructuralSystem");
138 
139  // the computations outlined above are repeated unless the
140  // nonlinear convergence criteria are satisfied.
141  bool
142  if_converged = false;
143 
144  _dl = 1.;
145 
146  // these vectors will be used for solution updates here
147  std::unique_ptr<libMesh::NumericVector<Real> >
148  x_old (this->solution->zero_clone().release()), // to store solution after previous iteration
149  delta_x0 (this->solution->zero_clone().release()), // displacement update for this load step
150  dx (this->solution->zero_clone().release()), // updates to delta_x
151  dx_residual (this->solution->zero_clone().release()),
152  dx_load (this->solution->zero_clone().release());
153 
154  // store the previous solution
155  *x_old = *(this->solution);
156 
157  Real
158  dp = 0.,
159  a0 = 0.,
160  a1 = 0.,
161  a2 = 0.,
162  dp1 = 0.,
163  dp2 = 0.,
164  v1 = 0.;
165 
166 
167  while (!if_converged) {
168 
169  // solve for dx due to residual. Set the maximum iterations to 1.
170 
171  // first solve the displacement update due to system residual
172  // this solution will return x. We will use this to calculate
173  // delta_x1 = x - x0
174  // dx = delta_x1 - delta_x0
175  // where delta_x0 is the delta_x at the end of the previous iterate
176  MAST::NonlinearSystem::solve(elem_ops, assembly);
177 
178  // if the total load steps have been taken to the max load, then
179  // quit
180  if (fabs((*_load_param)() - _max_p) < 1.0e-10) {
181  if_converged = true;
182  continue;
183  }
184 
185  *dx = *(this->solution);
186  dx->add(-1., *x_old);
187  dx->add(-1., *delta_x0);
188 
189  // swap the solution for later use
190  this->solution->swap(*dx_residual);
191 
192 
193  // next solve the displacement update due to load update
195  *dx_load = this->get_sensitivity_solution();
196 
197  // now, calculate the load update using the constraint definition.
198  // We use a second order constraint function, which is written as a
199  // quadratic equation
200  // a0 dp^2 + a1 dp + a2 = 0
201  a0 = dx_load->dot(*dx_load);
202  a1 = 2.*(delta_x0->dot(*dx_load) + dx_residual->dot(*dx_load));
203  v1 = -1.; // some arbitrary value to trigger the while loop
204  while (v1 < 0.) {
205 
206  a2 = (delta_x0->dot(*delta_x0) +
207  2.*delta_x0->dot(*dx_residual) +
208  dx_residual->dot(*dx_residual) - _dl*_dl);
209  v1 = a1*a1-4.*a0*a2;
210  dp1 = 0.;
211  dp2 = 0.;
212 
213  if (v1 >= 0.) {
214  dp1 = (-a1 + sqrt(v1))/(2.*a0); // this is the first root
215  dp2 = (-a1 - sqrt(v1))/(2.*a0); // this is the second root
216  }
217  else {
218  // reduce the value of dl and reevaluate the constraint
219  _dl /= 2.;
220  }
221  }
222 
223  // now we need to select one of the two roots
224  dp = dp1;
225  dp = std::min(_max_p - (*_load_param)(), dp);
226 
227  // change the load parameter
228  (*_load_param)() += dp;
229 
230  // use the load update to evaluate the total displacement update
231  *dx = *dx_residual;
232  dx->add(dp, *dx_load);
233  delta_x0->add(*dx);
234  this->solution->add(1., *dx);
235 
236  // some preliminary convergence criteria
237  if (dx->l2_norm() <= 1.e-6 ||
238  fabs(dp) <= 1.e-6)
239  if_converged = true;
240  }
241 
242 
243  // Update the system after the solve
244  this->update();
245 
246  STOP_LOG("solve()", "StructuralSystem");
247 }
248 
249 
virtual void sensitivity_solve(MAST::AssemblyElemOperations &elem_ops, MAST::AssemblyBase &assembly, const MAST::FunctionBase &p, bool if_assemble_jacobian=true)
Solves the sensitivity problem for the provided parameter.
void set_load_parameter(MAST::Parameter &param, Real min_p, Real max_p)
sets the laod parameter for incrementing
Real _dl
value of update length
This class implements a system for solution of nonlinear systems.
MAST::Parameter * _load_param
load parameter that is updated by this solution procedure
virtual void clear() libmesh_override
Clear all the data structures associated with the system.
This is a scalar function whose value can be changed and one that can be used as a design variable in...
Definition: parameter.h:35
libMesh::Real Real
virtual void clear() libmesh_override
Clear all the data structures associated with the system.
Real _beta
value of beta that scales the external load vector in the constrain
StructuralSystem(libMesh::EquationSystems &es, const std::string &name, const unsigned int number)
Default constructor.
Real _min_p
maximum and minimum values of the parameter
virtual void solve(MAST::AssemblyElemOperations &elem_ops, MAST::AssemblyBase &assembly) libmesh_override
Assembles & solves the nonlinear system R(x) = 0.
virtual void solve(MAST::AssemblyElemOperations &elem_ops, MAST::AssemblyBase &assembly)
solves the nonlinear problem with the specified assembly operation object