10#ifndef __ELASTIC_TIE_HPP__
11#define __ELASTIC_TIE_HPP__
35 boost::make_shared<MatrixDouble>();
37 boost::make_shared<MatrixDouble>();
46 const double tol = 1e-8) {
51 const int prism_face_side) {
55 : (side >= 3 && side < 6);
58 : (side >= 6 && side < 9);
60 return side == prism_face_side;
72 const EntityType row_type) {
77 return row_side >= 0 && row_side < 3;
87 using FunRule = boost::function<int(
int)>;
100 int order_col,
int order_data) {
103 auto fe_ptr =
static_cast<FlatPrismElementForcesAndSourcesCore *
>(fe_raw_ptr);
104 const int rule =
funRule(std::max(order_data, std::max(order_row, order_col)));
108 "-tie_ref_level has to be >= 0");
113 "Triangle quadrature rule %d is not available for TIE prism face "
120 "Expected 2D quadrature for TIE prism face integration");
125 "Wrong quadrature order %d < %d for TIE prism face integration",
132 const auto cache_key = std::make_pair(rule,
tieRefLevel);
135 MatrixDouble ref_gauss_pts;
140 fe_ptr->gaussPts = it->second;
143 const MatrixDouble slave_gauss_pts = fe_ptr->gaussPts;
144 const auto nb_gauss_pts = slave_gauss_pts.size2();
146 auto &moab = fe_ptr->mField.get_moab();
147 auto get_prism_face_coords = [&](
const int side, std::array<double, 9> &coords) {
151 int num_prism_nodes = 0;
152 CHKERR moab.get_connectivity(prism, prism_conn, num_prism_nodes,
true);
153 if (num_prism_nodes != 6) {
155 "TIE prism is expected to have 6 nodes");
158 std::array<EntityHandle, 3> face_conn;
161 face_conn = {prism_conn[0], prism_conn[1], prism_conn[2]};
164 face_conn = {prism_conn[3], prism_conn[4], prism_conn[5]};
168 "Unsupported TIE prism triangle side %d", side);
171 CHKERR moab.get_coords(face_conn.data(), 3, coords.data());
175 std::array<double, 9> slave_coords;
176 std::array<double, 9> master_coords;
180 MatrixDouble slave_global_coords(nb_gauss_pts, 3,
false);
181 MatrixDouble master_global_coords(nb_gauss_pts, 3,
false);
182 MatrixDouble slave_shape(nb_gauss_pts, 3,
false);
184 &slave_gauss_pts(1, 0), nb_gauss_pts);
185 for (
size_t gg = 0; gg != nb_gauss_pts; ++gg) {
186 for (
int dd = 0; dd != 3; ++dd) {
187 slave_global_coords(gg, dd) =
188 slave_shape(gg, 0) * slave_coords[0 + dd] +
189 slave_shape(gg, 1) * slave_coords[3 + dd] +
190 slave_shape(gg, 2) * slave_coords[6 + dd];
196 master_global_coords);
198 MatrixDouble master_local_coords(nb_gauss_pts, 2,
false);
199 CHKERR Tools::getLocalCoordinatesOnReferenceThreeNodeTri(
200 master_coords.data(), &master_global_coords(0, 0),
201 master_global_coords.size1(), &master_local_coords(0, 0));
203 MatrixDouble combined_gauss_pts(3, 2 * nb_gauss_pts,
false);
204 for (
size_t gg = 0; gg != nb_gauss_pts; ++gg) {
205 const bool valid_master_point =
207 master_local_coords(gg, 1));
208 const double paired_weight = valid_master_point ? slave_gauss_pts(2, gg) : 0.;
210 combined_gauss_pts(0, gg) = slave_gauss_pts(0, gg);
211 combined_gauss_pts(1, gg) = slave_gauss_pts(1, gg);
212 combined_gauss_pts(2, gg) = paired_weight;
214 combined_gauss_pts(0, gg + nb_gauss_pts) = master_local_coords(gg, 0);
215 combined_gauss_pts(1, gg + nb_gauss_pts) = master_local_coords(gg, 1);
216 combined_gauss_pts(2, gg + nb_gauss_pts) = paired_weight;
218 fe_ptr->gaussPts.swap(combined_gauss_pts);
225 FlatPrismElementForcesAndSourcesCore &fe,
const int rule) {
228 fe.gaussPts.resize(3, nb_gauss_pts,
false);
229 cblas_dcopy(nb_gauss_pts, &
QUAD_2D_TABLE[rule]->points[1], 3,
230 &fe.gaussPts(0, 0), 1);
231 cblas_dcopy(nb_gauss_pts, &
QUAD_2D_TABLE[rule]->points[2], 3,
232 &fe.gaussPts(1, 0), 1);
234 &fe.gaussPts(2, 0), 1);
240 double *projected_point) {
245 const double ax = master_coords[0];
246 const double ay = master_coords[1];
247 const double az = master_coords[2];
248 const double bx = master_coords[3];
249 const double by = master_coords[4];
250 const double bz = master_coords[5];
251 const double cx = master_coords[6];
252 const double cy = master_coords[7];
253 const double cz = master_coords[8];
255 const double abx = bx - ax;
256 const double aby = by - ay;
257 const double abz = bz - az;
258 const double acx = cx - ax;
259 const double acy = cy - ay;
260 const double acz = cz - az;
262 const double nx = aby * acz - abz * acy;
263 const double ny = abz * acx - abx * acz;
264 const double nz = abx * acy - aby * acx;
265 const double n_norm_sq = nx * nx + ny * ny + nz * nz;
266 if (n_norm_sq <= std::numeric_limits<double>::epsilon()) {
268 "Degenerated master triangle plane");
271 const double px = point[0] - ax;
272 const double py = point[1] - ay;
273 const double pz = point[2] - az;
274 const double signed_distance = (px * nx + py * ny + pz * nz) / n_norm_sq;
275 projected_point[0] = point[0] - signed_distance * nx;
276 projected_point[1] = point[1] - signed_distance * ny;
277 projected_point[2] = point[2] - signed_distance * nz;
283 const double *master_coords,
const MatrixDouble &slave_global_coords,
284 MatrixDouble &master_global_coords) {
290 master_global_coords.resize(slave_global_coords.size1(), 3,
false);
291 for (
size_t gg = 0; gg != slave_global_coords.size1(); ++gg) {
293 &slave_global_coords(gg, 0),
294 &master_global_coords(gg, 0));
301 FlatPrismElementForcesAndSourcesCore &fe,
const int refinement_levels,
302 MatrixDouble &ref_gauss_pts) {
305 constexpr int num_nodes = 3;
307 double base_coords[] = {0, 0, 0, 1, 0, 0, 0, 1, 0};
309 for (
int nn = 0; nn != num_nodes; ++nn)
310 CHKERR moab_ref.create_vertex(&base_coords[3 * nn], nodes[nn]);
313 CHKERR moab_ref.create_element(MBTRI, nodes, num_nodes, tri);
318 Range tris(tri, tri);
325 tris, 1,
true, edges, moab::Interface::UNION);
326 for (
auto edge : edges) {
327 int side_number = -1, sense = 0, offset = 0;
328 CHKERR moab_ref.side_number(tri, edge, side_number, sense, offset);
331 tris, BitRefLevel().set(0),
false,
VERBOSE);
334 auto *m_ref = m_field_ref.
getInterface<MeshRefinement>();
335 for (
int ll = 0; ll != refinement_levels; ++ll) {
338 ->getEntitiesByTypeAndRefLevel(BitRefLevel().set(ll),
339 BitRefLevel().set(), MBTRI, tris);
342 CHKERR moab_ref.get_adjacencies(tris, 1,
true, edges,
343 moab::Interface::UNION);
345 const BitRefLevel child_bit = BitRefLevel().set(ll + 1);
346 CHKERR m_ref->addVerticesInTheMiddleOfEdges(edges, child_bit);
347 CHKERR m_ref->refineTris(tris, child_bit,
QUIET,
false);
352 BitRefLevel().set(refinement_levels), BitRefLevel().set(), MBTRI, tris);
354 MatrixDouble ref_coords(tris.size(), 9,
false);
356 for (
auto tit = tris.begin(); tit != tris.end(); ++tit, ++tt) {
359 CHKERR moab_ref.get_connectivity(*tit, conn, num_conn,
false);
360 CHKERR moab_ref.get_coords(conn, num_conn, &ref_coords(tt, 0));
363 const size_t nb_gauss_pts = fe.gaussPts.size2();
364 MatrixDouble shape_n(nb_gauss_pts, 3,
false);
367 ref_gauss_pts.resize(3, nb_gauss_pts * ref_coords.size1(),
false);
369 for (
size_t rr = 0; rr != ref_coords.size1(); ++rr) {
370 double *tri_coords = &ref_coords(rr, 0);
372 CHKERR Tools::getTriNormal(tri_coords, &t_normal(0));
373 const double det = t_normal.
l2();
374 for (
size_t ggg = 0; ggg != nb_gauss_pts; ++ggg, ++gg) {
375 for (
int dd = 0; dd != 2; ++dd) {
376 ref_gauss_pts(dd, gg) =
377 shape_n(ggg, 0) * tri_coords[3 * 0 + dd] +
378 shape_n(ggg, 1) * tri_coords[3 * 1 + dd] +
379 shape_n(ggg, 2) * tri_coords[3 * 2 + dd];
381 ref_gauss_pts(2, gg) = fe.gaussPts(2, ggg) * det;
388 static inline std::map<std::pair<int, int>, MatrixDouble>
mapRefCoords;
391template <
int Tensor_Dim>
393 :
public OpCalculateVectorFieldValues_General<Tensor_Dim, MatrixDouble> {
395 using Base = OpCalculateVectorFieldValues_General<Tensor_Dim, MatrixDouble>;
399 EntitiesFieldData::EntData &data)
override {
409 FlatPrismElementForcesAndSourcesCore::UserDataOperator>::Assembly<A>::OpBase;
423 MoFEMErrorCode
iNtegrate(EntitiesFieldData::EntData &row_data)
override {
427 dynamic_cast<const FlatPrismElementForcesAndSourcesCore *
>(ptrFE);
430 "TIE prism RHS operator is attached to a wrong finite element");
432 const auto nb_gauss_pts = getGaussPts().size2();
433 if (!nb_gauss_pts || nb_gauss_pts % 2) {
435 "Expected concatenated [slave|master] TIE Gauss points");
437 const auto nb_slave_gauss = nb_gauss_pts / 2;
438 if (
dispPtr->size1() != nb_gauss_pts) {
440 "TIE displacement values at Gauss points were not prepared "
441 "before RHS assembly");
446 "Unexpected number of LAMBDA dofs on TIE prism rows");
448 auto &row_n = row_data.getN();
449 if (!row_n.size1() || !row_n.size2())
451 if (row_n.size1() != nb_gauss_pts)
453 "Unexpected number of Gauss points on TIE multiplier block");
455 const int nb_row_base = nbRows /
SPACE_DIM;
456 if (
static_cast<size_t>(nb_row_base) > row_n.size2())
458 "More TIE multiplier bases than shape functions");
461 "Unexpected TIE displacement matrix size: size2=%d expected=%d",
463 if (locF.size() !=
static_cast<size_t>(nbRows))
465 "Unexpected TIE RHS block size: rowSide=%d rowType=%d nbRows=%d "
466 "locF.size()=%d row_n=(%d,%d) disp=(%d,%d)",
467 rowSide, rowType, nbRows,
static_cast<int>(locF.size()),
468 static_cast<int>(row_n.size1()),
static_cast<int>(row_n.size2()),
469 static_cast<int>(
dispPtr->size1()),
470 static_cast<int>(
dispPtr->size2()));
472 auto t_w = getFTensor0IntegrationWeight();
473 for (
size_t gg = 0; gg != nb_slave_gauss; ++gg) {
475 auto t_row_base = row_data.getFTensor0N(gg, 0);
476 for (
int rr = 0; rr != nb_row_base; ++rr) {
477 const double row_base = t_row_base;
478 if (row_base != 0.) {
479 auto t_row_rhs = getFTensor1FromPtr<SPACE_DIM>(&locF[
SPACE_DIM * rr]);
480 for (
int dd = 0; dd !=
SPACE_DIM; ++dd) {
481 t_row_rhs(dd) += row_base * slave_alpha *
482 ((*dispPtr)(gg, dd) -
483 (*
dispPtr)(gg + nb_slave_gauss, dd));
502 boost::shared_ptr<MatrixDouble> lambda_ptr)
512 MoFEMErrorCode
iNtegrate(EntitiesFieldData::EntData &row_data)
override {
516 dynamic_cast<const FlatPrismElementForcesAndSourcesCore *
>(ptrFE);
519 "TIE prism RHS operator is attached to a wrong finite element");
521 const auto nb_gauss_pts = getGaussPts().size2();
522 if (!nb_gauss_pts || nb_gauss_pts % 2) {
524 "Expected concatenated [slave|master] TIE Gauss points");
526 const auto nb_slave_gauss = nb_gauss_pts / 2;
527 if (
lambdaPtr->size1() != nb_gauss_pts) {
529 "TIE multiplier values at Gauss points were not prepared "
530 "before RHS assembly");
535 "Unexpected number of TIE prism vector dofs on rows");
540 auto &row_n = row_data.getN();
541 if (!row_n.size1() || !row_n.size2())
543 if (row_n.size1() != nb_gauss_pts)
545 "Unexpected number of Gauss points on TIE displacement block");
547 const int nb_row_base = nbRows /
SPACE_DIM;
548 if (
static_cast<size_t>(nb_row_base) > row_n.size2())
550 "More TIE displacement bases than shape functions");
553 "Unexpected TIE multiplier matrix size: size2=%d expected=%d",
555 if (locF.size() !=
static_cast<size_t>(nbRows))
557 "Unexpected TIE U RHS block size: rowSide=%d rowType=%d "
558 "nbRows=%d locF.size()=%d row_n=(%d,%d) lambda=(%d,%d)",
559 rowSide, rowType, nbRows,
static_cast<int>(locF.size()),
560 static_cast<int>(row_n.size1()),
static_cast<int>(row_n.size2()),
564 auto t_w = getFTensor0IntegrationWeight();
565 for (
size_t gg = 0; gg != nb_slave_gauss; ++gg) {
567 for (
int rr = 0; rr != nb_row_base; ++rr) {
569 const double row_sign = base_on_slave ? 1.0 : -1.0;
570 const auto row_gg = base_on_slave ? gg : gg + nb_slave_gauss;
571 if (row_gg >= row_n.size1())
573 "TIE U RHS Gauss index out of range: rowSide=%d rowType=%d "
574 "rr=%d row_gg=%d row_n.size1()=%d nb_slave_gauss=%d",
575 rowSide, rowType, rr,
static_cast<int>(row_gg),
576 static_cast<int>(row_n.size1()),
577 static_cast<int>(nb_slave_gauss));
578 auto t_row_base = row_data.getFTensor0N(row_gg, rr);
579 const double row_base = t_row_base;
580 if (row_base != 0.) {
581 auto t_row_rhs = getFTensor1FromPtr<SPACE_DIM>(&locF[
SPACE_DIM * rr]);
584 row_sign * row_base * slave_alpha * (*lambdaPtr)(gg, dd);
600 FlatPrismElementForcesAndSourcesCore::UserDataOperator>::Assembly<A>::OpBase;
605 const std::string &col_field_name,
606 const bool assemble_transpose =
false)
610 this->assembleTranspose = assemble_transpose;
619 MoFEMErrorCode
iNtegrate(EntitiesFieldData::EntData &row_data,
620 EntitiesFieldData::EntData &col_data)
override {
624 dynamic_cast<const FlatPrismElementForcesAndSourcesCore *
>(ptrFE);
627 "TIE prism operator is attached to a wrong finite element");
632 "Unexpected number of TIE prism vector dofs on rows or columns: "
633 "rowField=%s colField=%s rowSide=%d colSide=%d rowType=%d colType=%d "
634 "nbRows=%d nbCols=%d",
636 rowType, colType, nbRows, nbCols);
641 const auto nb_gauss_pts = getGaussPts().size2();
642 if (!nb_gauss_pts || nb_gauss_pts % 2) {
644 "Expected concatenated [slave|master] TIE Gauss points");
646 const auto nb_slave_gauss = nb_gauss_pts / 2;
647 const int nb_row_base = nbRows /
SPACE_DIM;
648 const int nb_col_base = nbCols /
SPACE_DIM;
650 auto &col_n = col_data.getN();
651 if (!col_n.size1() || !col_n.size2())
654 auto &row_n = row_data.getN();
655 if (!row_n.size1() || !row_n.size2())
658 if (row_n.size1() != nb_gauss_pts || col_n.size1() != nb_gauss_pts)
660 "Unexpected number of Gauss points on TIE prism blocks");
662 if (
static_cast<size_t>(nb_row_base) > row_n.size2() ||
663 static_cast<size_t>(nb_col_base) > col_n.size2())
665 "More TIE prism bases than shape functions");
666 if (locMat.size1() !=
static_cast<size_t>(nbRows) ||
667 locMat.size2() !=
static_cast<size_t>(nbCols))
669 "Unexpected TIE LHS block size: rowField=%s colField=%s "
670 "rowSide=%d colSide=%d rowType=%d colType=%d nbRows=%d "
671 "nbCols=%d locMat=(%d,%d) row_n=(%d,%d) col_n=(%d,%d)",
673 rowType, colType, nbRows, nbCols,
674 static_cast<int>(locMat.size1()),
static_cast<int>(locMat.size2()),
675 static_cast<int>(row_n.size1()),
static_cast<int>(row_n.size2()),
676 static_cast<int>(col_n.size1()),
static_cast<int>(col_n.size2()));
681 auto t_w = getFTensor0IntegrationWeight();
682 for (
size_t gg = 0; gg != nb_slave_gauss; ++gg) {
684 for (
int rr = 0; rr != nb_row_base; ++rr) {
686 const double row_sign = base_on_slave ? 1.0 : -1.0;
687 const auto row_gg = base_on_slave ? gg : gg + nb_slave_gauss;
688 if (row_gg >= row_n.size1())
690 "TIE LHS Gauss index out of range: rowField=%s colField=%s "
691 "rowSide=%d rowType=%d rr=%d row_gg=%d row_n.size1()=%d "
694 rr,
static_cast<int>(row_gg),
static_cast<int>(row_n.size1()),
695 static_cast<int>(nb_slave_gauss));
696 auto t_row_base = row_data.getFTensor0N(row_gg, rr);
697 auto t_col_base = col_data.getFTensor0N(gg, 0);
698 for (
int cc = 0; cc != nb_col_base; ++cc) {
699 const double value = row_sign * slave_alpha * t_row_base * t_col_base;
718 if (!tie_data || !tie_data->hasTieConstraints || !tie_data->tieSlaveFaces ||
719 !tie_data->tieMasterFaces) {
724 auto comm_interface = mField.
getInterface<CommInterface>();
727 auto closure_with_faces = [&](
const Range &faces,
Range &closure) {
731 CHKERR moab.get_adjacencies(faces, 1,
true, edges, moab::Interface::UNION);
732 CHKERR moab.get_adjacencies(faces, 0,
true, verts, moab::Interface::UNION);
733 closure.merge(edges);
734 closure.merge(verts);
738 auto calculate_norms = [&](
const Range &ents,
double &l2_norm,
double &linf,
739 unsigned int &nb_dofs) {
743 unsigned int count = 0;
744 for (
auto ent : ents) {
746 unsigned char pstatus;
747 CHKERR moab.tag_get_data(pcomm->pstatus_tag(), &ent, 1, &pstatus);
748 if (pstatus & PSTATUS_NOT_OWNED)
753 const double value = (*dit)->getFieldData();
754 sum2 += value * value;
755 max_abs = std::max(max_abs, std::abs(value));
759 double global_sum2 = 0;
760 double global_max_abs = 0;
761 unsigned long long global_count = 0;
762 const auto local_count =
static_cast<unsigned long long>(count);
763 MPI_Allreduce(&sum2, &global_sum2, 1, MPI_DOUBLE, MPI_SUM,
765 MPI_Allreduce(&max_abs, &global_max_abs, 1, MPI_DOUBLE, MPI_MAX,
767 MPI_Allreduce(&local_count, &global_count, 1, MPI_UNSIGNED_LONG_LONG,
769 l2_norm = std::sqrt(global_sum2);
770 linf = global_max_abs;
771 nb_dofs =
static_cast<unsigned int>(global_count);
775 Range slave_closure, master_closure;
776 CHKERR closure_with_faces(*tie_data->tieSlaveFaces, slave_closure);
777 CHKERR closure_with_faces(*tie_data->tieMasterFaces, master_closure);
778 CHKERR comm_interface->synchroniseEntities(slave_closure);
779 CHKERR comm_interface->synchroniseEntities(master_closure);
781 double slave_l2 = 0, slave_linf = 0, master_l2 = 0, master_linf = 0;
782 unsigned int slave_nb_dofs = 0, master_nb_dofs = 0;
783 CHKERR calculate_norms(slave_closure, slave_l2, slave_linf, slave_nb_dofs);
784 CHKERR calculate_norms(master_closure, master_l2, master_linf, master_nb_dofs);
787 <<
"TIE solved displacement norms on slave face closure: dofs="
788 << slave_nb_dofs <<
" l2=" << slave_l2 <<
" linf=" << slave_linf;
790 <<
"TIE solved displacement norms on master face closure: dofs="
791 << master_nb_dofs <<
" l2=" << master_l2 <<
" linf=" << master_linf;
801 auto meshset_mng = mField.
getInterface<MeshsetsManager>();
802 auto comm_interface = mField.
getInterface<CommInterface>();
805 meshset_mng->getCubitMeshsetPtr(std::regex(
"^TIE_MASTER.*"));
806 auto tie_slave = meshset_mng->getCubitMeshsetPtr(std::regex(
"^TIE_SLAVE.*"));
808 const bool have_master_meshset = !tie_master.empty();
809 const bool have_slave_meshset = !tie_slave.empty();
811 if (!have_master_meshset && !have_slave_meshset) {
815 auto anyRank = [&](
const bool local_value) {
816 int global_value = 0;
817 const int local_int =
static_cast<int>(local_value);
818 MPI_Allreduce(&local_int, &global_value, 1, MPI_INT, MPI_MAX,
820 return global_value != 0;
825 "TIE prism constraints are supported only in 3D");
829 tie_data = boost::make_shared<CommonData>();
831 tie_data->tieRefLevel = 1;
832 CHKERR PetscOptionsGetInt(PETSC_NULLPTR,
"",
"-tie_ref_level",
833 &tie_data->tieRefLevel, PETSC_NULLPTR);
834 if (tie_data->tieRefLevel < 0) {
836 "-tie_ref_level has to be >= 0");
840 tie_data->dispFieldBase = base;
841 tie_data->dispFieldOrder =
order;
843 if (!have_master_meshset || !have_slave_meshset) {
845 "Both TIE_MASTER* and TIE_SLAVE* meshsets are required to "
846 "initialise TIE constraints");
850 CHKERR mField.
get_moab().get_entities_by_type(0, MBPRISM, local_prisms,
true);
851 Range local_prism_faces;
852 if (!local_prisms.empty()) {
855 moab::Interface::UNION);
856 local_prism_faces = local_prism_faces.subset_by_type(MBTRI);
859 auto collectTieFaces = [&](
const auto &meshsets,
860 boost::shared_ptr<Range> &face_range) {
862 face_range = boost::make_shared<Range>();
863 for (
const auto &meshset_ptr : meshsets) {
867 CHKERR mField.
get_moab().get_entities_by_type(meshset_ptr->meshset, MBTRI,
869 tris = intersect(tris, local_prism_faces);
870 face_range->merge(tris);
875 CHKERR collectTieFaces(tie_master, tie_data->tieMasterFaces);
876 CHKERR collectTieFaces(tie_slave, tie_data->tieSlaveFaces);
878 if (tie_data->tieMasterFaces->empty() != tie_data->tieSlaveFaces->empty()) {
880 "Local TIE_MASTER/TIE_SLAVE meshsets are inconsistent");
883 tie_data->tiePrisms = boost::make_shared<Range>();
884 Range master_adjacent_prisms, slave_adjacent_prisms;
885 CHKERR mField.
get_moab().get_adjacencies(*tie_data->tieSlaveFaces, 3,
false,
886 slave_adjacent_prisms,
887 moab::Interface::UNION);
888 CHKERR mField.
get_moab().get_adjacencies(*tie_data->tieMasterFaces, 3,
false,
889 master_adjacent_prisms,
890 moab::Interface::UNION);
891 slave_adjacent_prisms = slave_adjacent_prisms.subset_by_type(MBPRISM);
892 master_adjacent_prisms = master_adjacent_prisms.subset_by_type(MBPRISM);
894 if (!tie_data->tieSlaveFaces->empty() && slave_adjacent_prisms.empty()) {
896 "No prism elements are adjacent to TIE_SLAVE meshsets");
899 if (slave_adjacent_prisms.size() != master_adjacent_prisms.size()) {
901 "Different numbers of prisms are adjacent to TIE_SLAVE and "
902 "TIE_MASTER meshsets");
905 *tie_data->tiePrisms = slave_adjacent_prisms;
907 const bool have_tie_prisms = anyRank(!tie_data->tiePrisms->empty());
908 if (!have_tie_prisms) {
910 <<
"TIE_MASTER/TIE_SLAVE meshsets found but no prism elements are adjacent to them. "
911 <<
"TIE constraints cannot be initialised.";
915 if (!tie_data->tiePrisms->empty()) {
917 <<
"Initialising TIE constraints on " << tie_data->tiePrisms->size()
918 <<
" prism elements adjacent to the TIE slave/master surfaces.";
924 Range tie_prism_trace_faces = *tie_data->tieSlaveFaces;
925 tie_prism_trace_faces.merge(*tie_data->tieMasterFaces);
926 Range tie_prism_trace_edges;
927 CHKERR mField.
get_moab().get_adjacencies(tie_prism_trace_faces, 1,
false,
928 tie_prism_trace_edges,
929 moab::Interface::UNION);
930 Range tie_prism_edges;
931 CHKERR mField.
get_moab().get_adjacencies(*tie_data->tiePrisms, 1,
false,
933 moab::Interface::UNION);
934 const auto tie_prism_lateral_edges =
935 subtract(tie_prism_edges, tie_prism_trace_edges);
950 CHKERR comm_interface->synchroniseFieldEntities(
"LAMBDA", 0);
953 CHKERR mField.
get_moab().get_entities_by_type(0, MBVERTEX, verts,
true);
955 CHKERR mField.
get_moab().get_entities_by_type(0, MBTRI, faces,
true);
958 moab::Interface::UNION);
960 CHKERR comm_interface->synchroniseEntities(edges);
963 CHKERR comm_interface->synchroniseFieldEntities(
"U", 0);
1003 tie_data->tiePrismFeName);
1007 auto &other_fes =
simple->getOtherFiniteElements();
1008 other_fes.push_back(tie_data->tiePrismFeName);
1010 CHKERR DMMoFEMAddElement(
simple->getDM(), tie_data->tiePrismFeName);
1013 tie_data->hasTieConstraints =
true;
1021 if (!tie_data || !tie_data->hasTieConstraints) {
1025 if (!tie_data->tiePrismRhsFE) {
1026 tie_data->tiePrismRhsFE =
1027 boost::make_shared<FlatPrismElementForcesAndSourcesCore>(mField);
1028 tie_data->tiePrismRhsFE->getRuleHook = [](int, int, int) {
return -1; };
1029 tie_data->tiePrismRhsFE->setRuleHook =
1031 tie_data->tiePrismRhsFE->getOpPtrVector().push_back(
1033 "LAMBDA", tie_data->lambdaAtGaussPts, MBVERTEX));
1034 tie_data->tiePrismRhsFE->getOpPtrVector().push_back(
1036 tie_data->lambdaAtGaussPts));
1037 tie_data->tiePrismRhsFE->getOpPtrVector().push_back(
1039 tie_data->dispFieldName, tie_data->dispAtGaussPts, MBVERTEX));
1040 tie_data->tiePrismRhsFE->getOpPtrVector().push_back(
1044 if (!tie_data->tiePrismLhsFE) {
1045 tie_data->tiePrismLhsFE =
1046 boost::make_shared<FlatPrismElementForcesAndSourcesCore>(mField);
1047 tie_data->tiePrismLhsFE->getRuleHook = [](int, int, int) {
return -1; };
1048 tie_data->tiePrismLhsFE->setRuleHook =
1050 tie_data->tiePrismLhsFE->getOpPtrVector().push_back(
1051 new OpTiePrismLhs(tie_data->dispFieldName,
"LAMBDA",
true));
1058 boost::shared_ptr<CommonData> tie_data,
1059 SmartPetscObj<KSP> solver) {
1062 if (!tie_data || !tie_data->hasTieConstraints)
1068 CHKERR KSPGetDM(solver, &dm);
1069 boost::shared_ptr<FEMethod> null;
1070 CHKERR DMMoFEMKSPSetComputeOperators(dm, tie_data->tiePrismFeName,
1071 tie_data->tiePrismLhsFE, null, null);
1072 CHKERR DMMoFEMKSPSetComputeRHS(dm, tie_data->tiePrismFeName,
1073 tie_data->tiePrismRhsFE, null, null);
1079 boost::shared_ptr<CommonData> tie_data,
1080 SmartPetscObj<TS> solver) {
1083 if (!tie_data || !tie_data->hasTieConstraints)
1089 CHKERR TSGetDM(solver, &dm);
1090 boost::shared_ptr<FEMethod> null;
1091 CHKERR DMMoFEMTSSetIJacobian(dm, tie_data->tiePrismFeName,
1092 tie_data->tiePrismLhsFE, null, null);
1093 CHKERR DMMoFEMTSSetIFunction(dm, tie_data->tiePrismFeName,
1094 tie_data->tiePrismRhsFE, null, null);
#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
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 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 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[]
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 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.