10#ifndef __ELASTIC_TIE_HPP__
11#define __ELASTIC_TIE_HPP__
36 boost::make_shared<MatrixDouble>();
38 boost::make_shared<MatrixDouble>();
46 const Range &ents,
const int max_dim,
47 EntityHandle &meshset) {
50 for (
int d = 0; d < max_dim; ++d) {
52 CHKERR moab.get_adjacencies(ents, d,
false, adj,
53 moab::Interface::UNION);
56 CHKERR moab.create_meshset(MESHSET_SET, meshset);
57 CHKERR moab.add_entities(meshset, closure);
62 Range physical_ents = ents.subset_by_type(MBTET);
63 physical_ents.merge(ents.subset_by_type(MBHEX));
69 Range &triangle_faces) {
71 triangle_faces.clear();
72 const auto prisms = ents.subset_by_type(MBPRISM);
73 if (!prisms.empty()) {
74 CHKERR moab.get_adjacencies(prisms, 2,
false, triangle_faces,
75 moab::Interface::UNION);
76 triangle_faces = triangle_faces.subset_by_type(MBTRI);
90 Range &physicalBoundaryFaces) {
93 auto meshset_mng = mField.
getInterface<MeshsetsManager>();
94 auto comm_interface = mField.
getInterface<CommInterface>();
96 physicalBoundaryFaces.clear();
100 const char *) -> MoFEMErrorCode {
103 CHKERR moab.load_file(file_name, 0,
104 "PARALLEL=BCAST;PARTITION=PARALLEL_PARTITION;");
107 if (pcomm ==
nullptr)
108 pcomm =
new ParallelComm(&moab, mf.
get_comm());
110 const auto rank = pcomm->rank();
111 Tag part_tag = pcomm->part_tag();
112 Range all_ents, tagged_sets, proc_ents, off_proc_ents;
113 CHKERR moab.get_entities_by_handle(0, all_ents,
false);
114 CHKERR moab.get_entities_by_type_and_tag(
115 0, MBENTITYSET, &part_tag,
nullptr, 1, tagged_sets,
116 moab::Interface::UNION);
118 for (
auto meshset : tagged_sets) {
120 CHKERR moab.tag_get_data(part_tag, &meshset, 1, &part);
122 CHKERR moab.get_entities_by_handle(meshset, meshset_ents,
true);
124 proc_ents.merge(meshset_ents);
126 off_proc_ents.merge(meshset_ents);
127 CHKERR moab.tag_clear_data(part_tag, meshset_ents, &part);
130 const auto all_volume_ents = all_ents.subset_by_dimension(3);
131 const auto proc_volume_ents = proc_ents.subset_by_dimension(3);
135 std::array<Range, 4> proc_ents_skin;
137 Range all_skin, proc_skin;
138 CHKERR skin.find_skin(0, all_volume_ents,
false, all_skin);
139 CHKERR skin.find_skin(0, proc_volume_ents,
false, proc_skin);
140 proc_ents_skin[2] = subtract(proc_skin, all_skin);
142 Range all_phys_skin, local_phys_faces, physical_boundary_faces;
143 CHKERR skin.find_skin(0, all_phys_ents.subset_by_dimension(3),
false,
145 CHKERR moab.get_adjacencies(proc_phys_ents, 2,
false, local_phys_faces,
146 moab::Interface::UNION);
147 physical_boundary_faces = intersect(all_phys_skin, local_phys_faces);
148 if (!physical_boundary_faces.empty()) {
149 CHKERR moab.tag_clear_data(pcomm->partition_tag(),
150 physical_boundary_faces, &rank);
152 proc_ents_skin[2].merge(physical_boundary_faces);
154 Range prism_triangle_faces;
156 proc_ents_skin[2].merge(prism_triangle_faces);
157 CHKERR moab.get_adjacencies(proc_ents_skin[2], 1,
false,
158 proc_ents_skin[1], moab::Interface::UNION);
159 CHKERR moab.get_connectivity(proc_ents_skin[2], proc_ents_skin[0],
162 auto to_remove = off_proc_ents;
163 for (
int d = 2; d >= 0; --d)
164 to_remove = subtract(to_remove, proc_ents_skin[d]);
167 CHKERR moab.get_entities_by_type(0, MBENTITYSET, all_meshsets,
true);
168 for (
auto meshset : all_meshsets)
169 CHKERR moab.remove_entities(meshset, to_remove);
171 for (
int d = 3; d > 0; --d) {
172 Range ents = to_remove.subset_by_dimension(d);
174 CHKERR moab.delete_entities(ents);
177 physicalBoundaryFaces = physical_boundary_faces;
178 CHKERR pcomm->resolve_shared_ents(0, proc_ents, 3, -1,
179 proc_ents_skin.data());
190 CHKERR comm_interface->synchroniseEntities(physicalBoundaryFaces);
192 CHKERR meshset_mng->setMeshsetFromFile();
198 const double tol = 1e-8) {
203 const int prism_face_side) {
207 : (side >= 3 && side < 6);
210 : (side >= 6 && side < 9);
212 return side == prism_face_side;
224 const EntityType row_type) {
229 return row_side >= 0 && row_side < 3;
252 int order_col,
int order_data) {
255 auto fe_ptr =
static_cast<FlatPrismElementForcesAndSourcesCore *
>(fe_raw_ptr);
256 const int rule =
funRule(std::max(order_data, std::max(order_row, order_col)));
260 "-tie_ref_level has to be >= 0");
265 "Triangle quadrature rule %d is not available for TIE prism face "
272 "Expected 2D quadrature for TIE prism face integration");
277 "Wrong quadrature order %d < %d for TIE prism face integration",
284 const auto cache_key = std::make_pair(rule,
tieRefLevel);
287 MatrixDouble ref_gauss_pts;
292 fe_ptr->gaussPts = it->second;
295 const MatrixDouble slave_gauss_pts = fe_ptr->gaussPts;
296 const auto nb_gauss_pts = slave_gauss_pts.size2();
298 auto &moab = fe_ptr->mField.get_moab();
299 auto get_prism_face_coords = [&](
const int side, std::array<double, 9> &coords) {
301 const EntityHandle prism = fe_ptr->getFEEntityHandle();
302 const EntityHandle *prism_conn =
nullptr;
303 int num_prism_nodes = 0;
304 CHKERR moab.get_connectivity(prism, prism_conn, num_prism_nodes,
true);
305 if (num_prism_nodes != 6) {
307 "TIE prism is expected to have 6 nodes");
310 std::array<EntityHandle, 3> face_conn;
313 face_conn = {prism_conn[0], prism_conn[1], prism_conn[2]};
316 face_conn = {prism_conn[3], prism_conn[4], prism_conn[5]};
320 "Unsupported TIE prism triangle side %d", side);
323 CHKERR moab.get_coords(face_conn.data(), 3, coords.data());
327 std::array<double, 9> slave_coords;
328 std::array<double, 9> master_coords;
332 MatrixDouble slave_global_coords(nb_gauss_pts, 3,
false);
333 MatrixDouble master_global_coords(nb_gauss_pts, 3,
false);
334 MatrixDouble slave_shape(nb_gauss_pts, 3,
false);
336 &slave_gauss_pts(1, 0), nb_gauss_pts);
337 for (
size_t gg = 0; gg != nb_gauss_pts; ++gg) {
338 for (
int dd = 0; dd != 3; ++dd) {
339 slave_global_coords(gg, dd) =
340 slave_shape(gg, 0) * slave_coords[0 + dd] +
341 slave_shape(gg, 1) * slave_coords[3 + dd] +
342 slave_shape(gg, 2) * slave_coords[6 + dd];
348 master_global_coords);
350 MatrixDouble master_local_coords(nb_gauss_pts, 2,
false);
351 CHKERR Tools::getLocalCoordinatesOnReferenceThreeNodeTri(
352 master_coords.data(), &master_global_coords(0, 0),
353 master_global_coords.size1(), &master_local_coords(0, 0));
355 MatrixDouble combined_gauss_pts(3, 2 * nb_gauss_pts,
false);
356 for (
size_t gg = 0; gg != nb_gauss_pts; ++gg) {
357 const bool valid_master_point =
359 master_local_coords(gg, 1));
360 const double paired_weight = valid_master_point ? slave_gauss_pts(2, gg) : 0.;
362 combined_gauss_pts(0, gg) = slave_gauss_pts(0, gg);
363 combined_gauss_pts(1, gg) = slave_gauss_pts(1, gg);
364 combined_gauss_pts(2, gg) = paired_weight;
366 combined_gauss_pts(0, gg + nb_gauss_pts) = master_local_coords(gg, 0);
367 combined_gauss_pts(1, gg + nb_gauss_pts) = master_local_coords(gg, 1);
368 combined_gauss_pts(2, gg + nb_gauss_pts) = paired_weight;
370 fe_ptr->gaussPts.swap(combined_gauss_pts);
377 FlatPrismElementForcesAndSourcesCore &fe,
const int rule) {
380 fe.gaussPts.resize(3, nb_gauss_pts,
false);
381 cblas_dcopy(nb_gauss_pts, &
QUAD_2D_TABLE[rule]->points[1], 3,
382 &fe.gaussPts(0, 0), 1);
383 cblas_dcopy(nb_gauss_pts, &
QUAD_2D_TABLE[rule]->points[2], 3,
384 &fe.gaussPts(1, 0), 1);
386 &fe.gaussPts(2, 0), 1);
392 double *projected_point) {
397 const double ax = master_coords[0];
398 const double ay = master_coords[1];
399 const double az = master_coords[2];
400 const double bx = master_coords[3];
401 const double by = master_coords[4];
402 const double bz = master_coords[5];
403 const double cx = master_coords[6];
404 const double cy = master_coords[7];
405 const double cz = master_coords[8];
407 const double abx = bx - ax;
408 const double aby = by - ay;
409 const double abz = bz - az;
410 const double acx = cx - ax;
411 const double acy = cy - ay;
412 const double acz = cz - az;
414 const double nx = aby * acz - abz * acy;
415 const double ny = abz * acx - abx * acz;
416 const double nz = abx * acy - aby * acx;
417 const double n_norm_sq = nx * nx + ny * ny + nz * nz;
418 if (n_norm_sq <= std::numeric_limits<double>::epsilon()) {
420 "Degenerated master triangle plane");
423 const double px = point[0] - ax;
424 const double py = point[1] - ay;
425 const double pz = point[2] - az;
426 const double signed_distance = (px * nx + py * ny + pz * nz) / n_norm_sq;
427 projected_point[0] = point[0] - signed_distance * nx;
428 projected_point[1] = point[1] - signed_distance * ny;
429 projected_point[2] = point[2] - signed_distance * nz;
435 const double *master_coords,
const MatrixDouble &slave_global_coords,
436 MatrixDouble &master_global_coords) {
442 master_global_coords.resize(slave_global_coords.size1(), 3,
false);
443 for (
size_t gg = 0; gg != slave_global_coords.size1(); ++gg) {
445 &slave_global_coords(gg, 0),
446 &master_global_coords(gg, 0));
453 FlatPrismElementForcesAndSourcesCore &fe,
const int refinement_levels,
454 MatrixDouble &ref_gauss_pts) {
457 constexpr int num_nodes = 3;
459 double base_coords[] = {0, 0, 0, 1, 0, 0, 0, 1, 0};
460 EntityHandle nodes[num_nodes];
461 for (
int nn = 0; nn != num_nodes; ++nn)
462 CHKERR moab_ref.create_vertex(&base_coords[3 * nn], nodes[nn]);
465 CHKERR moab_ref.create_element(MBTRI, nodes, num_nodes, tri);
470 Range tris(tri, tri);
477 tris, 1,
true, edges, moab::Interface::UNION);
478 for (
auto edge : edges) {
479 int side_number = -1, sense = 0, offset = 0;
480 CHKERR moab_ref.side_number(tri, edge, side_number, sense, offset);
483 tris, BitRefLevel().set(0),
false,
VERBOSE);
486 auto *m_ref = m_field_ref.
getInterface<MeshRefinement>();
487 for (
int ll = 0; ll != refinement_levels; ++ll) {
490 ->getEntitiesByTypeAndRefLevel(BitRefLevel().set(ll),
491 BitRefLevel().set(), MBTRI, tris);
494 CHKERR moab_ref.get_adjacencies(tris, 1,
true, edges,
495 moab::Interface::UNION);
497 const BitRefLevel child_bit = BitRefLevel().set(ll + 1);
498 CHKERR m_ref->addVerticesInTheMiddleOfEdges(edges, child_bit);
499 CHKERR m_ref->refineTris(tris, child_bit,
QUIET,
false);
504 BitRefLevel().set(refinement_levels), BitRefLevel().set(), MBTRI, tris);
506 MatrixDouble ref_coords(tris.size(), 9,
false);
508 for (
auto tit = tris.begin(); tit != tris.end(); ++tit, ++tt) {
510 const EntityHandle *conn;
511 CHKERR moab_ref.get_connectivity(*tit, conn, num_conn,
false);
512 CHKERR moab_ref.get_coords(conn, num_conn, &ref_coords(tt, 0));
515 const size_t nb_gauss_pts = fe.gaussPts.size2();
516 MatrixDouble shape_n(nb_gauss_pts, 3,
false);
519 ref_gauss_pts.resize(3, nb_gauss_pts * ref_coords.size1(),
false);
521 for (
size_t rr = 0; rr != ref_coords.size1(); ++rr) {
522 double *tri_coords = &ref_coords(rr, 0);
524 CHKERR Tools::getTriNormal(tri_coords, &t_normal(0));
525 const double det = t_normal.
l2();
526 for (
size_t ggg = 0; ggg != nb_gauss_pts; ++ggg, ++gg) {
527 for (
int dd = 0; dd != 2; ++dd) {
528 ref_gauss_pts(dd, gg) =
529 shape_n(ggg, 0) * tri_coords[3 * 0 + dd] +
530 shape_n(ggg, 1) * tri_coords[3 * 1 + dd] +
531 shape_n(ggg, 2) * tri_coords[3 * 2 + dd];
533 ref_gauss_pts(2, gg) = fe.gaussPts(2, ggg) * det;
540 static inline std::map<std::pair<int, int>, MatrixDouble>
mapRefCoords;
543template <
int Tensor_Dim>
545 :
public OpCalculateVectorFieldValues_General<Tensor_Dim, MatrixDouble> {
547 using Base = OpCalculateVectorFieldValues_General<Tensor_Dim, MatrixDouble>;
551 EntitiesFieldData::EntData &data)
override {
561 FlatPrismElementForcesAndSourcesCore::UserDataOperator>::Assembly<A>::OpBase;
575 MoFEMErrorCode
iNtegrate(EntitiesFieldData::EntData &row_data)
override {
579 dynamic_cast<const FlatPrismElementForcesAndSourcesCore *
>(ptrFE);
582 "TIE prism RHS operator is attached to a wrong finite element");
584 const auto nb_gauss_pts = getGaussPts().size2();
585 if (!nb_gauss_pts || nb_gauss_pts % 2) {
587 "Expected concatenated [slave|master] TIE Gauss points");
589 const auto nb_slave_gauss = nb_gauss_pts / 2;
590 if (
dispPtr->size1() != nb_gauss_pts) {
592 "TIE displacement values at Gauss points were not prepared "
593 "before RHS assembly");
598 "Unexpected number of LAMBDA dofs on TIE prism rows");
600 auto &row_n = row_data.getN();
601 if (!row_n.size1() || !row_n.size2())
603 if (row_n.size1() != nb_gauss_pts)
605 "Unexpected number of Gauss points on TIE multiplier block");
607 const int nb_row_base = nbRows /
SPACE_DIM;
608 if (
static_cast<size_t>(nb_row_base) > row_n.size2())
610 "More TIE multiplier bases than shape functions");
613 "Unexpected TIE displacement matrix size: size2=%d expected=%d",
615 if (locF.size() !=
static_cast<size_t>(nbRows))
617 "Unexpected TIE RHS block size: rowSide=%d rowType=%d nbRows=%d "
618 "locF.size()=%d row_n=(%d,%d) disp=(%d,%d)",
619 rowSide, rowType, nbRows,
static_cast<int>(locF.size()),
620 static_cast<int>(row_n.size1()),
static_cast<int>(row_n.size2()),
621 static_cast<int>(
dispPtr->size1()),
622 static_cast<int>(
dispPtr->size2()));
624 auto t_w = getFTensor0IntegrationWeight();
625 for (
size_t gg = 0; gg != nb_slave_gauss; ++gg) {
627 auto t_row_base = row_data.getFTensor0N(gg, 0);
628 for (
int rr = 0; rr != nb_row_base; ++rr) {
629 const double row_base = t_row_base;
630 if (row_base != 0.) {
631 auto t_row_rhs = getFTensor1FromPtr<SPACE_DIM>(&locF[
SPACE_DIM * rr]);
632 for (
int dd = 0; dd !=
SPACE_DIM; ++dd) {
633 t_row_rhs(dd) += row_base * slave_alpha *
634 ((*dispPtr)(gg, dd) -
635 (*
dispPtr)(gg + nb_slave_gauss, dd));
654 boost::shared_ptr<MatrixDouble> lambda_ptr)
664 MoFEMErrorCode
iNtegrate(EntitiesFieldData::EntData &row_data)
override {
668 dynamic_cast<const FlatPrismElementForcesAndSourcesCore *
>(ptrFE);
671 "TIE prism RHS operator is attached to a wrong finite element");
673 const auto nb_gauss_pts = getGaussPts().size2();
674 if (!nb_gauss_pts || nb_gauss_pts % 2) {
676 "Expected concatenated [slave|master] TIE Gauss points");
678 const auto nb_slave_gauss = nb_gauss_pts / 2;
679 if (
lambdaPtr->size1() != nb_gauss_pts) {
681 "TIE multiplier values at Gauss points were not prepared "
682 "before RHS assembly");
687 "Unexpected number of TIE prism vector dofs on rows");
692 auto &row_n = row_data.getN();
693 if (!row_n.size1() || !row_n.size2())
695 if (row_n.size1() != nb_gauss_pts)
697 "Unexpected number of Gauss points on TIE displacement block");
699 const int nb_row_base = nbRows /
SPACE_DIM;
700 if (
static_cast<size_t>(nb_row_base) > row_n.size2())
702 "More TIE displacement bases than shape functions");
705 "Unexpected TIE multiplier matrix size: size2=%d expected=%d",
707 if (locF.size() !=
static_cast<size_t>(nbRows))
709 "Unexpected TIE U RHS block size: rowSide=%d rowType=%d "
710 "nbRows=%d locF.size()=%d row_n=(%d,%d) lambda=(%d,%d)",
711 rowSide, rowType, nbRows,
static_cast<int>(locF.size()),
712 static_cast<int>(row_n.size1()),
static_cast<int>(row_n.size2()),
716 auto t_w = getFTensor0IntegrationWeight();
717 for (
size_t gg = 0; gg != nb_slave_gauss; ++gg) {
719 for (
int rr = 0; rr != nb_row_base; ++rr) {
721 const double row_sign = base_on_slave ? 1.0 : -1.0;
722 const auto row_gg = base_on_slave ? gg : gg + nb_slave_gauss;
723 if (row_gg >= row_n.size1())
725 "TIE U RHS Gauss index out of range: rowSide=%d rowType=%d "
726 "rr=%d row_gg=%d row_n.size1()=%d nb_slave_gauss=%d",
727 rowSide, rowType, rr,
static_cast<int>(row_gg),
728 static_cast<int>(row_n.size1()),
729 static_cast<int>(nb_slave_gauss));
730 auto t_row_base = row_data.getFTensor0N(row_gg, rr);
731 const double row_base = t_row_base;
732 if (row_base != 0.) {
733 auto t_row_rhs = getFTensor1FromPtr<SPACE_DIM>(&locF[
SPACE_DIM * rr]);
736 row_sign * row_base * slave_alpha * (*lambdaPtr)(gg, dd);
752 FlatPrismElementForcesAndSourcesCore::UserDataOperator>::Assembly<A>::OpBase;
757 const std::string &col_field_name,
758 const bool assemble_transpose =
false)
762 this->assembleTranspose = assemble_transpose;
771 MoFEMErrorCode
iNtegrate(EntitiesFieldData::EntData &row_data,
772 EntitiesFieldData::EntData &col_data)
override {
776 dynamic_cast<const FlatPrismElementForcesAndSourcesCore *
>(ptrFE);
779 "TIE prism operator is attached to a wrong finite element");
784 "Unexpected number of TIE prism vector dofs on rows or columns: "
785 "rowField=%s colField=%s rowSide=%d colSide=%d rowType=%d colType=%d "
786 "nbRows=%d nbCols=%d",
788 rowType, colType, nbRows, nbCols);
793 const auto nb_gauss_pts = getGaussPts().size2();
794 if (!nb_gauss_pts || nb_gauss_pts % 2) {
796 "Expected concatenated [slave|master] TIE Gauss points");
798 const auto nb_slave_gauss = nb_gauss_pts / 2;
799 const int nb_row_base = nbRows /
SPACE_DIM;
800 const int nb_col_base = nbCols /
SPACE_DIM;
802 auto &col_n = col_data.getN();
803 if (!col_n.size1() || !col_n.size2())
806 auto &row_n = row_data.getN();
807 if (!row_n.size1() || !row_n.size2())
810 if (row_n.size1() != nb_gauss_pts || col_n.size1() != nb_gauss_pts)
812 "Unexpected number of Gauss points on TIE prism blocks");
814 if (
static_cast<size_t>(nb_row_base) > row_n.size2() ||
815 static_cast<size_t>(nb_col_base) > col_n.size2())
817 "More TIE prism bases than shape functions");
818 if (locMat.size1() !=
static_cast<size_t>(nbRows) ||
819 locMat.size2() !=
static_cast<size_t>(nbCols))
821 "Unexpected TIE LHS block size: rowField=%s colField=%s "
822 "rowSide=%d colSide=%d rowType=%d colType=%d nbRows=%d "
823 "nbCols=%d locMat=(%d,%d) row_n=(%d,%d) col_n=(%d,%d)",
825 rowType, colType, nbRows, nbCols,
826 static_cast<int>(locMat.size1()),
static_cast<int>(locMat.size2()),
827 static_cast<int>(row_n.size1()),
static_cast<int>(row_n.size2()),
828 static_cast<int>(col_n.size1()),
static_cast<int>(col_n.size2()));
833 auto t_w = getFTensor0IntegrationWeight();
834 for (
size_t gg = 0; gg != nb_slave_gauss; ++gg) {
836 for (
int rr = 0; rr != nb_row_base; ++rr) {
838 const double row_sign = base_on_slave ? 1.0 : -1.0;
839 const auto row_gg = base_on_slave ? gg : gg + nb_slave_gauss;
840 if (row_gg >= row_n.size1())
842 "TIE LHS Gauss index out of range: rowField=%s colField=%s "
843 "rowSide=%d rowType=%d rr=%d row_gg=%d row_n.size1()=%d "
846 rr,
static_cast<int>(row_gg),
static_cast<int>(row_n.size1()),
847 static_cast<int>(nb_slave_gauss));
848 auto t_row_base = row_data.getFTensor0N(row_gg, rr);
849 auto t_col_base = col_data.getFTensor0N(gg, 0);
850 for (
int cc = 0; cc != nb_col_base; ++cc) {
851 const double value = row_sign * slave_alpha * t_row_base * t_col_base;
870 if (!tie_data || !tie_data->hasTieConstraints || !tie_data->tieSlaveFaces ||
871 !tie_data->tieMasterFaces) {
876 auto comm_interface = mField.
getInterface<CommInterface>();
879 auto closure_with_faces = [&](
const Range &faces,
Range &closure) {
883 CHKERR moab.get_adjacencies(faces, 1,
true, edges, moab::Interface::UNION);
884 CHKERR moab.get_adjacencies(faces, 0,
true, verts, moab::Interface::UNION);
885 closure.merge(edges);
886 closure.merge(verts);
890 auto calculate_norms = [&](
const Range &ents,
double &l2_norm,
double &linf,
891 unsigned int &nb_dofs) {
895 unsigned int count = 0;
896 for (
auto ent : ents) {
898 unsigned char pstatus;
899 CHKERR moab.tag_get_data(pcomm->pstatus_tag(), &ent, 1, &pstatus);
900 if (pstatus & PSTATUS_NOT_OWNED)
905 const double value = (*dit)->getFieldData();
906 sum2 += value * value;
907 max_abs = std::max(max_abs, std::abs(value));
911 double global_sum2 = 0;
912 double global_max_abs = 0;
913 unsigned long long global_count = 0;
914 const auto local_count =
static_cast<unsigned long long>(count);
915 MPI_Allreduce(&sum2, &global_sum2, 1, MPI_DOUBLE, MPI_SUM,
917 MPI_Allreduce(&max_abs, &global_max_abs, 1, MPI_DOUBLE, MPI_MAX,
919 MPI_Allreduce(&local_count, &global_count, 1, MPI_UNSIGNED_LONG_LONG,
921 l2_norm = std::sqrt(global_sum2);
922 linf = global_max_abs;
923 nb_dofs =
static_cast<unsigned int>(global_count);
927 Range slave_closure, master_closure;
928 CHKERR closure_with_faces(*tie_data->tieSlaveFaces, slave_closure);
929 CHKERR closure_with_faces(*tie_data->tieMasterFaces, master_closure);
930 CHKERR comm_interface->synchroniseEntities(slave_closure);
931 CHKERR comm_interface->synchroniseEntities(master_closure);
933 double slave_l2 = 0, slave_linf = 0, master_l2 = 0, master_linf = 0;
934 unsigned int slave_nb_dofs = 0, master_nb_dofs = 0;
935 CHKERR calculate_norms(slave_closure, slave_l2, slave_linf, slave_nb_dofs);
936 CHKERR calculate_norms(master_closure, master_l2, master_linf, master_nb_dofs);
939 <<
"TIE solved displacement norms on slave face closure: dofs="
940 << slave_nb_dofs <<
" l2=" << slave_l2 <<
" linf=" << slave_linf;
942 <<
"TIE solved displacement norms on master face closure: dofs="
943 << master_nb_dofs <<
" l2=" << master_l2 <<
" linf=" << master_linf;
953 auto meshset_mng = mField.
getInterface<MeshsetsManager>();
954 auto comm_interface = mField.
getInterface<CommInterface>();
957 meshset_mng->getCubitMeshsetPtr(std::regex(
"^TIE_MASTER.*"));
958 auto tie_slave = meshset_mng->getCubitMeshsetPtr(std::regex(
"^TIE_SLAVE.*"));
960 const bool have_master_meshset = !tie_master.empty();
961 const bool have_slave_meshset = !tie_slave.empty();
963 if (!have_master_meshset && !have_slave_meshset) {
967 auto anyRank = [&](
const bool local_value) {
968 int global_value = 0;
969 const int local_int =
static_cast<int>(local_value);
970 MPI_Allreduce(&local_int, &global_value, 1, MPI_INT, MPI_MAX,
972 return global_value != 0;
977 "TIE prism constraints are supported only in 3D");
981 tie_data = boost::make_shared<CommonData>();
983 tie_data->tieRefLevel = 1;
984 CHKERR PetscOptionsGetInt(PETSC_NULLPTR,
"",
"-tie_ref_level",
985 &tie_data->tieRefLevel, PETSC_NULLPTR);
986 if (tie_data->tieRefLevel < 0) {
988 "-tie_ref_level has to be >= 0");
992 tie_data->dispFieldBase = base;
993 tie_data->dispFieldOrder =
order;
995 if (!have_master_meshset || !have_slave_meshset) {
997 "Both TIE_MASTER* and TIE_SLAVE* meshsets are required to "
998 "initialise TIE constraints");
1002 CHKERR mField.
get_moab().get_entities_by_type(0, MBPRISM, local_prisms,
true);
1003 Range local_prism_faces;
1004 if (!local_prisms.empty()) {
1007 moab::Interface::UNION);
1008 local_prism_faces = local_prism_faces.subset_by_type(MBTRI);
1011 auto collectTieFaces = [&](
const auto &meshsets,
1012 boost::shared_ptr<Range> &face_range) {
1014 face_range = boost::make_shared<Range>();
1015 for (
const auto &meshset_ptr : meshsets) {
1019 CHKERR mField.
get_moab().get_entities_by_type(meshset_ptr->meshset, MBTRI,
1021 tris = intersect(tris, local_prism_faces);
1022 face_range->merge(tris);
1027 CHKERR collectTieFaces(tie_master, tie_data->tieMasterFaces);
1028 CHKERR collectTieFaces(tie_slave, tie_data->tieSlaveFaces);
1030 if (tie_data->tieMasterFaces->empty() != tie_data->tieSlaveFaces->empty()) {
1032 "Local TIE_MASTER/TIE_SLAVE meshsets are inconsistent");
1035 tie_data->tiePrisms = boost::make_shared<Range>();
1036 Range master_adjacent_prisms, slave_adjacent_prisms;
1037 CHKERR mField.
get_moab().get_adjacencies(*tie_data->tieSlaveFaces, 3,
false,
1038 slave_adjacent_prisms,
1039 moab::Interface::UNION);
1040 CHKERR mField.
get_moab().get_adjacencies(*tie_data->tieMasterFaces, 3,
false,
1041 master_adjacent_prisms,
1042 moab::Interface::UNION);
1043 slave_adjacent_prisms = slave_adjacent_prisms.subset_by_type(MBPRISM);
1044 master_adjacent_prisms = master_adjacent_prisms.subset_by_type(MBPRISM);
1046 if (!tie_data->tieSlaveFaces->empty() && slave_adjacent_prisms.empty()) {
1048 "No prism elements are adjacent to TIE_SLAVE meshsets");
1051 if (slave_adjacent_prisms.size() != master_adjacent_prisms.size()) {
1053 "Different numbers of prisms are adjacent to TIE_SLAVE and "
1054 "TIE_MASTER meshsets");
1057 *tie_data->tiePrisms = slave_adjacent_prisms;
1059 const bool have_tie_prisms = anyRank(!tie_data->tiePrisms->empty());
1060 if (!have_tie_prisms) {
1062 <<
"TIE_MASTER/TIE_SLAVE meshsets found but no prism elements are adjacent to them. "
1063 <<
"TIE constraints cannot be initialised.";
1067 if (!tie_data->tiePrisms->empty()) {
1069 <<
"Initialising TIE constraints on " << tie_data->tiePrisms->size()
1070 <<
" prism elements adjacent to the TIE slave/master surfaces.";
1076 Range tie_prism_trace_faces = *tie_data->tieSlaveFaces;
1077 tie_prism_trace_faces.merge(*tie_data->tieMasterFaces);
1078 Range tie_prism_trace_edges;
1079 CHKERR mField.
get_moab().get_adjacencies(tie_prism_trace_faces, 1,
false,
1080 tie_prism_trace_edges,
1081 moab::Interface::UNION);
1082 Range tie_prism_edges;
1083 CHKERR mField.
get_moab().get_adjacencies(*tie_data->tiePrisms, 1,
false,
1085 moab::Interface::UNION);
1086 const auto tie_prism_lateral_edges =
1087 subtract(tie_prism_edges, tie_prism_trace_edges);
1102 CHKERR comm_interface->synchroniseFieldEntities(
"LAMBDA", 0);
1105 CHKERR mField.
get_moab().get_entities_by_type(0, MBVERTEX, verts,
true);
1107 CHKERR mField.
get_moab().get_entities_by_type(0, MBTRI, faces,
true);
1110 moab::Interface::UNION);
1112 CHKERR comm_interface->synchroniseEntities(edges);
1115 CHKERR comm_interface->synchroniseFieldEntities(
"U", 0);
1155 tie_data->tiePrismFeName);
1159 auto &other_fes =
simple->getOtherFiniteElements();
1160 other_fes.push_back(tie_data->tiePrismFeName);
1162 CHKERR DMMoFEMAddElement(
simple->getDM(), tie_data->tiePrismFeName);
1165 tie_data->hasTieConstraints =
true;
1173 if (!tie_data || !tie_data->hasTieConstraints) {
1177 if (!tie_data->tiePrismRhsFE) {
1178 tie_data->tiePrismRhsFE =
1179 boost::make_shared<FlatPrismElementForcesAndSourcesCore>(mField);
1180 tie_data->tiePrismRhsFE->getRuleHook = [](int, int, int) {
return -1; };
1181 tie_data->tiePrismRhsFE->setRuleHook =
1183 tie_data->tiePrismRhsFE->getOpPtrVector().push_back(
1185 "LAMBDA", tie_data->lambdaAtGaussPts, MBVERTEX));
1186 tie_data->tiePrismRhsFE->getOpPtrVector().push_back(
1188 tie_data->lambdaAtGaussPts));
1189 tie_data->tiePrismRhsFE->getOpPtrVector().push_back(
1191 tie_data->dispFieldName, tie_data->dispAtGaussPts, MBVERTEX));
1192 tie_data->tiePrismRhsFE->getOpPtrVector().push_back(
1196 if (!tie_data->tiePrismLhsFE) {
1197 tie_data->tiePrismLhsFE =
1198 boost::make_shared<FlatPrismElementForcesAndSourcesCore>(mField);
1199 tie_data->tiePrismLhsFE->getRuleHook = [](int, int, int) {
return -1; };
1200 tie_data->tiePrismLhsFE->setRuleHook =
1202 tie_data->tiePrismLhsFE->getOpPtrVector().push_back(
1203 new OpTiePrismLhs(tie_data->dispFieldName,
"LAMBDA",
true));
1210 boost::shared_ptr<CommonData> tie_data,
1211 SmartPetscObj<KSP> solver) {
1214 if (!tie_data || !tie_data->hasTieConstraints)
1220 CHKERR KSPGetDM(solver, &dm);
1221 boost::shared_ptr<FEMethod> null;
1222 CHKERR DMMoFEMKSPSetComputeOperators(dm, tie_data->tiePrismFeName,
1223 tie_data->tiePrismLhsFE, null, null);
1224 CHKERR DMMoFEMKSPSetComputeRHS(dm, tie_data->tiePrismFeName,
1225 tie_data->tiePrismRhsFE, null, null);
1231 boost::shared_ptr<CommonData> tie_data,
1232 SmartPetscObj<TS> solver) {
1235 if (!tie_data || !tie_data->hasTieConstraints)
1241 CHKERR TSGetDM(solver, &dm);
1242 boost::shared_ptr<FEMethod> null;
1243 CHKERR DMMoFEMTSSetIJacobian(dm, tie_data->tiePrismFeName,
1244 tie_data->tiePrismLhsFE, null, null);
1245 CHKERR DMMoFEMTSSetIFunction(dm, tie_data->tiePrismFeName,
1246 tie_data->tiePrismRhsFE, null, null);
1259 boost::shared_ptr<ElasticTie::CommonData>
tieData =
nullptr;
1262 MoFEMErrorCode
readMesh()
override;
1264 MoFEMErrorCode
setUpSolver(SmartPetscObj<KSP> solver)
override;
1279 enum bases { AINSWORTH, DEMKOWICZ, LASBASETOPT };
1280 const char *list_bases[LASBASETOPT] = {
"ainsworth",
"demkowicz"};
1281 PetscInt choice_base_value = AINSWORTH;
1282 CHKERR PetscOptionsGetEList(PETSC_NULLPTR, PETSC_NULLPTR,
"-base", list_bases,
1283 LASBASETOPT, &choice_base_value, PETSC_NULLPTR);
1286 switch (choice_base_value) {
1299 CHKERR PetscOptionsGetInt(PETSC_NULLPTR,
"",
"-order", &
order,
1308 if (!tet_hex_ents.empty()) {
1309 EntityHandle domain_meshset;
1312 simple->getMeshset() = domain_meshset;
1314 Range boundary_faces;
1318 CHKERR skin.find_skin(0, tet_hex_ents,
false, local_skin);
1324 CHKERR skin.find_skin(0, tet_hex_ents,
false, boundary_faces);
1326 EntityHandle boundary_meshset;
1329 simple->getBoundaryMeshSet() = boundary_meshset;
1340inline MoFEMErrorCode
1347inline MoFEMErrorCode
Implementation of elastic example class.
#define FTENSOR_INDEX(DIM, I)
void simple(double P1[], double P2[], double P3[], double c[], const int N)
FieldApproximationBase
approximation base
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define MYPCOMM_INDEX
default communicator number PCOMM
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_DATA_INCONSISTENCY
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
#define MoFEMFunctionBeginHot
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#define THROW_MESSAGE(msg)
Throw MoFEM exception.
#define _IT_GET_DOFS_FIELD_BY_NAME_AND_ENT_FOR_LOOP_(MFIELD, NAME, ENT, IT)
loop over all dofs from a moFEM field and particular field
virtual MoFEMErrorCode add_finite_element(const std::string &fe_name, enum MoFEMTypes bh=MF_EXCL, int verb=DEFAULT_VERBOSITY)=0
add finite element
virtual MoFEMErrorCode build_finite_elements(int verb=DEFAULT_VERBOSITY)=0
Build finite elements.
virtual MoFEMErrorCode modify_finite_element_add_field_col(const std::string &fe_name, const std::string name_row)=0
set field col which finite element use
virtual MoFEMErrorCode add_ents_to_finite_element_by_type(const EntityHandle entities, const EntityType type, const std::string name, const bool recursive=true)=0
add entities to finite element
virtual MoFEMErrorCode modify_finite_element_add_field_row(const std::string &fe_name, const std::string name_row)=0
set field row which finite element use
virtual MoFEMErrorCode modify_finite_element_add_field_data(const std::string &fe_name, const std::string name_field)=0
set finite element field data
virtual MoFEMErrorCode build_fields(int verb=DEFAULT_VERBOSITY)=0
virtual MoFEMErrorCode set_field_order(const EntityHandle meshset, const EntityType type, const std::string &name, const ApproximationOrder order, int verb=DEFAULT_VERBOSITY)=0
Set order approximation of the entities in the field.
virtual MoFEMErrorCode add_ents_to_field_by_type(const Range &ents, const EntityType type, const std::string &name, int verb=DEFAULT_VERBOSITY)=0
Add entities to field meshset.
virtual bool check_field(const std::string &name) const =0
check if field is in database
#define MOFEM_LOG(channel, severity)
Log.
FTensor::Index< 'i', SPACE_DIM > i
bool isInsideReferenceTriangle(const double xi, const double eta, const double tol=1e-8)
constexpr int MASTER_FACE_SIDE
MoFEMErrorCode loadTieMesh(MoFEM::Interface &mField, Range &physicalBoundaryFaces)
Load a mesh while preserving the shared entities needed by TIE constraints.
Range getPhysicalVolumeEntities(const Range &ents)
bool isOnPrismTieTrace(const int side, const EntityType type)
bool isOnSlaveTieRowBase(const int rr, const int row_side, const EntityType row_type)
MoFEMErrorCode initializeTieConstraints(MoFEM::Interface &mField, boost::shared_ptr< CommonData > &tie_data, const std::string &field_name, FieldApproximationBase base, int order)
bool isOnPrismTriFace(const int side, const EntityType type, const int prism_face_side)
MoFEMErrorCode getPrismTriangleFaces(moab::Interface &moab, const Range &ents, Range &triangle_faces)
MoFEMErrorCode setupTieConstraintOperators(MoFEM::Interface &mField, boost::shared_ptr< CommonData > tie_data)
constexpr int SLAVE_FACE_SIDE
MoFEMErrorCode logTieDisplacementNorms(MoFEM::Interface &mField, const boost::shared_ptr< CommonData > &tie_data, const std::string &field_name)
MoFEMErrorCode makeClosureMeshset(moab::Interface &moab, const Range &ents, const int max_dim, EntityHandle &meshset)
MoFEMErrorCode setupTieSolver(MoFEM::Interface &mField, boost::shared_ptr< CommonData > tie_data, SmartPetscObj< KSP > solver)
constexpr auto field_name
#define QUAD_2D_TABLE_SIZE
static QUAD *const QUAD_2D_TABLE[]
virtual MoFEMErrorCode setupProblem()
[Read mesh]
virtual MoFEMErrorCode kspSetUpAndSolve(SmartPetscObj< KSP > solver)
MoFEM::Interface & mField
ElasticExample(MoFEM::Interface &m_field)
ElasticExample extension providing reusable TIE mesh behaviour.
MoFEMErrorCode readMesh() override
[Run problem]
MoFEMErrorCode setupProblem() override
[Read mesh]
boost::shared_ptr< ElasticTie::CommonData > tieData
MoFEMErrorCode checkResults() override
[Postprocess results]
MoFEMErrorCode setUpSolver(SmartPetscObj< KSP > solver) override
[Push operators to pipeline]
Range physicalBoundaryFaces
MoFEMErrorCode kspSetUpAndSolve(SmartPetscObj< KSP > solver) override
boost::shared_ptr< MatrixDouble > dispAtGaussPts
boost::shared_ptr< Range > tiePrisms
boost::shared_ptr< Range > tieSlaveFaces
boost::shared_ptr< FlatPrismElementForcesAndSourcesCore > tiePrismLhsFE
std::string tiePrismFeName
boost::shared_ptr< MatrixDouble > lambdaAtGaussPts
FieldApproximationBase dispFieldBase
std::string dispFieldName
boost::shared_ptr< FlatPrismElementForcesAndSourcesCore > tiePrismRhsFE
boost::shared_ptr< Range > tieMasterFaces
OpCalculateVectorFieldValues_General< Tensor_Dim, MatrixDouble > Base
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data) override
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data, EntitiesFieldData::EntData &col_data) override
OpTiePrismLhs(const std::string &row_field_name, const std::string &col_field_name, const bool assemble_transpose=false)
double getSlaveFaceArea()
double getSlaveFaceArea()
OpTiePrismRhsU(const std::string &field_name, boost::shared_ptr< MatrixDouble > lambda_ptr)
boost::shared_ptr< MatrixDouble > lambdaPtr
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data) override
OpTiePrismRhs(boost::shared_ptr< MatrixDouble > disp_ptr)
double getSlaveFaceArea()
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data) override
boost::shared_ptr< MatrixDouble > dispPtr
static MoFEMErrorCode setBaseQuadrature(FlatPrismElementForcesAndSourcesCore &fe, const int rule)
SetIntegrationOnTiePrismFaces(int tie_ref_level=1)
static MoFEMErrorCode projectSlavePointsToMasterPlane(const double *master_coords, const MatrixDouble &slave_global_coords, MatrixDouble &master_global_coords)
static std::map< std::pair< int, int >, MatrixDouble > mapRefCoords
static MoFEMErrorCode refineQuadrature(FlatPrismElementForcesAndSourcesCore &fe, const int refinement_levels, MatrixDouble &ref_gauss_pts)
boost::function< int(int)> FunRule
SetIntegrationOnTiePrismFaces(FunRule fun_rule, int tie_ref_level=1)
static MoFEMErrorCode projectPointToMasterPlane(const double *master_coords, const double *point, double *projected_point)
SetIntegrationOnTiePrismFaces()=delete
MoFEMErrorCode operator()(ForcesAndSourcesCore *fe_raw_ptr, int order_row, int order_col, int order_data)
virtual int get_comm_size() const =0
virtual moab::Interface & get_moab()=0
virtual bool check_finite_element(const std::string &name) const =0
Check if finite element is in database.
virtual MoFEMErrorCode add_field(const std::string name, const FieldSpace space, const FieldApproximationBase base, const FieldCoefficientsNumber nb_of_coefficients, const TagType tag_type=MB_TAG_SPARSE, const enum MoFEMTypes bh=MF_EXCL, int verb=DEFAULT_VERBOSITY)=0
Add field.
virtual MPI_Comm & get_comm() const =0
Deprecated interface functions.
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.