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