v0.16.0
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
93 const std::string field_name,
94 boost::shared_ptr<ublas::vector<T, A>> data_ptr,
95 SmartPetscObj<Vec> data_vec, const EntityType zero_type = MBVERTEX)
98 data_vec, zero_type) {}
99
100 /**
101 * @brief Constructor for scalar field values calculation operator
102 *
103 * @param field_name Name of the scalar field to calculate values for
104 * @param data_ptr Shared pointer to ublas vector for storing calculated values
105 * @param zero_type Entity type for zero-level entities (default: MBVERTEX)
106 */
108 const std::string field_name,
109 boost::shared_ptr<ublas::vector<T, A>> data_ptr,
110 const EntityType zero_type = MBVERTEX)
113 SmartPetscObj<Vec>(), zero_type) {}
114
115 /**
116 * \brief calculate values of scalar field at integration points
117 * @param side side entity number
118 * @param type side entity type
119 * @param data entity data
120 * @return error code
121 */
122 MoFEMErrorCode doWork(int side, EntityType type,
124
125protected:
126 boost::shared_ptr<ublas::vector<T, A>> dataPtr;
130};
131
132/**
133 * \brief Specialization of member function
134 *
135 */
136template <class T, class A>
138 int side, EntityType type, EntitiesFieldData::EntData &data) {
140 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED, "Not implemented for T = %s",
141 typeid(T).name() // boost::core::demangle(typeid(T).name()).c_str()
142 );
144}
145
146/**
147 * @brief Specialization for double precision scalar field values calculation
148 *
149 * This structure is a specialization of OpCalculateScalarFieldValues_General
150 * for double precision scalar fields using DoubleAllocator. It provides
151 * concrete implementation for calculating scalar field values at integration
152 * points and storing them in double precision format.
153 *
154 * @ingroup mofem_forces_and_sources_user_data_operators
155 */
157 : public OpCalculateScalarFieldValues_General<double, DoubleAllocator> {
158
160 double, DoubleAllocator>::OpCalculateScalarFieldValues_General;
161
162 /**
163 * \brief calculate values of scalar field at integration points
164 * @param side side entity number
165 * @param type side entity type
166 * @param data entity data
167 * @return error code
168 */
169 MoFEMErrorCode doWork(int, EntityType type,
172 VectorDouble &vec = *dataPtr;
173 const size_t nb_gauss_pts = getGaussPts().size2();
174 if (type == zeroType || vec.size() != nb_gauss_pts) {
175 vec.resize(nb_gauss_pts, false);
176 vec.clear();
177 }
178
179 const size_t nb_dofs = data.getFieldData().size();
180
181 if (nb_dofs) {
182
183 if (dataVec.use_count()) {
184 dotVector.resize(nb_dofs, false);
185 const double *array;
186 CHKERR VecGetArrayRead(dataVec, &array);
187 const auto &local_indices = data.getLocalIndices();
188 for (size_t i = 0; i != local_indices.size(); ++i)
189 if (local_indices[i] != -1)
190 dotVector[i] = array[local_indices[i]];
191 else
192 dotVector[i] = 0;
193 CHKERR VecRestoreArrayRead(dataVec, &array);
194 data.getFieldData().swap(dotVector);
195 }
196
197 const size_t nb_base_functions = data.getN().size2();
198 auto base_function = data.getFTensor0N();
199 auto values_at_gauss_pts = getFTensor0FromVec(vec);
200 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
201 auto field_data = data.getFTensor0FieldData();
202 size_t bb = 0;
203 for (; bb != nb_dofs; ++bb) {
204 values_at_gauss_pts += field_data * base_function;
205 ++field_data;
206 ++base_function;
207 }
208 // It is possible to have more base functions than dofs
209 for (; bb < nb_base_functions; ++bb)
210 ++base_function;
211 ++values_at_gauss_pts;
212 }
213
214 if (dataVec.use_count()) {
215 data.getFieldData().swap(dotVector);
216 }
217 }
218
220 }
221};
222
223/**
224 * @brief Calculate scalar field values from PETSc vector at integration points
225 *
226 * This template structure extracts scalar field values from a PETSc vector
227 * and calculates them at integration points. It supports different data contexts
228 * through the template parameter and can handle various entity types.
229 *
230 * @tparam CTX PETSc data context type specifying how data is accessed
231 *
232 * @ingroup mofem_forces_and_sources_user_data_operators
233 */
234template <PetscData::DataContext CTX>
237
238 /**
239 * @brief Constructor for PETSc vector-based scalar field calculation
240 *
241 * @param field_name Name of the scalar field to extract values from
242 * @param data_ptr Shared pointer to VectorDouble for storing calculated values
243 * @param zero_at_type Entity type where values should be zeroed (default: MBVERTEX)
244 */
246 const std::string field_name, boost::shared_ptr<VectorDouble> data_ptr,
247 const EntityType zero_at_type = MBVERTEX)
250 dataPtr(data_ptr), zeroAtType(zero_at_type) {
251 if (!dataPtr)
252 THROW_MESSAGE("Pointer is not set");
253 }
254
255 MoFEMErrorCode doWork(int side, EntityType type,
258
259 const size_t nb_gauss_pts = getGaussPts().size2();
260
261 VectorDouble &vec = *dataPtr;
262 if (type == zeroAtType || vec.size() != nb_gauss_pts) {
263 vec.resize(nb_gauss_pts, false);
264 vec.clear();
265 }
266
267 auto &local_indices = data.getLocalIndices();
268 const size_t nb_dofs = local_indices.size();
269 if (nb_dofs) {
270
271 const double *array;
272
273 auto get_array = [&](const auto ctx, auto vec) {
275 #ifndef NDEBUG
276 if ((getFEMethod()->data_ctx & ctx).none()) {
277 MOFEM_LOG_CHANNEL("SELF");
278 MOFEM_LOG("SELF", Sev::error)
279 << "In this case field degrees of freedom are read from vector. "
280 "That usually happens when time solver is used, and acces to "
281 "first or second rates is needed. You probably not set ts_u, "
282 "ts_u_t, or ts_u_tt and associated data structure, i.e. "
283 "data_ctx to CTX_SET_X, CTX_SET_X_T, or CTX_SET_X_TT "
284 "respectively";
285 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Vector not set!");
286 }
287 #endif
288 CHKERR VecGetArrayRead(vec, &array);
290 };
291
292 auto restore_array = [&](auto vec) {
293 return VecRestoreArrayRead(vec, &array);
294 };
295
296 switch (CTX) {
298 CHKERR get_array(PetscData::CtxSetX, getFEMethod()->ts_u);
299 break;
301 CHKERR get_array(PetscData::CtxSetX_T, getFEMethod()->ts_u_t);
302 break;
304 CHKERR get_array(PetscData::CtxSetX_TT, getFEMethod()->ts_u_tt);
305 break;
306 default:
307 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
308 "That case is not implemented");
309 }
310
311 std::array<double, MAX_DOFS_ON_ENTITY> dot_dofs_vector;
312 for (int i = 0; i != local_indices.size(); ++i)
313 if (local_indices[i] != -1)
314 dot_dofs_vector[i] = array[local_indices[i]];
315 else
316 dot_dofs_vector[i] = 0;
317
318 switch (CTX) {
320 CHKERR restore_array(getFEMethod()->ts_u);
321 break;
323 CHKERR restore_array(getFEMethod()->ts_u_t);
324 break;
326 CHKERR restore_array(getFEMethod()->ts_u_tt);
327 break;
328 default:
329 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
330 "That case is not implemented");
331 }
332
333 const size_t nb_base_functions = data.getN().size2();
334 auto base_function = data.getFTensor0N();
335 auto values_at_gauss_pts = getFTensor0FromVec(vec);
336
337 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
338 size_t bb = 0;
339 for (; bb != nb_dofs; ++bb) {
340 values_at_gauss_pts += dot_dofs_vector[bb] * base_function;
341 ++base_function;
342 }
343 // Number of dofs can be smaller than number of Tensor_Dim x base
344 // functions
345 for (; bb < nb_base_functions; ++bb)
346 ++base_function;
347 ++values_at_gauss_pts;
348 }
349 }
351 }
352
353private:
354 boost::shared_ptr<VectorDouble> dataPtr;
356};
357
362
363/**
364 * \deprecated Name inconsistent with other operators
365 *
366 */
368
369/**@}*/
370
371/** \name Vector field values at integration points */
372
373/**@{*/
374
375/**
376 * @brief Calculate field values for tensor field rank 1, i.e. vector field
377 *
378 * This template structure calculates vector field values at integration points
379 * and stores them in a matrix container. It supports various tensor dimensions,
380 * matrix storage types through template parameters.
381 *
382 * @tparam Tensor_Dim Dimension of the vector field (e.g., 2 for 2D, 3 for 3D)
383 * @tparam M Matrix storage type for the field values
384 */
385template <int Tensor_Dim, typename M = MatrixDouble>
388
389 /**
390 * @brief Constructor for vector field values calculation operator
391 *
392 * @param field_name Name of the vector field to calculate values for
393 * @param data_ptr Shared pointer to ublas matrix for storing calculated values
394 * @param zero_type Entity type for zero-level entities (default: MBVERTEX)
395 */
397 const std::string field_name,
398 boost::shared_ptr<M> data_ptr,
399 const EntityType zero_type = MBVERTEX)
402 dataPtr(data_ptr), zeroType(zero_type) {
403 if (!dataPtr)
404 THROW_MESSAGE("Pointer is not set");
405 }
406
407 /**
408 * \brief calculate values of vector field at integration points
409 * @param side side entity number
410 * @param type side entity type
411 * @param data entity data
412 * @return error code
413 */
414 MoFEMErrorCode doWork(int side, EntityType type,
416
417protected:
418 boost::shared_ptr<M> dataPtr;
420};
421
422template <int Tensor_Dim, typename M>
425 int side, EntityType type, EntitiesFieldData::EntData &data) {
427 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
428 "Not implemented for matrix type = %s and dim = %d",
429 typeid(M).name(), // boost::core::demangle(typeid(M).name()),
430 Tensor_Dim);
432}
433
434/** \brief Calculate field values (template specialization) for tensor field
435 * rank 1, i.e. vector field
436 *
437 */
438template <int Tensor_Dim>
441
443 boost::shared_ptr<MatrixDouble> data_ptr,
444 const EntityType zero_type = MBVERTEX,
445 const int max_order = -1)
448 dataPtr(data_ptr), zeroType(zero_type), maxOrder(max_order) {
449 if (!dataPtr)
450 THROW_MESSAGE("Pointer is not set");
451 }
452
454 boost::shared_ptr<MatrixDouble> data_ptr,
455 SmartPetscObj<Vec> data_vec,
456 const EntityType zero_type = MBVERTEX,
457 const int max_order = -1)
460 dataPtr(data_ptr), dataVec(data_vec), zeroType(zero_type),
461 maxOrder(max_order) {
462 if (!dataPtr)
463 THROW_MESSAGE("Pointer is not set");
464 }
465
466 MoFEMErrorCode doWork(int side, EntityType type,
468
469protected:
470 boost::shared_ptr<MatrixDouble> dataPtr;
474 int maxOrder = -1;
475};
476
477/**
478 * \brief Member function specialization calculating values for tenor field rank
479 *
480 */
481template <int Tensor_Dim>
483 Tensor_Dim, MatrixDouble>::doWork(int, EntityType type,
486
487 const size_t nb_gauss_pts = getGaussPts().size2();
488 auto &mat = *dataPtr;
489
491 auto get_values_at_gauss_pts =
492 MatrixSizeHelper<GetFTensor1FromMatType<Tensor_Dim, -1, DL>, DL>::size(
493 mat, nb_gauss_pts);
494 if (type == zeroType) {
495 mat.clear();
496 }
497
498 const size_t nb_dofs = data.getFieldData().size();
499 if (nb_dofs) {
500
501 auto max_order =
502 (maxOrder == -1) ? MAX_DOFS_ON_ENTITY : maxOrder;
503 const auto max_size =
504 (type == MBVERTEX) ? MAX_DOFS_ON_ENTITY
505 : data.getFieldDofs()[0]->getOrderNbDofs(max_order);
506
507 if (dataVec.use_count()) {
508 dotVector.resize(nb_dofs, false);
509 const double *array;
510 CHKERR VecGetArrayRead(dataVec, &array);
511 const auto &local_indices = data.getLocalIndices();
512 for (size_t i = 0; i != local_indices.size(); ++i)
513 if (local_indices[i] != -1)
514 dotVector[i] = array[local_indices[i]];
515 else
516 dotVector[i] = 0;
517 CHKERR VecRestoreArrayRead(dataVec, &array);
518 data.getFieldData().swap(dotVector);
519 }
520
521 if (nb_gauss_pts) {
522 const size_t nb_base_functions = data.getN().size2();
523 auto base_function = data.getFTensor0N();
524 auto t_values_at_gauss_pts = get_values_at_gauss_pts();
525 FTensor::Index<'I', Tensor_Dim> I;
526 const size_t size = nb_dofs / Tensor_Dim;
527 if (nb_dofs % Tensor_Dim) {
528 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
529 "Nb. of DOFs is inconsistent with Tensor_Dim");
530 }
531 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
532 auto field_data = data.getFTensor1FieldData<Tensor_Dim>();
533
534 #ifndef NDEBUG
535 if (field_data.l2() != field_data.l2()) {
536 MOFEM_LOG("SELF", Sev::error) << "field data: " << field_data;
537 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
538 "Wrong number in coefficients");
539 }
540 #endif
541
542 size_t bb = 0;
543 for (; bb != size; ++bb) {
544
545 #ifndef SINGULARITY
546 #ifndef NDEBUG
547 if (base_function != base_function) {
548 MOFEM_LOG("SELF", Sev::error) << "base function: " << base_function;
549 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
550 "Wrong number number in base functions");
551 }
552 #endif
553 #endif
554
555 if (bb <= max_size) {
556 t_values_at_gauss_pts(I) += field_data(I) * base_function;
557 }
558 ++field_data;
559 ++base_function;
560 }
561 // Number of dofs can be smaller than number of Tensor_Dim x base
562 // functions
563 for (; bb < nb_base_functions; ++bb)
564 ++base_function;
565 ++t_values_at_gauss_pts;
566 }
567 }
568
569 if (dataVec.use_count()) {
570 data.getFieldData().swap(dotVector);
571 }
572 }
574}
575
576/**
577 * @brief Specialization for MatrixDouble vector field values calculation
578 *
579 * This structure is a specialization of OpCalculateVectorFieldValues_General
580 * for vector fields stored in MatrixDouble. It provides a convenient interface
581 * for calculating vector field values at integration points.
582 *
583 * @tparam Tensor_Dim Dimension of the vector field (e.g., 2 for 2D, 3 for 3D)
584 *
585 * @ingroup mofem_forces_and_sources_user_data_operators
586 */
587template <int Tensor_Dim>
589 : public OpCalculateVectorFieldValues_General<Tensor_Dim> {
590
592 Tensor_Dim>::OpCalculateVectorFieldValues_General;
593};
594
595/**@}*/
596
597/** \name Vector field values at integration points */
598
599/**@{*/
600
601/**
602 * @brief Calculate divergence of vector field at integration points
603 *
604 * This template structure calculates the divergence of a vector field at
605 * integration points. It supports different coordinate systems and tensor
606 * dimensions, making it suitable for various physical applications.
607 *
608 * @tparam Tensor_Dim Dimension of the vector field (e.g., 2 for 2D, 3 for 3D)
609 * @tparam COORDINATE_SYSTEM Coordinate system type (default: CARTESIAN)
610 */
611template <int Tensor_Dim, CoordinateTypes COORDINATE_SYSTEM = CARTESIAN>
614
615 /**
616 * @brief Constructor for vector field divergence calculation operator
617 *
618 * @param field_name Name of the vector field to calculate divergence for
619 * @param data_ptr Shared pointer to VectorDouble for storing calculated divergence values
620 * @param zero_type Entity type for zero-level entities (default: MBVERTEX)
621 */
623 const std::string field_name, boost::shared_ptr<VectorDouble> data_ptr,
624 const EntityType zero_type = MBVERTEX)
627 dataPtr(data_ptr), zeroType(zero_type) {
628 if (!dataPtr)
629 THROW_MESSAGE("Pointer is not set");
630 }
631
632 MoFEMErrorCode doWork(int side, EntityType type,
635
636 // When we move to C++17 add if constexpr()
637 if constexpr (COORDINATE_SYSTEM == POLAR || COORDINATE_SYSTEM == SPHERICAL)
638 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
639 "%s coordiante not implemented",
640 CoordinateTypesNames[COORDINATE_SYSTEM]);
641
642 const size_t nb_gauss_pts = getGaussPts().size2();
643 auto &vec = *dataPtr;
644 if (type == zeroType) {
645 vec.resize(nb_gauss_pts, false);
646 vec.clear();
647 }
648
649 const size_t nb_dofs = data.getFieldData().size();
650 if (nb_dofs) {
651
652 if (nb_gauss_pts) {
653 const size_t nb_base_functions = data.getN().size2();
654 auto values_at_gauss_pts = getFTensor0FromVec(vec);
655 FTensor::Index<'I', Tensor_Dim> I;
656 const size_t size = nb_dofs / Tensor_Dim;
657 #ifndef NDEBUG
658 if (nb_dofs % Tensor_Dim) {
659 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
660 "Number of dofs should multiple of dimensions");
661 }
662 #endif
663
664 // When we move to C++17 add if constexpr()
665 if constexpr (COORDINATE_SYSTEM == CARTESIAN) {
666 auto diff_base_function = data.getFTensor1DiffN<Tensor_Dim>();
667 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
668 auto field_data = data.getFTensor1FieldData<Tensor_Dim>();
669 size_t bb = 0;
670 for (; bb != size; ++bb) {
671 values_at_gauss_pts += field_data(I) * diff_base_function(I);
672 ++field_data;
673 ++diff_base_function;
674 }
675 // Number of dofs can be smaller than number of Tensor_Dim x base
676 // functions
677 for (; bb < nb_base_functions; ++bb)
678 ++diff_base_function;
679 ++values_at_gauss_pts;
680 }
681 }
682
683 // When we move to C++17 add if constexpr()
684 if constexpr (COORDINATE_SYSTEM == CYLINDRICAL) {
685 auto t_coords = getFTensor1CoordsAtGaussPts();
686 auto values_at_gauss_pts = getFTensor0FromVec(vec);
687 auto base_function = data.getFTensor0N();
688 auto diff_base_function = data.getFTensor1DiffN<Tensor_Dim>();
689 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
690 auto field_data = data.getFTensor1FieldData<Tensor_Dim>();
691 size_t bb = 0;
692 for (; bb != size; ++bb) {
693 values_at_gauss_pts += field_data(I) * diff_base_function(I);
694 values_at_gauss_pts +=
695 base_function * (field_data(0) / t_coords(0));
696 ++field_data;
697 ++base_function;
698 ++diff_base_function;
699 }
700 // Number of dofs can be smaller than number of Tensor_Dim x base
701 // functions
702 for (; bb < nb_base_functions; ++bb) {
703 ++base_function;
704 ++diff_base_function;
705 }
706 ++values_at_gauss_pts;
707 ++t_coords;
708 }
709 }
710 }
711 }
713 }
714
715protected:
716 boost::shared_ptr<VectorDouble> dataPtr;
718};
719
720/** \brief Approximate field values for given petsc vector
721 *
722 * \note Look at PetscData to see what vectors could be extracted with that user
723 * data operator.
724 *
725 * \ingroup mofem_forces_and_sources_user_data_operators
726 */
727template <int Tensor_Dim, PetscData::DataContext CTX>
730
732 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
733 const EntityType zero_at_type = MBVERTEX, bool throw_error = true)
736 dataPtr(data_ptr), zeroAtType(zero_at_type), throwError(throw_error) {
737 if (!dataPtr)
738 THROW_MESSAGE("Pointer is not set");
739 }
740
741 MoFEMErrorCode doWork(int side, EntityType type,
744
745 auto &local_indices = data.getLocalIndices();
746 const size_t nb_dofs = local_indices.size();
747 const size_t nb_gauss_pts = getGaussPts().size2();
748
749 MatrixDouble &mat = *dataPtr;
751 auto get_values_at_gauss_pts =
752 MatrixSizeHelper<GetFTensor1FromMatType<Tensor_Dim, -1, DL>,
753 DL>::size(mat, nb_gauss_pts);
754 if (type == zeroAtType) {
755 mat.clear();
756 }
757 if (!nb_dofs)
759
760 if (!throwError) {
761 if ((getFEMethod()->data_ctx & PetscData::Switches(CTX)).none()) {
763 }
764 }
765
766 const double *array;
767
768 auto get_array = [&](const auto ctx, auto vec) {
770 #ifndef NDEBUG
771 if ((getFEMethod()->data_ctx & ctx).none()) {
772 MOFEM_LOG_CHANNEL("SELF");
773 MOFEM_LOG("SELF", Sev::error)
774 << "In this case field degrees of freedom are read from vector. "
775 "That usually happens when time solver is used, and access to "
776 "first or second rates is needed. You probably not set ts_u, "
777 "ts_u_t, or ts_u_tt and associated data structure, i.e. "
778 "data_ctx to CTX_SET_X, CTX_SET_DX, CTX_SET_X_T, or "
779 "CTX_SET_X_TT respectively";
780 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Vector not set");
781 }
782 #endif
783 CHKERR VecGetArrayRead(vec, &array);
785 };
786
787 auto restore_array = [&](auto vec) {
788 return VecRestoreArrayRead(vec, &array);
789 };
790
791 switch (CTX) {
793 CHKERR get_array(PetscData::CtxSetX, getFEMethod()->ts_u);
794 break;
796 CHKERR get_array(PetscData::CtxSetX, getFEMethod()->dx);
797 break;
799 CHKERR get_array(PetscData::CtxSetX_T, getFEMethod()->ts_u_t);
800 break;
802 CHKERR get_array(PetscData::CtxSetX_TT, getFEMethod()->ts_u_tt);
803 break;
804 default:
805 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
806 "That case is not implemented");
807 }
808
809 dotVector.resize(local_indices.size());
810 for (int i = 0; i != local_indices.size(); ++i)
811 if (local_indices[i] != -1)
812 dotVector[i] = array[local_indices[i]];
813 else
814 dotVector[i] = 0;
815
816 switch (CTX) {
818 CHKERR restore_array(getFEMethod()->ts_u);
819 break;
821 CHKERR restore_array(getFEMethod()->dx);
822 break;
824 CHKERR restore_array(getFEMethod()->ts_u_t);
825 break;
827 CHKERR restore_array(getFEMethod()->ts_u_tt);
828 break;
829 default:
830 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
831 "That case is not implemented");
832 }
833
834 const size_t nb_base_functions = data.getN().size2();
835 auto base_function = data.getFTensor0N();
836 auto t_values_at_gauss_pts = get_values_at_gauss_pts();
837
838 FTensor::Index<'I', Tensor_Dim> I;
839 const size_t size = nb_dofs / Tensor_Dim;
840 if (nb_dofs % Tensor_Dim) {
841 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Data inconsistency");
842 }
843 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
844 auto field_data = getFTensor1FromArray<Tensor_Dim, Tensor_Dim>(dotVector);
845 size_t bb = 0;
846 for (; bb != size; ++bb) {
847 t_values_at_gauss_pts(I) += field_data(I) * base_function;
848 ++field_data;
849 ++base_function;
850 }
851 // Number of dofs can be smaller than number of Tensor_Dim x base
852 // functions
853 for (; bb < nb_base_functions; ++bb)
854 ++base_function;
855 ++t_values_at_gauss_pts;
856 }
858 }
859
860protected:
861 boost::shared_ptr<MatrixDouble> dataPtr;
865};
866
867/** \brief Get rate of values at integration pts for tensor field
868 * rank 1, i.e. vector field
869 *
870 * \ingroup mofem_forces_and_sources_user_data_operators
871 */
872template <int Tensor_Dim>
876
877/** \brief Get second rate of values at integration pts for tensor
878 * field rank 1, i.e. vector field
879 *
880 * \ingroup mofem_forces_and_sources_user_data_operators
881 */
882template <int Tensor_Dim>
886
887/** \brief Get second time second update vector at integration pts for tensor
888 * field rank 1, i.e. vector field
889 *
890 * \ingroup mofem_forces_and_sources_user_data_operators
891 */
892template <int Tensor_Dim>
896
897/**@}*/
898
899/** \name Tensor field values at integration points */
900
901/**@{*/
902
903/** \brief Calculate field values for tenor field rank 2.
904 *
905 */
906template <int Tensor_Dim0, int Tensor_Dim1, typename M = MatrixDouble>
909
911 const std::string field_name,
912 boost::shared_ptr<M> data_ptr,
913 const EntityType zero_type = MBVERTEX)
916 dataPtr(data_ptr), zeroType(zero_type) {
917 if (!dataPtr)
918 THROW_MESSAGE("Pointer is not set");
919 }
920
921 MoFEMErrorCode doWork(int side, EntityType type,
923
924protected:
925 boost::shared_ptr<M> dataPtr;
927};
928
929template <int Tensor_Dim0, int Tensor_Dim1, typename M>
932 doWork(int side, EntityType type, EntitiesFieldData::EntData &data) {
934 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
935 "Not implemented for matrix type = %s, dim0 = %d and dim1 = %d",
936 typeid(M).name(), // boost::core::demangle(typeid(M).name()),
937 Tensor_Dim0, Tensor_Dim1);
939}
940
941template <int Tensor_Dim0, int Tensor_Dim1>
942struct OpCalculateTensor2FieldValues_General<Tensor_Dim0, Tensor_Dim1,
945
948 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
949 SmartPetscObj<Vec> data_vec, const EntityType zero_type = MBVERTEX)
951 dataPtr(data_ptr), zeroType(zero_type), dataVec(data_vec) {
952 if (!dataPtr)
953 THROW_MESSAGE("Pointer is not set");
954 }
955
957 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
958 const EntityType zero_type = MBVERTEX)
961 SmartPetscObj<Vec>(), zero_type) {}
962
964 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
965 SmartPetscObj<Vec> data_vec, const EntityType zero_type = MBVERTEX)
968 data_vec, zero_type) {}
969
970 MoFEMErrorCode doWork(int side, EntityType type,
972
973protected:
974 boost::shared_ptr<MatrixDouble> dataPtr;
978};
979
980template <int Tensor_Dim0, int Tensor_Dim1>
982 Tensor_Dim0, Tensor_Dim1, MatrixDouble>::doWork(
983 int side, EntityType type, EntitiesFieldData::EntData &data) {
985
987 MatrixDouble &mat = *dataPtr;
988 const size_t nb_gauss_pts = data.getN().size1();
989 auto get_values_at_gauss_pts =
990 MatrixSizeHelper<GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
991 DL>::size(mat, nb_gauss_pts);
992 if (type == zeroType)
993 mat.clear();
994
995 const size_t nb_dofs = data.getFieldData().size();
996
997 if (dataVec.use_count()) {
998 dotVector.resize(nb_dofs, false);
999 const double *array;
1000 CHKERR VecGetArrayRead(dataVec, &array);
1001 const auto &local_indices = data.getLocalIndices();
1002 for (int i = 0; i != local_indices.size(); ++i)
1003 if (local_indices[i] != -1)
1004 dotVector[i] = array[local_indices[i]];
1005 else
1006 dotVector[i] = 0;
1007 CHKERR VecRestoreArrayRead(dataVec, &array);
1008 data.getFieldData().swap(dotVector);
1009 }
1010
1011 if (nb_dofs) {
1012 const size_t nb_base_functions = data.getN().size2();
1013 auto base_function = data.getFTensor0N();
1014 auto t_values_at_gauss_pts = get_values_at_gauss_pts();
1015 FTensor::Index<'i', Tensor_Dim0> i;
1016 FTensor::Index<'j', Tensor_Dim1> j;
1017 const size_t size = nb_dofs / (Tensor_Dim0 * Tensor_Dim1);
1018 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
1019 auto field_data = data.getFTensor2FieldData<Tensor_Dim0, Tensor_Dim1>();
1020 size_t bb = 0;
1021 for (; bb != size; ++bb) {
1022 t_values_at_gauss_pts(i, j) += field_data(i, j) * base_function;
1023 ++field_data;
1024 ++base_function;
1025 }
1026 for (; bb < nb_base_functions; ++bb)
1027 ++base_function;
1028 ++t_values_at_gauss_pts;
1029 }
1030
1031 if (dataVec.use_count()) {
1032 data.getFieldData().swap(dotVector);
1033 }
1034 }
1036}
1037
1038/** \brief Get values at integration pts for tensor field rank 2, i.e. matrix
1039 * field
1040 *
1041 * \ingroup mofem_forces_and_sources_user_data_operators
1042 */
1043template <int Tensor_Dim0, int Tensor_Dim1>
1045 : public OpCalculateTensor2FieldValues_General<Tensor_Dim0,
1046 Tensor_Dim1> {
1047
1049 Tensor_Dim0, Tensor_Dim1>::OpCalculateTensor2FieldValues_General;
1050};
1051
1052/** \brief Get time direvarive values at integration pts for tensor field rank
1053 * 2, i.e. matrix field
1054 *
1055 * \ingroup mofem_forces_and_sources_user_data_operators
1056 */
1057template <int Tensor_Dim0, int Tensor_Dim1>
1060
1062 boost::shared_ptr<MatrixDouble> data_ptr,
1063 const EntityType zero_at_type = MBVERTEX)
1066 dataPtr(data_ptr), zeroAtType(zero_at_type) {
1067 if (!dataPtr)
1068 THROW_MESSAGE("Pointer is not set");
1069 }
1070
1071 MoFEMErrorCode doWork(int side, EntityType type,
1074
1076 const size_t nb_gauss_pts = getGaussPts().size2();
1077 MatrixDouble &mat = *dataPtr;
1078 auto get_values_at_gauss_pts =
1080 GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
1081 DL>::size(mat, nb_gauss_pts);
1082 if (type == zeroAtType)
1083 mat.clear();
1084 const auto &local_indices = data.getLocalIndices();
1085 const size_t nb_dofs = local_indices.size();
1086 if (nb_dofs) {
1087 dotVector.resize(nb_dofs, false);
1088 const double *array;
1089 CHKERR VecGetArrayRead(getFEMethod()->ts_u_t, &array);
1090 for (size_t i = 0; i != local_indices.size(); ++i)
1091 if (local_indices[i] != -1)
1092 dotVector[i] = array[local_indices[i]];
1093 else
1094 dotVector[i] = 0;
1095 CHKERR VecRestoreArrayRead(getFEMethod()->ts_u_t, &array);
1096
1097 const size_t nb_base_functions = data.getN().size2();
1098
1099 auto base_function = data.getFTensor0N();
1100 auto t_values_at_gauss_pts = get_values_at_gauss_pts();
1101 FTensor::Index<'i', Tensor_Dim0> i;
1102 FTensor::Index<'j', Tensor_Dim1> j;
1103 const size_t size = nb_dofs / (Tensor_Dim0 * Tensor_Dim1);
1104 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
1105 auto field_data =
1106 getFTensor2FromPtr<Tensor_Dim0, Tensor_Dim1>(&*dotVector.begin());
1107 size_t bb = 0;
1108 for (; bb != size; ++bb) {
1109 t_values_at_gauss_pts(i, j) += field_data(i, j) * base_function;
1110 ++field_data;
1111 ++base_function;
1112 }
1113 for (; bb < nb_base_functions; ++bb)
1114 ++base_function;
1115 ++t_values_at_gauss_pts;
1116 }
1117 }
1119 }
1120
1121protected:
1122 boost::shared_ptr<MatrixDouble> dataPtr; ///< Data computed into this matrix
1123 EntityType zeroAtType; ///< Zero values at Gauss point at this type
1124 VectorDouble dotVector; ///< Keeps temporary values of time derivatives
1125};
1126
1127/**
1128 * @brief Calculate symmetric tensor field values at integration pts.
1129 *
1130 * @tparam Tensor_Dim
1131
1132 * \ingroup mofem_forces_and_sources_user_data_operators
1133 */
1134template <int Tensor_Dim>
1137
1139 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
1140 const EntityType zero_type = MBEDGE, const int zero_side = 0)
1143 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
1144 if (!dataPtr)
1145 THROW_MESSAGE("Pointer is not set");
1146 }
1147
1149 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
1150 SmartPetscObj<Vec> data_vec, const EntityType zero_type = MBEDGE,
1151 const int zero_side = 0)
1154 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side),
1155 dataVec(data_vec) {
1156 if (!dataPtr)
1157 THROW_MESSAGE("Pointer is not set");
1158 }
1159
1160 MoFEMErrorCode doWork(int side, EntityType type,
1163 MatrixDouble &mat = *dataPtr;
1164 const int nb_gauss_pts = getGaussPts().size2();
1166 auto get_values_at_gauss_pts =
1168 DL>::size(mat, nb_gauss_pts);
1169 if (type == this->zeroType && side == zeroSide) {
1170 mat.clear();
1171 }
1172 const int nb_dofs = data.getFieldData().size();
1173 if (!nb_dofs)
1175
1176 if (dataVec.use_count()) {
1177 dotVector.resize(nb_dofs, false);
1178 const double *array;
1179 CHKERR VecGetArrayRead(dataVec, &array);
1180 const auto &local_indices = data.getLocalIndices();
1181 for (int i = 0; i != local_indices.size(); ++i)
1182 if (local_indices[i] != -1)
1183 dotVector[i] = array[local_indices[i]];
1184 else
1185 dotVector[i] = 0;
1186 CHKERR VecRestoreArrayRead(dataVec, &array);
1187 data.getFieldData().swap(dotVector);
1188 }
1189
1190 const int nb_base_functions = data.getN().size2();
1191 auto base_function = data.getFTensor0N();
1192 auto t_values_at_gauss_pts = get_values_at_gauss_pts();
1193 FTensor::Index<'i', Tensor_Dim> i;
1194 FTensor::Index<'j', Tensor_Dim> j;
1195 const int size = nb_dofs / ((Tensor_Dim * (Tensor_Dim + 1)) / 2);
1196 for (int gg = 0; gg != nb_gauss_pts; ++gg) {
1197 auto field_data = data.getFTensor2SymmetricFieldData<Tensor_Dim>();
1198 int bb = 0;
1199 for (; bb != size; ++bb) {
1200 t_values_at_gauss_pts(i, j) += field_data(i, j) * base_function;
1201 ++field_data;
1202 ++base_function;
1203 }
1204 for (; bb < nb_base_functions; ++bb)
1205 ++base_function;
1206 ++t_values_at_gauss_pts;
1207 }
1208
1209 if (dataVec.use_count()) {
1210 data.getFieldData().swap(dotVector);
1211 }
1212
1214 }
1215
1216protected:
1217 boost::shared_ptr<MatrixDouble> dataPtr;
1219 const int zeroSide;
1222};
1223
1224/**
1225 * @brief Calculate symmetric tensor field rates ant integratio pts.
1226 *
1227 * @tparam Tensor_Dim
1228 *
1229 * \ingroup mofem_forces_and_sources_user_data_operators
1230 */
1231template <int Tensor_Dim>
1234
1236 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
1237 const EntityType zero_type = MBEDGE, const int zero_side = 0)
1240 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
1241 if (!dataPtr)
1242 THROW_MESSAGE("Pointer is not set");
1243 }
1244
1245 MoFEMErrorCode doWork(int side, EntityType type,
1248 const int nb_gauss_pts = getGaussPts().size2();
1249 MatrixDouble &mat = *dataPtr;
1250 constexpr auto symm_size = (Tensor_Dim * (Tensor_Dim + 1)) / 2;
1252 auto get_values_at_gauss_pts =
1254 DL>::size(mat, nb_gauss_pts);
1255 if (type == zeroType && side == zeroSide) {
1256 mat.clear();
1257 }
1258 auto &local_indices = data.getLocalIndices();
1259 const int nb_dofs = local_indices.size();
1260 if (!nb_dofs)
1262
1263 #ifndef NDEBUG
1264 if ((getFEMethod()->data_ctx & PetscData::CtxSetX_T).none()) {
1265 MOFEM_LOG_CHANNEL("SELF");
1266 MOFEM_LOG("SELF", Sev::error)
1267 << "In this case field degrees of freedom are read from vector. "
1268 "That usually happens when time solver is used, and acces to "
1269 "first rates is needed. You probably not set "
1270 "ts_u_t and associated data structure data_ctx to CTX_SET_X_T "
1271 "respectively";
1272 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Vector not set!");
1273 }
1274 #endif
1275
1276 dotVector.resize(nb_dofs, false);
1277 const double *array;
1278 CHKERR VecGetArrayRead(getFEMethod()->ts_u_t, &array);
1279 for (int i = 0; i != local_indices.size(); ++i)
1280 if (local_indices[i] != -1)
1281 dotVector[i] = array[local_indices[i]];
1282 else
1283 dotVector[i] = 0;
1284 CHKERR VecRestoreArrayRead(getFEMethod()->ts_u_t, &array);
1285
1286 const int nb_base_functions = data.getN().size2();
1287
1288 auto base_function = data.getFTensor0N();
1289 auto t_values_at_gauss_pts = get_values_at_gauss_pts();
1290 FTensor::Index<'i', Tensor_Dim> i;
1291 FTensor::Index<'j', Tensor_Dim> j;
1292 const int size = nb_dofs / symm_size;
1293 for (int gg = 0; gg != nb_gauss_pts; ++gg) {
1294 auto field_data = getFTensorDotData<Tensor_Dim>();
1295 int bb = 0;
1296 for (; bb != size; ++bb) {
1297 t_values_at_gauss_pts(i, j) += field_data(i, j) * base_function;
1298 ++field_data;
1299 ++base_function;
1300 }
1301 for (; bb < nb_base_functions; ++bb)
1302 ++base_function;
1303 ++t_values_at_gauss_pts;
1304 }
1305
1307 }
1308
1309protected:
1310 boost::shared_ptr<MatrixDouble> dataPtr;
1312 const int zeroSide;
1314
1315 template <int Dim> inline auto getFTensorDotData() {
1316 static_assert(Dim || !Dim, "not implemented");
1317 }
1318};
1319
1320template <>
1321template <>
1322inline auto
1325 &dotVector[0], &dotVector[1], &dotVector[2], &dotVector[3], &dotVector[4],
1326 &dotVector[5]);
1327}
1328
1329template <>
1330template <>
1331inline auto
1334 &dotVector[0], &dotVector[1], &dotVector[2]);
1335}
1336
1337/**@}*/
1338
1339/** \name Gradients and Hessian of scalar fields at integration points */
1340
1341/**@{*/
1342
1343/**
1344 * \brief Evaluate field gradient values for scalar field, i.e. gradient is
1345 * tensor rank 1 (vector)
1346 *
1347 */
1348template <int Tensor_Dim, typename M = MatrixDouble>
1350 : public OpCalculateVectorFieldValues_General<Tensor_Dim, M> {
1351
1353 Tensor_Dim, M>::OpCalculateVectorFieldValues_General;
1354};
1355
1356/** \brief Evaluate field gradient values for scalar field, i.e. gradient is
1357 * tensor rank 1 (vector), specialization
1358 *
1359 */
1360template <int Tensor_Dim>
1362 : public OpCalculateVectorFieldValues_General<Tensor_Dim, MatrixDouble> {
1363
1365 Tensor_Dim, MatrixDouble>::OpCalculateVectorFieldValues_General;
1366
1367 /**
1368 * \brief calculate gradient values of scalar field at integration points
1369 * @param side side entity number
1370 * @param type side entity type
1371 * @param data entity data
1372 * @return error code
1373 */
1374 MoFEMErrorCode doWork(int side, EntityType type,
1376};
1377
1378/**
1379 * \brief Member function specialization calculating scalar field gradients for
1380 * tenor field rank 1
1381 *
1382 */
1383template <int Tensor_Dim>
1385 Tensor_Dim, MatrixDouble>::doWork(int side, EntityType type,
1388
1389 const size_t nb_gauss_pts = this->getGaussPts().size2();
1390 auto &mat = *this->dataPtr;
1392 auto get_gradients_at_pts =
1393 MatrixSizeHelper<GetFTensor1FromMatType<Tensor_Dim, -1, DL>,
1394 DL>::size(mat, nb_gauss_pts);
1395 if (type == this->zeroType) {
1396 mat.clear();
1397 }
1398
1399 const int nb_dofs = data.getFieldData().size();
1400 if (nb_dofs) {
1401
1402 if (nb_gauss_pts) {
1403 const int nb_base_functions = data.getN().size2();
1404 auto diff_base_function = data.getFTensor1DiffN<Tensor_Dim>();
1405 auto t_gradients_at_pts = get_gradients_at_pts();
1406
1407 #ifndef NDEBUG
1408 if (nb_dofs > nb_base_functions)
1409 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1410 "Number of base functions inconsistent with number of DOFs "
1411 "(%d > %d)",
1412 nb_dofs, nb_base_functions);
1413
1414 if (data.getDiffN().size2() != nb_base_functions * Tensor_Dim)
1415 SETERRQ(
1416 PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1417 "Number of base functions inconsistent with number of derivatives "
1418 "(%zu != %d)",
1419 data.getDiffN().size2(), nb_base_functions);
1420
1421 if (data.getDiffN().size1() != nb_gauss_pts)
1422 SETERRQ(
1423 PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1424 "Number of base functions inconsistent with number of integration "
1425 "pts (%zu != %zu)",
1426 data.getDiffN().size1(), nb_gauss_pts);
1427
1428 #endif
1429
1430 FTensor::Index<'I', Tensor_Dim> I;
1431 for (int gg = 0; gg < nb_gauss_pts; ++gg) {
1432 auto field_data = data.getFTensor0FieldData();
1433 int bb = 0;
1434 for (; bb != nb_dofs; ++bb) {
1435 t_gradients_at_pts(I) += field_data * diff_base_function(I);
1436 ++field_data;
1437 ++diff_base_function;
1438 }
1439 // Number of dofs can be smaller than number of base functions
1440 for (; bb < nb_base_functions; ++bb)
1441 ++diff_base_function;
1442 ++t_gradients_at_pts;
1443 }
1444 }
1445 }
1446
1448}
1449
1450/** \brief Get field gradients at integration pts for scalar field rank 0, i.e.
1451 * vector field
1452 *
1453 * \ingroup mofem_forces_and_sources_user_data_operators
1454 */
1455template <int Tensor_Dim>
1457 : public OpCalculateScalarFieldGradient_General<Tensor_Dim> {
1459 Tensor_Dim>::OpCalculateScalarFieldGradient_General;
1460};
1461
1462/** \brief Evaluate field gradient values for scalar field, i.e. gradient is
1463 * tensor rank 1 (vector), specialization
1464 *
1465 */
1466template <int Tensor_Dim>
1468 : public OpCalculateVectorFieldValues_General<Tensor_Dim> {
1469
1471 Tensor_Dim>::OpCalculateVectorFieldValues_General;
1472
1473 /**
1474 * \brief calculate gradient values of scalar field at integration points
1475 * @param side side entity number
1476 * @param type side entity type
1477 * @param data entity data
1478 * @return error code
1479 */
1480 MoFEMErrorCode doWork(int side, EntityType type,
1482};
1483
1484template <int Tensor_Dim>
1486 int side, EntityType type, EntitiesFieldData::EntData &data) {
1488
1489 const size_t nb_gauss_pts = this->getGaussPts().size2();
1491 auto &mat = *this->dataPtr;
1492 auto get_hessian_at_gauss_pts =
1493 MatrixSizeHelper<GetFTensor2FromMatType<Tensor_Dim, Tensor_Dim, -1, DL>,
1494 DL>::size(mat, nb_gauss_pts);
1495 if (type == this->zeroType)
1496 mat.clear();
1497
1498 const int nb_dofs = data.getFieldData().size();
1499 if (nb_dofs) {
1500
1501 if (nb_gauss_pts) {
1502 const int nb_base_functions = data.getN().size2();
1503
1504 auto &hessian_base = data.getN(BaseDerivatives::SecondDerivative);
1505 #ifndef NDEBUG
1506 if (hessian_base.size1() != nb_gauss_pts) {
1507 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1508 "Wrong number of integration pts (%ld != %ld)",
1509 static_cast<long>(hessian_base.size1()),
1510 static_cast<long>(nb_gauss_pts));
1511 }
1512 if (hessian_base.size2() != nb_base_functions * Tensor_Dim * Tensor_Dim) {
1513 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1514 "Wrong number of base functions (%ld != %ld)",
1515 static_cast<long>(hessian_base.size2() /
1516 (Tensor_Dim * Tensor_Dim)),
1517 static_cast<long>(nb_base_functions));
1518 }
1519 if (hessian_base.size2() < nb_dofs * Tensor_Dim * Tensor_Dim) {
1520 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1521 "Wrong number of base functions (%ld < %ld)",
1522 static_cast<long>(hessian_base.size2()),
1523 static_cast<long>(nb_dofs * Tensor_Dim * Tensor_Dim));
1524 }
1525 #endif
1526
1527 auto t_diff2_base_function = getFTensor2FromPtr<Tensor_Dim, Tensor_Dim>(
1528 &*hessian_base.data().begin());
1529
1530 auto t_hessian_at_gauss_pts = get_hessian_at_gauss_pts();
1531
1532 FTensor::Index<'I', Tensor_Dim> I;
1533 FTensor::Index<'J', Tensor_Dim> J;
1534 for (int gg = 0; gg != nb_gauss_pts; ++gg) {
1535 auto field_data = data.getFTensor0FieldData();
1536 int bb = 0;
1537 for (; bb != nb_dofs; ++bb) {
1538 t_hessian_at_gauss_pts(I, J) +=
1539 field_data * t_diff2_base_function(I, J);
1540 ++field_data;
1541 ++t_diff2_base_function;
1542 }
1543 // Number of dofs can be smaller than number of base functions
1544 for (; bb < nb_base_functions; ++bb) {
1545 ++t_diff2_base_function;
1546 }
1547
1548 ++t_hessian_at_gauss_pts;
1549 }
1550 }
1551 }
1552
1554}
1555
1556/**}*/
1557
1558/** \name Gradients and hessian of tensor fields at integration points */
1559
1560/**@{*/
1561
1562/**
1563 * \brief Evaluate field gradient values for vector field, i.e. gradient is
1564 * tensor rank 2
1565 *
1566 * \tparam Tensor_Dim0 Dimension of the vector field
1567 * \tparam Tensor_Dim1 Dimension of the gradient (usually spatial dimension)
1568 * \tparam S Storage order for the field data
1569 * \tparam M Matrix storage type
1570 *
1571 */
1572template <int Tensor_Dim0, int Tensor_Dim1, int S,
1573 typename M = MatrixDouble>
1575 : public OpCalculateTensor2FieldValues_General<Tensor_Dim0, Tensor_Dim1,
1576 M> {
1577
1579 Tensor_Dim0, Tensor_Dim1, M>::OpCalculateTensor2FieldValues_General;
1580};
1581
1582template <int Tensor_Dim0, int Tensor_Dim1, int S>
1583struct OpCalculateVectorFieldGradient_General<Tensor_Dim0, Tensor_Dim1, S,
1586 Tensor_Dim0, Tensor_Dim1, MatrixDouble> {
1587
1589 Tensor_Dim0, Tensor_Dim1, MatrixDouble>::OpCalculateTensor2FieldValues_General;
1590
1591 /**
1592 * \brief calculate values of vector field at integration points
1593 * @param side side entity number
1594 * @param type side entity type
1595 * @param data entity data
1596 * @return error code
1597 */
1598 MoFEMErrorCode doWork(int side, EntityType type,
1600};
1601
1602/**
1603 * \brief Member function specialization calculating vector field gradients for
1604 * tenor field rank 2
1605 *
1606 */
1607template <int Tensor_Dim0, int Tensor_Dim1, int S>
1609 Tensor_Dim0, Tensor_Dim1, S, MatrixDouble>::doWork(
1610 int side, EntityType type, EntitiesFieldData::EntData &data) {
1612 if (!this->dataPtr)
1613 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1614 "Data pointer not allocated");
1615
1616 const size_t nb_gauss_pts = this->getGaussPts().size2();
1618 auto &mat = *this->dataPtr;
1619 auto get_gradients_at_pts =
1621 GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
1622 DL>::size(mat, nb_gauss_pts);
1623 if (type == this->zeroType)
1624 mat.clear();
1625
1626 if (nb_gauss_pts) {
1627 const size_t nb_dofs = data.getFieldData().size();
1628
1629 if (nb_dofs) {
1630
1631 if (this->dataVec.use_count()) {
1632 this->dotVector.resize(nb_dofs, false);
1633 const double *array;
1634 CHKERR VecGetArrayRead(this->dataVec, &array);
1635 const auto &local_indices = data.getLocalIndices();
1636 for (int i = 0; i != local_indices.size(); ++i)
1637 if (local_indices[i] != -1)
1638 this->dotVector[i] = array[local_indices[i]];
1639 else
1640 this->dotVector[i] = 0;
1641 CHKERR VecRestoreArrayRead(this->dataVec, &array);
1642 data.getFieldData().swap(this->dotVector);
1643 }
1644
1645 const int nb_base_functions = data.getN().size2();
1646 auto diff_base_function = data.getFTensor1DiffN<Tensor_Dim1>();
1647 auto t_gradients_at_pts = get_gradients_at_pts();
1648 FTensor::Index<'I', Tensor_Dim0> I;
1649 FTensor::Index<'J', Tensor_Dim1> J;
1650 int size = nb_dofs / Tensor_Dim0;
1651 if (nb_dofs % Tensor_Dim0) {
1652 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1653 "Data inconsistency");
1654 }
1655 for (int gg = 0; gg < nb_gauss_pts; ++gg) {
1656 auto field_data = getFTensor1FromPtr<Tensor_Dim0, S>(
1657 data.getFieldData().data().data());
1658
1659 #ifndef NDEBUG
1660 if (field_data.l2() != field_data.l2()) {
1661 MOFEM_LOG("SELF", Sev::error) << "field data " << field_data;
1662 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1663 "Wrong number in coefficients");
1664 }
1665 #endif
1666
1667 int bb = 0;
1668 for (; bb < size; ++bb) {
1669 #ifndef SINGULARITY
1670 #ifndef NDEBUG
1671 if (diff_base_function.l2() != diff_base_function.l2()) {
1672 MOFEM_LOG("SELF", Sev::error)
1673 << "diff_base_function: " << diff_base_function;
1674 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1675 "Wrong number number in base functions");
1676 }
1677 #endif
1678 #endif
1679
1680 t_gradients_at_pts(I, J) += field_data(I) * diff_base_function(J);
1681 ++field_data;
1682 ++diff_base_function;
1683 }
1684 // Number of dofs can be smaller than number of Tensor_Dim0 x base
1685 // functions
1686 for (; bb != nb_base_functions; ++bb)
1687 ++diff_base_function;
1688 ++t_gradients_at_pts;
1689 }
1690
1691 if (this->dataVec.use_count()) {
1692 data.getFieldData().swap(this->dotVector);
1693 }
1694 }
1695 }
1697}
1698
1699/** \brief Get field gradients at integration pts for scalar field rank 0, i.e.
1700 * vector field
1701 *
1702 * \tparam Tensor_Dim0 Dimension of the vector field
1703 * \tparam Tensor_Dim1 Dimension of the gradient (usually spatial dimension)
1704 * \tparam S Stride in the storage of the vector field, default is Tensor_Dim0
1705 *
1706 * \ingroup mofem_forces_and_sources_user_data_operators
1707 */
1708template <int Tensor_Dim0, int Tensor_Dim1, int S = Tensor_Dim0>
1710 : public OpCalculateVectorFieldGradient_General<Tensor_Dim0, Tensor_Dim1,
1711 S> {
1712
1714 Tensor_Dim0, Tensor_Dim1, S>::OpCalculateVectorFieldGradient_General;
1715};
1716
1717/** \brief Get field gradients time derivative at integration pts for scalar
1718 * field rank 0, i.e. vector field
1719 *
1720 * \ingroup mofem_forces_and_sources_user_data_operators
1721 */
1722template <int Tensor_Dim0, int Tensor_Dim1>
1725
1727 boost::shared_ptr<MatrixDouble> data_ptr,
1728 const EntityType zero_at_type = MBVERTEX)
1731 dataPtr(data_ptr), zeroAtType(zero_at_type) {
1732 if (!dataPtr)
1733 THROW_MESSAGE("Pointer is not set");
1734 }
1735
1736 MoFEMErrorCode doWork(int side, EntityType type,
1739
1740 const auto &local_indices = data.getLocalIndices();
1741 const int nb_dofs = local_indices.size();
1742 const int nb_gauss_pts = this->getGaussPts().size2();
1743
1745 auto &mat = *this->dataPtr;
1746 auto get_gradients_at_pts =
1748 GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
1749 DL>::size(mat, nb_gauss_pts);
1750 if (type == this->zeroAtType)
1751 mat.clear();
1752 if (!nb_dofs)
1754
1755 dotVector.resize(nb_dofs, false);
1756 const double *array;
1757 CHKERR VecGetArrayRead(getFEMethod()->ts_u_t, &array);
1758 for (int i = 0; i != local_indices.size(); ++i)
1759 if (local_indices[i] != -1)
1760 dotVector[i] = array[local_indices[i]];
1761 else
1762 dotVector[i] = 0;
1763 CHKERR VecRestoreArrayRead(getFEMethod()->ts_u_t, &array);
1764
1765 const int nb_base_functions = data.getN().size2();
1766 auto diff_base_function = data.getFTensor1DiffN<Tensor_Dim1>();
1767 auto t_gradients_at_pts = get_gradients_at_pts();
1768 FTensor::Index<'I', Tensor_Dim0> I;
1769 FTensor::Index<'J', Tensor_Dim1> J;
1770 int size = nb_dofs / Tensor_Dim0;
1771 if (nb_dofs % Tensor_Dim0) {
1772 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Data inconsistency");
1773 }
1774
1775 for (int gg = 0; gg < nb_gauss_pts; ++gg) {
1776 auto field_data = getFTensor1FromPtr<Tensor_Dim0>(&*dotVector.begin());
1777 int bb = 0;
1778 for (; bb < size; ++bb) {
1779 t_gradients_at_pts(I, J) += field_data(I) * diff_base_function(J);
1780 ++field_data;
1781 ++diff_base_function;
1782 }
1783 // Number of dofs can be smaller than number of Tensor_Dim0 x base
1784 // functions
1785 for (; bb != nb_base_functions; ++bb)
1786 ++diff_base_function;
1787 ++t_gradients_at_pts;
1788 }
1790 }
1791
1792private:
1793 boost::shared_ptr<MatrixDouble> dataPtr; ///< Data computed into this matrix
1794 EntityType zeroAtType; ///< Zero values at Gauss point at this type
1795 VectorDouble dotVector; ///< Keeps temporary values of time derivatives
1796};
1797
1798/**
1799 * \brief Evaluate field gradient values for symmetric 2nd order tensor field,
1800 * i.e. gradient is tensor rank 3
1801 *
1802 */
1803template <int Tensor_Dim0, int Tensor_Dim1, typename M = MatrixDouble>
1805 : public OpCalculateTensor2FieldValues_General<Tensor_Dim0, Tensor_Dim1,
1806 M> {
1807
1809 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
1810 const EntityType zero_type = MBVERTEX)
1811 : OpCalculateTensor2FieldValues_General<Tensor_Dim0, Tensor_Dim1, M>(
1812 field_name, data_ptr, zero_type) {}
1813};
1814
1815template <int Tensor_Dim0, int Tensor_Dim1>
1817 Tensor_Dim1,
1820 Tensor_Dim0, Tensor_Dim1, MatrixDouble> {
1821
1823 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
1824 const EntityType zero_type = MBVERTEX)
1825 : OpCalculateTensor2FieldValues_General<Tensor_Dim0, Tensor_Dim1,
1826 MatrixDouble>(
1827 field_name, data_ptr, zero_type) {}
1828
1829 /**
1830 * \brief calculate values of vector field at integration points
1831 * @param side side entity number
1832 * @param type side entity type
1833 * @param data entity data
1834 * @return error code
1835 */
1836 MoFEMErrorCode doWork(int side, EntityType type,
1838};
1839
1840/**
1841 * \brief Member function specialization calculating tensor field gradients for
1842 * symmetric tensor field rank 2
1843 *
1844 */
1845template <int Tensor_Dim0, int Tensor_Dim1>
1846MoFEMErrorCode OpCalculateTensor2SymmetricFieldGradient_General<
1847 Tensor_Dim0, Tensor_Dim1, MatrixDouble>::doWork(
1848 int side, EntityType type, EntitiesFieldData::EntData &data) {
1850 if (!this->dataPtr)
1851 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1852 "Data pointer not allocated");
1853
1854 const size_t nb_gauss_pts = this->getGaussPts().size2();
1855 constexpr size_t msize = (Tensor_Dim0 * (Tensor_Dim0 + 1)) / 2;
1856 auto &mat = *this->dataPtr;
1857 if (type == this->zeroType) {
1858 mat.resize(msize * Tensor_Dim1, nb_gauss_pts, false);
1859 mat.clear();
1860 }
1861
1862 if (nb_gauss_pts) {
1863 const size_t nb_dofs = data.getFieldData().size();
1864
1865 if (nb_dofs) {
1866
1867 const int nb_base_functions = data.getN().size2();
1868 auto diff_base_function = data.getFTensor1DiffN<Tensor_Dim1>();
1869 auto gradients_at_pts =
1870 getFTensor3DgFromMat<Tensor_Dim0, Tensor_Dim1, -1,
1872 FTensor::Index<'I', Tensor_Dim0> I;
1873 FTensor::Index<'J', Tensor_Dim0> J;
1874 FTensor::Index<'K', Tensor_Dim1> K;
1875 int size = nb_dofs / msize;
1876 if (nb_dofs % msize) {
1877 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1878 "Data inconsistency");
1879 }
1880 for (int gg = 0; gg < nb_gauss_pts; ++gg) {
1881 auto field_data = data.getFTensor2SymmetricFieldData<Tensor_Dim0>();
1882 int bb = 0;
1883 for (; bb < size; ++bb) {
1884 gradients_at_pts(I, J, K) +=
1885 field_data(I, J) * diff_base_function(K);
1886 ++field_data;
1887 ++diff_base_function;
1888 }
1889 // Number of dofs can be smaller than number of Tensor_Dim0 x base
1890 // functions
1891 for (; bb != nb_base_functions; ++bb)
1892 ++diff_base_function;
1893 ++gradients_at_pts;
1894 }
1895 }
1896 }
1898}
1899
1900/** \brief Get field gradients at integration pts for symmetric tensorial field
1901 * rank 2
1902 *
1903 * \ingroup mofem_forces_and_sources_user_data_operators
1904 */
1905template <int Tensor_Dim0, int Tensor_Dim1>
1908 Tensor_Dim0, Tensor_Dim1> {
1909
1911 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
1912 const EntityType zero_type = MBVERTEX)
1914 Tensor_Dim0, Tensor_Dim1>(field_name, data_ptr, zero_type) {}
1915};
1916
1917template <int Tensor_Dim0, int Tensor_Dim1>
1919 : public OpCalculateTensor2FieldValues_General<Tensor_Dim0,
1920 Tensor_Dim1> {
1921
1923 Tensor_Dim0, Tensor_Dim1>::OpCalculateTensor2FieldValues_General;
1924
1925 /**
1926 * \brief calculate values of vector field at integration points
1927 * @param side side entity number
1928 * @param type side entity type
1929 * @param data entity data
1930 * @return error code
1931 */
1932 MoFEMErrorCode doWork(int side, EntityType type,
1934};
1935
1936/**
1937 * \brief Member function specialization calculating vector field gradients for
1938 * tenor field rank 2
1939 *
1940 */
1941template <int Tensor_Dim0, int Tensor_Dim1>
1943 int side, EntityType type, EntitiesFieldData::EntData &data) {
1945 if (!this->dataPtr)
1946 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1947 "Data pointer not allocated");
1948
1949 const size_t nb_gauss_pts = this->getGaussPts().size2();
1950 auto &mat = *this->dataPtr;
1952 auto get_hessian_at_gauss_pts = MatrixSizeHelper<
1953 GetFTensor3FromMatType<Tensor_Dim0, Tensor_Dim1, Tensor_Dim1, -1, DL>,
1954 DL>::size(mat, nb_gauss_pts);
1955 if (type == this->zeroType) {
1956 mat.clear();
1957 }
1958
1959 if (nb_gauss_pts) {
1960 const size_t nb_dofs = data.getFieldData().size();
1961
1962 if (nb_dofs) {
1963
1964 if (this->dataVec.use_count()) {
1965 this->dotVector.resize(nb_dofs, false);
1966 const double *array;
1967 CHKERR VecGetArrayRead(this->dataVec, &array);
1968 const auto &local_indices = data.getLocalIndices();
1969 for (int i = 0; i != local_indices.size(); ++i)
1970 if (local_indices[i] != -1)
1971 this->dotVector[i] = array[local_indices[i]];
1972 else
1973 this->dotVector[i] = 0;
1974 CHKERR VecRestoreArrayRead(this->dataVec, &array);
1975 data.getFieldData().swap(this->dotVector);
1976 }
1977
1978 const int nb_base_functions = data.getN().size2();
1979
1980 auto &hessian_base = data.getN(BaseDerivatives::SecondDerivative);
1981 #ifndef NDEBUG
1982 if (hessian_base.size1() != nb_gauss_pts) {
1983 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1984 "Wrong number of integration pts (%ld != %ld)",
1985 static_cast<long>(hessian_base.size1()),
1986 static_cast<long>(nb_gauss_pts));
1987 }
1988 if (hessian_base.size2() !=
1989 nb_base_functions * Tensor_Dim1 * Tensor_Dim1) {
1990 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1991 "Wrong number of base functions (%ld != %ld)",
1992 static_cast<long>(hessian_base.size2() /
1993 (Tensor_Dim1 * Tensor_Dim1)),
1994 static_cast<long>(nb_base_functions));
1995 }
1996 if (hessian_base.size2() <
1997 (nb_dofs / Tensor_Dim0) * Tensor_Dim1 * Tensor_Dim1) {
1998 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1999 "Wrong number of base functions (%ld < %ld)",
2000 static_cast<long>(hessian_base.size2()),
2001 static_cast<long>((nb_dofs / Tensor_Dim0) * Tensor_Dim1 *
2002 Tensor_Dim1));
2003 }
2004 #endif
2005
2006 auto t_diff2_base_function = getFTensor2FromPtr<Tensor_Dim1, Tensor_Dim1>(
2007 &*hessian_base.data().begin());
2008
2009 auto t_hessian_at_gauss_pts = get_hessian_at_gauss_pts();
2010
2011 FTensor::Index<'I', Tensor_Dim0> I;
2012 FTensor::Index<'J', Tensor_Dim1> J;
2013 FTensor::Index<'K', Tensor_Dim1> K;
2014
2015 int size = nb_dofs / Tensor_Dim0;
2016 #ifndef NDEBUG
2017 if (nb_dofs % Tensor_Dim0) {
2018 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2019 "Data inconsistency");
2020 }
2021 #endif
2022
2023 for (int gg = 0; gg < nb_gauss_pts; ++gg) {
2024 auto field_data = data.getFTensor1FieldData<Tensor_Dim0>();
2025 int bb = 0;
2026 for (; bb < size; ++bb) {
2027 t_hessian_at_gauss_pts(I, J, K) +=
2028 field_data(I) * t_diff2_base_function(J, K);
2029 ++field_data;
2030 ++t_diff2_base_function;
2031 }
2032 // Number of dofs can be smaller than number of Tensor_Dim0 x base
2033 // functions
2034 for (; bb != nb_base_functions; ++bb)
2035 ++t_diff2_base_function;
2036 ++t_hessian_at_gauss_pts;
2037 }
2038
2039 if (this->dataVec.use_count()) {
2040 data.getFieldData().swap(this->dotVector);
2041 }
2042 }
2043 }
2045}
2046
2047/**@}*/
2048
2049/** \name Transform tensors and vectors */
2050
2051/**@{*/
2052
2053/**
2054 * @brief Calculate \f$ \pmb\sigma_{ij} = \mathbf{D}_{ijkl} \pmb\varepsilon_{kl}
2055 * \f$
2056 *
2057 * @tparam DIM
2058 *
2059 * \ingroup mofem_forces_and_sources_user_data_operators
2060 */
2061template <int DIM_01, int DIM_23, int S = 0>
2064
2067
2068 /**
2069 * @deprecated Do not use this constructor
2070 */
2073 boost::shared_ptr<MatrixDouble> in_mat,
2074 boost::shared_ptr<MatrixDouble> out_mat,
2075 boost::shared_ptr<MatrixDouble> d_mat)
2076 : UserOp(field_name, OPCOL), inMat(in_mat), outMat(out_mat), dMat(d_mat) {
2077 // Only is run for vertices
2078 std::fill(&doEntities[MBEDGE], &doEntities[MBMAXTYPE], false);
2079 if (!inMat)
2080 THROW_MESSAGE("Pointer for in mat is null");
2081 if (!outMat)
2082 THROW_MESSAGE("Pointer for out mat is null");
2083 if (!dMat)
2084 THROW_MESSAGE("Pointer for tensor mat is null");
2085 }
2086
2087 OpTensorTimesSymmetricTensor(boost::shared_ptr<MatrixDouble> in_mat,
2088 boost::shared_ptr<MatrixDouble> out_mat,
2089 boost::shared_ptr<MatrixDouble> d_mat)
2090 : UserOp(NOSPACE, OPSPACE), inMat(in_mat), outMat(out_mat), dMat(d_mat) {
2091 // Only is run for vertices
2092 if (!inMat)
2093 THROW_MESSAGE("Pointer for in mat is null");
2094 if (!outMat)
2095 THROW_MESSAGE("Pointer for out mat is null");
2096 if (!dMat)
2097 THROW_MESSAGE("Pointer for tensor mat is null");
2098 }
2099
2100 MoFEMErrorCode doWork(int, EntityType, EntData &) {
2102 const size_t nb_gauss_pts = getGaussPts().size2();
2104 auto get_D_at_pts =
2106 DL>::get(*dMat, nb_gauss_pts);
2107 auto get_in_at_pts =
2109 DL>::get(*inMat, nb_gauss_pts);
2110 auto get_out_at_pts =
2112 DL>::size(*outMat, nb_gauss_pts);
2113 auto t_D_at_pts = get_D_at_pts();
2114 auto t_in_at_pts = get_in_at_pts();
2115 auto t_out_at_pts = get_out_at_pts();
2116 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
2117 t_out_at_pts(i, j) = t_D_at_pts(i, j, k, l) * t_in_at_pts(k, l);
2118 ++t_in_at_pts;
2119 ++t_out_at_pts;
2120 ++t_D_at_pts;
2121 }
2123 }
2124
2125private:
2126 FTensor::Index<'i', DIM_01> i;
2127 FTensor::Index<'j', DIM_01> j;
2128 FTensor::Index<'k', DIM_23> k;
2129 FTensor::Index<'l', DIM_23> l;
2130
2131 boost::shared_ptr<MatrixDouble> inMat;
2132 boost::shared_ptr<MatrixDouble> outMat;
2133 boost::shared_ptr<MatrixDouble> dMat;
2134};
2135
2136/**
2137 * @brief Operator for symmetrizing tensor fields
2138 *
2139 * This template structure symmetrizes tensor fields by computing the symmetric
2140 * part of an input tensor and storing the result in an output matrix. It's
2141 * commonly used in mechanics where symmetric tensors (like stress and strain)
2142 * are required.
2143 *
2144 * @tparam DIM Dimension of the tensor field
2145 */
2146template <int DIM>
2148
2151
2152 /**
2153 * @deprecated Do not use this constructor
2154 */
2156 boost::shared_ptr<MatrixDouble> in_mat,
2157 boost::shared_ptr<MatrixDouble> out_mat)
2158 : UserOp(field_name, OPCOL), inMat(in_mat), outMat(out_mat) {
2159 // Only is run for vertices
2160 std::fill(&doEntities[MBEDGE], &doEntities[MBMAXTYPE], false);
2161 if (!inMat)
2162 THROW_MESSAGE("Pointer not set for in matrix");
2163 if (!outMat)
2164 THROW_MESSAGE("Pointer not set for in matrix");
2165 }
2166
2167 /**
2168 * @brief Constructor for tensor symmetrization operator
2169 *
2170 * @param in_mat Shared pointer to input matrix containing asymmetric tensor
2171 * @param out_mat Shared pointer to output matrix for storing symmetric tensor
2172 */
2173 OpSymmetrizeTensor(boost::shared_ptr<MatrixDouble> in_mat,
2174 boost::shared_ptr<MatrixDouble> out_mat)
2175 : UserOp(NOSPACE, OPSPACE), inMat(in_mat), outMat(out_mat) {
2176 // Only is run for vertices
2177 if (!inMat)
2178 THROW_MESSAGE("Pointer not set for in matrix");
2179 if (!outMat)
2180 THROW_MESSAGE("Pointer not set for in matrix");
2181 }
2182
2183 MoFEMErrorCode doWork(int, EntityType, EntData &) {
2185 const size_t nb_gauss_pts = getGaussPts().size2();
2187 auto get_in_at_pts =
2188 MatrixSizeHelper<GetFTensor2FromMatType<DIM, DIM, -1, DL>, DL>::get(
2189 *inMat, nb_gauss_pts);
2190 auto t_in_at_pts = get_in_at_pts();
2191 auto get_out_at_pts =
2193 DL>::size(*outMat, nb_gauss_pts);
2194 auto t_out_at_pts = get_out_at_pts();
2195 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
2196 t_out_at_pts(i, j) = (t_in_at_pts(i, j) || t_in_at_pts(j, i)) / 2;
2197 ++t_in_at_pts;
2198 ++t_out_at_pts;
2199 }
2201 }
2202
2203private:
2206 boost::shared_ptr<MatrixDouble> inMat;
2207 boost::shared_ptr<MatrixDouble> outMat;
2208};
2209
2210/**
2211 * @brief Operator for scaling matrix values by a scalar factor
2212 *
2213 * This structure performs element-wise scaling of matrix data by multiplying
2214 * all elements by a scalar value. It's useful for applying material properties,
2215 * coordinate transformations, or other scaling operations in finite element
2216 * computations.
2217 */
2219
2222
2223 /**
2224 * @deprecated Do not use this constructor
2225 */
2226 DEPRECATED OpScaleMatrix(const std::string field_name, const double scale,
2227 boost::shared_ptr<MatrixDouble> in_mat,
2228 boost::shared_ptr<MatrixDouble> out_mat)
2229 : UserOp(field_name, OPCOL), inMat(in_mat), outMat(out_mat) {
2230 scalePtr = boost::make_shared<double>(scale);
2231 // Only is run for vertices
2232 std::fill(&doEntities[MBEDGE], &doEntities[MBMAXTYPE], false);
2233 if (!inMat)
2234 THROW_MESSAGE("Pointer not set for in matrix");
2235 if (!outMat)
2236 THROW_MESSAGE("Pointer not set for in matrix");
2237 }
2238
2239 /**
2240 * @brief Constructor for matrix scaling operator
2241 *
2242 * @param scale_ptr Shared pointer to scalar value for scaling matrix elements
2243 * @param in_mat Shared pointer to input matrix to be scaled
2244 * @param out_mat Shared pointer to output matrix for storing scaled results
2245 */
2246 OpScaleMatrix(boost::shared_ptr<double> scale_ptr,
2247 boost::shared_ptr<MatrixDouble> in_mat,
2248 boost::shared_ptr<MatrixDouble> out_mat)
2249 : UserOp(NOSPACE, OPSPACE), scalePtr(scale_ptr), inMat(in_mat),
2250 outMat(out_mat) {
2251 if (!scalePtr)
2252 THROW_MESSAGE("Pointer not set for scale");
2253 if (!inMat)
2254 THROW_MESSAGE("Pointer not set for in matrix");
2255 if (!outMat)
2256 THROW_MESSAGE("Pointer not set for in matrix");
2257 }
2258
2259 MoFEMErrorCode doWork(int, EntityType, EntData &) {
2261 outMat->resize(inMat->size1(), inMat->size2(), false);
2262 noalias(*outMat) = (*scalePtr) * (*inMat);
2264 }
2265
2266private:
2267 boost::shared_ptr<double> scalePtr;
2268 boost::shared_ptr<MatrixDouble> inMat;
2269 boost::shared_ptr<MatrixDouble> outMat;
2270};
2271
2272/**@}*/
2273
2274/** \name H-div/H-curls (Vectorial bases) values at integration points */
2275
2276/**@{*/
2277
2278/** \brief Get vector field for H-div approximation
2279 * \ingroup mofem_forces_and_sources_user_data_operators
2280 */
2281template <int Base_Dim, int Field_Dim, typename M = MatrixDouble>
2283
2284/** \brief Get vector field for H-div approximation
2285 * \ingroup mofem_forces_and_sources_user_data_operators
2286 */
2287template <int Field_Dim>
2290
2292 boost::shared_ptr<MatrixDouble> data_ptr,
2293 SmartPetscObj<Vec> data_vec,
2294 const EntityType zero_type = MBEDGE,
2295 const int zero_side = 0)
2298 dataPtr(data_ptr), dataVec(data_vec), zeroType(zero_type),
2299 zeroSide(zero_side) {
2300 if (!dataPtr)
2301 THROW_MESSAGE("Pointer is not set");
2302 }
2303
2305 boost::shared_ptr<MatrixDouble> data_ptr,
2306 const EntityType zero_type = MBEDGE,
2307 const int zero_side = 0)
2309 field_name, data_ptr, SmartPetscObj<Vec>(), zero_type, zero_side) {}
2310
2311 /**
2312 * \brief Calculate values of vector field at integration points
2313 * @param side side entity number
2314 * @param type side entity type
2315 * @param data entity data
2316 * @return error code
2317 */
2318 MoFEMErrorCode doWork(int side, EntityType type,
2320
2321private:
2322 boost::shared_ptr<MatrixDouble> dataPtr;
2325 const int zeroSide;
2327};
2328
2329template <int Field_Dim>
2331 3, Field_Dim, MatrixDouble>::doWork(int side, EntityType type,
2334 const size_t nb_integration_points = this->getGaussPts().size2();
2335 auto &mat = *dataPtr;
2337 auto get_data_at_pts =
2338 MatrixSizeHelper<GetFTensor1FromMatType<Field_Dim, -1, DL>,
2339 DL>::size(mat, nb_integration_points);
2340 if (type == zeroType && side == zeroSide) {
2341 mat.clear();
2342 }
2343 const size_t nb_dofs = data.getFieldData().size();
2344 if (!nb_dofs)
2346
2347 if (dataVec.use_count()) {
2348 dotVector.resize(nb_dofs, false);
2349 const double *array;
2350 CHKERR VecGetArrayRead(dataVec, &array);
2351 const auto &local_indices = data.getLocalIndices();
2352 for (int i = 0; i != local_indices.size(); ++i)
2353 if (local_indices[i] != -1)
2354 dotVector[i] = array[local_indices[i]];
2355 else
2356 dotVector[i] = 0;
2357 CHKERR VecRestoreArrayRead(dataVec, &array);
2358 data.getFieldData().swap(dotVector);
2359 }
2360
2361 const size_t nb_base_functions = data.getN().size2() / 3;
2362 FTensor::Index<'i', Field_Dim> i;
2363 auto t_n_hdiv = data.getFTensor1N<3>();
2364 auto t_data_at_pts = get_data_at_pts();
2365 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
2366 auto t_dof = data.getFTensor0FieldData();
2367 int bb = 0;
2368 for (; bb != nb_dofs; ++bb) {
2369 t_data_at_pts(i) += t_n_hdiv(i) * t_dof;
2370 ++t_n_hdiv;
2371 ++t_dof;
2372 }
2373 for (; bb != nb_base_functions; ++bb)
2374 ++t_n_hdiv;
2375 ++t_data_at_pts;
2376 }
2377
2378 if (dataVec.use_count()) {
2379 data.getFieldData().swap(dotVector);
2380 }
2382}
2383
2384/** \brief Get vector field for H-div approximation
2385 *
2386 * \ingroup mofem_forces_and_sources_user_data_operators
2387 */
2388template <int Base_Dim, int Field_Dim = Base_Dim>
2390 : public OpCalculateHVecVectorField_General<Base_Dim, Field_Dim> {
2392 Base_Dim, Field_Dim>::OpCalculateHVecVectorField_General;
2393};
2394
2395/** \brief Get vector field for H-div approximation
2396 * \ingroup mofem_forces_and_sources_user_data_operators
2397 */
2398template <int Base_Dim, int Field_Dim = Base_Dim>
2400
2401template <int Field_Dim>
2404
2406 boost::shared_ptr<MatrixDouble> data_ptr,
2407 const EntityType zero_type = MBEDGE,
2408 const int zero_side = 0)
2411 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
2412 if (!dataPtr)
2413 THROW_MESSAGE("Pointer is not set");
2414 }
2415
2416 /**
2417 * \brief Calculate values of vector field at integration points
2418 * @param side side entity number
2419 * @param type side entity type
2420 * @param data entity data
2421 * @return error code
2422 */
2423 MoFEMErrorCode doWork(int side, EntityType type,
2425
2426private:
2427 boost::shared_ptr<MatrixDouble> dataPtr;
2429 const int zeroSide;
2430};
2431
2432template <int Field_Dim>
2434 int side, EntityType type, EntitiesFieldData::EntData &data) {
2436
2437 const size_t nb_integration_points = this->getGaussPts().size2();
2438 auto &mat = *dataPtr;
2440 auto get_data_at_pts =
2441 MatrixSizeHelper<GetFTensor1FromMatType<Field_Dim, -1, DL>,
2442 DL>::size(mat, nb_integration_points);
2443 if (type == zeroType && side == zeroSide) {
2444 mat.clear();
2445 }
2446
2447 auto &local_indices = data.getIndices();
2448 const size_t nb_dofs = local_indices.size();
2449 if (nb_dofs) {
2450
2451 std::array<double, MAX_DOFS_ON_ENTITY> dot_dofs_vector;
2452 const double *array;
2453 CHKERR VecGetArrayRead(getFEMethod()->ts_u_t, &array);
2454 for (size_t i = 0; i != nb_dofs; ++i)
2455 if (local_indices[i] != -1)
2456 dot_dofs_vector[i] = array[local_indices[i]];
2457 else
2458 dot_dofs_vector[i] = 0;
2459 CHKERR VecRestoreArrayRead(getFEMethod()->ts_u_t, &array);
2460
2461 const size_t nb_base_functions = data.getN().size2() / 3;
2462 FTensor::Index<'i', Field_Dim> i;
2463 auto t_n_hdiv = data.getFTensor1N<3>();
2464 auto t_data_at_pts = get_data_at_pts();
2465 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
2466 size_t bb = 0;
2467 for (; bb != nb_dofs; ++bb) {
2468 t_data_at_pts(i) += t_n_hdiv(i) * dot_dofs_vector[bb];
2469 ++t_n_hdiv;
2470 }
2471 for (; bb != nb_base_functions; ++bb)
2472 ++t_n_hdiv;
2473 ++t_data_at_pts;
2474 }
2475 }
2476
2478}
2479
2480/**
2481 * @brief Calculate divergence of vector field
2482 * @ingroup mofem_forces_and_sources_user_data_operators
2483 *
2484 * @tparam BASE_DIM
2485 * @tparam SPACE_DIM
2486 */
2487template <int BASE_DIM, int SPACE_DIM>
2490
2492 boost::shared_ptr<VectorDouble> data_ptr,
2493 const EntityType zero_type = MBEDGE,
2494 const int zero_side = 0)
2497 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
2498 if (!dataPtr)
2499 THROW_MESSAGE("Pointer is not set");
2500 }
2501
2502 MoFEMErrorCode doWork(int side, EntityType type,
2505 const size_t nb_integration_points = getGaussPts().size2();
2506 if (type == zeroType && side == zeroSide) {
2507 dataPtr->resize(nb_integration_points, false);
2508 dataPtr->clear();
2509 }
2510 const size_t nb_dofs = data.getFieldData().size();
2511 if (!nb_dofs)
2513 const size_t nb_base_functions = data.getN().size2() / BASE_DIM;
2516 auto t_n_diff_hdiv = data.getFTensor2DiffN<BASE_DIM, SPACE_DIM>();
2517 auto t_data = getFTensor0FromVec(*dataPtr);
2518 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
2519 auto t_dof = data.getFTensor0FieldData();
2520 size_t bb = 0;
2521 for (; bb != nb_dofs; ++bb) {
2522 t_data += t_dof * t_n_diff_hdiv(j, j);
2523 ++t_n_diff_hdiv;
2524 ++t_dof;
2525 }
2526 for (; bb != nb_base_functions; ++bb)
2527 ++t_n_diff_hdiv;
2528 ++t_data;
2529 }
2531 }
2532
2533private:
2534 boost::shared_ptr<VectorDouble> dataPtr;
2536 const int zeroSide;
2537};
2538
2539/**
2540 * @brief Calculate gradient of vector field
2541 * @ingroup mofem_forces_and_sources_user_data_operators
2542 *
2543 * @tparam BASE_DIM
2544 * @tparam SPACE_DIM
2545 */
2546template <int BASE_DIM, int SPACE_DIM>
2549
2551 boost::shared_ptr<MatrixDouble> data_ptr,
2552 const EntityType zero_type = MBEDGE,
2553 const int zero_side = 0)
2556 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
2557 if (!dataPtr)
2558 THROW_MESSAGE("Pointer is not set");
2559 }
2560
2561 MoFEMErrorCode doWork(int side, EntityType type,
2564 const size_t nb_integration_points = getGaussPts().size2();
2566 auto get_data_at_pts =
2569 DL>::size(*dataPtr, nb_integration_points);
2570 if (type == zeroType && side == zeroSide)
2571 dataPtr->clear();
2572 const size_t nb_dofs = data.getFieldData().size();
2573 if (!nb_dofs)
2575 const size_t nb_base_functions = data.getN().size2() / BASE_DIM;
2578 auto t_base_diff = data.getFTensor2DiffN<BASE_DIM, SPACE_DIM>();
2579 auto t_data_at_pts = get_data_at_pts();
2580 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
2581 auto t_dof = data.getFTensor0FieldData();
2582 size_t bb = 0;
2583 for (; bb != nb_dofs; ++bb) {
2584 t_data_at_pts(i, j) += t_dof * t_base_diff(i, j);
2585 ++t_base_diff;
2586 ++t_dof;
2587 }
2588 for (; bb != nb_base_functions; ++bb)
2589 ++t_base_diff;
2590 ++t_data_at_pts;
2591 }
2593 }
2594
2595private:
2596 boost::shared_ptr<MatrixDouble> dataPtr;
2598 const int zeroSide;
2599};
2600
2601/**
2602 * @brief Calculate gradient of tensor field
2603 * @ingroup mofem_forces_and_sources_user_data_operators
2604 *
2605 * @tparam BASE_DIM
2606 * @tparam FIELD_DIM
2607 * @tparam SPACE_DIM
2608 */
2609template <int BASE_DIM, int FIELD_DIM, int SPACE_DIM>
2611
2612/**
2613 * @brief Specialisation for 3D tensor field gradient calculation
2614 * @ingroup mofem_forces_and_sources_user_data_operators
2615 *
2616 */
2617template <>
2620
2622 boost::shared_ptr<MatrixDouble> data_ptr,
2623 const EntityType zero_type = MBEDGE,
2624 const int zero_side = 0)
2627 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
2628 if (!dataPtr)
2629 THROW_MESSAGE("Pointer is not set");
2630 }
2631
2632 MoFEMErrorCode doWork(int side, EntityType type,
2635
2636 const size_t nb_integration_points = getGaussPts().size2();
2638 auto get_data_at_pts =
2640 DL>::size(*dataPtr, nb_integration_points);
2641 if (type == zeroType && side == zeroSide) {
2642 dataPtr->clear();
2643 }
2644
2645 #ifndef NDEBUG
2646 if (data.getFieldData().size() % 3) {
2647 SETERRQ(
2648 PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2649 "Data inconsistency, nb_dofs %% COEFF_DIM != 0, that is %ld %% %d "
2650 "!= 0",
2651 data.getFieldData().size(), 3);
2652 }
2653 #endif
2654
2655 const auto nb_dofs = data.getFieldData().size() / 3;
2656 if (!nb_dofs)
2658
2659 const size_t nb_base_functions = data.getN().size2() / 3;
2660 FTensor::Index<'i', 3> i;
2661 FTensor::Index<'j', 3> j;
2662 FTensor::Index<'k', 3> k;
2663
2664 auto t_base_diff = data.getFTensor2DiffN<3, 3>();
2665 auto t_data_at_pts = get_data_at_pts();
2666 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
2667 auto t_dof = data.getFTensor1FieldData<3>();
2668 size_t bb = 0;
2669 for (; bb != nb_dofs; ++bb) {
2670 t_data_at_pts(k, i, j) += t_base_diff(i, j) * t_dof(k);
2671 ++t_base_diff;
2672 ++t_dof;
2673 }
2674 for (; bb != nb_base_functions; ++bb)
2675 ++t_base_diff;
2676 ++t_data_at_pts;
2677 }
2679 }
2680
2681private:
2682 boost::shared_ptr<MatrixDouble> dataPtr;
2684 const int zeroSide;
2685};
2686
2687template <>
2690
2692 boost::shared_ptr<MatrixDouble> data_ptr,
2693 const EntityType zero_type = MBEDGE,
2694 const int zero_side = 0)
2697 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
2698 if (!dataPtr)
2699 THROW_MESSAGE("Pointer is not set");
2700 }
2701
2702 MoFEMErrorCode doWork(int side, EntityType type,
2705
2706 const size_t nb_integration_points = getGaussPts().size2();
2708 auto get_data_at_pts =
2710 DL>::size(*dataPtr, nb_integration_points);
2711 if (type == zeroType && side == zeroSide) {
2712 dataPtr->clear();
2713 }
2714
2715 const auto nb_dofs = data.getFieldData().size();
2716 if (!nb_dofs)
2718
2719 const size_t nb_base_functions = data.getN().size2() / 9;
2720
2721 #ifndef NDEBUG
2722 if (data.getDiffN().size1() != nb_integration_points) {
2723 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2724 "Wrong number of integration pts (%ld != %ld)",
2725 static_cast<long>(data.getDiffN().size1()),
2726 static_cast<long>(nb_integration_points));
2727 }
2728 if (data.getDiffN().size2() != nb_base_functions * 27) {
2729 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2730 "Wrong number of base functions (%ld != %ld)",
2731 static_cast<long>(data.getDiffN().size2() / 27),
2732 static_cast<long>(nb_base_functions));
2733 }
2734 if (nb_base_functions < nb_dofs) {
2735 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2736 "Wrong number of base functions (%ld < %ld)",
2737 static_cast<long>(nb_base_functions),
2738 static_cast<long>(nb_dofs));
2739 }
2740 #endif
2741
2742 FTensor::Index<'i', 3> i;
2743 FTensor::Index<'j', 3> j;
2744 FTensor::Index<'k', 3> k;
2745
2746 auto t_base_diff = data.getFTensor3DiffN<3, 3, 3>();
2747 auto t_data_at_pts = get_data_at_pts();
2748 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
2749 auto t_dof = data.getFTensor0FieldData();
2750 size_t bb = 0;
2751 for (; bb != nb_dofs; ++bb) {
2752 t_data_at_pts(k, i, j) += t_base_diff(k, i, j) * t_dof;
2753 ++t_base_diff;
2754 ++t_dof;
2755 }
2756 for (; bb != nb_base_functions; ++bb)
2757 ++t_base_diff;
2758 ++t_data_at_pts;
2759 }
2760
2762 }
2763
2764private:
2765 boost::shared_ptr<MatrixDouble> dataPtr;
2767 const int zeroSide;
2768};
2769
2770/**
2771 * @brief Calculate gradient of vector field
2772 * @ingroup mofem_forces_and_sources_user_data_operators
2773 *
2774 * @tparam BASE_DIM
2775 * @tparam SPACE_DIM
2776 */
2777template <int BASE_DIM, int SPACE_DIM>
2780
2782 boost::shared_ptr<MatrixDouble> data_ptr,
2783 const EntityType zero_type = MBEDGE,
2784 const int zero_side = 0)
2787 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
2788 if (!dataPtr)
2789 THROW_MESSAGE("Pointer is not set");
2790 }
2791
2792 MoFEMErrorCode doWork(int side, EntityType type,
2795 const size_t nb_integration_points = getGaussPts().size2();
2797 auto get_data_at_pts = MatrixSizeHelper<
2799 DL>::size(*dataPtr, nb_integration_points);
2800 if (type == zeroType && side == zeroSide) {
2801 dataPtr->clear();
2802 }
2803 const size_t nb_dofs = data.getFieldData().size();
2804 if (!nb_dofs)
2806
2807 const int nb_base_functions = data.getN().size2() / BASE_DIM;
2808
2809 #ifndef NDEBUG
2810 auto &hessian_base = data.getN(BaseDerivatives::SecondDerivative);
2811 if (hessian_base.size1() != nb_integration_points) {
2812 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2813 "Wrong number of integration pts (%ld != %ld)",
2814 static_cast<long>(hessian_base.size1()),
2815 static_cast<long>(nb_integration_points));
2816 }
2817 if (hessian_base.size2() !=
2818 BASE_DIM * nb_base_functions * SPACE_DIM * SPACE_DIM) {
2819 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2820 "Wrong number of base functions (%ld != %ld)",
2821 static_cast<long>(hessian_base.size2() /
2823 static_cast<long>(nb_base_functions));
2824 }
2825 if (hessian_base.size2() < BASE_DIM * nb_dofs * SPACE_DIM * SPACE_DIM) {
2826 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2827 "Wrong number of base functions (%ld < %ld)",
2828 static_cast<long>(hessian_base.size2()),
2829 static_cast<long>(BASE_DIM * nb_dofs * SPACE_DIM * SPACE_DIM));
2830 }
2831 #endif
2832
2836
2837 auto t_base_diff2 =
2839 auto t_data_at_pts = get_data_at_pts();
2840 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
2841 auto t_dof = data.getFTensor0FieldData();
2842 int bb = 0;
2843 for (; bb != nb_dofs; ++bb) {
2844 t_data_at_pts(i, j, k) += t_dof * t_base_diff2(i, j, k);
2845
2846 ++t_base_diff2;
2847 ++t_dof;
2848 }
2849 for (; bb != nb_base_functions; ++bb)
2850 ++t_base_diff2;
2851 ++t_data_at_pts;
2852 }
2854 }
2855
2856private:
2857 boost::shared_ptr<MatrixDouble> dataPtr;
2859 const int zeroSide;
2860};
2861
2862/**
2863 * @brief Calculate divergence of vector field dot
2864 * @ingroup mofem_forces_and_sources_user_data_operators
2865 *
2866 * @tparam Tensor_Dim dimension of space
2867 */
2868template <int Tensor_Dim1, int Tensor_Dim2>
2871
2873 boost::shared_ptr<VectorDouble> data_ptr,
2874 const EntityType zero_type = MBEDGE,
2875 const int zero_side = 0)
2878 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
2879 if (!dataPtr)
2880 THROW_MESSAGE("Pointer is not set");
2881 }
2882
2883 MoFEMErrorCode doWork(int side, EntityType type,
2886 const size_t nb_integration_points = getGaussPts().size2();
2887 if (type == zeroType && side == zeroSide) {
2888 dataPtr->resize(nb_integration_points, false);
2889 dataPtr->clear();
2890 }
2891
2892 const auto &local_indices = data.getLocalIndices();
2893 const int nb_dofs = local_indices.size();
2894 if (nb_dofs) {
2895
2896 std::array<double, MAX_DOFS_ON_ENTITY> dot_dofs_vector;
2897 const double *array;
2898 CHKERR VecGetArrayRead(getFEMethod()->ts_u_t, &array);
2899 for (size_t i = 0; i != local_indices.size(); ++i)
2900 if (local_indices[i] != -1)
2901 dot_dofs_vector[i] = array[local_indices[i]];
2902 else
2903 dot_dofs_vector[i] = 0;
2904 CHKERR VecRestoreArrayRead(getFEMethod()->ts_u_t, &array);
2905
2906 const size_t nb_base_functions = data.getN().size2() / Tensor_Dim1;
2907 FTensor::Index<'i', Tensor_Dim1> i;
2908 auto t_n_diff_hdiv = data.getFTensor2DiffN<Tensor_Dim1, Tensor_Dim2>();
2909 auto t_data = getFTensor0FromVec(*dataPtr);
2910 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
2911 int bb = 0;
2912 for (; bb != nb_dofs; ++bb) {
2913 double div = 0;
2914 for (auto ii = 0; ii != Tensor_Dim2; ++ii)
2915 div += t_n_diff_hdiv(ii, ii);
2916 t_data += dot_dofs_vector[bb] * div;
2917 ++t_n_diff_hdiv;
2918 }
2919 for (; bb != nb_base_functions; ++bb)
2920 ++t_n_diff_hdiv;
2921 ++t_data;
2922 }
2923 }
2925 }
2926
2927private:
2928 boost::shared_ptr<VectorDouble> dataPtr;
2930 const int zeroSide;
2931};
2932
2933/**
2934 * @brief Calculate curl of vector field
2935 * @ingroup mofem_forces_and_sources_user_data_operators
2936 *
2937 * @tparam Base_Dim base function dimension
2938 * @tparam Space_Dim dimension of space
2939 * @tparam Hcurl field dimension
2940 */
2941template <int Base_Dim, int Space_Dim> struct OpCalculateHcurlVectorCurl;
2942
2943/**
2944 * @brief Calculate curl of vector field
2945 * @ingroup mofem_forces_and_sources_user_data_operators
2946 *
2947 * @tparam Base_Dim base function dimension
2948 * @tparam Space_Dim dimension of space
2949 * @tparam Hcurl field dimension
2950 */
2951template <>
2954 OpCalculateHcurlVectorCurl(const std::string field_name,
2955 boost::shared_ptr<MatrixDouble> data_ptr,
2956 const EntityType zero_type = MBEDGE,
2957 const int zero_side = 0);
2958 MoFEMErrorCode doWork(int side, EntityType type,
2960
2961private:
2962 boost::shared_ptr<MatrixDouble> dataPtr;
2964 const int zeroSide;
2965};
2966
2967/**
2968 * @brief Calculate curl of vector field
2969 * @ingroup mofem_forces_and_sources_user_data_operators
2970 *
2971 * @tparam Field_Dim dimension of field
2972 * @tparam Space_Dim dimension of space
2973 */
2974template <>
2977
2978 OpCalculateHcurlVectorCurl(const std::string field_name,
2979 boost::shared_ptr<MatrixDouble> data_ptr,
2980 const EntityType zero_type = MBVERTEX,
2981 const int zero_side = 0);
2982
2983 MoFEMErrorCode doWork(int side, EntityType type,
2985
2986private:
2987 boost::shared_ptr<MatrixDouble> dataPtr;
2989 const int zeroSide;
2990};
2991
2992/**
2993 * @brief Calculate curl of vector field
2994 * @ingroup mofem_forces_and_sources_user_data_operators
2995 *
2996 * @tparam Field_Dim dimension of field
2997 * @tparam Space_Dim dimension of space
2998 */
2999template <>
3002
3003 OpCalculateHcurlVectorCurl(const std::string field_name,
3004 boost::shared_ptr<MatrixDouble> data_ptr,
3005 const EntityType zero_type = MBVERTEX,
3006 const int zero_side = 0);
3007
3008 MoFEMErrorCode doWork(int side, EntityType type,
3010
3011private:
3012 boost::shared_ptr<MatrixDouble> dataPtr;
3014 const int zeroSide;
3015};
3016
3017/**
3018 * @brief Calculate tenor field using vectorial base, i.e. Hdiv/Hcurl
3019 * \ingroup mofem_forces_and_sources_user_data_operators
3020 *
3021 * @tparam Tensor_Dim0 rank of the field
3022 * @tparam Tensor_Dim1 dimension of space
3023 */
3024template <int Tensor_Dim0, int Tensor_Dim1>
3027
3029 boost::shared_ptr<MatrixDouble> data_ptr,
3030 boost::shared_ptr<double> scale_ptr,
3032 const EntityType zero_type = MBEDGE,
3033 const int zero_side = 0)
3036 dataPtr(data_ptr), scalePtr(scale_ptr), dataVec(data_vec),
3037 zeroType(zero_type), zeroSide(zero_side) {
3038 if (!dataPtr)
3039 CHK_THROW_MESSAGE(MOFEM_DATA_INCONSISTENCY, "Pointer is not set");
3040 }
3041
3043 boost::shared_ptr<MatrixDouble> data_ptr,
3044 const EntityType zero_type = MBEDGE,
3045 const int zero_side = 0)
3046 : OpCalculateHVecTensorField(field_name, data_ptr, nullptr,
3047 SmartPetscObj<Vec>(), zero_type, zero_side) {
3048 }
3049
3050 MoFEMErrorCode doWork(int side, EntityType type,
3053 const size_t nb_integration_points = getGaussPts().size2();
3055 auto get_data_at_pts =
3057 GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
3058 DL>::size(*dataPtr, nb_integration_points);
3059 if (type == zeroType && side == zeroSide)
3060 dataPtr->clear();
3061 const size_t nb_dofs = data.getFieldData().size();
3062 if (nb_dofs) {
3063
3064 if (dataVec.use_count()) {
3065 dotVector.resize(nb_dofs, false);
3066 const double *array;
3067 CHKERR VecGetArrayRead(dataVec, &array);
3068 const auto &local_indices = data.getLocalIndices();
3069 for (int i = 0; i != local_indices.size(); ++i)
3070 if (local_indices[i] != -1)
3071 dotVector[i] = array[local_indices[i]];
3072 else
3073 dotVector[i] = 0;
3074 CHKERR VecRestoreArrayRead(dataVec, &array);
3075 data.getFieldData().swap(dotVector);
3076 }
3077
3078 double scale = (scalePtr) ? *scalePtr : 1.0;
3079 const size_t nb_base_functions = data.getN().size2() / 3;
3080 FTensor::Index<'i', Tensor_Dim0> i;
3081 FTensor::Index<'j', Tensor_Dim1> j;
3082 auto t_n_hvec = data.getFTensor1N<3>();
3083 auto t_data_at_pts = get_data_at_pts();
3084 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
3085 auto t_dof = data.getFTensor1FieldData<Tensor_Dim0>();
3086 size_t bb = 0;
3087 for (; bb != nb_dofs / Tensor_Dim0; ++bb) {
3088 t_data_at_pts(i, j) += (scale * t_dof(i)) * t_n_hvec(j);
3089 ++t_n_hvec;
3090 ++t_dof;
3091 }
3092 for (; bb < nb_base_functions; ++bb)
3093 ++t_n_hvec;
3094 ++t_data_at_pts;
3095 }
3096
3097 if (dataVec.use_count()) {
3098 data.getFieldData().swap(dotVector);
3099 }
3100 }
3102 }
3103
3104private:
3105 boost::shared_ptr<MatrixDouble> dataPtr;
3106 boost::shared_ptr<double> scalePtr;
3109 const int zeroSide;
3110 VectorDouble dotVector; ///< Keeps temporary values of time derivatives
3111};
3112
3113/** \brief Approximate Hdiv/Hcurl tensor field values for a given PETSc vector
3114 *
3115 * \note Look at PetscData to see what vectors could be extracted with that user
3116 * data operator.
3117 *
3118 * \ingroup mofem_forces_and_sources_user_data_operators
3119 */
3120template <int Tensor_Dim0, int Tensor_Dim1, PetscData::DataContext CTX>
3123
3125 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
3126 const EntityType zero_type = MBEDGE, const int zero_side = 0)
3129 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side) {
3130 if (!dataPtr)
3131 THROW_MESSAGE("Pointer is not set");
3132 }
3133
3134 MoFEMErrorCode doWork(int side, EntityType type,
3137
3138 const size_t nb_integration_points = getGaussPts().size2();
3140 auto get_data_at_pts =
3142 GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
3143 DL>::size(*dataPtr, nb_integration_points);
3144 if (type == zeroType && side == zeroSide)
3145 dataPtr->clear();
3146
3147 const auto &local_indices = data.getLocalIndices();
3148 const size_t nb_dofs = local_indices.size();
3149 if (!nb_dofs)
3151
3152 const double *array;
3153
3154 auto get_array = [&](const auto ctx, auto vec) {
3156 #ifndef NDEBUG
3157 if ((getFEMethod()->data_ctx & ctx).none()) {
3158 MOFEM_LOG_CHANNEL("SELF");
3159 MOFEM_LOG("SELF", Sev::error)
3160 << "In this case field degrees of freedom are read from vector. "
3161 "That usually happens when time solver is used, and access to "
3162 "first or second rates is needed. You probably not set ts_u, "
3163 "ts_u_t, or ts_u_tt and associated data structure, i.e. "
3164 "data_ctx to CTX_SET_X, CTX_SET_DX, CTX_SET_X_T, or "
3165 "CTX_SET_X_TT respectively";
3166 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Vector not set");
3167 }
3168 #endif
3169 CHKERR VecGetArrayRead(vec, &array);
3171 };
3172
3173 auto restore_array = [&](auto vec) {
3174 return VecRestoreArrayRead(vec, &array);
3175 };
3176
3177 switch (CTX) {
3179 CHKERR get_array(PetscData::CtxSetX, getFEMethod()->ts_u);
3180 break;
3182 CHKERR get_array(PetscData::CtxSetX, getFEMethod()->dx);
3183 break;
3185 CHKERR get_array(PetscData::CtxSetX_T, getFEMethod()->ts_u_t);
3186 break;
3188 CHKERR get_array(PetscData::CtxSetX_TT, getFEMethod()->ts_u_tt);
3189 break;
3190 default:
3191 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
3192 "That case is not implemented");
3193 }
3194
3195 dotVector.resize(local_indices.size(), false);
3196 for (int i = 0; i != local_indices.size(); ++i)
3197 if (local_indices[i] != -1)
3198 dotVector[i] = array[local_indices[i]];
3199 else
3200 dotVector[i] = 0;
3201
3202 switch (CTX) {
3204 CHKERR restore_array(getFEMethod()->ts_u);
3205 break;
3207 CHKERR restore_array(getFEMethod()->dx);
3208 break;
3210 CHKERR restore_array(getFEMethod()->ts_u_t);
3211 break;
3213 CHKERR restore_array(getFEMethod()->ts_u_tt);
3214 break;
3215 default:
3216 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
3217 "That case is not implemented");
3218 }
3219
3220 const size_t nb_base_functions = data.getN().size2() / 3;
3221 FTensor::Index<'i', Tensor_Dim0> i;
3222 FTensor::Index<'j', Tensor_Dim1> j;
3223 auto t_n_hvec = data.getFTensor1N<3>();
3224 auto t_data_at_pts = get_data_at_pts();
3225 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
3226 auto t_dof = getFTensor1FromArray<Tensor_Dim0, Tensor_Dim0>(dotVector);
3227 size_t bb = 0;
3228 for (; bb != nb_dofs / Tensor_Dim0; ++bb) {
3229 t_data_at_pts(i, j) += t_dof(i) * t_n_hvec(j);
3230 ++t_n_hvec;
3231 ++t_dof;
3232 }
3233 for (; bb < nb_base_functions; ++bb)
3234 ++t_n_hvec;
3235 ++t_data_at_pts;
3236 }
3237
3239 }
3240
3241private:
3242 boost::shared_ptr<MatrixDouble> dataPtr;
3244 const int zeroSide;
3247};
3248
3249template <int Tensor_Dim0, int Tensor_Dim1>
3251 OpCalculateHVecTensorFieldFromPetscVecImpl<Tensor_Dim0, Tensor_Dim1,
3253
3254/** \brief Approximate tensor field values for a given PETSc vector on a tensor
3255 * basis
3256 *
3257 * \note Look at PetscData to see what vectors could be extracted with that user
3258 * data operator.
3259 *
3260 * \ingroup mofem_forces_and_sources_user_data_operators
3261 */
3262template <int Tensor_Dim0, int Tensor_Dim1, PetscData::DataContext CTX>
3265
3267 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
3268 const EntityType zero_type = MBEDGE, const int zero_side = 0,
3269 bool throw_error = true)
3272 dataPtr(data_ptr), zeroType(zero_type), zeroSide(zero_side),
3273 throwError(throw_error) {
3274 if (!dataPtr)
3275 THROW_MESSAGE("Pointer is not set");
3276 }
3277
3278 MoFEMErrorCode doWork(int side, EntityType type,
3281
3282 const size_t nb_integration_points = getGaussPts().size2();
3284 auto get_data_at_pts =
3286 GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
3287 DL>::size(*dataPtr, nb_integration_points);
3288 if (type == zeroType && side == zeroSide)
3289 dataPtr->clear();
3290
3291 const auto &local_indices = data.getLocalIndices();
3292 const size_t nb_dofs = local_indices.size();
3293 if (!nb_dofs)
3295
3296 if (!throwError) {
3297 if ((getFEMethod()->data_ctx & PetscData::Switches(CTX)).none()) {
3299 }
3300 }
3301
3302 const double *array;
3303
3304 auto get_array = [&](const auto ctx, auto vec) {
3306 #ifndef NDEBUG
3307 if ((getFEMethod()->data_ctx & ctx).none()) {
3308 MOFEM_LOG_CHANNEL("SELF");
3309 MOFEM_LOG("SELF", Sev::error)
3310 << "In this case field degrees of freedom are read from vector. "
3311 "That usually happens when time solver is used, and access to "
3312 "first or second rates is needed. You probably not set ts_u, "
3313 "ts_u_t, or ts_u_tt and associated data structure, i.e. "
3314 "data_ctx to CTX_SET_X, CTX_SET_DX, CTX_SET_X_T, or "
3315 "CTX_SET_X_TT respectively";
3316 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Vector not set");
3317 }
3318 #endif
3319 CHKERR VecGetArrayRead(vec, &array);
3321 };
3322
3323 auto restore_array = [&](auto vec) {
3324 return VecRestoreArrayRead(vec, &array);
3325 };
3326
3327 switch (CTX) {
3329 CHKERR get_array(PetscData::CtxSetX, getFEMethod()->ts_u);
3330 break;
3332 CHKERR get_array(PetscData::CtxSetX, getFEMethod()->dx);
3333 break;
3335 CHKERR get_array(PetscData::CtxSetX_T, getFEMethod()->ts_u_t);
3336 break;
3338 CHKERR get_array(PetscData::CtxSetX_TT, getFEMethod()->ts_u_tt);
3339 break;
3340 default:
3341 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
3342 "That case is not implemented");
3343 }
3344
3345 dotVector.resize(local_indices.size(), false);
3346 for (int i = 0; i != local_indices.size(); ++i)
3347 if (local_indices[i] != -1)
3348 dotVector[i] = array[local_indices[i]];
3349 else
3350 dotVector[i] = 0;
3351
3352 switch (CTX) {
3354 CHKERR restore_array(getFEMethod()->ts_u);
3355 break;
3357 CHKERR restore_array(getFEMethod()->dx);
3358 break;
3360 CHKERR restore_array(getFEMethod()->ts_u_t);
3361 break;
3363 CHKERR restore_array(getFEMethod()->ts_u_tt);
3364 break;
3365 default:
3366 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
3367 "That case is not implemented");
3368 }
3369
3370 const size_t nb_base_functions =
3371 data.getN().size2() / (Tensor_Dim0 * Tensor_Dim1);
3372 FTensor::Index<'i', Tensor_Dim0> i;
3373 FTensor::Index<'j', Tensor_Dim1> j;
3374 auto t_n_hten = data.getFTensor2N<Tensor_Dim0, Tensor_Dim1>();
3375 auto t_data_at_pts = get_data_at_pts();
3376 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
3377 auto t_dof = getFTensor0FromVec(dotVector);
3378 size_t bb = 0;
3379 for (; bb != nb_dofs; ++bb) {
3380 t_data_at_pts(i, j) += t_dof * t_n_hten(i, j);
3381 ++t_n_hten;
3382 ++t_dof;
3383 }
3384 for (; bb < nb_base_functions; ++bb)
3385 ++t_n_hten;
3386 ++t_data_at_pts;
3387 }
3388
3390 }
3391
3392private:
3393 boost::shared_ptr<MatrixDouble> dataPtr;
3395 const int zeroSide;
3398};
3399
3400template <int Tensor_Dim0, int Tensor_Dim1>
3402 OpCalculateHTensorTensorFieldFromPetscVecImpl<Tensor_Dim0, Tensor_Dim1,
3404
3405/** \brief Get tensor field for H-div approximation
3406 * \ingroup mofem_forces_and_sources_user_data_operators
3407 *
3408 * \warning This operator is not tested
3409 */
3410template <int Tensor_Dim0, int Tensor_Dim1>
3413
3415
3417 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
3418 SmartPetscObj<Vec> data_vec, EntityType broken_type,
3419 boost::shared_ptr<Range> broken_range_ptr = nullptr,
3420 boost::shared_ptr<double> scale_ptr = nullptr,
3421 const EntityType zero_type = MBEDGE, const int zero_side = 0)
3423 dataPtr(data_ptr), dataVec(data_vec), brokenType(broken_type),
3424 brokenRangePtr(broken_range_ptr), zeroType(zero_type) {
3425 if (!dataPtr)
3426 CHK_THROW_MESSAGE(MOFEM_DATA_INCONSISTENCY, "Pointer is not set");
3427 }
3428
3429 /**
3430 * \brief Calculate values of vector field at integration points
3431 * @param side side entity number
3432 * @param type side entity type
3433 * @param data entity data
3434 * @return error code
3435 */
3436 MoFEMErrorCode doWork(int side, EntityType type,
3438
3439private:
3440 boost::shared_ptr<MatrixDouble> dataPtr;
3442 EntityType brokenType;
3443 boost::shared_ptr<Range> brokenRangePtr;
3444 boost::shared_ptr<double> scalePtr;
3447};
3448
3449template <int Tensor_Dim0, int Tensor_Dim1>
3452 int side, EntityType type, EntitiesFieldData::EntData &data) {
3454 const size_t nb_integration_points = OP::getGaussPts().size2();
3456 auto get_data_at_pts =
3458 GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
3459 DL>::size(*dataPtr, nb_integration_points);
3460 if (type == zeroType)
3461 dataPtr->clear();
3462 const size_t nb_dofs = data.getFieldData().size();
3463 if (!nb_dofs)
3465
3466 if (dataVec.use_count()) {
3467 dotVector.resize(nb_dofs, false);
3468 const double *array;
3469 CHKERR VecGetArrayRead(dataVec, &array);
3470 const auto &local_indices = data.getLocalIndices();
3471 for (int i = 0; i != local_indices.size(); ++i)
3472 if (local_indices[i] != -1)
3473 dotVector[i] = array[local_indices[i]];
3474 else
3475 dotVector[i] = 0;
3476 CHKERR VecRestoreArrayRead(dataVec, &array);
3477 data.getFieldData().swap(dotVector);
3478 }
3479
3480 /**
3481 * @brief Get side face dofs
3482 *
3483 * Find which base functions on borken space have adjacent given entity type
3484 * and are in the range ptr if given.
3485 *
3486 */
3487 auto get_get_side_face_dofs = [&]() {
3488 auto fe_type = OP::getFEType();
3489
3490 BaseFunction::DofsSideMap &side_dof_map =
3491 data.getFieldEntities()[0]->getDofSideMap().at(fe_type);
3492 std::vector<int> side_face_dofs;
3493 side_face_dofs.reserve(data.getIndices().size() / Tensor_Dim0);
3494
3495 for (
3496
3497 auto it = side_dof_map.get<1>().begin();
3498 it != side_dof_map.get<1>().end(); ++it
3499
3500 ) {
3501 if ((Tensor_Dim0 * it->dof) >= data.getIndices().size()) {
3502 break;
3503 }
3504 if (it->type == brokenType) {
3505 if (brokenRangePtr) {
3506 auto ent = OP::getSideEntity(it->side, brokenType);
3507 if (brokenRangePtr->find(ent) != brokenRangePtr->end()) {
3508 side_face_dofs.push_back(it->dof);
3509 }
3510 } else {
3511 side_face_dofs.push_back(it->dof);
3512 }
3513 }
3514 }
3515
3516 return side_face_dofs;
3517 };
3518
3519 auto side_face_dofs = get_get_side_face_dofs();
3520
3521 FTensor::Index<'i', Tensor_Dim0> i;
3522 FTensor::Index<'j', Tensor_Dim1> j;
3523 auto t_data_at_pts = get_data_at_pts();
3524 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
3525 for (auto b : side_face_dofs) {
3526 auto t_row_base = data.getFTensor1N<3>(gg, b);
3527 auto t_dof = getFTensor1FromPtr<Tensor_Dim0>(data.getFieldData().data() +
3528 b * Tensor_Dim0);
3529 t_data_at_pts(i, j) += t_dof(i) * t_row_base(j);
3530 }
3531 ++t_data_at_pts;
3532 }
3533 *dataPtr *= (scalePtr) ? *scalePtr : 1.0;
3534
3535 if (dataVec.use_count()) {
3536 data.getFieldData().swap(dotVector);
3537 }
3538
3540}
3541
3542/**
3543 * @brief Calculate tenor field using tensor base, i.e. Hdiv/Hcurl
3544 * \ingroup mofem_forces_and_sources_user_data_operators
3545 *
3546 * @tparam Tensor_Dim0 rank of the field
3547 * @tparam Tensor_Dim1 dimension of space
3548 */
3549template <int Tensor_Dim0, int Tensor_Dim1>
3552
3554 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
3555 boost::shared_ptr<double> scale_ptr,
3557 const EntityType zero_type = MBEDGE, const int zero_side = 0)
3560 dataPtr(data_ptr), scalePtr(scale_ptr), dataVec(data_vec),
3561 zeroType(zero_type), zeroSide(zero_side) {
3562 if (!dataPtr)
3563 THROW_MESSAGE("Pointer is not set");
3564 }
3565
3567 boost::shared_ptr<MatrixDouble> data_ptr,
3568 const EntityType zero_type = MBEDGE,
3569 const int zero_side = 0)
3570 : OpCalculateHTensorTensorField(field_name, data_ptr, nullptr,
3571 SmartPetscObj<Vec>(), zero_type,
3572 zero_side) {}
3573
3574 MoFEMErrorCode doWork(int side, EntityType type,
3577 const size_t nb_integration_points = getGaussPts().size2();
3579 auto get_data_at_pts =
3581 GetFTensor2FromMatType<Tensor_Dim0, Tensor_Dim1, -1, DL>,
3582 DL>::size(*dataPtr, nb_integration_points);
3583 if (type == zeroType && side == zeroSide)
3584 dataPtr->clear();
3585 const size_t nb_dofs = data.getFieldData().size();
3586 if (!nb_dofs)
3588
3589 if (dataVec.use_count()) {
3590 dotVector.resize(nb_dofs, false);
3591 const double *array;
3592 CHKERR VecGetArrayRead(dataVec, &array);
3593 const auto &local_indices = data.getLocalIndices();
3594 for (int i = 0; i != local_indices.size(); ++i)
3595 if (local_indices[i] != -1)
3596 dotVector[i] = array[local_indices[i]];
3597 else
3598 dotVector[i] = 0;
3599 CHKERR VecRestoreArrayRead(dataVec, &array);
3600 data.getFieldData().swap(dotVector);
3601 }
3602
3603 double scale = (scalePtr) ? *scalePtr : 1.0;
3604 const size_t nb_base_functions =
3605 data.getN().size2() / (Tensor_Dim0 * Tensor_Dim1);
3606 FTensor::Index<'i', Tensor_Dim0> i;
3607 FTensor::Index<'j', Tensor_Dim1> j;
3608 auto t_n_hten = data.getFTensor2N<Tensor_Dim0, Tensor_Dim1>();
3609 auto t_data_at_pts = get_data_at_pts();
3610 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
3611 auto t_dof = data.getFTensor0FieldData();
3612 size_t bb = 0;
3613 for (; bb != nb_dofs; ++bb) {
3614 t_data_at_pts(i, j) += (scale * t_dof) * t_n_hten(i, j);
3615 ++t_n_hten;
3616 ++t_dof;
3617 }
3618 for (; bb < nb_base_functions; ++bb)
3619 ++t_n_hten;
3620 ++t_data_at_pts;
3621 }
3622
3623 if (dataVec.use_count()) {
3624 data.getFieldData().swap(dotVector);
3625 }
3626
3628 }
3629
3630private:
3631 boost::shared_ptr<MatrixDouble> dataPtr;
3632 boost::shared_ptr<double> scalePtr;
3635 const int zeroSide;
3636 VectorDouble dotVector; ///< Keeps temporary values of time derivatives
3637};
3638
3639/**
3640 * @brief Calculate divergence of tonsorial field using vectorial base
3641 * \ingroup mofem_forces_and_sources_user_data_operators
3642 *
3643 * @tparam Tensor_Dim0 rank of the field
3644 * @tparam Tensor_Dim1 dimension of space
3645 */
3646template <int Tensor_Dim0, int Tensor_Dim1,
3647 CoordinateTypes CoordSys = CARTESIAN>
3650
3652 boost::shared_ptr<MatrixDouble> data_ptr,
3653 SmartPetscObj<Vec> data_vec,
3654 const EntityType zero_type = MBEDGE,
3655 const int zero_side = 0)
3658 dataPtr(data_ptr), dataVec(data_vec), zeroType(zero_type),
3659 zeroSide(zero_side) {
3660 if (!dataPtr)
3661 CHK_THROW_MESSAGE(MOFEM_DATA_INCONSISTENCY, "Pointer is not set");
3662 }
3663
3665 boost::shared_ptr<MatrixDouble> data_ptr,
3666 const EntityType zero_type = MBEDGE,
3667 const int zero_side = 0)
3669 field_name, data_ptr, SmartPetscObj<Vec>(), zero_type, zero_side) {}
3670
3671 MoFEMErrorCode doWork(int side, EntityType type,
3674 const size_t nb_integration_points = getGaussPts().size2();
3675 auto &mat = *dataPtr;
3677 auto get_data_at_pts =
3678 MatrixSizeHelper<GetFTensor1FromMatType<Tensor_Dim0, -1, DL>,
3679 DL>::size(mat, nb_integration_points);
3680 if (type == zeroType && side == zeroSide) {
3681 mat.clear();
3682 }
3683 const size_t nb_dofs = data.getFieldData().size();
3684 if (nb_dofs) {
3685
3686 if (dataVec.use_count()) {
3687 dotVector.resize(nb_dofs, false);
3688 const double *array;
3689 CHKERR VecGetArrayRead(dataVec, &array);
3690 const auto &local_indices = data.getLocalIndices();
3691 for (int i = 0; i != local_indices.size(); ++i)
3692 if (local_indices[i] != -1)
3693 dotVector[i] = array[local_indices[i]];
3694 else
3695 dotVector[i] = 0;
3696 CHKERR VecRestoreArrayRead(dataVec, &array);
3697 data.getFieldData().swap(dotVector);
3698 }
3699
3700 const size_t nb_base_functions = data.getN().size2() / 3;
3701 FTensor::Index<'i', Tensor_Dim0> i;
3702 FTensor::Index<'j', Tensor_Dim1> j;
3703 auto t_n_diff_hvec = data.getFTensor2DiffN<3, Tensor_Dim1>();
3704 auto t_data_at_pts = get_data_at_pts();
3705 auto t_base = data.getFTensor1N<3>();
3706 auto t_coords = getFTensor1CoordsAtGaussPts();
3707 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
3708 auto t_dof = data.getFTensor1FieldData<Tensor_Dim0>();
3709 size_t bb = 0;
3710 for (; bb != nb_dofs / Tensor_Dim0; ++bb) {
3711 double div = t_n_diff_hvec(j, j);
3712 t_data_at_pts(i) += t_dof(i) * div;
3713 if constexpr (CoordSys == CYLINDRICAL) {
3714 t_data_at_pts(i) += t_base(0) * (t_dof(i) / t_coords(0));
3715 }
3716 ++t_n_diff_hvec;
3717 ++t_dof;
3718 ++t_base;
3719 }
3720 for (; bb < nb_base_functions; ++bb) {
3721 ++t_base;
3722 ++t_n_diff_hvec;
3723 }
3724 ++t_data_at_pts;
3725 ++t_coords;
3726 }
3727
3728 if (dataVec.use_count()) {
3729 data.getFieldData().swap(dotVector);
3730 }
3731 }
3733 }
3734
3735private:
3736 boost::shared_ptr<MatrixDouble> dataPtr;
3739 const int zeroSide;
3740
3741 VectorDouble dotVector; ///< Keeps temporary values of time derivatives
3742};
3743
3744/**
3745 * @brief Calculate divergence of tonsorial field using vectorial base
3746 * \ingroup mofem_forces_and_sources_user_data_operators
3747 *
3748 * \warning This operator is not tested
3749 *
3750 * @tparam Tensor_Dim0 rank of the field
3751 * @tparam Tensor_Dim1 dimension of space
3752 */
3753template <int Tensor_Dim0, int Tensor_Dim1,
3754 CoordinateTypes CoordSys = CARTESIAN>
3757
3759
3761 const std::string field_name, boost::shared_ptr<MatrixDouble> data_ptr,
3762 SmartPetscObj<Vec> data_vec, EntityType broken_type,
3763 boost::shared_ptr<Range> broken_range_ptr = nullptr,
3764 boost::shared_ptr<double> scale_ptr = nullptr,
3765 const EntityType zero_type = MBEDGE)
3767 dataPtr(data_ptr), dataVec(data_vec), brokenType(broken_type),
3768 brokenRangePtr(broken_range_ptr), scalePtr(scale_ptr),
3769 zeroType(zero_type) {
3770 if (!dataPtr)
3771 CHK_THROW_MESSAGE(MOFEM_DATA_INCONSISTENCY, "Pointer is not set");
3772 }
3773
3774 MoFEMErrorCode doWork(int side, EntityType type,
3777 const size_t nb_integration_points = getGaussPts().size2();
3778 auto &mat = *dataPtr;
3780 auto get_data_at_pts =
3781 MatrixSizeHelper<GetFTensor1FromMatType<Tensor_Dim0, -1, DL>,
3782 DL>::size(mat, nb_integration_points);
3783 if (type == zeroType && side == 0) {
3784 mat.clear();
3785 }
3786
3787 const size_t nb_dofs = data.getFieldData().size();
3788 if (nb_dofs) {
3789
3790 if (dataVec.use_count()) {
3791 dotVector.resize(nb_dofs, false);
3792 const double *array;
3793 CHKERR VecGetArrayRead(dataVec, &array);
3794 const auto &local_indices = data.getLocalIndices();
3795 for (int i = 0; i != local_indices.size(); ++i)
3796 if (local_indices[i] != -1)
3797 dotVector[i] = array[local_indices[i]];
3798 else
3799 dotVector[i] = 0;
3800 CHKERR VecRestoreArrayRead(dataVec, &array);
3801 data.getFieldData().swap(dotVector);
3802 }
3803
3804 /**
3805 * @brief Get side face dofs
3806 *
3807 * Find which base functions on borken space have adjacent given entity
3808 * type and are in the range ptr if given.
3809 *
3810 */
3811 auto get_get_side_face_dofs = [&]() {
3812 auto fe_type = OP::getFEType();
3813
3814 BaseFunction::DofsSideMap &side_dof_map =
3815 data.getFieldEntities()[0]->getDofSideMap().at(fe_type);
3816 std::vector<int> side_face_dofs;
3817 side_face_dofs.reserve(data.getIndices().size() / Tensor_Dim0);
3818
3819 for (
3820
3821 auto it = side_dof_map.get<1>().begin();
3822 it != side_dof_map.get<1>().end(); ++it
3823
3824 ) {
3825 if ((Tensor_Dim0 * it->dof) >= data.getIndices().size()) {
3826 break;
3827 }
3828 if (it->type == brokenType) {
3829 if (brokenRangePtr) {
3830 auto ent = OP::getSideEntity(it->side, brokenType);
3831 if (brokenRangePtr->find(ent) != brokenRangePtr->end()) {
3832 side_face_dofs.push_back(it->dof);
3833 }
3834 } else {
3835 side_face_dofs.push_back(it->dof);
3836 }
3837 }
3838 }
3839
3840 return side_face_dofs;
3841 };
3842
3843 auto side_face_dofs = get_get_side_face_dofs();
3844
3845 FTensor::Index<'i', Tensor_Dim0> i;
3846 FTensor::Index<'j', Tensor_Dim1> j;
3847 auto t_data_at_pts = get_data_at_pts();
3848 auto t_coords = getFTensor1CoordsAtGaussPts();
3849 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
3850 for (auto b : side_face_dofs) {
3851 auto t_dof = getFTensor1FromPtr<Tensor_Dim0>(
3852 data.getFieldData().data() + b * Tensor_Dim0);
3853 auto t_base = data.getFTensor1N<3>(gg, b);
3854 auto t_diff_base = data.getFTensor2DiffN<3, Tensor_Dim1>(gg, b);
3855 double div = t_diff_base(j, j);
3856 t_data_at_pts(i) += t_dof(i) * div;
3857 if constexpr (CoordSys == CYLINDRICAL) {
3858 t_data_at_pts(i) += t_base(0) * (t_dof(i) / t_coords(0));
3859 }
3860 }
3861 ++t_data_at_pts;
3862 ++t_coords;
3863 }
3864 }
3865
3866 if (dataVec.use_count()) {
3867 data.getFieldData().swap(dotVector);
3868 }
3869
3871 }
3872
3873private:
3874 boost::shared_ptr<MatrixDouble> dataPtr;
3876 EntityType brokenType;
3877 boost::shared_ptr<Range> brokenRangePtr;
3878 boost::shared_ptr<double> scalePtr;
3881};
3882
3883/**
3884 * @brief Calculate trace of vector (Hdiv/Hcurl) space
3885 *
3886 * @tparam Tensor_Dim
3887 * @tparam OpBase
3888 */
3889template <int Tensor_Dim, typename OpBase>
3891
3893 boost::shared_ptr<MatrixDouble> data_ptr,
3894 boost::shared_ptr<double> scale_ptr,
3895 const EntityType zero_type = MBEDGE,
3896 const int zero_side = 0)
3897 : OpBase(field_name, OpBase::OPCOL), dataPtr(data_ptr),
3898 scalePtr(scale_ptr), zeroType(zero_type), zeroSide(zero_side) {
3899 if (!dataPtr)
3900 THROW_MESSAGE("Pointer is not set");
3901 }
3902
3904 boost::shared_ptr<MatrixDouble> data_ptr,
3905 const EntityType zero_type = MBEDGE,
3906 const int zero_side = 0)
3907 : OpCalculateHVecTensorTrace(field_name, data_ptr, nullptr, zero_type,
3908 zero_side) {}
3909
3910 MoFEMErrorCode doWork(int side, EntityType type,
3913 const size_t nb_integration_points = OpBase::getGaussPts().size2();
3914 auto &mat = *dataPtr;
3916 auto get_data_at_pts =
3917 MatrixSizeHelper<GetFTensor1FromMatType<Tensor_Dim, -1, DL>,
3918 DL>::size(mat, nb_integration_points);
3919 if (type == zeroType && side == 0) {
3920 mat.clear();
3921 }
3922 const size_t nb_dofs = data.getFieldData().size();
3923 if (nb_dofs) {
3924 double scale_val = (scalePtr) ? *scalePtr : 1.0;
3925 auto t_normal = OpBase::getFTensor1NormalsAtGaussPts();
3926 const size_t nb_base_functions = data.getN().size2() / 3;
3927 auto t_base = data.getFTensor1N<3>();
3928 auto t_data_at_pts = get_data_at_pts();
3929 for (size_t gg = 0; gg != nb_integration_points; ++gg) {
3930 FTensor::Tensor1<double, Tensor_Dim> t_normalized_normal;
3931 t_normalized_normal(j) = t_normal(j);
3932 t_normalized_normal.normalize();
3933 auto t_dof = data.getFTensor1FieldData<Tensor_Dim>();
3934 size_t bb = 0;
3935 for (; bb != nb_dofs / Tensor_Dim; ++bb) {
3936 t_data_at_pts(i) +=
3937 (scale_val * t_dof(i)) * (t_base(j) * t_normalized_normal(j));
3938 ++t_base;
3939 ++t_dof;
3940 }
3941 for (; bb < nb_base_functions; ++bb) {
3942 ++t_base;
3943 }
3944 ++t_data_at_pts;
3945 ++t_normal;
3946 }
3947 }
3949 }
3950
3951private:
3952 boost::shared_ptr<MatrixDouble> dataPtr;
3953 boost::shared_ptr<double> scalePtr;
3955 const int zeroSide;
3956 FTensor::Index<'i', Tensor_Dim> i;
3957 FTensor::Index<'j', Tensor_Dim> j;
3958};
3959
3960/**@}*/
3961
3962/** \name Other operators */
3963
3964/**@{*/
3965
3966/**@}*/
3967
3968/** \name Operators for faces */
3969
3970/**@{*/
3971
3972/** \brief Transform local reference derivatives of shape functions to global
3973derivatives
3974
3975\ingroup mofem_forces_and_sources_tri_element
3976
3977*/
3978template <int DIM, int DERIVATIVE = 1> struct OpSetInvJacSpaceForFaceImpl;
3979
3982
3984 boost::shared_ptr<MatrixDouble> inv_jac_ptr);
3985
3986protected:
3987 /**
3988 * @brief Apply transformation to the input matrix
3989 *
3990 * @tparam D1 dimension of the derivative of base functions in input
3991 * @tparam D2 dimension of the derivative of base functions in output
3992 * @tparam J1 nb of rows in jacobian (= dimension of space)
3993 * @tparam J2 nb of columns in jacobian (= dimension of reference element)
3994 * @param diff_n
3995 * @return MoFEMErrorCode
3996 */
3997 template <int D1, int D2, int J1, int J2>
4000
4001 static_assert(D2 == J2, "Dimension of jacobian and dimension of <out> "
4002 "directive does not match");
4003
4004 size_t nb_functions = diff_n.size2() / D1;
4005 if (nb_functions) {
4006 size_t nb_gauss_pts = diff_n.size1();
4007
4008 #ifndef NDEBUG
4009 if (nb_gauss_pts != getGaussPts().size2())
4010 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
4011 "Wrong number of Gauss Pts");
4012 if (diff_n.size2() % D1)
4013 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
4014 "Number of directives of base functions and D1 dimension does "
4015 "not match");
4016 #endif
4017
4018 diffNinvJac.resize(diff_n.size1(), D2 * nb_functions, false);
4019
4020 FTensor::Index<'i', D2> i;
4021 FTensor::Index<'k', D1> k;
4022 auto t_diff_n = getFTensor1FromPtr<D2>(&*diffNinvJac.data().begin());
4023 auto t_diff_n_ref = getFTensor1FromPtr<D1>(&*diff_n.data().begin());
4025 auto get_inv_jac_at_pts =
4026 MatrixSizeHelper<GetFTensor2FromMatType<J1, J2, -1, DL>, DL>::get(
4027 *invJacPtr, nb_gauss_pts);
4028 auto t_inv_jac_at_pts = get_inv_jac_at_pts();
4029 for (size_t gg = 0; gg != nb_gauss_pts; ++gg, ++t_inv_jac_at_pts) {
4030 for (size_t dd = 0; dd != nb_functions; ++dd) {
4031 t_diff_n(i) = t_inv_jac_at_pts(k, i) * t_diff_n_ref(k);
4032 ++t_diff_n;
4033 ++t_diff_n_ref;
4034 }
4035 }
4036
4037 diff_n.swap(diffNinvJac);
4038 }
4040 }
4041
4042 boost::shared_ptr<MatrixDouble> invJacPtr;
4044};
4045
4046template <>
4049
4051
4052 MoFEMErrorCode doWork(int side, EntityType type,
4054};
4055
4056template <>
4058 : public OpSetInvJacSpaceForFaceImpl<2, 1> {
4059
4060 using OpSetInvJacSpaceForFaceImpl<2, 1>::OpSetInvJacSpaceForFaceImpl;
4061
4062 MoFEMErrorCode doWork(int side, EntityType type,
4064};
4065
4066template <>
4068 : public OpSetInvJacSpaceForFaceImpl<2, 1> {
4069
4070 using OpSetInvJacSpaceForFaceImpl<2, 1>::OpSetInvJacSpaceForFaceImpl;
4071
4072 MoFEMErrorCode doWork(int side, EntityType type,
4074};
4075
4076template <int DERIVARIVE = 1>
4078 : public OpSetInvJacSpaceForFaceImpl<2, DERIVARIVE> {
4079 OpSetInvJacH1ForFace(boost::shared_ptr<MatrixDouble> inv_jac_ptr)
4080 : OpSetInvJacSpaceForFaceImpl<2, DERIVARIVE>(H1, inv_jac_ptr) {}
4081};
4082
4083template <int DERIVARIVE = 1>
4085 : public OpSetInvJacSpaceForFaceImpl<2, DERIVARIVE> {
4086 OpSetInvJacL2ForFace(boost::shared_ptr<MatrixDouble> inv_jac_ptr)
4087 : OpSetInvJacSpaceForFaceImpl<2, DERIVARIVE>(L2, inv_jac_ptr) {}
4088};
4089
4090template <int DERIVARIVE = 1>
4092 : public OpSetInvJacSpaceForFaceImpl<3, DERIVARIVE> {
4094 boost::shared_ptr<MatrixDouble> inv_jac_ptr)
4095 : OpSetInvJacSpaceForFaceImpl<3, DERIVARIVE>(H1, inv_jac_ptr) {}
4096};
4097
4098template <int DERIVARIVE = 1>
4100 : public OpSetInvJacSpaceForFaceImpl<3, DERIVARIVE> {
4102 boost::shared_ptr<MatrixDouble> inv_jac_ptr)
4103 : OpSetInvJacSpaceForFaceImpl<3, DERIVARIVE>(L2, inv_jac_ptr) {}
4104};
4105
4106/**
4107 * \brief Transform local reference derivatives of shape function to
4108 global derivatives for face
4109
4110 * \ingroup mofem_forces_and_sources_tri_element
4111 */
4112template <int DIM> struct OpSetInvJacHcurlFaceImpl;
4113
4114template <>
4117
4118 OpSetInvJacHcurlFaceImpl(boost::shared_ptr<MatrixDouble> inv_jac_ptr)
4120 invJacPtr(inv_jac_ptr) {}
4121
4122 MoFEMErrorCode doWork(int side, EntityType type,
4124
4125protected:
4126 boost::shared_ptr<MatrixDouble> invJacPtr;
4128};
4129
4130template <>
4132 using OpSetInvJacHcurlFaceImpl<2>::OpSetInvJacHcurlFaceImpl;
4133 MoFEMErrorCode doWork(int side, EntityType type,
4135};
4136
4139
4140/**
4141 * @brief Make Hdiv space from Hcurl space in 2d
4142 * @ingroup mofem_forces_and_sources_tri_element
4143 */
4153
4154/** \brief Transform Hcurl base fluxes from reference element to physical
4155 * triangle
4156 */
4158
4159/** \brief Apply contravariant (Piola) transfer to Hdiv space on face
4160 *
4161 * Covariant Piola transformation
4162 \f[
4163 \psi_i|_t = J^{-1}_{ij}\hat{\psi}_j\\
4164 \left.\frac{\partial \psi_i}{\partial \xi_j}\right|_t
4165 = J^{-1}_{ik}\frac{\partial \hat{\psi}_k}{\partial \xi_j}
4166 \f]
4167
4168 */
4169template <>
4172
4174 boost::shared_ptr<MatrixDouble> inv_jac_ptr);
4175
4176 MoFEMErrorCode doWork(int side, EntityType type,
4178
4179private:
4180 boost::shared_ptr<MatrixDouble> invJacPtr;
4181
4184};
4185
4188
4189/** \brief Apply contravariant (Piola) transfer to Hdiv space on face
4190 *
4191 * \note Hdiv space is generated by Hcurl space in 2d.
4192 *
4193 * Contravariant Piola transformation
4194 * \f[
4195 * \psi_i|_t = \frac{1}{\textrm{det}(J)}J_{ij}\hat{\psi}_j\\
4196 * \left.\frac{\partial \psi_i}{\partial \xi_j}\right|_t
4197 * =
4198 * \frac{1}{\textrm{det}(J)}J_{ik}\frac{\partial \hat{\psi}_k}{\partial \xi_j}
4199 * \f]
4200 *
4201 * \ingroup mofem_forces_and_sources
4202 *
4203 */
4205
4206template <>
4209
4211 boost::shared_ptr<MatrixDouble> jac_ptr)
4213 jacPtr(jac_ptr) {}
4214
4215 MoFEMErrorCode doWork(int side, EntityType type,
4217
4218protected:
4219 boost::shared_ptr<MatrixDouble> jacPtr;
4222};
4223
4224template <>
4228 2>::OpSetContravariantPiolaTransformOnFace2DImpl;
4229
4230 MoFEMErrorCode doWork(int side, EntityType type,
4232};
4233
4238
4239/**@}*/
4240
4241/** \name Operators for edges */
4242
4243/**@{*/
4244
4254
4255/**
4256 * @deprecated Name is deprecated and this is added for backward compatibility
4257 */
4260
4261/**@}*/
4262
4263/** \name Operator for fat prisms */
4264
4265/**@{*/
4266
4267/**
4268 * @brief Operator for fat prism element updating integration weights in the
4269 * volume.
4270 *
4271 * Jacobian on the distorted element is nonconstant. This operator updates
4272 * integration weight on prism to take into account nonconstat jacobian.
4273 *
4274 * \f[
4275 * W_i = w_i \left( \frac{1}{2V} \left\| \frac{\partial \mathbf{x}}{\partial
4276 * \pmb\xi} \right\| \right)
4277 * \f]
4278 * where \f$w_i\f$ is integration weight at integration point \f$i\f$,
4279 * \f$\mathbf{x}\f$ is physical coordinate, and \f$\pmb\xi\f$ is reference
4280 * element coordinate.
4281 *
4282 */
4292
4293/** \brief Calculate inverse of jacobian for face element
4294
4295 It is assumed that face element is XY plane. Applied
4296 only for 2d problems.
4297
4298 FIXME Generalize function for arbitrary face orientation in 3d space
4299 FIXME Calculate to Jacobins for two faces
4300
4301 \ingroup mofem_forces_and_sources_prism_element
4302
4303*/
4306
4307 OpCalculateInvJacForFatPrism(boost::shared_ptr<MatrixDouble> inv_jac_ptr)
4309 invJacPtr(inv_jac_ptr), invJac(*invJacPtr) {}
4310
4314 MoFEMErrorCode doWork(int side, EntityType type,
4316
4317private:
4318 const boost::shared_ptr<MatrixDouble> invJacPtr;
4320};
4321
4322/** \brief Transform local reference derivatives of shape functions to global
4323derivatives
4324
4325FIXME Generalize to curved shapes
4326FIXME Generalize to case that top and bottom face has different shape
4327
4328\ingroup mofem_forces_and_sources_prism_element
4329
4330*/
4333
4334 OpSetInvJacH1ForFatPrism(boost::shared_ptr<MatrixDouble> inv_jac_ptr)
4336 invJacPtr(inv_jac_ptr), invJac(*invJacPtr) {}
4337
4341
4342 MoFEMErrorCode doWork(int side, EntityType type,
4344
4345private:
4346 const boost::shared_ptr<MatrixDouble> invJacPtr;
4349};
4350
4351// Flat prism
4352
4353/** \brief Calculate inverse of jacobian for face element
4354
4355 It is assumed that face element is XY plane. Applied
4356 only for 2d problems.
4357
4358 FIXME Generalize function for arbitrary face orientation in 3d space
4359 FIXME Calculate to Jacobins for two faces
4360
4361 \ingroup mofem_forces_and_sources_prism_element
4362
4363*/
4376
4377/** \brief Transform local reference derivatives of shape functions to global
4378derivatives
4379
4380FIXME Generalize to curved shapes
4381FIXME Generalize to case that top and bottom face has different shape
4382
4383\ingroup mofem_forces_and_sources_prism_element
4384
4385*/
4400
4401/**@}*/
4402
4403/** \name Operation on matrices at integration points */
4404
4405/**@{*/
4406
4407/**
4408 * @brief Operator for inverting matrices at integration points
4409 *
4410 * This template structure computes the inverse of square matrices and their
4411 * determinants at integration points. It's commonly used in finite element
4412 * methods for coordinate transformations, constitutive relations, and other
4413 * matrix operations requiring matrix inversion.
4414 *
4415 * @tparam DIM Dimension of the square matrix to be inverted
4416 */
4417template <int DIM>
4419
4420 /**
4421 * @brief Constructor for matrix inversion operator
4422 *
4423 * @param in_ptr Shared pointer to input matrix to be inverted
4424 * @param det_ptr Shared pointer to vector for storing matrix determinants
4425 * @param out_ptr Shared pointer to output matrix for storing inverted matrices
4426 */
4427 template <typename T>
4428 OpInvertMatrix(boost::shared_ptr<MatrixDouble> in_ptr,
4429 boost::shared_ptr<T> det_ptr,
4430 boost::shared_ptr<MatrixDouble> out_ptr)
4432 outPtr(out_ptr), detPtrVariant(det_ptr) {}
4433
4434 MoFEMErrorCode doWork(int side, EntityType type,
4436
4437private:
4438 boost::shared_ptr<MatrixDouble> inPtr;
4439 boost::shared_ptr<MatrixDouble> outPtr;
4440 std::variant<boost::shared_ptr<VectorDouble>, boost::shared_ptr<MatrixDouble>>
4442};
4443
4444template <int DIM>
4448
4449#ifndef NDEBUG
4450 if (!inPtr)
4451 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
4452 "Pointer for inPtr matrix not allocated");
4453
4454 if (!std::holds_alternative<boost::shared_ptr<VectorDouble>>(detPtrVariant) &&
4455 !std::holds_alternative<boost::shared_ptr<MatrixDouble>>(detPtrVariant)) {
4456 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
4457 "detPtrVariant must hold either VectorDouble or MatrixDouble");
4458 }
4459#endif
4460 const auto nb_integration_pts = inPtr->size1();
4461
4462#ifndef NDEBUG
4463 const auto nb_rows = inPtr->size2();
4464 if (nb_rows != DIM * DIM)
4465 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
4466 "Wrong number of matrix coefficients");
4467#endif
4468
4469 std::visit(
4470 [&](auto ptr) {
4471 using T = std::decay_t<decltype(ptr)>;
4472
4473 if constexpr (std::is_same_v<T, boost::shared_ptr<VectorDouble>>) {
4474 ptr->resize(nb_integration_pts, false);
4475 } else if constexpr (std::is_same_v<T, boost::shared_ptr<MatrixDouble>>) {
4476 ptr->resize(nb_integration_pts, 1, false);
4477 }
4478 },
4479 detPtrVariant);
4480
4482 auto get_in_at_pts =
4483 MatrixSizeHelper<GetFTensor2FromMatType<DIM, DIM, -1, DL>, DL>::get(
4484 *inPtr, nb_integration_pts);
4485
4486 // Calculate determinant
4487 {
4488 auto t_in_at_pts = get_in_at_pts();
4489 auto det_it = std::visit(
4490 [](auto p) -> std::vector<double>::iterator {
4491 return p->data().begin();
4492 },
4493 detPtrVariant);
4494 for (size_t gg = 0; gg != nb_integration_pts; ++gg) {
4495 *det_it = determinantTensor(t_in_at_pts);
4496 ++t_in_at_pts;
4497 ++det_it;
4498 }
4499 }
4500
4501 // Invert jacobian
4502 if (outPtr) {
4503 auto get_out_at_pts =
4504 MatrixSizeHelper<GetFTensor2FromMatType<DIM, DIM, -1, DL>, DL>::size(
4505 *outPtr, nb_integration_pts);
4506 auto t_in_at_pts = get_in_at_pts();
4507 auto t_out_at_pts = get_out_at_pts();
4508 auto det_it = std::visit(
4509 [](auto p) -> std::vector<double>::iterator {
4510 return p->data().begin();
4511 },
4512 detPtrVariant);
4513 for (size_t gg = 0; gg != nb_integration_pts; ++gg) {
4514 CHKERR invertTensor(t_in_at_pts, *det_it, t_out_at_pts);
4515 ++t_in_at_pts;
4516 ++t_out_at_pts;
4517 ++det_it;
4518 }
4519 }
4520
4522}
4523
4524/**@}*/
4525
4526/**
4527 * @brief Operator for calculating the trace of matrices at integration points
4528 *
4529 * This template structure computes the trace (sum of diagonal elements) of
4530 * square matrices at integration points. The trace is commonly used in
4531 * mechanics for calculating volumetric strain, pressure, and other scalar
4532 * quantities derived from tensors.
4533 *
4534 * @tparam DIM Dimension of the square matrix
4535 *
4536 * @ingroup mofem_forces_and_sources
4537 */
4538template <int DIM>
4540
4541 /**
4542 * @brief Constructor for matrix trace calculation operator
4543 *
4544 * @param in_ptr Shared pointer to input matrix for trace calculation
4545 * @param out_ptr Shared pointer to output vector for storing calculated traces
4546 */
4547 OpCalculateTraceFromMat(boost::shared_ptr<MatrixDouble> in_ptr,
4548 boost::shared_ptr<VectorDouble> out_ptr)
4550 outPtr(out_ptr) {}
4551
4552 MoFEMErrorCode doWork(int side, EntityType type,
4554
4555private:
4557 boost::shared_ptr<MatrixDouble> inPtr;
4558 boost::shared_ptr<VectorDouble> outPtr;
4559};
4560
4561template <int DIM>
4566
4567 if (!inPtr)
4568 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
4569 "Pointer for inPtr matrix not allocated");
4570
4571 const auto nb_integration_pts = inPtr->size1();
4572 // Invert jacobian
4573 if (outPtr) {
4575 auto get_in_at_pts =
4576 MatrixSizeHelper<GetFTensor2FromMatType<DIM, DIM, -1, DL>, DL>::get(
4577 *inPtr, nb_integration_pts);
4578 outPtr->resize(nb_integration_pts, false);
4579 auto t_in_at_pts = get_in_at_pts();
4580 auto t_out = getFTensor0FromVec(*outPtr);
4581
4582 for (size_t gg = 0; gg != nb_integration_pts; ++gg) {
4583 t_out = t_in_at_pts(i, i);
4584 ++t_in_at_pts;
4585 ++t_out;
4586 }
4587 }
4588
4590}
4591
4592/**@}*/
4593
4594/** \brief Calculates the trace of an input matrix
4595
4596\ingroup mofem_forces_and_sources
4597
4598*/
4599
4600template <int DIM>
4603
4604 OpCalculateTraceFromSymmMat(boost::shared_ptr<MatrixDouble> in_ptr,
4605 boost::shared_ptr<VectorDouble> out_ptr)
4607 outPtr(out_ptr) {}
4608
4609 MoFEMErrorCode doWork(int side, EntityType type,
4611
4612private:
4614 boost::shared_ptr<MatrixDouble> inPtr;
4615 boost::shared_ptr<VectorDouble> outPtr;
4616};
4617
4618template <int DIM>
4623
4624 if (!inPtr)
4625 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
4626 "Pointer for inPtr matrix not allocated");
4627
4628 const auto nb_integration_pts = inPtr->size1();
4629 // Invert jacobian
4630 if (outPtr) {
4631 outPtr->resize(nb_integration_pts, false);
4633 auto get_in_at_pts =
4635 DL>::get(*inPtr, nb_integration_pts);
4636 auto t_in_at_pts = get_in_at_pts();
4637 auto t_out = getFTensor0FromVec(*outPtr);
4638
4639 for (size_t gg = 0; gg != nb_integration_pts; ++gg) {
4640 t_out = t_in_at_pts(i, i);
4641 ++t_in_at_pts;
4642 ++t_out;
4643 }
4644 }
4645
4647}
4648
4649} // namespace MoFEM
4650
4651#endif // __USER_DATA_OPERATORS_HPP__
4652
4653/**
4654 * \defgroup mofem_forces_and_sources_user_data_operators Users Operators
4655 *
4656 * \brief Classes and functions used to evaluate fields at integration pts,
4657 *jacobians, etc..
4658 *
4659 * \ingroup mofem_forces_and_sources
4660 **/
std::string type
constexpr int SPACE_DIM
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
#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 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.
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
@ 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)
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.
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.
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)
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.
intrusive_ptr for managing petsc objects
double scale
Definition plastic.cpp:124