v0.16.0
Loading...
Searching...
No Matches
ElasticTie.hpp
Go to the documentation of this file.
1/**
2 * @file ElasticTie.hpp
3 *
4 * @brief TIE constraint support for the elastic tutorial
5 *
6 * @copyright Copyright (c) 2025
7 *
8 */
9
10#ifndef __ELASTIC_TIE_HPP__
11#define __ELASTIC_TIE_HPP__
12
13#include <regex>
14#include <quad.h>
15
16namespace ElasticTie {
17
19
20// we know this because we created the prisms in insert_constraint_prisms.cpp
21constexpr int SLAVE_FACE_SIDE = 3;
22constexpr int MASTER_FACE_SIDE = 4;
23
24struct CommonData {
25 bool hasTieConstraints = false;
26 std::string tiePrismFeName = "TIE_PRISM_FE";
27 std::string dispFieldName = "U";
30 int tieRefLevel = 1;
31 boost::shared_ptr<Range> tieMasterFaces = nullptr;
32 boost::shared_ptr<Range> tieSlaveFaces = nullptr;
33 boost::shared_ptr<Range> tiePrisms = nullptr;
34 boost::shared_ptr<MatrixDouble> dispAtGaussPts =
35 boost::make_shared<MatrixDouble>();
36 boost::shared_ptr<MatrixDouble> lambdaAtGaussPts =
37 boost::make_shared<MatrixDouble>();
38 boost::shared_ptr<FlatPrismElementForcesAndSourcesCore> tiePrismRhsFE =
39 nullptr;
40 boost::shared_ptr<FlatPrismElementForcesAndSourcesCore> tiePrismLhsFE =
41 nullptr;
42};
43
44
45inline bool isInsideReferenceTriangle(const double xi, const double eta,
46 const double tol = 1e-8) {
47 return xi >= -tol && eta >= -tol && xi + eta <= 1 + tol;
48}
49
50inline bool isOnPrismTriFace(const int side, const EntityType type,
51 const int prism_face_side) {
52 switch (type) {
53 case MBVERTEX:
54 return prism_face_side == SLAVE_FACE_SIDE ? (side >= 0 && side < 3)
55 : (side >= 3 && side < 6);
56 case MBEDGE:
57 return prism_face_side == SLAVE_FACE_SIDE ? (side >= 0 && side < 3)
58 : (side >= 6 && side < 9);
59 case MBTRI:
60 return side == prism_face_side;
61 default:
62 return false;
63 }
64}
65
66inline bool isOnPrismTieTrace(const int side, const EntityType type) {
67 return isOnPrismTriFace(side, type, SLAVE_FACE_SIDE) ||
69}
70
71inline bool isOnSlaveTieRowBase(const int rr, const int row_side,
72 const EntityType row_type) {
73 switch (row_type) {
74 case MBVERTEX:
75 return rr < 3;
76 case MBEDGE:
77 return row_side >= 0 && row_side < 3;
78 case MBTRI:
79 return row_side == SLAVE_FACE_SIDE;
80 default:
81 return false;
82 }
83}
84
86
87 using FunRule = boost::function<int(int)>;
88 FunRule funRule = [](int p) { return 2 * p + 1; };
89 int tieRefLevel = 1;
90
92
93 SetIntegrationOnTiePrismFaces(int tie_ref_level = 1)
94 : tieRefLevel(tie_ref_level) {}
95
96 SetIntegrationOnTiePrismFaces(FunRule fun_rule, int tie_ref_level = 1)
97 : funRule(fun_rule), tieRefLevel(tie_ref_level) {}
98
99 MoFEMErrorCode operator()(ForcesAndSourcesCore *fe_raw_ptr, int order_row,
100 int order_col, int order_data) {
102
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)));
105
106 if (tieRefLevel < 0) {
107 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
108 "-tie_ref_level has to be >= 0");
109 }
110
111 if (rule < 0 || rule >= QUAD_2D_TABLE_SIZE) {
112 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
113 "Triangle quadrature rule %d is not available for TIE prism face "
114 "integration",
115 rule);
116 }
117
118 if (QUAD_2D_TABLE[rule]->dim != 2) {
119 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
120 "Expected 2D quadrature for TIE prism face integration");
121 }
122
123 if (QUAD_2D_TABLE[rule]->order < rule) {
124 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
125 "Wrong quadrature order %d < %d for TIE prism face integration",
126 QUAD_2D_TABLE[rule]->order, rule);
127 }
128
129 CHKERR setBaseQuadrature(*fe_ptr, rule);
130
131 if (tieRefLevel > 0) {
132 const auto cache_key = std::make_pair(rule, tieRefLevel);
133 auto it = mapRefCoords.find(cache_key);
134 if (it == mapRefCoords.end()) {
135 MatrixDouble ref_gauss_pts;
136 CHKERR refineQuadrature(*fe_ptr, tieRefLevel, ref_gauss_pts);
137 mapRefCoords[cache_key].swap(ref_gauss_pts);
138 it = mapRefCoords.find(cache_key);
139 }
140 fe_ptr->gaussPts = it->second;
141 }
142
143 const MatrixDouble slave_gauss_pts = fe_ptr->gaussPts;
144 const auto nb_gauss_pts = slave_gauss_pts.size2();
145
146 auto &moab = fe_ptr->mField.get_moab();
147 auto get_prism_face_coords = [&](const int side, std::array<double, 9> &coords) {
149 const EntityHandle prism = fe_ptr->getFEEntityHandle();
150 const EntityHandle *prism_conn = nullptr;
151 int num_prism_nodes = 0;
152 CHKERR moab.get_connectivity(prism, prism_conn, num_prism_nodes, true);
153 if (num_prism_nodes != 6) {
154 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
155 "TIE prism is expected to have 6 nodes");
156 }
157
158 std::array<EntityHandle, 3> face_conn;
159 switch (side) {
160 case SLAVE_FACE_SIDE:
161 face_conn = {prism_conn[0], prism_conn[1], prism_conn[2]};
162 break;
163 case MASTER_FACE_SIDE:
164 face_conn = {prism_conn[3], prism_conn[4], prism_conn[5]};
165 break;
166 default:
167 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
168 "Unsupported TIE prism triangle side %d", side);
169 }
170
171 CHKERR moab.get_coords(face_conn.data(), 3, coords.data());
173 };
174
175 std::array<double, 9> slave_coords; // nodal coords
176 std::array<double, 9> master_coords; // nodal coords
177 CHKERR get_prism_face_coords(SLAVE_FACE_SIDE, slave_coords);
178 CHKERR get_prism_face_coords(MASTER_FACE_SIDE, master_coords);
179
180 MatrixDouble slave_global_coords(nb_gauss_pts, 3, false); // gp coords
181 MatrixDouble master_global_coords(nb_gauss_pts, 3, false); //gp coords
182 MatrixDouble slave_shape(nb_gauss_pts, 3, false);
183 CHKERR ShapeMBTRI(&slave_shape(0, 0), &slave_gauss_pts(0, 0),
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];
191 }
192 }
193
194 CHKERR projectSlavePointsToMasterPlane(master_coords.data(),
195 slave_global_coords,
196 master_global_coords);
197
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));
202
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 =
206 isInsideReferenceTriangle(master_local_coords(gg, 0),
207 master_local_coords(gg, 1));
208 const double paired_weight = valid_master_point ? slave_gauss_pts(2, gg) : 0.;
209
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;
213
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;
217 }
218 fe_ptr->gaussPts.swap(combined_gauss_pts);
219
221 }
222
223private:
224 static MoFEMErrorCode setBaseQuadrature(
225 FlatPrismElementForcesAndSourcesCore &fe, const int rule) {
227 const size_t nb_gauss_pts = QUAD_2D_TABLE[rule]->npoints;
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);
233 cblas_dcopy(nb_gauss_pts, QUAD_2D_TABLE[rule]->weights, 1,
234 &fe.gaussPts(2, 0), 1);
236 }
237
238 static MoFEMErrorCode projectPointToMasterPlane(const double *master_coords,
239 const double *point,
240 double *projected_point) {
242
243 // For the infinite master plane, the closest point is the orthogonal
244 // projection along the plane normal.
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];
254
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;
261
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()) {
267 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
268 "Degenerated master triangle plane");
269 }
270
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;
278
280 }
281
282 static MoFEMErrorCode projectSlavePointsToMasterPlane(
283 const double *master_coords, const MatrixDouble &slave_global_coords,
284 MatrixDouble &master_global_coords) {
286
287 // The weak form is integrated on the slave surface. Each slave Gauss point
288 // is paired with its orthogonal projection on the infinite plane defined
289 // by the master triangle.
290 master_global_coords.resize(slave_global_coords.size1(), 3, false);
291 for (size_t gg = 0; gg != slave_global_coords.size1(); ++gg) {
292 CHKERR projectPointToMasterPlane(master_coords,
293 &slave_global_coords(gg, 0),
294 &master_global_coords(gg, 0));
295 }
296
298 }
299
300 static MoFEMErrorCode refineQuadrature(
301 FlatPrismElementForcesAndSourcesCore &fe, const int refinement_levels,
302 MatrixDouble &ref_gauss_pts) {
304
305 constexpr int num_nodes = 3;
306 moab::Core moab_ref;
307 double base_coords[] = {0, 0, 0, 1, 0, 0, 0, 1, 0};
308 EntityHandle nodes[num_nodes];
309 for (int nn = 0; nn != num_nodes; ++nn)
310 CHKERR moab_ref.create_vertex(&base_coords[3 * nn], nodes[nn]);
311
312 EntityHandle tri;
313 CHKERR moab_ref.create_element(MBTRI, nodes, num_nodes, tri);
314 MoFEM::CoreTmp<-1> mofem_ref_core(moab_ref, PETSC_COMM_SELF, -2);
315 MoFEM::Interface &m_field_ref = mofem_ref_core;
316
317 {
318 Range tris(tri, tri);
319 Range edges;
320 // Force MOAB to materialise the triangle edges before the bit-ref
321 // database is seeded. The working reference-refinement snippets all do
322 // this, and the side-number lookup below verifies that MOAB sees a
323 // consistent local edge numbering on the temporary reference triangle.
324 CHKERR m_field_ref.get_moab().get_adjacencies(
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);
329 }
330 CHKERR m_field_ref.getInterface<BitRefManager>()->setBitRefLevel(
331 tris, BitRefLevel().set(0), false, VERBOSE);
332 }
333
334 auto *m_ref = m_field_ref.getInterface<MeshRefinement>();
335 for (int ll = 0; ll != refinement_levels; ++ll) {
336 Range tris;
337 CHKERR m_field_ref.getInterface<BitRefManager>()
338 ->getEntitiesByTypeAndRefLevel(BitRefLevel().set(ll),
339 BitRefLevel().set(), MBTRI, tris);
340
341 Range edges;
342 CHKERR moab_ref.get_adjacencies(tris, 1, true, edges,
343 moab::Interface::UNION);
344
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);
348 }
349
350 Range tris;
351 CHKERR m_field_ref.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
352 BitRefLevel().set(refinement_levels), BitRefLevel().set(), MBTRI, tris);
353
354 MatrixDouble ref_coords(tris.size(), 9, false);
355 int tt = 0;
356 for (auto tit = tris.begin(); tit != tris.end(); ++tit, ++tt) {
357 int num_conn;
358 const EntityHandle *conn;
359 CHKERR moab_ref.get_connectivity(*tit, conn, num_conn, false);
360 CHKERR moab_ref.get_coords(conn, num_conn, &ref_coords(tt, 0));
361 }
362
363 const size_t nb_gauss_pts = fe.gaussPts.size2();
364 MatrixDouble shape_n(nb_gauss_pts, 3, false);
365 CHKERR ShapeMBTRI(&shape_n(0, 0), &fe.gaussPts(0, 0), &fe.gaussPts(1, 0),
366 nb_gauss_pts);
367 ref_gauss_pts.resize(3, nb_gauss_pts * ref_coords.size1(), false);
368 int gg = 0;
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];
380 }
381 ref_gauss_pts(2, gg) = fe.gaussPts(2, ggg) * det;
382 }
383 }
384
386 }
387
388 static inline std::map<std::pair<int, int>, MatrixDouble> mapRefCoords;
389};
390
391template <int Tensor_Dim>
393 : public OpCalculateVectorFieldValues_General<Tensor_Dim, MatrixDouble> {
394
395 using Base = OpCalculateVectorFieldValues_General<Tensor_Dim, MatrixDouble>;
396 using Base::Base;
397
398 MoFEMErrorCode doWork(int side, EntityType type,
399 EntitiesFieldData::EntData &data) override {
401 if (!isOnPrismTieTrace(side, type))
403 CHKERR Base::doWork(side, type, data);
405 }
406};
407
408using TiePrismRhsBase = FormsIntegrators<
409 FlatPrismElementForcesAndSourcesCore::UserDataOperator>::Assembly<A>::OpBase;
410
412
413 OpTiePrismRhs(boost::shared_ptr<MatrixDouble> disp_ptr)
414 : TiePrismRhsBase("LAMBDA", "LAMBDA", OPROW, nullptr),
415 dispPtr(disp_ptr) {
416 if (!dispPtr)
417 THROW_MESSAGE("Pointers are not set");
418 }
419
420 inline double getSlaveFaceArea() { return getAreaF3(); }
421
422protected:
423 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data) override {
425
426 const auto *fe =
427 dynamic_cast<const FlatPrismElementForcesAndSourcesCore *>(ptrFE);
428 if (!fe)
429 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
430 "TIE prism RHS operator is attached to a wrong finite element");
431
432 const auto nb_gauss_pts = getGaussPts().size2();
433 if (!nb_gauss_pts || nb_gauss_pts % 2) {
434 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
435 "Expected concatenated [slave|master] TIE Gauss points");
436 }
437 const auto nb_slave_gauss = nb_gauss_pts / 2;
438 if (dispPtr->size1() != nb_gauss_pts) {
439 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
440 "TIE displacement values at Gauss points were not prepared "
441 "before RHS assembly");
442 }
443
444 if (nbRows % SPACE_DIM)
445 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
446 "Unexpected number of LAMBDA dofs on TIE prism rows");
447
448 auto &row_n = row_data.getN();
449 if (!row_n.size1() || !row_n.size2())
451 if (row_n.size1() != nb_gauss_pts)
452 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
453 "Unexpected number of Gauss points on TIE multiplier block");
454
455 const int nb_row_base = nbRows / SPACE_DIM;
456 if (static_cast<size_t>(nb_row_base) > row_n.size2())
457 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
458 "More TIE multiplier bases than shape functions");
459 if (dispPtr->size2() != SPACE_DIM)
460 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
461 "Unexpected TIE displacement matrix size: size2=%d expected=%d",
462 static_cast<int>(dispPtr->size2()), SPACE_DIM);
463 if (locF.size() != static_cast<size_t>(nbRows))
464 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
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()));
471
472 auto t_w = getFTensor0IntegrationWeight();
473 for (size_t gg = 0; gg != nb_slave_gauss; ++gg) {
474 const double slave_alpha = getSlaveFaceArea() * t_w;
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));
484 }
485 }
486 ++t_row_base;
487 }
488
489 ++t_w;
490 }
491
493 }
494
495private:
496 boost::shared_ptr<MatrixDouble> dispPtr;
497};
498
500
501 OpTiePrismRhsU(const std::string &field_name,
502 boost::shared_ptr<MatrixDouble> lambda_ptr)
503 : TiePrismRhsBase(field_name, field_name, OPROW, nullptr),
504 lambdaPtr(lambda_ptr) {
505 if (!lambdaPtr)
506 THROW_MESSAGE("Pointers are not set");
507 }
508
509 inline double getSlaveFaceArea() { return getAreaF3(); }
510
511protected:
512 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data) override {
514
515 const auto *fe =
516 dynamic_cast<const FlatPrismElementForcesAndSourcesCore *>(ptrFE);
517 if (!fe)
518 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
519 "TIE prism RHS operator is attached to a wrong finite element");
520
521 const auto nb_gauss_pts = getGaussPts().size2();
522 if (!nb_gauss_pts || nb_gauss_pts % 2) {
523 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
524 "Expected concatenated [slave|master] TIE Gauss points");
525 }
526 const auto nb_slave_gauss = nb_gauss_pts / 2;
527 if (lambdaPtr->size1() != nb_gauss_pts) {
528 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
529 "TIE multiplier values at Gauss points were not prepared "
530 "before RHS assembly");
531 }
532
533 if (nbRows % SPACE_DIM)
534 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
535 "Unexpected number of TIE prism vector dofs on rows");
536
537 if (!isOnPrismTieTrace(rowSide, rowType))
539
540 auto &row_n = row_data.getN();
541 if (!row_n.size1() || !row_n.size2())
543 if (row_n.size1() != nb_gauss_pts)
544 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
545 "Unexpected number of Gauss points on TIE displacement block");
546
547 const int nb_row_base = nbRows / SPACE_DIM;
548 if (static_cast<size_t>(nb_row_base) > row_n.size2())
549 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
550 "More TIE displacement bases than shape functions");
551 if (lambdaPtr->size2() != SPACE_DIM)
552 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
553 "Unexpected TIE multiplier matrix size: size2=%d expected=%d",
554 static_cast<int>(lambdaPtr->size2()), SPACE_DIM);
555 if (locF.size() != static_cast<size_t>(nbRows))
556 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
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()),
561 static_cast<int>(lambdaPtr->size1()),
562 static_cast<int>(lambdaPtr->size2()));
563
564 auto t_w = getFTensor0IntegrationWeight();
565 for (size_t gg = 0; gg != nb_slave_gauss; ++gg) {
566 const double slave_alpha = getSlaveFaceArea() * t_w;
567 for (int rr = 0; rr != nb_row_base; ++rr) {
568 const bool base_on_slave = isOnSlaveTieRowBase(rr, rowSide, rowType);
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())
572 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
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]);
582 for (int dd = 0; dd != SPACE_DIM; ++dd)
583 t_row_rhs(dd) +=
584 row_sign * row_base * slave_alpha * (*lambdaPtr)(gg, dd);
585 }
586 ++t_row_base;
587 }
588
589 ++t_w;
590 }
591
593 }
594
595private:
596 boost::shared_ptr<MatrixDouble> lambdaPtr;
597};
598
599using TiePrismLhsBase = FormsIntegrators<
600 FlatPrismElementForcesAndSourcesCore::UserDataOperator>::Assembly<A>::OpBase;
601
603
604 OpTiePrismLhs(const std::string &row_field_name,
605 const std::string &col_field_name,
606 const bool assemble_transpose = false)
607 : TiePrismLhsBase(row_field_name, col_field_name, OPROWCOL, nullptr),
608 rowFieldName(row_field_name), colFieldName(col_field_name) {
609 sYmm = false;
610 this->assembleTranspose = assemble_transpose;
611 }
612
613 inline double getSlaveFaceArea() { return getAreaF3(); }
614
615protected:
616 std::string rowFieldName;
617 std::string colFieldName;
618
619 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
620 EntitiesFieldData::EntData &col_data) override {
622
623 const auto *fe =
624 dynamic_cast<const FlatPrismElementForcesAndSourcesCore *>(ptrFE);
625 if (!fe)
626 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
627 "TIE prism operator is attached to a wrong finite element");
628
629 if (nbRows % SPACE_DIM || nbCols % SPACE_DIM)
630 SETERRQ(
631 PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
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",
635 rowFieldName.c_str(), colFieldName.c_str(), rowSide, colSide,
636 rowType, colType, nbRows, nbCols);
637
638 if (colFieldName != "LAMBDA")
640
641 const auto nb_gauss_pts = getGaussPts().size2();
642 if (!nb_gauss_pts || nb_gauss_pts % 2) {
643 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
644 "Expected concatenated [slave|master] TIE Gauss points");
645 }
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;
649
650 auto &col_n = col_data.getN();
651 if (!col_n.size1() || !col_n.size2())
653
654 auto &row_n = row_data.getN();
655 if (!row_n.size1() || !row_n.size2())
657
658 if (row_n.size1() != nb_gauss_pts || col_n.size1() != nb_gauss_pts)
659 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
660 "Unexpected number of Gauss points on TIE prism blocks");
661
662 if (static_cast<size_t>(nb_row_base) > row_n.size2() ||
663 static_cast<size_t>(nb_col_base) > col_n.size2())
664 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
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))
668 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
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)",
672 rowFieldName.c_str(), colFieldName.c_str(), rowSide, colSide,
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()));
677
678 if (!isOnPrismTieTrace(rowSide, rowType))
680
681 auto t_w = getFTensor0IntegrationWeight();
682 for (size_t gg = 0; gg != nb_slave_gauss; ++gg) {
683 const double slave_alpha = getSlaveFaceArea() * t_w;
684 for (int rr = 0; rr != nb_row_base; ++rr) {
685 const bool base_on_slave = isOnSlaveTieRowBase(rr, rowSide, rowType);
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())
689 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
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 "
692 "nb_slave_gauss=%d",
693 rowFieldName.c_str(), colFieldName.c_str(), rowSide, rowType,
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;
700 for (int dd = 0; dd != SPACE_DIM; ++dd)
701 locMat(SPACE_DIM * rr + dd, SPACE_DIM * cc + dd) += value;
702 ++t_col_base;
703 }
704 ++t_row_base;
705 }
706 ++t_w;
707 }
708
710 }
711};
712
713inline MoFEMErrorCode logTieDisplacementNorms(
714 MoFEM::Interface &mField, const boost::shared_ptr<CommonData> &tie_data,
715 const std::string &field_name) {
717
718 if (!tie_data || !tie_data->hasTieConstraints || !tie_data->tieSlaveFaces ||
719 !tie_data->tieMasterFaces) {
720 return 0;
721 }
722
723 auto &moab = mField.get_moab();
724 auto comm_interface = mField.getInterface<CommInterface>();
725 auto *pcomm = ParallelComm::get_pcomm(&moab, MYPCOMM_INDEX);
726
727 auto closure_with_faces = [&](const Range &faces, Range &closure) {
729 closure = faces;
730 Range edges, verts;
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);
736 };
737
738 auto calculate_norms = [&](const Range &ents, double &l2_norm, double &linf,
739 unsigned int &nb_dofs) {
741 double sum2 = 0;
742 double max_abs = 0;
743 unsigned int count = 0;
744 for (auto ent : ents) {
745 if (pcomm) {
746 unsigned char pstatus;
747 CHKERR moab.tag_get_data(pcomm->pstatus_tag(), &ent, 1, &pstatus);
748 if (pstatus & PSTATUS_NOT_OWNED)
749 continue;
750 }
752 dit)) {
753 const double value = (*dit)->getFieldData();
754 sum2 += value * value;
755 max_abs = std::max(max_abs, std::abs(value));
756 ++count;
757 }
758 }
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,
764 mField.get_comm());
765 MPI_Allreduce(&max_abs, &global_max_abs, 1, MPI_DOUBLE, MPI_MAX,
766 mField.get_comm());
767 MPI_Allreduce(&local_count, &global_count, 1, MPI_UNSIGNED_LONG_LONG,
768 MPI_SUM, mField.get_comm());
769 l2_norm = std::sqrt(global_sum2);
770 linf = global_max_abs;
771 nb_dofs = static_cast<unsigned int>(global_count);
773 };
774
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);
780
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);
785
786 MOFEM_LOG("WORLD", Sev::inform)
787 << "TIE solved displacement norms on slave face closure: dofs="
788 << slave_nb_dofs << " l2=" << slave_l2 << " linf=" << slave_linf;
789 MOFEM_LOG("WORLD", Sev::inform)
790 << "TIE solved displacement norms on master face closure: dofs="
791 << master_nb_dofs << " l2=" << master_l2 << " linf=" << master_linf;
792
794}
795
796inline MoFEMErrorCode initializeTieConstraints(
797 MoFEM::Interface &mField, boost::shared_ptr<CommonData> &tie_data,
798 const std::string &field_name, FieldApproximationBase base, int order) {
800 auto simple = mField.getInterface<Simple>();
801 auto meshset_mng = mField.getInterface<MeshsetsManager>();
802 auto comm_interface = mField.getInterface<CommInterface>();
803
804 auto tie_master =
805 meshset_mng->getCubitMeshsetPtr(std::regex("^TIE_MASTER.*"));
806 auto tie_slave = meshset_mng->getCubitMeshsetPtr(std::regex("^TIE_SLAVE.*"));
807
808 const bool have_master_meshset = !tie_master.empty();
809 const bool have_slave_meshset = !tie_slave.empty();
810
811 if (!have_master_meshset && !have_slave_meshset) {
813 }
814
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,
819 mField.get_comm());
820 return global_value != 0;
821 };
822
823 if (SPACE_DIM != 3) {
824 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
825 "TIE prism constraints are supported only in 3D");
826 }
827
828 if (!tie_data)
829 tie_data = boost::make_shared<CommonData>();
830
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) {
835 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
836 "-tie_ref_level has to be >= 0");
837 }
838
839 tie_data->dispFieldName = field_name;
840 tie_data->dispFieldBase = base;
841 tie_data->dispFieldOrder = order;
842
843 if (!have_master_meshset || !have_slave_meshset) {
844 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
845 "Both TIE_MASTER* and TIE_SLAVE* meshsets are required to "
846 "initialise TIE constraints");
847 }
848 // FIXME: this might not be necessary
849 Range local_prisms;
850 CHKERR mField.get_moab().get_entities_by_type(0, MBPRISM, local_prisms, true);
851 Range local_prism_faces;
852 if (!local_prisms.empty()) {
853 CHKERR mField.get_moab().get_adjacencies(local_prisms, 2, false,
854 local_prism_faces,
855 moab::Interface::UNION);
856 local_prism_faces = local_prism_faces.subset_by_type(MBTRI);
857 }
858
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) {
864 Range tris;
865 // TIE blocksets written to file can expose their surface triangles through
866 // nested child sets after reload, so collect them recursively.
867 CHKERR mField.get_moab().get_entities_by_type(meshset_ptr->meshset, MBTRI,
868 tris, true);
869 tris = intersect(tris, local_prism_faces);
870 face_range->merge(tris);
871 }
873 };
874
875 CHKERR collectTieFaces(tie_master, tie_data->tieMasterFaces);
876 CHKERR collectTieFaces(tie_slave, tie_data->tieSlaveFaces);
877
878 if (tie_data->tieMasterFaces->empty() != tie_data->tieSlaveFaces->empty()) {
879 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
880 "Local TIE_MASTER/TIE_SLAVE meshsets are inconsistent");
881 }
882
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);
893
894 if (!tie_data->tieSlaveFaces->empty() && slave_adjacent_prisms.empty()) {
895 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
896 "No prism elements are adjacent to TIE_SLAVE meshsets");
897 }
898
899 if (slave_adjacent_prisms.size() != master_adjacent_prisms.size()) {
900 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
901 "Different numbers of prisms are adjacent to TIE_SLAVE and "
902 "TIE_MASTER meshsets");
903 }
904
905 *tie_data->tiePrisms = slave_adjacent_prisms;
906
907 const bool have_tie_prisms = anyRank(!tie_data->tiePrisms->empty());
908 if (!have_tie_prisms) {
909 MOFEM_LOG("WORLD", Sev::warning)
910 << "TIE_MASTER/TIE_SLAVE meshsets found but no prism elements are adjacent to them. "
911 << "TIE constraints cannot be initialised.";
913 }
914
915 if (!tie_data->tiePrisms->empty()) {
916 MOFEM_LOG("WORLD", Sev::inform)
917 << "Initialising TIE constraints on " << tie_data->tiePrisms->size()
918 << " prism elements adjacent to the TIE slave/master surfaces.";
919 }
920
921 if (!mField.check_field("LAMBDA"))
922 CHKERR mField.add_field("LAMBDA", H1, base, SPACE_DIM);
923
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,
932 tie_prism_edges,
933 moab::Interface::UNION);
934 const auto tie_prism_lateral_edges =
935 subtract(tie_prism_edges, tie_prism_trace_edges);
936
937 CHKERR mField.add_ents_to_field_by_type(*tie_data->tiePrisms, MBPRISM,
938 field_name);
939 CHKERR mField.add_ents_to_field_by_type(*tie_data->tiePrisms, MBPRISM,
940 "GEOMETRY");
941 CHKERR mField.set_field_order(tie_prism_trace_edges, "GEOMETRY", 2);
942
943 // LAMBDA is a classical surface multiplier. It lives only on the slave
944 // interface, while the prism FE uses that trace space to constrain slave and
945 // master displacement traces. Work on the already collected recursive slave
946 // face range directly, since reloaded Cubit blocksets can expose triangles
947 // only through nested child sets.
948 CHKERR mField.add_ents_to_field_by_type(*tie_data->tieSlaveFaces, MBTRI,
949 "LAMBDA");
950 CHKERR comm_interface->synchroniseFieldEntities("LAMBDA", 0);
951
952 Range verts;
953 CHKERR mField.get_moab().get_entities_by_type(0, MBVERTEX, verts, true);
954 Range faces;
955 CHKERR mField.get_moab().get_entities_by_type(0, MBTRI, faces, true);
956 Range edges;
957 CHKERR mField.get_moab().get_adjacencies(faces, 1, true, edges,
958 moab::Interface::UNION);
959 CHKERR mField.add_ents_to_field_by_type(verts, MBVERTEX, "U");
960 CHKERR comm_interface->synchroniseEntities(edges);
961 CHKERR mField.add_ents_to_field_by_type(edges, MBEDGE, "U");
962 CHKERR mField.add_ents_to_field_by_type(faces, MBTRI, "U");
963 CHKERR comm_interface->synchroniseFieldEntities("U", 0);
964
965
966 CHKERR mField.set_field_order(0, MBVERTEX, field_name, 1);
967 CHKERR mField.set_field_order(0, MBEDGE, field_name, order);
968 CHKERR mField.set_field_order(0, MBTRI, field_name, order);
969 CHKERR mField.set_field_order(tie_prism_lateral_edges, field_name, 1);
970 CHKERR mField.set_field_order(0, MBVERTEX, "LAMBDA", 1);
971 CHKERR mField.set_field_order(0, MBEDGE, "LAMBDA", order - 1);
972 CHKERR mField.set_field_order(0, MBTRI, "LAMBDA", order - 1);
973
974 CHKERR mField.build_fields();
975
976 if (!mField.check_finite_element(tie_data->tiePrismFeName)) {
977 CHKERR mField.add_finite_element(tie_data->tiePrismFeName);
978 CHKERR mField.modify_finite_element_add_field_row(tie_data->tiePrismFeName,
979 field_name);
980 CHKERR mField.modify_finite_element_add_field_col(tie_data->tiePrismFeName,
981 field_name);
982 CHKERR mField.modify_finite_element_add_field_row(tie_data->tiePrismFeName,
983 "LAMBDA");
984 CHKERR mField.modify_finite_element_add_field_col(tie_data->tiePrismFeName,
985 "LAMBDA");
986 CHKERR mField.modify_finite_element_add_field_data(tie_data->tiePrismFeName,
987 field_name);
988 CHKERR mField.modify_finite_element_add_field_data(tie_data->tiePrismFeName,
989 "LAMBDA");
990 CHKERR mField.modify_finite_element_add_field_data(tie_data->tiePrismFeName,
991 "GEOMETRY");
992 }
993
994 CHKERR mField.modify_finite_element_add_field_row(simple->getDomainFEName(),
995 "LAMBDA");
996 CHKERR mField.modify_finite_element_add_field_col(simple->getDomainFEName(),
997 "LAMBDA");
998 CHKERR mField.modify_finite_element_add_field_data(simple->getDomainFEName(),
999 "LAMBDA");
1000
1001 CHKERR mField.add_ents_to_finite_element_by_type(*tie_data->tiePrisms,
1002 MBPRISM,
1003 tie_data->tiePrismFeName);
1004 CHKERR mField.build_finite_elements(simple->getDomainFEName());
1005 CHKERR mField.build_finite_elements(tie_data->tiePrismFeName);
1006
1007 auto &other_fes = simple->getOtherFiniteElements();
1008 other_fes.push_back(tie_data->tiePrismFeName);
1009
1010 CHKERR DMMoFEMAddElement(simple->getDM(), tie_data->tiePrismFeName);
1011 CHKERR simple->reSetUp(true);
1012
1013 tie_data->hasTieConstraints = true;
1015}
1016
1017inline MoFEMErrorCode setupTieConstraintOperators(
1018 MoFEM::Interface &mField, boost::shared_ptr<CommonData> tie_data) {
1020
1021 if (!tie_data || !tie_data->hasTieConstraints) {
1023 }
1024
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 =
1030 SetIntegrationOnTiePrismFaces(tie_data->tieRefLevel);
1031 tie_data->tiePrismRhsFE->getOpPtrVector().push_back(
1033 "LAMBDA", tie_data->lambdaAtGaussPts, MBVERTEX));
1034 tie_data->tiePrismRhsFE->getOpPtrVector().push_back(
1035 new OpTiePrismRhsU(tie_data->dispFieldName,
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(
1041 new OpTiePrismRhs(tie_data->dispAtGaussPts));
1042 }
1043
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 =
1049 SetIntegrationOnTiePrismFaces(tie_data->tieRefLevel);
1050 tie_data->tiePrismLhsFE->getOpPtrVector().push_back(
1051 new OpTiePrismLhs(tie_data->dispFieldName, "LAMBDA", true));
1052 }
1053
1055}
1056
1057inline MoFEMErrorCode setupTieSolver(MoFEM::Interface &mField,
1058 boost::shared_ptr<CommonData> tie_data,
1059 SmartPetscObj<KSP> solver) {
1061
1062 if (!tie_data || !tie_data->hasTieConstraints)
1064
1065 CHKERR setupTieConstraintOperators(mField, tie_data);
1066
1067 DM dm;
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);
1074
1076}
1077
1078inline MoFEMErrorCode setupTieSolver(MoFEM::Interface &mField,
1079 boost::shared_ptr<CommonData> tie_data,
1080 SmartPetscObj<TS> solver) {
1082
1083 if (!tie_data || !tie_data->hasTieConstraints)
1085
1086 CHKERR setupTieConstraintOperators(mField, tie_data);
1087
1088 DM dm;
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);
1095
1097}
1098
1099} // namespace ElasticTie
1100
1101#endif // __ELASTIC_TIE_HPP__
std::string type
#define FTENSOR_INDEX(DIM, I)
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
constexpr int SPACE_DIM
@ QUIET
@ VERBOSE
FieldApproximationBase
approximation base
Definition definitions.h:58
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
@ H1
continuous field
Definition definitions.h:85
#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
Definition definitions.h:31
#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.
constexpr int order
PetscErrorCode ShapeMBTRI(double *N, const double *X, const double *Y, const int G_DIM)
calculate shape functions on triangle
Definition fem_tools.c:182
double eta
#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
Definition quad.h:174
static QUAD *const QUAD_2D_TABLE[]
Definition quad.h:175
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)
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)
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)
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.
int npoints
Definition quad.h:29
double tol