deal.II version GIT relicensing-6809-ge913b9bb34 2026-09-25 17:20:01+00:00
\(\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
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
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
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
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 :
2331 std::min<unsigned int>(
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,
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());
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 =
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 =
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>
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<
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 :
2895 internal::MatrixFreeFunctions::DoFInfo::dof_access_cell]
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 :
2930 internal::MatrixFreeFunctions::DoFInfo::dof_access_cell]
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 &&
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] +
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<
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 // Whether the n_components copies of a vector-valued quantity live in
3326 // n_components separate (typically scalar) vectors, one component per
3327 // vector -- as opposed to all components being interleaved within a
3328 // single vector that belongs to an FESystem with n_fe_components ==
3329 // n_components. This distinction recurs throughout this function
3330 // because the two cases require different index computations; we
3331 // evaluate it once here rather than at each use.
3332 const bool separate_vectors =
3333 (n_components == 1 || this->n_fe_components == 1);
3334
3335 // Simple case: We have contiguous storage, so we can simply copy out the
3336 // data
3337 if (dof_info.index_storage_variants[ind][this->cell] ==
3339 interleaved_contiguous &&
3340 n_active_lanes == n_lanes && !accesses_exterior_dofs)
3341 {
3342 const unsigned int dof_index =
3343 dof_indices_cont[this->cell * n_lanes] +
3344 this->dof_info
3345 ->component_dof_indices_offset[this->active_fe_index]
3346 [this->first_selected_component] *
3347 n_lanes;
3348 if (separate_vectors)
3349 for (unsigned int comp = 0; comp < n_components; ++comp)
3350 operation.process_dofs_vectorized(dofs_per_component,
3351 dof_index,
3352 *src[comp],
3353 values_dofs[comp],
3354 vector_selector);
3355 else
3356 operation.process_dofs_vectorized(dofs_per_component * n_components,
3357 dof_index,
3358 *src[0],
3359 values_dofs[0],
3360 vector_selector);
3361 return;
3362 }
3363
3364 const std::array<unsigned int, n_lanes> &cells = this->get_cell_or_face_ids();
3365
3366 // More general case: Must go through the components one by one and apply
3367 // some transformations
3368 const unsigned int n_filled_lanes =
3369 dof_info.n_vectorization_lanes_filled[ind][this->cell];
3370
3371 const bool use_vectorized_path = n_filled_lanes == n_lanes &&
3372 n_active_lanes == n_lanes &&
3373 !accesses_exterior_dofs;
3374
3375 if (vectors_sm[0] != nullptr)
3376 {
3377 const auto compute_vector_ptrs = [&](const unsigned int comp) {
3378 std::array<typename VectorType::value_type *, n_lanes> vector_ptrs{
3379 {nullptr}};
3380
3381 const auto upper_bound =
3382 std::min<unsigned int>(n_filled_lanes, n_lanes);
3383 for (unsigned int v = 0; v < upper_bound; ++v)
3384 {
3385 if (mask[v] == false)
3386 {
3387 vector_ptrs[v] = nullptr;
3388 continue;
3389 }
3390
3393 Assert(ind < dof_info.dof_indices_contiguous_sm.size(),
3394 ExcIndexRange(ind,
3395 0,
3396 dof_info.dof_indices_contiguous_sm.size()));
3397 Assert(
3398 cells[v] < dof_info.dof_indices_contiguous_sm[ind].size(),
3399 ExcIndexRange(cells[v],
3400 0,
3401 dof_info.dof_indices_contiguous_sm[ind].size()));
3402
3403 const auto &temp =
3404 dof_info.dof_indices_contiguous_sm[ind][cells[v]];
3405
3406 if (temp.first != numbers::invalid_unsigned_int)
3407 vector_ptrs[v] = const_cast<typename VectorType::value_type *>(
3408 vectors_sm[comp]->operator[](temp.first).data() + temp.second +
3410 [this->active_fe_index][this->first_selected_component]);
3411 else
3412 vector_ptrs[v] = nullptr;
3413 }
3414 for (unsigned int v = n_filled_lanes; v < n_lanes; ++v)
3415 vector_ptrs[v] = nullptr;
3416
3417 return vector_ptrs;
3418 };
3419
3420 if (use_vectorized_path)
3421 {
3422 // If the components live in separate vectors, gather each one
3423 // with its own transposed access. If instead all components
3424 // come from a single FESystem-based vector, their DoFs are
3425 // contiguous per cell in both the source vector and
3426 // values_dofs, so we can process all of them with a single
3427 // bulk transposed access instead -- one loop iteration with a
3428 // correspondingly larger block size.
3429 const unsigned int n_blocks = separate_vectors ? n_components : 1;
3430 const unsigned int block_size = separate_vectors ?
3431 dofs_per_component :
3432 dofs_per_component * n_components;
3433 for (unsigned int comp = 0; comp < n_blocks; ++comp)
3434 {
3435 auto vector_ptrs =
3436 compute_vector_ptrs(separate_vectors ? comp : 0);
3437 operation.process_dofs_vectorized_transpose(block_size,
3438 vector_ptrs,
3439 separate_vectors ?
3440 values_dofs[comp] :
3441 &values_dofs[0][0],
3442 vector_selector);
3443 }
3444 }
3445 else
3446 for (unsigned int comp = 0; comp < n_components; ++comp)
3447 {
3448 auto vector_ptrs = compute_vector_ptrs(separate_vectors ? comp : 0);
3449
3450 for (unsigned int i = 0; i < dofs_per_component; ++i)
3451 operation.process_empty(values_dofs[comp][i]);
3452
3453 // As above: with separate vectors, component comp's DoFs sit
3454 // at the start of vector_ptrs; with a single FESystem-based
3455 // vector, they are offset by the preceding components' DoFs.
3456 const unsigned int comp_offset =
3457 separate_vectors ? 0 : comp * dofs_per_component;
3458 for (unsigned int v = 0; v < n_filled_lanes; ++v)
3459 if (mask[v] == true)
3460 for (unsigned int i = 0; i < dofs_per_component; ++i)
3461 operation.process_dof(vector_ptrs[v][i + comp_offset],
3462 values_dofs[comp][i][v]);
3463 }
3464 return;
3465 }
3466
3467 std::array<unsigned int, n_lanes> dof_indices{
3469 Assert(n_filled_lanes <= n_lanes, ExcInternalError());
3470 for (unsigned int v = 0; v < n_filled_lanes; ++v)
3471 {
3472 Assert(mask[v] == false || cells[v] != numbers::invalid_unsigned_int,
3474 if (mask[v] == true)
3475 dof_indices[v] =
3476 dof_indices_cont[cells[v]] +
3477 this->dof_info
3478 ->component_dof_indices_offset[this->active_fe_index]
3479 [this->first_selected_component] *
3480 dof_info.dof_indices_interleave_strides[ind][cells[v]];
3481 }
3482
3483 // In the case with contiguous cell indices, we know that there are no
3484 // constraints and that the indices within each element are contiguous
3485 if (use_vectorized_path)
3486 {
3487 if (dof_info.index_storage_variants[ind][this->cell] ==
3489 contiguous)
3490 {
3491 if (separate_vectors)
3492 for (unsigned int comp = 0; comp < n_components; ++comp)
3493 operation.process_dofs_vectorized_transpose(dofs_per_component,
3494 dof_indices.data(),
3495 *src[comp],
3496 values_dofs[comp],
3497 vector_selector);
3498 else
3499 operation.process_dofs_vectorized_transpose(dofs_per_component *
3500 n_components,
3501 dof_indices.data(),
3502 *src[0],
3503 &values_dofs[0][0],
3504 vector_selector);
3505 }
3506 else if (dof_info.index_storage_variants[ind][this->cell] ==
3508 interleaved_contiguous_strided)
3509 {
3510 std::array<typename VectorType::value_type *, n_components> src_ptrs{
3511 {nullptr}};
3512 if (separate_vectors)
3513 for (unsigned int comp = 0; comp < n_components; ++comp)
3514 src_ptrs[comp] = const_cast<typename VectorType::value_type *>(
3515 src[comp]->begin());
3516 else
3517 src_ptrs[0] =
3518 const_cast<typename VectorType::value_type *>(src[0]->begin());
3519
3520 if (separate_vectors)
3521 for (unsigned int i = 0; i < dofs_per_component; ++i)
3522 {
3523 for (unsigned int comp = 0; comp < n_components; ++comp)
3524 operation.process_dof_gather(dof_indices.data(),
3525 *src[comp],
3526 i * n_lanes,
3527 src_ptrs[comp] + i * n_lanes,
3528 values_dofs[comp][i],
3529 vector_selector);
3530 }
3531 else
3532 for (unsigned int comp = 0; comp < n_components; ++comp)
3533 for (unsigned int i = 0; i < dofs_per_component; ++i)
3534 {
3535 operation.process_dof_gather(
3536 dof_indices.data(),
3537 *src[0],
3538 (comp * dofs_per_component + i) * n_lanes,
3539 src_ptrs[0] + (comp * dofs_per_component + i) * n_lanes,
3540 values_dofs[comp][i],
3541 vector_selector);
3542 }
3543 }
3544 else
3545 {
3546 Assert(dof_info.index_storage_variants[ind][this->cell] ==
3548 IndexStorageVariants::interleaved_contiguous_mixed_strides,
3550 std::array<typename VectorType::value_type *, n_components> src_ptrs{
3551 {nullptr}};
3552 if (separate_vectors)
3553 for (unsigned int comp = 0; comp < n_components; ++comp)
3554 src_ptrs[comp] = const_cast<typename VectorType::value_type *>(
3555 src[comp]->begin());
3556 else
3557 src_ptrs[0] =
3558 const_cast<typename VectorType::value_type *>(src[0]->begin());
3559
3560 const unsigned int *offsets =
3561 &dof_info.dof_indices_interleave_strides[ind][n_lanes * this->cell];
3562 if (separate_vectors)
3563 for (unsigned int i = 0; i < dofs_per_component; ++i)
3564 {
3565 for (unsigned int comp = 0; comp < n_components; ++comp)
3566 operation.process_dof_gather(dof_indices.data(),
3567 *src[comp],
3568 0,
3569 src_ptrs[comp],
3570 values_dofs[comp][i],
3571 vector_selector);
3573 for (unsigned int v = 0; v < n_lanes; ++v)
3574 dof_indices[v] += offsets[v];
3575 }
3576 else
3577 for (unsigned int comp = 0; comp < n_components; ++comp)
3578 for (unsigned int i = 0; i < dofs_per_component; ++i)
3579 {
3580 operation.process_dof_gather(dof_indices.data(),
3581 *src[0],
3582 0,
3583 src_ptrs[0],
3584 values_dofs[comp][i],
3585 vector_selector);
3587 for (unsigned int v = 0; v < n_lanes; ++v)
3588 dof_indices[v] += offsets[v];
3589 }
3590 }
3591 }
3592 else
3593 for (unsigned int comp = 0; comp < n_components; ++comp)
3594 {
3595 for (unsigned int i = 0; i < dofs_per_component; ++i)
3596 operation.process_empty(values_dofs[comp][i]);
3597 if (accesses_exterior_dofs)
3598 {
3599 for (unsigned int v = 0; v < n_filled_lanes; ++v)
3600 if (mask[v] == true)
3601 {
3602 if (dof_info.index_storage_variants
3603 [ind][cells[v] / VectorizedArrayType::size()] ==
3606 {
3607 if (separate_vectors)
3608 {
3609 for (unsigned int i = 0; i < dofs_per_component; ++i)
3610 operation.process_dof(dof_indices[v] + i,
3611 *src[comp],
3612 values_dofs[comp][i][v]);
3613 }
3614 else
3615 {
3616 for (unsigned int i = 0; i < dofs_per_component; ++i)
3617 operation.process_dof(dof_indices[v] + i +
3618 comp * dofs_per_component,
3619 *src[0],
3620 values_dofs[comp][i][v]);
3621 }
3622 }
3623 else
3624 {
3625 const unsigned int offset =
3626 dof_info.dof_indices_interleave_strides[ind][cells[v]];
3627 AssertIndexRange(offset, VectorizedArrayType::size() + 1);
3628 if (separate_vectors)
3629 {
3630 for (unsigned int i = 0; i < dofs_per_component; ++i)
3631 operation.process_dof(dof_indices[v] + i * offset,
3632 *src[comp],
3633 values_dofs[comp][i][v]);
3634 }
3635 else
3636 {
3637 for (unsigned int i = 0; i < dofs_per_component; ++i)
3638 operation.process_dof(
3639 dof_indices[v] +
3640 (i + comp * dofs_per_component) * offset,
3641 *src[0],
3642 values_dofs[comp][i][v]);
3643 }
3644 }
3645 }
3646 }
3647 else
3648 {
3649 if (dof_info.index_storage_variants[ind][this->cell] ==
3651 contiguous)
3652 {
3653 if (separate_vectors)
3654 {
3655 for (unsigned int v = 0; v < n_filled_lanes; ++v)
3656 if (mask[v] == true)
3657 for (unsigned int i = 0; i < dofs_per_component; ++i)
3658 operation.process_dof(dof_indices[v] + i,
3659 *src[comp],
3660 values_dofs[comp][i][v]);
3661 }
3662 else
3663 {
3664 for (unsigned int v = 0; v < n_filled_lanes; ++v)
3665 if (mask[v] == true)
3666 for (unsigned int i = 0; i < dofs_per_component; ++i)
3667 operation.process_dof(dof_indices[v] + i +
3668 comp * dofs_per_component,
3669 *src[0],
3670 values_dofs[comp][i][v]);
3671 }
3672 }
3673 else
3674 {
3675 const unsigned int *offsets =
3677 [ind][VectorizedArrayType::size() * this->cell];
3678 for (unsigned int v = 0; v < n_filled_lanes; ++v)
3679 AssertIndexRange(offsets[v], VectorizedArrayType::size() + 1);
3680 if (separate_vectors)
3681 for (unsigned int v = 0; v < n_filled_lanes; ++v)
3682 {
3683 if (mask[v] == true)
3684 for (unsigned int i = 0; i < dofs_per_component; ++i)
3685 operation.process_dof(dof_indices[v] + i * offsets[v],
3686 *src[comp],
3687 values_dofs[comp][i][v]);
3688 }
3689 else
3690 {
3691 for (unsigned int v = 0; v < n_filled_lanes; ++v)
3692 if (mask[v] == true)
3693 for (unsigned int i = 0; i < dofs_per_component; ++i)
3694 operation.process_dof(
3695 dof_indices[v] +
3696 (i + comp * dofs_per_component) * offsets[v],
3697 *src[0],
3698 values_dofs[comp][i][v]);
3699 }
3700 }
3701 }
3702 }
3703}
3704
3705namespace internal
3706{
3707 template <
3708 typename Number,
3709 typename VectorType,
3710 std::enable_if_t<!IsBlockVector<VectorType>::value, VectorType> * = nullptr>
3711 decltype(std::declval<VectorType>().begin())
3712 get_beginning(VectorType &vec)
3713 {
3714 return vec.begin();
3715 }
3716
3717 template <
3718 typename Number,
3719 typename VectorType,
3720 std::enable_if_t<IsBlockVector<VectorType>::value, VectorType> * = nullptr>
3721 typename VectorType::value_type *
3722 get_beginning(VectorType &)
3723 {
3724 return nullptr;
3725 }
3726
3727 template <typename VectorType,
3728 std::enable_if_t<has_shared_vector_data<VectorType>, VectorType> * =
3729 nullptr>
3730 const std::vector<ArrayView<const typename VectorType::value_type>> *
3731 get_shared_vector_data(VectorType *vec,
3732 const bool is_valid_mode_for_sm,
3733 const unsigned int active_fe_index,
3735 {
3736 // note: no hp is supported
3737 if (is_valid_mode_for_sm &&
3738 dof_info->dof_indices_contiguous_sm[0 /*any index (<3) should work*/]
3739 .size() > 0 &&
3740 active_fe_index == 0)
3741 return &vec->shared_vector_data();
3742 else
3743 return nullptr;
3744 }
3745
3746 template <typename VectorType,
3747 std::enable_if_t<!has_shared_vector_data<VectorType>, VectorType>
3748 * = nullptr>
3749 const std::vector<ArrayView<const typename VectorType::value_type>> *
3750 get_shared_vector_data(VectorType *,
3751 const bool,
3752 const unsigned int,
3754 {
3755 return nullptr;
3756 }
3757
3758 template <int n_components, typename VectorType>
3759 std::pair<
3760 std::array<typename internal::BlockVectorSelector<
3761 VectorType,
3762 IsBlockVector<VectorType>::value>::BaseVectorType *,
3763 n_components>,
3764 std::array<
3765 const std::vector<ArrayView<const typename internal::BlockVectorSelector<
3766 VectorType,
3767 IsBlockVector<VectorType>::value>::BaseVectorType::value_type>> *,
3768 n_components>>
3769 get_vector_data(VectorType &src,
3770 const unsigned int first_index,
3771 const bool is_valid_mode_for_sm,
3772 const unsigned int active_fe_index,
3774 {
3775 // select between block vectors and non-block vectors. Note that the number
3776 // of components is checked in the internal data
3777 std::pair<
3778 std::array<typename internal::BlockVectorSelector<
3779 VectorType,
3780 IsBlockVector<VectorType>::value>::BaseVectorType *,
3781 n_components>,
3782 std::array<
3783 const std::vector<
3784 ArrayView<const typename internal::BlockVectorSelector<
3785 VectorType,
3786 IsBlockVector<VectorType>::value>::BaseVectorType::value_type>> *,
3787 n_components>>
3788 src_data;
3789
3790 for (unsigned int d = 0; d < n_components; ++d)
3791 src_data.first[d] = internal::BlockVectorSelector<
3792 VectorType,
3793 IsBlockVector<VectorType>::value>::get_vector_component(src,
3794 d +
3795 first_index);
3796
3797 for (unsigned int d = 0; d < n_components; ++d)
3798 src_data.second[d] = get_shared_vector_data(
3799 const_cast<typename internal::BlockVectorSelector<
3800 std::remove_const_t<VectorType>,
3802 *>(src_data.first[d]),
3803 is_valid_mode_for_sm,
3804 active_fe_index,
3805 dof_info);
3806
3807 return src_data;
3808 }
3809} // namespace internal
3810
3811
3812
3813template <int dim,
3814 int n_components_,
3815 typename Number,
3816 bool is_face,
3817 typename VectorizedArrayType>
3818inline void
3821{
3822 if (this->dof_info == nullptr ||
3823 this->dof_info->hanging_node_constraint_masks.empty() ||
3824 this->dof_info->hanging_node_constraint_masks_comp.empty() ||
3825 this->dof_info->hanging_node_constraint_masks_comp
3826 [this->active_fe_index][this->first_selected_component] == false)
3827 return; // nothing to do with faces
3828
3829 std::array<internal::MatrixFreeFunctions::compressed_constraint_kind, n_lanes>
3830 constraint_mask{{internal::MatrixFreeFunctions::
3831 unconstrained_compressed_constraint_kind}};
3832
3833 bool hn_available = false;
3834
3835 const std::array<unsigned int, n_lanes> &cells = this->get_cell_ids();
3836
3837 for (unsigned int v = 0; v < n_lanes; ++v)
3838 {
3839 if (cells[v] == numbers::invalid_unsigned_int)
3840 {
3841 constraint_mask[v] = internal::MatrixFreeFunctions::
3843 continue;
3844 }
3845
3846 const unsigned int cell_index = cells[v];
3847 const auto mask =
3849 constraint_mask[v] = mask;
3850
3851 hn_available |= (mask != internal::MatrixFreeFunctions::
3853 }
3854
3855 if (hn_available == false)
3856 return; // no hanging node on cell batch -> nothing to do
3857
3859 apply(n_components,
3860 this->data->data.front().fe_degree,
3861 this->get_shape_info(),
3862 transpose,
3863 constraint_mask,
3864 this->values_dofs);
3865}
3866
3867
3868
3869template <int dim,
3870 int n_components_,
3871 typename Number,
3872 bool is_face,
3873 typename VectorizedArrayType>
3874template <typename VectorType>
3875inline void
3877 read_dof_values(const VectorType &src,
3878 const unsigned int first_index,
3879 const std::bitset<n_lanes> &mask)
3880{
3881 const auto src_data = internal::get_vector_data<n_components_>(
3882 src,
3883 first_index,
3884 this->dof_info != nullptr &&
3885 this->dof_access_index ==
3887 this->active_fe_index,
3888 this->dof_info);
3889
3891 read_write_operation(reader, src_data.first, src_data.second, mask, true);
3892
3893 apply_hanging_node_constraints(false);
3894
3895 if constexpr (running_in_debug_mode())
3896 {
3897 this->dof_values_initialized = true;
3898 }
3899}
3900
3901
3902
3903template <int dim,
3904 int n_components_,
3905 typename Number,
3906 bool is_face,
3907 typename VectorizedArrayType>
3908template <typename VectorType>
3909inline void
3911 read_dof_values_plain(const VectorType &src,
3912 const unsigned int first_index,
3913 const std::bitset<n_lanes> &mask)
3914{
3915 const auto src_data = internal::get_vector_data<n_components_>(
3916 src,
3917 first_index,
3918 this->dof_info != nullptr &&
3919 this->dof_access_index ==
3921 this->active_fe_index,
3922 this->dof_info);
3923
3925 read_write_operation(reader, src_data.first, src_data.second, mask, false);
3926
3927 if constexpr (running_in_debug_mode())
3928 {
3929 this->dof_values_initialized = true;
3930 }
3931}
3932
3933
3934
3935template <int dim,
3936 int n_components_,
3937 typename Number,
3938 bool is_face,
3939 typename VectorizedArrayType>
3940template <typename VectorType>
3941inline void
3943 distribute_local_to_global(VectorType &dst,
3944 const unsigned int first_index,
3945 const std::bitset<n_lanes> &mask) const
3946{
3947 if constexpr (running_in_debug_mode())
3948 {
3949 Assert(this->dof_values_initialized == true,
3951 }
3952
3953 apply_hanging_node_constraints(true);
3954
3955 const auto dst_data = internal::get_vector_data<n_components_>(
3956 dst,
3957 first_index,
3958 this->dof_info != nullptr &&
3959 this->dof_access_index ==
3961 this->active_fe_index,
3962 this->dof_info);
3963
3965 distributor;
3966 read_write_operation(distributor, dst_data.first, dst_data.second, mask);
3967}
3968
3969
3970
3971template <int dim,
3972 int n_components_,
3973 typename Number,
3974 bool is_face,
3975 typename VectorizedArrayType>
3976template <typename VectorType>
3977inline void
3979 set_dof_values(VectorType &dst,
3980 const unsigned int first_index,
3981 const std::bitset<n_lanes> &mask) const
3982{
3983 if constexpr (running_in_debug_mode())
3984 {
3985 Assert(this->dof_values_initialized == true,
3987 }
3988
3989 const auto dst_data = internal::get_vector_data<n_components_>(
3990 dst,
3991 first_index,
3992 this->dof_info != nullptr &&
3993 this->dof_access_index ==
3995 this->active_fe_index,
3996 this->dof_info);
3997
3999 read_write_operation(setter, dst_data.first, dst_data.second, mask);
4000}
4001
4002
4003
4004template <int dim,
4005 int n_components_,
4006 typename Number,
4007 bool is_face,
4008 typename VectorizedArrayType>
4009template <typename VectorType>
4010inline void
4012 set_dof_values_plain(VectorType &dst,
4013 const unsigned int first_index,
4014 const std::bitset<n_lanes> &mask) const
4015{
4016 if constexpr (running_in_debug_mode())
4017 {
4018 Assert(this->dof_values_initialized == true,
4020 }
4021
4022 const auto dst_data = internal::get_vector_data<n_components_>(
4023 dst,
4024 first_index,
4025 this->dof_access_index ==
4027 this->active_fe_index,
4028 this->dof_info);
4029
4031 read_write_operation(setter, dst_data.first, dst_data.second, mask, false);
4032}
4033
4034
4035
4036/*------------------------------ access to data fields ----------------------*/
4037
4038
4039
4040template <int dim,
4041 int n_components_,
4042 typename Number,
4043 bool is_face,
4044 typename VectorizedArrayType>
4046 typename FEEvaluationBase<dim,
4047 n_components_,
4048 Number,
4049 is_face,
4050 VectorizedArrayType>::value_type
4052 get_dof_value(const unsigned int dof) const
4053{
4054 AssertIndexRange(dof, this->data->dofs_per_component_on_cell);
4055 if constexpr (n_components == 1)
4056 return this->values_dofs[dof];
4057 else
4058 {
4059 const std::size_t dofs = this->data->dofs_per_component_on_cell;
4060 Tensor<1, n_components_, VectorizedArrayType> return_value;
4061 for (unsigned int comp = 0; comp < n_components; ++comp)
4062 return_value[comp] = this->values_dofs[comp * dofs + dof];
4063 return return_value;
4064 }
4065}
4066
4067
4068
4069template <int dim,
4070 int n_components_,
4071 typename Number,
4072 bool is_face,
4073 typename VectorizedArrayType>
4075 typename FEEvaluationBase<dim,
4076 n_components_,
4077 Number,
4078 is_face,
4079 VectorizedArrayType>::value_type
4081 get_value(const unsigned int q_point) const
4082{
4083 if constexpr (running_in_debug_mode())
4084 {
4085 Assert(this->values_quad_initialized == true,
4087 }
4088
4089 AssertIndexRange(q_point, this->n_quadrature_points);
4090 if constexpr (n_components == 1)
4091 return this->values_quad[q_point];
4092 else
4093 {
4094 if (n_components == dim &&
4095 this->data->element_type ==
4097 {
4098 // Piola transform is required
4099 if constexpr (running_in_debug_mode())
4100 {
4101 Assert(this->values_quad_initialized == true,
4103 }
4104
4105 AssertIndexRange(q_point, this->n_quadrature_points);
4106 Assert(this->J_value != nullptr,
4108 "update_values"));
4109 const std::size_t nqp = this->n_quadrature_points;
4111
4112 if (!is_face &&
4114 {
4115 // Cartesian cell
4116 const Tensor<2, dim, VectorizedArrayType> jac = this->jacobian[1];
4117 const VectorizedArrayType inv_det =
4118 (dim == 2) ? this->jacobian[0][0][0] * this->jacobian[0][1][1] :
4119 this->jacobian[0][0][0] * this->jacobian[0][1][1] *
4120 this->jacobian[0][2][2];
4121
4122 // J * u * det(J^-1)
4123 for (unsigned int comp = 0; comp < n_components; ++comp)
4124 value_out[comp] = this->values_quad[comp * nqp + q_point] *
4125 jac[comp][comp] * inv_det;
4126 }
4127 else
4128 {
4129 // Affine or general cell
4130 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
4131 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
4132 this->jacobian[q_point] :
4133 this->jacobian[0];
4135 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
4136 transpose(invert(inv_t_jac)) :
4137 this->jacobian[1];
4138
4139 // Derivatives are reordered for faces. Need to take this into
4140 // account
4141 const VectorizedArrayType inv_det =
4142 (is_face && dim == 2 && this->get_face_no() < 2) ?
4143 -determinant(inv_t_jac) :
4144 determinant(inv_t_jac);
4145 // J * u * det(J^-1)
4146 for (unsigned int comp = 0; comp < n_components; ++comp)
4147 {
4148 value_out[comp] = this->values_quad[q_point] * jac[comp][0];
4149 for (unsigned int e = 1; e < dim; ++e)
4150 value_out[comp] +=
4151 this->values_quad[e * nqp + q_point] * jac[comp][e];
4152 value_out[comp] *= inv_det;
4153 }
4154 }
4155 return value_out;
4156 }
4157 else if (n_components == dim &&
4158 this->data->element_type ==
4160 {
4161 // Piola transform is required
4162 if constexpr (running_in_debug_mode())
4163 {
4164 Assert(this->values_quad_initialized == true,
4166 }
4167
4168 AssertIndexRange(q_point, this->n_quadrature_points);
4169 Assert(this->J_value != nullptr,
4171 "update_values"));
4172 const std::size_t nqp = this->n_quadrature_points;
4174
4175 if (!is_face &&
4177 {
4178 // Cartesian cell
4179 const Tensor<2, dim, VectorizedArrayType> inv_transp_jac =
4180 this->jacobian[0];
4181
4182
4183 // J^{-T} * u
4184 for (unsigned int comp = 0; comp < n_components; ++comp)
4185 value_out[comp] = this->values_quad[comp * nqp + q_point] *
4186 inv_transp_jac[comp][comp];
4187 }
4188 else
4189 {
4190 // Affine or general cell
4191 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
4192 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
4193 this->jacobian[q_point] :
4194 this->jacobian[0];
4195
4196 // J^{-T} * u
4197 for (unsigned int comp = 0; comp < n_components; ++comp)
4198 {
4199 value_out[comp] =
4200 this->values_quad[q_point] * inv_t_jac[comp][0];
4201 for (unsigned int e = 1; e < dim; ++e)
4202 value_out[comp] +=
4203 this->values_quad[e * nqp + q_point] * inv_t_jac[comp][e];
4204 }
4205 }
4206 return value_out;
4207 }
4208 else
4209 {
4210 const std::size_t nqp = this->n_quadrature_points;
4212 for (unsigned int comp = 0; comp < n_components; ++comp)
4213 return_value[comp] = this->values_quad[comp * nqp + q_point];
4214 return return_value;
4215 }
4216 }
4217}
4218
4219
4220
4221template <int dim,
4222 int n_components_,
4223 typename Number,
4224 bool is_face,
4225 typename VectorizedArrayType>
4227 typename FEEvaluationBase<dim,
4228 n_components_,
4229 Number,
4230 is_face,
4231 VectorizedArrayType>::gradient_type
4233 get_gradient(const unsigned int q_point) const
4234{
4235 if constexpr (running_in_debug_mode())
4236 {
4237 Assert(this->gradients_quad_initialized == true,
4239 }
4240
4241 AssertIndexRange(q_point, this->n_quadrature_points);
4242 Assert(this->jacobian != nullptr,
4244 "update_gradients"));
4245 const std::size_t nqp = this->n_quadrature_points;
4246
4247 if constexpr (n_components == dim && dim > 1)
4248 {
4249 if (this->data->element_type ==
4251 {
4252 // Piola transform is required
4253 if constexpr (running_in_debug_mode())
4254 {
4255 Assert(this->gradients_quad_initialized == true,
4257 }
4258
4259 AssertIndexRange(q_point, this->n_quadrature_points);
4260 Assert(this->jacobian != nullptr,
4262 "update_gradients"));
4263 const std::size_t nqp = this->n_quadrature_points;
4264 const std::size_t nqp_d = nqp * dim;
4266 const VectorizedArrayType *gradients =
4267 this->gradients_quad + q_point * dim;
4268
4269
4270 if (!is_face &&
4272 {
4273 // Cartesian cell
4274 const Tensor<2, dim, VectorizedArrayType> &inv_t_jac =
4275 this->jacobian[0];
4277 this->jacobian[1];
4278 const VectorizedArrayType inv_det =
4279 (dim == 2) ? this->jacobian[0][0][0] * this->jacobian[0][1][1] :
4280 this->jacobian[0][0][0] * this->jacobian[0][1][1] *
4281 this->jacobian[0][2][2];
4282
4283 // J * grad_quad * J^-1 * det(J^-1)
4284 for (unsigned int d = 0; d < dim; ++d)
4285 for (unsigned int comp = 0; comp < n_components; ++comp)
4286 grad_out[comp][d] = gradients[comp * nqp_d + d] *
4287 inv_t_jac[d][d] *
4288 (jac[comp][comp] * inv_det);
4289 }
4290 else if (this->cell_type <= internal::MatrixFreeFunctions::affine)
4291 {
4292 // Affine cell
4293 const Tensor<2, dim, VectorizedArrayType> &inv_t_jac =
4294 this->jacobian[0];
4296 this->jacobian[1];
4297
4298 // Derivatives are reordered for faces. Need to take this into
4299 // account
4300 const VectorizedArrayType inv_det =
4301 (is_face && dim == 2 && this->get_face_no() < 2) ?
4302 -determinant(inv_t_jac) :
4303 determinant(inv_t_jac);
4304
4305 VectorizedArrayType tmp[dim][dim];
4306 // J * grad_quad * J^-1 * det(J^-1)
4307 for (unsigned int d = 0; d < dim; ++d)
4308 for (unsigned int e = 0; e < dim; ++e)
4309 {
4310 tmp[d][e] = inv_t_jac[d][0] * gradients[e * nqp_d + 0];
4311 for (unsigned int f = 1; f < dim; ++f)
4312 tmp[d][e] += inv_t_jac[d][f] * gradients[e * nqp_d + f];
4313 }
4314 for (unsigned int comp = 0; comp < n_components; ++comp)
4315 for (unsigned int d = 0; d < dim; ++d)
4316 {
4317 VectorizedArrayType res = jac[comp][0] * tmp[d][0];
4318 for (unsigned int f = 1; f < dim; ++f)
4319 res += jac[comp][f] * tmp[d][f];
4320
4321 grad_out[comp][d] = res * inv_det;
4322 }
4323 }
4324 else
4325 {
4326 // General cell
4327
4328 // This assert could be removed if we make sure that this is
4329 // updated even though update_hessians or update_jacobian_grads is
4330 // not passed, i.e make the necessary changes in
4331 // MatrixFreeFunctions::MappingInfoStorage::compute_update_flags
4332 Assert(this->jacobian_gradients_non_inverse != nullptr,
4334 "update_hessians"));
4335
4336 const auto jac_grad =
4337 this->jacobian_gradients_non_inverse[q_point];
4338 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
4339 this->jacobian[q_point];
4340
4341 // Derivatives are reordered for faces. Need to take this into
4342 // account
4343 const VectorizedArrayType inv_det =
4344 (is_face && dim == 2 && this->get_face_no() < 2) ?
4345 -determinant(inv_t_jac) :
4346 determinant(inv_t_jac);
4348 invert(inv_t_jac);
4349
4350 // (J * grad_quad) * J^-1 * det(J^-1), part in braces
4351 VectorizedArrayType tmp[dim][dim];
4352 for (unsigned int d = 0; d < dim; ++d)
4353 for (unsigned int e = 0; e < dim; ++e)
4354 {
4355 tmp[e][d] = t_jac[0][d] * gradients[0 * nqp_d + e];
4356 for (unsigned int f = 1; f < dim; ++f)
4357 tmp[e][d] += t_jac[f][d] * gradients[f * nqp_d + e];
4358 }
4359
4360 // Add (jac_grad * values) * J^{-1} * det(J^{-1}), combine terms
4361 // outside braces with gradient part from above
4362 for (unsigned int d = 0; d < dim; ++d)
4363 {
4364 for (unsigned int e = 0; e < dim; ++e)
4365 tmp[e][d] +=
4366 jac_grad[e][d] * this->values_quad[e * nqp + q_point];
4367 for (unsigned int f = 0, r = dim; f < dim; ++f)
4368 for (unsigned int k = f + 1; k < dim; ++k, ++r)
4369 {
4370 tmp[k][d] +=
4371 jac_grad[r][d] * this->values_quad[f * nqp + q_point];
4372 tmp[f][d] +=
4373 jac_grad[r][d] * this->values_quad[k * nqp + q_point];
4374 }
4375 }
4376
4377 // Apply J^{-1} appearing in both terms outside braces above
4378 for (unsigned int d = 0; d < dim; ++d)
4379 for (unsigned int e = 0; e < dim; ++e)
4380 {
4381 VectorizedArrayType res = tmp[0][d] * inv_t_jac[e][0];
4382 for (unsigned int f = 1; f < dim; ++f)
4383 res += tmp[f][d] * inv_t_jac[e][f];
4384 grad_out[d][e] = res;
4385 }
4386
4387 // Add -(J^{-T} * jac_grad * J^{-1} * J * values * det(J^{-1})),
4388 // which can be expressed as a rank-1 update tmp[d] * tmp4[e],
4389 // where tmp = J * values and tmp4 = (J^{-T} * jac_grad * J^{-1})
4390 VectorizedArrayType tmp3[dim], tmp4[dim];
4391 for (unsigned int d = 0; d < dim; ++d)
4392 {
4393 tmp3[d] = inv_t_jac[0][d] * jac_grad[d][0];
4394 for (unsigned int e = 1; e < dim; ++e)
4395 tmp3[d] += inv_t_jac[e][d] * jac_grad[d][e];
4396 }
4397 for (unsigned int e = 0, k = dim; e < dim; ++e)
4398 for (unsigned int f = e + 1; f < dim; ++k, ++f)
4399 for (unsigned int d = 0; d < dim; ++d)
4400 {
4401 tmp3[f] += inv_t_jac[d][e] * jac_grad[k][d];
4402 tmp3[e] += inv_t_jac[d][f] * jac_grad[k][d];
4403 }
4404 for (unsigned int d = 0; d < dim; ++d)
4405 {
4406 tmp4[d] = tmp3[0] * inv_t_jac[d][0];
4407 for (unsigned int e = 1; e < dim; ++e)
4408 tmp4[d] += tmp3[e] * inv_t_jac[d][e];
4409 }
4410
4411 VectorizedArrayType tmp2[dim];
4412 for (unsigned int d = 0; d < dim; ++d)
4413 {
4414 tmp2[d] = t_jac[0][d] * this->values_quad[q_point];
4415 for (unsigned e = 1; e < dim; ++e)
4416 tmp2[d] +=
4417 t_jac[e][d] * this->values_quad[e * nqp + q_point];
4418 }
4419
4420 for (unsigned int d = 0; d < dim; ++d)
4421 for (unsigned int e = 0; e < dim; ++e)
4422 {
4423 grad_out[d][e] -= tmp4[e] * tmp2[d];
4424
4425 // finally multiply by det(J^{-1}) necessary in all
4426 // contributions above
4427 grad_out[d][e] *= inv_det;
4428 }
4429 }
4430 return grad_out;
4431 }
4432 }
4434
4435 // Cartesian cell
4436 if (!is_face && this->cell_type == internal::MatrixFreeFunctions::cartesian)
4437 {
4438 for (unsigned int comp = 0; comp < n_components; ++comp)
4439 for (unsigned int d = 0; d < dim; ++d)
4440 grad_out[comp][d] =
4441 this->gradients_quad[(comp * nqp + q_point) * dim + d] *
4442 this->jacobian[0][d][d];
4443 }
4444 // cell with general/affine Jacobian
4445 else
4446 {
4448 this->jacobian[this->cell_type > internal::MatrixFreeFunctions::affine ?
4449 q_point :
4450 0];
4451 for (unsigned int comp = 0; comp < n_components; ++comp)
4452 for (unsigned int d = 0; d < dim; ++d)
4453 {
4454 grad_out[comp][d] =
4455 jac[d][0] * this->gradients_quad[(comp * nqp + q_point) * dim];
4456 for (unsigned int e = 1; e < dim; ++e)
4457 grad_out[comp][d] +=
4458 jac[d][e] *
4459 this->gradients_quad[(comp * nqp + q_point) * dim + e];
4460 }
4461 }
4462 if constexpr (n_components == 1)
4463 return grad_out[0];
4464 else
4465 return grad_out;
4466}
4467
4468
4469
4470template <int dim,
4471 int n_components_,
4472 typename Number,
4473 bool is_face,
4474 typename VectorizedArrayType>
4476 typename FEEvaluationBase<dim,
4477 n_components_,
4478 Number,
4479 is_face,
4480 VectorizedArrayType>::value_type
4482 get_normal_derivative(const unsigned int q_point) const
4483{
4484 AssertIndexRange(q_point, this->n_quadrature_points);
4485 if constexpr (running_in_debug_mode())
4486 {
4487 Assert(this->gradients_quad_initialized == true,
4489 }
4490
4491 Assert(this->normal_x_jacobian != nullptr,
4493 "update_gradients"));
4494
4495 const std::size_t nqp = this->n_quadrature_points;
4497
4498 if (this->cell_type == internal::MatrixFreeFunctions::cartesian)
4499 for (unsigned int comp = 0; comp < n_components; ++comp)
4500 grad_out[comp] =
4501 this->gradients_quad[(comp * nqp + q_point) * dim + dim - 1] *
4502 (this->normal_x_jacobian[0][dim - 1]);
4503 else
4504 {
4505 const std::size_t index =
4506 this->cell_type <= internal::MatrixFreeFunctions::affine ? 0 : q_point;
4507 for (unsigned int comp = 0; comp < n_components; ++comp)
4508 {
4509 grad_out[comp] = this->gradients_quad[(comp * nqp + q_point) * dim] *
4510 this->normal_x_jacobian[index][0];
4511 for (unsigned int d = 1; d < dim; ++d)
4512 grad_out[comp] +=
4513 this->gradients_quad[(comp * nqp + q_point) * dim + d] *
4514 this->normal_x_jacobian[index][d];
4515 }
4516 }
4517 if constexpr (n_components == 1)
4518 return grad_out[0];
4519 else
4520 return grad_out;
4521}
4522
4523
4524
4525namespace internal
4526{
4527 // compute tmp = hess_unit(u) * J^T. do this manually because we do not
4528 // store the lower diagonal because of symmetry
4529 template <typename VectorizedArrayType>
4530 inline void
4531 hessian_unit_times_jac(const Tensor<2, 1, VectorizedArrayType> &jac,
4532 const VectorizedArrayType *const hessians,
4533 const unsigned int,
4534 VectorizedArrayType (&tmp)[1][1])
4535 {
4536 tmp[0][0] = jac[0][0] * hessians[0];
4537 }
4538
4539 template <typename VectorizedArrayType>
4540 inline void
4541 hessian_unit_times_jac(const Tensor<2, 2, VectorizedArrayType> &jac,
4542 const VectorizedArrayType *const hessians,
4543 const unsigned int nqp,
4544 VectorizedArrayType (&tmp)[2][2])
4545 {
4546 for (unsigned int d = 0; d < 2; ++d)
4547 {
4548 tmp[0][d] = (jac[d][0] * hessians[0] + jac[d][1] * hessians[2 * nqp]);
4549 tmp[1][d] =
4550 (jac[d][0] * hessians[2 * nqp] + jac[d][1] * hessians[1 * nqp]);
4551 }
4552 }
4553
4554 template <typename VectorizedArrayType>
4555 inline void
4556 hessian_unit_times_jac(const Tensor<2, 3, VectorizedArrayType> &jac,
4557 const VectorizedArrayType *const hessians,
4558 const unsigned int nqp,
4559 VectorizedArrayType (&tmp)[3][3])
4560 {
4561 for (unsigned int d = 0; d < 3; ++d)
4562 {
4563 tmp[0][d] =
4564 (jac[d][0] * hessians[0 * nqp] + jac[d][1] * hessians[3 * nqp] +
4565 jac[d][2] * hessians[4 * nqp]);
4566 tmp[1][d] =
4567 (jac[d][0] * hessians[3 * nqp] + jac[d][1] * hessians[1 * nqp] +
4568 jac[d][2] * hessians[5 * nqp]);
4569 tmp[2][d] =
4570 (jac[d][0] * hessians[4 * nqp] + jac[d][1] * hessians[5 * nqp] +
4571 jac[d][2] * hessians[2 * nqp]);
4572 }
4573 }
4574} // namespace internal
4575
4576
4577
4578template <int dim,
4579 int n_components_,
4580 typename Number,
4581 bool is_face,
4582 typename VectorizedArrayType>
4583inline typename FEEvaluationBase<dim,
4584 n_components_,
4585 Number,
4586 is_face,
4587 VectorizedArrayType>::hessian_type
4589 get_hessian(const unsigned int q_point) const
4590{
4591 if constexpr (running_in_debug_mode())
4592 {
4593 Assert(this->hessians_quad_initialized == true,
4595 }
4596 AssertIndexRange(q_point, this->n_quadrature_points);
4597
4598 Assert(this->jacobian != nullptr,
4600 "update_hessian"));
4602 this->jacobian[this->cell_type <= internal::MatrixFreeFunctions::affine ?
4603 0 :
4604 q_point];
4605
4607
4608 const std::size_t nqp = this->n_quadrature_points;
4609 constexpr unsigned int hdim = (dim * (dim + 1)) / 2;
4610
4611 // Cartesian cell
4612 if (!is_face && this->cell_type == internal::MatrixFreeFunctions::cartesian)
4613 {
4614 for (unsigned int comp = 0; comp < n_components; ++comp)
4615 {
4616 for (unsigned int d = 0; d < dim; ++d)
4617 hessian_out[comp][d][d] =
4618 this->hessians_quad[(comp * hdim + d) * nqp + q_point] *
4619 (jac[d][d] * jac[d][d]);
4620 switch (dim)
4621 {
4622 case 1:
4623 break;
4624 case 2:
4625 hessian_out[comp][0][1] =
4626 this->hessians_quad[(comp * hdim + 2) * nqp + q_point] *
4627 (jac[0][0] * jac[1][1]);
4628 break;
4629 case 3:
4630 hessian_out[comp][0][1] =
4631 this->hessians_quad[(comp * hdim + 3) * nqp + q_point] *
4632 (jac[0][0] * jac[1][1]);
4633 hessian_out[comp][0][2] =
4634 this->hessians_quad[(comp * hdim + 4) * nqp + q_point] *
4635 (jac[0][0] * jac[2][2]);
4636 hessian_out[comp][1][2] =
4637 this->hessians_quad[(comp * hdim + 5) * nqp + q_point] *
4638 (jac[1][1] * jac[2][2]);
4639 break;
4640 default:
4642 }
4643 for (unsigned int d = 0; d < dim; ++d)
4644 for (unsigned int e = d + 1; e < dim; ++e)
4645 hessian_out[comp][e][d] = hessian_out[comp][d][e];
4646 }
4647 }
4648 // cell with general Jacobian, but constant within the cell
4649 else if (this->cell_type <= internal::MatrixFreeFunctions::affine)
4650 {
4651 for (unsigned int comp = 0; comp < n_components; ++comp)
4652 {
4653 VectorizedArrayType tmp[dim][dim];
4654 internal::hessian_unit_times_jac(
4655 jac, this->hessians_quad + comp * hdim * nqp + q_point, nqp, tmp);
4656
4657 // compute first part of hessian, J * tmp = J * hess_unit(u) * J^T
4658 for (unsigned int d = 0; d < dim; ++d)
4659 for (unsigned int e = d; e < dim; ++e)
4660 {
4661 hessian_out[comp][d][e] = jac[d][0] * tmp[0][e];
4662 for (unsigned int f = 1; f < dim; ++f)
4663 hessian_out[comp][d][e] += jac[d][f] * tmp[f][e];
4664 }
4665
4666 // no J' * grad(u) part here because the Jacobian is constant
4667 // throughout the cell and hence, its derivative is zero
4668
4669 // take symmetric part
4670 for (unsigned int d = 0; d < dim; ++d)
4671 for (unsigned int e = d + 1; e < dim; ++e)
4672 hessian_out[comp][e][d] = hessian_out[comp][d][e];
4673 }
4674 }
4675 // cell with general Jacobian
4676 else
4677 {
4678 const auto &jac_grad = this->jacobian_gradients[q_point];
4679 for (unsigned int comp = 0; comp < n_components; ++comp)
4680 {
4681 VectorizedArrayType tmp[dim][dim];
4682 internal::hessian_unit_times_jac(
4683 jac, this->hessians_quad + comp * hdim * nqp + q_point, nqp, tmp);
4684
4685 // compute first part of hessian, J * tmp = J * hess_unit(u) * J^T
4686 for (unsigned int d = 0; d < dim; ++d)
4687 for (unsigned int e = d; e < dim; ++e)
4688 {
4689 hessian_out[comp][d][e] = jac[d][0] * tmp[0][e];
4690 for (unsigned int f = 1; f < dim; ++f)
4691 hessian_out[comp][d][e] += jac[d][f] * tmp[f][e];
4692 }
4693
4694 // add diagonal part of J' * grad(u)
4695 for (unsigned int d = 0; d < dim; ++d)
4696 for (unsigned int e = 0; e < dim; ++e)
4697 hessian_out[comp][d][d] +=
4698 jac_grad[d][e] *
4699 this->gradients_quad[(comp * nqp + q_point) * dim + e];
4700
4701 // add off-diagonal part of J' * grad(u)
4702 for (unsigned int d = 0, count = dim; d < dim; ++d)
4703 for (unsigned int e = d + 1; e < dim; ++e, ++count)
4704 for (unsigned int f = 0; f < dim; ++f)
4705 hessian_out[comp][d][e] +=
4706 jac_grad[count][f] *
4707 this->gradients_quad[(comp * nqp + q_point) * dim + f];
4708
4709 // take symmetric part
4710 for (unsigned int d = 0; d < dim; ++d)
4711 for (unsigned int e = d + 1; e < dim; ++e)
4712 hessian_out[comp][e][d] = hessian_out[comp][d][e];
4713 }
4714 }
4715 if constexpr (n_components == 1)
4716 return hessian_out[0];
4717 else
4718 return hessian_out;
4719}
4720
4721
4722
4723template <int dim,
4724 int n_components_,
4725 typename Number,
4726 bool is_face,
4727 typename VectorizedArrayType>
4728inline typename FEEvaluationBase<dim,
4729 n_components_,
4730 Number,
4731 is_face,
4732 VectorizedArrayType>::gradient_type
4734 get_hessian_diagonal(const unsigned int q_point) const
4735{
4736 Assert(!is_face, ExcNotImplemented());
4737 if constexpr (running_in_debug_mode())
4738 {
4739 Assert(this->hessians_quad_initialized == true,
4741 }
4742 AssertIndexRange(q_point, this->n_quadrature_points);
4743
4744 Assert(this->jacobian != nullptr, ExcNotImplemented());
4746 this->jacobian[this->cell_type <= internal::MatrixFreeFunctions::affine ?
4747 0 :
4748 q_point];
4749
4750 const std::size_t nqp = this->n_quadrature_points;
4751 constexpr unsigned int hdim = (dim * (dim + 1)) / 2;
4753
4754 // Cartesian cell
4755 if (this->cell_type == internal::MatrixFreeFunctions::cartesian)
4756 {
4757 for (unsigned int comp = 0; comp < n_components; ++comp)
4758 for (unsigned int d = 0; d < dim; ++d)
4759 hessian_out[comp][d] =
4760 this->hessians_quad[(comp * hdim + d) * nqp + q_point] *
4761 (jac[d][d] * jac[d][d]);
4762 }
4763 // cell with general Jacobian, but constant within the cell
4764 else if (this->cell_type == internal::MatrixFreeFunctions::affine)
4765 {
4766 for (unsigned int comp = 0; comp < n_components; ++comp)
4767 {
4768 // compute laplacian before the gradient because it needs to access
4769 // unscaled gradient data
4770 VectorizedArrayType tmp[dim][dim];
4771 internal::hessian_unit_times_jac(
4772 jac, this->hessians_quad + comp * hdim * nqp + q_point, nqp, tmp);
4773
4774 // compute only the trace part of hessian, J * tmp = J *
4775 // hess_unit(u) * J^T
4776 for (unsigned int d = 0; d < dim; ++d)
4777 {
4778 hessian_out[comp][d] = jac[d][0] * tmp[0][d];
4779 for (unsigned int f = 1; f < dim; ++f)
4780 hessian_out[comp][d] += jac[d][f] * tmp[f][d];
4781 }
4782 }
4783 }
4784 // cell with general Jacobian
4785 else
4786 {
4787 const auto &jac_grad = this->jacobian_gradients[q_point];
4788 for (unsigned int comp = 0; comp < n_components; ++comp)
4789 {
4790 // compute laplacian before the gradient because it needs to access
4791 // unscaled gradient data
4792 VectorizedArrayType tmp[dim][dim];
4793 internal::hessian_unit_times_jac(
4794 jac, this->hessians_quad + comp * hdim * nqp + q_point, nqp, tmp);
4795
4796 // compute only the trace part of hessian, J * tmp = J *
4797 // hess_unit(u) * J^T
4798 for (unsigned int d = 0; d < dim; ++d)
4799 {
4800 hessian_out[comp][d] = jac[d][0] * tmp[0][d];
4801 for (unsigned int f = 1; f < dim; ++f)
4802 hessian_out[comp][d] += jac[d][f] * tmp[f][d];
4803 }
4804
4805 for (unsigned int d = 0; d < dim; ++d)
4806 for (unsigned int e = 0; e < dim; ++e)
4807 hessian_out[comp][d] +=
4808 jac_grad[d][e] *
4809 this->gradients_quad[(comp * nqp + q_point) * dim + e];
4810 }
4811 }
4812
4813 if constexpr (n_components == 1)
4814 return hessian_out[0];
4815 else
4816 return hessian_out;
4817}
4818
4819
4820
4821template <int dim,
4822 int n_components_,
4823 typename Number,
4824 bool is_face,
4825 typename VectorizedArrayType>
4826inline typename FEEvaluationBase<dim,
4827 n_components_,
4828 Number,
4829 is_face,
4830 VectorizedArrayType>::value_type
4832 get_laplacian(const unsigned int q_point) const
4833{
4834 Assert(is_face == false, ExcNotImplemented());
4835 if constexpr (running_in_debug_mode())
4836 {
4837 Assert(this->hessians_quad_initialized == true,
4839 }
4840 AssertIndexRange(q_point, this->n_quadrature_points);
4841
4842 const gradient_type hess_diag = get_hessian_diagonal(q_point);
4843 if constexpr (n_components == 1)
4844 {
4845 VectorizedArrayType sum = hess_diag[0];
4846 for (unsigned int d = 1; d < dim; ++d)
4847 sum += hess_diag[d];
4848 return sum;
4849 }
4850 else
4851 {
4853 for (unsigned int comp = 0; comp < n_components; ++comp)
4854 {
4855 laplacian_out[comp] = hess_diag[comp][0];
4856 for (unsigned int d = 1; d < dim; ++d)
4857 laplacian_out[comp] += hess_diag[comp][d];
4858 }
4859 return laplacian_out;
4860 }
4861}
4862
4863
4864
4865template <int dim,
4866 int n_components_,
4867 typename Number,
4868 bool is_face,
4869 typename VectorizedArrayType>
4870inline typename FEEvaluationBase<dim,
4871 n_components_,
4872 Number,
4873 is_face,
4874 VectorizedArrayType>::value_type
4876 get_normal_hessian(const unsigned int q_point) const
4877{
4878 if constexpr (running_in_debug_mode())
4879 {
4880 Assert(this->hessians_quad_initialized == true,
4882 }
4883 AssertIndexRange(q_point, this->n_quadrature_points);
4884
4885 Assert(this->normal_x_jacobian != nullptr,
4887 "update_hessians"));
4888
4890
4891 const std::size_t nqp = this->n_quadrature_points;
4892 constexpr unsigned int hdim = (dim * (dim + 1)) / 2;
4893
4894 if (this->cell_type <= internal::MatrixFreeFunctions::affine)
4895 {
4896 const auto nxj = this->normal_x_jacobian[0];
4897
4898 for (unsigned int comp = 0; comp < n_components; ++comp)
4899 {
4900 for (unsigned int d = 0; d < dim; ++d)
4901 hessian_out[comp] +=
4902 this->hessians_quad[(comp * hdim + d) * nqp + q_point] *
4903 (nxj[d]) * (nxj[d]);
4904
4905 switch (dim)
4906 {
4907 case 1:
4908 break;
4909 case 2:
4910 hessian_out[comp] +=
4911 this->hessians_quad[(comp * hdim + 2) * nqp + q_point] *
4912 (nxj[0] * nxj[1]);
4913 break;
4914 case 3:
4915 hessian_out[comp] +=
4916 2. * this->hessians_quad[(comp * hdim + 3) * nqp + q_point] *
4917 (nxj[0] * nxj[1]);
4918 hessian_out[comp] +=
4919 2. * this->hessians_quad[(comp * hdim + 4) * nqp + q_point] *
4920 (nxj[0] * nxj[2]);
4921 hessian_out[comp] +=
4922 2. * this->hessians_quad[(comp * hdim + 5) * nqp + q_point] *
4923 (nxj[1] * nxj[2]);
4924 break;
4925 default:
4927 }
4928 }
4929 }
4930 // cell with general Jacobian
4931 else
4932 {
4933 const auto normal = this->normal_vector(q_point);
4934 const auto hessian = get_hessian(q_point);
4935
4936 if constexpr (n_components == 1)
4937 hessian_out[0] = hessian * normal * normal;
4938 else
4939 for (unsigned int comp = 0; comp < n_components; ++comp)
4940 hessian_out[comp] = hessian[comp] * normal * normal;
4941 }
4942 if constexpr (n_components == 1)
4943 return hessian_out[0];
4944 else
4945 return hessian_out;
4946}
4947
4948
4949
4950template <int dim,
4951 int n_components_,
4952 typename Number,
4953 bool is_face,
4954 typename VectorizedArrayType>
4955inline DEAL_II_ALWAYS_INLINE void
4957 submit_dof_value(const value_type val_in, const unsigned int dof)
4958{
4959 if constexpr (running_in_debug_mode())
4960 {
4961 this->dof_values_initialized = true;
4962 }
4963 const std::size_t dofs = this->data->dofs_per_component_on_cell;
4964 AssertIndexRange(dof, this->data->dofs_per_component_on_cell);
4965 for (unsigned int comp = 0; comp < n_components; ++comp)
4966 if constexpr (n_components == 1)
4967 this->values_dofs[comp * dofs + dof] = val_in;
4968 else
4969 this->values_dofs[comp * dofs + dof] = val_in[comp];
4970}
4971
4972
4973
4974template <int dim,
4975 int n_components_,
4976 typename Number,
4977 bool is_face,
4978 typename VectorizedArrayType>
4979inline DEAL_II_ALWAYS_INLINE void
4981 submit_value(const value_type val_in, const unsigned int q_point)
4982{
4983 if constexpr (running_in_debug_mode())
4984 {
4985 Assert(this->is_reinitialized, ExcNotInitialized());
4986 }
4987 AssertIndexRange(q_point, this->n_quadrature_points);
4988 Assert(this->J_value != nullptr,
4990 "update_values"));
4991 if constexpr (running_in_debug_mode())
4992 {
4993 this->values_quad_submitted = true;
4994 }
4995
4996 const std::size_t nqp = this->n_quadrature_points;
4997 VectorizedArrayType *values = this->values_quad + q_point;
4998
4999 const VectorizedArrayType JxW =
5000 this->cell_type <= internal::MatrixFreeFunctions::affine ?
5001 this->J_value[0] * this->quadrature_weights[q_point] :
5002 this->J_value[q_point];
5003 if constexpr (n_components == 1)
5004 values[0] = val_in * JxW;
5005 else
5006 {
5007 if (n_components == dim &&
5008 this->data->element_type ==
5010 {
5011 // Piola transform is required
5012 AssertIndexRange(q_point, this->n_quadrature_points);
5013 Assert(this->J_value != nullptr,
5015 "update_value"));
5016 if constexpr (running_in_debug_mode())
5017 {
5018 Assert(this->is_reinitialized, ExcNotInitialized());
5019 this->values_quad_submitted = true;
5020 }
5021
5022 VectorizedArrayType *values = this->values_quad + q_point;
5023 const std::size_t nqp = this->n_quadrature_points;
5024
5025 if (!is_face &&
5027 {
5028 const Tensor<2, dim, VectorizedArrayType> jac = this->jacobian[1];
5029 const VectorizedArrayType weight =
5030 this->quadrature_weights[q_point];
5031
5032 for (unsigned int comp = 0; comp < n_components; ++comp)
5033 values[comp * nqp] = val_in[comp] * weight * jac[comp][comp];
5034 }
5035 else
5036 {
5037 // Affine or general cell
5038 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
5039 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
5040 this->jacobian[q_point] :
5041 this->jacobian[0];
5042
5043 // Derivatives are reordered for faces. Need to take this into
5044 // account and 1/inv_det != J_value for faces
5045 const VectorizedArrayType fac =
5046 (!is_face) ?
5047 this->quadrature_weights[q_point] :
5048 (((this->cell_type > internal::MatrixFreeFunctions::affine) ?
5049 this->J_value[q_point] :
5050 this->J_value[0] * this->quadrature_weights[q_point]) *
5051 ((dim == 2 && this->get_face_no() < 2) ?
5052 -determinant(inv_t_jac) :
5053 determinant(inv_t_jac)));
5055 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
5056 transpose(invert(inv_t_jac)) :
5057 this->jacobian[1];
5058
5059 // J^T * u * factor
5060 for (unsigned int comp = 0; comp < n_components; ++comp)
5061 {
5062 values[comp * nqp] = val_in[0] * jac[0][comp];
5063 for (unsigned int e = 1; e < dim; ++e)
5064 values[comp * nqp] += val_in[e] * jac[e][comp];
5065 values[comp * nqp] *= fac;
5066 }
5067 }
5068 }
5069 else if (n_components == dim &&
5070 this->data->element_type ==
5072 {
5073 // Piola transform is required
5074 AssertIndexRange(q_point, this->n_quadrature_points);
5075 Assert(this->J_value != nullptr,
5077 "update_value"));
5078 if constexpr (running_in_debug_mode())
5079 {
5080 Assert(this->is_reinitialized, ExcNotInitialized());
5081 this->values_quad_submitted = true;
5082 }
5083
5084 VectorizedArrayType *values = this->values_quad + q_point;
5085 const std::size_t nqp = this->n_quadrature_points;
5086
5087 if (!is_face &&
5089 {
5090 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
5091 this->jacobian[0];
5092 const VectorizedArrayType det_jac =
5093 (dim == 2) ? this->jacobian[1][0][0] * this->jacobian[1][1][1] :
5094 this->jacobian[1][0][0] * this->jacobian[1][1][1] *
5095 this->jacobian[1][2][2];
5096
5097 const VectorizedArrayType weight =
5098 this->quadrature_weights[q_point];
5099
5100 // J^{-1} * u * det(J) * weight
5101 for (unsigned int comp = 0; comp < n_components; ++comp)
5102 values[comp * nqp] =
5103 val_in[comp] * weight * inv_t_jac[comp][comp] * det_jac;
5104 }
5105 else
5106 {
5107 // Affine or general cell
5108 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
5109 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
5110 this->jacobian[q_point] :
5111 this->jacobian[0];
5112
5113 const VectorizedArrayType fac =
5114 ((this->cell_type > internal::MatrixFreeFunctions::affine) ?
5115 this->J_value[q_point] :
5116 this->J_value[0] * this->quadrature_weights[q_point]);
5117
5118 // J^{-1} * u * factor
5119 for (unsigned int comp = 0; comp < n_components; ++comp)
5120 {
5121 values[comp * nqp] = val_in[0] * inv_t_jac[0][comp];
5122 for (unsigned int e = 1; e < dim; ++e)
5123 values[comp * nqp] += val_in[e] * inv_t_jac[e][comp];
5124 values[comp * nqp] *= fac;
5125 }
5126 }
5127 }
5128 else
5129 for (unsigned int comp = 0; comp < n_components; ++comp)
5130 values[comp * nqp] = val_in[comp] * JxW;
5131 }
5132}
5133
5134
5135
5136template <int dim,
5137 int n_components_,
5138 typename Number,
5139 bool is_face,
5140 typename VectorizedArrayType>
5141template <int, typename>
5142inline DEAL_II_ALWAYS_INLINE void
5145 const unsigned int q_point)
5146{
5147 static_assert(n_components == 1,
5148 "Do not try to modify the default template parameters used for"
5149 " selectively enabling this function via std::enable_if!");
5150 submit_value(val_in[0], q_point);
5151}
5152
5153
5154
5155template <int dim,
5156 int n_components_,
5157 typename Number,
5158 bool is_face,
5159 typename VectorizedArrayType>
5160inline DEAL_II_ALWAYS_INLINE void
5162 submit_gradient(const gradient_type grad_in, const unsigned int q_point)
5163{
5164 if constexpr (running_in_debug_mode())
5165 {
5166 Assert(this->is_reinitialized, ExcNotInitialized());
5167 }
5168 AssertIndexRange(q_point, this->n_quadrature_points);
5169 Assert(this->J_value != nullptr,
5171 "update_gradients"));
5172 Assert(this->jacobian != nullptr,
5174 "update_gradients"));
5175 if constexpr (running_in_debug_mode())
5176 {
5177 this->gradients_quad_submitted = true;
5178 }
5179
5180 if constexpr (dim > 1 && n_components == dim)
5181 {
5182 if (this->data->element_type ==
5184 {
5185 // Piola transform is required
5186
5187 if constexpr (running_in_debug_mode())
5188 {
5189 Assert(this->is_reinitialized, ExcNotInitialized());
5190 }
5191 AssertIndexRange(q_point, this->n_quadrature_points);
5192 Assert(this->J_value != nullptr,
5194 "update_gradients"));
5195 Assert(this->jacobian != nullptr,
5197 "update_gradients"));
5198 if constexpr (running_in_debug_mode())
5199 {
5200 this->gradients_quad_submitted = true;
5201 }
5202
5203 VectorizedArrayType *gradients = this->gradients_quad + q_point * dim;
5204 VectorizedArrayType *values =
5205 this->values_from_gradients_quad + q_point;
5206 const std::size_t nqp = this->n_quadrature_points;
5207 const std::size_t nqp_d = nqp * dim;
5208
5209 if (!is_face &&
5211 {
5212 // Cartesian cell
5213 const Tensor<2, dim, VectorizedArrayType> &inv_t_jac =
5214 this->jacobian[0];
5216 this->jacobian[1];
5217 const VectorizedArrayType weight =
5218 this->quadrature_weights[q_point];
5219 for (unsigned int d = 0; d < dim; ++d)
5220 for (unsigned int comp = 0; comp < n_components; ++comp)
5221 gradients[comp * nqp_d + d] = grad_in[comp][d] *
5222 inv_t_jac[d][d] *
5223 (jac[comp][comp] * weight);
5224 }
5225 else if (this->cell_type <= internal::MatrixFreeFunctions::affine)
5226 {
5227 // Affine cell
5228 const Tensor<2, dim, VectorizedArrayType> &inv_t_jac =
5229 this->jacobian[0];
5231 this->jacobian[1];
5232
5233 // Derivatives are reordered for faces. Need to take this into
5234 // account and 1/inv_det != J_value for faces
5235 const VectorizedArrayType fac =
5236 (!is_face) ?
5237 this->quadrature_weights[q_point] :
5238 this->J_value[0] * this->quadrature_weights[q_point] *
5239 ((dim == 2 && this->get_face_no() < 2) ?
5240 -determinant(inv_t_jac) :
5241 determinant(inv_t_jac));
5242
5243 // J_{j,i} * J^{-1}_{k,m} * grad_in_{j,m} * factor
5244 VectorizedArrayType tmp[dim][dim];
5245 for (unsigned int d = 0; d < dim; ++d)
5246 for (unsigned int e = 0; e < dim; ++e)
5247 {
5248 tmp[d][e] = inv_t_jac[0][d] * grad_in[e][0];
5249 for (unsigned int f = 1; f < dim; ++f)
5250 tmp[d][e] += inv_t_jac[f][d] * grad_in[e][f];
5251 }
5252 for (unsigned int comp = 0; comp < n_components; ++comp)
5253 for (unsigned int d = 0; d < dim; ++d)
5254 {
5255 VectorizedArrayType res = jac[0][comp] * tmp[d][0];
5256 for (unsigned int f = 1; f < dim; ++f)
5257 res += jac[f][comp] * tmp[d][f];
5258
5259 gradients[comp * nqp_d + d] = res * fac;
5260 }
5261 }
5262 else
5263 {
5264 // General cell
5265
5266 const auto jac_grad =
5267 this->jacobian_gradients_non_inverse[q_point];
5268 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
5269 this->jacobian[q_point];
5270
5271 // Derivatives are reordered for faces. Need to take this into
5272 // account and 1/inv_det != J_value for faces
5273 const VectorizedArrayType fac =
5274 (!is_face) ? this->quadrature_weights[q_point] :
5275 this->J_value[q_point] *
5276 ((dim == 2 && this->get_face_no() < 2) ?
5277 -determinant(inv_t_jac) :
5278 determinant(inv_t_jac));
5280 invert(inv_t_jac);
5281
5282 // Start evaluation for values part below to enable the compiler
5283 // to possibly re-use the same computation in get_gradient()
5284 // without interfering with stores to 'gradients'
5285 VectorizedArrayType tmp3[dim], tmp4[dim];
5286 for (unsigned int d = 0; d < dim; ++d)
5287 {
5288 tmp3[d] = inv_t_jac[0][d] * jac_grad[d][0];
5289 for (unsigned int e = 1; e < dim; ++e)
5290 tmp3[d] += inv_t_jac[e][d] * jac_grad[d][e];
5291 }
5292 for (unsigned int e = 0, k = dim; e < dim; ++e)
5293 for (unsigned int f = e + 1; f < dim; ++k, ++f)
5294 for (unsigned int d = 0; d < dim; ++d)
5295 {
5296 tmp3[f] += inv_t_jac[d][e] * jac_grad[k][d];
5297 tmp3[e] += inv_t_jac[d][f] * jac_grad[k][d];
5298 }
5299 for (unsigned int d = 0; d < dim; ++d)
5300 {
5301 tmp4[d] = tmp3[0] * inv_t_jac[d][0];
5302 for (unsigned int e = 1; e < dim; ++e)
5303 tmp4[d] += tmp3[e] * inv_t_jac[d][e];
5304 }
5305
5306 const Tensor<2, dim, VectorizedArrayType> grad_in_scaled =
5307 fac * grad_in;
5308
5309 VectorizedArrayType tmp[dim][dim];
5310
5311 // J * (J^{-1} * (grad_in * factor))
5312 for (unsigned int d = 0; d < dim; ++d)
5313 for (unsigned int e = 0; e < dim; ++e)
5314 {
5315 tmp[d][e] = inv_t_jac[0][d] * grad_in_scaled[e][0];
5316 for (unsigned int f = 1; f < dim; ++f)
5317 tmp[d][e] += inv_t_jac[f][d] * grad_in_scaled[e][f];
5318 }
5319
5320 for (unsigned int d = 0; d < dim; ++d)
5321 for (unsigned int e = 0; e < dim; ++e)
5322 {
5323 VectorizedArrayType res = t_jac[d][0] * tmp[e][0];
5324 for (unsigned int f = 1; f < dim; ++f)
5325 res += t_jac[d][f] * tmp[e][f];
5326
5327 gradients[d * nqp_d + e] = res;
5328 }
5329
5330 // jac_grad * (J^{-1} * (grad_in * factor)), re-use part in braces
5331 // as 'tmp' from above
5332 VectorizedArrayType value[dim];
5333 for (unsigned int d = 0; d < dim; ++d)
5334 {
5335 value[d] = tmp[d][0] * jac_grad[d][0];
5336 for (unsigned int e = 1; e < dim; ++e)
5337 value[d] += tmp[d][e] * jac_grad[d][e];
5338 }
5339 for (unsigned int e = 0, k = dim; e < dim; ++e)
5340 for (unsigned int f = e + 1; f < dim; ++k, ++f)
5341 for (unsigned int d = 0; d < dim; ++d)
5342 {
5343 value[e] += tmp[f][d] * jac_grad[k][d];
5344 value[f] += tmp[e][d] * jac_grad[k][d];
5345 }
5346
5347 // -(grad_in * factor) * J * (J^{-T} * jac_grad * J^{-1})
5348 // = -(grad_in * factor) * J * ( \------- tmp4 ---------/ )
5349 for (unsigned int d = 0; d < dim; ++d)
5350 {
5351 VectorizedArrayType tmp2 = grad_in_scaled[d][0] * tmp4[0];
5352 for (unsigned int e = 1; e < dim; ++e)
5353 tmp2 += grad_in_scaled[d][e] * tmp4[e];
5354 for (unsigned int e = 0; e < dim; ++e)
5355 value[e] -= t_jac[e][d] * tmp2;
5356 }
5357
5358 for (unsigned int d = 0; d < dim; ++d)
5359 values[d * nqp] = value[d];
5360 }
5361 return;
5362 }
5363 }
5364
5365 const std::size_t nqp_d = this->n_quadrature_points * dim;
5366 VectorizedArrayType *gradients = this->gradients_quad + q_point * dim;
5367
5368 if (!is_face && this->cell_type == internal::MatrixFreeFunctions::cartesian)
5369 {
5370 const VectorizedArrayType JxW =
5371 this->J_value[0] * this->quadrature_weights[q_point];
5372
5373 // Load all entries before starting to write back to make sure the
5374 // compiler sees opportunity of loads in a possibly nearby
5375 // get_gradient() function (i.e., the compiler should not think that
5376 // 'jacobian' could alias with 'gradients').
5377 std::array<VectorizedArrayType, dim> jac;
5378 for (unsigned int d = 0; d < dim; ++d)
5379 jac[d] = this->jacobian[0][d][d];
5380
5381 for (unsigned int d = 0; d < dim; ++d)
5382 {
5383 const VectorizedArrayType factor = this->jacobian[0][d][d] * JxW;
5384 if constexpr (n_components == 1)
5385 gradients[d] = grad_in[d] * factor;
5386 else
5387 for (unsigned int comp = 0; comp < n_components; ++comp)
5388 gradients[comp * nqp_d + d] = grad_in[comp][d] * factor;
5389 }
5390 }
5391 else
5392 {
5394 this->cell_type > internal::MatrixFreeFunctions::affine ?
5395 this->jacobian[q_point] :
5396 this->jacobian[0];
5397 const VectorizedArrayType JxW =
5398 this->cell_type > internal::MatrixFreeFunctions::affine ?
5399 this->J_value[q_point] :
5400 this->J_value[0] * this->quadrature_weights[q_point];
5401 if constexpr (n_components == 1)
5402 for (unsigned int d = 0; d < dim; ++d)
5403 {
5404 VectorizedArrayType new_val = jac[0][d] * grad_in[0];
5405 for (unsigned int e = 1; e < dim; ++e)
5406 new_val += (jac[e][d] * grad_in[e]);
5407 gradients[d] = new_val * JxW;
5408 }
5409 else
5410 for (unsigned int comp = 0; comp < n_components; ++comp)
5411 for (unsigned int d = 0; d < dim; ++d)
5412 {
5413 VectorizedArrayType new_val = jac[0][d] * grad_in[comp][0];
5414 for (unsigned int e = 1; e < dim; ++e)
5415 new_val += (jac[e][d] * grad_in[comp][e]);
5416 gradients[comp * nqp_d + d] = new_val * JxW;
5417 }
5418 }
5419}
5420
5421
5422
5423template <int dim,
5424 int n_components_,
5425 typename Number,
5426 bool is_face,
5427 typename VectorizedArrayType>
5428template <int, typename>
5429inline DEAL_II_ALWAYS_INLINE void
5432 const unsigned int q_point)
5433{
5434 static_assert(n_components == 1 && dim == 1,
5435 "Do not try to modify the default template parameters used for"
5436 " selectively enabling this function via std::enable_if!");
5437 submit_gradient(grad_in[0], q_point);
5438}
5439
5440
5441
5442template <int dim,
5443 int n_components_,
5444 typename Number,
5445 bool is_face,
5446 typename VectorizedArrayType>
5447inline DEAL_II_ALWAYS_INLINE void
5449 submit_normal_derivative(const value_type grad_in, const unsigned int q_point)
5450{
5451 AssertIndexRange(q_point, this->n_quadrature_points);
5452 Assert(this->normal_x_jacobian != nullptr,
5454 "update_gradients"));
5455 if constexpr (running_in_debug_mode())
5456 {
5457 this->gradients_quad_submitted = true;
5458 }
5459
5460 const std::size_t nqp_d = this->n_quadrature_points * dim;
5461 VectorizedArrayType *gradients = this->gradients_quad + q_point * dim;
5462
5463 if (this->cell_type == internal::MatrixFreeFunctions::cartesian)
5464 {
5465 const VectorizedArrayType JxW_jac = this->J_value[0] *
5466 this->quadrature_weights[q_point] *
5467 this->normal_x_jacobian[0][dim - 1];
5468 for (unsigned int comp = 0; comp < n_components; ++comp)
5469 {
5470 for (unsigned int d = 0; d < dim - 1; ++d)
5471 gradients[comp * nqp_d + d] = VectorizedArrayType();
5472 if constexpr (n_components == 1)
5473 gradients[dim - 1] = grad_in * JxW_jac;
5474 else
5475 gradients[comp * nqp_d + dim - 1] = grad_in[comp] * JxW_jac;
5476 }
5477 }
5478 else
5479 {
5480 const unsigned int index =
5481 this->cell_type <= internal::MatrixFreeFunctions::affine ? 0 : q_point;
5483 this->normal_x_jacobian[index];
5484 const VectorizedArrayType JxW =
5485 (this->cell_type <= internal::MatrixFreeFunctions::affine) ?
5486 this->J_value[index] * this->quadrature_weights[q_point] :
5487 this->J_value[index];
5488 for (unsigned int comp = 0; comp < n_components; ++comp)
5489 for (unsigned int d = 0; d < dim; ++d)
5490 if constexpr (n_components == 1)
5491 gradients[d] = (grad_in * JxW) * jac[d];
5492 else
5493 gradients[comp * nqp_d + d] = (grad_in[comp] * JxW) * jac[d];
5494 }
5495}
5496
5497
5498
5499template <int dim,
5500 int n_components_,
5501 typename Number,
5502 bool is_face,
5503 typename VectorizedArrayType>
5504inline DEAL_II_ALWAYS_INLINE void
5506 submit_hessian(const hessian_type hessian_in, const unsigned int q_point)
5507{
5508 if constexpr (running_in_debug_mode())
5509 {
5510 Assert(this->is_reinitialized, ExcNotInitialized());
5511 }
5512 AssertIndexRange(q_point, this->n_quadrature_points);
5513 Assert(this->J_value != nullptr,
5515 "update_hessians"));
5516 Assert(this->jacobian != nullptr,
5518 "update_hessians"));
5519 if constexpr (running_in_debug_mode())
5520 {
5521 this->hessians_quad_submitted = true;
5522 }
5523
5524 // compute hessian_unit = J^T * hessian_in(u) * J
5525 const std::size_t nqp = this->n_quadrature_points;
5526 constexpr unsigned int hdim = (dim * (dim + 1)) / 2;
5527 if (!is_face && this->cell_type == internal::MatrixFreeFunctions::cartesian)
5528 {
5529 const VectorizedArrayType JxW =
5530 this->J_value[0] * this->quadrature_weights[q_point];
5531
5532 // diagonal part
5533 for (unsigned int d = 0; d < dim; ++d)
5534 {
5535 const auto jac_d = this->jacobian[0][d][d];
5536 const VectorizedArrayType factor = jac_d * jac_d * JxW;
5537 for (unsigned int comp = 0; comp < n_components; ++comp)
5538 if constexpr (n_components == 1)
5539 this->hessians_quad[d * nqp + q_point] =
5540 hessian_in[d][d] * factor;
5541 else
5542 this->hessians_quad[(comp * hdim + d) * nqp + q_point] =
5543 hessian_in[comp][d][d] * factor;
5544 }
5545
5546 // off diagonal part
5547 for (unsigned int d = 1, off_dia = dim; d < dim; ++d)
5548 for (unsigned int e = 0; e < d; ++e, ++off_dia)
5549 {
5550 const auto jac_d = this->jacobian[0][d][d];
5551 const auto jac_e = this->jacobian[0][e][e];
5552 const VectorizedArrayType factor = jac_d * jac_e * JxW;
5553 for (unsigned int comp = 0; comp < n_components; ++comp)
5554 if constexpr (n_components == 1)
5555 this->hessians_quad[off_dia * nqp + q_point] =
5556 (hessian_in[d][e] + hessian_in[e][d]) * factor;
5557 else
5558 this->hessians_quad[(comp * hdim + off_dia) * nqp + q_point] =
5559 (hessian_in[comp][d][e] + hessian_in[comp][e][d]) * factor;
5560 }
5561 }
5562 // cell with general Jacobian, but constant within the cell
5563 else if (this->cell_type <= internal::MatrixFreeFunctions::affine)
5564 {
5565 const Tensor<2, dim, VectorizedArrayType> jac = this->jacobian[0];
5566 const VectorizedArrayType JxW =
5567 this->J_value[0] * this->quadrature_weights[q_point];
5568 for (unsigned int comp = 0; comp < n_components; ++comp)
5569 {
5571 if constexpr (n_components == 1)
5572 hessian_c = hessian_in;
5573 else
5574 hessian_c = hessian_in[comp];
5575
5576 // 1. tmp = hessian(u) * J
5577 VectorizedArrayType tmp[dim][dim];
5578 for (unsigned int i = 0; i < dim; ++i)
5579 for (unsigned int j = 0; j < dim; ++j)
5580 {
5581 tmp[i][j] = hessian_c[i][0] * jac[0][j];
5582 for (unsigned int k = 1; k < dim; ++k)
5583 tmp[i][j] += hessian_c[i][k] * jac[k][j];
5584 }
5585
5586 // 2. hessian_unit = J^T * tmp
5587 VectorizedArrayType tmp2[dim][dim];
5588 for (unsigned int i = 0; i < dim; ++i)
5589 for (unsigned int j = 0; j < dim; ++j)
5590 {
5591 tmp2[i][j] = jac[0][i] * tmp[0][j];
5592 for (unsigned int k = 1; k < dim; ++k)
5593 tmp2[i][j] += jac[k][i] * tmp[k][j];
5594 }
5595
5596 // diagonal part
5597 for (unsigned int d = 0; d < dim; ++d)
5598 this->hessians_quad[(comp * hdim + d) * nqp + q_point] =
5599 tmp2[d][d] * JxW;
5600
5601 // off diagonal part
5602 for (unsigned int d = 0, off_diag = dim; d < dim; ++d)
5603 for (unsigned int e = d + 1; e < dim; ++e, ++off_diag)
5604 this->hessians_quad[(comp * hdim + off_diag) * nqp + q_point] =
5605 (tmp2[d][e] + tmp2[e][d]) * JxW;
5606 }
5607 }
5608 else
5609 {
5610 const Tensor<2, dim, VectorizedArrayType> jac = this->jacobian[q_point];
5611 const VectorizedArrayType JxW = this->J_value[q_point];
5612 const auto &jac_grad = this->jacobian_gradients[q_point];
5613 for (unsigned int comp = 0; comp < n_components; ++comp)
5614 {
5616 if constexpr (n_components == 1)
5617 hessian_c = hessian_in;
5618 else
5619 hessian_c = hessian_in[comp];
5620
5621 // 1. tmp = hessian(u) * J
5622 VectorizedArrayType tmp[dim][dim];
5623 for (unsigned int i = 0; i < dim; ++i)
5624 for (unsigned int j = 0; j < dim; ++j)
5625 {
5626 tmp[i][j] = hessian_c[i][0] * jac[0][j];
5627 for (unsigned int k = 1; k < dim; ++k)
5628 tmp[i][j] += hessian_c[i][k] * jac[k][j];
5629 }
5630
5631 // 2. hessian_unit = J^T * tmp
5632 VectorizedArrayType tmp2[dim][dim];
5633 for (unsigned int i = 0; i < dim; ++i)
5634 for (unsigned int j = 0; j < dim; ++j)
5635 {
5636 tmp2[i][j] = jac[0][i] * tmp[0][j];
5637 for (unsigned int k = 1; k < dim; ++k)
5638 tmp2[i][j] += jac[k][i] * tmp[k][j];
5639 }
5640
5641 // diagonal part
5642 for (unsigned int d = 0; d < dim; ++d)
5643 this->hessians_quad[(comp * hdim + d) * nqp + q_point] =
5644 tmp2[d][d] * JxW;
5645
5646 // off diagonal part
5647 for (unsigned int d = 0, off_diag = dim; d < dim; ++d)
5648 for (unsigned int e = d + 1; e < dim; ++e, ++off_diag)
5649 this->hessians_quad[(comp * hdim + off_diag) * nqp + q_point] =
5650 (tmp2[d][e] + tmp2[e][d]) * JxW;
5651
5652 // 3. gradient_unit = J' * hessian
5653 for (unsigned int d = 0; d < dim; ++d)
5654 {
5655 VectorizedArrayType sum = 0;
5656 for (unsigned int e = 0; e < dim; ++e)
5657 sum += hessian_c[e][e] * jac_grad[e][d];
5658 for (unsigned int e = 0, count = dim; e < dim; ++e)
5659 for (unsigned int f = e + 1; f < dim; ++f, ++count)
5660 sum +=
5661 (hessian_c[e][f] + hessian_c[f][e]) * jac_grad[count][d];
5662 this->gradients_from_hessians_quad[(comp * nqp + q_point) * dim +
5663 d] = sum * JxW;
5664 }
5665 }
5666 }
5667}
5668
5669
5670
5671template <int dim,
5672 int n_components_,
5673 typename Number,
5674 bool is_face,
5675 typename VectorizedArrayType>
5676inline DEAL_II_ALWAYS_INLINE void
5678 submit_normal_hessian(const value_type normal_hessian_in,
5679 const unsigned int q_point)
5680{
5681 if constexpr (running_in_debug_mode())
5682 {
5683 Assert(this->is_reinitialized, ExcNotInitialized());
5684 }
5685 AssertIndexRange(q_point, this->n_quadrature_points);
5686 Assert(this->J_value != nullptr,
5688 "update_hessians"));
5689 Assert(this->jacobian != nullptr,
5691 "update_hessians"));
5692 if constexpr (running_in_debug_mode())
5693 {
5694 this->hessians_quad_submitted = true;
5695 }
5696
5697 // compute hessian_unit = J^T * hessian_in(u) * J
5698 const std::size_t nqp = this->n_quadrature_points;
5699 constexpr unsigned int hdim = (dim * (dim + 1)) / 2;
5700 if (this->cell_type <= internal::MatrixFreeFunctions::affine)
5701 {
5702 const VectorizedArrayType JxW =
5703 this->J_value[0] * this->quadrature_weights[q_point];
5704
5705 const auto nxj = this->normal_x_jacobian[0];
5706
5707 // diagonal part
5708 for (unsigned int d = 0; d < dim; ++d)
5709 {
5710 const auto nxj_d = nxj[d];
5711 const VectorizedArrayType factor = nxj_d * nxj_d * JxW;
5712 for (unsigned int comp = 0; comp < n_components; ++comp)
5713 if constexpr (n_components == 1)
5714 this->hessians_quad[d * nqp + q_point] =
5715 normal_hessian_in * factor;
5716 else
5717 this->hessians_quad[(comp * hdim + d) * nqp + q_point] =
5718 normal_hessian_in[comp] * factor;
5719 }
5720
5721 // off diagonal part
5722 for (unsigned int d = 1, off_dia = dim; d < dim; ++d)
5723 for (unsigned int e = 0; e < d; ++e, ++off_dia)
5724 {
5725 const auto jac_d = nxj[d];
5726 const auto jac_e = nxj[e];
5727 const VectorizedArrayType factor = jac_d * jac_e * JxW;
5728 for (unsigned int comp = 0; comp < n_components; ++comp)
5729 if constexpr (n_components == 1)
5730 this->hessians_quad[off_dia * nqp + q_point] =
5731 2. * normal_hessian_in * factor;
5732 else
5733 this->hessians_quad[(comp * hdim + off_dia) * nqp + q_point] =
5734 2. * normal_hessian_in[comp] * factor;
5735 }
5736 }
5737 else
5738 {
5739 const auto normal = this->normal_vector(q_point);
5740 const auto normal_projector = outer_product(normal, normal);
5741 if constexpr (n_components == 1)
5742 submit_hessian(normal_hessian_in * normal_projector, q_point);
5743 else
5744 {
5745 hessian_type tmp;
5746 for (unsigned int comp = 0; comp < n_components; ++comp)
5747 tmp[comp] = normal_hessian_in[comp] * normal_projector;
5748 submit_hessian(tmp, q_point);
5749 }
5750 }
5751}
5752
5753
5754
5755template <int dim,
5756 int n_components_,
5757 typename Number,
5758 bool is_face,
5759 typename VectorizedArrayType>
5760inline typename FEEvaluationBase<dim,
5761 n_components_,
5762 Number,
5763 is_face,
5764 VectorizedArrayType>::value_type
5766 integrate_value() const
5767{
5768 if constexpr (running_in_debug_mode())
5769 {
5770 Assert(this->is_reinitialized, ExcNotInitialized());
5771 Assert(this->values_quad_submitted == true,
5773 }
5774
5776 const std::size_t nqp = this->n_quadrature_points;
5777 for (unsigned int q = 0; q < nqp; ++q)
5778 for (unsigned int comp = 0; comp < n_components; ++comp)
5779 return_value[comp] += this->values_quad[comp * nqp + q];
5780 if constexpr (n_components == 1)
5781 return return_value[0];
5782 else
5783 return return_value;
5784}
5785
5786
5787
5788template <int dim,
5789 int n_components_,
5790 typename Number,
5791 bool is_face,
5792 typename VectorizedArrayType>
5793template <int, typename>
5794inline DEAL_II_ALWAYS_INLINE VectorizedArrayType
5796 get_divergence(const unsigned int q_point) const
5797{
5798 static_assert(n_components == dim,
5799 "Do not try to modify the default template parameters used for"
5800 " selectively enabling this function via std::enable_if!");
5801
5802 if constexpr (running_in_debug_mode())
5803 {
5804 Assert(this->gradients_quad_initialized == true,
5806 }
5807 AssertIndexRange(q_point, this->n_quadrature_points);
5808 Assert(this->jacobian != nullptr,
5810 "update_gradients"));
5811
5812 VectorizedArrayType divergence;
5813 const std::size_t nqp = this->n_quadrature_points;
5814
5815 if (dim > 1 &&
5816 this->data->element_type ==
5818 {
5819 VectorizedArrayType inv_det =
5820 (!is_face &&
5821 this->cell_type == internal::MatrixFreeFunctions::cartesian) ?
5822 this->jacobian[0][0][0] *
5823 ((dim == 2) ? this->jacobian[0][1][1] :
5824 this->jacobian[0][1][1] * this->jacobian[0][2][2]) :
5825 determinant(this->jacobian[this->cell_type >
5826 internal::MatrixFreeFunctions::affine ?
5827 q_point :
5828 0]);
5829
5830 // on faces in 2d, the determinant has the wrong sign due to ordering of
5831 // derivatives
5832 if (is_face && dim == 2 && this->get_face_no() < 2)
5833 inv_det = -inv_det;
5834
5835 // div * det(J^-1)
5836 divergence = this->gradients_quad[q_point * dim];
5837 for (unsigned int d = 1; d < dim; ++d)
5838 divergence += this->gradients_quad[(d * nqp + q_point) * dim + d];
5839 divergence *= inv_det;
5840 }
5841 else
5842 {
5843 if (!is_face &&
5845 {
5846 // Cartesian cell
5847 divergence =
5848 this->gradients_quad[q_point * dim] * this->jacobian[0][0][0];
5849 for (unsigned int d = 1; d < dim; ++d)
5850 divergence += this->gradients_quad[(d * nqp + q_point) * dim + d] *
5851 this->jacobian[0][d][d];
5852 }
5853 else
5854 {
5855 // cell with general/constant Jacobian
5857 this->cell_type == internal::MatrixFreeFunctions::general ?
5858 this->jacobian[q_point] :
5859 this->jacobian[0];
5860 divergence = jac[0][0] * this->gradients_quad[q_point * dim];
5861 for (unsigned int e = 1; e < dim; ++e)
5862 divergence += jac[0][e] * this->gradients_quad[q_point * dim + e];
5863 for (unsigned int d = 1; d < dim; ++d)
5864 for (unsigned int e = 0; e < dim; ++e)
5865 divergence +=
5866 jac[d][e] * this->gradients_quad[(d * nqp + q_point) * dim + e];
5867 }
5868 }
5869 return divergence;
5870}
5871
5872
5873
5874template <int dim,
5875 int n_components_,
5876 typename Number,
5877 bool is_face,
5878 typename VectorizedArrayType>
5879template <int, typename>
5882 get_symmetric_gradient(const unsigned int q_point) const
5883{
5884 static_assert(n_components == dim,
5885 "Do not try to modify the default template parameters used for"
5886 " selectively enabling this function via std::enable_if!");
5887
5888 // copy from generic function into dim-specialization function
5889 const auto grad = get_gradient(q_point);
5890 VectorizedArrayType symmetrized[(dim * dim + dim) / 2];
5891 VectorizedArrayType half = Number(0.5);
5892 for (unsigned int d = 0; d < dim; ++d)
5893 symmetrized[d] = grad[d][d];
5894 switch (dim)
5895 {
5896 case 1:
5897 break;
5898 case 2:
5899 symmetrized[2] = grad[0][1] + grad[1][0];
5900 symmetrized[2] *= half;
5901 break;
5902 case 3:
5903 symmetrized[3] = grad[0][1] + grad[1][0];
5904 symmetrized[3] *= half;
5905 symmetrized[4] = grad[0][2] + grad[2][0];
5906 symmetrized[4] *= half;
5907 symmetrized[5] = grad[1][2] + grad[2][1];
5908 symmetrized[5] *= half;
5909 break;
5910 default:
5912 }
5914}
5915
5916
5917
5918template <int dim,
5919 int n_components_,
5920 typename Number,
5921 bool is_face,
5922 typename VectorizedArrayType>
5923template <int, typename>
5925 typename FEEvaluationBase<dim,
5926 n_components_,
5927 Number,
5928 is_face,
5929 VectorizedArrayType>::curl_type
5931 get_curl(const unsigned int q_point) const
5932{
5933 static_assert(dim > 1 && n_components == dim,
5934 "Do not try to modify the default template parameters used for"
5935 " selectively enabling this function via std::enable_if!");
5936
5937 if (dim > 1 && this->data->element_type ==
5939 {
5940 // Piola transformation required: Since the transformation for Nedelec
5941 // is constructed to give a curl based on a scaled version of the
5942 // reference curl, this function turns out to be particularly simple.
5943 if constexpr (running_in_debug_mode())
5944 {
5945 Assert(this->gradients_quad_initialized == true,
5947 }
5948 AssertIndexRange(q_point, this->n_quadrature_points);
5949 Assert(this->jacobian != nullptr,
5951 "update_gradients"));
5952 curl_type curl;
5953 const std::size_t nqp = this->n_quadrature_points;
5954 const std::size_t nqp_d = nqp * dim;
5955 const VectorizedArrayType *gradients =
5956 this->gradients_quad + q_point * dim;
5957 if constexpr (dim == 2)
5958 curl = gradients[1 * nqp_d + 0] - gradients[0 * nqp_d + 1];
5959 else if constexpr (dim == 3)
5960 {
5961 curl[0] = gradients[2 * nqp_d + 1] - gradients[1 * nqp_d + 2];
5962 curl[1] = gradients[0 * nqp_d + 2] - gradients[2 * nqp_d + 0];
5963 curl[2] = gradients[1 * nqp_d + 0] - gradients[0 * nqp_d + 1];
5964 }
5965 else
5967
5968 if (!is_face &&
5970 {
5971 VectorizedArrayType inv_det =
5972 this->jacobian[0][0][0] *
5973 ((dim == 2) ? this->jacobian[0][1][1] :
5974 this->jacobian[0][1][1] * this->jacobian[0][2][2]);
5975
5976 const Tensor<2, dim, VectorizedArrayType> jac = this->jacobian[1];
5977
5978 // J * curl * det(J^-1)
5979 if constexpr (dim == 2)
5980 curl *= inv_det;
5981 else
5982 for (unsigned int d = 0; d < (dim == 2 ? 1 : dim); ++d)
5983 curl[d] *= jac[d][d] * inv_det;
5984 }
5985 else
5986 {
5987 // Cell with general/constant Jacobian.
5988 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
5989 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
5990 this->jacobian[q_point] :
5991 this->jacobian[0];
5993 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
5994 transpose(invert(inv_t_jac)) :
5995 this->jacobian[1];
5996
5997 VectorizedArrayType inv_det = determinant(inv_t_jac);
5998
5999 // on faces in 2d, the determinant has the wrong sign due to ordering
6000 // of derivatives
6001 if (is_face && dim == 2 && this->get_face_no() < 2)
6002 inv_det = -inv_det;
6003
6004 // J * curl * det(J^-1)
6005 // In case of 2D its just a scaling with det(J^-1)
6006 if constexpr (dim == 2)
6007 curl *= inv_det;
6008 else
6009 {
6011 for (unsigned int comp = 0; comp < dim; ++comp)
6012 {
6013 curl_temp[comp] = curl[0] * jac[comp][0];
6014 for (unsigned int e = 1; e < dim; ++e)
6015 curl_temp[comp] += jac[comp][e] * curl[e];
6016 }
6017 for (unsigned int comp = 0; comp < dim; ++comp)
6018 curl[comp] = curl_temp[comp] * inv_det;
6019 }
6020 }
6021 return curl;
6022 }
6023
6024 // copy from generic function into dim-specialization function
6025 const Tensor<2, dim, VectorizedArrayType> grad = get_gradient(q_point);
6026 curl_type curl;
6027 if constexpr (dim == 2)
6028 curl = grad[1][0] - grad[0][1];
6029 else if constexpr (dim == 3)
6030 {
6031 curl[0] = grad[2][1] - grad[1][2];
6032 curl[1] = grad[0][2] - grad[2][0];
6033 curl[2] = grad[1][0] - grad[0][1];
6034 }
6035 else
6037
6038 return curl;
6039}
6040
6041
6042
6043template <int dim,
6044 int n_components_,
6045 typename Number,
6046 bool is_face,
6047 typename VectorizedArrayType>
6048template <int, typename>
6049inline DEAL_II_ALWAYS_INLINE void
6051 submit_divergence(const VectorizedArrayType div_in,
6052 const unsigned int q_point)
6053{
6054 static_assert(n_components == dim,
6055 "Do not try to modify the default template parameters used for"
6056 " selectively enabling this function via std::enable_if!");
6057
6058 if constexpr (running_in_debug_mode())
6059 {
6060 Assert(this->is_reinitialized, ExcNotInitialized());
6061 }
6062 AssertIndexRange(q_point, this->n_quadrature_points);
6063 Assert(this->J_value != nullptr,
6065 "update_gradients"));
6066 Assert(this->jacobian != nullptr,
6068 "update_gradients"));
6069 if constexpr (running_in_debug_mode())
6070 {
6071 this->gradients_quad_submitted = true;
6072 }
6073
6074 const std::size_t nqp_d = this->n_quadrature_points * dim;
6075 VectorizedArrayType *gradients = this->gradients_quad + q_point * dim;
6076
6077 if (this->data->element_type ==
6079 {
6080 // General cell
6081
6082 // Derivatives are reordered for faces. Need to take this into account
6083 // and 1/inv_det != J_value for faces
6084 const VectorizedArrayType fac =
6085 (!is_face) ?
6086 this->quadrature_weights[q_point] * div_in :
6087 (this->cell_type > internal::MatrixFreeFunctions::affine ?
6088 this->J_value[q_point] :
6089 this->J_value[0] * this->quadrature_weights[q_point]) *
6090 div_in *
6092 this->jacobian[this->cell_type >
6093 internal::MatrixFreeFunctions::affine ?
6094 q_point :
6095 0]) *
6096 Number((dim == 2 && this->get_face_no() < 2) ? -1 : 1);
6097
6098 for (unsigned int d = 0; d < dim; ++d)
6099 {
6100 for (unsigned int e = 0; e < dim; ++e)
6101 gradients[d * nqp_d + e] = (d == e) ? fac : 0.;
6102 }
6103 this->divergence_is_requested = true;
6104 }
6105 else
6106 {
6107 if (!is_face &&
6109 {
6110 const VectorizedArrayType fac =
6111 this->J_value[0] * this->quadrature_weights[q_point] * div_in;
6112 for (unsigned int d = 0; d < dim; ++d)
6113 {
6114 const VectorizedArrayType jac_dd = this->jacobian[0][d][d];
6115 for (unsigned int e = 0; e < dim; ++e)
6116 gradients[d * nqp_d + e] = (d == e) ? fac * jac_dd : 0.;
6117 }
6118 }
6119 else
6120 {
6122 this->cell_type == internal::MatrixFreeFunctions::general ?
6123 this->jacobian[q_point] :
6124 this->jacobian[0];
6125 const VectorizedArrayType fac =
6126 (this->cell_type == internal::MatrixFreeFunctions::general ?
6127 this->J_value[q_point] :
6128 this->J_value[0] * this->quadrature_weights[q_point]) *
6129 div_in;
6130 for (unsigned int d = 0; d < dim; ++d)
6131 {
6132 for (unsigned int e = 0; e < dim; ++e)
6133 gradients[d * nqp_d + e] = jac[d][e] * fac;
6134 }
6135 }
6136 }
6137}
6138
6139
6140
6141template <int dim,
6142 int n_components_,
6143 typename Number,
6144 bool is_face,
6145 typename VectorizedArrayType>
6146template <int, typename>
6147inline DEAL_II_ALWAYS_INLINE void
6151 const unsigned int q_point)
6152{
6153 static_assert(n_components == dim,
6154 "Do not try to modify the default template parameters used for"
6155 " selectively enabling this function via std::enable_if!");
6156
6158 this->data->element_type !=
6161
6162 // could have used base class operator, but that involves some overhead
6163 // which is inefficient. it is nice to have the symmetric tensor because
6164 // that saves some operations
6165 if constexpr (running_in_debug_mode())
6166 {
6167 Assert(this->is_reinitialized, ExcNotInitialized());
6168 }
6169 AssertIndexRange(q_point, this->n_quadrature_points);
6170 Assert(this->J_value != nullptr,
6172 "update_gradients"));
6173 Assert(this->jacobian != nullptr,
6175 "update_gradients"));
6176 if constexpr (running_in_debug_mode())
6177 {
6178 this->gradients_quad_submitted = true;
6179 }
6180
6181 const std::size_t nqp_d = this->n_quadrature_points * dim;
6182 VectorizedArrayType *gradients = this->gradients_quad + dim * q_point;
6183 if (!is_face && this->cell_type == internal::MatrixFreeFunctions::cartesian)
6184 {
6185 const VectorizedArrayType JxW =
6186 this->J_value[0] * this->quadrature_weights[q_point];
6187 const Tensor<2, dim, VectorizedArrayType> jac = this->jacobian[0];
6188 for (unsigned int d = 0; d < dim; ++d)
6189 gradients[d * nqp_d + d] =
6190 (sym_grad.access_raw_entry(d) * JxW * jac[d][d]);
6191 for (unsigned int e = 0, counter = dim; e < dim; ++e)
6192 for (unsigned int d = e + 1; d < dim; ++d, ++counter)
6193 {
6194 const VectorizedArrayType value =
6195 sym_grad.access_raw_entry(counter) * JxW;
6196 gradients[e * nqp_d + d] = value * jac[d][d];
6197 gradients[d * nqp_d + e] = value * jac[e][e];
6198 }
6199 }
6200 // general/affine cell type
6201 else
6202 {
6203 const VectorizedArrayType JxW =
6204 this->cell_type == internal::MatrixFreeFunctions::general ?
6205 this->J_value[q_point] :
6206 this->J_value[0] * this->quadrature_weights[q_point];
6208 this->cell_type == internal::MatrixFreeFunctions::general ?
6209 this->jacobian[q_point] :
6210 this->jacobian[0];
6211 VectorizedArrayType weighted[dim][dim];
6212 for (unsigned int i = 0; i < dim; ++i)
6213 weighted[i][i] = sym_grad.access_raw_entry(i) * JxW;
6214 for (unsigned int i = 0, counter = dim; i < dim; ++i)
6215 for (unsigned int j = i + 1; j < dim; ++j, ++counter)
6216 {
6217 const VectorizedArrayType value =
6218 sym_grad.access_raw_entry(counter) * JxW;
6219 weighted[i][j] = value;
6220 weighted[j][i] = value;
6221 }
6222 for (unsigned int comp = 0; comp < dim; ++comp)
6223 for (unsigned int d = 0; d < dim; ++d)
6224 {
6225 VectorizedArrayType new_val = jac[0][d] * weighted[comp][0];
6226 for (unsigned int e = 1; e < dim; ++e)
6227 new_val += jac[e][d] * weighted[comp][e];
6228 gradients[comp * nqp_d + d] = new_val;
6229 }
6230 }
6231}
6232
6233
6234
6235template <int dim,
6236 int n_components_,
6237 typename Number,
6238 bool is_face,
6239 typename VectorizedArrayType>
6240template <int, typename>
6241inline DEAL_II_ALWAYS_INLINE void
6244 const typename FEEvaluationBase<dim,
6245 n_components_,
6246 Number,
6247 is_face,
6248 VectorizedArrayType>::curl_type curl,
6249 const unsigned int q_point)
6250{
6251 static_assert(n_components == dim,
6252 "Do not try to modify the default template parameters used for"
6253 " selectively enabling this function via std::enable_if!");
6254
6256
6257 if (this->data->element_type ==
6259 {
6260 curl_type curl_temp;
6261
6262 // Piola transform is required
6263 AssertIndexRange(q_point, this->n_quadrature_points);
6264 Assert(this->J_value != nullptr,
6266 "update_value"));
6267# ifdef DEBUG
6268 Assert(this->is_reinitialized, ExcNotInitialized());
6269 this->gradients_quad_submitted = true;
6270# endif
6271
6272 const std::size_t nqp_d = this->n_quadrature_points * dim;
6273 VectorizedArrayType *gradients = this->gradients_quad + q_point * dim;
6274
6275 if (!is_face &&
6277 {
6278 const Tensor<2, dim, VectorizedArrayType> jac = this->jacobian[1];
6279 const VectorizedArrayType weight = this->quadrature_weights[q_point];
6280
6281 if constexpr (dim == 2)
6282 {
6283 curl_temp = curl * weight;
6284 }
6285 else if constexpr (dim == 3)
6286 {
6287 for (unsigned int comp = 0; comp < dim; ++comp)
6288 {
6289 curl_temp[comp] = curl[comp] * jac[comp][comp] * weight;
6290 }
6291 }
6292 else
6294 }
6295 else
6296 {
6297 // Affine or general cell
6298 const Tensor<2, dim, VectorizedArrayType> inv_t_jac =
6299 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
6300 this->jacobian[q_point] :
6301 this->jacobian[0];
6302
6303 // Derivatives are reordered for faces. Need to take this into
6304 // account and 1/inv_det != J_value for faces
6305 const VectorizedArrayType fac =
6306 (!is_face) ?
6307 this->quadrature_weights[q_point] :
6308 (((this->cell_type > internal::MatrixFreeFunctions::affine) ?
6309 this->J_value[q_point] :
6310 this->J_value[0] * this->quadrature_weights[q_point]) *
6311 ((dim == 2 && this->get_face_no() < 2) ?
6312 -determinant(inv_t_jac) :
6313 determinant(inv_t_jac)));
6315 (this->cell_type > internal::MatrixFreeFunctions::affine) ?
6316 transpose(invert(inv_t_jac)) :
6317 this->jacobian[1];
6318
6319 if constexpr (dim == 2)
6320 {
6321 curl_temp = curl * fac;
6322 }
6323 else if constexpr (dim == 3)
6324 {
6325 // J^T * u * factor
6326 for (unsigned int comp = 0; comp < n_components; ++comp)
6327 {
6328 curl_temp[comp] = curl[0] * jac[0][comp];
6329 for (unsigned int e = 1; e < dim; ++e)
6330 curl_temp[comp] += curl[e] * jac[e][comp];
6331 curl_temp[comp] *= fac;
6332 }
6333 }
6334 else
6336 }
6337 switch (dim)
6338 {
6339 case 2:
6340 grad[1][0] = curl_temp[0];
6341 grad[0][1] = -curl_temp[0];
6342 grad[0][0] = 0;
6343 grad[1][1] = 0;
6344 break;
6345 case 3:
6346 grad[2][1] = curl_temp[0];
6347 grad[1][2] = -curl_temp[0];
6348 grad[0][2] = curl_temp[1];
6349 grad[2][0] = -curl_temp[1];
6350 grad[1][0] = curl_temp[2];
6351 grad[0][1] = -curl_temp[2];
6352 grad[0][0] = 0;
6353 grad[1][1] = 0;
6354 grad[2][2] = 0;
6355 break;
6356 default:
6358 }
6359 for (unsigned int d = 0; d < dim; ++d)
6360 {
6361 for (unsigned int comp = 0; comp < n_components; ++comp)
6362 gradients[comp * nqp_d + d] = grad[comp][d];
6363 }
6364 return;
6365 }
6366
6367 if constexpr (dim == 2)
6368 {
6369 grad[1][0] = curl;
6370 grad[0][1] = -curl;
6371 }
6372 else if constexpr (dim == 3)
6373 {
6374 grad[2][1] = curl[0];
6375 grad[1][2] = -curl[0];
6376 grad[0][2] = curl[1];
6377 grad[2][0] = -curl[1];
6378 grad[1][0] = curl[2];
6379 grad[0][1] = -curl[2];
6380 }
6381 else
6383
6384 submit_gradient(grad, q_point);
6385}
6386
6387
6388
6389/*-------------------------- FEEvaluation -----------------------------------*/
6390
6391
6392template <int dim,
6393 int fe_degree,
6394 int n_q_points_1d,
6395 int n_components_,
6396 typename Number,
6397 typename VectorizedArrayType>
6398inline FEEvaluation<dim,
6399 fe_degree,
6400 n_q_points_1d,
6401 n_components_,
6402 Number,
6403 VectorizedArrayType>::
6404 FEEvaluation(const MatrixFree<dim, Number, VectorizedArrayType> &matrix_free,
6405 const unsigned int fe_no,
6406 const unsigned int quadrature_index,
6407 const unsigned int first_selected_component,
6408 const unsigned int active_fe_index,
6409 const unsigned int active_quad_index)
6410 : BaseClass(matrix_free,
6411 fe_no,
6412 first_selected_component,
6413 quadrature_index,
6414 fe_degree,
6415 static_n_q_points,
6416 true /*note: this is not a face*/,
6417 active_fe_index,
6418 active_quad_index,
6419 numbers::invalid_unsigned_int /*face_type*/)
6420 , dofs_per_component(this->data->dofs_per_component_on_cell)
6421 , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
6422 , n_q_points(this->data->n_q_points)
6423{
6424 check_template_arguments(fe_no, 0);
6425}
6426
6427
6428
6429template <int dim,
6430 int fe_degree,
6431 int n_q_points_1d,
6432 int n_components_,
6433 typename Number,
6434 typename VectorizedArrayType>
6435inline FEEvaluation<dim,
6436 fe_degree,
6437 n_q_points_1d,
6438 n_components_,
6439 Number,
6440 VectorizedArrayType>::
6441 FEEvaluation(const MatrixFree<dim, Number, VectorizedArrayType> &matrix_free,
6442 const std::pair<unsigned int, unsigned int> &range,
6443 const unsigned int dof_handler_index,
6444 const unsigned int quadrature_index,
6445 const unsigned int first_selected_component)
6446 : FEEvaluation(matrix_free,
6447 dof_handler_index,
6448 quadrature_index,
6449 first_selected_component,
6450 matrix_free.get_cell_active_fe_index(range, dof_handler_index))
6451{}
6452
6453
6454
6455template <int dim,
6456 int fe_degree,
6457 int n_q_points_1d,
6458 int n_components_,
6459 typename Number,
6460 typename VectorizedArrayType>
6461inline FEEvaluation<dim,
6462 fe_degree,
6463 n_q_points_1d,
6464 n_components_,
6465 Number,
6466 VectorizedArrayType>::
6467 FEEvaluation(const Mapping<dim> &mapping,
6468 const FiniteElement<dim> &fe,
6469 const Quadrature<1> &quadrature,
6470 const UpdateFlags update_flags,
6471 const unsigned int first_selected_component)
6472 : BaseClass(mapping,
6473 fe,
6474 quadrature,
6475 update_flags,
6476 first_selected_component,
6477 nullptr)
6478 , dofs_per_component(this->data->dofs_per_component_on_cell)
6479 , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
6480 , n_q_points(this->data->n_q_points)
6481{
6482 check_template_arguments(numbers::invalid_unsigned_int, 0);
6483}
6484
6485
6486
6487template <int dim,
6488 int fe_degree,
6489 int n_q_points_1d,
6490 int n_components_,
6491 typename Number,
6492 typename VectorizedArrayType>
6493inline FEEvaluation<dim,
6494 fe_degree,
6495 n_q_points_1d,
6496 n_components_,
6497 Number,
6498 VectorizedArrayType>::
6499 FEEvaluation(const FiniteElement<dim> &fe,
6500 const Quadrature<1> &quadrature,
6501 const UpdateFlags update_flags,
6502 const unsigned int first_selected_component)
6503 : BaseClass(StaticMappingQ1<dim>::mapping,
6504 fe,
6505 quadrature,
6506 update_flags,
6507 first_selected_component,
6508 nullptr)
6509 , dofs_per_component(this->data->dofs_per_component_on_cell)
6510 , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
6511 , n_q_points(this->data->n_q_points)
6512{
6513 check_template_arguments(numbers::invalid_unsigned_int, 0);
6514}
6515
6516
6517
6518template <int dim,
6519 int fe_degree,
6520 int n_q_points_1d,
6521 int n_components_,
6522 typename Number,
6523 typename VectorizedArrayType>
6524inline FEEvaluation<dim,
6525 fe_degree,
6526 n_q_points_1d,
6527 n_components_,
6528 Number,
6529 VectorizedArrayType>::
6530 FEEvaluation(const FiniteElement<dim> &fe,
6532 const unsigned int first_selected_component)
6533 : BaseClass(other.mapped_geometry->get_fe_values().get_mapping(),
6534 fe,
6535 other.mapped_geometry->get_quadrature(),
6536 other.mapped_geometry->get_fe_values().get_update_flags(),
6537 first_selected_component,
6538 &other)
6539 , dofs_per_component(this->data->dofs_per_component_on_cell)
6540 , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
6541 , n_q_points(this->data->n_q_points)
6542{
6543 check_template_arguments(numbers::invalid_unsigned_int, 0);
6544}
6545
6546
6547
6548template <int dim,
6549 int fe_degree,
6550 int n_q_points_1d,
6551 int n_components_,
6552 typename Number,
6553 typename VectorizedArrayType>
6554inline FEEvaluation<dim,
6555 fe_degree,
6556 n_q_points_1d,
6557 n_components_,
6558 Number,
6559 VectorizedArrayType>::FEEvaluation(const FEEvaluation
6560 &other)
6561 : BaseClass(other)
6562 , dofs_per_component(this->data->dofs_per_component_on_cell)
6563 , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
6564 , n_q_points(this->data->n_q_points)
6565{
6566 check_template_arguments(numbers::invalid_unsigned_int, 0);
6567}
6568
6569
6570
6571template <int dim,
6572 int fe_degree,
6573 int n_q_points_1d,
6574 int n_components_,
6575 typename Number,
6576 typename VectorizedArrayType>
6577inline FEEvaluation<dim,
6578 fe_degree,
6579 n_q_points_1d,
6580 n_components_,
6581 Number,
6582 VectorizedArrayType> &
6583FEEvaluation<dim,
6584 fe_degree,
6585 n_q_points_1d,
6586 n_components_,
6587 Number,
6588 VectorizedArrayType>::operator=(const FEEvaluation &other)
6589{
6590 BaseClass::operator=(other);
6591 check_template_arguments(numbers::invalid_unsigned_int, 0);
6592 return *this;
6593}
6594
6595
6596
6597template <int dim,
6598 int fe_degree,
6599 int n_q_points_1d,
6600 int n_components_,
6601 typename Number,
6602 typename VectorizedArrayType>
6603inline void
6604FEEvaluation<dim,
6605 fe_degree,
6606 n_q_points_1d,
6607 n_components_,
6608 Number,
6609 VectorizedArrayType>::
6610 check_template_arguments(const unsigned int dof_handler_index,
6611 const unsigned int first_selected_component)
6612{
6613 (void)dof_handler_index;
6614 (void)first_selected_component;
6615
6616 Assert(
6617 this->data->dofs_per_component_on_cell > 0,
6618 ExcMessage(
6619 "There is nothing useful you can do with an FEEvaluation object with "
6620 "FE_Nothing, i.e., without DoFs! If you have passed to "
6621 "MatrixFree::reinit() a collection of finite elements also containing "
6622 "FE_Nothing, please check - before creating FEEvaluation - the category "
6623 "of the current range by calling either "
6624 "MatrixFree::get_cell_range_category(range) or "
6625 "MatrixFree::get_face_range_category(range). The returned category "
6626 "is the index of the active FE, which you can use to exclude "
6627 "FE_Nothing."));
6628
6629 if constexpr (running_in_debug_mode())
6630 {
6631 // print error message when the dimensions do not match. Propose a
6632 // possible fix
6633 if ((static_cast<unsigned int>(fe_degree) !=
6635 static_cast<unsigned int>(fe_degree) !=
6636 this->data->data.front().fe_degree) ||
6637 n_q_points != this->n_quadrature_points)
6638 {
6639 std::string message =
6640 "-------------------------------------------------------\n";
6641 message +=
6642 "Illegal arguments in constructor/wrong template arguments!\n";
6643 message += " Called --> FEEvaluation<dim,";
6644 message += Utilities::int_to_string(fe_degree) + ",";
6645 message += Utilities::int_to_string(n_q_points_1d);
6646 message += "," + Utilities::int_to_string(n_components);
6647 message += ",Number>(data";
6648 if (first_selected_component != numbers::invalid_unsigned_int)
6649 {
6650 message +=
6651 ", " + Utilities::int_to_string(dof_handler_index) + ", ";
6652 message +=
6653 Utilities::int_to_string(this->quadrature_index) + ", ";
6654 message += Utilities::int_to_string(first_selected_component);
6655 }
6656 message += ")\n";
6657
6658 // check whether some other vector component has the correct number of
6659 // points
6660 unsigned int proposed_dof_comp = numbers::invalid_unsigned_int,
6661 proposed_fe_comp = numbers::invalid_unsigned_int,
6662 proposed_quad_comp = numbers::invalid_unsigned_int;
6663 if (dof_handler_index != numbers::invalid_unsigned_int)
6664 {
6665 if (static_cast<unsigned int>(fe_degree) ==
6666 this->data->data.front().fe_degree)
6667 {
6668 proposed_dof_comp = dof_handler_index;
6669 proposed_fe_comp = first_selected_component;
6670 }
6671 else
6672 for (unsigned int no = 0;
6673 no < this->matrix_free->n_components();
6674 ++no)
6675 for (unsigned int nf = 0;
6676 nf < this->matrix_free->n_base_elements(no);
6677 ++nf)
6678 if (this->matrix_free
6679 ->get_shape_info(no, 0, nf, this->active_fe_index, 0)
6680 .data.front()
6681 .fe_degree == static_cast<unsigned int>(fe_degree))
6682 {
6683 proposed_dof_comp = no;
6684 proposed_fe_comp = nf;
6685 break;
6686 }
6687 if (n_q_points ==
6688 this->mapping_data->descriptor[this->active_quad_index]
6689 .n_q_points)
6690 proposed_quad_comp = this->quadrature_index;
6691 else
6692 for (unsigned int no = 0;
6693 no <
6694 this->matrix_free->get_mapping_info().cell_data.size();
6695 ++no)
6696 if (this->matrix_free->get_mapping_info()
6697 .cell_data[no]
6698 .descriptor[this->active_quad_index]
6699 .n_q_points == n_q_points)
6700 {
6701 proposed_quad_comp = no;
6702 break;
6703 }
6704 }
6705 if (proposed_dof_comp != numbers::invalid_unsigned_int &&
6706 proposed_quad_comp != numbers::invalid_unsigned_int)
6707 {
6708 if (proposed_dof_comp != first_selected_component)
6709 message += "Wrong vector component selection:\n";
6710 else
6711 message += "Wrong quadrature formula selection:\n";
6712 message += " Did you mean FEEvaluation<dim,";
6713 message += Utilities::int_to_string(fe_degree) + ",";
6714 message += Utilities::int_to_string(n_q_points_1d);
6715 message += "," + Utilities::int_to_string(n_components);
6716 message += ",Number>(data";
6717 if (dof_handler_index != numbers::invalid_unsigned_int)
6718 {
6719 message +=
6720 ", " + Utilities::int_to_string(proposed_dof_comp) + ", ";
6721 message +=
6722 Utilities::int_to_string(proposed_quad_comp) + ", ";
6723 message += Utilities::int_to_string(proposed_fe_comp);
6724 }
6725 message += ")?\n";
6726 std::string correct_pos;
6727 if (proposed_dof_comp != dof_handler_index)
6728 correct_pos = " ^ ";
6729 else
6730 correct_pos = " ";
6731 if (proposed_quad_comp != this->quadrature_index)
6732 correct_pos += " ^ ";
6733 else
6734 correct_pos += " ";
6735 if (proposed_fe_comp != first_selected_component)
6736 correct_pos += " ^\n";
6737 else
6738 correct_pos += " \n";
6739 message +=
6740 " " +
6741 correct_pos;
6742 }
6743 // ok, did not find the numbers specified by the template arguments in
6744 // the given list. Suggest correct template arguments
6745 const unsigned int proposed_n_q_points_1d = static_cast<unsigned int>(
6746 std::pow(1.001 * this->n_quadrature_points, 1. / dim));
6747 message += "Wrong template arguments:\n";
6748 message += " Did you mean FEEvaluation<dim,";
6749 message +=
6750 Utilities::int_to_string(this->data->data.front().fe_degree) + ",";
6751 message += Utilities::int_to_string(proposed_n_q_points_1d);
6752 message += "," + Utilities::int_to_string(n_components);
6753 message += ",Number>(data";
6754 if (dof_handler_index != numbers::invalid_unsigned_int)
6755 {
6756 message +=
6757 ", " + Utilities::int_to_string(dof_handler_index) + ", ";
6758 message += Utilities::int_to_string(this->quadrature_index);
6759 message +=
6760 ", " + Utilities::int_to_string(first_selected_component);
6761 }
6762 message += ")?\n";
6763 std::string correct_pos;
6764 if (this->data->data.front().fe_degree !=
6765 static_cast<unsigned int>(fe_degree))
6766 correct_pos = " ^";
6767 else
6768 correct_pos = " ";
6769 if (proposed_n_q_points_1d != n_q_points_1d)
6770 correct_pos += " ^\n";
6771 else
6772 correct_pos += " \n";
6773 message += " " + correct_pos;
6774
6775 Assert(static_cast<unsigned int>(fe_degree) ==
6776 this->data->data.front().fe_degree &&
6777 n_q_points == this->n_quadrature_points,
6778 ExcMessage(message));
6779 }
6780 if (dof_handler_index != numbers::invalid_unsigned_int)
6782 n_q_points,
6783 this->mapping_data->descriptor[this->active_quad_index].n_q_points);
6784 }
6785}
6786
6787
6788
6789template <int dim,
6790 int fe_degree,
6791 int n_q_points_1d,
6792 int n_components_,
6793 typename Number,
6794 typename VectorizedArrayType>
6795inline void
6796FEEvaluation<dim,
6797 fe_degree,
6798 n_q_points_1d,
6799 n_components_,
6800 Number,
6801 VectorizedArrayType>::reinit(const unsigned int cell_index)
6802{
6803 Assert(this->matrix_free != nullptr,
6804 ExcMessage("FEEvaluation was initialized without a matrix-free object."
6805 " Integer indexing is not possible."));
6806
6807 Assert(this->dof_info != nullptr, ExcNotInitialized());
6808 Assert(this->mapping_data != nullptr, ExcNotInitialized());
6809 this->cell = cell_index;
6810 this->cell_type =
6811 this->matrix_free->get_mapping_info().get_cell_type(cell_index);
6812
6813 const unsigned int offsets =
6814 this->mapping_data->data_index_offsets[cell_index];
6815 this->jacobian = &this->mapping_data->jacobians[0][offsets];
6816 this->J_value = &this->mapping_data->JxW_values[offsets];
6817 if (!this->mapping_data->jacobian_gradients[0].empty())
6818 {
6819 this->jacobian_gradients =
6820 this->mapping_data->jacobian_gradients[0].data() + offsets;
6821 this->jacobian_gradients_non_inverse =
6822 this->mapping_data->jacobian_gradients_non_inverse[0].data() + offsets;
6823 }
6824
6825 if (this->matrix_free->n_active_entries_per_cell_batch(this->cell) == n_lanes)
6826 {
6828 for (unsigned int i = 0; i < n_lanes; ++i)
6829 this->cell_ids[i] = cell_index * n_lanes + i;
6830 }
6831 else
6832 {
6833 unsigned int i = 0;
6834 for (; i < this->matrix_free->n_active_entries_per_cell_batch(this->cell);
6835 ++i)
6836 this->cell_ids[i] = cell_index * n_lanes + i;
6837 for (; i < n_lanes; ++i)
6838 this->cell_ids[i] = numbers::invalid_unsigned_int;
6839 }
6840
6841 if (this->mapping_data->quadrature_points.empty() == false)
6842 this->quadrature_points =
6843 &this->mapping_data->quadrature_points
6844 [this->mapping_data->quadrature_point_offsets[this->cell]];
6845
6846 if constexpr (running_in_debug_mode())
6847 {
6848 this->is_reinitialized = true;
6849 this->dof_values_initialized = false;
6850 this->values_quad_initialized = false;
6851 this->gradients_quad_initialized = false;
6852 this->hessians_quad_initialized = false;
6853 }
6854}
6855
6856
6857
6858template <int dim,
6859 int fe_degree,
6860 int n_q_points_1d,
6861 int n_components_,
6862 typename Number,
6863 typename VectorizedArrayType>
6864inline void
6865FEEvaluation<dim,
6866 fe_degree,
6867 n_q_points_1d,
6868 n_components_,
6869 Number,
6870 VectorizedArrayType>::reinit(const std::array<unsigned int,
6871 n_lanes> &cell_ids)
6872{
6873 Assert(this->dof_info != nullptr, ExcNotInitialized());
6874 Assert(this->mapping_data != nullptr, ExcNotInitialized());
6875
6876 this->cell = numbers::invalid_unsigned_int;
6877 this->cell_ids = cell_ids;
6878
6879 // determine type of cell batch
6881
6882 for (unsigned int v = 0; v < n_lanes; ++v)
6883 {
6884 const unsigned int cell_index = cell_ids[v];
6885
6887 continue;
6888
6889 this->cell_type =
6890 std::max(this->cell_type,
6891 this->matrix_free->get_mapping_info().get_cell_type(
6892 cell_index / n_lanes));
6893 }
6894
6895 // allocate memory for internal data storage
6896 if (this->mapped_geometry == nullptr)
6897 this->mapped_geometry =
6898 std::make_shared<internal::MatrixFreeFunctions::
6899 MappingDataOnTheFly<dim, VectorizedArrayType>>();
6900
6901 auto &mapping_storage = this->mapped_geometry->get_data_storage();
6902
6903 auto &this_jacobian_data = mapping_storage.jacobians[0];
6904 auto &this_J_value_data = mapping_storage.JxW_values;
6905 auto &this_jacobian_gradients_data = mapping_storage.jacobian_gradients[0];
6906 auto &this_jacobian_gradients_non_inverse_data =
6907 mapping_storage.jacobian_gradients_non_inverse[0];
6908 auto &this_quadrature_points_data = mapping_storage.quadrature_points;
6909
6911 {
6912 if (this_jacobian_data.size() != 2)
6913 this_jacobian_data.resize_fast(2);
6914
6915 if (this_J_value_data.size() != 1)
6916 this_J_value_data.resize_fast(1);
6917
6918 const auto &update_flags_cells =
6919 this->matrix_free->get_mapping_info().update_flags_cells;
6920
6921 if (update_flags_cells & update_jacobian_grads &&
6922 this_jacobian_gradients_data.size() != 1)
6923 {
6924 this_jacobian_gradients_data.resize_fast(1);
6925 this_jacobian_gradients_non_inverse_data.resize_fast(1);
6926 }
6927
6928 if (update_flags_cells & update_quadrature_points &&
6929 this_quadrature_points_data.size() != 1)
6930 this_quadrature_points_data.resize_fast(1);
6931 }
6932 else
6933 {
6934 if (this_jacobian_data.size() != this->n_quadrature_points)
6935 this_jacobian_data.resize_fast(this->n_quadrature_points);
6936
6937 if (this_J_value_data.size() != this->n_quadrature_points)
6938 this_J_value_data.resize_fast(this->n_quadrature_points);
6939
6940 const auto &update_flags_cells =
6941 this->matrix_free->get_mapping_info().update_flags_cells;
6942
6943 if (update_flags_cells & update_jacobian_grads &&
6944 this_jacobian_gradients_data.size() != this->n_quadrature_points)
6945 {
6946 this_jacobian_gradients_data.resize_fast(this->n_quadrature_points);
6947 this_jacobian_gradients_non_inverse_data.resize_fast(
6948 this->n_quadrature_points);
6949 }
6950
6951 if (update_flags_cells & update_quadrature_points &&
6952 this_quadrature_points_data.size() != this->n_quadrature_points)
6953 this_quadrature_points_data.resize_fast(this->n_quadrature_points);
6954 }
6955
6956 // set pointers to internal data storage
6957 this->jacobian = this_jacobian_data.data();
6958 this->J_value = this_J_value_data.data();
6959 this->jacobian_gradients = this_jacobian_gradients_data.data();
6960 this->jacobian_gradients_non_inverse =
6961 this_jacobian_gradients_non_inverse_data.data();
6962 this->quadrature_points = this_quadrature_points_data.data();
6963
6964 // fill internal data storage lane by lane
6965 for (unsigned int v = 0; v < n_lanes; ++v)
6966 {
6967 const unsigned int cell_index = cell_ids[v];
6968
6970 continue;
6971
6972 const unsigned int cell_batch_index = cell_index / n_lanes;
6973 const unsigned int offsets =
6974 this->mapping_data->data_index_offsets[cell_batch_index];
6975 const unsigned int lane = cell_index % n_lanes;
6976
6977 if (this->cell_type <=
6979 {
6980 // case that all cells are Cartesian or affine
6981 for (unsigned int q = 0; q < 2; ++q)
6982 for (unsigned int i = 0; i < dim; ++i)
6983 for (unsigned int j = 0; j < dim; ++j)
6984 this_jacobian_data[q][i][j][v] =
6985 this->mapping_data->jacobians[0][offsets + q][i][j][lane];
6986
6987 const unsigned int q = 0;
6988
6989 this_J_value_data[q][v] =
6990 this->mapping_data->JxW_values[offsets + q][lane];
6991
6992 const auto &update_flags_cells =
6993 this->matrix_free->get_mapping_info().update_flags_cells;
6994
6995 if (update_flags_cells & update_jacobian_grads)
6996 {
6997 for (unsigned int i = 0; i < dim * (dim + 1) / 2; ++i)
6998 for (unsigned int j = 0; j < dim; ++j)
6999 this_jacobian_gradients_data[q][i][j][v] =
7000 this->mapping_data
7001 ->jacobian_gradients[0][offsets + q][i][j][lane];
7002
7003 for (unsigned int i = 0; i < dim * (dim + 1) / 2; ++i)
7004 for (unsigned int j = 0; j < dim; ++j)
7005 this_jacobian_gradients_non_inverse_data[q][i][j][v] =
7006 this->mapping_data
7007 ->jacobian_gradients_non_inverse[0][offsets + q][i][j]
7008 [lane];
7009 }
7010
7011 if (update_flags_cells & update_quadrature_points)
7012 for (unsigned int i = 0; i < dim; ++i)
7013 this_quadrature_points_data[q][i][v] =
7014 this->mapping_data->quadrature_points
7015 [this->mapping_data
7016 ->quadrature_point_offsets[cell_batch_index] +
7017 q][i][lane];
7018 }
7019 else
7020 {
7021 // general case that at least one cell is not Cartesian or affine
7022 const auto cell_type =
7023 this->matrix_free->get_mapping_info().get_cell_type(
7024 cell_batch_index);
7025
7026 for (unsigned int q = 0; q < this->n_quadrature_points; ++q)
7027 {
7028 const unsigned int q_src =
7029 (cell_type <=
7031 0 :
7032 q;
7033
7034 this_J_value_data[q][v] =
7035 this->mapping_data->JxW_values[offsets + q_src][lane];
7036
7037 for (unsigned int i = 0; i < dim; ++i)
7038 for (unsigned int j = 0; j < dim; ++j)
7039 this_jacobian_data[q][i][j][v] =
7040 this->mapping_data
7041 ->jacobians[0][offsets + q_src][i][j][lane];
7042
7043 const auto &update_flags_cells =
7044 this->matrix_free->get_mapping_info().update_flags_cells;
7045
7046 if (update_flags_cells & update_jacobian_grads)
7047 {
7048 for (unsigned int i = 0; i < dim * (dim + 1) / 2; ++i)
7049 for (unsigned int j = 0; j < dim; ++j)
7050 this_jacobian_gradients_data[q][i][j][v] =
7051 this->mapping_data
7052 ->jacobian_gradients[0][offsets + q_src][i][j][lane];
7053
7054 for (unsigned int i = 0; i < dim * (dim + 1) / 2; ++i)
7055 for (unsigned int j = 0; j < dim; ++j)
7056 this_jacobian_gradients_non_inverse_data[q][i][j][v] =
7057 this->mapping_data
7058 ->jacobian_gradients_non_inverse[0][offsets + q_src]
7059 [i][j][lane];
7060 }
7061
7062 if (update_flags_cells & update_quadrature_points)
7063 {
7064 if (cell_type <=
7066 {
7067 // affine case: quadrature points are not available but
7068 // have to be computed from the corner point and the
7069 // Jacobian
7071 this->mapping_data->quadrature_points
7072 [this->mapping_data
7073 ->quadrature_point_offsets[cell_batch_index] +
7074 0];
7075
7077 this->mapping_data->jacobians[0][offsets + 1];
7079 for (unsigned int d = 0; d < dim; ++d)
7080 point[d] +=
7081 jac[d][d] *
7082 static_cast<Number>(
7083 this->descriptor->quadrature.point(q)[d]);
7084 else
7085 for (unsigned int d = 0; d < dim; ++d)
7086 for (unsigned int e = 0; e < dim; ++e)
7087 point[d] +=
7088 jac[d][e] *
7089 static_cast<Number>(
7090 this->descriptor->quadrature.point(q)[e]);
7091
7092 for (unsigned int i = 0; i < dim; ++i)
7093 this_quadrature_points_data[q][i][v] = point[i][lane];
7094 }
7095 else
7096 {
7097 // general case: quadrature points are available
7098 for (unsigned int i = 0; i < dim; ++i)
7099 this_quadrature_points_data[q][i][v] =
7100 this->mapping_data->quadrature_points
7101 [this->mapping_data
7102 ->quadrature_point_offsets[cell_batch_index] +
7103 q][i][lane];
7104 }
7105 }
7106 }
7107 }
7108 }
7109
7110 if constexpr (running_in_debug_mode())
7111 {
7112 this->is_reinitialized = true;
7113 this->dof_values_initialized = false;
7114 this->values_quad_initialized = false;
7115 this->gradients_quad_initialized = false;
7116 this->hessians_quad_initialized = false;
7117 }
7118}
7119
7120
7121
7122template <int dim,
7123 int fe_degree,
7124 int n_q_points_1d,
7125 int n_components_,
7126 typename Number,
7127 typename VectorizedArrayType>
7128template <bool level_dof_access>
7129inline void
7130FEEvaluation<dim,
7131 fe_degree,
7132 n_q_points_1d,
7133 n_components_,
7134 Number,
7135 VectorizedArrayType>::
7137{
7138 Assert(this->matrix_free == nullptr,
7139 ExcMessage("Cannot use initialization from cell iterator if "
7140 "initialized from MatrixFree object. Use variant for "
7141 "on the fly computation with arguments as for FEValues "
7142 "instead"));
7143 Assert(this->mapped_geometry.get() != nullptr, ExcNotInitialized());
7144 this->mapped_geometry->reinit(
7145 static_cast<typename Triangulation<dim>::cell_iterator>(cell));
7146 this->local_dof_indices.resize(cell->get_fe().n_dofs_per_cell());
7147 if (level_dof_access)
7148 cell->get_mg_dof_indices(this->local_dof_indices);
7149 else
7150 cell->get_dof_indices(this->local_dof_indices);
7151
7152 if constexpr (running_in_debug_mode())
7153 {
7154 this->is_reinitialized = true;
7155 }
7156}
7157
7158
7159
7160template <int dim,
7161 int fe_degree,
7162 int n_q_points_1d,
7163 int n_components_,
7164 typename Number,
7165 typename VectorizedArrayType>
7166inline void
7167FEEvaluation<dim,
7168 fe_degree,
7169 n_q_points_1d,
7170 n_components_,
7171 Number,
7172 VectorizedArrayType>::
7173 reinit(const typename Triangulation<dim>::cell_iterator &cell)
7174{
7175 Assert(this->matrix_free == 0,
7176 ExcMessage("Cannot use initialization from cell iterator if "
7177 "initialized from MatrixFree object. Use variant for "
7178 "on the fly computation with arguments as for FEValues "
7179 "instead"));
7180 Assert(this->mapped_geometry.get() != 0, ExcNotInitialized());
7181 this->mapped_geometry->reinit(cell);
7182
7183 if constexpr (running_in_debug_mode())
7184 {
7185 this->is_reinitialized = true;
7186 }
7187}
7188
7189
7190
7191template <int dim,
7192 int fe_degree,
7193 int n_q_points_1d,
7194 int n_components_,
7195 typename Number,
7196 typename VectorizedArrayType>
7197inline void
7198FEEvaluation<dim,
7199 fe_degree,
7200 n_q_points_1d,
7201 n_components_,
7202 Number,
7203 VectorizedArrayType>::
7204 evaluate(const EvaluationFlags::EvaluationFlags evaluation_flags)
7205{
7206 if constexpr (running_in_debug_mode())
7207 {
7208 Assert(this->dof_values_initialized == true,
7210 }
7211 evaluate(this->values_dofs, evaluation_flags);
7212}
7213
7214
7215
7216template <int dim,
7217 int fe_degree,
7218 int n_q_points_1d,
7219 int n_components_,
7220 typename Number,
7221 typename VectorizedArrayType>
7222inline void
7223FEEvaluation<dim,
7224 fe_degree,
7225 n_q_points_1d,
7226 n_components_,
7227 Number,
7228 VectorizedArrayType>::
7229 evaluate(const VectorizedArrayType *values_array,
7230 const EvaluationFlags::EvaluationFlags evaluation_flag)
7231{
7232 const bool hessians_on_general_cells =
7233 evaluation_flag & EvaluationFlags::hessians &&
7234 (this->cell_type > internal::MatrixFreeFunctions::affine);
7235 EvaluationFlags::EvaluationFlags evaluation_flag_actual = evaluation_flag;
7236 if (hessians_on_general_cells)
7237 evaluation_flag_actual |= EvaluationFlags::gradients;
7238
7239 if (this->data->element_type ==
7241 evaluation_flag & EvaluationFlags::gradients &&
7242 (this->cell_type > internal::MatrixFreeFunctions::affine))
7243 evaluation_flag_actual |= EvaluationFlags::values;
7244
7245 if constexpr (fe_degree > -1)
7246 {
7248 template run<fe_degree, n_q_points_1d>(n_components,
7249 evaluation_flag_actual,
7250 values_array,
7251 *this);
7252 }
7253 else
7254 {
7256 n_components,
7257 evaluation_flag_actual,
7258 const_cast<VectorizedArrayType *>(values_array),
7259 *this);
7260 }
7261
7262 if constexpr (running_in_debug_mode())
7263 {
7264 this->values_quad_initialized =
7265 evaluation_flag_actual & EvaluationFlags::values;
7266 this->gradients_quad_initialized =
7267 evaluation_flag_actual & EvaluationFlags::gradients;
7268 this->hessians_quad_initialized =
7269 evaluation_flag_actual & EvaluationFlags::hessians;
7270 }
7271}
7272
7273
7274namespace internal
7275{
7279 template <typename Number,
7280 typename VectorizedArrayType,
7281 typename VectorType,
7282 typename EvaluatorType,
7283 std::enable_if_t<internal::has_begin<VectorType> &&
7285 VectorType> * = nullptr>
7286 VectorizedArrayType *
7287 check_vector_access_inplace(const EvaluatorType &fe_eval, VectorType &vector)
7288 {
7289 // for user-defined cell batches this functionality is not supported
7290 if (fe_eval.get_current_cell_index() == numbers::invalid_unsigned_int)
7291 return nullptr;
7292
7293 const unsigned int cell = fe_eval.get_cell_or_face_batch_id();
7294 const auto &dof_info = fe_eval.get_dof_info();
7295
7296 // If the index storage is interleaved and contiguous and the vector
7297 // storage has the correct alignment, we can directly pass the pointer
7298 // into the vector to the evaluate() and integrate() calls, without
7299 // reading the vector entries into a separate data field. This saves some
7300 // operations.
7301 if (std::is_same_v<typename VectorType::value_type, Number> &&
7302 dof_info.index_storage_variants
7305 interleaved_contiguous &&
7306 reinterpret_cast<std::size_t>(
7307 vector.begin() +
7308 dof_info.dof_indices_contiguous
7309 [internal::MatrixFreeFunctions::DoFInfo::dof_access_cell]
7310 [cell * VectorizedArrayType::size()]) %
7311 sizeof(VectorizedArrayType) ==
7312 0)
7313 {
7314 return reinterpret_cast<VectorizedArrayType *>(
7315 vector.begin() +
7316 dof_info.dof_indices_contiguous
7318 [cell * VectorizedArrayType::size()] +
7320 [fe_eval.get_active_fe_index()]
7321 [fe_eval.get_first_selected_component()] *
7322 VectorizedArrayType::size());
7323 }
7324 else
7325 return nullptr;
7326 }
7327
7331 template <typename Number,
7332 typename VectorizedArrayType,
7333 typename VectorType,
7334 typename EvaluatorType,
7335 std::enable_if_t<!internal::has_begin<VectorType> ||
7337 VectorType> * = nullptr>
7338 VectorizedArrayType *
7339 check_vector_access_inplace(const EvaluatorType &, VectorType &)
7340 {
7341 return nullptr;
7342 }
7343} // namespace internal
7344
7345
7346
7347template <int dim,
7348 int fe_degree,
7349 int n_q_points_1d,
7350 int n_components_,
7351 typename Number,
7352 typename VectorizedArrayType>
7353template <typename VectorType>
7354inline void
7355FEEvaluation<dim,
7356 fe_degree,
7357 n_q_points_1d,
7358 n_components_,
7359 Number,
7360 VectorizedArrayType>::
7361 gather_evaluate(const VectorType &input_vector,
7362 const EvaluationFlags::EvaluationFlags evaluation_flag)
7363{
7364 const VectorizedArrayType *src_ptr =
7365 internal::check_vector_access_inplace<Number, const VectorizedArrayType>(
7366 *this, input_vector);
7367 if (src_ptr != nullptr)
7368 evaluate(src_ptr, evaluation_flag);
7369 else
7370 {
7371 this->read_dof_values(input_vector);
7372 evaluate(this->begin_dof_values(), evaluation_flag);
7373 }
7374}
7375
7376
7377
7378template <int dim,
7379 int fe_degree,
7380 int n_q_points_1d,
7381 int n_components_,
7382 typename Number,
7383 typename VectorizedArrayType>
7384inline void
7385FEEvaluation<dim,
7386 fe_degree,
7387 n_q_points_1d,
7388 n_components_,
7389 Number,
7390 VectorizedArrayType>::
7391 integrate(const EvaluationFlags::EvaluationFlags integration_flag)
7392{
7393 integrate(integration_flag, this->values_dofs);
7394
7395 if constexpr (running_in_debug_mode())
7396 {
7397 this->dof_values_initialized = true;
7398 }
7399}
7400
7401
7402
7403template <int dim,
7404 int fe_degree,
7405 int n_q_points_1d,
7406 int n_components_,
7407 typename Number,
7408 typename VectorizedArrayType>
7409inline void
7410FEEvaluation<dim,
7411 fe_degree,
7412 n_q_points_1d,
7413 n_components_,
7414 Number,
7415 VectorizedArrayType>::
7416 integrate(const EvaluationFlags::EvaluationFlags integration_flag,
7417 VectorizedArrayType *values_array,
7418 const bool sum_into_values_array)
7419{
7420 if constexpr (running_in_debug_mode())
7421 {
7422 if (integration_flag & EvaluationFlags::values)
7423 Assert(this->values_quad_submitted == true,
7425 if (integration_flag & EvaluationFlags::gradients)
7426 Assert(this->gradients_quad_submitted == true,
7428 if ((integration_flag & EvaluationFlags::hessians) != 0u)
7429 Assert(this->hessians_quad_submitted == true,
7431 }
7432 Assert(this->matrix_free != nullptr ||
7433 this->mapped_geometry->is_initialized(),
7435
7436 Assert(
7437 (integration_flag & ~(EvaluationFlags::values | EvaluationFlags::gradients |
7439 ExcMessage("Only EvaluationFlags::values, EvaluationFlags::gradients, and "
7440 "EvaluationFlags::hessians are supported."));
7441
7442 EvaluationFlags::EvaluationFlags integration_flag_actual = integration_flag;
7443 if (integration_flag & EvaluationFlags::hessians &&
7444 (this->cell_type > internal::MatrixFreeFunctions::affine))
7445 {
7446 unsigned int size = n_components * dim * n_q_points;
7447 if ((integration_flag & EvaluationFlags::gradients) != 0u)
7448 {
7449 for (unsigned int i = 0; i < size; ++i)
7450 this->gradients_quad[i] += this->gradients_from_hessians_quad[i];
7451 }
7452 else
7453 {
7454 for (unsigned int i = 0; i < size; ++i)
7455 this->gradients_quad[i] = this->gradients_from_hessians_quad[i];
7456 integration_flag_actual |= EvaluationFlags::gradients;
7457 }
7458 }
7459
7460 if (n_components == dim &&
7461 this->data->element_type ==
7463 integration_flag & EvaluationFlags::gradients &&
7464 this->cell_type > internal::MatrixFreeFunctions::affine &&
7465 this->divergence_is_requested == false)
7466 {
7467 unsigned int size = n_components * n_q_points;
7468 if ((integration_flag & EvaluationFlags::values) != 0u)
7469 {
7470 for (unsigned int i = 0; i < size; ++i)
7471 this->values_quad[i] += this->values_from_gradients_quad[i];
7472 }
7473 else
7474 {
7475 for (unsigned int i = 0; i < size; ++i)
7476 this->values_quad[i] = this->values_from_gradients_quad[i];
7477 integration_flag_actual |= EvaluationFlags::values;
7478 }
7479 }
7480
7481 if constexpr (fe_degree > -1)
7482 {
7484 template run<fe_degree, n_q_points_1d>(n_components,
7485 integration_flag_actual,
7486 values_array,
7487 *this,
7488 sum_into_values_array);
7489 }
7490 else
7491 {
7493 n_components,
7494 integration_flag_actual,
7495 values_array,
7496 *this,
7497 sum_into_values_array);
7498 }
7499
7500 if constexpr (running_in_debug_mode())
7501 {
7502 this->dof_values_initialized = true;
7503 }
7504}
7505
7506
7507
7508template <int dim,
7509 int fe_degree,
7510 int n_q_points_1d,
7511 int n_components_,
7512 typename Number,
7513 typename VectorizedArrayType>
7514template <typename VectorType>
7515inline void
7516FEEvaluation<dim,
7517 fe_degree,
7518 n_q_points_1d,
7519 n_components_,
7520 Number,
7521 VectorizedArrayType>::
7522 integrate_scatter(const EvaluationFlags::EvaluationFlags integration_flag,
7523 VectorType &destination)
7524{
7525 VectorizedArrayType *dst_ptr =
7526 internal::check_vector_access_inplace<Number, VectorizedArrayType>(
7527 *this, destination);
7528 if (dst_ptr != nullptr)
7529 integrate(integration_flag, dst_ptr, true);
7530 else
7531 {
7532 integrate(integration_flag, this->begin_dof_values());
7533 this->distribute_local_to_global(destination);
7534 }
7535}
7536
7537
7538
7539template <int dim,
7540 int fe_degree,
7541 int n_q_points_1d,
7542 int n_components_,
7543 typename Number,
7544 typename VectorizedArrayType>
7546FEEvaluation<dim,
7547 fe_degree,
7548 n_q_points_1d,
7549 n_components_,
7550 Number,
7551 VectorizedArrayType>::dof_indices() const
7552{
7554 0U, dofs_per_cell);
7555}
7556
7557
7558
7559/*-------------------------- FEFaceEvaluation ---------------------------*/
7560
7561
7562
7563template <int dim,
7564 int fe_degree,
7565 int n_q_points_1d,
7566 int n_components_,
7567 typename Number,
7568 typename VectorizedArrayType>
7569inline FEFaceEvaluation<dim,
7570 fe_degree,
7571 n_q_points_1d,
7572 n_components_,
7573 Number,
7574 VectorizedArrayType>::
7575 FEFaceEvaluation(
7577 const bool is_interior_face,
7578 const unsigned int dof_handler_index,
7579 const unsigned int quadrature_index,
7580 const unsigned int first_selected_component,
7581 const unsigned int active_fe_index,
7582 const unsigned int active_quad_index,
7583 const unsigned int face_type)
7584 : BaseClass(matrix_free,
7585 dof_handler_index,
7586 first_selected_component,
7587 quadrature_index,
7588 fe_degree,
7589 static_n_q_points,
7590 is_interior_face,
7591 active_fe_index,
7592 active_quad_index,
7593 face_type)
7594 , dofs_per_component(this->data->dofs_per_component_on_cell)
7595 , dofs_per_cell(this->data->dofs_per_component_on_cell * n_components_)
7596 , n_q_points(this->n_quadrature_points)
7597{}
7598
7599
7600
7601template <int dim,
7602 int fe_degree,
7603 int n_q_points_1d,
7604 int n_components_,
7605 typename Number,
7606 typename VectorizedArrayType>
7607inline FEFaceEvaluation<dim,
7608 fe_degree,
7609 n_q_points_1d,
7610 n_components_,
7611 Number,
7612 VectorizedArrayType>::
7613 FEFaceEvaluation(
7615 const std::pair<unsigned int, unsigned int> &range,
7616 const bool is_interior_face,
7617 const unsigned int dof_handler_index,
7618 const unsigned int quadrature_index,
7619 const unsigned int first_selected_component)
7620 : FEFaceEvaluation(matrix_free,
7621 is_interior_face,
7622 dof_handler_index,
7623 quadrature_index,
7624 first_selected_component,
7625 matrix_free.get_face_active_fe_index(range,
7626 is_interior_face),
7628 matrix_free.get_face_info(range.first).face_type)
7629{}
7630
7631
7632
7633template <int dim,
7634 int fe_degree,
7635 int n_q_points_1d,
7636 int n_components_,
7637 typename Number,
7638 typename VectorizedArrayType>
7639inline void
7641 fe_degree,
7642 n_q_points_1d,
7643 n_components_,
7644 Number,
7645 VectorizedArrayType>::reinit(const unsigned int face_index)
7646{
7647 Assert(this->mapped_geometry == nullptr,
7648 ExcMessage("FEEvaluation was initialized without a matrix-free object."
7649 " Integer indexing is not possible"));
7650 if (this->mapped_geometry != nullptr)
7651 return;
7652
7653 this->cell = face_index;
7654 this->dof_access_index =
7655 this->is_interior_face() ?
7658 Assert(this->mapping_data != nullptr, ExcNotInitialized());
7659
7660 if (face_index >=
7661 this->matrix_free->get_task_info().face_partition_data.back() &&
7662 face_index <
7663 this->matrix_free->get_task_info().boundary_partition_data.back())
7664 Assert(this->is_interior_face(),
7665 ExcMessage(
7666 "Boundary faces do not have a neighbor. When looping over "
7667 "boundary faces use FEFaceEvaluation with the parameter "
7668 "is_interior_face set to true. "));
7669
7670 this->reinit_face(this->matrix_free->get_face_info(face_index));
7671
7672 unsigned int i = 0;
7673 for (; i < this->matrix_free->n_active_entries_per_face_batch(this->cell);
7674 ++i)
7675 this->face_ids[i] = face_index * n_lanes + i;
7676 for (; i < n_lanes; ++i)
7677 this->face_ids[i] = numbers::invalid_unsigned_int;
7678
7679 this->cell_type = this->matrix_free->get_mapping_info().face_type[face_index];
7680 const unsigned int offsets =
7681 this->mapping_data->data_index_offsets[face_index];
7682 this->J_value = &this->mapping_data->JxW_values[offsets];
7683 this->normal_vectors = &this->mapping_data->normal_vectors[offsets];
7684 this->jacobian =
7685 &this->mapping_data->jacobians[!this->is_interior_face()][offsets];
7686 this->normal_x_jacobian =
7687 &this->mapping_data
7688 ->normals_times_jacobians[!this->is_interior_face()][offsets];
7689 this->jacobian_gradients =
7690 this->mapping_data->jacobian_gradients[!this->is_interior_face()].data() +
7691 offsets;
7692 this->jacobian_gradients_non_inverse =
7693 this->mapping_data
7694 ->jacobian_gradients_non_inverse[!this->is_interior_face()]
7695 .data() +
7696 offsets;
7697
7698 if (this->mapping_data->quadrature_point_offsets.empty() == false)
7699 {
7700 AssertIndexRange(this->cell,
7701 this->mapping_data->quadrature_point_offsets.size());
7702 this->quadrature_points =
7703 this->mapping_data->quadrature_points.data() +
7704 this->mapping_data->quadrature_point_offsets[this->cell];
7705 }
7706
7707 if constexpr (running_in_debug_mode())
7708 {
7709 this->is_reinitialized = true;
7710 this->dof_values_initialized = false;
7711 this->values_quad_initialized = false;
7712 this->gradients_quad_initialized = false;
7713 this->hessians_quad_initialized = false;
7714 }
7715}
7716
7717
7718
7719template <int dim,
7720 int fe_degree,
7721 int n_q_points_1d,
7722 int n_components_,
7723 typename Number,
7724 typename VectorizedArrayType>
7725inline void
7727 fe_degree,
7728 n_q_points_1d,
7729 n_components_,
7730 Number,
7731 VectorizedArrayType>::reinit(const unsigned int cell_index,
7732 const unsigned int face_number)
7733{
7734 Assert(
7735 this->quadrature_index <
7736 this->matrix_free->get_mapping_info().face_data_by_cells.size(),
7737 ExcMessage(
7738 "You must set MatrixFree::AdditionalData::mapping_update_flags_faces_by_cells to use the present reinit method."));
7741 this->matrix_free->get_mapping_info().cell_type.size());
7742 Assert(this->mapped_geometry == nullptr,
7743 ExcMessage("FEEvaluation was initialized without a matrix-free object."
7744 " Integer indexing is not possible"));
7745 if (this->mapped_geometry != nullptr)
7746 return;
7747 Assert(this->matrix_free != nullptr, ExcNotInitialized());
7748
7749 this->cell_type = this->matrix_free->get_mapping_info()
7750 .faces_by_cells_type[cell_index][face_number];
7751 this->cell = cell_index;
7752 this->subface_index = GeometryInfo<dim>::max_children_per_cell;
7753 this->dof_access_index =
7755
7756 if (this->is_interior_face() == false)
7757 {
7758 // for this case, we need to look into the FaceInfo field that collects
7759 // information from both sides of a face once for the global mesh, and
7760 // pick the face id that is not the local one (cell_this).
7761 for (unsigned int i = 0; i < n_lanes; ++i)
7762 {
7763 // compute actual (non vectorized) cell ID
7764 const unsigned int cell_this = cell_index * n_lanes + i;
7765 // compute face ID
7766 unsigned int face_index =
7767 this->matrix_free->get_cell_and_face_to_plain_faces()(cell_index,
7768 face_number,
7769 i);
7770
7771 this->face_ids[i] = face_index;
7772
7773 if (face_index == numbers::invalid_unsigned_int)
7774 {
7775 this->cell_ids[i] = numbers::invalid_unsigned_int;
7776 this->face_numbers[i] = static_cast<std::uint8_t>(-1);
7777 this->face_orientations[i] =
7779 continue; // invalid face ID: no neighbor on boundary
7780 }
7781
7782 const auto &faces =
7783 this->matrix_free->get_face_info(face_index / n_lanes);
7784 // get cell ID on both sides of face
7785 auto cell_m = faces.cells_interior[face_index % n_lanes];
7786 auto cell_p = faces.cells_exterior[face_index % n_lanes];
7787
7788 const bool face_identifies_as_interior = cell_m != cell_this;
7789
7790 Assert(cell_m == cell_this || cell_p == cell_this,
7792
7793 // compare the IDs with the given cell ID
7794 if (face_identifies_as_interior)
7795 {
7796 this->cell_ids[i] = cell_m; // neighbor has the other ID
7797 this->face_numbers[i] = faces.interior_face_no;
7798 }
7799 else
7800 {
7801 this->cell_ids[i] = cell_p;
7802 this->face_numbers[i] = faces.exterior_face_no;
7803 }
7804
7805 const bool orientation_interior_face = faces.face_orientation >= 8;
7806 types::geometric_orientation face_orientation =
7807 faces.face_orientation % 8;
7808 if (face_identifies_as_interior != orientation_interior_face)
7809 {
7810 Assert(this->matrix_free->get_cell_iterator(cell_index, i)
7811 ->reference_cell() ==
7812 ReferenceCells::get_hypercube<dim>(),
7814 face_orientation =
7816 .get_inverse_combined_orientation(face_orientation);
7817 }
7818 this->face_orientations[i] = face_orientation;
7819 }
7820 }
7821 else
7822 {
7823 this->face_orientations[0] = numbers::default_geometric_orientation;
7824 this->face_numbers[0] = face_number;
7825 if (this->matrix_free->n_active_entries_per_cell_batch(this->cell) ==
7826 n_lanes)
7827 {
7829 for (unsigned int i = 0; i < n_lanes; ++i)
7830 this->cell_ids[i] = cell_index * n_lanes + i;
7831 }
7832 else
7833 {
7834 unsigned int i = 0;
7835 for (; i <
7836 this->matrix_free->n_active_entries_per_cell_batch(this->cell);
7837 ++i)
7838 this->cell_ids[i] = cell_index * n_lanes + i;
7839 for (; i < n_lanes; ++i)
7840 this->cell_ids[i] = numbers::invalid_unsigned_int;
7841 }
7842 for (unsigned int i = 0; i < n_lanes; ++i)
7843 this->face_ids[i] =
7844 this->matrix_free->get_cell_and_face_to_plain_faces()(cell_index,
7845 face_number,
7846 i);
7847 }
7848
7849 const unsigned int offsets =
7850 this->matrix_free->get_mapping_info()
7851 .face_data_by_cells[this->quadrature_index]
7852 .data_index_offsets[cell_index * GeometryInfo<dim>::faces_per_cell +
7853 face_number];
7854 AssertIndexRange(offsets,
7855 this->matrix_free->get_mapping_info()
7856 .face_data_by_cells[this->quadrature_index]
7857 .JxW_values.size());
7858 this->J_value = &this->matrix_free->get_mapping_info()
7859 .face_data_by_cells[this->quadrature_index]
7860 .JxW_values[offsets];
7861 this->normal_vectors = &this->matrix_free->get_mapping_info()
7862 .face_data_by_cells[this->quadrature_index]
7863 .normal_vectors[offsets];
7864 this->jacobian = &this->matrix_free->get_mapping_info()
7865 .face_data_by_cells[this->quadrature_index]
7866 .jacobians[!this->is_interior_face()][offsets];
7867 this->normal_x_jacobian =
7868 &this->matrix_free->get_mapping_info()
7869 .face_data_by_cells[this->quadrature_index]
7870 .normals_times_jacobians[!this->is_interior_face()][offsets];
7871 this->jacobian_gradients =
7872 this->mapping_data->jacobian_gradients[!this->is_interior_face()].data() +
7873 offsets;
7874 this->jacobian_gradients_non_inverse =
7875 this->mapping_data
7876 ->jacobian_gradients_non_inverse[!this->is_interior_face()]
7877 .data() +
7878 offsets;
7879
7880 if (this->matrix_free->get_mapping_info()
7881 .face_data_by_cells[this->quadrature_index]
7882 .quadrature_point_offsets.empty() == false)
7883 {
7884 const unsigned int index =
7885 this->cell * GeometryInfo<dim>::faces_per_cell + this->face_numbers[0];
7887 this->matrix_free->get_mapping_info()
7888 .face_data_by_cells[this->quadrature_index]
7889 .quadrature_point_offsets.size());
7890 this->quadrature_points = this->matrix_free->get_mapping_info()
7891 .face_data_by_cells[this->quadrature_index]
7892 .quadrature_points.data() +
7893 this->matrix_free->get_mapping_info()
7894 .face_data_by_cells[this->quadrature_index]
7895 .quadrature_point_offsets[index];
7896 }
7897
7898 if constexpr (running_in_debug_mode())
7899 {
7900 this->is_reinitialized = true;
7901 this->dof_values_initialized = false;
7902 this->values_quad_initialized = false;
7903 this->gradients_quad_initialized = false;
7904 this->hessians_quad_initialized = false;
7905 }
7906}
7907
7908
7909
7910template <int dim,
7911 int fe_degree,
7912 int n_q_points_1d,
7913 int n_components_,
7914 typename Number,
7915 typename VectorizedArrayType>
7916inline void
7918 fe_degree,
7919 n_q_points_1d,
7920 n_components_,
7921 Number,
7922 VectorizedArrayType>::
7923 evaluate(const EvaluationFlags::EvaluationFlags evaluation_flag)
7924{
7925 if constexpr (running_in_debug_mode())
7926 {
7927 Assert(this->dof_values_initialized, ExcNotInitialized());
7928 }
7929
7930 evaluate(this->values_dofs, evaluation_flag);
7931}
7932
7933
7934
7935template <int dim,
7936 int fe_degree,
7937 int n_q_points_1d,
7938 int n_components_,
7939 typename Number,
7940 typename VectorizedArrayType>
7941inline void
7943 fe_degree,
7944 n_q_points_1d,
7945 n_components_,
7946 Number,
7947 VectorizedArrayType>::
7948 evaluate(const VectorizedArrayType *values_array,
7949 const EvaluationFlags::EvaluationFlags evaluation_flag)
7950{
7951 Assert((evaluation_flag &
7954 ExcMessage("Only EvaluationFlags::values, EvaluationFlags::gradients, "
7955 "and EvaluationFlags::hessians are supported."));
7956
7957 const bool hessians_on_general_cells =
7958 evaluation_flag & EvaluationFlags::hessians &&
7959 (this->cell_type > internal::MatrixFreeFunctions::affine);
7960 EvaluationFlags::EvaluationFlags evaluation_flag_actual = evaluation_flag;
7961 if (hessians_on_general_cells)
7962 evaluation_flag_actual |= EvaluationFlags::gradients;
7963
7964 if (this->data->element_type ==
7966 evaluation_flag & EvaluationFlags::gradients &&
7967 (this->cell_type > internal::MatrixFreeFunctions::affine))
7968 evaluation_flag_actual |= EvaluationFlags::values;
7969
7970 if constexpr (fe_degree > -1)
7972 template run<fe_degree, n_q_points_1d>(n_components,
7973 evaluation_flag_actual,
7974 values_array,
7975 *this);
7976 else
7978 n_components, evaluation_flag_actual, values_array, *this);
7979
7980 if constexpr (running_in_debug_mode())
7981 {
7982 this->values_quad_initialized =
7983 evaluation_flag_actual & EvaluationFlags::values;
7984 this->gradients_quad_initialized =
7985 evaluation_flag_actual & EvaluationFlags::gradients;
7986 this->hessians_quad_initialized =
7987 evaluation_flag_actual & EvaluationFlags::hessians;
7988 }
7989}
7990
7991
7992
7993template <int dim,
7994 int fe_degree,
7995 int n_q_points_1d,
7996 int n_components_,
7997 typename Number,
7998 typename VectorizedArrayType>
7999inline void
8001 fe_degree,
8002 n_q_points_1d,
8003 n_components_,
8004 Number,
8005 VectorizedArrayType>::
8006 project_to_face(const EvaluationFlags::EvaluationFlags evaluation_flag)
8007{
8008 if constexpr (running_in_debug_mode())
8009 {
8010 Assert(this->dof_values_initialized, ExcNotInitialized());
8011 }
8012
8013 project_to_face(this->values_dofs, evaluation_flag);
8014}
8015
8016
8017
8018template <int dim,
8019 int fe_degree,
8020 int n_q_points_1d,
8021 int n_components_,
8022 typename Number,
8023 typename VectorizedArrayType>
8024inline void
8026 fe_degree,
8027 n_q_points_1d,
8028 n_components_,
8029 Number,
8030 VectorizedArrayType>::
8031 project_to_face(const VectorizedArrayType *values_array,
8032 const EvaluationFlags::EvaluationFlags evaluation_flag)
8033{
8034 Assert((evaluation_flag &
8037 ExcMessage("Only EvaluationFlags::values, EvaluationFlags::gradients, "
8038 "and EvaluationFlags::hessians are supported."));
8039
8040 const bool hessians_on_general_cells =
8041 evaluation_flag & EvaluationFlags::hessians &&
8042 (this->cell_type > internal::MatrixFreeFunctions::affine);
8043 EvaluationFlags::EvaluationFlags evaluation_flag_actual = evaluation_flag;
8044 if (hessians_on_general_cells)
8045 evaluation_flag_actual |= EvaluationFlags::gradients;
8046
8047 if (this->data->element_type ==
8049 evaluation_flag & EvaluationFlags::gradients &&
8050 (this->cell_type > internal::MatrixFreeFunctions::affine))
8051 evaluation_flag_actual |= EvaluationFlags::values;
8052
8053 if constexpr (fe_degree > -1)
8055 dim,
8056 VectorizedArrayType>::template run<fe_degree>(n_components,
8057 evaluation_flag_actual,
8058 values_array,
8059 *this);
8060 else
8062 project_to_face(n_components,
8063 evaluation_flag_actual,
8064 values_array,
8065 *this);
8066
8067 // face dofs initialized
8068}
8069
8070
8071
8072template <int dim,
8073 int fe_degree,
8074 int n_q_points_1d,
8075 int n_components_,
8076 typename Number,
8077 typename VectorizedArrayType>
8078inline void
8080 fe_degree,
8081 n_q_points_1d,
8082 n_components_,
8083 Number,
8084 VectorizedArrayType>::
8085 evaluate_in_face(const EvaluationFlags::EvaluationFlags evaluation_flag)
8086{
8087 Assert((evaluation_flag &
8090 ExcMessage("Only EvaluationFlags::values, EvaluationFlags::gradients, "
8091 "and EvaluationFlags::hessians are supported."));
8092
8093 const bool hessians_on_general_cells =
8094 evaluation_flag & EvaluationFlags::hessians &&
8095 (this->cell_type > internal::MatrixFreeFunctions::affine);
8096 EvaluationFlags::EvaluationFlags evaluation_flag_actual = evaluation_flag;
8097 if (hessians_on_general_cells)
8098 evaluation_flag_actual |= EvaluationFlags::gradients;
8099
8100 if (this->data->element_type ==
8102 evaluation_flag & EvaluationFlags::gradients &&
8103 (this->cell_type > internal::MatrixFreeFunctions::affine))
8104 evaluation_flag_actual |= EvaluationFlags::values;
8105
8106 if constexpr (fe_degree > -1)
8108 dim,
8109 VectorizedArrayType>::template run<fe_degree>(n_components,
8110 evaluation_flag_actual,
8111 *this);
8112 else
8114 evaluate_in_face(n_components, evaluation_flag_actual, *this);
8115
8116 if constexpr (running_in_debug_mode())
8117 {
8118 this->values_quad_initialized =
8119 evaluation_flag_actual & EvaluationFlags::values;
8120 this->gradients_quad_initialized =
8121 evaluation_flag_actual & EvaluationFlags::gradients;
8122 this->hessians_quad_initialized =
8123 evaluation_flag_actual & EvaluationFlags::hessians;
8124 }
8125}
8126
8127
8128
8129template <int dim,
8130 int fe_degree,
8131 int n_q_points_1d,
8132 int n_components_,
8133 typename Number,
8134 typename VectorizedArrayType>
8135inline void
8137 fe_degree,
8138 n_q_points_1d,
8139 n_components_,
8140 Number,
8141 VectorizedArrayType>::
8142 integrate(const EvaluationFlags::EvaluationFlags integration_flag,
8143 const bool sum_into_values)
8144{
8145 integrate(integration_flag, this->values_dofs, sum_into_values);
8146
8147 if constexpr (running_in_debug_mode())
8148 {
8149 this->dof_values_initialized = true;
8150 }
8151}
8152
8153
8154
8155template <int dim,
8156 int fe_degree,
8157 int n_q_points_1d,
8158 int n_components_,
8159 typename Number,
8160 typename VectorizedArrayType>
8161inline void
8163 fe_degree,
8164 n_q_points_1d,
8165 n_components_,
8166 Number,
8167 VectorizedArrayType>::
8168 integrate(const EvaluationFlags::EvaluationFlags integration_flag,
8169 VectorizedArrayType *values_array,
8170 const bool sum_into_values)
8171{
8172 Assert((integration_flag &
8175 ExcMessage("Only EvaluationFlags::values, EvaluationFlags::gradients, "
8176 "and EvaluationFlags::hessians are supported."));
8177
8178 EvaluationFlags::EvaluationFlags integration_flag_actual = integration_flag;
8179 if (integration_flag & EvaluationFlags::hessians &&
8180 (this->cell_type > internal::MatrixFreeFunctions::affine))
8181 {
8182 unsigned int size = n_components * dim * n_q_points;
8183 if ((integration_flag & EvaluationFlags::gradients) != 0u)
8184 {
8185 for (unsigned int i = 0; i < size; ++i)
8186 this->gradients_quad[i] += this->gradients_from_hessians_quad[i];
8187 }
8188 else
8189 {
8190 for (unsigned int i = 0; i < size; ++i)
8191 this->gradients_quad[i] = this->gradients_from_hessians_quad[i];
8192 integration_flag_actual |= EvaluationFlags::gradients;
8193 }
8194 }
8195
8196 if (this->data->element_type ==
8198 integration_flag & EvaluationFlags::gradients &&
8199 this->cell_type > internal::MatrixFreeFunctions::affine &&
8200 this->divergence_is_requested == false)
8201 {
8202 unsigned int size = n_components * n_q_points;
8203 if ((integration_flag & EvaluationFlags::values) != 0u)
8204 {
8205 for (unsigned int i = 0; i < size; ++i)
8206 this->values_quad[i] += this->values_from_gradients_quad[i];
8207 }
8208 else
8209 {
8210 for (unsigned int i = 0; i < size; ++i)
8211 this->values_quad[i] = this->values_from_gradients_quad[i];
8212 integration_flag_actual |= EvaluationFlags::values;
8213 }
8214 }
8215
8216 if constexpr (fe_degree > -1)
8218 template run<fe_degree, n_q_points_1d>(n_components,
8219 integration_flag_actual,
8220 values_array,
8221 *this,
8222 sum_into_values);
8223 else
8225 n_components,
8226 integration_flag_actual,
8227 values_array,
8228 *this,
8229 sum_into_values);
8230}
8231
8232
8233
8234template <int dim,
8235 int fe_degree,
8236 int n_q_points_1d,
8237 int n_components_,
8238 typename Number,
8239 typename VectorizedArrayType>
8240inline void
8242 fe_degree,
8243 n_q_points_1d,
8244 n_components_,
8245 Number,
8246 VectorizedArrayType>::
8247 integrate_in_face(const EvaluationFlags::EvaluationFlags integration_flag)
8248{
8249 Assert((integration_flag &
8252 ExcMessage("Only EvaluationFlags::values, EvaluationFlags::gradients, "
8253 "and EvaluationFlags::hessians are supported."));
8254
8255 EvaluationFlags::EvaluationFlags integration_flag_actual = integration_flag;
8256 if (integration_flag & EvaluationFlags::hessians &&
8257 (this->cell_type > internal::MatrixFreeFunctions::affine))
8258 {
8259 unsigned int size = n_components * dim * n_q_points;
8260 if ((integration_flag & EvaluationFlags::gradients) != 0u)
8261 {
8262 for (unsigned int i = 0; i < size; ++i)
8263 this->gradients_quad[i] += this->gradients_from_hessians_quad[i];
8264 }
8265 else
8266 {
8267 for (unsigned int i = 0; i < size; ++i)
8268 this->gradients_quad[i] = this->gradients_from_hessians_quad[i];
8269 integration_flag_actual |= EvaluationFlags::gradients;
8270 }
8271 }
8272
8273 if (this->data->element_type ==
8275 integration_flag & EvaluationFlags::gradients &&
8276 this->cell_type > internal::MatrixFreeFunctions::affine &&
8277 this->divergence_is_requested == false)
8278 {
8279 unsigned int size = n_components * n_q_points;
8280 if ((integration_flag & EvaluationFlags::values) != 0u)
8281 {
8282 for (unsigned int i = 0; i < size; ++i)
8283 this->values_quad[i] += this->values_from_gradients_quad[i];
8284 }
8285 else
8286 {
8287 for (unsigned int i = 0; i < size; ++i)
8288 this->values_quad[i] = this->values_from_gradients_quad[i];
8289 integration_flag_actual |= EvaluationFlags::values;
8290 }
8291 }
8292
8293 if constexpr (fe_degree > -1)
8295 dim,
8296 VectorizedArrayType>::template run<fe_degree>(n_components,
8297 integration_flag_actual,
8298 *this);
8299 else
8301 integrate_in_face(n_components, integration_flag_actual, *this);
8302
8303 // face dofs initialized
8304}
8305
8306
8307
8308template <int dim,
8309 int fe_degree,
8310 int n_q_points_1d,
8311 int n_components_,
8312 typename Number,
8313 typename VectorizedArrayType>
8314inline void
8316 fe_degree,
8317 n_q_points_1d,
8318 n_components_,
8319 Number,
8320 VectorizedArrayType>::
8321 collect_from_face(const EvaluationFlags::EvaluationFlags integration_flag,
8322 const bool sum_into_values)
8323{
8324 collect_from_face(integration_flag, this->values_dofs, sum_into_values);
8325
8326 if constexpr (running_in_debug_mode())
8327 {
8328 this->dof_values_initialized = true;
8329 }
8330}
8331
8332
8333
8334template <int dim,
8335 int fe_degree,
8336 int n_q_points_1d,
8337 int n_components_,
8338 typename Number,
8339 typename VectorizedArrayType>
8340inline void
8342 fe_degree,
8343 n_q_points_1d,
8344 n_components_,
8345 Number,
8346 VectorizedArrayType>::
8347 collect_from_face(const EvaluationFlags::EvaluationFlags integration_flag,
8348 VectorizedArrayType *values_array,
8349 const bool sum_into_values)
8350{
8351 Assert((integration_flag &
8354 ExcMessage("Only EvaluationFlags::values, EvaluationFlags::gradients, "
8355 "and EvaluationFlags::hessians are supported."));
8356
8357 EvaluationFlags::EvaluationFlags integration_flag_actual = integration_flag;
8358 if (integration_flag & EvaluationFlags::hessians &&
8359 (this->cell_type > internal::MatrixFreeFunctions::affine))
8360 integration_flag_actual |= EvaluationFlags::gradients;
8361
8362 if (this->data->element_type ==
8364 integration_flag & EvaluationFlags::gradients &&
8365 this->cell_type > internal::MatrixFreeFunctions::affine &&
8366 this->divergence_is_requested == false)
8367 integration_flag_actual |= EvaluationFlags::values;
8368
8369 if constexpr (fe_degree > -1)
8371 dim,
8372 VectorizedArrayType>::template run<fe_degree>(n_components,
8373 integration_flag_actual,
8374 values_array,
8375 *this,
8376 sum_into_values);
8377 else
8379 collect_from_face(n_components,
8380 integration_flag_actual,
8381 values_array,
8382 *this,
8383 sum_into_values);
8384}
8385
8386
8387
8388template <int dim,
8389 int fe_degree,
8390 int n_q_points_1d,
8391 int n_components_,
8392 typename Number,
8393 typename VectorizedArrayType>
8394template <typename VectorType>
8395inline void
8397 fe_degree,
8398 n_q_points_1d,
8399 n_components_,
8400 Number,
8401 VectorizedArrayType>::
8402 gather_evaluate(const VectorType &input_vector,
8403 const EvaluationFlags::EvaluationFlags evaluation_flag)
8404{
8405 Assert((evaluation_flag &
8408 ExcMessage("Only EvaluationFlags::values, EvaluationFlags::gradients, "
8409 "and EvaluationFlags::hessians are supported."));
8410
8411 const auto shared_vector_data = internal::get_shared_vector_data(
8412 &input_vector,
8413 this->dof_access_index ==
8415 this->active_fe_index,
8416 this->dof_info);
8417
8418 if (this->data->data.front().fe_degree > 0 &&
8419 fast_evaluation_supported(this->data->data.front().fe_degree,
8420 this->data->data.front().n_q_points_1d) &&
8422 dim,
8423 typename VectorType::value_type,
8424 VectorizedArrayType>::
8425 supports(evaluation_flag,
8426 *this->data,
8427 internal::get_beginning<typename VectorType::value_type>(
8428 input_vector),
8429 this->dof_info->index_storage_variants[this->dof_access_index]
8430 [this->cell]))
8431 {
8432 if constexpr (fe_degree > -1)
8433 {
8435 dim,
8436 typename VectorType::value_type,
8437 VectorizedArrayType>::template run<fe_degree,
8438 n_q_points_1d>(
8439 n_components,
8440 evaluation_flag,
8441 internal::get_beginning<typename VectorType::value_type>(
8442 input_vector),
8443 shared_vector_data,
8444 *this);
8445 }
8446 else
8447 {
8449 dim,
8450 typename VectorType::value_type,
8451 VectorizedArrayType>::evaluate(n_components,
8452 evaluation_flag,
8453 internal::get_beginning<
8454 typename VectorType::value_type>(
8455 input_vector),
8456 shared_vector_data,
8457 *this);
8458 }
8459 }
8460 else
8461 {
8462 this->read_dof_values(input_vector);
8463 this->evaluate(evaluation_flag);
8464 }
8465
8466 if constexpr (running_in_debug_mode())
8467 {
8468 this->values_quad_initialized = evaluation_flag & EvaluationFlags::values;
8469 this->gradients_quad_initialized =
8470 evaluation_flag & EvaluationFlags::gradients;
8471 this->hessians_quad_initialized =
8472 evaluation_flag & EvaluationFlags::hessians;
8473 }
8474}
8475
8476
8477
8478template <int dim,
8479 int fe_degree,
8480 int n_q_points_1d,
8481 int n_components_,
8482 typename Number,
8483 typename VectorizedArrayType>
8484template <typename VectorType>
8485inline void
8487 dim,
8488 fe_degree,
8489 n_q_points_1d,
8490 n_components_,
8491 Number,
8492 VectorizedArrayType>::integrate_scatter(const bool integrate_values,
8493 const bool integrate_gradients,
8494 VectorType &destination)
8495{
8497 ((integrate_values) ? EvaluationFlags::values : EvaluationFlags::nothing) |
8498 ((integrate_gradients) ? EvaluationFlags::gradients :
8500
8501 integrate_scatter(flag, destination);
8502}
8503
8504
8505
8506template <int dim,
8507 int fe_degree,
8508 int n_q_points_1d,
8509 int n_components_,
8510 typename Number,
8511 typename VectorizedArrayType>
8512template <typename VectorType>
8513inline void
8515 fe_degree,
8516 n_q_points_1d,
8517 n_components_,
8518 Number,
8519 VectorizedArrayType>::
8520 integrate_scatter(const EvaluationFlags::EvaluationFlags integration_flag,
8521 VectorType &destination)
8522{
8523 Assert((this->dof_access_index ==
8525 this->is_interior_face() == false) == false,
8527
8528 const auto shared_vector_data = internal::get_shared_vector_data(
8529 &destination,
8530 this->dof_access_index ==
8532 this->active_fe_index,
8533 this->dof_info);
8534
8535 if (this->data->data.front().fe_degree > 0 &&
8536 fast_evaluation_supported(this->data->data.front().fe_degree,
8537 this->data->data.front().n_q_points_1d) &&
8539 dim,
8540 typename VectorType::value_type,
8541 VectorizedArrayType>::
8542 supports(integration_flag,
8543 *this->data,
8544 internal::get_beginning<typename VectorType::value_type>(
8545 destination),
8546 this->dof_info->index_storage_variants[this->dof_access_index]
8547 [this->cell]))
8548 {
8549 if constexpr (fe_degree > -1)
8550 {
8552 dim,
8553 typename VectorType::value_type,
8554 VectorizedArrayType>::template run<fe_degree,
8555 n_q_points_1d>(
8556 n_components,
8557 integration_flag,
8558 internal::get_beginning<typename VectorType::value_type>(
8559 destination),
8560 shared_vector_data,
8561 *this);
8562 }
8563 else
8564 {
8566 dim,
8567 typename VectorType::value_type,
8568 VectorizedArrayType>::integrate(n_components,
8569 integration_flag,
8570 internal::get_beginning<
8571 typename VectorType::value_type>(
8572 destination),
8573 shared_vector_data,
8574 *this);
8575 }
8576 }
8577 else
8578 {
8579 integrate(integration_flag);
8580 this->distribute_local_to_global(destination);
8581 }
8582}
8583
8584
8585
8586template <int dim,
8587 int fe_degree,
8588 int n_q_points_1d,
8589 int n_components_,
8590 typename Number,
8591 typename VectorizedArrayType>
8594 fe_degree,
8595 n_q_points_1d,
8596 n_components_,
8597 Number,
8598 VectorizedArrayType>::dof_indices() const
8599{
8601 0U, dofs_per_cell);
8602}
8603
8604
8605
8606template <int dim,
8607 int fe_degree,
8608 int n_q_points_1d,
8609 int n_components_,
8610 typename Number,
8611 typename VectorizedArrayType>
8612bool
8613FEEvaluation<dim,
8614 fe_degree,
8615 n_q_points_1d,
8616 n_components_,
8617 Number,
8618 VectorizedArrayType>::
8619 fast_evaluation_supported(const unsigned int given_degree,
8620 const unsigned int given_n_q_points_1d)
8621{
8622 return fe_degree == -1 ?
8624 fast_evaluation_supported(given_degree, given_n_q_points_1d) :
8625 true;
8626}
8627
8628
8629
8630template <int dim,
8631 int fe_degree,
8632 int n_q_points_1d,
8633 int n_components_,
8634 typename Number,
8635 typename VectorizedArrayType>
8636bool
8638 fe_degree,
8639 n_q_points_1d,
8640 n_components_,
8641 Number,
8642 VectorizedArrayType>::
8643 fast_evaluation_supported(const unsigned int given_degree,
8644 const unsigned int given_n_q_points_1d)
8645{
8646 return fe_degree == -1 ?
8648 fast_evaluation_supported(given_degree, given_n_q_points_1d) :
8649 true;
8650}
8651
8652
8653
8654template <int dim,
8655 int fe_degree,
8656 int n_q_points_1d,
8657 int n_components_,
8658 typename Number,
8659 typename VectorizedArrayType>
8660bool
8662 fe_degree,
8663 n_q_points_1d,
8664 n_components_,
8665 Number,
8666 VectorizedArrayType>::at_boundary() const
8667{
8668 Assert(this->dof_access_index !=
8671
8672 if (this->is_interior_face() == false)
8673 return false;
8674 else if (this->cell < this->matrix_free->n_inner_face_batches())
8675 return false;
8676 else if (this->cell < (this->matrix_free->n_inner_face_batches() +
8677 this->matrix_free->n_boundary_face_batches()))
8678 return true;
8679 else
8680 return false;
8681}
8682
8683
8684
8685template <int dim,
8686 int fe_degree,
8687 int n_q_points_1d,
8688 int n_components_,
8689 typename Number,
8690 typename VectorizedArrayType>
8693 fe_degree,
8694 n_q_points_1d,
8695 n_components_,
8696 Number,
8697 VectorizedArrayType>::boundary_id() const
8698{
8699 Assert(this->dof_access_index !=
8702
8703 if (at_boundary())
8704 return this->matrix_free->get_boundary_id(this->cell);
8705 else
8707}
8708
8709
8710
8711template <int dim,
8712 int fe_degree,
8713 int n_q_points_1d,
8714 int n_components_,
8715 typename Number,
8716 typename VectorizedArrayType>
8717unsigned int
8719 dim,
8720 fe_degree,
8721 n_q_points_1d,
8722 n_components_,
8723 Number,
8724 VectorizedArrayType>::get_dofs_per_component_projected_to_face()
8725{
8726 return this->data->dofs_per_component_on_face;
8727}
8728
8729
8730
8731template <int dim,
8732 int fe_degree,
8733 int n_q_points_1d,
8734 int n_components_,
8735 typename Number,
8736 typename VectorizedArrayType>
8737unsigned int
8739 fe_degree,
8740 n_q_points_1d,
8741 n_components_,
8742 Number,
8743 VectorizedArrayType>::get_dofs_projected_to_face()
8744{
8745 return this->data->dofs_per_component_on_face * n_components_;
8746}
8747
8748
8749
8750/*------------------------- end FEFaceEvaluation ------------------------- */
8751
8752
8753#endif // ifndef DOXYGEN
8754
8755
8757
8758#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
AlignedVector< VectorizedArrayType > * scratch_data_array
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)
internal::CurlType< dim, VectorizedArrayType > curl_type
static constexpr unsigned int dimension
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)
std::vector< types::global_dof_index > local_dof_indices
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< 2, dim, VectorizedArrayType >, std::conditional_t< n_components_==dim, Tensor< 3, dim, VectorizedArrayType >, Tensor< 1, n_components_, Tensor< 2, dim, VectorizedArrayType > > > > hessian_type
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
static constexpr unsigned int n_components
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)
std::conditional_t< n_components_==1, VectorizedArrayType, Tensor< 1, n_components_, VectorizedArrayType > > value_type
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
static constexpr unsigned int n_lanes
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
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)
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)
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)
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 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
const internal::MatrixFreeFunctions::MappingInfo< dim, Number, VectorizedArrayType > & get_mapping_info() 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
Definition point.h:111
constexpr const Number & access_raw_entry(const unsigned int unrolled_index) const
#define DEAL_II_ALWAYS_INLINE
Definition config.h:166
#define DEAL_II_OPENMP_SIMD_PRAGMA
Definition config.h:214
#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()
Point< 2 > second
Definition grid_out.cc:4640
Point< 2 > first
Definition grid_out.cc:4639
unsigned int cell_index
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)
UpdateFlags
@ update_jacobian_grads
Gradient of volume element.
@ update_quadrature_points
Transformed quadrature points.
std::vector< index_type > data
Definition mpi.cc:734
std::size_t size
Definition mpi.cc:733
The namespace for the EvaluationFlags enum.
EvaluationFlags
The EvaluationFlags enum.
Tpetra::Vector< Number, LO, GO, NodeType< MemorySpace > > VectorType
std::enable_if_t< IsBlockVector< VectorType >::value, unsigned int > n_blocks(const VectorType &vector)
Definition operators.h:47
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)
constexpr compressed_constraint_kind unconstrained_compressed_constraint_kind
std::conditional_t< dim==3, Tensor< 1, 3, NumberType >, std::conditional_t< dim==2, NumberType, std::monostate > > CurlType
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)
constexpr types::geometric_orientation invalid_geometric_orientation
Definition types.h:369
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
constexpr types::boundary_id internal_face_boundary_id
Definition types.h:319
constexpr types::geometric_orientation default_geometric_orientation
Definition types.h:342
boost::integer_range< IncrementableType > iota_view
Definition iota_view.h:43
STL namespace.
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)
std::uint8_t geometric_orientation
Definition types.h:38
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
unsigned int quad_index_from_n_q_points(const unsigned int n_q_points) const
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)