v0.16.3
Loading...
Searching...
No Matches
ContactOps.hpp
Go to the documentation of this file.
1
2
3/**
4 * \file ContactOps.hpp
5 * \example mofem/tutorials/adv-1_contact/src/ContactOps.hpp
6 */
7
8#ifndef __CONTACTOPS_HPP__
9#define __CONTACTOPS_HPP__
10
11namespace ContactOps {
12
13/** Indices into CommonData::totalTractionAndArea. */
22
23//! [Common data]
24struct CommonData : public boost::enable_shared_from_this<CommonData> {
25 // MatrixDouble contactStress;
26 MatrixDouble contactTraction;
27 MatrixDouble contactDisp;
28 MatrixDouble contactDispGrad;
29
30 VectorDouble sdfVals; ///< size is equal to number of gauss points on element
31 MatrixDouble gradsSdf; ///< nb of rows is equals to number of gauss points on
32 ///< element, and nb of cols is equals to dimension
33 MatrixDouble hessSdf; ///< nb of rows is equals to nb of element of symmetric
34 ///< matrix, and nb of cols is equals to number of gauss
35 ///< points on element
36 VectorDouble constraintVals;
37
38 static SmartPetscObj<Vec>
39 totalTractionAndArea; // User have to release and create vector when appropiate.
40
41 static auto createTotalTraction(MoFEM::Interface &m_field) {
42 constexpr int ghosts[] = {TX, TY, TZ, AREA_ACTIVE, AREA_POTENTIAL};
43 totalTractionAndArea = createGhostVector(
44 m_field.get_comm(),
45
46 (m_field.get_comm_rank() == 0) ? LAST_TOTAL_TRACTION_AND_AREA : 0,
48
49 (m_field.get_comm_rank() == 0) ? 0 : LAST_TOTAL_TRACTION_AND_AREA,
50 ghosts);
52 }
53
56 const double *t_ptr;
58 "get array");
60 t_ptr[TX], t_ptr[TY], t_ptr[TZ], t_ptr[AREA_ACTIVE],
61 t_ptr[AREA_POTENTIAL]};
62 CHK_THROW_MESSAGE(VecRestoreArrayRead(CommonData::totalTractionAndArea, &t_ptr),
63 "restore array");
64 return t;
65 } else {
67 0., 0.};
68 }
69 }
70
71 inline auto contactTractionPtr() {
72 return boost::shared_ptr<MatrixDouble>(shared_from_this(),
74 }
75
76 inline auto contactDispPtr() {
77 return boost::shared_ptr<MatrixDouble>(shared_from_this(), &contactDisp);
78 }
79
80 inline auto contactDispGradPtr() {
81 return boost::shared_ptr<MatrixDouble>(shared_from_this(),
83 }
84
85 inline auto sdfPtr() {
86 return boost::shared_ptr<VectorDouble>(shared_from_this(), &sdfVals);
87 }
88
89 inline auto gradSdfPtr() {
90 return boost::shared_ptr<MatrixDouble>(shared_from_this(), &gradsSdf);
91 }
92
93 inline auto hessSdfPtr() {
94 return boost::shared_ptr<MatrixDouble>(shared_from_this(), &hessSdf);
95 }
96
97 inline auto constraintPtr() {
98 return boost::shared_ptr<VectorDouble>(shared_from_this(), &constraintVals);
99 }
100};
101
102SmartPetscObj<Vec> CommonData::totalTractionAndArea;
103
104//! [Common data]
105
106//! [Surface distance function from python]
107#ifdef ENABLE_PYTHON_BINDING
108struct SDFPython {
109 SDFPython() = default;
110 virtual ~SDFPython() = default;
111
112 MoFEMErrorCode sdfInit(const std::string py_file) {
114 try {
115
116 // create main module
117 auto main_module = bp::import("__main__");
118 mainNamespace = main_module.attr("__dict__");
119 bp::exec_file(py_file.c_str(), mainNamespace, mainNamespace);
120 // create a reference to python function
121 sdfFun = mainNamespace["sdf"];
122 sdfGradFun = mainNamespace["grad_sdf"];
123 sdfHessFun = mainNamespace["hess_sdf"];
124
125 } catch (bp::error_already_set const &) {
126 // print all other errors to stderr
127 PyErr_Print();
129 }
131 };
132
133 template <typename T>
134 inline std::vector<T>
135 py_list_to_std_vector(const boost::python::object &iterable) {
136 return std::vector<T>(boost::python::stl_input_iterator<T>(iterable),
137 boost::python::stl_input_iterator<T>());
138 }
139
140 MoFEMErrorCode evalSdf(
141
142 double delta_t, double t, np::ndarray x, np::ndarray y, np::ndarray z,
143 np::ndarray tx, np::ndarray ty, np::ndarray tz, int block_id,
144 np::ndarray &sdf
145
146 ) {
148 try {
149
150 // call python function
151 sdf = bp::extract<np::ndarray>(
152 sdfFun(delta_t, t, x, y, z, tx, ty, tz, block_id));
153
154 } catch (bp::error_already_set const &) {
155 // print all other errors to stderr
156 PyErr_Print();
158 }
160 }
161
162 MoFEMErrorCode evalGradSdf(
163
164 double delta_t, double t, np::ndarray x, np::ndarray y, np::ndarray z,
165 np::ndarray tx, np::ndarray ty, np::ndarray tz, int block_id,
166 np::ndarray &grad_sdf
167
168 ) {
170 try {
171
172 // call python function
173 grad_sdf = bp::extract<np::ndarray>(
174 sdfGradFun(delta_t, t, x, y, z, tx, ty, tz, block_id));
175
176 } catch (bp::error_already_set const &) {
177 // print all other errors to stderr
178 PyErr_Print();
180 }
182 }
183
184 MoFEMErrorCode evalHessSdf(
185
186 double delta_t, double t, np::ndarray x, np::ndarray y, np::ndarray z,
187 np::ndarray tx, np::ndarray ty, np::ndarray tz, int block_id,
188 np::ndarray &hess_sdf
189
190 ) {
192 try {
193
194 // call python function
195 hess_sdf = bp::extract<np::ndarray>(
196 sdfHessFun(delta_t, t, x, y, z, tx, ty, tz, block_id));
197
198 } catch (bp::error_already_set const &) {
199 // print all other errors to stderr
200 PyErr_Print();
202 }
204 }
205
206private:
207 bp::object mainNamespace;
208 bp::object sdfFun;
209 bp::object sdfGradFun;
210 bp::object sdfHessFun;
211};
212
213static boost::weak_ptr<SDFPython> sdfPythonWeakPtr;
214
215inline np::ndarray convert_to_numpy(VectorDouble &data, int nb_gauss_pts,
216 int id) {
217 auto dtype = np::dtype::get_builtin<double>();
218 auto size = bp::make_tuple(nb_gauss_pts);
219 auto stride = bp::make_tuple(3 * sizeof(double));
220 return (np::from_data(&data[id], dtype, size, stride, bp::object()));
221};
222#endif
223//! [Surface distance function from python]
224
225using SurfaceDistanceFunction = boost::function<VectorDouble(
226 double delta_t, double t, int nb_gauss_pts, MatrixDouble &spatial_coords,
227 MatrixDouble &normals_at_pts, int block_id)>;
228
229using GradSurfaceDistanceFunction = boost::function<MatrixDouble(
230 double delta_t, double t, int nb_gauss_pts, MatrixDouble &spatial_coords,
231 MatrixDouble &normals_at_pts, int block_id)>;
232
233using HessSurfaceDistanceFunction = boost::function<MatrixDouble(
234 double delta_t, double t, int nb_gauss_pts, MatrixDouble &spatial_coords,
235 MatrixDouble &normals_at_pts, int block_id)>;
236
237inline VectorDouble surface_distance_function(double delta_t, double t,
238 int nb_gauss_pts,
239 MatrixDouble &m_spatial_coords,
240 MatrixDouble &m_normals_at_pts,
241 int block_id) {
242
243#ifdef ENABLE_PYTHON_BINDING
244 if (auto sdf_ptr = sdfPythonWeakPtr.lock()) {
245
246 VectorDouble v_spatial_coords = m_spatial_coords.data();
247 VectorDouble v_normal_at_pts = m_normals_at_pts.data();
248
249 bp::list python_coords;
250 bp::list python_normals;
251
252 for (int idx = 0; idx < 3; ++idx) {
253 python_coords.append(
254 convert_to_numpy(v_spatial_coords, nb_gauss_pts, idx));
255 python_normals.append(
256 convert_to_numpy(v_normal_at_pts, nb_gauss_pts, idx));
257 }
258
259 np::ndarray np_sdf = np::empty(bp::make_tuple(nb_gauss_pts),
260 np::dtype::get_builtin<double>());
261 CHK_MOAB_THROW(sdf_ptr->evalSdf(delta_t, t,
262 bp::extract<np::ndarray>(python_coords[0]),
263 bp::extract<np::ndarray>(python_coords[1]),
264 bp::extract<np::ndarray>(python_coords[2]),
265 bp::extract<np::ndarray>(python_normals[0]),
266 bp::extract<np::ndarray>(python_normals[1]),
267 bp::extract<np::ndarray>(python_normals[2]),
268 block_id, np_sdf),
269 "Failed python call");
270
271 // check the shape of returned array
272 if (np_sdf.get_nd() != 1 || np_sdf.get_shape()[0] != nb_gauss_pts) {
275 "Wrong number of dimensions or size of SDF returned from "
276 "python, expected: dim 1, got: " +
277 std::to_string(np_sdf.get_nd()) + ", expected size: (" +
278 std::to_string(nb_gauss_pts) + ")");
279 }
280
281 double *sdf_val_ptr = reinterpret_cast<double *>(np_sdf.get_data());
282
283 VectorDouble v_sdf;
284 v_sdf.resize(nb_gauss_pts, false);
285
286 for (size_t gg = 0; gg < nb_gauss_pts; ++gg)
287 v_sdf[gg] = *(sdf_val_ptr + gg);
288
289 return v_sdf;
290 }
291#endif
292 VectorDouble v_sdf;
293 v_sdf.resize(nb_gauss_pts, false);
294 auto t_coords = getFTensor1FromPtr<3>(&m_spatial_coords(0, 0));
295
296 for (size_t gg = 0; gg < nb_gauss_pts; ++gg) {
297 v_sdf[gg] = -t_coords(2) - 0.1;
298 ++t_coords;
299 }
300
301 return v_sdf;
302}
303
304inline MatrixDouble
305grad_surface_distance_function(double delta_t, double t, int nb_gauss_pts,
306 MatrixDouble &m_spatial_coords,
307 MatrixDouble &m_normals_at_pts, int block_id) {
308#ifdef ENABLE_PYTHON_BINDING
309 if (auto sdf_ptr = sdfPythonWeakPtr.lock()) {
310
311 VectorDouble v_spatial_coords = m_spatial_coords.data();
312 VectorDouble v_normal_at_pts = m_normals_at_pts.data();
313
314 bp::list python_coords;
315 bp::list python_normals;
316
317 for (int idx = 0; idx < 3; ++idx) {
318 python_coords.append(
319 convert_to_numpy(v_spatial_coords, nb_gauss_pts, idx));
320 python_normals.append(
321 convert_to_numpy(v_normal_at_pts, nb_gauss_pts, idx));
322 }
323
324 np::ndarray np_grad_sdf = np::empty(bp::make_tuple(nb_gauss_pts, 3),
325 np::dtype::get_builtin<double>());
326 CHK_MOAB_THROW(sdf_ptr->evalGradSdf(
327 delta_t, t, bp::extract<np::ndarray>(python_coords[0]),
328 bp::extract<np::ndarray>(python_coords[1]),
329 bp::extract<np::ndarray>(python_coords[2]),
330 bp::extract<np::ndarray>(python_normals[0]),
331 bp::extract<np::ndarray>(python_normals[1]),
332 bp::extract<np::ndarray>(python_normals[2]), block_id,
333 np_grad_sdf),
334 "Failed python call");
335
336 // check the shape of returned array
337 if (np_grad_sdf.get_shape()[0] != nb_gauss_pts ||
338 np_grad_sdf.get_shape()[1] != 3) {
340 "Wrong shape of gradient of SDF returned from "
341 "python, expected: (" +
342 std::to_string(nb_gauss_pts) + ", 3), got: (" +
343 std::to_string(np_grad_sdf.get_shape()[0]) + ", " +
344 std::to_string(np_grad_sdf.get_shape()[1]) + ")");
345 }
346
347 double *grad_ptr = reinterpret_cast<double *>(np_grad_sdf.get_data());
348
349 MatrixDouble m_grad_sdf;
350 m_grad_sdf.resize(nb_gauss_pts, 3, false);
351 for (size_t gg = 0; gg < nb_gauss_pts; ++gg) {
352 for (int idx = 0; idx < 3; ++idx)
353 m_grad_sdf(gg, idx) = *(grad_ptr + (3 * gg + idx));
354 }
355 return m_grad_sdf;
356 }
357#endif
358 MatrixDouble m_grad_sdf;
359 m_grad_sdf.resize(nb_gauss_pts, 3, false);
360 FTensor::Index<'i', 3> i;
361 FTensor::Tensor1<double, 3> t_grad_sdf_set{0.0, 0.0, -1.0};
362 auto t_grad_sdf = getFTensor1FromMat<3>(m_grad_sdf);
363
364 for (size_t gg = 0; gg < nb_gauss_pts; ++gg) {
365 t_grad_sdf(i) = t_grad_sdf_set(i);
366 ++t_grad_sdf;
367 }
368
369 return m_grad_sdf;
370}
371
372inline MatrixDouble
373hess_surface_distance_function(double delta_t, double t, int nb_gauss_pts,
374 MatrixDouble &m_spatial_coords,
375 MatrixDouble &m_normals_at_pts, int block_id) {
376#ifdef ENABLE_PYTHON_BINDING
377 if (auto sdf_ptr = sdfPythonWeakPtr.lock()) {
378
379 VectorDouble v_spatial_coords = m_spatial_coords.data();
380 VectorDouble v_normal_at_pts = m_normals_at_pts.data();
381
382 bp::list python_coords;
383 bp::list python_normals;
384
385 for (int idx = 0; idx < 3; ++idx) {
386 python_coords.append(
387 convert_to_numpy(v_spatial_coords, nb_gauss_pts, idx));
388 python_normals.append(
389 convert_to_numpy(v_normal_at_pts, nb_gauss_pts, idx));
390 };
391
392 np::ndarray np_hess_sdf = np::empty(bp::make_tuple(nb_gauss_pts, 6),
393 np::dtype::get_builtin<double>());
394 CHK_MOAB_THROW(sdf_ptr->evalHessSdf(
395 delta_t, t, bp::extract<np::ndarray>(python_coords[0]),
396 bp::extract<np::ndarray>(python_coords[1]),
397 bp::extract<np::ndarray>(python_coords[2]),
398 bp::extract<np::ndarray>(python_normals[0]),
399 bp::extract<np::ndarray>(python_normals[1]),
400 bp::extract<np::ndarray>(python_normals[2]), block_id,
401 np_hess_sdf),
402 "Failed python call");
403
404 // check the shape of returned array
405 if (np_hess_sdf.get_shape()[0] != nb_gauss_pts ||
406 np_hess_sdf.get_shape()[1] != 6) {
408 "Wrong shape of Hessian of SDF returned from "
409 "python, expected: (" +
410 std::to_string(nb_gauss_pts) + ", 6), got: (" +
411 std::to_string(np_hess_sdf.get_shape()[0]) + ", " +
412 std::to_string(np_hess_sdf.get_shape()[1]) + ")");
413 }
414
415 double *hess_ptr = reinterpret_cast<double *>(np_hess_sdf.get_data());
416
417 MatrixDouble m_hess_sdf;
418 m_hess_sdf.resize(nb_gauss_pts, 6, false);
419 for (size_t gg = 0; gg < nb_gauss_pts; ++gg) {
420 for (int idx = 0; idx < 6; ++idx)
421 m_hess_sdf(gg, idx) = *(hess_ptr + (6 * gg + idx));
422 }
423 return m_hess_sdf;
424 }
425#endif
426 MatrixDouble m_hess_sdf;
427 m_hess_sdf.resize(nb_gauss_pts, 6, false);
428 FTensor::Index<'i', 3> i;
429 FTensor::Index<'j', 3> j;
430 FTensor::Tensor2_symmetric<double, 3> t_hess_sdf_set{0., 0., 0., 0., 0., 0.};
431 auto t_hess_sdf = getFTensor2SymmetricFromMat<3>(m_hess_sdf);
432
433 for (size_t gg = 0; gg < nb_gauss_pts; ++gg) {
434 t_hess_sdf(i, j) = t_hess_sdf_set(i, j);
435 ++t_hess_sdf;
436 }
437 return m_hess_sdf;
438}
439
440template <int DIM, IntegrationType I, typename BoundaryEleOp>
442
443template <int DIM, IntegrationType I, typename BoundaryEleOp>
445
446template <int DIM, IntegrationType I, typename BoundaryEleOp>
448
449template <int DIM, IntegrationType I, typename AssemblyBoundaryEleOp>
451
452template <int DIM, IntegrationType I, typename AssemblyBoundaryEleOp>
454
455template <int DIM, IntegrationType I, typename AssemblyBoundaryEleOp>
457
458template <typename T1, typename T2, int DIM1, int DIM2>
461 size_t nb_gauss_pts) {
462 MatrixDouble m_spatial_coords(nb_gauss_pts, 3);
463 m_spatial_coords.clear();
464 auto t_spatial_coords = getFTensor1FromPtr<3>(&m_spatial_coords(0, 0));
465 FTensor::Index<'i', DIM2> i;
466 for (auto gg = 0; gg != nb_gauss_pts; ++gg) {
467 t_spatial_coords(i) = t_coords(i) + t_disp(i);
468 ++t_spatial_coords;
469 ++t_coords;
470 ++t_disp;
471 }
472 return m_spatial_coords;
473}
474
475template <typename T1, int DIM1>
477 size_t nb_gauss_pts) {
478 MatrixDouble m_normals_at_pts(nb_gauss_pts, 3);
479 m_normals_at_pts.clear();
480 FTensor::Index<'i', DIM1> i;
481 auto t_set_normal = getFTensor1FromMat<3>(m_normals_at_pts);
482 for (auto gg = 0; gg != nb_gauss_pts; ++gg) {
483 t_set_normal(i) = t_normal_at_pts(i) / t_normal_at_pts.l2();
484 ++t_set_normal;
485 ++t_normal_at_pts;
486 }
487 return m_normals_at_pts;
488}
489
490template <int DIM, typename BoundaryEleOp>
492 : public BoundaryEleOp {
494 boost::shared_ptr<CommonData> common_data_ptr, double scale = 1,
495 bool is_axisymmetric = false);
496 MoFEMErrorCode doWork(int side, EntityType type, EntData &data);
497
498private:
499 boost::shared_ptr<CommonData> commonDataPtr;
500 const double scaleTraction;
502};
503
504template <int DIM, typename BoundaryEleOp>
506 : public BoundaryEleOp {
508 boost::shared_ptr<CommonData> common_data_ptr,
509 bool is_axisymmetric = false,
510 boost::shared_ptr<Range> contact_range_ptr = nullptr);
511 MoFEMErrorCode doWork(int side, EntityType type, EntData &data);
512
514 GradSurfaceDistanceFunction gradSurfaceDistanceFunction =
516
517private:
518 boost::shared_ptr<CommonData> commonDataPtr;
520 boost::shared_ptr<Range> contactRange;
521};
522
523template <int DIM, typename BoundaryEleOp>
524struct OpEvaluateSDFImpl<DIM, GAUSS, BoundaryEleOp> : public BoundaryEleOp {
525 OpEvaluateSDFImpl(boost::shared_ptr<CommonData> common_data_ptr);
526 MoFEMErrorCode doWork(int side, EntityType type, EntData &data);
527
528private:
529 boost::shared_ptr<CommonData> commonDataPtr;
530
532 GradSurfaceDistanceFunction gradSurfaceDistanceFunction =
534 HessSurfaceDistanceFunction hessSurfaceDistanceFunction =
536};
537
538template <int DIM, typename AssemblyBoundaryEleOp>
540 : public AssemblyBoundaryEleOp {
541 OpConstrainBoundaryRhsImpl(const std::string field_name,
542 boost::shared_ptr<CommonData> common_data_ptr,
543 bool is_axisymmetric = false);
544 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &data);
545
547 GradSurfaceDistanceFunction gradSurfaceDistanceFunction =
549
550private:
551 boost::shared_ptr<CommonData> commonDataPtr;
553};
554
555template <int DIM, typename AssemblyBoundaryEleOp>
557 : public AssemblyBoundaryEleOp {
558 OpConstrainBoundaryLhs_dUImpl(const std::string row_field_name,
559 const std::string col_field_name,
560 boost::shared_ptr<CommonData> common_data_ptr,
561 bool is_axisymmetric = false);
562 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
563 EntitiesFieldData::EntData &col_data);
564
566 GradSurfaceDistanceFunction gradSurfaceDistanceFunction =
568 HessSurfaceDistanceFunction hessSurfaceDistanceFunction =
570
571 boost::shared_ptr<CommonData> commonDataPtr;
573};
574
575template <int DIM, typename AssemblyBoundaryEleOp>
577 : public AssemblyBoundaryEleOp {
579 const std::string row_field_name, const std::string col_field_name,
580 boost::shared_ptr<CommonData> common_data_ptr,
581 bool is_axisymmetric = false);
582 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
583 EntitiesFieldData::EntData &col_data);
584
586 GradSurfaceDistanceFunction gradSurfaceDistanceFunction =
588
589private:
590 boost::shared_ptr<CommonData> commonDataPtr;
592};
593
594template <typename BoundaryEleOp> struct ContactIntegrators {
595 template <int DIM, IntegrationType I>
598
599 template <int DIM, IntegrationType I>
602
603 template <int DIM, IntegrationType I>
605
606 template <AssemblyType A> struct Assembly {
607
609 typename FormsIntegrators<BoundaryEleOp>::template Assembly<A>::OpBase;
610
611 template <int DIM, IntegrationType I>
614
615 template <int DIM, IntegrationType I>
618
619 template <int DIM, IntegrationType I>
622 };
623};
624
625inline double sign(double x) {
626 constexpr auto eps = std::numeric_limits<float>::epsilon();
627 if (std::abs(x) < eps)
628 return 0;
629 else if (x > eps)
630 return 1;
631 else
632 return -1;
633};
634
635inline double w(const double sdf, const double tn) {
636 return sdf - cn_contact * tn;
637}
638
639/**
640 * @brief constrain function
641 *
642 * return 1 if negative sdf or positive tn
643 *
644 * @param sdf signed distance
645 * @param tn traction
646 * @return double
647 */
648inline double constrain(double sdf, double tn) {
649 const auto s = sign(w(sdf, tn));
650 return (1 - s) / 2;
651}
652
653template <int DIM, typename BoundaryEleOp>
656 boost::shared_ptr<CommonData> common_data_ptr, double scale,
657 bool is_axisymmetric)
659 commonDataPtr(common_data_ptr), scaleTraction(scale),
660 isAxisymmetric(is_axisymmetric) {}
661
662template <int DIM, typename BoundaryEleOp>
663MoFEMErrorCode
665 int side, EntityType type, EntData &data) {
667
668 FTensor::Index<'i', DIM> i;
669 FTensor::Tensor1<double, 3> t_sum_t{0., 0., 0.};
670
671 auto t_w = BoundaryEleOp::getFTensor0IntegrationWeight();
672 auto t_traction = getFTensor1FromMat<DIM>(commonDataPtr->contactTraction);
673 auto t_coords = BoundaryEleOp::getFTensor1CoordsAtGaussPts();
674
675 const auto nb_gauss_pts = BoundaryEleOp::getGaussPts().size2();
676 for (auto gg = 0; gg != nb_gauss_pts; ++gg) {
677 double jacobian = 1.;
678 if (isAxisymmetric) {
679 jacobian = 2. * M_PI * t_coords(0);
680 }
681 const double alpha = t_w * jacobian * BoundaryEleOp::getMeasure();
682 t_sum_t(i) += alpha * t_traction(i);
683 ++t_w;
684 ++t_traction;
685 ++t_coords;
686 }
687
688 t_sum_t(i) *= scaleTraction;
689
690 constexpr int ind[] = {TX, TY, TZ};
691 CHKERR VecSetValues(commonDataPtr->totalTractionAndArea, 3, ind, &t_sum_t(0),
692 ADD_VALUES);
693
695}
696template <int DIM, typename BoundaryEleOp>
699 boost::shared_ptr<CommonData> common_data_ptr, bool is_axisymmetric,
700 boost::shared_ptr<Range> contact_range_ptr)
702 commonDataPtr(common_data_ptr), isAxisymmetric(is_axisymmetric),
703 contactRange(contact_range_ptr) {}
704
705template <int DIM, typename BoundaryEleOp>
706MoFEMErrorCode
708 int side, EntityType type, EntData &data) {
710
711 auto fe_type = BoundaryEleOp::getFEType();
712
713 const auto fe_ent = BoundaryEleOp::getFEEntityHandle();
714
715 if (contactRange->find(fe_ent) != contactRange->end()) {
716 FTensor::Index<'i', DIM> i;
717 FTensor::Index<'j', DIM> j;
718 FTensor::Tensor1<double, 2> t_sum_a{0., 0.};
719
720 auto t_w = BoundaryEleOp::getFTensor0IntegrationWeight();
721 auto t_traction = getFTensor1FromMat<DIM>(commonDataPtr->contactTraction);
722 auto t_coords = BoundaryEleOp::getFTensor1CoordsAtGaussPts();
723
724 auto t_grad = getFTensor2FromMat<DIM, DIM>(commonDataPtr->contactDispGrad);
725 auto t_normal_at_pts = BoundaryEleOp::getFTensor1NormalsAtGaussPts();
726
727 const auto nb_gauss_pts = BoundaryEleOp::getGaussPts().size2();
728 auto m_spatial_coords = get_spatial_coords(
729 BoundaryEleOp::getFTensor1CoordsAtGaussPts(),
730 getFTensor1FromMat<DIM>(commonDataPtr->contactDisp), nb_gauss_pts);
731 auto m_normals_at_pts = get_normalize_normals(
732 BoundaryEleOp::getFTensor1NormalsAtGaussPts(), nb_gauss_pts);
733
734 auto ts_time = BoundaryEleOp::getTStime();
735 auto ts_time_step = BoundaryEleOp::getTStimeStep();
736 int block_id = 0;
737 auto v_sdf =
738 surfaceDistanceFunction(ts_time_step, ts_time, nb_gauss_pts,
739 m_spatial_coords, m_normals_at_pts, block_id);
740 auto m_grad_sdf = gradSurfaceDistanceFunction(
741 ts_time_step, ts_time, nb_gauss_pts, m_spatial_coords, m_normals_at_pts,
742 block_id);
743 auto t_sdf = getFTensor0FromVec(v_sdf);
744 auto t_grad_sdf = getFTensor1FromMat<3>(m_grad_sdf);
745 for (auto gg = 0; gg != nb_gauss_pts; ++gg) {
746 double jacobian = 1.;
747 if (isAxisymmetric) {
748 jacobian = 2. * M_PI * t_coords(0); // Axisymmetric Jacobian
749 }
750 auto tn = -t_traction(i) * t_grad_sdf(i);
751 auto c = constrain(t_sdf, tn);
752 double alpha = t_w * jacobian;
753
756 FTensor::Tensor1<double, DIM> t_normal_current;
757
758 F(i, j) = t_grad(i, j) + kronecker_delta(i, j);
759 auto det = determinantTensor(F);
760 CHKERR invertTensor(F, det, invF);
761 t_normal_current(i) = det * (invF(j, i) * t_normal_at_pts(j));
762
763 alpha *= sqrt(t_normal_current(i) * t_normal_current(i));
764
765 if (fe_type == MBTRI) {
766 alpha /= 2;
767 }
768 if (c > 1e-12) {
769 t_sum_a(0) += alpha; // real area
770 }
771 t_sum_a(1) += alpha; // Potential area
772 ++t_w;
773 ++t_traction;
774 ++t_coords;
775 ++t_sdf;
776 ++t_grad_sdf;
777
778 ++t_grad;
779 ++t_normal_at_pts;
780 }
781 constexpr int ind[] = {AREA_ACTIVE, AREA_POTENTIAL};
782 CHKERR VecSetValues(commonDataPtr->totalTractionAndArea, 2, ind, &t_sum_a(0),
783 ADD_VALUES);
784 }
786}
787
788template <int DIM, typename BoundaryEleOp>
790 boost::shared_ptr<CommonData> common_data_ptr)
792 commonDataPtr(common_data_ptr) {}
793
794template <int DIM, typename BoundaryEleOp>
795MoFEMErrorCode
797 EntData &data) {
799
800 const auto nb_gauss_pts = BoundaryEleOp::getGaussPts().size2();
801 auto &sdf_vec = commonDataPtr->sdfVals;
802 auto &grad_mat = commonDataPtr->gradsSdf;
803 auto &hess_mat = commonDataPtr->hessSdf;
804 auto &constraint_vec = commonDataPtr->constraintVals;
805 auto &contactTraction_mat = commonDataPtr->contactTraction;
806
807 sdf_vec.resize(nb_gauss_pts, false);
808 grad_mat.resize(nb_gauss_pts, DIM, false);
809 hess_mat.resize(nb_gauss_pts, (DIM * (DIM + 1)) / 2, false);
810 constraint_vec.resize(nb_gauss_pts, false);
811
812 auto t_traction = getFTensor1FromMat<DIM>(contactTraction_mat);
813
814 auto t_sdf = getFTensor0FromVec(sdf_vec);
815 auto t_grad_sdf = getFTensor1FromMat<DIM>(grad_mat);
816 auto t_hess_sdf = getFTensor2SymmetricFromMat<DIM>(hess_mat);
817 auto t_constraint = getFTensor0FromVec(constraint_vec);
818
819 auto t_disp = getFTensor1FromMat<DIM>(commonDataPtr->contactDisp);
820 FTensor::Index<'i', DIM> i;
821 FTensor::Index<'j', DIM> j;
822
823 auto ts_time = BoundaryEleOp::getTStime();
824 auto ts_time_step = BoundaryEleOp::getTStimeStep();
825
826 auto m_spatial_coords = get_spatial_coords(
827 BoundaryEleOp::getFTensor1CoordsAtGaussPts(),
828 getFTensor1FromMat<DIM>(commonDataPtr->contactDisp), nb_gauss_pts);
829 auto m_normals_at_pts = get_normalize_normals(
830 BoundaryEleOp::getFTensor1NormalsAtGaussPts(), nb_gauss_pts);
831
832 // placeholder to pass boundary block id to python
833 int block_id = 0;
834
835 auto v_sdf =
836 surfaceDistanceFunction(ts_time_step, ts_time, nb_gauss_pts,
837 m_spatial_coords, m_normals_at_pts, block_id);
838
839 auto m_grad_sdf =
840 gradSurfaceDistanceFunction(ts_time_step, ts_time, nb_gauss_pts,
841 m_spatial_coords, m_normals_at_pts, block_id);
842
843 auto m_hess_sdf =
844 hessSurfaceDistanceFunction(ts_time_step, ts_time, nb_gauss_pts,
845 m_spatial_coords, m_normals_at_pts, block_id);
846
847 auto t_sdf_v = getFTensor0FromVec(v_sdf);
848 auto t_grad_sdf_v = getFTensor1FromMat<3>(m_grad_sdf);
849 auto t_hess_sdf_v = getFTensor2SymmetricFromMat<3>(m_hess_sdf);
850
851 auto next = [&]() {
852 ++t_sdf;
853 ++t_sdf_v;
854 ++t_grad_sdf;
855 ++t_grad_sdf_v;
856 ++t_hess_sdf;
857 ++t_hess_sdf_v;
858 ++t_disp;
859 ++t_traction;
860 ++t_constraint;
861 };
862
863 for (auto gg = 0; gg != nb_gauss_pts; ++gg) {
864
865 auto tn = -t_traction(i) * t_grad_sdf_v(i);
866 auto c = constrain(t_sdf_v, tn);
867
868 t_sdf = t_sdf_v;
869 t_grad_sdf(i) = t_grad_sdf_v(i);
870 t_hess_sdf(i, j) = t_hess_sdf_v(i, j);
871 t_constraint = c;
872
873 next();
874 }
875
877}
878
879template <int DIM, typename AssemblyBoundaryEleOp>
882 boost::shared_ptr<CommonData> common_data_ptr,
883 bool is_axisymmetric)
885 AssemblyBoundaryEleOp::OPROW),
886 commonDataPtr(common_data_ptr), isAxisymmetric(is_axisymmetric) {}
887
888template <int DIM, typename AssemblyBoundaryEleOp>
889MoFEMErrorCode
891 EntitiesFieldData::EntData &data) {
893
894 FTensor::Index<'i', DIM> i;
895 FTensor::Index<'j', DIM> j;
896 FTensor::Index<'k', DIM> k;
897 FTensor::Index<'l', DIM> l;
898
899 const size_t nb_gauss_pts = AssemblyBoundaryEleOp::getGaussPts().size2();
900
901 auto &nf = AssemblyBoundaryEleOp::locF;
902
903 auto t_w = AssemblyBoundaryEleOp::getFTensor0IntegrationWeight();
904 auto t_disp = getFTensor1FromMat<DIM>(commonDataPtr->contactDisp);
905 auto t_traction = getFTensor1FromMat<DIM>(commonDataPtr->contactTraction);
906 auto t_coords = AssemblyBoundaryEleOp::getFTensor1CoordsAtGaussPts();
907
908 size_t nb_base_functions = data.getN().size2() / 3;
909 auto t_base = data.getFTensor1N<3>();
910
911 auto m_spatial_coords = get_spatial_coords(
912 BoundaryEleOp::getFTensor1CoordsAtGaussPts(),
913 getFTensor1FromMat<DIM>(commonDataPtr->contactDisp), nb_gauss_pts);
914 auto m_normals_at_pts = get_normalize_normals(
915 BoundaryEleOp::getFTensor1NormalsAtGaussPts(), nb_gauss_pts);
916
917 auto t_normal = getFTensor1FromMat<3>(m_normals_at_pts);
918
919 auto ts_time = AssemblyBoundaryEleOp::getTStime();
920 auto ts_time_step = AssemblyBoundaryEleOp::getTStimeStep();
921
922 // placeholder to pass boundary block id to python
923 int block_id = 0;
924
925 auto v_sdf =
926 surfaceDistanceFunction(ts_time_step, ts_time, nb_gauss_pts,
927 m_spatial_coords, m_normals_at_pts, block_id);
928
929 auto m_grad_sdf =
930 gradSurfaceDistanceFunction(ts_time_step, ts_time, nb_gauss_pts,
931 m_spatial_coords, m_normals_at_pts, block_id);
932
933 auto t_sdf = getFTensor0FromVec(v_sdf);
934 auto t_grad_sdf = getFTensor1FromMat<3>(m_grad_sdf);
935
936 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
937
938 auto t_nf = getFTensor1FromPtr<DIM>(&nf[0]);
939
940 double jacobian = 1.;
941 if (isAxisymmetric) {
942 jacobian = 2. * M_PI * t_coords(0);
943 }
944 const double alpha = t_w * jacobian * AssemblyBoundaryEleOp::getMeasure();
945
946 auto tn = -t_traction(i) * t_grad_sdf(i);
947 auto c = constrain(t_sdf, tn);
948
950 t_cP(i, j) = (c * t_grad_sdf(i)) * t_grad_sdf(j);
952 t_cQ(i, j) = kronecker_delta(i, j) - t_cP(i, j);
953
955 t_rhs(i) =
956
957 t_cQ(i, j) * (t_disp(j) - cn_contact * t_traction(j))
958
959 +
960
961 t_cP(i, j) * t_disp(j) +
962 c * (t_sdf * t_grad_sdf(i)); // add gap0 displacements
963
964 size_t bb = 0;
965 for (; bb != AssemblyBoundaryEleOp::nbRows / DIM; ++bb) {
966 const double beta = alpha * (t_base(i) * t_normal(i));
967 t_nf(i) -= beta * t_rhs(i);
968
969 ++t_nf;
970 ++t_base;
971 }
972 for (; bb < nb_base_functions; ++bb)
973 ++t_base;
974
975 ++t_disp;
976 ++t_traction;
977 ++t_coords;
978 ++t_w;
979 ++t_normal;
980 ++t_sdf;
981 ++t_grad_sdf;
982 }
983
985}
986
987template <int DIM, typename AssemblyBoundaryEleOp>
989 OpConstrainBoundaryLhs_dUImpl(const std::string row_field_name,
990 const std::string col_field_name,
991 boost::shared_ptr<CommonData> common_data_ptr,
992 bool is_axisymmetric)
993 : AssemblyBoundaryEleOp(row_field_name, col_field_name,
994 AssemblyBoundaryEleOp::OPROWCOL),
995 commonDataPtr(common_data_ptr), isAxisymmetric(is_axisymmetric) {
996 AssemblyBoundaryEleOp::sYmm = false;
997}
998
999template <int DIM, typename AssemblyBoundaryEleOp>
1000MoFEMErrorCode
1002 EntitiesFieldData::EntData &row_data,
1003 EntitiesFieldData::EntData &col_data) {
1005
1006 FTensor::Index<'i', DIM> i;
1007 FTensor::Index<'j', DIM> j;
1008 FTensor::Index<'k', DIM> k;
1009
1010 const size_t nb_gauss_pts = AssemblyBoundaryEleOp::getGaussPts().size2();
1011 auto &locMat = AssemblyBoundaryEleOp::locMat;
1012
1013 auto t_traction = getFTensor1FromMat<DIM>(commonDataPtr->contactTraction);
1014 auto t_coords = AssemblyBoundaryEleOp::getFTensor1CoordsAtGaussPts();
1015
1016 auto t_w = AssemblyBoundaryEleOp::getFTensor0IntegrationWeight();
1017 auto t_row_base = row_data.getFTensor1N<3>();
1018 size_t nb_face_functions = row_data.getN().size2() / 3;
1019
1020 auto m_spatial_coords = get_spatial_coords(
1021 BoundaryEleOp::getFTensor1CoordsAtGaussPts(),
1022 getFTensor1FromMat<DIM>(commonDataPtr->contactDisp), nb_gauss_pts);
1023 auto m_normals_at_pts = get_normalize_normals(
1024 BoundaryEleOp::getFTensor1NormalsAtGaussPts(), nb_gauss_pts);
1025
1026 auto t_normal = getFTensor1FromMat<3>(m_normals_at_pts);
1027
1028 auto ts_time = AssemblyBoundaryEleOp::getTStime();
1029 auto ts_time_step = AssemblyBoundaryEleOp::getTStimeStep();
1030
1031 // placeholder to pass boundary block id to python
1032 int block_id = 0;
1033
1034 auto v_sdf =
1035 surfaceDistanceFunction(ts_time_step, ts_time, nb_gauss_pts,
1036 m_spatial_coords, m_normals_at_pts, block_id);
1037
1038 auto m_grad_sdf =
1039 gradSurfaceDistanceFunction(ts_time_step, ts_time, nb_gauss_pts,
1040 m_spatial_coords, m_normals_at_pts, block_id);
1041
1042 auto m_hess_sdf =
1043 hessSurfaceDistanceFunction(ts_time_step, ts_time, nb_gauss_pts,
1044 m_spatial_coords, m_normals_at_pts, block_id);
1045
1046 auto t_sdf = getFTensor0FromVec(v_sdf);
1047 auto t_grad_sdf = getFTensor1FromMat<3>(m_grad_sdf);
1048 auto t_hess_sdf = getFTensor2SymmetricFromMat<3>(m_hess_sdf);
1049
1050 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
1051
1052 double jacobian = 1.;
1053 if (isAxisymmetric) {
1054 jacobian = 2. * M_PI * t_coords(0);
1055 }
1056 const double alpha = t_w * jacobian * AssemblyBoundaryEleOp::getMeasure();
1057
1058 auto tn = -t_traction(i) * t_grad_sdf(i);
1059 auto c = constrain(t_sdf, tn);
1060
1062 t_cP(i, j) = (c * t_grad_sdf(i)) * t_grad_sdf(j);
1064 t_cQ(i, j) = kronecker_delta(i, j) - t_cP(i, j);
1065
1067 t_res_dU(i, j) = kronecker_delta(i, j) + t_cP(i, j);
1068
1069 if (c > 0) {
1070 t_res_dU(i, j) +=
1071 (c * cn_contact) *
1072 (t_hess_sdf(i, j) * (t_grad_sdf(k) * t_traction(k)) +
1073 t_grad_sdf(i) * t_hess_sdf(k, j) * t_traction(k)) +
1074 c * t_sdf * t_hess_sdf(i, j);
1075 }
1076
1077 size_t rr = 0;
1078 for (; rr != AssemblyBoundaryEleOp::nbRows / DIM; ++rr) {
1079
1080 auto t_mat = getFTensor2FromArray<DIM, DIM, DIM>(locMat, DIM * rr);
1081
1082 const double row_base = t_row_base(i) * t_normal(i);
1083
1084 auto t_col_base = col_data.getFTensor0N(gg, 0);
1085 for (size_t cc = 0; cc != AssemblyBoundaryEleOp::nbCols / DIM; ++cc) {
1086 const double beta = alpha * row_base * t_col_base;
1087
1088 t_mat(i, j) -= beta * t_res_dU(i, j);
1089
1090 ++t_col_base;
1091 ++t_mat;
1092 }
1093
1094 ++t_row_base;
1095 }
1096 for (; rr < nb_face_functions; ++rr)
1097 ++t_row_base;
1098
1099 ++t_traction;
1100 ++t_coords;
1101 ++t_w;
1102 ++t_normal;
1103 ++t_sdf;
1104 ++t_grad_sdf;
1105 ++t_hess_sdf;
1106 }
1107
1109}
1110
1111template <int DIM, typename AssemblyBoundaryEleOp>
1114 const std::string row_field_name, const std::string col_field_name,
1115 boost::shared_ptr<CommonData> common_data_ptr, bool is_axisymmetric)
1116 : AssemblyBoundaryEleOp(row_field_name, col_field_name,
1117 AssemblyBoundaryEleOp::OPROWCOL),
1118 commonDataPtr(common_data_ptr), isAxisymmetric(is_axisymmetric) {
1119 AssemblyBoundaryEleOp::sYmm = false;
1120}
1121
1122template <int DIM, typename AssemblyBoundaryEleOp>
1123MoFEMErrorCode
1125 iNtegrate(EntitiesFieldData::EntData &row_data,
1126 EntitiesFieldData::EntData &col_data) {
1128
1129 FTensor::Index<'i', DIM> i;
1130 FTensor::Index<'j', DIM> j;
1131 FTensor::Index<'k', DIM> k;
1132
1133 const size_t nb_gauss_pts = AssemblyBoundaryEleOp::getGaussPts().size2();
1134 auto &locMat = AssemblyBoundaryEleOp::locMat;
1135
1136 auto t_traction = getFTensor1FromMat<DIM>(commonDataPtr->contactTraction);
1137 auto t_coords = AssemblyBoundaryEleOp::getFTensor1CoordsAtGaussPts();
1138
1139 auto t_w = AssemblyBoundaryEleOp::getFTensor0IntegrationWeight();
1140 auto t_row_base = row_data.getFTensor1N<3>();
1141 size_t nb_face_functions = row_data.getN().size2() / 3;
1142
1143 auto m_spatial_coords = get_spatial_coords(
1144 BoundaryEleOp::getFTensor1CoordsAtGaussPts(),
1145 getFTensor1FromMat<DIM>(commonDataPtr->contactDisp), nb_gauss_pts);
1146 auto m_normals_at_pts = get_normalize_normals(
1147 BoundaryEleOp::getFTensor1NormalsAtGaussPts(), nb_gauss_pts);
1148
1149 auto t_normal = getFTensor1FromMat<3>(m_normals_at_pts);
1150
1151 auto ts_time = AssemblyBoundaryEleOp::getTStime();
1152 auto ts_time_step = AssemblyBoundaryEleOp::getTStimeStep();
1153
1154 // placeholder to pass boundary block id to python
1155 int block_id = 0;
1156
1157 auto v_sdf =
1158 surfaceDistanceFunction(ts_time_step, ts_time, nb_gauss_pts,
1159 m_spatial_coords, m_normals_at_pts, block_id);
1160
1161 auto m_grad_sdf =
1162 gradSurfaceDistanceFunction(ts_time_step, ts_time, nb_gauss_pts,
1163 m_spatial_coords, m_normals_at_pts, block_id);
1164
1165 auto t_sdf = getFTensor0FromVec(v_sdf);
1166 auto t_grad_sdf = getFTensor1FromMat<3>(m_grad_sdf);
1167
1168 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
1169
1170 double jacobian = 1.;
1171 if (isAxisymmetric) {
1172 jacobian = 2. * M_PI * t_coords(0);
1173 }
1174 const double alpha = t_w * jacobian * AssemblyBoundaryEleOp::getMeasure();
1175
1176 auto tn = -t_traction(i) * t_grad_sdf(i);
1177 auto c = constrain(t_sdf, tn);
1178
1180 t_cP(i, j) = (c * t_grad_sdf(i)) * t_grad_sdf(j);
1182 t_cQ(i, j) = kronecker_delta(i, j) - t_cP(i, j);
1183
1185 t_res_dt(i, j) = -cn_contact * t_cQ(i, j);
1186
1187 size_t rr = 0;
1188 for (; rr != AssemblyBoundaryEleOp::nbRows / DIM; ++rr) {
1189
1190 auto t_mat = getFTensor2FromArray<DIM, DIM, DIM>(locMat, DIM * rr);
1191 const double row_base = t_row_base(i) * t_normal(i);
1192
1193 auto t_col_base = col_data.getFTensor1N<3>(gg, 0);
1194 for (size_t cc = 0; cc != AssemblyBoundaryEleOp::nbCols / DIM; ++cc) {
1195 const double col_base = t_col_base(i) * t_normal(i);
1196 const double beta = alpha * row_base * col_base;
1197
1198 t_mat(i, j) -= beta * t_res_dt(i, j);
1199
1200 ++t_col_base;
1201 ++t_mat;
1202 }
1203
1204 ++t_row_base;
1205 }
1206 for (; rr < nb_face_functions; ++rr)
1207 ++t_row_base;
1208
1209 ++t_traction;
1210 ++t_coords;
1211 ++t_w;
1212 ++t_normal;
1213 ++t_sdf;
1214 ++t_grad_sdf;
1215 }
1216
1218}
1219
1220template <int DIM, AssemblyType A, IntegrationType I, typename DomainEleOp>
1221MoFEMErrorCode opFactoryDomainRhs(
1222 boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pip,
1223 std::string sigma, std::string u, bool is_axisymmetric = false) {
1225
1226 using B = typename FormsIntegrators<DomainEleOp>::template Assembly<
1227 A>::template LinearForm<I>;
1228 using OpMixDivURhs = typename B::template OpMixDivTimesU<3, DIM, DIM>;
1229 using OpMixDivUCylRhs =
1230 typename B::template OpMixDivTimesU<3, DIM, DIM, CYLINDRICAL>;
1231
1232 using OpMixLambdaGradURhs = typename B::template OpMixTensorTimesGradU<DIM>;
1233 using OpMixUTimesDivLambdaRhs =
1234 typename B::template OpMixVecTimesDivLambda<SPACE_DIM>;
1235 using OpMixUTimesLambdaRhs =
1236 typename B::template OpGradTimesTensor<1, DIM, DIM>;
1237
1238 auto common_data_ptr = boost::make_shared<ContactOps::CommonData>();
1239 auto mat_grad_ptr = boost::make_shared<MatrixDouble>();
1240 auto div_stress_ptr = boost::make_shared<MatrixDouble>();
1241 auto contact_stress_ptr = boost::make_shared<MatrixDouble>();
1242
1243 auto jacobian = [is_axisymmetric](const double r, const double,
1244 const double) {
1245 if (is_axisymmetric)
1246 return 2. * M_PI * r;
1247 else
1248 return 1.;
1249 };
1250
1251 pip.push_back(new OpCalculateVectorFieldValues<DIM>(
1252 u, common_data_ptr->contactDispPtr()));
1253 pip.push_back(
1254 new OpCalculateHVecTensorField<DIM, DIM>(sigma, contact_stress_ptr));
1255
1256 if (!is_axisymmetric) {
1257 pip.push_back(
1258 new OpCalculateHVecTensorDivergence<DIM, DIM>(sigma, div_stress_ptr));
1259 } else {
1260 pip.push_back(new OpCalculateHVecTensorDivergence<DIM, DIM, CYLINDRICAL>(
1261 sigma, div_stress_ptr));
1262 }
1263
1264 pip.push_back(new OpCalculateVectorFieldGradient<DIM, DIM>(u, mat_grad_ptr));
1265
1266 if (!is_axisymmetric) {
1267 pip.push_back(
1268 new OpMixDivURhs(sigma, common_data_ptr->contactDispPtr(), jacobian));
1269 } else {
1270 pip.push_back(new OpMixDivUCylRhs(sigma, common_data_ptr->contactDispPtr(),
1271 jacobian));
1272 }
1273
1274 pip.push_back(new OpMixLambdaGradURhs(sigma, mat_grad_ptr, jacobian));
1275 pip.push_back(new OpMixUTimesDivLambdaRhs(u, div_stress_ptr, jacobian));
1276 pip.push_back(new OpMixUTimesLambdaRhs(u, contact_stress_ptr, jacobian));
1277
1279}
1280
1281template <typename OpMixLhs> struct OpMixLhsSide : public OpMixLhs {
1282 using OpMixLhs::OpMixLhs;
1283 MoFEMErrorCode doWork(int row_side, int col_side, EntityType row_type,
1284 EntityType col_type,
1285 EntitiesFieldData::EntData &row_data,
1286 EntitiesFieldData::EntData &col_data) {
1288 auto side_fe_entity = OpMixLhs::getSidePtrFE()->getFEEntityHandle();
1289 auto side_fe_data = OpMixLhs::getSideEntity(row_side, row_type);
1290 // Only assemble side which correspond to edge entity on boundary
1291 if (side_fe_entity == side_fe_data) {
1292 CHKERR OpMixLhs::doWork(row_side, col_side, row_type, col_type, row_data,
1293 col_data);
1294 }
1296 }
1297};
1298
1299template <int DIM, AssemblyType A, IntegrationType I, typename DomainEle>
1301 MoFEM::Interface &m_field,
1302 boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pip,
1303 std::string fe_domain_name, std::string sigma, std::string u,
1304 std::string geom, ForcesAndSourcesCore::RuleHookFun rule,
1305 bool is_axisymmetric = false) {
1307
1308 using DomainEleOp = typename DomainEle::UserDataOperator;
1309
1310 auto op_loop_side = new OpLoopSide<DomainEle>(
1311 m_field, fe_domain_name, DIM, Sev::noisy,
1312 boost::make_shared<ForcesAndSourcesCore::UserDataOperator::AdjCache>());
1313 pip.push_back(op_loop_side);
1314
1315 CHKERR AddHOOps<DIM, DIM, DIM>::add(op_loop_side->getOpPtrVector(),
1316 {H1, HDIV}, geom);
1317
1318 using B = typename FormsIntegrators<DomainEleOp>::template Assembly<
1319 A>::template BiLinearForm<I>;
1320
1321 using OpMixDivULhs = typename B::template OpMixDivTimesVec<DIM>;
1322 using OpMixDivUCylLhs =
1323 typename B::template OpMixDivTimesVec<DIM, CYLINDRICAL>;
1324 using OpLambdaGraULhs = typename B::template OpMixTensorTimesGrad<DIM>;
1325
1326 using OpMixDivULhsSide = OpMixLhsSide<OpMixDivULhs>;
1327 using OpMixDivUCylLhsSide = OpMixLhsSide<OpMixDivUCylLhs>;
1328 using OpLambdaGraULhsSide = OpMixLhsSide<OpLambdaGraULhs>;
1329
1330 auto unity = []() { return 1; };
1331 auto jacobian = [is_axisymmetric](const double r, const double,
1332 const double) {
1333 if (is_axisymmetric)
1334 return 2. * M_PI * r;
1335 else
1336 return 1.;
1337 };
1338
1339 if (!is_axisymmetric) {
1340 op_loop_side->getOpPtrVector().push_back(
1341 new OpMixDivULhsSide(sigma, u, unity, jacobian, true));
1342 } else {
1343 op_loop_side->getOpPtrVector().push_back(
1344 new OpMixDivUCylLhsSide(sigma, u, unity, jacobian, true));
1345 }
1346 op_loop_side->getOpPtrVector().push_back(
1347 new OpLambdaGraULhsSide(sigma, u, unity, jacobian, true));
1348
1349 op_loop_side->getSideFEPtr()->getRuleHook = rule;
1351}
1352
1353template <int DIM, AssemblyType A, IntegrationType I, typename BoundaryEleOp>
1355 boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pip,
1356 std::string sigma, std::string u, bool is_axisymmetric = false) {
1358
1360
1361 auto common_data_ptr = boost::make_shared<ContactOps::CommonData>();
1362
1363 pip.push_back(new OpCalculateVectorFieldValues<DIM>(
1364 u, common_data_ptr->contactDispPtr()));
1365 pip.push_back(new OpCalculateHVecTensorTrace<DIM, BoundaryEleOp>(
1366 sigma, common_data_ptr->contactTractionPtr()));
1367 pip.push_back(
1368 new typename C::template Assembly<A>::template OpConstrainBoundaryLhs_dU<
1369 DIM, GAUSS>(sigma, u, common_data_ptr, is_axisymmetric));
1370 pip.push_back(new typename C::template Assembly<A>::
1371 template OpConstrainBoundaryLhs_dTraction<DIM, GAUSS>(
1372 sigma, sigma, common_data_ptr, is_axisymmetric));
1373
1375}
1376
1377template <int DIM, AssemblyType A, IntegrationType I, typename BoundaryEleOp>
1379 boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pip,
1380 std::string sigma, std::string u, bool is_axisymmetric = false) {
1382
1384
1385 auto common_data_ptr = boost::make_shared<ContactOps::CommonData>();
1386
1387 pip.push_back(new OpCalculateVectorFieldValues<DIM>(
1388 u, common_data_ptr->contactDispPtr()));
1389 pip.push_back(new OpCalculateHVecTensorTrace<DIM, BoundaryEleOp>(
1390 sigma, common_data_ptr->contactTractionPtr()));
1391 pip.push_back(
1392 new typename C::template Assembly<A>::template OpConstrainBoundaryRhs<
1393 DIM, GAUSS>(sigma, common_data_ptr, is_axisymmetric));
1394
1396}
1397
1398template <int DIM, IntegrationType I, typename BoundaryEleOp>
1400 boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pip,
1401 std::string sigma, bool is_axisymmetric = false) {
1403
1405
1406 auto common_data_ptr = boost::make_shared<ContactOps::CommonData>();
1407 pip.push_back(new OpCalculateHVecTensorTrace<DIM, BoundaryEleOp>(
1408 sigma, common_data_ptr->contactTractionPtr()));
1409 pip.push_back(new typename C::template OpAssembleTotalContactTraction<DIM, I>(
1410 common_data_ptr, 1. / scale, is_axisymmetric));
1411
1413}
1414
1415template <int DIM, IntegrationType I, typename BoundaryEleOp>
1417 boost::ptr_deque<ForcesAndSourcesCore::UserDataOperator> &pip,
1418 OpLoopSide<SideEle> *op_loop_side, std::string sigma, std::string u,
1419 bool is_axisymmetric = false,
1420 boost::shared_ptr<Range> contact_range_ptr = nullptr) {
1423
1424 auto common_data_ptr = boost::make_shared<ContactOps::CommonData>();
1425
1426 op_loop_side->getOpPtrVector().push_back(
1427 new OpCalculateVectorFieldGradient<SPACE_DIM, SPACE_DIM>(
1428 "U", common_data_ptr->contactDispGradPtr()));
1429
1430 if (contact_range_ptr) {
1431 pip.push_back(new OpCalculateVectorFieldValues<DIM>(
1432 u, common_data_ptr->contactDispPtr()));
1433 pip.push_back(new OpCalculateHVecTensorTrace<DIM, BoundaryEleOp>(
1434 sigma, common_data_ptr->contactTractionPtr()));
1435 pip.push_back(op_loop_side);
1436 pip.push_back(new typename C::template OpAssembleTotalContactArea<DIM, I>(
1437 common_data_ptr, is_axisymmetric, contact_range_ptr));
1438 }
1440}
1441
1442}; // namespace ContactOps
1443
1444#endif // __CONTACTOPS_HPP__
SmartPetscObj< Mat > C
std::string type
SmartPetscObj< Mat > jacobian
PetscInt size
static const double eps
PetscBool is_axisymmetric
Definition contact.cpp:91
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
@ NOSPACE
Definition definitions.h:83
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#define CHK_MOAB_THROW(err, msg)
Check error code of MoAB function and throw MoFEM exception.
@ 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.
@ F
FTensor::Index< 'i', SPACE_DIM > i
const double c
speed of light (cm/ns)
constexpr int DIM2
Definition level_set.cpp:22
constexpr int DIM1
Definition level_set.cpp:21
FTensor::Index< 'l', 3 > l
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
boost::function< MatrixDouble(double delta_t, double t, int nb_gauss_pts, MatrixDouble &spatial_coords, MatrixDouble &normals_at_pts, int block_id)> GradSurfaceDistanceFunction
MoFEMErrorCode opFactoryDomainRhs(boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pip, std::string sigma, std::string u, bool is_axisymmetric=false)
auto get_normalize_normals(FTensor::Tensor1< T1, DIM1 > &&t_normal_at_pts, size_t nb_gauss_pts)
double cn_contact
Definition contact.cpp:95
MoFEMErrorCode opFactoryCalculateArea(boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pip, OpLoopSide< SideEle > *op_loop_side, std::string sigma, std::string u, bool is_axisymmetric=false, boost::shared_ptr< Range > contact_range_ptr=nullptr)
@ LAST_TOTAL_TRACTION_AND_AREA
MatrixDouble grad_surface_distance_function(double delta_t, double t, int nb_gauss_pts, MatrixDouble &m_spatial_coords, MatrixDouble &m_normals_at_pts, int block_id)
MoFEMErrorCode opFactoryBoundaryToDomainLhs(MoFEM::Interface &m_field, boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pip, std::string fe_domain_name, std::string sigma, std::string u, std::string geom, ForcesAndSourcesCore::RuleHookFun rule, bool is_axisymmetric=false)
MatrixDouble hess_surface_distance_function(double delta_t, double t, int nb_gauss_pts, MatrixDouble &m_spatial_coords, MatrixDouble &m_normals_at_pts, int block_id)
MoFEMErrorCode opFactoryBoundaryRhs(boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pip, std::string sigma, std::string u, bool is_axisymmetric=false)
double w(const double sdf, const double tn)
auto get_spatial_coords(FTensor::Tensor1< T1, DIM1 > &&t_coords, FTensor::Tensor1< T2, DIM2 > &&t_disp, size_t nb_gauss_pts)
double constrain(double sdf, double tn)
constrain function
boost::function< MatrixDouble(double delta_t, double t, int nb_gauss_pts, MatrixDouble &spatial_coords, MatrixDouble &normals_at_pts, int block_id)> HessSurfaceDistanceFunction
VectorDouble surface_distance_function(double delta_t, double t, int nb_gauss_pts, MatrixDouble &m_spatial_coords, MatrixDouble &m_normals_at_pts, int block_id)
boost::function< VectorDouble(double delta_t, double t, int nb_gauss_pts, MatrixDouble &spatial_coords, MatrixDouble &normals_at_pts, int block_id)> SurfaceDistanceFunction
[Common data]
MoFEMErrorCode opFactoryBoundaryLhs(boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pip, std::string sigma, std::string u, bool is_axisymmetric=false)
MoFEMErrorCode opFactoryCalculateTraction(boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pip, std::string sigma, bool is_axisymmetric=false)
double sign(double x)
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
Definition sdf.py:1
hess_sdf(delta_t, t, x, y, z, tx, ty, tz, block_id)
Definition sdf.py:20
grad_sdf(delta_t, t, x, y, z, tx, ty, tz, block_id)
Definition sdf.py:16
FormsIntegrators< DomainEleOp >::Assembly< A >::LinearForm< I >::OpGradTimesTensor< 1, FIELD_DIM, SPACE_DIM > OpGradTimesTensor
constexpr AssemblyType A
double scale
Definition plastic.cpp:124
constexpr double t
plate stiffness
Definition plate.cpp:58
constexpr auto field_name
MatrixDouble contactDispGrad
MatrixDouble contactDisp
static auto getFTensor1TotalTraction()
VectorDouble constraintVals
static SmartPetscObj< Vec > totalTractionAndArea
MatrixDouble contactTraction
static auto createTotalTraction(MoFEM::Interface &m_field)
VectorDouble sdfVals
size is equal to number of gauss points on element
MoFEMErrorCode doWork(int row_side, int col_side, EntityType row_type, EntityType col_type, EntitiesFieldData::EntData &row_data, EntitiesFieldData::EntData &col_data)
virtual MPI_Comm & get_comm() const =0
virtual int get_comm_rank() const =0
Deprecated interface functions.
Data on single entity (This is passed as argument to DataOperator::doWork)