libMesh
Loading...
Searching...
No Matches
Functions
miscellaneous_ex11.C File Reference

Go to the source code of this file.

Functions

void assemble_shell (EquationSystems &es, const std::string &system_name)
 
int main (int argc, char **argv)
 
void assemble_shell (EquationSystems &es, const std::string &libmesh_dbg_var(system_name))
 

Function Documentation

◆ assemble_shell() [1/2]

void assemble_shell ( EquationSystems es,
const std::string &  libmesh_dbg_varsystem_name 
)

Definition at line 264 of file miscellaneous_ex11.C.

266{
267 // It is a good idea to make sure we are assembling
268 // the proper system.
269 libmesh_assert_equal_to (system_name, "Shell");
270
271 // Get a constant reference to the mesh object.
272 const MeshBase & mesh = es.get_mesh();
273
274 // Get a reference to the shell system object.
276
277 // Get the shell parameters that we need during assembly.
278 const Real h = es.parameters.get<Real> ("thickness");
279 const Real E = es.parameters.get<Real> ("young's modulus");
280 const Real nu = es.parameters.get<Real> ("poisson ratio");
281 const Real q = es.parameters.get<Real> ("uniform load");
282
283 // Compute the membrane stiffness K and the bending
284 // rigidity D from these parameters.
285 const Real K = E * h / (1-nu*nu);
286 const Real D = E * h*h*h / (12*(1-nu*nu));
287
288 // Numeric ids corresponding to each variable in the system.
289 const unsigned int u_var = system.variable_number ("u");
290 const unsigned int v_var = system.variable_number ("v");
291 const unsigned int w_var = system.variable_number ("w");
292
293 // Get the Finite Element type for "u". Note this will be
294 // the same as the type for "v" and "w".
295 FEType fe_type = system.variable_type (u_var);
296
297 // Build a Finite Element object of the specified type.
298 std::unique_ptr<FEBase> fe (FEBase::build(2, fe_type));
299
300 // A Gauss quadrature rule for numerical integration.
301 // For subdivision shell elements, a single Gauss point per
302 // element is sufficient, hence we use extraorder = 0.
303 const int extraorder = 0;
304 std::unique_ptr<QBase> qrule (fe_type.default_quadrature_rule (2, extraorder));
305
306 // Tell the finite element object to use our quadrature rule.
307 fe->attach_quadrature_rule (qrule.get());
308
309 // The element Jacobian * quadrature weight at each integration point.
310 const std::vector<Real> & JxW = fe->get_JxW();
311
312 // The surface tangents in both directions at the quadrature points.
313 const std::vector<RealGradient> & dxyzdxi = fe->get_dxyzdxi();
314 const std::vector<RealGradient> & dxyzdeta = fe->get_dxyzdeta();
315
316 // The second partial derivatives at the quadrature points.
317 const std::vector<RealGradient> & d2xyzdxi2 = fe->get_d2xyzdxi2();
318 const std::vector<RealGradient> & d2xyzdeta2 = fe->get_d2xyzdeta2();
319 const std::vector<RealGradient> & d2xyzdxideta = fe->get_d2xyzdxideta();
320
321 // The element shape function and its derivatives evaluated at the
322 // quadrature points.
323 const std::vector<std::vector<Real>> & phi = fe->get_phi();
324 const std::vector<std::vector<RealGradient>> & dphi = fe->get_dphi();
325 const std::vector<std::vector<RealTensor>> & d2phi = fe->get_d2phi();
326
327 // A reference to the DofMap object for this system. The DofMap
328 // object handles the index translation from node and element numbers
329 // to degree of freedom numbers.
330 const DofMap & dof_map = system.get_dof_map();
331
332 // The global system matrix
333 SparseMatrix<Number> & matrix = system.get_system_matrix();
334
335 // Define data structures to contain the element stiffness matrix
336 // and right-hand-side vector contribution. Following
337 // basic finite element terminology we will denote these
338 // "Ke" and "Fe".
341
343 Kuu(Ke), Kuv(Ke), Kuw(Ke),
344 Kvu(Ke), Kvv(Ke), Kvw(Ke),
345 Kwu(Ke), Kwv(Ke), Kww(Ke);
346
348 Fu(Fe),
349 Fv(Fe),
350 Fw(Fe);
351
352 // This vector will hold the degree of freedom indices for
353 // the element. These define where in the global system
354 // the element degrees of freedom get mapped.
355 std::vector<dof_id_type> dof_indices;
356 std::vector<dof_id_type> dof_indices_u;
357 std::vector<dof_id_type> dof_indices_v;
358 std::vector<dof_id_type> dof_indices_w;
359
360 // Now we will loop over all the elements in the mesh. We will
361 // compute the element matrix and right-hand-side contribution.
362 for (const auto & elem : mesh.active_local_element_ptr_range())
363 {
364 // The ghost elements at the boundaries need to be excluded
365 // here, as they don't belong to the physical shell,
366 // but serve for a proper boundary treatment only.
367 libmesh_assert_equal_to (elem->type(), TRI3SUBDIVISION);
368 const Tri3Subdivision * sd_elem = static_cast<const Tri3Subdivision *> (elem);
369 if (sd_elem->is_ghost())
370 continue;
371
372 // Get the degree of freedom indices for the
373 // current element. These define where in the global
374 // matrix and right-hand-side this element will
375 // contribute to.
376 dof_map.dof_indices (elem, dof_indices);
377 dof_map.dof_indices (elem, dof_indices_u, u_var);
378 dof_map.dof_indices (elem, dof_indices_v, v_var);
379 dof_map.dof_indices (elem, dof_indices_w, w_var);
380
381 const std::size_t n_dofs = dof_indices.size();
382 const std::size_t n_u_dofs = dof_indices_u.size();
383 const std::size_t n_v_dofs = dof_indices_v.size();
384 const std::size_t n_w_dofs = dof_indices_w.size();
385
386 // Compute the element-specific data for the current
387 // element. This involves computing the location of the
388 // quadrature points and the shape functions
389 // (phi, dphi, d2phi) for the current element.
390 fe->reinit (elem);
391
392 // Zero the element matrix and right-hand side before
393 // summing them. We use the resize member here because
394 // the number of degrees of freedom might have changed from
395 // the last element.
396 Ke.resize (n_dofs, n_dofs);
397 Fe.resize (n_dofs);
398
399 // Reposition the submatrices... The idea is this:
400 //
401 // - - - -
402 // | Kuu Kuv Kuw | | Fu |
403 // Ke = | Kvu Kvv Kvw |; Fe = | Fv |
404 // | Kwu Kwv Kww | | Fw |
405 // - - - -
406 //
407 // The DenseSubMatrix.reposition () member takes the
408 // (row_offset, column_offset, row_size, column_size).
409 //
410 // Similarly, the DenseSubVector.reposition () member
411 // takes the (row_offset, row_size)
412 Kuu.reposition (u_var*n_u_dofs, u_var*n_u_dofs, n_u_dofs, n_u_dofs);
413 Kuv.reposition (u_var*n_u_dofs, v_var*n_u_dofs, n_u_dofs, n_v_dofs);
414 Kuw.reposition (u_var*n_u_dofs, w_var*n_u_dofs, n_u_dofs, n_w_dofs);
415
416 Kvu.reposition (v_var*n_v_dofs, u_var*n_v_dofs, n_v_dofs, n_u_dofs);
417 Kvv.reposition (v_var*n_v_dofs, v_var*n_v_dofs, n_v_dofs, n_v_dofs);
418 Kvw.reposition (v_var*n_v_dofs, w_var*n_v_dofs, n_v_dofs, n_w_dofs);
419
420 Kwu.reposition (w_var*n_w_dofs, u_var*n_w_dofs, n_w_dofs, n_u_dofs);
421 Kwv.reposition (w_var*n_w_dofs, v_var*n_w_dofs, n_w_dofs, n_v_dofs);
422 Kww.reposition (w_var*n_w_dofs, w_var*n_w_dofs, n_w_dofs, n_w_dofs);
423
424 Fu.reposition (u_var*n_u_dofs, n_u_dofs);
425 Fv.reposition (v_var*n_u_dofs, n_v_dofs);
426 Fw.reposition (w_var*n_u_dofs, n_w_dofs);
427
428 // Now we will build the element matrix and right-hand-side.
429 for (unsigned int qp=0; qp<qrule->n_points(); ++qp)
430 {
431 // First, we compute the external force resulting
432 // from a load q distributed uniformly across the plate.
433 // Since the load is supposed to be transverse to the plate,
434 // it affects the z-direction, i.e. the "w" variable.
435 for (unsigned int i=0; i<n_u_dofs; ++i)
436 Fw(i) += JxW[qp] * phi[i][qp] * q;
437
438 // Next, we assemble the stiffness matrix. This is only valid
439 // for the linear theory, i.e., for small deformations, where
440 // reference and deformed surface metrics are indistinguishable.
441
442 // Get the three surface basis vectors.
443 const RealVectorValue & a1 = dxyzdxi[qp];
444 const RealVectorValue & a2 = dxyzdeta[qp];
445 RealVectorValue a3 = a1.cross(a2);
446 const Real jac = a3.norm(); // the surface Jacobian
447 libmesh_assert_greater (jac, 0);
448 a3 /= jac; // the shell director a3 is normalized to unit length
449
450 // Get the derivatives of the surface tangents.
451 const RealVectorValue & a11 = d2xyzdxi2[qp];
452 const RealVectorValue & a22 = d2xyzdeta2[qp];
453 const RealVectorValue & a12 = d2xyzdxideta[qp];
454
455 // Compute the three covariant components of the first
456 // fundamental form of the surface.
457 const RealVectorValue a(a1*a1, a2*a2, a1*a2);
458
459 // The elastic H matrix in Voigt's notation, computed from the
460 // covariant components of the first fundamental form rather
461 // than the contravariant components, exploiting that the
462 // contravariant first fundamental form is the inverse of the
463 // covariant first fundamental form (hence the determinant etc.).
465 H(0,0) = a(1) * a(1);
466 H(0,1) = H(1,0) = nu * a(1) * a(0) + (1-nu) * a(2) * a(2);
467 H(0,2) = H(2,0) = -a(1) * a(2);
468 H(1,1) = a(0) * a(0);
469 H(1,2) = H(2,1) = -a(0) * a(2);
470 H(2,2) = 0.5 * ((1-nu) * a(1) * a(0) + (1+nu) * a(2) * a(2));
471 const Real det = a(0) * a(1) - a(2) * a(2);
472 libmesh_assert_not_equal_to (det * det, 0);
473 H /= det * det;
474
475 // Precompute come cross products for the bending part below.
476 const RealVectorValue a11xa2 = a11.cross(a2);
477 const RealVectorValue a22xa2 = a22.cross(a2);
478 const RealVectorValue a12xa2 = a12.cross(a2);
479 const RealVectorValue a1xa11 = a1.cross(a11);
480 const RealVectorValue a1xa22 = a1.cross(a22);
481 const RealVectorValue a1xa12 = a1.cross(a12);
482 const RealVectorValue a2xa3 = a2.cross(a3);
483 const RealVectorValue a3xa1 = a3.cross(a1);
484
485 // Loop over all pairs of nodes I,J.
486 for (unsigned int i=0; i<n_u_dofs; ++i)
487 {
488 for (unsigned int j=0; j<n_u_dofs; ++j)
489 {
490 // The membrane strain matrices in Voigt's notation.
491 RealTensorValue MI, MJ;
492 for (unsigned int k=0; k<3; ++k)
493 {
494 MI(0,k) = dphi[i][qp](0) * a1(k);
495 MI(1,k) = dphi[i][qp](1) * a2(k);
496 MI(2,k) = dphi[i][qp](1) * a1(k)
497 + dphi[i][qp](0) * a2(k);
498
499 MJ(0,k) = dphi[j][qp](0) * a1(k);
500 MJ(1,k) = dphi[j][qp](1) * a2(k);
501 MJ(2,k) = dphi[j][qp](1) * a1(k)
502 + dphi[j][qp](0) * a2(k);
503 }
504
505 // The bending strain matrices in Voigt's notation.
506 RealTensorValue BI, BJ;
507 for (unsigned int k=0; k<3; ++k)
508 {
509 const Real term_ik = dphi[i][qp](0) * a2xa3(k)
510 + dphi[i][qp](1) * a3xa1(k);
511 BI(0,k) = -d2phi[i][qp](0,0) * a3(k)
512 +(dphi[i][qp](0) * a11xa2(k)
513 + dphi[i][qp](1) * a1xa11(k)
514 + (a3*a11) * term_ik) / jac;
515 BI(1,k) = -d2phi[i][qp](1,1) * a3(k)
516 +(dphi[i][qp](0) * a22xa2(k)
517 + dphi[i][qp](1) * a1xa22(k)
518 + (a3*a22) * term_ik) / jac;
519 BI(2,k) = 2 * (-d2phi[i][qp](0,1) * a3(k)
520 +(dphi[i][qp](0) * a12xa2(k)
521 + dphi[i][qp](1) * a1xa12(k)
522 + (a3*a12) * term_ik) / jac);
523
524 const Real term_jk = dphi[j][qp](0) * a2xa3(k)
525 + dphi[j][qp](1) * a3xa1(k);
526 BJ(0,k) = -d2phi[j][qp](0,0) * a3(k)
527 +(dphi[j][qp](0) * a11xa2(k)
528 + dphi[j][qp](1) * a1xa11(k)
529 + (a3*a11) * term_jk) / jac;
530 BJ(1,k) = -d2phi[j][qp](1,1) * a3(k)
531 +(dphi[j][qp](0) * a22xa2(k)
532 + dphi[j][qp](1) * a1xa22(k)
533 + (a3*a22) * term_jk) / jac;
534 BJ(2,k) = 2 * (-d2phi[j][qp](0,1) * a3(k)
535 +(dphi[j][qp](0) * a12xa2(k)
536 + dphi[j][qp](1) * a1xa12(k)
537 + (a3*a12) * term_jk) / jac);
538 }
539
540 // The total stiffness matrix coupling the nodes
541 // I and J is a sum of membrane and bending
542 // contributions according to the following formula.
543 const RealTensorValue KIJ = JxW[qp] * K * MI.transpose() * H * MJ
544 + JxW[qp] * D * BI.transpose() * H * BJ;
545
546 // Insert the components of the coupling stiffness
547 // matrix KIJ into the corresponding directional
548 // submatrices.
549 Kuu(i,j) += KIJ(0,0);
550 Kuv(i,j) += KIJ(0,1);
551 Kuw(i,j) += KIJ(0,2);
552
553 Kvu(i,j) += KIJ(1,0);
554 Kvv(i,j) += KIJ(1,1);
555 Kvw(i,j) += KIJ(1,2);
556
557 Kwu(i,j) += KIJ(2,0);
558 Kwv(i,j) += KIJ(2,1);
559 Kww(i,j) += KIJ(2,2);
560 }
561 }
562
563 } // end of the quadrature point qp-loop
564
565 // The element matrix and right-hand-side are now built
566 // for this element. Add them to the global matrix and
567 // right-hand-side vector. The NumericMatrix::add_matrix()
568 // and NumericVector::add_vector() members do this for us.
569 matrix.add_matrix (Ke, dof_indices);
570 system.rhs->add_vector (Fe, dof_indices);
571 } // end of non-ghost element loop
572
573 // Next, we apply the boundary conditions. In this case,
574 // all boundaries are clamped by the penalty method, using
575 // the special "ghost" nodes along the boundaries. Note
576 // that there are better ways to implement boundary conditions
577 // for subdivision shells. We use the simplest way here,
578 // which is known to be overly restrictive and will lead to
579 // a slightly too small deformation of the plate.
580 for (const auto & elem : mesh.active_local_element_ptr_range())
581 {
582 // For the boundary conditions, we only need to loop over
583 // the ghost elements.
584 libmesh_assert_equal_to (elem->type(), TRI3SUBDIVISION);
585 const Tri3Subdivision * gh_elem = static_cast<const Tri3Subdivision *> (elem);
586 if (!gh_elem->is_ghost())
587 continue;
588
589 // Find the side which is part of the physical plate boundary,
590 // that is, the boundary of the original mesh without ghosts.
591 for (auto s : elem->side_index_range())
592 {
593 const Tri3Subdivision * nb_elem = static_cast<const Tri3Subdivision *> (elem->neighbor_ptr(s));
594 if (nb_elem == nullptr || nb_elem->is_ghost())
595 continue;
596
597 /*
598 * Determine the four nodes involved in the boundary
599 * condition treatment of this side. The MeshTools::Subdiv
600 * namespace provides lookup tables next and prev
601 * for an efficient determination of the next and previous
602 * nodes of an element, respectively.
603 *
604 * n4
605 * / \
606 * / gh \
607 * n2 ---- n3
608 * \ nb /
609 * \ /
610 * n1
611 */
612 const Node * nodes [4]; // n1, n2, n3, n4
613 nodes[1] = gh_elem->node_ptr(s); // n2
614 nodes[2] = gh_elem->node_ptr(MeshTools::Subdivision::next[s]); // n3
615 nodes[3] = gh_elem->node_ptr(MeshTools::Subdivision::prev[s]); // n4
616
617 // The node in the interior of the domain, n1, is the
618 // hardest to find. Walk along the edges of element nb until
619 // we have identified it.
620 unsigned int n_int = 0;
621 nodes[0] = nb_elem->node_ptr(0);
622 while (nodes[0]->id() == nodes[1]->id() || nodes[0]->id() == nodes[2]->id())
623 nodes[0] = nb_elem->node_ptr(++n_int);
624
625 // The penalty value. \f$ \frac{1}{\epsilon} \f$
626 const Real penalty = 1.e10;
627
628 // With this simple method, clamped boundary conditions are
629 // obtained by penalizing the displacements of all four nodes.
630 // This ensures that the displacement field vanishes on the
631 // boundary side s.
632 for (unsigned int n=0; n<4; ++n)
633 {
634 const dof_id_type u_dof = nodes[n]->dof_number (system.number(), u_var, 0);
635 const dof_id_type v_dof = nodes[n]->dof_number (system.number(), v_var, 0);
636 const dof_id_type w_dof = nodes[n]->dof_number (system.number(), w_var, 0);
637 matrix.add (u_dof, u_dof, penalty);
638 matrix.add (v_dof, v_dof, penalty);
639 matrix.add (w_dof, w_dof, penalty);
640 }
641 }
642 } // end of ghost element loop
643}
Defines a dense matrix for use in Finite Element-type computations.
void resize(const unsigned int new_m, const unsigned int new_n)
Resizes the matrix to the specified size and calls zero().
Defines a dense submatrix for use in Finite Element-type computations.
Defines a dense subvector for use in finite element computations.
Defines a dense vector for use in Finite Element-type computations.
void resize(const unsigned int n)
Resize the vector.
This class handles the numbering of degrees of freedom on a mesh.
Definition dof_map.h:181
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition dof_map.C:2201
dof_id_type dof_number(const unsigned int s, const unsigned int var, const unsigned int comp) const
dof_id_type id() const
Definition dof_object.h:819
const Node * node_ptr(const unsigned int i) const
Definition elem.h:2516
const MeshBase & get_mesh() const
Parameters parameters
Data structure holding arbitrary parameters.
const T_sys & get_system(std::string_view name) const
NumericVector< Number > * rhs
The system matrix.
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition fe_type.h:197
std::unique_ptr< QBase > default_quadrature_rule(const unsigned int dim, const int extraorder=0) const
Definition fe_type.C:34
const SparseMatrix< Number > & get_system_matrix() const
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and linear solvers ...
This is the MeshBase class.
Definition mesh_base.h:81
A Node is like a Point, but with more information.
Definition node.h:55
virtual void add_vector(const T *v, const std::vector< numeric_index_type > &dof_indices)
Computes , where v is a pointer and each dof_indices[i] specifies where to add value v[i].
const T & get(std::string_view) const
Definition parameters.h:451
Generic sparse matrix.
virtual void add_matrix(const DenseMatrix< T > &dm, const std::vector< numeric_index_type > &rows, const std::vector< numeric_index_type > &cols)=0
Add the full matrix dm to the SparseMatrix.
virtual void add(const numeric_index_type i, const numeric_index_type j, const T value)=0
Add value to the element (i,j).
const FEType & variable_type(const unsigned int i) const
Definition system.C:2721
unsigned int variable_number(std::string_view var) const
Definition system.C:1398
const DofMap & get_dof_map() const
Definition system.h:2417
unsigned int number() const
Definition system.h:2393
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.
The Tri3Subdivision element is a three-noded subdivision surface shell element used in mechanics calc...
TypeTensor< T > transpose() const
TypeVector< typename CompareTypes< T, T2 >::supertype > cross(const TypeVector< T2 > &v) const
auto norm() const
MeshBase & mesh
static const unsigned int next[3]
A lookup table for the increment modulo 3 operation, for iterating through the three nodes per elemen...
static const unsigned int prev[3]
A lookup table for the decrement modulo 3 operation, for iterating through the three nodes per elemen...
uint8_t dof_id_type
Definition id_types.h:67
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

