libMesh
Typedefs | Functions
miscellaneous_ex12.C File Reference

Go to the source code of this file.

Typedefs

typedef Eigen::Matrix< libMesh::Real, 2, 2 > MyMatrix2d
 
typedef Eigen::Matrix< libMesh::Real, 3, 3 > MyMatrix3d
 
typedef Eigen::Matrix< libMesh::Real, 2, 1 > MyVector2d
 
typedef Eigen::Matrix< libMesh::Real, 3, 1 > MyVector3d
 
typedef Eigen::Matrix< libMesh::Real, Eigen::Dynamic, Eigen::Dynamic > MyMatrixXd
 

Functions

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

Typedef Documentation

◆ MyMatrix2d

typedef Eigen::Matrix<libMesh::Real, 2, 2> MyMatrix2d

Definition at line 69 of file miscellaneous_ex12.C.

◆ MyMatrix3d

typedef Eigen::Matrix<libMesh::Real, 3, 3> MyMatrix3d

Definition at line 70 of file miscellaneous_ex12.C.

◆ MyMatrixXd

typedef Eigen::Matrix<libMesh::Real, Eigen::Dynamic, Eigen::Dynamic> MyMatrixXd

Definition at line 73 of file miscellaneous_ex12.C.

◆ MyVector2d

typedef Eigen::Matrix<libMesh::Real, 2, 1> MyVector2d

Definition at line 71 of file miscellaneous_ex12.C.

◆ MyVector3d

typedef Eigen::Matrix<libMesh::Real, 3, 1> MyVector3d

Definition at line 72 of file miscellaneous_ex12.C.

Function Documentation

◆ assemble_shell()

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

Definition at line 328 of file miscellaneous_ex12.C.

References libMesh::SparseMatrix< T >::add_matrix(), libMesh::NumericVector< T >::add_vector(), 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::EquationSystems::parameters, libMesh::Real, libMesh::DenseSubVector< T >::reposition(), libMesh::DenseVector< T >::resize(), libMesh::DenseMatrix< T >::resize(), libMesh::ExplicitSystem::rhs, libMesh::NumericVector< T >::set(), libMesh::BoundaryInfo::shellface_boundary_ids(), and libMesh::System::variable_type().

Referenced by main().

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();
469  MyMatrix3d F0;
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();
522  MyMatrix3d F0;
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 
561  MyMatrix2d b;
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 }
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:196
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:2330
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition: dof_map.C:2164
unsigned int dim
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and linear solvers ...
void resize(const unsigned int n)
Resize the vector.
Definition: dense_vector.h:396
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]...
Eigen::Matrix< libMesh::Real, Eigen::Dynamic, Eigen::Dynamic > MyMatrixXd
MeshBase & mesh
NumericVector< Number > * rhs
The system matrix.
Order default_quadrature_order() const
Definition: fe_type.h:371
void shellface_boundary_ids(const Elem *const elem, const unsigned short int shellface, std::vector< boundary_id_type > &vec_to_fill) const
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:165
const T_sys & get_system(std::string_view name) const
Eigen::Matrix< libMesh::Real, 3, 3 > MyMatrix3d
This is the MeshBase class.
Definition: mesh_base.h:75
Defines a dense subvector for use in finite element computations.
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:179
void libmesh_ignore(const Args &...)
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.
const T & get(std::string_view) const
Definition: parameters.h:426
Defines a dense submatrix for use in Finite Element-type computations.
Eigen::Matrix< libMesh::Real, 2, 2 > MyMatrix2d
virtual void close()=0
Calls the NumericVector&#39;s internal assembly routines, ensuring that the values are consistent across ...
Definition: assembly.h:127
const FEType & variable_type(const unsigned int i) const
Definition: system.h:2508
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const MeshBase & get_mesh() const
void resize(const unsigned int new_m, const unsigned int new_n)
Resizes the matrix to the specified size and calls zero().
Definition: dense_matrix.h:895
This class implements specific orders of Gauss quadrature.
unsigned int mesh_dimension() const
Definition: mesh_base.C:372
Parameters parameters
Data structure holding arbitrary parameters.
virtual void set(const numeric_index_type i, const T value)=0
Sets v(i) = value.
Eigen::Matrix< libMesh::Real, 2, 1 > MyVector2d
const DofMap & get_dof_map() const
Definition: system.h:2374
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
const SparseMatrix< Number > & get_system_matrix() const
Eigen::Matrix< libMesh::Real, 3, 1 > MyVector3d

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 86 of file miscellaneous_ex12.C.

