27#ifndef DUMUX_MULTIDOMAIN_EMBEDDED_CYLINDERINTEGRATOR_HH
28#define DUMUX_MULTIDOMAIN_EMBEDDED_CYLINDERINTEGRATOR_HH
38#include <dune/common/fvector.hh>
61 using GlobalPosition = Dune::FieldVector<Scalar, 3>;
71 rSamples_ = characteristicLengthToNumSamples_(rStep);
84 using std::ceil;
using std::clamp;
85 rSamples_ = characteristicLengthToNumSamples_(rStep);
86 zSamples_ = characteristicLengthToNumSamples_(zStep);
98 const GlobalPosition& topCenter,
102 const auto zAxis = (topCenter-bottomCenter);
103 const auto height = zAxis.two_norm();
104 const auto zAxisUnitVector = zAxis/height;
107 const auto rStep = radius/Scalar(rSamples_);
112 zSamples_ = std::max<std::size_t>(1, ceil(height/rStep));
113 const auto zStep = height/Scalar(zSamples_);
116 auto kOffset = numRingSamples_;
117 std::partial_sum(kOffset.begin(), kOffset.end(), kOffset.begin());
120 numPoints_ = zSamples_*circleSamples_;
122 std::cout <<
"CylinderIntegration -- number of integration points: " << numPoints_ << std::endl;
125 integrationElement_.resize(numPoints_);
126 points_.resize(numPoints_);
129 std::vector<GlobalPosition> ringPoints;
130 ringPoints.reserve(numRingSamples_.back());
133 for (std::size_t i = 0; i < zSamples_; ++i)
136 auto sliceCenter = bottomCenter;
137 sliceCenter.axpy((Scalar(i)+0.5)*zStep, zAxisUnitVector);
140 for (std::size_t j = 0; j < rSamples_; ++j)
142 const auto r = (Scalar(j)+0.5)*rStep;
143 circlePoints(ringPoints, sincos_[j], sliceCenter, zAxisUnitVector, r);
144 const auto ringOffest = j > 0 ? kOffset[j-1] : 0;
145 const auto ringSamples = numRingSamples_[j];
148 const auto integrationElement = M_PI*rStep*rStep*zStep*(1.0 + 2.0*Scalar(j))/ringSamples;
149 for (std::size_t k = 0; k < ringSamples; ++k)
151 const std::size_t idx = k + ringOffest + circleSamples_*i;
152 points_[idx] = ringPoints[k];
161 {
return integrationElement_[i]; }
165 {
return points_[i]; }
169 {
return numPoints_; }
176 numRingSamples_.resize(rSamples_);
177 for (
int j = 0; j < rSamples_; ++j)
181 numRingSamples_[j] = floor(2*M_PI*(Scalar(j)+0.5));
182 circleSamples_ += numRingSamples_[j];
186 sincos_.resize(rSamples_);
187 for (
int j = 0; j < rSamples_; ++j)
189 const auto numPoints = numRingSamples_[j];
190 sincos_[j].resize(2*numPoints);
192 for (std::size_t i = 0; i < numPoints; ++i)
194 using std::sin;
using std::cos;
195 sincos_[j][2*i] = sin(t);
196 sincos_[j][2*i + 1] = cos(t);
197 t += 2*M_PI/numPoints;
198 if (t > 2*M_PI) t -= 2*M_PI;
205 std::size_t characteristicLengthToNumSamples_(
const Scalar cl)
const
207 using std::clamp;
using std::min;
using std::max;
using std::ceil;
using std::nexttoward;
208 const Scalar clampedCl = clamp(cl, std::numeric_limits<Scalar>::min(), 1.0);
209 const Scalar floatNumSamples = ceil(1.0/clampedCl);
210 const Scalar largestValidFloat = nexttoward(std::numeric_limits<std::size_t>::max(), 0.0);
211 return static_cast<std::size_t
>(min(floatNumSamples, largestValidFloat));
214 bool zStepFixed_ =
false;
215 std::size_t zSamples_, rSamples_, numPoints_, circleSamples_;
216 std::vector<Scalar> integrationElement_;
217 std::vector<GlobalPosition> points_;
218 std::vector<std::size_t> numRingSamples_;
219 std::vector<std::vector<Scalar>> sincos_;
224template<
class GlobalPosition>
226 const GlobalPosition& center,
227 const GlobalPosition& firstAxis,
228 const GlobalPosition& secondAxis,
229 const GlobalPosition&
normal,
230 const typename GlobalPosition::value_type a,
231 const typename GlobalPosition::value_type b)
233 const auto d = p-center;
239 const auto da = (d*firstAxis);
240 const auto db = (d*secondAxis);
242 return (da*da/(a*a) + db*db/(b*b) < 1.0);
246template<
class GlobalPosition>
247inline std::pair<std::vector<GlobalPosition>,
typename GlobalPosition::value_type>
249 const GlobalPosition& firstUnitAxis,
250 const GlobalPosition& secondUnitAxis,
251 typename GlobalPosition::value_type a,
252 typename GlobalPosition::value_type b,
253 const GlobalPosition&
normal,
254 typename GlobalPosition::value_type characteristicLength)
257 const auto aStep = characteristicLength;
260 const std::size_t aSamples = std::max<std::size_t>(floor(2*a/aStep), 1);
261 const std::size_t bSamples = std::max<std::size_t>(floor(2*b/aStep), 1);
262 const auto bStep = 2*b / bSamples;
265 std::vector<GlobalPosition> points;
266 points.reserve(aSamples*bSamples);
269 auto startAB = center;
270 startAB.axpy(-a + 0.5*aStep, firstUnitAxis);
271 startAB.axpy(-b + 0.5*bStep, secondUnitAxis);
272 for (std::size_t as = 0; as < aSamples; ++as)
275 posA.axpy(as*aStep, firstUnitAxis);
276 for (std::size_t bs = 0; bs < bSamples; ++bs)
279 pos.axpy(bs*bStep, secondUnitAxis);
281 points.emplace_back(std::move(pos));
285 return {points, aStep*bStep};
300template<
class Scalar>
303 using GlobalPosition = Dune::FieldVector<Scalar, 3>;
312 : relCharLength_(relCharLength)
324 const GlobalPosition& topCenter,
325 const GlobalPosition& firstAxis,
326 const GlobalPosition& secondAxis,
329 const auto a = firstAxis.two_norm();
330 const auto b = secondAxis.two_norm();
331 const auto characteristicLength = relCharLength_*a;
333 auto firstUnitAxis = firstAxis; firstUnitAxis /= a;
334 auto secondUnitAxis = secondAxis; secondUnitAxis /= b;
337 auto zAxis = (topCenter-bottomCenter);
338 const auto length = zAxis.two_norm();
340 const auto height = (zAxis*
normal)*length;
342 const std::size_t zSamples = std::max<std::size_t>(floor(height/characteristicLength), 1);
343 const auto zStep = length / Scalar(zSamples);
344 const auto zStepFactor = length/height;
347 auto startZ = bottomCenter;
348 startZ.axpy(0.5*zStep, zAxis);
349 auto [ellipseIPs, ellipseIntegrationElement]
353 const auto abPoints = ellipseIPs.size();
354 numPoints_ = abPoints*zSamples;
358 points_.reserve(numPoints_);
359 std::move(ellipseIPs.begin(), ellipseIPs.end(), std::back_inserter(points_));
362 auto zStepVector = zAxis; zStepVector *= zStep;
363 for (std::size_t zs = 1; zs < zSamples; ++zs)
364 std::transform(points_.end() - abPoints, points_.end(), std::back_inserter(points_),
365 [&](
const auto& p){ return p + zStepVector; });
368 integrationElement_ = ellipseIntegrationElement*zStep/zStepFactor;
369 const auto meanLocalError = (height*a*b*M_PI - integrationElement_*numPoints_)/Scalar(numPoints_);
370 integrationElement_ += meanLocalError;
374 std::cout <<
"EllipticCylinderIntegration -- number of integration points: " << numPoints_ <<
"\n";
376 std::cout <<
" -- a: " << a <<
", b: " << b <<
", h: " << height <<
"\n"
377 <<
" -- volume: " << integrationElement_*numPoints_ <<
" (expected " << height*a*b*M_PI <<
")\n"
378 <<
" -- corrected a volume error of: " << meanLocalError/integrationElement_*100 <<
"%\n";
384 {
return integrationElement_; }
388 {
return points_[i]; }
392 {
return numPoints_; }
395 const Scalar relCharLength_;
396 std::size_t numPoints_;
397 Scalar integrationElement_;
398 std::vector<GlobalPosition> points_;
411template<
class Scalar>
414 using GlobalPosition = Dune::FieldVector<Scalar, 3>;
423 : relCharLength_(relCharLength)
434 const GlobalPosition& firstAxis,
435 const GlobalPosition& secondAxis,
438 const auto a = firstAxis.two_norm();
439 const auto b = secondAxis.two_norm();
440 const auto characteristicLength = relCharLength_*a;
442 auto firstUnitAxis = firstAxis; firstUnitAxis /= a;
443 auto secondUnitAxis = secondAxis; secondUnitAxis /= b;
447 std::tie(points_, integrationElement_)
451 const auto abPoints = points_.size();
452 numPoints_ = abPoints;
455 const auto meanLocalError = (a*b*M_PI - integrationElement_*numPoints_)/Scalar(numPoints_);
456 integrationElement_ += meanLocalError;
460 std::cout <<
"EllipseIntegration -- number of integration points: " << numPoints_ <<
"\n";
462 std::cout <<
" -- a: " << a <<
", b: " << b <<
"\n"
463 <<
" -- area: " << integrationElement_*numPoints_ <<
" (expected " << a*b*M_PI <<
")\n"
464 <<
" -- corrected an area error of: " << meanLocalError/integrationElement_*100 <<
"%\n";
470 {
return integrationElement_; }
474 {
return points_[i]; }
478 {
return numPoints_; }
481 const Scalar relCharLength_;
482 std::size_t numPoints_;
483 Scalar integrationElement_;
484 std::vector<GlobalPosition> points_;
Define some often used mathematical functions.
Helper function to compute points on a circle.
Vector normal(const Vector &v)
Create a vector normal to the given one (v is expected to be non-zero)
Definition: normal.hh:36
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:654
void circlePoints(std::vector< GlobalPosition > &points, const std::vector< Scalar > &sincos, const GlobalPosition ¢er, const GlobalPosition &normal, const Scalar radius)
Definition: circlepoints.hh:50
Definition: circlepoints.hh:36
std::pair< std::vector< GlobalPosition >, typename GlobalPosition::value_type > ellipseIntegrationPoints(const GlobalPosition ¢er, const GlobalPosition &firstUnitAxis, const GlobalPosition &secondUnitAxis, typename GlobalPosition::value_type a, typename GlobalPosition::value_type b, const GlobalPosition &normal, typename GlobalPosition::value_type characteristicLength)
construct evenly distributed integration points on an ellipse
Definition: cylinderintegration.hh:248
bool pointInEllipse(const GlobalPosition &p, const GlobalPosition ¢er, const GlobalPosition &firstAxis, const GlobalPosition &secondAxis, const GlobalPosition &normal, const typename GlobalPosition::value_type a, const typename GlobalPosition::value_type b)
check if a point is in an ellipse
Definition: cylinderintegration.hh:225
Helper class to integrate over a cylinder domain.
Definition: cylinderintegration.hh:60
CylinderIntegration(const Scalar rStep, const Scalar zStep)
Constructor.
Definition: cylinderintegration.hh:81
void setGeometry(const GlobalPosition &bottomCenter, const GlobalPosition &topCenter, const Scalar radius, int verbosity=0)
Set the geometry of the cylinder.
Definition: cylinderintegration.hh:97
std::size_t size() const
The number of integration points.
Definition: cylinderintegration.hh:168
Scalar integrationElement(std::size_t i) const
The integration element of the ith integration point.
Definition: cylinderintegration.hh:160
const GlobalPosition & integrationPoint(std::size_t i) const
The ith integration point.
Definition: cylinderintegration.hh:164
CylinderIntegration(const Scalar rStep)
Constructor.
Definition: cylinderintegration.hh:69
Helper class to integrate over an elliptic cylinder domain.
Definition: cylinderintegration.hh:302
void setGeometry(const GlobalPosition &bottomCenter, const GlobalPosition &topCenter, const GlobalPosition &firstAxis, const GlobalPosition &secondAxis, int verbosity=0)
Set the geometry of elliptic cylinder.
Definition: cylinderintegration.hh:323
const GlobalPosition & integrationPoint(std::size_t i) const
obtain ith integration point
Definition: cylinderintegration.hh:387
Scalar integrationElement(std::size_t i) const
obtain ith integration element
Definition: cylinderintegration.hh:383
EllipticCylinderIntegration(const Scalar relCharLength)
Constructor.
Definition: cylinderintegration.hh:311
std::size_t size() const
number of samples points
Definition: cylinderintegration.hh:391
Helper class to integrate over an elliptic domain.
Definition: cylinderintegration.hh:413
const GlobalPosition & integrationPoint(std::size_t i) const
obtain ith integration point
Definition: cylinderintegration.hh:473
EllipseIntegration(const Scalar relCharLength)
Constructor.
Definition: cylinderintegration.hh:422
Scalar integrationElement(std::size_t i) const
obtain ith integration element
Definition: cylinderintegration.hh:469
void setGeometry(const GlobalPosition ¢er, const GlobalPosition &firstAxis, const GlobalPosition &secondAxis, int verbosity=0)
set geometry of an ellipse
Definition: cylinderintegration.hh:433
std::size_t size() const
number of integration points
Definition: cylinderintegration.hh:477