References libMesh::SparseMatrix< T >::add(), libMesh::SparseMatrix< T >::add_matrix(), libMesh::NumericVector< T >::add_vector(), libMesh::FEGenericBase< OutputType >::build(), libMesh::TypeVector< T >::cross(), libMesh::FEType::default_quadrature_rule(), libMesh::DofMap::dof_indices(), libMesh::DofObject::dof_number(), libMesh::Parameters::get(), libMesh::System::get_dof_map(), libMesh::EquationSystems::get_mesh(), libMesh::EquationSystems::get_system(), libMesh::ImplicitSystem::get_system_matrix(), libMesh::DofObject::id(), libMesh::Tri3Subdivision::is_ghost(), mesh, libMesh::MeshTools::Subdivision::next, libMesh::Elem::node_ptr(), libMesh::TypeVector< T >::norm(), libMesh::System::number(), libMesh::EquationSystems::parameters, libMesh::MeshTools::Subdivision::prev, libMesh::Real, libMesh::DenseSubMatrix< T >::reposition(), libMesh::DenseSubVector< T >::reposition(), libMesh::DenseVector< T >::resize(), libMesh::DenseMatrix< T >::resize(), libMesh::ExplicitSystem::rhs, libMesh::TypeTensor< T >::transpose(), libMesh::TRI3SUBDIVISION, libMesh::System::variable_number(), and libMesh::System::variable_type().

