32 #include "libmesh/string_to_enum.h" 35 #include "libmesh/enum_solver_package.h" 38 #include "libmesh/mesh.h" 39 #include "libmesh/mesh_generation.h" 40 #include "libmesh/mesh_modification.h" 43 #include "libmesh/dense_matrix.h" 44 #include "libmesh/sparse_matrix.h" 45 #include "libmesh/dense_vector.h" 46 #include "libmesh/numeric_vector.h" 49 #include "libmesh/fe.h" 50 #include "libmesh/fe_interface.h" 51 #include "libmesh/elem.h" 54 #include "libmesh/quadrature_gauss.h" 57 #include "libmesh/dof_map.h" 60 #include "libmesh/equation_systems.h" 61 #include "libmesh/linear_implicit_system.h" 64 #include "libmesh/exact_solution.h" 65 #include "libmesh/enum_norm_type.h" 66 #include "solution_function.h" 69 #include "libmesh/getpot.h" 70 #include "libmesh/exodusII_io.h" 72 #ifdef LIBMESH_HAVE_EIGEN_DENSE 74 #include <Eigen/Dense> 77 using namespace Eigen;
79 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 93 main(
int argc,
char ** argv)
100 "--enable-petsc, --enable-trilinos, or --enable-eigen");
103 GetPot infile(
"vector_fe_ex8.in");
106 infile.parse_command_line(argc, argv);
109 const unsigned int dimension = infile(
"dim", 2);
110 const unsigned int grid_size = infile(
"grid_size", 15);
111 const unsigned int order = infile(
"order", 1);
112 const std::string family_str = infile(
"family",
"L2_LAGRANGE");
113 const FEFamily family = Utility::string_to_enum<FEFamily>(family_str);
114 const std::string vec_family_str = infile(
"vecfamily",
"L2_LAGRANGE_VEC");
115 const FEFamily vec_family = Utility::string_to_enum<FEFamily>(vec_family_str);
118 libmesh_example_requires(dimension <= LIBMESH_DIM, dimension <<
"D support");
127 const std::string elem_str = infile(
"element_type", std::string(
"TRI6"));
129 libmesh_error_msg_if((dimension == 2 && elem_str !=
"TRI6" && elem_str !=
"TRI7" &&
130 elem_str !=
"QUAD8" && elem_str !=
"QUAD9") ||
131 (dimension == 3 && elem_str !=
"TET14" && elem_str !=
"HEX27"),
134 <<
" but this example must be run with TRI6, TRI7, QUAD8, or QUAD9 in 2d" 135 <<
" or with TET14, or HEX27 in 3d.");
139 mesh, grid_size, grid_size, -1., 1., -1., 1., Utility::string_to_enum<ElemType>(elem_str));
140 else if (dimension == 3)
151 Utility::string_to_enum<ElemType>(elem_str));
167 system.
add_variable(
"q", static_cast<Order>(order), vec_family);
168 system.add_variable(
"u", static_cast<Order>(order), family);
173 system.add_variable(
"u_enriched", static_cast<Order>(order+1), family);
183 equation_systems.
init();
203 std::vector<FunctionBase<Number> *> sols(1, &soln_func);
204 std::vector<FunctionBase<Gradient> *> grads(1, &soln_grad);
209 else if (dimension == 3)
215 std::vector<FunctionBase<Number> *> sols(1, &soln_func);
216 std::vector<FunctionBase<Gradient> *> grads(1, &soln_grad);
223 int extra_error_quadrature = infile(
"extra_error_quadrature", 2);
224 if (extra_error_quadrature)
238 #ifdef LIBMESH_HAVE_EXODUS_API 243 #endif // #ifdef LIBMESH_HAVE_EXODUS_API 269 template <
typename SolnType,
typename PhiType,
typename LocalSolutionVector>
272 const unsigned int n_qps,
273 const std::vector<std::vector<PhiType>> & phi,
274 const LocalSolutionVector & soln)
277 qp_vec.resize(n_qps);
278 for (
auto & val : qp_vec)
282 const auto & qp_phis = phi[i];
284 const auto sol = soln(i);
286 qp_vec[qp] += qp_phis[qp] * sol;
294 const Elem *
const elem,
309 const FEType enriched_scalar_fe_type =
311 std::unique_ptr<FEBase> enriched_scalar_fe(
FEBase::build(
dim, enriched_scalar_fe_type));
312 std::unique_ptr<FEBase> enriched_scalar_fe_face(
FEBase::build(
dim, enriched_scalar_fe_type));
315 enriched_scalar_fe->attach_quadrature_rule(&qrule);
316 enriched_scalar_fe_face->attach_quadrature_rule(&qface);
319 const auto & JxW = vector_fe.
get_JxW();
320 const auto & q_point = vector_fe.
get_xyz();
321 const auto & scalar_phi = scalar_fe.
get_phi();
322 const auto & enriched_scalar_phi = enriched_scalar_fe->get_phi();
323 const auto & enriched_scalar_dphi = enriched_scalar_fe->get_dphi();
326 const auto & vector_phi_face = vector_fe_face.
get_phi();
327 const auto & scalar_phi_face = scalar_fe_face.
get_phi();
328 const auto & enriched_scalar_phi_face = enriched_scalar_fe_face->get_phi();
329 const auto & lambda_phi_face = lambda_fe_face.
get_phi();
330 const auto & JxW_face = scalar_fe_face.
get_JxW();
331 const auto & normals = vector_fe_face.
get_normals();
336 std::vector<dof_id_type> enriched_scalar_dof_indices;
339 std::vector<Number> lambda_qps;
341 std::vector<Number> scalar_qps;
343 std::vector<Gradient> vector_qps;
346 const auto enriched_scalar_n_dofs = enriched_scalar_dof_indices.size();
348 const auto m = enriched_scalar_n_dofs + 1;
349 const auto n = enriched_scalar_n_dofs + 1;
351 K_enriched_scalar.
resize(m, n);
352 F_enriched_scalar.
resize(m);
353 U_enriched_scalar.
resize(n);
355 enriched_scalar_fe->reinit(elem);
367 for (
const auto i :
make_range(enriched_scalar_n_dofs))
368 for (
const auto j :
make_range(enriched_scalar_n_dofs))
369 K_enriched_scalar(i, j) +=
370 JxW[qp] * (enriched_scalar_dphi[i][qp] * enriched_scalar_dphi[j][qp]);
374 const Real x = q_point[qp](0);
375 const Real y = q_point[qp](1);
376 const Real z = q_point[qp](2);
388 for (
const auto i :
make_range(enriched_scalar_n_dofs))
389 F_enriched_scalar(i) += JxW[qp] * enriched_scalar_phi[i][qp] * f;
395 for (
const auto i :
make_range(enriched_scalar_n_dofs))
396 K_enriched_scalar(i, enriched_scalar_n_dofs) += JxW[qp] * enriched_scalar_phi[i][qp];
399 for (
const auto j :
make_range(enriched_scalar_n_dofs))
400 K_enriched_scalar(enriched_scalar_n_dofs, j) += JxW[qp] * enriched_scalar_phi[j][qp];
403 F_enriched_scalar(enriched_scalar_n_dofs) += JxW[qp] * scalar_qps[qp];
407 bool tau_found =
false;
411 vector_fe_face.
reinit(elem, side);
414 enriched_scalar_fe_face->reinit(elem, side);
423 for (
const auto i :
make_range(enriched_scalar_n_dofs))
424 F_enriched_scalar(i) -=
425 JxW_face[qp] * enriched_scalar_phi_face[i][qp] * vector_qps[qp] * normals[qp];
428 scalar_fe_face.
reinit(elem, side);
430 lambda_fe_face.
reinit(elem, side);
435 const Real tau = tau_found ? 0 : 1 / elem->
hmin();
440 const auto normal = normals[qp];
441 const auto qhat = vector_qps[qp] + tau * (scalar_qps[qp] - lambda_qps[qp]) * normal;
444 for (
const auto i :
make_range(enriched_scalar_n_dofs))
445 F_enriched_scalar(i) -= JxW_face[qp] * enriched_scalar_phi_face[i][qp] * qhat * normal;
450 K_enriched_scalar.
lu_solve(F_enriched_scalar, U_enriched_scalar);
455 for (
const auto i :
make_range(enriched_scalar_n_dofs))
456 U_insertion(i) = U_enriched_scalar(i);
457 system.
solution->insert(U_insertion, enriched_scalar_dof_indices);
475 const auto & lambda_dof_map = lambda_system.
get_dof_map();
479 const FEType lambda_fe_type =
490 vector_fe->attach_quadrature_rule(&qrule);
491 scalar_fe->attach_quadrature_rule(&qrule);
503 vector_fe_face->attach_quadrature_rule(&qface);
504 scalar_fe_face->attach_quadrature_rule(&qface);
505 lambda_fe_face->attach_quadrature_rule(&qface);
508 const auto & JxW = vector_fe->get_JxW();
509 const auto & q_point = vector_fe->get_xyz();
510 const auto & vector_phi = vector_fe->get_phi();
511 const auto & scalar_phi = scalar_fe->get_phi();
512 const auto & grad_scalar_phi = scalar_fe->get_dphi();
513 const auto & div_vector_phi = vector_fe->get_div_phi();
516 const auto & vector_phi_face = vector_fe_face->get_phi();
517 const auto & scalar_phi_face = scalar_fe_face->get_phi();
518 const auto & lambda_phi_face = lambda_fe_face->get_phi();
519 const auto & JxW_face = scalar_fe_face->get_JxW();
520 const auto & qface_point = vector_fe_face->get_xyz();
521 const auto & normals = vector_fe_face->get_normals();
538 EigenMatrix A, Ainv,
B, Bt, C, Ct, Sinv, D, E, Et, H;
545 std::vector<dof_id_type> vector_dof_indices;
546 std::vector<dof_id_type> scalar_dof_indices;
547 std::vector<dof_id_type> lambda_dof_indices;
548 std::vector<Number> lambda_solution_std_vec;
553 for (
const auto & elem :
mesh.active_local_element_ptr_range())
556 dof_map.dof_indices(elem, vector_dof_indices, system.variable_number(
"q"));
557 dof_map.dof_indices(elem, scalar_dof_indices, system.variable_number(
"u"));
558 lambda_dof_map.dof_indices(elem, lambda_dof_indices, lambda_system.
variable_number(
"lambda"));
560 const auto vector_n_dofs = vector_dof_indices.size();
561 const auto scalar_n_dofs = scalar_dof_indices.size();
562 const auto lambda_n_dofs = lambda_dof_indices.size();
566 scalar_fe->reinit(elem);
568 libmesh_assert_equal_to(vector_n_dofs, vector_phi.size());
569 libmesh_assert_equal_to(scalar_n_dofs, scalar_phi.size());
572 A.setZero(vector_n_dofs, vector_n_dofs);
573 B.setZero(vector_n_dofs, scalar_n_dofs);
574 C.setZero(vector_n_dofs, lambda_n_dofs);
575 G.setZero(vector_n_dofs);
577 Bt.setZero(scalar_n_dofs, vector_n_dofs);
578 D.setZero(scalar_n_dofs, scalar_n_dofs);
579 E.setZero(scalar_n_dofs, lambda_n_dofs);
580 F.setZero(scalar_n_dofs);
582 Ct.setZero(lambda_n_dofs, vector_n_dofs);
583 Et.setZero(lambda_n_dofs, scalar_n_dofs);
584 H.setZero(lambda_n_dofs, lambda_n_dofs);
586 for (
const auto qp :
make_range(qrule.n_points()))
589 for (
const auto i :
make_range(vector_n_dofs))
590 for (
const auto j :
make_range(vector_n_dofs))
591 A(i, j) -= JxW[qp] * (vector_phi[i][qp] * vector_phi[j][qp]);
594 for (
const auto i :
make_range(vector_n_dofs))
595 for (
const auto j :
make_range(scalar_n_dofs))
596 B(i, j) += JxW[qp] * (div_vector_phi[i][qp] * scalar_phi[j][qp]);
599 for (
const auto i :
make_range(scalar_n_dofs))
600 for (
const auto j :
make_range(vector_n_dofs))
601 Bt(i, j) += JxW[qp] * (grad_scalar_phi[i][qp] * vector_phi[j][qp]);
608 const Real x = q_point[qp](0);
609 const Real y = q_point[qp](1);
610 const Real z = q_point[qp](2);
622 for (
const auto i :
make_range(scalar_n_dofs))
623 F(i) -= JxW[qp] * scalar_phi[i][qp] * f;
628 bool tau_found =
false;
629 for (
auto side : elem->side_index_range())
632 vector_fe_face->reinit(elem, side);
633 scalar_fe_face->reinit(elem, side);
634 lambda_fe_face->reinit(elem, side);
636 if (elem->neighbor_ptr(side) ==
nullptr)
637 for (
const auto qp :
make_range(qface.n_points()))
639 const Real xf = qface_point[qp](0);
640 const Real yf = qface_point[qp](1);
641 const Real zf = qface_point[qp](2);
644 Real scalar_value = 0;
651 for (
const auto i :
make_range(vector_n_dofs))
652 G(i) += JxW_face[qp] * (vector_phi_face[i][qp] * normals[qp]) * scalar_value;
659 for (
const auto i :
make_range(scalar_n_dofs))
660 for (
const auto j :
make_range(vector_n_dofs))
662 JxW_face[qp] * scalar_phi_face[i][qp] * (vector_phi_face[j][qp] * normals[qp]);
667 for (
const auto i :
make_range(lambda_n_dofs))
668 for (
const auto j :
make_range(lambda_n_dofs))
669 H(i, j) += JxW_face[qp] * lambda_phi_face[i][qp] * lambda_phi_face[j][qp];
676 const Real tau = tau_found ? 0 : 1 / elem->hmin();
679 for (
const auto qp :
make_range(qface.n_points()))
681 const auto normal = normals[qp];
682 const auto normal_sq = normal * normal;
685 for (
const auto i :
make_range(vector_n_dofs))
686 for (
const auto j :
make_range(lambda_n_dofs))
688 JxW_face[qp] * (vector_phi_face[i][qp] * normals[qp]) * lambda_phi_face[j][qp];
693 for (
const auto i :
make_range(scalar_n_dofs))
695 for (
const auto j :
make_range(vector_n_dofs))
696 Bt(i, j) -= JxW_face[qp] * scalar_phi_face[i][qp] * (vector_phi_face[j][qp] * normal);
698 for (
const auto j :
make_range(scalar_n_dofs))
700 JxW_face[qp] * scalar_phi_face[i][qp] * tau * scalar_phi_face[j][qp] * normal_sq;
702 for (
const auto j :
make_range(lambda_n_dofs))
704 JxW_face[qp] * scalar_phi_face[i][qp] * tau * lambda_phi_face[j][qp] * normal_sq;
710 for (
const auto i :
make_range(lambda_n_dofs))
712 for (
const auto j :
make_range(vector_n_dofs))
713 Ct(i, j) -= JxW_face[qp] * lambda_phi_face[i][qp] * (vector_phi_face[j][qp] * normal);
715 for (
const auto j :
make_range(scalar_n_dofs))
717 JxW_face[qp] * lambda_phi_face[i][qp] * tau * scalar_phi_face[j][qp] * normal_sq;
719 for (
const auto j :
make_range(lambda_n_dofs))
721 JxW_face[qp] * lambda_phi_face[i][qp] * tau * lambda_phi_face[j][qp] * normal_sq;
729 Sinv = (D - Bt * Ainv *
B).inverse();
730 const auto BtAinvCMinusE = Bt * Ainv * C - E;
731 const auto BtAinvGMinusF = Bt * Ainv * G - F;
732 const auto CtAinv = Ct * Ainv;
733 const auto BSinv =
B * Sinv;
734 const auto EtSinv = Et * Sinv;
735 K = -CtAinv * (BSinv * BtAinvCMinusE + C) + EtSinv * BtAinvCMinusE + H;
736 P = -CtAinv * (BSinv * BtAinvGMinusF + G) + EtSinv * BtAinvGMinusF;
739 K_libmesh.
resize(K.rows(), K.cols());
740 P_libmesh.
resize(P.size());
746 K_libmesh(i, j) = K(i, j);
753 dof_map.constrain_element_matrix_and_vector(K_libmesh, P_libmesh, lambda_dof_indices);
754 matrix.
add_matrix(K_libmesh, lambda_dof_indices);
755 lambda_system.rhs->
add_vector(P_libmesh, lambda_dof_indices);
765 Lambda.resize(lambda_n_dofs);
767 for (
const auto i :
make_range(lambda_n_dofs))
768 Lambda(i) = lambda_solution_std_vec[i];
769 const auto scalar_soln = Sinv * (BtAinvCMinusE * Lambda - BtAinvGMinusF);
770 const auto vector_soln = Ainv * (G -
B * scalar_soln - C * Lambda);
771 for (
const auto i :
make_range(vector_n_dofs))
772 system.solution->set(vector_dof_indices[i], vector_soln(i));
773 for (
const auto i :
make_range(scalar_n_dofs))
774 system.solution->set(scalar_dof_indices[i], scalar_soln(i));
797 system.solution->close();
807 libmesh_assert_equal_to(system_name,
"Lambda");
825 return 1 / elem->
hmin();
844 const auto & lambda_dof_map = lambda_system.
get_dof_map();
848 const FEType lambda_fe_type =
859 vector_fe->attach_quadrature_rule(&qrule);
860 scalar_fe->attach_quadrature_rule(&qrule);
872 vector_fe_face->attach_quadrature_rule(&qface);
873 scalar_fe_face->attach_quadrature_rule(&qface);
874 lambda_fe_face->attach_quadrature_rule(&qface);
877 const auto & JxW = vector_fe->get_JxW();
878 const auto & q_point = vector_fe->get_xyz();
879 const auto & vector_phi = vector_fe->get_phi();
880 const auto & scalar_phi = scalar_fe->get_phi();
881 const auto & grad_scalar_phi = scalar_fe->get_dphi();
882 const auto & div_vector_phi = vector_fe->get_div_phi();
885 const auto & vector_phi_face = vector_fe_face->get_phi();
886 const auto & scalar_phi_face = scalar_fe_face->get_phi();
887 const auto & lambda_phi_face = lambda_fe_face->get_phi();
888 const auto & JxW_face = scalar_fe_face->get_JxW();
889 const auto & qface_point = vector_fe_face->get_xyz();
890 const auto & normals = vector_fe_face->get_normals();
908 std::vector<dof_id_type> vector_dof_indices;
909 std::vector<dof_id_type> scalar_dof_indices;
910 std::vector<dof_id_type> lambda_dof_indices;
911 std::vector<Number> lambda_solution_std_vec;
915 std::vector<Number> mu;
918 auto & matrix = lambda_system.get_system_matrix();
920 auto compute_and_invert_K =
921 [&](
const auto vector_n_dofs_in,
const auto scalar_n_dofs_in,
const Elem *
const elem_in)
923 const auto mixed_size = vector_n_dofs_in + scalar_n_dofs_in;
925 K_mixed.setZero(mixed_size, mixed_size);
927 for (
const auto qp :
make_range(qrule.n_points()))
930 for (
const auto i :
make_range(vector_n_dofs_in))
931 for (
const auto j :
make_range(vector_n_dofs_in))
932 K_mixed(i, j) += JxW[qp] * (vector_phi[i][qp] * vector_phi[j][qp]);
935 for (
const auto i :
make_range(vector_n_dofs_in))
936 for (
const auto j :
make_range(scalar_n_dofs_in))
937 K_mixed(i, j + vector_n_dofs_in) -= JxW[qp] * (div_vector_phi[i][qp] * scalar_phi[j][qp]);
940 for (
const auto i :
make_range(scalar_n_dofs_in))
941 for (
const auto j :
make_range(vector_n_dofs_in))
942 K_mixed(i + vector_n_dofs_in, j) -= JxW[qp] * (grad_scalar_phi[i][qp] * vector_phi[j][qp]);
946 bool tau_found =
false;
947 for (
auto side : elem_in->side_index_range())
950 vector_fe_face->
reinit(elem_in, side);
951 scalar_fe_face->reinit(elem_in, side);
952 const bool internal_face = elem_in->neighbor_ptr(side);
953 const auto tau =
compute_tau(internal_face, tau_found, elem_in);
955 for (
const auto qp :
make_range(qface.n_points()))
957 const auto normal = normals[qp];
958 const auto normal_sq = normal * normal;
963 for (
const auto i :
make_range(scalar_n_dofs_in))
965 for (
const auto j :
make_range(vector_n_dofs_in))
966 K_mixed(i + vector_n_dofs_in, j) +=
967 JxW_face[qp] * scalar_phi_face[i][qp] * (vector_phi_face[j][qp] * normal);
970 for (
const auto j :
make_range(scalar_n_dofs_in))
971 K_mixed(i + vector_n_dofs_in, j + vector_n_dofs_in) +=
972 JxW_face[qp] * scalar_phi_face[i][qp] * tau * scalar_phi_face[j][qp] * normal_sq;
977 Kinv_mixed = K_mixed.inverse();
980 auto compute_rhs = [&](
const auto vector_n_dofs_in,
981 const auto scalar_n_dofs_in,
982 const Elem *
const elem_in,
983 const unsigned int shape_function)
985 const auto mixed_size = vector_n_dofs_in + scalar_n_dofs_in;
986 F_mixed.setZero(mixed_size);
992 for (
const auto qp :
make_range(qrule.n_points()))
994 const Real x = q_point[qp](0);
995 const Real y = q_point[qp](1);
996 const Real z = q_point[qp](2);
1003 for (
const auto ii :
make_range(scalar_n_dofs_in))
1004 F_mixed(ii + vector_n_dofs_in) += JxW[qp] * f * scalar_phi[ii][qp];
1008 bool tau_found =
false;
1009 std::vector<Number> g;
1011 for (
auto side : elem_in->side_index_range())
1014 vector_fe_face->reinit(elem_in, side);
1015 scalar_fe_face->reinit(elem_in, side);
1016 lambda_fe_face->reinit(elem_in, side);
1018 const auto & qp_mu = [&]()
1022 if (elem_in->neighbor_ptr(side))
1024 compute_qp_soln(lambda_solution_std_vec, qface.n_points(), lambda_phi_face, Lambda);
1025 return lambda_solution_std_vec;
1029 g.resize(qface.n_points());
1030 for (
const auto qp :
make_range(qface.n_points()))
1032 auto & g_qp = g[qp];
1033 const Real xf = qface_point[qp](0);
1034 const Real yf = qface_point[qp](1);
1035 const Real zf = qface_point[qp](2);
1048 auto & real_mu = lambda_phi_face[shape_function];
1049 mu.resize(qface.n_points());
1050 for (
const auto qp :
make_range(qface.n_points()))
1051 mu[qp] = real_mu[qp];
1056 const bool internal_face = elem_in->neighbor_ptr(side);
1057 const auto tau =
compute_tau(internal_face, tau_found, elem_in);
1059 for (
const auto qp :
make_range(qface.n_points()))
1061 const auto normal = normals[qp];
1062 const auto normal_sq = normal * normal;
1065 for (
const auto ii :
make_range(vector_n_dofs_in))
1066 F_mixed(ii) -= JxW_face[qp] * (vector_phi_face[ii][qp] * normal) * qp_mu[qp];
1071 for (
const auto ii :
make_range(scalar_n_dofs_in))
1072 F_mixed(ii + vector_n_dofs_in) +=
1073 JxW_face[qp] * scalar_phi_face[ii][qp] * tau * qp_mu[qp] * normal_sq;
1078 for (
const auto & elem :
mesh.active_local_element_ptr_range())
1080 std::vector<EigenVector> local_solns;
1081 std::vector<unsigned int> dofs_on_side;
1082 std::unordered_set<unsigned int> external_boundary_indices;
1083 std::vector<std::vector<Gradient>> volumetric_q;
1084 std::vector<std::vector<Number>> volumetric_u;
1085 std::vector<std::vector<Gradient>> face_q;
1088 dof_map.dof_indices(elem, vector_dof_indices, system.variable_number(
"q"));
1089 dof_map.dof_indices(elem, scalar_dof_indices, system.variable_number(
"u"));
1090 lambda_dof_map.dof_indices(elem, lambda_dof_indices, lambda_system.
variable_number(
"lambda"));
1092 const auto vector_n_dofs = vector_dof_indices.size();
1093 const auto scalar_n_dofs = scalar_dof_indices.size();
1094 const auto lambda_n_dofs = lambda_dof_indices.size();
1095 const std::size_t n_mu_funcs = global_solve ? lambda_n_dofs : 1;
1099 K_lm_libmesh.
resize(lambda_n_dofs, lambda_n_dofs);
1100 F_lm_libmesh.
resize(lambda_n_dofs);
1102 for (
const auto s : elem->side_index_range())
1103 if (!elem->neighbor_ptr(s))
1106 external_boundary_indices.insert(dofs_on_side.begin(), dofs_on_side.end());
1111 vector_fe->reinit(elem);
1112 scalar_fe->reinit(elem);
1114 libmesh_assert_equal_to(vector_n_dofs, vector_phi.size());
1115 libmesh_assert_equal_to(scalar_n_dofs, scalar_phi.size());
1117 compute_and_invert_K(vector_n_dofs, scalar_n_dofs, elem);
1118 local_solns.resize(n_mu_funcs);
1122 volumetric_q.resize(lambda_n_dofs);
1123 volumetric_u.resize(lambda_n_dofs);
1124 face_q.resize(lambda_n_dofs);
1126 for (
const auto i :
make_range(lambda_n_dofs))
1128 if (external_boundary_indices.count(i))
1131 compute_rhs(vector_n_dofs, scalar_n_dofs, elem, i);
1132 auto & local_soln = local_solns[i];
1133 local_soln = Kinv_mixed * F_mixed;
1134 const auto local_q_soln = local_soln.head(vector_n_dofs);
1135 const auto local_u_soln = local_soln.tail(scalar_n_dofs);
1136 compute_qp_soln(volumetric_q[i], qrule.n_points(), vector_phi, local_q_soln);
1137 compute_qp_soln(volumetric_u[i], qrule.n_points(), scalar_phi, local_u_soln);
1141 for (
const auto i :
make_range(lambda_n_dofs))
1142 if (!external_boundary_indices.count(i))
1143 for (
const auto j :
make_range(lambda_n_dofs))
1144 if (!external_boundary_indices.count(j))
1145 for (
const auto qp :
make_range(qrule.n_points()))
1146 K_lm_libmesh(i, j) += JxW[qp] * volumetric_q[i][qp] * volumetric_q[j][qp];
1149 for (
const auto qp :
make_range(qrule.n_points()))
1151 const Real x = q_point[qp](0);
1152 const Real y = q_point[qp](1);
1153 const Real z = q_point[qp](2);
1163 for (
const auto i :
make_range(lambda_n_dofs))
1164 if (!external_boundary_indices.count(i))
1165 F_lm_libmesh(i) += JxW[qp] * f * volumetric_u[i][qp];
1169 for (
const auto s : elem->side_index_range())
1171 lambda_fe_face->reinit(elem, s);
1172 for (
const auto i :
make_range(lambda_n_dofs))
1173 if (external_boundary_indices.count(i))
1174 for (
const auto j :
make_range(lambda_n_dofs))
1175 if (external_boundary_indices.count(j))
1176 for (
const auto qp :
make_range(qface.n_points()))
1177 K_lm_libmesh(i, j) +=
1178 JxW_face[qp] * lambda_phi_face[i][qp] * lambda_phi_face[j][qp];
1180 if (!elem->neighbor_ptr(s))
1182 vector_fe_face->reinit(elem, s);
1183 for (
const auto i :
make_range(lambda_n_dofs))
1185 if (external_boundary_indices.count(i))
1188 const auto local_q_soln = local_solns[i].head(vector_n_dofs);
1189 compute_qp_soln(face_q[i], qface.n_points(), vector_phi_face, local_q_soln);
1192 for (
const auto qp :
make_range(qface.n_points()))
1194 const Real xf = qface_point[qp](0);
1195 const Real yf = qface_point[qp](1);
1196 const Real zf = qface_point[qp](2);
1199 Real scalar_value = 0;
1204 for (
const auto i :
make_range(lambda_n_dofs))
1205 if (!external_boundary_indices.count(i))
1206 F_lm_libmesh(i) += JxW_face[qp] * scalar_value * face_q[i][qp] * normals[qp];
1213 dof_map.constrain_element_matrix_and_vector(K_lm_libmesh, F_lm_libmesh, lambda_dof_indices);
1214 matrix.
add_matrix(K_lm_libmesh, lambda_dof_indices);
1215 lambda_system.rhs->
add_vector(F_lm_libmesh, lambda_dof_indices);
1220 Lambda.resize(lambda_n_dofs);
1222 for (
const auto i :
make_range(lambda_n_dofs))
1223 Lambda(i) = lambda_solution_std_vec[i];
1226 auto & local_soln = local_solns[0];
1227 local_soln = Kinv_mixed * F_mixed;
1228 const auto vector_soln = local_soln.head(vector_n_dofs);
1229 const auto scalar_soln = local_soln.tail(scalar_n_dofs);
1230 for (
const auto i :
make_range(vector_n_dofs))
1231 system.solution->set(vector_dof_indices[i], vector_soln(i));
1232 for (
const auto i :
make_range(scalar_n_dofs))
1233 system.solution->set(scalar_dof_indices[i], scalar_soln(i));
1256 system.solution->close();
1266 libmesh_assert_equal_to(system_name,
"Lambda");
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Eigen::Matrix< Number, Eigen::Dynamic, Eigen::Dynamic > EigenMatrix
This class handles the computation of the L2 and/or H1 error for the Systems in the EquationSystems o...
This is the EquationSystems class.
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
IntRange< unsigned short > side_index_range() const
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
virtual void reinit()
Reinitializes degrees of freedom and other required data on the current mesh.
Real compute_tau(const bool internal_face, bool &tau_found, const Elem *const elem)
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
void attach_exact_values(const std::vector< FunctionBase< Number > *> &f)
Clone and attach arbitrary functors which compute the exact values of the EquationSystems' solutions ...
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and linear solvers ...
Eigen::Matrix< Number, Eigen::Dynamic, 1 > EigenVector
void resize(const unsigned int n)
Resize the vector.
const FEType & variable_type(const unsigned int c) const
void fe_assembly(EquationSystems &es, bool global_solve)
This is the base class from which all geometric element types are derived.
void extra_quadrature_order(const int extraorder)
Increases or decreases the order of the quadrature rule used for numerical integration.
Real scalar(Real x, Real y)
Order default_quadrature_order() const
NumericVector< Number > & add_vector(std::string_view vec_name, const bool projections=true, const ParallelType type=PARALLEL)
Adds the additional vector vec_name to this system.
virtual void reinit() override
Reinitializes the member data fields associated with the system, so that, e.g., assemble() may be use...
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
The libMesh namespace provides an interface to certain functionality in the library.
void attach_exact_derivs(const std::vector< FunctionBase< Gradient > *> &g)
Clone and attach arbitrary functors which compute the exact gradients of the EquationSystems' solutio...
const T_sys & get_system(std::string_view name) const
This is the MeshBase class.
unsigned int variable_number(std::string_view var) const
SolverPackage default_solver_package()
This class handles the numbering of degrees of freedom on a mesh.
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 Real hmin() const
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.
Manages consistently variables, degrees of freedom, and coefficient vectors.
void compute_error(std::string_view sys_name, std::string_view unknown_name)
Computes and stores the error in the solution value e = u-u_h, the gradient grad(e) = grad(u) - grad(...
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
void compute_enriched_soln(const MeshBase &mesh, const DofMap &dof_map, System &system, const Elem *const elem, const EigenVector &vector_soln, const EigenVector &scalar_soln, const EigenVector &Lambda, FEVectorBase &vector_fe, FEVectorBase &vector_fe_face, FEBase &scalar_fe, FEBase &scalar_fe_face, FEBase &lambda_fe_face, QBase &qrule, QBase &qface)
virtual_for_inffe const std::vector< Real > & get_JxW() const
virtual void reinit(const Elem *elem, const std::vector< Point > *const pts=nullptr, const std::vector< Real > *const weights=nullptr)=0
This is at the core of this class.
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.
unsigned int n_points() const
virtual_for_inffe const std::vector< Point > & get_xyz() const
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.
Real l2_error(std::string_view sys_name, std::string_view unknown_name)
virtual void solve()
Solves the system.
int main(int argc, char **argv)
const Elem * neighbor_ptr(unsigned int i) const
void lu_solve(const DenseVector< T > &b, DenseVector< T > &x)
Solve the system Ax=b given the input vector b.
Real forcing(Real x, Real y)
const FEType & variable_type(const unsigned int i) const
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void assemble_hdg(EquationSystems &es, const std::string &system_name)
virtual_for_inffe const std::vector< Point > & get_normals() const
void alternative_assemble_hdg(EquationSystems &es, const std::string &system_name)
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().
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
This class implements specific orders of Gauss quadrature.
unsigned int mesh_dimension() const
std::unique_ptr< NumericVector< Number > > current_local_solution
All the values I need to compute my contribution to the simulation at hand.
void compute_qp_soln(std::vector< SolnType > &qp_vec, const unsigned int n_qps, const std::vector< std::vector< PhiType >> &phi, const std::vector< Number > &dof_values)
virtual void init()
Initialize all the systems.
FEFamily
defines an enum for finite element families.
void alternative_fe_assembly(EquationSystems &es, bool global_solve)
virtual System & add_system(std::string_view system_type, std::string_view name)
Add the system of type system_type named name to the systems array.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
SparseMatrix< Number > & add_matrix(std::string_view mat_name, ParallelType type=PARALLEL, MatrixBuildType mat_build_type=MatrixBuildType::AUTOMATIC)
Adds the additional matrix mat_name to this system.
const DofMap & get_dof_map() const
static void dofs_on_side(const Elem *const elem, const unsigned int dim, const FEType &fe_t, unsigned int s, std::vector< unsigned int > &di, const bool add_p_level=true)
Fills the vector di with the local degree of freedom indices associated with side s of element elem A...
The QBase class provides the basic functionality from which various quadrature rules can be derived...
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
This class forms the foundation from which generic finite elements may be derived.
const std::vector< std::vector< OutputShape > > & get_phi() const