libMesh
assembly.C
Go to the documentation of this file.
1 // local includes
2 #include "assembly.h"
3 #include "rb_classes.h"
4 
5 // libMesh includes
6 #include "libmesh/sparse_matrix.h"
7 #include "libmesh/numeric_vector.h"
8 #include "libmesh/dense_matrix.h"
9 #include "libmesh/dense_submatrix.h"
10 #include "libmesh/dense_vector.h"
11 #include "libmesh/dense_subvector.h"
12 #include "libmesh/fe.h"
13 #include "libmesh/fe_interface.h"
14 #include "libmesh/fe_base.h"
15 #include "libmesh/elem_assembly.h"
16 #include "libmesh/quadrature_gauss.h"
17 #include "libmesh/boundary_info.h"
18 #include "libmesh/node.h"
19 
20 // C++ includes
21 #include <functional>
22 
23 #ifdef LIBMESH_ENABLE_DIRICHLET
24 
25 // Bring in bits from the libMesh namespace.
26 // Just the bits we're using, since this is a header.
30 using libMesh::Number;
31 using libMesh::Point;
32 using libMesh::RBTheta;
33 using libMesh::Real;
35 
36 // Kronecker delta function
37 inline Real kronecker_delta(unsigned int i,
38  unsigned int j)
39 {
40  return i == j ? 1. : 0.;
41 }
42 
43 Real elasticity_tensor(unsigned int i,
44  unsigned int j,
45  unsigned int k,
46  unsigned int l)
47 {
48  // Define the Poisson ratio and Young's modulus
49  const Real nu = 0.3;
50  const Real E = 1.;
51 
52  // Define the Lame constants (lambda_1 and lambda_2) based on nu and E
53  const Real lambda_1 = E * nu / ((1. + nu) * (1. - 2.*nu));
54  const Real lambda_2 = 0.5 * E / (1. + nu);
55 
56  return lambda_1 * kronecker_delta(i, j) * kronecker_delta(k, l)
57  + lambda_2 * (kronecker_delta(i, k) * kronecker_delta(j, l) + kronecker_delta(i, l) * kronecker_delta(j, k));
58 }
59 
61 {
62  const unsigned int n_components = rb_sys.n_vars();
63 
64  libmesh_assert_less_equal(n_components, 3);
65 
66  const unsigned int u_var = rb_sys.u_var;
67  const unsigned int v_var = rb_sys.v_var;
68  const unsigned int w_var = rb_sys.w_var;
69 
70  FEBase * elem_fe = nullptr;
71  c.get_element_fe(u_var, elem_fe);
72 
73  const std::vector<Real> & JxW = elem_fe->get_JxW();
74 
75  // The velocity shape function gradients at interior
76  // quadrature points.
77  const std::vector<std::vector<RealGradient>> & dphi = elem_fe->get_dphi();
78 
79  // Now we will build the affine operator
80  unsigned int n_qpoints = c.get_element_qrule().n_points();
81 
82  std::vector<unsigned int> n_var_dofs(n_components);
83  n_var_dofs[u_var] = c.get_dof_indices(u_var).size();
84  if (n_components > 1)
85  n_var_dofs[v_var] = c.get_dof_indices(v_var).size();
86  if (n_components > 2)
87  n_var_dofs[w_var] = c.get_dof_indices(w_var).size();
88 
89  for (unsigned int C_i = 0; C_i < n_components; C_i++)
90  {
91  unsigned int C_j = 0;
92  for (unsigned int C_k = 0; C_k < n_components; C_k++)
93  for (unsigned int C_l = 1; C_l < n_components; C_l++)
94  {
95  Real C_ijkl = elasticity_tensor(C_i, C_j, C_k, C_l);
96  for (unsigned int qp=0; qp<n_qpoints; qp++)
97  for (unsigned int i=0; i<n_var_dofs[C_i]; i++)
98  for (unsigned int j=0; j<n_var_dofs[C_k]; j++)
99  (c.get_elem_jacobian(C_i,C_k))(i,j) +=
100  JxW[qp]*(C_ijkl * dphi[i][qp](C_j)*dphi[j][qp](C_l));
101  }
102  }
103 
104  for (unsigned int C_i = 0; C_i < n_components; C_i++)
105  for (unsigned int C_j = 1; C_j < n_components; C_j++)
106  for (unsigned int C_k = 0; C_k < n_components; C_k++)
107  {
108  unsigned int C_l = 0;
109 
110  Real C_ijkl = elasticity_tensor(C_i, C_j, C_k, C_l);
111  for (unsigned int qp=0; qp<n_qpoints; qp++)
112  for (unsigned int i=0; i<n_var_dofs[C_i]; i++)
113  for (unsigned int j=0; j<n_var_dofs[C_k]; j++)
114  (c.get_elem_jacobian(C_i,C_k))(i,j) +=
115  JxW[qp]*(C_ijkl * dphi[i][qp](C_j)*dphi[j][qp](C_l));
116  }
117 
118 }
119 
121 {
122  const unsigned int n_components = rb_sys.n_vars();
123 
124  libmesh_assert_less_equal(n_components, 3);
125 
126  const unsigned int u_var = rb_sys.u_var;
127  const unsigned int v_var = rb_sys.v_var;
128  const unsigned int w_var = rb_sys.w_var;
129 
130  FEBase * elem_fe = nullptr;
131  c.get_element_fe(u_var, elem_fe);
132 
133  const std::vector<Real> & JxW = elem_fe->get_JxW();
134 
135  // The velocity shape function gradients at interior
136  // quadrature points.
137  const std::vector<std::vector<RealGradient>> & dphi = elem_fe->get_dphi();
138 
139  // Now we will build the affine operator
140  unsigned int n_qpoints = c.get_element_qrule().n_points();
141 
142  std::vector<unsigned int> n_var_dofs(n_components);
143  n_var_dofs[u_var] = c.get_dof_indices(u_var).size();
144  if (n_components > 1)
145  n_var_dofs[v_var] = c.get_dof_indices(v_var).size();
146  if (n_components > 2)
147  n_var_dofs[w_var] = c.get_dof_indices(w_var).size();
148 
149  for (unsigned int C_i = 0; C_i < n_components; C_i++)
150  for (unsigned int C_j = 1; C_j < n_components; C_j++)
151  for (unsigned int C_k = 0; C_k < n_components; C_k++)
152  for (unsigned int C_l = 1; C_l < n_components; C_l++)
153  {
154  Real C_ijkl = elasticity_tensor(C_i,C_j,C_k,C_l);
155  for (unsigned int qp=0; qp<n_qpoints; qp++)
156  for (unsigned int i=0; i<n_var_dofs[C_i]; i++)
157  for (unsigned int j=0; j<n_var_dofs[C_k]; j++)
158  (c.get_elem_jacobian(C_i,C_k))(i,j) +=
159  JxW[qp]*(C_ijkl * dphi[i][qp](C_j)*dphi[j][qp](C_l));
160  }
161 }
162 
164 {
165  const unsigned int n_components = rb_sys.n_vars();
166 
167  libmesh_assert_less_equal(n_components, 3);
168 
169  const unsigned int u_var = rb_sys.u_var;
170  const unsigned int v_var = rb_sys.v_var;
171  const unsigned int w_var = rb_sys.w_var;
172 
173  FEBase * elem_fe = nullptr;
174  c.get_element_fe(u_var, elem_fe);
175 
176  const std::vector<Real> & JxW = elem_fe->get_JxW();
177 
178  // The velocity shape function gradients at interior
179  // quadrature points.
180  const std::vector<std::vector<RealGradient>> & dphi = elem_fe->get_dphi();
181 
182  // Now we will build the affine operator
183  unsigned int n_qpoints = c.get_element_qrule().n_points();
184 
185  std::vector<unsigned int> n_var_dofs(n_components);
186  n_var_dofs[u_var] = c.get_dof_indices(u_var).size();
187  if (n_components > 1)
188  n_var_dofs[v_var] = c.get_dof_indices(v_var).size();
189  if (n_components > 2)
190  n_var_dofs[w_var] = c.get_dof_indices(w_var).size();
191 
192  for (unsigned int C_i = 0; C_i < n_components; C_i++)
193  {
194  unsigned int C_j = 0;
195 
196  for (unsigned int C_k = 0; C_k < n_components; C_k++)
197  {
198  unsigned int C_l = 0;
199 
200  Real C_ijkl = elasticity_tensor(C_i,C_j,C_k,C_l);
201  for (unsigned int qp=0; qp<n_qpoints; qp++)
202  for (unsigned int i=0; i<n_var_dofs[C_i]; i++)
203  for (unsigned int j=0; j<n_var_dofs[C_k]; j++)
204  (c.get_elem_jacobian(C_i,C_k))(i,j) +=
205  JxW[qp]*(C_ijkl * dphi[i][qp](C_j)*dphi[j][qp](C_l));
206  }
207  }
208 }
209 
211 {
213  (&c.get_elem(), c.side, BOUNDARY_ID_MAX_X))
214  {
215  const unsigned int u_var = 0;
216 
217  FEBase * side_fe = nullptr;
218  c.get_side_fe(u_var, side_fe);
219 
220  const std::vector<Real> & JxW_side = side_fe->get_JxW();
221 
222  const std::vector<std::vector<Real>> & phi_side = side_fe->get_phi();
223 
224  // The number of local degrees of freedom in each variable
225  const unsigned int n_u_dofs = c.get_dof_indices(u_var).size();
226 
227  // Now we will build the affine operator
228  unsigned int n_qpoints = c.get_side_qrule().n_points();
229  DenseSubVector<Number> & Fu = c.get_elem_residual(u_var);
230 
231  for (unsigned int qp=0; qp < n_qpoints; qp++)
232  for (unsigned int i=0; i < n_u_dofs; i++)
233  Fu(i) += JxW_side[qp] * (1. * phi_side[i][qp]);
234  }
235 }
236 
238 {
240  (&c.get_elem(), c.side, BOUNDARY_ID_MAX_X))
241  {
242  const unsigned int u_var = 0;
243  const unsigned int v_var = 1;
244 
245  FEBase * side_fe = nullptr;
246  c.get_side_fe(u_var, side_fe);
247 
248  const std::vector<Real> & JxW_side = side_fe->get_JxW();
249 
250  const std::vector<std::vector<Real>> & phi_side = side_fe->get_phi();
251 
252  // The number of local degrees of freedom in each variable
253  const unsigned int n_v_dofs = c.get_dof_indices(u_var).size();
254 
255  // Now we will build the affine operator
256  unsigned int n_qpoints = c.get_side_qrule().n_points();
257  DenseSubVector<Number> & Fv = c.get_elem_residual(v_var);
258 
259  for (unsigned int qp=0; qp < n_qpoints; qp++)
260  for (unsigned int i=0; i < n_v_dofs; i++)
261  Fv(i) += JxW_side[qp] * (1. * phi_side[i][qp]);
262  }
263 }
264 
266 {
268  (&c.get_elem(), c.side, BOUNDARY_ID_MAX_X))
269  {
270  const unsigned int u_var = 0;
271  const unsigned int w_var = 2;
272 
273  FEBase * side_fe = nullptr;
274  c.get_side_fe(u_var, side_fe);
275 
276  const std::vector<Real> & JxW_side = side_fe->get_JxW();
277 
278  const std::vector<std::vector<Real>> & phi_side = side_fe->get_phi();
279 
280  // The number of local degrees of freedom in each variable
281  const unsigned int n_w_dofs = c.get_dof_indices(w_var).size();
282 
283  // Now we will build the affine operator
284  unsigned int n_qpoints = c.get_side_qrule().n_points();
285  DenseSubVector<Number> & Fw = c.get_elem_residual(w_var);
286 
287  for (unsigned int qp=0; qp < n_qpoints; qp++)
288  for (unsigned int i=0; i < n_w_dofs; i++)
289  Fw(i) += JxW_side[qp] * (1. * phi_side[i][qp]);
290  }
291 }
292 
293 void AssemblyPointLoadX::get_nodal_rhs_values(std::map<numeric_index_type, Number> & values,
294  const System & sys,
295  const Node & node)
296 {
297  // First clear the values map
298  values.clear();
299 
300  if (sys.get_mesh().get_boundary_info().has_boundary_id
301  (&node, NODE_BOUNDARY_ID))
302  {
303  numeric_index_type dof_index =
304  node.dof_number(sys.number(), sys.variable_number("u"), 0);
305  values[dof_index] = 1.;
306  }
307 }
308 
309 void AssemblyPointLoadY::get_nodal_rhs_values(std::map<numeric_index_type, Number> & values,
310  const System & sys,
311  const Node & node)
312 {
313  // First clear the values map
314  values.clear();
315 
316  if (sys.get_mesh().get_boundary_info().has_boundary_id
317  (&node, NODE_BOUNDARY_ID))
318  {
319  numeric_index_type dof_index =
320  node.dof_number(sys.number(), sys.variable_number("v"), 0);
321  values[dof_index] = 1.;
322  }
323 }
324 
325 void AssemblyPointLoadZ::get_nodal_rhs_values(std::map<numeric_index_type, Number> & values,
326  const System & sys,
327  const Node & node)
328 {
329  // First clear the values map
330  values.clear();
331 
332  if (sys.get_mesh().get_boundary_info().has_boundary_id
333  (&node, NODE_BOUNDARY_ID))
334  {
335  numeric_index_type dof_index =
336  node.dof_number(sys.number(), sys.variable_number("w"), 0);
337  values[dof_index] = 1.;
338  }
339 }
340 
342 {
343  const unsigned int n_components = rb_sys.n_vars();
344 
345  libmesh_assert_less_equal(n_components, 3);
346 
347  const unsigned int u_var = rb_sys.u_var;
348  const unsigned int v_var = rb_sys.v_var;
349  const unsigned int w_var = rb_sys.w_var;
350 
351  FEBase * elem_fe = nullptr;
352  c.get_element_fe(u_var, elem_fe);
353 
354  const std::vector<Real> & JxW = elem_fe->get_JxW();
355 
356  // The velocity shape function gradients at interior
357  // quadrature points.
358  const std::vector<std::vector<RealGradient>>& dphi = elem_fe->get_dphi();
359 
360  // (u_var, v_var, w_var) all have the same number of dofs
361  const unsigned int n_dofs = c.get_dof_indices(u_var).size();
362 
363  // Now we will build the affine operator
364  unsigned int n_qpoints = c.get_element_qrule().n_points();
365 
366  // Get references to stiffness matrix diagonal blocks
367  std::reference_wrapper<DenseSubMatrix<Number>> Kdiag[3] =
368  {
369  c.get_elem_jacobian(u_var, u_var),
370  c.get_elem_jacobian(v_var, v_var),
371  c.get_elem_jacobian(w_var, w_var)
372  };
373 
374  for (unsigned int qp=0; qp<n_qpoints; qp++)
375  for (unsigned int d=0; d<n_components; ++d)
376  for (unsigned int i=0; i<n_dofs; i++)
377  for (unsigned int j=0; j<n_dofs; j++)
378  Kdiag[d](i,j) += JxW[qp]*(dphi[i][qp]*dphi[j][qp]);
379 }
380 
381 #endif // LIBMESH_ENABLE_DIRICHLET
RealVectorValue RealGradient
const DenseMatrix< Number > & get_elem_jacobian() const
Const accessor for element Jacobian.
Definition: diff_context.h:274
virtual void get_nodal_rhs_values(std::map< numeric_index_type, Number > &values, const System &sys, const Node &node)
Definition: assembly.C:325
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:317
bool has_boundary_id(const Node *const node, const boundary_id_type id) const
Real elasticity_tensor(unsigned int i, unsigned int j, unsigned int k, unsigned int l)
Definition: assembly.C:43
Real kronecker_delta(unsigned int i, unsigned int j)
Definition: assembly.C:37
const Elem & get_elem() const
Accessor for current Elem object.
Definition: fem_context.h:908
virtual void get_nodal_rhs_values(std::map< numeric_index_type, Number > &values, const System &sys, const Node &node)
Definition: assembly.C:309
virtual void boundary_assembly(FEMContext &c)
Perform the element boundary assembly.
Definition: assembly.C:237
unsigned int u_var
Variable numbers and approximation order.
Definition: rb_classes.h:136
ElasticityRBConstruction & rb_sys
The ElasticityRBConstruction object that will use this assembly.
Definition: assembly.h:56
virtual void boundary_assembly(FEMContext &c)
Perform the element boundary assembly.
Definition: assembly.C:265
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:165
const MeshBase & get_mesh() const
Definition: system.h:2358
virtual void boundary_assembly(FEMContext &c)
Perform the element boundary assembly.
Definition: assembly.C:210
virtual void interior_assembly(FEMContext &c)
Perform the element interior assembly.
Definition: assembly.C:60
dof_id_type numeric_index_type
Definition: id_types.h:99
virtual void interior_assembly(FEMContext &c)
Perform the element interior assembly.
Definition: assembly.C:163
This class provides all data required for a physics package (e.g.
Definition: fem_context.h:62
const std::vector< dof_id_type > & get_dof_indices() const
Accessor for element dof indices.
Definition: diff_context.h:363
unsigned int n_points() const
Definition: quadrature.h:131
FEGenericBase< Real > FEBase
virtual void get_nodal_rhs_values(std::map< numeric_index_type, Number > &values, const System &sys, const Node &node)
Definition: assembly.C:293
This class provides an encapsulated access to all static public member functions of finite element cl...
Definition: fe_interface.h:65
virtual void interior_assembly(FEMContext &c)
Perform the element interior assembly.
Definition: assembly.C:341
const DenseVector< Number > & get_elem_residual() const
Const accessor for element residual.
Definition: diff_context.h:242
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
unsigned char side
Current side for side_* to examine.
Definition: fem_context.h:1013
ElemAssembly provides a per-element (interior and boundary) assembly functionality.
Definition: elem_assembly.h:38
virtual void interior_assembly(FEMContext &c)
Perform the element interior assembly.
Definition: assembly.C:120
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:277
This class is part of the rbOOmit framework.
Definition: rb_theta.h:46
unsigned int n_vars() const
Definition: system.h:2430
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
const QBase & get_element_qrule() const
Accessor for element interior quadrature rule for the dimension of the current _elem.
Definition: fem_context.h:802
const QBase & get_side_qrule() const
Accessor for element side quadrature rule for the dimension of the current _elem. ...
Definition: fem_context.h:809