◆ assemble_shell() [2/2]

void assemble_shell ( EquationSystems es,
const std::string &  system_name 
)

Definition at line 328 of file miscellaneous_ex12.C.

330{
331 // This example requires Eigen to actually work, but we should still
332 // let it compile and throw a runtime error if you don't.
333
334 // The same holds for second derivatives,
335 // since they are class-members only depending on the config.
336#if defined(LIBMESH_HAVE_EIGEN) && defined(LIBMESH_ENABLE_SECOND_DERIVATIVES)
337 // It is a good idea to make sure we are assembling
338 // the proper system.
339 libmesh_assert_equal_to (system_name, "Shell");
340
341 // Get a constant reference to the mesh object.
342 const MeshBase & mesh = es.get_mesh();
343 const unsigned int dim = mesh.mesh_dimension();
344
345 // Get a reference to the shell system object.
346 LinearImplicitSystem & system = es.get_system<LinearImplicitSystem> (system_name);
347
348 // Get the shell parameters that we need during assembly.
349 const Real h = es.parameters.get<Real> ("thickness");
350 const Real E = es.parameters.get<Real> ("young's modulus");
351 const Real nu = es.parameters.get<Real> ("poisson ratio");
352 const Real q = es.parameters.get<Real> ("point load");
353 const bool distributed_load = es.parameters.get<bool> ("distributed load");
354
355 // The membrane elastic matrix.
356 MyMatrix3d Hm;
357 Hm <<
358 1., nu, 0.,
359 nu, 1., 0.,
360 0., 0., 0.5 * (1-nu);
361 Hm *= h * E/(1-nu*nu);
362
363 // The bending elastic matrix.
364 MyMatrix3d Hf;
365 Hf <<
366 1., nu, 0.,
367 nu, 1., 0.,
368 0., 0., 0.5 * (1-nu);
369 Hf *= h*h*h/12 * E/(1-nu*nu);
370
371 // The shear elastic matrices.
372 MyMatrix2d Hc0 = MyMatrix2d::Identity();
373 Hc0 *= h * 5./6*E/(2*(1+nu));
374
375 MyMatrix2d Hc1 = MyMatrix2d::Identity();
376 Hc1 *= h*h*h/12 * 5./6*E/(2*(1+nu));
377
378 // Get the Finite Element type, this will be
379 // the same for all variables.
380 FEType fe_type = system.variable_type (0);
381
382 std::unique_ptr<FEBase> fe (FEBase::build(dim, fe_type));
383 QGauss qrule (dim, fe_type.default_quadrature_order());
384 fe->attach_quadrature_rule (&qrule);
385
386 // The element Jacobian * quadrature weight at each integration point.
387 const std::vector<Real> & JxW = fe->get_JxW();
388
389 // The element shape function and its derivatives evaluated at the
390 // quadrature points.
391 const std::vector<RealGradient> & dxyzdxi = fe->get_dxyzdxi();
392 const std::vector<RealGradient> & dxyzdeta = fe->get_dxyzdeta();
393
394 const std::vector<RealGradient> & d2xyzdxi2 = fe->get_d2xyzdxi2();
395 const std::vector<RealGradient> & d2xyzdeta2 = fe->get_d2xyzdeta2();
396 const std::vector<RealGradient> & d2xyzdxideta = fe->get_d2xyzdxideta();
397 const std::vector<std::vector<Real>> & dphidxi = fe->get_dphidxi();
398 const std::vector<std::vector<Real>> & dphideta = fe->get_dphideta();
399 const std::vector<std::vector<Real>> & phi = fe->get_phi();
400
401 // A reference to the DofMap object for this system. The DofMap
402 // object handles the index translation from node and element numbers
403 // to degree of freedom numbers.
404 const DofMap & dof_map = system.get_dof_map();
405
406 // The global system matrix
407 SparseMatrix<Number> & matrix = system.get_system_matrix();
408
409 // Define data structures to contain the element stiffness matrix.
411 DenseSubMatrix<Number> Ke_var[6][6] =
412 {
425 };
426
427 // Define data structures to contain the element rhs vector.
429 DenseSubVector<Number> Fe_w(Fe);
430
431 std::vector<dof_id_type> dof_indices;
432 std::vector<std::vector<dof_id_type>> dof_indices_var(6);
433
434 // Now we will loop over all the elements in the mesh. We will
435 // compute the element matrix and right-hand-side contribution.
436 for (const auto & elem : mesh.active_local_element_ptr_range())
437 {
438 dof_map.dof_indices (elem, dof_indices);
439 for (unsigned int var=0; var<6; var++)
440 dof_map.dof_indices (elem, dof_indices_var[var], var);
441
442 const unsigned int n_dofs = dof_indices.size();
443 const unsigned int n_var_dofs = dof_indices_var[0].size();
444
445 // First compute element data at the nodes
446 std::vector<Point> nodes;
447 for (auto i : elem->node_index_range())
448 nodes.push_back(elem->reference_elem()->node_ref(i));
449 fe->reinit (elem, &nodes);
450
451 // Convenient notation for the element node positions
452 MyVector3d X1(elem->node_ref(0)(0), elem->node_ref(0)(1), elem->node_ref(0)(2));
453 MyVector3d X2(elem->node_ref(1)(0), elem->node_ref(1)(1), elem->node_ref(1)(2));
454 MyVector3d X3(elem->node_ref(2)(0), elem->node_ref(2)(1), elem->node_ref(2)(2));
455 MyVector3d X4(elem->node_ref(3)(0), elem->node_ref(3)(1), elem->node_ref(3)(2));
456
457 //Store covariant basis and local orthonormal basis at the nodes
458 std::vector<MyMatrix3d> F0node;
459 std::vector<MyMatrix3d> Qnode;
460 for (auto i : elem->node_index_range())
461 {
462 MyVector3d a1;
463 a1 << dxyzdxi[i](0), dxyzdxi[i](1), dxyzdxi[i](2);
464 MyVector3d a2;
465 a2 << dxyzdeta[i](0), dxyzdeta[i](1), dxyzdeta[i](2);
466 MyVector3d n;
467 n = a1.cross(a2);
468 n /= n.norm();
470 F0 <<
471 a1(0), a2(0), n(0),
472 a1(1), a2(1), n(1),
473 a1(2), a2(2), n(2);
474 F0node.push_back(F0);
475
476 Real nx = n(0);
477 Real ny = n(1);
478 Real C = n(2);
479 if (std::abs(1.+C)<1e-6)
480 {
481 MyMatrix3d Q;
482 Q <<
483 1, 0, 0,
484 0, -1, 0,
485 0, 0, -1;
486 Qnode.push_back(Q);
487 }
488 else
489 {
490 MyMatrix3d Q;
491 Q <<
492 C+1./(1+C)*ny*ny, -1./(1+C)*nx*ny, nx,
493 -1./(1+C)*nx*ny, C+1./(1+C)*nx*nx, ny,
494 -nx, -ny, C;
495 Qnode.push_back(Q);
496 }
497 }
498
499 Ke.resize (n_dofs, n_dofs);
500 for (unsigned int var_i=0; var_i<6; var_i++)
501 for (unsigned int var_j=0; var_j<6; var_j++)
502 Ke_var[var_i][var_j].reposition (var_i*n_var_dofs, var_j*n_var_dofs, n_var_dofs, n_var_dofs);
503
504 Fe.resize(n_dofs);
505 Fe_w.reposition(2*n_var_dofs,n_var_dofs);
506
507 // Reinit element data at the regular Gauss quadrature points
508 fe->reinit (elem);
509
510 // Now we will build the element matrix and right-hand-side.
511 for (unsigned int qp=0; qp<qrule.n_points(); ++qp)
512 {
513
514 //Covariant basis at the quadrature point
515 MyVector3d a1;
516 a1 << dxyzdxi[qp](0), dxyzdxi[qp](1), dxyzdxi[qp](2);
517 MyVector3d a2;
518 a2 << dxyzdeta[qp](0), dxyzdeta[qp](1), dxyzdeta[qp](2);
519 MyVector3d n;
520 n = a1.cross(a2);
521 n /= n.norm();
523 F0 <<
524 a1(0), a2(0), n(0),
525 a1(1), a2(1), n(1),
526 a1(2), a2(2), n(2);
527
528 //Contravariant basis
529 MyMatrix3d F0it;
530 F0it = F0.inverse().transpose();
531
532 //Local orthonormal basis at the quadrature point
533 Real nx = n(0);
534 Real ny = n(1);
535 Real C = n(2);
536 MyMatrix3d Q;
537 if (std::abs(1.+C) < 1e-6)
538 {
539 Q <<
540 1, 0, 0,
541 0, -1, 0,
542 0, 0, -1;
543 }
544 else
545 {
546 Q <<
547 C+1./(1+C)*ny*ny, -1./(1+C)*nx*ny, nx,
548 -1./(1+C)*nx*ny, C+1./(1+C)*nx*nx, ny,
549 -nx, -ny, C;
550 }
551
552 MyMatrix2d C0;
553 C0 = F0it.block<3,2>(0,0).transpose()*Q.block<3,2>(0,0);
554
555 // Normal derivatives in reference coordinates
556 MyVector3d d2Xdxi2(d2xyzdxi2[qp](0), d2xyzdxi2[qp](1), d2xyzdxi2[qp](2));
557 MyVector3d d2Xdeta2(d2xyzdeta2[qp](0), d2xyzdeta2[qp](1), d2xyzdeta2[qp](2));
558 MyVector3d d2Xdxideta(d2xyzdxideta[qp](0), d2xyzdxideta[qp](1), d2xyzdxideta[qp](2));
559
560
562 b <<
563 n.dot(d2Xdxi2), n.dot(d2Xdxideta),
564 n.dot(d2Xdxideta), n.dot(d2Xdeta2);
565
566 MyVector3d dndxi = -b(0,0)*F0it.col(0) - b(0,1)*F0it.col(1);
567 MyVector3d dndeta = -b(1,0)*F0it.col(0) - b(1,1)*F0it.col(1);
568
569 MyMatrix2d bhat;
570 bhat <<
571 F0it.col(1).dot(dndeta), -F0it.col(0).dot(dndeta),
572 -F0it.col(1).dot(dndxi), F0it.col(0).dot(dndxi);
573
574 MyMatrix2d bc;
575 bc = bhat*C0;
576
577 // Mean curvature
578 Real H = 0.5*(dndxi.dot(F0it.col(0))+dndeta.dot(F0it.col(1)));
579
580 // Quadrature point reference coordinates
581 Real xi = qrule.qp(qp)(0);
582 Real eta = qrule.qp(qp)(1);
583
584 // Preassemble the MITC4 shear strain matrix for all nodes as they involve
585 // cross references to midside nodes.
586 // The QUAD4 element has nodes X1,X2,X3,X4 with coordinates (xi,eta)
587 // in the reference element: (-1,-1),(1,-1),(1,1),(-1,1).
588 // The midside nodes are denoted A1=(X1+X2)/2, B2=(X2+X3)/2, A2=(X3+X4)/2, B1=(X4+X1)/2.
589
590 // Normals at the midside nodes (average of normals at the edge corners).
591 // Multiplication by the assumed shear strain shape function.
592 MyVector3d nA1 = 0.5*(Qnode[0].col(2)+Qnode[1].col(2));
593 nA1 /= nA1.norm();
594 nA1 *= (1-eta)/4;
595 MyVector3d nB2 = 0.5*(Qnode[1].col(2)+Qnode[2].col(2));
596 nB2 /= nB2.norm();
597 nB2 *= (1+xi)/4;
598 MyVector3d nA2 = 0.5*(Qnode[2].col(2)+Qnode[3].col(2));
599 nA2 /= nA2.norm();
600 nA2 *= (1+eta)/4;
601 MyVector3d nB1 = 0.5*(Qnode[3].col(2)+Qnode[0].col(2));
602 nB1 /= nB1.norm();
603 nB1 *= (1-xi)/4;
604
605 // Edge tangents
606 MyVector3d aA1 = 0.5*(X2-X1);
607 MyVector3d aA2 = 0.5*(X3-X4);
608 MyVector3d aB1 = 0.5*(X4-X1);
609 MyVector3d aB2 = 0.5*(X3-X2);
610
611 // Contribution of the rotational dofs to the shear strain
612 MyVector2d AS1A1(-aA1.dot(Qnode[0].col(1)), aA1.dot(Qnode[0].col(0)));
613 MyVector2d AS2A1(-aA1.dot(Qnode[1].col(1)), aA1.dot(Qnode[1].col(0)));
614 AS1A1 *= (1-eta)/4;
615 AS2A1 *= (1-eta)/4;
616
617 MyVector2d AS1A2(-aA2.dot(Qnode[3].col(1)), aA2.dot(Qnode[3].col(0)));
618 MyVector2d AS2A2(-aA2.dot(Qnode[2].col(1)), aA2.dot(Qnode[2].col(0)));
619 AS1A2 *= (1+eta)/4;
620 AS2A2 *= (1+eta)/4;
621
622 MyVector2d AS1B1(-aB1.dot(Qnode[0].col(1)), aB1.dot(Qnode[0].col(0)));
623 MyVector2d AS2B1(-aB1.dot(Qnode[3].col(1)), aB1.dot(Qnode[3].col(0)));
624 AS1B1 *= (1-xi)/4;
625 AS2B1 *= (1-xi)/4;
626
627 MyVector2d AS1B2(-aB2.dot(Qnode[1].col(1)), aB2.dot(Qnode[1].col(0)));
628 MyVector2d AS2B2(-aB2.dot(Qnode[2].col(1)), aB2.dot(Qnode[2].col(0)));
629 AS1B2 *= (1+xi)/4;
630 AS2B2 *= (1+xi)/4;
631
632 // Store previous quantities in the shear strain matrices for each node
633 std::vector<MyMatrixXd> Bcnode;
634 MyMatrixXd Bc(2, 5);
635 // Node 1
636 Bc.block<1,3>(0,0) = -nA1.transpose();
637 Bc.block<1,2>(0,3) = AS1A1.transpose();
638 Bc.block<1,3>(1,0) = -nB1.transpose();
639 Bc.block<1,2>(1,3) = AS1B1.transpose();
640 Bcnode.push_back(Bc);
641 // Node 2
642 Bc.block<1,3>(0,0) = nA1.transpose();
643 Bc.block<1,2>(0,3) = AS2A1.transpose();
644 Bc.block<1,3>(1,0) = -nB2.transpose();
645 Bc.block<1,2>(1,3) = AS1B2.transpose();
646 Bcnode.push_back(Bc);
647 // Node 3
648 Bc.block<1,3>(0,0) = nA2.transpose();
649 Bc.block<1,2>(0,3) = AS2A2.transpose();
650 Bc.block<1,3>(1,0) = nB2.transpose();
651 Bc.block<1,2>(1,3) = AS2B2.transpose();
652 Bcnode.push_back(Bc);
653 // Node 4
654 Bc.block<1,3>(0,0) = -nA2.transpose();
655 Bc.block<1,2>(0,3) = AS1A2.transpose();
656 Bc.block<1,3>(1,0) = nB1.transpose();
657 Bc.block<1,2>(1,3) = AS2B1.transpose();
658 Bcnode.push_back(Bc);
659
660 // Loop over all pairs of nodes I,J.
661 for (unsigned int i=0; i<n_var_dofs; ++i)
662 {
663 // Matrix B0, zeroth order (through thickness) membrane-bending strain
664 Real C1i = dphidxi[i][qp]*C0(0,0) + dphideta[i][qp]*C0(1,0);
665 Real C2i = dphidxi[i][qp]*C0(0,1) + dphideta[i][qp]*C0(1,1);
666
667 MyMatrixXd B0I(3, 5);
668 B0I = MyMatrixXd::Zero(3, 5);
669 B0I.block<1,3>(0,0) = C1i*Q.col(0).transpose();
670 B0I.block<1,3>(1,0) = C2i*Q.col(1).transpose();
671 B0I.block<1,3>(2,0) = C2i*Q.col(0).transpose()+C1i*Q.col(1).transpose();
672
673 // Matrix B1, first order membrane-bending strain
674 Real bc1i = dphidxi[i][qp]*bc(0,0) + dphideta[i][qp]*bc(1,0);
675 Real bc2i = dphidxi[i][qp]*bc(0,1) + dphideta[i][qp]*bc(1,1);
676
677 MyVector2d V1i(-Q.col(0).dot(Qnode[i].col(1)),
678 Q.col(0).dot(Qnode[i].col(0)));
679
680 MyVector2d V2i(-Q.col(1).dot(Qnode[i].col(1)),
681 Q.col(1).dot(Qnode[i].col(0)));
682
683 MyMatrixXd B1I(3,5);
684 B1I = MyMatrixXd::Zero(3,5);
685 B1I.block<1,3>(0,0) = bc1i*Q.col(0).transpose();
686 B1I.block<1,3>(1,0) = bc2i*Q.col(1).transpose();
687 B1I.block<1,3>(2,0) = bc2i*Q.col(0).transpose()+bc1i*Q.col(1).transpose();
688
689 B1I.block<1,2>(0,3) = C1i*V1i.transpose();
690 B1I.block<1,2>(1,3) = C2i*V2i.transpose();
691 B1I.block<1,2>(2,3) = C2i*V1i.transpose()+C1i*V2i.transpose();
692
693 // Matrix B2, second order membrane-bending strain
694 MyMatrixXd B2I(3,5);
695 B2I = MyMatrixXd::Zero(3,5);
696
697 B2I.block<1,2>(0,3) = bc1i*V1i.transpose();
698 B2I.block<1,2>(1,3) = bc2i*V2i.transpose();
699 B2I.block<1,2>(2,3) = bc2i*V1i.transpose()+bc1i*V2i.transpose();
700
701 // Matrix Bc0, zeroth order shear strain
702 MyMatrixXd Bc0I(2,5);
703 Bc0I = C0.transpose()*Bcnode[i];
704
705 // Matrix Bc1, first order shear strain
706 MyMatrixXd Bc1I(2,5);
707 Bc1I = bc.transpose()*Bcnode[i];
708
709 // Drilling dof (in-plane rotation)
710 MyVector2d BdxiI(dphidxi[i][qp],dphideta[i][qp]);
711 MyVector2d BdI = C0.transpose()*BdxiI;
712
713 for (unsigned int j=0; j<n_var_dofs; ++j)
714 {
715
716 // Matrix B0, zeroth order membrane-bending strain
717 Real C1j = dphidxi[j][qp]*C0(0,0) + dphideta[j][qp]*C0(1,0);
718 Real C2j = dphidxi[j][qp]*C0(0,1) + dphideta[j][qp]*C0(1,1);
719
720 MyMatrixXd B0J(3,5);
721 B0J = MyMatrixXd::Zero(3,5);
722 B0J.block<1,3>(0,0) = C1j*Q.col(0).transpose();
723 B0J.block<1,3>(1,0) = C2j*Q.col(1).transpose();
724 B0J.block<1,3>(2,0) = C2j*Q.col(0).transpose()+C1j*Q.col(1).transpose();
725
726 // Matrix B1, first order membrane-bending strain
727 Real bc1j = dphidxi[j][qp]*bc(0,0) + dphideta[j][qp]*bc(1,0);
728 Real bc2j = dphidxi[j][qp]*bc(0,1) + dphideta[j][qp]*bc(1,1);
729
730 MyVector2d V1j(-Q.col(0).dot(Qnode[j].col(1)),
731 Q.col(0).dot(Qnode[j].col(0)));
732
733 MyVector2d V2j(-Q.col(1).dot(Qnode[j].col(1)),
734 Q.col(1).dot(Qnode[j].col(0)));
735
736 MyMatrixXd B1J(3,5);
737 B1J = MyMatrixXd::Zero(3,5);
738 B1J.block<1,3>(0,0) = bc1j*Q.col(0).transpose();
739 B1J.block<1,3>(1,0) = bc2j*Q.col(1).transpose();
740 B1J.block<1,3>(2,0) = bc2j*Q.col(0).transpose()+bc1j*Q.col(1).transpose();
741
742 B1J.block<1,2>(0,3) = C1j*V1j.transpose();
743 B1J.block<1,2>(1,3) = C2j*V2j.transpose();
744 B1J.block<1,2>(2,3) = C2j*V1j.transpose()+C1j*V2j.transpose();
745
746 // Matrix B2, second order membrane-bending strain
747 MyMatrixXd B2J(3,5);
748 B2J = MyMatrixXd::Zero(3,5);
749
750 B2J.block<1,2>(0,3) = bc1j*V1j.transpose();
751 B2J.block<1,2>(1,3) = bc2j*V2j.transpose();
752 B2J.block<1,2>(2,3) = bc2j*V1j.transpose()+bc1j*V2j.transpose();
753
754 // Matrix Bc0, zeroth order shear strain
755 MyMatrixXd Bc0J(2, 5);
756 Bc0J = C0.transpose()*Bcnode[j];
757
758 // Matrix Bc1, first order shear strain
759 MyMatrixXd Bc1J(2, 5);
760 Bc1J = bc.transpose()*Bcnode[j];
761
762 // Drilling dof
763 MyVector2d BdxiJ(dphidxi[j][qp], dphideta[j][qp]);
764 MyVector2d BdJ = C0.transpose()*BdxiJ;
765
766 // The total stiffness matrix coupling the nodes
767 // I and J is a sum of membrane, bending and shear contributions.
768 MyMatrixXd local_KIJ(5, 5);
769 local_KIJ = JxW[qp] * (
770 B0I.transpose() * Hm * B0J
771 + B2I.transpose() * Hf * B0J
772 + B0I.transpose() * Hf * B2J
773 + B1I.transpose() * Hf * B1J
774 + 2*H * B0I.transpose() * Hf * B1J
775 + 2*H * B1I.transpose() * Hf * B0J
776 + Bc0I.transpose() * Hc0 * Bc0J
777 + Bc1I.transpose() * Hc1 * Bc1J
778 + 2*H * Bc0I.transpose() * Hc1 * Bc1J
779 + 2*H * Bc1I.transpose() * Hc1 * Bc0J
780 );
781
782 // Going from 5 to 6 dofs to add drilling dof
783 MyMatrixXd full_local_KIJ(6, 6);
784 full_local_KIJ = MyMatrixXd::Zero(6, 6);
785 full_local_KIJ.block<5,5>(0,0)=local_KIJ;
786
787 // Drilling dof stiffness contribution
788 // Note that in the original book, there is a coefficient of
789 // alpha between 1e-4 and 1e-7 to make the fictitious
790 // drilling stiffness small while preventing the stiffness
791 // matrix from being singular. For this problem, we can use
792 // alpha = 1 to also get a good result.
793 //
794 // The explicit conversion to Real here is to work
795 // around an Eigen+boost::float128 incompatibility.
796 full_local_KIJ(5,5) = Real(Hf(0,0)*JxW[qp]*BdI.transpose()*BdJ);
797
798 // Transform the stiffness matrix to global coordinates
799 MyMatrixXd global_KIJ(6,6);
800 MyMatrixXd TI(6,6);
801 TI = MyMatrixXd::Identity(6,6);
802 TI.block<3,3>(3,3) = Qnode[i].transpose();
803 MyMatrixXd TJ(6,6);
804 TJ = MyMatrixXd::Identity(6,6);
805 TJ.block<3,3>(3,3) = Qnode[j].transpose();
806 global_KIJ = TI.transpose()*full_local_KIJ*TJ;
807
808 // Insert the components of the coupling stiffness
809 // matrix KIJ into the corresponding directional
810 // submatrices.
811 for (unsigned int k=0;k<6;k++)
812 for (unsigned int l=0;l<6;l++)
813 Ke_var[k][l](i,j) += global_KIJ(k,l);
814 }
815 }
816
817 } // end of the quadrature point qp-loop
818
819 if (distributed_load)
820 {
821 // Loop on shell faces
822 for (unsigned int shellface=0; shellface<2; shellface++)
823 {
824 std::vector<boundary_id_type> bids;
825 mesh.get_boundary_info().shellface_boundary_ids(elem, shellface, bids);
826
827 for (std::size_t k=0; k<bids.size(); k++)
828 if (bids[k]==11) // sideset id for surface load
829 for (unsigned int qp=0; qp<qrule.n_points(); ++qp)
830 for (unsigned int i=0; i<n_var_dofs; ++i)
831 Fe_w(i) -= JxW[qp] * phi[i][qp];
832 }
833 }
834
835 // The element matrix is now built for this element.
836 // Add it to the global matrix.
837
838 dof_map.constrain_element_matrix_and_vector (Ke,Fe,dof_indices);
839
840 matrix.add_matrix (Ke, dof_indices);
841 system.rhs->add_vector (Fe, dof_indices);
842
843 }
844
845 if (!distributed_load)
846 {
847 //Adding point load to the RHS
848
849 //Pinch position
850 Point C(0, 3, 3);
851
852 //Finish assembling rhs so we can set one value
853 system.rhs->close();
854
855 for (const auto & node : mesh.node_ptr_range())
856 if (((*node) - C).norm() < 1e-3)
857 system.rhs->set(node->dof_number(0, 2, 0), -q/4);
858 }
859
860#else
861 // Avoid compiler warnings
862 libmesh_ignore(es, system_name);
863#endif // defined(LIBMESH_HAVE_EIGEN) && defined(LIBMESH_ENABLE_SECOND_DERIVATIVES)
864}
unsigned int dim
void shellface_boundary_ids(const Elem *const elem, const unsigned short int shellface, std::vector< boundary_id_type > &vec_to_fill) const
void constrain_element_matrix_and_vector(DenseMatrix< Number > &matrix, DenseVector< Number > &rhs, std::vector< dof_id_type > &elem_dofs, bool asymmetric_constraint_rows=true) const
Constrains the element matrix and vector.
Definition dof_map.h:2498
Order default_quadrature_order() const
Definition fe_type.h:415
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition mesh_base.h:170
unsigned int mesh_dimension() const
Definition mesh_base.C:430
virtual void close()=0
Calls the NumericVector's internal assembly routines, ensuring that the values are consistent across ...
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
This class implements specific orders of Gauss quadrature.
static const Real b
Eigen::Matrix< libMesh::Real, 3, 1 > MyVector3d
Eigen::Matrix< libMesh::Real, 3, 3 > MyMatrix3d
Eigen::Matrix< libMesh::Real, 2, 2 > MyMatrix2d
Eigen::Matrix< libMesh::Real, Eigen::Dynamic, Eigen::Dynamic > MyMatrixXd
Eigen::Matrix< libMesh::Real, 2, 1 > MyVector2d
auto norm(const T &a)
void libmesh_ignore(const Args &...)
Definition assembly.h:128

