libMesh
elasticity_system.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 #include "elasticity_system.h"
19 
20 #include "libmesh/dof_map.h"
21 #include "libmesh/fe_base.h"
22 #include "libmesh/fem_context.h"
23 #include "libmesh/zero_function.h"
24 #include "libmesh/dirichlet_boundaries.h"
25 #include "libmesh/quadrature.h"
26 #include "libmesh/unsteady_solver.h"
27 
28 using namespace libMesh;
29 
30 
31 #if LIBMESH_DIM > 2
32 
34 {
35  _u_var = this->add_variable ("Ux", FIRST, LAGRANGE);
36  _v_var = this->add_variable ("Uy", FIRST, LAGRANGE);
37  _w_var = this->add_variable ("Uz", FIRST, LAGRANGE);
38 
39  this->time_evolving(_u_var,2);
40  this->time_evolving(_v_var,2);
41  this->time_evolving(_w_var,2);
42 
43 #ifdef LIBMESH_ENABLE_DIRICHLET
44  std::set<boundary_id_type> boundary_ids;
45  boundary_ids.insert(BOUNDARY_ID_MIN_X);
46  boundary_ids.insert(NODE_BOUNDARY_ID);
47  boundary_ids.insert(EDGE_BOUNDARY_ID);
48 
49  std::vector<unsigned int> variables;
50  variables.push_back(_u_var);
51  variables.push_back(_v_var);
52  variables.push_back(_w_var);
53 
54  ZeroFunction<> zf;
55 
56  // Most DirichletBoundary users will want to supply a "locally
57  // indexed" functor
58  DirichletBoundary dirichlet_bc(boundary_ids, variables, zf,
60 
61  this->get_dof_map().add_dirichlet_boundary(dirichlet_bc);
62 
63 #endif // LIBMESH_ENABLE_DIRICHLET
64 
65  // Do the parent's initialization after variables and boundary constraints are defined
67 }
68 
70 {
71  FEMContext & c = cast_ref<FEMContext &>(context);
72 
73  FEBase * u_elem_fe;
74  FEBase * u_side_fe;
75 
76  c.get_element_fe(_u_var, u_elem_fe);
77  c.get_side_fe(_u_var, u_side_fe);
78 
79  // We should prerequest all the data
80  // we will need to build the residuals.
81  u_elem_fe->get_JxW();
82  u_elem_fe->get_phi();
83  u_elem_fe->get_dphi();
84 
85  u_side_fe->get_JxW();
86  u_side_fe->get_phi();
87 }
88 
89 bool ElasticitySystem::element_time_derivative(bool request_jacobian,
90  DiffContext & context)
91 {
92  FEMContext & c = cast_ref<FEMContext &>(context);
93 
94  // If we have an unsteady solver, then we need to extract the corresponding
95  // velocity variable. This allows us to use either a FirstOrderUnsteadySolver
96  // or a SecondOrderUnsteadySolver. That is, we get back the velocity variable
97  // index for FirstOrderUnsteadySolvers or, if it's a SecondOrderUnsteadySolver,
98  // this is actually just giving us back the same variable index.
99 
100  // If we only wanted to use a SecondOrderUnsteadySolver, then this
101  // step would be unnecessary and we would just
102  // populate the _u_var, etc. blocks of the residual and Jacobian.
103  unsigned int u_dot_var = this->get_second_order_dot_var(_u_var);
104  unsigned int v_dot_var = this->get_second_order_dot_var(_v_var);
105  unsigned int w_dot_var = this->get_second_order_dot_var(_w_var);
106 
107  FEBase * u_elem_fe;
108  c.get_element_fe(_u_var, u_elem_fe);
109 
110  // The number of local degrees of freedom in each variable
111  const unsigned int n_u_dofs = c.n_dof_indices(_u_var);
112 
113  // Element Jacobian * quadrature weights for interior integration
114  const std::vector<Real> & JxW = u_elem_fe->get_JxW();
115 
116  const std::vector<std::vector<Real>> & phi = u_elem_fe->get_phi();
117  const std::vector<std::vector<RealGradient>> & grad_phi = u_elem_fe->get_dphi();
118 
119  DenseSubVector<Number> & Fu = c.get_elem_residual(u_dot_var);
120  DenseSubVector<Number> & Fv = c.get_elem_residual(v_dot_var);
121  DenseSubVector<Number> & Fw = c.get_elem_residual(w_dot_var);
122 
123  DenseSubMatrix<Number> & Kuu = c.get_elem_jacobian(u_dot_var, _u_var);
124  DenseSubMatrix<Number> & Kvv = c.get_elem_jacobian(v_dot_var, _v_var);
125  DenseSubMatrix<Number> & Kww = c.get_elem_jacobian(w_dot_var, _w_var);
126  DenseSubMatrix<Number> & Kuv = c.get_elem_jacobian(u_dot_var, _v_var);
127  DenseSubMatrix<Number> & Kuw = c.get_elem_jacobian(u_dot_var, _w_var);
128  DenseSubMatrix<Number> & Kvu = c.get_elem_jacobian(v_dot_var, _u_var);
129  DenseSubMatrix<Number> & Kvw = c.get_elem_jacobian(v_dot_var, _w_var);
130  DenseSubMatrix<Number> & Kwu = c.get_elem_jacobian(w_dot_var, _u_var);
131  DenseSubMatrix<Number> & Kwv = c.get_elem_jacobian(w_dot_var, _v_var);
132 
133  unsigned int n_qpoints = c.get_element_qrule().n_points();
134 
135  Gradient body_force(0.0, 0.0, -1.0);
136 
137  for (unsigned int qp=0; qp != n_qpoints; qp++)
138  {
139  Gradient grad_u, grad_v, grad_w;
140  c.interior_gradient(_u_var, qp, grad_u);
141  c.interior_gradient(_v_var, qp, grad_v);
142  c.interior_gradient(_w_var, qp, grad_w);
143 
144  // Convenience
145  Tensor grad_U (grad_u, grad_v, grad_w);
146 
147  Tensor tau;
148  for (unsigned int i = 0; i < 3; i++)
149  for (unsigned int j = 0; j < 3; j++)
150  for (unsigned int k = 0; k < 3; k++)
151  for (unsigned int l = 0; l < 3; l++)
152  tau(i,j) += elasticity_tensor(i,j,k,l)*grad_U(k,l);
153 
154  for (unsigned int i=0; i != n_u_dofs; i++)
155  {
156  for (unsigned int alpha = 0; alpha < 3; alpha++)
157  {
158  Fu(i) += (tau(0,alpha)*grad_phi[i][qp](alpha) - body_force(0)*phi[i][qp])*JxW[qp];
159  Fv(i) += (tau(1,alpha)*grad_phi[i][qp](alpha) - body_force(1)*phi[i][qp])*JxW[qp];
160  Fw(i) += (tau(2,alpha)*grad_phi[i][qp](alpha) - body_force(2)*phi[i][qp])*JxW[qp];
161 
162  if (request_jacobian)
163  {
164  for (unsigned int j=0; j != n_u_dofs; j++)
165  {
166  for (unsigned int beta = 0; beta < 3; beta++)
167  {
168  // Convenience
169  const Real c0 = grad_phi[j][qp](beta)*c.get_elem_solution_derivative();
170 
171  Real dtau_uu = elasticity_tensor(0, alpha, 0, beta)*c0;
172  Real dtau_uv = elasticity_tensor(0, alpha, 1, beta)*c0;
173  Real dtau_uw = elasticity_tensor(0, alpha, 2, beta)*c0;
174  Real dtau_vu = elasticity_tensor(1, alpha, 0, beta)*c0;
175  Real dtau_vv = elasticity_tensor(1, alpha, 1, beta)*c0;
176  Real dtau_vw = elasticity_tensor(1, alpha, 2, beta)*c0;
177  Real dtau_wu = elasticity_tensor(2, alpha, 0, beta)*c0;
178  Real dtau_wv = elasticity_tensor(2, alpha, 1, beta)*c0;
179  Real dtau_ww = elasticity_tensor(2, alpha, 2, beta)*c0;
180 
181  Kuu(i,j) += dtau_uu*grad_phi[i][qp](alpha)*JxW[qp];
182  Kuv(i,j) += dtau_uv*grad_phi[i][qp](alpha)*JxW[qp];
183  Kuw(i,j) += dtau_uw*grad_phi[i][qp](alpha)*JxW[qp];
184  Kvu(i,j) += dtau_vu*grad_phi[i][qp](alpha)*JxW[qp];
185  Kvv(i,j) += dtau_vv*grad_phi[i][qp](alpha)*JxW[qp];
186  Kvw(i,j) += dtau_vw*grad_phi[i][qp](alpha)*JxW[qp];
187  Kwu(i,j) += dtau_wu*grad_phi[i][qp](alpha)*JxW[qp];
188  Kwv(i,j) += dtau_wv*grad_phi[i][qp](alpha)*JxW[qp];
189  Kww(i,j) += dtau_ww*grad_phi[i][qp](alpha)*JxW[qp];
190  }
191  }
192  }
193  }
194  }
195 
196  } // qp loop
197 
198  // If the Jacobian was requested, we computed it. Otherwise, we didn't.
199  return request_jacobian;
200 }
201 
202 bool ElasticitySystem::side_time_derivative (bool request_jacobian,
203  DiffContext & context)
204 {
205  FEMContext & c = cast_ref<FEMContext &>(context);
206 
207  // If we're on the correct side, apply the traction
208  if (c.has_side_boundary_id(BOUNDARY_ID_MAX_X))
209  {
210  // If we have an unsteady solver, then we need to extract the corresponding
211  // velocity variable. This allows us to use either a FirstOrderUnsteadySolver
212  // or a SecondOrderUnsteadySolver. That is, we get back the velocity variable
213  // index for FirstOrderUnsteadySolvers or, if it's a SecondOrderUnsteadySolver,
214  // this is actually just giving us back the same variable index.
215 
216  // If we only wanted to use a SecondOrderUnsteadySolver, then this
217  // step would be unnecessary and we would just
218  // populate the _u_var, etc. blocks of the residual and Jacobian.
219  unsigned int u_dot_var = this->get_second_order_dot_var(_u_var);
220  unsigned int v_dot_var = this->get_second_order_dot_var(_v_var);
221  unsigned int w_dot_var = this->get_second_order_dot_var(_w_var);
222 
223  FEBase * u_side_fe;
224  c.get_side_fe(_u_var, u_side_fe);
225 
226  // The number of local degrees of freedom in each variable
227  const unsigned int n_u_dofs = c.n_dof_indices(_u_var);
228 
229  DenseSubVector<Number> & Fu = c.get_elem_residual(u_dot_var);
230  DenseSubVector<Number> & Fv = c.get_elem_residual(v_dot_var);
231  DenseSubVector<Number> & Fw = c.get_elem_residual(w_dot_var);
232 
233  // Element Jacobian * quadrature weights for interior integration
234  const std::vector<Real> & JxW = u_side_fe->get_JxW();
235 
236  const std::vector<std::vector<Real>> & phi = u_side_fe->get_phi();
237 
238  unsigned int n_qpoints = c.get_side_qrule().n_points();
239 
240  Gradient traction(0.0, 0.0, -1.0);
241 
242  for (unsigned int qp=0; qp != n_qpoints; qp++)
243  {
244  for (unsigned int i=0; i != n_u_dofs; i++)
245  {
246  Fu(i) -= traction(0)*phi[i][qp]*JxW[qp];
247  Fv(i) -= traction(1)*phi[i][qp]*JxW[qp];
248  Fw(i) -= traction(2)*phi[i][qp]*JxW[qp];
249  }
250  }
251  }
252 
253  // If the Jacobian was requested, we computed it (in this case it's zero).
254  // Otherwise, we didn't.
255  return request_jacobian;
256 }
257 
258 bool ElasticitySystem::mass_residual(bool request_jacobian,
259  DiffContext & context)
260 {
261  FEMContext & c = cast_ref<FEMContext &>(context);
262 
263  // We need to extract the corresponding velocity variable.
264  // This allows us to use either a FirstOrderUnsteadySolver
265  // or a SecondOrderUnsteadySolver. That is, we get back the velocity variable
266  // index for FirstOrderUnsteadySolvers or, if it's a SecondOrderUnsteadySolver,
267  // this is actually just giving us back the same variable index.
268 
269  // If we only wanted to use a SecondOrderUnsteadySolver, then this
270  // step would be unnecessary and we would just
271  // populate the _u_var, etc. blocks of the residual and Jacobian.
272  unsigned int u_dot_var = this->get_second_order_dot_var(_u_var);
273  unsigned int v_dot_var = this->get_second_order_dot_var(_v_var);
274  unsigned int w_dot_var = this->get_second_order_dot_var(_w_var);
275 
276  FEBase * u_elem_fe;
277  c.get_element_fe(u_dot_var, u_elem_fe);
278 
279  // The number of local degrees of freedom in each variable
280  const unsigned int n_u_dofs = c.n_dof_indices(u_dot_var);
281 
282  // Element Jacobian * quadrature weights for interior integration
283  const std::vector<Real> & JxW = u_elem_fe->get_JxW();
284 
285  const std::vector<std::vector<Real>> & phi = u_elem_fe->get_phi();
286 
287  // Residuals that we're populating
291 
292  libMesh::DenseSubMatrix<libMesh::Number> & Kuu = c.get_elem_jacobian(u_dot_var, u_dot_var);
293  libMesh::DenseSubMatrix<libMesh::Number> & Kvv = c.get_elem_jacobian(v_dot_var, v_dot_var);
294  libMesh::DenseSubMatrix<libMesh::Number> & Kww = c.get_elem_jacobian(w_dot_var, w_dot_var);
295 
296  unsigned int n_qpoints = c.get_element_qrule().n_points();
297 
298  for (unsigned int qp=0; qp != n_qpoints; qp++)
299  {
300  // If we only cared about using FirstOrderUnsteadySolvers for time-stepping,
301  // then we could actually just use interior rate, but using interior_accel
302  // allows this assembly to function for both FirstOrderUnsteadySolvers
303  // and SecondOrderUnsteadySolvers
304  libMesh::Number u_ddot, v_ddot, w_ddot;
305  c.interior_accel(u_dot_var, qp, u_ddot);
306  c.interior_accel(v_dot_var, qp, v_ddot);
307  c.interior_accel(w_dot_var, qp, w_ddot);
308 
309  for (unsigned int i=0; i != n_u_dofs; i++)
310  {
311  Fu(i) += _rho*u_ddot*phi[i][qp]*JxW[qp];
312  Fv(i) += _rho*v_ddot*phi[i][qp]*JxW[qp];
313  Fw(i) += _rho*w_ddot*phi[i][qp]*JxW[qp];
314 
315  if (request_jacobian)
316  {
317  for (unsigned int j=0; j != n_u_dofs; j++)
318  {
319  libMesh::Real jac_term = _rho*phi[i][qp]*phi[j][qp]*JxW[qp];
320  jac_term *= context.get_elem_solution_accel_derivative();
321 
322  Kuu(i,j) += jac_term;
323  Kvv(i,j) += jac_term;
324  Kww(i,j) += jac_term;
325  }
326  }
327  }
328  }
329 
330  // If the Jacobian was requested, we computed it. Otherwise, we didn't.
331  return request_jacobian;
332 }
333 #endif // LIBMESH_DIM > 2
334 
335 Real ElasticitySystem::elasticity_tensor(unsigned int i, unsigned int j, unsigned int k, unsigned int l)
336 {
337  // Hard code material parameters for the sake of simplicity
338  const Real poisson_ratio = 0.3;
339  const Real young_modulus = 1.0e2;
340 
341  // Define the Lame constants
342  const Real lambda_1 = (young_modulus*poisson_ratio)/((1.+poisson_ratio)*(1.-2.*poisson_ratio));
343  const Real lambda_2 = young_modulus/(2.*(1.+poisson_ratio));
344 
345  return
346  lambda_1 * kronecker_delta(i, j) * kronecker_delta(k, l) +
347  lambda_2 * (kronecker_delta(i, k) * kronecker_delta(j, l) + kronecker_delta(i, l) * kronecker_delta(j, k));
348 }
elasticity_tensor
Real elasticity_tensor(unsigned int i, unsigned int j, unsigned int k, unsigned int l)
Definition: assembly.C:40
libMesh::Number
Real Number
Definition: libmesh_common.h:195
libMesh::DiffContext::get_elem_residual
const DenseVector< Number > & get_elem_residual() const
Const accessor for element residual.
Definition: diff_context.h:249
libMesh::FEMContext::get_element_qrule
const QBase & get_element_qrule() const
Accessor for element interior quadrature rule for the dimension of the current _elem.
Definition: fem_context.h:790
elasticity_system.h
libMesh::FEMSystem::init_data
virtual void init_data() override
Initializes the member data fields associated with the system, so that, e.g., assemble() may be used.
Definition: fem_system.C:843
libMesh::DenseSubMatrix
Defines a dense submatrix for use in Finite Element-type computations.
Definition: dense_submatrix.h:45
libMesh::QBase::n_points
unsigned int n_points() const
Definition: quadrature.h:126
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::DiffContext::get_elem_solution_derivative
Real get_elem_solution_derivative() const
The derivative of the current elem_solution w.r.t.
Definition: diff_context.h:436
libMesh::FEGenericBase
This class forms the foundation from which generic finite elements may be derived.
Definition: exact_error_estimator.h:39
kronecker_delta
Real kronecker_delta(unsigned int i, unsigned int j)
Definition: assembly.C:34
libMesh::FEAbstract::get_JxW
const std::vector< Real > & get_JxW() const
Definition: fe_abstract.h:244
libMesh::FEGenericBase::get_dphi
const std::vector< std::vector< OutputGradient > > & get_dphi() const
Definition: fe_base.h:214
libMesh::FEMContext::interior_accel
void interior_accel(unsigned int var, unsigned int qp, OutputType &u) const
Definition: fem_context.C:1349
libMesh::VectorValue< Number >
libMesh::LOCAL_VARIABLE_ORDER
Definition: dirichlet_boundaries.h:62
libMesh::TensorValue
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.
Definition: exact_solution.h:53
libMesh::DiffContext::n_dof_indices
unsigned int n_dof_indices() const
Total number of dof indices on the element.
Definition: diff_context.h:399
ElasticitySystem::side_time_derivative
virtual bool side_time_derivative(bool request_jacobian, DiffContext &context)
Adds the time derivative contribution on side of elem to elem_residual.
Definition: elasticity_system.C:202
ElasticitySystem::init_context
virtual void init_context(DiffContext &context)
Definition: elasticity_system.C:69
libMesh::ZeroFunction
ConstFunction that simply returns 0.
Definition: zero_function.h:36
libMesh::DiffContext
This class provides all data required for a physics package (e.g.
Definition: diff_context.h:55
libMesh::DenseSubVector< Number >
libMesh::FEMContext::get_element_fe
void get_element_fe(unsigned int var, FEGenericBase< OutputShape > *&fe) const
Accessor for interior finite element object for variable var for the largest dimension in the mesh.
Definition: fem_context.h:275
libMesh::FEMContext::interior_gradient
Gradient interior_gradient(unsigned int var, unsigned int qp) const
Definition: fem_context.C:426
libMesh::DiffContext::get_elem_jacobian
const DenseMatrix< Number > & get_elem_jacobian() const
Const accessor for element Jacobian.
Definition: diff_context.h:283
ElasticitySystem::init_data
virtual void init_data()
Initializes the member data fields associated with the system, so that, e.g., assemble() may be used.
Definition: elasticity_system.C:33
libMesh::FEMContext::has_side_boundary_id
bool has_side_boundary_id(boundary_id_type id) const
Reports if the boundary id is found on the current side.
Definition: fem_context.C:254
libMesh::DirichletBoundary
This class allows one to associate Dirichlet boundary values with a given set of mesh boundary ids an...
Definition: dirichlet_boundaries.h:88
ElasticitySystem::element_time_derivative
virtual bool element_time_derivative(bool request_jacobian, DiffContext &context)
Adds the time derivative contribution on elem to elem_residual.
Definition: elasticity_system.C:89
ElasticitySystem::elasticity_tensor
Real elasticity_tensor(unsigned int i, unsigned int j, unsigned int k, unsigned int l)
Definition: elasticity_system.C:335
libMesh::FEMContext::get_side_qrule
const QBase & get_side_qrule() const
Accessor for element side quadrature rule for the dimension of the current _elem.
Definition: fem_context.h:797
libMesh::FEMContext::get_side_fe
void get_side_fe(unsigned int var, FEGenericBase< OutputShape > *&fe) const
Accessor for edge/face (2D/3D) finite element object for variable var for the largest dimension in th...
Definition: fem_context.h:312
libMesh::LAGRANGE
Definition: enum_fe_family.h:36
libMesh::FEGenericBase::get_phi
const std::vector< std::vector< OutputShape > > & get_phi() const
Definition: fe_base.h:206
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121
ElasticitySystem::mass_residual
virtual bool mass_residual(bool request_jacobian, DiffContext &context)
Subtracts a mass vector contribution on elem from elem_residual.
Definition: elasticity_system.C:258
libMesh::DiffContext::get_elem_solution_accel_derivative
Real get_elem_solution_accel_derivative() const
The derivative of the current elem_solution_accel w.r.t.
Definition: diff_context.h:454
libMesh::FIRST
Definition: enum_order.h:42
libMesh::FEMContext
This class provides all data required for a physics package (e.g.
Definition: fem_context.h:62