v0.16.3
Loading...
Searching...
No Matches
UserDataOperators.hpp
Go to the documentation of this file.
1/** \file UserDataOperators.hpp
2 * \brief User data operators for finite element computations
3 *
4 * This file contains a comprehensive collection of user data operators used in
5 * MoFEM finite element computations. These operators provide functionality for
6 * calculating, transforming, and manipulating field values at integration points.
7 *
8 * ## Main Categories of Operators:
9 *
10 * ### Field Value Calculation Operators
11 * - **Scalar Field Operators**: Calculate scalar field values at integration points
12 * - OpCalculateScalarFieldValues: General scalar field value calculation
13 * - OpCalculateScalarFieldValuesFromPetscVecImpl: PETSc vector-based scalar values
14 * - **Vector Field Operators**: Calculate vector field values at integration points
15 * - OpCalculateVectorFieldValues: General vector field value calculation
16 * - OpCalculateDivergenceVectorFieldValues: Divergence calculation for vector fields
17 * - **Tensor Field Operators**: Calculate tensor field values at integration points
18 * - OpCalculateTensor2FieldValues: Second-rank tensor field calculations
19 * - OpCalculateTensor2SymmetricFieldValues: Symmetric tensor field calculations
20 *
21 * ### Field Gradient Calculation Operators
22 * - **Scalar Gradient Operators**:
23 * - OpCalculateScalarFieldGradient: Gradient of scalar fields
24 * - OpCalculateScalarFieldHessian: Hessian (second derivatives) of scalar fields
25 * - **Vector Gradient Operators**:
26 * - OpCalculateVectorFieldGradient: Gradient of vector fields
27 *
28 * ### Matrix and Tensor Operations
29 * - **Matrix Manipulation**:
30 * - OpInvertMatrix: Matrix inversion at integration points
31 * - OpScaleMatrix: Element-wise matrix scaling operations
32 * - OpCalculateTraceFromMat: Trace calculation for matrices
33 * - **Tensor Operations**:
34 * - OpSymmetrizeTensor: Tensor symmetrization operations
35 * - OpTensorTimesSymmetricTensor: Tensor multiplication operations
36 *
37 * @see ForcesAndSourcesCore::UserDataOperator for base class documentation
38 * @see EntitiesFieldData for field data management
39 * @see PipelineManager for operator pipeline management
40 */
41
42#ifndef __USER_DATA_OPERATORS_HPP__
43 #define __USER_DATA_OPERATORS_HPP__
44
45namespace MoFEM {
46
47/** \name Get values at Gauss pts */
48
49/**@{*/
50
51/** \name Scalar values */
52
53/**@{*/
54
55/** \brief Scalar field values at integration points
56 *
57 */
58
59/**
60 * @brief Operator for calculating scalar field values at integration points
61 *
62 * This template structure calculates scalar field values at integration points
63 * and stores them in a provided data container. It supports different storage
64 * types through template parameters and can optionally work with PETSc vectors.
65 *
66 * @tparam T Data type for the scalar field values (e.g., double, float)
67 * @tparam A Allocator type for the ublas vector storage
68 */
69template <class T, class A>
72
73 /**
74 * @brief Constructor with PETSc vector support
75 *
76 * @param field_name Name of the scalar field to calculate values for
77 * @param data_ptr Shared pointer to ublas vector for storing calculated values
78 * @param data_vec Smart PETSc vector object for additional data storage
79 * @param zero_type Entity type for zero-level entities (default: MBVERTEX)
80 */
83 const std::string field_name,
84 boost::shared_ptr<ublas::vector<T, A>> data_ptr,
85 SmartPetscObj<Vec> data_vec, const EntityType zero_type = MBVERTEX)
87 dataPtr(data_ptr), zeroType(zero_type), dataVec(data_vec) {
88 if (!dataPtr)
89 THROW_MESSAGE("Pointer is not set");
90 }
91
92 /**
93 * @brief Constructor with PETSc vector support for a different problem
94 * layout
95 *
96 * The finite-element data local indices belong to the problem driving the
97 * current loop. When @p data_vec belongs to another DM, @p data_dm maps
98 * field DOFs by their unique IDs to that vector's local indices. @p op_type
99 * selects row or column numbering in @p data_dm.
100 */
102 SmartPetscObj<DM> data_dm,
104 const std::string field_name,
105 boost::shared_ptr<ublas::vector<T, A>> data_ptr,
106 SmartPetscObj<Vec> data_vec, const EntityType zero_type = MBVERTEX)
108 dataPtr(data_ptr), zeroType(zero_type), dataVec(data_vec),
109 dataDm(data_dm) {
112 THROW_MESSAGE("Cross-DM field evaluation requires OPROW or OPCOL");
113 if (!dataPtr)
114 THROW_MESSAGE("Pointer is not set");
115 }
116
118 const std::string field_name,
119 boost::shared_ptr<ublas::vector<T, A>> data_ptr,
120 SmartPetscObj<Vec> data_vec, const EntityType zero_type = MBVERTEX)
123 data_vec, zero_type) {}
124
125 /**
126 * @brief Constructor for scalar field values calculation operator
127 *
128 * @param field_name Name of the scalar field to calculate values for
129 * @param data_ptr Shared pointer to ublas vector for storing calculated values
130 * @param zero_type Entity type for zero-level entities (default: MBVERTEX)
131 */
133 const std::string field_name,
134 boost::shared_ptr<ublas::vector<T, A>> data_ptr,
135 const EntityType zero_type = MBVERTEX)
138 SmartPetscObj<Vec>(), zero_type) {}
139
140 /**
141 * \brief calculate values of scalar field at integration points
142 * @param side side entity number
143 * @param type side entity type
144 * @param data entity data
145 * @return error code
146 */
147 MoFEMErrorCode doWork(int side, EntityType type,
149
150protected:
151 boost::shared_ptr<ublas::vector<T, A>> dataPtr;
152 const EntityHandle zeroType;
156};
157
158/**
159 * \brief Specialization of member function
160 *
161 */
162template <class T, class A>
164 int side, EntityType type, EntitiesFieldData::EntData &data) {
166 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED, "Not implemented for T = %s",
167 typeid(T).name() // boost::core::demangle(typeid(T).name()).c_str()
168 );
170}
171
172/**
173 * @brief Specialization for double precision scalar field values calculation
174 *
175 * This structure is a specialization of OpCalculateScalarFieldValues_General
176 * for double precision scalar fields using DoubleAllocator. It provides
177 * concrete implementation for calculating scalar field values at integration
178 * points and storing them in double precision format.
179 *
180 * @ingroup mofem_forces_and_sources_user_data_operators
181 */
183 : public OpCalculateScalarFieldValues_General<double, DoubleAllocator> {
184
186 double, DoubleAllocator>::OpCalculateScalarFieldValues_General;
187
188 /**
189 * \brief calculate values of scalar field at integration points
190 * @param side side entity number
191 * @param type side entity type
192 * @param data entity data
193 * @return error code
194 */
195 MoFEMErrorCode doWork(int, EntityType type,
198 VectorDouble &vec = *dataPtr;
199 const size_t nb_gauss_pts = getGaussPts().size2();
200 if (type == zeroType || vec.size() != nb_gauss_pts) {
201 vec.resize(nb_gauss_pts, false);
202 vec.clear();
203 }
204
205 const size_t nb_dofs = data.getFieldData().size();
206
207 if (nb_dofs) {
208
209 if (dataVec.use_count()) {
210 dotVector.resize(nb_dofs, false);
211 const double *array;
212 CHKERR VecGetArrayRead(dataVec, &array);
213 if (dataDm) {
214 const Problem *problem_ptr;
215 CHKERR DMMoFEMGetProblemPtr(dataDm, &problem_ptr);
216 const NumeredDofEntityByUId *dofs_by_uid;
217 switch (getOpType()) {
219 dofs_by_uid =
220 &problem_ptr->numeredRowDofsPtr->get<Unique_mi_tag>();
221 break;
223 dofs_by_uid =
224 &problem_ptr->numeredColDofsPtr->get<Unique_mi_tag>();
225 break;
226 default:
227 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
228 "Cross-DM field evaluation requires OPROW or OPCOL");
229 }
230 const auto &field_dofs = data.getFieldDofs();
231 for (size_t i = 0; i != field_dofs.size(); ++i) {
232 const auto dof_it =
233 dofs_by_uid->find(field_dofs[i]->getLocalUniqueId());
234 dotVector[i] =
235 (dof_it != dofs_by_uid->end())
236 ? array[(*dof_it)->getPetscLocalDofIdx()]
237 : 0;
238 }
239 } else {
240 const auto &local_indices = data.getLocalIndices();
241 for (size_t i = 0; i != local_indices.size(); ++i)
242 if (local_indices[i] != -1)
243 dotVector[i] = array[local_indices[i]];
244 else
245 dotVector[i] = 0;
246 }
247 CHKERR VecRestoreArrayRead(dataVec, &array);
248 data.getFieldData().swap(dotVector);
249 }
250
251 const size_t nb_base_functions = data.getN().size2();
252 auto base_function = data.getFTensor0N();
253 auto values_at_gauss_pts = getFTensor0FromVec(vec);
254 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
255 auto field_data = data.getFTensor0FieldData();
256 size_t bb = 0;
257 for (; bb != nb_dofs; ++bb) {
258 values_at_gauss_pts += field_data * base_function;
259 ++field_data;
260 ++base_function;
261 }
262 // It is possible to have more base functions than dofs
263 for (; bb < nb_base_functions; ++bb)
264 ++base_function;
265 ++values_at_gauss_pts;
266 }
267
268 if (dataVec.use_count()) {
269 data.getFieldData().swap(dotVector);
270 }
271 }
272
274 }
275};
276
277/**
278 * @brief Calculate scalar field values from PETSc vector at integration points
279 *
280 * This template structure extracts scalar field values from a PETSc vector
281 * and calculates them at integration points. It supports different data contexts
282 * through the template parameter and can handle various entity types.
283 *
284 * @tparam CTX PETSc data context type specifying how data is accessed
285 *
286 * @ingroup mofem_forces_and_sources_user_data_operators
287 */
288template <PetscData::DataContext CTX>
291
292 /**
293 * @brief Constructor for PETSc vector-based scalar field calculation
294 *
295 * @param field_name Name of the scalar field to extract values from
296 * @param data_ptr Shared pointer to VectorDouble for storing calculated values
297 * @param zero_at_type Entity type where values should be zeroed (default: MBVERTEX)
298 */
300 const std::string field_name, boost::shared_ptr<VectorDouble> data_ptr,
301 const EntityType zero_at_type = MBVERTEX)
304 dataPtr(data_ptr), zeroAtType(zero_at_type) {
305 if (!dataPtr)
306 THROW_MESSAGE("Pointer is not set");
307 }
308
309 MoFEMErrorCode doWork(int side, EntityType type,
312
313 const size_t nb_gauss_pts = getGaussPts().size2();
314
315 VectorDouble &vec = *dataPtr;
316 if (type == zeroAtType || vec.size() != nb_gauss_pts) {
317 vec.resize(nb_gauss_pts, false);
318 vec.clear();
319 }
320
321 auto &local_indices = data.getLocalIndices();
322 const size_t nb_dofs = local_indices.size();
323 if (nb_dofs) {
324
325 const double *array;
326
327 auto get_array = [&](const auto ctx, auto vec) {
329 #ifndef NDEBUG
330 if ((getFEMethod()->data_ctx & ctx).none()) {
331 MOFEM_LOG_CHANNEL("SELF");
332 MOFEM_LOG("SELF", Sev::error)
333 << "In this case field degrees of freedom are read from vector. "
334 "That usually happens when time solver is used, and acces to "
335 "first or second rates is needed. You probably not set ts_u, "
336 "ts_u_t, or ts_u_tt and associated data structure, i.e. "
337 "data_ctx to CTX_SET_X, CTX_SET_X_T, or CTX_SET_X_TT "
338 "respectively";
339 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Vector not set!");
340 }
341 #endif
342 CHKERR VecGetArrayRead(vec, &array);
344 };
345
346 auto restore_array = [&](auto vec) {
347 return VecRestoreArrayRead(vec, &array);
348 };
349
350 switch (CTX) {
352 CHKERR get_array(PetscData::CtxSetX, getFEMethod()->ts_u);
353 break;
355 CHKERR get_array(PetscData::CtxSetX_T, getFEMethod()->ts_u_t);
356 break;
358 CHKERR get_array(PetscData::CtxSetX_TT, getFEMethod()->ts_u_tt);
359 break;
360 default:
361 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
362 "That case is not implemented");
363 }
364
365 std::array<double, MAX_DOFS_ON_ENTITY> dot_dofs_vector;
366 for (int i = 0; i != local_indices.size(); ++i)
367 if (local_indices[i] != -1)
368 dot_dofs_vector[i] = array[local_indices[i]];
369 else
370 dot_dofs_vector[i] = 0;
371
372 switch (CTX) {
374 CHKERR restore_array(getFEMethod()->ts_u);
375 break;
377 CHKERR restore_array(getFEMethod()->ts_u_t);
378 break;
380 CHKERR restore_array(getFEMethod()->ts_u_tt);
381 break;
382 default:
383 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
384 "That case is not implemented");
385 }
386
387 const size_t nb_base_functions = data.getN().size2();
388 auto base_function = data.getFTensor0N();
389 auto values_at_gauss_pts = getFTensor0FromVec(vec);
390
391 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
392 size_t bb = 0;
393 for (; bb != nb_dofs; ++bb) {
394 values_at_gauss_pts += dot_dofs_vector[bb] * base_function;
395 ++base_function;
396 }
397 // Number of dofs can be smaller than number of Tensor_Dim x base
398 // functions
399 for (; bb < nb_base_functions; ++bb)
400 ++base_function;
401 ++values_at_gauss_pts;
402 }
403 }
405 }
406
407private:
408 boost::shared_ptr<VectorDouble> dataPtr;
409 const EntityHandle zeroAtType;
410};
411
416
417/**
418 * \deprecated Name inconsistent with other operators
419 *
420 */
422
423/**@}*/
424
425/** \name Vector field values at integration points */
426
427/**@{*/
428
429/**
430 * @brief Calculate field values for tensor field rank 1, i.e. vector field
431 *
432 * This template structure calculates vector field values at integration points
433 * and stores them in a matrix container. It supports various tensor dimensions,
434 * matrix storage types through template parameters.
435 *
436 * @tparam Tensor_Dim Dimension of the vector field (e.g., 2 for 2D, 3 for 3D)
437 * @tparam M Matrix storage type for the field values
438 */
439template <int Tensor_Dim, typename M = MatrixDouble>
442
443 /**
444 * @brief Constructor for vector field values calculation operator
445 *
446 * @param field_name Name of the vector field to calculate values for
447 * @param data_ptr Shared pointer to ublas matrix for storing calculated values
448 * @param zero_type Entity type for zero-level entities (default: MBVERTEX)
449 */
451 const std::string field_name,
452 boost::shared_ptr<M> data_ptr,
453 const EntityType zero_type = MBVERTEX)
456 dataPtr(data_ptr), zeroType(zero_type) {
457 if (!dataPtr)
458 THROW_MESSAGE("Pointer is not set");
459 }
460
461 /**
462 * \brief calculate values of vector field at integration points
463 * @param side side entity number
464 * @param type side entity type
465 * @param data entity data
466 * @return error code
467 */
468 MoFEMErrorCode doWork(int side, EntityType type,
470
471protected:
472 boost::shared_ptr<M> dataPtr;
473 const EntityHandle zeroType;
474};
475
476template <int Tensor_Dim, typename M>
479 int side, EntityType type, EntitiesFieldData::EntData &data) {
481 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
482 "Not implemented for matrix type = %s and dim = %d",
483 typeid(M).name(), // boost::core::demangle(typeid(M).name()),
484 Tensor_Dim);
486}
487
488/** \brief Calculate field values (template specialization) for tensor field
489 * rank 1, i.e. vector field
490 *
491 */
492template <int Tensor_Dim>
495
497 boost::shared_ptr<MatrixDouble> data_ptr,
498 const EntityType zero_type = MBVERTEX,
499 const int max_order = -1)
502 dataPtr(data_ptr), zeroType(zero_type), maxOrder(max_order) {
503 if (!dataPtr)
504 THROW_MESSAGE("Pointer is not set");
505 }
506
508 boost::shared_ptr<MatrixDouble> data_ptr,
509 SmartPetscObj<Vec> data_vec,
510 const EntityType zero_type = MBVERTEX,
511 const int max_order = -1)
514 dataPtr(data_ptr), dataVec(data_vec), zeroType(zero_type),
515 maxOrder(max_order) {
516 if (!dataPtr)
517 THROW_MESSAGE("Pointer is not set");
518 }
519
521 SmartPetscObj<DM> data_dm,
523 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
524 SmartPetscObj<Vec> data_vec, const EntityType zero_type = MBVERTEX,
525 const int max_order = -1)
527 dataPtr(data_ptr), dataVec(data_vec), dataDm(data_dm),
528 zeroType(zero_type), maxOrder(max_order) {
531 THROW_MESSAGE("Cross-DM field evaluation requires OPROW or OPCOL");
532 if (!dataPtr)
533 THROW_MESSAGE("Pointer is not set");
534 }
535
536 MoFEMErrorCode doWork(int side, EntityType type,
538
539protected:
540 boost::shared_ptr<MatrixDouble> dataPtr;
543 const EntityHandle zeroType;
545 int maxOrder = -1;
546};
547
548/**
549 * \brief Member function specialization calculating values for tenor field rank
550 *
551 */
552template <int Tensor_Dim>
554 Tensor_Dim, MatrixDouble>::doWork(int, EntityType type,
557
558 const size_t nb_gauss_pts = getGaussPts().size2();
559 auto &mat = *dataPtr;
560
562 auto get_values_at_gauss_pts =
563 MatrixSizeHelper<GetFTensor1FromMatType<Tensor_Dim, -1, DL>, DL>::size(
564 mat, nb_gauss_pts);
565 if (type == zeroType) {
566 mat.clear();
567 }
568
569 const size_t nb_dofs = data.getFieldData().size();
570 if (nb_dofs) {
571
572 auto max_order =
573 (maxOrder == -1) ? MAX_DOFS_ON_ENTITY : maxOrder;
574 const auto max_size =
575 (type == MBVERTEX) ? MAX_DOFS_ON_ENTITY
576 : data.getFieldDofs()[0]->getOrderNbDofs(max_order);
577
578 if (dataVec.use_count()) {
579 dotVector.resize(nb_dofs, false);
580 const double *array;
581 CHKERR VecGetArrayRead(dataVec, &array);
582 if (dataDm) {
583 const Problem *problem_ptr;
584 CHKERR DMMoFEMGetProblemPtr(dataDm, &problem_ptr);
585 const NumeredDofEntityByUId *dofs_by_uid;
586 switch (getOpType()) {
588 dofs_by_uid = &problem_ptr->numeredRowDofsPtr->get<Unique_mi_tag>();
589 break;
591 dofs_by_uid = &problem_ptr->numeredColDofsPtr->get<Unique_mi_tag>();
592 break;
593 default:
594 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
595 "Cross-DM field evaluation requires OPROW or OPCOL");
596 }
597 const auto &field_dofs = data.getFieldDofs();
598 for (size_t i = 0; i != field_dofs.size(); ++i) {
599 const auto dof_it =
600 dofs_by_uid->find(field_dofs[i]->getLocalUniqueId());
601 dotVector[i] = (dof_it != dofs_by_uid->end())
602 ? array[(*dof_it)->getPetscLocalDofIdx()]
603 : 0;
604 }
605 } else {
606 const auto &local_indices = data.getLocalIndices();
607 for (size_t i = 0; i != local_indices.size(); ++i)
608 if (local_indices[i] != -1)
609 dotVector[i] = array[local_indices[i]];
610 else
611 dotVector[i] = 0;
612 }
613 CHKERR VecRestoreArrayRead(dataVec, &array);
614 data.getFieldData().swap(dotVector);
615 }
616
617 if (nb_gauss_pts) {
618 const size_t nb_base_functions = data.getN().size2();
619 auto base_function = data.getFTensor0N();
620 auto t_values_at_gauss_pts = get_values_at_gauss_pts();
621 FTensor::Index<'I', Tensor_Dim> I;
622 const size_t size = nb_dofs / Tensor_Dim;
623 if (nb_dofs % Tensor_Dim) {
624 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
625 "Nb. of DOFs is inconsistent with Tensor_Dim");
626 }
627 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
628 auto field_data = data.getFTensor1FieldData<Tensor_Dim>();
629
630 #ifndef NDEBUG
631 if (field_data.l2() != field_data.l2()) {
632 MOFEM_LOG("SELF", Sev::error) << "field data: " << field_data;
633 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
634 "Wrong number in coefficients");
635 }
636 #endif
637
638 size_t bb = 0;
639 for (; bb != size; ++bb) {
640
641 #ifndef SINGULARITY
642 #ifndef NDEBUG
643 if (base_function != base_function) {
644 MOFEM_LOG("SELF", Sev::error) << "base function: " << base_function;
645 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
646 "Wrong number number in base functions");
647 }
648 #endif
649 #endif
650
651 if (bb <= max_size) {
652 t_values_at_gauss_pts(I) += field_data(I) * base_function;
653 }
654 ++field_data;
655 ++base_function;
656 }
657 // Number of dofs can be smaller than number of Tensor_Dim x base
658 // functions
659 for (; bb < nb_base_functions; ++bb)
660 ++base_function;
661 ++t_values_at_gauss_pts;
662 }
663 }
664
665 if (dataVec.use_count()) {
666 data.getFieldData().swap(dotVector);
667 }
668 }
670}
671
672/**
673 * @brief Specialization for MatrixDouble vector field values calculation
674 *
675 * This structure is a specialization of OpCalculateVectorFieldValues_General
676 * for vector fields stored in MatrixDouble. It provides a convenient interface
677 * for calculating vector field values at integration points.
678 *
679 * @tparam Tensor_Dim Dimension of the vector field (e.g., 2 for 2D, 3 for 3D)
680 *
681 * @ingroup mofem_forces_and_sources_user_data_operators
682 */
683template <int Tensor_Dim>
685 : public OpCalculateVectorFieldValues_General<Tensor_Dim> {
686
688 Tensor_Dim>::OpCalculateVectorFieldValues_General;
689};
690
691/**@}*/
692
693/** \name Vector field values at integration points */
694
695/**@{*/
696
697/**
698 * @brief Calculate divergence of vector field at integration points
699 *
700 * This template structure calculates the divergence of a vector field at
701 * integration points. It supports different coordinate systems and tensor
702 * dimensions, making it suitable for various physical applications.
703 *
704 * @tparam Tensor_Dim Dimension of the vector field (e.g., 2 for 2D, 3 for 3D)
705 * @tparam COORDINATE_SYSTEM Coordinate system type (default: CARTESIAN)
706 */
707template <int Tensor_Dim, CoordinateTypes COORDINATE_SYSTEM = CARTESIAN>
710
711 /**
712 * @brief Constructor for vector field divergence calculation operator
713 *
714 * @param field_name Name of the vector field to calculate divergence for
715 * @param data_ptr Shared pointer to VectorDouble for storing calculated divergence values
716 * @param zero_type Entity type for zero-level entities (default: MBVERTEX)
717 */
719 const std::string field_name, boost::shared_ptr<VectorDouble> data_ptr,
720 const EntityType zero_type = MBVERTEX)
723 dataPtr(data_ptr), zeroType(zero_type) {
724 if (!dataPtr)
725 THROW_MESSAGE("Pointer is not set");
726 }
727
728 MoFEMErrorCode doWork(int side, EntityType type,
731
732 // When we move to C++17 add if constexpr()
733 if constexpr (COORDINATE_SYSTEM == POLAR || COORDINATE_SYSTEM == SPHERICAL)
734 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
735 "%s coordiante not implemented",
736 CoordinateTypesNames[COORDINATE_SYSTEM]);
737
738 const size_t nb_gauss_pts = getGaussPts().size2();
739 auto &vec = *dataPtr;
740 if (type == zeroType) {
741 vec.resize(nb_gauss_pts, false);
742 vec.clear();
743 }
744
745 const size_t nb_dofs = data.getFieldData().size();
746 if (nb_dofs) {
747
748 if (nb_gauss_pts) {
749 const size_t nb_base_functions = data.getN().size2();
750 auto values_at_gauss_pts = getFTensor0FromVec(vec);
751 FTensor::Index<'I', Tensor_Dim> I;
752 const size_t size = nb_dofs / Tensor_Dim;
753 #ifndef NDEBUG
754 if (nb_dofs % Tensor_Dim) {
755 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
756 "Number of dofs should multiple of dimensions");
757 }
758 #endif
759
760 // When we move to C++17 add if constexpr()
761 if constexpr (COORDINATE_SYSTEM == CARTESIAN) {
762 auto diff_base_function = data.getFTensor1DiffN<Tensor_Dim>();
763 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
764 auto field_data = data.getFTensor1FieldData<Tensor_Dim>();
765 size_t bb = 0;
766 for (; bb != size; ++bb) {
767 values_at_gauss_pts += field_data(I) * diff_base_function(I);
768 ++field_data;
769 ++diff_base_function;
770 }
771 // Number of dofs can be smaller than number of Tensor_Dim x base
772 // functions
773 for (; bb < nb_base_functions; ++bb)
774 ++diff_base_function;
775 ++values_at_gauss_pts;
776 }
777 }
778
779 // When we move to C++17 add if constexpr()
780 if constexpr (COORDINATE_SYSTEM == CYLINDRICAL) {
781 auto t_coords = getFTensor1CoordsAtGaussPts();
782 auto values_at_gauss_pts = getFTensor0FromVec(vec);
783 auto base_function = data.getFTensor0N();
784 auto diff_base_function = data.getFTensor1DiffN<Tensor_Dim>();
785 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
786 auto field_data = data.getFTensor1FieldData<Tensor_Dim>();
787 size_t bb = 0;
788 for (; bb != size; ++bb) {
789 values_at_gauss_pts += field_data(I) * diff_base_function(I);
790 values_at_gauss_pts +=
791 base_function * (field_data(0) / t_coords(0));
792 ++field_data;
793 ++base_function;
794 ++diff_base_function;
795 }
796 // Number of dofs can be smaller than number of Tensor_Dim x base
797 // functions
798 for (; bb < nb_base_functions; ++bb) {
799 ++base_function;
800 ++diff_base_function;
801 }
802 ++values_at_gauss_pts;
803 ++t_coords;
804 }
805 }
806 }
807 }
809 }
810
811protected:
812 boost::shared_ptr<VectorDouble> dataPtr;
813 const EntityHandle zeroType;
814};
815
816/** \brief Approximate field values for given petsc vector
817 *
818 * \note Look at PetscData to see what vectors could be extracted with that user
819 * data operator.
820 *
821 * \ingroup mofem_forces_and_sources_user_data_operators
822 */
823template <int Tensor_Dim, PetscData::DataContext CTX>
826
828 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
829 const EntityType zero_at_type = MBVERTEX, bool throw_error = true)
832 dataPtr(data_ptr), zeroAtType(zero_at_type), throwError(throw_error) {
833 if (!dataPtr)
834 THROW_MESSAGE("Pointer is not set");
835 }
836
837 MoFEMErrorCode doWork(int side, EntityType type,
840
841 auto &local_indices = data.getLocalIndices();
842 const size_t nb_dofs = local_indices.size();
843 const size_t nb_gauss_pts = getGaussPts().size2();
844
845 MatrixDouble &mat = *dataPtr;
847 auto get_values_at_gauss_pts =
848 MatrixSizeHelper<GetFTensor1FromMatType<Tensor_Dim, -1, DL>,
849 DL>::size(mat, nb_gauss_pts);
850 if (type == zeroAtType) {
851 mat.clear();
852 }
853 if (!nb_dofs)
855
856 if (!throwError) {
857 if ((getFEMethod()->data_ctx & PetscData::Switches(CTX)).none()) {
859 }
860 }
861
862 const double *array;
863
864 auto get_array = [&](const auto ctx, auto vec) {
866 #ifndef NDEBUG
867 if ((getFEMethod()->data_ctx & ctx).none()) {
868 MOFEM_LOG_CHANNEL("SELF");
869 MOFEM_LOG("SELF", Sev::error)
870 << "In this case field degrees of freedom are read from vector. "
871 "That usually happens when time solver is used, and access to "
872 "first or second rates is needed. You probably not set ts_u, "
873 "ts_u_t, or ts_u_tt and associated data structure, i.e. "
874 "data_ctx to CTX_SET_X, CTX_SET_DX, CTX_SET_X_T, or "
875 "CTX_SET_X_TT respectively";
876 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Vector not set");
877 }
878 #endif
879 CHKERR VecGetArrayRead(vec, &array);
881 };
882
883 auto restore_array = [&](auto vec) {
884 return VecRestoreArrayRead(vec, &array);
885 };
886
887 switch (CTX) {
889 CHKERR get_array(PetscData::CtxSetX, getFEMethod()->ts_u);
890 break;
892 CHKERR get_array(PetscData::CtxSetX, getFEMethod()->dx);
893 break;
895 CHKERR get_array(PetscData::CtxSetX_T, getFEMethod()->ts_u_t);
896 break;
898 CHKERR get_array(PetscData::CtxSetX_TT, getFEMethod()->ts_u_tt);
899 break;
900 default:
901 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
902 "That case is not implemented");
903 }
904
905 dotVector.resize(local_indices.size());
906 for (int i = 0; i != local_indices.size(); ++i)
907 if (local_indices[i] != -1)
908 dotVector[i] = array[local_indices[i]];
909 else
910 dotVector[i] = 0;
911
912 switch (CTX) {
914 CHKERR restore_array(getFEMethod()->ts_u);
915 break;
917 CHKERR restore_array(getFEMethod()->dx);
918 break;
920 CHKERR restore_array(getFEMethod()->ts_u_t);
921 break;
923 CHKERR restore_array(getFEMethod()->ts_u_tt);
924 break;
925 default:
926 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
927 "That case is not implemented");
928 }
929
930 const size_t nb_base_functions = data.getN().size2();
931 auto base_function = data.getFTensor0N();
932 auto t_values_at_gauss_pts = get_values_at_gauss_pts();
933
934 FTensor::Index<'I', Tensor_Dim> I;
935 const size_t size = nb_dofs / Tensor_Dim;
936 if (nb_dofs % Tensor_Dim) {
937 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Data inconsistency");
938 }
939 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
940 auto field_data = getFTensor1FromArray<Tensor_Dim, Tensor_Dim>(dotVector);
941 size_t bb = 0;
942 for (; bb != size; ++bb) {
943 t_values_at_gauss_pts(I) += field_data(I) * base_function;
944 ++field_data;
945 ++base_function;
946 }
947 // Number of dofs can be smaller than number of Tensor_Dim x base
948 // functions
949 for (; bb < nb_base_functions; ++bb)
950 ++base_function;
951 ++t_values_at_gauss_pts;
952 }
954 }
955
956protected:
957 boost::shared_ptr<MatrixDouble> dataPtr;
958 const EntityHandle zeroAtType;
961};
962
963/** \brief Get rate of values at integration pts for tensor field
964 * rank 1, i.e. vector field
965 *
966 * \ingroup mofem_forces_and_sources_user_data_operators
967 */
968template <int Tensor_Dim>
972
973/** \brief Get second rate of values at integration pts for tensor
974 * field rank 1, i.e. vector field
975 *
976 * \ingroup mofem_forces_and_sources_user_data_operators
977 */
978template <int Tensor_Dim>
982
983/** \brief Get second time second update vector at integration pts for tensor
984 * field rank 1, i.e. vector field
985 *
986 * \ingroup mofem_forces_and_sources_user_data_operators
987 */
988template <int Tensor_Dim>
992
993/**@}*/
994
995/** \name Tensor field values at integration points */
996
997/**@{*/
998
999/** \brief Calculate field values for tenor field rank 2.
1000 *
1001 */
1002template <int Tensor_Dim0, int Tensor_Dim1, typename M = MatrixDouble>
1005
1007 const std::string field_name,
1008 boost::shared_ptr<M> data_ptr,
1009 const EntityType zero_type = MBVERTEX)
1012 dataPtr(data_ptr), zeroType(zero_type) {
1013 if (!dataPtr)
1014 THROW_MESSAGE("Pointer is not set");
1015 }
1016
1017 MoFEMErrorCode doWork(int side, EntityType type,
1019
1020protected:
1021 boost::shared_ptr<M> dataPtr;
1022 const EntityHandle zeroType;
1023};
1024
1025template <int Tensor_Dim0, int Tensor_Dim1, typename M>
1028 doWork(int side, EntityType type, EntitiesFieldData::EntData &data) {
1030 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
1031 "Not implemented for matrix type = %s, dim0 = %d and dim1 = %d",
1032 typeid(M).name(), // boost::core::demangle(typeid(M).name()),
1033 Tensor_Dim0, Tensor_Dim1);
1035}
1036
1037template <int Tensor_Dim0, int Tensor_Dim1>
1038struct OpCalculateTensor2FieldValues_General<Tensor_Dim0, Tensor_Dim1,
1041
1044 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
1045 SmartPetscObj<Vec> data_vec, const EntityType zero_type = MBVERTEX)
1047 dataPtr(data_ptr), zeroType(zero_type), dataVec(data_vec) {
1048 if (!dataPtr)
1049 THROW_MESSAGE("Pointer is not set");
1050 }
1051
1053 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
1054 const EntityType zero_type = MBVERTEX)
1057 SmartPetscObj<Vec>(), zero_type) {}
1058
1060 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
1061 SmartPetscObj<Vec> data_vec, const EntityType zero_type = MBVERTEX)
1064 data_vec, zero_type) {}
1065
1066 MoFEMErrorCode doWork(int side, EntityType type,
1068
1069protected:
1070 boost::shared_ptr<MatrixDouble> dataPtr;
1071 const EntityHandle zeroType;
1074};
1075
1076template <int Tensor_Dim0, int Tensor_Dim1>
1078 Tensor_Dim0, Tensor_Dim1, MatrixDouble>::doWork(
1079 int side, EntityType type, EntitiesFieldData::EntData &data) {
1081
1083 MatrixDouble &mat = *dataPtr;
1084 const size_t nb_gauss_pts = data.getN().size1();
1085 auto get_values_at_gauss_pts =
1086 MatrixSizeHelper<GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
1087 DL>::size(mat, nb_gauss_pts);
1088 if (type == zeroType)
1089 mat.clear();
1090
1091 const size_t nb_dofs = data.getFieldData().size();
1092
1093 if (dataVec.use_count()) {
1094 dotVector.resize(nb_dofs, false);
1095 const double *array;
1096 CHKERR VecGetArrayRead(dataVec, &array);
1097 const auto &local_indices = data.getLocalIndices();
1098 for (int i = 0; i != local_indices.size(); ++i)
1099 if (local_indices[i] != -1)
1100 dotVector[i] = array[local_indices[i]];
1101 else
1102 dotVector[i] = 0;
1103 CHKERR VecRestoreArrayRead(dataVec, &array);
1104 data.getFieldData().swap(dotVector);
1105 }
1106
1107 if (nb_dofs) {
1108 const size_t nb_base_functions = data.getN().size2();
1109 auto base_function = data.getFTensor0N();
1110 auto t_values_at_gauss_pts = get_values_at_gauss_pts();
1111 FTensor::Index<'i', Tensor_Dim0> i;
1112 FTensor::Index<'j', Tensor_Dim1> j;
1113 const size_t size = nb_dofs / (Tensor_Dim0 * Tensor_Dim1);
1114 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
1115 auto field_data = data.getFTensor2FieldData<Tensor_Dim0, Tensor_Dim1>();
1116 size_t bb = 0;
1117 for (; bb != size; ++bb) {
1118 t_values_at_gauss_pts(i, j) += field_data(i, j) * base_function;
1119 ++field_data;
1120 ++base_function;
1121 }
1122 for (; bb < nb_base_functions; ++bb)
1123 ++base_function;
1124 ++t_values_at_gauss_pts;
1125 }
1126
1127 if (dataVec.use_count()) {
1128 data.getFieldData().swap(dotVector);
1129 }
1130 }
1132}
1133
1134/** \brief Get values at integration pts for tensor field rank 2, i.e. matrix
1135 * field
1136 *
1137 * \ingroup mofem_forces_and_sources_user_data_operators
1138 */
1139template <int Tensor_Dim0, int Tensor_Dim1>
1141 : public OpCalculateTensor2FieldValues_General<Tensor_Dim0,
1142 Tensor_Dim1> {
1143
1145 Tensor_Dim0, Tensor_Dim1>::OpCalculateTensor2FieldValues_General;
1146};
1147
1148/** \brief Get time direvarive values at integration pts for tensor field rank
1149 * 2, i.e. matrix field
1150 *
1151 * \ingroup mofem_forces_and_sources_user_data_operators
1152 */
1153template <int Tensor_Dim0, int Tensor_Dim1>
1156
1158 boost::shared_ptr<MatrixDouble> data_ptr,
1159 const EntityType zero_at_type = MBVERTEX)
1162 dataPtr(data_ptr), zeroAtType(zero_at_type) {
1163 if (!dataPtr)
1164 THROW_MESSAGE("Pointer is not set");
1165 }
1166
1167 MoFEMErrorCode doWork(int side, EntityType type,
1170
1172 const size_t nb_gauss_pts = getGaussPts().size2();
1173 MatrixDouble &mat = *dataPtr;
1174 auto get_values_at_gauss_pts =
1176 GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
1177 DL>::size(mat, nb_gauss_pts);
1178 if (type == zeroAtType)
1179 mat.clear();
1180 const auto &local_indices = data.getLocalIndices();
1181 const size_t nb_dofs = local_indices.size();
1182 if (nb_dofs) {
1183 dotVector.resize(nb_dofs, false);
1184 const double *array;
1185 CHKERR VecGetArrayRead(getFEMethod()->ts_u_t, &array);
1186 for (size_t i = 0; i != local_indices.size(); ++i)
1187 if (local_indices[i] != -1)
1188 dotVector[i] = array[local_indices[i]];
1189 else
1190 dotVector[i] = 0;
1191 CHKERR VecRestoreArrayRead(getFEMethod()->ts_u_t, &array);
1192
1193 const size_t nb_base_functions = data.getN().size2();
1194
1195 auto base_function = data.getFTensor0N();
1196 auto t_values_at_gauss_pts = get_values_at_gauss_pts();
1197 FTensor::Index<'i', Tensor_Dim0> i;
1198 FTensor::Index<'j', Tensor_Dim1> j;
1199 const size_t size = nb_dofs / (Tensor_Dim0 * Tensor_Dim1);
1200 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
1201 auto field_data =
1202 getFTensor2FromPtr<Tensor_Dim0, Tensor_Dim1>(&*dotVector.begin());
1203 size_t bb = 0;
1204 for (; bb != size; ++bb) {
1205 t_values_at_gauss_pts(i, j) += field_data(i, j) * base_function;
1206 ++field_data;
1207 ++base_function;
1208 }
1209 for (; bb < nb_base_functions; ++bb)
1210 ++base_function;
1211 ++t_values_at_gauss_pts;
1212 }
1213 }
1215 }
1216
1217protected:
1218 boost::shared_ptr<MatrixDouble> dataPtr; ///< Data computed into this matrix
1219 EntityType zeroAtType; ///< Zero values at Gauss point at this type
1220 VectorDouble dotVector; ///< Keeps temporary values of time derivatives
1221};
1222
1223/**
1224 * @brief Calculate symmetric tensor field values at integration pts.
1225 *
1226 * @tparam Tensor_Dim
1227
1228 * \ingroup mofem_forces_and_sources_user_data_operators
1229 */
1230template <int Tensor_Dim>
1233
1235 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
1236 const EntityType zero_type = MBEDGE, const int zero_side = 0)
1239 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
1240 if (!dataPtr)
1241 THROW_MESSAGE("Pointer is not set");
1242 }
1243
1245 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
1246 SmartPetscObj<Vec> data_vec, const EntityType zero_type = MBEDGE,
1247 const int zero_side = 0)
1250 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side),
1251 dataVec(data_vec) {
1252 if (!dataPtr)
1253 THROW_MESSAGE("Pointer is not set");
1254 }
1255
1257 SmartPetscObj<DM> data_dm,
1259 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
1260 SmartPetscObj<Vec> data_vec, const EntityType zero_type = MBEDGE,
1261 const int zero_side = 0)
1263 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side),
1264 dataVec(data_vec), dataDm(data_dm) {
1267 THROW_MESSAGE("Cross-DM field evaluation requires OPROW or OPCOL");
1268 if (!dataPtr)
1269 THROW_MESSAGE("Pointer is not set");
1270 }
1271
1272 MoFEMErrorCode doWork(int side, EntityType type,
1275 MatrixDouble &mat = *dataPtr;
1276 const int nb_gauss_pts = getGaussPts().size2();
1278 auto get_values_at_gauss_pts =
1280 DL>::size(mat, nb_gauss_pts);
1281 if (type == this->zeroType && side == zeroSide) {
1282 mat.clear();
1283 }
1284 const int nb_dofs = data.getFieldData().size();
1285 if (!nb_dofs)
1287
1288 if (dataVec.use_count()) {
1289 dotVector.resize(nb_dofs, false);
1290 const double *array;
1291 CHKERR VecGetArrayRead(dataVec, &array);
1292 if (dataDm) {
1293 const Problem *problem_ptr;
1294 CHKERR DMMoFEMGetProblemPtr(dataDm, &problem_ptr);
1295 const NumeredDofEntityByUId *dofs_by_uid;
1296 switch (getOpType()) {
1298 dofs_by_uid = &problem_ptr->numeredRowDofsPtr->get<Unique_mi_tag>();
1299 break;
1301 dofs_by_uid = &problem_ptr->numeredColDofsPtr->get<Unique_mi_tag>();
1302 break;
1303 default:
1304 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
1305 "Cross-DM field evaluation requires OPROW or OPCOL");
1306 }
1307 const auto &field_dofs = data.getFieldDofs();
1308 for (int i = 0; i != field_dofs.size(); ++i) {
1309 const auto dof_it =
1310 dofs_by_uid->find(field_dofs[i]->getLocalUniqueId());
1311 dotVector[i] = (dof_it != dofs_by_uid->end())
1312 ? array[(*dof_it)->getPetscLocalDofIdx()]
1313 : 0;
1314 }
1315 } else {
1316 const auto &local_indices = data.getLocalIndices();
1317 for (int i = 0; i != local_indices.size(); ++i)
1318 if (local_indices[i] != -1)
1319 dotVector[i] = array[local_indices[i]];
1320 else
1321 dotVector[i] = 0;
1322 }
1323 CHKERR VecRestoreArrayRead(dataVec, &array);
1324 data.getFieldData().swap(dotVector);
1325 }
1326
1327 const int nb_base_functions = data.getN().size2();
1328 auto base_function = data.getFTensor0N();
1329 auto t_values_at_gauss_pts = get_values_at_gauss_pts();
1330 FTensor::Index<'i', Tensor_Dim> i;
1331 FTensor::Index<'j', Tensor_Dim> j;
1332 const int size = nb_dofs / ((Tensor_Dim * (Tensor_Dim + 1)) / 2);
1333 for (int gg = 0; gg != nb_gauss_pts; ++gg) {
1334 auto field_data = data.getFTensor2SymmetricFieldData<Tensor_Dim>();
1335 int bb = 0;
1336 for (; bb != size; ++bb) {
1337 t_values_at_gauss_pts(i, j) += field_data(i, j) * base_function;
1338 ++field_data;
1339 ++base_function;
1340 }
1341 for (; bb < nb_base_functions; ++bb)
1342 ++base_function;
1343 ++t_values_at_gauss_pts;
1344 }
1345
1346 if (dataVec.use_count()) {
1347 data.getFieldData().swap(dotVector);
1348 }
1349
1351 }
1352
1353protected:
1354 boost::shared_ptr<MatrixDouble> dataPtr;
1355 const EntityHandle zeroType;
1356 const int zeroSide;
1360};
1361
1362/** Orthonormal coordinates for three-dimensional symmetric deviators.
1363 * Three coordinates retain the planar E1, E2, E3 subspace; five span all
1364 * symmetric trace-free tensors. Both reconstructions return a 3x3 tensor.
1365 */
1367 /// Basis columns (11-22)/sqrt(2), (11+22-2*33)/sqrt(6), 12, 13, 23.
1369 static const auto t_basis = [] {
1370 FTENSOR_INDEXES(3, i, j);
1371 FTensor::Index<'A', 5> A;
1373 t_basis(i, j, A) = 0.;
1374 constexpr double inverse_sqrt_two = 0.70710678118654752440;
1375 constexpr double inverse_sqrt_six = 0.40824829046386301637;
1376 t_basis(0, 0, 0) = inverse_sqrt_two;
1377 t_basis(1, 1, 0) = -inverse_sqrt_two;
1378 t_basis(0, 0, 1) = inverse_sqrt_six;
1379 t_basis(1, 1, 1) = inverse_sqrt_six;
1380 t_basis(2, 2, 1) = -2. * inverse_sqrt_six;
1381 t_basis(0, 1, 2) = inverse_sqrt_two;
1382 t_basis(0, 2, 3) = inverse_sqrt_two;
1383 t_basis(1, 2, 4) = inverse_sqrt_two;
1384 return t_basis;
1385 }();
1386 return t_basis;
1387 }
1388
1389 /// Reconstruct D + theta*I/3; input may be an owning tensor or a view.
1390 template <typename T, int Size>
1393 const double theta = 0.) {
1394 static_assert(Size == 3 || Size == 5, "Expected three or five coordinates");
1395 FTENSOR_INDEXES(3, i, j);
1396 FTensor::Index<'A', Size> A;
1397 constexpr auto t_identity = FTensor::Kronecker_Delta_symmetric<int>();
1398 const auto &t_basis = getBasis();
1400 t_tensor(i, j) =
1401 t_basis(i, j, A) * t_coordinates(A) + (theta / 3.) * t_identity(i, j);
1402 return t_tensor;
1403 }
1404
1405 /// Project a full or symmetric tensor onto the five orthonormal columns.
1406 template <typename Tensor>
1407 static FTensor::Tensor1<double, 5> getCoordinates(const Tensor &t_tensor) {
1408 FTENSOR_INDEXES(3, i, j);
1409 FTensor::Index<'A', 5> A;
1410 const auto &t_basis = getBasis();
1411 FTensor::Tensor1<double, 5> t_coordinates;
1412 t_coordinates(A) = t_basis(i, j, A) * t_tensor(i, j);
1413 return t_coordinates;
1414 }
1415};
1416
1417
1418/** Interpolate deviator coordinates using the ordinary field evaluator.
1419 * Output is a symmetric 3x3 tensor in GaussByCoeffs storage. The optional
1420 * coordinates matrix shares the interpolated values with constitutive kernels
1421 * that work in coefficient space, without evaluating the field twice.
1422 */
1423template <int CoordinateSize>
1425 : public OpCalculateVectorFieldValues<CoordinateSize> {
1426 static_assert(CoordinateSize == 3 || CoordinateSize == 5,
1427 "Expected three or five deviator coordinates");
1429 using MatrixPtr = boost::shared_ptr<MatrixDouble>;
1430
1432 const std::string field_name, MatrixPtr data_ptr,
1433 const EntityType zero_type = MBEDGE, const int zero_side = 0)
1435 field_name, data_ptr, SmartPetscObj<Vec>(), zero_type, zero_side) {}
1436
1438 const std::string field_name, MatrixPtr data_ptr,
1439 SmartPetscObj<Vec> data_vec, const EntityType zero_type = MBEDGE,
1440 const int zero_side = 0, MatrixPtr coordinates = nullptr)
1441 : Base(field_name, coordinates ? coordinates : boost::make_shared<MatrixDouble>(),
1442 data_vec, MBMAXTYPE),
1443 tensorPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
1444 if (!tensorPtr)
1445 THROW_MESSAGE("Pointer is not set");
1446 }
1447
1449 SmartPetscObj<DM> data_dm,
1451 const std::string field_name, MatrixPtr data_ptr,
1452 SmartPetscObj<Vec> data_vec, const EntityType zero_type = MBEDGE,
1453 const int zero_side = 0, MatrixPtr coordinates = nullptr)
1454 : Base(data_dm, op_type, field_name,
1455 coordinates ? coordinates : boost::make_shared<MatrixDouble>(),
1456 data_vec, MBMAXTYPE),
1457 tensorPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
1458 if (!tensorPtr)
1459 THROW_MESSAGE("Pointer is not set");
1460 }
1461
1462 MoFEMErrorCode doWork(int side, EntityType type,
1463 EntitiesFieldData::EntData &data) override {
1466 const int nb_gauss_pts = this->getGaussPts().size2();
1467 // Reset at the same entity/side as the symmetric field evaluator. The
1468 // vector evaluator uses MBMAXTYPE so later sides accumulate normally.
1469 MatrixSizeHelper<GetFTensor1FromMatType<CoordinateSize, -1, DL>, DL>::size(
1470 *this->dataPtr, nb_gauss_pts);
1471 if (type == zeroType && side == zeroSide)
1472 this->dataPtr->clear();
1473 CHKERR Base::doWork(side, type, data);
1474
1475 auto get_coordinates =
1476 MatrixSizeHelper<GetFTensor1FromMatType<CoordinateSize, -1, DL>, DL>::get(
1477 *this->dataPtr, nb_gauss_pts);
1478 auto get_tensor =
1480 *tensorPtr, nb_gauss_pts);
1481 auto t_coordinates = get_coordinates();
1482 auto t_tensor = get_tensor();
1483 FTENSOR_INDEXES(3, i, j);
1484 for (int gg = 0; gg != nb_gauss_pts; ++gg) {
1485 const auto t_deviator = Tensor2SymmetricDeviatorBasis::getTensor(t_coordinates);
1486 t_tensor(i, j) = t_deviator(i, j);
1487 ++t_coordinates;
1488 ++t_tensor;
1489 }
1491 }
1492
1493protected:
1495 const EntityHandle zeroType;
1496 const int zeroSide;
1497};
1498
1499/** Evaluate a symmetric deviator field in the fixed orthonormal material basis.
1500 * @tparam SpaceDim Spatial dimension, 2 or 3. Both cases output a 3x3 tensor.
1501 * @ingroup mofem_forces_and_sources_user_data_operators
1502 */
1504
1505/** Planar deviator: three coefficients with D13=D23=0 and D33=-D11-D22. */
1506template <>
1510 3>::OpCalculateTensor2SymmetricDeviatorFieldValues_General;
1511};
1512
1513/** Three-dimensional deviator: all five orthonormal coefficients. */
1514template <>
1518 5>::OpCalculateTensor2SymmetricDeviatorFieldValues_General;
1519};
1520
1521/**
1522 * @brief Calculate symmetric tensor field rates ant integratio pts.
1523 *
1524 * @tparam Tensor_Dim
1525 *
1526 * \ingroup mofem_forces_and_sources_user_data_operators
1527 */
1528template <int Tensor_Dim>
1531
1533 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
1534 const EntityType zero_type = MBEDGE, const int zero_side = 0)
1537 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
1538 if (!dataPtr)
1539 THROW_MESSAGE("Pointer is not set");
1540 }
1541
1542 MoFEMErrorCode doWork(int side, EntityType type,
1545 const int nb_gauss_pts = getGaussPts().size2();
1546 MatrixDouble &mat = *dataPtr;
1547 constexpr auto symm_size = (Tensor_Dim * (Tensor_Dim + 1)) / 2;
1549 auto get_values_at_gauss_pts =
1551 DL>::size(mat, nb_gauss_pts);
1552 if (type == zeroType && side == zeroSide) {
1553 mat.clear();
1554 }
1555 auto &local_indices = data.getLocalIndices();
1556 const int nb_dofs = local_indices.size();
1557 if (!nb_dofs)
1559
1560 #ifndef NDEBUG
1561 if ((getFEMethod()->data_ctx & PetscData::CtxSetX_T).none()) {
1562 MOFEM_LOG_CHANNEL("SELF");
1563 MOFEM_LOG("SELF", Sev::error)
1564 << "In this case field degrees of freedom are read from vector. "
1565 "That usually happens when time solver is used, and acces to "
1566 "first rates is needed. You probably not set "
1567 "ts_u_t and associated data structure data_ctx to CTX_SET_X_T "
1568 "respectively";
1569 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Vector not set!");
1570 }
1571 #endif
1572
1573 dotVector.resize(nb_dofs, false);
1574 const double *array;
1575 CHKERR VecGetArrayRead(getFEMethod()->ts_u_t, &array);
1576 for (int i = 0; i != local_indices.size(); ++i)
1577 if (local_indices[i] != -1)
1578 dotVector[i] = array[local_indices[i]];
1579 else
1580 dotVector[i] = 0;
1581 CHKERR VecRestoreArrayRead(getFEMethod()->ts_u_t, &array);
1582
1583 const int nb_base_functions = data.getN().size2();
1584
1585 auto base_function = data.getFTensor0N();
1586 auto t_values_at_gauss_pts = get_values_at_gauss_pts();
1587 FTensor::Index<'i', Tensor_Dim> i;
1588 FTensor::Index<'j', Tensor_Dim> j;
1589 const int size = nb_dofs / symm_size;
1590 for (int gg = 0; gg != nb_gauss_pts; ++gg) {
1591 auto field_data = getFTensorDotData<Tensor_Dim>();
1592 int bb = 0;
1593 for (; bb != size; ++bb) {
1594 t_values_at_gauss_pts(i, j) += field_data(i, j) * base_function;
1595 ++field_data;
1596 ++base_function;
1597 }
1598 for (; bb < nb_base_functions; ++bb)
1599 ++base_function;
1600 ++t_values_at_gauss_pts;
1601 }
1602
1604 }
1605
1606protected:
1607 boost::shared_ptr<MatrixDouble> dataPtr;
1608 const EntityHandle zeroType;
1609 const int zeroSide;
1611
1612 template <int Dim> inline auto getFTensorDotData() {
1613 static_assert(Dim || !Dim, "not implemented");
1614 }
1615};
1616
1617template <>
1618template <>
1619inline auto
1622 &dotVector[0], &dotVector[1], &dotVector[2], &dotVector[3], &dotVector[4],
1623 &dotVector[5]);
1624}
1625
1626template <>
1627template <>
1628inline auto
1631 &dotVector[0], &dotVector[1], &dotVector[2]);
1632}
1633
1634/**@}*/
1635
1636/** \name Gradients and Hessian of scalar fields at integration points */
1637
1638/**@{*/
1639
1640/**
1641 * \brief Evaluate field gradient values for scalar field, i.e. gradient is
1642 * tensor rank 1 (vector)
1643 *
1644 */
1645template <int Tensor_Dim, typename M = MatrixDouble>
1647 : public OpCalculateVectorFieldValues_General<Tensor_Dim, M> {
1648
1650 Tensor_Dim, M>::OpCalculateVectorFieldValues_General;
1651};
1652
1653/** \brief Evaluate field gradient values for scalar field, i.e. gradient is
1654 * tensor rank 1 (vector), specialization
1655 *
1656 */
1657template <int Tensor_Dim>
1659 : public OpCalculateVectorFieldValues_General<Tensor_Dim, MatrixDouble> {
1660
1662 Tensor_Dim, MatrixDouble>::OpCalculateVectorFieldValues_General;
1663
1664 /**
1665 * \brief calculate gradient values of scalar field at integration points
1666 * @param side side entity number
1667 * @param type side entity type
1668 * @param data entity data
1669 * @return error code
1670 */
1671 MoFEMErrorCode doWork(int side, EntityType type,
1673};
1674
1675/**
1676 * \brief Member function specialization calculating scalar field gradients for
1677 * tenor field rank 1
1678 *
1679 */
1680template <int Tensor_Dim>
1682 Tensor_Dim, MatrixDouble>::doWork(int side, EntityType type,
1685
1686 const size_t nb_gauss_pts = this->getGaussPts().size2();
1687 auto &mat = *this->dataPtr;
1689 auto get_gradients_at_pts =
1690 MatrixSizeHelper<GetFTensor1FromMatType<Tensor_Dim, -1, DL>,
1691 DL>::size(mat, nb_gauss_pts);
1692 if (type == this->zeroType) {
1693 mat.clear();
1694 }
1695
1696 const int nb_dofs = data.getFieldData().size();
1697 if (nb_dofs) {
1698
1699 if (nb_gauss_pts) {
1700 const int nb_base_functions = data.getN().size2();
1701 auto diff_base_function = data.getFTensor1DiffN<Tensor_Dim>();
1702 auto t_gradients_at_pts = get_gradients_at_pts();
1703
1704 #ifndef NDEBUG
1705 if (nb_dofs > nb_base_functions)
1706 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1707 "Number of base functions inconsistent with number of DOFs "
1708 "(%d > %d)",
1709 nb_dofs, nb_base_functions);
1710
1711 if (data.getDiffN().size2() != nb_base_functions * Tensor_Dim)
1712 SETERRQ(
1713 PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1714 "Number of base functions inconsistent with number of derivatives "
1715 "(%zu != %d)",
1716 data.getDiffN().size2(), nb_base_functions);
1717
1718 if (data.getDiffN().size1() != nb_gauss_pts)
1719 SETERRQ(
1720 PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1721 "Number of base functions inconsistent with number of integration "
1722 "pts (%zu != %zu)",
1723 data.getDiffN().size1(), nb_gauss_pts);
1724
1725 #endif
1726
1727 FTensor::Index<'I', Tensor_Dim> I;
1728 for (int gg = 0; gg < nb_gauss_pts; ++gg) {
1729 auto field_data = data.getFTensor0FieldData();
1730 int bb = 0;
1731 for (; bb != nb_dofs; ++bb) {
1732 t_gradients_at_pts(I) += field_data * diff_base_function(I);
1733 ++field_data;
1734 ++diff_base_function;
1735 }
1736 // Number of dofs can be smaller than number of base functions
1737 for (; bb < nb_base_functions; ++bb)
1738 ++diff_base_function;
1739 ++t_gradients_at_pts;
1740 }
1741 }
1742 }
1743
1745}
1746
1747/** \brief Get field gradients at integration pts for scalar field rank 0, i.e.
1748 * vector field
1749 *
1750 * \ingroup mofem_forces_and_sources_user_data_operators
1751 */
1752template <int Tensor_Dim>
1754 : public OpCalculateScalarFieldGradient_General<Tensor_Dim> {
1756 Tensor_Dim>::OpCalculateScalarFieldGradient_General;
1757};
1758
1759/** \brief Evaluate field gradient values for scalar field, i.e. gradient is
1760 * tensor rank 1 (vector), specialization
1761 *
1762 */
1763template <int Tensor_Dim>
1765 : public OpCalculateVectorFieldValues_General<Tensor_Dim> {
1766
1768 Tensor_Dim>::OpCalculateVectorFieldValues_General;
1769
1770 /**
1771 * \brief calculate gradient values of scalar field at integration points
1772 * @param side side entity number
1773 * @param type side entity type
1774 * @param data entity data
1775 * @return error code
1776 */
1777 MoFEMErrorCode doWork(int side, EntityType type,
1779};
1780
1781template <int Tensor_Dim>
1783 int side, EntityType type, EntitiesFieldData::EntData &data) {
1785
1786 const size_t nb_gauss_pts = this->getGaussPts().size2();
1788 auto &mat = *this->dataPtr;
1789 auto get_hessian_at_gauss_pts =
1790 MatrixSizeHelper<GetFTensor2FromMatType<Tensor_Dim, Tensor_Dim, -1, DL>,
1791 DL>::size(mat, nb_gauss_pts);
1792 if (type == this->zeroType)
1793 mat.clear();
1794
1795 const int nb_dofs = data.getFieldData().size();
1796 if (nb_dofs) {
1797
1798 if (nb_gauss_pts) {
1799 const int nb_base_functions = data.getN().size2();
1800
1801 auto &hessian_base = data.getN(BaseDerivatives::SecondDerivative);
1802 #ifndef NDEBUG
1803 if (hessian_base.size1() != nb_gauss_pts) {
1804 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1805 "Wrong number of integration pts (%ld != %ld)",
1806 static_cast<long>(hessian_base.size1()),
1807 static_cast<long>(nb_gauss_pts));
1808 }
1809 if (hessian_base.size2() != nb_base_functions * Tensor_Dim * Tensor_Dim) {
1810 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1811 "Wrong number of base functions (%ld != %ld)",
1812 static_cast<long>(hessian_base.size2() /
1813 (Tensor_Dim * Tensor_Dim)),
1814 static_cast<long>(nb_base_functions));
1815 }
1816 if (hessian_base.size2() < nb_dofs * Tensor_Dim * Tensor_Dim) {
1817 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1818 "Wrong number of base functions (%ld < %ld)",
1819 static_cast<long>(hessian_base.size2()),
1820 static_cast<long>(nb_dofs * Tensor_Dim * Tensor_Dim));
1821 }
1822 #endif
1823
1824 auto t_diff2_base_function = getFTensor2FromPtr<Tensor_Dim, Tensor_Dim>(
1825 &*hessian_base.data().begin());
1826
1827 auto t_hessian_at_gauss_pts = get_hessian_at_gauss_pts();
1828
1829 FTensor::Index<'I', Tensor_Dim> I;
1830 FTensor::Index<'J', Tensor_Dim> J;
1831 for (int gg = 0; gg != nb_gauss_pts; ++gg) {
1832 auto field_data = data.getFTensor0FieldData();
1833 int bb = 0;
1834 for (; bb != nb_dofs; ++bb) {
1835 t_hessian_at_gauss_pts(I, J) +=
1836 field_data * t_diff2_base_function(I, J);
1837 ++field_data;
1838 ++t_diff2_base_function;
1839 }
1840 // Number of dofs can be smaller than number of base functions
1841 for (; bb < nb_base_functions; ++bb) {
1842 ++t_diff2_base_function;
1843 }
1844
1845 ++t_hessian_at_gauss_pts;
1846 }
1847 }
1848 }
1849
1851}
1852
1853/**}*/
1854
1855/** \name Gradients and hessian of tensor fields at integration points */
1856
1857/**@{*/
1858
1859/**
1860 * \brief Evaluate field gradient values for vector field, i.e. gradient is
1861 * tensor rank 2
1862 *
1863 * \tparam Tensor_Dim0 Dimension of the vector field
1864 * \tparam Tensor_Dim1 Dimension of the gradient (usually spatial dimension)
1865 * \tparam S Storage order for the field data
1866 * \tparam M Matrix storage type
1867 *
1868 */
1869template <int Tensor_Dim0, int Tensor_Dim1, int S,
1870 typename M = MatrixDouble>
1872 : public OpCalculateTensor2FieldValues_General<Tensor_Dim0, Tensor_Dim1,
1873 M> {
1874
1876 Tensor_Dim0, Tensor_Dim1, M>::OpCalculateTensor2FieldValues_General;
1877};
1878
1879template <int Tensor_Dim0, int Tensor_Dim1, int S>
1880struct OpCalculateVectorFieldGradient_General<Tensor_Dim0, Tensor_Dim1, S,
1883 Tensor_Dim0, Tensor_Dim1, MatrixDouble> {
1884
1886 Tensor_Dim0, Tensor_Dim1, MatrixDouble>::OpCalculateTensor2FieldValues_General;
1887
1888 /**
1889 * \brief calculate values of vector field at integration points
1890 * @param side side entity number
1891 * @param type side entity type
1892 * @param data entity data
1893 * @return error code
1894 */
1895 MoFEMErrorCode doWork(int side, EntityType type,
1897};
1898
1899/**
1900 * \brief Member function specialization calculating vector field gradients for
1901 * tenor field rank 2
1902 *
1903 */
1904template <int Tensor_Dim0, int Tensor_Dim1, int S>
1906 Tensor_Dim0, Tensor_Dim1, S, MatrixDouble>::doWork(
1907 int side, EntityType type, EntitiesFieldData::EntData &data) {
1909 if (!this->dataPtr)
1910 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1911 "Data pointer not allocated");
1912
1913 const size_t nb_gauss_pts = this->getGaussPts().size2();
1915 auto &mat = *this->dataPtr;
1916 auto get_gradients_at_pts =
1918 GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
1919 DL>::size(mat, nb_gauss_pts);
1920 if (type == this->zeroType)
1921 mat.clear();
1922
1923 if (nb_gauss_pts) {
1924 const size_t nb_dofs = data.getFieldData().size();
1925
1926 if (nb_dofs) {
1927
1928 if (this->dataVec.use_count()) {
1929 this->dotVector.resize(nb_dofs, false);
1930 const double *array;
1931 CHKERR VecGetArrayRead(this->dataVec, &array);
1932 const auto &local_indices = data.getLocalIndices();
1933 for (int i = 0; i != local_indices.size(); ++i)
1934 if (local_indices[i] != -1)
1935 this->dotVector[i] = array[local_indices[i]];
1936 else
1937 this->dotVector[i] = 0;
1938 CHKERR VecRestoreArrayRead(this->dataVec, &array);
1939 data.getFieldData().swap(this->dotVector);
1940 }
1941
1942 const int nb_base_functions = data.getN().size2();
1943 auto diff_base_function = data.getFTensor1DiffN<Tensor_Dim1>();
1944 auto t_gradients_at_pts = get_gradients_at_pts();
1945 FTensor::Index<'I', Tensor_Dim0> I;
1946 FTensor::Index<'J', Tensor_Dim1> J;
1947 int size = nb_dofs / Tensor_Dim0;
1948 if (nb_dofs % Tensor_Dim0) {
1949 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1950 "Data inconsistency");
1951 }
1952 for (int gg = 0; gg < nb_gauss_pts; ++gg) {
1953 auto field_data = getFTensor1FromPtr<Tensor_Dim0, S>(
1954 data.getFieldData().data().data());
1955
1956 #ifndef NDEBUG
1957 if (field_data.l2() != field_data.l2()) {
1958 MOFEM_LOG("SELF", Sev::error) << "field data " << field_data;
1959 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1960 "Wrong number in coefficients");
1961 }
1962 #endif
1963
1964 int bb = 0;
1965 for (; bb < size; ++bb) {
1966 #ifndef SINGULARITY
1967 #ifndef NDEBUG
1968 if (diff_base_function.l2() != diff_base_function.l2()) {
1969 MOFEM_LOG("SELF", Sev::error)
1970 << "diff_base_function: " << diff_base_function;
1971 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1972 "Wrong number number in base functions");
1973 }
1974 #endif
1975 #endif
1976
1977 t_gradients_at_pts(I, J) += field_data(I) * diff_base_function(J);
1978 ++field_data;
1979 ++diff_base_function;
1980 }
1981 // Number of dofs can be smaller than number of Tensor_Dim0 x base
1982 // functions
1983 for (; bb != nb_base_functions; ++bb)
1984 ++diff_base_function;
1985 ++t_gradients_at_pts;
1986 }
1987
1988 if (this->dataVec.use_count()) {
1989 data.getFieldData().swap(this->dotVector);
1990 }
1991 }
1992 }
1994}
1995
1996/** \brief Get field gradients at integration pts for scalar field rank 0, i.e.
1997 * vector field
1998 *
1999 * \tparam Tensor_Dim0 Dimension of the vector field
2000 * \tparam Tensor_Dim1 Dimension of the gradient (usually spatial dimension)
2001 * \tparam S Stride in the storage of the vector field, default is Tensor_Dim0
2002 *
2003 * \ingroup mofem_forces_and_sources_user_data_operators
2004 */
2005template <int Tensor_Dim0, int Tensor_Dim1, int S = Tensor_Dim0>
2007 : public OpCalculateVectorFieldGradient_General<Tensor_Dim0, Tensor_Dim1,
2008 S> {
2009
2011 Tensor_Dim0, Tensor_Dim1, S>::OpCalculateVectorFieldGradient_General;
2012};
2013
2014/** \brief Get field gradients time derivative at integration pts for scalar
2015 * field rank 0, i.e. vector field
2016 *
2017 * \ingroup mofem_forces_and_sources_user_data_operators
2018 */
2019template <int Tensor_Dim0, int Tensor_Dim1>
2022
2024 boost::shared_ptr<MatrixDouble> data_ptr,
2025 const EntityType zero_at_type = MBVERTEX)
2028 dataPtr(data_ptr), zeroAtType(zero_at_type) {
2029 if (!dataPtr)
2030 THROW_MESSAGE("Pointer is not set");
2031 }
2032
2033 MoFEMErrorCode doWork(int side, EntityType type,
2036
2037 const auto &local_indices = data.getLocalIndices();
2038 const int nb_dofs = local_indices.size();
2039 const int nb_gauss_pts = this->getGaussPts().size2();
2040
2042 auto &mat = *this->dataPtr;
2043 auto get_gradients_at_pts =
2045 GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
2046 DL>::size(mat, nb_gauss_pts);
2047 if (type == this->zeroAtType)
2048 mat.clear();
2049 if (!nb_dofs)
2051
2052 dotVector.resize(nb_dofs, false);
2053 const double *array;
2054 CHKERR VecGetArrayRead(getFEMethod()->ts_u_t, &array);
2055 for (int i = 0; i != local_indices.size(); ++i)
2056 if (local_indices[i] != -1)
2057 dotVector[i] = array[local_indices[i]];
2058 else
2059 dotVector[i] = 0;
2060 CHKERR VecRestoreArrayRead(getFEMethod()->ts_u_t, &array);
2061
2062 const int nb_base_functions = data.getN().size2();
2063 auto diff_base_function = data.getFTensor1DiffN<Tensor_Dim1>();
2064 auto t_gradients_at_pts = get_gradients_at_pts();
2065 FTensor::Index<'I', Tensor_Dim0> I;
2066 FTensor::Index<'J', Tensor_Dim1> J;
2067 int size = nb_dofs / Tensor_Dim0;
2068 if (nb_dofs % Tensor_Dim0) {
2069 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Data inconsistency");
2070 }
2071
2072 for (int gg = 0; gg < nb_gauss_pts; ++gg) {
2073 auto field_data = getFTensor1FromPtr<Tensor_Dim0>(&*dotVector.begin());
2074 int bb = 0;
2075 for (; bb < size; ++bb) {
2076 t_gradients_at_pts(I, J) += field_data(I) * diff_base_function(J);
2077 ++field_data;
2078 ++diff_base_function;
2079 }
2080 // Number of dofs can be smaller than number of Tensor_Dim0 x base
2081 // functions
2082 for (; bb != nb_base_functions; ++bb)
2083 ++diff_base_function;
2084 ++t_gradients_at_pts;
2085 }
2087 }
2088
2089private:
2090 boost::shared_ptr<MatrixDouble> dataPtr; ///< Data computed into this matrix
2091 EntityType zeroAtType; ///< Zero values at Gauss point at this type
2092 VectorDouble dotVector; ///< Keeps temporary values of time derivatives
2093};
2094
2095/**
2096 * \brief Evaluate field gradient values for symmetric 2nd order tensor field,
2097 * i.e. gradient is tensor rank 3
2098 *
2099 */
2100template <int Tensor_Dim0, int Tensor_Dim1, typename M = MatrixDouble>
2102 : public OpCalculateTensor2FieldValues_General<Tensor_Dim0, Tensor_Dim1,
2103 M> {
2104
2106 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
2107 const EntityType zero_type = MBVERTEX)
2108 : OpCalculateTensor2FieldValues_General<Tensor_Dim0, Tensor_Dim1, M>(
2109 field_name, data_ptr, zero_type) {}
2110};
2111
2112template <int Tensor_Dim0, int Tensor_Dim1>
2114 Tensor_Dim1,
2117 Tensor_Dim0, Tensor_Dim1, MatrixDouble> {
2118
2120 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
2121 const EntityType zero_type = MBVERTEX)
2122 : OpCalculateTensor2FieldValues_General<Tensor_Dim0, Tensor_Dim1,
2123 MatrixDouble>(
2124 field_name, data_ptr, zero_type) {}
2125
2126 /**
2127 * \brief calculate values of vector field at integration points
2128 * @param side side entity number
2129 * @param type side entity type
2130 * @param data entity data
2131 * @return error code
2132 */
2133 MoFEMErrorCode doWork(int side, EntityType type,
2135};
2136
2137/**
2138 * \brief Member function specialization calculating tensor field gradients for
2139 * symmetric tensor field rank 2
2140 *
2141 */
2142template <int Tensor_Dim0, int Tensor_Dim1>
2143MoFEMErrorCode OpCalculateTensor2SymmetricFieldGradient_General<
2144 Tensor_Dim0, Tensor_Dim1, MatrixDouble>::doWork(
2145 int side, EntityType type, EntitiesFieldData::EntData &data) {
2147 if (!this->dataPtr)
2148 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2149 "Data pointer not allocated");
2150
2151 const size_t nb_gauss_pts = this->getGaussPts().size2();
2152 constexpr size_t msize = (Tensor_Dim0 * (Tensor_Dim0 + 1)) / 2;
2153 auto &mat = *this->dataPtr;
2154 if (type == this->zeroType) {
2155 mat.resize(msize * Tensor_Dim1, nb_gauss_pts, false);
2156 mat.clear();
2157 }
2158
2159 if (nb_gauss_pts) {
2160 const size_t nb_dofs = data.getFieldData().size();
2161
2162 if (nb_dofs) {
2163
2164 const int nb_base_functions = data.getN().size2();
2165 auto diff_base_function = data.getFTensor1DiffN<Tensor_Dim1>();
2166 auto gradients_at_pts =
2167 getFTensor3DgFromMat<Tensor_Dim0, Tensor_Dim1, -1,
2169 FTensor::Index<'I', Tensor_Dim0> I;
2170 FTensor::Index<'J', Tensor_Dim0> J;
2171 FTensor::Index<'K', Tensor_Dim1> K;
2172 int size = nb_dofs / msize;
2173 if (nb_dofs % msize) {
2174 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2175 "Data inconsistency");
2176 }
2177 for (int gg = 0; gg < nb_gauss_pts; ++gg) {
2178 auto field_data = data.getFTensor2SymmetricFieldData<Tensor_Dim0>();
2179 int bb = 0;
2180 for (; bb < size; ++bb) {
2181 gradients_at_pts(I, J, K) +=
2182 field_data(I, J) * diff_base_function(K);
2183 ++field_data;
2184 ++diff_base_function;
2185 }
2186 // Number of dofs can be smaller than number of Tensor_Dim0 x base
2187 // functions
2188 for (; bb != nb_base_functions; ++bb)
2189 ++diff_base_function;
2190 ++gradients_at_pts;
2191 }
2192 }
2193 }
2195}
2196
2197/** \brief Get field gradients at integration pts for symmetric tensorial field
2198 * rank 2
2199 *
2200 * \ingroup mofem_forces_and_sources_user_data_operators
2201 */
2202template <int Tensor_Dim0, int Tensor_Dim1>
2205 Tensor_Dim0, Tensor_Dim1> {
2206
2208 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
2209 const EntityType zero_type = MBVERTEX)
2211 Tensor_Dim0, Tensor_Dim1>(field_name, data_ptr, zero_type) {}
2212};
2213
2214template <int Tensor_Dim0, int Tensor_Dim1>
2216 : public OpCalculateTensor2FieldValues_General<Tensor_Dim0,
2217 Tensor_Dim1> {
2218
2220 Tensor_Dim0, Tensor_Dim1>::OpCalculateTensor2FieldValues_General;
2221
2222 /**
2223 * \brief calculate values of vector field at integration points
2224 * @param side side entity number
2225 * @param type side entity type
2226 * @param data entity data
2227 * @return error code
2228 */
2229 MoFEMErrorCode doWork(int side, EntityType type,
2231};
2232
2233/**
2234 * \brief Member function specialization calculating vector field gradients for
2235 * tenor field rank 2
2236 *
2237 */
2238template <int Tensor_Dim0, int Tensor_Dim1>
2240 int side, EntityType type, EntitiesFieldData::EntData &data) {
2242 if (!this->dataPtr)
2243 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2244 "Data pointer not allocated");
2245
2246 const size_t nb_gauss_pts = this->getGaussPts().size2();
2247 auto &mat = *this->dataPtr;
2249 auto get_hessian_at_gauss_pts = MatrixSizeHelper<
2250 GetFTensor3FromMatType<Tensor_Dim0, Tensor_Dim1, Tensor_Dim1, -1, DL>,
2251 DL>::size(mat, nb_gauss_pts);
2252 if (type == this->zeroType) {
2253 mat.clear();
2254 }
2255
2256 if (nb_gauss_pts) {
2257 const size_t nb_dofs = data.getFieldData().size();
2258
2259 if (nb_dofs) {
2260
2261 if (this->dataVec.use_count()) {
2262 this->dotVector.resize(nb_dofs, false);
2263 const double *array;
2264 CHKERR VecGetArrayRead(this->dataVec, &array);
2265 const auto &local_indices = data.getLocalIndices();
2266 for (int i = 0; i != local_indices.size(); ++i)
2267 if (local_indices[i] != -1)
2268 this->dotVector[i] = array[local_indices[i]];
2269 else
2270 this->dotVector[i] = 0;
2271 CHKERR VecRestoreArrayRead(this->dataVec, &array);
2272 data.getFieldData().swap(this->dotVector);
2273 }
2274
2275 const int nb_base_functions = data.getN().size2();
2276
2277 auto &hessian_base = data.getN(BaseDerivatives::SecondDerivative);
2278 #ifndef NDEBUG
2279 if (hessian_base.size1() != nb_gauss_pts) {
2280 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2281 "Wrong number of integration pts (%ld != %ld)",
2282 static_cast<long>(hessian_base.size1()),
2283 static_cast<long>(nb_gauss_pts));
2284 }
2285 if (hessian_base.size2() !=
2286 nb_base_functions * Tensor_Dim1 * Tensor_Dim1) {
2287 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2288 "Wrong number of base functions (%ld != %ld)",
2289 static_cast<long>(hessian_base.size2() /
2290 (Tensor_Dim1 * Tensor_Dim1)),
2291 static_cast<long>(nb_base_functions));
2292 }
2293 if (hessian_base.size2() <
2294 (nb_dofs / Tensor_Dim0) * Tensor_Dim1 * Tensor_Dim1) {
2295 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2296 "Wrong number of base functions (%ld < %ld)",
2297 static_cast<long>(hessian_base.size2()),
2298 static_cast<long>((nb_dofs / Tensor_Dim0) * Tensor_Dim1 *
2299 Tensor_Dim1));
2300 }
2301 #endif
2302
2303 auto t_diff2_base_function = getFTensor2FromPtr<Tensor_Dim1, Tensor_Dim1>(
2304 &*hessian_base.data().begin());
2305
2306 auto t_hessian_at_gauss_pts = get_hessian_at_gauss_pts();
2307
2308 FTensor::Index<'I', Tensor_Dim0> I;
2309 FTensor::Index<'J', Tensor_Dim1> J;
2310 FTensor::Index<'K', Tensor_Dim1> K;
2311
2312 int size = nb_dofs / Tensor_Dim0;
2313 #ifndef NDEBUG
2314 if (nb_dofs % Tensor_Dim0) {
2315 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2316 "Data inconsistency");
2317 }
2318 #endif
2319
2320 for (int gg = 0; gg < nb_gauss_pts; ++gg) {
2321 auto field_data = data.getFTensor1FieldData<Tensor_Dim0>();
2322 int bb = 0;
2323 for (; bb < size; ++bb) {
2324 t_hessian_at_gauss_pts(I, J, K) +=
2325 field_data(I) * t_diff2_base_function(J, K);
2326 ++field_data;
2327 ++t_diff2_base_function;
2328 }
2329 // Number of dofs can be smaller than number of Tensor_Dim0 x base
2330 // functions
2331 for (; bb != nb_base_functions; ++bb)
2332 ++t_diff2_base_function;
2333 ++t_hessian_at_gauss_pts;
2334 }
2335
2336 if (this->dataVec.use_count()) {
2337 data.getFieldData().swap(this->dotVector);
2338 }
2339 }
2340 }
2342}
2343
2344/**@}*/
2345
2346/** \name Transform tensors and vectors */
2347
2348/**@{*/
2349
2350/**
2351 * @brief Calculate \f$ \pmb\sigma_{ij} = \mathbf{D}_{ijkl} \pmb\varepsilon_{kl}
2352 * \f$
2353 *
2354 * @tparam DIM
2355 *
2356 * \ingroup mofem_forces_and_sources_user_data_operators
2357 */
2358template <int DIM_01, int DIM_23, int S = 0>
2361
2364
2365 /**
2366 * @deprecated Do not use this constructor
2367 */
2370 boost::shared_ptr<MatrixDouble> in_mat,
2371 boost::shared_ptr<MatrixDouble> out_mat,
2372 boost::shared_ptr<MatrixDouble> d_mat)
2373 : UserOp(field_name, OPCOL), inMat(in_mat), outMat(out_mat), dMat(d_mat) {
2374 // Only is run for vertices
2375 std::fill(&doEntities[MBEDGE], &doEntities[MBMAXTYPE], false);
2376 if (!inMat)
2377 THROW_MESSAGE("Pointer for in mat is null");
2378 if (!outMat)
2379 THROW_MESSAGE("Pointer for out mat is null");
2380 if (!dMat)
2381 THROW_MESSAGE("Pointer for tensor mat is null");
2382 }
2383
2384 OpTensorTimesSymmetricTensor(boost::shared_ptr<MatrixDouble> in_mat,
2385 boost::shared_ptr<MatrixDouble> out_mat,
2386 boost::shared_ptr<MatrixDouble> d_mat)
2387 : UserOp(NOSPACE, OPSPACE), inMat(in_mat), outMat(out_mat), dMat(d_mat) {
2388 // Only is run for vertices
2389 if (!inMat)
2390 THROW_MESSAGE("Pointer for in mat is null");
2391 if (!outMat)
2392 THROW_MESSAGE("Pointer for out mat is null");
2393 if (!dMat)
2394 THROW_MESSAGE("Pointer for tensor mat is null");
2395 }
2396
2397 MoFEMErrorCode doWork(int, EntityType, EntData &) {
2399 const size_t nb_gauss_pts = getGaussPts().size2();
2401 auto get_D_at_pts =
2403 DL>::get(*dMat, nb_gauss_pts);
2404 auto get_in_at_pts =
2406 DL>::get(*inMat, nb_gauss_pts);
2407 auto get_out_at_pts =
2409 DL>::size(*outMat, nb_gauss_pts);
2410 auto t_D_at_pts = get_D_at_pts();
2411 auto t_in_at_pts = get_in_at_pts();
2412 auto t_out_at_pts = get_out_at_pts();
2413 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
2414 t_out_at_pts(i, j) = t_D_at_pts(i, j, k, l) * t_in_at_pts(k, l);
2415 ++t_in_at_pts;
2416 ++t_out_at_pts;
2417 ++t_D_at_pts;
2418 }
2420 }
2421
2422private:
2423 FTensor::Index<'i', DIM_01> i;
2424 FTensor::Index<'j', DIM_01> j;
2425 FTensor::Index<'k', DIM_23> k;
2426 FTensor::Index<'l', DIM_23> l;
2427
2428 boost::shared_ptr<MatrixDouble> inMat;
2429 boost::shared_ptr<MatrixDouble> outMat;
2430 boost::shared_ptr<MatrixDouble> dMat;
2431};
2432
2433/**
2434 * @brief Operator for symmetrizing tensor fields
2435 *
2436 * This template structure symmetrizes tensor fields by computing the symmetric
2437 * part of an input tensor and storing the result in an output matrix. It's
2438 * commonly used in mechanics where symmetric tensors (like stress and strain)
2439 * are required.
2440 *
2441 * @tparam DIM Dimension of the tensor field
2442 */
2443template <int DIM>
2445
2448
2449 /**
2450 * @deprecated Do not use this constructor
2451 */
2453 boost::shared_ptr<MatrixDouble> in_mat,
2454 boost::shared_ptr<MatrixDouble> out_mat)
2455 : UserOp(field_name, OPCOL), inMat(in_mat), outMat(out_mat) {
2456 // Only is run for vertices
2457 std::fill(&doEntities[MBEDGE], &doEntities[MBMAXTYPE], false);
2458 if (!inMat)
2459 THROW_MESSAGE("Pointer not set for in matrix");
2460 if (!outMat)
2461 THROW_MESSAGE("Pointer not set for in matrix");
2462 }
2463
2464 /**
2465 * @brief Constructor for tensor symmetrization operator
2466 *
2467 * @param in_mat Shared pointer to input matrix containing asymmetric tensor
2468 * @param out_mat Shared pointer to output matrix for storing symmetric tensor
2469 */
2470 OpSymmetrizeTensor(boost::shared_ptr<MatrixDouble> in_mat,
2471 boost::shared_ptr<MatrixDouble> out_mat)
2472 : UserOp(NOSPACE, OPSPACE), inMat(in_mat), outMat(out_mat) {
2473 // Only is run for vertices
2474 if (!inMat)
2475 THROW_MESSAGE("Pointer not set for in matrix");
2476 if (!outMat)
2477 THROW_MESSAGE("Pointer not set for in matrix");
2478 }
2479
2480 MoFEMErrorCode doWork(int, EntityType, EntData &) {
2482 const size_t nb_gauss_pts = getGaussPts().size2();
2484 auto get_in_at_pts =
2485 MatrixSizeHelper<GetFTensor2FromMatType<DIM, DIM, -1, DL>, DL>::get(
2486 *inMat, nb_gauss_pts);
2487 auto t_in_at_pts = get_in_at_pts();
2488 auto get_out_at_pts =
2490 DL>::size(*outMat, nb_gauss_pts);
2491 auto t_out_at_pts = get_out_at_pts();
2492 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
2493 t_out_at_pts(i, j) = (t_in_at_pts(i, j) || t_in_at_pts(j, i)) / 2;
2494 ++t_in_at_pts;
2495 ++t_out_at_pts;
2496 }
2498 }
2499
2500private:
2503 boost::shared_ptr<MatrixDouble> inMat;
2504 boost::shared_ptr<MatrixDouble> outMat;
2505};
2506
2507/**
2508 * @brief Operator for scaling matrix values by a scalar factor
2509 *
2510 * This structure performs element-wise scaling of matrix data by multiplying
2511 * all elements by a scalar value. It's useful for applying material properties,
2512 * coordinate transformations, or other scaling operations in finite element
2513 * computations.
2514 */
2516
2519
2520 /**
2521 * @deprecated Do not use this constructor
2522 */
2523 DEPRECATED OpScaleMatrix(const std::string field_name, const double scale,
2524 boost::shared_ptr<MatrixDouble> in_mat,
2525 boost::shared_ptr<MatrixDouble> out_mat)
2526 : UserOp(field_name, OPCOL), inMat(in_mat), outMat(out_mat) {
2527 scalePtr = boost::make_shared<double>(scale);
2528 // Only is run for vertices
2529 std::fill(&doEntities[MBEDGE], &doEntities[MBMAXTYPE], false);
2530 if (!inMat)
2531 THROW_MESSAGE("Pointer not set for in matrix");
2532 if (!outMat)
2533 THROW_MESSAGE("Pointer not set for in matrix");
2534 }
2535
2536 /**
2537 * @brief Constructor for matrix scaling operator
2538 *
2539 * @param scale_ptr Shared pointer to scalar value for scaling matrix elements
2540 * @param in_mat Shared pointer to input matrix to be scaled
2541 * @param out_mat Shared pointer to output matrix for storing scaled results
2542 */
2543 OpScaleMatrix(boost::shared_ptr<double> scale_ptr,
2544 boost::shared_ptr<MatrixDouble> in_mat,
2545 boost::shared_ptr<MatrixDouble> out_mat)
2546 : UserOp(NOSPACE, OPSPACE), scalePtr(scale_ptr), inMat(in_mat),
2547 outMat(out_mat) {
2548 if (!scalePtr)
2549 THROW_MESSAGE("Pointer not set for scale");
2550 if (!inMat)
2551 THROW_MESSAGE("Pointer not set for in matrix");
2552 if (!outMat)
2553 THROW_MESSAGE("Pointer not set for in matrix");
2554 }
2555
2556 MoFEMErrorCode doWork(int, EntityType, EntData &) {
2558 outMat->resize(inMat->size1(), inMat->size2(), false);
2559 noalias(*outMat) = (*scalePtr) * (*inMat);
2561 }
2562
2563private:
2564 boost::shared_ptr<double> scalePtr;
2565 boost::shared_ptr<MatrixDouble> inMat;
2566 boost::shared_ptr<MatrixDouble> outMat;
2567};
2568
2569/**@}*/
2570
2571/** \name H-div/H-curls (Vectorial bases) values at integration points */
2572
2573/**@{*/
2574
2575/** \brief Get vector field for H-div approximation
2576 * \ingroup mofem_forces_and_sources_user_data_operators
2577 */
2578template <int Base_Dim, int Field_Dim, typename M = MatrixDouble>
2580
2581/** \brief Get vector field for H-div approximation
2582 * \ingroup mofem_forces_and_sources_user_data_operators
2583 */
2584template <int Field_Dim>
2587
2589 boost::shared_ptr<MatrixDouble> data_ptr,
2590 SmartPetscObj<Vec> data_vec,
2591 const EntityType zero_type = MBEDGE,
2592 const int zero_side = 0)
2595 dataPtr(data_ptr), dataVec(data_vec), zeroType(zero_type),
2596 zeroSide(zero_side) {
2597 if (!dataPtr)
2598 THROW_MESSAGE("Pointer is not set");
2599 }
2600
2602 boost::shared_ptr<MatrixDouble> data_ptr,
2603 const EntityType zero_type = MBEDGE,
2604 const int zero_side = 0)
2606 field_name, data_ptr, SmartPetscObj<Vec>(), zero_type, zero_side) {}
2607
2608 /**
2609 * \brief Calculate values of vector field at integration points
2610 * @param side side entity number
2611 * @param type side entity type
2612 * @param data entity data
2613 * @return error code
2614 */
2615 MoFEMErrorCode doWork(int side, EntityType type,
2617
2618private:
2619 boost::shared_ptr<MatrixDouble> dataPtr;
2621 const EntityHandle zeroType;
2622 const int zeroSide;
2624};
2625
2626template <int Field_Dim>
2628 3, Field_Dim, MatrixDouble>::doWork(int side, EntityType type,
2631 const size_t nb_integration_points = this->getGaussPts().size2();
2632 auto &mat = *dataPtr;
2634 auto get_data_at_pts =
2635 MatrixSizeHelper<GetFTensor1FromMatType<Field_Dim, -1, DL>,
2636 DL>::size(mat, nb_integration_points);
2637 if (type == zeroType && side == zeroSide) {
2638 mat.clear();
2639 }
2640 const size_t nb_dofs = data.getFieldData().size();
2641 if (!nb_dofs)
2643
2644 if (dataVec.use_count()) {
2645 dotVector.resize(nb_dofs, false);
2646 const double *array;
2647 CHKERR VecGetArrayRead(dataVec, &array);
2648 const auto &local_indices = data.getLocalIndices();
2649 for (int i = 0; i != local_indices.size(); ++i)
2650 if (local_indices[i] != -1)
2651 dotVector[i] = array[local_indices[i]];
2652 else
2653 dotVector[i] = 0;
2654 CHKERR VecRestoreArrayRead(dataVec, &array);
2655 data.getFieldData().swap(dotVector);
2656 }
2657
2658 const size_t nb_base_functions = data.getN().size2() / 3;
2659 FTensor::Index<'i', Field_Dim> i;
2660 auto t_n_hdiv = data.getFTensor1N<3>();
2661 auto t_data_at_pts = get_data_at_pts();
2662 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
2663 auto t_dof = data.getFTensor0FieldData();
2664 int bb = 0;
2665 for (; bb != nb_dofs; ++bb) {
2666 t_data_at_pts(i) += t_n_hdiv(i) * t_dof;
2667 ++t_n_hdiv;
2668 ++t_dof;
2669 }
2670 for (; bb != nb_base_functions; ++bb)
2671 ++t_n_hdiv;
2672 ++t_data_at_pts;
2673 }
2674
2675 if (dataVec.use_count()) {
2676 data.getFieldData().swap(dotVector);
2677 }
2679}
2680
2681/** \brief Get vector field for H-div approximation
2682 *
2683 * \ingroup mofem_forces_and_sources_user_data_operators
2684 */
2685template <int Base_Dim, int Field_Dim = Base_Dim>
2687 : public OpCalculateHVecVectorField_General<Base_Dim, Field_Dim> {
2689 Base_Dim, Field_Dim>::OpCalculateHVecVectorField_General;
2690};
2691
2692/** \brief Get vector field for H-div approximation
2693 * \ingroup mofem_forces_and_sources_user_data_operators
2694 */
2695template <int Base_Dim, int Field_Dim = Base_Dim>
2697
2698template <int Field_Dim>
2701
2703 boost::shared_ptr<MatrixDouble> data_ptr,
2704 const EntityType zero_type = MBEDGE,
2705 const int zero_side = 0)
2708 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
2709 if (!dataPtr)
2710 THROW_MESSAGE("Pointer is not set");
2711 }
2712
2713 /**
2714 * \brief Calculate values of vector field at integration points
2715 * @param side side entity number
2716 * @param type side entity type
2717 * @param data entity data
2718 * @return error code
2719 */
2720 MoFEMErrorCode doWork(int side, EntityType type,
2722
2723private:
2724 boost::shared_ptr<MatrixDouble> dataPtr;
2725 const EntityHandle zeroType;
2726 const int zeroSide;
2727};
2728
2729template <int Field_Dim>
2731 int side, EntityType type, EntitiesFieldData::EntData &data) {
2733
2734 const size_t nb_integration_points = this->getGaussPts().size2();
2735 auto &mat = *dataPtr;
2737 auto get_data_at_pts =
2738 MatrixSizeHelper<GetFTensor1FromMatType<Field_Dim, -1, DL>,
2739 DL>::size(mat, nb_integration_points);
2740 if (type == zeroType && side == zeroSide) {
2741 mat.clear();
2742 }
2743
2744 auto &local_indices = data.getIndices();
2745 const size_t nb_dofs = local_indices.size();
2746 if (nb_dofs) {
2747
2748 std::array<double, MAX_DOFS_ON_ENTITY> dot_dofs_vector;
2749 const double *array;
2750 CHKERR VecGetArrayRead(getFEMethod()->ts_u_t, &array);
2751 for (size_t i = 0; i != nb_dofs; ++i)
2752 if (local_indices[i] != -1)
2753 dot_dofs_vector[i] = array[local_indices[i]];
2754 else
2755 dot_dofs_vector[i] = 0;
2756 CHKERR VecRestoreArrayRead(getFEMethod()->ts_u_t, &array);
2757
2758 const size_t nb_base_functions = data.getN().size2() / 3;
2759 FTensor::Index<'i', Field_Dim> i;
2760 auto t_n_hdiv = data.getFTensor1N<3>();
2761 auto t_data_at_pts = get_data_at_pts();
2762 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
2763 size_t bb = 0;
2764 for (; bb != nb_dofs; ++bb) {
2765 t_data_at_pts(i) += t_n_hdiv(i) * dot_dofs_vector[bb];
2766 ++t_n_hdiv;
2767 }
2768 for (; bb != nb_base_functions; ++bb)
2769 ++t_n_hdiv;
2770 ++t_data_at_pts;
2771 }
2772 }
2773
2775}
2776
2777/**
2778 * @brief Calculate divergence of vector field
2779 * @ingroup mofem_forces_and_sources_user_data_operators
2780 *
2781 * @tparam BASE_DIM
2782 * @tparam SPACE_DIM
2783 */
2784template <int BASE_DIM, int SPACE_DIM>
2787
2789 boost::shared_ptr<VectorDouble> data_ptr,
2790 const EntityType zero_type = MBEDGE,
2791 const int zero_side = 0)
2794 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
2795 if (!dataPtr)
2796 THROW_MESSAGE("Pointer is not set");
2797 }
2798
2799 MoFEMErrorCode doWork(int side, EntityType type,
2802 const size_t nb_integration_points = getGaussPts().size2();
2803 if (type == zeroType && side == zeroSide) {
2804 dataPtr->resize(nb_integration_points, false);
2805 dataPtr->clear();
2806 }
2807 const size_t nb_dofs = data.getFieldData().size();
2808 if (!nb_dofs)
2810 const size_t nb_base_functions = data.getN().size2() / BASE_DIM;
2813 auto t_n_diff_hdiv = data.getFTensor2DiffN<BASE_DIM, SPACE_DIM>();
2814 auto t_data = getFTensor0FromVec(*dataPtr);
2815 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
2816 auto t_dof = data.getFTensor0FieldData();
2817 size_t bb = 0;
2818 for (; bb != nb_dofs; ++bb) {
2819 t_data += t_dof * t_n_diff_hdiv(j, j);
2820 ++t_n_diff_hdiv;
2821 ++t_dof;
2822 }
2823 for (; bb != nb_base_functions; ++bb)
2824 ++t_n_diff_hdiv;
2825 ++t_data;
2826 }
2828 }
2829
2830private:
2831 boost::shared_ptr<VectorDouble> dataPtr;
2832 const EntityHandle zeroType;
2833 const int zeroSide;
2834};
2835
2836/**
2837 * @brief Calculate gradient of vector field
2838 * @ingroup mofem_forces_and_sources_user_data_operators
2839 *
2840 * @tparam BASE_DIM
2841 * @tparam SPACE_DIM
2842 */
2843template <int BASE_DIM, int SPACE_DIM>
2846
2848 boost::shared_ptr<MatrixDouble> data_ptr,
2849 const EntityType zero_type = MBEDGE,
2850 const int zero_side = 0)
2853 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
2854 if (!dataPtr)
2855 THROW_MESSAGE("Pointer is not set");
2856 }
2857
2858 MoFEMErrorCode doWork(int side, EntityType type,
2861 const size_t nb_integration_points = getGaussPts().size2();
2863 auto get_data_at_pts =
2866 DL>::size(*dataPtr, nb_integration_points);
2867 if (type == zeroType && side == zeroSide)
2868 dataPtr->clear();
2869 const size_t nb_dofs = data.getFieldData().size();
2870 if (!nb_dofs)
2872 const size_t nb_base_functions = data.getN().size2() / BASE_DIM;
2875 auto t_base_diff = data.getFTensor2DiffN<BASE_DIM, SPACE_DIM>();
2876 auto t_data_at_pts = get_data_at_pts();
2877 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
2878 auto t_dof = data.getFTensor0FieldData();
2879 size_t bb = 0;
2880 for (; bb != nb_dofs; ++bb) {
2881 t_data_at_pts(i, j) += t_dof * t_base_diff(i, j);
2882 ++t_base_diff;
2883 ++t_dof;
2884 }
2885 for (; bb != nb_base_functions; ++bb)
2886 ++t_base_diff;
2887 ++t_data_at_pts;
2888 }
2890 }
2891
2892private:
2893 boost::shared_ptr<MatrixDouble> dataPtr;
2894 const EntityHandle zeroType;
2895 const int zeroSide;
2896};
2897
2898/**
2899 * @brief Calculate gradient of tensor field
2900 * @ingroup mofem_forces_and_sources_user_data_operators
2901 *
2902 * @tparam BASE_DIM
2903 * @tparam FIELD_DIM
2904 * @tparam SPACE_DIM
2905 */
2906template <int BASE_DIM, int FIELD_DIM, int SPACE_DIM>
2908
2909/**
2910 * @brief Specialisation for 3D tensor field gradient calculation
2911 * @ingroup mofem_forces_and_sources_user_data_operators
2912 *
2913 */
2914template <>
2917
2919 boost::shared_ptr<MatrixDouble> data_ptr,
2920 const EntityType zero_type = MBEDGE,
2921 const int zero_side = 0)
2924 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
2925 if (!dataPtr)
2926 THROW_MESSAGE("Pointer is not set");
2927 }
2928
2929 MoFEMErrorCode doWork(int side, EntityType type,
2932
2933 const size_t nb_integration_points = getGaussPts().size2();
2935 auto get_data_at_pts =
2937 DL>::size(*dataPtr, nb_integration_points);
2938 if (type == zeroType && side == zeroSide) {
2939 dataPtr->clear();
2940 }
2941
2942 #ifndef NDEBUG
2943 if (data.getFieldData().size() % 3) {
2944 SETERRQ(
2945 PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2946 "Data inconsistency, nb_dofs %% COEFF_DIM != 0, that is %ld %% %d "
2947 "!= 0",
2948 data.getFieldData().size(), 3);
2949 }
2950 #endif
2951
2952 const auto nb_dofs = data.getFieldData().size() / 3;
2953 if (!nb_dofs)
2955
2956 const size_t nb_base_functions = data.getN().size2() / 3;
2957 FTensor::Index<'i', 3> i;
2958 FTensor::Index<'j', 3> j;
2959 FTensor::Index<'k', 3> k;
2960
2961 auto t_base_diff = data.getFTensor2DiffN<3, 3>();
2962 auto t_data_at_pts = get_data_at_pts();
2963 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
2964 auto t_dof = data.getFTensor1FieldData<3>();
2965 size_t bb = 0;
2966 for (; bb != nb_dofs; ++bb) {
2967 t_data_at_pts(k, i, j) += t_base_diff(i, j) * t_dof(k);
2968 ++t_base_diff;
2969 ++t_dof;
2970 }
2971 for (; bb != nb_base_functions; ++bb)
2972 ++t_base_diff;
2973 ++t_data_at_pts;
2974 }
2976 }
2977
2978private:
2979 boost::shared_ptr<MatrixDouble> dataPtr;
2980 const EntityHandle zeroType;
2981 const int zeroSide;
2982};
2983
2984template <>
2987
2989 boost::shared_ptr<MatrixDouble> data_ptr,
2990 const EntityType zero_type = MBEDGE,
2991 const int zero_side = 0)
2994 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
2995 if (!dataPtr)
2996 THROW_MESSAGE("Pointer is not set");
2997 }
2998
2999 MoFEMErrorCode doWork(int side, EntityType type,
3002
3003 const size_t nb_integration_points = getGaussPts().size2();
3005 auto get_data_at_pts =
3007 DL>::size(*dataPtr, nb_integration_points);
3008 if (type == zeroType && side == zeroSide) {
3009 dataPtr->clear();
3010 }
3011
3012 const auto nb_dofs = data.getFieldData().size();
3013 if (!nb_dofs)
3015
3016 const size_t nb_base_functions = data.getN().size2() / 9;
3017
3018 #ifndef NDEBUG
3019 if (data.getDiffN().size1() != nb_integration_points) {
3020 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
3021 "Wrong number of integration pts (%ld != %ld)",
3022 static_cast<long>(data.getDiffN().size1()),
3023 static_cast<long>(nb_integration_points));
3024 }
3025 if (data.getDiffN().size2() != nb_base_functions * 27) {
3026 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
3027 "Wrong number of base functions (%ld != %ld)",
3028 static_cast<long>(data.getDiffN().size2() / 27),
3029 static_cast<long>(nb_base_functions));
3030 }
3031 if (nb_base_functions < nb_dofs) {
3032 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
3033 "Wrong number of base functions (%ld < %ld)",
3034 static_cast<long>(nb_base_functions),
3035 static_cast<long>(nb_dofs));
3036 }
3037 #endif
3038
3039 FTensor::Index<'i', 3> i;
3040 FTensor::Index<'j', 3> j;
3041 FTensor::Index<'k', 3> k;
3042
3043 auto t_base_diff = data.getFTensor3DiffN<3, 3, 3>();
3044 auto t_data_at_pts = get_data_at_pts();
3045 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
3046 auto t_dof = data.getFTensor0FieldData();
3047 size_t bb = 0;
3048 for (; bb != nb_dofs; ++bb) {
3049 t_data_at_pts(k, i, j) += t_base_diff(k, i, j) * t_dof;
3050 ++t_base_diff;
3051 ++t_dof;
3052 }
3053 for (; bb != nb_base_functions; ++bb)
3054 ++t_base_diff;
3055 ++t_data_at_pts;
3056 }
3057
3059 }
3060
3061private:
3062 boost::shared_ptr<MatrixDouble> dataPtr;
3063 const EntityHandle zeroType;
3064 const int zeroSide;
3065};
3066
3067/**
3068 * @brief Calculate gradient of vector field
3069 * @ingroup mofem_forces_and_sources_user_data_operators
3070 *
3071 * @tparam BASE_DIM
3072 * @tparam SPACE_DIM
3073 */
3074template <int BASE_DIM, int SPACE_DIM>
3077
3079 boost::shared_ptr<MatrixDouble> data_ptr,
3080 const EntityType zero_type = MBEDGE,
3081 const int zero_side = 0)
3084 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
3085 if (!dataPtr)
3086 THROW_MESSAGE("Pointer is not set");
3087 }
3088
3089 MoFEMErrorCode doWork(int side, EntityType type,
3092 const size_t nb_integration_points = getGaussPts().size2();
3094 auto get_data_at_pts = MatrixSizeHelper<
3096 DL>::size(*dataPtr, nb_integration_points);
3097 if (type == zeroType && side == zeroSide) {
3098 dataPtr->clear();
3099 }
3100 const size_t nb_dofs = data.getFieldData().size();
3101 if (!nb_dofs)
3103
3104 const int nb_base_functions = data.getN().size2() / BASE_DIM;
3105
3106 #ifndef NDEBUG
3107 auto &hessian_base = data.getN(BaseDerivatives::SecondDerivative);
3108 if (hessian_base.size1() != nb_integration_points) {
3109 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
3110 "Wrong number of integration pts (%ld != %ld)",
3111 static_cast<long>(hessian_base.size1()),
3112 static_cast<long>(nb_integration_points));
3113 }
3114 if (hessian_base.size2() !=
3115 BASE_DIM * nb_base_functions * SPACE_DIM * SPACE_DIM) {
3116 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
3117 "Wrong number of base functions (%ld != %ld)",
3118 static_cast<long>(hessian_base.size2() /
3120 static_cast<long>(nb_base_functions));
3121 }
3122 if (hessian_base.size2() < BASE_DIM * nb_dofs * SPACE_DIM * SPACE_DIM) {
3123 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
3124 "Wrong number of base functions (%ld < %ld)",
3125 static_cast<long>(hessian_base.size2()),
3126 static_cast<long>(BASE_DIM * nb_dofs * SPACE_DIM * SPACE_DIM));
3127 }
3128 #endif
3129
3133
3134 auto t_base_diff2 =
3136 auto t_data_at_pts = get_data_at_pts();
3137 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
3138 auto t_dof = data.getFTensor0FieldData();
3139 int bb = 0;
3140 for (; bb != nb_dofs; ++bb) {
3141 t_data_at_pts(i, j, k) += t_dof * t_base_diff2(i, j, k);
3142
3143 ++t_base_diff2;
3144 ++t_dof;
3145 }
3146 for (; bb != nb_base_functions; ++bb)
3147 ++t_base_diff2;
3148 ++t_data_at_pts;
3149 }
3151 }
3152
3153private:
3154 boost::shared_ptr<MatrixDouble> dataPtr;
3155 const EntityHandle zeroType;
3156 const int zeroSide;
3157};
3158
3159/**
3160 * @brief Calculate divergence of vector field dot
3161 * @ingroup mofem_forces_and_sources_user_data_operators
3162 *
3163 * @tparam Tensor_Dim dimension of space
3164 */
3165template <int Tensor_Dim1, int Tensor_Dim2>
3168
3170 boost::shared_ptr<VectorDouble> data_ptr,
3171 const EntityType zero_type = MBEDGE,
3172 const int zero_side = 0)
3175 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
3176 if (!dataPtr)
3177 THROW_MESSAGE("Pointer is not set");
3178 }
3179
3180 MoFEMErrorCode doWork(int side, EntityType type,
3183 const size_t nb_integration_points = getGaussPts().size2();
3184 if (type == zeroType && side == zeroSide) {
3185 dataPtr->resize(nb_integration_points, false);
3186 dataPtr->clear();
3187 }
3188
3189 const auto &local_indices = data.getLocalIndices();
3190 const int nb_dofs = local_indices.size();
3191 if (nb_dofs) {
3192
3193 std::array<double, MAX_DOFS_ON_ENTITY> dot_dofs_vector;
3194 const double *array;
3195 CHKERR VecGetArrayRead(getFEMethod()->ts_u_t, &array);
3196 for (size_t i = 0; i != local_indices.size(); ++i)
3197 if (local_indices[i] != -1)
3198 dot_dofs_vector[i] = array[local_indices[i]];
3199 else
3200 dot_dofs_vector[i] = 0;
3201 CHKERR VecRestoreArrayRead(getFEMethod()->ts_u_t, &array);
3202
3203 const size_t nb_base_functions = data.getN().size2() / Tensor_Dim1;
3204 FTensor::Index<'i', Tensor_Dim1> i;
3205 auto t_n_diff_hdiv = data.getFTensor2DiffN<Tensor_Dim1, Tensor_Dim2>();
3206 auto t_data = getFTensor0FromVec(*dataPtr);
3207 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
3208 int bb = 0;
3209 for (; bb != nb_dofs; ++bb) {
3210 double div = 0;
3211 for (auto ii = 0; ii != Tensor_Dim2; ++ii)
3212 div += t_n_diff_hdiv(ii, ii);
3213 t_data += dot_dofs_vector[bb] * div;
3214 ++t_n_diff_hdiv;
3215 }
3216 for (; bb != nb_base_functions; ++bb)
3217 ++t_n_diff_hdiv;
3218 ++t_data;
3219 }
3220 }
3222 }
3223
3224private:
3225 boost::shared_ptr<VectorDouble> dataPtr;
3226 const EntityHandle zeroType;
3227 const int zeroSide;
3228};
3229
3230/**
3231 * @brief Calculate curl of vector field
3232 * @ingroup mofem_forces_and_sources_user_data_operators
3233 *
3234 * @tparam Base_Dim base function dimension
3235 * @tparam Space_Dim dimension of space
3236 * @tparam Hcurl field dimension
3237 */
3238template <int Base_Dim, int Space_Dim> struct OpCalculateHcurlVectorCurl;
3239
3240/**
3241 * @brief Calculate curl of vector field
3242 * @ingroup mofem_forces_and_sources_user_data_operators
3243 *
3244 * @tparam Base_Dim base function dimension
3245 * @tparam Space_Dim dimension of space
3246 * @tparam Hcurl field dimension
3247 */
3248template <>
3251 OpCalculateHcurlVectorCurl(const std::string field_name,
3252 boost::shared_ptr<MatrixDouble> data_ptr,
3253 const EntityType zero_type = MBEDGE,
3254 const int zero_side = 0);
3255 MoFEMErrorCode doWork(int side, EntityType type,
3257
3258private:
3259 boost::shared_ptr<MatrixDouble> dataPtr;
3260 const EntityHandle zeroType;
3261 const int zeroSide;
3262};
3263
3264/**
3265 * @brief Calculate curl of vector field
3266 * @ingroup mofem_forces_and_sources_user_data_operators
3267 *
3268 * @tparam Field_Dim dimension of field
3269 * @tparam Space_Dim dimension of space
3270 */
3271template <>
3274
3275 OpCalculateHcurlVectorCurl(const std::string field_name,
3276 boost::shared_ptr<MatrixDouble> data_ptr,
3277 const EntityType zero_type = MBVERTEX,
3278 const int zero_side = 0);
3279
3280 MoFEMErrorCode doWork(int side, EntityType type,
3282
3283private:
3284 boost::shared_ptr<MatrixDouble> dataPtr;
3285 const EntityHandle zeroType;
3286 const int zeroSide;
3287};
3288
3289/**
3290 * @brief Calculate curl of vector field
3291 * @ingroup mofem_forces_and_sources_user_data_operators
3292 *
3293 * @tparam Field_Dim dimension of field
3294 * @tparam Space_Dim dimension of space
3295 */
3296template <>
3299
3300 OpCalculateHcurlVectorCurl(const std::string field_name,
3301 boost::shared_ptr<MatrixDouble> data_ptr,
3302 const EntityType zero_type = MBVERTEX,
3303 const int zero_side = 0);
3304
3305 MoFEMErrorCode doWork(int side, EntityType type,
3307
3308private:
3309 boost::shared_ptr<MatrixDouble> dataPtr;
3310 const EntityHandle zeroType;
3311 const int zeroSide;
3312};
3313
3314/**
3315 * @brief Calculate tenor field using vectorial base, i.e. Hdiv/Hcurl
3316 * \ingroup mofem_forces_and_sources_user_data_operators
3317 *
3318 * @tparam Tensor_Dim0 rank of the field
3319 * @tparam Tensor_Dim1 dimension of space
3320 */
3321template <int Tensor_Dim0, int Tensor_Dim1>
3324
3326 boost::shared_ptr<MatrixDouble> data_ptr,
3327 boost::shared_ptr<double> scale_ptr,
3329 const EntityType zero_type = MBEDGE,
3330 const int zero_side = 0)
3333 dataPtr(data_ptr), scalePtr(scale_ptr), dataVec(data_vec),
3334 zeroType(zero_type), zeroSide(zero_side) {
3335 if (!dataPtr)
3336 CHK_THROW_MESSAGE(MOFEM_DATA_INCONSISTENCY, "Pointer is not set");
3337 }
3338
3340 boost::shared_ptr<MatrixDouble> data_ptr,
3341 const EntityType zero_type = MBEDGE,
3342 const int zero_side = 0)
3343 : OpCalculateHVecTensorField(field_name, data_ptr, nullptr,
3344 SmartPetscObj<Vec>(), zero_type, zero_side) {
3345 }
3346
3347 MoFEMErrorCode doWork(int side, EntityType type,
3350 const size_t nb_integration_points = getGaussPts().size2();
3352 auto get_data_at_pts =
3354 GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
3355 DL>::size(*dataPtr, nb_integration_points);
3356 if (type == zeroType && side == zeroSide)
3357 dataPtr->clear();
3358 const size_t nb_dofs = data.getFieldData().size();
3359 if (nb_dofs) {
3360
3361 if (dataVec.use_count()) {
3362 dotVector.resize(nb_dofs, false);
3363 const double *array;
3364 CHKERR VecGetArrayRead(dataVec, &array);
3365 const auto &local_indices = data.getLocalIndices();
3366 for (int i = 0; i != local_indices.size(); ++i)
3367 if (local_indices[i] != -1)
3368 dotVector[i] = array[local_indices[i]];
3369 else
3370 dotVector[i] = 0;
3371 CHKERR VecRestoreArrayRead(dataVec, &array);
3372 data.getFieldData().swap(dotVector);
3373 }
3374
3375 double scale = (scalePtr) ? *scalePtr : 1.0;
3376 const size_t nb_base_functions = data.getN().size2() / 3;
3377 FTensor::Index<'i', Tensor_Dim0> i;
3378 FTensor::Index<'j', Tensor_Dim1> j;
3379 auto t_n_hvec = data.getFTensor1N<3>();
3380 auto t_data_at_pts = get_data_at_pts();
3381 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
3382 auto t_dof = data.getFTensor1FieldData<Tensor_Dim0>();
3383 size_t bb = 0;
3384 for (; bb != nb_dofs / Tensor_Dim0; ++bb) {
3385 t_data_at_pts(i, j) += (scale * t_dof(i)) * t_n_hvec(j);
3386 ++t_n_hvec;
3387 ++t_dof;
3388 }
3389 for (; bb < nb_base_functions; ++bb)
3390 ++t_n_hvec;
3391 ++t_data_at_pts;
3392 }
3393
3394 if (dataVec.use_count()) {
3395 data.getFieldData().swap(dotVector);
3396 }
3397 }
3399 }
3400
3401private:
3402 boost::shared_ptr<MatrixDouble> dataPtr;
3403 boost::shared_ptr<double> scalePtr;
3405 const EntityHandle zeroType;
3406 const int zeroSide;
3407 VectorDouble dotVector; ///< Keeps temporary values of time derivatives
3408};
3409
3410/** \brief Approximate Hdiv/Hcurl tensor field values for a given PETSc vector
3411 *
3412 * \note Look at PetscData to see what vectors could be extracted with that user
3413 * data operator.
3414 *
3415 * \ingroup mofem_forces_and_sources_user_data_operators
3416 */
3417template <int Tensor_Dim0, int Tensor_Dim1, PetscData::DataContext CTX>
3420
3422 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
3423 const EntityType zero_type = MBEDGE, const int zero_side = 0)
3426 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
3427 if (!dataPtr)
3428 THROW_MESSAGE("Pointer is not set");
3429 }
3430
3431 MoFEMErrorCode doWork(int side, EntityType type,
3434
3435 const size_t nb_integration_points = getGaussPts().size2();
3437 auto get_data_at_pts =
3439 GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
3440 DL>::size(*dataPtr, nb_integration_points);
3441 if (type == zeroType && side == zeroSide)
3442 dataPtr->clear();
3443
3444 const auto &local_indices = data.getLocalIndices();
3445 const size_t nb_dofs = local_indices.size();
3446 if (!nb_dofs)
3448
3449 const double *array;
3450
3451 auto get_array = [&](const auto ctx, auto vec) {
3453 #ifndef NDEBUG
3454 if ((getFEMethod()->data_ctx & ctx).none()) {
3455 MOFEM_LOG_CHANNEL("SELF");
3456 MOFEM_LOG("SELF", Sev::error)
3457 << "In this case field degrees of freedom are read from vector. "
3458 "That usually happens when time solver is used, and access to "
3459 "first or second rates is needed. You probably not set ts_u, "
3460 "ts_u_t, or ts_u_tt and associated data structure, i.e. "
3461 "data_ctx to CTX_SET_X, CTX_SET_DX, CTX_SET_X_T, or "
3462 "CTX_SET_X_TT respectively";
3463 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Vector not set");
3464 }
3465 #endif
3466 CHKERR VecGetArrayRead(vec, &array);
3468 };
3469
3470 auto restore_array = [&](auto vec) {
3471 return VecRestoreArrayRead(vec, &array);
3472 };
3473
3474 switch (CTX) {
3476 CHKERR get_array(PetscData::CtxSetX, getFEMethod()->ts_u);
3477 break;
3479 CHKERR get_array(PetscData::CtxSetX, getFEMethod()->dx);
3480 break;
3482 CHKERR get_array(PetscData::CtxSetX_T, getFEMethod()->ts_u_t);
3483 break;
3485 CHKERR get_array(PetscData::CtxSetX_TT, getFEMethod()->ts_u_tt);
3486 break;
3487 default:
3488 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
3489 "That case is not implemented");
3490 }
3491
3492 dotVector.resize(local_indices.size(), false);
3493 for (int i = 0; i != local_indices.size(); ++i)
3494 if (local_indices[i] != -1)
3495 dotVector[i] = array[local_indices[i]];
3496 else
3497 dotVector[i] = 0;
3498
3499 switch (CTX) {
3501 CHKERR restore_array(getFEMethod()->ts_u);
3502 break;
3504 CHKERR restore_array(getFEMethod()->dx);
3505 break;
3507 CHKERR restore_array(getFEMethod()->ts_u_t);
3508 break;
3510 CHKERR restore_array(getFEMethod()->ts_u_tt);
3511 break;
3512 default:
3513 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
3514 "That case is not implemented");
3515 }
3516
3517 const size_t nb_base_functions = data.getN().size2() / 3;
3518 FTensor::Index<'i', Tensor_Dim0> i;
3519 FTensor::Index<'j', Tensor_Dim1> j;
3520 auto t_n_hvec = data.getFTensor1N<3>();
3521 auto t_data_at_pts = get_data_at_pts();
3522 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
3523 auto t_dof = getFTensor1FromArray<Tensor_Dim0, Tensor_Dim0>(dotVector);
3524 size_t bb = 0;
3525 for (; bb != nb_dofs / Tensor_Dim0; ++bb) {
3526 t_data_at_pts(i, j) += t_dof(i) * t_n_hvec(j);
3527 ++t_n_hvec;
3528 ++t_dof;
3529 }
3530 for (; bb < nb_base_functions; ++bb)
3531 ++t_n_hvec;
3532 ++t_data_at_pts;
3533 }
3534
3536 }
3537
3538private:
3539 boost::shared_ptr<MatrixDouble> dataPtr;
3540 const EntityHandle zeroType;
3541 const int zeroSide;
3544};
3545
3546template <int Tensor_Dim0, int Tensor_Dim1>
3548 OpCalculateHVecTensorFieldFromPetscVecImpl<Tensor_Dim0, Tensor_Dim1,
3550
3551/** \brief Approximate tensor field values for a given PETSc vector on a tensor
3552 * basis
3553 *
3554 * \note Look at PetscData to see what vectors could be extracted with that user
3555 * data operator.
3556 *
3557 * \ingroup mofem_forces_and_sources_user_data_operators
3558 */
3559template <int Tensor_Dim0, int Tensor_Dim1, PetscData::DataContext CTX>
3562
3564 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
3565 const EntityType zero_type = MBEDGE, const int zero_side = 0,
3566 bool throw_error = true)
3569 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side),
3570 throwError(throw_error) {
3571 if (!dataPtr)
3572 THROW_MESSAGE("Pointer is not set");
3573 }
3574
3575 MoFEMErrorCode doWork(int side, EntityType type,
3578
3579 const size_t nb_integration_points = getGaussPts().size2();
3581 auto get_data_at_pts =
3583 GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
3584 DL>::size(*dataPtr, nb_integration_points);
3585 if (type == zeroType && side == zeroSide)
3586 dataPtr->clear();
3587
3588 const auto &local_indices = data.getLocalIndices();
3589 const size_t nb_dofs = local_indices.size();
3590 if (!nb_dofs)
3592
3593 if (!throwError) {
3594 if ((getFEMethod()->data_ctx & PetscData::Switches(CTX)).none()) {
3596 }
3597 }
3598
3599 const double *array;
3600
3601 auto get_array = [&](const auto ctx, auto vec) {
3603 #ifndef NDEBUG
3604 if ((getFEMethod()->data_ctx & ctx).none()) {
3605 MOFEM_LOG_CHANNEL("SELF");
3606 MOFEM_LOG("SELF", Sev::error)
3607 << "In this case field degrees of freedom are read from vector. "
3608 "That usually happens when time solver is used, and access to "
3609 "first or second rates is needed. You probably not set ts_u, "
3610 "ts_u_t, or ts_u_tt and associated data structure, i.e. "
3611 "data_ctx to CTX_SET_X, CTX_SET_DX, CTX_SET_X_T, or "
3612 "CTX_SET_X_TT respectively";
3613 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Vector not set");
3614 }
3615 #endif
3616 CHKERR VecGetArrayRead(vec, &array);
3618 };
3619
3620 auto restore_array = [&](auto vec) {
3621 return VecRestoreArrayRead(vec, &array);
3622 };
3623
3624 switch (CTX) {
3626 CHKERR get_array(PetscData::CtxSetX, getFEMethod()->ts_u);
3627 break;
3629 CHKERR get_array(PetscData::CtxSetX, getFEMethod()->dx);
3630 break;
3632 CHKERR get_array(PetscData::CtxSetX_T, getFEMethod()->ts_u_t);
3633 break;
3635 CHKERR get_array(PetscData::CtxSetX_TT, getFEMethod()->ts_u_tt);
3636 break;
3637 default:
3638 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
3639 "That case is not implemented");
3640 }
3641
3642 dotVector.resize(local_indices.size(), false);
3643 for (int i = 0; i != local_indices.size(); ++i)
3644 if (local_indices[i] != -1)
3645 dotVector[i] = array[local_indices[i]];
3646 else
3647 dotVector[i] = 0;
3648
3649 switch (CTX) {
3651 CHKERR restore_array(getFEMethod()->ts_u);
3652 break;
3654 CHKERR restore_array(getFEMethod()->dx);
3655 break;
3657 CHKERR restore_array(getFEMethod()->ts_u_t);
3658 break;
3660 CHKERR restore_array(getFEMethod()->ts_u_tt);
3661 break;
3662 default:
3663 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
3664 "That case is not implemented");
3665 }
3666
3667 const size_t nb_base_functions =
3668 data.getN().size2() / (Tensor_Dim0 * Tensor_Dim1);
3669 FTensor::Index<'i', Tensor_Dim0> i;
3670 FTensor::Index<'j', Tensor_Dim1> j;
3671 auto t_n_hten = data.getFTensor2N<Tensor_Dim0, Tensor_Dim1>();
3672 auto t_data_at_pts = get_data_at_pts();
3673 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
3674 auto t_dof = getFTensor0FromVec(dotVector);
3675 size_t bb = 0;
3676 for (; bb != nb_dofs; ++bb) {
3677 t_data_at_pts(i, j) += t_dof * t_n_hten(i, j);
3678 ++t_n_hten;
3679 ++t_dof;
3680 }
3681 for (; bb < nb_base_functions; ++bb)
3682 ++t_n_hten;
3683 ++t_data_at_pts;
3684 }
3685
3687 }
3688
3689private:
3690 boost::shared_ptr<MatrixDouble> dataPtr;
3691 const EntityHandle zeroType;
3692 const int zeroSide;
3695};
3696
3697template <int Tensor_Dim0, int Tensor_Dim1>
3699 OpCalculateHTensorTensorFieldFromPetscVecImpl<Tensor_Dim0, Tensor_Dim1,
3701
3702/** \brief Get tensor field for H-div approximation
3703 * \ingroup mofem_forces_and_sources_user_data_operators
3704 *
3705 * \warning This operator is not tested
3706 */
3707template <int Tensor_Dim0, int Tensor_Dim1>
3710
3712
3714 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
3715 SmartPetscObj<Vec> data_vec, EntityType broken_type,
3716 boost::shared_ptr<Range> broken_range_ptr = nullptr,
3717 boost::shared_ptr<double> scale_ptr = nullptr,
3718 const EntityType zero_type = MBEDGE, const int zero_side = 0)
3720 dataPtr(data_ptr), dataVec(data_vec), brokenType(broken_type),
3721 brokenRangePtr(broken_range_ptr), zeroType(zero_type) {
3722 if (!dataPtr)
3723 CHK_THROW_MESSAGE(MOFEM_DATA_INCONSISTENCY, "Pointer is not set");
3724 }
3725
3726 /**
3727 * \brief Calculate values of vector field at integration points
3728 * @param side side entity number
3729 * @param type side entity type
3730 * @param data entity data
3731 * @return error code
3732 */
3733 MoFEMErrorCode doWork(int side, EntityType type,
3735
3736private:
3737 boost::shared_ptr<MatrixDouble> dataPtr;
3739 EntityType brokenType;
3740 boost::shared_ptr<Range> brokenRangePtr;
3741 boost::shared_ptr<double> scalePtr;
3742 const EntityHandle zeroType;
3744};
3745
3746template <int Tensor_Dim0, int Tensor_Dim1>
3749 int side, EntityType type, EntitiesFieldData::EntData &data) {
3751 const size_t nb_integration_points = OP::getGaussPts().size2();
3753 auto get_data_at_pts =
3755 GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
3756 DL>::size(*dataPtr, nb_integration_points);
3757 if (type == zeroType)
3758 dataPtr->clear();
3759 const size_t nb_dofs = data.getFieldData().size();
3760 if (!nb_dofs)
3762
3763 if (dataVec.use_count()) {
3764 dotVector.resize(nb_dofs, false);
3765 const double *array;
3766 CHKERR VecGetArrayRead(dataVec, &array);
3767 const auto &local_indices = data.getLocalIndices();
3768 for (int i = 0; i != local_indices.size(); ++i)
3769 if (local_indices[i] != -1)
3770 dotVector[i] = array[local_indices[i]];
3771 else
3772 dotVector[i] = 0;
3773 CHKERR VecRestoreArrayRead(dataVec, &array);
3774 data.getFieldData().swap(dotVector);
3775 }
3776
3777 /**
3778 * @brief Get side face dofs
3779 *
3780 * Find which base functions on borken space have adjacent given entity type
3781 * and are in the range ptr if given.
3782 *
3783 */
3784 auto get_get_side_face_dofs = [&]() {
3785 auto fe_type = OP::getFEType();
3786
3787 BaseFunction::DofsSideMap &side_dof_map =
3788 data.getFieldEntities()[0]->getDofSideMap().at(fe_type);
3789 std::vector<int> side_face_dofs;
3790 side_face_dofs.reserve(data.getIndices().size() / Tensor_Dim0);
3791
3792 for (
3793
3794 auto it = side_dof_map.get<1>().begin();
3795 it != side_dof_map.get<1>().end(); ++it
3796
3797 ) {
3798 if ((Tensor_Dim0 * it->dof) >= data.getIndices().size()) {
3799 break;
3800 }
3801 if (it->type == brokenType) {
3802 if (brokenRangePtr) {
3803 auto ent = OP::getSideEntity(it->side, brokenType);
3804 if (brokenRangePtr->find(ent) != brokenRangePtr->end()) {
3805 side_face_dofs.push_back(it->dof);
3806 }
3807 } else {
3808 side_face_dofs.push_back(it->dof);
3809 }
3810 }
3811 }
3812
3813 return side_face_dofs;
3814 };
3815
3816 auto side_face_dofs = get_get_side_face_dofs();
3817
3818 FTensor::Index<'i', Tensor_Dim0> i;
3819 FTensor::Index<'j', Tensor_Dim1> j;
3820 auto t_data_at_pts = get_data_at_pts();
3821 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
3822 for (auto b : side_face_dofs) {
3823 auto t_row_base = data.getFTensor1N<3>(gg, b);
3824 auto t_dof = getFTensor1FromPtr<Tensor_Dim0>(data.getFieldData().data() +
3825 b * Tensor_Dim0);
3826 t_data_at_pts(i, j) += t_dof(i) * t_row_base(j);
3827 }
3828 ++t_data_at_pts;
3829 }
3830 *dataPtr *= (scalePtr) ? *scalePtr : 1.0;
3831
3832 if (dataVec.use_count()) {
3833 data.getFieldData().swap(dotVector);
3834 }
3835
3837}
3838
3839/**
3840 * @brief Calculate tenor field using tensor base, i.e. Hdiv/Hcurl
3841 * \ingroup mofem_forces_and_sources_user_data_operators
3842 *
3843 * @tparam Tensor_Dim0 rank of the field
3844 * @tparam Tensor_Dim1 dimension of space
3845 */
3846template <int Tensor_Dim0, int Tensor_Dim1>
3849
3851 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
3852 boost::shared_ptr<double> scale_ptr,
3854 const EntityType zero_type = MBEDGE, const int zero_side = 0)
3857 dataPtr(data_ptr), scalePtr(scale_ptr), dataVec(data_vec),
3858 zeroType(zero_type), zeroSide(zero_side) {
3859 if (!dataPtr)
3860 THROW_MESSAGE("Pointer is not set");
3861 }
3862
3864 boost::shared_ptr<MatrixDouble> data_ptr,
3865 const EntityType zero_type = MBEDGE,
3866 const int zero_side = 0)
3867 : OpCalculateHTensorTensorField(field_name, data_ptr, nullptr,
3868 SmartPetscObj<Vec>(), zero_type,
3869 zero_side) {}
3870
3871 MoFEMErrorCode doWork(int side, EntityType type,
3874 const size_t nb_integration_points = getGaussPts().size2();
3876 auto get_data_at_pts =
3878 GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
3879 DL>::size(*dataPtr, nb_integration_points);
3880 if (type == zeroType && side == zeroSide)
3881 dataPtr->clear();
3882 const size_t nb_dofs = data.getFieldData().size();
3883 if (!nb_dofs)
3885
3886 if (dataVec.use_count()) {
3887 dotVector.resize(nb_dofs, false);
3888 const double *array;
3889 CHKERR VecGetArrayRead(dataVec, &array);
3890 const auto &local_indices = data.getLocalIndices();
3891 for (int i = 0; i != local_indices.size(); ++i)
3892 if (local_indices[i] != -1)
3893 dotVector[i] = array[local_indices[i]];
3894 else
3895 dotVector[i] = 0;
3896 CHKERR VecRestoreArrayRead(dataVec, &array);
3897 data.getFieldData().swap(dotVector);
3898 }
3899
3900 double scale = (scalePtr) ? *scalePtr : 1.0;
3901 const size_t nb_base_functions =
3902 data.getN().size2() / (Tensor_Dim0 * Tensor_Dim1);
3903 FTensor::Index<'i', Tensor_Dim0> i;
3904 FTensor::Index<'j', Tensor_Dim1> j;
3905 auto t_n_hten = data.getFTensor2N<Tensor_Dim0, Tensor_Dim1>();
3906 auto t_data_at_pts = get_data_at_pts();
3907 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
3908 auto t_dof = data.getFTensor0FieldData();
3909 size_t bb = 0;
3910 for (; bb != nb_dofs; ++bb) {
3911 t_data_at_pts(i, j) += (scale * t_dof) * t_n_hten(i, j);
3912 ++t_n_hten;
3913 ++t_dof;
3914 }
3915 for (; bb < nb_base_functions; ++bb)
3916 ++t_n_hten;
3917 ++t_data_at_pts;
3918 }
3919
3920 if (dataVec.use_count()) {
3921 data.getFieldData().swap(dotVector);
3922 }
3923
3925 }
3926
3927private:
3928 boost::shared_ptr<MatrixDouble> dataPtr;
3929 boost::shared_ptr<double> scalePtr;
3931 const EntityHandle zeroType;
3932 const int zeroSide;
3933 VectorDouble dotVector; ///< Keeps temporary values of time derivatives
3934};
3935
3936/**
3937 * @brief Calculate divergence of tonsorial field using vectorial base
3938 * \ingroup mofem_forces_and_sources_user_data_operators
3939 *
3940 * @tparam Tensor_Dim0 rank of the field
3941 * @tparam Tensor_Dim1 dimension of space
3942 */
3943template <int Tensor_Dim0, int Tensor_Dim1,
3944 CoordinateTypes CoordSys = CARTESIAN>
3947
3949 boost::shared_ptr<MatrixDouble> data_ptr,
3950 SmartPetscObj<Vec> data_vec,
3951 const EntityType zero_type = MBEDGE,
3952 const int zero_side = 0)
3955 dataPtr(data_ptr), dataVec(data_vec), zeroType(zero_type),
3956 zeroSide(zero_side) {
3957 if (!dataPtr)
3958 CHK_THROW_MESSAGE(MOFEM_DATA_INCONSISTENCY, "Pointer is not set");
3959 }
3960
3962 boost::shared_ptr<MatrixDouble> data_ptr,
3963 const EntityType zero_type = MBEDGE,
3964 const int zero_side = 0)
3966 field_name, data_ptr, SmartPetscObj<Vec>(), zero_type, zero_side) {}
3967
3968 MoFEMErrorCode doWork(int side, EntityType type,
3971 const size_t nb_integration_points = getGaussPts().size2();
3972 auto &mat = *dataPtr;
3974 auto get_data_at_pts =
3975 MatrixSizeHelper<GetFTensor1FromMatType<Tensor_Dim0, -1, DL>,
3976 DL>::size(mat, nb_integration_points);
3977 if (type == zeroType && side == zeroSide) {
3978 mat.clear();
3979 }
3980 const size_t nb_dofs = data.getFieldData().size();
3981 if (nb_dofs) {
3982
3983 if (dataVec.use_count()) {
3984 dotVector.resize(nb_dofs, false);
3985 const double *array;
3986 CHKERR VecGetArrayRead(dataVec, &array);
3987 const auto &local_indices = data.getLocalIndices();
3988 for (int i = 0; i != local_indices.size(); ++i)
3989 if (local_indices[i] != -1)
3990 dotVector[i] = array[local_indices[i]];
3991 else
3992 dotVector[i] = 0;
3993 CHKERR VecRestoreArrayRead(dataVec, &array);
3994 data.getFieldData().swap(dotVector);
3995 }
3996
3997 const size_t nb_base_functions = data.getN().size2() / 3;
3998 FTensor::Index<'i', Tensor_Dim0> i;
3999 FTensor::Index<'j', Tensor_Dim1> j;
4000 auto t_n_diff_hvec = data.getFTensor2DiffN<3, Tensor_Dim1>();
4001 auto t_data_at_pts = get_data_at_pts();
4002 auto t_base = data.getFTensor1N<3>();
4003 auto t_coords = getFTensor1CoordsAtGaussPts();
4004 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
4005 auto t_dof = data.getFTensor1FieldData<Tensor_Dim0>();
4006 size_t bb = 0;
4007 for (; bb != nb_dofs / Tensor_Dim0; ++bb) {
4008 double div = t_n_diff_hvec(j, j);
4009 t_data_at_pts(i) += t_dof(i) * div;
4010 if constexpr (CoordSys == CYLINDRICAL) {
4011 t_data_at_pts(i) += t_base(0) * (t_dof(i) / t_coords(0));
4012 }
4013 ++t_n_diff_hvec;
4014 ++t_dof;
4015 ++t_base;
4016 }
4017 for (; bb < nb_base_functions; ++bb) {
4018 ++t_base;
4019 ++t_n_diff_hvec;
4020 }
4021 ++t_data_at_pts;
4022 ++t_coords;
4023 }
4024
4025 if (dataVec.use_count()) {
4026 data.getFieldData().swap(dotVector);
4027 }
4028 }
4030 }
4031
4032private:
4033 boost::shared_ptr<MatrixDouble> dataPtr;
4035 const EntityHandle zeroType;
4036 const int zeroSide;
4037
4038 VectorDouble dotVector; ///< Keeps temporary values of time derivatives
4039};
4040
4041/**
4042 * @brief Calculate divergence of tonsorial field using vectorial base
4043 * \ingroup mofem_forces_and_sources_user_data_operators
4044 *
4045 * \warning This operator is not tested
4046 *
4047 * @tparam Tensor_Dim0 rank of the field
4048 * @tparam Tensor_Dim1 dimension of space
4049 */
4050template <int Tensor_Dim0, int Tensor_Dim1,
4051 CoordinateTypes CoordSys = CARTESIAN>
4054
4056
4058 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
4059 SmartPetscObj<Vec> data_vec, EntityType broken_type,
4060 boost::shared_ptr<Range> broken_range_ptr = nullptr,
4061 boost::shared_ptr<double> scale_ptr = nullptr,
4062 const EntityType zero_type = MBEDGE)
4064 dataPtr(data_ptr), dataVec(data_vec), brokenType(broken_type),
4065 brokenRangePtr(broken_range_ptr), scalePtr(scale_ptr),
4066 zeroType(zero_type) {
4067 if (!dataPtr)
4068 CHK_THROW_MESSAGE(MOFEM_DATA_INCONSISTENCY, "Pointer is not set");
4069 }
4070
4071 MoFEMErrorCode doWork(int side, EntityType type,
4074 const size_t nb_integration_points = getGaussPts().size2();
4075 auto &mat = *dataPtr;
4077 auto get_data_at_pts =
4078 MatrixSizeHelper<GetFTensor1FromMatType<Tensor_Dim0, -1, DL>,
4079 DL>::size(mat, nb_integration_points);
4080 if (type == zeroType && side == 0) {
4081 mat.clear();
4082 }
4083
4084 const size_t nb_dofs = data.getFieldData().size();
4085 if (nb_dofs) {
4086
4087 if (dataVec.use_count()) {
4088 dotVector.resize(nb_dofs, false);
4089 const double *array;
4090 CHKERR VecGetArrayRead(dataVec, &array);
4091 const auto &local_indices = data.getLocalIndices();
4092 for (int i = 0; i != local_indices.size(); ++i)
4093 if (local_indices[i] != -1)
4094 dotVector[i] = array[local_indices[i]];
4095 else
4096 dotVector[i] = 0;
4097 CHKERR VecRestoreArrayRead(dataVec, &array);
4098 data.getFieldData().swap(dotVector);
4099 }
4100
4101 /**
4102 * @brief Get side face dofs
4103 *
4104 * Find which base functions on borken space have adjacent given entity
4105 * type and are in the range ptr if given.
4106 *
4107 */
4108 auto get_get_side_face_dofs = [&]() {
4109 auto fe_type = OP::getFEType();
4110
4111 BaseFunction::DofsSideMap &side_dof_map =
4112 data.getFieldEntities()[0]->getDofSideMap().at(fe_type);
4113 std::vector<int> side_face_dofs;
4114 side_face_dofs.reserve(data.getIndices().size() / Tensor_Dim0);
4115
4116 for (
4117
4118 auto it = side_dof_map.get<1>().begin();
4119 it != side_dof_map.get<1>().end(); ++it
4120
4121 ) {
4122 if ((Tensor_Dim0 * it->dof) >= data.getIndices().size()) {
4123 break;
4124 }
4125 if (it->type == brokenType) {
4126 if (brokenRangePtr) {
4127 auto ent = OP::getSideEntity(it->side, brokenType);
4128 if (brokenRangePtr->find(ent) != brokenRangePtr->end()) {
4129 side_face_dofs.push_back(it->dof);
4130 }
4131 } else {
4132 side_face_dofs.push_back(it->dof);
4133 }
4134 }
4135 }
4136
4137 return side_face_dofs;
4138 };
4139
4140 auto side_face_dofs = get_get_side_face_dofs();
4141
4142 FTensor::Index<'i', Tensor_Dim0> i;
4143 FTensor::Index<'j', Tensor_Dim1> j;
4144 auto t_data_at_pts = get_data_at_pts();
4145 auto t_coords = getFTensor1CoordsAtGaussPts();
4146 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
4147 for (auto b : side_face_dofs) {
4148 auto t_dof = getFTensor1FromPtr<Tensor_Dim0>(
4149 data.getFieldData().data() + b * Tensor_Dim0);
4150 auto t_base = data.getFTensor1N<3>(gg, b);
4151 auto t_diff_base = data.getFTensor2DiffN<3, Tensor_Dim1>(gg, b);
4152 double div = t_diff_base(j, j);
4153 t_data_at_pts(i) += t_dof(i) * div;
4154 if constexpr (CoordSys == CYLINDRICAL) {
4155 t_data_at_pts(i) += t_base(0) * (t_dof(i) / t_coords(0));
4156 }
4157 }
4158 ++t_data_at_pts;
4159 ++t_coords;
4160 }
4161 }
4162
4163 if (dataVec.use_count()) {
4164 data.getFieldData().swap(dotVector);
4165 }
4166
4168 }
4169
4170private:
4171 boost::shared_ptr<MatrixDouble> dataPtr;
4173 EntityType brokenType;
4174 boost::shared_ptr<Range> brokenRangePtr;
4175 boost::shared_ptr<double> scalePtr;
4176 const EntityHandle zeroType;
4178};
4179
4180/**
4181 * @brief Calculate trace of vector (Hdiv/Hcurl) space
4182 *
4183 * @tparam Tensor_Dim
4184 * @tparam OpBase
4185 */
4186template <int Tensor_Dim, typename OpBase>
4188
4190 boost::shared_ptr<MatrixDouble> data_ptr,
4191 boost::shared_ptr<double> scale_ptr,
4192 const EntityType zero_type = MBEDGE,
4193 const int zero_side = 0)
4194 : OpBase(field_name, OpBase::OPCOL), dataPtr(data_ptr),
4195 scalePtr(scale_ptr), zeroType(zero_type), zeroSide(zero_side) {
4196 if (!dataPtr)
4197 THROW_MESSAGE("Pointer is not set");
4198 }
4199
4201 boost::shared_ptr<MatrixDouble> data_ptr,
4202 const EntityType zero_type = MBEDGE,
4203 const int zero_side = 0)
4204 : OpCalculateHVecTensorTrace(field_name, data_ptr, nullptr, zero_type,
4205 zero_side) {}
4206
4207 MoFEMErrorCode doWork(int side, EntityType type,
4210 const size_t nb_integration_points = OpBase::getGaussPts().size2();
4211 auto &mat = *dataPtr;
4213 auto get_data_at_pts =
4214 MatrixSizeHelper<GetFTensor1FromMatType<Tensor_Dim, -1, DL>,
4215 DL>::size(mat, nb_integration_points);
4216 if (type == zeroType && side == 0) {
4217 mat.clear();
4218 }
4219 const size_t nb_dofs = data.getFieldData().size();
4220 if (nb_dofs) {
4221 double scale_val = (scalePtr) ? *scalePtr : 1.0;
4222 auto t_normal = OpBase::getFTensor1NormalsAtGaussPts();
4223 const size_t nb_base_functions = data.getN().size2() / 3;
4224 auto t_base = data.getFTensor1N<3>();
4225 auto t_data_at_pts = get_data_at_pts();
4226 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
4227 FTensor::Tensor1<double, Tensor_Dim> t_normalized_normal;
4228 t_normalized_normal(j) = t_normal(j);
4229 t_normalized_normal.normalize();
4230 auto t_dof = data.getFTensor1FieldData<Tensor_Dim>();
4231 size_t bb = 0;
4232 for (; bb != nb_dofs / Tensor_Dim; ++bb) {
4233 t_data_at_pts(i) +=
4234 (scale_val * t_dof(i)) * (t_base(j) * t_normalized_normal(j));
4235 ++t_base;
4236 ++t_dof;
4237 }
4238 for (; bb < nb_base_functions; ++bb) {
4239 ++t_base;
4240 }
4241 ++t_data_at_pts;
4242 ++t_normal;
4243 }
4244 }
4246 }
4247
4248private:
4249 boost::shared_ptr<MatrixDouble> dataPtr;
4250 boost::shared_ptr<double> scalePtr;
4251 const EntityHandle zeroType;
4252 const int zeroSide;
4253 FTensor::Index<'i', Tensor_Dim> i;
4254 FTensor::Index<'j', Tensor_Dim> j;
4255};
4256
4257/**@}*/
4258
4259/** \name Other operators */
4260
4261/**@{*/
4262
4263/**@}*/
4264
4265/** \name Operators for faces */
4266
4267/**@{*/
4268
4269/** \brief Transform local reference derivatives of shape functions to global
4270derivatives
4271
4272\ingroup mofem_forces_and_sources_tri_element
4273
4274*/
4275template <int DIM, int DERIVATIVE = 1> struct OpSetInvJacSpaceForFaceImpl;
4276
4279
4281 boost::shared_ptr<MatrixDouble> inv_jac_ptr);
4282
4283protected:
4284 /**
4285 * @brief Apply transformation to the input matrix
4286 *
4287 * @tparam D1 dimension of the derivative of base functions in input
4288 * @tparam D2 dimension of the derivative of base functions in output
4289 * @tparam J1 nb of rows in jacobian (= dimension of space)
4290 * @tparam J2 nb of columns in jacobian (= dimension of reference element)
4291 * @param diff_n
4292 * @return MoFEMErrorCode
4293 */
4294 template <int D1, int D2, int J1, int J2>
4297
4298 static_assert(D2 == J2, "Dimension of jacobian and dimension of <out> "
4299 "directive does not match");
4300
4301 size_t nb_functions = diff_n.size2() / D1;
4302 if (nb_functions) {
4303 size_t nb_gauss_pts = diff_n.size1();
4304
4305 #ifndef NDEBUG
4306 if (nb_gauss_pts != getGaussPts().size2())
4307 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
4308 "Wrong number of Gauss Pts");
4309 if (diff_n.size2() % D1)
4310 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
4311 "Number of directives of base functions and D1 dimension does "
4312 "not match");
4313 #endif
4314
4315 diffNinvJac.resize(diff_n.size1(), D2 * nb_functions, false);
4316
4317 FTensor::Index<'i', D2> i;
4318 FTensor::Index<'k', D1> k;
4319 auto t_diff_n = getFTensor1FromPtr<D2>(&*diffNinvJac.data().begin());
4320 auto t_diff_n_ref = getFTensor1FromPtr<D1>(&*diff_n.data().begin());
4322 auto get_inv_jac_at_pts =
4323 MatrixSizeHelper<GetFTensor2FromMatType<J1, J2, -1, DL>, DL>::get(
4324 *invJacPtr, nb_gauss_pts);
4325 auto t_inv_jac_at_pts = get_inv_jac_at_pts();
4326 for (size_t gg = 0; gg != nb_gauss_pts; ++gg, ++t_inv_jac_at_pts) {
4327 for (size_t dd = 0; dd != nb_functions; ++dd) {
4328 t_diff_n(i) = t_inv_jac_at_pts(k, i) * t_diff_n_ref(k);
4329 ++t_diff_n;
4330 ++t_diff_n_ref;
4331 }
4332 }
4333
4334 diff_n.swap(diffNinvJac);
4335 }
4337 }
4338
4339 boost::shared_ptr<MatrixDouble> invJacPtr;
4341};
4342
4343template <>
4346
4348
4349 MoFEMErrorCode doWork(int side, EntityType type,
4351};
4352
4353template <>
4355 : public OpSetInvJacSpaceForFaceImpl<2, 1> {
4356
4357 using OpSetInvJacSpaceForFaceImpl<2, 1>::OpSetInvJacSpaceForFaceImpl;
4358
4359 MoFEMErrorCode doWork(int side, EntityType type,
4361};
4362
4363template <>
4365 : public OpSetInvJacSpaceForFaceImpl<2, 1> {
4366
4367 using OpSetInvJacSpaceForFaceImpl<2, 1>::OpSetInvJacSpaceForFaceImpl;
4368
4369 MoFEMErrorCode doWork(int side, EntityType type,
4371};
4372
4373template <int DERIVARIVE = 1>
4375 : public OpSetInvJacSpaceForFaceImpl<2, DERIVARIVE> {
4376 OpSetInvJacH1ForFace(boost::shared_ptr<MatrixDouble> inv_jac_ptr)
4377 : OpSetInvJacSpaceForFaceImpl<2, DERIVARIVE>(H1, inv_jac_ptr) {}
4378};
4379
4380template <int DERIVARIVE = 1>
4382 : public OpSetInvJacSpaceForFaceImpl<2, DERIVARIVE> {
4383 OpSetInvJacL2ForFace(boost::shared_ptr<MatrixDouble> inv_jac_ptr)
4384 : OpSetInvJacSpaceForFaceImpl<2, DERIVARIVE>(L2, inv_jac_ptr) {}
4385};
4386
4387template <int DERIVARIVE = 1>
4389 : public OpSetInvJacSpaceForFaceImpl<3, DERIVARIVE> {
4391 boost::shared_ptr<MatrixDouble> inv_jac_ptr)
4392 : OpSetInvJacSpaceForFaceImpl<3, DERIVARIVE>(H1, inv_jac_ptr) {}
4393};
4394
4395template <int DERIVARIVE = 1>
4397 : public OpSetInvJacSpaceForFaceImpl<3, DERIVARIVE> {
4399 boost::shared_ptr<MatrixDouble> inv_jac_ptr)
4400 : OpSetInvJacSpaceForFaceImpl<3, DERIVARIVE>(L2, inv_jac_ptr) {}
4401};
4402
4403/**
4404 * \brief Transform local reference derivatives of shape function to
4405 global derivatives for face
4406
4407 * \ingroup mofem_forces_and_sources_tri_element
4408 */
4409template <int DIM> struct OpSetInvJacHcurlFaceImpl;
4410
4411template <>
4414
4415 OpSetInvJacHcurlFaceImpl(boost::shared_ptr<MatrixDouble> inv_jac_ptr)
4417 invJacPtr(inv_jac_ptr) {}
4418
4419 MoFEMErrorCode doWork(int side, EntityType type,
4421
4422protected:
4423 boost::shared_ptr<MatrixDouble> invJacPtr;
4425};
4426
4427template <>
4429 using OpSetInvJacHcurlFaceImpl<2>::OpSetInvJacHcurlFaceImpl;
4430 MoFEMErrorCode doWork(int side, EntityType type,
4432};
4433
4436
4437/**
4438 * @brief Make Hdiv space from Hcurl space in 2d
4439 * @ingroup mofem_forces_and_sources_tri_element
4440 */
4450
4451/** \brief Transform Hcurl base fluxes from reference element to physical
4452 * triangle
4453 */
4455
4456/** \brief Apply contravariant (Piola) transfer to Hdiv space on face
4457 *
4458 * Covariant Piola transformation
4459 \f[
4460 \psi_i|_t = J^{-1}_{ij}\hat{\psi}_j\\
4461 \left.\frac{\partial \psi_i}{\partial \xi_j}\right|_t
4462 = J^{-1}_{ik}\frac{\partial \hat{\psi}_k}{\partial \xi_j}
4463 \f]
4464
4465 */
4466template <>
4469
4471 boost::shared_ptr<MatrixDouble> inv_jac_ptr);
4472
4473 MoFEMErrorCode doWork(int side, EntityType type,
4475
4476private:
4477 boost::shared_ptr<MatrixDouble> invJacPtr;
4478
4481};
4482
4485
4486/** \brief Apply contravariant (Piola) transfer to Hdiv space on face
4487 *
4488 * \note Hdiv space is generated by Hcurl space in 2d.
4489 *
4490 * Contravariant Piola transformation
4491 * \f[
4492 * \psi_i|_t = \frac{1}{\textrm{det}(J)}J_{ij}\hat{\psi}_j\\
4493 * \left.\frac{\partial \psi_i}{\partial \xi_j}\right|_t
4494 * =
4495 * \frac{1}{\textrm{det}(J)}J_{ik}\frac{\partial \hat{\psi}_k}{\partial \xi_j}
4496 * \f]
4497 *
4498 * \ingroup mofem_forces_and_sources
4499 *
4500 */
4502
4503template <>
4506
4508 boost::shared_ptr<MatrixDouble> jac_ptr)
4510 jacPtr(jac_ptr) {}
4511
4512 MoFEMErrorCode doWork(int side, EntityType type,
4514
4515protected:
4516 boost::shared_ptr<MatrixDouble> jacPtr;
4519};
4520
4521template <>
4525 2>::OpSetContravariantPiolaTransformOnFace2DImpl;
4526
4527 MoFEMErrorCode doWork(int side, EntityType type,
4529};
4530
4535
4536/**@}*/
4537
4538/** \name Operators for edges */
4539
4540/**@{*/
4541
4551
4552/**
4553 * @deprecated Name is deprecated and this is added for backward compatibility
4554 */
4557
4558/**@}*/
4559
4560/** \name Operator for fat prisms */
4561
4562/**@{*/
4563
4564/**
4565 * @brief Operator for fat prism element updating integration weights in the
4566 * volume.
4567 *
4568 * Jacobian on the distorted element is nonconstant. This operator updates
4569 * integration weight on prism to take into account nonconstat jacobian.
4570 *
4571 * \f[
4572 * W_i = w_i \left( \frac{1}{2V} \left\| \frac{\partial \mathbf{x}}{\partial
4573 * \pmb\xi} \right\| \right)
4574 * \f]
4575 * where \f$w_i\f$ is integration weight at integration point \f$i\f$,
4576 * \f$\mathbf{x}\f$ is physical coordinate, and \f$\pmb\xi\f$ is reference
4577 * element coordinate.
4578 *
4579 */
4589
4590/** \brief Calculate inverse of jacobian for face element
4591
4592 It is assumed that face element is XY plane. Applied
4593 only for 2d problems.
4594
4595 FIXME Generalize function for arbitrary face orientation in 3d space
4596 FIXME Calculate to Jacobins for two faces
4597
4598 \ingroup mofem_forces_and_sources_prism_element
4599
4600*/
4603
4604 OpCalculateInvJacForFatPrism(boost::shared_ptr<MatrixDouble> inv_jac_ptr)
4606 invJacPtr(inv_jac_ptr), invJac(*invJacPtr) {}
4607
4611 MoFEMErrorCode doWork(int side, EntityType type,
4613
4614private:
4615 const boost::shared_ptr<MatrixDouble> invJacPtr;
4617};
4618
4619/** \brief Transform local reference derivatives of shape functions to global
4620derivatives
4621
4622FIXME Generalize to curved shapes
4623FIXME Generalize to case that top and bottom face has different shape
4624
4625\ingroup mofem_forces_and_sources_prism_element
4626
4627*/
4630
4631 OpSetInvJacH1ForFatPrism(boost::shared_ptr<MatrixDouble> inv_jac_ptr)
4633 invJacPtr(inv_jac_ptr), invJac(*invJacPtr) {}
4634
4638
4639 MoFEMErrorCode doWork(int side, EntityType type,
4641
4642private:
4643 const boost::shared_ptr<MatrixDouble> invJacPtr;
4646};
4647
4648// Flat prism
4649
4650/** \brief Calculate inverse of jacobian for face element
4651
4652 It is assumed that face element is XY plane. Applied
4653 only for 2d problems.
4654
4655 FIXME Generalize function for arbitrary face orientation in 3d space
4656 FIXME Calculate to Jacobins for two faces
4657
4658 \ingroup mofem_forces_and_sources_prism_element
4659
4660*/
4673
4674/** \brief Transform local reference derivatives of shape functions to global
4675derivatives
4676
4677FIXME Generalize to curved shapes
4678FIXME Generalize to case that top and bottom face has different shape
4679
4680\ingroup mofem_forces_and_sources_prism_element
4681
4682*/
4697
4698/**@}*/
4699
4700/** \name Operation on matrices at integration points */
4701
4702/**@{*/
4703
4704/**
4705 * @brief Operator for inverting matrices at integration points
4706 *
4707 * This template structure computes the inverse of square matrices and their
4708 * determinants at integration points. It's commonly used in finite element
4709 * methods for coordinate transformations, constitutive relations, and other
4710 * matrix operations requiring matrix inversion.
4711 *
4712 * @tparam DIM Dimension of the square matrix to be inverted
4713 */
4714template <int DIM>
4716
4717 /**
4718 * @brief Constructor for matrix inversion operator
4719 *
4720 * @param in_ptr Shared pointer to input matrix to be inverted
4721 * @param det_ptr Shared pointer to vector for storing matrix determinants
4722 * @param out_ptr Shared pointer to output matrix for storing inverted matrices
4723 */
4724 template <typename T>
4725 OpInvertMatrix(boost::shared_ptr<MatrixDouble> in_ptr,
4726 boost::shared_ptr<T> det_ptr,
4727 boost::shared_ptr<MatrixDouble> out_ptr)
4729 outPtr(out_ptr), detPtrVariant(det_ptr) {}
4730
4731 MoFEMErrorCode doWork(int side, EntityType type,
4733
4734private:
4735 boost::shared_ptr<MatrixDouble> inPtr;
4736 boost::shared_ptr<MatrixDouble> outPtr;
4737 std::variant<boost::shared_ptr<VectorDouble>, boost::shared_ptr<MatrixDouble>>
4739};
4740
4741template <int DIM>
4745
4746#ifndef NDEBUG
4747 if (!inPtr)
4748 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
4749 "Pointer for inPtr matrix not allocated");
4750
4751 if (!std::holds_alternative<boost::shared_ptr<VectorDouble>>(detPtrVariant) &&
4752 !std::holds_alternative<boost::shared_ptr<MatrixDouble>>(detPtrVariant)) {
4753 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
4754 "detPtrVariant must hold either VectorDouble or MatrixDouble");
4755 }
4756#endif
4757 const auto nb_integration_pts = inPtr->size1();
4758
4759#ifndef NDEBUG
4760 const auto nb_rows = inPtr->size2();
4761 if (nb_rows != DIM * DIM)
4762 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
4763 "Wrong number of matrix coefficients");
4764#endif
4765
4766 std::visit(
4767 [&](auto ptr) {
4768 using T = std::decay_t<decltype(ptr)>;
4769
4770 if constexpr (std::is_same_v<T, boost::shared_ptr<VectorDouble>>) {
4771 ptr->resize(nb_integration_pts, false);
4772 } else if constexpr (std::is_same_v<T, boost::shared_ptr<MatrixDouble>>) {
4773 ptr->resize(nb_integration_pts, 1, false);
4774 }
4775 },
4776 detPtrVariant);
4777
4779 auto get_in_at_pts =
4780 MatrixSizeHelper<GetFTensor2FromMatType<DIM, DIM, -1, DL>, DL>::get(
4781 *inPtr, nb_integration_pts);
4782
4783 // Calculate determinant
4784 {
4785 auto t_in_at_pts = get_in_at_pts();
4786 auto det_it = std::visit(
4787 [](auto p) -> std::vector<double>::iterator {
4788 return p->data().begin();
4789 },
4790 detPtrVariant);
4791 for (size_t gg = 0; gg != nb_integration_pts; ++gg) {
4792 *det_it = determinantTensor(t_in_at_pts);
4793 ++t_in_at_pts;
4794 ++det_it;
4795 }
4796 }
4797
4798 // Invert jacobian
4799 if (outPtr) {
4800 auto get_out_at_pts =
4801 MatrixSizeHelper<GetFTensor2FromMatType<DIM, DIM, -1, DL>, DL>::size(
4802 *outPtr, nb_integration_pts);
4803 auto t_in_at_pts = get_in_at_pts();
4804 auto t_out_at_pts = get_out_at_pts();
4805 auto det_it = std::visit(
4806 [](auto p) -> std::vector<double>::iterator {
4807 return p->data().begin();
4808 },
4809 detPtrVariant);
4810 for (size_t gg = 0; gg != nb_integration_pts; ++gg) {
4811 CHKERR invertTensor(t_in_at_pts, *det_it, t_out_at_pts);
4812 ++t_in_at_pts;
4813 ++t_out_at_pts;
4814 ++det_it;
4815 }
4816 }
4817
4819}
4820
4821/**@}*/
4822
4823/**
4824 * @brief Operator for calculating the trace of matrices at integration points
4825 *
4826 * This template structure computes the trace (sum of diagonal elements) of
4827 * square matrices at integration points. The trace is commonly used in
4828 * mechanics for calculating volumetric strain, pressure, and other scalar
4829 * quantities derived from tensors.
4830 *
4831 * @tparam DIM Dimension of the square matrix
4832 *
4833 * @ingroup mofem_forces_and_sources
4834 */
4835template <int DIM>
4837
4838 /**
4839 * @brief Constructor for matrix trace calculation operator
4840 *
4841 * @param in_ptr Shared pointer to input matrix for trace calculation
4842 * @param out_ptr Shared pointer to output vector for storing calculated traces
4843 */
4844 OpCalculateTraceFromMat(boost::shared_ptr<MatrixDouble> in_ptr,
4845 boost::shared_ptr<VectorDouble> out_ptr)
4847 outPtr(out_ptr) {}
4848
4849 MoFEMErrorCode doWork(int side, EntityType type,
4851
4852private:
4854 boost::shared_ptr<MatrixDouble> inPtr;
4855 boost::shared_ptr<VectorDouble> outPtr;
4856};
4857
4858template <int DIM>
4863
4864 if (!inPtr)
4865 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
4866 "Pointer for inPtr matrix not allocated");
4867
4868 const auto nb_integration_pts = inPtr->size1();
4869 // Invert jacobian
4870 if (outPtr) {
4872 auto get_in_at_pts =
4873 MatrixSizeHelper<GetFTensor2FromMatType<DIM, DIM, -1, DL>, DL>::get(
4874 *inPtr, nb_integration_pts);
4875 outPtr->resize(nb_integration_pts, false);
4876 auto t_in_at_pts = get_in_at_pts();
4877 auto t_out = getFTensor0FromVec(*outPtr);
4878
4879 for (size_t gg = 0; gg != nb_integration_pts; ++gg) {
4880 t_out = t_in_at_pts(i, i);
4881 ++t_in_at_pts;
4882 ++t_out;
4883 }
4884 }
4885
4887}
4888
4889/**@}*/
4890
4891/** \brief Calculates the trace of an input matrix
4892
4893\ingroup mofem_forces_and_sources
4894
4895*/
4896
4897template <int DIM>
4900
4901 OpCalculateTraceFromSymmMat(boost::shared_ptr<MatrixDouble> in_ptr,
4902 boost::shared_ptr<VectorDouble> out_ptr)
4904 outPtr(out_ptr) {}
4905
4906 MoFEMErrorCode doWork(int side, EntityType type,
4908
4909private:
4911 boost::shared_ptr<MatrixDouble> inPtr;
4912 boost::shared_ptr<VectorDouble> outPtr;
4913};
4914
4915template <int DIM>
4920
4921 if (!inPtr)
4922 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
4923 "Pointer for inPtr matrix not allocated");
4924
4925 const auto nb_integration_pts = inPtr->size1();
4926 // Invert jacobian
4927 if (outPtr) {
4928 outPtr->resize(nb_integration_pts, false);
4930 auto get_in_at_pts =
4932 DL>::get(*inPtr, nb_integration_pts);
4933 auto t_in_at_pts = get_in_at_pts();
4934 auto t_out = getFTensor0FromVec(*outPtr);
4935
4936 for (size_t gg = 0; gg != nb_integration_pts; ++gg) {
4937 t_out = t_in_at_pts(i, i);
4938 ++t_in_at_pts;
4939 ++t_out;
4940 }
4941 }
4942
4944}
4945
4946} // namespace MoFEM
4947
4948#endif // __USER_DATA_OPERATORS_HPP__
4949
4950/**
4951 * \defgroup mofem_forces_and_sources_user_data_operators Users Operators
4952 *
4953 * \brief Classes and functions used to evaluate fields at integration pts,
4954 *jacobians, etc..
4955 *
4956 * \ingroup mofem_forces_and_sources
4957 **/
std::string type
PetscInt size
#define FTENSOR_INDEXES(DIM,...)
std::string name
constexpr int SPACE_DIM
Kronecker Delta class symmetric.
Tensor1< T, Tensor_Dim > normalize()
#define MAX_DOFS_ON_ENTITY
Maximal number of DOFs on entity.
static const char *const CoordinateTypesNames[]
Coordinate system names.
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
FieldSpace
approximation spaces
Definition definitions.h:82
@ L2
field with C-1 continuity
Definition definitions.h:88
@ H1
continuous field
Definition definitions.h:85
@ NOSPACE
Definition definitions.h:83
@ HCURL
field with continuous tangents
Definition definitions.h:86
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_DATA_INCONSISTENCY
Definition definitions.h:31
@ MOFEM_NOT_IMPLEMENTED
Definition definitions.h:32
CoordinateTypes
Coodinate system.
@ CYLINDRICAL
@ POLAR
@ CARTESIAN
@ SPHERICAL
#define DEPRECATED
Definition definitions.h:17
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
#define MoFEMFunctionBeginHot
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#define THROW_MESSAGE(msg)
Throw MoFEM exception.
constexpr int BASE_DIM
PetscErrorCode DMMoFEMGetProblemPtr(DM dm, const MoFEM::Problem **problem_ptr)
Get pointer to problem data structure.
Definition DMMoFEM.cpp:451
NumeredDofEntity_multiIndex::index< Unique_mi_tag >::type NumeredDofEntityByUId
Numbered DoF multi-index by UId.
#define MOFEM_LOG(channel, severity)
Log.
#define MOFEM_LOG_CHANNEL(channel)
Set and reset channel.
FTensor::Index< 'i', SPACE_DIM > i
FTensor::Index< 'J', DIM1 > J
Definition level_set.cpp:30
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
UBlasMatrix< double > MatrixDouble
Definition Types.hpp:77
VecAllocator< double > DoubleAllocator
Definition Types.hpp:62
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
decltype(GetFTensor2SymmetricFromMatImpl< Tensor_Dim, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor2SymmetricFromMatType
static auto getFTensor3DgFromMat(M &data)
Get symmetric tensor rank 3 on the first two indices from form data matrix.
static MoFEMErrorCode invertTensor(FTensor::Tensor2< T1, DIM, DIM > &t, T2 &det, FTensor::Tensor2< T3, DIM, DIM > &inv_t)
static auto determinantTensor(FTensor::Tensor2< T, DIM, DIM > &t)
Calculate the determinant of a tensor of rank DIM.
OpCalculateScalarFieldValuesFromPetscVecImpl< PetscData::CTX_SET_X_T > OpCalculateScalarFieldValuesDot
decltype(GetFTensor1FromMatImpl< Tensor_Dim, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor1FromMatType
static auto getFTensor0FromVec(V &data)
Get tensor rank 0 (scalar) form data vector.
decltype(GetFTensor3FromMatImpl< Tensor_Dim0, Tensor_Dim1, Tensor_Dim2, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor3FromMatType
decltype(GetFTensor2FromMatImpl< Tensor_Dim0, Tensor_Dim1, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor2FromMatType
constexpr IntegrationType I
constexpr AssemblyType A
double scale
Definition plastic.cpp:124
constexpr auto field_name
multi_index_container< DofsSideMapData, indexed_by< ordered_non_unique< tag< TypeSide_mi_tag >, composite_key< DofsSideMapData, member< DofsSideMapData, EntityType, &DofsSideMapData::type >, member< DofsSideMapData, int, &DofsSideMapData::side > > >, ordered_unique< tag< EntDofIdx_mi_tag >, member< DofsSideMapData, int, &DofsSideMapData::dof > > > > DofsSideMap
Map entity stype and side to element/entity dof index.
std::array< bool, MBMAXTYPE > doEntities
If true operator is executed for entity.
virtual MoFEMErrorCode doWork(int row_side, int col_side, EntityType row_type, EntityType col_type, EntitiesFieldData::EntData &row_data, EntitiesFieldData::EntData &col_data)
Operator for bi-linear form, usually to calculate values on left hand side.
Data on single entity (This is passed as argument to DataOperator::doWork)
FTensor::Tensor2< FTensor::PackPtr< double *, Tensor_Dim0 *Tensor_Dim1 >, Tensor_Dim0, Tensor_Dim1 > getFTensor2DiffN(FieldApproximationBase base)
Get derivatives of base functions for Hdiv space.
auto getFTensor2SymmetricFieldData()
Return symmetric FTensor rank 2, i.e. matrix from field data coefficients.
auto getFTensor2FieldData()
Return FTensor rank 2, i.e. matrix from field data coefficients.
FTensor::Tensor0< FTensor::PackPtr< double *, 1 > > getFTensor0N(const FieldApproximationBase base)
Get base function as Tensor0.
MatrixDouble & getDiffN(const FieldApproximationBase base)
get derivatives of base functions
const VectorFieldEntities & getFieldEntities() const
Get field entities (const version)
auto getFTensor1FieldData()
Return FTensor of rank 1, i.e. vector from field data coefficients.
auto getFTensor2N(FieldApproximationBase base)
Get base functions for Hdiv/Hcurl spaces.
auto getFTensor1DiffN(const FieldApproximationBase base)
Get derivatives of base functions.
MatrixDouble & getN(const FieldApproximationBase base)
get base functions this return matrix (nb. of rows is equal to nb. of Gauss pts, nb....
const VectorDouble & getFieldData() const
Get DOF values on entity.
FTensor::Tensor3< FTensor::PackPtr< double *, Tensor_Dim0 *Tensor_Dim1 *Tensor_Dim2 >, Tensor_Dim0, Tensor_Dim1, Tensor_Dim2 > getFTensor3Diff2N(FieldApproximationBase base)
Get second derivatives of base functions for Hvec space.
const VectorInt & getLocalIndices() const
Get local indices of degrees of freedom on entity.
auto getFTensor1N(FieldApproximationBase base)
Get base functions for Hdiv/Hcurl spaces.
FTensor::Tensor0< FTensor::PackPtr< double *, 1 > > getFTensor0FieldData()
Return scalar files as a FTensor of rank 0.
const VectorDofs & getFieldDofs() const
Get DOF data structures (const version)
const VectorInt & getIndices() const
Get global indices of degrees of freedom on entity.
FTensor::Tensor3< FTensor::PackPtr< double *, Tensor_Dim0 *Tensor_Dim1 *Tensor_Dim2 >, Tensor_Dim0, Tensor_Dim1, Tensor_Dim2 > getFTensor3DiffN(FieldApproximationBase base)
Get derivatives of base functions for tonsorial Hdiv space.
EntityType getFEType() const
Get dimension of finite element.
auto getFTensor1CoordsAtGaussPts()
Get coordinates at integration points assuming linear geometry.
EntityHandle getSideEntity(const int side_number, const EntityType type)
Get the side entity.
OpType
Controls loop over entities on element.
@ OPCOL
operator doWork function is executed on FE columns
@ OPROW
operator doWork function is executed on FE rows
@ OPSPACE
operator do Work is execute on space data
const FEMethod * getFEMethod() const
Return raw pointer to Finite Element Method object.
MatrixDouble & getGaussPts()
matrix of integration (Gauss) points for Volume Element
structure to get information from mofem into EntitiesFieldData
Calculate divergence of tonsorial field using vectorial base.
OpCalculateBrokenHVecTensorDivergence(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, SmartPetscObj< Vec > data_vec, EntityType broken_type, boost::shared_ptr< Range > broken_range_ptr=nullptr, boost::shared_ptr< double > scale_ptr=nullptr, const EntityType zero_type=MBEDGE)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
Get tensor field for H-div approximation.
boost::shared_ptr< MatrixDouble > dataPtr
OpCalculateBrokenHVecTensorField(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, SmartPetscObj< Vec > data_vec, EntityType broken_type, boost::shared_ptr< Range > broken_range_ptr=nullptr, boost::shared_ptr< double > scale_ptr=nullptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Calculate values of vector field at integration points.
Calculate divergence of vector field at integration points.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpCalculateDivergenceVectorFieldValues(const std::string field_name, boost::shared_ptr< VectorDouble > data_ptr, const EntityType zero_type=MBVERTEX)
Constructor for vector field divergence calculation operator.
Approximate tensor field values for a given PETSc vector on a tensor basis.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpCalculateHTensorTensorFieldFromPetscVecImpl(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0, bool throw_error=true)
Calculate tenor field using tensor base, i.e. Hdiv/Hcurl.
VectorDouble dotVector
Keeps temporary values of time derivatives.
OpCalculateHTensorTensorField(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, boost::shared_ptr< double > scale_ptr, SmartPetscObj< Vec > data_vec=SmartPetscObj< Vec >(), const EntityType zero_type=MBEDGE, const int zero_side=0)
boost::shared_ptr< MatrixDouble > dataPtr
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpCalculateHTensorTensorField(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
Calculate divergence of tonsorial field using vectorial base.
boost::shared_ptr< MatrixDouble > dataPtr
VectorDouble dotVector
Keeps temporary values of time derivatives.
OpCalculateHVecTensorDivergence(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, SmartPetscObj< Vec > data_vec, const EntityType zero_type=MBEDGE, const int zero_side=0)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpCalculateHVecTensorDivergence(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
Approximate Hdiv/Hcurl tensor field values for a given PETSc vector.
OpCalculateHVecTensorFieldFromPetscVecImpl(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
Calculate tenor field using vectorial base, i.e. Hdiv/Hcurl.
OpCalculateHVecTensorField(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, boost::shared_ptr< double > scale_ptr, SmartPetscObj< Vec > data_vec=SmartPetscObj< Vec >(), const EntityType zero_type=MBEDGE, const int zero_side=0)
boost::shared_ptr< MatrixDouble > dataPtr
OpCalculateHVecTensorField(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
VectorDouble dotVector
Keeps temporary values of time derivatives.
boost::shared_ptr< double > scalePtr
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpCalculateHVecTensorGradient(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
OpCalculateHVecTensorGradient(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
Calculate gradient of tensor field.
Calculate trace of vector (Hdiv/Hcurl) space.
boost::shared_ptr< MatrixDouble > dataPtr
boost::shared_ptr< double > scalePtr
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
OpCalculateHVecTensorTrace(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
FTensor::Index< 'j', Tensor_Dim > j
FTensor::Index< 'i', Tensor_Dim > i
OpCalculateHVecTensorTrace(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, boost::shared_ptr< double > scale_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
OpCalculateHVecVectorFieldDot(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
Get vector field for H-div approximation.
OpCalculateHVecVectorField_General(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
OpCalculateHVecVectorField_General(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, SmartPetscObj< Vec > data_vec, const EntityType zero_type=MBEDGE, const int zero_side=0)
Get vector field for H-div approximation.
Get vector field for H-div approximation.
Calculate gradient of vector field.
boost::shared_ptr< MatrixDouble > dataPtr
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpCalculateHVecVectorGradient(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
Calculate gradient of vector field.
boost::shared_ptr< MatrixDouble > dataPtr
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpCalculateHVecVectorHessian(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
boost::shared_ptr< MatrixDouble > dataPtr
boost::shared_ptr< MatrixDouble > dataPtr
boost::shared_ptr< MatrixDouble > dataPtr
Calculate curl of vector field.
Calculate divergence of vector field dot.
boost::shared_ptr< VectorDouble > dataPtr
OpCalculateHdivVectorDivergenceDot(const std::string field_name, boost::shared_ptr< VectorDouble > data_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
Calculate divergence of vector field.
boost::shared_ptr< VectorDouble > dataPtr
OpCalculateHdivVectorDivergence(const std::string field_name, boost::shared_ptr< VectorDouble > data_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
Calculate inverse of jacobian for face element.
OpCalculateInvJacForFatPrism(MatrixDouble &inv_jac)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpCalculateInvJacForFatPrism(boost::shared_ptr< MatrixDouble > inv_jac_ptr)
const boost::shared_ptr< MatrixDouble > invJacPtr
Calculate inverse of jacobian for face element.
OpCalculateInvJacForFlatPrism(MatrixDouble &inv_jac_f3)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
Evaluate field gradient values for scalar field, i.e. gradient is tensor rank 1 (vector)
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Evaluate field gradient values for scalar field, i.e. gradient is tensor rank 1 (vector),...
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
calculate gradient values of scalar field at integration points
Calculate scalar field values from PETSc vector at integration points.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpCalculateScalarFieldValuesFromPetscVecImpl(const std::string field_name, boost::shared_ptr< VectorDouble > data_ptr, const EntityType zero_at_type=MBVERTEX)
Constructor for PETSc vector-based scalar field calculation.
Scalar field values at integration points.
OpCalculateScalarFieldValues_General(const std::string field_name, boost::shared_ptr< ublas::vector< T, A > > data_ptr, SmartPetscObj< Vec > data_vec, const EntityType zero_type=MBVERTEX)
OpCalculateScalarFieldValues_General(SmartPetscObj< DM > data_dm, const ForcesAndSourcesCore::UserDataOperator::OpType op_type, const std::string field_name, boost::shared_ptr< ublas::vector< T, A > > data_ptr, SmartPetscObj< Vec > data_vec, const EntityType zero_type=MBVERTEX)
Constructor with PETSc vector support for a different problem layout.
boost::shared_ptr< ublas::vector< T, A > > dataPtr
OpCalculateScalarFieldValues_General(const ForcesAndSourcesCore::UserDataOperator::OpType op_type, const std::string field_name, boost::shared_ptr< ublas::vector< T, A > > data_ptr, SmartPetscObj< Vec > data_vec, const EntityType zero_type=MBVERTEX)
Constructor with PETSc vector support.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
calculate values of scalar field at integration points
OpCalculateScalarFieldValues_General(const std::string field_name, boost::shared_ptr< ublas::vector< T, A > > data_ptr, const EntityType zero_type=MBVERTEX)
Constructor for scalar field values calculation operator.
Specialization for double precision scalar field values calculation.
MoFEMErrorCode doWork(int, EntityType type, EntitiesFieldData::EntData &data)
calculate values of scalar field at integration points
Get time direvarive values at integration pts for tensor field rank 2, i.e. matrix field.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpCalculateTensor2FieldValuesDot(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_at_type=MBVERTEX)
EntityType zeroAtType
Zero values at Gauss point at this type.
VectorDouble dotVector
Keeps temporary values of time derivatives.
boost::shared_ptr< MatrixDouble > dataPtr
Data computed into this matrix.
OpCalculateTensor2FieldValues_General(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBVERTEX)
OpCalculateTensor2FieldValues_General(ForcesAndSourcesCore::UserDataOperator::OpType op_type, const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, SmartPetscObj< Vec > data_vec, const EntityType zero_type=MBVERTEX)
OpCalculateTensor2FieldValues_General(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, SmartPetscObj< Vec > data_vec, const EntityType zero_type=MBVERTEX)
Calculate field values for tenor field rank 2.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpCalculateTensor2FieldValues_General(const std::string field_name, boost::shared_ptr< M > data_ptr, const EntityType zero_type=MBVERTEX)
Get values at integration pts for tensor field rank 2, i.e. matrix field.
OpCalculateTensor2SymmetricDeviatorFieldValues_General(const std::string field_name, MatrixPtr data_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
OpCalculateTensor2SymmetricDeviatorFieldValues_General(SmartPetscObj< DM > data_dm, const ForcesAndSourcesCore::UserDataOperator::OpType op_type, const std::string field_name, MatrixPtr data_ptr, SmartPetscObj< Vec > data_vec, const EntityType zero_type=MBEDGE, const int zero_side=0, MatrixPtr coordinates=nullptr)
OpCalculateTensor2SymmetricDeviatorFieldValues_General(const std::string field_name, MatrixPtr data_ptr, SmartPetscObj< Vec > data_vec, const EntityType zero_type=MBEDGE, const int zero_side=0, MatrixPtr coordinates=nullptr)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data) override
Operator for linear form, usually to calculate values on right hand side.
OpCalculateTensor2SymmetricFieldGradient_General(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBVERTEX)
Evaluate field gradient values for symmetric 2nd order tensor field, i.e. gradient is tensor rank 3.
OpCalculateTensor2SymmetricFieldGradient_General(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBVERTEX)
Get field gradients at integration pts for symmetric tensorial field rank 2.
OpCalculateTensor2SymmetricFieldGradient(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBVERTEX)
Calculate symmetric tensor field rates ant integratio pts.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpCalculateTensor2SymmetricFieldValuesDot(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
Calculate symmetric tensor field values at integration pts.
OpCalculateTensor2SymmetricFieldValues(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, SmartPetscObj< Vec > data_vec, const EntityType zero_type=MBEDGE, const int zero_side=0)
OpCalculateTensor2SymmetricFieldValues(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBEDGE, const int zero_side=0)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpCalculateTensor2SymmetricFieldValues(SmartPetscObj< DM > data_dm, const ForcesAndSourcesCore::UserDataOperator::OpType op_type, const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, SmartPetscObj< Vec > data_vec, const EntityType zero_type=MBEDGE, const int zero_side=0)
Operator for calculating the trace of matrices at integration points.
boost::shared_ptr< MatrixDouble > inPtr
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
boost::shared_ptr< VectorDouble > outPtr
OpCalculateTraceFromMat(boost::shared_ptr< MatrixDouble > in_ptr, boost::shared_ptr< VectorDouble > out_ptr)
Constructor for matrix trace calculation operator.
Calculates the trace of an input matrix.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
boost::shared_ptr< VectorDouble > outPtr
boost::shared_ptr< MatrixDouble > inPtr
OpCalculateTraceFromSymmMat(boost::shared_ptr< MatrixDouble > in_ptr, boost::shared_ptr< VectorDouble > out_ptr)
Get field gradients time derivative at integration pts for scalar field rank 0, i....
boost::shared_ptr< MatrixDouble > dataPtr
Data computed into this matrix.
OpCalculateVectorFieldGradientDot(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_at_type=MBVERTEX)
EntityType zeroAtType
Zero values at Gauss point at this type.
VectorDouble dotVector
Keeps temporary values of time derivatives.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
Evaluate field gradient values for vector field, i.e. gradient is tensor rank 2.
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
calculate values of vector field at integration points
Approximate field values for given petsc vector.
OpCalculateVectorFieldValuesFromPetscVecImpl(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_at_type=MBVERTEX, bool throw_error=true)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpCalculateVectorFieldValues_General(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, SmartPetscObj< Vec > data_vec, const EntityType zero_type=MBVERTEX, const int max_order=-1)
OpCalculateVectorFieldValues_General(const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, const EntityType zero_type=MBVERTEX, const int max_order=-1)
OpCalculateVectorFieldValues_General(SmartPetscObj< DM > data_dm, const ForcesAndSourcesCore::UserDataOperator::OpType op_type, const std::string field_name, boost::shared_ptr< MatrixDouble > data_ptr, SmartPetscObj< Vec > data_vec, const EntityType zero_type=MBVERTEX, const int max_order=-1)
Calculate field values for tensor field rank 1, i.e. vector field.
OpCalculateVectorFieldValues_General(const std::string field_name, boost::shared_ptr< M > data_ptr, const EntityType zero_type=MBVERTEX)
Constructor for vector field values calculation operator.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
calculate values of vector field at integration points
Specialization for MatrixDouble vector field values calculation.
Operator for inverting matrices at integration points.
OpInvertMatrix(boost::shared_ptr< MatrixDouble > in_ptr, boost::shared_ptr< T > det_ptr, boost::shared_ptr< MatrixDouble > out_ptr)
Constructor for matrix inversion operator.
boost::shared_ptr< MatrixDouble > outPtr
boost::shared_ptr< MatrixDouble > inPtr
std::variant< boost::shared_ptr< VectorDouble >, boost::shared_ptr< MatrixDouble > > detPtrVariant
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
Make Hdiv space from Hcurl space in 2d.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
Operator for fat prism element updating integration weights in the volume.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
Operator for scaling matrix values by a scalar factor.
boost::shared_ptr< MatrixDouble > outMat
DEPRECATED OpScaleMatrix(const std::string field_name, const double scale, boost::shared_ptr< MatrixDouble > in_mat, boost::shared_ptr< MatrixDouble > out_mat)
boost::shared_ptr< double > scalePtr
OpScaleMatrix(boost::shared_ptr< double > scale_ptr, boost::shared_ptr< MatrixDouble > in_mat, boost::shared_ptr< MatrixDouble > out_mat)
Constructor for matrix scaling operator.
boost::shared_ptr< MatrixDouble > inMat
MoFEMErrorCode doWork(int, EntityType, EntData &)
Operator for linear form, usually to calculate values on right hand side.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpSetContravariantPiolaTransformOnEdge2D(const FieldSpace space=HCURL)
OpSetContravariantPiolaTransformOnFace2DImpl(boost::shared_ptr< MatrixDouble > jac_ptr)
Apply contravariant (Piola) transfer to Hdiv space on face.
Apply contravariant (Piola) transfer to Hdiv space on face.
Transform Hcurl base fluxes from reference element to physical triangle.
OpSetInvJacH1ForFaceEmbeddedIn3DSpace(boost::shared_ptr< MatrixDouble > inv_jac_ptr)
OpSetInvJacH1ForFace(boost::shared_ptr< MatrixDouble > inv_jac_ptr)
Transform local reference derivatives of shape functions to global derivatives.
const boost::shared_ptr< MatrixDouble > invJacPtr
OpSetInvJacH1ForFatPrism(MatrixDouble &inv_jac)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpSetInvJacH1ForFatPrism(boost::shared_ptr< MatrixDouble > inv_jac_ptr)
Transform local reference derivatives of shape functions to global derivatives.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpSetInvJacH1ForFlatPrism(MatrixDouble &inv_jac_f3)
boost::shared_ptr< MatrixDouble > invJacPtr
OpSetInvJacHcurlFaceImpl(boost::shared_ptr< MatrixDouble > inv_jac_ptr)
Transform local reference derivatives of shape function to global derivatives for face.
OpSetInvJacL2ForFaceEmbeddedIn3DSpace(boost::shared_ptr< MatrixDouble > inv_jac_ptr)
OpSetInvJacL2ForFace(boost::shared_ptr< MatrixDouble > inv_jac_ptr)
Transform local reference derivatives of shape functions to global derivatives.
MoFEMErrorCode applyTransform(MatrixDouble &diff_n)
Apply transformation to the input matrix.
OpSetInvJacToScalarBasesBasic(FieldSpace space, boost::shared_ptr< MatrixDouble > inv_jac_ptr)
boost::shared_ptr< MatrixDouble > invJacPtr
Operator for symmetrizing tensor fields.
FTensor::Index< 'i', DIM > i
boost::shared_ptr< MatrixDouble > outMat
OpSymmetrizeTensor(boost::shared_ptr< MatrixDouble > in_mat, boost::shared_ptr< MatrixDouble > out_mat)
Constructor for tensor symmetrization operator.
MoFEMErrorCode doWork(int, EntityType, EntData &)
Operator for linear form, usually to calculate values on right hand side.
FTensor::Index< 'j', DIM > j
DEPRECATED OpSymmetrizeTensor(const std::string field_name, boost::shared_ptr< MatrixDouble > in_mat, boost::shared_ptr< MatrixDouble > out_mat)
boost::shared_ptr< MatrixDouble > inMat
boost::shared_ptr< MatrixDouble > dMat
OpTensorTimesSymmetricTensor(boost::shared_ptr< MatrixDouble > in_mat, boost::shared_ptr< MatrixDouble > out_mat, boost::shared_ptr< MatrixDouble > d_mat)
boost::shared_ptr< MatrixDouble > inMat
MoFEMErrorCode doWork(int, EntityType, EntData &)
Operator for linear form, usually to calculate values on right hand side.
DEPRECATED OpTensorTimesSymmetricTensor(const std::string field_name, boost::shared_ptr< MatrixDouble > in_mat, boost::shared_ptr< MatrixDouble > out_mat, boost::shared_ptr< MatrixDouble > d_mat)
boost::shared_ptr< MatrixDouble > outMat
static constexpr Switches CtxSetX
Solution vector switch.
static constexpr Switches CtxSetX_TT
Second time derivative switch.
std::bitset< 8 > Switches
Bitset type for context switches.
static constexpr Switches CtxSetX_T
First time derivative switch.
@ CTX_SET_X_T
Time derivative X_t is set.
@ CTX_SET_DX
Solution increment DX is set.
@ CTX_SET_X
Solution vector X is set.
@ CTX_SET_X_TT
Second time derivative X_tt is set.
keeps basic data about problem
boost::shared_ptr< NumeredDofEntity_multiIndex > numeredRowDofsPtr
store DOFs on rows for this problem
boost::shared_ptr< NumeredDofEntity_multiIndex > numeredColDofsPtr
store DOFs on columns for this problem
intrusive_ptr for managing petsc objects
static FTensor::Tensor2_symmetric< double, 3 > getTensor(const FTensor::Tensor1< T, Size > &t_coordinates, const double theta=0.)
Reconstruct D + theta*I/3; input may be an owning tensor or a view.
static FTensor::Tensor1< double, 5 > getCoordinates(const Tensor &t_tensor)
Project a full or symmetric tensor onto the five orthonormal columns.
static const FTensor::Dg< double, 3, 5 > & getBasis()
Basis columns (11-22)/sqrt(2), (11+22-2*33)/sqrt(6), 12, 13, 23.