References libMesh::SparseMatrix< T >::add_matrix(), libMesh::NumericVector< T >::add_vector(), b, libMesh::FEGenericBase< OutputType >::build(), libMesh::NumericVector< T >::close(), libMesh::DofMap::constrain_element_matrix_and_vector(), libMesh::FEType::default_quadrature_order(), dim, libMesh::DofMap::dof_indices(), libMesh::Parameters::get(), libMesh::MeshBase::get_boundary_info(), libMesh::System::get_dof_map(), libMesh::EquationSystems::get_mesh(), libMesh::EquationSystems::get_system(), libMesh::ImplicitSystem::get_system_matrix(), libMesh::libmesh_ignore(), mesh, libMesh::MeshBase::mesh_dimension(), libMesh::QBase::n_points(), libMesh::TypeVector< T >::norm(), libMesh::EquationSystems::parameters, libMesh::QBase::qp(), libMesh::Real, libMesh::DenseSubVector< T >::reposition(), libMesh::DenseVector< T >::resize(), libMesh::DenseMatrix< T >::resize(), libMesh::ExplicitSystem::rhs, libMesh::SECOND, libMesh::NumericVector< T >::set(), libMesh::BoundaryInfo::shellface_boundary_ids(), and libMesh::System::variable_type().

Referenced by main().

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 80 of file miscellaneous_ex11.C.

