deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11: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
quadrature.cc
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) 1998 - 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#include <deal.II/base/config.h>
14
20#include <deal.II/base/point.h>
22#include <deal.II/base/tensor.h>
24
25#include <Kokkos_Macros.hpp>
26
27#include <algorithm>
28#include <array>
29#include <cmath>
30#include <cstddef>
31#include <iterator>
32#include <limits>
33#include <memory>
34#include <string>
35#include <type_traits>
36#include <utility>
37#include <vector>
38
40
41
42#ifndef DOXYGEN
43template <>
45 : is_tensor_product_flag(false)
46{}
47
48template <>
49Quadrature<0>::Quadrature(const unsigned int n_q)
51 , weights(n_q, 0)
52 , is_tensor_product_flag(false)
53{}
54#endif
55
56
57
58template <int dim>
60 : is_tensor_product_flag(dim == 1)
61{}
62
63
64
65template <int dim>
66Quadrature<dim>::Quadrature(const unsigned int n_q)
67 : quadrature_points(n_q, Point<dim>())
68 , weights(n_q, 0)
69 , is_tensor_product_flag(dim == 1)
70{}
71
72
73
74template <int dim>
75void
77 const ArrayView<const double> &weights)
78{
79 this->weights.clear();
80 if (weights.size() > 0)
81 {
82 AssertDimension(weights.size(), points.size());
83 this->weights.insert(this->weights.end(), weights.begin(), weights.end());
84 }
85 else
86 this->weights.resize(points.size(),
87 std::numeric_limits<double>::infinity());
88
89 quadrature_points.clear();
90 quadrature_points.insert(quadrature_points.end(),
91 points.begin(),
92 points.end());
93
94 is_tensor_product_flag = dim == 1;
95}
96
97
98
99template <int dim>
100Quadrature<dim>::Quadrature(const std::vector<Point<dim>> &points,
101 const std::vector<double> &weights)
102 : quadrature_points(points)
103 , weights(weights)
104 , is_tensor_product_flag(dim == 1)
105{
106 Assert(weights.size() == points.size(),
107 ExcDimensionMismatch(weights.size(), points.size()));
108}
109
110
111
112template <int dim>
114 std::vector<double> &&weights)
115 : quadrature_points(std::move(points))
116 , weights(std::move(weights))
117 , is_tensor_product_flag(dim == 1)
118{
119 Assert(weights.size() == points.size(),
120 ExcDimensionMismatch(weights.size(), points.size()));
121}
122
123
124
125template <int dim>
126Quadrature<dim>::Quadrature(const std::vector<Point<dim>> &points)
127 : quadrature_points(points)
128 , weights(points.size(), std::numeric_limits<double>::infinity())
129 , is_tensor_product_flag(dim == 1)
130{
131 Assert(weights.size() == points.size(),
132 ExcDimensionMismatch(weights.size(), points.size()));
133}
135
136
137template <int dim>
139 : quadrature_points(std::vector<Point<dim>>(1, point))
140 , weights(std::vector<double>(1, 1.))
141 , is_tensor_product_flag(true)
142 , tensor_basis(new std::array<Quadrature<1>, dim>())
143{
144 for (unsigned int i = 0; i < dim; ++i)
145 {
146 const std::vector<Point<1>> quad_vec_1d(1, Point<1>(point[i]));
147 (*tensor_basis)[i] = Quadrature<1>(quad_vec_1d, weights);
148 }
149}
150
151
152
153#ifndef DOXYGEN
154template <>
156 : quadrature_points(std::vector<Point<1>>(1, point))
157 , weights(std::vector<double>(1, 1.))
158 , is_tensor_product_flag(true)
159{}
160
161
162
163template <>
165 : is_tensor_product_flag(false)
166{
167 Assert(false, ExcImpossibleInDim(0));
168}
169
171
172template <>
174{
175 Assert(false, ExcImpossibleInDim(0));
176}
177#endif // DOXYGEN
178
179
180
181template <int dim>
183 : quadrature_points(q1.size() * q2.size())
184 , weights(q1.size() * q2.size())
185 , is_tensor_product_flag(q1.is_tensor_product())
186{
187 unsigned int present_index = 0;
188 for (unsigned int i2 = 0; i2 < q2.size(); ++i2)
189 for (unsigned int i1 = 0; i1 < q1.size(); ++i1)
190 {
191 // compose coordinates of new quadrature point by tensor product in the
192 // last component
193 for (unsigned int d = 0; d < dim - 1; ++d)
194 quadrature_points[present_index][d] = q1.point(i1)[d];
195 quadrature_points[present_index][dim - 1] = q2.point(i2)[0];
196
197 weights[present_index] = q1.weight(i1) * q2.weight(i2);
198
199 ++present_index;
201
202 if constexpr (running_in_debug_mode())
203 {
204 if (size() > 0)
205 {
206 double sum = 0;
207 for (unsigned int i = 0; i < size(); ++i)
208 sum += weights[i];
209 // we cannot guarantee the sum of weights to be exactly one, but it
210 // should be near that.
211 Assert((sum > 0.999999) && (sum < 1.000001), ExcInternalError());
212 }
213 }
214
215 if (is_tensor_product_flag)
216 {
217 tensor_basis = std::make_unique<std::array<Quadrature<1>, dim>>();
218 for (unsigned int i = 0; i < dim - 1; ++i)
219 (*tensor_basis)[i] = q1.get_tensor_basis()[i];
220 (*tensor_basis)[dim - 1] = q2;
221 }
222}
223
224
225#ifndef DOXYGEN
226template <>
227Quadrature<1>::Quadrature(const SubQuadrature &, const Quadrature<1> &q2)
228 : quadrature_points(q2.size())
229 , weights(q2.size())
230 , is_tensor_product_flag(true)
232 unsigned int present_index = 0;
233 for (unsigned int i2 = 0; i2 < q2.size(); ++i2)
234 {
235 // compose coordinates of new quadrature point by tensor product in the
236 // last component
237 quadrature_points[present_index][0] = q2.point(i2)[0];
238
239 weights[present_index] = q2.weight(i2);
240
241 ++present_index;
243
244 if constexpr (running_in_debug_mode())
245 {
246 if (size() > 0)
247 {
248 double sum = 0;
249 for (unsigned int i = 0; i < size(); ++i)
250 sum += weights[i];
251 // we cannot guarantee the sum of weights to be exactly one, but it
252 // should be near that.
253 Assert((sum > 0.999999) && (sum < 1.000001), ExcInternalError());
254 }
255 }
256}
257
258
259
260template <>
264 , weights(1, 1.)
265 , is_tensor_product_flag(false)
266{}
267
268
269template <>
272{
273 // this function should never be called -- this should be the copy constructor
274 // in 1d...
275 Assert(false, ExcImpossibleInDim(1));
276}
277#endif // DOXYGEN
278
279
280
281template <int dim>
284 , quadrature_points(Utilities::fixed_power<dim>(q.size()))
285 , weights(Utilities::fixed_power<dim>(q.size()))
286 , is_tensor_product_flag(true)
287{
288 Assert(dim <= 3, ExcNotImplemented());
289
290 const unsigned int n0 = q.size();
291 const unsigned int n1 = (dim > 1) ? n0 : 1;
292 const unsigned int n2 = (dim > 2) ? n0 : 1;
293
294 unsigned int k = 0;
295 for (unsigned int i2 = 0; i2 < n2; ++i2)
296 for (unsigned int i1 = 0; i1 < n1; ++i1)
297 for (unsigned int i0 = 0; i0 < n0; ++i0)
298 {
299 quadrature_points[k][0] = q.point(i0)[0];
300 if (dim > 1)
301 quadrature_points[k][1] = q.point(i1)[0];
302 if (dim > 2)
303 quadrature_points[k][2] = q.point(i2)[0];
304 weights[k] = q.weight(i0);
305 if (dim > 1)
306 weights[k] *= q.weight(i1);
307 if (dim > 2)
308 weights[k] *= q.weight(i2);
309 ++k;
310 }
311
312 tensor_basis = std::make_unique<std::array<Quadrature<1>, dim>>();
313 for (unsigned int i = 0; i < dim; ++i)
314 (*tensor_basis)[i] = q;
315}
316
317
318
319template <int dim>
322 , quadrature_points(q.quadrature_points)
323 , weights(q.weights)
324 , is_tensor_product_flag(q.is_tensor_product_flag)
325{
326 if (dim > 1 && is_tensor_product_flag)
328 std::make_unique<std::array<Quadrature<1>, dim>>(*q.tensor_basis);
329}
331
332
333template <int dim>
336{
337 weights = q.weights;
338 quadrature_points = q.quadrature_points;
339 is_tensor_product_flag = q.is_tensor_product_flag;
340 if (dim > 1 && is_tensor_product_flag)
341 {
342 if (tensor_basis == nullptr)
343 tensor_basis =
344 std::make_unique<std::array<Quadrature<1>, dim>>(*q.tensor_basis);
345 else
346 *tensor_basis = *q.tensor_basis;
347 }
348 return *this;
349}
350
351
352
353template <int dim>
354bool
356{
357 return ((quadrature_points == q.quadrature_points) && (weights == q.weights));
358}
359
360
361
362template <int dim>
363std::size_t
369
370
371
372template <int dim>
373typename std::conditional_t<dim == 1,
374 std::array<Quadrature<1>, dim>,
375 const std::array<Quadrature<1>, dim> &>
377{
378 Assert(this->is_tensor_product_flag == true,
379 ExcMessage("This function only makes sense if "
380 "this object represents a tensor product!"));
381 Assert(tensor_basis != nullptr, ExcInternalError());
382
383 return *tensor_basis;
384}
385
386
387#ifndef DOXYGEN
388template <>
389std::array<Quadrature<1>, 1>
391{
392 Assert(this->is_tensor_product_flag == true,
393 ExcMessage("This function only makes sense if "
394 "this object represents a tensor product!"));
395
396 return std::array<Quadrature<1>, 1>{{*this}};
397}
398#endif
399
400
401
402//---------------------------------------------------------------------------
403template <int dim>
405 : Quadrature<dim>(qx.size())
406{
407 Assert(dim == 1, ExcImpossibleInDim(dim));
408 unsigned int k = 0;
409 for (unsigned int k1 = 0; k1 < qx.size(); ++k1)
410 {
411 this->quadrature_points[k][0] = qx.point(k1)[0];
412 this->weights[k++] = qx.weight(k1);
413 }
414 Assert(k == this->size(), ExcInternalError());
415 this->is_tensor_product_flag = true;
416}
417
418
419
420template <int dim>
422 const Quadrature<1> &qy)
423 : Quadrature<dim>(qx.size() * qy.size())
424{
425 Assert(dim == 2, ExcImpossibleInDim(dim));
426
427 // placate compiler in the dim == 1 case
428 constexpr int dim_1 = dim == 2 ? 1 : 0;
429
430 unsigned int k = 0;
431 for (unsigned int k2 = 0; k2 < qy.size(); ++k2)
432 for (unsigned int k1 = 0; k1 < qx.size(); ++k1)
433 {
434 this->quadrature_points[k][0] = qx.point(k1)[0];
435 this->quadrature_points[k][dim_1] = qy.point(k2)[0];
436 this->weights[k++] = qx.weight(k1) * qy.weight(k2);
437 }
438 Assert(k == this->size(), ExcInternalError());
439
440 this->is_tensor_product_flag = true;
441 this->tensor_basis = std::make_unique<std::array<Quadrature<1>, dim>>();
442 (*this->tensor_basis)[0] = qx;
443 (*this->tensor_basis)[dim_1] = qy;
444}
445
446
447
448template <int dim>
450 const Quadrature<1> &qy,
451 const Quadrature<1> &qz)
452 : Quadrature<dim>(qx.size() * qy.size() * qz.size())
453{
454 Assert(dim == 3, ExcImpossibleInDim(dim));
455
456 // placate compiler in lower dimensions
457 constexpr int dim_1 = dim == 3 ? 1 : 0;
458 constexpr int dim_2 = dim == 3 ? 2 : 0;
459
460 unsigned int k = 0;
461 for (unsigned int k3 = 0; k3 < qz.size(); ++k3)
462 for (unsigned int k2 = 0; k2 < qy.size(); ++k2)
463 for (unsigned int k1 = 0; k1 < qx.size(); ++k1)
464 {
465 this->quadrature_points[k][0] = qx.point(k1)[0];
466 this->quadrature_points[k][dim_1] = qy.point(k2)[0];
467 this->quadrature_points[k][dim_2] = qz.point(k3)[0];
468 this->weights[k++] = qx.weight(k1) * qy.weight(k2) * qz.weight(k3);
469 }
470 Assert(k == this->size(), ExcInternalError());
471
472 this->is_tensor_product_flag = true;
473 this->tensor_basis = std::make_unique<std::array<Quadrature<1>, dim>>();
474 (*this->tensor_basis)[0] = qx;
475 (*this->tensor_basis)[dim_1] = qy;
476 (*this->tensor_basis)[dim_2] = qz;
477}
478
479
480
481// ------------------------------------------------------------ //
482
483namespace internal
484{
485 namespace QIteratedImplementation
486 {
487 namespace
488 {
489 bool
490 uses_both_endpoints(const Quadrature<1> &base_quadrature)
491 {
492 const bool at_left =
493 std::any_of(base_quadrature.get_points().cbegin(),
494 base_quadrature.get_points().cend(),
495 [](const Point<1> &p) { return p == Point<1>{0.}; });
496 const bool at_right =
497 std::any_of(base_quadrature.get_points().cbegin(),
498 base_quadrature.get_points().cend(),
499 [](const Point<1> &p) { return p == Point<1>{1.}; });
500 return (at_left && at_right);
501 }
502
503 std::vector<Point<1>>
504 create_equidistant_interval_points(const unsigned int n_copies)
505 {
506 std::vector<Point<1>> support_points(n_copies + 1);
507
508 for (unsigned int copy = 0; copy < n_copies; ++copy)
509 support_points[copy][0] =
510 static_cast<double>(copy) / static_cast<double>(n_copies);
511
512 support_points[n_copies][0] = 1.0;
513
514 return support_points;
515 }
516 } // namespace
517 } // namespace QIteratedImplementation
518} // namespace internal
519
520
521
522template <>
523QIterated<0>::QIterated(const Quadrature<1> &, const std::vector<Point<1>> &)
524 : Quadrature<0>()
525{
527}
528
529
530
531template <>
532QIterated<0>::QIterated(const Quadrature<1> &, const unsigned int)
533 : Quadrature<0>()
534{
536}
537
538
539
540template <>
542 const std::vector<Point<1>> &intervals)
543 : Quadrature<1>(
544 internal::QIteratedImplementation::uses_both_endpoints(base_quadrature) ?
545 (base_quadrature.size() - 1) * (intervals.size() - 1) + 1 :
546 base_quadrature.size() * (intervals.size() - 1))
547{
548 Assert(base_quadrature.size() > 0, ExcNotInitialized());
549 Assert(intervals.size() > 1, ExcZero());
550
551 const unsigned int n_copies = intervals.size() - 1;
552
553 if (!internal::QIteratedImplementation::uses_both_endpoints(base_quadrature))
554 // we don't have to skip some points in order to get a reasonable quadrature
555 // formula
556 {
557 unsigned int next_point = 0;
558 for (unsigned int copy = 0; copy < n_copies; ++copy)
559 for (unsigned int q_point = 0; q_point < base_quadrature.size();
560 ++q_point)
561 {
562 this->quadrature_points[next_point] =
563 Point<1>(base_quadrature.point(q_point)[0] *
564 (intervals[copy + 1][0] - intervals[copy][0]) +
565 intervals[copy][0]);
566 this->weights[next_point] =
567 base_quadrature.weight(q_point) *
568 (intervals[copy + 1][0] - intervals[copy][0]);
569
570 ++next_point;
571 }
572 }
573 else
574 // skip doubly available points
575 {
576 const unsigned int left_index =
577 std::distance(base_quadrature.get_points().begin(),
578 std::find_if(base_quadrature.get_points().cbegin(),
579 base_quadrature.get_points().cend(),
580 [](const Point<1> &p) {
581 return p == Point<1>{0.};
582 }));
583
584 const unsigned int right_index =
585 std::distance(base_quadrature.get_points().begin(),
586 std::find_if(base_quadrature.get_points().cbegin(),
587 base_quadrature.get_points().cend(),
588 [](const Point<1> &p) {
589 return p == Point<1>{1.};
590 }));
591
592 const unsigned double_point_offset =
593 left_index + (base_quadrature.size() - right_index);
594
595 for (unsigned int copy = 0, next_point = 0; copy < n_copies; ++copy)
596 for (unsigned int q_point = 0; q_point < base_quadrature.size();
597 ++q_point)
598 {
599 // skip the left point of this copy since we have already entered it
600 // the last time
601 if ((copy > 0) && (base_quadrature.point(q_point) == Point<1>(0.0)))
602 {
603 Assert(this->quadrature_points[next_point - double_point_offset]
604 .distance(Point<1>(
605 base_quadrature.point(q_point)[0] *
606 (intervals[copy + 1][0] - intervals[copy][0]) +
607 intervals[copy][0])) < 1e-10 /*tolerance*/,
609
610 this->weights[next_point - double_point_offset] +=
611 base_quadrature.weight(q_point) *
612 (intervals[copy + 1][0] - intervals[copy][0]);
613
614 continue;
615 }
616
617 this->quadrature_points[next_point] =
618 Point<1>(base_quadrature.point(q_point)[0] *
619 (intervals[copy + 1][0] - intervals[copy][0]) +
620 intervals[copy][0]);
621
622 // if this is the rightmost point of one of the non-last copies:
623 // give it the double weight
624 this->weights[next_point] =
625 base_quadrature.weight(q_point) *
626 (intervals[copy + 1][0] - intervals[copy][0]);
627
628 ++next_point;
629 }
630 }
631
632 // make sure that there is no rounding error for 0.0 and 1.0, since there
633 // are multiple asserts in the library checking for equality without
634 // tolerances
635 for (auto &i : this->quadrature_points)
636 if (std::abs(i[0] - 0.0) < 1e-12)
637 i[0] = 0.0;
638 else if (std::abs(i[0] - 1.0) < 1e-12)
639 i[0] = 1.0;
640
641 if constexpr (running_in_debug_mode())
642 {
643 double sum_of_weights = 0;
644 for (unsigned int i = 0; i < this->size(); ++i)
645 sum_of_weights += this->weight(i);
646 Assert(std::fabs(sum_of_weights - 1) < 1e-13, ExcInternalError());
647 }
648}
649
650
651
652template <>
654 const unsigned int n_copies)
655 : QIterated<1>(
656 base_quadrature,
657 internal::QIteratedImplementation::create_equidistant_interval_points(
658 n_copies))
659{
660 Assert(base_quadrature.size() > 0, ExcNotInitialized());
661 Assert(n_copies > 0, ExcZero());
662}
663
664
665
666// construct higher dimensional quadrature formula by tensor product
667// of lower dimensional iterated quadrature formulae
668template <int dim>
670 const std::vector<Point<1>> &intervals)
671 : Quadrature<dim>(QIterated<dim - 1>(base_quadrature, intervals),
672 QIterated<1>(base_quadrature, intervals))
673{}
674
675
676
677template <int dim>
679 const unsigned int n_copies)
680 : Quadrature<dim>(QIterated<dim - 1>(base_quadrature, n_copies),
681 QIterated<1>(base_quadrature, n_copies))
682{}
683
684
685
686// explicit instantiations; note: we need them all for all dimensions
687template class Quadrature<0>;
688template class Quadrature<1>;
689template class Quadrature<2>;
690template class Quadrature<3>;
691template class QAnisotropic<1>;
692template class QAnisotropic<2>;
693template class QAnisotropic<3>;
694template class QIterated<1>;
695template class QIterated<2>;
696template class QIterated<3>;
697
iterator begin() const
Definition array_view.h:755
iterator end() const
Definition array_view.h:764
std::size_t size() const
Definition array_view.h:737
Definition point.h:111
QAnisotropic(const Quadrature< 1 > &qx)
QIterated(const Quadrature< 1 > &base_quadrature, const unsigned int n_copies)
std::vector< Point< dim > > quadrature_points
Definition quadrature.h:352
void initialize(const ArrayView< const Point< dim > > &points, const ArrayView< const double > &weights={})
Definition quadrature.cc:76
std::unique_ptr< std::array< Quadrature< 1 >, dim > > tensor_basis
Definition quadrature.h:373
Quadrature & operator=(const Quadrature< dim > &)
std::size_t memory_consumption() const
const Point< dim > & point(const unsigned int i) const
bool is_tensor_product_flag
Definition quadrature.h:367
double weight(const unsigned int i) const
bool operator==(const Quadrature< dim > &p) const
const std::array< Quadrature< 1 >, dim > & get_tensor_basis() const
std::vector< double > weights
Definition quadrature.h:358
const std::vector< Point< dim > > & get_points() const
unsigned int size() const
#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
#define DEAL_II_NOT_IMPLEMENTED()
static ::ExceptionBase & ExcZero()
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
#define AssertDimension(dim1, dim2)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcNotInitialized()
static ::ExceptionBase & ExcMessage(std::string arg1)
std::size_t size
Definition mpi.cc:733
std::enable_if_t< std::is_fundamental_v< T >, std::size_t > memory_consumption(const T &t)
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)
*  *  if(update_pressure &update_flags) *  compute_pressure(constitutive_request
void copy(const T *begin, const T *end, U *dest)
STL namespace.
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)