2727#include < bout/bout_types.hxx>
2828#include < bout/generic_factory.hxx>
2929#include < bout/mask.hxx>
30+ #include < array>
3031
31- #define USE_NEW_WEIGHTS 1
3232#if BOUT_HAS_PETSC
33- #define HS_USE_PETSC 1
34- #endif
35-
36- #ifdef HS_USE_PETSC
3733#include " bout/petsclib.hxx"
3834#endif
3935
36+ namespace {
37+ enum class implementation_type { new_weights, petsc, legacy };
38+ }
39+
4040class Options ;
41+ class GlobalField3DAccess ;
4142
4243// / Interpolate a field onto a perturbed set of points
4344const Field3D interpolate (const Field3D& f, const Field3D& delta_x,
@@ -135,14 +136,26 @@ public:
135136 }
136137};
137138
138- class XZHermiteSpline : public XZInterpolation {
139+ // / Monotonic Hermite spline interpolator
140+ // /
141+ // / Similar to XZHermiteSpline, so uses most of the same code.
142+ // / Forces the interpolated result to be in the range of the
143+ // / neighbouring cell values. This prevents unphysical overshoots,
144+ // / but also degrades accuracy near maxima and minima.
145+ // / Perhaps should only impose near boundaries, since that is where
146+ // / problems most obviously occur.
147+ template <bool monotonic, implementation_type imp_type>
148+ class XZHermiteSplineBase : public XZInterpolation {
139149protected:
140150 // / This is protected rather than private so that it can be
141151 // / extended and used by HermiteSplineMonotonic
142152
143153 Tensor<SpecificInd<IND_TYPE::IND_3D>> i_corner; // index of bottom-left grid point
144154 Tensor<int > k_corner; // z-index of bottom-left grid point
145155
156+ std::unique_ptr<GlobalField3DAccess> gf3daccess;
157+ Tensor<std::array<int , 4 >> g3dinds;
158+
146159 // Basis functions for cubic Hermite spline interpolation
147160 // see http://en.wikipedia.org/wiki/Cubic_Hermite_spline
148161 // The h00 and h01 basis functions are applied to the function itself
@@ -160,23 +173,28 @@ protected:
160173
161174 std::vector<Field3D> newWeights;
162175
163- #if HS_USE_PETSC
176+ #if BOUT_HAS_PETSC
164177 PetscLib* petsclib;
165178 bool isInit{false };
166- Mat petscWeights;
167- Vec rhs, result;
179+ Mat petscWeights{} ;
180+ Vec rhs{} , result{} ;
168181#endif
169182
183+ // / Factors to allow for some wiggleroom
184+ BoutReal abs_fac_monotonic{1e-2 };
185+ BoutReal rel_fac_monotonic{1e-1 };
186+
170187public:
171- XZHermiteSpline (Mesh* mesh = nullptr , [[maybe_unused]] Options* options = nullptr )
172- : XZHermiteSpline(0 , mesh) {}
173- XZHermiteSpline (int y_offset = 0 , Mesh* mesh = nullptr );
174- XZHermiteSpline (const BoutMask& mask, int y_offset = 0 , Mesh* mesh = nullptr )
175- : XZHermiteSpline(y_offset, mesh) {
188+ XZHermiteSplineBase (Mesh* mesh = nullptr , [[maybe_unused]] Options* options = nullptr )
189+ : XZHermiteSplineBase(0 , mesh, options) {}
190+ XZHermiteSplineBase (int y_offset = 0 , Mesh* mesh = nullptr , Options* options = nullptr );
191+ XZHermiteSplineBase (const BoutMask& mask, int y_offset = 0 , Mesh* mesh = nullptr ,
192+ Options* options = nullptr )
193+ : XZHermiteSplineBase(y_offset, mesh, options) {
176194 setRegion (regionFromMask (mask, localmesh));
177195 }
178- ~XZHermiteSpline () {
179- #if HS_USE_PETSC
196+ ~XZHermiteSplineBase () override {
197+ #if BOUT_HAS_PETSC
180198 if (isInit) {
181199 MatDestroy (&petscWeights);
182200 VecDestroy (&rhs);
@@ -205,61 +223,21 @@ public:
205223 getWeightsForYApproximation (int i, int j, int k, int yoffset) override ;
206224};
207225
208- // / Monotonic Hermite spline interpolator
209- // /
210- // / Similar to XZHermiteSpline, so uses most of the same code.
211- // / Forces the interpolated result to be in the range of the
212- // / neighbouring cell values. This prevents unphysical overshoots,
213- // / but also degrades accuracy near maxima and minima.
214- // / Perhaps should only impose near boundaries, since that is where
215- // / problems most obviously occur.
216- // /
217- // / You can control how tight the clipping to the range of the neighbouring cell
218- // / values through ``rtol`` and ``atol``:
219- // /
220- // / diff = (max_of_neighours - min_of_neighours) * rtol + atol
221- // /
222- // / and the interpolated value is instead clipped to the range
223- // / ``[min_of_neighours - diff, max_of_neighours + diff]``
224- class XZMonotonicHermiteSpline : public XZHermiteSpline {
225- // / Absolute tolerance for clipping
226- BoutReal atol = 0.0 ;
227- // / Relative tolerance for clipping
228- BoutReal rtol = 1.0 ;
229-
230- public:
231- XZMonotonicHermiteSpline (Mesh* mesh = nullptr , Options* options = nullptr )
232- : XZHermiteSpline(0 , mesh),
233- atol{(*options)[" atol" ]
234- .doc (" Absolute tolerance for clipping overshoot" )
235- .withDefault (0.0 )},
236- rtol{(*options)[" rtol" ]
237- .doc (" Relative tolerance for clipping overshoot" )
238- .withDefault (1.0 )} {
239- if (localmesh->getNXPE () > 1 ) {
240- throw BoutException (" Do not support MPI splitting in X" );
241- }
242- }
243- XZMonotonicHermiteSpline (int y_offset = 0 , Mesh* mesh = nullptr )
244- : XZHermiteSpline(y_offset, mesh) {
245- if (localmesh->getNXPE () > 1 ) {
246- throw BoutException (" Do not support MPI splitting in X" );
247- }
248- }
249- XZMonotonicHermiteSpline (const BoutMask& mask, int y_offset = 0 , Mesh* mesh = nullptr )
250- : XZHermiteSpline(mask, y_offset, mesh) {
251- if (localmesh->getNXPE () > 1 ) {
252- throw BoutException (" Do not support MPI splitting in X" );
253- }
254- }
255-
256- using XZHermiteSpline::interpolate;
257- // / Interpolate using precalculated weights.
258- // / This function is called by the other interpolate functions
259- // / in the base class XZHermiteSpline.
260- Field3D interpolate (const Field3D& f,
261- const std::string& region = " RGN_NOBNDRY" ) const override ;
262- };
226+ using XZMonotonicHermiteSplineSerial =
227+ XZHermiteSplineBase<true , implementation_type::new_weights>;
228+ using XZHermiteSplineSerial =
229+ XZHermiteSplineBase<false , implementation_type::new_weights>;
230+ using XZMonotonicHermiteSplineLegacy =
231+ XZHermiteSplineBase<true , implementation_type::legacy>;
232+ using XZHermiteSplineLegacy = XZHermiteSplineBase<false , implementation_type::legacy>;
233+ #if BOUT_HAS_PETSC
234+ using XZMonotonicHermiteSpline = XZHermiteSplineBase<true , implementation_type::petsc>;
235+ using XZHermiteSpline = XZHermiteSplineBase<false , implementation_type::petsc>;
236+ #else
237+ using XZMonotonicHermiteSpline =
238+ XZHermiteSplineBase<true , implementation_type::new_weights>;
239+ using XZHermiteSpline = XZHermiteSplineBase<false , implementation_type::new_weights>;
240+ #endif
263241
264242// / XZLagrange4pt interpolation class
265243// /
0 commit comments