81{
82 // Initialize libMesh.
83 LibMeshInit init (argc, argv);
84
85 // This example requires a linear solver package.
86 libmesh_example_requires(libMesh::default_solver_package() != INVALID_SOLVER_PACKAGE,
87 "--enable-petsc, --enable-trilinos, or --enable-eigen");
88
89 // Skip this 3D example if libMesh was compiled as 1D/2D-only.
90 libmesh_example_requires (3 == LIBMESH_DIM, "3D support");
91
92 // Skip this example without --enable-node-valence
93#ifndef LIBMESH_ENABLE_NODE_VALENCE
94 libmesh_example_requires (false, "--enable-node-valence");
95#endif
96
97 // Skip this example without --enable-amr; requires MeshRefinement
98#ifndef LIBMESH_ENABLE_AMR
99 libmesh_example_requires(false, "--enable-amr");
100#else
101
102 // Skip this example without --enable-second; requires d2phi
103#ifndef LIBMESH_ENABLE_SECOND_DERIVATIVES
104 libmesh_example_requires(false, "--enable-second");
105#elif LIBMESH_DIM > 2
106
107 // Create a 2D mesh distributed across the default MPI communicator.
108 // Subdivision surfaces do not appear to work with DistributedMesh yet.
109 ReplicatedMesh mesh (init.comm(), 2);
110
111 // Read the coarse square mesh.
112 mesh.read ("square_mesh.off");
113
114 // Resize the square plate to edge length L.
115 const Real L = 100.;
117
118 // Get the number of mesh refinements from the command line
119 const int n_refinements =
120 libMesh::command_line_next("-n_refinements", 3);
121
122 // Quadrisect the mesh triangles a few times to obtain a
123 // finer mesh. Subdivision surface elements require the
124 // refinement data to be removed afterward.
125 MeshRefinement mesh_refinement (mesh);
126 mesh_refinement.uniformly_refine (n_refinements);
128
129 // Write the mesh before the ghost elements are added.
130#if defined(LIBMESH_HAVE_VTK)
131 VTKIO(mesh).write ("without_ghosts.pvtu");
132#endif
133#if defined(LIBMESH_HAVE_EXODUS_API)
134 ExodusII_IO(mesh).write ("without_ghosts.e");
135#endif
136
137 // Print information about the triangulated mesh to the screen.
139
140 // Turn the triangulated mesh into a subdivision mesh
141 // and add an additional row of "ghost" elements around
142 // it in order to complete the extended local support of
143 // the triangles at the boundaries. If the second
144 // argument is set to true, the outermost existing
145 // elements are converted into ghost elements, and the
146 // actual physical mesh is thus getting smaller.
148
149 // Print information about the subdivision mesh to the screen.
151
152 // Write the mesh with the ghost elements added.
153 // Compare this to the original mesh to see the difference.
154#if defined(LIBMESH_HAVE_VTK)
155 VTKIO(mesh).write ("with_ghosts.pvtu");
156#endif
157#if defined(LIBMESH_HAVE_EXODUS_API)
158 ExodusII_IO(mesh).write ("with_ghosts.e");
159#endif
160
161 // Create an equation systems object.
162 EquationSystems equation_systems (mesh);
163
164 // Declare the system and its variables.
165 // Create a linear implicit system named "Shell".
166 LinearImplicitSystem & system = equation_systems.add_system<LinearImplicitSystem> ("Shell");
167
168 // Add the three translational deformation variables
169 // "u", "v", "w" to "Shell". Since subdivision shell
170 // elements meet the C1-continuity requirement, no
171 // rotational or other auxiliary variables are needed.
172 // Loop Subdivision Elements are always interpolated
173 // by quartic box splines, hence the order must always
174 // be FOURTH.
175 system.add_variable ("u", FOURTH, SUBDIVISION);
176 system.add_variable ("v", FOURTH, SUBDIVISION);
177 system.add_variable ("w", FOURTH, SUBDIVISION);
178
179 // Give the system a pointer to the matrix and rhs assembly
180 // function.
182
183 // Use the parameters of the equation systems object to
184 // tell the shell system about the material properties, the
185 // shell thickness, and the external load.
186 const Real h = 1.;
187 const Real E = 1.e7;
188 const Real nu = 0.;
189 const Real q = 1.;
190 equation_systems.parameters.set<Real> ("thickness") = h;
191 equation_systems.parameters.set<Real> ("young's modulus") = E;
192 equation_systems.parameters.set<Real> ("poisson ratio") = nu;
193 equation_systems.parameters.set<Real> ("uniform load") = q;
194
195 // Initialize the data structures for the equation system.
196 equation_systems.init();
197
198 // Print information about the system to the screen.
199 equation_systems.print_info();
200
201 // Solve the linear system.
202 system.solve();
203
204 // After solving the system, write the solution to a VTK
205 // or ExodusII output file ready for import in, e.g.,
206 // Paraview.
207#if defined(LIBMESH_HAVE_VTK)
208 VTKIO(mesh).write_equation_systems ("out.pvtu", equation_systems);
209#endif
210#if defined(LIBMESH_HAVE_EXODUS_API)
211 ExodusII_IO(mesh).write_equation_systems ("out.e", equation_systems);
212#endif
213
214 // Find the center node to measure the maximum deformation of the plate.
215 Node * center_node = 0;
216 Real nearest_dist_sq = mesh.point(0).norm_sq();
217 for (unsigned int nid=1; nid<mesh.n_nodes(); ++nid)
218 {
219 const Real dist_sq = mesh.point(nid).norm_sq();
220 if (dist_sq < nearest_dist_sq)
221 {
222 nearest_dist_sq = dist_sq;
223 center_node = mesh.node_ptr(nid);
224 }
225 }
226
227 // Finally, we evaluate the z-displacement "w" at the center node.
228 const unsigned int w_var = system.variable_number ("w");
229 dof_id_type w_dof = center_node->dof_number (system.number(), w_var, 0);
230 Number w = 0;
231 if (w_dof >= system.get_dof_map().first_dof() &&
232 w_dof < system.get_dof_map().end_dof())
233 w = system.current_solution(w_dof);
234 system.comm().sum(w);
235
236
237 // The analytic solution for the maximum displacement of
238 // a clamped square plate in pure bending, from Taylor,
239 // Govindjee, Commun. Numer. Meth. Eng. 20, 757-765, 2004.
240 const Real D = E * h*h*h / (12*(1-nu*nu));
241 const Real w_analytic = 0.001265319 * L*L*L*L * q / D;
242
243 // Print the finite element solution and the analytic
244 // prediction of the maximum displacement of the clamped
245 // square plate to the screen.
246 libMesh::out << "z-displacement of the center point: " << w << std::endl;
247 libMesh::out << "Analytic solution for pure bending: " << w_analytic << std::endl;
248
249#endif // LIBMESH_ENABLE_SECOND_DERIVATIVES, LIBMESH_DIM > 2
250
251#endif // #ifdef LIBMESH_ENABLE_AMR
252
253 // All done.
254 return 0;
255}
dof_id_type first_dof(const processor_id_type proc) const
dof_id_type end_dof(const processor_id_type proc) const
This is the EquationSystems class.
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
Definition exodusII_io.h:53
virtual void write(const std::string &fname) override
This method implements writing a mesh to a specified file.
virtual void write_equation_systems(const std::string &fname, const EquationSystems &es, const std::set< std::string > *system_names=nullptr) override
Writes out the solution for no specific time or timestep.
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition libmesh.h:92
virtual void solve() override
Assembles & solves the linear system A*x=b.
virtual const Point & point(const dof_id_type i) const =0
virtual const Node * node_ptr(const dof_id_type i) const =0
virtual dof_id_type n_nodes() const =0
virtual void read(const std::string &name, void *mesh_data=nullptr, bool skip_renumber_nodes_and_elements=false, bool skip_find_neighbors=false, bool skip_detect_interior_parents=false)=0
Interfaces for reading/writing a mesh to/from a file.
void print_info(std::ostream &os=libMesh::out, const unsigned int verbosity=0, const bool global=true) const
Prints relevant information about the mesh.
Definition mesh_base.C:1755
virtual void write_equation_systems(const std::string &, const EquationSystems &, const std::set< std::string > *system_names=nullptr)
This method implements writing a mesh with data to a specified file where the data is taken from the ...
Definition mesh_output.C:31
Implements (adaptive) mesh refinement algorithms for a MeshBase.
const Parallel::Communicator & comm() const
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
Number current_solution(const dof_id_type global_dof_number) const
Definition system.C:162
void attach_assemble_function(void fptr(EquationSystems &es, const std::string &name))
Register a user function to use in assembling the system matrix and RHS.
Definition system.C:1959
unsigned int add_variable(std::string_view var, const FEType &type, const std::set< subdomain_id_type > *const active_subdomains=nullptr)
Adds the variable var to the list of variables for this system.
Definition system.C:1344
auto norm_sq() const
This class implements reading and writing meshes in the VTK format.
Definition vtk_io.h:62
virtual void write(const std::string &) override
Output the mesh without solutions to a .pvtu file.
void assemble_shell(EquationSystems &es, const std::string &system_name)
void flatten(MeshBase &mesh)
Removes all the refinement tree structure of Mesh, leaving only the highest-level (most-refined) elem...
void scale(MeshBase &mesh, const Real xs, const Real ys=0., const Real zs=0.)
Scales the mesh.
void prepare_subdivision_mesh(MeshBase &mesh, bool ghosted=false)
Prepares the mesh for use with subdivision elements.
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
SolverPackage default_solver_package()
Definition libmesh.C:1064
OStreamProxy out
T command_line_next(std::string name, T default_value)
Use GetPot's search()/next() functions to get following arguments from the command line.
Definition libmesh.C:1025

