27 MFEM_VERIFY(ipar.
Size() == 1 &&
28 dpar.
Size() == 0,
"Invalid spacing function parameters");
29 return std::unique_ptr<SpacingFunction>(
32 MFEM_VERIFY(ipar.
Size() == 3 &&
33 dpar.
Size() == 1,
"Invalid spacing function parameters");
34 return std::unique_ptr<SpacingFunction>(
38 MFEM_VERIFY(ipar.Size() == 3 &&
39 dpar.
Size() == 1,
"Invalid spacing function parameters");
40 return std::unique_ptr<SpacingFunction>(
42 dpar[0], (
bool) ipar[2]));
44 MFEM_VERIFY(ipar.Size() == 3 &&
45 dpar.
Size() == 2,
"Invalid spacing function parameters");
46 return std::unique_ptr<SpacingFunction>(
48 dpar[1], (
bool) ipar[2]));
50 MFEM_VERIFY(ipar.Size() == 3 &&
51 dpar.
Size() == 2,
"Invalid spacing function parameters");
52 return std::unique_ptr<SpacingFunction>(
54 dpar[1], (
bool) ipar[2]));
56 MFEM_VERIFY(ipar.Size() == 3 &&
57 dpar.
Size() == 1,
"Invalid spacing function parameters");
58 return std::unique_ptr<SpacingFunction>(
60 (
bool) ipar[2], dpar[0]));
62 MFEM_VERIFY(ipar.Size() >= 3,
"Invalid spacing function parameters");
63 ipar.GetSubArray(3, ipar[1], relN);
64 ipar.GetSubArray(3 + ipar[1], ipar.Size() - 3 - ipar[1], iparsub);
65 return std::unique_ptr<SpacingFunction>(
67 (
bool) ipar[2], relN, iparsub,
70 MFEM_ABORT(
"Unknown spacing type \"" <<
int(spacingType) <<
"\"");
74 MFEM_ABORT(
"Unknown spacing type");
75 return std::unique_ptr<SpacingFunction>(
nullptr);
80 MFEM_ABORT(
"Base class SpacingFunction should not be cloned");
81 return std::unique_ptr<SpacingFunction>(
nullptr);
84void GeometricSpacingFunction::CalculateSpacing()
88 if (
n == 1) {
return; }
92 constexpr real_t convTol = 1.0e-8;
93 constexpr int maxIter = 20;
97 r = s < s_unif ? 1.5 : 0.5;
99 bool converged =
false;
100 for (
int iter=0; iter<maxIter; ++iter)
102 const real_t g = (s * (std::pow(r,
n) - 1.0)) - r + 1.0;
103 const real_t dg = (
n * s * std::pow(r,
n-1)) - 1.0;
106 if (std::abs(g / dg) < convTol)
113 MFEM_VERIFY(converged,
"Convergence failure in GeometricSpacingFunction");
116void BellSpacingFunction::CalculateSpacing()
128 MFEM_VERIFY(s0 + s1 < 1.0,
"Sum of first and last Bell spacings must be"
137 s[1] = 1.0 - s0 - s1;
146 for (
int i=1; i<
n-1; ++i)
174 constexpr int maxIter = 100;
175 constexpr real_t convTol = 1.0e-10;
176 bool converged =
false;
177 for (
int iter=0; iter<maxIter; ++iter)
180 for (j = 1; j <=
n - 3; j++)
182 wk[0] = (s[j] + s[j+1]) * (s[j] + s[j+1]);
184 wk[2] = (s[j-1] + s[j]) * (s[j-1] + s[j]) * (s[j-1] + s[j]);
186 wk[4] = (s[j+2] + s[j+1]) * (s[j+2] + s[j+1]) * (s[j+2] + s[j+1]);
187 wk[5] = wk[0] * wk[1] / wk[2];
188 wk[6] = wk[0] * wk[3] / wk[4];
189 a[j+1] =
a[j+1] + urk*(wk[5] -
a[j+1]);
190 b[j+1] =
b[j+1] + urk*(wk[6] -
b[j+1]);
193 for (j = 2; j <=
n - 2; j++)
199 2.0*
b[j] +
beta[j - 1] + 1.0);
200 beta[j] = -
b[j]*wk[1];
201 gamma[j] = wk[1]*(
a[j]*(2.0*gamma[j - 1] - gamma[j - 2] -
202 alpha[j - 2]*gamma[j - 1]) + gamma[j - 1]);
208 s_new[j] = s_new[j-1] + s[j];
211 for (j =
n - 3; j >= 1; j--)
213 s_new[j] =
alpha[j+1]*s_new[j + 1] +
214 beta[j+1]*s_new[j + 2] + gamma[j+1];
218 for (j=
n-1; j>0; --j)
220 s_new[j] = s_new[j] - s_new[j-1];
224 for (j =
n - 2; j >= 2; j--)
226 wk[5] = wk[5] + s_new[j]*s_new[j];
227 wk[6] = wk[6] + pow(s_new[j] - s[j], 2);
232 const real_t res = sqrt(wk[6] / wk[5]);
240 MFEM_VERIFY(converged,
"Convergence failure in BellSpacingFunction");
243void GaussianSpacingFunction::CalculateSpacing()
260 s[1] = 1.0 - s0 - s1;
266 const real_t lnz01 = log(s0 / s1);
275 const real_t slinear =
n * (s0 + (h * (s1 - s0) * 0.5 * (
n-1)));
277 MFEM_VERIFY(std::abs(slinear - 1.0) > 1.0e-8,
"Bell distribution is too "
278 <<
"close to linear.");
280 const real_t u = slinear < 1.0 ? 1.0 : -1.0;
285 constexpr int maxIter = 10;
286 constexpr real_t convTol = 1.0e-8;
287 bool converged =
false;
288 for (
int iter=0; iter<maxIter; ++iter)
292 const real_t m = 0.5 * (1.0 - (
u * c2 * lnz01));
293 const real_t dmdc = -
u * c * lnz01;
298 for (
int i=0; i<
n; ++i)
301 const real_t ti = exp((-(x * x) + (2.0 * x * m)) *
u / c2);
305 drdc += ((-2.0 * (-(x * x) + (2.0 * x * m)) / (c2 * c)) +
306 ((2.0 * x * dmdc) / c2)) * ti;
312 if (std::abs(r) < convTol)
322 dc = std::min(dc, (
real_t) 2.0*c);
327 MFEM_VERIFY(converged,
"Convergence failure in GaussianSpacingFunction");
330 const real_t m = 0.5 * (1.0 - (
u * c2 * lnz01));
331 const real_t q = s0 * exp(
u*m*m / c2);
333 for (
int i=0; i<
n; ++i)
335 const real_t x = (i * h) - m;
336 s[i] = q * exp(-
u*x*x / c2);
340void LogarithmicSpacingFunction::CalculateSpacing()
342 MFEM_VERIFY(
n > 0 && logBase > 1.0,
343 "Invalid parameters in LogarithmicSpacingFunction");
345 if (sym) { CalculateSymmetric(); }
346 else { CalculateNonsymmetric(); }
349void LogarithmicSpacingFunction::CalculateSymmetric()
353 const bool odd = (
n % 2 == 1);
355 const int M0 =
n / 2;
356 const int M = odd ? (M0 + 1) : M0;
362 for (
int i=M-2; i>=0; --i)
364 const real_t p_i = (pow(logBase, (i+1)*h) - 1.0) / (logBase - 1.0);
376 const real_t t = odd ? 1.0 / (2.0 - s[M-1]) : 0.5;
378 for (
int i=0; i<M; ++i)
382 if (i < (M-1) || !odd)
389void LogarithmicSpacingFunction::CalculateNonsymmetric()
397 for (
int i=
n-2; i>=0; --i)
399 const real_t p_i = (pow(logBase, (i+1)*h) - 1.0) / (logBase - 1.0);
410 MFEM_VERIFY(partition.
Size() == np - 1,
"");
411 bool validPartition =
true;
414 for (
int i=0; i<np-1; ++i)
416 partition[i] = dpar[i];
418 if (partition[i] <= 0.0 || partition[i] >= 1.0)
420 validPartition =
false;
423 if (i > 0 && partition[i] <= partition[i-1])
425 validPartition =
false;
429 MFEM_VERIFY(validPartition,
"");
439 for (
int p=0;
p<np; ++
p)
443 const int numIntParam = ipar[osi+1];
444 const int numDoubleParam = ipar[osi+2];
447 dpar_p.
SetSize(numDoubleParam);
449 for (
int i=0; i<numIntParam; ++i)
451 ipar_p[i] = ipar[osi + 3 + i];
454 for (
int i=0; i<numDoubleParam; ++i)
456 dpar_p[i] = dpar[osd + i];
461 osi += 3 + numIntParam;
462 osd += numDoubleParam;
463 n_total += npartition[
p];
465 MFEM_VERIFY(pieces[
p]->
Size() >= 1,
"");
468 MFEM_VERIFY(osi == ipar.
Size() && osd == dpar.
Size(),
"");
474 for (
auto&
p : pieces) {
p->ScaleParameters(
a); }
482 for (
auto&
p : pieces)
485 inum +=
p->NumIntParameters() + 3;
486 dnum +=
p->NumDoubleParameters();
490 <<
n <<
" " << np <<
" " << (int)
reverse <<
"\n";
492 for (
auto n : npartition)
499 for (
auto&
p : pieces)
501 os <<
"\n" << int(
p->GetSpacingType()) <<
" " <<
p->NumIntParameters()
502 <<
" " <<
p->NumDoubleParameters();
504 p->GetIntParameters(ipar);
506 for (
auto& ip : ipar)
513 for (
auto p : partition)
520 for (
auto&
p : pieces)
522 p->GetDoubleParameters(dpar);
537void PiecewiseSpacingFunction::CalculateSpacing()
539 MFEM_VERIFY(
n >= 1 && (
n % n0 == 0 ||
n < n0),
"");
540 const int ref =
n / n0;
541 const int cf = n0 /
n;
545 bool coarsen = cf > 1 &&
n > 1;
549 for (
int p=0;
p<np; ++
p)
551 const int csize = pieces[
p]->Size() / cf;
552 if (pieces[
p]->
Size() != cf * csize)
562 for (
auto&
p : pieces) {
p->
SetSize(1); }
566 MFEM_VERIFY(coarsen ||
n >= n0,
567 "Invalid case in PiecewiseSpacingFunction::CalculateSpacing");
570 for (
int p=0;
p<np; ++
p)
576 pieces[
p]->SetSize(npartition[
p] / cf);
580 pieces[
p]->SetSize(ref * npartition[
p]);
583 const real_t p0 = (
p == 0) ? 0.0 : partition[
p-1];
584 const real_t p1 = (
p == np - 1) ? 1.0 : partition[
p];
585 const real_t h_p = p1 - p0;
587 for (
int i=0; i<pieces[
p]->Size(); ++i)
589 s[n_total + i] = h_p * pieces[
p]->Eval(i);
592 n_total += pieces[
p]->Size();
595 MFEM_VERIFY(n_total ==
n,
"");
600 for (
auto&
p : pieces)
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
int Size() const
Return the logical size of the array.
Bell spacing function, which produces spacing resembling a Bell curve.
Gaussian spacing function of the general form g(x) = a exp(-(x-m)^2 / c^2) for some scalar parameters...
Geometric spacing function.
Linear spacing function, defining the width of interval i as s + i * d.
Logarithmic spacing function, uniform in log base 10 by default.
Piecewise spacing function, with spacing functions defining spacing within arbitarily many fixed subi...
void ScaleParameters(real_t a) override
Scales parameters by the factor a associated with Size().
void Print(std::ostream &os) const override
Prints all the data necessary to define the spacing function and its current state (size and other pa...
bool Nested() const override
Returns true if the spacing function is nested during refinement.
void SetupPieces(Array< int > const &ipar, Vector const &dpar)
int Size() const
Returns the size, or number of intervals (elements).
virtual std::unique_ptr< SpacingFunction > Clone() const
Returns a clone (deep-copy) of this spacing function.
bool reverse
Whether to reverse the spacing.
int n
Size, or number of intervals (elements)
int Size() const
Returns the size of the vector.
void SetSize(int s)
Resize the vector to size s.
real_t u(const Vector &xvec)
std::unique_ptr< SpacingFunction > GetSpacingFunction(const SpacingType spacingType, Array< int > const &ipar, Vector const &dpar)
Returns a new SpacingFunction instance defined by the type and parameters.
real_t p(const Vector &x, real_t t)