References libMesh::DofMap::add_dirichlet_boundary(), libMesh::EquationSystems::add_system(), libMesh::System::add_variable(), assemble_shell(), libMesh::System::attach_assemble_function(), TIMPI::Communicator::broadcast(), libMesh::ParallelObject::comm(), libMesh::command_line_next(), libMesh::System::current_solution(), libMesh::DofObject::dof_number(), libMesh::DofMapBase::end_dof(), libMesh::DofMapBase::first_dof(), libMesh::System::get_dof_map(), libMesh::DofObject::id(), libMesh::TriangleWrapper::init(), libMesh::EquationSystems::init(), libMesh::LOCAL_VARIABLE_ORDER, mesh, TIMPI::Communicator::minloc(), libMesh::TensorTools::norm_sq(), libMesh::System::number(), libMesh::out, libMesh::EquationSystems::parameters, libMesh::System::point_value(), libMesh::EquationSystems::print_info(), libMesh::MeshBase::print_info(), libMesh::ParallelObject::processor_id(), libMesh::MeshBase::query_node_ptr(), libMesh::MeshBase::read(), libMesh::Real, libMesh::Parameters::set(), libMesh::LinearImplicitSystem::solve(), TIMPI::Communicator::sum(), libMesh::MeshRefinement::uniformly_refine(), libMesh::System::variable_number(), libMesh::MeshBase::write(), and libMesh::ExodusII_IO::write_equation_systems().