References libMesh::EquationSystems::add_system(), libMesh::System::add_variable(), assemble_shell(), libMesh::System::attach_assemble_function(), libMesh::ParallelObject::comm(), libMesh::command_line_next(), libMesh::System::current_solution(), libMesh::default_solver_package(), libMesh::DofObject::dof_number(), libMesh::DofMapBase::end_dof(), libMesh::DofMapBase::first_dof(), libMesh::MeshTools::Modification::flatten(), libMesh::FOURTH, libMesh::System::get_dof_map(), libMesh::EquationSystems::init(), libMesh::INVALID_SOLVER_PACKAGE, main(), mesh, libMesh::MeshBase::n_nodes(), libMesh::MeshBase::node_ptr(), libMesh::TypeVector< T >::norm_sq(), libMesh::System::number(), libMesh::out, libMesh::EquationSystems::parameters, libMesh::MeshBase::point(), libMesh::MeshTools::Subdivision::prepare_subdivision_mesh(), libMesh::EquationSystems::print_info(), libMesh::MeshBase::print_info(), libMesh::MeshBase::read(), libMesh::Real, libMesh::MeshTools::Modification::scale(), libMesh::Parameters::set(), libMesh::LinearImplicitSystem::solve(), libMesh::SUBDIVISION, libMesh::Parallel::Communicator::sum(), libMesh::MeshRefinement::uniformly_refine(), libMesh::System::variable_number(), libMesh::VTKIO::write(), libMesh::ExodusII_IO::write(), libMesh::MeshOutput< MT >::write_equation_systems(), and libMesh::ExodusII_IO::write_equation_systems().