deal.II version 9.8.0
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
portable_fe_evaluation.h
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2023 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#ifndef dealii_portable_fe_evaluation_h
14#define dealii_portable_fe_evaluation_h
15
16#include <deal.II/base/config.h>
17
19#include <deal.II/base/tensor.h>
21
26#include <deal.II/matrix_free/portable_matrix_free.templates.h>
28
29#include <Kokkos_Core.hpp>
30
32
36namespace Portable
37{
61 template <int dim,
62 int fe_degree,
63 int n_q_points_1d = fe_degree + 1,
64 int n_components_ = 1,
65 typename Number = double>
67 {
68 public:
73 using value_type = std::conditional_t<(n_components_ == 1),
74 Number,
76
80 using gradient_type = std::conditional_t<
81 n_components_ == 1,
83 std::conditional_t<n_components_ == dim,
86
91
95 static constexpr unsigned int dimension = dim;
96
100 static constexpr unsigned int n_components = n_components_;
101
105 static constexpr unsigned int n_q_points =
106 Utilities::pow(n_q_points_1d, dim);
107
112 static constexpr unsigned int tensor_dofs_per_component =
113 Utilities::pow(fe_degree + 1, dim);
114
120 static constexpr unsigned int tensor_dofs_per_cell =
122
132 explicit FEEvaluation(const data_type *data,
133 const unsigned int dof_handler_index = 0);
134
139 int
141
148 const data_type *
150
161
170
179 evaluate(const EvaluationFlags::EvaluationFlags evaluate_flag);
180
188 integrate(const EvaluationFlags::EvaluationFlags integration_flag);
189
196 get_value(const int q_point) const;
197
203 get_dof_value(const int dof_index) const;
204
211 submit_value(const value_type &val_in, const int q_point);
212
219 submit_dof_value(const value_type &value, const int dof_index);
220
227 get_gradient(const int q_point) const;
228
235 submit_gradient(const gradient_type &gradient, const int q_point);
236
245 get_symmetric_gradient(const int q_point) const;
246
254 get_divergence(const int q_point) const;
255
272 submit_divergence(const Number &div_in, const int q_point);
273
282 const int q_point);
283
284 // clang-format off
299 // clang-format on
300 template <typename Functor>
302 apply_for_each_quad_point(const Functor &func);
303
304 private:
305 const unsigned int dof_handler_index;
310 };
311
312
313
314 template <int dim,
315 int fe_degree,
316 int n_q_points_1d,
317 int n_components_,
318 typename Number>
321 FEEvaluation(const data_type *data, const unsigned int dof_handler_index)
323 , data(data)
326 , cell_id(data->team_member.league_rank())
327 {
328 AssertIndexRange(dof_handler_index, data->n_dof_handler);
329
330 Assert(
331 n_components_ == precomputed_data->n_components,
333 "Portable::FEEvaluation initialized with wrong number of components. Should be " +
335 " but the template argument 4 is set to " +
336 Utilities::to_string(n_components_)));
337
338 // TODO: check fe_degree is correct by storing the used FE degree
339 // inside PrecomputedData.
340 }
341
342
343
344 template <int dim,
345 int fe_degree,
346 int n_q_points_1d,
347 int n_components_,
348 typename Number>
355
356
357
358 template <int dim,
359 int fe_degree,
360 int n_q_points_1d,
361 int n_components_,
362 typename Number>
363 DEAL_II_HOST_DEVICE const typename FEEvaluation<dim,
364 fe_degree,
365 n_q_points_1d,
366 n_components_,
367 Number>::data_type *
373
374
375
376 template <int dim,
377 int fe_degree,
378 int n_q_points_1d,
379 int n_components_,
380 typename Number>
384 {
385 // Populate the scratch memory
386 Kokkos::parallel_for(Kokkos::TeamThreadRange(data->team_member,
388 [&](const int &i) {
389 for (unsigned int c = 0; c < n_components_; ++c)
390 shared_data->values(i, c) =
391 src[precomputed_data->local_to_global(
392 i + tensor_dofs_per_component * c, cell_id)];
393 });
394 data->team_member.team_barrier();
395
396 for (unsigned int c = 0; c < n_components_; ++c)
397 {
398 if (precomputed_data->constraint_mask(cell_id * n_components + c) !=
400 unconstrained)
402 data->team_member,
403 precomputed_data->constraint_weights,
404 precomputed_data->constraint_mask(cell_id * n_components + c),
405 Kokkos::subview(shared_data->values, Kokkos::ALL, c));
406 }
407 }
408
409
410
411 template <int dim,
412 int fe_degree,
413 int n_q_points_1d,
414 int n_components_,
415 typename Number>
419 {
420 for (unsigned int c = 0; c < n_components_; ++c)
421 {
422 if (precomputed_data->constraint_mask(cell_id * n_components + c) !=
424 unconstrained)
426 data->team_member,
427 precomputed_data->constraint_weights,
428 precomputed_data->constraint_mask(cell_id * n_components + c),
429 Kokkos::subview(shared_data->values, Kokkos::ALL, c));
430 }
431
432 if (precomputed_data->use_coloring)
433 {
434 Kokkos::parallel_for(
435 Kokkos::TeamThreadRange(data->team_member, tensor_dofs_per_component),
436 [&](const int &i) {
437 for (unsigned int c = 0; c < n_components_; ++c)
438 dst[precomputed_data->local_to_global(
439 i + tensor_dofs_per_component * c, cell_id)] +=
440 shared_data->values(i, c);
441 });
442 }
443 else
444 {
445 Kokkos::parallel_for(
446 Kokkos::TeamThreadRange(data->team_member, tensor_dofs_per_component),
447 [&](const int &i) {
448 for (unsigned int c = 0; c < n_components_; ++c)
449 Kokkos::atomic_add(&dst[precomputed_data->local_to_global(
450 i + (tensor_dofs_per_component)*c, cell_id)],
451 shared_data->values(i, c));
452 });
453 }
454 }
455
456
457
458 template <int dim,
459 int fe_degree,
460 int n_q_points_1d,
461 int n_components,
462 typename Number>
465 const EvaluationFlags::EvaluationFlags evaluation_flag)
466 {
468
469 if (fe_degree >= 0 && fe_degree + 1 == n_q_points_1d &&
470 precomputed_data->element_type ==
471 ElementType::tensor_symmetric_collocation)
472 {
474 dof_handler_index, n_components, evaluation_flag, data);
475 }
476 // '<=' on type means tensor_symmetric or tensor_symmetric_hermite, see
477 // shape_info.h for more details
478 else if (fe_degree >= 0 &&
479 internal::use_collocation_evaluation(fe_degree, n_q_points_1d) &&
480 precomputed_data->element_type <= ElementType::tensor_symmetric)
481 {
483 dim,
484 fe_degree,
485 n_q_points_1d,
488 evaluation_flag,
489 data);
490 }
491 else if (fe_degree >= 0 && precomputed_data->element_type <=
492 ElementType::tensor_symmetric_no_collocation)
493 {
495 evaluate(dof_handler_index, n_components, evaluation_flag, data);
496 }
497 else
498 {
499 Kokkos::abort("The element type is not yet supported by the portable "
500 "matrix-free module.");
501 }
502 }
503
504
505
506 template <int dim,
507 int fe_degree,
508 int n_q_points_1d,
509 int n_components_,
510 typename Number>
513 const EvaluationFlags::EvaluationFlags integration_flag)
514 {
516
517 if (fe_degree >= 0 && fe_degree + 1 == n_q_points_1d &&
518 precomputed_data->element_type ==
519 ElementType::tensor_symmetric_collocation)
520 {
522 integrate(dof_handler_index, n_components, integration_flag, data);
523 }
524 // '<=' on type means tensor_symmetric or tensor_symmetric_hermite, see
525 // shape_info.h for more details
526 else if (fe_degree >= 0 &&
527 internal::use_collocation_evaluation(fe_degree, n_q_points_1d) &&
528 precomputed_data->element_type <= ElementType::tensor_symmetric)
529 {
531 dim,
532 fe_degree,
533 n_q_points_1d,
536 integration_flag,
537 data);
538 }
539 else if (fe_degree >= 0 && precomputed_data->element_type <=
540 ElementType::tensor_symmetric_no_collocation)
541 {
543 integrate(dof_handler_index, n_components, integration_flag, data);
544 }
545 else
546 {
547 Kokkos::abort("The element type is not yet supported by the portable "
548 "matrix-free module.");
549 }
550 }
551
552
553
554 template <int dim,
555 int fe_degree,
556 int n_q_points_1d,
557 int n_components_,
558 typename Number>
560 fe_degree,
561 n_q_points_1d,
562 n_components_,
563 Number>::value_type
565 const int q_point) const
566 {
568 if constexpr (n_components_ == 1)
569 {
570 return shared_data->values(q_point, 0);
571 }
572 else
573 {
574 value_type result;
575 for (unsigned int c = 0; c < n_components; ++c)
576 result[c] = shared_data->values(q_point, c);
577 return result;
578 }
579 }
580
581
582
583 template <int dim,
584 int fe_degree,
585 int n_q_points_1d,
586 int n_components_,
587 typename Number>
589 fe_degree,
590 n_q_points_1d,
591 n_components_,
592 Number>::value_type
594 get_dof_value(const int dof_index) const
595 {
597 if constexpr (n_components_ == 1)
598 {
599 return shared_data->values(dof_index, 0);
600 }
601 else
602 {
603 value_type result;
604 for (unsigned int c = 0; c < n_components; ++c)
605 result[c] = shared_data->values(dof_index, c);
606 return result;
607 }
608 }
609
610
611
612 template <int dim,
613 int fe_degree,
614 int n_q_points_1d,
615 int n_components_,
616 typename Number>
619 submit_value(const value_type &value, const int q_point)
620 {
622 Assert(precomputed_data->JxW.size() > 0,
623 ExcMessage("submit_value() requires precomputed JxW"));
624 if constexpr (n_components_ == 1)
625 {
626 shared_data->values(q_point, 0) =
627 value * precomputed_data->JxW(q_point, cell_id);
628 }
629 else
630 {
631 for (unsigned int c = 0; c < n_components; ++c)
632 shared_data->values(q_point, c) =
633 value[c] * precomputed_data->JxW(q_point, cell_id);
634 }
635 }
636
637
638
639 template <int dim,
640 int fe_degree,
641 int n_q_points_1d,
642 int n_components_,
643 typename Number>
646 submit_dof_value(const value_type &value, const int dof_index)
647 {
649 if constexpr (n_components_ == 1)
650 {
651 shared_data->values(dof_index, 0) = value;
652 }
653 else
654 {
655 for (unsigned int c = 0; c < n_components; ++c)
656 shared_data->values(dof_index, c) = value[c];
657 }
658 }
659
660
661
662 template <int dim,
663 int fe_degree,
664 int n_q_points_1d,
665 int n_components_,
666 typename Number>
668 fe_degree,
669 n_q_points_1d,
670 n_components_,
671 Number>::gradient_type
673 get_gradient(const int q_point) const
674 {
676 Assert(precomputed_data->inv_jacobian.size() > 0,
677 ExcMessage("get_gradient() requires precomputed inv_jacobian"));
678 gradient_type grad;
679
680 if constexpr (n_components_ == 1)
681 {
682 for (unsigned int d_1 = 0; d_1 < dim; ++d_1)
683 {
684 Number tmp = 0.;
685 for (unsigned int d_2 = 0; d_2 < dim; ++d_2)
686 tmp +=
687 precomputed_data->inv_jacobian(q_point, cell_id, d_2, d_1) *
688 shared_data->gradients(q_point, d_2, 0);
689 grad[d_1] = tmp;
690 }
691 }
692 else
693 {
694 for (unsigned int c = 0; c < n_components; ++c)
695 for (unsigned int d_1 = 0; d_1 < dim; ++d_1)
696 {
697 Number tmp = 0.;
698 for (unsigned int d_2 = 0; d_2 < dim; ++d_2)
699 tmp +=
700 precomputed_data->inv_jacobian(q_point, cell_id, d_2, d_1) *
701 shared_data->gradients(q_point, d_2, c);
702 grad[c][d_1] = tmp;
703 }
704 }
705
706 return grad;
707 }
708
709
710
711 template <int dim,
712 int fe_degree,
713 int n_q_points_1d,
714 int n_components_,
715 typename Number>
718 submit_gradient(const gradient_type &gradient, const int q_point)
719 {
721 Assert(precomputed_data->inv_jacobian.size() > 0,
722 ExcMessage("submit_gradient() requires precomputed inv_jacobian"));
723 Assert(precomputed_data->JxW.size() > 0,
724 ExcMessage("submit_gradient() requires precomputed JxW"));
725
726 if constexpr (n_components_ == 1)
727 {
728 for (unsigned int d_1 = 0; d_1 < dim; ++d_1)
729 {
730 Number tmp = 0.;
731 for (unsigned int d_2 = 0; d_2 < dim; ++d_2)
732 tmp +=
733 precomputed_data->inv_jacobian(q_point, cell_id, d_1, d_2) *
734 gradient[d_2];
735 shared_data->gradients(q_point, d_1, 0) =
736 tmp * precomputed_data->JxW(q_point, cell_id);
737 }
738 }
739 else
740 {
741 for (unsigned int c = 0; c < n_components; ++c)
742 for (unsigned int d_1 = 0; d_1 < dim; ++d_1)
743 {
744 Number tmp = 0.;
745 for (unsigned int d_2 = 0; d_2 < dim; ++d_2)
746 tmp +=
747 precomputed_data->inv_jacobian(q_point, cell_id, d_1, d_2) *
748 gradient[c][d_2];
749 shared_data->gradients(q_point, d_1, c) =
750 tmp * precomputed_data->JxW(q_point, cell_id);
751 }
752 }
753 }
754
755
756
757 template <int dim,
758 int fe_degree,
759 int n_q_points_1d,
760 int n_components_,
761 typename Number>
764 get_symmetric_gradient(const int q_point) const
765 {
767 Assert(n_components_ == dim,
768 ExcMessage("Function get_symmetric_gradient() only works when the "
769 "number of components and the number of dimensions are "
770 "equal."));
771
772 return symmetrize(get_gradient(q_point));
773 }
774
775
776
777 template <int dim,
778 int fe_degree,
779 int n_q_points_1d,
780 int n_components_,
781 typename Number>
784 get_divergence(const int q_point) const
785 {
787 Assert(n_components_ == dim,
788 ExcMessage("Function get_divergence() only works when the "
789 "number of components and the number of dimensions are "
790 "equal."));
791 Assert(precomputed_data->inv_jacobian.size() > 0,
792 ExcMessage("get_divergence() requires precomputed inv_jacobian"));
793
794 Number divergence = 0.;
795 for (unsigned int c = 0; c < dim; ++c)
796 for (unsigned int d = 0; d < dim; ++d)
797 divergence += precomputed_data->inv_jacobian(q_point, cell_id, d, c) *
798 shared_data->gradients(q_point, d, c);
799 return divergence;
800 }
801
802
803
804 template <int dim,
805 int fe_degree,
806 int n_q_points_1d,
807 int n_components_,
808 typename Number>
811 submit_divergence(const Number &div_in, const int q_point)
812 {
814 Assert(n_components_ == dim,
815 ExcMessage("Function submit_divergence() only works when the "
816 "number of components and the number of dimensions are "
817 "equal."));
818 Assert(precomputed_data->inv_jacobian.size() > 0,
819 ExcMessage("submit_divergence() requires precomputed inv_jacobian"));
820 Assert(precomputed_data->JxW.size() > 0,
821 ExcMessage("submit_divergence() requires precomputed JxW"));
822
823 for (unsigned int c = 0; c < dim; ++c)
824 for (unsigned int d_1 = 0; d_1 < dim; ++d_1)
825 shared_data->gradients(q_point, d_1, c) =
826 precomputed_data->inv_jacobian(q_point, cell_id, d_1, c) * div_in *
827 precomputed_data->JxW(q_point, cell_id);
828 }
829
830
831
832 template <int dim,
833 int fe_degree,
834 int n_q_points_1d,
835 int n_components_,
836 typename Number>
840 const int q_point)
841 {
843 Assert(n_components_ == dim,
844 ExcMessage("Function submit_symmetric_gradient() only works when "
845 "the number of components and the number of dimensions "
846 "are equal."));
847 Assert(precomputed_data->inv_jacobian.size() > 0,
849 "submit_symmetric_gradient() requires precomputed inv_jacobian"));
850 Assert(precomputed_data->JxW.size() > 0,
851 ExcMessage("submit_symmetric_gradient() requires precomputed JxW"));
852
853 for (unsigned int c = 0; c < dim; ++c)
854 for (unsigned int d_1 = 0; d_1 < dim; ++d_1)
855 {
856 Number tmp = 0.;
857 for (unsigned int d_2 = 0; d_2 < dim; ++d_2)
858 tmp += precomputed_data->inv_jacobian(q_point, cell_id, d_1, d_2) *
859 sym_grad[c][d_2];
860 shared_data->gradients(q_point, d_1, c) =
861 tmp * precomputed_data->JxW(q_point, cell_id);
862 }
863 }
864
865
866
867 template <int dim,
868 int fe_degree,
869 int n_q_points_1d,
870 int n_components_,
871 typename Number>
872 template <typename Functor>
875 apply_for_each_quad_point(const Functor &func)
876 {
877 Kokkos::parallel_for(Kokkos::TeamThreadRange(data->team_member, n_q_points),
878 [&](const int &i) { func(this, i); });
879 data->team_member.team_barrier();
880 }
881
882
883
884#ifndef DOXYGEN
885 template <int dim,
886 int fe_degree,
887 int n_q_points_1d,
888 int n_components_,
889 typename Number>
890 constexpr unsigned int
892 n_q_points;
893#endif
894} // namespace Portable
895
897
898#endif
static constexpr unsigned int n_q_points
SharedData< dim, Number > * shared_data
void integrate(const EvaluationFlags::EvaluationFlags integration_flag)
static constexpr unsigned int dimension
const data_type * get_matrix_free_data()
const MatrixFree< dim, Number >::Data * data
static constexpr unsigned int n_components
void submit_gradient(const gradient_type &gradient, const int q_point)
void submit_divergence(const Number &div_in, const int q_point)
void evaluate(const EvaluationFlags::EvaluationFlags evaluate_flag)
void read_dof_values(const DeviceVector< Number > &src)
Number get_divergence(const int q_point) const
std::conditional_t<(n_components_==1), Number, Tensor< 1, n_components_, Number > > value_type
void distribute_local_to_global(DeviceVector< Number > &dst) const
static constexpr unsigned int tensor_dofs_per_cell
void submit_value(const value_type &val_in, const int q_point)
const MatrixFree< dim, Number >::PrecomputedData * precomputed_data
const unsigned int dof_handler_index
SymmetricTensor< 2, dim, Number > get_symmetric_gradient(const int q_point) const
void submit_dof_value(const value_type &value, const int dof_index)
value_type get_value(const int q_point) const
void submit_symmetric_gradient(const SymmetricTensor< 2, dim, Number > &sym_grad, const int q_point)
static constexpr unsigned int tensor_dofs_per_component
typename MatrixFree< dim, Number >::Data data_type
std::conditional_t< n_components_==1, Tensor< 1, dim, Number >, std::conditional_t< n_components_==dim, Tensor< 2, dim, Number >, Tensor< 1, n_components_, Tensor< 1, dim, Number > > > > gradient_type
gradient_type get_gradient(const int q_point) const
FEEvaluation(const data_type *data, const unsigned int dof_handler_index=0)
value_type get_dof_value(const int dof_index) const
void apply_for_each_quad_point(const Functor &func)
#define DEAL_II_DEPRECATED
Definition config.h:286
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_HOST_DEVICE
Definition config.h:170
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define Assert(cond, exc)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcMessage(std::string arg1)
const bool IsBlockVector< VectorType >::value
EvaluationFlags
The EvaluationFlags enum.
*  *  *  RotationFunction< dim, Number >::RotationFunction Number(dim)
void resolve_hanging_nodes(const Kokkos::TeamPolicy< MemorySpace::Default::kokkos_space::execution_space >::member_type &team_member, Kokkos::View< Number *, MemorySpace::Default::kokkos_space > constraint_weights, const ::internal::MatrixFreeFunctions::ConstraintKinds constraint_mask, ViewType values)
constexpr bool use_collocation_evaluation(const unsigned int fe_degree, const unsigned int n_q_points_1d)
Kokkos::View< Number *, MemorySpace::Default::kokkos_space > DeviceVector
std::string to_string(const number value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:473
constexpr T pow(const T base, const int iexp)
Definition utilities.h:966
static void integrate(const unsigned int dof_handler_index, const unsigned int n_components, const EvaluationFlags::EvaluationFlags integration_flag, const typename MatrixFree< dim, Number >::Data *data)
static void evaluate(const unsigned int dof_handler_index, const unsigned int n_components, const EvaluationFlags::EvaluationFlags evaluation_flag, const typename MatrixFree< dim, Number >::Data *data)
static void evaluate(const unsigned int dof_handler_index, const unsigned int n_components, const EvaluationFlags::EvaluationFlags evaluation_flag, const typename MatrixFree< dim, Number >::Data *data)
static void integrate(const unsigned int dof_handler_index, const unsigned int n_components, const EvaluationFlags::EvaluationFlags integration_flag, const typename MatrixFree< dim, Number >::Data *data)
constexpr SymmetricTensor< 2, dim, Number > symmetrize(const Tensor< 2, dim, Number > &t)