version 3.10-dev
localrefinementquadrature.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3//
4// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
13#ifndef DUMUX_MULTIDOMAIN_EMBEDDED_LOCAL_REFINEMENT_QUADRATURE_HH
14#define DUMUX_MULTIDOMAIN_EMBEDDED_LOCAL_REFINEMENT_QUADRATURE_HH
15
16#include <array>
17#include <vector>
18#include <utility>
19#include <algorithm>
20
21#include <dune/common/exceptions.hh>
22
23namespace Dumux {
24
39template<class Geometry, class IndicatorFunction>
41{
42 using IndicatorTriple = std::array<std::size_t, 3>;
43 using GlobalPosition = typename Geometry::GlobalCoordinate;
44 using LocalPosition = typename Geometry::LocalCoordinate;
45 using Corners = std::array<GlobalPosition, 3>;
46
47 class QuadPoint
48 {
49 LocalPosition localPos_;
50 double weight_;
51 std::size_t indicator_;
52
53 public:
54 QuadPoint(LocalPosition&& localPos, double weight, std::size_t i)
55 : localPos_(weight*std::move(localPos))
56 , weight_(weight)
57 , indicator_(i)
58 {}
59
60 void add(LocalPosition&& localPos, double weight)
61 {
62 localPos_ += weight*localPos;
63 weight_ += weight;
64 }
65
66 void finalize()
67 {
68 localPos_ /= weight_;
69 }
70
71 const LocalPosition& position() const { return localPos_; }
72 double weight() const { return weight_; }
73 std::size_t indicator() const { return indicator_; }
74 };
75
76 class Triangle
77 {
78 Corners corners_;
79 public:
80 Triangle(const Corners& c) : corners_(c) {}
81 Triangle(Corners&& c) : corners_(std::move(c)) {}
82 const GlobalPosition& operator[](std::size_t i) const { return corners_[i]; }
83
84 GlobalPosition center() const
85 {
86 GlobalPosition center(0.0);
87 for (const auto& c : corners_)
88 center += c;
89 center /= corners_.size();
90 return center;
91 }
92
93 auto volume() const
94 {
95 const auto ab = corners_[1] - corners_[0];
96 const auto ac = corners_[2] - corners_[0];
97 return crossProduct(ab, ac).two_norm()*0.5;
98 }
99 };
100
101public:
102 LocalRefinementSimplexQuadrature(const Geometry& geo, std::size_t maxLevel, const IndicatorFunction& i)
103 : ind_(i)
104 , maxLevel_(maxLevel)
105 , geometry_(geo)
106 {
107 static constexpr int dim = Geometry::mydimension;
108 static_assert(dim == 2, "Only triangles are supported so far");
109
110 if (geo.corners() != (dim+1))
111 DUNE_THROW(Dune::InvalidStateException, "Only simplex geometries are allowed");
112
113 // evaluate indicator
114 const auto tri = Triangle{{ geo.corner(0), geo.corner(1), geo.corner(2) }};
115 const auto triple = IndicatorTriple{{ ind_(tri[0]), ind_(tri[1]), ind_(tri[2]) }};
116 volume_ = tri.volume();
117
118 // add new sub-qps recursively by adaptive refinement
119 addSimplex_(tri, 0, triple, triple);
120
121 for (auto& qp : qps_)
122 qp.finalize();
123 }
124
125 auto begin() const { return qps_.begin(); }
126 auto end() const { return qps_.end(); }
127 auto size() const { return qps_.size(); }
128
129private:
130 void addSimplex_(const Triangle& tri, std::size_t level, const IndicatorTriple& triple, const IndicatorTriple& childTriple)
131 {
132 // if all indicator are the same just add the triangle
133 if (std::all_of(childTriple.begin(), childTriple.end(), [a0=childTriple[0]](auto a){ return (a == a0); }))
134 {
135 // the volumes need to sum up to 0.5 (triangle reference element volume)
136 auto it = std::find_if(qps_.begin(), qps_.end(), [&](const auto& qp){ return (qp.indicator() == childTriple[0]); });
137 if (it != qps_.end())
138 it->add(geometry_.local(tri.center()), 0.5*tri.volume()/volume_);
139 else
140 qps_.emplace_back(geometry_.local(tri.center()), 0.5*tri.volume()/volume_, childTriple[0]);
141 }
142
143 // if they are different but the maximum level is reached, split volume in three
144 else if (level == maxLevel_)
145 {
146 for (int i = 0; i < 3; ++i)
147 {
148 // the volumes need to sum up to 0.5 (triangle reference element volume)
149 auto it = std::find_if(qps_.begin(), qps_.end(), [&](const auto& qp){ return (qp.indicator() == childTriple[i]); });
150 if (it != qps_.end())
151 it->add(geometry_.local(tri[i]), 0.5*tri.volume()/volume_/3.0);
152 else
153 qps_.emplace_back(geometry_.local(tri[i]), 0.5*tri.volume()/volume_/3.0, childTriple[i]);
154 }
155 }
156
157 // otherwise refine and go recursively over all children
158 else
159 {
160 const auto children = refine(tri);
161 for (const auto& c : children)
162 {
163 // make sure to recompute indicator every time since new indices might come up
164 const auto grandChildTriple = IndicatorTriple{{ ind_(c[0]), ind_(c[1]), ind_(c[2]) }};
165 addSimplex_(c, level+1, triple, grandChildTriple);
166 }
167 }
168 }
169
170 std::array<Triangle, 4> refine(const Triangle& tri) const
171 {
172 const auto p01 = 0.5*(tri[0] + tri[1]);
173 const auto p12 = 0.5*(tri[1] + tri[2]);
174 const auto p20 = 0.5*(tri[2] + tri[0]);
175
176 return {{
177 {{ tri[0], p01, p20 }},
178 {{ tri[1], p01, p12 }},
179 {{ tri[2], p12, p20 }},
180 {{ p12, p01, p20 }}
181 }};
182 }
183
184 const IndicatorFunction &ind_;
185 std::size_t maxLevel_;
186 const Geometry& geometry_;
187 double volume_;
188
189 std::vector<QuadPoint> qps_;
190};
191
192} // end namespace Dumux
193
194#endif
A quadrature rule using local refinement to approximate partitioned elements.
Definition: localrefinementquadrature.hh:41
auto end() const
Definition: localrefinementquadrature.hh:126
auto size() const
Definition: localrefinementquadrature.hh:127
LocalRefinementSimplexQuadrature(const Geometry &geo, std::size_t maxLevel, const IndicatorFunction &i)
Definition: localrefinementquadrature.hh:102
auto begin() const
Definition: localrefinementquadrature.hh:125
Dune::FieldVector< Scalar, 3 > crossProduct(const Dune::FieldVector< Scalar, 3 > &vec1, const Dune::FieldVector< Scalar, 3 > &vec2)
Cross product of two vectors in three-dimensional Euclidean space.
Definition: math.hh:671
auto volume(const Geometry &geo, unsigned int integrationOrder=4)
The volume of a given geometry.
Definition: volume.hh:159
Corners::value_type center(const Corners &corners)
The center of a given list of corners.
Definition: center.hh:24
Definition: adapt.hh:17