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
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) 2012 - 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
14#ifndef dealii_matrix_free_fe_evaluation_h
15#define dealii_matrix_free_fe_evaluation_h
16
17
18#include <deal.II/base/config.h>
19
26
28
30
43
44#include <type_traits>
45
46
48
49
50
88template <int dim,
89 int n_components_,
90 typename Number,
91 bool is_face,
92 typename VectorizedArrayType>
94 : public FEEvaluationData<dim, VectorizedArrayType, is_face>
95{
96public:
97 using number_type = Number;
98 using value_type =
99 std::conditional_t<n_components_ == 1,
100 VectorizedArrayType,
102 using gradient_type = std::conditional_t<
103 n_components_ == 1,
105 std::conditional_t<
106 n_components_ == dim,
110 using hessian_type = std::conditional_t<
111 n_components_ == 1,
113 std::conditional_t<
114 n_components_ == dim,
117 static constexpr unsigned int dimension = dim;
118 static constexpr unsigned int n_components = n_components_;
119 static constexpr unsigned int n_lanes = VectorizedArrayType::size();
120
158 template <typename VectorType>
159 void
161 const VectorType &src,
162 const unsigned int first_index = 0,
163 const std::bitset<n_lanes> &mask = std::bitset<n_lanes>().flip());
164
196 template <typename VectorType>
197 void
199 const VectorType &src,
200 const unsigned int first_index = 0,
201 const std::bitset<n_lanes> &mask = std::bitset<n_lanes>().flip());
202
234 template <typename VectorType>
235 void
237 VectorType &dst,
238 const unsigned int first_index = 0,
239 const std::bitset<n_lanes> &mask = std::bitset<n_lanes>().flip()) const;
240
279 template <typename VectorType>
280 void
282 VectorType &dst,
283 const unsigned int first_index = 0,
284 const std::bitset<n_lanes> &mask = std::bitset<n_lanes>().flip()) const;
285
289 template <typename VectorType>
290 void
292 VectorType &dst,
293 const unsigned int first_index = 0,
294 const std::bitset<n_lanes> &mask = std::bitset<n_lanes>().flip()) const;
295
297
318 get_dof_value(const unsigned int dof) const;
319
328 void
329 submit_dof_value(const value_type val_in, const unsigned int dof);
330
342 get_value(const unsigned int q_point) const;
343
359 void
360 submit_value(const value_type val_in, const unsigned int q_point);
361
369 template <int n_components_local = n_components,
370 typename = std::enable_if_t<n_components == n_components_local>>
371 void
373 const unsigned int q_point);
374
385 get_gradient(const unsigned int q_point) const;
386
398 get_normal_derivative(const unsigned int q_point) const;
399
414 void
415 submit_gradient(const gradient_type grad_in, const unsigned int q_point);
416
424 template <int dim_ = dim,
425 typename = std::enable_if_t<dim_ == 1 && n_components == dim_>>
426 void
428 const unsigned int q_point);
429
445 void
447 const unsigned int q_point);
448
457 get_hessian(const unsigned int q_point) const;
458
465 get_hessian_diagonal(const unsigned int q_point) const;
466
475 get_laplacian(const unsigned int q_point) const;
476
487 get_normal_hessian(const unsigned int q_point) const;
488
503 void
504 submit_hessian(const hessian_type hessian_in, const unsigned int q_point);
505
521 void
522 submit_normal_hessian(const value_type normal_hessian_in,
523 const unsigned int q_point);
524
532 template <int dim_ = dim, typename = std::enable_if_t<n_components_ == dim_>>
533 VectorizedArrayType
534 get_divergence(const unsigned int q_point) const;
535
551 template <int dim_ = dim, typename = std::enable_if_t<n_components_ == dim_>>
552 void
553 submit_divergence(const VectorizedArrayType div_in,
554 const unsigned int q_point);
555
564 template <int dim_ = dim, typename = std::enable_if_t<n_components_ == dim_>>
566 get_symmetric_gradient(const unsigned int q_point) const;
567
583 template <int dim_ = dim, typename = std::enable_if_t<n_components_ == dim_>>
584 void
587 const unsigned int q_point);
588
597 template <int dim_ = dim,
598 typename = std::enable_if_t<n_components_ == dim_ && dim_ != 1>>
600 get_curl(const unsigned int q_point) const;
601
615 template <int dim_ = dim,
616 typename = std::enable_if_t<n_components_ == dim_ && dim != 1>>
617 void
618 submit_curl(const curl_type curl_in, const unsigned int q_point);
619
639
641
647
648protected:
658 const unsigned int dof_handler_index,
659 const unsigned int first_selected_component,
660 const unsigned int quadrature_index,
661 const unsigned int fe_degree,
662 const unsigned int n_q_points,
663 const bool is_interior_face,
664 const unsigned int active_fe_index,
665 const unsigned int active_quad_index,
666 const unsigned int face_type);
667
705 const Mapping<dim> &mapping,
706 const FiniteElement<dim> &fe,
707 const Quadrature<1> &quadrature,
708 const UpdateFlags update_flags,
709 const unsigned int first_selected_component,
711
719
728
733
740 template <typename VectorType, typename VectorOperation>
741 void
743 const VectorOperation &operation,
744 const std::array<VectorType *, n_components_> &vectors,
745 const std::array<
747 n_components_> &vectors_sm,
748 const std::bitset<n_lanes> &mask,
749 const bool apply_constraints = true) const;
750
758 template <typename VectorType, typename VectorOperation>
759 void
761 const VectorOperation &operation,
762 const std::array<VectorType *, n_components_> &vectors,
763 const std::array<
765 n_components_> &vectors_sm,
766 const std::bitset<n_lanes> &mask) const;
767
775 template <typename VectorType, typename VectorOperation>
776 void
778 const VectorOperation &operation,
779 const std::array<VectorType *, n_components_> &vectors) const;
780
784 void
786
791
796
801 mutable std::vector<types::global_dof_index> local_dof_indices;
802};
803
804
805
1369template <int dim,
1370 int fe_degree,
1371 int n_q_points_1d,
1372 int n_components_,
1373 typename Number,
1374 typename VectorizedArrayType>
1376 n_components_,
1377 Number,
1378 false,
1379 VectorizedArrayType>
1380{
1381 static_assert(
1382 std::is_same_v<Number, typename VectorizedArrayType::value_type>,
1383 "Type of Number and of VectorizedArrayType do not match.");
1384
1385public:
1391
1395 using number_type = Number;
1396
1403
1410
1414 static constexpr unsigned int dimension = dim;
1415
1420 static constexpr unsigned int n_components = n_components_;
1421
1425 static constexpr unsigned int n_lanes = VectorizedArrayType::size();
1426
1435 static constexpr unsigned int static_n_q_points =
1436 Utilities::pow(n_q_points_1d, dim);
1437
1447 static constexpr unsigned int static_dofs_per_component =
1448 Utilities::pow(fe_degree + 1, dim);
1449
1459 static constexpr unsigned int tensor_dofs_per_cell =
1461
1471 static constexpr unsigned int static_dofs_per_cell =
1473
1510 const unsigned int dof_handler_index = 0,
1511 const unsigned int quadrature_index = 0,
1512 const unsigned int first_selected_component = 0,
1515
1524 const std::pair<unsigned int, unsigned int> &range,
1525 const unsigned int dof_handler_index = 0,
1526 const unsigned int quadrature_index = 0,
1527 const unsigned int first_selected_component = 0);
1528
1558 const FiniteElement<dim> &fe,
1559 const Quadrature<1> &quadrature,
1560 const UpdateFlags update_flags,
1561 const unsigned int first_selected_component = 0);
1562
1569 const Quadrature<1> &quadrature,
1570 const UpdateFlags update_flags,
1571 const unsigned int first_selected_component = 0);
1572
1585 const unsigned int first_selected_component = 0);
1586
1594
1601 FEEvaluation &
1603
1612 void
1613 reinit(const unsigned int cell_batch_index);
1614
1621 void
1622 reinit(const std::array<unsigned int, n_lanes> &cell_ids);
1623
1636 template <bool level_dof_access>
1637 void
1639
1650 void
1652
1656 static bool
1657 fast_evaluation_supported(const unsigned int given_degree,
1658 const unsigned int given_n_q_points_1d);
1659
1669 void
1671
1684 void
1685 evaluate(const VectorizedArrayType *values_array,
1686 const EvaluationFlags::EvaluationFlags evaluation_flag);
1687
1701 template <typename VectorType>
1702 void
1703 gather_evaluate(const VectorType &input_vector,
1704 const EvaluationFlags::EvaluationFlags evaluation_flag);
1705
1715 void
1717
1729 void
1731 VectorizedArrayType *values_array,
1732 const bool sum_into_values = false);
1733
1747 template <typename VectorType>
1748 void
1750 VectorType &output_vector);
1751
1757 std_cxx20::ranges::iota_view<unsigned int, unsigned int>
1759
1766 const unsigned int dofs_per_component;
1767
1774 const unsigned int dofs_per_cell;
1775
1783 const unsigned int n_q_points;
1784
1785private:
1790 void
1791 check_template_arguments(const unsigned int fe_no,
1792 const unsigned int first_selected_component);
1793};
1794
1795
1796
1832template <int dim,
1833 int fe_degree,
1834 int n_q_points_1d = fe_degree + 1,
1835 int n_components_ = 1,
1836 typename Number = double,
1837 typename VectorizedArrayType = VectorizedArray<Number>>
1839 n_components_,
1840 Number,
1841 true,
1842 VectorizedArrayType>
1843{
1844 static_assert(
1845 std::is_same_v<Number, typename VectorizedArrayType::value_type>,
1846 "Type of Number and of VectorizedArrayType do not match.");
1847
1848public:
1854
1858 using number_type = Number;
1859
1866
1873
1877 static constexpr unsigned int dimension = dim;
1878
1883 static constexpr unsigned int n_components = n_components_;
1884
1888 static constexpr unsigned int n_lanes = VectorizedArrayType::size();
1889
1899 static constexpr unsigned int static_n_q_points =
1900 Utilities::pow(n_q_points_1d, dim - 1);
1901
1910 static constexpr unsigned int static_n_q_points_cell =
1911 Utilities::pow(n_q_points_1d, dim);
1912
1921 static constexpr unsigned int static_dofs_per_component =
1922 Utilities::pow(fe_degree + 1, dim);
1923
1932 static constexpr unsigned int tensor_dofs_per_cell =
1934
1943 static constexpr unsigned int static_dofs_per_cell =
1945
1989 const bool is_interior_face = true,
1990 const unsigned int dof_handler_index = 0,
1991 const unsigned int quadrature_index = 0,
1992 const unsigned int first_selected_component = 0,
1995 const unsigned int face_type = numbers::invalid_unsigned_int);
1996
2006 const std::pair<unsigned int, unsigned int> &range,
2007 const bool is_interior_face = true,
2008 const unsigned int dof_handler_index = 0,
2009 const unsigned int quadrature_index = 0,
2010 const unsigned int first_selected_component = 0);
2011
2022 void
2023 reinit(const unsigned int face_batch_number);
2024
2032 void
2033 reinit(const unsigned int cell_batch_number, const unsigned int face_number);
2034
2038 static bool
2039 fast_evaluation_supported(const unsigned int given_degree,
2040 const unsigned int given_n_q_points_1d);
2041
2052 void
2054
2067 void
2068 evaluate(const VectorizedArrayType *values_array,
2069 const EvaluationFlags::EvaluationFlags evaluation_flag);
2070
2075 void
2077
2082 void
2083 project_to_face(const VectorizedArrayType *values_array,
2084 const EvaluationFlags::EvaluationFlags evaluation_flag);
2085
2090 void
2092
2104 template <typename VectorType>
2105 void
2106 gather_evaluate(const VectorType &input_vector,
2107 const EvaluationFlags::EvaluationFlags evaluation_flag);
2108
2118 void
2120 const bool sum_into_values = false);
2121
2131 void
2133 VectorizedArrayType *values_array,
2134 const bool sum_into_values = false);
2135
2142 void
2144
2149 void
2151 const bool sum_into_values = false);
2152
2157 void
2159 VectorizedArrayType *values_array,
2160 const bool sum_into_values = false);
2161
2173 template <typename VectorType>
2174 void
2176 VectorType &output_vector);
2177
2181 template <typename VectorType>
2182 void
2183 integrate_scatter(const bool integrate_values,
2184 const bool integrate_gradients,
2185 VectorType &output_vector);
2186
2192 std_cxx20::ranges::iota_view<unsigned int, unsigned int>
2194
2199 bool
2201
2216
2221 unsigned int
2223
2228 unsigned int
2230
2237 const unsigned int dofs_per_component;
2238
2245 const unsigned int dofs_per_cell;
2246
2254 const unsigned int n_q_points;
2255};
2256
2257
2258
2259namespace internal
2260{
2261 namespace MatrixFreeFunctions
2262 {
2263 // a helper function to compute the number of DoFs of a DGP element at
2264 // compile time, depending on the degree
2265 template <int dim, int degree>
2267 {
2268 // this division is always without remainder
2269 static constexpr unsigned int value =
2270 (DGP_dofs_per_component<dim - 1, degree>::value * (degree + dim)) / dim;
2271 };
2272
2273 // base specialization: 1d elements have 'degree+1' degrees of freedom
2274 template <int degree>
2275 struct DGP_dofs_per_component<1, degree>
2276 {
2277 static constexpr unsigned int value = degree + 1;
2278 };
2279 } // namespace MatrixFreeFunctions
2280} // namespace internal
2281
2282
2283/*----------------------- Inline functions ----------------------------------*/
2284
2285#ifndef DOXYGEN
2286
2287
2288namespace internal
2289{
2290 // Extract all internal data pointers and indices in a single function that
2291 // get passed on to the constructor of FEEvaluationData, avoiding to look
2292 // things up multiple times
2293 template <bool is_face,
2294 int dim,
2295 typename Number,
2296 typename VectorizedArrayType>
2298 InitializationData
2299 extract_initialization_data(
2301 const unsigned int dof_handler_index,
2302 const unsigned int first_selected_component,
2303 const unsigned int quadrature_index,
2304 const unsigned int fe_degree,
2305 const unsigned int n_q_points,
2306 const unsigned int active_fe_index_given,
2307 const unsigned int active_quad_index_given,
2308 const unsigned int face_type)
2309 {
2311 InitializationData init_data;
2312
2313 init_data.dof_info = &matrix_free.get_dof_info(dof_handler_index);
2314 init_data.mapping_data =
2315 &internal::MatrixFreeFunctions::
2316 MappingInfoCellsOrFaces<dim, Number, is_face, VectorizedArrayType>::get(
2317 matrix_free.get_mapping_info(), quadrature_index);
2318
2319 init_data.active_fe_index =
2320 fe_degree != numbers::invalid_unsigned_int ?
2321 init_data.dof_info->fe_index_from_degree(first_selected_component,
2322 fe_degree) :
2323 (active_fe_index_given != numbers::invalid_unsigned_int ?
2324 active_fe_index_given :
2325 0);
2326
2327 init_data.active_quad_index =
2328 fe_degree == numbers::invalid_unsigned_int ?
2329 (active_quad_index_given != numbers::invalid_unsigned_int ?
2330 active_quad_index_given :
2332 init_data.active_fe_index,
2333 init_data.mapping_data->descriptor.size() /
2334 (is_face ? std::max<unsigned int>(1, dim - 1) : 1) -
2335 1)) :
2336 init_data.mapping_data->quad_index_from_n_q_points(n_q_points);
2337
2338 init_data.shape_info = &matrix_free.get_shape_info(
2339 dof_handler_index,
2340 quadrature_index,
2341 init_data.dof_info->component_to_base_index[first_selected_component],
2342 init_data.active_fe_index,
2343 init_data.active_quad_index);
2344 init_data.descriptor =
2345 &init_data.mapping_data->descriptor
2346 [is_face ?
2347 (init_data.active_quad_index * std::max<unsigned int>(1, dim - 1) +
2348 (face_type == numbers::invalid_unsigned_int ? 0 : face_type)) :
2349 init_data.active_quad_index];
2350
2351 return init_data;
2352 }
2353} // namespace internal
2354
2355
2356
2357/*----------------------- FEEvaluationBase ----------------------------------*/
2358
2359template <int dim,
2360 int n_components_,
2361 typename Number,
2362 bool is_face,
2363 typename VectorizedArrayType>
2364inline FEEvaluationBase<dim,
2365 n_components_,
2366 Number,
2367 is_face,
2368 VectorizedArrayType>::
2369 FEEvaluationBase(
2371 const unsigned int dof_handler_index,
2372 const unsigned int first_selected_component,
2373 const unsigned int quadrature_index,
2374 const unsigned int fe_degree,
2375 const unsigned int n_q_points,
2376 const bool is_interior_face,
2377 const unsigned int active_fe_index,
2378 const unsigned int active_quad_index,
2379 const unsigned int face_type)
2380 : FEEvaluationData<dim, VectorizedArrayType, is_face>(
2381 internal::extract_initialization_data<is_face>(matrix_free,
2382 dof_handler_index,
2383 first_selected_component,
2384 quadrature_index,
2385 fe_degree,
2386 n_q_points,
2387 active_fe_index,
2388 active_quad_index,
2389 face_type),
2390 is_interior_face,
2391 quadrature_index,
2392 first_selected_component)
2393 , scratch_data_array(matrix_free.acquire_scratch_data())
2394 , matrix_free(&matrix_free)
2395{
2396 this->set_data_pointers(scratch_data_array, n_components_);
2397 Assert(
2398 this->dof_info->start_components.back() == 1 ||
2399 static_cast<int>(n_components_) <=
2400 static_cast<int>(
2401 this->dof_info->start_components
2402 [this->dof_info->component_to_base_index[first_selected_component] +
2403 1]) -
2404 first_selected_component,
2405 ExcMessage(
2406 "You tried to construct a vector-valued evaluator with " +
2407 std::to_string(n_components) +
2408 " components. However, "
2409 "the current base element has only " +
2410 std::to_string(
2411 this->dof_info->start_components
2412 [this->dof_info->component_to_base_index[first_selected_component] +
2413 1] -
2414 first_selected_component) +
2415 " components left when starting from local element index " +
2416 std::to_string(
2417 first_selected_component -
2418 this->dof_info->start_components
2419 [this->dof_info->component_to_base_index[first_selected_component]]) +
2420 " (global index " + std::to_string(first_selected_component) + ")"));
2421
2422 // do not check for correct dimensions of data fields here, should be done
2423 // in derived classes
2424}
2425
2426
2427
2428template <int dim,
2429 int n_components_,
2430 typename Number,
2431 bool is_face,
2432 typename VectorizedArrayType>
2433inline FEEvaluationBase<dim,
2434 n_components_,
2435 Number,
2436 is_face,
2437 VectorizedArrayType>::
2438 FEEvaluationBase(
2439 const Mapping<dim> &mapping,
2440 const FiniteElement<dim> &fe,
2441 const Quadrature<1> &quadrature,
2442 const UpdateFlags update_flags,
2443 const unsigned int first_selected_component,
2444 const FEEvaluationData<dim, VectorizedArrayType, is_face> *other)
2445 : FEEvaluationData<dim, VectorizedArrayType, is_face>(
2446 other != nullptr &&
2447 other->mapped_geometry->get_quadrature() == quadrature ?
2448 other->mapped_geometry :
2449 std::make_shared<internal::MatrixFreeFunctions::
2450 MappingDataOnTheFly<dim, VectorizedArrayType>>(
2451 mapping,
2452 quadrature,
2453 update_flags),
2454 n_components_,
2455 first_selected_component)
2456 , scratch_data_array(new AlignedVector<VectorizedArrayType>())
2457 , matrix_free(nullptr)
2458{
2459 const unsigned int base_element_number =
2460 fe.component_to_base_index(first_selected_component).first;
2461 Assert(fe.element_multiplicity(base_element_number) == 1 ||
2462 fe.element_multiplicity(base_element_number) -
2463 first_selected_component >=
2464 n_components_,
2465 ExcMessage("The underlying element must at least contain as many "
2466 "components as requested by this class"));
2467 (void)base_element_number;
2468
2469 Assert(this->data == nullptr, ExcInternalError());
2470 this->data = new internal::MatrixFreeFunctions::ShapeInfo<Number>(
2471 Quadrature<(is_face ? dim - 1 : dim)>(quadrature),
2472 fe,
2473 fe.component_to_base_index(first_selected_component).first);
2474
2475 this->set_data_pointers(scratch_data_array, n_components_);
2476}
2477
2478
2479
2480template <int dim,
2481 int n_components_,
2482 typename Number,
2483 bool is_face,
2484 typename VectorizedArrayType>
2485inline FEEvaluationBase<dim,
2486 n_components_,
2487 Number,
2488 is_face,
2489 VectorizedArrayType>::
2490 FEEvaluationBase(const FEEvaluationBase<dim,
2491 n_components_,
2492 Number,
2493 is_face,
2494 VectorizedArrayType> &other)
2495 : FEEvaluationData<dim, VectorizedArrayType, is_face>(other)
2496 , scratch_data_array(other.matrix_free == nullptr ?
2497 new AlignedVector<VectorizedArrayType>() :
2498 other.matrix_free->acquire_scratch_data())
2499 , matrix_free(other.matrix_free)
2500{
2501 if (other.matrix_free == nullptr)
2502 {
2503 Assert(other.mapped_geometry.get() != nullptr, ExcInternalError());
2504 this->data =
2505 new internal::MatrixFreeFunctions::ShapeInfo<Number>(*other.data);
2506
2507 // Create deep copy of mapped geometry for use in parallel
2508 this->mapped_geometry =
2509 std::make_shared<internal::MatrixFreeFunctions::
2510 MappingDataOnTheFly<dim, VectorizedArrayType>>(
2511 other.mapped_geometry->get_fe_values().get_mapping(),
2512 other.mapped_geometry->get_quadrature(),
2513 other.mapped_geometry->get_fe_values().get_update_flags());
2514
2515 if constexpr (is_face == false)
2516 this->mapping_data = &this->mapped_geometry->get_data_storage();
2517 else
2518 Assert(false,
2519 ExcNotImplemented("On-the-fly geometry evaluation with "
2520 "face evaluators is not currently "
2521 "implemented!"));
2522
2523 this->cell = 0;
2524
2525 this->jacobian =
2526 this->mapped_geometry->get_data_storage().jacobians[0].begin();
2527 this->J_value =
2528 this->mapped_geometry->get_data_storage().JxW_values.begin();
2529 this->jacobian_gradients =
2530 this->mapped_geometry->get_data_storage().jacobian_gradients[0].begin();
2531 this->jacobian_gradients_non_inverse =
2532 this->mapped_geometry->get_data_storage()
2533 .jacobian_gradients_non_inverse[0]
2534 .begin();
2535 this->quadrature_points =
2536 this->mapped_geometry->get_data_storage().quadrature_points.begin();
2537 }
2538
2539 this->set_data_pointers(scratch_data_array, n_components_);
2540}
2541
2542
2543
2544template <int dim,
2545 int n_components_,
2546 typename Number,
2547 bool is_face,
2548 typename VectorizedArrayType>
2549inline FEEvaluationBase<dim,
2550 n_components_,
2551 Number,
2552 is_face,
2553 VectorizedArrayType> &
2555operator=(const FEEvaluationBase<dim,
2556 n_components_,
2557 Number,
2558 is_face,
2559 VectorizedArrayType> &other)
2560{
2561 // release old memory
2562 if (matrix_free == nullptr)
2563 {
2564 delete this->data;
2565 delete scratch_data_array;
2566 }
2567 else
2568 {
2569 matrix_free->release_scratch_data(scratch_data_array);
2570 }
2571
2573
2574 matrix_free = other.matrix_free;
2575
2576 if (other.matrix_free == nullptr)
2577 {
2578 Assert(other.mapped_geometry.get() != nullptr, ExcInternalError());
2579 this->data =
2580 new internal::MatrixFreeFunctions::ShapeInfo<Number>(*other.data);
2581 scratch_data_array = new AlignedVector<VectorizedArrayType>();
2582
2583 // Create deep copy of mapped geometry for use in parallel
2584 this->mapped_geometry =
2585 std::make_shared<internal::MatrixFreeFunctions::
2586 MappingDataOnTheFly<dim, VectorizedArrayType>>(
2587 other.mapped_geometry->get_fe_values().get_mapping(),
2588 other.mapped_geometry->get_quadrature(),
2589 other.mapped_geometry->get_fe_values().get_update_flags());
2590
2591 if constexpr (is_face == false)
2592 this->mapping_data = &this->mapped_geometry->get_data_storage();
2593 else
2594 Assert(false,
2595 ExcNotImplemented("On-the-fly geometry evaluation with "
2596 "face evaluators is not currently "
2597 "implemented!"));
2598 this->cell = 0;
2599
2600 this->jacobian =
2601 this->mapped_geometry->get_data_storage().jacobians[0].begin();
2602 this->J_value =
2603 this->mapped_geometry->get_data_storage().JxW_values.begin();
2604 this->jacobian_gradients =
2605 this->mapped_geometry->get_data_storage().jacobian_gradients[0].begin();
2606 this->jacobian_gradients_non_inverse =
2607 this->mapped_geometry->get_data_storage()
2608 .jacobian_gradients_non_inverse[0]
2609 .begin();
2610 this->quadrature_points =
2611 this->mapped_geometry->get_data_storage().quadrature_points.begin();
2612 }
2613 else
2614 {
2615 scratch_data_array = matrix_free->acquire_scratch_data();
2616 }
2617
2618 this->set_data_pointers(scratch_data_array, n_components_);
2619
2620 return *this;
2621}
2622
2623
2624
2625template <int dim,
2626 int n_components_,
2627 typename Number,
2628 bool is_face,
2629 typename VectorizedArrayType>
2630inline FEEvaluationBase<dim,
2631 n_components_,
2632 Number,
2633 is_face,
2634 VectorizedArrayType>::~FEEvaluationBase()
2635{
2636 if (matrix_free != nullptr)
2637 {
2638 try
2639 {
2640 matrix_free->release_scratch_data(scratch_data_array);
2641 }
2642 catch (...)
2643 {}
2644 }
2645 else
2646 {
2647 delete scratch_data_array;
2648 delete this->data;
2649 }
2650}
2651
2652
2653
2654template <int dim,
2655 int n_components_,
2656 typename Number,
2657 bool is_face,
2658 typename VectorizedArrayType>
2659inline const MatrixFree<dim, Number, VectorizedArrayType> &
2661 get_matrix_free() const
2662{
2663 Assert(matrix_free != nullptr,
2664 ExcMessage(
2665 "FEEvaluation was not initialized with a MatrixFree object!"));
2666 return *matrix_free;
2667}
2668
2669
2670
2671namespace internal
2672{
2673 // given a block vector return the underlying vector type
2674 // including constness (specified by bool)
2675 template <typename VectorType, bool>
2676 struct ConstBlockVectorSelector;
2677
2678 template <typename VectorType>
2679 struct ConstBlockVectorSelector<VectorType, true>
2680 {
2681 using BaseVectorType = const typename VectorType::BlockType;
2682 };
2683
2684 template <typename VectorType>
2685 struct ConstBlockVectorSelector<VectorType, false>
2686 {
2687 using BaseVectorType = typename VectorType::BlockType;
2688 };
2689
2690 // allows to select between block vectors and non-block vectors, which
2691 // allows to use a unified interface for extracting blocks on block vectors
2692 // and doing nothing on usual vectors
2693 template <typename VectorType, bool>
2694 struct BlockVectorSelector;
2695
2696 template <typename VectorType>
2697 struct BlockVectorSelector<VectorType, true>
2698 {
2699 using BaseVectorType = typename ConstBlockVectorSelector<
2700 VectorType,
2701 std::is_const_v<VectorType>>::BaseVectorType;
2702
2703 static BaseVectorType *
2704 get_vector_component(VectorType &vec, const unsigned int component)
2705 {
2706 AssertIndexRange(component, vec.n_blocks());
2707 return &vec.block(component);
2708 }
2709 };
2710
2711 template <typename VectorType>
2712 struct BlockVectorSelector<VectorType, false>
2713 {
2714 using BaseVectorType = VectorType;
2715
2716 static BaseVectorType *
2717 get_vector_component(VectorType &vec, const unsigned int component)
2718 {
2719 // FEEvaluation allows to combine several vectors from a scalar
2720 // FiniteElement into a "vector-valued" FEEvaluation object with
2721 // multiple components. These components can be extracted with the other
2722 // get_vector_component functions. If we do not get a vector of vectors
2723 // (std::vector<VectorType>, std::vector<VectorType*>, BlockVector), we
2724 // must make sure that we do not duplicate the components in input
2725 // and/or duplicate the resulting integrals. In such a case, we should
2726 // only get the zeroth component in the vector contained set nullptr for
2727 // the others which allows us to catch unintended use in
2728 // read_write_operation.
2729 if (component == 0)
2730 return &vec;
2731 else
2732 return nullptr;
2733 }
2734 };
2735
2736 template <typename VectorType>
2737 struct BlockVectorSelector<std::vector<VectorType>, false>
2738 {
2739 using BaseVectorType = VectorType;
2740
2741 static BaseVectorType *
2742 get_vector_component(std::vector<VectorType> &vec,
2743 const unsigned int component)
2744 {
2745 AssertIndexRange(component, vec.size());
2746 return &vec[component];
2747 }
2748 };
2749
2750 template <typename VectorType>
2751 struct BlockVectorSelector<const std::vector<VectorType>, false>
2752 {
2753 using BaseVectorType = const VectorType;
2754
2755 static const BaseVectorType *
2756 get_vector_component(const std::vector<VectorType> &vec,
2757 const unsigned int component)
2758 {
2759 AssertIndexRange(component, vec.size());
2760 return &vec[component];
2761 }
2762 };
2763
2764 template <typename VectorType>
2765 struct BlockVectorSelector<std::vector<VectorType *>, false>
2766 {
2767 using BaseVectorType = VectorType;
2768
2769 static BaseVectorType *
2770 get_vector_component(std::vector<VectorType *> &vec,
2771 const unsigned int component)
2772 {
2773 AssertIndexRange(component, vec.size());
2774 return vec[component];
2775 }
2776 };
2777
2778 template <typename VectorType>
2779 struct BlockVectorSelector<const std::vector<VectorType *>, false>
2780 {
2781 using BaseVectorType = const VectorType;
2782
2783 static const BaseVectorType *
2784 get_vector_component(const std::vector<VectorType *> &vec,
2785 const unsigned int component)
2786 {
2787 AssertIndexRange(component, vec.size());
2788 return vec[component];
2789 }
2790 };
2791
2792 template <typename VectorType, std::size_t N>
2793 struct BlockVectorSelector<std::array<VectorType *, N>, false>
2794 {
2795 using BaseVectorType = VectorType;
2796
2797 static BaseVectorType *
2798 get_vector_component(std::array<VectorType *, N> &vec,
2799 const unsigned int component)
2800 {
2801 AssertIndexRange(component, vec.size());
2802 return vec[component];
2803 }
2804 };
2805} // namespace internal
2806
2807
2808
2809template <int dim,
2810 int n_components_,
2811 typename Number,
2812 bool is_face,
2813 typename VectorizedArrayType>
2814template <typename VectorType, typename VectorOperation>
2815inline void
2818 const VectorOperation &operation,
2819 const std::array<VectorType *, n_components_> &src,
2820 const std::array<
2821 const std::vector<ArrayView<const typename VectorType::value_type>> *,
2822 n_components_> &src_sm,
2823 const std::bitset<n_lanes> &mask,
2824 const bool apply_constraints) const
2825{
2826 // Case 1: No MatrixFree object given, simple case because we do not need to
2827 // process constraints and need not care about vectorization -> go to
2828 // separate function
2829 if (this->matrix_free == nullptr)
2830 {
2831 read_write_operation_global(operation, src);
2832 return;
2833 }
2834
2835 Assert(this->dof_info != nullptr, ExcNotInitialized());
2836 const internal::MatrixFreeFunctions::DoFInfo &dof_info = *this->dof_info;
2837 Assert(this->matrix_free->indices_initialized() == true, ExcNotInitialized());
2838 if (this->n_fe_components == 1)
2839 for (unsigned int comp = 0; comp < n_components; ++comp)
2840 {
2841 Assert(src[comp] != nullptr,
2842 ExcMessage("The finite element underlying this FEEvaluation "
2843 "object is scalar, but you requested " +
2844 std::to_string(n_components) +
2845 " components via the template argument in "
2846 "FEEvaluation. In that case, you must pass an "
2847 "std::vector<VectorType> or a BlockVector to " +
2848 "read_dof_values and distribute_local_to_global."));
2850 *this->matrix_free,
2851 *this->dof_info);
2852 }
2853 else
2854 {
2856 *this->matrix_free,
2857 *this->dof_info);
2858 }
2859
2860 const bool accesses_exterior_dofs =
2861 this->dof_access_index ==
2863 this->is_interior_face() == false;
2864
2865 // Case 2: contiguous indices which use reduced storage of indices and can
2866 // use vectorized load/store operations -> go to separate function
2867 if (this->cell != numbers::invalid_unsigned_int)
2868 {
2870 this->cell,
2871 dof_info.index_storage_variants[this->dof_access_index].size());
2872
2873 bool is_contiguous = true;
2874 // check if exterior cells are not contiguous (ECL case)
2875 if (accesses_exterior_dofs)
2876 {
2877 const std::array<unsigned int, n_lanes> &cells = this->get_cell_ids();
2878 const unsigned int n_filled_lanes =
2881 [this->cell];
2882 // we have to check all filled lanes which are active in the mask
2883 for (unsigned int v = 0; v < n_filled_lanes; ++v)
2884 if (mask[v] == true &&
2885 dof_info.index_storage_variants
2887 [cells[v] / n_lanes] <
2889 contiguous)
2890 is_contiguous = false;
2891 } // or if cell/face batch is not contiguous
2892 else if (dof_info.index_storage_variants
2893 [is_face ?
2894 this->dof_access_index :
2896 [this->cell] < internal::MatrixFreeFunctions::DoFInfo::
2897 IndexStorageVariants::contiguous)
2898 {
2899 is_contiguous = false;
2900 }
2901
2902 if (is_contiguous)
2903 {
2904 read_write_operation_contiguous(operation, src, src_sm, mask);
2905 return;
2906 }
2907 }
2908
2909 // Case 3: standard operation with one index per degree of freedom -> go on
2910 // here
2911 std::array<unsigned int, n_lanes> cells = this->get_cell_ids();
2912
2913 const bool masking_is_active = mask.count() < n_lanes;
2914 if (masking_is_active)
2915 for (unsigned int v = 0; v < n_lanes; ++v)
2916 if (mask[v] == false)
2918
2919 std::bool_constant<internal::is_vectorizable<VectorType, Number>::value>
2920 vector_selector;
2921
2922 const bool use_vectorized_path =
2923 !(masking_is_active || accesses_exterior_dofs);
2924
2925 const std::size_t dofs_per_component = this->data->dofs_per_component_on_cell;
2926
2927 if (apply_constraints && this->cell != numbers::invalid_unsigned_int &&
2928 dof_info.index_storage_variants
2929 [is_face ? this->dof_access_index :
2931 [this->cell] == internal::MatrixFreeFunctions::DoFInfo::
2932 IndexStorageVariants::interleaved &&
2933 use_vectorized_path)
2934 {
2935 const unsigned int *dof_indices =
2936 dof_info.dof_indices_interleaved.data() +
2937 dof_info.row_starts[this->cell * this->n_fe_components * n_lanes]
2938 .first +
2939 this->dof_info
2940 ->component_dof_indices_offset[this->active_fe_index]
2941 [this->first_selected_component] *
2942 n_lanes;
2943
2944 std::array<typename VectorType::value_type *, n_components> src_ptrs;
2945 if (n_components == 1 || this->n_fe_components == 1)
2946 for (unsigned int comp = 0; comp < n_components; ++comp)
2947 src_ptrs[comp] =
2948 const_cast<typename VectorType::value_type *>(src[comp]->begin());
2949 else
2950 src_ptrs[0] =
2951 const_cast<typename VectorType::value_type *>(src[0]->begin());
2952
2953 if (n_components == 1 || this->n_fe_components == 1)
2954 for (unsigned int i = 0; i < dofs_per_component;
2955 ++i, dof_indices += n_lanes)
2956 for (unsigned int comp = 0; comp < n_components; ++comp)
2957 operation.process_dof_gather(
2958 dof_indices,
2959 *src[comp],
2960 0,
2961 src_ptrs[comp],
2962 this->values_dofs[comp * dofs_per_component + i],
2963 vector_selector);
2964 else
2965 for (unsigned int comp = 0; comp < n_components; ++comp)
2966 for (unsigned int i = 0; i < dofs_per_component;
2967 ++i, dof_indices += n_lanes)
2968 operation.process_dof_gather(
2969 dof_indices,
2970 *src[0],
2971 0,
2972 src_ptrs[0],
2973 this->values_dofs[comp * dofs_per_component + i],
2974 vector_selector);
2975 return;
2976 }
2977
2978 std::array<VectorizedArrayType *, n_components> values_dofs;
2979 for (unsigned int c = 0; c < n_components; ++c)
2980 values_dofs[c] = const_cast<VectorizedArrayType *>(this->values_dofs) +
2981 c * dofs_per_component;
2982
2983 // Allocate pointers, then initialize all of them to nullptrs and
2984 // below overwrite the ones we actually use:
2985 std::array<const unsigned int *, n_lanes> dof_indices;
2986 dof_indices.fill(nullptr);
2987
2988 // Assign the appropriate cell ids for face/cell case and get the pointers
2989 // to the dof indices of the cells on all lanes
2990
2991 bool has_constraints = false;
2992 const unsigned int n_components_read =
2993 this->n_fe_components > 1 ? n_components : 1;
2994
2995 if (is_face)
2996 {
2997 for (unsigned int v = 0; v < n_lanes; ++v)
2998 {
2999 if (cells[v] == numbers::invalid_unsigned_int)
3000 continue;
3001
3002 Assert(cells[v] < dof_info.row_starts.size() - 1, ExcInternalError());
3003 const std::pair<unsigned int, unsigned int> *my_index_start =
3004 &dof_info.row_starts[cells[v] * this->n_fe_components +
3005 this->first_selected_component];
3006
3007 // check whether any of the SIMD lanes has constraints, i.e., the
3008 // constraint indicator which is the second entry of row_starts
3009 // increments on this cell
3010 if (my_index_start[n_components_read].second !=
3011 my_index_start[0].second)
3012 has_constraints = true;
3013
3014 dof_indices[v] =
3015 dof_info.dof_indices.data() + my_index_start[0].first;
3016 }
3017 }
3018 else
3019 {
3020 for (unsigned int v = 0; v < n_lanes; ++v)
3021 {
3022 if (cells[v] == numbers::invalid_unsigned_int)
3023 continue;
3024
3025 const std::pair<unsigned int, unsigned int> *my_index_start =
3026 &dof_info.row_starts[cells[v] * this->n_fe_components +
3027 this->first_selected_component];
3028 if (my_index_start[n_components_read].second !=
3029 my_index_start[0].second)
3030 has_constraints = true;
3031
3032 Assert(my_index_start[n_components_read].first ==
3033 my_index_start[0].first ||
3034 my_index_start[0].first < dof_info.dof_indices.size(),
3035 ExcIndexRange(0,
3036 my_index_start[0].first,
3037 dof_info.dof_indices.size()));
3038 dof_indices[v] =
3039 dof_info.dof_indices.data() + my_index_start[0].first;
3040 }
3041 }
3042
3043 for (unsigned int comp = 0; comp < n_components; ++comp)
3044 for (unsigned int i = 0; i < dofs_per_component; ++i)
3045 operation.process_empty(values_dofs[comp][i]);
3046
3047 // Case where we have no constraints throughout the whole cell: Can go
3048 // through the list of DoFs directly
3049 if (!has_constraints && apply_constraints)
3050 {
3051 if (n_components == 1 || this->n_fe_components == 1)
3052 {
3053 for (unsigned int v = 0; v < n_lanes; ++v)
3054 {
3055 if (cells[v] == numbers::invalid_unsigned_int)
3056 continue;
3057
3058 for (unsigned int i = 0; i < dofs_per_component; ++i)
3059 if (dof_indices[v][i] != numbers::invalid_unsigned_int)
3060 for (unsigned int comp = 0; comp < n_components; ++comp)
3061 operation.process_dof(dof_indices[v][i],
3062 *src[comp],
3063 values_dofs[comp][i][v]);
3064 }
3065 }
3066 else
3067 {
3068 for (unsigned int comp = 0; comp < n_components; ++comp)
3069 for (unsigned int v = 0; v < n_lanes; ++v)
3070 {
3071 if (cells[v] == numbers::invalid_unsigned_int)
3072 continue;
3073
3074 for (unsigned int i = 0; i < dofs_per_component; ++i)
3075 if (dof_indices[v][comp * dofs_per_component + i] !=
3077 operation.process_dof(
3078 dof_indices[v][comp * dofs_per_component + i],
3079 *src[0],
3080 values_dofs[comp][i][v]);
3081 }
3082 }
3083 return;
3084 }
3085
3086 // In the case where there are some constraints to be resolved, loop over
3087 // all vector components that are filled and then over local dofs. ind_local
3088 // holds local number on cell, index iterates over the elements of
3089 // index_local_to_global and dof_indices points to the global indices stored
3090 // in index_local_to_global
3091
3092 for (unsigned int v = 0; v < n_lanes; ++v)
3093 {
3094 if (cells[v] == numbers::invalid_unsigned_int)
3095 continue;
3096
3097 const unsigned int cell_index = cells[v];
3098 const unsigned int cell_dof_index =
3099 cell_index * this->n_fe_components + this->first_selected_component;
3100 unsigned int index_indicators =
3101 dof_info.row_starts[cell_dof_index].second;
3102 unsigned int next_index_indicators =
3103 dof_info.row_starts[cell_dof_index + 1].second;
3104
3105 // For read_dof_values_plain, redirect the dof_indices field to the
3106 // unconstrained indices
3107 if (apply_constraints == false &&
3108 dof_info.row_starts_plain_indices[cell_index] !=
3110 {
3111 dof_indices[v] =
3112 dof_info.plain_dof_indices.data() +
3113 this->dof_info
3114 ->component_dof_indices_offset[this->active_fe_index]
3115 [this->first_selected_component] +
3116 dof_info.row_starts_plain_indices[cell_index];
3117 next_index_indicators = index_indicators;
3118 }
3119
3120 if (n_components == 1 || this->n_fe_components == 1)
3121 {
3122 unsigned int ind_local = 0;
3123 for (; index_indicators != next_index_indicators; ++index_indicators)
3124 {
3125 const std::pair<unsigned short, unsigned short> indicator =
3126 dof_info.constraint_indicator[index_indicators];
3127 // run through values up to next constraint
3128 for (unsigned int j = 0; j < indicator.first; ++j)
3129 if (dof_indices[v][j] != numbers::invalid_unsigned_int)
3130 for (unsigned int comp = 0; comp < n_components; ++comp)
3131 operation.process_dof(dof_indices[v][j],
3132 *src[comp],
3133 values_dofs[comp][ind_local + j][v]);
3134
3135 ind_local += indicator.first;
3136 dof_indices[v] += indicator.first;
3137
3138 // constrained case: build the local value as a linear
3139 // combination of the global value according to constraints
3140 Number value[n_components];
3141 for (unsigned int comp = 0; comp < n_components; ++comp)
3142 operation.pre_constraints(values_dofs[comp][ind_local][v],
3143 value[comp]);
3144
3145 const Number *data_val =
3146 this->matrix_free->constraint_pool_begin(indicator.second);
3147 const Number *end_pool =
3148 this->matrix_free->constraint_pool_end(indicator.second);
3149 for (; data_val != end_pool; ++data_val, ++dof_indices[v])
3150 if (*dof_indices[v] != numbers::invalid_unsigned_int)
3151 for (unsigned int comp = 0; comp < n_components; ++comp)
3152 operation.process_constraint(*dof_indices[v],
3153 *data_val,
3154 *src[comp],
3155 value[comp]);
3156
3157 for (unsigned int comp = 0; comp < n_components; ++comp)
3158 operation.post_constraints(value[comp],
3159 values_dofs[comp][ind_local][v]);
3160 ++ind_local;
3161 }
3162
3163 AssertIndexRange(ind_local, dofs_per_component + 1);
3164
3165 for (; ind_local < dofs_per_component; ++dof_indices[v], ++ind_local)
3166 if (*dof_indices[v] != numbers::invalid_unsigned_int)
3167 for (unsigned int comp = 0; comp < n_components; ++comp)
3168 operation.process_dof(*dof_indices[v],
3169 *src[comp],
3170 values_dofs[comp][ind_local][v]);
3171 }
3172 else
3173 {
3174 // case with vector-valued finite elements where all components are
3175 // included in one single vector. Assumption: first come all entries
3176 // to the first component, then all entries to the second one, and
3177 // so on. This is ensured by the way MatrixFree reads out the
3178 // indices.
3179 for (unsigned int comp = 0; comp < n_components; ++comp)
3180 {
3181 unsigned int ind_local = 0;
3182
3183 // check whether there is any constraint on the current cell
3184 for (; index_indicators != next_index_indicators;
3185 ++index_indicators)
3186 {
3187 const std::pair<unsigned short, unsigned short> indicator =
3188 dof_info.constraint_indicator[index_indicators];
3189
3190 // run through values up to next constraint
3191 for (unsigned int j = 0; j < indicator.first; ++j)
3192 if (dof_indices[v][j] != numbers::invalid_unsigned_int)
3193 operation.process_dof(
3194 dof_indices[v][j],
3195 *src[0],
3196 values_dofs[comp][ind_local + j][v]);
3197 ind_local += indicator.first;
3198 dof_indices[v] += indicator.first;
3199
3200 // constrained case: build the local value as a linear
3201 // combination of the global value according to constraints
3202 Number value;
3203 operation.pre_constraints(values_dofs[comp][ind_local][v],
3204 value);
3205
3206 const Number *data_val =
3207 this->matrix_free->constraint_pool_begin(indicator.second);
3208 const Number *end_pool =
3209 this->matrix_free->constraint_pool_end(indicator.second);
3210
3211 for (; data_val != end_pool; ++data_val, ++dof_indices[v])
3212 if (*dof_indices[v] != numbers::invalid_unsigned_int)
3213 operation.process_constraint(*dof_indices[v],
3214 *data_val,
3215 *src[0],
3216 value);
3217
3218 operation.post_constraints(value,
3219 values_dofs[comp][ind_local][v]);
3220 ++ind_local;
3221 }
3222
3223 AssertIndexRange(ind_local, dofs_per_component + 1);
3224
3225 // get the dof values past the last constraint
3226 for (; ind_local < dofs_per_component;
3227 ++dof_indices[v], ++ind_local)
3228 if (*dof_indices[v] != numbers::invalid_unsigned_int)
3229 {
3230 AssertIndexRange(*dof_indices[v], src[0]->size());
3231 operation.process_dof(*dof_indices[v],
3232 *src[0],
3233 values_dofs[comp][ind_local][v]);
3234 }
3235
3236 if (apply_constraints == true && comp + 1 < n_components)
3237 next_index_indicators =
3238 dof_info.row_starts[cell_dof_index + comp + 2].second;
3239 }
3240 }
3241 }
3242}
3243
3244
3245
3246template <int dim,
3247 int n_components_,
3248 typename Number,
3249 bool is_face,
3250 typename VectorizedArrayType>
3251template <typename VectorType, typename VectorOperation>
3252inline void
3255 const VectorOperation &operation,
3256 const std::array<VectorType *, n_components_> &src) const
3257{
3258 Assert(!local_dof_indices.empty(), ExcNotInitialized());
3259
3260 const std::size_t dofs_per_component = this->data->dofs_per_component_on_cell;
3261 unsigned int index = this->first_selected_component * dofs_per_component;
3262 for (unsigned int comp = 0; comp < n_components; ++comp)
3263 {
3264 for (unsigned int i = 0; i < dofs_per_component; ++i, ++index)
3265 {
3266 operation.process_empty(
3267 this->values_dofs[comp * dofs_per_component + i]);
3268 operation.process_dof_global(
3269 local_dof_indices[this->data->lexicographic_numbering[index]],
3270 *src[0],
3271 this->values_dofs[comp * dofs_per_component + i][0]);
3272 }
3273 }
3274}
3275
3276
3277
3278template <int dim,
3279 int n_components_,
3280 typename Number,
3281 bool is_face,
3282 typename VectorizedArrayType>
3283template <typename VectorType, typename VectorOperation>
3284inline void
3287 const VectorOperation &operation,
3288 const std::array<VectorType *, n_components_> &src,
3289 const std::array<
3290 const std::vector<ArrayView<const typename VectorType::value_type>> *,
3291 n_components_> &vectors_sm,
3292 const std::bitset<n_lanes> &mask) const
3293{
3294 // This functions processes the functions read_dof_values,
3295 // distribute_local_to_global, and set_dof_values with the same code for
3296 // contiguous cell indices (DG case). The distinction between these three
3297 // cases is made by the input VectorOperation that either reads values from
3298 // a vector and puts the data into the local data field or write local data
3299 // into the vector. Certain operations are no-ops for the given use case.
3300
3301 std::bool_constant<internal::is_vectorizable<VectorType, Number>::value>
3302 vector_selector;
3304 is_face ? this->dof_access_index :
3306 const unsigned int n_active_lanes = mask.count();
3307
3308 const internal::MatrixFreeFunctions::DoFInfo &dof_info = *this->dof_info;
3309 const std::vector<unsigned int> &dof_indices_cont =
3310 dof_info.dof_indices_contiguous[ind];
3311
3312 const std::size_t dofs_per_component = this->data->dofs_per_component_on_cell;
3313 std::array<VectorizedArrayType *, n_components> values_dofs{{nullptr}};
3314 for (unsigned int c = 0; c < n_components; ++c)
3315 values_dofs[c] = const_cast<VectorizedArrayType *>(this->values_dofs) +
3316 c * dofs_per_component;
3317
3319
3320 const bool accesses_exterior_dofs =
3321 this->dof_access_index ==
3323 this->is_interior_face() == false;
3324
3325 // Simple case: We have contiguous storage, so we can simply copy out the
3326 // data
3327 if (dof_info.index_storage_variants[ind][this->cell] ==
3329 interleaved_contiguous &&
3330 n_active_lanes == n_lanes && !accesses_exterior_dofs)
3331 {
3332 const unsigned int dof_index =
3333 dof_indices_cont[this->cell * n_lanes] +
3334 this->dof_info
3335 ->component_dof_indices_offset[this->active_fe_index]
3336 [this->first_selected_component] *
3337 n_lanes;
3338 if (n_components == 1 || this->n_fe_components == 1)
3339 for (unsigned int comp = 0; comp < n_components; ++comp)
3340 operation.process_dofs_vectorized(dofs_per_component,
3341 dof_index,
3342 *src[comp],
3343 values_dofs[comp],
3344 vector_selector);
3345 else
3346 operation.process_dofs_vectorized(dofs_per_component * n_components,
3347 dof_index,
3348 *src[0],
3349 values_dofs[0],
3350 vector_selector);
3351 return;
3352 }
3353
3354 const std::array<unsigned int, n_lanes> &cells = this->get_cell_or_face_ids();
3355
3356 // More general case: Must go through the components one by one and apply
3357 // some transformations
3358 const unsigned int n_filled_lanes =
3359 dof_info.n_vectorization_lanes_filled[ind][this->cell];
3360
3361 const bool use_vectorized_path = n_filled_lanes == n_lanes &&
3362 n_active_lanes == n_lanes &&
3363 !accesses_exterior_dofs;
3364
3365 if (vectors_sm[0] != nullptr)
3366 {
3367 const auto compute_vector_ptrs = [&](const unsigned int comp) {
3368 std::array<typename VectorType::value_type *, n_lanes> vector_ptrs{
3369 {nullptr}};
3370
3371 const auto upper_bound =
3372 std::min<unsigned int>(n_filled_lanes, n_lanes);
3373 for (unsigned int v = 0; v < upper_bound; ++v)
3374 {
3375 if (mask[v] == false)
3376 {
3377 vector_ptrs[v] = nullptr;
3378 continue;
3379 }
3380
3383 Assert(ind < dof_info.dof_indices_contiguous_sm.size(),
3384 ExcIndexRange(ind,
3385 0,
3386 dof_info.dof_indices_contiguous_sm.size()));
3387 Assert(
3388 cells[v] < dof_info.dof_indices_contiguous_sm[ind].size(),
3389 ExcIndexRange(cells[v],
3390 0,
3391 dof_info.dof_indices_contiguous_sm[ind].size()));
3392
3393 const auto &temp =
3394 dof_info.dof_indices_contiguous_sm[ind][cells[v]];
3395
3396 if (temp.first != numbers::invalid_unsigned_int)
3397 vector_ptrs[v] = const_cast<typename VectorType::value_type *>(
3398 vectors_sm[comp]->operator[](temp.first).data() + temp.second +
3400 [this->active_fe_index][this->first_selected_component]);
3401 else
3402 vector_ptrs[v] = nullptr;
3403 }
3404 for (unsigned int v = n_filled_lanes; v < n_lanes; ++v)
3405 vector_ptrs[v] = nullptr;
3406
3407 return vector_ptrs;
3408 };
3409
3410 if (use_vectorized_path)
3411 {
3412 if (n_components == 1 || this->n_fe_components == 1)
3413 {
3414 for (unsigned int comp = 0; comp < n_components; ++comp)
3415 {
3416 auto vector_ptrs = compute_vector_ptrs(comp);
3417 operation.process_dofs_vectorized_transpose(
3418 dofs_per_component,
3419 vector_ptrs,
3420 values_dofs[comp],
3421 vector_selector);
3422 }
3423 }
3424 else
3425 {
3426 auto vector_ptrs = compute_vector_ptrs(0);
3427 operation.process_dofs_vectorized_transpose(dofs_per_component *
3428 n_components,
3429 vector_ptrs,
3430 &values_dofs[0][0],
3431 vector_selector);
3432 }
3433 }
3434 else
3435 for (unsigned int comp = 0; comp < n_components; ++comp)
3436 {
3437 auto vector_ptrs = compute_vector_ptrs(
3438 (n_components == 1 || this->n_fe_components == 1) ? comp : 0);
3439
3440 for (unsigned int i = 0; i < dofs_per_component; ++i)
3441 operation.process_empty(values_dofs[comp][i]);
3442
3443 if (n_components == 1 || this->n_fe_components == 1)
3444 {
3445 for (unsigned int v = 0; v < n_filled_lanes; ++v)
3446 if (mask[v] == true)
3447 for (unsigned int i = 0; i < dofs_per_component; ++i)
3448 operation.process_dof(vector_ptrs[v][i],
3449 values_dofs[comp][i][v]);
3450 }
3451 else
3452 {
3453 for (unsigned int v = 0; v < n_filled_lanes; ++v)
3454 if (mask[v] == true)
3455 for (unsigned int i = 0; i < dofs_per_component; ++i)
3456 operation.process_dof(
3457 vector_ptrs[v][i + comp * dofs_per_component],
3458 values_dofs[comp][i][v]);
3459 }
3460 }
3461 return;
3462 }
3463
3464 std::array<unsigned int, n_lanes> dof_indices{
3466 Assert(n_filled_lanes <= n_lanes, ExcInternalError());
3467 for (unsigned int v = 0; v < n_filled_lanes; ++v)
3468 {
3469 Assert(mask[v] == false || cells[v] != numbers::invalid_unsigned_int,
3471 if (mask[v] == true)
3472 dof_indices[v] =
3473 dof_indices_cont[cells[v]] +
3474 this->dof_info
3475 ->component_dof_indices_offset[this->active_fe_index]
3476 [this->first_selected_component] *
3477 dof_info.dof_indices_interleave_strides[ind][cells[v]];
3478 }
3479
3480 // In the case with contiguous cell indices, we know that there are no
3481 // constraints and that the indices within each element are contiguous
3482 if (use_vectorized_path)
3483 {
3484 if (dof_info.index_storage_variants[ind][this->cell] ==
3486 contiguous)
3487 {
3488 if (n_components == 1 || this->n_fe_components == 1)
3489 for (unsigned int comp = 0; comp < n_components; ++comp)
3490 operation.process_dofs_vectorized_transpose(dofs_per_component,
3491 dof_indices.data(),
3492 *src[comp],
3493 values_dofs[comp],
3494 vector_selector);
3495 else
3496 operation.process_dofs_vectorized_transpose(dofs_per_component *
3497 n_components,
3498 dof_indices.data(),
3499 *src[0],
3500 &values_dofs[0][0],
3501 vector_selector);
3502 }
3503 else if (dof_info.index_storage_variants[ind][this->cell] ==
3505 interleaved_contiguous_strided)
3506 {
3507 std::array<typename VectorType::value_type *, n_components> src_ptrs{
3508 {nullptr}};
3509 if (n_components == 1 || this->n_fe_components == 1)
3510 for (unsigned int comp = 0; comp < n_components; ++comp)
3511 src_ptrs[comp] = const_cast<typename VectorType::value_type *>(
3512 src[comp]->begin());
3513 else
3514 src_ptrs[0] =
3515 const_cast<typename VectorType::value_type *>(src[0]->begin());
3516
3517 if (n_components == 1 || this->n_fe_components == 1)
3518 for (unsigned int i = 0; i < dofs_per_component; ++i)
3519 {
3520 for (unsigned int comp = 0; comp < n_components; ++comp)
3521 operation.process_dof_gather(dof_indices.data(),
3522 *src[comp],
3523 i * n_lanes,
3524 src_ptrs[comp] + i * n_lanes,
3525 values_dofs[comp][i],
3526 vector_selector);
3527 }
3528 else
3529 for (unsigned int comp = 0; comp < n_components; ++comp)
3530 for (unsigned int i = 0; i < dofs_per_component; ++i)
3531 {
3532 operation.process_dof_gather(
3533 dof_indices.data(),
3534 *src[0],
3535 (comp * dofs_per_component + i) * n_lanes,
3536 src_ptrs[0] + (comp * dofs_per_component + i) * n_lanes,
3537 values_dofs[comp][i],
3538 vector_selector);
3539 }
3540 }
3541 else
3542 {
3543 Assert(dof_info.index_storage_variants[ind][this->cell] ==
3544 internal::MatrixFreeFunctions::DoFInfo::
3545 IndexStorageVariants::interleaved_contiguous_mixed_strides,
3547 std::array<typename VectorType::value_type *, n_components> src_ptrs{
3548 {nullptr}};
3549 if (n_components == 1 || this->n_fe_components == 1)
3550 for (unsigned int comp = 0; comp < n_components; ++comp)
3551 src_ptrs[comp] = const_cast<typename VectorType::value_type *>(
3552 src[comp]->begin());
3553 else
3554 src_ptrs[0] =
3555 const_cast<typename VectorType::value_type *>(src[0]->begin());
3556
3557 const unsigned int *offsets =
3558 &dof_info.dof_indices_interleave_strides[ind][n_lanes * this->cell];
3559 if (n_components == 1 || this->n_fe_components == 1)
3560 for (unsigned int i = 0; i < dofs_per_component; ++i)
3561 {
3562 for (unsigned int comp = 0; comp < n_components; ++comp)
3563 operation.process_dof_gather(dof_indices.data(),
3564 *src[comp],
3565 0,
3566 src_ptrs[comp],
3567 values_dofs[comp][i],
3568 vector_selector);
3570 for (unsigned int v = 0; v < n_lanes; ++v)
3571 dof_indices[v] += offsets[v];
3572 }
3573 else
3574 for (unsigned int comp = 0; comp < n_components; ++comp)
3575 for (unsigned int i = 0; i < dofs_per_component; ++i)
3576 {
3577 operation.process_dof_gather(dof_indices.data(),
3578 *src[0],
3579 0,
3580 src_ptrs[0],
3581 values_dofs[comp][i],
3582 vector_selector);
3584 for (unsigned int v = 0; v < n_lanes; ++v)
3585 dof_indices[v] += offsets[v];
3586 }
3587 }
3588 }
3589 else
3590 for (unsigned int comp = 0; comp < n_components; ++comp)
3591 {
3592 for (unsigned int i = 0; i < dofs_per_component; ++i)
3593 operation.process_empty(values_dofs[comp][i]);
3594 if (accesses_exterior_dofs)
3595 {
3596 for (unsigned int v = 0; v < n_filled_lanes; ++v)
3597 if (mask[v] == true)
3598 {
3599 if (dof_info.index_storage_variants
3600 [ind][cells[v] / VectorizedArrayType::size()] ==
3601 internal::MatrixFreeFunctions::DoFInfo::
3602 IndexStorageVariants::contiguous)
3603 {
3604 if (n_components == 1 || this->n_fe_components == 1)
3605 {
3606 for (unsigned int i = 0; i < dofs_per_component; ++i)
3607 operation.process_dof(dof_indices[v] + i,
3608 *src[comp],
3609 values_dofs[comp][i][v]);
3610 }
3611 else
3612 {
3613 for (unsigned int i = 0; i < dofs_per_component; ++i)
3614 operation.process_dof(dof_indices[v] + i +
3615 comp * dofs_per_component,
3616 *src[0],
3617 values_dofs[comp][i][v]);
3618 }
3619 }
3620 else
3621 {
3622 const unsigned int offset =
3623 dof_info.dof_indices_interleave_strides[ind][cells[v]];
3624 AssertIndexRange(offset, VectorizedArrayType::size() + 1);
3625 if (n_components == 1 || this->n_fe_components == 1)
3626 {
3627 for (unsigned int i = 0; i < dofs_per_component; ++i)
3628 operation.process_dof(dof_indices[v] + i * offset,
3629 *src[comp],
3630 values_dofs[comp][i][v]);
3631 }
3632 else
3633 {
3634 for (unsigned int i = 0; i < dofs_per_component; ++i)
3635 operation.process_dof(
3636 dof_indices[v] +
3637 (i + comp * dofs_per_component) * offset,
3638 *src[0],
3639 values_dofs[comp][i][v]);
3640 }
3641 }
3642 }
3643 }
3644 else
3645 {
3646 if (dof_info.index_storage_variants[ind][this->cell] ==
3648 contiguous)
3649 {
3650 if (n_components == 1 || this->n_fe_components == 1)
3651 {
3652 for (unsigned int v = 0; v < n_filled_lanes; ++v)
3653 if (mask[v] == true)
3654 for (unsigned int i = 0; i < dofs_per_component; ++i)
3655 operation.process_dof(dof_indices[v] + i,
3656 *src[comp],
3657 values_dofs[comp][i][v]);
3658 }
3659 else
3660 {
3661 for (unsigned int v = 0; v < n_filled_lanes; ++v)
3662 if (mask[v] == true)
3663 for (unsigned int i = 0; i < dofs_per_component; ++i)
3664 operation.process_dof(dof_indices[v] + i +
3665 comp * dofs_per_component,
3666 *src[0],
3667 values_dofs[comp][i][v]);
3668 }
3669 }
3670 else
3671 {
3672 const unsigned int *offsets =
3674 [ind][VectorizedArrayType::size() * this->cell];
3675 for (unsigned int v = 0; v < n_filled_lanes; ++v)
3676 AssertIndexRange(offsets[v], VectorizedArrayType::size() + 1);
3677 if (n_components == 1 || this->n_fe_components == 1)
3678 for (unsigned int v = 0; v < n_filled_lanes; ++v)
3679 {
3680 if (mask[v] == true)
3681 for (unsigned int i = 0; i < dofs_per_component; ++i)
3682 operation.process_dof(dof_indices[v] + i * offsets[v],
3683 *src[comp],
3684 values_dofs[comp][i][v]);
3685 }
3686 else
3687 {
3688 for (unsigned int v = 0; v < n_filled_lanes; ++v)
3689 if (mask[v] == true)
3690 for (unsigned int i = 0; i < dofs_per_component; ++i)
3691 operation.process_dof(
3692 dof_indices[v] +
3693 (i + comp * dofs_per_component) * offsets[v],
3694 *src[0],
3695 values_dofs[comp][i][v]);
3696 }
3697 }
3698 }
3699 }
3700}
3701
3702namespace internal
3703{
3704 template <
3705 typename Number,
3706 typename VectorType,
3707 std::enable_if_t<!IsBlockVector<VectorType>::value, VectorType> * = nullptr>
3708 decltype(std::declval<VectorType>().begin())
3709 get_beginning(VectorType &vec)
3710 {
3711 return vec.begin();
3712 }
3713
3714 template <
3715 typename Number,
3716 typename VectorType,
3717 std::enable_if_t<IsBlockVector<VectorType>::value, VectorType> * = nullptr>
3718 typename VectorType::value_type *
3719 get_beginning(VectorType &)
3720 {
3721 return nullptr;
3722 }
3723
3724 template <typename VectorType,
3725 std::enable_if_t<has_shared_vector_data<VectorType>, VectorType> * =
3726 nullptr>
3727 const std::vector<ArrayView<const typename VectorType::value_type>> *
3728 get_shared_vector_data(VectorType *vec,
3729 const bool is_valid_mode_for_sm,
3730 const unsigned int active_fe_index,
3731 const internal::MatrixFreeFunctions::DoFInfo *dof_info)
3732 {
3733 // note: no hp is supported
3734 if (is_valid_mode_for_sm &&
3735 dof_info->dof_indices_contiguous_sm[0 /*any index (<3) should work*/]
3736 .size() > 0 &&
3737 active_fe_index == 0)
3738 return &vec->shared_vector_data();
3739 else
3740 return nullptr;
3741 }
3742
3743 template <typename VectorType,
3744 std::enable_if_t<!has_shared_vector_data<VectorType>, VectorType>
3745 * = nullptr>
3746 const std::vector<ArrayView<const typename VectorType::value_type>> *
3747 get_shared_vector_data(VectorType *,
3748 const bool,
3749 const unsigned int,
3750 const internal::MatrixFreeFunctions::DoFInfo *)
3751 {
3752 return nullptr;
3753 }
3754
3755 template <int n_components, typename VectorType>
3756 std::pair<
3757 std::array<typename internal::BlockVectorSelector<
3758 VectorType,
3759 IsBlockVector<VectorType>::value>::BaseVectorType *,
3760 n_components>,
3761 std::array<
3762 const std::vector<ArrayView<const typename internal::BlockVectorSelector<
3763 VectorType,
3764 IsBlockVector<VectorType>::value>::BaseVectorType::value_type>> *,
3765 n_components>>
3766 get_vector_data(VectorType &src,
3767 const unsigned int first_index,
3768 const bool is_valid_mode_for_sm,
3769 const unsigned int active_fe_index,
3770 const internal::MatrixFreeFunctions::DoFInfo *dof_info)
3771 {
3772 // select between block vectors and non-block vectors. Note that the number
3773 // of components is checked in the internal data
3774 std::pair<
3775 std::array<typename internal::BlockVectorSelector<
3776 VectorType,
3777 IsBlockVector<VectorType>::value>::BaseVectorType *,
3778 n_components>,
3779 std::array<
3780 const std::vector<
3781 ArrayView<const typename internal::BlockVectorSelector<
3782 VectorType,
3783 IsBlockVector<VectorType>::value>::BaseVectorType::value_type>> *,
3784 n_components>>
3785 src_data;
3786
3787 for (unsigned int d = 0; d < n_components; ++d)
3788 src_data.first[d] = internal::BlockVectorSelector<
3789 VectorType,
3790 IsBlockVector<VectorType>::value>::get_vector_component(src,
3791 d +
3792 first_index);
3793
3794 for (unsigned int d = 0; d < n_components; ++d)
3795 src_data.second[d] = get_shared_vector_data(
3796 const_cast<typename internal::BlockVectorSelector<
3797 std::remove_const_t<VectorType>,
3798 IsBlockVector<std::remove_const_t<VectorType>>::value>::BaseVectorType
3799 *>(src_data.first[d]),
3800 is_valid_mode_for_sm,
3801 active_fe_index,
3802 dof_info);
3803
3804 return src_data;
3805 }
3806} // namespace internal
3807
3808
3809
3810template <int dim,
3811 int n_components_,
3812 typename Number,
3813 bool is_face,
3814 typename VectorizedArrayType>
3815inline void
3818{
3819 if (this->dof_info == nullptr ||
3820 this->dof_info->hanging_node_constraint_masks.empty() ||
3821 this->dof_info->hanging_node_constraint_masks_comp.empty() ||
3822 this->dof_info->hanging_node_constraint_masks_comp
3823 [this->active_fe_index][this->first_selected_component] == false)
3824 return; // nothing to do with faces
3825
3826 std::array<internal::MatrixFreeFunctions::compressed_constraint_kind, n_lanes>
3827 constraint_mask{{internal::MatrixFreeFunctions::
3828 unconstrained_compressed_constraint_kind}};
3829
3830 bool hn_available = false;
3831
3832 const std::array<unsigned int, n_lanes> &cells = this->get_cell_ids();
3833
3834 for (unsigned int v = 0; v < n_lanes; ++v)
3835 {
3836 if (cells[v] == numbers::invalid_unsigned_int)
3837 {
3838 constraint_mask[v] = internal::MatrixFreeFunctions::
3839 unconstrained_compressed_constraint_kind;
3840 continue;
3841 }
3842
3843 const unsigned int cell_index = cells[v];
3844 const auto mask =
3845 this->dof_info->hanging_node_constraint_masks[cell_index];
3846 constraint_mask[v] = mask;
3847
3848 hn_available |= (mask != internal::MatrixFreeFunctions::
3849 unconstrained_compressed_constraint_kind);
3850 }
3851
3852 if (hn_available == false)
3853 return; // no hanging node on cell batch -> nothing to do
3854
3856 apply(n_components,
3857 this->data->data.front().fe_degree,
3858 this->get_shape_info(),
3859 transpose,
3860 constraint_mask,
3861 this->values_dofs);
3862}
3863
3864
3865
3866template <int dim,
3867 int n_components_,
3868 typename Number,
3869 bool is_face,
3870 typename VectorizedArrayType>
3871template <typename VectorType>
3872inline void
3874 read_dof_values(const VectorType &src,
3875 const unsigned int first_index,
3876 const std::bitset<n_lanes> &mask)
3877{
3878 const auto src_data = internal::get_vector_data<n_components_>(
3879 src,
3880 first_index,
3881 this->dof_info != nullptr &&
3882 this->dof_access_index ==
3884 this->active_fe_index,
3885 this->dof_info);
3886
3887 internal::VectorReader<Number, VectorizedArrayType> reader;
3888 read_write_operation(reader, src_data.first, src_data.second, mask, true);
3889
3890 apply_hanging_node_constraints(false);
3891
3892 if constexpr (running_in_debug_mode())
3893 {
3894 this->dof_values_initialized = true;
3895 }
3896}
3897
3898
3899
3900template <int dim,
3901 int n_components_,
3902 typename Number,
3903 bool is_face,
3904 typename VectorizedArrayType>
3905template <typename VectorType>
3906inline void
3908 read_dof_values_plain(const VectorType &src,
3909 const unsigned int first_index,
3910 const std::bitset<n_lanes> &mask)
3911{
3912 const auto src_data = internal::get_vector_data<n_components_>(
3913 src,
3914 first_index,
3915 this->dof_info != nullptr &&
3916 this->dof_access_index ==
3918 this->active_fe_index,
3919 this->dof_info);
3920
3921 internal::VectorReader<Number, VectorizedArrayType> reader;
3922 read_write_operation(reader, src_data.first, src_data.second, mask, false);
3923
3924 if constexpr (running_in_debug_mode())
3925 {
3926 this->dof_values_initialized = true;
3927 }
3928}
3929
3930
3931
3932template <int dim,
3933 int n_components_,
3934 typename Number,
3935 bool is_face,
3936 typename VectorizedArrayType>
3937template <typename VectorType>
3938inline void
3940 distribute_local_to_global(VectorType &dst,
3941 const unsigned int first_index,
3942 const std::bitset<n_lanes> &mask) const
3943{
3944 if constexpr (running_in_debug_mode())
3945 {
3946 Assert(this->dof_values_initialized == true,
3948 }
3949
3950 apply_hanging_node_constraints(true);
3951
3952 const auto dst_data = internal::get_vector_data<n_components_>(
3953 dst,
3954 first_index,
3955 this->dof_info != nullptr &&
3956 this->dof_access_index ==
3958 this->active_fe_index,
3959 this->dof_info);
3960
3961 internal::VectorDistributorLocalToGlobal<Number, VectorizedArrayType>
3962 distributor;
3963 read_write_operation(distributor, dst_data.first, dst_data.second, mask);
3964}
3965
3966
3967
3968template <int dim,
3969 int n_components_,
3970 typename Number,
3971 bool is_face,
3972 typename VectorizedArrayType>
3973template <typename VectorType>
3974inline void
3976 set_dof_values(VectorType &dst,
3977 const unsigned int first_index,
3978 const std::bitset<n_lanes> &mask) const
3979{
3980 if constexpr (running_in_debug_mode())
3981 {
3982 Assert(this->dof_values_initialized == true,
3984 }
3985
3986 const auto dst_data = internal::get_vector_data<n_components_>(
3987 dst,
3988 first_index,
3989 this->dof_info != nullptr &&
3990 this->dof_access_index ==
3992 this->active_fe_index,
3993 this->dof_info);
3994
3995 internal::VectorSetter<Number, VectorizedArrayType> setter;
3996 read_write_operation(setter, dst_data.first, dst_data.second, mask);
3997}
3998
3999
4000
4001template <int dim,
4002 int n_components_,
4003 typename Number,
4004 bool is_face,
4005 typename VectorizedArrayType>
4006template <typename VectorType>
4007inline void
4009 set_dof_values_plain(VectorType &dst,
4010 const unsigned int first_index,
4011 const std::bitset<n_lanes> &mask) const
4012{
4013 if constexpr (running_in_debug_mode())
4014 {
4015 Assert(this->dof_values_initialized == true,
4017 }
4018
4019 const auto dst_data = internal::get_vector_data<n_components_>(
4020 dst,
4021 first_index,
4022 this->dof_access_index ==
4024 this->active_fe_index,
4025 this->dof_info);
4026
4027 internal::VectorSetter<Number, VectorizedArrayType> setter;
4028 read_write_operation(setter, dst_data.first, dst_data.second, mask, false);
4029}
4030
4031
4032
4033/*------------------------------ access to data fields ----------------------*/
4034
4035
4036
4037template <int dim,
4038 int n_components_,
4039 typename Number,
4040 bool is_face,
4041 typename VectorizedArrayType>
4043 typename FEEvaluationBase<dim,
4044 n_components_,
4045 Number,
4046 is_face,
4047 VectorizedArrayType>::value_type
4049 get_dof_value(const unsigned int dof) const
4050{
4051 AssertIndexRange(dof, this->data->dofs_per_component_on_cell);
4052 if constexpr (n_components == 1)
4053 return this->values_dofs[dof];
4054 else
4055 {
4056 const std::size_t dofs = this->data->dofs_per_component_on_cell;
4057 Tensor<1, n_components_, VectorizedArrayType> return_value;
4058 for (unsigned int comp = 0; comp < n_components; ++comp)
4059 return_value[comp] = this->values_dofs[comp * dofs + dof];
4060 return return_value;
4061 }
4062}
4063
4064
4065
4066template <int dim,
4067 int n_components_,
4068 typename Number,
4069 bool is_face,
4070 typename VectorizedArrayType>
4072 typename FEEvaluationBase<dim,
4073 n_components_,
4074 Number,
4075 is_face,
4076 VectorizedArrayType>::value_type
4078 get_value(const unsigned int q_point) const
4079{
4080 if constexpr (running_in_debug_mode())
4081 {
4082 Assert(this->values_quad_initialized == true,
4084 }
4085
4086 AssertIndexRange(q_point, this->n_quadrature_points);
4087 if constexpr (n_components == 1)
4088 return this->values_quad[q_point];
4089 else
4090 {
4091 if (n_components == dim &&
4092 this->data->element_type ==
4094 {
4095 // Piola transform is required
4096 if constexpr (running_in_debug_mode())
4097 {
4098 Assert(this->values_quad_initialized == true,
4100 }
4101
4102 AssertIndexRange(q_point, this->n_quadrature_points);
4103 Assert(this->J_value != nullptr,
4105 "update_values"));
4106 const std::size_t nqp = this->n_quadrature_points;
4107 Tensor<1, n_components, VectorizedArrayType> value_out;
4108
4109 if (!is_face &&
4111 {
4112 // Cartesian cell
4113 const Tensor<2, dim, VectorizedArrayType> jac = this->jacobian[1];
4114 const VectorizedArrayType inv_det =
4115 (dim == 2) ? this->jacobian[0][0][0] * this->jacobian[0][1][1] :
4116 this->jacobian[0][0][0] * this->jacobian[0][1][1] *
4117 this->jacobian[0][2][2];
4118
4119 // J * u * det(J^-1)
4120 for (unsigned int comp = 0; comp < n_components; ++comp)
4121 value_out[comp] = this->values_quad[comp * nqp + q_point] *
4122 jac[comp][comp] * inv_det;
4123 }
4124 else
4125 {
4126 // Affine or general cell
4127 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
4128 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
4129 this->jacobian[q_point] :
4130 this->jacobian[0];
4131 const Tensor<2, dim, VectorizedArrayType> jac =
4132 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
4133 transpose(invert(inv_t_jac)) :
4134 this->jacobian[1];
4135
4136 // Derivatives are reordered for faces. Need to take this into
4137 // account
4138 const VectorizedArrayType inv_det =
4139 (is_face && dim == 2 && this->get_face_no() < 2) ?
4140 -determinant(inv_t_jac) :
4141 determinant(inv_t_jac);
4142 // J * u * det(J^-1)
4143 for (unsigned int comp = 0; comp < n_components; ++comp)
4144 {
4145 value_out[comp] = this->values_quad[q_point] * jac[comp][0];
4146 for (unsigned int e = 1; e < dim; ++e)
4147 value_out[comp] +=
4148 this->values_quad[e * nqp + q_point] * jac[comp][e];
4149 value_out[comp] *= inv_det;
4150 }
4151 }
4152 return value_out;
4153 }
4154 else if (n_components == dim &&
4155 this->data->element_type ==
4157 {
4158 // Piola transform is required
4159 if constexpr (running_in_debug_mode())
4160 {
4161 Assert(this->values_quad_initialized == true,
4163 }
4164
4165 AssertIndexRange(q_point, this->n_quadrature_points);
4166 Assert(this->J_value != nullptr,
4168 "update_values"));
4169 const std::size_t nqp = this->n_quadrature_points;
4170 Tensor<1, n_components, VectorizedArrayType> value_out;
4171
4172 if (!is_face &&
4174 {
4175 // Cartesian cell
4176 const Tensor<2, dim, VectorizedArrayType> inv_transp_jac =
4177 this->jacobian[0];
4178
4179
4180 // J^{-T} * u
4181 for (unsigned int comp = 0; comp < n_components; ++comp)
4182 value_out[comp] = this->values_quad[comp * nqp + q_point] *
4183 inv_transp_jac[comp][comp];
4184 }
4185 else
4186 {
4187 // Affine or general cell
4188 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
4189 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
4190 this->jacobian[q_point] :
4191 this->jacobian[0];
4192
4193 // J^{-T} * u
4194 for (unsigned int comp = 0; comp < n_components; ++comp)
4195 {
4196 value_out[comp] =
4197 this->values_quad[q_point] * inv_t_jac[comp][0];
4198 for (unsigned int e = 1; e < dim; ++e)
4199 value_out[comp] +=
4200 this->values_quad[e * nqp + q_point] * inv_t_jac[comp][e];
4201 }
4202 }
4203 return value_out;
4204 }
4205 else
4206 {
4207 const std::size_t nqp = this->n_quadrature_points;
4208 Tensor<1, n_components_, VectorizedArrayType> return_value;
4209 for (unsigned int comp = 0; comp < n_components; ++comp)
4210 return_value[comp] = this->values_quad[comp * nqp + q_point];
4211 return return_value;
4212 }
4213 }
4214}
4215
4216
4217
4218template <int dim,
4219 int n_components_,
4220 typename Number,
4221 bool is_face,
4222 typename VectorizedArrayType>
4224 typename FEEvaluationBase<dim,
4225 n_components_,
4226 Number,
4227 is_face,
4228 VectorizedArrayType>::gradient_type
4230 get_gradient(const unsigned int q_point) const
4231{
4232 if constexpr (running_in_debug_mode())
4233 {
4234 Assert(this->gradients_quad_initialized == true,
4236 }
4237
4238 AssertIndexRange(q_point, this->n_quadrature_points);
4239 Assert(this->jacobian != nullptr,
4241 "update_gradients"));
4242 const std::size_t nqp = this->n_quadrature_points;
4243
4244 if constexpr (n_components == dim && dim > 1)
4245 {
4246 if (this->data->element_type ==
4248 {
4249 // Piola transform is required
4250 if constexpr (running_in_debug_mode())
4251 {
4252 Assert(this->gradients_quad_initialized == true,
4254 }
4255
4256 AssertIndexRange(q_point, this->n_quadrature_points);
4257 Assert(this->jacobian != nullptr,
4259 "update_gradients"));
4260 const std::size_t nqp = this->n_quadrature_points;
4261 const std::size_t nqp_d = nqp * dim;
4262 Tensor<1, dim, Tensor<1, dim, VectorizedArrayType>> grad_out;
4263 const VectorizedArrayType *gradients =
4264 this->gradients_quad + q_point * dim;
4265
4266
4267 if (!is_face &&
4269 {
4270 // Cartesian cell
4271 const Tensor<2, dim, VectorizedArrayType> &inv_t_jac =
4272 this->jacobian[0];
4273 const Tensor<2, dim, VectorizedArrayType> &jac =
4274 this->jacobian[1];
4275 const VectorizedArrayType inv_det =
4276 (dim == 2) ? this->jacobian[0][0][0] * this->jacobian[0][1][1] :
4277 this->jacobian[0][0][0] * this->jacobian[0][1][1] *
4278 this->jacobian[0][2][2];
4279
4280 // J * grad_quad * J^-1 * det(J^-1)
4281 for (unsigned int d = 0; d < dim; ++d)
4282 for (unsigned int comp = 0; comp < n_components; ++comp)
4283 grad_out[comp][d] = gradients[comp * nqp_d + d] *
4284 inv_t_jac[d][d] *
4285 (jac[comp][comp] * inv_det);
4286 }
4287 else if (this->cell_type <= internal::MatrixFreeFunctions::affine)
4288 {
4289 // Affine cell
4290 const Tensor<2, dim, VectorizedArrayType> &inv_t_jac =
4291 this->jacobian[0];
4292 const Tensor<2, dim, VectorizedArrayType> &jac =
4293 this->jacobian[1];
4294
4295 // Derivatives are reordered for faces. Need to take this into
4296 // account
4297 const VectorizedArrayType inv_det =
4298 (is_face && dim == 2 && this->get_face_no() < 2) ?
4299 -determinant(inv_t_jac) :
4300 determinant(inv_t_jac);
4301
4302 VectorizedArrayType tmp[dim][dim];
4303 // J * grad_quad * J^-1 * det(J^-1)
4304 for (unsigned int d = 0; d < dim; ++d)
4305 for (unsigned int e = 0; e < dim; ++e)
4306 {
4307 tmp[d][e] = inv_t_jac[d][0] * gradients[e * nqp_d + 0];
4308 for (unsigned int f = 1; f < dim; ++f)
4309 tmp[d][e] += inv_t_jac[d][f] * gradients[e * nqp_d + f];
4310 }
4311 for (unsigned int comp = 0; comp < n_components; ++comp)
4312 for (unsigned int d = 0; d < dim; ++d)
4313 {
4314 VectorizedArrayType res = jac[comp][0] * tmp[d][0];
4315 for (unsigned int f = 1; f < dim; ++f)
4316 res += jac[comp][f] * tmp[d][f];
4317
4318 grad_out[comp][d] = res * inv_det;
4319 }
4320 }
4321 else
4322 {
4323 // General cell
4324
4325 // This assert could be removed if we make sure that this is
4326 // updated even though update_hessians or update_jacobian_grads is
4327 // not passed, i.e make the necessary changes in
4328 // MatrixFreeFunctions::MappingInfoStorage::compute_update_flags
4329 Assert(this->jacobian_gradients_non_inverse != nullptr,
4331 "update_hessians"));
4332
4333 const auto jac_grad =
4334 this->jacobian_gradients_non_inverse[q_point];
4335 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
4336 this->jacobian[q_point];
4337
4338 // Derivatives are reordered for faces. Need to take this into
4339 // account
4340 const VectorizedArrayType inv_det =
4341 (is_face && dim == 2 && this->get_face_no() < 2) ?
4342 -determinant(inv_t_jac) :
4343 determinant(inv_t_jac);
4344 const Tensor<2, dim, VectorizedArrayType> t_jac =
4345 invert(inv_t_jac);
4346
4347 // (J * grad_quad) * J^-1 * det(J^-1), part in braces
4348 VectorizedArrayType tmp[dim][dim];
4349 for (unsigned int d = 0; d < dim; ++d)
4350 for (unsigned int e = 0; e < dim; ++e)
4351 {
4352 tmp[e][d] = t_jac[0][d] * gradients[0 * nqp_d + e];
4353 for (unsigned int f = 1; f < dim; ++f)
4354 tmp[e][d] += t_jac[f][d] * gradients[f * nqp_d + e];
4355 }
4356
4357 // Add (jac_grad * values) * J^{-1} * det(J^{-1}), combine terms
4358 // outside braces with gradient part from above
4359 for (unsigned int d = 0; d < dim; ++d)
4360 {
4361 for (unsigned int e = 0; e < dim; ++e)
4362 tmp[e][d] +=
4363 jac_grad[e][d] * this->values_quad[e * nqp + q_point];
4364 for (unsigned int f = 0, r = dim; f < dim; ++f)
4365 for (unsigned int k = f + 1; k < dim; ++k, ++r)
4366 {
4367 tmp[k][d] +=
4368 jac_grad[r][d] * this->values_quad[f * nqp + q_point];
4369 tmp[f][d] +=
4370 jac_grad[r][d] * this->values_quad[k * nqp + q_point];
4371 }
4372 }
4373
4374 // Apply J^{-1} appearing in both terms outside braces above
4375 for (unsigned int d = 0; d < dim; ++d)
4376 for (unsigned int e = 0; e < dim; ++e)
4377 {
4378 VectorizedArrayType res = tmp[0][d] * inv_t_jac[e][0];
4379 for (unsigned int f = 1; f < dim; ++f)
4380 res += tmp[f][d] * inv_t_jac[e][f];
4381 grad_out[d][e] = res;
4382 }
4383
4384 // Add -(J^{-T} * jac_grad * J^{-1} * J * values * det(J^{-1})),
4385 // which can be expressed as a rank-1 update tmp[d] * tmp4[e],
4386 // where tmp = J * values and tmp4 = (J^{-T} * jac_grad * J^{-1})
4387 VectorizedArrayType tmp3[dim], tmp4[dim];
4388 for (unsigned int d = 0; d < dim; ++d)
4389 {
4390 tmp3[d] = inv_t_jac[0][d] * jac_grad[d][0];
4391 for (unsigned int e = 1; e < dim; ++e)
4392 tmp3[d] += inv_t_jac[e][d] * jac_grad[d][e];
4393 }
4394 for (unsigned int e = 0, k = dim; e < dim; ++e)
4395 for (unsigned int f = e + 1; f < dim; ++k, ++f)
4396 for (unsigned int d = 0; d < dim; ++d)
4397 {
4398 tmp3[f] += inv_t_jac[d][e] * jac_grad[k][d];
4399 tmp3[e] += inv_t_jac[d][f] * jac_grad[k][d];
4400 }
4401 for (unsigned int d = 0; d < dim; ++d)
4402 {
4403 tmp4[d] = tmp3[0] * inv_t_jac[d][0];
4404 for (unsigned int e = 1; e < dim; ++e)
4405 tmp4[d] += tmp3[e] * inv_t_jac[d][e];
4406 }
4407
4408 VectorizedArrayType tmp2[dim];
4409 for (unsigned int d = 0; d < dim; ++d)
4410 {
4411 tmp2[d] = t_jac[0][d] * this->values_quad[q_point];
4412 for (unsigned e = 1; e < dim; ++e)
4413 tmp2[d] +=
4414 t_jac[e][d] * this->values_quad[e * nqp + q_point];
4415 }
4416
4417 for (unsigned int d = 0; d < dim; ++d)
4418 for (unsigned int e = 0; e < dim; ++e)
4419 {
4420 grad_out[d][e] -= tmp4[e] * tmp2[d];
4421
4422 // finally multiply by det(J^{-1}) necessary in all
4423 // contributions above
4424 grad_out[d][e] *= inv_det;
4425 }
4426 }
4427 return grad_out;
4428 }
4429 }
4430 Tensor<1, n_components_, Tensor<1, dim, VectorizedArrayType>> grad_out;
4431
4432 // Cartesian cell
4433 if (!is_face && this->cell_type == internal::MatrixFreeFunctions::cartesian)
4434 {
4435 for (unsigned int comp = 0; comp < n_components; ++comp)
4436 for (unsigned int d = 0; d < dim; ++d)
4437 grad_out[comp][d] =
4438 this->gradients_quad[(comp * nqp + q_point) * dim + d] *
4439 this->jacobian[0][d][d];
4440 }
4441 // cell with general/affine Jacobian
4442 else
4443 {
4444 const Tensor<2, dim, VectorizedArrayType> &jac =
4445 this->jacobian[this->cell_type > internal::MatrixFreeFunctions::affine ?
4446 q_point :
4447 0];
4448 for (unsigned int comp = 0; comp < n_components; ++comp)
4449 for (unsigned int d = 0; d < dim; ++d)
4450 {
4451 grad_out[comp][d] =
4452 jac[d][0] * this->gradients_quad[(comp * nqp + q_point) * dim];
4453 for (unsigned int e = 1; e < dim; ++e)
4454 grad_out[comp][d] +=
4455 jac[d][e] *
4456 this->gradients_quad[(comp * nqp + q_point) * dim + e];
4457 }
4458 }
4459 if constexpr (n_components == 1)
4460 return grad_out[0];
4461 else
4462 return grad_out;
4463}
4464
4465
4466
4467template <int dim,
4468 int n_components_,
4469 typename Number,
4470 bool is_face,
4471 typename VectorizedArrayType>
4473 typename FEEvaluationBase<dim,
4474 n_components_,
4475 Number,
4476 is_face,
4477 VectorizedArrayType>::value_type
4479 get_normal_derivative(const unsigned int q_point) const
4480{
4481 AssertIndexRange(q_point, this->n_quadrature_points);
4482 if constexpr (running_in_debug_mode())
4483 {
4484 Assert(this->gradients_quad_initialized == true,
4486 }
4487
4488 Assert(this->normal_x_jacobian != nullptr,
4490 "update_gradients"));
4491
4492 const std::size_t nqp = this->n_quadrature_points;
4493 Tensor<1, n_components, VectorizedArrayType> grad_out;
4494
4495 if (this->cell_type == internal::MatrixFreeFunctions::cartesian)
4496 for (unsigned int comp = 0; comp < n_components; ++comp)
4497 grad_out[comp] =
4498 this->gradients_quad[(comp * nqp + q_point) * dim + dim - 1] *
4499 (this->normal_x_jacobian[0][dim - 1]);
4500 else
4501 {
4502 const std::size_t index =
4503 this->cell_type <= internal::MatrixFreeFunctions::affine ? 0 : q_point;
4504 for (unsigned int comp = 0; comp < n_components; ++comp)
4505 {
4506 grad_out[comp] = this->gradients_quad[(comp * nqp + q_point) * dim] *
4507 this->normal_x_jacobian[index][0];
4508 for (unsigned int d = 1; d < dim; ++d)
4509 grad_out[comp] +=
4510 this->gradients_quad[(comp * nqp + q_point) * dim + d] *
4511 this->normal_x_jacobian[index][d];
4512 }
4513 }
4514 if constexpr (n_components == 1)
4515 return grad_out[0];
4516 else
4517 return grad_out;
4518}
4519
4520
4521
4522namespace internal
4523{
4524 // compute tmp = hess_unit(u) * J^T. do this manually because we do not
4525 // store the lower diagonal because of symmetry
4526 template <typename VectorizedArrayType>
4527 inline void
4528 hessian_unit_times_jac(const Tensor<2, 1, VectorizedArrayType> &jac,
4529 const VectorizedArrayType *const hessians,
4530 const unsigned int,
4531 VectorizedArrayType (&tmp)[1][1])
4532 {
4533 tmp[0][0] = jac[0][0] * hessians[0];
4534 }
4535
4536 template <typename VectorizedArrayType>
4537 inline void
4538 hessian_unit_times_jac(const Tensor<2, 2, VectorizedArrayType> &jac,
4539 const VectorizedArrayType *const hessians,
4540 const unsigned int nqp,
4541 VectorizedArrayType (&tmp)[2][2])
4542 {
4543 for (unsigned int d = 0; d < 2; ++d)
4544 {
4545 tmp[0][d] = (jac[d][0] * hessians[0] + jac[d][1] * hessians[2 * nqp]);
4546 tmp[1][d] =
4547 (jac[d][0] * hessians[2 * nqp] + jac[d][1] * hessians[1 * nqp]);
4548 }
4549 }
4550
4551 template <typename VectorizedArrayType>
4552 inline void
4553 hessian_unit_times_jac(const Tensor<2, 3, VectorizedArrayType> &jac,
4554 const VectorizedArrayType *const hessians,
4555 const unsigned int nqp,
4556 VectorizedArrayType (&tmp)[3][3])
4557 {
4558 for (unsigned int d = 0; d < 3; ++d)
4559 {
4560 tmp[0][d] =
4561 (jac[d][0] * hessians[0 * nqp] + jac[d][1] * hessians[3 * nqp] +
4562 jac[d][2] * hessians[4 * nqp]);
4563 tmp[1][d] =
4564 (jac[d][0] * hessians[3 * nqp] + jac[d][1] * hessians[1 * nqp] +
4565 jac[d][2] * hessians[5 * nqp]);
4566 tmp[2][d] =
4567 (jac[d][0] * hessians[4 * nqp] + jac[d][1] * hessians[5 * nqp] +
4568 jac[d][2] * hessians[2 * nqp]);
4569 }
4570 }
4571} // namespace internal
4572
4573
4574
4575template <int dim,
4576 int n_components_,
4577 typename Number,
4578 bool is_face,
4579 typename VectorizedArrayType>
4580inline typename FEEvaluationBase<dim,
4581 n_components_,
4582 Number,
4583 is_face,
4584 VectorizedArrayType>::hessian_type
4586 get_hessian(const unsigned int q_point) const
4587{
4588 if constexpr (running_in_debug_mode())
4589 {
4590 Assert(this->hessians_quad_initialized == true,
4592 }
4593 AssertIndexRange(q_point, this->n_quadrature_points);
4594
4595 Assert(this->jacobian != nullptr,
4597 "update_hessian"));
4598 const Tensor<2, dim, VectorizedArrayType> &jac =
4599 this->jacobian[this->cell_type <= internal::MatrixFreeFunctions::affine ?
4600 0 :
4601 q_point];
4602
4603 Tensor<1, n_components, Tensor<2, dim, VectorizedArrayType>> hessian_out;
4604
4605 const std::size_t nqp = this->n_quadrature_points;
4606 constexpr unsigned int hdim = (dim * (dim + 1)) / 2;
4607
4608 // Cartesian cell
4609 if (!is_face && this->cell_type == internal::MatrixFreeFunctions::cartesian)
4610 {
4611 for (unsigned int comp = 0; comp < n_components; ++comp)
4612 {
4613 for (unsigned int d = 0; d < dim; ++d)
4614 hessian_out[comp][d][d] =
4615 this->hessians_quad[(comp * hdim + d) * nqp + q_point] *
4616 (jac[d][d] * jac[d][d]);
4617 switch (dim)
4618 {
4619 case 1:
4620 break;
4621 case 2:
4622 hessian_out[comp][0][1] =
4623 this->hessians_quad[(comp * hdim + 2) * nqp + q_point] *
4624 (jac[0][0] * jac[1][1]);
4625 break;
4626 case 3:
4627 hessian_out[comp][0][1] =
4628 this->hessians_quad[(comp * hdim + 3) * nqp + q_point] *
4629 (jac[0][0] * jac[1][1]);
4630 hessian_out[comp][0][2] =
4631 this->hessians_quad[(comp * hdim + 4) * nqp + q_point] *
4632 (jac[0][0] * jac[2][2]);
4633 hessian_out[comp][1][2] =
4634 this->hessians_quad[(comp * hdim + 5) * nqp + q_point] *
4635 (jac[1][1] * jac[2][2]);
4636 break;
4637 default:
4639 }
4640 for (unsigned int d = 0; d < dim; ++d)
4641 for (unsigned int e = d + 1; e < dim; ++e)
4642 hessian_out[comp][e][d] = hessian_out[comp][d][e];
4643 }
4644 }
4645 // cell with general Jacobian, but constant within the cell
4646 else if (this->cell_type <= internal::MatrixFreeFunctions::affine)
4647 {
4648 for (unsigned int comp = 0; comp < n_components; ++comp)
4649 {
4650 VectorizedArrayType tmp[dim][dim];
4651 internal::hessian_unit_times_jac(
4652 jac, this->hessians_quad + comp * hdim * nqp + q_point, nqp, tmp);
4653
4654 // compute first part of hessian, J * tmp = J * hess_unit(u) * J^T
4655 for (unsigned int d = 0; d < dim; ++d)
4656 for (unsigned int e = d; e < dim; ++e)
4657 {
4658 hessian_out[comp][d][e] = jac[d][0] * tmp[0][e];
4659 for (unsigned int f = 1; f < dim; ++f)
4660 hessian_out[comp][d][e] += jac[d][f] * tmp[f][e];
4661 }
4662
4663 // no J' * grad(u) part here because the Jacobian is constant
4664 // throughout the cell and hence, its derivative is zero
4665
4666 // take symmetric part
4667 for (unsigned int d = 0; d < dim; ++d)
4668 for (unsigned int e = d + 1; e < dim; ++e)
4669 hessian_out[comp][e][d] = hessian_out[comp][d][e];
4670 }
4671 }
4672 // cell with general Jacobian
4673 else
4674 {
4675 const auto &jac_grad = this->jacobian_gradients[q_point];
4676 for (unsigned int comp = 0; comp < n_components; ++comp)
4677 {
4678 VectorizedArrayType tmp[dim][dim];
4679 internal::hessian_unit_times_jac(
4680 jac, this->hessians_quad + comp * hdim * nqp + q_point, nqp, tmp);
4681
4682 // compute first part of hessian, J * tmp = J * hess_unit(u) * J^T
4683 for (unsigned int d = 0; d < dim; ++d)
4684 for (unsigned int e = d; e < dim; ++e)
4685 {
4686 hessian_out[comp][d][e] = jac[d][0] * tmp[0][e];
4687 for (unsigned int f = 1; f < dim; ++f)
4688 hessian_out[comp][d][e] += jac[d][f] * tmp[f][e];
4689 }
4690
4691 // add diagonal part of J' * grad(u)
4692 for (unsigned int d = 0; d < dim; ++d)
4693 for (unsigned int e = 0; e < dim; ++e)
4694 hessian_out[comp][d][d] +=
4695 jac_grad[d][e] *
4696 this->gradients_quad[(comp * nqp + q_point) * dim + e];
4697
4698 // add off-diagonal part of J' * grad(u)
4699 for (unsigned int d = 0, count = dim; d < dim; ++d)
4700 for (unsigned int e = d + 1; e < dim; ++e, ++count)
4701 for (unsigned int f = 0; f < dim; ++f)
4702 hessian_out[comp][d][e] +=
4703 jac_grad[count][f] *
4704 this->gradients_quad[(comp * nqp + q_point) * dim + f];
4705
4706 // take symmetric part
4707 for (unsigned int d = 0; d < dim; ++d)
4708 for (unsigned int e = d + 1; e < dim; ++e)
4709 hessian_out[comp][e][d] = hessian_out[comp][d][e];
4710 }
4711 }
4712 if constexpr (n_components == 1)
4713 return hessian_out[0];
4714 else
4715 return hessian_out;
4716}
4717
4718
4719
4720template <int dim,
4721 int n_components_,
4722 typename Number,
4723 bool is_face,
4724 typename VectorizedArrayType>
4725inline typename FEEvaluationBase<dim,
4726 n_components_,
4727 Number,
4728 is_face,
4729 VectorizedArrayType>::gradient_type
4731 get_hessian_diagonal(const unsigned int q_point) const
4732{
4733 Assert(!is_face, ExcNotImplemented());
4734 if constexpr (running_in_debug_mode())
4735 {
4736 Assert(this->hessians_quad_initialized == true,
4738 }
4739 AssertIndexRange(q_point, this->n_quadrature_points);
4740
4741 Assert(this->jacobian != nullptr, ExcNotImplemented());
4742 const Tensor<2, dim, VectorizedArrayType> &jac =
4743 this->jacobian[this->cell_type <= internal::MatrixFreeFunctions::affine ?
4744 0 :
4745 q_point];
4746
4747 const std::size_t nqp = this->n_quadrature_points;
4748 constexpr unsigned int hdim = (dim * (dim + 1)) / 2;
4749 Tensor<1, n_components_, Tensor<1, dim, VectorizedArrayType>> hessian_out;
4750
4751 // Cartesian cell
4752 if (this->cell_type == internal::MatrixFreeFunctions::cartesian)
4753 {
4754 for (unsigned int comp = 0; comp < n_components; ++comp)
4755 for (unsigned int d = 0; d < dim; ++d)
4756 hessian_out[comp][d] =
4757 this->hessians_quad[(comp * hdim + d) * nqp + q_point] *
4758 (jac[d][d] * jac[d][d]);
4759 }
4760 // cell with general Jacobian, but constant within the cell
4761 else if (this->cell_type == internal::MatrixFreeFunctions::affine)
4762 {
4763 for (unsigned int comp = 0; comp < n_components; ++comp)
4764 {
4765 // compute laplacian before the gradient because it needs to access
4766 // unscaled gradient data
4767 VectorizedArrayType tmp[dim][dim];
4768 internal::hessian_unit_times_jac(
4769 jac, this->hessians_quad + comp * hdim * nqp + q_point, nqp, tmp);
4770
4771 // compute only the trace part of hessian, J * tmp = J *
4772 // hess_unit(u) * J^T
4773 for (unsigned int d = 0; d < dim; ++d)
4774 {
4775 hessian_out[comp][d] = jac[d][0] * tmp[0][d];
4776 for (unsigned int f = 1; f < dim; ++f)
4777 hessian_out[comp][d] += jac[d][f] * tmp[f][d];
4778 }
4779 }
4780 }
4781 // cell with general Jacobian
4782 else
4783 {
4784 const auto &jac_grad = this->jacobian_gradients[q_point];
4785 for (unsigned int comp = 0; comp < n_components; ++comp)
4786 {
4787 // compute laplacian before the gradient because it needs to access
4788 // unscaled gradient data
4789 VectorizedArrayType tmp[dim][dim];
4790 internal::hessian_unit_times_jac(
4791 jac, this->hessians_quad + comp * hdim * nqp + q_point, nqp, tmp);
4792
4793 // compute only the trace part of hessian, J * tmp = J *
4794 // hess_unit(u) * J^T
4795 for (unsigned int d = 0; d < dim; ++d)
4796 {
4797 hessian_out[comp][d] = jac[d][0] * tmp[0][d];
4798 for (unsigned int f = 1; f < dim; ++f)
4799 hessian_out[comp][d] += jac[d][f] * tmp[f][d];
4800 }
4801
4802 for (unsigned int d = 0; d < dim; ++d)
4803 for (unsigned int e = 0; e < dim; ++e)
4804 hessian_out[comp][d] +=
4805 jac_grad[d][e] *
4806 this->gradients_quad[(comp * nqp + q_point) * dim + e];
4807 }
4808 }
4809
4810 if constexpr (n_components == 1)
4811 return hessian_out[0];
4812 else
4813 return hessian_out;
4814}
4815
4816
4817
4818template <int dim,
4819 int n_components_,
4820 typename Number,
4821 bool is_face,
4822 typename VectorizedArrayType>
4823inline typename FEEvaluationBase<dim,
4824 n_components_,
4825 Number,
4826 is_face,
4827 VectorizedArrayType>::value_type
4829 get_laplacian(const unsigned int q_point) const
4830{
4831 Assert(is_face == false, ExcNotImplemented());
4832 if constexpr (running_in_debug_mode())
4833 {
4834 Assert(this->hessians_quad_initialized == true,
4836 }
4837 AssertIndexRange(q_point, this->n_quadrature_points);
4838
4839 const gradient_type hess_diag = get_hessian_diagonal(q_point);
4840 if constexpr (n_components == 1)
4841 {
4842 VectorizedArrayType sum = hess_diag[0];
4843 for (unsigned int d = 1; d < dim; ++d)
4844 sum += hess_diag[d];
4845 return sum;
4846 }
4847 else
4848 {
4849 Tensor<1, n_components_, VectorizedArrayType> laplacian_out;
4850 for (unsigned int comp = 0; comp < n_components; ++comp)
4851 {
4852 laplacian_out[comp] = hess_diag[comp][0];
4853 for (unsigned int d = 1; d < dim; ++d)
4854 laplacian_out[comp] += hess_diag[comp][d];
4855 }
4856 return laplacian_out;
4857 }
4858}
4859
4860
4861
4862template <int dim,
4863 int n_components_,
4864 typename Number,
4865 bool is_face,
4866 typename VectorizedArrayType>
4867inline typename FEEvaluationBase<dim,
4868 n_components_,
4869 Number,
4870 is_face,
4871 VectorizedArrayType>::value_type
4873 get_normal_hessian(const unsigned int q_point) const
4874{
4875 if constexpr (running_in_debug_mode())
4876 {
4877 Assert(this->hessians_quad_initialized == true,
4879 }
4880 AssertIndexRange(q_point, this->n_quadrature_points);
4881
4882 Assert(this->normal_x_jacobian != nullptr,
4884 "update_hessians"));
4885
4886 Tensor<1, n_components, VectorizedArrayType> hessian_out;
4887
4888 const std::size_t nqp = this->n_quadrature_points;
4889 constexpr unsigned int hdim = (dim * (dim + 1)) / 2;
4890
4891 if (this->cell_type <= internal::MatrixFreeFunctions::affine)
4892 {
4893 const auto nxj = this->normal_x_jacobian[0];
4894
4895 for (unsigned int comp = 0; comp < n_components; ++comp)
4896 {
4897 for (unsigned int d = 0; d < dim; ++d)
4898 hessian_out[comp] +=
4899 this->hessians_quad[(comp * hdim + d) * nqp + q_point] *
4900 (nxj[d]) * (nxj[d]);
4901
4902 switch (dim)
4903 {
4904 case 1:
4905 break;
4906 case 2:
4907 hessian_out[comp] +=
4908 this->hessians_quad[(comp * hdim + 2) * nqp + q_point] *
4909 (nxj[0] * nxj[1]);
4910 break;
4911 case 3:
4912 hessian_out[comp] +=
4913 2. * this->hessians_quad[(comp * hdim + 3) * nqp + q_point] *
4914 (nxj[0] * nxj[1]);
4915 hessian_out[comp] +=
4916 2. * this->hessians_quad[(comp * hdim + 4) * nqp + q_point] *
4917 (nxj[0] * nxj[2]);
4918 hessian_out[comp] +=
4919 2. * this->hessians_quad[(comp * hdim + 5) * nqp + q_point] *
4920 (nxj[1] * nxj[2]);
4921 break;
4922 default:
4924 }
4925 }
4926 }
4927 // cell with general Jacobian
4928 else
4929 {
4930 const auto normal = this->normal_vector(q_point);
4931 const auto hessian = get_hessian(q_point);
4932
4933 if constexpr (n_components == 1)
4934 hessian_out[0] = hessian * normal * normal;
4935 else
4936 for (unsigned int comp = 0; comp < n_components; ++comp)
4937 hessian_out[comp] = hessian[comp] * normal * normal;
4938 }
4939 if constexpr (n_components == 1)
4940 return hessian_out[0];
4941 else
4942 return hessian_out;
4943}
4944
4945
4946
4947template <int dim,
4948 int n_components_,
4949 typename Number,
4950 bool is_face,
4951 typename VectorizedArrayType>
4952inline DEAL_II_ALWAYS_INLINE void
4954 submit_dof_value(const value_type val_in, const unsigned int dof)
4955{
4956 if constexpr (running_in_debug_mode())
4957 {
4958 this->dof_values_initialized = true;
4959 }
4960 const std::size_t dofs = this->data->dofs_per_component_on_cell;
4961 AssertIndexRange(dof, this->data->dofs_per_component_on_cell);
4962 for (unsigned int comp = 0; comp < n_components; ++comp)
4963 if constexpr (n_components == 1)
4964 this->values_dofs[comp * dofs + dof] = val_in;
4965 else
4966 this->values_dofs[comp * dofs + dof] = val_in[comp];
4967}
4968
4969
4970
4971template <int dim,
4972 int n_components_,
4973 typename Number,
4974 bool is_face,
4975 typename VectorizedArrayType>
4976inline DEAL_II_ALWAYS_INLINE void
4978 submit_value(const value_type val_in, const unsigned int q_point)
4979{
4980 if constexpr (running_in_debug_mode())
4981 {
4982 Assert(this->is_reinitialized, ExcNotInitialized());
4983 }
4984 AssertIndexRange(q_point, this->n_quadrature_points);
4985 Assert(this->J_value != nullptr,
4987 "update_values"));
4988 if constexpr (running_in_debug_mode())
4989 {
4990 this->values_quad_submitted = true;
4991 }
4992
4993 const std::size_t nqp = this->n_quadrature_points;
4994 VectorizedArrayType *values = this->values_quad + q_point;
4995
4996 const VectorizedArrayType JxW =
4997 this->cell_type <= internal::MatrixFreeFunctions::affine ?
4998 this->J_value[0] * this->quadrature_weights[q_point] :
4999 this->J_value[q_point];
5000 if constexpr (n_components == 1)
5001 values[0] = val_in * JxW;
5002 else
5003 {
5004 if (n_components == dim &&
5005 this->data->element_type ==
5007 {
5008 // Piola transform is required
5009 AssertIndexRange(q_point, this->n_quadrature_points);
5010 Assert(this->J_value != nullptr,
5012 "update_value"));
5013 if constexpr (running_in_debug_mode())
5014 {
5015 Assert(this->is_reinitialized, ExcNotInitialized());
5016 this->values_quad_submitted = true;
5017 }
5018
5019 VectorizedArrayType *values = this->values_quad + q_point;
5020 const std::size_t nqp = this->n_quadrature_points;
5021
5022 if (!is_face &&
5024 {
5025 const Tensor<2, dim, VectorizedArrayType> jac = this->jacobian[1];
5026 const VectorizedArrayType weight =
5027 this->quadrature_weights[q_point];
5028
5029 for (unsigned int comp = 0; comp < n_components; ++comp)
5030 values[comp * nqp] = val_in[comp] * weight * jac[comp][comp];
5031 }
5032 else
5033 {
5034 // Affine or general cell
5035 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
5036 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
5037 this->jacobian[q_point] :
5038 this->jacobian[0];
5039
5040 // Derivatives are reordered for faces. Need to take this into
5041 // account and 1/inv_det != J_value for faces
5042 const VectorizedArrayType fac =
5043 (!is_face) ?
5044 this->quadrature_weights[q_point] :
5045 (((this->cell_type > internal::MatrixFreeFunctions::affine) ?
5046 this->J_value[q_point] :
5047 this->J_value[0] * this->quadrature_weights[q_point]) *
5048 ((dim == 2 && this->get_face_no() < 2) ?
5049 -determinant(inv_t_jac) :
5050 determinant(inv_t_jac)));
5051 const Tensor<2, dim, VectorizedArrayType> jac =
5052 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
5053 transpose(invert(inv_t_jac)) :
5054 this->jacobian[1];
5055
5056 // J^T * u * factor
5057 for (unsigned int comp = 0; comp < n_components; ++comp)
5058 {
5059 values[comp * nqp] = val_in[0] * jac[0][comp];
5060 for (unsigned int e = 1; e < dim; ++e)
5061 values[comp * nqp] += val_in[e] * jac[e][comp];
5062 values[comp * nqp] *= fac;
5063 }
5064 }
5065 }
5066 else if (n_components == dim &&
5067 this->data->element_type ==
5069 {
5070 // Piola transform is required
5071 AssertIndexRange(q_point, this->n_quadrature_points);
5072 Assert(this->J_value != nullptr,
5074 "update_value"));
5075 if constexpr (running_in_debug_mode())
5076 {
5077 Assert(this->is_reinitialized, ExcNotInitialized());
5078 this->values_quad_submitted = true;
5079 }
5080
5081 VectorizedArrayType *values = this->values_quad + q_point;
5082 const std::size_t nqp = this->n_quadrature_points;
5083
5084 if (!is_face &&
5086 {
5087 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
5088 this->jacobian[0];
5089 const VectorizedArrayType det_jac =
5090 (dim == 2) ? this->jacobian[1][0][0] * this->jacobian[1][1][1] :
5091 this->jacobian[1][0][0] * this->jacobian[1][1][1] *
5092 this->jacobian[1][2][2];
5093
5094 const VectorizedArrayType weight =
5095 this->quadrature_weights[q_point];
5096
5097 // J^{-1} * u * det(J) * weight
5098 for (unsigned int comp = 0; comp < n_components; ++comp)
5099 values[comp * nqp] =
5100 val_in[comp] * weight * inv_t_jac[comp][comp] * det_jac;
5101 }
5102 else
5103 {
5104 // Affine or general cell
5105 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
5106 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
5107 this->jacobian[q_point] :
5108 this->jacobian[0];
5109
5110 const VectorizedArrayType fac =
5111 ((this->cell_type > internal::MatrixFreeFunctions::affine) ?
5112 this->J_value[q_point] :
5113 this->J_value[0] * this->quadrature_weights[q_point]);
5114
5115 // J^{-1} * u * factor
5116 for (unsigned int comp = 0; comp < n_components; ++comp)
5117 {
5118 values[comp * nqp] = val_in[0] * inv_t_jac[0][comp];
5119 for (unsigned int e = 1; e < dim; ++e)
5120 values[comp * nqp] += val_in[e] * inv_t_jac[e][comp];
5121 values[comp * nqp] *= fac;
5122 }
5123 }
5124 }
5125 else
5126 for (unsigned int comp = 0; comp < n_components; ++comp)
5127 values[comp * nqp] = val_in[comp] * JxW;
5128 }
5129}
5130
5131
5132
5133template <int dim,
5134 int n_components_,
5135 typename Number,
5136 bool is_face,
5137 typename VectorizedArrayType>
5138template <int, typename>
5139inline DEAL_II_ALWAYS_INLINE void
5141 submit_value(const Tensor<1, 1, VectorizedArrayType> val_in,
5142 const unsigned int q_point)
5143{
5144 static_assert(n_components == 1,
5145 "Do not try to modify the default template parameters used for"
5146 " selectively enabling this function via std::enable_if!");
5147 submit_value(val_in[0], q_point);
5148}
5149
5150
5151
5152template <int dim,
5153 int n_components_,
5154 typename Number,
5155 bool is_face,
5156 typename VectorizedArrayType>
5157inline DEAL_II_ALWAYS_INLINE void
5159 submit_gradient(const gradient_type grad_in, const unsigned int q_point)
5160{
5161 if constexpr (running_in_debug_mode())
5162 {
5163 Assert(this->is_reinitialized, ExcNotInitialized());
5164 }
5165 AssertIndexRange(q_point, this->n_quadrature_points);
5166 Assert(this->J_value != nullptr,
5168 "update_gradients"));
5169 Assert(this->jacobian != nullptr,
5171 "update_gradients"));
5172 if constexpr (running_in_debug_mode())
5173 {
5174 this->gradients_quad_submitted = true;
5175 }
5176
5177 if constexpr (dim > 1 && n_components == dim)
5178 {
5179 if (this->data->element_type ==
5181 {
5182 // Piola transform is required
5183
5184 if constexpr (running_in_debug_mode())
5185 {
5186 Assert(this->is_reinitialized, ExcNotInitialized());
5187 }
5188 AssertIndexRange(q_point, this->n_quadrature_points);
5189 Assert(this->J_value != nullptr,
5191 "update_gradients"));
5192 Assert(this->jacobian != nullptr,
5194 "update_gradients"));
5195 if constexpr (running_in_debug_mode())
5196 {
5197 this->gradients_quad_submitted = true;
5198 }
5199
5200 VectorizedArrayType *gradients = this->gradients_quad + q_point * dim;
5201 VectorizedArrayType *values =
5202 this->values_from_gradients_quad + q_point;
5203 const std::size_t nqp = this->n_quadrature_points;
5204 const std::size_t nqp_d = nqp * dim;
5205
5206 if (!is_face &&
5208 {
5209 // Cartesian cell
5210 const Tensor<2, dim, VectorizedArrayType> &inv_t_jac =
5211 this->jacobian[0];
5212 const Tensor<2, dim, VectorizedArrayType> &jac =
5213 this->jacobian[1];
5214 const VectorizedArrayType weight =
5215 this->quadrature_weights[q_point];
5216 for (unsigned int d = 0; d < dim; ++d)
5217 for (unsigned int comp = 0; comp < n_components; ++comp)
5218 gradients[comp * nqp_d + d] = grad_in[comp][d] *
5219 inv_t_jac[d][d] *
5220 (jac[comp][comp] * weight);
5221 }
5222 else if (this->cell_type <= internal::MatrixFreeFunctions::affine)
5223 {
5224 // Affine cell
5225 const Tensor<2, dim, VectorizedArrayType> &inv_t_jac =
5226 this->jacobian[0];
5227 const Tensor<2, dim, VectorizedArrayType> &jac =
5228 this->jacobian[1];
5229
5230 // Derivatives are reordered for faces. Need to take this into
5231 // account and 1/inv_det != J_value for faces
5232 const VectorizedArrayType fac =
5233 (!is_face) ?
5234 this->quadrature_weights[q_point] :
5235 this->J_value[0] * this->quadrature_weights[q_point] *
5236 ((dim == 2 && this->get_face_no() < 2) ?
5237 -determinant(inv_t_jac) :
5238 determinant(inv_t_jac));
5239
5240 // J_{j,i} * J^{-1}_{k,m} * grad_in_{j,m} * factor
5241 VectorizedArrayType tmp[dim][dim];
5242 for (unsigned int d = 0; d < dim; ++d)
5243 for (unsigned int e = 0; e < dim; ++e)
5244 {
5245 tmp[d][e] = inv_t_jac[0][d] * grad_in[e][0];
5246 for (unsigned int f = 1; f < dim; ++f)
5247 tmp[d][e] += inv_t_jac[f][d] * grad_in[e][f];
5248 }
5249 for (unsigned int comp = 0; comp < n_components; ++comp)
5250 for (unsigned int d = 0; d < dim; ++d)
5251 {
5252 VectorizedArrayType res = jac[0][comp] * tmp[d][0];
5253 for (unsigned int f = 1; f < dim; ++f)
5254 res += jac[f][comp] * tmp[d][f];
5255
5256 gradients[comp * nqp_d + d] = res * fac;
5257 }
5258 }
5259 else
5260 {
5261 // General cell
5262
5263 const auto jac_grad =
5264 this->jacobian_gradients_non_inverse[q_point];
5265 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
5266 this->jacobian[q_point];
5267
5268 // Derivatives are reordered for faces. Need to take this into
5269 // account and 1/inv_det != J_value for faces
5270 const VectorizedArrayType fac =
5271 (!is_face) ? this->quadrature_weights[q_point] :
5272 this->J_value[q_point] *
5273 ((dim == 2 && this->get_face_no() < 2) ?
5274 -determinant(inv_t_jac) :
5275 determinant(inv_t_jac));
5276 const Tensor<2, dim, VectorizedArrayType> t_jac =
5277 invert(inv_t_jac);
5278
5279 // Start evaluation for values part below to enable the compiler
5280 // to possibly re-use the same computation in get_gradient()
5281 // without interfering with stores to 'gradients'
5282 VectorizedArrayType tmp3[dim], tmp4[dim];
5283 for (unsigned int d = 0; d < dim; ++d)
5284 {
5285 tmp3[d] = inv_t_jac[0][d] * jac_grad[d][0];
5286 for (unsigned int e = 1; e < dim; ++e)
5287 tmp3[d] += inv_t_jac[e][d] * jac_grad[d][e];
5288 }
5289 for (unsigned int e = 0, k = dim; e < dim; ++e)
5290 for (unsigned int f = e + 1; f < dim; ++k, ++f)
5291 for (unsigned int d = 0; d < dim; ++d)
5292 {
5293 tmp3[f] += inv_t_jac[d][e] * jac_grad[k][d];
5294 tmp3[e] += inv_t_jac[d][f] * jac_grad[k][d];
5295 }
5296 for (unsigned int d = 0; d < dim; ++d)
5297 {
5298 tmp4[d] = tmp3[0] * inv_t_jac[d][0];
5299 for (unsigned int e = 1; e < dim; ++e)
5300 tmp4[d] += tmp3[e] * inv_t_jac[d][e];
5301 }
5302
5303 const Tensor<2, dim, VectorizedArrayType> grad_in_scaled =
5304 fac * grad_in;
5305
5306 VectorizedArrayType tmp[dim][dim];
5307
5308 // J * (J^{-1} * (grad_in * factor))
5309 for (unsigned int d = 0; d < dim; ++d)
5310 for (unsigned int e = 0; e < dim; ++e)
5311 {
5312 tmp[d][e] = inv_t_jac[0][d] * grad_in_scaled[e][0];
5313 for (unsigned int f = 1; f < dim; ++f)
5314 tmp[d][e] += inv_t_jac[f][d] * grad_in_scaled[e][f];
5315 }
5316
5317 for (unsigned int d = 0; d < dim; ++d)
5318 for (unsigned int e = 0; e < dim; ++e)
5319 {
5320 VectorizedArrayType res = t_jac[d][0] * tmp[e][0];
5321 for (unsigned int f = 1; f < dim; ++f)
5322 res += t_jac[d][f] * tmp[e][f];
5323
5324 gradients[d * nqp_d + e] = res;
5325 }
5326
5327 // jac_grad * (J^{-1} * (grad_in * factor)), re-use part in braces
5328 // as 'tmp' from above
5329 VectorizedArrayType value[dim];
5330 for (unsigned int d = 0; d < dim; ++d)
5331 {
5332 value[d] = tmp[d][0] * jac_grad[d][0];
5333 for (unsigned int e = 1; e < dim; ++e)
5334 value[d] += tmp[d][e] * jac_grad[d][e];
5335 }
5336 for (unsigned int e = 0, k = dim; e < dim; ++e)
5337 for (unsigned int f = e + 1; f < dim; ++k, ++f)
5338 for (unsigned int d = 0; d < dim; ++d)
5339 {
5340 value[e] += tmp[f][d] * jac_grad[k][d];
5341 value[f] += tmp[e][d] * jac_grad[k][d];
5342 }
5343
5344 // -(grad_in * factor) * J * (J^{-T} * jac_grad * J^{-1})
5345 // = -(grad_in * factor) * J * ( \------- tmp4 ---------/ )
5346 for (unsigned int d = 0; d < dim; ++d)
5347 {
5348 VectorizedArrayType tmp2 = grad_in_scaled[d][0] * tmp4[0];
5349 for (unsigned int e = 1; e < dim; ++e)
5350 tmp2 += grad_in_scaled[d][e] * tmp4[e];
5351 for (unsigned int e = 0; e < dim; ++e)
5352 value[e] -= t_jac[e][d] * tmp2;
5353 }
5354
5355 for (unsigned int d = 0; d < dim; ++d)
5356 values[d * nqp] = value[d];
5357 }
5358 return;
5359 }
5360 }
5361
5362 const std::size_t nqp_d = this->n_quadrature_points * dim;
5363 VectorizedArrayType *gradients = this->gradients_quad + q_point * dim;
5364
5365 if (!is_face && this->cell_type == internal::MatrixFreeFunctions::cartesian)
5366 {
5367 const VectorizedArrayType JxW =
5368 this->J_value[0] * this->quadrature_weights[q_point];
5369
5370 // Load all entries before starting to write back to make sure the
5371 // compiler sees opportunity of loads in a possibly nearby
5372 // get_gradient() function (i.e., the compiler should not think that
5373 // 'jacobian' could alias with 'gradients').
5374 std::array<VectorizedArrayType, dim> jac;
5375 for (unsigned int d = 0; d < dim; ++d)
5376 jac[d] = this->jacobian[0][d][d];
5377
5378 for (unsigned int d = 0; d < dim; ++d)
5379 {
5380 const VectorizedArrayType factor = this->jacobian[0][d][d] * JxW;
5381 if constexpr (n_components == 1)
5382 gradients[d] = grad_in[d] * factor;
5383 else
5384 for (unsigned int comp = 0; comp < n_components; ++comp)
5385 gradients[comp * nqp_d + d] = grad_in[comp][d] * factor;
5386 }
5387 }
5388 else
5389 {
5390 const Tensor<2, dim, VectorizedArrayType> jac =
5391 this->cell_type > internal::MatrixFreeFunctions::affine ?
5392 this->jacobian[q_point] :
5393 this->jacobian[0];
5394 const VectorizedArrayType JxW =
5395 this->cell_type > internal::MatrixFreeFunctions::affine ?
5396 this->J_value[q_point] :
5397 this->J_value[0] * this->quadrature_weights[q_point];
5398 if constexpr (n_components == 1)
5399 for (unsigned int d = 0; d < dim; ++d)
5400 {
5401 VectorizedArrayType new_val = jac[0][d] * grad_in[0];
5402 for (unsigned int e = 1; e < dim; ++e)
5403 new_val += (jac[e][d] * grad_in[e]);
5404 gradients[d] = new_val * JxW;
5405 }
5406 else
5407 for (unsigned int comp = 0; comp < n_components; ++comp)
5408 for (unsigned int d = 0; d < dim; ++d)
5409 {
5410 VectorizedArrayType new_val = jac[0][d] * grad_in[comp][0];
5411 for (unsigned int e = 1; e < dim; ++e)
5412 new_val += (jac[e][d] * grad_in[comp][e]);
5413 gradients[comp * nqp_d + d] = new_val * JxW;
5414 }
5415 }
5416}
5417
5418
5419
5420template <int dim,
5421 int n_components_,
5422 typename Number,
5423 bool is_face,
5424 typename VectorizedArrayType>
5425template <int, typename>
5426inline DEAL_II_ALWAYS_INLINE void
5428 submit_gradient(const Tensor<2, 1, VectorizedArrayType> grad_in,
5429 const unsigned int q_point)
5430{
5431 static_assert(n_components == 1 && dim == 1,
5432 "Do not try to modify the default template parameters used for"
5433 " selectively enabling this function via std::enable_if!");
5434 submit_gradient(grad_in[0], q_point);
5435}
5436
5437
5438
5439template <int dim,
5440 int n_components_,
5441 typename Number,
5442 bool is_face,
5443 typename VectorizedArrayType>
5444inline DEAL_II_ALWAYS_INLINE void
5446 submit_normal_derivative(const value_type grad_in, const unsigned int q_point)
5447{
5448 AssertIndexRange(q_point, this->n_quadrature_points);
5449 Assert(this->normal_x_jacobian != nullptr,
5451 "update_gradients"));
5452 if constexpr (running_in_debug_mode())
5453 {
5454 this->gradients_quad_submitted = true;
5455 }
5456
5457 const std::size_t nqp_d = this->n_quadrature_points * dim;
5458 VectorizedArrayType *gradients = this->gradients_quad + q_point * dim;
5459
5460 if (this->cell_type == internal::MatrixFreeFunctions::cartesian)
5461 {
5462 const VectorizedArrayType JxW_jac = this->J_value[0] *
5463 this->quadrature_weights[q_point] *
5464 this->normal_x_jacobian[0][dim - 1];
5465 for (unsigned int comp = 0; comp < n_components; ++comp)
5466 {
5467 for (unsigned int d = 0; d < dim - 1; ++d)
5468 gradients[comp * nqp_d + d] = VectorizedArrayType();
5469 if constexpr (n_components == 1)
5470 gradients[dim - 1] = grad_in * JxW_jac;
5471 else
5472 gradients[comp * nqp_d + dim - 1] = grad_in[comp] * JxW_jac;
5473 }
5474 }
5475 else
5476 {
5477 const unsigned int index =
5478 this->cell_type <= internal::MatrixFreeFunctions::affine ? 0 : q_point;
5479 const Tensor<1, dim, VectorizedArrayType> jac =
5480 this->normal_x_jacobian[index];
5481 const VectorizedArrayType JxW =
5482 (this->cell_type <= internal::MatrixFreeFunctions::affine) ?
5483 this->J_value[index] * this->quadrature_weights[q_point] :
5484 this->J_value[index];
5485 for (unsigned int comp = 0; comp < n_components; ++comp)
5486 for (unsigned int d = 0; d < dim; ++d)
5487 if constexpr (n_components == 1)
5488 gradients[d] = (grad_in * JxW) * jac[d];
5489 else
5490 gradients[comp * nqp_d + d] = (grad_in[comp] * JxW) * jac[d];
5491 }
5492}
5493
5494
5495
5496template <int dim,
5497 int n_components_,
5498 typename Number,
5499 bool is_face,
5500 typename VectorizedArrayType>
5501inline DEAL_II_ALWAYS_INLINE void
5503 submit_hessian(const hessian_type hessian_in, const unsigned int q_point)
5504{
5505 if constexpr (running_in_debug_mode())
5506 {
5507 Assert(this->is_reinitialized, ExcNotInitialized());
5508 }
5509 AssertIndexRange(q_point, this->n_quadrature_points);
5510 Assert(this->J_value != nullptr,
5512 "update_hessians"));
5513 Assert(this->jacobian != nullptr,
5515 "update_hessians"));
5516 if constexpr (running_in_debug_mode())
5517 {
5518 this->hessians_quad_submitted = true;
5519 }
5520
5521 // compute hessian_unit = J^T * hessian_in(u) * J
5522 const std::size_t nqp = this->n_quadrature_points;
5523 constexpr unsigned int hdim = (dim * (dim + 1)) / 2;
5524 if (!is_face && this->cell_type == internal::MatrixFreeFunctions::cartesian)
5525 {
5526 const VectorizedArrayType JxW =
5527 this->J_value[0] * this->quadrature_weights[q_point];
5528
5529 // diagonal part
5530 for (unsigned int d = 0; d < dim; ++d)
5531 {
5532 const auto jac_d = this->jacobian[0][d][d];
5533 const VectorizedArrayType factor = jac_d * jac_d * JxW;
5534 for (unsigned int comp = 0; comp < n_components; ++comp)
5535 if constexpr (n_components == 1)
5536 this->hessians_quad[d * nqp + q_point] =
5537 hessian_in[d][d] * factor;
5538 else
5539 this->hessians_quad[(comp * hdim + d) * nqp + q_point] =
5540 hessian_in[comp][d][d] * factor;
5541 }
5542
5543 // off diagonal part
5544 for (unsigned int d = 1, off_dia = dim; d < dim; ++d)
5545 for (unsigned int e = 0; e < d; ++e, ++off_dia)
5546 {
5547 const auto jac_d = this->jacobian[0][d][d];
5548 const auto jac_e = this->jacobian[0][e][e];
5549 const VectorizedArrayType factor = jac_d * jac_e * JxW;
5550 for (unsigned int comp = 0; comp < n_components; ++comp)
5551 if constexpr (n_components == 1)
5552 this->hessians_quad[off_dia * nqp + q_point] =
5553 (hessian_in[d][e] + hessian_in[e][d]) * factor;
5554 else
5555 this->hessians_quad[(comp * hdim + off_dia) * nqp + q_point] =
5556 (hessian_in[comp][d][e] + hessian_in[comp][e][d]) * factor;
5557 }
5558 }
5559 // cell with general Jacobian, but constant within the cell
5560 else if (this->cell_type <= internal::MatrixFreeFunctions::affine)
5561 {
5562 const Tensor<2, dim, VectorizedArrayType> jac = this->jacobian[0];
5563 const VectorizedArrayType JxW =
5564 this->J_value[0] * this->quadrature_weights[q_point];
5565 for (unsigned int comp = 0; comp < n_components; ++comp)
5566 {
5567 Tensor<2, dim, VectorizedArrayType> hessian_c;
5568 if constexpr (n_components == 1)
5569 hessian_c = hessian_in;
5570 else
5571 hessian_c = hessian_in[comp];
5572
5573 // 1. tmp = hessian(u) * J
5574 VectorizedArrayType tmp[dim][dim];
5575 for (unsigned int i = 0; i < dim; ++i)
5576 for (unsigned int j = 0; j < dim; ++j)
5577 {
5578 tmp[i][j] = hessian_c[i][0] * jac[0][j];
5579 for (unsigned int k = 1; k < dim; ++k)
5580 tmp[i][j] += hessian_c[i][k] * jac[k][j];
5581 }
5582
5583 // 2. hessian_unit = J^T * tmp
5584 VectorizedArrayType tmp2[dim][dim];
5585 for (unsigned int i = 0; i < dim; ++i)
5586 for (unsigned int j = 0; j < dim; ++j)
5587 {
5588 tmp2[i][j] = jac[0][i] * tmp[0][j];
5589 for (unsigned int k = 1; k < dim; ++k)
5590 tmp2[i][j] += jac[k][i] * tmp[k][j];
5591 }
5592
5593 // diagonal part
5594 for (unsigned int d = 0; d < dim; ++d)
5595 this->hessians_quad[(comp * hdim + d) * nqp + q_point] =
5596 tmp2[d][d] * JxW;
5597
5598 // off diagonal part
5599 for (unsigned int d = 0, off_diag = dim; d < dim; ++d)
5600 for (unsigned int e = d + 1; e < dim; ++e, ++off_diag)
5601 this->hessians_quad[(comp * hdim + off_diag) * nqp + q_point] =
5602 (tmp2[d][e] + tmp2[e][d]) * JxW;
5603 }
5604 }
5605 else
5606 {
5607 const Tensor<2, dim, VectorizedArrayType> jac = this->jacobian[q_point];
5608 const VectorizedArrayType JxW = this->J_value[q_point];
5609 const auto &jac_grad = this->jacobian_gradients[q_point];
5610 for (unsigned int comp = 0; comp < n_components; ++comp)
5611 {
5612 Tensor<2, dim, VectorizedArrayType> hessian_c;
5613 if constexpr (n_components == 1)
5614 hessian_c = hessian_in;
5615 else
5616 hessian_c = hessian_in[comp];
5617
5618 // 1. tmp = hessian(u) * J
5619 VectorizedArrayType tmp[dim][dim];
5620 for (unsigned int i = 0; i < dim; ++i)
5621 for (unsigned int j = 0; j < dim; ++j)
5622 {
5623 tmp[i][j] = hessian_c[i][0] * jac[0][j];
5624 for (unsigned int k = 1; k < dim; ++k)
5625 tmp[i][j] += hessian_c[i][k] * jac[k][j];
5626 }
5627
5628 // 2. hessian_unit = J^T * tmp
5629 VectorizedArrayType tmp2[dim][dim];
5630 for (unsigned int i = 0; i < dim; ++i)
5631 for (unsigned int j = 0; j < dim; ++j)
5632 {
5633 tmp2[i][j] = jac[0][i] * tmp[0][j];
5634 for (unsigned int k = 1; k < dim; ++k)
5635 tmp2[i][j] += jac[k][i] * tmp[k][j];
5636 }
5637
5638 // diagonal part
5639 for (unsigned int d = 0; d < dim; ++d)
5640 this->hessians_quad[(comp * hdim + d) * nqp + q_point] =
5641 tmp2[d][d] * JxW;
5642
5643 // off diagonal part
5644 for (unsigned int d = 0, off_diag = dim; d < dim; ++d)
5645 for (unsigned int e = d + 1; e < dim; ++e, ++off_diag)
5646 this->hessians_quad[(comp * hdim + off_diag) * nqp + q_point] =
5647 (tmp2[d][e] + tmp2[e][d]) * JxW;
5648
5649 // 3. gradient_unit = J' * hessian
5650 for (unsigned int d = 0; d < dim; ++d)
5651 {
5652 VectorizedArrayType sum = 0;
5653 for (unsigned int e = 0; e < dim; ++e)
5654 sum += hessian_c[e][e] * jac_grad[e][d];
5655 for (unsigned int e = 0, count = dim; e < dim; ++e)
5656 for (unsigned int f = e + 1; f < dim; ++f, ++count)
5657 sum +=
5658 (hessian_c[e][f] + hessian_c[f][e]) * jac_grad[count][d];
5659 this->gradients_from_hessians_quad[(comp * nqp + q_point) * dim +
5660 d] = sum * JxW;
5661 }
5662 }
5663 }
5664}
5665
5666
5667
5668template <int dim,
5669 int n_components_,
5670 typename Number,
5671 bool is_face,
5672 typename VectorizedArrayType>
5673inline DEAL_II_ALWAYS_INLINE void
5675 submit_normal_hessian(const value_type normal_hessian_in,
5676 const unsigned int q_point)
5677{
5678 if constexpr (running_in_debug_mode())
5679 {
5680 Assert(this->is_reinitialized, ExcNotInitialized());
5681 }
5682 AssertIndexRange(q_point, this->n_quadrature_points);
5683 Assert(this->J_value != nullptr,
5685 "update_hessians"));
5686 Assert(this->jacobian != nullptr,
5688 "update_hessians"));
5689 if constexpr (running_in_debug_mode())
5690 {
5691 this->hessians_quad_submitted = true;
5692 }
5693
5694 // compute hessian_unit = J^T * hessian_in(u) * J
5695 const std::size_t nqp = this->n_quadrature_points;
5696 constexpr unsigned int hdim = (dim * (dim + 1)) / 2;
5697 if (this->cell_type <= internal::MatrixFreeFunctions::affine)
5698 {
5699 const VectorizedArrayType JxW =
5700 this->J_value[0] * this->quadrature_weights[q_point];
5701
5702 const auto nxj = this->normal_x_jacobian[0];
5703
5704 // diagonal part
5705 for (unsigned int d = 0; d < dim; ++d)
5706 {
5707 const auto nxj_d = nxj[d];
5708 const VectorizedArrayType factor = nxj_d * nxj_d * JxW;
5709 for (unsigned int comp = 0; comp < n_components; ++comp)
5710 if constexpr (n_components == 1)
5711 this->hessians_quad[d * nqp + q_point] =
5712 normal_hessian_in * factor;
5713 else
5714 this->hessians_quad[(comp * hdim + d) * nqp + q_point] =
5715 normal_hessian_in[comp] * factor;
5716 }
5717
5718 // off diagonal part
5719 for (unsigned int d = 1, off_dia = dim; d < dim; ++d)
5720 for (unsigned int e = 0; e < d; ++e, ++off_dia)
5721 {
5722 const auto jac_d = nxj[d];
5723 const auto jac_e = nxj[e];
5724 const VectorizedArrayType factor = jac_d * jac_e * JxW;
5725 for (unsigned int comp = 0; comp < n_components; ++comp)
5726 if constexpr (n_components == 1)
5727 this->hessians_quad[off_dia * nqp + q_point] =
5728 2. * normal_hessian_in * factor;
5729 else
5730 this->hessians_quad[(comp * hdim + off_dia) * nqp + q_point] =
5731 2. * normal_hessian_in[comp] * factor;
5732 }
5733 }
5734 else
5735 {
5736 const auto normal = this->normal_vector(q_point);
5737 const auto normal_projector = outer_product(normal, normal);
5738 if constexpr (n_components == 1)
5739 submit_hessian(normal_hessian_in * normal_projector, q_point);
5740 else
5741 {
5742 hessian_type tmp;
5743 for (unsigned int comp = 0; comp < n_components; ++comp)
5744 tmp[comp] = normal_hessian_in[comp] * normal_projector;
5745 submit_hessian(tmp, q_point);
5746 }
5747 }
5748}
5749
5750
5751
5752template <int dim,
5753 int n_components_,
5754 typename Number,
5755 bool is_face,
5756 typename VectorizedArrayType>
5757inline typename FEEvaluationBase<dim,
5758 n_components_,
5759 Number,
5760 is_face,
5761 VectorizedArrayType>::value_type
5763 integrate_value() const
5764{
5765 if constexpr (running_in_debug_mode())
5766 {
5767 Assert(this->is_reinitialized, ExcNotInitialized());
5768 Assert(this->values_quad_submitted == true,
5770 }
5771
5772 Tensor<1, n_components, VectorizedArrayType> return_value;
5773 const std::size_t nqp = this->n_quadrature_points;
5774 for (unsigned int q = 0; q < nqp; ++q)
5775 for (unsigned int comp = 0; comp < n_components; ++comp)
5776 return_value[comp] += this->values_quad[comp * nqp + q];
5777 if constexpr (n_components == 1)
5778 return return_value[0];
5779 else
5780 return return_value;
5781}
5782
5783
5784
5785template <int dim,
5786 int n_components_,
5787 typename Number,
5788 bool is_face,
5789 typename VectorizedArrayType>
5790template <int, typename>
5791inline DEAL_II_ALWAYS_INLINE VectorizedArrayType
5793 get_divergence(const unsigned int q_point) const
5794{
5795 static_assert(n_components == dim,
5796 "Do not try to modify the default template parameters used for"
5797 " selectively enabling this function via std::enable_if!");
5798
5799 if constexpr (running_in_debug_mode())
5800 {
5801 Assert(this->gradients_quad_initialized == true,
5803 }
5804 AssertIndexRange(q_point, this->n_quadrature_points);
5805 Assert(this->jacobian != nullptr,
5807 "update_gradients"));
5808
5809 VectorizedArrayType divergence;
5810 const std::size_t nqp = this->n_quadrature_points;
5811
5812 if (dim > 1 &&
5813 this->data->element_type ==
5815 {
5816 VectorizedArrayType inv_det =
5817 (!is_face &&
5818 this->cell_type == internal::MatrixFreeFunctions::cartesian) ?
5819 this->jacobian[0][0][0] *
5820 ((dim == 2) ? this->jacobian[0][1][1] :
5821 this->jacobian[0][1][1] * this->jacobian[0][2][2]) :
5822 determinant(this->jacobian[this->cell_type >
5824 q_point :
5825 0]);
5826
5827 // on faces in 2d, the determinant has the wrong sign due to ordering of
5828 // derivatives
5829 if (is_face && dim == 2 && this->get_face_no() < 2)
5830 inv_det = -inv_det;
5831
5832 // div * det(J^-1)
5833 divergence = this->gradients_quad[q_point * dim];
5834 for (unsigned int d = 1; d < dim; ++d)
5835 divergence += this->gradients_quad[(d * nqp + q_point) * dim + d];
5836 divergence *= inv_det;
5837 }
5838 else
5839 {
5840 if (!is_face &&
5842 {
5843 // Cartesian cell
5844 divergence =
5845 this->gradients_quad[q_point * dim] * this->jacobian[0][0][0];
5846 for (unsigned int d = 1; d < dim; ++d)
5847 divergence += this->gradients_quad[(d * nqp + q_point) * dim + d] *
5848 this->jacobian[0][d][d];
5849 }
5850 else
5851 {
5852 // cell with general/constant Jacobian
5853 const Tensor<2, dim, VectorizedArrayType> &jac =
5854 this->cell_type == internal::MatrixFreeFunctions::general ?
5855 this->jacobian[q_point] :
5856 this->jacobian[0];
5857 divergence = jac[0][0] * this->gradients_quad[q_point * dim];
5858 for (unsigned int e = 1; e < dim; ++e)
5859 divergence += jac[0][e] * this->gradients_quad[q_point * dim + e];
5860 for (unsigned int d = 1; d < dim; ++d)
5861 for (unsigned int e = 0; e < dim; ++e)
5862 divergence +=
5863 jac[d][e] * this->gradients_quad[(d * nqp + q_point) * dim + e];
5864 }
5865 }
5866 return divergence;
5867}
5868
5869
5870
5871template <int dim,
5872 int n_components_,
5873 typename Number,
5874 bool is_face,
5875 typename VectorizedArrayType>
5876template <int, typename>
5877inline DEAL_II_ALWAYS_INLINE SymmetricTensor<2, dim, VectorizedArrayType>
5879 get_symmetric_gradient(const unsigned int q_point) const
5880{
5881 static_assert(n_components == dim,
5882 "Do not try to modify the default template parameters used for"
5883 " selectively enabling this function via std::enable_if!");
5884
5885 // copy from generic function into dim-specialization function
5886 const auto grad = get_gradient(q_point);
5887 VectorizedArrayType symmetrized[(dim * dim + dim) / 2];
5888 VectorizedArrayType half = Number(0.5);
5889 for (unsigned int d = 0; d < dim; ++d)
5890 symmetrized[d] = grad[d][d];
5891 switch (dim)
5892 {
5893 case 1:
5894 break;
5895 case 2:
5896 symmetrized[2] = grad[0][1] + grad[1][0];
5897 symmetrized[2] *= half;
5898 break;
5899 case 3:
5900 symmetrized[3] = grad[0][1] + grad[1][0];
5901 symmetrized[3] *= half;
5902 symmetrized[4] = grad[0][2] + grad[2][0];
5903 symmetrized[4] *= half;
5904 symmetrized[5] = grad[1][2] + grad[2][1];
5905 symmetrized[5] *= half;
5906 break;
5907 default:
5909 }
5910 return SymmetricTensor<2, dim, VectorizedArrayType>(symmetrized);
5911}
5912
5913
5914
5915template <int dim,
5916 int n_components_,
5917 typename Number,
5918 bool is_face,
5919 typename VectorizedArrayType>
5920template <int, typename>
5922 typename FEEvaluationBase<dim,
5923 n_components_,
5924 Number,
5925 is_face,
5926 VectorizedArrayType>::curl_type
5928 get_curl(const unsigned int q_point) const
5929{
5930 static_assert(dim > 1 && n_components == dim,
5931 "Do not try to modify the default template parameters used for"
5932 " selectively enabling this function via std::enable_if!");
5933
5934 if (dim > 1 && this->data->element_type ==
5936 {
5937 // Piola transformation required: Since the transformation for Nedelec
5938 // is constructed to give a curl based on a scaled version of the
5939 // reference curl, this function turns out to be particularly simple.
5940 if constexpr (running_in_debug_mode())
5941 {
5942 Assert(this->gradients_quad_initialized == true,
5944 }
5945 AssertIndexRange(q_point, this->n_quadrature_points);
5946 Assert(this->jacobian != nullptr,
5948 "update_gradients"));
5949 curl_type curl;
5950 const std::size_t nqp = this->n_quadrature_points;
5951 const std::size_t nqp_d = nqp * dim;
5952 const VectorizedArrayType *gradients =
5953 this->gradients_quad + q_point * dim;
5954 if constexpr (dim == 2)
5955 curl = gradients[1 * nqp_d + 0] - gradients[0 * nqp_d + 1];
5956 else if constexpr (dim == 3)
5957 {
5958 curl[0] = gradients[2 * nqp_d + 1] - gradients[1 * nqp_d + 2];
5959 curl[1] = gradients[0 * nqp_d + 2] - gradients[2 * nqp_d + 0];
5960 curl[2] = gradients[1 * nqp_d + 0] - gradients[0 * nqp_d + 1];
5961 }
5962 else
5964
5965 if (!is_face &&
5967 {
5968 VectorizedArrayType inv_det =
5969 this->jacobian[0][0][0] *
5970 ((dim == 2) ? this->jacobian[0][1][1] :
5971 this->jacobian[0][1][1] * this->jacobian[0][2][2]);
5972
5973 const Tensor<2, dim, VectorizedArrayType> jac = this->jacobian[1];
5974
5975 // J * curl * det(J^-1)
5976 if constexpr (dim == 2)
5977 curl *= inv_det;
5978 else
5979 for (unsigned int d = 0; d < (dim == 2 ? 1 : dim); ++d)
5980 curl[d] *= jac[d][d] * inv_det;
5981 }
5982 else
5983 {
5984 // Cell with general/constant Jacobian.
5985 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
5986 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
5987 this->jacobian[q_point] :
5988 this->jacobian[0];
5989 const Tensor<2, dim, VectorizedArrayType> jac =
5990 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
5991 transpose(invert(inv_t_jac)) :
5992 this->jacobian[1];
5993
5994 VectorizedArrayType inv_det = determinant(inv_t_jac);
5995
5996 // on faces in 2d, the determinant has the wrong sign due to ordering
5997 // of derivatives
5998 if (is_face && dim == 2 && this->get_face_no() < 2)
5999 inv_det = -inv_det;
6000
6001 // J * curl * det(J^-1)
6002 // In case of 2D its just a scaling with det(J^-1)
6003 if constexpr (dim == 2)
6004 curl *= inv_det;
6005 else
6006 {
6007 Tensor<1, dim, VectorizedArrayType> curl_temp;
6008 for (unsigned int comp = 0; comp < dim; ++comp)
6009 {
6010 curl_temp[comp] = curl[0] * jac[comp][0];
6011 for (unsigned int e = 1; e < dim; ++e)
6012 curl_temp[comp] += jac[comp][e] * curl[e];
6013 }
6014 for (unsigned int comp = 0; comp < dim; ++comp)
6015 curl[comp] = curl_temp[comp] * inv_det;
6016 }
6017 }
6018 return curl;
6019 }
6020
6021 // copy from generic function into dim-specialization function
6022 const Tensor<2, dim, VectorizedArrayType> grad = get_gradient(q_point);
6023 curl_type curl;
6024 if constexpr (dim == 2)
6025 curl = grad[1][0] - grad[0][1];
6026 else if constexpr (dim == 3)
6027 {
6028 curl[0] = grad[2][1] - grad[1][2];
6029 curl[1] = grad[0][2] - grad[2][0];
6030 curl[2] = grad[1][0] - grad[0][1];
6031 }
6032 else
6034
6035 return curl;
6036}
6037
6038
6039
6040template <int dim,
6041 int n_components_,
6042 typename Number,
6043 bool is_face,
6044 typename VectorizedArrayType>
6045template <int, typename>
6046inline DEAL_II_ALWAYS_INLINE void
6048 submit_divergence(const VectorizedArrayType div_in,
6049 const unsigned int q_point)
6050{
6051 static_assert(n_components == dim,
6052 "Do not try to modify the default template parameters used for"
6053 " selectively enabling this function via std::enable_if!");
6054
6055 if constexpr (running_in_debug_mode())
6056 {
6057 Assert(this->is_reinitialized, ExcNotInitialized());
6058 }
6059 AssertIndexRange(q_point, this->n_quadrature_points);
6060 Assert(this->J_value != nullptr,
6062 "update_gradients"));
6063 Assert(this->jacobian != nullptr,
6065 "update_gradients"));
6066 if constexpr (running_in_debug_mode())
6067 {
6068 this->gradients_quad_submitted = true;
6069 }
6070
6071 const std::size_t nqp_d = this->n_quadrature_points * dim;
6072 VectorizedArrayType *gradients = this->gradients_quad + q_point * dim;
6073
6074 if (this->data->element_type ==
6076 {
6077 // General cell
6078
6079 // Derivatives are reordered for faces. Need to take this into account
6080 // and 1/inv_det != J_value for faces
6081 const VectorizedArrayType fac =
6082 (!is_face) ?
6083 this->quadrature_weights[q_point] * div_in :
6084 (this->cell_type > internal::MatrixFreeFunctions::affine ?
6085 this->J_value[q_point] :
6086 this->J_value[0] * this->quadrature_weights[q_point]) *
6087 div_in *
6089 this->jacobian[this->cell_type >
6090 internal::MatrixFreeFunctions::affine ?
6091 q_point :
6092 0]) *
6093 Number((dim == 2 && this->get_face_no() < 2) ? -1 : 1);
6094
6095 for (unsigned int d = 0; d < dim; ++d)
6096 {
6097 for (unsigned int e = 0; e < dim; ++e)
6098 gradients[d * nqp_d + e] = (d == e) ? fac : 0.;
6099 }
6100 this->divergence_is_requested = true;
6101 }
6102 else
6103 {
6104 if (!is_face &&
6106 {
6107 const VectorizedArrayType fac =
6108 this->J_value[0] * this->quadrature_weights[q_point] * div_in;
6109 for (unsigned int d = 0; d < dim; ++d)
6110 {
6111 const VectorizedArrayType jac_dd = this->jacobian[0][d][d];
6112 for (unsigned int e = 0; e < dim; ++e)
6113 gradients[d * nqp_d + e] = (d == e) ? fac * jac_dd : 0.;
6114 }
6115 }
6116 else
6117 {
6118 const Tensor<2, dim, VectorizedArrayType> jac =
6119 this->cell_type == internal::MatrixFreeFunctions::general ?
6120 this->jacobian[q_point] :
6121 this->jacobian[0];
6122 const VectorizedArrayType fac =
6123 (this->cell_type == internal::MatrixFreeFunctions::general ?
6124 this->J_value[q_point] :
6125 this->J_value[0] * this->quadrature_weights[q_point]) *
6126 div_in;
6127 for (unsigned int d = 0; d < dim; ++d)
6128 {
6129 for (unsigned int e = 0; e < dim; ++e)
6130 gradients[d * nqp_d + e] = jac[d][e] * fac;
6131 }
6132 }
6133 }
6134}
6135
6136
6137
6138template <int dim,
6139 int n_components_,
6140 typename Number,
6141 bool is_face,
6142 typename VectorizedArrayType>
6143template <int, typename>
6144inline DEAL_II_ALWAYS_INLINE void
6147 const SymmetricTensor<2, dim, VectorizedArrayType> sym_grad,
6148 const unsigned int q_point)
6149{
6150 static_assert(n_components == dim,
6151 "Do not try to modify the default template parameters used for"
6152 " selectively enabling this function via std::enable_if!");
6153
6155 this->data->element_type !=
6158
6159 // could have used base class operator, but that involves some overhead
6160 // which is inefficient. it is nice to have the symmetric tensor because
6161 // that saves some operations
6162 if constexpr (running_in_debug_mode())
6163 {
6164 Assert(this->is_reinitialized, ExcNotInitialized());
6165 }
6166 AssertIndexRange(q_point, this->n_quadrature_points);
6167 Assert(this->J_value != nullptr,
6169 "update_gradients"));
6170 Assert(this->jacobian != nullptr,
6172 "update_gradients"));
6173 if constexpr (running_in_debug_mode())
6174 {
6175 this->gradients_quad_submitted = true;
6176 }
6177
6178 const std::size_t nqp_d = this->n_quadrature_points * dim;
6179 VectorizedArrayType *gradients = this->gradients_quad + dim * q_point;
6180 if (!is_face && this->cell_type == internal::MatrixFreeFunctions::cartesian)
6181 {
6182 const VectorizedArrayType JxW =
6183 this->J_value[0] * this->quadrature_weights[q_point];
6184 const Tensor<2, dim, VectorizedArrayType> jac = this->jacobian[0];
6185 for (unsigned int d = 0; d < dim; ++d)
6186 gradients[d * nqp_d + d] =
6187 (sym_grad.access_raw_entry(d) * JxW * jac[d][d]);
6188 for (unsigned int e = 0, counter = dim; e < dim; ++e)
6189 for (unsigned int d = e + 1; d < dim; ++d, ++counter)
6190 {
6191 const VectorizedArrayType value =
6192 sym_grad.access_raw_entry(counter) * JxW;
6193 gradients[e * nqp_d + d] = value * jac[d][d];
6194 gradients[d * nqp_d + e] = value * jac[e][e];
6195 }
6196 }
6197 // general/affine cell type
6198 else
6199 {
6200 const VectorizedArrayType JxW =
6201 this->cell_type == internal::MatrixFreeFunctions::general ?
6202 this->J_value[q_point] :
6203 this->J_value[0] * this->quadrature_weights[q_point];
6204 const Tensor<2, dim, VectorizedArrayType> jac =
6205 this->cell_type == internal::MatrixFreeFunctions::general ?
6206 this->jacobian[q_point] :
6207 this->jacobian[0];
6208 VectorizedArrayType weighted[dim][dim];
6209 for (unsigned int i = 0; i < dim; ++i)
6210 weighted[i][i] = sym_grad.access_raw_entry(i) * JxW;
6211 for (unsigned int i = 0, counter = dim; i < dim; ++i)
6212 for (unsigned int j = i + 1; j < dim; ++j, ++counter)
6213 {
6214 const VectorizedArrayType value =
6215 sym_grad.access_raw_entry(counter) * JxW;
6216 weighted[i][j] = value;
6217 weighted[j][i] = value;
6218 }
6219 for (unsigned int comp = 0; comp < dim; ++comp)
6220 for (unsigned int d = 0; d < dim; ++d)
6221 {
6222 VectorizedArrayType new_val = jac[0][d] * weighted[comp][0];
6223 for (unsigned int e = 1; e < dim; ++e)
6224 new_val += jac[e][d] * weighted[comp][e];
6225 gradients[comp * nqp_d + d] = new_val;
6226 }
6227 }
6228}
6229
6230
6231
6232template <int dim,
6233 int n_components_,
6234 typename Number,
6235 bool is_face,
6236 typename VectorizedArrayType>
6237template <int, typename>
6238inline DEAL_II_ALWAYS_INLINE void
6241 const typename FEEvaluationBase<dim,
6242 n_components_,
6243 Number,
6244 is_face,
6245 VectorizedArrayType>::curl_type curl,
6246 const unsigned int q_point)
6247{
6248 static_assert(n_components == dim,
6249 "Do not try to modify the default template parameters used for"
6250 " selectively enabling this function via std::enable_if!");
6251
6252 Tensor<2, dim, VectorizedArrayType> grad;
6253
6254 if (this->data->element_type ==
6256 {
6257 curl_type curl_temp;
6258
6259 // Piola transform is required
6260 AssertIndexRange(q_point, this->n_quadrature_points);
6261 Assert(this->J_value != nullptr,
6263 "update_value"));
6264# ifdef DEBUG
6265 Assert(this->is_reinitialized, ExcNotInitialized());
6266 this->gradients_quad_submitted = true;
6267# endif
6268
6269 const std::size_t nqp_d = this->n_quadrature_points * dim;
6270 VectorizedArrayType *gradients = this->gradients_quad + q_point * dim;
6271
6272 if (!is_face &&
6274 {
6275 const Tensor<2, dim, VectorizedArrayType> jac = this->jacobian[1];
6276 const VectorizedArrayType weight = this->quadrature_weights[q_point];
6277
6278 if constexpr (dim == 2)
6279 {
6280 curl_temp = curl * weight;
6281 }
6282 else if constexpr (dim == 3)
6283 {
6284 for (unsigned int comp = 0; comp < dim; ++comp)
6285 {
6286 curl_temp[comp] = curl[comp] * jac[comp][comp] * weight;
6287 }
6288 }
6289 else
6291 }
6292 else
6293 {
6294 // Affine or general cell
6295 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
6296 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
6297 this->jacobian[q_point] :
6298 this->jacobian[0];
6299
6300 // Derivatives are reordered for faces. Need to take this into
6301 // account and 1/inv_det != J_value for faces
6302 const VectorizedArrayType fac =
6303 (!is_face) ?
6304 this->quadrature_weights[q_point] :
6305 (((this->cell_type > internal::MatrixFreeFunctions::affine) ?
6306 this->J_value[q_point] :
6307 this->J_value[0] * this->quadrature_weights[q_point]) *
6308 ((dim == 2 && this->get_face_no() < 2) ?
6309 -determinant(inv_t_jac) :
6310 determinant(inv_t_jac)));
6311 const Tensor<2, dim, VectorizedArrayType> jac =
6312 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
6313 transpose(invert(inv_t_jac)) :
6314 this->jacobian[1];
6315
6316 if constexpr (dim == 2)
6317 {
6318 curl_temp = curl * fac;
6319 }
6320 else if constexpr (dim == 3)
6321 {
6322 // J^T * u * factor
6323 for (unsigned int comp = 0; comp < n_components; ++comp)
6324 {
6325 curl_temp[comp] = curl[0] * jac[0][comp];
6326 for (unsigned int e = 1; e < dim; ++e)
6327 curl_temp[comp] += curl[e] * jac[e][comp];
6328 curl_temp[comp] *= fac;
6329 }
6330 }
6331 else
6333 }
6334 switch (dim)
6335 {
6336 case 2:
6337 grad[1][0] = curl_temp[0];
6338 grad[0][1] = -curl_temp[0];
6339 grad[0][0] = 0;
6340 grad[1][1] = 0;
6341 break;
6342 case 3:
6343 grad[2][1] = curl_temp[0];
6344 grad[1][2] = -curl_temp[0];
6345 grad[0][2] = curl_temp[1];
6346 grad[2][0] = -curl_temp[1];
6347 grad[1][0] = curl_temp[2];
6348 grad[0][1] = -curl_temp[2];
6349 grad[0][0] = 0;
6350 grad[1][1] = 0;
6351 grad[2][2] = 0;
6352 break;
6353 default:
6355 }
6356 for (unsigned int d = 0; d < dim; ++d)
6357 {
6358 for (unsigned int comp = 0; comp < n_components; ++comp)
6359 gradients[comp * nqp_d + d] = grad[comp][d];
6360 }
6361 return;
6362 }
6363
6364 if constexpr (dim == 2)
6365 {
6366 grad[1][0] = curl;
6367 grad[0][1] = -curl;
6368 }
6369 else if constexpr (dim == 3)
6370 {
6371 grad[2][1] = curl[0];
6372 grad[1][2] = -curl[0];
6373 grad[0][2] = curl[1];
6374 grad[2][0] = -curl[1];
6375 grad[1][0] = curl[2];
6376 grad[0][1] = -curl[2];
6377 }
6378 else
6380
6381 submit_gradient(grad, q_point);
6382}
6383
6384
6385
6386/*-------------------------- FEEvaluation -----------------------------------*/
6387
6388
6389template <int dim,
6390 int fe_degree,
6391 int n_q_points_1d,
6392 int n_components_,
6393 typename Number,
6394 typename VectorizedArrayType>
6395inline FEEvaluation<dim,
6396 fe_degree,
6397 n_q_points_1d,
6398 n_components_,
6399 Number,
6400 VectorizedArrayType>::
6401 FEEvaluation(const MatrixFree<dim, Number, VectorizedArrayType> &matrix_free,
6402 const unsigned int fe_no,
6403 const unsigned int quadrature_index,
6404 const unsigned int first_selected_component,
6405 const unsigned int active_fe_index,
6406 const unsigned int active_quad_index)
6407 : BaseClass(matrix_free,
6408 fe_no,
6409 first_selected_component,
6410 quadrature_index,
6411 fe_degree,
6412 static_n_q_points,
6413 true /*note: this is not a face*/,
6414 active_fe_index,
6415 active_quad_index,
6416 numbers::invalid_unsigned_int /*face_type*/)
6417 , dofs_per_component(this->data->dofs_per_component_on_cell)
6418 , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
6419 , n_q_points(this->data->n_q_points)
6420{
6421 check_template_arguments(fe_no, 0);
6422}
6423
6424
6425
6426template <int dim,
6427 int fe_degree,
6428 int n_q_points_1d,
6429 int n_components_,
6430 typename Number,
6431 typename VectorizedArrayType>
6432inline FEEvaluation<dim,
6433 fe_degree,
6434 n_q_points_1d,
6435 n_components_,
6436 Number,
6437 VectorizedArrayType>::
6438 FEEvaluation(const MatrixFree<dim, Number, VectorizedArrayType> &matrix_free,
6439 const std::pair<unsigned int, unsigned int> &range,
6440 const unsigned int dof_handler_index,
6441 const unsigned int quadrature_index,
6442 const unsigned int first_selected_component)
6443 : FEEvaluation(matrix_free,
6444 dof_handler_index,
6445 quadrature_index,
6446 first_selected_component,
6447 matrix_free.get_cell_active_fe_index(range, dof_handler_index))
6448{}
6449
6450
6451
6452template <int dim,
6453 int fe_degree,
6454 int n_q_points_1d,
6455 int n_components_,
6456 typename Number,
6457 typename VectorizedArrayType>
6458inline FEEvaluation<dim,
6459 fe_degree,
6460 n_q_points_1d,
6461 n_components_,
6462 Number,
6463 VectorizedArrayType>::
6464 FEEvaluation(const Mapping<dim> &mapping,
6465 const FiniteElement<dim> &fe,
6466 const Quadrature<1> &quadrature,
6467 const UpdateFlags update_flags,
6468 const unsigned int first_selected_component)
6469 : BaseClass(mapping,
6470 fe,
6471 quadrature,
6472 update_flags,
6473 first_selected_component,
6474 nullptr)
6475 , dofs_per_component(this->data->dofs_per_component_on_cell)
6476 , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
6477 , n_q_points(this->data->n_q_points)
6478{
6479 check_template_arguments(numbers::invalid_unsigned_int, 0);
6480}
6481
6482
6483
6484template <int dim,
6485 int fe_degree,
6486 int n_q_points_1d,
6487 int n_components_,
6488 typename Number,
6489 typename VectorizedArrayType>
6490inline FEEvaluation<dim,
6491 fe_degree,
6492 n_q_points_1d,
6493 n_components_,
6494 Number,
6495 VectorizedArrayType>::
6496 FEEvaluation(const FiniteElement<dim> &fe,
6497 const Quadrature<1> &quadrature,
6498 const UpdateFlags update_flags,
6499 const unsigned int first_selected_component)
6500 : BaseClass(StaticMappingQ1<dim>::mapping,
6501 fe,
6502 quadrature,
6503 update_flags,
6504 first_selected_component,
6505 nullptr)
6506 , dofs_per_component(this->data->dofs_per_component_on_cell)
6507 , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
6508 , n_q_points(this->data->n_q_points)
6509{
6510 check_template_arguments(numbers::invalid_unsigned_int, 0);
6511}
6512
6513
6514
6515template <int dim,
6516 int fe_degree,
6517 int n_q_points_1d,
6518 int n_components_,
6519 typename Number,
6520 typename VectorizedArrayType>
6521inline FEEvaluation<dim,
6522 fe_degree,
6523 n_q_points_1d,
6524 n_components_,
6525 Number,
6526 VectorizedArrayType>::
6527 FEEvaluation(const FiniteElement<dim> &fe,
6528 const FEEvaluationData<dim, VectorizedArrayType, false> &other,
6529 const unsigned int first_selected_component)
6530 : BaseClass(other.mapped_geometry->get_fe_values().get_mapping(),
6531 fe,
6532 other.mapped_geometry->get_quadrature(),
6533 other.mapped_geometry->get_fe_values().get_update_flags(),
6534 first_selected_component,
6535 &other)
6536 , dofs_per_component(this->data->dofs_per_component_on_cell)
6537 , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
6538 , n_q_points(this->data->n_q_points)
6539{
6540 check_template_arguments(numbers::invalid_unsigned_int, 0);
6541}
6542
6543
6544
6545template <int dim,
6546 int fe_degree,
6547 int n_q_points_1d,
6548 int n_components_,
6549 typename Number,
6550 typename VectorizedArrayType>
6551inline FEEvaluation<dim,
6552 fe_degree,
6553 n_q_points_1d,
6554 n_components_,
6555 Number,
6556 VectorizedArrayType>::FEEvaluation(const FEEvaluation
6557 &other)
6558 : BaseClass(other)
6559 , dofs_per_component(this->data->dofs_per_component_on_cell)
6560 , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
6561 , n_q_points(this->data->n_q_points)
6562{
6563 check_template_arguments(numbers::invalid_unsigned_int, 0);
6564}
6565
6566
6567
6568template <int dim,
6569 int fe_degree,
6570 int n_q_points_1d,
6571 int n_components_,
6572 typename Number,
6573 typename VectorizedArrayType>
6574inline FEEvaluation<dim,
6575 fe_degree,
6576 n_q_points_1d,
6577 n_components_,
6578 Number,
6579 VectorizedArrayType> &
6580FEEvaluation<dim,
6581 fe_degree,
6582 n_q_points_1d,
6583 n_components_,
6584 Number,
6585 VectorizedArrayType>::operator=(const FEEvaluation &other)
6586{
6587 BaseClass::operator=(other);
6588 check_template_arguments(numbers::invalid_unsigned_int, 0);
6589 return *this;
6590}
6591
6592
6593
6594template <int dim,
6595 int fe_degree,
6596 int n_q_points_1d,
6597 int n_components_,
6598 typename Number,
6599 typename VectorizedArrayType>
6600inline void
6601FEEvaluation<dim,
6602 fe_degree,
6603 n_q_points_1d,
6604 n_components_,
6605 Number,
6606 VectorizedArrayType>::
6607 check_template_arguments(const unsigned int dof_handler_index,
6608 const unsigned int first_selected_component)
6609{
6610 (void)dof_handler_index;
6611 (void)first_selected_component;
6612
6613 Assert(
6614 this->data->dofs_per_component_on_cell > 0,
6615 ExcMessage(
6616 "There is nothing useful you can do with an FEEvaluation object with "
6617 "FE_Nothing, i.e., without DoFs! If you have passed to "
6618 "MatrixFree::reinit() a collection of finite elements also containing "
6619 "FE_Nothing, please check - before creating FEEvaluation - the category "
6620 "of the current range by calling either "
6621 "MatrixFree::get_cell_range_category(range) or "
6622 "MatrixFree::get_face_range_category(range). The returned category "
6623 "is the index of the active FE, which you can use to exclude "
6624 "FE_Nothing."));
6625
6626 if constexpr (running_in_debug_mode())
6627 {
6628 // print error message when the dimensions do not match. Propose a
6629 // possible fix
6630 if ((static_cast<unsigned int>(fe_degree) !=
6632 static_cast<unsigned int>(fe_degree) !=
6633 this->data->data.front().fe_degree) ||
6634 n_q_points != this->n_quadrature_points)
6635 {
6636 std::string message =
6637 "-------------------------------------------------------\n";
6638 message +=
6639 "Illegal arguments in constructor/wrong template arguments!\n";
6640 message += " Called --> FEEvaluation<dim,";
6641 message += Utilities::int_to_string(fe_degree) + ",";
6642 message += Utilities::int_to_string(n_q_points_1d);
6643 message += "," + Utilities::int_to_string(n_components);
6644 message += ",Number>(data";
6645 if (first_selected_component != numbers::invalid_unsigned_int)
6646 {
6647 message +=
6648 ", " + Utilities::int_to_string(dof_handler_index) + ", ";
6649 message +=
6650 Utilities::int_to_string(this->quadrature_index) + ", ";
6651 message += Utilities::int_to_string(first_selected_component);
6652 }
6653 message += ")\n";
6654
6655 // check whether some other vector component has the correct number of
6656 // points
6657 unsigned int proposed_dof_comp = numbers::invalid_unsigned_int,
6658 proposed_fe_comp = numbers::invalid_unsigned_int,
6659 proposed_quad_comp = numbers::invalid_unsigned_int;
6660 if (dof_handler_index != numbers::invalid_unsigned_int)
6661 {
6662 if (static_cast<unsigned int>(fe_degree) ==
6663 this->data->data.front().fe_degree)
6664 {
6665 proposed_dof_comp = dof_handler_index;
6666 proposed_fe_comp = first_selected_component;
6667 }
6668 else
6669 for (unsigned int no = 0;
6670 no < this->matrix_free->n_components();
6671 ++no)
6672 for (unsigned int nf = 0;
6673 nf < this->matrix_free->n_base_elements(no);
6674 ++nf)
6675 if (this->matrix_free
6676 ->get_shape_info(no, 0, nf, this->active_fe_index, 0)
6677 .data.front()
6678 .fe_degree == static_cast<unsigned int>(fe_degree))
6679 {
6680 proposed_dof_comp = no;
6681 proposed_fe_comp = nf;
6682 break;
6683 }
6684 if (n_q_points ==
6685 this->mapping_data->descriptor[this->active_quad_index]
6686 .n_q_points)
6687 proposed_quad_comp = this->quadrature_index;
6688 else
6689 for (unsigned int no = 0;
6690 no <
6691 this->matrix_free->get_mapping_info().cell_data.size();
6692 ++no)
6693 if (this->matrix_free->get_mapping_info()
6694 .cell_data[no]
6695 .descriptor[this->active_quad_index]
6696 .n_q_points == n_q_points)
6697 {
6698 proposed_quad_comp = no;
6699 break;
6700 }
6701 }
6702 if (proposed_dof_comp != numbers::invalid_unsigned_int &&
6703 proposed_quad_comp != numbers::invalid_unsigned_int)
6704 {
6705 if (proposed_dof_comp != first_selected_component)
6706 message += "Wrong vector component selection:\n";
6707 else
6708 message += "Wrong quadrature formula selection:\n";
6709 message += " Did you mean FEEvaluation<dim,";
6710 message += Utilities::int_to_string(fe_degree) + ",";
6711 message += Utilities::int_to_string(n_q_points_1d);
6712 message += "," + Utilities::int_to_string(n_components);
6713 message += ",Number>(data";
6714 if (dof_handler_index != numbers::invalid_unsigned_int)
6715 {
6716 message +=
6717 ", " + Utilities::int_to_string(proposed_dof_comp) + ", ";
6718 message +=
6719 Utilities::int_to_string(proposed_quad_comp) + ", ";
6720 message += Utilities::int_to_string(proposed_fe_comp);
6721 }
6722 message += ")?\n";
6723 std::string correct_pos;
6724 if (proposed_dof_comp != dof_handler_index)
6725 correct_pos = " ^ ";
6726 else
6727 correct_pos = " ";
6728 if (proposed_quad_comp != this->quadrature_index)
6729 correct_pos += " ^ ";
6730 else
6731 correct_pos += " ";
6732 if (proposed_fe_comp != first_selected_component)
6733 correct_pos += " ^\n";
6734 else
6735 correct_pos += " \n";
6736 message +=
6737 " " +
6738 correct_pos;
6739 }
6740 // ok, did not find the numbers specified by the template arguments in
6741 // the given list. Suggest correct template arguments
6742 const unsigned int proposed_n_q_points_1d = static_cast<unsigned int>(
6743 std::pow(1.001 * this->n_quadrature_points, 1. / dim));
6744 message += "Wrong template arguments:\n";
6745 message += " Did you mean FEEvaluation<dim,";
6746 message +=
6747 Utilities::int_to_string(this->data->data.front().fe_degree) + ",";
6748 message += Utilities::int_to_string(proposed_n_q_points_1d);
6749 message += "," + Utilities::int_to_string(n_components);
6750 message += ",Number>(data";
6751 if (dof_handler_index != numbers::invalid_unsigned_int)
6752 {
6753 message +=
6754 ", " + Utilities::int_to_string(dof_handler_index) + ", ";
6755 message += Utilities::int_to_string(this->quadrature_index);
6756 message +=
6757 ", " + Utilities::int_to_string(first_selected_component);
6758 }
6759 message += ")?\n";
6760 std::string correct_pos;
6761 if (this->data->data.front().fe_degree !=
6762 static_cast<unsigned int>(fe_degree))
6763 correct_pos = " ^";
6764 else
6765 correct_pos = " ";
6766 if (proposed_n_q_points_1d != n_q_points_1d)
6767 correct_pos += " ^\n";
6768 else
6769 correct_pos += " \n";
6770 message += " " + correct_pos;
6771
6772 Assert(static_cast<unsigned int>(fe_degree) ==
6773 this->data->data.front().fe_degree &&
6774 n_q_points == this->n_quadrature_points,
6775 ExcMessage(message));
6776 }
6777 if (dof_handler_index != numbers::invalid_unsigned_int)
6779 n_q_points,
6780 this->mapping_data->descriptor[this->active_quad_index].n_q_points);
6781 }
6782}
6783
6784
6785
6786template <int dim,
6787 int fe_degree,
6788 int n_q_points_1d,
6789 int n_components_,
6790 typename Number,
6791 typename VectorizedArrayType>
6792inline void
6793FEEvaluation<dim,
6794 fe_degree,
6795 n_q_points_1d,
6796 n_components_,
6797 Number,
6798 VectorizedArrayType>::reinit(const unsigned int cell_index)
6799{
6800 Assert(this->matrix_free != nullptr,
6801 ExcMessage("FEEvaluation was initialized without a matrix-free object."
6802 " Integer indexing is not possible."));
6803
6804 Assert(this->dof_info != nullptr, ExcNotInitialized());
6805 Assert(this->mapping_data != nullptr, ExcNotInitialized());
6806 this->cell = cell_index;
6807 this->cell_type =
6808 this->matrix_free->get_mapping_info().get_cell_type(cell_index);
6809
6810 const unsigned int offsets =
6811 this->mapping_data->data_index_offsets[cell_index];
6812 this->jacobian = &this->mapping_data->jacobians[0][offsets];
6813 this->J_value = &this->mapping_data->JxW_values[offsets];
6814 if (!this->mapping_data->jacobian_gradients[0].empty())
6815 {
6816 this->jacobian_gradients =
6817 this->mapping_data->jacobian_gradients[0].data() + offsets;
6818 this->jacobian_gradients_non_inverse =
6819 this->mapping_data->jacobian_gradients_non_inverse[0].data() + offsets;
6820 }
6821
6822 if (this->matrix_free->n_active_entries_per_cell_batch(this->cell) == n_lanes)
6823 {
6825 for (unsigned int i = 0; i < n_lanes; ++i)
6826 this->cell_ids[i] = cell_index * n_lanes + i;
6827 }
6828 else
6829 {
6830 unsigned int i = 0;
6831 for (; i < this->matrix_free->n_active_entries_per_cell_batch(this->cell);
6832 ++i)
6833 this->cell_ids[i] = cell_index * n_lanes + i;
6834 for (; i < n_lanes; ++i)
6835 this->cell_ids[i] = numbers::invalid_unsigned_int;
6836 }
6837
6838 if (this->mapping_data->quadrature_points.empty() == false)
6839 this->quadrature_points =
6840 &this->mapping_data->quadrature_points
6841 [this->mapping_data->quadrature_point_offsets[this->cell]];
6842
6843 if constexpr (running_in_debug_mode())
6844 {
6845 this->is_reinitialized = true;
6846 this->dof_values_initialized = false;
6847 this->values_quad_initialized = false;
6848 this->gradients_quad_initialized = false;
6849 this->hessians_quad_initialized = false;
6850 }
6851}
6852
6853
6854
6855template <int dim,
6856 int fe_degree,
6857 int n_q_points_1d,
6858 int n_components_,
6859 typename Number,
6860 typename VectorizedArrayType>
6861inline void
6862FEEvaluation<dim,
6863 fe_degree,
6864 n_q_points_1d,
6865 n_components_,
6866 Number,
6867 VectorizedArrayType>::reinit(const std::array<unsigned int,
6868 n_lanes> &cell_ids)
6869{
6870 Assert(this->dof_info != nullptr, ExcNotInitialized());
6871 Assert(this->mapping_data != nullptr, ExcNotInitialized());
6872
6873 this->cell = numbers::invalid_unsigned_int;
6874 this->cell_ids = cell_ids;
6875
6876 // determine type of cell batch
6878
6879 for (unsigned int v = 0; v < n_lanes; ++v)
6880 {
6881 const unsigned int cell_index = cell_ids[v];
6882
6883 if (cell_index == numbers::invalid_unsigned_int)
6884 continue;
6885
6886 this->cell_type =
6887 std::max(this->cell_type,
6888 this->matrix_free->get_mapping_info().get_cell_type(
6889 cell_index / n_lanes));
6890 }
6891
6892 // allocate memory for internal data storage
6893 if (this->mapped_geometry == nullptr)
6894 this->mapped_geometry =
6895 std::make_shared<internal::MatrixFreeFunctions::
6896 MappingDataOnTheFly<dim, VectorizedArrayType>>();
6897
6898 auto &mapping_storage = this->mapped_geometry->get_data_storage();
6899
6900 auto &this_jacobian_data = mapping_storage.jacobians[0];
6901 auto &this_J_value_data = mapping_storage.JxW_values;
6902 auto &this_jacobian_gradients_data = mapping_storage.jacobian_gradients[0];
6903 auto &this_jacobian_gradients_non_inverse_data =
6904 mapping_storage.jacobian_gradients_non_inverse[0];
6905 auto &this_quadrature_points_data = mapping_storage.quadrature_points;
6906
6908 {
6909 if (this_jacobian_data.size() != 2)
6910 this_jacobian_data.resize_fast(2);
6911
6912 if (this_J_value_data.size() != 1)
6913 this_J_value_data.resize_fast(1);
6914
6915 const auto &update_flags_cells =
6916 this->matrix_free->get_mapping_info().update_flags_cells;
6917
6918 if (update_flags_cells & update_jacobian_grads &&
6919 this_jacobian_gradients_data.size() != 1)
6920 {
6921 this_jacobian_gradients_data.resize_fast(1);
6922 this_jacobian_gradients_non_inverse_data.resize_fast(1);
6923 }
6924
6925 if (update_flags_cells & update_quadrature_points &&
6926 this_quadrature_points_data.size() != 1)
6927 this_quadrature_points_data.resize_fast(1);
6928 }
6929 else
6930 {
6931 if (this_jacobian_data.size() != this->n_quadrature_points)
6932 this_jacobian_data.resize_fast(this->n_quadrature_points);
6933
6934 if (this_J_value_data.size() != this->n_quadrature_points)
6935 this_J_value_data.resize_fast(this->n_quadrature_points);
6936
6937 const auto &update_flags_cells =
6938 this->matrix_free->get_mapping_info().update_flags_cells;
6939
6940 if (update_flags_cells & update_jacobian_grads &&
6941 this_jacobian_gradients_data.size() != this->n_quadrature_points)
6942 {
6943 this_jacobian_gradients_data.resize_fast(this->n_quadrature_points);
6944 this_jacobian_gradients_non_inverse_data.resize_fast(
6945 this->n_quadrature_points);
6946 }
6947
6948 if (update_flags_cells & update_quadrature_points &&
6949 this_quadrature_points_data.size() != this->n_quadrature_points)
6950 this_quadrature_points_data.resize_fast(this->n_quadrature_points);
6951 }
6952
6953 // set pointers to internal data storage
6954 this->jacobian = this_jacobian_data.data();
6955 this->J_value = this_J_value_data.data();
6956 this->jacobian_gradients = this_jacobian_gradients_data.data();
6957 this->jacobian_gradients_non_inverse =
6958 this_jacobian_gradients_non_inverse_data.data();
6959 this->quadrature_points = this_quadrature_points_data.data();
6960
6961 // fill internal data storage lane by lane
6962 for (unsigned int v = 0; v < n_lanes; ++v)
6963 {
6964 const unsigned int cell_index = cell_ids[v];
6965
6966 if (cell_index == numbers::invalid_unsigned_int)
6967 continue;
6968
6969 const unsigned int cell_batch_index = cell_index / n_lanes;
6970 const unsigned int offsets =
6971 this->mapping_data->data_index_offsets[cell_batch_index];
6972 const unsigned int lane = cell_index % n_lanes;
6973
6974 if (this->cell_type <=
6976 {
6977 // case that all cells are Cartesian or affine
6978 for (unsigned int q = 0; q < 2; ++q)
6979 for (unsigned int i = 0; i < dim; ++i)
6980 for (unsigned int j = 0; j < dim; ++j)
6981 this_jacobian_data[q][i][j][v] =
6982 this->mapping_data->jacobians[0][offsets + q][i][j][lane];
6983
6984 const unsigned int q = 0;
6985
6986 this_J_value_data[q][v] =
6987 this->mapping_data->JxW_values[offsets + q][lane];
6988
6989 const auto &update_flags_cells =
6990 this->matrix_free->get_mapping_info().update_flags_cells;
6991
6992 if (update_flags_cells & update_jacobian_grads)
6993 {
6994 for (unsigned int i = 0; i < dim * (dim + 1) / 2; ++i)
6995 for (unsigned int j = 0; j < dim; ++j)
6996 this_jacobian_gradients_data[q][i][j][v] =
6997 this->mapping_data
6998 ->jacobian_gradients[0][offsets + q][i][j][lane];
6999
7000 for (unsigned int i = 0; i < dim * (dim + 1) / 2; ++i)
7001 for (unsigned int j = 0; j < dim; ++j)
7002 this_jacobian_gradients_non_inverse_data[q][i][j][v] =
7003 this->mapping_data
7004 ->jacobian_gradients_non_inverse[0][offsets + q][i][j]
7005 [lane];
7006 }
7007
7008 if (update_flags_cells & update_quadrature_points)
7009 for (unsigned int i = 0; i < dim; ++i)
7010 this_quadrature_points_data[q][i][v] =
7011 this->mapping_data->quadrature_points
7012 [this->mapping_data
7013 ->quadrature_point_offsets[cell_batch_index] +
7014 q][i][lane];
7015 }
7016 else
7017 {
7018 // general case that at least one cell is not Cartesian or affine
7019 const auto cell_type =
7020 this->matrix_free->get_mapping_info().get_cell_type(
7021 cell_batch_index);
7022
7023 for (unsigned int q = 0; q < this->n_quadrature_points; ++q)
7024 {
7025 const unsigned int q_src =
7026 (cell_type <=
7028 0 :
7029 q;
7030
7031 this_J_value_data[q][v] =
7032 this->mapping_data->JxW_values[offsets + q_src][lane];
7033
7034 for (unsigned int i = 0; i < dim; ++i)
7035 for (unsigned int j = 0; j < dim; ++j)
7036 this_jacobian_data[q][i][j][v] =
7037 this->mapping_data
7038 ->jacobians[0][offsets + q_src][i][j][lane];
7039
7040 const auto &update_flags_cells =
7041 this->matrix_free->get_mapping_info().update_flags_cells;
7042
7043 if (update_flags_cells & update_jacobian_grads)
7044 {
7045 for (unsigned int i = 0; i < dim * (dim + 1) / 2; ++i)
7046 for (unsigned int j = 0; j < dim; ++j)
7047 this_jacobian_gradients_data[q][i][j][v] =
7048 this->mapping_data
7049 ->jacobian_gradients[0][offsets + q_src][i][j][lane];
7050
7051 for (unsigned int i = 0; i < dim * (dim + 1) / 2; ++i)
7052 for (unsigned int j = 0; j < dim; ++j)
7053 this_jacobian_gradients_non_inverse_data[q][i][j][v] =
7054 this->mapping_data
7055 ->jacobian_gradients_non_inverse[0][offsets + q_src]
7056 [i][j][lane];
7057 }
7058
7059 if (update_flags_cells & update_quadrature_points)
7060 {
7061 if (cell_type <=
7063 {
7064 // affine case: quadrature points are not available but
7065 // have to be computed from the corner point and the
7066 // Jacobian
7067 Point<dim, VectorizedArrayType> point =
7068 this->mapping_data->quadrature_points
7069 [this->mapping_data
7070 ->quadrature_point_offsets[cell_batch_index] +
7071 0];
7072
7073 const Tensor<2, dim, VectorizedArrayType> &jac =
7074 this->mapping_data->jacobians[0][offsets + 1];
7076 for (unsigned int d = 0; d < dim; ++d)
7077 point[d] +=
7078 jac[d][d] *
7079 static_cast<Number>(
7080 this->descriptor->quadrature.point(q)[d]);
7081 else
7082 for (unsigned int d = 0; d < dim; ++d)
7083 for (unsigned int e = 0; e < dim; ++e)
7084 point[d] +=
7085 jac[d][e] *
7086 static_cast<Number>(
7087 this->descriptor->quadrature.point(q)[e]);
7088
7089 for (unsigned int i = 0; i < dim; ++i)
7090 this_quadrature_points_data[q][i][v] = point[i][lane];
7091 }
7092 else
7093 {
7094 // general case: quadrature points are available
7095 for (unsigned int i = 0; i < dim; ++i)
7096 this_quadrature_points_data[q][i][v] =
7097 this->mapping_data->quadrature_points
7098 [this->mapping_data
7099 ->quadrature_point_offsets[cell_batch_index] +
7100 q][i][lane];
7101 }
7102 }
7103 }
7104 }
7105 }
7106
7107 if constexpr (running_in_debug_mode())
7108 {
7109 this->is_reinitialized = true;
7110 this->dof_values_initialized = false;
7111 this->values_quad_initialized = false;
7112 this->gradients_quad_initialized = false;
7113 this->hessians_quad_initialized = false;
7114 }
7115}
7116
7117
7118
7119template <int dim,
7120 int fe_degree,
7121 int n_q_points_1d,
7122 int n_components_,
7123 typename Number,
7124 typename VectorizedArrayType>
7125template <bool level_dof_access>
7126inline void
7127FEEvaluation<dim,
7128 fe_degree,
7129 n_q_points_1d,
7130 n_components_,
7131 Number,
7132 VectorizedArrayType>::
7133 reinit(const TriaIterator<DoFCellAccessor<dim, dim, level_dof_access>> &cell)
7134{
7135 Assert(this->matrix_free == nullptr,
7136 ExcMessage("Cannot use initialization from cell iterator if "
7137 "initialized from MatrixFree object. Use variant for "
7138 "on the fly computation with arguments as for FEValues "
7139 "instead"));
7140 Assert(this->mapped_geometry.get() != nullptr, ExcNotInitialized());
7141 this->mapped_geometry->reinit(
7142 static_cast<typename Triangulation<dim>::cell_iterator>(cell));
7143 this->local_dof_indices.resize(cell->get_fe().n_dofs_per_cell());
7144 if (level_dof_access)
7145 cell->get_mg_dof_indices(this->local_dof_indices);
7146 else
7147 cell->get_dof_indices(this->local_dof_indices);
7148
7149 if constexpr (running_in_debug_mode())
7150 {
7151 this->is_reinitialized = true;
7152 }
7153}
7154
7155
7156
7157template <int dim,
7158 int fe_degree,
7159 int n_q_points_1d,
7160 int n_components_,
7161 typename Number,
7162 typename VectorizedArrayType>
7163inline void
7164FEEvaluation<dim,
7165 fe_degree,
7166 n_q_points_1d,
7167 n_components_,
7168 Number,
7169 VectorizedArrayType>::
7170 reinit(const typename Triangulation<dim>::cell_iterator &cell)
7171{
7172 Assert(this->matrix_free == 0,
7173 ExcMessage("Cannot use initialization from cell iterator if "
7174 "initialized from MatrixFree object. Use variant for "
7175 "on the fly computation with arguments as for FEValues "
7176 "instead"));
7177 Assert(this->mapped_geometry.get() != 0, ExcNotInitialized());
7178 this->mapped_geometry->reinit(cell);
7179
7180 if constexpr (running_in_debug_mode())
7181 {
7182 this->is_reinitialized = true;
7183 }
7184}
7185
7186
7187
7188template <int dim,
7189 int fe_degree,
7190 int n_q_points_1d,
7191 int n_components_,
7192 typename Number,
7193 typename VectorizedArrayType>
7194inline void
7195FEEvaluation<dim,
7196 fe_degree,
7197 n_q_points_1d,
7198 n_components_,
7199 Number,
7200 VectorizedArrayType>::
7201 evaluate(const EvaluationFlags::EvaluationFlags evaluation_flags)
7202{
7203 if constexpr (running_in_debug_mode())
7204 {
7205 Assert(this->dof_values_initialized == true,
7207 }
7208 evaluate(this->values_dofs, evaluation_flags);
7209}
7210
7211
7212
7213template <int dim,
7214 int fe_degree,
7215 int n_q_points_1d,
7216 int n_components_,
7217 typename Number,
7218 typename VectorizedArrayType>
7219inline void
7220FEEvaluation<dim,
7221 fe_degree,
7222 n_q_points_1d,
7223 n_components_,
7224 Number,
7225 VectorizedArrayType>::
7226 evaluate(const VectorizedArrayType *values_array,
7227 const EvaluationFlags::EvaluationFlags evaluation_flag)
7228{
7229 const bool hessians_on_general_cells =
7230 evaluation_flag & EvaluationFlags::hessians &&
7231 (this->cell_type > internal::MatrixFreeFunctions::affine);
7232 EvaluationFlags::EvaluationFlags evaluation_flag_actual = evaluation_flag;
7233 if (hessians_on_general_cells)
7234 evaluation_flag_actual |= EvaluationFlags::gradients;
7235
7236 if (this->data->element_type ==
7238 evaluation_flag & EvaluationFlags::gradients &&
7239 (this->cell_type > internal::MatrixFreeFunctions::affine))
7240 evaluation_flag_actual |= EvaluationFlags::values;
7241
7242 if constexpr (fe_degree > -1)
7243 {
7244 internal::FEEvaluationImplSelector<dim, VectorizedArrayType, false>::
7245 template run<fe_degree, n_q_points_1d>(n_components,
7246 evaluation_flag_actual,
7247 values_array,
7248 *this);
7249 }
7250 else
7251 {
7253 n_components,
7254 evaluation_flag_actual,
7255 const_cast<VectorizedArrayType *>(values_array),
7256 *this);
7257 }
7258
7259 if constexpr (running_in_debug_mode())
7260 {
7261 this->values_quad_initialized =
7262 evaluation_flag_actual & EvaluationFlags::values;
7263 this->gradients_quad_initialized =
7264 evaluation_flag_actual & EvaluationFlags::gradients;
7265 this->hessians_quad_initialized =
7266 evaluation_flag_actual & EvaluationFlags::hessians;
7267 }
7268}
7269
7270
7271namespace internal
7272{
7276 template <typename Number,
7277 typename VectorizedArrayType,
7278 typename VectorType,
7279 typename EvaluatorType,
7280 std::enable_if_t<internal::has_begin<VectorType> &&
7282 VectorType> * = nullptr>
7283 VectorizedArrayType *
7284 check_vector_access_inplace(const EvaluatorType &fe_eval, VectorType &vector)
7285 {
7286 // for user-defined cell batches this functionality is not supported
7287 if (fe_eval.get_current_cell_index() == numbers::invalid_unsigned_int)
7288 return nullptr;
7289
7290 const unsigned int cell = fe_eval.get_cell_or_face_batch_id();
7291 const auto &dof_info = fe_eval.get_dof_info();
7292
7293 // If the index storage is interleaved and contiguous and the vector
7294 // storage has the correct alignment, we can directly pass the pointer
7295 // into the vector to the evaluate() and integrate() calls, without
7296 // reading the vector entries into a separate data field. This saves some
7297 // operations.
7298 if (std::is_same_v<typename VectorType::value_type, Number> &&
7299 dof_info.index_storage_variants
7302 interleaved_contiguous &&
7303 reinterpret_cast<std::size_t>(
7304 vector.begin() +
7305 dof_info.dof_indices_contiguous
7307 [cell * VectorizedArrayType::size()]) %
7308 sizeof(VectorizedArrayType) ==
7309 0)
7310 {
7311 return reinterpret_cast<VectorizedArrayType *>(
7312 vector.begin() +
7313 dof_info.dof_indices_contiguous
7315 [cell * VectorizedArrayType::size()] +
7317 [fe_eval.get_active_fe_index()]
7318 [fe_eval.get_first_selected_component()] *
7319 VectorizedArrayType::size());
7320 }
7321 else
7322 return nullptr;
7323 }
7324
7328 template <typename Number,
7329 typename VectorizedArrayType,
7330 typename VectorType,
7331 typename EvaluatorType,
7332 std::enable_if_t<!internal::has_begin<VectorType> ||
7334 VectorType> * = nullptr>
7335 VectorizedArrayType *
7336 check_vector_access_inplace(const EvaluatorType &, VectorType &)
7337 {
7338 return nullptr;
7339 }
7340} // namespace internal
7341
7342
7343
7344template <int dim,
7345 int fe_degree,
7346 int n_q_points_1d,
7347 int n_components_,
7348 typename Number,
7349 typename VectorizedArrayType>
7350template <typename VectorType>
7351inline void
7352FEEvaluation<dim,
7353 fe_degree,
7354 n_q_points_1d,
7355 n_components_,
7356 Number,
7357 VectorizedArrayType>::
7358 gather_evaluate(const VectorType &input_vector,
7359 const EvaluationFlags::EvaluationFlags evaluation_flag)
7360{
7361 const VectorizedArrayType *src_ptr =
7362 internal::check_vector_access_inplace<Number, const VectorizedArrayType>(
7363 *this, input_vector);
7364 if (src_ptr != nullptr)
7365 evaluate(src_ptr, evaluation_flag);
7366 else
7367 {
7368 this->read_dof_values(input_vector);
7369 evaluate(this->begin_dof_values(), evaluation_flag);
7370 }
7371}
7372
7373
7374
7375template <int dim,
7376 int fe_degree,
7377 int n_q_points_1d,
7378 int n_components_,
7379 typename Number,
7380 typename VectorizedArrayType>
7381inline void
7382FEEvaluation<dim,
7383 fe_degree,
7384 n_q_points_1d,
7385 n_components_,
7386 Number,
7387 VectorizedArrayType>::
7388 integrate(const EvaluationFlags::EvaluationFlags integration_flag)
7389{
7390 integrate(integration_flag, this->values_dofs);
7391
7392 if constexpr (running_in_debug_mode())
7393 {
7394 this->dof_values_initialized = true;
7395 }
7396}
7397
7398
7399
7400template <int dim,
7401 int fe_degree,
7402 int n_q_points_1d,
7403 int n_components_,
7404 typename Number,
7405 typename VectorizedArrayType>
7406inline void
7407FEEvaluation<dim,
7408 fe_degree,
7409 n_q_points_1d,
7410 n_components_,
7411 Number,
7412 VectorizedArrayType>::
7413 integrate(const EvaluationFlags::EvaluationFlags integration_flag,
7414 VectorizedArrayType *values_array,
7415 const bool sum_into_values_array)
7416{
7417 if constexpr (running_in_debug_mode())
7418 {
7419 if (integration_flag & EvaluationFlags::values)
7420 Assert(this->values_quad_submitted == true,
7422 if (integration_flag & EvaluationFlags::gradients)
7423 Assert(this->gradients_quad_submitted == true,
7425 if ((integration_flag & EvaluationFlags::hessians) != 0u)
7426 Assert(this->hessians_quad_submitted == true,
7428 }
7429 Assert(this->matrix_free != nullptr ||
7430 this->mapped_geometry->is_initialized(),
7432
7433 Assert(
7434 (integration_flag & ~(EvaluationFlags::values | EvaluationFlags::gradients |
7436 ExcMessage("Only EvaluationFlags::values, EvaluationFlags::gradients, and "
7437 "EvaluationFlags::hessians are supported."));
7438
7439 EvaluationFlags::EvaluationFlags integration_flag_actual = integration_flag;
7440 if (integration_flag & EvaluationFlags::hessians &&
7441 (this->cell_type > internal::MatrixFreeFunctions::affine))
7442 {
7443 unsigned int size = n_components * dim * n_q_points;
7444 if ((integration_flag & EvaluationFlags::gradients) != 0u)
7445 {
7446 for (unsigned int i = 0; i < size; ++i)
7447 this->gradients_quad[i] += this->gradients_from_hessians_quad[i];
7448 }
7449 else
7450 {
7451 for (unsigned int i = 0; i < size; ++i)
7452 this->gradients_quad[i] = this->gradients_from_hessians_quad[i];
7453 integration_flag_actual |= EvaluationFlags::gradients;
7454 }
7455 }
7456
7457 if (n_components == dim &&
7458 this->data->element_type ==
7460 integration_flag & EvaluationFlags::gradients &&
7461 this->cell_type > internal::MatrixFreeFunctions::affine &&
7462 this->divergence_is_requested == false)
7463 {
7464 unsigned int size = n_components * n_q_points;
7465 if ((integration_flag & EvaluationFlags::values) != 0u)
7466 {
7467 for (unsigned int i = 0; i < size; ++i)
7468 this->values_quad[i] += this->values_from_gradients_quad[i];
7469 }
7470 else
7471 {
7472 for (unsigned int i = 0; i < size; ++i)
7473 this->values_quad[i] = this->values_from_gradients_quad[i];
7474 integration_flag_actual |= EvaluationFlags::values;
7475 }
7476 }
7477
7478 if constexpr (fe_degree > -1)
7479 {
7480 internal::FEEvaluationImplSelector<dim, VectorizedArrayType, true>::
7481 template run<fe_degree, n_q_points_1d>(n_components,
7482 integration_flag_actual,
7483 values_array,
7484 *this,
7485 sum_into_values_array);
7486 }
7487 else
7488 {
7490 n_components,
7491 integration_flag_actual,
7492 values_array,
7493 *this,
7494 sum_into_values_array);
7495 }
7496
7497 if constexpr (running_in_debug_mode())
7498 {
7499 this->dof_values_initialized = true;
7500 }
7501}
7502
7503
7504
7505template <int dim,
7506 int fe_degree,
7507 int n_q_points_1d,
7508 int n_components_,
7509 typename Number,
7510 typename VectorizedArrayType>
7511template <typename VectorType>
7512inline void
7513FEEvaluation<dim,
7514 fe_degree,
7515 n_q_points_1d,
7516 n_components_,
7517 Number,
7518 VectorizedArrayType>::
7519 integrate_scatter(const EvaluationFlags::EvaluationFlags integration_flag,
7520 VectorType &destination)
7521{
7522 VectorizedArrayType *dst_ptr =
7523 internal::check_vector_access_inplace<Number, VectorizedArrayType>(
7524 *this, destination);
7525 if (dst_ptr != nullptr)
7526 integrate(integration_flag, dst_ptr, true);
7527 else
7528 {
7529 integrate(integration_flag, this->begin_dof_values());
7530 this->distribute_local_to_global(destination);
7531 }
7532}
7533
7534
7535
7536template <int dim,
7537 int fe_degree,
7538 int n_q_points_1d,
7539 int n_components_,
7540 typename Number,
7541 typename VectorizedArrayType>
7542inline std_cxx20::ranges::iota_view<unsigned int, unsigned int>
7543FEEvaluation<dim,
7544 fe_degree,
7545 n_q_points_1d,
7546 n_components_,
7547 Number,
7548 VectorizedArrayType>::dof_indices() const
7549{
7550 return std_cxx20::ranges::iota_view<unsigned int, unsigned int>(
7551 0U, dofs_per_cell);
7552}
7553
7554
7555
7556/*-------------------------- FEFaceEvaluation ---------------------------*/
7557
7558
7559
7560template <int dim,
7561 int fe_degree,
7562 int n_q_points_1d,
7563 int n_components_,
7564 typename Number,
7565 typename VectorizedArrayType>
7566inline FEFaceEvaluation<dim,
7567 fe_degree,
7568 n_q_points_1d,
7569 n_components_,
7570 Number,
7571 VectorizedArrayType>::
7572 FEFaceEvaluation(
7573 const MatrixFree<dim, Number, VectorizedArrayType> &matrix_free,
7574 const bool is_interior_face,
7575 const unsigned int dof_handler_index,
7576 const unsigned int quadrature_index,
7577 const unsigned int first_selected_component,
7578 const unsigned int active_fe_index,
7579 const unsigned int active_quad_index,
7580 const unsigned int face_type)
7581 : BaseClass(matrix_free,
7582 dof_handler_index,
7583 first_selected_component,
7584 quadrature_index,
7585 fe_degree,
7586 static_n_q_points,
7587 is_interior_face,
7588 active_fe_index,
7589 active_quad_index,
7590 face_type)
7591 , dofs_per_component(this->data->dofs_per_component_on_cell)
7592 , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
7593 , n_q_points(this->n_quadrature_points)
7594{}
7595
7596
7597
7598template <int dim,
7599 int fe_degree,
7600 int n_q_points_1d,
7601 int n_components_,
7602 typename Number,
7603 typename VectorizedArrayType>
7604inline FEFaceEvaluation<dim,
7605 fe_degree,
7606 n_q_points_1d,
7607 n_components_,
7608 Number,
7609 VectorizedArrayType>::
7610 FEFaceEvaluation(
7611 const MatrixFree<dim, Number, VectorizedArrayType> &matrix_free,
7612 const std::pair<unsigned int, unsigned int> &range,
7613 const bool is_interior_face,
7614 const unsigned int dof_handler_index,
7615 const unsigned int quadrature_index,
7616 const unsigned int first_selected_component)
7617 : FEFaceEvaluation(matrix_free,
7618 is_interior_face,
7619 dof_handler_index,
7620 quadrature_index,
7621 first_selected_component,
7622 matrix_free.get_face_active_fe_index(range,
7623 is_interior_face),
7624 numbers::invalid_unsigned_int,
7625 matrix_free.get_face_info(range.first).face_type)
7626{}
7627
7628
7629
7630template <int dim,
7631 int fe_degree,
7632 int n_q_points_1d,
7633 int n_components_,
7634 typename Number,
7635 typename VectorizedArrayType>
7636inline void
7637FEFaceEvaluation<dim,
7638 fe_degree,
7639 n_q_points_1d,
7640 n_components_,
7641 Number,
7642 VectorizedArrayType>::reinit(const unsigned int face_index)
7643{
7644 Assert(this->mapped_geometry == nullptr,
7645 ExcMessage("FEEvaluation was initialized without a matrix-free object."
7646 " Integer indexing is not possible"));
7647 if (this->mapped_geometry != nullptr)
7648 return;
7649
7650 this->cell = face_index;
7651 this->dof_access_index =
7652 this->is_interior_face() ?
7655 Assert(this->mapping_data != nullptr, ExcNotInitialized());
7656
7657 if (face_index >=
7658 this->matrix_free->get_task_info().face_partition_data.back() &&
7659 face_index <
7660 this->matrix_free->get_task_info().boundary_partition_data.back())
7661 Assert(this->is_interior_face(),
7662 ExcMessage(
7663 "Boundary faces do not have a neighbor. When looping over "
7664 "boundary faces use FEFaceEvaluation with the parameter "
7665 "is_interior_face set to true. "));
7666
7667 this->reinit_face(this->matrix_free->get_face_info(face_index));
7668
7669 unsigned int i = 0;
7670 for (; i < this->matrix_free->n_active_entries_per_face_batch(this->cell);
7671 ++i)
7672 this->face_ids[i] = face_index * n_lanes + i;
7673 for (; i < n_lanes; ++i)
7674 this->face_ids[i] = numbers::invalid_unsigned_int;
7675
7676 this->cell_type = this->matrix_free->get_mapping_info().face_type[face_index];
7677 const unsigned int offsets =
7678 this->mapping_data->data_index_offsets[face_index];
7679 this->J_value = &this->mapping_data->JxW_values[offsets];
7680 this->normal_vectors = &this->mapping_data->normal_vectors[offsets];
7681 this->jacobian =
7682 &this->mapping_data->jacobians[!this->is_interior_face()][offsets];
7683 this->normal_x_jacobian =
7684 &this->mapping_data
7685 ->normals_times_jacobians[!this->is_interior_face()][offsets];
7686 this->jacobian_gradients =
7687 this->mapping_data->jacobian_gradients[!this->is_interior_face()].data() +
7688 offsets;
7689 this->jacobian_gradients_non_inverse =
7690 this->mapping_data
7691 ->jacobian_gradients_non_inverse[!this->is_interior_face()]
7692 .data() +
7693 offsets;
7694
7695 if (this->mapping_data->quadrature_point_offsets.empty() == false)
7696 {
7697 AssertIndexRange(this->cell,
7698 this->mapping_data->quadrature_point_offsets.size());
7699 this->quadrature_points =
7700 this->mapping_data->quadrature_points.data() +
7701 this->mapping_data->quadrature_point_offsets[this->cell];
7702 }
7703
7704 if constexpr (running_in_debug_mode())
7705 {
7706 this->is_reinitialized = true;
7707 this->dof_values_initialized = false;
7708 this->values_quad_initialized = false;
7709 this->gradients_quad_initialized = false;
7710 this->hessians_quad_initialized = false;
7711 }
7712}
7713
7714
7715
7716template <int dim,
7717 int fe_degree,
7718 int n_q_points_1d,
7719 int n_components_,
7720 typename Number,
7721 typename VectorizedArrayType>
7722inline void
7723FEFaceEvaluation<dim,
7724 fe_degree,
7725 n_q_points_1d,
7726 n_components_,
7727 Number,
7728 VectorizedArrayType>::reinit(const unsigned int cell_index,
7729 const unsigned int face_number)
7730{
7731 Assert(
7732 this->quadrature_index <
7733 this->matrix_free->get_mapping_info().face_data_by_cells.size(),
7734 ExcMessage(
7735 "You must set MatrixFree::AdditionalData::mapping_update_flags_faces_by_cells to use the present reinit method."));
7737 AssertIndexRange(cell_index,
7738 this->matrix_free->get_mapping_info().cell_type.size());
7739 Assert(this->mapped_geometry == nullptr,
7740 ExcMessage("FEEvaluation was initialized without a matrix-free object."
7741 " Integer indexing is not possible"));
7742 if (this->mapped_geometry != nullptr)
7743 return;
7744 Assert(this->matrix_free != nullptr, ExcNotInitialized());
7745
7746 this->cell_type = this->matrix_free->get_mapping_info()
7747 .faces_by_cells_type[cell_index][face_number];
7748 this->cell = cell_index;
7749 this->subface_index = GeometryInfo<dim>::max_children_per_cell;
7750 this->dof_access_index =
7752
7753 if (this->is_interior_face() == false)
7754 {
7755 // for this case, we need to look into the FaceInfo field that collects
7756 // information from both sides of a face once for the global mesh, and
7757 // pick the face id that is not the local one (cell_this).
7758 for (unsigned int i = 0; i < n_lanes; ++i)
7759 {
7760 // compute actual (non vectorized) cell ID
7761 const unsigned int cell_this = cell_index * n_lanes + i;
7762 // compute face ID
7763 unsigned int face_index =
7764 this->matrix_free->get_cell_and_face_to_plain_faces()(cell_index,
7765 face_number,
7766 i);
7767
7768 this->face_ids[i] = face_index;
7769
7770 if (face_index == numbers::invalid_unsigned_int)
7771 {
7772 this->cell_ids[i] = numbers::invalid_unsigned_int;
7773 this->face_numbers[i] = static_cast<std::uint8_t>(-1);
7774 this->face_orientations[i] =
7776 continue; // invalid face ID: no neighbor on boundary
7777 }
7778
7779 const auto &faces =
7780 this->matrix_free->get_face_info(face_index / n_lanes);
7781 // get cell ID on both sides of face
7782 auto cell_m = faces.cells_interior[face_index % n_lanes];
7783 auto cell_p = faces.cells_exterior[face_index % n_lanes];
7784
7785 const bool face_identifies_as_interior = cell_m != cell_this;
7786
7787 Assert(cell_m == cell_this || cell_p == cell_this,
7789
7790 // compare the IDs with the given cell ID
7791 if (face_identifies_as_interior)
7792 {
7793 this->cell_ids[i] = cell_m; // neighbor has the other ID
7794 this->face_numbers[i] = faces.interior_face_no;
7795 }
7796 else
7797 {
7798 this->cell_ids[i] = cell_p;
7799 this->face_numbers[i] = faces.exterior_face_no;
7800 }
7801
7802 const bool orientation_interior_face = faces.face_orientation >= 8;
7803 types::geometric_orientation face_orientation =
7804 faces.face_orientation % 8;
7805 if (face_identifies_as_interior != orientation_interior_face)
7806 {
7807 Assert(this->matrix_free->get_cell_iterator(cell_index, i)
7808 ->reference_cell() ==
7811 face_orientation =
7813 .get_inverse_combined_orientation(face_orientation);
7814 }
7815 this->face_orientations[i] = face_orientation;
7816 }
7817 }
7818 else
7819 {
7820 this->face_orientations[0] = numbers::default_geometric_orientation;
7821 this->face_numbers[0] = face_number;
7822 if (this->matrix_free->n_active_entries_per_cell_batch(this->cell) ==
7823 n_lanes)
7824 {
7826 for (unsigned int i = 0; i < n_lanes; ++i)
7827 this->cell_ids[i] = cell_index * n_lanes + i;
7828 }
7829 else
7830 {
7831 unsigned int i = 0;
7832 for (; i <
7833 this->matrix_free->n_active_entries_per_cell_batch(this->cell);
7834 ++i)
7835 this->cell_ids[i] = cell_index * n_lanes + i;
7836 for (; i < n_lanes; ++i)
7837 this->cell_ids[i] = numbers::invalid_unsigned_int;
7838 }
7839 for (unsigned int i = 0; i < n_lanes; ++i)
7840 this->face_ids[i] =
7841 this->matrix_free->get_cell_and_face_to_plain_faces()(cell_index,
7842 face_number,
7843 i);
7844 }
7845
7846 const unsigned int offsets =
7847 this->matrix_free->get_mapping_info()
7848 .face_data_by_cells[this->quadrature_index]
7849 .data_index_offsets[cell_index * GeometryInfo<dim>::faces_per_cell +
7850 face_number];
7851 AssertIndexRange(offsets,
7852 this->matrix_free->get_mapping_info()
7853 .face_data_by_cells[this->quadrature_index]
7854 .JxW_values.size());
7855 this->J_value = &this->matrix_free->get_mapping_info()
7856 .face_data_by_cells[this->quadrature_index]
7857 .JxW_values[offsets];
7858 this->normal_vectors = &this->matrix_free->get_mapping_info()
7859 .face_data_by_cells[this->quadrature_index]
7860 .normal_vectors[offsets];
7861 this->jacobian = &this->matrix_free->get_mapping_info()
7862 .face_data_by_cells[this->quadrature_index]
7863 .jacobians[!this->is_interior_face()][offsets];
7864 this->normal_x_jacobian =
7865 &this->matrix_free->get_mapping_info()
7866 .face_data_by_cells[this->quadrature_index]
7867 .normals_times_jacobians[!this->is_interior_face()][offsets];
7868 this->jacobian_gradients =
7869 this->mapping_data->jacobian_gradients[!this->is_interior_face()].data() +
7870 offsets;
7871 this->jacobian_gradients_non_inverse =
7872 this->mapping_data
7873 ->jacobian_gradients_non_inverse[!this->is_interior_face()]
7874 .data() +
7875 offsets;
7876
7877 if (this->matrix_free->get_mapping_info()
7878 .face_data_by_cells[this->quadrature_index]
7879 .quadrature_point_offsets.empty() == false)
7880 {
7881 const unsigned int index =
7882 this->cell * GeometryInfo<dim>::faces_per_cell + this->face_numbers[0];
7884 this->matrix_free->get_mapping_info()
7885 .face_data_by_cells[this->quadrature_index]
7886 .quadrature_point_offsets.size());
7887 this->quadrature_points = this->matrix_free->get_mapping_info()
7888 .face_data_by_cells[this->quadrature_index]
7889 .quadrature_points.data() +
7890 this->matrix_free->get_mapping_info()
7891 .face_data_by_cells[this->quadrature_index]
7892 .quadrature_point_offsets[index];
7893 }
7894
7895 if constexpr (running_in_debug_mode())
7896 {
7897 this->is_reinitialized = true;
7898 this->dof_values_initialized = false;
7899 this->values_quad_initialized = false;
7900 this->gradients_quad_initialized = false;
7901 this->hessians_quad_initialized = false;
7902 }
7903}
7904
7905
7906
7907template <int dim,
7908 int fe_degree,
7909 int n_q_points_1d,
7910 int n_components_,
7911 typename Number,
7912 typename VectorizedArrayType>
7913inline void
7914FEFaceEvaluation<dim,
7915 fe_degree,
7916 n_q_points_1d,
7917 n_components_,
7918 Number,
7919 VectorizedArrayType>::
7920 evaluate(const EvaluationFlags::EvaluationFlags evaluation_flag)
7921{
7922 if constexpr (running_in_debug_mode())
7923 {
7924 Assert(this->dof_values_initialized, ExcNotInitialized());
7925 }
7926
7927 evaluate(this->values_dofs, evaluation_flag);
7928}
7929
7930
7931
7932template <int dim,
7933 int fe_degree,
7934 int n_q_points_1d,
7935 int n_components_,
7936 typename Number,
7937 typename VectorizedArrayType>
7938inline void
7939FEFaceEvaluation<dim,
7940 fe_degree,
7941 n_q_points_1d,
7942 n_components_,
7943 Number,
7944 VectorizedArrayType>::
7945 evaluate(const VectorizedArrayType *values_array,
7946 const EvaluationFlags::EvaluationFlags evaluation_flag)
7947{
7948 Assert((evaluation_flag &
7951 ExcMessage("Only EvaluationFlags::values, EvaluationFlags::gradients, "
7952 "and EvaluationFlags::hessians are supported."));
7953
7954 const bool hessians_on_general_cells =
7955 evaluation_flag & EvaluationFlags::hessians &&
7956 (this->cell_type > internal::MatrixFreeFunctions::affine);
7957 EvaluationFlags::EvaluationFlags evaluation_flag_actual = evaluation_flag;
7958 if (hessians_on_general_cells)
7959 evaluation_flag_actual |= EvaluationFlags::gradients;
7960
7961 if (this->data->element_type ==
7963 evaluation_flag & EvaluationFlags::gradients &&
7964 (this->cell_type > internal::MatrixFreeFunctions::affine))
7965 evaluation_flag_actual |= EvaluationFlags::values;
7966
7967 if constexpr (fe_degree > -1)
7968 internal::FEFaceEvaluationImplEvaluateSelector<dim, VectorizedArrayType>::
7969 template run<fe_degree, n_q_points_1d>(n_components,
7970 evaluation_flag_actual,
7971 values_array,
7972 *this);
7973 else
7975 n_components, evaluation_flag_actual, values_array, *this);
7976
7977 if constexpr (running_in_debug_mode())
7978 {
7979 this->values_quad_initialized =
7980 evaluation_flag_actual & EvaluationFlags::values;
7981 this->gradients_quad_initialized =
7982 evaluation_flag_actual & EvaluationFlags::gradients;
7983 this->hessians_quad_initialized =
7984 evaluation_flag_actual & EvaluationFlags::hessians;
7985 }
7986}
7987
7988
7989
7990template <int dim,
7991 int fe_degree,
7992 int n_q_points_1d,
7993 int n_components_,
7994 typename Number,
7995 typename VectorizedArrayType>
7996inline void
7997FEFaceEvaluation<dim,
7998 fe_degree,
7999 n_q_points_1d,
8000 n_components_,
8001 Number,
8002 VectorizedArrayType>::
8003 project_to_face(const EvaluationFlags::EvaluationFlags evaluation_flag)
8004{
8005 if constexpr (running_in_debug_mode())
8006 {
8007 Assert(this->dof_values_initialized, ExcNotInitialized());
8008 }
8009
8010 project_to_face(this->values_dofs, evaluation_flag);
8011}
8012
8013
8014
8015template <int dim,
8016 int fe_degree,
8017 int n_q_points_1d,
8018 int n_components_,
8019 typename Number,
8020 typename VectorizedArrayType>
8021inline void
8022FEFaceEvaluation<dim,
8023 fe_degree,
8024 n_q_points_1d,
8025 n_components_,
8026 Number,
8027 VectorizedArrayType>::
8028 project_to_face(const VectorizedArrayType *values_array,
8029 const EvaluationFlags::EvaluationFlags evaluation_flag)
8030{
8031 Assert((evaluation_flag &
8034 ExcMessage("Only EvaluationFlags::values, EvaluationFlags::gradients, "
8035 "and EvaluationFlags::hessians are supported."));
8036
8037 const bool hessians_on_general_cells =
8038 evaluation_flag & EvaluationFlags::hessians &&
8039 (this->cell_type > internal::MatrixFreeFunctions::affine);
8040 EvaluationFlags::EvaluationFlags evaluation_flag_actual = evaluation_flag;
8041 if (hessians_on_general_cells)
8042 evaluation_flag_actual |= EvaluationFlags::gradients;
8043
8044 if (this->data->element_type ==
8046 evaluation_flag & EvaluationFlags::gradients &&
8047 (this->cell_type > internal::MatrixFreeFunctions::affine))
8048 evaluation_flag_actual |= EvaluationFlags::values;
8049
8050 if constexpr (fe_degree > -1)
8051 internal::FEFaceEvaluationImplProjectToFaceSelector<
8052 dim,
8053 VectorizedArrayType>::template run<fe_degree>(n_components,
8054 evaluation_flag_actual,
8055 values_array,
8056 *this);
8057 else
8059 project_to_face(n_components,
8060 evaluation_flag_actual,
8061 values_array,
8062 *this);
8063
8064 // face dofs initialized
8065}
8066
8067
8068
8069template <int dim,
8070 int fe_degree,
8071 int n_q_points_1d,
8072 int n_components_,
8073 typename Number,
8074 typename VectorizedArrayType>
8075inline void
8076FEFaceEvaluation<dim,
8077 fe_degree,
8078 n_q_points_1d,
8079 n_components_,
8080 Number,
8081 VectorizedArrayType>::
8082 evaluate_in_face(const EvaluationFlags::EvaluationFlags evaluation_flag)
8083{
8084 Assert((evaluation_flag &
8087 ExcMessage("Only EvaluationFlags::values, EvaluationFlags::gradients, "
8088 "and EvaluationFlags::hessians are supported."));
8089
8090 const bool hessians_on_general_cells =
8091 evaluation_flag & EvaluationFlags::hessians &&
8092 (this->cell_type > internal::MatrixFreeFunctions::affine);
8093 EvaluationFlags::EvaluationFlags evaluation_flag_actual = evaluation_flag;
8094 if (hessians_on_general_cells)
8095 evaluation_flag_actual |= EvaluationFlags::gradients;
8096
8097 if (this->data->element_type ==
8099 evaluation_flag & EvaluationFlags::gradients &&
8100 (this->cell_type > internal::MatrixFreeFunctions::affine))
8101 evaluation_flag_actual |= EvaluationFlags::values;
8102
8103 if constexpr (fe_degree > -1)
8104 internal::FEFaceEvaluationImplEvaluateInFaceSelector<
8105 dim,
8106 VectorizedArrayType>::template run<fe_degree>(n_components,
8107 evaluation_flag_actual,
8108 *this);
8109 else
8111 evaluate_in_face(n_components, evaluation_flag_actual, *this);
8112
8113 if constexpr (running_in_debug_mode())
8114 {
8115 this->values_quad_initialized =
8116 evaluation_flag_actual & EvaluationFlags::values;
8117 this->gradients_quad_initialized =
8118 evaluation_flag_actual & EvaluationFlags::gradients;
8119 this->hessians_quad_initialized =
8120 evaluation_flag_actual & EvaluationFlags::hessians;
8121 }
8122}
8123
8124
8125
8126template <int dim,
8127 int fe_degree,
8128 int n_q_points_1d,
8129 int n_components_,
8130 typename Number,
8131 typename VectorizedArrayType>
8132inline void
8133FEFaceEvaluation<dim,
8134 fe_degree,
8135 n_q_points_1d,
8136 n_components_,
8137 Number,
8138 VectorizedArrayType>::
8139 integrate(const EvaluationFlags::EvaluationFlags integration_flag,
8140 const bool sum_into_values)
8141{
8142 integrate(integration_flag, this->values_dofs, sum_into_values);
8143
8144 if constexpr (running_in_debug_mode())
8145 {
8146 this->dof_values_initialized = true;
8147 }
8148}
8149
8150
8151
8152template <int dim,
8153 int fe_degree,
8154 int n_q_points_1d,
8155 int n_components_,
8156 typename Number,
8157 typename VectorizedArrayType>
8158inline void
8159FEFaceEvaluation<dim,
8160 fe_degree,
8161 n_q_points_1d,
8162 n_components_,
8163 Number,
8164 VectorizedArrayType>::
8165 integrate(const EvaluationFlags::EvaluationFlags integration_flag,
8166 VectorizedArrayType *values_array,
8167 const bool sum_into_values)
8168{
8169 Assert((integration_flag &
8172 ExcMessage("Only EvaluationFlags::values, EvaluationFlags::gradients, "
8173 "and EvaluationFlags::hessians are supported."));
8174
8175 EvaluationFlags::EvaluationFlags integration_flag_actual = integration_flag;
8176 if (integration_flag & EvaluationFlags::hessians &&
8177 (this->cell_type > internal::MatrixFreeFunctions::affine))
8178 {
8179 unsigned int size = n_components * dim * n_q_points;
8180 if ((integration_flag & EvaluationFlags::gradients) != 0u)
8181 {
8182 for (unsigned int i = 0; i < size; ++i)
8183 this->gradients_quad[i] += this->gradients_from_hessians_quad[i];
8184 }
8185 else
8186 {
8187 for (unsigned int i = 0; i < size; ++i)
8188 this->gradients_quad[i] = this->gradients_from_hessians_quad[i];
8189 integration_flag_actual |= EvaluationFlags::gradients;
8190 }
8191 }
8192
8193 if (this->data->element_type ==
8195 integration_flag & EvaluationFlags::gradients &&
8196 this->cell_type > internal::MatrixFreeFunctions::affine &&
8197 this->divergence_is_requested == false)
8198 {
8199 unsigned int size = n_components * n_q_points;
8200 if ((integration_flag & EvaluationFlags::values) != 0u)
8201 {
8202 for (unsigned int i = 0; i < size; ++i)
8203 this->values_quad[i] += this->values_from_gradients_quad[i];
8204 }
8205 else
8206 {
8207 for (unsigned int i = 0; i < size; ++i)
8208 this->values_quad[i] = this->values_from_gradients_quad[i];
8209 integration_flag_actual |= EvaluationFlags::values;
8210 }
8211 }
8212
8213 if constexpr (fe_degree > -1)
8214 internal::FEFaceEvaluationImplIntegrateSelector<dim, VectorizedArrayType>::
8215 template run<fe_degree, n_q_points_1d>(n_components,
8216 integration_flag_actual,
8217 values_array,
8218 *this,
8219 sum_into_values);
8220 else
8222 n_components,
8223 integration_flag_actual,
8224 values_array,
8225 *this,
8226 sum_into_values);
8227}
8228
8229
8230
8231template <int dim,
8232 int fe_degree,
8233 int n_q_points_1d,
8234 int n_components_,
8235 typename Number,
8236 typename VectorizedArrayType>
8237inline void
8238FEFaceEvaluation<dim,
8239 fe_degree,
8240 n_q_points_1d,
8241 n_components_,
8242 Number,
8243 VectorizedArrayType>::
8244 integrate_in_face(const EvaluationFlags::EvaluationFlags integration_flag)
8245{
8246 Assert((integration_flag &
8249 ExcMessage("Only EvaluationFlags::values, EvaluationFlags::gradients, "
8250 "and EvaluationFlags::hessians are supported."));
8251
8252 EvaluationFlags::EvaluationFlags integration_flag_actual = integration_flag;
8253 if (integration_flag & EvaluationFlags::hessians &&
8254 (this->cell_type > internal::MatrixFreeFunctions::affine))
8255 {
8256 unsigned int size = n_components * dim * n_q_points;
8257 if ((integration_flag & EvaluationFlags::gradients) != 0u)
8258 {
8259 for (unsigned int i = 0; i < size; ++i)
8260 this->gradients_quad[i] += this->gradients_from_hessians_quad[i];
8261 }
8262 else
8263 {
8264 for (unsigned int i = 0; i < size; ++i)
8265 this->gradients_quad[i] = this->gradients_from_hessians_quad[i];
8266 integration_flag_actual |= EvaluationFlags::gradients;
8267 }
8268 }
8269
8270 if (this->data->element_type ==
8272 integration_flag & EvaluationFlags::gradients &&
8273 this->cell_type > internal::MatrixFreeFunctions::affine &&
8274 this->divergence_is_requested == false)
8275 {
8276 unsigned int size = n_components * n_q_points;
8277 if ((integration_flag & EvaluationFlags::values) != 0u)
8278 {
8279 for (unsigned int i = 0; i < size; ++i)
8280 this->values_quad[i] += this->values_from_gradients_quad[i];
8281 }
8282 else
8283 {
8284 for (unsigned int i = 0; i < size; ++i)
8285 this->values_quad[i] = this->values_from_gradients_quad[i];
8286 integration_flag_actual |= EvaluationFlags::values;
8287 }
8288 }
8289
8290 if constexpr (fe_degree > -1)
8291 internal::FEFaceEvaluationImplIntegrateInFaceSelector<
8292 dim,
8293 VectorizedArrayType>::template run<fe_degree>(n_components,
8294 integration_flag_actual,
8295 *this);
8296 else
8298 integrate_in_face(n_components, integration_flag_actual, *this);
8299
8300 // face dofs initialized
8301}
8302
8303
8304
8305template <int dim,
8306 int fe_degree,
8307 int n_q_points_1d,
8308 int n_components_,
8309 typename Number,
8310 typename VectorizedArrayType>
8311inline void
8312FEFaceEvaluation<dim,
8313 fe_degree,
8314 n_q_points_1d,
8315 n_components_,
8316 Number,
8317 VectorizedArrayType>::
8318 collect_from_face(const EvaluationFlags::EvaluationFlags integration_flag,
8319 const bool sum_into_values)
8320{
8321 collect_from_face(integration_flag, this->values_dofs, sum_into_values);
8322
8323 if constexpr (running_in_debug_mode())
8324 {
8325 this->dof_values_initialized = true;
8326 }
8327}
8328
8329
8330
8331template <int dim,
8332 int fe_degree,
8333 int n_q_points_1d,
8334 int n_components_,
8335 typename Number,
8336 typename VectorizedArrayType>
8337inline void
8338FEFaceEvaluation<dim,
8339 fe_degree,
8340 n_q_points_1d,
8341 n_components_,
8342 Number,
8343 VectorizedArrayType>::
8344 collect_from_face(const EvaluationFlags::EvaluationFlags integration_flag,
8345 VectorizedArrayType *values_array,
8346 const bool sum_into_values)
8347{
8348 Assert((integration_flag &
8351 ExcMessage("Only EvaluationFlags::values, EvaluationFlags::gradients, "
8352 "and EvaluationFlags::hessians are supported."));
8353
8354 EvaluationFlags::EvaluationFlags integration_flag_actual = integration_flag;
8355 if (integration_flag & EvaluationFlags::hessians &&
8356 (this->cell_type > internal::MatrixFreeFunctions::affine))
8357 integration_flag_actual |= EvaluationFlags::gradients;
8358
8359 if (this->data->element_type ==
8361 integration_flag & EvaluationFlags::gradients &&
8362 this->cell_type > internal::MatrixFreeFunctions::affine &&
8363 this->divergence_is_requested == false)
8364 integration_flag_actual |= EvaluationFlags::values;
8365
8366 if constexpr (fe_degree > -1)
8367 internal::FEFaceEvaluationImplCollectFromFaceSelector<
8368 dim,
8369 VectorizedArrayType>::template run<fe_degree>(n_components,
8370 integration_flag_actual,
8371 values_array,
8372 *this,
8373 sum_into_values);
8374 else
8376 collect_from_face(n_components,
8377 integration_flag_actual,
8378 values_array,
8379 *this,
8380 sum_into_values);
8381}
8382
8383
8384
8385template <int dim,
8386 int fe_degree,
8387 int n_q_points_1d,
8388 int n_components_,
8389 typename Number,
8390 typename VectorizedArrayType>
8391template <typename VectorType>
8392inline void
8393FEFaceEvaluation<dim,
8394 fe_degree,
8395 n_q_points_1d,
8396 n_components_,
8397 Number,
8398 VectorizedArrayType>::
8399 gather_evaluate(const VectorType &input_vector,
8400 const EvaluationFlags::EvaluationFlags evaluation_flag)
8401{
8402 Assert((evaluation_flag &
8405 ExcMessage("Only EvaluationFlags::values, EvaluationFlags::gradients, "
8406 "and EvaluationFlags::hessians are supported."));
8407
8408 const auto shared_vector_data = internal::get_shared_vector_data(
8409 &input_vector,
8410 this->dof_access_index ==
8412 this->active_fe_index,
8413 this->dof_info);
8414
8415 if (this->data->data.front().fe_degree > 0 &&
8416 fast_evaluation_supported(this->data->data.front().fe_degree,
8417 this->data->data.front().n_q_points_1d) &&
8418 internal::FEFaceEvaluationImplGatherEvaluateSelector<
8419 dim,
8420 typename VectorType::value_type,
8421 VectorizedArrayType>::
8422 supports(evaluation_flag,
8423 *this->data,
8424 internal::get_beginning<typename VectorType::value_type>(
8425 input_vector),
8426 this->dof_info->index_storage_variants[this->dof_access_index]
8427 [this->cell]))
8428 {
8429 if constexpr (fe_degree > -1)
8430 {
8431 internal::FEFaceEvaluationImplGatherEvaluateSelector<
8432 dim,
8433 typename VectorType::value_type,
8434 VectorizedArrayType>::template run<fe_degree,
8435 n_q_points_1d>(
8436 n_components,
8437 evaluation_flag,
8438 internal::get_beginning<typename VectorType::value_type>(
8439 input_vector),
8440 shared_vector_data,
8441 *this);
8442 }
8443 else
8444 {
8445 internal::FEFaceEvaluationGatherFactory<
8446 dim,
8447 typename VectorType::value_type,
8448 VectorizedArrayType>::evaluate(n_components,
8449 evaluation_flag,
8450 internal::get_beginning<
8451 typename VectorType::value_type>(
8452 input_vector),
8453 shared_vector_data,
8454 *this);
8455 }
8456 }
8457 else
8458 {
8459 this->read_dof_values(input_vector);
8460 this->evaluate(evaluation_flag);
8461 }
8462
8463 if constexpr (running_in_debug_mode())
8464 {
8465 this->values_quad_initialized = evaluation_flag & EvaluationFlags::values;
8466 this->gradients_quad_initialized =
8467 evaluation_flag & EvaluationFlags::gradients;
8468 this->hessians_quad_initialized =
8469 evaluation_flag & EvaluationFlags::hessians;
8470 }
8471}
8472
8473
8474
8475template <int dim,
8476 int fe_degree,
8477 int n_q_points_1d,
8478 int n_components_,
8479 typename Number,
8480 typename VectorizedArrayType>
8481template <typename VectorType>
8482inline void
8483FEFaceEvaluation<
8484 dim,
8485 fe_degree,
8486 n_q_points_1d,
8487 n_components_,
8488 Number,
8489 VectorizedArrayType>::integrate_scatter(const bool integrate_values,
8490 const bool integrate_gradients,
8491 VectorType &destination)
8492{
8494 ((integrate_values) ? EvaluationFlags::values : EvaluationFlags::nothing) |
8495 ((integrate_gradients) ? EvaluationFlags::gradients :
8497
8498 integrate_scatter(flag, destination);
8499}
8500
8501
8502
8503template <int dim,
8504 int fe_degree,
8505 int n_q_points_1d,
8506 int n_components_,
8507 typename Number,
8508 typename VectorizedArrayType>
8509template <typename VectorType>
8510inline void
8511FEFaceEvaluation<dim,
8512 fe_degree,
8513 n_q_points_1d,
8514 n_components_,
8515 Number,
8516 VectorizedArrayType>::
8517 integrate_scatter(const EvaluationFlags::EvaluationFlags integration_flag,
8518 VectorType &destination)
8519{
8520 Assert((this->dof_access_index ==
8522 this->is_interior_face() == false) == false,
8524
8525 const auto shared_vector_data = internal::get_shared_vector_data(
8526 &destination,
8527 this->dof_access_index ==
8529 this->active_fe_index,
8530 this->dof_info);
8531
8532 if (this->data->data.front().fe_degree > 0 &&
8533 fast_evaluation_supported(this->data->data.front().fe_degree,
8534 this->data->data.front().n_q_points_1d) &&
8535 internal::FEFaceEvaluationImplGatherEvaluateSelector<
8536 dim,
8537 typename VectorType::value_type,
8538 VectorizedArrayType>::
8539 supports(integration_flag,
8540 *this->data,
8541 internal::get_beginning<typename VectorType::value_type>(
8542 destination),
8543 this->dof_info->index_storage_variants[this->dof_access_index]
8544 [this->cell]))
8545 {
8546 if constexpr (fe_degree > -1)
8547 {
8548 internal::FEFaceEvaluationImplIntegrateScatterSelector<
8549 dim,
8550 typename VectorType::value_type,
8551 VectorizedArrayType>::template run<fe_degree,
8552 n_q_points_1d>(
8553 n_components,
8554 integration_flag,
8555 internal::get_beginning<typename VectorType::value_type>(
8556 destination),
8557 shared_vector_data,
8558 *this);
8559 }
8560 else
8561 {
8562 internal::FEFaceEvaluationGatherFactory<
8563 dim,
8564 typename VectorType::value_type,
8565 VectorizedArrayType>::integrate(n_components,
8566 integration_flag,
8567 internal::get_beginning<
8568 typename VectorType::value_type>(
8569 destination),
8570 shared_vector_data,
8571 *this);
8572 }
8573 }
8574 else
8575 {
8576 integrate(integration_flag);
8577 this->distribute_local_to_global(destination);
8578 }
8579}
8580
8581
8582
8583template <int dim,
8584 int fe_degree,
8585 int n_q_points_1d,
8586 int n_components_,
8587 typename Number,
8588 typename VectorizedArrayType>
8589inline std_cxx20::ranges::iota_view<unsigned int, unsigned int>
8590FEFaceEvaluation<dim,
8591 fe_degree,
8592 n_q_points_1d,
8593 n_components_,
8594 Number,
8595 VectorizedArrayType>::dof_indices() const
8596{
8597 return std_cxx20::ranges::iota_view<unsigned int, unsigned int>(
8598 0U, dofs_per_cell);
8599}
8600
8601
8602
8603template <int dim,
8604 int fe_degree,
8605 int n_q_points_1d,
8606 int n_components_,
8607 typename Number,
8608 typename VectorizedArrayType>
8609bool
8610FEEvaluation<dim,
8611 fe_degree,
8612 n_q_points_1d,
8613 n_components_,
8614 Number,
8615 VectorizedArrayType>::
8616 fast_evaluation_supported(const unsigned int given_degree,
8617 const unsigned int given_n_q_points_1d)
8618{
8619 return fe_degree == -1 ?
8621 fast_evaluation_supported(given_degree, given_n_q_points_1d) :
8622 true;
8623}
8624
8625
8626
8627template <int dim,
8628 int fe_degree,
8629 int n_q_points_1d,
8630 int n_components_,
8631 typename Number,
8632 typename VectorizedArrayType>
8633bool
8634FEFaceEvaluation<dim,
8635 fe_degree,
8636 n_q_points_1d,
8637 n_components_,
8638 Number,
8639 VectorizedArrayType>::
8640 fast_evaluation_supported(const unsigned int given_degree,
8641 const unsigned int given_n_q_points_1d)
8642{
8643 return fe_degree == -1 ?
8645 fast_evaluation_supported(given_degree, given_n_q_points_1d) :
8646 true;
8647}
8648
8649
8650
8651template <int dim,
8652 int fe_degree,
8653 int n_q_points_1d,
8654 int n_components_,
8655 typename Number,
8656 typename VectorizedArrayType>
8657bool
8658FEFaceEvaluation<dim,
8659 fe_degree,
8660 n_q_points_1d,
8661 n_components_,
8662 Number,
8663 VectorizedArrayType>::at_boundary() const
8664{
8665 Assert(this->dof_access_index !=
8668
8669 if (this->is_interior_face() == false)
8670 return false;
8671 else if (this->cell < this->matrix_free->n_inner_face_batches())
8672 return false;
8673 else if (this->cell < (this->matrix_free->n_inner_face_batches() +
8674 this->matrix_free->n_boundary_face_batches()))
8675 return true;
8676 else
8677 return false;
8678}
8679
8680
8681
8682template <int dim,
8683 int fe_degree,
8684 int n_q_points_1d,
8685 int n_components_,
8686 typename Number,
8687 typename VectorizedArrayType>
8689FEFaceEvaluation<dim,
8690 fe_degree,
8691 n_q_points_1d,
8692 n_components_,
8693 Number,
8694 VectorizedArrayType>::boundary_id() const
8695{
8696 Assert(this->dof_access_index !=
8699
8700 if (at_boundary())
8701 return this->matrix_free->get_boundary_id(this->cell);
8702 else
8704}
8705
8706
8707
8708template <int dim,
8709 int fe_degree,
8710 int n_q_points_1d,
8711 int n_components_,
8712 typename Number,
8713 typename VectorizedArrayType>
8714unsigned int
8715FEFaceEvaluation<
8716 dim,
8717 fe_degree,
8718 n_q_points_1d,
8719 n_components_,
8720 Number,
8721 VectorizedArrayType>::get_dofs_per_component_projected_to_face()
8722{
8723 return this->data->dofs_per_component_on_face;
8724}
8725
8726
8727
8728template <int dim,
8729 int fe_degree,
8730 int n_q_points_1d,
8731 int n_components_,
8732 typename Number,
8733 typename VectorizedArrayType>
8734unsigned int
8735FEFaceEvaluation<dim,
8736 fe_degree,
8737 n_q_points_1d,
8738 n_components_,
8739 Number,
8740 VectorizedArrayType>::get_dofs_projected_to_face()
8741{
8742 return this->data->dofs_per_component_on_face * n_components_;
8743}
8744
8745
8746
8747/*------------------------- end FEFaceEvaluation ------------------------- */
8748
8749
8750#endif // ifndef DOXYGEN
8751
8752
8754
8755#endif
*  *  iterator begin()
value_type get_dof_value(const unsigned int dof) const
void read_write_operation_global(const VectorOperation &operation, const std::array< VectorType *, n_components_ > &vectors) const
value_type get_laplacian(const unsigned int q_point) const
gradient_type get_gradient(const unsigned int q_point) const
void submit_gradient(const Tensor< 2, 1, VectorizedArrayType > val_in, const unsigned int q_point)
void submit_normal_hessian(const value_type normal_hessian_in, const unsigned int q_point)
std::conditional_t< n_components_==1, Tensor< 2, dim, VectorizedArrayType >, std::conditional_t< n_components_==dim, Tensor< 3, dim, VectorizedArrayType >, Tensor< 1, n_components_, Tensor< 2, dim, VectorizedArrayType > > > > hessian_type
internal::CurlType< dim, VectorizedArrayType > curl_type
void read_write_operation(const VectorOperation &operation, const std::array< VectorType *, n_components_ > &vectors, const std::array< const std::vector< ArrayView< const typename VectorType::value_type > > *, n_components_ > &vectors_sm, const std::bitset< n_lanes > &mask, const bool apply_constraints=true) const
void submit_gradient(const gradient_type grad_in, const unsigned int q_point)
void submit_value(const value_type val_in, const unsigned int q_point)
void submit_divergence(const VectorizedArrayType div_in, const unsigned int q_point)
void submit_dof_value(const value_type val_in, const unsigned int dof)
void distribute_local_to_global(VectorType &dst, const unsigned int first_index=0, const std::bitset< n_lanes > &mask=std::bitset< n_lanes >().flip()) const
std::conditional_t< n_components_==1, Tensor< 1, dim, VectorizedArrayType >, std::conditional_t< n_components_==dim, Tensor< 2, dim, VectorizedArrayType >, Tensor< 1, n_components_, Tensor< 1, dim, VectorizedArrayType > > > > gradient_type
FEEvaluationBase(const MatrixFree< dim, Number, VectorizedArrayType > &matrix_free, const unsigned int dof_handler_index, const unsigned int first_selected_component, const unsigned int quadrature_index, const unsigned int fe_degree, const unsigned int n_q_points, const bool is_interior_face, const unsigned int active_fe_index, const unsigned int active_quad_index, const unsigned int face_type)
void read_dof_values_plain(const VectorType &src, const unsigned int first_index=0, const std::bitset< n_lanes > &mask=std::bitset< n_lanes >().flip())
curl_type get_curl(const unsigned int q_point) const
VectorizedArrayType get_divergence(const unsigned int q_point) const
hessian_type get_hessian(const unsigned int q_point) const
FEEvaluationBase(const Mapping< dim > &mapping, const FiniteElement< dim > &fe, const Quadrature< 1 > &quadrature, const UpdateFlags update_flags, const unsigned int first_selected_component, const FEEvaluationData< dim, VectorizedArrayType, is_face > *other)
void submit_curl(const curl_type curl_in, const unsigned int q_point)
FEEvaluationBase & operator=(const FEEvaluationBase &other)
SymmetricTensor< 2, dim, VectorizedArrayType > get_symmetric_gradient(const unsigned int q_point) const
void submit_symmetric_gradient(const SymmetricTensor< 2, dim, VectorizedArrayType > grad_in, const unsigned int q_point)
gradient_type get_hessian_diagonal(const unsigned int q_point) const
void submit_value(const Tensor< 1, 1, VectorizedArrayType > val_in, const unsigned int q_point)
const MatrixFree< dim, Number, VectorizedArrayType > & get_matrix_free() const
void apply_hanging_node_constraints(const bool transpose) const
void set_dof_values_plain(VectorType &dst, const unsigned int first_index=0, const std::bitset< n_lanes > &mask=std::bitset< n_lanes >().flip()) const
void submit_normal_derivative(const value_type grad_in, const unsigned int q_point)
void read_write_operation_contiguous(const VectorOperation &operation, const std::array< VectorType *, n_components_ > &vectors, const std::array< const std::vector< ArrayView< const typename VectorType::value_type > > *, n_components_ > &vectors_sm, const std::bitset< n_lanes > &mask) const
value_type integrate_value() const
FEEvaluationBase(const FEEvaluationBase &other)
void submit_hessian(const hessian_type hessian_in, const unsigned int q_point)
void set_dof_values(VectorType &dst, const unsigned int first_index=0, const std::bitset< n_lanes > &mask=std::bitset< n_lanes >().flip()) const
const MatrixFree< dim, Number, VectorizedArrayType > * matrix_free
value_type get_normal_derivative(const unsigned int q_point) const
value_type get_value(const unsigned int q_point) const
std::conditional_t< n_components_==1, VectorizedArrayType, Tensor< 1, n_components_, VectorizedArrayType > > value_type
value_type get_normal_hessian(const unsigned int q_point) const
void read_dof_values(const VectorType &src, const unsigned int first_index=0, const std::bitset< n_lanes > &mask=std::bitset< n_lanes >().flip())
const MappingInfoStorageType::QuadratureDescriptor * descriptor
const MappingInfoStorageType * mapping_data
const ShapeInfoType * data
std::shared_ptr< internal::MatrixFreeFunctions::MappingDataOnTheFly< dim, Number > > mapped_geometry
const DoFInfo * dof_info
FEEvaluationData & operator=(const FEEvaluationData &other)
FEEvaluationData(const ShapeInfoType &shape_info, const bool is_interior_face=true)
const unsigned int dofs_per_component
std_cxx20::ranges::iota_view< unsigned int, unsigned int > dof_indices() const
FEEvaluation(const Mapping< dim > &mapping, const FiniteElement< dim > &fe, const Quadrature< 1 > &quadrature, const UpdateFlags update_flags, const unsigned int first_selected_component=0)
const unsigned int n_q_points
FEEvaluation(const FiniteElement< dim > &fe, const Quadrature< 1 > &quadrature, const UpdateFlags update_flags, const unsigned int first_selected_component=0)
void reinit(const typename Triangulation< dim >::cell_iterator &cell)
static bool fast_evaluation_supported(const unsigned int given_degree, const unsigned int given_n_q_points_1d)
void integrate_scatter(const EvaluationFlags::EvaluationFlags integration_flag, VectorType &output_vector)
void reinit(const unsigned int cell_batch_index)
void reinit(const std::array< unsigned int, n_lanes > &cell_ids)
FEEvaluation(const FiniteElement< dim > &fe, const FEEvaluationData< dim, VectorizedArrayType, false > &other, const unsigned int first_selected_component=0)
void reinit(const TriaIterator< DoFCellAccessor< dim, dim, level_dof_access > > &cell)
FEEvaluationBase< dim, n_components_, Number, false, VectorizedArrayType > BaseClass
void evaluate(const EvaluationFlags::EvaluationFlags evaluation_flag)
FEEvaluation(const MatrixFree< dim, Number, VectorizedArrayType > &matrix_free, const unsigned int dof_handler_index=0, const unsigned int quadrature_index=0, const unsigned int first_selected_component=0, const unsigned int active_fe_index=numbers::invalid_unsigned_int, const unsigned int active_quad_index=numbers::invalid_unsigned_int)
static constexpr unsigned int tensor_dofs_per_cell
void evaluate(const VectorizedArrayType *values_array, const EvaluationFlags::EvaluationFlags evaluation_flag)
typename BaseClass::gradient_type gradient_type
void integrate(const EvaluationFlags::EvaluationFlags integration_flag, VectorizedArrayType *values_array, const bool sum_into_values=false)
FEEvaluation(const MatrixFree< dim, Number, VectorizedArrayType > &matrix_free, const std::pair< unsigned int, unsigned int > &range, const unsigned int dof_handler_index=0, const unsigned int quadrature_index=0, const unsigned int first_selected_component=0)
static constexpr unsigned int dimension
void gather_evaluate(const VectorType &input_vector, const EvaluationFlags::EvaluationFlags evaluation_flag)
const unsigned int dofs_per_cell
static constexpr unsigned int static_dofs_per_cell
typename BaseClass::value_type value_type
FEEvaluation & operator=(const FEEvaluation &other)
void integrate(const EvaluationFlags::EvaluationFlags integration_flag)
static constexpr unsigned int n_components
static constexpr unsigned int static_n_q_points
static constexpr unsigned int n_lanes
FEEvaluation(const FEEvaluation &other)
void check_template_arguments(const unsigned int fe_no, const unsigned int first_selected_component)
static constexpr unsigned int static_dofs_per_component
typename BaseClass::value_type value_type
std_cxx20::ranges::iota_view< unsigned int, unsigned int > dof_indices() const
void integrate(const EvaluationFlags::EvaluationFlags integration_flag, VectorizedArrayType *values_array, const bool sum_into_values=false)
FEFaceEvaluation(const MatrixFree< dim, Number, VectorizedArrayType > &matrix_free, const std::pair< unsigned int, unsigned int > &range, const bool is_interior_face=true, const unsigned int dof_handler_index=0, const unsigned int quadrature_index=0, const unsigned int first_selected_component=0)
void collect_from_face(const EvaluationFlags::EvaluationFlags integration_flag, VectorizedArrayType *values_array, const bool sum_into_values=false)
bool at_boundary() const
void integrate_scatter(const EvaluationFlags::EvaluationFlags integration_flag, VectorType &output_vector)
static constexpr unsigned int static_n_q_points_cell
void project_to_face(const EvaluationFlags::EvaluationFlags evaluation_flag)
static constexpr unsigned int tensor_dofs_per_cell
unsigned int get_dofs_per_component_projected_to_face()
void project_to_face(const VectorizedArrayType *values_array, const EvaluationFlags::EvaluationFlags evaluation_flag)
const unsigned int dofs_per_component
void reinit(const unsigned int face_batch_number)
const unsigned int n_q_points
void gather_evaluate(const VectorType &input_vector, const EvaluationFlags::EvaluationFlags evaluation_flag)
void reinit(const unsigned int cell_batch_number, const unsigned int face_number)
static bool fast_evaluation_supported(const unsigned int given_degree, const unsigned int given_n_q_points_1d)
void evaluate(const VectorizedArrayType *values_array, const EvaluationFlags::EvaluationFlags evaluation_flag)
const unsigned int dofs_per_cell
static constexpr unsigned int n_components
FEFaceEvaluation(const MatrixFree< dim, Number, VectorizedArrayType > &matrix_free, const bool is_interior_face=true, const unsigned int dof_handler_index=0, const unsigned int quadrature_index=0, const unsigned int first_selected_component=0, const unsigned int active_fe_index=numbers::invalid_unsigned_int, const unsigned int active_quad_index=numbers::invalid_unsigned_int, const unsigned int face_type=numbers::invalid_unsigned_int)
void evaluate(const EvaluationFlags::EvaluationFlags evaluation_flag)
FEEvaluationBase< dim, n_components_, Number, true, VectorizedArrayType > BaseClass
void collect_from_face(const EvaluationFlags::EvaluationFlags integration_flag, const bool sum_into_values=false)
static constexpr unsigned int static_dofs_per_component
static constexpr unsigned int n_lanes
static constexpr unsigned int static_n_q_points
unsigned int get_dofs_projected_to_face()
static constexpr unsigned int dimension
typename BaseClass::gradient_type gradient_type
types::boundary_id boundary_id() const
void integrate(const EvaluationFlags::EvaluationFlags integration_flag, const bool sum_into_values=false)
void evaluate_in_face(const EvaluationFlags::EvaluationFlags evaluation_flag)
void integrate_scatter(const bool integrate_values, const bool integrate_gradients, VectorType &output_vector)
static constexpr unsigned int static_dofs_per_cell
void integrate_in_face(const EvaluationFlags::EvaluationFlags integration_flag)
std::pair< unsigned int, unsigned int > component_to_base_index(const unsigned int component) const
unsigned int element_multiplicity(const unsigned int index) const
Abstract base class for mapping classes.
Definition mapping.h:318
const internal::MatrixFreeFunctions::TaskInfo & get_task_info() const
types::boundary_id get_boundary_id(const unsigned int face_batch_index) const
const Table< 3, unsigned int > & get_cell_and_face_to_plain_faces() const
unsigned int n_inner_face_batches() const
unsigned int n_active_entries_per_cell_batch(const unsigned int cell_batch_index) const
const internal::MatrixFreeFunctions::FaceToCellTopology< VectorizedArrayType::size()> & get_face_info(const unsigned int face_batch_index) const
const internal::MatrixFreeFunctions::DoFInfo & get_dof_info(const unsigned int dof_handler_index_component=0) const
AlignedVector< VectorizedArrayType > * acquire_scratch_data() const
const internal::MatrixFreeFunctions::MappingInfo< dim, Number, VectorizedArrayType > & get_mapping_info() const
const Number * constraint_pool_begin(const unsigned int pool_index) const
void release_scratch_data(const AlignedVector< VectorizedArrayType > *memory) const
DoFHandler< dim >::cell_iterator get_cell_iterator(const unsigned int cell_batch_index, const unsigned int lane_index, const unsigned int dof_handler_index=0) const
bool indices_initialized() const
const Number * constraint_pool_end(const unsigned int pool_index) const
unsigned int n_components() const
unsigned int n_active_entries_per_face_batch(const unsigned int face_batch_index) const
const internal::MatrixFreeFunctions::ShapeInfo< Number > & get_shape_info(const unsigned int dof_handler_index_component=0, const unsigned int quad_index=0, const unsigned int fe_base_element=0, const unsigned int hp_active_fe_index=0, const unsigned int hp_active_quad_index=0) const
unsigned int n_base_elements(const unsigned int dof_handler_index) const
constexpr const Number & access_raw_entry(const unsigned int unrolled_index) const
#define DEAL_II_ALWAYS_INLINE
Definition config.h:165
#define DEAL_II_OPENMP_SIMD_PRAGMA
Definition config.h:213
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
constexpr bool running_in_debug_mode()
Definition config.h:76
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
DerivativeForm< 1, spacedim, dim, Number > transpose(const DerivativeForm< 1, dim, spacedim, Number > &DF)
#define DEAL_II_NOT_IMPLEMENTED()
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcAccessToUninitializedField()
static ::ExceptionBase & ExcIndexRange(std::size_t arg1, std::size_t arg2, std::size_t arg3)
static ::ExceptionBase & ExcNotInitialized()
static ::ExceptionBase & ExcMatrixFreeAccessToUninitializedMappingField(std::string arg1)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
TriaIterator< CellAccessor< dim, spacedim > > cell_iterator
Definition tria.h:1624
const bool IsBlockVector< VectorType >::value
UpdateFlags
@ update_jacobian_grads
Gradient of volume element.
@ update_quadrature_points
Transformed quadrature points.
MappingQ< dim, spacedim > StaticMappingQ1< dim, spacedim >::mapping
Definition mapping_q1.h:101
EvaluationFlags
The EvaluationFlags enum.
Tpetra::Vector< Number, LO, GO, NodeType< MemorySpace > > VectorType
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
Definition utilities.cc:210
void quadrature_points(const Triangulation< dim, spacedim > &triangulation, const Quadrature< dim > &quadrature, const std::vector< std::vector< BoundingBox< spacedim > > > &global_bounding_boxes, ParticleHandler< dim, spacedim > &particle_handler, const Mapping< dim, spacedim > &mapping=(ReferenceCells::get_hypercube< dim >() .template get_default_linear_mapping< spacedim >()), const std::vector< std::vector< double > > &properties={})
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
*  *  *  ScaleZFunction< dim, Number, components >::ScaleZFunction *  component(component)
*  *  *  RotationFunction< dim, Number >::RotationFunction Number(dim)
*  *  *  *  *  *  TimeRateUpdateFlags TimeRateRequest< ValueType, dim, Number >  get_update_flags() const
*  *  *  *  std::vector< Number > ThermoPlasticMaterial< dim, ViscoplasticYieldLaw, Number >::get_state_parameters   const
constexpr const ReferenceCell< dim > & get_hypercube()
T sum(const T &t, const MPI_Comm mpi_communicator)
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:464
constexpr T pow(const T base, const int iexp)
Definition utilities.h:966
void run(const Iterator &begin, const std_cxx20::type_identity_t< Iterator > &end, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int queue_length, const unsigned int chunk_size)
void reinit(MatrixBlock< MatrixType > &v, const BlockSparsityPattern &p)
void check_vector_compatibility(const VectorType &vec, const MatrixFree< dim, Number, VectorizedArrayType > &, const internal::MatrixFreeFunctions::DoFInfo &dof_info)
std::conditional_t< dim==3, Tensor< 1, 3, NumberType >, std::conditional_t< dim==2, NumberType, std::monostate > > CurlType
constexpr types::geometric_orientation invalid_geometric_orientation
Definition types.h:377
constexpr unsigned int invalid_unsigned_int
Definition types.h:236
constexpr types::boundary_id internal_face_boundary_id
Definition types.h:327
constexpr types::geometric_orientation default_geometric_orientation
Definition types.h:350
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)
unsigned int boundary_id
Definition types.h:159
std::uint8_t geometric_orientation
Definition types.h:38
*  const unsigned int dofs_per_cell
*  const unsigned int n_q_points
static constexpr unsigned int faces_per_cell
static constexpr unsigned int max_children_per_cell
static const bool value
static bool fast_evaluation_supported(const unsigned int given_degree, const unsigned int n_q_points_1d)
static void evaluate(const unsigned int n_components, const EvaluationFlags::EvaluationFlags evaluation_flag, const Number *values_dofs, FEEvaluationData< dim, Number, false > &fe_eval)
static void integrate(const unsigned int n_components, const EvaluationFlags::EvaluationFlags integration_flag, Number *values_dofs, FEEvaluationData< dim, Number, false > &fe_eval, const bool sum_into_values_array)
static void apply(const unsigned int n_components, const unsigned int fe_degree, const MatrixFreeFunctions::ShapeInfo< Number > &shape_info, const bool transpose, const std::array< MatrixFreeFunctions::compressed_constraint_kind, VectorizedArrayType::size()> &c_mask, VectorizedArrayType *values)
static void integrate(const unsigned int n_components, const EvaluationFlags::EvaluationFlags integration_flag, Number *values_dofs, FEEvaluationData< dim, Number, true > &fe_eval, const bool sum_into_values)
static void evaluate(const unsigned int n_components, const EvaluationFlags::EvaluationFlags evaluation_flag, const Number *values_dofs, FEEvaluationData< dim, Number, true > &fe_eval)
static bool fast_evaluation_supported(const unsigned int given_degree, const unsigned int n_q_points_1d)
static void evaluate_in_face(const unsigned int n_components, const EvaluationFlags::EvaluationFlags evaluation_flag, FEEvaluationData< dim, Number, true > &fe_eval)
static void integrate_in_face(const unsigned int n_components, const EvaluationFlags::EvaluationFlags integration_flag, FEEvaluationData< dim, Number, true > &fe_eval)
static void collect_from_face(const unsigned int n_components, const EvaluationFlags::EvaluationFlags integration_flag, Number *values_dofs, FEEvaluationData< dim, Number, true > &fe_eval, const bool sum_into_values)
static void project_to_face(const unsigned int n_components, const EvaluationFlags::EvaluationFlags evaluation_flag, const Number *values_dofs, FEEvaluationData< dim, Number, true > &fe_eval)
std::vector< std::pair< unsigned short, unsigned short > > constraint_indicator
Definition dof_info.h:536
std::vector< std::pair< unsigned int, unsigned int > > row_starts
Definition dof_info.h:495
std::vector< std::vector< unsigned int > > component_dof_indices_offset
Definition dof_info.h:688
unsigned int fe_index_from_degree(const unsigned int first_selected_component, const unsigned int fe_degree) const
std::vector< unsigned int > dof_indices
Definition dof_info.h:512
std::vector< compressed_constraint_kind > hanging_node_constraint_masks
Definition dof_info.h:524
std::array< std::vector< unsigned int >, 3 > dof_indices_interleave_strides
Definition dof_info.h:572
std::array< std::vector< std::pair< unsigned int, unsigned int > >, 3 > dof_indices_contiguous_sm
Definition dof_info.h:562
std::vector< unsigned int > row_starts_plain_indices
Definition dof_info.h:635
std::vector< unsigned int > component_to_base_index
Definition dof_info.h:675
std::array< std::vector< unsigned int >, 3 > dof_indices_contiguous
Definition dof_info.h:551
std::vector< unsigned int > plain_dof_indices
Definition dof_info.h:645
std::array< std::vector< unsigned char >, 3 > n_vectorization_lanes_filled
Definition dof_info.h:583
std::vector< unsigned int > dof_indices_interleaved
Definition dof_info.h:541
std::array< std::vector< IndexStorageVariants >, 3 > index_storage_variants
Definition dof_info.h:487
std::vector< unsigned int > face_partition_data
Definition task_info.h:494
constexpr Number determinant(const SymmetricTensor< 2, dim, Number > &)
constexpr SymmetricTensor< 2, dim, Number > invert(const SymmetricTensor< 2, dim, Number > &)
constexpr SymmetricTensor< 4, dim, Number > outer_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, Number > &t2)