Skip to content

Commit 9f78a3c

Browse files
committed
Add rtol, atol to MonotonicHermiteSpline
This allows the user to control the clipping, allowing some overshoot Also restore the FCI MMS test with this interpolator
1 parent 3dbed9a commit 9f78a3c

File tree

4 files changed

+48
-17
lines changed

4 files changed

+48
-17
lines changed

include/bout/interpolation_xz.hxx

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#ifndef BOUT_INTERP_XZ_H
2525
#define BOUT_INTERP_XZ_H
2626

27+
#include "bout/bout_types.hxx"
2728
#include "bout/mask.hxx"
2829

2930
#define USE_NEW_WEIGHTS 1
@@ -166,7 +167,8 @@ protected:
166167
#endif
167168

168169
public:
169-
XZHermiteSpline(Mesh* mesh = nullptr) : XZHermiteSpline(0, mesh) {}
170+
XZHermiteSpline(Mesh* mesh = nullptr, [[maybe_unused]] Options* options = nullptr)
171+
: XZHermiteSpline(0, mesh) {}
170172
XZHermiteSpline(int y_offset = 0, Mesh* mesh = nullptr);
171173
XZHermiteSpline(const BoutMask& mask, int y_offset = 0, Mesh* mesh = nullptr)
172174
: XZHermiteSpline(y_offset, mesh) {
@@ -210,9 +212,29 @@ public:
210212
/// but also degrades accuracy near maxima and minima.
211213
/// Perhaps should only impose near boundaries, since that is where
212214
/// problems most obviously occur.
215+
///
216+
/// You can control how tight the clipping to the range of the neighbouring cell
217+
/// values through ``rtol`` and ``atol``:
218+
///
219+
/// diff = (max_of_neighours - min_of_neighours) * rtol + atol
220+
///
221+
/// and the interpolated value is instead clipped to the range
222+
/// ``[min_of_neighours - diff, max_of_neighours + diff]``
213223
class XZMonotonicHermiteSpline : public XZHermiteSpline {
224+
/// Absolute tolerance for clipping
225+
BoutReal atol = 0.0;
226+
/// Relative tolerance for clipping
227+
BoutReal rtol = 1.0;
228+
214229
public:
215-
XZMonotonicHermiteSpline(Mesh* mesh = nullptr) : XZHermiteSpline(0, mesh) {
230+
XZMonotonicHermiteSpline(Mesh* mesh = nullptr, Options* options = nullptr)
231+
: XZHermiteSpline(0, mesh),
232+
atol{(*options)["atol"]
233+
.doc("Absolute tolerance for clipping overshoot")
234+
.withDefault(0.0)},
235+
rtol{(*options)["rtol"]
236+
.doc("Relative tolerance for clipping overshoot")
237+
.withDefault(1.0)} {
216238
if (localmesh->getNXPE() > 1) {
217239
throw BoutException("Do not support MPI splitting in X");
218240
}
@@ -245,7 +267,8 @@ class XZLagrange4pt : public XZInterpolation {
245267
Field3D t_x, t_z;
246268

247269
public:
248-
XZLagrange4pt(Mesh* mesh = nullptr) : XZLagrange4pt(0, mesh) {}
270+
XZLagrange4pt(Mesh* mesh = nullptr, [[maybe_unused]] Options* options = nullptr)
271+
: XZLagrange4pt(0, mesh) {}
249272
XZLagrange4pt(int y_offset = 0, Mesh* mesh = nullptr);
250273
XZLagrange4pt(const BoutMask& mask, int y_offset = 0, Mesh* mesh = nullptr)
251274
: XZLagrange4pt(y_offset, mesh) {
@@ -278,7 +301,8 @@ class XZBilinear : public XZInterpolation {
278301
Field3D w0, w1, w2, w3;
279302

280303
public:
281-
XZBilinear(Mesh* mesh = nullptr) : XZBilinear(0, mesh) {}
304+
XZBilinear(Mesh* mesh = nullptr, [[maybe_unused]] Options* options = nullptr)
305+
: XZBilinear(0, mesh) {}
282306
XZBilinear(int y_offset = 0, Mesh* mesh = nullptr);
283307
XZBilinear(const BoutMask& mask, int y_offset = 0, Mesh* mesh = nullptr)
284308
: XZBilinear(y_offset, mesh) {
@@ -302,18 +326,18 @@ public:
302326
};
303327

304328
class XZInterpolationFactory
305-
: public Factory<XZInterpolation, XZInterpolationFactory, Mesh*> {
329+
: public Factory<XZInterpolation, XZInterpolationFactory, Mesh*, Options*> {
306330
public:
307331
static constexpr auto type_name = "XZInterpolation";
308332
static constexpr auto section_name = "xzinterpolation";
309333
static constexpr auto option_name = "type";
310334
static constexpr auto default_type = "hermitespline";
311335

312336
ReturnType create(Options* options = nullptr, Mesh* mesh = nullptr) const {
313-
return Factory::create(getType(options), mesh);
337+
return Factory::create(getType(options), mesh, options);
314338
}
315-
ReturnType create(const std::string& type, [[maybe_unused]] Options* options) const {
316-
return Factory::create(type, nullptr);
339+
ReturnType create(const std::string& type, Options* options) const {
340+
return Factory::create(type, nullptr, options);
317341
}
318342

319343
static void ensureRegistered();

src/mesh/interpolation/monotonic_hermite_spline_xz.cxx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
#include "bout/interpolation_xz.hxx"
2626
#include "bout/mesh.hxx"
2727

28-
#include <vector>
28+
#include <algorithm>
2929

3030
Field3D XZMonotonicHermiteSpline::interpolate(const Field3D& f,
3131
const std::string& region) const {
@@ -96,20 +96,17 @@ Field3D XZMonotonicHermiteSpline::interpolate(const Field3D& f,
9696
// Perhaps should only impose near boundaries, since that is where
9797
// problems most obviously occur.
9898
const BoutReal localmax = BOUTMAX(f[ic], f[icxp], f[iczp], f[icxpzp]);
99-
10099
const BoutReal localmin = BOUTMIN(f[ic], f[icxp], f[iczp], f[icxpzp]);
101100

102101
ASSERT2(std::isfinite(localmax) || i.x() < localmesh->xstart
103102
|| i.x() > localmesh->xend);
104103
ASSERT2(std::isfinite(localmin) || i.x() < localmesh->xstart
105104
|| i.x() > localmesh->xend);
106105

107-
if (result > localmax) {
108-
result = localmax;
109-
}
110-
if (result < localmin) {
111-
result = localmin;
112-
}
106+
const auto diff = ((localmax - localmin) * rtol) + atol;
107+
108+
result = std::min(result, localmax + diff);
109+
result = std::max(result, localmin - diff);
113110

114111
f_interp[iyp] = result;
115112
}

tests/MMS/spatial/fci/runtest

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,17 @@ if __name__ == "__main__":
236236
"yperiodic": True,
237237
"args": "mesh:ddy:first=C2 mesh:paralleltransform:xzinterpolation:type=lagrange4pt",
238238
},
239+
"nslice=1 monotonichermitespline": {
240+
"nslice": 1,
241+
"order": 2,
242+
"yperiodic": True,
243+
"args": (
244+
"mesh:ddy:first=C2 "
245+
"mesh:paralleltransform:xzinterpolation:type=monotonichermitespline "
246+
"mesh:paralleltransform:xzinterpolation:rtol=1e-3 "
247+
"mesh:paralleltransform:xzinterpolation:atol=5e-3"
248+
),
249+
},
239250
}
240251

241252
for name, case in cases.items():

tests/integrated/test-interpolate/runtest

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ methods = {
2525
"hermitespline": 3,
2626
"lagrange4pt": 3,
2727
"bilinear": 2,
28-
"monotonichermitespline": 2,
2928
}
3029

3130

0 commit comments

Comments
 (0)