331 const bool simplicial = es.
parameters.
get<
bool>(
"simplicial");
339 const auto & lambda_dof_map = lambda_system.
get_dof_map();
343 const FEType enriched_scalar_fe_type =
345 const FEType lambda_fe_type =
351 std::unique_ptr<FEBase> enriched_scalar_fe(
FEBase::build(
dim, enriched_scalar_fe_type));
357 vector_fe->attach_quadrature_rule(&qrule);
358 scalar_fe->attach_quadrature_rule(&qrule);
359 enriched_scalar_fe->attach_quadrature_rule(&qrule);
363 std::unique_ptr<FEBase> enriched_scalar_fe_face(
FEBase::build(
dim, enriched_scalar_fe_type));
371 vector_fe_face->attach_quadrature_rule(&qface);
372 enriched_scalar_fe_face->attach_quadrature_rule(&qface);
373 lambda_fe_face->attach_quadrature_rule(&qface);
376 const auto & JxW = vector_fe->get_JxW();
377 const auto & q_point = vector_fe->get_xyz();
378 const auto & vector_phi = vector_fe->get_phi();
379 const auto & scalar_phi = scalar_fe->get_phi();
380 const auto & enriched_scalar_phi = enriched_scalar_fe->get_phi();
381 const auto & div_vector_phi = vector_fe->get_div_phi();
384 const auto & vector_phi_face = vector_fe_face->get_phi();
385 const auto & enriched_scalar_phi_face = enriched_scalar_fe_face->get_phi();
386 const auto & lambda_phi_face = lambda_fe_face->get_phi();
387 const auto & JxW_face = vector_fe_face->get_JxW();
388 const auto & qface_point = vector_fe_face->get_xyz();
389 const auto & normals = vector_fe_face->get_normals();
420 std::vector<Number> lambda_qps;
422 std::vector<Number> scalar_qps;
429 std::vector<dof_id_type> vector_dof_indices;
430 std::vector<dof_id_type> scalar_dof_indices;
431 std::vector<dof_id_type> enriched_scalar_dof_indices;
432 std::vector<dof_id_type> lambda_dof_indices;
433 std::vector<Number> lambda_solution_std_vec;
438 for (
const auto & elem :
mesh.active_local_element_ptr_range())
441 dof_map.dof_indices(elem, vector_dof_indices, system.variable_number(
"u"));
442 dof_map.dof_indices(elem, scalar_dof_indices, system.variable_number(
"p"));
443 lambda_dof_map.dof_indices(elem, lambda_dof_indices, lambda_system.
variable_number(
"lambda"));
445 const auto vector_n_dofs = vector_dof_indices.size();
446 const auto scalar_n_dofs = scalar_dof_indices.size();
447 const auto lambda_n_dofs = lambda_dof_indices.size();
451 scalar_fe->reinit(elem);
453 libmesh_assert_equal_to(vector_n_dofs, vector_phi.size());
454 libmesh_assert_equal_to(scalar_n_dofs, scalar_phi.size());
457 A.setZero(vector_n_dofs, vector_n_dofs);
458 B.setZero(vector_n_dofs, scalar_n_dofs);
459 C.setZero(vector_n_dofs, lambda_n_dofs);
460 G.setZero(vector_n_dofs);
462 Bt.setZero(scalar_n_dofs, vector_n_dofs);
463 F.setZero(scalar_n_dofs);
465 Ct.setZero(lambda_n_dofs, vector_n_dofs);
466 L.setZero(lambda_n_dofs, lambda_n_dofs);
471 for (
const auto i :
make_range(vector_n_dofs))
472 for (
const auto j :
make_range(vector_n_dofs))
473 A(i, j) += JxW[qp] * (vector_phi[i][qp] * vector_phi[j][qp]);
476 for (
const auto i :
make_range(vector_n_dofs))
477 for (
const auto j :
make_range(scalar_n_dofs))
478 B(i, j) -= JxW[qp] * (div_vector_phi[i][qp] * scalar_phi[j][qp]);
481 for (
const auto i :
make_range(scalar_n_dofs))
482 for (
const auto j :
make_range(vector_n_dofs))
483 Bt(i, j) -= JxW[qp] * (scalar_phi[i][qp] * div_vector_phi[j][qp]);
490 const Real x = q_point[qp](0);
491 const Real y = q_point[qp](1);
492 const Real z = q_point[qp](2);
504 for (
const auto i :
make_range(scalar_n_dofs))
505 F(i) -= JxW[qp] * scalar_phi[i][qp] * f;
510 for (
auto side : elem->side_index_range())
513 vector_fe_face->reinit(elem, side);
514 libmesh_assert_equal_to(vector_n_dofs, vector_phi_face.size());
515 lambda_fe_face->reinit(elem, side);
517 if (elem->neighbor_ptr(side) ==
nullptr)
520 const Real xf = qface_point[qp](0);
521 const Real yf = qface_point[qp](1);
522 const Real zf = qface_point[qp](2);
525 Real scalar_value = 0;
532 for (
const auto i :
make_range(vector_n_dofs))
533 G(i) -= JxW_face[qp] * (vector_phi_face[i][qp] * normals[qp]) * scalar_value;
537 for (
const auto i :
make_range(lambda_n_dofs))
538 for (
const auto j :
make_range(lambda_n_dofs))
539 L(i, j) += JxW_face[qp] * lambda_phi_face[i][qp] * lambda_phi_face[j][qp];
545 for (
const auto i :
make_range(vector_n_dofs))
546 for (
const auto j :
make_range(lambda_n_dofs))
548 JxW_face[qp] * (vector_phi_face[i][qp] * normals[qp]) * lambda_phi_face[j][qp];
551 for (
const auto i :
make_range(lambda_n_dofs))
552 for (
const auto j :
make_range(vector_n_dofs))
554 JxW_face[qp] * lambda_phi_face[i][qp] * (vector_phi_face[j][qp] * normals[qp]);
561 Sinv = (Bt * Ainv *
B).inverse();
566 E = Ct * Ainv * (A -
B * Sinv * Bt) * Ainv * C;
568 Hg = Ct * Ainv * (A -
B * Sinv * Bt) * Ainv * G;
569 Hf = Ct * Ainv *
B * Sinv * F;
573 E_libmesh.
resize(E.rows(), E.cols());
574 H_libmesh.
resize(H.size());
580 E_libmesh(i, j) = E(i, j);
587 dof_map.constrain_element_matrix_and_vector(E_libmesh, H_libmesh, lambda_dof_indices);
588 matrix.
add_matrix(E_libmesh, lambda_dof_indices);
589 lambda_system.rhs->
add_vector(H_libmesh, lambda_dof_indices);
599 Lambda.resize(lambda_n_dofs);
601 for (
const auto i :
make_range(lambda_n_dofs))
602 Lambda(i) = lambda_solution_std_vec[i];
603 const auto scalar_soln = Sinv * Bt * Ainv * G - Sinv * F - Sinv * Bt * Ainv * C * Lambda;
604 const auto vector_soln = Ainv * (G -
B * scalar_soln - C * Lambda);
605 for (
const auto i :
make_range(vector_n_dofs))
606 system.solution->set(vector_dof_indices[i], vector_soln(i));
607 for (
const auto i :
make_range(scalar_n_dofs))
608 system.solution->set(scalar_dof_indices[i], scalar_soln(i));
610#if !defined(LIBMESH_HAVE_PETSC) || !defined(LIBMESH_USE_REAL_NUMBERS)
623 dof_map.dof_indices(elem, enriched_scalar_dof_indices, system.variable_number(
"p_enriched"));
624 const auto enriched_scalar_n_dofs = enriched_scalar_dof_indices.size();
625 const auto m = simplicial ? lambda_n_dofs : lambda_n_dofs + 1;
626 const auto n = enriched_scalar_n_dofs;
628 K_enriched_scalar.
resize(m, n);
629 F_enriched_scalar.
resize(m);
630 U_enriched_scalar.
resize(n);
633 for (
const auto side : elem->side_index_range())
635 vector_fe_face->reinit(elem, side);
636 enriched_scalar_fe_face->reinit(elem, side);
637 lambda_fe_face->reinit(elem, side);
638 if (elem->neighbor_ptr(side) ==
nullptr)
641 const Real xf = qface_point[qp](0);
642 const Real yf = qface_point[qp](1);
643 const Real zf = qface_point[qp](2);
646 Real scalar_value = 0;
652 for (
const auto i :
make_range(lambda_n_dofs))
654 F_enriched_scalar(i) += JxW_face[qp] * lambda_phi_face[i][qp] * scalar_value;
655 for (
const auto j :
make_range(enriched_scalar_n_dofs))
656 K_enriched_scalar(i, j) +=
657 JxW_face[qp] * lambda_phi_face[i][qp] * enriched_scalar_phi_face[j][qp];
664 for (
auto & lambda_qp : lambda_qps)
667 for (
const auto i :
index_range(lambda_solution_std_vec))
668 lambda_qps[qp] += lambda_solution_std_vec[i] * lambda_phi_face[i][qp];
671 for (
const auto i :
make_range(lambda_n_dofs))
673 F_enriched_scalar(i) += JxW_face[qp] * lambda_phi_face[i][qp] * lambda_qps[qp];
674 for (
const auto j :
make_range(enriched_scalar_n_dofs))
675 K_enriched_scalar(i, j) +=
676 JxW_face[qp] * lambda_phi_face[i][qp] * enriched_scalar_phi_face[j][qp];
682 K_enriched_scalar.
lu_solve(F_enriched_scalar, U_enriched_scalar);
691 enriched_scalar_fe->reinit(elem);
696 scalar_qps.resize(qrule.
n_points());
697 for (
auto & scalar_qp : scalar_qps)
700 scalar_qps[qp] += scalar_soln(0) * scalar_phi[0][qp];
703 F_enriched_scalar(n) += JxW[qp] * scalar_phi[0][qp] * scalar_qps[qp];
705 K_enriched_scalar(n, j) += JxW[qp] * scalar_phi[0][qp] * enriched_scalar_phi[j][qp];
708 K_enriched_scalar.
svd_solve(F_enriched_scalar, U_enriched_scalar);
712 system.solution->insert(U_enriched_scalar, enriched_scalar_dof_indices);
718 system.solution->close();