327{
330
331 const bool simplicial = es.
parameters.
get<
bool>(
"simplicial");
332
333
335
337
339 const auto & lambda_dof_map = lambda_system.
get_dof_map();
340
343 const FEType enriched_scalar_fe_type =
345 const FEType lambda_fe_type =
347
348
351 std::unique_ptr<FEBase> enriched_scalar_fe(
FEBase::build(
dim, enriched_scalar_fe_type));
352
353
355
356
357 vector_fe->attach_quadrature_rule(&qrule);
358 scalar_fe->attach_quadrature_rule(&qrule);
359 enriched_scalar_fe->attach_quadrature_rule(&qrule);
360
361
363 std::unique_ptr<FEBase> enriched_scalar_fe_face(
FEBase::build(
dim, enriched_scalar_fe_type));
365
366
367
369
370
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);
374
375
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();
382
383
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();
390
391
392
393
394
395
396
397
398
399
404
405
406
407
408
409
412
413
414
416
417
419
420 std::vector<Number> lambda_qps;
422 std::vector<Number> scalar_qps;
423
427
428
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;
434
435
437
438 for (
const auto & elem :
mesh.active_local_element_ptr_range())
439 {
440
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"));
444
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();
448
449
451 scalar_fe->reinit(elem);
452
453 libmesh_assert_equal_to(vector_n_dofs, vector_phi.size());
454 libmesh_assert_equal_to(scalar_n_dofs, scalar_phi.size());
455
456
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);
461
462 Bt.setZero(scalar_n_dofs, vector_n_dofs);
463 F.setZero(scalar_n_dofs);
464
465 Ct.setZero(lambda_n_dofs, vector_n_dofs);
466 L.setZero(lambda_n_dofs, lambda_n_dofs);
467
468 for (
const auto qp :
make_range(qrule.n_points()))
469 {
470
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]);
474
475
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]);
479
480
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]);
484
485
486
487
488
489 {
490 const Real x = q_point[qp](0);
491 const Real y = q_point[qp](1);
492 const Real z = q_point[qp](2);
493
494
495
496
502
503
504 for (
const auto i :
make_range(scalar_n_dofs))
505 F(i) -= JxW[qp] * scalar_phi[i][qp] * f;
506 }
507 }
508
509 {
510 for (auto side : elem->side_index_range())
511 {
512
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);
516
517 if (elem->neighbor_ptr(side) == nullptr)
518 for (
const auto qp :
make_range(qface.n_points()))
519 {
520 const Real xf = qface_point[qp](0);
521 const Real yf = qface_point[qp](1);
522 const Real zf = qface_point[qp](2);
523
524
525 Real scalar_value = 0;
530
531
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;
534
535
536
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];
540 }
541 else
542 for (
const auto qp :
make_range(qface.n_points()))
543 {
544
545 for (
const auto i :
make_range(vector_n_dofs))
546 for (const auto j :
make_range(lambda_n_dofs))
547 C(i, j) +=
548 JxW_face[qp] * (vector_phi_face[i][qp] * normals[qp]) * lambda_phi_face[j][qp];
549
550
551 for (
const auto i :
make_range(lambda_n_dofs))
552 for (const auto j :
make_range(vector_n_dofs))
553 Ct(i, j) +=
554 JxW_face[qp] * lambda_phi_face[i][qp] * (vector_phi_face[j][qp] * normals[qp]);
555 }
556 }
557 }
558
559 Ainv = A.inverse();
560
561 Sinv = (Bt * Ainv *
B).inverse();
562
563
564
565
566 E = Ct * Ainv * (A -
B * Sinv * Bt) * Ainv * C;
567 E = E + L;
568 Hg = Ct * Ainv * (A -
B * Sinv * Bt) * Ainv * G;
569 Hf = Ct * Ainv *
B * Sinv * F;
570 H = Hg + Hf;
571
572
573 E_libmesh.
resize(E.rows(), E.cols());
574 H_libmesh.
resize(H.size());
577 {
578 H_libmesh(i) = H(i);
580 E_libmesh(i, j) = E(i, j);
581 }
582
583 if (global_solve)
584 {
585
586
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);
590 }
591 else
592 {
593
594
595
596
597
598
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));
609
610#if !defined(LIBMESH_HAVE_PETSC) || !defined(LIBMESH_USE_REAL_NUMBERS)
611 if (!simplicial)
612
613 continue;
614#endif
615
616
617
618
619
620
621
622
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;
627
628 K_enriched_scalar.
resize(m, n);
629 F_enriched_scalar.
resize(m);
630 U_enriched_scalar.
resize(n);
631
632
633 for (const auto side : elem->side_index_range())
634 {
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)
639 for (
const auto qp :
make_range(qface.n_points()))
640 {
641 const Real xf = qface_point[qp](0);
642 const Real yf = qface_point[qp](1);
643 const Real zf = qface_point[qp](2);
644
645
646 Real scalar_value = 0;
651
652 for (
const auto i :
make_range(lambda_n_dofs))
653 {
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];
658 }
659 }
660 else
661 {
662
663 lambda_qps.
resize(qface.n_points());
664 for (auto & lambda_qp : lambda_qps)
665 lambda_qp = 0;
666 for (
const auto qp :
make_range(qface.n_points()))
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];
669
670 for (
const auto qp :
make_range(qface.n_points()))
671 for (const auto i :
make_range(lambda_n_dofs))
672 {
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];
677 }
678 }
679 }
680
681 if (simplicial)
682 K_enriched_scalar.
lu_solve(F_enriched_scalar, U_enriched_scalar);
683 else
684 {
685
686
687
688
689
690
691 enriched_scalar_fe->reinit(elem);
695
696 scalar_qps.resize(qrule.n_points());
697 for (auto & scalar_qp : scalar_qps)
698 scalar_qp = 0;
699 for (
const auto qp :
make_range(qrule.n_points()))
700 scalar_qps[qp] += scalar_soln(0) * scalar_phi[0][qp];
701 for (
const auto qp :
make_range(qrule.n_points()))
702 {
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];
706 }
707
708 K_enriched_scalar.
svd_solve(F_enriched_scalar, U_enriched_scalar);
709 }
710
711
712 system.solution->insert(U_enriched_scalar, enriched_scalar_dof_indices);
713 }
714 }
715
716 if (!global_solve)
717 {
718 system.solution->close();
719
720 system.update();
721 }
722}
Real forcing(Real x, Real y)
Real scalar(Real x, Real y)
Defines a dense matrix for use in Finite Element-type computations.
void svd_solve(const DenseVector< T > &rhs, DenseVector< T > &x, Real rcond=std::numeric_limits< Real >::epsilon()) const
Solve the system of equations for in the least-squares sense.
void resize(const unsigned int new_m, const unsigned int new_n)
Resizes the matrix to the specified size and calls zero().
void lu_solve(const DenseVector< T > &b, DenseVector< T > &x)
Solve the system Ax=b given the input vector b.
Defines a dense vector for use in Finite Element-type computations.
void resize(const unsigned int n)
Resize the vector.
const MeshBase & get_mesh() const
Parameters parameters
Data structure holding arbitrary parameters.
const T_sys & get_system(std::string_view name) const
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...
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and linear solvers ...
virtual void reinit() override
Reinitializes the member data fields associated with the system, so that, e.g., assemble() may be use...
This is the MeshBase class.
unsigned int mesh_dimension() const
const T & get(std::string_view) const
This class implements specific orders of Gauss quadrature.
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.
Manages consistently variables, degrees of freedom, and coefficient vectors.
std::unique_ptr< NumericVector< Number > > current_local_solution
All the values I need to compute my contribution to the simulation at hand.
const FEType & variable_type(const unsigned int i) 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.
unsigned int variable_number(std::string_view var) const
const DofMap & get_dof_map() const
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
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...