v0.15.0
Loading...
Searching...
No Matches
SurfaceSlidingConstrains.hpp
Go to the documentation of this file.
1/** \file SurfaceSlidingConstrains.hpp
2 * \brief Implementing surface sliding constrains
3 */
4
5
6
7#ifndef __SURFACE_SLIDING_CONSTRAINS_HPP__
8#define __SURFACE_SLIDING_CONSTRAINS_HPP__
9
10#ifdef WITH_ADOL_C
11
12/**
13 * @brief Implementation of surface sliding constrains
14 *
15 */
16struct GenericSliding {
17
18 GenericSliding() = default;
19 virtual ~GenericSliding() = default;
20
23 boost::shared_ptr<VectorDouble> activeVariablesPtr;
25 boost::shared_ptr<VectorDouble> &active_variables_ptr)
28 activeVariablesPtr(active_variables_ptr) {}
29 MoFEMErrorCode doWork(int side, EntityType type,
30 EntitiesFieldData::EntData &data) {
32 if (type == MBVERTEX) {
33 for (unsigned int dd = 0; dd != data.getFieldData().size(); ++dd)
34 (*activeVariablesPtr)[dd] = data.getFieldData()[dd];
35 }
37 }
38 };
39
40 template <int SizeLambda>
43 boost::shared_ptr<VectorDouble> activeVariablesPtr;
45 const std::string field_name,
46 boost::shared_ptr<VectorDouble> &active_variables_ptr)
49 activeVariablesPtr(active_variables_ptr) {}
50 MoFEMErrorCode doWork(int side, EntityType type,
51 EntitiesFieldData::EntData &data) {
53 if (type == MBVERTEX) {
54 for (unsigned int dd = 0; dd != data.getFieldData().size(); ++dd)
55 (*activeVariablesPtr)[SizeLambda + dd] = data.getFieldData()[dd];
56 }
58 }
59 };
60
61 template <int SizeLambda, int SizePositions>
63
64 boost::shared_ptr<VectorDouble> resultsPtr;
65
66 OpAssembleRhs(const std::string field_name,
67 boost::shared_ptr<VectorDouble> &results_ptr)
70 resultsPtr(results_ptr) {}
71
72 MoFEMErrorCode doWork(int side, EntityType type,
73 EntitiesFieldData::EntData &data) {
75 if (type != MBVERTEX)
77 VectorInt &indices = data.getIndices();
78 int shift = 0;
79 if (indices.empty())
81 else if (indices.size() == SizeLambda)
82 shift = 0;
83 else if (indices.size() == SizePositions)
84 shift = SizeLambda;
85 else
86 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
87 "Element %s: Data inconsistency nb of indices %ld",
88 getFEName().c_str(), indices.size());
89
90 CHKERR VecSetOption(getSNESf(), VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE);
91 CHKERR VecSetValues(getSNESf(), indices.size(), &indices[0],
92 &(*resultsPtr)[shift], ADD_VALUES);
94 }
95 };
96 template <int SizeLambda, int SizePositions>
98
99 boost::shared_ptr<MatrixDouble> jacobianPtr;
100
101 OpAssembleLhs(const std::string field_name_row,
102 const std::string field_name_col,
103 boost::shared_ptr<MatrixDouble> &jacobian_ptr)
105 field_name_row, field_name_col, UserDataOperator::OPROWCOL),
106 jacobianPtr(jacobian_ptr) {
107 sYmm = false;
108 }
109
110 MoFEMErrorCode doWork(int row_side, int col_side, EntityType row_type,
111 EntityType col_type,
112 EntitiesFieldData::EntData &row_data,
113 EntitiesFieldData::EntData &col_data) {
115 if (row_type != MBVERTEX)
117 if (col_type != MBVERTEX)
119 VectorInt &row_indices = row_data.getIndices();
120 VectorInt &col_indices = col_data.getIndices();
121 if (row_indices.empty() || col_indices.empty())
123
124 int shift_row = 0;
125 if (row_indices.size() == SizeLambda)
126 shift_row = 0;
127 else if (row_indices.size() == SizePositions)
128 shift_row = SizeLambda;
129 else
130 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
131 "Data inconsistency");
132
133 int shift_col = 0;
134 if (col_indices.size() == SizeLambda)
135 shift_col = 0;
136 else if (col_indices.size() == SizePositions)
137 shift_col = SizeLambda;
138 else
139 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
140 "Data inconsistency");
141
142 MatrixDouble jac(row_indices.size(), col_indices.size());
143 for (unsigned int rr = 0; rr != row_indices.size(); ++rr) {
144 for (unsigned int cc = 0; cc != col_indices.size(); ++cc) {
145 jac(rr, cc) = (*jacobianPtr)(shift_row + rr, shift_col + cc);
146 if (jac(rr, cc) != jac(rr, cc))
147 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
148 "Jacobian assemble not a number jac(rr,cc) = %3.4f",
149 jac(rr, cc));
150 }
151 }
152 CHKERR MatSetValues(getSNESB(), row_indices.size(), &row_indices[0],
153 col_indices.size(), &col_indices[0], &jac(0, 0),
154 ADD_VALUES);
156 }
157 };
158};
159
160/** \brief Shape preserving constrains, i.e. nodes sliding on body surface.
161
162 Derivation and implementation of constrains preserving body surface,
163 i.e. body shape and volume.
164
165 The idea starts form observation that body shape can be globally characterized
166 by constant calculated as volume over its area
167 \f[
168 \frac{V}{A} = C
169 \f]
170 Above equation expressed in integral form is
171 \f[
172 \int_\Omega \textrm{d}V = C \int_\Gamma \textrm{d}S
173 \f]
174 where notting that,
175 \f[
176 \frac{1}{3}
177 \int_\Omega \textrm{div}[\mathbf{X}] \textrm{d}\Omega
178 =
179 C \int_\Gamma \textrm{d}S
180 \f]
181 and applying Gauss theorem we get
182 \f[
183 \int_\Gamma
184 \mathbf{X}\cdot \frac{\mathbf{N}}{\|\mathbf{N}\|}
185 \textrm{d}\Gamma
186 =
187 3C \int_\Gamma \textrm{d}S.
188 \f]
189 Drooping integrals on both sides, and linearizing equation, we get
190 \f[
191 \frac{\mathbf{N}}{\|\mathbf{N}\|} \cdot \delta \mathbf{X}
192 =
193 3C - \frac{\mathbf{N}}{\|\mathbf{N}\|}\cdot \mathbf{X}
194 \f]
195 where \f$\delta \mathbf{X}\f$ is displacement sub-inctrement. Above equation
196 is a constrain if satisfied in body shape and volume is conserved. Final form
197 of constrain equation is \f[ \mathcal{r} =
198 \frac{\mathbf{N}}{\|\mathbf{N}\|}\cdot \mathbf{X}
199 -
200 \frac{\mathbf{N_0}}{\|\mathbf{N_0}\|}\cdot \mathbf{X}_0 =
201 \frac{\mathbf{N}}{\|\mathbf{N}\|}\cdot (\mathbf{X}-\mathbf{X}_0)
202 \f]
203
204 In the spirit of finite element method the constrain equation is multiplied
205 by shape functions and enforce using Lagrange multiplier method
206 \f[
207 \int_\Gamma \mathbf{N}^\mathsf{T}_\lambda
208 \left(
209 \frac{\mathbf{N}}{\|\mathbf{N}\|}\mathbf{N}_\mathbf{X}\cdot
210 (\overline{\mathbf{X}}-\overline{\mathbf{X}}_0)
211 \right)
212 \|\mathbf{N}\|
213 \textrm{d}\Gamma
214 =
215 \mathbf{0}.
216 \f]
217 Above equation is nonlinear, applying to it Taylor expansion, we can get form
218 which can be used with Newton interactive method \f[ \begin{split}
219 &\int_\Gamma \mathbf{N}^\mathsf{T}_\lambda
220 \left\{
221 \mathbf{N}\mathbf{N}_\mathbf{X}
222 +
223 \left(\mathbf{X}-\mathbf{X}_0\right) \cdot
224 \left(
225 \textrm{Spin}\left[\frac{\partial\mathbf{X}}{\partial\xi}\right]\cdot\mathbf{B}_\eta
226 -
227 \textrm{Spin}\left[\frac{\partial\mathbf{X}}{\partial\eta}\right]\cdot\mathbf{B}_\xi
228 \right)
229 \right\}
230 \textrm{d}\Gamma
231 \cdot
232 \delta
233 \overline{\mathbf{X}}\\
234 =
235 &\int_\Gamma \mathbf{N}^\mathsf{T}_\lambda
236 \mathbf{N}\cdot(\mathbf{X}-\mathbf{X}_0)
237 \textrm{d}\Gamma
238 \end{split}.
239 \f]
240 Equation expressing forces on shape as result of constrains, as result
241 Lagrange multiplier method have following form \f[ \begin{split}
242 &\int_\Gamma
243 \mathbf{N}^\mathsf{T}_\mathbf{X} \cdot \mathbf{N}
244 \mathbf{N}_\lambda
245 \textrm{d}\Gamma
246 \cdot
247 \delta\overline{\lambda}\\
248 +
249 &\int_\Gamma
250 \lambda
251 \mathbf{N}^\mathsf{T}_\mathbf{X}
252 \left(
253 \textrm{Spin}\left[\frac{\partial\mathbf{X}}{\partial\xi}\right]\cdot\mathbf{B}_\eta
254 -
255 \textrm{Spin}\left[\frac{\partial\mathbf{X}}{\partial\eta}\right]\cdot\mathbf{B}_\xi
256 \right)
257 \textrm{d}\Gamma
258 \delta\overline{\mathbf{X}}\\
259 =
260 &\int_\Gamma
261 \lambda
262 \mathbf{N}^\mathsf{T}_\mathbf{X} \cdot \mathbf{N}
263 \textrm{d}\Gamma
264 \end{split}
265 \f]
266
267 Above equations are assembled into global system of equations as following
268 \f[
269 \left[
270 \begin{array}{cc}
271 \mathbf{K} + \mathbf{B} & \mathbf{C}^\mathsf{T} \\
272 \mathbf{C} + \mathbf{A} & 0
273 \end{array}
274 \right]
275 \left\{
276 \begin{array}{c}
277 \delta \overline{\mathbf{X}} \\
278 \delta \overline{\lambda}
279 \end{array}
280 \right\}=
281 \left[
282 \begin{array}{c}
283 \mathbf{f} - \mathbf{C}^\mathsf{T}\overline{\lambda} \\
284 \overline{\mathbf{r}}
285 \end{array}
286 \right]
287 \f]
288 where
289 \f[
290 \mathbf{C}=
291 \int_\Gamma
292 \mathbf{N}_\lambda^\mathsf{T}
293 \mathbf{N} \cdot
294 \mathbf{N}_\mathbf{X}
295 \textrm{d}\Gamma,
296 \f]
297 \f[
298 \mathbf{B}=
299 \int_\Gamma
300 \lambda
301 (\mathbf{X}-\mathbf{X}_0)\cdot
302 \left(
303 \textrm{Spin}\left[\frac{\partial\mathbf{X}}{\partial\xi}\right]\cdot\mathbf{B}_\eta
304 -
305 \textrm{Spin}\left[\frac{\partial\mathbf{X}}{\partial\eta}\right]\cdot\mathbf{B}_\xi
306 \right)
307 \textrm{d}\Gamma
308 \f]
309 and
310 \f[
311 \mathbf{A}=
312 \int_\Gamma
313 \mathbf{N}^\mathsf{T}_\lambda
314 \left(\mathbf{X}-\mathbf{X}_0\right) \cdot
315 \left(
316 \textrm{Spin}\left[\frac{\partial\mathbf{X}}{\partial\xi}\right]\cdot\mathbf{B}_\eta
317 -
318 \textrm{Spin}\left[\frac{\partial\mathbf{X}}{\partial\eta}\right]\cdot\mathbf{B}_\xi
319 \right).
320 \f]
321
322*/
324
325 /** \brief Class implemented by user to detect face orientation
326
327 If mesh generated is with surface mesher, usually you don't have to do
328 nothing, all elements on the surface have consistent orientation. In case of
329 internal faces or if you do something with mesh connectivity which breaks
330 orientation on the face, you have to implement method which will set
331 orientation to face.
332
333 */
335
337
338 virtual MoFEMErrorCode
345 virtual MoFEMErrorCode getElementOrientation(MoFEM::Interface &m_field,
346 const EntityHandle face) {
350 }
351 };
352
354
356
357 Mat B;
358 Vec F;
359
361 : MoFEM::FaceElementForcesAndSourcesCore(m_field), B(PETSC_NULLPTR),
362 F(PETSC_NULLPTR) {}
363 int getRule(int order) { return 2 * order; };
364
365 MoFEMErrorCode preProcess() {
367
369
370 if (B != PETSC_NULLPTR) {
371 snes_B = B;
372 }
373
374 if (F != PETSC_NULLPTR) {
375 snes_f = F;
376 }
377
379 }
380 };
381
382 boost::shared_ptr<MyTriangleFE> feRhsPtr, feLhsPtr;
383
384 MyTriangleFE &feRhs;
386 MyTriangleFE &feLhs;
388
389 DriverElementOrientation &crackFrontOrientation;
390
391 double aLpha;
392 MoFEMErrorCode getOptions() {
394 PetscOptionsBegin(PETSC_COMM_WORLD, "",
395 "Get surface sliding constrains element scaling", "none");
396 CHKERR PetscOptionsScalar("-surface_sliding_alpha", "scaling parameter", "",
397 aLpha, &aLpha, PETSC_NULLPTR);
398 PetscOptionsEnd();
400 }
401
403 DriverElementOrientation &orientation)
404 : mField(m_field), feRhsPtr(new MyTriangleFE(m_field)),
405 feLhsPtr(new MyTriangleFE(m_field)), feRhs(*feRhsPtr), feLhs(*feLhsPtr),
406 crackFrontOrientation(orientation), aLpha(1) {
407
408 ierr = getOptions();
409 CHKERRABORT(PETSC_COMM_WORLD, ierr);
410 }
411
412 virtual ~SurfaceSlidingConstrains() = default;
413
416
417 const int tAg;
418 boost::shared_ptr<VectorDouble> activeVariablesPtr;
419 boost::shared_ptr<VectorDouble> resultsPtr;
420 boost::shared_ptr<MatrixDouble> jacobianPtr;
422 bool evaluateJacobian;
423
424 const double &aLpha;
425
426 OpJacobian(int tag, const std::string field_name,
427 boost::shared_ptr<VectorDouble> &active_variables_ptr,
428 boost::shared_ptr<VectorDouble> &results_ptr,
429 boost::shared_ptr<MatrixDouble> &jacobian_ptr,
430 DriverElementOrientation &orientation, bool evaluate_jacobian,
431 const double &alpha)
434 tAg(tag), activeVariablesPtr(active_variables_ptr),
435 resultsPtr(results_ptr), jacobianPtr(jacobian_ptr),
436 oRientation(orientation), evaluateJacobian(evaluate_jacobian),
437 aLpha(alpha) {}
438
439 MoFEMErrorCode doWork(int side, EntityType type,
440 EntitiesFieldData::EntData &data) {
442 if (type != MBVERTEX)
444
445 VectorInt &indices = data.getIndices();
446
447 trace_on(tAg);
448
449 ublas::vector<adouble> lambda_dofs(3);
450 for (int dd = 0; dd != 3; ++dd) {
451 lambda_dofs[dd] <<= (*activeVariablesPtr)[dd];
452 }
453 ublas::vector<adouble> position_dofs(9);
454 for (int dd = 0; dd != 9; ++dd) {
455 position_dofs[dd] <<= (*activeVariablesPtr)[3 + dd];
456 }
457
458 FTensor::Index<'i', 3> i;
459 FTensor::Index<'j', 3> j;
460 FTensor::Index<'k', 3> k;
464
466 getFEMethod());
468
469 int nb_gauss_pts = data.getN().size1();
470 int nb_base_functions = data.getN().size2();
471 auto t_base1 = data.getFTensor0N();
472 auto t_base2 = data.getFTensor0N();
473 auto t_diff_base = data.getFTensor1DiffN<2>();
475 FTensor::Tensor1<adouble, 3> t_position_ksi;
476 FTensor::Tensor1<adouble, 3> t_position_eta;
480
481 ublas::vector<adouble> c_vec(3);
482 ublas::vector<adouble> f_vec(9);
483 c_vec.clear();
484 f_vec.clear();
485
486 auto t_coord_ref = getFTensor1CoordsAtGaussPts();
487
488 for (int gg = 0; gg != nb_gauss_pts; ++gg) {
489
490 FTensor::Tensor1<adouble *, 3> t_position_dofs(
491 &position_dofs[0], &position_dofs[1], &position_dofs[2], 3);
492 FTensor::Tensor0<adouble *> t_lambda_dof(&lambda_dofs[0]);
493
494 t_position(i) = 0;
495 t_position_ksi(i) = 0;
496 t_position_eta(i) = 0;
497 lambda = 0;
498
499 for (int bb = 0; bb != nb_base_functions; ++bb) {
500 t_position(i) += t_base1 * t_position_dofs(i);
501 t_position_ksi(i) += t_diff_base(N0) * t_position_dofs(i);
502 t_position_eta(i) += t_diff_base(N1) * t_position_dofs(i);
503 lambda += t_base1 * t_lambda_dof;
504 ++t_base1;
505 ++t_position_dofs;
506 ++t_lambda_dof;
507 ++t_diff_base;
508 }
509
510 t_delta(i) = t_position(i) - t_coord_ref(i);
511 t_normal(k) = FTensor::cross(t_position_ksi(i), t_position_eta(j), k);
512
513 double w = getGaussPts()(2, gg) * 0.5 * aLpha;
514 adouble val;
515 FTensor::Tensor0<adouble *> t_c(&c_vec[0]);
516 FTensor::Tensor1<adouble *, 3> t_f(&f_vec[0], &f_vec[1], &f_vec[2], 3);
517
518 adouble area = sqrt(t_normal(i) * t_normal(i));
519
520 for (int bb = 0; bb != nb_base_functions; ++bb) {
521 if (indices[bb] != -1) {
522 val = w * eo * t_base2;
523 t_c += val * t_normal(i) * t_delta(i);
524 val *= lambda;
525 t_f(i) += val * t_normal(i);
526 }
527 ++t_c;
528 ++t_f;
529 ++t_base2;
530 }
531
532 ++t_coord_ref;
533 }
534
535 for (int rr = 0; rr != 3; ++rr)
536 c_vec[rr] >>= (*resultsPtr)[rr];
537
538 for (int rr = 0; rr != 9; ++rr)
539 f_vec(rr) >>= (*resultsPtr)[3 + rr];
540
541 trace_off();
542
543 if (evaluateJacobian) {
544 double *jac_ptr[3 + 9];
545 for (int rr = 0; rr != 3 + 9; ++rr)
546 jac_ptr[rr] = &(*jacobianPtr)(rr, 0);
547
548 // play recorder for jacobians
549 int r =
550 ::jacobian(tAg, 3 + 9, 3 + 9, &(*activeVariablesPtr)[0], jac_ptr);
551 if (r < 0)
552 SETERRQ(PETSC_COMM_SELF, MOFEM_OPERATION_UNSUCCESSFUL,
553 "ADOL-C function evaluation with error");
554 }
555
557 }
558 };
559
560 MoFEMErrorCode setOperators(int tag,
561 const std::string lagrange_multipliers_field_name,
562 const std::string material_field_name,
563 const double *alpha = nullptr) {
565
566 if (alpha != nullptr) {
567 aLpha = *alpha;
568 }
569
570 boost::shared_ptr<VectorDouble> active_variables_ptr(
571 new VectorDouble(3 + 9));
572 boost::shared_ptr<VectorDouble> results_ptr(new VectorDouble(3 + 9));
573 boost::shared_ptr<MatrixDouble> jacobian_ptr(
574 new MatrixDouble(3 + 9, 3 + 9));
575
576 feRhs.getOpPtrVector().clear();
578 lagrange_multipliers_field_name, active_variables_ptr));
580 material_field_name, active_variables_ptr));
581 feRhs.getOpPtrVector().push_back(new OpJacobian(
582 tag, lagrange_multipliers_field_name, active_variables_ptr, results_ptr,
583 jacobian_ptr, crackFrontOrientation, false, aLpha));
584 feRhs.getOpPtrVector().push_back(
585 new OpAssembleRhs<3, 9>(lagrange_multipliers_field_name, results_ptr));
586 feRhs.getOpPtrVector().push_back(
587 new OpAssembleRhs<3, 9>(material_field_name, results_ptr));
588
589 // Adding operators to calculate the left hand side
590 feLhs.getOpPtrVector().clear();
592 lagrange_multipliers_field_name, active_variables_ptr));
594 material_field_name, active_variables_ptr));
595 feLhs.getOpPtrVector().push_back(new OpJacobian(
596 tag, lagrange_multipliers_field_name, active_variables_ptr, results_ptr,
597 jacobian_ptr, crackFrontOrientation, true, aLpha));
599 lagrange_multipliers_field_name, material_field_name, jacobian_ptr));
601 material_field_name, lagrange_multipliers_field_name, jacobian_ptr));
603 material_field_name, material_field_name, jacobian_ptr));
604
606 }
607
608 MoFEMErrorCode
610 const std::string lagrange_multipliers_field_name,
611 const std::string material_field_name) {
613
614 boost::shared_ptr<VectorDouble> active_variables_ptr(
615 new VectorDouble(3 + 9));
616 boost::shared_ptr<VectorDouble> results_ptr(new VectorDouble(3 + 9));
617 boost::shared_ptr<MatrixDouble> jacobian_ptr(
618 new MatrixDouble(3 + 9, 3 + 9));
619
620 // Adding operators to calculate the left hand side
621 feLhs.getOpPtrVector().clear();
623 lagrange_multipliers_field_name, active_variables_ptr));
625 material_field_name, active_variables_ptr));
626 feLhs.getOpPtrVector().push_back(new OpJacobian(
627 tag, lagrange_multipliers_field_name, active_variables_ptr, results_ptr,
628 jacobian_ptr, crackFrontOrientation, true, aLpha));
630 lagrange_multipliers_field_name, material_field_name, jacobian_ptr));
631
633 }
634};
635
637
639
640 static MoFEMErrorCode createTag(moab::Interface &moab, Tag &th0, Tag &th1,
641 Tag &th2, Tag &th3) {
643 double def_val[] = {0, 0, 0};
644 CHKERR moab.tag_get_handle("EDGE_BASE0", 3, MB_TYPE_DOUBLE, th0,
645 MB_TAG_CREAT | MB_TAG_SPARSE, def_val);
646 CHKERR moab.tag_get_handle("EDGE_BASE1", 3, MB_TYPE_DOUBLE, th1,
647 MB_TAG_CREAT | MB_TAG_SPARSE, def_val);
648 int def_numb_val[] = {-1};
649 CHKERR moab.tag_get_handle("PATCH_NUMBER", 1, MB_TYPE_INTEGER, th2,
650 MB_TAG_CREAT | MB_TAG_SPARSE, def_numb_val);
651 int def_orientation_val[] = {1};
652 CHKERR moab.tag_get_handle("PATCH_ORIENTATION", 1, MB_TYPE_INTEGER, th3,
653 MB_TAG_CREAT | MB_TAG_SPARSE,
654 def_orientation_val);
655
657 }
658
659 static MoFEMErrorCode numberSurfaces(moab::Interface &moab, Range edges,
660 Range tris) {
662
663 auto get_edges = [&](const Range &ents) {
664 Range edges;
665 CHKERR moab.get_adjacencies(ents, 1, false, edges,
666 moab::Interface::UNION);
667 return edges;
668 };
669
670 auto get_face_adj = [&, get_edges](const Range &faces) {
671 Range adj_faces;
672 CHKERR moab.get_adjacencies(subtract(get_edges(faces), edges), 2, false,
673 adj_faces, moab::Interface::UNION);
674 return intersect(adj_faces, tris);
675 };
676
677 auto get_patch = [&, get_face_adj](const EntityHandle face) {
678 Range patch_ents;
679 patch_ents.insert(face);
680 unsigned int nb0;
681 do {
682 nb0 = patch_ents.size();
683 patch_ents.merge(get_face_adj(patch_ents));
684 } while (nb0 != patch_ents.size());
685 return patch_ents;
686 };
687
688 auto get_patches = [&]() {
689 std::vector<Range> patches;
690 while (!tris.empty()) {
691 patches.push_back(get_patch(tris[0]));
692 tris = subtract(tris, patches.back());
693 }
694 return patches;
695 };
696
697 Tag th0, th1, th2, th3;
698 CHKERR createTag(moab, th0, th1, th2, th3);
699
700 auto patches = get_patches();
701 int pp = 0;
702 for (auto patch : patches) {
703 // cerr << "pp: " << pp << endl;
704 // cerr << patch << endl;
705 std::vector<int> tags_vals(patch.size(), pp);
706 CHKERR moab.tag_set_data(th2, patch, &*tags_vals.begin());
707 ++pp;
708 }
709
711 }
712
713 static MoFEMErrorCode setTags(
714 moab::Interface &moab, Range edges, Range tris,
715 bool number_pathes = true,
716 boost::shared_ptr<SurfaceSlidingConstrains::DriverElementOrientation>
717 surface_orientation = nullptr,
718 MoFEM::Interface *m_field_ptr = nullptr) {
720 Tag th0, th1, th2, th3;
721 CHKERR createTag(moab, th0, th1, th2, th3);
722 if (number_pathes) {
723 CHKERR numberSurfaces(moab, edges, tris);
724 }
725 for (auto edge : edges) {
726 Range adj_faces;
727 CHKERR moab.get_adjacencies(&edge, 1, 2, false, adj_faces);
728 adj_faces = intersect(adj_faces, tris);
729 if (adj_faces.size() != 2) {
730 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
731 "Should be 2 faces adjacent to edge but is %ld",
732 adj_faces.size());
733 }
734 VectorDouble3 v[2] = {VectorDouble3(3), VectorDouble3(3)};
735 auto get_tensor_from_vec = [](VectorDouble3 &v) {
737 &v[0], &v[1], &v[2]);
738 };
739
740 FTensor::Index<'i', 3> i;
741 FTensor::Index<'j', 3> j;
742 FTensor::Index<'k', 3> k;
743
744 std::array<double, 3> areas;
745 auto calculate_normals = [&, get_tensor_from_vec]() {
746 int ff = 0;
747 for (auto face : adj_faces) {
748 double &x = (v[ff])[0];
749 double &y = (v[ff])[1];
750 double &z = (v[ff])[2];
751 moab::Util::normal(&moab, face, x, y, z);
752 auto t_n = get_tensor_from_vec(v[ff]);
753 areas[ff] = sqrt(t_n(i) * t_n(i));
754 t_n(i) /= areas[ff];
755 int orientation;
756 // FIXME: this tag is empty
757 CHKERR moab.tag_get_data(th3, &face, 1, &orientation);
758 if (orientation == -1) {
759 t_n(i) *= -1;
760 }
761 if (surface_orientation && m_field_ptr) {
762 CHKERR surface_orientation->getElementOrientation(*m_field_ptr,
763 face);
764 int eo = surface_orientation->elementOrientation;
765 if (eo == -1) {
766 t_n(i) *= -1;
767 }
768 }
769 ++ff;
770 }
771 };
772 calculate_normals();
773
774 auto get_patch_number = [&]() {
775 std::vector<int> p = {0, 0};
776 CHKERR moab.tag_get_data(th2, adj_faces, &*p.begin());
777 return p;
778 };
779
780 std::array<EntityHandle, 2> faces_handles = {adj_faces[0],
781 adj_faces[1]};
782 auto order_normals = [&, get_patch_number]() {
783 auto p = get_patch_number();
784 if (p[0] < p[1]) {
785 v[0].swap(v[1]);
786 faces_handles[0] = adj_faces[1];
787 faces_handles[1] = adj_faces[0];
788 }
789 };
790 order_normals();
791
793 auto t_n0 = get_tensor_from_vec(v[0]);
794 auto t_n1 = get_tensor_from_vec(v[1]);
795 t_cross(k) = FTensor::cross(t_n0(i), t_n1(j), k);
796
797 auto get_base_for_coplanar_faces = [&]() {
799
800 std::vector<EntityHandle> face_conn;
801 CHKERR moab.get_connectivity(&faces_handles[1], 1, face_conn, true);
802 std::vector<EntityHandle> edge_conn;
803 CHKERR moab.get_connectivity(&edge, 1, edge_conn, true);
804 std::sort(face_conn.begin(), face_conn.end());
805 std::sort(edge_conn.begin(), edge_conn.end());
806 int n = 0;
807 for (; n != 2; ++n)
808 if (face_conn[n] != edge_conn[n])
809 break;
810 VectorDouble3 coords_face(3);
811 CHKERR moab.get_coords(&face_conn[n], 1,
812 &*coords_face.data().begin());
813 VectorDouble6 coords_edge(6);
814 CHKERR moab.get_coords(&edge_conn[0], 2,
815 &*coords_edge.data().begin());
816 auto t_edge_n0 = FTensor::Tensor1<double, 3>(
817 coords_edge[0], coords_edge[1], coords_edge[2]);
818 auto t_edge_n1 = FTensor::Tensor1<double, 3>(
819 coords_edge[3], coords_edge[4], coords_edge[5]);
820 auto t_face_n = get_tensor_from_vec(coords_face);
821 t_face_n(i) -= t_edge_n0(i);
823 t_delta(i) = t_edge_n1(i) - t_edge_n0(i);
824 t_delta(i) /= sqrt(t_delta(i) * t_delta(i));
825 t_n1(k) = FTensor::cross(t_n0(i), t_delta(j), k);
826 if (t_n1(i) * t_face_n(i) < 0)
827 t_n1(i) *= -1;
828
830 };
831
832 auto get_base_for_not_planar_faces = [&]() {
834 t_n1(k) = FTensor::cross(t_n0(i), t_cross(j), k);
835 t_n1(i) /= sqrt(t_n1(i) * t_n1(i));
837 };
838
839 // This a case when faces adjacent to edge are coplanar !!!
840 constexpr double tol = 1e-6;
841 if ((t_cross(i) * t_cross(i)) < tol)
842 CHKERR get_base_for_coplanar_faces();
843 else
844 CHKERR get_base_for_not_planar_faces();
845
846 VectorDouble3 &v0 = v[0];
847 VectorDouble3 &v1 = v[1];
848 CHKERR moab.tag_set_data(th0, &edge, 1, &v0[0]);
849 CHKERR moab.tag_set_data(th1, &edge, 1, &v1[0]);
850 }
852 }
853
854 static MoFEMErrorCode saveEdges(moab::Interface &moab, std::string name,
855 Range edges, Range *faces = nullptr) {
857 EntityHandle meshset;
858 Tag ths[4];
859 CHKERR createTag(moab, ths[0], ths[1], ths[2], ths[3]);
860 CHKERR moab.create_meshset(MESHSET_SET, meshset);
861 CHKERR moab.add_entities(meshset, edges);
862 if (faces != nullptr) {
863 CHKERR moab.add_entities(meshset, *faces);
864 }
865 CHKERR moab.write_file(name.c_str(), "VTK", "", &meshset, 1, ths, 4);
866 CHKERR moab.delete_entities(&meshset, 1);
868 }
869 };
870
872
874
875 Mat B;
876 Vec F;
877
879 : MoFEM::EdgeElementForcesAndSourcesCore(m_field), B(PETSC_NULLPTR),
880 F(PETSC_NULLPTR) {}
881 int getRule(int order) { return 2 * order; };
882
883 MoFEMErrorCode preProcess() {
885
887
888 if (B != PETSC_NULLPTR) {
889 snes_B = B;
890 }
891
892 if (F != PETSC_NULLPTR) {
893 snes_f = F;
894 }
895
897 }
898 };
899
900 boost::shared_ptr<MyEdgeFE> feRhsPtr, feLhsPtr;
901
902 MyEdgeFE &feRhs;
904 MyEdgeFE &feLhs;
906
907 double aLpha;
908
909 MoFEMErrorCode getOptions() {
911 PetscOptionsBegin(PETSC_COMM_WORLD, "",
912 "Get edge sliding constrains element scaling",
913 "none");
914 CHKERR PetscOptionsScalar("-edge_sliding_alpha", "scaling parameter", "",
915 aLpha, &aLpha, PETSC_NULLPTR);
916 PetscOptionsEnd();
918 }
919
921 : mField(m_field), feRhsPtr(new MyEdgeFE(m_field)),
922 feLhsPtr(new MyEdgeFE(m_field)), feRhs(*feRhsPtr), feLhs(*feLhsPtr),
923 aLpha(1) {
924 ierr = getOptions();
925 CHKERRABORT(PETSC_COMM_WORLD, ierr);
926 }
927
930
931 const int tAg;
932 boost::shared_ptr<VectorDouble> activeVariablesPtr;
933 boost::shared_ptr<VectorDouble> resultsPtr;
934 boost::shared_ptr<MatrixDouble> jacobianPtr;
935 bool evaluateJacobian;
936
937 const double &aLpha;
938
939 OpJacobian(int tag, const std::string field_name,
940 boost::shared_ptr<VectorDouble> &active_variables_ptr,
941 boost::shared_ptr<VectorDouble> &results_ptr,
942 boost::shared_ptr<MatrixDouble> &jacobian_ptr,
943 bool evaluate_jacobian, const double &alpha)
946 tAg(tag), activeVariablesPtr(active_variables_ptr),
947 resultsPtr(results_ptr), jacobianPtr(jacobian_ptr),
948 evaluateJacobian(evaluate_jacobian), aLpha(alpha) {}
949
950 MoFEMErrorCode doWork(int side, EntityType type,
951 EntitiesFieldData::EntData &data) {
953 if (type != MBVERTEX)
955
956 FTensor::Index<'i', 3> i;
957 FTensor::Index<'j', 2> j;
960
961 Tag th0, th1, th2, th3;
963 th1, th2, th3);
964 FTensor::Tensor1<double, 3> t_edge_base0, t_edge_base1;
966 CHKERR getEdgeFE()->mField.get_moab().tag_get_data(th0, &fe_ent, 1,
967 &t_edge_base0(0));
968 CHKERR getEdgeFE()->mField.get_moab().tag_get_data(th1, &fe_ent, 1,
969 &t_edge_base1(0));
970
971 VectorInt &indices = data.getIndices();
972
973 trace_on(tAg);
974
975 ublas::vector<adouble> lambda_dofs(4);
976 for (int dd = 0; dd != 4; ++dd) {
977 lambda_dofs[dd] <<= (*activeVariablesPtr)[dd];
978 }
979 ublas::vector<adouble> position_dofs(6);
980 for (int dd = 0; dd != 6; ++dd) {
981 position_dofs[dd] <<= (*activeVariablesPtr)[4 + dd];
982 }
983
985 &position_dofs[0], &position_dofs[1], &position_dofs[2]);
987 &position_dofs[3], &position_dofs[4], &position_dofs[5]);
988
990 t_tangent(i) = t_node1(i) - t_node0(i);
991 adouble l = sqrt(t_tangent(i) * t_tangent(i));
992 t_tangent(i) /= l;
993
994 adouble t_dot0, t_dot1;
995 t_dot0 = t_edge_base0(i) * t_tangent(i);
996 t_dot1 = t_edge_base1(i) * t_tangent(i);
997
998 FTensor::Tensor1<adouble, 3> t_base0, t_base1;
999 t_base0(i) = t_edge_base0(i) - t_dot0 * t_tangent(i);
1000 t_base1(i) = t_edge_base1(i) - t_dot1 * t_tangent(i);
1001 t_base0(i) /= sqrt(t_base0(i) * t_base0(i));
1002 t_base1(i) /= sqrt(t_base1(i) * t_base1(i));
1003
1004 auto t_base_fun1 = data.getFTensor0N();
1005 auto t_base_fun2 = data.getFTensor0N();
1009 auto t_coord_ref = getFTensor1CoordsAtGaussPts();
1010
1011 ublas::vector<adouble> c_vec(4);
1012 ublas::vector<adouble> f_vec(6);
1013 c_vec.clear();
1014 f_vec.clear();
1015
1016 int nb_gauss_pts = data.getN().size1();
1017 int nb_base_functions = data.getN().size2();
1018 for (int gg = 0; gg != nb_gauss_pts; ++gg) {
1019
1020 FTensor::Tensor1<adouble *, 3> t_position_dofs(
1021 &position_dofs[0], &position_dofs[1], &position_dofs[2], 3);
1022 FTensor::Tensor1<adouble *, 2> t_lambda_dof(&lambda_dofs[0],
1023 &lambda_dofs[1], 2);
1024
1025 t_position(i) = 0;
1026 t_lambda(j) = 0;
1027 for (int bb = 0; bb != nb_base_functions; ++bb) {
1028 t_position(i) += t_base_fun1 * t_position_dofs(i);
1029 t_lambda(j) += t_base_fun1 * t_lambda_dof(j);
1030 ++t_base_fun1;
1031 ++t_position_dofs;
1032 ++t_lambda_dof;
1033 }
1034
1035 t_delta(i) = t_position(i) - t_coord_ref(i);
1036 adouble dot0 = t_base0(i) * t_delta(i);
1037 adouble dot1 = t_base1(i) * t_delta(i);
1038
1039 adouble w = getGaussPts()(1, gg) * l * aLpha;
1040 adouble val, val1, val2;
1041 FTensor::Tensor1<adouble *, 2> t_c(&c_vec[0], &c_vec[1], 2);
1042 FTensor::Tensor1<adouble *, 3> t_f(&f_vec[0], &f_vec[1], &f_vec[2], 3);
1043 for (int bb = 0; bb != nb_base_functions; ++bb) {
1044 if (indices[2 * bb] != -1) {
1045 val = w * t_base_fun2;
1046 t_c(N0) += val * dot0;
1047 t_c(N1) += val * dot1;
1048 val1 = val * t_lambda(N0);
1049 val2 = val * t_lambda(N1);
1050 t_f(i) += val1 * t_base0(i) + val2 * t_base1(i);
1051 }
1052 ++t_c;
1053 ++t_f;
1054 ++t_base_fun2;
1055 }
1056
1057 ++t_coord_ref;
1058 }
1059
1060 for (int rr = 0; rr != 4; ++rr) {
1061 c_vec[rr] >>= (*resultsPtr)[rr];
1062 }
1063 for (int rr = 0; rr != 6; ++rr) {
1064 f_vec(rr) >>= (*resultsPtr)[4 + rr];
1065 }
1066
1067 trace_off();
1068
1069 if (evaluateJacobian) {
1070 double *jac_ptr[4 + 6];
1071 for (int rr = 0; rr != 4 + 6; ++rr) {
1072 jac_ptr[rr] = &(*jacobianPtr)(rr, 0);
1073 }
1074 // play recorder for jacobians
1075 int r =
1076 ::jacobian(tAg, 4 + 6, 4 + 6, &(*activeVariablesPtr)[0], jac_ptr);
1077 if (r < 0) {
1078 SETERRQ(PETSC_COMM_SELF, MOFEM_OPERATION_UNSUCCESSFUL,
1079 "ADOL-C function evaluation with error");
1080 }
1081 }
1082
1084 }
1085 };
1086
1087 MoFEMErrorCode setOperators(int tag, Range edges, Range faces,
1088 const std::string lagrange_multipliers_field_name,
1089 const std::string material_field_name) {
1092 edges, faces);
1093 CHKERR setOperators(tag, lagrange_multipliers_field_name,
1094 material_field_name);
1096 }
1097
1098 MoFEMErrorCode setOperators(int tag,
1099 const std::string lagrange_multipliers_field_name,
1100 const std::string material_field_name,
1101 const double *alpha = nullptr) {
1103
1104 if (alpha) {
1105 aLpha = *alpha;
1106 }
1107
1108 boost::shared_ptr<VectorDouble> active_variables_ptr(
1109 new VectorDouble(4 + 6));
1110 boost::shared_ptr<VectorDouble> results_ptr(new VectorDouble(4 + 6));
1111 boost::shared_ptr<MatrixDouble> jacobian_ptr(
1112 new MatrixDouble(4 + 6, 4 + 6));
1113
1114 feRhs.getOpPtrVector().clear();
1116 lagrange_multipliers_field_name, active_variables_ptr));
1118 material_field_name, active_variables_ptr));
1119 feRhs.getOpPtrVector().push_back(new OpJacobian(
1120 tag, lagrange_multipliers_field_name, active_variables_ptr, results_ptr,
1121 jacobian_ptr, false, aLpha));
1122 feRhs.getOpPtrVector().push_back(
1123 new OpAssembleRhs<4, 6>(lagrange_multipliers_field_name, results_ptr));
1124 feRhs.getOpPtrVector().push_back(
1125 new OpAssembleRhs<4, 6>(material_field_name, results_ptr));
1126
1127 // Adding operators to calculate the left hand side
1128 feLhs.getOpPtrVector().clear();
1130 lagrange_multipliers_field_name, active_variables_ptr));
1132 material_field_name, active_variables_ptr));
1133 feLhs.getOpPtrVector().push_back(new OpJacobian(
1134 tag, lagrange_multipliers_field_name, active_variables_ptr, results_ptr,
1135 jacobian_ptr, true, aLpha));
1137 lagrange_multipliers_field_name, material_field_name, jacobian_ptr));
1139 material_field_name, lagrange_multipliers_field_name, jacobian_ptr));
1141 material_field_name, material_field_name, jacobian_ptr));
1142
1144 }
1145
1146 MoFEMErrorCode
1148 const std::string lagrange_multipliers_field_name,
1149 const std::string material_field_name) {
1151
1153 edges, faces);
1154 CHKERR setOperatorsConstrainOnly(tag, lagrange_multipliers_field_name,
1155 material_field_name);
1157 }
1158
1159 MoFEMErrorCode
1161 const std::string lagrange_multipliers_field_name,
1162 const std::string material_field_name) {
1164
1165 boost::shared_ptr<VectorDouble> active_variables_ptr(
1166 new VectorDouble(4 + 6));
1167 boost::shared_ptr<VectorDouble> results_ptr(new VectorDouble(4 + 6));
1168 boost::shared_ptr<MatrixDouble> jacobian_ptr(
1169 new MatrixDouble(4 + 6, 4 + 6));
1170
1171 // Adding operators to calculate the left hand side
1172 feLhs.getOpPtrVector().clear();
1174 lagrange_multipliers_field_name, active_variables_ptr));
1176 material_field_name, active_variables_ptr));
1177 feLhs.getOpPtrVector().push_back(new OpJacobian(
1178 tag, lagrange_multipliers_field_name, active_variables_ptr, results_ptr,
1179 jacobian_ptr, true, aLpha));
1181 lagrange_multipliers_field_name, material_field_name, jacobian_ptr));
1182
1184 }
1185};
1186
1187#endif // WITH_ADOL_C
1188
1189#endif // __SURFACE_SLIDING_CONSTRAINS_HPP__
ForcesAndSourcesCore::UserDataOperator UserDataOperator
static PetscErrorCode ierr
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_OPERATION_UNSUCCESSFUL
Definition definitions.h:34
@ 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 ...
constexpr int order
FTensor::Index< 'i', SPACE_DIM > i
static double lambda
const double v
phase velocity of light in medium (cm/ns)
const double n
refractive index of diffusive medium
FTensor::Index< 'l', 3 > l
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
double tol
auto cross(const Tensor1_Expr< A, T, 3, i > &a, const Tensor1_Expr< B, U, 3, j > &b, const Index< k, 3 > &)
Definition cross.hpp:10
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
constexpr auto field_name
static MoFEMErrorCode numberSurfaces(moab::Interface &moab, Range edges, Range tris)
static MoFEMErrorCode createTag(moab::Interface &moab, Tag &th0, Tag &th1, Tag &th2, Tag &th3)
static MoFEMErrorCode setTags(moab::Interface &moab, Range edges, Range tris, bool number_pathes=true, boost::shared_ptr< SurfaceSlidingConstrains::DriverElementOrientation > surface_orientation=nullptr, MoFEM::Interface *m_field_ptr=nullptr)
static MoFEMErrorCode saveEdges(moab::Interface &moab, std::string name, Range edges, Range *faces=nullptr)
MoFEMErrorCode preProcess()
function is run at the beginning of loop
boost::shared_ptr< VectorDouble > activeVariablesPtr
boost::shared_ptr< VectorDouble > resultsPtr
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
OpJacobian(int tag, const std::string field_name, boost::shared_ptr< VectorDouble > &active_variables_ptr, boost::shared_ptr< VectorDouble > &results_ptr, boost::shared_ptr< MatrixDouble > &jacobian_ptr, bool evaluate_jacobian, const double &alpha)
boost::shared_ptr< MatrixDouble > jacobianPtr
MoFEMErrorCode setOperators(int tag, Range edges, Range faces, const std::string lagrange_multipliers_field_name, const std::string material_field_name)
EdgeSlidingConstrains(MoFEM::Interface &m_field)
boost::shared_ptr< MyEdgeFE > feRhsPtr
MoFEMErrorCode setOperators(int tag, const std::string lagrange_multipliers_field_name, const std::string material_field_name, const double *alpha=nullptr)
boost::shared_ptr< MyEdgeFE > feLhsPtr
MoFEMErrorCode setOperatorsConstrainOnly(int tag, Range edges, Range faces, const std::string lagrange_multipliers_field_name, const std::string material_field_name)
MoFEMErrorCode setOperatorsConstrainOnly(int tag, const std::string lagrange_multipliers_field_name, const std::string material_field_name)
boost::shared_ptr< MatrixDouble > jacobianPtr
OpAssembleLhs(const std::string field_name_row, const std::string field_name_col, boost::shared_ptr< MatrixDouble > &jacobian_ptr)
MoFEMErrorCode doWork(int row_side, int col_side, EntityType row_type, EntityType col_type, EntitiesFieldData::EntData &row_data, EntitiesFieldData::EntData &col_data)
OpAssembleRhs(const std::string field_name, boost::shared_ptr< VectorDouble > &results_ptr)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
boost::shared_ptr< VectorDouble > resultsPtr
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
OpGetActiveDofsLambda(const std::string field_name, boost::shared_ptr< VectorDouble > &active_variables_ptr)
boost::shared_ptr< VectorDouble > activeVariablesPtr
OpGetActiveDofsPositions(const std::string field_name, boost::shared_ptr< VectorDouble > &active_variables_ptr)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
boost::shared_ptr< VectorDouble > activeVariablesPtr
Implementation of surface sliding constrains.
virtual ~GenericSliding()=default
GenericSliding()=default
virtual moab::Interface & get_moab()=0
bool sYmm
If true assume that matrix is symmetric structure.
Deprecated interface functions.
const EdgeElementForcesAndSourcesCore * getEdgeFE()
get pointer to this finite element
FaceElementForcesAndSourcesCore * getFaceFE()
return pointer to Generic Triangle Finite Element object
EntityHandle getFEEntityHandle() const
Return finite element entity handle.
auto getFTensor1CoordsAtGaussPts()
Get coordinates at integration points assuming linear geometry.
std::string getFEName() const
Get name of the element.
@ OPCOL
operator doWork function is executed on FE columns
@ OPROW
operator doWork function is executed on FE rows
@ OPROWCOL
operator doWork is executed on FE rows &columns
const FEMethod * getFEMethod() const
Return raw pointer to Finite Element Method object.
MatrixDouble & getGaussPts()
matrix of integration (Gauss) points for Volume Element
virtual MoFEMErrorCode preProcess()
function is run at the beginning of loop
boost::ptr_deque< UserDataOperator > & getOpPtrVector()
Use to push back operator for row operator.
Vec & snes_f
residual
Mat & snes_B
preconditioner of jacobian matrix
Class implemented by user to detect face orientation.
virtual MoFEMErrorCode getElementOrientation(MoFEM::Interface &m_field, const EntityHandle face)
virtual MoFEMErrorCode getElementOrientation(MoFEM::Interface &m_field, const FEMethod *fe_method_ptr)
MoFEMErrorCode preProcess()
function is run at the beginning of loop
OpJacobian(int tag, const std::string field_name, boost::shared_ptr< VectorDouble > &active_variables_ptr, boost::shared_ptr< VectorDouble > &results_ptr, boost::shared_ptr< MatrixDouble > &jacobian_ptr, DriverElementOrientation &orientation, bool evaluate_jacobian, const double &alpha)
boost::shared_ptr< VectorDouble > resultsPtr
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
boost::shared_ptr< VectorDouble > activeVariablesPtr
boost::shared_ptr< MatrixDouble > jacobianPtr
Shape preserving constrains, i.e. nodes sliding on body surface.
boost::shared_ptr< MyTriangleFE > feRhsPtr
virtual ~SurfaceSlidingConstrains()=default
DriverElementOrientation & crackFrontOrientation
boost::shared_ptr< MyTriangleFE > feLhsPtr
SurfaceSlidingConstrains(MoFEM::Interface &m_field, DriverElementOrientation &orientation)
MoFEMErrorCode setOperators(int tag, const std::string lagrange_multipliers_field_name, const std::string material_field_name, const double *alpha=nullptr)
MoFEMErrorCode setOperatorsConstrainOnly(int tag, const std::string lagrange_multipliers_field_name, const std::string material_field_name)