87 {
88  // Initialize libMesh.
89  LibMeshInit init (argc, argv);
90 
91  // Skip this 3D example if libMesh was compiled as 1D/2D-only.
92  libmesh_example_requires (3 == LIBMESH_DIM, "3D support");
93 
94  // We use Dirichlet boundary conditions here
95 #ifndef LIBMESH_ENABLE_DIRICHLET
96  libmesh_example_requires(false, "--enable-dirichlet");
97 #endif
98 
99  // Our input mesh here is in ExodusII format
100 #ifndef LIBMESH_HAVE_EXODUS_API
101  libmesh_example_requires (false, "ExodusII support");
102 #endif
103 
104 #ifndef LIBMESH_ENABLE_SECOND_DERIVATIVES
105  libmesh_example_requires (false, "second derivatives enabled");
106 #endif
107 
108  // This example does a bunch of linear algebra during assembly, and
109  // therefore requires Eigen.
110 #ifndef LIBMESH_HAVE_EIGEN
111  libmesh_example_requires(false, "--enable-eigen");
112 #endif
113 
114  // This example converts between ExodusII and XDR files, therefore
115  // it requires XDR support in libmesh.
116 #ifndef LIBMESH_HAVE_XDR
117  libmesh_example_requires (false, "XDR support");
118 #endif
119 
120  // This examples requires parallel minloc() support, which we don't
121  // implement yet for float128
122 #ifdef LIBMESH_DEFAULT_QUADRUPLE_PRECISION
123  libmesh_example_requires (false, "--disable-quadruple-precision");
124 #endif
125 
126  // Read the "distributed_load" flag from the command line
127  const int distributed_load =
128  libMesh::command_line_next("-distributed_load", 0);
129 
130  {
131  Mesh mesh (init.comm(), 3);
132 
133  // To confirm that both ExodusII and Xdr formats work for shell
134  // meshes, we read in cylinder.exo, then write out cylinder.xdr,
135  // then read in cylinder.exo again below and use that for the rest
136  // of the example.
137  mesh.read("cylinder.exo");
138  mesh.write("cylinder.xdr");
139  }
140  Mesh mesh (init.comm(), 3);
141  mesh.read("cylinder.xdr");
142 
143  // Get the number of mesh refinements from the command line
144  const int n_refinements =
145  libMesh::command_line_next("-n_refinements", 0);
146 
147  // Refine the mesh if requested
148  // Skip adaptive runs on a non-adaptive libMesh build
149 #ifndef LIBMESH_ENABLE_AMR
150  libmesh_example_requires(n_refinements==0, "--enable-amr");
151 #else
152  MeshRefinement mesh_refinement (mesh);
153  mesh_refinement.uniformly_refine (n_refinements);
154 #endif
155 
156  // Print information about the mesh to the screen.
157  mesh.print_info();
158 
159  // Create an equation systems object.
160  EquationSystems equation_systems (mesh);
161 
162  // Declare the system and its variables.
163  // Create a linear implicit system named "Shell".
164  LinearImplicitSystem & system = equation_systems.add_system<LinearImplicitSystem> ("Shell");
165 
166  // Add the three displacement variables "u", "v", "w",
167  // and the three rotational variables "theta_x", "theta_y", "theta_z".
168  // All variables are Q1 (first order on a quad mesh).
169  system.add_variable ("u");
170  system.add_variable ("v");
171  system.add_variable ("w");
172  system.add_variable ("theta_x");
173  system.add_variable ("theta_y");
174  system.add_variable ("theta_z");
175 
176  // Give the system a pointer to the matrix and rhs assembly
177  // function.
179 
180  // Use the parameters of the equation systems object to
181  // tell the shell system about the material properties, the
182  // shell thickness, and the external load.
183  const Real h = 0.03;
184  const Real E = 3e10;
185  const Real nu = 0.3;
186  const Real q = 1;
187  equation_systems.parameters.set<Real> ("thickness") = h;
188  equation_systems.parameters.set<Real> ("young's modulus") = E;
189  equation_systems.parameters.set<Real> ("poisson ratio") = nu;
190  equation_systems.parameters.set<Real> ("point load") = q;
191  equation_systems.parameters.set<bool>("distributed load") = (distributed_load != 0);
192 
193  // Dirichlet conditions for the pinched cylinder problem.
194  // Only one 8th of the cylinder is considered using symmetry considerations.
195  // The cylinder longitudinal axis is the y-axis.
196  // The four corners of the surface are named A(3,0,0), B(3,3,0), C(0,3,3), D(0,0,3).
197  // The point load (pinch) is applied at C in the -z direction.
198  // Edge AD is the actual edge of the cylinder and is rigid in the xz-plane.
199  // Other edges have symmetric boundary conditions.
200 
201 #ifdef LIBMESH_ENABLE_DIRICHLET
202  ZeroFunction<> zf;
203 
204  // AB w, theta_x, theta_y
205 
206  // Most DirichletBoundary users will want to supply a "locally
207  // indexed" functor
208  DirichletBoundary dirichlet_bc1
209  (/*boundary_ids =*/{7},/*variables =*/{2,3,4}, zf,
211  system.get_dof_map().add_dirichlet_boundary(dirichlet_bc1);
212 
213  // BC v, theta_x, theta_z
214  DirichletBoundary dirichlet_bc2
215  (/*boundary_ids =*/{8}, /*variables =*/{1,3,5}, zf,
217  system.get_dof_map().add_dirichlet_boundary(dirichlet_bc2);
218 
219  // CD u, theta_y, theta_z
220  DirichletBoundary dirichlet_bc3
221  (/*boundary_ids =*/{9}, /*variables =*/{0,4,5}, zf,
223  system.get_dof_map().add_dirichlet_boundary(dirichlet_bc3);
224 
225  // AD u, w, theta_y
226  DirichletBoundary dirichlet_bc4
227  (/*boundary_ids =*/{10}, /*variables =*/{0,2,4}, zf,
229  system.get_dof_map().add_dirichlet_boundary(dirichlet_bc4);
230 #endif // LIBMESH_ENABLE_DIRICHLET
231 
232  // Initialize the data structures for the equation system.
233  equation_systems.init();
234 
235  // Print information about the system to the screen.
236  equation_systems.print_info();
237 
238  // Solve the linear system.
239  system.solve();
240 
241  // After solving the system, write the solution to an
242  // ExodusII output file ready for import in, e.g.,
243  // Paraview.
244  ExodusII_IO(mesh).write_equation_systems ("out.e", equation_systems);
245 
246  // Compare with analytical solution for point load
247  if (distributed_load==0)
248  {
249  // Find the node nearest point C.
250  Node * node_C = nullptr;
251  Point point_C(0, 3, 3);
252  {
253  Real nearest_dist_sq = std::numeric_limits<Real>::max();
254 
255  // Find the closest local node. On a DistributedMesh we may
256  // not even know about the existence of closer non-local
257  // nodes.
258  for (auto & node : mesh.local_node_ptr_range())
259  {
260  const Real dist_sq = (*node - point_C).norm_sq();
261  if (dist_sq < nearest_dist_sq)
262  {
263  nearest_dist_sq = dist_sq;
264  node_C = node;
265  }
266  }
267 
268  // Check with other processors to see if any found a closer node
269  unsigned int minrank = 0;
270  system.comm().minloc(nearest_dist_sq, minrank);
271 
272  // Broadcast the ID of the closest node, so every processor can
273  // see for certain whether they have it or not.
274  dof_id_type nearest_node_id = 0;
275  if (system.processor_id() == minrank)
276  nearest_node_id = node_C->id();
277  system.comm().broadcast(nearest_node_id, minrank);
278  node_C = mesh.query_node_ptr(nearest_node_id);
279  }
280 
281  // Evaluate the z-displacement "w" at the node nearest C.
282  Number w = 0;
283 
284  // If we know about the closest node, and if we also own the DoFs
285  // on that node, then we can evaluate the solution at that node.
286  if (node_C)
287  {
288  const unsigned int w_var = system.variable_number ("w");
289  dof_id_type w_dof = node_C->dof_number (system.number(), w_var, 0);
290  if (w_dof >= system.get_dof_map().first_dof() &&
291  w_dof < system.get_dof_map().end_dof())
292  w = system.current_solution(w_dof);
293  }
294  system.comm().sum(w);
295 
296 
297  Number w_C_bar = -E*h*w/q;
298  const Real w_C_bar_analytic = 164.24;
299 
300  // Print the finite element solution and the analytic
301  // prediction to the screen.
302  libMesh::out << "z-displacement of the point C: " << w_C_bar << std::endl;
303  libMesh::out << "Analytic solution: " << w_C_bar_analytic << std::endl;
304 
305  // Evaluate the y-displacement "v" at point D. This time we'll
306  // evaluate at the exact point, not just the closest node.
307  Point point_D(0, 0, 3);
308  const unsigned int v_var = system.variable_number ("v");
309  Number v = system.point_value(v_var, point_D);
310 
311  Number v_D_bar = E*h*v/q;
312  const Real v_D_bar_analytic = 4.114;
313 
314  // Print the finite element solution and the analytic
315  // prediction to the screen.
316  libMesh::out << "y-displacement of the point D: " << v_D_bar << std::endl;
317  libMesh::out << "Analytic solution: " << v_D_bar_analytic << std::endl;
318  }
319 
320  // All done.
321  return 0;
322 }
T command_line_next(std::string name, T default_value)
Use GetPot&#39;s search()/next() functions to get following arguments from the command line...
Definition: libmesh.C:1078
dof_id_type end_dof(const processor_id_type proc) const
Definition: dof_map_base.h:191
This is the EquationSystems class.
virtual void read(const std::string &name, void *mesh_data=nullptr, bool skip_renumber_nodes_and_elements=false, bool skip_find_neighbors=false)=0
Interfaces for reading/writing a mesh to/from a file.
dof_id_type dof_number(const unsigned int s, const unsigned int var, const unsigned int comp) const
Definition: dof_object.h:1032
A Node is like a Point, but with more information.
Definition: node.h:52
ConstFunction that simply returns 0.
Definition: zero_function.h:38
void minloc(T &r, unsigned int &min_id) const
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
Definition: exodusII_io.h:52
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and linear solvers ...
void sum(T &r) const
MeshBase & mesh
Number point_value(unsigned int var, const Point &p, const bool insist_on_success=true, const NumericVector< Number > *sol=nullptr) const
Definition: system.C:2421
This class allows one to associate Dirichlet boundary values with a given set of mesh boundary ids an...
const Parallel::Communicator & comm() const
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition: libmesh.h:90
virtual void solve() override
Assembles & solves the linear system A*x=b.
Number current_solution(const dof_id_type global_dof_number) const
Definition: system.C:165
unsigned int variable_number(std::string_view var) const
Definition: system.C:1609
unsigned int number() const
Definition: system.h:2350
Implements (adaptive) mesh refinement algorithms for a MeshBase.
dof_id_type id() const
Definition: dof_object.h:828
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.
Definition: exodusII_io.C:2033
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:1562
virtual const Node * query_node_ptr(const dof_id_type i) const =0
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
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:1357
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:2161
void assemble_shell(EquationSystems &es, const std::string &system_name)
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
virtual void write(const std::string &name) const =0
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
auto norm_sq(const T &a) -> decltype(std::norm(a))
Definition: tensor_tools.h:104
OStreamProxy out
void add_dirichlet_boundary(const DirichletBoundary &dirichlet_boundary)
Adds a copy of the specified Dirichlet boundary to the system.
dof_id_type first_dof(const processor_id_type proc) const
Definition: dof_map_base.h:185
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50
processor_id_type processor_id() const
const DofMap & get_dof_map() const
Definition: system.h:2374
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
uint8_t dof_id_type
Definition: id_types.h:67